Программный модуль для обогревателя RFH-C4522S. Версия 2.15



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

Фрагмент исходного кода
/**
 *    	@file           application.c
 *   	@brief        application.c реализует функционал устройства RFH-C4522S
*
 *  	@internal
*	Revision:  	v2.15
 *	Compiler:  	armcc

 */
 
/********* HEADER FILE INCLUDES *************************************************/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "debug_info.h"

#include "nrf.h"
#include "nrf_delay.h"
#include "nrf_soc.h"
#include "nrf_gpio.h"
#include "app_timer.h"
#include "app_error.h"

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

#include "com_slave.h"
#include "com_extansion.h"

#include "Application.h"
#include "Application_api.h"
#include "app_ind.h"
#include "adv_data.h"

#include "buz_ac.h"
#include "timers.h"
#include "timers_config.h"
#include "keyb.h"
#include "keyb_config.h"
#include "config.h"
#include "temperature_service.h"
#include "evcal.h"
#include "calendar.h"
#include "stderrnum.h"


/********* DEFINES **************************************************************/
/********* MACROS ***************************************************************/
#define APP_ANTI_FROST_TEMP     7
#define APP_MAX_TEMP            35
#define APP_OVERHEAT_TEMP       38

#define HOUR_TO_MINUTES(x) ((x)*60)
#define MINUTES_TO_HOUR(x) ((x)/60)
/********* VARIABLES *****************************************************/
static keyb_data_t                 app_keyboard_data[KEYB_BUTTON_COUNT];   /* данные кнопок*/

static app_flags_t                 app_flags;                              /* флаги application*/
static app_heater_t                app_heater;                             /* флаги состояния нагревателя*/

static temp_serv_data_t            app_temp_serv_data = {                  /* данные температурного сервиса*/
                                                          .event_lower = TEMP_NO_EVENT, 
                                                          .event_higher = TEMP_NO_EVENT, 
                                                          .state = TEMP_STATE_UNKNOWN
                                                        };
static volatile uint16_t           app_sw_off_time_left_m = 0;              /* текущее время */
                                                        
static uint8_t                     app_target_temp = APP_MAX_TEMP;          /* целевая температура */
                                                        
static app_timer_id_t	           app_iteration_timer_id;		/* таймер Итерации */
static volatile bool               appIterStepAllowFl = true;
/********* FUNCTION PROTOTYPES **************************************************/
static void app_heat_off(void);
static void app_heat_low(void);
static void app_heat_turbo(void);
static void app_heat_fan(void);
static void app_heat_low_enable(void);
static void app_heat_turbo_enable(void);
static void app_heat_disable(void);

static void stateStandBy(void);
static void stateHeat(app_prog_t app_prog);
                                                        
static void app_timeouts_timer_start(uint32_t timeout);
static void app_timeouts_timer_stop(void);
static void app_cool_timer_start(void);
static void app_cool_timer_stop(void);
static void app_sw_off_timer_start(void);
static void app_sw_off_timer_stop(void);

static void app_state_change(app_state_t new_state);                                                                 
static void stateTest(void);                                                                 
static void stateStandBy(void);
 
/********* FUNCTIONS IMPLEMENTATION *********************************************/

static void app_iteration_timer_handler(void* p_context)
{
    appIterStepAllowFl = true;
}
/**@brief 	Обработчик таймера таймаута.
 *
 * @param	none
 *
 * @return 	none
 */
static void app_timeouts_handler( void )
{
    APP_ERROR_CHECK(timer_stop(TIMERS_APP_TIMEOUTS));
	switch(app_heater.app_state)
	{
		case APP_PAIRING:
		case APP_FW_UPDATE:
		{
            stateStandBy();
            break;
		}
		default:
			break;
	}
	return;
}

/**@brief 	Обработчик таймера охлаждения нагревателя.
 *
 * @param	none
 *
 * @return 	none
 */
static void app_cool_timeout_handler( void )
{
    APP_ERROR_CHECK(timer_stop(TIMERS_COOL_TIMEOUT));
    
    switch(app_heater.app_state)
	{
        case APP_HEAT:
        {
            switch(app_heater.app_prog)
            {
                case PROG_HEAT_FAN:
                {
                    app_heater.app_heater_enable.flags.cooling_en = 0;
                    break;
                }
                default:
                    break;
            }
            break;
        }
        case APP_STAND_BY:
        case APP_STAND_BY_AUTO:
        case APP_STAND_BY_AF:
        case APP_FW_UPDATE:
        case APP_PAIRING:
        case APP_OVER_HEAT:
        {
            app_heater.app_heater_enable.flags.cooling_en = 0;
            app_heat_off(); //выключаем обогрев и вентилятор
            break;
        }
		default:
			break;
	}
	return;
}

/**@brief 	Обработчик таймера отключения нагревателя через заданный промежуток времени.
 *
 * @param	none
 *
 * @return 	none
 */
static void app_sw_off_timeout_handler( void )
{ 
    if(--app_sw_off_time_left_m == 0)
    {
        stateStandBy();
    }
    else
    {
        app_sw_off_timer_start();
    }
	return;
}

/**
 *  @brief  Функция вызывается при срабатывании часов (1 сек)
 *
 *  @param  none
 *  @return none
 *
 */
static void calendar_timer_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;
	uint8_t action_code = p_data->array[1];
    
    if((app_heater.app_heater_state.bits & BIT_APP_LOCK ) == 0)
    {
        switch(action_code)
        {
            case AC_EXTANSION_START_CMD:
            {
                expan_req_start_t *p_in_exp_pckt = (expan_req_start_t *) &p_data->array[2];
                if((p_in_exp_pckt->mask & 0x1) != 0){
                    app_set_sw_on();
                }
                break;
            }
            case AC_EXTANSION_STOP_CMD:
            {
                expan_req_stop_t *p_in_exp_pckt = (expan_req_stop_t *) &p_data->array[2];
                if((p_in_exp_pckt->mask & 0x1) != 0){
                    app_set_sw_off();
                }
                break;
            }
            default:
                break;
        }
    }
}

/**@brief 	Функция инициализации
 *
 * @param	none
 *
 * @return 	none
 */
void application_init(void)
{
    NRF_GPIO->PIN_CNF[MAIN_HEAT_L] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
                                            |	(GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos)
                                            |	(GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
                                            |	(GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
                                            |	(GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
    
    NRF_GPIO->PIN_CNF[MAIN_HEAT_H] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
                                            | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
                                            | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
                                            | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
                                            | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
    
    NRF_GPIO->PIN_CNF[MOTO] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
                                            | (GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos)
                                            | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
                                            | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
                                            | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
    
   NRF_GPIO->PIN_CNF[FAN] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
                                            | (GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos)
                                            | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
                                            | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
                                            | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
    
    APP_ERROR_CHECK(timer_create(TIMERS_APP_TIMEOUTS, NULL, (callback_t)app_timeouts_handler ));
    
    APP_ERROR_CHECK(timer_create(TIMERS_COOL_TIMEOUT, NULL, (callback_t)app_cool_timeout_handler ));
    
    APP_ERROR_CHECK(timer_create(TIMERS_SW_OFF_TIMEOUT, NULL, (callback_t)app_sw_off_timeout_handler ));
    
    APP_ERROR_CHECK(app_timer_create( &app_iteration_timer_id, APP_TIMER_MODE_SINGLE_SHOT, app_iteration_timer_handler ));
	
	APP_ERROR_CHECK(calendar_set_one_sec_callback(calendar_timer_handle)); //установка callback часов

	APP_ERROR_CHECK(evcal_set_callback(evcal_calendar_task)); //установка callback при срабатывании расписания
    
    app_ind_init();
    
    stateTest();
    
	return;
}

/**@brief 	Функция запускает таймер переходов
 *
 * @param	none
 *
 * @return 	none
 */
static void app_timeouts_timer_start(uint32_t timeout)
{     
    APP_ERROR_CHECK(timer_write_period(TIMERS_APP_TIMEOUTS,TIMERS_MILLISECOND(timeout)));
    APP_ERROR_CHECK(timer_reset(TIMERS_APP_TIMEOUTS));      
    APP_ERROR_CHECK(timer_start(TIMERS_APP_TIMEOUTS));
}

/**@brief 	Функция останавливает таймер переходов
 *
 * @param	none
 *
 * @return 	none
 */
static void app_timeouts_timer_stop(void)
{
    APP_ERROR_CHECK(timer_stop(TIMERS_APP_TIMEOUTS));
}

/**@brief 	Функция зупускает таймер отключения
 *
 * @param	none
 *
 * @return 	none
 */
static void app_sw_off_timer_start(void)
{
    app_heater.app_heater_state.flags.APP_TIMER = 1;
    APP_ERROR_CHECK(timer_stop(TIMERS_SW_OFF_TIMEOUT));
    APP_ERROR_CHECK(timer_write_period(TIMERS_SW_OFF_TIMEOUT,TIMERS_MILLISECOND(APP_SW_OFF_TIMEOUT_MS)));
    APP_ERROR_CHECK(timer_reset(TIMERS_SW_OFF_TIMEOUT));
    APP_ERROR_CHECK(timer_start(TIMERS_SW_OFF_TIMEOUT));
}

/**@brief 	Функция останавливает таймер отключения
 *
 * @param	none
 *
 * @return 	none
 */
static void app_sw_off_timer_stop(void)
{
    app_heater.app_heater_state.flags.APP_TIMER = 0;
    APP_ERROR_CHECK(timer_stop(TIMERS_SW_OFF_TIMEOUT));
    app_sw_off_time_left_m = 0; //обнуляем текущее время
}

/**@brief 	Функция запускает таймер охлаждения
 *
 * @param	none
 *
 * @return 	none
 */
static void app_cool_timer_start(void)
{    
    uint8_t enable;
    
    APP_ERROR_CHECK(timer_read_enable_flag(TIMERS_COOL_TIMEOUT,&enable));

    if(enable) //если уже был запущен (в APP_HEAT_FAN) выходим, не перезапускаем
    {
        return;
    }

    APP_ERROR_CHECK(timer_write_period(TIMERS_COOL_TIMEOUT,TIMERS_MILLISECOND(APP_COOL_TIMEOUT_MS)));
    APP_ERROR_CHECK(timer_reset(TIMERS_COOL_TIMEOUT));
    APP_ERROR_CHECK(timer_start(TIMERS_COOL_TIMEOUT));
}

/**@brief 	Функция останавливает таймер охлаждения
 *
 * @param	none
 *
 * @return 	none
 */
static void app_cool_timer_stop(void)
{
    app_heater.app_heater_enable.flags.cooling_en = 0;
    APP_ERROR_CHECK(timer_stop(TIMERS_COOL_TIMEOUT));
}

static void stateTest(void)
{
    if(app_heater.app_state == APP_TEST) return;
    
    APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_TEST\r\n"RTT_CTRL_RESET);
    
    app_state_change(APP_TEST);
    
    app_set_sound(1);
    
    stateStandBy();
}

static void stateStandBy(void)
{
    if(app_heater.app_state == APP_STAND_BY) return;
    
    APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_STAND_BY\r\n"RTT_CTRL_RESET);
    
    if(app_heater.app_heater_enable.flags.sound_en)
    {
        APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_SINGLE));
    }
    
    app_state_change(APP_STAND_BY);
    
    app_heat_disable();
    
    if((app_heater.app_heater_enable.bits & BIT_COOLING_EN ) != 0)
    {
        app_cool_timer_start();
        app_heat_fan();
    }
    else
    {
        app_heat_off(); //выключаем обогрев и вентилятор
    }
    app_sw_off_timer_stop(); //останавливаем таймер отключения если запущен
    app_heater.app_heater_enable.flags.osc_en = 0;
    app_osc_stop();
}

static void stateHeat(app_prog_t app_prog)
{
    APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_HEAT\r\n"RTT_CTRL_RESET);
    
    if(app_heater.app_heater_enable.flags.sound_en)
    {
        APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_SINGLE));
    }
    
    app_state_change(APP_HEAT);
    
    switch(app_prog)
    {
        case PROG_HEAT_TURBO:
        {
            app_heater.app_prog = PROG_HEAT_TURBO;
            app_cool_timer_stop();
            app_heater.app_heater_enable.flags.cooling_en = 1;
            app_heat_turbo_enable();
            app_heat_turbo();
            break;
        }
        case PROG_HEAT_FAN:
        {
            app_heater.app_prog = PROG_HEAT_FAN;
            app_cool_timer_start();
            app_heat_disable();
            app_heat_fan();
            break;
        }
        case PROG_HEAT_LOW:
        default:
        {
            app_heater.app_prog = PROG_HEAT_LOW;
            app_cool_timer_stop();
            app_heater.app_heater_enable.flags.cooling_en = 1;
            app_heat_low_enable();
            app_heat_low();
            break;
        }
    }
    
    if((app_heater.app_heater_enable.bits & BIT_OSC_EN) != 0)
    {
        app_osc_start(); //запускаем вращение если оно было активировано
    }
}

static void stateStandByAuto(void)
{
    if(app_heater.app_state == APP_STAND_BY_AUTO) return;
    
    APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_STAND_BY_AUTO\r\n"RTT_CTRL_RESET);
    
    if(app_heater.app_heater_enable.flags.sound_en)
    {
        APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_SINGLE));
    }

    app_state_change(APP_STAND_BY_AUTO);
    
    app_heat_low_enable();
    
    if((app_heater.app_heater_enable.bits & BIT_COOLING_EN ) != 0)
    {
        app_cool_timer_start();
        app_heat_fan();
    }
    else
    {
        app_heat_off(); //выключаем обогрев и вентилятор
    }
    app_osc_stop();
}

static void stateHeatAuto(void)
{
    if(app_heater.app_state == APP_HEAT_AUTO) return;
    
    APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_HEAT_AUTO\r\n"RTT_CTRL_RESET);
    
    if(app_heater.app_heater_enable.flags.sound_en)
    {
        APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_SINGLE));
    }
    
    app_state_change(APP_HEAT_AUTO);
    
    app_cool_timer_stop();
    app_heater.app_heater_enable.flags.cooling_en = 1;
    app_heat_low_enable();
    app_heat_low();
    
    if((app_heater.app_heater_enable.bits & BIT_OSC_EN) != 0)
    {
        app_osc_start(); //запускаем вращение если оно было активировано
    }
}

static void stateStandByAf(void)
{
    if(app_heater.app_state == APP_STAND_BY_AF) return;
    
    APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_STAND_BY_AF\r\n"RTT_CTRL_RESET);

    app_state_change(APP_STAND_BY_AF);
    
    if(app_heater.app_heater_enable.flags.sound_en)
    {
        APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_SINGLE));
    }
    
    app_heat_low_enable();
    
    if((app_heater.app_heater_enable.bits & BIT_COOLING_EN ) != 0)
    {
        app_cool_timer_start();
        app_heat_fan();
    }
    else
    {
        app_heat_off(); //выключаем обогрев и вентилятор
    }
    app_osc_stop();
}

static void stateHeatAf(void)
{
    if(app_heater.app_state == APP_HEAT_AF) return;
    
    APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_HEAT_AF\r\n"RTT_CTRL_RESET);
    
    if(app_heater.app_heater_enable.flags.sound_en)
    {
        APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_SINGLE));
    }
    
    app_state_change(APP_HEAT_AF);
    
    app_cool_timer_stop();
    app_heater.app_heater_enable.flags.cooling_en = 1;    
    app_heat_low_enable();
    app_heat_low();

    if((app_heater.app_heater_enable.bits & BIT_OSC_EN) != 0)
    {
        app_osc_start();// запускаем вращение если оно было активировано(в случае авто режима) 
    }
}

static void stateParing(void)
{
    if(app_heater.app_state == APP_PAIRING) return;
    
    APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_PAIRING\r\n"RTT_CTRL_RESET);
    
    app_state_change(APP_PAIRING);
    
    adv_data_set_paring();
    
    app_ind_set_pairing();
    
    app_timeouts_timer_start(APP_PAIRING_TIMEOUT_MS); //запускаем таймер апдейта
}

static void stateUpdate(void)
{
    if(app_heater.app_state == APP_FW_UPDATE) return;
    
    APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_FW_UPDATE\r\n"RTT_CTRL_RESET);
    
    app_state_change(APP_FW_UPDATE);
    
    app_ind_set_update();
    
    app_timeouts_timer_start(APP_FW_UPDATE_TIMEOUT_MS); //запускаем таймер апдейта
}

static void stateOverHeat(void)
{    
    APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_OVER_HEAT\r\n"RTT_CTRL_RESET);
    
    app_state_change(APP_OVER_HEAT);
    
    APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_MULTI));
    APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_MULTI));
    APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_MULTI));
    APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_MULTI));
    APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_MULTI));
    APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_MULTI));

    app_heat_disable();
    
    if((app_heater.app_heater_enable.bits & BIT_COOLING_EN ) != 0)
    {
        app_cool_timer_start();
        app_heat_fan();
    }
    else
    {
        app_heat_off(); //выключаем обогрев и вентилятор
    }
    app_sw_off_timer_stop(); //останавливаем таймер отключения если запущен
    app_heater.app_heater_enable.flags.osc_en = 0;
    app_osc_stop();
}
/**@brief 	Функция выполняет работу при выходе из соответствующего состояния
 *
 * @param	none
 *
 * @return 	none
 */
static void app_exit_state( app_state_t app_state )
{
	switch( app_state )
	{
		case APP_PAIRING:
		{
            adv_data_unset_paring();
            app_timeouts_timer_stop(); //останавливаем таймер перинга если вышли из режима
			break;
		}
		case APP_FW_UPDATE:
		{
            app_timeouts_timer_stop(); //останавливаем таймер апдейта если вышли из режима
			break;
		}
		default:
		{
			break;
		}
	}
    
	return;
}

static void app_state_change(app_state_t new_state)
{
	app_exit_state( app_heater.app_state );
    
    app_heater.app_state = new_state;
}

static void app_keyb_proccess(void)
{
    if(app_get_state() == APP_API_ERROR_STATE) return;
    
    for(uint8_t i=0; i<KEYB_BUTTON_COUNT; ++i) //чтение состояния кнопок
    {
		keyb_read_data(i, &app_keyboard_data[i]);
    }
    
    for(uint8_t i=0;i<KEYB_BUTTON_COUNT;i++)
    {
        if(app_keyboard_data[i].event_press == KEYB_EVENT_CAPTURED)
        {
            if((app_heater.app_heater_state.bits & BIT_APP_LOCK ) != 0) //запрещаем обработку кнопок если включена блокировка
            {
                app_ind_set_lock();
                return;
            }
        }
    }
    
    if(app_get_state() == APP_API_FW_UPDATE_STATE 
        || app_get_state() == APP_API_PAIRING_STATE 
        || app_get_state() == APP_API_ERROR_STATE)
    {
        return;
    }
    
    if(app_keyboard_data[LOCK_KEY].pressed_time_ms >= APP_KEY_LOCK_TIME_MS) //проверяем время нажатия кнопки  для преключения в состояния блокировки
    {
        switch(app_heater.app_state)
        {
            case APP_STAND_BY:
            case APP_HEAT:
            case APP_STAND_BY_AUTO:
            case APP_HEAT_AUTO:
            case APP_STAND_BY_AF:
            case APP_HEAT_AF:
            {
                if(app_flags.b_release_wait == 0)
                {
                    app_flags.b_release_wait = 1;//выставляем флаг ожидания релиза кнопки
                    
                    app_set_lock(app_heater.app_heater_state.flags.APP_LOCK ? 0:1);
                }
                return;
            }
            default:
                break;
        }
    }
    
    if(app_keyboard_data[LOCK_KEY].event_release == KEYB_EVENT_CAPTURED)
    {
        switch(app_heater.app_state)
        {
            case APP_STAND_BY:
            case APP_HEAT:
            case APP_STAND_BY_AUTO:
            case APP_HEAT_AUTO:
            case APP_STAND_BY_AF:
            case APP_HEAT_AF:
            {
                if(app_flags.b_release_wait == 1)
                {
                    app_flags.b_release_wait = 0;
                    return;
                }
                break;
            }
            default:
                break;
        }
    }
    
    if((app_heater.app_heater_state.bits & BIT_APP_LOCK ) == 0) //запрещаем обработку кнопок если включена блокировка
    {
        if(app_keyboard_data[PAIRING_KEY].pressed_time_ms >= APP_KEY_PARING_TIME ) //ожидаем время нажатия для пейринга
        {
            switch(app_heater.app_state)
            {
                case APP_STAND_BY:
                {
                    if(app_flags.b_release_wait == 0)
                    {
                        app_flags.b_release_wait = 1;//выставляем флаг ожидания релиза кнопки
                        APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_MULTI));
                        APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_MULTI));
                        APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_MULTI));
                    }
                    return;
                }
                default:
                    break;
            }
        }
        
        if(app_keyboard_data[PAIRING_KEY].event_release == KEYB_EVENT_CAPTURED) //если кнопка перинга отпущена переходим в режим перига
        {
            switch(app_heater.app_state)
            {
                case APP_STAND_BY:
                {
                    if(app_flags.b_release_wait == 1)
                    {
                        app_flags.b_release_wait = 0;
                        stateParing();
                        return;
                    }
                    break;
                }
                default:
                    break;
            }
        }

        if(app_keyboard_data[UNPAIRING_KEY].pressed_time_ms >= APP_KEY_UNPARING_TIME ) //ожидаем время нажатия для анпейринга
        {
            switch(app_heater.app_state)
            {
                case APP_STAND_BY:
                {
                    if(app_flags.b_release_wait == 0)
                    {
                        app_flags.b_release_wait = 1;//выставляем флаг ожидания релиза кнопки
                        APP_ERROR_CHECK(buz_add_beep(300,150,BUZ_BEEP_MULTI));
                    }
                    return;
                }
                default:
                    break;
            }
            return; 
        }
        
        if(app_keyboard_data[UNPAIRING_KEY].event_release == KEYB_EVENT_CAPTURED)
        {
            switch(app_heater.app_state)
            {
                case APP_STAND_BY:
                {
                    if(app_flags.b_release_wait == 1)
                    {
                        app_flags.b_release_wait = 0;
                        com_slave_unpair_proccess(); //Делаем анперинг
                        return;
                    }
                    break;
                }
                default:
                    break;
            }
        }
        
        if(app_keyboard_data[OSC_KEY].event_release == KEYB_EVENT_CAPTURED) //переключаем состояние осцилятора
        {
            switch (app_heater.app_state)
            {
                case APP_HEAT:
                case APP_STAND_BY_AUTO:
                case APP_HEAT_AUTO:
                case APP_STAND_BY_AF:
                case APP_HEAT_AF:
                {
                    app_osc_enable(!app_heater.app_heater_enable.flags.osc_en);
                    break;
                }
                default:
                    break;
            }
        }
        
        //активируем таймер отключения и инкриментируем время
        if(app_keyboard_data[TIMER_KEY].event_release == KEYB_EVENT_CAPTURED)
        {
            switch (app_heater.app_state)
            {
                case APP_HEAT:
                case APP_STAND_BY_AUTO:
                case APP_HEAT_AUTO:
                case APP_STAND_BY_AF:
                case APP_HEAT_AF:
                {
                    if(app_heater.app_heater_enable.flags.sound_en)
                    {
                        APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_SINGLE));
                    }
                    
                    uint16_t time = HOUR_TO_MINUTES(app_get_sw_off_time_left_h() + 1);
                    
                    app_set_sw_off_time(time);
                    break;
                }
                default:
                    break;
            }
        }
        
        if(app_keyboard_data[LEVEL_KEY].event_release == KEYB_EVENT_CAPTURED)//переключение между режимами нагревателя
        {
            app_power_iterate(0);
        }
        
        if(app_keyboard_data[SWITCHER_KEY].event_release == KEYB_EVENT_CAPTURED) //выставляем флаг активной/пассивной работы
        {
            app_switch();
        }
        
    }
}

/********************************************************************************
 *
 ********************************************************************************/


static void app_temp_serv_proccess(void)
{
    temp_serv_read(&app_temp_serv_data);
    
    if(app_get_state() == APP_API_FW_UPDATE_STATE 
        || app_get_state() == APP_API_PAIRING_STATE 
        || app_get_state() == APP_API_ERROR_STATE)
    {
        return;
    }
    
    if(app_get_curent_temp() >= APP_OVERHEAT_TEMP)
    {
        stateOverHeat();
        app_ind_set_overheat();
    }
    
    switch (app_heater.app_state)
    {
        case APP_HEAT:
        case APP_HEAT_AUTO:
        case APP_STAND_BY_AUTO:
        case APP_HEAT_AF:
        case APP_STAND_BY_AF:
        {
            if(app_heater.app_prog == PROG_AUTO)
            {            
                if(app_temp_serv_data.event_lower == TEMP_EVENT_CAPTURED)
                {
                    stateHeatAuto();
                }
                
                else if(app_temp_serv_data.event_higher == TEMP_EVENT_CAPTURED)
                {
                    stateStandByAuto();
                }
            }
            else if(app_heater.app_prog == PROG_AF)
            {            
                if(app_temp_serv_data.event_lower == TEMP_EVENT_CAPTURED)
                {
                    stateHeatAf();
                }
                
                else if(app_temp_serv_data.event_higher == TEMP_EVENT_CAPTURED)
                {
                    stateStandByAf();
                }
            }
            break;
        }
        default:
            break;
    }
}

/********************************************************************************
 *
 ********************************************************************************/
void application_process(void)
{
    app_keyb_proccess();
    
    app_temp_serv_proccess();
    
    app_ind_proccess();
    
	return;
}
/********************************************************************************
 *
 ********************************************************************************/

/********************************************************************************
 *
 ********************************************************************************/
/**
 * 	описание в application_api.h
*/
uint16_t app_get_version(void)
{
	return FIRMWARE_VER;
}

bool app_state_check(app_state_t state)
{
    if(app_heater.app_state == state)
	{
		return true;
	}
	else
	{
		return false;
	}
}

uint8_t app_get_state(void)
{
	switch(app_heater.app_state)
	{
		case APP_FW_UPDATE:
		{
			return APP_API_FW_UPDATE_STATE;
		}
        case APP_PAIRING:
		{
			return APP_API_PAIRING_STATE;
		}
        case APP_STAND_BY:
        {
            return APP_API_OFF_STATE;
        }
        case APP_OVER_HEAT:
        {
            return APP_API_ERROR_STATE;
        }
		default:
		{
            return APP_API_ON_STATE;
		}
	}
}

uint8_t app_get_error(void)
{
	switch(app_heater.app_state)
	{
        case APP_OVER_HEAT:
        {
            return APP_API_CRITICAL_ERROR;
        }
		default:
			return APP_API_NO_ERROR;
	}
}

uint8_t app_set_sw_off_time(uint16_t time)
{
    if( app_get_state() != APP_API_ON_STATE) return 0;
    
    if((time > 480) || (time == 0)) //задать интервал можно неболее 8 часов
    {
        app_sw_off_timer_stop(); // если время = 0, отключаем таймер
    }
    else
    {
       app_sw_off_time_left_m = time;
       app_sw_off_timer_start();
    }
    
    app_ind_set_time_set();
    
    return 1;
}

uint8_t app_get_sw_off_time_left_h(void)
{
    if((app_sw_off_time_left_m % 60) == 0)
    {
        return MINUTES_TO_HOUR(app_sw_off_time_left_m);
    }
    else
    {
        return MINUTES_TO_HOUR(app_sw_off_time_left_m) + 1;
    }
}

uint16_t app_get_sw_off_time_left(void)
{
    return app_sw_off_time_left_m;
}

uint8_t app_get_sw_off_timer_flag(void)
{
    return app_heater.app_heater_state.flags.APP_TIMER;
}

uint8_t app_set_sw_on(void)
{
    if( app_get_state() == APP_API_FW_UPDATE_STATE 
        || app_get_state() == APP_API_PAIRING_STATE 
        || app_get_state() == APP_API_ERROR_STATE )
    {
        return 0;
    }
    
    stateHeat(app_heater.app_prog);
    
    return 1;
}

uint8_t app_set_sw_off(void)
{
    if( app_get_state() == APP_API_FW_UPDATE_STATE 
        || app_get_state() == APP_API_PAIRING_STATE 
        || app_get_state() == APP_API_ERROR_STATE )
    {
        return 0;
    }
    
    stateStandBy();
    
    return 1;
}

uint8_t app_switch(void)
{
    switch (app_heater.app_state)
    {
        case APP_STAND_BY:
        {
            stateHeat(PROG_HEAT_LOW);
            return 1;
        }
        
        case APP_HEAT:
        case APP_HEAT_AUTO:
        case APP_HEAT_AF:
        case APP_STAND_BY_AUTO:
        case APP_STAND_BY_AF:
        {
            stateStandBy();
            return 1;
        }
        default:
            return 0;
    }
}

uint8_t app_power_iterate(int8_t vector)
{
    if(appIterStepAllowFl == false) return 0;
    
    APP_ERROR_CHECK(app_timer_start(app_iteration_timer_id, APP_TIMER_TICKS(500, APP_TIMER_PRESCALER), NULL ));
    
    appIterStepAllowFl = false;
    
    switch(vector){
        case 0:{
            switch (app_heater.app_state){
                case APP_HEAT:{
                    switch(app_heater.app_prog){
                        case PROG_HEAT_LOW:{
                            stateHeat(PROG_HEAT_TURBO);
                            return 1;
                        }
                        case PROG_HEAT_TURBO:{
                            stateHeat(PROG_HEAT_FAN);
                            return 1;
                        }
                        case PROG_HEAT_FAN:{
                            stateHeat(PROG_HEAT_LOW);
                            return 1;
                        }
                        default:
                            return 0;
                    }
                }
                default:
                    return 0;
            }
        }
        default:
            return 0;
    }
}
uint8_t app_set_lock(uint8_t lock)
{
    if( app_get_state() == APP_API_FW_UPDATE_STATE 
        || app_get_state() == APP_API_PAIRING_STATE 
        || app_get_state() == APP_API_ERROR_STATE )
    {
        return 0;
    }
    
	if (lock > 1) return 0;
    
    if(app_heater.app_heater_enable.flags.sound_en)
    {
        APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_SINGLE));
    }
    
    if(lock)
    {
        app_heater.app_heater_state.flags.APP_LOCK = 1; //выставляем флаг блокировки
        app_ind_set_lock();  //выводим индикацию
    }
    else
    {
        app_heater.app_heater_state.flags.APP_LOCK = 0;//выставляем флаг разблокировки
        app_ind_set_unlock(); //выводим индикацию
    }
	return 1;
}

uint8_t app_get_lock(void)
{
	return app_heater.app_heater_state.flags.APP_LOCK;
}

uint8_t app_set_heat_program(uint8_t prog)
{
    if( app_get_state() == APP_API_FW_UPDATE_STATE 
        || app_get_state() == APP_API_PAIRING_STATE 
        || app_get_state() == APP_API_ERROR_STATE)
    {
        return 0;
    }
    
    switch(prog)
    {
        case PROG_HEAT_LOW:
        {
            if(app_heater.app_prog == PROG_HEAT_LOW) break;
            stateHeat(PROG_HEAT_LOW);
            break;
        }
        case PROG_HEAT_TURBO:
        {
            if(app_heater.app_prog == PROG_HEAT_TURBO) break;
            stateHeat(PROG_HEAT_TURBO);
            break;
        }
        case PROG_HEAT_FAN:
        {
            if(app_heater.app_prog == PROG_HEAT_FAN) break;
            stateHeat(PROG_HEAT_FAN);
            break;
        }
        case PROG_AUTO:
        {
            if(app_heater.app_prog == PROG_AUTO) break;
            app_heater.app_prog = PROG_AUTO;
            temp_serv_set_target(app_target_temp);
            app_ind_set_auto();
            break;
        }
        case PROG_AF:
        {
            if(app_heater.app_prog == PROG_AF) break;
            app_heater.app_prog = PROG_AF;
            temp_serv_set_target(APP_ANTI_FROST_TEMP);
            app_ind_set_af();
            break;                    
        }
        default:
            return 0;
    }
    
	return 1;
}

uint8_t app_get_heat_program(void)
{
    return app_heater.app_prog;
}

uint8_t app_set_target_temp(uint8_t targetTemp)
{
	if (targetTemp > 35 || targetTemp < 8) return 0;

    app_target_temp = targetTemp;
    
    if(app_heater.app_prog != PROG_AF)
    {
        temp_serv_set_target(app_target_temp);
    }
    
	return 1;
}

uint8_t app_get_target_temp(void)
{
	return app_target_temp;
}

uint8_t app_get_curent_temp(void)
{
	return (uint8_t)temp_serv_get_current_temp();
}


uint8_t app_osc_get_enable(void)
{
    return app_heater.app_heater_enable.flags.osc_en;
}

uint8_t app_osc_enable( uint8_t enable)
{
    if( app_get_state() == APP_API_FW_UPDATE_STATE 
        || app_get_state() == APP_API_PAIRING_STATE 
        || app_get_state() == APP_API_ERROR_STATE)
    {
        return 0;
    }
    
    if(enable > 1) return 0;
    
    if(app_heater.app_heater_enable.flags.sound_en)
    {
        APP_ERROR_CHECK(buz_add_beep(150,150,BUZ_BEEP_SINGLE));
    }
    
    if(enable)
    {
        switch(app_heater.app_state)
        {
            case APP_HEAT:
            case APP_HEAT_AUTO:
            case APP_HEAT_AF:
            {
                app_heater.app_heater_enable.flags.osc_en = 1;
                app_osc_start();
                break;
            }
            case APP_STAND_BY_AUTO:
            case APP_STAND_BY_AF:
            {
                app_heater.app_heater_enable.flags.osc_en = 1;
                break;
            }
            default:
                break;
        }
    }
    else
    {
        app_heater.app_heater_enable.flags.osc_en = 0;
        app_osc_stop();
    }
    
    return 1;
}

void app_osc_start(void)
{
    app_heater.app_heater_state.flags.APP_OSC = 1;
    NRF_GPIO->OUTSET = (1UL << MOTO);
}

void app_osc_stop(void)
{
    app_heater.app_heater_state.flags.APP_OSC = 0;
    NRF_GPIO->OUTCLR = (1UL << MOTO);
}

uint8_t app_get_heat_low_enable(void)
{
    return app_heater.app_heater_enable.flags.heat_low_en;
}

uint8_t app_get_heat_turbo_enable(void)
{
    return app_heater.app_heater_enable.flags.heat_turbo_en;
}

static void app_heat_off(void)
{
    NRF_GPIO->OUTCLR = (1UL << MAIN_HEAT_L);
    NRF_GPIO->OUTCLR = (1UL << MAIN_HEAT_H);
    NRF_GPIO->OUTCLR = (1UL << FAN);
    app_heater.app_heater_state.flags.APP_HEAT_LOW = 0;
    app_heater.app_heater_state.flags.APP_HEAT_TURBO = 0;
    app_heater.app_heater_state.flags.APP_HEAT_FAN = 0;
}

static void app_heat_fan(void)
{
    NRF_GPIO->OUTCLR = (1UL << MAIN_HEAT_L);
    NRF_GPIO->OUTCLR = (1UL << MAIN_HEAT_H);
    NRF_GPIO->OUTSET = (1UL << FAN);
    app_heater.app_heater_state.flags.APP_HEAT_LOW = 0;
    app_heater.app_heater_state.flags.APP_HEAT_TURBO = 0;
    app_heater.app_heater_state.flags.APP_HEAT_FAN = 1;
}

static void app_heat_low(void)
{
    NRF_GPIO->OUTSET = (1UL << MAIN_HEAT_L);
	NRF_GPIO->OUTCLR = (1UL << MAIN_HEAT_H);
    NRF_GPIO->OUTSET = (1UL << FAN);
    app_heater.app_heater_state.flags.APP_HEAT_LOW = 1;
    app_heater.app_heater_state.flags.APP_HEAT_TURBO = 0;
    app_heater.app_heater_state.flags.APP_HEAT_FAN = 1;
}

static void app_heat_turbo(void)
{
	NRF_GPIO->OUTSET = (1UL << MAIN_HEAT_L);
    NRF_GPIO->OUTSET = (1UL << MAIN_HEAT_H);
    NRF_GPIO->OUTSET = (1UL << FAN);
    app_heater.app_heater_state.flags.APP_HEAT_LOW = 1;
    app_heater.app_heater_state.flags.APP_HEAT_TURBO = 1;
    app_heater.app_heater_state.flags.APP_HEAT_FAN = 1;
}

static void app_heat_low_enable(void)
{
    app_heater.app_heater_enable.flags.heat_low_en = 1;
    app_heater.app_heater_enable.flags.heat_turbo_en = 0;
}

static void app_heat_turbo_enable(void)
{
    app_heater.app_heater_enable.flags.heat_low_en = 1;
    app_heater.app_heater_enable.flags.heat_turbo_en = 1;
}

static void app_heat_disable(void)
{
    app_heater.app_heater_enable.flags.heat_low_en = 0;
    app_heater.app_heater_enable.flags.heat_turbo_en = 0;
}

uint8_t app_set_sound(uint8_t sound_en)
{
	if (sound_en >1) return 0;
	app_heater.app_heater_enable.flags.sound_en = sound_en;
	return 1;
}

uint8_t app_get_sound (void) 
{
	return app_heater.app_heater_enable.flags.sound_en;
}

uint8_t app_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:
			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;
}

void app_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));
}

void app_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));
	}
}

uint8_t app_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;
}

uint8_t app_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;
}

uint8_t app_erase_evcal(void)
{
	if(evcal_erase_all_tasks() == NRF_SUCCESS){
		return ERSP_SUCCESS;
	} else {
		return ERSP_ERROR_INTERNAL;
	}
}

uint8_t app_get_ver_evcal(void)
{
	return EVCAL_DRIVER_VERSION;
}

uint8_t app_get_max_task_evcal(void)
{
	return EVCAL_MAX_TASKS;
}

uint8_t app_get_cur_task_num_evcal(void)
{
	uint8_t m_num_task = 0;
	APP_ERROR_CHECK(evcal_get_task_number(&m_num_task));
	return m_num_task;
}

uint8_t app_enter_fw_update_state(void)
{
	if(app_get_state() == APP_API_OFF_STATE)
	{
		stateUpdate();
		return 1;
	}
	return 0;
}

void app_exit_fw_update_state(void)
{
    stateStandBy();
}

void app_fw_update_proc(void)
{
	if( app_heater.app_state == APP_FW_UPDATE )
	{
        APP_ERROR_CHECK(timer_reset(TIMERS_APP_TIMEOUTS));
	}
}

void app_set_open_session_flag(void)
{
	app_flags.b_session_is_opened = 1;
	return;
}

void app_set_connection_flag(void)
{
	app_flags.b_connection_is_established = 1;
	return;
}

void app_clear_connection_flag(void)
{
	app_flags.b_session_is_opened = 0;
	app_flags.b_connection_is_established = 0;
	return;
}

void app_slave_pairing_complite( void )
{
    stateStandBy();
}

void app_slave_pairing_error(void)
{
    stateStandBy();
}
/*****************************************************************************************************/
Made on
Tilda