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,47 @@
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) 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 "ruby.h"
28
+ #include "c_gpio.h"
29
+ #include "event_gpio.h"
30
+ #include "cpuinfo.h"
31
+ #include "common.h"
32
+ #include "rb_pwm.h"
33
+
34
+ void define_gpio_module_stuff(void);
35
+ int mmap_gpio_mem(void);
36
+ int is_gpio_initialized(unsigned int gpio);
37
+ int is_gpio_output(unsigned int gpio);
38
+ int is_rpi(void);
39
+ VALUE GPIO_clean_up(int argc, VALUE *argv, VALUE self);
40
+ VALUE GPIO_reset(VALUE self);
41
+ VALUE GPIO_setup(VALUE self, VALUE channel, VALUE hash);
42
+ VALUE GPIO_set_numbering(VALUE self, VALUE mode);
43
+ VALUE GPIO_set_high(VALUE self, VALUE channel);
44
+ VALUE GPIO_set_low(VALUE self, VALUE channel);
45
+ VALUE GPIO_test_high(VALUE self, VALUE channel);
46
+ VALUE GPIO_test_low(VALUE self, VALUE channel);
47
+ VALUE GPIO_set_warnings(VALUE self, VALUE setting);
@@ -0,0 +1,148 @@
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) 2013-2018 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_pwm.h"
28
+
29
+ extern VALUE m_GPIO;
30
+ VALUE c_PWM = Qnil;
31
+
32
+ void define_pwm_class_stuff(void)
33
+ {
34
+ c_PWM = rb_define_class_under(m_GPIO, "PWM", rb_cObject);
35
+ rb_define_method(c_PWM, "initialize", PWM_initialize, 2);
36
+ rb_define_method(c_PWM, "start", PWM_start, 1);
37
+ rb_define_method(c_PWM, "gpio", PWM_get_gpio, 0);
38
+ rb_define_method(c_PWM, "duty_cycle", PWM_get_duty_cycle, 0);
39
+ rb_define_method(c_PWM, "duty_cycle=", PWM_set_duty_cycle, 1);
40
+ rb_define_method(c_PWM, "frequency", PWM_get_frequency, 0);
41
+ rb_define_method(c_PWM, "frequency=", PWM_set_frequency, 1);
42
+ rb_define_method(c_PWM, "stop", PWM_stop, 0);
43
+ rb_define_method(c_PWM, "running?", PWM_get_running, 0);
44
+ }
45
+
46
+ // RPi::GPIO::PWM#initialize
47
+ VALUE PWM_initialize(VALUE self, VALUE channel, VALUE frequency)
48
+ {
49
+ int chan;
50
+ unsigned int gpio;
51
+
52
+ chan = NUM2INT(channel);
53
+
54
+ // convert channel to gpio
55
+ if (get_gpio_number(chan, &gpio))
56
+ return Qnil;
57
+
58
+ // does soft pwm already exist on this channel?
59
+ if (pwm_exists(gpio))
60
+ {
61
+ rb_raise(rb_eRuntimeError, "a PWM object already exists for this GPIO channel");
62
+ return Qnil;
63
+ }
64
+
65
+ // ensure channel is set as output
66
+ if (gpio_direction[gpio] != OUTPUT)
67
+ {
68
+ rb_raise(rb_eRuntimeError, "you must setup the GPIO channel as output "
69
+ "first with RPi::GPIO.setup CHANNEL, :as => :output");
70
+ return Qnil;
71
+ }
72
+
73
+ rb_iv_set(self, "@gpio", UINT2NUM(gpio));
74
+ rb_iv_set(self, "@running", Qfalse);
75
+ PWM_set_frequency(self, frequency);
76
+ return self;
77
+ }
78
+
79
+ // RPi::GPIO::PWM#start
80
+ VALUE PWM_start(VALUE self, VALUE duty_cycle)
81
+ {
82
+ pwm_start(NUM2UINT(rb_iv_get(self, "@gpio")));
83
+ PWM_set_duty_cycle(self, duty_cycle);
84
+ rb_iv_set(self, "@running", Qtrue);
85
+ return self;
86
+ }
87
+
88
+ // RPi::GPIO::PWM#gpio
89
+ VALUE PWM_get_gpio(VALUE self)
90
+ {
91
+ return rb_iv_get(self, "@gpio");
92
+ }
93
+
94
+ // RPi::GPIO::PWM#duty_cycle
95
+ VALUE PWM_get_duty_cycle(VALUE self)
96
+ {
97
+ return rb_iv_get(self, "@duty_cycle");
98
+ }
99
+
100
+ // RPi::GPIO::PWM#duty_cycle=
101
+ VALUE PWM_set_duty_cycle(VALUE self, VALUE duty_cycle)
102
+ {
103
+ float dc = (float) NUM2DBL(duty_cycle);
104
+ if (dc < 0.0f || dc > 100.0f)
105
+ {
106
+ rb_raise(rb_eArgError, "duty cycle must be between 0.0 and 100.0");
107
+ return Qnil;
108
+ }
109
+
110
+ rb_iv_set(self, "@duty_cycle", duty_cycle);
111
+ pwm_set_duty_cycle(NUM2UINT(rb_iv_get(self, "@gpio")), dc);
112
+ return self;
113
+ }
114
+
115
+ // RPi::GPIO::PWM#frequency
116
+ VALUE PWM_get_frequency(VALUE self)
117
+ {
118
+ return rb_iv_get(self, "@frequency");
119
+ }
120
+
121
+ // RPi::GPIO::PWM#frequency=
122
+ VALUE PWM_set_frequency(VALUE self, VALUE frequency)
123
+ {
124
+ float freq = (float) NUM2DBL(frequency);
125
+ if (freq <= 0.0f)
126
+ {
127
+ rb_raise(rb_eArgError, "frequency must be greater than 0.0");
128
+ return Qnil;
129
+ }
130
+
131
+ rb_iv_set(self, "@frequency", frequency);
132
+ pwm_set_frequency(NUM2UINT(rb_iv_get(self, "@gpio")), freq);
133
+ return self;
134
+ }
135
+
136
+ // RPi::GPIO::PWM#stop
137
+ VALUE PWM_stop(VALUE self)
138
+ {
139
+ pwm_stop(NUM2UINT(rb_iv_get(self, "@gpio")));
140
+ rb_iv_set(self, "@running", Qfalse);
141
+ return self;
142
+ }
143
+
144
+ // RPi::GPIO::PWM#running?
145
+ VALUE PWM_get_running(VALUE self)
146
+ {
147
+ return rb_iv_get(self, "@running");
148
+ }
@@ -0,0 +1,41 @@
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 "ruby.h"
28
+ #include "soft_pwm.h"
29
+ #include "common.h"
30
+ #include "c_gpio.h"
31
+
32
+ void define_pwm_class_stuff(void);
33
+ VALUE PWM_initialize(VALUE self, VALUE channel, VALUE frequency);
34
+ VALUE PWM_start(VALUE self, VALUE duty_cycle);
35
+ VALUE PWM_get_gpio(VALUE self);
36
+ VALUE PWM_get_duty_cycle(VALUE self);
37
+ VALUE PWM_set_duty_cycle(VALUE self, VALUE duty_cycle);
38
+ VALUE PWM_get_frequency(VALUE self);
39
+ VALUE PWM_set_frequency(VALUE self, VALUE frequency);
40
+ VALUE PWM_stop(VALUE self);
41
+ VALUE PWM_get_running(VALUE self);
@@ -0,0 +1,45 @@
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 "rpi_gpio.h"
28
+ #include "rb_pwm.h"
29
+ #include "rb_gpio.h"
30
+
31
+ VALUE m_RPi = Qnil;
32
+ VALUE m_GPIO = Qnil;
33
+
34
+ void Init_rpi_gpio()
35
+ {
36
+ define_modules();
37
+ define_gpio_module_stuff();
38
+ define_pwm_class_stuff();
39
+ }
40
+
41
+ void define_modules(void)
42
+ {
43
+ m_RPi = rb_define_module("RPi");
44
+ m_GPIO = rb_define_module_under(m_RPi, "GPIO");
45
+ }
@@ -0,0 +1,28 @@
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
+ void Init_rpi_gpio();
28
+ void define_modules(void);
@@ -0,0 +1,235 @@
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) 2013-2018 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 <stdlib.h>
28
+ #include <pthread.h>
29
+ #include <time.h>
30
+ #include "c_gpio.h"
31
+ #include "soft_pwm.h"
32
+ pthread_t threads;
33
+
34
+ struct pwm
35
+ {
36
+ unsigned int gpio;
37
+ float freq;
38
+ float dutycycle;
39
+ float basetime;
40
+ float slicetime;
41
+ struct timespec req_on, req_off;
42
+ int running;
43
+ struct pwm *next;
44
+ };
45
+ struct pwm *pwm_list = NULL;
46
+
47
+ void remove_pwm(unsigned int gpio)
48
+ {
49
+ struct pwm *p = pwm_list;
50
+ struct pwm *prev = NULL;
51
+ struct pwm *temp;
52
+
53
+ while (p != NULL)
54
+ {
55
+ if (p->gpio == gpio)
56
+ {
57
+ if (prev == NULL) {
58
+ pwm_list = p->next;
59
+ } else {
60
+ prev->next = p->next;
61
+ }
62
+ temp = p;
63
+ p = p->next;
64
+ temp->running = 0; // signal the thread to stop. The thread will free() the pwm struct when it's done with it.
65
+ } else {
66
+ prev = p;
67
+ p = p->next;
68
+ }
69
+ }
70
+ }
71
+
72
+ void calculate_times(struct pwm *p)
73
+ {
74
+ long long usec;
75
+
76
+ usec = (long long)(p->dutycycle * p->slicetime * 1000.0);
77
+ p->req_on.tv_sec = (int)(usec / 1000000LL);
78
+ usec -= (long long)p->req_on.tv_sec * 1000000LL;
79
+ p->req_on.tv_nsec = (long)usec * 1000L;
80
+
81
+ usec = (long long)((100.0-p->dutycycle) * p->slicetime * 1000.0);
82
+ p->req_off.tv_sec = (int)(usec / 1000000LL);
83
+ usec -= (long long)p->req_off.tv_sec * 1000000LL;
84
+ p->req_off.tv_nsec = (long)usec * 1000L;
85
+ }
86
+
87
+ void full_sleep(struct timespec *req)
88
+ {
89
+ struct timespec rem = {0};
90
+
91
+ if (nanosleep(req,&rem) == -1)
92
+ full_sleep(&rem);
93
+ }
94
+
95
+ void *pwm_thread(void *threadarg)
96
+ {
97
+ struct pwm *p = (struct pwm *)threadarg;
98
+
99
+ while (p->running)
100
+ {
101
+
102
+ if (p->dutycycle > 0.0)
103
+ {
104
+ output_gpio(p->gpio, 1);
105
+ full_sleep(&p->req_on);
106
+ }
107
+
108
+ if (p->dutycycle < 100.0)
109
+ {
110
+ output_gpio(p->gpio, 0);
111
+ full_sleep(&p->req_off);
112
+ }
113
+ }
114
+
115
+ // clean up
116
+ output_gpio(p->gpio, 0);
117
+ free(p);
118
+ pthread_exit(NULL);
119
+ }
120
+
121
+ struct pwm *add_new_pwm(unsigned int gpio)
122
+ {
123
+ struct pwm *new_pwm;
124
+
125
+ new_pwm = malloc(sizeof(struct pwm));
126
+ new_pwm->gpio = gpio;
127
+ new_pwm->running = 0;
128
+ new_pwm->next = NULL;
129
+ // default to 1 kHz frequency, dutycycle 0.0
130
+ new_pwm->freq = 1000.0;
131
+ new_pwm->dutycycle = 0.0;
132
+ new_pwm->basetime = 1.0; // 1 ms
133
+ new_pwm->slicetime = 0.01; // 0.01 ms
134
+ calculate_times(new_pwm);
135
+ return new_pwm;
136
+ }
137
+
138
+ struct pwm *find_pwm(unsigned int gpio)
139
+ /* Return the pwm record for gpio, creating it if it does not exist */
140
+ {
141
+ struct pwm *p = pwm_list;
142
+
143
+ if (pwm_list == NULL)
144
+ {
145
+ pwm_list = add_new_pwm(gpio);
146
+ return pwm_list;
147
+ }
148
+
149
+ while (p != NULL)
150
+ {
151
+ if (p->gpio == gpio)
152
+ return p;
153
+ if (p->next == NULL)
154
+ {
155
+ p->next = add_new_pwm(gpio);
156
+ return p->next;
157
+ }
158
+ p = p->next;
159
+ }
160
+ return NULL;
161
+ }
162
+
163
+ void pwm_set_duty_cycle(unsigned int gpio, float dutycycle)
164
+ {
165
+ struct pwm *p;
166
+
167
+ if (dutycycle < 0.0 || dutycycle > 100.0)
168
+ {
169
+ // btc fixme - error
170
+ return;
171
+ }
172
+
173
+ if ((p = find_pwm(gpio)) != NULL)
174
+ {
175
+ p->dutycycle = dutycycle;
176
+ calculate_times(p);
177
+ }
178
+ }
179
+
180
+ void pwm_set_frequency(unsigned int gpio, float freq)
181
+ {
182
+ struct pwm *p;
183
+
184
+ if (freq <= 0.0) // to avoid divide by zero
185
+ {
186
+ // btc fixme - error
187
+ return;
188
+ }
189
+
190
+ if ((p = find_pwm(gpio)) != NULL)
191
+ {
192
+ p->basetime = 1000.0 / freq; // calculated in ms
193
+ p->slicetime = p->basetime / 100.0;
194
+ calculate_times(p);
195
+ }
196
+ }
197
+
198
+ void pwm_start(unsigned int gpio)
199
+ {
200
+ struct pwm *p;
201
+
202
+ if (((p = find_pwm(gpio)) == NULL) || p->running)
203
+ return;
204
+
205
+ p->running = 1;
206
+ if (pthread_create(&threads, NULL, pwm_thread, (void *)p) != 0)
207
+ {
208
+ // btc fixme - error
209
+ p->running = 0;
210
+ return;
211
+ }
212
+ pthread_detach(threads);
213
+ }
214
+
215
+ void pwm_stop(unsigned int gpio)
216
+ {
217
+ remove_pwm(gpio);
218
+ }
219
+
220
+ // returns 1 if there is a PWM for this gpio, 0 otherwise
221
+ int pwm_exists(unsigned int gpio)
222
+ {
223
+ struct pwm *p = pwm_list;
224
+
225
+ while (p != NULL)
226
+ {
227
+ if (p->gpio == gpio)
228
+ {
229
+ return 1;
230
+ } else {
231
+ p = p->next;
232
+ }
233
+ }
234
+ return 0;
235
+ }