bleSDK_expansion_board/projects/blezongkong/src/app_modbus.c

550 lines
16 KiB
C
Raw Normal View History

#include "b6x.h"
#include "drvs.h"
#include "dbg.h"
#include "sftmr.h"
#include "app_modbus.h"
#include "CRCxx.h"
#include "app_ota.h"
#include "sys_config.h"
#define ModbusCRC16_EN 1
#define DEBUG_MODBUS 1
#if DEBUG_MODBUS
#define DEBUG(fmt, args...) debug("[modbus]" fmt, ##args)
#else
#define DEBUG(fmt, args...)
#endif
#define MODBUS_MAX_LEN 64
static uint8_t MODBUS_ReceCount =0;
static uint8_t MODBUS_Rece_BUF[MODBUS_MAX_LEN];
static uint8_t MODBUS_Sent_BUF[MODBUS_MAX_LEN];
// 需掉电不丢失数据12*2字节//40027-40030//40514-40520
uint16_t MODBUS_FLASH_DAT[12] ={
[0]=1,//MODBUS从机地址
[1]=1,// 出厂模式状态 //写入 1设备将重置进入出厂模式
[2]=100,// 固件版本
[3]=1,// 硬件版本
[4]=30,//30*100ms // 代码过期时间
[5]=30,//30*100ms// 输出继电器的关闭时间
[6]=100,//100*100ms// Led 激活时间
[7]=10,//10*10ms// 蜂鸣器激活时间
[8]=0x001f,// Led 键盘颜色//RGB565 格式
[9]=0xf800,// Led Mifare 读卡颜色//RGB565 格式
[10]=0x07E0,// Led 状态灯0颜色//RGB565 格式
[11]=0x07ff,// Led 状态灯1颜色//RGB565 格式
};
bool app_modbus_CheckData(uint8_t *dat , uint8_t len);
//发送数据并计算CRC
void app_modbus_SendData(uint8_t *dat ,uint8_t len){
if(0 == len){
return;
}
uint16_t CRC16=crc16_modbus(dat ,len);
dat[len++] =CRC16 & 0xff;// CRC低字节在前
dat[len++] =CRC16 >> 8;
uart_send(UART1_PORT ,len ,dat);
while(len){//清空发送数据缓存
dat[--len] =0;
}
}
// 01 功能码
void FunctionalCode_01(uint16_t reg_addr){//ID寄存器地址//返回7字节
uint8_t len_count=0;
// DEBUG("FuncCode_01:0x%X\n",reg_addr);
MODBUS_Sent_BUF[len_count++] =MODBUS_ADDR;
MODBUS_Sent_BUF[len_count++] =0x01;
switch(reg_addr){
case 0x0005:
break;
default:
len_count =0;
break;
}
}
// 03 功能码 # 读 - 保持寄存器
// 06 功能码 # 写 - 单个寄存器
void FunctionalCode_03_06(uint8_t CMDCode, uint16_t reg_addr , uint16_t reg_val_num){//寄存器地址//返回8字节或15字节
uint8_t len_count=0;
// DEBUG("FuncCode_03:0x%X\n",reg_addr);
MODBUS_Sent_BUF[len_count++] =MODBUS_ADDR;
MODBUS_Sent_BUF[len_count++] =CMDCode;
if(CMDCode == 0x03){//寄存器个数计数
MODBUS_Sent_BUF[2] =0;
len_count++;
}else if(CMDCode == 0x06){
MODBUS_Sent_BUF[len_count++] =(reg_addr >> 8) & 0xff;
MODBUS_Sent_BUF[len_count++] =reg_addr & 0xff;
}
switch(reg_addr){
case 0x0001: // 设备的 Modbus地址
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =0x00;
MODBUS_Sent_BUF[len_count++] =MODBUS_ADDR & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
MODBUS_ADDR =reg_val_num & 0xff;
MODBUS_Sent_BUF[len_count++] =MODBUS_ADDR >> 8;
MODBUS_Sent_BUF[len_count++] =MODBUS_ADDR & 0xff;
break;
}
case 0x0002: // 设备的软件版本号
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =sys_conf.VERSION >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.VERSION & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
sys_conf.VERSION =reg_val_num;
MODBUS_Sent_BUF[len_count++] =sys_conf.VERSION >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.VERSION & 0xff;
break;
}
case 0x0003: // 系统自检(只读)
if(CMDCode == 0x03){
uint16_t sys_sta=0;
MODBUS_Sent_BUF[len_count++] =sys_sta >> 8;
MODBUS_Sent_BUF[len_count++] =sys_sta & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
// sys_conf.VERSION =reg_val_num;
// MODBUS_Sent_BUF[len_count++] =sys_conf.VERSION >> 8;
// MODBUS_Sent_BUF[len_count++] =sys_conf.VERSION & 0xff;
break;
}
{ // 0x0101-0x0002
case 0x0101: // // 写系统配置
if(CMDCode == 0x03){ // # 读 - 保持寄存器
break;
}else if(CMDCode == 0x06){ // # 写 - 单个寄存器
write_cfg(&sys_conf); //保存写入配置
break;
}
case 0x0102: // 管理员模式油门极限寄存器(Unit:%)
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =sys_conf.Manager_sLim >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Manager_sLim & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
sys_conf.Manager_sLim =reg_val_num > 100 ? 100 : reg_val_num;
MODBUS_Sent_BUF[len_count++] =sys_conf.Manager_sLim >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Manager_sLim & 0xff;
break;
}
case 0x0103: // 游客模式油门极限寄存器(Unit:%)
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =sys_conf.Tourist_sLim >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Tourist_sLim & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
sys_conf.Tourist_sLim =reg_val_num > 100 ? 100 : reg_val_num;
MODBUS_Sent_BUF[len_count++] =sys_conf.Tourist_sLim >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Tourist_sLim & 0xff;
break;
}
case 0x0104: // 减速油门极限寄存器(Unit:%)(自动减速时油门极限)
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_sLim >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_sLim & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
sys_conf.Speed_Cut_sLim =reg_val_num > 100 ? 100 : reg_val_num;
MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_sLim >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_sLim & 0xff;
break;
}
case 0x0105: // 刹车距离寄存器(前进)(Unit:mm)
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
sys_conf.Brake_DLimit =reg_val_num>4500 ? 4500 : reg_val_num;
MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit & 0xff;
break;
}
case 0x0106: // 减速距离寄存器(Unit:mm)
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
sys_conf.Speed_Cut_DLimit =reg_val_num>4500 ? 4500 : reg_val_num;
MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit & 0xff;
break;
}
case 0x0107: // 刹车距离极限寄存器(后退)(Unit:mm)
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit_B >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit_B & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
sys_conf.Brake_DLimit_B =reg_val_num>4500 ? 4500 : reg_val_num;
MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit_B >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit_B & 0xff;
break;
}
case 0x0108: // 减速距离极限寄存器(Unit:mm)
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit_B >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit_B & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
sys_conf.Speed_Cut_DLimit_B =reg_val_num>4500 ? 4500 : reg_val_num;
MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit_B >> 8;
MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit_B & 0xff;
break;
}
}
{ // 0x0109-0x010D
case 0x0201: //PAD模式寄存器
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =0;
MODBUS_Sent_BUF[len_count++] =sys_sta.Pmode & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
uint8_t Pmode_Timeout =((reg_val_num >> 8) & 0xff);
if(0 == Pmode_Timeout){
Time_Event_Cancel_DelayOff(Pmode_Timeout_Event);
}else{
Time_Event_DelayOff(Pmode_Timeout_Event ,1000 * Pmode_Timeout ,NULL);
}
sys_sta.Pmode =reg_val_num & 0x03;
MODBUS_Sent_BUF[len_count++] =reg_val_num >> 8;
MODBUS_Sent_BUF[len_count++] =sys_sta.Pmode & 0xff;
break;
}
case 0x0202: //系统模式寄存器(只读)
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =0;
MODBUS_Sent_BUF[len_count++] =sys_sta.Smode & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
// sys_sta.Smode =reg_val_num & 0xff;
// MODBUS_Sent_BUF[len_count++] =sys_sta.Smode >> 8;
// MODBUS_Sent_BUF[len_count++] =sys_sta.Smode & 0xff;
break;
}
case 0x0203: //输入输出状态寄存器
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =sys_sta.IO_STA >> 8;
MODBUS_Sent_BUF[len_count++] =sys_sta.IO_STA & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){// 输入输出状态寄存器可写
// sys_sta.I_STA =reg_val_num & 0xff;//输入寄存器不可写
sys_sta.IO_STA =reg_val_num & 0xff;
MODBUS_Sent_BUF[len_count++] =sys_sta.IO_STA >> 8;
MODBUS_Sent_BUF[len_count++] =sys_sta.IO_STA & 0xff;
break;
}
case 0x0204: //输入状态寄存器
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =sys_sta.I_STA >> 8;
MODBUS_Sent_BUF[len_count++] =sys_sta.I_STA & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
// sys_sta.I_STA =reg_val_num & 0xff;//输入寄存器不可写
MODBUS_Sent_BUF[len_count++] =sys_sta.I_STA >> 8;
MODBUS_Sent_BUF[len_count++] =sys_sta.I_STA & 0xff;
break;
}
case 0x0205: //0 关闭12V输出//1 开启12V输出
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =sys_sta.O_12V >> 8;
MODBUS_Sent_BUF[len_count++] =sys_sta.O_12V & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
sys_sta.O_12V =reg_val_num ? 1 : 0;
MODBUS_Sent_BUF[len_count++] =sys_sta.O_12V >> 8;
MODBUS_Sent_BUF[len_count++] =sys_sta.O_12V & 0xff;
break;
}
case 0x0206: //0 关闭游客雷达//1 开启游客雷达
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =sys_sta.P_Radar_EN >> 8;
MODBUS_Sent_BUF[len_count++] =sys_sta.P_Radar_EN & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
sys_sta.P_Radar_EN =reg_val_num ? 1 : 0;
MODBUS_Sent_BUF[len_count++] =sys_sta.P_Radar_EN >> 8;
MODBUS_Sent_BUF[len_count++] =sys_sta.P_Radar_EN & 0xff;
break;
}
}
{ // 0x0201-0x0203
case 0x0301: // 电池状态
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_STA >> 8;
MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_STA & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
break;
}
case 0x0302: // 电池电压
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_Voltage >> 8;
MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_Voltage & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
break;
}
case 0x0303: // 电池电量
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_Percent >> 8;
MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_Percent & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
break;
}
case 0x0304: // 剩余充电时间
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_Remain_Time >> 8;
MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_Remain_Time & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
break;
}
case 0x0305: // 雷达距离信息
if(CMDCode == 0x03){
MODBUS_Sent_BUF[len_count++] =radar_data.distance >> 8;
MODBUS_Sent_BUF[len_count++] =radar_data.distance & 0xff;
MODBUS_Sent_BUF[2] +=2;
if(0 == --reg_val_num){
break;
}
}else if(CMDCode == 0x06){
break;
}
}
default:
len_count =0;
break;
}
if(len_count == 0){
return;
}
app_modbus_SendData(MODBUS_Sent_BUF ,len_count);
}
bool app_modbus_CheckData(uint8_t *dat , uint8_t len){//检查数据
uint16_t CRC16;
// DEBUG("len:%d\n",len);
if(len > 8){
len = 8;
}
if(dat[0] ==MODBUS_ADDR || dat[0] == 0xff){//验证从机地址
CRC16 =crc16_modbus(dat ,len-2);//计算CRC
DEBUG("CRC16:0x%X\n",CRC16);
#if !ModbusCRC16_EN
CRC16 =((uint16_t)(dat[len-1])<<8) + dat[len-2];
#endif
if(CRC16 ==((uint16_t)(dat[len-1])<<8) + dat[len-2]){//CRC低字节在前
switch(dat[1]){//功能码
case 0x01:// 功能码 01
FunctionalCode_01(((uint16_t)dat[2]<<8) + dat[3]);
break;
case 0x03:// 功能码03 # 读 - 保持寄存器
FunctionalCode_03_06(0x03,((uint16_t)dat[2]<<8) + dat[3] ,((uint16_t)dat[4]<<8) + dat[5]);
// FunctionalCode_03(((uint16_t)dat[2]<<8) + dat[3] ,((uint16_t)dat[4]<<8) + dat[5]);
break;
case 0x06:// 功能码06 # 写 - 单个寄存器
FunctionalCode_03_06(0x06,((uint16_t)dat[2]<<8) + dat[3] ,((uint16_t)dat[4]<<8) + dat[5]);
// FunctionalCode_06(((uint16_t)dat[2]<<8) + dat[3] ,((uint16_t)dat[4]<<8) + dat[5]);
break;
default:
break;
}
return true;
}
}
return false;
}
#if !defined(Modbus_RBUF_SIZE)
#define Modbus_RBUF_SIZE 0x100
#endif
#define Modbus_FIFO_RXTL 8
#undef RBUF_SIZE
#define RBUF_SIZE Modbus_RBUF_SIZE
#include "rbuf.h"
/// RingBuffer for modbus1
static rbuf_t ModbusRbRx;
void app_modbus_Rb_Reset(void){
rbuf_init(&ModbusRbRx);
}
uint16_t app_modbus_Rb_Len(void){
return rbuf_len(&ModbusRbRx);
}
uint16_t app_modbus_Rb_Read(uint8_t *buff, uint16_t max){
return rbuf_gets(&ModbusRbRx, buff, max);
}
#define Rx_timeout _MS(20) // 接收超时时间
static tmr_tk_t Rx_timeout_id=0;
static tmr_tk_t Rx_timeout_handler(tmr_id_t id){
(void)(id);
MODBUS_ReceCount = app_modbus_Rb_Read(&MODBUS_Rece_BUF[0], MODBUS_MAX_LEN);
DEBUG("RC:%d\n",MODBUS_ReceCount);
app_PAD_CheckData(MODBUS_Rece_BUF, MODBUS_ReceCount);//PAD数据解析
app_modbus_CheckData(MODBUS_Rece_BUF, MODBUS_ReceCount);//modbus数据解析
app_otas_rxd(MODBUS_ReceCount ,MODBUS_Rece_BUF);//otas数据解析
while(MODBUS_ReceCount){
MODBUS_Rece_BUF[--MODBUS_ReceCount] = 0;
}
return 0;
}
void app_modbus_Init(uint32_t baudrate, uint8_t io_tx, uint8_t io_rx){
uart_init(UART1_PORT, io_tx, io_rx);
uart_conf(UART1_PORT, BRR_BAUD(baudrate), LCR_BITS(8, 1, none));
// 使能FIFO 接收8字节时触发、使能超过20字节触发超时中断
uart_fctl(UART1_PORT, FCR_FIFOEN_BIT | FCR_RXTL_8BYTE,
20/*bits_rto*/, UART_IR_RXRD_BIT | UART_IR_RTO_BIT);
// empty buffer
rbuf_init(&ModbusRbRx);
DEBUG("MODBUS init success!\n");
NVIC_EnableIRQ(UART1_IRQn);
Rx_timeout_id =sftmr_start(10, Rx_timeout_handler);
}
void UART1_IRQHandler(void){
uint32_t state = UART1->IFM.Word; // UART1->RIF.Word;
if (state & 0x01){ //(BIT_RXRD)
UART1->IDR.RXRD = 1; // Disable RXRD Interrupt
for (uint8_t i = 0; i < Modbus_FIFO_RXTL; i++){
rbuf_putc(&ModbusRbRx, UART1->RBR);
}
sftmr_Refresh(Rx_timeout_id ,Rx_timeout);
UART1->ICR.RXRD = 1; // Clear RXRD Interrupt Flag
UART1->IER.RXRD = 1; // Enable RXRD Interrupt
}
if (state & 0x10){ //(BIT_RTO)
UART1->IDR.RTO = 1; // Disable RTO Interrupt
while (UART1->SR.RFNE){
rbuf_putc(&ModbusRbRx, UART1->RBR);
if(0 ==UART1->SR.RFNE){
sftmr_Refresh(Rx_timeout_id ,Rx_timeout);
}
}
UART1->ICR.RTO = 1; // Clear RTO Interrupt Flag
UART1->IER.RTO = 1; // Enable RTO Interrupt
}
}