Serial Port programming in Linux using C – Working code

The library i used is from Teunis van Beelen’s website  www.teuniz.net

For my application, i wanted to communicate with SIM900 GSM module which was connected to my PC running Ubuntu OS. The SIM900 GSM module was connected to the PC using a CP2102 USB-UART bridge.

Do remember that you need to select the right port code in the Array of ports in the library. If you dont find your port number listed there, you can add it by removing a existing entry, or even add a new one. 

For me the /dev/ttyUSB5 port entry was not present so i added it below in RS232.c, because my USB converter was enumerated as /dev/ttyUSB5. You can find yours and modify the array. 

In the demo code below you can see that i am sending the index value of the comports array list corresponding to my Port name. 

Thank you Teunis van Beelen 🙂

{code lang:c title:"RS232.c" lines:false hidden:false}    #include "rs232.h"    #if defined(__linux__) || defined(__FreeBSD__)   /* Linux & FreeBSD */   int Cport[38],     error;  struct termios new_port_settings,        old_port_settings[38];  char comports[38][16]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2","/dev/ttyS3","/dev/ttyS4","/dev/ttyS5",                        "/dev/ttyS6","/dev/ttyS7","/dev/ttyS8","/dev/ttyS9","/dev/ttyS10","/dev/ttyS11",                        "/dev/ttyS12","/dev/ttyS13","/dev/ttyS14","/dev/ttyS15","/dev/ttyUSB0",                        "/dev/ttyUSB1","/dev/ttyUSB2","/dev/ttyUSB3","/dev/ttyUSB4","/dev/ttyUSB5",                        "/dev/ttyAMA0","/dev/ttyAMA1","/dev/ttyACM0","/dev/ttyACM1",                        "/dev/rfcomm0","/dev/rfcomm1","/dev/ircomm0","/dev/ircomm1",                        "/dev/cuau0","/dev/cuau1","/dev/cuau2","/dev/cuau3",                        "/dev/cuaU0","/dev/cuaU1","/dev/cuaU2","/dev/cuaU3"};  int RS232_OpenComport(int comport_number, int baudrate, const char *mode) {   int baudr,       status;    if((comport_number>37)||(comport_number<0))   {     printf("illegal comport number\n");     return(1);   }    switch(baudrate)   {     case      50 : baudr = B50;                    break;     case      75 : baudr = B75;                    break;     case     110 : baudr = B110;                    break;     case     134 : baudr = B134;                    break;     case     150 : baudr = B150;                    break;     case     200 : baudr = B200;                    break;     case     300 : baudr = B300;                    break;     case     600 : baudr = B600;                    break;     case    1200 : baudr = B1200;                    break;     case    1800 : baudr = B1800;                    break;     case    2400 : baudr = B2400;                    break;     case    4800 : baudr = B4800;                    break;     case    9600 : baudr = B9600;                    break;     case   19200 : baudr = B19200;                    break;     case   38400 : baudr = B38400;                    break;     case   57600 : baudr = B57600;                    break;     case  115200 : baudr = B115200;                    break;     case  230400 : baudr = B230400;                    break;     case  460800 : baudr = B460800;                    break;     case  500000 : baudr = B500000;                    break;     case  576000 : baudr = B576000;                    break;     case  921600 : baudr = B921600;                    break;     case 1000000 : baudr = B1000000;                    break;     case 1152000 : baudr = B1152000;                    break;     case 1500000 : baudr = B1500000;                    break;     case 2000000 : baudr = B2000000;                    break;     case 2500000 : baudr = B2500000;                    break;     case 3000000 : baudr = B3000000;                    break;     case 3500000 : baudr = B3500000;                    break;     case 4000000 : baudr = B4000000;                    break;     default      : printf("invalid baudrate\n");                    return(1);                    break;   }    int cbits=CS8,       cpar=0,       ipar=IGNPAR,       bstop=0;    if(strlen(mode) != 3)   {     printf("invalid mode \"%s\"\n", mode);     return(1);   }    switch(mode[0])   {     case '8': cbits = CS8;               break;     case '7': cbits = CS7;               break;     case '6': cbits = CS6;               break;     case '5': cbits = CS5;               break;     default : printf("invalid number of data-bits '%c'\n", mode[0]);               return(1);               break;   }    switch(mode[1])   {     case 'N':     case 'n': cpar = 0;               ipar = IGNPAR;               break;     case 'E':     case 'e': cpar = PARENB;               ipar = INPCK;               break;     case 'O':     case 'o': cpar = (PARENB | PARODD);               ipar = INPCK;               break;     default : printf("invalid parity '%c'\n", mode[1]);               return(1);               break;   }    switch(mode[2])   {     case '1': bstop = 0;               break;     case '2': bstop = CSTOPB;               break;     default : printf("invalid number of stop bits '%c'\n", mode[2]);               return(1);               break;   }  /* http://pubs.opengroup.org/onlinepubs/7908799/xsh/termios.h.html  http://man7.org/linux/man-pages/man3/termios.3.html */    Cport[comport_number] = open(comports[comport_number], O_RDWR | O_NOCTTY | O_NDELAY);   if(Cport[comport_number]==-1)   {     perror("unable to open comport ");     return(1);   }    error = tcgetattr(Cport[comport_number], old_port_settings + comport_number);   if(error==-1)   {     close(Cport[comport_number]);     perror("unable to read portsettings ");     return(1);   }   memset(&new_port_settings, 0, sizeof(new_port_settings));  /* clear the new struct */    new_port_settings.c_cflag = cbits | cpar | bstop | CLOCAL | CREAD;   new_port_settings.c_iflag = ipar;   new_port_settings.c_oflag = 0;   new_port_settings.c_lflag = 0;   new_port_settings.c_cc[VMIN] = 0;      /* block untill n bytes are received */   new_port_settings.c_cc[VTIME] = 0;     /* block untill a timer expires (n * 100 mSec.) */    cfsetispeed(&new_port_settings, baudr);   cfsetospeed(&new_port_settings, baudr);    error = tcsetattr(Cport[comport_number], TCSANOW, &new_port_settings);   if(error==-1)   {     close(Cport[comport_number]);     perror("unable to adjust portsettings ");     return(1);   }    if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)   {     perror("unable to get portstatus");     return(1);   }    status |= TIOCM_DTR;    /* turn on DTR */   status |= TIOCM_RTS;    /* turn on RTS */    if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)   {     perror("unable to set portstatus");     return(1);   }    return(0); }   int RS232_PollComport(int comport_number, unsigned char *buf, int size) {   int n;    n = read(Cport[comport_number], buf, size);    return(n); }   int RS232_SendByte(int comport_number, unsigned char byte) {   int n;   printf("%c",byte);   n = write(Cport[comport_number], &byte, 1);   if(n<0)  return(1);    return(0); }   int RS232_SendBuf(int comport_number, unsigned char *buf, int size) {   return(write(Cport[comport_number], buf, size)); }   void RS232_CloseComport(int comport_number) {   int status;    if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)   {     perror("unable to get portstatus");   }    status &= ~TIOCM_DTR;    /* turn off DTR */   status &= ~TIOCM_RTS;    /* turn off RTS */    if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)   {     perror("unable to set portstatus");   }    tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);   close(Cport[comport_number]); }  /* Constant  Description TIOCM_LE        DSR (data set ready/line enable) TIOCM_DTR       DTR (data terminal ready) TIOCM_RTS       RTS (request to send) TIOCM_ST        Secondary TXD (transmit) TIOCM_SR        Secondary RXD (receive) TIOCM_CTS       CTS (clear to send) TIOCM_CAR       DCD (data carrier detect) TIOCM_CD        see TIOCM_CAR TIOCM_RNG       RNG (ring) TIOCM_RI        see TIOCM_RNG TIOCM_DSR       DSR (data set ready)  http://man7.org/linux/man-pages/man4/tty_ioctl.4.html */  int RS232_IsDCDEnabled(int comport_number) {   int status;    ioctl(Cport[comport_number], TIOCMGET, &status);    if(status&TIOCM_CAR) return(1);   else return(0); }  int RS232_IsCTSEnabled(int comport_number) {   int status;    ioctl(Cport[comport_number], TIOCMGET, &status);    if(status&TIOCM_CTS) return(1);   else return(0); }  int RS232_IsDSREnabled(int comport_number) {   int status;    ioctl(Cport[comport_number], TIOCMGET, &status);    if(status&TIOCM_DSR) return(1);   else return(0); }  void RS232_enableDTR(int comport_number) {   int status;    if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)   {     perror("unable to get portstatus");   }    status |= TIOCM_DTR;    /* turn on DTR */    if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)   {     perror("unable to set portstatus");   } }  void RS232_disableDTR(int comport_number) {   int status;    if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)   {     perror("unable to get portstatus");   }    status &= ~TIOCM_DTR;    /* turn off DTR */    if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)   {     perror("unable to set portstatus");   } }  void RS232_enableRTS(int comport_number) {   int status;    if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)   {     perror("unable to get portstatus");   }    status |= TIOCM_RTS;    /* turn on RTS */    if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)   {     perror("unable to set portstatus");   } }  void RS232_disableRTS(int comport_number) {   int status;    if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)   {     perror("unable to get portstatus");   }    status &= ~TIOCM_RTS;    /* turn off RTS */    if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)   {     perror("unable to set portstatus");   } }   #else         /* windows */   HANDLE Cport[16];   char comports[16][10]={"\\\\.\\COM1",  "\\\\.\\COM2",  "\\\\.\\COM3",  "\\\\.\\COM4",                        "\\\\.\\COM5",  "\\\\.\\COM6",  "\\\\.\\COM7",  "\\\\.\\COM8",                        "\\\\.\\COM9",  "\\\\.\\COM10", "\\\\.\\COM11", "\\\\.\\COM12",                        "\\\\.\\COM13", "\\\\.\\COM14", "\\\\.\\COM15", "\\\\.\\COM16"};  char mode_str[128];   int RS232_OpenComport(int comport_number, int baudrate, const char *mode) {   if((comport_number>15)||(comport_number<0))   {     printf("illegal comport number\n");     return(1);   }    switch(baudrate)   {     case     110 : strcpy(mode_str, "baud=110");                    break;     case     300 : strcpy(mode_str, "baud=300");                    break;     case     600 : strcpy(mode_str, "baud=600");                    break;     case    1200 : strcpy(mode_str, "baud=1200");                    break;     case    2400 : strcpy(mode_str, "baud=2400");                    break;     case    4800 : strcpy(mode_str, "baud=4800");                    break;     case    9600 : strcpy(mode_str, "baud=9600");                    break;     case   19200 : strcpy(mode_str, "baud=19200");                    break;     case   38400 : strcpy(mode_str, "baud=38400");                    break;     case   57600 : strcpy(mode_str, "baud=57600");                    break;     case  115200 : strcpy(mode_str, "baud=115200");                    break;     case  128000 : strcpy(mode_str, "baud=128000");                    break;     case  256000 : strcpy(mode_str, "baud=256000");                    break;     case  500000 : strcpy(mode_str, "baud=500000");                    break;     case 1000000 : strcpy(mode_str, "baud=1000000");                    break;     default      : printf("invalid baudrate\n");                    return(1);                    break;   }    if(strlen(mode) != 3)   {     printf("invalid mode \"%s\"\n", mode);     return(1);   }    switch(mode[0])   {     case '8': strcat(mode_str, " data=8");               break;     case '7': strcat(mode_str, " data=7");               break;     case '6': strcat(mode_str, " data=6");               break;     case '5': strcat(mode_str, " data=5");               break;     default : printf("invalid number of data-bits '%c'\n", mode[0]);               return(1);               break;   }    switch(mode[1])   {     case 'N':     case 'n': strcat(mode_str, " parity=n");               break;     case 'E':     case 'e': strcat(mode_str, " parity=e");               break;     case 'O':     case 'o': strcat(mode_str, " parity=o");               break;     default : printf("invalid parity '%c'\n", mode[1]);               return(1);               break;   }    switch(mode[2])   {     case '1': strcat(mode_str, " stop=1");               break;     case '2': strcat(mode_str, " stop=2");               break;     default : printf("invalid number of stop bits '%c'\n", mode[2]);               return(1);               break;   }    strcat(mode_str, " dtr=on rts=on");  /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363145%28v=vs.85%29.aspx  http://technet.microsoft.com/en-us/library/cc732236.aspx */    Cport[comport_number] = CreateFileA(comports[comport_number],                       GENERIC_READ|GENERIC_WRITE,                       0,                          /* no share  */                       NULL,                       /* no security */                       OPEN_EXISTING,                       0,                          /* no threads */                       NULL);                      /* no templates */    if(Cport[comport_number]==INVALID_HANDLE_VALUE)   {     printf("unable to open comport\n");     return(1);   }    DCB port_settings;   memset(&port_settings, 0, sizeof(port_settings));  /* clear the new struct  */   port_settings.DCBlength = sizeof(port_settings);    if(!BuildCommDCBA(mode_str, &port_settings))   {     printf("unable to set comport dcb settings\n");     CloseHandle(Cport[comport_number]);     return(1);   }    if(!SetCommState(Cport[comport_number], &port_settings))   {     printf("unable to set comport cfg settings\n");     CloseHandle(Cport[comport_number]);     return(1);   }    COMMTIMEOUTS Cptimeouts;    Cptimeouts.ReadIntervalTimeout         = MAXDWORD;   Cptimeouts.ReadTotalTimeoutMultiplier  = 0;   Cptimeouts.ReadTotalTimeoutConstant    = 0;   Cptimeouts.WriteTotalTimeoutMultiplier = 0;   Cptimeouts.WriteTotalTimeoutConstant   = 0;    if(!SetCommTimeouts(Cport[comport_number], &Cptimeouts))   {     printf("unable to set comport time-out settings\n");     CloseHandle(Cport[comport_number]);     return(1);   }    return(0); }   int RS232_PollComport(int comport_number, unsigned char *buf, int size) {   int n;  /* added the void pointer cast, otherwise gcc will complain about */ /* "warning: dereferencing type-punned pointer will break strict aliasing rules" */    ReadFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL);    return(n); }   int RS232_SendByte(int comport_number, unsigned char byte) {   int n;       WriteFile(Cport[comport_number], &byte, 1, (LPDWORD)((void *)&n), NULL);    printf("%c",byte);   if(n<0)  return(1);    return(0); }   int RS232_SendBuf(int comport_number, unsigned char *buf, int size) {   int n; 	   if(WriteFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL))   {     return(n);   }    printf("%s",buf);    return(-1); }   void RS232_CloseComport(int comport_number) {   CloseHandle(Cport[comport_number]); }  /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363258%28v=vs.85%29.aspx */  int RS232_IsDCDEnabled(int comport_number) {   int status;    GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));    if(status&MS_RLSD_ON) return(1);   else return(0); }   int RS232_IsCTSEnabled(int comport_number) {   int status;    GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));    if(status&MS_CTS_ON) return(1);   else return(0); }   int RS232_IsDSREnabled(int comport_number) {   int status;    GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));    if(status&MS_DSR_ON) return(1);   else return(0); }   void RS232_enableDTR(int comport_number) {   EscapeCommFunction(Cport[comport_number], SETDTR); }   void RS232_disableDTR(int comport_number) {   EscapeCommFunction(Cport[comport_number], CLRDTR); }   void RS232_enableRTS(int comport_number) {   EscapeCommFunction(Cport[comport_number], SETRTS); }   void RS232_disableRTS(int comport_number) {   EscapeCommFunction(Cport[comport_number], CLRRTS); }   #endif   void RS232_cputs(int comport_number, const char *text)  /* sends a string to serial port */ {   while(*text != 0)   RS232_SendByte(comport_number, *(text++)); }    {/code}


{code lang:c title:"RS232.h" lines:false hidden:false}  #ifndef rs232_INCLUDED #define rs232_INCLUDED  #ifdef __cplusplus extern "C" { #endif  #include <stdio.h>
#include <string.h> #if defined(__linux__) || defined(__FreeBSD__) #include <termios.h> #include <sys/ioctl.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <limits.h> #else #include <windows.h> #endif int RS232_OpenComport(int, int, const char *); int RS232_PollComport(int, unsigned char *, int); int RS232_SendBy te(int, unsigned char); int RS232_SendBuf(int, unsigned char *, int); void RS232_CloseComport(int); void RS232_cputs(int, const char *); int RS232_IsDCDEnabled(int); int RS232_IsCTSEnabled(int); int RS232_IsDSREnabled(int); void RS232_enableDTR(int); void RS232_disableDTR(int); void RS232_enableRTS(int); void RS232_disableRTS(int); #ifdef __cplusplus } /* extern "C" */ #endif #endif {/code}

{code lang:c title:"Demo code showing how to use the library" lines:false hidden:false}   #include <stdlib.h> #include <stdio.h>  #ifdef _WIN32 #include <Windows.h> #else #include <unistd.h> #endif  #include "rs232.h"   /******************************************************************************* * Funtion name : MapForward                                                    * *                                                                              * * Description  : This function performs forward mapping and returns pointer    * *                to the start of the found data or else returns NULL pointer   * *                                                                              * * Arguments    : 1) Poshorter to the data in which mapping is to be made       * *                2) Length of the data in which mapping is to be made          * *                3) Poshorter to the data points to be mapped                  * *                4) Length of the data points to be mapped                     * *                                                                              * * Returns      : Pointer in which result is returned                           * *******************************************************************************/ unsigned char * MapForward ( 	unsigned char *pMapData, 	unsigned short   MapDataLength, 	unsigned char *pMapPoints, 	unsigned short   MapPointsLength	 ) {     unsigned short DataIndex;     unsigned short MapPointIndex;      for(DataIndex = 0; DataIndex < MapDataLength - MapPointsLength + 1; DataIndex++)     {                  for(MapPointIndex = 0; MapPointIndex < MapPointsLength; MapPointIndex++)         {             if( pMapData[DataIndex + MapPointIndex] != pMapPoints[MapPointIndex])             {                 goto PICK_NEXT_FMAPDATA;             }         }          return(& pMapData[DataIndex]);              PICK_NEXT_FMAPDATA:;      }     return(NULL); }   int ReadComport(int cport_nr,unsigned char *buf,int size,useconds_t count) //size=6000 { 	int n;         n=0; 	usleep(count);   while(1)   {      n = RS232_PollComport(cport_nr, buf, size);      if(n > 0)     {       buf[n] = 0;   /* always put a "null" at the end of a string! */        //for(i=0; i < n; i++)       //{         //if(buf[i] < 32)  /* replace unreadable control-codes by dots */         //{         //  buf[i] = '.';         //}       //}        printf("%s\n", (char *)buf);       break;     } }  	return n; }  void Resetbufer(unsigned char *buf,int size) { 	int i; 	for(i=0;i<size;i++) 	{ 		buf[i] = '0'; 	} } /* char comports[38][16]={"/dev/ttyS0","/dev/ttyS1=2","/dev/ttyS2","/dev/ttyS3","/dev/ttyS4","/dev/ttyS5",                        "/dev/ttyS6","/dev/ttyS7","/dev/ttyS8","/dev/ttyS9","/dev/ttyS10","/dev/ttyS11",                        "/dev/ttyS12","/dev/ttyS13","/dev/ttyS14","/dev/ttyS15","/dev/ttyUSB0=16",                        "/dev/ttyUSB1=17","/dev/ttyUSB2=18","/dev/ttyUSB3=19","/dev/ttyUSB4=20","/dev/ttyUSB5=21",                        "/dev/ttyAMA0","/dev/ttyAMA1","/dev/ttyACM0","/dev/ttyACM1",                        "/dev/rfcomm0","/dev/rfcomm1","/dev/ircomm0","/dev/ircomm1",                        "/dev/cuau0","/dev/cuau1","/dev/cuau2","/dev/cuau3",                        "/dev/cuaU0","/dev/cuaU1","/dev/cuaU2","/dev/cuaU3"};   */ int main() { 	int      cport_nr=21,        /* /dev/ttyUSB5 Look above to get the port code. () */ 	bdrate=9600;       /* 9600 baud */  	const unsigned char OKToken[]={"OK"}; 	//unsigned char URL[]={"http://www.marsinnovations.in/upload.php"}; 	unsigned char URL[]={"http://posttestserver.com/post.php"};  	unsigned char FILENAME[]={"data.txt"}; // File to be sent 	char mode[]={'8','N','1',0}, 	str[512];  	unsigned char buf[6000]; 	int buf_SIZE=sizeof(buf);  	int fsize;	 	char string[10000];   	FILE *f = fopen((const char*)FILENAME, "rb"); 	if (f != NULL) 	{ 		fseek(f, 0, SEEK_END); 		fsize = ftell(f); 		fseek(f, 0, SEEK_SET);  		//char *string = malloc(fsize + 1); 		fread(string, fsize, 1, f); 		fclose(f); 	 		string[fsize] = 0; 		printf("%s",string); 		 	} 	else 	{ 		printf("Doesnt exist"); 	}      if(RS232_OpenComport(cport_nr, bdrate, mode))   {     printf("Can not open comport\n");      return(0);   } restart:     //In my case i am using a SIM900 GSM modem to communicate using serial port,
// using Linux & a CP2102 USB-UART brudge
// Send AT command to GSM modem.
RS232_cputs(cport_nr, "AT\r\n");
// Clear the buffer i am using for reading data into.
Resetbufer(buf,sizeof(buf)); // Read the data received in the serial port buffer.
ReadComport(cport_nr,buf,6000,500000); // Check if "OK" string is present in the received data
if(MapForward(buf,buf_SIZE,(unsigned char*)OKToken,2) == NULL) goto exit; // You can send individual bytes to the serial/COM port using this function
RS232_SendByte(cport_nr,0x1A); // 0x1A is a hex equivalent of Ctrl^Z key press SUCCESS: printf("SUCCESS"); return(0); exit: printf("FAILED"); return(0); } {/code}

Hoping this helps someone 🙂

Leave a Comment