mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-24 11:07:08 +01:00
Merge branch 'master' into development
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
BUILD ?= zbs29v033
|
||||
|
||||
#file containing main() must be first!
|
||||
SOURCES += main.c eeprom.c
|
||||
SOURCES += main.c
|
||||
SOURCES += comms.c
|
||||
|
||||
|
||||
|
||||
@@ -64,102 +64,4 @@ void boardInitStage2(void)
|
||||
__bit boardGetOwnMac(uint8_t __xdata *mac)
|
||||
{
|
||||
return flashRead(FLASH_INFOPAGE_ADDR + 0x10, mac, 8);
|
||||
}
|
||||
|
||||
#pragma callee_saves prvUpdateApplierGet
|
||||
static uint32_t prvUpdateApplierGet(void) __naked
|
||||
{
|
||||
__asm__(
|
||||
" mov DPTR, #00098$ \n"
|
||||
" mov A, #00099$ \n"
|
||||
" clr C \n"
|
||||
" subb A, DPL \n"
|
||||
" mov B, A \n"
|
||||
" ret \n"
|
||||
|
||||
///actual updater code
|
||||
"00098$: \n"
|
||||
|
||||
|
||||
//copied to last page of flash for updating, called with ints off and eeprom ready to read update
|
||||
//flashes 63 flash pages, uses xram for buffer. uses combined erase+flash flash op
|
||||
|
||||
" mov _CLKSPEED, #0x21 \n"
|
||||
" mov _CFGPAGE, #0x04 \n"
|
||||
" mov R0, #0 \n"
|
||||
|
||||
"00001$: \n"
|
||||
|
||||
//read a page of update
|
||||
" mov DPTR, #0xe000 \n"
|
||||
" mov R1, #0x04 \n"
|
||||
" mov R2, #0x00 \n"
|
||||
"000010$: \n"
|
||||
" mov _SPITX, #0x00 \n"
|
||||
" mov _SPICFG, #0xa0 \n"
|
||||
"000011$: \n"
|
||||
" mov A, _SPICFG \n"
|
||||
" jb A.5, 000011$ \n"
|
||||
" mov A, _SPIRX \n"
|
||||
" movx @DPTR, A \n"
|
||||
" inc DPTR \n"
|
||||
" djnz R2, 000010$ \n"
|
||||
" djnz R1, 000010$ \n"
|
||||
|
||||
//flash it
|
||||
" clr A \n"
|
||||
" orl _SETTINGS, #0x38 \n"
|
||||
" mov _FWRTHREE, #0x03 \n"
|
||||
" mov _FPGNO, R0 \n"
|
||||
" mov _FWRDSTL, A \n"
|
||||
" mov _FWRDSTH, A \n"
|
||||
" mov _FWRLENL, #0xff \n"
|
||||
" mov _FWRLENH, #0x03 \n"
|
||||
" mov _FWRSRCL, A \n"
|
||||
" mov _FWRSRCH, #0xe0 \n"
|
||||
" orl _TRIGGER, #0x08 \n"
|
||||
"00050$: \n"
|
||||
" mov A, _TCON2 \n"
|
||||
" jnb A.3, 00050$ \n"
|
||||
" anl _TCON2, #~0x48 \n"
|
||||
" anl _SETTINGS, #~0x10 \n"
|
||||
|
||||
//go do next page
|
||||
" inc R0 \n"
|
||||
" cjne R0, #63, 00001$ \n"
|
||||
|
||||
//done? reset
|
||||
" mov _WDTCONF, #0x80 \n"
|
||||
" mov _WDTENA, #0x01 \n"
|
||||
" mov A, #0xff \n"
|
||||
" mov _WDTRSTVALH, A \n"
|
||||
" mov _WDTRSTVALM, A \n"
|
||||
" mov _WDTRSTVALL, A \n"
|
||||
"00090$: \n"
|
||||
" sjmp 00090$ \n"
|
||||
|
||||
"00099$: \n"
|
||||
);
|
||||
}
|
||||
|
||||
void selfUpdate(void)
|
||||
{
|
||||
uint32_t updaterInfo = prvUpdateApplierGet();
|
||||
uint8_t __code *src = (uint8_t __code*)updaterInfo;
|
||||
uint8_t i, len = updaterInfo >> 16;
|
||||
uint8_t __xdata *dst = mScreenRow;
|
||||
|
||||
for (i = len; i ; i--)
|
||||
*dst++ = *src++;
|
||||
|
||||
if (!flashWrite(0xfc00, mScreenRow, len, true))
|
||||
pr("failed to write updater\n");
|
||||
|
||||
IEN_EA = 0; //ints off
|
||||
|
||||
__asm__(
|
||||
" mov dptr, #0xfc00 \n"
|
||||
" clr a \n"
|
||||
" jmp @a+dptr \n"
|
||||
);
|
||||
}
|
||||
@@ -1,379 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
#include "asmUtil.h"
|
||||
#include "screen.h"
|
||||
#include "printf.h"
|
||||
#include "board.h"
|
||||
#include "timer.h"
|
||||
#include "sleep.h"
|
||||
#include "adc.h"
|
||||
#include "cpu.h"
|
||||
#include "spi.h"
|
||||
|
||||
uint8_t __xdata mScreenRow[320];
|
||||
|
||||
static __bit mInited = false, mPartial;
|
||||
static uint8_t __xdata mPassNo;
|
||||
|
||||
#define SCREEN_CMD_CLOCK_ON 0x80
|
||||
#define SCREEN_CMD_CLOCK_OFF 0x01
|
||||
|
||||
#define SCREEN_CMD_ANALOG_ON 0x40
|
||||
#define SCREEN_CMD_ANALOG_OFF 0x02
|
||||
|
||||
#define SCREEN_CMD_LATCH_TEMPERATURE_VAL 0x20
|
||||
|
||||
#define SCREEN_CMD_LOAD_LUT 0x10
|
||||
#define SCREEN_CMD_USE_MODE_2 0x08 // modified commands 0x10 and 0x04
|
||||
|
||||
#define SCREEN_CMD_REFRESH 0xC7
|
||||
|
||||
static const uint8_t __code mColorMap[][6] =
|
||||
{
|
||||
// colors are: B, DG, G, LG, W, R
|
||||
// phase 0 (LUTS: B:W:R:G, purpose: BWR, prepare greys)
|
||||
{
|
||||
1, 1, 1, 1, 0, 0, // lo plane (B)
|
||||
},
|
||||
{
|
||||
0, 0, 0, 0, 0, 1, // hi plane (R)
|
||||
}};
|
||||
|
||||
#define einkPrvSelect() \
|
||||
do \
|
||||
{ \
|
||||
P1_7 = 0; \
|
||||
} while (0)
|
||||
|
||||
#define einkPrvDeselect() \
|
||||
do \
|
||||
{ \
|
||||
P1_7 = 1; \
|
||||
} while (0)
|
||||
// urx pin
|
||||
#define einkPrvMarkCommand() \
|
||||
do \
|
||||
{ \
|
||||
P2_2 = 0; \
|
||||
} while (0)
|
||||
|
||||
#define einkPrvMarkData() \
|
||||
do \
|
||||
{ \
|
||||
P2_2 = 1; \
|
||||
} while (0)
|
||||
|
||||
#pragma callee_saves einkPrvCmd
|
||||
static void einkPrvCmd(uint8_t cmd) // sets chip select
|
||||
{
|
||||
einkPrvSelect();
|
||||
einkPrvMarkCommand();
|
||||
spiByte(cmd);
|
||||
}
|
||||
|
||||
#pragma callee_saves einkPrvData
|
||||
static void einkPrvData(uint8_t byte)
|
||||
{
|
||||
einkPrvMarkData();
|
||||
spiByte(byte);
|
||||
}
|
||||
|
||||
#pragma callee_saves einkPrvCmdWithOneByte
|
||||
static void einkPrvCmdWithOneByte(uint16_t vals) // passing in one u16 is better than two params cause SDCC sucks
|
||||
{
|
||||
einkPrvCmd(vals >> 8);
|
||||
einkPrvData(vals);
|
||||
einkPrvDeselect();
|
||||
}
|
||||
|
||||
#pragma callee_saves einkPrvWaitWithTimeout
|
||||
static void einkPrvWaitWithTimeout(uint32_t timeout)
|
||||
{
|
||||
uint32_t __xdata start = timerGet();
|
||||
|
||||
while (timerGet() - start < timeout)
|
||||
{
|
||||
|
||||
if (!P2_1)
|
||||
return;
|
||||
}
|
||||
pr("screen timeout %lu ticks\n", timerGet() - start);
|
||||
//while (1)
|
||||
;
|
||||
}
|
||||
|
||||
#pragma callee_saves einkPrvWaitWithTimeout
|
||||
static void einkPrvWaitWithTimeoutSleep(uint32_t timeout)
|
||||
{
|
||||
uint8_t tmp_P2FUNC = P2FUNC;
|
||||
uint8_t tmp_P2DIR = P2DIR;
|
||||
uint8_t tmp_P2PULL = P2PULL;
|
||||
uint8_t tmp_P2LVLSEL = P2LVLSEL;
|
||||
P2FUNC &= 0xfd;
|
||||
P2DIR |= 2;
|
||||
P2PULL |= 2;
|
||||
P2LVLSEL |= 2;
|
||||
|
||||
P2CHSTA &= 0xfd;
|
||||
P2INTEN |= 2;
|
||||
P2CHSTA &= 0xfd;
|
||||
sleepForMsec(timeout);
|
||||
P2CHSTA &= 0xfd;
|
||||
P2INTEN &= 0xfd;
|
||||
|
||||
P2FUNC = tmp_P2FUNC;
|
||||
P2DIR = tmp_P2DIR;
|
||||
P2PULL = tmp_P2PULL;
|
||||
P2LVLSEL = tmp_P2LVLSEL;
|
||||
/*if (!P2_1)
|
||||
return;
|
||||
|
||||
pr("screen timeout\n");
|
||||
while(1);*/
|
||||
}
|
||||
|
||||
#pragma callee_saves einkPrvReadByte
|
||||
static uint8_t einkPrvReadByte(void)
|
||||
{
|
||||
uint8_t val = 0, i;
|
||||
|
||||
P0DIR = (P0DIR & ~(1 << 0)) | (1 << 1);
|
||||
P0 &= ~(1 << 0);
|
||||
P0FUNC &= ~((1 << 0) | (1 << 1));
|
||||
|
||||
P2_2 = 1;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
P0_0 = 1;
|
||||
__asm__("nop\nnop\nnop\nnop\nnop\n");
|
||||
val <<= 1;
|
||||
if (P0_1)
|
||||
val++;
|
||||
P0_0 = 0;
|
||||
__asm__("nop\nnop\nnop\nnop\nnop\n");
|
||||
}
|
||||
|
||||
// set up pins for spi (0.0,0.1,0.2)
|
||||
P0FUNC |= (1 << 0) | (1 << 1);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
#pragma callee_saves einkPrvReadStatus
|
||||
static uint8_t einkPrvReadStatus(void)
|
||||
{
|
||||
uint8_t sta;
|
||||
einkPrvCmd(0x2f);
|
||||
|
||||
sta = einkPrvReadByte();
|
||||
einkPrvDeselect();
|
||||
|
||||
return sta;
|
||||
}
|
||||
|
||||
#pragma callee_saves screenPrvStartSubPhase
|
||||
static void screenPrvStartSubPhase(__bit redSubphase)
|
||||
{
|
||||
einkPrvCmd(0x4e);
|
||||
einkPrvData(0);
|
||||
einkPrvDeselect();
|
||||
|
||||
einkPrvCmd(0x4f);
|
||||
einkPrvData(0x00);
|
||||
einkPrvData(0x00);
|
||||
einkPrvDeselect();
|
||||
|
||||
einkPrvCmd(redSubphase ? 0x26 : 0x24);
|
||||
|
||||
einkPrvDeselect();
|
||||
}
|
||||
|
||||
#pragma callee_saves screenInitIfNeeded
|
||||
static void screenInitIfNeeded(__bit forPartial)
|
||||
{
|
||||
if (mInited)
|
||||
return;
|
||||
|
||||
mInited = true;
|
||||
mPartial = forPartial;
|
||||
|
||||
timerDelay(TIMER_TICKS_PER_SECOND / 1000);
|
||||
P2_0 = 0;
|
||||
timerDelay(TIMER_TICKS_PER_SECOND / 1000);
|
||||
P2_0 = 1;
|
||||
timerDelay(TIMER_TICKS_PER_SECOND / 1000);
|
||||
|
||||
einkPrvCmd(0x12); // software reset
|
||||
einkPrvDeselect();
|
||||
timerDelay(TIMER_TICKS_PER_SECOND / 1000);
|
||||
|
||||
einkPrvCmdWithOneByte(0x7454);
|
||||
|
||||
einkPrvCmdWithOneByte(0x7e3b);
|
||||
|
||||
einkPrvCmd(0x2b);
|
||||
einkPrvData(0x04);
|
||||
einkPrvData(0x63);
|
||||
einkPrvDeselect();
|
||||
|
||||
einkPrvCmd(0x0c); // they send 8f 8f 8f 3f
|
||||
einkPrvData(0x8f);
|
||||
einkPrvData(0x8f);
|
||||
einkPrvData(0x8f);
|
||||
einkPrvData(0x3f);
|
||||
einkPrvDeselect();
|
||||
|
||||
einkPrvCmd(0x01);
|
||||
einkPrvData((SCREEN_HEIGHT - 1) & 0xff);
|
||||
einkPrvData((SCREEN_HEIGHT - 1) >> 8);
|
||||
einkPrvData(0x00);
|
||||
einkPrvDeselect();
|
||||
|
||||
einkPrvCmdWithOneByte(0x1103);
|
||||
|
||||
einkPrvCmd(0x44);
|
||||
einkPrvData(0x00);
|
||||
einkPrvData(SCREEN_WIDTH / 8 - 1);
|
||||
einkPrvDeselect();
|
||||
|
||||
einkPrvCmd(0x45);
|
||||
einkPrvData(0x00);
|
||||
einkPrvData(0x00);
|
||||
einkPrvData((SCREEN_HEIGHT - 1) & 0xff);
|
||||
einkPrvData((SCREEN_HEIGHT - 1) >> 8);
|
||||
einkPrvDeselect();
|
||||
|
||||
einkPrvCmdWithOneByte(0x3cc0); // border will be HiZ
|
||||
|
||||
einkPrvCmdWithOneByte(0x1880); // internal temp sensor
|
||||
|
||||
einkPrvCmdWithOneByte(0x2108);
|
||||
// turn on clock & analog
|
||||
einkPrvCmdWithOneByte(0x22B1);
|
||||
einkPrvCmd(0x20); // do action
|
||||
einkPrvDeselect();
|
||||
einkPrvWaitWithTimeout(TIMER_TICKS_PER_SECOND);
|
||||
}
|
||||
|
||||
#pragma callee_saves screenPrvDraw
|
||||
static void screenPrvDraw(void)
|
||||
{
|
||||
einkPrvCmdWithOneByte(0x2200 | SCREEN_CMD_REFRESH);
|
||||
einkPrvCmd(0x20); // do actions
|
||||
if (1)
|
||||
{
|
||||
einkPrvWaitWithTimeoutSleep(1000 * 60UL);
|
||||
screenSleep();
|
||||
}
|
||||
else
|
||||
{
|
||||
einkPrvWaitWithTimeout(TIMER_TICKS_PER_SECOND * 60UL);
|
||||
}
|
||||
}
|
||||
|
||||
__bit screenTxStart(__bit forPartial)
|
||||
{
|
||||
screenInitIfNeeded(forPartial);
|
||||
mPassNo = 0;
|
||||
|
||||
screenPrvStartSubPhase(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void screenEndPass(void)
|
||||
{
|
||||
switch (mPassNo)
|
||||
{
|
||||
case 0:
|
||||
screenPrvStartSubPhase(true);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
mPassNo++;
|
||||
}
|
||||
|
||||
void screenTxEnd(void)
|
||||
{
|
||||
screenPrvDraw();
|
||||
screenShutdown();
|
||||
}
|
||||
|
||||
void screenShutdown(void)
|
||||
{
|
||||
if (!mInited)
|
||||
return;
|
||||
|
||||
mInited = false;
|
||||
einkPrvCmdWithOneByte(0x1003); // shut down
|
||||
}
|
||||
|
||||
void screenSleep(void)
|
||||
{
|
||||
P2_0 = 0;
|
||||
timerDelay(TIMER_TICKS_PER_SECOND / 250);
|
||||
P2_0 = 1;
|
||||
timerDelay(TIMER_TICKS_PER_SECOND / 250);
|
||||
|
||||
einkPrvCmd(0x12); // software reset
|
||||
einkPrvDeselect();
|
||||
einkPrvWaitWithTimeout(TIMER_TICKS_PER_SECOND);
|
||||
|
||||
einkPrvCmdWithOneByte(0x1003); // shut down
|
||||
}
|
||||
|
||||
#pragma callee_saves screenByteTx
|
||||
void screenByteTx(uint8_t byte)
|
||||
{
|
||||
static uint8_t __xdata prev, step = 0;
|
||||
|
||||
prev <<= 2;
|
||||
prev |= (mColorMap[mPassNo][byte >> 4] << 1) | mColorMap[mPassNo][byte & 0x0f];
|
||||
if (++step == 4)
|
||||
{
|
||||
step = 0;
|
||||
einkPrvSelect();
|
||||
einkPrvData(prev);
|
||||
einkPrvDeselect();
|
||||
}
|
||||
}
|
||||
|
||||
// yes this is here...
|
||||
uint16_t adcSampleBattery(void)
|
||||
{
|
||||
__bit wasInited = mInited;
|
||||
uint16_t voltage = 2600;
|
||||
|
||||
if (!mInited)
|
||||
screenInitIfNeeded(false);
|
||||
|
||||
uint8_t val;
|
||||
|
||||
einkPrvCmdWithOneByte(0x2200 | SCREEN_CMD_CLOCK_ON | SCREEN_CMD_ANALOG_ON);
|
||||
einkPrvCmd(0x20); // do action
|
||||
einkPrvDeselect();
|
||||
einkPrvWaitWithTimeout(TIMER_TICKS_PER_SECOND);
|
||||
|
||||
for (val = 3; val < 8; val++)
|
||||
{
|
||||
|
||||
einkPrvCmdWithOneByte(0x1500 + val);
|
||||
einkPrvWaitWithTimeout(TIMER_TICKS_PER_SECOND);
|
||||
if (einkPrvReadStatus() & 0x10)
|
||||
{ // set if voltage is less than threshold ( == 1.9 + val / 10)
|
||||
voltage = 1850 + mathPrvMul8x8(val, 100);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
einkPrvCmdWithOneByte(0x22B1);
|
||||
einkPrvCmd(0x20); // do action
|
||||
einkPrvDeselect();
|
||||
einkPrvWaitWithTimeout(TIMER_TICKS_PER_SECOND);
|
||||
|
||||
if (!wasInited)
|
||||
screenShutdown();
|
||||
|
||||
return voltage;
|
||||
}
|
||||
@@ -27,22 +27,6 @@ extern int8_t __xdata mCurTemperature;
|
||||
|
||||
#define SCREEN_DATA_PASSES 2
|
||||
|
||||
void screenShutdown(void);
|
||||
|
||||
void screenTest(void);
|
||||
|
||||
__bit screenTxStart(__bit forPartial);
|
||||
|
||||
void screenEndPass(void); //at end of each pass
|
||||
|
||||
#pragma callee_saves screenByteTx
|
||||
void screenByteTx(uint8_t byte);
|
||||
void screenTxEnd(void);
|
||||
|
||||
void screenSleep(void);
|
||||
|
||||
extern uint8_t __xdata mScreenRow[]; //320 bytes used as temp by many on cc where memory is tight
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -42,8 +42,6 @@ bool commsTxUnencrypted(const void __xdata *packetP, uint8_t len) {
|
||||
mCommsBuf[0] = len + RADIO_PAD_LEN_BY;
|
||||
|
||||
return radioTx(mCommsBuf);;
|
||||
radioTx(mCommsBuf);;
|
||||
|
||||
}
|
||||
|
||||
bool commsTxNoCpy(const void __xdata *packetp) {
|
||||
|
||||
322
ap_fw/eeprom.c
322
ap_fw/eeprom.c
@@ -1,322 +0,0 @@
|
||||
#include "asmUtil.h"
|
||||
#include "screen.h"
|
||||
#include "eeprom.h"
|
||||
#include "printf.h"
|
||||
#include "board.h"
|
||||
#include "cpu.h"
|
||||
|
||||
static uint32_t __xdata mEepromSize;
|
||||
static uint8_t __xdata mOpcodeErz4K = 0, mOpcodeErz32K = 0, mOpcodeErz64K = 0;
|
||||
uint8_t mScreenRow[320];
|
||||
|
||||
uint32_t eepromGetSize(void)
|
||||
{
|
||||
return mEepromSize;
|
||||
}
|
||||
|
||||
void eepromReadStart(uint32_t addr) __reentrant
|
||||
{
|
||||
eepromPrvSelect();
|
||||
eepromByte(0x03);
|
||||
eepromByte(addr >> 16);
|
||||
eepromByte(addr >> 8);
|
||||
eepromByte(addr & 0xff);
|
||||
}
|
||||
|
||||
void eepromRead(uint32_t addr, void __xdata *dstP, uint16_t len) __reentrant
|
||||
{
|
||||
uint8_t __xdata *dst = (uint8_t __xdata*)dstP;
|
||||
|
||||
eepromPrvSelect();
|
||||
eepromByte(0x03);
|
||||
eepromByte(addr >> 16);
|
||||
eepromByte(addr >> 8);
|
||||
eepromByte(addr & 0xff);
|
||||
|
||||
while (len--)
|
||||
*dst++ = eepromByte(0);
|
||||
eepromPrvDeselect();
|
||||
}
|
||||
|
||||
static void eepromPrvSimpleCmd(uint8_t cmd)
|
||||
{
|
||||
eepromPrvSelect();
|
||||
eepromByte(cmd);
|
||||
eepromPrvDeselect();
|
||||
}
|
||||
|
||||
static bool eepromPrvBusyWait(void)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
eepromPrvSelect();
|
||||
eepromByte(0x05);
|
||||
while ((val = eepromByte(0x00)) & 1);
|
||||
eepromPrvDeselect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool eepromWriteLL(uint32_t addr, const void __xdata *srcP, uint16_t len)
|
||||
{
|
||||
const uint8_t __xdata *src = (const uint8_t __xdata*)srcP;
|
||||
|
||||
eepromPrvSimpleCmd(0x06);
|
||||
|
||||
eepromPrvSelect();
|
||||
eepromByte(0x02);
|
||||
eepromByte(addr >> 16);
|
||||
eepromByte(addr >> 8);
|
||||
eepromByte(addr & 0xff);
|
||||
|
||||
while (len--)
|
||||
eepromByte(*src++);
|
||||
eepromPrvDeselect();
|
||||
|
||||
return eepromPrvBusyWait();
|
||||
}
|
||||
|
||||
void eepromDeepPowerDown(void)
|
||||
{
|
||||
eepromPrvSimpleCmd(0xb9);
|
||||
}
|
||||
|
||||
static void eepromPrvWakeFromPowerdown(void)
|
||||
{
|
||||
eepromPrvSimpleCmd(0xab);
|
||||
}
|
||||
|
||||
#pragma callee_saves eepromPrvSfdpRead
|
||||
static void eepromPrvSfdpRead(uint16_t ofst, uint8_t __xdata *dst, uint8_t len)
|
||||
{
|
||||
eepromPrvSelect();
|
||||
eepromByte(0x5a); //cmd
|
||||
eepromByte(0); //addr
|
||||
eepromByte(ofst >> 8);
|
||||
eepromByte(ofst);
|
||||
eepromByte(0x00); //dummy
|
||||
while(len--)
|
||||
*dst++ = eepromByte(0);
|
||||
eepromPrvDeselect();
|
||||
}
|
||||
|
||||
__bit eepromInit(void)
|
||||
{
|
||||
uint8_t __xdata buf[8];
|
||||
uint8_t i, nParamHdrs;
|
||||
|
||||
eepromPrvWakeFromPowerdown();
|
||||
|
||||
//process SFDP
|
||||
|
||||
eepromPrvSfdpRead(0, buf, 8);
|
||||
if (buf[0] != 0x53 || buf[1] != 0x46 || buf[2] != 0x44 || buf[3] != 0x50 || buf[7] != 0xff) {
|
||||
pr("SFDP: header not found\n");
|
||||
|
||||
__bit valid = false;
|
||||
|
||||
//try manual ID for chips we know of
|
||||
eepromPrvSelect();
|
||||
eepromByte(0x90);
|
||||
eepromByte(0x00);
|
||||
eepromByte(0x00);
|
||||
eepromByte(0x00);
|
||||
if (eepromByte(0) == 0xc2) { //old macronix chips
|
||||
valid = true;
|
||||
mOpcodeErz4K = 0x20;
|
||||
switch (eepromByte(0)) {
|
||||
case 0x05: //MX25V512
|
||||
mEepromSize = 0x00010000ul;
|
||||
break;
|
||||
|
||||
case 0x12: //MX25V4005
|
||||
mEepromSize = 0x00080000ul;
|
||||
break;
|
||||
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
eepromPrvDeselect();
|
||||
|
||||
return valid;
|
||||
}
|
||||
if (buf[5] != 0x01) {
|
||||
pr("SFDP: version wrong: %u.%d\n", buf[5], buf[4]);
|
||||
return false;
|
||||
}
|
||||
nParamHdrs = buf[6];
|
||||
if (nParamHdrs == 0xff) //that case is very unlikely and we just do not care
|
||||
nParamHdrs--;
|
||||
|
||||
//now we need to find the JEDEC parameter table header
|
||||
for (i = 0; i <= nParamHdrs; i++) {
|
||||
|
||||
eepromPrvSfdpRead(mathPrvMul8x8(i, 8) + 8, buf, 8);
|
||||
if (buf[0] == 0x00 && buf[2] == 0x01 && buf[3] >= 9) {
|
||||
|
||||
uint8_t j;
|
||||
|
||||
eepromPrvSfdpRead(*(uint16_t __xdata*)(buf + 4), mScreenRow, 9 * 4);
|
||||
if ((mScreenRow[0] & 3) != 1) {
|
||||
pr("SFDP: no 4K ERZ\n");
|
||||
break;
|
||||
}
|
||||
if (!(mScreenRow[0] & 0x04)) {
|
||||
pr("SFDP: no large write buf\n");
|
||||
break;
|
||||
}
|
||||
if ((mScreenRow[2] & 0x06)) {
|
||||
pr("SFDP: addr.len != 3\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mScreenRow[1] || mScreenRow[1] == 0xff) {
|
||||
pr("SFDP: 4K ERZ opcode invalid\n");
|
||||
break;
|
||||
}
|
||||
mOpcodeErz4K = mScreenRow[1];
|
||||
|
||||
if (mScreenRow[7] & 0x80) {
|
||||
|
||||
pr("SFDP: device too big\n");
|
||||
break;
|
||||
}
|
||||
else {
|
||||
|
||||
uint8_t t;
|
||||
|
||||
if (t = mScreenRow[7])
|
||||
mEepromSize = 0x00200000UL;
|
||||
else if (t = mScreenRow[6])
|
||||
mEepromSize = 0x00002000UL;
|
||||
else if (t = mScreenRow[5])
|
||||
mEepromSize = 0x00000020UL;
|
||||
else {
|
||||
pr("SFDP: device so small?!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
while (t) {
|
||||
mEepromSize <<= 1;
|
||||
t >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//get erase opcodes
|
||||
for (j = 0x1c; j < 0x24; j += 2) {
|
||||
uint8_t instr = mScreenRow[j + 1];
|
||||
|
||||
if (!instr || instr == 0xff)
|
||||
continue;
|
||||
|
||||
switch (mScreenRow[j]) {
|
||||
case 0x0c:
|
||||
if (mOpcodeErz4K != instr) {
|
||||
pr("4K ERZ opcode disagreement\n");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0f: //32K erase
|
||||
mOpcodeErz32K = instr;
|
||||
break;
|
||||
|
||||
case 0x10: //64K erase
|
||||
mOpcodeErz64K = instr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pr("EEPROM accepted\n");
|
||||
pr(" ERZ opcodes: \n");
|
||||
if (mOpcodeErz4K)
|
||||
pr(" 4K: %02xh\n", mOpcodeErz4K);
|
||||
if (mOpcodeErz32K)
|
||||
pr(" 32K: %02xh\n", mOpcodeErz32K);
|
||||
if (mOpcodeErz64K)
|
||||
pr(" 64K: %02xh\n", mOpcodeErz64K);
|
||||
pr(" Size: 0x%*08lx\n", (uint16_t)&mEepromSize);
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
pr("SFDP: no JEDEC table of expected version found\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool eepromWrite(uint32_t addr, const void __xdata *srcP, uint16_t len) __reentrant
|
||||
{
|
||||
const uint8_t __xdata *src = (const uint8_t __xdata*)srcP;
|
||||
|
||||
while (len) {
|
||||
|
||||
uint16_t lenNow = EEPROM_WRITE_PAGE_SZ - (addr & (EEPROM_WRITE_PAGE_SZ - 1));
|
||||
|
||||
if (lenNow > len)
|
||||
lenNow = len;
|
||||
|
||||
if (!eepromWriteLL(addr, src, lenNow))
|
||||
return false;
|
||||
|
||||
addr += lenNow;
|
||||
src += lenNow;
|
||||
len -= lenNow;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool eepromErase(uint32_t addr, uint16_t nSec) __reentrant
|
||||
{
|
||||
uint8_t now;
|
||||
|
||||
if (((uint16_t)addr) & 0x0fff)
|
||||
return false;
|
||||
|
||||
for (;nSec; nSec -= now) {
|
||||
|
||||
eepromPrvSimpleCmd(0x06);
|
||||
eepromPrvSelect();
|
||||
|
||||
if (nSec >= 16 && !(uint16_t)addr && mOpcodeErz64K) { //erase 64K
|
||||
|
||||
eepromByte(mOpcodeErz64K);
|
||||
now = 16;
|
||||
}
|
||||
else if (nSec >= 8 && !(((uint16_t)addr) & 0x7fff) && mOpcodeErz32K) { //erase 32K
|
||||
|
||||
eepromByte(mOpcodeErz32K);
|
||||
now = 8;
|
||||
}
|
||||
else { //erase 4K
|
||||
|
||||
eepromByte(mOpcodeErz4K);
|
||||
now = 1;
|
||||
}
|
||||
|
||||
eepromByte(addr >> 16);
|
||||
eepromByte(addr >> 8);
|
||||
eepromByte(addr);
|
||||
eepromPrvDeselect();
|
||||
|
||||
if (!eepromPrvBusyWait())
|
||||
return false;
|
||||
|
||||
addr += mathPrvMul16x8(EEPROM_ERZ_SECTOR_SZ, now);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void eepromOtpModeEnter(void)
|
||||
{
|
||||
eepromPrvSimpleCmd(0xb1);
|
||||
}
|
||||
|
||||
void eepromOtpModeExit(void)
|
||||
{
|
||||
eepromPrvSimpleCmd(0xc1);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#ifndef _EEPROM_H_
|
||||
#define _EEPROM_H_
|
||||
|
||||
#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
|
||||
|
||||
//device has 256 sectors, so eepromErase() cannot erase thw whole device...i can live with that
|
||||
|
||||
__bit eepromInit(void);
|
||||
void eepromOtpModeEnter(void);
|
||||
void eepromOtpModeExit(void);
|
||||
|
||||
#pragma callee_saves eepromRead
|
||||
void eepromRead(uint32_t addr, void __xdata *dst, uint16_t len) __reentrant;
|
||||
|
||||
#pragma callee_saves eepromWrite
|
||||
bool eepromWrite(uint32_t addr, const void __xdata *src, uint16_t len) __reentrant;
|
||||
|
||||
#pragma callee_saves eepromErase
|
||||
bool eepromErase(uint32_t addr, uint16_t numSectors) __reentrant;
|
||||
|
||||
void eepromDeepPowerDown(void);
|
||||
|
||||
#pragma callee_saves eepromGetSize
|
||||
uint32_t eepromGetSize(void);
|
||||
|
||||
//this is for firmware update use
|
||||
void eepromReadStart(uint32_t addr) __reentrant;
|
||||
|
||||
//structures
|
||||
#define EEPROM_IMG_INPROGRESS (0x7fffffffUL)
|
||||
#define EEPROM_IMG_VALID (0x494d4722UL)
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#define EEPROM_PIECE_SZ (88)
|
||||
struct EepromImageHeader { //each image space is 0x17000 bytes, we have space for ten of them
|
||||
uint64_t version;
|
||||
uint32_t validMarker;
|
||||
uint32_t size;
|
||||
uint32_t rfu[8]; //zero-filled for now
|
||||
uint8_t piecesMissing[EEPROM_PROGRESS_BYTES]; //each bit represents a EEPROM_PIECE_SZ-byte piece
|
||||
uint32_t id;
|
||||
|
||||
//image data here
|
||||
//we pre-erase so progress can be calculated by finding the first non-0xff byte
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
47
ap_fw/main.c
47
ap_fw/main.c
@@ -9,7 +9,6 @@
|
||||
#include "board.h"
|
||||
#include "comms.h"
|
||||
#include "cpu.h"
|
||||
#include "eeprom.h"
|
||||
#include "printf.h"
|
||||
#include "proto.h"
|
||||
#include "radio.h"
|
||||
@@ -40,7 +39,8 @@ struct MacFrameBcast {
|
||||
uint16_t srcPan;
|
||||
uint8_t src[8];
|
||||
} __packed;
|
||||
#define PKT_AVAIL_DATA_REQ_SHORT 0xE4
|
||||
|
||||
#define PKT_AVAIL_DATA_SHORTREQ 0xE3
|
||||
#define PKT_AVAIL_DATA_REQ 0xE5
|
||||
#define PKT_AVAIL_DATA_INFO 0xE6
|
||||
#define PKT_BLOCK_PARTIAL_REQUEST 0xE7
|
||||
@@ -61,10 +61,9 @@ struct AvailDataReq {
|
||||
uint16_t batteryMv;
|
||||
uint8_t hwType;
|
||||
uint8_t wakeupReason;
|
||||
uint8_t capabilities; // undefined, as of now
|
||||
uint8_t capabilities; // undefined, as of now
|
||||
} __packed;
|
||||
|
||||
|
||||
#define DATATYPE_NOUPDATE 0
|
||||
#define DATATYPE_IMG 1
|
||||
#define DATATYPE_IMGRAW 2
|
||||
@@ -72,14 +71,13 @@ struct AvailDataReq {
|
||||
|
||||
struct AvailDataInfo {
|
||||
uint8_t checksum;
|
||||
uint64_t dataVer; // MD5 of potential traffic
|
||||
uint32_t dataSize;
|
||||
uint8_t dataType; // allows for 16 different datatypes
|
||||
uint64_t dataVer; // MD5 of potential traffic
|
||||
uint32_t dataSize;
|
||||
uint8_t dataType; // allows for different datatypes
|
||||
uint8_t dataTypeArgument; // extra specification or instruction for the tag (LUT to be used for drawing image)
|
||||
uint16_t nextCheckIn; // when should the tag check-in again? Measured in minutes
|
||||
uint16_t nextCheckIn; // when should the tag check-in again? Measured in minutes
|
||||
} __packed;
|
||||
|
||||
|
||||
struct blockPart {
|
||||
uint8_t checksum;
|
||||
uint8_t blockId;
|
||||
@@ -585,7 +583,7 @@ void sendPart(uint8_t partNo) {
|
||||
radioTx(radiotxbuffer);
|
||||
}
|
||||
void sendBlockData() {
|
||||
if(getBlockDataLength()==0){
|
||||
if (getBlockDataLength() == 0) {
|
||||
pr("Invalid block request received, 0 parts..\n");
|
||||
requestedData.requestedParts[0] |= 0x01;
|
||||
}
|
||||
@@ -632,20 +630,14 @@ void sendCancelXfer(uint8_t *dst) {
|
||||
void sendPong(void *__xdata buf) {
|
||||
struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buf;
|
||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
|
||||
memset(radiotxbuffer, 0, sizeof(struct MacFrameNormal) + 2);
|
||||
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_PONG;
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
|
||||
memcpy(frameHeader->src, mSelfMac, 8);
|
||||
memcpy(frameHeader->dst, rxframe->src, 8);
|
||||
|
||||
frameHeader->fcs.frameType = 1;
|
||||
frameHeader->fcs.panIdCompressed = 1;
|
||||
frameHeader->fcs.destAddrType = 3;
|
||||
frameHeader->fcs.srcAddrType = 3;
|
||||
radiotxbuffer[1] = 0x41; // fast way to set the appropriate bits
|
||||
radiotxbuffer[2] = 0xCC; // normal frame
|
||||
frameHeader->seq = seq++;
|
||||
frameHeader->pan = rxframe->srcPan;
|
||||
|
||||
radioTx(radiotxbuffer);
|
||||
}
|
||||
|
||||
@@ -681,18 +673,16 @@ void main(void) {
|
||||
radioSetTxPower(10);
|
||||
radioRxEnable(true, true);
|
||||
|
||||
// uint8_t __xdata fromMac[8];
|
||||
pr("RDY>\n");
|
||||
|
||||
housekeepingTimer = timerGet();
|
||||
|
||||
// really... if I do the call below, it'll cost me 8 bytes IRAM. Not the kind of 'optimization' I ever dreamed of doing
|
||||
// pr("MAC>%02X%02X%02X%02X%02X%02X%02X%02X\n", mSelfMac[0], mSelfMac[1], mSelfMac[2], mSelfMac[3], mSelfMac[4], mSelfMac[5], mSelfMac[6], mSelfMac[7]);
|
||||
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]);
|
||||
|
||||
uint16_t __xdata loopCount = 1;
|
||||
pr("VER>%04X\n", version);
|
||||
while (1) {
|
||||
while ((timerGet() - housekeepingTimer) < ((TIMER_TICKS_PER_SECOND * HOUSEKEEPING_INTERVAL) - 100 * TIMER_TICKS_PER_MS)) {
|
||||
@@ -715,10 +705,17 @@ void main(void) {
|
||||
case PKT_PING:
|
||||
sendPong(radiorxbuffer);
|
||||
break;
|
||||
case PKT_AVAIL_DATA_SHORTREQ:
|
||||
// a short AvailDataReq is basically a very short (1 byte payload) packet that requires little preparation on the tx side, for optimal battery use
|
||||
// bytes of the struct are set 0, so it passes the checksum test, and the ESP32 can detect that no interesting payload is sent
|
||||
memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast), 0, sizeof(struct AvailDataReq)+2);
|
||||
processAvailDataReq(radiorxbuffer);
|
||||
break;
|
||||
default:
|
||||
pr("t=%02X\n", getPacketType(radiorxbuffer));
|
||||
break;
|
||||
}
|
||||
loopCount = 10000;
|
||||
}
|
||||
while (uartBytesAvail()) {
|
||||
processSerial(uartRx());
|
||||
@@ -730,8 +727,14 @@ void main(void) {
|
||||
blockStartTimer = 0;
|
||||
}
|
||||
}
|
||||
loopCount--;
|
||||
if (loopCount == 0) {
|
||||
loopCount = 10000;
|
||||
// every once in a while, especially when handling a lot of traffic, the radio will hang. Calling this every once in while
|
||||
// alleviates this problem. The radio is set back to 'receive' whenever loopCount overflows
|
||||
RADIO_command = RADIO_CMD_RECEIVE;
|
||||
}
|
||||
}
|
||||
pr("housekeeping...");
|
||||
|
||||
for (uint8_t __xdata c = 0; c < MAX_PENDING_MACS; c++) {
|
||||
if (pendingDataArr[c].attemptsLeft == 1) {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef _SLEEP_H_
|
||||
#define _SLEEP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
void sleepForMsec(uint32_t msec);
|
||||
void sleepTillInt(void); //assumes you left only one int enabled!
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,7 @@ FLAGS += -Isoc/zbs243
|
||||
|
||||
FLAGS += -DSOC_ZBS243 --xram-loc 0xe000 --xram-size 0x2000 --model-large
|
||||
|
||||
SOURCES += soc/zbs243/soc.c soc/zbs243/wdt.c soc/zbs243/sleep.c soc/zbs243/spi.c soc/zbs243/uart.c soc/zbs243/timer.c soc/zbs243/radio.c
|
||||
SOURCES += soc/zbs243/soc.c soc/zbs243/wdt.c soc/zbs243/spi.c soc/zbs243/uart.c soc/zbs243/timer.c soc/zbs243/radio.c
|
||||
SOURCES += soc/zbs243/flash.c soc/zbs243/temperature.c cpu/8051/random.c cpu/8051/printf.c
|
||||
|
||||
CPU = 8051
|
||||
CPU = 8051
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "timer.h"
|
||||
|
||||
#define RX_BUFFER_SIZE (RADIO_MAX_PACKET_LEN + 1 /* len byte */ + 2 /* RSSI & LQI */)
|
||||
#define RX_BUFFER_NUM 3
|
||||
#define RX_BUFFER_NUM 7
|
||||
|
||||
static volatile uint8_t __xdata mRxBufs[RX_BUFFER_NUM][RX_BUFFER_SIZE];
|
||||
static volatile uint8_t __xdata mLastRSSI, mLastTxedSeq, mRxOn, mRxBufNextR, mRxBufNextW, mRxBufNumFree;
|
||||
|
||||
@@ -9,10 +9,6 @@ void powerPortsDownForSleep(void);
|
||||
#pragma callee_saves boardInit
|
||||
void boardInit(void);
|
||||
|
||||
//early - before most things
|
||||
#pragma callee_saves boardInitStage2
|
||||
void boardInitStage2(void);
|
||||
|
||||
//late, after eeprom
|
||||
#pragma callee_saves boardInit
|
||||
__bit boardGetOwnMac(uint8_t __xdata *mac);
|
||||
|
||||
@@ -30,8 +30,6 @@ void powerPortsDownForSleep(void)
|
||||
|
||||
void boardInit(void)
|
||||
{
|
||||
wdtOff();
|
||||
|
||||
//set up pins for spi(0.0,0.1,0.2), UART (0.6)
|
||||
P0FUNC |= (1 << 0) | (1 << 1) | (1 << 2) | (1 << 6);
|
||||
P0DIR = (P0DIR &~ ((1 << 0) | (1 << 1) | (1 << 6))) | (1 << 2);
|
||||
@@ -54,14 +52,9 @@ void boardInit(void)
|
||||
//BS1 = low
|
||||
P1_2 = 0;
|
||||
|
||||
uartInit();
|
||||
spiInit();
|
||||
}
|
||||
|
||||
void boardInitStage2(void)
|
||||
{
|
||||
//nothing yet
|
||||
}
|
||||
|
||||
__bit boardGetOwnMac(uint8_t __xdata *mac)
|
||||
{
|
||||
|
||||
@@ -359,6 +359,5 @@ void drawImageAtAddress(uint32_t addr) {
|
||||
|
||||
pr(" complete.\n");
|
||||
|
||||
draw();
|
||||
epdEnterSleep();
|
||||
drawWithSleep();
|
||||
}
|
||||
|
||||
58
tag_fw/epd.c
58
tag_fw/epd.c
@@ -198,7 +198,7 @@ void epdEnterSleep() {
|
||||
P2_0 = 1;
|
||||
timerDelay(50);
|
||||
shortCommand(CMD_SOFT_RESET2);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 10);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 15);
|
||||
shortCommand1(CMD_ENTER_SLEEP, 0x03);
|
||||
isInited = false;
|
||||
}
|
||||
@@ -239,12 +239,24 @@ static uint8_t epdGetStatus() {
|
||||
return sta;
|
||||
}
|
||||
uint16_t epdGetBattery(void) {
|
||||
// epdEnterSleep(); // r
|
||||
// return 2600; // r
|
||||
uint16_t voltage = 2600;
|
||||
|
||||
if (!isInited)
|
||||
epdReset();
|
||||
uint8_t val;
|
||||
|
||||
//epdReset();
|
||||
|
||||
timerDelay(50);
|
||||
P2_0 = 0;
|
||||
timerDelay(50);
|
||||
P2_0 = 1;
|
||||
timerDelay(50);
|
||||
|
||||
shortCommand(CMD_SOFT_RESET); // software reset
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 30);
|
||||
shortCommand(CMD_SOFT_RESET2);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 30);
|
||||
|
||||
shortCommand1(CMD_DISP_UPDATE_CTRL2, SCREEN_CMD_CLOCK_ON | SCREEN_CMD_ANALOG_ON);
|
||||
shortCommand(CMD_ACTIVATION);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 100);
|
||||
@@ -258,12 +270,10 @@ uint16_t epdGetBattery(void) {
|
||||
}
|
||||
}
|
||||
|
||||
shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB1);
|
||||
shortCommand(CMD_ACTIVATION);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 100);
|
||||
shortCommand(CMD_SOFT_RESET2);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 15);
|
||||
shortCommand1(CMD_ENTER_SLEEP, 0x03);
|
||||
|
||||
if (!isInited)
|
||||
epdEnterSleep();
|
||||
return voltage;
|
||||
}
|
||||
|
||||
@@ -341,7 +351,7 @@ void selectLUT(uint8_t lut) {
|
||||
lutGroupDisable(LUTGROUP_NEGATIVE);
|
||||
lutGroupDisable(LUTGROUP_FASTBLINK);
|
||||
lutGroupDisable(LUTGROUP_SLOWBLINK);
|
||||
//lutGroupSpeedup(LUTGROUP_SET, 2);
|
||||
// lutGroupSpeedup(LUTGROUP_SET, 2);
|
||||
lutGroupDisable(LUTGROUP_IMPROVE_REDS);
|
||||
lutGroupDisable(LUTGROUP_IMPROVE_SHARPNESS);
|
||||
break;
|
||||
@@ -350,7 +360,7 @@ void selectLUT(uint8_t lut) {
|
||||
lutGroupDisable(LUTGROUP_FASTBLINK);
|
||||
lutGroupDisable(LUTGROUP_SLOWBLINK);
|
||||
lutGroupRepeat(LUTGROUP_SET, 0);
|
||||
//lutGroupSpeedup(LUTGROUP_SET, 2);
|
||||
// lutGroupSpeedup(LUTGROUP_SET, 2);
|
||||
lutGroupDisable(LUTGROUP_IMPROVE_REDS);
|
||||
lutGroupDisable(LUTGROUP_IMPROVE_SHARPNESS);
|
||||
break;
|
||||
@@ -421,6 +431,32 @@ void drawNoWait() {
|
||||
// shortCommand1(0x22, SCREEN_CMD_REFRESH);
|
||||
shortCommand(0x20);
|
||||
}
|
||||
void drawWithSleep() {
|
||||
shortCommand1(0x22, 0xCF);
|
||||
// shortCommand1(0x22, SCREEN_CMD_REFRESH);
|
||||
shortCommand(0x20);
|
||||
uint8_t tmp_P2FUNC = P2FUNC;
|
||||
uint8_t tmp_P2DIR = P2DIR;
|
||||
uint8_t tmp_P2PULL = P2PULL;
|
||||
uint8_t tmp_P2LVLSEL = P2LVLSEL;
|
||||
P2FUNC &= 0xfd;
|
||||
P2DIR |= 2;
|
||||
P2PULL |= 2;
|
||||
P2LVLSEL |= 2;
|
||||
|
||||
P2CHSTA &= 0xfd;
|
||||
P2INTEN |= 2;
|
||||
P2CHSTA &= 0xfd;
|
||||
sleepForMsec(TIMER_TICKS_PER_SECOND * 120);
|
||||
P2CHSTA &= 0xfd;
|
||||
P2INTEN &= 0xfd;
|
||||
|
||||
P2FUNC = tmp_P2FUNC;
|
||||
P2DIR = tmp_P2DIR;
|
||||
P2PULL = tmp_P2PULL;
|
||||
P2LVLSEL = tmp_P2LVLSEL;
|
||||
eepromPrvDeselect();
|
||||
}
|
||||
void epdWaitRdy() {
|
||||
epdBusyWait(TIMER_TICKS_PER_SECOND * 120);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ void clearWindow(bool color);
|
||||
void clearScreen();
|
||||
void draw();
|
||||
void drawNoWait();
|
||||
void drawWithSleep();
|
||||
void epdWaitRdy();
|
||||
void drawLineHorizontal(bool color, uint16_t x1, uint16_t x2, uint16_t y);
|
||||
void drawLineVertical(bool color, uint16_t x, uint16_t y1, uint16_t y2);
|
||||
|
||||
259
tag_fw/main.c
259
tag_fw/main.c
@@ -13,20 +13,21 @@
|
||||
#include "printf.h"
|
||||
#include "proto.h"
|
||||
#include "radio.h"
|
||||
#include "settings.h"
|
||||
#include "syncedproto.h"
|
||||
#include "timer.h"
|
||||
#include "userinterface.h"
|
||||
#include "wdt.h"
|
||||
|
||||
//#define DEBUG_MODE
|
||||
// #define DEBUG_MODE
|
||||
static bool __xdata attemptFirstContact = true;
|
||||
|
||||
|
||||
|
||||
uint8_t showChannelSelect() {
|
||||
uint8_t showChannelSelect() { // returns 0 if no accesspoints were found
|
||||
uint8_t __xdata result[16];
|
||||
memset(result, 0, sizeof(result));
|
||||
showScanningWindow();
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
powerUp(INIT_RADIO);
|
||||
for (uint8_t i = 0; i < 5; i++) {
|
||||
for (uint8_t c = 11; c < 27; c++) {
|
||||
if (detectAP(c)) {
|
||||
if (mLastLqi > result[c - 11]) result[c - 11] = mLastLqi;
|
||||
@@ -47,96 +48,184 @@ uint8_t showChannelSelect() {
|
||||
highestLqi = result[c];
|
||||
}
|
||||
}
|
||||
powerDown(INIT_RADIO);
|
||||
epdWaitRdy();
|
||||
mLastLqi = highestLqi;
|
||||
return highestSlot;
|
||||
}
|
||||
uint8_t channelSelect() { // returns 0 if no accesspoints were found
|
||||
uint8_t __xdata result[16];
|
||||
memset(result, 0, sizeof(result));
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
for (uint8_t c = 11; c < 27; c++) {
|
||||
if (detectAP(c)) {
|
||||
if (mLastLqi > result[c - 11]) result[c - 11] = mLastLqi;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint8_t __xdata highestLqi = 0;
|
||||
uint8_t __xdata highestSlot = 0;
|
||||
for (uint8_t c = 0; c < sizeof(result); c++) {
|
||||
if (result[c] > highestLqi) {
|
||||
highestSlot = c + 11;
|
||||
highestLqi = result[c];
|
||||
}
|
||||
}
|
||||
|
||||
mLastLqi = highestLqi;
|
||||
return highestSlot;
|
||||
}
|
||||
|
||||
void mainProtocolLoop(void) {
|
||||
clockingAndIntsInit();
|
||||
timerInit();
|
||||
boardInit();
|
||||
powerUp(INIT_BASE | INIT_UART | INIT_GPIO);
|
||||
wdt10s();
|
||||
boardGetOwnMac(mSelfMac);
|
||||
|
||||
if (!boardGetOwnMac(mSelfMac)) {
|
||||
pr("failed to get MAC. Aborting\n");
|
||||
while (1)
|
||||
;
|
||||
} else {
|
||||
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]);
|
||||
}
|
||||
|
||||
irqsOn();
|
||||
boardInitStage2();
|
||||
|
||||
pr("BOOTED> (UI 0.03-1)\n\n");
|
||||
|
||||
if (!eepromInit()) {
|
||||
pr("failed to init eeprom\n");
|
||||
while (1)
|
||||
;
|
||||
} else {
|
||||
initializeProto();
|
||||
}
|
||||
eepromDeepPowerDown();
|
||||
// initialize Powers-saving-attempt-array with the default value;
|
||||
initPowerSaving();
|
||||
#ifndef DEBUG_MODE
|
||||
// show the splashscreen
|
||||
getExtraData();
|
||||
|
||||
showSplashScreen();
|
||||
|
||||
eepromDeepPowerDown();
|
||||
initRadio();
|
||||
|
||||
currentChannel = showChannelSelect();
|
||||
if (currentChannel == 0) {
|
||||
// couldn't find an AP :()
|
||||
showNoAP();
|
||||
} else {
|
||||
radioSetChannel(currentChannel);
|
||||
// Found an AP.
|
||||
showAPFound();
|
||||
}
|
||||
#endif
|
||||
#ifdef DEBUG_MODE
|
||||
initRadio();
|
||||
currentChannel = 11;
|
||||
#endif
|
||||
epdEnterSleep();
|
||||
|
||||
P1CHSTA &= ~(1 << 0);
|
||||
|
||||
while (1) {
|
||||
radioRxEnable(true, true);
|
||||
|
||||
struct AvailDataInfo *__xdata avail = getAvailDataInfo();
|
||||
if (avail == NULL) {
|
||||
// no data :(
|
||||
nextCheckInFromAP = 0; // let the power-saving algorithm determine the next sleep period
|
||||
} else {
|
||||
nextCheckInFromAP = avail->nextCheckIn;
|
||||
// got some data from the AP!
|
||||
if (avail->dataType != DATATYPE_NOUPDATE) {
|
||||
// data transfer
|
||||
if (doDataDownload(avail)) {
|
||||
// succesful transfer, next wake time is determined by the NextCheckin;
|
||||
} else {
|
||||
// failed transfer, let the algorithm determine next sleep interval (not the AP)
|
||||
nextCheckInFromAP = 0;
|
||||
}
|
||||
} else {
|
||||
// no data transfer, just sleep.
|
||||
{
|
||||
bool __xdata macSet = false;
|
||||
for (uint8_t __xdata c = 0; c < 8; c++) {
|
||||
if (mSelfMac[c] != 0xFF) {
|
||||
macSet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if the AP told us to sleep for a specific period, do so.
|
||||
if (nextCheckInFromAP) {
|
||||
doSleep(nextCheckInFromAP * 60000UL);
|
||||
if (!macSet) {
|
||||
pr("Mac can't be all FF's.\n");
|
||||
powerUp(INIT_EPD);
|
||||
showNoMAC();
|
||||
powerDown(INIT_EPD | INIT_GPIO | INIT_EEPROM);
|
||||
doSleep(-1);
|
||||
wdtDeviceReset();
|
||||
}
|
||||
}
|
||||
|
||||
pr("BOOTED> %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
|
||||
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]);
|
||||
|
||||
powerUp(INIT_EPD_VOLTREADING | INIT_TEMPREADING | INIT_EEPROM);
|
||||
|
||||
// get the highest slot number, number of slots
|
||||
initializeProto();
|
||||
powerDown(INIT_EEPROM);
|
||||
|
||||
// show the splashscreen
|
||||
powerUp(INIT_EPD);
|
||||
showSplashScreen();
|
||||
|
||||
wdt30s();
|
||||
powerUp(INIT_EPD);
|
||||
currentChannel = showChannelSelect();
|
||||
|
||||
powerUp(INIT_GPIO | INIT_EPD);
|
||||
if (currentChannel) {
|
||||
showAPFound();
|
||||
initPowerSaving(INTERVAL_BASE);
|
||||
powerDown(INIT_EPD | INIT_GPIO);
|
||||
doSleep(5000UL);
|
||||
} else {
|
||||
showNoAP();
|
||||
initPowerSaving(INTERVAL_AT_MAX_ATTEMPTS);
|
||||
powerDown(INIT_EPD | INIT_GPIO);
|
||||
doSleep(120000UL);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (currentChannel) {
|
||||
// associated
|
||||
|
||||
struct AvailDataInfo *__xdata avail;
|
||||
if ((longDataReqCounter > LONG_DATAREQ_INTERVAL) || attemptFirstContact || wakeUpReason != WAKEUP_REASON_TIMED) {
|
||||
if (attemptFirstContact)
|
||||
wakeUpReason = WAKEUP_REASON_BOOTUP;
|
||||
|
||||
|
||||
if (voltageCheckCounter == VOLTAGE_CHECK_INTERVAL) {
|
||||
powerUp(INIT_BASE | INIT_TEMPREADING | INIT_EPD_VOLTREADING | INIT_RADIO);
|
||||
voltageCheckCounter = 0;
|
||||
} else {
|
||||
powerUp(INIT_BASE | INIT_TEMPREADING | INIT_RADIO);
|
||||
}
|
||||
voltageCheckCounter++;
|
||||
|
||||
avail = getAvailDataInfo();
|
||||
if (avail != NULL) {
|
||||
longDataReqCounter = 0;
|
||||
attemptFirstContact = false;
|
||||
}
|
||||
} else {
|
||||
powerUp(INIT_BASE | INIT_RADIO); //| INIT_GPIO | INIT_UART
|
||||
avail = getShortAvailDataInfo();
|
||||
}
|
||||
powerDown(INIT_RADIO);
|
||||
|
||||
addAverageValue();
|
||||
|
||||
if (avail == NULL) {
|
||||
// no data :(
|
||||
nextCheckInFromAP = 0; // let the power-saving algorithm determine the next sleep period
|
||||
} else {
|
||||
nextCheckInFromAP = avail->nextCheckIn;
|
||||
// got some data from the AP!
|
||||
if (avail->dataType != DATATYPE_NOUPDATE) {
|
||||
// data transfer
|
||||
wdt10s();
|
||||
powerUp(INIT_GPIO | INIT_UART);
|
||||
if (doDataDownload(avail)) {
|
||||
// succesful transfer, next wake time is determined by the NextCheckin;
|
||||
} else {
|
||||
// failed transfer, let the algorithm determine next sleep interval (not the AP)
|
||||
nextCheckInFromAP = 0;
|
||||
}
|
||||
powerUp(INIT_GPIO);
|
||||
powerDown(INIT_EEPROM | INIT_RADIO);
|
||||
} else {
|
||||
// no data transfer, just sleep.
|
||||
}
|
||||
}
|
||||
|
||||
powerDown(INIT_GPIO);
|
||||
|
||||
uint16_t nextCheckin = getNextSleep();
|
||||
longDataReqCounter += nextCheckin;
|
||||
if (nextCheckin == INTERVAL_AT_MAX_ATTEMPTS) {
|
||||
// disconnected, obviously...
|
||||
currentChannel = 0;
|
||||
}
|
||||
|
||||
// if the AP told us to sleep for a specific period, do so.
|
||||
if (nextCheckInFromAP) {
|
||||
doSleep(nextCheckInFromAP * 60000UL);
|
||||
} else {
|
||||
doSleep(getNextSleep() * 1000UL);
|
||||
}
|
||||
|
||||
} else {
|
||||
doSleep(getNextSleep() * 1000UL);
|
||||
// not associated
|
||||
powerUp(INIT_BASE | INIT_RADIO); // || INIT_GPIO | INIT_UART
|
||||
|
||||
// try to find a working channel
|
||||
powerUp(INIT_RADIO);
|
||||
wdt30s();
|
||||
currentChannel = channelSelect();
|
||||
powerDown(INIT_RADIO | INIT_GPIO);
|
||||
|
||||
// did we find a working channel?
|
||||
if (currentChannel) {
|
||||
// now associated!
|
||||
scanAttempts = 0;
|
||||
attemptFirstContact = true;
|
||||
initPowerSaving(INTERVAL_BASE);
|
||||
doSleep(getNextSleep() * 1000UL);
|
||||
|
||||
} else {
|
||||
// still not associated
|
||||
doSleep(getNextScanSleep(true) * 1000UL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "sleep.h"
|
||||
#include "syncedproto.h"
|
||||
#include "timer.h"
|
||||
#include "uart.h" // for initUart
|
||||
#include "userinterface.h"
|
||||
#include "wdt.h"
|
||||
|
||||
@@ -29,41 +30,105 @@ uint8_t __xdata dataReqAttemptArrayIndex = 0;
|
||||
uint8_t __xdata dataReqLastAttempt = 0;
|
||||
uint16_t __xdata nextCheckInFromAP = 0;
|
||||
uint8_t __xdata wakeUpReason = 0;
|
||||
|
||||
extern int8_t adcSampleTemperature(void); //in degrees C
|
||||
|
||||
void initPowerSaving() {
|
||||
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
|
||||
dataReqAttemptArr[c] = INTERVAL_BASE;
|
||||
}
|
||||
}
|
||||
uint8_t __xdata scanAttempts = 0;
|
||||
|
||||
int8_t __xdata temperature = 0;
|
||||
uint16_t __xdata batteryVoltage = 0;
|
||||
uint16_t __xdata longDataReqCounter = 0;
|
||||
uint16_t __xdata voltageCheckCounter = 0;
|
||||
|
||||
void getExtraData(){
|
||||
batteryVoltage = epdGetBattery();
|
||||
temperature = adcSampleTemperature();
|
||||
pr("temp = %d volt = %d\n", temperature, batteryVoltage);
|
||||
extern int8_t adcSampleTemperature(void); // in degrees C
|
||||
|
||||
void initPowerSaving(uint16_t initialValue) {
|
||||
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
|
||||
dataReqAttemptArr[c] = initialValue;
|
||||
}
|
||||
}
|
||||
|
||||
void powerUp(uint8_t parts) {
|
||||
if (parts & INIT_BASE) {
|
||||
clockingAndIntsInit();
|
||||
timerInit();
|
||||
irqsOn();
|
||||
wdtOn();
|
||||
wdt10s();
|
||||
}
|
||||
|
||||
if (parts & INIT_GPIO)
|
||||
boardInit();
|
||||
|
||||
// init/sleep
|
||||
void initAfterWake() {
|
||||
clockingAndIntsInit();
|
||||
timerInit();
|
||||
// partialInit();
|
||||
boardInit();
|
||||
epdEnterSleep();
|
||||
irqsOn();
|
||||
boardInitStage2();
|
||||
getExtraData();
|
||||
initRadio();
|
||||
if (parts & INIT_EPD)
|
||||
epdSetup();
|
||||
|
||||
if ((parts & INIT_BASE) && !(parts & INIT_EPD_VOLTREADING) && !(parts & INIT_EPD)) {
|
||||
if (!(parts & INIT_GPIO))
|
||||
boardInit();
|
||||
epdEnterSleep(); // this required fixing! halp halp fix me
|
||||
}
|
||||
|
||||
if (parts & INIT_EPD_VOLTREADING) {
|
||||
if (!(parts & INIT_GPIO))
|
||||
boardInit();
|
||||
batteryVoltage = epdGetBattery();
|
||||
}
|
||||
|
||||
if (parts & INIT_UART) {
|
||||
uartInit();
|
||||
}
|
||||
|
||||
if (parts & INIT_EEPROM) {
|
||||
if (!eepromInit()) {
|
||||
powerDown(INIT_RADIO);
|
||||
powerUp(INIT_EPD);
|
||||
showNoEEPROM();
|
||||
powerDown(INIT_EEPROM | INIT_EPD | INIT_GPIO);
|
||||
doSleep(-1);
|
||||
wdtDeviceReset();
|
||||
}
|
||||
}
|
||||
|
||||
if (parts & INIT_TEMPREADING) {
|
||||
temperature = adcSampleTemperature();
|
||||
}
|
||||
|
||||
if (parts & INIT_RADIO) {
|
||||
radioInit();
|
||||
radioRxFilterCfg(mSelfMac, 0x10000, PROTO_PAN_ID);
|
||||
radioSetTxPower(10);
|
||||
if (currentChannel >= 11 && currentChannel <= 25) {
|
||||
radioSetChannel(currentChannel);
|
||||
} else {
|
||||
radioSetChannel(RADIO_FIRST_CHANNEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void powerDown(uint8_t parts) {
|
||||
if (parts & INIT_RADIO) {
|
||||
radioRxEnable(false, true);
|
||||
RADIO_IRQ4_pending = 0;
|
||||
UNK_C1 &= ~0x81;
|
||||
TCON &= ~0x20;
|
||||
uint8_t __xdata cfgPg = CFGPAGE;
|
||||
CFGPAGE = 4;
|
||||
RADIO_command = 0xCA;
|
||||
RADIO_command = 0xC5;
|
||||
CFGPAGE = cfgPg;
|
||||
}
|
||||
if (parts & INIT_EEPROM) {
|
||||
eepromDeepPowerDown();
|
||||
eepromPrvDeselect();
|
||||
}
|
||||
if (parts & INIT_EPD)
|
||||
epdEnterSleep();
|
||||
|
||||
if (parts & INIT_GPIO)
|
||||
powerPortsDownForSleep();
|
||||
}
|
||||
|
||||
void doSleep(uint32_t __xdata t) {
|
||||
if (t > 1000) pr("s=%lu\n ", t / 1000);
|
||||
powerPortsDownForSleep();
|
||||
// if (t > 1000) pr("s=%lu\n ", t / 1000);
|
||||
// powerPortsDownForSleep();
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
// Button setup on TEST pin 1.0 (input pullup)
|
||||
@@ -78,7 +143,6 @@ void doSleep(uint32_t __xdata t) {
|
||||
// sleepy
|
||||
sleepForMsec(t);
|
||||
wakeUpReason = WAKEUP_REASON_TIMED;
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
P1INTEN = 0;
|
||||
if (P1CHSTA && (1 << 0)) {
|
||||
@@ -87,26 +151,37 @@ void doSleep(uint32_t __xdata t) {
|
||||
P1CHSTA &= ~(1 << 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
initAfterWake();
|
||||
}
|
||||
uint16_t getNextSleep() {
|
||||
|
||||
uint32_t getNextScanSleep(bool increment) {
|
||||
if (increment) {
|
||||
if (scanAttempts < 255)
|
||||
scanAttempts++;
|
||||
}
|
||||
|
||||
if (scanAttempts < INTERVAL_1_ATTEMPTS) {
|
||||
return INTERVAL_1_TIME;
|
||||
} else if (scanAttempts < (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS)) {
|
||||
return INTERVAL_2_TIME;
|
||||
} else {
|
||||
return INTERVAL_3_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
void addAverageValue() {
|
||||
uint16_t __xdata curval = INTERVAL_AT_MAX_ATTEMPTS - INTERVAL_BASE;
|
||||
curval *= dataReqLastAttempt;
|
||||
curval /= DATA_REQ_MAX_ATTEMPTS;
|
||||
curval += INTERVAL_BASE;
|
||||
dataReqAttemptArr[dataReqAttemptArrayIndex % POWER_SAVING_SMOOTHING] = curval;
|
||||
dataReqAttemptArrayIndex++;
|
||||
}
|
||||
|
||||
uint16_t getNextSleep() {
|
||||
uint16_t avg = 0;
|
||||
bool noNetwork = true;
|
||||
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
|
||||
avg += dataReqAttemptArr[c];
|
||||
if (dataReqAttemptArr[c] != INTERVAL_AT_MAX_ATTEMPTS) {
|
||||
noNetwork = false;
|
||||
}
|
||||
}
|
||||
if (noNetwork == true) return INTERVAL_NO_SIGNAL;
|
||||
avg /= POWER_SAVING_SMOOTHING;
|
||||
return avg;
|
||||
}
|
||||
@@ -2,41 +2,76 @@
|
||||
#define _POWERMGT_H_
|
||||
#include <stdint.h>
|
||||
|
||||
#define WAKEUP_REASON_TIMED 0
|
||||
#define WAKEUP_REASON_BOOTUP 1
|
||||
#define WAKEUP_REASON_GPIO 2
|
||||
#define WAKEUP_REASON_NFC 3
|
||||
|
||||
#define WAKEUP_REASON_TIMED 0
|
||||
#define WAKEUP_REASON_BOOTUP 1
|
||||
#define WAKEUP_REASON_GPIO 2
|
||||
#define WAKEUP_REASON_NFC 3
|
||||
#define INIT_EPD_VOLTREADING 0x80
|
||||
#define INIT_RADIO 0x40
|
||||
#define INIT_GPIO 0x20
|
||||
#define INIT_UART 0x10
|
||||
#define INIT_EPD 0x08
|
||||
#define INIT_EEPROM 0x04
|
||||
#define INIT_TEMPREADING 0x02
|
||||
#define INIT_BASE 0x01
|
||||
|
||||
#define wdt10s() \
|
||||
do { \
|
||||
wdtSetResetVal(0xFFF68A1F); \
|
||||
} while (0)
|
||||
|
||||
#define wdt30s() \
|
||||
do { \
|
||||
wdtSetResetVal(0xFFE39E5F); \
|
||||
} while (0)
|
||||
|
||||
#define wdt60s() \
|
||||
do { \
|
||||
wdtSetResetVal(0xFFC73CBF); \
|
||||
} while (0)
|
||||
|
||||
// power saving algorithm
|
||||
#define INTERVAL_BASE 40 // interval (in seconds) (when 1 packet is sent/received) for target current (7.2µA)
|
||||
#define INTERVAL_AT_MAX_ATTEMPTS 600 // interval (in seconds) (at max attempts) for target average current
|
||||
#define INTERVAL_NO_SIGNAL 1800 // interval (in seconds) when no answer for POWER_SAVING_SMOOTHING attempts,
|
||||
// (INTERVAL_AT_MAX_ATTEMPTS * POWER_SAVING_SMOOTHING) seconds
|
||||
#define DATA_REQ_RX_WINDOW_SIZE 5UL // How many milliseconds we should wait for a packet during the data_request.
|
||||
// If the AP holds a long list of data for tags, it may need a little more time to lookup the mac address
|
||||
#define DATA_REQ_MAX_ATTEMPTS 14 // How many attempts (at most) we should do to get something back from the AP
|
||||
#define POWER_SAVING_SMOOTHING 8 // How many samples we should use to smooth the data request interval
|
||||
#define MINIMUM_INTERVAL 45 // IMPORTANT: Minimum interval for check-in; this determines overal battery life!
|
||||
|
||||
#define MAXIMUM_PING_ATTEMPTS 20 // How many attempts to discover an AP the tag should do
|
||||
#define PING_REPLY_WINDOW 2UL
|
||||
|
||||
#define LONG_DATAREQ_INTERVAL 300 // How often (in seconds, approximately) the tag should do a long datareq (including temperature)
|
||||
#define VOLTAGE_CHECK_INTERVAL 288 // How often the tag should do a battery voltage check (multiplied by LONG_DATAREQ_INTERVAL)
|
||||
|
||||
// power saving when no AP's were found (scanning every X)
|
||||
#define INTERVAL_1_TIME 3600UL // Try every hour
|
||||
#define INTERVAL_1_ATTEMPTS 24 // for 24 attempts (an entire day)
|
||||
#define INTERVAL_2_TIME 7200UL // Try every 2 hours
|
||||
#define INTERVAL_2_ATTEMPTS 12 // for 12 attempts (an additional day)
|
||||
#define INTERVAL_3_TIME 86400UL // Finally, try every day
|
||||
|
||||
extern void powerUp(uint8_t parts);
|
||||
extern void powerDown(uint8_t parts);
|
||||
|
||||
extern void initAfterWake();
|
||||
extern void doSleep(uint32_t __xdata t);
|
||||
|
||||
extern void addAverageValue();
|
||||
extern uint16_t getNextSleep();
|
||||
extern void initPowerSaving();
|
||||
extern void getExtraData();
|
||||
|
||||
extern uint32_t getNextScanSleep(bool increment);
|
||||
extern void initPowerSaving(uint16_t initialValue);
|
||||
|
||||
extern uint8_t __xdata wakeUpReason;
|
||||
|
||||
|
||||
extern uint16_t __xdata nextCheckInFromAP;
|
||||
extern uint8_t __xdata dataReqLastAttempt;
|
||||
extern int8_t __xdata temperature;
|
||||
extern uint16_t __xdata batteryVoltage;
|
||||
|
||||
extern uint8_t __xdata scanAttempts;
|
||||
extern uint16_t __xdata longDataReqCounter;
|
||||
extern uint16_t __xdata voltageCheckCounter;
|
||||
|
||||
#endif
|
||||
@@ -90,7 +90,7 @@ struct MacFrameBcast {
|
||||
uint8_t src[8];
|
||||
} __packed;
|
||||
|
||||
#define PKT_AVAIL_DATA_REQ_SHORT 0xE4
|
||||
#define PKT_AVAIL_DATA_SHORTREQ 0xE3
|
||||
#define PKT_AVAIL_DATA_REQ 0xE5
|
||||
#define PKT_AVAIL_DATA_INFO 0xE6
|
||||
#define PKT_BLOCK_PARTIAL_REQUEST 0xE7
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#ifndef SYNCED_H
|
||||
#define SYNCED_H
|
||||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define FW_VERSION 012 // version number (max 2.5.5 :) )
|
||||
#define FW_VERSION_SUFFIX "-rf15" // suffix, like -RC1 or whatever.
|
||||
#define FW_VERSION 013 // version number (max 2.5.5 :) )
|
||||
#define FW_VERSION_SUFFIX "-rf99" // suffix, like -RC1 or whatever.
|
||||
#define HAS_BUTTON // uncomment to enable reading a push button (connect between 'TEST' en 'GND' on the tag, along with a 100nF capacitor in parallel).
|
||||
// #define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers
|
||||
|
||||
#define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,5 @@
|
||||
#define __packed
|
||||
|
||||
#include "syncedproto.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
@@ -120,27 +121,6 @@ void addCRC(void *p, uint8_t len) {
|
||||
}
|
||||
|
||||
// radio stuff
|
||||
void initRadio() {
|
||||
radioInit();
|
||||
radioRxFilterCfg(mSelfMac, 0x10000, PROTO_PAN_ID);
|
||||
if (currentChannel >= 11 && currentChannel <= 25) {
|
||||
radioSetChannel(currentChannel);
|
||||
} else {
|
||||
radioSetChannel(RADIO_FIRST_CHANNEL);
|
||||
}
|
||||
radioSetTxPower(10);
|
||||
}
|
||||
void killRadio() {
|
||||
radioRxEnable(false, true);
|
||||
RADIO_IRQ4_pending = 0;
|
||||
UNK_C1 &= ~0x81;
|
||||
TCON &= ~0x20;
|
||||
uint8_t __xdata cfgPg = CFGPAGE;
|
||||
CFGPAGE = 4;
|
||||
RADIO_command = 0xCA;
|
||||
RADIO_command = 0xC5;
|
||||
CFGPAGE = cfgPg;
|
||||
}
|
||||
void sendPing() {
|
||||
struct MacFrameBcast __xdata *txframe = (struct MacFrameBcast *)(outBuffer + 1);
|
||||
memset(outBuffer, 0, sizeof(struct MacFrameBcast) + 2 + 4);
|
||||
@@ -160,8 +140,8 @@ void sendPing() {
|
||||
uint8_t detectAP(uint8_t channel) {
|
||||
uint32_t __xdata t;
|
||||
radioRxEnable(false, true);
|
||||
radioRxFlush();
|
||||
radioSetChannel(channel);
|
||||
radioRxFlush();
|
||||
radioRxEnable(true, true);
|
||||
for (uint8_t c = 1; c <= MAXIMUM_PING_ATTEMPTS; c++) {
|
||||
sendPing();
|
||||
@@ -184,6 +164,19 @@ uint8_t detectAP(uint8_t channel) {
|
||||
}
|
||||
|
||||
// data xfer stuff
|
||||
void sendShortAvailDataReq() {
|
||||
struct MacFrameBcast __xdata *txframe = (struct MacFrameBcast *)(outBuffer + 1);
|
||||
outBuffer[0] = sizeof(struct MacFrameBcast) + 1 + 2;
|
||||
outBuffer[sizeof(struct MacFrameBcast) + 1] = PKT_AVAIL_DATA_SHORTREQ;
|
||||
memcpy(txframe->src, mSelfMac, 8);
|
||||
outBuffer[1] = 0x21;
|
||||
outBuffer[2] = 0xC8; // quickly set txframe fcs structure for broadcast packet
|
||||
txframe->seq = seq++;
|
||||
txframe->dstPan = 0xFFFF;
|
||||
txframe->dstAddr = 0xFFFF;
|
||||
txframe->srcPan = PROTO_PAN_ID;
|
||||
commsTxNoCpy(outBuffer);
|
||||
}
|
||||
void sendAvailDataReq() {
|
||||
struct MacFrameBcast __xdata *txframe = (struct MacFrameBcast *)(outBuffer + 1);
|
||||
memset(outBuffer, 0, sizeof(struct MacFrameBcast) + sizeof(struct AvailDataReq) + 2 + 4);
|
||||
@@ -202,7 +195,7 @@ void sendAvailDataReq() {
|
||||
// TODO: send some (more) meaningful data
|
||||
availreq->hwType = HW_TYPE;
|
||||
availreq->wakeupReason = wakeUpReason;
|
||||
availreq->lastPacketRSSI = (uint8_t)(-1*mLastRSSI);
|
||||
availreq->lastPacketRSSI = mLastRSSI;
|
||||
availreq->lastPacketLQI = mLastLqi;
|
||||
availreq->temperature = temperature;
|
||||
availreq->batteryMv = batteryVoltage;
|
||||
@@ -210,6 +203,7 @@ void sendAvailDataReq() {
|
||||
commsTxNoCpy(outBuffer);
|
||||
}
|
||||
struct AvailDataInfo *__xdata getAvailDataInfo() {
|
||||
radioRxEnable(true, true);
|
||||
uint32_t __xdata t;
|
||||
for (uint8_t c = 0; c < DATA_REQ_MAX_ATTEMPTS; c++) {
|
||||
sendAvailDataReq();
|
||||
@@ -232,6 +226,31 @@ struct AvailDataInfo *__xdata getAvailDataInfo() {
|
||||
dataReqLastAttempt = DATA_REQ_MAX_ATTEMPTS;
|
||||
return NULL;
|
||||
}
|
||||
struct AvailDataInfo *__xdata getShortAvailDataInfo() {
|
||||
radioRxEnable(true, true);
|
||||
uint32_t __xdata t;
|
||||
for (uint8_t c = 0; c < DATA_REQ_MAX_ATTEMPTS; c++) {
|
||||
sendShortAvailDataReq();
|
||||
// sendAvailDataReq();
|
||||
t = timerGet() + (TIMER_TICKS_PER_MS * DATA_REQ_RX_WINDOW_SIZE);
|
||||
while (timerGet() < t) {
|
||||
int8_t __xdata ret = commsRxUnencrypted(inBuffer);
|
||||
if (ret > 1) {
|
||||
if (getPacketType(inBuffer) == PKT_AVAIL_DATA_INFO) {
|
||||
if (checkCRC(inBuffer + sizeof(struct MacFrameNormal) + 1, sizeof(struct AvailDataInfo))) {
|
||||
struct MacFrameNormal *__xdata f = (struct MacFrameNormal *)inBuffer;
|
||||
memcpy(APmac, f->src, 8);
|
||||
APsrcPan = f->pan;
|
||||
dataReqLastAttempt = c;
|
||||
return (struct AvailDataInfo *)(inBuffer + sizeof(struct MacFrameNormal) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dataReqLastAttempt = DATA_REQ_MAX_ATTEMPTS;
|
||||
return NULL;
|
||||
}
|
||||
bool processBlockPart(struct blockPart *bp) {
|
||||
uint16_t __xdata start = bp->blockPart * BLOCK_PART_DATA_SIZE;
|
||||
uint16_t __xdata size = BLOCK_PART_DATA_SIZE;
|
||||
@@ -438,8 +457,7 @@ void drawImageFromEeprom() {
|
||||
wdtSetResetVal(0xFFFFFFFF - 0x38C340);
|
||||
wdtOn();
|
||||
drawImageAtAddress(getAddressForSlot(curImgSlot));
|
||||
// adcSampleBattery();
|
||||
initRadio();
|
||||
powerDown(INIT_EPD);
|
||||
}
|
||||
uint32_t getHighSlotId() {
|
||||
uint32_t temp = 0;
|
||||
@@ -483,15 +501,18 @@ bool doDataDownload(struct AvailDataInfo *__xdata avail) {
|
||||
if (curXferComplete && 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("old ver, already downloaded!\n");
|
||||
powerUp(INIT_RADIO);
|
||||
sendXferComplete();
|
||||
powerDown(INIT_RADIO);
|
||||
return true;
|
||||
} else {
|
||||
// check if we've seen this version before
|
||||
curImgSlot = findSlot(&(avail->dataVer));
|
||||
if (curImgSlot != 0xFF) {
|
||||
// found a (complete)valid image slot for this version
|
||||
powerDown(INIT_RADIO);
|
||||
sendXferComplete();
|
||||
killRadio();
|
||||
powerDown(INIT_RADIO);
|
||||
|
||||
pr("already seen, drawing from eeprom slot %d\n", curImgSlot);
|
||||
|
||||
@@ -551,6 +572,7 @@ bool doDataDownload(struct AvailDataInfo *__xdata avail) {
|
||||
while (!curXferComplete) {
|
||||
// this while loop loops until the transfer has been completed, or we get tired for other reasons
|
||||
startdownload:;
|
||||
wdt10s();
|
||||
#ifndef DEBUGBLOCKS
|
||||
pr("REQ %d ", curBlock.blockId);
|
||||
#endif
|
||||
@@ -571,6 +593,7 @@ bool doDataDownload(struct AvailDataInfo *__xdata avail) {
|
||||
// timerDelay(TIMER_TICKS_PER_MS*100);
|
||||
|
||||
// DO BLOCK REQUEST - request a block, get an ack with timing info (hopefully)
|
||||
powerUp(INIT_RADIO);
|
||||
struct blockRequestAck *__xdata ack = performBlockRequest();
|
||||
if (ack == NULL) {
|
||||
pr("Cancelled request\n");
|
||||
@@ -583,7 +606,9 @@ bool doDataDownload(struct AvailDataInfo *__xdata avail) {
|
||||
if (ack->pleaseWaitMs < 35) {
|
||||
timerDelay(ack->pleaseWaitMs * TIMER_TICKS_PER_MS);
|
||||
} else {
|
||||
powerDown(INIT_GPIO);
|
||||
doSleep(ack->pleaseWaitMs - 10);
|
||||
powerUp(INIT_BASE | INIT_GPIO | INIT_UART | INIT_RADIO);
|
||||
radioRxEnable(true, true);
|
||||
}
|
||||
} else {
|
||||
@@ -594,6 +619,7 @@ bool doDataDownload(struct AvailDataInfo *__xdata avail) {
|
||||
// didn't receive packets
|
||||
blockRequestAttempt++;
|
||||
if (blockRequestAttempt > 5) {
|
||||
powerDown(INIT_RADIO);
|
||||
pr("bailing on download, 0 blockparts rx'd\n");
|
||||
return false;
|
||||
}
|
||||
@@ -601,7 +627,7 @@ bool doDataDownload(struct AvailDataInfo *__xdata avail) {
|
||||
// successfull block RX loop
|
||||
blockRequestAttempt = 0;
|
||||
}
|
||||
|
||||
powerDown(INIT_RADIO);
|
||||
#ifdef DEBUGBLOCKS
|
||||
pr("RX %d[", curBlock.blockId);
|
||||
for (uint8_t c = 0; c < BLOCK_MAX_PARTS; c++) {
|
||||
@@ -695,19 +721,23 @@ bool doDataDownload(struct AvailDataInfo *__xdata avail) {
|
||||
eepromWrite(getAddressForSlot(curImgSlot), eih, sizeof(struct EepromImageHeader));
|
||||
// pr("transfer complete!");
|
||||
curXferComplete = true;
|
||||
powerUp(INIT_RADIO);
|
||||
sendXferComplete();
|
||||
killRadio();
|
||||
powerDown(INIT_RADIO);
|
||||
wdt60s();
|
||||
drawImageFromEeprom();
|
||||
curDataInfo.dataVer = 0xAA;
|
||||
break;
|
||||
case DATATYPE_UPDATE:
|
||||
pr("firmware download complete, doing update.\n");
|
||||
powerUp(INIT_EPD);
|
||||
showApplyUpdate();
|
||||
curXferComplete = true;
|
||||
powerUp(INIT_RADIO);
|
||||
sendXferComplete();
|
||||
killRadio();
|
||||
powerDown(INIT_RADIO);
|
||||
wdt60s();
|
||||
eepromReadStart(EEPROM_UPDATA_AREA_START);
|
||||
// wdtDeviceReset();
|
||||
selfUpdate();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
#define SYNCED_H
|
||||
|
||||
#include <stdint.h>
|
||||
//#include "settings.h"
|
||||
|
||||
|
||||
extern uint8_t __xdata mSelfMac[8];
|
||||
extern uint8_t __xdata mSelfMac[];
|
||||
extern uint8_t __xdata currentChannel;
|
||||
extern uint8_t __xdata APmac[];
|
||||
|
||||
extern void initRadio();
|
||||
extern void killRadio();
|
||||
extern void setupRadio(void);
|
||||
extern void killRadio(void);
|
||||
|
||||
|
||||
extern struct AvailDataInfo *__xdata getAvailDataInfo();
|
||||
extern struct AvailDataInfo *__xdata getShortAvailDataInfo();
|
||||
extern bool doDataDownload(struct AvailDataInfo *__xdata avail);
|
||||
extern void initializeProto();
|
||||
extern struct AvailDataInfo *__xdata getAvailDataInfo();
|
||||
uint8_t detectAP(uint8_t channel);
|
||||
extern uint8_t detectAP(uint8_t channel);
|
||||
|
||||
#endif
|
||||
@@ -25,12 +25,10 @@ extern uint8_t __xdata mSelfMac[8];
|
||||
extern uint8_t __xdata currentChannel;
|
||||
extern uint8_t __xdata APmac[];
|
||||
|
||||
static const uint8_t __code fwVersion = FW_VERSION;
|
||||
static const char __code fwVersionSuffix[] = FW_VERSION_SUFFIX;
|
||||
const uint8_t __code fwVersion = FW_VERSION;
|
||||
const char __code fwVersionSuffix[] = FW_VERSION_SUFFIX;
|
||||
|
||||
void showSplashScreen() {
|
||||
epdSetup();
|
||||
|
||||
#if (SCREEN_WIDTH == 152) // 1.54"
|
||||
clearScreen();
|
||||
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
|
||||
@@ -52,7 +50,7 @@ void showSplashScreen() {
|
||||
epdPrintBegin(2, 120, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("zbs154v033 %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
epdPrintEnd();
|
||||
draw();
|
||||
|
||||
#endif
|
||||
|
||||
#if (SCREEN_WIDTH == 128) // 2.9"
|
||||
@@ -88,7 +86,6 @@ void showSplashScreen() {
|
||||
// drawLineVertical(EPD_COLOR_RED, 64, 10, 286);
|
||||
// drawLineVertical(EPD_COLOR_BLACK, 65, 10, 286);
|
||||
|
||||
draw();
|
||||
// timerDelay(TIMER_TICKS_PER_SECOND * 4);
|
||||
#endif
|
||||
#if (SCREEN_WIDTH == 400) // 2.9"
|
||||
@@ -120,14 +117,12 @@ void showSplashScreen() {
|
||||
loadRawBitmap(solum, 253, 72, EPD_COLOR_BLACK);
|
||||
loadRawBitmap(hacked, 261, 82, EPD_COLOR_RED);
|
||||
|
||||
draw();
|
||||
#endif
|
||||
drawWithSleep();
|
||||
}
|
||||
|
||||
void showApplyUpdate() {
|
||||
epdSetup();
|
||||
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
|
||||
|
||||
selectLUT(1);
|
||||
clearScreen();
|
||||
setColorMode(EPD_MODE_IGNORE, EPD_MODE_NORMAL);
|
||||
@@ -140,7 +135,6 @@ void showApplyUpdate() {
|
||||
uint8_t __xdata resultcounter = 0;
|
||||
|
||||
void showScanningWindow() {
|
||||
epdSetup();
|
||||
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
|
||||
selectLUT(EPD_LUT_FAST_NO_REDS);
|
||||
clearScreen();
|
||||
@@ -180,8 +174,9 @@ void addScanResult(uint8_t channel, uint8_t lqi) {
|
||||
}
|
||||
|
||||
void showAPFound() {
|
||||
selectLUT(EPD_LUT_FAST_NO_REDS);
|
||||
clearScreen();
|
||||
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
|
||||
selectLUT(1);
|
||||
#if (SCREEN_WIDTH == 128)
|
||||
epdPrintBegin(0, 285, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("Waiting for data...");
|
||||
@@ -247,7 +242,7 @@ void showAPFound() {
|
||||
epdpr("%02X%02X", mSelfMac[1], mSelfMac[0]);
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
draw();
|
||||
drawWithSleep();
|
||||
}
|
||||
|
||||
void showNoAP() {
|
||||
@@ -281,5 +276,62 @@ void showNoAP() {
|
||||
epdpr("a little while");
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
draw();
|
||||
drawWithSleep();
|
||||
}
|
||||
|
||||
void showNoEEPROM() {
|
||||
selectLUT(EPD_LUT_NO_REPEATS);
|
||||
clearScreen();
|
||||
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
|
||||
#if (SCREEN_WIDTH == 128) // 2.9"
|
||||
epdPrintBegin(0, 285, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("EEPROM FAILED :(");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(64, 285, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("Sleeping forever :'(");
|
||||
epdPrintEnd();
|
||||
loadRawBitmap(failed, 42, 26, EPD_COLOR_RED);
|
||||
#endif
|
||||
#if (SCREEN_WIDTH == 152) // 1.54"
|
||||
epdPrintBegin(26, 0, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("EEPROM ");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(8, 32, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("FAILED :(");
|
||||
epdPrintEnd();
|
||||
loadRawBitmap(failed, 60, 72, EPD_COLOR_RED);
|
||||
|
||||
epdPrintBegin(3, 136, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("Sleeping forever :'(");
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
drawWithSleep();
|
||||
}
|
||||
|
||||
void showNoMAC() {
|
||||
selectLUT(EPD_LUT_NO_REPEATS);
|
||||
clearScreen();
|
||||
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
|
||||
#if (SCREEN_WIDTH == 128) // 2.9"
|
||||
epdPrintBegin(0, 285, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("NO MAC SET :(");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(64, 285, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("Sleeping forever :'(");
|
||||
epdPrintEnd();
|
||||
loadRawBitmap(failed, 42, 26, EPD_COLOR_RED);
|
||||
#endif
|
||||
#if (SCREEN_WIDTH == 152) // 1.54"
|
||||
epdPrintBegin(20, 0, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("NO MAC");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(30, 32, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("SET :(");
|
||||
epdPrintEnd();
|
||||
loadRawBitmap(failed, 60, 72, EPD_COLOR_RED);
|
||||
epdPrintBegin(3, 136, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("Sleeping forever :'(");
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
drawWithSleep();
|
||||
}
|
||||
@@ -8,4 +8,10 @@ void showScanningWindow();
|
||||
void addScanResult(uint8_t channel, uint8_t lqi);
|
||||
void showAPFound();
|
||||
void showNoAP();
|
||||
void showNoEEPROM();
|
||||
void showNoMAC();
|
||||
|
||||
|
||||
extern const uint8_t __code fwVersion;
|
||||
extern const char __code fwVersionSuffix[];
|
||||
#endif
|
||||
Reference in New Issue
Block a user