rpi_gpio 0.3.3 → 0.4.0

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