fix(ble): 주파수·cycle 설정은 mpa 가 아니라 mcs — 앱은 여태 한 번도 안 바꾸고 있었다

## 확인된 사실 (2026-09-02 펌웨어팀)
송신 주파수·cycle 설정 명령은 **`mcs?`** 다. `mpa?` 는 piezo power ON 이다.

이 앱은 여태 `mpa?` 에 [freq, cycles] 를 실어 보내며 그것이 주파수 설정이라고
가정하고 있었다(PlacementGuideView 의 `sendPiezoPowerOn()`, MeasurementService 의
`sendBurst(freqOption = 2, ...)`). `mcs` 는 코드에도 docs/BLE_PROTOCOL_REFERENCE.md
에도 **한 글자도 없다**.

즉 **지금까지 앱은 주파수·cycle 을 한 번도 바꾼 적이 없다.** 프로브 기본값으로만
측정해 온 셈이고, 그 사실을 아무도 몰랐다. 병원 임상 모드를 만들며 명령을 되짚다
드러났다.

## 고침
`BleManager.sendPiezoConfig(freqOption, cycles)` 를 추가하고 병원 임상 모드가 조합
진입마다 이것을 부른다. `sendPiezoPowerOn`(mpa)은 기존 호출부가 있어 그대로 둔다 —
power ON 은 그 나름의 역할이 있을 수 있고, 확인 전에 건드리면 정렬 화면이 깨진다.

응답 태그는 `sendRaw` 가 m→r 로 바꿔 `rcs` 를 기다린다. 파서의 when 에 rcs 분기가
없어도 태그 처리가 when 밖에 있어 큐는 정상 해제된다(BleManager L1783).

## ⚠ 아직 확인 안 된 것 — 인자 구성
명령 **이름만** 확인됐다. 인자의 개수·순서·인코딩은 듣지 못해, 이 프로토콜의 다른
수치 명령과 같은 규약을 따른다고 **가정**했다:

  mcs? = 6D 63 73 3F | freq(BE 2B) | cycles(BE 2B) | CRC16-CCITT(LE 2B)   총 10 B

  (1,3) 6D 63 73 3F 00 01 00 03 42 64
  (2,5) 6D 63 73 3F 00 02 00 05 D4 5D

값↔MHz 대응도 여전히 모른다. 파일에 실제 전송 정수를 남기는 안전장치는 그대로다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-02 17:05:08 +09:00
parent 53fd07c342
commit d1a5cfd4b4
2 changed files with 25 additions and 2 deletions
@@ -777,6 +777,28 @@ class BleManager private constructor(private val context: Context) {
sendRaw(CRC16.buildCommandBE("mpa", intArrayOf(freqOption, cycles))) sendRaw(CRC16.buildCommandBE("mpa", intArrayOf(freqOption, cycles)))
} }
/**
* 송신 주파수 · cycle 설정 (`mcs?`).
*
* ## mpa 가 아니다 (2026-09-02 펌웨어팀 확인)
* 이 앱은 여태 `mpa?`(piezo power ON)에 [freq, cycles] 를 실어 보내고 있었고, 그것이
* 주파수 설정이라고 코드가 가정하고 있었다. 실제 설정 명령은 **`mcs?`** 다.
* 즉 지금까지 앱은 주파수·cycle 을 **한 번도 바꾼 적이 없다** — 프로브 기본값으로만
* 측정해 온 셈이다.
*
* ## ⚠ 인자 구성은 아직 확인 전이다
* 명령 이름만 확인됐고, 인자의 개수·순서·인코딩은 듣지 못했다. 여기서는 이 프로토콜의
* 다른 수치 명령과 같은 규약을 따른다고 **가정**한다:
* "mcs?" + freq(BE 2B) + cycles(BE 2B) + CRC16(LE 2B) = 10 B
* 그리고 값↔MHz 대응도 여전히 모른다(HospitalProtocol KDoc 참고).
*
* 확인되면 이 함수 한 곳만 고치면 된다. 응답 태그는 `sendRaw` 가 m→r 로 바꿔
* `rcs` 를 기다린다 — 파서에 rcs 분기가 없어도 큐는 태그로 해제된다.
*/
fun sendPiezoConfig(freqOption: Int, cycles: Int) {
sendRaw(CRC16.buildCommandBE("mcs", intArrayOf(freqOption, cycles)))
}
fun sendPiezoStop() { fun sendPiezoStop() {
sendRaw(CRC16.buildCommandASCII("mps", " ")) sendRaw(CRC16.buildCommandASCII("mps", " "))
} }
@@ -10,7 +10,7 @@
* 다시 만들 수 없으므로, 그 자리에서 놓친 조합은 그날 데이터에서 영영 빈다. * 다시 만들 수 없으므로, 그 자리에서 놓친 조합은 그날 데이터에서 영영 빈다.
* *
* ## 측정 한 번의 흐름 * ## 측정 한 번의 흐름
* sendPiezoPowerOn(freqOption, cycles) ← 조합 진입 시 1회 * sendPiezoConfig(freqOption, cycles) ← 조합 진입 시 1회 (mcs?)
* sendMtb() → piezoCollector.onComplete ← n회 반복 * sendMtb() → piezoCollector.onComplete ← n회 반복
* *
* `sendMtb` 는 6채널+IMU 를 한 번에 받는 명령이고, 완료는 콜백으로 온다. 그래서 루프는 * `sendMtb` 는 6채널+IMU 를 한 번에 받는 명령이고, 완료는 콜백으로 온다. 그래서 루프는
@@ -109,7 +109,8 @@ fun HospitalModeView(appState: AppState) {
dir, patient, posture, fill, freq, cycle, startedAt) dir, patient, posture, fill, freq, cycle, startedAt)
// 조합 진입 — 프로브에 주파수·cycle 을 실어 보낸다. // 조합 진입 — 프로브에 주파수·cycle 을 실어 보낸다.
bleManager.sendPiezoPowerOn(freqOption = freq.freqOption, cycles = cycle.cycles) // `mpa?`(power ON)가 아니라 `mcs?`(설정)다 — 2026-09-02 펌웨어팀 확인.
bleManager.sendPiezoConfig(freqOption = freq.freqOption, cycles = cycle.cycles)
delay(COMBINATION_SETTLE_MS) delay(COMBINATION_SETTLE_MS)
var ok = 0; var fail = 0 var ok = 0; var fail = 0