Skyward boardcore
Loading...
Searching...
No Matches
SX1278Common.cpp
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#include "SX1278Common.h"
24
25#include <kernel/scheduler/scheduler.h>
26#include <utils/KernelTime.h>
27
28namespace Boardcore
29{
30
31namespace SX1278
32{
33
35{
36 if (state.irq_wait_thread)
37 {
38 state.irq_wait_thread->IRQwakeup();
39 if (state.irq_wait_thread->IRQgetPriority() >
40 miosix::Thread::IRQgetCurrentThread()->IRQgetPriority())
41 {
42 miosix::Scheduler::IRQfindNextThread();
43 }
44
45 state.irq_wait_thread = nullptr;
46 }
47}
48
49void SX1278Common::enableIrqs()
50{
54}
55
56void SX1278Common::disableIrqs()
57{
61}
62
64 InterruptTrigger dio1_trigger,
65 bool tx_frontend, bool rx_frontend)
66{
67 miosix::Lock<miosix::FastMutex> lock(mutex);
68 enterMode(mode, mapping, dio1_trigger, tx_frontend, rx_frontend);
69}
70
72 IrqFlags reset_irq, bool unlock)
73{
74 IrqFlags ret_irq = 0;
75
76 // Save current thread priority
77 auto oldPriority = miosix::Thread::getCurrentThread()->getPriority();
78 // While the current thread is acting as an IRQ handler, increase its
79 // priority if it's too low to ensure IRQs are handled in a timely manner
80 if (oldPriority < MIN_IRQ_PRIORITY)
81 miosix::Thread::getCurrentThread()->setPriority(MIN_IRQ_PRIORITY);
82
83 do
84 {
85 // An interrupt could occur and read from this variables
86 {
87 miosix::FastInterruptDisableLock lock;
88 state.irq_wait_thread = miosix::Thread::IRQgetCurrentThread();
89 }
90
91 // Check that this hasn't already happened
93 break;
94
95 if (!waitForIrqInner(guard, unlock))
96 {
97 // TODO: Something bad happened, do something!
98 }
99
100 // TODO: Check state of the device, and reset if needed!
101
102 // Protect against sporadic IRQs
103 } while ((ret_irq = checkForIrqAndReset(set_irq, reset_irq)) == 0);
104
105 // Restore the previous thread priority if it was changed
106 if (oldPriority < MIN_IRQ_PRIORITY)
107 miosix::Thread::getCurrentThread()->setPriority(oldPriority);
108
109 return ret_irq;
110}
111
115{
116 // Take a reference to a _guard to MAKE SURE that the mutex is locked, but
117 // otherwise don't do anything with it
118 (void)_guard;
119
120 long long start = Kernel::getOldTick();
121 IrqFlags ret_irq = 0;
122
123 while ((Kernel::getOldTick() - start) < timeout)
124 {
125 // Delay between polls
126 const unsigned int DELAY = 100;
127
128 // Tight loop on IRQ register
129 for (unsigned int i = 0; i < 1000 / DELAY; i++)
130 {
131 // Check if some of the interrupts triggered
133 return ret_irq;
134
135 miosix::delayUs(DELAY);
136 }
137 }
138
139 return 0;
140}
141
142bool SX1278Common::waitForIrqInner(LockMode& _guard, bool unlock)
143{
144 // Take a reference to a _guard to MAKE SURE that the mutex is locked, but
145 // otherwise don't do anything with it
146 (void)_guard;
147
148 // Release the lock for others to take
149 if (unlock)
150 mutex.unlock();
151
152 int start = Kernel::getOldTick();
153 miosix::TimedWaitResult result = miosix::TimedWaitResult::NoTimeout;
154
155 {
156 miosix::FastInterruptDisableLock lock;
157 while (state.irq_wait_thread &&
158 result == miosix::TimedWaitResult::NoTimeout)
159 {
161 lock, start + IRQ_TIMEOUT);
162 }
163 }
164
165 // Regain ownership of the lock
166 if (unlock)
167 mutex.lock();
168
169 // Check that we didn't have a timeout
170 return result == miosix::TimedWaitResult::NoTimeout;
171}
172
175{
177 if (cur_irq & set_irq)
178 {
179 // Reset all of the interrupts we have detected
181 }
182
183 return (cur_irq & set_irq) | (~cur_irq & reset_irq);
184}
185
187
189
190SX1278Common::DeviceState SX1278Common::lockMode(Mode mode, DioMapping mapping,
191 InterruptTrigger dio1_trigger,
192 bool tx_frontend,
193 bool rx_frontend)
194{
195 // Store previous state
196 DeviceState old_state = state;
197
198 enterMode(mode, mapping, dio1_trigger, tx_frontend, rx_frontend);
199 state.irq_wait_thread = nullptr;
200
201 return old_state;
202}
203
204void SX1278Common::unlockMode(DeviceState old_state)
205{
206 // Do this copy manually, we want stuff to be copied in a specific order
207 state.irq_wait_thread = old_state.irq_wait_thread;
208 enterMode(old_state.mode, old_state.mapping, old_state.dio1_trigger,
209 old_state.is_tx_frontend_on, old_state.is_rx_frontend_on);
210}
211
212void SX1278Common::lock() { mutex.lock(); }
213
214void SX1278Common::unlock() { mutex.unlock(); }
215
216void SX1278Common::enterMode(Mode mode, DioMapping mapping,
217 InterruptTrigger dio1_trigger,
218 bool set_tx_frontend_on, bool set_rx_frontend_on)
219{
220 // disable - enable in order to avoid having both RX/TX frontends active at
221 // the same time
222
223 // First disable all of the frontend if necessary
224 if (set_tx_frontend_on != state.is_tx_frontend_on && !set_tx_frontend_on)
226
227 if (set_rx_frontend_on != state.is_rx_frontend_on && !set_rx_frontend_on)
229
230 // Then enable the newly requested ones
231 if (set_tx_frontend_on != state.is_tx_frontend_on && set_tx_frontend_on)
233
234 if (set_rx_frontend_on != state.is_rx_frontend_on && set_rx_frontend_on)
236
237 state.is_tx_frontend_on = set_tx_frontend_on;
238 state.is_rx_frontend_on = set_rx_frontend_on;
239
240 if (mode != state.mode)
241 {
242 setMode(mode);
243 state.mode = mode;
244 }
245
246 // Change DIO1 interrupt kind
247 if (dio1_trigger != state.dio1_trigger)
248 {
249 changeInterruptTrigger(dio1, dio1_trigger);
250 state.dio1_trigger = dio1_trigger;
251 }
252
253 // Finally setup DIO mapping
254 if (mapping != state.mapping)
255 {
256 setMapping(mapping);
257 state.mapping = mapping;
258 }
259}
260
261} // namespace SX1278
262
263} // namespace Boardcore
Shared interface between all SX1278 frontends.
virtual IrqFlags getIrqFlags()=0
virtual void setMode(Mode mode)=0
virtual void setMapping(DioMapping mapping)=0
virtual void resetIrqFlags(IrqFlags flags)=0
RAII scoped bus lock guard.
RAII scoped mode lock, requires a previous lock.
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.
IrqFlags waitForIrq(LockMode &guard, IrqFlags set_irq, IrqFlags reset_irq, bool unlock=false)
Wait for generic irq.
void changeInterruptTrigger(unsigned int gpioPort, unsigned int gpioNum, InterruptTrigger trigger)
Changes interrupt trigger on an enabled interrupt.
void disableExternalInterrupt(unsigned int gpioPort, unsigned int gpioNum)
Disables external interrupts on the provided pin.
void enableExternalInterrupt(unsigned int gpioPort, unsigned int gpioNum, InterruptTrigger trigger, unsigned int priority)
Enables external interrupts on the provided pin. Remember to set the GPIO to input mode!
InterruptTrigger
miosix::TimedWaitResult IRQenableIrqAndTimedWaitMs(miosix::FastInterruptDisableLock &dLock, long long absoluteTimeMs)
Stops the thread until wakeup() is called or the specified absolute time in milliseconds is reached.
Definition KernelTime.h:87
long long getOldTick()
Get the current time in milliseconds.
Definition KernelTime.h:43
RegDioMapping::Mapping DioMapping
Driver for the VN100S IMU.
Contains information about a single SPI slave device.
Represents an actual Dio mapping..
Definition SX1278Defs.h:93