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