mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 00:04:28 +01:00
337 lines
8.9 KiB
C
337 lines
8.9 KiB
C
#include "radio.h"
|
|
|
|
#include "asmUtil.h"
|
|
#include "board.h"
|
|
#include "cpu.h"
|
|
#include "printf.h"
|
|
#include "timer.h"
|
|
|
|
#define RX_BUFFER_SIZE (RADIO_MAX_PACKET_LEN + 1 /* len byte */ + 2 /* RSSI & LQI */)
|
|
#define RX_BUFFER_NUM 3
|
|
|
|
static volatile uint8_t __xdata mRxBufs[RX_BUFFER_NUM][RX_BUFFER_SIZE];
|
|
static volatile uint8_t __xdata mLastRSSI, mLastTxedSeq, mRxOn, mRxBufNextR, mRxBufNextW, mRxBufNumFree;
|
|
static volatile __bit mAckTimePassed, mGotAck;
|
|
|
|
// some things look like: https://www.ti.com/lit/ds/symlink/cc2430.pdf
|
|
// maybe a licensed and heavily modified version?
|
|
|
|
// maybe rx on and tx cal?
|
|
// see segmented_ota.<<code:00006D7B radioRxEnable>>
|
|
|
|
void RF_IRQ1(void) __interrupt(4) {
|
|
uint8_t cause = RADIO_IRQ4_pending;
|
|
static uint8_t __xdata lastRSSI;
|
|
|
|
RADIO_IRQ4_pending = 0;
|
|
|
|
if (cause & 0x40) { // ack time happened
|
|
|
|
// radio will report ACK if we (1) got an ack or (2) sent a packet that did not require it
|
|
mAckTimePassed = true;
|
|
mGotAck = !!(cause & 0x10);
|
|
|
|
}
|
|
if (cause & 0x20) { // radio has RXed a packet into its internal buffer. vet it quickly and set up DMA
|
|
|
|
uint8_t len = RADIO_GOTLEN;
|
|
|
|
if (len < 3 || len >= 0x80 || RADIO_rxFirstByte + 1 != len || !mRxOn || !mRxBufNumFree) { // detect invalid packets right away, or RX being off
|
|
|
|
RADIO_command = RADIO_CMD_FLUSH_RX_FIFO;
|
|
} else {
|
|
uint8_t __xdata *buf = mRxBufs[mRxBufNextW];
|
|
uint8_t bkp;
|
|
|
|
buf[0] = len;
|
|
|
|
bkp = CFGPAGE;
|
|
CFGPAGE = 4;
|
|
RADIO_RXLEN = len - 1;
|
|
RADIO_RXPTRL = ((uint16_t)(buf + 1)) & 0xff;
|
|
RADIO_RXPTRH = ((uint16_t)(buf + 1)) >> 8;
|
|
TRIGGER |= 4; // start rx dma
|
|
|
|
TCON2 &= ~4; // without this we trigger next irq too fast and get garbage
|
|
|
|
CFGPAGE = bkp;
|
|
}
|
|
}
|
|
if ((cause & 0x10) && !(RADIO_curRfState & 0x20)) { // radio got a valid preamble and is RXing a packet. this is our chance to sample some RSSI
|
|
uint8_t i;
|
|
|
|
// we get here if radio is RXing a packet - tells us to capture some RSSI vals.
|
|
// Seems there is an offset. Value is signed and offset by 56
|
|
for (i = 0; i < 0x3c; i++)
|
|
mLastRSSI = RADIO_currentRSSI;
|
|
}
|
|
}
|
|
|
|
void RF_IRQ2(void) __interrupt(5) {
|
|
uint8_t bck = CFGPAGE;
|
|
CFGPAGE = 4;
|
|
|
|
if (TCON2 & 0x04) { // RX dma over - time to check packet for valid CRC
|
|
|
|
uint8_t __xdata *buf = mRxBufs[mRxBufNextW];
|
|
uint8_t len;
|
|
|
|
TCON2 &= ~0x04;
|
|
RADIO_command = RADIO_CMD_FLUSH_RX_FIFO;
|
|
|
|
// last byte we got DMAed to us has top bit as flags for "crc ok"
|
|
|
|
len = buf[0];
|
|
|
|
if (!(buf[len] & 0x80)) {
|
|
// CRC failed on packet
|
|
} else {
|
|
buf[len - 1] = mLastRSSI - 56;
|
|
|
|
if (++mRxBufNextW == RX_BUFFER_NUM)
|
|
mRxBufNextW = 0;
|
|
mRxBufNumFree--;
|
|
}
|
|
}
|
|
if (TCON2 & 0x02) { // TX DMA completed
|
|
TCON2 &= ~2;
|
|
|
|
// nothing to do here
|
|
}
|
|
if (TCON2 & 0x08) { // radio init over
|
|
TCON2 &= ~0x48;
|
|
SETTINGS &= ~0x10;
|
|
}
|
|
CFGPAGE = bck;
|
|
}
|
|
|
|
bool radioTx(const void __xdata *packetP) // waits for tx end
|
|
{
|
|
const uint8_t __xdata *packet = (const uint8_t __xdata *)packetP;
|
|
uint16_t bkp, wait;
|
|
__bit irqs;
|
|
|
|
// this is how to do CCA. we do not bother because fuck it
|
|
// this is how WE do CCA. 'Fuck it' still somewhat applies if we don't get a clear channel in a reasonable amount of time
|
|
// okay fuck it.
|
|
/*
|
|
for (uint8_t i = 0; i < 0x80; i++) {
|
|
if (!(RADIO_curRfState & 1)) {
|
|
//pr("radio CCA fail\n");
|
|
timerDelay(TIMER_TICKS_PER_SECOND / 2000);
|
|
//return;
|
|
}
|
|
}
|
|
*/
|
|
|
|
mAckTimePassed = false;
|
|
mGotAck = false;
|
|
mLastTxedSeq = packet[3];
|
|
|
|
bkp = CFGPAGE;
|
|
CFGPAGE = 4;
|
|
|
|
irqs = IEN_EA;
|
|
IEN_EA = 0;
|
|
|
|
RADIO_TXLEN = packet[0] - 2;
|
|
RADIO_TXPTRL = ((uint16_t)packet) & 0xff;
|
|
RADIO_TXPTRH = ((uint16_t)packet) >> 8;
|
|
RADIO_command = RADIO_CMD_LOAD_TX_FIFO;
|
|
TRIGGER |= 2; // start TX fifo DMA
|
|
|
|
IEN_EA = irqs;
|
|
|
|
CFGPAGE = bkp;
|
|
|
|
//RADIO_unk_C8 = 0xff; /// stock fw does this but seems unnecessary
|
|
|
|
// wait for tx to start
|
|
wait = 0;
|
|
wait--;
|
|
do {
|
|
if (RADIO_curRfState & 0x80)
|
|
break;
|
|
} while (--wait);
|
|
|
|
// wait for tx to end
|
|
if (wait) {
|
|
while (!mAckTimePassed)
|
|
;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
//RADIO_unk_C8 = 0x7f; /// stock fw does this but seems unnecessary
|
|
}
|
|
|
|
void radioRxAckReset(void) {
|
|
mGotAck = false;
|
|
}
|
|
|
|
int16_t radioRxAckGetLast(void) {
|
|
if (mGotAck)
|
|
return (uint16_t)mLastTxedSeq;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
void radioRxFilterCfg(const uint8_t __xdata *filterForLong, uint32_t myShortMac, uint16_t myPan) {
|
|
uint16_t shortMac = (myShortMac == SHORT_MAC_UNUSED) ? 0xffff : myShortMac;
|
|
uint8_t i;
|
|
|
|
RADIO_PANID_Hi = myPan >> 8;
|
|
RADIO_PANID_Lo = myPan;
|
|
|
|
RADIO_ownShortAddress_Hi = shortMac >> 8;
|
|
RADIO_ownShortAddress_Lo = shortMac;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
((volatile uint8_t __xdata *)&RADIO_ownMac_7)[i] = filterForLong[(uint8_t)((uint8_t)7 - (uint8_t)i)];
|
|
}
|
|
|
|
void radioRxEnable(__bit on, __bit autoAck) {
|
|
if (!autoAck) {
|
|
pr("auto ack forced for now\n");
|
|
while (1)
|
|
;
|
|
}
|
|
mRxOn = on;
|
|
}
|
|
|
|
void radioSetTxPower(int8_t dBm) {
|
|
if (dBm < -27)
|
|
dBm = -27;
|
|
else if (dBm > 8)
|
|
dBm = 8;
|
|
|
|
dBm += 27;
|
|
|
|
RADIO_txPower = (uint8_t)(((uint8_t)dBm) + 3) / 5;
|
|
}
|
|
|
|
void radioSetChannel(uint8_t ch) {
|
|
static const uint8_t perChannelSetting1[] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33, 0x33};
|
|
static const uint8_t perChannelSetting2[] = {4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2};
|
|
|
|
if (ch < RADIO_FIRST_CHANNEL || ch >= RADIO_FIRST_CHANNEL + RADIO_NUM_CHANNELS)
|
|
return;
|
|
|
|
RADIO_channel = ch; // configmed to be at least RX channel
|
|
RADIO_command = RADIO_CMD_RECEIVE;
|
|
RADIO_perChannelSetting1 = perChannelSetting1[ch - 11];
|
|
RADIO_perChannelSetting2 = perChannelSetting2[ch - 11];
|
|
}
|
|
|
|
void radioRxFlush(void) {
|
|
mRxBufNumFree = RX_BUFFER_NUM;
|
|
}
|
|
|
|
int8_t radioRxDequeuePktGet(const void __xdata *__xdata *dstBufP, uint8_t __xdata *lqiP, int8_t __xdata *rssiP) {
|
|
const uint8_t __xdata *buf = mRxBufs[mRxBufNextR];
|
|
uint8_t lqi, len = buf[0];
|
|
|
|
if (mRxBufNumFree == RX_BUFFER_NUM)
|
|
return -1;
|
|
|
|
lqi = (buf[len] & 0x7f);
|
|
|
|
*lqiP = lqi;
|
|
*rssiP = buf[len - 1];
|
|
*dstBufP = buf + 1;
|
|
|
|
return len - 2;
|
|
}
|
|
|
|
void radioRxDequeuedPktRelease(void) {
|
|
if (++mRxBufNextR == RX_BUFFER_NUM)
|
|
mRxBufNextR = 0;
|
|
|
|
__critical {
|
|
mRxBufNumFree++;
|
|
}
|
|
}
|
|
|
|
void radioInit(void) {
|
|
uint8_t bkp;
|
|
|
|
mRxBufNextW = 0;
|
|
mRxBufNextR = 0;
|
|
mRxBufNumFree = RX_BUFFER_NUM;
|
|
|
|
timerDelay(TIMER_TICKS_PER_SECOND / 1000);
|
|
RADIO_unk_F0 |= 0x80;
|
|
timerDelay(TIMER_TICKS_PER_SECOND / 1000);
|
|
CFGPAGE = 0;
|
|
RESET &= ~4;
|
|
RESET |= 4;
|
|
RESET &= ~4;
|
|
timerDelay(TIMER_TICKS_PER_SECOND / 10000);
|
|
|
|
RADIO_RadioPowerCtl |= 4;
|
|
|
|
bkp = CFGPAGE;
|
|
CFGPAGE = 4;
|
|
SETTINGS |= 2;
|
|
RADIO_INITSEQ0 = 2;
|
|
RADIO_INITSEQ1 = 0xFA;
|
|
RADIO_INITSEQ2 = 0xDD;
|
|
SETTINGS |= 4;
|
|
RADIO_INITSEQ3 = 1;
|
|
RADIO_INITSEQ4 = 0xFA;
|
|
RADIO_INITSEQ5 = 0xDD;
|
|
IEN_RF2 = 1;
|
|
CFGPAGE = bkp;
|
|
|
|
RADIO_command = 0xC1;
|
|
|
|
RADIO_unk_C1 = 0x02;
|
|
RADIO_calibration_C2 = 0xf7; // mdmctrl0L?
|
|
RADIO_calibration_C3 = 0x05;
|
|
RADIO_calibration_C4 = 0x35;
|
|
RADIO_calibration_C5 = 0x24;
|
|
RADIO_calibration_C6 = 0x33;
|
|
RADIO_calibration_C7 = 0x70;
|
|
RADIO_unk_CA = 0x58;
|
|
RADIO_perChannelSetting2 = 0x02;
|
|
RADIO_unk_CD = (RADIO_unk_CD & ~7) | (0x11 & 7);
|
|
RADIO_txPower = 0;
|
|
RADIO_calibration_CF = 0x30;
|
|
RADIO_calibration_D0 = 0x00;
|
|
RADIO_calibration_D1 = 0x49;
|
|
RADIO_calibration_D2 = 0x06;
|
|
RADIO_unk_D7 = 0x43;
|
|
RADIO_unk_E2 = 0x08; // setting bit 0x40 breaks rx entirely
|
|
RADIO_unk_83 = 0xe5; // maybe sync word?
|
|
|
|
RADIO_unk_C8 = 0x7f; // setting bit 0x80 breaks rx entirely
|
|
RADIO_calibration_81 = 0xf0; // removing bit 0x20 breask rx and tx
|
|
RADIO_FLAGS |= 0x08;
|
|
RADIO_unk_D8 = 0;
|
|
RADIO_calibration_9D = 0x3f; // firts untpouched calib val
|
|
RADIO_calibration_A1 = 0x04;
|
|
RADIO_calibration_94 = 0x7f; // IOCFG0 ?
|
|
RADIO_unk_CE = 0x55;
|
|
RADIO_calibration_D3 = 0x30;
|
|
RADIO_calibration_D4 = 0xcc;
|
|
RADIO_calibration_D5 = 0xf6;
|
|
RADIO_calibration_86 = 0x40; // setting this to values like 0x20, 0x80, and 0x60 breaks auto-ack and maybe tx
|
|
RADIO_calibration_95 = 0x08;
|
|
RADIO_calibration_96 = 0xd3;
|
|
RADIO_calibration_70 = 0x01;
|
|
RADIO_calibration_71 = 0x40;
|
|
|
|
RADIO_unk_A6 = 0x00;
|
|
RADIO_command = 0xC8;
|
|
RADIO_command = 0xC7;
|
|
RADIO_command = 0xC6;
|
|
RADIO_unk_AF = 0x60; // int enable (we need 0x60)
|
|
|
|
RADIO_unk_AF |= 0x10;
|
|
|
|
IEN_RF1 = 1;
|
|
|
|
RADIO_FLAGS |= 8;
|
|
}
|