#include "head_task.h" // FreeRTOS includes #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "semphr.h" #include "ltimers.h" #include "indicate_modes_task.h" #include "nixie_driver_process.h" #include "button_handler.h" // Номера функций меню typedef enum { MENU_FUNC_SIMPLE_TIME_VIEW = 0, MENU_ADJ_TIME, MAX_MENU_FUNCTIONS } MenuFunctionsNums_t; // Состояния режима меню AdjTime typedef enum { STATE_MENU_ADJ_TIME_START, STATE_MENU_ADJ_TIME_TIMER_OUT } MenuAdjTimeStates_t; static MenuFunctionsNums_t curr_menu_func = MENU_FUNC_SIMPLE_TIME_VIEW; // Прототипы функций меню static void MenuFunc_SimpleTimeView ( void ); static void MenuFunc_AdjTime ( void ); // Массив указателей на функции-меню typedef void ( *MenuFunctions_t ) ( void ); static const MenuFunctions_t MenuFunctions[MAX_MENU_FUNCTIONS] = { MenuFunc_SimpleTimeView, MenuFunc_AdjTime }; void GetCurrTime ( DataToIndicate_t* indic_data ); void SetTime ( DataToIndicate_t* indic_data ); void AdjTimeChangeTube ( ButtonCombName_t but_comb_name, uint8_t *position ); void AdjTimeChangeValue ( ButtonCombName_t but_comb_name, IndicModesMsgBlink_t* data, uint8_t position_mask ); void ChangeValue ( uint8_t increase, uint8_t *data, uint8_t limit ); DataToIndicate_t indic_data; extern QueueHandle_t queue_data_to_indic; // indicate_modes_task.c extern QueueHandle_t queue_but_comb; // button_handler.c extern QueueHandle_t queue_data_to_blink_mode; QueueHandle_t queue_switch_indic_mode; static MenuAdjTimeStates_t state_adj_time = STATE_MENU_ADJ_TIME_START; // ---------------------------------------------------------------------------- // // ---------------------------------------------------------------------------- void HeadTaskInit ( void ) { queue_switch_indic_mode = xQueueCreate ( 1, sizeof (IndicModesNums_t) ); configASSERT( queue_switch_indic_mode ); curr_menu_func = MENU_FUNC_SIMPLE_TIME_VIEW; } // ---------------------------------------------------------------------------- // // ---------------------------------------------------------------------------- void MenuFunc_SimpleTimeView ( void ) { //static uint8_t prev_time = 0; //static uint8_t curr_time = 1; RTC_TimeTypeDef RTC_TimeStructure; /* Get the current Time */ RTC_GetTime(RTC_Format_BCD, &RTC_TimeStructure); // curr_time = RTC_TimeStructure.RTC_Seconds; // // if ( prev_time != curr_time ) // { // prev_time = curr_time; // GetCurrTime ( &indic_data ); xQueueSend ( queue_data_to_indic, &indic_data, 0 ); // } } // ---------------------------------------------------------------------------- // Ф-я-меню настройки времени // ---------------------------------------------------------------------------- void MenuFunc_AdjTime ( void ) { static const uint32_t TIME_ADJ_OUT = 5000; //ms static IndicModesMsgBlink_t blink_data_struct; static ButtonCombName_t but_comb_name; IndicModesNums_t indic_mode_num; static uint8_t position_mask; //uint8_t prev_time = 1; //uint8_t curr_time = 0; // - при этом нужно постоянно слать текущее время на вывод, то есть // при настройке времени оно тикает как в обычном режиме, только // пользователь может его изменять при этом switch ( state_adj_time ) { case STATE_MENU_ADJ_TIME_START: indic_mode_num = INDIC_MODE_BLINK; // Отправляем сообщение на переключение режима индикации xQueueSend ( queue_switch_indic_mode, &indic_mode_num, 0 ); // Отправляем сообщение с данными для индикации // Но сначала, сотрем, вдруг прошлое собщение не было прочитано xQueueReceive ( queue_data_to_blink_mode, &blink_data_struct, 0 ); GetCurrTime ( &blink_data_struct.data ); blink_data_struct.mask_byte = 32; position_mask = blink_data_struct.mask_byte; xQueueSend ( queue_data_to_blink_mode, &blink_data_struct, 0 ); state_adj_time = STATE_MENU_ADJ_TIME_TIMER_OUT; StartLTimer ( LTIMER_MENU_ADJ_TIME_OUT ); break; case STATE_MENU_ADJ_TIME_TIMER_OUT: if ( GetLTimer (LTIMER_MENU_ADJ_TIME_OUT) >= TIME_ADJ_OUT ) { state_adj_time = STATE_MENU_ADJ_TIME_START; // Выходим из этого меню режима curr_menu_func = MENU_FUNC_SIMPLE_TIME_VIEW; indic_mode_num = INDIC_MODE_STANDART; xQueueSend ( queue_switch_indic_mode, &indic_mode_num, 0 ); // При выходе из настройки времени нужно послать сообщ. на обновление // данных в простой режим, т.к. фаза в моргающем режиме могла быть // отрицательной, а данные обновляются только раз в секунду, и поэтому // лампа может быть потухшей 1 секунду. // - тут лучше сделать завершение фазы моргания GetCurrTime ( &indic_data ); xQueueSend ( queue_data_to_indic, &indic_data, 0 ); } else { // Если жмакнули кнопушку, то сбрасываем таймер, затем смотрим // какую кнопушку жмакнули if ( pdPASS == xQueueReceive ( queue_but_comb, &but_comb_name, 0 ) ) { StartLTimer ( LTIMER_MENU_ADJ_TIME_OUT ); // Тут в зависимости от того, какую кнопушку жмакнули switch ( but_comb_name ) { case BUTTON_SINGLE_FORWARD: case BUTTON_SINGLE_BACKWARD: // Меняем позицию времени AdjTimeChangeTube (but_comb_name, &position_mask); GetCurrTime ( &blink_data_struct.data ); blink_data_struct.mask_byte = position_mask; xQueueSend ( queue_data_to_blink_mode, &blink_data_struct, 0 ); break; case BUTTON_HOLD_FORWARD: case BUTTON_HOLD_BACKWARD: // Меняем значение времени GetCurrTime ( &blink_data_struct.data ); AdjTimeChangeValue ( but_comb_name, &blink_data_struct, position_mask ); SetTime ( &blink_data_struct.data ); xQueueSend ( queue_data_to_blink_mode, &blink_data_struct, 0 ); break; default: break; } } else { // - тут, если время изменилось, то отправляем его на вывод GetCurrTime ( &blink_data_struct.data ); //curr_time = blink_data_struct.data.indic_6; //if ( curr_time != prev_time ) //{ // prev_time = curr_time; xQueueSend ( queue_data_to_blink_mode, &blink_data_struct, 0 ); //} } } break; default: break; } } // ---------------------------------------------------------------------------- // // ---------------------------------------------------------------------------- void ProcessFSM_Head ( void ) { // - тут можно совершать внешние переключения функций меню: // - ловить сообщения от внешних источников для перехода в нужный пункт // меню (сообщения от gps модуля, wifi и тд.) // 1. Ловим сообщение из модуля-обработчика нажатий кнопушек с командой // на переход в меню настройки (две кнопки зажать на 3 сек) // - перед отправкой сообщения в режим индикации сначала стираем сообщение static ButtonCombName_t but_comb_name; if ( pdPASS == xQueuePeek ( queue_but_comb, &but_comb_name, 0 ) ) { if ( but_comb_name == BUTTON_LONG ) { // - при изменении состояния меню или режима, нужно также сбрасывать // внутреннее состояние текущего режима xQueueReceive ( queue_but_comb, &but_comb_name, 0 ); curr_menu_func = MENU_ADJ_TIME; } } MenuFunctions [curr_menu_func](); taskYIELD(); } // ---------------------------------------------------------------------------- // // ---------------------------------------------------------------------------- //static DataToIndicate_t const_time; void GetCurrTime ( DataToIndicate_t *indic_data ) { RTC_TimeTypeDef RTC_TimeStructure; /* Get the current Time */ RTC_GetTime ( RTC_Format_BCD, &RTC_TimeStructure ); indic_data->indic_1 = RTC_TimeStructure.RTC_Hours>>4; indic_data->indic_2 = RTC_TimeStructure.RTC_Hours&0x0F; indic_data->indic_3 = RTC_TimeStructure.RTC_Minutes>>4; indic_data->indic_4 = RTC_TimeStructure.RTC_Minutes&0x0F; indic_data->indic_5 = RTC_TimeStructure.RTC_Seconds>>4; indic_data->indic_6 = RTC_TimeStructure.RTC_Seconds&0x0F; // indic_data->indic_1 = const_time.indic_1; // indic_data->indic_2 = const_time.indic_2; // // indic_data->indic_3 = const_time.indic_3; // indic_data->indic_4 = const_time.indic_4; // // indic_data->indic_5 = const_time.indic_5; // indic_data->indic_6 = const_time.indic_6; } // ---------------------------------------------------------------------------- // // ---------------------------------------------------------------------------- void SetTime ( DataToIndicate_t* indic_data ) { // const_time.indic_1 = indic_data->indic_1; // const_time.indic_2 = indic_data->indic_2; // const_time.indic_3 = indic_data->indic_3; // const_time.indic_4 = indic_data->indic_4; // const_time.indic_5 = indic_data->indic_5; // const_time.indic_6 = indic_data->indic_6; RTC_TimeTypeDef RTC_TimeStructure; RTC_TimeStructure.RTC_Hours = indic_data->indic_1 << 4; RTC_TimeStructure.RTC_Hours |= indic_data->indic_2 & 0x0F; RTC_TimeStructure.RTC_Minutes = indic_data->indic_3 << 4; RTC_TimeStructure.RTC_Minutes |= indic_data->indic_4 & 0x0F; RTC_TimeStructure.RTC_Seconds = indic_data->indic_5 << 4; RTC_TimeStructure.RTC_Seconds |= indic_data->indic_6 & 0x0F; RTC_SetTime ( RTC_Format_BCD, &RTC_TimeStructure ); } // ---------------------------------------------------------------------------- // Ф-я изменения текущего положения моргающей лампы при настройке времени // Ф-я вызывается из MenuFunc_AdjTime // Номер лампы соотносится с номером лампы ( левый бит - нулевой, и лампа тоже ) // ---------------------------------------------------------------------------- void AdjTimeChangeTube ( ButtonCombName_t but_comb_name, uint8_t *position_mask ) { if ( but_comb_name == BUTTON_SINGLE_FORWARD ) { if ( !(*position_mask & ( 1 << 0 )) ) { *position_mask >>= 1; } else { *position_mask = 32; } // 0010 0000 } else { if ( *position_mask & ( 1 << 5 ) ) { *position_mask = 1; } else { *position_mask <<= 1; } } } // ---------------------------------------------------------------------------- // Ф-я изменения значения цифры в текущем положении // То есть тут настраиваем время "поцифирно" // ---------------------------------------------------------------------------- void AdjTimeChangeValue ( ButtonCombName_t but_comb_name, IndicModesMsgBlink_t *data_struct, uint8_t position_mask ) { uint8_t increase; if ( but_comb_name == BUTTON_HOLD_FORWARD ) { increase = 1; } else { increase = 0; } switch ( position_mask & 0x3F ) { case 0x01: // Секунды единицы ChangeValue ( increase, &data_struct->data.indic_6, 9 ); break; case 0x04: // Минуты единицы ChangeValue ( increase, &data_struct->data.indic_4, 9 ); break; case 0x02: // Секунды десятки ChangeValue ( increase, &data_struct->data.indic_5, 5 ); break; case 0x08: // Минуты десятки ChangeValue ( increase, &data_struct->data.indic_3, 5 ); break; case 0x10: // Часы единицы if ( data_struct->data.indic_1 == 2 ) { ChangeValue ( increase, &data_struct->data.indic_2, 3 ); } else { ChangeValue ( increase, &data_struct->data.indic_2, 9 ); } break; case 0x20: // Часы десятки if ( data_struct->data.indic_2 <= 3 ) { ChangeValue ( increase, &data_struct->data.indic_1, 2 ); } else { ChangeValue ( increase, &data_struct->data.indic_1, 1 ); } break; } } // ---------------------------------------------------------------------------- // // ---------------------------------------------------------------------------- //static uint8_t temp; void ChangeValue ( uint8_t increase, uint8_t *data, uint8_t limit ) { //temp = *data; if ( increase ) //if ( temp ) { if ( *data < limit ) { *data += 1; } else { *data = 0; } } else { if ( *data > 0 ) { *data -= 1; } else { *data = limit; } } } // ---------------------------------------------------------------------------- // Задача ОС, реализующая головную задачу программы NixieClockSimply // ---------------------------------------------------------------------------- void Head_Task ( void *pvParameters ) { while(1)ProcessFSM_Head (); //vTaskDelete(NULL); }