diff --git a/app/include/better_log.h b/app/include/better_log.h index 98b30e8..13e7311 100755 --- a/app/include/better_log.h +++ b/app/include/better_log.h @@ -91,6 +91,7 @@ typedef enum LOG_STORAGE, LOG_DEBUG, LOG_UPGRADE, + LOG_MODBUS, LOG_MAX } LOG_MODULE_E; diff --git a/app/include/dbg.h b/app/include/dbg.h index af39bfc..efad35c 100755 --- a/app/include/dbg.h +++ b/app/include/dbg.h @@ -68,6 +68,9 @@ typedef enum DBG_M_PD_UPGRADE, DBG_M_PD_HF, DBG_M_PD_HF_ERR, + DBG_M_SERIAL, + DBG_M_PD_MODBUS, + DBG_M_PD_MODBUS_ERR, DBG_M_COUNT } DBG_MODULE_E; diff --git a/app/include/hwgpio.h b/app/include/hwgpio.h old mode 100644 new mode 100755 index 9847498..7d9dc19 --- a/app/include/hwgpio.h +++ b/app/include/hwgpio.h @@ -44,6 +44,7 @@ #define GPIO_DIR_OUT 2 #define GPIO_WATCHDONG 915 +#define GPIO_485_BUS 154 // GPIO4_D2 (4*32+3*8+2) /* Exported types ------------------------------------------------------------*/ /* 记录每个打开的gpio信息 */ @@ -57,8 +58,10 @@ typedef struct } gpio_node_t; /* Exported macro ------------------------------------------------------------*/ +#define GPIO_485BUS(_v_) gpio_val_set(gpio_485bus_idx, _v_) /* Extern global variables ---------------------------------------------------*/ +extern int32_t gpio_485bus_idx; /* Extern functions ----------------------------------------------------------*/ extern int32_t gpio_val_set(uint16_t gpio, uint8_t value); diff --git a/app/include/pd_modbus.h b/app/include/pd_modbus.h new file mode 100755 index 0000000..832c3ca --- /dev/null +++ b/app/include/pd_modbus.h @@ -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 diff --git a/app/include/serial.h b/app/include/serial.h new file mode 100755 index 0000000..4b3bbe5 --- /dev/null +++ b/app/include/serial.h @@ -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 diff --git a/app/lib/a_process/pd_main.c b/app/lib/a_process/pd_main.c index 6877c90..fe35d8b 100755 --- a/app/lib/a_process/pd_main.c +++ b/app/lib/a_process/pd_main.c @@ -53,6 +53,7 @@ #include "pd_main.h" #include "pd_dau.h" #include "pd_dbg.h" +#include "pd_modbus.h" /* Private typedef -----------------------------------------------------------*/ @@ -636,6 +637,7 @@ int32_t pd_main_after(void) rv |= dau_handle_init_after(); rv |= csg_handle_init_after(); rv |= debug_handle_init_after(); + rv |= modbus_handle_init_after(); rv |= _pd_broadcast_init(); return rv; diff --git a/app/lib/a_process/pd_modbus.c b/app/lib/a_process/pd_modbus.c new file mode 100755 index 0000000..bccf3a1 --- /dev/null +++ b/app/lib/a_process/pd_modbus.c @@ -0,0 +1,163 @@ +/* Includes ------------------------------------------------------------------*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef CFG_DEV_TYPE_LAND_PD +/* 标准C库头文件. */ +#include + +/* 用户代码头文件. */ +#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_id(1字节) + 后续PDU(5字节:功能码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, ¶m); + return E_NONE; +} + +#endif + diff --git a/app/lib/m_management/better_log.c b/app/lib/m_management/better_log.c index 6285173..0490895 100755 --- a/app/lib/m_management/better_log.c +++ b/app/lib/m_management/better_log.c @@ -88,6 +88,7 @@ static const log_module_t log_module_names[] = {LOG_STORAGE, "STORAGE"}, {LOG_DEBUG, "DEBUG"}, {LOG_UPGRADE, "UPGRADE"}, + {LOG_MODBUS, "MODBUS"}, {-1, NULL} }; diff --git a/app/lib/m_management/dbg.c b/app/lib/m_management/dbg.c index 0dc83bf..e477dc3 100755 --- a/app/lib/m_management/dbg.c +++ b/app/lib/m_management/dbg.c @@ -72,6 +72,9 @@ dbg_module_t _dbg_module[DBG_M_COUNT] = {DBG_M_PD_UPGRADE, FALSE, "upgrade"}, {DBG_M_PD_HF, FALSE, "pd_hf"}, {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 -----------------------------------------------*/ diff --git a/app/lib/z_hardware/hwgpio.c b/app/lib/z_hardware/hwgpio.c old mode 100644 new mode 100755 index 2a3906e..c0a3f9b --- a/app/lib/z_hardware/hwgpio.c +++ b/app/lib/z_hardware/hwgpio.c @@ -55,6 +55,8 @@ /* Private variables ---------------------------------------------------------*/ static array_t *gpios = NULL; +int32_t gpio_485bus_idx; + /* Private function prototypes -----------------------------------------------*/ /* Internal functions --------------------------------------------------------*/ @@ -327,6 +329,13 @@ int32_t gpio_export(uint16_t gpio) int32_t gpio_init(void) { 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; } diff --git a/app/lib/z_hardware/serial.c b/app/lib/z_hardware/serial.c new file mode 100755 index 0000000..99853e6 --- /dev/null +++ b/app/lib/z_hardware/serial.c @@ -0,0 +1,288 @@ +/* Includes ------------------------------------------------------------------*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* 标准C库头文件. */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* 用户代码头文件. */ +#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); + } +} + +