/*********************************************************** Chris Foster and Jeff Puchalski ECE 476 Spring 2003 Project - Xmodem Protocol Test ***********************************************************/ #include #include #include /* States */ #define IDLE 1 #define RECV 2 #define DONE 3 /* Xxmodem codes */ #define SOH 0x01 // start of header #define EOT 0x04 // end of transmission #define ACK 0x06 // acknowledgement #define NAK 0x15 // negative acknowledgement #define CAN 0x18 // cancel #define EOF 0x1a // end of file #define PACKET_SIZE 128 #define Rxmode 1 #define Ready 2 #define Baud 103 // 9600 baud w/ 16 MHz crystal /* Xxmodem packet format Byte Description 1 SOH (start of header) 2 Packet number 3 ~(Packet number) 4-131 Packet data (128 bytes) 132 checksum */ // Global variables unsigned char packet_num; unsigned int byte_num; unsigned char eot_num; unsigned char xmode; unsigned char buf[PACKET_SIZE]; // stores the current packet being recieved unsigned char data[PACKET_SIZE]; unsigned char data_loaded; unsigned char state; unsigned char checksum; void x_init(void) { unsigned char i; byte_num = 0; packet_num = 1; eot_num = 0; OCR1A = 313; TCNT1 = 0; xmode = Ready; for (i=0; i < PACKET_SIZE; i++) buf[i] = data[i] = 0; } void x_receive(void) { unsigned char c; while (xmode == Rxmode) { if (byte_num == 0 && packet_num == 1) { delay_ms(20000); UDR = NAK; byte_num = 1; } else if (UCSRA.7) { c = UDR; // current byte sent if (byte_num == 1) { // SOH switch (c) { case SOH : // have the start byte checksum = 0; byte_num++; break; case EOT : // send a NAK, and expect a EOT as the next byte // we do not increment byte_num because we want // to check if the next byte is also a EOT if (eot_num == 0) { // 1st EOT byte eot_num++; while (!UCSRA.5); // wait for output buffer UDR = NAK; } else { // 2nd EOT byte // need to end transmission // turn off Xmodem transfer eot_num = 2; while (!UCSRA.5); UDR = ACK; xmode = Ready; return; } break; default: byte_num = 1; break; } continue; } if (byte_num == 2) { // packet_num if (c == packet_num) byte_num++; else byte_num = 1; continue; } if (byte_num == 3) { // ~(packet_num) if ((c + packet_num) == 255) byte_num++; else byte_num = 1; continue; } if ((byte_num >= 4) && (byte_num < (4 + PACKET_SIZE))) { // packet data buf[byte_num-4] = c; checksum += c; // add to the checksum calculation byte_num++; continue; } if (byte_num == (4 + PACKET_SIZE)) { // checksum byte_num = 1; // packet ended if (checksum == c) { // checksum correct, accept packet if (packet_num == 1) strncpy(data,buf,PACKET_SIZE); packet_num++; while (!UCSRA.5); UDR = ACK; } else { // checksum is wrong, need to resend packet while (!UCSRA.5); UDR = NAK; } data_loaded = 1; continue; } } } } void uart_echo(char *str) { char *temp; temp = str; // xmodem protocol uses ^Z for padding packets while (*temp != 0x1a) { // 0x1a = SUB (substitute, ^Z) while (!UCSRA.5); UDR = *temp; temp++; } } void main(void) { unsigned char c; // set up the ports DDRD=0x00; // PORT C is the UART serial port DDRB=0xff; // PORT B is LEDs PORTB=0x00; // set up the UART UBRRH = Baud >> 8; UBRRL = Baud; UCSRB = 0x18; // enable receiver and transmitter UCSRC = 0x86; // async mode, 1 stop bit, 8-bit char size state = IDLE; data_loaded = 0; x_init(); while (1) { PORTB= ~state; switch (state) { case IDLE : // poll RX done bit if (UCSRA.7) { c = UDR; UDR = c; if (c == 'l' && xmode == Ready) { state = RECV; xmode = Rxmode; x_receive(); } } break; case RECV : while (!data_loaded); state = DONE; break; case DONE : uart_echo(data); while (1); break; } } }