SDK for TESAIoT Dev Kit
API reference & tutorials (ModusToolbox)
Loading...
Searching...
No Matches

Functions

void optiga_manager_touch_hold (void)
 Counted hold for the whole chip conversation; the first hold sleeps 50 ms.
void optiga_manager_touch_hold_reason (const char *reason)
 The same counted hold, plus the busy-modal string CM55 shows while touch is off.
void optiga_manager_touch_release (void)
 Decrement the hold counter — strict 1:1 with every hold, on every early return.

Detailed Description

Three functions — keeping CM55 off the shared bus. The secure element and the CM55 touch controller share one I2C bus (SCB5 on the AI Kit). A hold asks CM55 to stop polling touch for the duration of a chip conversation; a release lets it resume. The hold is a counter (s_touch_holds, tesaiot_optiga_manager.c:290): nesting is safe and required, and every hold needs exactly one release on every exit path — "an unbalanced release leaves the panel dead" (ipc_hsm_handler.c:1873-1877).

The ban: never send a raw IPC_CMD_TOUCH_RESUME yourself. CM55 treats it as an unconditional touch_disabled = false, cancelling another task's hold, and the next chip transfer collides with a touch read — OPTIGA_COMMS_ERROR (0x0102) (ipc_hsm_handler.c:1393-1405). Only optiga_manager_touch_release() decrements the counter.

Variant
mtb-mpy and mtb-only

Function Documentation

◆ optiga_manager_touch_hold()

void optiga_manager_touch_hold ( void )

Counted hold for the whole chip conversation; the first hold sleeps 50 ms.

Hold the chip powered between operations, and let it go again. _reason is the same hold with a string for the log.

Contract
Counted hold; the first hold sleeps 50 ms so an in-flight touch transfer can finish. Take it for the whole chip conversation, not per operation — releasing between steps reopens the same window. Structure the function so every exit funnels through one release label (goto pu_done in the ingest). It is a thin wrapper over optiga_manager_touch_hold_reason("Signing with secure element"). The two bare call sites in optiga_trust_helpers.c are the TLS signing path (:1673, inside trustm_ecdsa_sign) and the staged-model verify (:4629); both nest inside an outer lock or gate.
Variant
mtb-mpy and mtb-only
/* ...context: inside the Protected Update bundle ingest ... */
/* Keep CM55 touch off the bus for the whole ingest.
*
* The secure element and the touch controller share SCB5 on this board.
* The carried-over reference has no touchscreen and so no notion of this;
* dropped in here unchanged, its longest writes lose the bus mid-transfer.
* Observed 2026-08-06 on correlation bento-pu-1: the 8-byte trust anchor
* metadata write succeeded, and the 580-byte certificate write that follows
* failed with 0x0102 — OPTIGA_COMMS_ERROR, the transport layer, not the
* chip refusing anything — after 57 seconds of comms retries.
*
* Held across the entire function rather than per operation: the ingest is
* one long conversation with the chip, and releasing between steps would
* reopen the same window. Counted, so the signature path inside
* trustm_ecdsa_sign() nests without resuming polling early. Every exit runs
* through pu_done, which releases it. */
/* ...context: inside optiga_verify_staged_model() ... */
return STAGE_SIG_CHIP_ERROR;
}
/* Same bus discipline every other transaction here uses: the secure
* element and the touch controller share SCB5. */

◆ optiga_manager_touch_hold_reason()

void optiga_manager_touch_hold_reason ( const char * reason)

The same counted hold, plus the busy-modal string CM55 shows while touch is off.

Contract
The same counted hold, plus a string that CM55 surfaces on the provisioning screen while touch is off (the busy modal). Same pairing rule. The lifted site shows the one detail people miss: the hold is released on the failed optiga_chip_enter() branch too (ipc_hsm_handler.c:2419-2420) — the hold was taken before the gate, so a refused gate still owes a release.
Variant
mtb-mpy and mtb-only
/* ...context: inside the synchronous credential read ... */
/* Pause CM55 touch to get exclusive SCB0 I2C access */
optiga_manager_touch_hold_reason("Reading stored credentials");
/* These take s_optiga_mutex but never entered the gate, so they were the
* third mechanism that did not know about the other two. */
xSemaphoreGive(s_optiga_mutex);
return false;
}
bool ok = false;
if (optiga_open()) {
uint16_t len = read_oid(oid, buf, buf_len);
printf("[HSM] cred_read_sync: slot %u OID 0x%04X → %u bytes\r\n",
slot, oid, len);
if (len > 0) {
if (out_len) *out_len = len;
ok = true;
}
optiga_close();
} else {
printf("[HSM] cred_read_sync: optiga_open FAILED (slot %u)\r\n", slot);
}
/* Resume CM55 touch polling */

◆ optiga_manager_touch_release()

void optiga_manager_touch_release ( void )

Decrement the hold counter — strict 1:1 with every hold, on every early return.

Contract
Decrements the counter; CM55 resumes touch polling when it reaches zero. Strict 1:1 with every hold, on every early return. The five *_held() wrappers in ipc_hsm_handler.c are the cleanest demonstration: each takes one hold, does one thing, releases once, returns. "Nothing holds across the 60 second wait for the platform" — a hold is for a chip conversation, never for a network wait. mqtt_mtls_setup.c is the every-early-return reference: seven releases for one hold, one per exit.
Variant
mtb-mpy and mtb-only
static bool prov_open_held(void)
{
bool ok;
optiga_manager_touch_hold_reason("Opening the secure element");
return ok;
}
static void prov_close_held(void)
{
optiga_manager_touch_hold_reason("Closing the secure element");
}
static bool prov_make_csr_held(uint16_t key_oid)
{
bool ok;
optiga_manager_touch_hold_reason("Generating a key and signing the request");
ok = prov_make_csr(key_oid);
return ok;
}
static uint16_t prov_manifest_anchor_held(uint16_t oid)
{
uint16_t anchor;
optiga_manager_touch_hold_reason("Reading the secure element");
return anchor;
}
static int prov_publish_pu_held(const char *target, const char *anchor)
{
int rc;
optiga_manager_touch_hold_reason("Generating a key and signing the request");
rc = tesaiot_publish_protected_update(target, anchor, 1U, true);
return rc;
}