pixel_pi 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,464 @@
1
+ #include <ruby.h>
2
+ #include "ws2811.h"
3
+
4
+ #define RGB2COLOR(r,g,b) ((((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff))
5
+
6
+ VALUE mPixelPi;
7
+ VALUE cLeds;
8
+ VALUE ePixelPiError;
9
+
10
+ static VALUE sym_dma, sym_frequency, sym_invert, sym_brightness;
11
+
12
+ /* ======================================================================= */
13
+
14
+ static void
15
+ pp_leds_free( void *ptr )
16
+ {
17
+ ws2811_t *ledstring;
18
+ if (NULL == ptr) return;
19
+
20
+ ledstring= (ws2811_t*) ptr;
21
+ if (ledstring->device) ws2811_fini( ledstring );
22
+ xfree( ledstring );
23
+ }
24
+
25
+ static VALUE
26
+ pp_leds_allocate( VALUE klass )
27
+ {
28
+ int ii;
29
+ ws2811_t *ledstring;
30
+
31
+ ledstring = ALLOC_N( ws2811_t, 1 );
32
+ if (!ledstring) {
33
+ rb_raise(rb_eNoMemError, "could not allocate PixelPi::Leds instance");
34
+ }
35
+
36
+ ledstring->freq = WS2811_TARGET_FREQ;
37
+ ledstring->dmanum = 5;
38
+ ledstring->device = NULL;
39
+
40
+ for (ii=0; ii<RPI_PWM_CHANNELS; ii++) {
41
+ ledstring->channel[ii].gpionum = 0;
42
+ ledstring->channel[ii].count = 0;
43
+ ledstring->channel[ii].invert = 0;
44
+ ledstring->channel[ii].brightness = 255;
45
+ ledstring->channel[ii].leds = NULL;
46
+ }
47
+
48
+ return Data_Wrap_Struct( klass, NULL, pp_leds_free, ledstring );
49
+ }
50
+
51
+ static ws2811_t*
52
+ pp_leds_struct( VALUE self )
53
+ {
54
+ ws2811_t *ledstring;
55
+
56
+ if (TYPE(self) != T_DATA
57
+ || RDATA(self)->dfree != (RUBY_DATA_FUNC) pp_leds_free) {
58
+ rb_raise( rb_eTypeError, "expecting a PixelPi::Leds object" );
59
+ }
60
+ Data_Get_Struct( self, ws2811_t, ledstring );
61
+
62
+ if (!ledstring->device) {
63
+ rb_raise( ePixelPiError, "Leds are not initialized" );
64
+ }
65
+
66
+ return ledstring;
67
+ }
68
+
69
+ static int
70
+ pp_rgb_to_color( VALUE red, VALUE green, VALUE blue )
71
+ {
72
+ int r = NUM2INT(red);
73
+ int g = NUM2INT(green);
74
+ int b = NUM2INT(blue);
75
+ return RGB2COLOR(r, g, b);
76
+ }
77
+
78
+ /* ======================================================================= */
79
+ /* call-seq:
80
+ * PixelPi::Leds.new( length, gpio, options = {} )
81
+ *
82
+ * Create a new PixelPi::Leds instance that can be used to control a string of
83
+ * NeoPixels from a RaspberryPi. The length of the pixel string must be given as
84
+ * well as the GPIO pin number used to control the string. The remaining options
85
+ * have sensible defaults.
86
+ *
87
+ * length - the nubmer of leds in the string
88
+ * gpio - the GPIO pin number
89
+ * options - Hash of arguments
90
+ * :dma - DMA channel defaults to 5
91
+ * :frequency - output frequency defaults to 800,000 Hz
92
+ * :invert - defaults to `false`
93
+ * :brightness - defaults to 255
94
+ */
95
+ static VALUE
96
+ pp_leds_initialize( int argc, VALUE* argv, VALUE self )
97
+ {
98
+ ws2811_t *ledstring;
99
+ VALUE length, gpio, opts, tmp;
100
+ int resp;
101
+
102
+ if (TYPE(self) != T_DATA
103
+ || RDATA(self)->dfree != (RUBY_DATA_FUNC) pp_leds_free) {
104
+ rb_raise( rb_eTypeError, "expecting a PixelPi::Leds object" );
105
+ }
106
+ Data_Get_Struct( self, ws2811_t, ledstring );
107
+
108
+ /* parse out the length, gpio, and optional arguments if given */
109
+ rb_scan_args( argc, argv, "21", &length, &gpio, &opts );
110
+
111
+ /* get the number of pixels */
112
+ if (TYPE(length) == T_FIXNUM) {
113
+ ledstring->channel[0].count = NUM2INT(length);
114
+ if (ledstring->channel[0].count < 0) {
115
+ rb_raise( rb_eArgError, "length cannot be negative: %d", ledstring->channel[0].count );
116
+ }
117
+ } else {
118
+ rb_raise( rb_eTypeError, "length must be a number: %s", rb_obj_classname(length) );
119
+ }
120
+
121
+ /* get the GPIO number */
122
+ if (TYPE(gpio) == T_FIXNUM) {
123
+ ledstring->channel[0].gpionum = NUM2INT(gpio);
124
+ if (ledstring->channel[0].gpionum < 0) {
125
+ rb_raise( rb_eArgError, "GPIO cannot be negative: %d", ledstring->channel[0].gpionum );
126
+ }
127
+ } else {
128
+ rb_raise( rb_eTypeError, "GPIO must be a number: %s", rb_obj_classname(gpio) );
129
+ }
130
+
131
+ if (!NIL_P(opts)) {
132
+ Check_Type( opts, T_HASH );
133
+
134
+ /* get the DMA channel */
135
+ tmp = rb_hash_lookup( opts, sym_dma );
136
+ if (!NIL_P(tmp)) {
137
+ if (TYPE(tmp) == T_FIXNUM) {
138
+ ledstring->dmanum = NUM2INT(tmp);
139
+ if (ledstring->dmanum < 0) {
140
+ rb_raise( rb_eArgError, "DMA channel cannot be negative: %d", ledstring->dmanum );
141
+ }
142
+ } else {
143
+ rb_raise( rb_eTypeError, "DMA channel must be a number: %s", rb_obj_classname(tmp) );
144
+ }
145
+ }
146
+
147
+ /* get the frequency */
148
+ tmp = rb_hash_lookup( opts, sym_frequency );
149
+ if (!NIL_P(tmp)) {
150
+ if (TYPE(tmp) == T_FIXNUM) {
151
+ ledstring->freq = NUM2UINT(tmp);
152
+ } else {
153
+ rb_raise( rb_eTypeError, "frequency must be a number: %s", rb_obj_classname(tmp) );
154
+ }
155
+ }
156
+
157
+ /* get the brightness */
158
+ tmp = rb_hash_lookup( opts, sym_brightness );
159
+ if (!NIL_P(tmp)) {
160
+ if (TYPE(tmp) == T_FIXNUM) {
161
+ ledstring->channel[0].brightness = (NUM2UINT(tmp) & 0xff);
162
+ if (ledstring->channel[0].brightness < 0) {
163
+ rb_raise( rb_eArgError, "brightness cannot be negative: %d", ledstring->channel[0].brightness );
164
+ }
165
+ } else {
166
+ rb_raise( rb_eTypeError, "brightness must be a number: %s", rb_obj_classname(tmp) );
167
+ }
168
+ }
169
+
170
+ /* get the invert flag */
171
+ tmp = rb_hash_lookup( opts, sym_invert );
172
+ if (!NIL_P(tmp)) {
173
+ if (RTEST(tmp)) ledstring->channel[0].invert = 1;
174
+ else ledstring->channel[0].invert = 0;
175
+ }
176
+ }
177
+
178
+ /* initialize the DMA and PWM cycle */
179
+ resp = ws2811_init( ledstring );
180
+ if (resp < 0) {
181
+ rb_raise( ePixelPiError, "Leds could not be initialized: %d", resp );
182
+ }
183
+
184
+ return self;
185
+ }
186
+
187
+ /* call-seq:
188
+ * length
189
+ *
190
+ * Returns the number of pixels in the LED string.
191
+ */
192
+ static VALUE
193
+ pp_leds_length_get( VALUE self )
194
+ {
195
+ ws2811_t *ledstring = pp_leds_struct( self );
196
+ return INT2FIX(ledstring->channel[0].count);
197
+ }
198
+
199
+ /* call-seq:
200
+ * gpio
201
+ *
202
+ * Returns the GPIO number used to control the pixels.
203
+ */
204
+ static VALUE
205
+ pp_leds_gpio_get( VALUE self )
206
+ {
207
+ ws2811_t *ledstring = pp_leds_struct( self );
208
+ return INT2FIX(ledstring->channel[0].gpionum);
209
+ }
210
+
211
+ /* call-seq:
212
+ * dma
213
+ *
214
+ * Returns the DMA channel used to control the pixels.
215
+ */
216
+ static VALUE
217
+ pp_leds_dma_get( VALUE self )
218
+ {
219
+ ws2811_t *ledstring = pp_leds_struct( self );
220
+ return INT2FIX(ledstring->dmanum);
221
+ }
222
+
223
+ /* call-seq:
224
+ * frequency
225
+ *
226
+ * Returns the output frequency.
227
+ */
228
+ static VALUE
229
+ pp_leds_frequency_get( VALUE self )
230
+ {
231
+ ws2811_t *ledstring = pp_leds_struct( self );
232
+ return INT2FIX(ledstring->freq);
233
+ }
234
+
235
+ /* call-seq:
236
+ * invert
237
+ *
238
+ * Returns `true` if the invert flag is set and `false` if it is not set.
239
+ */
240
+ static VALUE
241
+ pp_leds_invert_get( VALUE self )
242
+ {
243
+ ws2811_t *ledstring = pp_leds_struct( self );
244
+ if (ledstring->channel[0].invert) {
245
+ return Qtrue;
246
+ } else {
247
+ return Qfalse;
248
+ }
249
+ }
250
+
251
+ /* call-seq:
252
+ * brightness
253
+ *
254
+ * Returns the brightness.
255
+ */
256
+ static VALUE
257
+ pp_leds_brightness_get( VALUE self )
258
+ {
259
+ ws2811_t *ledstring = pp_leds_struct( self );
260
+ return INT2FIX(ledstring->channel[0].brightness);
261
+ }
262
+
263
+ /* call-seq:
264
+ * brightness = 128 # value between 0 and 255
265
+ *
266
+ * Set the pixel brightness. This is a value between 0 and 255. All pixels will
267
+ * be scaled by this value. The hue is not affected; only the luminosity is
268
+ * affected.
269
+ *
270
+ * Returns the new brightness.
271
+ */
272
+ static VALUE
273
+ pp_leds_brightness_set( VALUE self, VALUE brightness )
274
+ {
275
+ ws2811_t *ledstring = pp_leds_struct( self );
276
+ ledstring->channel[0].brightness = (NUM2UINT(brightness) & 0xff);
277
+ return brightness;
278
+ }
279
+
280
+ /* call-seq:
281
+ * show
282
+ *
283
+ * Update the display with the data from the LED buffer.
284
+ *
285
+ * Returns this PixelPi::Leds instance.
286
+ */
287
+ static VALUE
288
+ pp_leds_show( VALUE self )
289
+ {
290
+ ws2811_t *ledstring = pp_leds_struct( self );
291
+ int resp = ws2811_render( ledstring );
292
+ if (resp < 0) {
293
+ rb_raise( ePixelPiError, "PixelPi::Leds failed to render: %d", resp );
294
+ }
295
+ return self;
296
+ }
297
+
298
+ /* call-seq:
299
+ * clear
300
+ *
301
+ * Clear the display. This will set all values in the LED buffer to zero, and
302
+ * then update the display. All pixels will be turned off by this method.
303
+ *
304
+ * Returns this PixelPi::Leds instance.
305
+ */
306
+ static VALUE
307
+ pp_leds_clear( VALUE self )
308
+ {
309
+ ws2811_t *ledstring = pp_leds_struct( self );
310
+ ws2811_channel_t channel = ledstring->channel[0];
311
+ int ii, resp;
312
+
313
+ for (ii=0; ii<channel.count; ii++) {
314
+ channel.leds[ii] = 0;
315
+ }
316
+
317
+ resp = ws2811_render( ledstring );
318
+ if (resp < 0) {
319
+ rb_raise( rb_eRuntimeError, "PixelPi::Leds failed to render: %d", resp );
320
+ }
321
+
322
+ return self;
323
+ }
324
+
325
+ /* call-seq:
326
+ * close
327
+ *
328
+ * FIXME
329
+ *
330
+ * Returns `nil`.
331
+ */
332
+ static VALUE
333
+ pp_leds_close( VALUE self )
334
+ {
335
+ ws2811_t *ledstring = pp_leds_struct( self );
336
+ if (ledstring->device) ws2811_fini( ledstring );
337
+ return Qnil;
338
+ }
339
+
340
+ /* call-seq:
341
+ * leds[num]
342
+ *
343
+ * Get the 24-bit RGB color value for the LED at position `num`.
344
+ *
345
+ * Returns a 24-bit RGB color value.
346
+ */
347
+ static VALUE
348
+ pp_leds_get_pixel_color( VALUE self, VALUE num )
349
+ {
350
+ ws2811_t *ledstring = pp_leds_struct( self );
351
+ ws2811_channel_t channel = ledstring->channel[0];
352
+
353
+ int n = NUM2INT(num);
354
+ if (n < 0 || n >= channel.count) {
355
+ rb_raise( rb_eIndexError, "index %d is outside of LED range: 0...%d", n, channel.count-1 );
356
+ }
357
+
358
+ return INT2FIX(channel.leds[n]);
359
+ }
360
+
361
+ /* call-seq:
362
+ * leds[num] = color
363
+ * leds[num] = PixelPi::Color( red, green, blue )
364
+ *
365
+ * Set the LED at position `num` to the provided 24-bit RGB color value.
366
+ *
367
+ * Returns the 24-bit RGB color value.
368
+ */
369
+ static VALUE
370
+ pp_leds_set_pixel_color( VALUE self, VALUE num, VALUE color )
371
+ {
372
+ ws2811_t *ledstring = pp_leds_struct( self );
373
+ ws2811_channel_t channel = ledstring->channel[0];
374
+
375
+ int n = NUM2INT(num);
376
+ if (n >= 0 && n < channel.count) {
377
+ channel.leds[n] = NUM2INT(color);
378
+ }
379
+ return self;
380
+ }
381
+
382
+ /* call-seq:
383
+ * set_pixel( num, color )
384
+ * set_pixel( num, red, green, blue )
385
+ *
386
+ * Set the LED at position `num` to the given color. The color can be a single
387
+ * 24-bit RGB `color` value or three separate color values - one for `red`, one
388
+ * for `green`, and one for `blue`.
389
+ *
390
+ * Returns this PixelPi::Leds instance.
391
+ */
392
+ static VALUE
393
+ pp_leds_set_pixel_color2( int argc, VALUE* argv, VALUE self )
394
+ {
395
+ VALUE num, color, red, green, blue;
396
+ rb_scan_args( argc, argv, "22", &num, &red, &green, &blue );
397
+
398
+ switch (argc) {
399
+ case 2: {
400
+ color = red;
401
+ break;
402
+ }
403
+ case 4: {
404
+ int c = pp_rgb_to_color( red, green, blue );
405
+ color = INT2FIX(c);
406
+ break;
407
+ }
408
+ default: {
409
+ rb_raise( rb_eArgError, "expecting either 2 or 4 arguments: %d", argc );
410
+ break;
411
+ }
412
+ }
413
+
414
+ pp_leds_set_pixel_color( self, num, color );
415
+ return self;
416
+ }
417
+
418
+ /* call-seq:
419
+ * PixelPi::Color(red, green, blue) #=> 24-bit color
420
+ *
421
+ * Given a set of RGB values return a single 24-bit color value. The RGB values
422
+ * are nubmers in the range 0..255.
423
+ *
424
+ * Returns a 24-bit RGB color value.
425
+ */
426
+ static VALUE
427
+ pp_color( VALUE klass, VALUE red, VALUE green, VALUE blue )
428
+ {
429
+ int color = pp_rgb_to_color( red, green, blue );
430
+ return INT2FIX(color);
431
+ }
432
+
433
+ void Init_leds( )
434
+ {
435
+ sym_dma = ID2SYM(rb_intern( "dma" ));
436
+ sym_frequency = ID2SYM(rb_intern( "frequency" ));
437
+ sym_invert = ID2SYM(rb_intern( "invert" ));
438
+ sym_brightness = ID2SYM(rb_intern( "brightness" ));
439
+
440
+ mPixelPi = rb_define_module( "PixelPi" );
441
+
442
+ cLeds = rb_define_class_under( mPixelPi, "Leds", rb_cObject );
443
+ rb_define_alloc_func( cLeds, pp_leds_allocate );
444
+ rb_define_method( cLeds, "initialize", pp_leds_initialize, -1 );
445
+
446
+ rb_define_method( cLeds, "length", pp_leds_length_get, 0 );
447
+ rb_define_method( cLeds, "gpio", pp_leds_gpio_get, 0 );
448
+ rb_define_method( cLeds, "dma", pp_leds_dma_get, 0 );
449
+ rb_define_method( cLeds, "frequency", pp_leds_frequency_get, 0 );
450
+ rb_define_method( cLeds, "invert", pp_leds_invert_get, 0 );
451
+ rb_define_method( cLeds, "brightness", pp_leds_brightness_get, 0 );
452
+ rb_define_method( cLeds, "brightness=", pp_leds_brightness_set, 1 );
453
+ rb_define_method( cLeds, "show", pp_leds_show, 0 );
454
+ rb_define_method( cLeds, "clear", pp_leds_clear, 0 );
455
+ rb_define_method( cLeds, "close", pp_leds_close, 0 );
456
+ rb_define_method( cLeds, "[]", pp_leds_get_pixel_color, 1 );
457
+ rb_define_method( cLeds, "[]=", pp_leds_set_pixel_color, 2 );
458
+ rb_define_method( cLeds, "set_pixel", pp_leds_set_pixel_color2, -1 );
459
+
460
+ rb_define_module_function( mPixelPi, "Color", pp_color, 3 );
461
+
462
+ /* Define the PixelPi::Error class */
463
+ ePixelPiError = rb_define_class_under( mPixelPi, "Error", rb_eStandardError );
464
+ }
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2014, jgarff
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
+
data/ext/ws2811/clk.h ADDED
@@ -0,0 +1,60 @@
1
+ /*
2
+ * clk.h
3
+ *
4
+ * Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
5
+ *
6
+ * All rights reserved.
7
+ *
8
+ * Redistribution and use in source and binary forms, with or without modification, are permitted
9
+ * provided that the following conditions are met:
10
+ *
11
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
12
+ * conditions and the following disclaimer.
13
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
14
+ * of conditions and the following disclaimer in the documentation and/or other materials
15
+ * provided with the distribution.
16
+ * 3. Neither the name of the owner nor the names of its contributors may be used to endorse
17
+ * or promote products derived from this software without specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
20
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
22
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ *
28
+ */
29
+
30
+ #ifndef __CLK_H__
31
+ #define __CLK_H__
32
+
33
+
34
+ typedef struct {
35
+ uint32_t ctl;
36
+ #define CM_PWM_CTL_PASSWD (0x5a << 24)
37
+ #define CM_PWM_CTL_MASH(val) ((val & 0x3) << 9)
38
+ #define CM_PWM_CTL_FLIP (1 << 8)
39
+ #define CM_PWM_CTL_BUSY (1 << 7)
40
+ #define CM_PWM_CTL_KILL (1 << 5)
41
+ #define CM_PWM_CTL_ENAB (1 << 4)
42
+ #define CM_PWM_CTL_SRC_GND (0 << 0)
43
+ #define CM_PWM_CTL_SRC_OSC (1 << 0)
44
+ #define CM_PWM_CTL_SRC_TSTDBG0 (2 << 0)
45
+ #define CM_PWM_CTL_SRC_TSTDBG1 (3 << 0)
46
+ #define CM_PWM_CTL_SRC_PLLA (4 << 0)
47
+ #define CM_PWM_CTL_SRC_PLLC (5 << 0)
48
+ #define CM_PWM_CTL_SRC_PLLD (6 << 0)
49
+ #define CM_PWM_CTL_SRC_HDMIAUX (7 << 0)
50
+ uint32_t div;
51
+ #define CM_PWM_DIV_PASSWD (0x5a << 24)
52
+ #define CM_PWM_DIV_DIVI(val) ((val & 0xfff) << 12)
53
+ #define CM_PWM_DIV_DIVF(val) ((val & 0xfff) << 0)
54
+ } __attribute__ ((packed)) cm_pwm_t;
55
+
56
+
57
+ #define CM_PWM (0x201010a0) // 0x7e1010a0
58
+
59
+
60
+ #endif /* __CLK_H__ */