Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <getopt.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <string.h>
- #include <termios.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <sys/stat.h>
- //Flags
- #define F_TRANSFER 0x01
- #define F_RECEIVE 0x02
- #define F_CRC 0x04
- #define F_CRCCONFIRMED 0x10
- #define F_NORMALCONFIR 0x20
- #define F_STOP 0x40
- #define F_VERBOSE 0x80
- #define F_NONE 0x00
- #define VERBOSE (params.flags & F_VERBOSE)
- //Parity bit
- #define N 0
- #define E 1
- #define O 2
- #define M 3
- #define S 4
- //Errors
- #define E_ERROR 1
- #define E_NOTIMPLEMENTED 2
- #define E_CANCEL 3
- //Special chars
- #define SOH 0x01
- #define EOT 0x04
- #define ACK 0x06
- #define NAK 0x15
- #define CAN 0x18
- #define SUB 0x1A
- typedef struct s_params
- {
- uint8_t flags;
- char *device;
- char *filename;
- int baudrate;
- int databits;
- uint8_t parity;
- } Params;
- typedef enum istimeout
- {
- TIMEOUT = 0,
- NOTOUT
- } ISTIMEOUT;
- /*
- * initialize serial port
- */
- int portInit(Params* params, char* pname);
- /*
- * convert baudrate as integer to one of the valid consts;
- * when not valid speed given returns (speed_t)-1
- */
- speed_t intToSpeed(int baud);
- /*
- * returns simple xmodem checksum for BUF of length N
- */
- uint8_t checksum(char *buf, int n);
- /*
- * returns crc-xmodem for BUF of length N
- */
- uint16_t crc16(char *buf, int n);
- /*
- * wait for data read on FD, then return TIMEOUT after SECONDS or NOTOUT if data ready
- */
- ISTIMEOUT wait_max(int fd, int seconds);
- int main(int argc, char **argv)
- {
- //default values
- int opt;
- Params params = {F_NONE, NULL, NULL, 9600, 8, N};
- params.device = (char*)malloc(256);
- params.device[0] = '\0';
- params.filename = (char*)malloc(256);
- //params from argv
- while ((opt = getopt(argc, argv, "cp:b:trd:hv")) != -1) {
- switch (opt) {
- case 'r':
- //receiver mode
- params.flags |= F_RECEIVE;
- break;
- case 't':
- //transmitter mode
- params.flags |= F_TRANSFER;
- break;
- case 'd':
- //device path
- strcpy(params.device,optarg);
- params.device = realloc(params.device,strlen(params.device) + 1);
- break;
- case 'b':
- //baudrate
- params.baudrate = strtol(optarg,NULL,10);
- if(intToSpeed(params.baudrate) == (speed_t)-1)
- {
- fprintf(stderr,"%s: Wrong baudrate given!\n",argv[0]);
- return 1;
- }
- break;
- case 'p':
- //connection parameters
- if(strlen(optarg)!=3)
- {
- fprintf(stderr,
- "%s: Conection params should be given as [Data][Parity][Stop],\n"
- "eg. 8N1 means 8 data bits, no parity bit and 1 stop bit\n",
- argv[0]);
- return 1;
- }
- if(optarg[0]>='5' && optarg[0]<='8')
- params.databits = optarg[0] & ~0x30;
- else
- {
- fprintf(stderr,
- "%s: Conection params should be given as [Data][Parity][Stop],\n"
- "eg. 8N1 means 8 data bits, no parity bit and 1 stop bit\n",
- argv[0]);
- return 1;
- }
- switch(optarg[1])
- {
- case 'n':
- case 'N':
- params.parity = N;
- break;
- case 'e':
- case 'E':
- params.parity = E;
- break;
- case 'o':
- case 'O':
- params.parity = O;
- break;
- case 'm':
- case 'M':
- params.parity = M;
- break;
- case 's':
- case 'S':
- params.parity = S;
- break;
- default:
- fprintf(stderr,
- "%s: Conection params should be given as [Data][Parity][Stop],\n"
- "eg. 8N1 means 8 data bits, no parity bit and 1 stop bit\n",
- argv[0]);
- return 1;
- }
- if(optarg[2] == '1')
- params.flags &= ~F_STOP;
- else if(optarg[2] == '2')
- params.flags |= F_STOP;
- else
- {
- fprintf(stderr,
- "%s: Conection params should be given as [Data][Parity][Stop],\n"
- "eg. 8N1 means 8 data bits, no parity bit and 1 stop bit\n",
- argv[0]);
- return 1;
- }
- break;
- case 'c':
- //crc16 mode
- params.flags |= F_CRC;
- break;
- case 'v':
- params.flags |= F_VERBOSE;
- break;
- default: /* '?' */
- fprintf(stderr, "Usage: %s [-tr] -d device filename\n",
- argv[0]);
- return 1;
- }
- }
- //check if given data is valid
- if(strlen(params.device) == 0)
- {
- fprintf(stderr, "Usage: %s [-tr] -d device filename\n",
- argv[0]);
- return 1;
- }
- if (optind >= argc) {
- fprintf(stderr, "%s: Expected argument after options\n",argv[0]);
- return 1;
- }
- if(params.flags&F_TRANSFER && params.flags&F_RECEIVE)
- {
- fprintf(stderr, "%s: You cannot transfer and receive at the same time\n", argv[0]);
- return 1;
- }
- strcpy(params.filename, argv[optind]);
- params.filename = realloc(params.filename, strlen(params.filename) + 1);
- //init serial device
- int dfd = 0;
- if((dfd = portInit(¶ms,argv[0])) == -1)
- {
- fprintf(stderr, "%s: Port initialization failed! Do you have rights to open it?\n", argv[0]);
- return 1;
- }
- //open file to transfer
- int ffd = 0;
- int oflag = 0;
- mode_t perm = S_IRWXU | S_IRWXG | S_IRWXO;
- if(params.flags & F_TRANSFER)
- oflag = O_RDONLY;
- else
- oflag = O_WRONLY | O_CREAT/* | O_NONBLOCK*/ | O_TRUNC;
- if((ffd = open(params.filename, oflag, perm)) == -1)
- {
- fprintf(stderr, "%s: Cannot open file! Do you have rights to open it?\n", argv[0]);
- return 1;
- }
- //do the transfer!
- if(params.flags&F_TRANSFER)
- {
- if(VERBOSE)
- printf("Transmit mode; device: %s; filename: %s\n", params.device, params.filename);
- //transmitter
- params.flags &= ~F_CRC; //turn off CRC flag
- char *buf = malloc(256);
- //decide if we will use checksum whether crc16
- while((buf[0] != NAK) && (buf[0] != 'C'))
- read(dfd,buf,256);
- char *packet;
- if(buf[0] == 'C')
- {
- params.flags |= F_CRC;
- packet = malloc(133);
- }
- else
- packet = malloc(132);
- #ifdef DEBUG
- printf("got: %c\n",buf[0]);
- #endif //DEBUG
- free(buf);
- buf = NULL;
- packet[0] = SOH;
- packet[1] = (char)1;
- packet[2] = (char)254;
- packet[131] = '\0';
- ssize_t size = 0;
- do
- {
- buf = malloc(128);
- size = read(ffd,buf,128);
- memset(packet+3,SUB,128);
- strncpy(packet+3,buf,size);
- if(params.flags & F_CRC)
- {
- uint16_t crc = crc16(packet+3, 128);
- packet[131] = (char)(crc / 0x100);
- packet[132] = (char)(crc % 0x100);
- }
- else
- packet[131] = checksum(packet+3,128);
- free(buf);
- buf = malloc(256);
- int i = 0;
- for(i = 0; i < 10; i++)
- {
- #ifdef DEBUG
- int j;
- for(j = 0; j < 133; j++)
- printf("%02X ",(unsigned char)packet[j]);
- printf("\n");
- #endif //DEBUG
- write(dfd,packet,(params.flags & F_CRC) ? 133 : 132);
- read(dfd,buf,256);
- if(buf[0] == ACK)
- break;
- if(buf[0] == CAN)
- {
- fprintf(stderr, "%s: Cancel received! Exiting...",argv[0]);
- return E_CANCEL;
- }
- fprintf(stderr, "%s: Did I just received a NAK?? It was error No. %d\n",argv[0], i+1);
- }
- if(buf[0] == NAK)
- {
- fprintf(stderr, "%s: Transfer failed! Received 10 NAKs in a row\n", argv[0]);
- char can = CAN;
- write(dfd,&can,1);
- return 1;
- }
- //packet sent
- packet[1] += 1;
- packet[2] = 255 - packet[1];
- free(buf);
- }
- while(size!=0);
- char eot = EOT;
- char ans = '\0';
- while(ans!=ACK)
- {
- write(dfd,&eot,1);
- read(dfd,&ans,1);
- }
- close(ffd);
- close(dfd);
- }
- else if(params.flags&F_RECEIVE)
- {
- if(VERBOSE)
- printf("Receive mode; device: %s; filename: %s\n", params.device, params.filename);
- //receiver
- char nak = NAK;
- char c = 'C';
- /*{
- //clear buffer
- char nth = '\0';
- int cnt;
- while(cnt = read(dfd,&nth,1));
- }*/
- params.flags &= ~F_CRCCONFIRMED;
- params.flags &= ~F_NORMALCONFIR;
- if(params.flags & F_CRC)
- {
- int j;
- for(j = 0; j < 3; j++)
- {
- //send 'C'
- write(dfd,&c,1);
- if(wait_max(dfd,3) == NOTOUT)
- break;
- #ifdef DEBUG
- fprintf(stderr, "%s: CRC mode: No. %d failed!\n", argv[0], j+1);
- #endif //DEBUG
- }
- if(j!=3)
- {
- params.flags |= F_CRCCONFIRMED;
- }
- #ifdef DEBUG
- else
- fprintf(stderr, "%s: CRC mode unavailable!\n", argv[0]);
- #endif //DEBUG
- }
- if(!(params.flags & F_CRCCONFIRMED))
- {
- int i;
- for(i = 0; i < ((params.flags & F_CRC) ? 5 : 6); i++)
- {
- //send NAKs
- write(dfd,&nak,1);
- if(wait_max(dfd,10) == NOTOUT)
- break;
- #ifdef DEBUG
- fprintf(stderr, "%s: No. %d failed!\n", argv[0], i+1);
- #endif //DEBUG
- }
- if(i!=((params.flags & F_CRC) ? 5 : 6))
- params.flags |= F_NORMALCONFIR;
- }
- if(!(params.flags & F_CRCCONFIRMED) && !(params.flags & F_NORMALCONFIR))
- {
- //no response, give up
- fprintf(stderr, "%s: After one minute of waiting, no response has been received. I'm giving up!\n", argv[0]);
- return 1;
- }
- //sender understood one of the methods
- int EXPLEN = ((params.flags & F_CRCCONFIRMED) ? 133: 132);
- char *buf = malloc(EXPLEN);
- int length = 0;
- int blkcnt = 0;
- while((length = read(dfd,buf,EXPLEN)) == EXPLEN)
- {
- // if(buf[0] == EOT)
- // break;
- #ifdef DEBUG
- int i;
- for(i = 0; i < EXPLEN; i++)
- printf("%02X ",(unsigned char)buf[i]);
- printf("\n");
- #endif //DEBUG
- //check crc/checksum
- uint16_t sum = 0;
- uint16_t expected = 0;
- sum = ((params.flags & F_CRCCONFIRMED) ? crc16(buf+3,128) : (uint16_t)checksum(buf+3,128));
- expected = ((params.flags & F_CRCCONFIRMED) ? ((buf[131] * 0x100) + (uint8_t)buf[132]) : (uint8_t)buf[131]);
- if(
- (sum == expected) &&
- (buf[0] == SOH) &&
- (buf[1] == (char)(blkcnt+1)) &&
- (buf[2] == (char)(0xFF - (blkcnt+1)))
- )
- {
- //checksums matched
- char ack = ACK;
- write(dfd,&ack,1);
- //write data to file
- int i;
- int lng = 128;
- for(i = 130; i > 2; i--)
- if(buf[i] == SUB)
- lng--;
- else
- break;
- write(ffd,buf+3,lng);
- }
- else
- {
- //wrong checksum
- #ifdef DEBUG
- printf("checksum: %02X, expected: %02X\n",(uint16_t)sum, (uint16_t)expected);
- #endif //DEBUG
- char nak = NAK;
- write(dfd,&nak,1);
- continue;
- }
- blkcnt++;
- }
- if(buf[0] == EOT)
- {
- //transmission successful, close files
- if(VERBOSE)
- printf("Transmission finished! %d blocks received.\n",blkcnt+1);
- char ack = ACK;
- write(dfd,&ack,1);
- close(dfd);
- close(ffd);
- free(buf);
- }
- else
- {
- fprintf(stderr,"Transmission failed on block no. %d\n",blkcnt+1);
- free(buf);
- return E_ERROR;
- }
- }
- else
- {
- fprintf(stderr, "%s: You need to define if you want to send or receive\n", argv[0]);
- return 1;
- }
- return EXIT_SUCCESS;
- }
- uint8_t checksum(char *buf, int n)
- {
- int i =0;
- uint8_t ret = 0;
- for(i = 0; i < n; i++)
- {
- ret += buf[i];
- }
- return ret;
- }
- uint16_t crc16(char *buf, int n)
- {
- uint16_t crc = 0;
- int i;
- while (n--)
- {
- crc ^= (unsigned short) (*buf++)<<8;
- for ( i=0 ; i<8 ; ++i ) {
- if (crc & 0x8000)
- crc = (crc << 1) ^ 0x1021;
- else
- crc <<= 1;
- }
- }
- return crc;
- }
- ISTIMEOUT wait_max(int fd, int seconds)
- {
- // Initialize file descriptor sets
- fd_set read_fds, write_fds, except_fds;
- FD_ZERO(&read_fds);
- FD_ZERO(&write_fds);
- FD_ZERO(&except_fds);
- FD_SET(fd, &read_fds);
- // Set timeout to 1.0 seconds
- struct timeval timeout;
- timeout.tv_sec = seconds;
- timeout.tv_usec = 0;
- /*
- * Wait for input to become ready or until the time out; the first parameter is
- * 1 more than the largest file descriptor in any of the sets
- */
- if (select(fd + 1, &read_fds, &write_fds, &except_fds, &timeout) == 1)
- {
- //returned
- return NOTOUT;
- }
- else
- {
- //timeout
- return TIMEOUT;
- }
- }
- int portInit(Params *params, char *pname)
- {
- int fd = open(params->device,O_RDWR|O_NOCTTY);
- if( fd== -1)
- {
- fprintf(stderr,"%s: Error: failed to open terminal device\n",pname);
- return -1;
- }
- struct termios attr;
- if(tcgetattr(fd,&attr))
- {
- fprintf(stderr,"%s: Error: failed to get tty attributes\n",pname);
- return -2;
- }
- #ifdef DEBUG
- fprintf(stderr,"%s: Terminal device opened: %s!\n",pname, params->device);
- #endif //DEBUG
- cfsetospeed(&attr,intToSpeed(params->baudrate)); //output baud rate
- cfsetispeed(&attr,intToSpeed(params->baudrate)); //input baud rate
- attr.c_cflag &= ~CRTSCTS; //hardware flow control off
- if(params->flags&F_STOP)
- attr.c_cflag &= ~CSTOPB; //1 stop bit
- if(params->parity!=N)
- attr.c_cflag |= PARENB; //parity check
- switch(params->parity)
- {
- case N:
- attr.c_cflag &= ~PARENB;
- break; //no parity?
- case E:
- attr.c_cflag &= ~PARODD;
- break; //parity even
- case O:
- attr.c_cflag |= PARODD;
- break; //parity odd
- case M:
- attr.c_cflag |= PARODD|CMSPAR;
- break; //parity mark
- case S:
- attr.c_cflag |= CMSPAR;
- break; //parity space
- default:
- fprintf(stderr,"%s: Parity mode not supported!\n",pname);
- return -3;
- }
- attr.c_cflag &= ~CSIZE;
- switch(params->databits) //data bits
- {
- case 5:
- attr.c_cflag |= CS5;
- break;
- case 6:
- attr.c_cflag |= CS6;
- break;
- case 7:
- attr.c_cflag |= CS7;
- break;
- case 8:
- attr.c_cflag |= CS8;
- break;
- }
- if(tcsetattr(fd,TCSANOW,&attr))
- {
- fprintf(stderr,"%s: Error: failed to set tty attributes\n",pname);
- return -4;
- }
- return fd;
- }
- speed_t intToSpeed(int baud)
- {
- int bauds[] = {
- 0,
- 50,
- 75,
- 110,
- 134,
- 150,
- 200,
- 300,
- 600,
- 1200,
- 1800,
- 2400,
- 4800,
- 9600,
- 19200,
- 38400,
- 57600,
- 115200,
- 230400
- };
- speed_t Bauds[] = {
- B0,
- B50,
- B75,
- B110,
- B134,
- B150,
- B200,
- B300,
- B600,
- B1200,
- B1800,
- B2400,
- B4800,
- B9600,
- B19200,
- B38400,
- B57600,
- B115200,
- B230400
- };
- int i;
- for(i = 0; i < (sizeof(bauds)/sizeof(int)); i++)
- {
- if(bauds[i]==baud)
- return Bauds[i];
- }
- return (speed_t)-1;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement