integrationcross-stackembedded
Firmware meets the cloud
10 Hz on the device, 50 ms on the ingest path — one invariant neither codebase can hold alone.
The contract lives in .rq because C and TypeScript cannot see each other.
sensor_sample_rate {
device samples at 10 Hz
implemented in ["./firmware/adc.c".sample_loop]
@tags (
firmware
timing
)
}
api_ingest {
backend must accept a burst within 50 ms
implemented in ["./api/ingest.ts".ingestBatch]
aligns with [sensor_sample_rate]
@tags (
backend
sla
)
}
ingest_contract (
sensor_sample_rate,
api_ingest
)/* rq:["../contracts/ingest.rq".sensor_sample_rate] */
void sample_loop(void) {
const uint32_t period_ms = 100; /* 10 Hz */
for (;;) {
adc_read(&sample);
queue_push(&sample);
sleep_ms(period_ms);
}
}// rq:["../contracts/ingest.rq".api_ingest]
export async function ingestBatch(events: Event[]) {
const deadline = Date.now() + 50;
await queue.push(events, { deadline });
}