rs232_fn.c
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 |