Программный модуль для чайника

RK-M216S-E. Версия 4.21



ПО является неотъемлемой частью чайника RK-M216S-Е, отдельно потребителю не поставляется и эксплуатируется только в составе устройства.

Фрагмент исходного кода
////////////////////////////////////////////////////////////////

//RK-M216S-E

//v4.21

//application.c

////////////////////////////////////////////////////////////////
/********* HEADER FILE INCLUDES *************************************************/
#ifdef DEBUG
	#include "SEGGER_RTT.h"
#endif //DEBUG

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "nrf.h"
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "nrf_soc.h"
#include "app_error.h"
#include "app_util_platform.h"
#include "crc16.h"

#include "r4s_lib.h"
#include "r4s_slave.h"
#include "r4s_slave_external.h"

#include "sfloat.h"
#include "timers.h"
#include "timers_config.h"
#include "buz.h"
#include "buz_config.h"
#include "led.h"
#include "led_config.h"
#include "led_pwm.h"
#include "led_pwm_config.h"
#include "keyb.h"
#include "keyb_config.h"
#include "pof_manager.h"
#include "pof_manager_config.h"

#include "param.h"

#include "keyb_services.h"

#include "evcal.h"
#include "calendar.h"

#include "config.h"
#include "application.h"
#include "application_api.h"
#include "boost_ctrl.h"

#if defined (WT2_SENSOR_AND_NEW_ALGORITHM)
	#include "temp_wt2.h"
#elif defined (OLD_SENSOR_AND_ALGORITHM)
	#include "temp.h"
#else
	#error "NO SENSOR AND ALGORITHM DEFINED"
#endif

#include "not_active.h"
#include "com_slave_extention.h"

#include "adv_data.h"
#include "mass_fw_update_config.h"

#ifdef APP_CUSTOM_COLOR_RGB_ON
	#include "quantization.h"
#else
	#include "color_led.h"
#endif
#include "noinit_ram.h"
//#include <noinit_ram_config.h>
#include "noinit_ram_params.h"

#include "button_gpio.h"
#include "button_gpio_config.h"

#include "continent.h"
#include "com_slave.h"

/********* DEFINES **************************************************************/
#define SENSOR_COOLDOWN_TEMP    (60)

#define MAX_BOILING_TIME_M      (15) // аварийный таймаут в минутах
#define MAX_PERIOD_BRIGHTNESS	(255)	//период мерцания
#define	MAX_BRIGHTNESS			(255)		//мах яркость при мерцании

#define TEMP_IND_KOEF_REDUCE_SPEED	4	//коэффициент торможения изменения значения температуры после кипения
#define APP_KEEP_WARM_END_INDEX		5	//количество поддерживаемых температур

//команды в календаре
#define CALENDAR_STOP_COM			4	//остановка программы
#define CALENDAR_START_COM			3	//запуск программы с параметрами
#define CALENDAR_OPTION_COM			15	//запуск расширенной программы с параметрами (для Европы)

#ifdef CONTINENT_USA
	#define CALENDAR_OPTION_USA_COM	17	//запуск расширенной программы с параметрами (для США)
#endif

#define APP_COLOR_HEAT_IDX			0
#define APP_COLOR_NIGHT_IDX			1
#define COLOR_BOIL_DEF_VALUE		{ \
										{ \
											35, 	255,	{	0,		0,		255	}, \
											70, 	255,	{	0,		255,	0	}, \
											100,	255,	{	255,	0,		0	}, \
										}, \
									}
#define COLOR_NIGHTLED_DEF_VALUE	{ \
										{ \
											 0, 	127,	{	0,		0,		255	}, \
											50, 	127,	{	0,		255,	0	}, \
											100,	127,	{	255,	0,		0	}, \
										}, \
									}
#define COLOR_DISCO_DEF_VALUE		{ \
										127, {	0,		0,		255	}, \
									}

#ifdef CONTINENT_USA
	#define COLOR_MASS_UPDATE_STANDBY_DEF_VALUE		{ \
					255, {128,		0,		128}, \
					}
#endif
/********* MACROS ***************************************************************/
#define APP_FULL_BLINK_CYCLE		(TIMERS_MILLISECOND(APP_BLINK_ON_MS + APP_BLINK_OFF_MS))
#define	APP_UNPRESS_ALL_BTN()		do{ \
										for(uint8_t i=0; i<KEYB_BUTTON_COUNT; ++i) \
										{ \
											if(app_keyb_data[i].state == KEYB_PRESSED) break; \
											if(KEYB_BUTTON_COUNT==(i+1)) APP_FLAGS.b_waiting_unpress_btn = 0;\
										} \
									}while(0)
#ifndef APP_CHECK_BLOCK_SWITCH
#define APP_CHECK_BLOCK()			do{ APP_FLAGS.b_keyb_block_en = 0; \
									}while(0)
#else									
#define APP_CHECK_BLOCK()			do{ \
										/*проверяем условие разблокировки */ \
										if( (app_keyb_serv_data[KEYB_PLUS].push_cnt == APP_BLINK_IN_BLOCK_KEYB) && \
											(app_keyb_serv_data[KEYB_PWR].push_cnt == 0) && \
											(app_keyb_data[KEYB_PLUS].state == KEYB_RELEASED) && \
											(app_keyb_data[KEYB_PWR].state == KEYB_RELEASED)){ \
											/*переводим в противоположное состояние значение блокировки*/ \
											APP_FLAGS.b_keyb_block_en = (APP_FLAGS.b_keyb_block_en == 1)? 0: 1; \
											/*подаем длинный сигнал*/ \
											APP_BEEP_UNPARING_SINGLE(); \
											/*обнуляем время для мигания*/ \
											app_blink_time_ms = 0; \
											/*переводим индикацию в режим "блок/разблок"*/ \
											app_ind_state = IND_KEYB_BLOCK;\
										} \
									}while(0)
#endif
									
#ifdef APP_CHECK_BLE_SWITCH
									
#ifndef NEW_BLE_STATUS_INDICATION
									
#define APP_CHANGE_BLE()	do{																														\
															/* переводим в противоположное состояние значение BLE */ 	\
														APP_FLAGS.b_ble_en = !APP_FLAGS.b_ble_en; 									\
															/*подаем длинный сигнал*/ 																	\
														if(APP_FLAGS.b_sound_en == 1)																\
															APP_BEEP_UNPARING_SINGLE();																\
															/*обнуляем время для мигания*/ 														\
														app_blink_time_ms = 0; 																			\
															/*переводим индикацию в режим "вкл./выкл. BLE"*/ 					\
														app_ind_ble = IND_BLE_EN;																		\
															/*если BLE требуется отключить  */ 												\
														if(APP_FLAGS.b_ble_en) r4s_slave_adv_disable();							\
														else r4s_slave_adv_restart();																\
													}while(0);	

#else
													
#define APP_CHANGE_BLE()	do{																														\
															/* переводим в противоположное состояние значение BLE */ 	\
														APP_FLAGS.b_ble_en = !APP_FLAGS.b_ble_en; 									\
															/*обнуляем время для мигания*/ 														\
														app_blink_time_ms = 0; 																			\
															/*подаем длинный сигнал*/ 																	\
														if(APP_FLAGS.b_sound_en == 1)																\
														{																														\
															err_code = buz_reset_beeps();															\
															APP_ERROR_CHECK(err_code);																\
															err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);\
															APP_ERROR_CHECK(err_code);																\
															err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);\
															APP_ERROR_CHECK(err_code);																\
														}																														\
															/*переводим индикацию в режим "вкл./выкл. BLE"*/ 					\
														app_ind_ble = IND_BLE_EN;																		\
															/*если BLE требуется отключить  */ 												\
														if(APP_FLAGS.b_ble_en) r4s_slave_adv_disable();							\
														else r4s_slave_adv_restart();																\
													}while(0);	

#endif
													
#else
#define APP_CHANGE_BLE()	do{																														\
														APP_FLAGS.b_ble_en = 0; 																		\
													}while(0);								
#endif	
													
#define APP_BEEP_UNPARING_SINGLE()	do{ \
											APP_ERROR_CHECK(buz_add_beep(APP_UNPAIR_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_SINGLE));\
									}while(0)
#define APP_BEEP_SINGLE()			do{ \
										if(APP_FLAGS.b_sound_en == 1) \
											APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_SINGLE));\
									}while(0)

#define APP_BEEP_SHORT_MULTI()			do{ \
										if(APP_FLAGS.b_sound_en == 1) \
											APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_SINGLE));\
									}while(0)

#define APP_SOUND_CHANGE_CHEK()		do{ \
										if(app_keyb_data[KEYB_PLUS].pressed_time_ms >= APP_PUSH_BTN_SOUND_MS) \
										{ \
											APP_FLAGS.b_sound_en = (APP_FLAGS.b_sound_en == 1)? 0: 1; \
											APP_BEEP_SINGLE(); \
											APP_FLAGS.b_waiting_unpress_btn = 1; \
											break; \
										} \
									}while(0)

#define TIMERS_MINUTES(t)			((t)*60)
#define TIMERS_HOURS(t)				(TIMERS_MINUTES(t)*60)
#define IN_TIMERS_HOURS(t)			((t)/60/60)
                                    
#define NIGHTLIGHT_MIN_TIME_MS      (300*TIMERS_TICK_MS*2U)
									
#ifdef CONTINENT_USA
	#define ROUND_TEMP(t)				((uint16_t)(((t)+0.05)*10))
#endif
/********* TYPES ****************************************************************/
#pragma pack(push, 1)
typedef struct{
	uint8_t		btn_num;		//номер последней нажатой кнопки
	uint32_t 	time_push_ms;	//время нажатия кнопки
}app_last_press_btn_t;

typedef struct{
	uint8_t		led_40			:1;
	uint8_t		led_55			:1;
	uint8_t		led_70			:1;
	uint8_t		led_85			:1;
}app_led_seg_t;

typedef struct{ //структура для управления ночной подсветкой
	uint32_t		cycle_time_10ms;			// время полного цикла смены цвета
	uint32_t		period_work_1c;				// время работы ночника
}color_nightlight_time_t;

typedef struct{
	uint8_t			brightness; //яркость
	cl_led_name_t	led; //значение шим для каждого светодиода
}color_disco_t;

typedef struct{ //структура для управления RGB
	uint8_t			idx;		//индекс палитры
	uint8_t			activ;		//ативность модуля
}color_config_t;

typedef struct{ //структура для записи в flash
	color_config_t		color_config[APP_COLOR_PALLET_NUM_MAX]; //индекс по какому обращаться к устройству
	cl_gradient_t 		color_table[APP_COLOR_PALLET_NUM_MAX]; //цветовая палитра
	uint16_t			crc16; //контрольная сумма
}app_flash_data_t;
#pragma pack(pop)

typedef enum{ //возможные состояния индикации одинаковые для всех режимов
	IND_IDLE,
	IND_KEYB_BLOCK,
	IND_UNPARING,
	IND_PARING,
	IND_MASS_FW_UPDATE,
	IND_END_ERROR_MASS_FW_UPDATE,
	IND_END_SUCCESS_MASS_FW_UPDATE,
	IND_BLE_EN,
    IND_ERROR,
}app_ind_state_t;
/********* GLOBAL VARIABLES *****************************************************/
/********* LOCAL VARIABLES ******************************************************/
static int RGB_TYPE	= 0;
static float quantization_color[5][3] = {	{0.000, 0.000, 0.000},		// not correla 
											{0.299, 0.587, 0.114}, 		// NTSC RGB
											{0.222, 0.707, 0.071},		// PAL_SECAM RGB 
											{0.212, 0.701, 0.087},		// SMPTE-C RGB 
											{0.212, 0.716, 0.072}};		// sRGB
static const uint8_t fib_array[] = {1,1,2,3,5,8,13,21,34,55,89,144,233};
static uint8_t app_disco_dec_time;
static uint8_t app_disco_time_max;

#define APP_STATE               (((app_ram_data_struct_t*) application_get_addr_ram())->app_state)
//static app_state_t 				app_state = APP_START;				/* состояние state machine*/

static app_state_t      	app_prew_state = APP_START;			/* предыдущее состояние машины если изменился app_state*/
static app_state_t 				app_prew_state_save = APP_START;//для хранения состояния машины, для возврата

#define MOBILE_STATE            (((app_ram_data_struct_t*) application_get_addr_ram())->app_mobile_state)
//static app_mobile_state_t		app_mobile_state = MOB_BOILING;		/* последний режим захождения был кипячение*/
static app_ind_state_t			app_ind_state = IND_IDLE;			/* состояние индикации в standby режиме*/
#ifdef APP_CHECK_BLE_SWITCH
static app_ind_state_t			app_ind_ble = IND_IDLE;			/* индикация BLE в standby режиме*/
#endif
//static app_flags_t				app_flags;							/* флаги используемые в application*/
#define APP_FLAGS               (((app_ram_data_struct_t*) application_get_addr_ram())->app_flags)

static uint32_t					app_user_on_cnt;					/* счетчик включений устройства пользователем*/

static app_led_seg_t			app_leds;								/* состояние светодиодов без ШИМ'а*/
static keyb_data_t				app_keyb_data[KEYB_BUTTON_COUNT]; 		/* данные с клавиатуры*/
static keyb_services_data_t		app_keyb_serv_data[KEYB_BUTTON_COUNT];	/* сервисные данные с клавиатуры*/
static app_last_press_btn_t		app_last_btn;							/* информация последней нажатой кнопки*/

#ifdef CONTINENT_USA
	static float_t boiling_ind_temp;												/* температура индикации кипячения */
#else
	static uint8_t boiling_ind_temp;												/* температура индикации кипячения */
#endif
#define BOOLING_TEMP                        (((app_ram_data_struct_t*) application_get_addr_ram())->booling_temp)

#define KEEP_WARM_CTRL_TYPE                 (((app_ram_data_struct_t*) application_get_addr_ram())->keep_warm_ctrl_type)
#define KEEP_WARM_CTRL_TYPE_PREW            (((app_ram_data_struct_t*) application_get_addr_ram())->keep_warm_ctrl_type_prew)
#define BOOST_STATE                         (((app_ram_data_struct_t*) application_get_addr_ram())->boost_state)

//static keep_warm_ctrl_type_t	keep_warm_ctrl_type		= KEEP_WARM_CTRL_REG;	/* алгоритм поддержания температуры регулятор или разгон */
//static keep_warm_ctrl_type_t	keep_warm_ctrl_type_prew= KEEP_WARM_CTRL_REG;	/* алгоритм поддержания температуры регулятор или разгон */
//static boost_state_type_t		boost_state				= BOOST_FINISHED;		/* состояние разгона */

volatile static uint32_t	app_blink_time_ms = 0;														/* таймера для мигания светодиодами*/
static uint16_t boiling_min_time_downcounter_s = 0;											/* счетчик минимального времени кипения */
static uint16_t boilig_temp_update_upcounter_s = 0;											/* счетчик времени обновления температуры кипения */
static uint16_t boilig_complete_ind_time_downcounter_s = APP_BOILING_COMPLETE_IND_TIME_S;	/* счетчик времени индикации состояния кипения после закипания чайника */

#define KEEP_WARM_TIME_DOWNCOUNTER_S        (((app_ram_data_struct_t*) application_get_addr_ram())->keep_warm_time_downcounter_s)
#define CURRENT_PERIOD_WORK_1C              (((app_ram_data_struct_t*) application_get_addr_ram())->current_period_work_1c)
#define CURRENT_TIME_10MS                   (((app_ram_data_struct_t*) application_get_addr_ram())->current_time_10ms)
//static uint16_t keep_warm_time_downcounter_s = APP_KEEPWARM_MAX_TIME_S;	 					/* счетчик времени подогрева */

static float delta_temp_ind;			// дельта температуры для отображения
static float add_temp_ind;				// дополнение для отображения к температуре датчика


static bool app_show_boiling_temp = false;													/* Флаг отображения температуры кипения вместо реальной температуры */
static bool boiling_temp_update_flag = false;												/* Флаг таймаута изменения температуры кипячения */
static bool boiling_temp_upcount_flag = true;												/* флаг изменения температуры от реальной вверх к температуре кипения */

static color_disco_t app_disco_color = COLOR_DISCO_DEF_VALUE;								/* палитра значений в режиме ДИСКО*/
static color_nightlight_time_t color_time = { 300*TIMERS_TICK_MS*2, TIMERS_HOURS(8)};		/* таймера режима "ночник" */
static color_config_t color_option[APP_COLOR_PALLET_NUM_MAX] = {
																	{0, 1},
																	{1, 1},
																};
static cl_gradient_t pwm_etalon_table[APP_COLOR_PALLET_NUM_MAX] = {							/* данные о палитре значений RGB светодиода*/
																	COLOR_BOIL_DEF_VALUE, 
																	COLOR_NIGHTLED_DEF_VALUE
																	};
																	
static app_save_info_struct_t	app_pof_info __attribute__((aligned(sizeof(uint32_t))));
static app_save_info_struct_pre_t	app_pof_info_pre __attribute__((aligned(sizeof(uint32_t))));
																	
static uint16_t app_timeout_boost_s = 0;	

static bool app_notification_uart_flg = false;
																	
static uint16_t app_switch_mass_timeout = 0;	//timeout для перехода в режим MASS_FW_UPDATE
static uint8_t on_mass_cnt = 0;									//кол-во включений на ограничение на вход в режим MASS_FW_UPDATE
																	
//проверка параметров
//STATIC_ASSERT(sizeof(keep_warm_temp) == APP_KEEP_WARM_END_INDEX);		/* проверка количества значений в массиве*/
/********* FUNCTION PROTOTYPES **************************************************/
inline static void app_clear_all_led(void);
inline static void app_set_all_led(void);

static void app_simple_timeout_timer_handler(void);
static void app_common_10ms_timeout_handler(void);
static void app_sec_timer_handler(void);
static void app_update_leds(void);
static void app_timeout_timers_restart(uint16_t timeout_s);
static void app_timeout_timers_stop(void);
static void app_show_start(void);
static void app_show_standby(app_ind_state_t *p_ind_state);
static void app_show_boiling(app_ind_state_t *p_ind_state);
static void app_show_warm(app_ind_state_t *p_ind_state);
static void app_show_warm_cfg(app_ind_state_t *p_ind_state);
static void app_show_keepwarm(app_ind_state_t *p_ind_state);
static void app_show_pairing(void);
static void app_show_fw_update(void);
static void app_show_error(app_ind_state_t *p_ind_state);
uint8_t api_stop_nightlight(void);
static void app_notification_uart(void);
/********* FUNCTIONS IMPLEMENTATION *********************************************/
static bool is_error_sensor()
{
    uint8_t temp;
    temp = temp_get_val();
    return (temp == 0 || temp >= TEMP_EMPTY_KETTLE_TEMP_C);
}

static bool app_get_error_sensor()
{
    // если обрыв датчика
	if (is_error_sensor()) {
        if (APP_STATE != APP_ERROR) {
            app_prew_state_save = APP_STATE;
        }
		APP_STATE = APP_ERROR;
		app_blink_time_ms = 0;
		return true;
	}
	return false;
}
/**
 *  @brief  Функция медленно гасит светодиоды с помощью чисел Фибоначчи
 *
 *  @param  *color 	- значение цвета
 *  @return 0 - число найдено
 *			1 - число не найдено
 *
 */
uint8_t app_fibonachchi_value(uint8_t *color){
	int i;	
	// определяем максимально близкое (равное) значение Фибоначчи меньше заданному
	for(i=0; i<(sizeof(fib_array)/sizeof(uint8_t)); ++i) 
		if(fib_array[i]>=*color) break;
	*color = (!i)?(0):(fib_array[i-1]);	// новое (предшедствующее) значение из чисел Фибоначчи
	return ( i >= (sizeof(fib_array)/sizeof(uint8_t)) )?(1):(0);
}
/**
 *  @brief  Функция очищает все светодиоды
 *
 *  @param  none
 *  @return none
 *
 */
inline static void app_clear_all_led(void){
	app_leds.led_40 = \
	app_leds.led_55 = \
	app_leds.led_70 = \
	app_leds.led_85 = 0;
}
/**
 *  @brief  Функция зажигает все светодиоды
 *
 *  @param  none
 *  @return none
 *
 */
inline static void app_set_all_led(void){
	app_leds.led_40 = \
	app_leds.led_55 = \
	app_leds.led_70 = \
	app_leds.led_85 = 1;
}
/**
 *  @brief  Обработчик таймера отмеряющего таймаут приложения. Используется для переходов state machine
 *
 *  @param  none
 *  @return none
 *
 */
static void app_simple_timeout_timer_handler(void){
	APP_FLAGS.b_simple_timeout = 1;
	APP_ERROR_CHECK(timer_stop(TIMER_APP_SIMPLE_TIMEOUT));
	return;
}
/**
 *  @brief  Обработчик таймера срабатывающего каждые 10мс
 *
 *  @param  none
 *  @return none
 *
 */
static void app_common_10ms_timeout_handler(void){

	static uint16_t timeout_1s = 0;

	if(app_switch_mass_timeout) --app_switch_mass_timeout;
	
	timeout_1s = (timeout_1s +1)%100;
	if(!timeout_1s) app_notification_uart_flg = true;
	
	if(app_blink_time_ms < UINT32_MAX) ++app_blink_time_ms;
	if(app_disco_dec_time) --app_disco_dec_time;
	if(++CURRENT_TIME_10MS >= color_time.cycle_time_10ms) 
        CURRENT_TIME_10MS = 0;
}
/**
 *  @brief  Обработчик секундного таймера приложения.
 * 			Импользуется для: 	1. изменения индикации внутри одного состояния state machine
 *   							2. отсчета времени поддержания
 * 								3. отсчета минимального времени кипячения
 * 								4. отсчета времени работы режима "ночник"
 *								5. отсчета времени работы длительного кипения
 *  @param  none
 *  @return none
 *
 */
static void app_sec_timer_handler(void){
	
	if(app_timeout_boost_s) --app_timeout_boost_s;
	
	if( 0 != boiling_min_time_downcounter_s ){
		boiling_min_time_downcounter_s--;	//секундомер до отключения кипечения
		add_temp_ind += delta_temp_ind;
		if( boiling_min_time_downcounter_s == 0 ) APP_FLAGS.b_boiling_complete = 1;
	}

	if( ++boilig_temp_update_upcounter_s >= APP_BOILING_TEMP_UPDATE_TIME_S )
	{
		boilig_temp_update_upcounter_s = 0;
		boiling_temp_update_flag = true;
	}
	if( 1 == APP_FLAGS.b_keep_wrm_boost_cmplt ){
		if( 0 != KEEP_WARM_TIME_DOWNCOUNTER_S )
            KEEP_WARM_TIME_DOWNCOUNTER_S--;
	}

	if( 1 == APP_FLAGS.b_boiling_complete ){
		if( 0 != boilig_complete_ind_time_downcounter_s )boilig_complete_ind_time_downcounter_s--;
	}
	if(CURRENT_PERIOD_WORK_1C < color_time.period_work_1c){
		++CURRENT_PERIOD_WORK_1C; 
        if(CURRENT_PERIOD_WORK_1C == color_time.period_work_1c) 
            APP_FLAGS.b_night_on = false;
	}
	return;
}
static void mass_hw_update_timer_handler(void)
{
    APP_ERROR_CHECK(sd_nvic_SystemReset());
}
/**
 *  @brief  Функция перезапускает таймер отсчитывающий таймауты переходов между состояниями state machine
 *
 *  @param none
 *  @return none
 *
 */
static void app_timeout_timers_stop(void){
	APP_ERROR_CHECK(timer_stop(TIMER_APP_SIMPLE_TIMEOUT));
	APP_FLAGS.b_simple_timeout = 0;
}
/**
 *  @brief  Функция перезапускает таймер отсчитывающий таймауты переходов между состояниями state machine
 *
 *  @param[in]  timeout_s - установленный таймаут в сек
 *  @return none
 *
 */
static void app_timeout_timers_restart(uint16_t timeout_s){
	uint32_t err_code;

	err_code = timer_stop(TIMER_APP_SIMPLE_TIMEOUT);
	APP_ERROR_CHECK(err_code);
	err_code = timer_write_period(TIMER_APP_SIMPLE_TIMEOUT, TIMERS_SECOND(timeout_s));
	APP_ERROR_CHECK(err_code);
	err_code = timer_reset(TIMER_APP_SIMPLE_TIMEOUT);
	APP_ERROR_CHECK(err_code);
	APP_FLAGS.b_simple_timeout = 0;
	err_code = timer_start(TIMER_APP_SIMPLE_TIMEOUT);
	APP_ERROR_CHECK(err_code);
}
/**
 *  @brief  Индикация режима APP_START
 *
 *  @param  none
 *  @return none
 *
 */
static void app_show_start(void){
#ifdef APP_CHECK_BLE_SWITCH
	if(app_ind_ble==IND_BLE_EN)
	{
		app_clear_all_led();
		if(app_blink_time_ms >= 210){ 
			app_blink_time_ms = 0; 
		}
		switch((app_blink_time_ms*TIMERS_TICK_MS/APP_LIGHT_RUN_MS)%LED_COMMON_INCLUDE_COUNT)
		{
			case 0: if(!APP_FLAGS.b_ble_en) app_leds.led_85 = 1; else app_leds.led_40 = 1; break;
			case 1: if(!APP_FLAGS.b_ble_en) app_leds.led_70 = 1; else app_leds.led_55 = 1; break;
			case 2: if(!APP_FLAGS.b_ble_en) app_leds.led_55 = 1; else app_leds.led_70 = 1; break;
			case 3: if(!APP_FLAGS.b_ble_en) app_leds.led_40 = 1; else app_leds.led_85 = 1; break;
		}
	}
	

	else if(APP_FLAGS.b_ble_en)
	{
		app_clear_all_led();
		if(app_blink_time_ms >= 210){ 
			app_blink_time_ms = 0; 
		}
		switch((app_blink_time_ms*TIMERS_TICK_MS/APP_BLE_OFF_IND_MS)%2)
		{
			case 0: 
			{
#ifndef NEW_BLE_STATUS_INDICATION
				app_set_all_led();  
#else
				app_leds.led_40 = 1;
#endif
				break;
			}
			case 1: 
			{
				app_clear_all_led(); 
				break;
			}
		}
	}
	else
#endif
	{
		app_set_all_led();
	
			//RGB подсветка
		APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
		APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
		APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
	}
	
	return;
}
/**
 *  @brief  Индикация режима APP_STAND_BY
 *
 *  @param[inout]  p_ind_state - указатель на текущий стэйт подсветки
 *  @return none
 *
 */
static void app_show_standby(app_ind_state_t *p_ind_state){
	switch(*p_ind_state)
	{
		case IND_IDLE:
		{
			app_clear_all_led();
			break;
		}
		case IND_KEYB_BLOCK:
		{
		
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_BLOCK_KEYB){
				//если по времени прошло APP_BLINK_IN_BLOCK_KEYB или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
			}
			else if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
				app_set_all_led(); //устанавливаем все светодиоды
				cl_led_name_t rgb = {0xFF, 0, 0};
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)rgb.r - (double)rgb.r*quantization_color[RGB_TYPE][0]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)rgb.g - (double)rgb.g*quantization_color[RGB_TYPE][1]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)rgb.b - (double)rgb.b*quantization_color[RGB_TYPE][2]));
			}
			else{
				app_clear_all_led(); //тушим все светодиоды
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			}
			
			break;
		}
		case IND_PARING:
		{
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_PARING){
				//если по времени прошло APP_BLINK_IN_PARING или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
			}
			else{ 
				if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
					app_set_all_led(); //устанавливаем все светодиоды
				}
				else{
					app_clear_all_led(); //тушим все светодиоды
				}
			}
			break;
		}
		case IND_UNPARING:
		{
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_UNPARING){
				//если по времени прошло APP_BLINK_IN_UNPARING или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
			}
			else if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
				app_set_all_led(); //устанавливаем все светодиоды
			}
			else{
				app_clear_all_led(); //тушим все светодиоды
			}	
			break;
		}

		default:
		{
			*p_ind_state = IND_IDLE;
			break;
		}

	}
	return;
}
/**
 *  @brief  Индикация режима APP_NIGHTLIGHT
 *
 *  @param[inout]  p_ind_state - указатель на текущий стэйт подсветки
 *  @return none
 *
 */
static void app_show_nightlight(app_ind_state_t *p_ind_state){
	switch(*p_ind_state)
	{
		case IND_IDLE:
		{
			app_clear_all_led();
			break;
		}
		case IND_KEYB_BLOCK:
		{
			
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_BLOCK_KEYB){
				//если по времени прошло APP_BLINK_IN_BLOCK_KEYB или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
			}
			else if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
				app_set_all_led(); //устанавливаем все светодиоды
				cl_led_name_t rgb = {0xFF, 0, 0};
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)rgb.r - (double)rgb.r*quantization_color[RGB_TYPE][0]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)rgb.g - (double)rgb.g*quantization_color[RGB_TYPE][1]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)rgb.b - (double)rgb.b*quantization_color[RGB_TYPE][2]));
			}
			else{
				app_clear_all_led(); //тушим все светодиоды
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			}
			break;
		}
		case IND_PARING:
		{
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_PARING){
				//если по времени прошло APP_BLINK_IN_PARING или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
			}
			else if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
				app_set_all_led(); //устанавливаем все светодиоды
			}
			else{
				app_clear_all_led(); //тушим все светодиоды
			}
			break;
		}
		case IND_UNPARING:
		{
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_UNPARING){
				//если по времени прошло APP_BLINK_IN_UNPARING или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
			}
			else if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
				app_set_all_led(); //устанавливаем все светодиоды
			}
			else{
				app_clear_all_led(); //тушим все светодиоды
			}	
			break;
		}
		default:
		{
			*p_ind_state = IND_IDLE;
			break;
		}
	}
	return;
}
/**
 *  @brief  Индикация режима APP_DISCO
 *
 *  @param[inout]  p_ind_state - указатель на текущий стэйт подсветки
 *  @return none
 *
 */
static void app_show_disco(app_ind_state_t *p_ind_state){
	switch(*p_ind_state)
	{
		case IND_IDLE:
		{
			app_clear_all_led();
			break;
		}
		case IND_KEYB_BLOCK:
		{
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_BLOCK_KEYB){
				//если по времени прошло APP_BLINK_IN_BLOCK_KEYB или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
			}
			else if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
				app_set_all_led(); //устанавливаем все светодиоды
				cl_led_name_t rgb = {0xFF, 0, 0};
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)rgb.r - (double)rgb.r*quantization_color[RGB_TYPE][0]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)rgb.g - (double)rgb.g*quantization_color[RGB_TYPE][1]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)rgb.b - (double)rgb.b*quantization_color[RGB_TYPE][2]));
			}
			else{
				app_clear_all_led(); //тушим все светодиоды
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			}
			break;
		}
		case IND_PARING:
		{
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_PARING){
				//если по времени прошло APP_BLINK_IN_PARING или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
			}
			else if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
				app_set_all_led(); //устанавливаем все светодиоды
			}
			else{
				app_clear_all_led(); //тушим все светодиоды
			}
			break;
		}
		case IND_UNPARING:
		{
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_UNPARING){
				//если по времени прошло APP_BLINK_IN_UNPARING или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
			}
			else if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
				app_set_all_led(); //устанавливаем все светодиоды
			}
			else{
				app_clear_all_led(); //тушим все светодиоды
			}	
			break;
		}
		default:
		{
			*p_ind_state = IND_IDLE;
			break;
		}		
	}
	return;
}

/**
 *  @brief  Индикация режима APP_ERROR
 *
 *  @param[inout]  p_ind_state - указатель на текущий стэйт подсветки
 *  @return none
 *
 */
static void app_show_error(app_ind_state_t* p_ind_state)
{
    switch (*p_ind_state) {
        case IND_IDLE:
        {
            app_clear_all_led();
            //if (app_blink_time_ms >= TIMERS_SECOND(APP_LED_ERROR_TIMEOUT_S)) {
                //если по времени прошло APP_LED_ERROR_TIMEOUT_S
            uint8_t temp;
            temp = temp_get_val();
            if (temp !=0 && temp <= SENSOR_COOLDOWN_TEMP) {
                APP_STATE = app_prew_state_save;
                break;
            }
            if ((app_blink_time_ms % (TIMERS_MILLISECOND(APP_BLINK_ERROR_MS*2))) <= TIMERS_MILLISECOND(APP_BLINK_ERROR_MS)) {
                app_leds.led_40 = 1;
            } else {
                app_leds.led_85 = 1;
            }
            break;
        }
        case IND_ERROR: 
        {
            app_clear_all_led();
            if ((app_blink_time_ms % (TIMERS_MILLISECOND(APP_BLINK_ERROR_MS*2))) <= TIMERS_MILLISECOND(APP_BLINK_ERROR_MS)) {
                app_leds.led_55 = 1;
            } else {
                app_leds.led_70 = 1;
            }
            break;
        }
        default:
        {
            *p_ind_state = IND_IDLE;
            break;
        }
    }
    return;
}

/**
 *  @brief  Индикация режима APP_BOILING_PROC
 *
 *  @param[inout]  p_ind_state - указатель на текущий стэйт подсветки
 *  @return none
 *
 */
static void app_show_boiling(app_ind_state_t *p_ind_state){
	switch(*p_ind_state)
	{
		case IND_IDLE:
		{
			app_clear_all_led();
#ifdef CONTINENT_USA
				if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_1)) app_leds.led_40 = 1;
				else if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_2)) app_leds.led_55 = 1;
				else if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_3)) app_leds.led_70 = 1;
				else if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_4)) app_leds.led_85 = 1;
#else
			switch(BOOLING_TEMP)
			{
				case 0: break;
				case TEMP_WARM_LED_1: app_leds.led_40 = 1; break;
				case TEMP_WARM_LED_2: app_leds.led_55 = 1; break;
				case TEMP_WARM_LED_3: app_leds.led_70 = 1; break;
				case TEMP_WARM_LED_4: app_leds.led_85 = 1; break;
			}
#endif			
			break;
		}
		case IND_KEYB_BLOCK:
		{
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_BLOCK_KEYB){
				//если по времени прошло APP_BLINK_IN_BLOCK_KEYB или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			}
			else if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
				app_set_all_led(); //устанавливаем все светодиоды
				cl_led_name_t rgb = {0xFF, 0, 0};
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)rgb.r - (double)rgb.r*quantization_color[RGB_TYPE][0]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)rgb.g - (double)rgb.g*quantization_color[RGB_TYPE][1]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)rgb.b - (double)rgb.b*quantization_color[RGB_TYPE][2]));
			}
			else{
				app_clear_all_led(); //тушим все светодиоды
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			}
			break;
		}
		default :
		{
			*p_ind_state = IND_IDLE;
			break;
		}
	}
	return;
}
/**
 *  @brief  Индикация режима APP_CONFIG_WARM
 *
 *  @param[inout]  p_ind_state - указатель на текущий стэйт подсветки
 *  @return none
 *
 */
static void app_show_warm_cfg(app_ind_state_t *p_ind_state){
	switch(*p_ind_state)
	{
		case IND_IDLE:
		{
			app_clear_all_led();
#ifdef CONTINENT_USA
				if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_1)) app_leds.led_40 = 1;
				else if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_2)) app_leds.led_55 = 1;
				else if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_3)) app_leds.led_70 = 1;
				else if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_4)) app_leds.led_85 = 1;
#else
			switch(BOOLING_TEMP)
			{
				case 0: break;
				case TEMP_WARM_LED_1: app_leds.led_40 = 1; break;
				case TEMP_WARM_LED_2: app_leds.led_55 = 1; break;
				case TEMP_WARM_LED_3: app_leds.led_70 = 1; break;
				case TEMP_WARM_LED_4: app_leds.led_85 = 1; break;
			}
#endif
			break;
		}
		case IND_KEYB_BLOCK:
		{
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_BLOCK_KEYB){
				//если по времени прошло APP_BLINK_IN_BLOCK_KEYB или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			}
			else if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
				app_set_all_led(); //устанавливаем все светодиоды
				cl_led_name_t rgb = {0xFF, 0, 0};
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)rgb.r - (double)rgb.r*quantization_color[RGB_TYPE][0]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)rgb.g - (double)rgb.g*quantization_color[RGB_TYPE][1]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)rgb.b - (double)rgb.b*quantization_color[RGB_TYPE][2]));
			}
			else{
				app_clear_all_led(); //тушим все светодиоды
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			}
			break;
		}
		default :
		{
			*p_ind_state = IND_IDLE;
			break;
		}
	}
	return;
}
/**
 *  @brief  Индикация режима APP_WARM_PROC
 *
 *  @param[inout]  p_ind_state - указатель на текущий стэйт подсветки
 *  @return none
 *
 */
static void app_show_warm(app_ind_state_t *p_ind_state){
	switch(*p_ind_state)
	{
		case IND_IDLE:
		{
			app_clear_all_led();
#ifdef CONTINENT_USA
				if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_1)) app_leds.led_40 = 1;
				else if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_2)) app_leds.led_55 = 1;
				else if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_3)) app_leds.led_70 = 1;
				else if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_4)) app_leds.led_85 = 1;
#else
			switch(BOOLING_TEMP)
			{
				case 0: break;
				case TEMP_WARM_LED_1: app_leds.led_40 = 1; break;
				case TEMP_WARM_LED_2: app_leds.led_55 = 1; break;
				case TEMP_WARM_LED_3: app_leds.led_70 = 1; break;
				case TEMP_WARM_LED_4: app_leds.led_85 = 1; break;
			}
#endif
			break;
		}
		case IND_KEYB_BLOCK:
		{
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_BLOCK_KEYB){
				//если по времени прошло APP_BLINK_IN_BLOCK_KEYB или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			}
			else if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
				app_set_all_led(); //устанавливаем все светодиоды
				cl_led_name_t rgb = {0xFF, 0, 0};
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)rgb.r - (double)rgb.r*quantization_color[RGB_TYPE][0]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)rgb.g - (double)rgb.g*quantization_color[RGB_TYPE][1]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)rgb.b - (double)rgb.b*quantization_color[RGB_TYPE][2]));
			}
			else{
				app_clear_all_led(); //тушим все светодиоды
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			}
			break;
		}
		default :
		{
			*p_ind_state = IND_IDLE;
			break;
		}
	}
	return;
}
/**
 *  @brief  Индикация режима APP_KEEPWARM_PROC
 *
 *  @param[inout]  p_ind_state - указатель на текущий стэйт подсветки
 *  @return none
 *
 */
static void app_show_keepwarm(app_ind_state_t *p_ind_state){
	switch(*p_ind_state)
	{
		case IND_IDLE:
		{
			app_clear_all_led();
#ifdef CONTINENT_USA
				if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_1)) app_leds.led_40 = 1;
				else if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_2)) app_leds.led_55 = 1;
				else if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_3)) app_leds.led_70 = 1;
				else if(ROUND_TEMP(BOOLING_TEMP) == ROUND_TEMP(TEMP_WARM_LED_4)) app_leds.led_85 = 1;
#else
			switch(BOOLING_TEMP)
			{
				case 0: break;
				case TEMP_WARM_LED_1: app_leds.led_40 = 1; break;
				case TEMP_WARM_LED_2: app_leds.led_55 = 1; break;
				case TEMP_WARM_LED_3: app_leds.led_70 = 1; break;
				case TEMP_WARM_LED_4: app_leds.led_85 = 1; break;
			}
#endif
			break;
		}
		case IND_KEYB_BLOCK:
		{
			//проверяем сколько раз уже мигнули
			if((app_blink_time_ms / APP_FULL_BLINK_CYCLE) >= APP_BLINK_IN_BLOCK_KEYB){
				//если по времени прошло APP_BLINK_IN_BLOCK_KEYB или более мигания
				*p_ind_state = IND_IDLE; //возвращаемся в режим IDLE
				app_clear_all_led(); //очищаем все светодиоды
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			}
			else if((app_blink_time_ms % APP_FULL_BLINK_CYCLE) <= APP_BLINK_ON_MS){
				app_set_all_led(); //устанавливаем все светодиоды
				cl_led_name_t rgb = {0xFF, 0, 0};
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)rgb.r - (double)rgb.r*quantization_color[RGB_TYPE][0]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)rgb.g - (double)rgb.g*quantization_color[RGB_TYPE][1]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)rgb.b - (double)rgb.b*quantization_color[RGB_TYPE][2]));
			}
			else{
				app_clear_all_led(); //тушим все светодиоды
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			}
			break;
		}
		default :
		{
			*p_ind_state = IND_IDLE;
			break;
		}
	}
	return;
}
/**
 *  @brief  Индикация режима APP_TEST
 *
 *  @param[inout]  p_ind_state - указатель на текущий стэйт подсветки
 *  @return none
 *
 */
static void app_show_test(app_ind_state_t *p_ind_state){
	switch(*p_ind_state)
	{
		case IND_IDLE:
		{
			app_clear_all_led();
			switch((app_blink_time_ms*TIMERS_TICK_MS/APP_TEST_LIGHT_RUN_MS)%LED_COMMON_INCLUDE_COUNT)
			{
				case 0: app_leds.led_40 = 1; break;
				case 1: app_leds.led_55 = 1; break;
				case 2: app_leds.led_70 = 1; break;
				case 3: app_leds.led_85 = 1; break;
			}
			break;
		}
		case IND_KEYB_BLOCK:
		{
			*p_ind_state = IND_IDLE;
			break;
		}
		default :
		{
			*p_ind_state = IND_IDLE;
			break;
		}
	}
	return;
}
/**
 *  @brief  Индикация режима APP_PAIRING
 *
 *  @param  none
 *  @return none
 *
 */
static void app_show_pairing(void){
	app_clear_all_led();

	if(app_blink_time_ms == UINT32_MAX) app_blink_time_ms = 0;

	switch((app_blink_time_ms*TIMERS_TICK_MS/APP_LIGHT_RUN_MS)%LED_COMMON_INCLUDE_COUNT)
	{
		case 0: app_leds.led_40 = 1; break;
		case 1: app_leds.led_55 = 1; break;
		case 2: app_leds.led_70 = 1; break;
		case 3: app_leds.led_85 = 1; break;
	}
	return;
}
/**
 *  @brief  Индикация режима APP_FW_UPDATE
 *
 *  @param  none
 *  @return none
 *
 */
static void app_show_fw_update(void){
	app_clear_all_led();

	if(app_blink_time_ms == UINT32_MAX) app_blink_time_ms = 0;

	switch((app_blink_time_ms*TIMERS_TICK_MS/APP_LIGHT_RUN_MS)%LED_COMMON_INCLUDE_COUNT)
	{
		case 0: app_leds.led_85 = 1; break;
		case 1: app_leds.led_70 = 1; break;
		case 2: app_leds.led_55 = 1; break;
		case 3: app_leds.led_40 = 1; break;
	}
	return;
}
/**
 *  @brief  Индикация режима APP_MASS_FW_UPDATE
 *
 *  @param  none
 *  @return none
 *
 */
static void app_show_mass_fw_update(app_ind_state_t *p_ind_state)
{
	cl_led_name_t rgb;
	
	app_clear_all_led();
	
	switch(*p_ind_state)
	{
		case IND_IDLE:
		{
			cl_led_name_t tmp = {0xC3, 0x4C, 0xFF};
			memcpy(&rgb, &tmp, sizeof(cl_led_name_t));

			break;
		}
		case IND_MASS_FW_UPDATE:
		{
			if(app_blink_time_ms == UINT32_MAX) app_blink_time_ms = 0;

			switch((app_blink_time_ms*TIMERS_TICK_MS/APP_LIGHT_RUN_MS)%LED_COMMON_INCLUDE_COUNT)
			{
				case 0: app_leds.led_85 = 1; break;
				case 1: app_leds.led_70 = 1; break;
				case 2: app_leds.led_55 = 1; break;
				case 3: app_leds.led_40 = 1; break;
			}

            cl_led_name_t rgb_max = {0x00, 0x00, 0xFF};
            const uint8_t speed_rate = 1;
			memcpy(&rgb, &rgb_max, sizeof(cl_led_name_t));
								
			float gr_brightness = (float)pwm_etalon_table->etalon->brightness/MAX_BRIGHTNESS;
			float gr_time = (float)(abs((signed int)MAX_PERIOD_BRIGHTNESS/2 - (signed int)((app_blink_time_ms/speed_rate)%MAX_PERIOD_BRIGHTNESS)))/(MAX_PERIOD_BRIGHTNESS/2);
					
			rgb.r *= gr_brightness*gr_time;
			rgb.g *= gr_brightness*gr_time;
			rgb.b *= gr_brightness*gr_time;

			break;
		}
		case IND_END_ERROR_MASS_FW_UPDATE:
		{
			cl_led_name_t tmp = {0xFF, 0x00, 0x00};
			memcpy(&rgb, &tmp, sizeof(cl_led_name_t));
			break;
		}
		case IND_END_SUCCESS_MASS_FW_UPDATE:
		{
			cl_led_name_t tmp = {0x00, 0xFF, 0x00};
			memcpy(&rgb, &tmp, sizeof(cl_led_name_t));
			break;
		}
		default :
		{
			break;
		}
	}
	APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)rgb.r - (double)rgb.r*quantization_color[RGB_TYPE][0]));
	APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)rgb.g - (double)rgb.g*quantization_color[RGB_TYPE][1]));
	APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)rgb.b - (double)rgb.b*quantization_color[RGB_TYPE][2]));
	
	return;
}

/**
 *  @brief  Функция используется для корректировки показаний датчиков температуры.
 *			На выходе данные для отображения для пользователю.
 *			Изменяет глобалюную переменную boiling_ind_temp.
 *
 *  @param  none
 *  @return none
 *
 */
static void app_boiling_temp_update( void ){
	static const uint8_t step = 1;				/* шаг приращения температуры индикации */

	if( app_show_boiling_temp == false )
	{
		//если не установлен флаг возвращаем реальную температуру
#ifdef CONTINENT_USA
		boiling_ind_temp = ( temp_get_float_val() > APP_HEATING_TEMP_C ) ? APP_HEATING_TEMP_C : temp_get_float_val();
#else
		boiling_ind_temp = ( temp_get_val() > APP_HEATING_TEMP_C ) ? APP_HEATING_TEMP_C : temp_get_val();
#endif
	}
	else
	{
#ifdef CONTINENT_USA
		if( temp_get_float_val() > boiling_ind_temp + step )
#else
		if( temp_get_val() > boiling_ind_temp + step )
#endif
		{
			//отменим "замазку", т.к. реальная температура больше "замазки"
			app_show_boiling_temp = false;
#ifdef CONTINENT_USA
			boiling_ind_temp = ( temp_get_float_val() > APP_HEATING_TEMP_C ) ? APP_HEATING_TEMP_C : temp_get_float_val();
#else
			boiling_ind_temp = ( temp_get_val() > APP_HEATING_TEMP_C ) ? APP_HEATING_TEMP_C : temp_get_val();
#endif
		}
		else
		{
			if( boiling_temp_update_flag == false )return;		//если не сработал таймер обновления информации
			boiling_temp_update_flag = false;

			if( boiling_temp_upcount_flag == true )
			{
				//идем вверх
				if( ( boiling_ind_temp + step ) >=  APP_HEATING_TEMP_C )
				{
					boiling_ind_temp = APP_HEATING_TEMP_C;
					boiling_temp_upcount_flag = false;	//начинаем идти вниз
				}else{
					boiling_ind_temp += step;
				}
			}else{
				if( APP_STATE ==  APP_BOILING_PROC  )return;	//не снижаем температуру пока в режиме кипения
				//идем вниз
#ifdef CONTINENT_USA
				if( boiling_ind_temp  >  temp_get_float_val() + step )	
#else
				if( boiling_ind_temp  >  temp_get_val() + step )
#endif
				{
					boiling_ind_temp -= step;
					add_temp_ind -= delta_temp_ind; 
					if(add_temp_ind<=0) add_temp_ind = 0;
					boiling_ind_temp = ( boiling_ind_temp > APP_HEATING_TEMP_C ) ? APP_HEATING_TEMP_C : boiling_ind_temp;
				}else{
					boiling_ind_temp = ( temp_get_val() > APP_HEATING_TEMP_C ) ? APP_HEATING_TEMP_C : temp_get_val();
					app_show_boiling_temp = false;
					add_temp_ind = delta_temp_ind = 0;
				}
			}
		}
	}
	return;
}


/**
 *  @brief  Функция обновляет состояния светодиодов
 *
 *  @param  none
 *  @return none
 *
 */
static void app_update_leds(void){
	uint32_t err_code = NRF_SUCCESS;

	err_code = led_write_data(LED_40_TMP, app_leds.led_40);
	APP_ERROR_CHECK(err_code);
	err_code = led_write_data(LED_55_TMP, app_leds.led_55);
	APP_ERROR_CHECK(err_code);
	err_code = led_write_data(LED_70_TMP, app_leds.led_70);
	APP_ERROR_CHECK(err_code);
	err_code = led_write_data(LED_85_TMP, app_leds.led_85);
	APP_ERROR_CHECK(err_code);
}
/**
*  @brief 	Определяет какой алгоритм использовать для поддержания температуры - разгон или поддержание
*
*  @param[in]	temp_cur 		- текущее значение температуры
*  @param[in]	temp_set 		- температура для поддержания
*  @return 						- алгоритм разгон/поддержание
*
*/
static keep_warm_ctrl_type_t keep_warm_get_ctrl_type( uint8_t temp_cur, uint8_t temp_set ){
	if( ( temp_cur + APP_TEMP_DIFFERENCE_KEEP_WARM_BOOST_START_C ) <= temp_set ){
		return KEEP_WARM_CTRL_BOOST;
	}else{
		return KEEP_WARM_CTRL_REG;		
	}
}
/**
 *  @brief  Простой П-регулятор
 *
 *  @param[in]  Y - значение регулируемой величины
 *	@param[in]	U - уставка
 *	@param[in]	KV - коэффициент усиления 
 *  @return -	выход регулятора
 *			
 */
static uint16_t simple_reg( uint8_t Y, uint8_t U, uint8_t KV ){
	unsigned long int X;		//reg out
	if( Y > U ){ return 0; }
	X = ( U - Y )*KV;
	
	if( X > REG_MAX_PWM	 ){
		return REG_MAX_PWM	;
	}else{
		return X;
	}
}
/**
 *  @brief  Функция проверки flash памяти на чистоту
 *
 *  @param  none
 *
 *  @return 1 - страница пустая
 *			0 - страница не пустая
 */
static uint8_t is_flash_empty(uint32_t const *p_rom_addr){
	for(uint32_t const*check_p = p_rom_addr;
		check_p < (p_rom_addr + R4S_APP_PAGE_MAX_SIZE/sizeof(uint32_t));
		++check_p){
		//проверка страницы на пустоту
		if(*check_p != UINT32_MAX) return 0;
	}
	return 1;
}
/**
 *  @brief  	Функция получения указателя на данные которые надо сохранять
 *
 *  @param		none
 *
 *  @return		возвращает указатель на данные для записи
 *			
 */
/**
 *  @brief  Функция вызывается при срабатывании часов (1 сек)
 *
 *  @param  none
 *  @return none
 *
 */
static void calendar_one_sec_handle(void){
	uint32_t err_code;

	err_code = evcal_one_sec_handler();
	APP_ERROR_CHECK(err_code);
}
/**
 *  @brief  Функция вызывается при срабатывании событий из календаря
 *
 *  @param  none
 *  @return none
 *
 */
static void evcal_calendar_task(evcal_info_packet_t const*p_data){
	if(p_data == NULL) return;
	if(APP_FLAGS.b_keyb_block_en || APP_FLAGS.b_ble_en) return;	//режим "блокировки" или откл. BLE

	switch(p_data->array[1])
	{
		case CALENDAR_START_COM:
		{
			api_set_prog(p_data->array[2]);	
#ifdef CONTINENT_USA
			api_set_boil_temp(p_data->array[4]+p_data->array[3]);			
#else
			api_set_boil_temp(p_data->array[4]);
#endif
			api_start();
			break;
		}
		case CALENDAR_STOP_COM:
		{
			api_stop_nightlight();	// остановка ночника даже если он в фоновом процессе
			if(APP_STATE != APP_BOILING_PROC) api_stop();
			break;
		}
#ifdef CONTINENT_USA
		case CALENDAR_OPTION_USA_COM:
		{
			api_set_prog_option(&p_data->array[2]);
			api_start();
			break;
		}
#else
		case CALENDAR_OPTION_COM:
		{
			api_set_prog_option(&p_data->array[2]);
			api_start();
			break;
		}
#endif
		default:
		{
			break;
		}
	}
	return;
}

static bool b_soft_reset = false;

void* application_check_ram_data(bool is_valid)
{
    b_soft_reset = is_valid;
    app_ram_data_struct_t* noinit_ram_data = (app_ram_data_struct_t*) application_get_addr_ram();
    if (is_valid == true) {
        api_set_calendar_data(&noinit_ram_data->savedGlobalTimeInS, &noinit_ram_data->savedGlobalTimeShiftInS);
        
        if (APP_STATE == APP_BOILING_PROC) {
            heating_force_on(HEATER_MAX_PWM_DUTY_CICLE);
        }
        SPREADER_RTT_LOG(0, "check data true with app state - %d\r\n", APP_STATE);
    } else {
        memset((uint8_t *)&APP_FLAGS, 0x00, sizeof(app_flags_t));
        APP_STATE = APP_START;
        BOOLING_TEMP = 0;
        CURRENT_TIME_10MS = 0;
        MOBILE_STATE = MOB_BOILING;
        CURRENT_PERIOD_WORK_1C = TIMERS_HOURS(8);
        KEEP_WARM_TIME_DOWNCOUNTER_S = APP_KEEPWARM_MAX_TIME_S;
        BOOST_STATE = BOOST_FINISHED;
        KEEP_WARM_CTRL_TYPE_PREW = KEEP_WARM_CTRL_REG;
        KEEP_WARM_CTRL_TYPE = KEEP_WARM_CTRL_REG;
        SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"check data false\r\n"RTT_CTRL_RESET);
    }
    return application_get_addr_ram();
}
	
void* application_save_ram_data(void)
{
	app_ram_data_struct_t* noinit_ram_data = (app_ram_data_struct_t*) application_get_addr_ram();
	
	uint32_t time;
	int32_t shift;
	calendar_get_utc_time(&time, &shift);
	noinit_ram_data->savedGlobalTimeInS = time;
	noinit_ram_data->savedGlobalTimeShiftInS = shift;
    
    return application_get_addr_ram();
}

void *application_get_adr_data(void)
{
	app_pof_info.b_block_en = APP_FLAGS.b_keyb_block_en;
	app_pof_info.b_ble_en = APP_FLAGS.b_ble_en;
	app_pof_info.work_time = heating_get_work_val();
	app_pof_info.rell_on_cnt = heating_get_rell_on_cnt();
	app_pof_info.user_on_cnt = app_user_on_cnt;
	app_pof_info.curr_time_night = CURRENT_PERIOD_WORK_1C;
	app_pof_info.cycle_time_night = color_time.cycle_time_10ms/200;	
	app_pof_info.period_time_night = IN_TIMERS_HOURS(color_time.period_work_1c);
	app_pof_info.b_night_on = APP_FLAGS.b_night_on;
	app_pof_info.b_sound_en = APP_FLAGS.b_sound_en;
	app_pof_info.b_notify_old_water_en = notActive_getNotificationState();
	app_pof_info.old_water_time = notActive_getPeriod();
	app_pof_info.b_ind_calendar_synchron_en = APP_FLAGS.b_ind_calendar_synchron_en;
	app_pof_info.on_mass_cnt = on_mass_cnt;
	app_pof_info.reserve = 0;
	return &app_pof_info;
}
void *application_get_adr_data_pre(void)
{
	app_pof_info_pre.b_block_en = APP_FLAGS.b_keyb_block_en;
	app_pof_info_pre.work_time = heating_get_work_val();
	app_pof_info_pre.rell_on_cnt = heating_get_rell_on_cnt();
	app_pof_info_pre.user_on_cnt = app_user_on_cnt;
	app_pof_info_pre.curr_time_night = CURRENT_PERIOD_WORK_1C;
	app_pof_info_pre.cycle_time_night = color_time.cycle_time_10ms/200;	
	app_pof_info_pre.period_time_night = IN_TIMERS_HOURS(color_time.period_work_1c);
	app_pof_info_pre.b_night_on = APP_FLAGS.b_night_on;
	app_pof_info_pre.b_sound_en = APP_FLAGS.b_sound_en;
	app_pof_info_pre.b_notify_old_water_en = notActive_getNotificationState();
	app_pof_info_pre.old_water_time = notActive_getPeriod();
	app_pof_info_pre.b_ind_calendar_synchron_en = APP_FLAGS.b_ind_calendar_synchron_en;
	return &app_pof_info_pre;
}

/********************************************************************************
 *
 ********************************************************************************/
int tmp = 0;
void application_init( void )
{
#ifdef APP_CHECK_BLE_SWITCH
	//по умолчанию bluetooth отключен (для RK-G200S-E, RK-G200S-A), поэтому выставляем флаг
	//значение флага перезаписывается pof_manager далее в функции инициализации, исключая первый запуск
    APP_FLAGS.b_ble_en = true;
#endif
    
    uint32_t err_code = NRF_SUCCESS;
    
    err_code = calendar_set_one_sec_callback(calendar_one_sec_handle); //установка callback часов
    APP_ERROR_CHECK(err_code);
    
    err_code = evcal_set_callback(evcal_calendar_task); //установка callback при срабатывании расписания
    APP_ERROR_CHECK(err_code);
    
    if (!b_soft_reset) {
        APP_FLAGS.b_sound_en = 1; //разрешаем звуковые сигналы
        APP_FLAGS.b_ind_calendar_synchron_en = 1; //разрешаем отображать синхронизацию с календарем
    }
    
    //задаем адрес от куда считывать данные о клавиатуре
    err_code = keyb_services_set_address(app_keyb_data);
    APP_ERROR_CHECK(err_code);
    
    err_code = timer_create(TIMER_APP_SIMPLE_TIMEOUT, 0, (callback_t)app_simple_timeout_timer_handler);
    APP_ERROR_CHECK(err_code);
    app_timeout_timers_restart(APP_START_TIMEOUT_S);
    err_code = timer_start(TIMER_APP_SIMPLE_TIMEOUT);
    APP_ERROR_CHECK(err_code);
    err_code = timer_create(TIMER_COMMON_SEC, TIMERS_SECOND(1), (callback_t)app_sec_timer_handler);
    APP_ERROR_CHECK(err_code);
    err_code = timer_start(TIMER_COMMON_SEC);
    APP_ERROR_CHECK(err_code);
    err_code = timer_create(TIMER_COMMON_10MS, TIMERS_MILLISECOND(10), (callback_t)app_common_10ms_timeout_handler);
    APP_ERROR_CHECK(err_code);
    err_code = timer_reset(TIMER_COMMON_10MS);
    APP_ERROR_CHECK(err_code);
    err_code = timer_start(TIMER_COMMON_10MS);
    APP_ERROR_CHECK(err_code);
    
    //проверяем данные касаемые палитры
    uint16_t crc = 0;
    app_flash_data_t app_save_data __attribute__((aligned(sizeof(uint32_t))));
    err_code = r4s_app_flash_read(APP_MEM_PAGE_PALLET, 0, (uint8_t *)app_save_data.color_config, sizeof(app_save_data));
    APP_ERROR_CHECK(err_code);
    //считаем CRC
    crc = crc16_compute((uint8_t *)app_save_data.color_config, (sizeof(color_config_t) + sizeof(cl_gradient_t))*APP_COLOR_PALLET_NUM_MAX, NULL);
    if (crc == app_save_data.crc16) {
        //проверяем CRC с записанной
        //восстанавливаем сохраненные данные
        memcpy(color_option, app_save_data.color_config, (sizeof(color_config_t)*APP_COLOR_PALLET_NUM_MAX));
        memcpy(pwm_etalon_table, app_save_data.color_table, (sizeof(cl_gradient_t)*APP_COLOR_PALLET_NUM_MAX));
    }
    
#ifdef APP_CUSTOM_COLOR_RGB_ON
    if (q_color_check_version(&pwm_etalon_table[0]) != NRF_SUCCESS || q_color_check_version(&pwm_etalon_table[1]) != NRF_SUCCESS) {
        //если есть несовпадения по любому цвету в любой палитре - устанавливает палитры по умолчанию
        api_default_palette();
    }
#endif
    
    err_code = notActive_init();
    APP_ERROR_CHECK(err_code);
    
    uint8_t b_pof_have_data = 0;
    notActive_setNotificationState(0);
    
    if (!b_soft_reset) {
    
    //восстановление сохраненных конфигураций
    if (!state_pre_fl) {
            APP_ERROR_CHECK(pof_manager_get_state(&b_pof_have_data));
            
            if (b_pof_have_data && !b_soft_reset) {
                //если есть данные, которые надо восстановить
                APP_ERROR_CHECK(pof_manager_copy_data()); 	//чтение из ПЗУ сохраненных параметров
                //восстанавливаем сохраненные данные
#ifdef APP_CHECK_BLOCK_SWITCH
                APP_FLAGS.b_keyb_block_en = app_pof_info.b_block_en;
#else
                APP_FLAGS.b_keyb_block_en = 0;
#endif
                
                APP_FLAGS.b_ble_en = app_pof_info.b_ble_en;
                
#ifdef APP_CHECK_BLE_SWITCH
                if (APP_FLAGS.b_ble_en == false) r4s_slave_adv_restart();
#else
                APP_FLAGS.b_ble_en = false;
#endif
                
                APP_FLAGS.b_night_on = app_pof_info.b_night_on;
                heating_load_work_time(app_pof_info.work_time);
                heating_load_rell_on_cnt(app_pof_info.rell_on_cnt);
                app_user_on_cnt = app_pof_info.user_on_cnt;
                APP_FLAGS.b_sound_en = (app_pof_info.b_sound_en)?(1):(0);
                notActive_setNotificationState(app_pof_info.b_notify_old_water_en);
                APP_FLAGS.b_ind_calendar_synchron_en = app_pof_info.b_ind_calendar_synchron_en;
                add_temp_ind = 0;
                
                if (app_pof_info.on_mass_cnt <= MASS_FW_UPDATE_ON_DIS_COUNT) {
                    on_mass_cnt = app_pof_info.on_mass_cnt;
                } else {
                    on_mass_cnt = MASS_FW_UPDATE_ON_DIS_COUNT;
                }
                if (app_pof_info.curr_time_night <= TIMERS_HOURS(24)) {
                    CURRENT_PERIOD_WORK_1C = app_pof_info.curr_time_night;
                }
                if (app_pof_info.period_time_night <= 24) {
                    color_time.period_work_1c = TIMERS_HOURS(app_pof_info.period_time_night);
                }
                if (app_pof_info.cycle_time_night*200 <= TIMERS_MINUTE(3*2)) {
                    color_time.cycle_time_10ms = app_pof_info.cycle_time_night*200;
                }
            }
            //инициализируем режим "живая вода"
            if (app_pof_info.old_water_time == 0) {
                app_pof_info.old_water_time = NOT_ACTIVE_DEFAULT_PERIOD;
            }
            APP_ERROR_CHECK(notActive_create(app_pof_info.old_water_time, NULL));
        } else {
            //восстанавливаем сохраненные данные из v2.xx
#ifdef APP_CHECK_BLOCK_SWITCH
            APP_FLAGS.b_keyb_block_en = app_pof_info_pre.b_block_en;
#else
            APP_FLAGS.b_keyb_block_en = 0;
#endif
            APP_FLAGS.b_night_on = app_pof_info_pre.b_night_on;
            heating_load_work_time(app_pof_info_pre.work_time);
            heating_load_rell_on_cnt(app_pof_info_pre.rell_on_cnt);
            app_user_on_cnt = app_pof_info_pre.user_on_cnt;

            APP_FLAGS.b_sound_en = (app_pof_info_pre.b_sound_en)?(1):(0);
            notActive_setNotificationState(app_pof_info_pre.b_notify_old_water_en);
            APP_FLAGS.b_ind_calendar_synchron_en = app_pof_info_pre.b_ind_calendar_synchron_en;
            add_temp_ind = 0;
            if (app_pof_info_pre.curr_time_night <= TIMERS_HOURS(24)) {
                CURRENT_PERIOD_WORK_1C = app_pof_info_pre.curr_time_night;
            }
            if (app_pof_info_pre.period_time_night <= 24) {
                color_time.period_work_1c = TIMERS_HOURS(app_pof_info_pre.period_time_night);
            }
            if (app_pof_info_pre.cycle_time_night*200 <= TIMERS_MINUTE(3*2)) {
                color_time.cycle_time_10ms = app_pof_info_pre.cycle_time_night*200;
            }
            //инициализируем режим "живая вода"
            if (app_pof_info_pre.old_water_time == 0) {
                app_pof_info_pre.old_water_time = NOT_ACTIVE_DEFAULT_PERIOD;
            }
            APP_ERROR_CHECK(notActive_create(app_pof_info_pre.old_water_time, NULL));
        }
        //восстановление сохраненных параметров
        err_code = param_get_data();
        if (err_code == NRF_ERROR_INVALID_DATA) {
            app_restore_default_temperature_shift();
        } else {
            APP_ERROR_CHECK(err_code);
        }
    }
    SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"APP_FLAGS: calendar - %d, night - %d, session - %d\r\n"RTT_CTRL_RESET, APP_FLAGS.b_is_calendar_synchron, APP_FLAGS.b_night_on, APP_FLAGS.b_session_is_opened);
	return;
}

/********************************************************************************
 *
 ********************************************************************************/
/**@brief 	Функция выполняет работу при выходе из соответствующего состояния
 *
 * @param	none
 *
 * @return 	none
 */
void application_init_prew_state(app_state_t app_new_state)
{
    if (app_prew_state == app_new_state) return;

	switch( app_prew_state )
	{
		case APP_START:
		{
			break;
		}
		case APP_STAND_BY:
		{
			break;
		}
		case APP_BOILING_PROC:
		{
#if defined (OLD_SENSOR_AND_ALGORITHM)			
			temp_clear_begin_boiling();	//сброс начальных значений кипения
#elif defined (WT2_SENSOR_AND_NEW_ALGORITHM)
			temp_set_standby();
#else
		#error "NO SENSOR AND ALGORITHM DEFINED"
#endif
			break;
		}
		case APP_CONFIG_WARM:
		{
			break;
		}
		case APP_DISCO:
		{
			memset( &app_disco_color, 0, sizeof(color_disco_t) );
			break;
		}
		case APP_PAIRING:
		{
			app_advertising_unset_paring_flag();
			break;
		}
        case APP_ERROR:
		default:
		{
			break;
		}
	}

	return;
}

/**@brief 	Функция выполняет работу при входе в новое состояние
 *
 * @param	none
 *
 * @return 	none
 */
void application_init_new_state( app_state_t app_new_state )
{

	if( app_prew_state == app_new_state )return;

	//если были переходы между состояниями
	//очищаем данные о клавиатуре
	app_last_btn.btn_num = KEYB_BUTTON_COUNT; //присваиваем несуществующий номер кнопки
	APP_FLAGS.b_waiting_unpress_btn = 1; //ожидаем отпускания всех кнопок
	app_last_btn.time_push_ms = 0; //время нажатия равен 0
	app_ind_state = IND_IDLE; //переводим состояние индикации в IDLE
    
//    SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"app_new_state = %d\n"RTT_CTRL_RESET, app_new_state);	

	switch( app_new_state )
	{
		case APP_START:
		{
			break;
		}
		case APP_TEST:
		{
			//подаем 3 коротких сигнала
			APP_ERROR_CHECK(buz_reset_beeps());
			APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
			APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
			APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
			app_blink_time_ms = 0;
			APP_FLAGS.b_test_mode_on = 0;
			app_timeout_timers_restart(APP_CONFIG_TIMEOUT_S);
#ifdef CONTINENT_USA
			app_switch_mass_timeout = TIMERS_SECOND(MASS_FW_UPDATE_ENTER_WINDOW_S);
#else
			app_switch_mass_timeout = TIMERS_SECOND(APP_SWITCH_MASS_TIMEOUT_S);
#endif
			break;
		}
		case APP_TEST_EXIT:
		{
			app_timeout_timers_restart(APP_START_TIMEOUT_S/2);
			break;
		}
		case APP_MASS_FW_UPDATE:
		{            
			app_timeout_timers_stop(); //очистка таймера 
			SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"-->APP_MASS_FW_UPDATE\n"RTT_CTRL_RESET);
			
			//включаем bluetooth; после MASS_UPDATE и подачи питания bluetooth перейдёт в своё сохранённое состояние
			r4s_slave_adv_restart();	
			
			APP_ERROR_CHECK(timer_create(TIMER_MASS_FW_UPDATE, TIMERS_HOUR(MASS_FW_UPDATE_TIMEOUT_H), (callback_t)mass_hw_update_timer_handler));
			APP_ERROR_CHECK(timer_start(TIMER_MASS_FW_UPDATE));

			app_ind_state = IND_IDLE;
			
      break;
		}
		case APP_STAND_BY:
		{
            SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"[APPLICATION]: --> APP_STAND_BY\r\n"RTT_CTRL_RESET);
			//сброс настроек цветовой палитры
			#ifdef APP_CUSTOM_COLOR_RGB_ON
				q_color_state_reset();
			#endif
			//очищаем все режимы
			APP_FLAGS.b_keep_warm_en = 0;
			if(CURRENT_PERIOD_WORK_1C<color_time.period_work_1c || APP_FLAGS.b_night_on){ // 
				APP_STATE = APP_NIGHTLIGHT;
				MOBILE_STATE = MOB_NIGHT_LIGHT; //настройка для перехода в режим ночника
			}
			break;
		}
		case APP_BOILING_PROC:
		{
            SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"[APPLICATION]: --> APP_BOILING_PROC\r\n"RTT_CTRL_RESET);
			//сброс настроек цветовой палитры
			#ifdef APP_CUSTOM_COLOR_RGB_ON
				q_color_state_reset();
			#endif
			app_show_boiling_temp = false;
			APP_FLAGS.b_boiling_complete = 0;
			APP_FLAGS.b_boiling_prev = 0;
			boiling_temp_upcount_flag = true;
			boiling_ind_temp = temp_get_val();
//			boiling_min_time_downcounter_s = APP_BOILING_MIN_TIME_S;
			boilig_complete_ind_time_downcounter_s = APP_BOILING_COMPLETE_IND_TIME_S;
			
#if defined (OLD_SENSOR_AND_ALGORITHM)
			temp_set_begin_boiling();	//сохранение начальных значений кипения
			clear_small_grad();
			clear_decline_grad();
#elif defined (WT2_SENSOR_AND_NEW_ALGORITHM)
			temp_set_boiling();
#else
	#error "NO SENSOR AND ALGORITHM DEFINED"
#endif
            app_timeout_timers_restart(TIMERS_MINUTES(MAX_BOILING_TIME_M));

			break;
		}
		case APP_CONFIG_WARM:
		{
	    SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"[APPLICATION]: --> CONFIG_WARM\r\n"RTT_CTRL_RESET);

			app_timeout_timers_restart(APP_CONFIG_TIMEOUT_S);
			APP_FLAGS.b_keep_warm_en = 1; //переход в режим кипячения активирован
			MOBILE_STATE = MOB_WARM; //режим для отображения на телефоне
			if( (APP_FLAGS.b_sound_en == 1) &&
				(temp_get_val() > BOOLING_TEMP) ){
				uint32_t err_code = buz_reset_beeps();
				APP_ERROR_CHECK(err_code);
				err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
				APP_ERROR_CHECK(err_code);
				err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
				APP_ERROR_CHECK(err_code);
				err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
				APP_ERROR_CHECK(err_code);
			}
			break;
		}
		case APP_WARM_PROC:
		{
			//сброс настроек цветовой палитры
			#ifdef APP_CUSTOM_COLOR_RGB_ON
				q_color_state_reset();
			#endif

			MOBILE_STATE = MOB_WARM; 								//режим для отображения на телефоне
			APP_FLAGS.b_keep_wrm_boost_cmplt = 0;						//флаг зашершения выхода на заданную температуру
			APP_FLAGS.b_keep_wrm_boost_cmplt_prew = 0;					//предъидущее значение флага зашершения выхода на заданную температуру(используется для подачи звукового сигнала)
			KEEP_WARM_TIME_DOWNCOUNTER_S = APP_KEEPWARM_MAX_TIME_S;		//время до окончания режима поддеражания
			KEEP_WARM_CTRL_TYPE = keep_warm_get_ctrl_type( temp_get_val(), BOOLING_TEMP );
			KEEP_WARM_CTRL_TYPE_PREW = KEEP_WARM_CTRL_TYPE;
			boost_proc_init();
			heating_force_off();
			break;
		}
		case APP_KEEPWARM_PROC:
		{
			//сброс настроек цветовой палитры
			#ifdef APP_CUSTOM_COLOR_RGB_ON
				q_color_state_reset();
			#endif

			APP_FLAGS.b_keep_wrm_boost_cmplt = 0;						//флаг завершения выхода на заданную температуру
			APP_FLAGS.b_keep_wrm_boost_cmplt_prew = 0;					//предыдущее значение флага завершения выхода на заданную температуру(используется для подачи звукового сигнала)
			KEEP_WARM_TIME_DOWNCOUNTER_S = APP_KEEPWARM_MAX_TIME_S;		//время до окончания режима поддержания
			KEEP_WARM_CTRL_TYPE = keep_warm_get_ctrl_type(  temp_get_val(), BOOLING_TEMP );
			KEEP_WARM_CTRL_TYPE_PREW = KEEP_WARM_CTRL_TYPE;
			boost_proc_init();
			heating_force_off();
			break;
		}
		case APP_PAIRING:
		{
			app_advertising_set_paring_flag();
			
			app_timeout_timers_restart(APP_PAIRING_TIMEOUT_S);
			break;
		}
		case APP_FW_UPDATE:
		{
	    SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"[APPLICATION]: --> FW_UPDATE\r\n"RTT_CTRL_RESET);

			app_timeout_timers_restart(APP_FW_UPDATE_TIMEOUT_S);
			break;
		}
		case APP_NIGHTLIGHT:
		{
            SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"[APPLICATION]: --> APP_NIGHTLIGHT\r\n"RTT_CTRL_RESET);
			//сброс настроек цветовой палитры
			#ifdef APP_CUSTOM_COLOR_RGB_ON
				q_color_state_reset();
			#endif
			CURRENT_TIME_10MS = 0;
			break;
		}
		case APP_DISCO:
		{
            SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"[APPLICATION]: --> APP_DISCO\r\n"RTT_CTRL_RESET);
            app_disco_dec_time =0;
            break;
		}
        case APP_ERROR:
        {
            SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"[APPLICATION]: --> APP_ERROR\r\n"RTT_CTRL_RESET);
            app_blink_time_ms = 0;
            if (app_get_error_sensor()) {
                app_ind_state = IND_IDLE;
            } else {
                app_ind_state = IND_ERROR;
            }
            break;
        }
		default:
		{
            SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"[APPLICATION]: --> default\r\n"RTT_CTRL_RESET);
			break;
		}
	}

	app_prew_state = app_new_state;
	app_notification_uart();
	
	return;
}

/********************************************************************************
 *
 ********************************************************************************/
void application_process( void )
{
	uint32_t err_code;

	//считываем данные с клавиатуры
	for(uint8_t i=0; i<KEYB_BUTTON_COUNT; ++i){
		err_code = keyb_read_data(i, &app_keyb_data[i]);
		APP_ERROR_CHECK(err_code);
	}
	//чтение дополнительных данных о клавиатуре
	for(uint8_t i=0; i<KEYB_BUTTON_COUNT; ++i){
		err_code = keyb_services_read_data(i, &app_keyb_serv_data[i]);
		APP_ERROR_CHECK(err_code);
	}

	if(app_notification_uart_flg)
	{
		app_notification_uart();
	}
	

	app_boiling_temp_update(); //обновляем значения температуры для индикации
	app_update_leds(); //обновляем состояния светодиодов

	if(APP_STATE != APP_START){
		//если значения не дефолтные и режим не START
		err_code = pof_manager_record_enable();
		APP_ERROR_CHECK(err_code);
	} else {
		err_code = pof_manager_record_disable();
		APP_ERROR_CHECK(err_code);
	}

	application_init_prew_state( APP_STATE );	//выполняет работу при изменении состояния state machine
	application_init_new_state( APP_STATE );	//выполняет работу при изменении состояния state machine

	switch(APP_STATE)
	{
		case APP_START:
		{
			//indication
			app_show_start();
			//RGB подсветка
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));

			//work
			heating_force_off();

			static bool flg_change_ble = false;
		
			if(flg_change_ble == false)
			{
				// если удерживаются кнопки при включении
				if(nrf_gpio_pin_read(PLUS_BTN_PIN)== 0 && nrf_gpio_pin_read(PWR_BTN_PIN)== 0 ){
					APP_CHANGE_BLE();
					flg_change_ble = true;
				}
					//если BLE требуется отключить (удерживалась кнопка 2 или предыдущее состояние из flash)
				if(APP_FLAGS.b_ble_en) r4s_slave_adv_disable();	
			}
			//indication
			app_show_start();

			//transition
			if( APP_FLAGS.b_simple_timeout ){
				APP_ERROR_CHECK(pof_manager_clear_memory());	//затираем данные для ускорения записи при пропадании питания	

				if( ( flg_change_ble == false ) && ( app_keyb_data[KEYB_PWR].state == KEYB_PRESSED ) && ( app_keyb_data[KEYB_PWR].pressed_time_ms >= (APP_START_TIMEOUT_S*1000*0.8) ) ){ 
						// переходим в режим TEST если кнопка удерживается при включении
					APP_STATE = APP_TEST;					
				} else {
					//переходим в режим ожидания
					++on_mass_cnt;
					APP_STATE = APP_STAND_BY;					
				}
			}
			break;
		}
		case APP_MASS_FW_UPDATE:
		{   
			on_mass_cnt = 0;
			app_show_mass_fw_update(&app_ind_state);

			if( APP_FLAGS.b_simple_timeout ){
				app_ind_state = IND_END_ERROR_MASS_FW_UPDATE;
			}			
			//work
			heating_force_off();
			
			break;
		}
		case APP_TEST:
		{
			//indication
			app_show_test(&app_ind_state);
			//RGB подсветка
			cl_led_name_t test_rgb = { .r = 0, .g = 0, .b = 0 };
			if(APP_FLAGS.b_test_mode_on == 0){
				switch((app_blink_time_ms*TIMERS_TICK_MS/APP_RGB_CHANGE_MS)%3)
				{
					//так как 3 светодиода, то меняем только для трех
					case 0: test_rgb.b = 255; break;
					case 1: test_rgb.g = 255; break;
					case 2: test_rgb.r = 255; break;
				}
			}
			else {
				
			#if defined (OLD_SENSOR_AND_ALGORITHM)
				if((temp_get_val() > 100)||(temp_get_val()<1)) test_rgb.r = 255;
				else if((temp_get_val() <= 100 && temp_get_val() > 15)) test_rgb.b = 255;
			#elif defined (WT2_SENSOR_AND_NEW_ALGORITHM) 
				if( (temp_get_val() < 1) ) test_rgb.r = 255;//||(temp_get_val()<1) ) ;//test_rgb.g = 255;
				else if((temp_get_val() <= 100 && temp_get_val() > 7)) test_rgb.b = 255;
			#else
				#error "NO SENSOR AND ALGORITHM DEFINED"
			#endif
			
			}
				
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)test_rgb.r - (double)test_rgb.r*quantization_color[RGB_TYPE][0]));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)test_rgb.g - (double)test_rgb.g*quantization_color[RGB_TYPE][1]));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)test_rgb.b - (double)test_rgb.b*quantization_color[RGB_TYPE][2]));

			//work
			if(app_blink_time_ms*TIMERS_TICK_MS < 3000){
				heating_force_on(HEATER_MAX_PWM_DUTY_CICLE);
			}else{
				heating_force_off();
			}

			if( APP_FLAGS.b_simple_timeout){
				//если прошел таймаут - выходим
				APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
				APP_STATE = APP_STAND_BY;	
				break;
			}
			APP_UNPRESS_ALL_BTN(); //проверка ожидания отпускания клавиши
			if(APP_FLAGS.b_waiting_unpress_btn == 1){ //если ожидаем отпускания клавиатуры
				break;
			}
			if( (app_keyb_data[KEYB_PWR].event_press == KEYB_EVENT_CAPTURED) && (app_keyb_data[KEYB_PLUS].state == KEYB_RELEASED) ){
				APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
			}
			if( (app_keyb_data[KEYB_PLUS].event_press == KEYB_EVENT_CAPTURED) && (app_keyb_data[KEYB_PWR].state == KEYB_RELEASED) ){
				APP_FLAGS.b_test_mode_on = 1;
				APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
			}
			if( (nrf_gpio_pin_read(PLUS_BTN_PIN) == 0) && (nrf_gpio_pin_read(PWR_BTN_PIN) == 0) ){
				APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
				heating_force_off();
				APP_STATE = APP_TEST_EXIT;
				break;
			}
			if( (app_switch_mass_timeout)  && (on_mass_cnt < MASS_FW_UPDATE_ON_DIS_COUNT) && (app_keyb_serv_data[KEYB_PWR].push_cnt == MASS_FW_UPDATE_PRESS_CNT_TO_ENTER) ){
                heating_force_off();
				APP_STATE = APP_MASS_FW_UPDATE; //переходим в режим MASS UPDATE
				break;
			}
			break;
		}
		case APP_TEST_EXIT:
		{
			app_show_standby(&app_ind_state);
			//RGB подсветка
			cl_led_name_t test_rgb = {0, 0, 0};
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)test_rgb.r - (double)test_rgb.r*quantization_color[RGB_TYPE][0]));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)test_rgb.g - (double)test_rgb.g*quantization_color[RGB_TYPE][1]));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)test_rgb.b - (double)test_rgb.b*quantization_color[RGB_TYPE][2]));
			//transition
			//условия проверки данных с клавиатуры
			APP_UNPRESS_ALL_BTN(); //проверка ожидания отпускания клавиши
			if(APP_FLAGS.b_waiting_unpress_btn == 1){ //если ожидаем отпускания клавиатуры
				break;
			}
			if(APP_FLAGS.b_simple_timeout){
				APP_STATE = APP_STAND_BY;
			}
			break;
		}
		case APP_STAND_BY:
		{
			//indication
			app_show_standby(&app_ind_state);
			//RGB подсветка
			
			if(app_ind_state != IND_KEYB_BLOCK)
			{
				cl_led_name_t rgb = {0, 0, 0};
				if (APP_FLAGS.b_ind_calendar_synchron_en && APP_FLAGS.b_is_calendar_synchron) {
					// индикация синхронизации с календарем если разрешена и синхронизирована
					cl_led_name_t rgb_max = {0, 0, 0};

					#ifdef APP_CUSTOM_COLOR_RGB_ON
						APP_ERROR_CHECK(q_color_pallet_get(&pwm_etalon_table[color_option[APP_COLOR_HEAT_IDX].idx], api_get_cur_temp(), &rgb_max, 1));
					#else
						APP_ERROR_CHECK(color_led_calc_value(&pwm_etalon_table[color_option[APP_COLOR_HEAT_IDX].idx], &rgb_max, api_get_cur_temp(), 1));
					#endif

					const uint8_t speed_rate = 1;
					memcpy(&rgb, &rgb_max, sizeof(cl_led_name_t));

					float gr_brightness = (float)pwm_etalon_table->etalon->brightness/MAX_BRIGHTNESS;
					float gr_time = (float)(abs((signed int)MAX_PERIOD_BRIGHTNESS/2 - (signed int)((app_blink_time_ms/speed_rate)%MAX_PERIOD_BRIGHTNESS)))/(MAX_PERIOD_BRIGHTNESS/2);
					
					rgb.r *= gr_brightness*gr_time;
					rgb.g *= gr_brightness*gr_time;
					rgb.b *= gr_brightness*gr_time;
				}
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)rgb.r - (double)rgb.r*quantization_color[RGB_TYPE][0]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)rgb.g - (double)rgb.g*quantization_color[RGB_TYPE][1]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)rgb.b - (double)rgb.b*quantization_color[RGB_TYPE][2]));
			}
			//work
			heating_force_off();

			//transition
			//условия проверки данных с клавиатуры
			APP_UNPRESS_ALL_BTN(); //проверка ожидания отпускания клавиши
			if(APP_FLAGS.b_waiting_unpress_btn == 1){ //если ожидаем отпускания клавиатуры
				break;
			}
			APP_CHECK_BLOCK(); //проверка выполнения условий на блок/разблок
			if(APP_FLAGS.b_keyb_block_en == 1){ //если клавиатура заблокирована
				if(	app_keyb_serv_data[KEYB_PWR].push_cnt > 0 ||
					app_keyb_serv_data[KEYB_PLUS].push_cnt > 0 ){
					/*обнуляем время для мигания*/
					app_blink_time_ms = 0;
					/*переводим индикацию в режим "блок/разблок"*/
					app_ind_state = IND_KEYB_BLOCK;
				}
				break;
			}
			//анализ клавиатуры
			APP_SOUND_CHANGE_CHEK(); //проверка на переключение звуковых сигналов
			if(app_keyb_data[KEYB_PWR].pressed_time_ms >= APP_PUSH_BTN_PARING_MS)
			{	//впервые заходим в режим и разрешена подача звукового сигнала
				if(APP_FLAGS.b_ble_en)
				{
					APP_FLAGS.b_ble_en = false;
					r4s_slave_adv_restart();
				}
				
				if(app_last_btn.time_push_ms == 0){
						err_code = buz_reset_beeps();
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						app_ind_state = IND_PARING; //переводим индикацию в режим "unparing"
						app_blink_time_ms = 0; //сбрасываем время для индикации
					}
				
/*				if(!APP_FLAGS.b_ble_en){
						//BLE включено
					if(app_last_btn.time_push_ms == 0){
						err_code = buz_reset_beeps();
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						app_ind_state = IND_PARING; //переводим индикацию в режим "unparing"
						app_blink_time_ms = 0; //сбрасываем время для индикации
					}
				}else{
							//BLE выключено
					if(app_last_btn.time_push_ms == 0){
						err_code = buz_reset_beeps();
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
					}
				}*/
				
				app_last_btn.btn_num = KEYB_PWR; //сохраняем номер последней нажатой кнопки
				app_last_btn.time_push_ms = app_keyb_data[KEYB_PWR].pressed_time_ms; //записываем время последней нажатой кнопки
			}
			if(app_keyb_data[KEYB_PWR].pressed_time_ms >= APP_PUSH_BTN_UNPARING_MS)
			{
				APP_BEEP_UNPARING_SINGLE(); //подаем длинный сигнал на анпэйринг
				APP_FLAGS.b_unpairing = 1; //выставляем флаг unparing
				APP_FLAGS.b_waiting_unpress_btn = 1; //ожидаем отпускания всех кнопок
				app_last_btn.time_push_ms = 0; //очищаем время зажатия клавиши
				app_last_btn.btn_num = KEYB_BUTTON_COUNT; //очищаем номер последней кнопки
				app_ind_state = IND_UNPARING; //переводим индикацию в режим "unparing"
				app_blink_time_ms = 0; //сбрасываем время для индикации
			}
			if(app_keyb_data[KEYB_PWR].event_release == KEYB_EVENT_CAPTURED)
			{//отжали кнопку пэйринга/анпэйринга/переход_между_режимами
				//анализируем время нажатия на клавиатуру
					if(app_last_btn.time_push_ms >= APP_PUSH_BTN_PARING_MS){
						//нет необходимости очищать значение кнопки
						//так как при переходе в другое состояние - это происходит автоматом
						if(!APP_FLAGS.b_ble_en) 
							APP_STATE = APP_PAIRING; //переходим в режим пэйринга если BLE включено
					}
			}
			//счетчик нажатий на кнопку больше нуля
			if(	app_keyb_data[KEYB_PWR].state == KEYB_RELEASED &&
				app_keyb_data[KEYB_PLUS].state == KEYB_RELEASED &&
				app_keyb_serv_data[KEYB_PWR].b_clear_when_event == 0 &&
				app_keyb_serv_data[KEYB_PLUS].b_clear_when_event == 0){
				//если кнопка отпущена
				if(app_keyb_serv_data[KEYB_PWR].push_cnt == 1){
					if(app_get_error_sensor() == true)	break;//обрыв датчика
					APP_BEEP_SINGLE();
					BOOLING_TEMP = 0;
					MOBILE_STATE = MOB_BOILING; //режим кипячения для отображения на телефоне
					APP_STATE = APP_BOILING_PROC; //переходим в режим кипячения
					if(app_user_on_cnt < UINT32_MAX) ++app_user_on_cnt;
				}
				if(app_keyb_serv_data[KEYB_PLUS].push_cnt == 1){
					if(app_get_error_sensor() == true) break;
					continent_clear_flg_temp();
					APP_BEEP_SINGLE();
					BOOLING_TEMP = TEMP_WARM_LED_1; //выставляем индекс температуры в 1(40°С)
					APP_STATE = APP_CONFIG_WARM; //переходим в режим настройки подогрева
				}
			}
			break;
		}
		case APP_NIGHTLIGHT:
		{
			//indication
			app_show_nightlight(&app_ind_state);
			
			//RGB подсветка
			cl_led_name_t pwm_led = {.r = 0, .g = 0, .b = 0};
			
			if(color_option[APP_COLOR_NIGHT_IDX].activ){
				uint8_t proc;
				if(CURRENT_TIME_10MS<=color_time.cycle_time_10ms/2) 
                    proc = ((float)CURRENT_TIME_10MS * 100.0) / ((float)color_time.cycle_time_10ms/2);
				else 
                    proc = ((float)(color_time.cycle_time_10ms-CURRENT_TIME_10MS) * 100.0) / ((float)color_time.cycle_time_10ms/2);
				#ifdef APP_CUSTOM_COLOR_RGB_ON
					APP_ERROR_CHECK(q_color_pallet_get(&pwm_etalon_table[color_option[APP_COLOR_NIGHT_IDX].idx], proc, &pwm_led, (color_time.cycle_time_10ms / NIGHTLIGHT_MIN_TIME_MS)));
				#else
				APP_ERROR_CHECK(color_led_calc_value(&pwm_etalon_table[color_option[APP_COLOR_NIGHT_IDX].idx], &pwm_led, proc, 1));
				#endif
			}
			
			pwm_led.r *= (float)pwm_etalon_table[color_option[APP_COLOR_NIGHT_IDX].idx].etalon[0].brightness/255;
			pwm_led.g *= (float)pwm_etalon_table[color_option[APP_COLOR_NIGHT_IDX].idx].etalon[0].brightness/255;
			pwm_led.b *= (float)pwm_etalon_table[color_option[APP_COLOR_NIGHT_IDX].idx].etalon[0].brightness/255;
			
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)pwm_led.r - (double)pwm_led.r*quantization_color[RGB_TYPE][0]));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)pwm_led.g - (double)pwm_led.g*quantization_color[RGB_TYPE][1]));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)pwm_led.b - (double)pwm_led.b*quantization_color[RGB_TYPE][2]));

			//work
			heating_force_off();

			//transition
			//условия проверки данных с клавиатуры
			APP_UNPRESS_ALL_BTN(); //проверка ожидания отпускания клавиши
			if(APP_FLAGS.b_waiting_unpress_btn == 1){ //если ожидаем отпускания клавиатуры
				break;
			}
			APP_CHECK_BLOCK(); //проверка выполнения условий на блок/разблок
			if(APP_FLAGS.b_keyb_block_en == 1){ //если клавиатура заблокирована
				if(	app_keyb_serv_data[KEYB_PWR].push_cnt > 0 ||
					app_keyb_serv_data[KEYB_PLUS].push_cnt > 0 ){
					/*обнуляем время для мигания*/
					app_blink_time_ms = 0;
					/*переводим индикацию в режим "блок/разблок"*/
					app_ind_state = IND_KEYB_BLOCK;
				}
				break;
			}
			//анализ клавитуры
			APP_SOUND_CHANGE_CHEK(); //проверка на переключение звуковых сигналов
			//счетчик нажатий на кнопку больше нуля
			if(	app_keyb_data[KEYB_PWR].state == KEYB_RELEASED &&
				app_keyb_data[KEYB_PLUS].state == KEYB_RELEASED &&
				app_keyb_serv_data[KEYB_PWR].b_clear_when_event == 0 &&
				app_keyb_serv_data[KEYB_PLUS].b_clear_when_event == 0){
				//если кнопка отпущенна
				if(app_keyb_serv_data[KEYB_PWR].push_cnt == 1){
					if(app_get_error_sensor() == true)	break;//обрыав датчика
					APP_BEEP_SINGLE();
					BOOLING_TEMP = 0;
					MOBILE_STATE = MOB_BOILING; //режим кипячения для отображения на телефоне
					APP_STATE = APP_BOILING_PROC; //переходим в режим кипячения
					if(app_user_on_cnt < UINT32_MAX) ++app_user_on_cnt;
				}
				if(app_keyb_serv_data[KEYB_PLUS].push_cnt == 1){
					if(app_get_error_sensor() == true)	break;//обрыв датчика
					continent_clear_flg_temp();
					APP_BEEP_SINGLE();
					BOOLING_TEMP = TEMP_WARM_LED_1; //выставляем индекс температуры в 1(40°С)
					APP_STATE = APP_CONFIG_WARM; //переходим в режим настройки подогрева
				}
			}
				// пэйринг
			if(app_keyb_data[KEYB_PWR].pressed_time_ms >= APP_PUSH_BTN_PARING_MS)
			{
				if(APP_FLAGS.b_ble_en)
				{
					APP_FLAGS.b_ble_en = false;
					r4s_slave_adv_restart();
				}
				
				if(app_last_btn.time_push_ms == 0){
						err_code = buz_reset_beeps();
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						app_ind_state = IND_PARING; //переводим индикацию в режим "unparing"
						app_blink_time_ms = 0; //сбрасываем время для индикации
					}				
				
/*				if(!APP_FLAGS.b_ble_en){
						//BLE включено
					//впервые заходим в режим и разрешена подача звукового сигнала
					if(app_last_btn.time_push_ms == 0){
						err_code = buz_reset_beeps();
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						app_ind_state = IND_PARING; //переводим индикацию в режим "unparing"
						app_blink_time_ms = 0; //сбрасываем время для индикации
					}
				}else{
							//BLE выключено
					if(app_last_btn.time_push_ms == 0){
						err_code = buz_reset_beeps();
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
					}
				}*/

				app_last_btn.btn_num = KEYB_PWR; //сохраняем номер последней нажатой кнопки
				app_last_btn.time_push_ms = app_keyb_data[KEYB_PWR].pressed_time_ms; //записываем время последней нажатой кнопки
			}
			if(app_keyb_data[KEYB_PWR].pressed_time_ms >= APP_PUSH_BTN_UNPARING_MS)
			{
				APP_BEEP_UNPARING_SINGLE(); //подаем длинный сигнал на анпэйринг
				APP_FLAGS.b_unpairing = 1; //выставляем флаг unparing
				APP_FLAGS.b_waiting_unpress_btn = 1; //ожидаем отпускания всех кнопок
				app_last_btn.time_push_ms = 0; //очищаем время зажатия клавиши
				app_last_btn.btn_num = KEYB_BUTTON_COUNT; //очищаем номер последней кнопки
				app_ind_state = IND_UNPARING; //переводим индикацию в режим "unparing"
				app_blink_time_ms = 0; //сбрасываем время для индикации
				api_stop_nightlight();
				APP_STATE = APP_STAND_BY;
			}
			if(app_keyb_data[KEYB_PWR].event_release == KEYB_EVENT_CAPTURED)
			{//отжали кнопку пэйринга/анпэйринга/переход_между_режимами
				//анализируем время нажатия на клавиатуру
				if(app_last_btn.time_push_ms >= APP_PUSH_BTN_PARING_MS){
					//нет необходимости очищать значение кнопки
					//так как при переходе в другое состояние - это происходит автоматом
					if(!APP_FLAGS.b_ble_en) 
						APP_STATE = APP_PAIRING; //переходим в режим пэйринга
				}
			}
			if(!APP_FLAGS.b_night_on){
				APP_STATE = APP_STAND_BY;
			}
			break;
		}
		case APP_DISCO:
		{
			//indication
			app_show_disco(&app_ind_state);

			if(app_ind_state != IND_KEYB_BLOCK)
			{
				//RGB подсветка
				if(!app_disco_dec_time){
					if(app_disco_time_max) app_fibonachchi_value(&(app_disco_color.brightness)); 
//					app_fibonachchi_value(&(app_disco_color.led.r));
//					app_fibonachchi_value(&(app_disco_color.led.g));
//					app_fibonachchi_value(&(app_disco_color.led.b));
					app_disco_dec_time = app_disco_time_max;
				}
				cl_led_name_t pwm_led;
				pwm_led.r = (double)app_disco_color.led.r * ( (double)app_disco_color.brightness / 255 );
				pwm_led.g = (double)app_disco_color.led.g * ( (double)app_disco_color.brightness / 255 );
				pwm_led.b = (double)app_disco_color.led.b * ( (double)app_disco_color.brightness / 255 );

				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)pwm_led.r - (double)pwm_led.r*quantization_color[RGB_TYPE][0]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)pwm_led.g - (double)pwm_led.g*quantization_color[RGB_TYPE][1]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)pwm_led.b - (double)pwm_led.b*quantization_color[RGB_TYPE][2]));
			}
			
			//work
			heating_force_off();

			//transition
			//условия проверки данных с клавиатуры
			APP_UNPRESS_ALL_BTN(); //проверка ожидания отпускания клавиши
			if(APP_FLAGS.b_waiting_unpress_btn == 1){ //если ожидаем отпускания клавиатуры
				break;
			}
			APP_CHECK_BLOCK(); //проверка выполнения условий на блок/разблок
			if(APP_FLAGS.b_keyb_block_en == 1){ //если клавиатура заблокирована
				if(	app_keyb_serv_data[KEYB_PWR].push_cnt > 0 ||
					app_keyb_serv_data[KEYB_PLUS].push_cnt > 0 ){
					/*обнуляем время для мигания*/
					app_blink_time_ms = 0;
					/*переводим индикацию в режим "блок/разблок"*/
					app_ind_state = IND_KEYB_BLOCK;
				}
				break;
			}
			//анализ клавитуры
			APP_SOUND_CHANGE_CHEK(); //проверка на переключение звуковых сигналов
			//счетчик нажатий на кнопку больше нуля
			if(	app_keyb_data[KEYB_PWR].state == KEYB_RELEASED &&
				app_keyb_data[KEYB_PLUS].state == KEYB_RELEASED &&
				app_keyb_serv_data[KEYB_PWR].b_clear_when_event == 0 &&
				app_keyb_serv_data[KEYB_PLUS].b_clear_when_event == 0){
				//если кнопка отпущенна
				if(app_keyb_serv_data[KEYB_PWR].push_cnt == 1){
					if(app_get_error_sensor() == true)	break;//обрыв датчика
					APP_BEEP_SINGLE();
					BOOLING_TEMP = 0;
					MOBILE_STATE = MOB_BOILING; //режим кипячения для отображения на телефоне
					APP_STATE = APP_BOILING_PROC; //переходим в режим кипячения
					if(app_user_on_cnt < UINT32_MAX) ++app_user_on_cnt;
				}
				if(app_keyb_serv_data[KEYB_PLUS].push_cnt == 1){
					if(app_get_error_sensor() == true)	break;//обрыв датчика
					continent_clear_flg_temp();
					APP_BEEP_SINGLE();
					BOOLING_TEMP = TEMP_WARM_LED_1; //выставляем индекс температуры в 1(40°С)
					APP_STATE = APP_CONFIG_WARM; //переходим в режим настройки подогрева
				}
			}
			if(APP_FLAGS.b_session_is_opened == 0){
				APP_STATE = APP_STAND_BY;
			}	
			break;
		}
		case APP_BOILING_PROC:
		{
			//indication
			app_show_boiling(&app_ind_state);
			
			if(app_ind_state != IND_KEYB_BLOCK)
			{
				//RGB подсветка
				cl_led_name_t pwm_led = {.r = 0, .g = 0, .b = 0};
				
				uint8_t idx = color_option[APP_COLOR_HEAT_IDX].idx;
                
				if (color_option[APP_COLOR_HEAT_IDX].activ) {
					#ifdef APP_CUSTOM_COLOR_RGB_ON
						APP_ERROR_CHECK(q_color_pallet_get(&pwm_etalon_table[idx], api_get_cur_temp(), &pwm_led, 3));
					#else
						APP_ERROR_CHECK(color_led_calc_value(&pwm_etalon_table[idx], &pwm_led, api_get_cur_temp(), 0));
					#endif
				}
				
				pwm_led.r *= (float)pwm_etalon_table[idx].etalon[0].brightness/255;
				pwm_led.g *= (float)pwm_etalon_table[idx].etalon[0].brightness/255;
				pwm_led.b *= (float)pwm_etalon_table[idx].etalon[0].brightness/255;
				
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)pwm_led.r - (double)pwm_led.r*quantization_color[RGB_TYPE][0]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)pwm_led.g - (double)pwm_led.g*quantization_color[RGB_TYPE][1]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)pwm_led.b - (double)pwm_led.b*quantization_color[RGB_TYPE][2]));
			}

			//work
			if(temp_is_water_boil() && ( 0 == boiling_min_time_downcounter_s )) //если температура медленно растет и кончилось время кипения
			{
				APP_FLAGS.b_boiling_complete = 1;
			}
			if( ( APP_FLAGS.b_boiling_complete == 1 )
				&& ( APP_FLAGS.b_boiling_prev == 0 ) )
			{
				app_show_boiling_temp = true;			//установим флаг показывать температуру кипения вместо реальной
				boilig_temp_update_upcounter_s = 0;		//установим счетчик обновления температуры в 0
				boiling_temp_update_flag = false;		//скинем флаг обновления температуры
				//звуковая индикация завершения кипечения
				if( APP_FLAGS.b_sound_en == 1 ){
					err_code = buz_reset_beeps();
					APP_ERROR_CHECK(err_code);
					#ifdef DEBUG
						#ifdef OLD_SENSOR_AND_ALGORITHM
							if(get_small_grad()) APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_SINGLE));
							else if(get_decline_grad()) {
								APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
								APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
							}
							else {
								APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
								APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
								APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
							}
						#else
							APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
							APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
							APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
						#endif 
					#else
						APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
						APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
						APP_ERROR_CHECK(buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI));
					#endif
				}
			}
			APP_FLAGS.b_boiling_prev = APP_FLAGS.b_boiling_complete;
            
            if (APP_FLAGS.b_simple_timeout == 1) {
                heating_force_off();
                APP_BEEP_SINGLE();
                APP_STATE = APP_ERROR;
                break;
            }

			if( APP_FLAGS.b_boiling_complete == 1 ){
				heating_force_off();
			}else{
				heating_force_on(HEATER_MAX_PWM_DUTY_CICLE);
			}

			//transition
			if( temp_is_empty_kettle() ){
				heating_force_off();
				APP_STATE = APP_EMPTY_KETTLE;
				break;
			}
			if( (1 == APP_FLAGS.b_boiling_complete)
				&& (0 == boilig_complete_ind_time_downcounter_s)){
				if( 1 == APP_FLAGS.b_keep_warm_en ){
					APP_STATE = APP_KEEPWARM_PROC;
				}else{
					APP_STATE = APP_STAND_BY;
				}
                timer_stop(TIMER_APP_SIMPLE_TIMEOUT);
			}
			//условия проверки данных с клавиатуры
			APP_UNPRESS_ALL_BTN(); //проверка ожидания отпускания клавиши
			if(APP_FLAGS.b_waiting_unpress_btn == 1){ //если ожидаем отпускания клавиатуры
				break;
			}
			APP_CHECK_BLOCK(); //проверка выполнения условий на блок/разблок
			if(APP_FLAGS.b_keyb_block_en == 1){ //если клавиатура заблокирована
				if(	app_keyb_serv_data[KEYB_PWR].push_cnt > 0 ||
					app_keyb_serv_data[KEYB_PLUS].push_cnt > 0 ){
					/*обнуляем время для мигания*/
					app_blink_time_ms = 0;
					/*переводим индикацию в режим "блок/разблок"*/
					app_ind_state = IND_KEYB_BLOCK;
				}
				break;
			}
			//анализ клавитуры
			//счетчик нажатий на кнопку больше нуля
			if(	app_keyb_data[KEYB_PWR].state == KEYB_RELEASED &&
				app_keyb_data[KEYB_PLUS].state == KEYB_RELEASED &&
				app_keyb_serv_data[KEYB_PWR].b_clear_when_event == 0 &&
				app_keyb_serv_data[KEYB_PLUS].b_clear_when_event == 0){
				//если кнопка отпущенна
				if(app_keyb_serv_data[KEYB_PLUS].push_cnt == 1){
					//изменяем режимы поддержания температуры
					continent_clear_flg_temp();
					APP_BEEP_SINGLE();
#ifdef CONTINENT_USA
					if(ROUND_TEMP(BOOLING_TEMP) >= ROUND_TEMP(TEMP_WARM_LED_4)){
						MOBILE_STATE = MOB_BOILING; //режим кипячения для мобильника
						APP_FLAGS.b_keep_warm_en = 0; //отключаем переход в режим подогрева
						BOOLING_TEMP = 0; //сбрасываем температуру, так как дошли до конца
					} else {
						if(BOOLING_TEMP == 0.) BOOLING_TEMP = TEMP_WARM_LED_1;
						else if(ROUND_TEMP(BOOLING_TEMP) >=ROUND_TEMP(35.) && ROUND_TEMP(BOOLING_TEMP) < ROUND_TEMP(TEMP_WARM_LED_1)) BOOLING_TEMP = TEMP_WARM_LED_1;
						else if(ROUND_TEMP(BOOLING_TEMP) >=ROUND_TEMP(TEMP_WARM_LED_1) && ROUND_TEMP(BOOLING_TEMP) < ROUND_TEMP(TEMP_WARM_LED_2)) BOOLING_TEMP = TEMP_WARM_LED_2;
						else if(ROUND_TEMP(BOOLING_TEMP) >=ROUND_TEMP(TEMP_WARM_LED_2) && ROUND_TEMP(BOOLING_TEMP) < ROUND_TEMP(TEMP_WARM_LED_3)) BOOLING_TEMP = TEMP_WARM_LED_3;
						else if(ROUND_TEMP(BOOLING_TEMP) >=ROUND_TEMP(TEMP_WARM_LED_3) && ROUND_TEMP(BOOLING_TEMP) < ROUND_TEMP(TEMP_WARM_LED_4)) BOOLING_TEMP = TEMP_WARM_LED_4;
						MOBILE_STATE = MOB_BOIL_WARM; //режим кипячения с подоревом для мобильника
						APP_FLAGS.b_keep_warm_en = 1; //переход в режим подогрева активирован
					}
#else
					if(BOOLING_TEMP >= TEMP_WARM_LED_4){
						MOBILE_STATE = MOB_BOILING; //режим кипячения для мобильника
						APP_FLAGS.b_keep_warm_en = 0; //отключаем переход в режим подогрева
						BOOLING_TEMP = 0; //сбрасываем температуру, так как дошли до конца
					} else {
						if(BOOLING_TEMP == 0) BOOLING_TEMP = TEMP_WARM_LED_1;
						else if(BOOLING_TEMP >=35 && BOOLING_TEMP < TEMP_WARM_LED_1) BOOLING_TEMP = TEMP_WARM_LED_1;
						else if(BOOLING_TEMP >=TEMP_WARM_LED_1 && BOOLING_TEMP < TEMP_WARM_LED_2) BOOLING_TEMP = TEMP_WARM_LED_2;
						else if(BOOLING_TEMP >=TEMP_WARM_LED_2 && BOOLING_TEMP < TEMP_WARM_LED_3) BOOLING_TEMP = TEMP_WARM_LED_3;
						else if(BOOLING_TEMP >=TEMP_WARM_LED_3 && BOOLING_TEMP < TEMP_WARM_LED_4) BOOLING_TEMP = TEMP_WARM_LED_4;
						MOBILE_STATE = MOB_BOIL_WARM; //режим кипячения с подоревом для мобильника
						APP_FLAGS.b_keep_warm_en = 1; //переход в режим подогрева активирован
					}
#endif
				}
				if(app_keyb_serv_data[KEYB_PWR].push_cnt == 1){
					APP_BEEP_SINGLE(); //подаем звуковой сигнал
					APP_STATE = APP_STAND_BY; //переход в режим ожидания
				}
			}
			break;
		}
		case APP_CONFIG_WARM:
		{
			//indication
			app_show_warm_cfg(&app_ind_state);
			if(app_ind_state != IND_KEYB_BLOCK)
			{
				//RGB подсветка
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			}
			//work
			heating_force_off();
			//transition
			if( APP_FLAGS.b_simple_timeout ){
				//сработал таймаут для перехода в режим ожидания
				APP_BEEP_SINGLE();
				APP_STATE = APP_STAND_BY; //переход в режим ожидания
				break;
			}
			//условия проверки данных с клавиатуры
			APP_UNPRESS_ALL_BTN(); //проверка ожидания отпускания клавиши
			if(APP_FLAGS.b_waiting_unpress_btn == 1){ //если ожидаем отпускания клавиатуры
				break;
			}
			APP_CHECK_BLOCK(); //проверка выполнения условий на блок/разблок
			if(APP_FLAGS.b_keyb_block_en == 1){ //если клавиатура заблокирована
				if(	app_keyb_serv_data[KEYB_PWR].push_cnt > 0 ||
					app_keyb_serv_data[KEYB_PLUS].push_cnt > 0 ){
					/*обнуляем время для мигания*/
					app_blink_time_ms = 0;
					/*переводим индикацию в режим "блок/разблок"*/
					app_ind_state = IND_KEYB_BLOCK;
				}
				break;
			}
			//анализ клавитуры
			//счетчик нажатий на кнопку больше нуля
			if(	app_keyb_data[KEYB_PWR].state == KEYB_RELEASED &&
				app_keyb_data[KEYB_PLUS].state == KEYB_RELEASED &&
				app_keyb_serv_data[KEYB_PWR].b_clear_when_event == 0 &&
				app_keyb_serv_data[KEYB_PLUS].b_clear_when_event == 0){
				//если кнопка отпущенна
				if(app_keyb_serv_data[KEYB_PLUS].push_cnt == 1){
					//изменяем режимы поддержания температуры
					continent_clear_flg_temp();
					APP_BEEP_SINGLE();
					app_timeout_timers_restart(APP_CONFIG_TIMEOUT_S); //сбрасываем настройки
#ifdef CONTINENT_USA
					if(ROUND_TEMP(BOOLING_TEMP) >= ROUND_TEMP(TEMP_WARM_LED_4))BOOLING_TEMP = TEMP_WARM_LED_1;
					else if(ROUND_TEMP(BOOLING_TEMP) >= ROUND_TEMP(35.) && ROUND_TEMP(BOOLING_TEMP) < ROUND_TEMP(TEMP_WARM_LED_1)) BOOLING_TEMP = TEMP_WARM_LED_1;
					else if(ROUND_TEMP(BOOLING_TEMP) >= ROUND_TEMP(TEMP_WARM_LED_1) && ROUND_TEMP(BOOLING_TEMP) < ROUND_TEMP(TEMP_WARM_LED_2)) BOOLING_TEMP = TEMP_WARM_LED_2;
					else if(ROUND_TEMP(BOOLING_TEMP) >= ROUND_TEMP(TEMP_WARM_LED_2) && ROUND_TEMP(BOOLING_TEMP) < ROUND_TEMP(TEMP_WARM_LED_3)) BOOLING_TEMP = TEMP_WARM_LED_3;
					else if(ROUND_TEMP(BOOLING_TEMP) >= ROUND_TEMP(TEMP_WARM_LED_3) && ROUND_TEMP(BOOLING_TEMP) < ROUND_TEMP(TEMP_WARM_LED_4)) BOOLING_TEMP = TEMP_WARM_LED_4;
#else
					if(BOOLING_TEMP >= TEMP_WARM_LED_4) BOOLING_TEMP = TEMP_WARM_LED_1;
					else if(BOOLING_TEMP >=35 && BOOLING_TEMP < TEMP_WARM_LED_1) BOOLING_TEMP = TEMP_WARM_LED_1;
					else if(BOOLING_TEMP >=TEMP_WARM_LED_1 && BOOLING_TEMP < TEMP_WARM_LED_2) BOOLING_TEMP = TEMP_WARM_LED_2;
					else if(BOOLING_TEMP >=TEMP_WARM_LED_2 && BOOLING_TEMP < TEMP_WARM_LED_3) BOOLING_TEMP = TEMP_WARM_LED_3;
					else if(BOOLING_TEMP >=TEMP_WARM_LED_3 && BOOLING_TEMP < TEMP_WARM_LED_4) BOOLING_TEMP = TEMP_WARM_LED_4;
#endif
					//звуковая индикация завершения подогрева
					if( (APP_FLAGS.b_sound_en == 1) &&
						(temp_get_val() > BOOLING_TEMP) ){
						err_code = buz_reset_beeps();
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
					}
				}
				if(app_keyb_serv_data[KEYB_PWR].push_cnt == 1){
					APP_BEEP_SINGLE(); //подаем звуковой сигнал
					if(app_user_on_cnt < UINT32_MAX) ++app_user_on_cnt;
					APP_STATE = APP_WARM_PROC; //переход в режим подогрева
				}
			}
			break;
		}
		case APP_WARM_PROC:
		{
			uint8_t buz_tmp = 0;
			//indication
			app_show_warm(&app_ind_state);
			
			if (app_ind_state != IND_KEYB_BLOCK) {
				//RGB подсветка
				cl_led_name_t pwm_led = {.r =0, .g = 0, .b = 0};
                
                uint8_t idx = color_option[APP_COLOR_HEAT_IDX].idx;
				if (color_option[APP_COLOR_HEAT_IDX].activ) {
					#ifdef APP_CUSTOM_COLOR_RGB_ON
						APP_ERROR_CHECK(q_color_pallet_get(&pwm_etalon_table[idx], api_get_cur_temp(), &pwm_led, 3));
					#else 
						APP_ERROR_CHECK(color_led_calc_value(&pwm_etalon_table[idx], &pwm_led, api_get_cur_temp(), 0));
					#endif 
				}
				pwm_led.r *= (float)pwm_etalon_table[idx].etalon[0].brightness/255;
				pwm_led.g *= (float)pwm_etalon_table[idx].etalon[0].brightness/255;
				pwm_led.b *= (float)pwm_etalon_table[idx].etalon[0].brightness/255;
				
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)pwm_led.r - (double)pwm_led.r*quantization_color[RGB_TYPE][0]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)pwm_led.g - (double)pwm_led.g*quantization_color[RGB_TYPE][1]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)pwm_led.b - (double)pwm_led.b*quantization_color[RGB_TYPE][2]));
			}
            
			//work
			if (KEEP_WARM_CTRL_TYPE_PREW != KEEP_WARM_CTRL_TYPE) {
				//если изменился алгоритм поддержания разгон/регулятор
				//инициализируем новый алгоритм
				if (KEEP_WARM_CTRL_TYPE == KEEP_WARM_CTRL_BOOST) {
					boost_proc_init();
				} else {
					heating_force_off();
				}
				KEEP_WARM_CTRL_TYPE_PREW = KEEP_WARM_CTRL_TYPE;
			}
			if (KEEP_WARM_CTRL_TYPE == KEEP_WARM_CTRL_BOOST) {
				//работа алгоритм разгона
				BOOST_STATE = boost_proc(temp_get_float_val(), (float)BOOLING_TEMP);
				if (BOOST_STATE == BOOST_FINISHED) {
					KEEP_WARM_CTRL_TYPE = KEEP_WARM_CTRL_REG;
					buz_tmp = 1;
					app_timeout_boost_s = 30;
				}
			} else {
				if (!app_timeout_boost_s) {
					//работа алгоритм регулятор
					KEEP_WARM_CTRL_TYPE = keep_warm_get_ctrl_type(temp_get_val(), BOOLING_TEMP);
					if (BOOLING_TEMP < 80) { //если заданная температура меньше чем 80 градусов
						heating_process_on(simple_reg(temp_get_val(), BOOLING_TEMP, 3));
					} else {
						heating_process_on(simple_reg(temp_get_val(), BOOLING_TEMP, 5));
					}
				}
			}
			if (fabs((double)(BOOLING_TEMP - temp_get_val())) < APP_KEEPWARM_TEMP_DIFFERENCE_BOOST_IS_OVER_C) {
				//установим флаг выхода на заданную температуру
				APP_FLAGS.b_keep_wrm_boost_cmplt = 1;
			}
			if ((0 == APP_FLAGS.b_keep_wrm_boost_cmplt_prew)
				&& (1 == APP_FLAGS.b_keep_wrm_boost_cmplt)) {
                APP_FLAGS.b_keep_wrm_boost_cmplt_prew = APP_FLAGS.b_keep_wrm_boost_cmplt;
			}

			//controll

			//transition
			if ((temp_is_empty_kettle() == true)
				|| ((APP_FLAGS.b_keep_wrm_boost_cmplt == 1) && (temp_get_val() > (BOOLING_TEMP + APP_OVERHEAT_NO_KETTLE_C)))) {
				//чайник без воды
				heating_force_off();	//если выходим из режима обязательно выключить нагреватель
				APP_STATE = APP_EMPTY_KETTLE;
			}
			if (buz_tmp || temp_get_val() >= BOOLING_TEMP) {
				//звуковая индикация завершения подогрева
				if (APP_FLAGS.b_sound_en == 1) {
					err_code = buz_reset_beeps();
					APP_ERROR_CHECK(err_code);
					err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
					APP_ERROR_CHECK(err_code);
					err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
					APP_ERROR_CHECK(err_code);
					err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
					APP_ERROR_CHECK(err_code);
				}
				APP_STATE = APP_KEEPWARM_PROC;
			}
			//условия проверки данных с клавиатуры
			APP_UNPRESS_ALL_BTN(); //проверка ожидания отпускания клавиши
			if (APP_FLAGS.b_waiting_unpress_btn == 1) { //если ожидаем отпускания клавиатуры
				break;
			}
			APP_CHECK_BLOCK(); //проверка выполнения условий на блок/разблок
			if (APP_FLAGS.b_keyb_block_en == 1) { //если клавиатура заблокирована
				if (app_keyb_serv_data[KEYB_PWR].push_cnt > 0
                    || app_keyb_serv_data[KEYB_PLUS].push_cnt > 0) {
					/*обнуляем время для мигания*/
					app_blink_time_ms = 0;
					/*переводим индикацию в режим "блок/разблок"*/
					app_ind_state = IND_KEYB_BLOCK;
				}
				break;
			}
			//анализ клавитуры
			//счетчик нажатий на кнопку больше нуля
			if (app_keyb_data[KEYB_PWR].state == KEYB_RELEASED
                && app_keyb_data[KEYB_PLUS].state == KEYB_RELEASED
                && app_keyb_serv_data[KEYB_PWR].b_clear_when_event == 0
                && app_keyb_serv_data[KEYB_PLUS].b_clear_when_event == 0) {
				//если кнопка отпущенна
				if (app_keyb_serv_data[KEYB_PWR].push_cnt == 1) {
					heating_force_off();	//если выходим из режима обязательно выключить нагреватель
					APP_BEEP_SINGLE();
					APP_STATE = APP_STAND_BY;
				}
			}
			break;
		}
		case APP_KEEPWARM_PROC:
		{
			//indication
			app_show_keepwarm(&app_ind_state);

			//RGB подсветка
			if (app_ind_state != IND_KEYB_BLOCK) {
				cl_led_name_t pwm_led = {.r =0, .g = 0, .b = 0};
                
                uint8_t idx = color_option[APP_COLOR_HEAT_IDX].idx;
				if (color_option[APP_COLOR_HEAT_IDX].activ) {
					#ifdef APP_CUSTOM_COLOR_RGB_ON
						APP_ERROR_CHECK(q_color_pallet_get(&pwm_etalon_table[idx], api_get_cur_temp(), &pwm_led, 3));
					#else 
						APP_ERROR_CHECK(color_led_calc_value(&pwm_etalon_table[idx], &pwm_led, api_get_cur_temp(), 0));
					#endif 
				}
				pwm_led.r *= (float)pwm_etalon_table[idx].etalon[0].brightness/255;
				pwm_led.g *= (float)pwm_etalon_table[idx].etalon[0].brightness/255;
				pwm_led.b *= (float)pwm_etalon_table[idx].etalon[0].brightness/255;
				
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, (double)pwm_led.r - (double)pwm_led.r*quantization_color[RGB_TYPE][0]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, (double)pwm_led.g - (double)pwm_led.g*quantization_color[RGB_TYPE][1]));
				APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, (double)pwm_led.b - (double)pwm_led.b*quantization_color[RGB_TYPE][2]));
			}
            
			//work
			if (KEEP_WARM_CTRL_TYPE_PREW != KEEP_WARM_CTRL_TYPE) {
				//если изменился алгоритм поддержания разгон/регулятор
				//инициализируем новый алгоритм
				if (KEEP_WARM_CTRL_TYPE == KEEP_WARM_CTRL_BOOST) {
					boost_proc_init();
				} else {
					heating_force_off();
				}
				KEEP_WARM_CTRL_TYPE_PREW = KEEP_WARM_CTRL_TYPE;
			}
			if (KEEP_WARM_CTRL_TYPE == KEEP_WARM_CTRL_BOOST) {
				//работа алгоритм разгона
				BOOST_STATE = boost_proc(temp_get_float_val(), (float)BOOLING_TEMP);
				if (BOOST_STATE == BOOST_FINISHED) {
					KEEP_WARM_CTRL_TYPE = KEEP_WARM_CTRL_REG;
					app_timeout_boost_s = 30;			
				}
			} else {
				if (!app_timeout_boost_s) {
					//работа алгоритм регулятор
					KEEP_WARM_CTRL_TYPE = keep_warm_get_ctrl_type(temp_get_val(), BOOLING_TEMP);
					if (BOOLING_TEMP < 80) { //если заданная температура меньше чем 80 градусов
						heating_process_on(simple_reg(temp_get_val() , BOOLING_TEMP, 3));
					} else {
						heating_process_on(simple_reg(temp_get_val() , BOOLING_TEMP, 4));
					}
				}
			}
			if (fabs((double)(BOOLING_TEMP - temp_get_val())) < APP_KEEPWARM_TEMP_DIFFERENCE_BOOST_IS_OVER_C) {
				//установим флаг выхода на заданную температуру
				APP_FLAGS.b_keep_wrm_boost_cmplt = 1;
			}
			if ((0 == APP_FLAGS.b_keep_wrm_boost_cmplt_prew)
				&& (1 == APP_FLAGS.b_keep_wrm_boost_cmplt)) {
				APP_FLAGS.b_keep_wrm_boost_cmplt_prew = APP_FLAGS.b_keep_wrm_boost_cmplt;
			}

			//controll

			//transition
			if ((temp_is_empty_kettle() == true)
				|| ((APP_FLAGS.b_keep_wrm_boost_cmplt == 1) && (temp_get_val() > (BOOLING_TEMP + APP_OVERHEAT_NO_KETTLE_C)))) {
				//чайник без воды
				heating_force_off();	//если выходим из режима обязательно выключить нагреватель
				APP_STATE = APP_EMPTY_KETTLE;
			}
			if (0 == KEEP_WARM_TIME_DOWNCOUNTER_S) {
				//закончено время подогрева
				APP_STATE = APP_STAND_BY;
				APP_BEEP_SINGLE();
			}
			//условия проверки данных с клавиатуры
			APP_UNPRESS_ALL_BTN(); //проверка ожидания отпускания клавиши
			if (APP_FLAGS.b_waiting_unpress_btn == 1) { //если ожидаем отпускания клавиатуры
				break;
			}
			APP_CHECK_BLOCK(); //проверка выполнения условий на блок/разблок
			if (APP_FLAGS.b_keyb_block_en == 1) { //если клавиатура заблокирована
				if (app_keyb_serv_data[KEYB_PWR].push_cnt > 0
                    || app_keyb_serv_data[KEYB_PLUS].push_cnt > 0) {
					/*обнуляем время для мигания*/
					app_blink_time_ms = 0;
					/*переводим индикацию в режим "блок/разблок"*/
					app_ind_state = IND_KEYB_BLOCK;
				}
				break;
			}
			//анализ клавитуры
			//счетчик нажатий на кнопку больше нуля
			if (app_keyb_data[KEYB_PWR].state == KEYB_RELEASED
                && app_keyb_data[KEYB_PLUS].state == KEYB_RELEASED
                && app_keyb_serv_data[KEYB_PWR].b_clear_when_event == 0
                && app_keyb_serv_data[KEYB_PLUS].b_clear_when_event == 0) {
				//если кнопка отпущенна
				if (app_keyb_serv_data[KEYB_PWR].push_cnt == 1) {
					heating_force_off();	//если выходим из режима обязательно выключить нагреватель
					APP_BEEP_SINGLE();
					APP_STATE = APP_STAND_BY;
				}
			}
			break;
		}
		case APP_PAIRING:
		{
			//indication
			app_show_pairing();
			//RGB подсветка
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));

			//work
			heating_force_off();

			//waiting for R4S reset pairing_flag
			if((APP_FLAGS.b_simple_timeout == 1) || (APP_FLAGS.b_session_is_opened == 1)){
				//если причиной входа было подключение
					err_code = buz_reset_beeps();
					APP_ERROR_CHECK(err_code);
					err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
					APP_ERROR_CHECK(err_code);
					err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
					APP_ERROR_CHECK(err_code);
					if(APP_FLAGS.b_session_is_opened == 1){ 
						err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
						APP_ERROR_CHECK(err_code);
					}
				APP_STATE = APP_STAND_BY;
			}
			
			break;
		}
		case APP_FW_UPDATE:
		{
			//indication
			app_show_fw_update();
			//RGB подсветка
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));

			//work
			heating_force_off();

			if(APP_FLAGS.b_simple_timeout == 1){
				//если разрешена подача звукового сигнала
				if(APP_FLAGS.b_sound_en == 1){ 
					//и причиной входа было подключение
					err_code = buz_reset_beeps();
					APP_ERROR_CHECK(err_code);
					err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
					APP_ERROR_CHECK(err_code);
					err_code = buz_add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BUZ_BEEP_MULTI);
					APP_ERROR_CHECK(err_code);
				}
				APP_STATE = APP_STAND_BY;
			}
			break;
		}
		case APP_ERROR:
		{
            //indication
			app_show_error(&app_ind_state);
			//RGB подсветка
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_RED, 0));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_GREEN, 0));
			APP_ERROR_CHECK(led_pwm_set_value(LED_PWM_BLUE, 0));
			
			//TODO::
			//заполнить режим ошибки
			heating_force_off();
			break;
		}
		default:
		{
			APP_STATE = APP_STAND_BY;
			//TODO::
			//и/или выполнить иное действие
			break;
		}
	}
	return;
}
/********************************************************************************
 *
 ********************************************************************************/

/********************************************************************************
 *
 ********************************************************************************/
/**
 * 	описание в application_api.h
*/
uint16_t api_get_version(void)
{
	return FIRMWARE_VER;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_get_state(void)
{
	switch(APP_STATE)
	{
		case APP_START:
		case APP_EMPTY_KETTLE:
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return APP_API_INACCESSIBLE_STATE;
		}
		case APP_FW_UPDATE:
		{
			return APP_API_FW_UPDATE_STATE;
		}
		case APP_STAND_BY:
		case APP_CONFIG_WARM:
		{
			return APP_API_STAND_BY_STATE;
		}
		case APP_WARM_PROC:
		case APP_BOILING_PROC:
		case APP_KEEPWARM_PROC:
		case APP_NIGHTLIGHT:
		case APP_DISCO:
		{
			return APP_API_WORK_STATE;
		}
		case APP_PAIRING:
		{
			return APP_API_PAIRING_STATE;
		}
		case APP_ERROR:
		{
			return APP_API_ERROR_STATE;
		}
		case APP_MASS_FW_UPDATE:
		{
			return APP_API_MASS_FW_UPDATE;
		}
	}
	return APP_API_ERROR_STATE;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_get_temperature_shift(void)
{
    if(param.temperature_shift > (TEMPERATURE_ZERO_SHIFT_VALUE + MAX_TEMPERATURE_CORRECTION_SHIFT) ||
    param.temperature_shift < (TEMPERATURE_ZERO_SHIFT_VALUE - MAX_TEMPERATURE_CORRECTION_SHIFT))
    {
        param.temperature_shift = TEMPERATURE_ZERO_SHIFT_VALUE;
    }    
	return (uint8_t)param.temperature_shift;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_get_error(void)
{
	//if(temp_get_val() >= TEMP_EMPTY_KETTLE_TEMP_C) return APP_API_BREAK_SENSOR;
	if (is_error_sensor()) {
        return APP_API_BREAK_SENSOR;
    }
    if (APP_STATE == APP_ERROR && app_ind_state == IND_IDLE) {
        return APP_API_OVERHEAT_ERROR;
    }
    if (APP_STATE == APP_ERROR && app_ind_state == IND_ERROR) {
        return APP_API_BOIL_TIMEOUT_ERROR;
    }
	return APP_API_NO_ERROR;
}
/**
 * 	описание в application_api.h
*/
bool api_is_unpairing(void)
{
	return APP_FLAGS.b_unpairing;
}
/**
 * 	описание в application_api.h
*/
void api_clr_unpairing(void)
{
    //here we restore some default parameters at unpairing
	APP_FLAGS.b_unpairing = 0;
    app_restore_default_temperature_shift();
	APP_FLAGS.b_night_on = false;
    BOOLING_TEMP = TEMP_WARM_LED_1;//исправление бага 263
    CURRENT_PERIOD_WORK_1C = TIMERS_HOURS(8);
    CURRENT_TIME_10MS = 0;
	color_nightlight_time_t color = { 300*TIMERS_TICK_MS*2, TIMERS_HOURS(8)};
	memcpy(&color_time, &color, sizeof(color_nightlight_time_t));
	APP_FLAGS.b_sound_en = 1;
	APP_FLAGS.b_keyb_block_en = 0;
	APP_FLAGS.b_ind_calendar_synchron_en = 1;
	app_pof_info.old_water_time = NOT_ACTIVE_DEFAULT_PERIOD;
	notActive_setNotificationState(0);
    MOBILE_STATE = MOB_BOILING;
	return;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_go_to_stand_by(void)
{
		switch(APP_STATE)
	{
		case APP_START: //в режиме старт
		case APP_PAIRING: //в режиме пэйринга
		case APP_EMPTY_KETTLE: //в режиме "пустой чайник"
		case APP_ERROR: //в режиме "ошибка"
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return 0;
		}
		case APP_FW_UPDATE: //в режиме обновления ошибки
		case APP_MASS_FW_UPDATE:
		{
			return 0;
		}
		case APP_STAND_BY: //в режиме ожидания
		{
			return 1;
		}
		case APP_CONFIG_WARM:
		{
			app_timeout_timers_stop(); //очистка таймера 
			APP_STATE = APP_STAND_BY; //перейти в режим ожидания
			return 1;
		}
		case APP_WARM_PROC:
		case APP_BOILING_PROC:
		case APP_KEEPWARM_PROC:
		case APP_NIGHTLIGHT:
		case APP_DISCO:
		{
			heating_force_off();	//если выходим из режима обязательно выключить нагреватель
			APP_STATE = APP_STAND_BY; //перейти в режим ожидания
			return 1;
		}
	}
	return 0;
}
/**
 * 	описание в application_api.h
*/
void api_set_open_session_flag(void)
{
//	SPREADER_RTT_LOG(0, "SET CCONNECTION FLAG\n");

	APP_FLAGS.b_session_is_opened = 1;
	return;
}
/**
 * 	описание в application_api.h
*/
void api_clear_connection_flag(void)
{
//	SPREADER_RTT_LOG(0, "CLEAR CONNECTION FLAG\n");

	APP_FLAGS.b_session_is_opened = 0;
	return;
}
/**
 * 	описание в application_api.h
*/
void api_set_connection_flag(void)
{
	return;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_enter_fw_update_state(void)
{
	switch(APP_STATE)
	{
		case APP_START:
		case APP_EMPTY_KETTLE:
		case APP_PAIRING:
		case APP_ERROR:
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return 0;
		}
		case APP_STAND_BY:
		case APP_CONFIG_WARM:
		case APP_BOILING_PROC:
		case APP_WARM_PROC:
		case APP_KEEPWARM_PROC:
		case APP_FW_UPDATE:
		case APP_NIGHTLIGHT:
		case APP_DISCO:
		{
			//api_clean_mass_fw_update();
			//pof_write_data_in_flash();
			APP_STATE = APP_FW_UPDATE;
			return 1;
		}
		case APP_MASS_FW_UPDATE:
		{
			app_timeout_timers_restart(APP_FW_UPDATE_TIMEOUT_S);
//			SPREADER_RTT_LOG(0, "START TIMER MASS UPDATE\n");
			app_ind_state = IND_MASS_FW_UPDATE;
			return 1;
		}
	}
	return 0;
}
/**
 * 	описание в application_api.h
*/
void api_fw_update_proc(void)
{
	if( APP_STATE == APP_FW_UPDATE || APP_STATE == APP_MASS_FW_UPDATE)
	{
		app_timeout_timers_restart(APP_FW_UPDATE_TIMEOUT_S);
	}
}
/**
 * 	описание в application_api.h
*/
uint8_t api_start(void)
{
	switch(APP_STATE)
	{
		case APP_START: //в режиме старт
		case APP_PAIRING: //в режиме пэйринга
		case APP_EMPTY_KETTLE: //в режиме "пустой чайник"
		case APP_ERROR: //в режиме "ошибка"
		case APP_FW_UPDATE: //в режиме обновления ошибки
		case APP_MASS_FW_UPDATE:
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return 0;
		}
		case APP_STAND_BY: //в режиме ожидания
		{
			switch(MOBILE_STATE)
			{
				case MOB_BOILING:
					if(is_error_sensor()==true) return 1;
					if(app_user_on_cnt < UINT32_MAX) ++app_user_on_cnt;
					APP_STATE = APP_BOILING_PROC; //переходим в режим кипячения
					return 1;
				case MOB_WARM:
					if(BOOLING_TEMP == 0){
						return 0;
					}
					if(is_error_sensor()==true) return 1;
					if(app_user_on_cnt < UINT32_MAX) ++app_user_on_cnt;
					APP_STATE = APP_WARM_PROC; //переходим в режим нагрева
					return 1;
				case MOB_BOIL_WARM:
					if(BOOLING_TEMP == 0){
						return 0;
					}
					if(is_error_sensor()==true) return 1;
					if(app_user_on_cnt < UINT32_MAX) ++app_user_on_cnt;
					APP_FLAGS.b_keep_warm_en = 1; //переход в режим нагрева активирован
					APP_STATE = APP_BOILING_PROC; //переходим в режим кипячение с нагревом
					return 1;
				case MOB_NIGHT_LIGHT:
					APP_STATE = APP_NIGHTLIGHT; //переходим в режим ночника
					CURRENT_PERIOD_WORK_1C = 0;
					APP_FLAGS.b_night_on = true;
					return 1;
				case MOB_DISCO:
					APP_STATE = APP_DISCO; //переходим в режим диско
					return 1;
			}
		}
		case APP_CONFIG_WARM:
		{ //перейти в режим подогрева
			if(is_error_sensor()==false) APP_STATE = APP_WARM_PROC;
			return 1;
		}
		case APP_NIGHTLIGHT:
		case APP_WARM_PROC:
		case APP_BOILING_PROC:
		case APP_KEEPWARM_PROC:
		case APP_DISCO:
		{ //уже стартонули делаем что-то
			return 1;
		}
	}
	return 0;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_stop(void)
{
//	api_stop_nightlight();	// остановка ночника даже если он в фоновом процессе

	switch(APP_STATE)
	{
		case APP_START: //в режиме старт
		case APP_PAIRING: //в режиме пэйринга
		case APP_EMPTY_KETTLE: //в режиме "пустой чайник"
		case APP_ERROR: //в режиме "ошибка"
		case APP_FW_UPDATE: //в режиме обновления ошибки
		case APP_MASS_FW_UPDATE:
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return 0;
		}
		case APP_STAND_BY: //в режиме ожидания
		{
			return 1;
		}
		case APP_CONFIG_WARM:
		{
			app_timeout_timers_stop(); //очистка таймера 
			APP_STATE = APP_STAND_BY; //перейти в режим ожидания
			return 1;
		}
		case APP_NIGHTLIGHT:
			api_stop_nightlight();
		case APP_WARM_PROC:
		case APP_BOILING_PROC:
		case APP_KEEPWARM_PROC:
		case APP_DISCO:
		{
			heating_force_off();	//если выходим из режима обязательно выключить нагреватель
			APP_STATE = APP_STAND_BY; //перейти в режим ожидания
			return 1;
		}
	}
	return 0;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_switch(void)
{
//	api_stop_nightlight();	// остановка ночника даже если он в фоновом процессе

	switch(APP_STATE)
	{
		case APP_START: //в режиме старт
		case APP_PAIRING: //в режиме пэйринга
		case APP_EMPTY_KETTLE: //в режиме "пустой чайник"
		case APP_ERROR: //в режиме "ошибка"
		case APP_FW_UPDATE: //в режиме обновления ошибки
		case APP_MASS_FW_UPDATE:
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return 0;
		}
		case APP_STAND_BY: //в режиме ожидания
		{
			switch(MOBILE_STATE)
			{
				case MOB_BOILING:
//					if(BOOLING_TEMP != 0){
//						return 0;
//					}
					if(app_user_on_cnt < UINT32_MAX) ++app_user_on_cnt;
					APP_STATE = APP_BOILING_PROC; //переходим в режим кипячения
					return 1;
				case MOB_WARM:
					if(BOOLING_TEMP == 0){
						return 0;
					}
					if(app_user_on_cnt < UINT32_MAX) ++app_user_on_cnt;
					APP_STATE = APP_WARM_PROC; //переходим в режим нагрева
					return 1;
				case MOB_BOIL_WARM:
					if(BOOLING_TEMP == 0){
						return 0;
					}
					if(app_user_on_cnt < UINT32_MAX) ++app_user_on_cnt;
					APP_FLAGS.b_keep_warm_en = 1; //переход в режим нагрева активирован
					APP_STATE = APP_BOILING_PROC; //переходим в режим кипячение с нагревом
					return 1;
				case MOB_NIGHT_LIGHT:
					APP_STATE = APP_NIGHTLIGHT; //переходим в режим ночника
					CURRENT_PERIOD_WORK_1C = 0;
					return 1;
				case MOB_DISCO:
					APP_STATE = APP_DISCO; //переходим в режим диско
					return 1;
			}
		}
		case APP_CONFIG_WARM:
		{
			app_timeout_timers_stop(); //очистка таймера 
			APP_STATE = APP_STAND_BY; //перейти в режим ожидания
			return 1;
		}
		case APP_NIGHTLIGHT:
			api_stop_nightlight();
		case APP_WARM_PROC:
		case APP_BOILING_PROC:
		case APP_KEEPWARM_PROC:
		case APP_DISCO:
		{
			heating_force_off();	//если выходим из режима обязательно выключить нагреватель
			APP_STATE = APP_STAND_BY; //перейти в режим ожидания
			return 1;
		}
	}
	return 0;
}
/**
 * 	описание в application_api.h
*/
#ifdef CONTINENT_USA
uint8_t api_set_boil_temp(uint16_t temp_boil)
#else
uint8_t api_set_boil_temp(uint8_t temp_boil)
#endif
{
	temp_boil = continent_set_temp(temp_boil);
	switch(APP_STATE)
	{
		case APP_START: //в режиме старт
		case APP_PAIRING: //в режиме пэйринга
		case APP_EMPTY_KETTLE: //в режиме "пустой чайник"
		case APP_ERROR: //в режиме "ошибка"
		case APP_FW_UPDATE: //в режиме обновления ошибки
		case APP_MASS_FW_UPDATE:
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return 0;
		}
		case APP_CONFIG_WARM:
		{
			if(temp_boil == 0) return 0;
			if(temp_boil == BOOLING_TEMP) return 1; //темп. выставлена
			app_timeout_timers_restart(APP_CONFIG_TIMEOUT_S); //сбрасываем настройки
			//break не нужен
		}
		case APP_STAND_BY: //в режиме ожидания
		case APP_NIGHTLIGHT:
		case APP_DISCO:
		{
			if( MOBILE_STATE == APP_WORK_PROG_BOIL
				&& (temp_boil == 0 || temp_boil == 100 ) )
			{
				BOOLING_TEMP = 0;
				return 1;
			}
			else if( temp_boil > APP_KEEPWARM_MAX_TEMP_C ||
				temp_boil < APP_KEEPWARM_MIN_TEMP_C){
				return 0;
			}
			BOOLING_TEMP = temp_boil;
			return 1;
		}
		case APP_BOILING_PROC:
		{
			if( (temp_boil > APP_KEEPWARM_MAX_TEMP_C ||
				temp_boil < APP_KEEPWARM_MIN_TEMP_C) &&
				(temp_boil != 0 || temp_boil != 100)){
				return 0;
			}
			BOOLING_TEMP = temp_boil;
			if(temp_boil == 0){
				MOBILE_STATE = MOB_BOILING; //выставляем режим кипячения
				APP_FLAGS.b_keep_warm_en = 0; //отключаем переход в режим подогрева
			}else{
				MOBILE_STATE = MOB_BOIL_WARM; //выставляем режим кипячения
				APP_FLAGS.b_keep_warm_en = 1; //включаем переход в режим подогрева
			}
			
			return 1;
		}
		case APP_WARM_PROC:
		case APP_KEEPWARM_PROC:
		{//нельзя настраивать температуру при работающем подогреве или ночнике
			return 0;
		}
	}
	return 0;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_set_temperature_shift(uint8_t temperature_shift)
{
    uint32_t err_code;

    if(temperature_shift > TEMPERATURE_ZERO_SHIFT_VALUE + MAX_TEMPERATURE_CORRECTION_SHIFT ||
       temperature_shift < TEMPERATURE_ZERO_SHIFT_VALUE - MAX_TEMPERATURE_CORRECTION_SHIFT) return 0;
    
	if(param.temperature_shift == temperature_shift) return 1;
		
	param.temperature_shift = temperature_shift;
	err_code = param_set_data();
	APP_ERROR_CHECK(err_code);
 
//    SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"PARAM_WRITE: temperature_shift = %d\r\n"RTT_CTRL_RESET, temperature_shift);
	return 1;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_set_disco_data(uint8_t r, uint8_t g, uint8_t b, uint8_t brs, uint16_t m_time)
{
	if( APP_STATE != APP_DISCO ) return ERSP_ERROR_INVALID_STATE;

	
	app_disco_dec_time = app_disco_time_max = m_time/10/(sizeof(fib_array)/sizeof(uint8_t));	// 10 ms
	
	app_disco_color.led.r = r;
	app_disco_color.led.b = b;
	app_disco_color.led.g = g;
	app_disco_color.brightness = brs;
	return ERSP_SUCCESS;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_set_nightlight_time(uint16_t cycle_time_s)
{
	if( (cycle_time_s < 30) || (cycle_time_s > 180) ) return ERSP_ERROR_INVALID_DATA;
	switch(APP_STATE)
	{
		case APP_START: //в режиме старт
		case APP_PAIRING: //в режиме пэйринга
		case APP_EMPTY_KETTLE: //в режиме "пустой чайник"
		case APP_ERROR: //в режиме "ошибка"
		case APP_FW_UPDATE: //в режиме обновления ошибки
		case APP_MASS_FW_UPDATE:
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return ERSP_ERROR_INVALID_STATE;
		}
		case APP_STAND_BY: //в режиме ожидания
		case APP_WARM_PROC:
		case APP_NIGHTLIGHT:
		case APP_DISCO:
		case APP_CONFIG_WARM:
		case APP_BOILING_PROC:
		case APP_KEEPWARM_PROC:
		{
			color_time.cycle_time_10ms = TIMERS_SECOND(cycle_time_s*2);
//				SPREADER_RTT_LOG(0,"%s[MAIN]  %sset cycle %d\n",	\
						RTT_CTRL_TEXT_BRIGHT_GREEN,	\
						RTT_CTRL_TEXT_BRIGHT_WHITE, (uint16_t)(color_time.cycle_time_10ms/2/100));

			CURRENT_TIME_10MS = 0;
			return ERSP_SUCCESS;
		}
	}
	return ERSP_ERROR_INTERNAL;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_set_period_night_time(uint16_t time)
{
    if (time > 24) {
        return ERSP_ERROR_INVALID_DATA;
    }
    CURRENT_PERIOD_WORK_1C = 0;
    color_time.period_work_1c = TIMERS_HOURS(time);
    return ERSP_SUCCESS;
}
/**
 * 	описание в application_api.h
*/
void api_get_pallet(void* data, uint8_t pallet_num)
{
	cl_gradient_t *p_data = (cl_gradient_t*) data;
	if( p_data == NULL ) return;
	memset(p_data, 0, sizeof(cl_gradient_t));
	if(pallet_num > 1) return;

	memcpy( p_data, &pwm_etalon_table[pallet_num], sizeof(cl_gradient_t));
	return;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_set_pallet(void* data, uint8_t pallet_num)
{
	cl_gradient_t const* p_data = (cl_gradient_t const* ) data;
	switch(APP_STATE)
	{
		case APP_START: //в режиме старт
		case APP_PAIRING: //в режиме пэйринга
		case APP_EMPTY_KETTLE: //в режиме "пустой чайник"
		case APP_ERROR: //в режиме "ошибка"
		case APP_FW_UPDATE: //в режиме обновления ошибки
		case APP_MASS_FW_UPDATE:
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return ERSP_ERROR_INVALID_STATE;
		}
		case APP_CONFIG_WARM:
		case APP_STAND_BY: //в режиме ожидания
		case APP_BOILING_PROC:
		case APP_WARM_PROC:
		case APP_KEEPWARM_PROC:
		case APP_NIGHTLIGHT:
		case APP_DISCO:
		{
			if( pallet_num >= APP_COLOR_PALLET_NUM_MAX ){
				return ERSP_ERROR_NOT_SUPPORTED;
			}
			if( (p_data->etalon[0].proc > p_data->etalon[1].proc) ||
				(p_data->etalon[1].proc > p_data->etalon[2].proc) ){
				return ERSP_ERROR_FORBIDDEN;
			}
			if( p_data->etalon[2].proc > 100 ){ //проверяем, если процент работы больше 100%
				return ERSP_ERROR_INVALID_DATA;
			}
			#ifdef APP_CUSTOM_COLOR_RGB_ON
				cl_gradient_t data;
				memcpy(&data, p_data, sizeof(cl_gradient_t));
				if(q_color_check_version(&data)!= NRF_SUCCESS){
					return ERSP_ERROR_FORBIDDEN;
				}else{
					memcpy(&pwm_etalon_table[pallet_num], &data, sizeof(cl_gradient_t));
				}
			#else
				memcpy(&pwm_etalon_table[pallet_num], p_data, sizeof(cl_gradient_t));
			#endif
			return ERSP_SUCCESS;
		}
	}
	return ERSP_ERROR_INTERNAL;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_set_block(uint8_t state)
{
	if(state > 1) return 0;
	switch(APP_STATE)
	{
		case APP_START: //в режиме старт
		case APP_PAIRING: //в режиме пэйринга
		case APP_EMPTY_KETTLE: //в режиме "пустой чайник"
		case APP_ERROR: //в режиме "ошибка"
		case APP_FW_UPDATE: //в режиме обновления ошибки
		case APP_MASS_FW_UPDATE:
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return 0;
		}
		case APP_CONFIG_WARM:
		case APP_STAND_BY: //в режиме ожидания
		case APP_BOILING_PROC:
		case APP_WARM_PROC:
		case APP_KEEPWARM_PROC:
		case APP_NIGHTLIGHT:
		case APP_DISCO:
		{
#ifdef APP_CHECK_BLOCK_SWITCH
			APP_FLAGS.b_keyb_block_en = state;
			return 1;
#endif
		}
	}
	return 0;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_set_sound(uint8_t state)
{
	if(state > 1) return 0;
	switch(APP_STATE)
	{
		case APP_START: //в режиме старт
		case APP_PAIRING: //в режиме пэйринга
		case APP_EMPTY_KETTLE: //в режиме "пустой чайник"
		case APP_ERROR: //в режиме "ошибка"
		case APP_FW_UPDATE: //в режиме обновления ошибки
		case APP_MASS_FW_UPDATE:
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return 0;
		}
		case APP_CONFIG_WARM:
		case APP_STAND_BY: //в режиме ожидания
		case APP_BOILING_PROC:
		case APP_WARM_PROC:
		case APP_KEEPWARM_PROC:
		case APP_NIGHTLIGHT:
		case APP_DISCO:
		{
			APP_FLAGS.b_sound_en = state;
			return 1;
		}
	}
	return 0;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_set_old_water(uint8_t state, uint16_t time)
{
	if(state > 1 || time == 0) return ERSP_ERROR_INVALID_DATA;
	switch(APP_STATE)
	{
		case APP_START: //в режиме старт
		case APP_PAIRING: //в режиме пэйринга
		case APP_EMPTY_KETTLE: //в режиме "пустой чайник"
		case APP_ERROR: //в режиме "ошибка"
		case APP_FW_UPDATE: //в режиме обновления ошибки
		case APP_MASS_FW_UPDATE:
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return ERSP_ERROR_INVALID_STATE;
		}
		case APP_CONFIG_WARM:
		case APP_STAND_BY: //в режиме ожидания
		case APP_BOILING_PROC:
		case APP_WARM_PROC:
		case APP_KEEPWARM_PROC:
		case APP_NIGHTLIGHT:
		case APP_DISCO:
		{
			notActive_setNotificationState(state);
			notActive_setPeriod( time );
			return ERSP_SUCCESS;
		}
	}
	return ERSP_ERROR_INVALID_STATE;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_set_prog(uint8_t prog_num)
{
	switch(APP_STATE)
	{
		case APP_START: //в режиме старт
		case APP_PAIRING: //в режиме пэйринга
		case APP_EMPTY_KETTLE: //в режиме "пустой чайник"
		case APP_ERROR: //в режиме "ошибка"
		case APP_FW_UPDATE: //в режиме обновления ошибки
		case APP_MASS_FW_UPDATE:
		case APP_TEST:
		case APP_TEST_EXIT:
		{
			return 0;
		}
		case APP_BOILING_PROC:
		{
			if( ((prog_num == APP_WORK_PROG_BOIL) && (MOBILE_STATE == MOB_BOILING)) ||
				((prog_num == APP_WORK_PROG_BOILWARM) && (MOBILE_STATE == MOB_BOIL_WARM))){
				return 1;
			} else {
				return 0;
			}
		}
		case APP_WARM_PROC:
		{
			if( (prog_num == APP_WORK_PROG_WARM) && (MOBILE_STATE == MOB_WARM) ){
				return 1;
			} else {
				return 0;
			}
		}
		case APP_KEEPWARM_PROC:
		{
			if( ((prog_num == APP_WORK_PROG_WARM) && (MOBILE_STATE == MOB_WARM)) ||
				((prog_num == APP_WORK_PROG_BOILWARM) && (MOBILE_STATE == MOB_BOIL_WARM))){
				return 1;
			} else {
				return 0;
			}
		}
		case APP_NIGHTLIGHT:
		{
			if( (prog_num == APP_WORK_PROG_NIGHTLIGHT) && (MOBILE_STATE == MOB_NIGHT_LIGHT) ){
				return 1;
			} else {
				return 0;
			}
		}
		case APP_DISCO:
		{
			if( (prog_num == APP_WORK_PROG_DISCO) && (MOBILE_STATE == MOB_DISCO) ){
				return 1;
			} else {
				return 0;
			}
		}
		case APP_CONFIG_WARM:
		case APP_STAND_BY:
		{
			switch(prog_num)
			{
				case APP_WORK_PROG_BOIL:
				{
					APP_STATE = APP_STAND_BY; //переходим в режим ожидания
					MOBILE_STATE = MOB_BOILING; //настройка для перехода в режим кипячение
					APP_FLAGS.b_keep_warm_en = 0; //отключаем переход в режим подогрева
					BOOLING_TEMP = 0; //сбрасываем температуру
					return 1;
				}
				case APP_WORK_PROG_WARM:
				{
					MOBILE_STATE = MOB_WARM; //настройка для перехода в режим подогрева
					APP_FLAGS.b_keep_warm_en = 1; //включаем переход в режим подогрева
					if(BOOLING_TEMP == 0){
						BOOLING_TEMP = TEMP_WARM_LED_1; //если температура не была выбрана
					}
					return 1;
				}
				case APP_WORK_PROG_BOILWARM:
				{
					APP_STATE = APP_STAND_BY; //переходим в режим ожидания
					MOBILE_STATE = MOB_BOIL_WARM; //настройка для перехода в режим кипячение с подогревом
					APP_FLAGS.b_keep_warm_en = 1; //включаем переход в режим подогрева
					if(BOOLING_TEMP == 0){
						BOOLING_TEMP = TEMP_WARM_LED_1; //если температура не была выбрана
					}
					return 1;
				}
				case APP_WORK_PROG_NIGHTLIGHT:
				{
					APP_STATE = APP_STAND_BY; //переходим в режим ожидания
					MOBILE_STATE = MOB_NIGHT_LIGHT; //настройка для перехода в режим ночника
					APP_FLAGS.b_keep_warm_en = 0; //отключаем переход в режим подогрева
					BOOLING_TEMP = 0; //сбрасываем температуру
					return 1;
				}
				case APP_WORK_PROG_DISCO:
				{
					APP_STATE = APP_STAND_BY; //переходим в режим ожидания
					MOBILE_STATE = MOB_DISCO; //настройка для перехода в режим ночника
					APP_FLAGS.b_keep_warm_en = 0; //отключаем переход в режим подогрева
					BOOLING_TEMP = 0; //сбрасываем температуру
					return 1;
				}
			}
			return 0;
		}
	}
	return 0;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_set_prog_option(const uint8_t* prog)
{
	exten_req_option_cmd_t* option = (exten_req_option_cmd_t*) prog;

	switch(APP_STATE)
	{
		case APP_START: //в режиме старт
		case APP_PAIRING: //в режиме пэйринга
		case APP_EMPTY_KETTLE: //в режиме "пустой чайник"
		case APP_ERROR: //в режиме "ошибка"
		case APP_FW_UPDATE: //в режиме обновления
		case APP_MASS_FW_UPDATE:
		case APP_TEST:
		case APP_TEST_EXIT:
		case APP_DISCO:
		case APP_BOILING_PROC:
		{
			return 0;
		}
		case APP_WARM_PROC:
		case APP_KEEPWARM_PROC:
		case APP_NIGHTLIGHT:
		case APP_CONFIG_WARM:
		case APP_STAND_BY:
		{
			if(option->mode1==0) return 0;														// если в первом параметре режим не задан
			if(option->mode1 == APP_WORK_PROG_NIGHTLIGHT_CALENDAR){								// первый параметр - режим "ночник"
				if(option->param1==0 || option->param1<1 || option->param1>24) return 0;		// неверные значения времени работы ночника 
				APP_STATE = APP_STAND_BY; 			//переходим в режим ожидания
				MOBILE_STATE = MOB_NIGHT_LIGHT; //настройка для перехода в режим ночника
				APP_FLAGS.b_keep_warm_en = 0; 		//отключаем переход в режим подогрева
				BOOLING_TEMP = 0; 					//сбрасываем температуру
				color_time.period_work_1c = TIMERS_HOURS(option->param1);	// инициализируем время (в секундах) работы ночника
				return 1;
			}
			if(option->mode1 == APP_WORK_PROG_BOIL_CALENDAR && option->mode2 == 0){				// первый параметр - режим "кипячение" второй параметр не задан
				APP_STATE = APP_STAND_BY; 		//переходим в режим ожидания
				MOBILE_STATE = MOB_BOILING; //настройка для перехода в режим кипячение
				APP_FLAGS.b_keep_warm_en = 0; 	//отключаем переход в режим подогрева
				BOOLING_TEMP = 0; 				//сбрасываем температуру
				return 1;
			}
			if(option->mode1 == APP_WORK_PROG_WARM_CALENDAR && option->mode2 == 0){				 // первый параметр - режим "нагрев" второй параметр не задан
#ifdef CONTINENT_USA
				if(continent_set_temp(option->param1) > APP_KEEPWARM_MAX_TEMP_C || continent_set_temp(option->param1) < APP_KEEPWARM_MIN_TEMP_C) return 0; // неверные значения температуры в режиме "нагрев"
#else
				if(continent_temp(option->param1) > APP_KEEPWARM_MAX_TEMP_C || continent_temp(option->param1) < APP_KEEPWARM_MIN_TEMP_C) return 0; // неверные значения температуры в режиме "нагрев"
#endif
				APP_STATE = APP_STAND_BY; 			//переходим в режим ожидания
				MOBILE_STATE = MOB_WARM; 	//настройка для перехода в режим подогрева
				APP_FLAGS.b_keep_warm_en = 1; 	//включаем переход в режим подогрева
				BOOLING_TEMP = continent_set_temp(option->param1);
				return 1;
			}
#ifdef CONTINENT_USA
			if((option->mode1 == APP_WORK_PROG_WARM_CALENDAR && option->mode2 == APP_WORK_PROG_BOIL_CALENDAR 
					&& continent_set_temp(option->param1) <= APP_KEEPWARM_MAX_TEMP_C && continent_set_temp(option->param1) >= APP_KEEPWARM_MIN_TEMP_C)
				||(option->mode2 == APP_WORK_PROG_WARM_CALENDAR && option->mode1 == APP_WORK_PROG_BOIL_CALENDAR  
			&& continent_set_temp(option->param2) <= APP_KEEPWARM_MAX_TEMP_C && continent_set_temp(option->param2) >= APP_KEEPWARM_MIN_TEMP_C))					// режим кипячения с подогревом
#else
			if((option->mode1 == APP_WORK_PROG_WARM_CALENDAR && option->mode2 == APP_WORK_PROG_BOIL_CALENDAR 
					&& continent_temp(option->param1) <= APP_KEEPWARM_MAX_TEMP_C && continent_temp(option->param1) >= APP_KEEPWARM_MIN_TEMP_C)
				||(option->mode2 == APP_WORK_PROG_WARM_CALENDAR && option->mode1 == APP_WORK_PROG_BOIL_CALENDAR  
			&& continent_temp(option->param2) <= APP_KEEPWARM_MAX_TEMP_C && continent_temp(option->param2) >= APP_KEEPWARM_MIN_TEMP_C))					// режим кипячения с подогревом
#endif
			{
					APP_STATE = APP_STAND_BY; 				//переходим в режим ожидания
					MOBILE_STATE = MOB_BOIL_WARM; 		//настройка для перехода в режим кипячение с подогревом
					APP_FLAGS.b_keep_warm_en = 1; 			//включаем переход в режим подогрева
					if(option->mode1 == APP_WORK_PROG_WARM_CALENDAR) BOOLING_TEMP = continent_set_temp(option->param1);
					else BOOLING_TEMP = continent_set_temp(option->param2);
					return 1;
					
			}
			return 0;
		}
	}
	return 0;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_set_pallet_param(uint8_t idx, uint8_t pallet_idx, uint8_t en)
{
	if(idx == NUM_STATE_PALLET_CALENDAR && pallet_idx == NUM_STATE_PALLET_CALENDAR && en <= 1){
		APP_FLAGS.b_ind_calendar_synchron_en = en;
		return ERSP_SUCCESS;
	}
	if( (idx > 1) || (en > 1) ) return ERSP_ERROR_INTERNAL;
	if( pallet_idx >= APP_COLOR_PALLET_NUM_MAX ) return ERSP_ERROR_NOT_SUPPORTED;

	color_option[idx].idx = pallet_idx;
	color_option[idx].activ = en;

	return ERSP_SUCCESS;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_get_prog(void)
{
	switch(MOBILE_STATE)
	{
		case MOB_WARM: return APP_WORK_PROG_WARM;
		case MOB_BOILING: return APP_WORK_PROG_BOIL;
		case MOB_BOIL_WARM: return APP_WORK_PROG_BOILWARM;
		case MOB_NIGHT_LIGHT: return APP_WORK_PROG_NIGHTLIGHT;
		case MOB_DISCO: return APP_WORK_PROG_DISCO;
	}
	return APP_WORK_PROG_BOIL;
}
/**
 * 	описание в application_api.h
*/
#ifdef CONTINENT_USA
uint16_t api_get_temp_boil(void)
#else
uint8_t api_get_temp_boil(void)
#endif
{
	return continent_get_temp(BOOLING_TEMP);
}
/**
 * 	описание в application_api.h
*/
uint16_t api_get_cycle_night_time(void)
{
//	SPREADER_RTT_LOG(0,"%s[MAIN]  %sget cycle %d\n",	\
						RTT_CTRL_TEXT_BRIGHT_GREEN,	\
						RTT_CTRL_TEXT_BRIGHT_WHITE, (uint16_t)(color_time.cycle_time_10ms/2/100));
	return (uint16_t)(color_time.cycle_time_10ms/2/100);
}
/**
 * 	описание в application_api.h
*/
uint16_t api_get_cur_night_time(void)
{
	if(APP_STATE != APP_NIGHTLIGHT) return 0;
//	return (color_time.current_time_10ms<color_time.cycle_time_10ms/2)?(color_time.current_time_10ms/100):((color_time.current_time_10ms-color_time.cycle_time_10ms/2)/100);
	return (TIMERS_MILLISECOND(CURRENT_TIME_10MS) / 1000);
}
/**
 * 	описание в application_api.h
*/
uint16_t api_get_period_night_time(void)
{
	return IN_TIMERS_HOURS(color_time.period_work_1c);
}
/**
 * 	описание в application_api.h
*/
uint8_t api_heat_pallet_num(void)
{
	return color_option[APP_COLOR_HEAT_IDX].idx;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_night_pallet_num(void)
{
	return color_option[APP_COLOR_NIGHT_IDX].idx;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_is_pallet_heat_active(void)
{
	return color_option[APP_COLOR_HEAT_IDX].activ;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_is_pallet_night_active(void)
{
	return color_option[APP_COLOR_NIGHT_IDX].activ;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_is_keyb_block(void)
{
	return APP_FLAGS.b_keyb_block_en;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_is_sound_en(void)
{
	return APP_FLAGS.b_sound_en;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_save_palette(void)
{
	uint32_t 	addr, 
				err_code;
	bool 		result = true;

	err_code = r4s_app_flash_page_get_addr(APP_MEM_PAGE_PALLET, &addr); //находим адрес рабочей страницы
	APP_ERROR_CHECK(err_code);
	//сравниваем сохраненные данные с текущими
	result &= (memcmp((uint32_t *)(addr), color_option, (sizeof(color_config_t)*APP_COLOR_PALLET_NUM_MAX)) == 0);
	result &= (memcmp((uint32_t *)(addr + sizeof(color_config_t)), pwm_etalon_table, (sizeof(cl_gradient_t)*APP_COLOR_PALLET_NUM_MAX)) == 0);
	if(result == true) return 1;

	//создать переменную для сохранения ее в flash
	app_flash_data_t app_save_data __attribute__((aligned(sizeof(uint32_t))));
	//заполнить переменную данными
	memcpy(app_save_data.color_config, color_option, (sizeof(color_config_t)*APP_COLOR_PALLET_NUM_MAX));
	memcpy(app_save_data.color_table, pwm_etalon_table, (sizeof(cl_gradient_t)*APP_COLOR_PALLET_NUM_MAX));

	//проверить флэш на пустоту
	if(is_flash_empty((uint32_t const*)addr) == 0){
		err_code = r4s_app_flash_erase(APP_MEM_PAGE_PALLET); //очистить страницу, если она не пустая
		APP_ERROR_CHECK(err_code);
	}
	//посчитать CRC
	app_save_data.crc16 = crc16_compute((uint8_t *)app_save_data.color_config,
										(sizeof(color_config_t) + sizeof(cl_gradient_t))*APP_COLOR_PALLET_NUM_MAX,
										NULL);
	//записать данны в flash
	err_code = r4s_app_flash_write(	APP_MEM_PAGE_PALLET, 
									0,
									(uint8_t *)app_save_data.color_config,
									sizeof(app_save_data));
	if(err_code == NRF_ERROR_TIMEOUT) return 0;
	else APP_ERROR_CHECK(err_code);

	return 1;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_default_palette(void)
{
	uint32_t 	addr, 
				err_code;
	bool 		result = true;

	APP_FLAGS.b_is_calendar_synchron = 0;	// 
	evcal_erase_all_tasks();

	err_code = r4s_app_flash_page_get_addr(APP_MEM_PAGE_PALLET, &addr); //находим адрес рабочей страницы
	APP_ERROR_CHECK(err_code);

	color_config_t color_option_tmp [APP_COLOR_PALLET_NUM_MAX] = {
																	{0, 1},
																	{1, 1}};
	cl_gradient_t pwm_etalon_table_tmp [APP_COLOR_PALLET_NUM_MAX] = {							/* данные о палитре значений RGB светодиода*/
																	COLOR_BOIL_DEF_VALUE, 
																	COLOR_NIGHTLED_DEF_VALUE
																	};
	
	//сравниваем сохраненные данные с заводскими
	result &= (memcmp((uint32_t *)(addr), color_option_tmp, (sizeof(color_config_t)*APP_COLOR_PALLET_NUM_MAX)) == 0);
	result &= (memcmp((uint32_t *)(addr + sizeof(color_config_t)), pwm_etalon_table_tmp, (sizeof(cl_gradient_t)*APP_COLOR_PALLET_NUM_MAX)) == 0);
	if(result == true) return 1;

	//создать переменную для сохранения ее в flash
	app_flash_data_t app_save_data __attribute__((aligned(sizeof(uint32_t))));
	//заполнить переменную данными
	memcpy(app_save_data.color_config, color_option_tmp, (sizeof(color_config_t)*APP_COLOR_PALLET_NUM_MAX));
	memcpy(app_save_data.color_table, pwm_etalon_table_tmp, (sizeof(cl_gradient_t)*APP_COLOR_PALLET_NUM_MAX));

	//проверить флэш на пустоту
	if(is_flash_empty((uint32_t const*)addr) == 0){
		err_code = r4s_app_flash_erase(APP_MEM_PAGE_PALLET); //очистить страницу, если она не пустая
		APP_ERROR_CHECK(err_code);
	}
	//посчитать CRC
	app_save_data.crc16 = crc16_compute((uint8_t *)app_save_data.color_config,
										(sizeof(color_config_t) + sizeof(cl_gradient_t))*APP_COLOR_PALLET_NUM_MAX,
										NULL);
	//записать данны в flash
	err_code = r4s_app_flash_write(	APP_MEM_PAGE_PALLET, 
									0,
									(uint8_t *)app_save_data.color_config,
									sizeof(app_save_data));
										
	memcpy(color_option, app_save_data.color_config, (sizeof(color_config_t)*APP_COLOR_PALLET_NUM_MAX));
	memcpy(pwm_etalon_table, app_save_data.color_table, (sizeof(cl_gradient_t)*APP_COLOR_PALLET_NUM_MAX));

	if(err_code == NRF_ERROR_TIMEOUT) return 0;
	else APP_ERROR_CHECK(err_code);

	return 1;
}
/**
 * 	описание в application_api.h
*/
#ifdef CONTINENT_USA
float api_get_cur_temp(void)
{
//    SPREADER_RTT_LOG(0,"%d.%02d %d.%02d    ",
//					(uint16_t) boiling_ind_temp, ((uint16_t)(boiling_ind_temp*100))%100,
//					(uint16_t) add_temp_ind, ((uint16_t)(add_temp_ind*100))%100);

	return (boiling_ind_temp+add_temp_ind>100.)?(100.):(boiling_ind_temp+add_temp_ind);
}
#else
uint8_t api_get_cur_temp(void)
{
//    SPREADER_RTT_LOG(0,"%d %d.%02d %d.%02d\n",
//					boiling_ind_temp,
//					(uint16_t) add_temp_ind, ((uint16_t)(add_temp_ind*100))%100,
//					(uint16_t) (boiling_ind_temp+add_temp_ind), ((uint16_t)((boiling_ind_temp+add_temp_ind)*100))%100);

	return continent_temp((boiling_ind_temp+add_temp_ind>100.)?(100.):(boiling_ind_temp+add_temp_ind));
}
#endif
/**
 * 	описание в application_api.h
*/
uint8_t api_set_calendar_data(void *timestamp, void *shift)
{
	calendar_utc_t m_time_stamp = 0;
	calendar_shift_utc_t m_shift = 0;
	
	m_time_stamp = uint32_decode(timestamp); //преобразуем данные массива в uint32_t
	m_shift = uint32_decode(shift); //преобразуем данные массива в uint32_t

	uint32_t err_code = calendar_set_time(m_time_stamp, m_shift);
	switch (err_code)
	{
		case NRF_SUCCESS:
			APP_FLAGS.b_is_calendar_synchron = 1;
			return ERSP_SUCCESS;
		case NRF_ERROR_INVALID_DATA:
			return ERSP_ERROR_INVALID_DATA;
		case DRIVER_MODULE_NOT_INITIALZED:
			return ERSP_ERROR_INTERNAL;
	}
	return ERSP_ERROR_UNKNOWN;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_get_heater_info(uint8_t idx, app_heater_info_t *p_out_str)
{
	if(idx > 0) return ERSP_ERROR_INVALID_PARAM;
	if(p_out_str == NULL) return ERSP_ERROR_NULL;
	double result = 0;

	p_out_str->time_s = heating_get_work_val();
	p_out_str->rell_on_cnt = heating_get_rell_on_cnt();
	result = ((double)p_out_str->time_s / 3600.0) * APP_HEATER_WATTS;
	p_out_str->pwr_in_watts = result;

	return ERSP_SUCCESS;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_get_user_on(uint32_t *p_user_on)
{
	if(p_user_on == NULL) return ERSP_ERROR_NULL;

	*p_user_on = app_user_on_cnt;
	return ERSP_SUCCESS;
}
/**
 * 	описание в application_api.h
*/
void api_get_calendar_data(void *timestamp, void *shift)
{
	calendar_utc_t m_time_stamp = 0;
	calendar_shift_utc_t m_shift = 0;

	//получаем данные о текущем UTC и времени сдвига
	uint32_t err_code = calendar_get_utc_time(&m_time_stamp, &m_shift);
	APP_ERROR_CHECK(err_code);
	
	memcpy(timestamp, &m_time_stamp, sizeof(calendar_utc_t));
	memcpy(shift, &m_shift, sizeof(calendar_shift_utc_t));
}
/**
 * 	описание в application_api.h
*/
void api_get_evcal_task(uint8_t task_num, void *p_buf)
{
	uint32_t err_code = evcal_get_task_data(task_num, p_buf);
	if(err_code != NRF_SUCCESS){
		memset(p_buf, 0, sizeof(evcal_task_t));
	}
}
/**
 * 	описание в application_api.h
*/
uint8_t api_add_evcal_task(void *p_input, uint8_t *uid)
{
	//записываем задачу в календарь
	uint32_t err_code = evcal_save_task(p_input);
	*uid = ((evcal_task_t *)p_input)->uid; //записываем UID присвоенной задачи
	switch (err_code)
	{
		case NRF_SUCCESS:
		{
			return ERSP_SUCCESS;
		}
		case NRF_ERROR_NO_MEM:
		{
			return ERSP_ERROR_NO_MEM;
		}
		case DRIVER_MODULE_NOT_INITIALZED:
		case NRF_ERROR_NULL:
		{
			return ERSP_ERROR_INTERNAL;
		}
	}
	return ERSP_ERROR_UNKNOWN;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_del_evcal_task(uint8_t uid_task)
{
	//записываем новую задачу в календарь
	uint32_t err_code = evcal_delete_task(uid_task);
	switch (err_code)
	{
		case NRF_SUCCESS:
		{
			return ERSP_SUCCESS;
		}
		case NRF_ERROR_NOT_FOUND:
		{
			return ERSP_ERROR_NOT_FOUND;
		}
		case NRF_ERROR_INVALID_PARAM:
		{
			return ERSP_ERROR_INVALID_PARAM;
		}
		case DRIVER_MODULE_NOT_INITIALZED:
		{
			return ERSP_ERROR_INTERNAL;
		}
	}
	return ERSP_ERROR_UNKNOWN;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_erase_evcal(void)
{
	if(evcal_erase_all_tasks() == NRF_SUCCESS){
		return ERSP_SUCCESS;
	} else {
		return ERSP_ERROR_INTERNAL;
	}
}
/**
 * 	описание в application_api.h
*/
uint8_t api_get_ver_evcal(void)
{
	return EVCAL_DRIVER_VERSION;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_get_max_task_evcal(void)
{
	return EVCAL_MAX_TASKS;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_get_cur_task_evcal(void)
{
	uint8_t m_num_task = 0;
	APP_ERROR_CHECK(evcal_get_task_number(&m_num_task));
	return m_num_task;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_is_pallet_ind_sync_calendar_active(void)
{
	return APP_FLAGS.b_ind_calendar_synchron_en;
}

/**
 * 	описание в application_api.h
*/
uint8_t api_pallet_ind_sync_calendar_num(void)
{
	return NUM_STATE_PALLET_CALENDAR;
}
/**
 * 	описание в application_api.h
*/
uint8_t api_stop_nightlight(void)
{
	CURRENT_TIME_10MS = 0;									//сброс текущего времеми цикла смены цвета
	CURRENT_PERIOD_WORK_1C = color_time.period_work_1c;	 	//остановка подсчета времени работы ночника
	APP_FLAGS.b_night_on = false;
	return ERSP_SUCCESS;
}
/**
 * 	описание в application_api.h
*/
void app_start_long_boiling(uint8_t time)
{
	boiling_min_time_downcounter_s = time;// + ((APP_FLAGS.b_long_boiling_en)?(APP_BOILING_MIN_TIME_S):(0));
	delta_temp_ind = fabs((float)(100. - temp_get_val())/boiling_min_time_downcounter_s);
	
//	boiling_min_time_downcounter_s = time + ((APP_FLAGS.b_long_boiling_en)?(APP_BOILING_MIN_TIME_S):(0));
//	delta_temp_ind = (float)(100. - temp_get_val())/boiling_min_time_downcounter_s;	//дельта температуры прибавляемое к текущей для отображения
//	delta_temp_down_ind = (float)(100. - temp_get_val())/APP_DOWN_TEMP_COUNT_TIME_S;	//дельта температуры прибавляемое к текущей при остывании для отображения
}

void app_restore_default_temperature_shift(void)
{
	uint32_t err_code;
	
    memset(&param,0xFF,sizeof(param_t));
    param.temperature_shift = TEMPERATURE_ZERO_SHIFT_VALUE;
	
#if defined (OLD_SENSOR_AND_ALGORITHM)
    param.saved_coef_A = PARAM_COEF_A;
    param.saved_coef_B = PARAM_COEF_B;
#elif defined (WT2_SENSOR_AND_NEW_ALGORITHM)
#else
	#error "NO SENSOR AND ALGORITHM DEFINED"
#endif
	
    err_code = param_set_data();
    APP_ERROR_CHECK(err_code);
//    SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"Default param values are restored\r\n"RTT_CTRL_RESET);
}

bool api_get_block_on(void)
{
	return APP_FLAGS.b_keyb_block_en;
}

#ifdef CONTINENT_USA
static int8_t app_cmp_pull_data(void *first, void* second, int size)
{	
	if(first == 0 || second == 0 || size == 0) return -1;
	
	uint16_t ftemp = (*((uint8_t*)first+8)+(*((uint8_t*)first+9)<<8));
	uint16_t ftemp_pre = (*((uint8_t*)second+8)+(*((uint8_t*)second+9)<<8));
	
//	SPREADER_RTT_LOG(0, "%d %d \n", (int)SFloat16ToFloat(ftemp), (int)SFloat16ToFloat(ftemp_pre));
	
	
	if( ((*((uint8_t*)first+3)) == (*((uint8_t*)second+3))) &&
			((*((uint8_t*)first+4)) == (*((uint8_t*)second+4))) &&
			((*((uint8_t*)first+5)) == (*((uint8_t*)second+5))) &&
			((*((uint8_t*)first+6)) == (*((uint8_t*)second+6))) &&
			((*((uint8_t*)first+7)) == (*((uint8_t*)second+7))) &&
			((int)SFloat16ToFloat(ftemp) == (int)SFloat16ToFloat(ftemp_pre)) &&
			((*((uint8_t*)first+11)) == (*((uint8_t*)second+11))) &&
			((*((uint8_t*)first+16)) == (*((uint8_t*)second+16))) &&
			((*((uint8_t*)first+18)) == (*((uint8_t*)second+18))))

		return 0;
	
	return 1;
}

void app_notification_uart(void)
{
	uint8_t buf[20];
	static	uint8_t pre_buf[20];
	
	memset(&buf, 0, 20);

	buf[0] = 0x55;
	buf[1] = 0;
	buf[2] = 6;
	
	buf[3] = api_get_prog();

	uint16_t temp = api_get_temp_boil();
	buf[4] = temp;
	buf[5] = temp>>8;
	
	buf[6] = api_is_keyb_block();
	buf[7] = api_is_sound_en();
	
	uint16_t tmp = continent_get_temp(api_get_cur_temp());
	buf[8] = tmp;
	buf[9] = tmp>>8;
			
	if(api_get_error() == APP_API_NO_ERROR){
		buf[11] = api_get_state();
	}else{
		buf[11] = APP_API_ERROR_STATE;
	}
	buf[16] = (uint8_t)api_get_temperature_shift();
	buf[18] = api_get_error();
	buf[19] = 0xAA;

	if(app_cmp_pull_data(buf, pre_buf, 20) != 0)
	{
		r4s_slave_data_transmit(buf, 20);
	}

	memcpy(pre_buf, buf, 20);

	app_notification_uart_flg = false;
}
#else
void app_notification_uart(void)
{
	uint8_t buf[20];
	static	uint8_t pre_buf[20];
	
	memset(&buf, 0, 20);

	buf[0] = 0x55;
	buf[1] = 0;
	buf[2] = 6;
	
	buf[3] = api_get_prog();
	buf[5] = api_get_temp_boil();
	buf[6] = api_is_keyb_block();
	buf[7] = api_is_sound_en();
	buf[8] = api_get_cur_temp();
			
	uint16_t time = api_get_cycle_night_time();
	buf[9] = (uint8_t)time;
	buf[10] = (uint8_t)(time>>8);

	if(api_get_error() == APP_API_NO_ERROR){
		buf[11] = api_get_state();
	}else{
		buf[11] = APP_API_ERROR_STATE;
	}
	buf[16] = (uint8_t)api_get_temperature_shift();
	buf[18] = api_get_error();
	buf[19] = 0xAA;

	if(memcmp(pre_buf, buf, 20) != 0){
		r4s_slave_data_transmit(buf, 20);
	}
	
	memcpy(pre_buf, buf, 20);
		
	app_notification_uart_flg = false;
}

#endif

void api_clean_mass_fw_update(void)
{
	on_mass_cnt = 0;
}

void api_error_mass_fw_update(void)
{
    SPREADER_RTT_LOG(0,"[APP] error_mass_fw_update");
	app_ind_state = IND_END_ERROR_MASS_FW_UPDATE;
}

void api_success_mass_fw_update(void)
{
	app_ind_state = IND_END_SUCCESS_MASS_FW_UPDATE;
	app_timeout_timers_stop();
}
bool api_state_mass_fw_update(void)
{
	if(	APP_STATE == APP_MASS_FW_UPDATE && 
			(app_ind_state == IND_END_SUCCESS_MASS_FW_UPDATE 
			|| app_ind_state == IND_END_ERROR_MASS_FW_UPDATE))
		return false;
	return true;
}

Made on
Tilda