diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/README.md b/APP_Framework/Applications/app_test/test_lora_net_final/README.md
new file mode 100755
index 000000000..f74ac38f5
--- /dev/null
+++ b/APP_Framework/Applications/app_test/test_lora_net_final/README.md
@@ -0,0 +1,187 @@
+# 基于初赛二级赛题1,实现多个LoRa节点和LoRa网关通信私有协议
+## 1. 简介
+基于 E220-400T22S Lora模块设计实现通信私有协议,主要包含以下几个方面:
+- 协议实现完全遵循LoRa Adapter代码规范,可以直接使用原有的Adapter相关函数基于本协议构建Lora网络。
+- 重新设计实现E220底层函数,增加了IOCTL函数实现,支持在运行时对地址、信道、通信模式、空中速率等参数的动态配置。
+- E220模块只支持单通道通信,本协议基于定向传输模式实现了多下行信道通信。
+- 支持数据帧完整性校验、支持数据帧丢失或者跳帧检测。
+- 支持节点断网自动重联,在数据发送失败时可以进行重联或者搜索其他网关。
+- 支持节点对网关的搜索,可以主动寻找在线网关入网。
+- 支持信道冲突检测,检测上行通道是否占用。
+## 2. 数据结构说明
+### E220模块相关数据结构
+
+```c
+enum LoraMode // E220工作模式,支持四种,配置模式与休眠模式一致
+{
+ MODE_TRANSFER_MODE = 0, // M0 : M1 = 0 : 0 可发可收
+ MODE_WOR_SEND, // M0 : M1 = 1 : 0 可发可收
+ MODE_WOR_RECV, // M0 : M1 = 0 : 1 可收不发
+ MODE_CONFIG_SLEEP // M0 : M1 = 1 : 1 不收不发
+};
+
+enum LoraState // 硬件状态
+{
+ STATE_CLOSED, // 硬件关闭
+ STATE_OPENED, // 已正常开启
+ STATE_BROKEN // 硬件损坏
+};
+
+enum LoraTransMode // 模块传输模式
+{
+ TRANS_MODE_HYALINE = 0X0, // 透明传输
+ TRANS_MODE_ORIENTED = 0X40, // 定点传输
+};
+
+enum LoraAirRate // 空中速率,通信双方必须设置一致的空中速率方可进行通信
+{
+ AIR_RATE_2D4K = 0X0, // 2.4K
+ AIR_RATE_4D8K = 0X3, // 4.8K
+ AIR_RATE_9D6K = 0X4, // 9.6K
+ AIR_RATE_19D2K = 0X5, // 19.2K
+ AIR_RATE_38D4K = 0X6, // 38.4K
+ AIR_RATE_62D5K = 0X7 // 62.5K
+};
+
+enum LoraConfig // 支持IOCTL函数进行配置的配置项枚举,某些项只支持9600波特率配置
+{
+ CONFIG_SERIAL_TIME_OUT = 0X0, // 串口超时时间
+ CONFIG_LORA_MODE = 0X1, // 配置Lora模式
+ CONFIG_TRANS_MODE = 0X2, // 配置Lora传输模式(9600)
+ CONFIG_AIR_RATE = 0X3, // 配置空中速率(9600)
+ CONFIG_BAUD_RATE = 0X4, // 配置波特率
+ CONFIG_ADDRESS = 0X5, // 配置设备地址(9600)
+ CONFIG_CHANNEL = 0X6, // 配置设备信道(9600)
+ CONFIG_SHOW = 0X7 // 打印配置信息
+};
+```
+
+### 数据帧相关数据结构
+
+```c
+enum FrameType // 数据帧类型枚举
+{
+ E_G_JOIN = 0, // 客户端入网请求,需回复
+ E_G_QUIT, // 客户端退网请求,不需回复
+ E_G_DATA, // 客户端上传数据,需回复
+ G_E_ANS, // 网关响应客户端请求
+};
+
+struct LoraFrame // 数据帧消息类型
+{
+ uint16 begin_mark; // 开始标志 0x3C3C
+ uint16 session_id; // 会话ID,客户端每次数据上传会随机设置,若是回复ID不一致则表示数据丢失
+ uint16 dev_addr; // 设备地址,特指终端地址,网关地址固定为 0XFFFF
+ uint8 down_channel; // 下行通道,即终端所在的信道
+ uint8 frame_type; // 数据帧的类型
+ uint8 frame_confirm; // 该数据帧是否需要确认回复
+ uint8 frame_attach; // 用于携带简单的数据,例如用户数据长度
+ uint8 *user_data; // 需要额外携带的大量数据
+ uint8 crc_hi; // 校验位高字节
+ uint8 crc_lo; // 校验位低字节
+ uint16 end_mark; // 结束标志 0X5A5A
+};
+```
+
+### Lora节点相关数据结构
+
+```c
+enum EndNodeState //节点状态
+{
+ NODE_STATE_DISCONNECT = 0, // 硬件开启,但是没有联网,后台程序可能开启
+ NODE_STATE_CONNECT, // 硬件开启,已经联网,后台程序可能开启
+ NODE_STATE_BROKEN, // 硬件损坏,无后台程序
+ NODE_STATE_CLOSED // 硬件关闭,无后台程序
+};
+
+struct EndNodeParam // 节点参数结构
+{
+ uint16 dev_addr; // 设备地址信息
+ uint8 down_channel; // 下行通道,终端可以接收信息的信道
+ uint8 upload_channel; // 上行通道,终端可以给网关发送信息的信道
+ uint16 session_id; // 会话ID,用于判定数据帧是否存在丢失
+
+ enum EndNodeState node_state; // 客户端状态
+ enum LoraAirRate air_rate; // 终端的空中速率
+ uint8 adr_enable; // 终端是否开启自动寻找上行网关
+ uint8 reconnect_enable; // 终端断网自动重联
+ uint8 recv_time; // 接受下行消息的时间窗口长度,单位为秒
+};
+```
+
+### Lora网关相关数据结构
+
+```c
+struct EndNodeInfo // 网关存储的客户端信息
+{
+ uint16 node_addr; // 客户端地址
+ uint8 node_down_channel; // 客户端下行通道
+ uint16 session_id; // 上一个命令的会话ID
+};
+
+enum GatewayState // 网关的状态枚举
+{
+ GATEWAY_CLOSED, // Lora还没有打开
+ GATEWAY_OPENED, // 已打开,但是未开始工作
+ GATEWAY_WORKING, // 正常打开且已经开始正常工作
+ GATEWAY_BROKEN // 模块损坏
+};
+
+struct GatewayParam // 网关参数
+{
+ uint16 dev_addr; // 设备ID
+ uint8 channel; // 网络编号
+
+ int recv_time; // 串口超时时间
+ enum LoraAirRate air_rate; // 网关空中速率
+ uint8 frame_retry; // 重传次数
+ enum GatewayState gateway_state; // 网关状态
+ struct EndNodeInfo *node_infos[LORA_GATEWAY_MAX_NODE]; // 客户端信息
+ uint16 node_count; // 已链接客户端数量
+};
+```
+
+## 3. 测试程序说明
+- 编译烧录两个不同地址、信道的客户端和一个网关。
+- 分别打开客户端和网关并联网。
+- 两个客户端分别向网关发送数据。
+## 4. 运行结果
+### (1)编译模块:
+- 配置MENUCONFIG
+
+> 开启连接框架支持,同时开启Lora Adapter支持
+
+
+> 选择E220模块
+
+
+> 开启测试函数
+
+
+> 测试单通道网关
+
+- 修改MakeFile:xiuos/APP_Framework/Applications/app_test/Makefile第141行修改为
+```c
+ SRC_FILES += test_lora_net_final/lora_driver/e220.c
+ SRC_FILES += test_lora_net_final/lora_mac/lora_mac.c
+ SRC_FILES += test_lora_net_final/test_lora_net_final.c
+```
+- 修改框架初始函数:
+> 1. 文件:xiuos/APP_Framework/Framework/framework_init.c 第27行修改为
extern int UsrAdapterLoraInit(void);
+> 2. 文件:xiuos/APP_Framework/Framework/framework_init.c 第170行的AdapterLoraInit修改为UsrAdapterLoraInit
+### (2)打开网关
+
+> 网关打开,地址OXFFFF,信道OXA,空中速率2.4K
+
+### (3)客户端连接网关
+
+> 两边客户端同时发送入网请求,可以看见信道检测效果
+
+### (4)客户端发送数据
+
+> 客户端向网关发送数据
+
+
+> 两边客户端同时发送数据
+
+使用自带的天线,2.4K空中速率,载荷64字节,在无大型遮盖物的情况下传输距离近1500米
\ No newline at end of file
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/images/0-1.png b/APP_Framework/Applications/app_test/test_lora_net_final/images/0-1.png
new file mode 100755
index 000000000..e3e3a8e74
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_net_final/images/0-1.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/images/0-2.png b/APP_Framework/Applications/app_test/test_lora_net_final/images/0-2.png
new file mode 100755
index 000000000..a24c14716
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_net_final/images/0-2.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/images/0-3.png b/APP_Framework/Applications/app_test/test_lora_net_final/images/0-3.png
new file mode 100755
index 000000000..544c91b43
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_net_final/images/0-3.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/images/0-4.png b/APP_Framework/Applications/app_test/test_lora_net_final/images/0-4.png
new file mode 100755
index 000000000..954d436c8
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_net_final/images/0-4.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/images/1.png b/APP_Framework/Applications/app_test/test_lora_net_final/images/1.png
new file mode 100755
index 000000000..77b3a5e7f
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_net_final/images/1.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/images/2.png b/APP_Framework/Applications/app_test/test_lora_net_final/images/2.png
new file mode 100755
index 000000000..4675aef37
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_net_final/images/2.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/images/3.png b/APP_Framework/Applications/app_test/test_lora_net_final/images/3.png
new file mode 100755
index 000000000..337d3de50
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_net_final/images/3.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/images/4.png b/APP_Framework/Applications/app_test/test_lora_net_final/images/4.png
new file mode 100755
index 000000000..a28da7bad
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_net_final/images/4.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/lora_driver/e220.c b/APP_Framework/Applications/app_test/test_lora_net_final/lora_driver/e220.c
new file mode 100755
index 000000000..cff76d97a
--- /dev/null
+++ b/APP_Framework/Applications/app_test/test_lora_net_final/lora_driver/e220.c
@@ -0,0 +1,570 @@
+#include "e220.h"
+
+struct RegisterCfg // 寄存器结构
+{
+ uint8 ADDH;
+ uint8 ADDL; // 地址
+ uint8 REG0; // 波特率/串口校验/空中速率
+ uint8 REG1; // 分包设定/RSSI环境噪声/发射功率
+ uint8 REG2; // 信道
+ uint8 REG3; // RSSI字节/传输方式/LBT使能/WOR周期
+ uint8 KEYH;
+ uint8 KEYL; // 密钥
+};
+
+/**
+ * 默认的寄存器配置信息,在每次配置更新后会同步更新该数据,保持其与硬件寄存器数据的一致性
+*/
+static struct RegisterCfg register_cfg =
+{
+ .ADDH = (E220_ADDRESS >> 8) & 0XFF,
+ .ADDL = E220_ADDRESS & 0XFF,
+ .REG0 = E220_DEFAULT_CONFIG_BAUD_RATE_BYTE | E220_DEFAULT_AIR_RATE,
+ .REG1 = 0X0,
+ .REG2 = E220_DEFAULT_CHANNEL,
+ .REG3 = E220_DEFAULT_TRANS_MODE,
+ .KEYH = 0X0,
+ .KEYL = 0X0,
+};
+
+/**
+ * 默认的串口配置信息,初始化时波特率为9600,保持与硬件一致,在波特率更改过程中也需要保证一致
+*/
+static struct SerialDataCfg serial_cfg =
+{
+ .serial_baud_rate = E220_DEFAULT_CONFIG_BAUD_RATE, // 串口波特率
+ .serial_data_bits = DATA_BITS_8,
+ .serial_stop_bits = STOP_BITS_1,
+ .serial_parity_mode = PARITY_NONE,
+ .serial_bit_order = BIT_ORDER_LSB,
+ .serial_invert_mode = NRZ_NORMAL,
+ .serial_buffer_size = SERIAL_RB_BUFSZ,
+ .serial_timeout = E220_DAFAULT_SERIAL_TIMEOUT, // 串口超时配置
+ .is_ext_uart = 0,
+};
+
+enum LoraMode current_mode = -1; // 当前模块处于什么模式
+enum LoraState lora_state = STATE_CLOSED; // 当前模块的状态
+uint8 lora_init = E220_NO; // 当前模块是否已经被初始化过了
+
+/**
+ * @brief: 将硬件切换至指定的模式
+ * @param mode: 支持休眠/配置模式 和 传输模式
+*/
+static uint8 E220LoraModeConfig(enum LoraMode mode)
+{
+ // 模式和状态判断
+ if (lora_state == STATE_BROKEN)
+ {
+ DDBG("E220LoraModeConfig-Fail: lora broken!\n");
+ return -1;
+ }
+ if(mode == current_mode)
+ {
+ // 同一个模式直接返回,不输出信息
+ return 0;
+ }
+ // 打开PIN驱动
+ int pin_fd = PrivOpen(E220_PIN_DRIVER,O_RDWR);
+ if (pin_fd < 0)
+ {
+ DDBG("E220LoraModeConfig-Fail: open pin driver fail %s!\n",E220_PIN_DRIVER);
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ // 配置管脚属性
+ struct PinParam pin_param ={.cmd = GPIO_CONFIG_MODE,.mode = GPIO_CFG_OUTPUT,.pin = E220_M0_PATH};
+ struct PrivIoctlCfg ioctl_config = {.ioctl_driver_type = PIN_TYPE, .args = &pin_param};
+ if (0 != PrivIoctl(pin_fd,OPE_CFG,&ioctl_config))
+ {
+ DDBG("E220LoraModeConfig-Fail: config m0 fail!\n");
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ pin_param.pin = E220_M1_PATH;
+ ioctl_config.args = &pin_param;
+ if (0 != PrivIoctl(pin_fd,OPE_CFG,&ioctl_config))
+ {
+ DDBG("E220LoraModeConfig-Fail: config m1 fail!\n");
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+
+ struct PinStat pin_stat;
+ switch (mode)
+ {
+ case MODE_TRANSFER_MODE:
+ {
+ pin_stat.pin = E220_M0_PATH;
+ pin_stat.val = GPIO_LOW;
+ if (-1 == PrivWrite(pin_fd, &pin_stat, 1))
+ {
+ DDBG("E220LoraModeConfig-Fail: config m0 low fail!\n");
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ pin_stat.pin = E220_M1_PATH;
+ pin_stat.val = GPIO_LOW;
+ if (-1 == PrivWrite(pin_fd, &pin_stat, 1))
+ {
+ DDBG("E220LoraModeConfig-Fail: config m1 low fail!\n");
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ break;
+ }
+ case MODE_CONFIG_SLEEP:
+ {
+ pin_stat.pin = E220_M0_PATH;
+ pin_stat.val = GPIO_HIGH;
+ if (-1 == PrivWrite(pin_fd, &pin_stat, 1))
+ {
+ DDBG("E220LoraModeConfig-Fail: config m0 high fail!\n");
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ pin_stat.pin = E220_M1_PATH;
+ pin_stat.val = GPIO_HIGH;
+ if (-1 == PrivWrite(pin_fd, &pin_stat, 1))
+ {
+ DDBG("E220LoraModeConfig-Fail: config m1 high fail!\n");
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ break;
+ }
+ default:
+ DDBG("E220LoraModeConfig-Fail: unsupported lora mode!\n");
+ PrivClose(pin_fd);
+ return -1;
+ }
+ PrivTaskDelay(E220_CONFIG_DELAY);
+ PrivClose(pin_fd);
+ // 记录当前模式,避免不必要的重复配置
+ current_mode = mode;
+ DDBG("E220LoraModeConfig-Success: change to mode %s !\n",mode == MODE_CONFIG_SLEEP ? "MODE_CONFIG_SLEEP" : "MODE_TRANSFER_MODE");
+ return 0;
+}
+
+/**
+ * @brief: 通过指令获取硬件寄存器参数后将其保存并输出
+ * @param adapter: 需要打开
+*/
+static void PrintRegister(char* prefix)
+{
+ // 打印数据
+ DDBG("%s Register:",prefix);
+ DDBG("ADDH:%X,ADDL:%X,REG0:%X,",register_cfg.ADDH,register_cfg.ADDL,register_cfg.REG0);
+ DDBG("REG1:%X,REG2:%X,REG3:%X,",register_cfg.REG1,register_cfg.REG2,register_cfg.REG3);
+ DDBG("KEYH:%X,KEYL:%X\n",register_cfg.KEYH,register_cfg.KEYL);
+}
+
+/**
+ * @brief: 根据配置的数据覆写硬件寄存器参数
+ * @param adapter: 一个已经打开了UART串口的Lora硬件
+ * @param start_addr: 需要覆写的寄存器起始地址
+ * @param byte_length: 需要覆写的寄存器数量
+ * @param args: 需要覆写的寄存器参数
+ * @return: 0 -> Success; -1 -> Fail
+*/
+static uint8 WriteRegister(struct Adapter *adapter,uint8 start_addr,uint8 byte_length,void* args)
+{
+ if (STATE_BROKEN == lora_state)
+ {
+ DDBG("WriteRegister-Fail: lora broken!\n");
+ return -1;
+ }
+ // 切换硬件到配置模式
+ E220LoraModeConfig(MODE_CONFIG_SLEEP);
+ // 构造寄存器覆写数据
+ uint8 buffer[11] = {0};
+ buffer[0] = 0XC0;
+ buffer[1] = start_addr;
+ buffer[2] = byte_length;
+ memcpy(&buffer[3],args,byte_length);
+ // 覆写寄存器参数
+ if (PrivWrite(adapter->fd, (void *)buffer, byte_length + 3) < 0)
+ {
+ PrintRegister("WriteRegister-Fail");
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ // 等待配置完成后读取回写数据
+ PrivTaskDelay(E220_CONFIG_DELAY);
+ PrivRead(adapter->fd, buffer, byte_length + 3);
+ PrintRegister("WriteRegister-Success");
+ return 0;
+}
+
+/**
+ * @brief: 根据默认的配置对一个已经打开UART串口的Lora硬件进行寄存器参数的初始化,开启后只会被调用一次
+ * @param adapter: 需要打开
+*/
+static uint8 E220RegisterInit(struct Adapter *adapter)
+{
+ if(STATE_BROKEN == lora_state)
+ {
+ DDBG("E220RegisterInit-Fail: lora broken!\n");
+ return -1;
+ }
+ if (lora_init == E220_YES)
+ {
+ DDBG("E220RegisterInit-Success: inited before!\n");
+ return 0;
+ }
+ // 按照默认的参数进行寄存器初始化
+ if (0 != WriteRegister(adapter,0X0,0X8,®ister_cfg))
+ {
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ // 防止重复初始化
+ lora_init = E220_YES;
+ DDBG("E220RegisterConfig-Success!\n");
+ return 0;
+}
+
+uint8 E220Open(struct Adapter *adapter)
+{
+ if (lora_state == STATE_BROKEN)
+ {
+ DDBG("E220Open-Fail: lora broken!\n");
+ return -1;
+ }
+ if (lora_state == STATE_OPENED)
+ {
+ // 避免重复打开
+ return 0;
+ }
+ // 打开UART串口
+ adapter->fd = PrivOpen(E220_UART_DRIVER,O_RDWR);
+ if (adapter->fd < 0)
+ {
+ DDBG("E220Open-Fail: open uart fail - %s \n",E220_UART_DRIVER);
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ // 按照默认串口配置信息初始化串口
+ struct PrivIoctlCfg ioctl_cfg;
+ ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
+ ioctl_cfg.args = &serial_cfg;
+ if (0 != PrivIoctl(adapter->fd, OPE_INT,&ioctl_cfg))
+ {
+ DDBG("E220Open-Fail: uart config fail - %s \n",E220_UART_DRIVER);
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ // 硬件的寄存器初始化
+ if (0 != E220RegisterInit(adapter))
+ {
+ DDBG("E220Open-Fail: register config fail!\n");
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ lora_state = STATE_OPENED;
+ DDBG("E220Open-Success: e220 open success!\n");
+ return 0;
+}
+
+uint8 E220Close(struct Adapter *adapter)
+{
+ if (lora_state != STATE_OPENED)
+ {
+ DDBG("E220Close-Success: broken or closed before!\n");
+ return 0;
+ }
+ // 关闭UART串口
+ if (adapter->fd > 0)
+ {
+ if (0 != PrivClose(adapter->fd))
+ {
+ DDBG("E220Close-Failed: result != 0\n");
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ }
+ adapter->fd = -1;
+ lora_init = E220_NO;
+ lora_state = STATE_CLOSED;
+ DDBG("E220Close-Success: success!\n");
+ return 0;
+}
+
+uint8 E220Ioctl(struct Adapter *adapter, int config_item, void *args)
+{
+ if (STATE_OPENED != lora_state)
+ {
+ DDBG("E220Ioctl-Fail: open lora or the lora is broken!\n");
+ return -1;
+ }
+ switch (config_item)
+ {
+ // 配置Lora串口超时时间
+ case CONFIG_SERIAL_TIME_OUT:
+ {
+ int32 time_out = *((int32*)args);
+ if (time_out == serial_cfg.serial_timeout)
+ {
+ DDBG("ConfigSerialTimeOut-Success: the same time_out %d !\n", time_out);
+ return 0;
+ }
+
+ serial_cfg.serial_timeout = time_out;
+ struct PrivIoctlCfg ioctl_cfg = { .ioctl_driver_type = SERIAL_TYPE,.args = &serial_cfg };
+ // 修改串口配置信息
+ if (0 != PrivIoctl(adapter->fd, OPE_INT, &ioctl_cfg))
+ {
+ DDBG("ConfigSerialTimeOut-Fail: %d\n", serial_cfg.serial_timeout);
+ lora_state = STATE_BROKEN;
+ return -1;
+ }
+ DDBG("ConfigSerialTimeOut-Success: %d\n", serial_cfg.serial_timeout);
+ return 0;
+ }
+ // 配置Lora模式
+ case CONFIG_LORA_MODE:
+ {
+ enum LoraMode mode = *((enum LoraMode*)args);
+ if (mode == current_mode)
+ {
+ DDBG("ConfigLoraMode-Success: the same mode %s!\n",mode == MODE_TRANSFER_MODE ? "MODE_TRANSFER_MODE" : "MODE_CONFIG_SLEEP");
+ return 0;
+ }
+ if (mode == MODE_TRANSFER_MODE || mode == MODE_CONFIG_SLEEP)
+ {
+ if (0 != E220LoraModeConfig(mode))
+ {
+ DDBG("ConfigLoraMode-Fail: config mode fail %s!\n",mode == MODE_TRANSFER_MODE ? "MODE_TRANSFER_MODE" : "MODE_CONFIG_SLEEP");
+ return -1;
+ }
+ DDBG("ConfigLoraMode-Success: change lora mode to %s!\n",mode == MODE_TRANSFER_MODE ? "MODE_TRANSFER_MODE" : "MODE_CONFIG_SLEEP");
+ return 0;
+ }
+ DDBG("ConfigLoraMode-Fail: unsupported lora mode %x!\n",mode);
+ return -1;
+ }
+ // 配置Lora传输模式
+ case CONFIG_TRANS_MODE:
+ {
+ if (serial_cfg.serial_baud_rate != E220_DEFAULT_CONFIG_BAUD_RATE)
+ {
+ DDBG("ConfigTransMode-Fail: only config by baud rate 9600!\n");
+ return -1;
+ }
+ uint8 trans_mode = *((uint8*)args);
+ if (trans_mode == TRANS_MODE_HYALINE || trans_mode == TRANS_MODE_ORIENTED)
+ {
+ // 判断参数是否有必要覆写
+ if (register_cfg.REG3 & 0X40 == trans_mode)
+ {
+ DDBG("ConfigTransMode-Success: the same trans mode %x!\n",trans_mode);
+ return 0;
+ }
+ trans_mode = register_cfg.REG3 & 0xBF | trans_mode;
+ if (0 != WriteRegister(adapter,0X5,1,&trans_mode))
+ {
+ lora_state = STATE_BROKEN;
+ DDBG("ConfigTransMode-Fail: config trans mode fail %x!\n",trans_mode);
+ return -1;
+ }
+ register_cfg.REG3 = trans_mode;
+ DDBG("ConfigTransMode-Success: config trans mode success %x!\n",trans_mode);
+ return 0;
+ }
+ DDBG("ConfigTransMode-Fail: unsupported trans mode %x!\n",trans_mode);
+ return -1;
+ }
+ // 配置Lora空中速率
+ case CONFIG_AIR_RATE:
+ {
+ if (serial_cfg.serial_baud_rate != E220_DEFAULT_CONFIG_BAUD_RATE)
+ {
+ DDBG("ConfigAirRate-Fail: only config by baud rate 9600!\n");
+ return -1;
+ }
+ uint8 air_rate = *((uint8*)args);
+ if (air_rate >= AIR_RATE_2D4K && air_rate <= AIR_RATE_62D5K)
+ {
+ // 判断参数是否有必要覆写
+ if (register_cfg.REG0 & 0X7 == air_rate)
+ {
+ DDBG("ConfigAirRate-Success: the same air rate %x!\n",air_rate);
+ return 0;
+ }
+ air_rate = ((register_cfg.REG0 >> 3) << 3) | air_rate;
+ if (0 != WriteRegister(adapter,0X2,1,&air_rate))
+ {
+ lora_state = STATE_BROKEN;
+ DDBG("ConfigAirRate-Fail: write register fail %x!\n",air_rate);
+ return -1;
+ }
+ register_cfg.REG0 = air_rate;
+ DDBG("ConfigAirRate-Success: config air rate success %x!\n",air_rate & 0X7);
+ return 0;
+ }
+ DDBG("ConfigAirRate-Fail: unsupported air rate %x!\n",air_rate);
+ return -1;
+ }
+ // 配置Lora的波特率
+ case CONFIG_BAUD_RATE:
+ {
+ uint8 arg_rate = *((uint8*)args);
+ uint8 temp_rate = arg_rate;
+ if (arg_rate == E220_DEFAULT_CONFIG_BAUD_RATE_BYTE || arg_rate == E220_DEFAULT_USED_BAUD_RATE_BYTE)
+ {
+ // 判断参数是否有必要覆写
+ if (register_cfg.REG0 & 0XE0 == arg_rate)
+ {
+ DDBG("ConfigBaudRate-Success: the same baud rate %x!\n",arg_rate);
+ return 0;
+ }
+ temp_rate = register_cfg.REG0 & 0X1F | arg_rate;
+ // 先更改寄存器的波特率
+ if (0 != WriteRegister(adapter,0X2,1,&temp_rate))
+ {
+ lora_state = STATE_BROKEN;
+ DDBG("ConfigBaudRate-Fail: write register config fail %x!\n",temp_rate);
+ return -1;
+ }
+ register_cfg.REG0 = temp_rate;
+ // 重新配置串口波特率
+ serial_cfg.serial_baud_rate = arg_rate == E220_DEFAULT_CONFIG_BAUD_RATE_BYTE ? BAUD_RATE_9600 : BAUD_RATE_115200;
+ struct PrivIoctlCfg ioctl_cfg;
+ ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
+ ioctl_cfg.args = &serial_cfg;
+ // 重新配置串口波特率
+ if (0 != PrivIoctl(adapter->fd, OPE_INT, &ioctl_cfg))
+ {
+ lora_state = STATE_BROKEN;
+ DDBG("ConfigBaudRate-Fail: config serail fail %x!\n",temp_rate);
+ return -1;
+ }
+ DDBG("ConfigBaudRate-Success: config baud rate success %d !\n",arg_rate == E220_DEFAULT_CONFIG_BAUD_RATE_BYTE ? BAUD_RATE_9600 : BAUD_RATE_115200);
+ return 0;
+ }
+ DDBG("ConfigBaudRate-Fail: unsupported baud rate %x!\n",arg_rate);
+ return -1;
+ }
+ // 配置Lora地址参数
+ case CONFIG_ADDRESS:
+ {
+ if (serial_cfg.serial_baud_rate != E220_DEFAULT_CONFIG_BAUD_RATE)
+ {
+ DDBG("ConfigAddress-Fail: only config by baud rate 9600!\n");
+ return -1;
+ }
+ uint16 address = *((uint16*)args);
+ if ((address >> 8) | 0XFF == register_cfg.ADDH && address & 0XFF == register_cfg.ADDL)
+ {
+ DDBG("ConfigAddress-Success: the same address %d!\n",address);
+ return 0;
+ }
+ register_cfg.ADDH = (address >> 8) & 0XFF;
+ register_cfg.ADDL = address & 0XFF;
+ if (0 != WriteRegister(adapter,0X0,2,®ister_cfg))
+ {
+ lora_state = STATE_BROKEN;
+ DDBG("ConfigAddress-Fail: write register fail %d!\n",address);
+ return -1;
+ }
+ DDBG("ConfigAddress-Success: config address success %d!\n",address);
+ return 0;
+ }
+ // 配置Lora信道参数
+ case CONFIG_CHANNEL:
+ {
+ if (serial_cfg.serial_baud_rate != E220_DEFAULT_CONFIG_BAUD_RATE)
+ {
+ DDBG("ConfigChannel-Fail: only config by baud rate 9600!\n");
+ return -1;
+ }
+ uint8 channel = *((uint8*)args);
+ if (channel <= E220_MAX_CHANNEL_NUMBER)
+ {
+ if (register_cfg.REG2 == channel)
+ {
+ DDBG("ConfigChannel-Success: the same channel %d!\n",channel);
+ return 0;
+ }
+ register_cfg.REG2 = channel;
+ if (0 != WriteRegister(adapter,0X4,1,®ister_cfg.REG2))
+ {
+ lora_state = STATE_BROKEN;
+ DDBG("ConfigChannel-Fail: write register fail %d!\n",channel);
+ return -1;
+ }
+ DDBG("ConfigChannel-Success: config channel success %X !\n",channel);
+ return 0;
+ }
+ DDBG("ConfigChannel-Fail: unsupported channel %d!\n",channel);
+ return -1;
+ }
+ // 打印配置信息
+ case CONFIG_SHOW:
+ {
+ DDBG("ConfigShow SerailTime: %d",serial_cfg.serial_timeout);
+ PrintRegister("CONFIG_SHOW");
+ return 0;
+ }
+ default:
+ DDBG("E220Ioctl-Failed: config item unsupported %d!\n",config_item);
+ return -1;
+ }
+}
+
+uint8 E220Send(struct Adapter *adapter, const void *buf, uint32 len)
+{
+ if (STATE_OPENED != lora_state)
+ {
+ DDBG("E220Send-Fail: open lora before send data!\n");
+ return -1;
+ }
+ // 切换至传输模式
+ if (0 != E220LoraModeConfig(MODE_TRANSFER_MODE))
+ {
+ DDBG("E220Send-Fail: change mode transfer fail!\n");
+ return -1;
+ }
+
+ if (len != PrivWrite(adapter->fd, (void *)buf, len))
+ {
+ DDBG("E220Send-Fail: send data fail!\n");
+ return -1;
+ }
+ return 0;
+}
+
+uint8 E220Recv(struct Adapter *adapter, void *buf, uint32 len)
+{
+ if (STATE_OPENED != lora_state)
+ {
+ DDBG("E220Recv-Fail: open lora before recv!\n");
+ return -1;
+ }
+ // 确保传输模式
+ if (0 != E220LoraModeConfig(MODE_TRANSFER_MODE))
+ {
+ return -1;
+ }
+
+ int recv_len = 0, recv_len_continue = 0;
+
+ uint8 *recv_buf = PrivMalloc(len);
+ // 读取数据并返回已读取数据量
+ recv_len = PrivRead(adapter->fd, recv_buf, len);
+ if (recv_len) {
+ while (recv_len < len) {
+ // 读取超时后退出循环
+ recv_len_continue = PrivRead(adapter->fd, recv_buf + recv_len, len - recv_len);
+ if (recv_len_continue) {
+ recv_len += recv_len_continue;
+ } else {
+ recv_len = 0;
+ break;
+ }
+ }
+ memcpy(buf, recv_buf, len);
+ }
+ PrivFree(recv_buf);
+ return recv_len;
+}
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/lora_driver/e220.h b/APP_Framework/Applications/app_test/test_lora_net_final/lora_driver/e220.h
new file mode 100755
index 000000000..87ef4d0e8
--- /dev/null
+++ b/APP_Framework/Applications/app_test/test_lora_net_final/lora_driver/e220.h
@@ -0,0 +1,125 @@
+#include
+#include
+
+#ifndef __E220_H__
+#define __E220_H__
+
+// #define __DRIVER_DEBUG__ // 驱动调试信息输出开关
+#ifdef __DRIVER_DEBUG__
+#define DDBG(format,...) printf(format, ##__VA_ARGS__)
+#else
+#define DDBG(format,...)
+#endif // __DRIVER_DEBUG__
+
+#define E220_M0_PATH 32 // M0管脚位置
+#define E220_M1_PATH 33 // M1管脚位置
+#define E220_PIN_DRIVER "/dev/pin_dev" // PIN驱动名称
+#define E220_UART_DRIVER "/dev/uart2_dev2" // UART驱动名称
+#define E220_ADDRESS 0XA // 地址默认值
+#define E220_DAFAULT_SERIAL_TIMEOUT 3000 // 串口默认3S超时
+#define E220_DEFAULT_CONFIG_BAUD_RATE BAUD_RATE_9600 // 在进行寄存器参数配置时,除了波特率本身的配置外,其他的配置只能在9600进行配置
+#define E220_DEFAULT_CONFIG_BAUD_RATE_BYTE 0X60 // 9600波特率
+#define E220_DEFAULT_USED_BAUD_RATE BAUD_RATE_115200 // 在进行使用时可以切换为该波特率,但是在配置时需要切换回配置波特率(9600)
+#define E220_DEFAULT_USED_BAUD_RATE_BYTE 0XE0 // 115200波特率
+
+#define E220_MAX_CHANNEL_NUMBER 83 // E220最多支持84个信道,0~83
+#define E220_DEFAULT_CHANNEL 0XA // 默认通道
+
+#define E220_DEFAULT_AIR_RATE 0X0 // 默认模块以2.4K的空中速率进行通信
+
+#define E220_DEFAULT_TRANS_MODE 0X40 // 默认使用定点传输传输模式
+#define E220_CONFIG_DELAY 1000 // 配置的硬件响应时间
+
+#define E220_YES 0XFF
+#define E220_NO 0X00
+
+enum LoraMode // E220工作模式,支持四种,配置模式与休眠模式一致
+{
+ MODE_TRANSFER_MODE = 0, // M0 : M1 = 0 : 0 可发可收
+ MODE_WOR_SEND, // M0 : M1 = 1 : 0 可发可收
+ MODE_WOR_RECV, // M0 : M1 = 0 : 1 可收不发
+ MODE_CONFIG_SLEEP // M0 : M1 = 1 : 1 不收不发
+};
+
+enum LoraState // 硬件状态
+{
+ STATE_CLOSED, // 硬件关闭
+ STATE_OPENED, // 已正常开启
+ STATE_BROKEN // 硬件损坏
+};
+
+enum LoraTransMode // 模块传输模式
+{
+ TRANS_MODE_HYALINE = 0X0, // 透明传输
+ TRANS_MODE_ORIENTED = 0X40, // 定点传输
+};
+
+enum LoraAirRate // 空中速率,通信双方必须设置一致的空中速率方可进行通信
+{
+ AIR_RATE_2D4K = 0X0, // 2.4K
+ AIR_RATE_4D8K = 0X3, // 4.8K
+ AIR_RATE_9D6K = 0X4, // 9.6K
+ AIR_RATE_19D2K = 0X5, // 19.2K
+ AIR_RATE_38D4K = 0X6, // 38.4K
+ AIR_RATE_62D5K = 0X7 // 62.5K
+};
+
+enum LoraConfig // 支持IOCTL函数进行配置的配置项枚举,某些项只支持9600波特率配置
+{
+ CONFIG_SERIAL_TIME_OUT = 0X0, // 串口超时时间
+ CONFIG_LORA_MODE = 0X1, // 配置Lora模式
+ CONFIG_TRANS_MODE = 0X2, // 配置Lora传输模式(9600)
+ CONFIG_AIR_RATE = 0X3, // 配置空中速率(9600)
+ CONFIG_BAUD_RATE = 0X4, // 配置波特率
+ CONFIG_ADDRESS = 0X5, // 配置设备地址(9600)
+ CONFIG_CHANNEL = 0X6, // 配置设备信道(9600)
+ CONFIG_SHOW = 0X7 // 打印配置信息
+};
+
+extern enum LoraMode current_mode; // 当前模块处于什么模式
+extern enum LoraState lora_state; // 当前模块的状态
+
+/**
+ * @brief: 打开硬件设施,开启串口并按照配置的初始化参数配置相关硬件、串口
+ * 重复开启会直接返回,开启失败后不能重复尝试
+ * @param adapter: 任何状态
+ * @return: 0 -> Success : -1 -> Fail
+*/
+uint8 E220Open(struct Adapter *adapter);
+
+/**
+ * @brief: 关闭硬件设施,关闭串口,同时会将所有的数据回复到原始的配置状态
+ * 关闭失败默认为硬件损坏,未开启不可关闭
+ * @param adapter: 任何状态
+ * @return: 0 -> Success (硬件不是开启状态即成功): -1 -> Fail (硬件关闭过错报错)
+*/
+uint8 E220Close(struct Adapter *adapter);
+
+/**
+ * @brief: 给处于开启状态的硬件配置相关信息,包括串口配置,寄存器参数等等
+ * 支持的配置类型为@LoraConfig
+ * @param adapter: 打开状态
+ * @param config_item: 配置类型
+ * @param args: 配置参数
+ * @return: 0 -> Success : -1 -> Fail
+*/
+uint8 E220Ioctl(struct Adapter *adapter, int config_item, void *args);
+
+/**
+ * @brief: 通过硬件发送指定长度的数据
+ * @param adapter: 打开状态
+ * @param buf: 数据缓存区
+ * @param len: 缓存区大小
+ * @return 0 -> Success(全部发送完毕) : -1 -> Fail(未发送或发送不完整)
+*/
+uint8 E220Send(struct Adapter *adapter, const void *buf, uint32 len);
+
+/**
+ * @brief: 通过硬件接受指定长度的数据到缓冲区
+ * @param adapter: 打开状态
+ * @param buf: 接受缓冲区
+ * @param len: 需要接受的数据长度,该长度小于等于接受缓存区长度
+ * @return 0 -> 接收到了指定长度的数据 : -1 -> 未接受到指定长度的数据或者串口超时
+*/
+uint8 E220Recv(struct Adapter *adapter, void *buf, uint32 len);
+#endif // __E220_H__
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/lora_mac/lora_mac.c b/APP_Framework/Applications/app_test/test_lora_net_final/lora_mac/lora_mac.c
new file mode 100755
index 000000000..f4fe29621
--- /dev/null
+++ b/APP_Framework/Applications/app_test/test_lora_net_final/lora_mac/lora_mac.c
@@ -0,0 +1,1182 @@
+#include "lora_mac.h"
+
+static const uint8 crc_hi_table[] =
+ {
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
+ };
+
+static const uint8 crc_lo_table[] =
+ {
+ 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04,
+ 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8,
+ 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
+ 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10,
+ 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
+ 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
+ 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C,
+ 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0,
+ 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
+ 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
+ 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C,
+ 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
+ 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54,
+ 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98,
+ 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
+ 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
+ };
+
+// 相关数据缓冲区,全局变量
+struct LoraFrame send_frame; // 数据帧发送缓冲区
+struct LoraFrame recv_frame; // 数据帧接受缓存区
+uint8 send_data_buffer[FRAME_MAX_USER_DATA_LENGTH]; // 数据发送缓冲区
+uint8 recv_data_buffer[FRAME_MAX_USER_DATA_LENGTH]; // 数据接受缓存区
+uint8 total_data_buffer[FRAME_MAX_DATA_LENGTH]; // 数据帧加数据的最大缓冲区
+
+void InitLoraFrame(struct LoraFrame* frame)
+{
+ // 数据清空
+ memset(frame,0,sizeof(struct LoraFrame));
+ // 设置帧头、帧尾
+ frame->begin_mark = FRAME_BEGIN_MARK;
+ frame->end_mark = FRAME_END_MARK;
+}
+
+void ShowLoraFrame(struct LoraFrame* frame,char* prefix)
+{
+ printf("%s -> ",prefix);
+ printf("session_id:%d,dev_addr:%X,down_channel:%X,frame_confirm:%X ",frame->session_id,frame->dev_addr,frame->down_channel,frame->frame_confirm);
+ switch (frame->frame_type)
+ {
+ case E_G_JOIN:
+ printf("-E_G_JOIN-");
+ break;
+ case E_G_QUIT:
+ printf("-E_G_QUIT-");
+ break;
+ case E_G_DATA:
+ printf("-E_G_DATA-");
+ printf("user_data:%s ",frame->user_data);
+ break;
+ case G_E_ANS:
+ printf("-G_E_ANS-");
+ break;
+ }
+ printf("frame_attach:%d,crc_hi:%X,crc_lo:%X\n",frame->frame_attach,frame->crc_hi,frame->crc_lo);
+}
+
+void CalCrcByte(uint8* data, uint8 data_length,unsigned int* temp,uint8* crc_hi,uint8* crc_lo)
+{
+ for (int i = 0; i < data_length; i++)
+ {
+ *temp = *crc_hi ^ *data++;
+ *crc_hi = *crc_lo ^ crc_hi_table[*temp];
+ *crc_lo = crc_lo_table[*temp];
+ }
+}
+
+uint8 CalCrlLoraFrame(struct LoraFrame* frame)
+{
+ uint8 crc_hi = 0xFF;
+ uint8 crc_lo = 0xFF;
+ unsigned int temp;
+ // 转化为字节的方式进行数据访问
+ uint8 *bit_arr = (uint8 *)frame;
+ // 计算除开帧头后面11位元数据的校验值
+ CalCrcByte(bit_arr + FRAME_CRC_INDEX_BEGIN,FRAME_CRC_LENGTH,&temp,&crc_hi,&crc_lo);
+ if (frame->frame_type == E_G_DATA)
+ {
+ // 数据传输必须要携带数据,否则就是出错
+ if (frame->frame_attach != 0 && frame->user_data != NULL)
+ {
+ // 计算用户数据的校验值
+ CalCrcByte(frame->user_data,frame->frame_attach,&temp,&crc_hi,&crc_lo);
+ }
+ else
+ {
+ printf("CalCrlLoraFrame: have no data!\n");
+ return -1;
+ }
+ }
+ frame->crc_lo = crc_lo;
+ frame->crc_hi = crc_hi;
+ return 0;
+}
+
+uint8 CheckCrcLoraFrame(struct LoraFrame* frame)
+{
+ uint8 crc_hi_tmp = frame->crc_hi;
+ uint8 crc_lo_tmp = frame->crc_lo;
+
+ if (0 == CalCrlLoraFrame(frame))
+ {
+ if (crc_hi_tmp == frame->crc_hi && crc_lo_tmp == frame->crc_lo)
+ {
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static const uint16 header_mark = FRAME_BEGIN_MARK & 0XFF; // 数据帧头部
+static const uint16 tail_mark = FRAME_END_MARK & 0XFF; // 数据帧尾部
+static uint16 header_buffer = 0; // 用于数据帧头部检测
+
+uint8 LoraRecvFrame(struct Adapter *adapter, struct LoraFrame *recv_buffer)
+{
+ if (lora_state != STATE_OPENED)
+ {
+ printf("LoraRecvFrame-Fail: lora closed or broken!\n");
+ return -1;
+ }
+ // 初始化接受缓冲区
+ memset(recv_buffer, 0, sizeof(struct LoraFrame));
+
+ header_buffer = 0;
+ // 用于查找数据帧的帧头
+ uint8 *header_temp = (uint8*)(&header_buffer);
+ // 查找数据帧的开始标志
+ while (1 == E220Recv(adapter, &header_temp[1], 1)) // 查找开始标志
+ {
+ // 找到了开始标识的一半
+ if (header_mark == header_temp[1])
+ {
+ // 判断上一个字节是否是开始标志,若是,则已找到,若不是,则继续
+ if (header_temp[1] == header_temp[0])
+ {
+ recv_buffer->begin_mark = FRAME_BEGIN_MARK;
+ // 接收帧头以下,用户数据以上的数据
+ if (FRAME_NECK_LENGTH == E220Recv(adapter, &recv_buffer->session_id, FRAME_NECK_LENGTH))
+ {
+ // 查看是否有用户数据
+ if (E_G_DATA == recv_buffer->frame_type)
+ {
+ // 如果携带了用户数据则接收用户数据
+ if (0 != recv_buffer->frame_attach)
+ {
+ // 重置用户数据缓冲区
+ memset(recv_data_buffer, 0, FRAME_MAX_USER_DATA_LENGTH);
+ // 接收用户数据
+ if (recv_buffer->frame_attach != E220Recv(adapter, recv_data_buffer, recv_buffer->frame_attach))
+ {
+ printf("LoraRecvFrame-Fail: recv user data fail!\n");
+ header_buffer = 0;
+ break;
+ }
+ // 将数据嫁接到数据帧
+ recv_buffer->user_data = recv_data_buffer;
+ }
+ }
+ // 开始接受最后的数据
+ if (FRAME_FOOT_LENGTH != E220Recv(adapter,&recv_buffer->crc_hi,FRAME_FOOT_LENGTH))
+ {
+ printf("LoraRecvFrame-Fail: recv foot frame fail!\n");
+ header_buffer = 0;
+ break;
+ }
+ // 开始检查数据帧尾巴是否正确
+ if (FRAME_END_MARK != recv_buffer->end_mark)
+ {
+ printf("LoraRecvFrame-Fail: frame end mark err!\n");
+ header_buffer = 0;
+ break;
+ }
+ // 开始进行数据帧校验
+ if (0 != CheckCrcLoraFrame(recv_buffer))
+ {
+ printf("LoraRecvFrame-Fail: check frame crc fail!\n");
+ header_buffer = 0;
+ break;
+ }
+ // 接受数据帧成功
+ ShowLoraFrame(recv_buffer,"LoraRecvFrame");
+ header_buffer = 0;
+ return 0;
+ }
+ else
+ {
+ printf("LoraRecvFrame-Fail: recv neck frame fail!\n");
+ header_buffer = 0;
+ break;
+ }
+ }
+ }
+ // 将接受到的数据放置在上一个位置
+ header_temp[0] = header_temp[1];
+ }
+ header_buffer = 0;
+ return -1;
+}
+
+uint8 LoraSendFrame(struct Adapter* adapter, struct LoraFrame* send_buffer,uint16 addr,uint8 channel)
+{
+ // 判断lora是否已经正确开启
+ if (lora_state != STATE_OPENED)
+ {
+ printf("LoraSendFrame-Fail: lora closed or broken!\n");
+ return -1;
+ }
+ // 计算数据帧的校验值
+ if (0 != CalCrlLoraFrame(send_buffer))
+ {
+ printf("LoraSendFrame-Fail: cal_crc fail!\n");
+ return -1;
+ }
+ // 记录整个数据帧的长度
+ int fram_length = 0;
+ // 重置数据发送缓冲区
+ memset(&total_data_buffer,0,FRAME_MAX_DATA_LENGTH);
+ // 组装目标地址
+ total_data_buffer[0] = (addr >> 8) & 0XFF;
+ total_data_buffer[1] = addr & 0XFF;
+ total_data_buffer[2] = channel;
+ fram_length += 3;
+
+ // 数据帧前半部分
+ memcpy(&total_data_buffer[fram_length],send_buffer,FRAME_META_LENGTH - FRAME_FOOT_LENGTH);
+ fram_length += (FRAME_META_LENGTH - FRAME_FOOT_LENGTH);
+ // 用户额外数据
+ if (E_G_DATA == send_buffer->frame_type)
+ {
+ memcpy(&total_data_buffer[fram_length],send_buffer->user_data,send_buffer->frame_attach);
+ fram_length += send_buffer->frame_attach;
+ }
+ // 剩下来的数据
+ memcpy(&total_data_buffer[fram_length],&send_buffer->crc_hi,FRAME_FOOT_LENGTH);
+ fram_length += FRAME_FOOT_LENGTH;
+ // 发送所有数据
+ if (0 != E220Send(adapter,&total_data_buffer,fram_length))
+ {
+ printf("LoraSendFrame-Fail: send fail!\n");
+ return -1;
+ }
+ ShowLoraFrame(send_buffer,"LoraSendFrame");
+ return 0;
+}
+
+uint16 GetSessionId(void)
+{
+ return rand() & 0XFFFF;
+}
+
+void SignalDetector(struct Adapter *adapter,uint8 download_channel,uint8 upload_channel)
+{
+ // 切换至上行信道,客户端上行通道为广播信息(地址为OXFFFF),该信道所有终端都可以接收到
+ E220Ioctl(adapter,CONFIG_CHANNEL,&upload_channel);
+ // 监听信道
+ uint8 temp_dst;
+ while (1 == E220Recv(adapter, &temp_dst, 1))
+ {
+ printf("LoraSignalDetector-Fail: Channel occupied!\n");
+ }
+ // 切换至切换至下行通道,准备发送数据
+ E220Ioctl(adapter,CONFIG_CHANNEL,&download_channel);
+ printf("LoraSignalDetector-Success: Channel idle!\n");
+}
+
+int UsrAdapterLoraInit(void)
+{
+ struct Adapter *adapter = PrivMalloc(sizeof(struct Adapter));
+ if (!adapter)
+ {
+ PrivFree(adapter);
+ return -1;
+ }
+ memset(adapter, 0, sizeof(struct Adapter));
+ // Adapter注册函数,终端和网关需要自己实现并开放接口
+ if (0 != UsrAdapterLoraRegister(adapter))
+ {
+ printf("UsrAdapterLoraInit-Fail: register lora adapter error\n");
+ PrivFree(adapter);
+ return -1;
+ }
+ // 获取函数操作集合,终端和网关需要自己实现并开放接口
+ AdapterProductInfoType product_info = LoraAttach(adapter);
+ if (NULL == product_info)
+ {
+ printf("UsrAdapterLoraInit-Fail: e220 attach error\n");
+ PrivFree(adapter);
+ return -1;
+ }
+ // 配置Adapter属性
+ adapter->product_info_flag = 1;
+ adapter->info = product_info;
+ adapter->done = product_info->model_done;
+ adapter->adapter_status = REGISTERED;
+ // 创建信号量和互斥量
+ PrivSemaphoreCreate(&adapter->sem, 0, 0);
+ PrivMutexCreate(&adapter->lock, 0);
+
+ printf("UsrAdapterLoraInit-Success!\n");
+ return 0;
+}
+
+#ifdef AS_LORA_GATEWAY
+
+struct GatewayParam gateway_param = // 网关配置参数
+{
+ .dev_addr = LORA_GATEWAY_ADDRESS,
+ .channel = LORA_GATEWAY_CHANNEL,
+ .recv_time = LORA_RECV_TIME,
+ .air_rate = LORA_AIR_RATE,
+ .frame_retry = LORA_FRAME_RETRY,
+ .gateway_state = GATEWAY_CLOSED,
+ .node_infos = {NULL},
+ .node_count = 0,
+};
+
+struct PrivProtocolDone gateway_done = // 网关操作函数集合
+{
+ .open = GatewayOpen,
+ .close = GatewayClose,
+ .ioctl = GatewayIoctl,
+ .setup = GatewaySetup,
+ .setdown = GatewaySetDown,
+ .netstat = GatewayNetState
+};
+
+int (*gateway_handlers[])(struct Adapter*,struct LoraFrame*) = // 网关处理程序
+{
+ [E_G_JOIN] = GatewayJoinHandler,
+ [E_G_QUIT] = GatewayQuitHandler,
+ [E_G_DATA] = GatewayDataSendHandler,
+};
+
+static UtaskType gateway_task; // 网关任务
+static int32 gateway_task_id = -1; // 任务ID
+
+/**
+ * @brief: 根据地址和信道定位到终端的信息
+*/
+static struct EndNodeInfo* GetEndNodeInfo(uint16 node_addr,uint8 channel)
+{
+ for (int i = 0; i < gateway_param.node_count; i++)
+ {
+ if (node_addr == gateway_param.node_infos[i]->node_addr && channel == gateway_param.node_infos[i]->node_down_channel)
+ {
+ return gateway_param.node_infos[i];
+ }
+ }
+ return NULL;
+}
+
+int GatewayOpen(struct Adapter *adapter)
+{
+ switch (gateway_param.gateway_state)
+ {
+ case GATEWAY_WORKING: case GATEWAY_OPENED:
+ printf("GatewayOpen-Success: lora already opened before!\n");
+ return 0;
+ case GATEWAY_BROKEN:
+ printf("GatewayOpen-Fail: lora broken!\n");
+ return -1;
+ case GATEWAY_CLOSED:
+ PrivMutexObtain(&adapter->lock);
+ // 打开底层硬件
+ if (0 != E220Open(adapter))
+ {
+ gateway_param.gateway_state = GATEWAY_BROKEN;
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ // 按照网关的配置信息配置底层的硬件
+ uint32 recv_time = gateway_param.recv_time * 1000;
+ if (0 != E220Ioctl(adapter,CONFIG_CHANNEL,&gateway_param.channel)
+ || 0 != E220Ioctl(adapter,CONFIG_ADDRESS,&gateway_param.dev_addr)
+ || 0 != E220Ioctl(adapter,CONFIG_AIR_RATE,&gateway_param.air_rate)
+ || 0 != E220Ioctl(adapter,CONFIG_SERIAL_TIME_OUT,&recv_time))
+ {
+ printf("GatewayOpen-Fail: config gateway fail -> channel: %X,address: %X,air_rate: %X!\n",gateway_param.channel,gateway_param.dev_addr,gateway_param.air_rate);
+ gateway_param.gateway_state = GATEWAY_BROKEN;
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ // 更新网关的状态信息
+ gateway_param.gateway_state = GATEWAY_OPENED;
+ printf("GatewayOpen-Success: channel: %X,address: %X!\n",gateway_param.channel,gateway_param.dev_addr);
+ PrivMutexAbandon(&adapter->lock);
+ return 0;
+ default:
+ printf("GatewayOpen-Fail: unknown gateway state!\n");
+ return -1;
+ }
+}
+
+int GatewayClose(struct Adapter *adapter)
+{
+ switch (gateway_param.gateway_state)
+ {
+ case GATEWAY_CLOSED: case GATEWAY_BROKEN:
+ printf("GatewayClose-Success: lora close or broken before!\n");
+ return 0;
+ case GATEWAY_WORKING:
+ printf("GatewayClose-Fail: quit net before close!\n");
+ return -1;
+ case GATEWAY_OPENED:
+ PrivMutexObtain(&adapter->lock);
+ if (0 != E220Close(adapter))
+ {
+ gateway_param.gateway_state = GATEWAY_BROKEN;
+ printf("GatewayClose-Fail: close lora fail!\n");
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ gateway_param.gateway_state = GATEWAY_CLOSED;
+ printf("GatewayClose-Success\n");
+ PrivMutexAbandon(&adapter->lock);
+ return 0;
+ default:
+ printf("GatewayClose-Fail: unknown err!\n");
+ return -1;
+ }
+}
+
+int GatewayIoctl(struct Adapter *adapter, int cmd, void *args)
+{
+ switch (gateway_param.gateway_state)
+ {
+ case GATEWAY_WORKING: case GATEWAY_BROKEN: case GATEWAY_CLOSED:
+ printf("GatewayIoctl-Fail: cant be config when lora broken、working、clesed!\n");
+ return -1;
+ case GATEWAY_OPENED:
+ PrivMutexObtain(&adapter->lock);
+ if (0 != E220Ioctl(adapter, cmd, args))
+ {
+ gateway_param.gateway_state = GATEWAY_BROKEN;
+ printf("GatewayIoctl-Fail: ioctl fail!\n");
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ printf("GatewayIoctl-Success\n");
+ PrivMutexAbandon(&adapter->lock);
+ return 0;
+ default:
+ printf("GatewayIoctl-Fail: unknown err!\n");
+ return -1;
+ }
+}
+
+int GatewaySetup(struct Adapter *adapter)
+{
+ if (GATEWAY_BROKEN == gateway_param.gateway_state)
+ {
+ printf("GatewaySetup-Fail: lora broken!\n");
+ return -1;
+ }
+ if (GATEWAY_CLOSED == gateway_param.gateway_state)
+ {
+ printf("GatewaySetup-Fail: please open lora before!\n");
+ return -1;
+ }
+ if (GATEWAY_WORKING == gateway_param.gateway_state)
+ {
+ printf("GatewaySetup-Success: lora setup before!\n");
+ return 0;
+ }
+ PrivMutexObtain(&adapter->lock);
+ // 配置硬件传输
+ if (0 != E220Ioctl(adapter,CONFIG_LORA_MODE,MODE_TRANSFER_MODE))
+ {
+ printf("GatewaySetup-Fail: config lora transfer fail!\n");
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+
+ gateway_task.prio = 24;
+ gateway_task.stack_size = 2048;
+ gateway_task.func_param = adapter;
+ gateway_task.func_entry = GatewayTask;
+ strncpy(gateway_task.name, "lora_gateway_task", strlen("lora_gateway_task"));
+
+ gateway_task_id = UserTaskCreate(gateway_task);
+
+ if (gateway_task_id < 0)
+ {
+ printf("GatewaySetup-Fail: create task fail!\n");
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+
+ if (0 == UserTaskStartup(gateway_task_id))
+ {
+ gateway_param.gateway_state = GATEWAY_WORKING;
+ printf("GatewaySetup-Success: start task success!\n");
+ PrivMutexAbandon(&adapter->lock);
+ return 0;
+ }
+ else
+ {
+ UserTaskDelete(gateway_task_id);
+ gateway_task_id = -1;
+ printf("GatewaySetup-Fail: start task fail!\n");
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+}
+
+int GatewaySetDown(struct Adapter *adapter)
+{
+
+ if (GATEWAY_WORKING != gateway_param.gateway_state)
+ {
+ printf("GatewaySetDown-Success: not in working state!\n");
+ return 0;
+ }
+ // 通知后台程序
+ PrivSemaphoreAbandon(&adapter->sem);
+ PrivMutexObtain(&adapter->lock);
+ if (0 == UserTaskDelete(gateway_task_id))
+ {
+ gateway_task_id = -1;
+ gateway_param.gateway_state = GATEWAY_OPENED;
+ printf("GatewaySetDown-Success!\n");
+ PrivMutexAbandon(&adapter->lock);
+ return 0;
+ }
+ printf("GatewaySetDown-Fail: delete task fail!\n");
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+}
+
+int GatewayNetState(struct Adapter *adapter)
+{
+ printf("GatewayInfos: \n");
+ printf("addr:%d,channel:%d,recv_time:%d,",gateway_param.dev_addr,gateway_param.channel,gateway_param.recv_time);
+ printf("air_rate:%d,state:%x,node_count:%d\n",gateway_param.air_rate,gateway_param.gateway_state,gateway_param.node_count);
+ for (int i = 0; i < gateway_param.node_count; i++)
+ {
+ struct EndNodeInfo *node = gateway_param.node_infos[i];
+ printf("node_addr:%d,node_down_channel:%d!n",node->node_addr,node->node_down_channel);
+ }
+ return 0;
+}
+
+void* GatewayTask(void* param)
+{
+ struct Adapter *gateway_adapter = (struct Adapter *)param;
+ if (gateway_adapter == NULL)
+ {
+ printf("GatewayTask-Fail: adapter is null!\n");
+ return NULL;
+ }
+
+ while (gateway_param.gateway_state != GATEWAY_WORKING) // 等待上一个函数修改网关状态
+ {
+ PrivTaskDelay(100);
+ }
+
+ while (1) // 业务大循环
+ {
+ if (0 == PrivSemaphoreObtainNoWait(&gateway_adapter->sem))
+ {
+ PrivTaskDelay(LORA_RECV_TIME);
+ continue;
+ }
+ PrivMutexObtain(&gateway_adapter->lock);
+ if (0 == LoraRecvFrame(gateway_adapter,&recv_frame))
+ {
+ // 进行相应的处理
+ if (0 == gateway_handlers[recv_frame.frame_type](gateway_adapter,&recv_frame))
+ {
+ printf("GatewayTask: handle success!\n");
+ }
+ else
+ {
+ printf("GatewayTask: handle fail!\n");
+ }
+ }
+ PrivMutexAbandon(&gateway_adapter->lock);
+ }
+
+ printf("GatewayTask: task exit!\n");
+ return NULL;
+}
+
+int GatewayJoinHandler(struct Adapter* adapter,struct LoraFrame* frame)
+{
+ // 获取终端的地址和信道,防止多个信道中同一个地址加入失败
+ uint16 node_addr = frame->dev_addr;
+ uint8 node_channel = frame->down_channel;
+ struct EndNodeInfo* node = NULL;
+ // 从现有的数据中查找
+ for (int i = 0; i < gateway_param.node_count; i++)
+ {
+ if (node_addr == gateway_param.node_infos[i]->node_addr && node_channel == gateway_param.node_infos[i]->node_down_channel) // 找到了这个终端,实现已经加入了
+ {
+ node = gateway_param.node_infos[i];
+ break;
+ }
+ }
+ // 如果事先没有加入就创建
+ if (node == NULL)
+ {
+ if(gateway_param.node_count == LORA_GATEWAY_MAX_NODE)
+ {
+ printf("NodeJoinHandler: too much node!\n");
+ return -1;
+ }
+ node = (struct EndNodeInfo *)PrivMalloc(sizeof(struct EndNodeInfo));
+ memset(node, 0, sizeof(struct EndNodeInfo));
+ node->node_addr = node_addr;
+ node->node_down_channel = node_channel;
+ gateway_param.node_infos[gateway_param.node_count] = node;
+ gateway_param.node_count++;
+ // 如果已经事先加入了,直接返回
+ }
+ // 响应终端
+ frame->frame_type = G_E_ANS;
+ frame->frame_confirm = FRAME_BYTE_NO;
+ frame->frame_attach = FRAME_BYTE_OK;
+
+ if (0 != LoraSendFrame(adapter, frame,node->node_addr,node->node_down_channel))
+ {
+ printf("NodeJoinHandler: response node fail!\n");
+ return -1;
+ }
+ printf("NodeJoinHandler: join net success addr:%d,channel:%d!\n",node->node_addr,node->node_down_channel);
+ return 0;
+}
+
+int GatewayQuitHandler(struct Adapter* adapter,struct LoraFrame* frame)
+{
+ uint16 node_addr = frame->dev_addr;
+ uint8 node_channel = frame->down_channel;
+ for (int i = 0; i < gateway_param.node_count; i++) // 查找是否存在这个终端
+ {
+ if (node_addr == gateway_param.node_infos[i]->node_addr && node_channel == gateway_param.node_infos[i]->node_down_channel)
+ {
+ frame->frame_type = G_E_ANS;
+ frame->frame_confirm = FRAME_BYTE_NO;
+ frame->frame_attach = FRAME_BYTE_OK;
+ if (0 != LoraSendFrame(adapter, frame,gateway_param.node_infos[i]->node_addr,gateway_param.node_infos[i]->node_down_channel))
+ {
+ printf("NodeQuitHandler: response node fail!\n");
+ return -1;
+ }
+ // 释放相关的空间
+ PrivFree(gateway_param.node_infos[i]);
+ for (int j = i; j < gateway_param.node_count - 1; j++)
+ {
+ gateway_param.node_infos[j] = gateway_param.node_infos[j+1];
+ }
+ gateway_param.node_count--;
+ gateway_param.node_infos[gateway_param.node_count] = NULL;
+ break;
+ }
+ }
+ printf("NodeQuitHandler: quit net success or quit before!\n");
+ return 0;
+}
+
+int GatewayDataSendHandler(struct Adapter* adapter,struct LoraFrame* frame)
+{
+ // 查找该终端
+ struct EndNodeInfo* node_info = GetEndNodeInfo(frame->dev_addr,frame->down_channel);
+ if (node_info == NULL)
+ {
+ printf("NodeDataSendHandler: no such node!\n");
+ return 0;
+ }
+ // 响应数据上传
+ frame->frame_type = G_E_ANS;
+ frame->frame_confirm = FRAME_BYTE_NO;
+ frame->frame_attach = LORA_OK;
+ if (0 != LoraSendFrame(adapter, frame,node_info->node_addr,node_info->node_down_channel))
+ {
+ printf("NodeDataSendHandler: response fail!\n");
+ return -1;
+ }
+ // TODO 数据上传在此处理
+ printf("NodeDataSendHandler-Success: recv data: %s\n!",frame->user_data);
+ return 0;
+}
+
+AdapterProductInfoType LoraAttach(struct Adapter *adapter)
+{
+ struct AdapterProductInfo *product_info = malloc(sizeof(struct AdapterProductInfo));
+ if (!product_info) {
+ printf("LoraAttach-Failed-Node: malloc fail!\n");
+ return NULL;
+ }
+
+ strncpy(product_info->model_name, LORA_ADAPTER_NAME,sizeof(product_info->model_name));
+ product_info->model_done = (void *)&gateway_done;
+
+ return product_info;
+}
+
+uint8 UsrAdapterLoraRegister(struct Adapter *adapter)
+{
+ strncpy(adapter->name, ADAPTER_LORA_NAME, NAME_NUM_MAX);
+ adapter->net_protocol = PRIVATE_PROTOCOL;
+
+ adapter->net_role = GATEWAY;
+ adapter->net_role_id = gateway_param.channel;
+ adapter->adapter_param = (void *)(&gateway_param);
+
+ adapter->adapter_status = UNREGISTERED;
+
+ if (AdapterDeviceRegister(adapter) < 0)
+ {
+ printf("UsrAdapterLoraRegister-Fail: lora register error!\n");
+ return -1;
+ }
+
+ printf("UsrAdapterLoraRegister-Success!\n");
+ return 0;
+}
+#else
+
+// 终端参数结构
+struct EndNodeParam node_param =
+{
+ .dev_addr = LORA_ADDRESS,
+ .down_channel = LORA_DOWN_CHANNEL,
+ .upload_channel = LORA_UP_CHANNEL,
+ .session_id = 0X0,
+ .node_state = NODE_STATE_CLOSED,
+ .air_rate = LORA_AIR_RATE,
+ .adr_enable = LORA_ADR_ENABLE,
+ .reconnect_enable = LORA_RECONNECT_ENABLE,
+ .recv_time = LORA_RECV_TIME,
+};
+// 终端操作集合
+static struct PrivProtocolDone node_done =
+{
+ .open = NodeOpen,
+ .close = NodeClose,
+ .join = NodeJoin,
+ .send = NodeSend,
+ .quit = NodeQuit,
+ .netstat = NodeNetState
+};
+// 空中速率枚举
+enum LoraAirRate air_rates[6] =
+ {
+ AIR_RATE_2D4K,
+ AIR_RATE_4D8K,
+ AIR_RATE_9D6K,
+ AIR_RATE_19D2K,
+ AIR_RATE_38D4K,
+ AIR_RATE_62D5K};
+
+int air_rate_length = 6;
+
+/**
+ * @brief: 向特定信道以特定空中速率发送入网请求
+ * @param adapter: 已打开的适配器
+ * @param join_buffer: 已组装数据帧的缓冲区
+ * @param upload_channel: 上行信道
+ * @param air_rate: 空中速率
+ * @return: 0 -> Success : -1 -> Fail(根据状态判定是否存在硬件损坏)
+*/
+static uint8 TargetConnectGateway(struct Adapter *adapter,struct LoraFrame *join_buffer,uint8 upload_channel,enum LoraAirRate air_rate)
+{
+ if (0 != E220Ioctl(adapter, CONFIG_AIR_RATE, &air_rate)) // 配置硬件空中速率
+ {
+ printf("TargetConnectGateway-Fail: config air rate fail %d!\n",air_rate);
+ node_param.node_state = NODE_STATE_BROKEN;
+ return -1;
+ }
+ node_param.air_rate = air_rate;
+ for (int i = 0; i < LORA_FRAME_RETRY; i++)
+ {
+ node_param.session_id = GetSessionId();
+ send_frame.session_id = node_param.session_id;
+
+ SignalDetector(adapter,node_param.down_channel,node_param.upload_channel); // 信道监听
+ if (0 != LoraSendFrame(adapter, &send_frame, LORA_GATEWAY_ADDRESS,upload_channel)) // 发送入网请求
+ {
+ node_param.node_state = NODE_STATE_BROKEN;
+ return -1;
+ }
+ PrivTaskDelay(LORA_TIME_ON_AIR * 1000);
+ while (0 == LoraRecvFrame(adapter, &recv_frame)) // 接收响应数据帧
+ {
+ if (recv_frame.session_id == node_param.session_id) // 判断数据帧是否丢失
+ {
+ if (G_E_ANS == recv_frame.frame_type && FRAME_BYTE_OK == recv_frame.frame_attach) // 成功加入网关
+ {
+ node_param.node_state = NODE_STATE_CONNECT; // 更改终端状态
+ node_param.upload_channel = upload_channel;
+ node_param.air_rate = air_rate;
+ printf("ConnectGateway-Success: upload_channel: %d, air_rate: %d !\n",upload_channel,air_rate);
+ return 0;
+ }
+ }
+ }
+ }
+ printf("ConnectGateway-Fail: upload_channel: %d, air_rate: %d !\n",upload_channel,air_rate);
+ return -1;
+}
+
+int NodeOpen(struct Adapter *adapter)
+{
+ // 获取硬件控制权
+ PrivMutexObtain(&adapter->lock);
+ // 硬件损坏
+ if (NODE_STATE_BROKEN == node_param.node_state)
+ {
+ printf("NodeOpen-Fail: lora broken!\n");
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ // 硬件已打开
+ if (NODE_STATE_CONNECT == node_param.node_state || NODE_STATE_DISCONNECT == node_param.node_state)
+ {
+ printf("NodeOpen-Success: opened before!\n");
+ PrivMutexAbandon(&adapter->lock);
+ return 0;
+ }
+ // 打开硬件设施
+ if (0 != E220Open(adapter))
+ {
+ printf("NodeOpen-Fail: lora open fail!\n");
+ node_param.node_state = NODE_STATE_BROKEN;
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ // 配置硬件地址、信道、超时时间,空中速率
+ int time_out = node_param.recv_time * 1000;
+ if (0 != E220Ioctl(adapter,CONFIG_ADDRESS,&node_param.dev_addr)
+ || 0 != E220Ioctl(adapter,CONFIG_CHANNEL,&node_param.down_channel)
+ || 0 != E220Ioctl(adapter,CONFIG_SERIAL_TIME_OUT,&time_out)
+ || 0 != E220Ioctl(adapter,CONFIG_AIR_RATE,&node_param.air_rate))
+ {
+ printf("NodeOpen-Fail: condfi client fail!\n");
+ node_param.node_state = NODE_STATE_BROKEN;
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ // 配置硬件休眠
+ enum LoraMode aim_mode = MODE_CONFIG_SLEEP;
+ if (0 != E220Ioctl(adapter, CONFIG_LORA_MODE, &aim_mode))
+ {
+ printf("NodeOpen-Fail: config lora sleep fail!\n");
+ node_param.node_state = NODE_STATE_BROKEN;
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ printf("NodeOpen-Success: node open success address: %d, dwon_channel: %d, upload_channel: %d!\n",node_param.dev_addr,node_param.down_channel,node_param.upload_channel);
+ node_param.node_state = NODE_STATE_DISCONNECT;
+ PrivMutexAbandon(&adapter->lock);
+ return 0;
+}
+
+int NodeClose(struct Adapter *adapter)
+{
+ if (NODE_STATE_BROKEN == node_param.node_state || NODE_STATE_CLOSED == node_param.node_state)
+ {
+ printf("NodeClose-Success: lora broken or cloded before!\n");
+ return 0;
+ }
+ if (NODE_STATE_CONNECT == node_param.node_state)
+ {
+ printf("NodeClose-Fail: quit net before close node!\n");
+ return -1;
+ }
+ PrivMutexObtain(&adapter->lock);
+ // 关闭硬件设施
+ if (0 != E220Close(adapter))
+ {
+ printf("NodeClose-Fail: lora close fail!\n");
+ node_param.node_state = NODE_STATE_BROKEN;
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ printf("NodeClose-Success: node close success!\n");
+ node_param.node_state = NODE_STATE_CLOSED;
+ PrivMutexAbandon(&adapter->lock);
+ return 0;
+}
+
+int NodeJoin(struct Adapter *adapter, unsigned char *net_group)
+{
+ switch (node_param.node_state)
+ {
+ case NODE_STATE_BROKEN:
+ printf("NodeJoin-Fail: lora broken!\n");
+ return -1;
+ case NODE_STATE_CLOSED:
+ printf("NodeJoin-Fail: open lora before join net!\n");
+ return -1;
+ case NODE_STATE_CONNECT:
+ if (node_param.upload_channel == *net_group && NODE_STATE_CONNECT == node_param.node_state)
+ {
+ printf("NodeJoin-Success: joined before!\n");
+ return 0;
+ }
+ // 退出当前网络
+ if (NODE_STATE_CONNECT == node_param.node_state)
+ {
+ // 退出当前的网络,断开上行通道
+ if (0 != NodeQuit(adapter, &node_param.upload_channel))
+ {
+ printf("NodeJoin-Fail: quit net before fail!\n");
+ return -1;
+ }
+ }
+ default:
+ // 构建入网数据帧
+ InitLoraFrame(&send_frame);
+ send_frame.dev_addr = node_param.dev_addr; // 当前设备地址
+ send_frame.down_channel = node_param.down_channel; // 下行通道信息,当前设备的信道
+ send_frame.frame_type = E_G_JOIN;
+ send_frame.frame_confirm = LORA_OK;
+ // 获取终端控制权
+ PrivMutexObtain(&adapter->lock);
+ // 以默认的空中速率尝试连接传入的网络
+ if (0 == TargetConnectGateway(adapter, &send_frame, *net_group,node_param.air_rate))
+ {
+ PrivMutexAbandon(&adapter->lock);
+ return 0;
+ }
+ else
+ {
+ // ADR自动寻找网关
+ if (LORA_OK == node_param.adr_enable)
+ {
+ // 默认连接出错
+ if (NODE_STATE_BROKEN == node_param.node_state)
+ {
+ printf("NodeJoin-Fail: send join frame fail!\n");
+ node_param.node_state = NODE_STATE_BROKEN;
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ // 尝试连接其他的网关
+ for (int i = 0; i < E220_MAX_CHANNEL_NUMBER; i++)
+ {
+ for (int j = 0; j < air_rate_length; j++)
+ {
+ printf("NodeJoin-Try: channel: %d air rate: %x!\n",i,air_rates[j]);
+ if (0 == TargetConnectGateway(adapter, &send_frame, i, air_rates[j]))
+ {
+ PrivMutexAbandon(&adapter->lock);
+ return 0;
+ }
+ if (NODE_STATE_BROKEN == node_param.node_state)
+ {
+ printf("NodeJoin-Fail: send join frame fail!\n");
+ node_param.node_state = NODE_STATE_BROKEN;
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ }
+ }
+ // 不存在网关
+ printf("NodeJoin-Fail: no gateway exits!\n");
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ else
+ {
+ printf("NodeJoin-Fail: the gateway config not exits!\n");
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ }
+ }
+}
+
+int NodeSend(struct Adapter *adapter, const void *buf, size_t len)
+{
+ // 只有处于联网状态的终端才可发送数据
+ if (NODE_STATE_CONNECT != node_param.node_state)
+ {
+ printf("NodeSend-Fail: open lora and join net before send data!\n");
+ return -1;
+ }
+ if (len > FRAME_MAX_USER_DATA_LENGTH) // 数据量太大
+ {
+ printf("NodeSend-Fail: to much data for send!\n");
+ return -1;
+ }
+ // 构造数据帧并发送数据
+ InitLoraFrame(&send_frame); // 初始化
+ send_frame.dev_addr = node_param.dev_addr;
+ send_frame.down_channel = node_param.down_channel;
+ send_frame.frame_type = E_G_DATA;
+ send_frame.frame_confirm = LORA_OK;
+ // 复制待发送的数据
+ memcpy(send_data_buffer,buf,len);
+ send_frame.user_data = send_data_buffer;
+ send_frame.frame_attach = len;
+
+ PrivMutexObtain(&adapter->lock);
+ // 发送用户数据帧
+ for (int i = 0; i < LORA_FRAME_RETRY; i++)
+ {
+ node_param.session_id = GetSessionId();
+ send_frame.session_id = node_param.session_id;
+
+ // 信道监听
+ SignalDetector(adapter,node_param.down_channel,node_param.upload_channel);
+ // 发送数据帧
+ if (0 != LoraSendFrame(adapter, &send_frame,LORA_GATEWAY_ADDRESS,node_param.upload_channel))
+ {
+ PrivMutexAbandon(&adapter->lock);
+ node_param.node_state = NODE_STATE_BROKEN;
+ return -1;
+ }
+ // 等待信号到达
+ PrivTaskDelay(LORA_TIME_ON_AIR * 1000);
+ // 准备数据缓冲区并等待网关响应
+ while (0 == LoraRecvFrame(adapter, &recv_frame))
+ {
+ // 判断数据是否丢失
+ if (recv_frame.session_id == node_param.session_id)
+ {
+ // 判断是否发送成功
+ if (G_E_ANS == recv_frame.frame_type && LORA_OK == recv_frame.frame_attach)
+ {
+ // 配置硬件休眠
+ enum LoraMode aim_mode = MODE_CONFIG_SLEEP;
+ E220Ioctl(adapter,CONFIG_LORA_MODE,&aim_mode);
+ PrivMutexAbandon(&adapter->lock);
+ return 0;
+ }
+
+ }
+ }
+ }
+ PrivMutexAbandon(&adapter->lock);
+ // 判定网关掉线
+ node_param.node_state = NODE_STATE_DISCONNECT;
+ // 数据发送失败,需要重新联网
+ if (LORA_OK == node_param.reconnect_enable)
+ {
+ printf("NodeSend-Fail: try to reconnect gateway!\n");
+ if (0 == NodeJoin(adapter,&node_param.upload_channel))
+ {
+ // 重新发送数据
+ return NodeSend(adapter,buf,len);
+ }
+ printf("NodeSend-Fail: try to reconnect gateway fail!\n");
+ }
+ return -1;
+}
+
+int NodeQuit(struct Adapter *adapter, unsigned char *net_group)
+{
+ if (NODE_STATE_CONNECT != node_param.node_state)
+ {
+ printf("NodeQuit-Success: disconnected before!\n");
+ return 0;
+ }
+
+ if (node_param.upload_channel != *net_group)
+ {
+ printf("NodeQuit-Success: not such net!\n");
+ return 0;
+ }
+
+ // 构建退网数据帧
+ InitLoraFrame(&send_frame);
+ send_frame.dev_addr = node_param.dev_addr;
+ send_frame.down_channel = node_param.down_channel;
+ send_frame.frame_type = E_G_QUIT;
+ send_frame.frame_confirm = FRAME_BYTE_OK;
+
+ PrivMutexObtain(&adapter->lock);
+ // 发送用户数据帧
+ for (int i = 0; i < LORA_FRAME_RETRY; i++)
+ {
+ node_param.session_id = GetSessionId();
+ send_frame.session_id = node_param.session_id;
+
+ // 信道监听
+ SignalDetector(adapter,node_param.down_channel,node_param.upload_channel);
+ // 发送数据帧
+ if (0 != LoraSendFrame(adapter, &send_frame,LORA_GATEWAY_ADDRESS,node_param.upload_channel))
+ {
+ node_param.node_state = NODE_STATE_BROKEN;
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+ }
+ // 等待信号到达
+ PrivTaskDelay(LORA_TIME_ON_AIR * 1000);
+ // 准备数据缓冲区并等待网关响应
+ while (0 == LoraRecvFrame(adapter, &recv_frame))
+ {
+ // 判断数据是否丢失
+ if (recv_frame.session_id == node_param.session_id)
+ {
+ // 判断是否退出成功
+ if (G_E_ANS == recv_frame.frame_type && FRAME_BYTE_OK == recv_frame.frame_attach)
+ {
+ // 配置硬件休眠
+ enum LoraMode aim_mode = MODE_CONFIG_SLEEP;
+ E220Ioctl(adapter,CONFIG_LORA_MODE,&aim_mode);
+ PrivMutexAbandon(&adapter->lock);
+ return 0;
+ }
+ }
+ }
+ }
+ printf("NodeQuit-Fail: quit net fail %d!\n",*net_group);
+ // 配置硬件休眠
+ enum LoraMode aim_mode = MODE_CONFIG_SLEEP;
+ E220Ioctl(adapter,CONFIG_LORA_MODE,&aim_mode);
+ PrivMutexAbandon(&adapter->lock);
+ return -1;
+}
+
+int NodeNetState(struct Adapter *adapter)
+{
+ printf("EndNodeInfos: \n");
+ printf("addr:%d,down_channel:%d,upload_channel:%d,",node_param.dev_addr,node_param.down_channel,node_param.upload_channel);
+ printf("state:%x,air_rate:%x,adr:%x,",node_param.node_state,node_param.air_rate,node_param.adr_enable);
+ printf("reconnect:%x,recv_time:%d \n",node_param.recv_time,node_param.reconnect_enable);
+ return 0;
+}
+
+AdapterProductInfoType LoraAttach(struct Adapter *adapter)
+{
+ struct AdapterProductInfo *product_info = malloc(sizeof(struct AdapterProductInfo));
+ if (!product_info) {
+ printf("LoraAttach-Failed-Node: malloc fail!\n");
+ return NULL;
+ }
+
+ strncpy(product_info->model_name, LORA_ADAPTER_NAME,sizeof(product_info->model_name));
+ product_info->model_done = (void *)&node_done;
+
+ return product_info;
+}
+
+uint8 UsrAdapterLoraRegister(struct Adapter *adapter)
+{
+ strncpy(adapter->name, ADAPTER_LORA_NAME, NAME_NUM_MAX);
+ adapter->net_protocol = PRIVATE_PROTOCOL;
+
+ adapter->net_role = CLIENT;
+ adapter->net_role_id = node_param.dev_addr;
+ adapter->adapter_param = (void *)(&node_param);
+
+ adapter->adapter_status = UNREGISTERED;
+
+ if (AdapterDeviceRegister(adapter) < 0)
+ {
+ printf("UsrAdapterLoraRegister-Fail: lora register error!\n");
+ return -1;
+ }
+
+ printf("UsrAdapterLoraRegister-Success!\n");
+ return 0;
+}
+#endif
\ No newline at end of file
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/lora_mac/lora_mac.h b/APP_Framework/Applications/app_test/test_lora_net_final/lora_mac/lora_mac.h
new file mode 100755
index 000000000..38a9b5e15
--- /dev/null
+++ b/APP_Framework/Applications/app_test/test_lora_net_final/lora_mac/lora_mac.h
@@ -0,0 +1,303 @@
+#include
+#include
+#include "../lora_driver/e220.h"
+
+// #define AS_LORA_GATEWAY
+
+/*数据帧**************************************************************************/
+#define FRAME_BEGIN_MARK 0x3C3C // 帧开始标志,高低字节相同
+#define FRAME_END_MARK 0X5A5A // 帧结束标志,高低字节相同
+#define FRAME_MAX_DATA_LENGTH 200 // 默认支持的最大数据包为200字节
+#define FRAME_ADDR_INFO_LENGTH 3 // 定点传输时前三字节为地址和信道共三个字节
+#define FRAME_META_LENGTH 14 // 数据帧相关信息长度
+#define FRAME_MAX_USER_DATA_LENGTH FRAME_MAX_DATA_LENGTH - FRAME_META_LENGTH - FRAME_ADDR_INFO_LENGTH
+#define FRAME_CRC_INDEX_BEGIN 2 // CRC校验开始地址
+#define FRAME_CRC_LENGTH 8 // CRC校验元数据量长度
+#define FRAME_BYTE_OK 0XFF // 是/成功
+#define FRAME_BYTE_NO 0X00 // 否/失败
+#define FRAME_NECK_LENGTH 8 // 帧头以下,额外数据以上的长度
+#define FRAME_FOOT_LENGTH 4 // 额外数据以下至帧尾的数据长度
+#define FRAME_MARK_LENGTH 2 // 帧头帧尾的数据长度
+
+enum FrameType // 数据帧类型枚举
+{
+ E_G_JOIN = 0, // 客户端入网请求,需回复
+ E_G_QUIT, // 客户端退网请求,不需回复
+ E_G_DATA, // 客户端上传数据,需回复
+ G_E_ANS, // 网关响应客户端请求
+};
+
+struct LoraFrame // 数据帧消息类型
+{
+ uint16 begin_mark; // 开始标志 0x3C3C
+ uint16 session_id; // 会话ID,客户端每次数据上传会随机设置,若是回复ID不一致则表示数据丢失
+ uint16 dev_addr; // 设备地址,特指终端地址,网关地址固定为 0XFFFF
+ uint8 down_channel; // 下行通道,即终端所在的信道
+ uint8 frame_type; // 数据帧的类型
+ uint8 frame_confirm; // 该数据帧是否需要确认回复
+ uint8 frame_attach; // 用于携带简单的数据,例如用户数据长度
+ uint8 *user_data; // 需要额外携带的大量数据
+ uint8 crc_hi; // 校验位高字节
+ uint8 crc_lo; // 校验位低字节
+ uint16 end_mark; // 结束标志 0X5A5A
+};
+
+extern struct LoraFrame send_frame; // 数据帧发送缓冲区
+extern struct LoraFrame recv_frame; // 数据帧接受缓存区
+extern uint8 send_data_buffer[FRAME_MAX_USER_DATA_LENGTH]; // 数据发送缓冲区
+extern uint8 recv_data_buffer[FRAME_MAX_USER_DATA_LENGTH]; // 数据接受缓存区
+extern uint8 total_data_buffer[FRAME_MAX_DATA_LENGTH]; // 数据帧加数据的最大缓冲区
+
+/**
+ * @brief: 将数据帧缓冲区置为 0 ,并添加帧头,帧尾数据
+ * @param frame: 数据帧缓冲区
+*/
+void InitLoraFrame(struct LoraFrame* frame);
+
+/**
+ * @brief: 打印数据帧结构信息,便于运行、开发调试
+ * @param fram: 需要打印的数据帧
+ * @param prefix: 那里打印的数据帧信息
+*/
+void ShowLoraFrame(struct LoraFrame* frame,char* prefix);
+
+/**
+ * @brief: 计算数据帧的校验值,除去帧头、帧尾、校验值本身,若是应该携带数据的类型未携带数据时报错
+ * @return: 消息类型和数据不匹配时为 -1
+*/
+uint8 CalCrlLoraFrame(struct LoraFrame* frame);
+
+/**
+ * @brief: 校验数据帧的完整性
+ * @return: 校验失败为 -1
+*/
+uint8 CheckCrcLoraFrame(struct LoraFrame* frame);
+/*数据帧**************************************************************************/
+
+/*基础操作************************************************************************/
+#define LORA_ADAPTER_NAME "e220"
+#define LORA_OK 0XFF
+#define LORA_NO 0X00
+#define LORA_TIME_ON_AIR 2
+#define LORA_AIR_RATE 0
+#define LORA_FRAME_RETRY 5
+#define LORA_GATEWAY_MAX_CMD 20
+#define LORA_GATEWAY_MAX_NODE 20
+#define LORA_GATEWAY_ADDRESS 0XFFFF
+
+#ifdef AS_LORA_GATEWAY
+
+#define LORA_RECV_TIME 10
+#define LORA_GATEWAY_CHANNEL 0XA
+
+#else
+
+#define LORA_ADDRESS 0X9
+#define LORA_RECV_TIME 5
+#define LORA_DOWN_CHANNEL 0X9
+#define LORA_UP_CHANNEL 0XA
+#define LORA_ADR_ENABLE LORA_NO
+#define LORA_RECONNECT_ENABLE LORA_OK
+#endif
+
+/**
+ * @brief: 从硬件获取一个完整的数据帧
+ * @param recv_buffer: 数据帧缓冲区,在检测到带数据的数据帧时会自动关联数据缓冲区
+ * @param prefix: 调用位置,便于调试
+ * @return 0: 成功接受到一个数据帧(从侦测到数据帧头部开始、成功接受到帧尾部且数据校验成功)
+ * -1:串口超时;数据帧接受不完整;数据帧完整性校验失败;
+*/
+uint8 LoraRecvFrame(struct Adapter* adapter, struct LoraFrame* recv_buffer);
+
+/**
+ * @brief: 通过硬件向指定的位置的信道发送数据
+ * @param send_buffer: 数据帧缓冲区,在检测到带数据的数据帧时会自动发送关联数据缓冲区
+ * @param addr: 目标的地址
+ * @param channel: 目标的信道
+ * @return 0: 成功发送指定长度的数据
+ * -1:未能成功发送制定数据
+*/
+uint8 LoraSendFrame(struct Adapter* adapter, struct LoraFrame* send_buffer,uint16 addr,uint8 channel);
+
+/**
+ * @brief: 在一轮超时后未能接收到信号时判定信道空闲
+ * @param download_channel: 下行信道
+ * @param upload_channel: 上行信道
+*/
+void SignalDetector(struct Adapter *adapter,uint8 download_channel,uint8 upload_channel);
+
+/**
+ * @brief: 获取随机数,用于客户端和网关之间的会话
+*/
+uint16 GetSessionId(void);
+
+/**
+ * @brief: 获取操作函数集合,客户端和网关各自实现
+*/
+AdapterProductInfoType LoraAttach(struct Adapter *adapter);
+
+/**
+ * @brief: 注册函数,需要各自实现
+*/
+uint8 UsrAdapterLoraRegister(struct Adapter *adapter);
+
+/**
+ * @brief: 框架初始化函数,需要替换掉原有的初始化函数
+*/
+int UsrAdapterLoraInit(void);
+
+/*基础操作************************************************************************/
+
+/*客户端操作************************************************************************/
+enum EndNodeState //节点状态
+{
+ NODE_STATE_DISCONNECT = 0, // 硬件开启,但是没有联网,后台程序可能开启
+ NODE_STATE_CONNECT, // 硬件开启,已经联网,后台程序可能开启
+ NODE_STATE_BROKEN, // 硬件损坏,无后台程序
+ NODE_STATE_CLOSED // 硬件关闭,无后台程序
+};
+
+struct EndNodeParam // 节点参数结构
+{
+ uint16 dev_addr; // 设备地址信息
+ uint8 down_channel; // 下行通道,终端可以接收信息的信道
+ uint8 upload_channel; // 上行通道,终端可以给网关发送信息的信道
+ uint16 session_id; // 会话ID,用于判定数据帧是否存在丢失
+
+ enum EndNodeState node_state; // 客户端状态
+ enum LoraAirRate air_rate; // 终端的空中速率
+ uint8 adr_enable; // 终端是否开启自动寻找上行网关
+ uint8 reconnect_enable; // 终端断网自动重联
+ uint8 recv_time; // 接受下行消息的时间窗口长度,单位为秒
+};
+
+extern struct EndNodeParam node_param; // 客户端参数
+extern int (*node_handlers[])(struct Adapter*,struct LoraFrame*); // 客户端处理流程
+
+/**
+ * @brief: 打开终端硬件,按照配置的CLASS决定是否开启硬件接收和后台处理程序
+ * @return: 0 -> Success : -1 -> Fail
+*/
+int NodeOpen(struct Adapter *adapter);
+
+/**
+ * @brief: 关闭终端硬件设施和后台处理程序
+ * @return: 0 -> Success : -1 -> Fail
+*/
+int NodeClose(struct Adapter *adapter);
+
+/**
+ * @brief: 终端接入网关,向该上行通道发送入网请求
+ * @param adapter: 已经打开的适配器
+ * @param net_group: 需要加入的网络编号
+ * @return: 0 -> Success : -1 -> Fail
+*/
+int NodeJoin(struct Adapter *adapter, unsigned char *net_group);
+
+/**
+ * @brief: 发送数据到网关
+ * @param adapter: 已经联网的适配器
+ * @param buf: 待发送数据
+ * @param len: 待发送数据长度
+ * @return: 0 -> Success : -1 -> Fail
+*/
+int NodeSend(struct Adapter *adapter, const void *buf, size_t len);
+
+/**
+ * @brief: 终端退出某个网络
+ * @param adapter: 已经联网的适配器
+ * @param net_group: 需要退出的网络编号
+ * @return: 0 -> Success : -1 -> Fail
+*/
+int NodeQuit(struct Adapter *adapter, unsigned char *net_group);
+
+/**
+ * @brief: 打印终端的信息
+*/
+int NodeNetState(struct Adapter *adapter);
+
+/*客户端操作************************************************************************/
+
+/*网关操作*************************************************************************/
+struct EndNodeInfo // 网关存储的客户端信息
+{
+ uint16 node_addr; // 客户端地址
+ uint8 node_down_channel; // 客户端下行通道
+ uint16 session_id; // 上一个命令的会话ID
+};
+
+enum GatewayState // 网关的状态枚举
+{
+ GATEWAY_CLOSED, // Lora还没有打开
+ GATEWAY_OPENED, // 已打开,但是未开始工作
+ GATEWAY_WORKING, // 正常打开且已经开始正常工作
+ GATEWAY_BROKEN // 模块损坏
+};
+
+struct GatewayParam // 网关参数
+{
+ uint16 dev_addr; // 设备ID
+ uint8 channel; // 网络编号
+
+ int recv_time; // 串口超时时间
+ enum LoraAirRate air_rate; // 网关空中速率
+ uint8 frame_retry; // 重传次数
+ enum GatewayState gateway_state; // 网关状态
+ struct EndNodeInfo *node_infos[LORA_GATEWAY_MAX_NODE]; // 客户端信息
+ uint16 node_count; // 已链接客户端数量
+};
+
+extern struct GatewayParam gateway_param; // 网关参数
+extern int (*gateway_handlers[])(struct Adapter*,struct LoraFrame*); // 处理程序
+
+/**
+ * @brief: 打开Lora硬件设施,但是不会将其接入网络中
+*/
+int GatewayOpen(struct Adapter *adapter);
+
+/**
+ * @brief: 关闭硬件设施,需要先断网
+*/
+int GatewayClose(struct Adapter *adapter);
+
+/**
+ * @brief: 配置网关参数的配置接口,这个函数配置的是网关的参数
+*/
+int GatewayIoctl(struct Adapter *adapter, int cmd, void *args);
+
+/**
+ * @brief: 启用网关,使其可以为其他终端服务
+*/
+int GatewaySetup(struct Adapter *adapter);
+
+/**
+ * @brief: 停用网关,但是不会给网络中的终端下线通知
+*/
+int GatewaySetDown(struct Adapter *adapter);
+
+/**
+ * @brief: 打印网关相关信息
+*/
+int GatewayNetState(struct Adapter *adapter);
+
+/**
+ * @brief: 网关主任务,负责终端各项事务的自动化处理
+*/
+void* GatewayTask(void* adapter);
+
+/**
+ * @brief: 处理终端入网请求
+*/
+int GatewayJoinHandler(struct Adapter* adapter,struct LoraFrame* frame);
+
+/**
+ * @brief: 处理终端退网
+*/
+int GatewayQuitHandler(struct Adapter* adapter,struct LoraFrame* frame);
+
+/**
+ * @brief: 处理终端数据传输
+*/
+int GatewayDataSendHandler(struct Adapter* adapter,struct LoraFrame* frame);
+
+/*网关操作*************************************************************************/
\ No newline at end of file
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/test_lora_net_final.c b/APP_Framework/Applications/app_test/test_lora_net_final/test_lora_net_final.c
new file mode 100755
index 000000000..e7bc5325f
--- /dev/null
+++ b/APP_Framework/Applications/app_test/test_lora_net_final/test_lora_net_final.c
@@ -0,0 +1,96 @@
+#include "test_lora_net_final.h"
+
+#ifdef AS_LORA_GATEWAY
+
+/**
+ * @brief: 网关测试函数
+ * 1. 打开Lora硬件设施.
+ * 2. 接入网络.
+*/
+void TestGateway(void)
+{
+ struct Adapter* gateway_adapter = (struct Adapter*)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
+ // 打开设备
+ if (0 != AdapterDeviceOpen(gateway_adapter))
+ {
+ printf("TestGateway-Fail: open lora fail!\n");
+ return;
+ }
+ printf("TestGateway-Info: open lora success!\n");
+ // 接入网络
+ if (0 != AdapterDeviceSetUp(gateway_adapter))
+ {
+ printf("TestGateway-Fail: setup net fail!\n");
+ return;
+ }
+ printf("TestGateway-Success: gateway set up success!\n");
+ AdapterDeviceNetstat(gateway_adapter);
+}
+PRIV_SHELL_CMD_FUNCTION(TestGateway,TestGateway, PRIV_SHELL_CMD_MAIN_ATTR);
+
+/**
+ * 打印网关信息
+*/
+void TestGatewayInfo(void)
+{
+ struct Adapter* gateway_adapter = (struct Adapter*)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
+ AdapterDeviceNetstat(gateway_adapter);
+}
+PRIV_SHELL_CMD_FUNCTION(TestGatewayInfo,TestGatewayInfo, PRIV_SHELL_CMD_MAIN_ATTR);
+
+#else
+
+/**
+ * @brief: 节点测试函数
+ * 1. 打开Lora硬件设施.
+ * 2. 连接到网关.
+*/
+void TestNodeUp(void)
+{
+ struct Adapter* node_adapter = (struct Adapter*)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
+ // 打开设备
+ if (0 != AdapterDeviceOpen(node_adapter))
+ {
+ printf("TestNodeUp-Fail: open lora fail!\n");
+ return;
+ }
+ AdapterDeviceNetstat(node_adapter);
+ // 接入网络
+ uint8 net_id = 0XA;
+ if (0 != AdapterDeviceJoin(node_adapter,&net_id))
+ {
+ printf("TestNodeUp-Fail: join net fail!\n");
+ return;
+ }
+ AdapterDeviceNetstat(node_adapter);
+}
+PRIV_SHELL_CMD_FUNCTION(TestNodeUp,TestNodeUp, PRIV_SHELL_CMD_MAIN_ATTR);
+
+/**
+ * @brief: 发送数据
+*/
+void TestNodeSend(void)
+{
+ char* data = "Hello,Gateway-OtherNode!";
+ struct Adapter* node_adapter = (struct Adapter*)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
+ AdapterDeviceSend(node_adapter,data,strlen(data));
+ AdapterDeviceNetstat(node_adapter);
+}
+PRIV_SHELL_CMD_FUNCTION(TestNodeSend,TestNodeSend, PRIV_SHELL_CMD_MAIN_ATTR);
+
+/**
+ * @brief: 循环发送数据
+*/
+void TestNodeSendCycle(void)
+{
+ int cycle_count = 5;
+ char* data = "Hello,Gateway-OtherNode-Cycle!";
+ struct Adapter *node_adapter = (struct Adapter *)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
+ while (cycle_count -- > 0)
+ {
+ AdapterDeviceSend(node_adapter, data, strlen(data));
+ AdapterDeviceNetstat(node_adapter);
+ }
+}
+PRIV_SHELL_CMD_FUNCTION(TestNodeSendCycle,TestNodeSendCycle, PRIV_SHELL_CMD_MAIN_ATTR);
+#endif
\ No newline at end of file
diff --git a/APP_Framework/Applications/app_test/test_lora_net_final/test_lora_net_final.h b/APP_Framework/Applications/app_test/test_lora_net_final/test_lora_net_final.h
new file mode 100755
index 000000000..1ab38fe96
--- /dev/null
+++ b/APP_Framework/Applications/app_test/test_lora_net_final/test_lora_net_final.h
@@ -0,0 +1,28 @@
+#include
+#include
+
+// #define AS_LORA_GATEWAY
+
+/**
+ * @brief: 节点测试函数
+ * 1. 打开Lora硬件设施.
+ * 2. 连接到网关.
+*/
+void TestNodeUp(void);
+
+/**
+ * @brief: 发送数据
+*/
+void TestNodeSend(void);
+
+/**
+ * @brief: 循环发送数据
+*/
+void TestNodeSendCycle(void);
+
+/**
+ * @brief: 网关测试函数
+ * 1. 打开Lora硬件设施.
+ * 2. 接入网络.
+*/
+void TestGateway(void);
\ No newline at end of file
diff --git a/APP_Framework/Applications/app_test/test_lora_p2p/README.md b/APP_Framework/Applications/app_test/test_lora_p2p/README.md
new file mode 100755
index 000000000..3bc748a9b
--- /dev/null
+++ b/APP_Framework/Applications/app_test/test_lora_p2p/README.md
@@ -0,0 +1,154 @@
+# 基于RISC-V终端,实现LoRa节点和LoRa网关通信私有协议
+
+## 一、简介
+在RISC-V终端上实现LoRa节点和LoRa网关私有协议通信功能,客户端可以通过SHELL终端连接\断开网关,并可以向网关发送数据.
+
+## 二、数据结构设计说明
+### 1、Lora工作模式枚举
+```c
+enum LoraMode
+{
+ LORA_SLEEP = 0, // 切换至休眠模式
+ LORA_WORK = 1 // 切换至工作模式
+};
+```
+在客户端需要传输数据时,Lora会工作在普通模式进行数据传输,在客户端数据传输完毕后,Lora会切换到休眠模式以屏蔽数据。
+
+### 2、客户端/网关状态信息
+```c
+enum ClientState
+{
+ CLIENT_DISCONNECT = 0, // 开启但断网
+ CLIENT_CONNECT, // 开启且联网
+ CLIENT_BROKEN, // 硬件损坏
+ CLIENT_CLOSED // 硬件关闭
+};
+enum GatewayState
+{
+ GATEWAY_ORIGINAL= 0, // 关闭且未开始工作
+ GATEWAY_WORKING, // 开启且已经开始工作
+ GATEWAY_BROKEN // 模块损坏
+};
+```
+### 3、客户端/网关参数信息
+```c
+struct ClientParam
+{
+ uint8_t client_id;
+ uint8_t panid;
+ uint8_t gateway_id;
+ enum ClientState client_state;
+ pthread_mutex_t client_mutex; // 互斥量
+};
+struct GatewayParam
+{
+ uint8_t gateway_id;
+ uint8_t panid;
+ uint8_t client_infos[GATEWAY_MAX_CLIENT_NUM];
+ uint8_t client_num;
+ enum GatewayState gateway_state;
+ pthread_mutex_t gateway_mutex; // 互斥量
+};
+```
+### 4、数据帧类型枚举
+```c
+enum FrameType
+{
+ /*C ---> G*/
+ CG_NET_JOIN = 0, // 入网请求
+ CG_NET_QUIT, // 退网请求
+ CG_DATA_SEND, // 数据传输请求
+ /*G ---> C*/
+ GC_REPLY_EXPECTED, // 上行请求执行成功
+ GC_REPLY_UNEXPECTED, // 上行请求执行失败
+};
+```
+### 5、数据帧结构设计
+```c
+struct DataFrameFormat
+{
+ uint8_t begin_mark_1; // 0XFF
+ uint8_t begin_mark_2; // 0XAA
+ uint8_t client_id; // 0 - 127
+ uint8_t panid; // 0 - 127
+ uint8_t gateway_id; // 0 - 127
+ uint8_t frame_type; // 0 - 127
+ uint8_t attach_data; // 0 - 127 可以是数据长度,该值的意义视数据帧类型而定
+ uint8_t* user_data; // 在有数据携带时才会发送该指针所指缓冲区数据
+ uint8_t crc_hi; // 这个字节没有0XFF
+ uint8_t crc_lo; // 这个字节会出现 0XFF,但是他的下一个字节不可能是00,必然是0XFF
+ uint8_t end_mark_1; // 0XFF
+ uint8_t end_mark_2; // 0X00
+};
+```
+## 三、包含以下功能
+### 1、客户端联网/退网/数据传输操作
+> (1)、获取使用权后将其配置为传输模式。
+> (2)、构建数据帧并设置好数据帧类型。
+> (3)、监听信道直到信道空闲。
+> (4)、发送数据帧(若是数据传输需要带上数据一起传输),若失败回到第三步。
+> (5)、接收数据帧并对数据帧进行数据过滤,若失败回到第三步。
+> (6)、解析数据帧并得到结果
+### 2、网关后台任务操作
+> (1)、获取使用权后开启数据接收。
+> (2)、根据数据帧结构,监听信道,过滤掉杂乱的信号,在接收到一个完整的数据帧并完整性校验通过后返回继续第三步,否则循环执行第二步。
+> (3)、根据得到的数据帧类型将其交付给对应的处理器处理,处理完毕后返回第二步。
+
+## 四、测试程序说明
+在进行测试时,最好先启动网关并开启网关程序,当然后启动网关也一样。
+### 1、客户端测试程序
+> (1)、`TestLoraConnectState`命令可以进行网络连接或者断开,`0-CLIENT_DISCONNECT 1-CLIENT_CONNECT`。
+> (2)、`TestLoraSendData`命令可以发送数据(联网状态下),请使用字符串(`void TestLoraSendData(char* data)`)。
+> (3)、`TestLoraClient`命令可以整体测试,先进行联网,再发送数据,再断开连接,最后再联网。
+### 2、网关测试程序
+> (1)、`TestLoraGateway`命令可以启动网关程序。
+
+## 五、运行结果(##需结合运行测试截图按步骤说明##)
+### 1、修改必要的框架和驱动代码
+
+#### 修改文件: `xiuos/APP_Framework/Framework/framework_init.c`
+1. 在第`28`行添加代码: `extern int UsrAdapterLoraInit(void);`;
+2. 将第`170`行代码的`AdapterLoraInit`修改为`UsrAdapterLoraInit`,更换Lora的初始化函数;
+
+#### 修改文件:`xiuos/APP_Framework/Framework/connection/lora/e220/e220.c`
+1. 将第`429`行代码修改为`cfg.serial_timeout = 5000;`,更改客户端超时时间;
+2. 为第`478`行的`E220Ioctl`添加函数体:
+```c
+static int E220Ioctl(struct Adapter *adapter, int cmd, void *args)
+{
+ switch (cmd)
+ {
+ case 0: // LORA_SLEEP
+ E220LoraModeConfig(CONFIGURE_MODE_MODE); // 切换至休眠模式
+ break;
+ case 1: // LORA_WORK
+ E220LoraModeConfig(DATA_TRANSFER_MODE); // 切换至传输模式
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+```
+### 2、修改Makefile
+
+#### 修改文件: `xiuos/APP_Framework/Applications/app_test/Makefile` 第 `137` 行为 `SRC_FILES += test_lora_p2p/test_lora_p2p.c`
+### 3、menuconfig配置
+1. `APP_Framework > Applications > test app` 开启 `Enable application test function` ,然后进入其中,开启 `Config test lora p2p (NEW)` ;
+
+2. `APP_Framework > Framework` 开启 `support connection framework (NEW)` ,然后进入其中,开启 `Using lora adapter device (NEW)` ,然后进入其中, 客户端将其配置如下图所示,网关将其配置为下下图所示;
+
+
+3. 将客户端和网关分别编译、烧录到不同的板子并启动后用串口进行连接;
+
+4. 启动网关程序;
+
+5. 整体测试客户端;
+
+6. 测试断网
+
+7. 测试联网
+
+8. 测试数据发送
+
\ No newline at end of file
diff --git a/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-1.png b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-1.png
new file mode 100755
index 000000000..cd4f859f9
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-1.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-2-1.png b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-2-1.png
new file mode 100755
index 000000000..aedf8eaf2
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-2-1.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-2-2.png b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-2-2.png
new file mode 100755
index 000000000..18cd03d99
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-2-2.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-3.png b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-3.png
new file mode 100755
index 000000000..181d471c0
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-3.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-4.png b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-4.png
new file mode 100755
index 000000000..71673186c
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-4.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-5.png b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-5.png
new file mode 100755
index 000000000..8a73cc1eb
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-5.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-6.png b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-6.png
new file mode 100755
index 000000000..29ccfa34d
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-6.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-7.png b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-7.png
new file mode 100755
index 000000000..2605a964e
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-7.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-8.png b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-8.png
new file mode 100755
index 000000000..1aa130aa5
Binary files /dev/null and b/APP_Framework/Applications/app_test/test_lora_p2p/images/5-3-8.png differ
diff --git a/APP_Framework/Applications/app_test/test_lora_p2p/test_lora_p2p.c b/APP_Framework/Applications/app_test/test_lora_p2p/test_lora_p2p.c
new file mode 100644
index 000000000..9e9ac72f1
--- /dev/null
+++ b/APP_Framework/Applications/app_test/test_lora_p2p/test_lora_p2p.c
@@ -0,0 +1,826 @@
+#include "test_lora_p2p.h"
+
+/******************************public_operate*********************************/
+static const uint8_t table_crc_hi[] =
+ {
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40};
+
+static const uint8_t table_crc_lo[] =
+ {
+ 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
+ 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
+ 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
+ 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
+ 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
+ 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
+ 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40};
+
+struct DataFrameFormat frame_send_buffer; // 消息发送缓冲区
+struct DataFrameFormat frame_recv_buffer; // 消息接收缓冲区
+uint8_t data_buffer[LORA_FRAME_USER_MAX_LENGTH]; // 数据发送/接收缓冲区
+
+// 按照要求计算出数据帧的校验值
+static uint8_t CalCrcDataFrameFormat(struct DataFrameFormat *frame)
+{
+ uint8_t crc_hi = 0xFF;
+ uint8_t crc_lo = 0xFF;
+ unsigned int temp;
+ uint8_t *bit_arr = (uint8_t *)frame; // 转化为字节的方式进行数据访问
+
+ uint8_t *temp_begin = bit_arr + 2; // 指向第二个数据段
+ for (int i = 0; i < 5; i++) // 计算第二个字段到第六个字段,计算完毕该指针失效
+ {
+ temp = crc_hi ^ *temp_begin++;
+ crc_hi = crc_lo ^ table_crc_hi[temp];
+ crc_lo = table_crc_lo[temp];
+ }
+
+ if (CG_DATA_SEND == frame->frame_type) // 是否携带了上传数据
+ {
+ if (NULL == frame->user_data)
+ {
+ printf("CalCrcDataFrameFormat: User data is null\n");
+ return -1;
+ }
+ uint8_t data_length = frame->attach_data;
+ temp_begin = frame->user_data;
+ for (int i = 0; i < data_length; i++) // 计算上传数据的校验值
+ {
+ temp = crc_hi ^ *temp_begin++;
+ crc_hi = crc_lo ^ table_crc_hi[temp];
+ crc_lo = table_crc_lo[temp];
+ }
+ }
+
+ frame->crc_lo = crc_lo;
+ frame->crc_hi = crc_hi;
+
+ return 0;
+}
+
+// 按照要求计算出数据帧的校验值
+static uint8_t CheckCrcDataFrameFormat(struct DataFrameFormat *frame)
+{
+ uint8_t crc_hi = 0xFF;
+ uint8_t crc_lo = 0xFF;
+ unsigned int temp;
+ uint8_t *bit_arr = (uint8_t *)frame; // 转化为字节的方式进行数据访问
+
+ uint8_t *temp_begin = bit_arr + 2; // 指向第二个数据段
+ for (int i = 0; i < 5; i++) // 计算第二个字段到第六个字段,计算完毕该指针失效
+ {
+ temp = crc_hi ^ *temp_begin++;
+ crc_hi = crc_lo ^ table_crc_hi[temp];
+ crc_lo = table_crc_lo[temp];
+ }
+
+ if (CG_DATA_SEND == frame->frame_type) // 是否携带了上传数据
+ {
+ if (NULL == frame->user_data)
+ {
+ printf("CheckCrcDataFrameFormat: User data is null\n");
+ return -1;
+ }
+ uint8_t data_length = frame->attach_data;
+ temp_begin = frame->user_data;
+ for (int i = 0; i < data_length; i++) // 计算上传数据的校验值
+ {
+ temp = crc_hi ^ *temp_begin++;
+ crc_hi = crc_lo ^ table_crc_hi[temp];
+ crc_lo = table_crc_lo[temp];
+ }
+ }
+
+ frame->crc_lo = crc_lo;
+ frame->crc_hi = crc_hi;
+
+ return (frame->crc_hi == crc_hi && frame->crc_lo == crc_lo) ? 0 : -1;
+}
+
+// 初始化数据帧的头部标识和尾部标识
+static void InitFrame(struct DataFrameFormat *frame)
+{
+ memset(frame, 0, sizeof(struct DataFrameFormat));
+ frame->begin_mark_1 = LORA_FRAME_BEGIN_MARK_1;
+ frame->begin_mark_2 = LORA_FRAME_BEGIN_MARK_2;
+ frame->end_mark_1 = LORA_FRAME_END_MARK_1;
+ frame->end_mark_2 = LORA_FRAME_END_MARK_2;
+}
+
+// 空中信号探测器,用于简易的信道碰撞检测,当一个周期未能收到数据时判定为信道空闲
+static uint8_t SignalDetector(struct Adapter *adapter)
+{
+ uint8_t temp_dst;
+ while (1 == AdapterDeviceRecv(adapter, &temp_dst, 1)) // 当读取数据超时时假定为信道空闲
+ {
+ printf("SignalDetector: Channel Occupied\n");
+ }
+ printf("SignalDetector: Channel Idle\n");
+ return 0;
+}
+
+// 打印消息头数据
+static void PrintFrame(struct DataFrameFormat *frame, char *prefix)
+{
+ printf("%s: ", prefix);
+ printf("client: %X, pan: %X, gateway: %X, frame_type: ", frame->client_id, frame->panid, frame->gateway_id);
+ switch (frame->frame_type)
+ {
+ case CG_NET_JOIN:
+ printf(" - CG_NET_JOIN- ");
+ break;
+ case CG_NET_QUIT:
+ printf(" - CG_NET_QUIT- ");
+ break;
+ case CG_DATA_SEND:
+ printf(" - CG_DATA_SEND- ");
+ break;
+ case GC_REPLY_EXPECTED:
+ printf(" - GC_REPLY_EXPECTED- ");
+ break;
+ case GC_REPLY_UNEXPECTED:
+ printf(" - GC_REPLY_UNEXPECTED- ");
+ break;
+ default:
+ break;
+ }
+ printf("attach_data: %X, crc: %X %X ", frame->attach_data, frame->crc_hi, frame->crc_lo);
+ if (frame->frame_type == CG_DATA_SEND)
+ {
+ frame->user_data[frame->attach_data] = '\0';
+ printf("user_data: %s \n", frame->user_data);
+ }
+ else
+ {
+ printf("\n");
+ }
+}
+
+// 接收直到一个完整的数据帧并校验其完整性,不完整的数据会被丢弃
+static uint8_t RecvFrame(struct Adapter *adapter, struct DataFrameFormat *frame)
+{
+ memset(frame, 0, sizeof(struct DataFrameFormat)); // 缓冲区数据初始化
+ uint8_t header_temp[2] = {0, 0}; // 头部数据查找缓冲区,一个用于接收数据,一个用于存储上一次接收到的数据
+
+ while (1 == AdapterDeviceRecv(adapter, &header_temp[1], 1)) // 查找开始标志
+ {
+ if (LORA_FRAME_BEGIN_MARK_2 == header_temp[1]) // 查找到了第二个标志
+ {
+ if (LORA_FRAME_BEGIN_MARK_1 == header_temp[0]) // 查看上一次的数据是不是第一个标识
+ {
+ frame->begin_mark_1 = header_temp[0];
+ frame->begin_mark_2 = header_temp[1];
+ // 开始按照结构读取数据
+ if (LORA_FRAME_NECK_LENGTH == AdapterDeviceRecv(adapter, &frame->client_id, LORA_FRAME_NECK_LENGTH)) // 接收除可能的用户数据以外的数据
+ {
+ // 判断是否有用户数据
+ if (CG_DATA_SEND == frame->frame_type) // 存在用户数据
+ {
+ frame->user_data = data_buffer; // 关联数据缓冲区用于接收数据
+ if (frame->attach_data != AdapterDeviceRecv(adapter, data_buffer, frame->attach_data)) // 接收数据
+ {
+ printf("RecvFrame: Timeout or Failed 5\n");
+ break; // 接收用户数据失败或者超时
+ }
+ }
+ // 继续接收接下来的数据
+ if (LORA_FRAME_CRC_LENGTH + LORA_FRAME_MARK_LENGTH == AdapterDeviceRecv(adapter, &frame->crc_hi, LORA_FRAME_CRC_LENGTH + LORA_FRAME_MARK_LENGTH))
+ {
+ // 判断数据帧的完善性,看是否有尾巴
+ if (LORA_FRAME_END_MARK_1 == frame->end_mark_1 && LORA_FRAME_END_MARK_2 == frame->end_mark_2)
+ {
+ // 进行数据完整性校验
+ if (0 == CheckCrcDataFrameFormat(frame))
+ {
+ return 0; // 成功接收了一帧数据
+ }
+ printf("RecvFrame: CRC ERROR!\n");
+ break;
+ }
+ printf("RecvFrame: End ERROR!\n");
+ break;
+ }
+ printf("RecvFrame: Timeout or Failed 4\n");
+ break;
+ }
+ printf("RecvFrame: Timeout or Failed 3\n");
+ break; // 找到了头数据,却没能收到完整数据的全部失败
+ }
+ else
+ {
+ header_temp[0] = header_temp[1]; // 记录这一次的数据
+ }
+ }
+ else
+ {
+ header_temp[0] = header_temp[1]; // 记录这一次的数据
+ }
+ }
+
+ return -1;
+}
+
+// 计算消息头校验并发送出去
+static uint8_t SendFrame(struct Adapter *adapter, struct DataFrameFormat *frame)
+{
+ // 校验数据
+ if (0 == CalCrcDataFrameFormat(frame))
+ {
+ // 发送公共信息
+ if (LORA_FRAME_MARK_LENGTH + LORA_FRAME_NECK_LENGTH == AdapterDeviceSend(adapter, frame, LORA_FRAME_MARK_LENGTH + LORA_FRAME_NECK_LENGTH))
+ {
+ // 判断是否有需要发送的用户数据
+ if (CG_DATA_SEND == frame->frame_type)
+ {
+ if (frame->attach_data != AdapterDeviceSend(adapter, frame->user_data, frame->attach_data))
+ {
+ return -1;
+ }
+ }
+ // 发送剩下的数据
+ if (LORA_FRAME_MARK_LENGTH + LORA_FRAME_CRC_LENGTH == AdapterDeviceSend(adapter, &frame->crc_hi, LORA_FRAME_MARK_LENGTH + LORA_FRAME_CRC_LENGTH))
+ {
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+
+// 切换Lora的工作模式
+static void LoraModeConfig(struct Adapter *adapter, enum LoraMode mode)
+{
+ if (adapter->net_protocol == PRIVATE_PROTOCOL)
+ {
+ struct PrivProtocolDone *done = (struct PrivProtocolDone *)adapter->done;
+ done->ioctl(adapter, mode, NULL);
+
+ printf("LoraModeConfig: Config Lora %s\n", mode == LORA_WORK ? "Working" : "Sleeping");
+ }
+ else
+ {
+ printf("LoraModeConfig: Config Lora Fail\n");
+ }
+}
+
+// 客户端数据帧过滤器
+static uint8_t LoraClientFrameFilter(struct ClientParam *client_param, struct DataFrameFormat *frame)
+{
+ if (client_param->panid != frame->panid) // 是否是同一个网络
+ {
+ printf("LoraFrameFilter: Different Networks\n");
+ return -1;
+ }
+
+ if (client_param->gateway_id != 0 && client_param->gateway_id != frame->gateway_id) // 不是该客户端所连接的网关
+ {
+ printf("LoraFrameFilter: Different Gateway\n");
+ return -1;
+ }
+
+ if (client_param->client_id != frame->client_id) // 不是该客户端所连接的网关
+ {
+ printf("LoraFrameFilter: Not For This Client\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+// 网关数据帧过滤器
+static uint8_t LoraGatewayFrameFilter(struct GatewayParam *gateway_param, struct DataFrameFormat *frame)
+{
+ if (gateway_param->panid != frame->panid) // 是否是同一个网络
+ {
+ printf("LoraFrameFilter: Different Networks\n");
+ return -1;
+ }
+
+ if (frame->gateway_id == 0 && frame->frame_type == CG_NET_JOIN) // 入网请求
+ {
+ return 0;
+ }
+
+ if (frame->gateway_id != gateway_param->gateway_id) // 不是该网关所连接的客户端
+ {
+ printf("LoraFrameFilter: Different Gateway\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/******************************client_operate*********************************/
+static uint8_t LoraClientConnectState(struct Adapter *adapter, enum ClientState aim_state)
+{
+ if (aim_state == CLIENT_CONNECT || aim_state == CLIENT_DISCONNECT) // 只支持联网和退网
+ {
+ struct ClientParam *client_param = (struct ClientParam *)adapter->adapter_param;
+
+ if (client_param->client_state == aim_state) // 已经处于目标状态
+ {
+ printf("LoraClientConnectState: Client %s Before\n", aim_state == CLIENT_CONNECT ? "Connect" : "Disconnect");
+ return 0;
+ }
+
+ PrivMutexObtain(&client_param->client_mutex); // 获取lora的使用权
+ LoraModeConfig(adapter, LORA_WORK); // 切换Lora到普通接收模式
+
+ InitFrame(&frame_send_buffer); // 准备数据帧
+ frame_send_buffer.client_id = client_param->client_id;
+ frame_send_buffer.panid = client_param->panid;
+ frame_send_buffer.gateway_id = client_param->gateway_id;
+ frame_send_buffer.frame_type = aim_state == CLIENT_CONNECT ? CG_NET_JOIN : CG_NET_QUIT;
+
+ while (1) // 不停的发送信息直到收到正确的响应
+ {
+ SignalDetector(adapter); // 监听信道直到信道空闲
+
+ if (0 == SendFrame(adapter, &frame_send_buffer))
+ {
+ printf("LoraClientConnectState: Send Frame Success\n");
+ PrintFrame(&frame_send_buffer, "LoraClientConnectState Send");
+ if (0 == RecvFrame(adapter, &frame_recv_buffer)) // 成功接收到了一个数据帧
+ {
+ printf("LoraClientConnectState: Recv Frame Success\n");
+ PrintFrame(&frame_recv_buffer, "LoraClientConnectState Recv");
+ if (0 == LoraClientFrameFilter(client_param, &frame_recv_buffer)) // 判断这个数据帧是不是自己
+ {
+ if (frame_recv_buffer.frame_type == GC_REPLY_EXPECTED) // 请求成功
+ {
+ client_param->gateway_id = aim_state == CLIENT_CONNECT ? frame_recv_buffer.gateway_id : 0;
+ client_param->client_state = aim_state;
+
+ printf("LoraClientConnectState: Success - > Client(%X) Gateway(%X) %s\n", client_param->client_id, client_param->gateway_id, aim_state == CLIENT_CONNECT ? "Connect" : "Disconnect");
+ break;
+ }
+ else
+ {
+ printf("LoraClientConnectState: Fail And Try Again\n");
+ }
+ }
+ }
+ else
+ {
+ printf("LoraClientConnectState: Recv Frame Failed\n");
+ }
+ }
+ else
+ {
+ printf("LoraClientConnectState: Send Frame Failed\n");
+ }
+ }
+
+ LoraModeConfig(adapter, LORA_SLEEP); // 切换Lora到休眠状态
+ PrivMutexAbandon(&client_param->client_mutex); // 释放Lora
+
+ return 0;
+ }
+ else
+ {
+ printf("LoraClientConnectState: Not Supported!\n");
+ return -1;
+ }
+}
+
+static uint8_t LoraClientSendData(struct Adapter *adapter, uint8_t *data_buffer, uint8_t data_length)
+{
+ struct ClientParam *client_param = (struct ClientParam *)adapter->adapter_param;
+
+ if (client_param->client_state == CLIENT_CONNECT) // 只有处于联网状态的客户端才可以进行数据传输任务
+ {
+ PrivMutexObtain(&client_param->client_mutex); // 拿到控制权
+ LoraModeConfig(adapter, LORA_WORK); // 切换Lora为工作模式
+
+ InitFrame(&frame_send_buffer); // 准备消息头
+ frame_send_buffer.client_id = client_param->client_id;
+ frame_send_buffer.panid = client_param->panid;
+ frame_send_buffer.gateway_id = client_param->gateway_id;
+ frame_send_buffer.frame_type = CG_DATA_SEND;
+ frame_send_buffer.user_data = data_buffer; // 关联数据缓冲区
+ frame_send_buffer.attach_data = data_length; // 数据长度
+
+ while (1) // 不停的发送信息直到收到正确的响应
+ {
+ SignalDetector(adapter); // 监听信道直到信道空闲
+
+ if (0 == SendFrame(adapter, &frame_send_buffer))
+ {
+ printf("LoraClientSendData: Send Frame Success\n");
+ PrintFrame(&frame_send_buffer, "LoraClientSendData Send");
+ if (0 == RecvFrame(adapter, &frame_recv_buffer)) // 成功接收到了一个数据帧
+ {
+ printf("LoraClientSendData: Recv Frame Success\n");
+ PrintFrame(&frame_recv_buffer, "LoraClientSendData Recv");
+ if (0 == LoraClientFrameFilter(client_param, &frame_recv_buffer)) // 判断这个数据帧是不是自己
+ {
+ if (frame_recv_buffer.frame_type == GC_REPLY_EXPECTED) // 发送成功
+ {
+ printf("LoraClientSendData: Send Data Success\n");
+ break;
+ }
+ else
+ {
+ printf("LoraClientSendData: Fail And Try Again\n");
+ }
+ }
+ }
+ else
+ {
+ printf("LoraClientSendData: Recv Frame Failed\n");
+ }
+ }
+ else
+ {
+ printf("LoraClientSendData: Send Frame Failed\n");
+ }
+ }
+
+ LoraModeConfig(adapter, LORA_SLEEP); // 切换Lora到睡眠模式
+ PrivMutexAbandon(&client_param->client_mutex); // 释放Lora
+
+ return 0;
+ }
+ else
+ {
+ printf("LoraClientSendData: Client Is Disconnect\n");
+ return -1;
+ }
+}
+
+/**************************gateway_handlers*********************************/
+
+// 网关处理客户端入网请求
+static uint8_t GatewayJoinNetHandler(struct Adapter *adapter, struct DataFrameFormat *frame)
+{
+ PrintFrame(frame, "GatewayJoinNetHandler Recv");
+
+ struct GatewayParam *gateway_param = (struct GatewayParam *)adapter->adapter_param;
+
+ frame->gateway_id = gateway_param->gateway_id; // 确保网关设备参数正确传递
+
+ if (gateway_param->client_num == GATEWAY_MAX_CLIENT_NUM) // 判断网关连接的客户端是否达到上限
+ {
+ printf("GatewayJoinNetHandler: Too much client\n");
+ frame->frame_type = GC_REPLY_UNEXPECTED;
+ if (0 != SendFrame(adapter, frame))
+ {
+ printf("GatewayJoinNetHandler: Client(%X) Join Gateway(%X) Failed 1 !\n", frame->client_id, gateway_param->gateway_id);
+ return -1;
+ }
+ PrintFrame(frame, "GatewayJoinNetHandler Send");
+ printf("GatewayJoinNetHandler: Client(%X) Join Gateway(%X) Failed (MAX)!\n", frame->client_id, gateway_param->gateway_id);
+ return -1;
+ }
+
+ for (int i = 0; i < gateway_param->client_num; i++) // 判断该客户端是否已经连接过了
+ {
+ if (gateway_param->client_infos[i] == frame->client_id)
+ {
+ printf("GatewayJoinNetHandler: Joined before\n");
+ frame->frame_type = GC_REPLY_EXPECTED;
+ if (0 != SendFrame(adapter, frame))
+ {
+ printf("GatewayJoinNetHandler: Client(%X) Join Gateway(%X) Failed 2 !\n", frame->client_id, gateway_param->gateway_id);
+ return -1;
+ }
+ PrintFrame(frame, "GatewayJoinNetHandler Send");
+ printf("GatewayJoinNetHandler: Client(%X) Join Gateway(%X) Success!\n", frame->client_id, gateway_param->gateway_id);
+ return 0;
+ }
+ }
+
+ gateway_param->client_infos[gateway_param->client_num] = frame->client_id;
+ gateway_param->client_num++;
+ frame->frame_type = GC_REPLY_EXPECTED; // 成功连接到网关
+ frame->gateway_id = gateway_param->gateway_id;
+ if (0 != SendFrame(adapter, frame))
+ {
+ printf("GatewayJoinNetHandler: Client(%X) Join Gateway(%X) Failed 3 !\n", frame->client_id, gateway_param->gateway_id);
+ return -1;
+ }
+ PrintFrame(frame, "GatewayJoinNetHandler Send");
+ printf("GatewayJoinNetHandler: Client(%X) Join Gateway(%X) Success!\n", frame->client_id, gateway_param->gateway_id);
+ return 0;
+}
+
+// 网关处理客户端退网请求
+static uint8_t GatewayQuitNetHandler(struct Adapter *adapter, struct DataFrameFormat *frame)
+{
+ PrintFrame(frame, "GatewayQuitNetHandler Recv");
+
+ struct GatewayParam *gateway_param = (struct GatewayParam *)adapter->adapter_param;
+
+ for (int i = 0; i < gateway_param->client_num; i++)
+ {
+ // 移除这个客户端的信息
+ if (gateway_param->client_infos[i] == frame->client_id)
+ {
+ for (int j = i; j < gateway_param->client_num - 1; j++)
+ {
+ gateway_param->client_infos[j] = gateway_param->client_infos[j + 1];
+ }
+ gateway_param->client_num--;
+ break;
+ }
+ }
+
+ frame->frame_type = GC_REPLY_EXPECTED;
+ if (0 != SendFrame(adapter, frame))
+ {
+ printf("GatewayQuitNetHandler: Client(%X) Quit Gateway(%X) Failed!\n", frame->client_id, gateway_param->gateway_id);
+ return -1;
+ }
+ PrintFrame(frame, "GatewayQuitNetHandler Send");
+ printf("GatewayQuitNetHandler: Client(%X) Quit Gateway(%X) Success!\n", frame->client_id, gateway_param->gateway_id);
+ return 0;
+}
+
+// 网关处理客户端的数据传输请求
+static uint8_t GatewayDataSendHandler(struct Adapter *adapter, struct DataFrameFormat *frame)
+{
+ PrintFrame(frame, "GatewayDataSendHandler Recv");
+
+ frame->frame_type = GC_REPLY_EXPECTED;
+
+ if (0 != SendFrame(adapter, frame))
+ {
+ printf("GatewayDataSendHandler: Client(%X) Send Data To Gateway(%X) Failed!\n", frame->client_id, frame->gateway_id);
+ return -1;
+ }
+ PrintFrame(frame, "GatewayDataSendHandler Send");
+ printf("GatewayDataSendHandler: Client(%X) Send Data To Gateway(%X) Success!\n", frame->client_id, frame->gateway_id);
+ return 0;
+}
+
+// 网关自动程序
+static void *GatewayDaemonTask(void *param)
+{
+ struct Adapter *gateway_adapter = (struct Adapter *)param;
+ if (gateway_adapter == NULL) // 判断参数合法性
+ {
+ return NULL;
+ }
+
+ struct GatewayParam *gateway_param = (struct GatewayParam *)gateway_adapter->adapter_param;
+ if (gateway_param->gateway_state != GATEWAY_WORKING)
+ {
+ if (0 != AdapterDeviceOpen(gateway_adapter)) // 开启Lora模块以接收消息
+ {
+ return NULL;
+ }
+ gateway_param->gateway_state = GATEWAY_WORKING;
+ }
+
+ PrivMutexObtain(&gateway_param->gateway_mutex); // 获取Lora控制权
+
+ while (1) // 内部业务大循环
+ {
+ if (0 == RecvFrame(gateway_adapter, &frame_recv_buffer) && 0 == LoraGatewayFrameFilter(gateway_param, &frame_recv_buffer)) // 是否接收成功且是发给自己的
+ {
+ gateway_handlers[frame_recv_buffer.frame_type](gateway_adapter, &frame_recv_buffer); // 根据消息类型,调用指定处理函数
+ }
+ else
+ {
+ printf("GatewayDaemonTask: Recv No Frame\n");
+ }
+ }
+
+ PrivMutexAbandon(&gateway_param->gateway_mutex); // 释放Lora
+
+ printf("GatewayDaemonTask: Exit!\n");
+ return NULL;
+}
+
+/**************************test_funcations*********************************/
+#ifdef AS_LORA_GATEWAY_ROLE
+
+void TestLoraGateway(void)
+{
+ struct Adapter *gateway_adapter = (struct Adapter *)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
+
+ UtaskType gateway_task;
+ gateway_task.prio = 24;
+ gateway_task.stack_size = 2048;
+ gateway_task.func_param = gateway_adapter;
+ gateway_task.func_entry = GatewayDaemonTask;
+ strncpy(gateway_task.name, "lora_gateway_task", strlen("lora_gateway_task"));
+
+ int32_t gateway_task_id = UserTaskCreate(gateway_task);
+
+ if (gateway_task_id > 0)
+ {
+ printf("TestLoraGateway: Create Gateway Task Success\n");
+ if (0 == UserTaskStartup(gateway_task_id))
+ {
+ printf("TestLoraGateway: Start Gateway Task Success\n");
+ }
+ else
+ {
+ printf("TestLoraGateway: Start Gateway Task Failed\n");
+ }
+ }
+ else
+ {
+ printf("TestLoraGateway: Create Gateway Task Failed\n");
+ }
+}
+PRIV_SHELL_CMD_FUNCTION(TestLoraGateway, TestLoraGateway No Param, PRIV_SHELL_CMD_MAIN_ATTR);
+
+#else
+void TestLoraConnectState(int user_state)
+{
+ enum ClientState state;
+ if (user_state == 0)
+ {
+ state = CLIENT_DISCONNECT;
+ printf("TestLoraConnectState: Config Lora Disconnect\n");
+ }
+ else if (user_state == 1)
+ {
+ state = CLIENT_CONNECT;
+ printf("TestLoraConnectState: Config Lora Connect\n");
+ }
+ else
+ {
+ printf("TestLoraConnectState: Not Suport 0-CLIENT_DISCONNECT 1-CLIENT_CONNECT\n");
+ }
+
+ struct Adapter *client_adapter = (struct Adapter *)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
+ if (0 == AdapterDeviceOpen(client_adapter))
+ {
+ if (0 == LoraClientConnectState(client_adapter, state))
+ {
+ printf("TestLoraConnectState: Config Lora Connect State Success\n");
+ }
+ else
+ {
+ printf("TestLoraConnectState: Config Lora Connect State Failed\n");
+ }
+ }
+ else
+ {
+ printf("TestLoraConnectState: Lora Open Failed\n");
+ }
+}
+PRIV_SHELL_CMD_FUNCTION(TestLoraConnectState, Only Suport 0-CLIENT_DISCONNECT 1-CLIENT_CONNECT, PRIV_SHELL_CMD_FUNC_ATTR);
+
+void TestLoraSendData(char* data)
+{
+ struct Adapter *client_adapter = (struct Adapter *)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
+ if (0 == AdapterDeviceOpen(client_adapter))
+ {
+ if (0 == LoraClientSendData(client_adapter, data,strlen(data)))
+ {
+ printf("TestLoraSendData: Send Data Success\n");
+ }
+ else
+ {
+ printf("TestLoraSendData: Send Data Failed\n");
+ }
+ }
+ else
+ {
+ printf("TestLoraSendData: Lora Open Failed\n");
+ }
+}
+PRIV_SHELL_CMD_FUNCTION(TestLoraSendData, char* data param, PRIV_SHELL_CMD_FUNC_ATTR);
+
+void TestLoraClient(void)
+{
+ struct Adapter *client_adapter = (struct Adapter *)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
+ if (0 == AdapterDeviceOpen(client_adapter))
+ {
+ printf("TestLoraClient: Open Lora Success!\n");
+ if (0 == LoraClientConnectState(client_adapter, CLIENT_CONNECT))
+ {
+ printf("TestLoraClient: Client Join Net Success!\n");
+ if (0 == LoraClientSendData(client_adapter, "Hello,Gateway!", strlen("Hello,Gateway!")))
+ {
+ printf("TestLoraClient: Client Send Data Success!\n");
+ if (0 == LoraClientConnectState(client_adapter, CLIENT_DISCONNECT))
+ {
+ printf("TestLoraClient: Client Quit Net Success!\n");
+ if (0 == LoraClientConnectState(client_adapter, CLIENT_CONNECT))
+ {
+ printf("TestLoraClient: Client Join Net Success!\n");
+ }
+ else
+ {
+ printf("TestLoraClient: Client Join Net Failed!\n");
+ }
+ }
+ else
+ {
+ printf("TestLoraClient: Client Quit Net Failed!\n");
+ }
+ }
+ else
+ {
+ printf("TestLoraClient: Client Send Data Fail!\n");
+ }
+ }
+ else
+ {
+ printf("TestLoraClient: Client Join Net Fail!\n");
+ }
+ }
+ else
+ {
+ printf("TestLoraClient: Open Lora Failed!\n");
+ }
+}
+PRIV_SHELL_CMD_FUNCTION(TestLoraClient, TestLoraClient No Param, PRIV_SHELL_CMD_MAIN_ATTR);
+
+#endif
+/*******************LORA ADAPTER FUNCTION********************/
+static int UsrAdapterLoraRegister(struct Adapter *adapter)
+{
+ int ret = 0;
+ struct GatewayParam *gateway_param;
+ struct ClientParam *client_param;
+ strncpy(adapter->name, ADAPTER_LORA_NAME, NAME_NUM_MAX);
+ adapter->net_protocol = PRIVATE_PROTOCOL;
+#ifdef AS_LORA_GATEWAY_ROLE
+ gateway_param = PrivMalloc(sizeof(struct GatewayParam));
+ if (!gateway_param)
+ {
+ PrivFree(gateway_param);
+ return -1;
+ }
+ memset(gateway_param, 0, sizeof(struct GatewayParam));
+ gateway_param->gateway_id = DEAFULT_GATEWAY_ID;
+ gateway_param->panid = DEAFULT_PANID;
+ gateway_param->gateway_state = GATEWAY_ORIGINAL;
+ PrivMutexCreate(&gateway_param->gateway_mutex, 0);
+ adapter->net_role = GATEWAY;
+ adapter->net_role_id = DEAFULT_GATEWAY_ID;
+ adapter->adapter_param = (void *)gateway_param;
+#else // AS_LORA_CLIENT_ROLE
+ client_param = PrivMalloc(sizeof(struct ClientParam));
+ if (!client_param)
+ {
+ PrivFree(client_param);
+ return -1;
+ }
+ memset(client_param, 0, sizeof(struct ClientParam));
+ client_param->client_id = DEAFULT_CLIENT_ID;
+ client_param->panid = DEAFULT_PANID;
+ client_param->gateway_id = 0;
+ client_param->client_state = CLIENT_DISCONNECT;
+ PrivMutexCreate(&client_param->client_mutex, 0);
+ adapter->net_role = CLIENT;
+ adapter->net_role_id = DEAFULT_CLIENT_ID;
+ adapter->adapter_param = (void *)client_param;
+#endif
+ adapter->adapter_status = UNREGISTERED;
+ ret = AdapterDeviceRegister(adapter);
+ if (ret < 0)
+ {
+ printf("Adapter lora register error\n");
+ if (gateway_param)
+ PrivFree(gateway_param);
+ if (client_param)
+ PrivFree(client_param);
+ return -1;
+ }
+ return ret;
+}
+
+int UsrAdapterLoraInit(void)
+{
+ int ret = 0;
+ struct Adapter *adapter = PrivMalloc(sizeof(struct Adapter));
+ if (!adapter)
+ {
+ PrivFree(adapter);
+ return -1;
+ }
+ memset(adapter, 0, sizeof(struct Adapter));
+ ret = UsrAdapterLoraRegister(adapter);
+ if (ret < 0)
+ {
+ printf("AdapterLoraInit register lora adapter error\n");
+ PrivFree(adapter);
+ return -1;
+ }
+ AdapterProductInfoType product_info = E220Attach(adapter);
+ if (!product_info)
+ {
+ printf("AdapterLoraInit e220 attach error\n");
+ PrivFree(adapter);
+ return -1;
+ }
+ adapter->product_info_flag = 1;
+ adapter->info = product_info;
+ adapter->done = product_info->model_done;
+ PrivSemaphoreCreate(&adapter->sem, 0, 0);
+ PrivMutexCreate(&adapter->lock, 0);
+ return ret;
+}
diff --git a/APP_Framework/Applications/app_test/test_lora_p2p/test_lora_p2p.h b/APP_Framework/Applications/app_test/test_lora_p2p/test_lora_p2p.h
new file mode 100644
index 000000000..7e4d690aa
--- /dev/null
+++ b/APP_Framework/Applications/app_test/test_lora_p2p/test_lora_p2p.h
@@ -0,0 +1,157 @@
+/*
+* Copyright (c) 2023 AIIT XUOS Lab
+* XiUOS is licensed under Mulan PSL v2.
+* You can use this software according to the terms and conditions of the Mulan PSL v2.
+* You may obtain a copy of Mulan PSL v2 at:
+* http://license.coscl.org.cn/MulanPSL2
+* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+* See the Mulan PSL v2 for more details.
+*/
+
+/**
+* @file: test_lora_p2p.h
+* @brief: a head file of lora structure
+* @version: 1.0
+* @author: Chu yunfei
+* @date: 2023/8/30
+*/
+
+#include
+#include
+
+#define LORA_FRAME_MAX_LENGTH 128
+#define LORA_FRAME_USER_MAX_LENGTH LORA_FRAME_MAX_LENGTH - 11
+#define LORA_FRAME_BEGIN_MARK_1 0XFF
+#define LORA_FRAME_BEGIN_MARK_2 0XAA
+#define LORA_FRAME_END_MARK_1 0XFF
+#define LORA_FRAME_END_MARK_2 0X00
+#define LORA_FRAME_MARK_LENGTH 2
+#define LORA_FRAME_NECK_LENGTH 5
+#define LORA_FRAME_CRC_LENGTH 2
+#define LORA_FRAME_SEND_INTERVAL 500
+
+#define GATEWAY_MAX_CLIENT_NUM 20
+
+#define DEFAULT_ID_MAX 125
+#define DEFAULT_ID_MIN 1
+#define DEAFULT_PANID 0XA
+#define DEAFULT_CLIENT_ID 0XB
+#define DEAFULT_GATEWAY_ID 0XC
+
+extern AdapterProductInfoType E220Attach(struct Adapter *adapter);
+
+// Lora工作模式枚举
+enum LoraMode
+{
+ LORA_SLEEP = 0, // 切换至休眠模式
+ LORA_WORK = 1 // 切换至工作模式
+};
+
+// 客户端状态
+enum ClientState
+{
+ CLIENT_DISCONNECT = 0, // 开启但断网
+ CLIENT_CONNECT, // 开启且联网
+ CLIENT_BROKEN, // 硬件损坏
+ CLIENT_CLOSED // 硬件关闭
+};
+
+// 客户端参数
+struct ClientParam
+{
+ uint8_t client_id;
+ uint8_t panid;
+ uint8_t gateway_id;
+ enum ClientState client_state;
+ pthread_mutex_t client_mutex; // 互斥量
+};
+
+// 网关状态
+enum GatewayState
+{
+ GATEWAY_ORIGINAL= 0, // 关闭且未开始工作
+ GATEWAY_WORKING, // 开启且已经开始工作
+ GATEWAY_BROKEN // 模块损坏
+};
+
+// 网关参数
+struct GatewayParam
+{
+ uint8_t gateway_id;
+ uint8_t panid;
+ uint8_t client_infos[GATEWAY_MAX_CLIENT_NUM];
+ uint8_t client_num;
+ enum GatewayState gateway_state;
+ pthread_mutex_t gateway_mutex; // 互斥量
+};
+
+// 消息类型
+enum FrameType
+{
+ /*C ---> G*/
+ CG_NET_JOIN = 0, // 入网请求
+ CG_NET_QUIT, // 退网请求
+ CG_DATA_SEND, // 数据传输请求
+ /*G ---> C*/
+ GC_REPLY_EXPECTED, // 上行请求执行成功
+ GC_REPLY_UNEXPECTED, // 上行请求执行失败
+};
+// 消息数据帧格式
+struct DataFrameFormat
+{
+ uint8_t begin_mark_1; // 0XFF
+ uint8_t begin_mark_2; // 0XAA
+ uint8_t client_id; // 0 - 127
+ uint8_t panid; // 0 - 127
+ uint8_t gateway_id; // 0 - 127
+ uint8_t frame_type; // 0 - 127
+ uint8_t attach_data; // 0 - 127
+ uint8_t* user_data; // 在有数据携带时才会发送该指针所指缓冲区数据
+ uint8_t crc_hi; // 这个字节没有0XFF
+ uint8_t crc_lo; // 这个字节会出现 0XFF,但是他的下一个字节不可能是00,必然是0XFF
+ uint8_t end_mark_1; // 0XFF
+ uint8_t end_mark_2; // 0X00
+};
+/******************************client_operate*********************************/
+/**
+ * @description: 将客户端网络状态切换为联网状态或者离线状态
+ * @param adapter - 需要是一个已经打开的设备
+ * @param aim_state - 需要转换的状态: CLIENT_CONNECT OR CLIENT_DISCONNECT
+ * @return success: 0, failure: -1
+ */
+static uint8_t LoraClientConnectState(struct Adapter *adapter, enum ClientState aim_state);
+
+/**
+ * @description: 在联网状态下向网关发送数据
+ * @param adapter - 需要是一个已经打开的设备
+ * @param data_buffer - 数据缓冲区地址
+ * @param data_length - 数据长度
+ * @return success: 0, failure: -1
+ */
+static uint8_t LoraClientSendData(struct Adapter *adapter, uint8_t *data_buffer, uint8_t data_length);
+
+/*****************************gateway_handlers*********************************/
+// 网关处理客户端入网请求
+static uint8_t GatewayJoinNetHandler(struct Adapter* adapter,struct DataFrameFormat* frame);
+// 网关处理客户端退网请求
+static uint8_t GatewayQuitNetHandler(struct Adapter* adapter,struct DataFrameFormat* frame);
+// 网关处理客户端的数据传输请求
+static uint8_t GatewayDataSendHandler(struct Adapter* adapter,struct DataFrameFormat* frame);
+// 网关自动化处理程序任务,需要启动
+static void *GatewayDaemonTask(void *param);
+
+// 网关处理程序与消息类型的对照表
+static uint8_t (*gateway_handlers[])(struct Adapter*,struct DataFrameFormat*) =
+{
+ [CG_NET_JOIN] = GatewayJoinNetHandler,
+ [CG_NET_QUIT] = GatewayQuitNetHandler,
+ [CG_DATA_SEND] = GatewayDataSendHandler
+};
+
+/************************lora adapter function*********************************/
+// 自定义注册函数
+static int UserAdapterLoraRegister(struct Adapter *adapter);
+// 自定义初始化函数
+int UserAdapterLoraInit(void);
\ No newline at end of file