LabHub
배우기 러닝패스 코스

The Fridge Insists It Is 255°C

Retries made us miss the next task

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

한 줄 요약

전송·복구·재시도는 하나의 시간 예산을 나눠 씁니다. 성공 응답도 늦게 왔다면 이번 호출의 성공이 아닙니다.

Concept map: 한 줄 요약 · 왜 이게 필요했나 · 어떻게 동작하나 · 시계가 0으로 돌아가는 순간을 직접 계산한다

왜 이게 필요했나

전송에 10ms, 복구에 10ms, 재시도에 다시 10ms를 주면 ‘10ms 안에 끝나는 읽기’가 아닙니다. 제어 루프가 다음 일을 해야 하는데 센서 하나가 실행 흐름을 붙잡을 수 있습니다. timeout은 개별 API의 옵션이기 전에 호출자가 전체 작업에 약속한 기한입니다. 본 실습의 시계는 결정적 모델 시간이고 실제 CPU 실행 지연을 측정하는 것이 아닙니다.

어떻게 동작하나

시작 시각을 한 번 읽고 deadline = start + budget을 구합니다. transfer와 recover에 늘 같은 deadline을 넘깁니다. 첫 전송 3ms, 복구 2ms, 두 번째 전송 3ms라면 합계 8ms입니다. 예산 10ms에서는 성공할 수 있지만 7ms에서는 두 번째 전송이 끝날 수 없습니다. 재시도 때 새 예산을 만드는 것은 시간을 연장한 것입니다.

HAL이 시간 약속을 지킨다는 가정도 시험합니다. 늦은 성공을 반환하는 모델에서는 호출 직후 시계를 다시 읽고 예산 이상 경과했다면 SENSOR_TIMEOUT을 반환해야 합니다. 복구 후에도 같은 검사를 합니다. 정확히 기한에 도착한 결과도 과제에서는 시간 초과입니다. 경계의 포함 여부를 명시하지 않으면 테스트와 구현이 서로 다른 약속을 지키게 됩니다.

시계는 uint32_t 밀리초이고 최댓값 다음에 0으로 돌아갑니다. 따라서 now >= deadline이라는 절대 비교는 래핑 직전·직후에 잘못될 수 있습니다. 이 과제는 예산을 1~INT32_MAX로 제한하고, 관찰 구간에서 래핑이 최대 한 번이라는 전제 아래 unsigned 뺄셈으로 경과 시간을 구합니다. uint32_t의 모듈러 연산을 쓰는 것이지 모든 시계 점프를 해결하는 마법은 아닙니다.

마지막 단계에서는 인자도 경계로 봅니다. bus와 out, 세 콜백이 NULL인지, 주소와 예산이 허용 범위인지 I/O 전에 검사합니다. 잘못된 포인터를 역참조한 뒤 오류를 반환할 수는 없습니다. ctx는 HAL이 정하는 불투명한 값이므로 드라이버가 무조건 NULL을 거부하지 않습니다. 출력 포인터의 두 필드는 성공한 호출에서만 바뀝니다.

시계가 0으로 돌아가는 순간을 직접 계산한다

시작을 0xfffffffe, 예산을 4ms로 정하면 32비트 기한은 2가 됩니다. 현재 시각이 1일 때는 3ms가 지났고, 2일 때는 4ms가 지났습니다. 후자는 이번 계약에서 시간 초과입니다. 아래 Python은 센서를 제어하지 않는 산술 실험입니다. 무제한 정수인 Python에서도 32비트 시계를 재현하도록 마스크를 명시합니다. 셸에서 Python에 붙여 실행하면 두 경계가 맞을 때만 마지막 문장이 출력됩니다.

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("기한 직전 성공 후보 / 기한 도착 시간 초과")

성공 후보라고 쓴 이유는 시간만 만족했다고 데이터까지 유효한 것은 아니기 때문입니다. 기한 안에 온 SENSOR_SHORT는 여전히 실패이고 예약 비트가 틀린 두 바이트도 성공이 아닙니다. 성공에는 전송 상태·형식·시간 세 조건이 모두 필요합니다. 반대로 전송이 SENSOR_OK여도 완료를 확인한 시점이 기한 이상이면 공개 표본은 바꾸지 않습니다.

시작 100ms·예산 7ms인 또 다른 기록을 비교해 봅시다. 첫 전송이 103ms에 BUS, 복구가 105ms에 OK, 재전송이 108ms에 OK를 돌려줍니다. 세 호출에 전달할 기한은 모두 107ms입니다. 마지막 상태가 OK여도 경과 8ms이므로 시간 초과이며, 처음의 온도와 시각을 보존합니다. 복구부터 새 예산을 주거나 복구 시간을 빼면 ‘7ms 안에 끝내라’는 호출자의 약속이 조용히 바뀝니다.

호출 뒤의 시간 검사는 무한히 멈춘 HAL 함수를 강제로 중단시키지 못합니다. 콜백이 돌아와야 드라이버가 시계를 다시 읽을 수 있기 때문입니다. 실물에서 응답 시간 상한을 보장하려면 HAL 자체의 제한된 대기·취소·하드웨어 타이머 같은 별도의 설계와 측정이 필요합니다. 이 실습의 결정적 콜백과 실행 시간 제한은 그런 실시간 보장의 대체물이 아닙니다. 모델 시간으로 계약을 검증했다는 결과와 실제 최악 실행 시간을 측정했다는 결과를 구분하세요.

현장에서 만나는 모습

센서 표본의 observed_ms는 호스트가 전송 완료를 확인한 시점입니다. ADC가 실제 온도를 변환한 시각이 아니므로 ‘방금 읽었다’만으로 ‘방금 측정했다’고 할 수 없습니다. 상위 프로그램은 마지막 성공 시각과 현재 오류를 함께 보여 줘야 오래된 값이 정상 최신값처럼 보이지 않습니다. 실패 뒤 다음 정상 읽기가 다시 갱신되는지도 시험해야 합니다.

완성 후에도 실물 검증은 남습니다. 풀업·배선·전원·클록·센서 변환 주기·실제 HAL 구현은 이 모델로 검증되지 않습니다. 포트폴리오에는 ‘호스트 C + 결정적 HAL 모델’이라고 적고, 검증한 입력·상태·기한과 검증하지 않은 물리적 항목을 나누세요. 모델 통과는 다음 실물 시험을 준비하는 근거이지 현장 안전 보증이 아닙니다.

다음 실습에서 할 것

7~8단계에서 공유 기한·늦은 성공·래핑·인자 검사를 완성합니다. 전체 채점은 앞 단계까지 다시 확인합니다. 정상→부분 실패→정상 수집에서 마지막 정상 표본이 보존되고 새 표본으로 교체되는지 확인하세요. 세션 종료 시 파일이 사라지므로 소스와 시험 기록을 별도로 보관하세요.