RGB LED cube 5x5x5  1.0
Martin Stejskal, Schmidt Dominik
 All Files Functions Variables Macros Groups Pages
anime_maker_rgb_5x5x5_led_cube.c
Go to the documentation of this file.
1 
13 #define version "1.0 beta"
14 
15 
16 #include <stdio.h> // Standard I/O
17 #include <stdlib.h> // Standard library
18 #include <string.h> // Library for string operations
19 
20 #include <inttypes.h> // Data types
21 
22 //#include <unistd.h> - if needed sleep function
23 
24 #include "settings.h" // Local settings for program
25 
26 #include "animation_codes.h" // Animation codes
27 
28 /*-----------------------------------------*
29  | Function prototypes |
30  *-----------------------------------------*/
31 void ask_for_anime_name(char *p_animation_name);
32 
33 int ask_for_slow_down_factor(void);
34 
35 uint8_t ask_for_pwm(char c_color);
36 
37 
38 void create_files_and_fill_headers(char *p_animation_name);
39 
40 void write_start_of_animation(int i_slowdown_factor, char *p_animation_name);
41 
42 void create_animation(char *p_animation_name, int i_slowdown_factor);
43 
44 void write_end_of_animation(int i_options, char *p_animation_name);
45 
46 void write_frame(uint8_t (*p_fb_data_virtual)[5][5][5],
47  uint16_t (*p_anim_stream)[max_size_anim_stream],
48  uint16_t (*p_commands),
49  uint32_t i_frame);
50 
51 
52 void write_content_to_file(uint16_t (*p_anim_stream)[max_size_anim_stream],
53  uint32_t i_frame,
54  char *p_animation_name);
55 
56 
57 void jump_out_to_next_screen(void);
58 
59 void clear_virtual_framebuffer(uint8_t (*p_fb_data_vitual)[5][5][5]);
60 
61 void set_virtual_framebuffer(uint8_t (*p_fb_data_virtual)[5][5][5]);
62 
63 
64 
65 void clear_real_framebuffer(uint16_t (*p_anim_stream)[max_size_anim_stream]);
66 
67 void show_preview(uint8_t (*p_fb_data_virtual)[5][5][5],
68  uint32_t i_frame_counter,
69  uint8_t i_wall,
70  uint8_t i_column,
71  uint8_t i_led_level,
72  uint8_t i_pwm_r,
73  uint8_t i_pwm_g,
74  uint8_t i_pwm_b,
75  float f_virtual_time);
76 
77 
82 int main(void)
83 {
84 
85  char c_animation_name[name_len]; // Variable for animation name
86 
87  int i_slowdown_factor; // Slowdown factor
88 
89  // Ask for name of animation
90  ask_for_anime_name( c_animation_name );
91 
92  // Create new animation file and fill headers
93  create_files_and_fill_headers( c_animation_name );
94 
95  // Load slowdown factor
96  i_slowdown_factor = ask_for_slow_down_factor();
97 
98  // Write start of animation
99  write_start_of_animation( i_slowdown_factor, c_animation_name );
100 
101  // Create body of animation
102  create_animation( c_animation_name, i_slowdown_factor );
103 
104  // End of animation
105  write_end_of_animation(1, c_animation_name);
106 
107  /*
108  int dec = 32768;
109 
110  printf("\n HEX: %X | DEC: %d\n\n", dec, dec);
111 */
112 
113  return(no_error);
114 }
115 
116 
117 
118 
119 
120 
121 
122 
123 
131 void ask_for_anime_name(char *p_animation_name){
132  printf(""
133 "+---------------------------------------------------------------------------+"
134 "\n"
135 "| Hello and welcome! This is simple animation maker for RGB 5x5x5 LED cube. |"
136 "\n"
137 "| First i need to know name for your animation, so please type animation |"
138 "\n"
139 "| name. Please DO NOT USE spaces! |"
140 "\n"
141 "+---------------------------------------------------------------------------+"
142 "\n| Animation name: ");
143 
144  // get animation name
145  int status = 0;
146  // Load data from keyboard
147  status = scanf("%s", p_animation_name );
148 
149  if( status != 1) // If problem...
150  {
151  printf(""
152 "| !! Sorry, this can not be used as animation name :( |"
153 "\n"
154 "+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx+"
155 "\n");
156 
157  exit( incorrect_input );
158  }
159 
160  printf(""
161 "+---------------------------------------------------------------------------+"
162 "\n");
163 }
164 
165 
166 
167 
168 
169 
170 int ask_for_slow_down_factor(void)
171 {
172  int i_slowdown_factor = 0;
173 
174  printf(""
175 "| OK, now we need slowdown factor. Normally LED cube produce 25 fps. That |"
176 "\n"
177 "| means we need 25 frames for 1 second. However, sometimes is not need to |"
178 "\n"
179 "| have 25 fps. And for this is slowdown factor. If is set to 1, then LED |"
180 "\n"
181 "| cube produce 25 fps. If is set to 2, then 12.5 fps and so on. Maximum |"
182 "\n"
183 "| value should not exceed 255. So please type slowdown factor. |"
184 "\n"
185 "+---------------------------------------------------------------------------+"
186 "\n| Slowdown factor: "
187  );
188 
189  int status = 0;
190 
191  // Read data from keyboard as text... Little bit bigger then needed
192  char c_input_data[default_text_len];
193 
194  while( status != 1 ) // Until name is not valid (one item)
195  {
196  // Load data from keyboard as string
197  status = scanf("%s", c_input_data);
198 
199  status = 1; // Set status to 1 - so far no problem
200 
201  int i;
202  // Scan input data - test if it is number, or not
203  for(i=0 ; i<default_text_len ; i++)
204  { /* Test character - if null (last character) -> break -> in "i" is
205  * length
206  */
207  if( c_input_data[i] == '\0' )
208  {
209  // Test if length is not zero
210  if( i == 0)
211  { // If length is zero -> not a number
212  status = 1;
213  }
214  break;
215  }
216  // Test character - if found anything else than 0~9 -> set status to "0"
217  if( (c_input_data[i]<'0') || (c_input_data[i]>'9'))
218  {
219  status = 0;
220  }
221  }
222 
223  if( status != 1 ) // If problem
224  {
225  printf(""
226 "| !! Sorry. this is not valid number. Please type number from 1 to 255 |"
227 "\n"
228 "| Slowdown factor: ");
229  }
230  else
231  { // If there was no problem -> calculate input number
232  int i_mul = 1; // Multiplier for calculation
233  i_slowdown_factor = 0; // Restart slowdown factor
234 
235  /* Load numbers backward, so it will be easy to calculate them. Variable
236  * "i" is used as counter from last for cycle
237  */
238  for(i=i-1 ; i>=0 ; i--)
239  {
240  /* Calculate value of actual "number" stored in text array and add it
241  * to previous result
242  */
243  i_slowdown_factor = i_slowdown_factor +
244  i_mul * ((c_input_data[i])-'0');
245  i_mul = i_mul * 10; // Multiply multiplier by 10 (decade)
246  }
247  }
248  }
249 
250 
251 
252 
253 
254 
255  // If user type number out of scale
256  if( i_slowdown_factor <= 0 )
257  { // If smaller than limit
258  i_slowdown_factor = 1; // Set minimum
259  printf(""
260 "| ! Warning: Slowdown factor can not be smaller than 1 -> set to 1. |"
261 "\n"
262  );
263  }
264 
265 
266 
267 
268  if( i_slowdown_factor > 255 )
269  {
270  i_slowdown_factor = 255;
271  printf(""
272 "| ! Warning: Slowdown factor can not be greater than 255 -> set to 255. |"
273 "\n"
274  );
275  }
276 
277  return i_slowdown_factor;
278 }
279 
280 
281 
282 
283 
284 
285 
286 
287 
288 uint8_t ask_for_pwm(char c_color)
289 {
290  uint8_t i_pwm_value = 0;
291 
292  // Just because of warning with scanf
293  uint8_t status;
294 
295  // Decide according color
296  switch(c_color)
297  {
298  case 'R': printf("| PWM - RED - value: "); break;
299  case 'r': printf("| PWM - RED - value: "); break;
300  case 'G': printf("| PWM - GREEN - value: "); break;
301  case 'g': printf("| PWM - GREEN - value: "); break;
302  case 'B': printf("| PWM - BLUE - value: "); break;
303  case 'b': printf("| PWM - BLUE - value: "); break;
304  default: printf("| PWM - value: ");
305  }
306 
307 
308  // For saving value - bigger than needed - because of dummy user
309  char c_value[15];
310 
311  // Scan input until there will not be valid data
312  while(1)
313  {
314  status = scanf("%s", c_value); // Load new value
315  if(status == 0) // If something is wrong
316  {
317  printf("\nPruser\n");
318  c_value[0]='\0'; // Set first character to NULL -> not a number
319  }
320 
321 
322  /* Maximum value can be set to 255 -> scan just first 3 bytes for null
323  * character. If not found -> presume length is 3 digits and other
324  * bytes throw
325  */
326  // Test if it could be number, or just dummy string
327  if( (c_value[0]>='0' || c_value[0]<='9') &&
328  (c_value[1]>='0' || c_value[1]<='9') &&
329  (c_value[2]>='0' || c_value[2]<='9') )
330  {
331  // Test if "second" character is NULL and first is number
332  if(c_value[1]=='\0')
333  {// In this case is length 1 -> easy to calculate
334  // Create command -> command number + value
335  // (ASCII value - ASCII number for 0)
336  i_pwm_value = (c_value[0]-'0');
337  break;
338  }
339  else if(c_value[2]=='\0')
340  {// Little bit tricky. First load [0] - 10x and then [1] - 1x
341  i_pwm_value = 10 * (c_value[0]-'0');
342  i_pwm_value = i_pwm_value + (c_value[1]-'0');
343  break; // Go out of the while (data valid)
344  }
345  else
346  {// Else assume that there is only 3 digit number
347  i_pwm_value = 100 * (c_value[0]-'0'); // 100x
348  i_pwm_value = i_pwm_value + 10 * (c_value[1]-'0'); // 10x
349  i_pwm_value = i_pwm_value + (c_value[2]-'0'); // 1x
350 
351  // Test if i_pwm_value
352  if(i_pwm_value > 255)
353  {
354  printf(""
355 "| ! Warning: PWM value can not be greater than 255 -> set 255. |"
356 "\n");
357  }
358  break;
359  }
360 
361  }
362  // If not possibly number -> printf message
363  printf(""
364 "| !! Sorry. this is not valid number. Please type number from 1 to 255 |"
365 "\n");
366 
367  // And print something extra depends on color
368  // Decide according color
369  switch(c_color)
370  {
371  case 'R': printf("\n| PWM - RED - value: "); break;
372  case 'r': printf("\n| PWM - RED - value: "); break;
373  case 'G': printf("\n| PWM - GREEN - value: "); break;
374  case 'g': printf("\n| PWM - GREEN - value: "); break;
375  case 'B': printf("\n| PWM - BLUE - value: "); break;
376  case 'b': printf("\n| PWM - BLUE - value: "); break;
377  default: printf("\n| PWM - value: ");
378  }
379  }// End while
380 
381 
382  return i_pwm_value;
383 }
384 
385 
386 
387 
388 
389 
390 
391 
399 void create_files_and_fill_headers(char *p_animation_name)
400 {
401  FILE *file; // Pointer to file
402 
403  // String for complete path (include filename and extension -> +2)
404  char c_file_and_path[name_len + path_len +2];
405 
406 
407  // Save string contains name of anime folder
408  strcpy(c_file_and_path, generated_anime_folder);
409  // Add slash and prefix anim
410  strcat(c_file_and_path, "/anim_");
411  // Add file name
412  strcat(c_file_and_path, p_animation_name);
413  // Add ".h"
414  strcat(c_file_and_path, ".h");
415 
416  // Open file - .h file (overwrite mode)
417  file = fopen( c_file_and_path, "w+");
418 
419  char c_file_content[3000];
420 
421  // OK, now fill content for .h file
422  strcpy(c_file_content, "\\n\
439 \n\
440 #ifndef _anim_");
441  strcat(c_file_content, p_animation_name);
442  strcat(c_file_content, "_library_\n#define _anim_");
443  strcat(c_file_content, p_animation_name);
444  strcat(c_file_content, "_library_\n\n"
445 "/*-----------------------------------------*\n"
446 " | Includes |\n"
447 " *-----------------------------------------*/\n"
448 "#include <avr/pgmspace.h> // For operations with flash memory\n"
449 "#include <inttypes.h> // Data types\n"
450 "\n"
451 "#include \"animation_codes.h\" // For more \"human read\" animation code\n"
452 "\n"
453 "extern const uint16_t bin_anim_");
454  strcat(c_file_content, p_animation_name);
455  strcat(c_file_content, "[];\n"
456 "\n"
457 "#endif\n");
458 
459  // Write content to file
460  fprintf(file, "%s", c_file_content);
461 
462  // Close .h file
463  fclose(file);
464 
465 
466 
467 
468 
469 
470  // Save string contains name of anime folder
471  strcpy(c_file_and_path, generated_anime_folder);
472  // Add slash and prefix anim
473  strcat(c_file_and_path, "/anim_");
474  // Add file name
475  strcat(c_file_and_path, p_animation_name);
476  // Add ".c"
477  strcat(c_file_and_path, ".c");
478 
479  // Open file - .c file (overwrite mode)
480  file = fopen( c_file_and_path, "w+");
481 
482  // OK, now fill content for .c file
483  strcpy(c_file_content, "\\n"
500 "\n"
501 "#include \"anim_");
502  strcat(c_file_content, p_animation_name);
503  strcat(c_file_content, ".h\"\n"
504 "\n"
505 "/* Data format (binary data for framebuffer)\n"
506 " * |MSB| |LSB|MSB| |LSB|MSB| |LSB|\n"
507 " * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\n"
508 " * | 0 | R | R | R | R | R | G | G | G | G | G | B | B | B | B | B |\n"
509 " * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\n"
510 " *\n"
511 " * Instruction format (if MSB is 1, then it is possible change some settings)"
512 "\n * |MSB| |LSB|MSB| |LSB|MSB| |LSB|\n"
513 " * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\n"
514 " * | 1 | C | C | C | C | C | C | C | V | V | V | V | V | V | V | V |\n"
515 " * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\n"
516 " * C - command (0~127)\n"
517 " * V - value (0~255)\n"
518 " *\n"
519 " */\n"
520 "const uint16_t bin_anim_");
521 
522  strcat(c_file_content, p_animation_name);
523  strcat(c_file_content, "[] PROGMEM =\n { // Serial stream of data\n");
524 
525  // Write content to file
526  fprintf(file, "%s", c_file_content);
527 
528  // Close .c file
529  fclose(file);
530 }
531 
532 
533 
534 
540 void write_start_of_animation(int i_slowdown_factor, char *p_animation_name)
541 {
542  // Test for input parameters
543  if( (i_slowdown_factor > 255) || (i_slowdown_factor < 0))
544  {
545  i_slowdown_factor = 0; // If input variable is out of range
546  printf(""
547 "| ! Warning: i_slowdown_factor out of range. Set to 0 (default) |"
548 "\n"
549  );
550  }
551 
552 
553  FILE *file; // Pointer to file
554 
555  // String for complete path (include filename and extension -> +2)
556  char c_file_and_path[name_len + path_len +2];
557 
558 
559  // Save string contains name of anime folder
560  strcpy(c_file_and_path, generated_anime_folder);
561  // Add slash and prefix anim
562  strcat(c_file_and_path, "/anim_");
563  // Add file name
564  strcat(c_file_and_path, p_animation_name);
565  // Add ".c"
566  strcat(c_file_and_path, ".c");
567 
568  // Open file - .c file (append mode)
569  file = fopen( c_file_and_path, "a+");
570 
571  char c_file_content[256];
572 
573  strcpy(c_file_content, ""
574 " // Command start of animation + value (slowdown factor)\n"
575 " cmd_anim_start + "
576  );
577 
578  // Transform i_slowdown_factor to string number
579  char c_number_as_text[4];
580  sprintf( c_number_as_text, "%d", i_slowdown_factor);
581 
582  strcat(c_file_content, c_number_as_text);
583  strcat(c_file_content, ",\n //Data + other commands (body)\n");
584 
585  // Write content to file
586  fprintf(file, "%s", c_file_content);
587 
588  fclose(file);
589 }
590 
591 
592 
593 
594 
595 
596 
597 
598 
599 void create_animation(char *p_animation_name, int i_slowdown_factor)
600 {
601  // Info for user
602  printf(""
603 "+---------------------------------------------------------------------------+"
604 "\n"
605 "| So, now i enable creative mode ;) There you can build your own animation. |"
606 "\n"
607 "| Ready? If yes, then enter |"
608 "\n"
609 "+---------------------------------------------------------------------------+"
610 "\n"
611  );
612 
613  getchar(); // Before flush must be read, else not work as expected
614  fflush(stdin);// Clean input buffer
615 
616  char c_pressed_key = '\0';
617 
618  // Wait until any key pressed
619  while( c_pressed_key == '\0')
620  {
621  c_pressed_key = getchar();
622  }
623 
624 
625  // Create some variables
626  uint32_t i_frame_counter = 0; // Counts whole frames
627  uint8_t i_wall = 0; // Number of active "wall" on LED cube
628  uint8_t i_column = 0; // Active column on LED cube
629 
630  uint8_t i_pwm_r = 255; // PWM value for red LEDs
631  uint8_t i_pwm_g = 255; // PWM value for green LEDs
632  uint8_t i_pwm_b = 255; // PWM value for blue LEDs
633 
634  float f_virtual_time = 0; // Virtual time of animation
635 
636  uint8_t i_led_level = 4; // Highest LED
637 
638  // Virtual framebuffer (just for preview)
639  // [wall][led level][column]
640  uint8_t i_fb_data_virtual[5][5][5];
641 
642  // "Real" stream for LED cube
643  uint16_t i_anim_stream[max_size_anim_stream];
644 
645  // Clear virtual framebuffer
646  clear_virtual_framebuffer( &i_fb_data_virtual );
647 
648  // Clear real framebuffer
649  clear_real_framebuffer( &i_anim_stream );
650 
651  // Array for commands (per whole frame)
652  uint16_t i_commands[max_commands_per_frame];
653 
654  // Clear first in array
655  i_commands[0] = 0; // No command so far
656 
657  // Index for counting commands
658  uint8_t i_command_index = 0;
659 
660  // Status variable
661  int status = 0;
662 
663  // Text array for command
664  char c_cmd[max_command_length];
665 
666 
667  int animation_done = 0;
668  // Wait until animation is done
669  while( animation_done == 0 )
670  {
671  // Clear screen
673  // Show actual data
674  show_preview( &i_fb_data_virtual,
675  i_frame_counter,
676  i_wall,
677  i_column,
678  i_led_level,
679  i_pwm_r,
680  i_pwm_g,
681  i_pwm_b,
682  f_virtual_time);
683 
684  // Clear - for case that previous command will be shorter than 3 characters
685  for(int i=0 ; i<max_command_length ; i++)
686  {
687  c_cmd[i] = '\0';
688  }
689 
690  status = scanf("%s", c_cmd);
691  // OK, let's test for possible commands
692 
693 
694  // EXIT
695  if( (strcmp(c_cmd,"exit")==0) ||
696  (strcmp(c_cmd,"Exit")==0) ||
697  (strcmp(c_cmd,"EXIT")==0) ||
698  (strcmp(c_cmd,"e") ==0) )
699  {// Exit - everything is done. Just break while condition
700  animation_done = 1;
701  }
702 
703  // ZEROS
704  if( (strcmp(c_cmd,"zeros")==0) ||
705  (strcmp(c_cmd,"Zeros")==0) ||
706  (strcmp(c_cmd,"ZEROS")==0) )
707  {
708  status = pressed_button; // Do not change position of cursor
709  for(int j=0 ; j<5 ; j++)
710  {
711  for(int k=0 ; k<5 ; k++)
712  {
713  i_fb_data_virtual[i_wall][j][k] = 0;
714  }
715  }
716  }
717 
718  // ONES
719  if( (strcmp(c_cmd,"ones")==0) ||
720  (strcmp(c_cmd,"Ones")==0) ||
721  (strcmp(c_cmd,"ONES")==0) )
722  {
723  status = pressed_button; // Do not change position of cursor
724  for(int j=0 ; j<5 ; j++)
725  {
726  for(int k=0 ; k<5 ; k++)
727  {
728  i_fb_data_virtual[i_wall][j][k] = (1<<red_shift)|
729  (1<<green_shift)|
730  (1<<blue_shift);
731  }
732  }
733  }
734 
735  // PWM red
736  if( (strcmp(c_cmd,"pwmr")==0) ||
737  (strcmp(c_cmd,"Pwmr")==0) ||
738  (strcmp(c_cmd,"PWMR")==0) )
739  {// And ask for value
740  i_pwm_r = ask_for_pwm('R');
741  // And create command
742  i_commands[i_command_index++] = cmd_set_pwm_r + i_pwm_r;
743  }
744 
745  // PWM green
746  if( (strcmp(c_cmd,"pwmg")==0) ||
747  (strcmp(c_cmd,"Pwmg")==0) ||
748  (strcmp(c_cmd,"PWMG")==0) )
749  {// And ask for value
750  i_pwm_g = ask_for_pwm('G');
751  // And create command
752  i_commands[i_command_index++] = cmd_set_pwm_g + i_pwm_g;
753  }
754 
755  // PWM blue
756  if( (strcmp(c_cmd,"pwmb")==0) ||
757  (strcmp(c_cmd,"Pwmb")==0) ||
758  (strcmp(c_cmd,"PWMB")==0) )
759  {// And ask for value
760  i_pwm_b = ask_for_pwm('B');
761  // And create command
762  i_commands[i_command_index++] = cmd_set_pwm_b + i_pwm_b;
763  }
764 
765  // LINE
766  if( (strcmp(c_cmd,"line")==0) ||
767  (strcmp(c_cmd,"Line")==0) ||
768  (strcmp(c_cmd,"LINE")==0) ||
769  (strcmp(c_cmd,"l") ==0) )
770  {
771  status = pressed_button; // Do not change position of cursor
772 
773  // Grab actual segment and copy it
774  uint8_t i_segment = i_fb_data_virtual[i_wall][i_led_level][i_column];
775  // And copy it thru actual 2D frame
776  for(int i=0 ; i<5 ; i++)
777  {
778  i_fb_data_virtual[i_wall][i_led_level][i] = i_segment;
779  }
780  }
781 
782  // COLUMN
783  if( (strcmp(c_cmd,"column")==0) ||
784  (strcmp(c_cmd,"Column")==0) ||
785  (strcmp(c_cmd,"COLUMN")==0) ||
786  (strcmp(c_cmd,"c") ==0) )
787  {
788  status = pressed_button; // Do not change position of cursor
789 
790  // Grab actual segment and copy it
791  uint8_t i_segment = i_fb_data_virtual[i_wall][i_led_level][i_column];
792  // And copy it thru actual 2D frame
793  for(int i=0 ; i<5 ; i++)
794  {
795  i_fb_data_virtual[i_wall][i][i_column] = i_segment;
796  }
797  }
798 
799 
800  // ARROW UP
801  if( c_cmd[0]==27 && c_cmd[1]==91 && c_cmd[2]==65 && c_cmd[3]==0)
802  {
803  // Signalizes, that button was pressed
804  status = pressed_button;
805 
806  i_led_level++; // Increase LED level
807  if(i_led_level>4) // If greater than 4 (should not be)
808  {
809  i_led_level=0; // Set to zero
810  }
811  }
812 
813  // ARROW DOWN
814  if( c_cmd[0]==27 && c_cmd[1]==91 && c_cmd[2]==66 && c_cmd[3]==0)
815  {
816  // Signalizes, that button was pressed
817  status = pressed_button;
818 
819  i_led_level--; // Decrease LED level
820  if(i_led_level==255) // If smaller than 0 (should not be)
821  {
822  i_led_level=4; // Set to highest level again
823  }
824  }
825 
826  // ARROW RIGHT
827  if( c_cmd[0]==27 && c_cmd[1]==91 && c_cmd[2]==67 && c_cmd[3]==0)
828  {
829  // Signalizes, that button was pressed
830  status = pressed_button;
831 
832  i_column++;
833  if(i_column>4)
834  {
835  i_column = 0;
836  }
837  }
838 
839  // ARROW LEFT
840  if( c_cmd[0]==27 && c_cmd[1]==91 && c_cmd[2]==68 && c_cmd[3]==0)
841  {
842  // Signalizes, that button was pressed
843  status = pressed_button;
844 
845  i_column--;
846  if(i_column==255)
847  {
848  i_column = 4;
849  }
850  }
851 
852  // NEXT (2D frame - wall)
853  if( (strcmp(c_cmd,"next")==0) ||
854  (strcmp(c_cmd,"Next")==0) ||
855  (strcmp(c_cmd,"NEXT")==0) ||
856  (strcmp(c_cmd,"n") ==0) )
857  {
858  // Signalizes, that button was pressed
859  status = pressed_button;
860 
861  i_column = 0;
862  i_led_level = 4;
863  i_wall++; // Move to next wall
864  // And check wall
865  if(i_wall>4)
866  {
867  i_commands[i_command_index] = 0; // On the last position write 0
868  // And load data to "real buffer"
869  write_frame(&i_fb_data_virtual,
870  &i_anim_stream,
871  i_commands,
872  i_frame_counter);
873 
874  i_command_index = 0; // After write reset
875  i_wall=0;
876  i_frame_counter++; // Next frame -> increase
877  // Recalculate time
878  f_virtual_time = f_virtual_time + (frame_period*i_slowdown_factor);
879  }
880  }
881 
882  // BACK (2D frame - wall)
883  if( (strcmp(c_cmd,"back")==0) ||
884  (strcmp(c_cmd,"Back")==0) ||
885  (strcmp(c_cmd,"BACK")==0) ||
886  (strcmp(c_cmd,"m") ==0) )
887  {
888  // Signalizes, that button was pressed
889  status = pressed_button;
890 
891  i_column = 0;
892  i_led_level = 4;
893  i_wall--; // Move to previous wall
894  // And check wall
895  if(i_wall>4)
896  {
897  i_wall = 0;
901  }
902  }
903 
904 
905 
906 
907 
908 
909 
910 
911 
912 
913 
914 
915  // DATA - global - test if there is at least one combination
916  if(((c_cmd[0]=='A' || c_cmd[0]=='a' || c_cmd[0]=='1' ||
917  c_cmd[0]=='R' || c_cmd[0]=='G' || c_cmd[0]=='B' ||
918  c_cmd[0]=='r' || c_cmd[0]=='g' || c_cmd[0]=='b' ||
919  c_cmd[0]=='0' || c_cmd[0]=='-') ||
920 
921  (c_cmd[1]=='1' ||
922  c_cmd[1]=='R' || c_cmd[1]=='G' || c_cmd[1]=='B' ||
923  c_cmd[1]=='r' || c_cmd[1]=='g' || c_cmd[1]=='b' ||
924  c_cmd[1]=='0' || c_cmd[1]=='-') ||
925 
926  (c_cmd[2]=='1' ||
927  c_cmd[2]=='R' || c_cmd[2]=='G' || c_cmd[2]=='B' ||
928  c_cmd[2]=='r' || c_cmd[2]=='g' || c_cmd[2]=='b' ||
929  c_cmd[2]=='0' || c_cmd[2]=='-')) &&
930 
931  // If some arrow pressed, then there can be symbol A,B,C or D, so...
932  ( status != pressed_button ) &&
933  ( c_cmd[0]!=27 ) && (c_cmd[1]!=91) && (c_cmd[3]!=27) && (c_cmd[4]!=91)
934  &&
935  (c_cmd[0]!='\0'))
936  {
937  // Write data to buffer
938  i_fb_data_virtual[i_wall][i_led_level][i_column] = 0; // Set to 0
939 
940  // And now add data
941  // Test if was set red color
942  if( c_cmd[0]=='r' || c_cmd[0]=='R' || c_cmd[0]=='a' || c_cmd[0]=='A' ||
943  c_cmd[1]=='r' || c_cmd[1]=='R' || c_cmd[0]=='1' ||
944  c_cmd[2]=='r' || c_cmd[2]=='R' )
945  {// If was set red bit -> add it
946  i_fb_data_virtual[i_wall][i_led_level][i_column] |= (1<<red_shift);
947  }
948 
949  // Test for "green bit"
950  if( c_cmd[0]=='g' || c_cmd[0]=='G' || c_cmd[0]=='a' || c_cmd[0]=='A' ||
951  c_cmd[1]=='g' || c_cmd[1]=='G' || c_cmd[1]=='1' ||
952  c_cmd[2]=='g' || c_cmd[2]=='G' )
953  {// If was set red bit -> add it
954  i_fb_data_virtual[i_wall][i_led_level][i_column] |= (1<<green_shift);
955  }
956  // And test for "blue bit"
957  if( c_cmd[0]=='b' || c_cmd[0]=='B' || c_cmd[0]=='a' || c_cmd[0]=='A' ||
958  c_cmd[1]=='b' || c_cmd[1]=='B' || c_cmd[2]=='1' ||
959  c_cmd[2]=='b' || c_cmd[2]=='B' )
960  {// If was set red bit -> add it
961  i_fb_data_virtual[i_wall][i_led_level][i_column] |= (1<<blue_shift);
962  }
963 
964 
965 
966 
967 
968  // Change index only if was not pressed any arrow button
969  if( status != pressed_button )
970  {
971  // Change index
972  i_column++; // Increase column number
973  }
974 
975 
976  if(i_column>4)
977  {
978  i_column=0; // Set to "first" colummn
979 
980  i_led_level--; // Decrease LED level
981  if(i_led_level==255) // If smaller than 0 (should not be)
982  {
983  i_led_level=4; // Set to highest level again
984  i_wall++; // Move to next wall
985  // And check wall
986  if(i_wall>4)
987  {
988  i_commands[i_command_index] = 0; // On the last position write 0
989  // And load data to "real buffer"
990  write_frame(&i_fb_data_virtual,
991  &i_anim_stream,
992  i_commands,
993  i_frame_counter);
994 
995  i_wall=0;
996 
997  i_command_index = 0; // After write reset command index
998 
999  i_frame_counter++; // Next frame -> increase
1000  // Recalculate time
1001  f_virtual_time = f_virtual_time + (frame_period*i_slowdown_factor);
1002  }
1003  }
1004  }
1005  }
1006 
1007 
1008  }
1009 
1010 
1011 
1012 
1013  // OK, now write data to file
1014  write_content_to_file( &i_anim_stream, i_frame_counter, p_animation_name);
1015 
1016  // String for complete path (include filename and extension -> +2)
1017  char c_file_and_path[name_len + path_len +2];
1018 
1019  // Save string contains name of anime folder
1020  strcpy(c_file_and_path, generated_anime_folder);
1021  // Add slash and prefix anim
1022  strcat(c_file_and_path, "/anim_");
1023  // Add file name
1024  strcat(c_file_and_path, p_animation_name);
1025 
1026 
1027  printf(""
1028 "+---------------------------------------------------------------------------+"
1029 "\n"
1030 "| Your animation files are: |"
1031 "\n"
1032 "| ./%s.c\n| ./%s.h\n"
1033 "+---------------------------------------------------------------------------+"
1034 "\n"
1035 " BYE!\n"
1036  ,c_file_and_path, c_file_and_path);
1037 
1038 }
1039 
1040 
1041 
1042 
1043 
1044 
1052 void write_frame(uint8_t (*p_fb_data_virtual)[5][5][5],
1053  uint16_t (*p_anim_stream)[max_size_anim_stream],
1054  uint16_t (*p_commands),
1055  uint32_t i_frame)
1056 {
1057  // Counts columns. If reached 25 (overflow) -> one frame
1058  uint8_t i_column_cnt = 0;
1059 
1060  // Counts found fames
1061  uint32_t i_actual_frame = 0;
1062 
1063  // Counter for stream index
1064  uint64_t i_index_cnt = 0;
1065 
1066  // Loaded word from stream
1067  uint16_t i_anime_word;
1068 
1069  // First we need to find where to continue write data
1070  while( (i_actual_frame < i_frame) & (i_frame != 0) )
1071  {
1072  // Load first anime_word
1073  i_anime_word = (*p_anim_stream)[i_index_cnt];
1074 
1075  // Increase counter (next time load following word)
1076  i_index_cnt++;
1077 
1078  // Test if i_anime_word is data (increase i_column_cnt) or command
1079  if( (i_anime_word & 0x8000)==0 )
1080  {// If data -> increase i_column_cnt
1081  i_column_cnt++;
1082 
1083  // Ok, test if i_column_cnt is not 25 -> overflow -> next frame
1084  if(i_column_cnt == 25)
1085  {
1086  // If yes, then restart i_column_cnt
1087  i_column_cnt = 0;
1088 
1089  // And increase i_actual_frame
1090  i_actual_frame++;
1091  }
1092 
1093  }
1094  // Else command do nothing
1095  }
1096 
1097  // OK, if we are out of while, then we add data from framebuffer
1098  i_anime_word = (*p_commands); // Load first command
1099 
1100 
1101  // First write commands - write until there are commands
1102  while( (i_anime_word & 0x8000) != 0 )
1103  {
1104  (*p_anim_stream)[i_index_cnt] = i_anime_word;
1105  i_index_cnt++;
1106 
1107  // Increase pointer;
1108  p_commands++;
1109  // And load next command
1110  i_anime_word = (*p_commands);
1111  }
1112 
1113  // Now data
1114  for(int i=0 ; i<5 ; i++) // Walls
1115  {
1116  for(int j=0 ; j<5 ; j++) // Columns
1117  {
1118  // Clear variable
1119  i_anime_word = 0;
1120 
1121  for(int k=0 ; k<5 ; k++) // LED level
1122  {
1123  // Red Color
1124  i_anime_word |= // Add data
1125  (((*p_fb_data_virtual)[i][k][j]) & (0b100)) // Masking
1126  <<((red_shift*5)+k-red_shift); // And bit shift
1127 
1128  // Red Green
1129  i_anime_word |= // Add data
1130  (((*p_fb_data_virtual)[i][k][j]) & (0b010)) // Masking
1131  <<((green_shift*5)+k-green_shift); // And bit shift
1132 
1133  // Red Blue
1134  i_anime_word |= // Add data
1135  (((*p_fb_data_virtual)[i][k][j]) & (0b001)) // Masking
1136  <<((blue_shift*5)+k-blue_shift); // And bit shift
1137  }
1138 
1139  // Write 16 bits
1140  (*p_anim_stream)[i_index_cnt++] = i_anime_word;
1141  }
1142  }
1143 }
1144 
1145 
1154 void write_content_to_file(uint16_t (*p_anim_stream)[max_size_anim_stream],
1155  uint32_t i_frame,
1156  char *p_animation_name)
1157 {
1158  // Open file...
1159  FILE *file; // Pointer to file
1160 
1161  // String for complete path (include filename and extension -> +2)
1162  char c_file_and_path[name_len + path_len +2];
1163 
1164  // Save string contains name of anime folder
1165  strcpy(c_file_and_path, generated_anime_folder);
1166  // Add slash and prefix anim
1167  strcat(c_file_and_path, "/anim_");
1168  // Add file name
1169  strcat(c_file_and_path, p_animation_name);
1170  // Add ".c"
1171  strcat(c_file_and_path, ".c");
1172 
1173  // Open file - .c file (append mode)
1174  file = fopen( c_file_and_path, "a+");
1175 
1176 
1177  // Temporary text string (for writing "one line")
1178  char c_tmp_txt[512];
1179 
1180  fprintf(file, " // Frame 0\n "); // Write to file
1181 
1182 
1183  // Temporary string for transformation integer to string
1184  char c_tmp_num[10];
1185 
1186  // Counts written frame
1187  uint32_t i_actual_frame = 0;
1188 
1189  // Counts actual wall
1190  uint8_t i_actual_wall = 0;
1191 
1192  // Counts actual column
1193  uint8_t i_actual_column = 0;
1194 
1195  // Counts words in p_anim_stream (used index)
1196  uint64_t i_word_index = 0;
1197 
1198  // Word read from anime stream
1199  uint16_t i_anime_word;
1200 
1201  /* Inform if there were made any frame compression thru command -> if yes,
1202  * then do not test for other compression
1203  */
1204  uint8_t i_command_created = 0;
1205 
1206  /* Write frame-by-frame (include special commands) - until all frames are
1207  * written
1208  */
1209  while( i_actual_frame < i_frame )
1210  {
1211  // Read word
1212  i_anime_word = (*p_anim_stream)[i_word_index];
1213 
1214  // No command was created. At least for this cycle....
1215  i_command_created = 0;
1216 
1217 
1218  /* Test if actual 3D frame is void. If yes, then create special command.
1219  */
1220  if( (*p_anim_stream)[i_word_index+ 0] == 0 &&
1221  (*p_anim_stream)[i_word_index+ 1] == 0 &&
1222  (*p_anim_stream)[i_word_index+ 2] == 0 &&
1223  (*p_anim_stream)[i_word_index+ 3] == 0 &&
1224  (*p_anim_stream)[i_word_index+ 4] == 0 &&
1225  (*p_anim_stream)[i_word_index+ 5] == 0 &&
1226  (*p_anim_stream)[i_word_index+ 6] == 0 &&
1227  (*p_anim_stream)[i_word_index+ 7] == 0 &&
1228  (*p_anim_stream)[i_word_index+ 8] == 0 &&
1229  (*p_anim_stream)[i_word_index+ 9] == 0 &&
1230  (*p_anim_stream)[i_word_index+10] == 0 &&
1231  (*p_anim_stream)[i_word_index+11] == 0 &&
1232  (*p_anim_stream)[i_word_index+12] == 0 &&
1233  (*p_anim_stream)[i_word_index+13] == 0 &&
1234  (*p_anim_stream)[i_word_index+14] == 0 &&
1235  (*p_anim_stream)[i_word_index+15] == 0 &&
1236  (*p_anim_stream)[i_word_index+16] == 0 &&
1237  (*p_anim_stream)[i_word_index+17] == 0 &&
1238  (*p_anim_stream)[i_word_index+18] == 0 &&
1239  (*p_anim_stream)[i_word_index+19] == 0 &&
1240  (*p_anim_stream)[i_word_index+20] == 0 &&
1241  (*p_anim_stream)[i_word_index+21] == 0 &&
1242  (*p_anim_stream)[i_word_index+22] == 0 &&
1243  (*p_anim_stream)[i_word_index+23] == 0 &&
1244  (*p_anim_stream)[i_word_index+24] == 0 &&
1245  // Must be at begin of 3D frame
1246  (i_actual_column == 0) && (i_actual_wall == 0) &&
1247  (i_command_created == 0))
1248  {
1249  i_anime_word = cmd_param_3D_frame + param_3D_frame_void;
1250  i_word_index = i_word_index +24;
1251  i_actual_wall = 5; /* Overflow -> when process command, then
1252  * do necessary routine
1253  */
1254 
1255  i_command_created = 1;
1256  }
1257 
1258 
1259  /* Test if actual 3D frame is full of ones. If yes, then create special
1260  * command.
1261  */
1262  if( (*p_anim_stream)[i_word_index+ 0] == 0x7FFF &&
1263  (*p_anim_stream)[i_word_index+ 1] == 0x7FFF &&
1264  (*p_anim_stream)[i_word_index+ 2] == 0x7FFF &&
1265  (*p_anim_stream)[i_word_index+ 3] == 0x7FFF &&
1266  (*p_anim_stream)[i_word_index+ 4] == 0x7FFF &&
1267  (*p_anim_stream)[i_word_index+ 5] == 0x7FFF &&
1268  (*p_anim_stream)[i_word_index+ 6] == 0x7FFF &&
1269  (*p_anim_stream)[i_word_index+ 7] == 0x7FFF &&
1270  (*p_anim_stream)[i_word_index+ 8] == 0x7FFF &&
1271  (*p_anim_stream)[i_word_index+ 9] == 0x7FFF &&
1272  (*p_anim_stream)[i_word_index+10] == 0x7FFF &&
1273  (*p_anim_stream)[i_word_index+11] == 0x7FFF &&
1274  (*p_anim_stream)[i_word_index+12] == 0x7FFF &&
1275  (*p_anim_stream)[i_word_index+13] == 0x7FFF &&
1276  (*p_anim_stream)[i_word_index+14] == 0x7FFF &&
1277  (*p_anim_stream)[i_word_index+15] == 0x7FFF &&
1278  (*p_anim_stream)[i_word_index+16] == 0x7FFF &&
1279  (*p_anim_stream)[i_word_index+17] == 0x7FFF &&
1280  (*p_anim_stream)[i_word_index+18] == 0x7FFF &&
1281  (*p_anim_stream)[i_word_index+19] == 0x7FFF &&
1282  (*p_anim_stream)[i_word_index+20] == 0x7FFF &&
1283  (*p_anim_stream)[i_word_index+21] == 0x7FFF &&
1284  (*p_anim_stream)[i_word_index+22] == 0x7FFF &&
1285  (*p_anim_stream)[i_word_index+23] == 0x7FFF &&
1286  (*p_anim_stream)[i_word_index+24] == 0x7FFF &&
1287  // Must be at begin of 3D frame
1288  (i_actual_column == 0) && (i_actual_wall == 0) &&
1289  (i_command_created == 0))
1290  {
1291  i_anime_word = cmd_param_3D_frame + param_3D_frame_ones;
1292  i_word_index = i_word_index +24;
1293  i_actual_wall = 5; /* Overflow -> when process command, then
1294  * do necessary routine
1295  */
1296  i_command_created = 1;
1297  }
1298 
1299 
1300  /* Test if actual 3D frame is same as previous. If yes, then create special
1301  * command.
1302  */
1303  if(
1304  (*p_anim_stream)[i_word_index+ 0] == (*p_anim_stream)[i_word_index-25] &&
1305  (*p_anim_stream)[i_word_index+ 1] == (*p_anim_stream)[i_word_index-24] &&
1306  (*p_anim_stream)[i_word_index+ 2] == (*p_anim_stream)[i_word_index-23] &&
1307  (*p_anim_stream)[i_word_index+ 3] == (*p_anim_stream)[i_word_index-22] &&
1308  (*p_anim_stream)[i_word_index+ 4] == (*p_anim_stream)[i_word_index-21] &&
1309  (*p_anim_stream)[i_word_index+ 5] == (*p_anim_stream)[i_word_index-20] &&
1310  (*p_anim_stream)[i_word_index+ 6] == (*p_anim_stream)[i_word_index-19] &&
1311  (*p_anim_stream)[i_word_index+ 7] == (*p_anim_stream)[i_word_index-18] &&
1312  (*p_anim_stream)[i_word_index+ 8] == (*p_anim_stream)[i_word_index-17] &&
1313  (*p_anim_stream)[i_word_index+ 9] == (*p_anim_stream)[i_word_index-16] &&
1314  (*p_anim_stream)[i_word_index+10] == (*p_anim_stream)[i_word_index-15] &&
1315  (*p_anim_stream)[i_word_index+11] == (*p_anim_stream)[i_word_index-14] &&
1316  (*p_anim_stream)[i_word_index+12] == (*p_anim_stream)[i_word_index-13] &&
1317  (*p_anim_stream)[i_word_index+13] == (*p_anim_stream)[i_word_index-12] &&
1318  (*p_anim_stream)[i_word_index+14] == (*p_anim_stream)[i_word_index-11] &&
1319  (*p_anim_stream)[i_word_index+15] == (*p_anim_stream)[i_word_index-10] &&
1320  (*p_anim_stream)[i_word_index+16] == (*p_anim_stream)[i_word_index- 9] &&
1321  (*p_anim_stream)[i_word_index+17] == (*p_anim_stream)[i_word_index- 8] &&
1322  (*p_anim_stream)[i_word_index+18] == (*p_anim_stream)[i_word_index- 7] &&
1323  (*p_anim_stream)[i_word_index+19] == (*p_anim_stream)[i_word_index- 6] &&
1324  (*p_anim_stream)[i_word_index+20] == (*p_anim_stream)[i_word_index- 5] &&
1325  (*p_anim_stream)[i_word_index+21] == (*p_anim_stream)[i_word_index- 4] &&
1326  (*p_anim_stream)[i_word_index+22] == (*p_anim_stream)[i_word_index- 3] &&
1327  (*p_anim_stream)[i_word_index+23] == (*p_anim_stream)[i_word_index- 2] &&
1328  (*p_anim_stream)[i_word_index+24] == (*p_anim_stream)[i_word_index- 1] &&
1329  // Must be at begin of 3D frame - and it could NOT be frame 0
1330  (i_actual_column == 0) && (i_actual_wall == 0) && (i_actual_frame > 0))
1331  {
1332  i_anime_word = cmd_param_3D_frame + param_3D_frame_same;
1333  i_word_index = i_word_index +24;
1334  i_actual_wall = 5; /* Overflow -> when process command, then
1335  * do necessary routine
1336  */
1337  i_command_created = 1;
1338  }
1339 
1340 
1341 
1342 
1343 
1344 
1345 
1346 
1347 
1348 
1349  /* However, test if there is void 2D frame. If yes, then change
1350  * i_anime_word into command and, of course, increase i_word_index
1351  */
1352  if( (*p_anim_stream)[i_word_index+0] == 0x0000 &&
1353  (*p_anim_stream)[i_word_index+1] == 0x0000 &&
1354  (*p_anim_stream)[i_word_index+2] == 0x0000 &&
1355  (*p_anim_stream)[i_word_index+3] == 0x0000 &&
1356  (*p_anim_stream)[i_word_index+4] == 0x0000 &&
1357  (i_actual_column == 0) && // Must be at the begin of 2D frame
1358  (i_command_created == 0))
1359  {
1360  i_anime_word = cmd_param_2D_frame + param_2D_frame_void;
1361  i_word_index = i_word_index +4; // And move to the next 2D frame
1362 
1363  // Move to next wall
1364  i_actual_wall++;
1365 
1366  i_command_created = 1;
1367  }
1368 
1369 
1370  /* Again, test if there is full 2D frame. If yes, then change
1371  * i_anime_word into command and, of course, increase i_word_index
1372  */
1373  if( (*p_anim_stream)[i_word_index+0] == 0x7FFF &&
1374  (*p_anim_stream)[i_word_index+1] == 0x7FFF &&
1375  (*p_anim_stream)[i_word_index+2] == 0x7FFF &&
1376  (*p_anim_stream)[i_word_index+3] == 0x7FFF &&
1377  (*p_anim_stream)[i_word_index+4] == 0x7FFF &&
1378  (i_actual_column == 0) && // Must be at the begin of 2D frame
1379  (i_command_created == 0))
1380  {
1381  i_anime_word = cmd_param_2D_frame + param_2D_frame_ones;
1382  i_word_index = i_word_index +4; // And move to the next 2D frame
1383 
1384  // Move to next wall
1385  i_actual_wall++;
1386 
1387  i_command_created = 1;
1388  }
1389 
1390 
1391  /* Test if actual frame is same as previous. Can work only for WALL1~WALL4.
1392  * Again change i_anime_word into command and, of course, increase
1393  * i_word_index
1394  */
1395  if( (*p_anim_stream)[i_word_index-5] == (*p_anim_stream)[i_word_index+0] &&
1396  (*p_anim_stream)[i_word_index-4] == (*p_anim_stream)[i_word_index+1] &&
1397  (*p_anim_stream)[i_word_index-3] == (*p_anim_stream)[i_word_index+2] &&
1398  (*p_anim_stream)[i_word_index-2] == (*p_anim_stream)[i_word_index+3] &&
1399  (*p_anim_stream)[i_word_index-1] == (*p_anim_stream)[i_word_index+4] &&
1400  // Must be at the begin of 2D frame and WALL must be greater than WALL0
1401  (i_actual_column == 0) && (i_actual_wall > 0) &&
1402  (i_command_created == 0))
1403  {
1404  i_anime_word = cmd_param_2D_frame + param_2D_frame_same;
1405  i_word_index = i_word_index +4; // And move to the next 2D frame
1406 
1407  // Move to next wall
1408  i_actual_wall++;
1409 
1410  i_command_created = 1;
1411  }
1412 
1413 
1414 
1415  // Read word from stream -> decide if it is command or value
1416  if( ( i_anime_word & (0x8000) ) == 0 )
1417  {// If zero (use AND masking) -> data
1418  // Transform integer to string (HEX format)
1419  sprintf( c_tmp_num, "0x%04X,", i_anime_word);
1420 
1421  // Write number
1422  fprintf(file, "%s", c_tmp_num);
1423 
1424  i_actual_column++;
1425 
1426  // Test if we are on the last column
1427  if(i_actual_column > 4)
1428  {// Write line to file ; increase i_actual_wall
1429  fprintf(file, "\n "); // Write to file newline
1430 
1431  i_actual_column = 0; // Set new active column to 0
1432 
1433  // Move to next wall
1434  i_actual_wall++;
1435  // Test if we on the last wall
1436  if(i_actual_wall > 4)
1437  {// If last wall -> write 2 newline ; increase i_actual_frame
1438  i_actual_frame++;
1439  i_actual_wall = 0; // Set actual wall to 0
1440 
1441  // Write to file 2 newlines and add info about frame #
1442  fprintf(file, "\n\n // Frame %d\n ", i_actual_frame);
1443  }
1444  }
1445  }
1446  else
1447  {// Else word is command
1448  // Extract just code number and then decide....
1449  switch( ((i_anime_word) & 0xFF00) )
1450  {
1451  case cmd_set_pwm_r: strcpy( c_tmp_txt, "cmd_set_pwm_r"); break;
1452  case cmd_set_pwm_g: strcpy( c_tmp_txt, "cmd_set_pwm_g"); break;
1453  case cmd_set_pwm_b: strcpy( c_tmp_txt, "cmd_set_pwm_b"); break;
1454 
1455  case cmd_param_2D_frame: strcpy( c_tmp_txt, "cmd_param_2D_frame"); break;
1456 
1457  case cmd_param_3D_frame: strcpy( c_tmp_txt, "cmd_param_3D_frame"); break;
1458 
1459  // Case, that command not found -> all to default
1460  default: strcpy( c_tmp_txt, "0x8000");
1461  }
1462 
1463  // Add value and some things
1464  // Add value to the code
1465  //sprintf( c_tmp_num, " + %d", (i_anime_word)&(0xFF)>>8 );
1466 
1467  // So, now just write it to the file - value is written low 8 bits
1468  fprintf(file, "%s + %d,\n ", c_tmp_txt, (i_anime_word)&(0xFF) );
1469 
1470  /* Test if we were on the last wall (for case,that was found compress
1471  * command -> increase wall -> now check *
1472  */
1473  if(i_actual_wall > 4)
1474  {// If last wall -> write 2 newline ; increase i_actual_frame
1475  i_actual_frame++;
1476  i_actual_wall = 0; // Set actual wall to 0
1477 
1478  // Write to file 2 newlines and add info about frame #
1479  fprintf(file, "\n\n // Frame %d\n ", i_actual_frame);
1480  }
1481 
1482 
1483  }
1484 
1485 
1486  // Move to next word
1487  i_word_index++;
1488  }
1489 
1490 
1491  // Close file
1492  fclose(file);
1493 }
1494 
1495 
1496 
1497 
1498 
1499 
1500 
1501 
1502 
1503 
1510 void write_end_of_animation(int i_options, char *p_animation_name)
1511 {
1512  // Test for input parameters
1513  if( (i_options > 255) || (i_options < 0))
1514  {
1515  i_options = 0; // If input variable is out of range
1516  printf(""
1517 "| ! Warning: End of animation option out of range. Set to 0 (default) |"
1518 "\n"
1519  );
1520  }
1521 
1522 
1523  FILE *file; // Pointer to file
1524 
1525  // String for complete path (include filename and extension -> +2)
1526  char c_file_and_path[name_len + path_len +2];
1527 
1528 
1529  // Save string contains name of anime folder
1530  strcpy(c_file_and_path, generated_anime_folder);
1531  // Add slash and prefix anim
1532  strcat(c_file_and_path, "/anim_");
1533  // Add file name
1534  strcat(c_file_and_path, p_animation_name);
1535  // Add ".c"
1536  strcat(c_file_and_path, ".c");
1537 
1538  // Open file - .c file (append mode)
1539  file = fopen( c_file_and_path, "a+");
1540 
1541  char c_file_content[128];
1542 
1543  strcpy(c_file_content, ""
1544 " // End of animation + option\n"
1545 " cmd_anim_stop + "
1546  );
1547 
1548  char c_number_as_text[4];
1549  sprintf( c_number_as_text, "%d", i_options);
1550 
1551  // Transform i_slowdown_factor to string number
1552  strcat(c_file_content, c_number_as_text);
1553  strcat(c_file_content, "\n };");
1554 
1555  // Write content to file
1556  fprintf(file, "%s", c_file_content);
1557 
1558  fclose(file);
1559 }
1560 
1561 
1562 
1563 
1564 
1565 
1566 
1571 {
1572  for(int i=0 ; i<screen_lines_max ; i++ )
1573  {
1574  printf("\n\n\n\n\n\n\n\n\n\n");
1575  }
1576 }
1577 
1578 
1583 void clear_virtual_framebuffer(uint8_t (*p_fb_data_vitual)[5][5][5])
1584 {
1585  for(int i=0 ; i<5 ; i++)
1586  {
1587  for(int j=0 ; j<5 ; j++)
1588  {
1589  for(int k=0 ; k<5 ; k++)
1590  {
1591  (*p_fb_data_vitual)[i][j][k] = 0;
1592  }
1593  }
1594  }
1595 }
1596 
1601 void set_virtual_framebuffer(uint8_t (*p_fb_data_virtual)[5][5][5])
1602 {
1603  for(int i=0 ; i<5 ; i++)
1604  {
1605  for(int j=0 ; j<5 ; j++)
1606  {
1607  for(int k=0 ; k<5 ; k++)
1608  {
1609  (*p_fb_data_virtual)[i][j][k] = (1<<red_shift)|
1610  (1<<green_shift)|
1611  (1<<blue_shift);
1612  }
1613 
1614  }
1615  }
1616 }
1617 
1618 
1619 
1620 
1621 
1622 void clear_real_framebuffer(uint16_t (*p_anim_stream)[max_size_anim_stream])
1623 {
1624  for(int i=0 ; i<max_size_anim_stream ; i++)
1625  {
1626  (*p_anim_stream)[i] = 0;
1627  }
1628 }
1629 
1630 
1631 
1632 
1633 void show_preview(uint8_t (*p_fb_data_virtual)[5][5][5],
1634  uint32_t i_frame_counter,
1635  uint8_t i_wall,
1636  uint8_t i_column,
1637  uint8_t i_led_level,
1638  uint8_t i_pwm_r,
1639  uint8_t i_pwm_g,
1640  uint8_t i_pwm_b,
1641  float f_virtual_time)
1642 {
1643 
1644  printf(""
1645 "+---------------------------------------------------------------------------+"
1646 "\n"
1647 "| Frame: %9d | Wall: %d/4 | Column: %d/4 | Time: %7.2f s |\n"
1648 "+--------------+---+-----------++------------+--+---------------------------+"
1649 "\n"
1650 "| PWM red: %3d | PWM green: %3d | PWM blue: %3d | |"
1651 "\n"
1652 "+--------------+----------------+---------------+---------------------------+"
1653 "\n"
1654 "| | C0 | | C1 | | C2 | | C3 | | C4 | |"
1655 "\n"
1656 "| |"
1657 "\n"
1658  , i_frame_counter, i_wall, i_column, f_virtual_time,
1659  i_pwm_r, i_pwm_g, i_pwm_b
1660  );
1661 
1662  for(int i=4 ; i>=0 ; i--) // led level (LED 0 ~ LED 4)
1663  {
1664  printf("| LED %d > ", i);
1665 
1666  for(int j=0 ; j<5 ; j++) // Collumn
1667  {
1668  // If actual "window" is active
1669  if( (i==i_led_level) && (j==i_column))
1670  {
1671  printf("| ");
1672  }
1673  else
1674  { // Else actual "window" is not active
1675  printf(" ");
1676  }
1677 
1678  // Test if red bit is set
1679  if( (*p_fb_data_virtual)[i_wall][i][j] & (1<<red_shift) )
1680  {
1681  printf("R");
1682  }
1683  else
1684  {
1685  printf("-");
1686  }
1687  // Test if green bit is set
1688  if( (*p_fb_data_virtual)[i_wall][i][j] & (1<<green_shift) )
1689  {
1690  printf("G");
1691  }
1692  else
1693  {
1694  printf("-");
1695  }
1696  // Test if blue bit is set
1697  if( (*p_fb_data_virtual)[i_wall][i][j] & (1<<blue_shift) )
1698  {
1699  printf("B");
1700  }
1701  else
1702  {
1703  printf("-");
1704  }
1705 
1706  // If actual "window" is active
1707  if( (i==i_led_level) && (j==i_column))
1708  {
1709  printf(" | ");
1710  }
1711  else
1712  {
1713  printf(" ");
1714  }
1715  }
1716  //End of line
1717  printf(" |\n"
1718 "| |"
1719 "\n");
1720  }
1721 
1722  // End of frame
1723  printf(""
1724 "+---------------------------------------------------------------------------+"
1725 "\n"
1726 "| Type command or data. Aviable commands: |"
1727 "\n"
1728 "| exit - save data (to actual frame) and exit from application |"
1729 "\n"
1730 "| zeros - clear actual frame - turn off all LEDs on actual frame |"
1731 "\n"
1732 "| ones - set actual frame - turn on all LEDs on acutal frame |"
1733 "\n"
1734 "| next - move to next wall. Actual 2D frame will be saved |"
1735 "\n"
1736 "| back - move to previous wall. Actual 2D frame will be saved |"
1737 "\n"
1738 "| pwmr - set PWM on channel with RED LEDs. pwmg is for green and pwmb for |"
1739 "\n"
1740 "| blue channel. Value of PWM is same for whole frame. |"
1741 "\n"
1742 "| line - copy actual segment thru line |"
1743 "\n"
1744 "| column - copy actual segment thru column |"
1745 "\n"
1746 
1747 
1748 
1749 
1750 
1751 
1752 
1753 "+---------------------------------------------------------------------------+"
1754 "\n"
1755 "| Howto type data (examples): |"
1756 "\n"
1757 "| rgb -> turn on all LEDs in segment |"
1758 "\n"
1759 "| r-- -> just turn on red LED |"
1760 "\n"
1761 "| 011 -> turn green and blue LED |"
1762 "\n"
1763 "| A -> turn on all LEDs in segment |"
1764 "\n"
1765 "| g -> turn on green LED |"
1766 "\n"
1767 
1768 
1769 
1770 
1771 "+---------------------------------------------------------------------------+"
1772 "\n"
1773 "| Command line: "
1774  );
1775 }