ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_epd_cal.c File Reference

Per-device e-paper VCOM calibration – record codec and resolver. More...

#include "ra8_epd_cal.h"
#include <stddef.h>
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_log.h"
Include dependency graph for ra8_epd_cal.c:

Go to the source code of this file.

Enumerations

enum  ra8_epd_cal_crc_t : uint32_t {
  k_ra8_epd_cal_crc_init = 0xFFFFFFFFU ,
  k_ra8_epd_cal_crc_poly = 0xEDB88320U
}
 IEEE 802.3 CRC-32 parameters. More...
enum  ra8_epd_cal_bits_t : uint8_t {
  k_ra8_epd_cal_bits_per_byte = 8U ,
  k_ra8_epd_cal_byte_shift = 8U ,
  k_ra8_epd_cal_byte_mask = 0xFFU ,
  k_ra8_epd_cal_off_b0 = 0U ,
  k_ra8_epd_cal_off_b1 = 1U ,
  k_ra8_epd_cal_off_b2 = 2U ,
  k_ra8_epd_cal_off_b3 = 3U
}
 Byte / word packing constants (no magic numbers). More...

Functions

static uint32_t internal_ra8_epd_cal_crc32 (const uint8_t *data, size_t len)
 Compute the IEEE 802.3 CRC-32 of a byte span.
static void internal_ra8_epd_cal_pack_le16 (uint8_t *dst, uint16_t val)
 Store a little-endian 16-bit value.
static uint16_t internal_ra8_epd_cal_unpack_le16 (const uint8_t *src)
 Load a little-endian 16-bit value.
static void internal_ra8_epd_cal_pack_le32 (uint8_t *dst, uint32_t val)
 Store a little-endian 32-bit value.
static uint32_t internal_ra8_epd_cal_unpack_le32 (const uint8_t *src)
 Load a little-endian 32-bit value.
static bool internal_ra8_epd_cal_magic_ok (const uint8_t *src)
 Report whether a serialised record carries the 'EVCM' magic.
static ra8_err_t internal_ra8_epd_cal_read_record (const ra8_epd_cal_store_t *store, ra8_epd_cal_record_t *out_rec)
 Read and validate the per-device record through the store seam.
bool ra8_epd_cal_vcom_in_range (uint16_t mv, const ra8_epd_cal_limits_mv_t *limits)
 Range-check a candidate VCOM against a panel's documented window.
ra8_err_t ra8_epd_cal_serialize (const ra8_epd_cal_record_t *rec, uint8_t *dst, size_t dst_size)
 Serialise a record into its 32-byte on-flash form.
ra8_err_t ra8_epd_cal_deserialize (const uint8_t *src, size_t src_size, ra8_epd_cal_record_t *out_rec)
 Parse and integrity-check a serialised record.
static ra8_err_t internal_ra8_epd_cal_try_panel (const ra8_epd_cal_cfg_t *cfg, ra8_epd_cal_result_t *out_result)
 Try the controller's own persisted VCOM (resolution source 1).
static ra8_err_t internal_ra8_epd_cal_try_record (const ra8_epd_cal_cfg_t *cfg, ra8_epd_cal_result_t *out_result)
 Try the per-device record in storage (resolution source 2).
ra8_err_t ra8_epd_cal_resolve (const ra8_epd_cal_cfg_t *cfg, ra8_epd_cal_result_t *out_result)
 Resolve the VCOM to drive this panel at, or fail safe.
ra8_err_t ra8_epd_cal_apply (const ra8_epd_cal_cfg_t *cfg, const ra8_epd_cal_result_t *result)
 Programme a resolved VCOM onto the controller and confirm it took.
ra8_err_t ra8_epd_cal_provision (const ra8_epd_cal_cfg_t *cfg, uint16_t vcom_mv)
 Write a per-device calibration record to non-volatile storage.

Variables

static const char *const s_tag = "EPD_CAL"
 Logging tag used by every error path in this TU.

Detailed Description

Per-device e-paper VCOM calibration – record codec and resolver.

Tag
[Ring 4 / Service] {World: NS}

Implements ra8_epd_cal.h. Two responsibilities, deliberately kept apart:

  • a self-describing, CRC-protected record codec (the storage format is unsigned and lives outside the DFU-signed image, so it carries its own integrity check), and
  • a resolver that walks controller -> per-device record -> operator value and fails rather than guesses.

No HAL header is included: the controller and the non-volatile store are reached only through the injected seams in the config struct, which is what lets every branch below run on the host.

Definition in file ra8_epd_cal.c.

Enumeration Type Documentation

◆ ra8_epd_cal_bits_t

enum ra8_epd_cal_bits_t : uint8_t

Byte / word packing constants (no magic numbers).

Enumerator
k_ra8_epd_cal_bits_per_byte 

CRC inner-loop bound.

k_ra8_epd_cal_byte_shift 

Bits per byte.

k_ra8_epd_cal_byte_mask 

Low-byte extraction mask.

k_ra8_epd_cal_off_b0 

Little-endian byte 0.

k_ra8_epd_cal_off_b1 

Little-endian byte 1.

k_ra8_epd_cal_off_b2 

Little-endian byte 2.

k_ra8_epd_cal_off_b3 

Little-endian byte 3.

Definition at line 103 of file ra8_epd_cal.c.

◆ ra8_epd_cal_crc_t

enum ra8_epd_cal_crc_t : uint32_t

IEEE 802.3 CRC-32 parameters.

Bit-banged rather than table-driven so the module has no dependency on a CRC library and no 1 KiB table in a build that only ever checks 32 bytes once per boot. Mirrors the constants in ra8_touch_cal.c so both calibration records use the same polynomial.

Enumerator
k_ra8_epd_cal_crc_init 

CRC seed / final XOR.

k_ra8_epd_cal_crc_poly 

Reversed IEEE 802.3 poly.

Definition at line 94 of file ra8_epd_cal.c.

Function Documentation

◆ internal_ra8_epd_cal_crc32()

uint32_t internal_ra8_epd_cal_crc32 ( const uint8_t * data,
size_t len )
staticnodiscard

Compute the IEEE 802.3 CRC-32 of a byte span.

Bit-banged reflected-polynomial form; no lookup table.

Parameters
[in]dataBytes to checksum; non-NULL.
[in]lenNumber of bytes.
Returns
The CRC-32 of data[0 .. len).
Precondition
data holds at least len readable bytes.
Postcondition
No state mutated.

Definition at line 133 of file ra8_epd_cal.c.

References k_ra8_epd_cal_bits_per_byte, k_ra8_epd_cal_crc_init, and k_ra8_epd_cal_crc_poly.

Referenced by ra8_epd_cal_deserialize(), and ra8_epd_cal_serialize().

◆ internal_ra8_epd_cal_magic_ok()

bool internal_ra8_epd_cal_magic_ok ( const uint8_t * src)
staticnodiscard

Report whether a serialised record carries the 'EVCM' magic.

Parameters
[in]srcSerialised record; non-NULL, >= blob size.
Returns
true when all four magic bytes match.
Precondition
src holds at least k_ra8_epd_cal_blob_size bytes.
Postcondition
No state mutated.

Definition at line 252 of file ra8_epd_cal.c.

References k_ra8_epd_cal_magic_b0, k_ra8_epd_cal_magic_b1, k_ra8_epd_cal_magic_b2, k_ra8_epd_cal_magic_b3, k_ra8_epd_cal_off_b0, k_ra8_epd_cal_off_b1, k_ra8_epd_cal_off_b2, k_ra8_epd_cal_off_b3, and k_ra8_epd_cal_off_magic.

Referenced by ra8_epd_cal_deserialize().

◆ internal_ra8_epd_cal_pack_le16()

void internal_ra8_epd_cal_pack_le16 ( uint8_t * dst,
uint16_t val )
static

Store a little-endian 16-bit value.

The record is serialised byte-at-a-time in an explicit byte order so a blob written on one machine deserialises identically on another. The host test suite is little-endian x86_64 and the target is little-endian Arm, but relying on that would make the on-storage format a property of the compiler rather than of the record.

Parameters
[out]dstDestination for two bytes; non-NULL.
[in]valValue to pack.
Precondition
dst has room for two bytes.
dst points inside the serialisation blob.
Postcondition
dst holds val little-endian.
Exactly two bytes are written.
Note
Not thread-safe; called only from the serialiser.
Since
0.1.0

Definition at line 169 of file ra8_epd_cal.c.

References k_ra8_epd_cal_byte_mask, k_ra8_epd_cal_byte_shift, k_ra8_epd_cal_off_b0, and k_ra8_epd_cal_off_b1.

Referenced by ra8_epd_cal_serialize().

◆ internal_ra8_epd_cal_pack_le32()

void internal_ra8_epd_cal_pack_le32 ( uint8_t * dst,
uint32_t val )
static

Store a little-endian 32-bit value.

The 32-bit counterpart of internal_ra8_epd_cal_pack_le16, used for the magic word and the CRC. Same rationale: the byte order is a property of the record format, not of the compiler that wrote it.

Parameters
[out]dstDestination for four bytes; non-NULL.
[in]valValue to pack.
Precondition
dst has room for four bytes.
dst points inside the serialisation blob.
Postcondition
dst holds val little-endian.
Exactly four bytes are written.
Note
Not thread-safe; called only from the serialiser.
Since
0.1.0

Definition at line 213 of file ra8_epd_cal.c.

References k_ra8_epd_cal_byte_mask, k_ra8_epd_cal_byte_shift, k_ra8_epd_cal_off_b0, k_ra8_epd_cal_off_b1, k_ra8_epd_cal_off_b2, and k_ra8_epd_cal_off_b3.

Referenced by ra8_epd_cal_serialize().

◆ internal_ra8_epd_cal_read_record()

ra8_err_t internal_ra8_epd_cal_read_record ( const ra8_epd_cal_store_t * store,
ra8_epd_cal_record_t * out_rec )
staticnodiscard

Read and validate the per-device record through the store seam.

Any failure – unbound seam, read fault, blank flash, corrupt record – reports "no record" so the resolver falls through to the next source. The distinction between the failure modes is logged, not returned, because the resolver's behaviour is the same for all of them.

Parameters
[in]storeStore seam; non-NULL.
[out]out_recReceives the decoded record; non-NULL.
Returns
k_ra8_ok when a valid record was decoded, else an error.
Precondition
store and out_rec are readable / writable.
Postcondition
On success out_rec->vcom_mv is non-zero.

Definition at line 279 of file ra8_epd_cal.c.

References ra8_epd_cal_store_t::ctx, k_ra8_epd_cal_blob_size, k_ra8_err_crc_mismatch, k_ra8_err_not_supported, k_ra8_ok, ra8_epd_cal_deserialize(), ra8_log_error, ra8_log_warn, ra8_epd_cal_store_t::read, and s_tag.

Referenced by internal_ra8_epd_cal_try_record().

◆ internal_ra8_epd_cal_try_panel()

ra8_err_t internal_ra8_epd_cal_try_panel ( const ra8_epd_cal_cfg_t * cfg,
ra8_epd_cal_result_t * out_result )
staticnodiscard

Try the controller's own persisted VCOM (resolution source 1).

A vendor-provisioned IT8951 driver board powers up holding the right VCOM, which is what makes a stock HAT work without provisioning. The value is still range-checked: a controller that has not finished booting reports 0, and a failed read reports 0xFFFF.

Parameters
[in]cfgResolution config; non-NULL.
[out]out_resultPopulated only on success; non-NULL.
Returns
k_ra8_ok when the controller supplied an in-range value.
Precondition
cfg and out_result are readable / writable.
cfg->limits has been validated by the caller.
Postcondition
On success out_result->source is k_ra8_epd_cal_src_panel.
On failure *out_result is untouched.

Definition at line 410 of file ra8_epd_cal.c.

References ra8_epd_cal_panel_ops_t::ctx, ra8_epd_cal_panel_ops_t::get, k_ra8_epd_cal_src_panel, k_ra8_err_hw_error, k_ra8_err_not_supported, k_ra8_err_range_check_failed, k_ra8_ok, ra8_epd_cal_cfg_t::limits, ra8_epd_cal_cfg_t::panel, ra8_epd_cal_vcom_in_range(), ra8_log_warn, s_tag, ra8_epd_cal_result_t::source, and ra8_epd_cal_result_t::vcom_mv.

Referenced by ra8_epd_cal_resolve().

◆ internal_ra8_epd_cal_try_record()

ra8_err_t internal_ra8_epd_cal_try_record ( const ra8_epd_cal_cfg_t * cfg,
ra8_epd_cal_result_t * out_result )
staticnodiscard

Try the per-device record in storage (resolution source 2).

The authority once a panel has been provisioned on this device, and the only source that survives a controller which has forgotten its own configuration. Lives outside both DFU code banks so a firmware update or a rollback cannot erase it.

Parameters
[in]cfgResolution config; non-NULL.
[out]out_resultPopulated only on success; non-NULL.
Returns
k_ra8_ok when a valid, in-range record was found.
Precondition
cfg and out_result are readable / writable.
cfg->limits has been validated by the caller.
Postcondition
On success out_result->source is k_ra8_epd_cal_src_record.
On failure *out_result is untouched.

Definition at line 448 of file ra8_epd_cal.c.

References internal_ra8_epd_cal_read_record(), k_ra8_epd_cal_src_record, k_ra8_err_not_found, k_ra8_err_range_check_failed, k_ra8_ok, ra8_epd_cal_cfg_t::limits, ra8_epd_cal_vcom_in_range(), ra8_log_warn, s_tag, ra8_epd_cal_result_t::source, ra8_epd_cal_cfg_t::store, ra8_epd_cal_record_t::vcom_mv, and ra8_epd_cal_result_t::vcom_mv.

Referenced by ra8_epd_cal_resolve().

◆ internal_ra8_epd_cal_unpack_le16()

uint16_t internal_ra8_epd_cal_unpack_le16 ( const uint8_t * src)
staticnodiscard

Load a little-endian 16-bit value.

Parameters
[in]srcTwo source bytes; non-NULL.
Returns
The unpacked value.
Precondition
src holds at least two readable bytes.
Postcondition
No state mutated.

Definition at line 186 of file ra8_epd_cal.c.

References k_ra8_epd_cal_byte_shift, k_ra8_epd_cal_off_b0, and k_ra8_epd_cal_off_b1.

Referenced by ra8_epd_cal_deserialize().

◆ internal_ra8_epd_cal_unpack_le32()

uint32_t internal_ra8_epd_cal_unpack_le32 ( const uint8_t * src)
staticnodiscard

Load a little-endian 32-bit value.

Parameters
[in]srcFour source bytes; non-NULL.
Returns
The unpacked value.
Precondition
src holds at least four readable bytes.
Postcondition
No state mutated.

Definition at line 234 of file ra8_epd_cal.c.

References k_ra8_epd_cal_byte_shift, k_ra8_epd_cal_off_b0, k_ra8_epd_cal_off_b1, k_ra8_epd_cal_off_b2, and k_ra8_epd_cal_off_b3.

Referenced by ra8_epd_cal_deserialize().

◆ ra8_epd_cal_apply()

ra8_err_t ra8_epd_cal_apply ( const ra8_epd_cal_cfg_t * cfg,
const ra8_epd_cal_result_t * result )
nodiscard

Programme a resolved VCOM onto the controller and confirm it took.

Re-checks the value against cfg->limits before writing it, writes it through cfg->panel.set, then reads it straight back through cfg->panel.get and requires an exact match. The pre-write re-check is deliberate belt-and-braces – result is caller-owned memory between resolve and here, and this is the last point before a number reaches the panel.

The readback is the load-bearing part. A dead link, a controller that ignores the command, or a bus stuck returning zeroes all accept the write and change nothing; without the compare that is indistinguishable from success, and the film would sit biased at the controller's own unknown value. The readback is compared for equality and deliberately not re-range-checked – the written value was range-checked a few lines earlier, so an equal readback is in range by construction and a second test would be unreachable code wearing a safety check's clothes. Range validation of a value the controller reports belongs where such a value is adopted rather than confirmed, which is the resolve-from- controller source, and it is applied there.

A cfg with no panel.get binding is rejected rather than write-and-hope: an unconfirmable bias is not one to leave on a panel.

Parameters
[in]cfgSeams and limits; non-NULL, with both panel.set and panel.get bound.
[in]resultA successful ra8_epd_cal_resolve outcome; non-NULL.
Returns
ra8_err_t Error code.
Return values
k_ra8_okController accepted the VCOM and echoed it back unchanged.
k_ra8_err_null_ptrcfg or result is NULL.
k_ra8_err_invalid_stateresult->source is none.
k_ra8_err_not_supportedcfg->panel.set or cfg->panel.get is not bound.
k_ra8_err_range_check_failedresult->vcom_mv is out of range.
k_ra8_err_hw_errorThe readback transaction failed.
k_ra8_err_validation_failedThe controller echoed a different value. Do not drive the panel.
otherForwarded from cfg->panel.set.
Precondition
result came from a successful ra8_epd_cal_resolve.
cfg->panel.set and cfg->panel.get are bound to the controller.
Postcondition
On success the controller reports result->vcom_mv as its VCOM.
On failure the caller must leave the panel dark – the bias in effect is unknown, which is precisely the state to refuse.
Note
Not thread-safe; boot-path use only.
See also
ra8_epd_cal_resolve
ra8_epaper_set_vcom
Since
0.1.0

Definition at line 507 of file ra8_epd_cal.c.

References ra8_epd_cal_panel_ops_t::ctx, ra8_epd_cal_panel_ops_t::get, k_ra8_epd_cal_src_none, k_ra8_err_hw_error, k_ra8_err_invalid_state, k_ra8_err_not_supported, k_ra8_err_range_check_failed, k_ra8_err_validation_failed, k_ra8_ok, ra8_epd_cal_cfg_t::limits, ra8_epd_cal_cfg_t::panel, RA8_CHECK_NULL_PTR, ra8_epd_cal_vcom_in_range(), ra8_log_error, s_tag, ra8_epd_cal_panel_ops_t::set, ra8_epd_cal_result_t::source, and ra8_epd_cal_result_t::vcom_mv.

Referenced by ep_calibrate_vcom().

◆ ra8_epd_cal_deserialize()

ra8_err_t ra8_epd_cal_deserialize ( const uint8_t * src,
size_t src_size,
ra8_epd_cal_record_t * out_rec )
nodiscard

Parse and integrity-check a serialised record.

Validation order is magic, then schema version, then payload length, then CRC-32. Each rejection is distinct so a caller can tell "never provisioned" (blank flash fails the magic check) from "provisioned but corrupted" (magic passes, CRC fails) – the two demand different operator responses.

A record whose version exceeds k_ra8_epd_cal_schema_version is rejected rather than best-effort parsed: a newer writer may have redefined the payload, and misreading calibration is exactly the failure this module exists to prevent.

Parameters
[in]srcSerialised record; non-NULL.
[in]src_sizeBytes available at src; must be >= k_ra8_epd_cal_blob_size.
[out]out_recReceives the decoded record; non-NULL.
Returns
ra8_err_t Error code.
Return values
k_ra8_okRecord valid; *out_rec populated.
k_ra8_err_null_ptrsrc or out_rec is NULL.
k_ra8_err_invalid_sizesrc_size too small.
k_ra8_err_not_foundMagic absent – never provisioned.
k_ra8_err_not_supportedSchema version newer than this build.
k_ra8_err_validation_failedPayload length wrong for the schema.
k_ra8_err_crc_mismatchCRC trailer does not match the body.
Precondition
src holds at least src_size readable bytes.
out_rec is writable.
Postcondition
On success out_rec->vcom_mv is non-zero.
On failure *out_rec is untouched.
Note
Thread-safe (no shared state).
See also
ra8_epd_cal_serialize
Since
0.1.0

Definition at line 348 of file ra8_epd_cal.c.

References internal_ra8_epd_cal_crc32(), internal_ra8_epd_cal_magic_ok(), internal_ra8_epd_cal_unpack_le16(), internal_ra8_epd_cal_unpack_le32(), k_ra8_epd_cal_blob_size, k_ra8_epd_cal_off_crc32, k_ra8_epd_cal_off_payload_len, k_ra8_epd_cal_off_vcom_mv, k_ra8_epd_cal_off_version, k_ra8_epd_cal_payload_len, k_ra8_epd_cal_schema_version, k_ra8_err_crc_mismatch, k_ra8_err_invalid_size, k_ra8_err_not_found, k_ra8_err_not_supported, k_ra8_err_validation_failed, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_log_error, s_tag, ra8_epd_cal_record_t::schema_version, and ra8_epd_cal_record_t::vcom_mv.

Referenced by internal_ra8_epd_cal_read_record().

◆ ra8_epd_cal_provision()

ra8_err_t ra8_epd_cal_provision ( const ra8_epd_cal_cfg_t * cfg,
uint16_t vcom_mv )
nodiscard

Write a per-device calibration record to non-volatile storage.

The explicit provisioning path: range-checks vcom_mv, serialises a sealed record and commits it through cfg->store.write. Called by a provisioning app or a service menu after the operator enters the value printed on the panel's flex cable – never automatically from a boot path, so calibration cannot drift without someone asking for it.

Parameters
[in]cfgSeams and limits; non-NULL.
[in]vcom_mvVCOM magnitude to persist, in millivolts.
Returns
ra8_err_t Error code.
Return values
k_ra8_okRecord committed durably.
k_ra8_err_null_ptrcfg is NULL.
k_ra8_err_not_supportedcfg->store.write is not bound.
k_ra8_err_range_check_failedvcom_mv outside cfg->limits.
otherForwarded from cfg->store.write.
Precondition
vcom_mv was read off this panel's own flex cable.
cfg->store.write targets storage outside both DFU code banks.
Postcondition
On success a later ra8_epd_cal_resolve finds the record.
On failure nothing was persisted.
Note
Not thread-safe.
Warning
Provisioning the wrong number is exactly as damaging as having none. Confirm the value against the panel's flex cable.
See also
ra8_epd_cal_resolve
Since
0.1.0

Definition at line 554 of file ra8_epd_cal.c.

References ra8_epd_cal_store_t::ctx, k_ra8_epd_cal_blob_size, k_ra8_epd_cal_schema_version, k_ra8_err_not_supported, k_ra8_err_range_check_failed, k_ra8_ok, ra8_epd_cal_cfg_t::limits, RA8_CHECK_NULL_PTR, ra8_epd_cal_serialize(), ra8_epd_cal_vcom_in_range(), ra8_log_error, s_tag, ra8_epd_cal_cfg_t::store, and ra8_epd_cal_store_t::write.

◆ ra8_epd_cal_resolve()

ra8_err_t ra8_epd_cal_resolve ( const ra8_epd_cal_cfg_t * cfg,
ra8_epd_cal_result_t * out_result )
nodiscard

Resolve the VCOM to drive this panel at, or fail safe.

Walks the sources documented at the top of this file – controller, then per-device record, then operator-provisioned value – and returns the first that yields a value inside cfg->limits. Every source is optional: a NULL seam or a failing read simply moves to the next.

This function never invents a value. When no source yields an in-range number it returns k_ra8_err_not_found with out_result->source == k_ra8_epd_cal_src_none and vcom_mv == 0, and the caller must not drive the panel. That is the whole point: an unpowered panel is recoverable, a panel driven at a guessed bias is not.

Parameters
[in]cfgSeams, limits and any provisioning value; non-NULL.
[out]out_resultReceives the resolved value and its provenance; non-NULL.
Returns
ra8_err_t Error code.
Return values
k_ra8_okA trusted VCOM was resolved.
k_ra8_err_null_ptrcfg or out_result is NULL.
k_ra8_err_invalid_argcfg->limits is self-inconsistent (zero or inverted window).
k_ra8_err_not_foundNo source produced an in-range value – refuse to drive the panel.
Precondition
The controller has been initialised if cfg->panel.get is bound.
cfg->limits states the panel's documented VCOM window.
Postcondition
On success out_result->vcom_mv is inside cfg->limits.
On failure out_result->source is k_ra8_epd_cal_src_none.
Note
Not thread-safe; boot-path use only.
Warning
Success means "a value worth trusting was found", not "the panel is now driving at it". Call ra8_epd_cal_apply to programme it.
Example:
if (ra8_epd_cal_resolve(&cfg, &r) != k_ra8_ok) {
ra8_log_error("APP", "no trusted VCOM -- panel left dark");
return k_ra8_err_not_found; // fail safe
}
(void)ra8_epd_cal_apply(&cfg, &r);
ra8_err_t ra8_epd_cal_resolve(const ra8_epd_cal_cfg_t *cfg, ra8_epd_cal_result_t *out_result)
Resolve the VCOM to drive this panel at, or fail safe.
ra8_err_t ra8_epd_cal_apply(const ra8_epd_cal_cfg_t *cfg, const ra8_epd_cal_result_t *result)
Programme a resolved VCOM onto the controller and confirm it took.
@ 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
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
Outcome of ra8_epd_cal_resolve.
See also
ra8_epd_cal_apply
ra8_epd_cal_provision
Since
0.1.0

Definition at line 464 of file ra8_epd_cal.c.

References ra8_epd_cal_cfg_t::has_provisioned, internal_ra8_epd_cal_try_panel(), internal_ra8_epd_cal_try_record(), k_ra8_epd_cal_src_bench, k_ra8_epd_cal_src_none, k_ra8_epd_cal_src_provisioned, k_ra8_err_invalid_arg, k_ra8_err_not_found, k_ra8_ok, ra8_epd_cal_cfg_t::limits, ra8_epd_cal_limits_mv_t::max_mv, ra8_epd_cal_limits_mv_t::min_mv, ra8_epd_cal_cfg_t::provisioned_mv, RA8_CHECK_NULL_PTR, ra8_epd_cal_vcom_in_range(), ra8_log_error, ra8_log_warn, s_tag, ra8_epd_cal_result_t::source, and ra8_epd_cal_result_t::vcom_mv.

Referenced by ep_calibrate_vcom().

◆ ra8_epd_cal_serialize()

ra8_err_t ra8_epd_cal_serialize ( const ra8_epd_cal_record_t * rec,
uint8_t * dst,
size_t dst_size )
nodiscard

Serialise a record into its 32-byte on-flash form.

Writes magic, schema version, payload length and the VCOM field, zeroes every reserved byte, then appends the CRC-32 (IEEE 802.3) of everything preceding the trailer. Reserved bytes are zeroed rather than left undefined so the CRC is reproducible for a given record.

Parameters
[in]recRecord to serialise; non-NULL.
[out]dstDestination buffer; non-NULL.
[in]dst_sizeCapacity of dst; must be >= k_ra8_epd_cal_blob_size.
Returns
ra8_err_t Error code.
Return values
k_ra8_okdst holds a sealed record.
k_ra8_err_null_ptrrec or dst is NULL.
k_ra8_err_invalid_sizedst_size too small.
k_ra8_err_invalid_argrec->vcom_mv is zero.
Precondition
dst has room for k_ra8_epd_cal_blob_size bytes.
rec->vcom_mv was range-checked by the caller.
Postcondition
On success ra8_epd_cal_deserialize round-trips dst.
On failure dst is untouched.
Note
Thread-safe (no shared state).
See also
ra8_epd_cal_deserialize
Since
0.1.0

Definition at line 318 of file ra8_epd_cal.c.

References internal_ra8_epd_cal_crc32(), internal_ra8_epd_cal_pack_le16(), internal_ra8_epd_cal_pack_le32(), k_ra8_epd_cal_blob_size, k_ra8_epd_cal_magic_b0, k_ra8_epd_cal_magic_b1, k_ra8_epd_cal_magic_b2, k_ra8_epd_cal_magic_b3, k_ra8_epd_cal_off_b0, k_ra8_epd_cal_off_b1, k_ra8_epd_cal_off_b2, k_ra8_epd_cal_off_b3, k_ra8_epd_cal_off_crc32, k_ra8_epd_cal_off_magic, k_ra8_epd_cal_off_payload_len, k_ra8_epd_cal_off_vcom_mv, k_ra8_epd_cal_off_version, k_ra8_epd_cal_payload_len, k_ra8_epd_cal_schema_version, k_ra8_err_invalid_arg, k_ra8_err_invalid_size, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_log_error, s_tag, and ra8_epd_cal_record_t::vcom_mv.

Referenced by ra8_epd_cal_provision().

◆ ra8_epd_cal_vcom_in_range()

bool ra8_epd_cal_vcom_in_range ( uint16_t mv,
const ra8_epd_cal_limits_mv_t * limits )
nodiscard

Range-check a candidate VCOM against a panel's documented window.

The single decision every source's value passes through. Rejects the two failure signatures that matter in practice – 0 from a controller that has not finished booting, and 0xFFFF from blank flash or a failed read – by requiring a non-zero min_mv in the limits.

Parameters
[in]mvCandidate VCOM magnitude in millivolts.
[in]limitsPanel's documented window; non-NULL.
Returns
Whether mv may be programmed.
Return values
truelimits->min_mv <= mv <= limits->max_mv.
falsemv is outside the window, or limits is NULL.
Precondition
limits is NULL or readable.
limits->min_mv <= limits->max_mv.
Postcondition
No state mutated.
Return depends solely on the arguments.
Note
Pure function; thread-safe.
See also
ra8_epd_cal_resolve
Since
0.1.0

Definition at line 306 of file ra8_epd_cal.c.

References ra8_epd_cal_limits_mv_t::max_mv.

Referenced by internal_ra8_epd_cal_try_panel(), internal_ra8_epd_cal_try_record(), ra8_epd_cal_apply(), ra8_epd_cal_provision(), and ra8_epd_cal_resolve().

Variable Documentation

◆ s_tag

const char* const s_tag = "EPD_CAL"
static

Logging tag used by every error path in this TU.

Definition at line 39 of file ra8_epd_cal.c.