diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/Arduino_OpenEPaperLink_H2_AP.ino b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/Arduino_OpenEPaperLink_H2_AP.ino new file mode 100644 index 00000000..b0c9fb3b --- /dev/null +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/Arduino_OpenEPaperLink_H2_AP.ino @@ -0,0 +1,786 @@ +// Ported to ESP32-C6 Arduino By ATC1441(ATCnetz.de) for OpenEPaperLink at ~03.2024 + +#include "led.h" +#include "proto.h" +#include "radio.h" +#include "driver/gpio.h" +#include "driver/uart.h" +#include "esp_err.h" +#include "esp_event.h" +#include "esp_ieee802154.h" +#include "esp_phy_init.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "sdkconfig.h" +#include "second_uart.h" +#include "soc/uart_struct.h" +#include +#include +#include +#include +#include +#include + +const uint8_t channelList[6] = { 11, 15, 20, 25, 26, 27 }; + +#define DATATYPE_NOUPDATE 0 +#define HW_TYPE 0xC2 + +#define MAX_PENDING_MACS 250 +#define HOUSEKEEPING_INTERVAL 60UL + +struct pendingData pendingDataArr[MAX_PENDING_MACS]; + +// VERSION GOES HERE! +uint16_t version = 0x0019; + +#define RAW_PKT_PADDING 2 + +uint8_t radiotxbuffer[128]; +uint8_t radiorxbuffer[128]; + +static uint32_t housekeepingTimer; + +struct blockRequest requestedData = { 0 }; // holds which data was requested by the tag + +uint8_t dstMac[8]; // target for the block transfer +uint16_t dstPan; // + +static uint32_t blockStartTimer = 0; // reference that holds when the AP sends the next block +uint32_t nextBlockAttempt = 0; // reference time for when the AP can request a new block from the ESP32 +uint8_t seq = 0; // holds current sequence number for transmission +uint8_t blockbuffer[BLOCK_XFER_BUFFER_SIZE + 5]; // block transfer buffer +uint8_t lastAckMac[8] = { 0 }; + +// these variables hold the current mac were talking to +#define CONCURRENT_REQUEST_DELAY 1200UL +uint32_t lastBlockRequest = 0; +uint8_t lastBlockMac[8]; +uint8_t lastTagReturn[8]; + +uint8_t curChannel = 25; +uint8_t curPower = 10; + +uint8_t curPendingData = 0; +uint8_t curNoUpdate = 0; + +bool highspeedSerial = false; + +void sendXferCompleteAck(uint8_t *dst); +void sendCancelXfer(uint8_t *dst); +void espNotifyAPInfo(); + +// tools +void addCRC(void *p, uint8_t len) { + uint8_t total = 0; + for (uint8_t c = 1; c < len; c++) { + total += ((uint8_t *)p)[c]; + } + ((uint8_t *)p)[0] = total; +} +bool checkCRC(void *p, uint8_t len) { + uint8_t total = 0; + for (uint8_t c = 1; c < len; c++) { + total += ((uint8_t *)p)[c]; + } + return ((uint8_t *)p)[0] == total; +} + +uint8_t getPacketType(void *buffer) { + struct MacFcs *fcs = (MacFcs *)buffer; + if ((fcs->frameType == 1) && (fcs->destAddrType == 2) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 0)) { + // broadcast frame + uint8_t type = ((uint8_t *)buffer)[sizeof(struct MacFrameBcast)]; + return type; + } else if ((fcs->frameType == 1) && (fcs->destAddrType == 3) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 1)) { + // normal frame + uint8_t type = ((uint8_t *)buffer)[sizeof(struct MacFrameNormal)]; + return type; + } + return 0; +} +uint8_t getBlockDataLength() { + uint8_t partNo = 0; + for (uint8_t c = 0; c < BLOCK_MAX_PARTS; c++) { + if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) { + partNo++; + } + } + return partNo; +} + +// pendingdata slot stuff +int8_t findSlotForMac(const uint8_t *mac) { + for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) { + if (memcmp(mac, ((uint8_t *)&(pendingDataArr[c].targetMac)), 8) == 0) { + if (pendingDataArr[c].attemptsLeft != 0) { + return c; + } + } + } + return -1; +} +int8_t findFreeSlot() { + for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) { + if (pendingDataArr[c].attemptsLeft == 0) { + return c; + } + } + return -1; +} +int8_t findSlotForVer(const uint8_t *ver) { + for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) { + if (memcmp(ver, ((uint8_t *)&(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); +} +void deleteAllPendingDataForMac(const uint8_t *mac) { + int8_t slot = -1; + do { + slot = findSlotForMac(mac); + if (slot != -1) pendingDataArr[slot].attemptsLeft = 0; + } while (slot != -1); +} + +void countSlots() { + curPendingData = 0; + curNoUpdate = 0; + for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) { + if (pendingDataArr[c].attemptsLeft != 0) { + if (pendingDataArr[c].availdatainfo.dataType != 0) { + curPendingData++; + } else { + curNoUpdate++; + } + } + } +} + +// processing serial data +#define ZBS_RX_WAIT_HEADER 0 +#define ZBS_RX_WAIT_SDA 1 // send data avail +#define ZBS_RX_WAIT_CANCEL 2 // cancel traffic for mac +#define ZBS_RX_WAIT_SCP 3 // set channel power +#define ZBS_RX_WAIT_BLOCKDATA 4 + +bool isSame(uint8_t *in1, char *in2, int len) { + bool flag = 1; + for (int i = 0; i < len; i++) { + if (in1[i] != in2[i]) flag = 0; + } + return flag; +} + +int blockPosition = 0; +void processSerial(uint8_t lastchar) { + static uint8_t cmdbuffer[4]; + static uint8_t RXState = 0; + static uint8_t serialbuffer[48]; + static uint8_t *serialbufferp; + static uint8_t bytesRemain = 0; + static uint32_t lastSerial = 0; + static uint32_t blockStartTime = 0; + if ((RXState != ZBS_RX_WAIT_HEADER) && ((millis() - lastSerial) > 1000)) { + RXState = ZBS_RX_WAIT_HEADER; + Serial.printf("UART Timeout\r\n"); + } + lastSerial = millis(); + switch (RXState) { + case ZBS_RX_WAIT_HEADER: + // shift characters in + for (uint8_t c = 0; c < 3; c++) { + cmdbuffer[c] = cmdbuffer[c + 1]; + } + cmdbuffer[3] = lastchar; + + if (isSame(cmdbuffer + 1, ">D>", 3)) { + pr("ACK>"); + blockStartTime = millis(); + Serial.printf("Starting BlkData, %lu ms after request\r\n", blockStartTime - nextBlockAttempt); + blockPosition = 0; + RXState = ZBS_RX_WAIT_BLOCKDATA; + } + + if (isSame(cmdbuffer, "SDA>", 4)) { + Serial.printf("SDA In\r\n"); + RXState = ZBS_RX_WAIT_SDA; + bytesRemain = sizeof(struct pendingData); + serialbufferp = serialbuffer; + break; + } + if (isSame(cmdbuffer, "CXD>", 4)) { + Serial.printf("CXD In\r\n"); + RXState = ZBS_RX_WAIT_CANCEL; + bytesRemain = sizeof(struct pendingData); + serialbufferp = serialbuffer; + break; + } + if (isSame(cmdbuffer, "SCP>", 4)) { + Serial.printf("SCP In\r\n"); + RXState = ZBS_RX_WAIT_SCP; + bytesRemain = sizeof(struct espSetChannelPower); + serialbufferp = serialbuffer; + break; + } + if (isSame(cmdbuffer, "NFO?", 4)) { + pr("ACK>"); + Serial.printf("NFO? In\r\n"); + espNotifyAPInfo(); + RXState = ZBS_RX_WAIT_HEADER; + } + if (isSame(cmdbuffer, "RDY?", 4)) { + pr("ACK>"); + Serial.printf("RDY? In\r\n"); + RXState = ZBS_RX_WAIT_HEADER; + } + if (isSame(cmdbuffer, "RSET", 4)) { + pr("ACK>"); + Serial.printf("RSET In\r\n"); + delay(100); + // TODO RESET US HERE + RXState = ZBS_RX_WAIT_HEADER; + } + if (isSame(cmdbuffer, "HSPD", 4)) { + pr("ACK>"); + Serial.printf("HSPD In, switching to 2000000\r\n"); + delay(100); + uart_switch_speed(2000000); + delay(100); + highspeedSerial = true; + pr("ACK>"); + RXState = ZBS_RX_WAIT_HEADER; + } + break; + case ZBS_RX_WAIT_BLOCKDATA: + blockbuffer[blockPosition++] = 0xAA ^ lastchar; + if (blockPosition >= 4100) { + Serial.printf("Blockdata fully received in %lu ms, %lu ms after the request\r\n", millis() - blockStartTime, millis() - nextBlockAttempt); + RXState = ZBS_RX_WAIT_HEADER; + } + break; + + case ZBS_RX_WAIT_SDA: + *serialbufferp = lastchar; + serialbufferp++; + bytesRemain--; + if (bytesRemain == 0) { + if (checkCRC(serialbuffer, sizeof(struct pendingData))) { + struct pendingData *pd = (struct pendingData *)serialbuffer; + int8_t slot = findSlotForMac(pd->targetMac); + if (slot == -1) slot = findFreeSlot(); + if (slot != -1) { + memcpy(&(pendingDataArr[slot]), serialbuffer, sizeof(struct pendingData)); + pr("ACK>"); + } else { + pr("NOQ>"); + } + } else { + pr("NOK>"); + } + + 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; + deleteAllPendingDataForMac((uint8_t *)&pd->targetMac); + pr("ACK>"); + } else { + pr("NOK>"); + } + + RXState = ZBS_RX_WAIT_HEADER; + } + break; + case ZBS_RX_WAIT_SCP: + *serialbufferp = lastchar; + serialbufferp++; + bytesRemain--; + if (bytesRemain == 0) { + if (checkCRC(serialbuffer, sizeof(struct espSetChannelPower))) { + struct espSetChannelPower *scp = (struct espSetChannelPower *)serialbuffer; + for (uint8_t c = 0; c < sizeof(channelList); c++) { + if (channelList[c] == scp->channel) goto SCPchannelFound; + } + goto SCPfailed; +SCPchannelFound: + pr("ACK>"); + if (curChannel != scp->channel) { + radioSetChannel(scp->channel); + curChannel = scp->channel; + } + curPower = scp->power; + radioSetTxPower(scp->power); + Serial.printf("Set channel: %d power: %d\r\n", curChannel, curPower); + } else { +SCPfailed: + pr("NOK>"); + } + RXState = ZBS_RX_WAIT_HEADER; + } + break; + } +} + +// sending data to the ESP +void espBlockRequest(const struct blockRequest *br, uint8_t *src) { + struct espBlockRequest *ebr = (struct espBlockRequest *)blockbuffer; + uartTx('R'); + uartTx('Q'); + uartTx('B'); + uartTx('>'); + memcpy(&(ebr->ver), &(br->ver), 8); + memcpy(&(ebr->src), src, 8); + ebr->blockId = br->blockId; + addCRC(ebr, sizeof(struct espBlockRequest)); + for (uint8_t c = 0; c < sizeof(struct espBlockRequest); c++) { + uartTx(((uint8_t *)ebr)[c]); + } +} +void espNotifyAvailDataReq(const struct AvailDataReq *adr, const uint8_t *src) { + uartTx('A'); + uartTx('D'); + uartTx('R'); + uartTx('>'); + + struct espAvailDataReq eadr = { 0 }; + memcpy((void *)eadr.src, (void *)src, 8); + memcpy((void *)&eadr.adr, (void *)adr, sizeof(struct AvailDataReq)); + addCRC(&eadr, sizeof(struct espAvailDataReq)); + for (uint8_t c = 0; c < sizeof(struct espAvailDataReq); c++) { + uartTx(((uint8_t *)&eadr)[c]); + } +} +void espNotifyXferComplete(const uint8_t *src) { + struct espXferComplete exfc; + memcpy(&exfc.src, src, 8); + uartTx('X'); + uartTx('F'); + uartTx('C'); + uartTx('>'); + addCRC(&exfc, sizeof(exfc)); + for (uint8_t c = 0; c < sizeof(exfc); c++) { + uartTx(((uint8_t *)&exfc)[c]); + } +} +void espNotifyTimeOut(const uint8_t *src) { + struct espXferComplete exfc; + memcpy(&exfc.src, src, 8); + uartTx('X'); + uartTx('T'); + uartTx('O'); + uartTx('>'); + addCRC(&exfc, sizeof(exfc)); + for (uint8_t c = 0; c < sizeof(exfc); c++) { + uartTx(((uint8_t *)&exfc)[c]); + } +} +void espNotifyAPInfo() { + pr("TYP>%02X", HW_TYPE); + pr("VER>%04X", version); + 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", mSelfMac[6], mSelfMac[7]); + pr("ZCH>%02X", curChannel); + pr("ZPW>%02X", curPower); + countSlots(); + pr("PEN>%02X", curPendingData); + pr("NOP>%02X", curNoUpdate); +} + +void espNotifyTagReturnData(uint8_t *src, uint8_t len) { + struct tagReturnData *trd = (struct tagReturnData *)(radiorxbuffer + sizeof(struct MacFrameBcast) + 1); // oh how I'd love to pass this as an argument, but sdcc won't let me + struct espTagReturnData *etrd = (struct espTagReturnData *)radiotxbuffer; + + if (memcmp((void *)&trd->dataVer, lastTagReturn, 8) == 0) { + return; + } else { + memcpy(lastTagReturn, &trd->dataVer, 8); + } + + memcpy(etrd->src, src, 8); + etrd->len = len; + memcpy(&etrd->returnData, trd, len); + addCRC(etrd, len + 10); + + uartTx('T'); + uartTx('R'); + uartTx('D'); + uartTx('>'); + for (uint8_t c = 0; c < len + 10; c++) { + uartTx(((uint8_t *)etrd)[c]); + } +} + +// process data from tag +void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) { + struct MacFrameNormal *rxHeader = (struct MacFrameNormal *)buffer; + struct blockRequest *blockReq = (struct blockRequest *)(buffer + sizeof(struct MacFrameNormal) + 1); + if (!checkCRC(blockReq, sizeof(struct blockRequest))) return; + + // check if we're already talking to this mac + if (memcmp(rxHeader->src, lastBlockMac, 8) == 0) { + lastBlockRequest = millis(); + } else { + // we weren't talking to this mac, see if there was a transfer in progress from another mac, recently + if ((millis() - lastBlockRequest) > CONCURRENT_REQUEST_DELAY) { + // mark this mac as the new current mac we're talking to + memcpy((void *)lastBlockMac, (void *)rxHeader->src, 8); + lastBlockRequest = millis(); + } else { + // we're talking to another mac, let this mac know we can't accomodate another request right now + pr("BUSY!\n"); + sendCancelXfer(rxHeader->src); + return; + } + } + + // 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 requestDataDownload = false; + if ((blockReq->blockId != requestedData.blockId) || (blockReq->ver != requestedData.ver)) { + // requested block isn't already in the buffer + requestDataDownload = true; + } else { + // requested block is already in the buffer + if (forceBlockDownload) { + if ((millis() - nextBlockAttempt) > 380) { + requestDataDownload = true; + pr("FORCED\n"); + } else { + pr("IGNORED\n"); + } + } + } + + // copy blockrequest into requested data + memcpy(&requestedData, blockReq, sizeof(struct blockRequest)); + + struct MacFrameNormal *txHeader = (struct MacFrameNormal *)(radiotxbuffer + 1); + struct blockRequestAck *blockRequestAck = (struct blockRequestAck *)(radiotxbuffer + sizeof(struct MacFrameNormal) + 2); + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct blockRequestAck) + RAW_PKT_PADDING; + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_REQUEST_ACK; + + if (blockStartTimer == 0) { + if (requestDataDownload) { + if (highspeedSerial == true) { + blockRequestAck->pleaseWaitMs = 140; + } else { + blockRequestAck->pleaseWaitMs = 550; + } + } else { + // block is already in buffer + blockRequestAck->pleaseWaitMs = 30; + } + } else { + blockRequestAck->pleaseWaitMs = 30; + } + blockStartTimer = millis() + blockRequestAck->pleaseWaitMs; + + memcpy(txHeader->src, mSelfMac, 8); + memcpy(txHeader->dst, rxHeader->src, 8); + + txHeader->pan = rxHeader->pan; + txHeader->fcs.frameType = 1; + txHeader->fcs.panIdCompressed = 1; + txHeader->fcs.destAddrType = 3; + txHeader->fcs.srcAddrType = 3; + txHeader->seq = seq++; + + addCRC((void *)blockRequestAck, sizeof(struct blockRequestAck)); + + radioTx(radiotxbuffer); + + // save the target for the blockdata + memcpy(dstMac, rxHeader->src, 8); + dstPan = rxHeader->pan; + + if (requestDataDownload) { + blockPosition = 0; + espBlockRequest(&requestedData, rxHeader->src); + nextBlockAttempt = millis(); + } +} + +void processAvailDataReq(uint8_t *buffer) { + struct MacFrameBcast *rxHeader = (struct MacFrameBcast *)buffer; + struct AvailDataReq *availDataReq = (struct AvailDataReq *)(buffer + sizeof(struct MacFrameBcast) + 1); + + if (!checkCRC(availDataReq, sizeof(struct AvailDataReq))) return; + + // prepare tx buffer to send a response + memset(radiotxbuffer, 0, sizeof(struct MacFrameNormal) + sizeof(struct AvailDataInfo) + 2); // 120); + struct MacFrameNormal *txHeader = (struct MacFrameNormal *)(radiotxbuffer + 1); + struct AvailDataInfo *availDataInfo = (struct AvailDataInfo *)(radiotxbuffer + sizeof(struct MacFrameNormal) + 2); + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct AvailDataInfo) + RAW_PKT_PADDING; + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_AVAIL_DATA_INFO; + + // check to see if we have data available for this mac + bool haveData = false; + for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) { + if (pendingDataArr[c].attemptsLeft) { + if (memcmp(pendingDataArr[c].targetMac, rxHeader->src, 8) == 0) { + haveData = true; + memcpy((void *)availDataInfo, &(pendingDataArr[c].availdatainfo), sizeof(struct AvailDataInfo)); + break; + } + } + } + + // couldn't find data for this mac + if (!haveData) availDataInfo->dataType = DATATYPE_NOUPDATE; + + memcpy(txHeader->src, mSelfMac, 8); + memcpy(txHeader->dst, rxHeader->src, 8); + txHeader->pan = rxHeader->dstPan; + txHeader->fcs.frameType = 1; + txHeader->fcs.panIdCompressed = 1; + txHeader->fcs.destAddrType = 3; + txHeader->fcs.srcAddrType = 3; + 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 + espNotifyAvailDataReq(availDataReq, rxHeader->src); +} +void processXferComplete(uint8_t *buffer) { + struct MacFrameNormal *rxHeader = (struct MacFrameNormal *)buffer; + sendXferCompleteAck(rxHeader->src); + if (memcmp(lastAckMac, rxHeader->src, 8) != 0) { + memcpy((void *)lastAckMac, (void *)rxHeader->src, 8); + espNotifyXferComplete(rxHeader->src); + int8_t slot = findSlotForMac(rxHeader->src); + if (slot != -1) pendingDataArr[slot].attemptsLeft = 0; + } +} + +void processTagReturnData(uint8_t *buffer, uint8_t len) { + struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buffer; + struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1); + + if (!checkCRC((buffer + sizeof(struct MacFrameBcast) + 1), len - (sizeof(struct MacFrameBcast) + 1))) { + return; + } + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_TAG_RETURN_DATA_ACK; + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING; + 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); + + espNotifyTagReturnData(rxframe->src, len - (sizeof(struct MacFrameBcast) + 1)); +} + +// send block data to the tag +void sendPart(uint8_t partNo) { + struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1); + struct blockPart *blockPart = (struct blockPart *)(radiotxbuffer + sizeof(struct MacFrameNormal) + 2); + memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal)); + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_PART; + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE + 1 + RAW_PKT_PADDING; + memcpy(frameHeader->src, mSelfMac, 8); + memcpy(frameHeader->dst, dstMac, 8); + blockPart->blockId = requestedData.blockId; + blockPart->blockPart = partNo; + memcpy(&(blockPart->data), blockbuffer + (partNo * BLOCK_PART_DATA_SIZE), BLOCK_PART_DATA_SIZE); + addCRC(blockPart, sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE); + frameHeader->fcs.frameType = 1; + frameHeader->fcs.panIdCompressed = 1; + frameHeader->fcs.destAddrType = 3; + frameHeader->fcs.srcAddrType = 3; + frameHeader->seq = seq++; + frameHeader->pan = dstPan; + radioTx(radiotxbuffer); +} +void sendBlockData() { + if (getBlockDataLength() == 0) { + pr("Invalid block request received, 0 parts..\n"); + requestedData.requestedParts[0] |= 0x01; + } + + pr("Sending parts:"); + for (uint8_t c = 0; (c < BLOCK_MAX_PARTS); c++) { + if (c % 10 == 0) pr(" "); + if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) { + pr("X"); + } else { + pr("."); + } + } + pr("\n"); + + uint8_t partNo = 0; + while (partNo < BLOCK_MAX_PARTS) { + for (uint8_t c = 0; (c < BLOCK_MAX_PARTS) && (partNo < BLOCK_MAX_PARTS); c++) { + if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) { + sendPart(c); + partNo++; + } + } + } +} +void sendXferCompleteAck(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_XFER_COMPLETE_ACK; + 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); +} +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); +} +void sendPong(void *buf) { + struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buf; + struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1); + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_PONG; + radiotxbuffer[sizeof(struct MacFrameNormal) + 2] = curChannel; + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + 1 + RAW_PKT_PADDING; + 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); +} + +void setup() { + Serial.begin(115200); + + init_led(); + init_second_uart(); + + requestedData.blockId = 0xFF; + // clear the array with pending information + memset(pendingDataArr, 0, sizeof(pendingDataArr)); + + radio_init(curChannel); + radioSetTxPower(10); + + pr("RES>"); + pr("RDY>"); + Serial.printf("C6 ready!\r\n"); + + housekeepingTimer = millis(); +} + +void loop() { + while ((millis() - housekeepingTimer) < ((1000 * HOUSEKEEPING_INTERVAL) - 100)) { + int8_t ret = commsRxUnencrypted(radiorxbuffer); + if (ret > 1) { + led_flash(0); + // received a packet, lets see what it is + switch (getPacketType(radiorxbuffer)) { + case PKT_AVAIL_DATA_REQ: + if (ret == 28) { + // old version of the AvailDataReq struct, set all the new fields to zero, so it will pass the CRC + memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast) + sizeof(struct oldAvailDataReq), 0, + sizeof(struct AvailDataReq) - sizeof(struct oldAvailDataReq) + 2); + processAvailDataReq(radiorxbuffer); + } else if (ret == 40) { + // new version of the AvailDataReq struct + processAvailDataReq(radiorxbuffer); + } + break; + case PKT_BLOCK_REQUEST: + processBlockRequest(radiorxbuffer, 1); + break; + case PKT_BLOCK_PARTIAL_REQUEST: + processBlockRequest(radiorxbuffer, 0); + break; + case PKT_XFER_COMPLETE: + processXferComplete(radiorxbuffer); + break; + 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 + if (ret == 18) { + memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast), 0, sizeof(struct AvailDataReq) + 2); + processAvailDataReq(radiorxbuffer); + } + break; + case PKT_TAG_RETURN_DATA: + processTagReturnData(radiorxbuffer, ret); + break; + default: + Serial.printf("t=%02X\r\n", getPacketType(radiorxbuffer)); + break; + } + } else if (blockStartTimer == 0) { + delay(10); + } + + uint8_t curr_char; + while (getRxCharSecond(&curr_char)) processSerial(curr_char); + + if (blockStartTimer) { + if (millis() > blockStartTimer) { + sendBlockData(); + blockStartTimer = 0; + } + } + } + + memset(&lastTagReturn, 0, 8); + for (uint8_t cCount = 0; cCount < MAX_PENDING_MACS; cCount++) { + if (pendingDataArr[cCount].attemptsLeft == 1) { + if (pendingDataArr[cCount].availdatainfo.dataType != DATATYPE_NOUPDATE) { + espNotifyTimeOut(pendingDataArr[cCount].targetMac); + } + pendingDataArr[cCount].attemptsLeft = 0; + } else if (pendingDataArr[cCount].attemptsLeft > 1) { + pendingDataArr[cCount].attemptsLeft--; + if (pendingDataArr[cCount].availdatainfo.nextCheckIn) pendingDataArr[cCount].availdatainfo.nextCheckIn--; + } + } + housekeepingTimer = millis(); +} diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/led.cpp b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/led.cpp new file mode 100644 index 00000000..19f140a1 --- /dev/null +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/led.cpp @@ -0,0 +1,44 @@ +#include "led.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "freertos/timers.h" +#include "proto.h" +#include +#include +#include +#include +#include + +#define NUM_LEDS 2 + +const uint8_t led_pins[NUM_LEDS] = { LED1, LED2 }; +TimerHandle_t led_timers[NUM_LEDS] = { 0 }; + +void led_timer_callback(TimerHandle_t xTimer) { + int led_index = (int)pvTimerGetTimerID(xTimer); + if (led_index >= 0 && led_index < NUM_LEDS) { + digitalWrite(led_pins[led_index], 0); + } +} + +void init_led() { + pinMode(LED1,OUTPUT); + pinMode(LED2,OUTPUT); + + for (int i = 0; i < NUM_LEDS; i++) { + led_timers[i] = xTimerCreate("led_timer", pdMS_TO_TICKS(50), pdFALSE, (void *)i, led_timer_callback); + } +} + +void led_flash(int nr) { + digitalWrite(led_pins[nr], 1); + if (nr >= 0 && nr < NUM_LEDS) { + xTimerStart(led_timers[nr], 0); + } +} + +void led_set(int nr, bool state) { + digitalWrite(nr, state); +} diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/led.h b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/led.h new file mode 100644 index 00000000..a76467c7 --- /dev/null +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/led.h @@ -0,0 +1,6 @@ +#pragma once +#include + +void init_led(); +void led_set(int nr, bool state); +void led_flash(int nr); diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/proto.h b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/proto.h new file mode 100644 index 00000000..5d7705f5 --- /dev/null +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/proto.h @@ -0,0 +1,190 @@ +#ifndef _PROTO_H_ +#define _PROTO_H_ +#include + +#define LED1 22 +#define LED2 25 + +#define PROTO_PAN_ID (0x4447) // PAN ID compression shall be used + +#define RADIO_MAX_PACKET_LEN (125) // useful payload, not including the crc + +#define ADDR_MODE_NONE (0) +#define ADDR_MODE_SHORT (2) +#define ADDR_MODE_LONG (3) + +#define FRAME_TYPE_BEACON (0) +#define FRAME_TYPE_DATA (1) +#define FRAME_TYPE_ACK (2) +#define FRAME_TYPE_MAC_CMD (3) + +#define SHORT_MAC_UNUSED (0x10000000UL) // for radioRxFilterCfg's myShortMac + +struct MacFcs { + uint8_t frameType : 3; + uint8_t secure : 1; + uint8_t framePending : 1; + uint8_t ackReqd : 1; + uint8_t panIdCompressed : 1; + uint8_t rfu1 : 1; + uint8_t rfu2 : 2; + uint8_t destAddrType : 2; + uint8_t frameVer : 2; + uint8_t srcAddrType : 2; +} __attribute__((packed, aligned(1))); + +struct MacFrameFromMaster { + struct MacFcs fcs; + uint8_t seq; + uint16_t pan; + uint8_t dst[8]; + uint16_t from; +} __attribute__((packed, aligned(1))); + +struct MacFrameNormal { + struct MacFcs fcs; + uint8_t seq; + uint16_t pan; + uint8_t dst[8]; + uint8_t src[8]; +} __attribute__((packed, aligned(1))); + +struct MacFrameBcast { + struct MacFcs fcs; + uint8_t seq; + uint16_t dstPan; + uint16_t dstAddr; + uint16_t srcPan; + uint8_t src[8]; +} __attribute__((packed, aligned(1))); + +#define PKT_TAG_RETURN_DATA 0xE1 +#define PKT_TAG_RETURN_DATA_ACK 0xE2 +#define PKT_AVAIL_DATA_SHORTREQ 0xE3 +#define PKT_AVAIL_DATA_REQ 0xE5 +#define PKT_AVAIL_DATA_INFO 0xE6 +#define PKT_BLOCK_PARTIAL_REQUEST 0xE7 +#define PKT_BLOCK_REQUEST_ACK 0xE9 +#define PKT_BLOCK_REQUEST 0xE4 +#define PKT_BLOCK_PART 0xE8 +#define PKT_XFER_COMPLETE 0xEA +#define PKT_XFER_COMPLETE_ACK 0xEB +#define PKT_CANCEL_XFER 0xEC +#define PKT_PING 0xED +#define PKT_PONG 0xEE + +struct AvailDataReq { + uint8_t checksum; + uint8_t lastPacketLQI; + int8_t lastPacketRSSI; + int8_t temperature; + uint16_t batteryMv; + uint8_t hwType; + uint8_t wakeupReason; + uint8_t capabilities; + uint16_t tagSoftwareVersion; + uint8_t currentChannel; + uint8_t customMode; + uint8_t reserved[8]; +} __attribute__((packed, aligned(1))); + +struct oldAvailDataReq { + uint8_t checksum; + uint8_t lastPacketLQI; + int8_t lastPacketRSSI; + int8_t temperature; + uint16_t batteryMv; + uint8_t hwType; + uint8_t wakeupReason; + uint8_t capabilities; +} __attribute__((packed, aligned(1))); + +struct AvailDataInfo { + uint8_t checksum; + 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 +} __attribute__((packed, aligned(1))); + +struct pendingData { + struct AvailDataInfo availdatainfo; + uint16_t attemptsLeft; + uint8_t targetMac[8]; +} __attribute__((packed, aligned(1))); + +struct blockPart { + uint8_t checksum; + uint8_t blockId; + uint8_t blockPart; + uint8_t data[]; +} __attribute__((packed, aligned(1))); + +struct blockData { + uint16_t size; + uint16_t checksum; + uint8_t data[]; +} __attribute__((packed, aligned(1))); + +#define TAG_RETURN_DATA_SIZE 90 + +struct tagReturnData { + uint8_t checksum; + uint8_t partId; + uint64_t dataVer; + uint8_t dataType; + uint8_t data[TAG_RETURN_DATA_SIZE]; +} __attribute__((packed, aligned(1))); + +#define BLOCK_PART_DATA_SIZE 99 +#define BLOCK_MAX_PARTS 42 +#define BLOCK_DATA_SIZE 4096UL +#define BLOCK_XFER_BUFFER_SIZE BLOCK_DATA_SIZE + sizeof(struct blockData) +#define BLOCK_REQ_PARTS_BYTES 6 + +struct blockRequest { + uint8_t checksum; + uint64_t ver; + uint8_t blockId; + uint8_t type; + uint8_t requestedParts[BLOCK_REQ_PARTS_BYTES]; +} __attribute__((packed, aligned(1))); + +struct blockRequestAck { + uint8_t checksum; + uint16_t pleaseWaitMs; +} __attribute__((packed, aligned(1))); + +struct espBlockRequest { + uint8_t checksum; + uint64_t ver; + uint8_t blockId; + uint8_t src[8]; +} __attribute__((packed, aligned(1))); + +struct espXferComplete { + uint8_t checksum; + uint8_t src[8]; +} __attribute__((packed, aligned(1))); + +struct espAvailDataReq { + uint8_t checksum; + uint8_t src[8]; + struct AvailDataReq adr; +} __attribute__((packed, aligned(1))); + +struct espSetChannelPower { + uint8_t checksum; + uint8_t channel; + uint8_t power; +} __attribute__((packed, aligned(1))); + +struct espTagReturnData { + uint8_t checksum; + uint8_t src[8]; + uint8_t len; + struct tagReturnData returnData; +} __attribute__((packed, aligned(1))); + +#endif diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/radio.cpp b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/radio.cpp new file mode 100644 index 00000000..a70834b1 --- /dev/null +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/radio.cpp @@ -0,0 +1,113 @@ +#include "radio.h" +#include "driver/gpio.h" +#include "driver/uart.h" +#include "esp_err.h" +#include "esp_event.h" +#include "esp_ieee802154.h" +#include "esp_phy_init.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "led.h" +#include "proto.h" +#include "sdkconfig.h" +#include "soc/uart_struct.h" +#include +#include +#include +#include +#include + +uint8_t mSelfMac[8]; +volatile uint8_t isInTransmit = 0; +QueueHandle_t packet_buffer = NULL; + +void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info) { + Serial.printf("RADIO info RX %d\r\n", frame[0]); + BaseType_t xHigherPriorityTaskWoken; + static uint8_t inner_rxPKT[130]; + memcpy(inner_rxPKT, &frame[0], frame[0] + 1); + xQueueSendFromISR(packet_buffer, (void *)&inner_rxPKT, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken); +} + +void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) { + isInTransmit = 0; + Serial.printf("RADIO err TX Err: %d\r\n", error); +} + +void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) { + isInTransmit = 0; + Serial.printf("RADIO info TX %d\r\n", frame[0]); +} + +void radio_init(uint8_t ch) { + if (packet_buffer == NULL) packet_buffer = xQueueCreate(32, 130); + + // this will trigger a "IEEE802154 MAC sleep init failed" when called a second time, but it works + esp_ieee802154_enable(); + esp_ieee802154_set_channel(ch); + // esp_ieee802154_set_txpower(int8_t power); + esp_ieee802154_set_panid(PROTO_PAN_ID); + esp_ieee802154_set_promiscuous(false); + esp_ieee802154_set_coordinator(false); + esp_ieee802154_set_pending_mode(ESP_IEEE802154_AUTO_PENDING_ZIGBEE); + + // esp_ieee802154_set_extended_address needs the MAC in reversed byte order + esp_read_mac(mSelfMac, ESP_MAC_IEEE802154); + uint8_t eui64_rev[8] = { 0 }; + for (int i = 0; i < 8; i++) { + eui64_rev[7 - i] = mSelfMac[i]; + } + esp_ieee802154_set_extended_address(eui64_rev); + esp_ieee802154_get_extended_address(mSelfMac); + + esp_ieee802154_set_short_address(0xFFFE); + esp_ieee802154_set_rx_when_idle(true); + esp_ieee802154_receive(); + + led_flash(1); + delay(100); + led_flash(0); + delay(100); + led_flash(1); + delay(100); + led_flash(0); + + Serial.printf("RADIO Receiver ready, panId=0x%04x, channel=%d, long=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, short=%04x\r\n", + esp_ieee802154_get_panid(), esp_ieee802154_get_channel(), + mSelfMac[0], mSelfMac[1], mSelfMac[2], mSelfMac[3], + mSelfMac[4], mSelfMac[5], mSelfMac[6], mSelfMac[7], + esp_ieee802154_get_short_address()); +} + +// uint32_t lastZbTx = 0; +bool radioTx(uint8_t *packet) { + static uint8_t txPKT[130]; + led_flash(1); + while (isInTransmit) { + } + // while (millis() - lastZbTx < 6) { + // } + // lastZbTx = millis(); + memcpy(txPKT, packet, packet[0]); + isInTransmit = 1; + esp_ieee802154_transmit(txPKT, false); + return true; +} + +void radioSetChannel(uint8_t ch) { + radio_init(ch); +} + +void radioSetTxPower(uint8_t power) {} + +int8_t commsRxUnencrypted(uint8_t *data) { + static uint8_t inner_rxPKT_out[130]; + if (xQueueReceive(packet_buffer, (void *)&inner_rxPKT_out, pdMS_TO_TICKS(100)) == pdTRUE) { + memcpy(data, &inner_rxPKT_out[1], inner_rxPKT_out[0] + 1); + return inner_rxPKT_out[0] - 2; + } + return 0; +} diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/radio.h b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/radio.h new file mode 100644 index 00000000..73cd5286 --- /dev/null +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/radio.h @@ -0,0 +1,11 @@ +#pragma once +#include +#include + +extern uint8_t mSelfMac[8]; + +void radio_init(uint8_t ch); +bool radioTx(uint8_t *packet); +void radioSetChannel(uint8_t ch); +void radioSetTxPower(uint8_t power); +int8_t commsRxUnencrypted(uint8_t *data); \ No newline at end of file diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/second_uart.cpp b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/second_uart.cpp new file mode 100644 index 00000000..00b2b91e --- /dev/null +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/second_uart.cpp @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include "driver/gpio.h" +#include "driver/uart.h" +#include "esp_err.h" +#include "esp_event.h" +#include "esp_ieee802154.h" +#include "esp_phy_init.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "nvs.h" +#include "nvs_flash.h" +#include "proto.h" +#include "sdkconfig.h" +#include "soc/uart_struct.h" +#include "second_uart.h" + +#define CONFIG_OEPL_HARDWARE_UART_TX 4 +#define CONFIG_OEPL_HARDWARE_UART_RX 5 + +#define BUF_SIZE (1024) +#define RD_BUF_SIZE (BUF_SIZE) +static QueueHandle_t uart0_queue; + +#define MAX_BUFF_POS 8000 +volatile int curr_buff_pos = 0; +volatile int worked_buff_pos = 0; +volatile uint8_t buff_pos[MAX_BUFF_POS + 5]; + +static void uart_event_task(void *pvParameters); +void init_second_uart() { + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + }; + ESP_ERROR_CHECK(uart_driver_install(1, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0)); + ESP_ERROR_CHECK(uart_param_config(1, &uart_config)); + ESP_ERROR_CHECK(uart_set_pin(1, CONFIG_OEPL_HARDWARE_UART_TX, CONFIG_OEPL_HARDWARE_UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + xTaskCreate(uart_event_task, "uart_event_task", 16384, NULL, 12, NULL); +} + +void uart_switch_speed(int baudrate) { + uart_config_t uart_config = { + .baud_rate = baudrate, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + }; + ESP_ERROR_CHECK(uart_param_config(1, &uart_config)); +} + +void uartTx(uint8_t data) { + uart_write_bytes(1, (const char *)&data, 1); +} + + +bool getRxCharSecond(uint8_t *newChar) { + if (curr_buff_pos != worked_buff_pos) { + *newChar = buff_pos[worked_buff_pos]; + worked_buff_pos++; + worked_buff_pos %= MAX_BUFF_POS; + return true; + } + return false; +} + +static void uart_event_task(void *pvParameters) { + uart_event_t event; + uint8_t *dtmp = (uint8_t *)malloc(RD_BUF_SIZE); + for (;;) { + if (xQueueReceive(uart0_queue, (void *)&event, (TickType_t)portMAX_DELAY)) { + bzero(dtmp, RD_BUF_SIZE); + switch (event.type) { + case UART_DATA: + uart_read_bytes(1, dtmp, event.size, portMAX_DELAY); + for (int i = 0; i < event.size; i++) { + buff_pos[curr_buff_pos] = dtmp[i]; + curr_buff_pos++; + curr_buff_pos %= MAX_BUFF_POS; + } + break; + default: + Serial.printf("Second UART uart event type: %d\r\n", event.type); + break; + } + } + } + free(dtmp); + dtmp = NULL; + vTaskDelete(NULL); +} + +void uart_printf(const char *format, ...) { + va_list args; + va_start(args, format); + + char buffer[128]; + int len = vsnprintf(buffer, sizeof(buffer), format, args); + + va_end(args); + + if (len > 0) { + uart_write_bytes(1, buffer, len); + } +} diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/second_uart.h b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/second_uart.h new file mode 100644 index 00000000..a1e4636f --- /dev/null +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/second_uart.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +void init_second_uart(); +void uart_switch_speed(int baudrate); + +void uartTx(uint8_t data); +bool getRxCharSecond(uint8_t *newChar); + +void uart_printf(const char *format, ...); + +#define pr uart_printf diff --git a/ESP32_AP-Flasher/platformio.ini b/ESP32_AP-Flasher/platformio.ini index 3045c726..d22a6b36 100644 --- a/ESP32_AP-Flasher/platformio.ini +++ b/ESP32_AP-Flasher/platformio.ini @@ -450,6 +450,52 @@ board_upload.maximum_size = 16777216 board_upload.maximum_ram_size = 327680 board_upload.flash_size = 16MB ; ---------------------------------------------------------------------------------------- +; !!! this configuration expects an ESP32-S3 4MB Flash 2MB RAM aka The Official Espressif Zigbee Gateway PCB +; ---------------------------------------------------------------------------------------- +[env:ESP_THREAD_BORDER_ROUTER] +board = esp32-s3-devkitc-1 +board_build.partitions = default.csv +build_unflags = + -std=gnu++11 + -D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +lib_deps = + ${env.lib_deps} +build_flags = + -std=gnu++17 + ${env.build_flags} + ;-D HAS_BLE_WRITER + -D CORE_DEBUG_LEVEL=0 + -D ARDUINO_USB_CDC_ON_BOOT + -D CONFIG_ESP32S3_SPIRAM_SUPPORT=1 + -D CONFIG_SPIRAM_USE_MALLOC=1 + -D POWER_NO_SOFT_POWER + -D BOARD_HAS_PSRAM + -D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y + -D FLASHER_AP_SS=-1 + -D FLASHER_AP_CLK=-1 + -D FLASHER_AP_MOSI=-1 + -D FLASHER_AP_MISO=-1 + -D FLASHER_AP_RESET=7 + -D FLASHER_AP_POWER={-1} + -D FLASHER_AP_TEST=-1 + -D FLASHER_AP_TXD=4 + -D FLASHER_AP_RXD=5 + -D FLASHER_DEBUG_TXD=17 + -D FLASHER_DEBUG_RXD=18 + -D FLASHER_DEBUG_PROG=8 + -D FLASHER_LED=-1 + -D MD5_ENABLED=1 + -D SERIAL_FLASHER_INTERFACE_UART=1 + -D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50 + -D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100 + -D C6_OTA_FLASHING +build_src_filter = + +<*>--- +board_build.psram_type=qspi_opi +board_upload.maximum_size = 4194304 +board_upload.maximum_ram_size = 327680 +board_upload.flash_size = 4MB +; ---------------------------------------------------------------------------------------- ; !!! this configuration expects an SONOFF ZB Bridge-P ; ---------------------------------------------------------------------------------------- ;[env:Sonoff_zb_bridge_P_AP] diff --git a/binaries/ESP32-H2/OpenEPaperLink_esp32_H2.bin b/binaries/ESP32-H2/OpenEPaperLink_esp32_H2.bin new file mode 100644 index 00000000..0ba0b869 Binary files /dev/null and b/binaries/ESP32-H2/OpenEPaperLink_esp32_H2.bin differ diff --git a/binaries/ESP32-H2/bootloader.bin b/binaries/ESP32-H2/bootloader.bin new file mode 100644 index 00000000..2aa92fa1 Binary files /dev/null and b/binaries/ESP32-H2/bootloader.bin differ diff --git a/binaries/ESP32-H2/firmware.json b/binaries/ESP32-H2/firmware.json new file mode 100644 index 00000000..5a3cd1dc --- /dev/null +++ b/binaries/ESP32-H2/firmware.json @@ -0,0 +1,12 @@ +[{ + "filename": "bootloader.bin", + "address": "0x0" +}, +{ + "filename": "partition-table.bin", + "address": "0x8000" +}, +{ + "filename": "OpenEPaperLink_esp32_H2.bin", + "address": "0x10000" +}] diff --git a/binaries/ESP32-H2/partition-table.bin b/binaries/ESP32-H2/partition-table.bin new file mode 100644 index 00000000..5a42b51e Binary files /dev/null and b/binaries/ESP32-H2/partition-table.bin differ