|
//xmodem.c //Xmodem protocol //#include "serial.h" /* Xmodem protocol documentation transfer sequence 1.SOH byte 2.packet number (1 byte) 3.1's complement of packet number (1 byte) 4.the packet (128 bytes) 5.the checksum (1 byte) Reciever must 1.check packet number. 1st block has packet number 1. if the packet number is wrong, send a CAN byte to cancel transfer 2. add the packet number and the 1's complement to get 0xff, if not, cancel transfer(send CAN). 3.do CRC check, send NAK if failed 4.if nothing fails, add the recieved packet to the buffer */ //Init_Xmodem intializes the Xmodem file transfer void Init_Xmodem(void) begin unsigned int i; //unsigned char tmpstr[BUF_SIZE]; //send a 'C' //wait for reply (SOH byte) //if no reply after 1 sec, send another 'C' //wait for reply //if no reply after 1 sec, send at least 2 CAN bytes ENABLE_XRAM; dataheadptr = BUF_START_ADD; //need to verify that we can write to the sram location pointed by dataheadptr /* for (i=0;i<BUF_BYTE_SIZE;i++) begin dataheadptr[i]=(unsigned char) (i+1)%47; if (dataheadptr[i]!=(unsigned char) (i+1)%47) begin S_Printf("Error in SRAM, cannot write "); sprintf(tmpstr,"at addr %04x\n\r",&dataheadptr[i]); S_Print(tmpstr); end end */ //check other method for (i=0;i<BUF_BYTE_SIZE;i++) begin *dataheadptr = (unsigned char) (i+1)%129; if (*dataheadptr!=(unsigned char) (i+1)%129) begin //S_Printf("Error in SRAM method 2, cannot write "); //sprintf(tmpstr,"at addr %04x\n\r",dataheadptr); //S_Print(tmpstr); lcd_gotoxy(0,1);lcd_putsf("SRAM err"); end end dataheadptr = BUF_START_ADD; datatailptr = BUF_START_ADD; mp3ptr = datatailptr; //S_Printf("SRAM validated\n\r"); //OCR1A = 15625U;//1 sec at CK 1024 //might be possible to cut down purge time to 10ms //time for 1 packet(133bytes) at 115.2kbps //1 CK = 6.4E-5s OCR1A = 313;//20ms TCNT1 = 0;//reset //S_Printf("1 Second Timer set\n\r"); EOT_Number = 0; Packet_Number = 0; Byte_Number = 0; retry=0; end //X modem start void X_Start(void) begin unsigned char i;unsigned char tmpstr[BUF_SIZE]; i=0; Init_Xmodem(); Byte_Number = 1; Packet_Number = 1; sprintf(tmpstr,"dataheadptr %04x datatailptr %04x mp3ptr %04x\n\r",dataheadptr,datatailptr,mp3ptr); S_Print(tmpstr); sprintf(tmpstr,"START %04x END %04x\n\r",BUF_START_ADD, BUF_END_ADD); S_Print(tmpstr); S_Printf("Xmodem starts in 10 secs...\n\r"); delay_ms(10000U); USART1_RXCIDIS;//disable receive interrupt SERIAL_MODE = Xmode; lcd_clear(); while(!UDRE); UDR1='C'; lcd_gotoxy(0,0);lcd_putsf("Playing..."); end void X_Start_Instant(void) begin Init_Xmodem(); Byte_Number = 1; Packet_Number = 1; USART1_RXCIDIS;//disable receive interrupt SERIAL_MODE = Xmode; lcd_clear(); while(!UDRE); UDR1='C'; lcd_gotoxy(0,0);lcd_putsf("Playing..."); end //X_Activate_Purge() - only used by X_Receive //Following function sets purge to 1 //so that X_Recieve will dump rx chars for 1 sec void X_Activate_Purge(void) begin //debug lcd_gotoxy(14,0);lcd_putsf("P!"); retry++; if (retry>100) begin//purged too many times lcd_gotoxy(0,0);lcd_putsf("Err,Retry>100 "); delay_ms(1000U); SERIAL_MODE=Nmode; USART1_RXCIEN;//turn on receive return; end //set TIM1 to count 1 sec //enable TIM1_COMPA purge = 1;//set X_Recieve to dump chars TCNT1 = 0;//init TIM1 value to 0 OCR1A = 15625U;//set to 1 sec at prescalar 1024(16Mhz) //Timer 1, CTC match OCR1A set the following //WGM13=0,WGM12=1,WGM11=0,WGM10=0 SEC_TIMER_ISR_ON;//turn on TIM1_COMPA ISR SEC_COUNTER_ON;//turn on counter //Timer1 will occur after 1 sec and clear purge end //Receive the current packet /*Xmodem CRC packet format is as follows Byte Description 1 SOH, start of header 2 Packet number 3 ~(Packet number) 4-131 Packet data(128 bytes) 132-133 16 bit CRC, 132(Hi-Byte) */ //write the current packet to the data buffer #define BURST_SIZE 0x050 //0x0100 bit jerky //Send a burst of at most n bytes to mp3 player #define LEAD_SIZE BUF_BYTE_SIZE/2 //0x1000 old val, if buffer overtaking mp3ptr, give mp3ptr a lead #define WAIT_PACKET 8 //4, wait for n packets before starting playback void X_Write_Packet(void) begin unsigned int i; unsigned int j; unsigned char tmpstr[16], play; i=0; while(i<PACKET_SIZE) begin //dataheadptr points to the 1st free address //verify /* if (*dataheadptr!=buf[i]) begin lcd_gotoxy(0,1); lcd_putsf("X_Write_Pkt Err"); end lcd_gotoxy(0,1); sprintf(tmpstr,"h%04xm%04xt%04x",dataheadptr,mp3ptr,datatailptr); lcd_puts(tmpstr); */ *dataheadptr=buf[i];i++; ++dataheadptr; if (dataheadptr==BUF_END_ADD) dataheadptr=BUF_START_ADD;//else ++ if (dataheadptr==mp3ptr) begin//headptr overtaking mp3 ptr for (j=0;j<LEAD_SIZE;j++) begin while (!DATA_REQ); STA013_Audio_Send(*mp3ptr); if (++mp3ptr==BUF_END_ADD) mp3ptr=BUF_START_ADD;//else ++ end//for end else//if headptr is distant from mp3ptr if (Packet_Number>WAIT_PACKET) for (j=0;j<BURST_SIZE;j++) begin//this is problematic while(!DATA_REQ); //if (DATA_REQ) // begin STA013_Audio_Send(*mp3ptr); if (++mp3ptr==BUF_END_ADD) mp3ptr=BUF_START_ADD;//else ++ if (mp3ptr==dataheadptr) j=BURST_SIZE;//can't overtake dataheadptr // end //else// DATA_REQ not high // j=BURST_SIZE; end end//while end //Shows the contents of the data buffer void X_Show_Buffer(void) begin unsigned char *tmpdataptr, i, tmpstr[BUF_SIZE]; // dataheadptr stores the end address // datatailptr stores the start address tmpdataptr = datatailptr; while (tmpdataptr!=dataheadptr) begin for (i=0;i<BUF_SIZE-1;i++) begin if (tmpdataptr==dataheadptr) begin tmpstr[i]=0;//null terminate break; end tmpstr[i]=*tmpdataptr; tmpdataptr++; if (tmpdataptr==BUF_END_ADD) tmpdataptr = BUF_START_ADD; end tmpstr[BUF_SIZE-1]=0;//null terminate S_Print(tmpstr); end end //This interrupt delays packet reception for the length //of 1 packet when the reciever detects that the packet //is invalid //at the end of the packet, a NACK is sent //so that the transmitter re-sends that packet interrupt[TIM1_COMPA] void TIM1_1_sec(void) begin if (purge==1) begin purge=0; Byte_Number=1;//receive the 1st byte again //send NACK while(!UDRE){}; UDR1=NACK; end SEC_COUNTER_OFF;//turn off the counter SEC_TIMER_ISR_OFF;//turn off this interrupt TCNT1=0;//reset counter value end //Polling void X_Poll(void) begin unsigned char c,i; //debug unsigned char tmpstr[16]; unsigned int *tmpptr; while(SERIAL_MODE==Xmode) begin if (RXC)//if a byte is waiting in the buffer begin//X_Receive(); //Copied here to speed up, no function call c = UDR1;//current byte sent //if purge is on, then dump all bytes //until TIM0 ovrfls (1 sec) and sets purge to 0. if (purge==0)//dump the byte if purge==1 if (Byte_Number==1) begin//1st Byte should be SOH switch(c) begin case SOH: //have the start byte //lcd_gotoxy(0,1);lcd_putsf("SOH rx "); CRC=0; Byte_Number++; goto End_X; break; case EOT: //send a NACK, and expect a EOT as the next byte //we do not increment Byte_Number because //we want to check if the next Byte is also a EOT if (EOT_Number==0) begin//1st EOT byte //return a NACK EOT_Number=1; //send NACK while(!UDRE);//wait for output buffer UDR1=NACK; end else begin//2nd EOT byte //need to end transmission //1.send a ACK //turn off Xmodem transfer EOT_Number=2;//2nd EOT byte //X_Transmit will check EOT_Number //if EOT_number == 2, then it sends ACK //and turns off Xmodem transfer //by setting SERIAL_MODE = Nmode; while(!UDRE); UDR1=ACK; SERIAL_MODE = Nmode; USART1_RXCIEN; return; end goto End_X; break; default: //we have a invalid byte so we //need to purge the buffer //i.e. get the remaining bytes then send NACK X_Activate_Purge(); Byte_Number = 1; //X_Activate_Purge will send NACK after 1 sec goto End_X; break; end//switch(c) end//if Byte_Number==1 if (Byte_Number==2)//should get the packet number begin if (c == Packet_Number) begin //lcd_gotoxy(0,1);lcd_putsf("Packet# ok "); Byte_Number++; end else//failed to get the 2nd byte begin//invalid byte, purge packet //lcd_gotoxy(0,0);lcd_putsf("Byte2 error "); //sprintf(tmpstr,"c=%02x p#%02x",c,Packet_Number); //lcd_gotoxy(0,1);lcd_puts(tmpstr);delay_ms(1000U); X_Activate_Purge(); Byte_Number=1; end //return; goto End_X; end//if Byte_Number==2 if (Byte_Number==3)//expect the 1's complement of packet number begin if (c + Packet_Number==255) begin //lcd_gotoxy(0,1);lcd_putsf("~Packet# ok "); Byte_Number++; end else//invalid byte begin //sprintf(tmpstr,"Err,B3=%02x,P=%02x",c,Packet_Number); //lcd_gotoxy(0,1);lcd_puts(tmpstr); //delay_ms(2000U); X_Activate_Purge(); end //return; goto End_X; end//if Byte_Number==3 if ((Byte_Number>=4U)&&(Byte_Number<(4U + PACKET_SIZE))) begin//receiving packet data //We have a valid byte //write to buffer and increment Byte_Number buf[Byte_Number-4] = c; //add to the crc calculations CRC = CRC ^ (unsigned int) c << 8; for (i=0;i<8;i++) begin if (CRC&0x8000) CRC = CRC << 1 ^ 0x1021; else CRC = CRC << 1; end //verify /* if (buf[Byte_Number-4]!=c) begin lcd_gotoxy(0,1); lcd_putsf("X_Rx WriteErr"); delay_ms(1000U); end */ Byte_Number++; /*this only makes it worse //Play a byte if possible to reduce jerkyness if (Packet_Number>4) begin tmpptr = mp3ptr+1; if (tmpptr==BUF_END_ADD) tmpptr = BUF_START_ADD; if (tmpptr!=dataheadptr) begin//try to play a byte only if we have data available if (DATA_REQ) begin//STA requests a byte STA013_Audio_Send(*mp3ptr); mp3ptr=tmpptr; end end end//packet>4 */ //return; goto End_X; end// 4<=Byte_Number<=131 if (Byte_Number==(4U+PACKET_SIZE))//Hi-Byte of CRC begin CRCword = ((unsigned int) c) << 8; //lcd_putsf("CRC check");this runs Byte_Number++; //return; goto End_X; end if (Byte_Number==(5U+PACKET_SIZE))//Lo-Byte of CRC begin Byte_Number = 1;//reset byte number, packet ended CRCword = CRCword + c; //lcd_putsf("CRC check"); this runs //now check to see that the CRC is correct //if (CRCword==calcrc(buf,PACKET_SIZE)) if (CRCword == CRC) begin//CRC correct, accept packet //1.write packet to data buffer //2.increment packet number //3.reset Byte_Number //4.ACK packet X_Write_Packet();//write to and playback from buffer //debounce buttons if (T3_Ovf) begin debounce(); if (New_Butnum) begin switch(Current_Butnum) begin case Btn_Stop: //send 4 CAN (cancel bytes) //go back to SERIAL_MODE = Nmode while(!UDRE); UDR1=CAN; while(!UDRE); UDR1=CAN; SERIAL_MODE = Nmode; lcd_gotoxy(0,0);lcd_putsf("Stopped"); USART1_RXCIEN; return; break; case Btn_Vol_Up: lcd_gotoxy(0,1);lcd_putsf("Vol up:0x"); if (vol_attn_l>0) vol_attn_l=vol_attn_l>>1;//vol_attn_l--; if (vol_attn_r>0) vol_attn_r=vol_attn_r>>1;//vol_attn_r--; STA013_Write(DLA, vol_attn_l); sprintf(tmpstr,"%02x",~vol_attn_l); lcd_puts(tmpstr); //Writes to STA013 should have some time seperation STA013_Write(DRA, vol_attn_r); break; case Btn_Vol_Dn: lcd_gotoxy(0,1);lcd_putsf("Vol dn:0x"); if (vol_attn_l<255) vol_attn_l=(vol_attn_l<<1)+1;//vol_attn_l++; if (vol_attn_r<255) vol_attn_r=(vol_attn_r<<1)+1;//vol_attn_r++; STA013_Write(DLA, vol_attn_l); sprintf(tmpstr,"%02x",~vol_attn_l); lcd_puts(tmpstr); STA013_Write(DRA, vol_attn_r); break; default: break; end//switch Clr_Butnum; end//if new_butnum T3_Ovf_Clr;//clear int flag //T3_Reset;//set TCNT3 = 0 TCNT3H=0;TCNT3L=0; end//if t3ovf Packet_Number++; //lcd_putsf("CRC ok"); //X_Transmit_State=SEND_ACK; //USART1_UDRIEN; while(!UDRE); UDR1=ACK; end else begin //CRC is wrong, need to resend packet //send NACK //lcd_putsf("CRC err");delay_ms(1000U); //X_Transmit_State = SEND_NACK; //USART1_UDRIEN;//turn on transmit interrupt while(!UDRE); UDR1=NACK; end //return; goto End_X; end//if Byte_Number = CRC Lo-Byte End_X://reiterate end//X_Receive end//while(SERIAL_MODE==Xmode) end |
|