| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- /*************************************************
- Copyright (c) 2019
- All rights reserved.
- File name: dlt645_port.c
- Description: DLT645 移植&使用例程文件
- History:
- 1. Version:
- Date: 2019-09-19
- Author: wangjunjie
- Modify:
- *************************************************/
- #include <stdio.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include "dlt645_private.h"
- #include <unistd.h>
- #include <termios.h>
- #include "serial_linux.h"
- //DL/T 645硬件拓展结构体
- typedef struct
- {
- int fd;
- uint8_t is_rs485;
- struct termios old_tios;
- } serial_port_t;
- static int serial_select(dlt645_t *ctx)
- {
- int s_rc;
- fd_set rfds;
- struct timeval tv;
- serial_port_t *port = ctx->port_data;
- FD_ZERO(&rfds);
- FD_SET(port->fd, &rfds);
- tv.tv_sec = ctx->response_timeout / 1000;
- tv.tv_usec = (ctx->response_timeout % 1000) * 1000;
- s_rc = select(port->fd + 1, &rfds, NULL, NULL, &tv);
- if (s_rc < 0)
- {
- return -1;
- }
- else
- {
- return s_rc;
- }
- }
- /**
- * Name: serial_linux_hw_read
- * Brief: dlt645 硬件层接收数据
- * Input:
- * @ctx: 645运行环境
- * @msg: 接收数据存放地址
- * @len: 数据最大接收长度
- * Output: 读取数据的长度 -1:error 0:timeout
- */
- static int serial_linux_hw_read(dlt645_t *ctx, uint8_t *msg, uint16_t len)
- {
- //实际接收长度
- int rc = 0;
- int length_to_read = 1, msg_length = 0;
- serial_port_t *port = ctx->port_data;
- _step_t step;
- step = _STEP_START;
- while (length_to_read != 0)
- {
- rc = serial_select(ctx);
- if (rc < 0)
- {
- printf("select error on fd %d\r\n", port->fd);
- return -1;
- }
- else if (rc == 0)
- {
- printf("select timeout on fd %d\r\n", port->fd);
- return 0;
- }
- rc = read(port->fd, msg + msg_length, length_to_read);
- if (rc < 0)
- {
- printf("read error on fd %d\r\n", port->fd);
- return -1;
- }
- //更新已收到的数据长度以及待接收的数据长度
- msg_length += rc;
- length_to_read -= rc;
- if (length_to_read == 0)
- {
- switch (step)
- {
- case _STEP_START:
- if (msg[0] == DLT645_START_CODE)
- {
- length_to_read = 9;
- step = _STEP_META;
- }
- break;
- case _STEP_META:
- length_to_read = msg[DLT645_LEN_POS];
- step = _STEP_DATA;
- break;
- case _STEP_DATA:
- length_to_read = 2;
- step = _STEP_END;
- break;
- case _STEP_END:
- if (msg[msg_length - 1] != DLT645_STOP_CODE)
- {
- printf("dlt645 frame error,no stop code\r\n");
- return -1;
- }
- break;
- default:
- break;
- }
- }
- }
- return msg_length;
- }
- /**
- * Name: serial_linux_hw_write
- * Brief: dlt645 硬件层发送数据
- * Input:
- * @ctx: 645运行环境
- * @buf: 待发送数据
- * @len: 发送长度
- * Output: 实际发送的字节数,错误返回-1
- */
- static int serial_linux_hw_write(dlt645_t *ctx, uint8_t *buf, uint16_t len)
- {
- serial_port_t *port = ctx->port_data;
- int write_len = 0;
- write_len = write(port->fd, buf, len);
- return write_len;
- }
- static void _port_close(serial_port_t *port)
- {
- if (port)
- {
- tcsetattr(port->fd, TCSANOW, &port->old_tios);
- if (port->fd)
- {
- if (close(port->fd) == 0)
- {
- printf("close fd:%d success\r\n", port->fd);
- }
- else
- {
- printf("close fd:%d failed\r\n", port->fd);
- }
- }
- }
- }
- static void serial_linux_hw_close(dlt645_t *ctx)
- {
- if (ctx == NULL)
- {
- return;
- }
- if (ctx->port_data)
- {
- _port_close(ctx->port_data);
- free(ctx->port_data);
- ctx->port_data = NULL;
- }
- free(ctx);
- ctx = NULL;
- }
- const dlt645_backend_t serial_linux_backend = {
- serial_linux_hw_close,
- serial_linux_hw_write,
- serial_linux_hw_read};
- /**
- * Name: serial_linux_port_init
- * Brief: 硬件层初始化
- * Input: None
- * Output: None
- */
- static int serial_linux_port_init(dlt645_t *ctx, void *param)
- {
- serial_linux_param_t *port_param = param;
- if (ctx == NULL)
- {
- printf("no ctx available\r\n");
- return -1;
- }
- serial_port_t *port = dlt645_malloc(sizeof(serial_port_t));
- if (port == NULL)
- {
- printf("no memory for serial_port_t\r\n");
- return -1;
- }
- memset(port, 0, sizeof(serial_port_t));
- //串口初始化
- port->fd = open(port_param->device_name, O_RDWR | O_NOCTTY);
- if (port->fd < 0)
- {
- printf("cannot open device %s \r\n", port_param->device_name);
- dlt645_free(port);
- return -1;
- }
- else
- {
- struct termios opt;
- int baudrate = 0;
- tcgetattr(port->fd, &port->old_tios);
- memset(&opt, 0, sizeof(struct termios));
- //清空串口接收缓冲区
- tcflush(port->fd, TCIOFLUSH);
- // 设置串口输出波特率
- switch (port_param->baud)
- {
- case SERIAL_B1200:
- baudrate = B1200;
- break;
- case SERIAL_B2400:
- baudrate = B2400;
- break;
- case SERIAL_B4800:
- baudrate = B4800;
- break;
- case SERIAL_B9600:
- baudrate = B9600;
- break;
- case SERIAL_B19200:
- baudrate = B19200;
- break;
- case SERIAL_B38400:
- baudrate = B38400;
- break;
- case SERIAL_B57600:
- baudrate = B57600;
- break;
- case SERIAL_B115200:
- baudrate = B115200;
- break;
- default:
- printf("unknown baud rate :%d, use default 9600\r\n", port_param->baud);
- baudrate = B9600;
- break;
- }
- if ((cfsetospeed(&opt, baudrate) < 0) ||
- (cfsetispeed(&opt, baudrate) < 0))
- {
- close(port->fd);
- dlt645_free(port);
- return -1;
- }
- //设置数据位数
- opt.c_cflag &= ~CSIZE;
- switch (port_param->data_bits)
- {
- case DATA_BITS_5:
- opt.c_cflag |= CS5;
- break;
- case DATA_BITS_6:
- opt.c_cflag |= CS6;
- break;
- case DATA_BITS_7:
- opt.c_cflag |= CS7;
- break;
- case DATA_BITS_8:
- default:
- opt.c_cflag |= CS8;
- break;
- }
- //校验位
- switch (port_param->parity)
- {
- case PARITY_NONE:
- opt.c_cflag &= ~PARENB;
- opt.c_iflag &= ~INPCK;
- break;
- case PARITY_EVEN:
- opt.c_cflag |= PARENB;
- opt.c_cflag &= ~PARODD;
- opt.c_iflag |= INPCK;
- break;
- case PARITY_ODD:
- opt.c_cflag |= PARENB;
- opt.c_cflag |= PARODD;
- opt.c_iflag |= INPCK;
- break;
- default:
- break;
- }
- //设置停止位
- if (port_param->stop_bits == STOP_BITS_1)
- {
- opt.c_cflag &= ~CSTOPB;
- }
- else
- {
- opt.c_cflag |= CSTOPB;
- }
- /* Software flow control is disabled */
- opt.c_iflag &= ~(IXON | IXOFF | IXANY);
- /* Raw ouput */
- opt.c_oflag &= ~OPOST;
- opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
- printf("Device %s on fd %d is set to 9600bps,8N1\n", port_param->device_name, port->fd);
- //更新配置
- if (tcsetattr(port->fd, TCSANOW, &opt) < 0)
- {
- close(port->fd);
- dlt645_free(port);
- return -1;
- }
- }
- ctx->port_data = port;
- return 0;
- }
- dlt645_t *dlt645_new_serial_linux(serial_linux_param_t *params)
- {
- //create dlt645 context
- dlt645_t *ctx = malloc(sizeof(dlt645_t));
- if (ctx == NULL)
- {
- printf("no memory for dlt645 ctx,malloc failed\r\n");
- return NULL;
- }
- //set default params
- dlt645_ctx_init_default(ctx);
- //set backend
- dlt645_set_backend(ctx, &serial_linux_backend);
- //hardware init
- if (serial_linux_port_init(ctx, params) < 0)
- {
- free(ctx);
- return NULL;
- }
- return ctx;
- }
|