# [001] dev report에 `Drive_Status` 바이트 추가

- **Status:** Open
- **Priority:** Critical
- **Raised:** 2026-04-08
- **Raised by:** 앱 팀 (Bruce)
- **앱 측 영향 코드:**
  - `packages/roomfit_protocol/lib/src/responses/response.dart` — `ReportResponse.fromFrame` (현재 36B 고정)
  - `packages/roomfit_exercise/lib/src/segmentation/detectors/six_state_fsm/six_state_fsm_detector.dart` — drive gating
  - `lib/features/exercise/data/motion_sample_mapper.dart:55` — `driveStatus: DriveStatus.runGym` 하드코딩

---

## 배경

앱의 rep detection FSM(`SixStateFsmRepDetector`)은 MCU 운동 단계가 `RunGym`일 때만
샘플을 처리하도록 게이팅합니다. `EncoderInit`/`Calibration` 단계에서 들어온
position·speed 값을 운동 동작으로 오인하면 부팅 직후 가짜 rep이 카운트되거나
calibration 중 force 변동을 rep로 잘못 분류합니다.

그런데 현재 dev 36B 리포트에는 `Drive_Status` 바이트가 포함되어 있지 않습니다.

- 출처: `docs/reference/mcu-source/Core/Src/protocol.c:222-269` `Return_Report_Task_dev`
- payload 36B 구성: `timeTick(2) + posL/R(4) + spdL/R(4) + accL/R(4) + icmdL/R(4) + ifbL/R(4) + fLoadL/R(4) + voltage(2) + weightModeL/R(2) + regionL/R(2) + weightSetL/R(4) = 36B`. 드라이브 상태 없음.

`Drive_Status`는 펌웨어 내부에서는 이미 존재하는 전역입니다 (`docs/reference/mcu-source/Core/Src/main.c:137` — `WP_DriveStatus Drive_Status = EncInit;`). 부팅 직후 `EncInit → Calibration → RunGym`으로 진행하며, 앱이 이 전이를 알 방법이 없는 것이 문제입니다.

## 요청

dev report payload 끝에 **`Drive_Status` 1바이트(uint8 enum)** 를 추가해주십시오.

```c
// 기존 36B 끝(weightSetR) 다음에 1바이트 추가
d[38]=(uint8_t)(wsetR>>8);  d[39]=(uint8_t)wsetR;
d[40]=Drive_Status;          // ← 추가 (0=Debug, 1=EncInit, 2=Calibration, 3=RunGym)
// d[41]은 기존 checksum 자리였음 — 한 칸씩 뒤로 밀림
```

이렇게 되면:
- payload: 36B → **37B**
- size 필드 (`d[2]`): 38 → **39**
- 전체 패킷: 41B → **42B**
- checksum 위치: `d[40]` → `d[41]`

대안 검토 (문제 있음):
- **별도 코드로 비주기 응답 보내기** (예: `Drive_Status` 변경 시에만 push) — 가능하지만 앱이 disconnect/reconnect 직후 첫 transition을 놓치면 영원히 모름. dev report에 포함시키는 것이 가장 안전.
- **빈 바이트 재활용** — dev payload에 reserved/padding 바이트가 없음 (`docs/reference/mcu-source/Core/Src/protocol.c:243-263` 참고). 새 바이트 추가가 유일한 길.

## 앱 측 호환성 안내 (중요)

현재 앱은 dev report를 **정확히 36B**일 때만 받아들이고, 그렇지 않으면
`FormatException`으로 거부합니다 (`packages/roomfit_protocol/lib/src/responses/response.dart`
의 `ReportResponse.fromFrame`). 이는 v3 12B fallback이 영구 제거된 이후 의도적으로
좁힌 invariant입니다.

따라서 펌웨어가 37B로 바뀌는 순간, 앱은 같은 변경을 동시에 머지하지 않으면
**모든 dev report를 silently drop**합니다. 출시 시점 조정이 필요합니다:

1. **(권장) MCU + 앱 동시 출시**: MCU PR과 앱 PR을 같은 펌웨어 버전 번호에 묶고
   release notes에 "FW vX.Y 이상 + App vA.B 이상" 명시.
2. **(차선) 새 cmd 코드 추가**: 기존 `0x41`은 36B 그대로 두고, 새로운 `0x4?`로
   37B dev2를 보냄. 앱이 양쪽 다 등록하고 점진 전환. 펌웨어 양쪽 코드를
   유지해야 해서 부담이 큼.

선호도와 출시 일정에 맞춰 어느 쪽으로 갈지 알려주시면 앱 PR 준비하겠습니다.

## 참고 (References)

- MCU enum 정의: `docs/reference/mcu-source/Core/Inc/WESPION_Def.h:46-52`
- MCU 부팅 시 초기값: `docs/reference/mcu-source/Core/Src/main.c:137`
- MCU 상태 전이 위치: `WESPION_App.c:1443`, `1738`, `protocol.c:1314`
- 앱 측 enum: `packages/roomfit_protocol/lib/src/constants/command_codes.dart` `DriveStatus`

---

## MCU 측 응답

<!-- 펌웨어 팀이 작성. 자유 형식. 작성자/날짜/펌웨어 버전 함께 부탁드립니다. -->

_(미응답)_

---

## 결과 (Outcome)

<!-- 응답 받은 후 앱 팀이 정리. 적용된 펌웨어 버전, 앱 측 후속 PR 번호, 검증 결과 등. -->

_(N/A)_
