TT Lab
Get started
Learn Learning paths Courses

The Fridge Insists It Is 255°C

Retries made us miss the next task

Continue in TT Lab

In one line

Transfer, recovery, and retry share a single time budget. A success response that arrives late is not a success for this call.

Why this was needed

If you give 10 ms to the transfer, 10 ms to the recovery, and another 10 ms to the retry, that is not a "read that finishes within 10 ms". The control loop needs to do its next job, yet one sensor can hold up the flow of execution. Before it is an option of an individual API, a timeout is the deadline the caller promised for the whole operation. The clock in this lab is deterministic model time; it does not measure real CPU execution delay.

How it works

Read the start time once and compute deadline = start + budget. Always pass the same deadline to transfer and recover. If the first transfer takes 3 ms, the recovery 2 ms, and the second transfer 3 ms, the total is 8 ms. With a 10 ms budget this can succeed, but with 7 ms the second transfer cannot finish. Creating a new budget on retry is extending the time.

The assumption that the HAL keeps its time promise is also tested. With a model that returns a late success, you must read the clock again right after the call and return SENSOR_TIMEOUT if the elapsed time has reached the budget. Do the same check after recovery. A result that arrives exactly at the deadline is also a timeout in this task. If you do not state whether the boundary is inclusive, the tests and the implementation end up keeping different promises.

The clock is uint32_t milliseconds and wraps back to 0 after the maximum. So an absolute comparison such as now >= deadline can go wrong just before or just after the wrap. This task limits the budget to 1 to INT32_MAX and, under the premise that the clock wraps at most once in the observed interval, computes elapsed time with unsigned subtraction. It uses the modular arithmetic of uint32_t; it is not magic that solves every clock jump.

In the last step you treat the arguments as a boundary too. Before any I/O, check whether bus, out, and the three callbacks are NULL and whether the address and budget are within the allowed range. You cannot return an error after dereferencing a bad pointer. ctx is an opaque value defined by the HAL, so the driver does not unconditionally reject NULL. The two fields of the output pointer change only on a successful call.

Calculate by hand the moment the clock wraps to 0

If you set the start to 0xfffffffe and the budget to 4 ms, the 32-bit deadline becomes 2. When the current time is 1, 3 ms have elapsed, and when it is 2, 4 ms have elapsed. The latter is a timeout under this contract. The Python below is an arithmetic experiment that does not control a sensor. It states the mask explicitly so that Python, whose integers are unbounded, still reproduces a 32-bit clock. If you paste it into Python from a shell, the last line is printed only when both boundaries are right.

mask = (1 << 32) - 1
start, budget = 0xfffffffe, 4
deadline = (start + budget) & mask
elapsed_before = (1 - start) & mask
elapsed_at = (2 - start) & mask
assert deadline == 2
assert elapsed_before == 3 and elapsed_before < budget
assert elapsed_at == 4 and elapsed_at >= budget
print("기한 직전 성공 후보 / 기한 도착 시간 초과")

I call it a success candidate because meeting the time alone does not make the data valid. A SENSOR_SHORT that arrives before the deadline is still a failure, and two bytes with a wrong reserved bit are not a success either. Success needs all three conditions: transfer status, format, and time. Conversely, even if the transfer returns SENSOR_OK, if the moment the completion was confirmed is at or past the deadline, you do not change the public sample.

Let's compare another record with a start of 100 ms and a budget of 7 ms. The first transfer returns BUS at 103 ms, the recovery returns OK at 105 ms, and the retransfer returns OK at 108 ms. The deadline passed to all three calls is 107 ms. Even though the last status is OK, the elapsed time is 8 ms, so it is a timeout, and you preserve the original temperature and time. If you give a new budget starting from the recovery, or subtract the recovery time, the caller's promise to "finish within 7 ms" is silently changed.

A time check after the call cannot forcibly abort a HAL function that has stopped forever. The driver can read the clock again only after the callback returns. To guarantee an upper bound on response time in real hardware, you need separate design and measurement, such as a bounded wait in the HAL itself, cancellation, or a hardware timer. The deterministic callbacks and the execution-time limit of this lab are not a substitute for that kind of real-time guarantee. Distinguish the result of verifying the contract in model time from the result of measuring the real worst-case execution time.

What it looks like in the field

The observed_ms of a sensor sample is the moment the host confirmed that the transfer completed. It is not the moment the ADC converted the real temperature, so "just read" alone does not let you say "just measured". The higher-level program must show the last success time together with the current error so that an old value does not look like a normal latest value. You must also test that the next good read after a failure updates the sample again.

Real-hardware verification remains even after you finish. The pull-up, wiring, power, clock, the sensor's conversion period, and the real HAL implementation are not verified by this model. In your portfolio, write "host C + deterministic HAL model", and separate the inputs, states, and deadlines you verified from the physical items you did not. Passing the model is grounds for preparing the next real-hardware test, not a guarantee of safety in the field.

What you will do in the next lab

In steps 7–8 you complete the shared deadline, late success, wraparound, and argument checks. The full grading rechecks up to the earlier steps. In a good → partial failure → good sequence, check that the last good sample is preserved and then replaced by the new sample. Files disappear when the session ends, so keep the source and your test records separately.