Advertisement
Guest User

Untitled

a guest
Mar 26th, 2019
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.44 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <getopt.h>
  3. #include <stdlib.h>
  4. #include <stdint.h>
  5. #include <string.h>
  6. #include <termios.h>
  7. #include <fcntl.h>
  8. #include <unistd.h>
  9. #include <sys/stat.h>
  10.  
  11. //Flags
  12. #define F_TRANSFER 0x01
  13. #define F_RECEIVE 0x02
  14. #define F_CRC 0x04
  15. #define F_CRCCONFIRMED 0x10
  16. #define F_NORMALCONFIR 0x20
  17. #define F_STOP 0x40
  18. #define F_VERBOSE 0x80
  19. #define F_NONE 0x00
  20.  
  21. #define VERBOSE (params.flags & F_VERBOSE)
  22.  
  23. //Parity bit
  24. #define N 0
  25. #define E 1
  26. #define O 2
  27. #define M 3
  28. #define S 4
  29.  
  30. //Errors
  31. #define E_ERROR 1
  32. #define E_NOTIMPLEMENTED 2
  33. #define E_CANCEL 3
  34.  
  35. //Special chars
  36. #define SOH 0x01
  37. #define EOT 0x04
  38. #define ACK 0x06
  39. #define NAK 0x15
  40. #define CAN 0x18
  41. #define SUB 0x1A
  42.  
  43. typedef struct s_params
  44. {
  45. uint8_t flags;
  46. char *device;
  47. char *filename;
  48. int baudrate;
  49. int databits;
  50. uint8_t parity;
  51. } Params;
  52.  
  53. typedef enum istimeout
  54. {
  55. TIMEOUT = 0,
  56. NOTOUT
  57. } ISTIMEOUT;
  58.  
  59. /*
  60. * initialize serial port
  61. */
  62. int portInit(Params* params, char* pname);
  63.  
  64. /*
  65. * convert baudrate as integer to one of the valid consts;
  66. * when not valid speed given returns (speed_t)-1
  67. */
  68. speed_t intToSpeed(int baud);
  69.  
  70. /*
  71. * returns simple xmodem checksum for BUF of length N
  72. */
  73. uint8_t checksum(char *buf, int n);
  74.  
  75. /*
  76. * returns crc-xmodem for BUF of length N
  77. */
  78. uint16_t crc16(char *buf, int n);
  79.  
  80. /*
  81. * wait for data read on FD, then return TIMEOUT after SECONDS or NOTOUT if data ready
  82. */
  83. ISTIMEOUT wait_max(int fd, int seconds);
  84.  
  85. int main(int argc, char **argv)
  86. {
  87. //default values
  88. int opt;
  89. Params params = {F_NONE, NULL, NULL, 9600, 8, N};
  90. params.device = (char*)malloc(256);
  91. params.device[0] = '\0';
  92. params.filename = (char*)malloc(256);
  93.  
  94. //params from argv
  95. while ((opt = getopt(argc, argv, "cp:b:trd:hv")) != -1) {
  96. switch (opt) {
  97. case 'r':
  98. //receiver mode
  99. params.flags |= F_RECEIVE;
  100. break;
  101. case 't':
  102. //transmitter mode
  103. params.flags |= F_TRANSFER;
  104. break;
  105. case 'd':
  106. //device path
  107. strcpy(params.device,optarg);
  108. params.device = realloc(params.device,strlen(params.device) + 1);
  109. break;
  110. case 'b':
  111. //baudrate
  112. params.baudrate = strtol(optarg,NULL,10);
  113. if(intToSpeed(params.baudrate) == (speed_t)-1)
  114. {
  115. fprintf(stderr,"%s: Wrong baudrate given!\n",argv[0]);
  116. return 1;
  117. }
  118. break;
  119. case 'p':
  120. //connection parameters
  121. if(strlen(optarg)!=3)
  122. {
  123. fprintf(stderr,
  124. "%s: Conection params should be given as [Data][Parity][Stop],\n"
  125. "eg. 8N1 means 8 data bits, no parity bit and 1 stop bit\n",
  126. argv[0]);
  127. return 1;
  128. }
  129. if(optarg[0]>='5' && optarg[0]<='8')
  130. params.databits = optarg[0] & ~0x30;
  131. else
  132. {
  133. fprintf(stderr,
  134. "%s: Conection params should be given as [Data][Parity][Stop],\n"
  135. "eg. 8N1 means 8 data bits, no parity bit and 1 stop bit\n",
  136. argv[0]);
  137. return 1;
  138. }
  139. switch(optarg[1])
  140. {
  141. case 'n':
  142. case 'N':
  143. params.parity = N;
  144. break;
  145. case 'e':
  146. case 'E':
  147. params.parity = E;
  148. break;
  149. case 'o':
  150. case 'O':
  151. params.parity = O;
  152. break;
  153. case 'm':
  154. case 'M':
  155. params.parity = M;
  156. break;
  157. case 's':
  158. case 'S':
  159. params.parity = S;
  160. break;
  161. default:
  162. fprintf(stderr,
  163. "%s: Conection params should be given as [Data][Parity][Stop],\n"
  164. "eg. 8N1 means 8 data bits, no parity bit and 1 stop bit\n",
  165. argv[0]);
  166. return 1;
  167. }
  168. if(optarg[2] == '1')
  169. params.flags &= ~F_STOP;
  170. else if(optarg[2] == '2')
  171. params.flags |= F_STOP;
  172. else
  173. {
  174. fprintf(stderr,
  175. "%s: Conection params should be given as [Data][Parity][Stop],\n"
  176. "eg. 8N1 means 8 data bits, no parity bit and 1 stop bit\n",
  177. argv[0]);
  178. return 1;
  179. }
  180. break;
  181. case 'c':
  182. //crc16 mode
  183. params.flags |= F_CRC;
  184. break;
  185. case 'v':
  186. params.flags |= F_VERBOSE;
  187. break;
  188. default: /* '?' */
  189. fprintf(stderr, "Usage: %s [-tr] -d device filename\n",
  190. argv[0]);
  191. return 1;
  192. }
  193. }
  194.  
  195. //check if given data is valid
  196. if(strlen(params.device) == 0)
  197. {
  198. fprintf(stderr, "Usage: %s [-tr] -d device filename\n",
  199. argv[0]);
  200. return 1;
  201. }
  202.  
  203. if (optind >= argc) {
  204. fprintf(stderr, "%s: Expected argument after options\n",argv[0]);
  205. return 1;
  206. }
  207.  
  208. if(params.flags&F_TRANSFER && params.flags&F_RECEIVE)
  209. {
  210. fprintf(stderr, "%s: You cannot transfer and receive at the same time\n", argv[0]);
  211. return 1;
  212. }
  213.  
  214. strcpy(params.filename, argv[optind]);
  215. params.filename = realloc(params.filename, strlen(params.filename) + 1);
  216.  
  217. //init serial device
  218. int dfd = 0;
  219. if((dfd = portInit(&params,argv[0])) == -1)
  220. {
  221. fprintf(stderr, "%s: Port initialization failed! Do you have rights to open it?\n", argv[0]);
  222. return 1;
  223. }
  224.  
  225. //open file to transfer
  226. int ffd = 0;
  227. int oflag = 0;
  228. mode_t perm = S_IRWXU | S_IRWXG | S_IRWXO;
  229. if(params.flags & F_TRANSFER)
  230. oflag = O_RDONLY;
  231. else
  232. oflag = O_WRONLY | O_CREAT/* | O_NONBLOCK*/ | O_TRUNC;
  233. if((ffd = open(params.filename, oflag, perm)) == -1)
  234. {
  235. fprintf(stderr, "%s: Cannot open file! Do you have rights to open it?\n", argv[0]);
  236. return 1;
  237. }
  238.  
  239. //do the transfer!
  240. if(params.flags&F_TRANSFER)
  241. {
  242. if(VERBOSE)
  243. printf("Transmit mode; device: %s; filename: %s\n", params.device, params.filename);
  244. //transmitter
  245. params.flags &= ~F_CRC; //turn off CRC flag
  246. char *buf = malloc(256);
  247. //decide if we will use checksum whether crc16
  248. while((buf[0] != NAK) && (buf[0] != 'C'))
  249. read(dfd,buf,256);
  250. char *packet;
  251. if(buf[0] == 'C')
  252. {
  253. params.flags |= F_CRC;
  254. packet = malloc(133);
  255. }
  256. else
  257. packet = malloc(132);
  258. #ifdef DEBUG
  259. printf("got: %c\n",buf[0]);
  260. #endif //DEBUG
  261. free(buf);
  262. buf = NULL;
  263. packet[0] = SOH;
  264. packet[1] = (char)1;
  265. packet[2] = (char)254;
  266. packet[131] = '\0';
  267. ssize_t size = 0;
  268. do
  269. {
  270. buf = malloc(128);
  271. size = read(ffd,buf,128);
  272. memset(packet+3,SUB,128);
  273. strncpy(packet+3,buf,size);
  274. if(params.flags & F_CRC)
  275. {
  276. uint16_t crc = crc16(packet+3, 128);
  277. packet[131] = (char)(crc / 0x100);
  278. packet[132] = (char)(crc % 0x100);
  279. }
  280. else
  281. packet[131] = checksum(packet+3,128);
  282. free(buf);
  283. buf = malloc(256);
  284. int i = 0;
  285. for(i = 0; i < 10; i++)
  286. {
  287. #ifdef DEBUG
  288. int j;
  289. for(j = 0; j < 133; j++)
  290. printf("%02X ",(unsigned char)packet[j]);
  291. printf("\n");
  292. #endif //DEBUG
  293. write(dfd,packet,(params.flags & F_CRC) ? 133 : 132);
  294. read(dfd,buf,256);
  295. if(buf[0] == ACK)
  296. break;
  297. if(buf[0] == CAN)
  298. {
  299. fprintf(stderr, "%s: Cancel received! Exiting...",argv[0]);
  300. return E_CANCEL;
  301. }
  302. fprintf(stderr, "%s: Did I just received a NAK?? It was error No. %d\n",argv[0], i+1);
  303. }
  304. if(buf[0] == NAK)
  305. {
  306. fprintf(stderr, "%s: Transfer failed! Received 10 NAKs in a row\n", argv[0]);
  307. char can = CAN;
  308. write(dfd,&can,1);
  309. return 1;
  310. }
  311. //packet sent
  312. packet[1] += 1;
  313. packet[2] = 255 - packet[1];
  314. free(buf);
  315. }
  316. while(size!=0);
  317. char eot = EOT;
  318. char ans = '\0';
  319. while(ans!=ACK)
  320. {
  321. write(dfd,&eot,1);
  322. read(dfd,&ans,1);
  323. }
  324. close(ffd);
  325. close(dfd);
  326. }
  327. else if(params.flags&F_RECEIVE)
  328. {
  329. if(VERBOSE)
  330. printf("Receive mode; device: %s; filename: %s\n", params.device, params.filename);
  331. //receiver
  332. char nak = NAK;
  333. char c = 'C';
  334. /*{
  335. //clear buffer
  336. char nth = '\0';
  337. int cnt;
  338. while(cnt = read(dfd,&nth,1));
  339. }*/
  340. params.flags &= ~F_CRCCONFIRMED;
  341. params.flags &= ~F_NORMALCONFIR;
  342. if(params.flags & F_CRC)
  343. {
  344. int j;
  345. for(j = 0; j < 3; j++)
  346. {
  347. //send 'C'
  348. write(dfd,&c,1);
  349. if(wait_max(dfd,3) == NOTOUT)
  350. break;
  351. #ifdef DEBUG
  352. fprintf(stderr, "%s: CRC mode: No. %d failed!\n", argv[0], j+1);
  353. #endif //DEBUG
  354. }
  355. if(j!=3)
  356. {
  357. params.flags |= F_CRCCONFIRMED;
  358. }
  359. #ifdef DEBUG
  360. else
  361. fprintf(stderr, "%s: CRC mode unavailable!\n", argv[0]);
  362. #endif //DEBUG
  363. }
  364. if(!(params.flags & F_CRCCONFIRMED))
  365. {
  366. int i;
  367. for(i = 0; i < ((params.flags & F_CRC) ? 5 : 6); i++)
  368. {
  369. //send NAKs
  370. write(dfd,&nak,1);
  371. if(wait_max(dfd,10) == NOTOUT)
  372. break;
  373. #ifdef DEBUG
  374. fprintf(stderr, "%s: No. %d failed!\n", argv[0], i+1);
  375. #endif //DEBUG
  376. }
  377. if(i!=((params.flags & F_CRC) ? 5 : 6))
  378. params.flags |= F_NORMALCONFIR;
  379. }
  380. if(!(params.flags & F_CRCCONFIRMED) && !(params.flags & F_NORMALCONFIR))
  381. {
  382. //no response, give up
  383. fprintf(stderr, "%s: After one minute of waiting, no response has been received. I'm giving up!\n", argv[0]);
  384. return 1;
  385. }
  386. //sender understood one of the methods
  387. int EXPLEN = ((params.flags & F_CRCCONFIRMED) ? 133: 132);
  388. char *buf = malloc(EXPLEN);
  389. int length = 0;
  390. int blkcnt = 0;
  391. while((length = read(dfd,buf,EXPLEN)) == EXPLEN)
  392. {
  393. // if(buf[0] == EOT)
  394. // break;
  395. #ifdef DEBUG
  396. int i;
  397. for(i = 0; i < EXPLEN; i++)
  398. printf("%02X ",(unsigned char)buf[i]);
  399. printf("\n");
  400. #endif //DEBUG
  401. //check crc/checksum
  402. uint16_t sum = 0;
  403. uint16_t expected = 0;
  404. sum = ((params.flags & F_CRCCONFIRMED) ? crc16(buf+3,128) : (uint16_t)checksum(buf+3,128));
  405. expected = ((params.flags & F_CRCCONFIRMED) ? ((buf[131] * 0x100) + (uint8_t)buf[132]) : (uint8_t)buf[131]);
  406. if(
  407. (sum == expected) &&
  408. (buf[0] == SOH) &&
  409. (buf[1] == (char)(blkcnt+1)) &&
  410. (buf[2] == (char)(0xFF - (blkcnt+1)))
  411. )
  412. {
  413. //checksums matched
  414. char ack = ACK;
  415. write(dfd,&ack,1);
  416. //write data to file
  417. int i;
  418. int lng = 128;
  419. for(i = 130; i > 2; i--)
  420. if(buf[i] == SUB)
  421. lng--;
  422. else
  423. break;
  424. write(ffd,buf+3,lng);
  425. }
  426. else
  427. {
  428. //wrong checksum
  429. #ifdef DEBUG
  430. printf("checksum: %02X, expected: %02X\n",(uint16_t)sum, (uint16_t)expected);
  431. #endif //DEBUG
  432. char nak = NAK;
  433. write(dfd,&nak,1);
  434. continue;
  435. }
  436. blkcnt++;
  437. }
  438. if(buf[0] == EOT)
  439. {
  440. //transmission successful, close files
  441. if(VERBOSE)
  442. printf("Transmission finished! %d blocks received.\n",blkcnt+1);
  443. char ack = ACK;
  444. write(dfd,&ack,1);
  445. close(dfd);
  446. close(ffd);
  447. free(buf);
  448. }
  449. else
  450. {
  451. fprintf(stderr,"Transmission failed on block no. %d\n",blkcnt+1);
  452. free(buf);
  453. return E_ERROR;
  454. }
  455. }
  456. else
  457. {
  458. fprintf(stderr, "%s: You need to define if you want to send or receive\n", argv[0]);
  459. return 1;
  460. }
  461.  
  462. return EXIT_SUCCESS;
  463. }
  464.  
  465. uint8_t checksum(char *buf, int n)
  466. {
  467. int i =0;
  468. uint8_t ret = 0;
  469. for(i = 0; i < n; i++)
  470. {
  471. ret += buf[i];
  472. }
  473. return ret;
  474. }
  475.  
  476. uint16_t crc16(char *buf, int n)
  477. {
  478. uint16_t crc = 0;
  479. int i;
  480. while (n--)
  481. {
  482. crc ^= (unsigned short) (*buf++)<<8;
  483. for ( i=0 ; i<8 ; ++i ) {
  484. if (crc & 0x8000)
  485. crc = (crc << 1) ^ 0x1021;
  486. else
  487. crc <<= 1;
  488. }
  489. }
  490. return crc;
  491. }
  492.  
  493. ISTIMEOUT wait_max(int fd, int seconds)
  494. {
  495. // Initialize file descriptor sets
  496. fd_set read_fds, write_fds, except_fds;
  497. FD_ZERO(&read_fds);
  498. FD_ZERO(&write_fds);
  499. FD_ZERO(&except_fds);
  500. FD_SET(fd, &read_fds);
  501.  
  502. // Set timeout to 1.0 seconds
  503. struct timeval timeout;
  504. timeout.tv_sec = seconds;
  505. timeout.tv_usec = 0;
  506.  
  507. /*
  508. * Wait for input to become ready or until the time out; the first parameter is
  509. * 1 more than the largest file descriptor in any of the sets
  510. */
  511. if (select(fd + 1, &read_fds, &write_fds, &except_fds, &timeout) == 1)
  512. {
  513. //returned
  514. return NOTOUT;
  515. }
  516. else
  517. {
  518. //timeout
  519. return TIMEOUT;
  520. }
  521. }
  522.  
  523. int portInit(Params *params, char *pname)
  524. {
  525. int fd = open(params->device,O_RDWR|O_NOCTTY);
  526. if( fd== -1)
  527. {
  528. fprintf(stderr,"%s: Error: failed to open terminal device\n",pname);
  529. return -1;
  530. }
  531. struct termios attr;
  532. if(tcgetattr(fd,&attr))
  533. {
  534. fprintf(stderr,"%s: Error: failed to get tty attributes\n",pname);
  535. return -2;
  536. }
  537. #ifdef DEBUG
  538. fprintf(stderr,"%s: Terminal device opened: %s!\n",pname, params->device);
  539. #endif //DEBUG
  540. cfsetospeed(&attr,intToSpeed(params->baudrate)); //output baud rate
  541. cfsetispeed(&attr,intToSpeed(params->baudrate)); //input baud rate
  542. attr.c_cflag &= ~CRTSCTS; //hardware flow control off
  543. if(params->flags&F_STOP)
  544. attr.c_cflag &= ~CSTOPB; //1 stop bit
  545. if(params->parity!=N)
  546. attr.c_cflag |= PARENB; //parity check
  547. switch(params->parity)
  548. {
  549. case N:
  550. attr.c_cflag &= ~PARENB;
  551. break; //no parity?
  552. case E:
  553. attr.c_cflag &= ~PARODD;
  554. break; //parity even
  555. case O:
  556. attr.c_cflag |= PARODD;
  557. break; //parity odd
  558. case M:
  559. attr.c_cflag |= PARODD|CMSPAR;
  560. break; //parity mark
  561. case S:
  562. attr.c_cflag |= CMSPAR;
  563. break; //parity space
  564. default:
  565. fprintf(stderr,"%s: Parity mode not supported!\n",pname);
  566. return -3;
  567. }
  568. attr.c_cflag &= ~CSIZE;
  569. switch(params->databits) //data bits
  570. {
  571. case 5:
  572. attr.c_cflag |= CS5;
  573. break;
  574. case 6:
  575. attr.c_cflag |= CS6;
  576. break;
  577. case 7:
  578. attr.c_cflag |= CS7;
  579. break;
  580. case 8:
  581. attr.c_cflag |= CS8;
  582. break;
  583. }
  584. if(tcsetattr(fd,TCSANOW,&attr))
  585. {
  586. fprintf(stderr,"%s: Error: failed to set tty attributes\n",pname);
  587. return -4;
  588. }
  589. return fd;
  590. }
  591.  
  592. speed_t intToSpeed(int baud)
  593. {
  594. int bauds[] = {
  595. 0,
  596. 50,
  597. 75,
  598. 110,
  599. 134,
  600. 150,
  601. 200,
  602. 300,
  603. 600,
  604. 1200,
  605. 1800,
  606. 2400,
  607. 4800,
  608. 9600,
  609. 19200,
  610. 38400,
  611. 57600,
  612. 115200,
  613. 230400
  614. };
  615. speed_t Bauds[] = {
  616. B0,
  617. B50,
  618. B75,
  619. B110,
  620. B134,
  621. B150,
  622. B200,
  623. B300,
  624. B600,
  625. B1200,
  626. B1800,
  627. B2400,
  628. B4800,
  629. B9600,
  630. B19200,
  631. B38400,
  632. B57600,
  633. B115200,
  634. B230400
  635. };
  636. int i;
  637. for(i = 0; i < (sizeof(bauds)/sizeof(int)); i++)
  638. {
  639. if(bauds[i]==baud)
  640. return Bauds[i];
  641. }
  642. return (speed_t)-1;
  643. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement