rpi_gpio 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,40 +0,0 @@
1
- /*
2
- Original code by Ben Croston modified for Ruby by Nick Lowery
3
- (github.com/clockvapor)
4
- Copyright (c) 2014-2020 Nick Lowery
5
-
6
- Copyright (c) 2013-2015 Ben Croston
7
-
8
- Permission is hereby granted, free of charge, to any person obtaining a copy of
9
- this software and associated documentation files (the "Software"), to deal in
10
- the Software without restriction, including without limitation the rights to
11
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12
- of the Software, and to permit persons to whom the Software is furnished to do
13
- so, subject to the following conditions:
14
-
15
- The above copyright notice and this permission notice shall be included in all
16
- copies or substantial portions of the Software.
17
-
18
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- SOFTWARE.
25
- */
26
-
27
- #define NO_EDGE 0
28
- #define RISING_EDGE 1
29
- #define FALLING_EDGE 2
30
- #define BOTH_EDGE 3
31
-
32
- int add_edge_detect(unsigned int gpio, unsigned int edge, int bouncetime);
33
- void remove_edge_detect(unsigned int gpio);
34
- int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio));
35
- int event_detected(unsigned int gpio);
36
- int gpio_event_added(unsigned int gpio);
37
- int event_initialise(void);
38
- void event_cleanup(int gpio);
39
- void event_cleanup_all(void);
40
- int blocking_wait_for_edge(unsigned int gpio, unsigned int edge, int bouncetime, int timeout);
@@ -1,453 +0,0 @@
1
- /*
2
- Original code by Ben Croston modified for Ruby by Nick Lowery
3
- (github.com/clockvapor)
4
- Copyright (c) 2014-2020 Nick Lowery
5
-
6
- Copyright (c) 2012-2016 Ben Croston
7
-
8
- Permission is hereby granted, free of charge, to any person obtaining a copy of
9
- this software and associated documentation files (the "Software"), to deal in
10
- the Software without restriction, including without limitation the rights to
11
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12
- of the Software, and to permit persons to whom the Software is furnished to do
13
- so, subject to the following conditions:
14
-
15
- The above copyright notice and this permission notice shall be included in all
16
- copies or substantial portions of the Software.
17
-
18
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- SOFTWARE.
25
- */
26
-
27
- #include "rb_gpio.h"
28
-
29
- extern VALUE m_GPIO;
30
- int gpio_warnings = 1;
31
-
32
- VALUE _extract_channels(VALUE channel_or_list)
33
- {
34
- VALUE channel_list;
35
-
36
- // parse arguments
37
- if (RB_TYPE_P(channel_or_list, T_ARRAY) == 1) {
38
- channel_list = channel_or_list;
39
- } else {
40
- channel_list = rb_ary_new();
41
- rb_ary_push(channel_list, channel_or_list);
42
- }
43
-
44
- return channel_list;
45
- }
46
-
47
- void define_gpio_module_stuff(void)
48
- {
49
- int i;
50
-
51
- rb_define_module_function(m_GPIO, "setup", GPIO_setup, 2);
52
- rb_define_module_function(m_GPIO, "clean_up", GPIO_clean_up, -1);
53
- rb_define_module_function(m_GPIO, "reset", GPIO_reset, 0);
54
- rb_define_module_function(m_GPIO, "set_numbering", GPIO_set_numbering, 1);
55
- rb_define_module_function(m_GPIO, "set_high", GPIO_set_high, 1);
56
- rb_define_module_function(m_GPIO, "set_low", GPIO_set_low, 1);
57
- rb_define_module_function(m_GPIO, "high?", GPIO_test_high, 1);
58
- rb_define_module_function(m_GPIO, "low?", GPIO_test_low, 1);
59
- rb_define_module_function(m_GPIO, "set_warnings", GPIO_set_warnings, 1);
60
-
61
- for (i = 0; i < 54; i++) {
62
- gpio_direction[i] = -1;
63
- }
64
-
65
- // detect board revision and set up accordingly
66
- if (get_rpi_info(&rpiinfo)) {
67
- rb_raise(rb_eRuntimeError, "this gem can only be run on a Raspberry Pi");
68
- setup_error = 1;
69
- return;
70
- } else if (rpiinfo.p1_revision == 1) {
71
- pin_to_gpio = &pin_to_gpio_rev1;
72
- } else if (rpiinfo.p1_revision == 2) {
73
- pin_to_gpio = &pin_to_gpio_rev2;
74
- } else { // assume model B+ or A+
75
- pin_to_gpio = &pin_to_gpio_rev3;
76
- }
77
- }
78
-
79
- int mmap_gpio_mem(void)
80
- {
81
- int result;
82
-
83
- if (module_setup) {
84
- return 0;
85
- }
86
-
87
- result = setup();
88
- if (result == SETUP_DEVMEM_FAIL) {
89
- rb_raise(rb_eRuntimeError, "no access to /dev/mem; try running as root");
90
- return 1;
91
- } else if (result == SETUP_MALLOC_FAIL) {
92
- rb_raise(rb_eNoMemError, "out of memory");
93
- return 2;
94
- } else if (result == SETUP_MMAP_FAIL) {
95
- rb_raise(rb_eRuntimeError, "mmap of GPIO registers failed");
96
- return 3;
97
- } else if (result == SETUP_CPUINFO_FAIL) {
98
- rb_raise(rb_eRuntimeError, "unable to open /proc/cpuinfo");
99
- return 4;
100
- } else if (result == SETUP_NOT_RPI_FAIL) {
101
- rb_raise(rb_eRuntimeError, "not running on a RPi");
102
- return 5;
103
- } else { // result == SETUP_OK
104
- module_setup = 1;
105
- return 0;
106
- }
107
- }
108
-
109
- int is_gpio_initialized(unsigned int gpio)
110
- {
111
- if (gpio_direction[gpio] != INPUT && gpio_direction[gpio] != OUTPUT) {
112
- rb_raise(rb_eRuntimeError,
113
- "you must setup the GPIO channel first with "
114
- "RPi::GPIO.setup CHANNEL, :as => :input or "
115
- "RPi::GPIO.setup CHANNEL, :as => :output");
116
- return 0;
117
- }
118
-
119
- return 1;
120
- }
121
-
122
- int is_gpio_output(unsigned int gpio)
123
- {
124
- if (gpio_direction[gpio] != OUTPUT) {
125
- if (gpio_direction[gpio] != INPUT) {
126
- rb_raise(rb_eRuntimeError,
127
- "you must setup the GPIO channel first with "
128
- "RPi::GPIO.setup CHANNEL, :as => :input or "
129
- "RPi::GPIO.setup CHANNEL, :as => :output");
130
- return 0;
131
- }
132
-
133
- rb_raise(rb_eRuntimeError, "GPIO channel not setup as output");
134
- return 0;
135
- }
136
-
137
- return 1;
138
- }
139
-
140
- int is_rpi(void)
141
- {
142
- if (setup_error) {
143
- rb_raise(rb_eRuntimeError, "this gem can only be run on a Raspberry Pi");
144
- return 0;
145
- }
146
-
147
- return 1;
148
- }
149
-
150
- // RPi::GPIO.clean_up(channel=nil)
151
- // clean up everything by default; otherwise, clean up given channel
152
- VALUE GPIO_clean_up(int argc, VALUE *argv, VALUE self)
153
- {
154
- int i;
155
- int found = 0;
156
- int channel = -666; // lol, quite a flag
157
- unsigned int gpio;
158
-
159
- if (argc == 1) {
160
- channel = NUM2INT(argv[0]);
161
- } else if (argc > 1) {
162
- rb_raise(rb_eArgError, "wrong number of arguments; 0 for all pins, 1 for a specific pin");
163
- return Qnil;
164
- }
165
-
166
- if (channel != -666 && get_gpio_number(channel, &gpio)) {
167
- return Qnil;
168
- }
169
-
170
- if (module_setup && !setup_error) {
171
- if (channel == -666) {
172
- // clean up any /sys/class exports
173
- event_cleanup_all();
174
-
175
- // set everything back to input
176
- for (i = 0; i < 54; i++) {
177
- if (gpio_direction[i] != -1) {
178
- setup_gpio(i, INPUT, PUD_OFF);
179
- gpio_direction[i] = -1;
180
- found = 1;
181
- }
182
- }
183
- } else {
184
- // clean up any /sys/class exports
185
- event_cleanup(gpio);
186
-
187
- // set everything back to input
188
- if (gpio_direction[gpio] != -1) {
189
- setup_gpio(gpio, INPUT, PUD_OFF);
190
- gpio_direction[gpio] = -1;
191
- found = 1;
192
- }
193
- }
194
- }
195
-
196
- // check if any channels set up - if not warn about misuse of GPIO.clean_up()
197
- if (!found && gpio_warnings) {
198
- rb_warn("no channels have been set up yet; nothing to clean up");
199
- }
200
-
201
- return Qnil;
202
- }
203
-
204
- // RPi::GPIO.reset
205
- //
206
- // cleans up all pins, unsets numbering mode, enables warnings.
207
- VALUE GPIO_reset(VALUE self)
208
- {
209
- GPIO_clean_up(0, NULL, self);
210
- gpio_mode = MODE_UNKNOWN;
211
- GPIO_set_warnings(self, Qtrue);
212
- return Qnil;
213
- }
214
-
215
- // RPi::GPIO.setup(channel, hash(:as => {:input, :output}, :pull => {:off,
216
- // :down, :up}(default :off), :initialize => {:high, :low}))
217
- //
218
- // sets up a channel as either input or output with an optional pull-down or
219
- // pull-up resistor and an optional initialize state
220
- VALUE GPIO_setup(VALUE self, VALUE channel, VALUE hash)
221
- {
222
- unsigned int gpio;
223
- int chan = -1;
224
- VALUE channel_list = _extract_channels(channel);
225
- int chan_count = RARRAY_LEN(channel_list);
226
- const char *direction_str = NULL;
227
- int direction;
228
- VALUE pud_val = Qnil;
229
- const char *pud_str = NULL;
230
- int pud = PUD_OFF;
231
- int func;
232
-
233
- VALUE initialize_val = Qnil;
234
- const char *initialize_str = NULL;
235
- int initialize = HIGH;
236
-
237
- // func to set up channel stored in channel variable
238
- int setup_one(void) {
239
- if (get_gpio_number(chan, &gpio)) {
240
- return 0;
241
- }
242
-
243
- // warn if the channel is already in use (not from this program).
244
- func = gpio_function(gpio);
245
- if (gpio_warnings &&
246
- ((func != 0 && func != 1) ||
247
- (gpio_direction[gpio] == -1 && func == 1)))
248
- {
249
- rb_warn("this channel is already in use... continuing anyway. use RPi::GPIO.set_warnings(false) to "
250
- "disable warnings");
251
- }
252
-
253
- if (gpio_warnings) {
254
- if (rpiinfo.p1_revision == 0) { // compute module - do nothing
255
- } else if ((rpiinfo.p1_revision == 1 &&
256
- (gpio == 0 || gpio == 1)) ||
257
- (gpio == 2 || gpio == 3)) {
258
- if (pud == PUD_UP || pud == PUD_DOWN) {
259
- rb_warn("a physical pull up resistor is fitted on this channel");
260
- }
261
- }
262
- }
263
-
264
- if (direction == OUTPUT && (initialize == LOW || initialize == HIGH)) {
265
- output_gpio(gpio, initialize);
266
- }
267
- setup_gpio(gpio, direction, pud);
268
- gpio_direction[gpio] = direction;
269
- return 1;
270
- }
271
-
272
- // pin direction
273
- direction_str = rb_id2name(rb_to_id(rb_hash_aref(hash, ID2SYM(rb_intern("as")))));
274
- if (strcmp("input", direction_str) == 0) {
275
- direction = INPUT;
276
- } else if (strcmp("output", direction_str) == 0) {
277
- direction = OUTPUT;
278
- } else {
279
- rb_raise(rb_eArgError, "invalid pin direction; must be :input or :output");
280
- }
281
-
282
- // pull up, down, or off
283
- pud_val = rb_hash_aref(hash, ID2SYM(rb_intern("pull")));
284
- if (pud_val != Qnil) {
285
- if (direction == OUTPUT) {
286
- rb_raise(rb_eArgError, "output pin cannot use pull argument");
287
- return Qnil;
288
- }
289
-
290
- pud_str = rb_id2name(rb_to_id(pud_val));
291
- if (strcmp("down", pud_str) == 0) {
292
- pud = PUD_DOWN;
293
- } else if (strcmp("up", pud_str) == 0) {
294
- pud = PUD_UP;
295
- } else if (strcmp("off", pud_str) == 0) {
296
- pud = PUD_OFF;
297
- } else {
298
- rb_raise(rb_eArgError, "invalid pin pull direction; must be :up, :down, or :off");
299
- return Qnil;
300
- }
301
- } else {
302
- pud = PUD_OFF;
303
- }
304
- // initialize high or low
305
- initialize_val = rb_hash_aref(hash, ID2SYM(rb_intern("initialize")));
306
- if (initialize_val != Qnil) {
307
- if (direction == INPUT) {
308
- rb_raise(rb_eArgError, "input pins cannot use initial argument");
309
- return Qnil;
310
- }
311
-
312
- initialize_str = rb_id2name(rb_to_id(initialize_val));
313
- if (strcmp("high", initialize_str) == 0) {
314
- initialize = HIGH;
315
- } else if (strcmp("low", initialize_str) == 0) {
316
- initialize = LOW;
317
- } else {
318
- rb_raise(rb_eArgError, "invalid pin initialize state; must be :high or :low");
319
- return Qnil;
320
- }
321
- } else {
322
- initialize = HIGH;
323
- }
324
-
325
- if (!is_rpi() || mmap_gpio_mem()) {
326
- return Qnil;
327
- }
328
-
329
- if (direction != INPUT && direction != OUTPUT) {
330
- rb_raise(rb_eArgError, "invalid direction");
331
- return Qnil;
332
- }
333
-
334
- if (direction == OUTPUT) {
335
- pud = PUD_OFF;
336
- }
337
-
338
- for (int i = 0; i < chan_count; i++) {
339
- chan = NUM2INT(rb_ary_entry(channel_list, i));
340
- if (!setup_one()) {
341
- return Qnil;
342
- }
343
- }
344
-
345
- return self;
346
- }
347
-
348
- // RPi::GPIO.set_numbering(mode)
349
- VALUE GPIO_set_numbering(VALUE self, VALUE mode)
350
- {
351
- int new_mode;
352
- const char *mode_str = NULL;
353
-
354
- if (TYPE(mode) == T_SYMBOL) {
355
- mode_str = rb_id2name(rb_to_id(mode));
356
- } else {
357
- mode_str = RSTRING_PTR(mode);
358
- }
359
-
360
- if (strcmp(mode_str, "board") == 0) {
361
- new_mode = BOARD;
362
- } else if (strcmp(mode_str, "bcm") == 0) {
363
- new_mode = BCM;
364
- } else {
365
- rb_raise(rb_eArgError, "invalid numbering mode; must be :board or :bcm");
366
- }
367
-
368
- if (!is_rpi()) {
369
- return Qnil;
370
- }
371
-
372
- if (new_mode != BOARD && new_mode != BCM) {
373
- rb_raise(rb_eArgError, "invalid mode");
374
- return Qnil;
375
- }
376
-
377
- if (rpiinfo.p1_revision == 0 && new_mode == BOARD) {
378
- rb_raise(rb_eRuntimeError, ":board numbering system not applicable on compute module");
379
- return Qnil;
380
- }
381
-
382
- gpio_mode = new_mode;
383
- return self;
384
- }
385
-
386
- // RPi::GPIO.set_high(channel)
387
- VALUE GPIO_set_high(VALUE self, VALUE channel)
388
- {
389
- unsigned int gpio;
390
- int chan = -1;
391
- VALUE channel_list = _extract_channels(channel);
392
- int chan_count = RARRAY_LEN(channel_list);
393
-
394
- for (int i = 0; i < chan_count; i++) {
395
- chan = NUM2INT(rb_ary_entry(channel_list, i));
396
- if (get_gpio_number(chan, &gpio) || !is_gpio_output(gpio) || check_gpio_priv()) {
397
- return Qnil;
398
- } else {
399
- output_gpio(gpio, 1);
400
- }
401
- }
402
-
403
- return self;
404
- }
405
-
406
- // RPi::GPIO.set_low(channel)
407
- VALUE GPIO_set_low(VALUE self, VALUE channel)
408
- {
409
- unsigned int gpio;
410
- int chan = -1;
411
- VALUE channel_list = _extract_channels(channel);
412
- int chan_count = RARRAY_LEN(channel_list);
413
-
414
- for (int i = 0; i < chan_count; i++) {
415
- chan = NUM2INT(rb_ary_entry(channel_list, i));
416
- if (get_gpio_number(chan, &gpio) || !is_gpio_output(gpio) || check_gpio_priv()) {
417
- return Qnil;
418
- } else {
419
- output_gpio(gpio, 0);
420
- }
421
- }
422
-
423
- return self;
424
- }
425
-
426
- // RPi::GPIO.high?(channel)
427
- VALUE GPIO_test_high(VALUE self, VALUE channel)
428
- {
429
- unsigned int gpio;
430
-
431
- if (get_gpio_number(NUM2INT(channel), &gpio) || !is_gpio_initialized(gpio) || check_gpio_priv()) {
432
- return Qnil;
433
- }
434
-
435
- return input_gpio(gpio) ? Qtrue : Qfalse;
436
- }
437
-
438
- // RPi::GPIO.low?(channel)
439
- VALUE GPIO_test_low(VALUE self, VALUE channel)
440
- {
441
- return GPIO_test_high(self, channel) ? Qfalse : Qtrue;
442
- }
443
-
444
- // RPi::GPIO.set_warnings(state)
445
- VALUE GPIO_set_warnings(VALUE self, VALUE setting)
446
- {
447
- if (!is_rpi()) {
448
- return Qnil;
449
- }
450
-
451
- gpio_warnings = RTEST(setting);
452
- return self;
453
- }