// upl - upload to Zipit // version 2.0 - new address ranges/file names // requires ZPM .02 //#include //#include // for keyboard polling //#include #include #include #include #include #include #include #include #include #include //#define verify assert /* lazy runtime check */ //#include // for Sleep void Sleep(int ms) { struct timeval tv; tv.tv_usec=(ms%1000)*1000; tv.tv_sec=ms/1000; select(0,0,0,0,&tv); } ///////////////////////////////////////////////////// // Serial Helpers /* HANDLE OpenSerial(int iPort) { char szPort[32]; sprintf(szPort, "COM%d", iPort); HANDLE h = CreateFile(szPort, GENERIC_READ | GENERIC_WRITE, 0, // exclusive access NULL, // no security attrs OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); return h; } */ /* static 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; // no XON/XOFF if (!SetCommState(hSerial, &dcb)) return false; return true; } */ /* bool SetCommDefaults(HANDLE hSerial) { if (!SetCommDefaultsPart1(hSerial, CBR_9600)) return false; // set no timeouts COMMTIMEOUTS to; memset(&to, 0, sizeof(to)); to.ReadIntervalTimeout = MAXDWORD; // return immediately if no data if (!SetCommTimeouts(hSerial, &to)) return false; // purge all 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 (true) { char 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; // empty } } */ /////////////////////////////////////////////////////////// // Serial helpers /* bool PeekSerialByte(HANDLE hSerial, char& bRet) { // no logging 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; // no data } */ /* void SendSerialBytes(HANDLE hSerial, const char* 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); } } */ /////////////////////////////////////////////////////////// /* 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) { // check the rest is zero 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; /* static bool EchoSerial(HANDLE hSerial) { char 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; // something echoed } */ /* static void EchoSerialTilEmpty(HANDLE hSerial, int nDelay) { for (int iTry = 0; iTry < 10; iTry++) { while (EchoSerial(hSerial)) ; Sleep(nDelay); if (!EchoSerial(hSerial)) break; } } */ char* LoadFile(const char* szFile, long& cbRet) { FILE* fin = fopen(szFile,"rb"); if (!fin) { fprintf(stderr,"upl: failed to open '%s'\n",szFile); return NULL; } struct stat sbuf; if (fstat(fileno(fin),&sbuf)!=0) { fprintf(stderr,"upl: failed to stat '%s'\n",szFile); return NULL; } cbRet = sbuf.st_size; if (sbuf.st_size==0) return NULL; char* result = new char[cbRet]; if (fread(result,cbRet,1,fin)!=1) { fprintf(stderr,"upl: failed to read '%s'\n",szFile); delete[] result; return NULL; } fclose(fin); return result; } char CalcChecksum(const char* pb, long cb) { char csum = 0; while (cb--) csum += *pb++; return csum; } bool UploadFile(int hSerial, const char* szFile, char chCmd) { long cbFile; const char* 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); // send command byte if (write(hSerial,&chCmd,1)!=1) { fprintf(stderr,"upl: failed to upload file\n"); return false; } // send length (little endian) char c = cbFile; write(hSerial,&c,1); c = cbFile>>8; write(hSerial,&c,1); c = cbFile>>16; write(hSerial,&c,1); c = cbFile>>24; write(hSerial,&c,1); tcdrain(hSerial); 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; } }*/ char buf[256]; /* buf[4+8]=0; if (read(hSerial,&buf,12)!=12) { printf("Zipit is not responding - not ready to upload\n"); return false; } printf("reply: '%s'\n",buf); */ // send file time_t start = time(0); if (write(hSerial,pbFile,cbFile)!=cbFile) { fprintf(stderr,"upl: failed to upload file\n"); return false; } tcdrain(hSerial); time_t end = time(0); char 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; char 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: csum=%x (%lds)\n",(int)csum,end-start); return true; } /* bool GrabFile(HANDLE hSerial, const char* szFile, long cbGrab, char 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) { // sloppy read 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; } */ int main(int argc, char* argv[]) { if (argc!=3) { printf("usage:\n\tupl port file\n"); return -1; } const char* szPort = argv[1]; const char* szInputSource = argv[2]; // read input file long cbImage; char* g_rgbImage = LoadFile(szInputSource,cbImage); if (g_rgbImage==NULL) return 1; if (cbImage!=2048) { fprintf(stderr,"upl: loader must be 2048 bytes\n"); return 1; } // connect to serial port int hSerial = open(szPort,O_RDWR); if (hSerial==-1) { fprintf(stderr,"upl: failed to open '%s'\n",szPort); return 1; } // set to 9600 baud struct termios tios; if (tcgetattr(hSerial,&tios)!=0) { fprintf(stderr,"upl: failed to get serial attributes\n"); return 1; } tios.c_iflag = IGNBRK|IGNPAR; tios.c_oflag = 0; tios.c_cflag = CS8|CLOCAL; tios.c_lflag = 0; cfsetospeed(&tios,B9600); cfsetispeed(&tios,B9600); if (tcsetattr(hSerial,TCSANOW,&tios)!=0) { fprintf(stderr,"upl: failed to set serial attributes\n"); return 1; } printf("Connected\n"); printf("Turn on the Zipit (press button, wait for green, release)\n"); printf(" Wait 10 seconds, then press ENTER to start transfer\n"); printf(" (DBG pin must be grounded)\n"); /* int nSkip = 0; char bIgnore; while (PeekSerialByte(hSerial, bIgnore)) nSkip++; if (nSkip > 0) printf("Skipping %d left over data bytes\n"); */ char buf[256]; fgets(buf,256,stdin); setvbuf(stdin,0,_IONBF,0); printf("Transfering bootstrap program\n"); if (write(hSerial,g_rgbImage,cbImage)!=cbImage) { fprintf(stderr,"upl: failed to upload boot loader\n"); return 1; } tcdrain(hSerial); printf("Transfer complete\n"); Sleep(100); printf("Switch to 57.6kbps\n"); cfsetospeed(&tios,B57600); cfsetispeed(&tios,B57600); if (tcsetattr(hSerial,TCSANOW,&tios)!=0) { fprintf(stderr,"upl: failed to set serial attributes\n"); return 1; } //g_pfLog = fopen("log.txt", "at"); // save session 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 (true) { fd_set rfds; FD_ZERO(&rfds); FD_SET(0,&rfds); //stdin FD_SET(hSerial,&rfds); select(hSerial+1,&rfds,NULL,NULL,NULL); if (FD_ISSET(hSerial,&rfds)) { char c; read(hSerial,&c,1); printf("%c",c); fflush(stdout); } if (FD_ISSET(0,&rfds)) { char c; read(0,&c,1); if (c=='u') UploadFile(hSerial,"ramdisk.gz",c); // -> ramdisk.gz else if (c=='k') UploadFile(hSerial,"zimage.dat",c); // -> kernel.gz else if (c=='a') UploadFile(hSerial,"loader.bin",c); // -> start of ROM image else if (c=='A') UploadFile(hSerial,"allrom.bin",c); // -> start of ROM image /* else if (b == 'R') { GrabFile(hSerial, "grabrom.bin", 2*1024*1024, b); printf("// grab done -- I hope...\n"); } */ else if (c=='q') { printf("// done echo mode\n"); break; } else if (c=='\n') { // nothing } else { write(hSerial,&c,1); tcdrain(hSerial); } //Sleep(50); // don't be a total CPU pig } } /* if (g_pfLog != NULL) fclose(g_pfLog); g_pfLog = NULL; */ return 0; }