ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1
45
46#include <stddef.h>
47#include <stdint.h>
48
49#include "ra8_app.h"
50#include "ra8_board_ek_ra8d2.h"
51#include "ra8_boot_entry.h"
52#include "ra8_box.h"
53#include "ra8_cgc.h"
54#include "ra8_display_pal.h"
55#include "ra8_display_pal_lcd.h"
56#include "ra8_err.h"
57#include "ra8_gfx.h"
58#include "ra8_gfx_font.h"
59#include "ra8_glcdc.h"
60#include "ra8_isr.h"
61#include "ra8_mstp.h"
62#include "ra8_panel.h"
63#include "ra8_panel_timing.h"
64#include "ra8_port_constants.h"
65#include "ra8_port_utils.h"
66#include "ra8_time.h"
67#include "ra8_ui.h"
68#include "ra8_widget.h"
69
71#ifndef WA_APP_SETTINGS
73#define WA_APP_SETTINGS (1)
74#endif
75
81typedef enum : uint16_t {
82 k_wd_fb_w = 512U,
83 k_wd_fb_h = 512U,
86 k_wd_pad = 8U,
89} wd_geom_t;
90
96typedef enum : uint32_t {
97 k_wd_col_clear = 0x000008U,
98 k_wd_col_status_bg = 0x1E2A40U,
99 k_wd_col_tabbar_bg = 0x14141AU,
100 k_wd_col_tab_on = 0x3060C0U,
101 k_wd_col_tab_off = 0x303038U,
102 k_wd_col_text = 0xFFFFFFU,
103 k_wd_col_dim = 0xA0A0B0U,
104 k_wd_col_lib_bg = 0x102038U,
105 k_wd_col_rdr_bg = 0x382414U,
106 k_wd_col_set_bg = 0x102818U,
107} wd_color_t;
108
114typedef enum : uint16_t {
119
125typedef enum : uint16_t {
128} wd_btn_t;
129
142
148typedef enum : uint32_t {
149 k_wd_uart_baud = 115200U,
151 k_wd_fnv_offset = 2166136261U,
152 k_wd_fnv_prime = 16777619U,
158
163
168[[gnu::aligned(k_ra8_board_fb_align_bytes)]] static uint16_t
169 s_framebuffer[(uint32_t)k_wd_fb_w * (uint32_t)k_wd_fb_h];
170
176typedef struct {
177 const char* title;
178 const char* const* lines;
179 uint16_t nlines;
180 uint32_t bg;
182
188typedef struct {
191
197typedef struct {
198 ra8_widget_t widgets[k_wd_w_count];
200 uint32_t enters;
201 uint32_t leaves;
203
206static wa_chrome_t s_chrome = {.reg = &s_reg};
209#if WA_APP_SETTINGS
211#endif
212
220static volatile int16_t g_wd_request = (int16_t)k_ra8_app_none;
222static display_handle_t* s_display = nullptr;
224static bool s_was_sw1;
226static bool s_was_sw2;
227
228/* Content text for each app. */
229static const char* const k_wd_lib_lines[] = {
230 "The Time Machine H. G. Wells",
231 "Frankenstein M. Shelley",
232 "Pride and Prejudice J. Austen",
233 "Open with SW2; browse with SW1/SW2.",
234};
235static const char* const k_wd_rdr_lines[] = {
236 "Chapter 1",
237 "The Time Traveller (for so it will be",
238 "convenient to speak of him) was",
239 "expounding a recondite matter to us.",
240 " page 1/214",
241};
242#if WA_APP_SETTINGS
243static const char* const k_wd_set_lines[] = {
244 "Refresh cadence fast (A2)",
245 "Margins normal",
246 "Font 8x16 mono",
247 "This app is removable (WA_APP_SETTINGS).",
248};
249#endif
250
251static const uint8_t k_wd_msg_boot[] = "widget-app-demo: boot\r\n";
252static const uint8_t k_wd_msg_finit[] = "widget-app-demo: FAIL init\r\n";
253static const uint8_t k_wd_msg_fpanl[] = "widget-app-demo: FAIL panel\r\n";
254static const uint8_t k_wd_msg_freg[] = "widget-app-demo: FAIL register\r\n";
255static const uint8_t k_wd_msg_fchk[] = "widget-app-demo: FAIL selfcheck\r\n";
256static const uint8_t k_wd_msg_pre[] = "widget-app-demo: apps=";
257static const uint8_t k_wd_msg_lib[] = " lib=";
258static const uint8_t k_wd_msg_rdr[] = " rdr=";
259static const uint8_t k_wd_msg_route[] = " route=ok flush=512x44 hint=fast";
260static const uint8_t k_wd_msg_pass[] = " PASS\r\n";
261
262/* ===========================================================================
263 * Console
264 * ===========================================================================
265 */
266
268static void wd_print(const uint8_t* msg, uint32_t len)
269{
270 (void)ra8_board_uart_console_write(msg, (size_t)len);
271}
272
274static void wd_fail_halt(const uint8_t* msg, uint32_t len)
275{
276 wd_print(msg, len);
277 while (1) {
278 __asm__ volatile("wfi");
279 }
280}
281
283static void wd_print_hex(uint32_t value)
284{
285 uint8_t buf[k_wd_hex_nibbles];
286 for (uint32_t i = 0U; i < (uint32_t)k_wd_hex_nibbles; i++) {
287 const uint32_t shift = ((uint32_t)k_wd_hex_nibbles - 1U - i) * (uint32_t)k_wd_nibble_bits;
288 const uint32_t nib = (value >> shift) & (uint32_t)k_wd_nibble_mask;
289 buf[i] = (uint8_t)((nib < (uint32_t)k_wd_dec_ten) ? ('0' + nib) : ('A' + (nib - k_wd_dec_ten)));
290 }
291 wd_print(buf, (uint32_t)k_wd_hex_nibbles);
292}
293
295static void wd_print_uint(uint32_t value)
296{
297 uint8_t buf[k_wd_dec_ten];
298 uint32_t n = 0U;
299 if (value == 0U) {
300 buf[n] = '0';
301 n++;
302 }
303 while ((value > 0U) && (n < (uint32_t)k_wd_dec_ten)) {
304 buf[n] = (uint8_t)('0' + (value % (uint32_t)k_wd_dec_ten));
305 n++;
306 value /= (uint32_t)k_wd_dec_ten;
307 }
308 for (uint32_t i = 0U; i < n; i++) {
309 wd_print(&buf[n - 1U - i], 1U);
310 }
311}
312
314static uint32_t wd_framebuffer_hash(void)
315{
316 const uint8_t* p = (const uint8_t*)s_framebuffer;
317 const size_t n = sizeof(s_framebuffer);
318 uint32_t hsh = (uint32_t)k_wd_fnv_offset;
319 for (size_t i = 0U; i < n; i++) {
320 hsh = (hsh ^ (uint32_t)p[i]) * (uint32_t)k_wd_fnv_prime;
321 }
322 return hsh;
323}
324
325/* ===========================================================================
326 * Widget render + input
327 * ===========================================================================
328 */
329
331static const char* wd_active_name(const ra8_app_registry_t* reg)
332{
333 ra8_app_t* act = nullptr;
334 if (ra8_app_active(reg, &act) != k_ra8_ok) {
335 return "?";
336 }
337 if (act == nullptr) {
338 return "?";
339 }
340 return act->name;
341}
342
345{
346 const wa_chrome_t* ch = (const wa_chrome_t*)w->ctx;
347 (void)
348 ra8_gfx_rect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, (uint32_t)k_wd_col_status_bg, true);
349 const int32_t tx = w->rect.x + (int32_t)k_wd_pad;
350 (void)ra8_gfx_text_out(tx,
351 w->rect.y + (int32_t)k_wd_pad,
352 wd_active_name(ch->reg),
354 (uint32_t)k_wd_col_text,
355 (uint32_t)k_wd_col_status_bg);
356 (void)ra8_gfx_text_out(tx,
357 w->rect.y + (int32_t)k_wd_pad + (int32_t)k_wd_line_h,
358 "SW1 < prev SW2 next > tap a tab",
360 (uint32_t)k_wd_col_dim,
361 (uint32_t)k_wd_col_status_bg);
362}
363
366{
367 const wa_content_t* c = (const wa_content_t*)w->ctx;
368 (void)ra8_gfx_rect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, c->bg, true);
369 const int32_t tx = w->rect.x + (int32_t)k_wd_pad;
370 int32_t ty = w->rect.y + (int32_t)k_wd_pad;
371 (void)ra8_gfx_text_out(tx, ty, c->title, &ra8_gfx_font_8x16, (uint32_t)k_wd_col_text, c->bg);
372 ty += (int32_t)k_wd_line_h + (int32_t)k_wd_line_h;
373 for (uint16_t i = 0U; i < c->nlines; i++) {
374 (void)ra8_gfx_text_out(tx, ty, c->lines[i], &ra8_gfx_font_8x16, (uint32_t)k_wd_col_dim, c->bg);
375 ty += (int32_t)k_wd_line_h;
376 }
377}
378
381{
382 const wa_chrome_t* ch = (const wa_chrome_t*)w->ctx;
383 uint16_t n = 0U;
384 if (ra8_app_count(ch->reg, &n) != k_ra8_ok) {
385 return;
386 }
387 if (n == 0U) {
388 return;
389 }
390 (void)
391 ra8_gfx_rect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, (uint32_t)k_wd_col_tabbar_bg, true);
392 const int32_t tabw = w->rect.w / (int32_t)n;
393 for (uint16_t i = 0U; i < n; i++) {
394 ra8_app_t* app = nullptr;
395 if (ra8_app_at(ch->reg, i, &app) != k_ra8_ok) {
396 continue;
397 }
398 const int32_t cx = w->rect.x + ((int32_t)i * tabw);
399 const bool on = ((int32_t)i == ch->reg->active);
400 const uint32_t fill = on ? (uint32_t)k_wd_col_tab_on : (uint32_t)k_wd_col_tab_off;
401 (void)ra8_gfx_rect(cx + (int32_t)k_wd_tab_inset,
402 w->rect.y + (int32_t)k_wd_tab_inset,
403 tabw - (2 * (int32_t)k_wd_tab_inset),
404 w->rect.h - (2 * (int32_t)k_wd_tab_inset),
405 fill,
406 true);
407 (void)ra8_gfx_text_out(cx + (int32_t)k_wd_pad,
408 w->rect.y + (w->rect.h / 2) - ((int32_t)k_wd_line_h / 2),
409 app->name,
411 (uint32_t)k_wd_col_text,
412 fill);
413 }
414}
415
418{
419 if (ev->kind != k_ra8_widget_ev_touch) {
420 return false;
421 }
422 const wa_chrome_t* ch = (const wa_chrome_t*)w->ctx;
423 uint16_t n = 0U;
424 if (ra8_app_count(ch->reg, &n) != k_ra8_ok) {
425 return false;
426 }
427 if (n == 0U) {
428 return false;
429 }
430 const int32_t tabw = w->rect.w / (int32_t)n;
431 if (tabw <= 0) {
432 return false;
433 }
434 const int32_t col = (ev->x - w->rect.x) / tabw;
435 if (col < 0) {
436 return false;
437 }
438 if (col >= (int32_t)n) {
439 return false;
440 }
441 ra8_app_t* app = nullptr;
442 if (ra8_app_at(ch->reg, (uint16_t)col, &app) != k_ra8_ok) {
443 return false;
444 }
445 g_wd_request = (int16_t)app->id;
446 return true;
447}
448
450static const ra8_widget_vtable_t k_wd_status_vt = {.measure = nullptr,
451 .render = wd_status_render,
452 .on_input = nullptr};
453static const ra8_widget_vtable_t k_wd_content_vt = {.measure = nullptr,
454 .render = wd_content_render,
455 .on_input = nullptr};
456static const ra8_widget_vtable_t k_wd_tabbar_vt = {.measure = nullptr,
457 .render = wd_tabbar_render,
458 .on_input = wd_tabbar_on_input};
459
460/* ===========================================================================
461 * App lifecycle
462 * ===========================================================================
463 */
464
466static int16_t wd_neighbor_id(int32_t dir)
467{
468 uint16_t n = 0U;
469 if (ra8_app_count(&s_reg, &n) != k_ra8_ok) {
470 return (int16_t)k_ra8_app_none;
471 }
472 if (n == 0U) {
473 return (int16_t)k_ra8_app_none;
474 }
475 int32_t cur = (int32_t)s_reg.active;
476 if (cur < 0) {
477 cur = 0;
478 }
479 const int32_t nx = (cur + dir + (int32_t)n) % (int32_t)n;
480 ra8_app_t* app = nullptr;
481 if (ra8_app_at(&s_reg, (uint16_t)nx, &app) != k_ra8_ok) {
482 return (int16_t)k_ra8_app_none;
483 }
484 return (int16_t)app->id;
485}
486
489{
490 wa_app_state_t* st = (wa_app_state_t*)a->ctx;
491 if (ev->kind == k_ra8_widget_ev_button) {
492 int32_t dir = 0;
493 if (ev->button_id == (uint16_t)k_wd_btn_prev) {
494 dir = -1;
495 }
496 if (ev->button_id == (uint16_t)k_wd_btn_next) {
497 dir = 1;
498 }
499 if (dir == 0) {
500 return false;
501 }
503 return true;
504 }
505 bool handled = false;
506 (void)ra8_widget_dispatch(st->widgets, (uint16_t)k_wd_w_count, ev, &handled);
507 return handled;
508}
509
511static void wd_app_render(const ra8_app_t* a)
512{
513 wa_app_state_t* st = (wa_app_state_t*)a->ctx;
514 ra8_box_t scratch[k_wd_box_cap];
515 const ra8_ui_rect_t frame = {.x = 0, .y = 0, .w = (int32_t)k_wd_fb_w, .h = (int32_t)k_wd_fb_h};
516 (void)ra8_gfx_clear((uint32_t)k_wd_col_clear);
518 (uint16_t)k_wd_w_count,
519 &frame,
521 0,
522 0,
523 scratch,
524 (uint16_t)k_wd_box_cap);
525 for (uint16_t i = 0U; i < (uint16_t)k_wd_w_count; i++) {
527 }
528 (void)ra8_widget_render_dirty(st->widgets, (uint16_t)k_wd_w_count);
529}
530
531static void wd_app_enter(ra8_app_t* a)
532{
533 ((wa_app_state_t*)a->ctx)->enters++;
534}
535
536static void wd_app_leave(ra8_app_t* a)
537{
538 ((wa_app_state_t*)a->ctx)->leaves++;
539}
540
543 .init = nullptr,
544 .on_enter = wd_app_enter,
545 .tick = nullptr,
546 .render = wd_app_render,
547 .on_input = wd_app_on_input,
548 .on_leave = wd_app_leave,
549 .deinit = nullptr,
550};
551
554 const char* title,
555 const char* const* lines,
556 uint16_t nlines,
557 uint32_t bg)
558{
559 st->content.title = title;
560 st->content.lines = lines;
561 st->content.nlines = nlines;
562 st->content.bg = bg;
563 st->enters = 0U;
564 st->leaves = 0U;
565
568 st->widgets[k_wd_w_status].ctx = &s_chrome;
569 st->widgets[k_wd_w_status].fixed = (int16_t)k_wd_status_h;
570 st->widgets[k_wd_w_status].visible = true;
571
574 st->widgets[k_wd_w_content].ctx = &st->content;
575 st->widgets[k_wd_w_content].flex = 1U;
576 st->widgets[k_wd_w_content].visible = true;
577
580 st->widgets[k_wd_w_tabbar].ctx = &s_chrome;
581 st->widgets[k_wd_w_tabbar].fixed = (int16_t)k_wd_tabbar_h;
582 st->widgets[k_wd_w_tabbar].visible = true;
583}
584
585/* ===========================================================================
586 * GLCDC panel bring-up + flush
587 * ===========================================================================
588 */
589
593 .framebuffer = s_framebuffer,
594 .framebuffer_bytes = sizeof(s_framebuffer),
595 .width_px = (uint16_t)k_wd_fb_w,
596 .height_px = (uint16_t)k_wd_fb_h,
597 .pixfmt = k_display_pixfmt_rgb565,
598 .panel_timing = &s_ra8_panel_ek_ra8d2_timing,
599};
600
602static bool wd_panel_up(void)
603{
605 return false;
606 }
607 if (s_display == nullptr) {
608 return false;
609 }
610 display_fb_t fb = {};
612 return false;
613 }
614 if (fb.pixels != (void*)s_framebuffer) {
615 return false;
616 }
618 (uint16_t)k_wd_fb_w,
619 (uint16_t)k_wd_fb_h,
621}
622
624static void wd_flush_full(void)
625{
626 if (s_display == nullptr) {
627 return;
628 }
630}
631
633static void wd_render_active(void)
634{
635 (void)ra8_app_render(&s_reg);
637}
638
639/* ===========================================================================
640 * Input polling
641 * ===========================================================================
642 */
643
646{
648 if (ra8_gpio_read(pin, &level) != k_ra8_ok) {
649 return false;
650 }
651 return (level == k_ra8_level_low);
652}
653
655static void wd_route_button(wd_btn_t btn)
656{
657 const ra8_widget_event_t ev = {.kind = k_ra8_widget_ev_button,
658 .reserved = 0U,
659 .button_id = (uint16_t)btn,
660 .x = 0,
661 .y = 0};
662 bool handled = false;
663 (void)ra8_app_route_input(&s_reg, &ev, &handled);
664}
665
667static void wd_poll_buttons(void)
668{
669 const bool sw1 = wd_sw_pressed(s_wd_sw1_pin);
670 const bool sw2 = wd_sw_pressed(s_wd_sw2_pin);
671 bool fresh1 = false;
672 if (sw1) {
673 if (!s_was_sw1) {
674 fresh1 = true;
675 }
676 }
677 bool fresh2 = false;
678 if (sw2) {
679 if (!s_was_sw2) {
680 fresh2 = true;
681 }
682 }
683 s_was_sw1 = sw1;
684 s_was_sw2 = sw2;
685 if (fresh1) {
687 }
688 if (fresh2) {
690 }
691}
692
694static void wd_service_request(void)
695{
696 const int16_t want = g_wd_request;
697 g_wd_request = (int16_t)k_ra8_app_none;
698 if (want == (int16_t)k_ra8_app_none) {
699 return;
700 }
701 ra8_app_t* act = nullptr;
702 (void)ra8_app_active(&s_reg, &act);
703 if (act != nullptr) {
704 if (act->id == (uint16_t)want) {
705 return; /* already focused -- no flicker. */
706 }
707 }
708 if (ra8_app_launch(&s_reg, (uint16_t)want) == k_ra8_ok) {
710 }
711}
712
713/* ===========================================================================
714 * Registration + deterministic self-check
715 * ===========================================================================
716 */
717
719static bool wd_register_apps(ra8_app_t* library, ra8_app_t* reader, ra8_app_t* settings)
720{
722 "Library",
724 (uint16_t)(sizeof(k_wd_lib_lines) / sizeof(k_wd_lib_lines[0])),
725 (uint32_t)k_wd_col_lib_bg);
727 "Reader",
729 (uint16_t)(sizeof(k_wd_rdr_lines) / sizeof(k_wd_rdr_lines[0])),
730 (uint32_t)k_wd_col_rdr_bg);
731 *library = (ra8_app_t){.vt = &k_wd_app_vt,
732 .ctx = &s_library,
733 .id = (uint16_t)k_wd_app_library,
734 .name = "Library",
735 .removable = false};
736 *reader = (ra8_app_t){.vt = &k_wd_app_vt,
737 .ctx = &s_reader,
738 .id = (uint16_t)k_wd_app_reader,
739 .name = "Reader",
740 .removable = false};
741 if (ra8_app_registry_init(&s_reg, s_slots, (uint16_t)(sizeof(s_slots) / sizeof(s_slots[0]))) !=
742 k_ra8_ok) {
743 return false;
744 }
745 if (ra8_app_register(&s_reg, library) != k_ra8_ok) {
746 return false;
747 }
748 if (ra8_app_register(&s_reg, reader) != k_ra8_ok) {
749 return false;
750 }
751#if WA_APP_SETTINGS
753 "Settings",
755 (uint16_t)(sizeof(k_wd_set_lines) / sizeof(k_wd_set_lines[0])),
756 (uint32_t)k_wd_col_set_bg);
757 *settings = (ra8_app_t){.vt = &k_wd_app_vt,
758 .ctx = &s_settings,
759 .id = (uint16_t)k_wd_app_settings,
760 .name = "Settings",
761 .removable = true};
762 return ra8_app_register(&s_reg, settings) == k_ra8_ok;
763#else
764 (void)settings;
765 return true;
766#endif
767}
768
770static bool wd_check_touch_dispatch(void)
771{
772 ra8_widget_t* tb = &s_reader.widgets[k_wd_w_tabbar];
773 uint16_t n = 0U;
774 if (ra8_app_count(&s_reg, &n) != k_ra8_ok) {
775 return false;
776 }
777 if (n == 0U) {
778 return false;
779 }
780 const int32_t tabw = tb->rect.w / (int32_t)n;
781 const ra8_widget_event_t tev = {.kind = k_ra8_widget_ev_touch,
782 .reserved = 0U,
783 .button_id = 0U,
784 .x = tb->rect.x + (tabw / 2),
785 .y = tb->rect.y + (tb->rect.h / 2)};
786 g_wd_request = (int16_t)k_ra8_app_none;
787 bool handled = false;
788 (void)ra8_app_route_input(&s_reg, &tev, &handled);
789 if (!handled) {
790 return false;
791 }
792 return (g_wd_request == (int16_t)k_wd_app_library);
793}
794
796static bool wd_check_damage(void)
797{
799 ra8_ui_rect_t dmg = {};
801 uint16_t nd = 0U;
802 (void)ra8_widget_damage(s_reader.widgets, (uint16_t)k_wd_w_count, &dmg, &hint, &nd);
803 if (nd != 1U) {
804 return false;
805 }
806 if (dmg.h != (int32_t)k_wd_status_h) {
807 return false;
808 }
809 return (hint == k_ra8_widget_refresh_fast);
810}
811
813static bool wd_selfcheck(uint32_t* out_lib, uint32_t* out_rdr)
814{
815 if (ra8_app_launch(&s_reg, (uint16_t)k_wd_app_library) != k_ra8_ok) {
816 return false;
817 }
818 (void)ra8_app_render(&s_reg);
819 const uint32_t lib = wd_framebuffer_hash();
820 if (ra8_app_launch(&s_reg, (uint16_t)k_wd_app_reader) != k_ra8_ok) {
821 return false;
822 }
823 (void)ra8_app_render(&s_reg);
824 const uint32_t rdr = wd_framebuffer_hash();
825 if (lib == rdr) {
826 return false;
827 }
828 if (s_library.leaves != 1U) {
829 return false;
830 }
831 if (s_reader.enters != 1U) {
832 return false;
833 }
834 if (s_library.enters != 1U) {
835 return false;
836 }
838 return false;
839 }
840 if (!wd_check_damage()) {
841 return false;
842 }
843 *out_lib = lib;
844 *out_rdr = rdr;
845 return true;
846}
847
848/* ===========================================================================
849 * Boot
850 * ===========================================================================
851 */
852
854static void wd_setup_or_halt(void)
855{
856 uint32_t cpuclk0_hz = 0U;
857 if ((ra8_cgc_init() != k_ra8_ok) || (ra8_mstp_init() != k_ra8_ok)) {
858 wd_fail_halt(k_wd_msg_finit, (uint32_t)sizeof(k_wd_msg_finit) - 1U);
859 }
861 wd_fail_halt(k_wd_msg_finit, (uint32_t)sizeof(k_wd_msg_finit) - 1U);
862 }
863 if (ra8_time_init(cpuclk0_hz) != k_ra8_ok) {
864 wd_fail_halt(k_wd_msg_finit, (uint32_t)sizeof(k_wd_msg_finit) - 1U);
865 }
867 wd_fail_halt(k_wd_msg_finit, (uint32_t)sizeof(k_wd_msg_finit) - 1U);
868 }
873}
874
876static void wd_print_banner(uint32_t lib_crc, uint32_t rdr_crc)
877{
878 uint16_t n = 0U;
879 (void)ra8_app_count(&s_reg, &n);
880 wd_print(k_wd_msg_pre, (uint32_t)sizeof(k_wd_msg_pre) - 1U);
881 wd_print_uint((uint32_t)n);
882 wd_print(k_wd_msg_lib, (uint32_t)sizeof(k_wd_msg_lib) - 1U);
883 wd_print_hex(lib_crc);
884 wd_print(k_wd_msg_rdr, (uint32_t)sizeof(k_wd_msg_rdr) - 1U);
885 wd_print_hex(rdr_crc);
886 wd_print(k_wd_msg_route, (uint32_t)sizeof(k_wd_msg_route) - 1U);
887 wd_print(k_wd_msg_pass, (uint32_t)sizeof(k_wd_msg_pass) - 1U);
888}
889
899void main(void)
900{
903 wd_print(k_wd_msg_boot, (uint32_t)sizeof(k_wd_msg_boot) - 1U);
904
905 if (!wd_panel_up()) {
906 wd_fail_halt(k_wd_msg_fpanl, (uint32_t)sizeof(k_wd_msg_fpanl) - 1U);
907 }
908
909 ra8_app_t library = {};
910 ra8_app_t reader = {};
911 ra8_app_t settings = {};
912 if (!wd_register_apps(&library, &reader, &settings)) {
913 wd_fail_halt(k_wd_msg_freg, (uint32_t)sizeof(k_wd_msg_freg) - 1U);
914 }
915
916 uint32_t lib_crc = 0U;
917 uint32_t rdr_crc = 0U;
918 if (!wd_selfcheck(&lib_crc, &rdr_crc)) {
919 wd_fail_halt(k_wd_msg_fchk, (uint32_t)sizeof(k_wd_msg_fchk) - 1U);
920 }
921 wd_print_banner(lib_crc, rdr_crc);
922
923 /* Land on the Library app and show it live on the panel. */
924 g_wd_request = (int16_t)k_ra8_app_none;
925 (void)ra8_app_launch(&s_reg, (uint16_t)k_wd_app_library);
927
928 while (1) {
931 ra8_delay_ms((uint32_t)k_wd_frame_ms);
932 }
933}
void main(void)
Secure fallback main entry point.
Definition main.c:37
static display_handle_t * s_display
Definition main.c:78
static uint16_t s_framebuffer[(size_t) k_panel_height_px *(size_t) k_panel_width_px]
1024x600 RGB565 framebuffer in external SDRAM (GLCDC scans this).
Definition main.c:67
static bool s_chrome
True while the status bar + scroll rail chrome is shown.
Definition main.c:304
static bool s_was_sw1
Edge-detect: was SW1 held on the previous button poll.
Definition main.c:308
static bool s_was_sw2
Edge-detect: was SW2 held on the previous button poll.
Definition main.c:310
static mg_reader_t s_reader
The pan/zoom viewer over the tiled page.
Definition main.c:227
static wa_app_state_t s_library
Definition main.c:96
static bool wd_tabbar_on_input(ra8_widget_t *w, const ra8_widget_event_t *ev)
Tab-bar input: map a touch column to an app id (request a launch).
Definition main.c:417
static const uint8_t k_wd_msg_fchk[]
Definition main.c:255
wd_widget_idx_t
Index of each widget within an app's tree.
Definition main.c:135
@ k_wd_box_cap
ra8_box scratch (count + 1).
Definition main.c:140
@ k_wd_w_tabbar
Tab bar (fixed).
Definition main.c:138
@ k_wd_w_content
Content (flex).
Definition main.c:137
@ k_wd_w_count
Widgets per app.
Definition main.c:139
@ k_wd_w_status
Status bar (fixed).
Definition main.c:136
static const display_cfg_t k_wd_display_cfg
Display PAL config: GLCDC LCD backend bound to the SRAM framebuffer.
Definition main.c:591
static void wd_app_enter(ra8_app_t *a)
Definition main.c:531
static void wd_route_button(wd_btn_t btn)
Route a navigation button through the focused app (#146).
Definition main.c:655
static void wd_status_render(ra8_widget_t *w)
Status-bar render: fill + active app name + the button hint.
Definition main.c:344
static const uint8_t k_wd_msg_rdr[]
Definition main.c:258
static const uint8_t k_wd_msg_fpanl[]
Definition main.c:253
static const uint8_t k_wd_msg_boot[]
Definition main.c:251
static const uint8_t k_wd_msg_route[]
Definition main.c:259
static void wd_print_uint(uint32_t value)
Print a small unsigned integer in decimal.
Definition main.c:295
wd_app_id_t
Registered app ids (launch keys).
Definition main.c:114
@ k_wd_app_settings
Settings app (optional).
Definition main.c:117
@ k_wd_app_reader
EPUB reader app.
Definition main.c:116
@ k_wd_app_library
Library / home app.
Definition main.c:115
static const uint8_t k_wd_msg_freg[]
Definition main.c:254
static void wd_setup_or_halt(void)
Bring up clocks/MSTP/time, the console, and the SW1/SW2 inputs.
Definition main.c:854
static bool wd_selfcheck(uint32_t *out_lib, uint32_t *out_rdr)
Run the whole deterministic surface; return the two composites' hashes.
Definition main.c:813
static const char *const k_wd_rdr_lines[]
Definition main.c:235
static void wd_print(const uint8_t *msg, uint32_t len)
Emit a byte run on the SCI8 console.
Definition main.c:268
static void wd_render_active(void)
Render the focused app and flush the whole panel.
Definition main.c:633
static void wd_print_banner(uint32_t lib_crc, uint32_t rdr_crc)
Emit the PASS banner once the self-check holds.
Definition main.c:876
wd_btn_t
Navigation button ids carried in a button widget event.
Definition main.c:125
@ k_wd_btn_next
SW2: focus the next app.
Definition main.c:127
@ k_wd_btn_prev
SW1: focus the previous app.
Definition main.c:126
static void wd_print_hex(uint32_t value)
Print value as 8 uppercase hex digits.
Definition main.c:283
static void wd_flush_full(void)
Push the whole composited frame to the panel (GC16-quality).
Definition main.c:624
static volatile int16_t g_wd_request
App id an input handler asked to focus, or k_ra8_app_none.
Definition main.c:220
static bool wd_register_apps(ra8_app_t *library, ra8_app_t *reader, ra8_app_t *settings)
Initialise app state, the registry, and register every app.
Definition main.c:719
wd_geom_t
Framebuffer + band geometry (no magic numbers).
Definition main.c:81
@ k_wd_tab_inset
Tab cell inset from the band, pixels.
Definition main.c:88
@ k_wd_fb_h
Framebuffer height, pixels.
Definition main.c:83
@ k_wd_tabbar_h
Tab-bar band height, pixels.
Definition main.c:85
@ k_wd_status_h
Status-bar band height, pixels.
Definition main.c:84
@ k_wd_line_h
Text line pitch (16px glyph + 2).
Definition main.c:87
@ k_wd_pad
Inner text padding, pixels.
Definition main.c:86
@ k_wd_fb_w
Framebuffer width, pixels.
Definition main.c:82
static const ra8_app_vtable_t k_wd_app_vt
Shared app lifecycle vtable (every app behaves the same way).
Definition main.c:542
static void wd_content_render(ra8_widget_t *w)
Content render: fill + title over the app's body lines.
Definition main.c:365
static void wd_fail_halt(const uint8_t *msg, uint32_t len)
Print a fail banner and park forever in WFI.
Definition main.c:274
static uint32_t wd_framebuffer_hash(void)
FNV-1a-32 over the composited framebuffer bytes.
Definition main.c:314
static bool wd_panel_up(void)
Bring up the GLCDC panel and bind ra8_gfx to its framebuffer.
Definition main.c:602
static const char *const k_wd_set_lines[]
Definition main.c:243
static bool wd_sw_pressed(ra8_port_pin_t pin)
Read a user switch (active-low); true == pressed.
Definition main.c:645
static const uint8_t k_wd_msg_lib[]
Definition main.c:257
static ra8_port_pin_t s_wd_sw1_pin
SW1 (previous app) port pin, sourced from the board layer at init.
Definition main.c:160
static const ra8_widget_vtable_t k_wd_content_vt
Definition main.c:453
wd_color_t
0xRRGGBB palette (ra8_gfx packs to RGB565).
Definition main.c:96
@ k_wd_col_set_bg
Settings content (deep green).
Definition main.c:106
@ k_wd_col_lib_bg
Library content (deep blue).
Definition main.c:104
@ k_wd_col_tab_off
Idle tab cell (gray).
Definition main.c:101
@ k_wd_col_tabbar_bg
Tab-bar fill (dark).
Definition main.c:99
@ k_wd_col_rdr_bg
Reader content (warm brown).
Definition main.c:105
@ k_wd_col_status_bg
Status-bar fill (slate).
Definition main.c:98
@ k_wd_col_text
Primary text (white).
Definition main.c:102
@ k_wd_col_dim
Secondary text (gray).
Definition main.c:103
@ k_wd_col_clear
Whole-frame clear (near black).
Definition main.c:97
@ k_wd_col_tab_on
Active tab cell (blue).
Definition main.c:100
static bool wd_check_damage(void)
Assert status-bar-only invalidation yields exactly its rect, fast.
Definition main.c:796
static void wd_tabbar_render(ra8_widget_t *w)
Tab-bar render: one cell per app, the active one highlighted.
Definition main.c:380
static void wd_app_render(const ra8_app_t *a)
App render: clear, lay out the tree, mark all dirty, composite.
Definition main.c:511
static bool wd_app_on_input(ra8_app_t *a, const ra8_widget_event_t *ev)
App input: SW button -> neighbour app; touch -> widget dispatch.
Definition main.c:488
static int16_t wd_neighbor_id(int32_t dir)
Resolve the app id at (active + dir), wrapped, or k_ra8_app_none.
Definition main.c:466
static const uint8_t k_wd_msg_pre[]
Definition main.c:256
static const ra8_widget_vtable_t k_wd_status_vt
Status / content widgets ignore input (NULL handler never consumes).
Definition main.c:450
static const char * wd_active_name(const ra8_app_registry_t *reg)
Name of the focused app, or a placeholder if none.
Definition main.c:331
static const ra8_widget_vtable_t k_wd_tabbar_vt
Definition main.c:456
static ra8_port_pin_t s_wd_sw2_pin
SW2 (next app) port pin, sourced from the board layer at init.
Definition main.c:162
wd_console_t
Console baud + text-format constants.
Definition main.c:148
@ k_wd_frame_ms
Input poll period (ms).
Definition main.c:150
@ k_wd_hex_nibbles
Hex digits per 32-bit.
Definition main.c:153
@ k_wd_dec_ten
Hex/decimal split + buf.
Definition main.c:156
@ k_wd_fnv_prime
FNV-1a-32 prime.
Definition main.c:152
@ k_wd_nibble_bits
Bits per hex nibble.
Definition main.c:154
@ k_wd_nibble_mask
Low-nibble mask.
Definition main.c:155
@ k_wd_fnv_offset
FNV-1a-32 offset basis.
Definition main.c:151
@ k_wd_uart_baud
Console baud.
Definition main.c:149
static void wd_app_leave(ra8_app_t *a)
Definition main.c:536
static void wd_state_init(wa_app_state_t *st, const char *title, const char *const *lines, uint16_t nlines, uint32_t bg)
Build one app's widget tree: status (fixed) / content (flex) / tabs (fixed).
Definition main.c:553
static bool wd_check_touch_dispatch(void)
Drive a synthetic touch on the Library tab while Reader is focused.
Definition main.c:770
static const uint8_t k_wd_msg_pass[]
Definition main.c:260
static wa_app_state_t s_settings
Settings app state (optional).
Definition main.c:210
static const char *const k_wd_lib_lines[]
Definition main.c:229
static void wd_service_request(void)
Apply a pending app-switch request: launch + re-composite if changed.
Definition main.c:694
static const uint8_t k_wd_msg_finit[]
Definition main.c:252
static void wd_poll_buttons(void)
Poll SW1/SW2 (edge-triggered) and route a fresh press as a button.
Definition main.c:667
Zero-heap app framework: lifecycle + static registry + launcher (#146).
ra8_err_t ra8_app_launch(ra8_app_registry_t *reg, uint16_t id)
Launch (focus) the app with id, running the focus lifecycle.
Definition ra8_app.c:78
ra8_err_t ra8_app_register(ra8_app_registry_t *reg, ra8_app_t *app)
Register an app (calls its init once) and add it to the registry.
Definition ra8_app.c:48
ra8_err_t ra8_app_count(const ra8_app_registry_t *reg, uint16_t *out_count)
Number of registered apps (for the launcher to list).
Definition ra8_app.c:166
@ k_ra8_app_none
No active app / not found.
Definition ra8_app.h:84
ra8_err_t ra8_app_at(const ra8_app_registry_t *reg, uint16_t idx, ra8_app_t **out_app)
Get the app at registry index idx (launcher enumeration).
Definition ra8_app.c:174
ra8_err_t ra8_app_route_input(ra8_app_registry_t *reg, const ra8_widget_event_t *ev, bool *out_handled)
Route an input event to the focused app.
Definition ra8_app.c:124
ra8_err_t ra8_app_active(const ra8_app_registry_t *reg, ra8_app_t **out_app)
Get the currently focused app.
Definition ra8_app.c:115
ra8_err_t ra8_app_render(ra8_app_registry_t *reg)
Run the focused app's render (on-target; no-op if none / NULL).
Definition ra8_app.c:153
ra8_err_t ra8_app_registry_init(ra8_app_registry_t *reg, ra8_app_t **storage, uint16_t cap)
Bind a registry to caller-owned pointer storage (empty, no focus).
Definition ra8_app.c:20
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_sw_pin(ra8_board_sw_id_t sw, ra8_port_pin_t *out_pin)
Translate a board switch id into its underlying ra8_port_pin_t.
ra8_err_t ra8_board_sw_init(ra8_board_sw_id_t sw)
Configure a switch pin as an input with internal pull-up.
@ k_ra8_board_sw1
SW1, P009, IRQ13-DS (jumper E31).
@ k_ra8_board_sw2
SW2, P008, IRQ12-DS (jumper E32).
ra8_board_eth_pin_t pin
Pin.
ra8_err_t ra8_board_uart_console_write(const uint8_t *data, size_t len)
Polled blocking write to the J-Link OB VCOM console.
ra8_err_t ra8_board_uart_console_init(uint32_t baud)
Configure SCI8 + PD02/PD03 as the debug-console UART.
Boot entry points shared between a vector table and its startup code.
Bounded, allocation-free box-model layout for e-reader chrome.
High-level Clock Generation Circuit driver.
ra8_err_t ra8_cgc_get_clock_hz(ra8_clock_id_t id, uint32_t *out_hz)
Query the current frequency of a clock-tree domain.
Definition ra8_cgc.c:132
@ k_ra8_clock_id_cpuclk0
Cortex-M85 CPUCLK0.
Definition ra8_cgc.h:70
ra8_err_t ra8_cgc_init(void)
Configure the clock tree to a safe default.
Definition ra8_cgc.c:727
Display Platform Abstraction Layer for the RA8D2.
@ k_display_pixfmt_rgb565
16 bpp, 5/6/5 packed.
display_rect_t display_full_rect(const display_handle_t *d)
Convenience helper returning the rect covering the whole framebuffer.
ra8_err_t display_get_framebuffer(const display_handle_t *d, display_fb_t *out)
Return the framebuffer descriptor the backend is targeting.
ra8_err_t display_flush(const display_handle_t *d, display_rect_t rect, display_refresh_hint_t hint)
Commit pending framebuffer changes to the panel.
struct display_handle display_handle_t
ra8_err_t display_init(const display_cfg_t *cfg, display_handle_t **out_handle)
Initialise the display PAL and bring the selected backend up to a state where display_flush succeeds.
@ k_display_refresh_quality
Prioritise final quality.
LCD backend (ra8_glcdc) for the display PAL.
const display_backend_iface_t k_display_backend_lcd_ra8_glcdc
LCD backend vtable – pass its address through display_cfg_t.iface to drive the EK-RA8D2 panel.
Error Code Definitions for ra8-firmware.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
Software 2D graphics primitives layered on top of a caller-ownedframebuffer (DRW / D/AVE 2D / GLCDC r...
@ k_ra8_gfx_format_rgb565
16-bit RGB565, little-endian in memory.
Definition ra8_gfx.h:40
ra8_err_t ra8_gfx_clear(uint32_t color)
Fill the bound framebuffer's clip region with a single colour.
ra8_err_t ra8_gfx_text_out(int32_t x, int32_t y, const char *str, const ra8_gfx_font_t *font, uint32_t fg_color, uint32_t bg_color)
Render a NUL-terminated ASCII string.
ra8_err_t ra8_gfx_init(void *fb, uint16_t width, uint16_t height, ra8_gfx_format_t format)
Bind ra8_gfx to a caller-owned framebuffer.
ra8_err_t ra8_gfx_rect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color, bool filled)
Draw an axis-aligned rectangle.
Bitmap font descriptor + bundled font handles for ra8_gfx.
const ra8_gfx_font_t ra8_gfx_font_8x16
Bundled 8x16 IBM PC VGA bitmap font, ASCII 0x20..0x7E.
Graphics LCD Controller driver (two-layer with alpha blending).
static const ra8_io_fsfmt_t * s_reg[(uint32_t) k_ra8_io_fsfmt_max]
Registered formats, in probe priority order.
static ra8_isr_slot_t s_slots[k_ra8_isr_slot_count]
Per-slot dispatch table.
Definition ra8_isr.c:77
NVIC + ICU IELSR allocator.
void ra8_isr_globals_enable(void)
Globally enable maskable interrupts (PRIMASK = 0).
Definition ra8_isr.c:439
Ref-counted Module Stop Control wrapper for the RA8D2.
ra8_err_t ra8_mstp_init(void)
Re-establish the ra8_mstp ref-count table from current hardware state.
Definition ra8_mstp.c:291
Active display-panel descriptor for the EK-RA8D2 (ER-TFT070-6).
@ k_ra8_board_fb_align_bytes
GLCDC AXI burst alignment, in bytes.
Definition ra8_panel.h:108
EK-RA8D2 panel timing as the HAL's ra8_glcdc_timing_t (ER-TFT070-6).
static const ra8_glcdc_timing_t s_ra8_panel_ek_ra8d2_timing
EK-RA8D2 ER-TFT070-6 RGB timing for ra8_glcdc_init / the LCD backend.
Typed Port / Pin Constants for the RA8D2 IOPORT Module.
ra8_port_pin_t
Packed (port << 8) | pin pin identifier.
@ k_ra8_pin_none
Sentinel: no pin selected.
ra8_level_t
Digital output / input level.
@ k_ra8_level_high
Drive or read 1.
@ k_ra8_level_low
Drive or read 0.
High-level GPIO helpers on top of the PORT + PFS register layer.
ra8_err_t ra8_gpio_read(ra8_port_pin_t pin, ra8_level_t *out_level)
Read a previously-configured input.
Definition gpio.c:210
SysTick-based tick counter, delay and timestamp helpers.
ra8_err_t ra8_time_init(uint32_t cpu_hz)
Initialise SysTick for a 1 kHz tick interrupt.
Definition ra8_time.c:59
void ra8_delay_ms(uint32_t ms)
Busy-wait for at least ms milliseconds.
Definition ra8_time.c:129
Bounded UI interaction core: hit-testing, screen stack, paging.
Zero-heap composable widget layer (dwm-style) over ra8_box + ra8_ui.
@ k_ra8_widget_axis_col
Vertical stack (top -> bottom).
Definition ra8_widget.h:176
ra8_err_t ra8_widget_layout_stack(ra8_widget_t *widgets, uint16_t count, const ra8_ui_rect_t *frame, ra8_widget_axis_t axis, int16_t gap, int16_t pad, ra8_box_t *box_scratch, uint16_t box_cap)
Lay a stack of widgets out inside a frame (delegates to ra8_box).
Definition ra8_widget.c:215
ra8_err_t ra8_widget_damage(const ra8_widget_t *widgets, uint16_t count, ra8_ui_rect_t *out_rect, ra8_widget_refresh_t *out_hint, uint16_t *out_count)
Compute the minimal damage rectangle + refresh hint to flush.
Definition ra8_widget.c:299
ra8_err_t ra8_widget_invalidate(ra8_widget_t *w, ra8_widget_refresh_t refresh)
Mark a widget dirty with a refresh hint (folds upward in strength).
Definition ra8_widget.c:286
ra8_widget_refresh_t
E-ink-style refresh hint carried by a dirty widget.
Definition ra8_widget.h:98
@ k_ra8_widget_refresh_fast
Partial / A2 (text-only change).
Definition ra8_widget.h:100
@ k_ra8_widget_refresh_none
Clean – not dirty.
Definition ra8_widget.h:99
@ k_ra8_widget_refresh_quality
Full / GC16 (whole-area redraw).
Definition ra8_widget.h:101
@ k_ra8_widget_ev_touch
A touch / tap at (x, y).
Definition ra8_widget.h:69
@ k_ra8_widget_ev_button
A physical button press (button_id).
Definition ra8_widget.h:70
ra8_err_t ra8_widget_render_dirty(ra8_widget_t *widgets, uint16_t count)
Render every visible + dirty widget, clearing its damage.
Definition ra8_widget.c:331
ra8_err_t ra8_widget_dispatch(ra8_widget_t *widgets, uint16_t count, const ra8_widget_event_t *ev, bool *out_handled)
Route an event to the widget that should handle it.
Definition ra8_widget.c:252
Configuration descriptor passed into display_init.
Framebuffer descriptor returned by display_get_framebuffer.
void * pixels
Base of pixel data (RGB565 unless noted).
Fixed table of registered apps + the focused index.
Definition ra8_app.h:161
int16_t active
Focused app index, or k_ra8_app_none.
Definition ra8_app.h:165
One app instance + its metadata (caller-owned, static).
App lifecycle callbacks (shared by all instances of one app).
Definition ra8_app.h:133
One node in a box tree (caller-owned).
Definition ra8_box.h:90
Axis-aligned rectangle in framebuffer pixel coordinates.
Definition ra8_ui.h:72
int32_t h
Height (pixels, >= 0).
Definition ra8_ui.h:76
One input event delivered to ra8_widget_dispatch.
Definition ra8_widget.h:77
int32_t x
Touch X (for k_ra8_widget_ev_touch).
Definition ra8_widget.h:81
ra8_widget_ev_kind_t kind
Touch or button.
Definition ra8_widget.h:78
uint16_t button_id
Button id (for k_ra8_widget_ev_button).
Definition ra8_widget.h:80
One widget instance (caller-owned, no allocation).
Behaviour table shared by all widgets of one kind.
Definition ra8_widget.h:121
Per-app state: its widget tree + a focus-lifecycle counter.
Definition main.c:88
uint32_t enters
Times on_enter fired.
Definition main.c:92
uint32_t leaves
Times on_leave fired.
Definition main.c:93
wa_content_t content
Content widget state.
Definition main.c:199
ra8_widget_t widgets[2]
[0] status bar, [1] content.
Definition main.c:89
Shared chrome state: the registry the status bar + tab bar read.
Definition main.c:188
ra8_app_registry_t * reg
Registry (active index + app names).
Definition main.c:189
Per-app content widget state: a title over a list of text lines.
Definition main.c:176
const char *const * lines
Body lines (each NUL-term).
Definition main.c:178
uint32_t bg
Content background colour.
Definition main.c:180
const char * title
Heading line.
Definition main.c:177
uint16_t nlines
Number of body lines.
Definition main.c:179