Программный модуль для терморегулятора теплого пола RSF-171S. Версия 1.41
ПО является неотъемлемой частью терморегулятора теплого пола RSF-171S, отдельно потребителю не поставляется и эксплуатируется только в составе устройства.
////////////////////////////////////////////////////////////////
//RSF-171S
//v1.41
//application.c
/********* 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_gpio.h"
#include "nrf_soc.h"
#include "app_timer.h"
#include "app_error.h"
#include "calendar.h"
#include "evcal.h"
//#include "evcal_case.h"
#include "utc_date_convert.h"
#include "r4s_lib.h"
#include "r4s_master.h"
#include "Application.h"
#include "Application_api.h"
#include "event_base.h"
#include "timers_config.h"
#include "control.h"
#include "display.h"
#include "display_config.h"
#include "com_slave_extention.h"
//#include "config.h"
#include "pof_manager.h"
#include "evcal_config.h"
/********* TYPE **************************************************************/
#pragma pack(push, 1)
typedef enum{
APP_ACTIVE_AIR_SENSOR = false,
APP_ACTIVE_FLOOR_SENSOR = true,
}active_sensor_temp_t;
//биты состояния индикации температуры
typedef enum{
TYPE_AIR_SENSOR_IND = (uint8_t) 0x01,
TYPE_FLOOR_SENSOR_IND = (uint8_t) 0x02,
CURRENT_TEMP_IND = (uint8_t) 0x04,
SET_TEMP_IND = (uint8_t) 0x08
} ind_state_temp_t;
//биты состояния индикации дня недели
typedef enum{
SUNDAY_IND = (uint8_t) 0x01,
SATURDAY_IND = (uint8_t) 0x02,
FRIDAY_IND = (uint8_t) 0x04,
THURSDAY_IND = (uint8_t) 0x08,
WEDNESDAY_IND = (uint8_t) 0x10,
TUESDAY_IND = (uint8_t) 0x20,
MONDAY_IND = (uint8_t) 0x40,
} ind_state_week_t;
//биты состояния индикации события
typedef enum{
EVENT_SUN_IND = (uint8_t) 0x01,
EVENT_OUT_IND = (uint8_t) 0x02,
EVENT_IN_IND = (uint8_t) 0x04,
EVENT_NIGHT_IND = (uint8_t) 0x08,
}ind_state_event_t;
typedef struct{
uint16_t app_sensor_se :1; //температурный датчик управления (0/1 - AIR/FLOOR)
uint16_t app_lock_en :1; //блокировка клавиатуры (0/1 - выкл/вкл)
uint16_t app_contrast :1; //контраст дисплея 0/1 - 2/3)
uint16_t app_calendar_en :1; //блокировка calendar (0/1 - выкл/вкл)
uint16_t app_selfteaching_en :1; //самообучение (0/1 - выкл/вкл)
uint16_t app_off_en :1; // 0/1-вкл/выкл
uint8_t app_floor_sensor_idx; //индекс подключенного температурного датчика пола
float app_floor_sensor_calib; //калибровка датчика пола -9 ... +9, шаг 0.5 (0.0)
float app_air_sensor_calib; //калибровка датчика воздуха -9 ... +9, шаг 0.5 (0.0)
uint8_t app_hysteresis; //отсрочка срабатывания реле по датчику +1 ... +9, шаг 1 (2)
uint16_t app_selfteaching_time_s; //
uint16_t app_custom_power;
int32_t app_shift_utc;
}app_state_device_t;
typedef struct{
uint32_t app_timer_power_on;
uint32_t app_count_set_relay;
}app_state_device_log_t;
typedef struct{
float app_sensor_calendar_set;
float app_sensor_custom_set; //установленная температура пользователя
float app_sensor_active_set; //установленная температура активная
}app_state_hand_t;
typedef struct{
uint16_t sm_clean_setting :1; //сброс до заводских настроек инженерного меню
app_service_menu_t sm_index_menu; //выбранный пункт инженерного меню
}app_state_service_menu_t;
typedef struct{
uint8_t app_floor_sensor_idx; //индекс подключенного температурного датчика пола
uint8_t app_hysteresis; //отсрочка срабатывания реле по датчику +1 ... +9, шаг 1 (2)
float app_floor_sensor_calib; //калибровка датчика пола -9 ... +9, шаг 0.5 (0.0)
float app_air_sensor_calib; //калибровка датчика воздуха -9 ... +9, шаг 0.5 (0.0)
uint16_t app_contrast :1; //контраст дисплея 0/1 - 2/3)
}app_data_service_menu_t;
typedef struct{
uint8_t element_edit;
uint8_t param_edit;
}app_state_clock_edit_t;
typedef struct{
uint32_t timer_relay_on;
uint32_t power;
uint32_t count_relay_set;
}api_get_heater_info_t;
#pragma pack(pop)
/********* DEFINES **************************************************************/
#define SYMBOL_MOON DISPLAY_S0
#define SYMBOL_LOCK DISPLAY_S1
#define SYMBOL_AIR_TEMP DISPLAY_S2
#define SYMBOL_WEEK_3 DISPLAY_S3
#define SYMBOL_WEEK_4 DISPLAY_S4
#define SYMBOL_SUN DISPLAY_S5
#define SYMBOL_ANTI_FROST DISPLAY_S6
#define SYMBOL_FLOOR_TEMP DISPLAY_S7
#define SYMBOL_WEEK_2 DISPLAY_S8
#define SYMBOL_WEEK_5 DISPLAY_S9
#define SYMBOL_IN_HOUSE DISPLAY_S10
#define SYMBOL_OUT_HOUSE DISPLAY_S11
#define SYMBOL_HAND DISPLAY_S12
#define SYMBOL_WEEK_1 DISPLAY_S13
#define SYMBOL_WEEK_6 DISPLAY_S14
#define SYMBOL_HEAT DISPLAY_S17
#define SYMBOL_CLOCK_DOT DISPLAY_S18
#define SYMBOL_WEEK_7 DISPLAY_S19
#define SYMBOL_L_CELSIUS DISPLAY_S20
#define SYMBOL_B_CELSIUS DISPLAY_S21
#define SYMBOL_IN_NOT DISPLAY_S15
#define SYMBOL_OUT_NOT DISPLAY_S16
#define BTN_ALL_RELEASE BTN_TOUCH_KEY_NO
#define BTN_ON BTN_TOUCH_KEY_K1
#define BTN_MENU BTN_TOUCH_KEY_K2
#define BTN_CLOCK BTN_TOUCH_KEY_K3
#define BTN_UP BTN_TOUCH_KEY_K4
#define BTN_DOWN BTN_TOUCH_KEY_K5
#define BTN_ON_CLOCK BTN_TOUCH_KEY_K1K3
#define BTN_MENU_UP BTN_TOUCH_KEY_K2K4
#define BTN_CLOCK_DOWN BTN_TOUCH_KEY_K3K5
#define CALIB_SENSOR_FLOOR_MIN -9.f
#define CALIB_SENSOR_FLOOR_MAX 9.f
#define CALIB_SENSOR_FLOOR_STEP 0.5f
#define CALIB_SENSOR_FLOOR_DEFAULT 0.f
#define CALIB_SENSOR_AIR_MIN -9.f
#define CALIB_SENSOR_AIR_MAX 9.f
#define CALIB_SENSOR_AIR_STEP 0.5f
#define CALIB_SENSOR_AIR_DEFAULT 0.f
#define APP_CONTROL_IDX_MIN 0
#define APP_CONTROL_IDX_MAX 17
#define APP_CONTROL_IDX_STEP 1
#define APP_CONTROL_IDX_DEFAULT 0
#define APP_HYSTERESIS_MIN 1
#define APP_HYSTERESIS_MAX 9
#define APP_HYSTERESIS_STEP 1
#define APP_HYSTERESIS_DEFAULT 2
#define APP_FLOOR_SENSOR_IDX_MIN 0
#define APP_FLOOR_SENSOR_IDX_MAX (APP_FLOOR_SENSOR_CONT - 1)
#define APP_FLOOR_SENSOR_IDX_STEP 1
#define APP_FLOOR_SENSOR_IDX_DEFAULT 0
#define APP_CUSTOM_SET_TEMP_DEFAULT 23 //установленная пользовательская температура по умолчанию
#define APP_TIMEOUT_ON_RELAY 6 //m задержка на включение реле после автоотключения
#define APP_TIMEOUT_SYMBOL_CALENDAR_MAX_MS (5*1000)
//#define APP_TIMEOUT_HEAT_ERROR (5*60*60*1000)
#define APP_TIMEOUT_SERVICE_MENU (5*1000*60)
#define APP_TIME_CALENDAR_BEFORE (60*60) //время вызова callback перед событием календаря
#define APP_TIMEOUT_TEST (1*60*1000) //таймаут выхода из теста
/********* MACROS ***************************************************************/
#define DAYS_IN_WEEK 7
uint8_t SYMBOL_WEEKS[] = {SYMBOL_WEEK_1, SYMBOL_WEEK_2, SYMBOL_WEEK_3, SYMBOL_WEEK_4, SYMBOL_WEEK_5, SYMBOL_WEEK_6, SYMBOL_WEEK_7};
#define EVENT_COUNT 4
uint8_t SYMBOL_EVENTS[] = {SYMBOL_SUN, SYMBOL_OUT_HOUSE, SYMBOL_IN_HOUSE, SYMBOL_MOON};
#define TEMPS_COUNT 4
uint8_t SYMBOL_TEMPS[] = {SYMBOL_AIR_TEMP, SYMBOL_FLOOR_TEMP, SYMBOL_L_CELSIUS, SYMBOL_L_CELSIUS};
#define APP_SYMBOL_DIGIT_TEMP_ADDR (DISPLAY_DIG1)
#define APP_SYMBOL_DIGIT_SET_TEMP_ADDR (DISPLAY_DIG4)
#define APP_SYMBOL_DIGIT_HOURS_ADDR (DISPLAY_DIG7)
#define APP_SYMBOL_DIGIT_MINUTES_ADDR (DISPLAY_DIG9)
#define APP_PAIRING_TIME_MS 5000//ms время таймаут входа в режим APP_PAIRING
#define APP_CLOCK_EDIT_TIME_MS 5000//ms время таймаут входа в режим APP_CLOCK_EDIT
#define APP_CASE_EDIT_TIME_MS 5000//ms время таймаут входа в режим редактирования кейсов
#define APP_TIMEOUT_PRESS_TIME_MS 500//ms время таймаут удержания кнопок UP/DOWN
#define APP_UNPAIRING_TIME_MS 5000//ms время таймаут входа в режим APP_UNPAIRING
#define APP_TIMEOUT_CHANGE_STATE_TICKS 5000 //ms время удержания типа режима(на индикаторе) и задержка на перезапись событий календаря при управлении с кнопок
#define APP_PARAM_INC(value, max, step) ((((value)+(step)) < (max))?((value)+(step)):((max)))
#define APP_PARAM_DEC(value, min, step) ((((value)-(step)) > (min))?((value)-(step)):((min)))
#define APP_TEST_TIMEOUT_STAGES_10MS 400 //timeout выполнения одного этапа теста
#define APP_OFF_DEVICE() do{ \
if(keyb_data.event_release == BTN_EVENT_CAPTURED && keyb_data.code_press == BTN_ON) \
api_state_change(APP_OFF); \
}while(0);
#define APP_CHANGE_LOCK_DEVICE() do{ \
if(keyb_data.event_press == BTN_EVENT_CAPTURED && keyb_data.code_press == BTN_CLOCK_DOWN) \
app_state_device.app_lock_en = ~app_state_device.app_lock_en; \
}while(0);
#define APP_TEMP_BEFORE_MIN 20 //минут, время изменения на 1 градус
#define APP_STATE_DEVICE_DEFAULT() \
{ \
.app_sensor_se = false, \
.app_lock_en = false, \
.app_contrast = true, \
.app_calendar_en = false, \
.app_selfteaching_en = false, \
.app_floor_sensor_idx = 0, \
.app_floor_sensor_calib = CALIB_SENSOR_FLOOR_DEFAULT, \
.app_air_sensor_calib = CALIB_SENSOR_AIR_DEFAULT, \
.app_hysteresis = APP_HYSTERESIS_DEFAULT, \
.app_custom_power = 0, \
.app_selfteaching_time_s = (APP_TEMP_BEFORE_MIN*60), \
.app_shift_utc = 0, \
}
#define APP_STATE_DEVICE_LOG_DEFAULT() \
{ \
.app_timer_power_on = 0, \
.app_count_set_relay = 0, \
}
#define APP_STATE_CLOCK_EDIT_DEFAULT() \
{ \
.element_edit = 0, \
.param_edit = 0, \
}
#define APP_TIMEOUT_ADV_CUSTOM 1000 //ms, период адвертайзинга
#define TIMERS_MINUTES(t) ((t)*60*1000)
#define TIMERS_HOURS(t) ((t)*60)
#define IN_TIMERS_HOURS(t) ((t)/60)
#define IN_TIMERS_MINUTES(t) ((t)%60)
/********* VARIABLES *****************************************************/
static uint32_t app_timeout_adv_ms = APP_TIMEOUT_ADV_CUSTOM;
static bool app_timeout_adv_en = false;
static app_error_t app_state_err[2] = {APP_ERROR_NO, APP_ERROR_NO}; // состояние ошибки
static app_state_t app_state = APP_START; /* состояние state machine*/
//static app_state_t app_prev_off_state = APP_STAND_BY; /* состояние state machine перед отключением прибора*/
static bool app_level_err_test_fl = false;
//таймеры
static volatile uint32_t app_timeout_on_relay_ms = 0;
static volatile bool AppTimeoutFl = false; /* флаг timeout-a */
//static uint8_t app_case_idx = 0;
//static uint8_t app_case_event_max = EVENT_COUNT;
//static bool is_connected = false;
//static bool AppMasterConnectedFl = false; /* флаг master connected*/
//static bool AppPairingCh1Fl = false; /* флаг pairing*/
//static bool AppPairingCh2Fl = false; /* флаг pairing*/
//static bool AppUnPairingCh1Fl = false; /* флаг unpairing*/
//static bool AppUnPairingCh2Fl = false; /* флаг unpairing*/
static bool flag_control_smartfone = false; //флаг управления с телефона
static uint8_t fl_over_hi = 0; //флаг перегрева
static volatile uint32_t app_timeout_ind_change_state_10ms = 0; //timeout отображения кейса при изменении state
static volatile uint32_t app_timeout_illumination_10s = 0;
static uint32_t app_timeout_blink_10ms = 0;
static volatile uint32_t app_timeout_ind_pairing_10ms = 0;
static volatile uint32_t app_timeout_blink_calendar_10ms = 0; //сигнал отсутствия задач календаря
static volatile uint8_t app_blink_num = 0;
static bool app_first_press_menu = false;
static uint8_t app_test_btn_mask = 0;
static uint32_t app_selfteaching_time_ms = 0; //ms время выхода датчика температуры на заданную температуру
static float app_begin_temp_heating; //начальная температура подогрева с учетом калибровочного коэффициента
static float app_end_temp_heating; //конечная температура подогрева с учетом калибровочного коэффициента
static uint8_t app_test_stage = 0;
static uint32_t app_timeout_test_10ms = APP_TEST_TIMEOUT_STAGES_10MS;
APP_TIMER_DEF(app_timer_id);
APP_TIMER_DEF(app_timer_10ms_id);
APP_TIMER_DEF(app_timer_before_cal_id);
static app_state_device_t app_state_device = APP_STATE_DEVICE_DEFAULT();
static app_state_device_log_t app_state_device_log = APP_STATE_DEVICE_LOG_DEFAULT();
static volatile app_state_hand_t app_state_hand = {
.app_sensor_calendar_set = 0,
.app_sensor_custom_set = APP_CUSTOM_SET_TEMP_DEFAULT,
.app_sensor_active_set = APP_CUSTOM_SET_TEMP_DEFAULT,
};
static app_state_service_menu_t app_state_service_menu = {.sm_index_menu = SM_FLOOR_SENSOR_IDX_01, .sm_clean_setting = false};
static app_state_clock_edit_t app_state_clock_edit = APP_STATE_CLOCK_EDIT_DEFAULT();
static app_save_info_struct_t app_pof_info __attribute__((aligned(sizeof(uint32_t))));
static uint8_t app_symbol_calendar_on = 0; //номер отображаемого символа на дисплее задачи календаря
static uint32_t app_timeout_symbol_calendar_ms = APP_TIMEOUT_SYMBOL_CALENDAR_MAX_MS; //ms, время смены на дисплее значка задачи календаря
static uint32_t app_timeout_update_ms = 0;
static uint16_t app_symbol_update_dysplay = 0;
static uint32_t app_timeout_service_menu = 0;
//static uint32_t app_timeout_heat_error = 0;
static bool fl_inc_set_heat = false; //флаг разрешения инкремента кол-ва включений реле
static app_data_service_menu_t app_data_service_menu;
static uint32_t app_timeout_test = 0;
static bool app_update_fw_fl = false;
/********* FUNCTION PROTOTYPES **************************************************/
void api_create_case_calendar(app_state_t state);
static void app_set_relay(void);
static void app_clear_relay(bool reach);
/********* FUNCTIONS IMPLEMENTATION *********************************************/
/********************************************************************************
*
********************************************************************************/
/**@brief Обработчик таймера таймаута.
*
* @param none
*
* @return none
*/
static void app_timeout_timer_handler( void* p_context )
{
AppTimeoutFl = true;
return;
}
static void app_timeout_before_calendar_handler(void* p_context)
{
if(app_state_err[app_state_device.app_sensor_se] != APP_ERROR_NO && app_state_err[app_state_device.app_sensor_se] != APP_ERROR_AIR_LESS_MIN) return;
app_state_hand.app_sensor_custom_set = app_state_hand.app_sensor_active_set;
app_state_hand.app_sensor_active_set = app_state_hand.app_sensor_calendar_set;
api_start();
return;
}
#ifdef DEBUG_LOG_TEMP
static uint32_t app_timeout_log_temp = 0;
static bool app_flg_log_temp = false;
#endif
/**@brief Обработчик таймера 10 ms таймаута.
*
* @param none
*
* @return none
*/
static void app_timeout_timer_10ms_handler( void* p_context )
{
static uint32_t timer_log_ms = 0;
#ifdef DEBUG_LOG_TEMP
if(app_timeout_log_temp) app_timeout_log_temp -= APP_TIMEOUT_CUSTOM_10MS;
else{ app_timeout_log_temp = 10000; app_flg_log_temp = true; }
#endif
if(app_timeout_adv_ms) app_timeout_adv_ms -= APP_TIMEOUT_CUSTOM_10MS;
else{ app_timeout_adv_ms = APP_TIMEOUT_ADV_CUSTOM; app_timeout_adv_en = true; }
if(app_timeout_update_ms) app_timeout_update_ms -= APP_TIMEOUT_CUSTOM_10MS;
if(app_timeout_service_menu) app_timeout_service_menu -= APP_TIMEOUT_CUSTOM_10MS;
app_timeout_blink_10ms += APP_TIMEOUT_CUSTOM_10MS;
++app_timeout_ind_pairing_10ms;
if(app_timeout_test_10ms) --app_timeout_test_10ms;
if(app_timeout_ind_change_state_10ms) app_timeout_ind_change_state_10ms -= APP_TIMEOUT_CUSTOM_10MS;
if(app_timeout_illumination_10s) app_timeout_illumination_10s -= APP_TIMEOUT_CUSTOM_10MS;
else if(!app_blink_num) nrf_gpio_pin_clear(BL_PIN);
if(app_timeout_on_relay_ms) app_timeout_on_relay_ms -= APP_TIMEOUT_CUSTOM_10MS;
if(app_timeout_test) app_timeout_test -= APP_TIMEOUT_CUSTOM_10MS;
app_timeout_symbol_calendar_ms -= APP_TIMEOUT_CUSTOM_10MS;
if(!app_timeout_symbol_calendar_ms){
++app_symbol_calendar_on;
app_symbol_calendar_on %= 4;
app_timeout_symbol_calendar_ms = APP_TIMEOUT_SYMBOL_CALENDAR_MAX_MS;
}
if(nrf_gpio_pin_read(RELE_PIN))
{
app_selfteaching_time_ms += APP_TIMEOUT_CUSTOM_10MS; //подсчет времени нагрева до температуры установки
// app_timeout_heat_error += APP_TIMEOUT_CUSTOM_10MS; //подсчет времени нагрева до времени ошибки
timer_log_ms += APP_TIMEOUT_CUSTOM_10MS; //подсчет времени работы реле для статистики
if(timer_log_ms >= 1000){
++app_state_device_log.app_timer_power_on;
timer_log_ms = 0;
}
}
// else
// {
// if(app_timeout_heat_error < APP_TIMEOUT_HEAT_ERROR) app_timeout_heat_error = 0;
// }
if(app_timeout_blink_calendar_10ms) app_timeout_blink_calendar_10ms -= APP_TIMEOUT_CUSTOM_10MS;
}
/**
* @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){
// APP_PRINTF(0, "calendar task\n");
if(p_data == NULL || app_state_device.app_calendar_en) return;
if(app_state_err[app_state_device.app_sensor_se] != APP_ERROR_NO && app_state_err[app_state_device.app_sensor_se] != APP_ERROR_AIR_LESS_MIN) return;
switch(p_data->array[1])
{
case AC_EXTENTION_TEMP_SFLOAT_CMD:
{
exten_req_temp_sfloat_cmd_t* reg_temp_sfloat = (exten_req_temp_sfloat_cmd_t*)&p_data->array[2];
float temp_set = SFloat16ToFloat(reg_temp_sfloat->param1);
if(temp_set<APP_ALARM_TEMPERATURE_BOTTOM || temp_set > APP_CUSTOM_TEMPERATURE_TOP) break;
app_state_hand.app_sensor_calendar_set = temp_set;
app_timeout_before_calendar_handler(NULL);
break;
}
case AC_EXTENTION_STOP_CMD:
{
api_stop();
break;
}
case AC_EXTENTION_START_CMD:
{
api_start();
break;
}
case AC_EXTENTION_SWITCH_CMD:
{
api_switch();
break;
}
default:
{
break;
}
}
return;
}
static void evcal_calendar_before_task(evcal_info_packet_t const*p_data){
if(p_data == NULL || !app_state_device.app_selfteaching_en || app_state_device.app_calendar_en) return;
switch(p_data->array[1])
{
case AC_EXTENTION_TEMP_SFLOAT_CMD:
{
exten_req_temp_sfloat_cmd_t* reg_temp_sfloat = (exten_req_temp_sfloat_cmd_t*)&p_data->array[2];
//текущее значение температуры
float temp;
api_get_temp_value_with_calibration(app_state_device.app_sensor_se, &temp);
float temp_set = SFloat16ToFloat(reg_temp_sfloat->param1);
if(temp_set<APP_ALARM_TEMPERATURE_BOTTOM || temp_set > APP_CUSTOM_TEMPERATURE_TOP) break;
// проверка на большую температуру
app_state_hand.app_sensor_calendar_set = temp_set;
uint32_t timeout = (temp_set - temp)*app_state_device.app_selfteaching_time_s; //
if(timeout >= APP_TIME_CALENDAR_BEFORE) app_timeout_before_calendar_handler(NULL);
else APP_ERROR_CHECK(app_timer_start(app_timer_before_cal_id,APP_TIMER_TICKS((APP_TIME_CALENDAR_BEFORE-timeout)*1000, APP_TIMER_PRESCALER), NULL ));
break;
}
}
return;
}
void *application_get_adr_data(void)
{
app_pof_info.b_sensor_se = app_state_device.app_sensor_se;
app_pof_info.b_off_en = app_state_device.app_off_en;
app_pof_info.b_lock_en = app_state_device.app_lock_en;
app_pof_info.b_contrast = app_state_device.app_contrast;
app_pof_info.b_calendar_en = app_state_device.app_calendar_en;
app_pof_info.b_selfteaching_en = app_state_device.app_selfteaching_en;
app_pof_info.floor_sensor_idx = app_state_device.app_floor_sensor_idx;
app_pof_info.floor_sensor_calib = app_state_device.app_floor_sensor_calib;
app_pof_info.air_sensor_calib = app_state_device.app_air_sensor_calib;
app_pof_info.sensor_hysteresis = app_state_device.app_hysteresis;
app_pof_info.sensor_custom_set = app_state_hand.app_sensor_custom_set;
app_pof_info.sensor_active_set = app_state_hand.app_sensor_active_set;
app_pof_info.timer_power_on = app_state_device_log.app_timer_power_on;
app_pof_info.count_set_relay = app_state_device_log.app_count_set_relay;
app_pof_info.custom_power = app_state_device.app_custom_power;
app_pof_info.selfteaching_time_s = app_state_device.app_selfteaching_time_s;
app_pof_info.shift_utc = app_state_device.app_shift_utc;
app_pof_info.state = app_state;
return &app_pof_info;
}
/********************************************************************************
* индикация
********************************************************************************/
/**
* @brief Вывод числа на дисплей.
*
* @param[in] digit_index - начальный индекс числа на дисплее. Значения согласно DISPLAY_DIGIT_INDEX
* @param[in] len - кол-во цифр для вывода на дисплей
* @param[in] digit_int - число
* @param[in] state - состояние (1/0 - отображать/не отображать)
*
* @return - нет
*/
static void app_digit_get_symbol(uint8_t digit_index, uint8_t len, int16_t digit_int, uint8_t state)
{
uint16_t del;
bool negative = false;
//проверка на меньше 0
if(digit_int<0){negative = true; digit_int = abs(digit_int);}
//проверка числа на максимальное выводимое на дисплей число
if(!negative) del = pow(10, len)-1;
else del = pow(10, len-1)-1;
if(digit_int > del) digit_int = del;
if(negative){
if(state) display_write_digit_data(digit_index, display_symbol_get_symbol('-'));
else display_write_digit_data(digit_index, 0); //не выводит символ
++digit_index;
del = pow(10, len-2);
}
else
del = pow(10, len-1);
//расклад числа на символы
for(uint8_t i = digit_index; i < digit_index+len; ++i){
if(state) display_write_digit_data(i, display_digit_get_symbol((uint8_t)(digit_int/del)));
else display_write_digit_data(i, 0); //не выводит символ
digit_int %= del;
del /=10;
}
}
/**
* @brief Вывод символов на дисплей.
*
* @param[in] digit_index - начальный индекс числа на дисплее. Значения согласно DISPLAY_DIGIT_INDEX
* @param[in] len - кол-во цифр для вывода на дисплей
* @param[in] digit_int - число
* @param[in] state - состояние (1/0 - отображать/не отображать)
*
* @return - нет
*/
static void app_symbol_get_symbol(uint8_t symbol_index, uint8_t len, uint8_t* str, uint8_t state)
{
//проверка числа на максимальное выводимое на дисплей число
if(len != 2) return;
//расклад строки на символы
for(uint8_t i = symbol_index; i < symbol_index+len; ++i){
if(state) display_write_digit_data(i, display_symbol_get_symbol(*(str+(i-symbol_index))));
else display_write_digit_data(i, 0); //не выводит символ
}
}
/**
* @brief Отображение температуры.
*
* @param[in] state - маска состояния символов (1/0 - отображать/не отображать)
* 0x01 - тип датчика (датчик воздуха)
* 0x02 - тип датчика (датчик пола)
* 0x04 - текущая температура
* 0x08 - установленная температура
* 0xF0 - 0
* @param[in] temp - текущая температура
* @param[in] set_temp - установленная температура
*
*
* @return NRF_SUCCESS успешно
* @return NRF_ERROR_INVALID_PARAM недопустимые входные параметры
*/
static uint32_t app_ind_temp(float temp, float set_temp, uint8_t state)
{
if( state & 0xF0) return NRF_ERROR_INVALID_PARAM;
//отображение символов
for(uint8_t i=0, mask = 0x01; i<TEMPS_COUNT; ++i, mask <<= 1)
{
if(!(mask&state)) display_write_symbol_data(SYMBOL_TEMPS[i], 0);
else display_write_symbol_data(SYMBOL_TEMPS[i], 1);
}
if(state == 0)
display_write_symbol_data(SYMBOL_TEMPS[0], 0);
//отображение текущей температуры
app_digit_get_symbol( APP_SYMBOL_DIGIT_TEMP_ADDR, \
APP_SYMBOL_DIGIT_SET_TEMP_ADDR - APP_SYMBOL_DIGIT_TEMP_ADDR, \
(uint16_t)((((uint16_t)(temp/0.5+0.5))*0.5)*10), \
((state&CURRENT_TEMP_IND)?(1):(0)));
//отображения установленной температуры
app_digit_get_symbol( APP_SYMBOL_DIGIT_SET_TEMP_ADDR, \
APP_SYMBOL_DIGIT_HOURS_ADDR - APP_SYMBOL_DIGIT_SET_TEMP_ADDR, \
(uint16_t)((((uint16_t)(set_temp/0.5+0.5))*0.5)*10), \
((state&SET_TEMP_IND)?(1):(0)));
return NRF_SUCCESS;
}
/**
* @brief Отображение часов.
*
* @param[in] hour - часы
* @param[in] minute - минуты
* @param[in] state - состояние (1/0 - отображать/не отображать)
*
*
* @return NRF_SUCCESS успешно
* @return NRF_ERROR_INVALID_PARAM недопустимые входные параметры
*/
static uint32_t app_ind_clock(uint8_t hour, uint8_t minute, uint8_t state)
{
if( hour >= 24 || minute >= 60){
hour = 0; minute = 0;
}
//отображение чаcа
app_digit_get_symbol(APP_SYMBOL_DIGIT_HOURS_ADDR, 1, 0, 0);
uint8_t add_adr = 0;
if(hour<10) ++add_adr;
app_digit_get_symbol( APP_SYMBOL_DIGIT_HOURS_ADDR+add_adr, \
APP_SYMBOL_DIGIT_HOURS_ADDR - APP_SYMBOL_DIGIT_SET_TEMP_ADDR-1-add_adr, \
hour, \
((state&0x01)?(1):(0)));
//отображения минут
app_digit_get_symbol( APP_SYMBOL_DIGIT_MINUTES_ADDR, \
APP_SYMBOL_DIGIT_MINUTES_ADDR - APP_SYMBOL_DIGIT_HOURS_ADDR, \
minute, \
((state&0x02)?(1):(0)));
display_write_symbol_data(SYMBOL_CLOCK_DOT, ((state&0x04)?(1):(0)));
return NRF_SUCCESS;
}
/********************************************************************************
* индикация режимов
********************************************************************************/
static void disp_clear()
{
display_write_symbol_data(SYMBOL_HAND, 0);
display_write_symbol_data(SYMBOL_ANTI_FROST, 0);
display_write_symbol_data(SYMBOL_HEAT, nrf_gpio_pin_read(RELE_PIN));
display_write_symbol_data(SYMBOL_LOCK, app_state_device.app_lock_en);
//отображение событий
app_ind_event(0);
}
//****************************************
//************ режим ВЫКЛ ****************
static void app_ind_off()
{
disp_clear();
//отображение температур и датчика
app_ind_temp(0, 0, 0);
//отображение времени
app_ind_clock(0, 0, 0);
app_ind_week(0x80);
}
typedef enum{
IND_CLOCK_EDIT_HOUR = 0,
IND_CLOCK_EDIT_MINUTE = 1,
IND_CLOCK_EDIT_DOT = 2,
}ind_clock_edit_t;
//********* режим CLOCK EDIT *************
static void app_ind_clock_edit()
{
if(app_timeout_blink_10ms >= APP_TIMEOUT_BLINK_10MS) app_timeout_blink_10ms = 0;
disp_clear();
app_ind_temp( 0, 0, 0);
//время
uint8_t state;
if(app_timeout_blink_10ms < APP_ON_BLINK_10MS || app_state_clock_edit.element_edit > 1) state = (1<<IND_CLOCK_EDIT_HOUR)|(1<<IND_CLOCK_EDIT_MINUTE)|(1<<IND_CLOCK_EDIT_DOT);
else if(app_state_clock_edit.element_edit == 0) state = (1<<IND_CLOCK_EDIT_MINUTE)|(1<<IND_CLOCK_EDIT_DOT);
else if(app_state_clock_edit.element_edit == 1) state = (1<<IND_CLOCK_EDIT_HOUR)|(1<<IND_CLOCK_EDIT_DOT);
pcf8563_date_time_t time;
calendar_utc_t timestamp;
calendar_shift_utc_t shift;
calendar_get_utc_time(×tamp, &shift);
utc_to_date(timestamp+shift, &time);
app_ind_clock(time.hours, time.minutes, state);
if(app_state_clock_edit.element_edit == 2 && app_timeout_blink_10ms > APP_ON_BLINK_10MS) app_ind_week(0);
else app_ind_week(day_of_week(&time));
}
//************ режим TEST ****************
static void app_ind_test()
{
if(app_test_stage == 0){
if(app_timeout_illumination_10s) nrf_gpio_pin_set(BL_PIN);
//отображение режимов
display_write_symbol_data(SYMBOL_HAND, 0);
display_write_symbol_data(SYMBOL_HEAT, 1);
display_write_symbol_data(SYMBOL_LOCK, 1);
display_write_symbol_data(SYMBOL_ANTI_FROST, 1);
//отображение температур и датчика
app_ind_temp( 88.5, 88.5, (TYPE_FLOOR_SENSOR_IND|TYPE_AIR_SENSOR_IND|CURRENT_TEMP_IND|SET_TEMP_IND));
//отображение времени
app_digit_get_symbol(APP_SYMBOL_DIGIT_HOURS_ADDR, 2, 28, 1);
//отображения минут
app_digit_get_symbol(APP_SYMBOL_DIGIT_MINUTES_ADDR, 2,88, 1);
display_write_symbol_data(SYMBOL_CLOCK_DOT, 1);
app_ind_week(MONDAY_IND|TUESDAY_IND|FRIDAY_IND|THURSDAY_IND|WEDNESDAY_IND|SUNDAY_IND|SATURDAY_IND);
app_ind_event(0x0F);
}
else{
//отображение режимов
display_write_symbol_data(SYMBOL_HAND, 0);
if(app_test_stage == 1) display_write_symbol_data(SYMBOL_HEAT, nrf_gpio_pin_read(RELE_PIN));
else display_write_symbol_data(SYMBOL_HEAT, 0);
display_write_symbol_data(SYMBOL_LOCK, 0);
display_write_symbol_data(SYMBOL_ANTI_FROST, 0);
//отображение температур и датчика
if(app_test_stage == 3){
float temp[2];
for(uint8_t i=0; i<2; ++i)
APP_ERROR_CHECK(temp_get_value(i, &temp[i]));
uint8_t str[3][3] = {"E_", "E~", "E-"};
uint8_t *p_str; p_str = 0;
if(temp[0] >= 100.f) p_str = str[0];
if(temp[0] < 0.f) p_str = str[1];
if(p_str != 0){
app_digit_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 3, 0, 0); //не отображаем дробную часть
app_symbol_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 2, p_str, 1);
display_write_symbol_data(SYMBOL_B_CELSIUS, 0); //не отображаем знак сельсия
}else{
app_digit_get_symbol( APP_SYMBOL_DIGIT_TEMP_ADDR, \
APP_SYMBOL_DIGIT_SET_TEMP_ADDR - APP_SYMBOL_DIGIT_TEMP_ADDR, \
(uint16_t)((((uint16_t)(temp[0]/0.5+0.5))*0.5)*10), \
(TYPE_AIR_SENSOR_IND|CURRENT_TEMP_IND|SET_TEMP_IND));
display_write_symbol_data(SYMBOL_B_CELSIUS, 0);
}
p_str = 0;
if(temp[1] >= 100.f) p_str = str[0];
if(temp[1] < 0.f) p_str = str[1];
if(app_level_err_test_fl == true) p_str = str[2];
if(p_str != 0){
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, 0, 0); //не отображаем дробную часть
app_symbol_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 2, p_str, 1);
display_write_symbol_data(SYMBOL_L_CELSIUS, 0); //не отображаем знак сельсия
}
else{
//отображения установленной температуры
app_digit_get_symbol( APP_SYMBOL_DIGIT_SET_TEMP_ADDR, \
APP_SYMBOL_DIGIT_HOURS_ADDR - APP_SYMBOL_DIGIT_SET_TEMP_ADDR, \
(uint16_t)((((uint16_t)(temp[1]/0.5+0.5))*0.5)*10), \
1);
display_write_symbol_data(SYMBOL_L_CELSIUS, 1);
}
// APP_ERROR_CHECK(app_ind_temp(temp[0], temp[1], (TYPE_AIR_SENSOR_IND|CURRENT_TEMP_IND|SET_TEMP_IND)));
}
else app_ind_temp(0, 0, 0);
//отображение времени
app_ind_clock(0, 0, 0);
app_ind_week(0x80);
//отображение событий
app_ind_event(0);
if(app_test_stage == 2){
app_ind_week(app_test_btn_mask);
}else
app_ind_week(0);
}
}
//********************************************
//************ режим ОЖИДАНИЯ ****************
static void app_ind_stand_by()
{
if(app_timeout_blink_10ms >= APP_TIMEOUT_BLINK_10MS) app_timeout_blink_10ms = 0;
//отображение режимов
//символ "РУЧНОЕ УПРАВЛЕНИЕ" не отображается
display_write_symbol_data(SYMBOL_HAND, false);
//символ "НАГРЕВ" отображается, если включено реле
display_write_symbol_data(SYMBOL_HEAT, nrf_gpio_pin_read(RELE_PIN));
//символ "БЛОКИРОВКА" отображается, если блокировка включена
display_write_symbol_data(SYMBOL_LOCK, app_state_device.app_lock_en);
//символ "РЕЖИМ АНТИЗАМЕРЗАНИЯ" включен, если температура установки меньше APP_ALARM_TEMPERATURE_ANTI_FROST
display_write_symbol_data(SYMBOL_ANTI_FROST, (app_state_hand.app_sensor_active_set <= APP_ALARM_TEMPERATURE_ANTI_FROST)&& app_state_device.app_off_en == false);
//символы "СОБЫТИЕ" включены, если запущен календарь
uint8_t num;
evcal_get_task_number(&num);
if(num && app_state_device.app_calendar_en == false)
app_ind_event(1<<app_symbol_calendar_on);
else{
if((app_timeout_blink_calendar_10ms%APP_TIMEOUT_BLINK_10MS) < APP_OFF_BLINK_10MS) app_ind_event(0);
else app_ind_event(0x0F);
}
//отображение температур и датчика
float temp[2];
for(uint8_t i=0; i<2; ++i)
APP_ERROR_CHECK(api_get_temp_value_with_calibration(i, &temp[i]));
float temp_cur = temp[app_state_device.app_sensor_se];
// ошибка текущей температуры: меньше минимальной допустимой
uint8_t str[4][3] = {"LO", "HI", "E_", "E-"};
uint8_t str0[3] = {"--"};
if(fl_over_hi){
//перегрев
app_digit_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 3, 0, 0); //не отображаем дробную часть
app_symbol_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 2, str[1], ((app_timeout_blink_10ms <= APP_ON_BLINK_10MS)?(1):(0)));
display_write_symbol_data(SYMBOL_B_CELSIUS, 0); //не отображаем знак сельсия
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, (uint16_t)((((uint16_t)(app_state_hand.app_sensor_active_set/0.5+0.5))*0.5)*10), 1);
display_write_symbol_data(SYMBOL_L_CELSIUS, 1);
}else{
switch(app_state_err[app_state_device.app_sensor_se]){
case APP_ERROR_NO:
{
float temp = app_state_hand.app_sensor_active_set;
if(app_state_device.app_off_en){
app_ind_temp( temp_cur, temp, \
(((app_state_device.app_sensor_se==APP_ACTIVE_AIR_SENSOR)?(TYPE_AIR_SENSOR_IND):(TYPE_FLOOR_SENSOR_IND))|CURRENT_TEMP_IND));
// app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 2, app_data_service_menu.app_floor_sensor_idx, 1);
app_symbol_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 2, str0, 1);
}
else
app_ind_temp( temp_cur, temp, \
(((app_state_device.app_sensor_se==APP_ACTIVE_AIR_SENSOR)?(TYPE_AIR_SENSOR_IND):(TYPE_FLOOR_SENSOR_IND))|CURRENT_TEMP_IND|SET_TEMP_IND));
break;
}
case APP_ERROR_FLOOR_LESS_MIN:
case APP_ERROR_AIR_LESS_MIN:
{
app_digit_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 3, 0, 0); //не отображаем дробную часть
app_symbol_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 2, str[0], ((app_timeout_blink_10ms <= APP_ON_BLINK_10MS)?(1):(0)));
display_write_symbol_data(SYMBOL_B_CELSIUS, 0); //не отображаем знак сельсия
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, (uint16_t)((((uint16_t)(app_state_hand.app_sensor_active_set/0.5+0.5))*0.5)*10), 1);
display_write_symbol_data(SYMBOL_L_CELSIUS, 1);
display_write_symbol_data(SYMBOL_TEMPS[0], 0);
display_write_symbol_data(SYMBOL_TEMPS[1], 0);
display_write_symbol_data(SYMBOL_TEMPS[(app_state_device.app_sensor_se==APP_ACTIVE_AIR_SENSOR)?(0):(1)], 1);
break;
}
case APP_ERROR_FLOOR_OVER_MAX:
case APP_ERROR_AIR_OVER_MAX:
{
app_digit_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 3, 0, 0); //не отображаем дробную часть
app_symbol_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 2, str[1], ((app_timeout_blink_10ms <= APP_ON_BLINK_10MS)?(1):(0)));
display_write_symbol_data(SYMBOL_B_CELSIUS, 0); //не отображаем знак сельсия
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, (uint16_t)((((uint16_t)(app_state_hand.app_sensor_active_set/0.5+0.5))*0.5)*10), 1);
display_write_symbol_data(SYMBOL_L_CELSIUS, 1);
break;
}
case APP_ERROR_FLOOR_SENSOR_DROP:
case APP_ERROR_AIR_SENSOR_DROP:
{
app_digit_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 3, 0, 0); //не отображаем дробную часть
app_symbol_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 2, str[2], 1);
display_write_symbol_data(SYMBOL_B_CELSIUS, 0); //не отображаем знак сельсия
display_write_symbol_data(((app_state_device.app_sensor_se==APP_ACTIVE_AIR_SENSOR)?(SYMBOL_AIR_TEMP):(SYMBOL_FLOOR_TEMP)), ((app_timeout_blink_10ms <= APP_ON_BLINK_10MS)?(1):(0)));
display_write_symbol_data(((app_state_device.app_sensor_se!=APP_ACTIVE_AIR_SENSOR)?(SYMBOL_AIR_TEMP):(SYMBOL_FLOOR_TEMP)), 0);
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, (uint16_t)((((uint16_t)(app_state_hand.app_sensor_active_set/0.5+0.5))*0.5)*10), 1);
display_write_symbol_data(SYMBOL_L_CELSIUS, 1);
break;
}
case APP_ERROR_FLOOR_SENSOR_LOWER:
case APP_ERROR_AIR_SENSOR_LOWER:
{
app_digit_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 3, 0, 0); //не отображаем дробную часть
app_symbol_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 2, str[3], 1);
display_write_symbol_data(SYMBOL_B_CELSIUS, 0); //не отображаем знак сельсия
display_write_symbol_data(((app_state_device.app_sensor_se==APP_ACTIVE_AIR_SENSOR)?(SYMBOL_AIR_TEMP):(SYMBOL_FLOOR_TEMP)), ((app_timeout_blink_10ms <= APP_ON_BLINK_10MS)?(1):(0)));
display_write_symbol_data(((app_state_device.app_sensor_se!=APP_ACTIVE_AIR_SENSOR)?(SYMBOL_AIR_TEMP):(SYMBOL_FLOOR_TEMP)), 0);
display_write_symbol_data(SYMBOL_B_CELSIUS, 0); //не отображаем знак сельсия
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, (uint16_t)((((uint16_t)(app_state_hand.app_sensor_active_set/0.5+0.5))*0.5)*10), 1);
display_write_symbol_data(SYMBOL_L_CELSIUS, 1);
break;
}
}
}
//отображение времени
pcf8563_date_time_t time;
calendar_utc_t timestamp;
calendar_shift_utc_t shift;
calendar_get_utc_time(×tamp, &shift);
utc_to_date(timestamp+shift, &time);
app_ind_clock(time.hours, time.minutes, (1<<IND_CLOCK_EDIT_HOUR)|(1<<IND_CLOCK_EDIT_MINUTE)|(1<<IND_CLOCK_EDIT_DOT));
app_ind_week(day_of_week(&time));
}
//******************************************
static void app_ind_service_menu()
{
disp_clear();
app_digit_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 2, app_state_service_menu.sm_index_menu, 1);
//отображение температур и датчика
switch(app_state_service_menu.sm_index_menu)
{
case SM_FLOOR_SENSOR_IDX_01:
{
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, 0, 0); //не отображаем дробную часть
display_write_symbol_data(SYMBOL_L_CELSIUS, 0); //не отображаем знак сельсия
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 2, app_data_service_menu.app_floor_sensor_idx, 1);
break;
}
case SM_HYSTERESIS_02:
{
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, app_data_service_menu.app_hysteresis*10, 1);
display_write_symbol_data(SYMBOL_L_CELSIUS, 1);
break;
}
case SM_CALIB_AIR_03:
{
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, app_data_service_menu.app_air_sensor_calib*10, 1);
display_write_symbol_data(SYMBOL_L_CELSIUS, 1);
break;
}
case SM_CALIB_FLOOR_04:
{
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, app_data_service_menu.app_floor_sensor_calib*10, 1);
display_write_symbol_data(SYMBOL_L_CELSIUS, 1);
break;
}
case SM_CONTRAST_05:
{
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, 0, 0); //не отображаем дробную часть
display_write_symbol_data(SYMBOL_L_CELSIUS, 0); //не отображаем знак сельсия
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 2, app_data_service_menu.app_contrast, 1);
break;
}
case SM_CLEAN_SETTING_06:
{
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, 0, 0); //не отображаем дробную часть
display_write_symbol_data(SYMBOL_L_CELSIUS, 0); //не отображаем знак сельсия
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 2, (!app_state_service_menu.sm_clean_setting)?(0):(3), 1);
break;
}
}
//отображение времени
app_ind_clock(0, 0, 0);
app_ind_week(0);
}
void app_ind_pairing()
{
if(app_timeout_ind_pairing_10ms >= 70) app_timeout_ind_pairing_10ms = 0;
disp_clear();
//отображение температур и тип датчика
APP_ERROR_CHECK(app_ind_temp(0, 0, 0));
if(AppTimeoutFl == false){
display_write_digit_data(APP_SYMBOL_DIGIT_TEMP_ADDR, display_symbol_get_symbol(((app_timeout_ind_pairing_10ms>50)?(1):(2))));
display_write_digit_data(APP_SYMBOL_DIGIT_TEMP_ADDR+1, display_symbol_get_symbol(((app_timeout_ind_pairing_10ms>50)?(2):(1))));
}else{
uint8_t str[] = "OO";
app_symbol_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 2, str, 1);
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, 0, 0); //не отображаем дробную часть
display_write_symbol_data(SYMBOL_L_CELSIUS, 0); //не отображаем знак сельсия
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 2, 0, 0); //отображаем целую часть
}
//отображение времени
app_ind_clock(0, 0, 0);
app_ind_week(0);
}
//********************************************
//************ ****************
void application_init(void)
{
APP_ERROR_CHECK(app_timer_create( &app_timer_id, APP_TIMER_MODE_SINGLE_SHOT, app_timeout_timer_handler ));
APP_ERROR_CHECK(app_timer_create( &app_timer_10ms_id, APP_TIMER_MODE_REPEATED, app_timeout_timer_10ms_handler ));
APP_ERROR_CHECK(app_timer_start(app_timer_10ms_id, APP_TIMER_TICKS(APP_TIMEOUT_CUSTOM_10MS, APP_TIMER_PRESCALER), NULL ));
APP_ERROR_CHECK(app_timer_create(&app_timer_before_cal_id, APP_TIMER_MODE_SINGLE_SHOT, app_timeout_before_calendar_handler));
//инициализация реле
NRF_GPIO->OUTCLR = (1UL << RELE_PIN);
NRF_GPIO->PIN_CNF[RELE_PIN] = (GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos) \
| (GPIO_PIN_CNF_PULL_Pulldown << 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->OUTCLR = (1UL << BL_PIN);
NRF_GPIO->PIN_CNF[BL_PIN] = (GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos) \
| (GPIO_PIN_CNF_PULL_Pulldown << 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->OUTCLR = (1UL << UNUSED10_PIN);
// NRF_GPIO->PIN_CNF[UNUSED10_PIN] = (GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos) \
// | (GPIO_PIN_CNF_PULL_Pulldown << 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(calendar_set_one_sec_callback(calendar_one_sec_handle)); //установка callback часов
APP_ERROR_CHECK(evcal_set_callback(evcal_calendar_task)); //установка callback при срабатывании расписания
APP_ERROR_CHECK(evcal_set_before_callback(evcal_calendar_before_task)); //установка callback при срабатывании расписания
APP_ERROR_CHECK(evcal_set_offset_task(APP_TIME_CALENDAR_BEFORE, 0));
api_param_update();
// calendar_utc_t timestamp;
// calendar_shift_utc_t shift;
// calendar_get_utc_time(×tamp, &shift);
return;
}
}
/**@brief Функция выполняет работу при входе в новое состояние
*
* @param none
*
* @return none
*/
static void application_init_new_state( app_state_t app_new_state )
{
static app_state_t app_prew_state = APP_START;
if( app_prew_state == app_new_state )return;
switch( app_new_state )
{
case APP_OFF:
{
// APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_OFF\r\n"RTT_CTRL_RESET);
// app_timeout_heat_error = 0;
APP_ERROR_CHECK(r4s_slave_disconnect());
APP_ERROR_CHECK(r4s_slave_adv_disable());
//выключаем подсветку
nrf_gpio_pin_clear(BL_PIN);
app_ind_temp( 88.5, 88.5, (TYPE_FLOOR_SENSOR_IND|TYPE_AIR_SENSOR_IND|CURRENT_TEMP_IND|SET_TEMP_IND));
// app_prev_off_state = app_prew_state;
break;
}
case APP_START:
{
// APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_START\r\n"RTT_CTRL_RESET);
break;
}
case APP_TEST:
{
// APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_TEST\r\n"RTT_CTRL_RESET);
app_test_stage = 0;
// app_timeout_test_10ms = APP_TEST_TIMEOUT_STAGES_10MS;
app_test_btn_mask = MONDAY_IND|TUESDAY_IND|FRIDAY_IND|THURSDAY_IND|WEDNESDAY_IND;
app_timeout_test = APP_TIMEOUT_TEST;
break;
}
case APP_STAND_BY:
{
// APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_STAND_BY\r\n"RTT_CTRL_RESET);
break;
}
case APP_PREPAIRING:
{
// APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_PREPAIRING\r\n"RTT_CTRL_RESET);
app_timeout_ind_pairing_10ms = 0;
app_blink_num = 1;
nrf_gpio_pin_set(BL_PIN);
break;
}
case APP_PREUNPAIRING:
{
// APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_PREUNPAIRING\r\n"RTT_CTRL_RESET);
app_timeout_ind_pairing_10ms = 0;
app_blink_num = 1;
nrf_gpio_pin_set(BL_PIN);
break;
}
case APP_PAIRING:
{
// APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_PAIRING\r\n"RTT_CTRL_RESET);
app_timeout_ind_change_state_10ms = 3000;
r4s_enable_bonding();
// app_pairing_set();
APP_ERROR_CHECK(app_timer_stop(app_timer_id));
AppTimeoutFl = false;
APP_ERROR_CHECK(app_timer_start(app_timer_id,APP_TIMER_TICKS(APP_PAIRING_TIMEOUT_MS, APP_TIMER_PRESCALER), NULL ));
// com_master_pairing_start(&m_required_ac);
app_advertising_set_paring_flag();
break;
}
case APP_UNPAIRING:
{
// APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_UNPAIRING\r\n"RTT_CTRL_RESET);
// com_master_unpairing();
com_slave_unpair_proccess();
api_param_update();
app_blink_num = 3;
app_timeout_ind_pairing_10ms = 0;
break;
}
#ifdef NRF51
case APP_SLAVE_FW_UPDATE:
{
// APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: >>APP_SLAVE_FW_UPDATE\r\n"RTT_CTRL_RESET);
APP_ERROR_CHECK(app_timer_stop(app_timer_id));
AppTimeoutFl = false;
APP_ERROR_CHECK(app_timer_start(app_timer_id,APP_TIMER_TICKS(APP_FW_UPDATE_TIMEOUT_MS, APP_TIMER_PRESCALER), NULL ));
app_clear_relay(false);
app_ind_off();
app_update_fw_fl = false;
break;
}
#endif
case APP_CLOCK_EDIT:
{
// APP_PRINTF(0, ">>APP_CLOCK_EDIT\n");
app_state_clock_edit_t state_case_edit = APP_STATE_CLOCK_EDIT_DEFAULT();
memcpy(&app_state_clock_edit, &state_case_edit, sizeof(app_state_clock_edit_t));
app_first_press_menu = false;
break;
}
case APP_SERVICE_MENU:
{
// APP_PRINTF(0, ">>APP_SERVICE_MENU\n");
app_state_service_menu.sm_index_menu = SM_FLOOR_SENSOR_IDX_01;
app_state_service_menu.sm_clean_setting = false;
app_timeout_service_menu = APP_TIMEOUT_SERVICE_MENU;
//копируем данные во временную структуру
app_data_service_menu.app_air_sensor_calib = app_state_device.app_air_sensor_calib;
app_data_service_menu.app_floor_sensor_calib = app_state_device.app_floor_sensor_calib;
app_data_service_menu.app_contrast = app_state_device.app_contrast;
app_data_service_menu.app_floor_sensor_idx = app_state_device.app_floor_sensor_idx;
app_data_service_menu.app_hysteresis = app_state_device.app_hysteresis;
break;
}
default:
{
break;
}
}
app_prew_state = app_new_state;
return;
}
static void app_service_menu_handler(const btn_data_t* p_keyb_data)
{
switch(app_state_service_menu.sm_index_menu)
{
case SM_HYSTERESIS_02:
{
//изменение гистирезиса для порога срабатывания напольного температурного датчика
if((p_keyb_data->code_press == BTN_UP)&&(app_data_service_menu.app_hysteresis < APP_HYSTERESIS_MAX))
app_data_service_menu.app_hysteresis += APP_HYSTERESIS_STEP;
if((p_keyb_data->code_press == BTN_DOWN)&&(app_data_service_menu.app_hysteresis > APP_HYSTERESIS_MIN))
app_data_service_menu.app_hysteresis -= APP_HYSTERESIS_STEP;
break;
}
case SM_CALIB_AIR_03:
{
//изменение значения калибровки температурного датчика воздуха
if((p_keyb_data->code_press == BTN_UP)&&(app_data_service_menu.app_air_sensor_calib < CALIB_SENSOR_AIR_MAX))
app_data_service_menu.app_air_sensor_calib += CALIB_SENSOR_AIR_STEP;
if((p_keyb_data->code_press == BTN_DOWN)&&(app_data_service_menu.app_air_sensor_calib > CALIB_SENSOR_AIR_MIN))
app_data_service_menu.app_air_sensor_calib -= CALIB_SENSOR_AIR_STEP;
break;
}
case SM_CALIB_FLOOR_04:
{
//изменение значения калибровки напольного температурного датчика
if((p_keyb_data->code_press == BTN_UP)&&(app_data_service_menu.app_floor_sensor_calib < CALIB_SENSOR_FLOOR_MAX))
app_data_service_menu.app_floor_sensor_calib += CALIB_SENSOR_FLOOR_STEP;
if((p_keyb_data->code_press == BTN_DOWN)&&(app_data_service_menu.app_floor_sensor_calib > CALIB_SENSOR_FLOOR_MIN))
app_data_service_menu.app_floor_sensor_calib -= CALIB_SENSOR_FLOOR_STEP;
break;
}
case SM_CONTRAST_05:
{
//вкл./выкл. управления устройствами в помещениии
if(p_keyb_data->code_press == BTN_UP) app_data_service_menu.app_contrast = 1;
if(p_keyb_data->code_press == BTN_DOWN) app_data_service_menu.app_contrast = 0;
display_set_bias(app_data_service_menu.app_contrast);
break;
}
case SM_FLOOR_SENSOR_IDX_01:
{
//изменение подключенного напольного датчика
if((p_keyb_data->code_press == BTN_UP)&&(app_data_service_menu.app_floor_sensor_idx < APP_FLOOR_SENSOR_IDX_MAX))
app_data_service_menu.app_floor_sensor_idx += APP_FLOOR_SENSOR_IDX_STEP;
if((p_keyb_data->code_press == BTN_DOWN)&&(app_data_service_menu.app_floor_sensor_idx > APP_FLOOR_SENSOR_IDX_MIN))
app_data_service_menu.app_floor_sensor_idx -= APP_FLOOR_SENSOR_IDX_STEP;
temp_set_idx_floor(app_data_service_menu.app_floor_sensor_idx);
break;
}
case SM_CLEAN_SETTING_06:
{
//изменение сброса до заводских настроек
if(p_keyb_data->code_press == BTN_UP) app_state_service_menu.sm_clean_setting = 1;
if(p_keyb_data->code_press == BTN_DOWN) app_state_service_menu.sm_clean_setting = 0;
break;
}
default:
{
break;
}
}
}
/********************************************************************************
*
********************************************************************************/
void application_process()
{
static uint32_t pre_time_ms = 0;
calendar_utc_t timestamp;
calendar_shift_utc_t shift;
pcf8563_date_time_t time;
//чтение состояния кнопок
btn_data_t keyb_data;
APP_ERROR_CHECK(button_read(&keyb_data));
//проверка во всех режимах факта нажатия кнопок (кроме режима ВЫКЛ - в этом режиме обрабатывается индивидуально)
if(!app_state_device.app_lock_en && app_state != APP_OFF && keyb_data.code_release != BTN_ALL_RELEASE){
app_timeout_illumination_10s = APP_TIMEOUT_ILLUMINATION_MS; //запуск timeout подсветки экрана
if(!app_blink_num) nrf_gpio_pin_set(BL_PIN); //вкл. подсветку экрана, если не в состоянии мигания
if(app_timeout_service_menu) app_timeout_service_menu = APP_TIMEOUT_SERVICE_MENU;
fl_over_hi = 0;
}
//получаем значения с температурных датчиков с калибровкой
float temp[2];
for(uint8_t i=0; i<2; ++i)
APP_ERROR_CHECK(api_get_temp_value_with_calibration(i, &temp[i]));
#ifdef DEBUG_LOG_TEMP
if(app_flg_log_temp == true){
app_flg_log_temp = false;
APP_PRINTF(0, "%d,%02d, %d,%02d\n", (uint16_t) temp[0], (uint16_t)(temp[0]*100)%100, (uint16_t) temp[1], (uint16_t)(temp[1]*100)%100);
}
#endif
//обработка ошибок
if(temp[0] >=100.f) app_state_err[0] = APP_ERROR_AIR_SENSOR_LOWER; // КЗ
else if(temp[0] < -5.f) app_state_err[0] = APP_ERROR_AIR_SENSOR_DROP; // ОБРЫВ
else if(temp[0] >= -5.f && temp[0] < APP_ALARM_TEMPERATURE_BOTTOM) app_state_err[0] = APP_ERROR_AIR_LESS_MIN;
else if(temp[0] > APP_ALARM_TEMPERATURE_TOP && temp[0] < 100.f){ app_state_err[0] = APP_ERROR_AIR_OVER_MAX; fl_over_hi = 1;}
else app_state_err[0] = APP_ERROR_NO;
if(temp[1] >=100.f) app_state_err[1] = APP_ERROR_FLOOR_SENSOR_LOWER; // КЗ
else if(temp[1]< -5.f) app_state_err[1] = APP_ERROR_FLOOR_SENSOR_DROP; // ОБРЫВ
else if(temp[1] < APP_ALARM_TEMPERATURE_BOTTOM && temp[1] >= -5.f) app_state_err[1] = APP_ERROR_FLOOR_LESS_MIN;
else if(temp[1] > APP_ALARM_TEMPERATURE_TOP && temp[1] < 100.f){ app_state_err[1] = APP_ERROR_FLOOR_OVER_MAX; fl_over_hi = 2;}
else app_state_err[1] = APP_ERROR_NO;
if(fl_over_hi && temp[0]<=25.f && temp[1]<=25.f) fl_over_hi = 0;
if(app_timeout_adv_en){
app_timeout_adv_en = false;
app_advertising_set_temp(temp[app_state_device.app_sensor_se]);
}
if(app_state != APP_START){
//если значения не дефолтные и режим не START
APP_ERROR_CHECK(pof_manager_record_enable());
}else{
APP_ERROR_CHECK(pof_manager_record_disable());
}
switch(app_state)
{
case APP_START:
{
//выключение реле
app_clear_relay(false);
uint8_t b_pof_have_data = 0;
//восстановление сохраненных конфигураций
APP_ERROR_CHECK(pof_manager_get_state(&b_pof_have_data));
// APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: pof_manager %d\r\n"RTT_CTRL_RESET, b_pof_have_data);
pcf8563_date_time_t time;
time.seconds = 0;
time.minutes = 7;
time.hours = 12;
time.days = 18;
time.weekdays = pcf8563_wednesday;
time.months = april;
time.years = 2018;
if( b_pof_have_data){
//если есть данные, которые надо восстановить
APP_ERROR_CHECK(pof_manager_copy_data()); //чтение из ПЗУ сохраненных параметров
APP_ERROR_CHECK(pof_manager_clear_memory()); //затираем данные для ускорения записи при пропадании питания
// APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: pof_manager %d\r\n"RTT_CTRL_RESET, app_pof_info.state);
app_state_device.app_sensor_se = app_pof_info.b_sensor_se;
app_state_device.app_lock_en = app_pof_info.b_lock_en;
app_state_device.app_contrast = app_pof_info.b_contrast;
app_state_device.app_calendar_en = app_pof_info.b_calendar_en;
app_state_device.app_floor_sensor_idx = app_pof_info.floor_sensor_idx;
app_state_device.app_floor_sensor_calib = app_pof_info.floor_sensor_calib;
app_state_device.app_air_sensor_calib = app_pof_info.air_sensor_calib;
app_state_device.app_hysteresis = app_pof_info.sensor_hysteresis;
app_state_device_log.app_timer_power_on = app_pof_info.timer_power_on;
app_state_device_log.app_count_set_relay = app_pof_info.count_set_relay;
app_state_device.app_custom_power = app_pof_info.custom_power;
app_state_device.app_selfteaching_en = app_pof_info.b_selfteaching_en;
app_state_device.app_selfteaching_time_s = app_pof_info.selfteaching_time_s;
app_state_device.app_off_en = app_pof_info.b_off_en;
app_state_hand.app_sensor_custom_set = app_pof_info.sensor_custom_set;
app_state_hand.app_sensor_active_set = app_pof_info.sensor_active_set;
temp_set_idx_floor(app_state_device.app_floor_sensor_idx);
display_set_bias(app_state_device.app_contrast);
app_state_device.app_shift_utc = app_pof_info.shift_utc;
do{
uint32_t utc;
uint32_t timeout = 10;
uint16_t err_code = pcf8563_get_time_utc(&utc);
if (err_code == NRF_SUCCESS) {
calendar_set_time(utc, app_state_device.app_shift_utc);
break;
}else
if(err_code == NRF_ERROR_INTERNAL) {
APP_PRINTF(0, "Cannot access\r\n");
nrf_delay_ms(100);
if(timeout-- == 0) {
APP_ERROR_CHECK(err_code);
}
continue;
}else
if(err_code != NRF_ERROR_INVALID_DATA) {
APP_ERROR_CHECK(err_code);
}else
{
pcf8563_set_time(&time);
}
}while(1);
switch(app_pof_info.state){
case APP_STAND_BY:
case APP_SLAVE_FW_UPDATE:
{
// if(app_pof_info.state == APP_SLAVE_FW_UPDATE) APP_PRINTF(0,"UPDATE\r\n");
api_state_change(APP_STAND_BY);
return;
}
default:
{
// APP_PRINTF(0,"DFAULT\r\n");
api_state_change(APP_OFF);
return;
}
}
}
pcf8563_set_time(&time);
// APP_PRINTF(0,"OFF\r\n");
temp_set_idx_floor(app_state_device.app_floor_sensor_idx);
api_state_change(APP_OFF);
return;
}
case APP_TEST:
{
if(app_timeout_test_10ms == 0 && app_test_stage == 1){ app_test_stage = 2; app_clear_relay(false); }
if(app_test_stage == 3){
float temp[4];
for(uint8_t i=0; i<=3; ++i){
NRF_GPIO->OUTSET = (1UL << TEMP_LEVEL_1);
NRF_GPIO->OUTSET = (1UL << TEMP_LEVEL_2);
NRF_GPIO->OUTSET = (1UL << TEMP_LEVEL_3);
if(i == 1) NRF_GPIO->OUTCLR = (1UL << TEMP_LEVEL_1);
if(i == 2) NRF_GPIO->OUTCLR = (1UL << TEMP_LEVEL_2);
if(i == 3) NRF_GPIO->OUTCLR = (1UL << TEMP_LEVEL_3);
nrf_delay_ms(100);
temp[i] = temp_v2_meas();
}
for(uint8_t i=1; i<=3; ++i){
if((temp[0] < temp[i]+5) && (temp[0] > temp[i]-5)) app_level_err_test_fl = true;
}
}
//управление дисплеем
app_ind_test();
if(!app_timeout_test)
{
api_state_change(APP_OFF);
}
//обработка кнопок
APP_CHANGE_LOCK_DEVICE(); //блокировка/разблокировка кнопок
if(app_state_device.app_lock_en || evcal_get_cur_transaction()) break;
if(app_test_stage != 2) APP_OFF_DEVICE(); //transition in mode APP_OFF, if press button "ON/OFF"
if(keyb_data.event_press == BTN_EVENT_CAPTURED)
{
app_timeout_test = APP_TIMEOUT_TEST;
nrf_gpio_pin_set(BL_PIN);
}
if(keyb_data.event_release == BTN_EVENT_CAPTURED){
nrf_gpio_pin_clear(BL_PIN);
if(keyb_data.code_press == BTN_MENU && app_test_stage == 0) {app_test_stage = 1; app_timeout_test_10ms = APP_TEST_TIMEOUT_STAGES_10MS; app_set_relay();}
if(keyb_data.code_press == BTN_ON && app_test_stage == 2) app_test_btn_mask &= ~MONDAY_IND;
if(keyb_data.code_press == BTN_MENU && app_test_stage == 2) app_test_btn_mask &= ~TUESDAY_IND;
if(keyb_data.code_press == BTN_CLOCK && app_test_stage == 2) app_test_btn_mask &= ~WEDNESDAY_IND;
if(keyb_data.code_press == BTN_UP && app_test_stage == 2) app_test_btn_mask &= ~THURSDAY_IND;
if(keyb_data.code_press == BTN_DOWN && app_test_stage == 2) app_test_btn_mask &= ~FRIDAY_IND;
}
if(app_test_stage == 2 && !app_test_btn_mask) app_test_stage = 3;
break;
}
case APP_PREPAIRING:
{
//обработка подсветки дисплея
if(app_blink_num && app_timeout_ind_pairing_10ms >= 70){ app_timeout_ind_pairing_10ms = 0; --app_blink_num; }
if(app_blink_num && app_timeout_ind_pairing_10ms > 30) nrf_gpio_pin_clear(BL_PIN);
if(app_blink_num && app_timeout_ind_pairing_10ms <= 30) nrf_gpio_pin_set(BL_PIN);
if(keyb_data.event_release == BTN_EVENT_CAPTURED){
api_state_change(APP_PAIRING);
}
// if( (keyb_data.code_press == BTN_MENU_UP) && (!(keyb_data.pressed_time_ms%APP_UNPAIRING_TIME_MS)&& keyb_data.pressed_time_ms))
// {
// api_state_change(APP_PREUNPAIRING);
// }
break;
}
case APP_PAIRING:
{
app_ind_pairing();
app_clear_relay(false);
if(AppTimeoutFl == false) app_timeout_ind_change_state_10ms = 3000;
if(AppTimeoutFl == true && !app_timeout_ind_change_state_10ms)
{ //таймаут пейринга
api_state_change(APP_OFF);
}
break;
}
case APP_SLAVE_FW_UPDATE:
{
//выключение реле
app_clear_relay(false);
uint8_t symbol[8][2]={{0x01, 0x00}, {0x00, 0x01}, {0x00, 0x02}, {0x00, 0x04}, {0x00, 0x08}, {0x08, 0x00}, {0x10, 0x00}, {0x20, 0x00}};
//update prosses
if(AppTimeoutFl == false && app_update_fw_fl == false){
app_blink_num = 3;
app_timeout_ind_pairing_10ms = 0;
app_timeout_ind_change_state_10ms = 3000;
if(!app_timeout_update_ms){ app_timeout_update_ms = 1000; app_symbol_update_dysplay = (app_symbol_update_dysplay+1)%8;}
display_write_digit_data(APP_SYMBOL_DIGIT_TEMP_ADDR, symbol[app_symbol_update_dysplay][0]);
display_write_digit_data(APP_SYMBOL_DIGIT_TEMP_ADDR+1, symbol[app_symbol_update_dysplay][1]);
}
//update success
if(app_update_fw_fl == true)
{
//обработка подсветки дисплея
if(app_blink_num && app_timeout_ind_pairing_10ms >= 70){ app_timeout_ind_pairing_10ms = 0; --app_blink_num; }
if(app_blink_num && app_timeout_ind_pairing_10ms <= 30) nrf_gpio_pin_set(BL_PIN);
if(app_blink_num && app_timeout_ind_pairing_10ms > 30) nrf_gpio_pin_clear(BL_PIN);
if(app_blink_num == 0){
app_timeout_ind_change_state_10ms = 0;
APP_ERROR_CHECK(r4s_slave_disconnect());
r4s_bsl_start();
}
}
//update error
if(AppTimeoutFl == true && app_update_fw_fl == false){
uint8_t str[] = "OO";
app_symbol_get_symbol(APP_SYMBOL_DIGIT_TEMP_ADDR, 2, str, 1);
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 3, 0, 0); //не отображаем дробную часть
display_write_symbol_data(SYMBOL_L_CELSIUS, 0); //не отображаем знак сельсия
app_digit_get_symbol(APP_SYMBOL_DIGIT_SET_TEMP_ADDR, 2, 0, 0); //отображаем целую часть
}
if((AppTimeoutFl == true || app_update_fw_fl == true) && !app_timeout_ind_change_state_10ms)
{
app_blink_num = 0;
api_state_change(APP_STAND_BY);
}
//проверка кнопки "ON/OFF"
APP_OFF_DEVICE(); //transition in mode APP_OFF, if press button "ON/OFF"
break;
}
case APP_OFF:
{
bool flg_press_btn = false;
//управление дисплеем
app_ind_off();
//выключение реле
app_clear_relay(false);
//обработка кнопок
// APP_CHANGE_LOCK_DEVICE(); //блокировка/разблокировка кнопок
// if(app_state_device.app_lock_en) break;
if(keyb_data.code_press == BTN_UP && keyb_data.pressed_time_ms == APP_PAIRING_TIME_MS){
//переход в режим pairing
api_state_change(APP_PREPAIRING);
}
if(keyb_data.code_press == BTN_DOWN && keyb_data.pressed_time_ms == APP_UNPAIRING_TIME_MS){
//переход в режим unpairing
api_state_change(APP_UNPAIRING);
}
if(keyb_data.event_release == BTN_EVENT_CAPTURED)
{
flg_press_btn = true;
switch(keyb_data.code_press){
case BTN_ON:
{
api_state_change(APP_STAND_BY);
break;
}
case BTN_ON_CLOCK: //переход в сервисный режим
{
api_state_change(APP_SERVICE_MENU);
break;
}
case BTN_MENU_UP: //переход в тестовый режим
{
api_state_change(APP_TEST);
break;
}
default:
flg_press_btn = false;
}
}
if(flg_press_btn == true){
app_timeout_illumination_10s = APP_TIMEOUT_ILLUMINATION_MS;
if(!app_blink_num) nrf_gpio_pin_set(BL_PIN);
}
break;
}
case APP_STAND_BY:
{
//управление дисплеем
app_ind_stand_by();
//управление реле
if((temp[app_state_device.app_sensor_se] >= app_state_hand.app_sensor_active_set+app_state_device.app_hysteresis)/*температура активного датчика превышает установку*/ \
|| (app_state_device.app_sensor_se == APP_ACTIVE_AIR_SENSOR \
&& app_state_err[app_state_device.app_sensor_se] != APP_ERROR_NO \
&& app_state_err[app_state_device.app_sensor_se] != APP_ERROR_AIR_LESS_MIN) \
|| (app_state_device.app_sensor_se == APP_ACTIVE_FLOOR_SENSOR \
&& app_state_err[app_state_device.app_sensor_se] != APP_ERROR_NO \
&& app_state_err[app_state_device.app_sensor_se] != APP_ERROR_FLOOR_LESS_MIN) \
|| (app_state_device.app_off_en == true) /*отключено реле*/ \
|| (fl_over_hi)) /*превышение максимального порога на любом из датчиков*/
{
if(nrf_gpio_pin_read(RELE_PIN) && !app_timeout_illumination_10s && !flag_control_smartfone){
//реле включено и нет пользовательского управления => считаем selfteachin
app_end_temp_heating = temp[app_state_device.app_sensor_se]; //запоминаем конечную температуру нагрева
app_clear_relay(true); //выключаем реле и расчитываем значения selfteachin
}
if(flag_control_smartfone == true) flag_control_smartfone = false;
//запускаем задержку на повторное включение реле
else app_timeout_on_relay_ms = TIMERS_MINUTES(APP_TIMEOUT_ON_RELAY);
//выключаем реле без расчета selfteaching
app_clear_relay(false);
}
else if(temp[app_state_device.app_sensor_se] <= app_state_hand.app_sensor_active_set-app_state_device.app_hysteresis)
{
flag_control_smartfone = false;
if(!nrf_gpio_pin_read(RELE_PIN)){
//запоминаем начальную температуру нагрева
app_begin_temp_heating = temp[app_state_device.app_sensor_se];
}
//включаем реле
app_set_relay();
}
//обработка подсветки дисплея
if(app_blink_num && app_timeout_ind_pairing_10ms >= 70){ app_timeout_ind_pairing_10ms = 0; --app_blink_num; }
if(app_blink_num && app_timeout_ind_pairing_10ms <= 30) nrf_gpio_pin_set(BL_PIN);
if(app_blink_num && app_timeout_ind_pairing_10ms > 30) nrf_gpio_pin_clear(BL_PIN);
//обработка кнопок
APP_CHANGE_LOCK_DEVICE(); //блокировка/разблокировка кнопок
if(app_state_device.app_lock_en) break;
//проверка кнопки "ON/OFF"
APP_OFF_DEVICE(); //transition in mode APP_OFF, if press button "ON/OFF"
if( (keyb_data.code_press == BTN_UP) && (keyb_data.event_press == BTN_EVENT_CAPTURED || \
(!(keyb_data.pressed_time_ms%APP_TIMEOUT_PRESS_TIME_MS)&&(pre_time_ms != keyb_data.pressed_time_ms))))
{
//инкремент/декримент порога выставленной температуры
pre_time_ms = keyb_data.pressed_time_ms;
//увеличиваем/уменьшаем значение порога температурных датчиков на step
if(app_state_device.app_off_en == true) app_state_device.app_off_en = false;
else{
app_state_hand.app_sensor_active_set = (APP_PARAM_INC(app_state_hand.app_sensor_active_set, APP_CUSTOM_TEMPERATURE_TOP, 0.5f));
app_state_hand.app_sensor_custom_set = app_state_hand.app_sensor_active_set;
}
}
if( (keyb_data.code_press == BTN_DOWN) && (keyb_data.event_press == BTN_EVENT_CAPTURED || \
(!(keyb_data.pressed_time_ms%APP_TIMEOUT_PRESS_TIME_MS)&&(pre_time_ms != keyb_data.pressed_time_ms))))
{
//инкремент/декримент порога выставленной температуры
pre_time_ms = keyb_data.pressed_time_ms;
//увеличиваем/уменьшаем значение порога температурных датчиков на step
if(app_state_hand.app_sensor_active_set == APP_ALARM_TEMPERATURE_BOTTOM) app_state_device.app_off_en = true;
else{
app_state_hand.app_sensor_active_set = (APP_PARAM_DEC(app_state_hand.app_sensor_active_set, APP_ALARM_TEMPERATURE_BOTTOM, 0.5f));
app_state_hand.app_sensor_custom_set = app_state_hand.app_sensor_active_set;
}
}
//переключение температурного датчика (AIR/FLOOR) для управления прибором
if(keyb_data.code_press == BTN_ON_CLOCK && keyb_data.event_press == BTN_EVENT_CAPTURED)
{
app_state_device.app_sensor_se = ~app_state_device.app_sensor_se;
}
if(keyb_data.event_release == BTN_EVENT_CAPTURED){
//включение/выключение выполнения задач календаря
if(keyb_data.code_press == BTN_MENU){
app_state_device.app_calendar_en = ~app_state_device.app_calendar_en;
uint8_t num;
evcal_get_task_number(&num);
if(app_state_device.app_calendar_en == false && num){
//установка пользовательского температурного порога
app_state_hand.app_sensor_active_set = app_state_hand.app_sensor_custom_set;
}else{
app_timeout_blink_calendar_10ms = APP_TIMEOUT_BLINK_10MS*3;
}
}
}
if( keyb_data.code_press == BTN_CLOCK && (keyb_data.pressed_time_ms >= APP_CLOCK_EDIT_TIME_MS))
{
//переход в режим настройки часов
api_state_change(APP_CLOCK_EDIT);
}
// if( (keyb_data.code_press == BTN_MENU_UP) && (!(keyb_data.pressed_time_ms%APP_PAIRING_TIME_MS) && keyb_data.pressed_time_ms))
// {
// api_state_change(APP_PREPAIRING);
// }
break;
}
case APP_PREUNPAIRING:
{
if(app_blink_num && app_timeout_ind_pairing_10ms >= 70){ app_timeout_ind_pairing_10ms = 0; --app_blink_num; }
if(app_blink_num && app_timeout_ind_pairing_10ms > 30) nrf_gpio_pin_clear(BL_PIN);
if(app_blink_num && app_timeout_ind_pairing_10ms <= 30) nrf_gpio_pin_set(BL_PIN);
if(keyb_data.event_release == BTN_EVENT_CAPTURED){
api_state_change(APP_UNPAIRING);
}
break;
}
case APP_SERVICE_MENU:
{
//управление дисплеем
app_ind_service_menu();
//выключение реле
app_clear_relay(false);
//обработка кнопок
APP_CHANGE_LOCK_DEVICE(); //блокировка/разблокировка кнопок
if(app_state_device.app_lock_en) break;
APP_OFF_DEVICE(); //transition in mode APP_OFF, if press button "ON/OFF"
//удержание кнопки UP/DOWN
if( (keyb_data.code_press == BTN_UP || keyb_data.code_press == BTN_DOWN) \
&& (keyb_data.event_press == BTN_EVENT_CAPTURED || (!(keyb_data.pressed_time_ms%APP_TIMEOUT_PRESS_TIME_MS)&&(pre_time_ms != keyb_data.pressed_time_ms))))
{
pre_time_ms = keyb_data.pressed_time_ms;
//обработка сервисного меню
app_service_menu_handler(&keyb_data);
}
if(keyb_data.event_release == BTN_EVENT_CAPTURED){
if(keyb_data.code_press == BTN_MENU){
if(++app_state_service_menu.sm_index_menu > SM_CLEAN_SETTING_06){
if(app_state_service_menu.sm_clean_setting == true){
//сброс к заводским настройкам
app_state_device.app_air_sensor_calib = CALIB_SENSOR_AIR_DEFAULT;
app_state_device.app_floor_sensor_calib = CALIB_SENSOR_FLOOR_DEFAULT;
app_state_device.app_contrast = true;
app_state_device.app_floor_sensor_idx = 0;
app_state_device.app_hysteresis = APP_HYSTERESIS_DEFAULT;
app_state_device.app_custom_power = 0;
display_set_bias(app_state_device.app_contrast);
temp_set_idx_floor(app_state_device.app_floor_sensor_idx);
}else{
//копируем данные из временной структуры
app_state_device.app_air_sensor_calib = app_data_service_menu.app_air_sensor_calib;
app_state_device.app_floor_sensor_calib = app_data_service_menu.app_floor_sensor_calib;
app_state_device.app_contrast = app_data_service_menu.app_contrast;
app_state_device.app_floor_sensor_idx = app_data_service_menu.app_floor_sensor_idx;
app_state_device.app_hysteresis = app_data_service_menu.app_hysteresis;
}
api_state_change(APP_STAND_BY);
}
}
}
if(!app_timeout_service_menu) api_state_change(APP_STAND_BY);
break;
}
case APP_UNPAIRING:
{
if(app_blink_num && app_timeout_ind_pairing_10ms >= 70)
{
app_timeout_ind_pairing_10ms = 0;
--app_blink_num;
}
if(app_blink_num && app_timeout_ind_pairing_10ms <= 30)
nrf_gpio_pin_set(BL_PIN);
else nrf_gpio_pin_clear(BL_PIN);
if(!app_blink_num && keyb_data.code_release == BTN_ALL_RELEASE)
{
api_state_change(APP_OFF);
}
break;
}
case APP_CLOCK_EDIT:
{
//display shows
app_ind_clock_edit();
//off relay
app_clear_relay(false);
//controls buttons
APP_CHANGE_LOCK_DEVICE(); //block/unblock buttons
if(app_state_device.app_lock_en) break;
APP_OFF_DEVICE(); //transition in mode APP_OFF, if press button "ON/OFF"
if(keyb_data.code_press == BTN_UP
&& (keyb_data.event_press == BTN_EVENT_CAPTURED || (!(keyb_data.pressed_time_ms%APP_TIMEOUT_PRESS_TIME_MS)&&(pre_time_ms != keyb_data.pressed_time_ms))))
{
//инкремент/декримент порога выставленной температуры
pre_time_ms = keyb_data.pressed_time_ms;
calendar_get_utc_time(×tamp, &shift);
utc_to_date(timestamp, &time);
if(app_state_clock_edit.element_edit == 0){ if(time.hours <= 23) if(++time.hours >=24) time.hours = 0; }
else if(app_state_clock_edit.element_edit == 1){ if(time.minutes <= 59) if(++time.minutes >= 60) time.minutes = 0; }
else if(app_state_clock_edit.element_edit == 2){
++time.days;
}
else break;
calendar_set_time(date_to_utc(&time), shift);
}
if(keyb_data.code_press == BTN_DOWN && (keyb_data.event_press == BTN_EVENT_CAPTURED || \
(!(keyb_data.pressed_time_ms%APP_TIMEOUT_PRESS_TIME_MS)&&(pre_time_ms != keyb_data.pressed_time_ms))))
{
//инкремент/декримент порога выставленной температуры
pre_time_ms = keyb_data.pressed_time_ms;
calendar_get_utc_time(×tamp, &shift);
utc_to_date(timestamp, &time);
if(app_state_clock_edit.element_edit == 0){ if(time.hours != 0) --time.hours; else time.hours = 23;}
else if(app_state_clock_edit.element_edit == 1){ if(time.minutes != 0) --time.minutes; else time.minutes = 59;}
else if(app_state_clock_edit.element_edit == 2){
--time.days;
}
else break;
calendar_set_time(date_to_utc(&time), shift);
}
if(keyb_data.event_release == BTN_EVENT_CAPTURED && !app_state_device.app_lock_en && !evcal_get_cur_transaction()){
if(keyb_data.code_press == BTN_CLOCK){
if(app_first_press_menu == false) app_first_press_menu = true;
else if(++app_state_clock_edit.element_edit >= 3){
calendar_get_utc_time(×tamp, &shift);
pcf8563_set_time_utc(×tamp);
api_state_change(APP_STAND_BY);
}
}
}
break;
}
default:
{
// APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_YELLOW"[APPL]: default\r\n"RTT_CTRL_RESET);
api_state_change(APP_STAND_BY);
break;
}
}
return;
}
/********************************************************************************
*
********************************************************************************/
static void app_clear_relay(bool reach)
{
if(reach == true && ((int8_t)(app_end_temp_heating - app_begin_temp_heating))> 0)
{
app_state_device.app_selfteaching_time_s = app_selfteaching_time_ms/1000/(app_end_temp_heating - app_begin_temp_heating);
APP_PRINTF(0,"[SELFTEACHING]: timer_ms=%d, temp=%d.02%d, time_s=%d%\n", app_selfteaching_time_ms,
(uint16_t)(app_end_temp_heating - app_begin_temp_heating), (uint16_t)((app_end_temp_heating - app_begin_temp_heating)*100)%100,
app_state_device.app_selfteaching_time_s);
}
nrf_gpio_pin_clear(RELE_PIN);
app_selfteaching_time_ms = 0;
fl_inc_set_heat = false;
}
static void app_set_relay(void)
{
nrf_gpio_pin_set(RELE_PIN);
if(!fl_inc_set_heat){
fl_inc_set_heat = true;
++app_state_device_log.app_count_set_relay;
}
}
/********************************************************************************
*
********************************************************************************/
/**
* описание в application_api.h
*/
uint16_t api_get_version(void)
{
return FIRMWARE_VER;
}
/***************************COMMON************************************/
void api_state_change(app_state_t new_state)
{
app_state = new_state;
application_init_prew_state( app_state );
application_init_new_state( app_state );
}
bool api_state_check(app_state_t state)
{
if(app_state == state)
{
return true;
}
else
{
return false;
}
}
uint8_t api_get_state(void)
{
switch(app_state)
{
#ifdef NRF51
case APP_SLAVE_FW_UPDATE:
{
return APP_API_FW_UPDATE_STATE;
}
#endif
case APP_STAND_BY:
{
if( (app_state_err[app_state_device.app_sensor_se] == APP_ERROR_AIR_OVER_MAX) \
||(app_state_err[app_state_device.app_sensor_se] == APP_ERROR_AIR_SENSOR_LOWER) \
||(app_state_err[app_state_device.app_sensor_se] == APP_ERROR_AIR_SENSOR_DROP) \
||(app_state_err[app_state_device.app_sensor_se] == APP_ERROR_FLOOR_OVER_MAX) \
||(app_state_err[app_state_device.app_sensor_se] == APP_ERROR_FLOOR_SENSOR_LOWER) \
||(app_state_err[app_state_device.app_sensor_se] == APP_ERROR_FLOOR_SENSOR_DROP) \
|| fl_over_hi)
return APP_API_ERROR_STATE;
if(app_state_device.app_off_en == true) return APP_API_STAND_BY_STATE;
else return APP_API_RUN_STATE;
}
case APP_PAIRING:
return APP_API_PAIRING_STATE;
default:
{
return APP_API_ERROR_STATE;
}
}
}
/********************************************************************************/
/***************************PERIPHERAL************************************/
/**
* описание в application_api.h
*/
float api_get_temp(void)
{
float temp;
temp_get_value(app_state_device.app_sensor_se, &temp);
temp += ((app_state_device.app_sensor_se==APP_ACTIVE_AIR_SENSOR)?(app_state_device.app_air_sensor_calib):(app_state_device.app_floor_sensor_calib));
return temp;
}
uint8_t api_get_error(void)
{
if((app_state_err[APP_ACTIVE_AIR_SENSOR] == APP_ERROR_AIR_OVER_MAX \
|| app_state_err[APP_ACTIVE_AIR_SENSOR] == APP_ERROR_AIR_SENSOR_LOWER \
|| app_state_err[APP_ACTIVE_AIR_SENSOR] == APP_ERROR_AIR_SENSOR_DROP))\
return app_state_err[APP_ACTIVE_AIR_SENSOR];
if((app_state_err[APP_ACTIVE_FLOOR_SENSOR] == APP_ERROR_FLOOR_OVER_MAX \
|| app_state_err[APP_ACTIVE_FLOOR_SENSOR] == APP_ERROR_FLOOR_SENSOR_LOWER \
|| app_state_err[APP_ACTIVE_FLOOR_SENSOR] == APP_ERROR_FLOOR_SENSOR_DROP))\
return app_state_err[APP_ACTIVE_FLOOR_SENSOR];
if(fl_over_hi == 1) return APP_ERROR_AIR_OVER_MAX;
if(fl_over_hi == 2) return APP_ERROR_FLOOR_OVER_MAX;
return APP_ERROR_NO;
}
/**
* описание в application_api.h
*/
/*
void api_master_event_proccess(uint8_t index)
{
// com_master_proccess(EVT_BTN_PRESSED(index, BTN_CLICK_SINGLE));
}
*/
#ifdef NRF51
uint8_t api_enter_fw_update_state(void)
{
if((app_state == APP_STAND_BY)
||( app_state == APP_SLAVE_FW_UPDATE))
{
api_state_change(APP_SLAVE_FW_UPDATE);
return 1;
}
return 0;
}
void api_fw_update_proc(void)
{
if( app_state == APP_SLAVE_FW_UPDATE )
{
APP_ERROR_CHECK(app_timer_stop(app_timer_id));
APP_ERROR_CHECK(app_timer_start(app_timer_id,APP_TIMER_TICKS(APP_FW_UPDATE_TIMEOUT_MS, APP_TIMER_PRESCALER), NULL ));
}
}
#endif
void api_slave_pairing_complete( void )
{
}
void api_slave_pairing_error(void)
{
}
/********************************************************************************/
/***************************CENTRAL************************************/
/********************************************************************************/
//формирование событий календаря по case
//void api_create_case_calendar(app_state_t state)
//{
// calendar_time_t time;
// calendar_get_calendar_time(&time);
//
// evcal_task_t data = {0};
// data.enable = true;
// data.repeat_type = 2;
//
// *(data.cmd.array+1) = AC_EXTENTION_TEMP_SFLOAT_CMD;
// exten_req_temp_sfloat_cmd_t* param_ac = (exten_req_temp_sfloat_cmd_t*)(data.cmd.array+2);
// param_ac->mode = 0x02; //задаем режим подогрева до температуры param1
//
// api_add_trans_in_calendar(EVCAL_TRANSACTION_WRITE);
//
// switch(state)
// {
// case APP_CASE_HOLIDAY:
// {
// //удаляем предыдущие задачи календаря
// evcal_erase_all_tasks();
// //создаем новые задачи по кейсу
// for(uint8_t i=0; i<4; ++i){
// //задаем время
// time.hours = IN_TIMERS_HOURS(app_state_case_holiday.holiday.state_event[i].time_m);
// time.minutes = IN_TIMERS_MINUTES(app_state_case_holiday.holiday.state_event[i].time_m);
// data.timestart = date_to_utc(&time);
// //задаем дни недели
// data.repeat_rules = 0x7F;
// //задаем температуру
// param_ac->param1 = FloatToSFloat16(app_state_case_holiday.holiday.state_event[i].temp_set);
// //сохраняем задачу
// APP_ERROR_CHECK(evcal_save_task(&data));
// }
// break;
// }
// case APP_CASE_COTTAGE:
// {
// //удаляем предыдущие задачи календаря
// evcal_erase_all_tasks();
// //создаем новые задачи по кейсу
// for(uint8_t i=0; i<4; ++i){
// time.hours = IN_TIMERS_HOURS(app_state_case_cottage.cottage.state_event[i].time_m);
// time.minutes = IN_TIMERS_MINUTES(app_state_case_cottage.cottage.state_event[i].time_m);
// data.timestart = date_to_utc(&time);
// data.repeat_rules = 0x60;
// param_ac->param1 = FloatToSFloat16(app_state_case_cottage.cottage.state_event[i].temp_set);
// APP_ERROR_CHECK(evcal_save_task(&data));
// }
// break;
// }
// default:
// {
// break;
// }
// }
// api_dec_trans_in_calendar(EVCAL_COMMIT_TRANSACTION);
//}
//static uint32_t app_parse_case_calendar(uint8_t* p_index, app_state_case_t* p_case, evcal_task_t* p_data, const uint8_t max_count)
//{
// calendar_time_t time;
//
// //задач в календаре больше допустимого
// if(*p_index > max_count) return NRF_ERROR_INVALID_PARAM;
// //определяем время
// utc_to_date(p_data->timestart, &time);
// p_case->state_event[*p_index].time_m = TIMERS_HOURS(time.hours)+time.minutes;
// if((p_case->state_event[*p_index].time_m)>TIMERS_HOURS(24)) return NRF_ERROR_INVALID_PARAM;
//
// //определяем температурный порог
// exten_req_temp_sfloat_cmd_t* param_ac = (exten_req_temp_sfloat_cmd_t*)(p_data->cmd.array+2);
// p_case->state_event[*p_index].temp_set = SFloat16ToFloat(param_ac->param1);
//
// if((param_ac->mode&0x0F) != 2) return NRF_ERROR_INVALID_PARAM;
// if((param_ac->mode&0x0F) == 2 && p_case->state_event[*p_index].temp_set > APP_ALARM_TEMPERATURE_TOP) p_case->state_event[*p_index].temp_set = APP_ALARM_TEMPERATURE_TOP;
// if((param_ac->mode&0x0F) == 2 && p_case->state_event[*p_index].temp_set > APP_ALARM_TEMPERATURE_BOTTOM) p_case->state_event[*p_index].temp_set = APP_ALARM_TEMPERATURE_BOTTOM;
//
// //увеличиваем кол-во задач в календаре
// ++(*p_index);
//
// return NRF_SUCCESS;
//}
//сортировка (выбором) полученных из календаря задач
//static void app_choices_sort_case_calendar(app_state_case_t* p_case, const uint8_t max_count)
//{
// uint32_t tmp_time_m;
// float tmp_temp_set;
// for(int repeat_counter=0; repeat_counter<max_count; ++repeat_counter){
// for(int element_counter=repeat_counter+1; element_counter<max_count; ++element_counter){
// if (p_case->state_event[repeat_counter].time_m > p_case->state_event[element_counter].time_m){
// tmp_time_m = p_case->state_event[repeat_counter].time_m;
// tmp_temp_set = p_case->state_event[repeat_counter].temp_set;
//
// p_case->state_event[repeat_counter].time_m = p_case->state_event[element_counter].time_m;
// p_case->state_event[repeat_counter].temp_set = p_case->state_event[element_counter].temp_set;
//
// p_case->state_event[element_counter].time_m = tmp_time_m;
// p_case->state_event[element_counter].temp_set = tmp_temp_set;
// }
// }
// }
//}
//uint32_t api_get_case_calendar(app_state_t state)
//{
// evcal_task_t data;
// uint8_t num_task;
// APP_ERROR_CHECK(evcal_get_task_number(&num_task));
//
// return NRF_SUCCESS;
//}
/*
void api_master_pairing_success( uint8_t tok_id, cm_dev_support_ac_t * required_ac )
{
// mct_transaction_t * tran = NULL;
mct_link_t link;
memset(&link, 0, sizeof(mct_link_t));
mct_searchp_context_t search;
memset(&search, 0, sizeof(mct_searchp_context_t));
bool start_support = false;
bool stop_support = false;
// uint32_t err_code;
APP_PRINTF(0, RTT_CTRL_TEXT_BRIGHT_GREEN"[APPL]: api_master_pairing_complete\r\n"RTT_CTRL_RESET);
// Тип транзации READ_WRITE не рекомендуется использовать, если не будет гарантированной записи
// иначе пока транзакция не будет закрыта остальные транзакции не возможны
// err_code = mct_open_transaction(&tran, TRAN_READ_WRITE, TRAN_COMMON_PERM);
// if (err_code != NRF_ERROR_BUSY){
// APP_ERROR_CHECK(err_code);
bool defaultAllowFl = true;
// Чтобы пэйринг по дефолту был доступен 5 раз нужно раскоментировать код ниже
// search.params.filter.event_mask = EVENT_CODE_MASK; // Также будем искать по коду события
// search.params.values.event = BTN_EVENT_CODE<<EVENT_CODE_Pos; // Только события нажатия кнопки
//
// uint8_t evt_cnt = 0;
// while (mct_find_link(tran, &search, &link) == NRF_SUCCESS){ // События найдено
// if (link.event & ((1ul<<PairButtonId)<<(BTN_EVT_MASK_Pos))) {
// evt_cnt++;
// if (evt_cnt > 5) { // 5 - количество событий, позволенных для кнопки PairButtonId
// defaultAllowFl = false; // Тогда события не нужны
// break;
// }
// }
// }
if (required_ac->is_support[0]){
start_support = true;
}
if (required_ac->is_support[1]){
stop_support = true;
}
if(defaultAllowFl && (stop_support || start_support))
{
link.tok_id = tok_id;
if (stop_support) {
// link.event = EVT_BTN_PRESSED(PairButtonId, BTN_CLICK_SINGLE);
link.ac = AC_EXTENTION_STOP_CMD;
link.data[0]=0xFF;
link.data[1]=0xFF;
link.enable = 0x01;
link.perm = MCT_PERM(MCT_PERM_ANY_USER, MCT_PERM_ANY_USER); // полный доступ
// Рекомендуется создавать события с ограничениями НЕ ПРИ ПРЯМОМ ПЭЙРИНГЕ
// поскольку при анпейринге такие события не будут удалены.
//
// Событие, которое может быть прочитано только устройством
//link.perm = MCT_PERM(MCT_PERM_ONLY_MASTER, MCT_PERM_ANY_USER);
// Событие, которое может быть изменено только устройством
//link.perm = MCT_PERM(MCT_PERM_ANY_USER, MCT_PERM_ONLY_MASTER);
// Событие, которое не может быть изменено и не может быть прочитано через приложение
//link.perm = MCT_PERM(MCT_PERM_ONLY_MASTER, MCT_PERM_ONLY_MASTER);
link.uuid = 0;
// err_code = mct_set_link(tran, &link);
// if (err_code != NRF_ERROR_NO_MEM)
// APP_ERROR_CHECK(err_code);
}
if (start_support){
// link.event = EVT_BTN_PRESSED(PairButtonId-1, BTN_CLICK_SINGLE);
link.ac = AC_EXTENTION_START_CMD;
link.data[0]=0xFF;
link.data[1]=0xFF;
link.enable = 0x01;
link.perm = MCT_PERM(MCT_PERM_ANY_USER, MCT_PERM_ANY_USER); // полный доступ
link.uuid = 0;
// err_code = mct_set_link(tran, &link);
// if (err_code != NRF_ERROR_NO_MEM)
// APP_ERROR_CHECK(err_code);
}
}
// APP_ERROR_CHECK(mct_commit(&tran));
// Уведомляем модули о обновлении mct
com_slave_mct_notify();
api_param_update();
// }
api_state_change(APP_STAND_BY);
}
void api_master_pairing_error( void )
{
APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_GREEN"[APPL]: api_master_pairing_error\r\n"RTT_CTRL_RESET);
api_state_change(APP_STAND_BY);
}
*/
uint8_t api_go_to_stand_by(void)
{
if(( app_state != APP_STAND_BY )
&& ( app_state != APP_PAIRING )
#ifdef NRF51
&& ( app_state != APP_SLAVE_FW_UPDATE )
#endif
)
{
return 0;
}
if( app_state == APP_PAIRING)
{
app_blink_num = 3;
app_timeout_ind_pairing_10ms = 0;
api_state_change(APP_STAND_BY);
return 1;
}
#ifdef NRF51
if(app_state == APP_SLAVE_FW_UPDATE){
AppTimeoutFl = true;
}
#endif
return 1;
}
void api_process_event(mct_link_t *link){
switch(link->ac){
// case AC_EXTANSION_START_CMD:{
// if (api_state_check(APP_PASSIVE)) {
// api_state_change(APP_STAND_BY);
// }
// }
// break;
// case AC_EXTANSION_STOP_CMD: {
// if (!api_state_check(APP_PASSIVE))
// api_state_change(APP_PASSIVE);
// }
// break;
default: // неизвестный action code
break;
}
}
void api_param_update(void)
{
}
app_state_t api_get_state_prev_off(app_state_t state)
{
switch(state)
{
case APP_START:
#ifdef NRF51
case APP_SLAVE_FW_UPDATE: //обновление прошивки
#endif
{
return state;
}
case APP_CLOCK_EDIT:
case APP_OFF:
case APP_SERVICE_MENU:
case APP_STAND_BY:
case APP_PAIRING: //pairing
case APP_UNPAIRING: //pairing
case APP_PREPAIRING: //prepairing
case APP_PREUNPAIRING: //prepairing
case APP_ERROR: //ошибка
case APP_TEST:
{
return APP_STAND_BY;
}
}
return APP_STAND_BY;
}
/**
* описание в 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);
pcf8563_set_time_utc(&m_time_stamp);
app_state_device.app_shift_utc = 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;
}
/**
* описание в 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)
{
//записываем задачу в календарь
// uint8_t id = ((evcal_task_t*)p_input)->uid;
uint32_t err_code = evcal_save_task(p_input);
*uid = ((evcal_task_t *)p_input)->uid; //записываем UID присвоенной задачи
switch (err_code)
{
case NRF_SUCCESS:
{
// if(id == 0) app_state_device.app_calendar_en = true;
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);
uint8_t num;
evcal_get_task_number(&num);
// if(!num) app_state_device.app_calendar_en = false;
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){
// app_state_device.app_calendar_en = false;
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;
}
/**
* @brief Закрытие сессии в календаре
*
* @param task commit/rollback
*
* @return возвращает код ошибки
*
*/
uint8_t api_dec_trans_in_calendar(uint8_t task)
{
if(task!=0 && task!=1) return ERSP_ERROR_INVALID_PARAM;
uint32_t err_code = evcal_dec_transaction((!task)?(EVCAL_COMMIT_TRANSACTION):(EVCAL_ROLLBACK_TRANSACTION));
switch (err_code)
{
case NRF_SUCCESS:
{
return ERSP_SUCCESS;
}
case NRF_ERROR_INVALID_PARAM:
{
return ERSP_ERROR_INVALID_PARAM;
}
case DRIVER_MODULE_NOT_INITIALZED:
{
return ERSP_ERROR_INTERNAL;
}
case NRF_ERROR_FORBIDDEN:
return ERSP_ERROR_FORBIDDEN;
}
return ERSP_ERROR_UNKNOWN;
}
/*****************************************************************************************************/
/**
* описание в application_api.h
*/
uint8_t api_start(void)
{
switch(app_state)
{
case APP_STAND_BY:
{
app_state_device.app_off_en = false;
return 1;
}
default:
{
return 0;
}
}
}
/**
* описание в application_api.h
*/
uint8_t api_stop(void)
{
switch(app_state)
{
case APP_STAND_BY:
{
app_state_device.app_off_en = true;
return 1;
}
default:
{
return 0;
}
}
}
/**
* описание в application_api.h
*/
uint8_t api_switch(void)
{
switch(app_state)
{
case APP_STAND_BY:
{
app_state_device.app_off_en = ~app_state_device.app_off_en;
return 1;
}
default:
{
return 0;
}
}
}