the ESP32 can now tell the AP data isn't available

This commit is contained in:
Jelmer
2023-01-22 00:07:24 +01:00
parent 2b89919d00
commit 532ca354e2
2 changed files with 95 additions and 39 deletions

View File

@@ -49,6 +49,7 @@ struct MacFrameBcast {
#define PKT_BLOCK_PART 0xE8
#define PKT_XFER_COMPLETE 0xEA
#define PKT_XFER_COMPLETE_ACK 0xEB
#define PKT_CANCEL_XFER 0xEC
struct AvailDataReq {
uint8_t checksum;
@@ -113,7 +114,6 @@ struct blockRequest {
struct blockRequestAck {
uint8_t checksum;
uint16_t pleaseWaitMs;
uint8_t cancelXfer;
} __packed;
struct espPendingData {
@@ -169,7 +169,9 @@ uint32_t __xdata nextBlockAttempt = 0; // reference time for when
uint8_t seq = 0; // holds current sequence number for transmission
uint8_t __xdata blockbuffer[BLOCK_XFER_BUFFER_SIZE]; // block transfer buffer
uint8_t lastAckMac[8] = {0};
void sendXferCompleteAck(uint8_t *dst);
void sendCancelXfer(uint8_t *dst);
// tools
void addCRC(void *p, uint8_t len) {
@@ -231,7 +233,9 @@ uint8_t __xdata getPacketType(void *__xdata buffer) {
int8_t findSlotForMac(const uint8_t *mac) {
for (uint8_t __xdata c = 0; c < MAX_PENDING_MACS; c++) {
if (u64_isEq((uint64_t __xdata *)mac, (uint64_t __xdata *)&(pendingDataArr[c].targetMac))) { // this costs 1 sloc :(
return c;
if (pendingDataArr[c].attemptsLeft != 0) {
return c;
}
}
}
return -1;
@@ -244,10 +248,27 @@ int8_t findFreeSlot() {
}
return -1;
}
int8_t findSlotForVer(const uint8_t *ver) {
for (uint8_t __xdata c = 0; c < MAX_PENDING_MACS; c++) {
// if (u64_isEq((uint64_t __xdata *)ver, (uint64_t __xdata *)&(pendingDataArr[c].availdatainfo.dataVer))) {
if (memcmp(ver, ((uint8_t __xdata *)&(pendingDataArr[c].availdatainfo.dataVer)), 8) == 0) {
if (pendingDataArr[c].attemptsLeft != 0) return c;
}
}
return -1;
}
void deleteAllPendingDataForVer(const uint8_t *ver) {
int8_t slot = -1;
do {
slot = findSlotForVer(ver);
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
} while (slot != -1);
}
// processing serial data
#define ZBS_RX_WAIT_HEADER 0
#define ZBS_RX_WAIT_SDA 1
#define ZBS_RX_WAIT_CANCEL 2
void processSerial(uint8_t lastchar) {
// uartTx(lastchar); echo
switch (RXState) {
@@ -263,6 +284,12 @@ void processSerial(uint8_t lastchar) {
serialbufferp = serialbuffer;
break;
}
if (strncmp(cmdbuffer, "CXD>", 4) == 0) {
RXState = ZBS_RX_WAIT_CANCEL;
bytesRemain = sizeof(struct pendingData);
serialbufferp = serialbuffer;
break;
}
if (strncmp(cmdbuffer, "VER?", 4) == 0) {
pr("VER>%04X\n", version);
}
@@ -294,6 +321,22 @@ void processSerial(uint8_t lastchar) {
RXState = ZBS_RX_WAIT_HEADER;
}
break;
case ZBS_RX_WAIT_CANCEL:
*serialbufferp = lastchar;
serialbufferp++;
bytesRemain--;
if (bytesRemain == 0) {
if (checkCRC(serialbuffer, sizeof(struct pendingData))) {
struct pendingData *pd = (struct pendingData *)serialbuffer;
deleteAllPendingDataForVer((uint8_t *)&pd->availdatainfo.dataVer);
pr("ACK>\n");
} else {
pr("NOK>\n");
}
RXState = ZBS_RX_WAIT_HEADER;
}
break;
}
}
@@ -348,7 +391,16 @@ void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) {
struct MacFrameNormal *__xdata rxHeader = (struct MacFrameNormal *)buffer;
struct blockRequest *__xdata blockReq = (struct blockRequest *)(buffer + sizeof(struct MacFrameNormal) + 1);
if (!checkCRC(blockReq, sizeof(struct blockRequest))) return;
// todo: actually do something with the block request
// check if we have data for this mac
if(findSlotForMac(rxHeader->src)==-1){
// no data for this mac, politely tell it to fuck off
sendCancelXfer(rxHeader->src);
return;
}
bool __xdata requestDataDownload = false;
if ((blockReq->blockId != requestedData.blockId) || (!u64_isEq((const uint64_t __xdata *)&blockReq->ver, (const uint64_t __xdata *)&requestedData.ver))) {
// requested block isn't already in the buffer
@@ -390,8 +442,6 @@ void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) {
}
blockStartTimer = timerGet() + blockRequestAck->pleaseWaitMs * TIMER_TICKS_PER_MS;
blockRequestAck->cancelXfer = 0;
memcpy(txHeader->src, mSelfMac, 8);
memcpy(txHeader->dst, rxHeader->src, 8);
@@ -468,10 +518,9 @@ void processAvailDataReq(uint8_t *buffer) {
txHeader->seq = seq++;
addCRC(availDataInfo, sizeof(struct AvailDataInfo));
radioTx(radiotxbuffer);
memset(lastAckMac, 0, 8); // reset lastAckMac, so we can record if we've received exactly one ack packet
memset(lastAckMac, 0, 8); // reset lastAckMac, so we can record if we've received exactly one ack packet
espNotifyAvailDataReq(availDataReq, rxHeader->src);
}
void processXferComplete(uint8_t *buffer) {
struct MacFrameNormal *rxHeader = (struct MacFrameNormal *)buffer;
sendXferCompleteAck(rxHeader->src);
@@ -530,6 +579,21 @@ void sendXferCompleteAck(uint8_t *dst) {
frameHeader->pan = dstPan;
radioTx(radiotxbuffer);
}
void sendCancelXfer(uint8_t *dst) {
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_CANCEL_XFER;
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
memcpy(frameHeader->src, mSelfMac, 8);
memcpy(frameHeader->dst, dst, 8);
frameHeader->fcs.frameType = 1;
frameHeader->fcs.panIdCompressed = 1;
frameHeader->fcs.destAddrType = 3;
frameHeader->fcs.srcAddrType = 3;
frameHeader->seq = seq++;
frameHeader->pan = dstPan;
radioTx(radiotxbuffer);
}
// main loop
void main(void) {

View File

@@ -49,8 +49,7 @@ struct MacFrameBcast {
uint8_t src[8];
} __packed;
#define PKT_TIMING_REQ 0xE0
#define PKT_TIMING_RESPONSE 0xE1
#define PKT_AVAIL_DATA_REQ 0xE5
#define PKT_AVAIL_DATA_INFO 0xE6
#define PKT_BLOCK_PARTIAL_REQUEST 0xE7
@@ -59,17 +58,7 @@ struct MacFrameBcast {
#define PKT_BLOCK_PART 0xE8
#define PKT_XFER_COMPLETE 0xEA
#define PKT_XFER_COMPLETE_ACK 0xEB
#define PKT_SYNC_BURST 0xEF
struct timingResponse {
uint8_t checksum;
uint32_t burstInterval; // time between burst-start
uint8_t burstLength; // in packets; due to use of sequence field, limited to a 256-packet burst
uint16_t burstLengthMs; // burst length in ms
uint32_t timerValue; // current timer value (used to sync up other RC timers/oscillators)
uint32_t burstIntervalRemaining; // time until the next sync burst
uint8_t dataAvailable;
} __packed;
#define PKT_CANCEL_XFER 0xEC
struct AvailDataReq {
uint8_t checksum;
@@ -129,7 +118,6 @@ struct blockRequest {
struct blockRequestAck {
uint8_t checksum;
uint16_t pleaseWaitMs;
uint8_t cancelXfer;
} __packed;
#define TIMER_TICKS_PER_MS 1333UL
@@ -254,7 +242,7 @@ void initAfterWake() {
initRadio();
}
void doSleep(uint32_t __xdata t) {
pr("s=%lu\n ", t/1000);
pr("s=%lu\n ", t / 1000);
powerPortsDownForSleep();
// sleepy
sleepForMsec(t);
@@ -327,16 +315,16 @@ struct AvailDataInfo *__xdata getAvailDataInfo() {
dataReqLastAttempt = DATA_REQ_MAX_ATTEMPTS;
return NULL;
}
void processBlockPart(struct blockPart *bp) {
bool processBlockPart(struct blockPart *bp) {
uint16_t __xdata start = bp->blockPart * BLOCK_PART_DATA_SIZE;
uint16_t __xdata size = BLOCK_PART_DATA_SIZE;
// validate if it's okay to copy data
if (bp->blockId != curBlock.blockId) {
// pr("got a packet for block %02X\n", bp->blockId);
return;
return false;
}
if (start >= (sizeof(blockXferBuffer) - 1)) return;
if (bp->blockPart > BLOCK_MAX_PARTS) return;
if (start >= (sizeof(blockXferBuffer) - 1)) return false;
if (bp->blockPart > BLOCK_MAX_PARTS) return false;
if ((start + size) > sizeof(blockXferBuffer)) {
size = sizeof(blockXferBuffer) - start;
}
@@ -345,6 +333,9 @@ void processBlockPart(struct blockPart *bp) {
xMemCopy((void *)(blockXferBuffer + start), (const void *)bp->data, size);
// we don't need this block anymore, set bit to 0 so we don't request it again
curBlock.requestedParts[bp->blockPart / 8] &= ~(1 << (bp->blockPart % 8));
return true;
} else {
return false;
}
}
bool blockRxLoop(uint32_t timeout) {
@@ -356,9 +347,8 @@ bool blockRxLoop(uint32_t timeout) {
int8_t __xdata ret = commsRxUnencrypted(inBuffer);
if (ret > 1) {
if (getPacketType(inBuffer) == PKT_BLOCK_PART) {
success = true;
struct blockPart *bp = (struct blockPart *)(inBuffer + sizeof(struct MacFrameNormal) + 1);
processBlockPart(bp);
success = processBlockPart(bp);
}
}
}
@@ -369,7 +359,6 @@ bool blockRxLoop(uint32_t timeout) {
struct blockRequestAck *__xdata continueToRX() {
struct blockRequestAck *ack = (struct blockRequestAck *)(inBuffer + sizeof(struct MacFrameNormal) + 1);
ack->pleaseWaitMs = 0;
ack->cancelXfer = 0;
return ack;
}
void sendBlockRequest() {
@@ -421,6 +410,8 @@ struct blockRequestAck *__xdata performBlockRequest() {
// processBlockPart((struct blockPart *)(inBuffer + sizeof(struct MacFrameNormal) + 1));
return continueToRX();
break;
case PKT_CANCEL_XFER:
return NULL;
default:
pr("pkt w/type %02X\n", getPacketType(inBuffer));
break;
@@ -681,9 +672,9 @@ void doDataDownload(struct AvailDataInfo *__xdata avail) {
// do transfer!
uint8_t __xdata blockRequestAttempt = 0;
uint8_t __xdata blockValidateAttempt = 0;
while (!curXferComplete) {
// this while loop loops until the transfer has been completed, or we get tired for other reasons
blockRequestAttempt = 0;
startdownload:;
#ifdef DEBUGBLOCKS
pr("REQ %d[", curBlock.blockId);
@@ -703,15 +694,10 @@ void doDataDownload(struct AvailDataInfo *__xdata avail) {
// DO BLOCK REQUEST - request a block, get an ack with timing info (hopefully)
struct blockRequestAck *__xdata ack = performBlockRequest();
if (ack == NULL) {
pr("no reply on gblockrequest\n");
// didn't get an ack :( we'll probably try again later
return;
} else if (ack->cancelXfer == 1) {
// we were asked to cancel the transfer by the AP
pr("transfer cancelled by AP\n");
pr("Cancelled request\n");
return;
} else {
// got an ack
// got an ack!
}
// SLEEP - until the AP is ready with the data
@@ -764,7 +750,8 @@ void doDataDownload(struct AvailDataInfo *__xdata avail) {
if (blockComplete) {
if (validateBlockData()) {
// checked and found okay
requestPartialBlock = false;
requestPartialBlock = false; // next block is going to be requested from the ESP32 by the AP
blockValidateAttempt = 0;
switch (curBlock.type) {
case DATATYPE_IMG:
case DATATYPE_IMGRAW:
@@ -776,6 +763,11 @@ void doDataDownload(struct AvailDataInfo *__xdata avail) {
}
} else {
// block checked, but failed validation. Mark all parts for this block as 'request'
blockValidateAttempt++;
if (blockValidateAttempt > 5) {
pr("bailing on download, 0 blockparts rx'd\n");
return;
}
for (uint8_t c = 0; c < partsThisBlock; c++) {
curBlock.requestedParts[c / 8] |= (1 << (c % 8));
}
@@ -905,6 +897,6 @@ void mainProtocolLoop(void) {
} else {
}
}
doSleep(getNextSleep()*1000UL);
doSleep(getNextSleep() * 1000UL);
}
}