Point Coordination Function TDMA
PCF TDMA is a simple protocol used to collect data in a contention free manner from neighbors within a 1-hop star topology. A master node sends out a broadcast message that is used to synchronize all of the client nodes. Each node then replies using a dedicated time slot in collision-free manner. Time slots are either pre-defined, or requested at runtime from the master node. The size of the TDMA slots and cycles can be changed dynamically at the start of each cycle by the master making this protocol extremely flexible for applications that require shifting on-demand from high data-rate to low-power operation. Client nodes remain in power-down mode during non-assigned slots making the protocol extremely energy efficient.
Application Programming Interface
void tdma_task_config ()
int8_t tdma_init(uint8_t tdma_mode, uint8_t chan, uint16_t my_mac)
int8_t tdma_started()
tdma_info struct
This is the structured passed to and from the tdma_send and tdma_recv communication functions.
typedef struct {
uint16_t slot;
uint16_t cycle_size;
uint8_t slot_len_ms;
uint16_t dst;
uint16_t src;
uint16_t seq_num;
int16_t rssi;
} tdma_info;
int8_t tdma_send(tdma_info *fd, uint8_t *buf, uint8_t len, uint8_t flags)
Options for flags include TDMA_BLOCKING and TDMA_NONBLOCKING.
int8_t tdma_recv(tdma_info *fd, uint8_t *buf, uint8_t *len, uint8_t flags)
Options for flags include TDMA_BLOCKING and TDMA_NONBLOCKING.
int8_t tdma_tx_slot_add(uint16_t slot)
int8_t tdma_set_slot_len_ms(uint16_t len)
int8_t tdma_set_slots_per_cycle(uint16_t slots_per_cycle)
nrk_sig_t tdma_get_tx_done_signal()
nrk_sig_t tdma_get_rx_pkt_signal()
Host Example
The following examples are snapshots from the simple_msg project. If you wish to run the projects, it is easier to refer to the original source with the associated makefiles etc. T
void tx_task ()
{
int8_t v;
uint8_t len, cnt;
printf ("Gateway Tx Task PID=%u\r\n", nrk_get_pid ());
while (!tdma_started ())
nrk_wait_until_next_period ();
cnt = 0;
while (1) {
sprintf (tx_buf, "Host data counter %d\n", cnt);
cnt++;
len = strlen (tx_buf) + 1;
// Only transmit data if you want to do so
// Messages from the host are always broadcasts
v = tdma_send (&tx_tdma_fd, &tx_buf, len, TDMA_BLOCKING);
if (v == NRK_OK) {
nrk_kprintf (PSTR ("Host Packet Sent\n"));
}
}
}
void rx_task ()
{
nrk_time_t t;
uint16_t cnt;
int8_t v;
uint8_t len, i;
cnt = 0;
nrk_kprintf (PSTR ("Nano-RK Version "));
printf ("%d\r\n", NRK_VERSION);
printf ("RX Task PID=%u\r\n", nrk_get_pid ());
tdma_init (TDMA_HOST, 13, 0);
// Change these parameters at runtime...
tdma_set_slot_len_ms (10);
tdma_set_slots_per_cycle (10);
while (!tdma_started ())
nrk_wait_until_next_period ();
while (1) {
v = tdma_recv (&rx_tdma_fd, &rx_buf, &len, TDMA_BLOCKING);
if (v == NRK_OK) {
nrk_kprintf (PSTR ("Got pkt "));
printf ("src: %u rssi: %d ", rx_tdma_fd.src, rx_tdma_fd.rssi);
printf ("slot: %u ", rx_tdma_fd.slot);
printf ("len: %u\r\npayload: ", len);
for (i = 0; i < len; i++)
printf ("%c", rx_buf[i]);
printf ("\r\n");
}
}
}
void nrk_create_taskset ()
{
nrk_task_set_entry_function (&rx_task_info, rx_task);
nrk_task_set_stk (&rx_task_info, rx_task_stack, NRK_APP_STACKSIZE);
rx_task_info.prio = 1;
rx_task_info.FirstActivation = TRUE;
rx_task_info.Type = BASIC_TASK;
rx_task_info.SchType = PREEMPTIVE;
rx_task_info.period.secs = 0;
rx_task_info.period.nano_secs = 250 * NANOS_PER_MS;
rx_task_info.cpu_reserve.secs = 0;
rx_task_info.cpu_reserve.nano_secs = 100 * NANOS_PER_MS;
rx_task_info.offset.secs = 0;
rx_task_info.offset.nano_secs = 0;
nrk_activate_task (&rx_task_info);
nrk_task_set_entry_function (&tx_task_info, tx_task);
nrk_task_set_stk (&tx_task_info, tx_task_stack, NRK_APP_STACKSIZE);
tx_task_info.prio = 1;
tx_task_info.FirstActivation = TRUE;
tx_task_info.Type = BASIC_TASK;
tx_task_info.SchType = PREEMPTIVE;
tx_task_info.period.secs = 0;
tx_task_info.period.nano_secs = 250 * NANOS_PER_MS;
tx_task_info.cpu_reserve.secs = 0;
tx_task_info.cpu_reserve.nano_secs = 100 * NANOS_PER_MS;
tx_task_info.offset.secs = 0;
tx_task_info.offset.nano_secs = 0;
nrk_activate_task (&tx_task_info);
tdma_task_config ();
}
Client Example
void tx_task ()
{
int8_t v;
uint8_t len, cnt;
printf ("Tx Task PID=%u\r\n", nrk_get_pid ());
while (!tdma_started ())
nrk_wait_until_next_period ();
cnt = 0;
while (1) {
sprintf (tx_buf, "Node MAC: %u cnt: %d\n", mac_address, cnt);
cnt++;
len = strlen (tx_buf) + 1;
v = tdma_send (&tx_tdma_fd, &tx_buf, len, TDMA_BLOCKING);
if (v == NRK_OK) {
nrk_kprintf (PSTR ("App Packet Sent\n"));
}
}
}
void rx_task ()
{
nrk_time_t t;
uint16_t cnt;
int8_t v;
uint8_t len, i;
cnt = 0;
nrk_kprintf (PSTR ("Nano-RK Version "));
printf ("%d\r\n", NRK_VERSION);
printf ("RX Task PID=%u\r\n", nrk_get_pid ());
t.secs = 5;
t.nano_secs = 0;
mac_address = 1;
tdma_init (TDMA_CLIENT, 13, mac_address);
while (!tdma_started ())
nrk_wait_until_next_period ();
v = tdma_tx_slot_add (mac_address);
if (v != NRK_OK)
nrk_kprintf (PSTR ("Could not add slot!\r\n"));
while (1) {
v = tdma_recv (&rx_tdma_fd, &rx_buf, &len, TDMA_BLOCKING);
if (v == NRK_OK) {
printf ("src: %u\r\nrssi: %d\r\n", rx_tdma_fd.src, rx_tdma_fd.rssi);
printf ("slot: %u\r\n", rx_tdma_fd.slot);
printf ("cycle len: %u\r\n", rx_tdma_fd.cycle_size);
printf ("len: %u\r\npayload: ", len);
for (i = 0; i < len; i++)
printf ("%c", rx_buf[i]);
printf ("\r\n");
}
}
}
void nrk_create_taskset ()
{
nrk_task_set_entry_function (&rx_task_info, rx_task);
nrk_task_set_stk (&rx_task_info, rx_task_stack, NRK_APP_STACKSIZE);
rx_task_info.prio = 1;
rx_task_info.FirstActivation = TRUE;
rx_task_info.Type = BASIC_TASK;
rx_task_info.SchType = PREEMPTIVE;
rx_task_info.period.secs = 0;
rx_task_info.period.nano_secs = 250 * NANOS_PER_MS;
rx_task_info.cpu_reserve.secs = 1;
rx_task_info.cpu_reserve.nano_secs = 50 * NANOS_PER_MS;
rx_task_info.offset.secs = 0;
rx_task_info.offset.nano_secs = 0;
nrk_activate_task (&rx_task_info);
nrk_task_set_entry_function (&tx_task_info, tx_task);
nrk_task_set_stk (&tx_task_info, tx_task_stack, NRK_APP_STACKSIZE);
tx_task_info.prio = 1;
tx_task_info.FirstActivation = TRUE;
tx_task_info.Type = BASIC_TASK;
tx_task_info.SchType = PREEMPTIVE;
tx_task_info.period.secs = 0;
tx_task_info.period.nano_secs = 250 * NANOS_PER_MS;
tx_task_info.cpu_reserve.secs = 1;
tx_task_info.cpu_reserve.nano_secs = 50 * NANOS_PER_MS;
tx_task_info.offset.secs = 0;
tx_task_info.offset.nano_secs = 0;
nrk_activate_task (&tx_task_info);
tdma_task_config ();
}
Attachments
-
tdma-pcf.png
(49.8 KB) -
added by agr 18 months ago.

