This is the embeNET Border Router User Guide. You can read through the following topics:
The following sections give brief information about the embeNET networking. This is just an overview. Most topics are covered in depth in the following chapters.
The embeNET network is a wireless mesh network capable of providing communication between hundreds of nodes. It uses a special TSCH (Time Slotted Channel Hopping) scheme for accessing the radio channels, which greatly reduces idle listening and packet collisions even in dense networks. The network works with IEEE 802.15.4 compatible radio transceivers. The network is synchronized meaning that all nodes that joined the same network have a common sense of time, which is very precise and allows the nodes to schedule radio transmission and reception in exact moments.
The embeNET network is started by a special device called border router. Other nodes need to join the network started by the border router in order to be able to communicate. The border router may accept or reject a node based on the specifically configured joining rules.
The border router integrates a special node called root node. Your may think of the border router as a root node + router. The root node is a special kind of network node that is directly controlled by the router and may be regarded as a radio interface for the router. Typically root node and router are separate CPUs connected by a serial interface (like UART). Is such case root node has its own, fixed firmware.
The embeNET network uses the IPv6 protocol for addressing the nodes. It supports multicast addressing mode so that devices can be grouped and the data can be sent to all devices within a group simultaneously. Each device in the network is identified by a 64-bit unique identifier (UID) which is an EUI64 address. In most cases this number comes from the hardware platform the stack works on and should not be altered by the application code. In addition each network started by the border router is identified by a 64-bit network prefix. These two values - the network prefix and the UID are used to form a unicast IPv6 address of the node. A multicast address is being formed by the network prefix and group identifier.
In order to start a network the border router must assign a network key (K1), a network prefix and network ID (PANID).
The network key (K1) is shared across all devices within a network and typically can be the same for all devices used in an organization. It is a utility measure and network security is not based on this key. T
The network prefix is a 64-bit prefix that will constitute the first part of every IPv6 address within this network. It is beneficial for each network to have it's own network prefix, as it allows routing between the networks.
The network ID (PANID) is a 16-bit short network identifier that identifies the network.
Once these properties are set, the border router starts to advertise the network by periodically issuing BEACON packets. In reaction other nodes that wish to join the network may start the joining process.
The joining of node to the network is a multistep process. Firstly the node synchronizes to the network, meaning that it can follow the scheduled slots in which the communication with other nodes takes place. It selects a node (called pledge) through which it wishes to join. Next it sends credentials including own UID and PSK to the border router.
The border router has a list of join rules that decide which nodes can be accepted in the network. Each join rule may require that the nodes UID matches, the PSK matches or both values match the rule. This allows to shape the joining rules according to specific requirements. Once the node is accepted it can communicate with any other node in the network. Nodes that don't fit any join rule will be rejected.
The embeNET network uses UDP protocol for transporting data between the nodes. The UDP datagrams are handled by sockets which are registered in the nodes as well as in the border router.
The embeNET Border Router library implements the functionality of the central gateway and the router in a wireless mesh network. From the user perspective it is a library that provides interfaces, that the user application (and other middleware - such as network services) can use. However, due to the fact that the library is also portable across multiple hardware platforms, it also relies on some required interfaces. Those need to be implemented in either the 'port' or 'bsp'. Here, we will only focus on the provided interfaces - see embeNET BRC Porting Guide for the description of the required interfaces and how to implement them on a new or custom hardware.
The embeNET Border Router library utilizes event-driven style of programming. Most actions taken by the library last for a relatively long time before results are observed. Thus many function calls take callbacks as arguments.
The embeNET Border Router library provides the following interfaces:
The embeNET Border Router C API provides a set of functions that allow to start and stop the network. It also allows to manage join rules that dictate which nodes can join the network. The border router can also list the nodes that are joined as well as list the groups to which the nodes are assigned.
The embeNET UDP C API provides a set of functions that allow to register network sockets, through which all user communication is carried out. The protocol of choice here is UDP. See embeNET UDP C API for the description of functions and Using UDP sockets for the information on how to use them.
In the following sections we will assume that the border router is run as a thread within some operating system. This may however also be a main loop of some embedded code.
The embeNET Border Router follows a simple init-proc-deinit rule. Before using the router you need to initialize the library through a call to EMBENET_BR_Init. Once the library is initialized it is expected that the EMBENET_BR_Proc is called periodically - usually within the main loop of a thread. When (and if) the application is done with the library it may call EMBENET_BR_Deinit to deinitialize it.
The following example illustrates the idea:
There is just one more thing to consider. The embeNET Border Router stack uses EXPECT error handling utility for handling input validation and unrecoverable errors. Whenever the stack detects an really faulty condition it calls the EXPECT_OnAbortHandler which must be defined in the user code. The program must not continue operation after calling this function. A typical behavior of such function is to:
Below is the empty implementation of such function that you can copy, paste and extend.
Once the border router is initialized the following elements of the API are available:
The border router is responsible for starting the network. This is done through a call to EMBENET_BR_StartNetwork. This function accepts two arguments - the network configuration (EMBENET_BR_Config) and the list of event handlers (EMBENET_BR_EventHandlers).
In order to start the network we need to provide four things:
The following example illustrates the starting of the network.
In the above example only one event handler (EMBENET_BR_EventHandlers::onNetworkStarted) is set. This handler will be called when the network is actually started by the border router.
At any time after the network was started the application can call EMBENET_BR_GetNetworkPrefix to get the network prefix that was set in the provided network configuration and EMBENET_BR_GetOwnUid to get the UID of the root node.
At any time the border router can stop the network by calling the EMBENET_BR_StopNetwork function. When the network is stopped the EMBENET_BR_EventHandlers::onNetworkStopped event handler is called.
One of the key responsibilities of the border router is to give access to nodes that wish to join the network. When a node wishes to join the network it sends a join request along with the nodes 64-bit unique identifier (UID) and a device-specific 128-bit key called pre-shared-key (PSK). The border router decides whether to allow the node to join the network or not based on a set of rules called join rules. These rules are defined by the application using EMBENET_BR_AddJoinRule and EMBENET_BR_RemoveJoinRule calls. The rules are stored in a list that can have multiple entries (currently up to 500 entries).
Each join rule is a set of UID and PSK: we can denote it as [UID:PSK]. A special value of 0 (zero) for UID means that the rule applies to every UID This means that the border router may apply one of these authorization strategies:
This strategy allows every node to join the network as long as they use a pre-shared matching PSK key. This is useful for development and applications requiring limited security. The authorization of the nodes relies on a common PSK being known to the joining nodes. The network is secure as long as that can be kept secret. This strategy can be applied by adding a single rule of [0:PSK], where PSK is a common pre-shared key.
This strategy is a simple evolution of the single global PSK strategy. It just allows to use more than one PSK. This is however even less secure as there are now more than one keys that need to be kept secret. However in some scenarios this solution may be desired - for example to more control in more granular way when a set of devices is allowed or not allowed to join. This strategy can be applied by adding a multiple rules: [0:PSK1], [0:PSK2], ... where PSKs are a common pre-shared keys.
This strategy allows to only join nodes with matching UID, however still only one (or couple) global pre-shared keys are used. This strategy can be applied by adding a rule for each device: [UID1:PSK], [UID2:PSK], [UID3:PSK],
This strategy is most secure and requires each node to have own PSK matching its UID. It also requires most preparation in the border router as the UID+PSK pairs need to be provided as join rules. This strategy can be applied by adding a rule for each device: [UID1:PSK1], [UID2:PSK2], [UID3:PSK3],
These strategies can also be mixed together. When the join request is received from a node, the list is searched and if any rule allows the node to join, the node is let in to the network.
The join rules are cleared during initialization (EMBENET_BR_Init). They can be added and managed after the stack is initialized.
To add a rule the application should use EMBENET_BR_AddJoinRule. The rule can be later removed using EMBENET_BR_RemoveJoinRule. At any time after initialization the application can get a list of rules by first calling EMBENET_BR_GetJoinRulesCount to get the number of rules and then EMBENET_BR_GetJoinRuleByIndex to get each specific rule.
The code below illustrates the usage:
Once the network is started it is possible to list all the nodes that are currently joined. This can be done using EMBENET_BR_GetJoinedNodesCount to get the number of nodes and then using EMBENET_BR_GetJoinedNodeUidByIndex to get the UID of each joined node.
The following code illustrates the usage:
The application may also easily check if the node with a given UID is joined using EMBENET_BR_IsNodeJoined function.
Nodes can be organized in groups. The idea is to enable multicast addressing of such a group so that UDP packets can be sent to all the members of the group simultaneously. It is the node that decides to which groups it belongs to. The border router only observes the grouping behavior of nodes and can list all the group members, but it cannot directly make a given node join or leave particular group.
Each group is identified by a EMBENET_GroupId group identifier, which is freely chosen by the nodes.
Once the network is started it is possible to list all the groups that the joined nodes have currently joined to. This can be done using EMBENET_BR_GetGroupCount to get the number of groups and then using EMBENET_BR_GetGroupIdByIndex to get the group identifier of each registered group.
In addition, for every joined node it is possible to list the groups it belongs to using first EMBENET_BR_GetGroupCountForNode to get the number of groups and then EMBENET_BR_GetGroupIdForNodeByIndex to get each groupId.
The following code illustrates the usage:
The EMBENET_BR_EventHandlers structure gathers all the event handlers. If a particular event handler is not used it should be set to NULL.
The following table lists all the event handlers with their description:
Event handler | Description |
---|---|
EMBENET_BR_EventHandlers::onNetworkStarted | Called when the network is started (see Starting the network) |
EMBENET_BR_EventHandlers::onNetworkStopped | Called when the network is stopped (see Stopping the network) |
EMBENET_BR_EventHandlers::onNodeJoined | Called when a node joins the network |
EMBENET_BR_EventHandlers::onNodeLeft | Called when a node leaves the network |
EMBENET_BR_EventHandlers::onNodeAddedToGroup | Called when a node is added to a group |
EMBENET_BR_EventHandlers::onNodeRemovedFromGroup | Called when a node is removed from a group |
EMBENET_BR_EventHandlers::onDatagramOnUnregisteredPort | Called when an UDP datagram is received but no socket can handle it |