ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
usb_host_msc_browse_host.c
Go to the documentation of this file.
1
27
28#include <stdint.h>
29#include <string.h>
30
32
33#ifndef RA8_OFF_TARGET
34
35#include "ra8_board_ek_ra8d2.h"
36#include "ra8_err.h"
37#include "ra8_fs.h"
38#include "ra8_io_blockdev.h"
40#include "ra8_time.h"
41#include "ra8_usb_hmsc.h"
42
43/* -------------------------------------------------------------------------- */
44/* Tunables */
45/* -------------------------------------------------------------------------- */
46
58
63typedef enum : uint32_t {
67
81
95
96/* -------------------------------------------------------------------------- */
97/* J-Link probes */
98/* -------------------------------------------------------------------------- */
99
101static volatile uint32_t s_dbg_phase;
103static volatile uint32_t s_dbg_verified_bytes;
105static volatile uint32_t s_dbg_mismatch_off = (uint32_t)k_selftest_no_mismatch;
107static volatile uint32_t s_dbg_verify_ms;
109static volatile uint32_t s_dbg_pass_count;
110
111/* -------------------------------------------------------------------------- */
112/* Console helpers (SCI8 -> J-Link OB CDC) */
113/* -------------------------------------------------------------------------- */
114
133static uint8_t selftest_nibble_to_hex(uint32_t nibble)
134{
135 if (nibble < k_selftest_hex_digit_split) {
136 return (uint8_t)((uint8_t)'0' + (uint8_t)nibble);
137 }
138 return (uint8_t)((uint8_t)'A' + (uint8_t)nibble - (uint8_t)k_selftest_hex_digit_split);
139}
140
159static uint32_t selftest_str_len(const char* text)
160{
161 uint32_t len = 0U;
162 while (len < (uint32_t)k_selftest_print_cap) {
163 if (text[len] == '\0') {
164 break;
165 }
166 len++;
167 }
168 return len;
169}
170
190[[nodiscard]] static ra8_err_t selftest_sci_write(const uint8_t* data, uint32_t len)
191{
192 return ra8_board_uart_console_write(data, (size_t)len);
193}
194
213[[nodiscard]] static ra8_err_t selftest_print(const char* text)
214{
215 return selftest_sci_write((const uint8_t*)text, selftest_str_len(text));
216}
217
236[[nodiscard]] static ra8_err_t selftest_print_dec(uint32_t value)
237{
238 uint8_t scratch[k_selftest_dec_chars_u32] = {};
239 uint8_t out[k_selftest_dec_chars_u32] = {};
240 uint8_t count = 0U;
241 uint32_t v = value;
242 if (v == 0U) {
243 out[0] = (uint8_t)'0';
244 return selftest_sci_write(out, 1U);
245 }
246 while (v != 0U) {
247 if (count >= (uint8_t)k_selftest_dec_chars_u32) {
248 break;
249 }
250 scratch[count] = (uint8_t)((uint8_t)'0' + (uint8_t)(v % k_selftest_dec_radix));
251 v = v / k_selftest_dec_radix;
252 count++;
253 }
254 for (uint8_t i = 0U; i < count; i++) {
255 out[i] = scratch[count - 1U - i];
256 }
257 return selftest_sci_write(out, (uint32_t)count);
258}
259
279[[nodiscard]] static ra8_err_t selftest_print_hex(uint32_t value, uint8_t digits)
280{
281 uint8_t out[k_selftest_hex_chars_u32] = {};
282 uint8_t width = digits;
283 if (width > (uint8_t)k_selftest_hex_chars_u32) {
284 width = (uint8_t)k_selftest_hex_chars_u32;
285 }
286 for (uint8_t i = 0U; i < width; i++) {
287 const uint8_t shift = (uint8_t)((width - 1U - i) * k_selftest_nibble_bits);
288 out[i] = selftest_nibble_to_hex((value >> shift) & k_selftest_nibble_mask);
289 }
290 return selftest_sci_write(out, (uint32_t)width);
291}
292
313[[nodiscard]] static ra8_err_t selftest_print_fail(const char* what, ra8_err_t err)
314{
315 ra8_err_t e = selftest_print("ra8d2 selftest: FAIL ");
316 if (e != k_ra8_ok) {
317 return e;
318 }
319 e = selftest_print(what);
320 if (e != k_ra8_ok) {
321 return e;
322 }
323 e = selftest_print(" err=0x");
324 if (e != k_ra8_ok) {
325 return e;
326 }
327 e = selftest_print_hex((uint32_t)err, (uint8_t)k_selftest_hex_chars_u32);
328 if (e != k_ra8_ok) {
329 return e;
330 }
331 return selftest_print("\r\n");
332}
333
334/* -------------------------------------------------------------------------- */
335/* Host side: ra8_fs mount over the ra8_io USB-MSC block device */
336/* -------------------------------------------------------------------------- */
337
353
367
386static const char* selftest_fs_type_name(ra8_fs_type_t type)
387{
388 switch (type) {
390 return "fat12";
392 return "fat16";
394 return "fat32";
396 return "exfat";
398 default:
399 return "unknown";
400 }
401}
402
424[[nodiscard]] static ra8_err_t selftest_mount_volume(ra8_fs_mount_t** out_mount)
425{
428 (uint8_t)k_selftest_target_lun);
429 if (err != k_ra8_ok) {
430 (void)selftest_print_fail("blockdev", err);
431 return err;
432 }
433 ra8_fs_backend_t backend = {};
435 if (err != k_ra8_ok) {
436 (void)selftest_print_fail("backend", err);
437 return err;
438 }
439 err = ra8_fs_mount(&backend, out_mount);
440 if (err != k_ra8_ok) {
441 (void)selftest_print_fail("mount", err);
442 return err;
443 }
444 err = selftest_print("ra8d2 selftest: mounted fs=");
445 if (err != k_ra8_ok) {
446 return err;
447 }
448 err = selftest_print(selftest_fs_type_name((*out_mount)->type));
449 if (err != k_ra8_ok) {
450 return err;
451 }
452 return selftest_print("\r\n");
453}
454
485[[nodiscard]] static ra8_err_t selftest_verify_mram_raw(void)
486{
487 static uint8_t s_burst[k_selftest_burst_bytes] = {};
488
491 const uint32_t t0 = ra8_time_ms();
492 for (uint32_t blk = 0U; blk < (uint32_t)k_fat_mram_clusters;
493 blk += (uint32_t)k_selftest_burst_blocks) {
494 const uint32_t lba = (uint32_t)k_fat_data_lba + blk;
496 lba,
497 (uint16_t)k_selftest_burst_blocks,
498 s_burst);
499 if (err != k_ra8_ok) {
500 (void)selftest_print_fail("READ(10) burst", err);
501 return err;
502 }
503 const uint32_t offset = blk * (uint32_t)k_selftest_block_size;
504 const uint8_t* mram = (const uint8_t*)(uintptr_t)((uint32_t)k_mram_base_addr + offset);
505 if (memcmp(s_burst, mram, (size_t)k_selftest_burst_bytes) != 0) {
506 s_dbg_mismatch_off = offset;
507 (void)selftest_print_fail("content mismatch at 0x", (ra8_err_t)offset);
509 }
510 s_dbg_verified_bytes = offset + (uint32_t)k_selftest_burst_bytes;
511 }
513 return k_ra8_ok;
514}
515
532[[nodiscard]] static ra8_err_t selftest_print_verify_verdict(void)
533{
534 ra8_err_t err = selftest_print("ra8d2 selftest: verified ");
535 if (err != k_ra8_ok) {
536 return err;
537 }
539 if (err != k_ra8_ok) {
540 return err;
541 }
542 err = selftest_print(" bytes vs MRAM in ");
543 if (err != k_ra8_ok) {
544 return err;
545 }
547 if (err != k_ra8_ok) {
548 return err;
549 }
550 err = selftest_print(" ms (");
551 if (err != k_ra8_ok) {
552 return err;
553 }
554 uint32_t ms = s_dbg_verify_ms;
555 if (ms == 0U) {
556 ms = 1U;
557 }
558 const uint32_t kib_per_s =
559 (uint32_t)(((uint64_t)s_dbg_verified_bytes * (uint64_t)k_selftest_ms_per_sec) /
560 ((uint64_t)ms * (uint64_t)k_selftest_bytes_per_kib));
561 err = selftest_print_dec(kib_per_s);
562 if (err != k_ra8_ok) {
563 return err;
564 }
565 return selftest_print(" KiB/s)\r\n");
566}
567
597[[nodiscard]] static ra8_err_t selftest_write_protect_probe(void)
598{
599 static uint8_t s_wp_buf[k_selftest_block_size] = {};
600
601 ra8_err_t err = selftest_print("ra8d2 selftest: WRITE(10) into RO LUN must be rejected...\r\n");
602 if (err != k_ra8_ok) {
603 return err;
604 }
606 (uint32_t)k_selftest_wp_probe_lba,
607 1U,
608 s_wp_buf);
609 if (wr == k_ra8_ok) {
610 (void)selftest_print_fail("write unexpectedly accepted", k_ra8_err_invalid_state);
612 }
613 err = selftest_print("ra8d2 selftest: write rejected (code 0x");
614 if (err != k_ra8_ok) {
615 return err;
616 }
617 err = selftest_print_hex((uint32_t)wr, (uint8_t)k_selftest_hex_chars_u32);
618 if (err != k_ra8_ok) {
619 return err;
620 }
621 return selftest_print("), MRAM protected\r\n");
622}
623
645{
647 ra8_err_t err = selftest_print("ra8d2 selftest: host up on USB-HS, probing the loop...\r\n");
648 if (err != k_ra8_ok) {
649 return err;
650 }
652 if (err != k_ra8_ok) {
653 (void)selftest_print_fail("host init", err);
654 return err;
655 }
657 err = ra8_usb_hmsc_enumerate(out_device);
658 if (err != k_ra8_ok) {
659 (void)selftest_print_fail("enumerate", err);
660 (void)ra8_usb_hmsc_close();
661 return err;
662 }
663 err = selftest_print("ra8d2 selftest: enumerated vid=0x");
664 if (err != k_ra8_ok) {
665 return err;
666 }
667 err = selftest_print_hex((uint32_t)out_device->vendor_id, (uint8_t)k_selftest_hex_chars_u16);
668 if (err != k_ra8_ok) {
669 return err;
670 }
671 err = selftest_print(" pid=0x");
672 if (err != k_ra8_ok) {
673 return err;
674 }
675 err = selftest_print_hex((uint32_t)out_device->product_id, (uint8_t)k_selftest_hex_chars_u16);
676 if (err != k_ra8_ok) {
677 return err;
678 }
679 return selftest_print(" over the loop cable\r\n");
680}
681
700[[nodiscard]] static ra8_err_t selftest_browse_root(void)
701{
702 static uint8_t s_dir[k_selftest_block_size] = {};
703
704 ra8_err_t err =
705 ra8_usb_hmsc_read10((uint8_t)k_selftest_target_lun, (uint32_t)k_fat_root_lba, 1U, s_dir);
706 if (err != k_ra8_ok) {
707 (void)selftest_print_fail("READ(10) root dir", err);
708 return err;
709 }
710 const uint8_t* entry = &s_dir[k_dir_entry_bytes]; /* entry 0 = volume label */
711 char name[(uint32_t)k_dir_name_bytes + 1U];
712 for (uint32_t i = 0U; i < (uint32_t)k_dir_name_bytes; i++) {
713 name[i] = (char)entry[i];
714 }
715 name[(uint32_t)k_dir_name_bytes] = '\0';
716 uint32_t size = 0U;
717 for (uint32_t i = 0U; i < 4U; i++) {
718 size |= (uint32_t)entry[(uint32_t)k_dir_off_size + i] << (i * (uint32_t)k_byte_shift);
719 }
720 err = selftest_print("ra8d2 host: browsed root, file=");
721 if (err == k_ra8_ok) {
722 err = selftest_print(name);
723 }
724 if (err == k_ra8_ok) {
725 err = selftest_print(" size=");
726 }
727 if (err == k_ra8_ok) {
728 err = selftest_print_dec(size);
729 }
730 if (err == k_ra8_ok) {
731 err = selftest_print(" bytes\r\n");
732 }
733 return err;
734}
735
738[[nodiscard]] ra8_err_t selftest_host_pass(void)
739{
740 ra8_usb_hmsc_device_t device = {};
741 ra8_err_t err = selftest_host_enumerate(&device);
742 if (err != k_ra8_ok) {
743 return err;
744 }
745
746 /* Mount proves the host can PARSE the FAT16 volume over the loop;
747 * then unmount and do the heavy integrity check with raw multi-block
748 * READ(10) (ra8_fs's per-cluster metadata re-reads are far too slow
749 * for a 1 MiB sweep). */
751 ra8_fs_mount_t* mount = nullptr;
752 err = selftest_mount_volume(&mount);
753 if (err != k_ra8_ok) {
754 (void)ra8_usb_hmsc_close();
755 return err;
756 }
757 (void)ra8_fs_unmount(mount);
758
759 /* Browse the FAT directory of the fake peripheral (the host-side
760 * directory walk this app adds on top of the raw integrity check). */
761 err = selftest_browse_root();
762 if (err != k_ra8_ok) {
763 (void)ra8_usb_hmsc_close();
764 return err;
765 }
766
769 if (err == k_ra8_ok) {
771 }
772 if (err == k_ra8_ok) {
775 }
776 if (err != k_ra8_ok) {
777 (void)ra8_usb_hmsc_close();
778 return err;
779 }
780
783 err = selftest_print("ra8d2 host: USB HOST MSC BROWSE PASS\r\n");
784 if (err != k_ra8_ok) {
785 return err;
786 }
788 return k_ra8_ok;
789}
790
791#endif /* !RA8_OFF_TARGET */
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_led_on(ra8_board_led_id_t led)
Drive led HIGH (light it).
@ 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_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
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int memcmp(const void *a, const void *b, size_t n)
Compare bytes in two memory areas.
Minimal FAT12/FAT16/FAT32 filesystem adapter (read + write).
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_unmount(ra8_fs_mount_t *handle)
Unmount a previously mounted volume and release its slot.
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.
ra8_io block-device fabric – one LBA vtable across every storage medium.
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.
SysTick-based tick counter, delay and timestamp helpers.
uint32_t ra8_time_ms(void)
Get the current 1 kHz tick count.
Definition ra8_time.c:108
@ k_ra8_usb_speed_hs
High-Speed controller (USBHS @ 0x40351000).
Native USB host-side MSC (Mass Storage Class) class layer.
ra8_err_t ra8_usb_hmsc_read10(uint8_t target_lun, uint32_t lba, uint16_t block_count, uint8_t *out_buf)
Issue a SCSI READ(10) (opcode 0x28) over BBB.
ra8_err_t ra8_usb_hmsc_enumerate(ra8_usb_hmsc_device_t *out_device)
Enumerate the attached MSC device end to end (polled).
ra8_err_t ra8_usb_hmsc_close(void)
Tear down the host-MSC driver and release the controller.
ra8_err_t ra8_usb_hmsc_init(ra8_usb_speed_t speed)
Bring up the host-MSC driver on a chosen USB controller.
ra8_err_t ra8_usb_hmsc_write10(uint8_t target_lun, uint32_t lba, uint16_t block_count, const uint8_t *in_buf)
Issue a SCSI WRITE(10) (opcode 0x2A) over BBB.
Block-device interface that ra8_fs runs on top of.
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.
Snapshot of the attached MSC device, passed to the attach callback.
uint16_t vendor_id
idVendor from device descriptor.
uint16_t product_id
idProduct from device descriptor.
selftest_hex_t
Hex/decimal text-formatter sizing constants.
@ k_selftest_hex_digit_split
Threshold between '0-9'/'A-F'.
@ k_selftest_hex_chars_u16
16-bit value -> "ABCD".
@ k_selftest_dec_chars_u32
Max digits for a 32-bit count.
@ k_selftest_hex_chars_u32
32-bit value -> "ABCDEF01".
@ k_selftest_nibble_bits
Bits per hex nibble.
static ra8_err_t selftest_print_dec(uint32_t value)
Print a uint32_t as ASCII decimal.
static const char * selftest_fs_type_name(ra8_fs_type_t type)
Map a detected filesystem type to a printable name.
static ra8_io_blockdev_usbmsc_state_t s_selftest_usb_state
Caller-owned backend state for s_selftest_usb_dev.
selftest_phase_t
J-Link probe values marking host-ladder progress.
@ k_selftest_phase_wp
Write-protect rejection test.
@ k_selftest_phase_mount
Mounting the FAT16 volume.
@ k_selftest_phase_boot
Host thread not yet started.
@ k_selftest_phase_enum
Enumerating the FS device.
@ k_selftest_phase_pass
Full config A pass.
@ k_selftest_phase_host_init
ra8_usb_hmsc_init issued.
@ k_selftest_phase_verify
Streaming + comparing MRAM.BIN.
static ra8_err_t selftest_print_hex(uint32_t value, uint8_t digits)
Print a value as fixed-width uppercase hex.
static ra8_err_t selftest_browse_root(void)
Browse the FAT root directory: READ(10) it and parse the file entry.
static ra8_io_blockdev_t s_selftest_usb_dev
Block device fronting the hosted MSC volume for this ladder.
static uint32_t selftest_str_len(const char *text)
Bounded ASCII string length (cap k_selftest_print_cap).
static ra8_err_t selftest_host_enumerate(ra8_usb_hmsc_device_t *out_device)
Bring the host controller up and enumerate the loop device.
ra8_err_t selftest_host_pass(void)
Implementation of selftest_host_pass() – closes the host on any mid-ladder failure so the worker's ne...
static ra8_err_t selftest_verify_mram_raw(void)
Raw multi-block READ(10) of the MRAM data region vs MRAM.
static uint8_t selftest_nibble_to_hex(uint32_t nibble)
Format one nibble (0..15) into an uppercase hex character.
selftest_verify_t
Content-verification geometry over the device's FAT16 volume.
@ k_selftest_wp_probe_lba
Data-region LBA for WP test.
@ k_selftest_ms_per_sec
Milliseconds per second.
@ k_selftest_target_lun
Single-LUN device.
@ k_selftest_burst_bytes
8 x 512 B burst buffer size.
@ k_selftest_burst_blocks
Blocks per READ(10) burst.
@ k_selftest_no_mismatch
Probe: no mismatch found.
@ k_selftest_bytes_per_kib
Bytes per KiB (rate math).
static ra8_err_t selftest_sci_write(const uint8_t *data, uint32_t len)
Push a literal block over SCI8 polled.
static ra8_err_t selftest_print(const char *text)
Print a NUL-terminated ASCII string over the console.
static ra8_err_t selftest_print_verify_verdict(void)
Print the verify verdict line (bytes + duration + rate).
static ra8_err_t selftest_write_protect_probe(void)
WRITE(10) into the read-only LUN must be rejected.
static volatile uint32_t s_dbg_verified_bytes
Bytes content-verified so far this pass.
static ra8_err_t selftest_print_fail(const char *what, ra8_err_t err)
Print "FAIL <what> err=0xNNNNNNNN" on its own line.
static volatile uint32_t s_dbg_mismatch_off
First mismatching MRAM offset (k_selftest_no_mismatch = none).
static ra8_err_t selftest_mount_volume(ra8_fs_mount_t **out_mount)
Mount the loop device's volume through the USB-MSC backend.
static volatile uint32_t s_dbg_verify_ms
Milliseconds the 1 MiB verify streamed for.
selftest_mask_t
Bit-mask constants used by the text formatters.
@ k_selftest_dec_radix
Base for decimal conversion.
@ k_selftest_nibble_mask
4-bit nibble mask.
Shared constants + device-side FAT16/MSC step declarations.
@ k_fat_data_lba
First data sector (cluster 2).
@ k_fat_root_lba
First root-directory sector.
@ k_fat_mram_clusters
Clusters backed by MRAM (1 MiB).
@ k_dir_entry_bytes
Directory entry size.
@ k_dir_off_size
File size (32-bit LE).
@ k_dir_name_bytes
8.3 name field length.
@ k_byte_shift
Bits per byte for LE packing.
@ k_mram_base_addr
MRAM code window base address.
@ k_selftest_block_size
SCSI logical block size (bytes).
@ k_selftest_print_cap
Bound for console-string scans.
static volatile uint32_t s_dbg_phase
Host-ladder phase marker (wlun_phase_t).
static volatile uint32_t s_dbg_pass_count
Completed full passes (sticky success counter).