diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugins/CATEGORIES | 1 | ||||
-rw-r--r-- | apps/plugins/SOURCES | 1 | ||||
-rw-r--r-- | apps/plugins/codebuster.c | 514 |
3 files changed, 516 insertions, 0 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 6809844efb..505f83bff1 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES | |||
@@ -14,6 +14,7 @@ chip8,viewers | |||
14 | chopper,games | 14 | chopper,games |
15 | clix,games | 15 | clix,games |
16 | clock,apps | 16 | clock,apps |
17 | codebuster,games | ||
17 | credits,viewers | 18 | credits,viewers |
18 | cube,demos | 19 | cube,demos |
19 | demystify,demos | 20 | demystify,demos |
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index d89b0b6e5f..82dd4b78e4 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES | |||
@@ -67,6 +67,7 @@ robotfindskitten.c | |||
67 | #ifdef HAVE_LCD_COLOR | 67 | #ifdef HAVE_LCD_COLOR |
68 | clix.c | 68 | clix.c |
69 | ppmviewer.c | 69 | ppmviewer.c |
70 | codebuster.c | ||
70 | #endif | 71 | #endif |
71 | 72 | ||
72 | /* Plugins needing the grayscale lib on low-depth LCDs */ | 73 | /* Plugins needing the grayscale lib on low-depth LCDs */ |
diff --git a/apps/plugins/codebuster.c b/apps/plugins/codebuster.c new file mode 100644 index 0000000000..edcb7e7904 --- /dev/null +++ b/apps/plugins/codebuster.c | |||
@@ -0,0 +1,514 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: | ||
9 | * | ||
10 | * Copyright (C) 2009 Clément Pit--Claudel | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "plugin.h" | ||
23 | #include "lib/configfile.h" | ||
24 | #include "lib/playback_control.h" | ||
25 | #include "lib/pluginlib_actions.h" | ||
26 | |||
27 | PLUGIN_HEADER | ||
28 | |||
29 | /* Limits */ | ||
30 | #define MAX_PIECES_COUNT 5 | ||
31 | #define MAX_COLORS_COUNT 8 | ||
32 | #define MAX_GUESSES_COUNT 10 | ||
33 | |||
34 | const struct button_mapping *plugin_contexts[] = | ||
35 | {generic_directions, generic_actions}; | ||
36 | |||
37 | /* Mapping */ | ||
38 | #define EXIT PLA_QUIT | ||
39 | #define VALIDATE PLA_FIRE | ||
40 | #define PREV_PIECE PLA_LEFT | ||
41 | #define PREV_PIECE_REPEAT PLA_LEFT_REPEAT | ||
42 | #define NEXT_PIECE PLA_RIGHT | ||
43 | #define NEXT_PIECE_REPEAT PLA_RIGHT_REPEAT | ||
44 | #define PREV_COLOR PLA_UP | ||
45 | #define PREV_COLOR_REPEAT PLA_UP_REPEAT | ||
46 | #define NEXT_COLOR PLA_DOWN | ||
47 | #define NEXT_COLOR_REPEAT PLA_DOWN_REPEAT | ||
48 | |||
49 | /* | ||
50 | * Screen structure: | ||
51 | * * (guesses_count) lines of guesses, | ||
52 | * * 1 center line of solution (hidden), | ||
53 | * * 1 line showing available colors. | ||
54 | * | ||
55 | * Status vars: | ||
56 | * * quit: exit the plugin | ||
57 | * * leave: restart the plugin (leave the current game) | ||
58 | * * game_ended: the game has ended | ||
59 | * * found: the combination has been found | ||
60 | * | ||
61 | * Colors used are taken from the Tango project. | ||
62 | * | ||
63 | * Due to integer truncations, 2 vars are used for some objects' dimensions | ||
64 | * (eg. true_guess_w, true_score_w). The actual dimension of these objects is | ||
65 | * stored in the corresponding var. without the "true" prefix. | ||
66 | */ | ||
67 | |||
68 | struct mm_score { | ||
69 | int correct; | ||
70 | int misplaced; | ||
71 | }; | ||
72 | |||
73 | struct mm_line { | ||
74 | struct mm_score score; | ||
75 | int pieces[MAX_PIECES_COUNT]; | ||
76 | }; | ||
77 | |||
78 | const int colors[MAX_COLORS_COUNT] = { | ||
79 | LCD_RGBPACK(252, 233, 79), | ||
80 | LCD_RGBPACK(206, 92, 0), | ||
81 | LCD_RGBPACK(143, 89, 2), | ||
82 | LCD_RGBPACK( 78, 154, 6), | ||
83 | /* LCD_RGBPACK( 32, 74, 135), */ | ||
84 | LCD_RGBPACK( 52, 101, 164), | ||
85 | /* LCD_RGBPACK(114, 159, 207), */ | ||
86 | LCD_RGBPACK(117, 80, 123), | ||
87 | /* LCD_RGBPACK(173, 127, 168), */ | ||
88 | LCD_RGBPACK(164, 0, 0), | ||
89 | LCD_RGBPACK(238, 238, 236), | ||
90 | }; | ||
91 | |||
92 | /* Flags */ | ||
93 | static bool quit, leave, usb; | ||
94 | static bool found, game_ended; | ||
95 | |||
96 | /* Settings */ | ||
97 | static int pieces_count; | ||
98 | static int colors_count; | ||
99 | static int guesses_count; | ||
100 | static int pieces_tmp = 5; | ||
101 | static int colors_tmp = 7; | ||
102 | static int guesses_tmp = 10; | ||
103 | static bool labeling = false, framing = false; | ||
104 | |||
105 | /* Display */ | ||
106 | #define ALUMINIUM LCD_RGBPACK(136, 138, 133) | ||
107 | |||
108 | #define MARGIN 5 | ||
109 | #define X_MARGIN (LCD_WIDTH / 20) | ||
110 | #define Y_MARGIN (LCD_HEIGHT / 20) | ||
111 | #define GAME_H (LCD_HEIGHT - (2 * Y_MARGIN)) | ||
112 | #define LINE_W (LCD_WIDTH - (2 * X_MARGIN)) | ||
113 | |||
114 | #define CONFIG_FILE_NAME "codebuster.cfg" | ||
115 | |||
116 | static struct configdata config[] = { | ||
117 | {TYPE_INT, 0, MAX_PIECES_COUNT, { .int_p = &pieces_tmp }, "pieces", NULL}, | ||
118 | {TYPE_INT, 0, MAX_COLORS_COUNT, { .int_p = &colors_tmp }, "colors", NULL}, | ||
119 | {TYPE_INT, 0, MAX_GUESSES_COUNT, { .int_p = &guesses_tmp }, "guesses", NULL}, | ||
120 | {TYPE_BOOL, 0, 1, { .bool_p = &labeling }, "labeling", NULL}, | ||
121 | {TYPE_BOOL, 0, 1, { .bool_p = &framing }, "framing", NULL}, | ||
122 | }; | ||
123 | static bool settings_changed = false; | ||
124 | |||
125 | static int line_h; | ||
126 | static int piece_w, tick_w; | ||
127 | static int true_guess_w, true_score_w, guess_w, score_w; | ||
128 | |||
129 | /* Guesses and solution */ | ||
130 | struct mm_line solution, hidden; | ||
131 | struct mm_line guesses[MAX_GUESSES_COUNT]; | ||
132 | |||
133 | /* Alias for pluginlib_getaction */ | ||
134 | static inline int get_button(void) { | ||
135 | return pluginlib_getaction(TIMEOUT_BLOCK, plugin_contexts, 2); | ||
136 | } | ||
137 | |||
138 | /* Computes the margin to center an element */ | ||
139 | static inline int get_margin(int width, int full_w) { | ||
140 | return ((full_w - width) / 2); | ||
141 | } | ||
142 | |||
143 | static inline bool stop_game(void) { | ||
144 | return (quit || leave || found); | ||
145 | } | ||
146 | |||
147 | static void fill_color_rect(int x, int y, int w, int h, int color) { | ||
148 | rb->lcd_set_foreground(color); | ||
149 | rb->lcd_fillrect(x, y, w, h); | ||
150 | rb->lcd_set_foreground(LCD_WHITE); | ||
151 | } | ||
152 | |||
153 | static void overfill_rect(int x, int y, int w, int h) { | ||
154 | rb->lcd_fillrect(x - 2, y - 2, w + 4, h + 4); | ||
155 | } | ||
156 | |||
157 | static void draw_piece(int x, int y, int w, int h, int color_id, bool emph) { | ||
158 | int color = LCD_BLACK; | ||
159 | |||
160 | if (color_id >= 0) | ||
161 | color = colors[color_id]; | ||
162 | else if (color_id == -2) /* Hidden piece */ | ||
163 | color = ALUMINIUM; | ||
164 | |||
165 | if (emph) | ||
166 | overfill_rect(x, y, w, h); | ||
167 | |||
168 | if (color_id == -1) /* Uninitialised color */ | ||
169 | rb->lcd_drawrect(x, y, w, h); | ||
170 | else | ||
171 | fill_color_rect(x, y, w, h, color); | ||
172 | |||
173 | if (!emph && framing) | ||
174 | rb->lcd_drawrect(x, y, w, h); | ||
175 | |||
176 | if (labeling && color_id >= 0) { | ||
177 | char text[2]; | ||
178 | rb->snprintf(text, 2, "%d", color_id); | ||
179 | |||
180 | int fw, fh; rb->font_getstringsize(text, &fw, &fh, FONT_SYSFIXED); | ||
181 | rb->lcd_putsxy(x + get_margin(fw, w), y + get_margin(fh, h), text); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | /* Compute the score for a given guess (expressed in ticks) */ | ||
186 | static void validate_guess(struct mm_line* guess) { | ||
187 | bool solution_match[pieces_count]; | ||
188 | bool guess_match[pieces_count]; | ||
189 | |||
190 | guess->score.misplaced = 0; | ||
191 | guess->score.correct = 0; | ||
192 | |||
193 | int guess_pos; | ||
194 | |||
195 | /* Initialisation with 0s */ | ||
196 | for (guess_pos = 0; guess_pos < pieces_count; guess_pos++) | ||
197 | solution_match[guess_pos] = guess_match[guess_pos] = false; | ||
198 | |||
199 | /* 1st step : detect correctly positioned pieces */ | ||
200 | for (guess_pos = 0; guess_pos < pieces_count; guess_pos++) { | ||
201 | if (solution.pieces[guess_pos] == guess->pieces[guess_pos]) { | ||
202 | guess->score.correct += 1; | ||
203 | |||
204 | guess_match[guess_pos] = solution_match[guess_pos] | ||
205 | = true; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | /* Second step : detect mispositioned pieces */ | ||
210 | for (guess_pos = 0; guess_pos < pieces_count; guess_pos++) { | ||
211 | if (guess_match[guess_pos]) continue; | ||
212 | |||
213 | int sol_pos; | ||
214 | for (sol_pos = 0; sol_pos < pieces_count; sol_pos++) { | ||
215 | if (guess_match[guess_pos]) break; | ||
216 | if (solution_match[sol_pos]) continue; | ||
217 | |||
218 | if (guess->pieces[guess_pos] == solution.pieces[sol_pos]) { | ||
219 | guess->score.misplaced += 1; | ||
220 | |||
221 | solution_match[sol_pos] = true; | ||
222 | break; | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | |||
228 | static void draw_guess(int line, struct mm_line* guess, int cur_guess, | ||
229 | int cur_piece, bool show_score) { | ||
230 | int cur_y = (Y_MARGIN + MARGIN) + 2 * line_h * line; | ||
231 | int l_margin = X_MARGIN + (show_score ? 0 : get_margin(guess_w, LINE_W)); | ||
232 | |||
233 | int piece; | ||
234 | for (piece = 0; piece < pieces_count; piece++) { | ||
235 | int cur_x = l_margin + 2 * piece_w * piece; | ||
236 | draw_piece(cur_x, cur_y, piece_w, line_h, guess->pieces[piece], | ||
237 | line == cur_guess && piece == cur_piece); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | static void draw_score(int line, struct mm_line* guess) { | ||
242 | int cur_y = Y_MARGIN + 2 * line_h * line; | ||
243 | int l_margin = X_MARGIN + true_guess_w + MARGIN; | ||
244 | |||
245 | int tick = 0; | ||
246 | for (; tick < guess->score.correct; tick++) { | ||
247 | int cur_x = l_margin + 2 * tick_w * tick; | ||
248 | |||
249 | fill_color_rect(cur_x, cur_y, tick_w, line_h, LCD_RGBPACK(239, 41, 41)); | ||
250 | } | ||
251 | |||
252 | for (; tick < guess->score.correct + guess->score.misplaced; tick++) { | ||
253 | int cur_x = l_margin + 2 * tick_w * tick; | ||
254 | |||
255 | fill_color_rect(cur_x, cur_y, tick_w, line_h, LCD_RGBPACK(211, 215, 207)); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | static void draw_board(int cur_guess, int cur_piece) { | ||
260 | rb->lcd_clear_display(); | ||
261 | |||
262 | int line = 0; | ||
263 | for (; line < guesses_count; line++) { | ||
264 | draw_guess(line, &guesses[line], cur_guess, cur_piece, true); | ||
265 | if (line < cur_guess) draw_score(line, &guesses[line]); | ||
266 | } | ||
267 | |||
268 | int color; | ||
269 | int colors_margin = 2; | ||
270 | int cur_y = (Y_MARGIN + MARGIN) + 2 * line_h * line; | ||
271 | int color_w = (LINE_W - colors_margin * (colors_count - 1)) / colors_count; | ||
272 | |||
273 | for (color = 0; color < colors_count; color++) { | ||
274 | int cur_x = X_MARGIN + color * (color_w + colors_margin); | ||
275 | draw_piece(cur_x, cur_y, color_w, line_h, color, | ||
276 | color == guesses[cur_guess].pieces[cur_piece]); | ||
277 | } | ||
278 | |||
279 | line++; | ||
280 | |||
281 | if(game_ended) | ||
282 | draw_guess(line, &solution, cur_guess, cur_piece, false); | ||
283 | else | ||
284 | draw_guess(line, &hidden, cur_guess, cur_piece, false); | ||
285 | |||
286 | rb->lcd_update(); | ||
287 | } | ||
288 | |||
289 | static void init_vars(void) { | ||
290 | quit = leave = usb = found = game_ended = false; | ||
291 | |||
292 | int guess, piece; | ||
293 | for (guess = 0; guess < guesses_count; guess++) { | ||
294 | for (piece = 0; piece < pieces_count; piece++) | ||
295 | guesses[guess].pieces[piece] = -1; | ||
296 | } | ||
297 | for (piece = 0; piece < pieces_count; piece++) { | ||
298 | guesses[0].pieces[piece] = 0; | ||
299 | hidden.pieces[piece] = -2; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | static void init_board(void) { | ||
304 | |||
305 | pieces_count = pieces_tmp; | ||
306 | colors_count = colors_tmp; | ||
307 | guesses_count = guesses_tmp; | ||
308 | |||
309 | line_h = GAME_H / (2 * (guesses_count + 2) - 1); | ||
310 | |||
311 | true_score_w = LINE_W * 0.25; | ||
312 | true_guess_w = LINE_W - (true_score_w + MARGIN); | ||
313 | |||
314 | tick_w = true_score_w / (2 * pieces_count - 1); | ||
315 | piece_w = true_guess_w / (2 * pieces_count - 1); | ||
316 | |||
317 | /* Readjust (due to integer divisions) */ | ||
318 | score_w = tick_w * (2 * pieces_count - 1); | ||
319 | guess_w = piece_w * (2 * pieces_count - 1); | ||
320 | } | ||
321 | |||
322 | static void randomize_solution(void) { | ||
323 | int piece_id; | ||
324 | for (piece_id = 0; piece_id < pieces_count; piece_id++) | ||
325 | solution.pieces[piece_id] = rb->rand() % colors_count; | ||
326 | } | ||
327 | |||
328 | static void settings_menu(void) { | ||
329 | MENUITEM_STRINGLIST(settings_menu, "Settings", NULL, | ||
330 | "Number of colors", "Number of pieces", | ||
331 | "Number of guesses", "Labels ?", "Frames ?"); | ||
332 | |||
333 | int cur_item =0; | ||
334 | |||
335 | bool menu_quit = false; | ||
336 | while(!menu_quit) { | ||
337 | |||
338 | switch(rb->do_menu(&settings_menu, &cur_item, NULL, false)) { | ||
339 | case 0: | ||
340 | rb->set_int("Number of colors", "", UNIT_INT, &colors_tmp, | ||
341 | NULL, -1, MAX_COLORS_COUNT, 1, NULL); | ||
342 | break; | ||
343 | case 1: | ||
344 | rb->set_int("Number of pieces", "", UNIT_INT, &pieces_tmp, | ||
345 | NULL, -1, MAX_PIECES_COUNT, 1, NULL); | ||
346 | break; | ||
347 | case 2: | ||
348 | rb->set_int("Number of guesses", "", UNIT_INT, &guesses_tmp, | ||
349 | NULL, -1, MAX_GUESSES_COUNT, 1, NULL); | ||
350 | break; | ||
351 | case 3: | ||
352 | rb->set_bool("Display labels ?", &labeling); | ||
353 | break; | ||
354 | case 4: | ||
355 | rb->set_bool("Display frames ?", &framing); | ||
356 | break; | ||
357 | case GO_TO_PREVIOUS: | ||
358 | menu_quit = true; | ||
359 | break; | ||
360 | default: | ||
361 | break; | ||
362 | } | ||
363 | } | ||
364 | } | ||
365 | |||
366 | static bool resume; | ||
367 | static int menu_cb(int action, const struct menu_item_ex *this_item) | ||
368 | { | ||
369 | int i = ((intptr_t)this_item); | ||
370 | if ((action == ACTION_REQUEST_MENUITEM) && (!resume && (i==0))) | ||
371 | return ACTION_EXIT_MENUITEM; | ||
372 | return action; | ||
373 | } | ||
374 | |||
375 | static void main_menu(void) { | ||
376 | MENUITEM_STRINGLIST(main_menu, "Codebuster Menu", menu_cb, | ||
377 | "Resume Game", "Start New Game", "Settings", | ||
378 | "Playback Control", "Quit"); | ||
379 | |||
380 | int cur_item =0; | ||
381 | |||
382 | bool menu_quit = false; | ||
383 | while(!menu_quit) { | ||
384 | |||
385 | switch(rb->do_menu(&main_menu, &cur_item, NULL, false)) { | ||
386 | case 0: | ||
387 | resume = true; | ||
388 | menu_quit = true; | ||
389 | break; | ||
390 | case 1: | ||
391 | leave = true; | ||
392 | menu_quit = true; | ||
393 | break; | ||
394 | case 2: | ||
395 | settings_menu(); | ||
396 | settings_changed = true; | ||
397 | break; | ||
398 | case 3: | ||
399 | playback_control(NULL); | ||
400 | break; | ||
401 | case 4: | ||
402 | quit = menu_quit = true; | ||
403 | break; | ||
404 | case MENU_ATTACHED_USB: | ||
405 | usb = menu_quit = true; | ||
406 | break; | ||
407 | default: | ||
408 | break; | ||
409 | } | ||
410 | } | ||
411 | } | ||
412 | |||
413 | enum plugin_status plugin_start(const void* parameter) { | ||
414 | (void)parameter; | ||
415 | |||
416 | rb->srand(*rb->current_tick); | ||
417 | rb->lcd_setfont(FONT_SYSFIXED); | ||
418 | rb->lcd_set_backdrop(NULL); | ||
419 | rb->lcd_set_foreground(LCD_WHITE); | ||
420 | rb->lcd_set_background(LCD_BLACK); | ||
421 | |||
422 | configfile_load(CONFIG_FILE_NAME,config,5,0); | ||
423 | |||
424 | main_menu(); | ||
425 | while (!quit) { | ||
426 | init_board(); | ||
427 | randomize_solution(); | ||
428 | init_vars(); | ||
429 | |||
430 | draw_board(0, 0); | ||
431 | int button = 0, guess = 0, piece = 0; | ||
432 | for (guess = 0; guess < guesses_count && !stop_game(); guess++) { | ||
433 | while(!stop_game()) { | ||
434 | draw_board(guess, piece); | ||
435 | |||
436 | if ((button = get_button()) == VALIDATE) break; | ||
437 | |||
438 | switch (button) { | ||
439 | |||
440 | case EXIT: | ||
441 | resume = true; | ||
442 | main_menu(); | ||
443 | break; | ||
444 | |||
445 | case NEXT_PIECE: | ||
446 | case NEXT_PIECE_REPEAT: | ||
447 | piece = (piece + 1) % pieces_count; | ||
448 | break; | ||
449 | |||
450 | case PREV_PIECE: | ||
451 | case PREV_PIECE_REPEAT: | ||
452 | piece = (piece + pieces_count - 1) % pieces_count; | ||
453 | break; | ||
454 | |||
455 | |||
456 | case NEXT_COLOR: | ||
457 | case NEXT_COLOR_REPEAT: | ||
458 | guesses[guess].pieces[piece] = | ||
459 | (guesses[guess].pieces[piece] + 1) | ||
460 | % colors_count; | ||
461 | break; | ||
462 | |||
463 | case PREV_COLOR: | ||
464 | case PREV_COLOR_REPEAT: | ||
465 | guesses[guess].pieces[piece] = | ||
466 | (guesses[guess].pieces[piece] + colors_count - 1) | ||
467 | % colors_count; | ||
468 | break; | ||
469 | |||
470 | default: | ||
471 | if (rb->default_event_handler(button) == SYS_USB_CONNECTED) | ||
472 | quit = usb = true; | ||
473 | } | ||
474 | |||
475 | if (guesses[guess].pieces[piece] == -1) | ||
476 | guesses[guess].pieces[piece] = 0; | ||
477 | } | ||
478 | |||
479 | if (!quit) { | ||
480 | validate_guess(&guesses[guess]); | ||
481 | |||
482 | if (guesses[guess].score.correct == pieces_count) | ||
483 | found = true; | ||
484 | |||
485 | if (guess + 1 < guesses_count && !found) | ||
486 | guesses[guess + 1] = guesses[guess]; | ||
487 | } | ||
488 | } | ||
489 | |||
490 | game_ended = true; | ||
491 | resume = false; | ||
492 | if (!quit && !leave) { | ||
493 | draw_board(guess, piece); | ||
494 | |||
495 | if (found) | ||
496 | rb->splash(HZ, "Well done :)"); | ||
497 | else | ||
498 | rb->splash(HZ, "Wooops :("); | ||
499 | do { | ||
500 | button = rb->button_get(true); | ||
501 | if (rb->default_event_handler(button) == SYS_USB_CONNECTED) { | ||
502 | quit = usb = true; | ||
503 | } | ||
504 | } while( ( button == BUTTON_NONE ) | ||
505 | || ( button & (BUTTON_REL|BUTTON_REPEAT) ) ); | ||
506 | main_menu(); | ||
507 | } | ||
508 | } | ||
509 | if (settings_changed) | ||
510 | configfile_save(CONFIG_FILE_NAME,config,5,0); | ||
511 | |||
512 | rb->lcd_setfont(FONT_UI); | ||
513 | return (usb) ? PLUGIN_USB_CONNECTED : PLUGIN_OK; | ||
514 | } | ||