ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
usb_host_file_ops_steps.c
Go to the documentation of this file.
1
23
25
26#include <stdint.h>
27
28#include "ra8_board_ek_ra8d2.h"
29#include "ra8_err.h"
30#include "ra8_fs.h"
31#include "ra8_io_blockdev.h"
33
34/* =============================================================================
35 * Test fixtures
36 * =============================================================================
37 */
38
40static const char k_fileops_name_a[] = "USBTEST.TXT";
41
43static const char k_fileops_name_b[] = "USBDONE.TXT";
44
46static const uint8_t k_fileops_payload[] =
47 "ra8d2 usb-hs host file-ops payload 0123456789 the quick brown fox\r\n";
48
49/* =============================================================================
50 * Console helpers
51 * =============================================================================
52 */
53
67static uint8_t fileops_nibble_to_hex(uint32_t nibble)
68{
69 if (nibble < k_fileops_hex_digit_split) {
70 return (uint8_t)((uint8_t)'0' + (uint8_t)nibble);
71 }
72 return (uint8_t)((uint8_t)'A' + (uint8_t)nibble - (uint8_t)k_fileops_hex_digit_split);
73}
74
88static uint32_t fileops_str_len(const char* text)
89{
90 uint32_t len = 0U;
91 while (len < (uint32_t)k_fileops_print_cap) {
92 if (text[len] == '\0') {
93 break;
94 }
95 len++;
96 }
97 return len;
98}
99
114static bool fileops_name_eq(const char* a, const char* b)
115{
116 for (uint32_t i = 0U; i < (uint32_t)k_fileops_name_cap; i++) {
117 if (a[i] != b[i]) {
118 return false;
119 }
120 if (a[i] == '\0') {
121 return true;
122 }
123 }
124 return false;
125}
126
141[[nodiscard]] static ra8_err_t fileops_sci_write(const uint8_t* data, uint32_t len)
142{
143 return ra8_board_uart_console_write(data, (size_t)len);
144}
145
146[[nodiscard]] ra8_err_t fileops_print(const char* text)
147{
148 return fileops_sci_write((const uint8_t*)text, fileops_str_len(text));
149}
150
151[[nodiscard]] ra8_err_t fileops_print_dec(uint64_t value)
152{
153 uint8_t scratch[k_fileops_dec_chars_u64] = {};
154 uint8_t out[k_fileops_dec_chars_u64] = {};
155 uint8_t count = 0U;
156 uint64_t v = value;
157 if (v == 0U) {
158 out[0] = (uint8_t)'0';
159 return fileops_sci_write(out, 1U);
160 }
161 while ((v != 0U) && (count < (uint8_t)k_fileops_dec_chars_u64)) {
162 scratch[count] = (uint8_t)((uint8_t)'0' + (uint8_t)(v % k_fileops_dec_radix));
163 v = v / k_fileops_dec_radix;
164 count++;
165 }
166 for (uint8_t i = 0U; i < count; i++) {
167 out[i] = scratch[count - 1U - i];
168 }
169 return fileops_sci_write(out, (uint32_t)count);
170}
171
172[[nodiscard]] ra8_err_t fileops_print_hex(uint32_t value, uint8_t digits)
173{
174 uint8_t out[k_fileops_hex_chars_u32] = {};
175 uint8_t width = digits;
176 if (width > (uint8_t)k_fileops_hex_chars_u32) {
177 width = (uint8_t)k_fileops_hex_chars_u32;
178 }
179 for (uint8_t i = 0U; i < width; i++) {
180 const uint8_t shift = (uint8_t)((width - 1U - i) * k_fileops_nibble_bits);
181 out[i] = fileops_nibble_to_hex((value >> shift) & k_fileops_nibble_mask);
182 }
183 return fileops_sci_write(out, (uint32_t)width);
184}
185
186[[nodiscard]] ra8_err_t fileops_print_fail(const char* what, ra8_err_t err)
187{
188 ra8_err_t e = fileops_print("ra8d2 fileops: FAIL ");
189 if (e != k_ra8_ok) {
190 return e;
191 }
192 e = fileops_print(what);
193 if (e != k_ra8_ok) {
194 return e;
195 }
196 e = fileops_print(" err=0x");
197 if (e != k_ra8_ok) {
198 return e;
199 }
200 e = fileops_print_hex((uint32_t)err, (uint8_t)k_fileops_hex_chars_u32);
201 if (e != k_ra8_ok) {
202 return e;
203 }
204 return fileops_print("\r\n");
205}
206
207/* =============================================================================
208 * ra8_io USB-MSC block device behind the ra8_fs mount
209 * =============================================================================
210 */
211
227
241
255static const char* fileops_fs_type_name(ra8_fs_type_t type)
256{
257 switch (type) {
259 return "fat12";
261 return "fat16";
263 return "fat32";
265 return "exfat";
267 default:
268 return "unknown";
269 }
270}
271
273{
276 (uint8_t)k_fileops_target_lun);
277 if (err != k_ra8_ok) {
278 (void)fileops_print_fail("blockdev", err);
279 return err;
280 }
281 ra8_fs_backend_t backend = {};
283 if (err != k_ra8_ok) {
284 (void)fileops_print_fail("backend", err);
285 return err;
286 }
287 err = ra8_fs_mount(&backend, out_mount);
288 if (err != k_ra8_ok) {
289 (void)fileops_print_fail("mount", err);
290 return err;
291 }
292 err = fileops_print("ra8d2 fileops: mounted fs=");
293 if (err != k_ra8_ok) {
294 return err;
295 }
296 err = fileops_print(fileops_fs_type_name((*out_mount)->type));
297 if (err != k_ra8_ok) {
298 return err;
299 }
300 err = fileops_print(" base_lba=");
301 if (err != k_ra8_ok) {
302 return err;
303 }
304 err = fileops_print_dec((*out_mount)->partition_base_lba);
305 if (err != k_ra8_ok) {
306 return err;
307 }
308 return fileops_print("\r\n");
309}
310
311/* =============================================================================
312 * Directory listing
313 * =============================================================================
314 */
315
320typedef struct {
321 const char* want;
322 const char* avoid;
323 uint8_t found_want;
324 uint8_t found_avoid;
325 uint32_t count;
327
342static void fileops_listdir_cb(const char* name, uint8_t attr, uint64_t size, void* ctx)
343{
345 c->count++;
346 (void)fileops_print("ra8d2 fileops: - ");
347 (void)fileops_print(name);
348 if ((attr & (uint8_t)k_ra8_fs_attr_directory) != 0U) {
349 (void)fileops_print(" <dir>");
350 } else {
351 (void)fileops_print(" size=");
352 (void)fileops_print_dec(size);
353 }
354 (void)fileops_print("\r\n");
355 if (c->want != nullptr) {
356 if (fileops_name_eq(name, c->want)) {
357 c->found_want = 1U;
358 }
359 }
360 if (c->avoid != nullptr) {
361 if (fileops_name_eq(name, c->avoid)) {
362 c->found_avoid = 1U;
363 }
364 }
365}
366
383[[nodiscard]] static ra8_err_t
384fileops_step_listdir(ra8_fs_mount_t* mount, const char* want, const char* avoid)
385{
387 .want = want,
388 .avoid = avoid,
389 .found_want = 0U,
390 .found_avoid = 0U,
391 .count = 0U,
392 };
393 ra8_err_t err = fileops_print("ra8d2 fileops: -- listdir / --\r\n");
394 if (err != k_ra8_ok) {
395 return err;
396 }
397 err = ra8_fs_listdir(mount, "/", fileops_listdir_cb, &ctx);
398 if (err != k_ra8_ok) {
399 (void)fileops_print_fail("listdir", err);
400 return err;
401 }
402 err = fileops_print("ra8d2 fileops: entries=");
403 if (err != k_ra8_ok) {
404 return err;
405 }
406 err = fileops_print_dec(ctx.count);
407 if (err != k_ra8_ok) {
408 return err;
409 }
410 err = fileops_print("\r\n");
411 if (err != k_ra8_ok) {
412 return err;
413 }
414 if (want != nullptr) {
415 if (ctx.found_want == 0U) {
416 (void)fileops_print_fail("listdir expected-name missing", k_ra8_err_not_found);
417 return k_ra8_err_not_found;
418 }
419 }
420 if (avoid != nullptr) {
421 if (ctx.found_avoid != 0U) {
422 (void)fileops_print_fail("listdir stale-name present", k_ra8_err_exists);
423 return k_ra8_err_exists;
424 }
425 }
426 return k_ra8_ok;
427}
428
429/* =============================================================================
430 * File-operation steps
431 * =============================================================================
432 */
433
449[[nodiscard]] static ra8_err_t fileops_read_back(ra8_fs_mount_t* mount, const char* path)
450{
451 static uint8_t s_read_buf[k_fileops_sector_bytes] = {};
452
453 const uint32_t payload_len = (uint32_t)(sizeof(k_fileops_payload) - 1U);
454 ra8_fs_file_t* file = nullptr;
455 ra8_err_t err = ra8_fs_open(mount, path, k_ra8_fs_mode_read, &file);
456 if (err != k_ra8_ok) {
457 (void)fileops_print_fail("open for read-back", err);
458 return err;
459 }
460 uint32_t got = 0U;
461 err = ra8_fs_read(file, s_read_buf, (uint32_t)sizeof(s_read_buf), &got);
462 (void)ra8_fs_close(file);
463 if (err != k_ra8_ok) {
464 (void)fileops_print_fail("read", err);
465 return err;
466 }
467 if (got != payload_len) {
468 (void)fileops_print_fail("read-back length", k_ra8_err_invalid_size);
470 }
471 for (uint32_t i = 0U; i < payload_len; i++) {
472 if (s_read_buf[i] != k_fileops_payload[i]) {
473 (void)fileops_print_fail("read-back content", k_ra8_err_invalid_state);
475 }
476 }
477 return k_ra8_ok;
478}
479
494[[nodiscard]] static ra8_err_t fileops_expect_absent(ra8_fs_mount_t* mount, const char* path)
495{
496 ra8_fs_file_t* file = nullptr;
497 ra8_err_t err = ra8_fs_open(mount, path, k_ra8_fs_mode_read, &file);
498 if (err == k_ra8_ok) {
499 (void)ra8_fs_close(file);
500 (void)fileops_print_fail("name still present", k_ra8_err_exists);
501 return k_ra8_err_exists;
502 }
503 if (err != k_ra8_err_not_found) {
504 (void)fileops_print_fail("absence lookup", err);
505 return err;
506 }
507 return k_ra8_ok;
508}
509
523[[nodiscard]] static ra8_err_t fileops_step_write(ra8_fs_mount_t* mount)
524{
525 ra8_err_t err = fileops_print("ra8d2 fileops: [3/9] write USBTEST.TXT len=");
526 if (err != k_ra8_ok) {
527 return err;
528 }
529 err = fileops_print_dec((uint32_t)(sizeof(k_fileops_payload) - 1U));
530 if (err != k_ra8_ok) {
531 return err;
532 }
533 err = fileops_print("\r\n");
534 if (err != k_ra8_ok) {
535 return err;
536 }
537 err = ra8_fs_write_file(mount,
540 (uint32_t)(sizeof(k_fileops_payload) - 1U));
541 if (err != k_ra8_ok) {
542 (void)fileops_print_fail("write", err);
543 return err;
544 }
545 return k_ra8_ok;
546}
547
549{
550 ra8_err_t err = fileops_print("ra8d2 fileops: [1/9] cleanup leftovers\r\n");
551 if (err != k_ra8_ok) {
552 return err;
553 }
554 (void)ra8_fs_unlink(mount, k_fileops_name_a);
555 (void)ra8_fs_unlink(mount, k_fileops_name_b);
557
558 err = fileops_print("ra8d2 fileops: [2/9] baseline root listing\r\n");
559 if (err != k_ra8_ok) {
560 return err;
561 }
562 err = fileops_step_listdir(mount, nullptr, nullptr);
563 if (err != k_ra8_ok) {
564 return err;
565 }
567
568 err = fileops_step_write(mount);
569 if (err != k_ra8_ok) {
570 return err;
571 }
573
574 err = fileops_print("ra8d2 fileops: [4/9] read back + verify payload\r\n");
575 if (err != k_ra8_ok) {
576 return err;
577 }
579 if (err != k_ra8_ok) {
580 return err;
581 }
583
584 err = fileops_print("ra8d2 fileops: [5/9] listdir must show USBTEST.TXT\r\n");
585 if (err != k_ra8_ok) {
586 return err;
587 }
588 err = fileops_step_listdir(mount, k_fileops_name_a, nullptr);
589 if (err != k_ra8_ok) {
590 return err;
591 }
593 return k_ra8_ok;
594}
595
597{
598 ra8_err_t err = fileops_print("ra8d2 fileops: [6/9] rename USBTEST.TXT -> USBDONE.TXT\r\n");
599 if (err != k_ra8_ok) {
600 return err;
601 }
603 if (err != k_ra8_ok) {
604 (void)fileops_print_fail("rename", err);
605 return err;
606 }
608
609 err = fileops_print("ra8d2 fileops: [7/9] old name gone, new name intact\r\n");
610 if (err != k_ra8_ok) {
611 return err;
612 }
614 if (err != k_ra8_ok) {
615 return err;
616 }
618 if (err != k_ra8_ok) {
619 return err;
620 }
622
623 err = fileops_print("ra8d2 fileops: [8/9] listdir must show USBDONE.TXT only\r\n");
624 if (err != k_ra8_ok) {
625 return err;
626 }
628 if (err != k_ra8_ok) {
629 return err;
630 }
632
633 err = fileops_print("ra8d2 fileops: [9/9] unlink USBDONE.TXT\r\n");
634 if (err != k_ra8_ok) {
635 return err;
636 }
637 err = ra8_fs_unlink(mount, k_fileops_name_b);
638 if (err != k_ra8_ok) {
639 (void)fileops_print_fail("unlink", err);
640 return err;
641 }
643 if (err != k_ra8_ok) {
644 return err;
645 }
646 err = fileops_step_listdir(mount, nullptr, k_fileops_name_b);
647 if (err != k_ra8_ok) {
648 return err;
649 }
651 return k_ra8_ok;
652}
653
654/* =============================================================================
655 * Mount-failure layout probe (diagnostic)
656 * =============================================================================
657 */
658
672static void fileops_dump_rows(const uint8_t* data, uint32_t offset, uint32_t len)
673{
674 for (uint32_t i = 0U; i < len; i++) {
675 if ((i % (uint32_t)k_fileops_probe_row) == 0U) {
676 (void)fileops_print("ra8d2 fileops: 0x");
677 (void)fileops_print_hex(offset + i, (uint8_t)k_fileops_hex_chars_u16);
678 (void)fileops_print(":");
679 }
680 (void)fileops_print(" ");
681 (void)fileops_print_hex((uint32_t)data[offset + i], 2U);
682 if ((i % (uint32_t)k_fileops_probe_row) == ((uint32_t)k_fileops_probe_row - 1U)) {
683 (void)fileops_print("\r\n");
684 }
685 }
686}
687
689{
690 static uint8_t s_probe_buf[k_fileops_sector_bytes] = {};
691
692 for (uint32_t lba = 0U; lba < (uint32_t)k_fileops_probe_lba_max; lba++) {
693 if (ra8_io_blockdev_read(&s_fileops_usb_dev, lba, 1U, s_probe_buf) != k_ra8_ok) {
694 (void)fileops_print("ra8d2 fileops: probe read failed\r\n");
695 return;
696 }
697 (void)fileops_print("ra8d2 fileops: probe lba=");
698 (void)fileops_print_dec(lba);
699 (void)fileops_print("\r\n");
700 if (lba == 0U) {
701 fileops_dump_rows(s_probe_buf,
702 (uint32_t)k_fileops_probe_tbl_off,
703 (uint32_t)k_fileops_probe_tbl_len);
704 } else {
705 fileops_dump_rows(s_probe_buf, 0U, (uint32_t)k_fileops_probe_head_len);
706 }
707 }
708}
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_led_toggle(ra8_board_led_id_t led)
Toggle led's output state.
@ k_ra8_board_led2
LED2, GREEN, P303 (jumper E26).
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.
Error Code Definitions for ra8-firmware.
@ k_ra8_err_exists
Item already exists – cannot create again.
Definition ra8_err.h:216
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_not_found
Requested item not found (lookup / search missed).
Definition ra8_err.h:173
@ 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
Minimal FAT12/FAT16/FAT32 filesystem adapter (read + write).
ra8_err_t ra8_fs_listdir(const ra8_fs_mount_t *handle, const char *path, ra8_fs_listdir_cb_t cb, void *ctx)
Enumerate directory entries; invoke cb once per visible entry.
ra8_err_t ra8_fs_rename(const ra8_fs_mount_t *handle, const char *old_path, const char *new_path)
Rename a file within its own directory.
ra8_err_t ra8_fs_mount(const ra8_fs_backend_t *backend, ra8_fs_mount_t **out_handle)
Mount a FAT volume from a block-device backend, auto-selecting the first partition.
ra8_err_t ra8_fs_read(ra8_fs_file_t *file, uint8_t *buf, uint32_t max_len, uint32_t *got_len)
Read up to max_len bytes; advance the cluster chain on cluster crossings.
ra8_err_t ra8_fs_unlink(const ra8_fs_mount_t *handle, const char *path)
Delete a file: mark its dir entry deleted and free its clusters.
ra8_err_t ra8_fs_open(ra8_fs_mount_t *handle, const char *path, ra8_fs_mode_t mode, ra8_fs_file_t **out_file)
Open or create a file by path, 8.3 or long.
ra8_err_t ra8_fs_close(ra8_fs_file_t *file)
Close an open file, stamping its final modification time.
ra8_err_t ra8_fs_write_file(ra8_fs_mount_t *handle, const char *path, const uint8_t *data, uint32_t len)
Create a whole file in one call (provisioning helper).
ra8_fs_type_t
FAT variant detected from the BPB cluster-count rule.
@ k_ra8_fs_type_fat12
count_of_clusters < 4085.
@ k_ra8_fs_type_fat32
count_of_clusters >= 65525.
@ k_ra8_fs_type_exfat
exFAT (read + streaming write + format).
@ k_ra8_fs_type_fat16
4085 <= count_of_clusters < 65525.
@ k_ra8_fs_type_unknown
Not yet detected / mount failed.
@ k_ra8_fs_attr_directory
MS FAT spec sec 6 "ATTR_DIRECTORY".
@ k_ra8_fs_mode_read
Read-only, must exist.
ra8_io block-device fabric – one LBA vtable across every storage medium.
ra8_err_t ra8_io_blockdev_read(const ra8_io_blockdev_t *bd, uint32_t lba, uint32_t count, uint8_t *buf)
Read count logical blocks starting at lba into buf.
ra8_err_t ra8_io_blockdev_as_fs_backend(const ra8_io_blockdev_t *bd, ra8_fs_backend_t *out)
Expose a bound block device as an ra8_fs_backend_t for ra8_fs.
ra8_io block-device backend over a hosted USB mass-storage device.
ra8_err_t ra8_io_blockdev_usbmsc_init(ra8_io_blockdev_t *bd, ra8_io_blockdev_usbmsc_state_t *state, uint8_t lun)
Bind a hosted USB mass-storage backend into a caller-owned handle.
Cookie carried through ra8_fs_listdir for printing + matching.
uint32_t count
Total entries reported.
const char * want
Name expected present (nullptr = none).
uint8_t found_want
1 when want was seen.
const char * avoid
Name expected absent (nullptr = none).
uint8_t found_avoid
1 when avoid was seen.
Block-device interface that ra8_fs runs on top of.
Open-file state.
Cached parse of one mounted FAT volume.
Caller-allocated block-device handle binding a backend to its context.
Caller-owned private state for a USB mass-storage block device.
void fileops_probe_layout(void)
Dump the partition table + LBA1/LBA2 heads after a mount failure.
static ra8_err_t fileops_read_back(ra8_fs_mount_t *mount, const char *path)
Open path and verify it reads back the known payload.
static void fileops_dump_rows(const uint8_t *data, uint32_t offset, uint32_t len)
Hex-dump len bytes of data starting at offset.
static uint8_t fileops_nibble_to_hex(uint32_t nibble)
Format one nibble (0..15) into an uppercase hex character.
static const uint8_t k_fileops_payload[]
Known payload written to and read back from the drive.
static uint32_t fileops_str_len(const char *text)
Bounded ASCII string length (cap k_fileops_print_cap).
ra8_err_t fileops_print_dec(uint64_t value)
Print a uint32_t as ASCII decimal.
ra8_err_t fileops_suite_mutate(ra8_fs_mount_t *mount)
Suite steps 6..9: rename, old-gone/new-intact, list, delete.
static ra8_io_blockdev_usbmsc_state_t s_fileops_usb_state
Caller-owned backend state for s_fileops_usb_dev.
static const char k_fileops_name_a[]
Name the payload file is created under (8.3-safe, <= 15 chars).
static ra8_err_t fileops_expect_absent(ra8_fs_mount_t *mount, const char *path)
Require that path no longer resolves on the volume.
ra8_err_t fileops_suite_create(ra8_fs_mount_t *mount)
Suite steps 1..5: cleanup, baseline listdir, write, verify, list.
static const char k_fileops_name_b[]
Name the payload file is renamed to (8.3-safe, <= 15 chars).
static void fileops_listdir_cb(const char *name, uint8_t attr, uint64_t size, void *ctx)
Listdir callback: print one entry, match the expectation names.
static const char * fileops_fs_type_name(ra8_fs_type_t type)
Map a detected filesystem type to a printable name.
ra8_err_t fileops_mount_volume(ra8_fs_mount_t **out_mount)
Mount the attached drive through the USB-MSC backend.
static bool fileops_name_eq(const char *a, const char *b)
Bounded ASCII string equality (cap k_fileops_name_cap).
static ra8_io_blockdev_t s_fileops_usb_dev
Block device fronting the hosted MSC volume for this ladder.
ra8_err_t fileops_print_fail(const char *what, ra8_err_t err)
Print "FAIL <what> err=0xNNNNNNNN" on its own line.
static ra8_err_t fileops_step_write(ra8_fs_mount_t *mount)
Step 3: print the banner and write the payload file.
ra8_err_t fileops_print_hex(uint32_t value, uint8_t digits)
Print a value as fixed-width uppercase hex.
static ra8_err_t fileops_sci_write(const uint8_t *data, uint32_t len)
Push a literal block over SCI8 polled.
static ra8_err_t fileops_step_listdir(ra8_fs_mount_t *mount, const char *want, const char *avoid)
List the root directory and check presence/absence expectations.
ra8_err_t fileops_print(const char *text)
Print a NUL-terminated ASCII string over the console.
examples/ek_ra8d2/hw_validated/manual/usb_host_file_ops/inc/usb_host_file_ops_steps....
@ k_fileops_probe_lba_max
Probe reads LBAs 0..2.
@ k_fileops_probe_tbl_off
LBA0 dump start (partition table).
@ k_fileops_probe_head_len
LBA1/LBA2 head dump length.
@ k_fileops_probe_row
Hex bytes per dump row.
@ k_fileops_probe_tbl_len
LBA0 dump length (incl.
@ k_fileops_name_cap
Listdir name compare bound.
@ k_fileops_sector_bytes
One SCSI block / FAT sector.
@ k_fileops_target_lun
Exercise LUN 0 (typical stick).
@ k_fileops_print_cap
Bound for console-string scans.
@ k_fileops_hex_chars_u32
32-bit value -> "ABCDEF01".
@ k_fileops_hex_digit_split
Threshold between '0-9'/'A-F'.
@ k_fileops_nibble_bits
Bits per hex nibble.
@ k_fileops_hex_chars_u16
16-bit value -> "ABCD".
@ k_fileops_dec_chars_u64
Max digits for a 64-bit count.
@ k_fileops_nibble_mask
4-bit nibble mask.
@ k_fileops_dec_radix
Base for decimal conversion.