working mesh

This commit is contained in:
Jelmer
2023-03-11 13:39:22 +01:00
parent daea208c50
commit e5c06b39b4
7 changed files with 310 additions and 20 deletions

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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;