fix(ble): mcs 스펙 반영 — 인자 5개 · 주파수 0/5 · rcs echo 검증
## 앞선 커밋이 세 군데 틀렸다 2026-09-02 펌웨어팀 스펙을 받아 바로잡는다. 1. **인자가 2개가 아니라 5개다.** mcs? [tag 4B][freq 2B][cycles 2B][avg 2B][delay_us 2B][samples 2B][crc 2B] = 16B avg·delay_us·samples 를 안 보내면 길이 부족으로 거부된다(freq=0xFFFF 응답). 2. **주파수 값이 1/2 가 아니라 0/5 다.** 0=1.8 · 1=1.9 · 2=2.0 · 3=2.1 · 4=2.2 · 5=2.3 MHz. 앞선 커밋의 가정(1.8→1, 2.3→2)은 둘 다 틀렸다 — 실제로는 2.0 과 2.3 을 재게 된다. 가정을 파일명에 남겨 둔 안전장치가 없었다면 못 알아챌 뻔했다. 3. **응답을 확인하지 않고 있었다.** 이게 가장 위험하다 — 아래 참고. ## 설정 실패는 조용하다 — 그래서 반드시 확인한다 실패해도 `rcs:` 는 온다. 구분은 freq 값이다: · 0xFFFF — 파라미터 범위 초과 또는 데이터 길이 부족 · 0xFFFD — 검증은 통과했으나 NVS 저장 실패 거부돼도 프로브는 **옛 설정으로 측정을 계속한다.** 확인하지 않으면 파일에는 요청한 값이 적힌 채 다른 조건의 데이터가 쌓인다 — 잘못된 데이터가 정상처럼 보이는, 임상에서 가장 나쁜 결과다. 그래서 조합마다 echo 를 받아 **요청한 다섯 값과 전부 일치할 때만** 측정한다. 불일치·무응답이면 그 조합을 통째로 건너뛰고 run json 에 `skipped_reason` 을 남기며 화면에 빨갛게 띄운다. 비는 편이 틀린 것보다 낫다. ## 고정 파라미터 프로토콜이 바꾸는 것은 주파수·cycle 뿐이다. 나머지 셋은 모든 조합에서 같아야 비교가 성립하므로 `HospitalFixedParams` 한 곳에 둔다 — avg 10 · delay_us 10 · samples 100 (펌웨어팀 예시값, samples 는 앱 채널 버퍼 100 과도 일치). 1.8MHz·c3 6D 63 73 3F 00 00 00 03 00 0A 00 0A 00 64 3C 4A 2.3MHz·c7 6D 63 73 3F 00 05 00 07 00 0A 00 0A 00 64 36 FC ## ⚠ 설정이 프로브에 영구 저장된다 (NVS) 전원을 껐다 켜도 유지된다. 즉 이 모드로 측정하고 나면 **일반 측정 화면도 마지막 조합(2.3MHz·cycle 7)으로 동작한다.** run json 에 남기고 화면에도 명시했다. 임상 후 원래 값으로 되돌릴지는 별도 결정이 필요하다 — 공장 기본값을 모른다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,31 +9,50 @@
|
||||
* 사람이 개입하는 지점을 방광 채움 하나로 줄인 것이 핵심이다 — 조합을 손으로 바꾸면
|
||||
* 반드시 빠뜨리거나 잘못 기록한다. 6조합 × n회가 한 번의 버튼으로 끝난다.
|
||||
*
|
||||
* ## ⚠ 주파수 코드값이 아직 확인되지 않았다 (2026-09-02)
|
||||
* 펌웨어에 보내는 `mpa?` 명령의 첫 인자는 **정수**인데, 그 정수와 실제 MHz 의 대응이
|
||||
* 코드에도 `docs/BLE_PROTOCOL_REFERENCE.md` 에도 적혀 있지 않다. 기존 코드는 항상
|
||||
* `freqOption = 2` 만 쓰고 있었다(PlacementGuideView · MeasurementService).
|
||||
* ## 측정 파라미터 (2026-09-02 펌웨어팀 확인)
|
||||
* `mcs?` 는 **다섯** 개를 받는다 — freq · cycles · avg · delay_us · samples.
|
||||
*
|
||||
* 그래서 [ProbeFrequency.freqOption] 값은 **가정**이다. 펌웨어팀 확인 후 이 표 한 줄만
|
||||
* 고치면 된다.
|
||||
* 요청: mcs? [tag 4B] [freq 2B][cycles 2B][avg 2B][delay_us 2B][samples 2B] [crc 2B] = 16B
|
||||
* 응답: rcs: 같은 구성으로 **저장된 값을 echo**
|
||||
*
|
||||
* 확인 전에 모은 데이터가 버려지지 않도록, 저장 파일명과 meta 에 **실제로 보낸 정수**를
|
||||
* `fopt{N}` 으로 함께 남긴다. 대응이 반대로 밝혀져도 라벨만 바꿔 되살릴 수 있다.
|
||||
* | 필드 | 범위 | 뜻 |
|
||||
* |---|---|---|
|
||||
* | freq | 0~5 | 0=1.8 · 1=1.9 · 2=2.0 · 3=2.1 · 4=2.2 · 5=2.3 MHz |
|
||||
* | cycles | 3~7 | burst cycle 수 |
|
||||
* | avg | 1~10 | averaging 횟수 |
|
||||
* | delay_us | 0~50 | burst 후 capture delay |
|
||||
* | samples | 80~117 | echo sample 개수 |
|
||||
*
|
||||
* ## ⚠ 설정은 프로브에 **영구 저장**된다 (NVS)
|
||||
* 한 번 보내면 전원을 껐다 켜도 유지된다. 즉 이 모드로 측정하고 나면 **일반 측정
|
||||
* 화면도 마지막으로 설정한 값으로 동작한다.** 임상이 끝나면 원래 값으로 되돌리든지,
|
||||
* 적어도 무엇으로 바꿔 놓았는지 알고 있어야 한다 — run json 에 남긴다.
|
||||
*
|
||||
* ## 응답을 반드시 확인한다
|
||||
* 실패해도 `rcs:` 는 온다. 구분은 freq 값이다:
|
||||
* · 0xFFFF — 데이터 길이 부족 또는 파라미터 범위 초과
|
||||
* · 0xFFFD — 검증은 통과했으나 NVS 저장 실패
|
||||
* 확인하지 않으면 **설정이 거부된 채 옛 설정으로 측정**하고, 파일에는 요청한 값이
|
||||
* 적힌다. 데이터가 조용히 잘못 라벨링되는 가장 나쁜 경우다.
|
||||
*/
|
||||
package com.medithings.vesiscan.models
|
||||
|
||||
/** 프로브 송신 주파수. [freqOption] 이 `mpa?` 의 첫 인자로 나간다. */
|
||||
/**
|
||||
* 프로브 송신 주파수. [freqOption] 이 `mcs?` 의 첫 인자다.
|
||||
*
|
||||
* 펌웨어는 0~5 여섯 단계를 지원하지만(0=1.8 … 5=2.3, 0.1MHz 간격) 이 프로토콜은 양 끝
|
||||
* 둘만 쓴다. 중간값이 필요해지면 여기 항목만 더하면 된다.
|
||||
*/
|
||||
enum class ProbeFrequency(val label: String, val freqOption: Int) {
|
||||
// ⚠ freqOption 값은 펌웨어팀 확인 전의 가정이다. 위 KDoc 참고.
|
||||
F_1_8("1.8", 1),
|
||||
F_2_3("2.3", 2), // 기존 코드가 늘 쓰던 값이 2 다.
|
||||
F_1_8("1.8", 0),
|
||||
F_2_3("2.3", 5),
|
||||
;
|
||||
|
||||
/** 파일명에 쓸 표기 — MHz 와 실제 보낸 정수를 함께 남긴다. */
|
||||
val fileTag: String get() = "${label}MHz-fopt$freqOption"
|
||||
/** 파일명에 쓸 표기 — MHz 와 실제 보낸 값을 함께 남긴다. */
|
||||
val fileTag: String get() = "${label}MHz-f$freqOption"
|
||||
}
|
||||
|
||||
/** 버스트 cycle 수. `mpa?` 의 둘째 인자로 그대로 나간다. */
|
||||
/** 버스트 cycle 수. `mcs?` 의 둘째 인자로 그대로 나간다 (허용 3~7). */
|
||||
enum class ProbeCycle(val cycles: Int) {
|
||||
C3(3), C5(5), C7(7);
|
||||
|
||||
@@ -65,3 +84,21 @@ val HOSPITAL_COMBINATIONS: List<Pair<ProbeFrequency, ProbeCycle>> =
|
||||
|
||||
/** 한 조합당 기본 반복 횟수. 화면에서 바꿀 수 있다. */
|
||||
const val HOSPITAL_DEFAULT_REPEATS = 20
|
||||
|
||||
/**
|
||||
* 이 프로토콜이 고정으로 쓰는 나머지 측정 파라미터.
|
||||
*
|
||||
* 프로토콜이 바꾸는 것은 주파수와 cycle 뿐이다. 나머지 셋은 **모든 조합에서 같아야**
|
||||
* 조합 간 비교가 성립하므로 여기 한 곳에 박아 둔다. 값은 펌웨어팀 예시
|
||||
* (`00 05 00 03 00 0A 00 0A 00 64`)를 따랐다.
|
||||
*
|
||||
* ⚠ 이 값들도 프로브에 영구 저장된다. 바꾸면 이후 모든 측정에 영향을 준다.
|
||||
*/
|
||||
object HospitalFixedParams {
|
||||
/** averaging 횟수 (허용 1~10). */
|
||||
const val AVG = 10
|
||||
/** burst 후 capture delay, µs (허용 0~50). */
|
||||
const val DELAY_US = 10
|
||||
/** echo sample 개수 (허용 80~117). 앱의 채널 버퍼가 100 샘플 기준이다. */
|
||||
const val SAMPLES = 100
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user