summaryrefslogtreecommitdiff
path: root/app/head_task/head_task.c
blob: db693f776dae3501fb566588047f93fd002db1ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
#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"
#include "stm32f0xx_rtc.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 )
{
    RTC_TimeTypeDef RTC_TimeStructure;

    /* Get the current Time */
    RTC_GetTime(RTC_Format_BCD, &RTC_TimeStructure);
    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;

   // - при этом нужно постоянно слать текущее время на вывод, то есть
   //   при настройке времени оно тикает как в обычном режиме, только
   //   пользователь может его изменять при этом

   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 );
            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();
}


// ----------------------------------------------------------------------------
//
// ----------------------------------------------------------------------------

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


// ----------------------------------------------------------------------------
//
// ----------------------------------------------------------------------------
void SetTime ( DataToIndicate_t* indic_data )
{
  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;
    }
}


// ----------------------------------------------------------------------------
//
// ----------------------------------------------------------------------------

void ChangeValue ( uint8_t increase, uint8_t *data, uint8_t limit )
{

   if ( increase )
   {
      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 ();
}