From f9a299001cb583d88c331e594aa0fb670c5d4930 Mon Sep 17 00:00:00 2001 From: guowenxu <guowenxue@gmail.com> Date: Wed, 28 Apr 2021 18:46:22 +0800 Subject: [PATCH] add comport source code --- booster/util_time.h | 8 booster/comport.h | 84 +++++++ booster/comport.c | 584 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 668 insertions(+), 8 deletions(-) diff --git a/booster/comport.c b/booster/comport.c new file mode 100644 index 0000000..30e814d --- /dev/null +++ b/booster/comport.c @@ -0,0 +1,584 @@ +/********************************************************************************* + * Copyright: (C) 2018 LingYun IoT System Studio + * All rights reserved. + * + * Filename: cp_comport.c + * Description: It's the comport operate library. + * + * Version: 2.0.0(10/17/2018~) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "10/17/2018 03:33:25 PM" + * + ********************************************************************************/ + +#include "comport.h" + +static void set_settings(comport_t *comport, const char *settings); + +#ifdef COM_DEBUG +void disp_settings(comport_t *comport); +#endif + + + +/* + * 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 ) + { + COM_PRINT("%s() get invalid input arguments.\n", __FUNCTION__); + return -1; + } + + memset(comport, 0, sizeof(*comport)); + strncpy(comport->devname, devname, DEVNAME_LEN); + comport->baudrate = baudrate; + comport->fd = -1; + comport->frag_size = 128; + + set_settings(comport, settings); +#ifdef COM_DEBUG + disp_settings(comport); +#endif + + /* Not a TTY device */ + if( !strstr(comport->devname, "tty")) + { + COM_PRINT("Open Not tty device \"%s\"\n", comport->devname); + return -2; + } + + comport->fd = open(comport->devname, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (comport->fd < 0) + { + rv = -3; + goto CleanUp; + } + COM_PRINT("Open device \"%s\"\n", comport->devname); + + if ((-1 != (old_flags = fcntl(comport->fd, F_GETFL, 0))) + && (-1 != fcntl(comport->fd, F_SETFL, old_flags & ~O_NONBLOCK))) + { + /* Flush input and output */ + if (-1 == tcflush(comport->fd, TCIOFLUSH)) + { + rv = -4; + goto CleanUp; + } + } + else + { + rv = -5; + goto CleanUp; + } + + if (0 != tcgetattr(comport->fd, &old_cfg)) + { + rv = -6; // Failed to get Com settings + goto CleanUp; + } + + memset(&new_cfg, 0, sizeof(new_cfg)); + + /*=====================================*/ + /* Configure comport */ + /*=====================================*/ + + 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; // Also called 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) + { + case 115200: + tmp = B115200; + break; + case 57600: + tmp = B57600; + break; + 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 = -7; // Failed to set device com port settings + goto CleanUp; + } + + COM_PRINT("Connected device \"%s\".\n", comport->devname); + + rv = comport->fd; + +CleanUp: + COM_PRINT("Open device \"%s\" %s.\n", comport->devname, rv>0 ? "successfully" : "failure"); + return rv; +} + + + +/* + * description: close comport + * input args: $comport: corresponding comport point + */ + +void comport_close(comport_t *comport) +{ + if( !comport ) + { + COM_PRINT("%s() get invalid input arguments.\n", __FUNCTION__); + return ; + } + + if ( comport->fd >= 0 ) + { + COM_PRINT("Close device \"%s\"\n", comport->devname); + close(comport->fd); + } + + comport->fd = -1; + return ; +} + +/* + * description: write $send_bytes bytes data from $buf to $comport + * return value: 0: write ok <0: write failure + */ + +int comport_send(comport_t *comport, char *buf, int send_bytes) +{ + int rv = 0; + char *ptr, *end; + int send = 0; + + if ( !comport || !buf || send_bytes<=0 ) + { + COM_PRINT("%s() get invalid input arguments.\n", __FUNCTION__); + rv = -1; + goto CleanUp; + } + + if ( comport->fd < 0 ) // Comport not opened ? + { + rv = -3; + COM_PRINT("Serail not connected.\n"); + goto CleanUp; + } + + //printf("Send %s with %d bytes.\n", buf, send_bytes); + + // Large data, then slice them and send + if (comport->frag_size < send_bytes) + { + ptr = buf; + end = buf + send_bytes; + + do + { + // Large than frag_size + if (comport->frag_size < (end - ptr)) + { + send = write(comport->fd, ptr, comport->frag_size); + if (0 >= send || comport->frag_size != send) + { + rv = -4; + goto CleanUp; + } + ptr += comport->frag_size; + } + else // Less than frag_size, maybe last fragmention. + { + send = write(comport->fd, ptr, (end - ptr)); + if (0 >= send || (end - ptr) != send) + { + rv = -4; + goto CleanUp; + } + ptr += (end - ptr); + } + } + while (ptr < end); + } + else // The send data is not large than a fragmention. + { + send = write(comport->fd, buf, send_bytes); + if (0 >= send || send_bytes != send) + { + rv = -5; + goto CleanUp; + } + } + +CleanUp: + return rv; +} + + +/* + * description: read data from $comport in $timeout <ms> to $buf no more than $bufsize bytes + * return value: the actual read data bytes, <0: read failure + */ + +int comport_recv(comport_t *comport, char *buf, int bufsize, unsigned long timeout) +{ + int rv = 0; + int iRet; + fd_set rdfds, exfds; + struct timeval stTime; + + if ( !comport || !buf || bufsize<=0 ) + { + COM_PRINT("%s() get invalid input arguments.\n", __FUNCTION__); + rv = -1; + goto CleanUp; + } + + if ( comport->fd < 0 ) + { + COM_PRINT("%s() comport not connected.\n", __FUNCTION__); + rv = -2; + goto CleanUp; + } + + FD_ZERO(&rdfds); + FD_ZERO(&exfds); + FD_SET(comport->fd, &rdfds); + FD_SET(comport->fd, &exfds); + + if (0xFFFFFFFF != timeout) + { + stTime.tv_sec = (time_t) (timeout / 1000); + stTime.tv_usec = (long)(1000 * (timeout % 1000)); + + iRet = select(comport->fd + 1, &rdfds, 0, &exfds, &stTime); + if (0 == iRet) + { + rv = 0; + goto CleanUp; + } + else if (0 < iRet) + { + if (0 != FD_ISSET(comport->fd, &exfds)) + { + rv = -6; + COM_PRINT("Error checking recv status.\n"); + goto CleanUp; + } + + if (0 == FD_ISSET(comport->fd, &rdfds)) + { + rv = 0; + COM_PRINT("No incoming data.\n"); + goto CleanUp; + } + } + else + { + if (EINTR == errno) + { + COM_PRINT("catch interrupt signal.\n"); + rv = 0; + } + else + { + COM_PRINT("Check recv status failure.\n"); + rv = -7; + } + + goto CleanUp; + } + } + + usleep(10000); /* sleep for 10ms for data incoming */ + + // Get data from Com port + iRet = read(comport->fd, buf, bufsize); + if (0 > iRet) + { + if (EINTR == errno) + rv = 0; // Interrupted signal catched + else + rv = -3; // Failed to read Com port + + goto CleanUp; + } + +#if 0 + { + int i=0; + printf("Receive %d bytes data: \n", iRet); + for(i=0; i<iRet; i++) + { + printf("0x%02x ", buf[i]); + } + printf("\n"); + } +#endif + + rv = iRet; + +CleanUp: + 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 + *************************************************************************************/ +void set_settings(comport_t * comport, const char *settings) +{ + if( !settings || !comport ) + { + COM_PRINT("%s() get invalid input arguments.\n", __FUNCTION__); + 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; + } +} + + + +#ifdef COM_DEBUG +void disp_settings(comport_t *comport) +{ + COM_PRINT("Device:\t\t\t\"%s\"\n", comport->devname); + COM_PRINT("Baudrate:\t\t%ld\n", comport->baudrate); + COM_PRINT("DataBit:\t\t\'%d\'\n", comport->databit); + + switch (comport->parity) + { + case 0: + COM_PRINT("Parity:\t\t\t\'N\'\n"); + break; + case 1: + COM_PRINT("Parity:\t\t\t\'O\'\n"); + break; + case 2: + COM_PRINT("Parity:\t\t\t\'E\'\n"); + break; + case 3: + COM_PRINT("Parity:\t\t\t\'S\'\n"); + break; + } + COM_PRINT("StopBit:\t\t\'%ld\'\n", (long int)comport->stopbit); + switch (comport->flowctrl) + { + case 0: + COM_PRINT("FlowCtrl:\t\t\'N\'\n"); + break; + case 1: + COM_PRINT("FlowCtrl:\t\t\'S\'\n"); + break; + case 2: + COM_PRINT("FlowCtrl:\t\t\'H\'\n"); + break; + case 3: + COM_PRINT("FlowCtrl:\t\t\'B\'\n"); + break; + } + COM_PRINT("\n"); + return; +} +#endif + + diff --git a/booster/comport.h b/booster/comport.h new file mode 100644 index 0000000..244e0cf --- /dev/null +++ b/booster/comport.h @@ -0,0 +1,84 @@ +/********************************************************************************* + * Copyright: (C) 2018 LingYun IoT System Studio + * All rights reserved. + * + * Filename: comport.h + * Description: This head file is for the common TTY/Serial port operator library + * + * Version: 1.0.0(10/17/2018~) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "10/17/2018 03:33:25 PM" + * + ********************************************************************************/ +#ifndef __COMPORT_H_ +#define __COMPORT_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <getopt.h> +#include <fcntl.h> +#include <errno.h> +#include <termios.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/select.h> + + +#ifndef DEVNAME_LEN +#define DEVNAME_LEN 32 +#endif + +//#define COM_DEBUG +#ifdef COM_DEBUG +#define COM_PRINT(format,args...) printf(format, ##args) +#else +#define COM_PRINT(format,args...) do{} while(0); +#endif + +typedef struct comport_s +{ + char devname[DEVNAME_LEN]; + unsigned char databit, parity, stopbit, flowctrl; + long baudrate; + + int fd; + int frag_size; +} comport_t; + + +/* + * description: Open the comport specified by $comport + * + * input args: $comport: corresponding comport point + * $devname: 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 + */ +extern int comport_open(comport_t *comport, const char *devname, long baudrate, const char *settings); + +/* + * description: close comport + * input args: $comport: corresponding comport point + */ +extern void comport_close(comport_t *comport); + +/* + * description: write $send_bytes bytes data from $buf to $comport + * return value: 0: write ok <0: write failure + */ +extern int comport_send(comport_t *comport, char *buf, int send_bytes); + +/* + * description: read data from $comport in $timeout <ms> to $buf no more than $bufsize bytes + * return value: the actual read data bytes, <0: read failure + */ +extern int comport_recv(comport_t *comport, char *buf, int bufsize, unsigned long timeout); + + +#endif diff --git a/booster/util_time.h b/booster/util_time.h index a48d8ae..adf7391 100644 --- a/booster/util_time.h +++ b/booster/util_time.h @@ -26,14 +26,6 @@ #include <sys/time.h> -#ifndef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -#endif - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - typedef struct date_time_s { int year; -- Gitblit v1.9.1