本贴讨论代码实现架构。
1、接收侧
先说接收侧,相对发送侧简单一些。
接收消息的机制一般就分轮询(polling)和回调(callback)(或者叫事件机制(event)或中断方式(interrupt))两种方式。轮询就是定期去查看是否有消息到达,有就处理;回调就是预先设置一个回调函数,当消息到达时(事件发生)由中断服务程序(或消息调度机制)调用该回调函数。这两者各有优缺点,视具体应用需要来选择。
一般来说消息的到达是随机的(如果消息是有规律的则更适合采用轮询方式),主程序并不知道什么时候应该执行消息处理程序,因此要么定期查看,要么先设置回调函数,等待被调用。
当应用对消息处理的实时性(收到消息到开始处理之间的时间差)要求较高时,建议采用回调方式。
modRf链路层采用回调机制。先通过modRfSetRxCallback()设置回调函数,目前只允许设一个。(在Java等面向对象的高级语言中,回调函数相当于Listener类,设置回调函数相当于addListener()操作)。
当消息到达,芯片硬件产生中断,执行中服程序modRfRxFrmDoneIsr()。
1)从RF FIFO中读入分组,
2a)如果是ACK分组,判断是否正确的ACK(ACK分组本身有没有出错,ACK分组内的消息序号是否本节点正在发送的消息的序号),如果是则设置ACK收到标志;(注:802.15.4规范中的ACK分组格式中没有srcId和destId,所以如果不巧别人发的ACK中的序号和你的相同,会产生误操作)
2b)对消息分组,判断CRC校验是否正确,判断目的地址是否本节点地址或广播地址,然后将消息内容、长度及RSSI值作为输入参数传给用户提供的回调函数。
目前的协议实现中没有支持命令分组。
2、发送侧
发送消息的函数可以分为阻塞型和非阻塞型两种,阻塞型是等到发送动作有结果(可能成功可能失败)时才返回,非阻塞型是将消息加入缓冲区就返回(假如缓冲区满会返回失败)。(又,接收侧若采用轮询方式时,接收消息的函数也可以分为阻塞型和非阻塞型两种,阻塞型是等到有数据到达才返回(比如socket的read()函数),非阻塞型是没数据时返回0)
modRfSendPkt()是阻塞型的函数实现。因此不需要考虑该函数被调用时,射频是否正在发送消息的问题。
(1)不需要消息确认
不需要消息确认时,实现很简单。
1) 构造分组,将分组数据写入FIFO;
2) 执行发送:
-- 判断信道是否空闲,如果10ms内信道都不空闲,则返回失败;
-- 通知硬件发送消息(ISTXON),等待发送成功标志,如果10ms内标志没有设置,则返回失败;(注:这个10ms设得太长了,下来要改小)
(2)需要消息确认
1) 构造分组,将分组数据写入FIFO;
2) 重复以下动作一定次数(3次),如果仍不成功,则返回失败:
-- 执行发送;(内容同上(不需要ACK的2)))
-- 如果发送成功,则在3ms内等待ACK消息,如果收到则返回成功;如果未收到则延时5ms再次尝试;
-- 如果发送不成功,则延时100us再次尝试;
3、讨论
这个实现机制还是有不少问题的。比如:
(1)信道空闲后没有随机等待再次判断,会造成多个同时等信道空闲的节点同时发消息。
(2)需要ACK时,假如误码率高,发送函数的阻塞时间会较长。
(3)发送函数不能在消息接收回调函数里面调用,因为回调函数在中断服务程序的线程里。
文章评论(0条评论)
登录后参与讨论