ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_overlay.c
Go to the documentation of this file.
1
17
18#include "board_overlay.h"
19
20#include <stdint.h>
21#include <stdio.h>
22
24
26typedef struct {
27 uint16_t* pixels;
28 uint16_t stride;
30
47RA8_INTERNAL static bool internal_memory_fill(void* context,
48 uint16_t x,
49 uint16_t y,
50 uint16_t width,
51 uint16_t height,
52 uint16_t color)
53{
54 overlay_memory_context_t* const memory = (overlay_memory_context_t*)context;
55 if ((memory == nullptr) || (memory->pixels == nullptr)) {
56 return false;
57 }
58 for (uint16_t row = 0U; row < height; row++) {
59 uint16_t* const begin =
60 &memory->pixels[((size_t)(y + row) * (size_t)memory->stride) + (size_t)x];
61 for (uint16_t column = 0U; column < width; column++) {
62 begin[column] = color;
63 }
64 }
65 return true;
66}
67
81 int32_t x,
82 int32_t y,
83 const board_led_status_t* led)
84{
85 enum : int32_t {
86 k_dot = 18,
87 };
88 priv_fill_rect(surface, x - 1, y - 1, k_dot + 2, k_dot + 2, (uint16_t)k_ovl_led_ring);
89 const uint16_t fill = led->on ? led->color : (uint16_t)k_ovl_led_off;
90 priv_fill_rect(surface, x, y, k_dot, k_dot, fill);
91 priv_draw_text(surface,
92 x + k_dot + 8,
94 (led->label != nullptr) ? led->label : "LED",
95 (uint16_t)k_ovl_text,
96 1);
97}
98
113RA8_INTERNAL static int32_t
114internal_draw_leds(board_overlay_surface_t* surface, int32_t x, int32_t y, const board_status_t* st)
115{
116 const int32_t row_y = priv_section_head(surface, x, y, "LEDS");
117 for (uint32_t i = 0U; i < (uint32_t)k_overlay_led_count; i++) {
118 internal_draw_led(surface, x + ((int32_t)i * k_led_col_dx), row_y, &st->leds[i]);
119 }
120 return row_y + k_led_row_h;
121}
122
138 int32_t x,
139 int32_t y,
140 const board_status_t* st)
141{
142 enum : uint8_t {
143 k_run_row_cap = 64U,
144 };
145 char buf[k_run_row_cap];
146 int32_t cy = priv_section_head(surface, x, y, "RUN");
147 (void)snprintf(buf, sizeof(buf), "0x%08X", st->pc);
148 cy = priv_kv_row(surface, x, cy, "pc", buf, (uint16_t)k_ovl_heading);
149 (void)snprintf(buf, sizeof(buf), "%s chunk %u", st->running ? "RUNNING" : "parked", st->chunks);
150 cy = priv_kv_row(surface,
151 x,
152 cy,
153 "state",
154 buf,
155 st->running ? (uint16_t)k_ovl_ok : (uint16_t)k_ovl_dim);
156 (void)snprintf(buf, sizeof(buf), "%u rd / %u wr", st->mmio_reads, st->mmio_writes);
157 cy = priv_kv_row(surface, x, cy, "mmio", buf, (uint16_t)k_ovl_text);
158 return cy;
159}
160
176 int32_t x,
177 int32_t y,
178 const board_status_t* st)
179{
180 enum : uint8_t {
181 k_io_row_cap = 96U,
182 };
183 char buf[k_io_row_cap];
184 int32_t cy = priv_section_head(surface, x, y, "I/O");
185 cy = priv_kv_row(surface,
186 x,
187 cy,
188 "usb",
189 (st->usb_state != nullptr) ? st->usb_state : "-",
190 (uint16_t)k_ovl_text);
191 (void)
192 snprintf(buf, sizeof(buf), "%u total IRQ0 x%u IRQ1 x%u", st->irq_total, st->irq0, st->irq1);
193 cy = priv_kv_row(surface, x, cy, "irq", buf, (uint16_t)k_ovl_text);
194 if (st->has_touch) {
195 (void)snprintf(buf, sizeof(buf), "%u, %u", st->touch_x, st->touch_y);
196 } else {
197 (void)snprintf(buf, sizeof(buf), "-");
198 }
199 cy = priv_kv_row(surface, x, cy, "touch", buf, (uint16_t)k_ovl_text);
200 const bool sd_gb = (st->sd_bytes >= (k_sd_unit_div * k_sd_unit_div * k_sd_unit_div));
201 const unsigned long sd_sz =
202 sd_gb ? (unsigned long)(st->sd_bytes / (k_sd_unit_div * k_sd_unit_div * k_sd_unit_div))
203 : (unsigned long)(st->sd_bytes / (k_sd_unit_div * k_sd_unit_div));
204 const char* sd_u = sd_gb ? "GB" : "MB";
205 if (!st->sd_attached) {
206 (void)snprintf(buf, sizeof(buf), "-");
207 } else if (st->sd_fat_bits != 0U) {
208 (void)snprintf(buf,
209 sizeof(buf),
210 "%lu %s FAT%u %s",
211 sd_sz,
212 sd_u,
213 (unsigned)st->sd_fat_bits,
214 (st->sd_label != nullptr) ? st->sd_label : "");
215 } else {
216 (void)snprintf(buf, sizeof(buf), "%lu %s (image)", sd_sz, sd_u);
217 }
218 cy = priv_kv_row(surface, x, cy, "sd", buf, (uint16_t)k_ovl_text);
219 return cy;
220}
221
242RA8_INTERNAL static uint32_t internal_console_tabs_per_row(int32_t panel_w, uint32_t count)
243{
244 if (count == 0U) {
245 return 1U;
246 }
247 int32_t per = panel_w / (int32_t)k_con_tab_min_w;
248 if (per < 1) {
249 per = 1;
250 }
251 if ((uint32_t)per > count) {
252 per = (int32_t)count;
253 }
254 return (uint32_t)per;
255}
256
275RA8_INTERNAL static uint32_t internal_console_tab_row_count(int32_t panel_w, uint32_t count)
276{
277 if (count == 0U) {
278 return 0U;
279 }
280 const uint32_t per_row = internal_console_tabs_per_row(panel_w, count);
281 return (count + per_row - 1U) / per_row;
282}
283
306RA8_INTERNAL static void internal_console_tab_rect(int32_t panel_x,
307 int32_t panel_w,
308 uint32_t idx,
309 uint32_t count,
310 int32_t* r)
311{
312 if (r == nullptr) {
313 return;
314 }
315 const uint32_t per_row = internal_console_tabs_per_row(panel_w, count);
316 const uint32_t row = idx / per_row;
317 const uint32_t col = idx % per_row;
318 const int32_t pitch = panel_w / (int32_t)per_row;
319 r[0] = panel_x + ((int32_t)col * pitch);
320 r[1] = (int32_t)k_con_y + ((int32_t)row * (int32_t)k_con_tab_h);
321 r[2] = pitch - (int32_t)k_con_tab_gap;
322 r[3] = (int32_t)k_con_tab_h - (int32_t)k_con_tab_gap;
323 if (r[2] < 0) {
324 r[2] = 0;
325 }
326 if (r[3] < 0) {
327 r[3] = 0;
328 }
329}
330
354 int32_t panel_x,
355 int32_t panel_w,
356 const board_status_t* st)
357{
358 if (st == nullptr) {
359 return;
360 }
361 uint32_t count = st->console_ch_count;
362 if (count > (uint32_t)k_overlay_console_tabs_max) {
363 count = (uint32_t)k_overlay_console_tabs_max;
364 }
365 for (uint32_t i = 0U; i < count; i++) {
366 int32_t rect[4] = {0, 0, 0, 0};
367 internal_console_tab_rect(panel_x, panel_w, i, count, rect);
368 const bool active = (i == st->console_active_ch);
369 const bool empty = (st->console_ch_count_lines[i] == 0U);
370 uint16_t bg = (uint16_t)k_ovl_tab_off_bg;
371 uint16_t txt = (uint16_t)k_ovl_tab_off_txt;
372 if (active) {
373 bg = (uint16_t)k_ovl_tab_on_bg;
374 txt = (uint16_t)k_ovl_tab_on_txt;
375 } else if (empty) {
376 txt = (uint16_t)k_ovl_tab_empty_txt;
377 }
378 priv_fill_rect(surface, rect[0], rect[1], rect[2], rect[3], bg);
379 enum : uint8_t {
380 k_tab_caption_cap = 24U,
381 };
382 char cap[k_tab_caption_cap];
383 const char* name = (st->console_ch_name[i] != nullptr) ? st->console_ch_name[i] : "?";
384 (void)snprintf(cap, sizeof(cap), "%s %u", name, st->console_ch_count_lines[i]);
385 priv_draw_text(surface,
386 rect[0] + (int32_t)k_con_tab_txt,
387 rect[1] + (int32_t)k_con_tab_cap_y,
388 cap,
389 txt,
390 1);
391 }
392}
393
394/* @brief Paint the tabbed console panel (newest line at the bottom). */
414RA8_INTERNAL static void
416{
417 enum : uint8_t {
418 k_console_head_cap = 80U,
419 };
420 char buf[k_console_head_cap];
421 uint16_t head_col;
422 if (!st->console_autoscroll) {
423 /* Paused: amber heading + how far back the held view sits and how to resume. */
424 (void)snprintf(buf,
425 sizeof(buf),
426 "CONSOLE PAUSED -%u/%u click=follow",
427 st->console_scroll,
428 st->console_total);
429 head_col = (uint16_t)k_ovl_amber;
430 } else {
431 (void)snprintf(buf, sizeof(buf), "CONSOLE LIVE (UART %u B, wheel=scroll)", st->uart_tx_total);
432 head_col = (uint16_t)k_ovl_ok;
433 }
434 priv_draw_text(surface, x, (int32_t)k_con_head_y, buf, head_col, 1);
435 priv_fill_rect(surface,
436 x,
437 (int32_t)k_con_head_y + (int32_t)k_rule_dy,
438 (int32_t)k_ovl_sidebar_w - (2 * (int32_t)k_pad_x),
439 1,
440 (uint16_t)k_ovl_rule);
441}
442
465 int32_t panel_x,
466 int32_t body_y,
467 int32_t body_h,
468 const board_status_t* st)
469{
470 const int32_t max_rows = (body_h - (2 * (int32_t)k_con_pad)) / (int32_t)k_con_line_h;
471 int32_t rows = (int32_t)st->console_count;
472 if (rows > max_rows) {
473 rows = max_rows;
474 }
475 for (int32_t i = 0; i < rows; i++) {
476 /* Bottom row (i=0 from the bottom) is console[0], the newest line. */
477 const int32_t ly = body_y + body_h - (int32_t)k_con_pad - ((i + 1) * (int32_t)k_con_line_h);
478 const uint16_t col = (i == 0) ? (uint16_t)k_ovl_console_new : (uint16_t)k_ovl_console_txt;
479 priv_draw_text(surface, panel_x + (int32_t)k_con_pad, ly, st->console[i], col, 1);
480 }
481}
482
494RA8_INTERNAL static void
496{
497 internal_draw_console_heading(surface, x, st);
498 const int32_t panel_x = x;
499 const int32_t panel_w = (int32_t)k_ovl_sidebar_w - (2 * (int32_t)k_pad_x);
500 const int32_t panel_h = (int32_t)surface->height - (int32_t)k_con_y - (int32_t)k_con_bottom;
501 if (panel_h < (int32_t)k_con_line_h) {
502 return;
503 }
504 priv_fill_rect(surface, panel_x, (int32_t)k_con_y, panel_w, panel_h, (uint16_t)k_ovl_console_bg);
505 /* The tab bar wraps into as many rows as the channel count needs; the scrolling
506 * body fills whatever is left below it. */
507 internal_draw_console_tabs(surface, panel_x, panel_w, st);
508 uint32_t tab_count = st->console_ch_count;
509 if (tab_count > (uint32_t)k_overlay_console_tabs_max) {
510 tab_count = (uint32_t)k_overlay_console_tabs_max;
511 }
512 const int32_t tab_rows = (int32_t)internal_console_tab_row_count(panel_w, tab_count);
513 const int32_t tab_band = tab_rows * (int32_t)k_con_tab_h;
514 const int32_t body_y = (int32_t)k_con_y + tab_band;
515 const int32_t body_h = panel_h - tab_band;
516 if (body_h < (int32_t)k_con_line_h) {
517 return;
518 }
519 /* Fit as many lines as the body height allows; show the newest at the bottom
520 * so the console scrolls upward like a terminal. console[0] is the newest. */
521 internal_draw_console_body(surface, panel_x, body_y, body_h, st);
522}
523
536RA8_INTERNAL static void
537internal_draw_button(board_overlay_surface_t* surface, int32_t x, const char* label, bool pressed)
538{
539 const uint16_t face = pressed ? (uint16_t)k_ovl_btn_down : (uint16_t)k_ovl_btn_up;
540 priv_fill_rect(surface,
541 x - 1,
542 (int32_t)k_btn_y - 1,
543 (int32_t)k_btn_w + 2,
544 (int32_t)k_btn_h + 2,
545 (uint16_t)k_ovl_btn_border);
546 priv_fill_rect(surface, x, (int32_t)k_btn_y, (int32_t)k_btn_w, (int32_t)k_btn_h, face);
547 priv_draw_text(surface,
548 x + (int32_t)k_btn_label_x,
549 (int32_t)k_btn_y + (int32_t)k_btn_label_y,
550 label,
551 (uint16_t)k_ovl_btn_label,
552 2);
553}
554
566RA8_INTERNAL static void
568{
569 (void)priv_section_head(surface, x, (int32_t)k_btn_head_y, "BUTTONS (click)");
570 internal_draw_button(surface, x, "SW1", st->sw1_pressed);
571 internal_draw_button(surface, x + (int32_t)k_btn_w + (int32_t)k_btn_gap, "SW2", st->sw2_pressed);
572}
573
585RA8_INTERNAL static uint8_t internal_battery_clamp(uint8_t soc)
586{
587 return (soc > (uint8_t)k_pwr_soc_full) ? (uint8_t)k_pwr_soc_full : soc;
588}
589
602RA8_INTERNAL static uint16_t internal_battery_fill_color(uint8_t soc, bool charging)
603{
604 if (charging) {
605 return (uint16_t)k_ovl_ok; /* charging always reads green. */
606 }
607 if (soc <= (uint8_t)k_pwr_soc_low) {
608 return (uint16_t)k_ovl_red;
609 }
610 if (soc <= (uint8_t)k_pwr_soc_mid) {
611 return (uint16_t)k_ovl_amber;
612 }
613 return (uint16_t)k_ovl_ok;
614}
615
634RA8_INTERNAL static void
636{
637 (void)priv_section_head(surface, x, (int32_t)k_pwr_head_y, "POWER (drag)");
638 const uint8_t soc = internal_battery_clamp(st->battery_soc);
639 const int32_t fill_w = ((int32_t)k_pwr_track_w * (int32_t)soc) / (int32_t)k_pwr_soc_full;
640 const uint16_t fill = internal_battery_fill_color(soc, st->battery_charging);
641 /* Slider track: border, dark bed, then the SOC-proportional level fill. */
642 priv_fill_rect(surface,
643 x - 1,
644 (int32_t)k_pwr_y - 1,
645 (int32_t)k_pwr_track_w + 2,
646 (int32_t)k_pwr_h + 2,
647 (uint16_t)k_ovl_btn_border);
648 priv_fill_rect(surface,
649 x,
650 (int32_t)k_pwr_y,
651 (int32_t)k_pwr_track_w,
652 (int32_t)k_pwr_h,
653 (uint16_t)k_ovl_btn_up);
654 priv_fill_rect(surface, x, (int32_t)k_pwr_y, fill_w, (int32_t)k_pwr_h, fill);
655 char buf[16];
656 (void)snprintf(buf, sizeof(buf), "%u%%", (unsigned)soc);
657 priv_draw_text(surface,
658 x + (int32_t)k_btn_label_x,
659 (int32_t)k_pwr_y + (int32_t)k_pwr_label_y,
660 buf,
661 (uint16_t)k_ovl_heading,
662 1);
663 /* CHG toggle: green "CHG +" while charging, dim "BATT" on battery. */
664 const int32_t cx = x + (int32_t)k_pwr_chg_off;
665 const uint16_t face = st->battery_charging ? (uint16_t)k_ovl_btn_down : (uint16_t)k_ovl_btn_up;
666 priv_fill_rect(surface,
667 cx - 1,
668 (int32_t)k_pwr_y - 1,
669 (int32_t)k_pwr_chg_w + 2,
670 (int32_t)k_pwr_h + 2,
671 (uint16_t)k_ovl_btn_border);
672 priv_fill_rect(surface, cx, (int32_t)k_pwr_y, (int32_t)k_pwr_chg_w, (int32_t)k_pwr_h, face);
673 priv_draw_text(surface,
674 cx + (int32_t)k_btn_label_x,
675 (int32_t)k_pwr_y + (int32_t)k_pwr_label_y,
676 st->battery_charging ? "CHG +" : "BATT",
677 (uint16_t)k_ovl_btn_label,
678 1);
679}
680
696RA8_INTERNAL static void
698{
699 const int32_t lx = x + (int32_t)k_core_lp_off;
700 const uint16_t face = st->low_power ? (uint16_t)k_ovl_btn_down : (uint16_t)k_ovl_btn_up;
701 priv_fill_rect(surface,
702 lx - 1,
703 (int32_t)k_btn_y - 1,
704 (int32_t)k_core_lp_w + 2,
705 (int32_t)k_btn_h + 2,
706 (uint16_t)k_ovl_btn_border);
707 priv_fill_rect(surface, lx, (int32_t)k_btn_y, (int32_t)k_core_lp_w, (int32_t)k_btn_h, face);
708 char cbuf[16];
709 (void)snprintf(cbuf,
710 sizeof(cbuf),
711 "%s %s",
712 st->core_is_m33 ? "M33" : "M85",
713 st->low_power ? "LP" : "FULL");
714 priv_draw_text(surface,
715 lx + (int32_t)k_btn_label_x,
716 (int32_t)k_btn_y + (int32_t)k_btn_label_y,
717 cbuf,
718 (uint16_t)k_ovl_btn_label,
719 1);
720}
721
724 uint16_t panel_w,
725 const board_status_t* st)
726{
727 if ((surface == nullptr) || !surface->ok || (surface->fill == nullptr) || (panel_w == 0U) ||
728 (surface->width != board_overlay_total_width(panel_w)) ||
729 (surface->height < board_overlay_total_height(1U))) {
730 return false;
731 }
732 priv_fill_rect(surface,
733 (int32_t)panel_w,
734 0,
735 (int32_t)k_ovl_sidebar_w,
736 (int32_t)surface->height,
737 (uint16_t)k_ovl_bg);
738 priv_fill_rect(surface,
739 (int32_t)panel_w,
740 0,
741 3,
742 (int32_t)surface->height,
743 (uint16_t)k_ovl_divider);
744 if (st == nullptr) {
745 return surface->ok;
746 }
747 const int32_t x = (int32_t)panel_w + (int32_t)k_pad_x;
748 int32_t y = k_sidebar_top;
749 /* Title bar: a filled accent band with the board name at 2x scale. */
750 priv_fill_rect(surface,
751 (int32_t)panel_w + 3,
752 0,
753 (int32_t)k_ovl_sidebar_w - 3,
754 (int32_t)k_title_bar_h,
755 (uint16_t)k_ovl_bg_alt);
756 priv_draw_text(surface, x, y, "EK-RA8D2 EMULATOR", (uint16_t)k_ovl_accent, 2);
757 y = (int32_t)k_title_bar_h + (int32_t)k_section_gap;
758 priv_draw_text(surface,
759 x,
760 y,
761 (st->app_name != nullptr) ? st->app_name : "",
762 (uint16_t)k_ovl_heading,
763 1);
764 y += (int32_t)k_title_gap;
765 /* The RUN and LEDS sections sit on the upper sidebar; the layout below them
766 * (I/O, BUTTONS, CONSOLE) uses fixed Y anchors so the console always fills the
767 * bottom regardless of panel height. */
768 y = internal_draw_run_stats(surface, x, y, st);
769 y += (int32_t)k_section_gap;
770 (void)internal_draw_leds(surface, x, y, st);
771 (void)internal_draw_io_block(surface, x, (int32_t)k_io_head_y, st);
772 internal_draw_power(surface, x, st);
773 internal_draw_core(surface, x, st);
774 internal_draw_buttons(surface, x, st);
775 internal_draw_console(surface, x, st);
776 return surface->ok;
777}
778
779void board_overlay_compose(uint16_t* out,
780 const uint16_t* panel,
781 uint16_t panel_w,
782 uint16_t panel_h,
783 const board_status_t* st)
784{
785 if ((out == nullptr) || (panel_w == 0U)) {
786 return;
787 }
788 const uint16_t w = board_overlay_total_width(panel_w);
789 const uint16_t h = board_overlay_total_height(panel_h);
790 priv_blit_panel(out, w, h, panel, panel_w, panel_h);
791 overlay_memory_context_t memory = {.pixels = out, .stride = w};
792 board_overlay_surface_t surface = {.context = &memory,
793 .fill = internal_memory_fill,
794 .width = w,
795 .height = h,
796 .ok = true};
797 (void)board_overlay_draw_sidebar(&surface, panel_w, st);
798}
799
800board_overlay_btn_t board_overlay_hit_button(uint16_t x, uint16_t y, uint16_t panel_w)
801{
802 const int32_t cx = (int32_t)x;
803 const int32_t cy = (int32_t)y;
804 const int32_t side_lo = (int32_t)panel_w;
805 const int32_t side_hi = (int32_t)panel_w + (int32_t)k_ovl_sidebar_w;
806 const bool in_sidex = (cx >= side_lo) && (cx < side_hi);
807 /* SW1 / SW2 push-buttons. */
808 if ((cy >= (int32_t)k_btn_y) && (cy < ((int32_t)k_btn_y + (int32_t)k_btn_h))) {
809 const int32_t bx1 = (int32_t)panel_w + (int32_t)k_btn_x_dx;
810 if ((cx >= bx1) && (cx < (bx1 + (int32_t)k_btn_w))) {
812 }
813 const int32_t bx2 = bx1 + (int32_t)k_btn_w + (int32_t)k_btn_gap;
814 if ((cx >= bx2) && (cx < (bx2 + (int32_t)k_btn_w))) {
816 }
817 }
818 /* POWER row: the battery slider track and the CHG toggle share one row. */
819 if ((cy >= (int32_t)k_pwr_y) && (cy < ((int32_t)k_pwr_y + (int32_t)k_pwr_h))) {
820 const int32_t sx = (int32_t)panel_w + (int32_t)k_pwr_x_dx;
821 if ((cx >= sx) && (cx < (sx + (int32_t)k_pwr_track_w))) {
823 }
824 const int32_t cgx = sx + (int32_t)k_pwr_chg_off;
825 if ((cx >= cgx) && (cx < (cgx + (int32_t)k_pwr_chg_w))) {
827 }
828 }
829 /* Core / low-power toggle: shares the BUTTONS row, right of SW1/SW2. */
830 if ((cy >= (int32_t)k_btn_y) && (cy < ((int32_t)k_btn_y + (int32_t)k_btn_h))) {
831 const int32_t lx = (int32_t)panel_w + (int32_t)k_btn_x_dx + (int32_t)k_core_lp_off;
832 if ((cx >= lx) && (cx < (lx + (int32_t)k_core_lp_w))) {
834 }
835 }
836 /* Console region (heading + panel): a click toggles autoscroll / jumps live,
837 * like clicking the Arduino Serial Monitor's pane. */
838 if (in_sidex && (cy >= (int32_t)k_con_head_y)) {
840 }
842}
843
844bool board_overlay_battery_pct_at(uint16_t x, uint16_t panel_w, uint8_t* out_pct)
845{
846 if (out_pct == nullptr) {
847 return false;
848 }
849 const int32_t cx = (int32_t)x;
850 const int32_t sx = (int32_t)panel_w + (int32_t)k_pwr_x_dx;
851 if (cx <= sx) {
852 *out_pct = 0U;
853 } else if (cx >= (sx + (int32_t)k_pwr_track_w)) {
854 *out_pct = (uint8_t)k_pwr_soc_full;
855 } else {
856 *out_pct = (uint8_t)(((cx - sx) * (int32_t)k_pwr_soc_full) / (int32_t)k_pwr_track_w);
857 }
858 return true;
859}
860
862 uint16_t y,
863 uint16_t panel_w,
864 uint32_t tab_count,
865 uint32_t* out_idx)
866{
867 if (out_idx == nullptr) {
868 return false;
869 }
870 if (tab_count == 0U) {
871 return false;
872 }
873 uint32_t count = tab_count;
874 if (count > (uint32_t)k_overlay_console_tabs_max) {
875 count = (uint32_t)k_overlay_console_tabs_max;
876 }
877 const int32_t cx = (int32_t)x;
878 const int32_t cy = (int32_t)y;
879 const int32_t origin_x = (int32_t)panel_w + (int32_t)k_pad_x;
880 const int32_t pan_w = (int32_t)k_ovl_sidebar_w - (2 * (int32_t)k_pad_x);
881 /* Point-in-cell test against the wrapping grid: each cell carries its own
882 * row y, so a click resolves to the right tab on any row. The four bounds are
883 * split into separate guards (no compound decision) so each edge is its own
884 * branch. */
885 for (uint32_t i = 0U; i < count; i++) {
886 int32_t rect[4] = {0, 0, 0, 0};
887 internal_console_tab_rect(origin_x, pan_w, i, count, rect);
888 if (cx < rect[0]) {
889 continue;
890 }
891 if (cx >= (rect[0] + rect[2])) {
892 continue;
893 }
894 if (cy < rect[1]) {
895 continue;
896 }
897 if (cy >= (rect[1] + rect[3])) {
898 continue;
899 }
900 *out_idx = i;
901 return true;
902 }
903 return false;
904}
static void internal_draw_console(board_overlay_surface_t *surface, int32_t x, const board_status_t *st)
Perform draw console for the board overlay model.
static void internal_draw_button(board_overlay_surface_t *surface, int32_t x, const char *label, bool pressed)
Draw one labelled push-button face at x (green when pressed).
static uint32_t internal_console_tabs_per_row(int32_t panel_w, uint32_t count)
Tabs drawn per row for a wrapping tab grid of count cells.
static uint32_t internal_console_tab_row_count(int32_t panel_w, uint32_t count)
Number of rows a wrapping tab grid of count cells occupies.
static int32_t internal_draw_run_stats(board_overlay_surface_t *surface, int32_t x, int32_t y, const board_status_t *st)
Paint the run-stats block (PC / chunks / MMIO / state); next free y.
bool board_overlay_draw_sidebar(board_overlay_surface_t *surface, uint16_t panel_w, const board_status_t *st)
Paint the sidebar background, divider, title and all status sections.
board_overlay_btn_t board_overlay_hit_button(uint16_t x, uint16_t y, uint16_t panel_w)
Classify a composite-space click against the sidebar's on-screen buttons.
static uint16_t internal_battery_fill_color(uint8_t soc, bool charging)
Pick the battery gauge fill colour: green charging, else red/amber/green by level.
static void internal_console_tab_rect(int32_t panel_x, int32_t panel_w, uint32_t idx, uint32_t count, int32_t *r)
Compute one console tab's cell rectangle in the wrapping grid.
static void internal_draw_led(board_overlay_surface_t *surface, int32_t x, int32_t y, const board_led_status_t *led)
Draw one LED indicator dot (filled when on) plus its caption.
bool board_overlay_hit_console_tab(uint16_t x, uint16_t y, uint16_t panel_w, uint32_t tab_count, uint32_t *out_idx)
Map a composite-space click on the console tab bar to a tab index.
static void internal_draw_buttons(board_overlay_surface_t *surface, int32_t x, const board_status_t *st)
Paint the "BUTTONS" heading and the clickable SW1 / SW2 buttons.
static void internal_draw_console_tabs(board_overlay_surface_t *surface, int32_t panel_x, int32_t panel_w, const board_status_t *st)
Draw the wrapping console tab bar at the top of the console panel.
void board_overlay_compose(uint16_t *out, const uint16_t *panel, uint16_t panel_w, uint16_t panel_h, const board_status_t *st)
Render the full composite (panel region + status sidebar) into out.
static void internal_draw_console_heading(board_overlay_surface_t *surface, int32_t x, const board_status_t *st)
Draw the console heading line and its rule.
static bool internal_memory_fill(void *context, uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color)
Fill one already-clipped rectangle in a contiguous RGB565 surface.
static int32_t internal_draw_leds(board_overlay_surface_t *surface, int32_t x, int32_t y, const board_status_t *st)
Paint the three LED indicators in a row; returns the next free y.
static uint8_t internal_battery_clamp(uint8_t soc)
Clamp a SOC value to 0..100 for display.
static void internal_draw_core(board_overlay_surface_t *surface, int32_t x, const board_status_t *st)
Paint the primary-core / low-power toggle on the right of the BUTTONS row.
static void internal_draw_console_body(board_overlay_surface_t *surface, int32_t panel_x, int32_t body_y, int32_t body_h, const board_status_t *st)
Draw the scrolling console body below the tab bar.
static void internal_draw_power(board_overlay_surface_t *surface, int32_t x, const board_status_t *st)
Paint the POWER section: a drag-to-set battery slider and a CHG toggle.
static int32_t internal_draw_io_block(board_overlay_surface_t *surface, int32_t x, int32_t y, const board_status_t *st)
Paint the I/O block (USB / IRQ / touch / SD); returns next free y.
bool board_overlay_battery_pct_at(uint16_t x, uint16_t panel_w, uint8_t *out_pct)
Map a click column on the battery slider track to a 0..100 SOC percent.
Composite board-view renderer: panel framebuffer + a status sidebar.
uint16_t board_overlay_total_width(uint16_t panel_w)
Total composite width for a panel of width panel_w.
board_overlay_btn_t
On-screen sidebar control a click landed on.
@ k_board_overlay_btn_sw2
On-screen SW2 (P008) push-button.
@ k_board_overlay_btn_console
Console panel: toggle autoscroll.
@ k_board_overlay_btn_battery
Battery slider track: set SOC.
@ k_board_overlay_btn_batt_chg
Battery CHG button: toggle charge.
@ k_board_overlay_btn_none
Click did not land on a control.
@ k_board_overlay_btn_lowpower
CORE low-power toggle button.
@ k_board_overlay_btn_sw1
On-screen SW1 (P009) push-button.
@ k_overlay_console_tabs_max
Tab-bar capacity (channels = tabs).
uint16_t board_overlay_total_height(uint16_t panel_h)
Total composite height for a panel of height panel_h.
@ k_overlay_led_count
LED1 / LED2 / LED3 (mirrors the BSP).
Module-private layout constants + draw primitives for the overlay.
int32_t priv_draw_text(board_overlay_surface_t *surface, int32_t x, int32_t y, const char *s, uint16_t color, int32_t sc)
Draw a NUL-terminated string; returns the x after the last glyph.
@ k_btn_head_y
"BUTTONS" heading row.
@ k_btn_gap
Horizontal gap between SW1 and SW2.
@ k_btn_y
Button face top.
@ k_btn_w
Button face width.
@ k_btn_label_y
Caption top inset within the button face.
@ k_btn_x_dx
Button column inset from the sidebar origin.
@ k_btn_label_x
Caption inset within the button face.
@ k_btn_h
Button face height.
@ k_sd_unit_div
Bytes per KiB step (KiB->MiB->GiB ladder).
@ k_con_tab_h
Tab-bar row height (one row of the grid).
@ k_con_pad
Inner padding inside the console panel.
@ k_con_line_h
Vertical step between console text lines.
@ k_con_head_y
"CONSOLE" heading row.
@ k_con_tab_cap_y
Caption y-offset within a tab row.
@ k_con_tab_gap
Gap between adjacent tab cells.
@ k_con_y
Console panel top.
@ k_con_tab_txt
Caption inset within a tab cell.
@ k_con_tab_min_w
Minimum tab-cell pitch; sets tabs-per-row.
@ k_con_bottom
Bottom margin below the console panel.
@ k_title_bar_h
Title-bar band height (board name at 2x).
@ k_section_gap
Gap above a section heading.
@ k_rule_dy
Heading baseline to its underline rule.
@ k_led_col_dx
Horizontal spacing between LEDs.
@ k_led_row_h
LED row height (advance to next block).
@ k_title_gap
Title line to the app-name line.
@ k_sidebar_top
Sidebar top margin.
@ k_led_label_dy
LED label vertical offset within its dot.
@ k_pad_x
Left padding inside the sidebar.
@ k_ovl_tab_empty_txt
Inactive empty tab.
@ k_ovl_rule
Thin horizontal section rule.
@ k_ovl_tab_off_bg
Inactive tab background.
@ k_ovl_btn_up
Button face, released.
@ k_ovl_btn_border
On-screen button outline.
@ k_ovl_ok
Green "running / ok" indicator.
@ k_ovl_amber
Amber attention indicator.
@ k_ovl_console_txt
Console text (terminal green).
@ k_ovl_console_bg
Near-black console background.
@ k_ovl_text
Light-grey body text.
@ k_ovl_divider
Panel/sidebar divider.
@ k_ovl_heading
White heading text.
@ k_ovl_tab_off_txt
Inactive tab with traffic.
@ k_ovl_bg
Dark slate sidebar background.
@ k_ovl_btn_label
Button caption text.
@ k_ovl_accent
Cyan title accent.
@ k_ovl_console_new
Newest line (white).
@ k_ovl_bg_alt
Lighter section band.
@ k_ovl_led_off
Unlit LED dot.
@ k_ovl_tab_on_bg
Active tab background.
@ k_ovl_led_ring
LED dot outline.
@ k_ovl_btn_down
Button face, pressed (green).
@ k_ovl_sidebar_w
Sidebar width.
@ k_ovl_red
Low-SOC red gauge.
@ k_ovl_tab_on_txt
Active tab caption.
@ k_ovl_dim
Dim label text (field names).
@ k_io_head_y
"I/O" section heading row (clear of the LEDs).
@ k_pwr_head_y
"POWER" heading row.
@ k_pwr_soc_full
SOC clamp / percent denominator.
@ k_pwr_x_dx
POWER column inset from the sidebar origin.
@ k_pwr_chg_w
CHG toggle face width.
@ k_core_lp_off
Low-power toggle x offset (right of SW1/SW2).
@ k_pwr_h
Slider track height.
@ k_pwr_track_w
Slider track width (the full drag range).
@ k_pwr_soc_low
SOC at or below this draws the gauge red.
@ k_pwr_soc_mid
SOC at or below this draws the gauge amber.
@ k_pwr_chg_off
CHG toggle x offset from the track origin.
@ k_core_lp_w
Low-power toggle face width.
@ k_pwr_y
Battery slider track top.
@ k_pwr_label_y
Caption top inset within a POWER face.
void priv_blit_panel(uint16_t *out, uint16_t w, uint16_t h, const uint16_t *panel, uint16_t panel_w, uint16_t panel_h)
Blit the rendered panel into the composite's panel region.
int32_t priv_section_head(board_overlay_surface_t *surface, int32_t x, int32_t y, const char *title)
Draw a section heading (accent colour) with a thin rule beneath it.
void priv_fill_rect(board_overlay_surface_t *surface, int32_t x, int32_t y, int32_t rw, int32_t rh, uint16_t color)
Fill a clipped rectangle in the composite (draw primitive).
int32_t priv_kv_row(board_overlay_surface_t *surface, int32_t x, int32_t y, const char *label, const char *value, uint16_t val_color)
Draw a "label value" row: dim label, coloured value; returns next y.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
One board LED's live state for the status sidebar.
const char * label
Short ASCII caption (e.g.
uint16_t color
RGB565 lit colour (blue / green / red).
bool on
True when the GPIO pin is driven high.
Non-owning drawing surface used by memory and raw-fd compositors.
board_overlay_fill_fn fill
Clipped solid-rectangle writer.
bool ok
Sticky false after a sink write fault.
uint16_t width
Complete composite width in pixels.
uint16_t height
Complete composite height in pixels.
Live peripheral snapshot the status sidebar renders each frame.
uint16_t touch_y
Last touch Y (if any).
char console[k_overlay_console_rows][k_overlay_line_cap]
Visible lines (active tab).
const char * app_name
App / window title.
uint32_t console_ch_count
Tabs to draw (<= max).
bool battery_charging
Fuel gauge reports charge.
uint32_t irq1
IRQ1 taken count.
uint32_t mmio_writes
Modelled-peripheral MMIO writes served.
uint16_t touch_x
Last touch X (if any).
uint8_t battery_soc
Fuel-gauge SOC percent.
bool core_is_m33
Primary core is the M33.
uint32_t console_active_ch
Active tab index.
bool console_autoscroll
True = following live tail; false=paused.
board_led_status_t leds[k_overlay_led_count]
Per-LED indicator state.
uint32_t console_total
Total lines in the active channel ring.
uint32_t console_ch_count_lines[k_overlay_console_tabs_max]
Per-tab line count.
uint32_t uart_tx_total
Total UART TX bytes the firmware emitted.
uint32_t irq0
IRQ0 taken count.
uint64_t sd_bytes
SD card size in bytes (>4GB).
bool sw1_pressed
On-screen SW1 held down.
bool sd_attached
A microSD card is attached.
uint32_t console_count
Visible lines populated (<= rows).
const char * console_ch_name[k_overlay_console_tabs_max]
Per-tab caption.
const char * sd_label
SD volume label (–sd-new).
bool low_power
Low-power (M33 4:1 clock) on.
uint32_t console_scroll
Lines scrolled back from newest (0=live).
uint8_t sd_fat_bits
12/16/32 if –sd-new, else 0.
uint32_t chunks
Emulation chunks run so far.
bool running
True while the run loop is live (not parked).
uint32_t pc
Current emulated program counter.
const char * usb_state
USB device state string.
uint32_t mmio_reads
Modelled-peripheral MMIO reads served.
bool has_touch
A touch has been drained.
bool sw2_pressed
On-screen SW2 held down.
uint32_t irq_total
Total NVIC IRQs taken.
Context adapting the legacy contiguous composite to a fill surface.
uint16_t * pixels
Caller-owned row-major RGB565 pixels.
uint16_t stride
Complete composite row width.