요구사항 명세(SR) 학습 노트 목차

04. Smart Access — 인증·근접·상태 정합성

출처: SR §6.4.1 (1. Digital Key 기반 자동 잠금 해제 / 2. 도어 잠금 및 잠금 해제 / 3. 도어 상태 관리 / 4. Auto Re-lock / 5. 사용자 이탈 기반 Auto Lock / 6. 오류 및 안전 동작) 관련 TBD: TBD-016(BLE Digital Key 접근·근접·이탈 판단 기준 및 유지시간), TBD-017(Auto Re-lock 대기시간 및 Door Lock/Unlock 결과 확인시간) 담당 노드: ESP32(BLE Digital Key 인증·근접 판단) + S32K144 Function Controller(Door Lock Actuator 직접 제어) + Central Controller(상태 종합)


0. 이 절이 다루는 진짜 문제

"키를 들고 다가가면 문이 열린다"는 한 문장이 요구사항 30여 개로 늘어난다. 왜인가?

세 가지 문제가 겹쳐 있기 때문이다.

다이어그램 로딩 중…

①은 암호학, ②는 무선 신호, ③은 분산 상태 관리다. 세 영역 모두에서 실패할 수 있고, 실패의 결과가 차량 도난이거나 탑승자 갇힘이다.


1. Digital Key 기반 자동 잠금 해제

  • 시스템은 등록된 Digital Key 가 확인된 경우에만 자동 잠금 해제를 허용해야 한다.
  • 시스템은 유효한 사용자 근접 상태가 확인된 경우에만 자동 잠금 해제를 허용해야 한다.
  • 시스템은 사용자 근접 상태를 신뢰할 수 없는 경우 자동 잠금 해제를 수행하지 않아야 한다.
  • 시스템은 Digital Key 기능에 필요한 통신 정보를 신뢰할 수 없는 경우 자동 잠금 해제를 수행하지 않아야 한다.

1-1. "~인 경우에만"이 두 번 나온다

등록된 Digital Key 가 확인된 경우에만 …
유효한 사용자 근접 상태가 확인된 경우에만 …

"~인 경우에만"(only if)은 필요조건을 뜻한다. 두 문장이 각각 필요조건이므로, 실제 조건은 AND다.

자동 잠금 해제 허용 ⟺ 등록된 Digital Key 확인 AND 유효한 근접 상태 확인

그리고 뒤의 두 문장이 부정형으로 같은 말을 한 번 더 한다 — 근접을 못 믿으면 안 되고, 통신을 못 믿어도 안 된다. 긍정 조건과 부정 조건을 각각 별도 요구사항으로 쓴 것은 §9의 분리 원칙 때문이기도 하고, 시험에서 "조건 만족 시 열림"과 "조건 불만족 시 안 열림"을 각각 검증해야 하기 때문이다.

§5의 Smart Access 정의를 다시 보면 조건이 사실 셋이다.

"인증된 Digital Key 와 사용자 근접 상태 및 차량 보안 조건을 이용하여 자동 도어 잠금·잠금 해제 기능을 제공하는 기능."

차량 보안 조건은 §6.4.1의 요구사항 문장에 명시적으로 안 나오지만 용어 정의에 있다. 이런 게 SR 리뷰에서 잡아야 할 지점이다 — 용어 정의와 요구사항 본문의 불일치.

1-2. 왜 인증만으로 부족하고 근접이 필요한가 — 릴레이 공격

인증만 있으면 이런 공격이 성립한다.

다이어그램 로딩 중…

암호는 하나도 깨지지 않았다. 키는 진짜고 서명도 진짜다. 공격자는 단지 거리를 속였을 뿐이다.

그래서 "유효한 사용자 근접 상태"가 별도 필요조건이 된다. 근접을 어떻게 판단하는가가 TBD-016이다.

TBD-016: "BLE Digital Key 접근·근접·이탈 판단 기준 및 유지시간 — RSSI Filtering, 접근·근접·이탈 판단, 유지시간 및 Hysteresis 벤치 확정"

1-3. RSSI 기반 근접 판단의 한계

RSSI(Received Signal Strength Indicator)는 거리에 따라 감소하지만, 거리만의 함수가 아니다.

RSSI ≈ TxPower − 10·n·log₁₀(d) + (환경 요인)
                                    ↑ 여기가 문제
환경 요인RSSI 영향
사람 몸 (물이 2.4 GHz를 흡수)주머니 속 폰이면 −10~−20 dB
금속 (차체, 기둥)반사·차폐로 널뛰기
다중 경로 페이딩위치가 몇 cm만 변해도 수 dB 요동
폰 기종별 안테나같은 거리에서도 기기마다 다름
방향 (안테나 지향성)폰을 돌리면 변함

결과: RSSI 하나로는 1 m와 5 m를 안정적으로 구분할 수 없다.

그래서 TBD-016이 요구하는 것들:

/* TBD-016 — RSSI 필터링 + 히스테리시스 + 유지 시간 */
typedef enum {
    PROX_FAR,        /* 이탈 */
    PROX_APPROACH,   /* 접근 중 */
    PROX_NEAR,       /* 근접 — 자동 해제 허용 구간 */
} prox_state_t;

typedef struct {
    int16_t       rssi_filt_q4;   /* 필터링된 RSSI (Q12.4) */
    prox_state_t  state;
    uint32_t      state_since_ms;
    uint8_t       sample_count;
} prox_ctx_t;

/* 1차 IIR 저역 필터 — 순간 요동 억제 */
#define ALPHA_Q4   3      /* α ≈ 3/16 ≈ 0.19 */

static void prox_feed(prox_ctx_t *c, int8_t rssi_dbm)
{
    int16_t x = (int16_t)rssi_dbm << 4;                       /* Q12.4 로 */
    if (c->sample_count == 0) c->rssi_filt_q4 = x;
    else c->rssi_filt_q4 += (int16_t)(((int32_t)(x - c->rssi_filt_q4) * ALPHA_Q4) >> 4);
    if (c->sample_count < 255) c->sample_count++;

    prox_state_t next = c->state;

    /* 히스테리시스 — 진입 임계와 이탈 임계를 다르게 (TBD-016) */
    switch (c->state) {
    case PROX_FAR:
        if (c->rssi_filt_q4 > RSSI_APPROACH_IN)  next = PROX_APPROACH;
        break;
    case PROX_APPROACH:
        if (c->rssi_filt_q4 > RSSI_NEAR_IN)      next = PROX_NEAR;
        else if (c->rssi_filt_q4 < RSSI_APPROACH_OUT) next = PROX_FAR;
        break;
    case PROX_NEAR:
        if (c->rssi_filt_q4 < RSSI_NEAR_OUT)     next = PROX_APPROACH;
        break;
    }

    if (next != c->state) { c->state = next; c->state_since_ms = hal_now_ms(); }
}

/* §6.4.1 — "유효한 사용자 근접 상태"의 판정 */
static bool prox_valid_near(const prox_ctx_t *c)
{
    if (c->state != PROX_NEAR) return false;
    if (c->sample_count < MIN_SAMPLES) return false;               /* 표본 부족 = 신뢰 불가 */
    return (hal_now_ms() - c->state_since_ms) >= NEAR_HOLD_MS;     /* 유지 시간 (TBD-016) */
}

세 겹의 방어: 필터(순간 노이즈) + 히스테리시스(경계 채터링) + 유지 시간(스쳐 지나감).

유지 시간이 특히 중요하다. 차 옆을 지나가기만 한 사용자에게 문을 열어주면 안 된다. 잠깐 NEAR였다가 다시 FAR로 가는 패턴을 걸러내려면 시간 조건이 필수다.

RSSI로 릴레이 공격을 막을 수 있는가? — 못 막는다. 공격자가 중계기의 송신 출력을 조절하면 RSSI를 원하는 값으로 만들 수 있다. RSSI는 거리의 증거가 아니라 힌트다. 진짜 해법은 UWB(Ultra-Wideband) 기반 ToF 거리 측정이다. 신호의 비행 시간을 재므로 중계기가 거리를 줄일 수 없다(빛보다 빠를 수 없으므로). 최신 차량용 Digital Key 표준(CCC Digital Key Release 3)이 UWB를 채택한 이유다. 이 프로토타입은 BLE만 쓰므로 릴레이 공격에 원리적으로 취약하다. §7.1이 "프로토타입의 로컬 네트워크/BLE 환경에서 검증한다"고 범위를 제한한 것과 맞물려, 이건 알려진 한계로 문서화되어야 할 항목이다.


2. 도어 잠금 및 잠금 해제

  • 사용자는 차량 내 HMI 및 모바일 인터페이스를 통해 도어 잠금 및 잠금 해제를 요청할 수 있어야 한다.
  • 시스템은 유효한 도어 잠금 요청이 확인된 경우 도어를 잠가야 한다.
  • 시스템은 유효한 도어 잠금 해제 요청이 확인된 경우 도어의 잠금을 해제해야 한다.
  • 시스템은 현재 도어 잠금 상태와 동일한 목표의 요청이 반복되더라도 의도하지 않은 반복 구동이 발생하지 않도록 해야 한다.
  • 시스템은 도어가 열린 상태에서 새로운 잠금 요청이 발생한 경우 도어 잠금 동작을 수행하지 않아야 한다.

2-1. 마지막 문장이 안전 요구사항이다

"시스템은 도어가 열린 상태에서 새로운 잠금 요청이 발생한 경우 도어 잠금 동작을 수행하지 않아야 한다."

물리적으로 열려 있는 문에 잠금 액추에이터를 구동하면:

  • 래치가 잠김 위치로 가고, 문을 닫는 순간 키 없이 잠긴 상태가 된다 (lockout)
  • 구형 차량에서 키를 안에 두고 잠기는 사고의 전형적 경로
  • 래치 기구가 정렬되지 않은 상태에서 구동되어 기계적 손상 가능

**"열린 문은 잠그지 않는다"**는 게 파워 도어락의 기본 규칙이다.

2-2. 멱등성 — 00편 패턴 E

윈도우(§6.2.1)와 완전히 같은 문장이 도어에도 있다. 도어락 액추에이터는 솔레노이드나 소형 DC 모터인데, 이미 잠긴 상태에서 반복 구동하면:

  • "철컥철컥" 소음 반복 → 사용자 불쾌
  • 액추에이터 수명 소모
  • 전류 소비 (주차 중이면 배터리)
static bool lock_request_redundant(lock_cmd_t cmd)
{
    /* §6.4.1 — 상태를 신뢰할 수 없으면 멱등성 판단 자체가 성립하지 않는다 */
    if (!g_lock_state_trusted) return false;   /* 판단 불가 → 중복 아님으로 취급하고 진행 */
    return (cmd == LOCK_CMD_LOCK   && g_lock_state == LOCK_LOCKED)
        || (cmd == LOCK_CMD_UNLOCK && g_lock_state == LOCK_UNLOCKED);
}

상태를 못 믿을 때 어떻게 할 것인가가 설계 결정이다. 위 코드는 "진행"을 택했다. 근거: 잠금 상태를 모르는데 사용자가 잠금을 요청했다면, 실제로 안 잠겨 있을 가능성이 있고 보안상 잠그는 게 안전하다. 반대로 "차단"을 택하면 사용자가 문을 잠글 수 없게 된다.


3. 도어 상태 관리 — 이 절에서 가장 정교한 부분

  • 시스템은 도어의 잠금 상태와 물리적 개폐 상태를 서로 독립적으로 구분해야 한다.
  • 시스템은 도어 잠금 상태를 차량 내 HMI 및 모바일 인터페이스를 통해 사용자가 확인할 수 있도록 해야 한다.
  • 시스템은 도어의 열림 및 닫힘 상태를 차량 내 HMI 및 모바일 인터페이스를 통해 사용자가 확인할 수 있도록 해야 한다.
  • 시스템은 도어 상태를 신뢰할 수 없는 경우 해당 상태를 정상 상태로 확정하여 사용하지 않아야 한다.
  • 시스템은 도어 잠금 상태가 LOCKED 로 확인되는 동시에 물리적 도어 상태가 OPEN 으로 확인되는 등 비정상적인 상태 조합이 발생한 경우 이를 정상 도어 상태로 취급하지 않아야 한다.
  • 시스템은 비정상적인 도어 상태 조합이 발생한 경우 실제 확인된 도어 상태를 임의의 정상 상태로 변경하여 표시하지 않아야 한다.
  • 시스템은 도어 관련 상태 이상을 차량 내 HMI 및 모바일 인터페이스를 통해 사용자가 확인할 수 있도록 해야 한다.

3-1. 두 개의 직교 축

"시스템은 도어의 잠금 상태와 물리적 개폐 상태를 서로 독립적으로 구분해야 한다."

이 한 문장이 전체 상태 모델을 결정한다.

물리 CLOSED물리 OPEN
잠금 UNLOCKED정상 — 탑승 가능정상 — 승하차 중
잠금 LOCKED정상 — 주차 상태비정상 조합

LOCKED × OPEN이 물리적으로 모순이다. 래치가 잠겨 있는데 문이 열려 있을 수는 없다. 이 조합이 관측된다면 셋 중 하나다.

  1. 도어 개폐 센서(문 스위치) 고장
  2. 잠금 상태 피드백 센서 고장
  3. 실제로 문이 강제로 열림 (도난·사고)

세 경우 모두 "정상 상태"로 처리하면 안 된다.

3-2. "임의의 정상 상태로 변경하여 표시하지 않아야 한다"

이 요구사항이 특히 중요하다.

"시스템은 비정상적인 도어 상태 조합이 발생한 경우 실제 확인된 도어 상태를 임의의 정상 상태로 변경하여 표시하지 않아야 한다."

무슨 뜻인가? 개발자가 흔히 하는 짓을 금지하는 것이다.

/* ✗ 금지되는 구현 — 모순을 "정리"해서 보여준다 */
door_state_t door_state_for_hmi(void)
{
    if (g_lock == LOCKED && g_ajar == OPEN) {
        return DOOR_LOCKED;      /* 모순이니 잠금 쪽을 믿자 — 요구사항 위반 */
    }
    ...
}

모순을 임의로 해소하면 정보가 사라진다. 사용자는 "잠김"을 보고 차를 떠나지만, 실제로는 문이 열려 있을 수 있다. 도난으로 이어진다.

/* ✓ 올바른 구현 — 모순을 모순으로 노출 */
typedef enum {
    DOOR_OK_LOCKED_CLOSED,
    DOOR_OK_UNLOCKED_CLOSED,
    DOOR_OK_UNLOCKED_OPEN,
    DOOR_INCONSISTENT,        /* LOCKED × OPEN — §6.4.1 */
    DOOR_UNTRUSTED,           /* 센서/통신 신뢰 불가 */
} door_report_t;

door_report_t door_state_for_hmi(void)
{
    if (!g_lock_trusted || !g_ajar_trusted)      return DOOR_UNTRUSTED;
    if (g_lock == LOCKED && g_ajar == OPEN)      return DOOR_INCONSISTENT;
    if (g_lock == LOCKED)                        return DOOR_OK_LOCKED_CLOSED;
    return (g_ajar == OPEN) ? DOOR_OK_UNLOCKED_OPEN : DOOR_OK_UNLOCKED_CLOSED;
}

5개 상태 중 2개가 "정상 아님"을 표현하는 데 쓰인다. 이게 이 SR이 요구하는 정직한 상태 모델이다.

3-3. 세 겹의 표시 요구사항

잠금 상태를 확인할 수 있도록          ← 정상 정보
열림/닫힘 상태를 확인할 수 있도록      ← 정상 정보
도어 관련 상태 이상을 확인할 수 있도록  ← 비정상 정보

이상(異常)도 표시 대상이라는 게 요구사항으로 못 박혀 있다. 오류를 조용히 삼키고 아무것도 안 보여주는 게 아니라, "지금 도어 상태에 문제가 있다"를 보여줘야 한다.


4. Auto Re-lock

  • 시스템은 Auto Re-lock 판단에 필요한 도어 개폐 상태를 확인해야 한다.
  • 시스템은 Auto Unlock 이후 정의된 시간 동안 도어 열림이 발생하지 않은 경우 Auto Re-lock 을 수행해야 한다.
  • 시스템은 도어 상태를 신뢰할 수 없는 경우 Auto Re-lock 을 수행하지 않아야 한다.

4-1. 무엇을 막는 기능인가

사용자가 차에 다가가서 문이 자동으로 열렸다. 그런데 차에 타지 않고 그냥 갔다. (물건만 확인하려던 참이었거나, 마음이 바뀌었거나.)

이때 문이 열린 채로 남으면 차량이 무방비 상태가 된다. Auto Re-lock은 **"열어줬는데 안 탔으면 다시 잠근다"**는 기능이다.

다이어그램 로딩 중…

4-2. "도어 상태를 신뢰할 수 없는 경우 수행하지 않아야 한다"

왜 잠그지 않는가? 잠그는 게 더 안전해 보이는데?

갇힘(entrapment) 위험 때문이다. 도어 개폐 센서를 못 믿는 상황에서, 사용자가 실제로는 차에 타 있을 수 있다. 그런데 "열림이 감지 안 됐다"고 판단해 잠그면 사용자가 갇힌다.

이 시스템에서 잠금은 fail-safe 방향이 아니다. 보안 관점에서는 잠그는 게 안전하지만, 인명 관점에서는 잠그지 않는 게 안전하다. SR은 인명을 택했다.

비교 — §6.2.2의 윈도우는 반대다. "Anti-pinch를 못 쓰면 닫힘을 시작하지 않는다" — 즉 동작하지 않는 쪽이 안전하다. 공통점은 **"확신이 없으면 물리적 동작을 하지 않는다"**이다. 도어는 잠금이 물리 동작이고, 윈도우는 닫힘이 물리 동작이다. 둘 다 "가만히 있기"를 택한다.

TBD-017: "Auto Re-lock 대기시간 및 Door Lock/Unlock 결과 확인시간 — Door 상태 센서 시험 후 확정".

두 개의 시간이 함께 확정된다는 게 의미가 있다.

  • Auto Re-lock 대기시간: 얼마나 기다렸다 다시 잠글 것인가 (너무 짧으면 사용자가 문 열기 전에 잠김, 너무 길면 무방비 시간이 김)
  • 결과 확인시간: 잠금 명령 후 실제 상태를 확인하기까지 대기 시간 (액추에이터 동작 시간 + 센서 안정화 시간)

5. 사용자 이탈 기반 Auto Lock

  • 시스템은 등록된 Digital Key 사용자의 유효한 이탈 상태가 확인된 경우 Auto Lock 필요 여부를 판단해야 한다.
  • 시스템은 Auto Lock 수행 전에 도어 개폐 상태를 확인해야 한다.
  • 시스템은 사용자가 이탈한 상태에서 도어가 닫혀 있고 Auto Lock 조건을 만족하는 경우 도어를 자동으로 잠가야 한다.
  • 시스템은 사용자가 이탈한 상태에서 도어가 열린 경우 Auto Lock 을 수행하지 않아야 한다.
  • 시스템은 사용자가 이탈하여 확인된 상태에서 도어가 열린 상태로 유지되는 경우 모바일 인터페이스를 통해 사용자에게 해당 상태를 알려야 한다.
  • 시스템은 도어 상태를 신뢰할 수 없는 경우 Auto Lock 을 수행하지 않아야 한다.

5-1. Auto Re-lock과 Auto Lock의 차이

Auto Re-lockAuto Lock
트리거Auto Unlock 후 시간 경과사용자 이탈 감지
전제문이 안 열렸음사용자가 멀어짐
목적"열어줬는데 안 탔네""다 쓰고 갔네"
시간축짧음 (수십 초)이탈 판정 유지 시간 (TBD-016)

5-2. 열린 문을 만났을 때의 처리가 정교하다

도어가 열린 경우  →  Auto Lock 수행하지 않는다        (동작 금지)
도어가 열린 상태로 유지  →  모바일로 사용자에게 알린다  (알림)

단순히 안 하고 마는 게 아니라 알려준다. 사용자는 차에서 멀어지고 있어서 문이 열린 걸 모른다. 이때 폰 알림이 오면 돌아가서 닫을 수 있다.

이건 §6.4.1 첫 부분의 "도어가 열린 상태에서 새로운 잠금 요청이 발생한 경우 도어 잠금 동작을 수행하지 않아야 한다"와 짝을 이룬다. 그 요구사항은 동작만 막았는데, Auto Lock 문맥에서는 알림까지 요구한다. 사용자가 현장에 없기 때문이다.

/* §6.4.1 — 이탈 기반 Auto Lock */
static void auto_lock_evaluate(void)
{
    if (!key_departed_valid())     return;   /* 유효한 이탈 상태 미확인 */

    /* 도어 상태 확인이 선행 요구사항 */
    if (!g_ajar_trusted) return;             /* 신뢰 불가 → 수행 안 함 */

    if (g_ajar == DOOR_OPEN) {
        /* 잠그지 않고 알린다 */
        mobile_notify(NOTIFY_DOOR_LEFT_OPEN);
        return;
    }
    if (auto_lock_conditions_met()) {
        door_lock_execute();
    }
}

5-3. "이탈"을 판정하는 어려움

접근 판정보다 이탈 판정이 훨씬 어렵다.

접근이탈
신호RSSI 상승RSSI 하강 또는 광고 패킷 소실
실패 모드늦게 열림 (불편)차 안에 폰이 있는데 이탈로 오판 (도난 위험) 또는 주머니 속 폰이 차폐되어 이탈로 오판
확인 방법계속 다가오면 확신 증가신호가 없다 = 멀어짐? 배터리 방전? 차폐?

"신호가 없다"는 것은 여러 원인을 갖는다. 폰 배터리가 죽어도, 주머니 깊숙이 들어가도, 지하로 내려가도 신호가 사라진다. 그래서 이탈 판정에는 반드시 유지 시간이 붙어야 하고(TBD-016), 실무에서는 도어 개폐 이벤트 같은 다른 근거와 조합한다.

이탈 확신도를 높이는 근거들:
  · RSSI가 단조 감소 패턴 (갑자기 사라진 게 아니라 서서히)
  · 도어 열림 → 닫힘 이벤트가 직전에 있었음 (내려서 갔다)
  · 이탈 상태가 유지 시간 이상 지속

6. 오류 및 안전 동작

  • 시스템은 도어 잠금 또는 잠금 해제 동작 후 실제 목표 상태가 확인되지 않는 경우 해당 요청을 정상 완료로 처리하지 않아야 한다.
  • 시스템은 도어 상태를 신뢰할 수 없는 경우 해당 정보를 새로운 Auto Lock 또는 Auto Re-lock 판단의 정상 입력으로 사용하지 않아야 한다.
  • 시스템은 도어 제어에 필요한 통신 정보를 신뢰할 수 없는 경우 새로운 자동 도어 제어를 수행하지 않아야 한다.
  • 시스템은 도어 제어 중 오류가 발생한 경우 의도하지 않은 도어락 액추에이터의 지속 동작을 방지해야 한다.
  • 시스템은 도어 관련 오류를 차량 내 HMI 및 모바일 인터페이스를 통해 사용자가 확인할 수 있도록 해야 한다.

6-1. "명령 ≠ 완료" — 폐루프 확인

"시스템은 도어 잠금 또는 잠금 해제 동작 후 실제 목표 상태가 확인되지 않는 경우 해당 요청을 정상 완료로 처리하지 않아야 한다."

개루프(open-loop) 제어를 금지하는 요구사항이다.

✗ 개루프:  잠금 명령 송신 → "잠김" 표시 → 차임 출력
✓ 폐루프:  잠금 명령 송신 → 액추에이터 구동 → 상태 센서 확인 → 목표 도달 확인 → "잠김" 표시 → 차임 출력
                                                        ↑ 실패 시 여기서 멈춘다

이게 01편의 VSS 요구사항과 직접 연결된다.

§6.1.1 "시스템은 도어 잠금이 정상적으로 완료된 경우 잠금 완료 피드백 차임을 1 회 출력해야 한다." §6.1.1 "시스템은 도어 잠금 상태에서 도어가 열려 있거나 정상 잠금에 실패한 경우 경적(Horn) 경고음을 출력해야 한다."

성공하면 차임, 실패하면 경적. 폐루프 확인 없이는 이 두 요구사항을 구분할 수 없다.

/* TBD-017 — "Door Lock/Unlock 결과 확인시간" */
#define LOCK_RESULT_TIMEOUT_MS   800u

typedef enum { LOCK_RES_OK, LOCK_RES_TIMEOUT, LOCK_RES_MISMATCH, LOCK_RES_UNTRUSTED } lock_result_t;

static lock_result_t door_lock_execute(lock_cmd_t cmd)
{
    lock_state_t target = (cmd == LOCK_CMD_LOCK) ? LOCK_LOCKED : LOCK_UNLOCKED;

    actuator_drive(cmd);
    uint32_t t0 = hal_now_ms();

    while ((hal_now_ms() - t0) < LOCK_RESULT_TIMEOUT_MS) {
        actuator_tick();                    /* §6.4.1 — 지속 동작 방지 (아래 6-2) */
        if (!g_lock_trusted) { actuator_stop(); return LOCK_RES_UNTRUSTED; }
        if (g_lock_state == target) { actuator_stop(); return LOCK_RES_OK; }
    }
    actuator_stop();
    return LOCK_RES_TIMEOUT;                /* 정상 완료로 처리하지 않는다 */
}

6-2. 액추에이터 지속 동작 방지

"시스템은 도어 제어 중 오류가 발생한 경우 의도하지 않은 도어락 액추에이터의 지속 동작을 방지해야 한다."

도어락 액추에이터(솔레노이드 또는 소형 모터)는 연속 정격(continuous duty)이 아니다. 짧게 구동하고 멈추도록 설계됐다. 계속 전류를 흘리면:

  • 코일이 과열되어 절연 파괴 → 영구 고장
  • 화재 위험
  • 배터리 방전

전형적인 사고 시나리오: 상태 센서가 고장 나서 "목표 도달"이 영영 오지 않고, 폐루프 코드가 목표 도달까지 구동을 유지한다. 무한 구동.

방어는 하드웨어 타이머 기반 강제 차단이다.

/* 소프트웨어가 어떤 상태에 빠지든 액추에이터는 최대 시간 후 꺼진다 */
#define ACTUATOR_MAX_ON_MS   500u
#define ACTUATOR_COOLDOWN_MS 2000u

static uint32_t g_act_on_since;
static uint32_t g_act_off_since;
static bool     g_act_on;

void actuator_tick(void)   /* 주기 호출 — 또는 타이머 ISR */
{
    if (g_act_on && (hal_now_ms() - g_act_on_since) >= ACTUATOR_MAX_ON_MS) {
        actuator_stop();                    /* 강제 차단 */
        fault_set(FAULT_DOOR_ACT_TIMEOUT);
    }
}

static bool actuator_drive(lock_cmd_t cmd)
{
    /* 쿨다운 — 연속 재구동으로 과열되는 것도 막는다 */
    if (!g_act_on && (hal_now_ms() - g_act_off_since) < ACTUATOR_COOLDOWN_MS) return false;
    gpio_set_lock_drive(cmd);
    g_act_on = true; g_act_on_since = hal_now_ms();
    return true;
}

더 나아가 하드웨어 워치독이나 드라이버 IC의 과열 보호에 의존하는 게 정석이다. 소프트웨어가 폭주하면 소프트웨어 타이머도 같이 멈추기 때문이다. S32K144에는 독립 워치독(WDOG)이 있고, 모터 드라이버 IC에는 보통 열 셧다운(thermal shutdown)이 내장돼 있다.

함정 — 소프트웨어 타이머만 믿지 마라 actuator_tick()이 메인 루프에서 호출되는데 메인 루프가 어딘가에서 블로킹되면, 액추에이터는 계속 켜져 있다. 안전 차단은 소프트웨어와 독립된 경로를 가져야 한다. 최소한 타이머 ISR에서 호출하고, 가능하면 하드웨어 PWM 폴트 입력이나 드라이버 IC 보호를 쓴다.


7. Smart Access 전체 흐름 통합

다이어그램 로딩 중…

8. 한 줄 요약

항목한 줄
Digital Key 자동 해제등록 키 확인 AND 유효 근접 확인, 둘 다 필요조건. 근접·통신 불신 시 수행 금지
잠금/해제열린 문은 잠그지 않는다. 같은 목표 반복은 재구동 없음
도어 상태 관리잠금 축과 개폐 축은 독립. LOCKED×OPEN은 비정상 조합, 임의로 정상화 금지
Auto Re-lock열어줬는데 안 탔으면 다시 잠근다. 도어 상태 불신 시 수행 금지(갇힘 방지)
Auto Lock이탈 확인 + 문 닫힘 → 잠금. 문이 열려 있으면 잠그지 않고 모바일로 알린다
오류·안전명령이 아니라 실제 상태 확인으로 완료 판정. 액추에이터 지속 동작 방지

설계 판단 체크포인트

구현에 들어가기 전에 팀이 답을 갖고 있어야 하는 것들이다. 답이 안 나오면 그 자리가 곧 설계 문의 또는 TBD 후보다.

  1. RSSI 임계값만으로 자동 잠금 해제를 구현하면 어떤 공격에 취약한가? 어떻게 막는가? 릴레이 공격이다. 공격자가 집 안의 키와 차 옆 사이에서 챌린지-응답을 중계하면 암호는 완전히 유효하다. RSSI는 중계기 출력 조절로 위조할 수 있으므로 방어가 안 된다. 근본 해법은 UWB ToF 거리 측정이다 — 비행 시간은 중계로 줄일 수 없다. 이 프로토타입은 BLE만 쓰므로 원리적으로 취약하며, 이는 문서화해야 할 알려진 한계다.

  2. 도어 상태를 못 믿을 때, Auto Lock은 하지 않고 사용자 요청 잠금은 처리한다. 이 비대칭의 근거는? Auto Lock은 시스템이 스스로 판단해 물리 동작을 만드는 것이고, 사용자가 현장에 없을 수 있어 갇힘 위험이 있다. 사용자 요청 잠금은 사람이 의도를 갖고 지금 내린 명령이고, 대개 차 근처에 있다. "누가 판단했는가"와 "누가 현장에 있는가"가 위험도를 가른다.

  3. LOCKED × OPEN 조합을 만났을 때 "잠금 쪽을 믿는다"고 구현하면 무엇이 나빠지나? 실제로 문이 열려 있는데 사용자에게 "잠김"을 보여주게 된다. 사용자는 안심하고 차를 떠나고, 차량은 무방비로 남는다. §6.4.1은 "실제 확인된 도어 상태를 임의의 정상 상태로 변경하여 표시하지 않아야 한다"로 이걸 명시적으로 금지한다. 모순은 해소하는 게 아니라 보고하는 것이다.

  4. 잠금 명령 직후 차임을 울리면 §6.1.1의 어떤 요구사항이 깨지나? "정상적으로 완료된 경우"라는 조건이 깨진다. 잠금에 실패했을 때도 성공 차임이 울려서, "정상 잠금에 실패한 경우 경적 경고음" 요구사항과 충돌한다. 폐루프 확인(TBD-017의 결과 확인시간) 후에 울려야 한다.

  5. 액추에이터 최대 구동 시간을 소프트웨어 타이머로만 구현하면 왜 부족한가? 메인 루프가 블로킹되거나 소프트웨어가 폭주하면 타이머 체크 코드도 같이 멈춘다. 그러면 액추에이터가 켜진 채 남아 과열·화재로 간다. 안전 차단은 소프트웨어와 독립된 경로 — 타이머 ISR, 독립 워치독(WDOG), 드라이버 IC의 열 셧다운 — 에 두어야 한다.

  6. Auto Re-lock 대기시간을 5초로 잡으면? 5분으로 잡으면? 5초면 사용자가 트렁크에 짐을 놓고 오는 사이 다시 잠겨서, 문을 열려는 순간 잠겨 있다(재인증 필요 → 불편). 5분이면 사용자가 그냥 떠난 경우 5분간 차가 열려 있다(보안 위험). TBD-017이 벤치 시험으로 확정하는 이유이고, 실무에서는 30초~1분대가 흔하다. 불편과 보안의 교환비를 사용자 행동 데이터로 정해야 하는 값이다.

센싱·비전 — 유효성 3축·초음파·ROA·엔진룸 CVPredictive Climate — Fan 소유권·Pre-conditioning·자동 환기