Программный модуль для чайника RK-G200S
v.3.17
ПО является неотъемлемой частью чайника RK-G200S, отдельно потребителю не поставляется и эксплуатируется только в составе устройства.
////////////////////////////////////////////////////////////////
//RK-G200S
//v3.17
//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 "com_slave.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"
#include "temp.h"
#include "not_active.h"
#include "continent.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
/********* DEFINES **************************************************************/
#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 //запуск расширенной программы с параметрами
#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 }, \
}
/********* 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_CNECK_BLOCK_ON
#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;\
SPREADER_RTT_LOG(0,"%s[APPLICATION] %sblock=%d\n", \
RTT_CTRL_TEXT_BRIGHT_GREEN, \
RTT_CTRL_TEXT_BRIGHT_WHITE, \
app_flags.b_keyb_block_en); \
} \
}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_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)
/********* 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{
/* флаги функционала*/
uint16_t b_sound_en :1; //флаг разрешения подачи звукового сигнала
uint16_t b_keyb_block_en :1; //флаг блокировки панели
uint16_t b_is_calendar_synchron :1; //флаг синхронизации с календарем
uint16_t b_ind_calendar_synchron_en :1; //флаг разрешения индикации синхронизации с календарем
uint16_t b_night_on :1; //флаг разрешения длительного кипения
/* bluetooth*/
uint16_t b_unpairing :1; //флаг unparing
uint16_t b_connection_is_established :1; //флаг наличия активного соединения по ble
uint16_t b_session_is_opened :1; //флаг наличия сесии по ble
/* вспомогательные флаги условий*/
uint16_t b_waiting_unpress_btn :1; //флаг ожидания отпускания клавиши
uint16_t b_test_mode_on :1; //флаг ожидания отпускания клавиши
/* для таймеров*/
uint16_t b_simple_timeout :1; //флаг срабатывания перехода между режимами
/* флаги управления подогревом и кипячения*/
uint16_t b_boiling_complete :1; //флаг окончания кипения
uint16_t b_boiling_prev :1; //флаг сигнализации о предыдущем этапе кипячения
uint16_t b_keep_warm_en :1; //флаг необходимости перехода в режим подогрева
uint16_t b_keep_wrm_boost_cmplt :1; //флаг зашершения выхода на заданную температуру
uint16_t b_keep_wrm_boost_cmplt_prew :1; //предъидущее значение флага зашершения выхода на заданную температуру(используется для подачи звукового сигнала)
}app_flags_t;
typedef struct{ //структура для управления ночной подсветкой
uint32_t cycle_time_10ms; // время полного цикла смены цвета
uint32_t current_time_10ms; // текущее время цикла смены цвета
uint32_t period_work_1c; // время работы ночника
uint32_t current_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,
}app_ind_state_t;
/********* GLOBAL VARIABLES *****************************************************/
/********* LOCAL VARIABLES ******************************************************/
static int RGB_TYPE = 4;
static float quantization_color[5][3] = { {1.000, 1.000, 1.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;
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;//для хранения состояния машины, для возврата
static app_mobile_state_t app_mobile_state = MOB_BOILING; /* последний режим захождения был кипячение*/
static app_ind_state_t app_ind_state = IND_IDLE; /* состояние индикации в standby режиме*/
static app_flags_t app_flags; /* флаги используемые в application*/
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; /* информация последней нажатой кнопки*/
static uint8_t boiling_ind_temp; /* температура индикации кипячения */
static uint8_t booling_temp = 0; /* температура подогрева*/
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; /* счетчик времени индикации состояния кипения после закипания чайника */
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, 0 , TIMERS_HOURS(8), 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(uint8_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_get_val();
return (temp==0 || temp >= TEMP_EMPTY_KETTLE_TEMP_C);
}
static bool app_get_error_sensor()
{
if(is_error_sensor()) //обрыав датчика
{
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 mashine
*
* @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(++color_time.current_time_10ms >= color_time.cycle_time_10ms) color_time.current_time_10ms = 0;
}
/**
* @brief Обработчик секундного таймера приложения.
* Импользуется для: 1. изменения индикации внутри одного сотояния state mashine
* 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( ++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(color_time.current_period_work_1c < color_time.period_work_1c){
++color_time.current_period_work_1c; if(color_time.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(uint8_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){
app_set_all_led();
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
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;
}
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();
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;
}
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();
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;
}
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();
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;
}
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();
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;
}
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_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 = {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));
#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;
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 )
{
//если не установлен флаг возвращаем реальную температуру
boiling_ind_temp = ( temp_get_val() > APP_HEATING_TEMP_C ) ? APP_HEATING_TEMP_C : temp_get_val();
}else{
if( temp_get_val() > boiling_ind_temp + step )
{
//отменим "замазку", т.к. реальная температура больше "замазки"
app_show_boiling_temp = false;
boiling_ind_temp = ( temp_get_val() > APP_HEATING_TEMP_C ) ? APP_HEATING_TEMP_C : temp_get_val();
}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; //не снижаем температуру пока в режиме кипения
//идем вниз
if( boiling_ind_temp > temp_get_val() + step )
{
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) return; //режим "блокировки"
switch(p_data->array[1])
{
case CALENDAR_START_COM:
{
api_set_prog(p_data->array[2]);
api_set_boil_temp(p_data->array[4]);
api_start();
break;
}
case CALENDAR_STOP_COM:
{
api_stop_nightlight(); // остановка ночника даже если он в фоновом процессе
if(app_state != APP_BOILING_PROC) api_stop();
break;
}
case CALENDAR_OPTION_COM:
api_set_prog_option(&p_data->array[2]);
api_start();
break;
default:
{
break;
}
}
return;
}
void *application_get_adr_data(void)
{
app_pof_info.b_block_en = app_flags.b_keyb_block_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 = color_time.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 = color_time.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 )
{
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);
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(!state_pre_fl){
APP_ERROR_CHECK(pof_manager_get_state(&b_pof_have_data));
if( b_pof_have_data ){
//если есть данные, которые надо восстановить
APP_ERROR_CHECK(pof_manager_copy_data()); //чтение из ПЗУ сохраненных параметров
APP_ERROR_CHECK(pof_manager_clear_memory()); //затираем данные для ускорения записи при пропадании питания
//восстанавливаем сохраненные данные
#ifdef APP_CNECK_BLOCK_ON
app_flags.b_keyb_block_en = app_pof_info.b_block_en;
#else
app_flags.b_keyb_block_en = 0;
#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)){
color_time.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_CNECK_BLOCK_ON
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)){
color_time.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);
}
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:
{
temp_clear_begin_boiling(); //сброс начальных значений кипения
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;
}
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);
app_switch_mass_timeout = TIMERS_SECOND(APP_SWITCH_MASS_TIMEOUT_S);
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);
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:
{
//сброс настроек цветовой палитры
#ifdef APP_CUSTOM_COLOR_RGB_ON
q_color_state_reset();
#endif
//очищаем все режимы
app_flags.b_keep_warm_en = 0;
if(color_time.current_period_work_1c<color_time.period_work_1c || app_flags.b_night_on){ //
app_state = APP_NIGHTLIGHT;
app_mobile_state = MOB_NIGHT_LIGHT; //настройка для перехода в режим ночника
}
SPREADER_RTT_LOG(0,RTT_CTRL_TEXT_BRIGHT_WHITE"-->STAND_BY\n"RTT_CTRL_RESET);
break;
}
case APP_BOILING_PROC:
{
//сброс настроек цветовой палитры
#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;
temp_set_begin_boiling(); //сохранение начальных значений кипения
clear_small_grad();
clear_decline_grad();
break;
}
case APP_CONFIG_WARM:
{
app_timeout_timers_restart(APP_CONFIG_TIMEOUT_S);
app_flags.b_keep_warm_en = 1; //переход в режим кипячения активирован
app_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
app_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:
{
app_timeout_timers_restart(APP_FW_UPDATE_TIMEOUT_S);
break;
}
case APP_NIGHTLIGHT:
{
//сброс настроек цветовой палитры
#ifdef APP_CUSTOM_COLOR_RGB_ON
q_color_state_reset();
#endif
color_time.current_time_10ms = 0;
break;
}
case APP_DISCO:
{
app_disco_dec_time =0;
break;
}
default:
{
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 mashine
application_init_new_state( app_state ); //выполняет работу при изменении состояния state mashine
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();
//transition
if( app_flags.b_simple_timeout ){
if( 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;
app_flags.b_waiting_unpress_btn = 1;
} else {
//переходим в режим ожидания
++on_mass_cnt;
app_state = APP_STAND_BY;
}
}
break;
}
case APP_MASS_FW_UPDATE:
{
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 = {0, 0, 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((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;
}
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(sd_nvic_SystemReset());
}
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_BEEP_SINGLE();
}
if(app_keyb_data[KEYB_PLUS].event_press == KEYB_EVENT_CAPTURED){
app_flags.b_test_mode_on = 1;
APP_BEEP_SINGLE();
}
if( app_keyb_data[KEYB_PWR].state == KEYB_PRESSED && app_keyb_data[KEYB_PLUS].state == KEYB_PRESSED ){
APP_BEEP_SINGLE();
APP_ERROR_CHECK(sd_nvic_SystemReset());
}
// SPREADER_RTT_LOG(0,"[TEST] cnt = %d, push cnt = %d\n", on_mass_cnt, app_keyb_serv_data[KEYB_PWR].push_cnt);
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)
{
app_state = APP_MASS_FW_UPDATE; //переходим в режим MASS UPDATE
}
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));
#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_last_btn.time_push_ms == 0){
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_ind_state = IND_PARING; //переводим индикацию в режим "unparing"
app_blink_time_ms = 0; //сбрасываем время для индикации
}
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){
//нет необходимости очищать значение кнопки
//так как при переходе в другое состояние - это происходит автоматом
app_state = APP_PAIRING; //переходим в режим пэйринга
}
}
//счетчик нажатий на кнопку больше нуля
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;
app_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(color_time.current_time_10ms<=color_time.cycle_time_10ms/2) proc = ((float)color_time.current_time_10ms * 100.0) / ((float)color_time.cycle_time_10ms/2);
else proc = ((float)(color_time.cycle_time_10ms-color_time.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));
#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;
app_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_last_btn.time_push_ms == 0){
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_ind_state = IND_PARING; //переводим индикацию в режим "unparing"
app_blink_time_ms = 0; //сбрасываем время для индикации
}
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){
//нет необходимости очищать значение кнопки
//так как при переходе в другое состояние - это происходит автоматом
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;
app_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[color_option[APP_COLOR_HEAT_IDX].idx], api_get_cur_temp(), &pwm_led));
#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
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
}
}
app_flags.b_boiling_prev = app_flags.b_boiling_complete;
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;
}
}
//условия проверки данных с клавиатуры
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();
if(booling_temp >= TEMP_WARM_LED_4){
app_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;
app_mobile_state = MOB_BOIL_WARM; //режим кипячения с подоревом для мобильника
app_flags.b_keep_warm_en = 1; //переход в режим подогрева активирован
}
}
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); //сбрасываем настройки
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;
//звуковая индикация завершения подогрева
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};
if(color_option[APP_COLOR_HEAT_IDX].activ){
uint8_t idx = color_option[APP_COLOR_HEAT_IDX].idx;
#ifdef APP_CUSTOM_COLOR_RGB_ON
APP_ERROR_CHECK(q_color_pallet_get(&pwm_etalon_table[idx], api_get_cur_temp(), &pwm_led));
#else
APP_ERROR_CHECK(color_led_calc_value( &pwm_etalon_table[idx], &pwm_led, api_get_cur_temp(), 0));
#endif
}
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};
if(color_option[APP_COLOR_HEAT_IDX].activ){
#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(), &pwm_led));
#else
APP_ERROR_CHECK(color_led_calc_value( &pwm_etalon_table[color_option[APP_COLOR_HEAT_IDX].idx],&pwm_led, api_get_cur_temp(), 0));
#endif
}
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)){
//если разрешена подача звукового сигнала
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);
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;
}
uint8_t api_get_state(void)
{
switch(app_state)
{
case APP_START:
case APP_EMPTY_KETTLE:
case APP_TEST:
{
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(app_state == APP_ERROR) return APP_API_OVERHEAT_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
color_nightlight_time_t color = { 300*TIMERS_TICK_MS, 0 , TIMERS_HOURS(8), 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);
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:
{
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;
app_flags.b_connection_is_established = 0;
return;
}
/**
* описание в application_api.h
*/
void api_set_connection_flag(void)
{
app_flags.b_connection_is_established = 1;
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:
{
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:
{
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_TEST:
{
return 0;
}
case APP_STAND_BY: //в режиме ожидания
{
switch(app_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; //переходим в режим кипячение с нагревом
if(app_user_on_cnt < UINT32_MAX) ++app_user_on_cnt;
return 1;
case MOB_NIGHT_LIGHT:
app_state = APP_NIGHTLIGHT; //переходим в режим ночника
color_time.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_TEST:
{
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_TEST:
{
return 0;
}
case APP_STAND_BY: //в режиме ожидания
{
switch(app_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; //переходим в режим ночника
color_time.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
*/
uint8_t api_set_boil_temp(uint8_t temp_boil)
{
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_TEST:
{
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( app_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){
app_mobile_state = MOB_BOILING; //выставляем режим кипячения
app_flags.b_keep_warm_en = 0; //отключаем переход в режим подогрева
}else{
app_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_TEST:
{
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));
color_time.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;
color_time.current_period_work_1c = 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_TEST:
{
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_TEST:
{
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_CNECK_BLOCK_ON
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_TEST:
{
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_TEST:
{
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_TEST:
{
return 0;
}
case APP_BOILING_PROC:
{
if( ((prog_num == APP_WORK_PROG_BOIL) && (app_mobile_state == MOB_BOILING)) ||
((prog_num == APP_WORK_PROG_BOILWARM) && (app_mobile_state == MOB_BOIL_WARM))){
return 1;
} else {
return 0;
}
}
case APP_WARM_PROC:
{
if( (prog_num == APP_WORK_PROG_WARM) && (app_mobile_state == MOB_WARM) ){
return 1;
} else {
return 0;
}
}
case APP_KEEPWARM_PROC:
{
if( ((prog_num == APP_WORK_PROG_WARM) && (app_mobile_state == MOB_WARM)) ||
((prog_num == APP_WORK_PROG_BOILWARM) && (app_mobile_state == MOB_BOIL_WARM))){
return 1;
} else {
return 0;
}
}
case APP_NIGHTLIGHT:
{
if( (prog_num == APP_WORK_PROG_NIGHTLIGHT) && (app_mobile_state == MOB_NIGHT_LIGHT) ){
return 1;
} else {
return 0;
}
}
case APP_DISCO:
{
if( (prog_num == APP_WORK_PROG_DISCO) && (app_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; //переходим в режим ожидания
app_mobile_state = MOB_BOILING; //настройка для перехода в режим кипячение
app_flags.b_keep_warm_en = 0; //отключаем переход в режим подогрева
booling_temp = 0; //сбрасываем температуру
return 1;
}
case APP_WORK_PROG_WARM:
{
app_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; //переходим в режим ожидания
app_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; //переходим в режим ожидания
app_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; //переходим в режим ожидания
app_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_TEST:
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; //переходим в режим ожидания
app_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; //переходим в режим ожидания
app_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){ // первый параметр - режим "нагрев" второй параметр не задан
if(continent_temp(option->param1) > APP_KEEPWARM_MAX_TEMP_C || continent_temp(option->param1) < APP_KEEPWARM_MIN_TEMP_C) return 0; // неверные значения температуры в режиме "нагрев"
app_state = APP_STAND_BY; //переходим в режим ожидания
app_mobile_state = MOB_WARM; //настройка для перехода в режим подогрева
app_flags.b_keep_warm_en = 1; //включаем переход в режим подогрева
booling_temp = continent_set_temp(option->param1);
return 1;
}
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)) // режим кипячения с подогревом
{
app_state = APP_STAND_BY; //переходим в режим ожидания
app_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(app_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
*/
uint8_t api_get_temp_boil(void)
{
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(color_time.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
*/
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));
}
/**
* описание в 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_WATS;
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)
{
color_time.current_time_10ms = 0; //сброс текущего времеми цикла смены цвета
color_time.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 = (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(¶m,0xFF,sizeof(param_t));
param.temperature_shift = TEMPERATURE_ZERO_SHIFT_VALUE;
param.saved_coef_A = PARAM_COEF_A;
param.saved_coef_B = PARAM_COEF_B;
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;
}
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;
}
void api_clean_mass_fw_update(void)
{
on_mass_cnt = 0;
}
void api_error_mass_fw_update(void)
{
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;
}