pixel_pi 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/examples/strandtest.rb +12 -11
- data/ext/pixel_pi/leds.c +225 -19
- data/lib/pixel_pi/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c158234b67ccd01d55b48cf274c5ccb437ae77a
|
4
|
+
data.tar.gz: 5125b6c0d47381ca23ba8fc942ac73d22f9f3bbb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d010f3d8e722cb39aea7cd13cb78e92621628014799899bb08def77a0b0e1333dcf88362aa797f88ccdf2949b6d524f80bf23fa3302951e875e974fbf0e7a80b
|
7
|
+
data.tar.gz: acdac849b6517a354918be99681e360592a8edb77ca18a77bc741aba66008c56b42a62a760500a9026f6bd41c7d6d1a7794d5085765e3a39fee56637ef8129e0
|
data/.gitignore
CHANGED
data/examples/strandtest.rb
CHANGED
@@ -54,11 +54,11 @@ module StrandTest
|
|
54
54
|
spacing = opts.fetch(:spacing, 3)
|
55
55
|
|
56
56
|
iterations.times do
|
57
|
-
spacing.times do |
|
58
|
-
|
57
|
+
spacing.times do |sp|
|
58
|
+
self.clear
|
59
|
+
(sp...self.length).step(spacing) { |ii| self[ii] = color }
|
59
60
|
self.show
|
60
61
|
sleep(wait_ms / 1000.0)
|
61
|
-
(0...self.length).step(spacing) { |ii| self[ii+jj] = 0 }
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
@@ -71,6 +71,7 @@ module StrandTest
|
|
71
71
|
#
|
72
72
|
# Returns a 24-bit RGB color value.
|
73
73
|
def wheel( pos )
|
74
|
+
pos = pos & 0xff
|
74
75
|
if pos < 85
|
75
76
|
return PixelPi::Color(pos * 3, 255 - pos * 3, 0)
|
76
77
|
elsif pos < 170
|
@@ -94,7 +95,7 @@ module StrandTest
|
|
94
95
|
iterations = opts.fetch(:iterations, 1)
|
95
96
|
|
96
97
|
(0...256*iterations).each do |jj|
|
97
|
-
self.
|
98
|
+
self.fill { |ii| wheel(ii+jj) }
|
98
99
|
self.show
|
99
100
|
sleep(wait_ms / 1000.0)
|
100
101
|
end
|
@@ -114,7 +115,7 @@ module StrandTest
|
|
114
115
|
iterations = opts.fetch(:iterations, 5)
|
115
116
|
|
116
117
|
(0...256*iterations).each do |jj|
|
117
|
-
self.
|
118
|
+
self.fill { |ii| wheel((ii * 256 / self.length) + jj) }
|
118
119
|
self.show
|
119
120
|
sleep(wait_ms / 1000.0)
|
120
121
|
end
|
@@ -135,10 +136,10 @@ module StrandTest
|
|
135
136
|
|
136
137
|
256.times do |jj|
|
137
138
|
spacing.times do |sp|
|
138
|
-
|
139
|
+
self.clear
|
140
|
+
(sp...self.length).step(spacing) { |ii| self[ii] = wheel((ii+jj) % 255) }
|
139
141
|
self.show
|
140
142
|
sleep(wait_ms / 1000.0)
|
141
|
-
(0...self.length).step(spacing) { |ii| self[ii+sp] = 0 }
|
142
143
|
end
|
143
144
|
end
|
144
145
|
|
@@ -158,10 +159,10 @@ strip = PixelPi::Leds.new \
|
|
158
159
|
strip.extend StrandTest
|
159
160
|
|
160
161
|
trap("SIGINT") do
|
161
|
-
strip.clear
|
162
|
-
strip.close
|
163
|
-
exit
|
164
|
-
end
|
162
|
+
strip.clear.show # turn off all the LEDs
|
163
|
+
strip.close # close is not explicitly needed - the finalizer will
|
164
|
+
exit # gracefully shutdown the PWM channel and release the
|
165
|
+
end # DMA memory
|
165
166
|
|
166
167
|
STDOUT.puts "Press Ctrl-C to quit."
|
167
168
|
|
data/ext/pixel_pi/leds.c
CHANGED
@@ -3,6 +3,10 @@
|
|
3
3
|
|
4
4
|
#define RGB2COLOR(r,g,b) ((((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff))
|
5
5
|
|
6
|
+
#ifndef MIN
|
7
|
+
#define MIN(a,b) (((a)<(b))?(a):(b))
|
8
|
+
#endif
|
9
|
+
|
6
10
|
VALUE mPixelPi;
|
7
11
|
VALUE cLeds;
|
8
12
|
VALUE ePixelPiError;
|
@@ -69,9 +73,9 @@ pp_leds_struct( VALUE self )
|
|
69
73
|
static int
|
70
74
|
pp_rgb_to_color( VALUE red, VALUE green, VALUE blue )
|
71
75
|
{
|
72
|
-
int r =
|
73
|
-
int g =
|
74
|
-
int b =
|
76
|
+
int r = FIX2INT(red);
|
77
|
+
int g = FIX2INT(green);
|
78
|
+
int b = FIX2INT(blue);
|
75
79
|
return RGB2COLOR(r, g, b);
|
76
80
|
}
|
77
81
|
|
@@ -110,7 +114,7 @@ pp_leds_initialize( int argc, VALUE* argv, VALUE self )
|
|
110
114
|
|
111
115
|
/* get the number of pixels */
|
112
116
|
if (TYPE(length) == T_FIXNUM) {
|
113
|
-
ledstring->channel[0].count =
|
117
|
+
ledstring->channel[0].count = FIX2INT(length);
|
114
118
|
if (ledstring->channel[0].count < 0) {
|
115
119
|
rb_raise( rb_eArgError, "length cannot be negative: %d", ledstring->channel[0].count );
|
116
120
|
}
|
@@ -120,7 +124,7 @@ pp_leds_initialize( int argc, VALUE* argv, VALUE self )
|
|
120
124
|
|
121
125
|
/* get the GPIO number */
|
122
126
|
if (TYPE(gpio) == T_FIXNUM) {
|
123
|
-
ledstring->channel[0].gpionum =
|
127
|
+
ledstring->channel[0].gpionum = FIX2INT(gpio);
|
124
128
|
if (ledstring->channel[0].gpionum < 0) {
|
125
129
|
rb_raise( rb_eArgError, "GPIO cannot be negative: %d", ledstring->channel[0].gpionum );
|
126
130
|
}
|
@@ -135,7 +139,7 @@ pp_leds_initialize( int argc, VALUE* argv, VALUE self )
|
|
135
139
|
tmp = rb_hash_lookup( opts, sym_dma );
|
136
140
|
if (!NIL_P(tmp)) {
|
137
141
|
if (TYPE(tmp) == T_FIXNUM) {
|
138
|
-
ledstring->dmanum =
|
142
|
+
ledstring->dmanum = FIX2INT(tmp);
|
139
143
|
if (ledstring->dmanum < 0) {
|
140
144
|
rb_raise( rb_eArgError, "DMA channel cannot be negative: %d", ledstring->dmanum );
|
141
145
|
}
|
@@ -148,7 +152,7 @@ pp_leds_initialize( int argc, VALUE* argv, VALUE self )
|
|
148
152
|
tmp = rb_hash_lookup( opts, sym_frequency );
|
149
153
|
if (!NIL_P(tmp)) {
|
150
154
|
if (TYPE(tmp) == T_FIXNUM) {
|
151
|
-
ledstring->freq =
|
155
|
+
ledstring->freq = FIX2UINT(tmp);
|
152
156
|
} else {
|
153
157
|
rb_raise( rb_eTypeError, "frequency must be a number: %s", rb_obj_classname(tmp) );
|
154
158
|
}
|
@@ -158,7 +162,7 @@ pp_leds_initialize( int argc, VALUE* argv, VALUE self )
|
|
158
162
|
tmp = rb_hash_lookup( opts, sym_brightness );
|
159
163
|
if (!NIL_P(tmp)) {
|
160
164
|
if (TYPE(tmp) == T_FIXNUM) {
|
161
|
-
ledstring->channel[0].brightness = (
|
165
|
+
ledstring->channel[0].brightness = (FIX2UINT(tmp) & 0xff);
|
162
166
|
if (ledstring->channel[0].brightness < 0) {
|
163
167
|
rb_raise( rb_eArgError, "brightness cannot be negative: %d", ledstring->channel[0].brightness );
|
164
168
|
}
|
@@ -273,7 +277,7 @@ static VALUE
|
|
273
277
|
pp_leds_brightness_set( VALUE self, VALUE brightness )
|
274
278
|
{
|
275
279
|
ws2811_t *ledstring = pp_leds_struct( self );
|
276
|
-
ledstring->channel[0].brightness = (
|
280
|
+
ledstring->channel[0].brightness = (FIX2UINT(brightness) & 0xff);
|
277
281
|
return brightness;
|
278
282
|
}
|
279
283
|
|
@@ -308,24 +312,23 @@ pp_leds_clear( VALUE self )
|
|
308
312
|
{
|
309
313
|
ws2811_t *ledstring = pp_leds_struct( self );
|
310
314
|
ws2811_channel_t channel = ledstring->channel[0];
|
311
|
-
int ii
|
315
|
+
int ii;
|
312
316
|
|
313
317
|
for (ii=0; ii<channel.count; ii++) {
|
314
318
|
channel.leds[ii] = 0;
|
315
319
|
}
|
316
320
|
|
317
|
-
resp = ws2811_render( ledstring );
|
318
|
-
if (resp < 0) {
|
319
|
-
rb_raise( rb_eRuntimeError, "PixelPi::Leds failed to render: %d", resp );
|
320
|
-
}
|
321
|
-
|
322
321
|
return self;
|
323
322
|
}
|
324
323
|
|
325
324
|
/* call-seq:
|
326
325
|
* close
|
327
326
|
*
|
328
|
-
*
|
327
|
+
* Shutdown the NeoPixels connected to the DMA / PWM channel. After this method
|
328
|
+
* the current PixelPi::Leds instance will no longer be usable; a new instance
|
329
|
+
* will need to be created. This method is automatically invoked when the
|
330
|
+
* instance is deallcoated by the Ruby garbage collector. It does not need to be
|
331
|
+
* explicitly invoked.
|
329
332
|
*
|
330
333
|
* Returns `nil`.
|
331
334
|
*/
|
@@ -350,7 +353,7 @@ pp_leds_get_pixel_color( VALUE self, VALUE num )
|
|
350
353
|
ws2811_t *ledstring = pp_leds_struct( self );
|
351
354
|
ws2811_channel_t channel = ledstring->channel[0];
|
352
355
|
|
353
|
-
int n =
|
356
|
+
int n = FIX2INT(num);
|
354
357
|
if (n < 0 || n >= channel.count) {
|
355
358
|
rb_raise( rb_eIndexError, "index %d is outside of LED range: 0...%d", n, channel.count-1 );
|
356
359
|
}
|
@@ -372,9 +375,9 @@ pp_leds_set_pixel_color( VALUE self, VALUE num, VALUE color )
|
|
372
375
|
ws2811_t *ledstring = pp_leds_struct( self );
|
373
376
|
ws2811_channel_t channel = ledstring->channel[0];
|
374
377
|
|
375
|
-
int n =
|
378
|
+
int n = FIX2INT(num);
|
376
379
|
if (n >= 0 && n < channel.count) {
|
377
|
-
channel.leds[n] =
|
380
|
+
channel.leds[n] = FIX2UINT(color);
|
378
381
|
}
|
379
382
|
return self;
|
380
383
|
}
|
@@ -415,6 +418,204 @@ pp_leds_set_pixel_color2( int argc, VALUE* argv, VALUE self )
|
|
415
418
|
return self;
|
416
419
|
}
|
417
420
|
|
421
|
+
/* call-seq:
|
422
|
+
* to_a
|
423
|
+
*
|
424
|
+
* Takes the current list of 24-bit RGB values stored in the LED strings and
|
425
|
+
* returns them as an Array. These colors might not be actively displayed; it
|
426
|
+
* all depends if `show` has been called on the PixelPi::Leds instance.
|
427
|
+
*
|
428
|
+
* Returns an Array of 24-bit RGB values.
|
429
|
+
*/
|
430
|
+
static VALUE
|
431
|
+
pp_leds_to_a( VALUE self )
|
432
|
+
{
|
433
|
+
ws2811_t *ledstring = pp_leds_struct( self );
|
434
|
+
ws2811_channel_t channel = ledstring->channel[0];
|
435
|
+
int ii;
|
436
|
+
VALUE ary;
|
437
|
+
|
438
|
+
ary = rb_ary_new2( channel.count );
|
439
|
+
for (ii=0; ii<channel.count; ii++) {
|
440
|
+
rb_ary_push( ary, INT2NUM(channel.leds[ii]) );
|
441
|
+
}
|
442
|
+
|
443
|
+
return ary;
|
444
|
+
}
|
445
|
+
|
446
|
+
/* call-seq:
|
447
|
+
* replace( ary )
|
448
|
+
*
|
449
|
+
* Replace the LED colors with the 24-bit RGB color values found in the `ary`.
|
450
|
+
* If the `ary` is longer than the LED string then the extra color values will
|
451
|
+
* be ignored. If the `ary` is shorter than the LED string then only the LEDS
|
452
|
+
* up to `ary.length` will be changed.
|
453
|
+
*
|
454
|
+
* You must call `show` for the new colors to be displayed.
|
455
|
+
*
|
456
|
+
* Returns this PixelPi::Leds instance.
|
457
|
+
*/
|
458
|
+
static VALUE
|
459
|
+
pp_leds_replace( VALUE self, VALUE ary )
|
460
|
+
{
|
461
|
+
ws2811_t *ledstring = pp_leds_struct( self );
|
462
|
+
ws2811_channel_t channel = ledstring->channel[0];
|
463
|
+
int ii, min;
|
464
|
+
|
465
|
+
Check_Type( ary, T_ARRAY );
|
466
|
+
min = MIN(channel.count, RARRAY_LEN(ary));
|
467
|
+
|
468
|
+
for (ii=0; ii<min; ii++) {
|
469
|
+
channel.leds[ii] = FIX2UINT(rb_ary_entry( ary, ii ));
|
470
|
+
}
|
471
|
+
|
472
|
+
return self;
|
473
|
+
}
|
474
|
+
|
475
|
+
static void
|
476
|
+
pp_leds_reverse( ws2811_led_t *p1, ws2811_led_t *p2 )
|
477
|
+
{
|
478
|
+
while (p1 < p2) {
|
479
|
+
ws2811_led_t tmp = *p1;
|
480
|
+
*p1++ = *p2;
|
481
|
+
*p2-- = tmp;
|
482
|
+
}
|
483
|
+
}
|
484
|
+
|
485
|
+
/* call-seq:
|
486
|
+
* reverse
|
487
|
+
*
|
488
|
+
* Reverse the order of the LED colors.
|
489
|
+
*
|
490
|
+
* Returns this PixelPi::Leds instance.
|
491
|
+
*/
|
492
|
+
static VALUE
|
493
|
+
pp_leds_reverse_m( VALUE self )
|
494
|
+
{
|
495
|
+
ws2811_t *ledstring = pp_leds_struct( self );
|
496
|
+
ws2811_channel_t channel = ledstring->channel[0];
|
497
|
+
ws2811_led_t *ptr = channel.leds;
|
498
|
+
int len = channel.count;
|
499
|
+
|
500
|
+
if (--len > 0) pp_leds_reverse( ptr, ptr + len );
|
501
|
+
|
502
|
+
return self;
|
503
|
+
}
|
504
|
+
|
505
|
+
/* call-seq:
|
506
|
+
* rotate( count = 1 )
|
507
|
+
*
|
508
|
+
* Rotates the LED colors in place so that the color at `count` comes first. If
|
509
|
+
* `count` is negative then it rotates in the opposite direction, starting from
|
510
|
+
* the end of the LEDs where -1 is the last LED.
|
511
|
+
*
|
512
|
+
* Returns this PixelPi::Leds instance.
|
513
|
+
*/
|
514
|
+
static VALUE
|
515
|
+
pp_leds_rotate( int argc, VALUE* argv, VALUE self )
|
516
|
+
{
|
517
|
+
ws2811_t *ledstring = pp_leds_struct( self );
|
518
|
+
ws2811_channel_t channel = ledstring->channel[0];
|
519
|
+
int cnt = 1;
|
520
|
+
|
521
|
+
switch (argc) {
|
522
|
+
case 1: cnt = FIX2INT(argv[0]);
|
523
|
+
case 0: break;
|
524
|
+
default: rb_scan_args( argc, argv, "01", NULL );
|
525
|
+
}
|
526
|
+
|
527
|
+
if (cnt != 0) {
|
528
|
+
ws2811_led_t *ptr = channel.leds;
|
529
|
+
int len = channel.count;
|
530
|
+
cnt = (cnt < 0) ? (len - (~cnt % len) - 1) : (cnt % len);
|
531
|
+
|
532
|
+
if (len > 0 && cnt > 0) {
|
533
|
+
--len;
|
534
|
+
if (cnt < len) pp_leds_reverse( ptr + cnt, ptr + len );
|
535
|
+
if (--cnt > 0) pp_leds_reverse( ptr, ptr + cnt );
|
536
|
+
if (len > 0) pp_leds_reverse( ptr, ptr + len );
|
537
|
+
}
|
538
|
+
}
|
539
|
+
|
540
|
+
return self;
|
541
|
+
}
|
542
|
+
|
543
|
+
/* call-seq:
|
544
|
+
* fill( color )
|
545
|
+
* fill( color, start [, length] )
|
546
|
+
* fill( color, range )
|
547
|
+
* fill { |index| block }
|
548
|
+
* fill( start [, length] ) { |index| block }
|
549
|
+
* fill( range ) { |index| block }
|
550
|
+
*
|
551
|
+
* Set the selected LEDs to the given `color`. The `color` msut be given as a
|
552
|
+
* 24-bit RGB value. You can also supply a block that receives an LED index and
|
553
|
+
* returns a 24-bit RGB color.
|
554
|
+
*
|
555
|
+
* Examples:
|
556
|
+
* leds.fill( 0x00FF00 )
|
557
|
+
* leds.fill( 0xFF0000, 2, 2 )
|
558
|
+
* leds.fill( 0x0000FF, (4...8) )
|
559
|
+
* leds.fill { |i| 256 << i }
|
560
|
+
*
|
561
|
+
* Returns this PixelPi::Leds instance.
|
562
|
+
*/
|
563
|
+
static VALUE
|
564
|
+
pp_leds_fill( int argc, VALUE* argv, VALUE self )
|
565
|
+
{
|
566
|
+
ws2811_t *ledstring = pp_leds_struct( self );
|
567
|
+
ws2811_channel_t channel = ledstring->channel[0];
|
568
|
+
ws2811_led_t color = 0;
|
569
|
+
|
570
|
+
VALUE item, arg1, arg2, v;
|
571
|
+
long ii, beg = 0, end = 0, len = 0;
|
572
|
+
int block_p = 0;
|
573
|
+
|
574
|
+
if (rb_block_given_p()) {
|
575
|
+
block_p = 1;
|
576
|
+
rb_scan_args( argc, argv, "02", &arg1, &arg2 );
|
577
|
+
argc += 1;
|
578
|
+
} else {
|
579
|
+
rb_scan_args( argc, argv, "12", &item, &arg1, &arg2 );
|
580
|
+
color = FIX2UINT(item);
|
581
|
+
}
|
582
|
+
|
583
|
+
switch (argc) {
|
584
|
+
case 1:
|
585
|
+
beg = 0;
|
586
|
+
len = channel.count;
|
587
|
+
break;
|
588
|
+
case 2:
|
589
|
+
if (rb_range_beg_len(arg1, &beg, &len, channel.count, 1)) {
|
590
|
+
break;
|
591
|
+
}
|
592
|
+
/* fall through */
|
593
|
+
case 3:
|
594
|
+
beg = NIL_P(arg1) ? 0 : NUM2LONG(arg1);
|
595
|
+
if (beg < 0) {
|
596
|
+
beg = channel.count + beg;
|
597
|
+
if (beg < 0) beg = 0;
|
598
|
+
}
|
599
|
+
len = NIL_P(arg2) ? channel.count - beg : NUM2LONG(arg2);
|
600
|
+
break;
|
601
|
+
}
|
602
|
+
|
603
|
+
if (len < 0) return self;
|
604
|
+
|
605
|
+
end = beg + len;
|
606
|
+
end = MIN((long) channel.count, end);
|
607
|
+
|
608
|
+
for (ii=beg; ii<end; ii++) {
|
609
|
+
if (block_p) {
|
610
|
+
v = rb_yield(INT2NUM(ii));
|
611
|
+
color = FIX2UINT(v);
|
612
|
+
}
|
613
|
+
channel.leds[ii] = color;
|
614
|
+
}
|
615
|
+
|
616
|
+
return self;
|
617
|
+
}
|
618
|
+
|
418
619
|
/* call-seq:
|
419
620
|
* PixelPi::Color(red, green, blue) #=> 24-bit color
|
420
621
|
*
|
@@ -456,6 +657,11 @@ void Init_leds( )
|
|
456
657
|
rb_define_method( cLeds, "[]", pp_leds_get_pixel_color, 1 );
|
457
658
|
rb_define_method( cLeds, "[]=", pp_leds_set_pixel_color, 2 );
|
458
659
|
rb_define_method( cLeds, "set_pixel", pp_leds_set_pixel_color2, -1 );
|
660
|
+
rb_define_method( cLeds, "to_a", pp_leds_to_a, 0 );
|
661
|
+
rb_define_method( cLeds, "replace", pp_leds_replace, 1 );
|
662
|
+
rb_define_method( cLeds, "reverse", pp_leds_reverse_m, 0 );
|
663
|
+
rb_define_method( cLeds, "rotate", pp_leds_rotate, -1 );
|
664
|
+
rb_define_method( cLeds, "fill", pp_leds_fill, -1 );
|
459
665
|
|
460
666
|
rb_define_module_function( mPixelPi, "Color", pp_color, 3 );
|
461
667
|
|
data/lib/pixel_pi/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pixel_pi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Pease
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|