mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 07:06:36 +01:00
M2 FW 2.2 - Preload and buttons
This commit is contained in:
BIN
binaries/Tag/SOLUM_154_SSD1619-tag-00-0022.bin
Normal file
BIN
binaries/Tag/SOLUM_154_SSD1619-tag-00-0022.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_29_SSD1619-tag-01-0022.bin
Normal file
BIN
binaries/Tag/SOLUM_29_SSD1619-tag-01-0022.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_29_UC8151-tag-11-0022.bin
Normal file
BIN
binaries/Tag/SOLUM_29_UC8151-tag-11-0022.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_42_SSD1619-tag-02-0022.bin
Normal file
BIN
binaries/Tag/SOLUM_42_SSD1619-tag-02-0022.bin
Normal file
Binary file not shown.
@@ -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
|
||||
#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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
0
zbs243_shared/eeprom.c
Normal file → Executable file
0
zbs243_shared/eeprom.c
Normal file → Executable file
49
zbs243_shared/eeprom.h
Normal file → Executable file
49
zbs243_shared/eeprom.h
Normal file → Executable file
@@ -4,10 +4,10 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user