/** \file global.h
 * \brief Общие описания
 *
 * \author ARV
 * \date	5 апр. 2017 г.
 * \copyright Copyright 2015 © ARV. All rights reserved.
 *
 */

#ifndef EFFECTS_H_
#define EFFECTS_H_
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "avr_helper.h"
#include "pixel.h"
#include "ws2812.h"
#include "color_transform.h"
#include "hardware.h"
#include "PFFS/pff.h"
#include "com_io.h"
#include "usart_debug.h"

#ifndef NULL
#define NULL	(void*)0
#endif

extern uint16_t limit;
extern bool cfg_lock;
extern EEMEM ws_led_t e_led;

/// структура настроек плейера
typedef struct{
	uint16_t	pause;			//!< величина паузы между скриптами
	uint16_t	run_limit;		//!< длительность исполнения зацикленного скрипта
	uint16_t	total_files;	//!< общее количество файлов на флешке
	uint16_t	fid;			//!< номер текущего файла
	ws_led_t	led;			//!< тип ленты
	bool		random;			//!< признак случайного воспроизведения файлов
	bool		skip_missing;	//!< признак пропуска несуществующих файлов
	uint8_t		tp;
	uint8_t		mx;
	uint8_t		my;
} config_t;

#define STACK_DEPTH		10

#define FIRST_EXT_VAR	'A'
#define LAST_HEX_SYMBOL	'F'
#define LAST_EXT_VAR	'Z'

#define VAR_CNT			(11 + LAST_EXT_VAR - FIRST_EXT_VAR)

typedef struct{
	// параметры скрипта, касающиеся файла
	char		fname[13];	//!< имя файла скрипта
	uint16_t	seek;		//!< смещение
	uint16_t	next;		//!< позиция файла для следующего чтения
	uint16_t	readed;		//!< размер считанного блока
	char		*pos;		//!< указатель на текущую анализируемую позицию
	// не переставлять нижеследующие поля местами и добавлять только в конец структуры!!!
	uint16_t	stack[STACK_DEPTH];
	uint8_t		var[VAR_CNT];
	uint8_t		stack_head;
	uint8_t		br;
	uint8_t		fd;
	rgb_t		pc;
	bool 		rev;
	bool		matrix;
	uint8_t		min_px;
	uint8_t		max_px;
	uint8_t		delta;
	uint8_t		skip;
	uint8_t		ain_bounds[4]; // масштаб аналогового сигнала
} script_t;

#define AIN_CNT		2
extern bool autopaint;
extern uint8_t ain[AIN_CNT];

#define FIRST_PX	script.min_px
#define LAST_PX		script.max_px
#define DELTA_PX	script.delta

/// макрос выполнения действия над всеми пикселами, номер пиксела задается через px
/// пример: \code forall_px(pixels[px].fade = 0);
#define forall_px(x) for(uint8_t px=FIRST_PX; px < LAST_PX; px += DELTA_PX) x


#define CLR_MEMSET_LEN (sizeof(script_t) - sizeof(uint16_t)*STACK_DEPTH - VAR_CNT - sizeof(bool) - sizeof(rgb_t) - 3)

#if defined(__AVR_ATmega328P__)
#define BUF_SZ	512
#else
#define BUF_SZ	256
#endif

extern char buf[BUF_SZ+1];

extern config_t cfg;
extern script_t	script;
extern FATFS fs;

typedef struct{
	const __flash char *name;
	int	(*func)(char *str);
} cmd_t;

#define EXEC_SEEK	-3
#define EXEC_SKIP	-2
#define EXEC_END	-1
#define EXEC_NEXT	0

#define SCMD(x) CONCAT(_ , x)
#define FCMD(x) CONCAT(f_cmd_, x)

#define CMD(x)	static const __flash char SCMD(x)[] = # x ; \
	static int FCMD(x)(char *str); \
	static const cmd_t __attribute__((used, section(".my_table"))) CONCAT(_ , SCMD(x)) = { \
				.name = SCMD(x), .func = FCMD(x) }; \
	static int CONCAT(f_cmd_, x)(char *str)

#define CMD_ALIAS(x,a)	static const __flash char SCMD(x)[] = # x ; \
	static const cmd_t __attribute__((used, section(".my_table"))) CONCAT(_ , SCMD(x)) = { \
				.name = SCMD(x), .func = FCMD(a) }

#define CMD_DEF(x)	static int FCMD(x)(char *str)

bool separator(char ch);
uint16_t rnd(uint16_t limi);
void paint(void);
char* skip_invalid(char *s);
bool script_exec(void);
void clr_script(void);

// костыль - запрет WS2812b
#define enter_sd_mode()		do { SPCR = _BV(SPE) | _BV(MSTR); PORT(WS_LOCK_PORT) &= ~_BV(WS_LOCK_PIN);} while(0)
// костыль - разрешение WS2812b
#define leave_sd_mode()		do { SPCR = _BV(SPE) | _BV(MSTR) | _BV(CPHA); SPDR=0;  while(!(SPSR & (1<<SPIF))); PORT(WS_LOCK_PORT) |= _BV(WS_LOCK_PIN); } while(0)

#if defined(__AVR_ATmega8__)

#elif defined(__AVR_ATmega328P__)
#define TIFR	TIFR1
#define TIMSK	TIMSK1
#endif

#if AIN_CNT > 7
#error "ADC_CNT more than approved!"
#endif
#endif /* EFFECTS_H_ */
