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
38
39#include <stddef.h>
40#include <stdint.h>
41
42#include "ra8_app.h"
43#include "ra8_board_ek_ra8d2.h"
44#include "ra8_boot_entry.h"
45#include "ra8_box.h"
46#include "ra8_cgc.h"
47#include "ra8_err.h"
48#include "ra8_gfx.h"
49#include "ra8_isr.h"
50#include "ra8_mstp.h"
51#include "ra8_time.h"
52#include "ra8_ui.h"
53#include "ra8_widget.h"
54
56typedef enum : uint32_t {
57 k_wa_uart_baud = 115200U,
58 k_wa_fb_w = 160U,
59 k_wa_fb_h = 120U,
61 k_wa_col_bg = 0x101018U,
62 k_wa_col_status = 0x808088U,
63 k_wa_col_library = 0x3050C0U,
64 k_wa_col_reader = 0xC05030U,
65 k_wa_fnv_offset = 0x811C9DC5U,
66 k_wa_fnv_prime = 0x01000193U,
72
74typedef enum : uint16_t {
78
80static uint16_t s_framebuffer[(size_t)k_wa_fb_h * (size_t)k_wa_fb_w];
81
83typedef struct {
84 uint32_t color;
85} wa_fill_t;
86
95
98
99static const uint8_t k_msg_boot[] = "widget-app-hil: boot\r\n";
100static const uint8_t k_msg_fail[] = "widget-app-hil: FAIL init\r\n";
101static const uint8_t k_msg_freg[] = "widget-app-hil: FAIL register\r\n";
102static const uint8_t k_msg_fcrc[] = "widget-app-hil: FAIL crc-equal\r\n";
103static const uint8_t k_msg_flife[] = "widget-app-hil: FAIL lifecycle\r\n";
104static const uint8_t k_msg_fdmg[] = "widget-app-hil: FAIL damage\r\n";
105static const uint8_t k_msg_pre[] = "widget-app-hil: apps=2 lib=";
106static const uint8_t k_msg_rdr[] = " rdr=";
107static const uint8_t k_msg_flush[] = " flush=160x16 hint=fast";
108static const uint8_t k_msg_ok[] = " PASS\r\n";
109
111static void wa_print(const uint8_t* msg, uint32_t len)
112{
113 (void)ra8_board_uart_console_write(msg, (size_t)len);
114}
115
117static void wa_panic_halt(const uint8_t* msg, uint32_t len)
118{
119 wa_print(msg, len);
120 __asm__ volatile("bkpt #0");
121 while (1) {
122 __asm__ volatile("wfi");
123 }
124}
125
127static uint32_t wa_framebuffer_hash(void)
128{
129 const uint8_t* p = (const uint8_t*)s_framebuffer;
130 const size_t n = sizeof(s_framebuffer);
131 uint32_t hsh = (uint32_t)k_wa_fnv_offset;
132 for (size_t i = 0U; i < n; i++) {
133 hsh = (hsh ^ (uint32_t)p[i]) * (uint32_t)k_wa_fnv_prime;
134 }
135 return hsh;
136}
137
139static void wa_print_hex(uint32_t value)
140{
141 uint8_t buf[k_wa_hex_nibbles];
142 for (uint32_t i = 0U; i < (uint32_t)k_wa_hex_nibbles; i++) {
143 const uint32_t shift = ((uint32_t)k_wa_hex_nibbles - 1U - i) * (uint32_t)k_wa_nibble_bits;
144 const uint32_t nib = (value >> shift) & (uint32_t)k_wa_nibble_mask;
145 buf[i] = (uint8_t)((nib < (uint32_t)k_wa_dec_ten) ? ('0' + nib) : ('A' + (nib - k_wa_dec_ten)));
146 }
147 wa_print(buf, (uint32_t)k_wa_hex_nibbles);
148}
149
152{
153 const uint32_t color = ((const wa_fill_t*)w->ctx)->color;
154 (void)ra8_gfx_rect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, color, true);
155}
156
159 .measure = nullptr,
160 .render = wa_fill_render,
161 .on_input = nullptr,
162};
163
165static void wa_state_init(wa_app_state_t* st, uint32_t content_color)
166{
167 st->status_fill.color = (uint32_t)k_wa_col_status;
168 st->content_fill.color = content_color;
169 st->enters = 0U;
170 st->leaves = 0U;
171
172 st->widgets[0] = (ra8_widget_t){};
173 st->widgets[0].vt = &k_wa_fill_vt;
174 st->widgets[0].ctx = &st->status_fill;
175 st->widgets[0].fixed = (int16_t)k_wa_statusbar_h;
176 st->widgets[0].visible = true;
177
178 st->widgets[1] = (ra8_widget_t){};
179 st->widgets[1].vt = &k_wa_fill_vt;
180 st->widgets[1].ctx = &st->content_fill;
181 st->widgets[1].flex = 1U;
182 st->widgets[1].visible = true;
183}
184
186static void wa_app_render(const ra8_app_t* a)
187{
188 wa_app_state_t* st = (wa_app_state_t*)a->ctx;
189 ra8_box_t scratch[4];
190 const ra8_ui_rect_t frame = {.x = 0, .y = 0, .w = (int32_t)k_wa_fb_w, .h = (int32_t)k_wa_fb_h};
191 (void)ra8_gfx_clear((uint32_t)k_wa_col_bg);
192 (void)ra8_widget_layout_stack(st->widgets, 2U, &frame, k_ra8_widget_axis_col, 0, 0, scratch, 4U);
195 (void)ra8_widget_render_dirty(st->widgets, 2U);
196}
197
198static void wa_app_enter(ra8_app_t* a)
199{
200 ((wa_app_state_t*)a->ctx)->enters++;
201}
202
203static void wa_app_leave(ra8_app_t* a)
204{
205 ((wa_app_state_t*)a->ctx)->leaves++;
206}
207
210 .init = nullptr,
211 .on_enter = wa_app_enter,
212 .tick = nullptr,
213 .render = wa_app_render,
214 .on_input = nullptr,
215 .on_leave = wa_app_leave,
216 .deinit = nullptr,
217};
218
220static void wa_setup_or_halt(void)
221{
222 uint32_t cpuclk0_hz = 0U;
223 if ((ra8_cgc_init() != k_ra8_ok) || (ra8_mstp_init() != k_ra8_ok)) {
224 wa_panic_halt(k_msg_fail, (uint32_t)sizeof(k_msg_fail) - 1U);
225 }
227 wa_panic_halt(k_msg_fail, (uint32_t)sizeof(k_msg_fail) - 1U);
228 }
229 if (ra8_time_init(cpuclk0_hz) != k_ra8_ok) {
230 wa_panic_halt(k_msg_fail, (uint32_t)sizeof(k_msg_fail) - 1U);
231 }
233 wa_panic_halt(k_msg_fail, (uint32_t)sizeof(k_msg_fail) - 1U);
234 }
235}
236
238static void wa_run_two_apps(ra8_app_registry_t* reg, uint32_t* out_lib, uint32_t* out_rdr)
239{
240 if (ra8_app_launch(reg, (uint16_t)k_wa_app_library) != k_ra8_ok) {
241 wa_panic_halt(k_msg_freg, (uint32_t)sizeof(k_msg_freg) - 1U);
242 }
243 (void)ra8_app_render(reg);
244 *out_lib = wa_framebuffer_hash();
245
246 if (ra8_app_launch(reg, (uint16_t)k_wa_app_reader) != k_ra8_ok) {
247 wa_panic_halt(k_msg_freg, (uint32_t)sizeof(k_msg_freg) - 1U);
248 }
249 (void)ra8_app_render(reg);
250 *out_rdr = wa_framebuffer_hash();
251}
252
254static void wa_verify_or_halt(uint32_t lib_crc, uint32_t rdr_crc)
255{
256 /* The two app compositions must differ (different content widget). */
257 if (lib_crc == rdr_crc) {
258 wa_panic_halt(k_msg_fcrc, (uint32_t)sizeof(k_msg_fcrc) - 1U);
259 }
260 /* The focus lifecycle must have fired exactly once each. */
261 if ((s_library.leaves != 1U) || (s_reader.enters != 1U) || (s_library.enters != 1U)) {
262 wa_panic_halt(k_msg_flife, (uint32_t)sizeof(k_msg_flife) - 1U);
263 }
264 /* Partial-flush: invalidate ONLY the status bar -> damage is just its rect. */
266 ra8_ui_rect_t dmg = {};
268 uint16_t ndirty = 0U;
269 (void)ra8_widget_damage(s_reader.widgets, 2U, &dmg, &hint, &ndirty);
270 if ((ndirty != 1U) || (dmg.h != (int32_t)k_wa_statusbar_h) || (dmg.y != 0) ||
271 (dmg.w != (int32_t)k_wa_fb_w) || (hint != k_ra8_widget_refresh_fast)) {
272 wa_panic_halt(k_msg_fdmg, (uint32_t)sizeof(k_msg_fdmg) - 1U);
273 }
274}
275
284void main(void)
285{
288 wa_print(k_msg_boot, (uint32_t)sizeof(k_msg_boot) - 1U);
289
291 (uint16_t)k_wa_fb_w,
292 (uint16_t)k_wa_fb_h,
294 wa_panic_halt(k_msg_fail, (uint32_t)sizeof(k_msg_fail) - 1U);
295 }
296
297 /* Two apps, each a widget tree. */
300 ra8_app_t library = {.vt = &k_wa_app_vt,
301 .ctx = &s_library,
302 .id = (uint16_t)k_wa_app_library,
303 .name = "Library",
304 .removable = false};
305 ra8_app_t reader = {.vt = &k_wa_app_vt,
306 .ctx = &s_reader,
307 .id = (uint16_t)k_wa_app_reader,
308 .name = "Reader",
309 .removable = false};
310
311 ra8_app_t* slots[2];
312 ra8_app_registry_t reg = {};
313 if ((ra8_app_registry_init(&reg, slots, 2U) != k_ra8_ok) ||
314 (ra8_app_register(&reg, &library) != k_ra8_ok) ||
315 (ra8_app_register(&reg, &reader) != k_ra8_ok)) {
316 wa_panic_halt(k_msg_freg, (uint32_t)sizeof(k_msg_freg) - 1U);
317 }
318
319 uint32_t lib_crc = 0U;
320 uint32_t rdr_crc = 0U;
321 wa_run_two_apps(&reg, &lib_crc, &rdr_crc);
322 wa_verify_or_halt(lib_crc, rdr_crc);
323
324 wa_print(k_msg_pre, (uint32_t)sizeof(k_msg_pre) - 1U);
325 wa_print_hex(lib_crc);
326 wa_print(k_msg_rdr, (uint32_t)sizeof(k_msg_rdr) - 1U);
327 wa_print_hex(rdr_crc);
328 wa_print(k_msg_flush, (uint32_t)sizeof(k_msg_flush) - 1U);
329 wa_print(k_msg_ok, (uint32_t)sizeof(k_msg_ok) - 1U);
330
331 while (1) {
332 __asm__ volatile("wfi");
333 }
334}
void main(void)
Secure fallback main entry point.
Definition main.c:37
static const uint8_t k_msg_pre[]
Definition main.c:151
static const uint8_t k_msg_ok[]
Definition main.c:153
static const uint8_t k_msg_boot[]
Definition main.c:140
static const uint8_t k_msg_fcrc[]
Definition main.c:149
static const uint8_t k_msg_fail[]
Definition main.c:63
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 mg_reader_t s_reader
The pan/zoom viewer over the tiled page.
Definition main.c:227
static const uint8_t k_msg_fdmg[]
Definition main.c:104
wa_app_id_t
Registered app ids.
Definition main.c:74
@ k_wa_app_reader
EPUB reader app.
Definition main.c:76
@ k_wa_app_library
Library / home app.
Definition main.c:75
static const uint8_t k_msg_freg[]
Definition main.c:101
static void wa_app_leave(ra8_app_t *a)
Definition main.c:203
static void wa_fill_render(ra8_widget_t *w)
Widget render callback: fill the widget's rect with its colour.
Definition main.c:151
static void wa_panic_halt(const uint8_t *msg, uint32_t len)
Print the fail banner and trap (ra8_emulator halts on the BKPT).
Definition main.c:117
wa_consts_t
Console / layout knobs (no magic numbers).
Definition main.c:56
@ k_wa_fb_w
Framebuffer width, pixels.
Definition main.c:58
@ k_wa_col_bg
Framebuffer clear colour.
Definition main.c:61
@ k_wa_nibble_bits
Bits per hex nibble.
Definition main.c:68
@ k_wa_fnv_offset
FNV-1a 32-bit offset basis.
Definition main.c:65
@ k_wa_dec_ten
Hex digit / decimal split.
Definition main.c:70
@ k_wa_hex_nibbles
Hex digits in a 32-bit value.
Definition main.c:67
@ k_wa_statusbar_h
Status-bar widget height.
Definition main.c:60
@ k_wa_nibble_mask
Low-nibble mask.
Definition main.c:69
@ k_wa_col_reader
Reader content fill (orange).
Definition main.c:64
@ k_wa_fnv_prime
FNV-1a 32-bit prime.
Definition main.c:66
@ k_wa_uart_baud
Console baud.
Definition main.c:57
@ k_wa_col_status
Status-bar fill (gray).
Definition main.c:62
@ k_wa_fb_h
Framebuffer height, pixels.
Definition main.c:59
@ k_wa_col_library
Library content fill (blue).
Definition main.c:63
static uint32_t wa_framebuffer_hash(void)
FNV-1a hash over the composited framebuffer.
Definition main.c:127
static void wa_setup_or_halt(void)
Bring up clocks/MSTP/time + the SCI8 console; halt on failure.
Definition main.c:220
static void wa_run_two_apps(ra8_app_registry_t *reg, uint32_t *out_lib, uint32_t *out_rdr)
Launch + composite both apps, returning each composite's hash.
Definition main.c:238
static void wa_print_hex(uint32_t value)
Print a 32-bit value as 8 upper-case hex digits.
Definition main.c:139
static void wa_state_init(wa_app_state_t *st, uint32_t content_color)
Build one app's widget tree: status bar (fixed) over content (flex).
Definition main.c:165
static void wa_verify_or_halt(uint32_t lib_crc, uint32_t rdr_crc)
Assert distinct composites, a fired lifecycle, and a partial flush.
Definition main.c:254
static void wa_print(const uint8_t *msg, uint32_t len)
Emit a byte run on the SCI8 console.
Definition main.c:111
static void wa_app_enter(ra8_app_t *a)
Definition main.c:198
static const ra8_widget_vtable_t k_wa_fill_vt
Shared vtable for the solid-fill widget.
Definition main.c:158
static const uint8_t k_msg_flush[]
Definition main.c:107
static const ra8_app_vtable_t k_wa_app_vt
Shared app lifecycle vtable.
Definition main.c:209
static wa_app_state_t s_library
Definition main.c:96
static void wa_app_render(const ra8_app_t *a)
App.render: lay out + composite the app's widget tree.
Definition main.c:186
static const uint8_t k_msg_flife[]
Definition main.c:103
static const uint8_t k_msg_rdr[]
Definition main.c:106
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_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_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
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_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.
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
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
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
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
Fixed table of registered apps + the focused index.
Definition ra8_app.h:161
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 w
Width (pixels, >= 0).
Definition ra8_ui.h:75
int32_t h
Height (pixels, >= 0).
Definition ra8_ui.h:76
int32_t y
Top edge (pixels).
Definition ra8_ui.h:74
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
wa_fill_t status_fill
Status-bar colour.
Definition main.c:90
wa_fill_t content_fill
Content colour (per app).
Definition main.c:91
uint32_t leaves
Times on_leave fired.
Definition main.c:93
ra8_widget_t widgets[2]
[0] status bar, [1] content.
Definition main.c:89
A solid-fill widget: renders one colour into its rect via ra8_gfx.
Definition main.c:83
uint32_t color
0xRRGGBB fill.
Definition main.c:84