Skip to content

Commit d23a10a

Browse files
committed
Initial commit
0 parents  commit d23a10a

File tree

15 files changed

+808
-0
lines changed

15 files changed

+808
-0
lines changed

LICENSE.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Copyright 2023, Thomas Spielauer
2+
3+
Redistribution and use in source and binary forms, with or without modification,
4+
are permitted provided that the following conditions are met:
5+
6+
* Redistributions of source code must retain this list of conditions
7+
and the following disclaimer.
8+
* Redistributions in binary form must reproduce this list of conditions
9+
and the following disclaimer in the documentation and/or other materials
10+
provided with the distribution.
11+
* Neither the name of the copyright holder nor the names of its contributors
12+
may be used to endorse or promote products derived from this software without
13+
specific prior written permission.
14+
15+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18+
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
19+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# GPIO wrapper for FreeBSD
2+
3+
This is a simple collection of GPIO wrappers for various languages
4+
for the FreeBSD gpio device. Currently it contains:
5+
6+
* An native ANSI C wrapper in ```native```
7+
* A Python wrapper based on the ```ioctl``` interface of the ```fcntl```
8+
module. This is an implementation of the ```GPIO``` class
9+
of the [labdevices GPIO base class](https://github.com/tspspi/pylabdevs/blob/master/src/labdevices/gpio.py)
10+
11+
Those wrappers have been used to access the GPIO pins on platforms
12+
like the RaspberryPi.

native/GPIO.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# GPIO module
2+
3+
The GPIO module provides a simple wrapper over the respective platforms
4+
GPIO system. It exposes an object oriented interface. It gets initialized
5+
via either
6+
7+
```
8+
enum gpioError gpioOpen(struct gpio** lpOut, const char* lpFilename);
9+
```
10+
11+
or
12+
13+
```
14+
enum gpioError gpioOpenDefault(struct gpio** lpOut);
15+
```
16+
17+
In the latter case the default GPIO port on the respective platform is used.
18+
19+
## Common operations
20+
21+
### Releasing / closing the GPIO subsystem
22+
23+
```
24+
gpioObject->vtbl->release(gpioObject);
25+
```
26+
27+
### Querying the number of I/O channels
28+
29+
```
30+
unsigned long int channels;
31+
enum gpioError e;
32+
33+
e = gpioObject->vtbl->getIOCount(gpioObject, &channels);
34+
```
35+
36+
### Setting input or output direction
37+
38+
```
39+
enum gpioError e;
40+
41+
e = gpioObject->vtbl->setModeInput(gpioObject, PINNUMBER);
42+
e = gpioObject->vtbl->setModeOutput(gpioObject, PINNUMBER);
43+
```
44+
45+
### Setting output state
46+
47+
```
48+
e = gpioObject->vtbl->set(gpioObject, PINNUMBER, 1);
49+
e = gpioObject->vtbl->set(gpioObject, PINNUMBER, 0);
50+
```
51+
52+
### Pulsing an output port
53+
54+
```
55+
# The delay is given in microseconds so to pulse for 1 millisecond:
56+
57+
e = gpioObject->vtbl->pulse(gpioObject, PINNUMBER, 1000);
58+
```
59+
60+
### Reading an input port
61+
62+
```
63+
int state;
64+
65+
e = gpioObject->vtbl->get(gpioObject, PINNUMBER, &state);
66+
```
67+

native/gpio.c

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
#include <fcntl.h>
2+
#include <stdlib.h>
3+
#include <unistd.h>
4+
5+
#include <sys/gpio.h>
6+
7+
#include "./gpio.h"
8+
9+
struct gpioImpl {
10+
struct gpio base;
11+
12+
int hHandle;
13+
unsigned long int dwMaxCount;
14+
};
15+
16+
17+
18+
static enum gpioError gpioImpl_Release(
19+
struct gpio* lpSelf
20+
) {
21+
if(lpSelf == NULL) {
22+
return gpioE_InvalidParam;
23+
}
24+
25+
struct gpioImpl* lpThis = (struct gpioImpl*)(lpSelf->lpReserved);
26+
27+
if(lpThis->hHandle == -1) {
28+
return gpioE_InvalidParam;
29+
}
30+
close(lpThis->hHandle);
31+
free(lpThis);
32+
return gpioE_Ok;
33+
}
34+
static enum gpioError gpioImpl_GetIOCount(
35+
struct gpio* lpSelf,
36+
unsigned long int* lpCountOut
37+
) {
38+
if(lpSelf == NULL) { return gpioE_InvalidParam; }
39+
if(lpCountOut == NULL) { return gpioE_Ok; }
40+
41+
(*lpCountOut) = 0;
42+
struct gpioImpl* lpThis = (struct gpioImpl*)(lpSelf->lpReserved);
43+
if(lpThis->hHandle < 0) { return gpioE_InvalidParam; }
44+
45+
(*lpCountOut) = lpThis->dwMaxCount;
46+
return gpioE_Ok;
47+
}
48+
static enum gpioError gpioImpl_SetModeInput(
49+
struct gpio* lpSelf,
50+
unsigned long int pinNumber
51+
) {
52+
if(lpSelf == NULL) { return gpioE_InvalidParam; }
53+
54+
struct gpioImpl* lpThis = (struct gpioImpl*)(lpSelf->lpReserved);
55+
56+
if(pinNumber >= lpThis->dwMaxCount) {
57+
return gpioE_InvalidParam;
58+
}
59+
60+
struct gpio_pin gpPin;
61+
gpPin.gp_pin = pinNumber;
62+
if(ioctl(lpThis->hHandle, GPIOGETCONFIG, &gpPin) < 0) {
63+
return gpioE_Failed;
64+
}
65+
66+
gpPin.gp_flags = GPIO_PIN_INPUT;
67+
if(ioctl(lpThis->hHandle, GPIOSETCONFIG, &gpPin) < 0) {
68+
return gpioE_Failed;
69+
}
70+
71+
return gpioE_Ok;
72+
}
73+
static enum gpioError gpioImpl_SetModeOutput(
74+
struct gpio* lpSelf,
75+
unsigned long int dwPinNumber
76+
) {
77+
if(lpSelf == NULL) { return gpioE_InvalidParam; }
78+
struct gpioImpl* lpThis = (struct gpioImpl*)(lpSelf->lpReserved);
79+
80+
if(dwPinNumber >= lpThis->dwMaxCount) {
81+
return gpioE_InvalidParam;
82+
}
83+
struct gpio_pin gpPin;
84+
gpPin.gp_pin = dwPinNumber;
85+
if(ioctl(lpThis->hHandle, GPIOGETCONFIG, &gpPin) < 0) { return gpioE_Failed; }
86+
gpPin.gp_flags = GPIO_PIN_OUTPUT;
87+
if(ioctl(lpThis->hHandle, GPIOSETCONFIG, &gpPin) < 0) { return gpioE_Failed; }
88+
return gpioE_Ok;
89+
}
90+
static enum gpioError gpioImpl_Set(
91+
struct gpio* lpSelf,
92+
unsigned long int pinNumber,
93+
int state
94+
) {
95+
if(lpSelf == NULL) { return gpioE_InvalidParam; }
96+
struct gpioImpl* lpThis = (struct gpioImpl*)(lpSelf->lpReserved);
97+
if(pinNumber >= lpThis->dwMaxCount) { return gpioE_InvalidParam; }
98+
99+
struct gpio_req rq;
100+
rq.gp_pin = pinNumber;
101+
rq.gp_value = (state == 0) ? 0 : 1;
102+
if(ioctl(lpThis->hHandle, GPIOSET, &rq) < 0) { return gpioE_Failed; }
103+
return gpioE_Ok;
104+
}
105+
static enum gpioError gpioImpl_Get(
106+
struct gpio* lpSelf,
107+
unsigned long int pinNumber,
108+
int* lpStateOut
109+
) {
110+
if(lpSelf == NULL) { return gpioE_InvalidParam; }
111+
if(lpStateOut == NULL) { return gpioE_Ok; }
112+
(*lpStateOut) = -1;
113+
114+
struct gpioImpl* lpThis = (struct gpioImpl*)(lpSelf->lpReserved);
115+
if(pinNumber >= lpThis->dwMaxCount) { return gpioE_InvalidParam; }
116+
117+
struct gpio_req rq;
118+
rq.gp_pin = pinNumber;
119+
if(ioctl(lpThis->hHandle, GPIOGET, &rq) < 0) { return gpioE_Failed; }
120+
(*lpStateOut) = rq.gp_value;
121+
return gpioE_Ok;
122+
}
123+
static enum gpioError gpioImpl_Pulse(
124+
struct gpio* lpSelf,
125+
unsigned long int pinNumber,
126+
unsigned long int dwMicrosecs
127+
) {
128+
if(lpSelf == NULL) { return gpioE_InvalidParam; }
129+
130+
struct gpioImpl* lpThis = (struct gpioImpl*)(lpSelf->lpReserved);
131+
if(pinNumber >= lpThis->dwMaxCount) { return gpioE_InvalidParam; }
132+
133+
struct gpio_req rq;
134+
rq.gp_pin = pinNumber;
135+
136+
if(ioctl(lpThis->hHandle, GPIOGET, &rq) < 0) { return gpioE_Failed; }
137+
138+
rq.gp_value = (rq.gp_value == 0) ? 1 : 0;
139+
if(ioctl(lpThis->hHandle, GPIOSET, &rq) < 0) { return gpioE_Failed; }
140+
usleep(dwMicrosecs);
141+
rq.gp_value = (rq.gp_value == 0) ? 1 : 0;
142+
if(ioctl(lpThis->hHandle, GPIOSET, &rq) < 0) { return gpioE_Failed; }
143+
144+
return gpioE_Ok;
145+
}
146+
147+
148+
149+
struct gpioVtbl gpioVtblDefault = {
150+
&gpioImpl_Release,
151+
152+
&gpioImpl_GetIOCount,
153+
&gpioImpl_SetModeInput,
154+
&gpioImpl_SetModeOutput,
155+
156+
&gpioImpl_Set,
157+
&gpioImpl_Get,
158+
&gpioImpl_Pulse
159+
};
160+
#ifdef __cplusplus
161+
extern "C" {
162+
#endif
163+
164+
enum gpioError gpioOpen(struct gpio** lpOut, const char* lpFilename) {
165+
struct gpioImpl* gpNew;
166+
167+
if(lpOut == NULL) {
168+
return gpioE_InvalidParam;
169+
}
170+
(*lpOut) = (struct gpio*)NULL;
171+
172+
if(lpFilename == NULL) {
173+
lpFilename = "/dev/gpioc0";
174+
}
175+
176+
gpNew = (struct gpioImpl*)malloc(sizeof(struct gpioImpl));
177+
if(gpNew == (void*)NULL) {
178+
return gpioE_OutOfMemory;
179+
}
180+
181+
gpNew->base.lpReserved = (void*)gpNew;
182+
gpNew->base.vtbl = &gpioVtblDefault;
183+
184+
gpNew->hHandle = -1;
185+
gpNew->dwMaxCount = 0;
186+
187+
/* Open device, determine maximum I/O count */
188+
gpNew->hHandle = open(lpFilename, O_RDONLY);
189+
if(gpNew->hHandle < 0) {
190+
free(gpNew);
191+
return gpioE_Failed;
192+
}
193+
194+
int maxPins;
195+
if(ioctl(gpNew->hHandle, GPIOMAXPIN, &maxPins) < 0) {
196+
close(gpNew->hHandle);
197+
free(gpNew);
198+
return gpioE_Failed;
199+
}
200+
gpNew->dwMaxCount = (unsigned long int)maxPins;
201+
202+
(*lpOut) = &(gpNew->base);
203+
return gpioE_Ok;
204+
}
205+
206+
enum gpioError gpioOpenDefault(struct gpio** lpOut) {
207+
return gpioOpen(lpOut, (void*)NULL);
208+
}
209+
210+
#ifdef __cplusplus
211+
} /* extern "C" */
212+
#endif

native/gpio.h

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#ifndef __is_included__ffcc55d5_77a0_11ee_a349_b499badf00a1
2+
#define __is_included__ffcc55d5_77a0_11ee_a349_b499badf00a1
3+
4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
8+
enum gpioError {
9+
gpioE_Ok = 0,
10+
11+
gpioE_InvalidParam,
12+
gpioE_OutOfMemory,
13+
gpioE_Failed,
14+
};
15+
16+
struct gpio;
17+
struct gpioVtbl;
18+
19+
typedef enum gpioError (*lpfnGpio_Release)(
20+
struct gpio* lpSelf
21+
);
22+
typedef enum gpioError (*lpfnGpio_GetIOCount)(
23+
struct gpio* lpSelf,
24+
unsigned long int* lpCountOut
25+
);
26+
typedef enum gpioError (*lpfnGpio_SetModeInput)(
27+
struct gpio* lpSelf,
28+
unsigned long int pinNumber
29+
);
30+
typedef enum gpioError (*lpfnGpio_SetModeOutput)(
31+
struct gpio* lpSelf,
32+
unsigned long int pinNumber
33+
);
34+
typedef enum gpioError (*lpfnGpio_Set)(
35+
struct gpio* lpSelf,
36+
unsigned long int pinNumber,
37+
int state
38+
);
39+
typedef enum gpioError (*lpfnGpio_Get)(
40+
struct gpio* lpSelf,
41+
unsigned long int pinNumber,
42+
int* lpStateOut
43+
);
44+
typedef enum gpioError (*lpfnGpio_Pulse)(
45+
struct gpio* lpSelf,
46+
unsigned long int pinNumber,
47+
unsigned long int dwMicroseconds
48+
);
49+
50+
struct gpioVtbl {
51+
lpfnGpio_Release release;
52+
53+
lpfnGpio_GetIOCount getIOCount;
54+
lpfnGpio_SetModeInput setModeInput;
55+
lpfnGpio_SetModeOutput setModeOutput;
56+
57+
lpfnGpio_Set set;
58+
lpfnGpio_Get get;
59+
lpfnGpio_Pulse pulse;
60+
};
61+
62+
struct gpio {
63+
struct gpioVtbl* vtbl;
64+
void* lpReserved;
65+
};
66+
67+
/* Constructor methods */
68+
69+
enum gpioError gpioOpen(struct gpio** lpOut, const char* lpFilename);
70+
enum gpioError gpioOpenDefault(struct gpio** lpOut);
71+
72+
#ifdef __cplusplus
73+
} /* extern "C" */
74+
#endif
75+
76+
#endif

0 commit comments

Comments
 (0)