From e5c06b39b414d9bbebc2b09b4e83a5fde7104e3b Mon Sep 17 00:00:00 2001 From: Jelmer Date: Sat, 11 Mar 2023 13:39:22 +0100 Subject: [PATCH] working mesh --- ap_fw/main.c | 43 +++++++++++++++- tag_fw/main.c | 110 ++++++++++++++++++++++++++++++++++++++-- tag_fw/proto.h | 30 +++++++---- tag_fw/syncedproto.c | 111 +++++++++++++++++++++++++++++++++++++++-- tag_fw/syncedproto.h | 6 +++ tag_fw/userinterface.c | 25 +++++++++- tag_fw/userinterface.h | 5 ++ 7 files changed, 310 insertions(+), 20 deletions(-) diff --git a/ap_fw/main.c b/ap_fw/main.c index 9adf2766..058c161a 100644 --- a/ap_fw/main.c +++ b/ap_fw/main.c @@ -53,6 +53,16 @@ struct MacFrameBcast { #define PKT_PING 0xED #define PKT_PONG 0xEE +#define PKT_EVENT_PONG 0xC1 +#define PKT_EVENT_DATA_REQ 0xC2 +#define PKT_EVENT_DATA 0xC3 + +struct eventData { + uint8_t checksum; + uint8_t eventDataID; + uint8_t data[]; +} __packed; + struct AvailDataReq { uint8_t checksum; uint8_t lastPacketLQI; @@ -169,6 +179,9 @@ uint8_t seq = 0; // holds current sequence uint8_t __xdata blockbuffer[BLOCK_XFER_BUFFER_SIZE]; // block transfer buffer uint8_t lastAckMac[8] = {0}; +uint8_t* eventDataBuffer = blockbuffer+1024; +bool __xdata eventMode = true; + // these variables hold the current mac were talking to #define CONCURRENT_REQUEST_DELAY 1200UL * TIMER_TICKS_PER_MS uint32_t __xdata lastBlockRequest = 0; @@ -643,7 +656,11 @@ void sendCancelXfer(uint8_t *dst) { void sendPong(void *__xdata buf) { struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buf; struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1); - radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_PONG; + if (eventMode) { + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_EVENT_PONG; + } else { + 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); @@ -654,6 +671,27 @@ void sendPong(void *__xdata buf) { radioTx(radiotxbuffer); } +#define EVENT_PKT_SIZE 100 + +void sendEventData(void *__xdata buf) { + struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buf; + struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1); + struct eventData *ed = (struct eventData *)(radiotxbuffer + sizeof(struct MacFrameNormal) + 2); + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_EVENT_DATA; + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct eventData) + EVENT_PKT_SIZE + RAW_PKT_PADDING; + memcpy(ed, eventDataBuffer, sizeof(struct eventData) + EVENT_PKT_SIZE); + addCRC(ed, sizeof(struct eventData) + EVENT_PKT_SIZE); + memcpy(frameHeader->src, mSelfMac, 8); + memcpy(frameHeader->dst, rxframe->src, 8); + radiotxbuffer[1] = 0x41; // fast way to set the appropriate bits + radiotxbuffer[2] = 0xCC; // normal frame + frameHeader->seq = seq++; + frameHeader->pan = rxframe->srcPan; + radioTx(radiotxbuffer); +} + + + // main loop void main(void) { clockingAndIntsInit(); @@ -715,6 +753,9 @@ void main(void) { case PKT_XFER_COMPLETE: processXferComplete(radiorxbuffer); break; + case PKT_EVENT_DATA_REQ: + sendEventData(radiorxbuffer); + break; case PKT_PING: sendPong(radiorxbuffer); break; diff --git a/tag_fw/main.c b/tag_fw/main.c index 4b755a57..cf5ea6f4 100644 --- a/tag_fw/main.c +++ b/tag_fw/main.c @@ -8,11 +8,11 @@ #include "asmUtil.h" #include "comms.h" // for mLastLqi and mLastRSSI #include "eeprom.h" -#include "screen.h" #include "powermgt.h" #include "printf.h" #include "proto.h" #include "radio.h" +#include "screen.h" #include "settings.h" #include "syncedproto.h" #include "timer.h" @@ -21,8 +21,26 @@ // #define DEBUG_MODE +void eventMode(); + void displayLoop() { - powerUp(INIT_BASE | INIT_UART | INIT_GPIO); + while (1) { + wdt120s(); + pr("Splash screen\n"); + powerUp(INIT_EPD); + showSplashScreen(); + timerDelay(TIMER_TICKS_PER_SECOND * 4); + wdt120s(); + pr("Event screen1\n"); + powerUp(INIT_EPD); + eventUpdateScreen(); + timerDelay(TIMER_TICKS_PER_SECOND * 4); + wdt120s(); + pr("Event screen2\n"); + powerUp(INIT_EPD); + eventScreen(); + timerDelay(TIMER_TICKS_PER_SECOND * 4); + } pr("Splash screen\n"); powerUp(INIT_EPD); @@ -98,6 +116,13 @@ uint8_t showChannelSelect() { // returns 0 if no accesspoints were found if (mLastLqi > result[c - 11]) result[c - 11] = mLastLqi; pr("Channel: %d - LQI: %d RSSI %d\n", c, mLastLqi, mLastRSSI); } + if (eventModeActive) { + // if event mode became active, skip the rest of the scan and go straight to event mode + epdWaitRdy(); + powerDown(INIT_RADIO); + // skip the rest of the scan if + return c; + } } epdWaitRdy(); for (uint8_t c = 0; c < 16; c++) { @@ -142,10 +167,11 @@ uint8_t channelSelect() { // returns 0 if no accesspoints were found } void main() { - // displayLoop(); // remove me setupPortsInitial(); powerUp(INIT_BASE | INIT_UART); + // displayLoop(); // remove me + if (RESET & 0x01) { wakeUpReason = WAKEUP_REASON_WDT_RESET; pr("WDT reset!\n"); @@ -194,6 +220,7 @@ void main() { // show the splashscreen powerUp(INIT_EPD); + showSplashScreen(); powerUp(INIT_EPD); @@ -202,6 +229,11 @@ void main() { wdt10s(); + if (eventModeActive) { + // skip straight to event mode + eventMode(); + } + if (currentChannel) { showAPFound(); initPowerSaving(INTERVAL_BASE); @@ -220,7 +252,7 @@ void main() { if (currentChannel) { // associated - struct AvailDataInfo *__xdata avail; + 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) { // check if we should do a voltage measurement (those are pretty expensive) @@ -341,3 +373,73 @@ void main() { } } } + +#define EVENT_POLL_INTERVAL 5000 +uint8_t __xdata eventDataID = 0; + +void eventMode() { + powerUp(INIT_EPD); + setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT); + selectLUT(EPD_LUT_FAST_NO_REDS); + clearScreen(); + epdPrintBegin(0, 60, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK); + epdpr("EventMode"); + epdPrintEnd(); + drawWithSleep(); + powerDown(INIT_EPD); + + doSleep(1000); + + uint16_t __xdata failedCount = 0; + + // display welcome! + + while (failedCount < 17280) { // 24 hours at 5 second intervals + wdt10s(); + powerUp(INIT_RADIO | INIT_UART); + struct eventData* __xdata ed = getEventData(); + powerDown(INIT_RADIO); + + if (ed == NULL) { + failedCount++; + } else { + // eventdata is copied to blockXferBuffer, gets picked up from + failedCount = 0; + + // check if should display this data, and make it available to other tags + if ((ed->eventDataID > eventDataID) || (ed->eventDataID - eventDataID > 128)) { + eventDataID = ed->eventDataID; + + // display event logo while we run the AP (we could just skip straight to showing the data, but where's the fun in that) + powerUp(INIT_EPD); + eventUpdateScreen(); + + wdt30s(); + // enter AP mode + pr("AP enabled\n"); + powerUp(INIT_RADIO); + eventAPMode(); + powerDown(INIT_RADIO); + pr("AP disabled\n"); + + // for good measure, check if the EPD was ready with the picture + epdWaitRdy(); + + wdt10s(); + // display new data + eventScreen(); + powerDown(INIT_EPD); + } else { + // ignore + } + } + doSleep(EVENT_POLL_INTERVAL); + } + + // display thank you blah + + while (1) { + // sleep forever + doSleep(-1); + } +} \ No newline at end of file diff --git a/tag_fw/proto.h b/tag_fw/proto.h index 2ee3da03..8eb6209e 100644 --- a/tag_fw/proto.h +++ b/tag_fw/proto.h @@ -103,6 +103,10 @@ struct MacFrameBcast { #define PKT_PING 0xED #define PKT_PONG 0xEE +#define PKT_EVENT_PONG 0xC1 +#define PKT_EVENT_DATA_REQ 0xC2 +#define PKT_EVENT_DATA 0xC3 + struct AvailDataReq { uint8_t checksum; uint8_t lastPacketLQI; @@ -111,28 +115,26 @@ 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_BMP 2 #define DATATYPE_FW_UPDATE 3 -#define DATATYPE_IMG_DIFF 0x10 // always 1BPP -#define DATATYPE_IMG_RAW_1BPP 0x20 // 2888 bytes for 1.54" / 4736 2.9" / 15000 4.2" -#define DATATYPE_IMG_RAW_2BPP 0x21 // 5776 bytes for 1.54" / 9472 2.9" / 30000 4.2" -#define DATATYPE_IMG_RAW_1BPP_DIRECT 0x3F // only for 1.54", don't write to EEPROM, but straightaway to the EPD +#define DATATYPE_IMG_DIFF 0x10 // always 1BPP +#define DATATYPE_IMG_RAW_1BPP 0x20 // 2888 bytes for 1.54" / 4736 2.9" / 15000 4.2" +#define DATATYPE_IMG_RAW_2BPP 0x21 // 5776 bytes for 1.54" / 9472 2.9" / 30000 4.2" +#define DATATYPE_IMG_RAW_1BPP_DIRECT 0x3F // only for 1.54", don't write to EEPROM, but straightaway to the EPD struct AvailDataInfo { uint8_t checksum; - uint64_t dataVer; // MD5 of potential traffic - uint32_t dataSize; - uint8_t dataType; + uint64_t dataVer; // MD5 of potential traffic + uint32_t dataSize; + uint8_t dataType; 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; @@ -151,6 +153,12 @@ struct burstMacData { uint8_t targetMac[8]; } __packed; +struct eventData { + uint8_t checksum; + uint8_t eventDataID; + uint8_t data[]; +} __packed; + #define BLOCK_PART_DATA_SIZE 99 #define BLOCK_MAX_PARTS 42 #define BLOCK_DATA_SIZE 4096UL diff --git a/tag_fw/syncedproto.c b/tag_fw/syncedproto.c index 5a1f950f..c10760d5 100644 --- a/tag_fw/syncedproto.c +++ b/tag_fw/syncedproto.c @@ -18,12 +18,12 @@ #include "printf.h" #include "proto.h" #include "radio.h" +#include "screen.h" #include "settings.h" #include "sleep.h" #include "timer.h" #include "userinterface.h" #include "wdt.h" -#include "screen.h" // download-stuff uint8_t __xdata blockXferBuffer[BLOCK_XFER_BUFFER_SIZE] = {0}; @@ -46,6 +46,9 @@ uint8_t __xdata mSelfMac[8] = {0}; static uint8_t __xdata seq = 0; uint8_t __xdata currentChannel = 0; +// check if we're in event mode +bool __xdata eventModeActive = false; + // buffer we use to prepare/read packets static uint8_t __xdata inBuffer[128] = {0}; static uint8_t __xdata outBuffer[128] = {0}; @@ -150,6 +153,12 @@ uint8_t detectAP(const uint8_t channel) { return c; } } + if (getPacketType(inBuffer) == PKT_EVENT_PONG) { + if (pktIsUnicast(inBuffer)) { + eventModeActive = true; + return c; + } + } } } } @@ -479,7 +488,7 @@ static bool getDataBlock(const uint16_t blockSize) { partsThisBlock = BLOCK_MAX_PARTS; memset(curBlock.requestedParts, 0xFF, BLOCK_REQ_PARTS_BYTES); } else { - partsThisBlock = (sizeof(struct blockData)+blockSize) / BLOCK_PART_DATA_SIZE; + partsThisBlock = (sizeof(struct blockData) + blockSize) / BLOCK_PART_DATA_SIZE; if (blockSize % BLOCK_PART_DATA_SIZE) partsThisBlock++; memset(curBlock.requestedParts, 0x00, BLOCK_REQ_PARTS_BYTES); for (uint8_t c = 0; c < partsThisBlock; c++) { @@ -698,7 +707,7 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { } xMemCopyShort(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo)); if (avail->dataSize > 4096) avail->dataSize = 4096; - + if (getDataBlock(avail->dataSize)) { powerUp(INIT_RADIO); sendXferComplete(); @@ -799,4 +808,100 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) { void initializeProto() { getNumSlots(); curHighSlotId = getHighSlotId(); +} + +// event mode +#define EVENT_AP_TIME 10 +#define RAW_PKT_PADDING 2 +#define EVENT_PKT_SIZE 100 +#define EVENT_DATA_REQ_RX_WINDOW_SIZE 10 + +static void sendEventPong(const void *__xdata buf) { + struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buf; + struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(outBuffer + 1); + outBuffer[sizeof(struct MacFrameNormal) + 1] = PKT_EVENT_PONG; + outBuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING; + memcpy(frameHeader->src, mSelfMac, 8); + memcpy(frameHeader->dst, rxframe->src, 8); + outBuffer[1] = 0x41; // fast way to set the appropriate bits + outBuffer[2] = 0xCC; // normal frame + frameHeader->seq = seq++; + frameHeader->pan = rxframe->srcPan; + radioTx(outBuffer); +} +static void sendEventDataReply(const void *__xdata buf) { + struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buf; + struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(outBuffer + 1); + struct eventData *eventData = (struct eventData *)(outBuffer + sizeof(struct MacFrameNormal) + 2); + memset(outBuffer + 1, 0, sizeof(struct eventData) + sizeof(struct MacFrameNormal)); + outBuffer[sizeof(struct MacFrameNormal) + 1] = PKT_EVENT_DATA; + outBuffer[0] = sizeof(struct MacFrameNormal) + sizeof(struct eventData) + EVENT_PKT_SIZE + 1 + RAW_PKT_PADDING; + memcpy(frameHeader->src, mSelfMac, 8); + memcpy(frameHeader->dst, rxframe->src, 8); + memcpy(eventData, blockXferBuffer, sizeof(struct eventData) + EVENT_PKT_SIZE); + addCRC(eventData, sizeof(struct eventData) + EVENT_PKT_SIZE); + frameHeader->fcs.frameType = 1; + frameHeader->fcs.panIdCompressed = 1; + frameHeader->fcs.destAddrType = 3; + frameHeader->fcs.srcAddrType = 3; + frameHeader->seq = seq++; + frameHeader->pan = rxframe->srcPan; + radioTx(outBuffer); +} +void eventAPMode() { + radioRxEnable(true, true); + uint32_t __xdata APTime = timerGet(); + while ((timerGet() - APTime) < (TIMER_TICKS_PER_SECOND * EVENT_AP_TIME)) { + int8_t ret = commsRxUnencrypted(inBuffer); + if (ret > 1) { + // received a packet, lets see what it is + switch (getPacketType(inBuffer)) { + case PKT_PING: + pr("pong rx\n"); + sendEventPong(inBuffer); + break; + case PKT_EVENT_DATA_REQ: + pr("event data reply\n"); + sendEventDataReply(inBuffer); + break; + } + } + } +} +static void sendEventDataReq() { + struct MacFrameBcast __xdata *txframe = (struct MacFrameBcast *)(outBuffer + 1); + memset(outBuffer, 0, sizeof(struct MacFrameBcast) + sizeof(struct AvailDataReq) + 2 + 4); + outBuffer[0] = sizeof(struct MacFrameBcast) + 2 + 2; + outBuffer[sizeof(struct MacFrameBcast) + 1] = PKT_EVENT_DATA_REQ; + memcpy(txframe->src, mSelfMac, 8); + txframe->fcs.frameType = 1; + txframe->fcs.ackReqd = 1; + txframe->fcs.destAddrType = 2; + txframe->fcs.srcAddrType = 3; + txframe->seq = seq++; + txframe->dstPan = PROTO_PAN_ID; + txframe->dstAddr = 0xFFFF; + txframe->srcPan = PROTO_PAN_ID; + commsTxNoCpy(outBuffer); +} +struct eventData *__xdata getEventData() { + radioRxEnable(true, true); + uint32_t __xdata t; + for (uint8_t c = 0; c < DATA_REQ_MAX_ATTEMPTS; c++) { + sendEventDataReq(); + t = timerGet() + (TIMER_TICKS_PER_MS * EVENT_DATA_REQ_RX_WINDOW_SIZE); + while (timerGet() < t) { + int8_t __xdata ret = commsRxUnencrypted(inBuffer); + if (ret > 1) { + if (getPacketType(inBuffer) == PKT_EVENT_DATA) { + if (checkCRC(inBuffer + sizeof(struct MacFrameNormal) + 1, sizeof(struct eventData) + EVENT_PKT_SIZE)) { + struct MacFrameNormal *__xdata f = (struct MacFrameNormal *)inBuffer; + memcpy(blockXferBuffer, inBuffer + sizeof(struct MacFrameNormal) + 1, 128); + return (struct eventData *)(inBuffer + sizeof(struct MacFrameNormal) + 1); + } + } + } + } + } + return NULL; } \ No newline at end of file diff --git a/tag_fw/syncedproto.h b/tag_fw/syncedproto.h index fe39ec87..21902848 100644 --- a/tag_fw/syncedproto.h +++ b/tag_fw/syncedproto.h @@ -21,4 +21,10 @@ extern bool processAvailDataInfo(struct AvailDataInfo *__xdata avail); extern void initializeProto(); extern uint8_t detectAP(const uint8_t channel); + +extern uint8_t __xdata eventDataID; +extern bool __xdata eventModeActive; +struct eventData *__xdata getEventData(); +void eventAPMode(); + #endif \ No newline at end of file diff --git a/tag_fw/userinterface.c b/tag_fw/userinterface.c index 11b994c0..bb072f09 100644 --- a/tag_fw/userinterface.c +++ b/tag_fw/userinterface.c @@ -63,6 +63,29 @@ void addOverlay() { } } +void eventUpdateScreen() { + selectLUT(EPD_LUT_FAST_NO_REDS); + clearScreen(); + setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT); + loadRawBitmap(hackaday, 0, 0, EPD_COLOR_BLACK); + drawNoWait(); +} + +extern uint8_t __xdata blockXferBuffer[]; + +void eventScreen() { + selectLUT(EPD_LUT_NO_REPEATS); + clearScreen(); + setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT); + loadRawBitmap(hadberlin, 0, 0, EPD_COLOR_BLACK); + + epdPrintBegin(2, 120, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK); + epdpr("ID=%d",blockXferBuffer[1]); + epdPrintEnd(); + + drawWithSleep(); +} + void showSplashScreen() { selectLUT(EPD_LUT_NO_REPEATS); clearScreen(); @@ -421,7 +444,7 @@ void showNoEEPROM() { epdPrintEnd(); #endif #if (SCREEN_WIDTH == 400) // 4.2" - epdPrintBegin(50 , 3, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK); + epdPrintBegin(50, 3, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK); epdpr("EEPROM FAILED :("); epdPrintEnd(); loadRawBitmap(failed, 176, 126, EPD_COLOR_RED); diff --git a/tag_fw/userinterface.h b/tag_fw/userinterface.h index 2149de35..11d41a86 100644 --- a/tag_fw/userinterface.h +++ b/tag_fw/userinterface.h @@ -14,6 +14,11 @@ void showLongTermSleep(); void showNoEEPROM(); void showNoMAC(); +void eventUpdateScreen(); +void eventScreen(); + + + extern const uint8_t __code fwVersion; extern const char __code fwVersionSuffix[]; extern bool __xdata lowBatteryShown;