diff options
Diffstat (limited to 'ROMTransfer/Source/ROM_Transfer.c')
-rw-r--r-- | ROMTransfer/Source/ROM_Transfer.c | 768 |
1 files changed, 768 insertions, 0 deletions
diff --git a/ROMTransfer/Source/ROM_Transfer.c b/ROMTransfer/Source/ROM_Transfer.c new file mode 100644 index 0000000..2126ce9 --- /dev/null +++ b/ROMTransfer/Source/ROM_Transfer.c @@ -0,0 +1,768 @@ +/* -*- mode: C++; tab-width: 4 -*- */ +/* ===================================================================== *\ + Copyright (c) 1998-2001 Palm, Inc. or its subsidiaries. + All rights reserved. + + This file is part of the Palm OS Emulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +\* ===================================================================== */ + +#define PILOT_PRECOMPILED_HEADERS_OFF + +#include <PalmOS.h> + +#include "ROM_Transfer.h" +#include "ROM_Transfer.rsrc.h" + +UInt32 HwrMemReadable(void *addr) + HAL_CALL(sysTrapHwrMemReadable); + +static void SendXModem (FormType* form, UInt8* romStart, Int32 romSize); +static void SendRaw (FormType* form, UInt8* romStart, Int32 romSize); +static void UpdatePercentComplete (FormType* form, Int32 offset, Int32 romSize); +static void GetROMStartSize (UInt8** romStart, Int32* romSize); +static void PrvUpdateStatus (FormType* form, const char*); +static void PrvStrPrintF (char* dest, const char* fmt, Int32 num); +static void PrvStrIToX (char* dest, UInt32 val); + +static UInt32 gROMVersion; + +const char* kSerialErrors[] = +{ + "Bad Param", + "Bad Port", + "No Memory", + "Bad ConnID", + "Timeout", + "Line Error", + "Already Open", + "Still Open", + "Not Open", + "Not Supported", + "No Devices" +}; + + +// --------------------------------------------------------------------------- +// ¥ PilotMain +// --------------------------------------------------------------------------- +// The main entry point for ROM Transfer. + +UInt32 PilotMain ( UInt16 iCommand, + void* iCommandParams, + UInt16 iLaunchFlags) +{ + if (iCommand != sysAppLaunchCmdNormalLaunch) + return 0; + + ErrTry + { + InitializeApplication (); + ExecuteApplication (); + } + + // Catch any unhandled exceptions. + + ErrCatch (iError) + { + } + ErrEndCatch + + // Clean up. + + DisposeApplication (); + + return 0; +} + + +#pragma mark - + + +// --------------------------------------------------------------------------- +// ¥ InitializeApplication +// --------------------------------------------------------------------------- +// Initializes the application globals and prepares to execute the event loop. + +void InitializeApplication (void) +{ + Char* aLabel; + ListPtr aList; + UInt16 aListItem; + ControlPtr aControl; + FormPtr aMainForm; + + FtrGet (sysFtrCreator, sysFtrNumROMVersion, &gROMVersion); + + // Initialize and draw the main form. + + aMainForm = FrmInitForm (MainForm); + Throw_IfNil (aMainForm, 0); + + FrmSetActiveForm (aMainForm); + FrmDrawForm (aMainForm); + + // Set up the speed popup. + + aListItem = kItem_115200; + aList = FrmGetObjectPtr (aMainForm, FrmGetObjectIndex (aMainForm, MainSpeedList)); + aLabel = LstGetSelectionText (aList, aListItem); + aControl = FrmGetObjectPtr (aMainForm, FrmGetObjectIndex (aMainForm, MainSpeedPopTrigger)); + CtlSetLabel (aControl, aLabel); + LstSetSelection (aList, aListItem); + +#if 0 +{ + #define sysFtrNewSerialVersion 2 + int fred; + +#define gSerialManagerVersion fred + + Err err; + char buffer[20]; + UInt32 systemVersion; + UInt32 ftrValue; + + // Determine what version Serial Manager we have: + // + // 0 = undetermined + // 1 = Original driver in Pilot 1000/5000 + // 2 = Updated driver in PalmPilot (new Send/Receive calls) + // 3 = New Serial Manager (Srm calls) + // 4 = Updated Serial Manager (includes SrmExtOpen call) + + err = FtrGet (sysFileCSystem, sysFtrNumROMVersion, &systemVersion); + + ErrFatalDisplayIf (err, "Unable to determine System version"); + + if (sysGetROMVerMajor(systemVersion) < 2) + { + gSerialManagerVersion = 1; + } + else + { + err = FtrGet (sysFileCSerialMgr, sysFtrNewSerialPresent, &ftrValue); + + if (err || ftrValue == 0) + { + gSerialManagerVersion = 2; + } + else + { + err = FtrGet (sysFileCSerialMgr, sysFtrNewSerialVersion, &ftrValue); + + if (err) + { + gSerialManagerVersion = 3; + } + else if (ftrValue <= 2) + { + gSerialManagerVersion = 3; + + // Palm OS 3.5.2 for Handspring implements + // sysFtrNewSerialVersion and returns a feature value of 2. + // Palm OS 4.0 also implements sysFtrNewSerialVersion and + // returns a value of 2. However, the two serial managers + // are different: the latter implements SrmExtOpen. In + // order to differentiate between the two, we have to check + // the OS version. + + if (ftrValue == 2 && + sysGetROMVerMajor (systemVersion) == 4 && + sysGetROMVerMinor (systemVersion) == 0) + { + gSerialManagerVersion = 4; + } + } + else + { + // ftrValue should be at least 3 for versions of the + // Serial Manager that implement SrmExtOpen. + + gSerialManagerVersion = ftrValue + 1; + } + } + } + + StrPrintF (buffer, "%d %d", (int) err, (int) gSerialManagerVersion); + + PrvUpdateStatus (aMainForm, buffer); +} +#endif + +#if 0 +{ + char buffer1[20]; + char buffer2[20]; + char buffer3[20]; + UInt8* romStart; + Int32 romSize; + + GetROMStartSize (&romStart, &romSize); + + PrvStrIToX (buffer1, (UInt32) romStart); + PrvStrIToX (buffer2, (UInt32) romSize); + + StrCopy (buffer3, buffer1); + StrCat (buffer3, " "); + StrCat (buffer3, buffer2); + + PrvUpdateStatus (aMainForm, buffer3); +} +#endif +} + + +// --------------------------------------------------------------------------- +// ¥ DisposeApplication +// --------------------------------------------------------------------------- +// Disposes the application globals and prepares to exit. + +void DisposeApplication (void) +{ + FrmCloseAllForms (); +} + + +// --------------------------------------------------------------------------- +// ¥ ExecuteApplication +// --------------------------------------------------------------------------- +// Executes an event loop until the application quits. + +void ExecuteApplication (void) +{ + EventType aEvent; + + aEvent.eType = nilEvent; + + // Repeat until the application quits. + + while (aEvent.eType != appStopEvent) + { + // Get the next available event. + + EvtGetEvent (&aEvent, evtWaitForever); + + // Give the system a chance to handle the event. + + if (!SysHandleEvent (&aEvent)) + + // Try to handle the event ourselves. + + if (!ProcessEvent (&aEvent)) + + // Let the form provide default handling of the event. + + FrmHandleEvent (FrmGetActiveForm (), &aEvent); + } +} + + +// --------------------------------------------------------------------------- +// ¥ ProcessEvent +// --------------------------------------------------------------------------- +// Attempts to process the specified event. + +Boolean ProcessEvent (EventPtr iEvent) +{ + Boolean aWasHandled = false; + + if (iEvent->eType == ctlSelectEvent) + { + switch (iEvent->data.ctlEnter.controlID) + { + case MainBeginTransferButton: + { + TransferROM (); + + aWasHandled = true; + break; + } + } + } + + return aWasHandled; +} + + +// --------------------------------------------------------------------------- +// ¥ TransferROM +// --------------------------------------------------------------------------- +// Downloads the ROM via the serial connection. + +static UInt32 MySysTicksPerSecond () +{ + if (sysGetROMVerMajor(gROMVersion) < 2) + return sysTicksPerSecond; + + return SysTicksPerSecond (); +} + +void TransferROM (void) +{ + Int16 err; + UInt8* romStart; + Int32 romSize; + + Int16 speedChoice; + UInt32 speed; + FormPtr form; + + form = FrmGetActiveForm (); + + ErrTry + { + ErrFatalDisplayIf (!form, "Unable to get form"); + + speedChoice = LstGetSelection (FrmGetObjectPtr (form, FrmGetObjectIndex (form, MainSpeedList))); + switch (speedChoice) + { + case kItem_1200: speed = kBaud_1200; break; + case kItem_2400: speed = kBaud_2400; break; + case kItem_4800: speed = kBaud_4800; break; + case kItem_9600: speed = kBaud_9600; break; + case kItem_14400: speed = kBaud_14400; break; + case kItem_19200: speed = kBaud_19200; break; + case kItem_28800: speed = kBaud_28800; break; + case kItem_38400: speed = kBaud_38400; break; + case kItem_57600: speed = kBaud_57600; break; + case kItem_115200: speed = kBaud_115200; break; + default: speed = kBaud_14400; break; + } + + err = Comm_Initialize (speed); + Throw_IfError (err, err); + + // Get the size and location of the ROM. + + GetROMStartSize (&romStart, &romSize); + + // Send the data using a protocol appropriate for the connection. + +#if 0 + if (using_USB) + { + SendRaw (form, romStart, romSize); + } + else +#endif + { + SendXModem (form, romStart, romSize); + } + + // Change the status text. + + PrvUpdateStatus (form, "Finished"); + } + + // Catch any exceptions. + + ErrCatch (iError) + { + // Change the status text. + + if (form != NULL) + { + char buffer[20]; + + if (iError >= serErrBadParam && + iError <= serErrNoDevicesAvail) + { + StrCopy (buffer, kSerialErrors[iError - serErrBadParam]); + } + else + { + PrvStrPrintF (buffer, "Error #%d", iError); + } + + PrvUpdateStatus (form, buffer); + } + } + ErrEndCatch + + Comm_Dispose (); +} + + +// --------------------------------------------------------------------------- +// ¥ PrvSendChar +// --------------------------------------------------------------------------- + +static void PrvSendChar (UInt8 ch) +{ + Err err = Comm_Send (&ch, 1); + Throw_IfError (err, err); + + EvtResetAutoOffTimer (); +} + + +// --------------------------------------------------------------------------- +// ¥ PrvReceiveChar +// --------------------------------------------------------------------------- + +static void PrvReceiveChar (UInt8* ch) +{ + Err err = Comm_Receive (ch, 1, 30 * MySysTicksPerSecond ()); + Throw_IfError (err, err); + + EvtResetAutoOffTimer (); +} + + +// --------------------------------------------------------------------------- +// ¥ SendXModem +// --------------------------------------------------------------------------- + +void SendXModem (FormType* form, UInt8* romStart, Int32 romSize) +{ + const int kXModemBodySize = 1024; // 1k-XModem variant + const int kXModemSohOffset = 0; + const int kXModemBlkOffset = kXModemSohOffset + 1; + const int kXModemNBlkOffset = kXModemBlkOffset + 1; + const int kXModemBodyOffset = kXModemNBlkOffset + 1; + const int kXModemChk1Offset = kXModemBodyOffset + kXModemBodySize; + const int kXModemChk2Offset = kXModemChk1Offset + 1; + const int kXModemBlockSize = kXModemChk2Offset + 1; + + const char kXModemSoh = 1; // start of block header + const char kXModemEof = 4; // end of file signal + const char kXModemAck = 6; // acknowledge + const char kXModemNak = 21; // negative acknowledge (resend packet) + const char kXModemCan = 24; // cancel + const char kXModemNakCrc = 'C'; // used instead of NAK for initial block + + Err err; + UInt8 c; + UInt8 blockNum; + UInt32 i; + Boolean bXModemCrc; + char block[kXModemBlockSize]; + Boolean bXModemHeaderBlock; + Int32 offset; + UInt16 crc; + char* body = &block[kXModemBodyOffset]; + + // Change the status text. + + PrvUpdateStatus (form, "Waiting..."); + + // First, wait for the receiver to send us a nak. If it's + // a real nak, then we'll send in checksum mode. If it's + // a 'C', we'll send in CRC mode. + + Comm_ClearError (); + + while (true) + { + PrvReceiveChar (&c); + + if (c == kXModemNakCrc) + { + bXModemCrc = true; + break; + } + else if (c == kXModemNak) + { + bXModemCrc = false; + break; + } + else if (c == kXModemCan) + { + ErrThrow (c); + } + } + + // Send the ROM one block at a time until it's done. + + offset = 0; + blockNum = 0; + bXModemHeaderBlock = true; + + while (offset < romSize) + { + // Change the status text. + + UpdatePercentComplete (form, offset, romSize); + + // Build up the block. + + block[kXModemSohOffset] = kXModemSoh; + block[kXModemBlkOffset] = blockNum; + block[kXModemNBlkOffset] = ~blockNum; + + if (bXModemHeaderBlock) + { + // The very first block sends over a "file name" + // and "file size". + + MemSet (body, kXModemBodySize, 0); + StrCopy (body, "PalmOS.ROM"); // What's in a name? + StrIToA (&body[StrLen (body) + 1], romSize); + } + else + { + // All subseqent blocks contain 1K of the ROM. + + MemMove (body, romStart + offset, kXModemBodySize); + } + + // Figure out and add the checksum. + + if (bXModemCrc) + { + // Calculate the checksum of the body data, as + // well as the two empty spots that will get filled + // in with the checksum bytes in a moment. + + block[kXModemChk1Offset] = 0; + block[kXModemChk2Offset] = 0; + + crc = Crc16CalcBlock (body, kXModemBodySize + 2, 0); + + block[kXModemChk1Offset] = crc >> 8; + block[kXModemChk2Offset] = crc; + + err = Comm_Send (block, kXModemBlockSize); + } + else + { + c = 0; + + for (i = 0; i < kXModemBodySize; i++) + { + c += (romStart + offset)[i]; + } + + body[kXModemChk1Offset] = c; + + err = Comm_Send (block, kXModemBlockSize - 1); + } + + Throw_IfError (err, err); + + EvtResetAutoOffTimer (); + + // Wait for the other end to ack or nak us. Leave + // plenty of timeout so the receiver has time to + // decide whether it got a partial block. + + do + { + PrvReceiveChar (&c); + } while (c != kXModemAck && c != kXModemNak && c != kXModemNakCrc); + + if (c == kXModemAck) + { + if (!bXModemHeaderBlock) + { + // Only do this if we're into sending the file + // (don't increment on the file header block). + + offset += kXModemBodySize; + } + + blockNum++; + bXModemHeaderBlock = false; + } + } + + // Send an EOF and wait for an acknowledgement. + + do + { + PrvSendChar (kXModemEof); + PrvReceiveChar (&c); + } while (c != kXModemAck); +} + + +// --------------------------------------------------------------------------- +// ¥ SendRaw +// --------------------------------------------------------------------------- + +void SendRaw (FormType* form, UInt8* romStart, Int32 romSize) +{ +#define kRawBlockSize 1024 + + Err err; + Int32 offset = 0; + + // Start by sending the size. + + err = Comm_Send (&romSize, sizeof (romSize)); + Throw_IfError (err, err); + + // Now send the ROM. + + while (offset < romSize) + { + // Change the status text. + + UpdatePercentComplete (form, offset, romSize); + + err = Comm_Send (romStart + offset, kRawBlockSize); + Throw_IfError (err, err); + + offset += kRawBlockSize; + } +} + + +// --------------------------------------------------------------------------- +// ¥ UpdatePercentComplete +// --------------------------------------------------------------------------- + +void UpdatePercentComplete (FormType* form, Int32 offset, Int32 romSize) +{ + Int32 percentComplete = (offset * 100) / romSize; + char buffer[20]; + + PrvStrPrintF (buffer, "Sending...%d%%", percentComplete); + + PrvUpdateStatus (form, buffer); +} + + +// --------------------------------------------------------------------------- +// ¥ GetROMStartSize +// --------------------------------------------------------------------------- + +void * MemHeapPtr(UInt16 heapID) + SYS_TRAP(sysTrapMemHeapPtr); + +#define memHeapFlagReadOnly 0x0001 // heap is read-only (ROM based) + +void GetROMStartSize (UInt8** romStartP, Int32* romSizeP) +{ +#if 0 + void* romStart = (void*) HwrMemReadable ((void*) 0xFFFFFFFF); + UInt32 romSize = HwrMemReadable (romStart); + + *romStartP = romStart; + *romSizeP = romSize; +#else + UInt16 numHeaps = MemNumHeaps (0); + UInt16 heapID; + UInt16 heapFlags; + UInt8* heapBegin; + UInt8* heapEnd; + UInt32 heapSize; + + UInt8* romLow = (UInt8*) 0xFFFFFFFF; + UInt8* romHigh = (UInt8*) NULL; + + for (heapID = 0; heapID < numHeaps; ++heapID) + { + heapFlags = MemHeapFlags (heapID); + + if (heapFlags & memHeapFlagReadOnly) + { + heapBegin = (UInt8*) MemHeapPtr (heapID); + heapSize = MemHeapSize (heapID); + heapEnd = heapBegin + heapSize; + + if (romLow > heapBegin) + { + romLow = heapBegin; + } + + if (romHigh < heapEnd) + { + romHigh = heapEnd; + } + } + } + + // Round up/down to 512K boundaries. (512K is the size + // of the Pilot 1000/5000 ROM). + + #define MASK (512L * 1024 - 1) + + romLow = (UInt8*) ((UInt32) romLow & ~MASK); + romHigh = (UInt8*) (((UInt32) romHigh + MASK) & ~MASK); + + *romStartP = romLow; + *romSizeP = romHigh - romLow; +#endif +} + + +// --------------------------------------------------------------------------- +// ¥ PrvUpdateStatus +// --------------------------------------------------------------------------- + +void PrvUpdateStatus (FormType* form, const char* txt) +{ + char buffer[100]; + StrCopy (buffer, txt); + StrCat (buffer, " "); + + FrmCopyLabel (form, MainStatusTextLabel, buffer); +} + + +// --------------------------------------------------------------------------- +// ¥ PrvStrPrintF +// --------------------------------------------------------------------------- +// Roll our own StrPrintF, since it doesn't exist in 1.0. + +void PrvStrPrintF (char* dest, const char* fmt, Int32 num) +{ + char ch; + const char* s = fmt; + char* d = dest; + char numBuff[12]; // -2 xxx xxx xxx \0 = 12 bytes + + while ((ch = *s++) != 0) + { + if (ch != '%') + { + *d++ = ch; + } + else + { + ch = *s++; + + if (ch == 'd') + { + StrIToA (numBuff, num); + StrCopy (d, numBuff); + d += StrLen (numBuff); + } + else if (ch == 'c') + { + *d++ = (char) num; + } + else if (ch == '%') + { + *d++ = '%'; + } + } + } + + *d = 0; +} + + +// --------------------------------------------------------------------------- +// ¥ PrvStrIToX +// --------------------------------------------------------------------------- + +void PrvStrIToX (char* dest, UInt32 val) +{ + const char* kDigits = "0123456789ABCDEF"; + int ii; + + for (ii = 0; ii < 8; ++ii) + { + unsigned nybble = (val >> (28 - ii * 4)) & 0x0F; + dest[ii] = kDigits[nybble]; + } + + dest[8] = 0; +} |