rs232_fn.c

source

   1 #include <stdio.h>
   2 #include <string.h>
   3 #include <errno.h>
   4 #include <termios.h>
   5 #include <sys/time.h>
   6 #include <sys/types.h>
   7 #include <sys/ioctl.h>
   8 #include <unistd.h>
   9 #include <fcntl.h>
  10 #include <stdarg.h>
  11 #include "rs232_fn.h"
  12 
  13 //#define DEBUG 1
  14 //#define DEBUG_COUNT 0
  15 
  16 //#define WITHOUT_CFSETSPEED
  17 
  18 #ifdef WITHOUT_CFSETSPEED
  19 
  20 struct rs232_speed_struct
  21 {
  22   speed_t value;
  23   speed_t internal;
  24 };
  25 
  26 static const struct rs232_speed_struct rs232_speeds[] =
  27   {
  28 #ifdef B0
  29     { 0, B0 },
  30 #endif
  31 #ifdef B50
  32     { 50, B50 },
  33 #endif
  34 #ifdef B75
  35     { 75, B75 },
  36 #endif
  37 #ifdef B110
  38     { 110, B110 },
  39 #endif
  40 #ifdef B134
  41     { 134, B134 },
  42 #endif
  43 #ifdef B150
  44     { 150, B150 },
  45 #endif
  46 #ifdef B200
  47     { 200, B200 },
  48 #endif
  49 #ifdef B300
  50     { 300, B300 },
  51 #endif
  52 #ifdef B600
  53     { 600, B600 },
  54 #endif
  55 #ifdef B1200
  56     { 1200, B1200 },
  57 #endif
  58 #ifdef B1200
  59     { 1200, B1200 },
  60 #endif
  61 #ifdef B1800
  62     { 1800, B1800 },
  63 #endif
  64 #ifdef B2400
  65     { 2400, B2400 },
  66 #endif
  67 #ifdef B4800
  68     { 4800, B4800 },
  69 #endif
  70 #ifdef B9600
  71     { 9600, B9600 },
  72 #endif
  73 #ifdef B19200
  74     { 19200, B19200 },
  75 #endif
  76 #ifdef B38400
  77     { 38400, B38400 },
  78 #endif
  79 #ifdef B57600
  80     { 57600, B57600 },
  81 #endif
  82 #ifdef B76800
  83     { 76800, B76800 },
  84 #endif
  85 #ifdef B115200
  86     { 115200, B115200 },
  87 #endif
  88 #ifdef B153600
  89     { 153600, B153600 },
  90 #endif
  91 #ifdef B230400
  92     { 230400, B230400 },
  93 #endif
  94 #ifdef B307200
  95     { 307200, B307200 },
  96 #endif
  97 #ifdef B460800
  98     { 460800, B460800 },
  99 #endif
 100   };
 101 
 102 /**
 103  * Set both the input and output baud rates stored in *TERMIOS_P to SPEED.  
 104  */
 105 int
 106 rs232_cfsetspeed (struct termios *termios_p, speed_t speed)
 107 {
 108   size_t cnt;
 109 
 110   for (cnt = 0; cnt < sizeof (rs232_speeds) / sizeof (rs232_speeds[0]); ++cnt)
 111     if (speed == rs232_speeds[cnt].internal)
 112       {
 113 	cfsetispeed (termios_p, speed);
 114 	cfsetospeed (termios_p, speed);
 115 	return 0;
 116       }
 117     else if (speed == rs232_speeds[cnt].value)
 118       {
 119 	cfsetispeed (termios_p, rs232_speeds[cnt].internal);
 120 	cfsetospeed (termios_p, rs232_speeds[cnt].internal);
 121 	return 0;
 122       }
 123   /*__set_errno (EINVAL);*/
 124 
 125   return -1;
 126 }
 127 
 128 #endif /* WITHOUT_CFSETSPEED */
 129 
 130 /**
 131  * Set right mode and speed for RS232 interface 
 132  * baud can be either speed in character per second or special Bxxxx constant 
 133  */
 134 int rs232_setmode(int fd, int baud, int mode, int flowc)
 135 {
 136   struct termios ts;
 137 
 138   /* Flush input and output queues. */
 139   if (tcflush(fd, TCIOFLUSH) != 0) {
 140     fprintf(stderr,"Error in tcflush\n");
 141     return -1;
 142   }	
 143 
 144   /* Fetch the current terminal parameters. */
 145   if (tcgetattr(fd, &ts) != 0) {
 146     fprintf(stderr,"Error in tcgetattr\n");
 147     return -1;
 148   }	
 149 
 150   /* Sets hardware control flags:                              */
 151   /* 8 data bits                                               */
 152   /* Enable receiver                                           */
 153   /* Ignore CD (local connection)                              */
 154   ts.c_cflag = CS8 | CREAD | CLOCAL;
 155   if(flowc&1){
 156     /* Use RTS/CTS flow control */
 157     ts.c_cflag |= CRTSCTS; /* CCTS_OFLOW | CRTS_IFLOW */
 158   }
 159   ts.c_iflag = 0;
 160   ts.c_oflag = NL0 | CR0 | TAB0 | BS0 | VT0 | FF0;
 161   ts.c_lflag = 0;
 162 
 163   /* set right ispeed and ospeed */
 164  #ifdef WITHOUT_CFSETSPEED
 165   if(rs232_cfsetspeed(&ts,baud)<0){
 166     fprintf(stderr,"Error in rs232_cfsetspeed\n");
 167     return -1;
 168   }
 169  #else /* WITHOUT_CFSETSPEED */
 170   if(cfsetspeed(&ts,baud)<0){
 171     fprintf(stderr,"Error in cfsetspeed\n");
 172     return -1;
 173   }
 174  #endif /* WITHOUT_CFSETSPEED */
 175 
 176   ts.c_cc[VINTR]    = '\0';
 177   ts.c_cc[VQUIT]    = '\0';
 178   ts.c_cc[VERASE]   = '\0';
 179   ts.c_cc[VKILL]    = '\0';
 180   ts.c_cc[VEOF]     = '\0';
 181   ts.c_cc[VTIME]    = '\0';
 182   ts.c_cc[VMIN]     = 1;
 183   ts.c_cc[VSWTC]    = '\0';
 184   ts.c_cc[VSTART]   = '\0';
 185   ts.c_cc[VSTOP]    = '\0';
 186   ts.c_cc[VSUSP]    = '\0';
 187   ts.c_cc[VEOL]     = '\0';
 188   ts.c_cc[VREPRINT] = '\0';
 189   ts.c_cc[VDISCARD] = '\0';
 190   ts.c_cc[VWERASE]  = '\0';
 191   ts.c_cc[VLNEXT]   = '\0';
 192   ts.c_cc[VEOL2]    = '\0';
 193 
 194   /* Sets the new terminal parameters. */
 195   if (tcsetattr(fd, TCSANOW, &ts) != 0) {
 196     fprintf(stderr,"Error in tcsetattr\n");
 197     return -1;
 198   }	
 199 
 200   return 0;
 201 }
 202 
 203 /**
 204  * sends one char
 205  */
 206 int rs232_sendch(int fd,unsigned char c)
 207 {
 208   if(write(fd, &c, 1) != 1){
 209     fprintf(stderr,"Error in rs232_sendch\n");
 210     return -1;
 211   }	
 212  #if DEBUG
 213   printf("rs232_sendch 0x%02X ",c);
 214  #endif
 215   return c;
 216 }
 217 
 218 /**
 219  * reads one char
 220  */
 221 int rs232_recch(int fd)
 222 {
 223   unsigned char c;
 224   if (read(fd, &c, 1) != 1){
 225     fprintf(stderr,"Error in rs232_recch\n");
 226     return -1;
 227   }	
 228  #if DEBUG
 229   printf("R:0x%02X '%c' ",c,c>=0x20?c:'?');
 230  #endif
 231   return c;
 232 }
 233 
 234 /**
 235  * waits for time usec to presence of char
 236  */
 237 int rs232_test(int fd, int time)
 238 {
 239   struct timeval tv;
 240   fd_set rfds;
 241   int x;
 242 
 243   tv.tv_sec = 0;
 244   tv.tv_usec = time;
 245   FD_ZERO(&rfds);
 246   FD_SET(fd, &rfds);
 247   x=select(fd + 1, &rfds, NULL, NULL, &tv);
 248  #if DEBUG
 249   printf("rs232_test %d ",x);
 250  #endif
 251   return x;
 252 }
 253 
 254 /**
 255  * waits for time usec to presence of char
 256  * and reads it, if it arrives
 257  */
 258 int rs232_recch_wait(int fd,int time)
 259 {
 260   int ret;
 261   int ch;
 262 
 263   ret=rs232_test(fd,time);
 264   if(ret<=0){
 265    #if DEBUG
 266     printf("\nrs232_recch_wait: rs232_test failed\n");
 267    #endif
 268     return -1;
 269   }
 270   ch=rs232_recch(fd);
 271   if(ch<0){
 272    #if DEBUG
 273     printf("\nrs232_recch_wait: rs232_recch failed\n");
 274    #endif
 275     return -1;
 276   }
 277   return ch;
 278 }
 279 
 280 /*
 281  * reads chars until one of delimit chars arrives
 282  */
 283 int rs232_wait_delimit(int fd,char *delimit,int time)
 284 {
 285   int ret;
 286   int ch;
 287 
 288   do{  
 289     ret=rs232_test(fd,time);
 290     if(ret<=0){
 291      #if DEBUG
 292       printf("\nrs232_wait_delimit: rs232_test failed\n");
 293      #endif
 294       return -1;
 295     }
 296     ch=rs232_recch(fd);
 297     if(ch<0){
 298      #if DEBUG
 299       printf("\nrs232_wait_delimit: rs232_recch failed\n");
 300      #endif
 301       return -1;
 302     }
 303   } while(!strchr(delimit,ch));
 304   return ch;
 305 }
 306 
 307 #define B_LEN 8
 308 /**
 309  * safe writing of long data
 310  */
 311 int rs232_writem(int fd, int mode, char *data, int len)
 312 {
 313   char *p, *r, *e;
 314   int res;
 315   char chk[B_LEN];
 316   int wcnt=0;
 317 
 318  #if DEBUG
 319   printf("\nrs232_writem: write len %d\n",len);
 320  #endif
 321   r=p=data;
 322   e=data+len;
 323   while(e!=r){
 324     len=e-p;
 325     if(len>B_LEN) len=B_LEN;
 326     if(len){
 327       if((res=write(fd,p,len))==-1){
 328        #if DEBUG
 329 	printf("\nrs232_writem: write failed\n");
 330        #endif
 331 	return -1;
 332       }
 333       p+=res;
 334      #if DEBUG
 335       printf("\nwrm: %d>%d \n",len,res);
 336      #endif
 337     }
 338     if(mode&RS232_SF_ECHO){
 339       rs232_test(fd,100);
 340       len=p-r;
 341       if(len>B_LEN) len=B_LEN;
 342       chk[0]='Y',
 343       res=read(fd,chk,len);
 344       if(res<0){
 345         if((errno==EAGAIN)||(errno==EINTR))
 346           if(wcnt<2) { wcnt++; continue; }
 347        #if DEBUG
 348 	printf("\nrs232_writem: read failed %s (%d)\n", strerror(errno),errno);
 349        #endif
 350         return -2;
 351       }
 352       if(res){
 353         wcnt = 0;
 354 	if(memcmp(chk,r,res)){
 355 	 #if DEBUG
 356 	  int i;
 357 	  printf("\nrs232_writem: compare failed\n");
 358 	  for(i=0;i<res;i++){
 359 	    if(chk[i]==r[i])
 360 	      printf("%02X '%c' ",chk[i],chk[i]>=0x20?chk[i]:'?');
 361 	    else
 362 	      printf("%02X!%02X '%c'!'%c' ",chk[i],r[i],
 363 	        chk[i]>=0x20?chk[i]:'?',r[i]>=0x20?r[i]:'?');
 364 	  }
 365 	  printf("\n");
 366 	 #endif
 367           return -3;
 368 	}
 369 	r+=res;
 370        #if DEBUG
 371 	printf("res=%d\n",res);
 372        #endif
 373       } else {
 374         if(wcnt++>2) {
 375          #if DEBUG
 376 	  printf("\nrs232_writem: read failed %s (%d)\n", strerror(errno),errno);
 377          #endif
 378           return -4;
 379 	}
 380       }
 381     } else r=p;
 382   }
 383   return r-data;
 384 }
 385 
 386 /**
 387  * reads up to len chars coming with max time delay
 388  */
 389 int rs232_readm(int fd, int time, char *data, int len)
 390 {
 391   int res;
 392   char *p=data;
 393 
 394  #if DEBUG
 395   printf("\nrs232_readm: read len %d\n",len);
 396  #endif
 397   while(len){
 398     if(rs232_test(fd,time)<0){
 399      #if DEBUG
 400       printf("\nrs232_readm: timeout\n");
 401      #endif
 402       return -1;
 403     }
 404     res=read(fd,p,len);
 405     if(res<0){
 406       if((errno==EAGAIN)||(errno==EINTR)) continue;
 407      #if DEBUG
 408       printf("\nrs232_readm: read failed\n");
 409      #endif
 410       return -2;
 411     }
 412     p+=res;
 413     len-=res;
 414   }
 415 
 416  #if DEBUG
 417   printf("\nrs232_readm: received %d characters\n",p-data);
 418  #endif
 419   return p-data;
 420 }
 421 
 422 #define S_LEN 88
 423 /**
 424  * printf to the serial line
 425  */
 426 int rs232_sendf(int fd, int mode, char *template, ...)
 427 {
 428   va_list ap;
 429   char s[S_LEN];
 430   int cnt;
 431 
 432   va_start (ap, template);
 433   cnt=vsnprintf (s, S_LEN, template, ap);
 434   if(cnt>S_LEN) return -1;
 435   va_end (ap);
 436   return  rs232_writem(fd, mode, s, cnt);
 437 }
 438