RadioLib
Universal wireless communication library for Arduino
Loading...
Searching...
No Matches
PiHal.h
1#ifndef PI_HAL_LGPIO_H
2#define PI_HAL_LGPIO_H
3
4// include RadioLib
5#include <RadioLib.h>
6
7// include the library for Raspberry GPIO pins
8#include <lgpio.h>
9
10#define PI_RISING (LG_RISING_EDGE)
11#define PI_FALLING (LG_FALLING_EDGE)
12#define PI_INPUT (0)
13#define PI_OUTPUT (1)
14#define PI_MAX_USER_GPIO (31)
15
16// forward declaration of alert handler that will be used to emulate interrupts
17static void lgpioAlertHandler(int num_alerts, lgGpioAlert_p alerts, void *userdata);
18
19// create a new Raspberry Pi hardware abstraction layer
20// using the lgpio library
21// the HAL must inherit from the base RadioLibHal class
22// and implement all of its virtual methods
23class PiHal : public RadioLibHal {
24 public:
25 // default constructor - initializes the base HAL and any needed private members
26 PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000, uint8_t spiDevice = 0, uint8_t gpioDevice = 0)
27 : RadioLibHal(PI_INPUT, PI_OUTPUT, LG_LOW, LG_HIGH, PI_RISING, PI_FALLING),
28 _gpioDevice(gpioDevice),
29 _spiDevice(spiDevice),
30 _spiSpeed(spiSpeed),
31 _spiChannel(spiChannel) {
32 }
33
34 void init() override {
35 if(_gpioHandle != -1) {
36 return;
37 }
38
39 // first initialise lgpio library
40 if((_gpioHandle = lgGpiochipOpen(_gpioDevice)) < 0) {
41 fprintf(stderr, "Could not open GPIO chip: %s\n", lguErrorText(_gpioHandle));
42 return;
43 }
44
45 // now the SPI
46 spiBegin();
47 }
48
49 void term() override {
50 // stop the SPI
51 spiEnd();
52
53 // finally, stop the lgpio library
54 lgGpiochipClose(_gpioHandle);
55 _gpioHandle = -1;
56 }
57
58 // GPIO-related methods (pinMode, digitalWrite etc.) should check
59 // RADIOLIB_NC as an alias for non-connected pins
60 void pinMode(uint32_t pin, uint32_t mode) override {
61 if(pin == RADIOLIB_NC) {
62 return;
63 }
64
65 int result;
66 switch(mode) {
67 case PI_INPUT:
68 result = lgGpioClaimInput(_gpioHandle, pinFlags[pin], pin);
69 break;
70 case PI_OUTPUT:
71 result = lgGpioClaimOutput(_gpioHandle, pinFlags[pin], pin, LG_HIGH);
72 break;
73 default:
74 fprintf(stderr, "Unknown pinMode mode %" PRIu32 "\n", mode);
75 return;
76 }
77
78 if(result < 0) {
79 fprintf(stderr, "Could not claim pin %" PRIu32 " for mode %" PRIu32 ": %s\n",
80 pin, mode, lguErrorText(result));
81 }
82 }
83
84 void digitalWrite(uint32_t pin, uint32_t value) override {
85 if(pin == RADIOLIB_NC) {
86 return;
87 }
88
89 int result = lgGpioWrite(_gpioHandle, pin, value);
90 if(result < 0) {
91 fprintf(stderr, "Error writing value to pin %" PRIu32 ": %s\n", pin, lguErrorText(result));
92 }
93 }
94
95 uint32_t digitalRead(uint32_t pin) override {
96 if(pin == RADIOLIB_NC) {
97 return(0);
98 }
99
100 int result = lgGpioRead(_gpioHandle, pin);
101 if(result < 0) {
102 fprintf(stderr, "Error writing reading from pin %" PRIu32 ": %s\n", pin, lguErrorText(result));
103 }
104 return result;
105 }
106
107 void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
108 if((interruptNum == RADIOLIB_NC) || (interruptNum > PI_MAX_USER_GPIO)) {
109 return;
110 }
111
112 // set lgpio alert callback
113 int result = lgGpioClaimAlert(_gpioHandle, 0, mode, interruptNum, -1);
114 if(result < 0) {
115 fprintf(stderr, "Could not claim pin %" PRIu32 " for alert: %s\n", interruptNum, lguErrorText(result));
116 return;
117 }
118
119 // enable emulated interrupt
120 interruptEnabled[interruptNum] = true;
121 interruptCallbacks[interruptNum] = interruptCb;
122
123 // lpgio reports the value of level after an interrupt, not the actual direction
124 interruptModes[interruptNum] = (mode == this->GpioInterruptFalling) ? LG_LOW : LG_HIGH;
125
126 lgGpioSetAlertsFunc(_gpioHandle, interruptNum, lgpioAlertHandler, (void *)this);
127 }
128
129 void detachInterrupt(uint32_t interruptNum) override {
130 if((interruptNum == RADIOLIB_NC) || (interruptNum > PI_MAX_USER_GPIO)) {
131 return;
132 }
133
134 // clear emulated interrupt
135 interruptEnabled[interruptNum] = false;
136 interruptModes[interruptNum] = 0;
137 interruptCallbacks[interruptNum] = NULL;
138
139 // disable lgpio alert callback
140 lgGpioFree(_gpioHandle, interruptNum);
141 lgGpioSetAlertsFunc(_gpioHandle, interruptNum, NULL, NULL);
142 }
143
144 void delay(unsigned long ms) override {
145 if(ms == 0) {
146 sched_yield();
147 return;
148 }
149
150 lguSleep(ms / 1000.0);
151 }
152
153 void delayMicroseconds(unsigned long us) override {
154 if(us == 0) {
155 sched_yield();
156 return;
157 }
158
159 lguSleep(us / 1000000.0);
160 }
161
162 void yield() override {
163 sched_yield();
164 }
165
166 unsigned long millis() override {
167 uint32_t time = lguTimestamp() / 1000000UL;
168 return time;
169 }
170
171 unsigned long micros() override {
172 uint32_t time = lguTimestamp() / 1000UL;
173 return time;
174 }
175
176 long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
177 if(pin == RADIOLIB_NC) {
178 return(0);
179 }
180
181 this->pinMode(pin, PI_INPUT);
182 uint32_t start = this->micros();
183 uint32_t curtick = this->micros();
184
185 while(this->digitalRead(pin) == state) {
186 if((this->micros() - curtick) > timeout) {
187 return(0);
188 }
189 }
190
191 return(this->micros() - start);
192 }
193
194 void spiBegin() {
195 if(_spiHandle < 0) {
196 if((_spiHandle = lgSpiOpen(_spiDevice, _spiChannel, _spiSpeed, 0)) < 0) {
197 fprintf(stderr, "Could not open SPI handle on 0: %s\n", lguErrorText(_spiHandle));
198 }
199 }
200 }
201
203
204 void spiTransfer(uint8_t* out, size_t len, uint8_t* in) {
205 int result = lgSpiXfer(_spiHandle, (char *)out, (char*)in, len);
206 if(result < 0) {
207 fprintf(stderr, "Could not perform SPI transfer: %s\n", lguErrorText(result));
208 }
209 }
210
212
213 void spiEnd() {
214 if(_spiHandle >= 0) {
215 lgSpiClose(_spiHandle);
216 _spiHandle = -1;
217 }
218 }
219
220 void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) {
221 lgTxPwm(_gpioHandle, pin, frequency, 50, 0, duration);
222 }
223
224 void noTone(uint32_t pin) {
225 lgTxPwm(_gpioHandle, pin, 0, 0, 0, 0);
226 }
227
228 void pullUpDown(uint32_t pin, bool enable, bool up) {
229 if((pin == RADIOLIB_NC) || (pin > PI_MAX_USER_GPIO)) {
230 return;
231 }
232
233 pinFlags[pin] = enable ? (up ? LG_SET_PULL_UP : LG_SET_PULL_DOWN) : LG_SET_PULL_NONE;
234 }
235
236 // interrupt emulation
237 bool interruptEnabled[PI_MAX_USER_GPIO + 1];
238 uint32_t interruptModes[PI_MAX_USER_GPIO + 1];
239 typedef void (*RadioLibISR)(void);
240 RadioLibISR interruptCallbacks[PI_MAX_USER_GPIO + 1];
241
242 private:
243 // the HAL can contain any additional private members
244 const uint8_t _gpioDevice;
245 const uint8_t _spiDevice;
246 const unsigned int _spiSpeed;
247 const uint8_t _spiChannel;
248 int _gpioHandle = -1;
249 int _spiHandle = -1;
250
251 int pinFlags[PI_MAX_USER_GPIO + 1] = { 0 };
252};
253
254// this handler emulates interrupts
255static void lgpioAlertHandler(int num_alerts, lgGpioAlert_p alerts, void *userdata) {
256 if(!userdata)
257 return;
258
259 // PiHal instance is passed via the user data
260 PiHal* hal = (PiHal*)userdata;
261
262 // check the interrupt is enabled, the level matches and a callback exists
263 for(lgGpioAlert_t *alert = alerts; alert < (alerts + num_alerts); alert++) {
264 if((hal->interruptEnabled[alert->report.gpio]) &&
265 (hal->interruptModes[alert->report.gpio] == alert->report.level) &&
266 (hal->interruptCallbacks[alert->report.gpio])) {
267 hal->interruptCallbacks[alert->report.gpio]();
268 }
269 }
270}
271
272#endif
Definition PiHal.h:23
void noTone(uint32_t pin)
Method to stop producing a tone.
Definition PiHal.h:224
unsigned long millis() override
Get number of milliseconds since start. Must be implemented by the platform-specific hardware abstrac...
Definition PiHal.h:166
void digitalWrite(uint32_t pin, uint32_t value) override
Digital write method. Must be implemented by the platform-specific hardware abstraction!
Definition PiHal.h:84
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override
Measure the length of incoming digital pulse in microseconds. Must be implemented by the platform-spe...
Definition PiHal.h:176
void spiBegin()
SPI initialization method.
Definition PiHal.h:194
void spiEnd()
SPI termination method.
Definition PiHal.h:213
void init() override
Module initialization method. This will be called by all radio modules at the beginning of startup....
Definition PiHal.h:34
void spiEndTransaction()
Method to end SPI transaction.
Definition PiHal.h:211
void tone(uint32_t pin, unsigned int frequency, unsigned long duration=0)
Method to produce a square-wave with 50% duty cycle ("tone") of a given frequency at some pin.
Definition PiHal.h:220
void spiTransfer(uint8_t *out, size_t len, uint8_t *in)
Method to transfer buffer over SPI.
Definition PiHal.h:204
unsigned long micros() override
Get number of microseconds since start. Must be implemented by the platform-specific hardware abstrac...
Definition PiHal.h:171
void spiBeginTransaction()
Method to start SPI transaction.
Definition PiHal.h:202
uint32_t digitalRead(uint32_t pin) override
Digital read method. Must be implemented by the platform-specific hardware abstraction!
Definition PiHal.h:95
void delayMicroseconds(unsigned long us) override
Blocking microsecond wait function. Must be implemented by the platform-specific hardware abstraction...
Definition PiHal.h:153
void attachInterrupt(uint32_t interruptNum, void(*interruptCb)(void), uint32_t mode) override
Method to attach function to an external interrupt. Must be implemented by the platform-specific hard...
Definition PiHal.h:107
void pullUpDown(uint32_t pin, bool enable, bool up)
Enable or disable pull up or pull down for a specific pin.
Definition PiHal.h:228
void pinMode(uint32_t pin, uint32_t mode) override
GPIO pin mode (input/output/...) configuration method. Must be implemented by the platform-specific h...
Definition PiHal.h:60
void delay(unsigned long ms) override
Blocking wait function. Must be implemented by the platform-specific hardware abstraction!
Definition PiHal.h:144
void term() override
Module termination method. This will be called by all radio modules when the destructor is called....
Definition PiHal.h:49
void yield() override
Yield method, called from long loops in multi-threaded environment (to prevent blocking other threads...
Definition PiHal.h:162
void detachInterrupt(uint32_t interruptNum) override
Method to detach function from an external interrupt. Must be implemented by the platform-specific ha...
Definition PiHal.h:129
Hardware abstraction library base interface.
Definition Hal.h:16
const uint32_t GpioInterruptFalling
Value to be used as the "falling" GPIO level change direction.
Definition Hal.h:50