From c13c9806f957ebc675462737f4b328d3ab89e028 Mon Sep 17 00:00:00 2001 From: guowenxue <guowenxue@gmail.com> Date: Mon, 10 Jul 2023 17:29:22 +0800 Subject: [PATCH] update gpsd.c --- gpsd/booster/comport.c | 515 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 515 insertions(+), 0 deletions(-) diff --git a/gpsd/booster/comport.c b/gpsd/booster/comport.c new file mode 100644 index 0000000..27de29a --- /dev/null +++ b/gpsd/booster/comport.c @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2022 Guo Wenxue + * Author: Guo Wenxue <guowenxue@gmail.com> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GPL license. + */ + +#include "comport.h" + +#define CONFIG_PRINT_LOGGER +//#define CONFIG_PRINT_STDOUT + +#if ( defined CONFIG_PRINT_LOGGER ) +#include "logger.h" +#define dbg_print(format,args...) log_error(format, ##args) + +#elif ( defined CONFIG_PRINT_STDOUT ) +#define dbg_print(format,args...) printf(format, ##args) + +#else +#define dbg_print(format,args...) do{} while(0); +#endif + + +static inline void set_settings(comport_t * comport, const char *settings); + +/* + * description: Open the serial port + * + * input args: $comport: corresponding comport point + * $dev_name: The comport device name path, such as '/dev/ttyS3' + * $baudrate: The baudrate, such as 115200 + * $settings: The databit,parity,stopbit,flowctrl settings, such as '8N1N' + * + * return value: The comport opened file description, <0 means failure + */ +int comport_open(comport_t *comport, const char *devname, long baudrate, const char *settings) +{ + int rv = -1; + struct termios old_cfg, new_cfg; + int old_flags; + long tmp; + + if( !comport || !devname ) + { + dbg_print("invalid input arugments\n"); + return -1; + } + + /*+-----------------------+ + *| open the serial port | + *+-----------------------+*/ + + memset(comport, 0, sizeof(*comport)); + strncpy(comport->devname, devname, sizeof(comport->devname)); + comport->baudrate = baudrate; + comport->fd = -1; + comport->fragsize = CONFIG_DEF_FRAGSIZE; + set_settings(comport, settings); + + if( !strstr(comport->devname, "tty") ) + { + dbg_print("comport device \"%s\" is not tty device\n", comport->devname); + return -2; + } + + comport->fd = open(comport->devname, O_RDWR | O_NOCTTY | O_NONBLOCK); + if( comport->fd<0 ) + { + dbg_print("comport open \"%s\" failed:%s\n", comport->devname, strerror(errno)); + return -3; + } + + if( (-1 != (old_flags = fcntl(comport->fd, F_GETFL, 0))) + && (-1 != fcntl(comport->fd, F_SETFL, old_flags & ~O_NONBLOCK)) ) + { + /* Flush input and output */ + tcflush(comport->fd, TCIOFLUSH); + } + else + { + rv = -4; + goto CleanUp; + } + + if (0 != tcgetattr(comport->fd, &old_cfg)) + { + rv = -5; + goto CleanUp; + } + + + /*+-----------------------+ + *| configure serial port | + *+-----------------------+*/ + + memset(&new_cfg, 0, sizeof(new_cfg)); + new_cfg.c_cflag &= ~CSIZE; + new_cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + new_cfg.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + new_cfg.c_oflag &= ~(OPOST); + + /* Set the data bit */ + switch (comport->databit) + { + case 0x07: + new_cfg.c_cflag |= CS7; + break; + case 0x06: + new_cfg.c_cflag |= CS6; + break; + case 0x05: + new_cfg.c_cflag |= CS5; + break; + default: + new_cfg.c_cflag |= CS8; + break; + } + + /* Set the parity */ + switch (comport->parity) + { + case 0x01: /* Odd */ + new_cfg.c_cflag |= (PARENB | PARODD); + new_cfg.c_cflag |= (INPCK | ISTRIP); + break; + case 0x02: /* Even */ + new_cfg.c_cflag |= PARENB; + new_cfg.c_cflag &= ~PARODD;; + new_cfg.c_cflag |= (INPCK | ISTRIP); + break; + case 0x03: + new_cfg.c_cflag &= ~PARENB; + new_cfg.c_cflag &= ~CSTOPB; + break; + default: + new_cfg.c_cflag &= ~PARENB; + } + + /* Set Stop bit */ + if (0x01 != comport->stopbit) + { + new_cfg.c_cflag |= CSTOPB; + } + else + { + new_cfg.c_cflag &= ~CSTOPB; + } + + /* Set flow control */ + switch (comport->flowctrl) + { + case 1: /* Software control */ + case 3: + new_cfg.c_cflag &= ~(CRTSCTS); + new_cfg.c_iflag |= (IXON | IXOFF); + break; + case 2: /* Hardware control */ + new_cfg.c_cflag |= CRTSCTS; + new_cfg.c_iflag &= ~(IXON | IXOFF); + break; + default: /* NONE */ + new_cfg.c_cflag &= ~(CRTSCTS); + new_cfg.c_iflag &= ~(IXON | IXOFF); + break; + } + + /* Set baudrate */ + switch (comport->baudrate) + { + /* Upper is not POSIX(bits/termios-baud.h) */ + case 4000000: + tmp = B4000000; + break; + case 3500000: + tmp = B3500000; + break; + case 3000000: + tmp = B3000000; + break; + case 2500000: + tmp = B2500000; + break; + case 2000000: + tmp = B2000000; + break; + case 1500000: + tmp = B1500000; + break; + case 1152000: + tmp = B1152000; + break; + case 1000000: + tmp = B1000000; + break; + case 921600: + tmp = B921600; + break; + case 576000: + tmp = B576000; + break; + case 500000: + tmp = B500000; + break; + case 460800: + tmp = B460800; + break; + case 230400: + tmp = B230400; + break; + case 115200: + tmp = B115200; + break; + case 57600: + tmp = B57600; + break; + + /* Below is POSIX(bits/termios.h) */ + case 38400: + tmp = B38400; + break; + case 19200: + tmp = B19200; + break; + case 9600: + tmp = B9600; + break; + case 4800: + tmp = B4800; + break; + case 2400: + tmp = B2400; + break; + case 1800: + tmp = B1800; + break; + case 1200: + tmp = B1200; + break; + case 600: + tmp = B600; + break; + case 300: + tmp = B300; + break; + case 200: + tmp = B200; + break; + case 150: + tmp = B150; + break; + case 134: + tmp = B134; + break; + case 110: + tmp = B110; + break; + case 75: + tmp = B75; + break; + case 50: + tmp = B50; + break; + default: + tmp = B115200; + } + cfsetispeed(&new_cfg, tmp); + cfsetispeed(&new_cfg, tmp); + + /* Set the Com port timeout settings */ + new_cfg.c_cc[VMIN] = 0; + new_cfg.c_cc[VTIME] = 0; + + tcflush(comport->fd, TCIFLUSH); + if (0 != tcsetattr(comport->fd, TCSANOW, &new_cfg)) + { + rv = -6; // Failed to set device com port settings + goto CleanUp; + } + + rv = comport->fd; + +CleanUp: + return rv; +} + + +/* + * description: close comport + * input args: $comport: corresponding comport point + */ + +void comport_close(comport_t *comport) +{ + if( !comport ) + { + dbg_print("invalid input arugments\n"); + return ; + } + + if ( comport->fd >= 0 ) + { + close(comport->fd); + } + + comport->fd = -1; + return ; +} + +/* + * description: write $data_bytes $data to $comport + * return value: 0: write ok <0: write failure + */ + +int comport_send(comport_t *comport, char *data, int data_bytes) +{ + char *ptr; + int left, bytes = 0; + int rv = 0; + + if( !comport || !data || data_bytes<=0 ) + { + dbg_print("invalid input arugments\n"); + return -1; + } + + if( comport->fd < 0 ) + { + dbg_print("Serail port not opened\n"); + return -2; + } + + ptr = data; + left = data_bytes; + + while( left > 0 ) + { + /* Large data, then slice them to frag and send */ + bytes = left>comport->fragsize ? comport->fragsize : left; + + rv = write(comport->fd, ptr, bytes); + if( rv<0 ) + { + rv = -3; + break; + } + + left -= rv; + ptr += rv; + } + + return rv; +} + + +/* + * description: read data from $comport in $timeout <ms> to $buf no more than $buf_size bytes + * return value: the actual read data bytes, <0: read failure + */ + +int comport_recv(comport_t *comport, char *buf, int buf_size, unsigned long timeout) +{ + fd_set rdfds, exfds; + struct timeval to, *to_ptr = NULL; + int ret, rv = 0; + int bytes = 0; + + if ( !comport || !buf || buf_size<=0 ) + { + dbg_print("invalid input arugments\n"); + return -1; + } + + if ( comport->fd < 0 ) + { + dbg_print("Serail port not opened\n"); + return -2; + } + + memset(buf, 0, buf_size); + + FD_ZERO(&rdfds); + FD_ZERO(&exfds); + FD_SET(comport->fd, &rdfds); + FD_SET(comport->fd, &exfds); + + if( TIMEOUT_NONE != timeout ) + { + to.tv_sec = (time_t) (timeout / 1000); + to.tv_usec = (long)(1000 * (timeout % 1000)); + to_ptr = &to; + } + + while( 1 ) + { + /* check got data arrive or not */ + ret = select(comport->fd+1, &rdfds, 0, &exfds, to_ptr); + if( ret<0 ) + { + /* EINTR means catch interrupt signal */ + dbg_print("comport select() failed: %s\n", strerror(errno)); + rv = EINTR==errno ? 0 : -3; + break; + } + else if( 0 == ret ) /* timeout */ + { + break; + } + + /* read data from comport */ + ret = read(comport->fd, buf+bytes, buf_size-bytes); + if(ret <= 0) + { + dbg_print("comport read() failed: %s\n", strerror(errno)); + break; + } + + bytes += ret; + if( bytes >= buf_size ) + break; + + /* try to read data in 1ms again, if no data arrive it will break */ + to.tv_sec = 0; + to.tv_usec = 10000; + to_ptr = &to; + } + + if( !rv ) + rv = bytes; + + return rv; +} + + +/************************************************************************************** + * Description: Set the comport databit,parity,stopbit,flowctrl into the comport structure + * Input Args: comport: the comport_t pointer + * settings: The databit/parity/stopbit/flowctrl settings as like "8N1N" + * Output Args: NONE + * Return Value: NONE + *************************************************************************************/ +static inline void set_settings(comport_t * comport, const char *settings) +{ + if( !settings || !comport ) + { + dbg_print("invalid input arugments\n"); + return ; + } + + switch (settings[0]) /* data bit */ + { + case '7': + comport->databit = 7; + break; + case '8': + default: + comport->databit = 8; + break; + } + + switch (settings[1]) /* parity */ + { + case 'O': + case 'o': + comport->parity = 1; + break; + case 'E': + case 'e': + comport->parity = 2; + break; + case 'S': + case 's': + comport->parity = 3; + break; + case 'N': + case 'n': + default: + comport->parity = 0; + break; + } + + switch (settings[2]) /* stop bit */ + { + case '0': + comport->stopbit = 0; + break; + case '1': + default: + comport->stopbit = 1; + break; + } + + switch (settings[3]) /* flow control */ + { + case 'S': + case 's': + comport->flowctrl = 1; + break; + case 'H': + case 'h': + comport->flowctrl = 2; + break; + case 'B': + case 'b': + comport->flowctrl = 3; + break; + case 'N': + case 'n': + default: + comport->flowctrl = 0; + break; + } +} + -- Gitblit v1.9.1