mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 00:04:28 +01:00
Added build option for Espressif ESP Thread Border Router /Zigbee Gateway including ESP32-H2 AP Firmware
This commit is contained in:
@@ -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 <esp_mac.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
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();
|
||||
}
|
||||
44
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/led.cpp
Normal file
44
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/led.cpp
Normal file
@@ -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 <Arduino.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
6
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/led.h
Normal file
6
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/led.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
|
||||
void init_led();
|
||||
void led_set(int nr, bool state);
|
||||
void led_flash(int nr);
|
||||
190
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/proto.h
Normal file
190
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/proto.h
Normal file
@@ -0,0 +1,190 @@
|
||||
#ifndef _PROTO_H_
|
||||
#define _PROTO_H_
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
113
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/radio.cpp
Normal file
113
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/radio.cpp
Normal file
@@ -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 <esp_mac.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
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;
|
||||
}
|
||||
11
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/radio.h
Normal file
11
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/radio.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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);
|
||||
117
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/second_uart.cpp
Normal file
117
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/second_uart.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
#include <esp_mac.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <Arduino.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 "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);
|
||||
}
|
||||
}
|
||||
13
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/second_uart.h
Normal file
13
ARM_Tag_FW/Arduino_OpenEPaperLink_H2_AP/second_uart.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
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
|
||||
@@ -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 =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||
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]
|
||||
|
||||
BIN
binaries/ESP32-H2/OpenEPaperLink_esp32_H2.bin
Normal file
BIN
binaries/ESP32-H2/OpenEPaperLink_esp32_H2.bin
Normal file
Binary file not shown.
BIN
binaries/ESP32-H2/bootloader.bin
Normal file
BIN
binaries/ESP32-H2/bootloader.bin
Normal file
Binary file not shown.
12
binaries/ESP32-H2/firmware.json
Normal file
12
binaries/ESP32-H2/firmware.json
Normal file
@@ -0,0 +1,12 @@
|
||||
[{
|
||||
"filename": "bootloader.bin",
|
||||
"address": "0x0"
|
||||
},
|
||||
{
|
||||
"filename": "partition-table.bin",
|
||||
"address": "0x8000"
|
||||
},
|
||||
{
|
||||
"filename": "OpenEPaperLink_esp32_H2.bin",
|
||||
"address": "0x10000"
|
||||
}]
|
||||
BIN
binaries/ESP32-H2/partition-table.bin
Normal file
BIN
binaries/ESP32-H2/partition-table.bin
Normal file
Binary file not shown.
Reference in New Issue
Block a user