Программный модуль для чайника RK-M171S. Версия 2.6
ПО является неотъемлемой частью чайника RK-M171S, отдельно потребителю не поставляется и эксплуатируется только в составе устройства.
////////////////////////////////////////////////////////////////
//RK-M171S
//v2.6
//application.c
////////////////////////////////////////////////////////////////
/********* HEADER FILE INCLUDES *************************************************/
#include "math.h"
#include "keyb.h"
#include "timers.h"
#include "kpt_2383ab.h"
#include "seg7_dynamic_ind.h"
#include "temp.h"
#include "err.h"
#include "buz.h"
#include "config.h"
#include "heat.h"
#include "err.h"
#include "boost_ctrl.h"
#include "app_ind.h"
#include "test.h"
#include "application.h"
/********* DEFINES **************************************************************/
/********* MACROS ***************************************************************/
/********* GLOBAL VARIABLES *****************************************************/
/********* LOCAL VARIABLES ******************************************************/
static app_state_t app_state = APP_START; //APP_STAND_BY;// /** Состояние главной state machine*/
static BOOL app_simple_timeout_flag = 0;
static BOOL app_param_adj_timer_flag = 0; /** флаг по которому при удеражнии кнопки изменяется задаваемый параметер*/
static unsigned char setting_keepwarm_temp = APP_KEEPWARM_DEFAULT_TEMP_C; /** темпереатура поддержания(подогрева) задается в диапазоне */
static unsigned char stand_by_ind_temp = APP_KEEPWARM_DEFAULT_TEMP_C; /** темпереhатура отображения в режиме stand by */
static app_sound_mode_t sound_mode = APP_SOUND_ON; /** Состояние звуковых сигналов(вкл/выкл)*/
static error_type_t app_error = ERR_NO;
static app_unpairing_flag_t unpairing_flag = APP_UNPARING_KEEP_PAIR; /** Флаг команды unpairing-а*/
static bool unpairing_event_trigger = false; /** Флаг используется для отслеживания возникновения события unpairing-а*/
static app_pairing_clear_flag_t pairing_flag = APP_MAINTAIN_PARING; /** Флаг режима pairing-а*/
static keep_warm_ctrl_type_t keep_warm_ctrl_type = KEEP_WARM_CTRL_REG; /** алгоритм поддержания температуры регулятор или разгон */
static boost_state_type_t boost_state = BOOST_FINISHED; /** состояние разгона */
static unsigned int keep_warm_time_downcounter_s = APP_KEEPWARM_MAX_TIME_S; /** счетчик времени подогрева */
static unsigned int boiling_min_time_downcounter_s = APP_BOILING_MIN_TIME_S; /** счетчик минимального времени кипения */
static unsigned int block_ind_time_downcounter_s = 0; /** счетчик времени индикации блокировки клавитуры */
static unsigned int stand_by_start_ind_time_downcounter_s = APP_STAND_BY_START_IND_TIME_S; /** счетчик времени индикации стартового состояния */
static unsigned int keep_warm_temp_set_time_downcounter_s = 0; /** счетчик времени мигания температуры подогрева при ее изменении */
static unsigned int boinig_complete_ind_time_downcounter_s = APP_BOILING_COMPLETE_IND_TIME_S; /** счетчик времени индикации стартового состояния */
static bool boiling_complete_flag = FALSE; /** Флаг завершения процесса кипечения */
static bool boiling_complete_flag_prew = FALSE; /** Флаг завершения процесса кипечения предъидущее значение*/
static bool keep_warm_boost_complete_flag = FALSE; /** Флаг завершения процесса выхода на температуру поддержания */
static bool keep_warm_boost_complete_flag_prew = FALSE; /** Флаг завершения процесса выхода на температуру поддержания предъидущее значение*/
static bool keep_warm_enable = FALSE; /** Флаг разрешения подогрева */
static app_stand_by_temp_ind_t stand_by_temp_ind_state = STAND_BY_TEMP_IND_NONE; /** Состояние отображения температуры в режиме stand_by*/
/********* FUNCTION PROTOTYPES **************************************************/
static void app_simple_timeout_timer_handler(void);
/********* FUNCTIONS IMPLEMENTATION *********************************************/
/**
* @brief Индикация режима APP_START
*
* @param none
* @return none
*
*/
static void appl_show_start(void){
app_ind_show_set_temp(188, false);
return;
}
/**
* @brief Индикация режима APP_STAND_BY
*
* @param[in] temp_ind_en - TRUE - индикация температуры разрешена, FALSE - запрещена
* @param[in] temp - температура для индикации
* @return none
*
*/
static void appl_show_stand_by( bool temp_ind_en, uint8_t temp ){
if( temp_ind_en == false )
{
app_ind_hide_set_temp();
kpt_2383ab_cmd( KPT_2383AB_CMD_SET_ICON_DATA, KPT_2383AB_DOT, 0 );
}else{
if( temp > 100 )temp = 100;
app_ind_show_set_temp(temp, false);
kpt_2383ab_cmd( KPT_2383AB_CMD_SET_ICON_DATA, KPT_2383AB_DOT, 1 );
}
return;
}
/**
* @brief Индикация режима APP_EMPTY_KETTLE
*
* @param none
* @return none
*
*/
/** Функция не используется т.к. невозможно определить пустой чайник*/
/**
* @brief Индикация режима APP_PAIRING
*
* @param none
* @return none
*
*/
static void appl_show_pairing(void){
kpt_2383ab_cmd( KPT_2383AB_CMD_SET_ICON_DATA, KPT_2383AB_DOT, 0 );
kpt_2383ab_cmd( KPT_2383AB_CMD_BACKLIGHT_CTRL, 1 );
app_ind_show_pairing();
return;
}
/**
* @brief Индикация режима APP_BOILING_PROC
*
* @param[in] keep_warm_en - подогрев разрешен
* @param[in] temp - температура уставки для индикации
* @param[in] temp_blink - температура мигает или нет
* @return none
*
*/
static void app_show_boiling(bool keep_warm_en, unsigned char temp, bool temp_blink){
kpt_2383ab_cmd( KPT_2383AB_CMD_BACKLIGHT_CTRL, 1 );
app_ind_show_set_temp(temp, temp_blink);
if( true == keep_warm_en ){
kpt_2383ab_cmd( KPT_2383AB_CMD_SET_ICON_DATA, KPT_2383AB_DOT, 1 );
}else{
kpt_2383ab_cmd( KPT_2383AB_CMD_SET_ICON_DATA, KPT_2383AB_DOT, 0 );
}
//app_ind_show_temp(temp_get_val());
return;
}
/**
* @brief Индикация режима APP_KEEPWARM_PROC
*
* @param[in] temp - температура уставки для индикации
* @param[in] temp_blink - температура мигает или нет
* @param[in] keep_warm_boost_complete - разгон поддержания закончен или нет
* @return none
*
*/
static void app_show_keepwarm(unsigned char temp, bool temp_blink, bool keep_warm_boost_complete){
kpt_2383ab_cmd( KPT_2383AB_CMD_BACKLIGHT_CTRL, 1 );
app_ind_show_set_temp(temp, temp_blink);
kpt_2383ab_cmd( KPT_2383AB_CMD_SET_ICON_DATA, KPT_2383AB_DOT, 1 );
//app_ind_show_temp(temp_get_val());
return;
}
/**
* @brief Индикация режима APP_ERROR
*
* @param[in] err - ошибка для индикации
* @return none
*
*/
static void app_show_error(error_type_t err){
kpt_2383ab_cmd( KPT_2383AB_CMD_SET_ICON_DATA, KPT_2383AB_DOT, 0 );
kpt_2383ab_cmd( KPT_2383AB_CMD_BACKLIGHT_CTRL, 1 );
app_ind_show_err(err);
}
/**
* @brief Обработчик таймера отмеряющего таймаут приложения. Используется для переходов state mashine
*
* @param none
* @return none
*
*/
static void app_simple_timeout_timer_handler(void){
app_simple_timeout_flag = 1;
return;
}
/**
* @brief Обработчик таймера отмеряющего таймаут изменения параметров
*
* @param none
* @return none
*
*/
static void app_param_adj_timer_handler(void){
app_param_adj_timer_flag = 1;
return;
}
static bool app_param_adj_timer_expired(const key_data_t* key_data){
if(key_data->key_trigger == KEY_SHORT_PRES){
timer_set( TIMER_APP_PARAM_ADJ, TIMER_MILISECOND(APP_PARAM_ADJ_SPEED_SLOW_MS) );
timer_stop( TIMER_APP_PARAM_ADJ );
app_param_adj_timer_flag = 0;
timer_reset(TIMER_APP_PARAM_ADJ);
return TRUE;
}
return FALSE;
}
/**
* @brief Обработчик секундного таймера приложения.
* Импользуется для: 1. изменения индикации внутри одного сотояния state mashine
* 2. отсчета времени поддержания
* 3. отсчета минимального времени кипечения
* @param none
* @return none
*
*/
static void app_sec_timer_handler(void){
if( TRUE == keep_warm_boost_complete_flag ){
if( 0 != keep_warm_time_downcounter_s )keep_warm_time_downcounter_s--;
}
if( TRUE == boiling_complete_flag ){
if( 0 != boinig_complete_ind_time_downcounter_s )boinig_complete_ind_time_downcounter_s--;
}
if( 0 != boiling_min_time_downcounter_s )boiling_min_time_downcounter_s--;
if( 0 != block_ind_time_downcounter_s )block_ind_time_downcounter_s--;
if( 0 != stand_by_start_ind_time_downcounter_s )stand_by_start_ind_time_downcounter_s--;
if( 0 != keep_warm_temp_set_time_downcounter_s )keep_warm_temp_set_time_downcounter_s--;
return;
}
/**
* @brief Функция сбрасывает секундный таймер
*
* @param none
* @return none
*
*/
static void app_sec_timer_reset(void){
timer_reset( TIMER_APP_SEC_TIMER );
}
/**
* @brief Вычисляет значение температуры после вычитания из нее значения step
*
* @param[in] temp - исходная температура
* @param[in] min_val - минимальное значение температуры
* @param[in] max_val - максимальное значение температуры
* @param[in] step - шаг изменения температуры
* @return - вычисленное значение температуры
*
*/
static unsigned char app_sub_temp( unsigned char temp, unsigned char min_val, unsigned char max_val, unsigned char step ){
if( temp%step != 0 ){
if( temp < min_val + step ){
temp = min_val;
}else{
temp -= temp%step; //округление до меньшего деленного на step без остатка
}
}else{
if( temp < min_val + step )
{
temp = min_val;
}else{
temp -= step;
}
}
if( temp > max_val )temp = max_val;
return temp;
}
/**
* @brief Вычисляет значение температуры после сложения ее со значением step
*
* @param[in] temp - исходная температура
* @param[in] min_val - минимальное значение температуры
* @param[in] max_val - максимальное значение температуры
* @param[in] step - шаг изменения температуры
* @return - вычисленное значение температуры
*
*/
static unsigned char app_add_temp( unsigned char temp, unsigned char min_val, unsigned char max_val, unsigned char step ){
if( temp%step != 0 ){
if( temp + step > max_val ){
temp = max_val;
}else{
temp += (step - temp%step); //округление до большего деленного на step без остатка
}
}else{
if( temp + step > max_val ){
temp = max_val;
}else{
temp += step;
}
}
if( temp < min_val )temp = min_val;
return temp;
}
/**
* @brief Простой П-регулятор
*
* @param[in] Y - значение регулируемой величины
* @param[in] U - уставка
* @param[in] KV - коэффициент усиления
* @return - выход регулятора
*
*/
static unsigned int simple_reg( unsigned char Y, unsigned char U, unsigned char 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 Функция перезапускает таймер отсчитывающий таймауты переходов между состояниями state machine
*
* @param[in] timeout_s - установленный таймаут в сек
* @return none
*
*/
static void app_timeout_timers_restart(U8 timeout_s){
app_simple_timeout_flag = 0;
timer_set(TIMER_APP_SIMPLE_TIMEOUT, TIMER_SECOND(timeout_s));
timer_reset(TIMER_APP_SIMPLE_TIMEOUT);
}
/**
* @brief Определяет какой алгоритм использовать для поддержания температуры - разгон или поддаржание
*
* @param[in] temp_cur - текущее значение температуры
* @param[in] temp_set - температура для поддержания
* @return - алгоритм разгон/поддержание
*
*/
static keep_warm_ctrl_type_t keep_warm_get_ctrl_type( unsigned char temp_cur, unsigned char temp_set ){
if( temp_cur + APP_TEMP_DIFFERENCE_KEEP_WARM_BOOST_START_C >= temp_set ){
return KEEP_WARM_CTRL_REG;
}else{
return KEEP_WARM_CTRL_BOOST;
}
}
/**
* @brief Функция инициализирует новой состояние state machine.
* Инициализируеются переменные и таймеры инициализация которых не зависит от того из какого состояния был переход в текущее состояние.
* Инициализация переменных, зависящих от предъидущего состояния, производится в самой state machine или функциях изменяемых состояние state machine.
*
* @param[in] state - новое состояние state machine
* @return none
*
*/
static void app_new_state_init( app_state_t state ){
static app_state_t state_prew = APP_STAND_BY;
if( state == state_prew )return;
switch( state ){
case APP_START:
{
break;
}
case APP_STAND_BY:
{
stand_by_temp_ind_state = STAND_BY_TEMP_IND_NONE;
block_ind_time_downcounter_s = 0;
keep_warm_temp_set_time_downcounter_s = 0;
stand_by_start_ind_time_downcounter_s = APP_STAND_BY_START_IND_TIME_S;
ind_reset_dynamic_ind_timer();
app_sec_timer_reset();
break;
}
case APP_PAIRING:
{
app_timeout_timers_restart(APP_PAIRING_TIMEOUT_S);
break;
}
case APP_BOILING_PROC:
{
ind_reset_dynamic_ind_timer();
boiling_complete_flag = FALSE;
boiling_complete_flag_prew = FALSE;
keep_warm_temp_set_time_downcounter_s = 0;
boiling_min_time_downcounter_s = APP_BOILING_MIN_TIME_S;
boinig_complete_ind_time_downcounter_s = APP_BOILING_COMPLETE_IND_TIME_S;
break;
}
case APP_KEEPWARM_PROC:
{
ind_reset_dynamic_ind_timer();
app_sec_timer_reset(); //сброс таймера для отсчета времени подогрева
keep_warm_enable = TRUE; //флаг разрешения побогрева
keep_warm_boost_complete_flag = FALSE; //флаг зашершения выхода на заданную температуру
keep_warm_boost_complete_flag_prew = FALSE; //предъидущее значение флага зашершения выхода на заданную температуру(используется для подачи звукового сигнала)
keep_warm_time_downcounter_s = APP_KEEPWARM_MAX_TIME_S; //время до окончания режима поддеражания
if( setting_keepwarm_temp > APP_KEEPWARM_MAX_TEMP_C )
{
setting_keepwarm_temp = APP_KEEPWARM_MAX_TEMP_C;
}
if( setting_keepwarm_temp < APP_KEEPWARM_MIN_TEMP_C )
{
setting_keepwarm_temp = APP_KEEPWARM_MIN_TEMP_C;
}
keep_warm_ctrl_type = keep_warm_get_ctrl_type( temp_get_val(), setting_keepwarm_temp );
boost_proc_init();
heating_force_off();
break;
}
case APP_ERROR:
{
break;
}
case APP_TEST:
{
app_timeout_timers_restart(APP_TEST_TIMEOUT_S);
test_init();
break;
}
default:
{
break;
}
}
state_prew = state;
}
/**
* @brief Инициализания applicatino
*
* @param none
* @return none
*
*/
void application_init(void){
app_ind_init();
timer_init(TIMER_APP_PARAM_ADJ, 0, (callback_t)app_param_adj_timer_handler );
timer_stop(TIMER_APP_PARAM_ADJ);
timer_init(TIMER_APP_SIMPLE_TIMEOUT, 0, (callback_t)app_simple_timeout_timer_handler );
timer_start(TIMER_APP_SIMPLE_TIMEOUT);
timer_init(TIMER_APP_SEC_TIMER, TIMER_SECOND(1), (callback_t)app_sec_timer_handler );
timer_start(TIMER_APP_SEC_TIMER);
app_timeout_timers_restart(APP_START_TIMEOUT_S);
return;
}
/**
* @brief application state machine
*
* @param none
* @return none
*
*/
void application_proc(void){
static keyboard_data_t app_keyb_data;
keybord_data_read( &app_keyb_data );
app_new_state_init( app_state );
switch(app_state)
{
case APP_START:
{
//transition
if( app_simple_timeout_flag ){
app_state = APP_STAND_BY;
}
if( ( app_keyb_data.keys_value.plus_key.state == KEY_CONDITION_PRESSED )
&&( app_keyb_data.keys_value.pwr_key.state == KEY_CONDITION_PRESSED ) )
{
app_state = APP_TEST;
break;
}
//indication
appl_show_start();
break;
}
case APP_STAND_BY:
{
//indication
if( 0 == keep_warm_temp_set_time_downcounter_s ){
stand_by_temp_ind_state = STAND_BY_TEMP_IND_NONE;
appl_show_stand_by( false, 0 );
}else{
appl_show_stand_by( true, stand_by_ind_temp );
}
//app_show_boiling(FALSE, temp_get_val(), TRUE);
//work
heating_process_off();
//controll
if( app_keyb_data.keys_value.minus_key.key_timer > KEY_POLLING_TIMER_S( APP_UNPAIRING_ENTER_TIME_S ) ){
if( unpairing_event_trigger == false ){
//tckb
unpairing_flag = APP_UNPARING_CLEAR_PAIR;
if(APP_SOUND_ON == sound_mode ){
add_beep(APP_UNPAIR_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
unpairing_event_trigger = true;
}else{
unpairing_flag = APP_UNPARING_KEEP_PAIR;
unpairing_event_trigger = false;
}
if( app_keyb_data.keys_value.plus_key.state == KEY_CONDITION_PRESSED )
{
if( app_param_adj_timer_expired(&app_keyb_data.keys_value.plus_key) )
{
if( stand_by_temp_ind_state == STAND_BY_TEMP_IND_NONE )
{
stand_by_ind_temp = temp_get_val();
stand_by_temp_ind_state = STAND_BY_TEMP_IND_CUR_TEMP;
if( KEY_SHORT_PRES == app_keyb_data.keys_value.plus_key.key_trigger ){
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
keep_warm_temp_set_time_downcounter_s = APP_KEEP_WARM_SET_TIME_S;
app_timeout_timers_restart(APP_TEMP_PRESET_TIMEOUT_S);
}else if( stand_by_temp_ind_state == STAND_BY_TEMP_IND_CUR_TEMP ){
stand_by_temp_ind_state = STAND_BY_TEMP_IND_SET_TEMP;
stand_by_ind_temp = app_add_temp( stand_by_ind_temp, APP_KEEPWARM_MIN_TEMP_C, APP_KEEPWARM_MAX_TEMP_C, APP_TEMP_ADJ_STEP_C );
keep_warm_temp_set_time_downcounter_s = APP_KEEP_WARM_SET_TIME_S;
app_timeout_timers_restart(APP_TEMP_PRESET_TIMEOUT_S);
if( KEY_SHORT_PRES == app_keyb_data.keys_value.plus_key.key_trigger ){
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
}else{
stand_by_ind_temp = app_add_temp( stand_by_ind_temp, APP_KEEPWARM_MIN_TEMP_C, APP_KEEPWARM_MAX_TEMP_C, APP_TEMP_ADJ_STEP_C );
keep_warm_temp_set_time_downcounter_s = APP_KEEP_WARM_SET_TIME_S;
app_timeout_timers_restart(APP_TEMP_PRESET_TIMEOUT_S);
if( KEY_SHORT_PRES == app_keyb_data.keys_value.plus_key.key_trigger ){
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
}
}
}
if( app_keyb_data.keys_value.minus_key.state == KEY_CONDITION_PRESSED )
{
if( app_param_adj_timer_expired(&app_keyb_data.keys_value.minus_key) )
{
if( stand_by_temp_ind_state == STAND_BY_TEMP_IND_NONE )
{
stand_by_ind_temp = temp_get_val();
stand_by_temp_ind_state = STAND_BY_TEMP_IND_CUR_TEMP;
if( KEY_SHORT_PRES == app_keyb_data.keys_value.minus_key.key_trigger ){
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
keep_warm_temp_set_time_downcounter_s = APP_KEEP_WARM_SET_TIME_S;
app_timeout_timers_restart(APP_TEMP_PRESET_TIMEOUT_S);
}else if( stand_by_temp_ind_state == STAND_BY_TEMP_IND_CUR_TEMP ){
stand_by_temp_ind_state = STAND_BY_TEMP_IND_SET_TEMP;
stand_by_ind_temp = app_sub_temp( stand_by_ind_temp, APP_KEEPWARM_MIN_TEMP_C, APP_KEEPWARM_MAX_TEMP_C, APP_TEMP_ADJ_STEP_C );
if( KEY_SHORT_PRES == app_keyb_data.keys_value.minus_key.key_trigger ){
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
keep_warm_temp_set_time_downcounter_s = APP_KEEP_WARM_SET_TIME_S;
app_timeout_timers_restart(APP_TEMP_PRESET_TIMEOUT_S);
}else{
stand_by_ind_temp = app_sub_temp( stand_by_ind_temp, APP_KEEPWARM_MIN_TEMP_C, APP_KEEPWARM_MAX_TEMP_C, APP_TEMP_ADJ_STEP_C );
if( KEY_SHORT_PRES == app_keyb_data.keys_value.minus_key.key_trigger ){
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
keep_warm_temp_set_time_downcounter_s = APP_KEEP_WARM_SET_TIME_S;
app_timeout_timers_restart(APP_TEMP_PRESET_TIMEOUT_S);
}
}
}
//transition
if( app_keyb_data.keys_value.plus_key.key_timer > KEY_POLLING_TIMER_S( APP_PAIRING_ENTER_TIME_S ) )
{
app_state = APP_PAIRING;
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_MULTI);
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_MULTI);
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_MULTI);
}
}
if( KEY_SHORT_PRES == app_keyb_data.keys_value.pwr_key.key_trigger ){
keep_warm_enable = FALSE;
app_state = APP_BOILING_PROC;
setting_keepwarm_temp = APP_KEEPWARM_DEFAULT_TEMP_C;
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
if( ( 0 != keep_warm_temp_set_time_downcounter_s )
&& ( stand_by_temp_ind_state == STAND_BY_TEMP_IND_SET_TEMP ) )
{
if( KEY_SHORT_PRES == app_keyb_data.keys_value.preheat_key.key_trigger ){
setting_keepwarm_temp = stand_by_ind_temp;
app_state = APP_KEEPWARM_PROC;
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
}
break;
}
/** Состояние не используется т.к. невозможно определить пустой чайник*/
/*case APP_EMPTY_KETTLE:
{
//indication
appl_show_empty_kettle();
//work
heating_process_off();
//transition
if( temp_get_val() < TEMP_KETTLE_NOT_EMPTY_C ){
app_state = APP_STAND_BY;
}
if( KEY_SHORT_PRES == app_keyb_data.keys_value.pwr_key.key_trigger ){
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
app_state = APP_STAND_BY;
}
break;
}*/
case APP_PAIRING:
{
static bool paring_timeout_ind_flag = 0;
appl_show_pairing();
if( pairing_flag == APP_CLEAR_PARING ){
if( paring_timeout_ind_flag == 0 ){
paring_timeout_ind_flag = 1;
app_timeout_timers_restart(APP_PAIRING_IND_TIMEOUT_S);
}
}
//work
heating_process_off();
//waiting for R4S reset unpairing_flag
if( app_simple_timeout_flag ){
pairing_flag = APP_MAINTAIN_PARING;
paring_timeout_ind_flag = 0;
app_state = APP_STAND_BY;
break;
}
break;
}
case APP_BOILING_PROC:
{
//indication
if( ( 0 != keep_warm_temp_set_time_downcounter_s )
&&( TRUE == keep_warm_enable ) )
{
if( (app_keyb_data.keys_value.plus_key.state == KEY_CONDITION_PRESSED) || (app_keyb_data.keys_value.minus_key.state == KEY_CONDITION_PRESSED) )
{
app_show_boiling(keep_warm_enable, setting_keepwarm_temp, FALSE);
}else{
app_show_boiling(keep_warm_enable, setting_keepwarm_temp, TRUE);
}
}else{
app_show_boiling(keep_warm_enable, APP_HEATING_TEMP_C, TRUE);
}
//work
if( ( temp_is_water_boil() )
&&( 0 == boiling_min_time_downcounter_s ))
{
boiling_complete_flag = TRUE;
}
if( ( boiling_complete_flag == TRUE )
&& ( boiling_complete_flag_prew == FALSE ) )
{
//звуковая индикация завершения кипечения
if( APP_SOUND_ON == sound_mode )
{
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_MULTI);
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_MULTI);
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_MULTI);
}
}
boiling_complete_flag_prew = boiling_complete_flag;
if( boiling_complete_flag == TRUE ){
heating_force_off();
}else{
heating_force_on(HEATER_MAX_PWM_DUTY_CICLE);
}
//controll
if( TRUE == keep_warm_enable )
{
if( app_keyb_data.keys_value.plus_key.state == KEY_CONDITION_PRESSED )
{
if( app_param_adj_timer_expired(&app_keyb_data.keys_value.plus_key) )
{
//если истек таймаут изменения параметра
if( setting_keepwarm_temp != app_add_temp( setting_keepwarm_temp, APP_KEEPWARM_MIN_TEMP_C, APP_KEEPWARM_MAX_TEMP_C, APP_TEMP_ADJ_STEP_C ) )
{
//если уставка изменилась
setting_keepwarm_temp = app_add_temp( setting_keepwarm_temp, APP_KEEPWARM_MIN_TEMP_C, APP_KEEPWARM_MAX_TEMP_C, APP_TEMP_ADJ_STEP_C );
if( KEY_SHORT_PRES == app_keyb_data.keys_value.plus_key.key_trigger ){
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
keep_warm_temp_set_time_downcounter_s = APP_KEEP_WARM_SET_TIME_S;
app_timeout_timers_restart(APP_TEMP_PRESET_TIMEOUT_S);
}
}
}
if( app_keyb_data.keys_value.minus_key.state == KEY_CONDITION_PRESSED )
{
if( app_param_adj_timer_expired(&app_keyb_data.keys_value.minus_key) )
{
//если истек таймаут изменения параметра
if( setting_keepwarm_temp != app_sub_temp( setting_keepwarm_temp, APP_KEEPWARM_MIN_TEMP_C, APP_KEEPWARM_MAX_TEMP_C, APP_TEMP_ADJ_STEP_C ) )
{
//если уставка изменилась
setting_keepwarm_temp = app_sub_temp( setting_keepwarm_temp, APP_KEEPWARM_MIN_TEMP_C, APP_KEEPWARM_MAX_TEMP_C, APP_TEMP_ADJ_STEP_C );
if( KEY_SHORT_PRES == app_keyb_data.keys_value.minus_key.key_trigger ){
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
keep_warm_temp_set_time_downcounter_s = APP_KEEP_WARM_SET_TIME_S;
app_timeout_timers_restart(APP_TEMP_PRESET_TIMEOUT_S);
}
}
}
}
if( KEY_SHORT_PRES == app_keyb_data.keys_value.preheat_key.key_trigger ){
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
if( TRUE == keep_warm_enable ){
keep_warm_enable = FALSE;
keep_warm_temp_set_time_downcounter_s = 0;
}else{
keep_warm_enable = TRUE;
keep_warm_temp_set_time_downcounter_s = APP_KEEP_WARM_SET_TIME_S;
}
}
//transition
if( KEY_SHORT_PRES == app_keyb_data.keys_value.pwr_key.key_trigger ){
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
if( TRUE == keep_warm_enable ){
app_state = APP_KEEPWARM_PROC;
}else{
app_state = APP_STAND_BY;
}
}
/** Состояние не используется т.к. невозможно определить пустой чайник*/
/*if( temp_is_empty_kettle() ){
heating_force_off();
app_state = APP_EMPTY_KETTLE;
}*/
if( ( boiling_complete_flag == TRUE )
&& ( 0 == boinig_complete_ind_time_downcounter_s ) )
{
if( TRUE == keep_warm_enable ){
app_state = APP_KEEPWARM_PROC;
}else{
app_state = APP_STAND_BY;
}
}
break;
}
case APP_KEEPWARM_PROC:
{
//indication
if( keep_warm_boost_complete_flag )
{
app_show_keepwarm(setting_keepwarm_temp, FALSE, keep_warm_boost_complete_flag);
}else{
app_show_keepwarm(setting_keepwarm_temp, TRUE, keep_warm_boost_complete_flag);
}
//work
if( KEEP_WARM_CTRL_BOOST == keep_warm_ctrl_type ){
boost_state = boost_proc( temp_get_float_val(), (float)setting_keepwarm_temp );
if( BOOST_FINISHED == boost_state ){
keep_warm_ctrl_type = KEEP_WARM_CTRL_REG;
}
}else{
keep_warm_ctrl_type = keep_warm_get_ctrl_type( temp_get_val(), setting_keepwarm_temp );
if( KEEP_WARM_CTRL_BOOST == keep_warm_ctrl_type ){
//при переходе из регулятора в разгон инициализируем алгоритм заново
boost_proc_init();
}else{
heating_process_on( simple_reg( temp_get_val() , setting_keepwarm_temp, 2 ) );
}
}
if( fabs( setting_keepwarm_temp - temp_get_val() ) < APP_KEEPWARM_TEMP_DIFFERENCE_BOOST_IS_OVER_C ){
keep_warm_boost_complete_flag = TRUE;
}
if( ( FALSE == keep_warm_boost_complete_flag_prew )
&&( TRUE == keep_warm_boost_complete_flag ) )
{
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_MULTI);
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_MULTI);
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_MULTI);
}
app_sec_timer_reset();
}
keep_warm_boost_complete_flag_prew = keep_warm_boost_complete_flag;
//controll
if( app_keyb_data.keys_value.plus_key.state == KEY_CONDITION_PRESSED )
{
if( app_param_adj_timer_expired(&app_keyb_data.keys_value.plus_key) )
{
//если истек таймаут изменения параметра
if( setting_keepwarm_temp != app_add_temp( setting_keepwarm_temp, APP_KEEPWARM_MIN_TEMP_C, APP_KEEPWARM_MAX_TEMP_C, APP_TEMP_ADJ_STEP_C ) )
{
//если уставка изменилась
setting_keepwarm_temp = app_add_temp( setting_keepwarm_temp, APP_KEEPWARM_MIN_TEMP_C, APP_KEEPWARM_MAX_TEMP_C, APP_TEMP_ADJ_STEP_C );
keep_warm_ctrl_type = keep_warm_get_ctrl_type( temp_get_float_val(), (float)setting_keepwarm_temp );
if( keep_warm_ctrl_type == KEEP_WARM_CTRL_BOOST ){
//если остались в алгоритме разгона обновить уставку
boost_proc_setting_update( temp_get_val(), setting_keepwarm_temp );
}
keep_warm_boost_complete_flag = FALSE;
keep_warm_boost_complete_flag_prew = FALSE;
keep_warm_time_downcounter_s = APP_KEEPWARM_MAX_TIME_S;
if( KEY_SHORT_PRES == app_keyb_data.keys_value.plus_key.key_trigger ){
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
}
}
}
if( app_keyb_data.keys_value.minus_key.state == KEY_CONDITION_PRESSED )
{
if( app_param_adj_timer_expired(&app_keyb_data.keys_value.minus_key) )
{
//если истек таймаут изменения параметра
if( setting_keepwarm_temp != app_sub_temp( setting_keepwarm_temp, APP_KEEPWARM_MIN_TEMP_C, APP_KEEPWARM_MAX_TEMP_C, APP_TEMP_ADJ_STEP_C ) )
{
//если уставка изменилась
setting_keepwarm_temp = app_sub_temp( setting_keepwarm_temp, APP_KEEPWARM_MIN_TEMP_C, APP_KEEPWARM_MAX_TEMP_C, APP_TEMP_ADJ_STEP_C );
keep_warm_ctrl_type = keep_warm_get_ctrl_type( temp_get_float_val(), (float)setting_keepwarm_temp );
if( keep_warm_ctrl_type == KEEP_WARM_CTRL_BOOST ){
//если остались в алгоритме разгона обновить уставку
boost_proc_setting_update( temp_get_val(), setting_keepwarm_temp );
}
keep_warm_boost_complete_flag = FALSE;
keep_warm_boost_complete_flag_prew = FALSE;
keep_warm_time_downcounter_s = APP_KEEPWARM_MAX_TIME_S;
if( KEY_SHORT_PRES == app_keyb_data.keys_value.minus_key.key_trigger )
{
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
}
}
}
//transition
if( KEY_SHORT_PRES == app_keyb_data.keys_value.pwr_key.key_trigger ){
heating_force_off(); //если выходим из режима обязательно выключить нагреватель
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
app_state = APP_BOILING_PROC;
}
if( KEY_SHORT_PRES == app_keyb_data.keys_value.preheat_key.key_trigger ){
heating_force_off(); //если выходим из режима обязательно выключить нагреватель
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
app_state = APP_STAND_BY;
}
if( 0 == keep_warm_time_downcounter_s ){
app_state = APP_STAND_BY;
if( APP_SOUND_ON == sound_mode ){
add_beep(APP_SHORT_BEEP_MS, APP_BEEP_PAUSE_MS, BEEP_SINGLE);
}
}
break;
}
case APP_ERROR:
{
//indication
app_show_error(app_error);
//work
heating_process_off();
//transition
//no transition
break;
}
case APP_TEST:
{
uint8_t test_finished;
test_finished = test_proc();
if( ( test_finished == 1 )
|| ( app_simple_timeout_flag ) )
{
app_state = APP_STAND_BY;
}
break;
}
default:
{
app_state = APP_STAND_BY;
break;
}
}
}
/*
* @brief Возвращает версия ПО
*
* @param none
* @return версия ПО
*
*/
unsigned int Appl_GetVersion(void){
return SOFTWARE_VERSION;
}
/*
* @brief Возвращает текущую температуру
*
* @param none
* @return текущая температура
*
*/
unsigned char Appl_GetTemp( void ){
unsigned char temp;
switch( app_state )
{
case APP_BOILING_PROC:
{
/** Если находимся в режиме кипечения отображаем текущую температуру или 100 когда процесс кипечения завершен.
*/
/*if( boiling_complete_flag == true )
{
return 100;
}else{*/
temp = temp_get_val();
//}
break;
}
case APP_KEEPWARM_PROC:
{
/** Если находимся в режиме подогрева отображаем текущую температуру или температуру уставки если выход на заданную температуру завершен.
*/
if( keep_warm_boost_complete_flag == true )
{
temp = setting_keepwarm_temp;
}else{
temp = temp_get_val();
}
break;
}
default :
{
temp = temp_get_val();
break;
}
}
if( temp > 100 )temp = 100;
return temp;
}
/*
* @brief Возвращает температуру уставки поддержания температуры
*
* @param none
* @return уставка поддержания температуры
*
*/
unsigned char Appl_GetSetTemp(void){
if( keep_warm_enable == true )
{
//если подогрев разрешен возвращаем уставку
return setting_keepwarm_temp;
}else{
//если запрещен возвращам 0 - признак запрета подогрева
return 0;
}
}
/*
* @brief Возвращает время до окончания поддержания температуры
*
* @param none
* @return время до окончания поддержания температуры
*
*/
unsigned int Appl_GetTime(void){
return (keep_warm_time_downcounter_s/60); //приводим к минутам
}
/*
* @brief Возвращает ошибку
*
* @param none
* @return время ошибку
*
*/
unsigned char Appl_GetError(void){
switch( app_error ){
case ERR_NO:
return APPL_NO_ERR;
case ERR_OVERHEAT:
return APPL_OVERHEAT_ERR;
default:
return APPL_NO_ERR;
}
}
/*
* @brief Устанавливает температуру поддержания
*
* @param[in] температура для установки
* @return TRUE - температура установлена. FALSE - температура не установлена
*
*/
bool Appl_SetTemp(uint8_t temp){
if( APP_KEEPWARM_PROC == app_state )
{
if( ( temp <= APP_KEEPWARM_MAX_TEMP_C )
&&( temp >= APP_KEEPWARM_MIN_TEMP_C ))
{
keep_warm_time_downcounter_s = APP_KEEPWARM_MAX_TIME_S;
keep_warm_boost_complete_flag = false;
keep_warm_boost_complete_flag_prew = false;
setting_keepwarm_temp = temp;
return true;
}else{
if( 0 == temp )
{
keep_warm_enable = FALSE;
app_state = APP_STAND_BY;
return true;
}
}
}
if( APP_BOILING_PROC == app_state )
{
if( ( temp <= APP_KEEPWARM_MAX_TEMP_C )
&&( temp >= APP_KEEPWARM_MIN_TEMP_C ))
{
setting_keepwarm_temp = temp;
keep_warm_enable = TRUE;
return true;
}else{
if( 0 == temp )
{
keep_warm_enable = FALSE;
return true;
}
}
}
return false;
}
/*
* @brief Возвращает выполняемую программу
*
* @param none
* @return выполняемая программа
*/
unsigned char Appl_GetProgram(void){
if( app_state == APP_KEEPWARM_PROC )
{
return APPL_KEEPWARM_PROG;
}else{
return APPL_BOILING_PROG;
}
}
/*
* @brief Устанавливает программу для выполнения. Переводит state machine в соответсвуещее состояние
*
* @param[in] prog - программа для выполнения
* @return TRUE - программа установлена. FALSE - программа не установлена
*/
bool Appl_SetProgram(unsigned char prog){
if( app_state == APP_STAND_BY ){
//запуск программы из STAND BY
switch(prog)
{
case APPL_BOILING_PROG:
{
setting_keepwarm_temp = APP_KEEPWARM_DEFAULT_TEMP_C;
keep_warm_enable = FALSE;
app_state = APP_BOILING_PROC;
return true;
}
case APPL_KEEPWARM_PROG:
{
setting_keepwarm_temp = APP_KEEPWARM_DEFAULT_TEMP_C;
app_state = APP_KEEPWARM_PROC;
return true;
}
default:
{
return false;
}
}
}
if( app_state == APP_KEEPWARM_PROC ){
//запуск программы из APP_KEEPWARM_PROC
if( APPL_BOILING_PROG == prog )
{
app_state = APP_BOILING_PROC;
return true;
}
if( APPL_KEEPWARM_PROG == prog )
{
return true;
}
}
if( app_state == APP_BOILING_PROC ){
//запуск программы из APP_KEEPWARM_PROC
if( APPL_KEEPWARM_PROG == prog )
{
app_state = APP_KEEPWARM_PROC;
return true;
}
if( APPL_BOILING_PROG == prog )
{
keep_warm_enable = TRUE;
return true;
}
}
return false;
}
/*
* @brief Останавливает выполняемую программу.
*
* @param none
* @return TRUE - программа остановлена. FALSE - программа не остановлена
*/
bool Appl_Stop(void){
if( ( app_state == APP_BOILING_PROC )
|| ( app_state == APP_KEEPWARM_PROC ) )
{
app_state = APP_STAND_BY;
return true;
}
return false;
}
/*
* @brief Возвращает текущее состояние устройства
*
* @param none
* @return текущее состояние устройства
*/
unsigned char Appl_GetState(void){
switch( app_state ){
case APP_STAND_BY:
case APP_START:
return APPL_BEGIN_STATE;
case APP_PAIRING:
return APPL_PAIRING_STATE;
case APP_BOILING_PROC:
case APP_KEEPWARM_PROC:
return APPL_PROGRAM_STATE;
case APP_ERROR:
return APPL_ERROR_STATE;
default:
return 0xFF;
}
}
/*
* @brief Возвращает текущее состояние поддержания
*
* @param none
* @return TRUE - поддержание включено. FALSE - поддержание вsключено.
*/
bool Appl_GetPreheat(void){
return keep_warm_enable;
}
/*
* @brief Возвращает состояние запроса от пользователя на unparing всех устройств
*
* @param none
* @return TRUE - запрос на unparing всех устройств. FALSE - нет запроса на unparing всех устройств
*/
bool Appl_IsUnpairing(void){
return unpairing_flag;
}
/*
* @brief Обработчик ошибок. Переводити state mashine в состояние APP_ERROR
*
* @param[in] Err - ошибка
* @return none
*/
void Appl_ErrorHandler(error_type_t Err){
app_error = Err;
app_state = APP_ERROR;
return;
}
/*
* @brief Запрос от R4S на выход из режима paring
*
* @param none
* @return none
*/
void Appl_ClrPairing(void){
pairing_flag = APP_CLEAR_PARING;
return;
}
/*
* @brief Возвращает состояние блокировки кнопок
*
* @param none
* @return состояние блокировки
*/
bool Appl_GetBlock( void ){
return 0;
}
/*
* @brief Устанавливает состояние блокировки кнопок
*
* @param[in] block - состояние блокировки
* @return TRUE - состояние блокировки установленно. FALSE - не установленно.
*/
bool Appl_SetBlock( bool block ){
/*if( APP_STAND_BY != app_state )return false;
app_panel_block_flag = block;
if( false == app_panel_block_flag ){
block_ind_time_downcounter_s = 0;
}*/
return false;
}