diff --git a/binaries/Tag/SOLUM_154_SSD1619-tag-00-0022.bin b/binaries/Tag/SOLUM_154_SSD1619-tag-00-0022.bin new file mode 100644 index 00000000..aaf0edd5 Binary files /dev/null and b/binaries/Tag/SOLUM_154_SSD1619-tag-00-0022.bin differ diff --git a/binaries/Tag/SOLUM_29_SSD1619-tag-01-0022.bin b/binaries/Tag/SOLUM_29_SSD1619-tag-01-0022.bin new file mode 100644 index 00000000..9dea4e92 Binary files /dev/null and b/binaries/Tag/SOLUM_29_SSD1619-tag-01-0022.bin differ diff --git a/binaries/Tag/SOLUM_29_UC8151-tag-11-0022.bin b/binaries/Tag/SOLUM_29_UC8151-tag-11-0022.bin new file mode 100644 index 00000000..e8aee8e1 Binary files /dev/null and b/binaries/Tag/SOLUM_29_UC8151-tag-11-0022.bin differ diff --git a/binaries/Tag/SOLUM_42_SSD1619-tag-02-0022.bin b/binaries/Tag/SOLUM_42_SSD1619-tag-02-0022.bin new file mode 100644 index 00000000..bf69baac Binary files /dev/null and b/binaries/Tag/SOLUM_42_SSD1619-tag-02-0022.bin differ diff --git a/oepl-definitions.h b/oepl-definitions.h index 70ef8c0d..cbf0aa45 100755 --- a/oepl-definitions.h +++ b/oepl-definitions.h @@ -58,6 +58,11 @@ #define CMD_DO_DEEPSLEEP 3 #define CMD_DO_LEDFLASH 4 #define CMD_ERASE_EEPROM_IMAGES 5 +#define CMD_ENTER_SLIDESHOW_FAST 0x06 +#define CMD_ENTER_SLIDESHOW_MEDIUM 0x07 +#define CMD_ENTER_SLIDESHOW_SLOW 0x08 +#define CMD_ENTER_SLIDESHOW_GLACIAL 0x09 +#define CMD_ENTER_NORMAL_MODE 0x0F #define WAKEUP_REASON_TIMED 0 #define WAKEUP_REASON_GPIO 2 @@ -87,4 +92,10 @@ #define CUSTOM_IMAGE_BUTTON2 0x11 // UNUSED: 0x12 to 0x1C #define CUSTOM_IMAGE_GPIO 0x1D -#define CUSTOM_IMAGE_NFC_WAKE 0x1E \ No newline at end of file +#define CUSTOM_IMAGE_NFC_WAKE 0x1E + +#define TAG_CUSTOM_MODE_NONE 0x00 +#define TAG_CUSTOM_SLIDESHOW_FAST 0x06 +#define TAG_CUSTOM_SLIDESHOW_MEDIUM 0x07 +#define TAG_CUSTOM_SLIDESHOW_SLOW 0x08 +#define TAG_CUSTOM_SLIDESHOW_GLACIAL 0x09 \ No newline at end of file diff --git a/zbs243_Tag_FW/main.c b/zbs243_Tag_FW/main.c index c1a36f4c..92b21d4c 100755 --- a/zbs243_Tag_FW/main.c +++ b/zbs243_Tag_FW/main.c @@ -24,15 +24,23 @@ #include "../oepl-definitions.h" #include "../oepl-proto.h" - // #define DEBUG_MODE static const uint64_t __code __at(0x008b) mVersionRom = 0x1000011300000000ull; #define TAG_MODE_CHANSEARCH 0 #define TAG_MODE_ASSOCIATED 1 + +#define DELAY_SLIDESHOW_FAST 30 +#define DELAY_SLIDESHOW_MEDIUM 60 +#define DELAY_SLIDESHOW_SLOW 300 +#define DELAY_SLIDESHOW_GLACIAL 1800 + uint8_t currentTagMode = TAG_MODE_CHANSEARCH; +uint8_t __xdata slideShowCurrentImg = 0; +uint8_t __xdata slideShowRefreshCount = 1; + void displayLoop() { powerUp(INIT_BASE | INIT_UART); @@ -46,22 +54,6 @@ void displayLoop() { showApplyUpdate(); timerDelay(TIMER_TICKS_PER_SECOND * 4); - wdt60s(); - - pr("Scanning screen - "); - powerUp(INIT_EPD); - showScanningWindow(); - timerDelay(TIMER_TICKS_PER_SECOND * 8); - for (uint8_t i = 0; i < 5; i++) { - for (uint8_t c = 0; c < 16; c++) { - addScanResult(11 + c, 2 * i + 60 + c); - } - pr("redraw... "); - draw(); - } - pr("\n"); - timerDelay(TIMER_TICKS_PER_SECOND * 4); - wdt30s(); pr("AP Found\n"); @@ -99,43 +91,16 @@ void displayLoop() { wdtDeviceReset(); } -uint8_t showChannelSelect() { // returns 0 if no accesspoints were found - uint8_t __xdata result[sizeof(channelList)]; - memset(result, 0, sizeof(result)); - showScanningWindow(); - drawNoWait(); - powerUp(INIT_RADIO); - for (uint8_t i = 0; i < 4; i++) { - for (uint8_t c = 0; c < sizeof(channelList); c++) { - if (detectAP(channelList[c])) { - if (mLastLqi > result[c]) result[c] = mLastLqi; - pr("Channel: %d - LQI: %d RSSI %d\n", channelList[c], mLastLqi, mLastRSSI); - } - } - } - - uint8_t __xdata highestLqi = 0; - uint8_t __xdata highestSlot = 0; - for (uint8_t c = 0; c < sizeof(result); c++) { - if (result[c] > highestLqi) { - highestSlot = channelList[c]; - highestLqi = result[c]; - } - } - powerDown(INIT_RADIO); - epdWaitRdy(); - mLastLqi = highestLqi; - return highestSlot; -} -uint8_t channelSelect() { // returns 0 if no accesspoints were found +uint8_t channelSelect(uint8_t rounds) { // returns 0 if no accesspoints were found powerUp(INIT_RADIO); uint8_t __xdata result[16]; memset(result, 0, sizeof(result)); - for (uint8_t i = 0; i < 2; i++) { + for (uint8_t i = 0; i < rounds; i++) { for (uint8_t c = 0; c < sizeof(channelList); c++) { if (detectAP(channelList[c])) { if (mLastLqi > result[c]) result[c] = mLastLqi; + if (rounds > 2) pr("Channel: %d - LQI: %d RSSI %d\n", channelList[c], mLastLqi, mLastRSSI); } } } @@ -215,6 +180,7 @@ 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) { @@ -234,7 +200,8 @@ void TagAssociated() { if (curImgSlot != 0xFF) { powerUp(INIT_EEPROM | INIT_EPD); wdt60s(); - drawImageFromEeprom(curImgSlot); + uint8_t lut = getEepromImageDataArgument(curImgSlot) & 0x03; + drawImageFromEeprom(curImgSlot, lut); powerDown(INIT_EEPROM | INIT_EPD); } else { powerUp(INIT_EPD); @@ -247,6 +214,23 @@ void TagAssociated() { avail = getAvailDataInfo(); powerDown(INIT_RADIO); + switch (wakeUpReason) { + case WAKEUP_REASON_BUTTON1: + gpioButton1(); + fastNextCheckin = true; + break; + case WAKEUP_REASON_BUTTON2: + gpioButton2(); + fastNextCheckin = true; + break; +#ifdef ENABLE_GPIO_WAKE + case WAKEUP_REASON_GPIO: + gpioButtonOther(); + fastNextCheckin = true; + break; +#endif + } + if (avail != NULL) { // we got some data! longDataReqCounter = 0; @@ -254,14 +238,12 @@ void TagAssociated() { wakeUpReason = WAKEUP_REASON_TIMED; } if (tagSettings.enableTagRoaming) { - uint8_t roamChannel = channelSelect(); + uint8_t roamChannel = channelSelect(1); if (roamChannel) currentChannel = roamChannel; } } else { powerUp(INIT_RADIO); - - #ifdef ENABLE_RETURN_DATA // example code to send data back to the AP. Up to 90 bytes can be sent in one packet uint8_t __xdata blaat[2] = {0xAB, 0xBA}; @@ -304,11 +286,22 @@ void TagAssociated() { } } - // if the AP told us to sleep for a specific period, do so. - if (nextCheckInFromAP) { - doSleep(nextCheckInFromAP * 60000UL); + if (fastNextCheckin) { + // do a fast check-in next + fastNextCheckin = false; + doSleep(100UL); } else { - doSleep(getNextSleep() * 1000UL); + if (nextCheckInFromAP) { + // if the AP told us to sleep for a specific period, do so. + if (nextCheckInFromAP & 0x8000) { + doSleep((nextCheckInFromAP & 0x7FFF) * 1000UL); + } else { + doSleep(nextCheckInFromAP * 60000UL); + } + } else { + // sleep determined by algorithm + doSleep(getNextSleep() * 1000UL); + } } } @@ -319,7 +312,7 @@ void TagChanSearch() { } // try to find a working channel - currentChannel = channelSelect(); + currentChannel = channelSelect(2); // Check if we should redraw the screen with icons, info screen or screensaver if ((!currentChannel && !noAPShown && tagSettings.enableNoRFSymbol) || @@ -328,9 +321,12 @@ void TagChanSearch() { powerUp(INIT_EPD); wdt60s(); if (curImgSlot != 0xFF) { - powerUp(INIT_EEPROM); - drawImageFromEeprom(curImgSlot); - powerDown(INIT_EEPROM); + if (!displayCustomImage(CUSTOM_IMAGE_LOST_CONNECTION)) { + powerUp(INIT_EEPROM); + uint8_t lut = getEepromImageDataArgument(curImgSlot) & 0x03; + drawImageFromEeprom(curImgSlot, lut); + powerDown(INIT_EEPROM); + } } else if ((scanAttempts >= (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) { showLongTermSleep(); } else { @@ -354,6 +350,72 @@ void TagChanSearch() { } } +void TagSlideShow() { + currentChannel = 11; // suppress the no-rf image thing + displayCustomImage(CUSTOM_IMAGE_SPLASHSCREEN); + + // do a short channel search + currentChannel = channelSelect(2); + + pr("Slideshow mode ch: %d\n", currentChannel); + + // if we did find an AP, check in once + if (currentChannel) { + doVoltageReading(); + struct AvailDataInfo *__xdata avail; + powerUp(INIT_RADIO); + avail = getAvailDataInfo(); + + if (avail != NULL) { + processAvailDataInfo(avail); + } + } + powerDown(INIT_RADIO); + + // suppress the no-rf image + currentChannel = 11; + + while (1) { + powerUp(INIT_UART); + wdt60s(); + powerUp(INIT_EEPROM); + uint8_t img = findNextSlideshowImage(slideShowCurrentImg); + if (img != slideShowCurrentImg) { + slideShowCurrentImg = img; + uint8_t lut = getEepromImageDataArgument(img) & 0x03; + powerUp(INIT_EPD); + if (SLIDESHOW_FORCE_FULL_REFRESH_EVERY) { + slideShowRefreshCount++; + } + if ((slideShowRefreshCount == SLIDESHOW_FORCE_FULL_REFRESH_EVERY) || (lut == 0)) { + slideShowRefreshCount = 1; + lut = 0; + } + drawImageFromEeprom(img, lut); + powerDown(INIT_EPD | INIT_EEPROM); + } else { + // same image, so don't update the screen; this only happens when there's exactly one slideshow image + powerDown(INIT_EEPROM); + } + + switch (tagSettings.customMode) { + case TAG_CUSTOM_SLIDESHOW_FAST: + doSleep(1000UL * SLIDESHOW_INTERVAL_FAST); + break; + case TAG_CUSTOM_SLIDESHOW_MEDIUM: + doSleep(1000UL * SLIDESHOW_INTERVAL_MEDIUM); + break; + case TAG_CUSTOM_SLIDESHOW_SLOW: + doSleep(1000UL * SLIDESHOW_INTERVAL_SLOW); + break; + case TAG_CUSTOM_SLIDESHOW_GLACIAL: + doSleep(1000UL * SLIDESHOW_INTERVAL_GLACIAL); + break; + } + pr("wake...\n"); + } +} + void executeCommand(uint8_t cmd) { switch (cmd) { case CMD_DO_REBOOT: @@ -364,7 +426,7 @@ void executeCommand(uint8_t cmd) { writeSettings(); break; case CMD_DO_SCAN: - currentChannel = channelSelect(); + currentChannel = channelSelect(4); break; case CMD_DO_DEEPSLEEP: powerUp(INIT_EPD); @@ -374,6 +436,61 @@ void executeCommand(uint8_t cmd) { doSleep(-1); } break; + case CMD_ERASE_EEPROM_IMAGES: + powerUp(INIT_EEPROM); + eraseImageBlocks(); + powerDown(INIT_EEPROM); + break; + case CMD_ENTER_SLIDESHOW_FAST: + powerUp(INIT_EEPROM); + if (findSlotDataTypeArg(CUSTOM_IMAGE_SLIDESHOW << 3) == 0xFF) { + powerDown(INIT_EEPROM); + return; + } + powerDown(INIT_EEPROM); + tagSettings.customMode = TAG_CUSTOM_SLIDESHOW_FAST; + writeSettings(); + wdtDeviceReset(); + break; + case CMD_ENTER_SLIDESHOW_MEDIUM: + powerUp(INIT_EEPROM); + if (findSlotDataTypeArg(CUSTOM_IMAGE_SLIDESHOW << 3) == 0xFF) { + powerDown(INIT_EEPROM); + return; + } + powerDown(INIT_EEPROM); + tagSettings.customMode = TAG_CUSTOM_SLIDESHOW_MEDIUM; + writeSettings(); + wdtDeviceReset(); + break; + case CMD_ENTER_SLIDESHOW_SLOW: + powerUp(INIT_EEPROM); + if (findSlotDataTypeArg(CUSTOM_IMAGE_SLIDESHOW << 3) == 0xFF) { + powerDown(INIT_EEPROM); + return; + } + powerDown(INIT_EEPROM); + + tagSettings.customMode = TAG_CUSTOM_SLIDESHOW_SLOW; + writeSettings(); + wdtDeviceReset(); + break; + case CMD_ENTER_SLIDESHOW_GLACIAL: + powerUp(INIT_EEPROM); + if (findSlotDataTypeArg(CUSTOM_IMAGE_SLIDESHOW << 3) == 0xFF) { + powerDown(INIT_EEPROM); + return; + } + powerDown(INIT_EEPROM); + tagSettings.customMode = TAG_CUSTOM_SLIDESHOW_GLACIAL; + writeSettings(); + wdtDeviceReset(); + break; + case CMD_ENTER_NORMAL_MODE: + tagSettings.customMode = TAG_CUSTOM_MODE_NONE; + writeSettings(); + wdtDeviceReset(); + break; } } @@ -399,6 +516,17 @@ void main() { // get the highest slot number, number of slots initializeProto(); + switch (tagSettings.customMode) { + case TAG_CUSTOM_SLIDESHOW_FAST: + case TAG_CUSTOM_SLIDESHOW_MEDIUM: + case TAG_CUSTOM_SLIDESHOW_SLOW: + case TAG_CUSTOM_SLIDESHOW_GLACIAL: + TagSlideShow(); + break; + default: + break; + } + if (tagSettings.enableFastBoot) { // Fastboot pr("Doing fast boot\n"); @@ -406,7 +534,7 @@ void main() { if (tagSettings.fixedChannel) { currentChannel = tagSettings.fixedChannel; } else { - currentChannel = channelSelect(); + currentChannel = channelSelect(2); } } else { // Normal boot/startup @@ -426,9 +554,9 @@ void main() { detectButtonOrJig(); // show the splashscreen - pr("EPD: First powerup\n"); - powerUp(INIT_EPD); + currentChannel = 11; showSplashScreen(); + currentChannel = 0; // we've now displayed something on the screen; for the SSD1619, we are now aware of the lut-size #ifdef EPD_SSD1619 @@ -443,28 +571,25 @@ void main() { writeSettings(); // scan for channels - powerUp(INIT_EPD); wdt30s(); if (tagSettings.fixedChannel) { currentChannel = tagSettings.fixedChannel; } else { - currentChannel = showChannelSelect(); + currentChannel = channelSelect(4); } } - // end of the fastboot option split + wdt10s(); powerUp(INIT_EPD); if (currentChannel) { showAPFound(); initPowerSaving(INTERVAL_BASE); - powerDown(INIT_EPD | INIT_UART); currentTagMode = TAG_MODE_ASSOCIATED; doSleep(5000UL); } else { showNoAP(); initPowerSaving(INTERVAL_AT_MAX_ATTEMPTS); - powerDown(INIT_EPD | INIT_UART); currentTagMode = TAG_MODE_CHANSEARCH; doSleep(120000UL); } diff --git a/zbs243_Tag_FW/powermgt.c b/zbs243_Tag_FW/powermgt.c index d403eac9..077b16b7 100755 --- a/zbs243_Tag_FW/powermgt.c +++ b/zbs243_Tag_FW/powermgt.c @@ -292,16 +292,34 @@ void doSleep(const uint32_t __xdata t) { P1DIR |= (1 << 0); P1PULL |= (1 << 0); P1LVLSEL |= (1 << 0); - P1INTEN = (1 << 0); + P1INTEN |= (1 << 0); P1CHSTA &= ~(1 << 0); + + // Button setup on RXD pin 0.7 (input pullup) + P0FUNC &= ~(1 << 7); + P0DIR |= (1 << 7); + P0PULL |= (1 << 7); + P0LVLSEL |= (1 << 7); + P0INTEN |= (1 << 7); + P0CHSTA &= ~(1 << 7); } +#ifdef ENABLE_GPIO_WAKE + // enable wake on pin 0.2 (MISO) + P0FUNC &= ~(1 << 3); + P0DIR |= (1 << 3); + P0PULL |= (1 << 3); + P0LVLSEL |= (1 << 3); + P0INTEN |= (1 << 3); + P0CHSTA &= ~(1 << 3); +#endif + if (capabilities & CAPABILITY_NFC_WAKE) { P1FUNC &= ~(1 << 3); P1DIR |= (1 << 3); P1PULL |= (1 << 3); P1LVLSEL |= (1 << 3); - P1INTEN = (1 << 3); + P1INTEN |= (1 << 3); P1CHSTA &= ~(1 << 3); } @@ -313,15 +331,29 @@ void doSleep(const uint32_t __xdata t) { // sleepy time sleepForMsec(t); P1INTEN = 0; + P0INTEN = 0; if ((P1CHSTA & (1 << 0)) && (capabilities & CAPABILITY_HAS_WAKE_BUTTON)) { - wakeUpReason = WAKEUP_REASON_GPIO; + wakeUpReason = WAKEUP_REASON_BUTTON1; P1CHSTA &= ~(1 << 0); } + if ((P0CHSTA & (1 << 7)) && (capabilities & CAPABILITY_HAS_WAKE_BUTTON)) { + wakeUpReason = WAKEUP_REASON_BUTTON2; + P0CHSTA &= ~(1 << 7); + } + if ((P1CHSTA & (1 << 3)) && (capabilities & CAPABILITY_NFC_WAKE)) { wakeUpReason = WAKEUP_REASON_NFC; P1CHSTA &= ~(1 << 3); } + +#ifdef ENABLE_GPIO_WAKE + if (P0CHSTA & (1 << 3)) { + wakeUpReason = WAKEUP_REASON_GPIO; + P0CHSTA &= ~(1 << 3); + } +#endif + } void doVoltageReading() { diff --git a/zbs243_Tag_FW/powermgt.h b/zbs243_Tag_FW/powermgt.h index f93bc3a1..8ee8bc1b 100755 --- a/zbs243_Tag_FW/powermgt.h +++ b/zbs243_Tag_FW/powermgt.h @@ -40,6 +40,13 @@ #define INTERVAL_2_ATTEMPTS 12 // for 12 attempts (an additional day) #define INTERVAL_3_TIME 86400UL // Finally, try every day +// slideshow power settings +#define SLIDESHOW_FORCE_FULL_REFRESH_EVERY 16 // force a full refresh every X screen draws +#define SLIDESHOW_INTERVAL_FAST 15 // interval for 'fast' +#define SLIDESHOW_INTERVAL_MEDIUM 60 +#define SLIDESHOW_INTERVAL_SLOW 300 +#define SLIDESHOW_INTERVAL_GLACIAL 1800 + extern uint8_t checkButtonOrJig(); extern void setupPortsInitial(); diff --git a/zbs243_Tag_FW/settings.h b/zbs243_Tag_FW/settings.h index 3bd820fd..b058c8cb 100755 --- a/zbs243_Tag_FW/settings.h +++ b/zbs243_Tag_FW/settings.h @@ -3,11 +3,11 @@ #include -#define FW_VERSION 21 // version number (max 2.5.5 :) ) -#define FW_VERSION_SUFFIX "-RET" // suffix, like -RC1 or whatever. +#define FW_VERSION 22 // version number (max 2.5.5 :) ) +#define FW_VERSION_SUFFIX "-BUT" // 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_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 SETTINGS_STRUCT_VERSION 0x01 diff --git a/zbs243_Tag_FW/syncedproto.c b/zbs243_Tag_FW/syncedproto.c index 4efbb641..938c9c4c 100755 --- a/zbs243_Tag_FW/syncedproto.c +++ b/zbs243_Tag_FW/syncedproto.c @@ -28,17 +28,17 @@ // download-stuff uint8_t __xdata blockXferBuffer[BLOCK_XFER_BUFFER_SIZE] = {0}; -static struct blockRequest __xdata curBlock = {0}; // used by the block-requester, contains the next request that we'll send -static struct AvailDataInfo __xdata curDataInfo = {0}; // last 'AvailDataInfo' we received from the AP -static bool __xdata requestPartialBlock = false; // if we should ask the AP to get this block from the host or not +static struct blockRequest __xdata curBlock = {0}; // used by the block-requester, contains the next request that we'll send +static uint8_t __xdata curDispDataVer[8] = {0}; +static struct AvailDataInfo __xdata xferDataInfo = {0}; // holds the AvailDataInfo during the transfer +static bool __xdata requestPartialBlock = false; // if we should ask the AP to get this block from the host or not #define BLOCK_TRANSFER_ATTEMPTS 5 -uint8_t __xdata prevImgSlot = 0xFF; -uint8_t __xdata curImgSlot = 0xFF; -static uint32_t __xdata curHighSlotId = 0; -static uint8_t __xdata nextImgSlot = 0; +static uint8_t xferImgSlot = 0xFF; // holds current transfer slot in progress +uint8_t __xdata curImgSlot = 0xFF; // currently shown image +static uint32_t __xdata curHighSlotId = 0; // current highest ID, will be incremented before getting written to a new slot +static uint8_t __xdata nextImgSlot = 0; // next slot in sequence for writing static uint8_t __xdata imgSlots = 0; -uint8_t __xdata drawWithLut = 0; // stuff we need to keep track of related to the network/AP uint8_t __xdata APmac[8] = {0}; @@ -51,6 +51,9 @@ uint8_t __xdata currentChannel = 0; static uint8_t __xdata inBuffer[128] = {0}; static uint8_t __xdata outBuffer[128] = {0}; +// other stuff we shouldn't have to put here... +static uint32_t __xdata markerValid = EEPROM_IMG_VALID; + extern void executeCommand(uint8_t cmd); // this is defined in main.c // tools @@ -469,10 +472,9 @@ static void getNumSlots() { } else imgSlots = nSlots; } -static uint8_t findSlot(const uint8_t *__xdata ver) { +static uint8_t findSlotVer(const uint8_t *ver) { // 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 - uint32_t __xdata markerValid = EEPROM_IMG_VALID; - for (uint8_t __xdata c = 0; c < imgSlots; c++) { + for (uint8_t c = 0; c < imgSlots; c++) { struct EepromImageHeader __xdata *eih = (struct EepromImageHeader __xdata *)blockXferBuffer; eepromRead(getAddressForSlot(c), eih, sizeof(struct EepromImageHeader)); if (xMemEqual4(&eih->validMarker, &markerValid)) { @@ -483,6 +485,42 @@ static uint8_t findSlot(const uint8_t *__xdata ver) { } return 0xFF; } + +// making this reentrant saves one byte of idata... +uint8_t __xdata findSlotDataTypeArg(uint8_t arg) __reentrant { + arg &= (0xF8); // unmatch with the 'preload' bit and LUT bits + for (uint8_t c = 0; c < imgSlots; c++) { + struct EepromImageHeader __xdata *eih = (struct EepromImageHeader __xdata *)blockXferBuffer; + eepromRead(getAddressForSlot(c), eih, sizeof(struct EepromImageHeader)); + if (xMemEqual4(&eih->validMarker, &markerValid)) { + if ((eih->argument & 0xF8) == arg) { + return c; + } + } + } + return 0xFF; +} +uint8_t getEepromImageDataArgument(const uint8_t slot) { + struct EepromImageHeader __xdata *eih = (struct EepromImageHeader __xdata *)blockXferBuffer; + eepromRead(getAddressForSlot(slot), eih, sizeof(struct EepromImageHeader)); + return eih->argument; +} +uint8_t __xdata findNextSlideshowImage(uint8_t start) __reentrant { + struct EepromImageHeader __xdata *eih = (struct EepromImageHeader __xdata *)blockXferBuffer; + uint8_t c = start; + while (1) { + c++; + if (c > imgSlots) c = 0; + if (c == start) return c; + eepromRead(getAddressForSlot(c), eih, sizeof(struct EepromImageHeader)); + if (xMemEqual4(&eih->validMarker, &markerValid)) { + if ((eih->argument & 0xF8) == (CUSTOM_IMAGE_SLIDESHOW << 3)) { + return c; + } + } + } +} + static void eraseUpdateBlock() { eepromErase(EEPROM_UPDATA_AREA_START, EEPROM_UPDATE_AREA_LEN / EEPROM_ERZ_SECTOR_SZ); } @@ -500,13 +538,16 @@ static void saveImgBlockData(const uint8_t imgSlot, const uint8_t blockId) { if (!eepromWrite(getAddressForSlot(imgSlot) + sizeof(struct EepromImageHeader) + (blockId * BLOCK_DATA_SIZE), blockXferBuffer + sizeof(struct blockData), length)) pr("EEPROM write failed\n"); } -void drawImageFromEeprom(const uint8_t imgSlot) { - drawImageAtAddress(getAddressForSlot(imgSlot), drawWithLut); - drawWithLut = 0; // default back to the regular ol' stock/OTP LUT +void eraseImageBlocks() { + for (uint8_t c = 0; c < imgSlots; c++) { + eraseImageBlock(c); + } +} +void drawImageFromEeprom(const uint8_t imgSlot, uint8_t lut) { + drawImageAtAddress(getAddressForSlot(imgSlot), lut); } static uint32_t getHighSlotId() { uint32_t temp = 0; - uint32_t __xdata markerValid = EEPROM_IMG_VALID; for (uint8_t __xdata c = 0; c < imgSlots; c++) { struct EepromImageHeader __xdata *eih = (struct EepromImageHeader __xdata *)blockXferBuffer; eepromRead(getAddressForSlot(c), eih, sizeof(struct EepromImageHeader)); @@ -625,25 +666,25 @@ static bool getDataBlock(const uint16_t blockSize) { uint16_t __xdata dataRequestSize = 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) & curDataInfo.dataVer, 8) && curDataInfo.dataSize) { + 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 { // 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(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); + xMemCopyShort(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); eraseUpdateBlock(); } - while (curDataInfo.dataSize) { + while (xferDataInfo.dataSize) { wdt10s(); - if (curDataInfo.dataSize > BLOCK_DATA_SIZE) { + if (xferDataInfo.dataSize > BLOCK_DATA_SIZE) { // more than one block remaining dataRequestSize = BLOCK_DATA_SIZE; } else { // only one block remains - dataRequestSize = curDataInfo.dataSize; + dataRequestSize = xferDataInfo.dataSize; } if (getDataBlock(dataRequestSize)) { // succesfully downloaded datablock, save to eeprom @@ -651,7 +692,7 @@ static bool downloadFWUpdate(const struct AvailDataInfo *__xdata avail) { saveUpdateBlockData(curBlock.blockId); powerDown(INIT_EEPROM); curBlock.blockId++; - curDataInfo.dataSize -= dataRequestSize; + xferDataInfo.dataSize -= dataRequestSize; } else { // failed to get the block we wanted, we'll stop for now, maybe resume later return false; @@ -664,21 +705,42 @@ static bool downloadFWUpdate(const struct AvailDataInfo *__xdata avail) { 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 - if (xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & curDataInfo.dataVer, 8) && curDataInfo.dataSize) { + 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. pr("restarting image download"); - curImgSlot = nextImgSlot; } else { - // go to the next image slot - nextImgSlot++; - if (nextImgSlot >= imgSlots) nextImgSlot = 0; - curImgSlot = nextImgSlot; - pr("Saving to image slot %d\n", curImgSlot); - drawWithLut = avail->dataTypeArgument; + // new transfer powerUp(INIT_EEPROM); + // go to the next image slot + uint8_t startingSlot = nextImgSlot; + while (1) { + nextImgSlot++; + if (nextImgSlot >= imgSlots) nextImgSlot = 0; + if (nextImgSlot == startingSlot) { + powerDown(INIT_EEPROM); + pr("No slots available. Too many images in the slideshow?\n"); + return true; + } + struct EepromImageHeader __xdata *eih = (struct EepromImageHeader __xdata *)blockXferBuffer; + eepromRead(getAddressForSlot(nextImgSlot), eih, sizeof(struct EepromImageHeader)); + // check if the marker is indeed valid + if (xMemEqual4(&eih->validMarker, &markerValid)) { + struct imageDataTypeArgStruct *eepromDataArgument = (struct imageDataTypeArgStruct *)&(eih->argument); + // normal type, we can overwrite this + if (eepromDataArgument->specialType == 0x00) break; + } else { + // bullshit marker, so safe to overwrite + break; + } + } + + xferImgSlot = nextImgSlot; + uint8_t __xdata attempt = 5; while (attempt--) { - if (eepromErase(getAddressForSlot(curImgSlot), EEPROM_IMG_EACH / EEPROM_ERZ_SECTOR_SZ)) goto eraseSuccess; + if (eepromErase(getAddressForSlot(xferImgSlot), EEPROM_IMG_EACH / EEPROM_ERZ_SECTOR_SZ)) goto eraseSuccess; } eepromFail: powerDown(INIT_RADIO); @@ -688,35 +750,36 @@ static bool downloadImageDataToEEPROM(const struct AvailDataInfo *__xdata avail) doSleep(-1); wdtDeviceReset(); eraseSuccess: - pr("new download, writing to slot %d\n", curImgSlot); + powerDown(INIT_EEPROM); + pr("new download, writing to slot %d\n", xferImgSlot); // 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)); curBlock.type = avail->dataType; - xMemCopyShort(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); - imageSize = curDataInfo.dataSize; + xMemCopyShort(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); + imageSize = xferDataInfo.dataSize; } - while (curDataInfo.dataSize) { + while (xferDataInfo.dataSize) { wdt10s(); - if (curDataInfo.dataSize > BLOCK_DATA_SIZE) { + if (xferDataInfo.dataSize > BLOCK_DATA_SIZE) { // more than one block remaining dataRequestSize = BLOCK_DATA_SIZE; } else { // only one block remains - dataRequestSize = curDataInfo.dataSize; + dataRequestSize = xferDataInfo.dataSize; } if (getDataBlock(dataRequestSize)) { // succesfully downloaded datablock, save to eeprom powerUp(INIT_EEPROM); #ifdef DEBUGBLOCKS - pr("Saving block %d to slot %d\n", curBlock.blockId, curImgSlot); + pr("Saving block %d to slot %d\n", curBlock.blockId, xferImgSlot); #endif - saveImgBlockData(curImgSlot, curBlock.blockId); + saveImgBlockData(xferImgSlot, curBlock.blockId); powerDown(INIT_EEPROM); curBlock.blockId++; - curDataInfo.dataSize -= dataRequestSize; + xferDataInfo.dataSize -= dataRequestSize; } else { // failed to get the block we wanted, we'll stop for now, probably resume later return false; @@ -726,111 +789,138 @@ static bool downloadImageDataToEEPROM(const struct AvailDataInfo *__xdata avail) // borrow the blockXferBuffer temporarily struct EepromImageHeader __xdata *eih = (struct EepromImageHeader __xdata *)blockXferBuffer; - xMemCopy8(&eih->version, &curDataInfo.dataVer); + xMemCopy8(&eih->version, &xferDataInfo.dataVer); eih->validMarker = EEPROM_IMG_VALID; eih->id = ++curHighSlotId; eih->size = imageSize; - eih->dataType = curDataInfo.dataType; + eih->dataType = xferDataInfo.dataType; + eih->argument = xferDataInfo.dataTypeArgument; #ifdef DEBUGBLOCKS - pr("Now writing datatype 0x%02X to slot %d\n", curDataInfo.dataType, curImgSlot); + pr("Now writing datatype 0x%02X to slot %d\n", xferDataInfo.dataType, xferImgSlot); #endif powerUp(INIT_EEPROM); - eepromWrite(getAddressForSlot(curImgSlot), eih, sizeof(struct EepromImageHeader)); + eepromWrite(getAddressForSlot(xferImgSlot), eih, sizeof(struct EepromImageHeader)); powerDown(INIT_EEPROM); return true; } -bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { - switch (avail->dataType) { -#if (SCREEN_WIDTH == 152) - // the 1.54" screen is pretty small, we can write an entire 1bpp image from the block transfer buffer directly to the EPD buffer - case DATATYPE_IMG_RAW_1BPP_DIRECT: - pr("Direct draw image received\n"); - if (curDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & curDataInfo.dataVer, 8)) { - // we've downloaded this already, we're guessing it's already displayed - pr("currently shown image, send xfc\n"); - powerUp(INIT_RADIO); - sendXferComplete(); - powerDown(INIT_RADIO); - return true; - } - xMemCopyShort(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); - if (avail->dataSize > 4096) avail->dataSize = 4096; +inline bool processImageDataAvail(struct AvailDataInfo *__xdata avail) { + struct imageDataTypeArgStruct arg; + *((uint8_t *)arg) = avail->dataTypeArgument; - if (getDataBlock(avail->dataSize)) { - powerUp(INIT_RADIO); - sendXferComplete(); - powerDown(INIT_RADIO); + if (arg.preloadImage) { + pr("Preloading image with type 0x%02X from arg 0x%02X\n", arg.specialType, avail->dataTypeArgument); + 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 + default: { + uint8_t slot = findSlotDataTypeArg(avail->dataTypeArgument); + if (slot != 0xFF) { + eepromErase(getAddressForSlot(slot), EEPROM_IMG_EACH / EEPROM_ERZ_SECTOR_SZ); + } + } break; + // regular image preload, there can be multiple of this type in the EEPROM + case CUSTOM_IMAGE_NOCUSTOM: { + // check if a version of this already exists + uint8_t slot = findSlotVer(&(avail->dataVer)); + if (slot != 0xFF) { + powerUp(INIT_RADIO); + sendXferComplete(); + powerDown(INIT_RADIO); + return true; + } + } break; + case CUSTOM_IMAGE_SLIDESHOW: + break; + } + powerDown(INIT_EEPROM); - curDataInfo.dataSize = 0; // mark as transfer not pending - powerUp(INIT_EPD); - drawImageFromBuffer(blockXferBuffer, drawWithLut); - powerDown(INIT_EPD); - drawWithLut = 0; // default back to the regular ol' stock/OTP LUT - return true; - } + pr("downloading preload image...\n"); + if (downloadImageDataToEEPROM(avail)) { + // sets xferImgSlot to the right slot + pr("preload complete!\n"); + powerUp(INIT_RADIO); + sendXferComplete(); + powerDown(INIT_RADIO); + return true; + } else { return false; - break; -#endif - case DATATYPE_IMG_BMP: - case DATATYPE_IMG_DIFF: - case DATATYPE_IMG_RAW_1BPP: - case DATATYPE_IMG_RAW_2BPP: - // check if this download is currently displayed or active - if (curDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & curDataInfo.dataVer, 8)) { - // we've downloaded this already, we're guessing it's already displayed - pr("currently shown image, send xfc\n"); - powerUp(INIT_RADIO); - sendXferComplete(); - powerDown(INIT_RADIO); - return true; - } + } - // check if we've seen this version before + } else { + // 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 + + pr("currently shown image, send xfc\n"); + powerUp(INIT_RADIO); + sendXferComplete(); + powerDown(INIT_RADIO); + return true; + + } else { + // currently not displayed + + // try to find the data in the SPI EEPROM powerUp(INIT_EEPROM); - curImgSlot = findSlot(&(avail->dataVer)); + uint8_t findImgSlot = findSlotVer(&(avail->dataVer)); powerDown(INIT_EEPROM); - if (curImgSlot != 0xFF) { + + // Is this image already in a slot somewhere + if (findImgSlot != 0xFF) { // found a (complete)valid image slot for this version powerUp(INIT_RADIO); sendXferComplete(); powerDown(INIT_RADIO); - pr("already seen, drawing from eeprom slot %d\n", curImgSlot); - // mark as completed and draw from EEPROM - xMemCopyShort(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); - curDataInfo.dataSize = 0; // mark as transfer not pending + xMemCopyShort(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); + xferDataInfo.dataSize = 0; // mark as transfer not pending - drawWithLut = avail->dataTypeArgument; wdt60s(); + curImgSlot = findImgSlot; powerUp(INIT_EPD | INIT_EEPROM); - drawImageFromEeprom(curImgSlot); + drawImageFromEeprom(findImgSlot, arg.lut); powerDown(INIT_EPD | INIT_EEPROM); - return true; + } else { // not found in cache, prepare to download - pr("downloading to imgslot\n"); - drawWithLut = avail->dataTypeArgument; - powerUp(INIT_EEPROM); + pr("downloading image...\n"); if (downloadImageDataToEEPROM(avail)) { + // sets xferImgSlot to the right slot pr("download complete!\n"); powerUp(INIT_RADIO); sendXferComplete(); powerDown(INIT_RADIO); + // not preload, draw now wdt60s(); + curImgSlot = xferImgSlot; powerUp(INIT_EPD | INIT_EEPROM); - drawImageFromEeprom(curImgSlot); + drawImageFromEeprom(xferImgSlot, arg.lut); powerDown(INIT_EPD | INIT_EEPROM); - return true; + } else { - powerDown(INIT_EEPROM); return false; } } + + // keep track on what is currently displayed + xMemCopy8(curDispDataVer, xferDataInfo.dataVer); + return true; + } + } +} + +bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { + switch (avail->dataType) { + case DATATYPE_IMG_BMP: + case DATATYPE_IMG_DIFF: + case DATATYPE_IMG_RAW_1BPP: + case DATATYPE_IMG_RAW_2BPP: + return processImageDataAvail(avail); break; case DATATYPE_FW_UPDATE: powerUp(INIT_EEPROM); @@ -866,6 +956,7 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { } pr("NFC URL received\n"); + /* if (curDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & curDataInfo.dataVer, 8)) { // we've already downloaded this NFC data, disregard and send XFC pr("this was the same as the last transfer, disregard\n"); @@ -899,8 +990,9 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { } return false; break; + */ case DATATYPE_TAG_CONFIG_DATA: - if (curDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & curDataInfo.dataVer, 8)) { + if (xferDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & xferDataInfo.dataVer, 8)) { pr("this was the same as the last transfer, disregard\n"); powerUp(INIT_RADIO); sendXferComplete(); @@ -910,10 +1002,10 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { curBlock.blockId = 0; xMemCopy8(&(curBlock.ver), &(avail->dataVer)); curBlock.type = avail->dataType; - xMemCopyShort(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); + xMemCopyShort(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); wdt10s(); if (getDataBlock(avail->dataSize)) { - curDataInfo.dataSize = 0; // mark as transfer not pending + xferDataInfo.dataSize = 0; // mark as transfer not pending loadSettingsFromBuffer(sizeof(struct blockData) + blockXferBuffer); powerUp(INIT_RADIO); sendXferComplete(); @@ -943,7 +1035,7 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { } #ifdef EPD_SSD1619 pr("OTA LUT received\n"); - if (curDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & curDataInfo.dataVer, 8)) { + if (xferDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & xferDataInfo.dataVer, 8)) { pr("this was the same as the last transfer, disregard\n"); powerUp(INIT_RADIO); sendXferComplete(); @@ -953,10 +1045,10 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { curBlock.blockId = 0; xMemCopy8(&(curBlock.ver), &(avail->dataVer)); curBlock.type = avail->dataType; - xMemCopyShort(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); + xMemCopyShort(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); wdt10s(); if (getDataBlock(avail->dataSize)) { - curDataInfo.dataSize = 0; // mark as transfer not pending + xferDataInfo.dataSize = 0; // mark as transfer not pending memcpy(customLUT, sizeof(struct blockData) + blockXferBuffer, 6 + (dispLutSize * 10)); powerUp(INIT_RADIO); sendXferComplete(); diff --git a/zbs243_Tag_FW/syncedproto.h b/zbs243_Tag_FW/syncedproto.h index 5f6287b7..3a01a5b8 100755 --- a/zbs243_Tag_FW/syncedproto.h +++ b/zbs243_Tag_FW/syncedproto.h @@ -10,8 +10,8 @@ extern uint8_t __xdata APmac[]; extern uint8_t __xdata curImgSlot; -extern void setupRadio(void); -extern void killRadio(void); +//extern void setupRadio(void); +//extern void killRadio(void); #ifdef ENABLE_RETURN_DATA @@ -19,9 +19,14 @@ extern bool sendTagReturnData(uint8_t __xdata *data, uint8_t len, uint8_t type); #endif void dump(const uint8_t *__xdata a, const uint16_t __xdata l); + +extern uint8_t __xdata findSlotDataTypeArg(uint8_t arg) __reentrant; +uint8_t __xdata findNextSlideshowImage(uint8_t start) __reentrant; +uint8_t getEepromImageDataArgument(const uint8_t slot); extern struct AvailDataInfo *__xdata getAvailDataInfo(); extern struct AvailDataInfo *__xdata getShortAvailDataInfo(); -extern void drawImageFromEeprom(const uint8_t imgSlot); +extern void drawImageFromEeprom(const uint8_t imgSlot, uint8_t lut); +void eraseImageBlocks(); extern bool processAvailDataInfo(struct AvailDataInfo *__xdata avail); extern void initializeProto(); extern uint8_t detectAP(const uint8_t channel); diff --git a/zbs243_Tag_FW/userinterface.c b/zbs243_Tag_FW/userinterface.c index 912ff923..47cdb2cc 100755 --- a/zbs243_Tag_FW/userinterface.c +++ b/zbs243_Tag_FW/userinterface.c @@ -52,7 +52,7 @@ void addCapabilities() { } void addOverlay() { - if ((currentChannel == 0)&&(tagSettings.enableNoRFSymbol)) { + if ((currentChannel == 0) && (tagSettings.enableNoRFSymbol)) { #if (SCREEN_WIDTH == 152) loadRawBitmap(ant, SCREEN_WIDTH - 16, 0, EPD_COLOR_BLACK); loadRawBitmap(cross, SCREEN_WIDTH - 8, 7, EPD_COLOR_RED); @@ -83,6 +83,7 @@ void addOverlay() { } void afterFlashScreenSaver() { + if (displayCustomImage(CUSTOM_IMAGE_LONGTERMSLEEP)) return; selectLUT(EPD_LUT_DEFAULT); clearScreen(); setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT); @@ -92,7 +93,6 @@ void afterFlashScreenSaver() { epdpr("OpenEPaperLink"); epdPrintEnd(); - epdPrintBegin(100, 32, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_RED); epdpr("v%d.%d.%d", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10)); epdPrintEnd(); @@ -172,7 +172,7 @@ void afterFlashScreenSaver() { epdpr("v%d.%d.%d", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10)); epdPrintEnd(); - epdPrintBegin(10, 48, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK); + epdPrintBegin(10, 48, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK); epdpr("I'm fast asleep... UwU To wake me:"); epdPrintEnd(); @@ -201,6 +201,8 @@ void afterFlashScreenSaver() { } void showSplashScreen() { + if (displayCustomImage(CUSTOM_IMAGE_SPLASHSCREEN)) return; + powerUp(INIT_EPD); selectLUT(EPD_LUT_NO_REPEATS); clearScreen(); setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT); @@ -298,6 +300,7 @@ void showSplashScreen() { #endif drawWithSleep(); + powerUp(INIT_EPD); } void showApplyUpdate() { @@ -322,60 +325,10 @@ void showApplyUpdate() { drawNoWait(); } -uint8_t __xdata resultcounter = 0; - -void showScanningWindow() { - setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT); - selectLUT(EPD_LUT_FAST_NO_REDS); - clearScreen(); -#if (SCREEN_WIDTH == 128) // 2.9" - epdPrintBegin(2, 275, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK); - epdpr("Scanning for APs"); - epdPrintEnd(); - // epdPrintBegin(40, 262, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_RED); - // epdpr("Channel - Quality"); - // epdPrintEnd(); - loadRawBitmap(receive, 36, 24, EPD_COLOR_BLACK); -#endif -#if (SCREEN_WIDTH == 152) // 1.54" - loadRawBitmap(receive, 96, 28, EPD_COLOR_BLACK); - epdPrintBegin(3, 0, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK); - epdpr("Scanning..."); - epdPrintEnd(); -#endif -#if (SCREEN_WIDTH == 400) // 4.2" - epdPrintBegin(2, 2, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK); - epdpr("Scanning for APs"); - epdPrintEnd(); - - // epdPrintBegin(2, 40, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_RED); - // epdpr("Channel - Quality"); - // epdPrintEnd(); - loadRawBitmap(receive, 320, 125, EPD_COLOR_BLACK); -#endif - - draw(); - selectLUT(EPD_LUT_FAST); - resultcounter = 0; -} - -void addScanResult(uint8_t channel, uint8_t lqi) { - if (channel == 11) resultcounter = 0; -#if (SCREEN_WIDTH == 128) // 2.9" - epdPrintBegin(56 + ((resultcounter % 4) * 16), 282 - (47 * (resultcounter / 4)), EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK); -#endif -#if (SCREEN_WIDTH == 152) // 1.54" - epdPrintBegin(4 + (47 * (resultcounter / 8)), 31 + (15 * (resultcounter % 8)), EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK); -#endif -#if (SCREEN_WIDTH == 400) // 4.2" - epdPrintBegin(4 + (47 * (resultcounter / 8)), 58 + (15 * (resultcounter % 8)), EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK); -#endif - epdpr("%d-%d", channel, lqi); - epdPrintEnd(); - resultcounter++; -} - void showAPFound() { + if (displayCustomImage(CUSTOM_IMAGE_APFOUND)) return; + powerUp(INIT_EPD | INIT_EEPROM); + clearScreen(); setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT); selectLUT(1); @@ -479,9 +432,14 @@ void showAPFound() { #endif addOverlay(); drawWithSleep(); + powerDown(INIT_EPD | INIT_EEPROM); + } void showNoAP() { + if (displayCustomImage(CUSTOM_IMAGE_NOAPFOUND)) return; + powerUp(INIT_EPD | INIT_EEPROM); + selectLUT(EPD_LUT_NO_REPEATS); setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT); clearScreen(); @@ -525,9 +483,11 @@ void showNoAP() { #endif addOverlay(); drawWithSleep(); + powerDown(INIT_EPD | INIT_EEPROM); } void showLongTermSleep() { + if (displayCustomImage(CUSTOM_IMAGE_LONGTERMSLEEP)) return; selectLUT(EPD_LUT_NO_REPEATS); setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT); clearScreen(); @@ -616,4 +576,71 @@ void showNoMAC() { epdPrintEnd(); #endif drawWithSleep(); -} \ No newline at end of file +} + +bool displayCustomImage(uint8_t imagetype) { + powerUp(INIT_EEPROM); + uint8_t slot = findSlotDataTypeArg(imagetype << 3); + if (slot != 0xFF) { + // found a slot for gpio button 1 + + uint8_t lut = getEepromImageDataArgument(slot); + lut &= 0x03; + powerUp(INIT_EPD); + drawImageFromEeprom(slot, lut); + powerDown(INIT_EPD | INIT_EEPROM); + return true; + } else { + powerDown(INIT_EEPROM); + } + return false; +} + +void gpioButton1() { + if (displayCustomImage(CUSTOM_IMAGE_BUTTON1)) { + sleepForMsec(2000); + + // if something else was previously on the display, draw that + if (curImgSlot != 0xFF) { + powerUp(INIT_EEPROM); + uint8_t lut = getEepromImageDataArgument(curImgSlot); + lut &= 0x03; + powerUp(INIT_EPD); + drawImageFromEeprom(curImgSlot, lut); + powerDown(INIT_EPD | INIT_EEPROM); + } + } +} + +void gpioButton2() { + if (displayCustomImage(CUSTOM_IMAGE_BUTTON1)) { + sleepForMsec(2000); + + // if something else was previously on the display, draw that + if (curImgSlot != 0xFF) { + powerUp(INIT_EEPROM); + uint8_t lut = getEepromImageDataArgument(curImgSlot); + lut &= 0x03; + powerUp(INIT_EPD); + drawImageFromEeprom(curImgSlot, lut); + powerDown(INIT_EPD | INIT_EEPROM); + } + } +} + +#ifdef ENABLE_GPIO_WAKE +void gpioButtonOther() { + if (displayCustomImage(CUSTOM_IMAGE_GPIO)) { + sleepForMsec(2000); + // if something else was previously on the display, draw that + if (curImgSlot != 0xFF) { + powerUp(INIT_EEPROM); + uint8_t lut = getEepromImageDataArgument(curImgSlot); + lut &= 0x03; + powerUp(INIT_EPD); + drawImageFromEeprom(curImgSlot, lut); + powerDown(INIT_EPD | INIT_EEPROM); + } + } +} +#endif diff --git a/zbs243_Tag_FW/userinterface.h b/zbs243_Tag_FW/userinterface.h index e3bc33b6..f923b0b5 100755 --- a/zbs243_Tag_FW/userinterface.h +++ b/zbs243_Tag_FW/userinterface.h @@ -4,17 +4,22 @@ void addOverlay(); +bool displayCustomImage(uint8_t imagetype); + void afterFlashScreenSaver(); void showSplashScreen(); void showApplyUpdate(); -void showScanningWindow(); -void addScanResult(uint8_t channel, uint8_t lqi); void showAPFound(); void showNoAP(); void showLongTermSleep(); void showNoEEPROM(); void showNoMAC(); + +void gpioButton1(); +void gpioButton2(); +void gpioButtonOther(); + extern const uint16_t __code fwVersion; extern const char __code fwVersionSuffix[]; extern bool __xdata lowBatteryShown; diff --git a/zbs243_shared/eeprom.c b/zbs243_shared/eeprom.c old mode 100644 new mode 100755 diff --git a/zbs243_shared/eeprom.h b/zbs243_shared/eeprom.h old mode 100644 new mode 100755 index 59f36984..476f5b5e --- a/zbs243_shared/eeprom.h +++ b/zbs243_shared/eeprom.h @@ -4,10 +4,10 @@ #include #include -#define EEPROM_WRITE_PAGE_SZ 256 //max write size & alignment -#define EEPROM_ERZ_SECTOR_SZ 4096 //erase size and alignment +#define EEPROM_WRITE_PAGE_SZ 256 // max write size & alignment +#define EEPROM_ERZ_SECTOR_SZ 4096 // erase size and alignment -//device has 256 sectors, so eepromErase() cannot erase thw whole device...i can live with that +// device has 256 sectors, so eepromErase() cannot erase thw whole device...i can live with that __bit eepromInit(void); void eepromOtpModeEnter(void); @@ -27,25 +27,40 @@ void eepromDeepPowerDown(void); #pragma callee_saves eepromGetSize uint32_t eepromGetSize(void); -//this is for firmware update use -void eepromReadStart(uint32_t addr) __reentrant; +// this is for firmware update use +void eepromReadStart(uint32_t addr) __reentrant; + +// structures +#define EEPROM_IMG_INPROGRESS (0x7fffffffUL) +//#define EEPROM_IMG_VALID (0x494d4721UL) +#define EEPROM_IMG_VALID (0x474d4721UL) -//structures -#define EEPROM_IMG_INPROGRESS (0x7fffffffUL) -#define EEPROM_IMG_VALID (0x494d4721UL) #include "board.h" -struct EepromImageHeader { //each image space is 0x17000 bytes, we have space for ten of them - uint64_t version; - uint32_t validMarker; - uint32_t size; - uint8_t dataType; - uint32_t id; - - //image data here - //we pre-erase so progress can be calculated by finding the first non-0xff byte +struct EepromImageHeader { // each image space is 0x17000 bytes, we have space for ten of them + uint64_t version; + uint32_t validMarker; + uint32_t size; + uint8_t dataType; + uint32_t id; + uint8_t argument; + // image data here + // we pre-erase so progress can be calculated by finding the first non-0xff byte }; +#define CUSTOM_IMAGE_NOCUSTOM 0x00 // regular image type +#define CUSTOM_IMAGE_SPLASHSCREEN 0x01 // will show at first boot/powerup +#define CUSTOM_IMAGE_LOST_CONNECTION 0x02 // this image will be shown (if it exists on the tag) if the tag looses its connection +#define CUSTOM_IMAGE_APFOUND 0x03 // this image will be shown during bootup if an AP was found +#define CUSTOM_IMAGE_NOAPFOUND 0x04 // shown if during bootup no AP was found +// UNUSED: 0x05-0x0F +#define CUSTOM_IMAGE_SLIDESHOW 0x0F // image is part of a slideshow +#define CUSTOM_IMAGE_BUTTON1 0x10 +#define CUSTOM_IMAGE_BUTTON2 0x11 +// UNUSED: 0x12 to 0x1C +#define CUSTOM_IMAGE_GPIO 0x1D +#define CUSTOM_IMAGE_NFC_WAKE 0x1E + #endif