修复软件包

This commit is contained in:
sc committed 2025-12-26 21:33:38 +08:00
1 parent e99dd7a6c3
commit ccd0acd07b
52 files changed
+229298 -886

No files matched your search

+170
View File
@@ -0,0 +1,170 @@
/*
#include <packages/qmodbus/inc/modbus.h>
#include <packages/qmodbus/inc/modbus_cvt.h>
#include <packages/qmodbus/inc/modbus_port.h>
* modbus.c
*
* Change Logs:
* Date Author Notes
* 2024-04-02 qiyongzhong first version
*/
#include <stdio.h>
#include <stdlib.h>
#ifdef MB_USING_RAW_PRT
static void mb_raw_prt(bool is_send, const u8 *pdata, int dlen)//原始数据打印
{
MB_PRINTF("%s", is_send ? ">>" : "<<");
for (int i=0; i<dlen; i++)
{
MB_PRINTF("%02X ", pdata[i]);
}
MB_PRINTF("\n");
}
#endif
//创建modbus实例, 成功返回实例指针, 失败返回NULL
mb_inst_t * mb_create(mb_backend_type_t type, const mb_backend_param_t *param)
{
MB_ASSERT(param != NULL);
mb_backend_t *backend = mb_backend_create(type, param);
if (backend == NULL)
{
return(NULL);
}
mb_inst_t *hinst = malloc(sizeof(mb_inst_t));
if (hinst == NULL)
{
mb_backend_destory(backend);
return(NULL);
}
hinst->saddr = MB_RTU_ADDR_DEF;
hinst->prot = (type == MB_BACKEND_TYPE_RTU) ? MB_PROT_RTU : MB_PROT_TCP;
hinst->tid = 0;
hinst->backend = backend;
#ifdef MB_USING_SLAVE
extern const mb_cb_table_t mb_cb_table;
hinst->cb = (mb_cb_table_t *)&mb_cb_table;
#else
hinst->cb = NULL;
#endif
return(hinst);
}
//销毁modbus实例
void mb_destory(mb_inst_t *hinst)
{
MB_ASSERT(hinst != NULL);
if (hinst->backend != NULL)
{
mb_backend_destory(hinst->backend);
hinst->backend = NULL;
}
free(hinst);
}
//修改从机地址, 默认地址为1
void mb_set_slave(mb_inst_t *hinst, u8 saddr)
{
MB_ASSERT(hinst != NULL);
hinst->saddr = saddr;
}
//修改协议, 默认使用与后端类型一致的协议类型
void mb_set_prot(mb_inst_t *hinst, mb_prot_t prot)
{
MB_ASSERT(hinst != NULL);
hinst->prot = prot;
}
//修改超时时间, 默认应答超时300ms, 字节超时32ms
void mb_set_tmo(mb_inst_t *hinst, int ack_tmo_ms, int byte_tmo_ms)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(hinst->backend != NULL);
mb_backend_config(hinst->backend, ack_tmo_ms, byte_tmo_ms);
}
//建立连接, 成功返回0, 失败返回-1
int mb_connect(mb_inst_t *hinst)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(hinst->backend != NULL);
return(mb_backend_open(hinst->backend));
}
//断开连接, 成功返回0, 失败返回-1
int mb_disconn(mb_inst_t *hinst)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(hinst->backend != NULL);
return(mb_backend_close(hinst->backend));
}
int mb_recv(mb_inst_t *hinst, u8 *buf, int bufsize)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(hinst->backend != NULL);
MB_ASSERT(buf != NULL);
MB_ASSERT(bufsize > 0);
int len = mb_backend_read(hinst->backend, buf, bufsize);
if (len < 0)//发生错误, 关闭后端
{
mb_backend_close(hinst->backend);
}
#ifdef MB_USING_RAW_PRT
if (len > 0)
{
mb_raw_prt(false, buf, len);
}
#endif
return(len);
}
int mb_send(mb_inst_t *hinst, u8 *buf, int size)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(hinst->backend != NULL);
MB_ASSERT(buf != NULL);
MB_ASSERT(size > 0);
int len = mb_backend_write(hinst->backend, buf, size);
if (len < 0)//发生错误, 关闭后端
{
mb_backend_close(hinst->backend);
}
#ifdef MB_USING_RAW_PRT
if (len > 0)
{
mb_raw_prt(true, buf, len);
}
#endif
return(len);
}
//清空接收缓存, 成功返回0, 失败返回-1
int mb_flush(mb_inst_t *hinst)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(hinst->backend != NULL);
return(mb_backend_flush(hinst->backend));
}
+306
View File
@@ -0,0 +1,306 @@
/*
#include <packages/qmodbus/inc/modbus_backend.h>
#include <packages/qmodbus/inc/modbus_port.h>
* modbus_backend.c
*
* Change Logs:
* Date Author Notes
* 2024-04-02 qiyongzhong first version
*/
#include <stdlib.h>
#include <string.h>
#ifdef MB_USING_RTU_BACKEND
static const mb_backend_ops_t mb_port_rtu_ops =
{
mb_port_rtu_open,
mb_port_rtu_close,
mb_port_rtu_read,
mb_port_rtu_write,
mb_port_rtu_flush
};
static mb_backend_t * mb_backend_create_rtu(const mb_backend_param_rtu_t *rtu)//创建rtu后端
{
extern char *strdup(const char *str);
mb_backend_t *backend = malloc(sizeof(mb_backend_t));
if (backend)
{
backend->type = MB_BACKEND_TYPE_RTU;
backend->param.rtu = *rtu;
backend->param.rtu.dev = strdup(rtu->dev);
backend->ops = &mb_port_rtu_ops;
backend->ack_tmo_ms = MB_BKD_ACK_TMO_MS_DEF;
backend->byte_tmo_ms = MB_BKD_BYTE_TMO_MS_DEF;
backend->hinst = NULL;
}
return(backend);
}
#endif
#ifdef MB_USING_TCP_BACKEND
static const mb_backend_ops_t mb_port_tcp_ops =
{
mb_port_tcp_open,
mb_port_tcp_close,
mb_port_tcp_read,
mb_port_tcp_write,
mb_port_tcp_flush
};
static mb_backend_t *mb_backend_create_tcp(const mb_backend_param_tcp_t *tcp)//创建tcp后端
{
extern char *strdup(const char *str);
mb_backend_t *backend = calloc(1, sizeof(mb_backend_t));
if (backend)
{
backend->type = MB_BACKEND_TYPE_TCP;
backend->param.tcp.host = strdup(tcp->host);
backend->param.tcp.port = tcp->port;
backend->ops = &mb_port_tcp_ops;
backend->ack_tmo_ms = MB_BKD_ACK_TMO_MS_DEF;
backend->byte_tmo_ms = MB_BKD_BYTE_TMO_MS_DEF;
backend->hinst = NULL;
}
return(backend);
}
#endif
#ifdef MB_USING_SOCK_BACKEND
static const mb_backend_ops_t mb_port_sock_ops =
{
NULL,
mb_port_tcp_close,
mb_port_tcp_read,
mb_port_tcp_write,
mb_port_tcp_flush
};
static mb_backend_t *mb_backend_create_sock(const mb_backend_param_sock_t *sock)//创建sock后端
{
mb_backend_t *backend = calloc(1, sizeof(mb_backend_t));
if (backend)
{
backend->type = MB_BACKEND_TYPE_SOCK;
backend->param.sock.fd = sock->fd;
backend->ops = &mb_port_sock_ops;
backend->ack_tmo_ms = MB_BKD_ACK_TMO_MS_DEF;
backend->byte_tmo_ms = MB_BKD_BYTE_TMO_MS_DEF;
backend->hinst = (void *)(sock->fd);
}
return(backend);
}
#endif
mb_backend_t *mb_backend_create(mb_backend_type_t type, const mb_backend_param_t *param)//创建后端, 成功返回后端指针, 失败返回NULL
{
mb_backend_t *backend = NULL;
switch(type)
{
#ifdef MB_USING_RTU_BACKEND
case MB_BACKEND_TYPE_RTU :
backend = mb_backend_create_rtu(&(param->rtu));
break;
#endif
#ifdef MB_USING_TCP_BACKEND
case MB_BACKEND_TYPE_TCP :
backend = mb_backend_create_tcp(&(param->tcp));
break;
#endif
#ifdef MB_USING_SOCK_BACKEND
case MB_BACKEND_TYPE_SOCK :
backend = mb_backend_create_sock(&(param->sock));
break;
#endif
default:
break;
}
return(backend);
}
void mb_backend_destory(mb_backend_t *backend)//销毁后端
{
if (backend == NULL)
{
return;
}
mb_backend_close(backend);
switch(backend->type)
{
#ifdef MB_USING_RTU_BACKEND
case MB_BACKEND_TYPE_RTU :
if (backend->param.rtu.dev)
{
free(backend->param.rtu.dev);
backend->param.rtu.dev = NULL;
}
break;
#endif
#ifdef MB_USING_TCP_BACKEND
case MB_BACKEND_TYPE_TCP :
if (backend->param.tcp.host)
{
free(backend->param.tcp.host);
backend->param.tcp.host = NULL;
}
break;
#endif
default:
break;
}
free(backend);
}
int mb_backend_open(mb_backend_t *backend)//打开后端, 成功返回0, 错误返回-1
{
if (backend == NULL)
{
return(-1);
}
if (backend->hinst != NULL)//已打开
{
return(0);
}
if ((backend->ops == NULL) || (backend->ops->open == NULL))
{
return(-1);
}
backend->hinst = backend->ops->open((void *)&(backend->param));
if (backend->hinst == NULL)//打开失败
{
return(-1);
}
return(0);
}
int mb_backend_close(mb_backend_t *backend)//关闭后端, 成功返回0, 错误返回-1
{
if (backend == NULL)
{
return(-1);
}
if (backend->hinst == NULL)//已关闭
{
return(0);
}
if ((backend->ops == NULL) || (backend->ops->close == NULL))
{
return(-1);
}
if (backend->ops->close(backend->hinst) != 0)//关闭失败
{
return(-1);
}
backend->hinst = NULL;
return(0);
}
int mb_backend_config(mb_backend_t *backend, int ack_tmo_ms, int byte_tmo_ms)//配置后端超时参数, 成功返回0, 错误返回-1
{
if (backend == NULL)
{
return(-1);
}
backend->ack_tmo_ms = ack_tmo_ms;
backend->byte_tmo_ms = byte_tmo_ms;
return(0);
}
int mb_backend_read(mb_backend_t *backend, u8 *buf, int bufsize)//从后端读数据, 返回读取到数据长度, 0表示超时, 错误返回-1
{
if ((backend == NULL) || (buf == NULL) || (bufsize <= 0))
{
return(-1);
}
if (backend->hinst == NULL)//未打开
{
return(-1);
}
if ((backend->ops == NULL) || (backend->ops->read == NULL))
{
return(-1);
}
int pos = 0;
long long told_ms = mb_port_get_ms();
while(pos < bufsize)
{
int len = backend->ops->read(backend->hinst, buf + pos, bufsize - pos);
if (len < 0)//发生错误
{
return(-1);
}
if (len > 0)//读到数据
{
told_ms = mb_port_get_ms();
pos += len;
continue;
}
int tmo_ms = mb_port_get_ms() - told_ms;
if (pos)//已有数据接收到, 则检查字节超时
{
if (tmo_ms > backend->byte_tmo_ms)//字节超时了
{
break;
}
}
else//未收到过数据, 则检查应答超时
{
if (tmo_ms > backend->ack_tmo_ms)//应答超时了
{
break;
}
}
mb_port_delay_ms(2);
}
return(pos);
}
int mb_backend_write(mb_backend_t *backend, u8 *buf, int size)//向后端写数据, 返回已发送数据长度, 错误返回-1
{
if ((backend == NULL) || (buf == NULL) || (size <= 0))
{
return(-1);
}
if (backend->hinst == NULL)//未打开
{
return(-1);
}
if ((backend->ops == NULL) || (backend->ops->write == NULL))
{
return(-1);
}
return(backend->ops->write(backend->hinst, buf, size));
}
int mb_backend_flush(mb_backend_t *backend)//清空后端接收缓存, 成功返回0, 错误返回-1
{
if (backend == NULL)
{
return(-1);
}
if (backend->hinst == NULL)//未打开
{
return(-1);
}
if ((backend->ops == NULL) || (backend->ops->flush == NULL))
{
return(-1);
}
return(backend->ops->flush(backend->hinst));
}
+62
View File
@@ -0,0 +1,62 @@
/*
* modbus_crc.c
*
* Change Logs:
* Date Author Notes
* 2024-04-02 qiyongzhong first version
*/
#include <packages/qmodbus/inc/modbus_crc.h>
static const u16 mb_crc_table[] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
u16 mb_crc_cyc_cal(u16 init, const u8 *pdata, int len)
{
u16 crc = init;
for(int i=0; i<len; i++)
{
int idx = ((u8)crc) ^ (*pdata++);
crc = (crc>>8) ^ mb_crc_table[idx];
}
return(crc);
}
u16 mb_crc_cal(const u8 *pdata, int len)
{
return(mb_crc_cyc_cal(MB_CRC_INIT_VOL, pdata, len));
}
+93
View File
@@ -0,0 +1,93 @@
/*
* modbus_cvt.c
*
* Change Logs:
* Date Author Notes
* 2024-04-01 qiyongzhong first version
*/
#include <packages/qmodbus/inc/modbus_cvt.h>
int mb_cvt_u8_put(u8 *buf, u8 val)
{
*buf = val;
return(1);
}
int mb_cvt_u8_get(const u8 *buf, u8 *pval)
{
*pval = *buf;
return(1);
}
int mb_cvt_u16_put(u8 *buf, u16 val)
{
u8 *p = buf;
*p++ = (val >> 8);
*p++ = val;
return(2);
}
int mb_cvt_u16_get(const u8 *buf, u16 *pval)
{
u8 *p = (u8 *)buf;
u16 uval = *p++;
uval <<= 8;
uval += *p++;
*pval = uval;
return(2);
}
int mb_cvt_u32_put(u8 *buf, u32 val)
{
u8 *p = buf;
*p++ = (val >> 24);
*p++ = (val >> 16);
*p++ = (val >> 8);
*p++ = val;
return(4);
}
int mb_cvt_u32_get(const u8 *buf, u32 *pval)
{
u8 *p = (u8 *)buf;
u32 uval = *p++;
uval <<= 8;
uval += *p++;
uval <<= 8;
uval += *p++;
uval <<= 8;
uval += *p++;
*pval = uval;
return(4);
}
int mb_cvt_f32_put(u8 *buf, f32 val)
{
float fval = val;
u32 *puv = (u32 *)&fval;
return(mb_cvt_u32_put(buf, *puv));
}
int mb_cvt_f32_get(const u8 *buf, f32 *pval)
{
return(mb_cvt_u32_get(buf, (u32 *)pval));
}
u8 mb_bitmap_get(const u8 *pbits, int idx)//从位表中读指定索引的位
{
return(((pbits[idx/8] & (1 << (idx % 8))) != 0) ? 1 : 0);
}
void mb_bitmap_set(u8 *pbits, int idx, u8 bit)//向位表中写指定索引的位
{
if (bit)
{
pbits[idx/8] |= (1 << (idx % 8));
}
else
{
pbits[idx/8] &= ~(1 << (idx % 8));
}
}
+802
View File
@@ -0,0 +1,802 @@
/*
#include <packages/qmodbus/inc/modbus.h>
#include <packages/qmodbus/inc/modbus_cvt.h>
#include <packages/qmodbus/inc/modbus_port.h>
* modbus_master.c
*
* Change Logs:
* Date Author Notes
* 2024-04-02 qiyongzhong first version
*/
#include <string.h>
#ifdef MB_USING_MASTER
#ifdef MB_USING_RTU_PROTOCOL
static int mb_read_req_rtu(mb_inst_t *hinst, u8 func, u16 addr, int nb, u8 *pdata)
{
mb_rtu_frm_t frm;
frm.saddr = hinst->saddr;
frm.pdu.rd_req.fc = func;
frm.pdu.rd_req.addr = addr;
frm.pdu.rd_req.nb = nb;
int flen = mb_rtu_frm_make(hinst->buf, (void *)&frm, MB_PDU_TYPE_REQ);
int slen = mb_send(hinst, hinst->buf, flen);
if (slen != flen)
{
return(0);
}
int rlen = mb_recv(hinst, hinst->buf, sizeof(hinst->buf));
if (rlen <= 0)
{
return(0);
}
int pdu_len = mb_rtu_frm_parse(hinst->buf, rlen, &frm, MB_PDU_TYPE_RSP);
if (pdu_len <= 0)
{
return(0);
}
#ifdef MB_USING_ADDR_CHK
if (frm.saddr != hinst->saddr)
{
return(0);
}
#endif
if (MODBUS_FC_EXCEPT_CHK(frm.pdu.fc))//是异常应答
{
return(-(int)frm.pdu.exc.ec);
}
int dlen = frm.pdu.rd_rsp.dlen;
memcpy(pdata, frm.pdu.rd_rsp.pdata, dlen);
return(dlen);
}
#endif
#ifdef MB_USING_TCP_PROTOCOL
static int mb_read_req_tcp(mb_inst_t *hinst, u8 func, u16 addr, int nb, u8 *pdata)
{
mb_tcp_frm_t frm;
hinst->tid++;
frm.mbap.tid = hinst->tid;
frm.mbap.pid = MB_TCP_MBAP_PID;
frm.mbap.did = hinst->saddr;
frm.pdu.rd_req.fc = func;
frm.pdu.rd_req.addr = addr;
frm.pdu.rd_req.nb = nb;
int flen = mb_tcp_frm_make(hinst->buf, (void *)&frm, MB_PDU_TYPE_REQ);
int slen = mb_send(hinst, hinst->buf, flen);
if (slen != flen)
{
return(0);
}
int rlen = mb_recv(hinst, hinst->buf, sizeof(hinst->buf));
if (rlen <= 0)
{
return(0);
}
int pdu_len = mb_tcp_frm_parse(hinst->buf, rlen, &frm, MB_PDU_TYPE_RSP);
if (pdu_len < 0)
{
return(0);
}
#ifdef MB_USING_ADDR_CHK
if (frm.mbap.did != hinst->saddr)
{
return(0);
}
#endif
#ifdef MB_USING_MBAP_CHK
if ((frm.mbap.tid != hinst->tid) || (frm.mbap.pid != MB_TCP_MBAP_PID) || (frm.mbap.dlen != (pdu_len + 1)))
{
return(0);
}
#endif
if (MODBUS_FC_EXCEPT_CHK(frm.pdu.fc))//是异常应答
{
return(-(int)frm.pdu.exc.ec);
}
int dlen = frm.pdu.rd_rsp.dlen;
memcpy(pdata, frm.pdu.rd_rsp.pdata, dlen);
return(dlen);
}
#endif
//读请求, 功能码和数据由用户确定, 成功返回应答数据长度, 异常应答返回负值错误码, 其它错误返回0
int mb_read_req(mb_inst_t *hinst, u8 func, u16 addr, int nb, u8 *pdata)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(pdata != NULL);
MB_ASSERT(nb > 0);
switch (hinst->prot)
{
#ifdef MB_USING_RTU_PROTOCOL
case MB_PROT_RTU :
return(mb_read_req_rtu(hinst, func, addr, nb, pdata));
#endif
#ifdef MB_USING_TCP_PROTOCOL
case MB_PROT_TCP :
return(mb_read_req_tcp(hinst, func, addr, nb, pdata));
#endif
default:
break;
}
return(0);
}
#ifdef MB_USING_RTU_PROTOCOL
static int mb_write_req_rtu(mb_inst_t *hinst, u8 func, u16 addr, int nb, const u8 *pdata, int dlen)
{
mb_rtu_frm_t frm;
frm.saddr = hinst->saddr;
frm.pdu.wr_req.fc = func;
frm.pdu.wr_req.addr = addr;
frm.pdu.wr_req.nb = nb;
frm.pdu.wr_req.dlen = dlen;
frm.pdu.wr_req.pdata = (u8 *)pdata;
int flen = mb_rtu_frm_make(hinst->buf, (void *)&frm, MB_PDU_TYPE_REQ);
int slen = mb_send(hinst, hinst->buf, flen);
if (slen != flen)
{
return(0);
}
int rlen = mb_recv(hinst, hinst->buf, sizeof(hinst->buf));
if (rlen <= 0)
{
return(0);
}
int pdu_len = mb_rtu_frm_parse(hinst->buf, rlen, &frm, MB_PDU_TYPE_RSP);
if (pdu_len <= 0)
{
return(0);
}
#ifdef MB_USING_ADDR_CHK
if (frm.saddr != hinst->saddr)
{
return(0);
}
#endif
if (MODBUS_FC_EXCEPT_CHK(frm.pdu.fc))//是异常应答
{
return(-(int)frm.pdu.exc.ec);
}
return(frm.pdu.wr_rsp.nb);
}
#endif
#ifdef MB_USING_TCP_PROTOCOL
static int mb_write_req_tcp(mb_inst_t *hinst, u8 func, u16 addr, int nb, const u8 *pdata, int dlen)
{
mb_tcp_frm_t frm;
hinst->tid++;
frm.mbap.tid = hinst->tid;
frm.mbap.pid = MB_TCP_MBAP_PID;
frm.mbap.did = hinst->saddr;
frm.pdu.wr_req.fc = func;
frm.pdu.wr_req.addr = addr;
frm.pdu.wr_req.nb = nb;
frm.pdu.wr_req.dlen = dlen;
frm.pdu.wr_req.pdata = (u8 *)pdata;
int flen = mb_tcp_frm_make(hinst->buf, (void *)&frm, MB_PDU_TYPE_REQ);
int slen = mb_send(hinst, hinst->buf, flen);
if (slen != flen)
{
return(0);
}
int rlen = mb_recv(hinst, hinst->buf, sizeof(hinst->buf));
if (rlen <= 0)
{
return(0);
}
int pdu_len = mb_tcp_frm_parse(hinst->buf, rlen, &frm, MB_PDU_TYPE_RSP);
if (pdu_len < 0)
{
return(0);
}
#ifdef MB_USING_ADDR_CHK
if (frm.mbap.did != hinst->saddr)
{
return(0);
}
#endif
#ifdef MB_USING_MBAP_CHK
if ((frm.mbap.tid != hinst->tid) || (frm.mbap.pid != MB_TCP_MBAP_PID) || (frm.mbap.dlen != (pdu_len + 1)))
{
return(0);
}
#endif
if (MODBUS_FC_EXCEPT_CHK(frm.pdu.fc))//是异常应答
{
return(-(int)frm.pdu.exc.ec);
}
return(frm.pdu.wr_rsp.nb);
}
#endif
//写请求, 功能码和数据由用户确定, 成功返回写入数量, 异常应答返回负值错误码, 其它错误返回0
int mb_write_req(mb_inst_t *hinst, u8 func, u16 addr, int nb, const u8 *pdata, int dlen)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(pdata != NULL);
MB_ASSERT(nb > 0);
MB_ASSERT(dlen > 0);
switch (hinst->prot)
{
#ifdef MB_USING_RTU_PROTOCOL
case MB_PROT_RTU :
return(mb_write_req_rtu(hinst, func, addr, nb, pdata, dlen));
#endif
#ifdef MB_USING_TCP_PROTOCOL
case MB_PROT_TCP :
return(mb_write_req_tcp(hinst, func, addr, nb, pdata, dlen));
#endif
default:
break;
}
return(0);
}
//读多个线圈, 功能码-0x01, 成功返回读取位数量, 异常应答返回负值错误码, 其它错误返回0
int mb_read_bits(mb_inst_t *hinst, u16 addr, int nb, u8 *pbits)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(pbits != NULL);
MB_ASSERT(nb > 0);
int dlen = mb_read_req(hinst, MODBUS_FC_READ_COILS, addr, nb, pbits);
return((dlen != (nb + 7) / 8) ? dlen : nb);
}
//读多个离散量输入, 功能码-0x02, 成功返回读取位数量, 异常应答返回负值错误码, 其它错误返回0
int mb_read_input_bits(mb_inst_t *hinst, u16 addr, int nb, u8 *pbits)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(pbits != NULL);
MB_ASSERT(nb > 0);
int dlen = mb_read_req(hinst, MODBUS_FC_READ_DISCRETE_INPUTS, addr, nb, pbits);
return((dlen != (nb + 7) / 8) ? dlen : nb);
}
//读多个保持寄存器, 功能码-0x03, 成功返回读取寄存器数量, 异常应答返回负值错误码, 其它错误返回0
int mb_read_regs(mb_inst_t *hinst, u16 addr, int nb, u16 *pregs)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(pregs != NULL);
MB_ASSERT(nb > 0);
int dlen = mb_read_req(hinst, MODBUS_FC_READ_HOLDING_REGISTERS, addr, nb, hinst->datas);
if (dlen <= 0)
{
return(dlen);
}
if (dlen != (nb * 2))
{
return(0);
}
u8 *p = hinst->datas;
for (int i=0; i<nb; i++)
{
p += mb_cvt_u16_get(p, pregs + i);
}
return(nb);
}
//读多个输入寄存器, 功能码-0x04, 成功返回读取寄存器数量, 异常应答返回负值错误码, 其它错误返回0
int mb_read_input_regs(mb_inst_t *hinst, u16 addr, int nb, u16 *pregs)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(pregs != NULL);
MB_ASSERT(nb > 0);
int dlen = mb_read_req(hinst, MODBUS_FC_READ_INPUT_REGISTERS, addr, nb, hinst->datas);
if (dlen <= 0)
{
return(dlen);
}
if (dlen != (nb * 2))
{
return(0);
}
u8 *p = hinst->datas;
for (int i=0; i<nb; i++)
{
p += mb_cvt_u16_get(p, pregs + i);
}
return(nb);
}
#ifdef MB_USING_RTU_PROTOCOL
static int mb_write_single_rtu(mb_inst_t *hinst, u8 func, u16 addr, u16 val)
{
mb_rtu_frm_t frm;
frm.saddr = hinst->saddr;
frm.pdu.wr_single.fc = func;
frm.pdu.wr_single.addr = addr;
frm.pdu.wr_single.val = val;
int flen = mb_rtu_frm_make(hinst->buf, (void *)&frm, MB_PDU_TYPE_REQ);
int slen = mb_send(hinst, hinst->buf, flen);
if (slen != flen)
{
return(0);
}
int rlen = mb_recv(hinst, hinst->buf, sizeof(hinst->buf));
if (rlen <= 0)
{
return(0);
}
int pdu_len = mb_rtu_frm_parse(hinst->buf, rlen, &frm, MB_PDU_TYPE_RSP);
if (pdu_len <= 0)
{
return(0);
}
#ifdef MB_USING_ADDR_CHK
if (frm.saddr != hinst->saddr)
{
return(0);
}
#endif
if (MODBUS_FC_EXCEPT_CHK(frm.pdu.fc))//是异常应答
{
return(-(int)frm.pdu.exc.ec);
}
return(1);
}
#endif
#ifdef MB_USING_TCP_PROTOCOL
static int mb_write_single_tcp(mb_inst_t *hinst, u8 func, u16 addr, u16 val)
{
mb_tcp_frm_t frm;
hinst->tid++;
frm.mbap.tid = hinst->tid;
frm.mbap.pid = MB_TCP_MBAP_PID;
frm.mbap.did = hinst->saddr;
frm.pdu.wr_single.fc = func;
frm.pdu.wr_single.addr = addr;
frm.pdu.wr_single.val = val;
int flen = mb_tcp_frm_make(hinst->buf, (void *)&frm, MB_PDU_TYPE_REQ);
int slen = mb_send(hinst, hinst->buf, flen);
if (slen != flen)
{
return(0);
}
int rlen = mb_recv(hinst, hinst->buf, sizeof(hinst->buf));
if (rlen <= 0)
{
return(0);
}
int pdu_len = mb_tcp_frm_parse(hinst->buf, rlen, &frm, MB_PDU_TYPE_RSP);
if (pdu_len < 0)
{
return(0);
}
#ifdef MB_USING_ADDR_CHK
if (frm.mbap.did != hinst->saddr)
{
return(0);
}
#endif
#ifdef MB_USING_MBAP_CHK
if ((frm.mbap.tid != hinst->tid) || (frm.mbap.pid != MB_TCP_MBAP_PID) || (frm.mbap.dlen != (pdu_len + 1)))
{
return(0);
}
#endif
if (MODBUS_FC_EXCEPT_CHK(frm.pdu.fc))//是异常应答
{
return(-(int)frm.pdu.exc.ec);
}
return(1);
}
#endif
static int mb_write_single(mb_inst_t *hinst, u8 func, u16 addr, u16 val)
{
switch (hinst->prot)
{
#ifdef MB_USING_RTU_PROTOCOL
case MB_PROT_RTU :
return(mb_write_single_rtu(hinst, func, addr, val));
#endif
#ifdef MB_USING_TCP_PROTOCOL
case MB_PROT_TCP :
return(mb_write_single_tcp(hinst, func, addr, val));
#endif
default:
break;
}
return(0);
}
//写单个线圈, 功能码-0x05, 成功返回1, 异常应答返回负值错误码, 其它错误返回0
int mb_write_bit(mb_inst_t *hinst, u16 addr, u8 bit)
{
MB_ASSERT(hinst != NULL);
u16 val = bit ? 0xFF00 : 0x0000;
return(mb_write_single(hinst, MODBUS_FC_WRITE_SINGLE_COIL, addr, val));
}
//写单个寄存器, 功能码-0x06, 成功返回1, 异常应答返回负值错误码, 其它错误返回0
int mb_write_reg(mb_inst_t *hinst, u16 addr, u16 val)
{
MB_ASSERT(hinst != NULL);
return(mb_write_single(hinst, MODBUS_FC_WRITE_SINGLE_REGISTER, addr, val));
}
//写多个线圈, 功能码-0x0F, 成功返回写位数量, 异常应答返回负值错误码, 其它错误返回0
int mb_write_bits(mb_inst_t *hinst, u16 addr, int nb, const u8 *pbits)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(pbits != NULL);
MB_ASSERT(nb > 0);
int dlen = (nb + 7) / 8;
return(mb_write_req(hinst, MODBUS_FC_WRITE_MULTIPLE_COILS, addr, nb, pbits, dlen));
}
//写多个寄存器, 功能码-0x10, 成功返回写寄存器数量, 异常应答返回负值错误码, 其它错误返回0
int mb_write_regs(mb_inst_t *hinst, u16 addr, int nb, const u16 *pregs)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(pregs != NULL);
MB_ASSERT(nb > 0);
u8 *p = hinst->datas;
for (int i=0; i<nb; i++)
{
p += mb_cvt_u16_put(p, pregs[i]);
}
int dlen = nb * 2;
return(mb_write_req(hinst, MODBUS_FC_WRITE_MULTIPLE_REGISTERS, addr, nb, hinst->datas, dlen));
}
#ifdef MB_USING_RTU_PROTOCOL
static int mb_mask_write_rtu(mb_inst_t *hinst, u16 addr, u16 val_and, u16 val_or)
{
mb_rtu_frm_t frm;
frm.saddr = hinst->saddr;
frm.pdu.mask_wr.fc = MODBUS_FC_MASK_WRITE_REGISTER;
frm.pdu.mask_wr.addr = addr;
frm.pdu.mask_wr.val_and = val_and;
frm.pdu.mask_wr.val_or = val_or;
int flen = mb_rtu_frm_make(hinst->buf, (void *)&frm, MB_PDU_TYPE_REQ);
int slen = mb_send(hinst, hinst->buf, flen);
if (slen != flen)
{
return(0);
}
int rlen = mb_recv(hinst, hinst->buf, sizeof(hinst->buf));
if (rlen <= 0)
{
return(0);
}
int pdu_len = mb_rtu_frm_parse(hinst->buf, rlen, &frm, MB_PDU_TYPE_RSP);
if (pdu_len <= 0)
{
return(0);
}
#ifdef MB_USING_ADDR_CHK
if (frm.saddr != hinst->saddr)
{
return(0);
}
#endif
if (MODBUS_FC_EXCEPT_CHK(frm.pdu.fc))//是异常应答
{
return(-(int)frm.pdu.exc.ec);
}
return(1);
}
#endif
#ifdef MB_USING_TCP_PROTOCOL
static int mb_mask_write_tcp(mb_inst_t *hinst, u16 addr, u16 val_and, u16 val_or)
{
mb_tcp_frm_t frm;
hinst->tid++;
frm.mbap.tid = hinst->tid;
frm.mbap.pid = MB_TCP_MBAP_PID;
frm.mbap.did = hinst->saddr;
frm.pdu.mask_wr.fc = MODBUS_FC_MASK_WRITE_REGISTER;
frm.pdu.mask_wr.addr = addr;
frm.pdu.mask_wr.val_and = val_and;
frm.pdu.mask_wr.val_or = val_or;
int flen = mb_tcp_frm_make(hinst->buf, (void *)&frm, MB_PDU_TYPE_REQ);
int slen = mb_send(hinst, hinst->buf, flen);
if (slen != flen)
{
return(0);
}
int rlen = mb_recv(hinst, hinst->buf, sizeof(hinst->buf));
if (rlen <= 0)
{
return(0);
}
int pdu_len = mb_tcp_frm_parse(hinst->buf, rlen, &frm, MB_PDU_TYPE_RSP);
if (pdu_len < 0)
{
return(0);
}
#ifdef MB_USING_ADDR_CHK
if (frm.mbap.did != hinst->saddr)
{
return(0);
}
#endif
#ifdef MB_USING_MBAP_CHK
if ((frm.mbap.tid != hinst->tid) || (frm.mbap.pid != MB_TCP_MBAP_PID) || (frm.mbap.dlen != (pdu_len + 1)))
{
return(0);
}
#endif
if (MODBUS_FC_EXCEPT_CHK(frm.pdu.fc))//是异常应答
{
return(-(int)frm.pdu.exc.ec);
}
return(1);
}
#endif
//屏蔽写寄存器, 功能码-0x16, 成功返回1, 异常应答返回负值错误码, 其它错误返回0
int mb_mask_write_reg(mb_inst_t *hinst, u16 addr, u16 mask_and, u16 mask_or)
{
MB_ASSERT(hinst != NULL);
switch (hinst->prot)
{
#ifdef MB_USING_RTU_PROTOCOL
case MB_PROT_RTU :
return(mb_mask_write_rtu(hinst, addr, mask_and, mask_or));
#endif
#ifdef MB_USING_TCP_PROTOCOL
case MB_PROT_TCP :
return(mb_mask_write_tcp(hinst, addr, mask_and, mask_or));
#endif
default:
break;
}
return(0);
}
#ifdef MB_USING_RTU_PROTOCOL
static int mb_write_and_read_regs_rtu(mb_inst_t *hinst, u16 wr_addr, int wr_nb, const u16 *p_wr_regs,
u16 rd_addr, int rd_nb, u16 *p_rd_regs)
{
u8 *p = hinst->datas;
for (int i=0; i<wr_nb; i++)
{
p += mb_cvt_u16_put(p, p_wr_regs[i]);
}
mb_rtu_frm_t frm;
frm.saddr = hinst->saddr;
frm.pdu.wr_rd_req.fc = MODBUS_FC_WRITE_AND_READ_REGISTERS;
frm.pdu.wr_rd_req.rd_addr = rd_addr;
frm.pdu.wr_rd_req.rd_nb = rd_nb;
frm.pdu.wr_rd_req.wr_addr = wr_addr;
frm.pdu.wr_rd_req.wr_nb = wr_nb;
frm.pdu.wr_rd_req.dlen = wr_nb * 2;
frm.pdu.wr_rd_req.pdata = hinst->datas;
int flen = mb_rtu_frm_make(hinst->buf, (void *)&frm, MB_PDU_TYPE_REQ);
int slen = mb_send(hinst, hinst->buf, flen);
if (slen != flen)
{
return(0);
}
int rlen = mb_recv(hinst, hinst->buf, sizeof(hinst->buf));
if (rlen <= 0)
{
return(0);
}
int pdu_len = mb_rtu_frm_parse(hinst->buf, rlen, &frm, MB_PDU_TYPE_RSP);
if (pdu_len <= 0)
{
return(0);
}
#ifdef MB_USING_ADDR_CHK
if (frm.saddr != hinst->saddr)
{
return(0);
}
#endif
if (MODBUS_FC_EXCEPT_CHK(frm.pdu.fc))//是异常应答
{
return(-(int)frm.pdu.exc.ec);
}
int dlen = frm.pdu.rd_rsp.dlen;
if (dlen != (rd_nb * 2))
{
return(0);
}
p = frm.pdu.rd_rsp.pdata;
for (int i=0; i<rd_nb; i++)
{
p += mb_cvt_u16_get(p, p_rd_regs + i);
}
return(rd_nb);
}
#endif
#ifdef MB_USING_TCP_PROTOCOL
static int mb_write_and_read_regs_tcp(mb_inst_t *hinst, u16 wr_addr, int wr_nb, const u16 *p_wr_regs,
u16 rd_addr, int rd_nb, u16 *p_rd_regs)
{
u8 *p = hinst->datas;
for (int i=0; i<wr_nb; i++)
{
p += mb_cvt_u16_put(p, p_wr_regs[i]);
}
mb_tcp_frm_t frm;
hinst->tid++;
frm.mbap.tid = hinst->tid;
frm.mbap.pid = MB_TCP_MBAP_PID;
frm.mbap.did = hinst->saddr;
frm.pdu.wr_rd_req.fc = MODBUS_FC_WRITE_AND_READ_REGISTERS;
frm.pdu.wr_rd_req.rd_addr = rd_addr;
frm.pdu.wr_rd_req.rd_nb = rd_nb;
frm.pdu.wr_rd_req.wr_addr = wr_addr;
frm.pdu.wr_rd_req.wr_nb = wr_nb;
frm.pdu.wr_rd_req.dlen = wr_nb * 2;
frm.pdu.wr_rd_req.pdata = hinst->datas;
int flen = mb_tcp_frm_make(hinst->buf, (void *)&frm, MB_PDU_TYPE_REQ);
int slen = mb_send(hinst, hinst->buf, flen);
if (slen != flen)
{
return(0);
}
int rlen = mb_recv(hinst, hinst->buf, sizeof(hinst->buf));
if (rlen <= 0)
{
return(0);
}
int pdu_len = mb_tcp_frm_parse(hinst->buf, rlen, &frm, MB_PDU_TYPE_RSP);
if (pdu_len < 0)
{
return(0);
}
#ifdef MB_USING_ADDR_CHK
if (frm.mbap.did != hinst->saddr)
{
return(0);
}
#endif
#ifdef MB_USING_MBAP_CHK
if ((frm.mbap.tid != hinst->tid) || (frm.mbap.pid != MB_TCP_MBAP_PID) || (frm.mbap.dlen != (pdu_len + 1)))
{
return(0);
}
#endif
if (MODBUS_FC_EXCEPT_CHK(frm.pdu.fc))//是异常应答
{
return(-(int)frm.pdu.exc.ec);
}
int dlen = frm.pdu.rd_rsp.dlen;
if (dlen != (rd_nb * 2))
{
return(0);
}
p = frm.pdu.rd_rsp.pdata;
for (int i=0; i<rd_nb; i++)
{
p += mb_cvt_u16_get(p, p_rd_regs + i);
}
return(rd_nb);
}
#endif
//读/写多个寄存器, 功能码-0x17, 成功返回读取寄存器数量, 异常应答返回负值错误码, 其它错误返回0
int mb_write_and_read_regs(mb_inst_t *hinst, u16 wr_addr, int wr_nb, const u16 *p_wr_regs,
u16 rd_addr, int rd_nb, u16 *p_rd_regs)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(p_wr_regs != NULL);
MB_ASSERT(p_rd_regs != NULL);
MB_ASSERT(wr_nb > 0);
MB_ASSERT(rd_nb > 0);
switch (hinst->prot)
{
#ifdef MB_USING_RTU_PROTOCOL
case MB_PROT_RTU :
return(mb_write_and_read_regs_rtu(hinst, wr_addr, wr_nb, p_wr_regs, rd_addr, rd_nb, p_rd_regs));
#endif
#ifdef MB_USING_TCP_PROTOCOL
case MB_PROT_TCP :
return(mb_write_and_read_regs_tcp(hinst, wr_addr, wr_nb, p_wr_regs, rd_addr, rd_nb, p_rd_regs));
#endif
default:
break;
}
return(0);
}
#endif
+427
View File
@@ -0,0 +1,427 @@
/*
#include <packages/qmodbus/inc/modbus_cvt.h>
#include <packages/qmodbus/inc/modbus_pdu.h>
* modbus_pdu.c
*
* Change Logs:
* Date Author Notes
* 2024-04-01 qiyongzhong first version
*/
#include <string.h>
static int mb_pdu_except_make(u8 *buf, const mb_pdu_except_t *exc)
{
u8 *p = buf;
p += mb_cvt_u8_put(p, exc->fc);
p += mb_cvt_u8_put(p, exc->ec);
return((int)(p - buf));
}
static int mb_pdu_except_parse(const u8 *buf, int len, mb_pdu_except_t *exc)
{
if (len < 2)
{
return(0);
}
u8 *p = (u8 *)buf;
p += mb_cvt_u8_get(p, &(exc->fc));
p += mb_cvt_u8_get(p, &(exc->ec));
return((int)(p - buf));
}
static int mb_pdu_rd_req_make(u8 *buf, const mb_pdu_rd_req_t *rd_req)
{
u8 *p = buf;
p += mb_cvt_u8_put(p, rd_req->fc);
p += mb_cvt_u16_put(p, rd_req->addr);
p += mb_cvt_u16_put(p, rd_req->nb);
return((int)(p - buf));
}
static int mb_pdu_rd_req_parse(const u8 *buf, int len, mb_pdu_rd_req_t *rd_req)
{
if (len < 5)
{
return(0);
}
u8 *p = (u8 *)buf;
p += mb_cvt_u8_get(p, &(rd_req->fc));
p += mb_cvt_u16_get(p, &(rd_req->addr));
p += mb_cvt_u16_get(p, &(rd_req->nb));
return((int)(p - buf));
}
static int mb_pdu_rd_rsp_make(u8 *buf, const mb_pdu_rd_rsp_t *rd_rsp)
{
u8 *p = buf;
p += mb_cvt_u8_put(p, rd_rsp->fc);
p += mb_cvt_u8_put(p, rd_rsp->dlen);
memcpy(p, rd_rsp->pdata, rd_rsp->dlen);
p += rd_rsp->dlen;
return((int)(p - buf));
}
static int mb_pdu_rd_rsp_parse(const u8 *buf, int len, mb_pdu_rd_rsp_t *rd_rsp)
{
if (len < 3)
{
return(0);
}
u8 *p = (u8 *)buf;
p += mb_cvt_u8_get(p, &(rd_rsp->fc));
p += mb_cvt_u8_get(p, &(rd_rsp->dlen));
rd_rsp->pdata = p;
p += rd_rsp->dlen;
return((int)(p - buf));
}
static int mb_pdu_wr_single_make(u8 *buf, const mb_pdu_wr_single_t *wr_single)
{
u8 *p = buf;
p += mb_cvt_u8_put(p, wr_single->fc);
p += mb_cvt_u16_put(p, wr_single->addr);
p += mb_cvt_u16_put(p, wr_single->val);
return((int)(p - buf));
}
static int mb_pdu_wr_single_parse(const u8 *buf, int len, mb_pdu_wr_single_t *wr_single)
{
if (len < 5)
{
return(0);
}
u8 *p = (u8 *)buf;
p += mb_cvt_u8_get(p, &(wr_single->fc));
p += mb_cvt_u16_get(p, &(wr_single->addr));
p += mb_cvt_u16_get(p, &(wr_single->val));
return((int)(p - buf));
}
static int mb_pdu_wr_req_make(u8 *buf, const mb_pdu_wr_req_t *wr_req)
{
u8 *p = buf;
p += mb_cvt_u8_put(p, wr_req->fc);
p += mb_cvt_u16_put(p, wr_req->addr);
p += mb_cvt_u16_put(p, wr_req->nb);
p += mb_cvt_u8_put(p, wr_req->dlen);
memcpy(p, wr_req->pdata, wr_req->dlen);
p += wr_req->dlen;
return((int)(p - buf));
}
static int mb_pdu_wr_req_parse(const u8 *buf, int len, mb_pdu_wr_req_t *wr_req)
{
if (len < 7)
{
return(0);
}
u8 *p = (u8 *)buf;
p += mb_cvt_u8_get(p, &(wr_req->fc));
p += mb_cvt_u16_get(p, &(wr_req->addr));
p += mb_cvt_u16_get(p, &(wr_req->nb));
p += mb_cvt_u8_get(p, &(wr_req->dlen));
wr_req->pdata = p;
p += wr_req->dlen;
return((int)(p - buf));
}
static int mb_pdu_wr_rsp_make(u8 *buf, const mb_pdu_wr_rsp_t *wr_rsp)
{
u8 *p = buf;
p += mb_cvt_u8_put(p, wr_rsp->fc);
p += mb_cvt_u16_put(p, wr_rsp->addr);
p += mb_cvt_u16_put(p, wr_rsp->nb);
return((int)(p - buf));
}
static int mb_pdu_wr_rsp_parse(const u8 *buf, int len, mb_pdu_wr_rsp_t *wr_rsp)
{
if (len < 5)
{
return(0);
}
u8 *p = (u8 *)buf;
p += mb_cvt_u8_get(p, &(wr_rsp->fc));
p += mb_cvt_u16_get(p, &(wr_rsp->addr));
p += mb_cvt_u16_get(p, &(wr_rsp->nb));
return((int)(p - buf));
}
static int mb_pdu_mask_wr_make(u8 *buf, const mb_pdu_mask_wr_t *mask_wr)
{
u8 *p = buf;
p += mb_cvt_u8_put(p, mask_wr->fc);
p += mb_cvt_u16_put(p, mask_wr->addr);
p += mb_cvt_u16_put(p, mask_wr->val_and);
p += mb_cvt_u16_put(p, mask_wr->val_or);
return((int)(p - buf));
}
static int mb_pdu_mask_wr_parse(const u8 *buf, int len, mb_pdu_mask_wr_t *mask_wr)
{
if (len < 7)
{
return(0);
}
u8 *p = (u8 *)buf;
p += mb_cvt_u8_get(p, &(mask_wr->fc));
p += mb_cvt_u16_get(p, &(mask_wr->addr));
p += mb_cvt_u16_get(p, &(mask_wr->val_and));
p += mb_cvt_u16_get(p, &(mask_wr->val_or));
return((int)(p - buf));
}
static int mb_pdu_wr_rd_req_make(u8 *buf, const mb_pdu_wr_rd_req_t *wr_rd_req)
{
u8 *p = buf;
p += mb_cvt_u8_put(p, wr_rd_req->fc);
p += mb_cvt_u16_put(p, wr_rd_req->rd_addr);
p += mb_cvt_u16_put(p, wr_rd_req->rd_nb);
p += mb_cvt_u16_put(p, wr_rd_req->wr_addr);
p += mb_cvt_u16_put(p, wr_rd_req->wr_nb);
p += mb_cvt_u8_put(p, wr_rd_req->dlen);
memcpy(p, wr_rd_req->pdata, wr_rd_req->dlen);
p += wr_rd_req->dlen;
return((int)(p - buf));
}
static int mb_pdu_wr_rd_req_parse(const u8 *buf, int len, mb_pdu_wr_rd_req_t *wr_rd_req)
{
if (len < 11)
{
return(0);
}
u8 *p = (u8 *)buf;
p += mb_cvt_u8_get(p, &(wr_rd_req->fc));
p += mb_cvt_u16_get(p, &(wr_rd_req->rd_addr));
p += mb_cvt_u16_get(p, &(wr_rd_req->rd_nb));
p += mb_cvt_u16_get(p, &(wr_rd_req->wr_addr));
p += mb_cvt_u16_get(p, &(wr_rd_req->wr_nb));
p += mb_cvt_u8_get(p, &(wr_rd_req->dlen));
wr_rd_req->pdata = p;
p += wr_rd_req->dlen;
return((int)(p - buf));
}
static int mb_pdu_req_make(u8 *buf, const mb_pdu_t *pdu)//生成pdu请求帧, 返回帧长度, 失败返回0
{
switch(pdu->fc)
{
case MODBUS_FC_READ_COILS :
return(mb_pdu_rd_req_make(buf, (mb_pdu_rd_req_t *)pdu));
case MODBUS_FC_READ_DISCRETE_INPUTS :
return(mb_pdu_rd_req_make(buf, (mb_pdu_rd_req_t *)pdu));
case MODBUS_FC_READ_HOLDING_REGISTERS :
return(mb_pdu_rd_req_make(buf, (mb_pdu_rd_req_t *)pdu));
case MODBUS_FC_READ_INPUT_REGISTERS :
return(mb_pdu_rd_req_make(buf, (mb_pdu_rd_req_t *)pdu));
case MODBUS_FC_WRITE_SINGLE_COIL :
return(mb_pdu_wr_single_make(buf, (mb_pdu_wr_single_t *)pdu));
case MODBUS_FC_WRITE_SINGLE_REGISTER :
return(mb_pdu_wr_single_make(buf, (mb_pdu_wr_single_t *)pdu));
case MODBUS_FC_READ_EXCEPTION_STATUS :
break;
case MODBUS_FC_WRITE_MULTIPLE_COILS :
return(mb_pdu_wr_req_make(buf, (mb_pdu_wr_req_t *)pdu));
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS :
return(mb_pdu_wr_req_make(buf, (mb_pdu_wr_req_t *)pdu));
case MODBUS_FC_REPORT_SLAVE_ID :
break;
case MODBUS_FC_MASK_WRITE_REGISTER :
return(mb_pdu_mask_wr_make(buf, (mb_pdu_mask_wr_t *)pdu));
case MODBUS_FC_WRITE_AND_READ_REGISTERS :
return(mb_pdu_wr_rd_req_make(buf, (mb_pdu_wr_rd_req_t *)pdu));
default:
break;
}
return(0);
}
static int mb_pdu_req_parse(const u8 *buf, int len, mb_pdu_t *pdu)//解析pdu请求帧, 成功返回帧长度, 失败返回-1
{
u8 fc = *buf;
switch(fc)
{
case MODBUS_FC_READ_COILS :
return(mb_pdu_rd_req_parse(buf, len, (mb_pdu_rd_req_t *)pdu));
case MODBUS_FC_READ_DISCRETE_INPUTS :
return(mb_pdu_rd_req_parse(buf, len, (mb_pdu_rd_req_t *)pdu));
case MODBUS_FC_READ_HOLDING_REGISTERS :
return(mb_pdu_rd_req_parse(buf, len, (mb_pdu_rd_req_t *)pdu));
case MODBUS_FC_READ_INPUT_REGISTERS :
return(mb_pdu_rd_req_parse(buf, len, (mb_pdu_rd_req_t *)pdu));
case MODBUS_FC_WRITE_SINGLE_COIL :
return(mb_pdu_wr_single_parse(buf, len, (mb_pdu_wr_single_t *)pdu));
case MODBUS_FC_WRITE_SINGLE_REGISTER :
return(mb_pdu_wr_single_parse(buf, len, (mb_pdu_wr_single_t *)pdu));
case MODBUS_FC_READ_EXCEPTION_STATUS :
break;
case MODBUS_FC_WRITE_MULTIPLE_COILS :
return(mb_pdu_wr_req_parse(buf, len, (mb_pdu_wr_req_t *)pdu));
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS :
return(mb_pdu_wr_req_parse(buf, len, (mb_pdu_wr_req_t *)pdu));
case MODBUS_FC_REPORT_SLAVE_ID :
break;
case MODBUS_FC_MASK_WRITE_REGISTER :
return(mb_pdu_mask_wr_parse(buf, len, (mb_pdu_mask_wr_t *)pdu));
case MODBUS_FC_WRITE_AND_READ_REGISTERS :
return(mb_pdu_wr_rd_req_parse(buf, len, (mb_pdu_wr_rd_req_t *)pdu));
default:
break;
}
return(-1);
}
static int mb_pdu_rsp_make(u8 *buf, const mb_pdu_t *pdu)//生成pdu响应帧, 返回帧长度, 失败返回0
{
if (MODBUS_FC_EXCEPT_CHK(pdu->fc))
{
return(mb_pdu_except_make(buf, (mb_pdu_except_t *)pdu));
}
switch(pdu->fc)
{
case MODBUS_FC_READ_COILS :
return(mb_pdu_rd_rsp_make(buf, (mb_pdu_rd_rsp_t *)pdu));
case MODBUS_FC_READ_DISCRETE_INPUTS :
return(mb_pdu_rd_rsp_make(buf, (mb_pdu_rd_rsp_t *)pdu));
case MODBUS_FC_READ_HOLDING_REGISTERS :
return(mb_pdu_rd_rsp_make(buf, (mb_pdu_rd_rsp_t *)pdu));
case MODBUS_FC_READ_INPUT_REGISTERS :
return(mb_pdu_rd_rsp_make(buf, (mb_pdu_rd_rsp_t *)pdu));
case MODBUS_FC_WRITE_SINGLE_COIL :
return(mb_pdu_wr_single_make(buf, (mb_pdu_wr_single_t *)pdu));
case MODBUS_FC_WRITE_SINGLE_REGISTER :
return(mb_pdu_wr_single_make(buf, (mb_pdu_wr_single_t *)pdu));
case MODBUS_FC_READ_EXCEPTION_STATUS :
break;
case MODBUS_FC_WRITE_MULTIPLE_COILS :
return(mb_pdu_wr_rsp_make(buf, (mb_pdu_wr_rsp_t *)pdu));
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS :
return(mb_pdu_wr_rsp_make(buf, (mb_pdu_wr_rsp_t *)pdu));
case MODBUS_FC_REPORT_SLAVE_ID :
break;
case MODBUS_FC_MASK_WRITE_REGISTER :
return(mb_pdu_mask_wr_make(buf, (mb_pdu_mask_wr_t *)pdu));
case MODBUS_FC_WRITE_AND_READ_REGISTERS :
return(mb_pdu_rd_rsp_make(buf, (mb_pdu_rd_rsp_t *)pdu));
default:
break;
}
return(0);
}
static int mb_pdu_rsp_parse(const u8 *buf, int len, mb_pdu_t *pdu)//解析pdu响应帧, 成功返回帧长度, 失败返回-1
{
u8 fc = *buf;
if (MODBUS_FC_EXCEPT_CHK(fc))
{
return(mb_pdu_except_parse(buf, len, (mb_pdu_except_t *)pdu));
}
switch(fc)
{
case MODBUS_FC_READ_COILS :
return(mb_pdu_rd_rsp_parse(buf, len, (mb_pdu_rd_rsp_t *)pdu));
case MODBUS_FC_READ_DISCRETE_INPUTS :
return(mb_pdu_rd_rsp_parse(buf, len, (mb_pdu_rd_rsp_t *)pdu));
case MODBUS_FC_READ_HOLDING_REGISTERS :
return(mb_pdu_rd_rsp_parse(buf, len, (mb_pdu_rd_rsp_t *)pdu));
case MODBUS_FC_READ_INPUT_REGISTERS :
return(mb_pdu_rd_rsp_parse(buf, len, (mb_pdu_rd_rsp_t *)pdu));
case MODBUS_FC_WRITE_SINGLE_COIL :
return(mb_pdu_wr_single_parse(buf, len, (mb_pdu_wr_single_t *)pdu));
case MODBUS_FC_WRITE_SINGLE_REGISTER :
return(mb_pdu_wr_single_parse(buf, len, (mb_pdu_wr_single_t *)pdu));
case MODBUS_FC_READ_EXCEPTION_STATUS :
break;
case MODBUS_FC_WRITE_MULTIPLE_COILS :
return(mb_pdu_wr_rsp_parse(buf, len, (mb_pdu_wr_rsp_t *)pdu));
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS :
return(mb_pdu_wr_rsp_parse(buf, len, (mb_pdu_wr_rsp_t *)pdu));
case MODBUS_FC_REPORT_SLAVE_ID :
break;
case MODBUS_FC_MASK_WRITE_REGISTER :
return(mb_pdu_mask_wr_parse(buf, len, (mb_pdu_mask_wr_t *)pdu));
case MODBUS_FC_WRITE_AND_READ_REGISTERS :
return(mb_pdu_rd_rsp_parse(buf, len, (mb_pdu_rd_rsp_t *)pdu));
default:
break;
}
return(-1);
}
int mb_pdu_make(u8 *buf, const mb_pdu_t *pdu, mb_pdu_type_t type)//生成pdu帧, 返回帧长度, 错误返回0
{
switch(type)
{
case MB_PDU_TYPE_REQ:
return(mb_pdu_req_make(buf, pdu));
case MB_PDU_TYPE_RSP:
return(mb_pdu_rsp_make(buf, pdu));
default:
break;
}
return(0);
}
int mb_pdu_parse(const u8 *buf, int len, mb_pdu_t *pdu, mb_pdu_type_t type)//解析pdu帧, 成功返回帧长度, 帧错误返回0, 功能码不支持返回-1
{
switch(type)
{
case MB_PDU_TYPE_REQ:
return(mb_pdu_req_parse(buf, len, pdu));
case MB_PDU_TYPE_RSP:
return(mb_pdu_rsp_parse(buf, len, pdu));
default:
break;
}
return(0);
}
+357
View File
@@ -0,0 +1,357 @@
/*
* modbus_port_linux.c
*
* Change Logs:
* Date Author Notes
* 2024-04-02 qiyongzhong first version
*/
#include <packages/qmodbus/inc/modbus_port.h>
#ifdef MB_USING_PORT_LINUX
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#define QLOG_TAG "modbus.port.linux"
#define QLOG_LVL QLOG_LVL_LOG //QLOG_LVL_INFO //
#include "qlog.h"
MB_WEAK long long mb_port_get_ms(void)//获取毫秒时间
{
long long ms;
struct timeval tv;
gettimeofday(&tv, NULL);
ms = tv.tv_sec;
ms = ms * 1000;
ms = ms + (tv.tv_usec / 1000);
return(ms);
}
MB_WEAK void mb_port_delay_ms(int tmo_ms)
{
usleep((long long)tmo_ms * 1000);
}
#ifdef MB_USING_RTU_BACKEND
static int mb_port_uart_config(int fd, int baudrate, int databit, int parity, int stopbit)//配置串口, 成功返回0, 失败返回-1
{
struct termios options;
//获取串口相关参数,该函数还可以测试配置是否正确,该串口是否可用等。
//若调用成功,函数返回值为0,若调用失败,函数返回值为1.
if( tcgetattr(fd, &options) != 0)
{
//zlog_error(g_zc, "uart(fd=%d) get attr fail.", fd);
return(-1);
}
//设置串口输入波特率和输出波特率
int speed = B115200;
switch(baudrate)
{
case 1200:
speed = B1200;
break;
case 2400:
speed = B2400;
break;
case 4800:
speed = B4800;
break;
case 9600:
speed = B9600;
break;
case 19200:
speed = B19200;
break;
case 38400:
speed = B38400;
break;
case 57600:
speed = B57600;
break;
case 115200:
speed = B115200;
break;
default:
break;
}
cfsetispeed(&options, speed);
cfsetospeed(&options, speed);
options.c_cflag |= CLOCAL;//修改控制模式,保证程序不会占用串口
options.c_cflag |= CREAD;//修改控制模式,使得能够从串口中读取输入数据
//options.c_cflag &= ~CRTSCTS;//不使用流控制
options.c_iflag = 0;
//options.c_iflag &= ~(IGNCR | ICRNL | INLCR);//不使用回车换行转换
//options.c_iflag &= ~(IXON | IXOFF | IXANY);//不使用软件流控制
//options.c_iflag |= IXON | IXOFF | IXANY;//使用软件流控制
options.c_cflag &= ~CSIZE;//屏蔽其他标志位
switch (databit)//设置数据位
{
case 5:
options.c_cflag |= CS5;
break;
case 6:
options.c_cflag |= CS6;
break;
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
options.c_cflag |= CS8;
break;
}
switch (parity)//设置校验位
{
case 0: //无奇偶校验位。
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
case 1://设置为奇校验
options.c_cflag |= (PARODD | PARENB);
options.c_iflag |= INPCK;
break;
case 2://设置为偶校验
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag |= INPCK;
break;
default://无奇偶校验位。
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
}
switch (stopbit)// 设置停止位
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
options.c_cflag &= ~CSTOPB;
break;
}
options.c_oflag &= ~OPOST;//关闭输出处理
options.c_lflag &= ~(ISIG | TCSADRAIN | ICANON | ECHO | ECHOE);//关闭特殊字符信号发送, 关闭规范输入, 关闭回显
//options.c_lflag &= ~(ISIG | ICANON);//关闭特殊字符信号发送, 关闭规范输入
//设置等待时间和最小接收字符
options.c_cc[VTIME] = 0; /* 读取一个字符等待1*(1/10)s */
options.c_cc[VMIN] = 0; /* 读取字符的最少个数为1 */
//如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读
//tcflush(fd, TCIFLUSH);
//激活配置 (将修改后的termios数据设置到串口中)
//opt : TCSANOW--立即生效, TCSADRAIN--发送完成后生效, TCSAFLUSH--发送完成后生效并清除输入缓冲
if (tcsetattr(fd, TCSADRAIN, &options) != 0)//发送完成后生效
{
LOG_E("uart set attr error!");
return (-1);
}
return (0);
}
MB_WEAK void * mb_port_rtu_open(const mb_backend_param_t *param)//打开, 成功返回实例指针或文件标识, 错误返回NULL
{
MB_ASSERT(param != NULL);
MB_ASSERT(param->rtu.dev != NULL);
char *path = param->rtu.dev;
int fd = open(path, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (fd == -1)
{
LOG_E("device (%s) open fail.", path);
return(NULL);
}
if(fcntl(fd, F_SETFL, 0) < 0)//恢复串口为阻塞状态
{
close(fd);
LOG_E("device (%s) fcntl fail.", path);
return(NULL);
}
if (mb_port_uart_config(fd, param->rtu.baudrate, 8, param->rtu.parity, 1) < 0)
{
close(fd);
LOG_E("device (%s) config fail.", path);
return(NULL);
}
LOG_D("device (%s, fd=%d) open suceess.", path, fd);
return((void *)fd);
}
MB_WEAK int mb_port_rtu_close(void *hinst)//关闭, 成功返回0, 错误返回-1
{
MB_ASSERT(hinst != NULL);
int fd = (int)hinst;
return(close(fd));
}
MB_WEAK int mb_port_rtu_read(void *hinst, u8 *buf, int bufsize)//接收数据, 返回接收到的数据长度, 0表示超时, 错误返回-1
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(buf != NULL);
int fd = (int)hinst;
int len = read(fd, buf, bufsize);
if (len < 0)
{
LOG_E("device (fd = %d) read error!", fd);
return(-1);
}
return(len);
}
MB_WEAK int mb_port_rtu_write(void *hinst, u8 *buf, int size)//发送数据, , 返回成功发送的数据长度, 错误返回-1
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(buf != NULL);
int fd = (int)hinst;
int len = write(fd, buf, size);
if (len <= 0)
{
LOG_E("device (fd = %d) write error!", fd);
return(-1);
}
return(len);
}
MB_WEAK int mb_port_rtu_flush(void *hinst)//清空接收缓存, 成功返回0, 错误返回-1
{
MB_ASSERT(hinst != NULL);
int fd = (int)hinst;
return(tcflush(fd, TCIFLUSH));
}
#endif
#if (defined(MB_USING_TCP_BACKEND) || defined(MB_USING_SOCK_BACKEND))
MB_WEAK void * mb_port_tcp_open(const mb_backend_param_t *param)//打开, 成功返回实例指针或文件标识, 错误返回NULL
{
MB_ASSERT(param != NULL);
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
LOG_E("socket create fail.");
return(NULL);
}
LOG_D("socket create success, fd = %d.", sock);
struct hostent *host = gethostbyname(param->tcp.host);
if (host == NULL)
{
close(sock);
LOG_E("host get error.");
return(NULL);
}
struct sockaddr_in srv_addr;
memset(&srv_addr, 0, sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(param->tcp.port);
srv_addr.sin_addr = *((struct in_addr *)host->h_addr);
if (connect(sock, (struct sockaddr *)&srv_addr, sizeof(struct sockaddr)) < 0)
{
close(sock);
LOG_E("socket connect fail.");
return(NULL);
}
return((void *)sock);
}
MB_WEAK int mb_port_tcp_close(void *hinst)//关闭, 成功返回0, 错误返回-1
{
MB_ASSERT(hinst != NULL);
int sock = (int)hinst;
return((close(sock) == 0) ? 0 : -1);
}
MB_WEAK int mb_port_tcp_read(void *hinst, u8 *buf, int bufsize)//接收数据, 返回接收到的数据长度, 0表示超时, 错误返回-1
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(buf != NULL);
int sock = (int)hinst;
int len = recv(sock, buf, bufsize, MSG_DONTWAIT);
if (len == 0)//socket已关闭
{
LOG_E("tcp read error, fd = %d", sock);
return(-1);
}
if (len < 0)//超时或其它错误
{
return(0);
}
return(len);
}
MB_WEAK int mb_port_tcp_write(void *hinst, u8 *buf, int size)//发送数据, , 返回成功发送的数据长度, 错误返回-1
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(buf != NULL);
int sock = (int)hinst;
int len = send(sock, buf, size, 0);
if (len <= 0)//socket已关闭
{
LOG_E("tcp write error, fd = %d", sock);
return(-1);
}
return(len);
}
MB_WEAK int mb_port_tcp_flush(void *hinst)//清空接收缓存, 成功返回0, 错误返回-1
{
MB_ASSERT(hinst != NULL);
u8 c;
int sock = (int)hinst;
while(1)
{
int len = recv(sock, &c, 1, MSG_DONTWAIT);
if (len == 0)//socket已关闭
{
return(-1);
}
if (len < 0)//超时或其它错误
{
break;
}
}
return(0);
}
#endif
#endif
+252
View File
@@ -0,0 +1,252 @@
/*
* modbus_port_rtt.c
*
* Change Logs:
* Date Author Notes
* 2024-04-02 qiyongzhong first version
*/
#include <packages/qmodbus/inc/modbus_port.h>
#ifdef MB_USING_PORT_RTT
#include <stdio.h>
#include <string.h>
#include "rtdevice.h"
#define DBG_TAG "modbus.port.rtt"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
MB_WEAK long long mb_port_get_ms(void)//获取毫秒时间
{
return(rt_tick_get_millisecond());
}
MB_WEAK void mb_port_delay_ms(int tmo_ms)
{
rt_thread_mdelay(tmo_ms);
}
#ifdef MB_USING_RTU_BACKEND
MB_WEAK void * mb_port_rtu_open(const mb_backend_param_t *param)//打开, 成功返回实例指针或文件标识, 错误返回NULL
{
MB_ASSERT(param != NULL);
MB_ASSERT(param->rtu.dev != NULL);
char *name = param->rtu.dev;
rt_device_t dev = rt_device_find(name);
if (dev == RT_NULL)
{
LOG_E("device (%s) not found.", name);
return(NULL);
}
struct serial_configure cfg = RT_SERIAL_CONFIG_DEFAULT;
cfg.baud_rate = param->rtu.baudrate;
cfg.parity = param->rtu.parity;
if (rt_device_control(dev, RT_DEVICE_CTRL_CONFIG, &cfg) < 0)
{
LOG_E("device (%s) config fail.", name);
return(NULL);
}
if ( rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX) < 0)
{
LOG_E("device (%s) open fail.", name);
return(NULL);
}
int pin = param->rtu.pin;
int lvl = param->rtu.lvl;
if (pin >= 0)
{
u32 ud = 0xABCD0000 + ((pin << 1) & 0xFFFF) + (lvl ? 1 : 0);
dev->user_data = (void *)ud;
rt_pin_mode(pin, PIN_MODE_OUTPUT);
rt_pin_write(pin, ! lvl);
}
LOG_D("device (%s) open suceess.", name);
return((void *)dev);
}
MB_WEAK int mb_port_rtu_close(void *hinst)//关闭, 成功返回0, 错误返回-1
{
MB_ASSERT(hinst != NULL);
rt_device_t dev = (rt_device_t)hinst;
return(rt_device_close(dev));
}
MB_WEAK int mb_port_rtu_read(void *hinst, u8 *buf, int bufsize)//接收数据, 返回接收到的数据长度, 0表示超时, 错误返回-1
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(buf != NULL);
rt_device_t dev = (rt_device_t)hinst;
int len = rt_device_read(dev, -1, buf, bufsize);
if (len < 0)
{
LOG_E("device read error.");
return(-1);
}
return(len);
}
MB_WEAK int mb_port_rtu_write(void *hinst, u8 *buf, int size)//发送数据, , 返回成功发送的数据长度, 错误返回-1
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(buf != NULL);
rt_device_t dev = (rt_device_t)hinst;
u32 ud = (u32)(dev->user_data);
int pin = ((ud & 0xFFFF0000) == 0xABCD0000) ? ((ud & 0xFFFF) >> 1) : -1;
int lvl = (ud & 0x01);
if (pin >= 0) rt_pin_write(pin, lvl);
int len = rt_device_write(dev, -1, buf, size);
if (pin >= 0) rt_pin_write(pin, ! lvl);
if (len < 0)
{
LOG_E("device read error.");
return(-1);
}
return(len);
}
MB_WEAK int mb_port_rtu_flush(void *hinst)//清空接收缓存, 成功返回0, 错误返回-1
{
MB_ASSERT(hinst != NULL);
u8 c;
rt_device_t dev = (rt_device_t)hinst;
while(1)
{
int len = rt_device_read(dev, -1, &c, 1);
if (len < 0)
{
return(-1);
}
if (len == 0)
{
break;
}
}
return(0);
}
#endif
#if (defined(MB_USING_TCP_BACKEND) || defined(MB_USING_SOCK_BACKEND))
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#include <unistd.h>
MB_WEAK void * mb_port_tcp_open(const mb_backend_param_t *param)//打开, 成功返回实例指针或文件标识, 错误返回NULL
{
MB_ASSERT(param != NULL);
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
LOG_E("socket create fail.");
return(NULL);
}
LOG_D("socket create success, fd = %d.", sock);
struct hostent *host = gethostbyname(param->tcp.host);
if (host == NULL)
{
closesocket(sock);
LOG_E("host get error.");
return(NULL);
}
struct sockaddr_in srv_addr;
memset(&srv_addr, 0, sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(param->tcp.port);
srv_addr.sin_addr = *((struct in_addr *)host->h_addr);
if (connect(sock, (struct sockaddr *)&srv_addr, sizeof(struct sockaddr)) < 0)
{
closesocket(sock);
LOG_E("socket connect fail.");
return(NULL);
}
return((void *)sock);
}
MB_WEAK int mb_port_tcp_close(void *hinst)//关闭, 成功返回0, 错误返回-1
{
MB_ASSERT(hinst != NULL);
int sock = (int)hinst;
return((closesocket(sock) == 0) ? 0 : -1);
}
MB_WEAK int mb_port_tcp_read(void *hinst, u8 *buf, int bufsize)//接收数据, 返回接收到的数据长度, 0表示超时, 错误返回-1
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(buf != NULL);
int sock = (int)hinst;
int len = recv(sock, buf, bufsize, MSG_DONTWAIT);
if (len == 0)//socket已关闭
{
LOG_E("TCP read error.");
return(-1);
}
if (len < 0)//超时或其它错误
{
return(0);
}
return(len);
}
MB_WEAK int mb_port_tcp_write(void *hinst, u8 *buf, int size)//发送数据, , 返回成功发送的数据长度, 错误返回-1
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(buf != NULL);
int sock = (int)hinst;
int len = send(sock, buf, size, 0);
if (len <= 0)//socket已关闭
{
LOG_E("TCP write error.");
return(-1);
}
return(len);
}
MB_WEAK int mb_port_tcp_flush(void *hinst)//清空接收缓存, 成功返回0, 错误返回-1
{
MB_ASSERT(hinst != NULL);
u8 c;
int sock = (int)hinst;
while(1)
{
int len = recv(sock, &c, 1, MSG_DONTWAIT);
if (len == 0)//socket已关闭
{
return(-1);
}
if (len < 0)//超时或其它错误
{
break;
}
}
return(0);
}
#endif
#endif
+51
View File
@@ -0,0 +1,51 @@
/*
* modbus_port_slave.c
*
* Change Logs:
* Date Author Notes
* 2024-04-02 qiyongzhong first version
*/
#include <packages/qmodbus/inc/modbus_port.h>
#ifdef MB_USING_SLAVE
MB_WEAK int mb_port_read_disc(u16 addr, u8 *pbit)//读离散量输入, 返回 : 0-成功, -2-地址错误
{
MB_ASSERT(pbit != NULL);
return(-2);
}
MB_WEAK int mb_port_read_coil(u16 addr, u8 *pbit)//读线圈, 返回 : 0-成功, -2-地址错误
{
MB_ASSERT(pbit != NULL);
return(-2);
}
MB_WEAK int mb_port_write_coil(u16 addr, u8 bit)//写线圈, 返回 : 0-成功, -2-地址错误, -4-设备故障
{
return(-2);
}
MB_WEAK int mb_port_read_input(u16 addr, u16 *preg)//读输入寄存器, 返回 : 0-成功, -2-地址错误
{
MB_ASSERT(preg != NULL);
return(-2);
}
MB_WEAK int mb_port_read_hold(u16 addr, u16 *preg)//读保持寄存器, 返回 : 0-成功, -2-地址错误
{
MB_ASSERT(preg != NULL);
return(-2);
}
MB_WEAK int mb_port_write_hold(u16 addr, u16 reg)//写保持寄存器, 返回 : 0-成功, -2-地址错误, -3-值非法, -4-设备故障
{
return(-2);
}
#endif
+56
View File
@@ -0,0 +1,56 @@
/*
* modbus_rtu.c
*
* Change Logs:
* Date Author Notes
* 2024-04-01 qiyongzhong first version
*/
#include <packages/qmodbus/inc/modbus_crc.h>
#include <packages/qmodbus/inc/modbus_cvt.h>
#include <packages/qmodbus/inc/modbus_rtu.h>
#ifdef MB_USING_RTU_PROTOCOL
int mb_rtu_frm_make(u8 *buf, const mb_rtu_frm_t *frm, mb_pdu_type_t type)//生成rtu帧, 返回帧长度
{
u8 *p = buf;
p += mb_cvt_u8_put(p, frm->saddr);
p += mb_pdu_make(p, &(frm->pdu), type);
u16 crc = mb_crc_cal(buf, (int)(p - buf));
*p++ = crc;
*p++ = (crc >> 8);
return((int)(p - buf));
}
int mb_rtu_frm_parse(const u8 *buf, int len, mb_rtu_frm_t *frm, mb_pdu_type_t type)//解析rtu帧, 返回pdu数据长度, 解析失败返回0, 功能码不支持返回-1
{
if (len < MB_RTU_FRM_MIN)
{
return(0);
}
frm->saddr = *buf;
int remain = len - (MB_RTU_SADDR_SIZE + MB_RTU_CRC_SIZE);
int pdu_len = mb_pdu_parse(buf + 1, remain, &(frm->pdu), type);
if (pdu_len <= 0)
{
return(pdu_len);
}
if (remain < pdu_len)
{
return(0);
}
int flen = pdu_len + (MB_RTU_SADDR_SIZE + MB_RTU_CRC_SIZE);
u16 cal_crc = mb_crc_cal(buf, flen);
if (cal_crc != 0)
{
return(0);
}
return(pdu_len);
}
#endif
+475
View File
@@ -0,0 +1,475 @@
/*
#include <packages/qmodbus/inc/modbus.h>
#include <packages/qmodbus/inc/modbus_cvt.h>
#include <packages/qmodbus/inc/modbus_port.h>
* modbus_slave.c
*
* Change Logs:
* Date Author Notes
* 2024-04-02 qiyongzhong first version
*/
#include <string.h>
#ifdef MB_USING_SLAVE
static void mb_slave_pdu_deal_read_coils(mb_inst_t *hinst, mb_pdu_t *pdu)
{
if ((hinst->cb == NULL) || (hinst->cb->read_coil == NULL))
{
pdu->exc.ec = MODBUS_EC_SLAVE_OR_SERVER_FAILURE;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
u16 addr = pdu->rd_req.addr;
int nb = pdu->rd_req.nb;
memset(hinst->datas, 0, sizeof(hinst->datas));
for (int i=0; i<nb; i++)
{
u8 bit;
int rst = hinst->cb->read_coil(addr + i, &bit);
if (rst < 0)
{
pdu->exc.ec = -rst;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
mb_bitmap_set(hinst->datas, i, bit);
}
pdu->rd_rsp.dlen = (nb + 7) / 8;
pdu->rd_rsp.pdata = hinst->datas;
}
static void mb_slave_pdu_deal_read_discs(mb_inst_t *hinst, mb_pdu_t *pdu)
{
if ((hinst->cb == NULL) || (hinst->cb->read_disc == NULL))
{
pdu->exc.ec = MODBUS_EC_SLAVE_OR_SERVER_FAILURE;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
u16 addr = pdu->rd_req.addr;
int nb = pdu->rd_req.nb;
memset(hinst->datas, 0, sizeof(hinst->datas));
for (int i=0; i<nb; i++)
{
u8 bit;
int rst = hinst->cb->read_disc(addr + i, &bit);
if (rst < 0)
{
pdu->exc.ec = -rst;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
mb_bitmap_set(hinst->datas, i, bit);
}
pdu->rd_rsp.dlen = (nb + 7) / 8;
pdu->rd_rsp.pdata = hinst->datas;
}
static void mb_slave_pdu_deal_read_holds(mb_inst_t *hinst, mb_pdu_t *pdu)
{
if ((hinst->cb == NULL) || (hinst->cb->read_hold == NULL))
{
pdu->exc.ec = MODBUS_EC_SLAVE_OR_SERVER_FAILURE;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
u16 addr = pdu->rd_req.addr;
int nb = pdu->rd_req.nb;
u8 *p = hinst->datas;
for (int i=0; i<nb; i++)
{
u16 val;
int rst = hinst->cb->read_hold(addr + i, &val);
if (rst < 0)
{
pdu->exc.ec = -rst;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
p += mb_cvt_u16_put(p, val);
}
pdu->rd_rsp.dlen = 2 * nb;
pdu->rd_rsp.pdata = hinst->datas;
}
static void mb_slave_pdu_deal_read_inputs(mb_inst_t *hinst, mb_pdu_t *pdu)
{
if ((hinst->cb == NULL) || (hinst->cb->read_input == NULL))
{
pdu->exc.ec = MODBUS_EC_SLAVE_OR_SERVER_FAILURE;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
u16 addr = pdu->rd_req.addr;
int nb = pdu->rd_req.nb;
u8 *p = hinst->datas;
for (int i=0; i<nb; i++)
{
u16 val;
int rst = hinst->cb->read_input(addr + i, &val);
if (rst < 0)
{
pdu->exc.ec = -rst;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
p += mb_cvt_u16_put(p, val);
}
pdu->rd_rsp.dlen = 2 * nb;
pdu->rd_rsp.pdata = hinst->datas;
}
static void mb_slave_pdu_deal_write_coil(mb_inst_t *hinst, mb_pdu_t *pdu)
{
if ((hinst->cb == NULL) || (hinst->cb->write_coil == NULL))
{
pdu->exc.ec = MODBUS_EC_SLAVE_OR_SERVER_FAILURE;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
u16 addr = pdu->wr_single.addr;
u16 val = pdu->wr_single.val;
if ((val != 0xFF00) && (val != 0x0000))
{
pdu->exc.ec = MODBUS_EC_ILLEGAL_DATA_VALUE;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
int rst = hinst->cb->write_coil(addr, (val ? 1 : 0));
if (rst < 0)
{
pdu->exc.ec = -rst;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
}
static void mb_slave_pdu_deal_write_reg(mb_inst_t *hinst, mb_pdu_t *pdu)
{
if ((hinst->cb == NULL) || (hinst->cb->write_hold == NULL))
{
pdu->exc.ec = MODBUS_EC_SLAVE_OR_SERVER_FAILURE;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
u16 addr = pdu->wr_single.addr;
u16 val = pdu->wr_single.val;
int rst = hinst->cb->write_hold(addr, val);
if (rst < 0)
{
pdu->exc.ec = -rst;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
}
static void mb_slave_pdu_deal_write_coils(mb_inst_t *hinst, mb_pdu_t *pdu)
{
if ((hinst->cb == NULL) || (hinst->cb->write_coil == NULL))
{
pdu->exc.ec = MODBUS_EC_SLAVE_OR_SERVER_FAILURE;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
u16 addr = pdu->wr_req.addr;
int nb = pdu->wr_req.nb;
u8 *pbits = pdu->wr_req.pdata;
for (int i=0; i<nb; i++)
{
u8 bit = mb_bitmap_get(pbits, i);
int rst = hinst->cb->write_coil(addr + i, bit);
if (rst < 0)
{
pdu->exc.ec = -rst;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
}
}
static void mb_slave_pdu_deal_write_regs(mb_inst_t *hinst, mb_pdu_t *pdu)
{
if ((hinst->cb == NULL) || (hinst->cb->write_hold == NULL))
{
pdu->exc.ec = MODBUS_EC_SLAVE_OR_SERVER_FAILURE;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
u16 addr = pdu->wr_req.addr;
int nb = pdu->wr_req.nb;
u8 *p = pdu->wr_req.pdata;
for (int i=0; i<nb; i++)
{
u16 val;
p += mb_cvt_u16_get(p, &val);
int rst = hinst->cb->write_hold(addr + i, val);
if (rst < 0)
{
pdu->exc.ec = -rst;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
}
}
static void mb_slave_pdu_deal_mask_write_reg(mb_inst_t *hinst, mb_pdu_t *pdu)
{
if ((hinst->cb == NULL) || (hinst->cb->read_hold == NULL) || (hinst->cb->write_hold == NULL))
{
pdu->exc.ec = MODBUS_EC_SLAVE_OR_SERVER_FAILURE;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
u16 addr = pdu->mask_wr.addr;
u16 val_and = pdu->mask_wr.val_and;
u16 val_or = pdu->mask_wr.val_or;
u16 val;
int rst = hinst->cb->read_hold(addr, &val);
if (rst < 0)
{
pdu->exc.ec = -rst;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
val = ((val & val_and) | (val_or & ~val_and));
rst = hinst->cb->write_hold(addr, val);
if (rst < 0)
{
pdu->exc.ec = -rst;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
}
static void mb_slave_pdu_deal_write_and_read_regs(mb_inst_t *hinst, mb_pdu_t *pdu)
{
if ((hinst->cb == NULL) || (hinst->cb->read_hold == NULL) || (hinst->cb->write_hold == NULL))
{
pdu->exc.ec = MODBUS_EC_SLAVE_OR_SERVER_FAILURE;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
u16 rd_addr = pdu->wr_rd_req.rd_addr;
int rd_nb = pdu->wr_rd_req.rd_nb;
u16 wr_addr = pdu->wr_rd_req.wr_addr;
int wr_nb = pdu->wr_rd_req.wr_nb;
u8 *p = pdu->wr_rd_req.pdata;
for (int i=0; i<wr_nb; i++)
{
u16 val;
p += mb_cvt_u16_get(p, &val);
int rst = hinst->cb->write_hold(wr_addr + i, val);
if (rst < 0)
{
pdu->exc.ec = -rst;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
}
p = hinst->datas;
for (int i=0; i<rd_nb; i++)
{
u16 val;
int rst = hinst->cb->read_hold(rd_addr + i, &val);
if (rst < 0)
{
pdu->exc.ec = -rst;
pdu->exc.fc = MODBUS_FC_EXCEPT_MAKE(pdu->exc.fc);
return;
}
p += mb_cvt_u16_put(p, val);
}
pdu->rd_rsp.dlen = rd_nb * 2;
pdu->rd_rsp.pdata = hinst->datas;
}
static void mb_slave_pdu_deal(mb_inst_t *hinst, mb_pdu_t *pdu)
{
switch(pdu->fc)
{
case MODBUS_FC_READ_COILS :
mb_slave_pdu_deal_read_coils(hinst, pdu);
break;
case MODBUS_FC_READ_DISCRETE_INPUTS :
mb_slave_pdu_deal_read_discs(hinst, pdu);
break;
case MODBUS_FC_READ_HOLDING_REGISTERS :
mb_slave_pdu_deal_read_holds(hinst, pdu);
break;
case MODBUS_FC_READ_INPUT_REGISTERS :
mb_slave_pdu_deal_read_inputs(hinst, pdu);
break;
case MODBUS_FC_WRITE_SINGLE_COIL :
mb_slave_pdu_deal_write_coil(hinst, pdu);
break;
case MODBUS_FC_WRITE_SINGLE_REGISTER :
mb_slave_pdu_deal_write_reg(hinst, pdu);
break;
case MODBUS_FC_READ_EXCEPTION_STATUS :
break;
case MODBUS_FC_WRITE_MULTIPLE_COILS :
mb_slave_pdu_deal_write_coils(hinst, pdu);
break;
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS :
mb_slave_pdu_deal_write_regs(hinst, pdu);
break;
case MODBUS_FC_REPORT_SLAVE_ID :
break;
case MODBUS_FC_MASK_WRITE_REGISTER :
mb_slave_pdu_deal_mask_write_reg(hinst, pdu);
break;
case MODBUS_FC_WRITE_AND_READ_REGISTERS :
mb_slave_pdu_deal_write_and_read_regs(hinst, pdu);
break;
default:
break;
}
}
#ifdef MB_USING_RTU_PROTOCOL
static void mb_slave_recv_deal_rtu(mb_inst_t *hinst, u8 *buf, int len)
{
mb_rtu_frm_t frm;
int pdu_len = mb_rtu_frm_parse(buf, len, &frm, MB_PDU_TYPE_REQ);
if (pdu_len == 0)//帧错误, 不处理
{
return;
}
#ifdef MB_USING_ADDR_CHK
if (frm.saddr != hinst->saddr)//地址不同, 不处理
{
return;
}
#endif
if (pdu_len < 0)//功能码不支持, 响应异常帧
{
frm.pdu.exc.ec = MODBUS_EC_ILLEGAL_FUNCTION;
frm.pdu.exc.fc = MODBUS_FC_EXCEPT_MAKE(frm.pdu.exc.fc);
}
else
{
mb_slave_pdu_deal(hinst, &(frm.pdu));
}
int flen = mb_rtu_frm_make(hinst->buf, &frm, MB_PDU_TYPE_RSP);
mb_send(hinst, hinst->buf, flen);
}
#endif
#ifdef MB_USING_TCP_PROTOCOL
static void mb_slave_recv_deal_tcp(mb_inst_t *hinst, u8 *buf, int len)
{
mb_tcp_frm_t frm;
int pdu_len = mb_tcp_frm_parse(buf, len, &frm, MB_PDU_TYPE_REQ);
if (pdu_len == 0)//帧错误, 不处理
{
return;
}
#ifdef MB_USING_ADDR_CHK
if ((frm.mbap.did != 0xFF) && (frm.mbap.did != hinst->saddr))//使用地址且地址不同, 不处理
{
return;
}
#endif
#ifdef MB_USING_MBAP_CHK
if (frm.mbap.pid != MB_TCP_MBAP_PID)//协议标识错误, 不处理
{
return;
}
#endif
if (pdu_len < 0)//功能码不支持, 响应异常帧
{
frm.pdu.exc.ec = MODBUS_EC_ILLEGAL_FUNCTION;
frm.pdu.exc.fc = MODBUS_FC_EXCEPT_MAKE(frm.pdu.exc.fc);
}
else
{
mb_slave_pdu_deal(hinst, &(frm.pdu));
}
int flen = mb_tcp_frm_make(hinst->buf, &frm, MB_PDU_TYPE_RSP);
mb_send(hinst, hinst->buf, flen);
}
#endif
static void mb_slave_recv_deal(mb_inst_t *hinst, u8 *buf, int len)
{
switch(hinst->prot)
{
#ifdef MB_USING_RTU_PROTOCOL
case MB_PROT_RTU :
mb_slave_recv_deal_rtu(hinst, buf, len);
break;
#endif
#ifdef MB_USING_TCP_PROTOCOL
case MB_PROT_TCP :
mb_slave_recv_deal_tcp(hinst, buf, len);
break;
#endif
default:
break;
}
}
const mb_cb_table_t mb_cb_table = {
.read_disc = mb_port_read_disc, //读离散量输入
.read_coil = mb_port_read_coil, //读线圈
.write_coil = mb_port_write_coil, //写线圈
.read_input = mb_port_read_input, //读输入寄存器
.read_hold = mb_port_read_hold, //读保持寄存器
.write_hold = mb_port_write_hold, //写保持寄存器
};
//修改从机回调函数表, 默认使用modbus_port中接口函数做回调函数
void mb_set_cb_table(mb_inst_t *hinst, const mb_cb_table_t *cb)
{
MB_ASSERT(hinst != NULL);
MB_ASSERT(cb != NULL);
hinst->cb = (mb_cb_table_t *)cb;
}
//从机状态机处理, 在线程中循环调用即可
void mb_slave_fsm(mb_inst_t *hinst)
{
MB_ASSERT(hinst != NULL);
if (mb_connect(hinst) < 0)//连接失败, 延时返回
{
mb_port_delay_ms(1000);
return;
}
int rlen = mb_recv(hinst, hinst->buf, sizeof(hinst->buf));
if (rlen <= 0)
{
return;
}
mb_slave_recv_deal(hinst, hinst->buf, rlen);
}
#endif
+56
View File
@@ -0,0 +1,56 @@
/*
* modbus_tcp.c
*
* Change Logs:
* Date Author Notes
* 2024-04-01 qiyongzhong first version
*/
#include <packages/qmodbus/inc/modbus_cvt.h>
#include <packages/qmodbus/inc/modbus_tcp.h>
#ifdef MB_USING_TCP_PROTOCOL
int mb_tcp_frm_make(u8 *buf, const mb_tcp_frm_t *frm, mb_pdu_type_t type)//生成tcp帧, 返回帧长度
{
int pdu_len = mb_pdu_make(buf + MB_TCP_MBAP_SIZE, &(frm->pdu), type);
u8 *p = buf;
p += mb_cvt_u16_put(p, frm->mbap.tid);
p += mb_cvt_u16_put(p, frm->mbap.pid);
p += mb_cvt_u16_put(p, pdu_len + 1);
p += mb_cvt_u8_put(p, frm->mbap.did);
p += pdu_len;
return((int)(p - buf));
}
int mb_tcp_frm_parse(const u8 *buf, int len, mb_tcp_frm_t *frm, mb_pdu_type_t type)//解析tcp帧, 返回pdu数据长度, 解析失败返回0, 功能码不支持返回-1
{
if (len < MB_TCP_FRM_MIN)
{
return(0);
}
u8 *p = (u8 *)buf;
p += mb_cvt_u16_get(p, &(frm->mbap.tid));
p += mb_cvt_u16_get(p, &(frm->mbap.pid));
p += mb_cvt_u16_get(p, &(frm->mbap.dlen));
p += mb_cvt_u8_get(p, &(frm->mbap.did));
int remain = len - (int)(p - buf);
int pdu_len = mb_pdu_parse(p, remain, &(frm->pdu), type);
if (pdu_len <= 0)
{
return(pdu_len);
}
if (remain < pdu_len)
{
return(0);
}
return(pdu_len);
}
#endif