rpi_gpio 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cf2e5fe321ddea6602db36bf081dcdd9b16d1248a584c9fe2156cf3b1cc8764b
4
+ data.tar.gz: aea0df6d2ce23b6b60ffdd35a1a856c09920fda38dfdcc197f4d38b417129935
5
+ SHA512:
6
+ metadata.gz: e2d50e340b0d24349c291b4927fa4bc03e3c477862659a4b6a4f81c5a6c10a94e612e70acef98299627fc299f53cad68f15606b9795b610af1e82d559face6d3
7
+ data.tar.gz: f6495cbea95ddfe0348bd9be92d716d4929329414ef49d6d6649a373f87af4a62346d1fe74631771de24a066b3b7bfcb1335efda76bda8dbd934e5d1eab644de
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
@@ -0,0 +1,36 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rpi_gpio (0.4.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.4.4)
10
+ rake (13.0.1)
11
+ rake-compiler (1.1.1)
12
+ rake
13
+ rspec (3.9.0)
14
+ rspec-core (~> 3.9.0)
15
+ rspec-expectations (~> 3.9.0)
16
+ rspec-mocks (~> 3.9.0)
17
+ rspec-core (3.9.2)
18
+ rspec-support (~> 3.9.3)
19
+ rspec-expectations (3.9.2)
20
+ diff-lcs (>= 1.2.0, < 2.0)
21
+ rspec-support (~> 3.9.0)
22
+ rspec-mocks (3.9.1)
23
+ diff-lcs (>= 1.2.0, < 2.0)
24
+ rspec-support (~> 3.9.0)
25
+ rspec-support (3.9.3)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ rake-compiler
32
+ rpi_gpio!
33
+ rspec
34
+
35
+ BUNDLED WITH
36
+ 2.1.4
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014-2020 Nick Lowery
4
+ Copyright (c) 2012-2014 Ben Croston
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,145 @@
1
+ # rpi_gpio v0.4.0
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.7.0, 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-2020 [Nick Lowery](https://github.com/ClockVapor)
143
+
144
+ View LICENSE for full license.
145
+
@@ -0,0 +1,3 @@
1
+ require 'rake/extensiontask'
2
+
3
+ Rake::ExtensionTask.new('rpi_gpio')
@@ -0,0 +1,305 @@
1
+ /*
2
+ Original code by Ben Croston modified for Ruby by Nick Lowery
3
+ (github.com/clockvapor)
4
+ Copyright (c) 2014-2020 Nick Lowery
5
+
6
+ Copyright (c) 2012-2019 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 <stdio.h>
28
+ #include <stdint.h>
29
+ #include <stdlib.h>
30
+ #include <fcntl.h>
31
+ #include <sys/mman.h>
32
+ #include <string.h>
33
+ #include "c_gpio.h"
34
+
35
+ #define BCM2708_PERI_BASE_DEFAULT 0x20000000
36
+ #define BCM2709_PERI_BASE_DEFAULT 0x3f000000
37
+ #define GPIO_BASE_OFFSET 0x200000
38
+ #define FSEL_OFFSET 0 // 0x0000
39
+ #define SET_OFFSET 7 // 0x001c / 4
40
+ #define CLR_OFFSET 10 // 0x0028 / 4
41
+ #define PINLEVEL_OFFSET 13 // 0x0034 / 4
42
+ #define EVENT_DETECT_OFFSET 16 // 0x0040 / 4
43
+ #define RISING_ED_OFFSET 19 // 0x004c / 4
44
+ #define FALLING_ED_OFFSET 22 // 0x0058 / 4
45
+ #define HIGH_DETECT_OFFSET 25 // 0x0064 / 4
46
+ #define LOW_DETECT_OFFSET 28 // 0x0070 / 4
47
+ #define PULLUPDN_OFFSET 37 // 0x0094 / 4
48
+ #define PULLUPDNCLK_OFFSET 38 // 0x0098 / 4
49
+
50
+ #define PULLUPDN_OFFSET_2711_0 57
51
+ #define PULLUPDN_OFFSET_2711_1 58
52
+ #define PULLUPDN_OFFSET_2711_2 59
53
+ #define PULLUPDN_OFFSET_2711_3 60
54
+
55
+ #define PAGE_SIZE (4*1024)
56
+ #define BLOCK_SIZE (4*1024)
57
+
58
+ static volatile uint32_t *gpio_map;
59
+
60
+ void short_wait(void)
61
+ {
62
+ int i;
63
+
64
+ for (i=0; i<150; i++) { // wait 150 cycles
65
+ asm volatile("nop");
66
+ }
67
+ }
68
+
69
+ int setup(void)
70
+ {
71
+ int mem_fd;
72
+ uint8_t *gpio_mem;
73
+ uint32_t peri_base = 0;
74
+ uint32_t gpio_base;
75
+ unsigned char buf[4];
76
+ FILE *fp;
77
+ char buffer[1024];
78
+ char hardware[1024];
79
+ int found = 0;
80
+
81
+ // try /dev/gpiomem first - this does not require root privs
82
+ if ((mem_fd = open("/dev/gpiomem", O_RDWR|O_SYNC)) > 0)
83
+ {
84
+ if ((gpio_map = (uint32_t *)mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0)) == MAP_FAILED) {
85
+ return SETUP_MMAP_FAIL;
86
+ } else {
87
+ return SETUP_OK;
88
+ }
89
+ }
90
+
91
+ // revert to /dev/mem method - requires root
92
+
93
+ // determine peri_base
94
+ if ((fp = fopen("/proc/device-tree/soc/ranges", "rb")) != NULL) {
95
+ // get peri base from device tree
96
+ fseek(fp, 4, SEEK_SET);
97
+ if (fread(buf, 1, sizeof buf, fp) == sizeof buf) {
98
+ peri_base = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
99
+ }
100
+ fclose(fp);
101
+ } else {
102
+ // guess peri base based on /proc/cpuinfo hardware field
103
+ if ((fp = fopen("/proc/cpuinfo", "r")) == NULL)
104
+ return SETUP_CPUINFO_FAIL;
105
+
106
+ while(!feof(fp) && !found && fgets(buffer, sizeof(buffer), fp)) {
107
+ sscanf(buffer, "Hardware : %s", hardware);
108
+ if (strcmp(hardware, "BCM2708") == 0 || strcmp(hardware, "BCM2835") == 0) {
109
+ // pi 1 hardware
110
+ peri_base = BCM2708_PERI_BASE_DEFAULT;
111
+ found = 1;
112
+ } else if (strcmp(hardware, "BCM2709") == 0 || strcmp(hardware, "BCM2836") == 0) {
113
+ // pi 2 hardware
114
+ peri_base = BCM2709_PERI_BASE_DEFAULT;
115
+ found = 1;
116
+ }
117
+ }
118
+ fclose(fp);
119
+ if (!found)
120
+ return SETUP_NOT_RPI_FAIL;
121
+ }
122
+
123
+ if (!peri_base)
124
+ return SETUP_NOT_RPI_FAIL;
125
+ gpio_base = peri_base + GPIO_BASE_OFFSET;
126
+
127
+ // mmap the GPIO memory registers
128
+ if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
129
+ return SETUP_DEVMEM_FAIL;
130
+
131
+ if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
132
+ return SETUP_MALLOC_FAIL;
133
+
134
+ if ((uint32_t)gpio_mem % PAGE_SIZE)
135
+ gpio_mem += PAGE_SIZE - ((uint32_t)gpio_mem % PAGE_SIZE);
136
+
137
+ if ((gpio_map = (uint32_t *)mmap( (void *)gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, gpio_base)) == MAP_FAILED)
138
+ return SETUP_MMAP_FAIL;
139
+
140
+ return SETUP_OK;
141
+ }
142
+
143
+ void clear_event_detect(int gpio)
144
+ {
145
+ int offset = EVENT_DETECT_OFFSET + (gpio/32);
146
+ int shift = (gpio%32);
147
+
148
+ *(gpio_map+offset) |= (1 << shift);
149
+ short_wait();
150
+ *(gpio_map+offset) = 0;
151
+ }
152
+
153
+ int eventdetected(int gpio)
154
+ {
155
+ int offset, value, bit;
156
+
157
+ offset = EVENT_DETECT_OFFSET + (gpio/32);
158
+ bit = (1 << (gpio%32));
159
+ value = *(gpio_map+offset) & bit;
160
+ if (value)
161
+ clear_event_detect(gpio);
162
+ return value;
163
+ }
164
+
165
+ void set_rising_event(int gpio, int enable)
166
+ {
167
+ int offset = RISING_ED_OFFSET + (gpio/32);
168
+ int shift = (gpio%32);
169
+
170
+ if (enable)
171
+ *(gpio_map+offset) |= 1 << shift;
172
+ else
173
+ *(gpio_map+offset) &= ~(1 << shift);
174
+ clear_event_detect(gpio);
175
+ }
176
+
177
+ void set_falling_event(int gpio, int enable)
178
+ {
179
+ int offset = FALLING_ED_OFFSET + (gpio/32);
180
+ int shift = (gpio%32);
181
+
182
+ if (enable) {
183
+ *(gpio_map+offset) |= (1 << shift);
184
+ *(gpio_map+offset) = (1 << shift);
185
+ } else {
186
+ *(gpio_map+offset) &= ~(1 << shift);
187
+ }
188
+ clear_event_detect(gpio);
189
+ }
190
+
191
+ void set_high_event(int gpio, int enable)
192
+ {
193
+ int offset = HIGH_DETECT_OFFSET + (gpio/32);
194
+ int shift = (gpio%32);
195
+
196
+ if (enable)
197
+ *(gpio_map+offset) |= (1 << shift);
198
+ else
199
+ *(gpio_map+offset) &= ~(1 << shift);
200
+ clear_event_detect(gpio);
201
+ }
202
+
203
+ void set_low_event(int gpio, int enable)
204
+ {
205
+ int offset = LOW_DETECT_OFFSET + (gpio/32);
206
+ int shift = (gpio%32);
207
+
208
+ if (enable)
209
+ *(gpio_map+offset) |= 1 << shift;
210
+ else
211
+ *(gpio_map+offset) &= ~(1 << shift);
212
+ clear_event_detect(gpio);
213
+ }
214
+
215
+ void set_pullupdn(int gpio, int pud)
216
+ {
217
+ // Check GPIO register
218
+ int is2711 = *(gpio_map+PULLUPDN_OFFSET_2711_3) != 0x6770696f;
219
+ if (is2711) {
220
+ // Pi 4 Pull-up/down method
221
+ int pullreg = PULLUPDN_OFFSET_2711_0 + (gpio >> 4);
222
+ int pullshift = (gpio & 0xf) << 1;
223
+ unsigned int pullbits;
224
+ unsigned int pull = 0;
225
+ switch (pud) {
226
+ case PUD_OFF: pull = 0; break;
227
+ case PUD_UP: pull = 1; break;
228
+ case PUD_DOWN: pull = 2; break;
229
+ default: pull = 0; // switch PUD to OFF for other values
230
+ }
231
+ pullbits = *(gpio_map + pullreg);
232
+ pullbits &= ~(3 << pullshift);
233
+ pullbits |= (pull << pullshift);
234
+ *(gpio_map + pullreg) = pullbits;
235
+ } else {
236
+ // Legacy Pull-up/down method
237
+ int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32);
238
+ int shift = (gpio%32);
239
+
240
+ if (pud == PUD_DOWN) {
241
+ *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_DOWN;
242
+ } else if (pud == PUD_UP) {
243
+ *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_UP;
244
+ } else { // pud == PUD_OFF
245
+ *(gpio_map+PULLUPDN_OFFSET) &= ~3;
246
+ }
247
+ short_wait();
248
+ *(gpio_map+clk_offset) = 1 << shift;
249
+ short_wait();
250
+ *(gpio_map+PULLUPDN_OFFSET) &= ~3;
251
+ *(gpio_map+clk_offset) = 0;
252
+ }
253
+ }
254
+
255
+ void setup_gpio(int gpio, int direction, int pud)
256
+ {
257
+ int offset = FSEL_OFFSET + (gpio/10);
258
+ int shift = (gpio%10)*3;
259
+
260
+ set_pullupdn(gpio, pud);
261
+ if (direction == OUTPUT)
262
+ *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift)) | (1<<shift);
263
+ else // direction == INPUT
264
+ *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift));
265
+ }
266
+
267
+ // Contribution by Eric Ptak <trouch@trouch.com>
268
+ int gpio_function(int gpio)
269
+ {
270
+ int offset = FSEL_OFFSET + (gpio/10);
271
+ int shift = (gpio%10)*3;
272
+ int value = *(gpio_map+offset);
273
+ value >>= shift;
274
+ value &= 7;
275
+ return value; // 0=input, 1=output, 4=alt0
276
+ }
277
+
278
+ void output_gpio(int gpio, int value)
279
+ {
280
+ int offset, shift;
281
+
282
+ if (value) // value == HIGH
283
+ offset = SET_OFFSET + (gpio/32);
284
+ else // value == LOW
285
+ offset = CLR_OFFSET + (gpio/32);
286
+
287
+ shift = (gpio%32);
288
+
289
+ *(gpio_map+offset) = 1 << shift;
290
+ }
291
+
292
+ int input_gpio(int gpio)
293
+ {
294
+ int offset, value, mask;
295
+
296
+ offset = PINLEVEL_OFFSET + (gpio/32);
297
+ mask = (1 << gpio%32);
298
+ value = *(gpio_map+offset) & mask;
299
+ return value;
300
+ }
301
+
302
+ void cleanup(void)
303
+ {
304
+ munmap((void *)gpio_map, BLOCK_SIZE);
305
+ }