DIGILIGHT
sd_script.c
См. документацию.
1 
18 #include <avr/io.h>
19 #include <avr_helper.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <avr/pgmspace.h>
23 #include "global.h"
24 #include "pixel.h"
25 #include "color_transform.h"
26 #include "avr_helper.h"
27 #include "hardware.h"
28 #include "main_effect.h"
29 #include "lcd_show.h"
30 #include <util/delay.h>
31 #include "PFFS/pff.h"
32 #include "sd_script.h"
33 #if !defined(DISABLE_SD_SCRIPT)
34 
38 // костыль - запрет WS2812b
39 #define enter_sd_mode() do { SPCR = _BV(SPE) | _BV(MSTR); PORT(WS_LOCK_PORT) &= ~WS_LOCK_PIN;} while(0)
40 // костыль - разрешение WS2812b
41 #define leave_sd_mode() do { SPCR = _BV(SPE) | _BV(MSTR) | _BV(CPHA); SPDR=0; while(!(SPSR & (1<<SPIF))); PORT(WS_LOCK_PORT) |= WS_LOCK_PIN; } while(0)
42 
43 #define MODULE_NAME "SCRIPT PLAYER"
44 
45 static __flash const char _name[] = MODULE_NAME;
46 
48 typedef struct{
49  char filename[13];
50  uint32_t pos;
51  uint16_t readed;
52  char *cmd;
53 } script_t;
54 
56 static script_t script;
57 
59 #define SD_BUF_SZ 256UL
60 
62 typedef enum{
68 #if defined(_DEBUG_)
69  ,DBG_ERROR // отладочное состояние
70 #endif
72 
73 static script_result_t sdcard_open(void);
74 static uint16_t get_script_count(void);
75 static script_result_t script_open(script_t *s, uint16_t id);
76 
78 static script_result_t script_read_str(script_t *s, char *str);
79 static script_result_t script_seek(script_t *s, uint32_t pos);
80 static void script_exec(signal_t *s);
81 
82 static int8_t select_next = 0;
83 
85 #define VAR_CNT 16
86 #define STACK_DEPTH 5
88 
90 typedef struct{
91  uint8_t bright;
92  uint8_t fade;
94  uint8_t var[VAR_CNT];
95  uint8_t rev;
96  uint8_t stack_head;
97  uint32_t loop_stack[STACK_DEPTH];
99 
101 static script_param_t param;
103 static char *buf;
105 static script_result_t status;
107 static uint16_t total_script_files;
109 static uint16_t script_id;
111 static FATFS fs;
113 static DIR dir;
114 
119 static script_result_t sdcard_open(void){
120  // монтируем файловую систему
121  if(pf_mount(&fs) == FR_OK){
122  // если смонтировалась - открываем корневую директорию
123  if(pf_opendir(&dir, "") == FR_OK){
124  // если открылась - ОК
125  return SCRIPT_OK;
126  }
127  }
128  // при любом сбое возвращаем ошибку
129  return SCRIPT_NO_SD;
130 }
131 
136 static uint16_t get_script_count(void){
137  FRESULT res;
138  FILINFO file;
139  uint16_t count = 0;
140 
141  // инициализация сканирования директории
142  res = pf_readdir(&dir, 0);
143  // пока сканирование успешно
144  while(res == FR_OK){
145  // считываем очередную запись о файле
146  res = pf_readdir(&dir, &file);
147  // прекращаем цикл при ошибке или конце записей
148  if (res || !file.fname[0]) break;
149  // проверяем, что запись - НЕ директория и НЕ скрытый файл,
150  // и при этом расширение у него правильное
151  if (!(file.fattrib & (AM_DIR|AM_HID)) && strstr(file.fname, ".SC"))
152  count++; // ведем подсчет "правильных" файлов
153  }
154  return count;
155 }
156 
163 static script_result_t script_open(script_t *s, uint16_t id){
164  FRESULT res;
165  FILINFO file;
166  // файлы отсчитываются с 0, но их количество - с 1, поэтому корректируем номер
167  id++;
168  // отсчитываем нужное количество файлов в директории
169  res = pf_readdir(&dir, 0);
170  do {
171  res = pf_readdir(&dir, &file);
172  if (res || !file.fname[0]) break;
173  if (!(file.fattrib & (AM_DIR|AM_HID)) && strstr(file.fname, ".SC")) id--;
174  } while(id && (res == FR_OK));
175 
176  if(res != FR_OK)
177  return SCRIPT_NO_SD;
178  else {
179  // если добрались до указанного номера файла - инициализируем объект скрипта
180  memset(s, 0, sizeof(script_t));
181  memset(&param, 0, sizeof(script_param_t));
182  memset(buf, 0, SD_BUF_SZ);
183  strncpy(s->filename, file.fname, 12);
184  // и пробуем открыть его
185  return pf_open(s->filename) == FR_OK ? SCRIPT_OK : SCRIPT_NOTFOUND;
186  }
187 }
188 
195 static script_result_t script_read_str(script_t *s, char *str){
196  uint16_t n = SD_BUF_SZ;
197  if(status == SCRIPT_OK){
198  // позиционируем файл
199  if(pf_lseek(s->pos) == FR_OK){
200  // читаем в кэш
201  if(pf_read(str, SD_BUF_SZ, &s->readed) == FR_OK){
202  // корректируем считанное кол-во байтов
203  if(s->readed < n) n = s->readed;
204  // ищем последнюю "целую" команду и после неё ставим пометку конца строки
205  uint8_t b = n-1;
206  // поиск "целой" команды прост: ищем первый символ-разделитель от конца считанных данных
207  while(n && str[b] && (str[b] != ' ') && (str[b] != '\n') && (str[b] != '\r') && (str[b] != '\t')) {
208  n--;
209  b = n-1;
210  }
211  // помечаем найденное место
212  str[n] = 0;
213  // корректируем считанное количество и позицию файла
214  s->readed = n;
215  s->pos += n;
216  return SCRIPT_OK;
217  }
218  }
219  }
220  return SCRIPT_ERROR_IO;
221 }
222 
229 static script_result_t script_seek(script_t *s, uint32_t pos){
230  s->pos = pos;
231  return pf_lseek(pos) == FR_OK ? SCRIPT_OK : SCRIPT_ERROR_IO;
232 }
233 
239 static uint8_t get_script_digit(char *str){
240  if((str[0] >= '0') && (str[0] <= '9')) return str[0] - '0';
241  else if((str[0] >= 'A') && (str[0] <= 'F')) return str[0] - 'A' + 10;
242  else return 255;
243 }
244 
245 #define ERROR_CH 0xFF00
246 
253 static uint16_t get_script_val(char *str){
254  // это переменная?
255  if(str[0] == 'V'){
256  // извлекаем номер переменной
257  uint8_t n = get_script_digit(++str);
258  // номер переменной должен быть корректным
259  return n < VAR_CNT ? param.var[n] : ERROR_CH;
260  } else if (str[0] == 'R'){
261  // функция RD или RP
262  if(str[1] == 'D') return rand() & 0x00FF;
263  else if(str[1] == 'P') return rand() % PIXEL_CNT;
264  else return ERROR_CH;
265  } else if (str[0] == 'T'){
266  // функция TP
267  if(str[1] == 'P') return PIXEL_CNT-1;
268  else return ERROR_CH;
269  } else {
270  // байт
271  uint8_t nh = get_script_digit(str++);
272  uint8_t nl = get_script_digit(str);
273  if((nh < 0x10) && (nl < 0x10)) return (nh << 4) | nl;
274  else return ERROR_CH;
275  }
276 }
277 
282 static uint32_t popstack(void){
283  // стек должен быть заполнен
284  if(param.stack_head != 0){
285  // сдвигаем "голову"
286  param.stack_head--;
287  // возвращаем позицию
288  return param.loop_stack[param.stack_head];
289  }
290  else // если стек пуст - придется с начала файла повторять
291  return 0;
292 }
293 
298 static void pushstack(uint32_t d){
299  // в стеке должно быть место
300  if(param.stack_head < (STACK_DEPTH-1)){
301  param.loop_stack[param.stack_head++] = d;
302  }
303  // а если места в стеке нет - цикл будет потерян, и это ошибка скрипта
304 }
305 
311 static uint8_t execute_cmd(char *cmd){
312  uint16_t tmp;
313  // цикл только для удобства прекращения парсинга
314  do{
315  // проверка на команду с переменными
316  if(cmd[0] == 'V'){
317  // номер переменной
318  uint8_t n = get_script_digit(cmd+1);
319  if(n >= VAR_CNT) break;
320  // параметр команды
321  tmp = get_script_val(cmd+3);
322  if(tmp > 255) break;
323  // разбор оператора команды
324  switch(cmd[2]){
325  case '=': param.var[n] = tmp; break;
326  case '+': tmp += param.var[n]; param.var[n] = tmp > 255 ? 255 : tmp; break;
327  case '-': tmp = param.var[n] - tmp; param.var[n] = tmp < 0 ? 255: tmp; break;
328  case '*': tmp *= param.var[n]; param.var[n] = tmp > 255 ? 255 : tmp; break;
329  case '/': if(tmp == 0) return 0;
330  param.var[n] /= tmp;
331  break;
332  case '%': if(tmp == 0) return 0;
333  param.var[n] %= tmp;
334  break;
335  // пока не отлаженные действия
336  //case '>' param.var[n] = param.var[n] > tmp; break;
337  //case '<' param.var[n] = param.var[n] < tmp; break;
338  //case '=' param.var[n] = param.var[n] == tmp; break;
339  //case '!' param.var[n] = param.var[n] != tmp; break;
340  default:
341  // недопустимый оператор
342  break;
343  }
344  // любая строка, начинающаяся на V, но не попавшая в разбор - игнор
345  break;
346  }
347  // проверка на команду с параметром
348  if(cmd[2] == '='){
349  // получаем параметр
350  tmp = get_script_val(cmd+3);
351  if(tmp > 255) break;
352  // если параметр валидный - разбираем команду
353  if(strncmp_P(cmd, PSTR("PB"), 2) == 0){
354  // яркость
355  param.bright = tmp;
356 
357  } else if(strncmp_P(cmd, PSTR("GB"), 2) == 0){
358  // глобальная яркость
359  for(uint8_t i=0; i<PIXEL_CNT; i++)
360  pixels[i].bright = tmp;
361 
362  } else if(strncmp_P(cmd, PSTR("PF"), 2) == 0){
363  // затухание
364  param.fade = tmp;
365 
366  } else if(strncmp_P(cmd, PSTR("GF"), 2) == 0){
367  // глобальное затухание
368  for(uint8_t i=0; i<PIXEL_CNT; i++)
369  pixels[i].delta = tmp;
370 
371  } else if(strncmp_P(cmd, PSTR("PC"), 2) == 0){
372  // цвет
373  uint16_t tmp2 = get_script_val(cmd+5);
374  uint16_t tmp3 = get_script_val(cmd+7);
375  if((tmp2 > 255) || (tmp3 > 255)) break;
376  param.color.r = tmp;
377  param.color.g = tmp2;
378  param.color.b = tmp3;
379 
380  } else if(strncmp_P(cmd, PSTR("GC"), 2) == 0){
381  // цвет глобально
382  uint16_t tmp2 = get_script_val(cmd+5);
383  uint16_t tmp3 = get_script_val(cmd+7);
384  if((tmp2 > 255) || (tmp3 > 255)) break;
385  for(uint8_t i=0; i<PIXEL_CNT; i++)
386  set_rgb_color(i, tmp, tmp2, tmp3);
387 
388  } else if(strncmp_P(cmd, PSTR("PM"), 2) == 0){
389  // карта пикселов
390  char *ptr = cmd+5;
391  while(tmp <= 255){
392  if(tmp < PIXEL_CNT){
393  if(param.rev) tmp = PIXEL_CNT - tmp - 1;
394  // только для допустимого номера пиксела
395  pixels[tmp].bright = param.bright;
396  pixels[tmp].delta = param.fade;
397  pixels[tmp].r = param.color.r;
398  pixels[tmp].g = param.color.g;
399  pixels[tmp].b = param.color.b;
400  } // недопустимые номера пикселов игнорируются без прекращения парсинга
401  tmp = get_script_val(ptr);
402  ptr += 2;
403  }
404 
405  } else if(strncmp_P(cmd, PSTR("WT"), 2) == 0){
406  // задержка
407  return tmp;
408 
409  }
410  }
411  // проверка на команду конца цикла
412  if(strncmp_P(cmd, PSTR("LV"), 2) == 0){
413  // номер переменной цикла
414  uint8_t n = get_script_digit(cmd+2);
415  if(n > VAR_CNT) break;
416  // проверка условия
417  if((cmd[3] == '=') || (cmd[3] == '>') || (cmd[3] == '<') || (cmd[3] == '!')){
418  tmp = get_script_val(cmd+4);
419  if(tmp > 255) break;
420  switch(cmd[3]){
421  case '=': if(param.var[n] == tmp) goto do_loop_cmd;
422  break;
423  case '>': if(param.var[n] > tmp) goto do_loop_cmd;
424  break;
425  case '<': if(param.var[n] < tmp) goto do_loop_cmd;
426  break;
427  case '!': if(param.var[n] != tmp) goto do_loop_cmd;
428  break;
429  }
430  goto do_skip_loop;
431  }
432  // цикл повторяется, если переменная не равна нулю
433  if(param.var[n] != 0){
434  // автодекремент переменной
435  param.var[n]--;
436  do_loop_cmd:
437  // переход на начало цикла
438  status = script_seek(&script, popstack());
439  cmd[0] = 0; // !!!! магия!!!
440  if(status == SCRIPT_OK) pushstack(script.pos);
441  } else {
442  // если переменная цикла обнулена - извлечем из стека без перехода,
443  // чтобы не засорять стек
444  do_skip_loop:
445  popstack();
446  }
447 
448  break;
449  }
450  // проверка на команду без параметров
451  if(strncmp_P(cmd, PSTR("END"), 3) == 0){
452  // конец скрипта
453  cmd[0] = 0;
454  status = SCRIPT_ERROR_IO;
455  break;
456  } else if(strncmp_P(cmd, PSTR("CLR"), 3) == 0){
457  // очистка
458  memset(pixels, 0, PIXEL_CNT * sizeof(pixel_t));
459  memset(&param, 0, sizeof(script_param_t));
460  param.bright = 0xFF;
461 
462  } else if(strncmp_P(cmd, PSTR("INF"), 3) == 0){
463  // бесконечный цикл
464  goto do_loop_cmd;
465  //status = script_seek(&script, popstack());
466  //cmd[0] = 0; // !!!! магия!!!
467  //if(status == SCRIPT_OK) pushstack(script.pos);
468 
469  } else if(strncmp_P(cmd, PSTR("RST"), 3) == 0){
470  // рестарт
471  status = script_seek(&script, 0);
472  cmd[0] = 0; // !!!! магия!!!
473 
474  } else if(strncmp_P(cmd, PSTR("RPT"), 3) == 0){
475  // начало цикла
476  // магия указателей !!!!
477  uint32_t next = script.pos - (script.readed - (cmd - buf + 3));
478  pushstack(next);
479  //pushstack(script.pos);
480 
481  } else if(strncmp_P(cmd, PSTR("PNT"), 3) == 0){
482  // отрисовка
483  return 1;
484  }else if(strncmp_P(cmd, PSTR("REV"), 3) == 0){
485  // реверс
486  param.rev = !param.rev;
487 
488  } else if(strncmp_P(cmd, PSTR("NEG"), 3) == 0){
489  // инверсия яркости
490  for(uint8_t i=0; i<PIXEL_CNT; i++)
491  pixels[i].bright ^= 0xFF;
492  }
493  } while(0);
494 
495  return 0;
496 }
497 
501 static void _start(void){
502  uint16_t buf_sz;
503  // ставим блокировку
504  lock_input = 1;
505  // пикселы гасим
506  off_all_pixels();
507  // запрашиваем память под кэш
508  buf_sz = SD_BUF_SZ;
509  buf = get_reserved_memory(&buf_sz);
510 #if defined(_DEBUG_)
511  if(buf_sz != SD_BUF_SZ){
512  status = DBG_ERROR;
513  return;
514  }
515 #endif
516  // пробуем открыть карту
517  status = sdcard_open();
518  if(status == SCRIPT_OK){
519  // считаем скрипты на карте
520  total_script_files = get_script_count();
521  script_id = 0;
522  if(total_script_files > 0){
523  // пробуем открыть первый скрипт
524  status = script_open(&script, script_id);
525  } else
526  status = SCRIPT_NOTFOUND;
527  }
528 }
529 
535 static char* skip_cmd(char *s){
536  uint8_t n = 0;
537  // находим первый не значащий символ
538  while(s[n] && (s[n] != ' ') && (s[n] != '\n') && (s[n] != '\r') && (s[n] != '\t')) n++;
539  return s + n;
540 }
541 
548 static char* get_cmd(char *s){
549  uint8_t n = 0;
550  // находим первый значащий символ
551  while(s[n] && ((s[n] == ' ') || (s[n] == '\n') || (s[n] == '\r') || (s[n] == '\t'))) n++;
552  return s[n] ? s + n : NULL;
553 }
554 
560 uint8_t script_execute(char *buf){
561  uint8_t inf = 0;
562  uint8_t result;
563 
564  do{
565  if(!++inf){
566  // если прошло больше 255 итераций цикла - это ошибка в скрипте
567  status = SCRIPT_INFLOOP;
568  break;
569  }
570  if(script.cmd == NULL){
571  // если текущая команда отсутствует, надо заполнить кэш
572  status = script_read_str(&script, buf);
573  // команда будет с начала кэша
574  script.cmd = get_cmd(buf);
575  continue;
576  }
577  // исполняем текущую команду
578  result = execute_cmd(script.cmd);
579  // и берем следующую
580  script.cmd = get_cmd(skip_cmd(script.cmd));
581  // если нужно - выход для выполнения задержки
582  if(result) return result;
583  }while(status == SCRIPT_OK);
584 
585  return 0;
586 }
587 
593 static preset_result_t next_file(int8_t d){
594  select_next = d;
595  return PRESET_NOTHING;
596 }
597 
599 #define IND_SD_STATUS 50
600 
605 void script_exec(signal_t *s){
606  static uint8_t div;
607 
608  if(select_next != 0){
609  div = 0;
610  enter_sd_mode();
611  goto next_file_load;
612  }
613 
614  if(div){
615  // отрабатывание задержки в скрипте
616  if(--div) return;
617  }
618 
619  enter_sd_mode();
620 
621  switch(status){
622  case SCRIPT_OK:
623  // скрипт открыт успешно
624  div = script_execute(buf);
625  break;
626  case SCRIPT_NO_SD:
627  div = IND_SD_STATUS;
628  _start();
629  break;
630  case SCRIPT_NOTFOUND:
631  div = IND_SD_STATUS;
632  _start();
633  break;
634  case SCRIPT_INFLOOP:
635  // бесконечный цикл в скрипте путем имитации ошибки чтения файла
636  // вызывает запуск следующего скрипта
637  div = IND_SD_STATUS;
638  status = SCRIPT_ERROR_IO;
639  break;
640  case SCRIPT_ERROR_IO:
641  // ошибка при чтении скрипта - в нормальном случае возникает после
642  // считывания всех строк файла, иначе - сбой карты
643  if(select_next == 0){
644  select_next = 1;
645  }
646  next_file_load:
647 
648  if(total_script_files){
649  if(select_next < 0){
650  if(script_id == 0)
651  script_id = total_script_files-1;
652  else
653  script_id--;
654  } else {
655  script_id += select_next;
656  if(script_id >= total_script_files) script_id = 0;
657  }
658  }
659  status = script_open(&script, script_id);
660  select_next = 0;
661 
662  default:
663  break;
664  }
665 
666  leave_sd_mode();
667 }
668 
672 static void _stop(void){
673  // снимаем блокировку
674  lock_input = 0;
675 }
676 
678 #define ANIMATE_DELAY 50
679 #define ANIMATE_LEN 3
680 
686 static effect_info_t _info(uint8_t show){
687  static uint8_t ind_pos;
688  static uint8_t div = ANIMATE_DELAY;
689  if(show){
690  char str[17];
691  switch(status){
692  case SCRIPT_NO_SD:
693  center_str_p(1, PSTR("NO CARD"));
694  break;
695  case SCRIPT_NOTFOUND:
696  center_str_p(1, PSTR("NO SCRIPT"));
697  break;
698  case SCRIPT_ERROR_IO:
699  center_str_p(1, PSTR("SEARCH..."));
700  break;
701  case SCRIPT_OK:
702  // анимация перед имененм файла
703  for(uint8_t i=0; i<ANIMATE_LEN; i++){
704  str[i] = i == ind_pos ? '>' : '-';
705  }
706  if(!--div){
707  div = ANIMATE_DELAY;
708  if(++ind_pos >= ANIMATE_LEN) ind_pos = 0;
709  }
710  str[ANIMATE_LEN] = ' ';
711  str[ANIMATE_LEN+1] = 0;
712  // имя файла
713  strncat(str, script.filename, 11);
714  show_rpad_str(1, str);
715  break;
716  case SCRIPT_INFLOOP:
717  center_str_p(1, PSTR("INF.LOOP"));
718  break;
719 #if defined(_DEBUG_)
720  case DBG_ERROR:
721  center_str_p(1, PSTR("<NO MEMORY>"));
722  break;
723 #endif
724  }
725  }
726  return INFO_ALWAYS;
727 }
728 
730 static flash_effect_t effect_def = {
731  .name = _name,
732  .start = _start,
733  .work = script_exec,
734  .stop = _stop,
735  .preset = next_file,
736  .save = NULL,
737  .info = _info
738 };
739 
740 INIT(7){
741  // регистрация эффекта
742  register_effect(BACKGROUND_EFFECT, &effect_def);
743  // так же пин управления блокировкой WS2812b
744  DDR(WS_LOCK_PORT) |= WS_LOCK_PIN;
745 
746  leave_sd_mode();
747 }
752 #endif
в скрипте есть бесконечный цикл
Definition: sd_script.c:67
uint8_t fade
затухание
Definition: sd_script.c:92
uint32_t loop_stack[STACK_DEPTH]
стек циклов
Definition: sd_script.c:97
структура скрипта
Definition: sd_script.c:48
структура параметров скрипта
Definition: sd_script.c:90
rgb_t color
цвет
Definition: sd_script.c:93
uint16_t readed
считанное в последний раз кол-во байтов
Definition: sd_script.c:51
#define ANIMATE_DELAY
период анимации при воспроизведении скрипта в интервалах по 10 мс
Definition: sd_script.c:678
#define SD_BUF_SZ
КОНСТАНТА - размер блока чтения с карты. Может быть МЕНЬШЕ, но НЕ БОЛЬШЕ 256.
Definition: sd_script.c:59
uint8_t b
синяя составляющая цвета
Definition: pixel.h:36
void off_all_pixels(void)
Выключение всех пикселов
Definition: pixel.c:162
int8_t delta
условная скорость автоматического изменения яркости
Definition: pixel.h:38
uint8_t rev
реверс
Definition: sd_script.c:95
uint8_t lock_input
Definition: main.c:220
нет пресетов
Definition: main_effect.h:58
Вспомогательные эффекты ЖКИ
Общие описания
uint32_t pos
следующая позиция в файле для чтения
Definition: sd_script.c:50
void set_rgb_color(uint8_t pos, uint8_t r, uint8_t g, uint8_t b)
Пиксел произвольного цвета
Definition: pixel.c:107
uint8_t stack_head
"голова" стека циклов
Definition: sd_script.c:96
const __flash effect_t flash_effect_t
тип описания эффекта, размещенного во FLASH.
Definition: main_effect.h:79
структура параметров звукового сигнала
Definition: global.h:72
#define VAR_CNT
КОНСТАНТА - количество переменных в скрипте, НЕ МЕНЯТЬ
Definition: sd_script.c:85
карта не вставлена
Definition: sd_script.c:64
uint8_t var[VAR_CNT]
переменные
Definition: sd_script.c:94
Структура, описывающая один пиксель
Definition: pixel.h:33
сервисный модуль для реализации эффектов Набор вспомогательных функций для базовых манипуляций над це...
ошибка чтения с карты
Definition: sd_script.c:66
char filename[13]
имя файла скрипта
Definition: sd_script.c:49
void show_rpad_str(uint8_t line, char *src)
вывод строки с очисткой дисплея справа
Definition: lcd_show.c:147
void center_str_p(uint8_t row, const char *src)
вывод строки из flash по центру дисплея
Definition: lcd_show.c:111
#define STACK_DEPTH
глубина вложенности циклов в скрипте
Definition: sd_script.c:87
Аппаратно-зависимые определения
файл скрипта не найден на карте
Definition: sd_script.c:65
#define BACKGROUND_EFFECT
фоновый эффект
Definition: main_effect.h:48
preset_result_t
результат функции смены пресета
Definition: main_effect.h:56
#define PIXEL_CNT
Общее количество пикселов
Definition: pixel.h:27
Описания модуля скрипт-плейера
#define IND_SD_STATUS
длительность индикации состояния модуля в интервалах по 10 мс
Definition: sd_script.c:599
Тип для представления цвета в RGB-модели
script_result_t
тип текущего состояния модуля
Definition: sd_script.c:62
Интерфейс визуальных эффектов
uint8_t g
зеленая составляющая цвета
Definition: pixel.h:35
uint8_t bright
яркость
Definition: sd_script.c:91
uint8_t r
красная составляющая цвета
Definition: pixel.h:34
pixel_t pixels[MAX_TOTAL_PIX]
Массив пикселей предельного размера
Definition: pixel.c:22
нормальная работа
Definition: sd_script.c:63
void register_effect(uint8_t toe, flash_effect_t *eff)
Регистрация эффекта в списках
Definition: main_effect.c:41
типы представления цвета разными способами
uint8_t bright
яркость пиксела
Definition: pixel.h:37
void * get_reserved_memory(uint16_t *size)
запрос резервной памяти
Definition: spectrum.c:58
uint8_t script_execute(char *buf)
Definition: sd_script.c:560