From 229962165ae4faf8925cacbf3ec71a12a4f35975 Mon Sep 17 00:00:00 2001 From: atc1441 Date: Tue, 9 Jan 2024 00:10:11 +0100 Subject: [PATCH] Added SubGHz Alpha --- .../Arduino_OpenEPaperLink_C6_AP.ino | 84 +-- .../Arduino_OpenEPaperLink_C6_AP/radio.cpp | 63 +- .../Arduino_OpenEPaperLink_C6_AP/radio.h | 4 +- .../Arduino_OpenEPaperLink_C6_AP/subGhz.cpp | 609 ++++++++++++++++++ .../Arduino_OpenEPaperLink_C6_AP/subGhz.h | 32 + 5 files changed, 742 insertions(+), 50 deletions(-) create mode 100644 ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/subGhz.cpp create mode 100644 ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/subGhz.h diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/Arduino_OpenEPaperLink_C6_AP.ino b/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/Arduino_OpenEPaperLink_C6_AP.ino index 4d02c5c4..d29b685a 100644 --- a/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/Arduino_OpenEPaperLink_C6_AP.ino +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/Arduino_OpenEPaperLink_C6_AP.ino @@ -3,6 +3,7 @@ #include "led.h" #include "proto.h" #include "radio.h" +#include "subGhz.h" #include "driver/gpio.h" #include "driver/uart.h" #include "esp_err.h" @@ -39,8 +40,8 @@ uint16_t version = 0x0019; #define RAW_PKT_PADDING 2 -uint8_t radiotxbuffer[128]; -uint8_t radiorxbuffer[128]; +uint8_t radiotxbuffer[135]; +uint8_t radiorxbuffer[135]; static uint32_t housekeepingTimer; @@ -69,8 +70,8 @@ uint8_t curNoUpdate = 0; bool highspeedSerial = false; -void sendXferCompleteAck(uint8_t *dst); -void sendCancelXfer(uint8_t *dst); +void sendXferCompleteAck(uint8_t *dst, bool isSubGHz); +void sendCancelXfer(uint8_t *dst, bool isSubGHz); void espNotifyAPInfo(); // tools @@ -115,7 +116,7 @@ uint8_t getBlockDataLength() { // 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 (memcmp(mac, ((uint8_t *) & (pendingDataArr[c].targetMac)), 8) == 0) { if (pendingDataArr[c].attemptsLeft != 0) { return c; } @@ -133,7 +134,7 @@ int8_t findFreeSlot() { } 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 (memcmp(ver, ((uint8_t *) & (pendingDataArr[c].availdatainfo.dataVer)), 8) == 0) { if (pendingDataArr[c].attemptsLeft != 0) return c; } } @@ -431,7 +432,7 @@ void espNotifyTagReturnData(uint8_t *src, uint8_t len) { } // process data from tag -void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) { +void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload, bool isSubGHz) { struct MacFrameNormal *rxHeader = (struct MacFrameNormal *)buffer; struct blockRequest *blockReq = (struct blockRequest *)(buffer + sizeof(struct MacFrameNormal) + 1); if (!checkCRC(blockReq, sizeof(struct blockRequest))) return; @@ -448,7 +449,7 @@ void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) { } 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); + sendCancelXfer(rxHeader->src, isSubGHz); return; } } @@ -456,7 +457,7 @@ void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) { // 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); + sendCancelXfer(rxHeader->src, isSubGHz); return; } @@ -512,7 +513,7 @@ void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) { addCRC((void *)blockRequestAck, sizeof(struct blockRequestAck)); - radioTx(radiotxbuffer); + radioTx(radiotxbuffer, isSubGHz); // save the target for the blockdata memcpy(dstMac, rxHeader->src, 8); @@ -525,7 +526,7 @@ void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) { } } -void processAvailDataReq(uint8_t *buffer) { +void processAvailDataReq(uint8_t *buffer, bool isSubGHz) { struct MacFrameBcast *rxHeader = (struct MacFrameBcast *)buffer; struct AvailDataReq *availDataReq = (struct AvailDataReq *)(buffer + sizeof(struct MacFrameBcast) + 1); @@ -562,13 +563,13 @@ void processAvailDataReq(uint8_t *buffer) { txHeader->fcs.srcAddrType = 3; txHeader->seq = seq++; addCRC(availDataInfo, sizeof(struct AvailDataInfo)); - radioTx(radiotxbuffer); + radioTx(radiotxbuffer, isSubGHz); 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) { +void processXferComplete(uint8_t *buffer, bool isSubGHz) { struct MacFrameNormal *rxHeader = (struct MacFrameNormal *)buffer; - sendXferCompleteAck(rxHeader->src); + sendXferCompleteAck(rxHeader->src, isSubGHz); if (memcmp(lastAckMac, rxHeader->src, 8) != 0) { memcpy((void *)lastAckMac, (void *)rxHeader->src, 8); espNotifyXferComplete(rxHeader->src); @@ -577,7 +578,7 @@ void processXferComplete(uint8_t *buffer) { } } -void processTagReturnData(uint8_t *buffer, uint8_t len) { +void processTagReturnData(uint8_t *buffer, uint8_t len, bool isSubGHz) { struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buffer; struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1); @@ -592,13 +593,13 @@ void processTagReturnData(uint8_t *buffer, uint8_t len) { radiotxbuffer[2] = 0xCC; // normal frame frameHeader->seq = seq++; frameHeader->pan = rxframe->srcPan; - radioTx(radiotxbuffer); + radioTx(radiotxbuffer, isSubGHz); espNotifyTagReturnData(rxframe->src, len - (sizeof(struct MacFrameBcast) + 1)); } // send block data to the tag -void sendPart(uint8_t partNo) { +void sendPart(uint8_t partNo, bool isSubGHz) { 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)); @@ -616,9 +617,9 @@ void sendPart(uint8_t partNo) { frameHeader->fcs.srcAddrType = 3; frameHeader->seq = seq++; frameHeader->pan = dstPan; - radioTx(radiotxbuffer); + radioTx(radiotxbuffer, isSubGHz); } -void sendBlockData() { +void sendBlockData(bool isSubGHz) { if (getBlockDataLength() == 0) { pr("Invalid block request received, 0 parts..\n"); requestedData.requestedParts[0] |= 0x01; @@ -639,13 +640,13 @@ void sendBlockData() { 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); + sendPart(c, isSubGHz); partNo++; } } } } -void sendXferCompleteAck(uint8_t *dst) { +void sendXferCompleteAck(uint8_t *dst, bool isSubGHz) { 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; @@ -658,9 +659,9 @@ void sendXferCompleteAck(uint8_t *dst) { frameHeader->fcs.srcAddrType = 3; frameHeader->seq = seq++; frameHeader->pan = dstPan; - radioTx(radiotxbuffer); + radioTx(radiotxbuffer, isSubGHz); } -void sendCancelXfer(uint8_t *dst) { +void sendCancelXfer(uint8_t *dst, bool isSubGHz) { 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; @@ -673,9 +674,9 @@ void sendCancelXfer(uint8_t *dst) { frameHeader->fcs.srcAddrType = 3; frameHeader->seq = seq++; frameHeader->pan = dstPan; - radioTx(radiotxbuffer); + radioTx(radiotxbuffer, isSubGHz); } -void sendPong(void *buf) { +void sendPong(void *buf, bool isSubGHz) { struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buf; struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1); radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_PONG; @@ -687,9 +688,10 @@ void sendPong(void *buf) { radiotxbuffer[2] = 0xCC; // normal frame frameHeader->seq = seq++; frameHeader->pan = rxframe->srcPan; - radioTx(radiotxbuffer); + radioTx(radiotxbuffer, isSubGHz); } +extern uint8_t mSelfMac[8]; void setup() { Serial.begin(115200); @@ -710,10 +712,20 @@ void setup() { housekeepingTimer = millis(); } +bool isSubGhzRx = false; void loop() { while ((millis() - housekeepingTimer) < ((1000 * HOUSEKEEPING_INTERVAL) - 100)) { - int8_t ret = commsRxUnencrypted(radiorxbuffer); + int8_t ret = commsRxUnencrypted(radiorxbuffer, &isSubGhzRx); if (ret > 1) { + if (0) + { + Serial.printf("RXed packet len %u :", ret); + for (int t = 0; t < ret; t++) { + Serial.printf(" %02x", radiorxbuffer[t]); + } + Serial.printf("\n"); + } + led_flash(0); // received a packet, lets see what it is switch (getPacketType(radiorxbuffer)) { @@ -722,23 +734,23 @@ void loop() { // 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); + processAvailDataReq(radiorxbuffer, isSubGhzRx); } else if (ret == 40) { // new version of the AvailDataReq struct - processAvailDataReq(radiorxbuffer); + processAvailDataReq(radiorxbuffer, isSubGhzRx); } break; case PKT_BLOCK_REQUEST: - processBlockRequest(radiorxbuffer, 1); + processBlockRequest(radiorxbuffer, 1, isSubGhzRx); break; case PKT_BLOCK_PARTIAL_REQUEST: - processBlockRequest(radiorxbuffer, 0); + processBlockRequest(radiorxbuffer, 0, isSubGhzRx); break; case PKT_XFER_COMPLETE: - processXferComplete(radiorxbuffer); + processXferComplete(radiorxbuffer, isSubGhzRx); break; case PKT_PING: - sendPong(radiorxbuffer); + sendPong(radiorxbuffer, isSubGhzRx); 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 @@ -746,11 +758,11 @@ void loop() { // sent if (ret == 18) { memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast), 0, sizeof(struct AvailDataReq) + 2); - processAvailDataReq(radiorxbuffer); + processAvailDataReq(radiorxbuffer, isSubGhzRx); } break; case PKT_TAG_RETURN_DATA: - processTagReturnData(radiorxbuffer, ret); + processTagReturnData(radiorxbuffer, ret, isSubGhzRx); break; default: Serial.printf("t=%02X\r\n", getPacketType(radiorxbuffer)); @@ -765,7 +777,7 @@ void loop() { if (blockStartTimer) { if (millis() > blockStartTimer) { - sendBlockData(); + sendBlockData(isSubGhzRx); blockStartTimer = 0; } } diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/radio.cpp b/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/radio.cpp index 02de4289..a72da29d 100644 --- a/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/radio.cpp +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/radio.cpp @@ -10,6 +10,7 @@ #include "freertos/queue.h" #include "freertos/task.h" #include "led.h" +#include "subGhz.h" #include "proto.h" #include "sdkconfig.h" // if you get an error about soc/lp_uart_reg.h not being found, @@ -22,6 +23,8 @@ #include #include +bool has_sub_ghz = false; + uint8_t mSelfMac[8]; volatile uint8_t isInTransmit = 0; QueueHandle_t packet_buffer = NULL; @@ -83,34 +86,70 @@ void radio_init(uint8_t ch) { mSelfMac[0], mSelfMac[1], mSelfMac[2], mSelfMac[3], mSelfMac[4], mSelfMac[5], mSelfMac[6], mSelfMac[7], esp_ieee802154_get_short_address()); + + + // Lets here take care of the SubGhz Init + if (!init_subGhz()) + Serial.printf("Sub-GHz radio init failed\r\n"); + else if (!tiRadioSetChannel(ch)) + Serial.printf("SubGHz radio channel fail\r\n"); + else + has_sub_ghz = true; + + Serial.printf("SubGhz %s\r\n", has_sub_ghz ? "Active" : "Not Found"); + if (has_sub_ghz) { + tiRadioRxFilterCfg(mSelfMac, SHORT_MAC_UNUSED, PROTO_PAN_ID, true); + tiRadioTxConfigure(mSelfMac, SHORT_MAC_UNUSED, PROTO_PAN_ID); + tiRadioRxEnable(true, false); + } } // uint32_t lastZbTx = 0; -bool radioTx(uint8_t *packet) { - static uint8_t txPKT[130]; +bool radioTx(uint8_t *packet, bool subGhz) { led_flash(1); - while (isInTransmit) { + if (has_sub_ghz && subGhz) { + tiRadioTxLL(packet); + } else { + static uint8_t txPKT[130]; + while (isInTransmit) { + } + // while (millis() - lastZbTx < 6) { + // } + // lastZbTx = millis(); + memcpy(txPKT, packet, packet[0]); + isInTransmit = 1; + esp_ieee802154_transmit(txPKT, false); + return true; } - // 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); + if (has_sub_ghz) + tiRadioSetChannel(ch); } void radioSetTxPower(uint8_t power) {} -int8_t commsRxUnencrypted(uint8_t *data) { - static uint8_t inner_rxPKT_out[130]; +int8_t commsRxUnencrypted(uint8_t *data, bool *subGhzRx) { + int8_t rssi_sub_rx = 0; + uint8_t lqi_sub_rx = 0; + + static uint8_t inner_rxPKT_out[135]; if (xQueueReceive(packet_buffer, (void *)&inner_rxPKT_out, pdMS_TO_TICKS(100)) == pdTRUE) { memcpy(data, &inner_rxPKT_out[1], inner_rxPKT_out[0] + 1); + *subGhzRx = false; // This is Normal data return inner_rxPKT_out[0] - 2; } + if (has_sub_ghz) { + int32_t ret_sub_rx_len = tiRadioRxDequeuePkt(inner_rxPKT_out, sizeof(inner_rxPKT_out), &rssi_sub_rx, &lqi_sub_rx); + if (ret_sub_rx_len > 0) + { + //Serial.printf("Got Sub Ghz Len %i data: %i %u\r\n", ret_sub_rx, rssi_sub_rx, lqi_sub_rx); + memcpy(data, inner_rxPKT_out, ret_sub_rx_len); + *subGhzRx = true; // This is SubGHz data + return ret_sub_rx_len; + } + } return 0; } diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/radio.h b/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/radio.h index 73cd5286..94d5a69b 100644 --- a/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/radio.h +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/radio.h @@ -5,7 +5,7 @@ extern uint8_t mSelfMac[8]; void radio_init(uint8_t ch); -bool radioTx(uint8_t *packet); +bool radioTx(uint8_t *packet, bool subGhz); void radioSetChannel(uint8_t ch); void radioSetTxPower(uint8_t power); -int8_t commsRxUnencrypted(uint8_t *data); \ No newline at end of file +int8_t commsRxUnencrypted(uint8_t *data, bool *subGhzRx); diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/subGhz.cpp b/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/subGhz.cpp new file mode 100644 index 00000000..64f2516e --- /dev/null +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/subGhz.cpp @@ -0,0 +1,609 @@ + +// This code is heavily depending on Dmitrys wonderful Work ! +// https://dmitry.gr/?r=05.Projects&proj=29.%20eInk%20Price%20Tags +// Ported and modified to fit the OpenEPaperLink Project by ATC1441 (ATCnetz.de) ~01.2024 + +#include "subGhz.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 +#include + +#define SUB_GHZ_CH_OFST 11 +#define SUB_GHZ_NUM_CHANNELS 25 + +/* + //we configure GDO_2 is for TX.has_fifo_space + //we configure GDO_0 is for RX.has_data + WIRING: +*/ +#define sub_CS 4 +#define sub_GD0 5 +#define sub_GD2 6 +#define sub_MISO 7 +#define sub_CLK 0 +#define sub_MOSI 1 + +#define CMD_SRES 0x30 +#define CMD_SFSTXON 0x31 +#define CMD_SXOFF 0x32 +#define CMD_SCAL 0x33 +#define CMD_SRX 0x34 +#define CMD_STX 0x35 +#define CMD_SIDLE 0x36 +#define CMD_SWOR 0x38 +#define CMD_SPWD 0x39 +#define CMD_SFRX 0x3a +#define CMD_SFTX 0x3b +#define CMD_SWORRST 0x3c +#define CMD_SNOP 0x3d + +#define REG_IOCFG2 0x00 +#define REG_IOCFG1 0x01 +#define REG_IOCFG0 0x02 +#define REG_FIFOTHR 0x03 +#define REG_SYNC1 0x04 +#define REG_SYNC0 0x05 +#define REG_PKTLEN 0x06 +#define REG_PKTCTRL1 0x07 +#define REG_PKTCTRL0 0x08 +#define REG_ADDR 0x09 +#define REG_CHANNR 0x0a +#define REG_FSCTRL1 0x0b +#define REG_FSCTRL0 0x0c +#define REG_FREQ2 0x0d +#define REG_FREQ1 0x0e +#define REG_FREQ0 0x0f +#define REG_MDMCFG4 0x10 +#define REG_MDMCFG3 0x11 +#define REG_MDMCFG2 0x12 +#define REG_MDMCFG1 0x13 +#define REG_MDMCFG0 0x14 +#define REG_DEVIATN 0x15 +#define REG_MCSM2 0x16 +#define REG_MCSM1 0x17 +#define REG_MCSM0 0x18 +#define REG_FOCCFG 0x19 +#define REG_BSCFG 0x1a +#define REG_AGCTRL2 0x1b +#define REG_AGCTRL1 0x1c +#define REG_AGCTRL0 0x1d +#define REG_WOREVT1 0x1e +#define REG_WOREVT0 0x1f +#define REG_WORCTRL 0x20 +#define REG_FREND1 0x21 +#define REG_FREND0 0x22 +#define REG_FSCAL3 0x23 +#define REG_FSCAL2 0x24 +#define REG_FSCAL1 0x25 +#define REG_FSCAL0 0x26 +#define REG_RCCTRL1 0x27 +#define REG_RCCTRL0 0x28 +#define REG_FSTEST 0x29 +#define REG_PTEST 0x2a +#define REG_AGCTEST 0x2b +#define REG_TEST2 0x2c +#define REG_TEST1 0x2d +#define REG_TEST0 0x2e + +#define REG_PATABLE 0x3e +#define REG_FIFO 0x3f + +#define REG_PARTNUM 0xf0 +#define REG_VERSION 0xf1 +#define REG_FREQEST 0xf2 +#define REG_LQI 0xf3 +#define REG_RSSI 0xf4 +#define REG_MARCSTATE 0xf5 +#define REG_WORTIME1 0xf6 +#define REG_WORTIME0 0xf7 +#define REG_PKTSTATUS 0xf8 +#define REG_VCO_VC_DAC 0xf9 +#define REG_TXBYTES 0xfa +#define REG_RXBYTES 0xfb +#define REG_RCCTRL1_STA 0xfc +#define REG_RCCTRL0_STA 0xfd + + + +#define MAX_RX_PKTS 80 + +static volatile uint8_t mRxBufs[MAX_RX_PKTS][RADIO_MAX_PACKET_LEN + 1 /* length */ + 2 /* RSSI, LQI/STA */]; +static volatile uint8_t mRxNextWrite, mRxNextRead, mRxNumFree, mRxNumGot; +static uint8_t mRxFilterLongMac[8], mTxLongMac[8]; +static uint32_t mRxFilterShortMac, mTxShortMac; +static bool mRxEnabled, mAutoAck, mPromisc; +static uint16_t mRxFilterPan, mTxPan; +static volatile int16_t mLastAck; + +struct MacHeaderGenericAddr { + struct MacFcs fixed; + uint8_t seq; +} __attribute__((packed)); + +struct MacHeaderShortAddr { + struct MacFcs fixed; + uint8_t seq; + uint16_t pan; + uint16_t shortDstAddr; +} __attribute__((packed)); + +struct MacHeaderLongAddr { + struct MacFcs fixed; + uint8_t seq; + uint16_t pan; + uint8_t longDstAddr[8]; +} __attribute__((packed)); + + + +void tiRadioTxConfigure(const uint8_t *myLongMac, uint32_t myShortMac, uint16_t pan) { + memcpy(mTxLongMac, myLongMac, sizeof(mTxLongMac)); + mTxShortMac = myShortMac; + mTxPan = pan; +} + +void tiRadioRxFilterCfg(const uint8_t *myMac, uint32_t myShortMac, uint16_t myPan, bool promisc) { + mPromisc = promisc; + mRxFilterShortMac = myShortMac; + mRxFilterPan = myPan; + memcpy(mRxFilterLongMac, myMac, sizeof(mRxFilterLongMac)); +} + +static bool tiRadioPrvSelect(void) { + digitalWrite(sub_CS, LOW); + SPI.beginTransaction(SPISettings(6000000, MSBFIRST, SPI_MODE0)); + asm volatile("nop \n nop \n nop \n"); + return true; +} + +static void tiRadioPrvDeselect(void) { + asm volatile("nop \n nop \n nop \n"); + SPI.endTransaction(); + digitalWrite(sub_CS, HIGH); + asm volatile("nop \n nop \n nop \n"); +} + +static void read_multiple(uint8_t *dst, uint_fast8_t rxLen) { + for (int i = 0; i < rxLen; i++) { + dst[i] = SPI.transfer(0xff); + } +} + +static int_fast16_t tiRadioPrvStrobe(uint8_t cmd) //negative on error +{ + if (!tiRadioPrvSelect()) + return -1; + + cmd = SPI.transfer(cmd); + + tiRadioPrvDeselect(); + + return (uint_fast16_t)cmd; +} + +static bool tiRadioPrvRegWrite(uint_fast8_t reg, uint_fast8_t val) { + if (!tiRadioPrvSelect()) + return false; + + SPI.transfer(reg); + SPI.transfer(val); + + tiRadioPrvDeselect(); + + return true; +} + +static int_fast16_t tiRadioPrvRegRead(uint_fast8_t reg) { + uint8_t read_data = 0x00; + + if (!tiRadioPrvSelect()) + return -1; + + SPI.transfer(reg | 0x80); + read_data = SPI.transfer(0xff); + + tiRadioPrvDeselect(); + + return (uint_fast16_t)read_data; +} + +static bool tiRadioPrvRegWriteLong(uint8_t reg, const uint8_t *valP, uint8_t len) { + if (!tiRadioPrvSelect()) + return false; + + SPI.transfer(reg | 0x40); + + for (int i = 0; i < len; i++) { + SPI.transfer(valP[i]); + } + + tiRadioPrvDeselect(); + + return true; +} + +bool tiRadioRxEnable(bool on, bool autoAck) { + bool ret = false; + + if (on) { + + mAutoAck = autoAck; + if (mRxEnabled) { + ret = true; + goto out; + } + + if (!tiRadioPrvStrobe(CMD_SRX)) + goto out; + + mRxEnabled = true; + } else if (mRxEnabled) { + + if (!tiRadioPrvStrobe(CMD_SIDLE)) + goto out; + + mRxEnabled = false; + } + ret = true; + +out: + return ret; +} + +static bool radioPrvMacsEqual(const uint8_t *macA, const uint8_t *macB) { + const uint32_t *a = (const uint32_t *)(const char *)macA; + const uint32_t *b = (const uint32_t *)(const char *)macB; + return a[0] == b[0] && a[1] == b[1]; +} + +static uint_fast8_t tiRadioPrvGetState(void) { + uint_fast8_t state; + + do { + state = tiRadioPrvRegRead(REG_MARCSTATE); + } while (tiRadioPrvRegRead(REG_MARCSTATE) != state); + + return state; +} + +static void tiRadioPrvPacketRx(void) { + uint8_t *rxedPkt = (uint8_t *)mRxBufs[mRxNextWrite]; + const struct MacHeaderShortAddr *withShortDst = (const struct MacHeaderShortAddr *)(rxedPkt + 1); + const struct MacHeaderGenericAddr *generic = (const struct MacHeaderGenericAddr *)(rxedPkt + 1); + const struct MacHeaderLongAddr *withLongDst = (const struct MacHeaderLongAddr *)(rxedPkt + 1); + bool crcOk, acceptPacket, sendAck = false; + int32_t t, lenNoCrc, lenNoMacFixed; + uint32_t nWaitCycles = 10000; + uint_fast8_t spiLen, now; + + t = tiRadioPrvRegRead(REG_FIFO); + if (t < 0) + goto fail; + + if (!mRxNumFree) + goto fail; + + spiLen = t; + if (spiLen > RADIO_MAX_PACKET_LEN) + goto fail; + + t = 0; + rxedPkt[t++] = lenNoCrc = spiLen; + now = 31; //we just read one so 31 left for sure in the FIFO + spiLen += 2; //we expect 2 more bytes + + while (spiLen) { + + uint8_t reg; + + if (!tiRadioPrvSelect()) { + tiRadioPrvDeselect(); + goto fail; + } + + reg = 0xc0 | REG_FIFO; //burst read + reg = SPI.transfer(reg); + now = reg & 0x0f; + + if (now > spiLen) + now = spiLen; + + if (!now && !--nWaitCycles) { + tiRadioPrvDeselect(); + //Serial.printf(" !!! RX timeout !!! \r\n"); + goto fail; + } + + read_multiple(rxedPkt + t, now); + t += now; + spiLen -= now; + + tiRadioPrvDeselect(); + } + + rxedPkt++; //skip len; + crcOk = !!(rxedPkt[lenNoCrc + 1] & 0x80); + + lenNoMacFixed = lenNoCrc - sizeof(struct MacFcs) - sizeof(uint8_t); + + if (mPromisc) + acceptPacket = true; + //otherwise, we need a valid crc + else if (!crcOk) { + acceptPacket = false; + } + //packet should be big enough to contain a header + else if (lenNoMacFixed < 0) + acceptPacket = false; + else switch (generic->fixed.frameType) { + + case FRAME_TYPE_ACK: + mLastAck = (uint16_t)generic->seq; + acceptPacket = false; //no need to save it as a packet + break; + + case FRAME_TYPE_DATA: //we are not the coordinator, so we demand to see our address as destination... + + switch (generic->fixed.destAddrType) { + case ADDR_MODE_SHORT: + acceptPacket = (withShortDst->pan == 0xffff && withShortDst->shortDstAddr == 0xffff) || (withShortDst->pan == mRxFilterPan && (withShortDst->shortDstAddr == 0xffff || ((uint32_t)withShortDst->shortDstAddr) == mRxFilterShortMac)); + break; + + case ADDR_MODE_LONG: + acceptPacket = withLongDst->pan == mRxFilterPan && radioPrvMacsEqual(withLongDst->longDstAddr, mRxFilterLongMac); + break; + + default: + acceptPacket = false; + break; + } + sendAck = generic->fixed.ackReqd && mAutoAck; + break; + + default: + //no riff-raff please + acceptPacket = false; + break; + } + + if (acceptPacket) { //other checks here too plz + + if (sendAck) { + + static struct { + uint8_t len; + struct MacFcs mac; + uint8_t seq; + } __attribute__((packed)) ack = { + .len = sizeof(ack) + sizeof(uint16_t) - sizeof(ack.len), + .mac = { + .frameType = FRAME_TYPE_ACK, + }, + }; + + ack.seq = generic->seq; + + tiRadioTxLL(&ack); + } + + mRxNumFree--; + if (++mRxNextWrite == MAX_RX_PKTS) + mRxNextWrite = 0; + mRxNumGot++; + } + +out: + if (mRxEnabled && !sendAck) { //if ack is being TXed, TX irq will restart rx later + uint32_t maxWait = 100000; + uint8_t state; + + (void)tiRadioPrvStrobe(CMD_SRX); + + do { + state = tiRadioPrvGetState(); + + if (!--maxWait) { + //Serial.printf("too long wait for rx state. state is %d\n", state); + break; + } + + } while (state != 13 && state != 14 && state != 15); + } + return; + +fail: + (void)tiRadioPrvStrobe(CMD_SFRX); + goto out; +} + +void tiRadioRxAckReset(void) { + mLastAck = -1; +} + +int16_t tiRadioRxAckGetLast(void) { + return mLastAck; +} + +int32_t tiRadioRxDequeuePkt(void *dstBuf, uint32_t maxLen, int8_t *rssiP, uint8_t *lqiP) { + uint32_t len, copyLen = maxLen; + + if (!mRxNumGot) + return -1; + + len = mRxBufs[mRxNextRead][0]; + + if (copyLen > len) + copyLen = len; + memcpy(dstBuf, (const void *)(mRxBufs[mRxNextRead] + 1), copyLen); + + if (lqiP) { + + uint32_t lqi = 296 - ((mRxBufs[mRxNextRead][len + 2] & 0x7f) * 2); + + //LQI: lower is better. 48 is very good (no lower value seen), 127 is very bad (max value possible) + //we want LQI 0..255 so we scale as SATURATE(296 - 2 * val) + + if (lqi > 255) + lqi = 255; + + *lqiP = lqi; + } + + if (rssiP) + *rssiP = ((int8_t)mRxBufs[mRxNextRead][len + 1]) / 2 - 77; + + if (++mRxNextRead == MAX_RX_PKTS) + mRxNextRead = 0; + + noInterrupts(); + mRxNumFree++; + mRxNumGot--; + interrupts(); + + //ti radio never stalls RX state machine so nothing to do even if we just freed up a buffer + return len; +} + +void data_input_interrupt(void) { + while (digitalRead(sub_GD0)) //while there is data (packets) + tiRadioPrvPacketRx(); +} + +static void tiRadioPrvIfInit(void) { + //configure pins + pinMode(sub_CS, OUTPUT); + pinMode(sub_GD0, INPUT_PULLUP); + pinMode(sub_GD2, INPUT_PULLUP); + SPI.begin(sub_CLK, sub_MISO, sub_MOSI); + + tiRadioPrvDeselect(); + + mRxNumFree = MAX_RX_PKTS; +} + +static void tiRadioPrvIrqInit(void) { + attachInterrupt(sub_GD0, data_input_interrupt, RISING); +} + +bool tiRadioSetChannel(uint_fast8_t channel) { + channel -= SUB_GHZ_CH_OFST; + if (channel >= SUB_GHZ_NUM_CHANNELS) + return false; + + return tiRadioPrvRegWrite(REG_CHANNR, channel * 3); +} + +bool tiRadioTxLL(const void *pkt) { + const uint8_t *data = (const uint8_t *)pkt; + uint32_t len = 1 + *data, now; + bool ret = false; + + if (0) { + Serial.printf("TX packet len %u :", len); + for (int t = 0; t < len; t++) { + Serial.printf(" %02x", data[1 + t]); + } + Serial.printf("\n"); + } + + if (tiRadioPrvStrobe(CMD_SIDLE) < 0) + goto out; + + if (tiRadioPrvStrobe(CMD_SFTX) < 0) + goto out; + + now = (len > 64 ? 64 : len); + if (!tiRadioPrvRegWriteLong(REG_FIFO, data, now)) + goto out; + len -= now; + data += now; + + if (tiRadioPrvStrobe(CMD_STX) < 0) + goto out; + + while (len) { + + now = 8; + if (now > len) + now = len; + + while (digitalRead(sub_GD2)) + ; //wait till there is space + + if (!tiRadioPrvRegWriteLong(REG_FIFO, data, now)) + goto out; + + data += now; + len -= now; + } + + while (tiRadioPrvGetState() != 1) + ; + + if (!tiRadioPrvStrobe(mRxEnabled ? CMD_SRX : CMD_SIDLE)) + goto out; + + ret = true; + +out: + return ret; +} + +bool init_subGhz(void) { + uint8_t regsCfg[] = { + /* 0x00 */ 0x02, 0x2e, 0x01, 0x07, 0xd3, 0x91, 0x7f, 0x04, + /* 0x08 */ 0x45, 0x22, 0x00, 0x0e, 0x00, 0x22, 0xbb, 0x13, + /* 0x10 */ 0x1d, 0x3b, 0x13, 0x43, 0xa4, 0x65, 0x07, 0x30, + /* 0x18 */ 0x1d, 0x1e, 0x1c, 0xc7, 0x00, 0xb0, 0x87, 0x6b, + /* 0x20 */ 0xfb, 0xb6, 0x10, 0xea, 0x2a, 0x00, 0x1f, 0x41, + /* 0x28 */ 0x00, + }; + + uint8_t paTab[] = { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 }; + + tiRadioPrvIfInit(); + + if (tiRadioPrvRegRead(REG_PARTNUM) != 0x00) { + Serial.printf("partnum is wrong\n"); + return false; + } + + if (tiRadioPrvStrobe(CMD_SRES) < 0) { + Serial.printf("res reply\n"); + return false; + } + + delayMicroseconds(300); + + if (tiRadioPrvStrobe(CMD_SIDLE) != 0x0f) { + Serial.printf("idle reply\n"); + return false; + } + + if (!tiRadioPrvRegWriteLong(0, regsCfg, sizeof(regsCfg))) { + Serial.printf("config issue\n"); + return false; + } + + if (!tiRadioPrvRegWriteLong(REG_PATABLE, paTab, sizeof(paTab))) { + Serial.printf("PAtable issue\n"); + return false; + } + + tiRadioPrvIrqInit(); + + Serial.printf("Sub-GHz radio inited\n"); + + tiRadioRxEnable(true, false); + Serial.printf("Sub-GHz rx is on\n"); + return true; +} diff --git a/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/subGhz.h b/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/subGhz.h new file mode 100644 index 00000000..1b08ad79 --- /dev/null +++ b/ARM_Tag_FW/Arduino_OpenEPaperLink_C6_AP/subGhz.h @@ -0,0 +1,32 @@ + +// This code is heavily depending on Dmitrys wonderful Work ! +// https://dmitry.gr/?r=05.Projects&proj=29.%20eInk%20Price%20Tags +// Ported and modified to fit the OpenEPaperLink Project by ATC1441 (ATCnetz.de) ~01.2024 + +#pragma once +#include +#include + +void tiRadioTxConfigure(const uint8_t *myLongMac, uint32_t myShortMac, uint16_t pan); +void tiRadioRxFilterCfg(const uint8_t *myMac, uint32_t myShortMac, uint16_t myPan, bool promisc); +static bool tiRadioPrvSelect(void); +static void tiRadioPrvDeselect(void); +static void read_multiple(uint8_t *dst, uint_fast8_t rxLen); +static int_fast16_t tiRadioPrvStrobe(uint8_t cmd); +static bool tiRadioPrvRegWrite(uint_fast8_t reg, uint_fast8_t val); +static int_fast16_t tiRadioPrvRegRead(uint_fast8_t reg); +static bool tiRadioPrvRegWriteLong(uint8_t reg, const uint8_t *valP, uint8_t len); +bool tiRadioRxEnable(bool on, bool autoAck); +static bool radioPrvMacsEqual(const uint8_t *macA, const uint8_t *macB); +static uint_fast8_t tiRadioPrvGetState(void); +static void tiRadioPrvPacketRx(void); +void tiRadioRxAckReset(void); +int16_t tiRadioRxAckGetLast(void); +int32_t tiRadioRxDequeuePkt(void* dstBuf, uint32_t maxLen, int8_t *rssiP, uint8_t *lqiP); +void data_input_interrupt(void); +static void tiRadioPrvIfInit(void); +static void tiRadioPrvIrqInit(void); +bool tiRadioSetChannel(uint_fast8_t channel); +bool tiRadioTxLL(const void* pkt); + +bool init_subGhz(void);