小编觉得网上关于LoRaWAN ClassB的解读大多停留在科普阶段,再往下深入的就比较少了。所以小编从看协议到对照代码,自己有一些整理和理解,分享给大家,也欢迎同行交流指正。这篇文章需要有一些LoRaWAN ClassB的基础,如果没有到话,可以参阅小编的另一篇翻译博文《LoRaWan协议1.1 ClassB部分学习笔记》。
先修博文:《LoRaWan协议1.1 ClassB部分学习笔记》https://blog.csdn.net/yanwumuxi/article/details/107133511
协议文档参考:《lorawantm_specification_-v1.1》
开源代码:https://github.com/Lora-net/LoRaMac-node
目录
小编默认大家已经完成了“先修博文”的学习,对于ClassB类型的LoRa设备来说,在MAC层的源代码中有三个非常重要的过程:
- LoRaMacClassBProcessBeacon();
- LoRaMacClassBProcessPingSlot();
- LoRaMacClassBProcessMulticastSlot();
这篇博文重点关注第一个process,也就是关于beacon的过程。当应用层跑到DEVICE_STATE_BEACON_ACQUISITION的状态中时,mac层需要向网络服务器发两个MAC命令进行时间同步和beacon搜索,此时也将mac层状态切换到了MLME_BEACON_ACQUISITION。具体的beacon算法就在MLME_BEACON_ACQUISITION的状态中。
我们知道ClassB中有一些默认的参数,在协议里也有定义。这些参数十分的重要,因为它们决定了ClassB接收窗口时间的计算,是ClassB能够正常运行的基础。这些参数值一般不可以更改,只需要理解。
CLASSB_BEACON_RESERVED 2120
CLASSB_BEACON_GUARD 3000
CLASSB_BEACON_WINDOW 122880
CLASSB_BEACON_INTERVAL 128000
LoRaMacClassBProcessBeacon();
在这个process中就描述了关于beacon各个状态的处理。
Beacon在mac层的状态机运行过程概括
beacon的处理过程主要活动于mac层,当射频模块(物理层)搜索到beacon前导码后,mac层对设备状态进行处理,然后通知应用层。
- MAC层beacon的状态机初始状态为BEACON_STATE_ACQUISITION;
- 收到beacon,状态为BEACON_STATE_LOCKED;超过时间没收到beacon,状态为BEACON_STATE_TIMEOUT;
- 没收到beacon要重新接收,状态为BEACON_STATE_REACQUISITION;如果收到了,状态为BEACON_STATE_LOCKED;
- mac层收到了beacon时间,状态为BEACON_STATE_ACQUISITION_BY_TIME;
注:在这里,区分两个处理方法:
LoRaMacClassBIsAcquisitionInProgress();//获得同步时间,即置态BEACON_STATE_ACQUISITION_BY_TIME
LoRaMacClassBIsAcquisitionPending();//搜索beacon
- 如果beacon丢失的时间超过了2个小时,需要切换class,状态为BEACON_STATE_LOST;
- 如果进程被优先级更高的任务打断,状态为BEACON_STATE_HALT;
- 如果beacon因为有上行数据包发送而丢失了,状态为BEACON_STATE_BEACON_MISSED;
注:初始化的时候把beacon的状态置为BEACON_STATE_ACQUISITION,后来收到beacon后,就不用这个初始状态了,转为BEACON_STATE_ACQUISITION_BY_TIME,其实也是回到了初始状态,只不过这个初始状态是接收到过beacon,获取同步时间后新一轮周期的初始状态。
Beacon状态机详述
BEACON_STATE_ACQUISITION
最初状态。置该状态。
//若发现正在搜索beacon:
if(Ctx.BeaconCtx.Ctrl.AcquisitionPending == 1)
Radio.Sleep();//射频进入休眠模式。
置态-BEACON_STATE_LOST;
//若没有搜索beacon
else
ResetWindowTimeout();//设置beacon,pingslot的超时量和beacon窗口偏移量,单位为symbol。
将beacon搜索位置1;//beaconctx.ctrl.acquisitionpending=1;
RxBeaconSetup();
//若mac收到了beacon,置态BEACON_STATE_LOCKED,若没有找到,就会停留在这个状态。
BEACON_STATE_ACQUISITION_BY_TIME
收到beacon后mac层成功收到一个beacon的参考时间(即下一个beacon的下发时间),置该状态。否则停留在BEACON_STATE_ACQUISITION状态。
LoRaMacClassBIsAcquisitionPending表示正在搜索beacon的过程中(置1),如果beacon_state_locked则会置0。
//状态为收到beacon,但是:
if(Ctx.BeaconCtx.Ctrl.AcquisitionPending == 1)
置态-BEACON_STATE_LOST;
//若不在搜索beacon的状态
else
ResetWindowTimeout();//重置接收beacon的窗口时间windowtime,单位为symbol
if(BeaconDelaySet == 1)//接收到beacon,获得了下一个beacon的时间。
if(BeaconTimingDelay>0)//delay for next beacon
rtc时间校准温度补偿。
else
RxBeaconSetup(CLASSB_BEACON_RESERVED,false);//在CLASSB_BEACON_RESERVED的时间内持续接收beacon。
else//没有获得beacon的时间
置态-BEACON_STATE_ACQUISITION//状态仍然停留在BEACON_STATE_ACQUISITION
BEACON_STATE_TIMEOUT
beacon接收超时了。beacon接收失败,置该状态。
更新beacon时间;//虽然收不到beacon,时间还是要更新,向后加一个beacon周期(128s)。
EnlargeWindowTimeout();//加长接收beacon的窗口时间。
置态BEACON_STATE_REACQUISITION;//即再次接收beacon的状态。
BEACON_STATE_REACQUISITION
beacon重新接收的机制。
将beaconacquired位置0.//表示不再收到beacon,即上个beacon丢失了。
if(当前时间和最后一个接收到beacon的时间差>2小时)
置态-BEACON_STATE_LOST
else
//处理beacon丢失
rtc时间校准温度补偿;
启动PingslotTimer和MulticastSlotTimer定时器;//按自己的时间来打开接收窗口。
通知状态给上层-LORAMAC_EVENT_INFO_STATUS_BEACON_LOST;
设置beacon保护时间CLASSB_BEACON_GUARD;//在beacon_guard时间内没有pingslot打开,以避免接收冲突,确保beacon的接收。
置态-BEACON_STATE_IDLE;
BEACON_STATE_LOCKED
表示收到beacon:
Ctx.BeaconCtx.Ctrl.AcquisitionPending = 0;//将搜索beacon位置0;
更新beacon事件状态-LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED//处理beacon接收事件。
if(Ctx.LoRaMacClassBParams.LoRaMacFlags->Bits.MlmeReq == 1)//有mac命令发送
if( LoRaMacConfirmQueueIsCmdActive( MLME_BEACON_ACQUISITION ) == true )//mac命令发送成功
LoRaMacConfirmQueueSetStatus(
LORAMAC_EVENT_INFO_STATUS_OK,MLME_BEACON_ACQUISITION );
置态-BEACON_STATE_IDLE;
BEACON_STATE_IDLE
TimerGetCurrentTime();//获取rtc时间
if(Ctx.LoRaMacClassBParams.LoRaMacFlags->Bits.MlmeReq == 1)
定义beaconeventtime为下一次接收beacon的时间-设备唤醒所需要的时间。
定义currenttime为当前时间。
if(beaconeventtime>currenttime)//接收beacon时间在现时间之后(若在现时间之前就会发生异常,重新接收beacon)
置态-BEACON_STATE_GUARD;//在此时间区间没有pingslot打开。
算出beaconEventTime;//现在时间到接收beacon的时间间隔。
rtc时间校准温度补偿。
else//接收时间在现时间之前
置态-BEACON_STATE_REACQUISITION;//重新接收beacon
BEACON_STATE_GUARD
置态-BEACON_STATE_RX;
LoRaMacClassBStopRxSlots();//停止rxslot接收;
RxBeaconSetup(CLASSB_BEACON_RESERVED,false);//在CLASSB_BEACON_RESERVED时间持续接收beacon。
BEACON_STATE_LOST
if(Ctx.LoRaMacClassBParams.LoRaMacFlags->Bits.MlmeReq == 1)
if( LoRaMacConfirmQueueIsCmdActive( MLME_BEACON_ACQUISITION ) == true )
LoRaMacConfirmQueueSetStatus(
LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND,MLME_BEACON_ACQUISITION );//更新beacon事件状态。
LoRaMacClassBStopRxSlots();//停止rxslot接收;
InitClassBDefaults();//恢复classB默认设置。
小结:开源代码中的封装还是条理清晰的,从应用层的设备状态机到MAC层的MLME状态机,再到BEACON状态机。每一层都保证了上一层的一部分功能能够正常运行。