614 lines
24 KiB
C
614 lines
24 KiB
C
#include "bsp_modbus.h"
|
||
#include "kit_time.h"
|
||
#include "kit_data.h"
|
||
//#include "kit_debug.h"
|
||
|
||
/********************************************************************************************************************************************************************************
|
||
1.Modbus数据结构
|
||
0x01 读线圈 设备地址/1B 功能码/1B 起始地址/2B 线圈数量/2B 设备地址/1B 功能码/1B 字节数/1B 线圈状态/NB
|
||
0x02 读离散量输入 设备地址/1B 功能码/1B 起始地址/2B 输入数量/2B 设备地址/1B 功能码/1B 字节数/1B 输入状态/NB
|
||
0x03 读保持寄存器 设备地址/1B 功能码/1B 起始地址/2B 寄存器数量/2B 设备地址/1B 功能码/1B 字节数/1B 寄存器值/2NB
|
||
0x04 读输入寄存器 设备地址/1B 功能码/1B 起始地址/2B 输入寄存器数量/2B 设备地址/1B 功能码/1B 字节数/1B 输入寄存器/2NB
|
||
0x05 写单个线圈 设备地址/1B 功能码/1B 输出地址/2B 输出值/2B 设备地址/1B 功能码/1B 输出地址/2B 输出值/2B
|
||
0x06 写单个寄存器 设备地址/1B 功能码/1B 寄存器地址/2B 寄存器值/2B 设备地址/1B 功能码/1B 寄存器地址/2B 寄存器值/2B
|
||
0x0F 写多个线圈 设备地址/1B 功能码/1B 起始地址/2B 输出数量/2B 字节数/1B 输出值/NB 设备地址/1B 功能码/1B 起始地址/2B 输出数量/2B
|
||
0x10 写多个寄存器 设备地址/1B 功能码/1B 起始地址/2B 寄存器数量/2B 字节数/1B 寄存器值/2NB 设备地址/1B 功能码/1B 起始地址/2B 寄存器数量/2B
|
||
|
||
2.Modbus TCP MBAP报文头
|
||
地址 功能码 数据 CRC校验
|
||
事务处理标识符 协议标识符 长度 单元标识符 功能码 数据
|
||
0001 0000 0006 01 04 00000005
|
||
0001 0000 000D 01 04 0A00000001000200030004
|
||
-----------------------------------------------------------------------------------
|
||
事务处理标识符 2字节 Modbus请求/响应事务处理的标识 客户机启动 复制响应
|
||
协议标识符 2字节 0=Modbus协议 客户机启动 复制响应
|
||
长度 2字节 长度之后的字节总数 客户机启动 服务器启动
|
||
单元标识符 1字节 串行链路或其它总线的从站识别 客户端启动 复制响应
|
||
|
||
3.写线圈
|
||
十六进制值0xFF00,请求线圈为 ON。十六进制值0x0000请求线圈为OFF。其它所有值均为非法的,并且对线圈不起作用。
|
||
|
||
********************************************************************************************************************************************************************************/
|
||
#define BRROCAST_ADDR (0u)
|
||
#define MB_DEV_ADDR_POS (0u)
|
||
#define MB_FUN_CODE_POS (1u)
|
||
#define MB_REG_ADDR_POS (2u)
|
||
#define MB_DATA_POS (2u)
|
||
#define MB_REG_NUM_POS (4u)
|
||
|
||
#define MB_MIN_LEN (3u)
|
||
//TCP比RTU多了事务处理标识符、协议标识符和长度,总共6B
|
||
#define MB_TCP_OFFSET (6u)
|
||
#define MB_TCP_DATA_LEN_POS (4u)
|
||
#define MB_TCP_DEV_ADDR_POS (6u)
|
||
|
||
|
||
ModbusCommData modbus_comm_data __attribute__((section (".CCM_RAM")));
|
||
const uint8_t modbus_offset_len[kModbusType_End] = {0, MB_TCP_OFFSET};
|
||
static void bsp_modbus_task_poll(uint32_t base_time, ModbusItem * const item, ModbusTask *cur_task, GateItem *gate);
|
||
|
||
void bsp_modbus_poll(ModbusItem * const item, bool is_enable_call)
|
||
{
|
||
uint8_t fun_code;
|
||
uint16_t tmp, pos, addr, reg_num;
|
||
uint32_t i, data, tick_diff;
|
||
bool cond[kModbusType_End];
|
||
GateItem *gate;
|
||
ModbusTask *cur_task = NULL;
|
||
BspMdExCode err = kBspMdEx_InvalidFunc;
|
||
|
||
if((item != NULL) && (item->ctrl_rx_int_call != NULL))
|
||
{
|
||
if(item->task_num > 0)
|
||
{
|
||
cur_task = &item->modbus_task[item->cur_task_idx];
|
||
}
|
||
//判断超时时关闭接收中断,防止刚判断完超时后,马上收到数据,导致数据丢失
|
||
item->ctrl_rx_int_call(item->comm_dev, false);
|
||
tick_diff = kit_time_get_interval_by_now(item->tick);
|
||
if(tick_diff >= 5)
|
||
{
|
||
pos = item->buf_pos;
|
||
item->buf_pos = 0;
|
||
item->tick = kit_time_get_tick();
|
||
item->ctrl_rx_int_call(item->comm_dev, true);
|
||
tmp = modbus_offset_len[item->type];
|
||
addr = item->buf[MB_DEV_ADDR_POS + tmp];
|
||
//当为主设备时接收任何addr设备数据,从设备时需要判断地址
|
||
if (((item->is_master == true) || ((item->is_master == false) && ((item->addr == addr) || (addr == BRROCAST_ADDR))))
|
||
&& (pos > MB_MIN_LEN))
|
||
{
|
||
if(addr < MODBUS_MAX_DEV)
|
||
{
|
||
item->time_out[addr] = 0;
|
||
}
|
||
//modbus RTU校验CRC
|
||
cond[kModbusType_RTU] = (kit_check_crc16(item->buf, pos) == 0);
|
||
cond[kModbusType_TCP] = (pos == (READ_BT_INT16U_BY_CONST_POS(item->buf, MB_TCP_DATA_LEN_POS) + 6));
|
||
if(cond[item->type] == true)
|
||
{
|
||
//做从机,起始地址直接从数据中获取
|
||
//做主机,主动发送数据时会记录起始地址,用于接收从设备数据时使用
|
||
addr = (item->is_master == true) ? addr = item->start_addr : READ_BT_INT16U_BY_CONST_POS(item->buf, MB_REG_ADDR_POS + tmp);
|
||
fun_code = item->buf[MB_FUN_CODE_POS + tmp];
|
||
if((item->fun_call_array[fun_code] != NULL) || (item->task_num != 0))
|
||
{
|
||
gate = item->gate;
|
||
reg_num = READ_BT_INT16U_BY_CONST_POS(item->buf, MB_REG_NUM_POS + tmp);
|
||
switch(fun_code)
|
||
{
|
||
case kModbusFun_0x01:
|
||
case kModbusFun_0x02:
|
||
case kModbusFun_0x03:
|
||
case kModbusFun_0x04:
|
||
//对于接收RTC数据长度 = 报文总长度-(地址 功能码 CRC校验),TCP数据长度 = 报文总长度-(MBAP报文头 功能码)
|
||
pos = (item->type == kModbusType_RTU)? (pos - 1 - 1 - 2 - 1) : (pos - 7 - 1);
|
||
if(item->task_num == 0)
|
||
{
|
||
//对于Master addr为请求起始地址 reg_num 无意义 buf为数据 pos为buf长度
|
||
//对于Slaver addr为请求起始地址 reg_num 线圈/寄存器数量 buf为要写入回复数据地址 pos无意义,更具reg_num填数据
|
||
//MB_DATA_POS + tmp + 1,+1为字节数
|
||
err = item->fun_call_array[fun_code](addr, reg_num, &item->buf[MB_DATA_POS + tmp + 1], &pos);
|
||
//数据长度
|
||
pos = (fun_code < kModbusFun_0x03) ? ((reg_num + 7) >> 3) : (reg_num << 1);
|
||
item->buf[MB_DATA_POS + tmp] = pos;
|
||
pos++; //增加字节数
|
||
}
|
||
//通过建模方式进行modbus通信
|
||
else if(cur_task != NULL)
|
||
{
|
||
cur_task->tick += 900;
|
||
//读读数据
|
||
if(cur_task->head->fun_code < 3)
|
||
{
|
||
tmp = (pos == 1) ? ((uint16_t)item->buf[MB_DATA_POS + tmp + 1] << 8) : READ_BT_INT16U_BY_CONST_POS(item->buf, MB_DATA_POS + tmp + 1);
|
||
item->gate->read_buf[cur_task->buf_addr] = tmp;
|
||
}
|
||
else if(cur_task->head->fun_code < 5)
|
||
{
|
||
item->gate->read_buf[cur_task->buf_addr] = tmp;
|
||
bsp_gate_push_read_data(item->gate, cur_task->buf_addr, &item->buf[MB_DATA_POS + tmp + 1], pos);
|
||
}
|
||
//读写数据
|
||
else
|
||
{
|
||
if(fun_code < kModbusFun_0x03)
|
||
{
|
||
//一个task最多限制32个线圈,每个线圈在写buf中占2字节
|
||
data = kit_bt_read_buf(&item->buf[MB_DATA_POS + tmp + 1], 0, pos);
|
||
for(i = 0; i < cur_task->head->reg_num; i++)
|
||
{
|
||
pos = (KIT_GET_BIT(data, i) != 0) << 8;
|
||
bsp_gate_push_write_data(gate, cur_task->buf_addr + i, (uint8_t *)&pos, 2);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
bsp_gate_push_write_data(gate, cur_task->buf_addr, &item->buf[MB_DATA_POS + tmp + 1], pos);
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case kModbusFun_0x05:
|
||
case kModbusFun_0x06:
|
||
if(item->task_num == 0)
|
||
{
|
||
//对于Master addr为请求起始地址 reg_num 输出值 buf无意义 pos 无意义
|
||
//对于Slaver addr为请求起始地址 reg_num 输出值 buf无意义 pos 无意义
|
||
err = item->fun_call_array[fun_code](addr, reg_num, &item->buf[MB_REG_NUM_POS + tmp], &pos);
|
||
pos = 4;//起始地址+输出数量
|
||
}
|
||
//通过建模方式进行modbus通信
|
||
else if(cur_task != NULL)
|
||
{
|
||
cur_task->tick += 900;
|
||
pos = modbus_offset_len[item->type] + 4;
|
||
data = READ_LT_INT16U_BY_CONST_POS(item->buf, pos);
|
||
if(item->gate_write_data_absolute_addr == addr)
|
||
{
|
||
if(fun_code == kModbusFun_0x05)
|
||
{
|
||
data = (data == 0xFF) ? 0x0100 : 0;
|
||
}
|
||
if(data == item->gate_write_data_value)
|
||
{
|
||
gate->write_buf[item->gate_write_data_addr] = data;
|
||
item->gate_write_data_absolute_addr = MODBUS_GATE_FREE_ADDR;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case kModbusFun_0x0F:
|
||
case kModbusFun_0x10:
|
||
//对于Master addr为请求起始地址 reg_num 线圈/寄存器数量 buf无意义 pos无意义
|
||
//对于Slaver addr为请求起始地址 reg_num 线圈/寄存器数量 buf寄存器值 pos为buf长度
|
||
tmp += 7; //buf 地址7为要写数据
|
||
err = item->fun_call_array[fun_code](addr, reg_num, &item->buf[tmp], &pos);
|
||
pos = 4;//起始地址+输出数量
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
err = kBspMdEx_InvalidFunc;
|
||
}
|
||
|
||
//做主机时不回复从机报文
|
||
if(item->is_master == false)
|
||
{
|
||
if(err == kBspMdEx_None)
|
||
{
|
||
bsp_modbus_pos_send(item, pos);
|
||
|
||
}
|
||
else
|
||
{
|
||
bsp_modbus_neg_send(item, err);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if(cur_task != NULL)
|
||
{
|
||
bsp_modbus_task_poll(tick_diff, item, cur_task, item->gate);
|
||
}
|
||
|
||
if((item->master_call != NULL) && (is_enable_call == true))
|
||
{
|
||
item->master_call(item, tick_diff);
|
||
}
|
||
|
||
for(i = 0; i < MODBUS_MAX_DEV; i++)
|
||
{
|
||
if(item->time_out[i] < 60000)
|
||
{
|
||
item->time_out[i] += tick_diff;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
item->ctrl_rx_int_call(item->comm_dev, true);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
uint16_t bsp_modbus_get_time_out(ModbusItem * const item, uint8_t addr)
|
||
{
|
||
uint16_t tmp = 65000;
|
||
if(addr < MODBUS_MAX_DEV)
|
||
{
|
||
tmp = item->time_out[addr];
|
||
}
|
||
return tmp;
|
||
}
|
||
|
||
static void bsp_modbus_task_poll(uint32_t base_time, ModbusItem * const item, ModbusTask *cur_task, GateItem *gate)
|
||
{
|
||
uint8_t fun_code;
|
||
uint16_t tmp, data;
|
||
int32_t addr;
|
||
uint32_t cur_idx;
|
||
ModbusHead *head;
|
||
|
||
cur_task->tick += base_time;
|
||
if(cur_task->tick >= cur_task->head->time_out + 1000)
|
||
{
|
||
cur_task->tick = 0;
|
||
if(item->task_cashe != 0xFF)
|
||
{
|
||
cur_idx = item->task_cashe;
|
||
item->task_cashe = 0xFF;
|
||
}
|
||
else
|
||
{
|
||
//查找下一个读指令,当轮询完一轮后首个即默认为读指令,故第一个task必须为读指令
|
||
cur_idx = item->cur_task_idx;
|
||
if(item->is_read_write_data == true)
|
||
{
|
||
if(++cur_idx >= item->task_num)
|
||
{
|
||
cur_idx = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
while(true)
|
||
{
|
||
if(++cur_idx >= item->task_num)
|
||
{
|
||
cur_idx = 0;
|
||
}
|
||
if(item->modbus_task[cur_idx].head->fun_code < 0x05)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
addr = item->gate_write_data_absolute_addr;
|
||
if(addr != MODBUS_GATE_FREE_ADDR)
|
||
{
|
||
//每一次请求写数据gate 重试次数+1
|
||
if(item->gate_write_try_cnt++ >= 3)
|
||
{
|
||
item->gate_write_data_absolute_addr = MODBUS_GATE_FREE_ADDR;
|
||
}
|
||
else
|
||
{
|
||
head = item->gate_write_data_head;
|
||
tmp = item->gate_write_data_value;
|
||
if(head->fun_code == 0x05)
|
||
{
|
||
data = (tmp != 0)? 0xFF00 : 0;
|
||
}
|
||
else
|
||
{
|
||
data = tmp >> 8;
|
||
data |= tmp << 8;
|
||
}
|
||
bsp_modbus_master_single_write(item, head->slave_addr, head->fun_code, addr, data);
|
||
item->task_cashe = cur_idx;
|
||
return;
|
||
}
|
||
}
|
||
|
||
item->cur_task_idx = cur_idx;
|
||
head = item->modbus_task[cur_idx].head;
|
||
|
||
fun_code = head->fun_code;
|
||
if(fun_code > 4)
|
||
{
|
||
fun_code = head->time_out;
|
||
}
|
||
//head->time_out 为0时为主动上送
|
||
if(head->time_out != 0)
|
||
{
|
||
bsp_modbus_master_read(item, head->slave_addr, fun_code, head->reg_addr, head->reg_num);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void bsp_modbus_pos_send(ModbusItem * const item, uint16_t len)
|
||
{
|
||
uint16_t mb_crc;
|
||
uint32_t cnt;
|
||
|
||
if((item != NULL) && (item->send_call != NULL)
|
||
&&(item->buf[MB_DEV_ADDR_POS + modbus_offset_len[item->type]] != BRROCAST_ADDR))
|
||
{
|
||
cnt = len + 1 + 1;//addr and code
|
||
if(item->type == kModbusType_RTU)
|
||
{
|
||
mb_crc = kit_check_crc16(item->buf, cnt);
|
||
WRITE_LT_INT16U(item->buf, cnt, mb_crc);
|
||
}
|
||
else
|
||
{
|
||
WRITE_BT_INT16U_BY_CONST_POS(item->buf, MB_TCP_DATA_LEN_POS, cnt)
|
||
}
|
||
item->send_call(item->comm_dev, item->buf, cnt + modbus_offset_len[item->type]);
|
||
}
|
||
}
|
||
|
||
void bsp_modbus_neg_send(ModbusItem * const item, BspMdExCode ex_code)
|
||
{
|
||
uint16_t mb_crc;
|
||
uint32_t cnt;
|
||
if((item != NULL) && (item->send_call != NULL)
|
||
&&item->buf[MB_DEV_ADDR_POS + modbus_offset_len[item->type]] != BRROCAST_ADDR)
|
||
{
|
||
cnt = 3;
|
||
item->buf[1 + modbus_offset_len[item->type]] |= 0x80;
|
||
item->buf[2 + modbus_offset_len[item->type]] = ex_code;
|
||
|
||
if(item->type == kModbusType_RTU)
|
||
{
|
||
mb_crc = kit_check_crc16(item->buf, cnt);
|
||
WRITE_LT_INT16U(item->buf, cnt, mb_crc);
|
||
}
|
||
else
|
||
{
|
||
item->buf[5] = 3;
|
||
}
|
||
|
||
item->send_call(item->comm_dev, item->buf, cnt + modbus_offset_len[item->type]);
|
||
}
|
||
}
|
||
|
||
void bsp_modbus_push_data(ModbusItem * const item, uint8_t *buf, uint16_t len)
|
||
{
|
||
uint32_t i;
|
||
|
||
if((item != NULL) && (item->buf_pos + len < item->buf_size))
|
||
{
|
||
for (i = 0; i < len; i++)
|
||
{
|
||
item->buf[item->buf_pos++] = buf[i];
|
||
}
|
||
|
||
if(item->type == kModbusType_RTU)
|
||
{
|
||
item->tick = kit_time_get_tick();
|
||
}
|
||
else
|
||
{
|
||
item->tick = 0;
|
||
//tcp使用同步接口时,不用poll
|
||
//bsp_modbus_poll(item);
|
||
}
|
||
}
|
||
}
|
||
|
||
void bsp_modbus_set_slaver_addr(ModbusItem * const item, uint8_t addr)
|
||
{
|
||
if(item != NULL)
|
||
{
|
||
item->addr = addr;
|
||
}
|
||
}
|
||
|
||
uint16_t bsp_modbus_fill_mbap_head(ModbusItem * const item, uint8_t dev_addr, uint16_t len)
|
||
{
|
||
uint32_t cnt = 0;
|
||
if(item->type == kModbusType_TCP)
|
||
{
|
||
//事务元标识符:服务器从接收的请求中复制 客户端每次++
|
||
item->tcp_transaction++;
|
||
WRITE_BT_INT16U(item->buf, cnt, item->tcp_transaction);
|
||
//协议标识符:0=MODBUS 协议
|
||
WRITE_BT_INT16U(item->buf, cnt, 0);
|
||
//长度:单元标识符1B + 功能码1B + 数据4B
|
||
WRITE_BT_INT16U(item->buf, cnt, len);
|
||
}
|
||
//单元标识符:从设备地址 RTU TCP都需要填地址
|
||
WRITE_BT_INT8U(item->buf, cnt, dev_addr);
|
||
|
||
return cnt;
|
||
}
|
||
|
||
//start_addr 用于做主站时记录请求的地址 支持0x01 0x02 0x03 0x04
|
||
void bsp_modbus_master_read(ModbusItem * const item, uint8_t dev_addr, uint8_t fun_code, uint16_t start_addr, uint16_t reg_num)
|
||
{
|
||
uint16_t mb_crc;
|
||
uint32_t cnt;
|
||
|
||
if((item != NULL) && (item->send_call != NULL))
|
||
{
|
||
item->buf_pos = 0;
|
||
item->is_master = true;
|
||
item->start_addr = start_addr;
|
||
//6 = 单元标识符1Byte + 功能码1Byte + 起始地址2Byte + 寄存器数2Byte
|
||
cnt = bsp_modbus_fill_mbap_head(item, dev_addr, 6);
|
||
|
||
item->buf[cnt++] = fun_code;
|
||
WRITE_BT_INT16U(item->buf, cnt, start_addr);
|
||
WRITE_BT_INT16U(item->buf, cnt, reg_num);
|
||
if(item->type != kModbusType_TCP)
|
||
{
|
||
mb_crc = kit_check_crc16(item->buf, cnt);
|
||
WRITE_LT_INT16U(item->buf, cnt, mb_crc);
|
||
}
|
||
item->send_call(item->comm_dev, item->buf, cnt);
|
||
}
|
||
}
|
||
|
||
//做从站时主动发送数据 支持0x01 0x02 0x03 0x04
|
||
void bsp_modbus_slaver_send_read(ModbusItem * const item, uint8_t dev_addr, uint8_t fun_code, uint8_t *buf, uint16_t len)
|
||
{
|
||
uint16_t mb_crc;
|
||
uint32_t cnt;
|
||
|
||
if((item != NULL) && (item->send_call != NULL))
|
||
{
|
||
item->buf_pos = 0;
|
||
cnt = bsp_modbus_fill_mbap_head(item, dev_addr, 1 + 1 + 1 + len);
|
||
item->buf[cnt++] = fun_code;
|
||
|
||
WRITE_BT_INT8U(item->buf, cnt, len);
|
||
|
||
kit_copy_buf(&item->buf[cnt], buf, len);
|
||
cnt += len;
|
||
if(item->type != kModbusType_TCP)
|
||
{
|
||
mb_crc = kit_check_crc16(item->buf, cnt);
|
||
WRITE_LT_INT16U(item->buf, cnt, mb_crc);
|
||
}
|
||
item->send_call(item->comm_dev, item->buf, cnt);
|
||
}
|
||
}
|
||
|
||
//支持 0x05 0x06
|
||
void bsp_modbus_master_single_write(ModbusItem * const item, uint8_t dev_addr, uint8_t fun_code, uint16_t start_addr, uint16_t value)
|
||
{
|
||
bsp_modbus_master_read(item, dev_addr, fun_code, start_addr, value);
|
||
}
|
||
|
||
//支持 0x0F 0x10
|
||
void bsp_modbus_master_series_write(ModbusItem * const item, uint8_t dev_addr, uint8_t fun_code, uint16_t start_addr, uint16_t reg_num, uint8_t *buf)
|
||
{
|
||
uint16_t mb_crc, len;
|
||
uint32_t cnt = 0;
|
||
|
||
if((item != NULL) && (item->send_call != NULL))
|
||
{
|
||
item->buf_pos = 0;
|
||
item->is_master = true;
|
||
item->start_addr = start_addr;
|
||
|
||
//数据计算字节数
|
||
if(fun_code == 0x10)
|
||
{
|
||
len = reg_num << 1;
|
||
}
|
||
else
|
||
{
|
||
len = reg_num / 8;
|
||
len = ((reg_num % 8) == 0) ? len : (len + 1);
|
||
}
|
||
cnt = bsp_modbus_fill_mbap_head(item, dev_addr, 2 + 4 + 1 + len);
|
||
|
||
item->buf[cnt++] = fun_code;
|
||
WRITE_BT_INT16U(item->buf, cnt, start_addr);
|
||
WRITE_BT_INT16U(item->buf, cnt, reg_num);
|
||
|
||
WRITE_BT_INT8U(item->buf, cnt, len);
|
||
kit_copy_buf(&item->buf[cnt], buf, len);
|
||
cnt += len;
|
||
if(item->type != kModbusType_TCP)
|
||
{
|
||
mb_crc = kit_check_crc16(item->buf, cnt);
|
||
WRITE_LT_INT16U(item->buf, cnt, mb_crc);
|
||
}
|
||
item->send_call(item->comm_dev, item->buf, cnt);
|
||
}
|
||
}
|
||
|
||
void bsp_modbus_link_list(ModbusItem * const item)
|
||
{
|
||
ModbusItem ** cur_item = &modbus_comm_data.head_item;
|
||
while(*cur_item != NULL)
|
||
{
|
||
if(*cur_item == item)
|
||
{
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
cur_item = &(*cur_item)->next_item;
|
||
}
|
||
}
|
||
*cur_item = item;
|
||
}
|
||
|
||
void bsp_modbus_register_master_fun(ModbusItem * const item, MasterCall master_call)
|
||
{
|
||
if((item != NULL) && (master_call != NULL))
|
||
{
|
||
item->master_call = master_call;
|
||
bsp_modbus_link_list(item);
|
||
}
|
||
}
|
||
|
||
|
||
void bsp_modbus_register_fun(ModbusItem * const item, ModbusFun fun_code, ModbusFunCall register_call)
|
||
{
|
||
if((item != NULL) && (fun_code < kModbusFun_End))
|
||
{
|
||
item->fun_call_array[fun_code] = register_call;
|
||
|
||
bsp_modbus_link_list(item);
|
||
}
|
||
}
|
||
|
||
//为了方便统一处理
|
||
//05写单个线圈也占用2个字节,ON为1 OFF为0,发送时将数据转换ON为0xFF00 OFF为0
|
||
//
|
||
bool bsp_modbus_register_task(ModbusItem * const item, ModbusHead *head)
|
||
{
|
||
uint16_t len;
|
||
bool res = false;
|
||
ModbusTask *task;
|
||
if((item != NULL) && (item->gate != NULL) && (modbus_comm_data.max_task_num < MODBUS_MAX_TASK))
|
||
{
|
||
res = true;
|
||
item->is_master = true;
|
||
if(item->modbus_task == NULL)
|
||
{
|
||
item->gate_write_data_end_addr = item->gate_write_data_start_addr = modbus_comm_data.gate_write_data_cnt;
|
||
item->modbus_task = &modbus_comm_data.modbus_task_buf[modbus_comm_data.max_task_num];
|
||
}
|
||
modbus_comm_data.max_task_num++;
|
||
|
||
task = &item->modbus_task[item->task_num++];
|
||
|
||
len = head->reg_num;
|
||
if(head->fun_code < 3)
|
||
{
|
||
len = (len + 15) / 16;
|
||
task->buf_addr = bsp_gate_get_read_buf_addr(item->gate, len);
|
||
}
|
||
else if(head->fun_code < 5)
|
||
{
|
||
task->buf_addr = bsp_gate_get_read_buf_addr(item->gate, len);
|
||
}
|
||
else
|
||
{
|
||
modbus_comm_data.gate_write_data_cnt += len;
|
||
item->gate_write_data_end_addr += len;
|
||
task->buf_addr = bsp_gate_get_write_buf_addr(item->gate, len);
|
||
}
|
||
|
||
task->tick = 0;
|
||
task->head = head;
|
||
bsp_modbus_link_list(item);
|
||
}
|
||
return res;
|
||
}
|