1
0
mirror of https://github.com/peterantypas/maiana.git synced 2025-05-16 15:30:10 -07:00
maiana/latest/Firmware/Transponder/Src/RadioManager.cpp
2021-09-23 15:06:51 -07:00

216 lines
4.9 KiB
C++

/*
Copyright (c) 2016-2020 Peter Antypas
This file is part of the MAIANA™ transponder firmware.
The firmware is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>
*/
#include "RadioManager.hpp"
#include "NoiseFloorDetector.hpp"
#include "bsp.hpp"
#include "TXErrors.h"
void rxClockCB();
void trxClockCB();
RadioManager &RadioManager::instance()
{
static RadioManager __instance;
return __instance;
}
RadioManager::RadioManager()
: mTXQueue(4)
{
mTransceiverIC = NULL;
mReceiverIC = NULL;
mInitializing = true;
mUTC = 0;
EventQueue::instance().addObserver(this, CLOCK_EVENT);
}
bool RadioManager::initialized()
{
return !mInitializing;
}
void RadioManager::init()
{
NoiseFloorDetector::instance();
mTransceiverIC = new Transceiver(SDN1_PORT, SDN1_PIN,
CS1_PORT, CS1_PIN,
TRX_IC_DATA_PORT, TRX_IC_DATA_PIN,
TRX_IC_CLK_PORT, TRX_IC_CLK_PIN, 0);
mTransceiverIC->init();
mReceiverIC = new Receiver(SDN2_PORT, SDN2_PIN,
CS2_PORT, CS2_PIN,
RX_IC_DATA_PORT, RX_IC_DATA_PIN,
RX_IC_CLK_PORT, RX_IC_CLK_PIN, 1);
mReceiverIC->init();
mInitializing = false;
}
void RadioManager::transmitCW(VHFChannel channel)
{
mTransceiverIC->transmitCW(channel);
}
void RadioManager::start()
{
configureInterrupts();
if ( mTransceiverIC )
mTransceiverIC->startReceiving(CH_87, true);
if ( mReceiverIC )
mReceiverIC->startReceiving(CH_88, true);
GPS::instance().setDelegate(this);
}
void RadioManager::stop()
{
// TODO: Implement this
}
void RadioManager::configureInterrupts()
{
bsp_set_trx_clk_callback(trxClockCB);
bsp_set_rx_clk_callback(rxClockCB);
}
void RadioManager::processEvent(const Event &e)
{
mUTC = e.clock.utc;
if ( mStartTime == 0 )
{
mStartTime = mUTC;
}
if ( !mTXQueue.empty() && mTransceiverIC->assignedTXPacket() == NULL )
{
// There is no current TX operation pending, so we assign one
TXPacket *packet = NULL;
mTXQueue.pop(packet);
ASSERT(packet);
VHFChannel txChannel = packet->channel();
// Do we need to swap channels?
if ( txChannel != mTransceiverIC->channel() )
{
// The receiver needs to be explicitly told to switch channels
if ( mReceiverIC )
mReceiverIC->switchToChannel(alternateChannel(txChannel));
}
// The transceiver will switch channel if the packet channel is different
mTransceiverIC->assignTXPacket(packet);
}
else if ( mUTC - mStartTime >= 3600 )
{
/**
* For some reason, RX performance seems to go downhill after many hours
* of continuous operation, so the easiest remedy is to reboot every hour.
* The impact of this is pretty small.
*/
bsp_reboot();
}
}
VHFChannel RadioManager::alternateChannel(VHFChannel channel)
{
// TODO: Delegate this to the ChannelManager
return channel == CH_88 ? CH_87 : CH_88;
}
void RadioManager::onBitClock(uint8_t ic)
{
if ( mInitializing )
return;
if ( ic == 1 && mTransceiverIC )
mTransceiverIC->onBitClock();
else if ( mReceiverIC )
mReceiverIC->onBitClock();
}
void RadioManager::timeSlotStarted(uint32_t slotNumber)
{
if ( mInitializing )
return;
mTransceiverIC->timeSlotStarted(slotNumber);
mReceiverIC->timeSlotStarted(slotNumber);
}
void RadioManager::scheduleTransmission(TXPacket *packet)
{
#if REPORT_TX_SCHEDULING
Event *e = EventPool::instance().newEvent(PROPR_NMEA_SENTENCE);
#endif
if ( !mTXQueue.push(packet) )
{
#if REPORT_TX_SCHEDULING
if ( e )
{
sprintf(e->nmeaBuffer.sentence, "$PAISCHTX,%s,%d*", packet->messageType(), TX_QUEUE_FULL);
Utils::completeNMEA(e->nmeaBuffer.sentence);
EventQueue::instance().push(e);
}
#endif
TXPacketPool::instance().deleteTXPacket(packet);
}
#if REPORT_TX_SCHEDULING
else
{
if ( e )
{
sprintf(e->nmeaBuffer.sentence, "$PAISCHTX,%s,%d*", packet->messageType(), TX_NO_ERROR);
Utils::completeNMEA(e->nmeaBuffer.sentence);
EventQueue::instance().push(e);
}
}
#endif
}
void RadioManager::sendTestPacketNow(TXPacket *packet)
{
if ( mTransceiverIC )
{
mTransceiverIC->assignTXPacket(packet);
}
}
void rxClockCB()
{
RadioManager::instance().onBitClock(2);
}
void trxClockCB()
{
RadioManager::instance().onBitClock(1);
}