rpi_gpio 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ }