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