Zipit Z1

Upload程式(C/C++)


程式碼(Windows)如下:

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#define verify assert
#include <windows.h>
#include <conio.h>

HANDLE OpenSerial(int iPort)
{
  char szPort[32];
  
  sprintf(szPort, "COM%d", iPort);
  return CreateFile(szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}

void CloseSerial(HANDLE hSerial)
{
  CloseHandle(hSerial);
}

bool SetCommDefaultsPart1(HANDLE hSerial, int baud)
{
  DCB dcb;

  memset(&dcb, 0, sizeof(DCB));
  dcb.DCBlength = sizeof(DCB);
  dcb.fBinary = TRUE;
  dcb.fParity = TRUE;
  dcb.BaudRate = baud;
  dcb.ByteSize = 8;
  dcb.Parity = NOPARITY;
  dcb.StopBits = ONESTOPBIT;
  dcb.fOutxDsrFlow = FALSE;
  dcb.fDtrControl = DTR_CONTROL_ENABLE;
  dcb.fOutxCtsFlow = FALSE;
  dcb.fRtsControl = RTS_CONTROL_ENABLE;
  dcb.fInX = dcb.fOutX = FALSE;

  if(!SetCommState(hSerial, &dcb)){
    return false;
  }
  return true;
}

bool SetCommDefaults(HANDLE hSerial)
{
  if(!SetCommDefaultsPart1(hSerial, CBR_9600)){
    return false;
  }

  COMMTIMEOUTS to;
  memset(&to, 0, sizeof(to));
  to.ReadIntervalTimeout = MAXDWORD;
  if(!SetCommTimeouts(hSerial, &to)){
    return false;
  }
  PurgeComm(hSerial, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
  return true;
}

bool SetBaud(HANDLE hSerial, int baud)
{
  if(!SetCommDefaultsPart1(hSerial, baud)){
    return false;
  }
  PurgeComm(hSerial, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
  return true;
}

void PurgeSerial(HANDLE hSerial)
{
  while(1){
    BYTE b;
    DWORD cbRead;
    if(!ReadFile(hSerial, &b, 1, &cbRead, NULL)){
      fprintf(stderr, "FATAL: Purge failed for serial port\n");
      exit(-1);
    }
    if(cbRead == 0){
      break;
    }
  }
}

bool PeekSerialByte(HANDLE hSerial, BYTE& bRet)
{
  DWORD cbRead;
  
  if(!ReadFile(hSerial, &bRet, 1, &cbRead, NULL)){
    fprintf(stderr, "FATAL: ReadFile failed for serial port\n");
    exit(-1);
  }
  if(cbRead == 1){
    return true;
  }
  return false;
}

void SendSerialBytes(HANDLE hSerial, const BYTE* pb, int cb)
{
  DWORD cbWrite;
  if(!WriteFile(hSerial, pb, cb, &cbWrite, NULL) || cbWrite != cb){
    fprintf(stderr, "FATAL: WriteFile failed for serial port\n");
    exit(-1);
  }
}

void PrUsage(void)
{
  printf("usage: upl -# file.bin\n");
  printf("  -# = port number [COM1 default]\n");
  exit(-1);
}

bool LoadFile(const char* szInFile, byte* pbImage, int cbImage)
{
  FILE* pfIn = fopen(szInFile, "rb");
  if(pfIn == NULL){
    fprintf(stderr, "FATAL: can't open input file '%s'\n", szInFile);
    return false;
  }
  fseek(pfIn, 0, SEEK_END);
  int cbFile = ftell(pfIn);
  fseek(pfIn, 0, SEEK_SET);

  if(cbFile < cbImage){
    fclose(pfIn);
    fprintf(stderr, "FATAL: input file '%s' wrong size\n", szInFile);
    fprintf(stderr, "\t %d bytes (%d bytes expected)\n", cbFile, cbImage);
    return false;
  }
  
  if(cbFile > cbImage){
    printf("uploading %d bytes of %d byte file\n", cbImage, cbFile);
  }

  if(fread(pbImage, cbImage, 1, pfIn) != 1){
    fclose(pfIn);
    fprintf(stderr, "FATAL: read error on input file '%s'\n", szInFile);
    return false;
  }

  if(cbFile > cbImage){
    int cbExtra = cbFile - cbImage;
    byte* pbExtra = new byte[cbExtra];
    assert(fread(pbExtra, cbExtra, 1, pfIn) == 1);
    int nErr = 0;
    for(int i=0; i<cbExtra; i++){
      if(pbExtra[i] != 0){
        nErr++;
      }
    }

    delete [] pbExtra;
    if(nErr > 0){
      fclose(pfIn);
      fprintf(stderr, "FATAL: non-zero data at end of input file '%s'\n", szInFile);
      return false;
    }
  }
  fclose(pfIn);
  return true;
}
  
FILE* g_pfLog = NULL;
bool EchoSerial(HANDLE hSerial)
{
  BYTE b;
  if(!PeekSerialByte(hSerial, b)){
    return false;
  }
  if(b >= 0x20 && b < 0x7f){
    printf("%c", b);
  }
  else if(b == 0xD || b == 0xA){
    printf("%c", b);
  }
  else{
    printf("$%02x$", b);
  }
  
  if(g_pfLog != NULL){
    fputc((char)b, g_pfLog);
  }
  return true;
}

void EchoSerialTilEmpty(HANDLE hSerial, int nDelay)
{
  for(int iTry=0; iTry<10; iTry++){
    while(EchoSerial(hSerial));
    Sleep(nDelay);
    if(!EchoSerial(hSerial)){
      break;
    }
  }
}

BYTE* LoadFile(const char* szFile, long& cbRet)
{
  FILE* pf = fopen(szFile, "rb");
  
  if(pf == NULL){
    return NULL;
  }
  fseek(pf, 0, SEEK_END);
  cbRet = ftell(pf);
  fseek(pf, 0, SEEK_SET);
  byte* pbFile = new byte[cbRet];
  assert(fread(pbFile, cbRet, 1, pf) == 1);
  fclose(pf);
  return pbFile;
}

BYTE CalcChecksum(const BYTE* pb, long cb)
{
  BYTE csum = 0;
  
  while(cb--){
    csum += *pb++;
  }
  return csum;
}

bool UploadFile(HANDLE hSerial, const char* szFile, BYTE chCmd)
{
  long cbFile;
  byte* pbFile = LoadFile(szFile, cbFile);
  
  if(pbFile == NULL){
    printf("No %s to upload!\n", szFile);
    return false;
  }
  assert(cbFile > 0);
  printf("//Uploading %ld bytes from %s\n", cbFile, szFile);
  SendSerialBytes(hSerial, &chCmd, 1);
  SendSerialBytes(hSerial, (BYTE*)&cbFile, 4);
  Sleep(250);

  //BLOCK: ZPM should reply with "BEG:xxxxxxxx" where xxxxxxxx = hex length
  {
    char reply[4+8+1];
    reply[4+8] = '\0';
    DWORD cbRead;
    long cbAck;
    
    if(!ReadFile(hSerial, reply, sizeof(reply)-1, &cbRead, NULL) ||
      cbRead != sizeof(reply)-1 ||
      memcmp(reply, "BEG:", 4) != 0 ||
      sscanf(reply+4, "%08lX", &cbAck) != 1 ||
      cbAck != cbFile)
    {
      printf("Zipit is not responding - not ready to upload\n");
      printf("\t'%s'\n", reply);
      delete [] pbFile;
      return false;
    }
  }
  SendSerialBytes(hSerial, pbFile, cbFile);

  BYTE csum = CalcChecksum(pbFile, cbFile);
  delete [] pbFile;
  Sleep(500);

  //BLOCK: ZPM should reply with "END:xx" where xx = hex checksum
  {
    char reply[4+2+1];
    reply[4+2] = '\0';
    DWORD cbRead;
    BYTE csumAck;
    
    if(!ReadFile(hSerial, reply, sizeof(reply)-1, &cbRead, NULL) ||
      cbRead != sizeof(reply)-1 ||
      memcmp(reply, "END:", 4) != 0 ||
      sscanf(reply+4, "%02X", &csumAck) != 1)
    {
      printf("Zipit did not upload properly\n");
      return false;
    }
    
    if(csumAck != csum){
      printf("Zipit uploaded incorrectly - checksum mismatch\n");
      return false;
    }
  }
    
  printf("// done upload\n");
  return true;
}

bool GrabFile(HANDLE hSerial, const char* szFile, long cbGrab, BYTE chCmd)
{
  byte* pbGrab = new byte[cbGrab];
  
  assert(cbGrab > 0);
  printf("//Grabbing %ld bytes from ROM - store in %s\n", cbGrab, szFile);

  // send command byte, 'R'
  SendSerialBytes(hSerial, &chCmd, 1);
  int cbSoFar = 0;
  while (cbSoFar < cbGrab){
    DWORD cbRead = 0;
    if(!ReadFile(hSerial, &pbGrab[cbSoFar], cbGrab-cbSoFar, &cbRead, NULL) || cbRead <= 0){
      printf("-");
      Sleep(50);
      continue;
    }
    printf("+");
    assert(cbRead > 0);
    cbSoFar += cbRead;
  }

  FILE* pf = fopen(szFile, "wb");
  verify(pf != NULL);
  verify(fwrite(pbGrab, cbGrab, 1, pf) == 1);
  verify(fclose(pf) == 0);

  delete [] pbGrab;
  return true;
}

BYTE g_rgbImage[2*1024];
int main(int argc, char* argv[])
{
  int iPort = 1;  // default COM1
  const char* szInputSource;
  
  if(argc == 3 && argv[1][0] == '-'){
    iPort = atoi(&argv[1][1]);
    szInputSource = argv[2];
  }
  else if(argc == 2){
    szInputSource = argv[1];
  }
  else{
    PrUsage();
  }
  assert(iPort > 0);

  int cbImage = 2*1024;
  if(!LoadFile(szInputSource, g_rgbImage, cbImage)){
    return -1;
  }

  HANDLE hSerial = OpenSerial(iPort);
  if(hSerial == (HANDLE)-1){
    fprintf(stderr, "Failed to open serial port COM%d\n", iPort);
    exit(-1);
  }

  if(!SetCommDefaults(hSerial)){
    fprintf(stderr, "Failed to set COM%d to 9600 baud\n", iPort);
    CloseSerial(hSerial);
    return -1;
  }
  printf("Connected\n");
  printf("Turn on the Zipit (press button, wait for green, release)\n");
  printf("  Wait 10 seconds, then press any key to start transfer\n");
  printf("  (DBG pin must be grounded)\n");

  int nSkip = 0;
  BYTE bIgnore;
  while(PeekSerialByte(hSerial, bIgnore)){
    nSkip++;
  }
  
  if(nSkip > 0){
    printf("Skipping %d left over data bytes\n");
  }

  while(_kbhit() == 0){
    Sleep(100);
  }
  _getch(); // eat the character

  printf("Transfering bootstrap program\n");
  SendSerialBytes(hSerial, g_rgbImage, cbImage);
  printf("Transfer complete\n");

  Sleep(100);
  printf("Switch to 57.6kbps\n");
  if(!SetBaud(hSerial, 57600)){
    printf("SET BAUD RATE ERROR!\n");
    return -1;
  }

#if 0
  g_pfLog = fopen("log.txt", "at"); // save session
#endif

  printf("Echo + upload commands\n");
  printf("\tDecide what to upload\n");
  printf("\t'A' - allrom.bin upload (2MB)\n");
  printf("\t'a' - loader.bin upload (8K max)\n");
  printf("\t'k' - zimage.dat upload (581K max)\n");
  printf("\t'u' - ramdisk.gz upload (1.5MB max)\n");
  printf("\tFollow changes with 'WYes' to write\n");
  printf("\tOther commands\n");
  printf("\t'R' - grab ROM\n");
  while(1){
    while(EchoSerial(hSerial));
    if(_kbhit()){
      BYTE b = _getch();
      if(b == 'u'){
        UploadFile(hSerial, "ramdisk.gz", b); // -> ramdisk.gz
      }
      else if(b == 'k'){
        UploadFile(hSerial, "zimage.dat", b); // -> kernel.gz
      }
      else if(b == 'a'){
        UploadFile(hSerial, "loader.bin", b); // -> start of ROM image
      }
      else if(b == 'A'){
        UploadFile(hSerial, "allrom.bin", b); // -> start of ROM image
      }
      else if(b == 'R'){
        GrabFile(hSerial, "grabrom.bin", 2*1024*1024, b);
        printf("// grab done -- I hope...\n");
      }
      else if(b == 'Q'){
        printf("// done echo mode\n");
        break;
      }
      else{
        SendSerialBytes(hSerial, &b, 1);
      }
    }
    Sleep(50);  // don't be a total CPU pig
  }
  if(g_pfLog != NULL){
    fclose(g_pfLog);
  }
  g_pfLog = NULL;
  return 0;
}



返回上一頁