OSDN Git Service

First commitment for the BlackTank LPC1769.
[blacktank/blacktank.git] / task_menu.c
1 /**
2  * @file task_menu.c
3  * @author Shinichiro Nakamura
4  * @brief メニュータスクの実装(task_menu)
5  * @details
6  * メニュータスクはユーザにシステムのサービスを提示し、
7  * ユーザからの要求をシステムに伝達する役目を果たす。
8  * ユーザからの入力はそれらを管理するタスクからの通知に依存する。
9  */
10
11 #include <LPC17xx.h>
12 #include <kernel.h>
13 #include <t_syslog.h>
14
15 #include "kernel_cfg.h"
16 #include "task_menu.h"
17 #include "task_led.h"
18 #include "task_display.h"
19 #include "task_audio.h"
20 #include "oled.h"
21 #include "config.h"
22
23 #define MSG_DEVICE(n) (((n) & 0xF000) >> 12)
24 #define MSG_VALUE(n)  (((n) & 0x0FFF) >>  0)
25
26 /*
27  * メニュータスクの雛形。
28  * 簡単に階層化ができる。
29  */
30
31 typedef enum {
32     PAGE_TOP,
33     PAGE_100,
34     PAGE_200,
35     PAGE_300,
36     PAGE_VER
37 } PAGEID;
38
39 typedef enum {
40     PAGE_IN,
41     PAGE_TICK,
42     PAGE_OUT
43 } ACTION;
44
45 typedef struct {
46     PAGEID curr_page;
47     PAGEID next_page[4];
48     void (*func)(ACTION act);
49 } menu_t;
50
51 static PAGEID curr_page = PAGE_TOP;
52
53 typedef struct {
54     int val[4];
55 } menu_work_t;
56
57 menu_work_t menu_work;
58
59 #define DISP_MENUNAME(NAME) \
60     do { \
61         TSKAPI_DISPLAY_FILLBOX(0, 0, OLED_X - 1, 8, \
62                 0x00, 0x00, 0x00, \
63                 0x00, 0x00, 0x00); \
64         TSKAPI_DISPLAY_TEXT(0, 0, 0xFF, 0xFF, 0xFF, (NAME)); \
65     } while(0)
66
67 #define DISP_MENUTAG(A,B,C,D) \
68     do { \
69         TSKAPI_DISPLAY_FILLBOX(0, 52, OLED_X - 1, OLED_Y - 1, \
70                 0x00, 0x00, 0x00, \
71                 0x00, 0x00, 0x00); \
72         TSKAPI_DISPLAY_TEXT(2 + (24 * 0), 52, 0xFF, 0xFF, 0xFF, (A)); \
73         TSKAPI_DISPLAY_TEXT(2 + (24 * 1), 52, 0xFF, 0xFF, 0xFF, (B)); \
74         TSKAPI_DISPLAY_TEXT(2 + (24 * 2), 52, 0xFF, 0xFF, 0xFF, (C)); \
75         TSKAPI_DISPLAY_TEXT(2 + (24 * 3), 52, 0xFF, 0xFF, 0xFF, (D)); \
76     } while(0)
77
78 void page_splash(ACTION act)
79 {
80     /* 他のタスクが初期化状態を表示するため
81      * このタスクでは何も表示しない。
82      */
83 }
84
85 void page_top(ACTION act)
86 {
87     if (act == PAGE_IN) {
88         TSKAPI_DISPLAY_CLEAR(0x00, 0x00, 0x00);
89         DISP_MENUNAME("[TOP]");
90         DISP_MENUTAG("M-1", "M-2", "M-3", "VER");
91     }
92     if (act == PAGE_TICK) {
93         int i;
94         for (i = 0; i < 4; i++) {
95             static const int MAXVAL = (1023/ 32);
96             static const int XOFS = 10;
97             static const int YOFS = 18;
98             int val = MAXVAL - (menu_work.val[i] / 32);
99             TSKAPI_DISPLAY_FILLBOX(
100                     XOFS + i * 20, YOFS + 0,
101                     XOFS + i * 20 + 10, YOFS + val,
102                     0x00, 0x00, 0x00,
103                     0x00, 0x00, 0x00);
104             TSKAPI_DISPLAY_FILLBOX(
105                     XOFS + i * 20, YOFS + val,
106                     XOFS + i * 20 + 10, YOFS + MAXVAL,
107                     0xFF, 0xFF, 0xFF,
108                     0xFF, 0xFF, 0xFF);
109         }
110         if (!TASK_AUDIO_ENABLED()) {
111             TSKAPI_DISPLAY_TEXT(10, 8, 0xFF, 0xFF, 0xFF, "AUDIO DISABLED");
112         }
113     }
114     if (act == PAGE_OUT) {
115         TSKAPI_DISPLAY_CLEAR(0x00, 0x00, 0x00);
116     }
117 }
118
119 void page_100(ACTION act)
120 {
121     if (act == PAGE_IN) {
122         TSKAPI_DISPLAY_CLEAR(0x00, 0x00, 0x00);
123         DISP_MENUNAME("[MENU-1]");
124         TSKAPI_DISPLAY_TEXT(20, 30, 0xFF, 0xFF, 0xFF, "-- MENU 1 --");
125         DISP_MENUTAG("", "", "", "RET");
126     }
127     if (act == PAGE_OUT) {
128         TSKAPI_DISPLAY_CLEAR(0x00, 0x00, 0x00);
129     }
130 }
131
132 void page_200(ACTION act)
133 {
134     if (act == PAGE_IN) {
135         TSKAPI_DISPLAY_CLEAR(0x00, 0x00, 0x00);
136         DISP_MENUNAME("[MENU-2]");
137         TSKAPI_DISPLAY_TEXT(20, 30, 0xFF, 0xFF, 0xFF, "-- MENU 2 --");
138         DISP_MENUTAG("", "", "", "RET");
139     }
140     if (act == PAGE_OUT) {
141         TSKAPI_DISPLAY_CLEAR(0x00, 0x00, 0x00);
142     }
143 }
144
145 void page_300(ACTION act)
146 {
147     if (act == PAGE_IN) {
148         TSKAPI_DISPLAY_CLEAR(0x00, 0x00, 0x00);
149         DISP_MENUNAME("[MENU-3]");
150         TSKAPI_DISPLAY_TEXT(20, 30, 0xFF, 0xFF, 0xFF, "-- MENU 3 --");
151         DISP_MENUTAG("", "", "", "RET");
152     }
153     if (act == PAGE_OUT) {
154         TSKAPI_DISPLAY_CLEAR(0x00, 0x00, 0x00);
155     }
156 }
157
158 void page_ver(ACTION act)
159 {
160     if (act == PAGE_IN) {
161         TSKAPI_DISPLAY_CLEAR(0x00, 0x00, 0x00);
162         DISP_MENUNAME("[Version]");
163         TSKAPI_DISPLAY_TEXT(20, 30, 0xFF, 0xFF, 0xFF, "Preliminary");
164         DISP_MENUTAG("", "", "", "RET");
165     }
166     if (act == PAGE_OUT) {
167         TSKAPI_DISPLAY_CLEAR(0x00, 0x00, 0x00);
168     }
169 }
170
171 static const menu_t menu[6] = {
172     {PAGE_TOP, {PAGE_100, PAGE_200, PAGE_300, PAGE_VER}, page_top},
173     {PAGE_100, {PAGE_100, PAGE_100, PAGE_100, PAGE_TOP}, page_100},
174     {PAGE_200, {PAGE_200, PAGE_200, PAGE_200, PAGE_TOP}, page_200},
175     {PAGE_300, {PAGE_300, PAGE_300, PAGE_300, PAGE_TOP}, page_300},
176     {PAGE_VER, {PAGE_VER, PAGE_VER, PAGE_VER, PAGE_TOP}, page_ver}
177 };
178
179 void execute_pagefunc(PAGEID page, ACTION act)
180 {
181     int i;
182     for (i = 0; i < sizeof(menu) / sizeof(menu[0]); i++) {
183         if (menu[i].curr_page == page) {
184             if (menu[i].func != NULL) {
185                 menu[i].func(act);
186                 return;
187             }
188         }
189     }
190 }
191
192 PAGEID get_next_page(PAGEID page, int sw)
193 {
194     int i;
195     for (i = 0; i < sizeof(menu) / sizeof(menu[0]); i++) {
196         if (menu[i].curr_page == page) {
197             return menu[i].next_page[sw];
198         }
199     }
200     return page;
201 }
202
203 void splash(void)
204 {
205     static const int XOFS = 5;
206     static const int YOFS = 10;
207     static const int YSTP = 12;
208
209     TSKAPI_DISPLAY_CLEAR(0x00, 0x00, 0x00);
210     TSKAPI_DISPLAY_BMPFILE("0:LOGO.BMP");
211     tslp_tsk(2000);
212
213     TSKAPI_DISPLAY_CLEAR(0x00, 0x00, 0x00);
214     TSKAPI_DISPLAY_TEXT(XOFS + 0, YOFS + YSTP * 0,
215             0xFF, 0xFF, 0xFF, "Special thanks to");
216     TSKAPI_DISPLAY_TEXT(XOFS + 22, YOFS + YSTP * 2,
217             0xFF, 0xFF, 0xFF, "Horie-san");
218     TSKAPI_DISPLAY_TEXT(XOFS + 20, YOFS + YSTP * 3,
219             0xFF, 0xFF, 0xFF, "Kaneko-san");
220     tslp_tsk(2000);
221 }
222
223 #define SCREEN_SAVE_COUNTER_INIT 100
224
225 void task_menu(intptr_t exinf)
226 {
227     volatile uint16_t msg;
228     volatile uint16_t screen_save = SCREEN_SAVE_COUNTER_INIT;
229
230     splash();
231
232     execute_pagefunc(curr_page, PAGE_IN);
233     while(1)
234     {
235         /*
236          * 有機ELディスプレイは焼き付けを起こしやすい。
237          * スクリーンを保護する意味で一定時間の操作がなければ
238          * 表示を消去することにした。
239          */
240         if (screen_save == 0) {
241             /*
242              * スクリーン焼き付けを防止するための描画を実行する。
243              */
244             static uint32_t color = 0;
245             TSKAPI_DISPLAY_CLEAR(
246                     (color >> 16) & 0xff,
247                     (color >>  8) & 0xff,
248                     (color >>  0) & 0xff);
249             color++;
250         } else {
251             /*
252              * ページにティックを与える。
253              * 各ページは自身が必要とする再描画を行うだろう。
254              */
255             execute_pagefunc(curr_page, PAGE_TICK);
256             /*
257              * スクリーンセーバ起動カウンタをデクリメントする。
258              */
259             screen_save--;
260         }
261
262         /*
263          * データキューの受信状態を見る。
264          * ここではポーリングして、データがなければスルーする。
265          */
266         while (prcv_dtq(DTQ_USERINPUT, (intptr_t *)&msg) == E_OK) {
267             /*
268              * スイッチイベントの受信。
269              */
270             if ((DEVICE_SW0 <= MSG_DEVICE(msg))
271                     && (MSG_DEVICE(msg) <= DEVICE_SW3)) {
272                 /*
273                  * スイッチ入力がある時にはスクリーンセーバカウンタを
274                  * 初期値にする。
275                  */
276                 if (screen_save == 0) {
277                     execute_pagefunc(curr_page, PAGE_IN);
278                 }
279                 screen_save = SCREEN_SAVE_COUNTER_INIT;
280
281                 /*
282                  * スイッチがONエッジならばページの遷移処理を実行。
283                  */
284                 if (MSG_VALUE(msg)) {
285                     PAGEID next_page = get_next_page(
286                             curr_page, MSG_DEVICE(msg));
287                     if (next_page != curr_page) {
288                         execute_pagefunc(curr_page, PAGE_OUT);
289                         curr_page = next_page;
290                         execute_pagefunc(curr_page, PAGE_IN);
291                     }
292                 }
293                 /*
294                  * 押されたスイッチのLEDを点灯させる。
295                  */
296                 switch (MSG_DEVICE(msg)) {
297                     case DEVICE_SW0:
298                         TSKAPI_LED_LEDMSG(SWLED0, MSG_VALUE(msg));
299                         break;
300                     case DEVICE_SW1:
301                         TSKAPI_LED_LEDMSG(SWLED1, MSG_VALUE(msg));
302                         break;
303                     case DEVICE_SW2:
304                         TSKAPI_LED_LEDMSG(SWLED2, MSG_VALUE(msg));
305                         break;
306                     case DEVICE_SW3:
307                         TSKAPI_LED_LEDMSG(SWLED3, MSG_VALUE(msg));
308                         break;
309                 }
310             }
311             /*
312              * ボリュームイベントの受信。
313              */
314             if ((DEVICE_VOL0 <= MSG_DEVICE(msg))
315                     && (MSG_DEVICE(msg) <= DEVICE_VOL3)) {
316                 /*
317                  * 作業用変数に与えられたレベルを格納しておく。
318                  */
319                 int ch = MSG_DEVICE(msg) - DEVICE_VOL0;
320                 menu_work.val[ch] = MSG_VALUE(msg);
321                 /*
322                  * オーディオパラメータをオーディオタスクに伝達する。
323                  */
324                 if (TASK_AUDIO_ENABLED()) {
325                     switch (MSG_DEVICE(msg)) {
326                         case DEVICE_VOL0:
327                             TSKAPI_AUDIO_PARAM(
328                                     AUDIO_PARAM_VAR0, MSG_VALUE(msg));
329                             break;
330                         case DEVICE_VOL1:
331                             TSKAPI_AUDIO_PARAM(
332                                     AUDIO_PARAM_VAR1, MSG_VALUE(msg));
333                             break;
334                         case DEVICE_VOL2:
335                             TSKAPI_AUDIO_PARAM(
336                                     AUDIO_PARAM_VAR2, MSG_VALUE(msg));
337                             break;
338                         case DEVICE_VOL3:
339                             TSKAPI_AUDIO_PARAM(
340                                     AUDIO_PARAM_VAR3, MSG_VALUE(msg));
341                             break;
342                         default:
343                             break;
344                     }
345                 }
346             }
347         }
348
349         tslp_tsk(100);
350     }
351 }
352