| |
//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
|