ADD 增加modbus协议;

main
wangbo 2 months ago
parent 4a304f38e4
commit e23e448bd4

@ -91,6 +91,7 @@ typedef enum
LOG_STORAGE, LOG_STORAGE,
LOG_DEBUG, LOG_DEBUG,
LOG_UPGRADE, LOG_UPGRADE,
LOG_MODBUS,
LOG_MAX LOG_MAX
} LOG_MODULE_E; } LOG_MODULE_E;

@ -68,6 +68,9 @@ typedef enum
DBG_M_PD_UPGRADE, DBG_M_PD_UPGRADE,
DBG_M_PD_HF, DBG_M_PD_HF,
DBG_M_PD_HF_ERR, DBG_M_PD_HF_ERR,
DBG_M_SERIAL,
DBG_M_PD_MODBUS,
DBG_M_PD_MODBUS_ERR,
DBG_M_COUNT DBG_M_COUNT
} DBG_MODULE_E; } DBG_MODULE_E;

@ -44,6 +44,7 @@
#define GPIO_DIR_OUT 2 #define GPIO_DIR_OUT 2
#define GPIO_WATCHDONG 915 #define GPIO_WATCHDONG 915
#define GPIO_485_BUS 154 // GPIO4_D2 (4*32+3*8+2)
/* Exported types ------------------------------------------------------------*/ /* Exported types ------------------------------------------------------------*/
/* 记录每个打开的gpio信息 */ /* 记录每个打开的gpio信息 */
@ -57,8 +58,10 @@ typedef struct
} gpio_node_t; } gpio_node_t;
/* Exported macro ------------------------------------------------------------*/ /* Exported macro ------------------------------------------------------------*/
#define GPIO_485BUS(_v_) gpio_val_set(gpio_485bus_idx, _v_)
/* Extern global variables ---------------------------------------------------*/ /* Extern global variables ---------------------------------------------------*/
extern int32_t gpio_485bus_idx;
/* Extern functions ----------------------------------------------------------*/ /* Extern functions ----------------------------------------------------------*/
extern int32_t gpio_val_set(uint16_t gpio, uint8_t value); extern int32_t gpio_val_set(uint16_t gpio, uint8_t value);

@ -0,0 +1,49 @@
#ifndef __PD_MODBUS_H__
#define __PD_MODBUS_H__
#ifdef CFG_DEV_TYPE_LAND_PD
#define WRITE 1
#define READ 0
#define MODBUS_IR_CURRENT_ADDR 0x0 // 铁芯
#define MODBUS_IR_CURRENT_LEN 2
#define MODBUS_DC_CURRENT_ADDR 0x34 // 直流偏磁
#define MODBUS_DC_CURRENT_LEN 2
#define MODBUS_UNIT_IR 0x01
#define MODBUS_CURRENT_LEN 4
#define MODBUS_ADDR_ALARM 0x32
#define MODBUS_ALARM_LEN 2
// 定义Modbus TCP MBAP头
//#pragma pack(push, 1)
typedef struct
{
uint16_t transaction_id; // 事务处理标识
uint16_t protocol_id; // 协议标识
uint16_t length; // 数据长度
uint8_t unit_id; // 设备地址
uint8_t function_code; // 功能码
} modbus_tcp_t;
//#pragma pack(pop)
typedef struct
{
uint8_t function;
uint16_t address;
uint16_t length;
} pdu_t;
typedef struct
{
int fd;
uint8_t txbuf[512];
uint8_t rxbuf[512];
}modbus_t;
extern int32_t modbus_handle_init_after(void);
#endif
#endif

@ -0,0 +1,33 @@
#ifndef __SERIAL_H__
#define __SERIAL_H__
/* Includes ------------------------------------------------------------------*/
/* Define --------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
typedef struct
{
char tty[20]; //tty: 0, 1, 2, 3, 4, 5, 6, 7
unsigned int baudrate; //baudrate
unsigned char prompt; //prompt after reciving data
unsigned char databit; //data bits, 5, 6, 7, 8
unsigned char debug; //debug mode, 0: none, 1: debug
unsigned char echo; //echo mode, 0: none, 1: echo
unsigned char fctl; //flow control, 0: none, 1: hardware, 2: software
unsigned char parity; //parity 0: none, 1: odd, 2: even
unsigned char stopbit; //stop bits, 1, 2
unsigned char reserved;
} serial_attr_t;
/* Exported macro ------------------------------------------------------------*/
/* Extern global variables ---------------------------------------------------*/
/* Extern functions ----------------------------------------------------------*/
extern int serial_open(const char * devname, int baudrate);
extern int serial_read(int fd, unsigned char * data, int len);
extern int serial_write(int fd, unsigned char * data, int len);
extern void serial_close(int fd);
#endif

@ -53,6 +53,7 @@
#include "pd_main.h" #include "pd_main.h"
#include "pd_dau.h" #include "pd_dau.h"
#include "pd_dbg.h" #include "pd_dbg.h"
#include "pd_modbus.h"
/* Private typedef -----------------------------------------------------------*/ /* Private typedef -----------------------------------------------------------*/
@ -636,6 +637,7 @@ int32_t pd_main_after(void)
rv |= dau_handle_init_after(); rv |= dau_handle_init_after();
rv |= csg_handle_init_after(); rv |= csg_handle_init_after();
rv |= debug_handle_init_after(); rv |= debug_handle_init_after();
rv |= modbus_handle_init_after();
rv |= _pd_broadcast_init(); rv |= _pd_broadcast_init();
return rv; return rv;

@ -0,0 +1,163 @@
/* Includes ------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef CFG_DEV_TYPE_LAND_PD
/* 标准C库头文件. */
#include <arpa/inet.h>
/* 用户代码头文件. */
#include "hwgpio.h"
#include "serial.h"
#include "pd_modbus.h"
/* Private variables ---------------------------------------------------------*/
modbus_t modbus;
int32_t _modbus_tcp_transaction(uint16_t transaction_id, uint8_t unit_id,
uint16_t start_addr, uint16_t data_num)
{
int txlen = 0;
int rxlen = 0;
modbus_tcp_t *frame = (modbus_tcp_t *)modbus.txbuf;
uint8_t *pdata = NULL;
uint8_t datalen = 0;
frame->transaction_id = htons(transaction_id);
frame->protocol_id = htons(0); // Modbus
// 长度unit_id1字节 + 后续PDU5字节功能码1 + 起始地址2 + 数量2
frame->length = htons(6);
frame->unit_id = unit_id;
// PDU
frame->function_code = 0x03;
pdata = modbus.txbuf + sizeof(modbus_tcp_t);
pdata[datalen++] = (start_addr >> 8) & 0xFF; // 起始地址高字节
pdata[datalen++] = start_addr & 0xFF; // 起始地址低字节
pdata[datalen++] = (data_num >> 8) & 0xFF; // 数据数量高字节
pdata[datalen++] = data_num & 0xFF; // 数据数量低字节
txlen = datalen + sizeof(modbus_tcp_t);
// 发送请求帧
GPIO_485BUS(WRITE);
if (serial_write(modbus.fd, modbus.txbuf, txlen) < 0)
{
DBG(DBG_M_PD_MODBUS_ERR, "Modbus write error\r\n");
return E_ERROR;
}
DBG(DBG_M_PD_MODBUS_ERR, "Modbus write len = %d\r\n", txlen);
buf_print((char *)modbus.txbuf, txlen);
// 等待传输完成
usleep(13000); // 13000
GPIO_485BUS(READ);
rxlen = serial_read(modbus.fd, modbus.rxbuf, sizeof(modbus.rxbuf));
if (rxlen > 0)
{
DBG(DBG_M_PD_MODBUS_ERR, "Modbus read len = %d\r\n", rxlen);
buf_print((char *)modbus.rxbuf, rxlen);
}
return E_NONE;
}
int32_t _modbus_rtu_transaction(void)
{
int sndlen = 0;
int rcvlen = 0;
uint8_t *ptxbuf = modbus.txbuf;
ptxbuf[sndlen++] = 0x05;
ptxbuf[sndlen++] = 0x03;
ptxbuf[sndlen++] = 0x00;
ptxbuf[sndlen++] = 0x34;
ptxbuf[sndlen++] = 0x00;
ptxbuf[sndlen++] = 0x02;
ptxbuf[sndlen++] = 0x84;
ptxbuf[sndlen++] = 0x41;
// 发送请求帧
GPIO_485BUS(WRITE);
if (serial_write(modbus.fd, ptxbuf, sndlen) < 0)
{
DBG(DBG_M_PD_MODBUS_ERR, "Modbus write error\r\n");
return E_ERROR;
}
usleep(10000);
GPIO_485BUS(READ);
rcvlen = serial_read(modbus.fd, modbus.rxbuf, sizeof(modbus.rxbuf));
if (rcvlen > 0)
{
DBG(DBG_M_PD_MODBUS_ERR, "Modbus read len = %d\r\n", rcvlen);
buf_print((char *)modbus.rxbuf, rcvlen);
}
return E_NONE;
}
void *_modbus_send_handle()
{
while (1)
{
#if 0
for (int unit = 1; unit <= 6; unit++)
{
if (_modbus_tcp_transaction(0, unit, MODBUS_ADDR_CURRENT, MODBUS_CURRENT_LEN) > 0)
{
}
if (_modbus_tcp_transaction(0, unit, MODBUS_ADDR_CURRENT, MODBUS_CURRENT_LEN) > 0)
{
}
}
#else
//_modbus_rtu_transaction();
_modbus_tcp_transaction(5, MODBUS_UNIT_IR, MODBUS_IR_CURRENT_ADDR, MODBUS_IR_CURRENT_LEN);
#endif
sleep(2);
}
if (modbus.fd > 0)
{
close(modbus.fd);
modbus.fd = -1;
}
}
int32_t modbus_handle_init(void)
{
memset(&modbus, 0, sizeof(modbus));
modbus.fd = -1;
return E_NONE;
}
int32_t modbus_handle_init_after(void)
{
int baud_rate = 9600;
thread_param_t param = {0};
// 初始化串口
int fd = serial_open("/dev/ttyS0", baud_rate);
if (fd < 0)
{
DBG(DBG_M_PD_MODBUS_ERR, "Failed to initialize serial port\n");
return E_ERROR;
}
modbus.fd = fd;
DBG(DBG_M_PD_MODBUS, "fd=%d\n", modbus.fd);
param.arg = NULL;
param.priority = 80;
param.log_module = LOG_MODBUS;
snprintf(param.thread_name, THREAD_NAME_LEN, "MODBUS_SEND");
create_thread(_modbus_send_handle, &param);
return E_NONE;
}
#endif

@ -88,6 +88,7 @@ static const log_module_t log_module_names[] =
{LOG_STORAGE, "STORAGE"}, {LOG_STORAGE, "STORAGE"},
{LOG_DEBUG, "DEBUG"}, {LOG_DEBUG, "DEBUG"},
{LOG_UPGRADE, "UPGRADE"}, {LOG_UPGRADE, "UPGRADE"},
{LOG_MODBUS, "MODBUS"},
{-1, NULL} {-1, NULL}
}; };

@ -72,6 +72,9 @@ dbg_module_t _dbg_module[DBG_M_COUNT] =
{DBG_M_PD_UPGRADE, FALSE, "upgrade"}, {DBG_M_PD_UPGRADE, FALSE, "upgrade"},
{DBG_M_PD_HF, FALSE, "pd_hf"}, {DBG_M_PD_HF, FALSE, "pd_hf"},
{DBG_M_PD_HF_ERR, TRUE, "pd_hf_err"}, {DBG_M_PD_HF_ERR, TRUE, "pd_hf_err"},
{DBG_M_SERIAL, TRUE, "serial"},
{DBG_M_PD_MODBUS, TRUE, "pd_modbus"},
{DBG_M_PD_MODBUS_ERR, TRUE, "pd_modbus_err"},
}; };
/* Private function prototypes -----------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/

@ -55,6 +55,8 @@
/* Private variables ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/
static array_t *gpios = NULL; static array_t *gpios = NULL;
int32_t gpio_485bus_idx;
/* Private function prototypes -----------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/
/* Internal functions --------------------------------------------------------*/ /* Internal functions --------------------------------------------------------*/
@ -327,6 +329,13 @@ int32_t gpio_export(uint16_t gpio)
int32_t gpio_init(void) int32_t gpio_init(void)
{ {
gpios = array_init(ARRAY_MIN_SIZE, MTYPE_GPIO); gpios = array_init(ARRAY_MIN_SIZE, MTYPE_GPIO);
gpio_485bus_idx = gpio_export(GPIO_485_BUS);
if (gpio_485bus_idx < 0)
{
DBG(DBG_M_GPIO, "ERROR return %d!\r\n", gpio_485bus_idx);
return E_BAD_PARAM;
}
LD_E_RETURN(DBG_M_GPIO, gpio_dir_set(gpio_485bus_idx, GPIO_DIR_OUT));
return E_NONE; return E_NONE;
} }

@ -0,0 +1,288 @@
/* Includes ------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* 标准C库头文件. */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
/* 用户代码头文件. */
#include "serial.h"
int serial_band_convert(unsigned int baudrate)
{
switch (baudrate)
{
case 2400:
return B2400;
case 4800:
return B4800;
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
case 921600:
return B921600;
case 1152000:
return B1152000;
default:
return B115200;
}
}
int serial_attr_set(int fd, serial_attr_t * attr)
{
unsigned char databit = 0;
unsigned char stopbit = 0;
unsigned char parity = 0;
unsigned char fctl = 0;
int ret = -1;
unsigned int baudrate = 0;
struct termios termios_old;
struct termios termios_new;
memset(&termios_old, 0, sizeof(termios_old));
memset(&termios_new, 0, sizeof(termios_new));
cfmakeraw(&termios_new);
if (tcgetattr(fd, &termios_old) != 0)
{
DBG(DBG_M_SERIAL, "Setup Serial!\r\n");
return ret;
}
//baudrates
baudrate = serial_band_convert(attr->baudrate);
cfsetispeed(&termios_new, baudrate);
cfsetospeed(&termios_new, baudrate);
termios_new.c_cflag |= CLOCAL;
termios_new.c_cflag |= CREAD;
//flow control
fctl = attr-> fctl;
switch (fctl)
{
case 0:
termios_new.c_cflag &= ~CRTSCTS; //no flow control
break;
case 1:
termios_new.c_cflag |= CRTSCTS; //hardware flow control
break;
case 2:
termios_new.c_iflag |= IXON | IXOFF | IXANY; //software flow control
break;
}
//data bits
termios_new.c_cflag &= ~CSIZE; //控制模式,屏蔽字符大小位
databit = attr->databit;
switch (databit)
{
case 5:
termios_new.c_cflag |= CS5;
break;
case 6:
termios_new.c_cflag |= CS6;
break;
case 7:
termios_new.c_cflag |= CS7;
break;
case 8:
termios_new.c_cflag |= CS8;
break;
default:
termios_new.c_cflag |= CS8;
break;
}
//parity check
parity = attr->parity;
switch (parity)
{
case 0: //no parity check
termios_new.c_cflag &= ~PARENB;
break;
case 1: //odd check
termios_new.c_cflag |= PARENB;
termios_new.c_cflag &= ~PARODD;
break;
case 2: //even check
termios_new.c_cflag |= PARENB;
termios_new.c_cflag |= PARODD;
break;
}
//stop bits
stopbit = attr->stopbit;
if (stopbit == 2)
{
termios_new.c_cflag |= CSTOPB;
}
else if (stopbit == 1)
{
termios_new.c_cflag &= ~CSTOPB;
}
//other attributions default
termios_new.c_oflag &= ~OPOST;
termios_new.c_cc[VMIN] = 1;
termios_new.c_cc[VTIME] = 1;
tcflush(fd, TCIFLUSH);
ret = tcsetattr(fd, TCSANOW, &termios_new);
return ret;
}
int serial_open(const char * devname, int baudrate)
{
int fd;
serial_attr_t attr;
fd = open(devname, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0)
{
DBG(DBG_M_SERIAL, "Open SerialPort(%s) failed[error = %d, %s]!!!!!!!\r\n",
devname, errno, strerror(errno));
return E_SYS_CALL;
}
strcpy(attr.tty, devname);
attr.baudrate = baudrate;
serial_attr_set(fd, &attr);
DBG(DBG_M_SERIAL, "Open SerialPort(%s:%d) port success!!!\r\n", devname, baudrate);
return fd;
}
int serial_read(int fd, unsigned char * data, int len)
{
int ret = -1;
fd_set fs_read;
int maxfd = -1;
if (fd < 0 || data == NULL || len <= 0)
{
DBG(DBG_M_SERIAL, "Param Error, fd = %d or NULL == data or len <= 0.\r\n", fd);
return E_ERROR;
}
FD_ZERO(&fs_read);
FD_SET(fd, &fs_read);
maxfd = fd + 1;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1000 * 1000;
ret = select(maxfd, &fs_read, NULL, NULL, &tv);
if (ret < 0)
{
DBG(DBG_M_SERIAL, "select error[%d, %s]!!!\r\n", errno, strerror(errno));
return E_SYS_CALL;
}
if (ret == 0)
{
DBG(DBG_M_SERIAL, "Timeout......\r\n");
return E_TIMEOUT;
}
ret = read(fd, data, len);
if (ret < 0)
{
DBG(DBG_M_SERIAL, "read error[%d, %s]\r\n", errno, strerror(errno));
return E_SYS_CALL;
}
return ret;
}
int serial_write(int fd, unsigned char * data, int len)
{
if (fd < 0 || NULL == data || len <= 0)
{
DBG(DBG_M_SERIAL, "Param Error, fd = %d or NULL == data or len = %d.\r\n", fd, len);
return E_BAD_PARAM;
}
fd_set fs_write;
FD_ZERO(&fs_write);
FD_SET(fd, &fs_write);
int maxfd = fd + 1;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1000 * 1000;
int ret = select(maxfd, NULL, &fs_write, NULL, &tv);
if (ret < 0)
{
DBG(DBG_M_SERIAL, "select Error[errno = %d, %s]\r\n", errno, strerror(errno));
return E_SYS_CALL;
}
else if (ret == 0)
{
DBG(DBG_M_SERIAL, "Timeout!\r\n");
return E_TIMEOUT;
}
if (FD_ISSET(fd, &fs_write))
{
int pos = 0;
while (len > 0)
{
ret = write(fd, data + pos, len);
if (ret < 0)
{
DBG(DBG_M_SERIAL, "write com[fd = %d] error[errno = %d, %s]\r\n", fd, errno, strerror(errno));
return E_SYS_CALL;
}
len -= ret;
pos += ret;
}
}
return len;
}
void serial_close(int fd)
{
if (fd > 0)
{
close(fd);
}
}
Loading…
Cancel
Save