2023_open_source_contest_preliminary_2st_issue1 from 西北工业大学_天仙永昌战队_楚云飞

it is OK
This commit is contained in:
IACU 2023-10-23 13:57:15 +08:00
commit c7bbf2935f
27 changed files with 3628 additions and 0 deletions

View File

@ -0,0 +1,187 @@
# 基于初赛二级赛题1实现多个LoRa节点和LoRa网关通信私有协议
## 1. 简介
基于 E220-400T22S Lora模块设计实现通信私有协议主要包含以下几个方面<br>
- 协议实现完全遵循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
![image](./images/0-1.png)
> 开启连接框架支持同时开启Lora Adapter支持
![image](./images/0-2.png)
> 选择E220模块
![image](./images/0-3.png)
> 开启测试函数
![image](./images/0-4.png)
> 测试单通道网关
- 修改MakeFilexiuos/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行修改为<br> extern int UsrAdapterLoraInit(void);
> 2. 文件xiuos/APP_Framework/Framework/framework_init.c 第170行的AdapterLoraInit修改为UsrAdapterLoraInit
### 2打开网关
![image](./images/1.png)
> 网关打开地址OXFFFF信道OXA空中速率2.4K
### 3客户端连接网关
![image](./images/2.png)
> 两边客户端同时发送入网请求,可以看见信道检测效果
### 4客户端发送数据
![image](./images/3.png)
> 客户端向网关发送数据
![image](./images/4.png)
> 两边客户端同时发送数据
使用自带的天线2.4K空中速率载荷64字节在无大型遮盖物的情况下传输距离近1500米

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@ -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,&register_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,&register_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,&register_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;
}

View File

@ -0,0 +1,125 @@
#include <transform.h>
#include <adapter.h>
#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个信道083
#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__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,303 @@
#include <transform.h>
#include <adapter.h>
#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);
/*网关操作*************************************************************************/

View File

@ -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

View File

@ -0,0 +1,28 @@
#include <transform.h>
#include <adapter.h>
// #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);

View File

@ -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)、获取使用权后将其配置为传输模式。<br>
> (2)、构建数据帧并设置好数据帧类型。<br>
> (3)、监听信道直到信道空闲。<br>
> (4)、发送数据帧(若是数据传输需要带上数据一起传输),若失败回到第三步。<br>
> (5)、接收数据帧并对数据帧进行数据过滤,若失败回到第三步。<br>
> (6)、解析数据帧并得到结果<br>
### 2、网关后台任务操作
> (1)、获取使用权后开启数据接收。<br>
> (2)、根据数据帧结构,监听信道,过滤掉杂乱的信号,在接收到一个完整的数据帧并完整性校验通过后返回继续第三步,否则循环执行第二步。<br>
> (3)、根据得到的数据帧类型将其交付给对应的处理器处理,处理完毕后返回第二步。<br>
## 四、测试程序说明
在进行测试时,最好先启动网关并开启网关程序,当然后启动网关也一样。
### 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)` ;
![image](images/5-3-1.png)
2. `APP_Framework > Framework` 开启 `support connection framework (NEW)` ,然后进入其中,开启 `Using lora adapter device (NEW)` ,然后进入其中, 客户端将其配置如下图所示,网关将其配置为下下图所示;
![image](images/5-3-2-1.png)
![image](images/5-3-2-2.png)
3. 将客户端和网关分别编译、烧录到不同的板子并启动后用串口进行连接;
![image](images/5-3-3.png)
4. 启动网关程序;
![image](images/5-3-4.png)
5. 整体测试客户端;
![image](images/5-3-5.png)
6. 测试断网
![image](images/5-3-6.png)
7. 测试联网
![image](images/5-3-7.png)
8. 测试数据发送
![image](images/5-3-8.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

View File

@ -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;
}

View File

@ -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<adapter.h>
#include<transform.h>
#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);