微電腦 - Zipit Z1 - Upload程式(C/C++)
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#define verify assert
#include <windows.h>
#include <conio.h>
HANDLE OpenSerial(int iPort)
{
char szPort[32] = {0};
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];
DWORD cbRead;
long cbAck;
reply[4 + 8] = '\0';
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;
}