| | |
| | | /* ******************************************************************************** |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * Copyright: (C) 2020 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~) |
| | | * Version: 1.0.0(6/29/2018~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "10/17/2018 03:33:25 PM" |
| | | * ChangeLog: 1, Release initial version on "6/29/2018 03:33:25 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include "comport.h" |
| | | |
| | | #ifdef COM_DEBUG |
| | | void disp_settings(comport_t *comport); |
| | | #endif |
| | | |
| | | void set_settings(comport_t * comport, const char *settings); |
| | | |
| | | /************************************************************************************** |
| | | * Description: Set the comport structure |
| | | * Input Args: dev_name: The comport device name path, such as '/dev/ttyS3' |
| | | * Description: initialise the comport structure |
| | | * |
| | | * Input Args: |
| | | * comport: The comport work context pointer |
| | | * 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' |
| | | * Output Args: NONE |
| | | * Return Value: The comport_t structure pointer. |
| | | * |
| | | * Return Value: 0: Successfully <0: Failure |
| | | * |
| | | *************************************************************************************/ |
| | | comport_t *comport_init(const char *dev_name, int baudrate, const char *settings) |
| | | int comport_init(comport_t *comport, const char *dev_name, int baudrate, const char *settings) |
| | | { |
| | | comport_t *comport = NULL; |
| | | if (NULL == (comport = (comport_t *) malloc(sizeof(comport_t)))) |
| | | if( !comport ) |
| | | { |
| | | return NULL; |
| | | COM_PRINT("Invalid input arugments in %s().\n", __FUNCTION__); |
| | | return -1; |
| | | } |
| | | |
| | | memset(comport, 0, sizeof(comport_t)); |
| | | comport->frag_size = 128; |
| | | |
| | |
| | | comport->baudrate = baudrate; |
| | | |
| | | set_settings(comport, settings); |
| | | |
| | | #ifdef COM_DEBUG |
| | | disp_settings(comport); |
| | | #endif |
| | | |
| | | return comport; |
| | | return 0; |
| | | } |
| | | |
| | | /*+-----------------------------------------------------------------------------------------+ |
| | | * description: display current comport settings such as databit,parity,stopbit,flowctrl |
| | | * input args: $comport: corresponding comport point |
| | | *+-----------------------------------------------------------------------------------------+*/ |
| | | #ifdef COM_DEBUG |
| | | void disp_settings(comport_t *comport) |
| | | { |
| | | if( !comport) |
| | | { |
| | | COM_PRINT("Invalid input arugments in %s().\n", __FUNCTION__); |
| | | return ; |
| | | } |
| | | |
| | | COM_PRINT("Device:\t\t\t\"%s\"\n", comport->dev_name); |
| | | COM_PRINT("Baudrate:\t\t%ld\n", comport->baudrate); |
| | | COM_PRINT("DataBit:\t\t\'%d\'\n", comport->databit); |
| | |
| | | *************************************************************************************/ |
| | | void set_settings(comport_t * comport, const char *settings) |
| | | { |
| | | if(NULL==settings || NULL==comport) |
| | | if( !settings || !comport) |
| | | { |
| | | COM_PRINT("Invalid input arugments in %s().\n", __FUNCTION__); |
| | | return ; |
| | | } |
| | | |
| | | switch (settings[0]) /* data bit */ |
| | | { |
| | |
| | | comport->fd = -1; |
| | | } |
| | | |
| | | void comport_term(comport_t * comport) |
| | | { |
| | | if(NULL == comport) |
| | | return; |
| | | |
| | | if ( comport->fd > 0 ) |
| | | { |
| | | comport_close(comport); |
| | | } |
| | | |
| | | memset(comport, 0x00, sizeof(comport_t)); |
| | | free(comport); |
| | | |
| | | return; |
| | | } |
| | | |
| | | int comport_open(comport_t * comport) |
| | | { |
| | | int retval = -1; |
| | | int rv = -1; |
| | | struct termios old_cfg, new_cfg; |
| | | int old_flags; |
| | | long tmp; |
| | | |
| | | if(NULL==comport) |
| | | if( !comport ) |
| | | { |
| | | COM_PRINT("Invalid input arugments in %s().\n", __FUNCTION__); |
| | | return -1; |
| | | } |
| | | |
| | | comport_close(comport); |
| | | |
| | |
| | | { |
| | | COM_PRINT("Open Not tty device \"%s\"\n", comport->dev_name); |
| | | comport->fd = open(comport->dev_name, O_RDWR); |
| | | retval = comport->fd<0 ? -2 : comport->fd; |
| | | rv = comport->fd<0 ? -2 : comport->fd; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | comport->fd = open(comport->dev_name, O_RDWR | O_NOCTTY | O_NONBLOCK); |
| | | if (comport->fd < 0) |
| | | { |
| | | retval = -3; |
| | | rv = -3; |
| | | goto CleanUp; |
| | | } |
| | | COM_PRINT("Open device \"%s\"\n", comport->dev_name); |
| | |
| | | // Flush input and output |
| | | if (-1 == tcflush(comport->fd, TCIOFLUSH)) |
| | | { |
| | | retval = -4; |
| | | rv = -4; |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | else // Failure |
| | | { |
| | | retval = -5; |
| | | rv = -5; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if (0 != tcgetattr(comport->fd, &old_cfg)) |
| | | { |
| | | retval = -6; // Failed to get Com settings |
| | | rv = -6; // Failed to get Com settings |
| | | goto CleanUp; |
| | | } |
| | | |
| | |
| | | tcflush(comport->fd, TCIFLUSH); |
| | | if (0 != tcsetattr(comport->fd, TCSANOW, &new_cfg)) |
| | | { |
| | | retval = -7; // Failed to set device com port settings |
| | | rv = -7; // Failed to set device com port settings |
| | | goto CleanUp; |
| | | } |
| | | |
| | | COM_PRINT("Connected device \"%s\".\n", comport->dev_name); |
| | | |
| | | retval = comport->fd; |
| | | rv = comport->fd; |
| | | |
| | | CleanUp: |
| | | COM_PRINT("Open device \"%s\" %s.\n", comport->dev_name, retval>0 ? "successfully" : "failure"); |
| | | return retval; |
| | | COM_PRINT("Open device \"%s\" %s.\n", comport->dev_name, rv>0 ? "successfully" : "failure"); |
| | | return rv; |
| | | } |
| | | |
| | | |
| | | int comport_recv(comport_t * comport, char *buf, int buf_size, unsigned long timeout) |
| | | { |
| | | int retval = 0; // Function return value |
| | | int rv = 0; // Function return value |
| | | int iRet; |
| | | fd_set stReadFds, stExcpFds; |
| | | struct timeval stTime; |
| | | |
| | | if (NULL == buf || 0 >= buf_size) |
| | | if ( !buf || buf_size<0 ) |
| | | { |
| | | COM_PRINT("%s() usage error.\n", __FUNCTION__); |
| | | retval = -1; |
| | | COM_PRINT("Invalid input arugments in %s().\n", __FUNCTION__); |
| | | rv = -1; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if ( comport->fd < 0 ) |
| | | { |
| | | COM_PRINT("%s() comport not connected.\n", __FUNCTION__); |
| | | retval = -2; |
| | | rv = -2; |
| | | goto CleanUp; |
| | | } |
| | | |
| | |
| | | iRet = select(comport->fd + 1, &stReadFds, 0, &stExcpFds, &stTime); |
| | | if (0 == iRet) |
| | | { |
| | | retval = 0; // No data in Com port buffer |
| | | rv = 0; // No data in Com port buffer |
| | | goto CleanUp; |
| | | } |
| | | else if (0 < iRet) |
| | | { |
| | | if (0 != FD_ISSET(comport->fd, &stExcpFds)) |
| | | { |
| | | retval = -6; // Error during checking recv status |
| | | rv = -6; // Error during checking recv status |
| | | COM_PRINT("Error checking recv status.\n"); |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if (0 == FD_ISSET(comport->fd, &stReadFds)) |
| | | { |
| | | retval = 0; // No incoming data |
| | | rv = 0; // No incoming data |
| | | COM_PRINT("No incoming data.\n"); |
| | | goto CleanUp; |
| | | } |
| | |
| | | if (EINTR == errno) |
| | | { |
| | | COM_PRINT("catch interrupt signal.\n"); |
| | | retval = 0; // Interrupted signal catched |
| | | rv = 0; // Interrupted signal catched |
| | | } |
| | | else |
| | | { |
| | | COM_PRINT("Check recv status failure.\n"); |
| | | retval = -7; // Error during checking recv status |
| | | rv = -7; // Error during checking recv status |
| | | } |
| | | |
| | | goto CleanUp; |
| | |
| | | if (0 > iRet) |
| | | { |
| | | if (EINTR == errno) |
| | | retval = 0; // Interrupted signal catched |
| | | rv = 0; // Interrupted signal catched |
| | | else |
| | | retval = -3; // Failed to read Com port |
| | | rv = -3; // Failed to read Com port |
| | | |
| | | goto CleanUp; |
| | | } |
| | |
| | | } |
| | | #endif |
| | | |
| | | retval = iRet; |
| | | rv = iRet; |
| | | |
| | | CleanUp: |
| | | return retval; |
| | | |
| | | return rv; |
| | | } |
| | | |
| | | int comport_send(comport_t * comport, char *buf, int send_bytes) |
| | | int comport_send(comport_t * comport, char *buf, int bytes) |
| | | { |
| | | char *ptr, *end; |
| | | int retval = 0; |
| | | int send = 0; |
| | | int i; |
| | | int left_bytes; |
| | | int rv = 0; |
| | | |
| | | if (NULL == buf || 0 >= send_bytes) |
| | | if( !buf || bytes<=0 ) |
| | | { |
| | | COM_PRINT("%s() Usage error.\n", __FUNCTION__); |
| | | retval = -1; |
| | | COM_PRINT("Invalid input arugments in %s().\n", __FUNCTION__); |
| | | rv = -1; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if ( comport->fd < 0 ) // Comport not opened ? |
| | | { |
| | | retval = -3; |
| | | COM_PRINT("Serail not connected.\n"); |
| | | rv = -3; |
| | | COM_PRINT("Serail port not connected.\n"); |
| | | goto CleanUp; |
| | | } |
| | | |
| | | //printf("Send %s with %d bytes.\n", buf, send_bytes); |
| | | //printf("Send %s with %d bytes.\n", buf, bytes); |
| | | |
| | | // Large data, then slice them and send |
| | | if (comport->frag_size < send_bytes) |
| | | if (bytes > comport->frag_size ) |
| | | { |
| | | ptr = buf; |
| | | end = buf + send_bytes; |
| | | i = 0; |
| | | left_bytes = bytes; |
| | | |
| | | do |
| | | while( left_bytes >= 0 ) |
| | | { |
| | | // Large than frag_size |
| | | if (comport->frag_size < (end - ptr)) |
| | | if( left_bytes > comport->frag_size ) |
| | | rv = write(comport->fd, &buf[i], comport->frag_size); |
| | | else |
| | | rv = write(comport->fd, &buf[i], left_bytes); |
| | | |
| | | if( rv < 0 ) |
| | | { |
| | | send = write(comport->fd, ptr, comport->frag_size); |
| | | if (0 >= send || comport->frag_size != send) |
| | | { |
| | | retval = -4; |
| | | rv = -4; |
| | | goto CleanUp; |
| | | } |
| | | ptr += comport->frag_size; |
| | | |
| | | i += rv; |
| | | left_bytes -= rv; |
| | | } |
| | | else // Less than frag_size, maybe last fragmention. |
| | | } |
| | | /* The send data is not large than a fragmention, send in one time. */ |
| | | else |
| | | { |
| | | send = write(comport->fd, ptr, (end - ptr)); |
| | | if (0 >= send || (end - ptr) != send) |
| | | rv = write(comport->fd, buf, bytes); |
| | | if ( rv<=0 || rv!=bytes ) |
| | | { |
| | | retval = -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) |
| | | { |
| | | retval = -5; |
| | | rv = -5; |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | |
| | | CleanUp: |
| | | return retval; |
| | | return rv; |
| | | } |
| | | |