SHARE
TWEET

Untitled

a guest Mar 26th, 2019 89 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top