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
12
13#include <signal.h>
14#include <stdalign.h>
15#include <stddef.h>
16#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19#include <time.h>
20#include <unistd.h>
21
22#include "ra8_attributes.h"
23#include "ra8_err.h"
24#include "ra8_io_stream.h"
25#include "ra8_io_stream_posix.h"
26#include "ra8_log.h"
28#include "ra8_viewer_reader.h"
29#include "ra8_viewer_view.h"
30
32typedef enum : int32_t {
33 k_viewer_frame_ns = 16000000,
37 k_viewer_composition_bytes = 32 * 1024 * 1024,
39
41typedef struct {
42 const char* path;
43 const char* dump_ppm;
44 uint32_t page;
45 int64_t dump_tile;
46 bool headless;
48
50alignas(max_align_t) static uint8_t s_viewer_composition[k_viewer_composition_bytes];
51
64RA8_INTERNAL static void internal_usage(ra8_io_stream_t* output, const char* executable)
65{
66 (void)priv_viewer_output_usage(output, executable);
67}
68
85RA8_INTERNAL static bool internal_parse_arguments(int argc, char** argv, viewer_options_t* options)
86{
87 if (argc < (int)k_viewer_min_args) {
88 return false;
89 }
90 *options = (viewer_options_t){.path = argv[1], .dump_tile = -1};
91 for (int index = 2; index < argc; ++index) {
92 if ((strcmp(argv[index], "--page") == 0) && ((index + 1) < argc)) {
93 options->page = (uint32_t)strtoul(argv[++index], nullptr, (int)k_viewer_radix_dec);
94 } else if ((strcmp(argv[index], "--dump-ppm") == 0) && ((index + 1) < argc)) {
95 options->dump_ppm = argv[++index];
96 } else if ((strcmp(argv[index], "--dump-tile") == 0) && ((index + 1) < argc)) {
97 options->dump_tile = strtoll(argv[++index], nullptr, (int)k_viewer_radix_dec);
98 } else if (strcmp(argv[index], "--headless") == 0) {
99 options->headless = true;
100 } else {
101 return false;
102 }
103 }
104 return true;
105}
106
122RA8_INTERNAL static uint32_t internal_clamp_page(uint32_t page, uint32_t count)
123{
124 if (count == 0U) {
125 return 0U;
126 }
127 return (page >= count) ? (count - 1U) : page;
128}
129
146RA8_INTERNAL static bool internal_align_offset(size_t offset, size_t alignment, size_t* out)
147{
148 const size_t mask = alignment - 1U;
149 if ((alignment == 0U) || ((alignment & mask) != 0U) || (offset > (SIZE_MAX - mask))) {
150 return false;
151 }
152 *out = (offset + mask) & ~mask;
153 return true;
154}
155
170 const char* subject,
171 const ra8_viewer_workspace_report_t* report)
172{
173 (void)
174 priv_viewer_output_capacity(output, subject, report->required_bytes, report->supplied_bytes);
175}
176
195 const viewer_options_t* options,
196 uint32_t page,
197 ra8_io_stream_t* diagnostic)
198{
199 const ra8_err_t error = ra8_viewer_render_page(reader, page);
200 if (error != k_ra8_ok) {
201 (void)priv_viewer_output_index_error(diagnostic, "render page ", page, error);
202 return false;
203 }
204 if ((options->dump_ppm != nullptr) &&
205 (ra8_viewer_dump_ppm(reader, options->dump_ppm) != k_ra8_ok)) {
206 (void)priv_viewer_output_text(diagnostic, "dump ppm failed\n");
207 return false;
208 }
209 if (options->dump_ppm != nullptr) {
210 (void)priv_viewer_output_wrote(diagnostic, options->dump_ppm);
211 }
212 return true;
213}
214
236 uint32_t tile,
237 const char* path,
238 void* workspace,
239 size_t workspace_bytes,
240 ra8_io_stream_t* diagnostic)
241{
242 uint32_t width = 0U;
243 uint32_t height = 0U;
244 uint16_t* pixels = nullptr;
246 const ra8_err_t error = ra8_viewer_render_tile565(reader,
247 tile,
248 workspace,
249 workspace_bytes,
250 &width,
251 &height,
252 &pixels,
253 &report);
254 if (error != k_ra8_ok) {
255 if (error == k_ra8_err_invalid_size) {
256 internal_report_capacity(diagnostic, "tile", &report);
257 }
258 (void)priv_viewer_output_index_error(diagnostic, "render tile ", tile, error);
259 return false;
260 }
261 const ra8_err_t write_error = ra8_viewer_write_ppm565(pixels, width, height, path);
262 if (write_error != k_ra8_ok) {
263 (void)priv_viewer_output_error(diagnostic, "write tile ppm", write_error);
264 return false;
265 }
266 (void)priv_viewer_output_tile(diagnostic, tile, width, height, path);
267 return true;
268}
269
289 void* workspace,
290 size_t workspace_bytes,
291 ra8_io_stream_t* diagnostic)
292{
293 ra8_viewer_view_requirements_t requirements = {};
294 if (ra8_viewer_view_requirements(reader, &requirements) != k_ra8_ok) {
295 (void)priv_viewer_output_text(diagnostic,
296 "no window (headless host?); use --headless --dump-ppm PATH\n");
297 return 1;
298 }
299 ra8_viewer_view_t* view = nullptr;
301 const ra8_err_t error = ra8_viewer_view_open(&view,
302 reader,
303 "RA8 Viewer",
304 workspace,
305 workspace_bytes,
306 &requirements,
307 &report);
308 if (error != k_ra8_ok) {
309 if (error == k_ra8_err_invalid_size) {
310 internal_report_capacity(diagnostic, "view", &report);
311 }
312 (void)priv_viewer_output_text(diagnostic,
313 "no window (headless host?); use --headless --dump-ppm PATH\n");
314 return 1;
315 }
316 const struct timespec frame = {.tv_sec = 0, .tv_nsec = k_viewer_frame_ns};
317 while (!ra8_viewer_view_pump(view)) {
318 (void)nanosleep(&frame, nullptr);
319 }
321 return 0;
322}
323
337RA8_INTERNAL static void internal_log_sink(void* context, uint8_t byte)
338{
339 (void)ra8_io_stream_putc((ra8_io_stream_t*)context, (char)byte);
340}
341
360{
361 struct sigaction action = {.sa_handler = SIG_IGN};
362 if ((sigemptyset(&action.sa_mask) != 0) || (sigaction(SIGPIPE, &action, nullptr) != 0)) {
364 }
365 return ra8_io_stream_posix_init(output, state, STDERR_FILENO);
366}
367
388 const ra8_viewer_reader_requirements_t* requirements,
389 const viewer_options_t* options,
390 uint32_t page,
391 ra8_io_stream_t* diagnostic)
392{
393 size_t scratch_offset = 0U;
394 if (!internal_align_offset(requirements->required_bytes, alignof(max_align_t), &scratch_offset) ||
395 (scratch_offset > sizeof(s_viewer_composition))) {
396 return 1;
397 }
398 void* scratch = &s_viewer_composition[scratch_offset];
399 const size_t scratch_bytes = sizeof(s_viewer_composition) - scratch_offset;
400 if (options->dump_tile >= 0) {
401 const char* output = (options->dump_ppm != nullptr) ? options->dump_ppm : "/tmp/ra8_tile.ppm";
402 return internal_dump_tile(reader,
403 (uint32_t)options->dump_tile,
404 output,
405 scratch,
406 scratch_bytes,
407 diagnostic)
408 ? 0
409 : 1;
410 }
411 if (options->headless || (options->dump_ppm != nullptr)) {
412 return internal_render_page(reader, options, page, diagnostic) ? 0 : 1;
413 }
414 return internal_run_window(reader, scratch, scratch_bytes, diagnostic);
415}
416
418int main(int argc, char** argv)
419{
420 ra8_io_stream_t diagnostic = {};
421 ra8_io_stream_posix_state_t diagnostic_state = {};
422 if (internal_bind_diagnostic(&diagnostic, &diagnostic_state) != k_ra8_ok) {
423 return 1;
424 }
426 viewer_options_t options = {};
427 if (!internal_parse_arguments(argc, argv, &options)) {
428 internal_usage(&diagnostic, argv[0]);
429 return 2;
430 }
431 ra8_viewer_reader_requirements_t requirements = {};
432 ra8_err_t error = ra8_viewer_reader_requirements(options.path, &requirements);
433 if (error != k_ra8_ok) {
434 (void)priv_viewer_output_open_error(&diagnostic, options.path, error);
435 return 1;
436 }
437 ra8_viewer_reader_t* reader = nullptr;
439 error = ra8_viewer_reader_bind(&reader,
441 sizeof(s_viewer_composition),
442 &requirements,
443 &report);
444 if (error != k_ra8_ok) {
445 internal_report_capacity(&diagnostic, "reader", &report);
446 (void)priv_viewer_output_open_error(&diagnostic, options.path, error);
447 return 1;
448 }
449 error = ra8_viewer_open(reader, options.path);
450 if (error != k_ra8_ok) {
451 (void)priv_viewer_output_open_error(&diagnostic, options.path, error);
452 return 1;
453 }
454 const uint32_t count = ra8_viewer_page_count(reader);
455 const uint32_t page = internal_clamp_page(options.page, count);
456 (void)priv_viewer_output_opened(&diagnostic, options.path, count);
457 const int status = internal_execute(reader, &requirements, &options, page, &diagnostic);
458 ra8_viewer_close(reader);
459 return status;
460}
void main(void)
Secure fallback main entry point.
Definition main.c:37
static void internal_log_sink(void *ctx, uint8_t byte)
ra8_log byte sink: forward every log byte to the SCI8 console.
Definition main.c:160
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Error Code Definitions for ra8-firmware.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_comm_error
Generic communication error (use a more specific code when possible).
Definition ra8_err.h:399
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
ra8_io targetable byte-stream facade – one writer, many destinations.
ra8_err_t ra8_io_stream_putc(ra8_io_stream_t *s, char c)
Write a single byte to the bound sink.
Borrowed raw-descriptor backend for the portable byte-stream facade.
ra8_err_t ra8_io_stream_posix_init(ra8_io_stream_t *stream, ra8_io_stream_posix_state_t *state, int fd)
Bind a borrowed writable descriptor as a byte-stream sink.
Lightweight Logging Interface for ra8-firmware.
void ra8_log_set_byte_sink(ra8_log_byte_sink_fn_t fn, void *ctx)
Install (or clear) an optional byte sink for log output.
Definition ra8_log.c:56
Private typed diagnostic writers for the host viewer.
ra8_err_t priv_viewer_output_error(ra8_io_stream_t *output, const char *operation, ra8_err_t error)
Write an unnumbered operation failure and hexadecimal status.
ra8_err_t priv_viewer_output_open_error(ra8_io_stream_t *output, const char *path, ra8_err_t error)
Write a document-open failure with its path and status.
ra8_err_t priv_viewer_output_index_error(ra8_io_stream_t *output, const char *operation, uint32_t index, ra8_err_t error)
Write a numbered operation failure and hexadecimal status.
ra8_err_t priv_viewer_output_text(ra8_io_stream_t *output, const char *text)
Write one fixed diagnostic without a terminating byte.
ra8_err_t priv_viewer_output_wrote(ra8_io_stream_t *output, const char *path)
Write a successful path-publication diagnostic.
ra8_err_t priv_viewer_output_usage(ra8_io_stream_t *output, const char *executable)
Write the complete command-line usage message.
ra8_err_t priv_viewer_output_opened(ra8_io_stream_t *output, const char *path, uint32_t page_count)
Write a successful document-open diagnostic.
ra8_err_t priv_viewer_output_tile(ra8_io_stream_t *output, uint32_t tile, uint32_t width, uint32_t height, const char *path)
Write a successful tile-publication diagnostic.
ra8_err_t priv_viewer_output_capacity(ra8_io_stream_t *output, const char *subject, size_t required, size_t supplied)
Write an exact workspace requirement diagnostic.
Caller-owned host JOF/comic reader and RGB565 render surface.
ra8_err_t ra8_viewer_write_ppm565(const uint16_t *px, uint32_t w, uint32_t h, const char *path)
Write arbitrary caller-owned RGB565 pixels as binary PPM.
uint32_t ra8_viewer_page_count(const ra8_viewer_reader_t *reader)
Number of viewport pages in reader, or zero for NULL/closed.
void ra8_viewer_close(ra8_viewer_reader_t *reader)
Close the descriptor and reset reader state without freeing workspace.
ra8_err_t ra8_viewer_open(ra8_viewer_reader_t *reader, const char *path)
Open the document class used to size and bind reader.
ra8_err_t ra8_viewer_render_tile565(ra8_viewer_reader_t *reader, uint32_t index, void *workspace, size_t workspace_bytes, uint32_t *width, uint32_t *height, uint16_t **out_pixels, ra8_viewer_workspace_report_t *report)
Render tile index into caller-owned RGB565 storage.
ra8_err_t ra8_viewer_render_page(ra8_viewer_reader_t *reader, uint32_t page)
Render one page into the reader's fixed RGB565 framebuffer.
ra8_err_t ra8_viewer_dump_ppm(const ra8_viewer_reader_t *reader, const char *path)
Write the current fixed framebuffer as binary PPM.
ra8_err_t ra8_viewer_reader_bind(ra8_viewer_reader_t **out, void *workspace, size_t workspace_bytes, const ra8_viewer_reader_requirements_t *requirements, ra8_viewer_workspace_report_t *report)
Bind one reader state to caller-owned bytes.
ra8_err_t ra8_viewer_reader_requirements(const char *path, ra8_viewer_reader_requirements_t *out)
Inspect path and calculate its exact reader workspace.
struct ra8_viewer_reader ra8_viewer_reader_t
Opaque state bound inside caller-owned workspace.
Caller-owned C ABI for the Cocoa scrolling JOF view.
struct ra8_viewer_view ra8_viewer_view_t
Opaque view state bound inside caller workspace.
ra8_err_t ra8_viewer_view_open(ra8_viewer_view_t **out, ra8_viewer_reader_t *reader, const char *title, void *workspace, size_t workspace_bytes, const ra8_viewer_view_requirements_t *requirements, ra8_viewer_workspace_report_t *report)
Open a scrolling window into caller-owned first-party workspace.
void ra8_viewer_view_close(ra8_viewer_view_t *view)
Close the window and reset borrowed view state without freeing it.
ra8_err_t ra8_viewer_view_requirements(const ra8_viewer_reader_t *reader, ra8_viewer_view_requirements_t *out)
Calculate the exact view workspace for reader.
bool ra8_viewer_view_pump(ra8_viewer_view_t *view)
Drain pending events; true after the window closes.
static void internal_usage(void)
Print CLI usage and the explicit compiled cache ceiling.
Caller-owned state retained by one POSIX stream binding.
Caller-allocated byte-stream handle binding a sink to its context.
Exact immutable layout returned for one document.
size_t required_bytes
Complete workspace extent.
Exact first-party workspace required by one platform view.
Required-versus-supplied evidence from a bind attempt.
Parsed command-line options.
Definition main.c:41
int64_t dump_tile
Tile index, or -1.
Definition main.c:45
bool headless
Do not create a window.
Definition main.c:46
const char * dump_ppm
Output path, or NULL.
Definition main.c:43
uint32_t page
Headless page index.
Definition main.c:44
const char * path
Input document path.
Definition main.c:42
static uint32_t internal_clamp_page(uint32_t page, uint32_t count)
Clamp a requested page into the document.
Definition main.c:122
static void internal_report_capacity(ra8_io_stream_t *output, const char *subject, const ra8_viewer_workspace_report_t *report)
Report exact capacity evidence.
Definition main.c:169
static bool internal_render_page(ra8_viewer_reader_t *reader, const viewer_options_t *options, uint32_t page, ra8_io_stream_t *diagnostic)
Render and optionally write one fixed-framebuffer page.
Definition main.c:194
static ra8_err_t internal_bind_diagnostic(ra8_io_stream_t *output, ra8_io_stream_posix_state_t *state)
Bind standard error through the raw POSIX stream adapter.
Definition main.c:358
viewer_main_config_t
Composition limits and CLI constants.
Definition main.c:32
@ k_viewer_composition_bytes
Entire first-party byte budget.
Definition main.c:37
@ k_viewer_min_args
argv count with an input path.
Definition main.c:34
@ k_viewer_frame_ns
Cooperative pump period.
Definition main.c:33
@ k_viewer_radix_dec
Decimal option radix.
Definition main.c:35
static uint8_t s_viewer_composition[k_viewer_composition_bytes]
Explicit host composition storage; another target may replace it.
Definition main.c:50
static int internal_execute(ra8_viewer_reader_t *reader, const ra8_viewer_reader_requirements_t *requirements, const viewer_options_t *options, uint32_t page, ra8_io_stream_t *diagnostic)
Execute the selected viewer mode over the composition remainder.
Definition main.c:387
static bool internal_dump_tile(ra8_viewer_reader_t *reader, uint32_t tile, const char *path, void *workspace, size_t workspace_bytes, ra8_io_stream_t *diagnostic)
Render and publish one caller-buffered scroll tile.
Definition main.c:235
static int internal_run_window(ra8_viewer_reader_t *reader, void *workspace, size_t workspace_bytes, ra8_io_stream_t *diagnostic)
Open and cooperatively pump the caller-workspace Cocoa view.
Definition main.c:288
static bool internal_align_offset(size_t offset, size_t alignment, size_t *out)
Align a composition offset upward.
Definition main.c:146
static bool internal_parse_arguments(int argc, char **argv, viewer_options_t *options)
Parse the bounded viewer command line.
Definition main.c:85