#include "app_vlad.h"
#include "app_serv.h"
#include "time.h"
#include "mode.h"
#include "data.h"
#include "datadesc.h"
#include "menu.h"
#include "menudesc.h"
#include "journal.h"
#include "fr.h"
#include "fiscal.h"
#include "validator.h"
#include "CCRSProtocol.h"
#include "coin.h"
#include "term_tsk.h"
#include "modem_task.h"
#include "keyboard.h"
#include "music_tsk.h"
#include "score_tsk.h"
#include "host_app.h"
#include "crc16.h"
#include "fram.h"
#include "fram_map.h"
#include <math.h>
#include "ftp_app.h"

#include "rfid-spi.h"
#include "mfrc522data.h"

extern CPU_INT32U ChannelsPayedTime[CHANNELS_NUM];

ApplicationState app_state;

//static CPU_INT08U fr_conn_ctr = 0;
static CPU_INT08U cash_accept_enabled = 0;
static CPU_INT08U incassation = 0;
extern int player_conn;
CPU_INT08U start_pass_ok = 0;

void PrintHelloMenu(void);
void PrintStartReadCardMenu(void);
void PrintBalanceMenu(void);
void PrintMenuStartPay(void);
void PrintMenuAllPrice(CPU_INT08U blink);
void PrintSilverMenu(void);
void PrintGoldMenu(void);
void PrintPlatMenu(void);
void PrintDiamondMenu(void);
void PrintStartPayCardMenu(void);
void PrintInsertBankCardMenu(void);
void PrintInsertBonusCardMenu(void);
void PrintFinishPayMenu(void);
void PrintAnotherCardMenu(void);
void PrintSelectMethodPayCardMenu(CPU_INT08U blink);
void PrintWarning1Menu(void);
void PrintWarning2Menu(void);
void PrintWrongAbonementMenu(void);
void PrintSelectChMenu(CPU_INT08U blink);
void PrintSelectModeMenu(CPU_INT08U blink);
void PrintAckModeMenu(void);
void PrintSelectPayTypeMenu(CPU_INT08U blink);
void PrintCashPayingMenu(CPU_INT08U blink);
void PrintCardPayingMenu(CPU_INT08U blink);
void PrintTerminalRequestMenu(void);
void PrintThanksMenu(void);
void PrintSkinTypeAttentionMenu(CPU_INT08U skintype);
void PrintServiceTimeSelectMenu(CPU_INT08U blink);
void StopMusic(void);
int IsPlaying(void);
int MusicEnabled(void);

///
void app_1ms_callback(void)
{
    control_1ms_callback();
        
    if (app_state.blink_ctr >= 1000)
    {
        app_state.blink_ctr = 0;
        PostUserEvent(EVENT_BLINK);
    }
    else
    {
        app_state.blink_ctr++;
        if (app_state.blink_ctr == 500)
        {
            PostUserEvent(EVENT_BLINK);
        }
    }
}

SolarCounters counters;

void IncAbonentCounters(CPU_INT08U abonement, CPU_INT32U money, CPU_INT32U bonus)
{
    ReadArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);

    counters.abonement[abonement].card_money += money;
    counters.abonement[abonement].card_bonus += bonus;
    counters.abonement[abonement].runs++;

    counters.abonement[4].card_money += money;
    counters.abonement[4].card_bonus += bonus;
    counters.abonement[4].runs++;

    counters.checksum = crc16((unsigned char*)&counters, offsetof(SolarCounters, checksum));
    WriteArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);
}

void IncSolarAbonementCounters(CPU_INT08U ch, CPU_INT08U mode, CPU_INT32U money, CPU_INT32U bonus)
{
    ReadArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);

    counters.solar_chm[ch * SOLAR_MODES_COUNT + mode].card_money += money;
    counters.solar_m[mode].card_money += money;

    counters.solar_chm[ch * SOLAR_MODES_COUNT + mode].card_bonus += bonus;
    counters.solar_m[mode].card_bonus += bonus;
    
    counters.abonement_money += money;
    counters.common_money += (money * 100); // * 100 тк переменная от банковского терминала

    counters.checksum = crc16((unsigned char*)&counters, offsetof(SolarCounters, checksum));
    WriteArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);
}

///
void IncSolarCounters(CPU_INT08U ch, CPU_INT08U mode, CPU_INT32U worktime, CPU_INT32U money, CPU_INT08U card, CPU_INT32U bonus)
{
    //SolarCounters counters;
    ReadArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);

    if (card == 2)
    {
        /*counters.solar_chm[ch * SOLAR_MODES_COUNT + mode].card_money += money;
        counters.solar_m[mode].card_money += money;

        counters.solar_chm[ch * SOLAR_MODES_COUNT + mode].card_bonus += bonus;
        counters.solar_m[mode].card_bonus += bonus;*/
    }
    else
    {
        counters.solar_chm[ch * SOLAR_MODES_COUNT + mode].money += money;
        counters.solar_m[mode].money += money;
    }

    if (worktime > 0)
    {
        counters.solar_chm[ch * SOLAR_MODES_COUNT + mode].runs += 1;
        counters.solar_chm[ch * SOLAR_MODES_COUNT + mode].worktime += worktime;
        counters.solar_m[mode].runs += 1;
        counters.solar_m[mode].worktime += worktime;
    }

    if ((mode == SUNBURN_MODE_COLLATEN) || (mode == SUNBURN_MODE_MAX))
    {
        counters.collaten_time[ch] += worktime;
    }

    if ((mode == SUNBURN_MODE_UF) || (mode == SUNBURN_MODE_MAX))
    {
        counters.uf_time[ch] += worktime;
    }

    if(card == 2)
    {
        //counters.abonement_money += money;
    }
    else if (card)
    {
        counters.common_money += money;
        counters.card_money += money;
    }
    else
    {
        counters.common_money += money;
        counters.cash_money += money;
    }
    
    counters.checksum = crc16((unsigned char*)&counters, offsetof(SolarCounters, checksum));
    WriteArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);
}  

///
void IncSolarTestCounters(CPU_INT08U ch, CPU_INT08U mode, CPU_INT32U worktime)
{
    //SolarCounters counters;
    ReadArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);

    if (worktime > 0)
    {
        counters.solar_chm_test[ch * SOLAR_MODES_COUNT + mode].runs += 1;
        counters.solar_chm_test[ch * SOLAR_MODES_COUNT + mode].worktime += worktime;
        counters.solar_m_test[mode].runs += 1;
        counters.solar_m_test[mode].worktime += worktime;
        counters.test_count[ch] += 1;
        counters.test_time[ch] += worktime;
    }

    if (counters.test_count[ch] > 0)
    {
        counters.test_mean_time[ch] = counters.test_time[ch] / counters.test_count[ch];
    }
    
    if ((mode == SUNBURN_MODE_COLLATEN) || (mode == SUNBURN_MODE_MAX))
    {
        counters.collaten_time[ch] += worktime;
    }

    if ((mode == SUNBURN_MODE_UF) || (mode == SUNBURN_MODE_MAX))
    {
        counters.uf_time[ch] += worktime;
    }
    
    counters.checksum = crc16((unsigned char*)&counters, offsetof(SolarCounters, checksum));
    WriteArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);
}  

///
void IncSolarCleaningCounters(CPU_INT08U ch, CPU_INT32U cleaning_time)
{
    //SolarCounters counters;
    ReadArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);
    if (cleaning_time > 0)
    {
        counters.cleaning_count[ch] += 1;
        counters.cleaning_time[ch] += cleaning_time;
    }
    if (counters.cleaning_count[ch] > 0)
    {
        counters.cleaning_mean_time[ch] = counters.cleaning_time[ch] / counters.cleaning_count[ch];
    }
    counters.checksum = crc16((unsigned char*)&counters, offsetof(SolarCounters, checksum));
    WriteArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);
}  

///
void CheckSolarCounters(void)
{
    //SolarCounters counters;
    ReadArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);
    if (crc16((unsigned char*)&counters, offsetof(SolarCounters, checksum)) != counters.checksum)
    {
        memset(&counters, 0, sizeof(SolarCounters));
        counters.checksum = crc16((unsigned char*)&counters, offsetof(SolarCounters, checksum));
        WriteArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);
    }
}  

void ClearAbonementCounters(void)
{
    ReadArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);

    memset(&counters.abonement[0], 0, sizeof(AbonentCountersRecord) * 5);
    
    counters.abonement_money = 0;

    counters.solar_chm[0].card_money = 0;
    counters.solar_chm[0].card_bonus = 0;
    counters.solar_chm[1].card_money = 0;
    counters.solar_chm[1].card_bonus = 0;
    counters.solar_chm[2].card_money = 0;
    counters.solar_chm[2].card_bonus = 0;
    counters.solar_chm[3].card_money = 0;
    counters.solar_chm[3].card_bonus = 0;

    counters.solar_m[0].card_money = 0;
    counters.solar_m[0].card_bonus = 0;
    counters.solar_m[1].card_money = 0;
    counters.solar_m[1].card_bonus = 0;
    counters.solar_m[2].card_money = 0;
    counters.solar_m[2].card_bonus = 0;

    counters.checksum = crc16((unsigned char*)&counters, offsetof(SolarCounters, checksum));
    WriteArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);   
}

///
void SolarClearAllCounters(void)
{
    //SolarCounters counters;
    ReadArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);
    /// счетчики по соляриям и режимам
    memset(&counters.solar_chm[0], 0, sizeof(SolarCountersRecord) * CHANNELS_NUM * SOLAR_MODES_COUNT);
    memset(&counters.solar_chm_test[0], 0, sizeof(SolarCountersRecord) * CHANNELS_NUM * SOLAR_MODES_COUNT);
    /// счетчики по режимам
    memset(&counters.solar_m[0], 0, sizeof(SolarCountersRecord) * SOLAR_MODES_COUNT);
    memset(&counters.solar_m_test[0], 0, sizeof(SolarCountersRecord) * SOLAR_MODES_COUNT);
    memset(&counters.abonement[0], 0, sizeof(AbonentCountersRecord) * 5);
    // отработанное время коллатен+макси по соляриям
    //CPU_INT32U collaten_time[CHANNELS_NUM];
    // отработанное время ультрафиолет+макси по соляриям
    //CPU_INT32U uf_time[CHANNELS_NUM];
    counters.common_money = 0;
    counters.cash_money = 0;
    counters.card_money = 0;
    counters.abonement_money = 0;
    counters.bill_count = 0;
    memset(&counters.cleaning_count[0], 0, sizeof(CPU_INT32U) * CHANNELS_NUM);
    memset(&counters.cleaning_time[0], 0, sizeof(CPU_INT32U) * CHANNELS_NUM);
    counters.checksum = crc16((unsigned char*)&counters, offsetof(SolarCounters, checksum));
    WriteArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);
}

///
void SolarClearLampsCounters(CPU_INT08U ch)
{
    //SolarCounters counters;
    ReadArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);
    counters.collaten_time[ch] = 0;
    counters.uf_time[ch] = 0;
    counters.test_count[ch] = 0;
    counters.test_time[ch] = 0;
    counters.cleaning_count[ch] = 0;
    counters.cleaning_time[ch] = 0;
    counters.cleaning_mean_time[ch] = 0;
    counters.test_mean_time[ch] = 0;
    counters.checksum = crc16((unsigned char*)&counters, offsetof(SolarCounters, checksum));
    WriteArrayFram(offsetof(TFramMap, solar_counters), sizeof(SolarCounters), (unsigned char*)&counters);
}

///
CPU_INT08U CheckSkinTypeAttention(CPU_INT32U suntime)
{
    for (CPU_INT08U i = 0; i < 4; i++)
    {
        CPU_INT32U max_time;
            
        if (app_state.skin_flags & (1 << i)) continue;
        
        if (app_state.mode_index == 0)
        {
            GetData(&SkinCollatenMaxTimeDesc, &max_time, i, DATA_FLAG_DIRECT_INDEX);
        }
        else if (app_state.mode_index == 1)
        {
            GetData(&SkinUFMaxTimeDesc, &max_time, i, DATA_FLAG_DIRECT_INDEX);
        }
        else
        {
            GetData(&SkinMaximalMaxTimeDesc, &max_time, i, DATA_FLAG_DIRECT_INDEX);
        }
        
        if (max_time)
        {
            max_time *= 60;
            if (suntime >= max_time)
            {
                app_state.skin_flags |= (1 << i);
                return i + 1;
            }
        }
    }
    return 0;
}

///
void AppInitVlad(void)
{
    app_state.user_menu = USER_MENU_IDLE;

    CheckSolarCounters();
        
    // проверим, висит ли оплата на соляриях    
    for (int i = 0; i < CHANNELS_NUM; i++)
    {
        CPU_INT32U d[2], crc, crct;
        
        GetData(&SolariumTimePayedDesc, &d[0], i, DATA_FLAG_DIRECT_INDEX);
        GetData(&SolariumMoneyPayedDesc, &d[1], i, DATA_FLAG_DIRECT_INDEX);
        crct = crc16((unsigned char*)&d, sizeof(CPU_INT32U) * 2);
        GetData(&SolariumTimePayedCrc16Desc, &crc, i, DATA_FLAG_DIRECT_INDEX);    
        if (crct != crc)
        {
            // обнуляем, если crc не сошлась
            d[0] = d[1] = 0;
            crc = crc16((unsigned char*)&d, sizeof(CPU_INT32U) * 2);
            SetData(&SolariumTimePayedDesc, &d[0], i, DATA_FLAG_DIRECT_INDEX);
            SetData(&SolariumMoneyPayedDesc, &d[1], i, DATA_FLAG_DIRECT_INDEX);
            SetData(&SolariumTimePayedCrc16Desc, &crc, i, DATA_FLAG_DIRECT_INDEX);
        }
        
        PostScoreClear(i);
    }
}

/// сохранение денег для канала (деньги списываются, если в солярии нажали СТАРТ)
void SaveTimeMoneyForChannel(CPU_INT08U ch, CPU_INT32U time, CPU_INT32U money)
{
    CPU_INT32U d[2], crc;
    d[0] = time;
    d[1] = money;
    crc = crc16((unsigned char*)&d, sizeof(CPU_INT32U) * 2);
    SetData(&SolariumTimePayedDesc, &d[0], ch, DATA_FLAG_DIRECT_INDEX);
    SetData(&SolariumMoneyPayedDesc, &d[1], ch, DATA_FLAG_DIRECT_INDEX);
    SetData(&SolariumTimePayedCrc16Desc, &crc, ch, DATA_FLAG_DIRECT_INDEX);
}

///
CPU_INT32U GetPayedMoneyForChannel(CPU_INT08U ch)
{
    CPU_INT32U d[2], crc, crct;
    
    GetData(&SolariumTimePayedDesc, &d[0], ch, DATA_FLAG_DIRECT_INDEX);
    GetData(&SolariumMoneyPayedDesc, &d[1], ch, DATA_FLAG_DIRECT_INDEX);
    crct = crc16((unsigned char*)&d, sizeof(CPU_INT32U) * 2);
    GetData(&SolariumTimePayedCrc16Desc, &crc, ch, DATA_FLAG_DIRECT_INDEX);    
    if (crct != crc)
    {
        return 0;
    }
    return d[1];
}

///
CPU_INT32U GetPayedTimeForChannel(CPU_INT08U ch)
{
    CPU_INT32U d[2], crc, crct;
    
    GetData(&SolariumTimePayedDesc, &d[0], ch, DATA_FLAG_DIRECT_INDEX);
    GetData(&SolariumMoneyPayedDesc, &d[1], ch, DATA_FLAG_DIRECT_INDEX);
    crct = crc16((unsigned char*)&d, sizeof(CPU_INT32U) * 2);
    GetData(&SolariumTimePayedCrc16Desc, &crc, ch, DATA_FLAG_DIRECT_INDEX);    
    if (crct != crc)
    {
        return 0;
    }
    return d[0];
}

///
int SolariumEnabled(CPU_INT08U ch)
{
    CPU_INT32U en;
    GetData(&EnableChannelDesc, &en, ch, DATA_FLAG_DIRECT_INDEX);
    if (en) return 1;
    return 0;
}

///
CPU_INT08U SolariumEnabledCount(void)
{
    CPU_INT08U en_count = 0;
    for (CPU_INT08U i = 0; i < CHANNELS_NUM; i++)
    {
        if (SolariumEnabled(i))
        {
            en_count++;
        }
    }
    return en_count;
}
///
int SolariumTimeToEnd(CPU_INT08U ch)
{
    CPU_INT32U timetoend = app_state.timetoend[ch];
            
    if (app_state.solar_state[ch] == SOLAR_STATE_TIMEOUT_PRE)
    {
        CPU_INT32U sec;
        timetoend += GetPayedTimeForChannel(ch);
        GetData(&SolarVentilationTimeMinutesDesc, &sec, ch, DATA_FLAG_DIRECT_INDEX);
        timetoend += sec * 60;
        GetData(&SolarTimeoutAfterMinutesDesc, &sec, ch, DATA_FLAG_DIRECT_INDEX);  
        if (app_state.solar_srv[ch] != SOLAR_IN_SERVICE) timetoend += sec * 60;
    }
    else if ((app_state.solar_state[ch] == SOLAR_STATE_SUNBURN) || (app_state.solar_state[ch] == SOLAR_STATE_PAUSE))
    {
        CPU_INT32U sec;
        GetData(&SolarVentilationTimeMinutesDesc, &sec, ch, DATA_FLAG_DIRECT_INDEX);  
        timetoend += sec * 60;
        GetData(&SolarTimeoutAfterMinutesDesc, &sec, ch, DATA_FLAG_DIRECT_INDEX);  
        if (app_state.solar_srv[ch] != SOLAR_IN_SERVICE) timetoend += sec * 60;
    }
    else if (app_state.solar_state[ch] == SOLAR_STATE_VENT)
    {
        CPU_INT32U sec;
        GetData(&SolarTimeoutAfterMinutesDesc, &sec, ch, DATA_FLAG_DIRECT_INDEX);  
        if (app_state.solar_srv[ch] != SOLAR_IN_SERVICE) timetoend += sec * 60;
    }
    
    return timetoend;
}

///
CPU_INT32U CalcCurrentDiscount(CPU_INT32U time)
{
    TRTC_Data rtc_time;
    CPU_INT32U d_hour, d_day, d_month, d_custom;

    Sec2Date(&rtc_time, time);

    // 1. час
    d_hour = 0;
    for (int i = 0; i < 4; i++)
    {
        CPU_INT32U begin, end;
        GetData(&DiscountBeginHourDesc, &begin, i, DATA_FLAG_DIRECT_INDEX);
        GetData(&DiscountEndHourDesc, &end, i, DATA_FLAG_DIRECT_INDEX);
        if ((rtc_time.hour >= begin) && (rtc_time.hour <= end))
        {
            GetData(&DiscountValueHourDesc, &d_hour, i, DATA_FLAG_DIRECT_INDEX);
            break;
        }
    }
    
    // 2. день недели
    GetData(&DiscountValueDayDesc, &d_day, rtc_time.day, DATA_FLAG_DIRECT_INDEX);
       
    // 3. месяц
    GetData(&DiscountValueMonthDesc, &d_month, (rtc_time.mon - 1) % 12, DATA_FLAG_DIRECT_INDEX);

    // 4. разовая скидка по дате
    d_custom = 0;
    {
        CPU_INT32U datesec;
        rtc_time.sec = 0;
        rtc_time.min = 0;
        rtc_time.hour = 0;
        datesec = GetSec(&rtc_time);
        for (int i = 0; i < 3; i++)
        {
            CPU_INT32U begin, end;
            GetData(&DiscountDateBeginCustomDesc, &begin, i, DATA_FLAG_DIRECT_INDEX);
            GetData(&DiscountDateEndCustomDesc, &end, i, DATA_FLAG_DIRECT_INDEX);
            if ((datesec >= begin) && (datesec < end + (3600UL * 24)))
            {
                GetData(&DiscountValueCustomDesc, &d_custom, i, DATA_FLAG_DIRECT_INDEX);
                break;
            }
        }
    }
    
    return (CPU_INT32U)(100.0 - (100.0 * (((100 - d_hour) * 0.01
           * (100 - d_day) * 0.01
           * (100 - d_month) * 0.01
           * (100 - d_custom) * 0.01))));
}

/// полчение текущей цены, в копейках
int GetPricePerMin(CPU_INT08U channel, CPU_INT08U mode)
{
    CPU_INT32U discount = CalcCurrentDiscount(SystemTime);
    CPU_INT32U price_nom;
    
    GetData(&SolarPricePerMinuteDesc, &price_nom, channel * SOLAR_MODES_COUNT + mode, DATA_FLAG_DIRECT_INDEX);
    return (int)(price_nom * (float)(100 - discount) / 100.0);
}

/// 
int PayTypeTermEnabled(void)
{
    CPU_INT32U term_en;
    GetData(&EnableTerminalDesc, &term_en, 0, DATA_FLAG_SYSTEM_INDEX);
    return term_en;
}

///
int PayTypeCashEnabled(void)
{
    CPU_INT32U validator_en, coin_en, abonement_en;
    GetData(&EnableValidatorDesc, &validator_en, 0, DATA_FLAG_SYSTEM_INDEX);  
    GetData(&EnableCoinDesc, &coin_en, 0, DATA_FLAG_SYSTEM_INDEX);
    GetData(&EnableAbonementDesc, &abonement_en, 0, DATA_FLAG_SYSTEM_INDEX);

    return validator_en | coin_en | abonement_en;
}

///
CPU_INT08U RelayChannelsMask(CPU_INT08U index)
{
    static const CPU_INT08U relay_mask[10] = {0x01, 0x02, 0x04, 0x08, 0x03, 0x05, 0x09, 0x06, 0x0A, 0x0C};
    CPU_INT32U channel;
    GetData(&RelayChannelDesc, &channel, index, DATA_FLAG_DIRECT_INDEX);
    if (channel < 10) return relay_mask[channel];
    return 0;
}

/// очистка режима сервиса с сохранением в журнал
void ClearSolarService(CPU_INT08U ch)
{
    if (app_state.solar_srv[ch] == SOLAR_IN_SERVICE)
    {
        SaveEventRecord(ch, JOURNAL_EVENT_SOLARIUM_SERVICE_END, 0);
    }
    else if (app_state.solar_srv[ch] == SOLAR_IN_TEST)
    {
        SaveEventRecord(ch, JOURNAL_EVENT_SOLARIUM_TESTMODE_END, 0);
    }
    else if (app_state.solar_state[ch] != SOLAR_STATE_FREE)
    {
        SaveEventRecord(ch, JOURNAL_EVENT_END_SESSION, 0);
    }
    app_state.solar_srv[ch] = 0;
}
            
/// 
static void WorkServer(void)
{
    for (int i = 0; i < CHANNELS_NUM; i++)
    {
        if (app_state.solar_state[i] == SOLAR_STATE_TIMEOUT_PRE)
        {
            if (app_state.timetoend[i])
            {
                app_state.timetoend[i]--;
                continue;
            }
            // кончилось время ожидания, кнопку СТАРТ внутри солярия не нажали
            app_state.solar_state[i] = SOLAR_STATE_SUNBURN;
            app_state.timetoend[i] = GetPayedTimeForChannel(i);
            app_state.pause_timeout[i] = 0;
            SaveTimeMoneyForChannel(i, 0, 0);
            SetControl(i, CONTROL_STATE_COLLATEN + app_state.sunburn_mode[i]);
        }
        else if (app_state.solar_state[i] == SOLAR_STATE_SUNBURN)
        {
            if (app_state.timetoend[i])
            {
                app_state.timetoend[i]--;
                continue;
            }
            GetData(&SolarVentilationTimeMinutesDesc, &app_state.timetoend[i], i, DATA_FLAG_DIRECT_INDEX);  
            app_state.timetoend[i] *= 60;
            app_state.solar_state[i] = SOLAR_STATE_VENT;
            SetControl(i, CONTROL_STATE_OFF);
        }
        else if (app_state.solar_state[i] == SOLAR_STATE_PAUSE)
        {
            if (app_state.pause_timeout[i] < SOLAR_PAUSE_TIMEOUT)
            {
                SetControl(i, CONTROL_STATE_PAUSED);
                app_state.pause_timeout[i]++;
            }
            else
            {
                GetData(&SolarVentilationTimeMinutesDesc, &app_state.timetoend[i], i, DATA_FLAG_DIRECT_INDEX);  
                app_state.timetoend[i] *= 60;
                app_state.solar_state[i] = SOLAR_STATE_VENT;
                SetControl(i, CONTROL_STATE_OFF);
            }
        }                        
        else if (app_state.solar_state[i] == SOLAR_STATE_VENT)
        {
            if (app_state.timetoend[i])
            {
                app_state.timetoend[i]--;
                SetControl(i, CONTROL_STATE_VENT);
                continue;
            }
            GetData(&SolarTimeoutAfterMinutesDesc, &app_state.timetoend[i], i, DATA_FLAG_DIRECT_INDEX);  
            if (app_state.solar_srv[i] == SOLAR_IN_SERVICE) app_state.timetoend[i] = 0;
            else app_state.timetoend[i] *= 60;
            app_state.solar_state[i] = SOLAR_STATE_TIMEOUT_AFTER;
            SetControl(i, CONTROL_STATE_OFF);
        }
        else if (app_state.solar_state[i] == SOLAR_STATE_TIMEOUT_AFTER)
        {
            SetControl(i, CONTROL_STATE_OFF);
            if (app_state.timetoend[i])
            {
                app_state.timetoend[i]--;
                continue;
            }
            ClearSolarService(i);
            app_state.solar_state[i] = SOLAR_STATE_FREE;
            PostUserEvent(EVENT_CLOSE_RELAY1 + i);
            PostScoreClear(i);
        }
        else if (app_state.solar_state[i] == SOLAR_STATE_CLEANING)
        {
            CPU_INT32U cleaning_timeout;
            GetData(&SolarCleaningTimeoutMinutesDesc, &cleaning_timeout, 0, DATA_FLAG_SYSTEM_INDEX);  
            cleaning_timeout *= 60;
            CPU_INT32U cleaning_time = GetTimeSec() - app_state.time_cleaning_start[i];
            if ((cleaning_timeout > 0) && (cleaning_time >= cleaning_timeout))
            {
                app_state.solar_state[i] = SOLAR_STATE_FREE;
                app_state.solar_srv[i] = 0;
                PostUserEvent(EVENT_CLOSE_RELAY1 + i);
                SaveEventRecord(i, JOURNAL_EVENT_SOLARIUM_CLEANING_END, cleaning_time);
                IncSolarCleaningCounters(i, cleaning_time);
            }
        }
    }
}

///
static int AppCanStart(void)
{
    if (GetMode() != MODE_WORK)
    {
        return 0;
    }
    if (!start_pass_ok)
    {
        return 0;
    }
    #if !APP_DEBUG
    if (TstCriticalErrors())
    {
        return 0;
    }
    #endif
    if (incassation)
    {
        return 0;
    }
    return 1;
}

/// 
void AppVladEventProcess(CPU_INT32U event)
{
    switch (event)
    {
        case EVENT_SEC:
            {
                //NetDbg_ChkStatus();
                // прочитаем текущее время
                SystemTime = GetTimeSec();
                {
                    current_discount = CalcCurrentDiscount(SystemTime);
                }
                
                #if APP_DEBUG
                if ((SystemTime % 30) == 0)
                {
                    file_menu_cmd = (file_menu_cmd + 1) % 20;
                    if (!file_menu_cmd) file_menu_cmd++;
                    PostUserEvent(EVENT_PLAY_SOUND_FILE);
                }

                if ((SystemTime % 10) == 0)
                {
                     static uint8_t counter = 0;
                     PostUserEvent(EVENT_OPEN_RELAY1 + counter);
                     counter = (counter + 1) % 6;
                }
                #endif
                
                // проверка режима
                CheckMode();
                // рабочий сервер - счетчики, состояния и т.п.
                WorkServer();
                if (GetMode() == MODE_WORK)
                {
                    SetBacklight(LED_OK, 1);
                }
                else
                {
                    SetBacklight(LED_OK, 0);
                }
                    
                for (int i = 0; i < RELAY_COUNT; i++)
                {
                    if (app_state.relay_timeout[i])
                    {
                        app_state.relay_timeout[i]--;
                        if (!app_state.relay_timeout[i])
                        {
                            PostUserEvent(EVENT_CLOSE_RELAY1 + i);
                            relay_cmd = 0;
                        }
                    }
                }
                
                // проверим фискальник, если он отвалился
                /*if ((++fr_conn_ctr % 10) == 0)
                {
                    if ((FiscalConnState == FISCAL_NOCONN) || (TstCriticalFiscalError()))
                    {
                        if (ConnectFiscalFast() == 0)
                        {
                            CheckFiscalStatus();
                        }
                    }
                }*/
                
                // сервер ошибок
                ErrorServer();
    
                CPU_INT32U sec_min = (SystemTime % 60);
                for (CPU_INT08U i = 0; i < CHANNELS_NUM; i++)
                {
                    if ((sec_min == i) || (sec_min == (30 + i)))
                    {
                        PostScoreEvent(SCORE_EVENT_UPDATE_PRICE1 + i);
                    }
                }
                    
                for (CPU_INT08U i = 0; i < CHANNELS_NUM; i++)
                {
                    for (CPU_INT08U j = 0; j < SOLAR_MODES_COUNT; j++)
                    {
                        CPU_INT32U price = GetPricePerMin(i, j);
                        SetData(&SolarCurrentPricePerMinuteDesc, &price, i * SOLAR_MODES_COUNT + j, DATA_FLAG_DIRECT_INDEX);
                    }
                }
                
                FtpCheckTimeToSend(SystemTime);

                if (file_menu_cmd)
                {
                    if (!IsPlaying())
                    {
                        file_menu_cmd = 0;
                    }
                }
            
                if (GetCurrentMenu() == FtpUploadInProgressMenu)
                {
                    if (time_to_ftp == 0)
                    {
                        CPU_INT32U ftp_result;
                        GetData(&FtpLastSendResultDesc, &ftp_result, app_state.ch_index, DATA_FLAG_DIRECT_INDEX);
                        if (ftp_result == 1)
                        {
                            GoToPreviousMenu(); 
                            GoToMenu(FtpOKMenu);
                        }
                        else
                        {
                            GoToPreviousMenu(); 
                            GoToMenu(FtpFAILMenu);
                        }
                    }
                }

                // дальше только в рабочем режиме
                if (GetMode() != MODE_WORK)
                {
                    // Look for new cards
                    /*if (picc_is_new_card_present() ) {
                        // Select one of the cards
                        if (picc_read_card_serial()) {
                            if(read_mifare_card() != NULL) {
                                if(is_empty_mifare_card()) {
                                    init_mifare_card_data();
        
                                    if(!write_mifare_card())
                                    {
                                        stop_card_working();
                                        break;
                                    }
                                }
                                
                                stop_card_working();
                            }
                        }
                    }*/

                    break;
                }

                // Look for new cards
                if (picc_is_new_card_present() ) {
                  
                    if(app_state.user_menu == USER_MENU_IDLE) {
                        // меню старта чтения карты
                        PrintStartReadCardMenu();
                        RefreshMenu();
                        PlayMusicFile(40);
                    }
                  
                    // Select one of the cards
                    if (picc_read_card_serial()) {
                        if(app_state.user_menu != USER_MENU_INSERT_BONUS_CARD
                        && app_state.user_menu != USER_MENU_ABONENT_PROCESSING) {
                            if(read_mifare_card() != NULL) {
                                if(is_empty_mifare_card()) {
                                    init_mifare_card_data();
        
                                    if(!write_mifare_card())
                                    {
                                        app_state.user_menu = USER_MENU_IDLE;
                                        stop_card_working();
                                        break;
                                    }
                                }
        
                                CPU_INT32U password;
                                GetData(&PassDescAdmin, &password, 0, DATA_FLAG_SYSTEM_INDEX);
                                if(get_abonement_data()->uid[0] != password)
                                {
                                    app_state.last_card_manipulation_time = OSTimeGet();

                                    app_state.user_menu = USER_MENU_ABONENT_WRONG;
                                    PrintWrongAbonementMenu();
                                    RefreshMenu();
                                    StopMusic();

                                    stop_card_working();

                                    TEventRecord record;    // 18 + 4 = 22
                                    record.event = JOURNAL_EVENT_ABONEMENT_WRONG;           // +1
                                    record.type_abonement = 0;                              // +1
                                    record.money = 0;                                       // +2
                                    record.bonus = 0;                                       // +2
                                    record.password = get_abonement_data()->uid[0];         // +4
                                    record.number_abonement = get_abonement_data()->number_abonement;  // +4
                                    record.money_sum = 0;                                   // +2
                                    record.bonus_sum = 0;                                   // +2

                                    SaveEventAbonementRecord(&record);

                                    break;
                                }

                                if(app_state.user_menu == USER_MENU_IDLE)
                                {
                                    // проверим - не надо ли бонусы очистить
                                    if(need_clear_bonus()) {
                                        // нужно - запишем это
                                        write_mifare_card();
                                    }

                                    // нужно показать баланс
                                    app_state.last_card_manipulation_time = OSTimeGet();

                                    app_state.user_menu = USER_MENU_BALANCE_CARD;
                                    PrintBalanceMenu();
                                    RefreshMenu();

                                    abonement_data* data = get_abonement_data();
                                    TEventRecord record;    // 18 + 4 = 22
                                    record.event = JOURNAL_EVENT_ABONEMENT_BALANCE;         // +1
                                    record.type_abonement = app_state.current_abonement;    // +1
                                    record.money = 0;                                       // +2
                                    record.bonus = 0;                                       // +2
                                    record.time_before = data->best_before;                 // +4
                                    record.number_abonement = data->number_abonement;       // +4
                                    record.money_sum = data->money;                         // +2
                                    record.bonus_sum = data->bonus;                         // +2

                                    SaveEventAbonementRecord(&record);

                                    PlayMusicFile(41);
                                }
                            } else {
                                app_state.user_menu = USER_MENU_IDLE;
                            }
                            
                            stop_card_working();
                        }

                        if(app_state.user_menu == USER_MENU_INSERT_BONUS_CARD)
                        {
                            if(read_mifare_card() != NULL)
                            {
                                // пополняем карту
                                abonement_data* data = get_abonement_data();

                                CPU_INT32U password;
                                GetData(&PassDescAdmin, &password, 0, DATA_FLAG_SYSTEM_INDEX);
                                if(data->uid[0] == password)
                                {
                                    uint32_t pay = 0, bonus = 0, best_before = 0;

                                    GetData(&AbonementMoneyDesc, &pay, app_state.current_abonement, DATA_FLAG_DIRECT_INDEX);
                                    GetData(&AbonementBonusDesc, &bonus, app_state.current_abonement, DATA_FLAG_DIRECT_INDEX);
                                    GetData(&AbonementBestBeforeDesc, &best_before, app_state.current_abonement, DATA_FLAG_DIRECT_INDEX);

                                    IncAbonentCounters(app_state.current_abonement, pay, bonus);

                                    uint32_t time_before = GetTimeSec() + best_before * 24L * 60L * 60L;

                                    data->money += pay;
                                    data->bonus = bonus;
                                    data->best_before = time_before;
                                    data->type_abonement = app_state.current_abonement;

                                    if(!write_mifare_card())
                                    {
                                        app_state.user_menu = USER_MENU_IDLE;
                                        SaveEventRecord(bonus, JOURNAL_EVENT_ABONEMENT_PAY_REJECTED, pay);
                                    }
                                    else
                                    {
                                        app_state.user_menu = USER_MENU_FINISH_PAY_BONUS_CARD;
                                        PrintFinishPayMenu();
                                        RefreshMenu();
                                        
                                        TEventRecord record;    // 18 + 4 = 22
                                        record.event = JOURNAL_EVENT_ABONEMENT_PAY_ACCEPTED;    // +1
                                        record.type_abonement = app_state.current_abonement;    // +1
                                        record.money = pay;                                     // +2
                                        record.bonus = bonus;                                   // +2
                                        record.time_before = time_before;                       // +4
                                        record.number_abonement = data->number_abonement;       // +4
                                        record.money_sum = data->money;                         // +2
                                        record.bonus_sum = data->bonus;                         // +2

                                        SaveEventAbonementRecord(&record);

                                        PlayMusicFile(52);
                                    }
                                }
                                else
                                {
                                    app_state.last_card_manipulation_time = OSTimeGet();

                                    app_state.user_menu = USER_MENU_ABONENT_WRONG;
                                    PrintWrongAbonementMenu();
                                    RefreshMenu();
                                    StopMusic();

                                    TEventRecord record;    // 18 + 4 = 22
                                    record.event = JOURNAL_EVENT_ABONEMENT_WRONG;           // +1
                                    record.type_abonement = 0;                              // +1
                                    record.money = 0;                                       // +2
                                    record.bonus = 0;                                       // +2
                                    record.password = data->uid[0];                         // +4
                                    record.number_abonement = data->number_abonement;       // +4
                                    record.money_sum = 0;                                   // +2
                                    record.bonus_sum = 0;                                   // +2

                                    SaveEventAbonementRecord(&record);
                                }
                            }

                            stop_card_working();
                        }
                        
                        if(app_state.user_menu == USER_MENU_ABONENT_PROCESSING)
                        {
                            abonement_data* data = get_abonement_data();
                            CPU_INT32U password;
                            GetData(&PassDescAdmin, &password, 0, DATA_FLAG_SYSTEM_INDEX);

                            CPU_INT32U moneytopay = app_state.moneytopay/100;
                            
                            if(read_mifare_card() != NULL
                            && data->money + data->bonus > moneytopay
                            && data->uid[0] == password)
                            {
                                TRTC_Data rtc_data_currnet, rtc_data_abonement;
                                uint32_t time_current = GetTimeSec();
                                uint32_t count_use = 0;
                                GetData(&CountUseAbonementDesc, &count_use, 0, DATA_FLAG_SYSTEM_INDEX);

                                Sec2Date(&rtc_data_currnet, time_current);
                                Sec2Date(&rtc_data_abonement, data->fileds.time_use);

                                int32_t delta = data->money - moneytopay;
                                uint16_t bonus = (delta < 0) ? -delta : 0;
                                uint16_t money = (delta < 0) ? data->money : moneytopay;

                                if(rtc_data_currnet.day == rtc_data_abonement.day
                                && rtc_data_currnet.mon == rtc_data_abonement.mon
                                && rtc_data_currnet.year == rtc_data_abonement.year
                                && data->fileds.count_use >= count_use)
                                {
                                    TEventRecord record;    // 18 + 4 = 22
                                    record.event = JOURNAL_EVENT_CARD_ABONEMENT_REAPEATE;   // +1
                                    record.type_abonement = app_state.current_abonement;    // +1
                                    record.money = 0;                                       // +2
                                    record.bonus = 0;                                       // +2
                                    record.time_before = 0;                                 // +4
                                    record.number_abonement = data->number_abonement;       // +4
                                    record.money_sum = data->money;                         // +2
                                    record.bonus_sum = data->bonus;                         // +2

                                    SaveEventAbonementRecord(&record);

                                    // сегодня оплата уже была указанное количество раз - уходим в ошибку
                                    UserPrintAbonementPaymentErrorMenu();
                                    RefreshMenu();
                                    app_state.user_menu = USER_MENU_ABONEMENT_FAIL;
                                    app_state.menu_timeout = MENU_CARD_FAIL_TIMEOUT;

                                    stop_card_working();
                                    break;
                                }
                                else
                                {
                                    data->bonus -= bonus;
                                    data->money -= money;

                                    data->fileds.time_use = time_current;
                                    data->fileds.count_use = 
                                        rtc_data_currnet.day != rtc_data_abonement.day
                                            || rtc_data_currnet.mon != rtc_data_abonement.mon
                                                || rtc_data_currnet.year != rtc_data_abonement.year ? 1 : data->fileds.count_use + 1;
                                }

                                if(!write_mifare_card())
                                {
                                    TEventRecord record;    // 18 + 4 = 22
                                    record.event = JOURNAL_EVENT_ABONEMENT_REJECTED;        // +1
                                    record.type_abonement = data->type_abonement;           // +1
                                    record.money = 0;                                       // +2
                                    record.bonus = 0;                                       // +2
                                    record.time_before = data->best_before;                 // +4
                                    record.number_abonement = data->number_abonement;       // +4
                                    record.money_sum = data->money;                         // +2
                                    record.bonus_sum = data->bonus;                         // +2

                                    SaveEventAbonementRecord(&record);

                                    UserPrintPaymentErrorMenu();
                                    RefreshMenu();
                                    app_state.user_menu = USER_MENU_CARD_FAIL;
                                    app_state.menu_timeout = MENU_CARD_FAIL_TIMEOUT;
                                }
                                else
                                {
                                    SetAcceptedMoney(app_state.moneytopay);

                                    TEventRecord record;    // 18 + 4 = 22
                                    record.event = JOURNAL_EVENT_ABONEMENT_ACCEPTED;        // +1
                                    record.type_abonement = data->type_abonement;           // +1
                                    record.money = money;                                   // +2
                                    record.bonus = bonus;                                   // +2
                                    record.time_before = data->best_before;                 // +4
                                    record.number_abonement = data->number_abonement;       // +4
                                    record.money_sum = data->money;                         // +2
                                    record.bonus_sum = data->bonus;                         // +2

                                    SaveEventAbonementRecord(&record);

                                    IncSolarAbonementCounters(app_state.ch_index, app_state.mode_index, money, bonus);

                                    app_state.user_menu = USER_MENU_CARD_OK;
                                    PostUserEvent(EVENT_FINISH_PAYMENT_ABONEMENT_SOLARIUM);
                                }
                            }
                            else if(data->uid[0] != password)
                            {
                                app_state.last_card_manipulation_time = OSTimeGet();

                                app_state.user_menu = USER_MENU_ABONENT_WRONG;
                                PrintWrongAbonementMenu();
                                RefreshMenu();
                                StopMusic();

                                TEventRecord record;    // 18 + 4 = 22
                                record.event = JOURNAL_EVENT_ABONEMENT_WRONG;           // +1
                                record.type_abonement = 0;                              // +1
                                record.money = 0;                                       // +2
                                record.bonus = 0;                                       // +2
                                record.password = data->uid[0];                         // +4
                                record.number_abonement = data->number_abonement;       // +4
                                record.money_sum = 0;                                   // +2
                                record.bonus_sum = 0;                                   // +2

                                SaveEventAbonementRecord(&record);
                            }
                            else
                            {
                                TEventRecord record;    // 18 + 4 = 22
                                record.event = JOURNAL_EVENT_ABONEMENT_REJECTED;        // +1
                                record.type_abonement = data->type_abonement;           // +1
                                record.money = 0;                                       // +2
                                record.bonus = 0;                                       // +2
                                record.time_before = data->best_before;                 // +4
                                record.number_abonement = data->number_abonement;       // +4
                                record.money_sum = data->money;                         // +2
                                record.bonus_sum = data->bonus;                         // +2

                                SaveEventAbonementRecord(&record);

                                UserPrintPaymentErrorMenu();
                                RefreshMenu();
                                app_state.user_menu = USER_MENU_CARD_FAIL;
                                app_state.menu_timeout = MENU_CARD_FAIL_TIMEOUT;                               
                            }
                            
                            stop_card_working();
                        }
                    } else {
                        if(app_state.user_menu == USER_MENU_ABONENT_PROCESSING)
                        {
                            app_state.user_menu = USER_MENU_SELECT_PAY_TYPE;
                            app_state.pay_index = 0;
                            app_state.blink_ctr = 0;
                            PrintSelectPayTypeMenu(0);
                            RefreshMenu();
                            PlayMusicFile(8);
                        }
                        else
                        {
                            app_state.user_menu = USER_MENU_IDLE;
                        }
                    }
                }
                
                // если инкассация, не работаем
                if (incassation)
                {
                    break;
                }
                
                // если есть ошибки, не работаем
                #if !APP_DEBUG
                if (TstCriticalErrors()) 
                {
                    UserPrintErrorMenu(); 
                    RefreshMenu(); 
                    // выключим прием денег
                    if (cash_accept_enabled)
                    {
                        if (IsValidatorConnected()) CC_CmdBillType(0x000000, 0x000000, ADDR_FL);
                        CoinDisable();
                        cash_accept_enabled = 0;
                    }
                    break;
                }
                #endif
                
                if (app_state.user_menu == USER_MENU_IDLE)
                {
                    app_state.skin_flags = 0;
                    PrintHelloMenu();
                }
                else if(app_state.user_menu == USER_MENU_BALANCE_CARD)
                {
                    if (OSTimeGet() - app_state.last_card_manipulation_time > MENU_CARD_MANIPULATION_TIMEOUT_MS)
                    {
                        app_state.user_menu = USER_MENU_START_INSERT_CARD_MONEY;
                        PrintMenuStartPay();
                        RefreshMenu();
                        PlayMusicFile(42);
                    }
                }
                else if(app_state.user_menu == USER_MENU_ABONENT_WRONG)
                {
                    if (OSTimeGet() - app_state.last_card_manipulation_time > MENU_CARD_WRONG_TIMEOUT_MS)
                    {
                        app_state.user_menu = USER_MENU_IDLE;
                        PrintHelloMenu();
                        RefreshMenu();
                    }
                }
                else if(app_state.user_menu == USER_MENU_ABONENT_PROCESSING)
                {
                    if (OSTimeGet() - app_state.last_card_manipulation_time > MENU_WAIT_CARD_ABONEMENT_TIMEOUT_MS)
                    {
                        app_state.user_menu = USER_MENU_SELECT_PAY_TYPE;
                        app_state.pay_index = 0;
                        app_state.blink_ctr = 0;
                        PrintSelectPayTypeMenu(0);
                        RefreshMenu();
                        PlayMusicFile(8);
                    }
                }
                else if(app_state.user_menu == USER_MENU_ALL_PRICE)
                {
                    //PrintMenuAllPrice(app_state.blink_ctr >= 500);
                }
                else if (app_state.user_menu == USER_MENU_WARNING_1)
                {
                    app_state.skin_flags = 0;
                    PrintWarning1Menu();
                }
                else if (app_state.user_menu == USER_MENU_WARNING_2)
                {
                    app_state.skin_flags = 0;
                    PrintWarning2Menu();
                }
                else if ((app_state.user_menu == USER_MENU_SELECT_CH) 
                         || (app_state.user_menu == USER_MENU_SELECT_MODE) 
                         || (app_state.user_menu == USER_MENU_ACK_MODE) 
                         || (app_state.user_menu == USER_MENU_SELECT_PAY_TYPE) 
                         || (app_state.user_menu == USER_MENU_CARD_PAYING) 
                         || (app_state.user_menu == USER_MENU_SELECT_CH_CLEANING) 
                         || (app_state.user_menu == USER_MENU_SELECT_CH_SERVICE) 
                         || (app_state.user_menu == USER_MENU_SELECT_CH_TESTMODE)
                         || (app_state.user_menu == USER_MENU_START_INSERT_CARD_MONEY)
                         )
                {
                    if (OSTimeGet() - app_state.last_key_time > MENU_KEY_PRESS_TIMEOUT_MS)
                    {
                        app_state.user_menu = USER_MENU_IDLE;
                        app_state.ch_index = 0;
                        app_state.mode_index = 0;
                        app_state.pay_index = 0;
                        app_state.current_abonement = 0;
                        PrintHelloMenu();
                        RefreshMenu();
                    }
                }
                else if (app_state.user_menu == USER_MENU_CASH_PAYING)
                { 
                    // принимаем наличные
                    //CheckFiscalStatus();
                    // включим заново прием денег, если была ошибка в этом же меню
                    if (!cash_accept_enabled)
                    {
                        if (IsValidatorConnected()) CC_CmdBillType(0xffffff, 0xffffff, ADDR_FL);
                        CoinEnable();
                        cash_accept_enabled = 1;
                    }
                    if (OSTimeGet() - app_state.last_key_time > MENU_KEY_PRESS_TIMEOUT_MS)
                    {
                        if (IsValidatorConnected()) CC_CmdBillType(0x000000, 0x000000, ADDR_FL);
                        CoinDisable();
                        cash_accept_enabled = 0;
                        app_state.user_menu = USER_MENU_IDLE;
                        app_state.solar_srv[app_state.ch_index] = 0;
                        app_state.ch_index = 0;
                        app_state.mode_index = 0;
                        app_state.pay_index = 0;
                        PrintHelloMenu();
                        RefreshMenu();
                    }
                }
                else if (app_state.user_menu == USER_MENU_CARD_PROCESSING)  // если в меню приема банковской карты
                {
                    //CheckFiscalStatus();
                    if (GetTermState() == TERM_STATE_DONE_PUR)
                    {
                        /// печать чека терминала
                        SetTermCommand(TERM_COMMAND_CLEAR_STATE, NULL);
                        SetAcceptedMoney(app_state.moneytopay);
                        SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_CARD_ACCEPTED, app_state.moneytopay);
                        if (term_protocol() == TERMINAL_PROTOCOL_TTK2) PrintCardBill();
                        app_state.user_menu = USER_MENU_CARD_OK;
                        PostUserEvent(EVENT_FINISH_PAYMENT);
                    }
                    else if (GetTermState() == TERM_STATE_ERR_PUR)
                    {
                        SetTermCommand(TERM_COMMAND_CLEAR_STATE, NULL);
                        SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_CARD_REJECTED, 0);
                        UserPrintPaymentErrorMenu();
                        RefreshMenu();
                        app_state.user_menu = USER_MENU_CARD_FAIL;
                        app_state.menu_timeout = MENU_CARD_FAIL_TIMEOUT;
                    }
                    else
                    {
                        PrintTerminalRequestMenu();
                        RefreshMenu();
                    }
                }
                else if (app_state.user_menu == USER_MENU_INSERT_BANK_CARD)  // если в меню приема банковской карты для абонемента
                {
                    //CheckFiscalStatus();
                    if (GetTermState() == TERM_STATE_DONE_PUR)
                    {
                        /// печать чека терминала
                        SetTermCommand(TERM_COMMAND_CLEAR_STATE, NULL);

                        TEventRecord record;    // 18 + 4 = 22
                        record.event = JOURNAL_EVENT_CARD_ABONEMENT_ACCEPTED;   // +1
                        record.type_abonement = app_state.current_abonement;    // +1
                        record.money_bank = app_state.abonementtopay;           // +2
                        record.bonus = 0;                                       // +2
                        record.number_abonement = 0;                            // +4
                        record.money_sum = 0;                                   // +2
                        record.bonus_sum = 0;                                   // +2

                        SaveEventAbonementRecord(&record);

                        if (term_protocol() == TERMINAL_PROTOCOL_TTK2) PrintCardBill();
                        app_state.user_menu = USER_MENU_INSERT_BONUS_CARD;
                        PostUserEvent(EVENT_FINISH_PAYMENT_ABONEMENT);
                    }
                    else if (GetTermState() == TERM_STATE_ERR_PUR)
                    {
                        SetTermCommand(TERM_COMMAND_CLEAR_STATE, NULL);
                        SaveEventRecord(app_state.current_abonement, JOURNAL_EVENT_CARD_REJECTED, 0);
                        PrintAnotherCardMenu();
                        RefreshMenu();
                        PlayMusicFile(51);
                        app_state.user_menu = USER_MENU_ERROR_BANK_CARD;
                        app_state.menu_timeout = MENU_CARD_ABONEMENT_FAIL_TIMEOUT;
                    }
                    else
                    {
                        PrintInsertBankCardMenu();
                        RefreshMenu();

                        // temporally
                        //SetAcceptedMoney(app_state.abonementtopay);
                        //SaveEventRecord(app_state.current_abonement, JOURNAL_EVENT_CARD_ABONEMENT_ACCEPTED, app_state.abonementtopay);
                        //app_state.user_menu = USER_MENU_INSERT_BONUS_CARD;
                        //PostUserEvent(EVENT_FINISH_PAYMENT_ABONEMENT);
                    }
                }
                else if (app_state.user_menu == USER_MENU_SHOW_THANKS)
                {
                    if (!app_state.menu_timeout)
                    {
                        if (!IsPlaying())
                        {
                            app_state.user_menu = USER_MENU_IDLE;
                            app_state.ch_index = 0;
                            app_state.mode_index = 0;
                            app_state.pay_index = 0;
                            PrintHelloMenu();
                            RefreshMenu();
                        }
                    }
                    else
                    {
                        PrintThanksMenu();
                        app_state.menu_timeout--;
                    }
                }
                else if ((app_state.user_menu == USER_MENU_SKIN_ATTENTION_1) 
                         || (app_state.user_menu == USER_MENU_SKIN_ATTENTION_2) 
                           || (app_state.user_menu == USER_MENU_SKIN_ATTENTION_3) 
                             || (app_state.user_menu == USER_MENU_SKIN_ATTENTION_4))
                {
                    if (!app_state.menu_timeout)
                    {
                        if (!IsPlaying())
                        {
                            if (app_state.user_menu_prev == USER_MENU_CARD_PAYING)
                            {
                                app_state.user_menu = USER_MENU_CARD_PAYING;
                                app_state.blink_ctr = 0;
                                PrintCardPayingMenu(0);
                                RefreshMenu();
                            }
                            else if (app_state.user_menu_prev == USER_MENU_CASH_PAYING)
                            {
                                app_state.user_menu = USER_MENU_CASH_PAYING;
                                app_state.blink_ctr = 0;
                                PrintCashPayingMenu(0);
                                RefreshMenu();
                            }
                            else
                            {
                                app_state.user_menu = USER_MENU_IDLE;
                                app_state.solar_srv[app_state.ch_index] = 0;
                                app_state.ch_index = 0;
                                app_state.mode_index = 0;
                                app_state.pay_index = 0;
                                PrintHelloMenu();
                                RefreshMenu();
                            }
                        }
                    }
                    else
                    {
                        PrintSkinTypeAttentionMenu(app_state.user_menu - USER_MENU_SKIN_ATTENTION_1);
                        app_state.menu_timeout--;
                    }
                }
                else if (app_state.user_menu == USER_MENU_CARD_FAIL)
                {
                    if (!app_state.menu_timeout)
                    {
                        PostUserEvent(EVENT_KEY_CANSEL);
                    }
                    else
                    {
                        UserPrintPaymentErrorMenu();
                        app_state.menu_timeout--;
                    }
                }
                else if (app_state.user_menu == USER_MENU_ABONEMENT_FAIL)
                {
                    if (!app_state.menu_timeout)
                    {
                        PostUserEvent(EVENT_KEY_CANSEL);
                    }
                    else
                    {
                        UserPrintAbonementPaymentErrorMenu();
                        app_state.menu_timeout--;
                    }
                }
                else if (app_state.user_menu == USER_MENU_ERROR_BANK_CARD)
                {
                    if (!app_state.menu_timeout)
                    {
                        PostUserEvent(EVENT_KEY_CANSEL);
                    }
                    else
                    {
                        PrintAnotherCardMenu();
                        app_state.menu_timeout--;
                    }
                }
            }
            break;
        case EVENT_KEY_START:
            app_state.last_key_time = OSTimeGet();
            if (GetMode() != MODE_WORK)
            {
                if (!FlagForPrintReport) break;
                if (GetCurrentMenu() == xReportMenuPanel)
                { 
                    // печатаем X-отчет
                    if (IsFiscalConnected())
                    {
                        CPU_INT08U err;
                        FPend();
                        FiscPrintDayReportNoClear(30, &err);
                        FPost();
                        if (err) {SetFiscalErrorByCode(err);}
                        SaveEventRecord(0, JOURNAL_EVENT_PRINT_X, GetTimeSec());
                        GoToPreviousMenu();
                    }
                }
                else if (GetCurrentMenu() == zReportMenuPanel)
                {
                    // печатаем Z-отчет
                    if (IsFiscalConnected()) 
                    {
                        CPU_INT08U err;
                        FPend();
                        FiscPrintDayReportClear(30, &err);
                        FPost();
                        if (err) {SetFiscalErrorByCode(err);}
                        SaveEventRecord(0, JOURNAL_EVENT_PRINT_Z, GetTimeSec());
                        GoToPreviousMenu();
                        ClrFiscalErrorByCode(FR_ERROR_CODE_4E);
                    }
                }
                else if (GetCurrentMenu() == bufReportMenuPanel)
                {
                    // печатаем Z-отчеты из буфера
                    if (IsFiscalConnected()) 
                    {
                        CPU_INT08U err;
                        FPend();
                        FiscPrintDayReportsFromBuf(30, &err);
                        FPost();
                        if (err) {SetFiscalErrorByCode(err);}
                        SaveEventRecord(0, JOURNAL_EVENT_PRINT_BUF, GetTimeSec());
                        GoToPreviousMenu();
                    }
                }
                break;
            }
            
            if (!AppCanStart() && !((app_state.user_menu == USER_MENU_SELECT_CH_CLEANING)
                                     || (app_state.user_menu == USER_MENU_SELECT_CH_SERVICE)
                                     || (app_state.user_menu == USER_MENU_SELECT_CH_TESTMODE)))
            {
                break;
            }
            
            if (app_state.user_menu == USER_MENU_IDLE)
            {
                app_state.user_menu = USER_MENU_WARNING_1;
                app_state.skin_flags = 0;
                PrintWarning1Menu();
                RefreshMenu();
                PlayMusicFile(2);
            }
            else if(app_state.user_menu == USER_MENU_FINISH_PAY_BONUS_CARD)
            {
                app_state.user_menu = USER_MENU_IDLE;
                PrintHelloMenu();
                RefreshMenu();
                StopMusic();
            }
            else if(app_state.user_menu == USER_MENU_BALANCE_CARD)
            {
                // предложим пополнить карту
                app_state.user_menu = USER_MENU_START_INSERT_CARD_MONEY;

                PrintMenuStartPay();
                RefreshMenu();
                PlayMusicFile(42);
            }
            else if(app_state.user_menu == USER_MENU_START_INSERT_CARD_MONEY)
            {
                // покажем полный прайс
                app_state.user_menu = USER_MENU_ALL_PRICE;

                PrintMenuAllPrice(app_state.blink_ctr >= 500);
                RefreshMenu();
                PlayMusicFile(43);
            }
            else if(app_state.user_menu == USER_MENU_ALL_PRICE)
            {
                app_state.user_menu = USER_MENU_SILVER_BONUS + app_state.current_abonement;

                // получим сумму оплаты
                GetData(&AbonementMoneyDesc, &app_state.abonementtopay, app_state.current_abonement, DATA_FLAG_DIRECT_INDEX);

                // выбрали абонемент
                if(app_state.current_abonement == SILVER_ABONEMENT) {
                    PrintSilverMenu();
                } else if(app_state.current_abonement == GOLD_ABONEMENT) {
                    PrintGoldMenu();
                } else if(app_state.current_abonement == PLATINUM_ABONEMENT) {
                    PrintPlatMenu();
                } else if(app_state.current_abonement == DIAMOND_ABONEMENT) {
                    PrintDiamondMenu();
                }

                RefreshMenu();
                PlayMusicFile(44 + app_state.current_abonement);
            }
            else if(app_state.user_menu == USER_MENU_SILVER_BONUS
                    || app_state.user_menu == USER_MENU_GOLD_BONUS
                    || app_state.user_menu == USER_MENU_PLATINUM_BONUS
                    || app_state.user_menu == USER_MENU_BRILLANCE_BONUS
            )
            {
                app_state.user_menu = USER_MENU_START_PAY_CARD;

                PrintStartPayCardMenu();
                RefreshMenu();
                PlayMusicFile(48);
            }
            else if(app_state.user_menu == USER_MENU_START_PAY_CARD)
            {
                uint32_t pay = 0;
                GetData(&AbonementMoneyDesc, &pay, app_state.current_abonement, DATA_FLAG_DIRECT_INDEX);
                app_state.abonementtopay = pay * 100;   // сумма в копейках

                uint32_t param[TERM_PARAM_COUNT];
                param[0] = app_state.abonementtopay;
                SetTermCommand(TERM_COMMAND_PEND_PUR, param);
                app_state.user_menu = USER_MENU_INSERT_BANK_CARD;
                PrintInsertBankCardMenu();
                RefreshMenu();
                StopMusic();
                PlayMusicFile(49);
            }
            else if (app_state.user_menu == USER_MENU_WARNING_1)
            {
                app_state.user_menu = USER_MENU_WARNING_2;
                app_state.skin_flags = 0;
                PrintWarning2Menu();
                RefreshMenu();
                PlayMusicFile(20);
            }
            else if (app_state.user_menu == USER_MENU_WARNING_2)
            {
                if (!IsPlaying())
                {
                    app_state.user_menu = USER_MENU_SELECT_CH;
                    app_state.ch_index = 0;
                    for (int i = 0; i < CHANNELS_NUM; i++)
                    {
                        if (SolariumEnabled(i) && (app_state.solar_state[i] == SOLAR_STATE_FREE))
                        {
                            app_state.ch_index = i;
                            break;
                        }
                    }                   
                    app_state.blink_ctr = 0;
                    app_state.skin_flags = 0;
                    PrintSelectChMenu(0);
                    RefreshMenu();
                    PlayMusicFile(3);
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_CH)
            {
                if (SolariumEnabled(app_state.ch_index) && (app_state.solar_state[app_state.ch_index] == SOLAR_STATE_FREE))
                {
                    app_state.user_menu = USER_MENU_SELECT_MODE;
                    app_state.blink_ctr = 0;
                    app_state.mode_index = 0;
                    PrintSelectModeMenu(0);
                    RefreshMenu();
                    PlayMusicFile(4);
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_CH_CLEANING)
            {
                if (SolariumEnabled(app_state.ch_index))
                {
                    if (app_state.solar_state[app_state.ch_index] == SOLAR_STATE_FREE)
                    {
                        app_state.solar_state[app_state.ch_index] = SOLAR_STATE_CLEANING;
                        PostUserEvent(EVENT_OPEN_RELAY1 + app_state.ch_index);
                        app_state.user_menu = USER_MENU_SELECT_CH;
                        SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_SOLARIUM_CLEANING_START, GetTimeSec());
                        app_state.time_cleaning_start[app_state.ch_index] = GetTimeSec();
                    }
                    else if (app_state.solar_state[app_state.ch_index] == SOLAR_STATE_CLEANING)
                    {
                        app_state.solar_state[app_state.ch_index] = SOLAR_STATE_FREE;
                        PostUserEvent(EVENT_CLOSE_RELAY1 + app_state.ch_index);
                        app_state.solar_srv[app_state.ch_index] = 0;
                        app_state.user_menu = USER_MENU_IDLE;
                        CPU_INT32U cleaning_time = GetTimeSec() - app_state.time_cleaning_start[app_state.ch_index];
                        SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_SOLARIUM_CLEANING_END, cleaning_time);
                        IncSolarCleaningCounters(app_state.ch_index, cleaning_time);
                        PrintHelloMenu();
                        RefreshMenu();
                    }
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_CH_SERVICE)
            {
                if ((SolariumEnabled(app_state.ch_index)) && (app_state.solar_state[app_state.ch_index] == SOLAR_STATE_FREE))
                {
                    app_state.user_menu = USER_MENU_SELECT_MODE;
                    app_state.blink_ctr = 0;
                    app_state.mode_index = 0;
                    app_state.solar_srv[app_state.ch_index] = SOLAR_IN_SERVICE;
                    PrintSelectModeMenu(0);
                    RefreshMenu();
                    PlayMusicFile(4);
                    //SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_SOLARIUM_SERVICE_START, GetTimeSec());
                    //app_state.time_cleaning_start[app_state.ch_index] = GetTimeSec();
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_CH_TESTMODE)
            {
                if ((SolariumEnabled(app_state.ch_index)) && (app_state.solar_state[app_state.ch_index] == SOLAR_STATE_FREE))
                {
                    app_state.user_menu = USER_MENU_SELECT_MODE;
                    app_state.blink_ctr = 0;
                    app_state.mode_index = 0;
                    app_state.solar_srv[app_state.ch_index] = SOLAR_IN_TEST;
                    PrintSelectModeMenu(0);
                    RefreshMenu();
                    PlayMusicFile(4);
                    //SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_SOLARIUM_SERVICE_START, GetTimeSec());
                    //app_state.time_cleaning_start[app_state.ch_index] = GetTimeSec();
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_MODE)
            {
                if ((app_state.solar_srv[app_state.ch_index] == SOLAR_IN_SERVICE) || (app_state.solar_srv[app_state.ch_index] == SOLAR_IN_TEST))
                {
                    app_state.user_menu = USER_MENU_SELECT_SERVICE_TIME;
                    app_state.timetopay = 0;
                    app_state.blink_ctr = 0;
                    PrintServiceTimeSelectMenu(0);
                    RefreshMenu();
                }
                else
                {
                    app_state.user_menu = USER_MENU_ACK_MODE;
                    PrintAckModeMenu();
                    RefreshMenu();
                    PlayMusicFile(5 + app_state.mode_index);
                }
            }
            else if (app_state.user_menu == USER_MENU_ACK_MODE)
            {
                if (PayTypeTermEnabled() && PayTypeCashEnabled())
                {
                    app_state.user_menu = USER_MENU_SELECT_PAY_TYPE;
                    app_state.pay_index = 0;
                    app_state.blink_ctr = 0;
                    PrintSelectPayTypeMenu(0);
                    RefreshMenu();
                    PlayMusicFile(8);
                }
                #if APP_DEBUG
                else if (1)
                #else
                else if (PayTypeCashEnabled())
                #endif
                {
                    app_state.user_menu = USER_MENU_CASH_PAYING;
                    app_state.pay_index = PAY_TYPE_CASH;
                    app_state.blink_ctr = 0;
                    PrintCashPayingMenu(0);
                    RefreshMenu();
                    PlayMusicFile(9 + app_state.mode_index);
                }
                else if (PayTypeTermEnabled())
                {
                    GetData(&SolarMinimumTimeMinutesDesc, &app_state.timetopay, app_state.ch_index, DATA_FLAG_DIRECT_INDEX);
                    app_state.timetopay *= 60;
                    app_state.user_menu = USER_MENU_CARD_PAYING;
                    app_state.pay_index = PAY_TYPE_CARD;
                    app_state.blink_ctr = 0;
                    PrintCardPayingMenu(0);
                    RefreshMenu();
                    PlayMusicFile(12 + app_state.mode_index);
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_PAY_TYPE)
            {
                if (app_state.pay_index == PAY_TYPE_CASH)
                {
                    app_state.user_menu = USER_MENU_CASH_PAYING;
                    app_state.blink_ctr = 0;
                    PrintCashPayingMenu(0);
                    RefreshMenu();
                    PlayMusicFile(9 + app_state.mode_index);
                }
                else if (app_state.pay_index == PAY_TYPE_CARD_ABONEMENT)
                {
                    GetData(&SolarMinimumTimeMinutesDesc, &app_state.timetopay, app_state.ch_index, DATA_FLAG_DIRECT_INDEX);
                    app_state.timetopay *= 60;
                    app_state.user_menu = USER_MENU_CARD_PAYING;
                    app_state.blink_ctr = 0;
                    PrintCardPayingMenu(0);
                    RefreshMenu();
                    PlayMusicFile(12 + app_state.mode_index);
                }
                else if (app_state.pay_index == PAY_TYPE_CARD)
                {
                    GetData(&SolarMinimumTimeMinutesDesc, &app_state.timetopay, app_state.ch_index, DATA_FLAG_DIRECT_INDEX);
                    app_state.timetopay *= 60;
                    app_state.user_menu = USER_MENU_CARD_PAYING;
                    app_state.blink_ctr = 0;
                    PrintCardPayingMenu(0);
                    RefreshMenu();
                    PlayMusicFile(12 + app_state.mode_index);
                }
            }
            else if (app_state.user_menu == USER_MENU_CASH_PAYING)
            {
                PostUserEvent(EVENT_FINISH_PAYMENT);
            }
            else if (app_state.user_menu == USER_MENU_CARD_PAYING)
            {
                if(app_state.pay_index == PAY_TYPE_CARD)
                {
                    uint32_t param[TERM_PARAM_COUNT];
                    param[0] = app_state.moneytopay;
                    SetTermCommand(TERM_COMMAND_PEND_PUR, param);
                    app_state.user_menu = USER_MENU_CARD_PROCESSING;
                    PrintTerminalRequestMenu();
                    RefreshMenu();
                }
                else if(app_state.pay_index == PAY_TYPE_CARD_ABONEMENT)
                {
                    app_state.user_menu = USER_MENU_ABONENT_PROCESSING;
                    app_state.last_card_manipulation_time = OSTimeGet();

                    PrintInsertBonusCardMenu();
                    RefreshMenu();
                    PlayMusicFile(50);
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_SERVICE_TIME)
            {
                // запускаем таймаут до старта солярия
                app_state.solar_state[app_state.ch_index] = SOLAR_STATE_TIMEOUT_PRE;
                if (app_state.solar_srv[app_state.ch_index] == SOLAR_IN_SERVICE)
                {
                    app_state.timetoend[app_state.ch_index] = 2 * 60;
                }
                else
                {
                    GetData(&SolarTimeoutBeforeMinutesDesc, &app_state.timetoend[app_state.ch_index], app_state.ch_index, DATA_FLAG_DIRECT_INDEX);
                    app_state.timetoend[app_state.ch_index] *= 60;
                }
                app_state.sunburn_mode[app_state.ch_index] = app_state.mode_index;
                SetControl(app_state.ch_index, CONTROL_STATE_OFF);
                // сохраняем запись события
                if (app_state.solar_srv[app_state.ch_index] == SOLAR_IN_SERVICE)
                {
                    SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_SOLARIUM_SERVICE_START, app_state.timetopay);
                }
                else if (app_state.solar_srv[app_state.ch_index] == SOLAR_IN_TEST)
                {
                    SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_SOLARIUM_TESTMODE_START, app_state.timetopay);
                    IncSolarTestCounters(app_state.ch_index, app_state.mode_index, app_state.timetopay);
                }
                SaveTimeMoneyForChannel(app_state.ch_index, app_state.timetopay, 0);
                // откроем дверь
                PostUserEvent(EVENT_OPEN_RELAY1 + app_state.ch_index);
                PlayMusicFile(19);
                app_state.user_menu = USER_MENU_SHOW_THANKS;
                if (MusicEnabled()) app_state.menu_timeout = 0;
                else app_state.menu_timeout = MENU_THANKS_TIMEOUT;
                PrintThanksMenu();
                RefreshMenu();
            }
            break;
        case EVENT_PASS_OK:
            if (GetCurrentMenu() == ReqCleaningPassMenuPanel)
            {
                app_state.user_menu = USER_MENU_SELECT_CH_CLEANING;
                app_state.blink_ctr = 0;
                GoToPreviousMenu();
                PrintSelectChMenu(0);
                RefreshMenu();
            }
            else if (GetCurrentMenu() == ReqServicePassMenuPanel)
            {
                app_state.user_menu = USER_MENU_SELECT_CH_SERVICE;
                app_state.blink_ctr = 0;
                GoToPreviousMenu();
                PrintSelectChMenu(0);
                RefreshMenu();
            }
            else if (GetCurrentMenu() == ReqTestPassMenuPanel)
            {
                app_state.user_menu = USER_MENU_SELECT_CH_TESTMODE;
                app_state.blink_ctr = 0;
                GoToPreviousMenu();
                PrintSelectChMenu(0);
                RefreshMenu();
            }
            break;
        case EVENT_PASS_FAIL:
            if ((GetCurrentMenu() == ReqCleaningPassMenuPanel) || (GetCurrentMenu() == ReqServicePassMenuPanel) || (GetCurrentMenu() == ReqTestPassMenuPanel))
            {
                app_state.user_menu = USER_MENU_IDLE;
                PrintHelloMenu();
                GoToPreviousMenu();
            }            
            break;
        case EVENT_FINISH_PAYMENT_ABONEMENT:
            {
                if (app_state.user_menu != USER_MENU_INSERT_BONUS_CARD)
                {
                    break;
                }

                // пополнение карты закончили - сообщим об этом
                PrintInsertBonusCardMenu();
                RefreshMenu();
                PlayMusicFile(50);
            }
        break;
        case EVENT_FINISH_PAYMENT_ABONEMENT_SOLARIUM:
            {
                CPU_INT32U price, accmoney;
                CPU_INT32U min_time;
                
                if (app_state.user_menu != USER_MENU_CARD_OK)
                {
                    break;
                }
                    
                accmoney = GetAcceptedMoney();
                price = GetPricePerMin(app_state.ch_index, app_state.mode_index);
                GetData(&SolarMinimumTimeMinutesDesc, &min_time, app_state.ch_index, DATA_FLAG_DIRECT_INDEX);
                if ((accmoney * 60) / price < (min_time * 60))
                {
                    break;
                }
                
                ChannelsPayedTime[app_state.ch_index] = (accmoney * 60) / price;

                IncCounter(app_state.ch_index, ChannelsPayedTime[app_state.ch_index], accmoney, 2);
                IncSolarCounters(app_state.ch_index, app_state.mode_index, ChannelsPayedTime[app_state.ch_index], accmoney, 2, 0);
                SetAcceptedMoney(0);

                // сохраним оплаченное время и деньги
                SaveTimeMoneyForChannel(app_state.ch_index, ChannelsPayedTime[app_state.ch_index], accmoney);
                                    
                // запускаем таймаут до старта солярия
                app_state.solar_state[app_state.ch_index] = SOLAR_STATE_TIMEOUT_PRE;
                GetData(&SolarTimeoutBeforeMinutesDesc, &app_state.timetoend[app_state.ch_index], app_state.ch_index, DATA_FLAG_DIRECT_INDEX);
                app_state.timetoend[app_state.ch_index] *= 60;
                app_state.sunburn_mode[app_state.ch_index] = app_state.mode_index;
                SetControl(app_state.ch_index, CONTROL_STATE_OFF);
                    
                // сохраняем запись события
                SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_START_SESSION, ChannelsPayedTime[app_state.ch_index]);

                // откроем дверь
                PostUserEvent(EVENT_OPEN_RELAY1 + app_state.ch_index);
                
                PlayMusicFile(19);

                app_state.user_menu = USER_MENU_SHOW_THANKS;
                if (MusicEnabled()) app_state.menu_timeout = 0;
                else app_state.menu_timeout = MENU_THANKS_TIMEOUT;
                PrintThanksMenu();
                RefreshMenu();
            }
        break;
        case EVENT_FINISH_PAYMENT:
            {
                CPU_INT32U price, accmoney;
                CPU_INT32U min_time;
                
                if ((app_state.user_menu != USER_MENU_CARD_OK) && (app_state.user_menu != USER_MENU_CASH_PAYING))
                {
                    break;
                }
                    
                accmoney = GetAcceptedMoney();
                price = GetPricePerMin(app_state.ch_index, app_state.mode_index);
                GetData(&SolarMinimumTimeMinutesDesc, &min_time, app_state.ch_index, DATA_FLAG_DIRECT_INDEX);
                if ((accmoney * 60) / price < (min_time * 60))
                {
                    break;
                }
                
                ChannelsPayedTime[app_state.ch_index] = (accmoney * 60) / price;

                // выключим купюроприемник
                if (app_state.user_menu == USER_MENU_CASH_PAYING)
                {
                    if (IsValidatorConnected()) CC_CmdBillType(0x000000, 0x000000, ADDR_FL);
                    CoinDisable();
                    cash_accept_enabled = 0;
                }

                // напечатаем чек
                /*if (IsFiscalConnected())
                {
                    CPU_INT32U format;
                    char service_name[48];
                    GetData(&BillFormatDesc, &format, 0, DATA_FLAG_SYSTEM_INDEX);
                    GetDataStr(&ServiceNameDesc, (CPU_INT08U*)service_name, 0, DATA_FLAG_SYSTEM_INDEX);
                    sprintf(&service_name[strlen(service_name)], ". Солярий %d", app_state.ch_index + 1);
                    if (format == 0)
                    {
                        strcat(service_name, ", мин.");
                    }
      
                    if (PrintFiscalBill(accmoney, ChannelsPayedTime[app_state.ch_index], app_state.user_menu == USER_MENU_CARD_OK, service_name, price) == 0)
                    {
                        SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_PRINT_BILL, GetTimeSec());
                    }
                    else
                    {
                        // ошибка печати чека
                    
                    }
                }*/

                IncCounter(app_state.ch_index, ChannelsPayedTime[app_state.ch_index], accmoney, app_state.user_menu == USER_MENU_CARD_OK);
                IncSolarCounters(app_state.ch_index, app_state.mode_index, ChannelsPayedTime[app_state.ch_index], accmoney, app_state.user_menu == USER_MENU_CARD_OK, 0);
                SetAcceptedMoney(0);

                // сохраним оплаченное время и деньги
                SaveTimeMoneyForChannel(app_state.ch_index, ChannelsPayedTime[app_state.ch_index], accmoney);
                                    
                // запускаем таймаут до старта солярия
                app_state.solar_state[app_state.ch_index] = SOLAR_STATE_TIMEOUT_PRE;
                GetData(&SolarTimeoutBeforeMinutesDesc, &app_state.timetoend[app_state.ch_index], app_state.ch_index, DATA_FLAG_DIRECT_INDEX);
                app_state.timetoend[app_state.ch_index] *= 60;
                app_state.sunburn_mode[app_state.ch_index] = app_state.mode_index;
                SetControl(app_state.ch_index, CONTROL_STATE_OFF);
                    
                // сохраняем запись события
                SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_START_SESSION, ChannelsPayedTime[app_state.ch_index]);

                // откроем дверь
                PostUserEvent(EVENT_OPEN_RELAY1 + app_state.ch_index);
                
                PlayMusicFile(19);

                app_state.user_menu = USER_MENU_SHOW_THANKS;
                if (MusicEnabled()) app_state.menu_timeout = 0;
                else app_state.menu_timeout = MENU_THANKS_TIMEOUT;
                PrintThanksMenu();
                RefreshMenu();
            }
            break;
        case EVENT_KEY_DOWN:
            app_state.last_key_time = OSTimeGet();
            if ((app_state.user_menu == USER_MENU_SELECT_CH) || (app_state.user_menu == USER_MENU_SELECT_CH_CLEANING) || (app_state.user_menu == USER_MENU_SELECT_CH_SERVICE) || (app_state.user_menu == USER_MENU_SELECT_CH_TESTMODE))
            {
                if (AppCanStart())
                {
                    app_state.ch_index = (app_state.ch_index + 1) % CHANNELS_NUM;
                    PrintSelectChMenu(app_state.blink_ctr >= 500);
                    RefreshMenu();
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_MODE)
            {
                if (AppCanStart())
                {
                    app_state.mode_index = (app_state.mode_index + 1) % (SUNBURN_MODE_MAX + 1);
                    PrintSelectModeMenu(app_state.blink_ctr >= 500);
                    RefreshMenu();
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_PAY_TYPE)
            {
                if (AppCanStart())
                {
                    app_state.pay_index = (app_state.pay_index + 1) & 0x01;
                    PrintSelectPayTypeMenu(app_state.blink_ctr >= 500);
                    RefreshMenu();
                }
            }
            else if (app_state.user_menu == USER_MENU_ALL_PRICE)
            {
                if (AppCanStart())
                {
                    app_state.current_abonement = (app_state.current_abonement + 1) & 0x03;
                    PrintMenuAllPrice(app_state.blink_ctr >= 500);
                    RefreshMenu();
                }
            }
            else if (app_state.user_menu == USER_MENU_CARD_PAYING)
            {
                if (AppCanStart())
                {
                    CPU_INT32U min_time;
                    GetData(&SolarMinimumTimeMinutesDesc, &min_time, app_state.ch_index, DATA_FLAG_DIRECT_INDEX);
                    min_time *= 60;
                    if ((app_state.timetopay > min_time) && (app_state.timetopay > 30)) app_state.timetopay -= 30;
                    PrintCardPayingMenu(app_state.blink_ctr >= 500);
                    RefreshMenu();
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_SERVICE_TIME)
            {
                if (AppCanStart())
                {
                    if (app_state.timetopay >= 30) app_state.timetopay -= 30;
                    PrintServiceTimeSelectMenu(app_state.blink_ctr >= 500);
                    RefreshMenu();
                }
            }
            break;
        case EVENT_KEY_UP:
            app_state.last_key_time = OSTimeGet();
            if ((app_state.user_menu == USER_MENU_SELECT_CH) || (app_state.user_menu == USER_MENU_SELECT_CH_CLEANING) || (app_state.user_menu == USER_MENU_SELECT_CH_SERVICE) || (app_state.user_menu == USER_MENU_SELECT_CH_TESTMODE))
            {
                if (AppCanStart())
                {
                    app_state.ch_index = (app_state.ch_index > 0) ? (app_state.ch_index - 1) : (CHANNELS_NUM - 1);
                    PrintSelectChMenu(app_state.blink_ctr >= 500);
                    RefreshMenu();
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_MODE)
            {
                if (AppCanStart())
                {
                    app_state.mode_index = (app_state.mode_index > SUNBURN_MODE_COLLATEN) ? (app_state.mode_index - 1) : SUNBURN_MODE_MAX;
                    PrintSelectModeMenu(app_state.blink_ctr >= 500);
                    RefreshMenu();
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_PAY_TYPE)
            {
                if (AppCanStart())
                {
                    app_state.pay_index = (app_state.pay_index + 1) & 0x01;
                    PrintSelectPayTypeMenu(app_state.blink_ctr >= 500);
                    RefreshMenu();
                }
            }
            else if (app_state.user_menu == USER_MENU_ALL_PRICE)
            {
                if (AppCanStart())
                {
                    app_state.current_abonement = (app_state.current_abonement + 1) & 0x03;
                    PrintMenuAllPrice(app_state.blink_ctr >= 500);
                    RefreshMenu();
                }
            }
            else if (app_state.user_menu == USER_MENU_CARD_PAYING)
            {
                if (AppCanStart())
                {
                    CPU_INT32U max_time;
                    CPU_INT08U skin_att;
                    GetData(&SolarMaximumTimeMinutesDesc, &max_time, app_state.ch_index * SOLAR_MODES_COUNT + app_state.mode_index, DATA_FLAG_DIRECT_INDEX);
                    max_time *= 60;
                    if (app_state.timetopay < max_time) app_state.timetopay += 30;
                    skin_att = CheckSkinTypeAttention(app_state.timetopay);
                    if (skin_att > 0)
                    {
                        app_state.user_menu_prev = app_state.user_menu;
                        app_state.user_menu = skin_att - 1 + USER_MENU_SKIN_ATTENTION_1;
                        if (MusicEnabled()) app_state.menu_timeout = 0;
                        else app_state.menu_timeout = MENU_ATTENTION_TIMEOUT;
                        PrintSkinTypeAttentionMenu(app_state.user_menu - USER_MENU_SKIN_ATTENTION_1);
                        RefreshMenu();
                        PlayMusicFile(15 + app_state.user_menu - USER_MENU_SKIN_ATTENTION_1);
                    }
                    else
                    {
                        PrintCardPayingMenu(app_state.blink_ctr >= 500);
                        RefreshMenu();
                    }
                }
            }
            else if (app_state.user_menu == USER_MENU_SELECT_SERVICE_TIME)
            {
                if (AppCanStart())
                {
                    CPU_INT32U max_time;
                    GetData(&SolarMaximumTimeMinutesDesc, &max_time, app_state.ch_index * SOLAR_MODES_COUNT + app_state.mode_index, DATA_FLAG_DIRECT_INDEX);
                    max_time *= 60;
                    if (app_state.timetopay < max_time) app_state.timetopay += 30;
                    PrintServiceTimeSelectMenu(app_state.blink_ctr >= 500);
                    RefreshMenu();
                }
            }
            break;
        case EVENT_BLINK:
            if ((app_state.user_menu == USER_MENU_SELECT_CH) || (app_state.user_menu == USER_MENU_SELECT_CH_CLEANING) || (app_state.user_menu == USER_MENU_SELECT_CH_SERVICE) || (app_state.user_menu == USER_MENU_SELECT_CH_TESTMODE))
            {
                PrintSelectChMenu(app_state.blink_ctr >= 500);
            }
            else if (app_state.user_menu == USER_MENU_SELECT_MODE)
            {
                PrintSelectModeMenu(app_state.blink_ctr >= 500);
            }
            else if (app_state.user_menu == USER_MENU_ALL_PRICE)
            {
                PrintMenuAllPrice(app_state.blink_ctr >= 500);
            }
            else if (app_state.user_menu == USER_MENU_SELECT_PAY_TYPE)
            {
                PrintSelectPayTypeMenu(app_state.blink_ctr >= 500);
            }
            else if (app_state.user_menu == USER_MENU_CASH_PAYING)
            {
                CPU_INT08U skin_att = CheckSkinTypeAttention(app_state.timetopay);
                if (skin_att > 0)
                {
                    app_state.user_menu_prev = app_state.user_menu;
                    app_state.user_menu = skin_att - 1 + USER_MENU_SKIN_ATTENTION_1;
                    if (MusicEnabled()) app_state.menu_timeout = 0;
                    else app_state.menu_timeout = MENU_ATTENTION_TIMEOUT;
                    PrintSkinTypeAttentionMenu(app_state.user_menu - USER_MENU_SKIN_ATTENTION_1);
                    PlayMusicFile(15 + app_state.user_menu - USER_MENU_SKIN_ATTENTION_1);
                }
                else
                {
                    PrintCashPayingMenu(app_state.blink_ctr >= 500);
                }
            }
            else if (app_state.user_menu == USER_MENU_CARD_PAYING)
            {
                PrintCardPayingMenu(app_state.blink_ctr >= 500);
            }
            else if (app_state.user_menu == USER_MENU_SELECT_SERVICE_TIME)
            {
                PrintServiceTimeSelectMenu(app_state.blink_ctr >= 500);
            }
            
            RefreshMenu();
            
            for (int i = 0; i < CHANNELS_NUM; i++)
            {
                if (app_state.solar_state[i] == SOLAR_STATE_TIMEOUT_PRE)
                {
                    CPU_INT32U min, sec;
                    min = app_state.timetoend[i] / 60;
                    sec = app_state.timetoend[i] % 60;
                    PostScoreNumber(i, (CPU_INT16U)min * 100 + sec, app_state.blink_ctr >= 500);
                }
                else if ((app_state.solar_state[i] == SOLAR_STATE_SUNBURN)
                            || (app_state.solar_state[i] == SOLAR_STATE_VENT)
                            || (app_state.solar_state[i] == SOLAR_STATE_TIMEOUT_AFTER)
                            || (app_state.solar_state[i] == SOLAR_STATE_PAUSE)
                        )
                {
                    PostScoreNumber(i, 0, 0);
                }
            }
            
            /*
            TRTC_Data rtc;
            Sec2Date(&rtc, SystemTime);
            PostScoreNumber(0, (CPU_INT16U)rtc.hour * 100 + rtc.min, app_state.blink_ctr >= 500);
            */
            break;
        case EVENT_OPEN_RELAY1:
        case EVENT_OPEN_RELAY2:
        case EVENT_OPEN_RELAY3:
            {
                CPU_INT08U index = event - EVENT_OPEN_RELAY1;
                CPU_INT32U enable;
                GetData(&RelayEnableDesc, &enable, index, DATA_FLAG_DIRECT_INDEX);
                if (enable)
                {
                    CPU_INT32U ip;
                    CPU_INT08U channels_mask;
                    GetData(&RelayIpAddrDesc, &ip, index, DATA_FLAG_DIRECT_INDEX);
                    channels_mask = RelayChannelsMask(index);
                    for (CPU_INT08U i = 0; i < 8; i++)
                    {
                        if (channels_mask & (1 << i))
                        {
                            if (HostRodosSwitch(ip, 80, i, 1, 500) == 0)
                            {
                                if ((app_state.solar_state[index] == SOLAR_STATE_CLEANING) || (app_state.solar_srv[index] == SOLAR_IN_SERVICE))
                                {
                                    app_state.relay_timeout[index] = 0;
                                }
                                else
                                {
                                    GetData(&RelayOpenTimeDesc, &app_state.relay_timeout[index], index, DATA_FLAG_DIRECT_INDEX);
                                }
                            }
                        }
                    }
                }
            }
            break;
        case EVENT_CLOSE_RELAY1:
        case EVENT_CLOSE_RELAY2:
        case EVENT_CLOSE_RELAY3:
            {
                CPU_INT08U index = event - EVENT_CLOSE_RELAY1;
                CPU_INT32U enable;
                GetData(&RelayEnableDesc, &enable, index, DATA_FLAG_DIRECT_INDEX);
                if (enable)
                {
                    CPU_INT32U ip;
                    CPU_INT08U channels_mask;
                    GetData(&RelayIpAddrDesc, &ip, index, DATA_FLAG_DIRECT_INDEX);
                    channels_mask = RelayChannelsMask(index);
                    for (CPU_INT08U i = 0; i < 8; i++)
                    {
                        if (channels_mask & (1 << i))
                        {
                            if (HostRodosSwitch(ip, 80, i, 0, 500))
                            {
                                asm(" nop");
                            }
                        }
                    }
                }
            }
            break;
        case EVENT_KEY_F1:
            #if APP_DEBUG
            if (app_state.user_menu == USER_MENU_CASH_PAYING)
            {
                CPU_INT32U note,accmoney;
                note = 12;
                accmoney = GetAcceptedMoney();
                accmoney += note * 100;
                SetAcceptedMoney(accmoney);
            }
            #else
            if (GetMode() == MODE_WORK)
            {
                if ((app_state.user_menu == USER_MENU_IDLE) || (app_state.user_menu == USER_MENU_WARNING_1))
                {
                    app_state.user_menu = USER_MENU_SERVICE_PASS;
                    GoToMenu(ReqCleaningPassMenuPanel);
                }
            }
            #endif
            break;
        case EVENT_KEY_F2:
            if (GetMode() == MODE_WORK)
            {
                if ((app_state.user_menu == USER_MENU_IDLE) || (app_state.user_menu == USER_MENU_WARNING_1))
                {
                    app_state.user_menu = USER_MENU_SERVICE_PASS;
                    GoToMenu(ReqServicePassMenuPanel);
                }
            }
            break;
        case EVENT_KEY_F3:
            if (GetMode() == MODE_WORK)
            {
                if ((app_state.user_menu == USER_MENU_IDLE) || (app_state.user_menu == USER_MENU_WARNING_1))
                {
                    app_state.user_menu = USER_MENU_SERVICE_PASS;
                    GoToMenu(ReqTestPassMenuPanel);
                }
            }
            break;
        case EVENT_KEY_SOLAR_START1:
        case EVENT_KEY_SOLAR_START2:
        case EVENT_KEY_SOLAR_START3:
            {
                CPU_INT08U index = event - EVENT_KEY_SOLAR_START1;
                for (CPU_INT08U i = 0; i < CHANNELS_NUM; i++)
                {
                    if (control_channels[i] == index)
                    {
                        index = i;
                        break;
                    }
                }
                if (app_state.solar_state[index] == SOLAR_STATE_TIMEOUT_PRE)
                {
                    app_state.solar_state[index] = SOLAR_STATE_SUNBURN;
                    app_state.timetoend[index] = GetPayedTimeForChannel(index);
                    app_state.pause_timeout[index] = 0;
                    SaveTimeMoneyForChannel(index, 0, 0);
                    SetControl(index, CONTROL_STATE_COLLATEN + app_state.sunburn_mode[index]);
                }
                else if (app_state.solar_state[index] == SOLAR_STATE_PAUSE)
                {
                    app_state.solar_state[index] = SOLAR_STATE_SUNBURN;
                    SetControl(index, CONTROL_STATE_COLLATEN + app_state.sunburn_mode[index]);
                }
            }   
            break;
        case EVENT_KEY_SOLAR_STOP1:
        case EVENT_KEY_SOLAR_STOP2:
        case EVENT_KEY_SOLAR_STOP3:
            {
                CPU_INT08U index = event - EVENT_KEY_SOLAR_STOP1;
                for (CPU_INT08U i = 0; i < CHANNELS_NUM; i++)
                {
                    if (control_channels[i] == index)
                    {
                        index = i;
                        break;
                    }
                }
                if (app_state.solar_state[index] == SOLAR_STATE_SUNBURN)
                {
                    app_state.solar_state[index] = SOLAR_STATE_PAUSE;
                    SetControl(index, CONTROL_STATE_PAUSED);
                }
                else if (app_state.solar_state[index] == SOLAR_STATE_PAUSE)
                {
                    ClearSolarService(index);
                    app_state.solar_state[index] = SOLAR_STATE_FREE;
                    SetControl(index, CONTROL_STATE_OFF);
                    PostScoreClear(index);
                }
            }            
            break;
        case EVENT_KEY_CANSEL:
        case EVENT_KEY_STOP:
            app_state.last_key_time = OSTimeGet();
            if (GetMode() != MODE_WORK) break;
            if ((GetCurrentMenu() == ReqCleaningPassMenuPanel) || (GetCurrentMenu() == ReqServicePassMenuPanel) || (GetCurrentMenu() == ReqTestPassMenuPanel))
            {
                app_state.user_menu = USER_MENU_IDLE;
                OSTimeDly(100);
                GoToPreviousMenu();
                SetMenu(WORK_MENU);
                PrintHelloMenu();
                RefreshMenu();
            }
            else if ((app_state.user_menu == USER_MENU_WARNING_1)
                 || (app_state.user_menu == USER_MENU_WARNING_2)
                 || (app_state.user_menu == USER_MENU_SELECT_CH)
                 || (app_state.user_menu == USER_MENU_SERVICE_PASS)
                 || (app_state.user_menu == USER_MENU_SELECT_CH_CLEANING)
                 || (app_state.user_menu == USER_MENU_BALANCE_CARD)
                 || (app_state.user_menu == USER_MENU_START_INSERT_CARD_MONEY)
                 || (app_state.user_menu == USER_MENU_ALL_PRICE)
                 || (app_state.user_menu == USER_MENU_SILVER_BONUS)
                 || (app_state.user_menu == USER_MENU_GOLD_BONUS)
                 || (app_state.user_menu == USER_MENU_PLATINUM_BONUS)
                 || (app_state.user_menu == USER_MENU_BRILLANCE_BONUS)
                 || app_state.user_menu == USER_MENU_SILVER_BONUS
                 || app_state.user_menu == USER_MENU_GOLD_BONUS
                 || app_state.user_menu == USER_MENU_PLATINUM_BONUS
                 || app_state.user_menu == USER_MENU_BRILLANCE_BONUS
                 || app_state.user_menu == USER_MENU_ERROR_BANK_CARD
                 || app_state.user_menu == USER_MENU_FINISH_PAY_BONUS_CARD
                 || app_state.user_menu == USER_MENU_ABONEMENT_FAIL
                )
            {
                app_state.user_menu = USER_MENU_IDLE;
                PrintHelloMenu();
                RefreshMenu();
                StopMusic();
            }
            else if(app_state.user_menu == USER_MENU_ABONENT_PROCESSING)
            {
                app_state.user_menu = USER_MENU_SELECT_PAY_TYPE;
                app_state.pay_index = 0;
                app_state.blink_ctr = 0;
                PrintSelectPayTypeMenu(0);
                RefreshMenu();
                PlayMusicFile(8);
            }
            else if ((app_state.user_menu == USER_MENU_SELECT_CH_SERVICE)
                     || (app_state.user_menu == USER_MENU_SELECT_CH_TESTMODE)
                )
            {
                app_state.user_menu = USER_MENU_IDLE;
                //app_state.solar_srv[app_state.ch_index] = 0;
                PrintHelloMenu();
                RefreshMenu();
            }
            else if (app_state.user_menu == USER_MENU_SELECT_MODE)
            {
                if (app_state.solar_srv[app_state.ch_index] == SOLAR_IN_SERVICE)
                    app_state.user_menu = USER_MENU_SELECT_CH_SERVICE;
                else if (app_state.solar_srv[app_state.ch_index] == SOLAR_IN_TEST)
                    app_state.user_menu = USER_MENU_SELECT_CH_TESTMODE;
                else 
                    app_state.user_menu = USER_MENU_SELECT_CH;
                app_state.solar_srv[app_state.ch_index] = 0;
                app_state.blink_ctr = 0;
                PrintSelectChMenu(0);
                RefreshMenu();
                PlayMusicFile(3);
            }
            else if ((app_state.user_menu == USER_MENU_ACK_MODE) || (app_state.user_menu == USER_MENU_SELECT_PAY_TYPE))
            {
                app_state.user_menu = USER_MENU_SELECT_MODE;
                app_state.blink_ctr = 0;
                PrintSelectModeMenu(0);
                RefreshMenu();
                PlayMusicFile(4);
            }
            else if (app_state.user_menu == USER_MENU_CASH_PAYING)
            {
                if (IsValidatorConnected()) CC_CmdBillType(0x000000, 0x000000, ADDR_FL);
                CoinDisable();
                cash_accept_enabled = 0;
                if (PayTypeTermEnabled() && PayTypeCashEnabled())
                {
                    app_state.user_menu = USER_MENU_SELECT_PAY_TYPE;
                    app_state.blink_ctr = 0;
                    PrintSelectPayTypeMenu(0);
                    RefreshMenu();
                    PlayMusicFile(8);
                }
                else
                {
                    app_state.user_menu = USER_MENU_SELECT_MODE;
                    app_state.blink_ctr = 0;
                    PrintSelectModeMenu(0);
                    RefreshMenu();
                    PlayMusicFile(4);
                }
            }
            else if ((app_state.user_menu == USER_MENU_CARD_PAYING) || (app_state.user_menu == USER_MENU_CARD_FAIL))
            {
                if (PayTypeTermEnabled() && PayTypeCashEnabled())
                {
                    app_state.user_menu = USER_MENU_SELECT_PAY_TYPE;
                    app_state.blink_ctr = 0;
                    PrintSelectPayTypeMenu(0);
                    RefreshMenu();
                    PlayMusicFile(8);
                }
                else
                {
                    app_state.user_menu = USER_MENU_SELECT_MODE;
                    app_state.blink_ctr = 0;
                    PrintSelectModeMenu(0);
                    RefreshMenu();
                    PlayMusicFile(4);
                }
            }
            else if (app_state.user_menu == USER_MENU_CARD_PROCESSING)
            {
                SetTermCommand(TERM_COMMAND_ABORT_PUR, NULL);
                app_state.user_menu = USER_MENU_CARD_PAYING;
                app_state.blink_ctr = 0;
                PrintCardPayingMenu(0);
                RefreshMenu();
                PlayMusicFile(12 + app_state.mode_index);
            }
            break;
        case EVENT_COIN_INSERTED:
            {
                CPU_INT32U cpp = 1;
                CPU_INT32U money, accmoney;
                GetData(&CoinPerPulseDesc, &cpp, 0, DATA_FLAG_SYSTEM_INDEX);
                money = cpp * GetResetCoinCount();
                accmoney = GetAcceptedMoney();
                accmoney += money * 100;
                SetAcceptedMoney(accmoney);
                CoinEnable();
                cash_accept_enabled = 1;
                SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_MONEY_COIN, money * 100);
                app_state.last_key_time = OSTimeGet();
            }
            break;
        case EVENT_BILL_ESCROW:
            // купюра в положении возврата
            if (app_state.user_menu != USER_MENU_CASH_PAYING)
            {
                if (IsValidatorConnected()) if (!CC_CmdReturn(ADDR_FL)) SetErrorFlag(ERROR_VALIDATOR_CONN);
            }
            else
            {
                if (IsValidatorConnected()) if (!CC_CmdPack(ADDR_FL)) SetErrorFlag(ERROR_VALIDATOR_CONN);
            }
            app_state.last_key_time = OSTimeGet();
            break;
        case EVENT_BILL_STACKED:
            // купюра уложена
            {
                CPU_INT32U billnom_index;
                CPU_INT32U note,accmoney;
                note = GetResetBillCount(&billnom_index);
                accmoney = GetAcceptedMoney();
                accmoney += note * 100;
                SetAcceptedMoney(accmoney);
                if (IsValidatorConnected()) CC_CmdBillType(0xffffff, 0xffffffff, ADDR_FL);
                CoinEnable();
                cash_accept_enabled = 1;
                SaveEventRecord(app_state.ch_index, JOURNAL_EVENT_MONEY_NOTE, note * 100);
                IncBillnomCounter(billnom_index);
                app_state.last_key_time = OSTimeGet();
            }
            break;      
        case EVENT_INCASSATION:
            {
                // считаем сумму инкассации
                CPU_INT32U incas_sum = 0, temp;              
                for (CPU_INT32U i = 0; i < 24; i++)
                {
                    CPU_INT32U val = 0;
                    GetData(&BillnomCountersDesc, &val, i, DATA_FLAG_DIRECT_INDEX);
                    incas_sum += val*BillNominals[i];
                }
                incassation = 1;
                // вешаем меню инкассации
                sprintf((char*)str_UserMenu_3, "  СУММА %u руб.", incas_sum);
                GoToMenu(IncasMenuPanel);
                // сохраним событие с указанием суммы денег
                SaveEventRecord(0, JOURNAL_EVENT_INCASSATION, incas_sum);
                GetData(&BillCounterDesc, &incas_common_bill_counter, 0, DATA_FLAG_SYSTEM_INDEX);
                for (CPU_INT32U i = 0; i < 24; i++)
                {
                    GetData(&BillnomCountersDesc, &incas_bill_nom_counter[i], i, DATA_FLAG_DIRECT_INDEX);
                }
                SetData(&IncasMoneyDesc, &incas_sum, 0, DATA_FLAG_SYSTEM_INDEX);
                temp = GetTimeSec();
                SetData(&IncasTimeDesc, &temp, 0, DATA_FLAG_SYSTEM_INDEX);

                #if defined(CONFIG_MODEM_ENABLE)
                temp = INCAS_SEND_FLAG; 
                SetData(&IncasSendFlagDesc, &temp, 0, DATA_FLAG_SYSTEM_INDEX);
                PostModemTask(MODEM_TASK_SEND_INCAS);
                #endif
                
                // очищаем счетчики купюр
                ClearBillnomCounter();
            }
            break;
        case EVENT_INCASSATION_FINISH:
            incassation = 0;
            GoToPreviousMenu();
            break;
        case EVENT_MODE_CHANGE:
            if (!start_pass_ok) break;
            ReInitMenu();
            SaveEventRecord(0, JOURNAL_EVENT_CHANGE_MODE, GetMode());
            if (GetMode() == MODE_WORK)
            {
                if (IsValidatorConnected()) CC_CmdBillType(0x000000, 0x000000, ADDR_FL);
                CoinDisable();
                cash_accept_enabled = 0;
                SetTermCommand(TERM_COMMAND_ABORT_PUR, NULL);
                app_state.user_menu = USER_MENU_IDLE;
                PrintHelloMenu();
                RefreshMenu();
            }
            else
            {
                if (app_state.user_menu == USER_MENU_CARD_PROCESSING)
                {
                    SetTermCommand(TERM_COMMAND_ABORT_PUR, NULL);
                }
                else
                {
                    if (IsValidatorConnected()) CC_CmdBillType(0x000000, 0x000000, ADDR_FL);
                    CoinDisable();
                    cash_accept_enabled = 0;
                }
            }
            
            break;
        case EVENT_UPDATE_MUSIC_VOLUME:
            {
                CPU_INT32U sound_type;
                GetData(&SoundTypeDesc, &sound_type, 0, DATA_FLAG_SYSTEM_INDEX);
                if (sound_type == 2)
                {
                    CPU_INT32U sound_ip, volume;
                    GetData(&SoundIpAddrDesc, &sound_ip, 0, DATA_FLAG_SYSTEM_INDEX); 
                    GetData(&SoundVolumeDesc, &volume, 0, DATA_FLAG_SYSTEM_INDEX); 
                    if (HostSetVolume(sound_ip, volume) >= 0)
                    {
                        player_conn = 1;
                    }
                    else
                    {
                        player_conn = 0;
                    }
                }
            }
            break;
        case EVENT_STOP_SOUND_FILE:
            {
                CPU_INT32U sound_type;
                GetData(&SoundTypeDesc, &sound_type, 0, DATA_FLAG_SYSTEM_INDEX);
                if (sound_type == 2)
                {
                    CPU_INT32U sound_ip;
                    GetData(&SoundIpAddrDesc, &sound_ip, 0, DATA_FLAG_SYSTEM_INDEX); 
                    if (HostMusicStop(sound_ip) >= 0)
                    {
                        player_conn = 1;
                    }
                    else
                    {
                        player_conn = 0;
                    }
                }
            }
            break;
        case EVENT_PLAY_SOUND_FILE:
            PlayMusicFile(file_menu_cmd);
            if (!IsPlaying())
            {
                file_menu_cmd = 0;
            }
            break;            
    } // switch (event)
}

void PrintStartReadCardMenu(void)
{
    PrintUserMenuStr("                    ", 0);
    PrintUserMenuStr(" Удерживайте карту  ", 1);
    PrintUserMenuStr("у специального окна!", 2);
    PrintUserMenuStr("                    ", 3);    
}

void PrintBalanceMenu(void)
{
    char str[32];
    abonement_data* data = get_abonement_data();

    PrintUserMenuStr(" Ваша карта загара: ", 0);

    sprintf(str, "    %d рублей", data->money);
    PrintUserMenuStr(str, 1);

    sprintf(str, "%d бонусов, сгорят:", data->bonus);
    PrintUserMenuStr(str, 2);

    PrintDateString(str, data->best_before);
    PrintUserMenuStr(str, 3);
}

void PrintMenuStartPay(void)
{
    PrintUserMenuStr("Не желаете пополнить", 0);
    PrintUserMenuStr("   карту загара?    ", 1);
    PrintUserMenuStr("(Купить бонусный    ", 2);
    PrintUserMenuStr("     абонемент?)    ", 3);
}

void PrintMenuAllPrice(CPU_INT08U blink)
{
    char str[32];
    uint32_t pay_silver = 0, bonus_silver = 0;
    uint32_t pay_gold = 0, bonus_gold = 0;
    uint32_t pay_plat = 0, bonus_plat = 0;
    uint32_t pay_diamond = 0, bonus_diamond = 0;

    GetData(&AbonementMoneyDesc, &pay_silver, 0, DATA_FLAG_DIRECT_INDEX);
    GetData(&AbonementBonusDesc, &bonus_silver, 0, DATA_FLAG_DIRECT_INDEX);

    GetData(&AbonementMoneyDesc, &pay_gold, 1, DATA_FLAG_DIRECT_INDEX);
    GetData(&AbonementBonusDesc, &bonus_gold, 1, DATA_FLAG_DIRECT_INDEX);

    GetData(&AbonementMoneyDesc, &pay_plat, 2, DATA_FLAG_DIRECT_INDEX);
    GetData(&AbonementBonusDesc, &bonus_plat, 2, DATA_FLAG_DIRECT_INDEX);

    GetData(&AbonementMoneyDesc, &pay_diamond, 3, DATA_FLAG_DIRECT_INDEX);
    GetData(&AbonementBonusDesc, &bonus_diamond, 3, DATA_FLAG_DIRECT_INDEX);

    if(app_state.current_abonement == SILVER_ABONEMENT)
    {
        if(blink) {
            PrintUserMenuStr(" ", 0);
            sprintf(str, "ЗОЛОТ-%5dр %5d Б", pay_gold, bonus_gold);
            PrintUserMenuStr(str, 1);
            sprintf(str, "ПЛАТ.-%5dр %5d Б", pay_plat, bonus_plat);
            PrintUserMenuStr(str, 2);
            sprintf(str, "АЛМАЗ-%5dр %5d Б", pay_diamond, bonus_diamond);
            PrintUserMenuStr(str, 3);
        } else {
            sprintf(str, "СЕРЕБ-%5dр %5d Б", pay_silver, bonus_silver);
            PrintUserMenuStr(str, 0);
            sprintf(str, "ЗОЛОТ-%5dр %5d Б", pay_gold, bonus_gold);
            PrintUserMenuStr(str, 1);
            sprintf(str, "ПЛАТ.-%5dр %5d Б", pay_plat, bonus_plat);
            PrintUserMenuStr(str, 2);
            sprintf(str, "АЛМАЗ-%5dр %5d Б", pay_diamond, bonus_diamond);
            PrintUserMenuStr(str, 3);
        }
    }
    else if(app_state.current_abonement == GOLD_ABONEMENT)
    {
        if(blink) {
            sprintf(str, "СЕРЕБ-%5dр %5d Б", pay_silver, bonus_silver);
            PrintUserMenuStr(str, 0);

            PrintUserMenuStr(" ", 1);
            sprintf(str, "ПЛАТ.-%5dр %5d Б", pay_plat, bonus_plat);
            PrintUserMenuStr(str, 2);
            sprintf(str, "АЛМАЗ-%5dр %5d Б", pay_diamond, bonus_diamond);
            PrintUserMenuStr(str, 3);
        } else {
            sprintf(str, "СЕРЕБ-%5dр %5d Б", pay_silver, bonus_silver);
            PrintUserMenuStr(str, 0);
            sprintf(str, "ЗОЛОТ-%5dр %5d Б", pay_gold, bonus_gold);
            PrintUserMenuStr(str, 1);
            sprintf(str, "ПЛАТ.-%5dр %5d Б", pay_plat, bonus_plat);
            PrintUserMenuStr(str, 2);
            sprintf(str, "АЛМАЗ-%5dр %5d Б", pay_diamond, bonus_diamond);
            PrintUserMenuStr(str, 3);
        }
    }
    else if(app_state.current_abonement == PLATINUM_ABONEMENT)
    {
        if(blink) {
            sprintf(str, "СЕРЕБ-%5dр %5d Б", pay_silver, bonus_silver);
            PrintUserMenuStr(str, 0);
            sprintf(str, "ЗОЛОТ-%5dр %5d Б", pay_gold, bonus_gold);
            PrintUserMenuStr(str, 1);

            PrintUserMenuStr(" ", 2);
            sprintf(str, "АЛМАЗ-%5dр %5d Б", pay_diamond, bonus_diamond);
            PrintUserMenuStr(str, 3);
        } else {
            sprintf(str, "СЕРЕБ-%5dр %5d Б", pay_silver, bonus_silver);
            PrintUserMenuStr(str, 0);
            sprintf(str, "ЗОЛОТ-%5dр %5d Б", pay_gold, bonus_gold);
            PrintUserMenuStr(str, 1);
            sprintf(str, "ПЛАТ.-%5dр %5d Б", pay_plat, bonus_plat);
            PrintUserMenuStr(str, 2);
            sprintf(str, "АЛМАЗ-%5dр %5d Б", pay_diamond, bonus_diamond);
            PrintUserMenuStr(str, 3);
        }
    }
    else if(app_state.current_abonement == DIAMOND_ABONEMENT)
    {
        if(blink) {
            sprintf(str, "СЕРЕБ-%5dр %5d Б", pay_silver, bonus_silver);
            PrintUserMenuStr(str, 0);
            sprintf(str, "ЗОЛОТ-%5dр %5d Б", pay_gold, bonus_gold);
            PrintUserMenuStr(str, 1);
            sprintf(str, "ПЛАТ.-%5dр %5d Б", pay_plat, bonus_plat);
            PrintUserMenuStr(str, 2);

            PrintUserMenuStr(" ", 3);
        } else {
            sprintf(str, "СЕРЕБ-%5dр %5d Б", pay_silver, bonus_silver);
            PrintUserMenuStr(str, 0);
            sprintf(str, "ЗОЛОТ-%5dр %5d Б", pay_gold, bonus_gold);
            PrintUserMenuStr(str, 1);
            sprintf(str, "ПЛАТ.-%5dр %5d Б", pay_plat, bonus_plat);
            PrintUserMenuStr(str, 2);
            sprintf(str, "АЛМАЗ-%5dр %5d Б", pay_diamond, bonus_diamond);
            PrintUserMenuStr(str, 3);
        }
    }
}

void PrintSilverMenu(void)
{
    char str[32];
    char str1[20];
    uint32_t pay_silver = 0, bonus_silver = 0, best_before = 0;

    GetData(&AbonementMoneyDesc, &pay_silver, 0, DATA_FLAG_DIRECT_INDEX);
    GetData(&AbonementBonusDesc, &bonus_silver, 0, DATA_FLAG_DIRECT_INDEX);
    GetData(&AbonementBestBeforeDesc, &best_before, 0, DATA_FLAG_DIRECT_INDEX);

    uint32_t SystemTime = GetTimeSec() + best_before * 24L * 60L * 60L;

    PrintUserMenuStr("Серебрянный абонемент", 0);

    sprintf(str, "Стоимость - %d руб", pay_silver);
    PrintUserMenuStr(str, 1);

    sprintf(str, "Доп.бонусы- %d руб", bonus_silver);
    PrintUserMenuStr(str, 2);

    PrintDateString(str1, SystemTime);
    sprintf(str, "Бонусы до %s", str1);
    PrintUserMenuStr(str, 3);
}

void PrintGoldMenu(void)
{
    char str[32];
    char str1[20];
    uint32_t pay_gold = 0, bonus_gold = 0, best_before = 0;

    GetData(&AbonementMoneyDesc, &pay_gold, 1, DATA_FLAG_DIRECT_INDEX);
    GetData(&AbonementBonusDesc, &bonus_gold, 1, DATA_FLAG_DIRECT_INDEX);
    GetData(&AbonementBestBeforeDesc, &best_before, 1, DATA_FLAG_DIRECT_INDEX);

    uint32_t SystemTime = GetTimeSec() + best_before * 24L * 60L * 60L;

    PrintUserMenuStr(" Золотой абонемент  ", 0);

    sprintf(str, "Стоимость - %d руб", pay_gold);
    PrintUserMenuStr(str, 1);

    sprintf(str, "Доп.бонусы- %d руб", bonus_gold);
    PrintUserMenuStr(str, 2);

    PrintDateString(str1, SystemTime);
    sprintf(str, "Бонусы до %s", str1);
    PrintUserMenuStr(str, 3);
}

void PrintPlatMenu(void)
{
    char str[32];
    char str1[20];
    uint32_t pay_plat = 0, bonus_plat = 0, best_before = 0;

    GetData(&AbonementMoneyDesc, &pay_plat, 2, DATA_FLAG_DIRECT_INDEX);
    GetData(&AbonementBonusDesc, &bonus_plat, 2, DATA_FLAG_DIRECT_INDEX);
    GetData(&AbonementBestBeforeDesc, &best_before, 2, DATA_FLAG_DIRECT_INDEX);

    uint32_t SystemTime = GetTimeSec() + best_before * 24L * 60L * 60L;

    PrintUserMenuStr("Платиновый абонемент", 0);

    sprintf(str, "Стоимость - %d руб", pay_plat);
    PrintUserMenuStr(str, 1);

    sprintf(str, "Доп.бонусы- %d руб", bonus_plat);
    PrintUserMenuStr(str, 2);

    PrintDateString(str1, SystemTime);
    sprintf(str, "Бонусы до %s", str1);
    PrintUserMenuStr(str, 3);
}

void PrintDiamondMenu(void)
{
    char str[32];
    char str1[20];
    uint32_t pay_diamond = 0, bonus_diamond = 0, best_before = 0;

    GetData(&AbonementMoneyDesc, &pay_diamond, 3, DATA_FLAG_DIRECT_INDEX);
    GetData(&AbonementBonusDesc, &bonus_diamond, 3, DATA_FLAG_DIRECT_INDEX);
    GetData(&AbonementBestBeforeDesc, &best_before, 3, DATA_FLAG_DIRECT_INDEX);

    uint32_t SystemTime = GetTimeSec() + best_before * 24L * 60L * 60L;

    PrintUserMenuStr(" Алмазный абонемент ", 0);

    sprintf(str, "Стоимость - %d руб", pay_diamond);
    PrintUserMenuStr(str, 1);

    sprintf(str, "Доп.бонусы- %d руб", bonus_diamond);
    PrintUserMenuStr(str, 2);

    PrintDateString(str1, SystemTime);
    sprintf(str, "Бонусы до %s", str1);
    PrintUserMenuStr(str, 3);
}

void PrintStartPayCardMenu(void)
{
    PrintUserMenuStr("При оплате:", 0);
    PrintUserMenuStr("Деньги - суммируются", 1);
    PrintUserMenuStr("Стар. бонусы сгорают", 2);
    PrintUserMenuStr("Сроки бонусов-новые ", 3);
}

void PrintInsertBankCardMenu(void)
{
    PrintUserMenuStr("Приложите банковскую", 0);
    PrintUserMenuStr(" карту к терминалу  ", 1);
    PrintUserMenuStr("  или оплатите по   ", 2);
    PrintUserMenuStr("     Q-коду         ", 3);
}

void PrintInsertBonusCardMenu(void)
{
    PrintUserMenuStr("     Приложите      ", 0);
    PrintUserMenuStr("    КАРТУ ЗАГАРА    ", 1);
    PrintUserMenuStr("к специальному окну!", 2);
    PrintUserMenuStr("                    ", 3);
}

void PrintFinishPayMenu(void)
{
    PrintUserMenuStr("  Ваша КАРТА ЗАГАРА ", 0);
    PrintUserMenuStr("       готова       ", 1);
    PrintUserMenuStr("  Для продолжения   ", 2);
    PrintUserMenuStr("   нажмите СТАРТ!   ", 3);
}

void PrintAnotherCardMenu(void)
{
    PrintUserMenuStr("  Приложите другую  ", 0);
    PrintUserMenuStr(" карту к терминалу! ", 1);
    PrintUserMenuStr("  или оплатите по   ", 2);
    PrintUserMenuStr("     Q-коду        ", 3);
}

void PrintHelloMenu(void)
{
    PrintUserMenuStr("  Здравствуйте!", 0);
    PrintUserMenuStr("Для начала работы", 1);
    PrintUserMenuStr("Определите тип своей", 2);
    PrintUserMenuStr("кожи и нажмите СТАРТ", 3);
}

void PrintWarning1Menu(void)
{
    PrintUserMenuStrUnalign("  Перед посещением", 0);
    PrintUserMenuStrUnalign(" солярия необходима", 1);
    PrintUserMenuStrUnalign(" консультация врача", 2);
    PrintUserMenuStrUnalign("по противопоказаниям", 3);
}

void PrintWarning2Menu(void)
{
    PrintUserMenuStrUnalign("Перед использованием", 0);
    PrintUserMenuStrUnalign("АВТОМАТА  необходимо", 1);
    PrintUserMenuStrUnalign("    ознакомиться    ", 2);
    PrintUserMenuStrUnalign(" с его инструкцией", 3);
}

void PrintWrongAbonementMenu(void)
{
    PrintUserMenuStrUnalign(" Ваша КАРТА ЗАГАРА ", 0);
    PrintUserMenuStrUnalign("   не может быть   ", 1);
    PrintUserMenuStrUnalign("    использована   ", 2);
    PrintUserMenuStrUnalign("  на этом АВТОМАТЕ ", 3);
}

void PrintSelectChMenu(CPU_INT08U blink)
{
    CPU_INT08U i;

    PrintUserMenuStrUnalign("   ВЫБОР СОЛЯРИЯ", 0);

    for (i = 0; i < CHANNELS_NUM; i++)
    {
        char str[32];

        if (blink && (i == app_state.ch_index))
        {
            str[0] = '\0';
        }
        else if (!SolariumEnabled(i))
        {
            sprintf(str, "%d НЕ РАБОТАЕТ", i + 1);
        }
        /*else if (app_state.solar_srv[i] == SOLAR_IN_SERVICE)
        {
            sprintf(str, "%d СЕРВИСНЫй РЕЖИМ", i + 1);
        }
        else if (app_state.solar_srv[i] == SOLAR_IN_TEST)
        {
            sprintf(str, "%d ТЕСТОВЫЙ РЕЖИМ", i + 1);
        }
        */
        else if (app_state.solar_state[i] == SOLAR_STATE_FREE)
        {
            sprintf(str, "%d СОЛЯРИй СВОБОДЕН", i + 1);
        }
        else if (app_state.solar_state[i] == SOLAR_STATE_CLEANING)
        {
            sprintf(str, "%d ИДЕТ УБОРКА", i + 1);
        }
        else
        {
            CPU_INT32U timetoend = SolariumTimeToEnd(i);
            sprintf(str, "%d Осталось ", i + 1);
            PrintSecToMinSec(&str[strlen(str)], timetoend);
        }
        PrintUserMenuStrUnalign(str, 1 + i);
    }
}

void PrintSelectModeMenu(CPU_INT08U blink)
{
    char str[32];
    int price;
    if (app_state.solar_srv[app_state.ch_index] == SOLAR_IN_SERVICE)
      PrintUserMenuStrUnalign("Режимы загара сервис", 0);
    else if (app_state.solar_srv[app_state.ch_index] == SOLAR_IN_TEST)
      PrintUserMenuStrUnalign("Режимы загара тест", 0);
    else
      PrintUserMenuStrUnalign("Режимы загара   Цена", 0);
        
    price = GetPricePerMin(app_state.ch_index, SUNBURN_MODE_COLLATEN);
    if (app_state.solar_srv[app_state.ch_index] == 0) sprintf(str, "КОЛЛАТЭН      %3d,%02d", price/100, price%100);
    else sprintf(str, "КОЛЛАТЭН ");
    if ((blink) && (app_state.mode_index == SUNBURN_MODE_COLLATEN))
    {
        str[0] = '\0';
    }
    PrintUserMenuStrUnalign(str, 1);
    
    price = GetPricePerMin(app_state.ch_index, SUNBURN_MODE_UF);
    if (app_state.solar_srv[app_state.ch_index] == 0) sprintf(str, "УЛbТРАФИОЛЕТ  %3d,%02d", price/100, price%100);
    else sprintf(str, "УЛbТРАФИОЛЕТ ");
    if ((blink) && (app_state.mode_index == SUNBURN_MODE_UF))
    {
        str[0] = '\0';
    }
    PrintUserMenuStrUnalign(str, 2);

    price = GetPricePerMin(app_state.ch_index, SUNBURN_MODE_MAX);
    if (app_state.solar_srv[app_state.ch_index] == 0) sprintf(str, "МАКСИМАЛbНЫй  %3d,%02d", price/100, price%100);
    else sprintf(str, "МАКСИМАЛbНЫй ");
    if ((blink) && (app_state.mode_index == SUNBURN_MODE_MAX))
    {
        str[0] = '\0';
    }
    PrintUserMenuStrUnalign(str, 3);
}

void PrintAckModeMenu(void)
{
    CPU_INT32U price, lamps;
    char str[32];
    
    if (app_state.mode_index == SUNBURN_MODE_COLLATEN)
    {
        PrintUserMenuStrUnalign("   РЕЖИМ КОЛЛАТЭН", 0);
        PrintUserMenuStrUnalign("Слабый загар +", 1);
        PrintUserMenuStrUnalign("омоложен.+витамин D3", 2);
        GetData(&SolarLampsCountDesc, &lamps, app_state.ch_index * SOLAR_MODES_COUNT + SUNBURN_MODE_COLLATEN, DATA_FLAG_DIRECT_INDEX);
        price = GetPricePerMin(app_state.ch_index, SUNBURN_MODE_COLLATEN);
    }
    else if (app_state.mode_index == SUNBURN_MODE_UF)
    {
        PrintUserMenuStrUnalign(" РЕЖИМ УЛbТРАФИОЛЕТ", 0);
        PrintUserMenuStrUnalign("Умеренный загар +", 1);
        PrintUserMenuStrUnalign("витамин D3", 2);
        GetData(&SolarLampsCountDesc, &lamps, app_state.ch_index * SOLAR_MODES_COUNT + SUNBURN_MODE_UF, DATA_FLAG_DIRECT_INDEX);
        price = GetPricePerMin(app_state.ch_index, SUNBURN_MODE_UF);
    }
    else
    {
        PrintUserMenuStrUnalign(" РЕЖИМ МАКСИМАЛbНЫй", 0);
        PrintUserMenuStrUnalign("Сильный загар +", 1);
        PrintUserMenuStrUnalign("омоложен.+витамин D3", 2);
        GetData(&SolarLampsCountDesc, &lamps, app_state.ch_index * SOLAR_MODES_COUNT + SUNBURN_MODE_MAX, DATA_FLAG_DIRECT_INDEX);
        price = GetPricePerMin(app_state.ch_index, SUNBURN_MODE_MAX);
    }

    sprintf(str, "%d ламп-%d,%02dруб/мин", lamps, price/100, price%100);
    PrintUserMenuStrUnalign(str, 3);
}

void PrintSelectPayTypeMenu(CPU_INT08U blink)
{
    PrintUserMenuStrUnalign("  Выберите способ", 0);
    PrintUserMenuStrUnalign("      оплаты", 1);
    if (app_state.pay_index == PAY_TYPE_CARD_ABONEMENT)
    {
        if (blink)
        {
            PrintUserMenuStrUnalign(" ", 2);
            PrintUserMenuStrUnalign("2. Банковской картой", 3);
        }
        else
        {
            PrintUserMenuStrUnalign("1. Картой загара", 2);
            PrintUserMenuStrUnalign("2. Банковской картой", 3);
        }
    }
    if (app_state.pay_index == PAY_TYPE_CARD)
    {
        if (blink)
        {
            PrintUserMenuStrUnalign("1. Картой загара", 2);
            PrintUserMenuStrUnalign(" ", 3);
        }
        else
        {
            PrintUserMenuStrUnalign("1. Картой загара", 2);
            PrintUserMenuStrUnalign("2. Банковской картой", 3);
        }
    }
}

void PrintCashPayingMenu(CPU_INT08U blink)
{
    char str[32];
    int money = GetAcceptedMoney();
    int price, sec;
        
    if (app_state.mode_index == SUNBURN_MODE_COLLATEN)
    {
        PrintUserMenuStrUnalign("   Режим КОЛЛАТЭН", 0);
    }   
    else if (app_state.mode_index == SUNBURN_MODE_UF)
    {
        PrintUserMenuStrUnalign(" Режим УЛbТРАФИОЛЕТ", 0);
    }
    else if (app_state.mode_index == SUNBURN_MODE_MAX)
    {
        PrintUserMenuStrUnalign(" Режим МАКСИМАЛbНЫй", 0);
    }

    sprintf(str, "Внесено: %d,%02d руб.", money / 100, money % 100);
    PrintUserMenuStrUnalign(str, 1);
    
    price = GetPricePerMin(app_state.ch_index, app_state.mode_index);
    sprintf(str, "   %d,%02dруб/мин", price/100, price%100);
    PrintUserMenuStrUnalign(str, 2);

    sec = (money * 60) / price;
    app_state.timetopay = sec;
    
    if (blink)
    {
        strcpy(str, "ОПЛАЧЕНО");
    }
    else
    {
        sprintf(str, "ОПЛАЧЕНО %dмин %dсек", sec / 60, sec % 60);
    }
    PrintUserMenuStrUnalign(str, 3);
}

void PrintCardPayingMenu(CPU_INT08U blink)
{
    char str[32];
    int price;
    
    if (app_state.mode_index == SUNBURN_MODE_COLLATEN)
    {
        PrintUserMenuStrUnalign("   Режим КОЛЛАТЭН", 0);
    }
    else if (app_state.mode_index == SUNBURN_MODE_UF)
    {
        PrintUserMenuStrUnalign(" Режим УЛbТРАФИОЛЕТ", 0);
    }
    else if (app_state.mode_index == SUNBURN_MODE_MAX)
    {
        PrintUserMenuStrUnalign(" Режим МАКСИМАЛbНЫй", 0);
    }

    sprintf(str, "Время загара %d,%dмин", app_state.timetopay / 60, (app_state.timetopay % 60) / 6);
    if (blink)
    {
        char *ptr1 = strstr(str, "мин");
        char *ptr2 = &str[13];
        while (ptr2 < ptr1) *ptr2++ = ' ';
    }
    PrintUserMenuStrUnalign(str, 1);
    
    price = GetPricePerMin(app_state.ch_index, app_state.mode_index);
    sprintf(str, "    %d,%02dруб/мин", price/100, price%100);
    PrintUserMenuStrUnalign(str, 2);
    
    app_state.moneytopay = (int)(((float)app_state.timetopay / 60.0) * (float)price);
    sprintf(str, "К оплате:%dруб.%02dкоп.", app_state.moneytopay/100, app_state.moneytopay%100);
    PrintUserMenuStrUnalign(str, 3);
}

void PrintServiceTimeSelectMenu(CPU_INT08U blink)
{
    char str[32];

    if (app_state.mode_index == SUNBURN_MODE_COLLATEN)
    {
        PrintUserMenuStrUnalign("   Режим КОЛЛАТЭН", 0);
    }
    else if (app_state.mode_index == SUNBURN_MODE_UF)
    {
        PrintUserMenuStrUnalign(" Режим УЛbТРАФИОЛЕТ", 0);
    }
    else if (app_state.mode_index == SUNBURN_MODE_MAX)
    {
        PrintUserMenuStrUnalign(" Режим МАКСИМАЛbНЫй", 0);
    }

    if (app_state.solar_srv[app_state.ch_index] == SOLAR_IN_SERVICE)
    {
        PrintUserMenuStrUnalign("      СЕРВИС", 1);
    }
    else
    {
        PrintUserMenuStrUnalign("       ТЕСТ ", 1);
    }

    sprintf(str, "    Время загара");
    PrintUserMenuStrUnalign(str, 2);

    sprintf(str, "     %dмин %02dсек", app_state.timetopay / 60, app_state.timetopay % 60);
    if (blink)
    {
        char *ptr1 = strstr(str, "мин");
        char *ptr2 = &str[0];
        while (ptr2 < ptr1) *ptr2++ = ' ';
        ptr1 += strlen("мин");
        ptr2 = strstr(str, "сек");
        while (ptr1 < ptr2) *ptr1++ = ' ';
    }
    PrintUserMenuStrUnalign(str, 3);
}
                    
void PrintTerminalRequestMenu(void)
{
    char str[32];

    sprintf(str, "ОПЛАТА %dруб.%02dкоп.", app_state.moneytopay/100, app_state.moneytopay%100);
    PrintUserMenuStr(str, 0);
    if (term_protocol() == TERMINAL_PROTOCOL_TTK2) 
    {
        PrintUserMenuStr("     Вставьте ", 1);
        PrintUserMenuStr("  банковскую карту", 2);
        PrintUserMenuStr("   в картоприемник", 3);
    }
    else
    {
        PrintUserMenuStr("   Приложите ", 1);
        PrintUserMenuStr("  банковскую карту", 2);
        PrintUserMenuStr("  к терминалу", 3);
    }
}

void PrintThanksMenu(void)
{
    if (app_state.solar_srv[app_state.ch_index] == SOLAR_IN_SERVICE)
    {
        PrintUserMenuStr("Сервисный режим", 0);
        PrintUserMenuStr("активирован", 1);
        PrintUserMenuStr("Пройдите в солярий", 2);
        PrintUserMenuStr("", 3);
    }
    else if (app_state.solar_srv[app_state.ch_index] == SOLAR_IN_TEST)
    {
        PrintUserMenuStr("Тестовый режим", 0);
        PrintUserMenuStr("активирован", 1);
        PrintUserMenuStr("Пройдите в солярий", 2);
        PrintUserMenuStr("", 3);
    }
    else
    {
        PrintUserMenuStr("Оплата принята", 0);
        PrintUserMenuStr("Спасибо", 1);
        PrintUserMenuStr("Пройдите в солярий", 2);
        PrintUserMenuStr("", 3);
    }
}

void PrintSkinTypeAttentionMenu(CPU_INT08U skintype)
{
    if (skintype == 0)
    {
        PrintUserMenuStrUnalign("Для 1 фототипа кожи", 0);
        PrintUserMenuStrUnalign(" достигнут максимум", 1);
        PrintUserMenuStrUnalign("  ОПАСАйТЕСb ОЖОГА", 2);
        PrintUserMenuStrUnalign("        !!!", 3);
    }
    else if (skintype == 1)
    {
        PrintUserMenuStrUnalign("Для 2 фототипа кожи", 0);
        PrintUserMenuStrUnalign(" достигнут максимум", 1);
        PrintUserMenuStrUnalign("  ОПАСАйТЕСb ОЖОГА", 2);
        PrintUserMenuStrUnalign("        !!!", 3);
    }
    else if (skintype == 2)
    {
        PrintUserMenuStrUnalign("Для 3 фототипа кожи", 0);
        PrintUserMenuStrUnalign(" достигнут максимум", 1);
        PrintUserMenuStrUnalign("  ОПАСАйТЕСb ОЖОГА", 2);
        PrintUserMenuStrUnalign("        !!!", 3);
    }
    else if (skintype == 3)
    {
        PrintUserMenuStrUnalign("Для 4 фототипа кожи", 0);
        PrintUserMenuStrUnalign(" достигнут максимум", 1);
        PrintUserMenuStrUnalign("  ОПАСАйТЕСb ОЖОГА", 2);
        PrintUserMenuStrUnalign("        !!!", 3);
    }
}

///
void StopMusic(void)
{
    CPU_INT32U sound_type;
    GetData(&SoundTypeDesc, &sound_type, 0, DATA_FLAG_SYSTEM_INDEX);
    if (sound_type == 1) MusicCanselPlay();
    else if (sound_type == 2)
    {
        CPU_INT32U sound_ip;
        GetData(&SoundIpAddrDesc, &sound_ip, 0, DATA_FLAG_SYSTEM_INDEX);    
        HostMusicStop(sound_ip);
    }
}

int MusicEnabled(void)
{
    CPU_INT32U sound_type;
    GetData(&SoundTypeDesc, &sound_type, 0, DATA_FLAG_SYSTEM_INDEX);
    if (sound_type > 0) return 1;
    return 0;
}
      
int IsPlaying(void)
{
    CPU_INT32U sound_type;
    GetData(&SoundTypeDesc, &sound_type, 0, DATA_FLAG_SYSTEM_INDEX);
    if (sound_type == 1) return IsMusicPlaying();
    else if (sound_type == 2)
    {
        CPU_INT32U sound_ip;
        GetData(&SoundIpAddrDesc, &sound_ip, 0, DATA_FLAG_SYSTEM_INDEX);    
        return HostIsMusicPlaying(sound_ip);
    }
    return 0;
}

void PlayMusicFile(int file_index)
{
    CPU_INT32U sound_type;
    GetData(&SoundTypeDesc, &sound_type, 0, DATA_FLAG_SYSTEM_INDEX);
    if (sound_type == 1)
    {
        StopMusic();
        PostMusicEvent(MUSIC_EVENT_PLAY_FILE + file_index);
    }
    else if (sound_type == 2)
    {
        CPU_INT32U sound_ip;
        GetData(&SoundIpAddrDesc, &sound_ip, 0, DATA_FLAG_SYSTEM_INDEX);    
        if (HostMusicPlay(sound_ip, file_index) >= 0)
        {
            player_conn = 1;
        }
        else
        {
            player_conn = 0;
        }
    }
}
