RT-Link is a TDMA-based link protocol for wireless sensor networks. All packet exchanges occur in well-defined time slots allowing for collision-free energy-efficient communication with well defined time properties. RT-Link supports external out of band hardware-based synchronization as well as software-based in-band time synchronization. Hardware time synchronized nodes can implicitly pass time synchronization onto other nodes that receive or overhear packets. This implicit time synchronization can then cascade across multiple hops to extend the hardware based coverage. Hybrid time synchronization using hardware and in-band techniques allows for large area, fine-grained time synchronization. RT-Link is designed to support largely static infrastructure with peripheral mobile nodes. The static nodes are given a schedule based on their neighbors and network requirements. Mobile nodes communicate with the nearest infrastructure node using dedicated contention slots. Contention slots are a set of slots at the end of each frame that can be used in a slotted aloha fashion. These slots are not collision free like scheduled slots. They are used to allow mobile nodes to communicate as well as a mechanism for setting up scheduled slots. Once a mobile node's message is received by a scheduled node, it can rapidly be delivered to a destination within the scheduled network. Fixed and mobile nodes can dynamically form a network and facilitate applications such as utility monitoring, surveillance, location tracking and voice communication.

Each slot is 8ms in length. There are 32 slots per frame (256 ms) and 32 frames per cycle (8.192 seconds).
For examples of using the RT-link api, please refer to the basic_rtl project

Protocol Overview

RT-Link supports two types of slots: Scheduled Slots (SS) within which nodes are assigned
specific transmit and receive time slots and (b) a series of unscheduled or Contention
Slots (CS) where nodes, which are not assigned slots in the SS, select a transmit
slot at random as in slotted-Aloha. Nodes operating in SS are provided timeliness guarantees
as they are granted exclusive access of the shared channel and hence enjoy the
privilege of interference-free and hence collision-free communication. While the support
of SS and CS are similar to 802.15.4, RT-Link is designed for operation across
synchronized multi-hop networks.
After an active slot is complete, the node schedules its timer to wake up just before
the expected time of next active slot and promptly switches to sleep mode. The common
packet header includes a 32-bit transmit and 32-bit receive bit-mask to indicate
during which slots of a node is active.


RT-Link does not require any nrk_cfg.h settings, however you do need to add some lines into your makefile (see this example-makefile). You must add the following lines to your makefile:

1SRC += $(ROOT_DIR)/src/net/rt_link/rt_link.c 
2SRC += $(ROOT_DIR)/src/net/rt_link/rtl_scheduler.c 
3SRC += $(ROOT_DIR)/src/net/rt_link/rtl_debug.c
7EXTRAINCDIRS += $(ROOT_DIR)/src/net/rt_link/
8EXTRAINCDIRS += $(ROOT_DIR)/src/net/rt_link/platform/$(PLATFORM_TYPE)/

Below is a sample of how to setup a project that uses the link layer:

 2// You should define a globle buffer for your transmit and receive
 3uint8_t tx_buf[MAX_RTL_PKT_SIZE];
 4uint8_t rx_buf[MAX_RTL_PKT_SIZE];
 7main ()
 9  nrk_setup_ports();
10  nrk_setup_uart(UART_BAUDRATE_115K2);
12  nrk_kprintf( PSTR("Starting up...\r\n") );
14  nrk_init();
16  nrk_led_clr(0);
17  nrk_led_clr(1);
18  nrk_led_clr(2);
19  nrk_led_clr(3);
21  nrk_time_set(0,0);
23  // This is where the magic happens
24  rtl_task_config();
26  nrk_create_taskset ();
28  nrk_start();
30  return 0;

void rtl_task_config()

  • This function configures the RT-Link task and should be called in main during startup. See example above.

void rtl_init (enum rtl_node_mode_t mode)

  • This function initializes RT-Link. Each node can be configured in one of the following modes: RTL_COORDINATOR, RTL_FIXED, or RTL_MOBILE. Each network requires at least one RTL_COORDINATOR which is typically the gateway. RTL_FIXED nodes are nodes that are statically scheduled and have access to a hardware time synchronization module. RTL_MOBILE nodes are nodes which use (and propogate) in-band time synchronization.
1typedef enum {
2        RTL_MOBILE,
3        RTL_FIXED,
5} rtl_node_mode_t;

void rtl_start()

  • This function starts RT-Link and should be called after rtl_init().

void rtl_set_tx_power(uint8_t pwr)

  • This function controls the radio transmit power. pwr is hardware specific. On the cc2420 the value is between 0 and 31. The default is 31 which corresponds to maximum power.

void rtl_set_channel(uint8_t chan)

  • This function sets the channel that the radio operates on. chan is hardware specific. On the cc2420, there are 16 channel (10-25).


Below is an example showing how a schedule can be configured. In this case the node is configured as a coordinator which can transmit on slot 6 at rate 1 and receive on slot 8 at rate 1. A coordinator will also send time sync packets on slot 0 which may be detected by other nodes within range, however they should be ignored.

 1void myTask()
 4  printf( "myTask PID=%d\r\n",nrk_get_pid());
 6  rtl_init (RTL_COORDINATOR);
 7  // rtl_init (RTL_MOBILE);
 8  rtl_set_schedule( RTL_TX, 6, 1 ); 
 9  rtl_set_schedule( RTL_RX, 8, 1 ); 
10  // rtl_set_contention(8,1);
11  rtl_start();
13  // set the receive buffer
14  rtl_rx_pkt_set_buffer(rx_buf, RF_MAX_PAYLOAD_SIZE);
15  nrk_kprintf( PSTR("start done\r\n") );
16  while(!rtl_ready())  nrk_wait_until_next_period(); 

nrk_status_t rtl_set_schedule( enum rtl_rx_tx_t mode, uint8_t slot, uint8_t rate )

  • This function sets the mode and rate for a particular communication slot. The mode is either RTL_TX or RTL_RX depending on if the slot is intended for transmitting packets or receiving them. The slot value denotes which slot in the TDMA frame that should be scheduled. The rate sets how many frames in each cycle should be used for communication. See table below for rate details. This function returns NRK_OK upon success and NRK_ERROR upon failure.
1typedef enum {
2    RTL_RX,
3    RTL_TX,
4} rtl_rx_tx_t;
Rate Frame Interval Active Frames/ Cycle Single Slot Throughput (Kbps)
0 n/a n/a n/a
1 1 32 4
2 2 16 2
3 4 8 1
4 8 4 0.5
5 16 2 0.25
6 32 1 0.125

nrk_status_t rtl_clr_schedule (enum rtl_rx_tx_t mode, uint8_t slot)

  • This function clears a slot that was previously scheduled. This is useful for changing the schedule during system operation. This function return NRK_OK upon success and NRK_ERROR upon failure.

int8_t rtl_get_schedule (uint8_t slot)

  • This function returns the rate set for a particular slot. It does not return if the slot is a TX or RX slot. 0 is the default rate if the slot is not active.

void rtl_set_contention(uint8_t slots, uint8_t rate)

  • This function sets the number of contention slots and the set of slots operating rate. By default there are 0 contention slots.

nrk_status_t rtl_set_abs_wakeup (uint16_t slot, uint8_t repeat)

  • This function can be used to set a single global absolute wakeup slot in the TDMA schedule. This slot can be valued between 0 and 1024 since it specifies a location in the entire TDMA frame. There is no rate associated with this slot since it is not repeated over frames. It is up to the user to make sure there are no conflicts with the existing schedule. Setting repeat to 1 will tell the RT-link scheduler to wakeup on every cycle on the defined slot. Setting repeat to 0 will make the scheduler wakeup once and then clear the absolute wakeup schedule. The max number of absolute wakeups is by default 4, but can be overwritten by adding #define MAX_ABS_WAKEUP in nrk_cfg.h. This function returns NRK_OK upon success and NRK_ERROR on failure.

void rtl_clr_abs_wakeup (uint16_t slot)

  • This function clears an absolute wakeup scheduled for slot slot.


int8_t rtl_tx_pkt_check(unit8_t slot)

  • This function returns 0 if the packet queued for slot has been sent, or 1 if it is still pending.

nrk_status_t rtl_tx_pkt( char *buf, uint8_t length, uint8_t slot )

  • This function sends a packet on a particular slot. It is possible to send different packets on multiple slots before any particular slot has completed its transmission. buf is a pointer to the data buffer that will be sent. length is the size of the data buffer. slot denotes which slot the data should be transmitted on. Use RTL_CONTENTION as the slot identifier to transmit a packet on the contention slots. Only 1 message can be pending on the contention slots at a time. This function returns NRK_OK upon success and NRK_ERROR on failure.
    1     sprintf( &tx_buf[PKT_DATA_START], "Hello World %d", cnt ); 
    2     // Remember to add 1 with strlen since it does not include the terminating character
    3     length=strlen(&tx_buf[PKT_DATA_START])+1+PKT_DATA_START;
    4     rtl_tx_pkt( tx_buf, length, MY_TX_SLOT );
    5     printf( "Sending Packet on slot %d\r\n",MY_TX_SLOT );
    7     // Suspend until the packet is sent
    8     rtl_wait_until_tx_done();
int8_t rtl_tx_abs_pkt (uint8_t *buf, uint8_t len, uint16_t abs_slot)
  • This function is identical to rtl_tx_pkt() except that it will transmit on an arbitrary slot in the TDMA cycle. The slot value shold now be between 0 and 1024.


rtl_rx_pkt_set_buffer(rx_buf, RF_MAX_PAYLOAD_SIZE)
  • Pass this function a buffer that RT-Link can use to store the next incoming packet. Many users will not need to worry about changing buffers, however this must be set at least once. This function is to allow advanced users to manage multiple buffers quickly without copying. Returns 1 upon success.
    1rtl_rx_pkt_set_buffer(rx_buf, RF_MAX_PAYLOAD_SIZE);

int8_t rtl_rx_pkt_check()

  • This function returns 1 if a packet has been received and is waiting, or 0 otherwise.
char *local_buf = rtl_rx_pkt_get(uint8_t *length, int8_t *rssi, uint8_t *slot)
  • This function returns a pointer to the buffer containing a newly received packet. length is set to the length of the returned packet. rssi is set to the raw RSSI value from the radio (add 45 for dB). On failure, this function returns NULL (if for example a packet has not been received since the last rtl_rx_pkt_release() call). Typically you should use rtl_rx_pkt_check() or rtl_wait_until_rx_pkt() before calling this function. slot will be set to RTL_CONTENTION if the message arrived on a contention slot.
     1uint8_t length,slot;
     2int8_t rssi;
     3char *local_rx_buf;
     7if( rtl_rx_pkt_check()!=0 )
     8               {
     9           local_rx_buf=rtl_rx_pkt_get(&length, &rssi, &slot);
    10                   printf( "Got Packet on slot %d %d: ",slot,length );
    11                   for(i=PKT_DATA_START; i<length; i++ )
    12                     {
    13                        printf( "%c",local_rx_buf[i] );
    14                     }
    15                   nrk_kprintf( PSTR("\r\n") );
    16                   rtl_rx_pkt_release();
    17               }

void rtl_rx_pkt_release()

  • This function releases the RX buffer so that new packets can be received. This function should be called quickly after a packet is received to avoid dropping data. See rtl_rx_pkt_get() example code.



  • This function suspends the task until a RX signal arrives.

rtl_wait_until_tx_done(uint8_t slot)

  • This function suspends the task until a TX signal arrives for a particular slot. If you want to wait on any done signal, you can directly use the tx done signal using rtl_get_tx_done_signal().


  • This function suspends the task until a TX or RX signal arrives.

nrk_sig_t rtl_get_tx_done_signal()

  • This function returns the signal that is sent by RT-Link when a packet transmission completes. This signal handler can be muxed together with other signals to allow for non-blocking style waits. See nrk-api-signals-semaphores for more information about how to use signals.

nrk_sig_t rtl_get_rx_pkt_signal()

  • This function returns the signal that is sent by RT-Link when a new packet arrives. This signal handler can be muxed together with other signals to allow for non-blocking style waits. See nrk-api-signals-semaphores for more information about how to use signals. Below is an example of how to wait for a received packet, or time out using the nrk_next_wakeup kernel signal.
 1   nrk_time_t timeout;
 2   nrk_sig_t my_rx_sig;
 3   nrk_sig_mask_t my_sigs;
 5   timeout.secs=10;
 6   timeout.nano_secs=0;
 7   ...
 8   my_rx_sig = rtl_get_rx_pkt_signal();
 9   nrk_signal_register(my_rx_signal);
10   // nrk_wakeup_signal is a special per task kernel signal that does not need to be registered or retrieved
12   ...  // Do something here and then wait for RX packet
14   nrk_set_next_wakeup(timeout);
15   my_sigs=nrk_event_wait( SIG(my_rx_sig) | SIG(nrk_wakeup_signal) );
17   // Lets check which signal we got...
18   if(my_sigs==0)                        nrk_kprintf( PSTR( "Error calling nrk_event_wait()\r\n" ));
19   if(my_sigs & SIG(my_rx_sig))         nrk_kprintf( PSTR( "Got rx packet signal\r\n") );
20   if(my_sigs & SIG(nrk_wakeup_signal))  nrk_kprintf( PSTR( "Task got timeout signal! \r\n") );


uint8_t rtl_sync_status()
  • This function returns 1 if the node is synchronized with the network, or 0 if it is out of sync and searching for a message or beacon.
uint16_t rtl_get_global_slot()
  • This function returns the current global slot that RT-Link is executing.
uint16_t rtl_get_slots_until_next_wakeup (uint16_t current_slot)
  • This function returns the number of slots until the specified slot in the cycle.

rt_link_slots.jpg (43.5 kB) Anthony Rowe, 03/05/2007 01:17 am