rpi_gpio 0.2.0 → 0.4.0

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