物联网LoRa系列-11:LoRa终端--基于物理层协议的PingPong应用程序的软件架构

至此,我们已经搭建好LoRa终端的软硬件开发环境,接下来,将解构和实现LoRa终端的应用程序。

LoRa终端的应用程序,(1)可以直接基于LoRa的物理层协议(LoRa芯片实现);(2)也可以基于LoRa MAC协议。

本文将介绍LoRa的终端--基于物理层协议的PingPong应用程序的软件架构

目录:

1. PingPong应用程序的模型

2. PingPong应用程序的协议栈

3. PingPong应用程序软件架构

4. PingPong软件模块的来源

5. PingPong的工程文件解读

6. PingPong应用程序的主流程图解读

7. PingPong的Master/Slave的状态机切换解读

8. LED灯控制的优化


1. PingPong应用程序的模型

上图LoRa终端PingPong应用程序的模型。

在此模型中,有两个LoRa终端节点,我们称为NodeA和NodeB;

每个节点是两个角色中的一个:Master和Slave角色。

Master负责发送或广播Ping消息,当Slave收到Ping消息后,延时10ms后,发送Pong消息作为回复。

Master在收到Slave的Pong回复消息后,延时1s,再发送下一个Ping消息。

就这样周而复始,master不断的发送Ping消息,slave不断的回复Pong消息。

Master和Slave的角色,是在消息交互过程中自动协商出来的。

当然,为了可视化PingPong的消息交互流程,在发送消息时,点亮LED, 发送完消息后,关闭LED.

由于master和slave发送消息的延时不同,因此LED灯亮的时间也不相同。

详细参考源代码。

备注:

在本案例中,只有一个灯,用于展示数据的发送和接收:在收到数据后,打开LED, 在发送完数据后,关闭LED.


2. PingPong应用程序的协议栈

在上图中,

(1)PingPong应用程序:

负责发送和接收Ping和Pong消息,Ping和Pong是两个不同的字符串消息,一个是"Ping”字符串,一个是"Pong”字符串。

同时负责根据收到Ping和Pong消息后,进行Master和Slave角色的切换。

(2)LoMAC:在该应用中,并没有实现LoRa MAC层协议,本文主要关注:如何直接通过LoRa的物理层射频层芯片SX126X发送特定的数据:ping和pong字符串。

(3)MCU驱动程序:应用程序通过MCU的驱动程序来访问LoRa SX126X芯片,用于发送和接收Ping和Pong消息。

(4)MCU单片机:所有应用程序的执行体。

(5)LoRa物理层芯片Sx126X:芯片实现LoRa协议的最底层(RF射频层和物理层协议)。

如下是LoRa物理层协议的帧结构,ping和pong字符串消息是承载在物理层的Payloa中的。

更详细的软件模块见如下:


3. PingPong应用程序软件架构

在上图中,灰色的部分不在本文讨论。


4. PingPong软件模块的来源

上述所有的软件模块,都可以由开发板供应商一次性提供,包括IAR或STDP集成开发工具的工程文件。

但我们需要知道,开发板供应商只是这些程序的集成者,他们并非所有程序的创建者,程序主要来源如下几方:

(1)STM8 MCU的芯片商:ST公司

(2)LoRa射频芯片SX1262的芯片供应商:semtech

(3)IAR和STDP集成开发环境:IAR公司或ST公司

(4)LoRa模组供应商:翱捷科技,该公司是模组代码的主要的集成者,他们集成了STM8 外设驱动 + SX126x驱动

(5)开发板提供商:成都芯域矩阵,是最终代码继承者,但95%以上的代码都不是其实现的,他们只对于开发板相关的代码进行了部分的适配。

代码模块类型代码位置

代码的提供者

PingPong应用程序..\LoRaMac-node\src\apps\ping-pong\ASR6505\main.c

semtech提供样本, 可以semtech官网获取

模组和开发板厂家只提供模板和开发板相关的适配

LoRa射频芯片驱动..\LoRaMac-node\Src\Radio\SX1626x\*.*

semtech提供样本,

模组厂家提供适配版本

操作系统级接口驱动程序..\LoRaMac-node\src\system\*.*semtech提供,屏蔽不同MCU和不同目标的差别
C语言标准库:静态库..\LoRaMac-node\src\boards\*.*IAR或ST集成工具公司提供
STM8标准外设接口驱动程序..\Libraries\STM8L15x_StdPeriph_Driver\*.*ST公司提供,可以ST官网获取
IRA软件工程或STDP..\Projects\PingPong\EWSTM8开发板供应商

5. PingPong的工程文件解读

User: 用户应用程序,LoRa Ping Pong应用程序和MAC class A, C都在此。

STM815x_StdPeriph_Driver:MCU外设接口,如SPI, I2C,timer等接口驱动。

LoRaNode: LoRa协议栈程序,包括物理层+射频层芯片Sx126x驱动程序与MAC协议程序。

Ouput:编译输出。


6. PingPong应用程序的主流程图解读

在上图汇总可以看出,

在master模式下,如果收到ping消息,说明这里有两个master,则收到Ping消息的节点,主动让出master模式,进入Slave模式;

在slave模式下,如果收到pong消息,说明这里有两个Slave,则收到Pong消息的节点,主动退出Slave模式,进入master模式。

在master模式下,如果超时没有收到slave的发来的pong响应,则master认为,slave可能没有收到master的ping,则重发ping。

在slave模式下,如果超时没有收到slave的发来的ping消息,由于ping pong应用程序是请求、响应模式,因此slave则一直等待。

这种设计有一个缺陷:

就是Master掉线之后,Slave也无法响应了,因此在测试过程中,会发现一个奇怪的现象,就是master断线后,slave也没有反应了,且此时,Slave无法切换到master模式,这是ping Pong应用程序的缺陷之一。

解决办法:

(1)重启master节点。


7. PingPong的Master/Slave的状态机切换解读

上电初始状态,每个节点默认是master模式,在启动的过程中,先发送ping的节点,就可能保持在master模式,而后启动慢一点的节点,会收到启动快一点的节点的ping消息,然后切换到slave模式。这样,就完成在启动过程中,master和slave角色的自动协商。

但这样的设计和代码实现,也有一个大的缺陷,就是如果两个节点的启动时间基本相同,发送ping报文的时间也基本相同,则两个节点在发送ping报文的过程中,都无法处于接收状态,因此无法收到对方的ping报文,导致一个很严重的测试后果:即两个节点都master状态,超时之后,持续发送ping报文,始终无法进入一个master,一个slave的ping pong效果。

下图展现了这个特殊的异常过程:

在上图中,master1和master2的启动时间相差无几,Master1正在发送ping消息的时候,master2也在发送ping消息,而RFIC收和发是不能同时进行的,在发送的时候,不能接收,在接收的时候,不能发送。

这样导致master1和master2始终处于5分钟接收Rx超时状态,超时后,两个节点,同时发送ping,同时进入接收状态,因此,任何一个节点,都无法进入slave模式。现象是:两个节点的接收LED灯都一直不闪烁,误以为程序没有执行。

错误的根本原因:

(1)设计的缺陷,未能考虑到两个节点同时发送和同时接收这样的小概率事件。

(2)发送消息时间过长,到2-3s中。ping和pong消息只有4个字节,但在代码实现是,消息的长度是64字节,后续的60字节都是填充数据。

解决的办法:

(1)重启其中一个节点,确保两个节点的发送消息的时间是错开的,即一个节点在发送,一个节点在接收。如果一次不成,多重启几次。达到如下的效果:

master2的滞后,可以使得Master1和Master2在接受和发送时是错开的,即master1在发送,master2在接受,在master2发送时,master1处于接收状态。

这样错开的结果是,master2先收到master1发送过来的ping消息,然后切换到slave模式下,然后被动等待master1的ping消息,然后被动的发送响应消息pong消息。

(2)减少发送数据包的长度,数据包的长度越长,发送的窗口的时间越长,这样master1和master2发送窗口重叠的可能就越大。减少发送数据包的长度,降低发送窗口的长度,降低问题出现的概率,但不能根除。

(3)加大接收超时定时器,目前的接收超时定时器是5分钟,加大该定时器,实际上就是加大接收窗口的长度。这样可以降低问题出现的概率,但不能根除。

(4)设计上解决:在接收超时后,采用随机的延时发送ping报文,而不是固定的延时,或立即发送。但这需要MCU提供随机延时的功能。


8.  LED显示的优化

为了展示RFIC发送64字节的数据需要较长的时间,我们可以优化LED的显示。

(1)当前的LED显示的代码逻辑:

        case RX:
            if( isMaster == true ) //master
            {
                if( BufferSize > 0 )
                {
                    if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 )
                    {                        
                        printf("Master Received: PONG\r\n");

                        // Send the next PING frame
                        /* LED TX ON */
                        GPIO_LOW(LED_TX_PORT,LED_TX_PIN);  //打开LED

                        Buffer[0] = 'P';
                        Buffer[1] = 'I';
                        Buffer[2] = 'N';
                        Buffer[3] = 'G';
                        // We fill the buffer with numbers for the payload
                        for( i = 4; i < BufferSize; i++ )
                        {
                            Buffer[i] = i - 4;
                        }
                        DelayMs(1000);
                        printf("Master Sent: PING\r\n");
                        Radio.Send( Buffer, BufferSize );  //请求射频芯片发送ping消息。
                        /* LED TX OFF */
                        GPIO_HIGH(LED_TX_PORT,LED_TX_PIN); //关闭LED
                    }

                 }         

           else  //Slave模式
            {
                if( BufferSize > 0 )
                {
                    if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 )
                    {
                        printf("Slave Received: PING\r\n");
                        printf("Slave Rssi: %d\r\n", RssiValue);
                        printf("Slave Snr: %d\r\n",  SnrValue);
                        // Send the reply to the PONG string
                        /* LED TX ON */
                        GPIO_LOW(LED_TX_PORT,LED_TX_PIN);  //打开LED
                        Buffer[0] = 'P';
                        Buffer[1] = 'O';
                        Buffer[2] = 'N';
                        Buffer[3] = 'G';
                        // We fill the buffer with numbers for the payload
                        for( i = 4; i < BufferSize; i++ )
                        {
                            Buffer[i] = i - 4;
                        }
                        DelayMs(1);
                        Radio.Send( Buffer, BufferSize );    //请求射频芯片发送ping消息。
                        printf("Slave Sent: PONG\r\n");
                        /* LED TX OFF */
                        GPIO_HIGH(LED_TX_PORT,LED_TX_PIN); //关闭LED
                    }

(2)当前的LED显示的优化逻辑

把LED灯的关闭时间点,推迟到射频芯片发送完完整的消息之后。

        case TX:  //射频芯片发送完成

             GPIO_HIGH(LED_TX_PORT,LED_TX_PIN); //关闭LED
             //turn Rx on as soon as possible
             Radio.Rx( RX_TIMEOUT_VALUE );

        case TX_TIMEOUT: //射频芯片发送出错,或发送被打断。

              GPIO_HIGH(LED_TX_PORT,LED_TX_PIN); //关闭LED

通过LED等的亮度时间,就可以清晰地知道:

射频芯片什么时候处于发送状态,发送数据。

什么时候,处于接收状态,等待接受消息。


结束语:

至此,我们可以利用开发板提供商提供的软件工程代码,能够进行两个LoRa节点间,点对点通信。

两个LoRa节点直接利用的是LoRa芯片提供的物理层的功能。ping和pong消息是直接承载在LoRa的物理成的帧结构中。

后续会进一步深入拆解LoRa物理层的功能和原理:包括物理层的编码、调制解调、天线、电磁波频频等概念与原理。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文火冰糖的硅基工坊

你的鼓励是我前进的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值