📄 ymodem.c
字号:
/******************************************************************
* ymodem.c: Serial Interface to PC UART
*
* Copyright (c) 2001 Atmel Corporation.
* All Rights Reserved.
*
* You are autorized to use, copy and distribute this software only at
* a single site (the term "site" meaning a single company location).
* This copyright notice must be included in any copy, modification
* or portion of this software merged into another program.
*
* This software is licenced solely for use with Atmel AVR micro
* controller family. The software may not be modified to execute on
* any other microcontroller architectures
*
* This software is provided "as is"; Without warranties either express
* or implied, including any warranty regarding merchantability,
* fitness for a particular purpose or noninfringement.
*
* In no event shall Atmel or its suppliers be liable for any special,
* indirect,incidential or concequential damages resulting from the
* use or inability to use this software.
*
* Revision history:
*
* January 17, 2001: Version 1.0 Created by JB
* July 13, 2001 Version 1.2 JB
* - Changed to IAR compiler V2.25
* - Renamed flash file functions to avoid conflict with
* standard file I/O names
* - Bug fixes in HTTP
* - Speed optimization in TCP
*
*
* July 13, 2001 Version 1.2
* - Changed to IAR compiler V2.25
* - Renamed flash file functions to avoid conflict with
* standard file I/O names
* - Bug fixes in HTTP
* - Speed optimization in TCP
*******************************************************************/
#include "iom103.h"
#include "ymodem.h"
#include "ffile.h"
#include "string.h"
#include "stdio.h"
#include "ina90.h"
void TransmitByte( unsigned char data );
void Send (unsigned char *string);
char ymodemBuf[1030];
char *ymodemRecvPtr;
char ymodemRecvError;
unsigned char ymodemPacketNumber;
unsigned char ymodemSync;
unsigned char ymodemNakCnt;
unsigned int ymodemCnt;
unsigned int ymodemDataLength;
FFILE * ymodemDestFile;
void initYmodem(void)
{
unsigned char temp;
// portd bit 2 used to start data reception
// Pb7, Pb6, Pb5, Pb4, Pb3, Pb2, Pb1, Pb0
// O O O O O O O O
// 1 1 1 1 1 1 1 1
DDRD = 0xfb;
PORTD = 0xff;
temp = UDR; // Dummy reading, ignore compiler warning
UCR = 0x98; // enable receiver, transmitter, and receiver interrupt
UBRR = 29; // 9.6k with 4.608Mhz crystal
ymodemRecvPtr = &ymodemBuf[0];
ymodemSync = 1;
ymodemPacketNumber=0;
ymodemNakCnt=0;
}
/* uart interrupt routine*/
#pragma vector = UART_RX_vect
__interrupt void UART_RX_interrupt(void)
{
char *localPtr = ymodemRecvPtr;
char filename[13];
unsigned char packet = canc; //status flag
unsigned int packetSize;
// check for errors before reading data register ... reading UDR clears status
if (USR & 0x18) // Framing or over run error
{
ymodemRecvError = true; // will NAK sender
ymodemBuf[0]=0;
}
// always read a character otherwise another interrupt could get generated
*localPtr++ = UDR; // get char
//determine if it is a complete pathname packet
if(ymodemBuf[0]==SOH)
{
packetSize = 128;
if ( (ymodemBuf[1] == 0) && (localPtr == (&ymodemBuf[133])) )
{
if (( ymodemBuf[2]) == 0xff)
{ // block number and block number checksum are ok
if ((calcrc(&ymodemBuf[3],128)) == (unsigned int)((ymodemBuf[131] << 8) | (ymodemBuf[132])))
{
strncpy(filename, &ymodemBuf[3],13); //read pathname
if (!strlen(filename))
{ //a null pathname terminates tranmission
packet = good;
}
else if (strlen(filename)<13)
{
ffclose(ymodemDestFile); //in case there is an open file
ffdelete(filename); //delete file first
ymodemDestFile=ffopen(filename, 'w'); //open file
strcpy(filename, &ymodemBuf[strlen(filename)+4]);
sscanf(filename,"%d",&ymodemDataLength); //read data length
if (ymodemDestFile!=NULL)
{ //file has been opened
packet = good;
}
}
}
}
localPtr = &ymodemBuf[0];
respond(packet); //send respons
} //determine if buffer is full
if(localPtr != (&ymodemBuf[133]))
{
ymodemRecvPtr = localPtr; // restore global pointer
return;
}
}
else if(ymodemBuf[0]==STX) //buffer is full, or end of transmission, or first char unknown
{
packetSize = 1024;
if(localPtr != (&ymodemBuf[1029]))
{
ymodemRecvPtr = localPtr; // restore global pointer
return;
}
}
packet = validate_packet(&ymodemBuf[0], packetSize); //validate
if (packet==good)
{
if (ymodemPacketNumber == 1)
{
ymodemSync=0; //sync is done
}
if (ymodemDataLength<packetSize)
{
ffwrite(ymodemDestFile, &ymodemBuf[3], ymodemDataLength);//write last packet to dataflash
}
else
{
ffwrite(ymodemDestFile, &ymodemBuf[3], packetSize); //write to dataflash
ymodemDataLength-=packetSize;
}
}
if (packet==end)
{
ffclose(ymodemDestFile); //close file
ymodemPacketNumber=0;
ymodemSync=1;
}
if (!ymodemSync)
{ //reset timeout counters
ymodemCnt=0;
ymodemNakCnt=0;
}
localPtr = &ymodemBuf[0];
respond(packet);
ymodemRecvPtr = localPtr; // restore global pointer
}
/* validate_packet*/
unsigned char validate_packet(char *bufptr, unsigned int size)
{
unsigned char packet = bad;
unsigned char bufptr0 = bufptr[0];
unsigned char bufptr1 = bufptr[1];
if (!ymodemRecvError)
{
if (bufptr0 == SOH || (size==1024 && bufptr0 == STX))
{ // valid start
if (bufptr1 == ((ymodemPacketNumber+1)))
{ // sequential block number ?
if ((bufptr1 + bufptr[2]) == 0xff)
{ // block number and block number checksum are ok
// compute CRC and validate it
if ((calcrc(&bufptr[3],size)) == (unsigned int)((ymodemBuf[size+3] << 8) | (ymodemBuf[size+4])))
{
ymodemPacketNumber++; // good packet ... ok to increment
packet = good;
}
} // block number checksum
} // bad block number or same block number
else if (bufptr1 == (ymodemPacketNumber))
{ // same block number ... ack got glitched
packet = dup; // packet is previous packet don't inc packet number
}
}
else if (bufptr0 == EOT) // check for the end
{
packet = end;
}
}
else
{
packet = err;
}
return (packet);
}
/*wait for sender to empy its transmit buffer*/
void purge(unsigned char temp)
{
unsigned char flush;
unsigned char ii=100;
while (!(USR & 0x20)) // wait till Data register is empty
{
}
do
{
flush = UDR; // Dummy reading, ignore compiler warning
} while (--ii);
UDR = temp;
}
void respond(char packet)
{
if (ymodemRecvError)
{
ymodemRecvError = false; // framing and over run detection
}
if ((packet == good) || (packet == dup) || (packet == end))
{
while (!(USR & 0x20)); // wait till transmit register is empty
UDR = ACK; // now for the next packet
}
else if (packet == canc)
{
purge(CAN); // tell sender to cancel
UDR = CAN; // must be done twice
}
else
{
purge(NAK); // let transmitter empty its buffer
// tell sender error
}
}
void checkYmodem(void)
{
ymodemCnt++;
if (ymodemCnt>YMODEM_3SEC)
{
ymodemCnt = 0;
if (ymodemSync)
{
while (!(USR & 0x20)); // wait till Data register is empty
UDR = CRCCHR; // send a 'C'
}
else
{
ymodemRecvPtr=&ymodemBuf[0]; //resett buffer pointer
if (ymodemNakCnt > 3)
{
purge(CAN); // tell sender to cancel
UDR = CAN; // must be done twice
ymodemPacketNumber=0;
ymodemSync=1;
ymodemNakCnt=0;
ffclose(ymodemDestFile);
}
else
{
purge(NAK); // send NAK
ymodemNakCnt++;
}
}
}
}
unsigned int calcrc(char *ptr, int count)
{
unsigned int crc = 0;
unsigned char i;
while(--count >= 0)
{
crc = crc ^ (unsigned int) *ptr++ << 8;
for(i=0; i<8; ++i)
{
if (crc & 0x8000)
{
crc = crc << 1 ^ 0x1021;
}
else
{
crc = crc << 1;
}
}
}
return (crc);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -