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