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