Skyward boardcore
Loading...
Searching...
No Matches
SX1278Common.h
Go to the documentation of this file.
1/* Copyright (c) 2022 Skyward Experimental Rocketry
2 * Author: Davide Mor
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
27#include <miosix.h>
28#include <radio/Transceiver.h>
29
30#include <cmath>
31#include <memory>
32
33#include "SX1278Defs.h"
34
35namespace Boardcore
36{
37
38namespace SX1278
39{
40// The minimum required thread priority to ensure IRQs are handled in a timely
41// manner, to avoid packet loss because of high data retrieval latency
42static constexpr auto MIN_IRQ_PRIORITY = miosix::PRIORITY_MAX - 2;
43
45
49class ISX1278 : public Transceiver
50{
51public:
55 virtual float getLastRxRssi() = 0;
56
61 virtual float getLastRxFei() { return std::nanf(""); }
62
67 virtual float getLastRxSnr() { return std::nanf(""); }
68
69protected:
70 /*
71 * Stuff used internally by SX1278Common
72 */
73
74 using IrqFlags = int;
75 using Mode = int;
76
77 virtual void setMode(Mode mode) = 0;
78 virtual void setMapping(DioMapping mapping) = 0;
79
80 virtual IrqFlags getIrqFlags() = 0;
81 virtual void resetIrqFlags(IrqFlags flags) = 0;
82};
83
88{
89public:
93 virtual bool isOnPaBoost() = 0;
94
98 virtual int maxInPower() = 0;
99
100 virtual void enableRx() = 0;
101 virtual void disableRx() = 0;
102 virtual void enableTx() = 0;
103 virtual void disableTx() = 0;
104};
105
106class SX1278Common : public ISX1278
107{
108private:
109 struct DeviceState
110 {
111 // Current device mode (dummy number to signal no mode)
112 Mode mode = -1;
113 // Current Dio mapping
114 DioMapping mapping = DioMapping();
115 // Thread waiting listening for interrupts
116 miosix::Thread* irq_wait_thread = nullptr;
117 // True if the RX frontend is enabled
118 bool is_rx_frontend_on = false;
119 // True if the TX frontend is enabled
120 bool is_tx_frontend_on = false;
121 // Mode of trigger for dio1
123 };
124
125 // This is reasonably the maximum we should wait for an interrupt
126 static constexpr int IRQ_TIMEOUT = 100;
127
128public:
132 void handleDioIRQ();
133
134protected:
135 explicit SX1278Common(SPIBus& bus, miosix::GpioPin cs, miosix::GpioPin dio0,
136 miosix::GpioPin dio1, miosix::GpioPin dio3,
138 std::unique_ptr<ISX1278Frontend> frontend)
139 : slave(SPISlave(bus, cs, getSpiBusConfig(clock_divider))), dio0(dio0),
140 dio1(dio1), dio3(dio3), frontend(std::move(frontend))
141 {
142 enableIrqs();
143 }
144
145 ~SX1278Common() { disableIrqs(); }
146
150 class Lock
151 {
152 public:
153 explicit Lock(SX1278Common& driver) : driver(driver) { driver.lock(); }
154
155 ~Lock() { driver.unlock(); }
156
157 private:
158 SX1278Common& driver;
159 };
160
165 {
166 public:
167 LockMode(SX1278Common& driver, Lock& lock, Mode mode,
168 DioMapping mapping, InterruptTrigger dio1_trigger,
169 bool set_tx_frontend_on = false,
170 bool set_rx_frontend_on = false)
171 : driver(driver), lock(lock)
172 {
173 // cppcheck-suppress useInitializationList
174 old_state = driver.lockMode(mode, mapping, dio1_trigger,
176 }
177
178 ~LockMode() { driver.unlockMode(old_state); }
179
180 private:
181 SX1278Common& driver;
182 Lock& lock;
183 DeviceState old_state;
184 };
185
191 void setDefaultMode(Mode mode, DioMapping mapping,
192 InterruptTrigger dio1_trigger, bool set_tx_frontend_on,
193 bool set_rx_frontend_on);
194
198 IrqFlags waitForIrq(LockMode& guard, IrqFlags set_irq, IrqFlags reset_irq,
199 bool unlock = false);
200
206 IrqFlags waitForIrqBusy(LockMode& guard, IrqFlags set_irq,
207 IrqFlags reset_irq, int timeout);
208
220 IrqFlags checkForIrqAndReset(IrqFlags set_irq, IrqFlags reset_irq);
221
223
225
226private:
227 void enableIrqs();
228 void disableIrqs();
229
230 bool waitForIrqInner(LockMode& guard, bool unlock);
231
232 DeviceState lockMode(Mode mode, DioMapping mapping,
233 InterruptTrigger dio1_trigger, bool set_tx_frontend_on,
234 bool set_rx_frontend_on);
235 void unlockMode(DeviceState old_state);
236
237 void lock();
238 void unlock();
239
240 void enterMode(Mode mode, DioMapping mapping, InterruptTrigger dio1_trigger,
241 bool set_tx_frontend_on, bool set_rx_frontend_on);
242
243 miosix::FastMutex mutex;
244 DeviceState state;
245 SPISlave slave;
246 miosix::GpioPin dio0;
247 miosix::GpioPin dio1;
248 miosix::GpioPin dio3;
249 std::unique_ptr<ISX1278Frontend> frontend;
250};
251
252} // namespace SX1278
253
254} // namespace Boardcore
Driver for STM32 low level SPI peripheral.
Definition SPIBus.h:61
Shared interface between all SX1278 frontends.
virtual bool isOnPaBoost()=0
Is this frontend connected to PA_BOOST or RFO_LF/_HF?
virtual int maxInPower()=0
What is the maximum power supported by this frontend?
Shared interface between all SX1278 drivers.
virtual IrqFlags getIrqFlags()=0
virtual float getLastRxFei()
Get the frequency error index in Hz, during last packet receive (NaN if not available).
virtual void setMode(Mode mode)=0
virtual void setMapping(DioMapping mapping)=0
virtual void resetIrqFlags(IrqFlags flags)=0
virtual float getLastRxRssi()=0
Get the RSSI in dBm, during last packet receive.
virtual float getLastRxSnr()
Get the signal to noise ratio, during last packet receive (NaN if not available).
RAII scoped bus lock guard.
RAII scoped mode lock, requires a previous lock.
LockMode(SX1278Common &driver, Lock &lock, Mode mode, DioMapping mapping, InterruptTrigger dio1_trigger, bool set_tx_frontend_on=false, bool set_rx_frontend_on=false)
void handleDioIRQ()
Handle generic DIO irq.
IrqFlags waitForIrqBusy(LockMode &guard, IrqFlags set_irq, IrqFlags reset_irq, int timeout)
Busy waits for an interrupt by polling the irq register.
void setDefaultMode(Mode mode, DioMapping mapping, InterruptTrigger dio1_trigger, bool set_tx_frontend_on, bool set_rx_frontend_on)
Set default device mode.
IrqFlags checkForIrqAndReset(IrqFlags set_irq, IrqFlags reset_irq)
Returns a mask containing triggered interrupts.
SX1278Common(SPIBus &bus, miosix::GpioPin cs, miosix::GpioPin dio0, miosix::GpioPin dio1, miosix::GpioPin dio3, SPI::ClockDivider clock_divider, std::unique_ptr< ISX1278Frontend > frontend)
IrqFlags waitForIrq(LockMode &guard, IrqFlags set_irq, IrqFlags reset_irq, bool unlock=false)
Wait for generic irq.
InterruptTrigger
ClockDivider
SPI Clock divider.
Definition SPIDefs.h:70
SPIBusConfig getSpiBusConfig(SPI::ClockDivider clock_divider)
Definition SX1278Defs.h:45
RegDioMapping::Mapping DioMapping
Driver for the VN100S IMU.
Definition WIZ5500.h:339
Contains information about a single SPI slave device.
Represents an actual Dio mapping..
Definition SX1278Defs.h:93