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