ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_devcfg.c
Go to the documentation of this file.
1
20
21#include "ra8_devcfg.h"
22
23#include <stddef.h>
24#include <stdint.h>
25#include <string.h>
26
27#include "ra8_attributes.h"
28#include "ra8_check.h"
29#include "ra8_err.h"
30#include "ra8_log.h"
31
39static const char* const s_tag = "DEVCFG";
40
51typedef enum : uint32_t {
52 k_ra8_devcfg_crc_init = 0xFFFFFFFFU,
53 k_ra8_devcfg_crc_poly = 0xEDB88320U,
55
69
96
104
112
113/* ===========================================================================
114 * Local helpers -- byte codec
115 * ===========================================================================
116 */
117
139[[nodiscard]] static uint32_t internal_devcfg_crc32(const uint8_t* data, uint32_t len)
140{
141 uint32_t crc = (uint32_t)k_ra8_devcfg_crc_init;
142 for (uint32_t i = 0U; i < len; i++) {
143 crc ^= (uint32_t)data[i];
144 for (uint8_t bit = 0U; bit < (uint8_t)k_ra8_devcfg_bits_per_byte; bit++) {
145 const uint32_t mask = (uint32_t)0U - (crc & 1U);
146 crc = (crc >> 1U) ^ ((uint32_t)k_ra8_devcfg_crc_poly & mask);
147 }
148 }
149 return crc ^ (uint32_t)k_ra8_devcfg_crc_init;
150}
151
170static void internal_devcfg_pack_le16(uint8_t* dst, uint16_t val)
171{
172 dst[k_ra8_devcfg_off_b0] = (uint8_t)(val & (uint16_t)k_ra8_devcfg_byte_mask);
174 (uint8_t)((val >> (uint16_t)k_ra8_devcfg_byte_shift) & (uint16_t)k_ra8_devcfg_byte_mask);
175}
176
195static void internal_devcfg_pack_le32(uint8_t* dst, uint32_t val)
196{
197 const uint32_t sh = (uint32_t)k_ra8_devcfg_byte_shift;
198 dst[k_ra8_devcfg_off_b0] = (uint8_t)(val & (uint32_t)k_ra8_devcfg_byte_mask);
199 dst[k_ra8_devcfg_off_b1] = (uint8_t)((val >> sh) & (uint32_t)k_ra8_devcfg_byte_mask);
200 dst[k_ra8_devcfg_off_b2] = (uint8_t)((val >> (sh * 2U)) & (uint32_t)k_ra8_devcfg_byte_mask);
201 dst[k_ra8_devcfg_off_b3] = (uint8_t)((val >> (sh * 3U)) & (uint32_t)k_ra8_devcfg_byte_mask);
202}
203
224[[nodiscard]] static uint16_t internal_devcfg_unpack_le16(const uint8_t* src)
225{
226 return (uint16_t)((uint16_t)src[k_ra8_devcfg_off_b0] |
227 ((uint16_t)src[k_ra8_devcfg_off_b1] << (uint16_t)k_ra8_devcfg_byte_shift));
228}
229
250[[nodiscard]] static uint32_t internal_devcfg_unpack_le32(const uint8_t* src)
251{
252 const uint32_t sh = (uint32_t)k_ra8_devcfg_byte_shift;
253 return (uint32_t)src[k_ra8_devcfg_off_b0] | ((uint32_t)src[k_ra8_devcfg_off_b1] << sh) |
254 ((uint32_t)src[k_ra8_devcfg_off_b2] << (sh * 2U)) |
255 ((uint32_t)src[k_ra8_devcfg_off_b3] << (sh * 3U));
256}
257
258/* ===========================================================================
259 * Local helpers -- record codec
260 * ===========================================================================
261 */
262
284static void internal_devcfg_serialize(const ra8_devcfg_record_t* rec, uint32_t seq, uint8_t* buf)
285{
286 (void)memset(buf, 0, (size_t)k_ra8_devcfg_record_len);
287 const ra8_devcfg_body_t* b = &rec->body;
288 (void)memcpy(&buf[k_ra8_devcfg_off_serial], b->serial, (size_t)k_ra8_devcfg_serial_len);
290 b->panel_serial,
293 b->panel_lut_id,
295 (void)memcpy(&buf[k_ra8_devcfg_off_touch_cal], b->touch_cal, (size_t)k_ra8_devcfg_touch_cal_len);
297 internal_devcfg_pack_le32(&buf[k_ra8_devcfg_off_key_id], b->device_key_id);
300 internal_devcfg_pack_le16(&buf[k_ra8_devcfg_off_vcom], b->panel_vcom_mv);
301
302 const uint32_t crc =
310}
311
351
376[[nodiscard]] static bool internal_devcfg_copy_valid(const uint8_t* buf)
377{
379 return false; /* not our record / blank window */
380 }
382 (uint16_t)k_ra8_devcfg_schema_ver) {
383 return false; /* written by a newer, unknown schema -- reject, never guess */
384 }
386 (uint16_t)k_ra8_devcfg_record_len) {
387 return false; /* length not what this schema expects */
388 }
389 const uint32_t stored = internal_devcfg_unpack_le32(&buf[k_ra8_devcfg_off_crc]);
390 const uint32_t calc =
392 return stored == calc;
393}
394
421[[nodiscard]] static bool
423{
424 uint8_t buf[k_ra8_devcfg_record_len] = {};
425 if (store->read(offset, buf, (uint32_t)k_ra8_devcfg_record_len) != k_ra8_ok) {
426 return false; /* read fault / blank -> copy absent, resolver falls through */
427 }
428 if (!internal_devcfg_copy_valid(buf)) {
429 return false;
430 }
432 return true;
433}
434
460[[nodiscard]] static uint32_t
461internal_devcfg_target(bool valid0, uint32_t seq0, bool valid1, uint32_t seq1)
462{
463 if (!valid0) {
464 return (uint32_t)k_ra8_devcfg_copy0_off;
465 }
466 if (!valid1) {
467 return (uint32_t)k_ra8_devcfg_copy1_off;
468 }
469 return (seq0 <= seq1) ? (uint32_t)k_ra8_devcfg_copy0_off : (uint32_t)k_ra8_devcfg_copy1_off;
470}
471
493static void
494internal_devcfg_plan(const ra8_devcfg_store_t* store, uint32_t* out_target, uint32_t* out_seq)
495{
496 ra8_devcfg_record_t cur0 = {};
497 ra8_devcfg_record_t cur1 = {};
498 const bool valid0 = internal_devcfg_probe(store, (uint32_t)k_ra8_devcfg_copy0_off, &cur0);
499 const bool valid1 = internal_devcfg_probe(store, (uint32_t)k_ra8_devcfg_copy1_off, &cur1);
500 const uint32_t seq0 = valid0 ? cur0.seq : 0U;
501 const uint32_t seq1 = valid1 ? cur1.seq : 0U;
502 const uint32_t newest = (seq0 >= seq1) ? seq0 : seq1;
503 *out_seq = newest + 1U;
504 *out_target = internal_devcfg_target(valid0, seq0, valid1, seq1);
505}
506
532[[nodiscard]] static ra8_err_t
533internal_devcfg_write_record(const ra8_devcfg_store_t* store, uint32_t target, const uint8_t* buf)
534{
535 const ra8_err_t body_err = store->write(target + (uint32_t)k_ra8_devcfg_hdr_bytes,
537 (uint32_t)k_ra8_devcfg_body_bytes);
538 RA8_RETURN_ON_ERROR(body_err, s_tag, "commit: body write failed");
539 const ra8_err_t hdr_err = store->write(target, buf, (uint32_t)k_ra8_devcfg_hdr_bytes);
540 RA8_RETURN_ON_ERROR(hdr_err, s_tag, "commit: header write failed");
541 return k_ra8_ok;
542}
543
544/* ===========================================================================
545 * Public API
546 * ===========================================================================
547 */
548
550{
551 RA8_CHECK_NULL_PTR(store, s_tag, "load: store null");
552 RA8_CHECK_NULL_PTR(store->read, s_tag, "load: store->read null");
553
554 ra8_devcfg_record_t rec0 = {};
555 ra8_devcfg_record_t rec1 = {};
556 const bool valid0 = internal_devcfg_probe(store, (uint32_t)k_ra8_devcfg_copy0_off, &rec0);
557 const bool valid1 = internal_devcfg_probe(store, (uint32_t)k_ra8_devcfg_copy1_off, &rec1);
558
559 if (valid0 && valid1) {
560 /* Both survive -- the higher sequence is the newer record; a tie takes 0. */
561 s_record = (rec0.seq >= rec1.seq) ? rec0 : rec1;
562 } else if (valid0) {
563 s_record = rec0;
564 } else if (valid1) {
565 s_record = rec1;
566 } else {
568 ra8_log_warn(s_tag, "no valid device config -- UNPROVISIONED");
570 }
572 return k_ra8_ok;
573}
574
575[[nodiscard]] ra8_err_t ra8_devcfg_get_vcom_mv(uint16_t* out_mv)
576{
577 RA8_CHECK_NULL_PTR(out_mv, s_tag, "get_vcom: out_mv null");
580 }
581 if ((s_record.flags & (uint32_t)k_ra8_devcfg_flag_vcom_valid) == 0U) {
582 ra8_log_error(s_tag, "VCOM not marked valid -- refuse the panel");
584 }
585 const uint16_t mv = s_record.body.panel_vcom_mv;
586 if ((mv < (uint16_t)k_ra8_devcfg_vcom_min_mv) || (mv > (uint16_t)k_ra8_devcfg_vcom_max_mv)) {
587 ra8_log_error(s_tag, "VCOM out of plausible range -- refuse the panel");
589 }
590 *out_mv = mv;
591 return k_ra8_ok;
592}
593
594[[nodiscard]] ra8_err_t ra8_devcfg_get_body(const ra8_devcfg_body_t** out_body)
595{
596 RA8_CHECK_NULL_PTR(out_body, s_tag, "get_body: out_body null");
599 }
600 *out_body = &s_record.body;
601 return k_ra8_ok;
602}
603
604[[nodiscard]] bool ra8_devcfg_is_blank(void)
605{
607}
608
610 const ra8_devcfg_record_t* rec)
611{
612 RA8_CHECK_NULL_PTR(store, s_tag, "commit: store null");
613 RA8_CHECK_NULL_PTR(store->read, s_tag, "commit: store->read null");
614 RA8_CHECK_NULL_PTR(store->write, s_tag, "commit: store->write null");
615 RA8_CHECK_NULL_PTR(rec, s_tag, "commit: rec null");
616
617 uint32_t target = 0U;
618 uint32_t new_seq = 0U;
619 internal_devcfg_plan(store, &target, &new_seq);
620
621 uint8_t buf[k_ra8_devcfg_record_len] = {};
622 internal_devcfg_serialize(rec, new_seq, buf);
623 return internal_devcfg_write_record(store, target, buf);
624}
625
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
ra8_devcfg_state_t
Module cache state established by ra8_devcfg_load.
Definition ra8_devcfg.c:91
@ k_ra8_devcfg_state_loaded
A valid record is cached.
Definition ra8_devcfg.c:93
@ k_ra8_devcfg_state_unloaded
No load attempted this boot.
Definition ra8_devcfg.c:92
@ k_ra8_devcfg_state_unprovisioned
Load ran; neither copy was valid.
Definition ra8_devcfg.c:94
void ra8_devcfg_reset(void)
Drop the cached record so a later load re-resolves from scratch.
Definition ra8_devcfg.c:626
ra8_err_t ra8_devcfg_commit(const ra8_devcfg_store_t *store, const ra8_devcfg_record_t *rec)
Commit a new record to the stale copy slot with header-last ordering.
Definition ra8_devcfg.c:609
ra8_err_t ra8_devcfg_load(const ra8_devcfg_store_t *store)
Load and resolve the device configuration record from both copies.
Definition ra8_devcfg.c:549
static ra8_err_t internal_devcfg_write_record(const ra8_devcfg_store_t *store, uint32_t target, const uint8_t *buf)
Program a serialised record to a slot with the header page written last.
Definition ra8_devcfg.c:533
static void internal_devcfg_plan(const ra8_devcfg_store_t *store, uint32_t *out_target, uint32_t *out_seq)
Probe both copies and choose the commit target slot and next sequence.
Definition ra8_devcfg.c:494
static uint32_t internal_devcfg_unpack_le32(const uint8_t *src)
Load a little-endian 32-bit value from a blob.
Definition ra8_devcfg.c:250
static void internal_devcfg_serialize(const ra8_devcfg_record_t *rec, uint32_t seq, uint8_t *buf)
Serialise a record into a k_ra8_devcfg_record_len byte buffer.
Definition ra8_devcfg.c:284
static uint32_t internal_devcfg_crc32(const uint8_t *data, uint32_t len)
Compute the IEEE 802.3 CRC-32 of a byte span.
Definition ra8_devcfg.c:139
ra8_devcfg_bits_t
Byte / word packing constants (no magic numbers).
Definition ra8_devcfg.c:60
@ k_ra8_devcfg_bits_per_byte
CRC inner-loop bound.
Definition ra8_devcfg.c:61
@ k_ra8_devcfg_byte_mask
Low-byte extraction mask.
Definition ra8_devcfg.c:63
@ k_ra8_devcfg_off_b0
Little-endian byte 0.
Definition ra8_devcfg.c:64
@ k_ra8_devcfg_off_b2
Little-endian byte 2.
Definition ra8_devcfg.c:66
@ k_ra8_devcfg_off_b3
Little-endian byte 3.
Definition ra8_devcfg.c:67
@ k_ra8_devcfg_byte_shift
Bits per byte.
Definition ra8_devcfg.c:62
@ k_ra8_devcfg_off_b1
Little-endian byte 1.
Definition ra8_devcfg.c:65
ra8_devcfg_crc_t
IEEE 802.3 CRC-32 parameters.
Definition ra8_devcfg.c:51
@ k_ra8_devcfg_crc_poly
Reversed IEEE 802.3 poly.
Definition ra8_devcfg.c:53
@ k_ra8_devcfg_crc_init
CRC seed / final XOR.
Definition ra8_devcfg.c:52
static uint32_t internal_devcfg_target(bool valid0, uint32_t seq0, bool valid1, uint32_t seq1)
Choose the copy offset a new record overwrites (the stale slot).
Definition ra8_devcfg.c:461
static bool internal_devcfg_copy_valid(const uint8_t *buf)
Report whether a serialised copy passes every integrity gate.
Definition ra8_devcfg.c:376
static void internal_devcfg_pack_le16(uint8_t *dst, uint16_t val)
Store a little-endian 16-bit value into a blob.
Definition ra8_devcfg.c:170
static ra8_devcfg_record_t s_record
The resolved record cached by the last successful ra8_devcfg_load.
Definition ra8_devcfg.c:111
static uint16_t internal_devcfg_unpack_le16(const uint8_t *src)
Load a little-endian 16-bit value from a blob.
Definition ra8_devcfg.c:224
bool ra8_devcfg_is_blank(void)
Report whether neither record copy is valid (the provisioning gate).
Definition ra8_devcfg.c:604
ra8_err_t ra8_devcfg_get_vcom_mv(uint16_t *out_mv)
Fetch the validated panel VCOM magnitude in millivolts.
Definition ra8_devcfg.c:575
ra8_err_t ra8_devcfg_get_body(const ra8_devcfg_body_t **out_body)
Expose the decoded body of the loaded record.
Definition ra8_devcfg.c:594
static void internal_devcfg_deserialize(const uint8_t *buf, ra8_devcfg_record_t *out)
Decode a validated record buffer into a ra8_devcfg_record_t.
Definition ra8_devcfg.c:331
static void internal_devcfg_pack_le32(uint8_t *dst, uint32_t val)
Store a little-endian 32-bit value into a blob.
Definition ra8_devcfg.c:195
static bool internal_devcfg_probe(const ra8_devcfg_store_t *store, uint32_t offset, ra8_devcfg_record_t *out)
Read one copy through the store and validate it.
Definition ra8_devcfg.c:422
Per-device (per-unit) configuration record – schema, storage seam, two-copy resolution.
@ k_ra8_devcfg_body_bytes
Per-unit payload bytes.
Definition ra8_devcfg.h:96
@ k_ra8_devcfg_schema_ver
Current schema version.
Definition ra8_devcfg.h:94
@ k_ra8_devcfg_magic
"RA8C" record marker.
Definition ra8_devcfg.h:93
@ k_ra8_devcfg_record_len
Active record = header + body.
Definition ra8_devcfg.h:97
@ k_ra8_devcfg_copy0_off
Copy 0 offset in extra-MRAM.
Definition ra8_devcfg.h:101
@ k_ra8_devcfg_copy1_off
Copy 1 offset in extra-MRAM.
Definition ra8_devcfg.h:102
@ k_ra8_devcfg_hdr_bytes
Header page (written LAST).
Definition ra8_devcfg.h:95
@ k_ra8_devcfg_panel_serial_len
Panel identity, NUL-padded.
Definition ra8_devcfg.h:111
@ k_ra8_devcfg_touch_cal_len
ra8_touch_cal_save blob.
Definition ra8_devcfg.h:113
@ k_ra8_devcfg_serial_len
Unit serial, NUL-padded.
Definition ra8_devcfg.h:110
@ k_ra8_devcfg_panel_lut_len
Panel LUT id, e.g.
Definition ra8_devcfg.h:112
@ k_ra8_devcfg_flag_vcom_valid
panel_vcom_mv is real.
Definition ra8_devcfg.h:181
@ k_ra8_devcfg_off_vcom
u16 panel VCOM magnitude (mV).
Definition ra8_devcfg.h:145
@ k_ra8_devcfg_off_fixture
u16 provisioning fixture id.
Definition ra8_devcfg.h:144
@ k_ra8_devcfg_off_hw_rev
u16 board revision.
Definition ra8_devcfg.h:143
@ k_ra8_devcfg_off_magic
u32 magic.
Definition ra8_devcfg.h:130
@ k_ra8_devcfg_off_serial
char[16] serial (body start).
Definition ra8_devcfg.h:137
@ k_ra8_devcfg_off_crc
u32 CRC-32 of the body.
Definition ra8_devcfg.h:134
@ k_ra8_devcfg_off_mfg_date
u32 packed YYYYMMDD.
Definition ra8_devcfg.h:141
@ k_ra8_devcfg_off_panel_lut
char[8] panel LUT id.
Definition ra8_devcfg.h:139
@ k_ra8_devcfg_off_seq
u32 monotonic sequence.
Definition ra8_devcfg.h:133
@ k_ra8_devcfg_off_panel_serial
char[12] panel serial.
Definition ra8_devcfg.h:138
@ k_ra8_devcfg_off_schema
u16 schema_version.
Definition ra8_devcfg.h:131
@ k_ra8_devcfg_off_flags
u32 ra8_devcfg_flags_t.
Definition ra8_devcfg.h:135
@ k_ra8_devcfg_off_key_id
u32 device-key identifier.
Definition ra8_devcfg.h:142
@ k_ra8_devcfg_off_reclen
u16 record_len.
Definition ra8_devcfg.h:132
@ k_ra8_devcfg_off_touch_cal
uint8[36] touch-cal blob.
Definition ra8_devcfg.h:140
@ k_ra8_devcfg_vcom_max_mv
Highest accepted VCOM magnitude, mV.
Definition ra8_devcfg.h:166
@ k_ra8_devcfg_vcom_min_mv
Lowest accepted VCOM magnitude, mV.
Definition ra8_devcfg.h:165
Error Code Definitions for ra8-firmware.
@ k_ra8_err_validation_failed
Validation rule failed (caller-supplied invariant not satisfied).
Definition ra8_err.h:459
@ k_ra8_err_not_initialized
Module not initialized – _init() not yet called successfully.
Definition ra8_err.h:235
@ 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
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_warn(tag, message)
RA8 log warn.
Definition ra8_log.h:347
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
static uint32_t s_state
Decoded per-unit payload (the 96-byte record body).
Definition ra8_devcfg.h:206
Decoded record: the body plus the header discriminators.
Definition ra8_devcfg.h:233
uint32_t flags
ra8_devcfg_flags_t bit-set.
Definition ra8_devcfg.h:235
uint32_t seq
Monotonic sequence of this record.
Definition ra8_devcfg.h:236
uint16_t schema_version
Schema the record was written under.
Definition ra8_devcfg.h:237
ra8_devcfg_body_t body
Per-unit payload.
Definition ra8_devcfg.h:234
Dependency-injection vtable for the record backing store.
Definition ra8_devcfg.h:320
ra8_devcfg_read_fn_t read
Backing read; non-NULL.
Definition ra8_devcfg.h:321
ra8_devcfg_write_fn_t write
Backing write; non-NULL.
Definition ra8_devcfg.h:322