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..02fc7b3f9
--- /dev/null
+++ b/APP_Framework/Applications/app_test/test_lora_net_final/README.md
@@ -0,0 +1,179 @@
+# 基于初赛二级赛题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