rpi_gpio 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 86ea9cc97cf1ad0545d3d3b6cdd1e67e9fb2bcf6
4
+ data.tar.gz: e03a4eebed31cc7dc53c946a3fb12fde1a4281b9
5
+ SHA512:
6
+ metadata.gz: 1a6552df0cc6cbf3e7d24d2c9f5affd7f4940b59e7de1ba1dee4bb60e1a12fb4f2bc2bad79db7e22db1782327f01b6fb6926930a814f206d659a31e15a4f1a76
7
+ data.tar.gz: 8d3853451e5e8d6aab73756b65530b0d352fd79c14d10b732768ee52e64e37561dd565a16d3442f4dd3000c8163b895649024b7a4ee8c63fee25bef85222a89e
@@ -1,20 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rpi_gpio (0.3.0)
4
+ rpi_gpio (0.3.3)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- diff-lcs (1.2.5)
10
- rake (11.2.2)
11
- rake-compiler (1.0.1)
9
+ diff-lcs (1.3)
10
+ rake (12.0.0)
11
+ rake-compiler (1.0.3)
12
12
  rake
13
13
  rspec (3.5.0)
14
14
  rspec-core (~> 3.5.0)
15
15
  rspec-expectations (~> 3.5.0)
16
16
  rspec-mocks (~> 3.5.0)
17
- rspec-core (3.5.1)
17
+ rspec-core (3.5.4)
18
18
  rspec-support (~> 3.5.0)
19
19
  rspec-expectations (3.5.0)
20
20
  diff-lcs (>= 1.2.0, < 2.0)
@@ -31,6 +31,3 @@ DEPENDENCIES
31
31
  rake-compiler
32
32
  rpi_gpio!
33
33
  rspec
34
-
35
- BUNDLED WITH
36
- 1.10.6
data/README.md CHANGED
@@ -1,145 +1,145 @@
1
- # rpi_gpio v0.3.2
2
-
3
- Ruby conversion of [RPi.GPIO Python module](https://pypi.python.org/pypi/RPi.GPIO)
4
-
5
- ## Features
6
-
7
- Manipulate your Raspberry Pi's GPIO pins from Ruby!
8
-
9
- - Boolean input/output
10
- - Software-driven PWM (written in C for speed)
11
-
12
- Up-to-date with RPi.GPIO Python module version 0.6.2, so it works on all Raspberry Pi models!
13
-
14
- ## Sample Usage
15
-
16
- I aimed to make the gem's usage exactly the same as its Python counterpart -- only with a few semantic differences to utilize Ruby's readability. If anything is confusing, you can always check [here](http://sourceforge.net/p/raspberry-gpio-python/wiki/Examples/) for the original Python module's documentation.
17
-
18
- #### Download the gem
19
-
20
- The easiest way to download the gem is to use [Bundler](http://bundler.io/) with a Gemfile. In your Gemfile, include the line
21
- ```ruby
22
- gem 'rpi_gpio'
23
- ```
24
- Then you can run `bundle install` to automatically download and compile the gem for your system. To include the gem in a Ruby file, use the line `require 'rpi_gpio'`.
25
-
26
- #### Pin numbering
27
-
28
- Before you can do anything with the GPIO pins, you need to specify how you want to number them.
29
- ```ruby
30
- RPi::GPIO.set_numbering :board
31
- # or
32
- RPi::GPIO.set_numbering :bcm
33
- ````
34
- `:board` numbering refers to the physical pin numbers on the Pi, whereas `:bcm` numbering refers to the Broadcom SOC channel numbering. Note that `:bcm` numbering differs between Pi models, while `:board` numbering does not.
35
-
36
- #### Input
37
-
38
- To receive input from a GPIO pin, you must first initialize it as an input pin:
39
- ```ruby
40
- RPi::GPIO.setup PIN_NUM, :as => :input
41
- ```
42
- The pin number will differ based on your selected numbering system and which pin you want to use.
43
-
44
- Now you can use the calls
45
- ```ruby
46
- RPi::GPIO.high? PIN_NUM
47
- RPi::GPIO.low? PIN_NUM
48
- ```
49
- to receive either `true` or `false`.
50
-
51
- You can use the additional hash argument `:pull` to apply a pull-up or pull-down resistor to the input pin like so:
52
- ```ruby
53
- RPi::GPIO.setup PIN_NUM, :as => :input, :pull => :down
54
- # or
55
- RPi::GPIO.setup PIN_NUM, :as => :input, :pull => :up
56
- # or (not necessary; :off is the default value)
57
- RPi::GPIO.setup PIN_NUM, :as => :input, :pull => :off
58
- ```
59
-
60
- #### Output
61
-
62
- To send output to a GPIO pin, you must first initialize it as an output pin:
63
- ```ruby
64
- RPi::GPIO.setup PIN_NUM, :as => :output
65
- ```
66
- Now you can use the calls
67
- ```ruby
68
- RPi::GPIO.set_high PIN_NUM
69
- RPi::GPIO.set_low PIN_NUM
70
- ```
71
- to set the pin either high or low.
72
-
73
- You can use the additional hash argument `:initialize` to set the pin's initial state like so:
74
- ```ruby
75
- RPi::GPIO.setup PIN_NUM, :as => :output, :initialize => :high
76
- # or
77
- RPi::GPIO.setup PIN_NUM, :as => :output, :initialize => :low
78
- ```
79
-
80
- #### PWM (pulse-width modulation)
81
-
82
- Pulse-width modulation is a useful tool for controlling things like LED brightness or motor speed. To utilize PWM, first create a PWM object for an [output pin](#output).
83
- ```ruby
84
- pwm = RPi::GPIO::PWM.new(PIN_NUM, PWM_FREQ)
85
- ```
86
- The `PWM_FREQ` is a value in hertz that specifies the amount of pulse cycles per second.
87
-
88
- Now you can call the following method to start PWM:
89
- ```ruby
90
- pwm.start DUTY_CYCLE
91
- ```
92
- `DUTY_CYCLE` is a value from `0.0` to `100.0` indicating the percent of the time that the signal will be high.
93
-
94
- Once running, you can get/set the PWM duty cycle with
95
- ```ruby
96
- pwm.duty_cycle # get
97
- pwm.duty_cycle = NEW_DUTY_CYCLE # set
98
- ```
99
- get/set the PWM frequency with
100
- ```ruby
101
- pwm.frequency # get
102
- pwm.frequency = NEW_FREQUENCY # set
103
- ```
104
- and get the PWM GPIO number with
105
- ```ruby
106
- pwm.gpio
107
- ```
108
- Note that this number corresponds to `:bcm` numbering of the GPIO pins, so it will be different than pin number you used if you created the PWM with `:board` numbering.
109
-
110
- To stop PWM, use
111
- ```ruby
112
- pwm.stop
113
- ```
114
-
115
- To check if a PWM object is currently running, use
116
- ```ruby
117
- pwm.running?
118
- ```
119
-
120
- #### Cleaning up
121
-
122
- After your program is finished using the GPIO pins, it's a good idea to release them so other programs can use them later. Simply call
123
- ```ruby
124
- RPi::GPIO.clean_up PIN_NUM
125
- ```
126
- to release a specific pin, or
127
- ```ruby
128
- RPi::GPIO.clean_up
129
- ```
130
- to release all allocated pins.
131
-
132
- Alternatively, you can call
133
- ```ruby
134
- RPi::GPIO.reset
135
- ```
136
- to clean up all pins and to also reset the selected numbering mode.
137
-
138
- ## Credits
139
-
140
- Original Python code by Ben Croston modified for Ruby by Nick Lowery
141
-
142
- Copyright (c) 2014-2015 [Nick Lowery](https://github.com/ClockVapor)
143
-
144
- View LICENSE for full license.
145
-
1
+ # rpi_gpio v0.3.3
2
+
3
+ Ruby conversion of [RPi.GPIO Python module](https://pypi.python.org/pypi/RPi.GPIO)
4
+
5
+ ## Features
6
+
7
+ Manipulate your Raspberry Pi's GPIO pins from Ruby!
8
+
9
+ - Boolean input/output
10
+ - Software-driven PWM (written in C for speed)
11
+
12
+ Up-to-date with RPi.GPIO Python module version 0.6.3, so it works on all Raspberry Pi models!
13
+
14
+ ## Sample Usage
15
+
16
+ I aimed to make the gem's usage exactly the same as its Python counterpart -- only with a few semantic differences to utilize Ruby's readability. If anything is confusing, you can always check [here](http://sourceforge.net/p/raspberry-gpio-python/wiki/Examples/) for the original Python module's documentation.
17
+
18
+ #### Download the gem
19
+
20
+ The easiest way to download the gem is to use [Bundler](http://bundler.io/) with a Gemfile. In your Gemfile, include the line
21
+ ```ruby
22
+ gem 'rpi_gpio'
23
+ ```
24
+ Then you can run `bundle install` to automatically download and compile the gem for your system. To include the gem in a Ruby file, use the line `require 'rpi_gpio'`.
25
+
26
+ #### Pin numbering
27
+
28
+ Before you can do anything with the GPIO pins, you need to specify how you want to number them.
29
+ ```ruby
30
+ RPi::GPIO.set_numbering :board
31
+ # or
32
+ RPi::GPIO.set_numbering :bcm
33
+ ````
34
+ `:board` numbering refers to the physical pin numbers on the Pi, whereas `:bcm` numbering refers to the Broadcom SOC channel numbering. Note that `:bcm` numbering differs between Pi models, while `:board` numbering does not.
35
+
36
+ #### Input
37
+
38
+ To receive input from a GPIO pin, you must first initialize it as an input pin:
39
+ ```ruby
40
+ RPi::GPIO.setup PIN_NUM, :as => :input
41
+ ```
42
+ The pin number will differ based on your selected numbering system and which pin you want to use.
43
+
44
+ Now you can use the calls
45
+ ```ruby
46
+ RPi::GPIO.high? PIN_NUM
47
+ RPi::GPIO.low? PIN_NUM
48
+ ```
49
+ to receive either `true` or `false`.
50
+
51
+ You can use the additional hash argument `:pull` to apply a pull-up or pull-down resistor to the input pin like so:
52
+ ```ruby
53
+ RPi::GPIO.setup PIN_NUM, :as => :input, :pull => :down
54
+ # or
55
+ RPi::GPIO.setup PIN_NUM, :as => :input, :pull => :up
56
+ # or (not necessary; :off is the default value)
57
+ RPi::GPIO.setup PIN_NUM, :as => :input, :pull => :off
58
+ ```
59
+
60
+ #### Output
61
+
62
+ To send output to a GPIO pin, you must first initialize it as an output pin:
63
+ ```ruby
64
+ RPi::GPIO.setup PIN_NUM, :as => :output
65
+ ```
66
+ Now you can use the calls
67
+ ```ruby
68
+ RPi::GPIO.set_high PIN_NUM
69
+ RPi::GPIO.set_low PIN_NUM
70
+ ```
71
+ to set the pin either high or low.
72
+
73
+ You can use the additional hash argument `:initialize` to set the pin's initial state like so:
74
+ ```ruby
75
+ RPi::GPIO.setup PIN_NUM, :as => :output, :initialize => :high
76
+ # or
77
+ RPi::GPIO.setup PIN_NUM, :as => :output, :initialize => :low
78
+ ```
79
+
80
+ #### PWM (pulse-width modulation)
81
+
82
+ Pulse-width modulation is a useful tool for controlling things like LED brightness or motor speed. To utilize PWM, first create a PWM object for an [output pin](#output).
83
+ ```ruby
84
+ pwm = RPi::GPIO::PWM.new(PIN_NUM, PWM_FREQ)
85
+ ```
86
+ The `PWM_FREQ` is a value in hertz that specifies the amount of pulse cycles per second.
87
+
88
+ Now you can call the following method to start PWM:
89
+ ```ruby
90
+ pwm.start DUTY_CYCLE
91
+ ```
92
+ `DUTY_CYCLE` is a value from `0.0` to `100.0` indicating the percent of the time that the signal will be high.
93
+
94
+ Once running, you can get/set the PWM duty cycle with
95
+ ```ruby
96
+ pwm.duty_cycle # get
97
+ pwm.duty_cycle = NEW_DUTY_CYCLE # set
98
+ ```
99
+ get/set the PWM frequency with
100
+ ```ruby
101
+ pwm.frequency # get
102
+ pwm.frequency = NEW_FREQUENCY # set
103
+ ```
104
+ and get the PWM GPIO number with
105
+ ```ruby
106
+ pwm.gpio
107
+ ```
108
+ Note that this number corresponds to `:bcm` numbering of the GPIO pins, so it will be different than pin number you used if you created the PWM with `:board` numbering.
109
+
110
+ To stop PWM, use
111
+ ```ruby
112
+ pwm.stop
113
+ ```
114
+
115
+ To check if a PWM object is currently running, use
116
+ ```ruby
117
+ pwm.running?
118
+ ```
119
+
120
+ #### Cleaning up
121
+
122
+ After your program is finished using the GPIO pins, it's a good idea to release them so other programs can use them later. Simply call
123
+ ```ruby
124
+ RPi::GPIO.clean_up PIN_NUM
125
+ ```
126
+ to release a specific pin, or
127
+ ```ruby
128
+ RPi::GPIO.clean_up
129
+ ```
130
+ to release all allocated pins.
131
+
132
+ Alternatively, you can call
133
+ ```ruby
134
+ RPi::GPIO.reset
135
+ ```
136
+ to clean up all pins and to also reset the selected numbering mode.
137
+
138
+ ## Credits
139
+
140
+ Original Python code by Ben Croston modified for Ruby by Nick Lowery
141
+
142
+ Copyright (c) 2014-2015 [Nick Lowery](https://github.com/ClockVapor)
143
+
144
+ View LICENSE for full license.
145
+
@@ -1,446 +1,426 @@
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
- VALUE initialize_val = Qnil;
226
- const char *initialize_str = NULL;
227
- int initialize = HIGH;
228
-
229
- // func to set up channel stored in channel variable
230
- int setup_one(void) {
231
- if (get_gpio_number(chan, &gpio)) {
232
- return 0;
233
- }
234
-
235
- // warn if the channel is already in use (not from this program).
236
- func = gpio_function(gpio);
237
- if (gpio_warnings &&
238
- ((func != 0 && func != 1) ||
239
- (gpio_direction[gpio] == -1 && func == 1)))
240
- {
241
- rb_warn("this channel is already in use... continuing anyway. use RPi::GPIO.set_warnings(false) to disable warnings");
242
- }
243
-
244
- if (gpio_warnings) {
245
- if (rpiinfo.p1_revision == 0) { // compute module - do nothing
246
- } else if ((rpiinfo.p1_revision == 1 &&
247
- (gpio == 0 || gpio == 1)) ||
248
- (gpio == 2 || gpio == 3)) {
249
- if (pud == PUD_UP || pud == PUD_DOWN) {
250
- rb_warn("a physical pull up resistor is fitted on "
251
- "this channel");
252
- }
253
- }
254
- }
255
-
256
- if (direction == OUTPUT && (initialize == LOW || initialize == HIGH)) {
257
- output_gpio(gpio, initialize);
258
- }
259
- setup_gpio(gpio, direction, pud);
260
- gpio_direction[gpio] = direction;
261
- return 1;
262
- }
263
-
264
- // parse arguments
265
-
266
- // channel
267
- chan = NUM2INT(channel);
268
-
269
- // pin direction
270
- direction_str = rb_id2name(rb_to_id(rb_hash_aref(hash, ID2SYM(rb_intern("as")))));
271
- if (strcmp("input", direction_str) == 0) {
272
- direction = INPUT;
273
- } else if (strcmp("output", direction_str) == 0) {
274
- direction = OUTPUT;
275
- } else {
276
- rb_raise(rb_eArgError,
277
- "invalid pin direction; must be :input or :output");
278
- }
279
-
280
- // pull up, down, or off
281
- pud_val = rb_hash_aref(hash, ID2SYM(rb_intern("pull")));
282
- if (pud_val != Qnil) {
283
- if (direction == OUTPUT) {
284
- rb_raise(rb_eArgError, "output pin cannot use pull argument");
285
- return Qnil;
286
- }
287
-
288
- pud_str = rb_id2name(rb_to_id(pud_val));
289
- if (strcmp("down", pud_str) == 0) {
290
- pud = PUD_DOWN;
291
- } else if (strcmp("up", pud_str) == 0) {
292
- pud = PUD_UP;
293
- } else if (strcmp("off", pud_str) == 0) {
294
- pud = PUD_OFF;
295
- } else {
296
- rb_raise(rb_eArgError,
297
- "invalid pin pull direction; must be :up, :down, or :off");
298
- return Qnil;
299
- }
300
- } else {
301
- pud = PUD_OFF;
302
- }
303
- // initialize high or low
304
- initialize_val = rb_hash_aref(hash, ID2SYM(rb_intern("initialize")));
305
- if (initialize_val != Qnil) {
306
- if (direction == INPUT) {
307
- rb_raise(rb_eArgError, "input pins cannot use initial argument");
308
- return Qnil;
309
- }
310
-
311
- initialize_str = rb_id2name(rb_to_id(initialize_val));
312
- if (strcmp("high", initialize_str) == 0) {
313
- initialize = HIGH;
314
- } else if (strcmp("low", initialize_str) == 0) {
315
- initialize = LOW;
316
- } else {
317
- rb_raise(rb_eArgError,
318
- "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
- if (!setup_one()) {
339
- return Qnil;
340
- }
341
-
342
- return self;
343
- }
344
-
345
- // RPi::GPIO.set_numbering(mode)
346
- VALUE GPIO_set_numbering(VALUE self, VALUE mode)
347
- {
348
- int new_mode;
349
- const char *mode_str = NULL;
350
-
351
- if (TYPE(mode) == T_SYMBOL) {
352
- mode_str = rb_id2name(rb_to_id(mode));
353
- } else {
354
- mode_str = RSTRING_PTR(mode);
355
- }
356
-
357
- if (strcmp(mode_str, "board") == 0) {
358
- new_mode = BOARD;
359
- } else if (strcmp(mode_str, "bcm") == 0) {
360
- new_mode = BCM;
361
- } else {
362
- rb_raise(rb_eArgError,
363
- "invalid numbering mode; must be :board or :bcm");
364
- }
365
-
366
- if (!is_rpi()) {
367
- return Qnil;
368
- }
369
-
370
- if (new_mode != BOARD && new_mode != BCM) {
371
- rb_raise(rb_eArgError, "invalid mode");
372
- return Qnil;
373
- }
374
-
375
- if (rpiinfo.p1_revision == 0 && new_mode == BOARD) {
376
- rb_raise(rb_eRuntimeError, ":board numbering system not applicable on "
377
- "compute module");
378
- return Qnil;
379
- }
380
-
381
- gpio_mode = new_mode;
382
- return self;
383
- }
384
-
385
- // RPi::GPIO.set_high(channel)
386
- VALUE GPIO_set_high(VALUE self, VALUE channel)
387
- {
388
- unsigned int gpio;
389
- int chan = NUM2INT(channel);
390
-
391
- if (get_gpio_number(chan, &gpio) ||
392
- !is_gpio_output(gpio) ||
393
- check_gpio_priv()) {
394
- return Qnil;
395
- }
396
-
397
- output_gpio(gpio, 1);
398
- return self;
399
- }
400
-
401
- // RPi::GPIO.set_low(channel)
402
- VALUE GPIO_set_low(VALUE self, VALUE channel)
403
- {
404
- unsigned int gpio;
405
- int chan = NUM2INT(channel);
406
-
407
- if (get_gpio_number(chan, &gpio) ||
408
- !is_gpio_output(gpio) ||
409
- check_gpio_priv()) {
410
- return Qnil;
411
- }
412
-
413
- output_gpio(gpio, 0);
414
- return self;
415
- }
416
-
417
- // RPi::GPIO.high?(channel)
418
- VALUE GPIO_test_high(VALUE self, VALUE channel)
419
- {
420
- unsigned int gpio;
421
-
422
- if (get_gpio_number(NUM2INT(channel), &gpio) ||
423
- !is_gpio_input(gpio) ||
424
- check_gpio_priv()) {
425
- return Qnil;
426
- }
427
-
428
- return input_gpio(gpio) ? Qtrue : Qfalse;
429
- }
430
-
431
- // RPi::GPIO.low?(channel)
432
- VALUE GPIO_test_low(VALUE self, VALUE channel)
433
- {
434
- return GPIO_test_high(self, channel) ? Qfalse : Qtrue;
435
- }
436
-
437
- // RPi::GPIO.set_warnings(state)
438
- VALUE GPIO_set_warnings(VALUE self, VALUE setting)
439
- {
440
- if (!is_rpi()) {
441
- return Qnil;
442
- }
443
-
444
- gpio_warnings = RTEST(setting);
445
- return self;
446
- }
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
+ }