Source file: /~heha/enas/Kleingeräte/srserver.zip/src/sertrans.cpp

#include <windows.h>
#include <stdio.h>
#include "blockio.h"

static bool IsCommand(int cmd) {
 return(cmd>='A' && cmd<='Z');  // commands are uppercase characters
}

int SerialReceiveFile(HANDLE fh,char* fileName,char* block,DWORD restartat){
 int err=TimedSendChar(RQ_READY,5000);
 if (err) return err_send;
 uint32_t fileSize=0,fileRead=restartat;
 uint32_t datareceived;
 uint32_t blockoffset=0;
 uint8_t sequencenr=0;
 uint8_t expectedsequencenr=0;
 FILETIME fileDate={0,0};
 for(;;) {
  int retries=0;		// Receive a whole block
  do {
   err=ReceiveNextBlock(block+blockoffset,maxblocksizeusb-blockoffset,&datareceived,&sequencenr);
   if (IsCommand(err)) {	// upload was aborted, this is already a new command!
    TimedSendChar(RQ_CRCERR,5000); // requests re-send
    return CMD_CRCERR;		// wrong block received!
   }
   if (err==CMD_BODY && expectedsequencenr!=sequencenr)
     err=CMD_CRCERR;	// wrong block received!
   if (err==CMD_CRCERR) {
    printf("CRC-Error");
    ClearBuffers(PURGE_RXCLEAR);
    TimedSendChar(RQ_CRCERR,5000);
   }
   if (err==CMD_TIMEOUT) {
    printf("Timeout!");
    Sleep(1000);
    ClearBuffers(PURGE_RXCLEAR);
    TimedSendChar(RQ_CRCERR,500);
    Sleep(2000);
   }
  } while ((err==CMD_CRCERR || err==CMD_TIMEOUT) && retries++<10);
  if (err==CMD_ABORT || err==CMD_RECVERR || err==CMD_CRCERR || err==CMD_TIMEOUT)
    return err;
  if (err==CMD_BODY) expectedsequencenr++;
  if (err==CMD_EOF) {
   if (blockoffset>0) {
    DWORD written;
    if (!WriteFile(fh,block,blockoffset,&written,NULL)) return err_file;
    fileRead += blockoffset;
   }
   if (fileDate.dwHighDateTime||fileDate.dwLowDateTime)
     SetFileTime(fh,NULL,NULL,&fileDate);
   TimedSendChar(RQ_OK,5000);
   break;
  }
  if (err==CMD_SIZE) {		// size block
   char*pdate=strchr(block,'\t');
   if (pdate) {
    *pdate=0;
    ConvertIsoDateToDateTime(++pdate,fileDate);
   }
   fileSize = atoi(block);	// Send acknowledge for block
   err = TimedSendChar(RQ_OK,5000);
  }else if (err==CMD_BODY) {	// body
   uint32_t writesize;		// Send acknowledge for block
   err = TimedSendChar(RQ_OK,5000);
		// Write to file if there is any data to write
   writesize=datareceived;
   if (fh!=INVALID_HANDLE_VALUE) {
				// If less than 16k received, just increase block offset
				// but only if blockoffset+2*DataReceived<maxblocksize
    if (writesize<16384 && blockoffset+2*writesize<maxblocksizeusb) blockoffset+=writesize;
    else {
     DWORD written;
     if (!WriteFile(fh,block,blockoffset+writesize,&written,NULL)) return err_file;
     blockoffset=0;
    }
    fileRead += writesize;
   }
  }
 }
 return 0;
}

int SerialSendFile(HANDLE fh,char* filename,char* block,DWORD resumeat, BOOL sizeonly) {
 uint32_t filesize;
 uint8_t sequencenr;
 FILETIME ft;
 int err;
 char bytereceived;
 HANDLE searchhandle=0;
 WIN32_FIND_DATA srec;

 if (fh!=INVALID_HANDLE_VALUE) filesize=GetFileSize(fh,NULL);
 else{
  char dirbuf[MAX_PATH];
  filesize=0xFFFFFFFF;
  strncpy(dirbuf,filename+1,sizeof dirbuf-3);
  char*p=dirbuf+strlen(dirbuf);
  if (p[-1]=='\\') --p;	// avoid double backslash (not good searching "c:\\*")
  strcpy(p,"\\*");	// find any file
  searchhandle=FindFirstFile(dirbuf,&srec);
 }
 sequencenr=0;
	// Wait for RQ_READY
 err=TimedReceiveChar(&bytereceived,5000);

 if (err) {	// timeout!
  printf("Initial byte timeout!");
  if (searchhandle!=INVALID_HANDLE_VALUE) FindClose(searchhandle);
  return err;
 }
 if (bytereceived!=RQ_READY) {
  printf("Initial byte receive error!");
  if (searchhandle!=INVALID_HANDLE_VALUE) FindClose(searchhandle);
  return err_recv;
 }	
	// send header block
 sprintf(block,"%d",filesize);
	// send also date, separated by a Tab
 if (GetFileTime(fh,NULL,NULL,&ft)) {
  char *p=block+strlen(block);
  strcpy(p,"\t");
  if (!CreateIsoDateString(ft,p+1)) p[0]=0; //yyyymmddhhmmss 
			   // don't send tab in case of error
  err=SendNextBlockRetry10(CMD_SIZE,block,strlen(block)+1,0);
  if (err!=RQ_OK) {
   printf("Size block not acknowledged!");
   if (searchhandle!=INVALID_HANDLE_VALUE) FindClose(searchhandle);
   if (err==RQ_LOCALABORT) return err_abort;
   return err_recv;
  }
  if (sizeonly) {
   if (searchhandle!=INVALID_HANDLE_VALUE) FindClose(searchhandle);
   return 0;
  }
 }
	// send body
 DWORD offset = resumeat;
 while (offset < filesize) {
  int blocksize=filesize-offset;
  if (blocksize>maxblocksize) blocksize=maxblocksize;
  if (filename[0]=='\\' && filename[1]==0) {  // drives!
   block[0]=0;
   char* pNextName=block;
   char drvbuf[8];
   char ch;
   for (ch='A';ch<='Z';ch++) {
    strcpy(drvbuf,"a:\\");
    drvbuf[0]=ch;
    int tp=GetDriveType(drvbuf);
    if (tp!=DRIVE_UNKNOWN && tp!=DRIVE_NO_ROOT_DIR) {
     strcpy(pNextName,drvbuf);
     strcat(pNextName,"\r\n");
     pNextName+=strlen(pNextName);
    }
   }
   blocksize=pNextName-(char*)block;   // without #0 at end!
   offset=filesize;
  }else if (fh==INVALID_HANDLE_VALUE) {  // directory!
   block[0]=0;
   blocksize=0;
   char* pEndBody;
   char* pNextName=block;
   blocksize=1024;	//maxblocksize;
   pEndBody=block+blocksize-262;	// if more files, continue in next block
   while (searchhandle!=INVALID_HANDLE_VALUE && pNextName<pEndBody) {
    if (strcmp(srec.cFileName,".") && strcmp(srec.cFileName,"..")) {
     if (srec.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
      pNextName+=sprintf(pNextName,"%s\\\t0\t",srec.cFileName);
     }else{
      pNextName+=sprintf(pNextName,"%s\t%d\t",srec.cFileName,srec.nFileSizeLow);
     }
     pNextName+=CreateIsoDateString(srec.ftLastWriteTime,pNextName);
     pNextName+=sprintf(pNextName,"\t%d\r\n",srec.dwFileAttributes);
    }
    if (!FindNextFile(searchhandle,&srec)) {
     FindClose(searchhandle);
     searchhandle=INVALID_HANDLE_VALUE;
    }
    blocksize=pNextName-(char*)block; // without #0 at end!
   }
   if (searchhandle==INVALID_HANDLE_VALUE) offset=filesize;
  }else if (blocksize>0) {
   DWORD numBytesRead;
   if (!ReadFile(fh,block,blocksize,&numBytesRead,NULL)) {
    printf("ReadFile failed!");
    return err_recv;
   }
  }
  err=SendNextBlockRetry10(CMD_BODY,block,blocksize,sequencenr);
  if (err!=RQ_OK) {
   printf("Body block not acknowledged!");
   if (searchhandle!=INVALID_HANDLE_VALUE) FindClose(searchhandle);
   if (err==RQ_LOCALABORT) return err_abort;
   return err_recv;
  }
  sequencenr++;
  if (filesize!=0xFFFFFFFF) {
   offset += blocksize;
  }
 }
 if (searchhandle!=INVALID_HANDLE_VALUE) FindClose(searchhandle);
	// Send end of file block
 err=SendNextBlockRetry10(CMD_EOF,NULL,0,0);
 if (err!=RQ_OK) {	// timeout!
  printf("End of file block not acknowledged!");
  if (err==RQ_LOCALABORT) return err_abort;
  return err_recv;
 }
 return err_ok;
}


int SerialSendChar(char byte) {
 return TimedSendChar(byte,5000);
}

/********* utils.cpp ***************/

static int atoi1(const char*s) {return *s-'0';}
static int atoi2(const char*s) {return atoi1(s)*10+atoi1(s+1);}
static int atoi4(const char*s) {return atoi2(s)*100+atoi2(s+2);}

bool ConvertIsoDateToDateTime(const char*s,FILETIME&ft) {
 SYSTEMTIME st;
 st.wYear=atoi4(s);
 st.wMonth=atoi2(s+4);
 st.wDay=atoi2(s+6);
 st.wHour=atoi2(s+8);
 st.wMinute=atoi2(s+10);
 st.wSecond=atoi2(s+12);
 st.wDayOfWeek=0;
 st.wMilliseconds=0;
 FILETIME ft2;
 if (!SystemTimeToFileTime(&st,&ft2)) {
  ft.dwHighDateTime=0xFFFFFFFF;
  ft.dwLowDateTime=0xFFFFFFFF;
  return false;
 }
 return !!LocalFileTimeToFileTime(&ft2,&ft);  // Totalcmd expects system time!
}

static void itoa2(char*s,int v) {	// <v> must be <= 99
 s[0]=v/10+'0';
 s[1]=v%10+'0';
}
static void itoa4(char*s,int v) {	// <v> must be <=9999
 itoa2(s,v/100);
 itoa2(s+2,v%100);
}

bool CreateIsoDateString(const FILETIME&ft,char*s) {
 FILETIME ft2;
 FileTimeToLocalFileTime(&ft,&ft2);  // Totalcmd expects system time!
 SYSTEMTIME datetime;
 if (FileTimeToSystemTime(&ft2,&datetime)) {
  itoa4(s,datetime.wYear);
  itoa2(s+4,datetime.wMonth);
  itoa2(s+6,datetime.wDay);
  itoa2(s+8,datetime.wHour);
  itoa2(s+10,datetime.wMinute);
  itoa2(s+12,datetime.wSecond);
  s[14]=0;
  return true;
 }
 *s=0;
 return false;
}

WORD Crc16CalcBlock(char*p,int len,WORD crc16) {
 static WORD crctable[256]={
  0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
  0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
  0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
  0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
  0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
  0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
  0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
  0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
  0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
  0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
  0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
  0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
  0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
  0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
  0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
  0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
  0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
  0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
  0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
  0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
  0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
  0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
  0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
  0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
  0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
  0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
  0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
  0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
  0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
  0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
  0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0};
 if (len) do{
  crc16 = crc16<<8 ^ crctable[BYTE(HIBYTE(crc16)^*p++)];
 }while(--len);
 return crc16;
}
Detected encoding: ASCII (7 bit)2