Added SubGHz Alpha

This commit is contained in:
atc1441
2024-01-09 00:10:11 +01:00
parent f95e957361
commit 229962165a
5 changed files with 742 additions and 50 deletions

View File

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

View File

@@ -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 <string.h>
#include <Arduino.h>
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;
}

View File

@@ -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);
int8_t commsRxUnencrypted(uint8_t *data, bool *subGhzRx);

View File

@@ -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 <Arduino.h>
#include <SPI.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}

View File

@@ -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 <Arduino.h>
#include <stdbool.h>
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);