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
42
46class ISX1278 : public Transceiver
47{
48public:
52 virtual float getLastRxRssi() = 0;
53
58 virtual float getLastRxFei() { return std::nanf(""); }
59
64 virtual float getLastRxSnr() { return std::nanf(""); }
65
66protected:
67 /*
68 * Stuff used internally by SX1278Common
69 */
70
71 using IrqFlags = int;
72 using Mode = int;
73
74 virtual void setMode(Mode mode) = 0;
75 virtual void setMapping(DioMapping mapping) = 0;
76
77 virtual IrqFlags getIrqFlags() = 0;
78 virtual void resetIrqFlags(IrqFlags flags) = 0;
79};
80
85{
86public:
90 virtual bool isOnPaBoost() = 0;
91
95 virtual int maxInPower() = 0;
96
97 virtual void enableRx() = 0;
98 virtual void disableRx() = 0;
99 virtual void enableTx() = 0;
100 virtual void disableTx() = 0;
101};
102
103class SX1278Common : public ISX1278
104{
105private:
106 struct DeviceState
107 {
108 // Current device mode (dummy number to signal no mode)
109 Mode mode = -1;
110 // Current Dio mapping
111 DioMapping mapping = DioMapping();
112 // Thread waiting listening for interrupts
113 miosix::Thread* irq_wait_thread = nullptr;
114 // True if the RX frontend is enabled
115 bool is_rx_frontend_on = false;
116 // True if the TX frontend is enabled
117 bool is_tx_frontend_on = false;
118 // Mode of trigger for dio1
120 };
121
122 // This is reasonably the maximum we should wait for an interrupt
123 static constexpr int IRQ_TIMEOUT = 100;
124
125public:
129 void handleDioIRQ();
130
131protected:
132 explicit SX1278Common(SPIBus& bus, miosix::GpioPin cs, miosix::GpioPin dio0,
133 miosix::GpioPin dio1, miosix::GpioPin dio3,
135 std::unique_ptr<ISX1278Frontend> frontend)
136 : slave(SPISlave(bus, cs, getSpiBusConfig(clock_divider))), dio0(dio0),
137 dio1(dio1), dio3(dio3), frontend(std::move(frontend))
138 {
139 enableIrqs();
140 }
141
142 ~SX1278Common() { disableIrqs(); }
143
147 class Lock
148 {
149 public:
150 explicit Lock(SX1278Common& driver) : driver(driver) { driver.lock(); }
151
152 ~Lock() { driver.unlock(); }
153
154 private:
155 SX1278Common& driver;
156 };
157
162 {
163 public:
164 LockMode(SX1278Common& driver, Lock& lock, Mode mode,
165 DioMapping mapping, InterruptTrigger dio1_trigger,
166 bool set_tx_frontend_on = false,
167 bool set_rx_frontend_on = false)
168 : driver(driver), lock(lock)
169 {
170 // cppcheck-suppress useInitializationList
171 old_state = driver.lockMode(mode, mapping, dio1_trigger,
173 }
174
175 ~LockMode() { driver.unlockMode(old_state); }
176
177 private:
178 SX1278Common& driver;
179 Lock& lock;
180 DeviceState old_state;
181 };
182
188 void setDefaultMode(Mode mode, DioMapping mapping,
189 InterruptTrigger dio1_trigger, bool set_tx_frontend_on,
190 bool set_rx_frontend_on);
191
195 IrqFlags waitForIrq(LockMode& guard, IrqFlags set_irq, IrqFlags reset_irq,
196 bool unlock = false);
197
203 IrqFlags waitForIrqBusy(LockMode& guard, IrqFlags set_irq,
204 IrqFlags reset_irq, int timeout);
205
217 IrqFlags checkForIrqAndReset(IrqFlags set_irq, IrqFlags reset_irq);
218
220
222
223private:
224 void enableIrqs();
225 void disableIrqs();
226
227 bool waitForIrqInner(LockMode& guard, bool unlock);
228
229 DeviceState lockMode(Mode mode, DioMapping mapping,
230 InterruptTrigger dio1_trigger, bool set_tx_frontend_on,
231 bool set_rx_frontend_on);
232 void unlockMode(DeviceState old_state);
233
234 void lock();
235 void unlock();
236
237 void enterMode(Mode mode, DioMapping mapping, InterruptTrigger dio1_trigger,
238 bool set_tx_frontend_on, bool set_rx_frontend_on);
239
240 miosix::FastMutex mutex;
241 DeviceState state;
242 SPISlave slave;
243 miosix::GpioPin dio0;
244 miosix::GpioPin dio1;
245 miosix::GpioPin dio3;
246 std::unique_ptr<ISX1278Frontend> frontend;
247};
248
249} // namespace SX1278
250
251} // 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
This file includes all the types the logdecoder script will decode.
Definition WIZ5500.h:318
Contains information about a single SPI slave device.
Represents an actual Dio mapping..
Definition SX1278Defs.h:93