bleSDK_expansion_board/projects/blezongkong/src/app_modbus.c

550 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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
}
}