有人可以解释一下 Contiki-OS 在传输 UDP 数据包时发生了什么吗?
这是我的设备在 CC2538 芯片上运行的详细电流消耗:

我的问题是:为什么传输 UDP 广播数据包需要这么长时间(大约 250 毫秒)知道理论上 250kbps 的 408 位长度的数据包应该在大约 2 毫秒内传输?我会理解传输是否持续十毫秒,但这里的差异是巨大的。
我用这个例子 contiki/examples/ipv6/simple-udp-rpl/broadcast-example.c
有人有想法吗?
默认情况下,Contiki 使用 ContikiMAC 无线电占空比 (RDC) 协议。该协议必须处理两个相互冲突的要求:允许接收节点在没有数据包接收时几乎一直处于休眠状态,但同时允许尽可能可靠地传递数据。ContikiMAC 采用的解决方案是将负担放在发射机上。鉴于接收器每秒检查无线电信道 8 次(cc2538dk 平台上的默认配置),发送器必须传输至少 125 毫秒的持续时间,以确保接收器已唤醒并看到数据包。实际上,这意味着一个数据包会连续多次重传。有关更详细的说明,请参阅ContikiMAC 论文和Contiki 文档。
话虽如此,您不会总是看到具有最长持续时间的传输。如果是单播,接收者通常会在成功接收后发送一个 ACK。发送器检查此 ACK,如果收到则停止发送。这样,所需的预期平均传输次数减少了两倍。然后还有相位优化——它允许发送者将传输的开始与接收者的预期唤醒时间同步。但是对于广播,不会生成 ACK,相位优化也不起作用。
意外长传输的另一个可能原因是 CCA 检查失败。在传输数据包之前,无线电栈首先检查介质是否空闲;如果不是,它将备份一段时间并重试。
我发现了问题:传输数据包后无线电没有正确关闭。
transmit()在文件中的函数结束时,cpu/cc2538/dev/cc2538-rf.c无线电仅在之前关闭时才关闭。
if(rf_flags & WAS_OFF) {
rf_flags &= ~WAS_OFF;
off();
}
但实际上程序永远不会在这种情况下运行,并且在传输数据包后不会立即关闭无线电。
问题出现是因为函数channel_clear()(在函数开头transmit()调用)首先清除了这个标志。因此,该函数transmit()不再知道无线电在其执行之前已关闭,因此无线电保持打开状态。
为了解决这个问题,我在其中放置了一个局部变量,channel_clear()它关闭无线电并仅在函数本身内部打开标志时才清除标志。
static int
channel_clear(void)
{
int cca;
/* Fix: local variable */
uint8_t intern_onoff;
intern_onoff = 0;
PRINTF("RF: CCA\n");
/* If we are off, turn on first */
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
rf_flags |= WAS_OFF;
on();
intern_onoff = 1;
}
/* Wait on RSSI_VALID */
while((REG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) == 0);
if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_CCA) {
cca = CC2538_RF_CCA_CLEAR;
} else {
cca = CC2538_RF_CCA_BUSY;
}
/* If we were off, turn back off */
if((rf_flags & WAS_OFF) == WAS_OFF && intern_onoff) {
rf_flags &= ~WAS_OFF;
off();
intern_onoff = 0;
}
return cca;
}
数据包传输期间的电流消耗现在看起来像:

注意:选通时间故意减少到 10 毫秒:
#define STROBE_TIME RTIMER_ARCH_SECOND / 100
这就解释了为什么广播消息只有三个选通传输。
频闪持续时间为 3ms。这意味着数据速率约为 140kbps (?)。