Программный модуль для мини-пекарни «Мультипекарь» RMB-M659/3S версия 1.0
ПО является неотъемлемой частью мини-пекарни "Мультипекарь" RMB-M659/3S, отдельно потребителю не поставляется и эксплуатируется только в составе устройства.
/******************************************************************************
* @file main.c
* @brief main.c реализует функционал устройства RMB-M659/3S
* Created: 17.05.2019
* Revision: ver 1.0
* Compiler: armcc
******************************************************************************/
/********* HEADER FILE INCLUDES *************************************************/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf_delay.h"
#include "debug_info.h"
#include "nordic_common.h"
#include "nrf_sdm.h"
#include "nrf_assert.h"
#include "nrf_drv_rng.h"
#include "app_util_platform.h"
#include "hardfault.h"
#include "app_error.h"
#include "app_timer.h"
#include "app_scheduler.h"
#include "nrf_gpio.h"
#include "nrf_drv_gpiote.h"
#include "timers_config.h"
#include "Application.h"
#include "com_slave.h"
#include "r4s_lib.h"
#include "config.h"
#include "r4s_slave.h"
#include "adv_data.h"
#include "heat.h"
#include "key.h"
#include "led.h"
#include "logic_led.h"
#include "buz_ac.h"
#include "timers.h"
#include "timers_config.h"
#include "pof_manager.h"
#include "storage.h"
/********* DEFINES **************************************************************/
/**< Maximum size of scheduler events. */
#define SCHED_MAX_EVENT_DATA_SIZE sizeof(nrf_drv_gpiote_pin_t)
/**< Maximum number of events in the scheduler queue. */
#define SCHED_QUEUE_SIZE 10
/********* FUNCTIONS IMPLEMENTATION *********************************************/
int main(void)
{
uint32_t err_code;
key_init();
nrf_delay_ms(15);
APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
r4s_init_conf_t r4s_init_conf;
r4s_init_conf.app_timer_prescaler = APP_TIMER_PRESCALER;
r4s_init_conf.low_power_mode_enable = false;
#ifdef DEBUG
SEGGER_RTT_WriteString(0, RTT_CTRL_CLEAR);
APP_PRINTF(0,"\r\n");
APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_RED"====================\r\n"RTT_CTRL_RESET);
APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_RED" RFS-KMB001 ver%d.%d \r\n"RTT_CTRL_RESET,(FIRMWARE_VER&0xFF00)>>8,(FIRMWARE_VER&0xFF));
APP_PRINTF(0,RTT_CTRL_TEXT_BRIGHT_RED"====================\r\n"RTT_CTRL_RESET);
#endif
#ifdef LOCK_EN
r4s_init_conf.mem_protection_enable = true;
err_code = r4s_init( &r4s_init_conf );
APP_ERROR_CHECK( err_code );
#else
r4s_init_conf.mem_protection_enable = false;
err_code = r4s_init( &r4s_init_conf );
APP_ERROR_CHECK( err_code );
#endif
err_code = sd_ble_gap_tx_power_set(4);
APP_ERROR_CHECK(err_code);
err_code = app_advertising_init();
APP_ERROR_CHECK(err_code);
app_advertising_unset_paring_flag();
err_code = timers_init();
APP_ERROR_CHECK(err_code);
err_code = buz_init();
APP_ERROR_CHECK(err_code);
err_code = buz_off();
APP_ERROR_CHECK( err_code );
err_code = storage_init();
APP_ERROR_CHECK(err_code);
err_code = pof_manager_init();
APP_ERROR_CHECK(err_code);
led_init();
heat_init();
application_init();
com_slave_init();
while(1)
{
app_sched_execute();
err_code = timers_update();
APP_ERROR_CHECK(err_code);
err_code = buz_update();
APP_ERROR_CHECK(err_code);
err_code = storage_update();
APP_ERROR_CHECK(err_code);
err_code = pof_manager_update();
APP_ERROR_CHECK(err_code);
application_process();
com_slave();
app_send_notification();
app_advertising_update();
}
}
/******************************************************************************
* @file aplication.c
* @brief aplication.c логику работы и реализует функционал устройства
* RMB-M659/3S
* Created: 17.05.2019
* Revision: ver 1.0
* 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_gpio.h"
#include "nrf_soc.h"
#include "app_timer.h"
#include "app_error.h"
#include "com_slave.h"
#include "r4s_lib.h"
#include "r4s_master.h"
#include "adv_data.h"
#include "adv_data.h"
#include "Application.h"
#include "Application_api.h"
#include "com_slave_extention.h"
#include "config.h"
#include "heat.h"
#include "key.h"
#include "led.h"
#include "logic_led.h"
#include "buz_ac.h"
#include "timers.h"
#include "timers_config.h"
#include "pof_manager.h"
/********* LOCAL VARIABLES ******************************************************/
static app_state_t app_state = APP_START;
static app_flags_t app_flags;
static cooking_settings_t cooking_settings;
static app_notify_complex_t prew_notify_complex;
static uint8_t app_key_state = 0;
static bool toggle_heat = false;
static app_save_info_struct_t app_pof_info __attribute__((aligned(sizeof(uint32_t))));
/********* FUNCTIONS IMPLEMENTATION *********************************************/
/********************************************************************************
* @brief Параметры для хранения в pof_manager
*********************************************************************************/
void *application_get_adr_data(void)
{
app_pof_info.Count_HeaterTimeUsage_sec = heat_get_Count_HeaterTimeUsage_sec();
app_pof_info.Count_ReleyUsage = heat_get_Count_ReleyUsage();
return &app_pof_info;
}
/********************************************************************************
* @brief Сброс всех флагов
*********************************************************************************/
void app_clear_flags(void)
{
app_flags.b_Timeout = false;
app_flags.b_1s_Timeout = false;
app_flags.b_HeatUpdate = false;
app_flags.b_LedUpdate = false;
app_flags.b_KeyUpdate = false;
app_flags.b_WaitKEYUnpress = false;
app_flags.b_Key5SecPressed = false;
app_flags.b_DefferredStart = false;
app_flags.b_SessionIsOpened = false;
app_flags.b_Pairing = false;
app_flags.b_UnPairing = false;
app_flags.b_SendNotification = false;
app_flags.b_GotoSelftest = false;
}
/********************************************************************************
* @brief Обработчик таймера таймаута.
*********************************************************************************/
static void timeout_app_handler(void)
{
app_flags.b_Timeout = true;
return;
}
/********************************************************************************
* @brief Обработчик таймера светодиодов
*********************************************************************************/
static void timeout_led_handler(void)
{
app_flags.b_LedUpdate = true;
return;
}
/********************************************************************************
* @brief Обработчик таймера светодиодов
*********************************************************************************/
static void timeout_heat_handler(void)
{
app_flags.b_HeatUpdate = true;
return;
}
/********************************************************************************
* @brief Обработчик таймера кнопки
*********************************************************************************/
static void timeout_key_handler(void)
{
app_flags.b_KeyUpdate = true;
return;
}
/********************************************************************************
* @brief Обработчик таймера кнопки
*********************************************************************************/
static void timeout_1s_handler(void)
{
app_flags.b_1s_Timeout = true;
return;
}
/********************************************************************************
* @brief Инициализация application
*********************************************************************************/
void application_init(void)
{
uint32_t err_code;
app_clear_flags();
logic_led_set(LOGIC_LED_NONE);
err_code = timer_create( TIMER_APP_TIMEOUT, NULL, (callback_t)timeout_app_handler);
APP_ERROR_CHECK( err_code );
APP_ERROR_CHECK(timer_stop(TIMER_APP_TIMEOUT));
err_code = timer_create( TIMER_LED, TIMERS_MILLISECOND(50), (callback_t)timeout_led_handler );
APP_ERROR_CHECK( err_code );
err_code = timer_start( TIMER_LED );
APP_ERROR_CHECK( err_code );
err_code = timer_create( TIMER_KEY, TIMERS_MILLISECOND(20), (callback_t)timeout_key_handler );
APP_ERROR_CHECK( err_code );
err_code = timer_start( TIMER_KEY );
APP_ERROR_CHECK( err_code );
err_code = timer_create( TIMER_HEAT, TIMERS_MILLISECOND(200), (callback_t)timeout_heat_handler );
APP_ERROR_CHECK( err_code );
err_code = timer_start( TIMER_HEAT );
APP_ERROR_CHECK( err_code );
err_code = timer_create( TIMER_1s, TIMERS_SECOND(1), (callback_t)timeout_1s_handler );
APP_ERROR_CHECK( err_code );
uint32_t reset_reason;
APP_ERROR_CHECK(sd_power_reset_reason_get(&reset_reason));
APP_ERROR_CHECK(sd_power_reset_reason_clr(0xFFFFFFFF));
if((reset_reason & POWER_RESETREAS_SREQ_Msk) == POWER_RESETREAS_SREQ_NotDetected)
{
if(nrf_gpio_pin_read(KEY1_PIN) == 0){
app_flags.b_GotoSelftest = true;
}
}else{
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
}
uint8_t b_pof_have_data = 0;
err_code = pof_manager_get_state(&b_pof_have_data);
APP_ERROR_CHECK(err_code);
if(b_pof_have_data){
err_code = pof_manager_copy_data();
APP_ERROR_CHECK(err_code);
pof_manager_delay_page_clear();
heat_set_Count_HeaterTimeUsage_sec(app_pof_info.Count_HeaterTimeUsage_sec);
heat_set_Count_ReleyUsage(app_pof_info.Count_ReleyUsage);
heat_get_Count_HeaterTimeUsage_sec(), heat_get_Count_ReleyUsage());
}else{
pof_manager_record_enable();
heat_get_Count_HeaterTimeUsage_sec(), heat_get_Count_ReleyUsage());
}
return;
}
/********************************************************************************
* @brief Функция выполняет работу при выходе из соответствующего состояния
*********************************************************************************/
void application_init_prew_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_prew_state )
{
case APP_START:
case APP_STAND_BY:
case APP_PRE_HEATING:
case APP_WAITING_PRODUCT:
break;
case APP_COOKING:
timer_stop(TIMER_APP_TIMEOUT);
app_flags.b_Timeout = false;
break;
case APP_RE_HEATING:
case APP_DEFERRED_START:
break;
case APP_PAIRING:
app_advertising_unset_paring_flag();
r4s_disable_bonding();
timer_stop(TIMER_APP_TIMEOUT);
app_flags.b_Timeout = false;
app_flags.b_Pairing = false;
break;
case APP_UNPAIRING:
timer_stop(TIMER_APP_TIMEOUT);
app_flags.b_Timeout = false;
app_flags.b_UnPairing = false;
break;
case APP_SLAVE_FW_UPDATE:
timer_stop(TIMER_APP_TIMEOUT);
app_flags.b_Timeout = false;
break;
case APP_SELFTEST:
case APP_ERROR:
default:
break;
}
app_prew_state = app_new_state;
return;
}
/********************************************************************************
* @brief Функция выполняет работу при входе в новое состояние
*********************************************************************************/
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_START:
heat_off();
break;
case APP_STAND_BY:
logic_led_set(LOGIC_LED_NONE);
heat_off(); cooking_settings.CookingTime_s = 0;
cooking_settings.DefStartTime_s = 0;
cooking_settings.StateOutTime_s = 0;
break;
case APP_PRE_HEATING:
APP_ERROR_CHECK(heat_on(MAX_HEATING)); if(cooking_settings.Programm == APP_PROG_RE_HEATING){
logic_led_set(LOGIC_LED_RE_HEATING);
cooking_settings.StateOutTime_s = APP_PRE_HEATING_FOR_RE_HEATING_s;
}else{
logic_led_set(LOGIC_LED_PRE_HEATING);
cooking_settings.StateOutTime_s = APP_PRE_HEATING_TIMEOUT_s;
}
app_flags.b_1s_Timeout = false; APP_ERROR_CHECK(timer_reset(TIMER_1s));
APP_ERROR_CHECK(timer_start(TIMER_1s)); break;
case APP_WAITING_PRODUCT:
logic_led_set(LOGIC_LED_WAITING_PRODUCT);
APP_ERROR_CHECK(heat_on(MAX_HEATING));
cooking_settings.StateOutTime_s = APP_WAITING_PRODUCT_TIMEOUT_s;
app_flags.b_1s_Timeout = false; APP_ERROR_CHECK(timer_reset(TIMER_1s));
APP_ERROR_CHECK(timer_start(TIMER_1s)); break;
case APP_COOKING:
if(cooking_settings.Programm == APP_PROG_RE_HEATING){
logic_led_set(LOGIC_LED_RE_HEATING);
APP_ERROR_CHECK(heat_on(RE_PRE_HEATING_DUTY_CYCLE));
}else{
logic_led_set(LOGIC_LED_COOKING);
APP_ERROR_CHECK(heat_on(MAX_HEATING));
}
if(cooking_settings.Programm != APP_PROG_MANUAL){
if(cooking_settings.Programm == APP_PROG_RE_HEATING){
cooking_settings.StateOutTime_s = cooking_settings.CookingTime_s - APP_PRE_HEATING_FOR_RE_HEATING_s;
}else{
cooking_settings.StateOutTime_s = cooking_settings.CookingTime_s;
}
app_flags.b_1s_Timeout = false; app_flags.b_Timeout = false;
APP_ERROR_CHECK(timer_reset(TIMER_1s));
APP_ERROR_CHECK(timer_start(TIMER_1s));
}else{ cooking_settings.StateOutTime_s = 0;
cooking_settings.CookingTime_s = 0;
APP_ERROR_CHECK(timer_stop(TIMER_1s));
app_flags.b_1s_Timeout = false;
app_flags.b_Timeout = false;
APP_ERROR_CHECK(timer_write_period(TIMER_APP_TIMEOUT, TIMERS_SECOND(APP_COOKING_TIMEOUT_s)));
APP_ERROR_CHECK(timer_reset(TIMER_APP_TIMEOUT));
APP_ERROR_CHECK(timer_start(TIMER_APP_TIMEOUT));
}
break;
case APP_RE_HEATING:
logic_led_set(LOGIC_LED_RE_HEATING);
APP_ERROR_CHECK(heat_on(RE_PRE_HEATING_DUTY_CYCLE));
cooking_settings.StateOutTime_s = APP_RE_HEATING_TIMEOUT_s;
app_flags.b_1s_Timeout = false;
APP_ERROR_CHECK(timer_reset(TIMER_1s));
APP_ERROR_CHECK(timer_start(TIMER_1s));
break;
case APP_DEFERRED_START:
logic_led_set(LOGIC_LED_DEFERRED_START);
heat_off();
cooking_settings.StateOutTime_s = cooking_settings.DefStartTime_s;
app_flags.b_1s_Timeout = false;
APP_ERROR_CHECK(timer_reset(TIMER_1s));
APP_ERROR_CHECK(timer_start(TIMER_1s));
break;
case APP_PAIRING:
heat_off();
r4s_enable_bonding();
app_advertising_set_paring_flag();
app_flags.b_Pairing = true;
app_flags.b_Timeout = false;
APP_ERROR_CHECK(timer_write_period(TIMER_APP_TIMEOUT, TIMERS_SECOND(APP_PAIRING_TIMEOUT_s)));
APP_ERROR_CHECK(timer_reset(TIMER_APP_TIMEOUT));
APP_ERROR_CHECK(timer_start(TIMER_APP_TIMEOUT));
break;
case APP_UNPAIRING:
logic_led_set(LOGIC_LED_UNPAIRING);
heat_off();
app_flags.b_UnPairing = true;
com_slave_unpair_proccess();
APP_ERROR_CHECK( buz_add_beep( APP_BIG_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK(timer_write_period(TIMER_APP_TIMEOUT, TIMERS_MILLISECOND(APP_UNPAIRING_TIMEOUT_ms)));
APP_ERROR_CHECK(timer_reset(TIMER_APP_TIMEOUT));
APP_ERROR_CHECK(timer_start(TIMER_APP_TIMEOUT));
break;
case APP_SLAVE_FW_UPDATE:
heat_off();
logic_led_set(LOGIC_LED_FW_UPDATE);
app_flags.b_Timeout = false;
APP_ERROR_CHECK(timer_write_period(TIMER_APP_TIMEOUT, TIMERS_SECOND(APP_FW_UPDATE_TIMEOUT_s)));
APP_ERROR_CHECK(timer_reset(TIMER_APP_TIMEOUT));
APP_ERROR_CHECK(timer_start(TIMER_APP_TIMEOUT));
break;
case APP_SELFTEST:
logic_led_set(LOGIC_LED_NONE);
APP_ERROR_CHECK( buz_add_beep( APP_BIG_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
break;
case APP_ERROR:
heat_off();
break;
default:
break;
}
app_prew_state = app_new_state;
return;
}
/********************************************************************************
* @brief Функция должна вызываться в основном цикле для работы приложения
*********************************************************************************/
void application_process()
{
uint32_t err_code;
if( app_flags.b_LedUpdate == true){
app_flags.b_LedUpdate = false;
led_update();
}
if( app_flags.b_KeyUpdate == true){
app_flags.b_KeyUpdate = false;
key_update();
}
if( app_flags.b_HeatUpdate == true){
app_flags.b_HeatUpdate = false;
heat_update();
}
switch(app_state)
{
case APP_START:
{
if(app_flags.b_GotoSelftest == true){
api_state_change(APP_SELFTEST);
}else{
api_state_change(APP_STAND_BY);
}
break;
}
case APP_STAND_BY:
{
app_key_state = key_get();
if(app_key_state == KEY_ON){
app_flags.b_WaitKEYUnpress = true;
}
if(app_flags.b_WaitKEYUnpress == true){
if(app_key_state == KEY_ON_5SEK){
app_flags.b_Key5SecPressed = true;
logic_led_set(LOGIC_LED_PAIRING);
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
}
if(app_key_state == KEY_ON_10SEK){
api_state_change(APP_UNPAIRING);
app_flags.b_WaitKEYUnpress = false;
app_flags.b_Key5SecPressed = false;
}else if(app_key_state == KEY_OFF){
if(app_flags.b_Key5SecPressed == true){
api_state_change(APP_PAIRING);
}else{
cooking_settings.Programm = APP_PROG_MANUAL;
cooking_settings.CookingTime_s = 0;
cooking_settings.DefStartTime_s = 0;
cooking_settings.StateOutTime_s = 0;
cooking_settings.Order.pre_heating = cooking_default_order[cooking_settings.Programm].pre_heating;
cooking_settings.Order.waiting_product = cooking_default_order[cooking_settings.Programm].waiting_product;
cooking_settings.Order.re_heating = cooking_default_order[cooking_settings.Programm].re_heating;
api_state_change(api_get_next_cooking_state());
}
app_flags.b_WaitKEYUnpress = false;
app_flags.b_Key5SecPressed = false;
}
}
break;
}
case APP_PRE_HEATING:
{
app_key_state = key_get();
if(app_key_state == KEY_ON){
api_state_change(APP_STAND_BY);
break;
}
if(app_flags.b_1s_Timeout == true){
app_flags.b_1s_Timeout = false;
if(cooking_settings.StateOutTime_s == 0){
APP_ERROR_CHECK(timer_stop(TIMER_1s));
if(cooking_settings.Programm != APP_PROG_RE_HEATING){
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
}
api_state_change(api_get_next_cooking_state());
break;
}
cooking_settings.StateOutTime_s--;
if(cooking_settings.Programm == APP_PROG_RE_HEATING){
if((cooking_settings.CookingTime_s - (APP_PRE_HEATING_FOR_RE_HEATING_s - cooking_settings.StateOutTime_s)) == 0){
APP_ERROR_CHECK( buz_add_beep( APP_BIG_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK( buz_add_beep( APP_BIG_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK( buz_add_beep( APP_BIG_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK(timer_stop(TIMER_1s));
api_state_change(APP_STAND_BY); break;
}
}
}
break;
}
case APP_WAITING_PRODUCT:
{
app_key_state = key_get();
if(app_key_state == KEY_ON){
api_state_change(APP_STAND_BY);
break;
}
if(app_flags.b_1s_Timeout == true){
app_flags.b_1s_Timeout = false;
if(cooking_settings.StateOutTime_s == 0){
APP_ERROR_CHECK(timer_stop(TIMER_1s));
APP_ERROR_CHECK( buz_add_beep( APP_BIG_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK( buz_add_beep( APP_BIG_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK( buz_add_beep( APP_BIG_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
api_state_change(APP_STAND_BY);
break;
}
cooking_settings.StateOutTime_s--;
}
break;
}
case APP_COOKING:
{
app_key_state = key_get();
if(app_key_state == KEY_ON){
api_state_change(APP_STAND_BY);
break;
}
if(app_flags.b_1s_Timeout == true){
app_flags.b_1s_Timeout = false;
if(cooking_settings.StateOutTime_s == 0){
APP_ERROR_CHECK( buz_add_beep( APP_BIG_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK( buz_add_beep( APP_BIG_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK( buz_add_beep( APP_BIG_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK(timer_stop(TIMER_1s));
api_state_change(api_get_next_cooking_state());
break;
}
cooking_settings.StateOutTime_s--;
}
if(app_flags.b_Timeout == true){
api_state_change(APP_STAND_BY);
}
break;
}
case APP_RE_HEATING:
{
app_key_state = key_get();
if(app_key_state == KEY_ON){
api_state_change(APP_STAND_BY);
}
if(app_flags.b_1s_Timeout == true){
app_flags.b_1s_Timeout = false;
if(cooking_settings.StateOutTime_s == 0){
APP_ERROR_CHECK(timer_stop(TIMER_1s));
api_state_change(APP_STAND_BY);
break;
}
cooking_settings.StateOutTime_s--;
}
break;
}
case APP_DEFERRED_START:
{
app_key_state = key_get();
if(app_key_state == KEY_ON){
api_state_change(APP_STAND_BY);
}
if(app_flags.b_1s_Timeout == true){
app_flags.b_1s_Timeout = false;
if(cooking_settings.StateOutTime_s == 0){
APP_ERROR_CHECK(timer_stop(TIMER_1s)); cooking_settings.Order.waiting_product = DISABLE_PHASE;
api_state_change(api_get_next_cooking_state());
break;
}
cooking_settings.StateOutTime_s--;
}
break;
}
case APP_PAIRING:
{
if( app_flags.b_SessionIsOpened == 1 ){
api_state_change(APP_STAND_BY);
break;
}
if( app_flags.b_Timeout == true ){
api_slave_pairing_error();
api_state_change(APP_STAND_BY);
break;
}
break;
}
case APP_UNPAIRING:
{
if( app_flags.b_Timeout == true ){
api_state_change(APP_STAND_BY);
}
break;
}
case APP_SLAVE_FW_UPDATE:
{
if( app_flags.b_Timeout == true ){
api_slave_fw_update_error();
api_state_change(APP_STAND_BY);
}
break;
}
case APP_SELFTEST:
{
app_key_state = key_get();
if(app_key_state == KEY_ON){
if(toggle_heat == true){
toggle_heat = false;
err_code = buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI );
logic_led_set(LOGIC_LED_GREEN); APP_ERROR_CHECK( err_code );
heat_off();
}else{
err_code = buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI );
logic_led_set(LOGIC_LED_RED); APP_ERROR_CHECK( err_code );
toggle_heat = true;
APP_ERROR_CHECK(heat_on(MAX_HEATING));
app_flags.b_Timeout = false;
APP_ERROR_CHECK(timer_write_period(TIMER_APP_TIMEOUT, TIMERS_SECOND(APP_SELFTEST_HEATING_TIMEOUT_s)));
APP_ERROR_CHECK(timer_reset(TIMER_APP_TIMEOUT));
APP_ERROR_CHECK(timer_start(TIMER_APP_TIMEOUT));
}
}
if(app_flags.b_Timeout == true){
app_flags.b_Timeout = false;
if( toggle_heat == true){
toggle_heat = false;
err_code = buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI );
logic_led_set(LOGIC_LED_GREEN);
APP_ERROR_CHECK( err_code );
heat_off();
}
}
break;
}
case APP_ERROR:
{
api_state_change(APP_STAND_BY);
break;
}
default:
{
api_state_change(APP_STAND_BY);
break;
}
}
return;
}
/********************************************************************************
* @brief Отправка нотификаций
*********************************************************************************/
void app_send_notification(void)
{
if(prew_notify_complex.Programm != api_get_program()){
prew_notify_complex.Programm = api_get_program();
app_flags.b_SendNotification = true;
}
if(prew_notify_complex.OriginalStateTime_s != api_get_original_state_time()){
prew_notify_complex.OriginalStateTime_s = api_get_original_state_time();
app_flags.b_SendNotification = true;
}
if(prew_notify_complex.StateOutTime_s != api_get_state_out_time()){
prew_notify_complex.StateOutTime_s = api_get_state_out_time();
app_flags.b_SendNotification = true;
}
if(prew_notify_complex.Re_Heating != api_get_reheat()){
prew_notify_complex.Re_Heating = api_get_reheat();
app_flags.b_SendNotification = true;
}
if(prew_notify_complex.Off_Pre_Heating != api_get_off_preheat()){
prew_notify_complex.Off_Pre_Heating = api_get_off_preheat();
app_flags.b_SendNotification = true;
}
if(prew_notify_complex.AppState != api_get_state()){
prew_notify_complex.AppState = api_get_state();
app_flags.b_SendNotification = true;
}
if(prew_notify_complex.AppErr != api_get_error()){
prew_notify_complex.AppErr = api_get_error();
app_flags.b_SendNotification = true;
}
if(app_flags.b_SendNotification == true){
com_slave_send_state(); app_flags.b_SendNotification = false;
}
}
/*********************************************************************************
********************* API (описание в application_api.h) *******************************
**********************************************************************************/
/********************************************************************************
* @brief Функция запроса флага пейринга
*********************************************************************************/
bool api_get_pairing_flag(void)
{
return app_flags.b_Pairing;
}
/********************************************************************************
* @brief Функция сброса флага открытой сессии
*********************************************************************************/
void api_clear_SessionIsOpened_flag(void)
{
if(app_flags.b_SessionIsOpened == true){
if((api_get_state() == APP_API_FW_UPDATE_STATE) ||
(api_get_state() == APP_PAIRING) )
{
api_state_change(APP_STAND_BY);
}
}
app_flags.b_SessionIsOpened = false;
}
/********************************************************************************
* @brief Функция установки флага открытой сессии
*********************************************************************************/
void api_set_SessionIsOpened_flag(void)
{
app_flags.b_SessionIsOpened = true;
}
/********************************************************************************
* @brief Функция запроса версии
*********************************************************************************/
uint16_t api_get_version(void)
{
return FIRMWARE_VER;
}
/********************************************************************************
* @brief Функция смены состояний
*********************************************************************************/
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 );
}
/********************************************************************************
* @brief Функция возвращает следующую стадию готовки в зависимости
* от настроек текущего стейта и настроек готовки
*********************************************************************************/
app_state_t api_get_next_cooking_state(void)
{
switch(app_state)
{
case APP_STAND_BY:
if(cooking_settings.Order.pre_heating == ENABLE_PHASE){
return APP_PRE_HEATING;
}
else if(cooking_settings.Order.waiting_product == ENABLE_PHASE){
return APP_WAITING_PRODUCT;
}else{
return APP_COOKING;
}
case APP_PRE_HEATING:
if(cooking_settings.Order.waiting_product == ENABLE_PHASE){
return APP_WAITING_PRODUCT;
}else{
return APP_COOKING;
}
case APP_WAITING_PRODUCT:
return APP_COOKING;
case APP_COOKING:
if(cooking_settings.Order.re_heating == ENABLE_PHASE){
return APP_RE_HEATING;
}
else if(cooking_settings.Order.waiting_product == ENABLE_PHASE){
return APP_WAITING_PRODUCT;
}else{
return APP_STAND_BY;
}
case APP_RE_HEATING:
return APP_STAND_BY;
case APP_DEFERRED_START:
if(cooking_settings.Order.pre_heating == ENABLE_PHASE){
return APP_PRE_HEATING;
}
else if(cooking_settings.Order.waiting_product == ENABLE_PHASE){
return APP_WAITING_PRODUCT;
}else{
return APP_COOKING;
}
case APP_SLAVE_FW_UPDATE:
case APP_PAIRING:
case APP_UNPAIRING:
case APP_SELFTEST:
case APP_START:
case APP_ERROR:
default:
return APP_STAND_BY;
}
}
/********************************************************************************
* @brief Функция запроса состояния
*********************************************************************************/
uint8_t api_get_state(void)
{
switch(app_state)
{
case APP_STAND_BY:
return APP_API_STAND_BY_STATE;
case APP_PRE_HEATING:
if(cooking_settings.Programm == APP_PROG_RE_HEATING){
return APP_API_COOKING_STATE;
}else{
return APP_API_PRE_HEATING_STATE;
}
case APP_WAITING_PRODUCT:
return APP_API_WAITING_PRODUCT_STATE;
case APP_COOKING:
return APP_API_COOKING_STATE;
case APP_RE_HEATING:
return APP_API_RE_HEATING_STATE;
case APP_SLAVE_FW_UPDATE:
return APP_API_FW_UPDATE_STATE;
case APP_DEFERRED_START:
return APP_API_DEFERRED_START_STATE;
case APP_PAIRING:
case APP_UNPAIRING:
case APP_SELFTEST:
case APP_START:
case APP_ERROR:
default:
return APP_API_ERROR_STATE;
}
}
/********************************************************************************
* @brief Функция запроса ошибки
*********************************************************************************/
uint8_t api_get_error(void)
{
switch(app_state)
{
case APP_SELFTEST:
return APP_API_IN_SELFTEST_ERROR;
case APP_START:
case APP_STAND_BY:
case APP_PRE_HEATING:
case APP_WAITING_PRODUCT:
case APP_COOKING:
case APP_RE_HEATING:
case APP_DEFERRED_START:
case APP_PAIRING:
case APP_UNPAIRING:
case APP_SLAVE_FW_UPDATE:
case APP_ERROR:
default:
return APP_API_NO_ERROR;
}
}
/********************************************************************************
* @brief Функция сравнения текущего состояния
*********************************************************************************/
bool api_state_check(app_state_t state)
{
if(app_state == state){
return true;
}else{
return false;
}
}
/********************************************************************************
* @brief Функция начала готовки
*********************************************************************************/
uint8_t api_start(void)
{
if((cooking_settings.Programm < PROG_MAX_COUNT) &&
(cooking_settings.Programm != APP_PROG_MANUAL) &&
(cooking_settings.CookingTime_s != 0) &&
(api_state_check(APP_STAND_BY) || api_state_check(APP_WAITING_PRODUCT)) )
{
if(cooking_settings.DefStartTime_s != 0){
api_state_change(APP_DEFERRED_START);
}else{
api_state_change(api_get_next_cooking_state());
}
return 1;
}else{
return 0;
}
}
/********************************************************************************
* @brief Функция начала готовки
*********************************************************************************/
uint8_t api_stop(void)
{
api_state_change(APP_STAND_BY);
return 1;
}
/********************************************************************************
* @brief Функция проверки параметров праграммы готовки
*********************************************************************************/
uint8_t api_check_cook_param(uint8_t prog, uint8_t hour, uint8_t min, uint8_t sec, uint8_t ds_hour, uint8_t ds_min, uint8_t ds_sec, uint8_t re_heat, uint8_t off_pre_heat)
{
uint32_t cook_time;
uint32_t defered_start_time;
if(app_state != APP_STAND_BY) return 0;
if(hour > 12) return 0;
if(min > 59) return 0;
if(sec > 59) return 0;
if(ds_hour > 12) return 0;
if(ds_min > 59) return 0;
if(ds_sec > 59) return 0;
if(re_heat > 1) return 0;
if(off_pre_heat > 1) return 0;
defered_start_time = ds_hour*3600 + ds_min*60 + ds_sec;
if(defered_start_time != 0){
if((defered_start_time < APP_MIN_DEF_START_TIME_s) ||
(defered_start_time > APP_MAX_DEF_START_TIME_s) ||
((defered_start_time % APP_STEP_DEF_START_TIME_s) != 0))
{
return 0;
}
}
cook_time = hour*3600 + min*60 + sec;
switch(prog)
{
case APP_PROG_FRY:
if((cook_time < APP_MIN_FRY_TIME_s) ||
(cook_time > APP_MAX_FRY_TIME_s) ||
((cook_time % APP_STEP_FRY_TIME_s) != 0))
{
return 0;
}
return 1;
case APP_PROG_RE_HEATING:
if((cook_time < APP_MIN_RE_HEATING_TIME_s) ||
(cook_time > APP_MAX_RE_HEATING_TIME_s) ||
((cook_time % APP_STEP_RE_HEATING_TIME_s) != 0) )
{
return 0;
}
if(re_heat != 0) return 0;
if(off_pre_heat != 0) return 0;
return 1;
default:
return 0;
}
}
/********************************************************************************
* @brief Функция установки программы готовки
*********************************************************************************/
uint8_t api_set_program(uint8_t new_program)
{
if(api_state_check(APP_STAND_BY)){
if((new_program < PROG_MAX_COUNT) &&
(new_program != APP_PROG_MANUAL))
{
switch(new_program)
{
case APP_API_FRY_PROG:
cooking_settings.Programm = APP_PROG_FRY; cooking_settings.CookingTime_s = APP_MIN_FRY_TIME_s;
break;
case APP_API_RE_HEATING_PROG:
cooking_settings.Programm = APP_PROG_RE_HEATING;
cooking_settings.CookingTime_s = APP_MIN_RE_HEATING_TIME_s;
break;
default:
return 0;
}
cooking_settings.DefStartTime_s = 0;
cooking_settings.StateOutTime_s = 0;
cooking_settings.Order.pre_heating = cooking_default_order[cooking_settings.Programm].pre_heating;
cooking_settings.Order.waiting_product = cooking_default_order[cooking_settings.Programm].waiting_product;
cooking_settings.Order.re_heating = cooking_default_order[cooking_settings.Programm].re_heating;
return 1;
}else{
return 0;
}
}else{
return 0;
}
}
/********************************************************************************
* @brief Функция запроса программы готовки
*********************************************************************************/
uint8_t api_get_program(void)
{
return cooking_settings.Programm;
}
/********************************************************************************
* @brief Функция установки времени готовки в секундах
*********************************************************************************/
uint8_t api_set_cook_time(uint8_t hour, uint8_t min, uint8_t sec)
{
if((app_state != APP_STAND_BY) &&
(app_state != APP_DEFERRED_START) &&
(app_state != APP_PRE_HEATING) &&
(app_state != APP_WAITING_PRODUCT) &&
(app_state != APP_COOKING))
{
return 0;
}
uint32_t cook_time;
if(hour > 12) return 0;
if(min > 59) return 0;
if(sec > 59) return 0;
cook_time = hour*3600 + min*60 + sec;
switch(cooking_settings.Programm)
{
case APP_PROG_FRY:
if((cook_time < APP_MIN_FRY_TIME_s) ||
(cook_time > APP_MAX_FRY_TIME_s) ||
((cook_time % APP_STEP_FRY_TIME_s) != 0) )
{
return 0;
}
if(api_state_check(APP_COOKING)){
if(cook_time >= cooking_settings.CookingTime_s){
cooking_settings.StateOutTime_s += (cook_time - cooking_settings.CookingTime_s);
}else{
if(cooking_settings.StateOutTime_s <=
(cooking_settings.CookingTime_s - cook_time))
{
return 0;
}else{
cooking_settings.StateOutTime_s -= (cooking_settings.CookingTime_s - cook_time);
}
}
}
cooking_settings.CookingTime_s = cook_time;
return 1;
case APP_PROG_RE_HEATING:
if((cook_time < APP_MIN_RE_HEATING_TIME_s) ||
(cook_time > APP_MAX_RE_HEATING_TIME_s) ||
((cook_time % APP_STEP_RE_HEATING_TIME_s) != 0) )
{
return 0;
}
if(api_state_check(APP_COOKING)){
if(cook_time >= cooking_settings.CookingTime_s){
cooking_settings.StateOutTime_s += (cook_time - cooking_settings.CookingTime_s);
}else{
if(cooking_settings.StateOutTime_s <=
(cooking_settings.CookingTime_s - cook_time))
{
return 0;
}else{
cooking_settings.StateOutTime_s -= (cooking_settings.CookingTime_s - cook_time);
}
}
}
cooking_settings.CookingTime_s = cook_time;
return 1;
default:
return 0;
}
}
/********************************************************************************
* @brief Функция запроса времени готовки в секундах
*********************************************************************************/
uint32_t api_get_cook_time(void)
{
return cooking_settings.CookingTime_s;
}
/********************************************************************************
* @brief Функция запроса изначально установленного времени состояния.
* То время, от которого идёт обратный отсчёт до выхода из текущего состояния.
* Время не декрементится и используется для восстановления прогресса
* текущего состояния.
*********************************************************************************/
uint32_t api_get_original_state_time(void)
{
switch(app_state)
{
case APP_PRE_HEATING:
if(cooking_settings.Programm != APP_PROG_RE_HEATING){
return APP_PRE_HEATING_TIMEOUT_s;
}else{
return cooking_settings.CookingTime_s;
}
case APP_WAITING_PRODUCT:
return APP_WAITING_PRODUCT_TIMEOUT_s;
case APP_COOKING:
return cooking_settings.CookingTime_s;
case APP_RE_HEATING:
return APP_RE_HEATING_TIMEOUT_s;
case APP_DEFERRED_START:
return cooking_settings.DefStartTime_s;
case APP_SELFTEST:
case APP_START:
case APP_STAND_BY:
case APP_PAIRING:
case APP_UNPAIRING:
case APP_SLAVE_FW_UPDATE:
case APP_ERROR:
default:
return 0;
}
}
/********************************************************************************
* @brief Функция запроса оставшегося времени готовки в секундах
*********************************************************************************/
uint32_t api_get_end_cook_time(void)
{
if(api_state_check(APP_COOKING)){
return cooking_settings.StateOutTime_s;
}
else if((api_state_check(APP_PRE_HEATING)) &&
(cooking_settings.Programm == APP_PROG_RE_HEATING))
{
return (cooking_settings.CookingTime_s - (APP_PRE_HEATING_FOR_RE_HEATING_s - cooking_settings.StateOutTime_s));
}else{
return cooking_settings.CookingTime_s;
}
}
/********************************************************************************
* @brief Функция запроса времени оставшегося до выхода из состояния
*********************************************************************************/
uint32_t api_get_state_out_time(void)
{
if((api_state_check(APP_PRE_HEATING)) &&
(cooking_settings.Programm == APP_PROG_RE_HEATING))
{
return (cooking_settings.CookingTime_s - (APP_PRE_HEATING_FOR_RE_HEATING_s - cooking_settings.StateOutTime_s));
}else{
return cooking_settings.StateOutTime_s;
}
}
/********************************************************************************
* @brief Функция установки времени отложенного старта в секундах
*********************************************************************************/
uint8_t api_set_defered_start_time(uint8_t ds_hour, uint8_t ds_min, uint8_t ds_sec)
{
if((app_state != APP_STAND_BY) &&
(app_state != APP_DEFERRED_START) )
{
return 0;
}
uint32_t defered_start_time;
if(ds_hour > 12) return 0;
if(ds_min > 59) return 0;
if(ds_sec > 59) return 0;
defered_start_time = ds_hour*3600 + ds_min*60 + ds_sec;
if(defered_start_time != 0){
if((defered_start_time < APP_MIN_DEF_START_TIME_s) ||
(defered_start_time > APP_MAX_DEF_START_TIME_s) ||
((defered_start_time % APP_STEP_DEF_START_TIME_s) != 0))
{
return 0;
}
}
switch(cooking_settings.Programm)
{
case APP_PROG_FRY:
case APP_PROG_RE_HEATING:
if(api_state_check(APP_DEFERRED_START)){
if(defered_start_time >= cooking_settings.DefStartTime_s){
cooking_settings.StateOutTime_s += (defered_start_time - cooking_settings.DefStartTime_s);
}else{
if(cooking_settings.StateOutTime_s <=
(cooking_settings.DefStartTime_s - defered_start_time)){
return 0;
}else{
cooking_settings.StateOutTime_s -= (cooking_settings.DefStartTime_s - defered_start_time);
}
}
}
cooking_settings.DefStartTime_s= defered_start_time;
return 1;
default:
return 0;
}
}
/********************************************************************************
* @brief Функция запроса времени отложенного старта в секундах
*********************************************************************************/
uint32_t api_get_defered_start_time(void)
{
return cooking_settings.DefStartTime_s;
}
/********************************************************************************
* @brief Функция установки подогрева по завершении программы
*********************************************************************************/
uint8_t api_set_reheat(uint8_t reheat_flag)
{
if(cooking_settings.Programm != APP_PROG_MANUAL){
if(reheat_flag == 1){
if (cooking_settings.Programm != APP_PROG_RE_HEATING){
cooking_settings.Order.re_heating = ENABLE_PHASE;
}else{
return 0;
}
}
else if(reheat_flag == 0){
cooking_settings.Order.re_heating = DISABLE_PHASE;
}else{
return 0;
}
return 1;
}else{
return 0;
}
}
/********************************************************************************
* @brief Функция запроса подогрева по завершении программы
*********************************************************************************/
uint8_t api_get_reheat(void)
{
return cooking_settings.Order.re_heating;
}
/********************************************************************************
* @brief Функция отключения нагрева панелей до температуры готовки перед ожиданием закладки продукта
*********************************************************************************/
uint8_t api_set_off_preheat(uint8_t off_preheat_flag)
{
if(cooking_settings.Programm != APP_PROG_MANUAL){
if(off_preheat_flag == 1){
if(cooking_settings.Programm == APP_PROG_FRY){
cooking_settings.Order.pre_heating = DISABLE_PHASE;
}else{
return 0;
}
}
else if(off_preheat_flag == 0){
cooking_settings.Order.pre_heating = ENABLE_PHASE;
}else{
return 0;
}
return 1;
}else{
return 0;
}
}
/********************************************************************************
* @brief Функция запроса отключения нагрева панелей до температуры готовки перед ожиданием закладки продукта
*********************************************************************************/
uint8_t api_get_off_preheat(void)
{
if(cooking_settings.Order.pre_heating == ENABLE_PHASE){
return 0;
}
else if(cooking_settings.Order.pre_heating == DISABLE_PHASE){
return 1;
}
else{
return 0;
}
}
/********************************************************************************
* @brief Функция входа в режим обновления прошивки
*********************************************************************************/
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;
}
/********************************************************************************
* @brief Функция сброса таймера таймаута режима обновления прошивки
*********************************************************************************/
void api_fw_update_proc(void)
{
if( app_state == APP_SLAVE_FW_UPDATE ){
APP_ERROR_CHECK(timer_reset(TIMER_APP_TIMEOUT));
APP_ERROR_CHECK(timer_start(TIMER_APP_TIMEOUT));
}
}
/********************************************************************************
* @brief Функция записи данных pof_manager
*********************************************************************************/
void api_pof_write_data_in_flash(void)
{
pof_write_data_in_flash();
}
/********************************************************************************
* @brief Функция перехода в режим ожидания
*********************************************************************************/
uint8_t api_go_to_stand_by(void)
{
if((app_state != APP_STAND_BY ) &&
(app_state != APP_PAIRING ) &&
(app_state != APP_SLAVE_FW_UPDATE ))
{
return 0;
}
if( app_state == APP_PAIRING || app_state == APP_SLAVE_FW_UPDATE)
{
api_state_change(APP_STAND_BY);
}
return 1;
}
/********************************************************************************
* @brief Функция callback по успешному завершению пейринга
*********************************************************************************/
void api_slave_pairing_complete(void)
{
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
}
/********************************************************************************
* @brief Функция callback по неудачному завершению пейринга
*********************************************************************************/
void api_slave_pairing_error(void)
{
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
}
/********************************************************************************
* @brief Функция callback по неудачному обновлению прошивки
*********************************************************************************/
void api_slave_fw_update_error(void)
{
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
APP_ERROR_CHECK(buz_add_beep( APP_SMALL_BEEP_TIME, APP_SMALL_WAIT_BEEP_TIME, BUZ_BEEP_MULTI ));
}
/********************************************************************************/
void api_param_update(void)
{
}
/********************************************************************************/