1940 lines
50 KiB
C++
1940 lines
50 KiB
C++
// Zmodem.cpp: implementation of the Zmodem class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "Zmodem.h"
|
|
#include "CtrlProtocolDef.h"
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[]=__FILE__;
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
|
|
extern SYSTEMTIME g_sysCurTime;
|
|
extern int g_iUILanguage;
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Zmodem::Zmodem()
|
|
// {
|
|
//
|
|
// }
|
|
//
|
|
Zmodem::~Zmodem()
|
|
{
|
|
//str = NULL;
|
|
|
|
}
|
|
|
|
Zmodem::Zmodem( CSComPort *rs232_port )
|
|
{
|
|
port = rs232_port;
|
|
// str = NULL;
|
|
// m_BuffCount = 0;
|
|
// m_BufReadIndex = 0;
|
|
ClearReadBuf();
|
|
file_count = 0;
|
|
file_name[ 0 ] = '\0';
|
|
file_length = -1L;
|
|
file = NULL;
|
|
receiver_buffer_length = 16384;
|
|
wake_up_sender_header_type = ZRINIT;
|
|
|
|
memset(m_WriteBuff, 0, 8192);
|
|
m_WriteBuffLength = 0;
|
|
|
|
m_ByteTransfer = 0;
|
|
m_FileSize = 0;
|
|
|
|
nIndex = 0;
|
|
|
|
// nTestID = 123456;
|
|
}
|
|
|
|
// The public Send functionsends a batch of files one at a time
|
|
// via the SendSingleFile function. When a normal completion
|
|
// occurs, it is flagged with a ZFIN frame.
|
|
|
|
BOOL Zmodem::Send( char *files[] )
|
|
{
|
|
//log
|
|
zmodemLog = fopen("log\\zmodemSZLog.txt","ab");
|
|
if (!zmodemLog)
|
|
{
|
|
zmodemLog = fopen("zmodemSZLog.txt","ab");
|
|
}
|
|
|
|
dwBegin = GetTickCount();
|
|
memset(cReadLog,0,2048);
|
|
|
|
nLogLength = sprintf(cReadLog,"\r\n");
|
|
fwrite(cReadLog,nLogLength,1,zmodemLog);
|
|
fflush(zmodemLog);
|
|
|
|
nLogLength = sprintf(cReadLog,*files);
|
|
fwrite(cReadLog,nLogLength,1,zmodemLog);
|
|
fflush(zmodemLog);
|
|
|
|
nLogLength = sprintf(cReadLog,"\r\n");
|
|
fwrite(cReadLog,nLogLength,1,zmodemLog);
|
|
fflush(zmodemLog);
|
|
//log
|
|
|
|
PackLongIntoHeader( 0L );
|
|
SendHexHeader(4, ZRQINIT, transmitted_header);
|
|
GetRinitHeader();
|
|
byte_count = -1;
|
|
while ( *files )
|
|
{
|
|
int n = SendSingleFile( *files );
|
|
if ( n == ZERROR )
|
|
{
|
|
if (file)
|
|
{
|
|
//log
|
|
nLogLength = sprintf(cReadLog,"SendSingleFile = %d\r\n",n);
|
|
fwrite(cReadLog,nLogLength,1,zmodemLog);
|
|
fflush(zmodemLog);
|
|
//log
|
|
|
|
fclose(file);
|
|
fclose(zmodemLog);
|
|
return FALSE;
|
|
}
|
|
//log
|
|
nLogLength = sprintf(cReadLog,"SendSingleFile = %d\r\n",n);
|
|
fwrite(cReadLog,nLogLength,1,zmodemLog);
|
|
fflush(zmodemLog);
|
|
//log
|
|
}
|
|
files++;
|
|
}
|
|
|
|
SendZFIN();
|
|
|
|
if (file)
|
|
fclose(file);
|
|
|
|
if (zmodemLog)
|
|
fclose(zmodemLog);
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// This function is used *everywhere*, and benefits from being
|
|
// declared as inline.
|
|
|
|
inline int Zmodem::ReadChar( long timeout )
|
|
{
|
|
// int c = ReadBuff( timeout );
|
|
// return ( c < 0 ) ? TIMEOUT : c;
|
|
|
|
if ((0 == m_BuffCount) || (m_nBufReadIndex == m_BuffCount))//除非已经读取完毕,再进行缓存的读取
|
|
{
|
|
if (ReadBuff(timeout) != TIMEOUT)
|
|
{
|
|
return buff[m_nBufReadIndex++ ] & 0377;
|
|
}
|
|
else
|
|
return TIMEOUT;
|
|
}
|
|
|
|
return buff[m_nBufReadIndex++ ] & 0377;
|
|
}
|
|
|
|
|
|
// This is the worker routine that transmits a single file.
|
|
|
|
int Zmodem::SendSingleFile( char *name )
|
|
{
|
|
int c;
|
|
unsigned long crc_value;
|
|
long lastcrcrq = -1;
|
|
int length;
|
|
//add by waston
|
|
int nnlen;//log
|
|
char *FileName;
|
|
int nLogCode = 0;
|
|
CString strLogTmp = _T("");
|
|
//add by waston
|
|
|
|
file = fopen( name, "rb" );
|
|
|
|
FileName = strrchr(name,'\\');
|
|
FileName++;
|
|
|
|
if ( file == NULL) {
|
|
error( "Failed to open %s", name );
|
|
return OK;
|
|
}
|
|
file_at_eof = 0;
|
|
fseek( file, 0, SEEK_END );
|
|
file_length = ftell( file );
|
|
fseek( file, 0, SEEK_SET );
|
|
m_FileSize = file_length; //将文件大小写到接口
|
|
length = sprintf( buffer,
|
|
"%s%c%u 0 0 0 0 0",
|
|
FileName,
|
|
0,
|
|
file_length );
|
|
|
|
for ( ; ; ) {
|
|
PackLongIntoHeader( 0L );
|
|
SendBinaryHeader( 4, ZFILE, transmitted_header );
|
|
SendDataFrame( buffer, length, ZCRCW );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRUN: send ZFILE DATA FRAME: %s"), __LINE__,
|
|
GetTickCount() - dwBegin,buffer);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
again:
|
|
c = ReadHeader( received_header );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tswitch = %d"), __LINE__,
|
|
GetTickCount() - dwBegin, c);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
switch ( c ) {
|
|
case ZRINIT:
|
|
while ( ( c = ReadChar( 5000L ) ) > 0 )
|
|
if ( c == ZPAD )
|
|
goto again;
|
|
/* **** FALL THRU TO **** */
|
|
default:
|
|
continue;
|
|
case ZCAN:
|
|
case TIMEOUT:
|
|
case ZABORT:
|
|
case ZFIN:
|
|
return ZERROR;
|
|
case ZCRC:
|
|
if ( received_file_position != lastcrcrq ) {
|
|
Crc32 crc( 0xFFFFFFFFL );
|
|
lastcrcrq = received_file_position;
|
|
fseek( file, 0L, SEEK_SET );
|
|
while ( ( ( c = getc( file ) ) != EOF )
|
|
&& --lastcrcrq )
|
|
crc.update(c );
|
|
crc_value = ~crc.value();
|
|
fseek( file, 0L, SEEK_SET );
|
|
lastcrcrq = received_file_position;
|
|
}
|
|
PackLongIntoHeader( crc_value );
|
|
SendBinaryHeader( 4, ZCRC, transmitted_header );
|
|
goto again;
|
|
case ZSKIP:
|
|
fclose( file );
|
|
return OK;
|
|
case ZRPOS:
|
|
nLogCode = fseek(file,received_file_position,SEEK_SET);
|
|
if (nLogCode)
|
|
{
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\t case ZRPOS = %d,fseek = %d"), __LINE__,
|
|
GetTickCount() - dwBegin, received_file_position,nLogCode);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
return ZERROR;
|
|
}
|
|
|
|
last_sync_position =
|
|
(byte_count=transmitted_file_position=
|
|
last_reported_position=
|
|
received_file_position) - 1;
|
|
return SendFileContents();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int Zmodem::SendFileContents( void )
|
|
{
|
|
int c;
|
|
int e;
|
|
int n;
|
|
int junkcount;
|
|
int newcnt;
|
|
|
|
junkcount = 0;
|
|
|
|
CString strLogTmp = _T("");
|
|
|
|
start_read:
|
|
receiver_buffer_length = 2048;
|
|
newcnt = receiver_buffer_length;
|
|
PackLongIntoHeader( transmitted_file_position );
|
|
SendBinaryHeader( 4, ZDATA, transmitted_header );
|
|
|
|
do {
|
|
n = fread( buffer, 1, 1024, file );
|
|
|
|
if ( n < 1024 )
|
|
file_at_eof = 1;
|
|
|
|
if ( file_at_eof )
|
|
e = ZCRCE;
|
|
else if ( junkcount > 3 )
|
|
e = ZCRCW;
|
|
else if ( byte_count == last_sync_position )
|
|
e = ZCRCW;
|
|
else if ( receiver_buffer_length && ( newcnt -= n ) <= 0 )
|
|
e = ZCRCW;
|
|
else
|
|
e = ZCRCG;
|
|
|
|
SendDataFrame( buffer, n, e );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tSendData: %d, fread = %d"), __LINE__,
|
|
GetTickCount() - dwBegin, e,n);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
m_ByteTransfer = byte_count = transmitted_file_position += n;
|
|
|
|
if ( e == ZCRCW )
|
|
goto waitack;
|
|
while ( /*port->RXSpaceUsed()*/ m_nBufReadIndex < m_BuffCount) {
|
|
switch ( ReadChar( 100 ) ) {
|
|
case CAN:
|
|
case ZPAD:
|
|
c = SyncWithReceiver( 1 );
|
|
if ( c == ZACK )
|
|
break;
|
|
SendDataFrame( buffer, 0, ZCRCE );
|
|
goto gotack;
|
|
case XOFF:
|
|
case XOFF | 0x80 :
|
|
ReadChar( 10000L );
|
|
default:
|
|
junkcount++;
|
|
}
|
|
}
|
|
} while ( !file_at_eof );
|
|
int nnlen;
|
|
for ( ; ; ) {
|
|
PackLongIntoHeader( transmitted_file_position );
|
|
SendBinaryHeader( 4, ZEOF, transmitted_header );
|
|
switch ( SyncWithReceiver( 0 ) ) {
|
|
case ZACK:
|
|
continue;
|
|
case ZRPOS:
|
|
goto start_read;
|
|
case ZRINIT:
|
|
return OK;
|
|
case ZSKIP:
|
|
fclose( file );
|
|
return c;
|
|
default:
|
|
fclose( file );
|
|
return ZERROR;
|
|
}
|
|
}
|
|
|
|
//Backchannel processing
|
|
waitack:
|
|
junkcount = 0;
|
|
c = SyncWithReceiver( 0 );
|
|
gotack:
|
|
switch ( c ) {
|
|
default:
|
|
case ZCAN:
|
|
fclose( file );
|
|
return ZERROR;
|
|
case ZSKIP:
|
|
fclose( file );
|
|
return c;
|
|
case ZACK:
|
|
case ZRPOS:
|
|
break;
|
|
case ZRINIT:
|
|
return OK;
|
|
}
|
|
while ( /*port->RXSpaceUsed()*/ m_nBufReadIndex < m_BuffCount) {
|
|
switch ( ReadChar( 100 ) ) {
|
|
case CAN:
|
|
case ZPAD:
|
|
c = SyncWithReceiver( 1 );
|
|
goto gotack;
|
|
case XOFF :
|
|
case XOFF | 0x80 :
|
|
ReadChar( 10000L );
|
|
}
|
|
}
|
|
goto start_read;
|
|
}
|
|
|
|
// If all goes well, the public receive function just calls
|
|
// WakeUpSender(), then ReceiveFiles(). If both of those
|
|
// do what they are supposed to do, a batch of files will
|
|
// have been properly transferred.
|
|
|
|
BOOL Zmodem::Receive( CString Path )
|
|
{
|
|
|
|
//log
|
|
zmodemLog = fopen("log\\zmodemRZLog.txt","ab");
|
|
if (!zmodemLog)
|
|
{
|
|
zmodemLog = fopen("zmodemRZLog.txt","ab");
|
|
}
|
|
dwBegin = GetTickCount();
|
|
memset(cReadLog,0,2048);
|
|
|
|
nLogLength = sprintf(cReadLog,"\r\n");
|
|
fwrite(cReadLog,nLogLength,1,zmodemLog);
|
|
fflush(zmodemLog);
|
|
|
|
nLogLength = sprintf(cReadLog,"\r\n");
|
|
fwrite(cReadLog,nLogLength,1,zmodemLog);
|
|
fflush(zmodemLog);
|
|
//log
|
|
|
|
memset(buffer,0,BUFFSIZE);
|
|
|
|
static char CancelString[] = {
|
|
CAN, CAN, CAN, CAN, CAN, CAN, CAN, CAN, CAN, CAN,
|
|
BS, BS, BS, BS, BS, BS, BS, BS, BS, BS };
|
|
|
|
switch ( WakeUpSender() )
|
|
{
|
|
case 0 :
|
|
case ZCOMPL : return OK;
|
|
case ZERROR : break;
|
|
default : if ( ReceiveFiles(Path) == OK )
|
|
{
|
|
if ( file )
|
|
{
|
|
if (0 != fclose(file))
|
|
{
|
|
CString strTmp = _T("");
|
|
strTmp.Format(_T("{Zmodem} [%d] close file failed!!!,ErrorNo = %d"), __LINE__, GetLastError());
|
|
PrintLogLast(strTmp);
|
|
}
|
|
file = NULL;
|
|
}
|
|
|
|
fclose(zmodemLog);//log;
|
|
return TRUE;
|
|
}
|
|
}
|
|
port->ZmodemSendDataDirectly( CancelString, sizeof CancelString);//tmp
|
|
|
|
if ( file )
|
|
{
|
|
if (0 != fclose(file))
|
|
{
|
|
CString strTmp = _T("");
|
|
strTmp.Format(_T("{Zmodem} [%d] close file failed!!!,ErrorNo = %d"), __LINE__, GetLastError());
|
|
PrintLogLast(strTmp);
|
|
}
|
|
file = NULL;
|
|
}
|
|
|
|
|
|
fclose(zmodemLog);//log;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// This is the general purpose receiver function. It calls the
|
|
// ReceiveSingleFile function repeatedly as long as the wakeup
|
|
// function keeps receiving ZFILE frames.
|
|
|
|
int Zmodem::ReceiveFiles( CString Path )
|
|
{
|
|
int return_status ;
|
|
|
|
for ( ; ; ) {
|
|
switch ( return_status = ReceiveSingleFile(Path) )
|
|
{
|
|
case ZEOF:
|
|
case ZSKIP:
|
|
switch ( WakeUpSender() ) {
|
|
case ZCOMPL:
|
|
return OK;
|
|
default:
|
|
return ZERROR;
|
|
case ZFILE:
|
|
break;
|
|
}
|
|
continue;
|
|
default:
|
|
return return_status;
|
|
case ZERROR:
|
|
return ZERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Some data used various places in the class
|
|
|
|
static char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"};
|
|
|
|
static char *frametypes[] = {
|
|
"No Response to Error Correction Request",
|
|
"No Carrier Detect",
|
|
"TIMEOUT",
|
|
"ZERROR",
|
|
"ZRQINIT", "ZRINIT", "ZSINIT", "ZACK", "ZFILE",
|
|
"ZSKIP", "ZNAK", "ZABORT", "ZFIN", "ZRPOS",
|
|
"ZDATA", "ZEOF", "ZFERR", "ZCRC", "ZCHALLENGE",
|
|
"ZCOMPL", "ZCAN", "ZFREECNT", "ZCOMMAND", "ZSTDERR"
|
|
};
|
|
|
|
// This function is used when receiving files. It sends out the
|
|
// initial frame and waits for a response from the sender. If
|
|
// things go properly it will get the file data subpacket and
|
|
// return ZFILE. If the sender has no more files it will send a
|
|
// ZFIN, which is handled here.
|
|
|
|
int Zmodem::WakeUpSender( void )
|
|
{
|
|
int c;
|
|
int n;
|
|
|
|
for ( n = 0 ; n < 16 ; n++ ) {
|
|
PackLongIntoHeader( 3072L );
|
|
transmitted_header[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
|
|
SendHexHeader( 4,
|
|
wake_up_sender_header_type,
|
|
transmitted_header );
|
|
if ( wake_up_sender_header_type == ZSKIP )
|
|
wake_up_sender_header_type = ZRINIT;
|
|
for ( int try_again = 1 ; try_again ; ) {
|
|
switch ( ReadHeader( received_header ) ) {
|
|
case ZRQINIT :
|
|
case ZEOF :
|
|
case TIMEOUT :
|
|
default :
|
|
try_again = 0;
|
|
break;
|
|
case ZFILE :
|
|
wake_up_sender_header_type = ZRINIT;
|
|
c = ReadDataFrame( buffer, 1024 );
|
|
if ( c == GOTCRCW )
|
|
return ZFILE;
|
|
SendHexHeader( 4, ZNAK, transmitted_header );
|
|
break;
|
|
case ZSINIT :
|
|
if (ReadDataFrame(attention_string, ZATTNLEN)
|
|
== GOTCRCW ) {
|
|
PackLongIntoHeader( 1L );
|
|
SendHexHeader(4,ZACK,transmitted_header);
|
|
} else
|
|
SendHexHeader(4,ZNAK,transmitted_header);
|
|
break;
|
|
case ZCOMPL :
|
|
break;
|
|
case ZFIN :
|
|
AckZFIN();
|
|
return ZCOMPL;
|
|
case ZCAN :
|
|
return ZERROR;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// This is the workhorse routine that reads a single file from the
|
|
// sender. It reads in headers until it gets a ZDATA header, then
|
|
// it switches over to reading data subpackets until it gets one
|
|
// of the end of supbacket codes.
|
|
|
|
int Zmodem::ReceiveSingleFile( CString Path )
|
|
{
|
|
int c;
|
|
int error_count;
|
|
long rxbytes;
|
|
|
|
if ( OpenInputFile( Path, buffer ) == ZERROR )
|
|
return wake_up_sender_header_type = ZSKIP;
|
|
error_count = 0;
|
|
rxbytes = 0L;
|
|
long log_data2;
|
|
// char chLog[200] = "";
|
|
CString strLogTmp = _T("");
|
|
|
|
for ( ; ; ) {
|
|
PackLongIntoHeader( rxbytes );
|
|
SendHexHeader( 4, ZRPOS, transmitted_header );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRUN: send ZPROS:rxbytes = %d"), __LINE__,
|
|
GetTickCount() - dwBegin, rxbytes);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
nxthdr:
|
|
c = ReadHeader( received_header );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRUN: read ReadHeader c = %d"), __LINE__,
|
|
GetTickCount() - dwBegin, c);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
switch (c) {
|
|
default:
|
|
error( "ReceiveSingleFile: ReadHeader returned %d",
|
|
c );
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRUN: default:"), __LINE__, GetTickCount() - dwBegin);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
// return ZERROR;3
|
|
goto nxthdr;
|
|
case ZNAK:
|
|
{
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d \t\t\t\t\t\ Receice ZANK!!!"), __LINE__, GetTickCount() - dwBegin);
|
|
PrintLogLast(strLogTmp);
|
|
continue;
|
|
}
|
|
case TIMEOUT:
|
|
if ( ++error_count >= 20 )
|
|
{
|
|
error("ReceiveSingleFile: ReadHeader returned %d",
|
|
c );
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d \t\t\t\t\t\ Receice TIMEOUT"), __LINE__, GetTickCount() - dwBegin);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
return ZERROR;
|
|
}
|
|
continue;
|
|
case ZFILE:
|
|
ReadDataFrame( buffer, 1024 );
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d \t\t\t\t\t\tRUN: ZFILE:"), __LINE__, GetTickCount() - dwBegin);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
continue;
|
|
|
|
case ZEOF:
|
|
log_data2 = UnpackHeaderIntoLong(received_header);
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d \t\t\t\t\t\tRUN: ZEOF:log_data2 = %d, rxbytes = %d"), __LINE__,
|
|
GetTickCount() - dwBegin, log_data2, rxbytes);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
if (log_data2 != rxbytes)
|
|
goto nxthdr;
|
|
// continue;
|
|
// if ( fclose( file ) != 0 )
|
|
// {
|
|
// wake_up_sender_header_type = ZFERR;
|
|
// error( "ReceiveSingleFile: fclose() "
|
|
// "returned error" );
|
|
// return ZERROR;
|
|
// }
|
|
return c;
|
|
|
|
case ZERROR:
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d \t\t\t\t\t\tRUN: ZERROR:"), __LINE__, GetTickCount() - dwBegin);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
if ( ++error_count >= 20 ) {
|
|
error( "ReceiveSingleFile: ReadHeader "
|
|
"returned %d", c );
|
|
return ZERROR;
|
|
}
|
|
// SendAttentionString();
|
|
// continue;1
|
|
goto nxthdr;
|
|
case ZSKIP:
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d \t\t\t\t\t\tRUN: ZSKIP:"), __LINE__, GetTickCount() - dwBegin);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
status("ReceiveSingleFile: Sender SKIPPED file");
|
|
return c;
|
|
case ZDATA:
|
|
long log_data = UnpackHeaderIntoLong( received_header );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d \t\t\t\t\t\tRUN: recv ZDATA:log_data = %d, rxbytes = %d"), __LINE__,
|
|
GetTickCount() - dwBegin, log_data,rxbytes);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
if ( log_data != rxbytes )
|
|
{
|
|
if ( ++error_count >= 20 )
|
|
return ZERROR;
|
|
|
|
// SendAttentionString();
|
|
continue;
|
|
}
|
|
|
|
// if ( UnpackHeaderIntoLong( received_header ) != rxbytes )
|
|
// {
|
|
// if ( ++error_count >= 20 )
|
|
// return ZERROR;
|
|
//
|
|
// SendAttentionString();
|
|
// continue;
|
|
// }
|
|
moredata:
|
|
switch ( c = ReadDataFrame( buffer, 1024 ) ) {
|
|
case ZCAN:
|
|
error( "ReceiveSingleFile: ReadData returned %d",
|
|
c );
|
|
return ZERROR;
|
|
case ZERROR:
|
|
if ( ++error_count >= 20 ) {
|
|
error( "ReceiveSingleFile: ReadData "
|
|
"returned %d", c );
|
|
return ZERROR;
|
|
}
|
|
// SendAttentionString();
|
|
continue;
|
|
case TIMEOUT:
|
|
if ( ++error_count >= 20 ) {
|
|
error( "ReceiveSingleFile: ReadData "
|
|
"returned %d", c );
|
|
return ZERROR;
|
|
}
|
|
continue;
|
|
case GOTCRCW:
|
|
error_count = 0;
|
|
fwrite( buffer, 1, Rxcount, file );
|
|
rxbytes += Rxcount;
|
|
m_ByteTransfer = rxbytes;
|
|
PackLongIntoHeader( rxbytes );
|
|
SendHexHeader( 4, ZACK, transmitted_header );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d \t\t\t\t\t\tRUN: send ZACK:rxbytes = %d"), __LINE__,
|
|
GetTickCount() - dwBegin, rxbytes);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
SendChar( XON );
|
|
SendCharToComm();
|
|
goto nxthdr;
|
|
case GOTCRCQ:
|
|
error_count = 0;
|
|
fwrite( buffer, 1, Rxcount, file );
|
|
rxbytes += Rxcount;
|
|
m_ByteTransfer = rxbytes;
|
|
PackLongIntoHeader( rxbytes );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d \t\t\t\t\t\tRUN: send ZACK:rxbytes = %d"), __LINE__,
|
|
GetTickCount() - dwBegin, rxbytes);
|
|
PrintLogLast(strLogTmp);
|
|
|
|
//log
|
|
|
|
SendHexHeader( 4, ZACK, transmitted_header );
|
|
goto moredata;
|
|
case GOTCRCG:
|
|
error_count = 0;
|
|
fwrite( buffer, 1, Rxcount, file );
|
|
rxbytes += Rxcount;
|
|
m_ByteTransfer = rxbytes;
|
|
goto moredata;
|
|
case GOTCRCE:
|
|
error_count = 0;
|
|
fwrite( buffer, 1, Rxcount, file );
|
|
rxbytes += Rxcount;
|
|
m_ByteTransfer = rxbytes;
|
|
goto nxthdr;
|
|
}
|
|
|
|
// return ZERROR;
|
|
}
|
|
}
|
|
#ifdef _MSC_VER
|
|
return 0; // MSC 7.0 generates an error w/o this line,
|
|
// although it can never be reached
|
|
#endif
|
|
}
|
|
|
|
// This routine just has to decide whether to send the binary
|
|
// header using CRC-16 or CRC-32. After that it just spits out
|
|
// the data.
|
|
|
|
void Zmodem::SendBinaryHeader( int length,
|
|
int type,
|
|
char *header )
|
|
{
|
|
CString strLogTmp = _T("");
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tSend: %d"), __LINE__,
|
|
GetTickCount() - dwBegin, type);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
int i;
|
|
Crc32 crc32( 0xFFFFFFFFL );
|
|
unsigned long crc32val;
|
|
Crc16 crc16( 0 );
|
|
|
|
status( "SendBinaryHeader: %d %s %lx",
|
|
length,
|
|
frametypes[ type + 4 ],
|
|
UnpackHeaderIntoLong( header ) );
|
|
SendChar( ZPAD );
|
|
SendChar( ZDLE );
|
|
if ( receiver_wants_crc32 ) {
|
|
SendChar( ZBIN32 );
|
|
SendEncodedChar( type );
|
|
crc32.update( type );
|
|
for ( i = 0; i < length; i++ ) {
|
|
crc32.update( 0xff & header[ i ] );
|
|
SendEncodedChar( header[ i ] );
|
|
}
|
|
crc32val = ~crc32.value();
|
|
for ( i = 0 ; i < 4 ; i++ ) {
|
|
SendEncodedChar( (int) crc32val );
|
|
crc32val >>= 8;
|
|
}
|
|
} else {
|
|
SendChar( ZBIN );
|
|
SendEncodedChar( type );
|
|
crc16.update( type );
|
|
for ( i = 0 ; i < length ; i++ ) {
|
|
SendEncodedChar( header[ i ] );
|
|
crc16.update( header[ i ] & 0xff );
|
|
}
|
|
crc16.update( 0 );
|
|
crc16.update( 0 );
|
|
SendEncodedChar( crc16.value() >> 8 );
|
|
SendEncodedChar( crc16.value() );
|
|
}
|
|
SendCharToComm();
|
|
}
|
|
|
|
// Sending the hex header involves no decisions whatsoever.
|
|
|
|
void Zmodem::SendHexHeader( int len, int type, char *header )
|
|
{
|
|
CString strLogTmp = _T("");
|
|
|
|
if (type == ZRPOS)
|
|
{
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tSend:%d\tZrposIndex = %d"), __LINE__,
|
|
GetTickCount() - dwBegin, type,nIndex);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
nIndex++;
|
|
}
|
|
else
|
|
{
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tSend: %d"), __LINE__,
|
|
GetTickCount() - dwBegin, type);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
}
|
|
|
|
|
|
int n;
|
|
Crc16 crc( 0 );
|
|
status( "SendHexHeader: %d %s %lx", len,
|
|
frametypes[type+4], UnpackHeaderIntoLong( header ) );
|
|
SendChar( ZPAD );
|
|
SendChar( ZPAD );
|
|
SendChar( ZDLE );
|
|
SendChar( ZHEX );
|
|
SendHexEncodedChar( type );
|
|
crc.update( type );
|
|
for ( n = 0 ; n < len ; n++ ) {
|
|
SendHexEncodedChar( header[ n ] );
|
|
crc.update( 0xff & header[ n ] );
|
|
}
|
|
crc.update( 0 );
|
|
crc.update( 0 );
|
|
SendHexEncodedChar( crc.value() >> 8 );
|
|
SendHexEncodedChar( crc.value() );
|
|
SendChar( CR );
|
|
SendChar( LF | 0x80 );
|
|
if ( type != ZFIN && type != ZACK )
|
|
SendChar( XON );
|
|
|
|
|
|
SendCharToComm();
|
|
}
|
|
|
|
// Reading in headers and data subpackets is a relatively
|
|
// difficult job. The next four routines combine to read in
|
|
// headers. The first routine dispatches one of the next three,
|
|
// depending on what the header type is.
|
|
|
|
int Zmodem::ReadHeader( char *header )
|
|
{
|
|
int c;
|
|
int n;
|
|
int cancount;
|
|
Settings settings;
|
|
|
|
ReadSettings( settings );
|
|
n = 1400;
|
|
n += ( settings.BaudRate > 19200L ) ?
|
|
19200 : (int) settings.BaudRate;
|
|
|
|
startover:
|
|
cancount = 0;
|
|
again:
|
|
switch ( c = ReadChar( 10000L ) ) {
|
|
case TIMEOUT:
|
|
goto finished;
|
|
case CAN:
|
|
gotcan:
|
|
if ( ++cancount >= 5 ) {
|
|
c = ZCAN;
|
|
goto finished;
|
|
}
|
|
switch ( c = ReadChar( 100 ) ) {
|
|
case TIMEOUT:
|
|
goto again;
|
|
case ZCRCW:
|
|
switch ( ReadChar( 100 ) )
|
|
{
|
|
case TIMEOUT:
|
|
c = ZERROR;
|
|
goto finished;
|
|
default:
|
|
goto agn2;
|
|
}
|
|
default:
|
|
break;
|
|
case CAN:
|
|
if ( ++cancount >= 5 ) {
|
|
c = ZCAN;
|
|
goto finished;
|
|
}
|
|
goto again;
|
|
}
|
|
default:
|
|
agn2:
|
|
if ( --n == 0 ) {
|
|
c = GARBAGE_COUNT;
|
|
goto finished;
|
|
}
|
|
goto startover;
|
|
case ZPAD | 0x80: /* This is what we want. */
|
|
case ZPAD:
|
|
break;
|
|
}
|
|
cancount = 0;
|
|
splat:
|
|
switch ( c = ReadUnencodedByte() ) {
|
|
case ZPAD:
|
|
goto splat;
|
|
case TIMEOUT:
|
|
goto finished;
|
|
default:
|
|
goto agn2;
|
|
case ZDLE: /* This is what we want. */
|
|
break;
|
|
}
|
|
|
|
c = ReadUnencodedByte();
|
|
switch ( c ) {
|
|
case ZBIN32:
|
|
current_frame_uses_crc32 = 1;
|
|
c = ReadBinaryHeaderCRC32( header );
|
|
break;
|
|
case TIMEOUT:
|
|
goto finished;
|
|
case ZBIN:
|
|
current_frame_uses_crc32 = 0;
|
|
c = ReadBinaryHeaderCRC16( header );
|
|
break;
|
|
case ZHEX:
|
|
current_frame_uses_crc32 = 0;
|
|
c = ReadHexHeaderCRC16( header );
|
|
break;
|
|
case CAN:
|
|
goto gotcan;
|
|
default:
|
|
goto agn2;
|
|
}
|
|
received_file_position = header[ ZP3 ] & 0xff;
|
|
received_file_position <<= 8;
|
|
received_file_position += header[ ZP2 ] & 0xff;
|
|
received_file_position <<= 8;
|
|
received_file_position += header[ ZP1 ] & 0xff;
|
|
received_file_position <<= 8;
|
|
received_file_position += header[ ZP0 ] & 0xff;
|
|
finished:
|
|
switch ( c ) {
|
|
case GOTCAN:
|
|
c = ZCAN;
|
|
/* **** FALL THRU TO **** */
|
|
case ZNAK:
|
|
case ZCAN:
|
|
case ZERROR:
|
|
case TIMEOUT:
|
|
case GARBAGE_COUNT:
|
|
error( "Got %s", frametypes[ c + 4 ] );
|
|
/* **** FALL THRU TO **** */
|
|
default:
|
|
if ( c >= -4 && c <= 22 )
|
|
error( "ReadHeader: %s %lx",
|
|
frametypes[ c + 4 ],
|
|
received_file_position );
|
|
else
|
|
error( "ReadHeader: %d %lx",
|
|
c,
|
|
received_file_position );
|
|
}
|
|
return c;
|
|
}
|
|
|
|
// At this point most of the hard work has been done. The next
|
|
//three routines just read in the type of header and the data
|
|
// associated with it, then check to see if the CRC is correct.
|
|
|
|
int Zmodem::ReadBinaryHeaderCRC16( char *header )
|
|
{
|
|
int c;
|
|
int i;
|
|
Crc16 crc( 0 );
|
|
int header_type;
|
|
CString strLogTmp=_T("");
|
|
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff )
|
|
return c;
|
|
header_type = c;
|
|
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRead: %d\t\t\t\tin ReadBinaryHeaderCRC16"), __LINE__,
|
|
GetTickCount() - dwBegin, header_type);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
crc.update( c );
|
|
|
|
for ( i = 0 ; i < 4 ; i++ ) {
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff )
|
|
return c;
|
|
crc.update( c );
|
|
header[ i ] = (char) c;
|
|
}
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff )
|
|
return c;
|
|
crc.update( c );
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff )
|
|
return c;
|
|
crc.update( c );
|
|
if ( crc.value() & 0xFFFF ) {
|
|
error( "Bad CRC" );
|
|
return ZERROR;
|
|
}
|
|
return header_type;
|
|
}
|
|
|
|
int Zmodem::ReadBinaryHeaderCRC32( char *header )
|
|
{
|
|
int c;
|
|
int i;
|
|
Crc32 crc( 0xFFFFFFFFL );
|
|
int header_type;
|
|
CString strLogTmp=_T("");
|
|
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff )
|
|
return c;
|
|
header_type = c;
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRead: %d\t\t\t\tin ReadBinaryHeaderCRC32"), __LINE__,
|
|
GetTickCount() - dwBegin, header_type);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
crc.update( c );
|
|
|
|
for ( i = 0 ; i < 4 ; i++ ) {
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff )
|
|
return c;
|
|
crc.update( c );
|
|
header[ i ] = (char) c;
|
|
}
|
|
for ( i = 0; i < 4 ; i++ ) {
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff )
|
|
return c;
|
|
crc.update( c );
|
|
}
|
|
if ( crc.value() != 0xDEBB20E3L ) {
|
|
error( "Bad CRC" );
|
|
return ZERROR;
|
|
}
|
|
return header_type;
|
|
}
|
|
|
|
int Zmodem::ReadHexHeaderCRC16( char *header )
|
|
{
|
|
int c;
|
|
Crc16 crc( 0 );
|
|
int i;
|
|
int header_type;
|
|
CString strLogTmp = _T("");
|
|
|
|
if ( ( c = ReadHexByte() ) < 0 )
|
|
return c;
|
|
header_type = c;
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRead: %d\t\t\t\tin ReadHexHeaderCRC16"), __LINE__,
|
|
GetTickCount() - dwBegin, header_type);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
crc.update( c );
|
|
|
|
for ( i = 0 ; i < 4 ; i++ ) {
|
|
if ( ( c = ReadHexByte() ) < 0 )
|
|
return c;
|
|
crc.update( c );
|
|
header[ i ] = (char) c;
|
|
}
|
|
if ( ( c = ReadHexByte() ) < 0 )
|
|
return c;
|
|
crc.update( c );
|
|
if ( ( c = ReadHexByte() ) < 0 )
|
|
return c;
|
|
crc.update( c );
|
|
if ( crc.value() & 0xFFFF ) {
|
|
error( "Bad CRC" );
|
|
return ZERROR;
|
|
}
|
|
switch ( c = ReadChar( 100 ) ) {
|
|
case CR :
|
|
case CR | 0x80 :
|
|
ReadChar( 100 );
|
|
}
|
|
return header_type;
|
|
}
|
|
|
|
// The next three routines are used to read in binary data
|
|
// subpackets. This code is somewhat simpler than the code
|
|
// used to read in a header, mostly because there are fewer
|
|
// things to go wrong.
|
|
|
|
int Zmodem::ReadDataFrame( char *buffer, int length )
|
|
{
|
|
int typee;
|
|
CString strLogTmp = _T("");
|
|
|
|
if ( current_frame_uses_crc32 )
|
|
{
|
|
typee = ReadDataFrameCRC32( buffer, length );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRead: %d\t\t\t\tin ReadDataFrame CRC32"), __LINE__,
|
|
GetTickCount() - dwBegin, typee);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
return typee;
|
|
}
|
|
else
|
|
{
|
|
typee = ReadDataFrameCRC16( buffer, length );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRead: %d\t\t\t\tin ReadDataFrame CRC16"), __LINE__,
|
|
GetTickCount() - dwBegin, typee);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
return typee;
|
|
}
|
|
}
|
|
|
|
int Zmodem::ReadDataFrameCRC32( char *buffer, int length )
|
|
{
|
|
int c;
|
|
Crc32 crc( 0xFFFFFFFFL );
|
|
char *end;
|
|
int d;
|
|
|
|
CString strLogTmp = _T("");
|
|
|
|
Rxcount = 0;
|
|
end = buffer + length;
|
|
while ( buffer <= end ) {
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff ) {
|
|
crcfoo:
|
|
switch ( c ) {
|
|
case GOTCRCE:
|
|
case GOTCRCG:
|
|
case GOTCRCQ:
|
|
case GOTCRCW:
|
|
d = c;
|
|
c &= 0xff;
|
|
crc.update( c );
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff )
|
|
goto crcfoo;
|
|
crc.update( c );
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff )
|
|
goto crcfoo;
|
|
crc.update( c );
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff )
|
|
goto crcfoo;
|
|
crc.update( c );
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff )
|
|
goto crcfoo;
|
|
crc.update( c );
|
|
if ( crc.value() != 0xDEBB20E3L ) {
|
|
error( "Bad CRC" );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRead:\t\tCRC32:Bad CRC"), __LINE__,
|
|
GetTickCount() - dwBegin);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
return ZERROR;
|
|
}
|
|
Rxcount = (int) ( length - (end - buffer) );
|
|
error( "ReadDataFrameCRC32: %d %s",
|
|
Rxcount,
|
|
Zendnames[ d - GOTCRCE & 3 ] );
|
|
return d;
|
|
case GOTCAN:
|
|
error( "Sender Canceled" );
|
|
return ZCAN;
|
|
case TIMEOUT:
|
|
error( "TIMEOUT" );
|
|
return c;
|
|
default:
|
|
error( "Garbled data subpacket" );
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRead:\t\tCRC32:Garbled data subpacket"), __LINE__,
|
|
GetTickCount() - dwBegin);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
return c;
|
|
}
|
|
}
|
|
*buffer++ = (char) c;
|
|
crc.update( c );
|
|
}
|
|
error( "Data subpacket too long" );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRead:\t\tCRC32:subpacket too long"), __LINE__,
|
|
GetTickCount() - dwBegin);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
return ZERROR;
|
|
}
|
|
|
|
int Zmodem::ReadDataFrameCRC16( char *buffer, int length )
|
|
{
|
|
int c;
|
|
Crc16 crc( 0 );
|
|
char *end;
|
|
int d;
|
|
|
|
CString strLogTmp = _T("");
|
|
|
|
Rxcount = 0;
|
|
end = buffer + length;
|
|
while ( buffer <= end ) {
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff ) {
|
|
crcfoo:
|
|
switch ( c ) {
|
|
case GOTCRCE:
|
|
case GOTCRCG:
|
|
case GOTCRCQ:
|
|
case GOTCRCW:
|
|
crc.update( (d = c) & 0xff );
|
|
if ( ( c = ReadEncodedByte()) & ~0xff )
|
|
goto crcfoo;
|
|
crc.update( c );
|
|
if ( ( c = ReadEncodedByte() ) & ~0xff )
|
|
goto crcfoo;
|
|
crc.update( c );
|
|
if ( crc.value() & 0xFFFF ) {
|
|
error( "Bad CRC");
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRead:\t\tCRC16:Bad CRC"), __LINE__,
|
|
GetTickCount() - dwBegin);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
return ZERROR;
|
|
}
|
|
Rxcount = (int) ( length - ( end - buffer ) );
|
|
error( "ReadDataFrame: %d %s",
|
|
Rxcount,
|
|
Zendnames[ d - GOTCRCE & 3 ] );
|
|
return d;
|
|
case GOTCAN:
|
|
error( "Sender Canceled" );
|
|
return ZCAN;
|
|
case TIMEOUT:
|
|
error( "TIMEOUT" );
|
|
return c;
|
|
default:
|
|
error( "Garbled data subpacket" );
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRead:\t\tCRC16:Garbled data subpacket"), __LINE__,
|
|
GetTickCount() - dwBegin);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
return c;
|
|
}
|
|
}
|
|
*buffer++ = (char) c;
|
|
crc.update( c );
|
|
}
|
|
error( "Data subpacket too long" );
|
|
|
|
//log
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRead:\t\tCRC16:subpacket too long"), __LINE__,
|
|
GetTickCount() - dwBegin);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
return ZERROR;
|
|
}
|
|
|
|
// The attention string processor has to process a couple of
|
|
// special characters used to sleep and send breaks.
|
|
|
|
void Zmodem::SendAttentionString()
|
|
{
|
|
int i = 0;
|
|
int c;
|
|
long timer;
|
|
|
|
while ( TXSpaceUsed() > 0 )
|
|
//port->IdleFunction();
|
|
while ( ( c = attention_string[ i++ ] ) != 0 ) {
|
|
switch ( c ) {
|
|
case 0xde :
|
|
timer = ReadTime() + 1000L;
|
|
while ( ReadTime() < timer )
|
|
// port->IdleFunction();
|
|
break;
|
|
case 0xdd :
|
|
//port->Break();
|
|
break;
|
|
default:
|
|
SendChar( c );
|
|
}
|
|
}
|
|
}
|
|
|
|
// This function is called by the receiver before exiting.
|
|
|
|
void Zmodem::AckZFIN( void )
|
|
{
|
|
int n;
|
|
|
|
status( "AckZFIN" );
|
|
PackLongIntoHeader( 0L );
|
|
for ( n = 0 ; n < 7 ; n++ ) {
|
|
/*port->FlushRXBuffer();*/
|
|
SendHexHeader( 4, ZFIN, transmitted_header );
|
|
switch ( ReadChar( 10000L ) ) {
|
|
case 'O':
|
|
ReadChar( 120 ); /* Discard 2nd 'O' */
|
|
status( "AckZFIN complete" );
|
|
return;
|
|
case TIMEOUT:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// This utility routine has to scan the incoming data subpacket
|
|
// for the file name and length.
|
|
|
|
int Zmodem::OpenInputFile( CString Path, char *data )
|
|
{
|
|
CString szFileName(data);
|
|
Path+=szFileName;
|
|
|
|
m_FileSize = GetFileSize(data + szFileName.GetLength() + 1);//这个地方把文件名之后的信息传进去
|
|
|
|
//log
|
|
CString strLogTmp = _T("");
|
|
// strcpy( file_name, data );
|
|
strLogTmp.Empty();
|
|
strLogTmp.Format(_T("[%d] Duration: %d\t\t\t\t\t\tRead: %s"), __LINE__,
|
|
GetTickCount() - dwBegin,data);
|
|
PrintLogLast(strLogTmp);
|
|
//log
|
|
|
|
strcpy( file_name, data );
|
|
if (sscanf(data+strlen(data)+1, "%ld", &file_length ) < 1 )
|
|
file_length = -1L;
|
|
file = fopen( Path.GetBuffer(Path.GetLength()), "wb" );
|
|
|
|
if (NULL == file)
|
|
{
|
|
DWORD dwErrNo = GetLastError();
|
|
CString strTmp = _T("");
|
|
if (LANG_ZHCN == g_iUILanguage)
|
|
{
|
|
strTmp.Format(_T("[%d] 打开文件失败!, 错误码 = %d"), __LINE__, dwErrNo);
|
|
AfxMessageBox(strTmp.GetBuffer(0));
|
|
}
|
|
else
|
|
{
|
|
strTmp.Format(_T("[%d] Open file failed!, error = %d"), __LINE__, dwErrNo);
|
|
MessageBoxEx(NULL, strTmp, STRING_MESSAGEBOXEX_TITLE, MB_OK, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
|
|
}
|
|
PrintLogLast(strTmp);
|
|
return ZERROR;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
// File position values are longs packed into a four byt header.
|
|
// The following two routines are resposible for packing and
|
|
// unpacking the data.
|
|
|
|
void Zmodem::PackLongIntoHeader( long header_data )
|
|
{
|
|
transmitted_header[ ZP0 ] = (char) header_data;
|
|
transmitted_header[ ZP1 ] = (char) ( header_data >> 8 );
|
|
transmitted_header[ ZP2 ] = (char) ( header_data >> 16 );
|
|
transmitted_header[ ZP3 ] = (char) ( header_data >> 24 );
|
|
}
|
|
|
|
long Zmodem::UnpackHeaderIntoLong( char *header )
|
|
{
|
|
long l;
|
|
|
|
l = header[ ZP3 ] & 0xff;
|
|
l = ( l << 8 ) | ( header[ ZP2 ] & 0xff );
|
|
l = ( l << 8 ) | ( header[ ZP1 ] & 0xff );
|
|
l = ( l << 8 ) | ( header[ ZP0 ] & 0xff );
|
|
return l;
|
|
}
|
|
|
|
// Hex headers need to send data in hex format.
|
|
void Zmodem::SendHexEncodedChar( int c )
|
|
{
|
|
static char *digits = "0123456789abcdef";
|
|
|
|
SendChar( digits[ ( c & 0xF0 ) >> 4 ] );
|
|
SendChar( digits[ c & 0xF ] );
|
|
}
|
|
|
|
// This routine handles all the escape sequences necessary to send
|
|
// control characters.
|
|
|
|
void Zmodem::SendEncodedChar( int c ,bool b)
|
|
{
|
|
if ( c & 0x60 )
|
|
SendChar( last_char_sent = c ,b);
|
|
else {
|
|
switch ( c &= 0xff ) {
|
|
case CR :
|
|
case CR | 0x80 :
|
|
if ( ( last_char_sent & 0x7f ) != '@' ) {
|
|
SendChar( last_char_sent = c ,b);
|
|
break;
|
|
} // else fall through
|
|
case ZDLE :
|
|
case DLE :
|
|
case XON :
|
|
case XOFF :
|
|
case DLE | 0x80 :
|
|
case XON | 0x80 :
|
|
case XOFF | 0x80 :
|
|
SendChar( ZDLE ,b);
|
|
c ^= 0x40;
|
|
SendChar( last_char_sent = c ,b);
|
|
break;
|
|
default:
|
|
SendChar( last_char_sent = c ,b);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Read a byte, taking into account escape sequences, and checking
|
|
// for the 5*CAN abort sequence.
|
|
|
|
int Zmodem::ReadEncodedByte( void )
|
|
{
|
|
int c;
|
|
|
|
for ( ; ; ) {
|
|
c = ReadChar( 10000L );
|
|
if ( c == ZDLE )
|
|
break;
|
|
switch ( c ) {
|
|
case XON :
|
|
case XON | 0x80 :
|
|
case XOFF :
|
|
case XOFF | 0x80 :
|
|
break;
|
|
default:
|
|
return c;
|
|
}
|
|
}
|
|
for ( ; ; ) {
|
|
if ( ( c = ReadChar( 10000L ) ) < 0 )
|
|
return c;
|
|
if ( c == CAN && ( c = ReadChar( 10000L ) ) < 0 )
|
|
return c;
|
|
if ( c == CAN && ( c = ReadChar( 10000L ) ) < 0 )
|
|
return c;
|
|
if ( c == CAN && ( c = ReadChar( 10000L ) ) < 0 )
|
|
return c;
|
|
switch ( c ) {
|
|
case CAN:
|
|
return GOTCAN;
|
|
case ZCRCE:
|
|
case ZCRCG:
|
|
case ZCRCQ:
|
|
case ZCRCW:
|
|
return c | GOTFLAG;
|
|
case ZRUB0:
|
|
return 0x7f;
|
|
case ZRUB1:
|
|
return 0xff;
|
|
case XOFF :
|
|
case XOFF | 0x80 :
|
|
case XON :
|
|
case XON | 0x80 :
|
|
break;
|
|
default:
|
|
if ( ( c & 0x60 ) == 0x40 )
|
|
return ( c ^ 0x40 );
|
|
else
|
|
return ZERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
// This routine reads a raw data byte, throws out the parity bit and
|
|
// ignores handshaking characters.
|
|
|
|
int Zmodem::ReadUnencodedByte( void )
|
|
{
|
|
int c;
|
|
|
|
for ( ; ; ) {
|
|
if ( ( c = ReadChar( 10000L ) ) < 0 )
|
|
return c;
|
|
switch ( c &= 0x7f ) {
|
|
case XON:
|
|
case XOFF:
|
|
continue;
|
|
default:
|
|
return c;
|
|
}
|
|
}
|
|
}
|
|
|
|
// When reading Hex headers, we need to convert hex values to a
|
|
// usable format.
|
|
int Zmodem::ReadHexByte( void )
|
|
{
|
|
int c;
|
|
int n;
|
|
|
|
if ( ( c = ReadUnencodedByte() ) < 0 )
|
|
return c;
|
|
n = c - '0';
|
|
if ( n > 9 )
|
|
n -= ( 'a' - ':' );
|
|
if ( n & ~0xF )
|
|
return ZERROR;
|
|
if ( ( c = ReadUnencodedByte( )) < 0 )
|
|
return c;
|
|
c -= '0';
|
|
if ( c > 9 )
|
|
c -= ( 'a' - ':' );
|
|
if ( c & ~0xF )
|
|
return ZERROR;
|
|
c += ( n << 4 );
|
|
return c;
|
|
}
|
|
|
|
// The sender needs to get the RINIT frame before it can start
|
|
// sending the file. This routine takes care of that.
|
|
|
|
int Zmodem::GetRinitHeader( void )
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0 ; i < 10 ; i++ ) {
|
|
switch ( ReadHeader( received_header ) ) {
|
|
case ZCHALLENGE: // Echo receiver's challenge number
|
|
PackLongIntoHeader( received_file_position );
|
|
SendHexHeader( 4, ZACK, transmitted_header );
|
|
continue;
|
|
case ZCOMMAND: // They didn't see our ZRQINIT
|
|
PackLongIntoHeader( 0L );
|
|
SendHexHeader( 4, ZRQINIT, transmitted_header );
|
|
continue;
|
|
case ZRINIT:
|
|
receiver_wants_crc32 = received_header[ ZF0 ] & CANFC32;
|
|
receiver_buffer_length =
|
|
( received_header[ ZP0 ] & 0xff ) +
|
|
( ( received_header[ ZP1 ] & 0xff ) << 8 );
|
|
return OK;
|
|
case ZCAN:
|
|
case TIMEOUT:
|
|
return ZERROR;
|
|
case ZRQINIT:
|
|
if ( received_header[ ZF0 ] == ZCOMMAND )
|
|
continue;
|
|
default:
|
|
SendHexHeader( 4, ZNAK, transmitted_header );
|
|
continue;
|
|
}
|
|
}
|
|
return ZERROR;
|
|
}
|
|
|
|
// This routine sends a data subpacket, which is used here to send
|
|
// file names and file data.
|
|
|
|
void Zmodem::SendDataFrame( char *buffer, int length, int frameend )
|
|
{
|
|
Crc32 crc32( 0xFFFFFFFFL );
|
|
unsigned long crc32val;
|
|
Crc16 crc16( 0 );
|
|
int i;
|
|
|
|
status( "SendDataFrame: %d %s",
|
|
length, Zendnames[ frameend - ZCRCE & 3 ] );
|
|
|
|
int nnlen = 0;
|
|
|
|
if ( receiver_wants_crc32 ) {
|
|
|
|
for ( i = 0 ; i < length ; i++ )
|
|
{
|
|
|
|
SendEncodedChar( buffer[ i ] ,TRUE);
|
|
crc32.update( buffer[ i ] & 0xff );
|
|
}
|
|
|
|
SendChar( ZDLE ,TRUE);
|
|
SendChar( frameend ,TRUE);
|
|
crc32.update( frameend );
|
|
crc32val = ~crc32.value();
|
|
|
|
for ( i = 0 ; i < 4 ; i++ ) {
|
|
SendEncodedChar( (int) crc32val ,TRUE);
|
|
crc32val >>= 8;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
for ( i = 0 ; i < length ; i++ )
|
|
{
|
|
SendEncodedChar( buffer[ i ] ,TRUE);
|
|
crc16.update( buffer[ i ] & 0xff );
|
|
}
|
|
|
|
SendChar( ZDLE ,TRUE);
|
|
SendChar( frameend ,TRUE);
|
|
crc16.update( frameend );
|
|
crc16.update( 0 );
|
|
crc16.update( 0 );
|
|
SendEncodedChar( crc16.value() >> 8 ,TRUE);
|
|
SendEncodedChar( crc16.value() ,TRUE);
|
|
}
|
|
|
|
if ( frameend == ZCRCW )
|
|
SendChar( XON ,TRUE);
|
|
|
|
SendCharToComm();
|
|
}
|
|
|
|
// The sender sends a ZFIN frame just before exiting.
|
|
|
|
void Zmodem::SendZFIN( void )
|
|
{
|
|
for ( ; ; ) {
|
|
PackLongIntoHeader( 0L );
|
|
SendHexHeader( 4, ZFIN, transmitted_header );
|
|
switch ( ReadHeader( received_header ) ) {
|
|
case ZFIN:
|
|
SendChar( 'O');
|
|
SendChar( 'O');
|
|
SendCharToComm();
|
|
case ZCAN:
|
|
case TIMEOUT:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
int Zmodem::SyncWithReceiver( int flag )
|
|
{
|
|
int c;
|
|
|
|
for ( ; ; ) {
|
|
c = ReadHeader( received_header );
|
|
switch ( c ) {
|
|
case ZCAN:
|
|
case ZABORT:
|
|
case ZFIN:
|
|
case TIMEOUT:
|
|
return ZERROR;
|
|
case ZRPOS:
|
|
if ( fseek( file, received_file_position, SEEK_SET ) )
|
|
return ZERROR;
|
|
file_at_eof = 0;
|
|
byte_count = last_reported_position
|
|
= transmitted_file_position = received_file_position;
|
|
last_sync_position = received_file_position;
|
|
return c;
|
|
case ZACK:
|
|
last_reported_position = received_file_position;
|
|
if ( flag || transmitted_file_position ==
|
|
received_file_position )
|
|
return ZACK;
|
|
continue;
|
|
case ZRINIT:
|
|
case ZSKIP:
|
|
fclose( file );
|
|
return c;
|
|
case ZERROR:
|
|
default:
|
|
SendBinaryHeader( 4, ZNAK, transmitted_header );
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
long Zmodem::ReadTime( void )
|
|
{
|
|
return 0;
|
|
}
|
|
//----------------------------------------------------------------------------------
|
|
int Zmodem::ReadBuff(long timeout)
|
|
{
|
|
/*暂时注释用新写法来写
|
|
int nCountError;
|
|
|
|
nCountError = 0;
|
|
|
|
if (m_BuffCount > 0)
|
|
{
|
|
m_BuffCount -= 1;
|
|
|
|
if(m_BuffCount == 0)
|
|
{
|
|
return (*str & 0377);
|
|
}
|
|
else
|
|
{
|
|
return (*str++ & 0377);
|
|
}
|
|
}
|
|
|
|
m_BuffCount = 0;
|
|
memset(buff,0,BUFFSIZE);
|
|
|
|
do
|
|
{
|
|
port->ZmodemReceiveDataDirectly(buff,&m_BuffCount);
|
|
if (m_BuffCount != 0)
|
|
{
|
|
nCountError = 0;
|
|
str = buff;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
nCountError++;
|
|
Sleep(50);
|
|
}
|
|
|
|
}while(nCountError < 40);
|
|
|
|
if( nCountError == 40 )
|
|
{
|
|
return TIMEOUT;
|
|
}
|
|
|
|
m_BuffCount -=1;
|
|
|
|
if(m_BuffCount == 0)
|
|
{
|
|
return (*str & 0377);
|
|
}
|
|
else
|
|
{
|
|
return (*str++ & 0377);
|
|
}
|
|
*/
|
|
|
|
int nCountError = 0;
|
|
CString strTmp = _T("");
|
|
ClearReadBuf();
|
|
|
|
do
|
|
{
|
|
port->ZmodemReceiveDataDirectly(buff,&m_BuffCount);
|
|
if (0 == m_BuffCount)
|
|
{
|
|
nCountError++;
|
|
Sleep(50);
|
|
}
|
|
else if (m_BuffCount > BUFFSIZE)
|
|
{
|
|
strTmp.Format(_T("[%d] read buffersize is too big than 8K, read_buffer_size = %d"), __LINE__, m_BuffCount);
|
|
PrintLogLast(strTmp);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
|
|
}
|
|
}while(nCountError < 240);
|
|
|
|
strTmp.Format(_T("[%d] read buffersize is TIMEOUT"), __LINE__);
|
|
PrintLogLast(strTmp);
|
|
|
|
return TIMEOUT;
|
|
}
|
|
|
|
void Zmodem::ReadSettings(Settings ©)
|
|
{
|
|
copy.BaudRate = 115200;
|
|
copy.Parity = 'N';
|
|
copy.WordLength = 8;
|
|
copy.StopBits = 1;
|
|
copy.Dtr = 1;
|
|
copy.Rts = 0;
|
|
copy.XonXoff = 0;
|
|
copy.RtsCts = 0;
|
|
copy.DtrDsr = 0;
|
|
}
|
|
|
|
int Zmodem::TXSpaceUsed( void )
|
|
{
|
|
return (m_BuffCount - BUFFSIZE);
|
|
}
|
|
|
|
|
|
|
|
int Zmodem::GetFileSize(char *buffer)
|
|
{
|
|
char cFileSize[64];
|
|
memset(cFileSize, 0, 64);
|
|
int nIndex = 0;
|
|
|
|
while(buffer[nIndex] != ' ')
|
|
{
|
|
cFileSize[nIndex] = buffer[nIndex];
|
|
nIndex++;
|
|
}
|
|
|
|
return atoi(cFileSize);
|
|
}
|
|
|
|
void Zmodem::SendCharToComm()
|
|
{
|
|
port->ZmodemSendDataDirectly(m_WriteBuff, m_WriteBuffLength);
|
|
|
|
memset(m_WriteBuff, 0, 8192);
|
|
m_WriteBuffLength = 0;
|
|
}
|
|
void Zmodem::ClearReadBuf()
|
|
{
|
|
m_BuffCount = 0;
|
|
m_nBufReadIndex = 0;
|
|
memset(buff,0,BUFFSIZE);
|
|
|
|
}
|
|
|
|
void Zmodem::PrintLog(char *chPrtlog, int nLogLen)
|
|
{
|
|
ASSERT(NULL != chPrtlog);
|
|
fwrite(chPrtlog,nLogLen,1,zmodemLog);
|
|
fflush(zmodemLog);
|
|
}
|
|
|
|
void Zmodem::PrintLogLast(CString& strLog)
|
|
{
|
|
if (NULL == zmodemLog)
|
|
{
|
|
if (LANG_ZHCN == g_iUILanguage)
|
|
AfxMessageBox(_T("无法写入device_log,日志文件点为空"));
|
|
else
|
|
MessageBoxEx(NULL, _T("Can't write device_log, log File point is NULL"), _T("LOG_ERROR"), MB_OK, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
|
|
return;
|
|
}
|
|
CString strOutPut = _T("");
|
|
strOutPut.Format(_T("%04d-%02d-%02d %02d:%02d:%02d.%03d %s \r\n"),g_sysCurTime.wYear, g_sysCurTime.wMonth, g_sysCurTime.wDay,
|
|
g_sysCurTime.wHour, g_sysCurTime.wMinute, g_sysCurTime.wSecond, g_sysCurTime.wMilliseconds, strLog.GetBuffer(0));
|
|
fwrite(strOutPut.GetBuffer(0), 1, strOutPut.GetLength(), zmodemLog);
|
|
fflush(zmodemLog);
|
|
}
|
|
|
|
|
|
int Zmodem::GetFileSize()
|
|
{
|
|
return m_FileSize;
|
|
}
|
|
|
|
int Zmodem::GetTransferPosit()
|
|
{
|
|
return m_ByteTransfer;
|
|
}
|
|
|
|
BOOL Zmodem::SendCancelString()
|
|
{
|
|
char chCancelString[] = {
|
|
CAN, CAN, CAN, CAN, CAN, CAN, CAN, CAN, CAN, CAN,
|
|
BS, BS, BS, BS, BS, BS, BS, BS, BS, BS };
|
|
return port->ZmodemSendDataDirectly( chCancelString, sizeof(chCancelString));//tmp
|
|
} |