1
0
mirror of https://github.com/peterantypas/maiana.git synced 2025-06-01 07:10:33 -07:00

onBitClock() rarely runs over 104us now

This commit is contained in:
Peter Antypas 2020-11-03 18:49:57 -08:00
parent f97aa0b82f
commit 973a28e0c7
5 changed files with 137 additions and 75 deletions

View File

@ -50,6 +50,7 @@ public:
protected: protected:
virtual void configure(); virtual void configure();
bool sendCmd(uint8_t cmd, void* params, uint8_t paramLen, void* result, uint8_t resultLen); bool sendCmd(uint8_t cmd, void* params, uint8_t paramLen, void* result, uint8_t resultLen);
bool sendCmdNoWait(uint8_t cmd, void* params, uint8_t paramLen);
bool isInitialized(); bool isInitialized();
void powerOnReset(); void powerOnReset();
bool isReceiving(); bool isReceiving();
@ -71,8 +72,8 @@ protected:
uint32_t mClockPin; uint32_t mClockPin;
uint8_t mLastNRZIBit; uint8_t mLastNRZIBit;
BitState mBitState; BitState mBitState;
bool mSPIBusy;
uint32_t mChipID; uint32_t mChipID;
bool mCTSPending = false;
}; };
#endif /* RFIC_HPP_ */ #endif /* RFIC_HPP_ */

View File

@ -50,12 +50,19 @@ public:
virtual void timeSlotStarted(uint32_t slot); virtual void timeSlotStarted(uint32_t slot);
void switchToChannel(VHFChannel channel); void switchToChannel(VHFChannel channel);
protected: protected:
typedef enum
{
NO_ACTION,
RESTART_RX,
RETRIEVE_RSSI
} Action;
void startListening(VHFChannel channel, bool reconfigGPIOs); void startListening(VHFChannel channel, bool reconfigGPIOs);
bool addBit(uint8_t bit); bool addBit(uint8_t bit);
void resetBitScanner(); void resetBitScanner();
uint8_t reportRSSI(); uint8_t reportRSSI();
void pushPacket(); void pushPacket();
void processNRZIBit(uint8_t level); Action processNRZIBit(uint8_t level);
virtual void configureGPIOsForRX(); virtual void configureGPIOsForRX();
protected: protected:
RXPacket *mRXPacket = nullptr; RXPacket *mRXPacket = nullptr;
@ -66,9 +73,8 @@ protected:
BitState mBitState; BitState mBitState;
uint8_t mRXByte; uint8_t mRXByte;
VHFChannel mChannel; VHFChannel mChannel;
uint16_t mSlotBitNumber; int mSlotBitNumber;
bool mSwitchAtNextSlot; VHFChannel mNextChannel;
VHFChannel mSwitchToChannel;
uint32_t mTimeSlot = 0xffffffff; uint32_t mTimeSlot = 0xffffffff;
}; };

View File

@ -15,15 +15,14 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/> along with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include "RFIC.hpp" #include "RFIC.hpp"
#include "radio_config.h" #include "radio_config.h"
#include "Utils.hpp" #include "Utils.hpp"
#include "EZRadioPRO.h" #include "EZRadioPRO.h"
#include <cstring> #include <string.h>
#include "printf_serial.h"
#include "bsp.hpp" #include "bsp.hpp"
RFIC::RFIC(GPIO_TypeDef *sdnPort, RFIC::RFIC(GPIO_TypeDef *sdnPort,
@ -46,8 +45,6 @@ RFIC::RFIC(GPIO_TypeDef *sdnPort,
mDataPin = dataPin; mDataPin = dataPin;
mClockPin = clockPin; mClockPin = clockPin;
//mRSSIAdjustment = 0;
mSPIBusy = false;
mChipID = chipID; mChipID = chipID;
if ( !isInitialized() ) if ( !isInitialized() )
@ -71,7 +68,13 @@ inline void RFIC::spiOff()
bool RFIC::sendCmd(uint8_t cmd, void* params, uint8_t paramLen, void* result, uint8_t resultLen) bool RFIC::sendCmd(uint8_t cmd, void* params, uint8_t paramLen, void* result, uint8_t resultLen)
{ {
mSPIBusy = true; if ( mCTSPending )
{
while ( readSPIResponse(NULL, 0) == false)
;
mCTSPending = false;
}
//bsp_signal_high(); //bsp_signal_high();
spiOn(); spiOn();
@ -90,11 +93,34 @@ bool RFIC::sendCmd(uint8_t cmd, void* params, uint8_t paramLen, void* result, ui
; ;
//bsp_signal_low(); //bsp_signal_low();
mSPIBusy = false;
return true; return true;
} }
bool RFIC::sendCmdNoWait(uint8_t cmd, void* params, uint8_t paramLen)
{
if ( mCTSPending )
{
while ( readSPIResponse(NULL, 0) == false)
;
mCTSPending = false;
}
spiOn();
bsp_tx_spi_byte(cmd);
uint8_t *b = (uint8_t*) params;
for ( int i = 0; i < paramLen; ++i )
{
bsp_tx_spi_byte(b[i]);
}
spiOff();
mCTSPending = true;
return true;
}
// This is borrowed from the dAISy project. Thank you Adrian :) // This is borrowed from the dAISy project. Thank you Adrian :)
bool RFIC::readSPIResponse(void *data, uint8_t length) bool RFIC::readSPIResponse(void *data, uint8_t length)
{ {
@ -106,12 +132,15 @@ bool RFIC::readSPIResponse(void *data, uint8_t length)
return false; return false;
} }
uint8_t* b = (uint8_t*) data; if ( data )
uint8_t i = 0;
while (i < length)
{ {
b[i] = bsp_tx_spi_byte(0); uint8_t* b = (uint8_t*) data;
++i; uint8_t i = 0;
while (i < length)
{
b[i] = bsp_tx_spi_byte(0);
++i;
}
} }
spiOff(); spiOff();
@ -138,11 +167,9 @@ bool RFIC::isInitialized()
HAL_GPIO_WritePin(mSDNP, mSDNPin, GPIO_PIN_RESET); HAL_GPIO_WritePin(mSDNP, mSDNPin, GPIO_PIN_RESET);
HAL_Delay(100); HAL_Delay(100);
//DBG("Checking RF chip status\r\n");
CHIP_STATUS_REPLY chip_status; CHIP_STATUS_REPLY chip_status;
memset(&chip_status, 0, sizeof chip_status); memset(&chip_status, 0, sizeof chip_status);
sendCmd(GET_CHIP_STATUS, NULL, 0, &chip_status, sizeof chip_status); sendCmd(GET_CHIP_STATUS, NULL, 0, &chip_status, sizeof chip_status);
//DBG("Chip status: 0x%.2x\r\n", chip_status.Current);
if ( chip_status.Current & 0x08 ) if ( chip_status.Current & 0x08 )
{ {
return false; return false;
@ -150,13 +177,11 @@ bool RFIC::isInitialized()
else else
{ {
return true; return true;
} }
} }
void RFIC::powerOnReset() void RFIC::powerOnReset()
{ {
//DBG("Performing Power On Reset\r\n");
// Pull SDN high to shut down the IC // Pull SDN high to shut down the IC
HAL_GPIO_WritePin(mSDNP, mSDNPin, GPIO_PIN_SET); HAL_GPIO_WritePin(mSDNP, mSDNPin, GPIO_PIN_SET);
@ -166,12 +191,8 @@ void RFIC::powerOnReset()
// Pull SDN low and poll the status of GPIO1 // Pull SDN low and poll the status of GPIO1
HAL_GPIO_WritePin(mSDNP, mSDNPin, GPIO_PIN_RESET); HAL_GPIO_WritePin(mSDNP, mSDNPin, GPIO_PIN_RESET);
//DBG("Waiting for GPIO1\r\n");
while ( HAL_GPIO_ReadPin(mDataPort, mDataPin) == GPIO_PIN_RESET ) while ( HAL_GPIO_ReadPin(mDataPort, mDataPin) == GPIO_PIN_RESET )
; ;
// We're done!
//DBG("Radio Ready!\r\n");
} }
uint8_t RFIC::readRSSI() uint8_t RFIC::readRSSI()

View File

@ -30,14 +30,13 @@ Receiver::Receiver(GPIO_TypeDef *sdnPort, uint32_t sdnPin, GPIO_TypeDef *csPort,
GPIO_TypeDef *clockPort, uint32_t clockPin, int chipId) GPIO_TypeDef *clockPort, uint32_t clockPin, int chipId)
: RFIC(sdnPort, sdnPin, csPort, csPin, dataPort, dataPin, clockPort, clockPin, chipId) : RFIC(sdnPort, sdnPin, csPort, csPin, dataPort, dataPin, clockPort, clockPin, chipId)
{ {
mSlotBitNumber = 0xffff; mSlotBitNumber = -1;
mSwitchAtNextSlot = false;
mOneBitCount = 0; mOneBitCount = 0;
mChannel = CH_88; mChannel = CH_88;
mBitCount = 0; mBitCount = 0;
mBitState = BIT_STATE_PREAMBLE_SYNC; mBitState = BIT_STATE_PREAMBLE_SYNC;
mLastNRZIBit=0x00; mLastNRZIBit=0x00;
mSwitchToChannel = mChannel; mNextChannel = mChannel;
mRXByte = 0; mRXByte = 0;
mBitWindow = 0; mBitWindow = 0;
mRXPacket = EventPool::instance().newRXPacket(); mRXPacket = EventPool::instance().newRXPacket();
@ -55,25 +54,22 @@ VHFChannel Receiver::channel()
bool Receiver::init() bool Receiver::init()
{ {
//DBG("Configuring IC\r\n");
configure(); configure();
resetBitScanner(); resetBitScanner();
//configureGPIOsForRX();
return true; return true;
} }
void Receiver::startReceiving(VHFChannel channel, bool reconfigGPIOs) void Receiver::startReceiving(VHFChannel channel, bool reconfigGPIOs)
{ {
mChannel = channel; mChannel = channel;
mNextChannel = channel;
startListening(mChannel, reconfigGPIOs); startListening(mChannel, reconfigGPIOs);
resetBitScanner(); resetBitScanner();
} }
void Receiver::switchToChannel(VHFChannel channel) void Receiver::switchToChannel(VHFChannel channel)
{ {
mSwitchAtNextSlot = true; mNextChannel = channel;
mSwitchToChannel = channel;
} }
// TODO: This is a really, really long operation - over 320us !!! // TODO: This is a really, really long operation - over 320us !!!
@ -95,10 +91,10 @@ void Receiver::startListening(VHFChannel channel, bool reconfigGPIOs)
options.next_state3 = 0; options.next_state3 = 0;
/** /**
* This can take up to 220us, that's 3 bit clocks!!! * This never takes more than 65us now :D
*/ */
//bsp_signal_high(); //bsp_signal_high();
sendCmd (START_RX, &options, sizeof options, NULL, 0); sendCmdNoWait(START_RX, &options, sizeof options);//, NULL, 0);
//bsp_signal_low(); //bsp_signal_low();
} }
@ -110,8 +106,8 @@ void Receiver::resetBitScanner()
mLastNRZIBit = 0xff; mLastNRZIBit = 0xff;
mRXByte = 0; mRXByte = 0;
mBitState = BIT_STATE_PREAMBLE_SYNC; mBitState = BIT_STATE_PREAMBLE_SYNC;
if ( mRXPacket )
mRXPacket->reset(); mRXPacket->reset();
} }
/* /*
@ -123,49 +119,79 @@ void Receiver::resetBitScanner()
void Receiver::onBitClock() void Receiver::onBitClock()
{ {
++mSlotBitNumber;
// Don't waste time processing bits when the transceiver is transmitting // Don't waste time processing bits when the transceiver is transmitting
if ( gRadioState == RADIO_TRANSMITTING ) if ( gRadioState == RADIO_TRANSMITTING )
return; return;
//bsp_signal_high(); bsp_signal_high();
if ( !mRXPacket )
{
mRXPacket = EventPool::instance().newRXPacket();
if ( !mRXPacket )
{
return;
}
}
uint8_t bit = HAL_GPIO_ReadPin(mDataPort, mDataPin); uint8_t bit = HAL_GPIO_ReadPin(mDataPort, mDataPin);
processNRZIBit(bit); Receiver::Action action = processNRZIBit(bit);
if ( mTimeSlot != 0xffffffff && mSlotBitNumber != 0xffff && if ( action == RESTART_RX )
mTimeSlot % 17 == mChipID && mSlotBitNumber++ == CCA_SLOT_BIT - 1 ) {
startReceiving(mChannel, false);
}
/**
* This trick ensures that we only sample RSSI every 17 time slots and never in the
* same time slot for both ICs, so we don't conduct long SPI operations on consecutive
* interrupt handlers that might exceed the bit clock period. There is no reason for RSSI
* collection to have a high duty cycle anyway, it just serves to establish the noise floor.
*/
else if ( mTimeSlot != 0xffffffff && mSlotBitNumber != 0xffff &&
mTimeSlot % 17 == mChipID && mSlotBitNumber == CCA_SLOT_BIT - 1 )
{ {
uint8_t rssi = reportRSSI(); uint8_t rssi = reportRSSI();
mRXPacket->setRSSI(rssi); mRXPacket->setRSSI(rssi);
} }
//bsp_signal_low();
bsp_signal_low();
} }
/**
* This is called from the SOTDMA timer interrupt, which is at the same priority as the bit clock.
* So timeSlotStarted() and onBitClock() cannot preempt each other.
*/
void Receiver::timeSlotStarted(uint32_t slot) void Receiver::timeSlotStarted(uint32_t slot)
{ {
// This should never be called while transmitting. Transmissions start after the slot boundary and end before the end of it. // This should never be called while transmitting. Transmissions start after the slot boundary and end before the end of it.
//assert(gRadioState == RADIO_RECEIVING); ASSERT(gRadioState == RADIO_RECEIVING);
//if ( gRadioState != RADIO_RECEIVING )
//DBG(" **** WTF??? Transmitting past slot boundary? **** \r\n");
mSlotBitNumber = 0; mSlotBitNumber = -1;
mTimeSlot = slot; mTimeSlot = slot;
if ( mBitState == BIT_STATE_IN_PACKET ) if ( mBitState == BIT_STATE_IN_PACKET )
return; return;
mRXPacket->setSlot(slot); if ( mRXPacket )
if ( mSwitchAtNextSlot ) mRXPacket->setSlot(slot);
if ( mChannel != mNextChannel )
{ {
mSwitchAtNextSlot = false; startReceiving(mNextChannel, false);
startReceiving(mSwitchToChannel, false);
} }
} }
void Receiver::processNRZIBit(uint8_t bit) /**
* This method must complete in a few microseconds, worst case!
*/
Receiver::Action Receiver::processNRZIBit(uint8_t bit)
{ {
if ( mLastNRZIBit == 0xff ) if ( mLastNRZIBit == 0xff )
{ {
mLastNRZIBit = bit; mLastNRZIBit = bit;
return; return NO_ACTION;
} }
uint8_t decodedBit = !(mLastNRZIBit ^ bit); uint8_t decodedBit = !(mLastNRZIBit ^ bit);
@ -178,7 +204,7 @@ void Receiver::processNRZIBit(uint8_t bit)
mBitWindow |= decodedBit; mBitWindow |= decodedBit;
/* /*
* By checking for the last few training bits plus the HDLC start flag, * By checking for the last few preamble bits plus the HDLC start flag,
* we gain enough confidence that this is not random noise. * we gain enough confidence that this is not random noise.
*/ */
if ( mBitWindow == 0b1010101001111110 || mBitWindow == 0b0101010101111110 ) if ( mBitWindow == 0b1010101001111110 || mBitWindow == 0b0101010101111110 )
@ -194,29 +220,29 @@ void Receiver::processNRZIBit(uint8_t bit)
if ( mRXPacket->size() >= MAX_AIS_RX_PACKET_SIZE ) if ( mRXPacket->size() >= MAX_AIS_RX_PACKET_SIZE )
{ {
// Start over // Start over
startReceiving(mChannel, false); return RESTART_RX;
return;
} }
if ( mOneBitCount >= 7 ) if ( mOneBitCount >= 7 )
{ {
// Bad packet! // Bad packet!
startReceiving(mChannel, false); return RESTART_RX;
return;
} }
mLastNRZIBit = bit; mLastNRZIBit = bit;
mBitWindow <<= 1; mBitWindow <<= 1;
mBitWindow |= decodedBit; mBitWindow |= decodedBit;
if ( (mBitWindow & 0x00ff) == 0x7E ) if ( (mBitWindow & 0x00ff) == 0x7E )
{ {
// We have a complete packet
mBitState = BIT_STATE_PREAMBLE_SYNC; mBitState = BIT_STATE_PREAMBLE_SYNC;
/**
* This is the longest operation undertaken here. Now that we use object pools and pointers,
* it completes in about 14us
*/
pushPacket(); pushPacket();
startReceiving(mChannel, false); return RESTART_RX;
} }
else else
{ {
@ -227,6 +253,7 @@ void Receiver::processNRZIBit(uint8_t bit)
} }
} }
return NO_ACTION;
} }
@ -267,29 +294,36 @@ bool Receiver::addBit(uint8_t bit)
void Receiver::pushPacket() void Receiver::pushPacket()
{ {
Event *p = EventPool::instance().newEvent(AIS_PACKET_EVENT); Event *p = EventPool::instance().newEvent(AIS_PACKET_EVENT);
RXPacket *currPacket = mRXPacket; ASSERT_VALID_PTR(p);
mRXPacket = EventPool::instance().newRXPacket();
ASSERT_VALID_PTR(mRXPacket);
if ( p ) if ( p )
{ {
//bsp_signal_high(); //bsp_signal_high();
p->rxPacket = currPacket; p->rxPacket = mRXPacket;
EventQueue::instance().push(p); EventQueue::instance().push(p);
//bsp_signal_low(); //bsp_signal_low();
mRXPacket = EventPool::instance().newRXPacket();
}
else
{
/**
* We're out of resources so just keep using the existing packet.
* If this happens, the most logical outcome is a watchdog reset
* because something has blocked the main task and the pool is not
* getting replenished
*/
mRXPacket->reset();
} }
mRXPacket->reset();
} }
/**
* This operation typically takes under 85us
*/
uint8_t Receiver::reportRSSI() uint8_t Receiver::reportRSSI()
{ {
//bsp_signal_high();
uint8_t rssi = readRSSI(); uint8_t rssi = readRSSI();
//bsp_signal_low();
char channel = AIS_CHANNELS[mChannel].designation; char channel = AIS_CHANNELS[mChannel].designation;
NoiseFloorDetector::instance().report(channel, rssi); NoiseFloorDetector::instance().report(channel, rssi);
return rssi; return rssi;
} }
@ -303,7 +337,7 @@ void Receiver::configureGPIOsForRX()
gpiocfg.NIRQ = 0x00; // Nothing gpiocfg.NIRQ = 0x00; // Nothing
gpiocfg.SDO = 0x00; // No change gpiocfg.SDO = 0x00; // No change
gpiocfg.GENCFG = 0x00; // No change gpiocfg.GENCFG = 0x00; // No change
sendCmd(GPIO_PIN_CFG, &gpiocfg, sizeof gpiocfg, &gpiocfg, sizeof gpiocfg); sendCmd(GPIO_PIN_CFG, &gpiocfg, sizeof gpiocfg, NULL, 0);
} }

View File

@ -150,7 +150,7 @@ void Transceiver::configureGPIOsForTX(tx_power_level powerLevel)
gpiocfg.NIRQ = 0x1A; // Sync word detect gpiocfg.NIRQ = 0x1A; // Sync word detect
gpiocfg.SDO = 0x00; // No change gpiocfg.SDO = 0x00; // No change
gpiocfg.GENCFG = 0x00; // No change gpiocfg.GENCFG = 0x00; // No change
sendCmd(GPIO_PIN_CFG, &gpiocfg, sizeof gpiocfg, &gpiocfg, sizeof gpiocfg); sendCmd(GPIO_PIN_CFG, &gpiocfg, sizeof gpiocfg, NULL, 0);
setTXPower(powerLevel); setTXPower(powerLevel);
} }
@ -323,7 +323,7 @@ void Transceiver::configureGPIOsForRX()
gpiocfg.NIRQ = 0x00; // Nothing gpiocfg.NIRQ = 0x00; // Nothing
gpiocfg.SDO = 0x00; // No change gpiocfg.SDO = 0x00; // No change
gpiocfg.GENCFG = 0x00; // No change gpiocfg.GENCFG = 0x00; // No change
sendCmd(GPIO_PIN_CFG, &gpiocfg, sizeof gpiocfg, &gpiocfg, sizeof gpiocfg); sendCmd(GPIO_PIN_CFG, &gpiocfg, sizeof gpiocfg, NULL, 0);
} }
void Transceiver::reportTXEvent() void Transceiver::reportTXEvent()