Pixie Chroma
Documentation for the easiest 5x7 LED displays for Arduino!
pixie_chroma_internal.cpp
Go to the documentation of this file.
1
10// TODO: Make print() and write() calls allocate proper char array size
11// ...for each variable type, instead of just 32 chars no matter the type.
12
13#include "Pixie_Chroma.h"
15
16// ---------------------------------------------------------------------------------------------------------|
17// -- PUBLIC CLASS FUNCTIONS -------------------------------------------------------------------------------|
18// ---------------------------------------------------------------------------------------------------------|
19
20//............................................................................
37
38// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39// %% FUNCTIONS - SETUP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41//............................................................................
84void PixieChroma::begin( const uint8_t data_pin, uint8_t pixies_x, uint8_t pixies_y ){
85 pixie_pin = data_pin;
86
87 chars_x = (pixies_x+1) * 2; // Pixies have two chars each, plus deadzone for scrolling
88 chars_y = pixies_y;
89
90 matrix_width = display_width * chars_x;
91 matrix_height = display_height * chars_y;
92
94
95 color_map = new CRGB[ pixel_count + 1 ]; // Hidden extra LED to write to if we call an out-of-bounds XY coordinate for color or mask
96 mask = new uint8_t[ pixel_count + 1 ];
97 xy_table = new int16_t[ pixel_count ];
98
99 calc_xy(); // led_count is calculated here
100
101 color_map_out = new CRGB[ led_count ];
102 mask_out = new uint8_t[ led_count ];
103
104 for( uint16_t i = 0; i < pixel_count; i++ ){
105 color_map[i] = CRGB( 0, 255, 0 );
106 }
107
108 current_palette.loadDynamicGradientPalette( GREEN_SOLID );
109
110 build_controller( pixie_pin ); // ----- Initialize FastLED
111 set_color_animation( ANIMATION_NULL ); // --- Set animation function to an empty one
112 clear(); // --------------------------- Clear anything in mask (should be empty anyways), reset cursor
113 set_max_power( 5.0, 500 ); // --------- Set default power budget in volts and milliamps (5.0V, 500mA)
114}
115//............................................................................
213void PixieChroma::begin_quad( uint8_t pixies_per_pin, uint8_t pixies_x, uint8_t pixies_y ){
214 chars_x = (pixies_x+1) * 2; // Pixies have two chars each, plus deadzone for scrolling
215 chars_y = pixies_y;
216
217 matrix_width = display_width * chars_x;
218 matrix_height = display_height * chars_y;
219
221
222 color_map = new CRGB[ pixel_count + 1 ]; // Hidden extra LED to write to if we call an out-of-bounds XY coordinate for color or mask
223 mask = new uint8_t[ pixel_count + 1 ];
224 xy_table = new int16_t[ pixel_count ];
225
226 calc_xy();
227
228 color_map_out = new CRGB[ led_count ];
229 mask_out = new uint8_t[ led_count ];
230
231 for( uint16_t i = 0; i < led_count; i++ ){
232 color_map[i] = CRGB( 0,255,0 );
233 }
234
235 current_palette.loadDynamicGradientPalette( GREEN_SOLID );
236
237 #if defined( ARDUINO_ARCH_ESP8266 )
238 // WS2811_PORTA on ESP8266 takes up GPIO 12, GPIO 13, GPIO 14 and GPIO 15 for Quad Mode
239 FastLED.addLeds<WS2811_PORTA,4>( color_map_out, pixies_per_pin * leds_per_pixie ).setCorrection( TypicalLEDStrip ); // Initialize FastLED
240
241 #elif defined( ARDUINO_ARCH_ESP32 )
242 // Quad Mode on ESP32 takes up GPIO 12, GPIO 13, GPIO 14 and GPIO 27
243 FastLED.addLeds<NEOPIXEL, 13>( // Initialize FastLED Data Out 1
244 color_map_out,
245 ( pixies_per_pin*leds_per_pixie ) * 0,
246 ( pixies_per_pin*leds_per_pixie )
247 ).setCorrection( TypicalLEDStrip );
248
249 FastLED.addLeds<NEOPIXEL, 12>( // Initialize FastLED Data Out 2
250 color_map_out,
251 ( pixies_per_pin*leds_per_pixie ) * 1,
252 ( pixies_per_pin*leds_per_pixie )
253 ).setCorrection( TypicalLEDStrip );
254
255 FastLED.addLeds<NEOPIXEL, 14>( // Initialize FastLED Data Out 3
256 color_map_out,
257 ( pixies_per_pin*leds_per_pixie ) * 2,
258 ( pixies_per_pin*leds_per_pixie )
259 ).setCorrection( TypicalLEDStrip );
260
261 FastLED.addLeds<NEOPIXEL, 27>( // Initialize FastLED Data Out 4
262 color_map_out,
263 ( pixies_per_pin*leds_per_pixie ) * 3,
264 ( pixies_per_pin*leds_per_pixie )
265 ).setCorrection( TypicalLEDStrip );
266
267 #elif defined( ARDUINO_ARCH_TEENSY_3_X )
268 // WS2811_PORTD on TEENSY 3.X takes up GPIO 2, GPIO 14, GPIO 7 and GPIO 8 for Quad Mode
269 FastLED.addLeds<WS2811_PORTD,4>( color_map_out, pixies_per_pin * leds_per_pixie ).setCorrection( TypicalLEDStrip ); // Initialize FastLED
270 #endif
271
272 set_color_animation( ANIMATION_NULL ); // --- Set animation function to an empty one
273 clear(); // --------------------------- Clear anything in mask ( should be empty anyways ), reset cursor
274 set_max_power( 5, 500 ); // ----------- Set default power budget in volts and milliamps
275}
276
277//............................................................................
287void PixieChroma::set_color_animation( void ( *action )(PixieChroma*, float) ) {
288 anim_func = action;
290 custom_animation = false;
291 }
292 else{
293 custom_animation = true;
294 }
295 clear();
296 show();
297}
298
299//............................................................................
308 animation_speed = speed;
309}
310
311//............................................................................
319void PixieChroma::set_brightness( uint8_t level ){
320 brightness_level = level;
321}
322
323//............................................................................
342 fps_target = target;
343}
344
345//............................................................................
354 correct_gamma = enabled;
355}
356
357//............................................................................
366void PixieChroma::set_justification( t_justification justification, int16_t row ){
367 if(row == -1){
368 for(uint8_t i = 0; i < chars_y; i++){
369 justifications[i] = justification;
370 }
371 }
372 else{
373 justifications[row] = justification;
374 }
375}
376
377//............................................................................
388void PixieChroma::set_line_wrap( bool enabled ){
389 line_wrap = enabled;
390}
391
392//............................................................................
407void PixieChroma::set_max_power( float volts, uint16_t milliamps ){
408 max_V = volts;
409 max_mA = milliamps;
410}
411
412//............................................................................
432void PixieChroma::set_palette( const uint8_t* pal ){
433 if(custom_animation == false){
435 }
436 current_palette.loadDynamicGradientPalette( pal ); // GRADIENT PALETTE
437 clear();
438 show();
439}
440
441//............................................................................
449void PixieChroma::set_palette( CRGBPalette16 pal ){ // STANDARD PALETTE
450 if(custom_animation == false){
452 }
453 current_palette = pal;
454 clear();
455 show();
456}
457
458//............................................................................
470 scroll_type = type;
471
472 if(scroll_type == INSTANT){
473 scroll_frame_delay_ms = 0;
474 scroll_hold_ms = 150;
475 }
476 else if(scroll_type == SHIFT){
477 scroll_frame_delay_ms = 10;
478 scroll_hold_ms = 80;
479 }
480 else if(scroll_type == SMOOTH){
481 scroll_frame_delay_ms = 10;
482 scroll_hold_ms = 0;
483 }
484}
485
486//............................................................................
510 if( mode == AUTOMATIC && ticker_running == false ){
512
513 #if defined( ARDUINO_ARCH_ESP8266 ) || defined( ARDUINO_ARCH_ESP32 )
514 animate.attach_ms<typeof this>(
515 round(1000 / float(FPS)),
516 [](typeof this _p){ _p->show(); },
517 // This. ^ This is the magic sauce
518 // right here. This is apparently how
519 // you add a non-static class member to
520 // Ticker from within a class and I
521 // hate it. Readability sucks, oh well.
522 // At least I got a Lambdaghini.
523 this
524 );
525 #elif defined( ARDUINO_ARCH_TEENSY_3_X )
526 animate.begin(
527 [](typeof this _p){ _p->show(); },
528 round(1000000 / float(FPS))
529 );
530 animate.priority(1);
531 #endif
532
533 ticker_running = true;
534 }
535 else if( mode == MANUAL && ticker_running == true ){
536 #if defined( ARDUINO_ARCH_ESP8266 ) || defined( ARDUINO_ARCH_ESP32 )
537 animate.detach();
538 #elif defined( ARDUINO_ARCH_TEENSY_3_X )
539 animate.end();
540 #endif
541 ticker_running = false;
542 }
543}
544
545
546// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
547// %% FUNCTIONS - WRITE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
548// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
549//............................................................................
562void PixieChroma::add_char( char chr, int16_t x_dest, int16_t y_dest ){
563 color(print_col, x_dest/display_width, y_dest/display_height);
564
565 if ( chr >= printable_ascii_offset ) {
567 }
568
569 for( uint8_t x = 0; x < font_col_width; x++ ){
570 uint8_t column = pgm_read_byte( font + ( chr * font_col_width + x ) );
571
572 uint16_t row1_index = xy( x_dest+x, y_dest+0 );
573 uint16_t row2_index = xy( x_dest+x, y_dest+1 );
574 uint16_t row3_index = xy( x_dest+x, y_dest+2 );
575 uint16_t row4_index = xy( x_dest+x, y_dest+3 );
576 uint16_t row5_index = xy( x_dest+x, y_dest+4 );
577 uint16_t row6_index = xy( x_dest+x, y_dest+5 );
578 uint16_t row7_index = xy( x_dest+x, y_dest+6 );
579
580 // "Subtract" from mask transparency with saturating function
581 mask[row1_index] = qadd8( mask[row1_index], bit_table[bitRead( column, 0 )] );
582 mask[row2_index] = qadd8( mask[row2_index], bit_table[bitRead( column, 1 )] );
583 mask[row3_index] = qadd8( mask[row3_index], bit_table[bitRead( column, 2 )] );
584 mask[row4_index] = qadd8( mask[row4_index], bit_table[bitRead( column, 3 )] );
585 mask[row5_index] = qadd8( mask[row5_index], bit_table[bitRead( column, 4 )] );
586 mask[row6_index] = qadd8( mask[row6_index], bit_table[bitRead( column, 5 )] );
587 mask[row7_index] = qadd8( mask[row7_index], bit_table[bitRead( column, 6 )] );
588 }
589}
590
591//............................................................................
604void PixieChroma::add_char( uint8_t bitmap_col_1, uint8_t bitmap_col_2, uint8_t bitmap_col_3, uint8_t bitmap_col_4, uint8_t bitmap_col_5, int16_t x_dest, int16_t y_dest ){
605 uint16_t row1_index;
606 uint16_t row2_index;
607 uint16_t row3_index;
608 uint16_t row4_index;
609 uint16_t row5_index;
610 uint16_t row6_index;
611 uint16_t row7_index;
612
613 // COLUMN 1 --------------------------------------------------------------------------------------------------------------
614 row1_index = xy( x_dest+0, y_dest+0 ); mask[row1_index] = qadd8( mask[row1_index], bit_table[bitRead( bitmap_col_1,0 )] );
615 row2_index = xy( x_dest+0, y_dest+1 ); mask[row2_index] = qadd8( mask[row2_index], bit_table[bitRead( bitmap_col_1,1 )] );
616 row3_index = xy( x_dest+0, y_dest+2 ); mask[row3_index] = qadd8( mask[row3_index], bit_table[bitRead( bitmap_col_1,2 )] );
617 row4_index = xy( x_dest+0, y_dest+3 ); mask[row4_index] = qadd8( mask[row4_index], bit_table[bitRead( bitmap_col_1,3 )] );
618 row5_index = xy( x_dest+0, y_dest+4 ); mask[row5_index] = qadd8( mask[row5_index], bit_table[bitRead( bitmap_col_1,4 )] );
619 row6_index = xy( x_dest+0, y_dest+5 ); mask[row6_index] = qadd8( mask[row6_index], bit_table[bitRead( bitmap_col_1,5 )] );
620 row7_index = xy( x_dest+0, y_dest+6 ); mask[row7_index] = qadd8( mask[row7_index], bit_table[bitRead( bitmap_col_1,6 )] );
621
622 // COLUMN 2 --------------------------------------------------------------------------------------------------------------
623 row1_index = xy( x_dest+1, y_dest+0 ); mask[row1_index] = qadd8( mask[row1_index], bit_table[bitRead( bitmap_col_2,0 )] );
624 row2_index = xy( x_dest+1, y_dest+1 ); mask[row2_index] = qadd8( mask[row2_index], bit_table[bitRead( bitmap_col_2,1 )] );
625 row3_index = xy( x_dest+1, y_dest+2 ); mask[row3_index] = qadd8( mask[row3_index], bit_table[bitRead( bitmap_col_2,2 )] );
626 row4_index = xy( x_dest+1, y_dest+3 ); mask[row4_index] = qadd8( mask[row4_index], bit_table[bitRead( bitmap_col_2,3 )] );
627 row5_index = xy( x_dest+1, y_dest+4 ); mask[row5_index] = qadd8( mask[row5_index], bit_table[bitRead( bitmap_col_2,4 )] );
628 row6_index = xy( x_dest+1, y_dest+5 ); mask[row6_index] = qadd8( mask[row6_index], bit_table[bitRead( bitmap_col_2,5 )] );
629 row7_index = xy( x_dest+1, y_dest+6 ); mask[row7_index] = qadd8( mask[row7_index], bit_table[bitRead( bitmap_col_2,6 )] );
630
631 // COLUMN 3 --------------------------------------------------------------------------------------------------------------
632 row1_index = xy( x_dest+2, y_dest+0 ); mask[row1_index] = qadd8( mask[row1_index], bit_table[bitRead( bitmap_col_3,0 )] );
633 row2_index = xy( x_dest+2, y_dest+1 ); mask[row2_index] = qadd8( mask[row2_index], bit_table[bitRead( bitmap_col_3,1 )] );
634 row3_index = xy( x_dest+2, y_dest+2 ); mask[row3_index] = qadd8( mask[row3_index], bit_table[bitRead( bitmap_col_3,2 )] );
635 row4_index = xy( x_dest+2, y_dest+3 ); mask[row4_index] = qadd8( mask[row4_index], bit_table[bitRead( bitmap_col_3,3 )] );
636 row5_index = xy( x_dest+2, y_dest+4 ); mask[row5_index] = qadd8( mask[row5_index], bit_table[bitRead( bitmap_col_3,4 )] );
637 row6_index = xy( x_dest+2, y_dest+5 ); mask[row6_index] = qadd8( mask[row6_index], bit_table[bitRead( bitmap_col_3,5 )] );
638 row7_index = xy( x_dest+2, y_dest+6 ); mask[row7_index] = qadd8( mask[row7_index], bit_table[bitRead( bitmap_col_3,6 )] );
639
640 // COLUMN 4 --------------------------------------------------------------------------------------------------------------
641 row1_index = xy( x_dest+3, y_dest+0 ); mask[row1_index] = qadd8( mask[row1_index], bit_table[bitRead( bitmap_col_4,0 )] );
642 row2_index = xy( x_dest+3, y_dest+1 ); mask[row2_index] = qadd8( mask[row2_index], bit_table[bitRead( bitmap_col_4,1 )] );
643 row3_index = xy( x_dest+3, y_dest+2 ); mask[row3_index] = qadd8( mask[row3_index], bit_table[bitRead( bitmap_col_4,2 )] );
644 row4_index = xy( x_dest+3, y_dest+3 ); mask[row4_index] = qadd8( mask[row4_index], bit_table[bitRead( bitmap_col_4,3 )] );
645 row5_index = xy( x_dest+3, y_dest+4 ); mask[row5_index] = qadd8( mask[row5_index], bit_table[bitRead( bitmap_col_4,4 )] );
646 row6_index = xy( x_dest+3, y_dest+5 ); mask[row6_index] = qadd8( mask[row6_index], bit_table[bitRead( bitmap_col_4,5 )] );
647 row7_index = xy( x_dest+3, y_dest+6 ); mask[row7_index] = qadd8( mask[row7_index], bit_table[bitRead( bitmap_col_4,6 )] );
648
649 // COLUMN 5 --------------------------------------------------------------------------------------------------------------
650 row1_index = xy( x_dest+4, y_dest+0 ); mask[row1_index] = qadd8( mask[row1_index], bit_table[bitRead( bitmap_col_5,0 )] );
651 row2_index = xy( x_dest+4, y_dest+1 ); mask[row2_index] = qadd8( mask[row2_index], bit_table[bitRead( bitmap_col_5,1 )] );
652 row3_index = xy( x_dest+4, y_dest+2 ); mask[row3_index] = qadd8( mask[row3_index], bit_table[bitRead( bitmap_col_5,2 )] );
653 row4_index = xy( x_dest+4, y_dest+3 ); mask[row4_index] = qadd8( mask[row4_index], bit_table[bitRead( bitmap_col_5,3 )] );
654 row5_index = xy( x_dest+4, y_dest+4 ); mask[row5_index] = qadd8( mask[row5_index], bit_table[bitRead( bitmap_col_5,4 )] );
655 row6_index = xy( x_dest+4, y_dest+5 ); mask[row6_index] = qadd8( mask[row6_index], bit_table[bitRead( bitmap_col_5,5 )] );
656 row7_index = xy( x_dest+4, y_dest+6 ); mask[row7_index] = qadd8( mask[row7_index], bit_table[bitRead( bitmap_col_5,6 )] );
657}
658
659//............................................................................
694void PixieChroma::write( uint8_t bitmap_col_1, uint8_t bitmap_col_2, uint8_t bitmap_col_3, uint8_t bitmap_col_4, uint8_t bitmap_col_5, uint8_t x_pos, uint8_t y_pos ){
695 write_pix( bitmap_col_1, bitmap_col_2, bitmap_col_3, bitmap_col_4, bitmap_col_5, x_pos, y_pos );
696}
697
698//............................................................................
707void PixieChroma::write( char* message, uint8_t x_pos, uint8_t y_pos ){
708 write_pix(
709 message,
710 display_padding_x + ( display_width * x_pos ),
711 display_padding_y + ( display_height * y_pos )
712 );
713}
714
715//............................................................................
724void PixieChroma::write( int16_t input, uint8_t x_pos, uint8_t y_pos ){
725 char char_buf[32];
726 itoa( input, char_buf, 10 );
727
728 write_pix(
729 char_buf,
730 display_padding_x + ( display_width * x_pos ),
731 display_padding_y + ( display_height * y_pos )
732 );
733}
734
735//............................................................................
744void PixieChroma::write( uint16_t input, uint8_t x_pos, uint8_t y_pos ){
745 char char_buf[32];
746 utoa( input, char_buf, 10 );
747
748 write_pix(
749 char_buf,
750 display_padding_x + ( display_width * x_pos ),
751 display_padding_y + ( display_height * y_pos )
752 );
753}
754
755//............................................................................
764void PixieChroma::write( int32_t input, uint8_t x_pos, uint8_t y_pos ){
765 char char_buf[32];
766 ltoa( input, char_buf, 10 );
767
768 write_pix(
769 char_buf,
770 display_padding_x + ( display_width * x_pos ),
771 display_padding_y + ( display_height * y_pos )
772 );
773}
774
775//............................................................................
784void PixieChroma::write( uint32_t input, uint8_t x_pos, uint8_t y_pos ){
785 char char_buf[32];
786 ultoa( input, char_buf, 10 );
787
788 write_pix(
789 char_buf,
790 display_padding_x + ( display_width * x_pos ),
791 display_padding_y + ( display_height * y_pos )
792 );
793}
794
795//............................................................................
805#ifndef ARDUINO_ARCH_TEENSY_3_X
806void PixieChroma::write( long unsigned int input, uint8_t x_pos, uint8_t y_pos ){
807 char char_buf[32];
808 ultoa( input, char_buf, 10 );
809
810 write_pix(
811 char_buf,
812 display_padding_x + ( display_width * x_pos ),
813 display_padding_y + ( display_height * y_pos )
814 );
815}
816#endif
817
818//............................................................................
829void PixieChroma::write( float input, uint8_t places, uint8_t x_pos, uint8_t y_pos ){
830 write(
831 double( input ),
832 places,
833 x_pos,
834 y_pos
835 );
836}
837
838//............................................................................
849void PixieChroma::write( double input, uint8_t places, uint8_t x_pos, uint8_t y_pos ){
850 char char_buf[32];
851 dtoa( input, char_buf, places );
852
853 write_pix(
854 char_buf,
855 display_padding_x + ( display_width * x_pos ),
856 display_padding_y + ( display_height * y_pos )
857 );
858}
859
860//............................................................................
875void PixieChroma::write_pix( char* message, int16_t x_dest, int16_t y_dest ){
876 int16_t offset_x = 0;
877 int16_t offset_y = 0;
878
879 just_wrapped = false;
880
881 uint8_t len = strlen( message );
882 for( uint8_t i = 0; i < len; i++ ){
883 if( message[i] == '\n' ){ // Newline, force line break
884 if(just_wrapped == true){
885 just_wrapped = false;
886 // Skip newline, auto wrapping just newline'd for us.
887 }
888 else{
889 x_dest = extra_space_left+display_padding_x;
890 offset_x = 0;
891 offset_y = display_height;
892 }
893 }
894 else if( line_wrap == true && x_dest+offset_x+display_width >= (matrix_width) ){ // End of line reached, wrap to new line if line_wrap enabled
895 add_char(
896 message[i],
897 x_dest + offset_x,
898 y_dest + offset_y
899 );
900 offset_x += display_width;
901
902 x_dest = extra_space_left+display_padding_x;
903 offset_x = 0;
904 offset_y = display_height;
905
906 just_wrapped = true;
907 }
908 else if( message[i] == 0 || message[i] == '\0' ){ // end of string
909 return;
910 }
911 else{ // Normal char
912 add_char(
913 message[i],
914 x_dest + offset_x,
915 y_dest + offset_y
916 );
917 offset_x += display_width;
918 }
919 }
920
921 cursor_x_temp = x_dest+offset_x;
922 cursor_y_temp = y_dest+offset_y;
923}
924
925//............................................................................
942void PixieChroma::write_pix( uint8_t bitmap_col_1, uint8_t bitmap_col_2, uint8_t bitmap_col_3, uint8_t bitmap_col_4, uint8_t bitmap_col_5, int16_t x_dest, int16_t y_dest ){
943 int16_t offset_x = 0;
944 int16_t offset_y = 0;
945
946 if( line_wrap == true && x_dest+offset_x >= ( display_width * chars_x ) ){ // End of line reached, wrap to new line if line_wrap enabled
947 x_dest = display_padding_x;
948 offset_x = 0;
949 offset_y = display_height;
950 }
951
952 add_char(
953 bitmap_col_1,
954 bitmap_col_2,
955 bitmap_col_3,
956 bitmap_col_4,
957 bitmap_col_5,
958 x_dest + offset_x,
959 y_dest + offset_y
960 );
961 offset_x += display_width;
962
963
964 cursor_x_temp = x_dest+offset_x;
965 cursor_y_temp = y_dest+offset_y;
966}
967
968
969// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
970// %% FUNCTIONS - PRINT %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
971// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
972//............................................................................
1005void PixieChroma::print( uint8_t bitmap_col_1, uint8_t bitmap_col_2, uint8_t bitmap_col_3, uint8_t bitmap_col_4, uint8_t bitmap_col_5 ){
1006 cursor_x_temp = cursor_x;
1007 cursor_y_temp = cursor_y;
1008
1009 write_pix( bitmap_col_1, bitmap_col_2, bitmap_col_3, bitmap_col_4, bitmap_col_5, cursor_x, cursor_y );
1010
1011 // Store cursor changes
1012 cursor_x = cursor_x_temp;
1013 cursor_y = cursor_y_temp;
1014}
1015
1016//............................................................................
1023void PixieChroma::print( char chr ){
1024 if(chr != '\n'){
1025 add_char(
1026 chr,
1027 cursor_x,
1028 cursor_y
1029 );
1030
1031 cursor_x += display_width;
1032
1033 if(line_wrap && cursor_x >= ( display_width * chars_x ) ){
1034 cursor_x = extra_space_left+display_padding_x;
1035 cursor_y += display_height;
1036 just_wrapped = true;
1037 }
1038 }
1039 else{
1040 if(just_wrapped == false){
1041 cursor_x = extra_space_left+display_padding_x;
1042 cursor_y += display_height;
1043 }
1044 else{
1045 just_wrapped = false;
1046 }
1047 }
1048}
1049
1050//............................................................................
1064void PixieChroma::print( char* message ){
1065 uint16_t len = strlen(message);
1066 uint16_t i = 0;
1067 while (i < len - 1) {
1068 if (message[i] == '[' && message[i + 1] == ':') { // Found start of shortcode
1069 for (uint16_t j = i; j < len - 1; j++) {
1070 if (message[j] == ':' && message[j + 1] == ']') { // Found end of shortcode
1071 fetch_shortcode( message, i + 2, j );
1072 i = j + 2;
1073 break;
1074 }
1075 }
1076 }
1077 else {
1078 print(message[i]);
1079 i += 1;
1080 }
1081 }
1082
1083 if(message[len-1] != ']'){ // If message doesn't end with shortcode
1084 print( message[len-1] );
1085 }
1086}
1087
1088//............................................................................
1096void PixieChroma::print( int16_t input ){
1097 char char_buf[32];
1098 itoa( input, char_buf, 10 );
1099 write_pix( char_buf, cursor_x, cursor_y );
1100
1101 // Store cursor changes
1102 cursor_x = cursor_x_temp;
1103 cursor_y = cursor_y_temp;
1104}
1105
1106//............................................................................
1114void PixieChroma::print( uint16_t input ){
1115 char char_buf[32];
1116 utoa( input, char_buf, 10 );
1117 write_pix( char_buf, cursor_x, cursor_y );
1118
1119 // Store cursor changes
1120 cursor_x = cursor_x_temp;
1121 cursor_y = cursor_y_temp;
1122}
1123
1124//............................................................................
1132void PixieChroma::print( int32_t input ){
1133 char char_buf[32];
1134 ltoa( input, char_buf, 10 );
1135 write_pix( char_buf, cursor_x, cursor_y );
1136
1137 // Store cursor changes
1138 cursor_x = cursor_x_temp;
1139 cursor_y = cursor_y_temp;
1140}
1141
1142//............................................................................
1150void PixieChroma::print( uint32_t input ){
1151 char char_buf[32];
1152 ultoa( input, char_buf, 10 );
1153 write_pix( char_buf, cursor_x, cursor_y );
1154
1155 // Store cursor changes
1156 cursor_x = cursor_x_temp;
1157 cursor_y = cursor_y_temp;
1158}
1159
1160//............................................................................
1168#ifndef ARDUINO_ARCH_TEENSY_3_X
1169void PixieChroma::print( long unsigned int input ){
1170 char char_buf[32];
1171 ultoa( input, char_buf, 10 );
1172 write_pix( char_buf, cursor_x, cursor_y );
1173
1174 // Store cursor changes
1175 cursor_x = cursor_x_temp;
1176 cursor_y = cursor_y_temp;
1177}
1178#endif
1179
1180//............................................................................
1189void PixieChroma::print( float input, uint8_t places ){
1190 print( double( input ), places );
1191
1192 // Store cursor changes
1193 cursor_x = cursor_x_temp;
1194 cursor_y = cursor_y_temp;
1195}
1196
1197//............................................................................
1206void PixieChroma::print( double input, uint8_t places ){
1207 char char_buf[32];
1208 dtoa( input, char_buf, places );
1209 write_pix( char_buf, cursor_x, cursor_y );
1210
1211 // Store cursor changes
1212 cursor_x = cursor_x_temp;
1213 cursor_y = cursor_y_temp;
1214}
1215
1216
1217// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1218// %% FUNCTIONS - PRINTLN %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1219// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1220//............................................................................
1233void PixieChroma::println( uint8_t bitmap_col_1, uint8_t bitmap_col_2, uint8_t bitmap_col_3, uint8_t bitmap_col_4, uint8_t bitmap_col_5 ){
1234 print( bitmap_col_1, bitmap_col_2, bitmap_col_3, bitmap_col_4, bitmap_col_5 );
1235 print('\n');
1236}
1237
1238//............................................................................
1254void PixieChroma::println( char* message ){
1255 print(message);
1256 print('\n');
1257}
1258
1259//............................................................................
1268void PixieChroma::println( int16_t input ){
1269 print( input );
1270 print('\n');
1271}
1272
1273//............................................................................
1282void PixieChroma::println( uint16_t input ){
1283 print( input );
1284 print('\n');
1285}
1286
1287//............................................................................
1296void PixieChroma::println( int32_t input ){
1297 print( input );
1298 print('\n');
1299}
1300
1301//............................................................................
1310void PixieChroma::println( uint32_t input ){
1311 print( input );
1312 print('\n');
1313}
1314
1315//............................................................................
1324#ifndef ARDUINO_ARCH_TEENSY_3_X
1325void PixieChroma::println( long unsigned int input ){
1326 print( input );
1327 print('\n');
1328}
1329#endif
1330
1331//............................................................................
1342void PixieChroma::println( float input, uint8_t places ){
1343 println( double(input), places );
1344}
1345
1346//............................................................................
1357void PixieChroma::println( double input, uint8_t places ){
1358 print( input, places );
1359 print('\n');
1360}
1361
1362
1363// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1364// %% FUNCTIONS - CURSOR %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1365// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1366//............................................................................
1374 return cursor_x / display_width;
1375}
1376
1377//............................................................................
1385 return cursor_x;
1386}
1387
1388//............................................................................
1396 return cursor_y / display_height;
1397}
1398
1399//............................................................................
1407 return cursor_y;
1408}
1409
1410//............................................................................
1456void PixieChroma::set_cursor( uint8_t x_position, uint8_t y_position ){
1457 cursor_x = extra_space_left + display_padding_x + ( display_width * x_position );
1458 cursor_y = display_padding_y + ( display_height * y_position );
1459}
1460
1461
1462// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1463// %% FUNCTIONS - UPDATING THE MASK / LEDS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1464// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1465
1466//............................................................................
1472 memset( mask, 0, pixel_count );
1473 set_cursor( 0, 0 );
1474}
1475
1476//............................................................................
1483 freeze = false;
1484}
1485
1486//............................................................................
1495 freeze = true;
1496}
1497
1498//............................................................................
1508 uint32_t t_now = micros();
1509 float frame_delta_us = t_now-t_last;
1510 frame_rate = 1000000.0 / frame_delta_us;
1511 delta = fps_target / frame_rate;
1512 t_last = t_now;
1513
1514 anim_func( this, delta ); // Call custom animation function
1515
1516 noInterrupts();
1517
1518 for(uint8_t i = 0; i < chars_y; i++){
1519 if(scrolling[i] == false){
1520 int16_t x_offset = calc_justification(justifications[i], i);
1521 shift_mask_x( x_offset, i);
1522 if( custom_animation == false ){
1523 shift_color_map_x( x_offset, i);
1524 }
1525 }
1526 }
1527
1528 if( !freeze ){ // If we're not holding out for a pix.free() call, show with the current mask
1529 memcpy( mask_out, mask, led_count );
1530 }
1531
1532 memcpy( color_map_out, color_map, sizeof( CRGB )*led_count );
1533
1534 for( uint16_t i = 0; i < led_count; i++ ){
1535 // MASKING
1536 color_map_out[i].fadeLightBy( 255-mask_out[i] ); // Apply mask "over" LED color layer
1537
1538 // GAMMA CORRECTION
1539 if( correct_gamma ){
1540 color_map_out[i].r = gamma8[ color_map_out[i].r ]; // Apply gamma correction LUT
1541 color_map_out[i].g = gamma8[ color_map_out[i].g ];
1542 color_map_out[i].b = gamma8[ color_map_out[i].b ];
1543 }
1544 }
1545
1546 // Regulate brightness to keep power within budget set with pix.set_max_power( V, mA );
1547 FastLED.setBrightness( calculate_max_brightness_for_power_vmA( color_map_out, led_count, brightness_level, max_V, max_mA ) );
1548 FastLED.show();
1549
1550 interrupts();
1551}
1552//............................................................................
1561void PixieChroma::delay(uint32_t milliseconds){
1562 FastLED.delay( milliseconds );
1563}
1564
1565// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1566// %% FUNCTIONS - COLOR %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1567// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1568//............................................................................
1582void PixieChroma::color( CRGB col ){
1583 print_col = col;
1584 fill_solid( color_map, pixel_count, col );
1585}
1586
1587//............................................................................
1604void PixieChroma::color( CRGB col, uint8_t x, uint8_t y ){
1605 int16_t x_pos = x * display_width + display_padding_x;
1606 int16_t y_pos = y * display_height + display_padding_y;
1607
1608 for( uint8_t xi = 0; xi < font_col_width; xi++ ){
1609 color_map[xy( x_pos+xi, y_pos+0 )] = col;
1610 color_map[xy( x_pos+xi, y_pos+1 )] = col;
1611 color_map[xy( x_pos+xi, y_pos+2 )] = col;
1612 color_map[xy( x_pos+xi, y_pos+3 )] = col;
1613 color_map[xy( x_pos+xi, y_pos+4 )] = col;
1614 color_map[xy( x_pos+xi, y_pos+5 )] = col;
1615 color_map[xy( x_pos+xi, y_pos+6 )] = col;
1616 }
1617}
1618
1619//............................................................................
1638void PixieChroma::color( CRGB col, int16_t x1, int16_t y1, int16_t x2, int16_t y2 ){
1639 // Make rectangle selection inclusive
1640 x2 += 1;
1641 y2 += 1;
1642
1643 if( x2 < x1 ){
1644 uint8_t x_temp = x2;
1645 x2 = x1;
1646 x1 = x_temp;
1647 }
1648 if( y2 < y1 ){
1649 uint8_t y_temp = y2;
1650 y2 = y1;
1651 y1 = y_temp;
1652 }
1653
1654 uint16_t x_delta = x2 - x1;
1655 uint16_t y_delta = y2 - y1;
1656
1657 for( uint16_t y = 0; y < y_delta; y++ ){
1658 for( uint16_t x = 0; x < x_delta; x++ ){
1659 int16_t x2_pos = x1 + x;
1660 int16_t y2_pos = y1 + y;
1661 color_map[xy( x2_pos, y2_pos )] = col;
1662 }
1663 }
1664}
1665
1666//............................................................................
1679 print_col = col;
1680}
1681
1682//............................................................................
1704CRGB PixieChroma::kelvin_to_rgb( uint16_t temperature ){
1705 // Tanner Helland formula
1706 float _temperature;
1707 float _red;
1708 float _green;
1709 float _blue;
1710
1711 _temperature = constrain( temperature, 0, 65500 );
1712
1713 _red = _green = _blue = 0;
1714 float t = _temperature * 0.01;
1715
1716 if ( t <= 66 ){
1717 _red = 255;
1718 _green = ( 99.4708025861 * log( t ) ) - 161.1195681661;
1719 if ( t > 19 ){
1720 _blue = ( 138.5177312231 * log( t - 10 ) ) - 305.0447927307;
1721 }
1722 else{
1723 _blue = 0;
1724 }
1725 }
1726 else{
1727 _red = 329.698727466 * pow( t - 60, -0.1332047592 );
1728 _green = 288.1221695283 * pow( t - 60, -0.0755148492 );
1729 _blue = 255;
1730 }
1731
1732 float f = 0.01 * 100;
1733
1734 _red = constrain( f * _red, 0, 255 );
1735 _green = constrain( f * _green, 0, 255 );
1736 _blue = constrain( f * _blue, 0, 255 );
1737
1738 return CRGB( _red, _green, _blue );
1739}
1740
1741
1742// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1743// %% FUNCTIONS - MASK EFFECTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1745//............................................................................
1752void PixieChroma::blur( fract8 blur_amount ){
1753 blur_x( blur_amount );
1754 blur_y( blur_amount );
1755}
1756
1757//............................................................................
1764void PixieChroma::blur_x( fract8 blur_amount ){
1765 uint8_t keep = 255 - blur_amount;
1766 uint8_t seep = blur_amount >> 1;
1767 for( uint8_t row = 0; row < matrix_height; row++ ) {
1768 uint8_t carryover = 0;
1769 for( uint8_t i = 0; i < matrix_width; i++ ) {
1770 uint8_t cur = mask[xy( i,row )];
1771 uint8_t part = cur;
1772 part = scale8( part, seep );
1773 cur = scale8( cur, keep );
1774 cur = qadd8( cur,carryover );
1775 if( i ){
1776 mask[xy( i-1,row )] = qadd8( mask[xy( i-1,row )],part );
1777 }
1778 mask[xy( i,row )] = cur;
1779 carryover = part;
1780 }
1781 }
1782}
1783
1784//............................................................................
1791void PixieChroma::blur_y( fract8 blur_amount ){
1792 // blur columns
1793 uint8_t keep = 255 - blur_amount;
1794 uint8_t seep = blur_amount >> 1;
1795 for( uint8_t col = 0; col < matrix_width; ++col ) {
1796 uint8_t carryover = 0;
1797 for( uint8_t i = 0; i < matrix_height; ++i ) {
1798 uint8_t cur = mask[xy( col,i )];
1799 uint8_t part = cur;
1800 part = scale8( part, seep );
1801 cur = scale8( cur, keep );
1802 cur = qadd8( cur,carryover );
1803 if( i ){
1804 mask[xy( col,i-1 )] = qadd8( mask[xy( col,i-1 )],part );
1805 }
1806 mask[xy( col,i )] = cur;
1807 carryover = part;
1808 }
1809 }
1810}
1811
1812//............................................................................
1821void PixieChroma::dim( uint8_t amount, bool reset_cursor ){
1822 if( reset_cursor == true ){
1823 set_cursor( 0,0 );
1824 }
1825
1826 for( uint16_t i = 0; i < pixel_count; i+=11 ){
1827 mask[i+0] = scale8( mask[i+0], 255-amount );
1828 mask[i+1] = scale8( mask[i+1], 255-amount );
1829 mask[i+2] = scale8( mask[i+2], 255-amount );
1830 mask[i+3] = scale8( mask[i+3], 255-amount );
1831 mask[i+4] = scale8( mask[i+4], 255-amount );
1832 mask[i+5] = scale8( mask[i+5], 255-amount );
1833 mask[i+6] = scale8( mask[i+6], 255-amount );
1834 mask[i+7] = scale8( mask[i+7], 255-amount );
1835 mask[i+8] = scale8( mask[i+8], 255-amount );
1836 mask[i+9] = scale8( mask[i+9], 255-amount );
1837 mask[i+10] = scale8( mask[i+10], 255-amount );
1838 }
1839}
1840
1841
1842// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1843// %% FUNCTIONS - COLOR EFFECTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1844// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1845//............................................................................
1852void PixieChroma::color_blur( fract8 blur_amount ){
1853 color_blur_x( blur_amount );
1854 color_blur_y( blur_amount );
1855}
1856
1857//............................................................................
1864void PixieChroma::color_blur_x( fract8 blur_amount ){
1865 uint8_t keep = 255 - blur_amount;
1866 uint8_t seep = blur_amount >> 1;
1867 for( uint8_t row = 0; row < matrix_height; row++ ) {
1868 uint8_t carryover = 0;
1869 for( uint8_t i = 0; i < matrix_width; i++ ) {
1870 CRGB cur = color_map[xy( i,row )];
1871 CRGB part = cur;
1872 part.nscale8( seep );
1873 cur.nscale8( keep );
1874 cur += carryover;
1875 if( i ) color_map[xy( i-1,row )] += part;
1876 color_map[xy( i,row )] = cur;
1877 carryover = part;
1878 }
1879 }
1880}
1881
1882//............................................................................
1889void PixieChroma::color_blur_y( fract8 blur_amount ){
1890 // blur rows same as columns, for irregular matrix
1891 uint8_t keep = 255 - blur_amount;
1892 uint8_t seep = blur_amount >> 1;
1893 for( uint8_t row = 0; row < matrix_width; row++ ) {
1894 CRGB carryover = CRGB::Black;
1895 for( uint8_t i = 0; i < matrix_height; i++ ) {
1896 CRGB cur = color_map[xy( i,row )];
1897 CRGB part = cur;
1898 part.nscale8( seep );
1899 cur.nscale8( keep );
1900 cur += carryover;
1901 if( i ) color_map[xy( i-1,row )] += part;
1902 color_map[xy( i,row )] = cur;
1903 carryover = part;
1904 }
1905 }
1906}
1907
1908//............................................................................
1915void PixieChroma::color_dim( uint8_t amount ){
1916 CRGBSet leds_temp( color_map, pixel_count );
1917 leds_temp.fadeToBlackBy( amount );
1918}
1919
1920
1921// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1922// %% FUNCTIONS - 2D TOOLS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1923// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1924//............................................................................
1935void PixieChroma::draw_line_color( int16_t x1, int16_t y1, int16_t x2, int16_t y2, CRGB color ){
1936 //Bresenham's line algorithm
1937 uint16_t index;
1938
1939 int16_t x,y,dx,dy,dx1,dy1,px,py,xe,ye,i;
1940 dx=x2-x1;
1941 dy=y2-y1;
1942 dx1=fabs( dx );
1943 dy1=fabs( dy );
1944 px=2*dy1-dx1;
1945 py=2*dx1-dy1;
1946 if( dy1<=dx1 ){
1947 if( dx>=0 ){
1948 x=x1;
1949 y=y1;
1950 xe=x2;
1951 }
1952 else{
1953 x=x2;
1954 y=y2;
1955 xe=x1;
1956 }
1957 set_pixel_color( x, y, color );
1958 for( i=0;x<xe;i++ ){
1959 x=x+1;
1960 if( px<0 ){
1961 px=px+2*dy1;
1962 }
1963 else{
1964 if( ( dx<0 && dy<0 ) || ( dx>0 && dy>0 ) ){
1965 y=y+1;
1966 }
1967 else{
1968 y=y-1;
1969 }
1970 px=px+2*( dy1-dx1 );
1971 }
1972 set_pixel_color( x, y, color );
1973 }
1974 }
1975 else{
1976 if( dy>=0 ){
1977 x=x1;
1978 y=y1;
1979 ye=y2;
1980 }
1981 else{
1982 x=x2;
1983 y=y2;
1984 ye=y1;
1985 }
1986 set_pixel_color( x, y, color );
1987 for( i=0;y<ye;i++ ){
1988 y=y+1;
1989 if( py<=0 ){
1990 py=py+2*dx1;
1991 }
1992 else{
1993 if( ( dx<0 && dy<0 ) || ( dx>0 && dy>0 ) ){
1994 x=x+1;
1995 }
1996 else{
1997 x=x-1;
1998 }
1999 py=py+2*( dx1-dy1 );
2000 }
2001 set_pixel_color( x, y, color );
2002 }
2003 }
2004}
2005
2006//............................................................................
2017void PixieChroma::draw_line_mask( int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t value ){
2018 //Bresenham's line algorithm
2019 uint16_t index;
2020
2021 int16_t x,y,dx,dy,dx1,dy1,px,py,xe,ye,i;
2022 dx=x2-x1;
2023 dy=y2-y1;
2024 dx1=fabs( dx );
2025 dy1=fabs( dy );
2026 px=2*dy1-dx1;
2027 py=2*dx1-dy1;
2028 if( dy1<=dx1 ){
2029 if( dx>=0 ){
2030 x=x1;
2031 y=y1;
2032 xe=x2;
2033 }
2034 else{
2035 x=x2;
2036 y=y2;
2037 xe=x1;
2038 }
2039 set_pixel_mask( x, y, value );
2040 for( i=0;x<xe;i++ ){
2041 x=x+1;
2042 if( px<0 ){
2043 px=px+2*dy1;
2044 }
2045 else{
2046 if( ( dx<0 && dy<0 ) || ( dx>0 && dy>0 ) ){
2047 y=y+1;
2048 }
2049 else{
2050 y=y-1;
2051 }
2052 px=px+2*( dy1-dx1 );
2053 }
2054 set_pixel_mask( x, y, value );
2055 }
2056 }
2057 else{
2058 if( dy>=0 ){
2059 x=x1;
2060 y=y1;
2061 ye=y2;
2062 }
2063 else{
2064 x=x2;
2065 y=y2;
2066 ye=y1;
2067 }
2068 set_pixel_mask( x, y, value );
2069 for( i=0;y<ye;i++ ){
2070 y=y+1;
2071 if( py<=0 ){
2072 py=py+2*dx1;
2073 }
2074 else{
2075 if( ( dx<0 && dy<0 ) || ( dx>0 && dy>0 ) ){
2076 x=x+1;
2077 }
2078 else{
2079 x=x-1;
2080 }
2081 py=py+2*( dx1-dy1 );
2082 }
2083 set_pixel_mask( x, y, value );
2084 }
2085 }
2086}
2087
2088//............................................................................
2096float PixieChroma::get_uv_x( int32_t x_pixel ){
2097 return x_pixel / float( matrix_width );
2098}
2099
2100//............................................................................
2108float PixieChroma::get_uv_y( int32_t y_pixel ){
2109 y_pixel = matrix_height - y_pixel;
2110 return y_pixel / float( matrix_height );
2111}
2112
2113//............................................................................
2122uint8_t PixieChroma::get_pixel_mask( int32_t x, int32_t y ){
2123 return mask[ xy(x,y) ];
2124}
2125
2126//............................................................................
2135CRGB PixieChroma::get_pixel_color( int32_t x, int32_t y ){
2136 return color_map[ xy(x,y) ];
2137}
2138
2139//............................................................................
2181 for( uint8_t y = 0; y < matrix_height; y++ ){
2182 for( uint8_t x = 0; x < matrix_width; x++ ){
2183 uint16_t index = ( matrix_width*y )+x;
2184 Serial.print( xy_table[index] );
2185 Serial.print( '\t' );
2186 }
2187 Serial.println();
2188 }
2189}
2190
2191//............................................................................
2201void PixieChroma::scroll_message( char* message, uint8_t row ){
2202 scrolling[row] = true;
2203
2204 uint16_t len = strlen(message);
2205 uint16_t i = 0;
2206 while (i < len - 1) {
2207 if (message[i] == '[' && message[i + 1] == ':') { // Found start of shortcode
2208 for (uint16_t j = i; j < len - 1; j++) {
2209 if (message[j] == ':' && message[j + 1] == ']') { // Found end of shortcode
2210 fetch_shortcode( message, i + 2, j, true );
2211 scroll_char(temp_code, row);
2212 i = j + 2;
2213 break;
2214 }
2215 }
2216 }
2217 else {
2218 scroll_char(message[i], row);
2219 i += 1;
2220 }
2221 }
2222
2223 if(message[len-1] != ']'){ // If message doesn't end with shortcode
2224 scroll_char(message[len-1], row);
2225 }
2226
2227 for(uint8_t i = 0; i < chars_x; i++){
2228 scroll_char(' ', row);
2229 }
2230
2231 scrolling[row] = false;
2232}
2233
2234//............................................................................
2243void PixieChroma::set_pixel_mask( int32_t x, int32_t y, uint8_t value ){
2244 mask[ xy(x,y) ] = value;
2245}
2246
2247//............................................................................
2256void PixieChroma::set_pixel_color( int32_t x, int32_t y, CRGB color ){
2257 color_map[ xy(x,y) ] = color;
2258}
2259
2260//............................................................................
2269void PixieChroma::shift_mask_x( int16_t amount, int16_t row ){
2270 int16_t y_start = 0;
2271 int16_t y_end = matrix_height;
2272
2273 if(row != -1){
2274 y_start = display_height*row;
2275 y_end = display_height*(row+1);
2276 }
2277
2278 if(amount < 0){
2279 for( uint16_t x = 0; x < matrix_width; x++ ){
2280 for( uint16_t y = y_start; y < y_end; y++ ){
2281 int16_t x_dest = x - amount;
2282 int16_t y_dest = y - 0;
2283
2284 if(x_dest >= 0 && y_dest >= 0 && x_dest < matrix_width && y_dest < matrix_height){
2285 mask[ xy( x,y ) ] = mask[ xy( x_dest, y_dest ) ];
2286 }
2287 else{
2288 mask[ xy( x,y ) ] = 0;
2289 }
2290 }
2291 }
2292 }
2293 else if(amount > 0){
2294 for( int16_t x = matrix_width; x >= 0; x-- ){
2295 for( uint16_t y = y_start; y < y_end; y++ ){
2296 int16_t x_dest = x - amount;
2297 int16_t y_dest = y - 0;
2298
2299 if(x_dest >= 0 && y_dest >= 0 && x_dest < matrix_width && y_dest < matrix_height){
2300 mask[ xy( x,y ) ] = mask[ xy( x_dest, y_dest ) ];
2301 }
2302 else{
2303 mask[ xy( x,y ) ] = 0;
2304 }
2305 }
2306 }
2307 }
2308}
2309
2310//............................................................................
2317void PixieChroma::shift_mask_y( int16_t amount ){
2318 if(amount < 0){
2319 for( uint16_t y = 0; y < matrix_height; y++ ){
2320 for( uint16_t x = 0; x < matrix_width; x++ ){
2321 int16_t x_dest = x - 0;
2322 int16_t y_dest = y - amount;
2323
2324 if(x_dest >= 0 && y_dest >= 0 && x_dest < matrix_width && y_dest < matrix_height){
2325 mask[ xy( x,y ) ] = mask[ xy( x_dest, y_dest ) ];
2326 }
2327 else{
2328 mask[ xy( x,y ) ] = 0;
2329 }
2330 }
2331 }
2332 }
2333 else if(amount > 0){
2334 for( int16_t y = matrix_height; y >= 0; y-- ){
2335 for( uint16_t x = 0; x < matrix_width; x++ ){
2336 int16_t x_dest = x - 0;
2337 int16_t y_dest = y - amount;
2338
2339 if(x_dest >= 0 && y_dest >= 0 && x_dest < matrix_width && y_dest < matrix_height){
2340 mask[ xy( x,y ) ] = mask[ xy( x_dest, y_dest ) ];
2341 }
2342 else{
2343 mask[ xy( x,y ) ] = 0;
2344 }
2345 }
2346 }
2347 }
2348}
2349
2350//............................................................................
2359void PixieChroma::shift_color_map_x( int16_t amount, int16_t row ){
2360 int16_t y_start = 0;
2361 int16_t y_end = matrix_height;
2362
2363 if(row != -1){
2364 y_start = display_height*row;
2365 y_end = display_height*(row+1);
2366 }
2367
2368 if(amount < 0){
2369 for( uint16_t x = 0; x < matrix_width; x++ ){
2370 for( uint16_t y = y_start; y < y_end; y++ ){
2371 int16_t x_dest = x - amount;
2372 int16_t y_dest = y - 0;
2373
2374 if(x_dest >= 0 && y_dest >= 0 && x_dest < matrix_width && y_dest < matrix_height){
2375 color_map[ xy( x,y ) ] = color_map[ xy( x_dest, y_dest ) ];
2376 }
2377 else{
2378 color_map[ xy( x,y ) ] = 0;
2379 }
2380
2381 }
2382 }
2383 }
2384 else if(amount > 0){
2385 for( int16_t x = matrix_width; x >= 0; x-- ){
2386 for( uint16_t y = y_start; y < y_end; y++ ){
2387 int16_t x_dest = x - amount;
2388 int16_t y_dest = y - 0;
2389
2390 if(x_dest >= 0 && y_dest >= 0 && x_dest < matrix_width && y_dest < matrix_height){
2391 color_map[ xy( x,y ) ] = color_map[ xy( x_dest, y_dest ) ];
2392 }
2393 else{
2394 color_map[ xy( x,y ) ] = 0;
2395 }
2396 }
2397 }
2398 }
2399}
2400
2401//............................................................................
2408void PixieChroma::shift_color_map_y( int16_t amount ){
2409 if(amount < 0){
2410 for( uint16_t x = 0; x < matrix_width; x++ ){
2411 for( uint16_t y = 0; y < matrix_height; y++ ){
2412 int16_t x_dest = x - 0;
2413 int16_t y_dest = y - amount;
2414
2415 if(x_dest >= 0 && y_dest >= 0 && x_dest < matrix_width && y_dest < matrix_height){
2416 color_map[ xy( x,y ) ] = color_map[ xy( x_dest, y_dest ) ];
2417 }
2418 else{
2419 color_map[ xy( x,y ) ] = 0;
2420 }
2421 }
2422 }
2423 }
2424 else if(amount > 0){
2425 for( int16_t x = matrix_width; x >= 0; x-- ){
2426 for( uint16_t y = 0; y < matrix_height; y++ ){
2427 int16_t x_dest = x - amount;
2428 int16_t y_dest = y - 0;
2429
2430 if(x_dest >= 0 && y_dest >= 0 && x_dest < matrix_width && y_dest < matrix_height){
2431 color_map[ xy( x,y ) ] = color_map[ xy( x_dest, y_dest ) ];
2432 }
2433 else{
2434 color_map[ xy( x,y ) ] = 0;
2435 }
2436 }
2437 }
2438 }
2439}
2440
2441//............................................................................
2463uint16_t PixieChroma::uv( float x, float y, bool wrap ) {
2464 if( wrap ){
2465 while( x < 0.0 ){
2466 x += 1.0;
2467 }
2468 while( x > 1.0 ){
2469 x -= 1.0;
2470 }
2471 while( y < 0.0 ){
2472 y += 1.0;
2473 }
2474 while( y > 1.0 ){
2475 y -= 1.0;
2476 }
2477 }
2478
2479 y = 1.0-y; // Invert Y axis for OpenGL coordinate style
2480
2481 return xy(
2482 uint16_t( matrix_width * x ),
2483 uint16_t( matrix_height * y )
2484 );
2485}
2486
2487//............................................................................
2542uint16_t PixieChroma::xy( int32_t x, int32_t y, bool wrap ) {
2543 if( wrap ){
2544 while( x < 0 ){
2545 x += matrix_width;
2546 }
2547 while( x >= matrix_width ){
2548 x -= matrix_width;
2549 }
2550 while( y < 0 ){
2551 y += matrix_height;
2552 }
2553 while( y >= matrix_height ){
2554 y -= matrix_height;
2555 }
2556 }
2557 else{
2558 if( x < 0 ){
2559 return pixel_count; // If offscreen without wrap return last led in matrix
2560 }
2561 else if( x >= matrix_width ){
2562 return pixel_count; // If offscreen without wrap return last led in matrix
2563 }
2564 if( y < 0 ){
2565 return pixel_count; // If offscreen without wrap return last led in matrix
2566 }
2567 else if( y >= matrix_height ){
2568 return pixel_count; // If offscreen without wrap return last led in matrix
2569 }
2570 }
2571
2572 // done wrapping / culling, time for transformation
2573 return xy_table[ ( y * matrix_width ) + x ];
2574}
2575
2576
2577
2578// ---------------------------------------------------------------------------------------------------------|
2579// -- PRIVATE CLASS FUNCTIONS ------------------------------------------------------------------------------|
2580// ---------------------------------------------------------------------------------------------------------|
2581
2582void PixieChroma::build_controller( const uint8_t pin ){
2583 // FastLED control pin has to be defined as a constant, ( not just declared const, it's weirdly different ) so
2584 // this is a hacky workaround. Since we have to hardwire the damn pin number variable, we also have
2585 // to be careful of the current architecture we're compiling to, since FastLED doesn't let you
2586 // define non-existent pins either.
2587
2588 #ifdef ARDUINO_ARCH_ESP8266
2589 if ( pin == 0 ){FastLED.addLeds<WS2812B, 0, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2590 if ( pin == 1 ){FastLED.addLeds<WS2812B, 1, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2591 if ( pin == 2 ){FastLED.addLeds<WS2812B, 2, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2592 if ( pin == 3 ){FastLED.addLeds<WS2812B, 3, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2593 if ( pin == 4 ){FastLED.addLeds<WS2812B, 4, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2594 if ( pin == 5 ){FastLED.addLeds<WS2812B, 5, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2595 // annnnd a bunch of missing pins that are tied to external flash...
2596 if ( pin == 12 ){FastLED.addLeds<WS2812B, 12, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2597 if ( pin == 13 ){FastLED.addLeds<WS2812B, 13, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2598 if ( pin == 14 ){FastLED.addLeds<WS2812B, 14, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2599 if ( pin == 15 ){FastLED.addLeds<WS2812B, 15, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2600 if ( pin == 16 ){FastLED.addLeds<WS2812B, 16, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2601 #endif
2602
2603 #ifdef ARDUINO_ARCH_ESP32
2604 if ( pin == 0 ){FastLED.addLeds<WS2812B, 0, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2605 if ( pin == 1 ){FastLED.addLeds<WS2812B, 1, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2606 if ( pin == 2 ){FastLED.addLeds<WS2812B, 2, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2607 if ( pin == 3 ){FastLED.addLeds<WS2812B, 3, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2608 if ( pin == 4 ){FastLED.addLeds<WS2812B, 4, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2609 if ( pin == 5 ){FastLED.addLeds<WS2812B, 5, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2610 if ( pin == 12 ){FastLED.addLeds<WS2812B, 12, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2611 if ( pin == 13 ){FastLED.addLeds<WS2812B, 13, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2612 if ( pin == 14 ){FastLED.addLeds<WS2812B, 14, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2613 if ( pin == 15 ){FastLED.addLeds<WS2812B, 15, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2614 if ( pin == 16 ){FastLED.addLeds<WS2812B, 16, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2615 if ( pin == 17 ){FastLED.addLeds<WS2812B, 17, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2616 if ( pin == 18 ){FastLED.addLeds<WS2812B, 18, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2617 if ( pin == 19 ){FastLED.addLeds<WS2812B, 19, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2618 if ( pin == 21 ){FastLED.addLeds<WS2812B, 21, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2619 if ( pin == 22 ){FastLED.addLeds<WS2812B, 22, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2620 if ( pin == 23 ){FastLED.addLeds<WS2812B, 23, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2621 if ( pin == 25 ){FastLED.addLeds<WS2812B, 25, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2622 if ( pin == 26 ){FastLED.addLeds<WS2812B, 26, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2623 if ( pin == 27 ){FastLED.addLeds<WS2812B, 27, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2624 if ( pin == 32 ){FastLED.addLeds<WS2812B, 32, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2625 if ( pin == 33 ){FastLED.addLeds<WS2812B, 33, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2626 #endif
2627
2628 #ifdef ARDUINO_ARCH_TEENSY_3_X
2629 if ( pin == 0 ){FastLED.addLeds<WS2812B, 0, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2630 if ( pin == 1 ){FastLED.addLeds<WS2812B, 1, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2631 if ( pin == 2 ){FastLED.addLeds<WS2812B, 2, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2632 if ( pin == 3 ){FastLED.addLeds<WS2812B, 3, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2633 if ( pin == 4 ){FastLED.addLeds<WS2812B, 4, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2634 if ( pin == 5 ){FastLED.addLeds<WS2812B, 5, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2635 if ( pin == 6 ){FastLED.addLeds<WS2812B, 6, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2636 if ( pin == 7 ){FastLED.addLeds<WS2812B, 7, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2637 if ( pin == 8 ){FastLED.addLeds<WS2812B, 8, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2638 if ( pin == 9 ){FastLED.addLeds<WS2812B, 9, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2639 if ( pin == 10 ){FastLED.addLeds<WS2812B, 10, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2640 if ( pin == 11 ){FastLED.addLeds<WS2812B, 11, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2641 if ( pin == 12 ){FastLED.addLeds<WS2812B, 12, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2642 if ( pin == 13 ){FastLED.addLeds<WS2812B, 13, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2643 if ( pin == 14 ){FastLED.addLeds<WS2812B, 14, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2644 if ( pin == 15 ){FastLED.addLeds<WS2812B, 15, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2645 if ( pin == 16 ){FastLED.addLeds<WS2812B, 16, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2646 if ( pin == 17 ){FastLED.addLeds<WS2812B, 17, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2647 if ( pin == 18 ){FastLED.addLeds<WS2812B, 18, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2648 if ( pin == 19 ){FastLED.addLeds<WS2812B, 19, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2649 if ( pin == 20 ){FastLED.addLeds<WS2812B, 20, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2650 if ( pin == 21 ){FastLED.addLeds<WS2812B, 21, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2651 if ( pin == 22 ){FastLED.addLeds<WS2812B, 22, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2652 if ( pin == 23 ){FastLED.addLeds<WS2812B, 23, GRB>( color_map_out, led_count ).setCorrection( TypicalLEDStrip );}
2653 #endif
2654}
2655
2656
2657void PixieChroma::calc_xy(){
2658 // Initialize XY table
2659 for( uint16_t yi = 0; yi < chars_y; yi++ ){
2660 for( uint16_t y = 0; y < 11; y++ ){
2661 for( uint16_t xi = 0; xi < chars_x; xi++ ){
2662 for( uint16_t x = 0; x < 7; x++ ){
2663 int16_t x_pos = ( xi*display_width )+x;
2664 int16_t y_pos = ( yi*display_height )+y;
2665
2666 int16_t x_pos_mod = x_pos % display_width;
2667 int16_t y_pos_mod = y_pos % display_height;
2668
2669 uint16_t i_table = ( y_pos * matrix_width ) + x_pos;
2670 uint16_t i_template = ( y_pos_mod * display_width ) + x_pos_mod;
2671
2672 if(xi != 0 && xi != chars_x-1){
2673 xy_table[i_table] = int8_t( pgm_read_byte( xy_template + i_template ) );
2674 }
2675 else{
2676 xy_table[i_table] = -2;
2677 }
2678 }
2679 }
2680 }
2681 }
2682
2683 //Serial.println( "SOLVING VISIBLE" );
2684
2685 // Initialize first row of displays
2686 uint8_t visible_rows = 0;
2687 for( uint16_t row = 0; row < display_height; row++ ){
2688 uint16_t index = ( 5*visible_rows );
2689 bool found_visible = false;
2690 int16_t last_data = 0;
2691 for( uint16_t col = 0; col < matrix_width; col++ ){
2692 uint16_t i = ( row*matrix_width )+col;
2693 int16_t map_data = xy_table[i];
2694
2695 if( map_data == -1 ){
2696 xy_table[i] = index;
2697 index++;
2698 found_visible = true;
2699 }
2700
2701 else if( map_data == -2 ){
2702 if( last_data == -1 ){
2703 index+=30;
2704 }
2705 }
2706
2707 last_data = map_data;
2708 }
2709
2710 if( found_visible ){
2711 visible_rows++;
2712 }
2713 }
2714
2715 led_count = 35*(chars_x-2); // account for first row
2716
2717 // Solve additional rows
2718 if( chars_y > 1 ){
2719 uint8_t rows_left = chars_y-1;
2720 uint16_t row_length = ( display_width*display_height )*chars_x;
2721 for( uint8_t ii = 0; ii < rows_left; ii++ ){
2722 for( uint16_t r = 0; r < row_length; r++ ){
2723 uint16_t final_src_index = ( ii*row_length )+r;
2724 int16_t src_data = xy_table[final_src_index];
2725 if( src_data >= 0 ){
2726 src_data += ( 35*(chars_x-2) );
2727
2728 if( src_data > led_count ){
2729 led_count = src_data+1;
2730 }
2731 xy_table[final_src_index+row_length] = src_data;
2732 }
2733 }
2734 }
2735 }
2736
2737 uint16_t index = led_count;
2738
2739 //Serial.println( "SOLVING INVISIBLE" );
2740 for( uint16_t y = 0; y < matrix_height; y++ ){
2741 for( uint16_t x = 0; x < matrix_width; x++ ){
2742 uint16_t i = ( y * matrix_width ) + x;
2743 uint16_t j = xy_table[i];
2744
2745 if( xy_table[i] == -2 ){
2746 xy_table[i] = index;
2747 index++;
2748 }
2749 }
2750 }
2751 //Serial.println( "DONE" );
2752}
2753
2754
2755void PixieChroma::fetch_shortcode( char* message, uint16_t code_start, uint16_t code_end, bool return_code ){
2756 if( message[code_start] == '#' ){ // custom data, no lookup needed
2757 parse_custom_shortcode( message, code_start+1, code_end, return_code );
2758 return;
2759 }
2760 char bitmap_name[32];
2761 memset(bitmap_name, 0, 32);
2762 char bitmap_temp[32];
2763 memset(bitmap_temp, 0, 32);
2764 uint8_t bitmap_temp_index = 0;
2765
2766 uint16_t code_length = code_end - code_start;
2767 for (uint16_t i = 0; i < code_length; i++) {
2768 bitmap_name[i] = message[code_start + i];
2769 }
2770
2771 // Allow for lowercase shortcodes as well
2772 for (uint16_t i = 0; i < code_length; i++) {
2773 if( uint8_t(bitmap_name[i]) >= 97 && uint8_t(bitmap_name[i]) <= 122 ){ // if in lowercase a-z range
2774 bitmap_name[i] -= 32; // shift to uppercase A-Z range
2775 }
2776 }
2777
2778 uint32_t index = 0;
2779 while (index < sizeof(PIXIE_SHORTCODE_LIBRARY)) {
2780 if (PIXIE_SHORTCODE_LIBRARY[index] >= 200) {
2781 uint8_t skips = PIXIE_SHORTCODE_LIBRARY[index]-200;
2782 index += 1; // Skip the mark byte
2783 skips -= 1;
2784
2785 char first_name_char = PIXIE_SHORTCODE_LIBRARY[index];
2786 if(bitmap_name[0] == first_name_char){
2787 memset(bitmap_temp, 0, 32);
2788 bitmap_temp_index = 0;
2789 uint32_t bitmap_data_index = index - 6;
2790
2791 bool end_found = false;
2792 while (end_found == false) {
2793 uint8_t val = PIXIE_SHORTCODE_LIBRARY[index];
2794
2795 bitmap_temp[bitmap_temp_index] = char(val); // Gather chars, even null terminator
2796 if (val == 0) { // Found end of name
2797 end_found = true;
2798 }
2799
2800 bitmap_temp_index += 1;
2801 index += 1;
2802 skips -= 1;
2803 }
2804 if (strcmp(bitmap_temp, bitmap_name) == 0) { // If a string match is found:
2805
2806 if(return_code == false){
2807 color(print_col, cursor_x/display_width, cursor_y/display_height);
2808
2809 print( // Print column data
2810 PIXIE_SHORTCODE_LIBRARY[bitmap_data_index + 0],
2811 PIXIE_SHORTCODE_LIBRARY[bitmap_data_index + 1],
2812 PIXIE_SHORTCODE_LIBRARY[bitmap_data_index + 2],
2813 PIXIE_SHORTCODE_LIBRARY[bitmap_data_index + 3],
2814 PIXIE_SHORTCODE_LIBRARY[bitmap_data_index + 4]
2815 );
2816 }
2817 else{
2818 temp_code[0] = PIXIE_SHORTCODE_LIBRARY[bitmap_data_index + 0];
2819 temp_code[1] = PIXIE_SHORTCODE_LIBRARY[bitmap_data_index + 1];
2820 temp_code[2] = PIXIE_SHORTCODE_LIBRARY[bitmap_data_index + 2];
2821 temp_code[3] = PIXIE_SHORTCODE_LIBRARY[bitmap_data_index + 3];
2822 temp_code[4] = PIXIE_SHORTCODE_LIBRARY[bitmap_data_index + 4];
2823 }
2824
2825 return;
2826 }
2827 }
2828 else{
2829 index += skips;
2830 skips = 0;
2831 }
2832 }
2833 else {
2834 index += 1;
2835 }
2836 }
2837}
2838
2839
2840void PixieChroma::parse_custom_shortcode( char* message, uint16_t code_start, uint16_t code_end, bool return_code ){
2841 uint8_t input[10];
2842
2843 for(uint8_t i = 0; i < (code_end-code_start); i++){
2844 char chr = message[code_start+i];
2845
2846 if (chr == '0'){ input[i] = 0; }
2847 else if(chr == '1'){ input[i] = 1; }
2848 else if(chr == '2'){ input[i] = 2; }
2849 else if(chr == '3'){ input[i] = 3; }
2850 else if(chr == '4'){ input[i] = 4; }
2851 else if(chr == '5'){ input[i] = 5; }
2852 else if(chr == '6'){ input[i] = 6; }
2853 else if(chr == '7'){ input[i] = 7; }
2854 else if(chr == '8'){ input[i] = 8; }
2855 else if(chr == '9'){ input[i] = 9; }
2856 else if(chr == 'A'){ input[i] = 10; }
2857 else if(chr == 'B'){ input[i] = 11; }
2858 else if(chr == 'C'){ input[i] = 12; }
2859 else if(chr == 'D'){ input[i] = 13; }
2860 else if(chr == 'E'){ input[i] = 14; }
2861 else if(chr == 'F'){ input[i] = 15; }
2862 }
2863
2864 uint8_t column_1 = input[1] + (input[0]<<4);
2865 uint8_t column_2 = input[3] + (input[2]<<4);
2866 uint8_t column_3 = input[5] + (input[4]<<4);
2867 uint8_t column_4 = input[7] + (input[6]<<4);
2868 uint8_t column_5 = input[9] + (input[8]<<4);
2869
2870 if(return_code == false){
2871 color(print_col, cursor_x/display_width, cursor_y/display_height);
2872
2873 print( // Print column data
2874 column_1,
2875 column_2,
2876 column_3,
2877 column_4,
2878 column_5
2879 );
2880 }
2881 else{
2882 temp_code[0] = column_1;
2883 temp_code[1] = column_2;
2884 temp_code[2] = column_3;
2885 temp_code[3] = column_4;
2886 temp_code[4] = column_5;
2887 }
2888}
2889
2890
2891void PixieChroma::scroll_char(char c, uint8_t row){
2892 add_char(c, (chars_x * display_width)-6, 2+(row*display_height));
2893 for (uint8_t i = 0; i < 7; i++) {
2894 shift_mask_x(-1, row);
2895 if(scroll_type != INSTANT){
2896 show();
2897 delay(scroll_frame_delay_ms);
2898 }
2899 }
2900 show();
2901 delay(scroll_hold_ms);
2902}
2903
2904
2905void PixieChroma::scroll_char(uint8_t* bitmap, uint8_t row){
2906 add_char(bitmap[0], bitmap[1], bitmap[2], bitmap[3], bitmap[4], (chars_x * display_width)-6, 2+(row*display_height));
2907 for (uint8_t i = 0; i < 7; i++) {
2908 shift_mask_x(-1, row);
2909 if(scroll_type != INSTANT){
2910 show();
2911 delay(scroll_frame_delay_ms);
2912 }
2913 }
2914 show();
2915 delay(scroll_hold_ms);
2916}
2917
2918
2919int16_t PixieChroma::calc_justification( t_justification justification, uint8_t row ){
2920 if(justification == LEFT){
2921 return 0;
2922 }
2923
2924 uint8_t x_disp_start = 0;
2925 uint8_t x_disp_end = 0;
2926
2927 uint16_t x_led = 0;
2928 uint16_t x_pos = 0;
2929
2930 for(int16_t x = 0; x < matrix_width; x++){
2931 for(int16_t y = (display_height*row); y < (display_height*(row+1)); y++){
2932 if(mask[ xy(x,y) ] != 0){
2933 x = matrix_width;
2934 y = matrix_height;
2935 break;
2936 }
2937 else{
2938 x_led += 1;
2939 if(x_led >= (display_width*display_height)){
2940 x_led = 0;
2941 x_pos += 1;
2942 }
2943 }
2944 }
2945 }
2946
2947 x_disp_start = x_pos;
2948 x_led = 0;
2949 x_pos = chars_x;
2950
2951 for(int16_t x = matrix_width-1; x > 0; x--){
2952 for(int16_t y = (display_height*row); y < (display_height*(row+1)); y++){
2953 if(mask[ xy(x,y) ] != 0){
2954 x = 0;
2955 y = matrix_height;
2956 break;
2957 }
2958 else{
2959 x_led += 1;
2960 if(x_led >= (display_width*display_height)){
2961 x_led = 0;
2962 x_pos -= 1;
2963 }
2964 }
2965 }
2966 }
2967
2968 x_disp_end = x_pos;
2969
2970 uint8_t length = x_disp_end - x_disp_start;
2971 int16_t x_offset_chars;
2972
2973 if(length > (chars_x-2)){
2974 return 0;
2975 }
2976
2977 if(justification == CENTER){
2978 x_offset_chars = floor(((chars_x-2) - length) / 2.0);
2979
2980 if((x_offset_chars*2) + length > (chars_x-2)){
2981 x_offset_chars -= 1;
2982 }
2983 }
2984 else if(justification == RIGHT){
2985 x_offset_chars = (chars_x-2)-length;
2986 }
2987
2988 return x_offset_chars * display_width;
2989}
2990
2991// (End of user code)
2992
2993// ##########################################################################################################
2994// ##########################################################################################################
2995// ##########################################################################################################
2996// ##########################################################################################################
2997// ##########################################################################################################
2998// ##########################################################################################################
2999// ##########################################################################################################
3000// ##########################################################################################################
3001// ##########################################################################################################
3002// ##########################################################################################################
3003// ##########################################################################################################
3004// ##########################################################################################################
3005// ##########################################################################################################
3006// ##########################################################################################################
3007// ##########################################################################################################
3008// ##########################################################################################################
3009// ##########################################################################################################
3010// ##########################################################################################################
3011// ##########################################################################################################
3012// ##########################################################################################################
3013// ##########################################################################################################
3014// ##########################################################################################################
3015// ##########################################################################################################
3016// ##########################################################################################################
3017// ##########################################################################################################
3018// ##########################################################################################################
3019// ##########################################################################################################
3020// ##########################################################################################################
3021// ##########################################################################################################
3022// ##########################################################################################################
3023
3024// ---------------------------------------------------------------------------------------------------------|
3025// -- DEVELOPER FUNCTIONS ----------------------------------------------------------------------------------|
3026// ---------------------------------------------------------------------------------------------------------|
3027//............................................................................
3035 //randomSeed(
3036 // analogRead( ANALOG_PIN )
3037 //);
3038
3039 char* border = "+---------------------------------------------+";
3040
3041 char* testing = "Testing: ";
3042 char* PASS = "PASS";
3043 char* FAIL = "FAIL\n--------------------------------------------------------- #####";
3044 bool success = true;
3045
3046
3047 // ----------------------------------------------------------------------------------------------------
3048 // @@@@@ begin ---------------------------------------------------------------------------------- @@@@@
3049 // ----------------------------------------------------------------------------------------------------
3050
3051 Serial.println( border );
3052 Serial.print ( testing );
3053 Serial.print(F("begin() ......................... "));
3054 uint8_t fail_step = 0;
3055
3056 begin_quad( // 12 Pixies, (6x2) in quad mode
3060 );
3061
3062 if( chars_x != 12 ){ fail_step = 1; }
3063 if( chars_y != 2 ){ fail_step = 2; }
3064 if( matrix_width != 84 ){ fail_step = 3; }
3065 if( matrix_height != 22 ){ fail_step = 4; }
3066 if( pixel_count != 1848 ){ fail_step = 5; }
3067 if( led_count != 840 ){ fail_step = 6; }
3068 if( xy_table[0] != 840 ){ fail_step = 7; }
3069 if( xy_table[500] != 402 ){ fail_step = 8; }
3070 if( color_map[0].g != 255 ){ fail_step = 9; }
3071
3072 if(fail_step == 0){
3073 Serial.println(PASS);
3074
3075 clear();
3076 print("------------------------");
3077 }
3078 else{
3079 Serial.println(FAIL);
3080 Serial.print("FAIL_STEP: ");
3081 Serial.println(fail_step);
3082
3083 success = false;
3084 }
3085
3086 Serial.println(border);
3087
3088
3089 // ----------------------------------------------------------------------------------------------------
3090 // @@@@@ xy ------------------------------------------------------------------------------------- @@@@@
3091 // ----------------------------------------------------------------------------------------------------
3092
3093 Serial.println( border );
3094 Serial.print ( testing );
3095 Serial.print(F("xy() ............................ "));
3096 fail_step = 0;
3097
3098 if( xy(0, 0 ) != 840 ){ fail_step = 1; } // top left
3099 if( xy(83,0 ) != 923 ){ fail_step = 2; } // top right
3100 if( xy(0, 21) != 1764 ){ fail_step = 3; } // bottom left
3101 if( xy(83,21) != 1847 ){ fail_step = 4; } // bottom_right
3102 if( xy(41,10) != 1301 ){ fail_step = 5; } // center
3103
3104 if(fail_step == 0){
3105 Serial.println(PASS);
3106 }
3107 else{
3108 Serial.println(FAIL);
3109 Serial.print("FAIL_STEP: ");
3110 Serial.println(fail_step);
3111
3112 success = false;
3113 }
3114
3115 Serial.println(border);
3116
3117
3118 // ----------------------------------------------------------------------------------------------------
3119 // @@@@@ set_brightness ------------------------------------------------------------------------- @@@@@
3120 // ----------------------------------------------------------------------------------------------------
3121
3122 Serial.println( border );
3123 Serial.print ( testing );
3124 Serial.print(F("set_brightness() ................ "));
3125
3126 bool success_temp = true;
3127 for(uint8_t i = 0; i < 100; i++){
3128 uint8_t rand_brightness = random( 0, 255 );
3129 set_brightness( rand_brightness );
3130 show();
3131
3132 if( brightness_level != rand_brightness ){
3133 success_temp = false;
3134 }
3135 }
3136
3137 if(success_temp == true){
3138 set_brightness( 8 );
3139 show();
3140 Serial.println(PASS);
3141 }
3142 else{
3143 Serial.println(FAIL);
3144 success = false;
3145 }
3146
3147 Serial.println(border);
3148
3149
3150 // ----------------------------------------------------------------------------------------------------
3151 // @@@@@ set_palette ---------------------------------------------------------------------------- @@@@@
3152 // ----------------------------------------------------------------------------------------------------
3153
3155
3156 Serial.println( border );
3157 Serial.print ( testing );
3158 Serial.print(F("set_palette() ................... "));
3159
3160 print("------------------------");
3161
3162 success_temp = true;
3163 for(uint8_t i = 0; i < 100; i++){
3164 CRGB rands[8] = {
3165 CRGB(random(0,255), random(0,255), random(0,255)),
3166 CRGB(random(0,255), random(0,255), random(0,255)),
3167 CRGB(random(0,255), random(0,255), random(0,255)),
3168 CRGB(random(0,255), random(0,255), random(0,255)),
3169 CRGB(random(0,255), random(0,255), random(0,255)),
3170 CRGB(random(0,255), random(0,255), random(0,255)),
3171 CRGB(random(0,255), random(0,255), random(0,255)),
3172 CRGB(random(0,255), random(0,255), random(0,255))
3173 };
3174
3175 CRGBPalette16 test_palette = CRGBPalette16(
3176 rands[0], rands[1], rands[2], rands[3],
3177 rands[4], rands[5], rands[6], rands[7],
3178 rands[0], rands[1], rands[2], rands[3],
3179 rands[4], rands[5], rands[6], rands[7]
3180 );
3181
3182 set_palette( test_palette );
3183 show();
3184
3185 bool success_temp_b = true;
3186 for(uint8_t i = 0; i < 8; i++){
3187 if(test_palette.entries[i] != rands[i] || test_palette.entries[i+8] != rands[i]){
3188 success_temp_b = false;
3189 }
3190 }
3191
3192 if(!success_temp_b){
3193 success_temp = false;
3194 }
3195 }
3196
3197 if(success_temp){
3198 Serial.println(PASS);
3199 set_palette(GREEN_SOLID);
3200 }
3201 else{
3202 Serial.println(FAIL);
3203 success = false;
3204 }
3205
3206 Serial.println(border);
3207
3208
3209 // ----------------------------------------------------------------------------------------------------
3210 // @@@@@ set_update_mode ------------------------------------------------------------------------ @@@@@
3211 // ----------------------------------------------------------------------------------------------------
3212
3213 Serial.println( border );
3214 Serial.print ( testing );
3215 Serial.print(F("set_update_mode() ............... "));
3216 fail_step = 0;
3217
3219 if(!ticker_running){
3220 fail_step = 1;
3221 }
3222
3224 if(ticker_running){
3225 fail_step = 2;
3226 }
3227
3228 if(fail_step == 0){
3230 Serial.println(PASS);
3231 }
3232 else{
3233 Serial.println(FAIL);
3234 Serial.println(fail_step);
3235 success = false;
3236 }
3237
3238 Serial.println(border);
3239
3240
3241 // ----------------------------------------------------------------------------------------------------
3242 // @@@@@ write(bitmap) ---------------------------------------------------------------------------- @@@@@
3243 // ----------------------------------------------------------------------------------------------------
3244 /*
3245
3246 Serial.println( border );
3247 Serial.print ( testing );
3248 Serial.print(F("write(bitmap) ..................... "));
3249
3250 clear();
3251 write(bitmap_HEART,0,0);
3252 show();
3253
3254 success_temp = true;
3255 for(uint8_t x = 0; x < 5; x++){
3256 uint8_t column = pgm_read_byte_far( bitmap_HEART+x );
3257
3258 for(uint8_t y = 0; y < 7; y++){
3259 uint8_t bitmap_val = bit_table[ bitRead( column, y ) ];
3260
3261 uint16_t index = xy(x+display_padding_x, y+display_padding_y);
3262 uint8_t mask_val = mask[index];
3263
3264 if(bitmap_val != mask_val){
3265 success_temp = false;
3266 }
3267 }
3268 }
3269
3270 if(success_temp){
3271 Serial.println(PASS);
3272 }
3273 else{
3274 Serial.println(FAIL);
3275 success = false;
3276 }
3277
3278 Serial.println(border);
3279
3280 */
3281 // ----------------------------------------------------------------------------------------------------
3282 // @@@@@ write(int16_t) ------------------------------------------------------------------------- @@@@@
3283 // ----------------------------------------------------------------------------------------------------
3284
3285 Serial.println( border );
3286 Serial.print ( testing );
3287 Serial.print(F("write(int16_t) .................. "));
3288
3289 clear();
3290 write(int16_t(-2),0,0);
3291 show();
3292
3293 success_temp = true;
3294 for(uint8_t x = 0; x < 5; x++){
3295 char chr = '-';
3297 uint8_t column = pgm_read_byte( font + ( chr * font_col_width + x ) );
3298
3299 for(uint8_t y = 0; y < 7; y++){
3300 uint8_t char_val = bit_table[ bitRead( column, y ) ];
3301
3302 uint16_t index = xy(x+display_padding_x, y+display_padding_y);
3303 uint8_t mask_val = mask[index];
3304
3305 if(char_val != mask_val){
3306 success_temp = false;
3307 }
3308 }
3309 }
3310 for(uint8_t x = 0; x < 5; x++){
3311 char chr = '2';
3313 uint8_t column = pgm_read_byte( font + ( chr * font_col_width + x ) );
3314
3315 for(uint8_t y = 0; y < 7; y++){
3316 uint8_t char_val = bit_table[ bitRead( column, y ) ];
3317
3318 uint16_t index = xy(x+display_padding_x+(display_width*1), y+display_padding_y);
3319 uint8_t mask_val = mask[index];
3320
3321 if(char_val != mask_val){
3322 success_temp = false;
3323 }
3324 }
3325 }
3326 for(uint8_t x = 0; x < 5; x++){
3327 char chr = ' ';
3329 uint8_t column = pgm_read_byte( font + ( chr * font_col_width + x ) );
3330
3331 for(uint8_t y = 0; y < 7; y++){
3332 uint8_t char_val = bit_table[ bitRead( column, y ) ];
3333
3334 uint16_t index = xy(x+display_padding_x+(display_width*2), y+display_padding_y);
3335 uint8_t mask_val = mask[index];
3336
3337 if(char_val != mask_val){
3338 success_temp = false;
3339 }
3340 }
3341 }
3342
3343 if(success_temp){
3344 Serial.println(PASS);
3345 }
3346 else{
3347 Serial.println(FAIL);
3348 success = false;
3349 }
3350
3351 Serial.println(border);
3352
3353
3354 // ----------------------------------------------------------------------------------------------------
3355 // @@@@@ print(bitmap) ---------------------------------------------------------------------------- @@@@@
3356 // ----------------------------------------------------------------------------------------------------
3357 /*
3358
3359 Serial.println( border );
3360 Serial.print ( testing );
3361 Serial.print(F("print(bitmap) ..................... "));
3362
3363 clear();
3364 print(bitmap_HEART);
3365 show();
3366
3367 success_temp = true;
3368 for(uint8_t x = 0; x < 5; x++){
3369 uint8_t column = pgm_read_byte_far( bitmap_HEART+x );
3370
3371 for(uint8_t y = 0; y < 7; y++){
3372 uint8_t bitmap_val = bit_table[ bitRead( column, y ) ];
3373
3374 uint16_t index = xy(x+display_padding_x, y+display_padding_y);
3375 uint8_t mask_val = mask[index];
3376
3377 if(bitmap_val != mask_val){
3378 success_temp = false;
3379 }
3380 }
3381 }
3382
3383 if(success_temp){
3384 Serial.println(PASS);
3385 }
3386 else{
3387 Serial.println(FAIL);
3388 success = false;
3389 }
3390
3391 Serial.println(border);
3392
3393 */
3394 // ----------------------------------------------------------------------------------------------------
3395 // @@@@@ print(int16_t) ------------------------------------------------------------------------- @@@@@
3396 // ----------------------------------------------------------------------------------------------------
3397
3398 Serial.println( border );
3399 Serial.print ( testing );
3400 Serial.print(F("print(int16_t) .................. "));
3401
3402 clear();
3403 print(int16_t(-2));
3404 show();
3405
3406 success_temp = true;
3407 for(uint8_t x = 0; x < 5; x++){
3408 char chr = '-';
3410 uint8_t column = pgm_read_byte( font + ( chr * font_col_width + x ) );
3411
3412 for(uint8_t y = 0; y < 7; y++){
3413 uint8_t char_val = bit_table[ bitRead( column, y ) ];
3414
3415 uint16_t index = xy(x+display_padding_x, y+display_padding_y);
3416 uint8_t mask_val = mask[index];
3417
3418 if(char_val != mask_val){
3419 success_temp = false;
3420 }
3421 }
3422 }
3423 for(uint8_t x = 0; x < 5; x++){
3424 char chr = '2';
3426 uint8_t column = pgm_read_byte( font + ( chr * font_col_width + x ) );
3427
3428 for(uint8_t y = 0; y < 7; y++){
3429 uint8_t char_val = bit_table[ bitRead( column, y ) ];
3430
3431 uint16_t index = xy(x+display_padding_x+(display_width*1), y+display_padding_y);
3432 uint8_t mask_val = mask[index];
3433
3434 if(char_val != mask_val){
3435 success_temp = false;
3436 }
3437 }
3438 }
3439 for(uint8_t x = 0; x < 5; x++){
3440 char chr = ' ';
3442 uint8_t column = pgm_read_byte( font + ( chr * font_col_width + x ) );
3443
3444 for(uint8_t y = 0; y < 7; y++){
3445 uint8_t char_val = bit_table[ bitRead( column, y ) ];
3446
3447 uint16_t index = xy(x+display_padding_x+(display_width*2), y+display_padding_y);
3448 uint8_t mask_val = mask[index];
3449
3450 if(char_val != mask_val){
3451 success_temp = false;
3452 }
3453 }
3454 }
3455
3456 if(success_temp){
3457 Serial.println(PASS);
3458 }
3459 else{
3460 Serial.println(FAIL);
3461 success = false;
3462 }
3463
3464 Serial.println(border);
3465
3466
3467 // ----------------------------------------------------------------------------------------------------
3468 // @@@@@ set_cursor(2,3) ------------------------------------------------------------------------ @@@@@
3469 // ----------------------------------------------------------------------------------------------------
3470
3471 Serial.println( border );
3472 Serial.print ( testing );
3473 Serial.print(F("set_cursor(2,3) ................. "));
3474
3475 set_cursor(2,3); // whole displays
3476
3477 if(cursor_x != 15 || cursor_y != 35){ // pixel positions calculated
3478 success = false;
3479 }
3480
3481 if(success){
3482 Serial.println(PASS);
3483 }
3484 else{
3485 Serial.println(FAIL);
3486 Serial.print("cursor: (");
3487 Serial.print(cursor_x);
3488 Serial.print(',');
3489 Serial.println(") != (15,35)");
3490 }
3491
3492 Serial.println(border);
3493
3494
3495 // ----------------------------------------------------------------------------------------------------
3496 // @@@@@ get_cursor_x --------------------------------------------------------------------------- @@@@@
3497 // ----------------------------------------------------------------------------------------------------
3498
3499 Serial.println( border );
3500 Serial.print ( testing );
3501 Serial.print(F("get_cursor_x() .................. "));
3502
3503 if(get_cursor_x() == 2){ // whole displays
3504 Serial.println(PASS);
3505 }
3506 else{
3507 Serial.println(FAIL);
3508 Serial.print(get_cursor_x());
3509 Serial.println(" != 2");
3510 success = false;
3511 }
3512
3513 Serial.println(border);
3514
3515
3516 // ----------------------------------------------------------------------------------------------------
3517 // @@@@@ get_cursor_y --------------------------------------------------------------------------- @@@@@
3518 // ----------------------------------------------------------------------------------------------------
3519
3520 Serial.println( border );
3521 Serial.print ( testing );
3522 Serial.print(F("get_cursor_y() .................. "));
3523
3524 if(get_cursor_y() == 3){ // whole displays
3525 Serial.println(PASS);
3526 }
3527 else{
3528 Serial.println(FAIL);
3529 Serial.print(get_cursor_y());
3530 Serial.println(" != 2");
3531 success = false;
3532 }
3533
3534 Serial.println(border);
3535
3536
3537 // ----------------------------------------------------------------------------------------------------
3538 // @@@@@ get_cursor_x_exact --------------------------------------------------------------------- @@@@@
3539 // ----------------------------------------------------------------------------------------------------
3540
3541 Serial.println( border );
3542 Serial.print ( testing );
3543 Serial.print(F("get_cursor_x_exact() ............ "));
3544
3545 if(get_cursor_x_exact() == 15){ // whole displays
3546 Serial.println(PASS);
3547 }
3548 else{
3549 Serial.println(FAIL);
3550 Serial.print(get_cursor_x_exact());
3551 Serial.println(" != 15");
3552 success = false;
3553 }
3554
3555 Serial.println(border);
3556
3557
3558 // ----------------------------------------------------------------------------------------------------
3559 // @@@@@ get_cursor_y_exact --------------------------------------------------------------------- @@@@@
3560 // ----------------------------------------------------------------------------------------------------
3561
3562 Serial.println( border );
3563 Serial.print ( testing );
3564 Serial.print(F("get_cursor_y_exact() ............ "));
3565
3566 if(get_cursor_y_exact() == 35){ // whole displays
3567 Serial.println(PASS);
3568 }
3569 else{
3570 Serial.println(FAIL);
3571 Serial.print(get_cursor_y_exact());
3572 Serial.println(" != 35");
3573 success = false;
3574 }
3575
3576 Serial.println(border);
3577
3578
3579 // ----------------------------------------------------------------------------------------------------
3580 // @@@@@ clear ---------------------------------------------------------------------------------- @@@@@
3581 // ----------------------------------------------------------------------------------------------------
3582
3583 Serial.println( border );
3584 Serial.print ( testing );
3585 Serial.print(F("clear() ......................... "));
3586
3587 clear();
3588 fail_step = 0;
3589
3590 for(uint16_t i = 0; i < pixel_count; i++){
3591 if(mask[i] != 0){
3592 fail_step = 1;
3593 }
3594 }
3595
3596 if(success_temp){
3597 if(cursor_x != display_padding_x || cursor_y != display_padding_y){ // Default position after clear()
3598 fail_step = 2;
3599 }
3600 }
3601
3602 if(fail_step == 0){
3603 Serial.println(PASS);
3604 }
3605 else{
3606 Serial.println(FAIL);
3607 Serial.println(fail_step);
3608 success = false;
3609 }
3610
3611 Serial.println(border);
3612
3613
3614 Serial.println("\nXY MAP:");
3616
3617 return success;
3618}
#define UNIT_TEST_PIXIES_X
Developer use - unit testing defaults.
Definition: Pixie_Chroma.h:85
#define UNIT_TEST_PIXIES_PER_PIN
Developer use - unit testing defaults.
Definition: Pixie_Chroma.h:83
#define UNIT_TEST_PIXIES_Y
Developer use - unit testing defaults.
Definition: Pixie_Chroma.h:87
This is the software documentation for using Pixie Chroma functions on Arduino! For full example usag...
void color_blur(fract8 blur_amount)
Blurs the color buffer in both axes by blur_amount.
void set_scroll_type(t_scroll_type type)
Sets the scroll behavior:
void shift_color_map_y(int16_t amount)
Shifts the color map data by amount on the Y axis. Useful for scrolling!
void print(uint8_t bitmap_col_1, uint8_t bitmap_col_2, uint8_t bitmap_col_3, uint8_t bitmap_col_4, uint8_t bitmap_col_5)
Prints a bitmap to the displays at the current cursor position, taking five uint8_t as input for the ...
void draw_line_mask(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t value=255)
Draws a line in the mask buffer using Bresenham's line algorithm.
void set_color_animation_speed(float speed)
Used to scale the animation speed of animation ISRs that can use pix.animation_speed() to scale their...
void color(CRGB col)
Sets the entire color buffer to a CRGB value.
float animation_speed
Used by animation functions to scale the apparent speed of animation.
void write(uint8_t bitmap_col_1, uint8_t bitmap_col_2, uint8_t bitmap_col_3, uint8_t bitmap_col_4, uint8_t bitmap_col_5, uint8_t x_pos=0, uint8_t y_pos=0)
Writes a bitmap to a specified X and Y cursor position, taking five uint8_t as input for the column d...
void write_pix(char *message, int16_t x_offset=0, int16_t y_offset=0)
Internal function for rendering char* strings to the mask buffer.
void set_brightness(uint8_t level)
Takes an 8-bit brightness value and passes it to FastLED internally, to provide global brightness con...
PixieChroma()
Construct a Pixie Chroma class object.
void set_color_animation(void(*action)(PixieChroma *, float))
Accepts a preset Color Animation or custom function to use for the animation ISR.
void print_color(CRGB col)
All print() calls after a print_color() will be colored with this value.
float delta
Used by animation functions as a way of self-regulating speed if performance drops,...
float get_uv_y(int32_t y_pixel)
Returns the Y-axis UV coordinate for a given Y-axis pixel position.
CRGB * color_map
Contains the entire color map, including "invisible" areas.
void set_line_wrap(bool enabled)
Sets the line wrapping behavior.
uint16_t led_count
Stores the total number of physical LEDs, not including invisible pixels. This is calculated for you ...
void shift_color_map_x(int16_t amount, int16_t row=-1)
Shifts the color_map data by amount on the X axis. Useful for scrolling or justification!
void print_xy_table()
Prints the index table for the calculated XY map. Requires Serial.begin() first to function.
uint8_t * mask
Contains the entire mask, including "invisible" areas.
void begin(const uint8_t data_pin, uint8_t pixies_x, uint8_t pixies_y)
Initializes the display buffer, populates the XY coordinate table, defaults the display colors to gre...
void free()
Unfreezes the current mask buffer in memory to allow showing updated text the next time show() is cal...
CRGB get_pixel_color(int32_t x, int32_t y)
Gets the RGB color value at a given pixel coordinate.
void blur(fract8 blur_amount)
Blurs the mask buffer in both axes by blur_amount.
void set_pixel_color(int32_t x, int32_t y, CRGB color)
Sets the RGB color value at a given pixel coordinate.
void println(uint8_t bitmap_col_1, uint8_t bitmap_col_2, uint8_t bitmap_col_3, uint8_t bitmap_col_4, uint8_t bitmap_col_5)
Prints a bitmap to the displays at the current cursor position, (taking five uint8_t as input for the...
void clear()
Clears (blackens) the current mask buffer and resets the cursor to 0,0.
uint16_t matrix_width
Stores the final width of the matrix, including invisible pixels.
CRGBPalette16 current_palette
The current FastLED CRGBPalette16 used for animations.
void show()
Processes 1D image data into truncated versions, sending them to the Pixie Chroma displays.
uint8_t get_pixel_mask(int32_t x, int32_t y)
Gets the mask value at a given pixel coordinate.
uint16_t uv(float x, float y, bool wrap=false)
This wrapper function returns the 1D color_map / mask index of a given OpenGL-style UV coordinate in ...
uint8_t get_cursor_y()
Returns the cursor's Y position.
void blur_x(fract8 blur_amount)
Blurs the mask buffer in the X axis by blur_amount.
void shift_mask_x(int16_t amount, int16_t row=-1)
Shifts the mask data by amount on the X axis. Useful for scrolling or justification!
int16_t get_cursor_x_exact()
Returns the cursor's X position in exact pixel coordinates.
uint16_t xy(int32_t x, int32_t y, bool wrap=false)
This function returns the 1D color_map / mask index of a given 2D coordinate in the display matrix.
float get_uv_x(int32_t x_pixel)
Returns the X-axis UV coordinate for a given X-axis pixel position.
void color_blur_y(fract8 blur_amount)
Blurs the color buffer in the Y axis by blur_amount.
bool unit_tests()
Developer use - automated unit testing of PixieChroma code.
void color_blur_x(fract8 blur_amount)
Blurs the color buffer in the X axis by blur_amount.
void draw_line_color(int16_t x1, int16_t y1, int16_t x2, int16_t y2, CRGB color)
Draws a line in the color map using Bresenham's line algorithm.
void color_dim(uint8_t amount)
Darkens the color buffer by an 8-bit amount.
void set_max_power(float volts, uint16_t milliamps)
Sets the maximum power budget in volts and milliamps.
uint16_t matrix_height
Stores the final height of the matrix, including invisible pixels.
void set_pixel_mask(int32_t x, int32_t y, uint8_t value)
Sets the mask value at a given pixel coordinate.
int16_t get_cursor_y_exact()
Returns the cursor's Y position in exact pixel coordinates.
float frame_rate
Allows the user to access a live frame rate calculation (1 frame latency)
void set_frame_rate_target(uint16_t target)
Sets the target frame rate for animation. This target frame rate is only used to calculate delta in c...
void set_palette(const uint8_t *pal)
Accepts a const uint8_t (8-bit) array to generate a FastLED Gradient Palette at runtime:
void dim(uint8_t amount, bool reset_cursor=false)
Darkens the mask buffer by an 8-bit amount. Optionally resets the cursor position.
void set_update_mode(t_update_mode mode, uint16_t FPS=60)
Allows for automatic show() calls at a specified frames per second if AUTOMATIC is used....
void set_cursor(uint8_t x_position, uint8_t y_position=0)
Sets the cursor position in a 2D context, in whole displays.
void shift_mask_y(int16_t amount)
Shifts the mask data by amount on the Y axis. Useful for scrolling!
void add_char(char chr, int16_t x_pos, int16_t y_pos)
Internal function for rendering a single char to the mask buffer.
void scroll_message(char *message, uint8_t row=0)
Scrolls a message across the matrix by constructing it one character at a time in the dead-space outs...
void set_gamma_correction(bool enabled)
Allows you to enable built-in automatic gamma correction, using a fast LUT in pixie_utility....
CRGB kelvin_to_rgb(uint16_t temperature)
Approximates the conversion of a blackbody radiation temperature (i.e. 3500K) to a CRGB color object.
void set_justification(t_justification justification, int16_t row=-1)
Sets the text justification globally, or by row.
void delay(uint32_t milliseconds)
Custom delay() function from FastLED that allows automatic refreshing of the displays during a delay(...
void begin_quad(uint8_t pixies_per_pin, uint8_t pixies_x, uint8_t pixies_y)
Initializes the display buffer, populates the XY coordinate table, defaults the display colors to gre...
uint8_t get_cursor_x()
Returns the cursor's X position.
void blur_y(fract8 blur_amount)
Blurs the mask buffer in the Y axis by blur_amount.
uint16_t pixel_count
Stores the total number of pixels, including invisible pixels.
void hold()
Freezes the current mask buffer in memory to prevent showing unfinished text if show() automaticall f...
void ANIMATION_STATIC(PixieChroma *_p, float delta)
Shows the current color palette without animation.
void ANIMATION_NULL(PixieChroma *_p, float delta)
It does nothing, but it does nothing REALLY WELL! You can enable this empty function with pix....
const uint8_t printable_ascii_offset
Constant defining the offset into the ASCII table that printable characters begin.
Definition: pixie_font.h:16
const uint8_t font_col_width
Constant defining the width of a character.
Definition: pixie_font.h:13
const uint8_t gamma8[]
Used as a fast lookup table for gamma correction.
Definition: pixie_utility.h:37
void(* anim_func)(PixieChroma *_p, float delta)
Used to store the pointer to any preset/custom animation functions the library needs to call during s...
Definition: pixie_utility.h:19
char * dtoa(double input, char *buffer, int precision)
Homebrew C function to convert double precision floats to char*. (Arduino Forum link)
Definition: pixie_utility.h:64