diff --git a/binaries/Tag/SOL_M2_154_SSD_26.bin b/binaries/Tag/SOL_M2_154_SSD_26.bin new file mode 100644 index 00000000..014de2b9 Binary files /dev/null and b/binaries/Tag/SOL_M2_154_SSD_26.bin differ diff --git a/binaries/Tag/SOL_M2_29_SSD_26.bin b/binaries/Tag/SOL_M2_29_SSD_26.bin new file mode 100644 index 00000000..b1c55596 Binary files /dev/null and b/binaries/Tag/SOL_M2_29_SSD_26.bin differ diff --git a/binaries/Tag/SOL_M2_42_SSD_26.bin b/binaries/Tag/SOL_M2_42_SSD_26.bin new file mode 100644 index 00000000..a2f78dcb Binary files /dev/null and b/binaries/Tag/SOL_M2_42_SSD_26.bin differ diff --git a/binaries/Tag/tagotaversions.json b/binaries/Tag/tagotaversions.json index 1e745bea..427ca168 100644 --- a/binaries/Tag/tagotaversions.json +++ b/binaries/Tag/tagotaversions.json @@ -2,17 +2,17 @@ { "00" : { "type": "SOL_M2_154_SSD", - "version": "25", + "version": "26", "md5": "57e02f80c9f2581be0a140979b1124e1" }, "01" : { "type": "SOL_M2_29_SSD", - "version": "25", + "version": "26", "md5": "bed1a20ca6af04e29e5aabce480c1e9d" }, "02" : { "type": "SOL_M2_42_SSD", - "version": "25", + "version": "26", "md5": "80e36c7d4d08beaca8ad2f00f42923d0" }, "05" : { diff --git a/zbs243_Tag_FW/Makefile b/zbs243_Tag_FW/Makefile index 39fa1d6c..a7871ed9 100644 --- a/zbs243_Tag_FW/Makefile +++ b/zbs243_Tag_FW/Makefile @@ -7,6 +7,8 @@ SOURCES += comms.c SOURCES += syncedproto.c userinterface.c SOURCES += powermgt.c barcode.c i2cdevices.c settings.c + + all: #make sure it is the first target include board/$(BUILD)/make.mk @@ -20,6 +22,8 @@ SOURCES += cpu/$(CPU)/cpu.c SOURCES += board/$(BUILD)/board.c SOURCES += board/$(BUILD)/screen.c +SOURCES += md5.c + EEPROMDRV ?= eeprom.c diff --git a/zbs243_Tag_FW/drawing.c b/zbs243_Tag_FW/drawing.c index 5443ddea..7adfd0d2 100755 --- a/zbs243_Tag_FW/drawing.c +++ b/zbs243_Tag_FW/drawing.c @@ -16,17 +16,22 @@ uint8_t __xdata* drawBuffer; -void drawImageAtAddress(uint32_t addr, uint8_t lut) { +void drawImageAtAddress(uint32_t addr, uint8_t lut) __reentrant { drawBuffer = malloc(512); if (!drawBuffer) { +#ifdef DEBUGDRAWING pr("malloc during draw failed..\n"); +#endif return; } - struct EepromImageHeader* __xdata eih = (struct EepromImageHeader*)drawBuffer; + static struct EepromImageHeader* __xdata eih; + eih = (struct EepromImageHeader*)drawBuffer; eepromRead(addr, drawBuffer, sizeof(struct EepromImageHeader)); switch (eih->dataType) { case DATATYPE_IMG_RAW_1BPP: - pr("Doing raw 1bpp\n"); +#ifdef DEBUGDRAWING + pr("Doing raw 1bpp with lut %d\n", lut); +#endif epdSetup(); if (lut) selectLUT(lut); beginFullscreenImage(); @@ -45,7 +50,9 @@ void drawImageAtAddress(uint32_t addr, uint8_t lut) { endWriteFramebuffer(); break; case DATATYPE_IMG_RAW_2BPP: - pr("Doing raw 2bpp\n"); +#ifdef DEBUGDRAWING + pr("Doing raw 2bpp with lut %d\n", lut); +#endif epdSetup(); if (lut) selectLUT(lut); beginFullscreenImage(); @@ -76,7 +83,9 @@ void drawImageAtAddress(uint32_t addr, uint8_t lut) { endWriteFramebuffer(); break; default: // prevent drawing from an unknown file image type +#ifdef DEBUGDRAWING pr("Image with type 0x%02X was requested, but we don't know what to do with that currently...\n", eih->dataType); +#endif free(drawBuffer); return; } diff --git a/zbs243_Tag_FW/drawing.h b/zbs243_Tag_FW/drawing.h index 8ed12e96..131f4e0e 100644 --- a/zbs243_Tag_FW/drawing.h +++ b/zbs243_Tag_FW/drawing.h @@ -3,11 +3,8 @@ #include -#define DRAWING_MIN_BITMAP_SIZE (128) //minimum size we'll consider - -void set_offline(__bit state); +//void set_offline(__bit state); #pragma callee_saves drawImageAtAddress -void drawImageAtAddress(uint32_t addr, uint8_t lut); -void drawImageFromBuffer(uint8_t* buffer, const uint8_t lut); +extern void drawImageAtAddress(uint32_t addr, uint8_t lut) __reentrant; #endif diff --git a/zbs243_Tag_FW/i2cdevices.c b/zbs243_Tag_FW/i2cdevices.c index de978989..7eb9296c 100755 --- a/zbs243_Tag_FW/i2cdevices.c +++ b/zbs243_Tag_FW/i2cdevices.c @@ -24,7 +24,9 @@ extern void dump(uint8_t* __xdata a, uint16_t __xdata l); // remove me when done -__xdata uint8_t i2cbuffer[18]; +#ifndef LEAN_VERSION + +uint8_t __xdata i2cbuffer[18]; extern uint8_t __xdata blockbuffer[]; bool supportsNFCWake() { @@ -106,16 +108,22 @@ void i2cBusScan() { struct I2cTransaction __xdata iictest; iictest.numBytes = 0; iictest.bytes = NULL; +#ifdef DEBUGNFC pr("Starting I2C scan...\n"); +#endif for (uint8_t address = 0x00; address <= 0x7F; address++) { iictest.deviceAddr = address << 1; uint8_t res = i2cTransact(&iictest, 1); if (res == 0) { +#ifdef DEBUGNFC pr(" - Found i2c device at %02X\n", address); +#endif } timerDelay(13330); } +#ifdef DEBUGNFC pr("I2C scan complete\n"); +#endif } bool i2cCheckDevice(uint8_t address) { @@ -124,8 +132,12 @@ bool i2cCheckDevice(uint8_t address) { iictest.deviceAddr = address << 1; uint8_t res = i2cTransact(&iictest, 1); if (res == 0) { +#ifdef DEBUGNFC pr("I2C: Device found at 0x%02X\n", address); +#endif return true; } return false; -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/zbs243_Tag_FW/main.c b/zbs243_Tag_FW/main.c index 9ea75dd9..78217398 100755 --- a/zbs243_Tag_FW/main.c +++ b/zbs243_Tag_FW/main.c @@ -30,7 +30,7 @@ // #define DEBUG_MODE -// static const uint64_t __code __at(0x008b) mVersionRom = 0x1000011300000000ull; +static const uint64_t __code __at(0x008b) firmwaremagic = (0xdeadd0d0beefcafeull) + HW_TYPE; #define TAG_MODE_CHANSEARCH 0 #define TAG_MODE_ASSOCIATED 1 @@ -43,74 +43,11 @@ uint8_t __xdata slideShowRefreshCount = 1; extern uint8_t *__idata blockp; extern uint8_t __xdata blockbuffer[]; +static bool __xdata secondLongCheckIn = false; // send another full request if the previous was a special reason + uint8_t *rebootP; -#ifdef ENABLE_EEPROM_LOADER -extern bool __idata serialBypassActive; -bool __xdata serialActive = false; -void processSerial(uint8_t lastchar) { - static uint8_t __xdata cmdbuffer[4]; - // shift characters in - for (uint8_t c = 0; c < 3; c++) { - cmdbuffer[c] = cmdbuffer[c + 1]; - } - cmdbuffer[3] = lastchar; - - if (strncmp(cmdbuffer + 1, ">D>", 3) == 0) { - wdt120s(); - blockp = blockbuffer; - serialBypassActive = true; - pr("ACK>\n"); - while (serialBypassActive) - ; - if (validateBlockData()) { - pr("ACK>\n"); - } else { - pr("NOK>\n"); - } - } - - if (strncmp(cmdbuffer + 1, ""); - for (uint16_t c = 0; c < 4100; c++) { - uartTx(blockbuffer[c]); - timerDelay(TIMER_TICKS_PER_MS / 400); // 30 okay // 50 kinda okay // 80 ook okay? - } - pr("blaat"); - } - - if (strncmp(cmdbuffer, "STE", 3) == 0) { // store block to offset - if (!eepromErase(4096UL * cmdbuffer[3], 4096 / EEPROM_ERZ_SECTOR_SZ)) { - pr("NOK>\n"); - return; - } - if (eepromWrite(4096UL * cmdbuffer[3], blockbuffer + 4, 4096)) - pr("ACK>\n"); - else - pr("NOK>\n"); - } - if (strncmp(cmdbuffer, "LDE", 3) == 0) { // load block from offset - eepromRead(4096UL * cmdbuffer[3], blockbuffer + 4, 4096); - uint16_t *header = blockbuffer; - *header = 4096; - uint16_t *sum = blockbuffer + 2; - *sum = 0; - for (uint16_t c = 4; c < 4100; c++) { - *sum += blockbuffer[c]; - } - pr("ACK>\n"); - } -} -void serialTerminal() { - serialActive = true; - while (serialActive) { - while (uartBytesAvail()) { - processSerial(uartRx()); - } - } -} -#endif +#ifdef DEBUGGUI void displayLoop() { powerUp(INIT_BASE | INIT_UART); @@ -126,6 +63,12 @@ void displayLoop() { wdt30s(); + pr("Failed update screen\n"); + powerUp(INIT_EPD); + showFailedUpdate(); + timerDelay(TIMER_TICKS_PER_SECOND * 4); + wdt30s(); + pr("AP Found\n"); powerUp(INIT_EPD); showAPFound(); @@ -154,13 +97,15 @@ void displayLoop() { wdt30s(); - pr("NO EEPROM\n"); + pr("NO MAC\n"); powerUp(INIT_EPD); showNoMAC(); timerDelay(TIMER_TICKS_PER_SECOND * 4); wdtDeviceReset(); } +#endif + #ifdef WRITE_MAC_FROM_FLASH void writeInfoPageWithMac() { uint8_t *settemp = blockbuffer + 2048; @@ -215,7 +160,9 @@ uint8_t channelSelect(uint8_t rounds) { // returns 0 if no accesspoints were fo for (uint8_t c = 0; c < sizeof(channelList); c++) { if (detectAP(channelList[c])) { if (mLastLqi > result[c]) result[c] = mLastLqi; +#ifdef DEBUGMAIN if (rounds > 2) pr("Channel: %d - LQI: %d RSSI %d\n", channelList[c], mLastLqi, mLastRSSI); +#endif } } } @@ -238,8 +185,10 @@ void validateMacAddress() { for (uint8_t __xdata c = 0; c < 8; c++) { if (mSelfMac[c] != 0xFF) goto macIsValid; } - // invalid mac address. Display warning screen and sleep forever +// invalid mac address. Display warning screen and sleep forever +#ifdef DEBUGMAIN pr("Mac can't be all FF's.\n"); +#endif powerUp(INIT_EPD); showNoMAC(); powerDown(INIT_EPD | INIT_UART | INIT_EEPROM); @@ -250,11 +199,15 @@ macIsValid: } uint8_t getFirstWakeUpReason() { if (RESET & 0x01) { +#ifdef DEBUGMAIN pr("WDT reset!\n"); +#endif return WAKEUP_REASON_WDT_RESET; } return WAKEUP_REASON_FIRSTBOOT; } + +#ifndef LEAN_VERSION void checkI2C() { powerUp(INIT_I2C); // i2cBusScan(); @@ -263,15 +216,20 @@ void checkI2C() { // found something! capabilities |= CAPABILITY_HAS_NFC; if (supportsNFCWake()) { +#ifdef DEBUGNFC pr("NFC: NFC Wake Supported\n"); +#endif capabilities |= CAPABILITY_NFC_WAKE; } } else { +#ifdef DEBUGNFC pr("I2C: No devices found"); +#endif // didn't find a NFC chip on the expected ID powerDown(INIT_I2C); } } +#endif void detectButtonOrJig() { switch (checkButtonOrJig()) { @@ -280,18 +238,11 @@ void detectButtonOrJig() { break; case DETECT_P1_0_JIG: wdt120s(); -#ifdef ENABLE_EEPROM_LOADER - // run the eeprom loader interface - powerUp(INIT_EPD | INIT_EEPROM); - serialActive = true; - serialTerminal(); -#else // show splashscreen powerUp(INIT_EPD); afterFlashScreenSaver(); while (1) ; -#endif break; case DETECT_P1_0_NOTHING: break; @@ -302,10 +253,9 @@ void detectButtonOrJig() { void TagAssociated() { // associated - bool fastNextCheckin = false; struct AvailDataInfo *__xdata avail; // Is there any reason why we should do a long (full) get data request (including reason, status)? - if ((longDataReqCounter > LONG_DATAREQ_INTERVAL) || wakeUpReason != WAKEUP_REASON_TIMED) { + if ((longDataReqCounter > LONG_DATAREQ_INTERVAL) || wakeUpReason != WAKEUP_REASON_TIMED || secondLongCheckIn) { // check if we should do a voltage measurement (those are pretty expensive) if (voltageCheckCounter == VOLTAGE_CHECK_INTERVAL) { doVoltageReading(); @@ -353,16 +303,26 @@ void TagAssociated() { externalWakeHandler(CUSTOM_IMAGE_RF_WAKE); fastNextCheckin = true; break; +#ifndef LEAN_VERSION case WAKEUP_REASON_NFC: externalWakeHandler(CUSTOM_IMAGE_NFC_WAKE); fastNextCheckin = true; break; +#endif } if (avail != NULL) { // we got some data! longDataReqCounter = 0; + + if (secondLongCheckIn == true) { + secondLongCheckIn = false; + } + // since we've had succesful contact, and communicated the wakeup reason succesfully, we can now reset to the 'normal' status + if (wakeUpReason != WAKEUP_REASON_TIMED) { + secondLongCheckIn = true; + } wakeUpReason = WAKEUP_REASON_TIMED; } if (tagSettings.enableTagRoaming) { @@ -431,6 +391,7 @@ void TagAssociated() { doSleep(getNextSleep() * 1000UL); } } + powerUp(INIT_UART); } void TagChanSearch() { @@ -541,12 +502,16 @@ void TagSlideShow() { doSleep(1000UL * SLIDESHOW_INTERVAL_GLACIAL); break; } +#ifdef DEBUGMAIN pr("wake...\n"); +#endif } } void TagShowWaitRFWake() { +#ifdef DEBUGMAIN pr("waiting for RF wake to start slideshow, now showing image\n"); +#endif currentChannel = 11; // suppress the no-rf image thing displayCustomImage(CUSTOM_IMAGE_SLIDESHOW); // powerDown(INIT_EEPROM | INIT_EPD); @@ -657,40 +622,36 @@ void executeCommand(uint8_t cmd) { } void main() { - // displayLoop(); // remove me setupPortsInitial(); powerUp(INIT_BASE | INIT_UART); pr("BOOTED> %d.%d.%d%s\n", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix); +#ifdef DEBUGGUI + displayLoop(); // remove me +#endif + // Find the reason why we're booting; is this a WDT? wakeUpReason = getFirstWakeUpReason(); // dump(blockbuffer, 1024); // get our own mac address. this is stored in Infopage at offset 0x10-onwards boardGetOwnMac(mSelfMac); + +#ifdef DEBUGMAIN pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]); pr("%02X%02X", mSelfMac[2], mSelfMac[3]); pr("%02X%02X", mSelfMac[4], mSelfMac[5]); pr("%02X%02X\n", mSelfMac[6], mSelfMac[7]); - - for (uint16_t c = 0; c < 4096; c++) { - blockbuffer[c] = (c % 256) & 0xFF; - } - +#endif // do a little sleep, this prevents a partial boot during battery insertion - doSleep(2000UL); + doSleep(400UL); powerUp(INIT_EEPROM | INIT_UART); - uint8_t __idata dati; - pr("blockbuffer @%d, idata@%d\n",&blockbuffer[0], &dati); - dump(blockbuffer, 4096); - // load settings from infopage loadSettings(); // invalidate the settings, and write them back in a later state invalidateSettingsEEPROM(); - #ifdef WRITE_MAC_FROM_FLASH if (mSelfMac[7] == 0xFF && mSelfMac[6] == 0xFF) { wdt10s(); @@ -738,8 +699,10 @@ void main() { #endif if (tagSettings.enableFastBoot) { - // Fastboot +// Fastboot +#ifdef DEBUGMAIN pr("Doing fast boot\n"); +#endif capabilities = tagSettings.fastBootCapabilities; if (tagSettings.fixedChannel) { currentChannel = tagSettings.fixedChannel; @@ -748,15 +711,18 @@ void main() { } } else { // Normal boot/startup +#ifdef DEBUGMAIN pr("Normal boot\n"); +#endif // validate the mac address; this will display a warning on the screen if the mac address is invalid validateMacAddress(); +#ifndef LEAN_VERSION #if (NFC_TYPE == 1) // initialize I2C checkI2C(); #endif - +#endif // Get a voltage reading on the tag, loading down the battery with the radio doVoltageReading(); diff --git a/zbs243_Tag_FW/md5.c b/zbs243_Tag_FW/md5.c new file mode 100644 index 00000000..5ffd8930 --- /dev/null +++ b/zbs243_Tag_FW/md5.c @@ -0,0 +1,208 @@ +/* + * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm + * and modified slightly to be functionally identical but condensed into control structures. + */ + +#include "md5.h" + +/* + * Constants defined by the MD5 algorithm + */ +#define A 0x67452301 +#define B 0xefcdab89 +#define C 0x98badcfe +#define D 0x10325476 + +const static uint32_t __code S[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; + +const static uint32_t __code K[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; + +/* + * Padding used to make the size (in bits) of the input congruent to 448 mod 512 + */ +const static uint8_t __code PADDING[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/* + * Bit-manipulation functions defined by the MD5 algorithm + */ +#define F(X, Y, Z) ((X & Y) | (~X & Z)) +#define G(X, Y, Z) ((X & Z) | (Y & ~Z)) +#define H(X, Y, Z) (X ^ Y ^ Z) +#define I(X, Y, Z) (Y ^ (X | ~Z)) + +/* + * Rotates a 32-bit word left by n bits + */ +uint32_t rotateLeft(uint32_t x, uint32_t n) { + return (x << n) | (x >> (32 - n)); +} + +/* + * Initialize a context + */ +uint64_t __xdata ctxsize = 0; // Size of input in bytes +uint32_t __xdata ctxbuffer[4] = {0}; // Current accumulation of hash +uint8_t __xdata ctxinput[64] = {0}; // Input to be used in the next step +uint8_t __xdata ctxdigest[16] = {0}; // Result of algorithm + +void md5Init() { + ctxsize = (uint64_t)0; + ctxbuffer[0] = (uint32_t)A; + ctxbuffer[1] = (uint32_t)B; + ctxbuffer[2] = (uint32_t)C; + ctxbuffer[3] = (uint32_t)D; +} + +/* + * Add some amount of input to the context + * + * If the input fills out a block of 512 bits, apply the algorithm (md5Step) + * and save the result in the buffer. Also updates the overall size. + */ + +uint32_t swapEndian(uint8_t j) __reentrant{ + static uint32_t __xdata temp; + temp = (uint32_t)(ctxinput[(j * 4) + 3]) << 24 | + (uint32_t)(ctxinput[(j * 4) + 2]) << 16 | + (uint32_t)(ctxinput[(j * 4) + 1]) << 8 | + (uint32_t)(ctxinput[(j * 4)]); + return temp; +} + + +uint32_t __xdata input[16]; + +void md5Update(uint8_t *input_buffer, size_t input_len) __reentrant{ + static unsigned int __xdata offset; + offset = ctxsize % 64; + ctxsize += (uint64_t)input_len; + + // Copy each byte in input_buffer into the next space in our context input + for (unsigned int i = 0; i < input_len; ++i) { + ctxinput[offset++] = (uint8_t) * (input_buffer + i); + + // If we've filled our context input, copy it into our local array input + // then reset the offset to 0 and fill in a new buffer. + // Every time we fill out a chunk, we run it through the algorithm + // to enable some back and forth between cpu and i/o + if (offset % 64 == 0) { + for (unsigned int j = 0; j < 16; ++j) { + // Convert to little-endian + // The local variable `input` our 512-bit chunk separated into 32-bit words + // we can use in calculations + input[j] = swapEndian(j); + } + md5Step(input); + offset = 0; + } + } +} + +/* + * Pad the current input to get to 448 bytes, append the size in bits to the very end, + * and save the result of the final iteration into digest. + */ +void md5Finalize() __reentrant{ +// uint32_t __xdata input[16]; + static unsigned int __xdata offset; + offset = ctxsize % 64; + static unsigned int __xdata padding_length; + padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset; + + // Fill in the padding and undo the changes to size that resulted from the update + md5Update(PADDING, padding_length); + ctxsize -= (uint64_t)padding_length; + + // Do a final update (internal to this function) + // Last two 32-bit words are the two halves of the size (converted from bytes to bits) + for (unsigned int j = 0; j < 14; ++j) { + input[j] = swapEndian(j); + } + input[14] = (uint32_t)(ctxsize * 8); + input[15] = (uint32_t)((ctxsize * 8) >> 32); + + md5Step(input); + + // Move the result into digest (convert from little-endian) + for (unsigned int i = 0; i < 4; ++i) { + ctxdigest[(i * 4) + 0] = (uint8_t)((ctxbuffer[i] & 0x000000FF)); + ctxdigest[(i * 4) + 1] = (uint8_t)((ctxbuffer[i] & 0x0000FF00) >> 8); + ctxdigest[(i * 4) + 2] = (uint8_t)((ctxbuffer[i] & 0x00FF0000) >> 16); + ctxdigest[(i * 4) + 3] = (uint8_t)((ctxbuffer[i]) >> 24); + } +} + +/* + * Step on 512 bits of input with the main MD5 algorithm. + */ +void md5Step(uint32_t *input) __reentrant { + static uint32_t __xdata AA; + static uint32_t __xdata BB; + static uint32_t __xdata CC; + static uint32_t __xdata DD; + static uint32_t __xdata E; + static unsigned int __xdata j; + static unsigned int __xdata i; + + AA = ctxbuffer[0]; + BB = ctxbuffer[1]; + CC = ctxbuffer[2]; + DD = ctxbuffer[3]; + + for (i = 0; i < 64; ++i) { + switch (i / 16) { + case 0: + E = F(BB, CC, DD); + j = i; + break; + case 1: + E = G(BB, CC, DD); + j = ((i * 5) + 1) % 16; + break; + case 2: + E = H(BB, CC, DD); + j = ((i * 3) + 5) % 16; + break; + default: + E = I(BB, CC, DD); + j = (i * 7) % 16; + break; + } + + uint32_t temp = DD; + DD = CC; + CC = BB; + BB = BB + rotateLeft(AA + E + K[i] + input[j], S[i]); + AA = temp; + } + + ctxbuffer[0] += AA; + ctxbuffer[1] += BB; + ctxbuffer[2] += CC; + ctxbuffer[3] += DD; +} \ No newline at end of file diff --git a/zbs243_Tag_FW/md5.h b/zbs243_Tag_FW/md5.h new file mode 100644 index 00000000..dff4e36b --- /dev/null +++ b/zbs243_Tag_FW/md5.h @@ -0,0 +1,19 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +//#include +//#include + +extern uint64_t __xdata ctxsize; // Size of input in bytes +extern uint32_t __xdata ctxbuffer[4]; // Current accumulation of hash +extern uint8_t __xdata ctxinput[64]; // Input to be used in the next step +extern uint8_t __xdata ctxdigest[16]; // Result of algorithm + +void md5Init(); +void md5Update(uint8_t *input, size_t input_len) __reentrant; +void md5Finalize(); +void md5Step(uint32_t *input); + +#endif diff --git a/zbs243_Tag_FW/powermgt.c b/zbs243_Tag_FW/powermgt.c index 90372b30..a7b17569 100755 --- a/zbs243_Tag_FW/powermgt.c +++ b/zbs243_Tag_FW/powermgt.c @@ -119,13 +119,12 @@ static void configSPI(const bool setup) { static void configUART(const bool setup) { if (uartActive == setup) return; if (setup) { - P0FUNC |= (1 << 6) | (1 << 7); + P0FUNC |= (1 << 6); P0DIR &= ~(1 << 6); - P0DIR |= (1 << 7); uartInit(); } else { P0DIR |= (1 << 6); - P0FUNC &= ~((1 << 6) | (1 << 7)); + P0FUNC &= ~(1 << 6); CLKEN &= ~(0x20); } uartActive = setup; @@ -268,13 +267,6 @@ void powerDown(const uint8_t parts) { } void doSleep(const uint32_t __xdata t) { - // if (t > 1000) pr("s=%lu\n ", t / 1000); - // powerPortsDownForSleep(); - - // set up pins for spi(0.0,0.1,0.2), UART (0.6) - // setup 1.1(eeprom_nCS), 1.2(eink_BS1), 1.7(eink_nCS) - // setup 2.0(eink_nRST), 2.1(eink_BUSY), 2.2(eink_D/nC) - UartTxWait(); P0FUNC = 0; P1FUNC = 0; P2FUNC = 0; @@ -294,7 +286,9 @@ void doSleep(const uint32_t __xdata t) { uartActive = false; eepromActive = false; - //capabilities |= CAPABILITY_HAS_WAKE_BUTTON; +#ifdef ISDEBUGBUILD + capabilities |= CAPABILITY_HAS_WAKE_BUTTON; +#endif if (capabilities & CAPABILITY_HAS_WAKE_BUTTON) { // Button setup on TEST pin 1.0 (input pullup) diff --git a/zbs243_Tag_FW/settings.c b/zbs243_Tag_FW/settings.c index 0939b733..c2697d62 100755 --- a/zbs243_Tag_FW/settings.c +++ b/zbs243_Tag_FW/settings.c @@ -38,13 +38,17 @@ void loadDefaultSettings() { } void loadSettingsFromBuffer(uint8_t* p) { +#ifdef DEBUGSETTINGS pr("SETTINGS: received settings from AP\n"); +#endif switch (*p) { case SETTINGS_STRUCT_VERSION: // the current tag struct memcpy((void*)tagSettings, (void*)p, sizeof(struct tagsettings)); break; default: +#ifdef DEBUGSETTINGS pr("SETTINGS: received something we couldn't really process, version %d\n"); +#endif break; } tagSettings.fastBootCapabilities = capabilities; @@ -75,29 +79,39 @@ void loadSettings() { if (tagSettings.settingsVer == 0xFF || valid != SETTINGS_MAGIC) { // settings not set. load the defaults loadDefaultSettings(); +#ifdef DEBUGSETTINGS pr("SETTINGS: Loaded default settings\n"); +#endif } else { if (tagSettings.settingsVer < SETTINGS_STRUCT_VERSION) { // upgrade upgradeSettings(); +#ifdef DEBUGSETTINGS pr("SETTINGS: Upgraded from previous version\n"); +#endif } else { // settings are valid +#ifdef DEBUGSETTINGS pr("SETTINGS: Loaded from EEPROM\n"); +#endif } } } void writeSettings() { if (compareSettings()) { +#ifdef DEBUGSETTINGS pr("SETTINGS: Settings matched current settings\n"); +#endif return; } eepromErase(EEPROM_SETTINGS_AREA_START, 1); uint32_t __xdata valid = SETTINGS_MAGIC; eepromWrite(EEPROM_SETTINGS_AREA_START, (void*)&valid, 4); eepromWrite(EEPROM_SETTINGS_AREA_START + 4, (void*)&tagSettings, sizeof(tagSettings)); +#ifdef DEBUGSETTINGS pr("SETTINGS: Updated settings in EEPROM\n"); +#endif } void invalidateSettingsEEPROM() { diff --git a/zbs243_Tag_FW/settings.h b/zbs243_Tag_FW/settings.h index 362d62ab..06c449f2 100755 --- a/zbs243_Tag_FW/settings.h +++ b/zbs243_Tag_FW/settings.h @@ -3,15 +3,28 @@ #include -#define FW_VERSION 0x0025 // version number -#define FW_VERSION_SUFFIX "-FIX3" // suffix, like -RC1 or whatever. -// #define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers -// #define PRINT_LUT // uncomment if you want the tag to print the LUT for the current temperature bracket -// #define ENABLE_EEPROM_LOADER // uncomment if you want to load eeprom images via the serial interface -// #define ENABLE_GPIO_WAKE // uncomment to enable GPIO wake -// #define ENABLE_RETURN_DATA // enables the tag to send blocks of data back. Enabling this costs about 4 IRAM bytes -// #define LEAN_VERSION // makes a smaller version, leaving extra flash space for other things -// #define WRITE_MAC_FROM_FLASH // takes mac address from flash if none is set in the infopage +#define FW_VERSION 0x0026 // version number +#define FW_VERSION_SUFFIX "-MD5" // suffix, like -RC1 or whatever. +// #define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers +// #define DEBUGPROTO // debug protocol +// #define DEBUGOTA // debug OTA FW updates +// #define DEBUGDRAWING // debug the drawing part +// #define DEBUGEPD // debug the EPD driver +// #define DEBUGMAIN // parts in the main loop +// #define DEBUGNFC // debug NFC functions +// #define DEBUGGUI // debug GUI drawing (enabled) +// #define DEBUGSETTINGS // debug settings module (preferences/eeprom) + +#define VALIDATE_IMAGE_MD5 // The firmware can validate the image MD5 before displaying it. This costs about 8mAS (milliamp-second) for a 1.54, 16 +// #define PRINT_LUT // uncomment if you want the tag to print the LUT for the current temperature bracket +// #define ENABLE_GPIO_WAKE // uncomment to enable GPIO wake +// #define ENABLE_RETURN_DATA // enables the tag to send blocks of data back. Enabling this costs about 4 IRAM bytes +// #define LEAN_VERSION // makes a smaller version, leaving extra flash space for other things +// #define WRITE_MAC_FROM_FLASH // takes mac address from flash if none is set in the infopage + +#if defined(DEBUGSETTINGS) || defined(DEBUGMSG) || defined(DEBUGBLOCKS) || defined(DEBUGPROTO) || defined(DEBUGOTA) || defined(DEBUGNFC) || defined(DEBUGEPD) || defined(DEBUGMAIN) +#define ISDEBUGBUILD +#endif #define SETTINGS_STRUCT_VERSION 0x01 diff --git a/zbs243_Tag_FW/syncedproto.c b/zbs243_Tag_FW/syncedproto.c index d07b14e3..d3bec98e 100755 --- a/zbs243_Tag_FW/syncedproto.c +++ b/zbs243_Tag_FW/syncedproto.c @@ -26,6 +26,8 @@ #include "userinterface.h" #include "wdt.h" #include "uart.h" +#include "md5.h" +#include "flash.h" // download-stuff uint8_t __xdata blockbuffer[BLOCK_XFER_BUFFER_SIZE] = {0}; @@ -54,6 +56,9 @@ uint8_t __xdata currentChannel = 0; static uint8_t __xdata inBuffer[128] = {0}; static uint8_t __xdata outBuffer[128] = {0}; +// determines if the tagAssociated loop in main.c performs a rapid next checkin +bool __xdata fastNextCheckin = false; + // other stuff we shouldn't have to put here... static uint32_t __xdata markerValid = EEPROM_IMG_VALID; @@ -99,7 +104,6 @@ void dump(const uint8_t *__xdata a, const uint16_t __xdata l) { pr("\n0x%04X | ", c); } pr("%02X ", a[c]); - UartTxWait(); } pr("\n--------"); for (uint8_t c = 0; c < ROWS; c++) { @@ -140,8 +144,8 @@ static void sendPing() { txframe->srcPan = PROTO_PAN_ID; commsTxNoCpy(outBuffer); } -uint8_t detectAP(const uint8_t channel) { - uint32_t __xdata t; +uint8_t detectAP(const uint8_t channel) __reentrant { + static uint32_t __xdata t; radioRxEnable(false, true); radioSetChannel(channel); radioRxFlush(); @@ -150,12 +154,14 @@ uint8_t detectAP(const uint8_t channel) { sendPing(); t = timerGet() + (TIMER_TICKS_PER_MS * PING_REPLY_WINDOW); while (timerGet() < t) { - int8_t __xdata ret = commsRxUnencrypted(inBuffer); + static int8_t __xdata ret; + ret = commsRxUnencrypted(inBuffer); if (ret > 1) { // dump(inBuffer+sizeof(struct MacFrameNormal),32); if ((inBuffer[sizeof(struct MacFrameNormal) + 1] == channel) && (getPacketType(inBuffer) == PKT_PONG)) { if (pktIsUnicast(inBuffer)) { - struct MacFrameNormal *__xdata f = (struct MacFrameNormal *)inBuffer; + static struct MacFrameNormal *__xdata f; + f = (struct MacFrameNormal *)inBuffer; memcpy(APmac, f->src, 8); APsrcPan = f->pan; return c; @@ -317,9 +323,6 @@ static bool processBlockPart(const struct blockPart *bp) { size = sizeof(blockbuffer) - start; } - // check if we already processed this blockpart - if (!(curBlock.requestedParts[bp->blockPart / 8] & (1 << (bp->blockPart % 8)))) return false; - if (checkCRC(bp, sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE)) { // copy block data to buffer xMemCopy((void *)(blockbuffer + start), (const void *)bp->data, size); @@ -381,15 +384,16 @@ static void sendBlockRequest() { addCRC(blockreq, sizeof(struct blockRequest)); commsTxNoCpy(outBuffer); } -static struct blockRequestAck *__xdata performBlockRequest() { - uint32_t __xdata t; +static struct blockRequestAck *__xdata performBlockRequest() __reentrant { + static uint32_t __xdata t; radioRxEnable(true, true); radioRxFlush(); for (uint8_t c = 0; c < 30; c++) { sendBlockRequest(); t = timerGet() + (TIMER_TICKS_PER_MS * (7UL + c / 10)); do { - int8_t __xdata ret = commsRxUnencrypted(inBuffer); + static int8_t __xdata ret; + ret = commsRxUnencrypted(inBuffer); if (ret > 1) { switch (getPacketType(inBuffer)) { case PKT_BLOCK_REQUEST_ACK: @@ -405,7 +409,9 @@ static struct blockRequestAck *__xdata performBlockRequest() { case PKT_CANCEL_XFER: return NULL; default: +#ifdef DEBUGPROTO pr("pkt w/type %02X\n", getPacketType(inBuffer)); +#endif break; } } @@ -444,13 +450,17 @@ static void sendXferComplete() { int8_t __xdata ret = commsRxUnencrypted(inBuffer); if (ret > 1) { if (getPacketType(inBuffer) == PKT_XFER_COMPLETE_ACK) { +#ifdef DEBUGPROTO pr("XFC ACK\n"); +#endif return; } } } } +#ifdef DEBUGPROTO pr("XFC NACK!\n"); +#endif return; } bool validateBlockData() { @@ -471,18 +481,26 @@ static void getNumSlots() { eeSize = eepromGetSize(); uint16_t nSlots = mathPrvDiv32x16(eeSize - EEPROM_IMG_START, EEPROM_IMG_EACH >> 8) >> 8; if (eeSize < EEPROM_IMG_START || !nSlots) { +#ifdef DEBUGPROTO pr("eeprom is too small\n"); +#endif while (1) ; } else if (nSlots >> 8) { +#ifdef DEBUGPROTO pr("eeprom is too big, some will be unused\n"); +#endif imgSlots = 254; } else imgSlots = nSlots; - +#ifdef DEBUGPROTO pr("PROTO: %d image slots total\n", imgSlots); +#endif } static uint8_t findSlotVer(const uint8_t *ver) { +#ifdef DEBUGBLOCKS + return 0xFF; +#endif // return 0xFF; // remove me! This forces the tag to re-download each and every upload without checking if it's already in the eeprom somewhere for (uint8_t c = 0; c < imgSlots; c++) { struct EepromImageHeader __xdata *eih = (struct EepromImageHeader __xdata *)blockbuffer; @@ -538,15 +556,13 @@ static void eraseImageBlock(const uint8_t c) { eepromErase(getAddressForSlot(c), EEPROM_IMG_EACH / EEPROM_ERZ_SECTOR_SZ); } static void saveUpdateBlockData(uint8_t blockId) { - if (!eepromWrite(eeSize - OTA_UPDATE_SIZE + (blockId * BLOCK_DATA_SIZE), blockbuffer + sizeof(struct blockData), BLOCK_DATA_SIZE)) - pr("EEPROM write failed\n"); + eepromWrite(eeSize - OTA_UPDATE_SIZE + (blockId * BLOCK_DATA_SIZE), blockbuffer + sizeof(struct blockData), BLOCK_DATA_SIZE); } static void saveImgBlockData(const uint8_t imgSlot, const uint8_t blockId) { uint16_t length = EEPROM_IMG_EACH - (sizeof(struct EepromImageHeader) + (blockId * BLOCK_DATA_SIZE)); if (length > 4096) length = 4096; - if (!eepromWrite(getAddressForSlot(imgSlot) + sizeof(struct EepromImageHeader) + (blockId * BLOCK_DATA_SIZE), blockbuffer + sizeof(struct blockData), length)) - pr("EEPROM write failed\n"); + eepromWrite(getAddressForSlot(imgSlot) + sizeof(struct EepromImageHeader) + (blockId * BLOCK_DATA_SIZE), blockbuffer + sizeof(struct blockData), length); } void eraseImageBlocks() { for (uint8_t c = 0; c < imgSlots; c++) { @@ -568,7 +584,9 @@ static uint32_t getHighSlotId() { } } } +#ifdef DEBUGPROTO pr("found high id=%lu in slot %d\n", temp, nextImgSlot); +#endif return temp; } @@ -612,7 +630,9 @@ static bool getDataBlock(const uint16_t blockSize) { struct blockRequestAck *__xdata ack = performBlockRequest(); if (ack == NULL) { +#ifdef DEBUGPROTO pr("Cancelled request\n"); +#endif return false; } if (ack->pleaseWaitMs) { // SLEEP - until the AP is ready with the data @@ -674,17 +694,22 @@ static bool getDataBlock(const uint16_t blockSize) { } uint16_t __xdata dataRequestSize = 0; +uint16_t __xdata otaSize = 0; static bool downloadFWUpdate(const struct AvailDataInfo *__xdata avail) { // check if we already started the transfer of this information & haven't completed it if (xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & xferDataInfo.dataVer, 8) && xferDataInfo.dataSize) { // looks like we did. We'll carry on where we left off. } else { +#if defined(DEBUGOTA) + pr("OTA: Start update!\n"); +#endif // start, or restart the transfer from 0. Copy data from the AvailDataInfo struct, and the struct intself. This forces a new transfer curBlock.blockId = 0; xMemCopy8(&(curBlock.ver), &(avail->dataVer)); curBlock.type = avail->dataType; xMemCopyShort(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); eraseUpdateBlock(); + otaSize = xferDataInfo.dataSize; } while (xferDataInfo.dataSize) { @@ -708,18 +733,35 @@ static bool downloadFWUpdate(const struct AvailDataInfo *__xdata avail) { return false; } } + wdt60s(); + powerUp(INIT_EEPROM); + if (!validateMD5(eeSize - OTA_UPDATE_SIZE, otaSize)) { +#if defined(DEBUGOTA) + pr("OTA: MD5 verification failed!\n"); +#endif + // if not valid, restart transfer from the beginning + curBlock.blockId = 0; + powerDown(INIT_EEPROM); + return false; + } +#if defined(DEBUGOTA) + pr("OTA: MD5 pass!\n"); +#endif + // no more data, download complete return true; } uint16_t __xdata imageSize = 0; static bool downloadImageDataToEEPROM(const struct AvailDataInfo *__xdata avail) { - // check if we already started the transfer of this information & haven't completed it + // check if we already started the transfer of this information & haven't completed it if (xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & xferDataInfo.dataVer, 8) && (xferDataInfo.dataTypeArgument == avail->dataTypeArgument) && xferDataInfo.dataSize) { - // looks like we did. We'll carry on where we left off. +// looks like we did. We'll carry on where we left off. +#ifdef DEBUGPROTO pr("restarting image download"); +#endif } else { // new transfer powerUp(INIT_EEPROM); @@ -737,7 +779,9 @@ static bool downloadImageDataToEEPROM(const struct AvailDataInfo *__xdata avail) if (nextImgSlot >= imgSlots) nextImgSlot = 0; if (nextImgSlot == startingSlot) { powerDown(INIT_EEPROM); +#ifdef DEBUGPROTO pr("No slots available. Too many images in the slideshow?\n"); +#endif return true; } struct EepromImageHeader __xdata *eih = (struct EepromImageHeader __xdata *)blockbuffer; @@ -768,8 +812,9 @@ static bool downloadImageDataToEEPROM(const struct AvailDataInfo *__xdata avail) wdtDeviceReset(); eraseSuccess: powerDown(INIT_EEPROM); +#ifdef DEBUGPROTO pr("new download, writing to slot %d\n", xferImgSlot); - +#endif // start, or restart the transfer. Copy data from the AvailDataInfo struct, and the struct intself. This forces a new transfer curBlock.blockId = 0; xMemCopy8(&(curBlock.ver), &(avail->dataVer)); @@ -806,6 +851,16 @@ static bool downloadImageDataToEEPROM(const struct AvailDataInfo *__xdata avail) } // no more data, download complete + // validate MD5 + powerUp(INIT_EEPROM); +#ifdef VALIDATE_IMAGE_MD5 + if (!validateMD5(getAddressForSlot(xferImgSlot) + sizeof(struct EepromImageHeader), imageSize)) { + // if not valid, restart transfer from the beginning + curBlock.blockId = 0; + powerDown(INIT_EEPROM); + return false; + } +#endif // borrow the blockbuffer temporarily struct EepromImageHeader __xdata *eih = (struct EepromImageHeader __xdata *)blockbuffer; xMemCopy8(&eih->version, &xferDataInfo.dataVer); @@ -818,19 +873,19 @@ static bool downloadImageDataToEEPROM(const struct AvailDataInfo *__xdata avail) #ifdef DEBUGBLOCKS pr("Now writing datatype 0x%02X to slot %d\n", xferDataInfo.dataType, xferImgSlot); #endif - powerUp(INIT_EEPROM); eepromWrite(getAddressForSlot(xferImgSlot), eih, sizeof(struct EepromImageHeader)); powerDown(INIT_EEPROM); return true; } +struct imageDataTypeArgStruct __xdata arg = {0}; // this is related to the function below, but if declared -inside- the function, it gets cleared during sleep... inline bool processImageDataAvail(struct AvailDataInfo *__xdata avail) { - struct imageDataTypeArgStruct arg; *((uint8_t *)arg) = avail->dataTypeArgument; - if (arg.preloadImage) { +#ifdef DEBUGPROTO pr("Preloading image with type 0x%02X from arg 0x%02X\n", arg.specialType, avail->dataTypeArgument); +#endif powerUp(INIT_EEPROM); switch (arg.specialType) { // check if a slot with this argument is already set; if so, erase. Only one of each arg type should exist @@ -855,11 +910,14 @@ inline bool processImageDataAvail(struct AvailDataInfo *__xdata avail) { break; } powerDown(INIT_EEPROM); - +#ifdef DEBUGPROTO pr("downloading preload image...\n"); +#endif if (downloadImageDataToEEPROM(avail)) { // sets xferImgSlot to the right slot +#ifdef DEBUGPROTO pr("preload complete!\n"); +#endif powerUp(INIT_RADIO); sendXferComplete(); powerDown(INIT_RADIO); @@ -872,8 +930,9 @@ inline bool processImageDataAvail(struct AvailDataInfo *__xdata avail) { // check if we're currently displaying this data payload if (xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata)curDispDataVer, 8)) { // currently displayed, not doing anything except for sending an XFC - +#ifdef DEBUGPROTO pr("currently shown image, send xfc\n"); +#endif powerUp(INIT_RADIO); sendXferComplete(); powerDown(INIT_RADIO); @@ -904,11 +963,15 @@ inline bool processImageDataAvail(struct AvailDataInfo *__xdata avail) { drawImageFromEeprom(findImgSlot, arg.lut); powerDown(INIT_EPD | INIT_EEPROM); } else { - // not found in cache, prepare to download +// not found in cache, prepare to download +#ifdef DEBUGPROTO pr("downloading image...\n"); +#endif if (downloadImageDataToEEPROM(avail)) { - // sets xferImgSlot to the right slot +// sets xferImgSlot to the right slot +#ifdef DEBUGPROTO pr("download complete!\n"); +#endif powerUp(INIT_RADIO); sendXferComplete(); powerDown(INIT_RADIO); @@ -942,23 +1005,42 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { case DATATYPE_FW_UPDATE: powerUp(INIT_EEPROM); if (downloadFWUpdate(avail)) { - pr("firmware download complete, doing update.\n"); - - powerUp(INIT_EPD); - showApplyUpdate(); - +#if defined(DEBUGOTA) + pr("OTA: Download complete\n"); +#endif powerUp(INIT_RADIO); sendXferComplete(); powerDown(INIT_RADIO); powerUp(INIT_EEPROM); - wdt60s(); - eepromReadStart(eeSize - OTA_UPDATE_SIZE); - selfUpdate(); + if (validateFWMagic()) { +#if defined(DEBUGOTA) + pr("OTA: Valid magic number\n"); +#endif + powerUp(INIT_EPD); + showApplyUpdate(); + wdt60s(); + eepromReadStart(eeSize - OTA_UPDATE_SIZE); + selfUpdate(); + // ends in WDT reset + } else { +#if defined(DEBUGOTA) + pr("OTA: Invalid magic number!\n"); +#endif + fastNextCheckin = true; + powerDown(INIT_EEPROM); + wakeUpReason = WAKEUP_REASON_FAILED_OTA_FW; + powerUp(INIT_EPD); + showFailedUpdate(); + powerDown(INIT_EPD); + memset(curDispDataVer, 0x00, 8); + } + } else { return false; } break; + case DATATYPE_NFC_URL_DIRECT: case DATATYPE_NFC_RAW_CONTENT: // Handle data for the NFC IC (if we have it) @@ -971,11 +1053,15 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { powerDown(INIT_RADIO); return true; } - +#ifndef LEAN_VERSION +#ifdef DEBUGPROTO pr("NFC URL received\n"); +#endif if (xferDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & xferDataInfo.dataVer, 8)) { // we've already downloaded this NFC data, disregard and send XFC +#ifdef DEBUGPROTO pr("this was the same as the last transfer, disregard\n"); +#endif powerUp(INIT_RADIO); sendXferComplete(); powerDown(INIT_RADIO); @@ -1005,10 +1091,14 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { return true; } return false; +#endif break; + case DATATYPE_TAG_CONFIG_DATA: if (xferDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & xferDataInfo.dataVer, 8)) { +#ifdef DEBUGPROTO pr("this was the same as the last transfer, disregard\n"); +#endif powerUp(INIT_RADIO); sendXferComplete(); powerDown(INIT_RADIO); @@ -1032,7 +1122,9 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { return false; break; case DATATYPE_COMMAND_DATA: +#ifdef DEBUGPROTO pr("CMD received\n"); +#endif powerUp(INIT_RADIO); sendXferComplete(); powerDown(INIT_RADIO); @@ -1051,9 +1143,13 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { return true; } #ifdef EPD_SSD1619 +#ifdef DEBUGPROTO pr("OTA LUT received\n"); +#endif if (xferDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & xferDataInfo.dataVer, 8)) { +#ifdef DEBUGPROTO pr("this was the same as the last transfer, disregard\n"); +#endif powerUp(INIT_RADIO); sendXferComplete(); powerDown(INIT_RADIO); @@ -1079,6 +1175,48 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { return true; } +bool validateMD5(uint32_t __xdata addr, uint16_t __xdata len) { + md5Init(); + while (len) { + eepromRead(addr, blockbuffer, 256); + if (len >= 256) { + md5Update(blockbuffer, 256); + len -= 256; + addr += 256; + } else { + md5Update(blockbuffer, len); + len = 0; + } + } + md5Finalize(); + if (xMemEqual((const void *__xdata)ctxdigest, (const void *__xdata) & xferDataInfo.dataVer, 8)) { +#ifdef DEBUGPROTO + pr("MD5 pass!"); +#endif + return true; + } else { +#ifdef DEBUGPROTO + pr("MD5 fail..."); +#endif + return false; + } +} + +bool validateFWMagic() { + flashRead(0x8b, (void *)(blockbuffer + 1024), 256); + eepromRead(eeSize - OTA_UPDATE_SIZE, blockbuffer, 256); + if (xMemEqual((const void *__xdata)(blockbuffer + 1024), (const void *__xdata)(blockbuffer + 0x8b), 8)) { +#ifdef DEBUGPROTO + pr("magic number matches! good fw"); +#endif + return true; + } else { +#ifdef DEBUGPROTO + pr("this probably isn't a (recent) firmware file\n"); +#endif + return false; + } +} void initializeProto() { getNumSlots(); curHighSlotId = getHighSlotId(); diff --git a/zbs243_Tag_FW/syncedproto.h b/zbs243_Tag_FW/syncedproto.h index 6e8ca280..bfb6bb0a 100755 --- a/zbs243_Tag_FW/syncedproto.h +++ b/zbs243_Tag_FW/syncedproto.h @@ -9,6 +9,8 @@ extern uint8_t __xdata currentChannel; extern uint8_t __xdata APmac[]; extern uint8_t __xdata curImgSlot; +extern bool __xdata fastNextCheckin; + //extern void setupRadio(void); //extern void killRadio(void); @@ -35,4 +37,7 @@ extern bool processAvailDataInfo(struct AvailDataInfo *__xdata avail); extern void initializeProto(); extern uint8_t detectAP(const uint8_t channel); +extern bool validateMD5(uint32_t __xdata addr, uint16_t __xdata len); +extern bool validateFWMagic(); + #endif \ No newline at end of file diff --git a/zbs243_Tag_FW/userinterface.c b/zbs243_Tag_FW/userinterface.c index 9a4e7882..8984d9e3 100755 --- a/zbs243_Tag_FW/userinterface.c +++ b/zbs243_Tag_FW/userinterface.c @@ -76,6 +76,19 @@ void addOverlay() { } else { lowBatteryShown = false; } + +#ifdef ISDEBUGBUILD +#if (SCREEN_WIDTH == 152) + epdPrintBegin(139, 151, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_RED); +#elif (SCREEN_WIDTH == 400) + epdPrintBegin(87, 0, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_RED); +#elif (SCREEN_WIDTH == 128) + epdPrintBegin(87, 0, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_RED); +#endif + epdpr("DEBUG"); + epdPrintEnd(); +#endif + } void afterFlashScreenSaver() { @@ -203,7 +216,7 @@ void showSplashScreen() { if (displayCustomImage(CUSTOM_IMAGE_SPLASHSCREEN)) return; powerUp(INIT_EPD); - #if (HW_TYPE != SOLUM_M2_BW_29_LOWTEMP) +#if (HW_TYPE != SOLUM_M2_BW_29_LOWTEMP) selectLUT(EPD_LUT_NO_REPEATS); #endif @@ -235,14 +248,27 @@ void showSplashScreen() { epdpr("zbs154 %04X%s", fwVersion, fwVersionSuffix); epdPrintEnd(); +#ifdef ISDEBUGBUILD + epdPrintBegin(5, 78, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_RED); + epdpr("DEBUG"); + epdPrintEnd(); +#endif + + #endif #if (SCREEN_WIDTH == 128) // 2.9" epdPrintBegin(0, 295, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK); - epdpr("Starting"); + epdpr("OpenEPaperLink"); epdPrintEnd(); +#ifdef ISDEBUGBUILD + epdPrintBegin(35, 280, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK); + epdpr("DEBUG"); + epdPrintEnd(); +#endif + epdPrintBegin(64, 295, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK); addCapabilities(); epdPrintEnd(); @@ -268,11 +294,6 @@ void showSplashScreen() { loadRawBitmap(oepli, 0, 12, EPD_COLOR_BLACK); loadRawBitmap(cloud, 0, 0, EPD_COLOR_RED); #endif - // lutTest(); - // drawLineVertical(EPD_COLOR_RED, 64, 10, 286); - // drawLineVertical(EPD_COLOR_BLACK, 65, 10, 286); - - // timerDelay(TIMER_TICKS_PER_SECOND * 4); #endif #if (SCREEN_WIDTH == 400) // 4.2" epdPrintBegin(3, 3, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK); @@ -331,13 +352,33 @@ void showApplyUpdate() { drawNoWait(); } +void showFailedUpdate() { + setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT); + selectLUT(1); + clearScreen(); + setColorMode(EPD_MODE_IGNORE, EPD_MODE_NORMAL); +#if (SCREEN_WIDTH == 152) + epdPrintBegin(18, 60, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK); +#endif +#if (SCREEN_WIDTH == 128) + epdPrintBegin(48, 270, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK); +#endif + +#if (SCREEN_WIDTH == 400) + epdPrintBegin(68, 134, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK); +#endif + epdpr("Invalid OTA FW!"); + epdPrintEnd(); + drawWithSleep(); +} + void showAPFound() { if (displayCustomImage(CUSTOM_IMAGE_APFOUND)) return; powerUp(INIT_EPD | INIT_EEPROM); clearScreen(); setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT); - #if (HW_TYPE != SOLUM_M2_BW_29_LOWTEMP) +#if (HW_TYPE != SOLUM_M2_BW_29_LOWTEMP) selectLUT(1); #endif @@ -451,7 +492,7 @@ void showAPFound() { void showNoAP() { if (displayCustomImage(CUSTOM_IMAGE_NOAPFOUND)) return; powerUp(INIT_EPD | INIT_EEPROM); - #if (HW_TYPE != SOLUM_M2_BW_29_LOWTEMP) +#if (HW_TYPE != SOLUM_M2_BW_29_LOWTEMP) selectLUT(EPD_LUT_NO_REPEATS); #endif diff --git a/zbs243_Tag_FW/userinterface.h b/zbs243_Tag_FW/userinterface.h index a3fbce46..1cd87d97 100755 --- a/zbs243_Tag_FW/userinterface.h +++ b/zbs243_Tag_FW/userinterface.h @@ -8,7 +8,10 @@ bool displayCustomImage(uint8_t imagetype); void afterFlashScreenSaver(); void showSplashScreen(); + void showApplyUpdate(); +void showFailedUpdate(); + void showAPFound(); void showNoAP(); void showLongTermSleep(); diff --git a/zbs243_shared/bitmaps.h b/zbs243_shared/bitmaps.h index 1a4e4b10..80221f03 100644 --- a/zbs243_shared/bitmaps.h +++ b/zbs243_shared/bitmaps.h @@ -8,6 +8,7 @@ #ifndef LEAN_VERSION + static const uint8_t __code oepli[] = { 128, 26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, diff --git a/zbs243_shared/board/ssd1619.c b/zbs243_shared/board/ssd1619.c index 23e53e1e..054329d3 100755 --- a/zbs243_shared/board/ssd1619.c +++ b/zbs243_shared/board/ssd1619.c @@ -198,9 +198,9 @@ static void epdReset() { timerDelay(TIMER_TICKS_PER_SECOND / 1000); shortCommand(CMD_SOFT_RESET); // software reset - timerDelay(TIMER_TICKS_PER_SECOND / 1000); + timerDelay(TIMER_TICKS_PER_SECOND / 500); shortCommand(CMD_SOFT_RESET2); - timerDelay(TIMER_TICKS_PER_SECOND / 1000); + timerDelay(TIMER_TICKS_PER_SECOND / 500); } void epdConfigGPIO(bool setup) { // data / _command: 2.2 @@ -233,7 +233,7 @@ void epdEnterSleep() { P2_0 = 1; timerDelay(50); shortCommand(CMD_SOFT_RESET2); - epdBusyWait(TIMER_TICKS_PER_MS * 15); + epdBusyWait(TIMER_TICKS_PER_MS * 150); shortCommand1(CMD_ENTER_SLEEP, 0x03); isInited = false; } @@ -291,11 +291,11 @@ uint16_t epdGetBattery(void) { shortCommand1(CMD_DISP_UPDATE_CTRL2, SCREEN_CMD_CLOCK_ON | SCREEN_CMD_ANALOG_ON); shortCommand(CMD_ACTIVATION); - epdBusyWait(TIMER_TICKS_PER_MS * 100); + epdBusyWait(TIMER_TICKS_PER_MS * 150); for (val = 3; val < 8; val++) { shortCommand1(CMD_SETUP_VOLT_DETECT, val); - epdBusyWait(TIMER_TICKS_PER_MS * 100); + epdBusyWait(TIMER_TICKS_PER_MS * 150); if (epdGetStatus() & 0x10) { // set if voltage is less than threshold ( == 1.9 + val / 10) voltage = 1850 + mathPrvMul8x8(val, 100); break; @@ -400,7 +400,9 @@ void selectLUT(uint8_t lut) { if (dispLutSize == 0) { dispLutSize = getLutSize(); dispLutSize /= 10; + #ifdef DEBUGEPD pr("lut size = %d\n", dispLutSize); + #endif #ifdef PRINT_LUT dump(waveformbuffer, LUT_BUFFER_SIZE); #endif @@ -721,6 +723,8 @@ static void pushYFontBytesToEPD(uint8_t byte1, uint8_t byte2) { } } void writeCharEPD(uint8_t c) { + c-=0x20; + // Writes a single character to the framebuffer bool empty = true; for (uint8_t i = 0; i < 20; i++) { diff --git a/zbs243_shared/font.h b/zbs243_shared/font.h index 3dece553..e06b1681 100644 --- a/zbs243_shared/font.h +++ b/zbs243_shared/font.h @@ -1,36 +1,5 @@ -static const uint8_t __code font[256][20]={ // https://raw.githubusercontent.com/basti79/LCD-fonts/master/10x16_vertikal_MSB_1.h -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x00 -{0xE0,0x01,0x30,0x03,0x50,0x02,0x28,0x05,0x28,0x04,0x28,0x04,0x28,0x05,0x50,0x02,0x30,0x03,0xE0,0x01}, // 0x01 -{0xE0,0x01,0xF0,0x03,0xB0,0x03,0xD8,0x06,0xD8,0x07,0xD8,0x07,0xD8,0x06,0xB0,0x03,0xF0,0x03,0xE0,0x01}, // 0x02 -{0x00,0x3E,0x80,0x7F,0xE0,0x7F,0xF0,0x7F,0xF8,0x3F,0xF8,0x3F,0xF0,0x7F,0xE0,0x7F,0x80,0x7F,0x00,0x3E}, // 0x03 -{0x00,0x01,0x80,0x03,0xC0,0x0F,0xE0,0x1F,0xF8,0x7F,0xF0,0x1F,0xE0,0x0F,0xC0,0x07,0x80,0x03,0x00,0x01}, // 0x04 -{0x80,0x03,0xC0,0x07,0xC0,0x07,0xC0,0x3F,0xF8,0x7F,0xB8,0x7F,0xC0,0x3F,0xC0,0x07,0xC0,0x07,0x80,0x03}, // 0x05 -{0x80,0x03,0xC0,0x07,0xC0,0x0F,0xC0,0x1F,0xF8,0x3F,0xB8,0x7F,0xC0,0x1F,0xC0,0x0F,0xC0,0x07,0x80,0x03}, // 0x06 -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x07 -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x08 -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x09 -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x0A -{0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0x08,0x04,0x08,0x24,0x10,0x2E,0xE0,0x71,0x00,0x70,0x00,0x18}, // 0x0B -{0x00,0x00,0x00,0x1E,0x20,0x21,0xA0,0x40,0xF8,0x40,0xA0,0x40,0xA0,0x41,0x00,0x21,0x00,0x1E,0x00,0x00}, // 0x0C -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x0D -{0x06,0x00,0x0E,0x00,0x0E,0x00,0xFC,0x1F,0x00,0x18,0x30,0x10,0x70,0x30,0x70,0x20,0xE0,0x7F,0x00,0x00}, // 0x0E -{0x00,0x01,0xC0,0x0F,0xC0,0x04,0x40,0x08,0x60,0x18,0x40,0x08,0x40,0x04,0xC0,0x0C,0xC0,0x0B,0x00,0x01}, // 0x0F -{0xF8,0x0F,0xF0,0x07,0xF0,0x07,0xE0,0x03,0xE0,0x03,0xE0,0x03,0xC0,0x01,0xC0,0x01,0x80,0x00,0x80,0x00}, // 0x10 -{0x80,0x00,0x80,0x00,0xC0,0x01,0xC0,0x01,0xE0,0x03,0xE0,0x03,0xE0,0x03,0xF0,0x07,0xF0,0x07,0xF8,0x0F}, // 0x11 -{0x00,0x00,0x00,0x00,0x08,0x10,0x04,0x20,0xFE,0x7F,0x04,0x20,0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x12 -{0x00,0x00,0x00,0x00,0xD8,0x7F,0x00,0x00,0x00,0x00,0xD8,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x13 -{0x00,0x00,0x00,0x38,0x00,0x7C,0x00,0x7E,0xFE,0x7F,0x00,0x40,0x00,0x40,0xFE,0x7F,0x00,0x00,0x00,0x00}, // 0x14 -{0x00,0x00,0x00,0x00,0x86,0x3B,0xC2,0x4C,0x42,0x44,0x62,0x46,0x32,0x42,0xDC,0x41,0x00,0x00,0x00,0x00}, // 0x15 -{0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x00}, // 0x16 -{0x00,0x00,0x00,0x00,0x11,0x10,0x09,0x20,0xFD,0x7F,0x09,0x20,0x11,0x10,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x17 -{0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x20,0xFE,0x7F,0x00,0x20,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x18 -{0x00,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0xFE,0x7F,0x04,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x19 -{0x00,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0xA0,0x02,0xC0,0x01,0x80,0x00,0x00,0x00}, // 0x1A -{0x00,0x00,0x80,0x00,0xC0,0x01,0xA0,0x02,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00,0x00}, // 0x1B -{0x00,0x00,0xF8,0x07,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00}, // 0x1C -{0x00,0x00,0x80,0x00,0xC0,0x01,0xA0,0x02,0x80,0x00,0x80,0x00,0xA0,0x02,0xC0,0x01,0x80,0x00,0x00,0x00}, // 0x1D -{0x08,0x00,0x18,0x00,0x78,0x00,0xF8,0x01,0xF8,0x03,0xF8,0x0F,0xF8,0x03,0xF8,0x00,0x38,0x00,0x08,0x00}, // 0x1E -{0x00,0x08,0x00,0x0C,0x00,0x0F,0xC0,0x0F,0xE0,0x0F,0xF8,0x0F,0xE0,0x0F,0x80,0x0F,0x00,0x0E,0x00,0x08}, // 0x1F +static const uint8_t __code font[96][20]={ // https://raw.githubusercontent.com/basti79/LCD-fonts/master/10x16_vertikal_MSB_1.h + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x20 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD8,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x21 {0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x22 @@ -127,132 +96,4 @@ static const uint8_t __code font[256][20]={ // https://raw.githubusercontent.com {0x00,0x00,0x00,0x00,0x02,0x40,0x02,0x40,0x02,0x40,0x7C,0x3F,0x80,0x00,0x80,0x00,0x00,0x00,0x00,0x00}, // 0x7D {0xC0,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x80,0x00,0x80,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x80,0x01}, // 0x7E {0x00,0x00,0xF8,0x01,0x08,0x03,0x08,0x04,0x08,0x08,0x08,0x04,0x08,0x03,0xF8,0x01,0x00,0x00,0x00,0x00}, // 0x7F -{0xC0,0x03,0x30,0x0C,0x10,0x08,0x08,0x10,0x08,0x10,0x09,0x10,0x0D,0x10,0x0B,0x18,0x00,0x00,0x00,0x00}, // 0x80 -{0x00,0x00,0xF0,0x07,0x08,0x20,0x08,0x00,0x08,0x00,0x10,0x20,0xF8,0x07,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x81 -{0x00,0x00,0xE0,0x01,0x90,0x02,0x88,0x04,0x88,0x24,0x88,0x44,0x88,0x04,0x88,0x03,0x00,0x00,0x00,0x00}, // 0x82 -{0x00,0x00,0x30,0x00,0x48,0x24,0x88,0x44,0x88,0x44,0x90,0x24,0xF8,0x03,0x08,0x00,0x00,0x00,0x00,0x00}, // 0x83 -{0x00,0x00,0x30,0x00,0x48,0x24,0x88,0x04,0x88,0x04,0x90,0x24,0xF8,0x03,0x08,0x00,0x00,0x00,0x00,0x00}, // 0x84 -{0x00,0x00,0x30,0x00,0x48,0x44,0x88,0x24,0x88,0x04,0x90,0x04,0xF8,0x03,0x08,0x00,0x00,0x00,0x00,0x00}, // 0x85 -{0x00,0x00,0x30,0x00,0x48,0x04,0x88,0x44,0x88,0xA4,0x90,0x44,0xF8,0x03,0x08,0x00,0x00,0x00,0x00,0x00}, // 0x86 -{0x00,0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x09,0x04,0x0D,0x04,0x0B,0x04,0x08,0x04,0x00,0x00,0x00,0x00}, // 0x87 -{0x00,0x00,0xE0,0x01,0x90,0x22,0x88,0x44,0x88,0x44,0x88,0x24,0x88,0x04,0x88,0x03,0x00,0x00,0x00,0x00}, // 0x88 -{0x00,0x00,0xE0,0x01,0x90,0x02,0x88,0x24,0x88,0x04,0x88,0x04,0x88,0x24,0x88,0x03,0x00,0x00,0x00,0x00}, // 0x89 -{0x00,0x00,0xE0,0x01,0x90,0x02,0x88,0x44,0x88,0x24,0x88,0x04,0x88,0x04,0x88,0x03,0x00,0x00,0x00,0x00}, // 0x8A -{0x00,0x00,0x00,0x04,0x00,0x24,0x00,0x04,0xF8,0x07,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x8B -{0x00,0x00,0x00,0x04,0x00,0x24,0x00,0x44,0xF8,0x47,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x8C -{0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x44,0xF8,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x8D -{0x08,0x00,0x70,0x00,0xC0,0x81,0x40,0x0E,0x40,0x18,0x40,0x0C,0x40,0x83,0xC0,0x00,0x30,0x00,0x08,0x00}, // 0x8E -{0x08,0x00,0x70,0x00,0xC0,0x01,0x40,0x4E,0x40,0xB0,0x40,0xB8,0x40,0x4F,0xC0,0x01,0x70,0x00,0x08,0x00}, // 0x8F -{0x00,0x00,0xF8,0x1F,0x88,0x10,0x88,0x10,0x88,0x50,0x88,0x90,0x88,0x10,0x08,0x10,0x00,0x00,0x00,0x00}, // 0x90 -{0x70,0x04,0xC8,0x04,0x88,0x04,0x88,0x04,0xF0,0x03,0x98,0x04,0x88,0x04,0x88,0x04,0x88,0x03,0x00,0x00}, // 0x91 -{0x08,0x00,0x30,0x00,0xE0,0x01,0x20,0x06,0x20,0x18,0xF8,0x1F,0x88,0x10,0x88,0x10,0x08,0x10,0x00,0x00}, // 0x92 -{0x00,0x00,0xE0,0x01,0x10,0x22,0x08,0x44,0x08,0x44,0x08,0x24,0x10,0x02,0xE0,0x01,0x00,0x00,0x00,0x00}, // 0x93 -{0x00,0x00,0xE0,0x01,0x10,0x22,0x08,0x04,0x08,0x04,0x08,0x24,0x10,0x02,0xE0,0x01,0x00,0x00,0x00,0x00}, // 0x94 -{0x00,0x00,0xE0,0x01,0x10,0x42,0x08,0x24,0x08,0x04,0x08,0x04,0x10,0x02,0xE0,0x01,0x00,0x00,0x00,0x00}, // 0x95 -{0x00,0x00,0xF0,0x07,0x08,0x20,0x08,0x40,0x08,0x40,0x10,0x20,0xF8,0x07,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x96 -{0x00,0x00,0xF0,0x07,0x08,0x40,0x08,0x20,0x08,0x00,0x10,0x00,0xF8,0x07,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x97 -{0x01,0x04,0x01,0x03,0xC1,0x20,0x62,0x00,0x1C,0x00,0x18,0x20,0x60,0x00,0x80,0x00,0x00,0x03,0x00,0x04}, // 0x98 -{0x00,0x00,0xE0,0x07,0x10,0x88,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x90,0x10,0x08,0xE0,0x07,0x00,0x00}, // 0x99 -{0x00,0x00,0xE0,0x1F,0x18,0x80,0x08,0x00,0x08,0x00,0x08,0x00,0x10,0x80,0xE0,0x1F,0x00,0x00,0x00,0x00}, // 0x9A -{0x00,0x00,0xE8,0x01,0x10,0x02,0x28,0x04,0xC8,0x04,0x08,0x05,0x10,0x02,0xE0,0x05,0x00,0x00,0x00,0x00}, // 0x9B -{0x00,0x00,0x00,0x00,0x08,0x00,0x18,0x02,0xE8,0x3F,0x08,0x42,0x08,0x42,0x08,0x40,0x00,0x00,0x00,0x00}, // 0x9C -{0x00,0x00,0xE8,0x07,0x30,0x08,0x68,0x10,0x88,0x10,0x08,0x11,0x08,0x16,0x10,0x0C,0xE0,0x17,0x00,0x00}, // 0x9D -{0x00,0x00,0x08,0x04,0x10,0x02,0x20,0x01,0xC0,0x00,0xC0,0x00,0x20,0x01,0x10,0x02,0x08,0x04,0x00,0x00}, // 0x9E -{0x00,0x00,0x01,0x00,0x01,0x04,0x01,0x04,0xFE,0x7F,0x00,0x84,0x00,0x84,0x00,0x80,0x00,0x00,0x00,0x00}, // 0x9F -{0x00,0x00,0x30,0x00,0x48,0x04,0x88,0x04,0x88,0x24,0x90,0x44,0xF8,0x03,0x08,0x00,0x00,0x00,0x00,0x00}, // 0xA0 -{0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x04,0xF8,0x27,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xA1 -{0x00,0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x24,0x08,0x44,0x10,0x02,0xE0,0x01,0x00,0x00,0x00,0x00}, // 0xA2 -{0x00,0x00,0xF0,0x07,0x08,0x00,0x08,0x00,0x08,0x20,0x10,0x40,0xF8,0x07,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xA3 -{0x00,0x00,0xF8,0x07,0x00,0x23,0x00,0x42,0x00,0x24,0x00,0x24,0x00,0x44,0xF8,0x03,0x00,0x00,0x00,0x00}, // 0xA4 -{0x00,0x00,0xF8,0x1F,0x00,0x48,0x00,0x86,0x80,0xC1,0x60,0x40,0x10,0x80,0xF8,0x1F,0x00,0x00,0x00,0x00}, // 0xA5 -{0x00,0x00,0x00,0x00,0x00,0x4C,0x00,0x52,0x00,0x52,0x00,0x52,0x00,0x3E,0x00,0x02,0x00,0x00,0x00,0x00}, // 0xA6 -{0x00,0x00,0x00,0x00,0x00,0x3C,0x00,0x42,0x00,0x42,0x00,0x42,0x00,0x42,0x00,0x3C,0x00,0x00,0x00,0x00}, // 0xA7 -{0x00,0x00,0x0E,0x00,0x13,0x00,0x11,0x00,0x21,0x00,0xC1,0x06,0x01,0x00,0x07,0x00,0x00,0x00,0x00,0x00}, // 0xA8 -{0x00,0x00,0x00,0x1C,0x00,0x22,0x00,0x5D,0x00,0x55,0x00,0x5D,0x00,0x22,0x00,0x1C,0x00,0x00,0x00,0x00}, // 0xA9 -{0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0xE0,0x01,0x00,0x00}, // 0xAA -{0x08,0x40,0x30,0x7E,0x40,0x00,0x80,0x01,0x00,0x06,0x00,0x08,0x08,0x31,0x38,0x41,0x28,0x01,0xC8,0x00}, // 0xAB -{0x08,0x40,0x30,0x7E,0x40,0x00,0x80,0x01,0x00,0x06,0x60,0x08,0xA0,0x30,0x20,0x41,0xF8,0x01,0x20,0x00}, // 0xAC -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xAD -{0x00,0x00,0x80,0x00,0x40,0x01,0x20,0x02,0x10,0x04,0x80,0x00,0x40,0x01,0x20,0x02,0x10,0x04,0x00,0x00}, // 0xAE -{0x00,0x00,0x10,0x04,0x20,0x02,0x40,0x01,0x80,0x00,0x10,0x04,0x20,0x02,0x40,0x01,0x80,0x00,0x00,0x00}, // 0xAF -{0x36,0xDB,0x36,0xDB,0x00,0x00,0x36,0xDB,0x36,0xDB,0x00,0x00,0x36,0xDB,0x36,0xDB,0x00,0x00,0x00,0x00}, // 0xB0 -{0xDB,0x36,0xDB,0x36,0x36,0xDB,0xFF,0xFF,0xDB,0x36,0x36,0xDB,0xFF,0xFF,0xDB,0x36,0x36,0xDB,0x36,0xDB}, // 0xB1 -{0xFF,0xFF,0xFF,0xFF,0x36,0xDB,0xFF,0xFF,0xFF,0xFF,0x36,0xDB,0xFF,0xFF,0xFF,0xFF,0x36,0xDB,0x36,0xDB}, // 0xB2 -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xB3 -{0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xB4 -{0x08,0x00,0x70,0x00,0xC0,0x01,0x40,0x0E,0x40,0x58,0x40,0x8C,0x40,0x03,0xC0,0x00,0x30,0x00,0x08,0x00}, // 0xB5 -{0x08,0x00,0x70,0x00,0xC0,0x01,0x40,0x4E,0x40,0x98,0x40,0x8C,0x40,0x43,0xC0,0x00,0x30,0x00,0x08,0x00}, // 0xB6 -{0x08,0x00,0x70,0x00,0xC0,0x01,0x40,0x8E,0x40,0x58,0x40,0x0C,0x40,0x03,0xC0,0x00,0x30,0x00,0x08,0x00}, // 0xB7 -{0xC0,0x0F,0x30,0x30,0x98,0x67,0xC8,0x4C,0x48,0x48,0x48,0x48,0x58,0x68,0x30,0x30,0xC0,0x0F,0x00,0x00}, // 0xB8 -{0x40,0x01,0x40,0x01,0x40,0x01,0x7F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xB9 -{0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xBA -{0x40,0x01,0x40,0x01,0x40,0x01,0x7F,0x01,0x00,0x01,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xBB -{0x40,0x01,0x40,0x01,0x40,0x01,0x40,0xFF,0x40,0x00,0xC0,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xBC -{0x00,0x00,0xC0,0x0F,0x20,0x10,0x30,0x20,0x10,0x20,0xF8,0x7F,0x10,0x20,0x10,0x20,0x00,0x00,0x00,0x00}, // 0xBD -{0x00,0x40,0x00,0x20,0x20,0x19,0x20,0x05,0xF8,0x03,0x20,0x05,0x20,0x09,0x00,0x10,0x00,0x20,0x00,0x40}, // 0xBE -{0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xBF -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00}, // 0xC0 -{0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0xFF,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00}, // 0xC1 -{0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0xFF,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00}, // 0xC2 -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00}, // 0xC3 -{0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00}, // 0xC4 -{0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0xFF,0xFF,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00}, // 0xC5 -{0x00,0x00,0x30,0x00,0x48,0x24,0x88,0x44,0x88,0x24,0x90,0x24,0xF8,0x43,0x08,0x00,0x00,0x00,0x00,0x00}, // 0xC6 -{0x08,0x00,0x70,0x00,0xC0,0x41,0x40,0x8E,0x40,0xD8,0x40,0x4C,0x40,0x83,0xC0,0x00,0x30,0x00,0x08,0x00}, // 0xC7 -{0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0x40,0x00,0x40,0xFF,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01}, // 0xC8 -{0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x01,0x00,0x01,0x7F,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01}, // 0xC9 -{0x40,0x01,0x40,0x01,0x40,0x01,0x40,0xFF,0x40,0x00,0x40,0xFF,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01}, // 0xCA -{0x40,0x01,0x40,0x01,0x40,0x01,0x7F,0x01,0x00,0x01,0x7F,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01}, // 0xCB -{0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x7F,0xFF,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01}, // 0xCC -{0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01}, // 0xCD -{0x40,0x01,0x40,0x01,0x40,0x01,0x7F,0xFF,0x00,0x00,0x7F,0xFF,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01}, // 0xCE -{0x00,0x00,0x20,0x10,0xC0,0x0F,0x40,0x08,0x40,0x08,0x40,0x08,0x40,0x08,0xC0,0x0F,0x20,0x10,0x00,0x00}, // 0xCF -{0x00,0x00,0xE0,0x41,0x10,0x52,0x08,0x74,0x08,0x24,0x08,0x54,0x10,0x0E,0xE0,0x03,0x00,0x00,0x00,0x00}, // 0xD0 -{0x00,0x01,0xF8,0x1F,0x08,0x11,0x08,0x11,0x08,0x10,0x08,0x10,0x10,0x08,0xE0,0x07,0x00,0x00,0x00,0x00}, // 0xD1 -{0x00,0x00,0xF8,0x1F,0x88,0x10,0x88,0x50,0x88,0x90,0x88,0x90,0x88,0x50,0x08,0x10,0x00,0x00,0x00,0x00}, // 0xD2 -{0x00,0x00,0xF8,0x1F,0x88,0x90,0x88,0x10,0x88,0x10,0x88,0x10,0x88,0x90,0x08,0x10,0x00,0x00,0x00,0x00}, // 0xD3 -{0x00,0x00,0xF8,0x1F,0x88,0x10,0x88,0x10,0x88,0x90,0x88,0x50,0x88,0x10,0x08,0x10,0x00,0x00,0x00,0x00}, // 0xD4 -{0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x04,0xF8,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xD5 -{0x00,0x00,0x08,0x10,0x08,0x10,0x08,0x10,0xF8,0x5F,0x08,0x90,0x08,0x10,0x08,0x10,0x00,0x00,0x00,0x00}, // 0xD6 -{0x00,0x00,0x08,0x10,0x08,0x10,0x08,0x50,0xF8,0x9F,0x08,0x90,0x08,0x50,0x08,0x10,0x00,0x00,0x00,0x00}, // 0xD7 -{0x00,0x00,0x08,0x10,0x08,0x90,0x08,0x10,0xF8,0x1F,0x08,0x10,0x08,0x90,0x08,0x10,0x00,0x00,0x00,0x00}, // 0xD8 -{0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xD9 -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00}, // 0xDA -{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, // 0xDB -{0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00}, // 0xDC -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xDD -{0x00,0x00,0x08,0x10,0x08,0x10,0x08,0x90,0xF8,0x5F,0x08,0x10,0x08,0x10,0x08,0x10,0x00,0x00,0x00,0x00}, // 0xDE -{0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF}, // 0xDF -{0x00,0x00,0xE0,0x07,0x10,0x08,0x08,0x10,0x08,0x50,0x08,0x90,0x08,0x10,0x10,0x08,0xE0,0x07,0x00,0x00}, // 0xE0 -{0x00,0x00,0xF8,0x3F,0x00,0x40,0x00,0x40,0x08,0x47,0x88,0x38,0x48,0x00,0x30,0x00,0x00,0x00,0x00,0x00}, // 0xE1 -{0x00,0x00,0xE0,0x07,0x10,0x08,0x08,0x50,0x08,0x90,0x08,0x90,0x08,0x50,0x10,0x08,0xE0,0x07,0x00,0x00}, // 0xE2 -{0x00,0x00,0xE0,0x07,0x10,0x08,0x08,0x90,0x08,0x50,0x08,0x10,0x08,0x10,0x10,0x08,0xE0,0x07,0x00,0x00}, // 0xE3 -{0x00,0x00,0xE0,0x01,0x10,0x22,0x08,0x44,0x08,0x24,0x08,0x24,0x10,0x42,0xE0,0x01,0x00,0x00,0x00,0x00}, // 0xE4 -{0x00,0x00,0xE0,0x07,0x10,0x48,0x08,0x90,0x08,0xD0,0x08,0x50,0x08,0x90,0x10,0x08,0xE0,0x07,0x00,0x00}, // 0xE5 -{0x00,0x00,0xFF,0x07,0x10,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x10,0x00,0xF8,0x07,0x00,0x00,0x00,0x00}, // 0xE6 -{0x00,0x00,0xFF,0x7F,0x10,0x02,0x08,0x04,0x08,0x04,0x08,0x04,0x10,0x06,0xE0,0x01,0x00,0x00,0x00,0x00}, // 0xE7 -{0x00,0x00,0xF8,0x1F,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x40,0x04,0x80,0x03,0x00,0x00,0x00,0x00}, // 0xE8 -{0x00,0x00,0xE0,0x1F,0x18,0x00,0x08,0x00,0x08,0x40,0x08,0x80,0x10,0x00,0xE0,0x1F,0x00,0x00,0x00,0x00}, // 0xE9 -{0x00,0x00,0xE0,0x1F,0x18,0x00,0x08,0x40,0x08,0x80,0x08,0x80,0x10,0x40,0xE0,0x1F,0x00,0x00,0x00,0x00}, // 0xEA -{0x00,0x00,0xE0,0x1F,0x18,0x00,0x08,0x80,0x08,0x40,0x08,0x00,0x10,0x00,0xE0,0x1F,0x00,0x00,0x00,0x00}, // 0xEB -{0x01,0x04,0x01,0x03,0xC1,0x00,0x62,0x00,0x1C,0x20,0x18,0x40,0x60,0x00,0x80,0x00,0x00,0x03,0x00,0x04}, // 0xEC -{0x00,0x10,0x00,0x08,0x00,0x06,0x00,0x01,0xF8,0x40,0x00,0x81,0x00,0x02,0x00,0x04,0x00,0x08,0x00,0x10}, // 0xED -{0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80}, // 0xEE -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xEF -{0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00,0x00,0x00,0x00}, // 0xF0 -{0x00,0x00,0x08,0x01,0x08,0x01,0x08,0x01,0x08,0x01,0xC8,0x07,0x08,0x01,0x08,0x01,0x08,0x01,0x00,0x00}, // 0xF1 -{0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00}, // 0xF2 -{0x08,0x42,0x10,0x52,0x20,0x5A,0xC0,0x6C,0x00,0x01,0x60,0x02,0xA0,0x0C,0x20,0x11,0xF8,0x21,0x20,0x40}, // 0xF3 -{0x00,0x00,0x00,0x38,0x00,0x7C,0x00,0x7E,0xFE,0x7F,0x00,0x40,0x00,0x40,0xFE,0x7F,0x00,0x00,0x00,0x00}, // 0xF4 -{0x00,0x00,0x00,0x00,0x86,0x3B,0xC2,0x4C,0x42,0x44,0x62,0x46,0x32,0x42,0xDC,0x41,0x00,0x00,0x00,0x00}, // 0xF5 -{0x00,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x58,0x06,0x58,0x06,0x40,0x00,0x40,0x00,0x40,0x00,0x00,0x00}, // 0xF6 -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x05,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xF7 -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x48,0x00,0x48,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xF8 -{0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xF9 -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xFA -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xFB -{0x00,0x00,0x00,0x00,0x00,0x42,0x00,0x52,0x00,0x52,0x00,0x52,0x00,0x6C,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xFC -{0x00,0x00,0x00,0x00,0x00,0x42,0x00,0x46,0x00,0x4A,0x00,0x4A,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00}, // 0xFD -{0x00,0x00,0xF8,0x07,0xF8,0x07,0xF8,0x07,0xF8,0x07,0xF8,0x07,0xF8,0x07,0xF8,0x07,0xF8,0x07,0x00,0x00}, // 0xFE -{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // 0xFF }; \ No newline at end of file diff --git a/zbs243_shared/soc/zbs243/uart.c b/zbs243_shared/soc/zbs243/uart.c index f02cb53e..49618145 100755 --- a/zbs243_shared/soc/zbs243/uart.c +++ b/zbs243_shared/soc/zbs243/uart.c @@ -2,42 +2,47 @@ #include "cpu.h" +#ifdef AP_FW #include "stdbool.h" -// #include "string.h" +#include "string.h" +#endif void uartInit(void) { // clock it up CLKEN |= 0x20; // configure baud rate UARTBRGH = 0x00; - +#ifdef AP_FW // UARTBRGL = 69; // nice. 230400 baud - // UARTBRGL = 70; // 79 == 200k - // UARTSTA = 0x12; // also set the "empty" bit else we wait forever for it to go up - UARTBRGL = 0x8A; // config for 115200 - UARTSTA = 0x10; // clear the register, don't trigger the interrupt just yet + //UARTBRGL = 70; // 79 == 200k IEN_UART0 = 1; + UARTBRGL = 0x8A; // config for 115200 +#else + UARTBRGL = 0x8A; // config for 115200 +#endif + UARTSTA = 0x12; // also set the "empty" bit else we wait forever for it to go up } +#ifndef AP_FW +void uartTx(uint8_t val) { + while (!(UARTSTA & (1 << 1))) + ; + UARTSTA &= ~(1 << 1); + UARTBUF = val; +} +#else + extern uint8_t __xdata blockbuffer[]; -volatile uint8_t __xdata txtail = 0; -volatile uint8_t __xdata txhead = 0; +volatile uint8_t txtail = 0; +volatile uint8_t txhead = 0; uint8_t __xdata txbuf[256] = {0}; volatile uint8_t __idata rxtail = 0; volatile uint8_t __idata rxhead = 0; uint8_t __xdata rxbuf[256] = {0}; -void UartTxWait() { - while (txhead != txtail) { - } -} - void uartTx(uint8_t val) { - while(txhead+1 == txtail){ - - } __critical { txbuf[txhead] = val; if (txhead == txtail) { @@ -62,8 +67,20 @@ uint8_t uartBytesAvail() { } uint8_t* __idata blockp; +uint8_t __idata cmd[3]; volatile bool __idata serialBypassActive = false; +void checkcommand(uint8_t rx) { + for (uint8_t c = 0; c < 2; c++) { + cmd[c] = cmd[c + 1]; + } + cmd[2] = rx; + if (strncmp(cmd, ">D>", 3) == 0) { + blockp = blockbuffer; + serialBypassActive = true; + } +} + void UART_IRQ1(void) __interrupt(0) { if (UARTSTA & 1) { // RXC UARTSTA &= 0xfe; @@ -76,6 +93,7 @@ void UART_IRQ1(void) __interrupt(0) { } else { rxbuf[rxhead] = UARTBUF; rxhead++; + // checkcommand(UARTBUF); } } if (UARTSTA & 2) { // TXC @@ -86,3 +104,4 @@ void UART_IRQ1(void) __interrupt(0) { } } } +#endif \ No newline at end of file diff --git a/zbs243_shared/soc/zbs243/uart.h b/zbs243_shared/soc/zbs243/uart.h index e699a73e..97385358 100644 --- a/zbs243_shared/soc/zbs243/uart.h +++ b/zbs243_shared/soc/zbs243/uart.h @@ -3,12 +3,17 @@ #include +//pre-configured for 115200 8n1 +//RX can be done but i do not need it + #pragma callee_saves uartInit void uartInit(void); #pragma callee_saves uartTx void uartTx(uint8_t val); + +#ifdef AP_FW void UART_IRQ1(void) __interrupt (0); #pragma callee_saves uartBytesAvail @@ -16,8 +21,6 @@ uint8_t uartBytesAvail(void); #pragma callee_saves uartRX uint8_t uartRx(); - -void UartTxWait(); - #endif +#endif \ No newline at end of file