refactor: 데모 브랜치 패키지 통일 com.example.medilightv2android → com.medithings.vesiscan

사용자앱 (feature/tab-navigation) 과 패키지 이름 일치. namespace + applicationId
둘 다 com.medithings.vesiscan 로 변경 (기존 데모 앱은 재설치 필요).

## 변경 범위
- Kotlin 148 파일: package + import 문 (714 occurrences)
- 디렉토리 이동: com/example/medilightv2android → com/medithings/vesiscan
  (main, test, androidTest 각각)
- app/build.gradle.kts: namespace, applicationId
- docs/FLAVOR_DEMO_STABLE.md: 참조 갱신
- V41DetectorCH4Test: BvDispatchResult.methodChosen → method (dto field name fix)

## 주의
- applicationId 가 바뀌므로 기존 데모 앱 (com.example.medilightv2android.demo) 은
  Android 관점에서 다른 앱으로 취급 — 재설치 시 PIN/설정 초기화됨.
- Fresh install 권장. 기존 앱 (com.example...) 은 별도로 uninstall 필요.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 14:30:43 +09:00
parent 55d55225ab
commit bcbc7b440c
159 changed files with 2865 additions and 717 deletions
+85
View File
@@ -0,0 +1,85 @@
# RawBleLogger session — started 15:50:20.665
# Format: HH:mm:ss.SSS dir=RX prefix=XXX len=N hex=AA BB ...
15:50:28.876 dir=RX prefix=reb: len=210 hex=72 65 62 3A 16 00 00 64 08 80 08 B6 08 F8 09 25 08 BC 08 76 07 F4 06 F7 06 BA 06 9C 06 94 06 6D 06 2C 05 EF 05 8C 05 41 05 0E 04 C1 04 9E 04 42 03 CE 03 8B 03 6E 03 5B 03 4A 03 55 03 45 03 4C 03 47 03 34 03 50 03 48 03 53 03 3D 03 36 03 44 03 2E 03 4A 03 4C 03 55 03 3D 03 30 03 25 03 4E 03 55 03 4A 03 36 03 3C 03 48 03 4A 03 47 03 44 03 4D 03 4B 03 4A 03 36 03 59 03 52 03 39 03 4B 03 4A 03 29 03 3F 03 4B 03 46 03 47 03 4A 03 3D 03 5D 03 50 03 47 03 38 03 4E 03 45 03 2C 03 3C 03 42 03 45 03 43 03 31 03 3A 03 28 03 4E 03 43 03 5B 03 55 03 45 03 47 03 2F 03 4A 03 42 03 4C 03 31 03 3F 03 3A 03 4A 03 3D 03 3C 03 32 03 44 6C 80
15:50:28.919 dir=RX prefix=reb: len=210 hex=72 65 62 3A 16 01 00 64 08 84 07 48 07 40 06 7B 06 47 06 59 05 CF 05 B0 04 DD 04 89 04 15 03 FC 03 A1 03 65 03 5B 03 54 03 52 03 53 03 55 03 3B 03 4A 03 42 03 24 03 35 03 50 03 36 03 50 03 36 03 46 03 49 03 3B 03 23 03 57 03 44 03 3D 03 4F 03 46 03 43 03 59 03 3C 03 37 03 38 03 46 03 47 03 61 03 44 03 33 03 55 03 2F 03 43 03 44 03 59 03 44 03 3A 03 4C 03 50 03 3D 03 32 03 3E 03 2C 03 49 03 4F 03 47 03 52 03 3F 03 48 03 4F 03 3F 03 36 03 35 03 51 03 44 03 32 03 39 03 37 03 53 03 43 03 41 03 4E 03 3D 03 33 03 55 03 51 03 34 03 48 03 44 03 51 03 62 03 41 03 34 03 3A 03 38 03 49 03 35 03 4E 03 3F 03 43 03 52 03 54 03 56 72 8C
15:50:28.942 dir=RX prefix=reb: len=210 hex=72 65 62 3A 16 02 00 64 08 D2 07 93 06 F0 06 C9 06 A9 05 90 05 E0 05 A3 06 13 05 0C 04 76 04 6D 04 1B 03 99 03 68 03 39 03 41 03 55 03 8F 03 75 03 83 03 81 03 6F 03 6F 03 71 03 80 03 7E 03 68 03 8A 03 7B 03 7A 03 6D 03 88 03 93 03 6F 03 84 03 8F 03 8E 03 75 03 89 03 7E 03 70 03 74 03 73 03 8A 03 75 03 74 03 81 03 8C 03 78 03 65 03 91 03 75 03 8A 03 87 03 7D 03 71 03 46 03 5B 03 3B 03 4B 03 4B 03 41 03 4B 03 3B 03 36 03 38 03 47 03 42 03 48 03 52 03 55 03 4E 03 4C 03 47 03 53 03 52 03 47 03 44 03 58 03 68 03 3E 03 41 03 2F 03 23 03 49 03 4E 03 47 03 49 03 50 03 4D 03 43 03 3A 03 56 03 44 03 46 03 44 03 47 03 61 03 3B 68 54
15:50:28.963 dir=RX prefix=reb: len=210 hex=72 65 62 3A 16 03 00 64 09 35 08 D9 07 C2 07 30 06 E4 06 2A 06 0A 06 20 05 E2 05 81 04 C4 03 F5 04 9E 03 B6 03 66 03 6E 03 7D 03 3E 03 41 03 46 03 3F 03 3E 03 47 03 41 03 4A 03 3D 03 4A 03 46 03 56 03 47 03 4C 03 4A 03 47 03 36 03 43 03 2C 03 52 03 4A 03 38 03 4A 03 3B 03 46 03 4D 03 47 03 53 03 44 03 41 03 4C 03 40 03 3D 03 42 03 55 03 38 03 42 03 32 03 41 03 49 03 48 03 41 03 42 03 36 03 38 03 2D 03 54 03 5F 03 32 03 4E 03 47 03 4F 03 46 03 48 03 3A 03 47 03 51 03 54 03 42 03 44 03 28 03 4D 03 42 03 51 03 3F 03 3F 03 4F 03 3E 03 3E 03 52 03 5E 03 44 03 39 03 40 03 44 03 3C 03 44 03 41 03 56 03 5F 03 55 03 49 03 2E B9 A7
15:50:28.995 dir=RX prefix=reb: len=210 hex=72 65 62 3A 16 04 00 64 07 1F 06 E9 06 9B 05 EE 05 D9 05 DD 05 79 05 48 05 47 04 85 04 0B 03 C0 03 6A 03 4C 03 42 03 5D 03 43 03 48 03 48 03 5A 03 47 03 42 03 3B 03 2D 03 45 03 50 03 42 03 48 03 40 03 40 03 51 03 3D 03 3B 03 59 03 44 03 33 03 41 03 40 03 49 03 38 03 47 03 51 03 41 03 42 03 49 03 47 03 5F 03 41 03 31 03 48 03 46 03 53 03 39 03 4B 03 55 03 61 03 47 03 43 03 52 03 4D 03 3E 03 3A 03 46 03 50 03 3F 03 41 03 46 03 47 03 5C 03 3E 03 4E 03 5E 03 3C 03 53 03 41 03 4A 03 54 03 47 03 63 03 34 03 49 03 49 03 41 03 44 03 49 03 3D 03 4C 03 66 03 44 03 95 03 A6 03 8E 03 9C 03 92 03 88 03 8B 03 99 03 99 03 8D 03 C9 36 DD
15:50:29.038 dir=RX prefix=reb: len=210 hex=72 65 62 3A 16 05 00 64 07 8E 06 90 06 CD 06 38 06 3C 05 D8 05 3B 05 24 05 17 04 D8 04 39 03 96 03 7D 03 59 03 63 03 50 03 4C 03 50 03 4D 03 67 03 55 03 4F 03 43 03 48 03 45 03 62 03 46 03 4F 03 44 03 4D 03 5D 03 5A 03 44 03 3F 03 49 03 37 03 3D 03 5D 03 57 03 66 03 45 03 38 03 3F 03 46 03 44 03 4B 03 60 03 4A 03 59 03 72 03 72 03 43 03 4E 03 4A 03 64 03 4E 03 56 03 4A 03 3F 03 4A 03 52 03 52 03 32 03 41 03 46 03 50 03 4F 03 56 03 59 03 54 03 42 03 46 03 44 03 54 03 53 03 3F 03 51 03 50 03 46 03 49 03 42 03 54 03 3B 03 55 03 43 03 41 03 39 03 45 03 59 03 36 03 47 03 54 03 51 03 62 03 54 03 63 03 48 03 58 03 55 03 49 2D 8F
15:50:29.066 dir=RX prefix=raa: len=8 hex=72 61 61 3A 00 00 43 5E
15:50:29.145 dir=RX prefix=rim: len=188 hex=72 69 6D 3A 00 0F 07 71 02 8D 00 6C FD 46 DC 2C 04 C5 08 95 02 D7 FF D7 FB 71 DD 30 05 7A 09 93 03 01 FF 06 F9 8C DF 0F 05 E4 0A 68 02 D5 FE E5 F8 61 E2 9B 06 2D 0B 57 02 A6 FF BC F8 59 E6 CD 06 78 0C 76 02 0C 00 AF F9 93 EA D0 06 B0 0D A1 01 29 01 77 FB B8 ED E4 06 D2 0E 92 00 3F 01 84 FE 58 EF 30 06 AA 10 0C FE D3 FF F9 00 E8 F0 19 06 AD 11 FB FD 31 FE 0C 02 BB F0 49 05 C6 11 E0 FD 0D FC 0D 03 39 EF 8A 03 CC 0F 86 FE 6D FB 2B 02 46 EE 3A 02 26 0B 76 00 FA FD 9D 00 C0 EB 94 02 20 08 26 01 CB FF 99 00 97 E6 E4 03 DE 07 98 00 BE FE 48 03 08 E5 FB 06 59 1F 5A
15:50:38.878 dir=RX prefix=reb: len=210 hex=72 65 62 3A 17 00 00 64 08 78 08 AB 08 F8 09 27 08 BE 08 77 07 E2 06 E4 06 D6 06 AC 06 A9 06 73 06 31 05 EE 05 8E 05 42 05 09 04 D1 04 A2 04 57 03 D7 03 96 03 64 03 61 03 63 03 5D 03 5D 03 48 03 3E 03 50 03 44 03 44 03 3D 03 3E 03 3A 03 4E 03 3D 03 49 03 50 03 3A 03 51 03 3C 03 44 03 4B 03 3C 03 26 03 30 03 5E 03 45 03 39 03 4A 03 4C 03 2A 03 42 03 3C 03 3C 03 38 03 34 03 48 03 4A 03 43 03 38 03 42 03 39 03 37 03 44 03 4E 03 35 03 47 03 3A 03 48 03 45 03 65 03 47 03 58 03 4B 03 34 03 50 03 3F 03 59 03 52 03 43 03 45 03 3C 03 30 03 40 03 57 03 4B 03 48 03 40 03 44 03 45 03 4D 03 2F 03 44 03 48 03 4D 03 3B 03 3E 03 51 35 A5
15:50:38.894 dir=RX prefix=reb: len=210 hex=72 65 62 3A 17 01 00 64 08 86 07 56 07 3C 06 D0 06 92 06 A8 06 1A 05 BE 05 38 04 58 04 52 04 10 03 AA 03 67 03 49 03 5E 03 3B 03 49 03 63 03 49 03 50 03 4F 03 5C 03 43 03 44 03 3E 03 43 03 38 03 4F 03 48 03 44 03 46 03 53 03 3E 03 4E 03 46 03 47 03 59 03 4C 03 4B 03 37 03 4D 03 48 03 44 03 3C 03 2B 03 40 03 4D 03 36 03 49 03 33 03 36 03 4C 03 34 03 4E 03 44 03 48 03 4A 03 45 03 35 03 46 03 3B 03 4A 03 42 03 40 03 46 03 50 03 4C 03 5B 03 3B 03 31 03 55 03 2E 03 46 03 38 03 35 03 2B 03 53 03 50 03 58 03 3A 03 42 03 30 03 45 03 36 03 45 03 3A 03 47 03 45 03 3D 03 58 03 4C 03 3A 03 27 03 47 03 35 03 41 03 4F 03 4D 03 3D 89 66
15:50:38.939 dir=RX prefix=reb: len=210 hex=72 65 62 3A 17 02 00 64 08 D1 07 9E 06 E6 06 E2 06 D8 05 9B 05 CB 05 CC 06 4E 04 E9 04 92 04 55 04 05 03 A1 03 78 03 58 03 43 03 4D 03 4B 03 4D 03 24 03 6C 03 7D 03 71 03 7C 03 6C 03 83 03 75 03 7B 03 8E 03 84 03 82 03 75 03 79 03 82 03 89 03 70 03 87 03 76 03 7D 03 7B 03 6F 03 87 03 82 03 90 03 7E 03 90 03 80 03 79 03 85 03 7C 03 82 03 7C 03 75 03 86 03 81 03 85 03 8A 03 7A 03 77 03 5C 03 44 03 41 03 47 03 4A 03 54 03 4C 03 3F 03 3C 03 4D 03 33 03 40 03 62 03 41 03 3F 03 45 03 15 03 47 03 4A 03 48 03 23 03 57 03 46 03 42 03 49 03 3D 03 44 03 42 03 41 03 31 03 56 03 55 03 69 03 52 03 43 03 38 03 4F 03 42 03 4C 03 51 04 4C
15:50:38.969 dir=RX prefix=reb: len=210 hex=72 65 62 3A 17 03 00 64 09 31 08 DB 07 BF 07 1F 06 EC 06 2D 05 C0 06 0F 05 F2 05 95 04 C7 03 EC 04 93 03 A1 03 5B 03 79 03 68 03 4B 03 42 03 53 03 31 03 54 03 3C 03 4A 03 40 03 4B 03 5F 03 38 03 4C 03 36 03 4B 03 2C 03 38 03 46 03 57 03 54 03 47 03 33 03 47 03 36 03 44 03 46 03 59 03 48 03 45 03 41 03 42 03 51 03 41 03 40 03 47 03 49 03 36 03 4E 03 34 03 5E 03 40 03 49 03 28 03 3E 03 49 03 4F 03 3C 03 3C 03 42 03 47 03 49 03 3F 03 4D 03 41 03 39 03 4E 03 40 03 55 03 38 03 35 03 4F 03 51 03 44 03 43 03 45 03 4A 03 46 03 4A 03 44 03 26 03 49 03 3C 03 25 03 51 03 47 03 30 03 56 03 44 03 43 03 49 03 41 03 3E 03 44 03 3F B0 79
15:50:38.999 dir=RX prefix=reb: len=210 hex=72 65 62 3A 17 04 00 64 07 26 06 DF 06 8E 05 C2 05 BF 05 B8 05 2A 05 67 05 4A 04 C9 04 17 03 D7 03 78 03 63 03 43 03 57 03 3F 03 5E 03 56 03 3E 03 3D 03 4F 03 46 03 3D 03 69 03 46 03 40 03 5B 03 4A 03 40 03 4B 03 42 03 5E 03 46 03 41 03 3D 03 4B 03 3E 03 42 03 52 03 3E 03 4A 03 40 03 44 03 3D 03 60 03 49 03 46 03 41 03 48 03 2D 03 43 03 56 03 36 03 55 03 3B 03 4A 03 5A 03 53 03 52 03 55 03 3F 03 47 03 3E 03 4E 03 54 03 4B 03 53 03 39 03 4C 03 48 03 48 03 49 03 49 03 3A 03 3F 03 53 03 49 03 57 03 56 03 44 03 33 03 46 03 41 03 48 03 48 03 43 03 3D 03 43 03 86 03 7F 03 78 03 8B 03 80 03 9A 03 A6 03 97 03 82 03 78 03 87 8D B4
15:50:39.030 dir=RX prefix=reb: len=210 hex=72 65 62 3A 17 05 00 64 07 8C 06 84 06 DA 06 50 06 03 05 E8 05 5B 05 97 05 65 04 AC 04 65 03 8F 03 7C 03 66 03 CD 03 6C 03 4B 03 5C 03 65 03 4E 03 55 03 55 03 3E 03 4E 03 4D 03 42 03 40 03 51 03 52 03 6F 03 5D 03 3A 03 55 03 5F 03 54 03 57 03 5A 03 4B 03 5F 03 52 03 49 03 4E 03 64 03 52 03 5C 03 60 03 43 03 5C 03 5C 03 62 03 4F 03 60 03 30 03 46 03 45 03 24 03 52 03 5F 03 5E 03 5E 03 55 03 4C 03 3C 03 42 03 60 03 48 03 51 03 5C 03 60 03 3C 03 3E 03 4A 03 3E 03 43 03 40 03 40 03 50 03 4C 03 5C 03 54 03 51 03 51 03 47 03 5D 03 4E 03 54 03 4A 03 55 03 65 03 5C 03 5C 03 48 03 4F 03 57 03 59 03 4B 03 5F 03 55 03 52 03 43 86 73
15:50:39.057 dir=RX prefix=raa: len=8 hex=72 61 61 3A 00 00 43 5E
15:50:39.149 dir=RX prefix=rim: len=188 hex=72 69 6D 3A 00 0F 00 6A 00 10 10 27 FF F9 00 00 00 04 00 69 00 0A 10 23 FF F9 00 00 00 05 00 6C 00 0A 10 20 FF F9 00 00 00 05 00 69 00 0C 10 22 FF F9 00 01 00 04 00 67 00 0B 10 27 FF F9 00 01 00 05 00 69 00 0C 10 27 FF FA 00 01 00 05 00 68 00 0B 10 25 FF F9 00 00 00 05 00 6A 00 0D 10 24 FF F9 00 00 00 04 00 6C 00 0B 10 25 FF F9 00 01 00 04 00 6B 00 0D 10 24 FF FA 00 01 00 05 00 6B 00 0D 10 22 FF FA 00 00 00 05 00 6A 00 0D 10 22 FF F9 00 00 00 04 00 6B 00 0E 10 24 FF F9 FF FF 00 04 00 6A 00 0F 10 21 FF F9 00 01 00 04 00 6B 00 0E 10 25 FF F9 00 01 00 05 22 D6
15:50:39.509 dir=RX prefix=reb: len=210 hex=72 65 62 3A 18 00 00 64 08 77 08 AD 08 F8 09 27 08 BF 08 78 07 E7 06 E4 06 D5 06 A9 06 A7 06 74 06 32 05 F5 05 8F 05 42 05 15 04 D1 04 A1 04 4D 03 D9 03 84 03 70 03 67 03 46 03 4D 03 57 03 4C 03 4C 03 40 03 4C 03 3A 03 55 03 4C 03 38 03 4B 03 3A 03 3B 03 3B 03 3E 03 3F 03 43 03 45 03 37 03 36 03 42 03 33 03 28 03 46 03 3E 03 43 03 40 03 4D 03 27 03 3A 03 34 03 48 03 38 03 42 03 44 03 48 03 30 03 32 03 45 03 47 03 3F 03 53 03 59 03 50 03 41 03 3D 03 4A 03 41 03 36 03 3E 03 3D 03 4E 03 3F 03 46 03 46 03 40 03 2E 03 42 03 45 03 5C 03 4B 03 44 03 33 03 44 03 3F 03 3E 03 41 03 3B 03 40 03 3D 03 3C 03 3D 03 38 03 49 03 5D 19 6C
15:50:39.538 dir=RX prefix=reb: len=210 hex=72 65 62 3A 18 01 00 64 08 87 07 53 07 3D 06 CA 06 98 06 A5 06 08 05 C4 05 41 04 5E 04 4E 04 05 03 A0 03 7C 03 63 03 50 03 45 03 47 03 4D 03 30 03 42 03 2D 03 3E 03 3D 03 40 03 3F 03 39 03 30 03 38 03 40 03 43 03 3A 03 36 03 52 03 30 03 43 03 50 03 36 03 2D 03 48 03 40 03 40 03 2E 03 37 03 3F 03 42 03 4A 03 45 03 3F 03 3C 03 39 03 4B 03 51 03 50 03 58 03 37 03 48 03 50 03 54 03 4B 03 55 03 56 03 47 03 3C 03 3A 03 45 03 40 03 6B 03 48 03 4B 03 2F 03 35 03 4B 03 4B 03 40 03 4A 03 69 03 54 03 3B 03 23 03 39 03 4A 03 4A 03 43 03 50 03 4D 03 42 03 35 03 41 03 55 03 3B 03 32 03 4F 03 4B 03 51 03 26 03 36 03 5A 03 46 03 40 75 FB
15:50:39.568 dir=RX prefix=reb: len=210 hex=72 65 62 3A 18 02 00 64 08 40 07 32 06 7D 06 70 06 82 05 5E 05 5D 05 7F 06 05 04 CA 04 84 04 26 03 DC 03 8C 03 68 03 43 03 4D 03 4A 03 4C 03 3E 03 4D 03 46 03 54 03 30 03 45 03 22 03 50 03 37 03 32 03 4C 03 3D 03 4D 03 47 03 3C 03 4D 03 3F 03 34 03 52 03 2D 03 42 03 47 03 43 03 46 03 46 03 3B 03 81 03 80 03 86 03 7D 03 7A 03 79 03 95 03 93 03 6C 03 85 03 78 03 79 03 88 03 74 03 8A 03 94 03 85 03 82 03 77 03 75 03 80 03 7F 03 86 03 8F 03 78 03 79 03 88 03 85 03 77 03 5D 03 6D 03 82 03 7F 03 85 03 7E 03 5F 03 80 03 6B 03 3D 03 44 03 3E 03 55 03 4F 03 3B 03 38 03 57 03 37 03 50 03 54 03 40 03 2E 03 45 03 5A 03 41 03 5A A8 87
15:50:39.599 dir=RX prefix=reb: len=210 hex=72 65 62 3A 18 03 00 64 09 30 08 DE 07 C1 07 25 06 EB 06 2E 05 BC 06 15 05 EA 05 9D 04 D4 03 DD 04 99 03 9F 03 71 03 69 03 5D 03 4B 03 54 03 3B 03 46 03 4B 03 44 03 3B 03 3A 03 3E 03 52 03 43 03 49 03 39 03 51 03 49 03 40 03 39 03 40 03 49 03 49 03 4D 03 46 03 31 03 4A 03 48 03 3B 03 3F 03 39 03 4C 03 5A 03 4E 03 54 03 4D 03 4B 03 4B 03 3C 03 4F 03 47 03 1F 03 52 03 33 03 3E 03 39 03 23 03 51 03 3A 03 51 03 4A 03 33 03 47 03 25 03 57 03 3E 03 3D 03 39 03 51 03 45 03 2C 03 3C 03 37 03 4E 03 3A 03 4B 03 50 03 45 03 37 03 45 03 3B 03 4D 03 39 03 38 03 37 03 40 03 38 03 3D 03 2D 03 3E 03 48 03 43 03 3D 03 56 03 4B 03 58 FE 0F
15:50:39.629 dir=RX prefix=reb: len=210 hex=72 65 62 3A 18 04 00 64 07 43 07 10 06 9F 05 D4 05 C9 05 BE 05 3B 05 6B 05 62 04 B6 03 FB 03 CD 03 70 03 50 03 56 03 51 03 45 03 61 03 5A 03 47 03 50 03 4F 03 3B 03 36 03 39 03 3E 03 46 03 59 03 47 03 4D 03 56 03 4A 03 3E 03 3A 03 2E 03 41 03 53 03 37 03 46 03 4D 03 53 03 59 03 48 03 3F 03 43 03 28 03 31 03 49 03 51 03 51 03 43 03 3D 03 43 03 53 03 4E 03 42 03 59 03 46 03 52 03 58 03 40 03 5A 03 3E 03 48 03 46 03 3A 03 3F 03 49 03 50 03 5B 03 3F 03 46 03 3D 03 4E 03 4B 03 3C 03 41 03 4D 03 50 03 42 03 47 03 3C 03 3C 03 36 03 45 03 56 03 45 03 43 03 54 03 5D 03 4D 03 3A 03 59 03 3F 03 49 03 4A 03 8D 03 A2 03 A7 03 83 8D 96
15:50:39.658 dir=RX prefix=reb: len=210 hex=72 65 62 3A 18 05 00 64 07 87 06 87 06 D9 06 54 06 05 05 E8 05 66 05 8E 05 6A 04 A6 04 5B 03 94 03 80 03 6E 03 CC 03 6F 03 61 03 62 03 5A 03 4E 03 4B 03 54 03 5C 03 6B 03 41 03 49 03 44 03 58 03 49 03 3C 03 59 03 5B 03 37 03 55 03 45 03 55 03 30 03 4B 03 40 03 54 03 57 03 5B 03 4F 03 48 03 38 03 5B 03 3C 03 69 03 46 03 59 03 65 03 55 03 4B 03 58 03 35 03 4C 03 63 03 3E 03 53 03 58 03 58 03 61 03 53 03 44 03 49 03 58 03 4B 03 51 03 4C 03 5C 03 50 03 4B 03 43 03 37 03 54 03 56 03 53 03 41 03 4F 03 5C 03 63 03 5E 03 5C 03 33 03 33 03 46 03 53 03 5B 03 50 03 66 03 66 03 4B 03 46 03 45 03 48 03 56 03 53 03 59 03 55 03 52 B7 52
15:50:39.687 dir=RX prefix=raa: len=8 hex=72 61 61 3A 00 00 43 5E
15:50:40.182 dir=RX prefix=rls: len=8 hex=72 6C 73 3A 00 04 72 C9
15:50:40.453 dir=RX prefix=reb: len=210 hex=72 65 62 3A 19 00 00 64 08 7F 08 AF 08 F6 09 27 08 BF 08 79 07 F1 06 E1 06 D6 06 A3 06 A1 06 71 06 30 05 F1 05 93 05 49 05 14 04 C8 04 9C 04 3A 03 E6 03 76 03 63 03 4F 03 58 03 3B 03 3B 03 42 03 45 03 3B 03 3F 03 57 03 3F 03 4E 03 32 03 44 03 35 03 4C 03 40 03 3A 03 3B 03 34 03 3D 03 41 03 30 03 48 03 33 03 45 03 46 03 4C 03 38 03 4D 03 46 03 40 03 34 03 39 03 3D 03 33 03 53 03 49 03 50 03 4C 03 28 03 34 03 3A 03 39 03 4D 03 52 03 40 03 49 03 30 03 5A 03 46 03 3F 03 29 03 5A 03 2D 03 44 03 52 03 23 03 40 03 3B 03 3E 03 2C 03 5A 03 49 03 53 03 48 03 47 03 4B 03 5E 03 43 03 3B 03 42 03 55 03 3E 03 3F 03 29 03 39 03 3A 18 21
15:50:40.483 dir=RX prefix=reb: len=210 hex=72 65 62 3A 19 01 00 64 08 85 07 51 07 3C 06 C9 06 95 06 9D 06 11 05 BC 05 43 04 6E 04 3E 04 08 03 9B 03 77 03 4B 03 5E 03 45 03 47 03 4F 03 37 03 31 03 63 03 5D 03 43 03 3D 03 38 03 45 03 44 03 26 03 5A 03 42 03 3D 03 37 03 3F 03 44 03 42 03 51 03 45 03 46 03 3E 03 5B 03 47 03 53 03 35 03 52 03 46 03 45 03 4A 03 44 03 4C 03 49 03 3E 03 38 03 3C 03 48 03 37 03 54 03 32 03 41 03 35 03 34 03 43 03 30 03 47 03 30 03 42 03 34 03 53 03 49 03 41 03 3A 03 39 03 37 03 41 03 42 03 46 03 48 03 4A 03 4C 03 3E 03 41 03 33 03 57 03 39 03 4B 03 46 03 47 03 5B 03 4D 03 3A 03 36 03 31 03 46 03 42 03 30 03 3B 03 52 03 3E 03 4E 03 4C 6E 57
15:50:40.515 dir=RX prefix=reb: len=210 hex=72 65 62 3A 19 02 00 64 08 D5 07 A9 06 E1 06 D1 06 E1 05 8D 05 A3 05 D3 06 55 04 DF 04 78 04 21 03 E3 03 96 03 6B 03 4A 03 45 03 4D 03 4D 03 41 03 42 03 56 03 4C 03 3F 03 4E 03 41 03 2C 03 4F 03 3E 03 52 03 31 03 51 03 42 03 48 03 4C 03 44 03 3D 03 2C 03 64 03 3E 03 46 03 72 03 6B 03 6A 03 90 03 6E 03 77 03 7A 03 66 03 6D 03 7F 03 81 03 79 03 84 03 7B 03 7F 03 8B 03 87 03 75 03 74 03 81 03 62 03 6D 03 8C 03 77 03 70 03 63 03 6F 03 6B 03 6C 03 7D 03 69 03 7F 03 84 03 7A 03 7C 03 69 03 87 03 7D 03 82 03 5A 03 4D 03 3B 03 5C 03 50 03 48 03 51 03 3F 03 37 03 53 03 43 03 54 03 48 03 45 03 41 03 2E 03 43 03 2B 03 48 03 4C 45 24
15:50:40.543 dir=RX prefix=reb: len=210 hex=72 65 62 3A 19 03 00 64 09 34 08 DA 07 BE 07 20 06 EF 06 31 05 CA 06 11 05 E4 05 9C 04 C8 03 DE 04 9E 03 B9 03 60 03 7C 03 71 03 49 03 4C 03 43 03 47 03 50 03 50 03 40 03 36 03 43 03 58 03 39 03 40 03 47 03 3E 03 50 03 49 03 44 03 32 03 46 03 54 03 3D 03 34 03 3E 03 4A 03 28 03 41 03 4D 03 51 03 48 03 44 03 45 03 4F 03 4B 03 3B 03 44 03 3A 03 49 03 3B 03 42 03 3E 03 4A 03 44 03 39 03 4B 03 44 03 35 03 42 03 44 03 3B 03 36 03 56 03 38 03 47 03 5B 03 43 03 3C 03 5B 03 3A 03 40 03 44 03 38 03 49 03 40 03 40 03 4D 03 38 03 38 03 47 03 44 03 4C 03 3E 03 3E 03 4F 03 46 03 4A 03 4A 03 43 03 3A 03 38 03 41 03 30 03 57 03 46 3C A0
15:50:40.573 dir=RX prefix=reb: len=210 hex=72 65 62 3A 19 04 00 64 07 41 06 E9 06 9C 05 CE 05 C5 05 BD 05 3A 05 52 05 6C 04 C3 04 0B 03 CC 03 78 03 4D 03 6F 03 44 03 4C 03 46 03 49 03 4C 03 51 03 4B 03 56 03 47 03 43 03 3D 03 46 03 42 03 4C 03 41 03 45 03 57 03 54 03 4A 03 41 03 40 03 2E 03 45 03 47 03 47 03 52 03 3C 03 4F 03 4C 03 4E 03 4C 03 42 03 3F 03 52 03 2F 03 49 03 50 03 3D 03 3C 03 36 03 43 03 39 03 48 03 4C 03 33 03 46 03 48 03 46 03 40 03 49 03 57 03 4A 03 2D 03 46 03 3C 03 2F 03 39 03 37 03 5B 03 41 03 4E 03 57 03 43 03 28 03 56 03 5D 03 44 03 4D 03 49 03 50 03 3F 03 5A 03 4D 03 6B 03 52 03 4A 03 47 03 65 03 47 03 44 03 89 03 7A 03 72 03 69 03 A0 41 9E
15:50:40.603 dir=RX prefix=reb: len=210 hex=72 65 62 3A 19 05 00 64 07 86 06 85 06 DB 06 4F 06 0D 05 EC 05 4A 05 86 05 6B 04 BA 04 62 03 7A 03 84 03 6C 03 DE 03 5C 03 44 03 38 03 68 03 54 03 55 03 63 03 54 03 40 03 47 03 51 03 46 03 48 03 5D 03 50 03 60 03 56 03 39 03 54 03 45 03 4A 03 4B 03 51 03 55 03 63 03 52 03 50 03 48 03 54 03 41 03 39 03 52 03 5E 03 54 03 58 03 53 03 50 03 52 03 51 03 48 03 40 03 51 03 53 03 4C 03 6D 03 46 03 5A 03 50 03 24 03 30 03 31 03 43 03 4D 03 5B 03 55 03 65 03 5C 03 42 03 56 03 39 03 41 03 54 03 58 03 59 03 54 03 52 03 5F 03 54 03 53 03 51 03 44 03 4A 03 4F 03 57 03 4B 03 52 03 48 03 58 03 4F 03 4E 03 40 03 49 03 5E 03 48 03 5A AF 6C
15:50:40.633 dir=RX prefix=raa: len=8 hex=72 61 61 3A 00 00 43 5E
15:50:41.023 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1A 00 00 64 08 80 08 AF 08 F4 09 27 08 BE 08 77 07 F4 06 E1 06 D2 06 A1 06 9F 06 72 06 32 05 F5 05 92 05 47 05 12 04 C8 04 A3 04 50 03 E7 03 94 03 64 03 72 03 5A 03 48 03 3E 03 49 03 4A 03 41 03 4C 03 49 03 42 03 54 03 47 03 3A 03 3C 03 49 03 45 03 41 03 44 03 49 03 30 03 4F 03 2B 03 45 03 4E 03 40 03 3F 03 54 03 39 03 31 03 34 03 41 03 3D 03 3F 03 4C 03 4E 03 44 03 57 03 40 03 43 03 50 03 3B 03 38 03 36 03 45 03 45 03 46 03 3C 03 4E 03 46 03 4F 03 35 03 3A 03 47 03 48 03 48 03 38 03 27 03 3A 03 3E 03 3B 03 37 03 37 03 5D 03 40 03 40 03 43 03 44 03 33 03 2C 03 4C 03 52 03 47 03 50 03 46 03 2E 03 3F 03 49 0F 72
15:50:41.053 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1A 01 00 64 08 84 07 53 07 39 06 CC 06 95 06 AC 06 0A 05 C6 05 44 04 6B 04 47 04 0A 03 9A 03 80 03 56 03 5F 03 3D 03 62 03 61 03 46 03 47 03 37 03 6E 03 36 03 55 03 53 03 56 03 53 03 39 03 38 03 3B 03 3A 03 4E 03 47 03 49 03 2A 03 48 03 4A 03 40 03 5B 03 37 03 40 03 4B 03 47 03 47 03 35 03 41 03 5D 03 31 03 38 03 2C 03 49 03 4C 03 53 03 44 03 3E 03 56 03 49 03 4A 03 38 03 3D 03 36 03 50 03 3F 03 39 03 37 03 53 03 37 03 5F 03 48 03 56 03 4D 03 41 03 39 03 36 03 55 03 4B 03 41 03 32 03 41 03 56 03 3A 03 52 03 47 03 48 03 3C 03 4D 03 46 03 48 03 4B 03 56 03 3A 03 33 03 50 03 38 03 5F 03 4C 03 46 03 3F 03 39 6E D9
15:50:41.084 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1A 02 00 64 08 D2 07 9E 06 E2 06 E5 06 DA 05 8E 05 B3 05 D5 06 56 05 0A 04 A9 04 61 04 14 03 BB 03 9A 03 8A 03 89 03 75 03 7B 03 75 03 6D 03 74 03 70 03 78 03 6A 03 72 03 67 03 7E 03 7F 03 7B 03 70 03 79 03 76 03 7E 03 6E 03 8B 03 76 03 6F 03 8A 03 70 03 76 03 74 03 85 03 7F 03 72 03 76 03 78 03 7D 03 58 03 35 03 3C 03 43 03 4E 03 37 03 3A 03 5B 03 51 03 49 03 56 03 41 03 4F 03 38 03 3C 03 4F 03 4E 03 51 03 4B 03 3C 03 45 03 42 03 44 03 37 03 42 03 37 03 43 03 47 03 3F 03 5C 03 39 03 42 03 3F 03 46 03 4D 03 63 03 5C 03 60 03 42 03 39 03 55 03 4A 03 50 03 4D 03 3E 03 61 03 2E 03 45 03 3E 03 35 03 60 03 46 71 3E
15:50:41.114 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1A 03 00 64 09 34 08 D5 07 B8 07 1E 06 EE 06 2F 05 C8 06 14 05 F2 05 9D 04 E5 03 D4 04 8D 03 AD 03 85 03 72 03 4F 03 67 03 42 03 4E 03 53 03 3F 03 58 03 56 03 4D 03 51 03 54 03 50 03 66 03 4A 03 36 03 39 03 4E 03 3E 03 46 03 3C 03 40 03 4B 03 35 03 32 03 39 03 3B 03 41 03 3E 03 49 03 55 03 54 03 50 03 38 03 46 03 41 03 3D 03 45 03 46 03 4D 03 44 03 3F 03 45 03 53 03 3E 03 42 03 48 03 2D 03 36 03 41 03 4F 03 4C 03 50 03 3E 03 47 03 37 03 31 03 57 03 58 03 41 03 44 03 3E 03 46 03 3F 03 45 03 4A 03 5A 03 3F 03 41 03 53 03 30 03 48 03 3D 03 67 03 45 03 4A 03 44 03 40 03 3B 03 52 03 4D 03 47 03 38 03 58 03 46 66 9E
15:50:41.143 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1A 04 00 64 07 49 07 0C 06 C1 05 D4 05 FE 05 EE 05 5B 05 AB 05 A9 04 E8 04 12 03 B1 03 78 03 4A 03 4B 03 45 03 34 03 4C 03 4E 03 5E 03 29 03 58 03 4F 03 42 03 40 03 34 03 55 03 4F 03 40 03 44 03 57 03 38 03 3B 03 51 03 4F 03 30 03 53 03 45 03 61 03 4A 03 49 03 4B 03 48 03 3D 03 59 03 42 03 48 03 31 03 50 03 52 03 50 03 51 03 54 03 36 03 44 03 52 03 4F 03 3D 03 77 03 8C 03 72 03 7B 03 73 03 78 03 86 03 63 03 87 03 79 03 75 03 7F 03 79 03 85 03 78 03 6C 03 6A 03 7C 03 82 03 8A 03 88 03 78 03 52 03 7D 03 84 03 75 03 82 03 6E 03 78 03 7D 03 82 03 82 03 8E 03 8B 03 8C 03 71 03 76 03 74 03 71 03 46 03 52 03 3A F2 0A
15:50:41.173 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1A 05 00 64 07 8D 06 2C 06 81 06 0A 05 BF 05 AB 05 1E 05 47 05 2F 04 87 04 46 03 7F 03 8A 03 55 03 B7 03 66 03 5D 03 61 03 49 03 4C 03 4A 03 64 03 41 03 3E 03 28 03 57 03 35 03 40 03 4E 03 60 03 60 03 28 03 3B 03 3C 03 38 03 47 03 45 03 47 03 5B 03 67 03 66 03 51 03 5E 03 3E 03 34 03 4C 03 34 03 42 03 75 03 5C 03 4F 03 42 03 51 03 49 03 56 03 58 03 40 03 41 03 5E 03 54 03 64 03 4F 03 4E 03 4C 03 43 03 40 03 62 03 52 03 57 03 6E 03 45 03 57 03 4A 03 43 03 4C 03 3F 03 5C 03 6F 03 57 03 40 03 55 03 5A 03 49 03 42 03 35 03 48 03 4D 03 59 03 53 03 51 03 5B 03 52 03 3A 03 43 03 57 03 5B 03 50 03 69 03 70 03 63 65 B3
15:50:41.201 dir=RX prefix=raa: len=8 hex=72 61 61 3A 00 00 43 5E
15:50:41.625 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1B 00 00 64 08 7A 08 B0 08 FA 09 26 08 BF 08 75 07 DE 06 E4 06 D5 06 AB 06 A6 06 72 06 31 05 EE 05 8E 05 46 05 14 04 CB 04 99 04 4A 03 F2 03 8F 03 73 03 5A 03 44 03 49 03 50 03 51 03 44 03 39 03 4E 03 4A 03 46 03 42 03 4E 03 55 03 48 03 3D 03 37 03 3C 03 30 03 2F 03 40 03 4C 03 44 03 3B 03 42 03 43 03 63 03 5A 03 37 03 4B 03 53 03 39 03 42 03 4A 03 45 03 55 03 58 03 45 03 38 03 49 03 3A 03 43 03 4E 03 53 03 3A 03 4B 03 47 03 4F 03 45 03 37 03 30 03 2A 03 4B 03 29 03 2A 03 3A 03 45 03 40 03 68 03 45 03 39 03 45 03 54 03 3A 03 41 03 3C 03 4F 03 4D 03 3E 03 51 03 41 03 40 03 55 03 33 03 34 03 3E 03 4D 03 41 F7 0B
15:50:41.664 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1B 01 00 64 08 80 07 4F 07 3C 06 CA 06 95 06 A2 06 15 05 BA 05 45 04 83 04 4C 04 0B 03 88 03 85 03 62 03 5C 03 3B 03 4A 03 4A 03 37 03 4C 03 38 03 38 03 46 03 34 03 23 03 37 03 43 03 3B 03 47 03 39 03 2E 03 49 03 37 03 3F 03 49 03 33 03 30 03 52 03 4D 03 6B 03 4F 03 40 03 40 03 4E 03 4D 03 3C 03 56 03 3C 03 3C 03 4B 03 41 03 48 03 43 03 27 03 43 03 49 03 2B 03 3C 03 3C 03 40 03 46 03 3E 03 44 03 42 03 40 03 5A 03 37 03 2D 03 4D 03 2A 03 51 03 28 03 43 03 42 03 48 03 59 03 2E 03 40 03 25 03 38 03 3C 03 3C 03 44 03 3A 03 27 03 45 03 28 03 4D 03 3E 03 3B 03 4D 03 42 03 49 03 3F 03 49 03 59 03 23 03 36 03 40 0D 2A
15:50:41.687 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1B 02 00 64 07 B5 06 D5 06 22 06 09 06 25 05 1E 05 20 05 4C 05 B3 04 A4 04 73 04 11 03 D7 03 87 03 58 03 44 03 53 03 33 03 58 03 4A 03 35 03 2B 03 4B 03 3D 03 48 03 45 03 42 03 48 03 67 03 7A 03 78 03 82 03 8C 03 70 03 77 03 6E 03 7C 03 89 03 82 03 78 03 70 03 8C 03 74 03 90 03 6C 03 83 03 8A 03 8B 03 8F 03 8A 03 86 03 8D 03 77 03 80 03 87 03 7F 03 7D 03 7F 03 79 03 86 03 7A 03 7D 03 83 03 73 03 7A 03 7E 03 7F 03 8E 03 52 03 4A 03 41 03 3F 03 53 03 44 03 39 03 37 03 4F 03 3D 03 60 03 2F 03 42 03 45 03 51 03 23 03 36 03 4B 03 3B 03 2F 03 3C 03 56 03 49 03 41 03 40 03 51 03 3B 03 36 03 56 03 47 03 4F 03 4A 94 D8
15:50:41.714 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1B 03 00 64 09 34 08 D9 07 BC 07 1E 06 EB 06 2D 05 BE 06 0B 05 EA 05 9F 04 D4 03 D2 04 96 03 B9 03 5E 03 77 03 73 03 4F 03 41 03 48 03 43 03 3C 03 4F 03 4F 03 54 03 4F 03 53 03 4C 03 34 03 59 03 43 03 35 03 3B 03 48 03 35 03 47 03 35 03 49 03 41 03 62 03 4B 03 37 03 45 03 31 03 3B 03 3E 03 3F 03 4E 03 4C 03 3D 03 4C 03 4F 03 46 03 44 03 43 03 5E 03 47 03 42 03 49 03 47 03 72 03 4F 03 69 03 43 03 4E 03 41 03 47 03 36 03 4E 03 30 03 46 03 54 03 4F 03 4E 03 41 03 3E 03 43 03 42 03 42 03 48 03 47 03 50 03 56 03 38 03 47 03 4D 03 4C 03 4D 03 34 03 43 03 4A 03 4A 03 4A 03 56 03 55 03 53 03 44 03 45 03 5A 03 52 F8 FD
15:50:41.744 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1B 04 00 64 07 3F 07 08 06 C5 05 E1 05 EE 05 F3 05 5D 05 9F 05 8D 04 FA 04 09 03 AB 03 79 03 33 03 40 03 39 03 48 03 52 03 3A 03 60 03 49 03 40 03 4F 03 42 03 2E 03 34 03 43 03 47 03 4E 03 3D 03 3C 03 42 03 3E 03 4E 03 40 03 44 03 62 03 4C 03 40 03 3E 03 45 03 3E 03 4C 03 5A 03 38 03 33 03 35 03 39 03 46 03 51 03 41 03 3D 03 4E 03 54 03 45 03 47 03 58 03 46 03 66 03 51 03 54 03 58 03 2F 03 4B 03 5B 03 50 03 3F 03 45 03 57 03 4C 03 50 03 45 03 4D 03 3C 03 32 03 51 03 3C 03 4D 03 5D 03 41 03 40 03 55 03 86 03 93 03 7E 03 7B 03 88 03 74 03 7F 03 7A 03 82 03 73 03 79 03 91 03 6D 03 86 03 80 03 81 03 7C 03 A8 65 2D
15:50:41.774 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1B 05 00 64 07 8B 06 85 06 D7 06 4D 06 01 05 F2 05 67 05 A1 05 7E 04 A8 04 6D 03 AF 03 AC 03 86 03 D6 03 66 03 56 03 5D 03 59 03 4D 03 6D 03 48 03 3F 03 3C 03 4F 03 43 03 49 03 47 03 48 03 4F 03 53 03 57 03 52 03 71 03 42 03 50 03 44 03 47 03 3D 03 57 03 4B 03 47 03 58 03 5B 03 4A 03 46 03 43 03 51 03 42 03 4F 03 5F 03 4D 03 5E 03 49 03 57 03 3A 03 5A 03 4C 03 2F 03 51 03 6E 03 52 03 49 03 58 03 51 03 41 03 42 03 34 03 54 03 60 03 5E 03 4E 03 5A 03 49 03 55 03 2F 03 35 03 56 03 4E 03 57 03 51 03 67 03 5C 03 55 03 4C 03 3C 03 44 03 57 03 5B 03 50 03 56 03 5A 03 54 03 47 03 3A 03 50 03 2F 03 41 03 4F 03 6A 2A C1
15:50:41.803 dir=RX prefix=raa: len=8 hex=72 61 61 3A 00 00 43 5E
15:50:42.255 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1C 00 00 64 08 7A 08 B2 08 FC 09 24 08 BC 08 72 07 DB 06 D6 06 D2 06 A9 06 A3 06 6F 06 2B 05 E9 05 8B 05 3B 05 0D 04 BC 04 91 04 4E 03 E4 03 97 03 70 03 69 03 51 03 5C 03 4C 03 32 03 56 03 57 03 42 03 3E 03 45 03 3B 03 3C 03 3B 03 3C 03 38 03 3F 03 26 03 44 03 41 03 37 03 47 03 22 03 45 03 39 03 3F 03 4D 03 4E 03 4B 03 48 03 4F 03 2D 03 35 03 3F 03 25 03 3D 03 47 03 3E 03 43 03 46 03 39 03 31 03 3D 03 40 03 4A 03 50 03 5C 03 4A 03 35 03 49 03 2D 03 4E 03 4B 03 54 03 3D 03 4A 03 45 03 40 03 36 03 43 03 3D 03 3D 03 50 03 4A 03 36 03 51 03 41 03 44 03 49 03 3D 03 4E 03 41 03 45 03 49 03 39 03 3F 03 3B 03 4F A7 E6
15:50:42.283 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1C 01 00 64 08 85 07 51 07 38 06 CC 06 A4 06 AB 06 00 05 C5 05 3C 04 63 04 3E 04 0B 03 8B 03 5C 03 76 03 55 03 31 03 40 03 4E 03 3B 03 3F 03 55 03 50 03 43 03 49 03 4B 03 2B 03 5B 03 45 03 3C 03 3C 03 3B 03 44 03 2A 03 42 03 4A 03 52 03 44 03 4A 03 3F 03 4F 03 3E 03 48 03 42 03 39 03 47 03 3F 03 55 03 34 03 2E 03 49 03 44 03 42 03 53 03 2C 03 4B 03 24 03 31 03 5B 03 3F 03 38 03 36 03 4B 03 44 03 46 03 4A 03 5A 03 48 03 37 03 5B 03 3B 03 38 03 56 03 5D 03 43 03 4D 03 4F 03 4E 03 3D 03 4E 03 44 03 45 03 48 03 47 03 4A 03 44 03 39 03 50 03 43 03 43 03 45 03 46 03 3A 03 43 03 42 03 4F 03 4A 03 54 03 3D 03 39 8A 8B
15:50:42.315 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1C 02 00 64 08 43 07 38 06 7E 06 80 06 7A 05 6E 05 6E 05 83 05 FA 04 C8 04 5F 04 3D 04 02 03 9D 03 68 03 5D 03 4A 03 45 03 4F 03 46 03 48 03 49 03 57 03 90 03 80 03 83 03 7C 03 6F 03 75 03 7E 03 7A 03 70 03 7F 03 72 03 7E 03 7B 03 93 03 89 03 64 03 74 03 7B 03 78 03 7A 03 6E 03 5F 03 86 03 8C 03 73 03 83 03 7E 03 83 03 89 03 8D 03 6F 03 7F 03 6E 03 79 03 7E 03 79 03 81 03 81 03 6B 03 46 03 44 03 55 03 39 03 3F 03 41 03 42 03 3B 03 3F 03 59 03 34 03 47 03 43 03 42 03 4A 03 39 03 51 03 49 03 44 03 4A 03 3B 03 4B 03 3B 03 2C 03 48 03 3F 03 42 03 47 03 58 03 3D 03 38 03 3B 03 4B 03 40 03 49 03 3E 03 57 03 48 A7 25
15:50:42.344 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1C 03 00 64 09 34 08 DA 07 BB 07 1C 06 EB 06 28 05 BE 06 14 05 DF 05 A1 04 C5 03 E8 04 96 03 8E 03 60 03 62 03 65 03 44 03 39 03 3F 03 42 03 4C 03 51 03 4F 03 46 03 49 03 4E 03 44 03 37 03 3D 03 3E 03 43 03 44 03 41 03 5C 03 32 03 43 03 3E 03 43 03 47 03 4B 03 5E 03 38 03 3D 03 57 03 49 03 4B 03 4B 03 2F 03 4B 03 3F 03 48 03 30 03 42 03 34 03 39 03 45 03 5C 03 4E 03 3B 03 35 03 39 03 3F 03 4E 03 5C 03 32 03 5F 03 5C 03 43 03 34 03 46 03 35 03 56 03 3A 03 35 03 2B 03 42 03 37 03 3C 03 3D 03 35 03 4E 03 48 03 4C 03 50 03 41 03 39 03 40 03 37 03 2D 03 55 03 3B 03 46 03 42 03 38 03 2E 03 55 03 4A 03 46 03 4E AE 43
15:50:42.373 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1C 04 00 64 07 1A 06 E7 06 9E 05 C1 05 C5 05 AB 05 1E 05 68 05 69 04 C1 04 04 03 C9 03 84 03 42 03 3E 03 35 03 42 03 5B 03 5D 03 4D 03 4E 03 57 03 3C 03 3E 03 4F 03 58 03 5C 03 3E 03 45 03 4A 03 33 03 47 03 54 03 57 03 46 03 40 03 43 03 45 03 59 03 3B 03 49 03 35 03 56 03 4A 03 3F 03 43 03 3A 03 45 03 40 03 42 03 3D 03 33 03 51 03 2F 03 59 03 4D 03 40 03 49 03 59 03 4E 03 35 03 45 03 3F 03 3E 03 3B 03 44 03 4D 03 3D 03 4A 03 62 03 58 03 48 03 3A 03 49 03 46 03 7F 03 93 03 84 03 95 03 84 03 87 03 88 03 70 03 87 03 90 03 93 03 93 03 79 03 80 03 82 03 7E 03 8A 03 84 03 83 03 8D 03 87 03 7A 03 8C 03 9A 03 7F AC B0
15:50:42.403 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1C 05 00 64 07 91 06 70 06 D6 06 56 06 00 05 F5 05 5C 05 82 05 58 04 B1 04 62 03 77 03 7F 03 72 03 D5 03 69 03 52 03 53 03 70 03 4A 03 4A 03 4F 03 40 03 5B 03 43 03 36 03 55 03 58 03 54 03 42 03 5E 03 43 03 4E 03 49 03 42 03 4A 03 49 03 47 03 4B 03 4C 03 4E 03 3C 03 4F 03 52 03 43 03 48 03 49 03 55 03 4F 03 49 03 62 03 55 03 40 03 4A 03 57 03 46 03 43 03 55 03 6B 03 4B 03 3D 03 4E 03 43 03 5F 03 4C 03 49 03 43 03 65 03 51 03 5B 03 52 03 26 03 4D 03 4E 03 50 03 43 03 66 03 61 03 64 03 57 03 4F 03 49 03 56 03 43 03 54 03 3E 03 4F 03 52 03 5A 03 59 03 32 03 51 03 63 03 55 03 3F 03 51 03 51 03 56 03 5D 03 40 EE AC
15:50:42.431 dir=RX prefix=raa: len=8 hex=72 61 61 3A 00 00 43 5E
15:50:42.794 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1D 00 00 64 08 7B 08 B7 08 FC 09 23 08 BA 08 75 07 E8 06 DA 06 D0 06 A4 06 A2 06 70 06 2C 05 EE 05 90 05 41 05 11 04 C6 04 A1 04 42 03 E5 03 95 03 5F 03 4A 03 4B 03 4A 03 3A 03 4A 03 4E 03 4B 03 51 03 38 03 3A 03 58 03 43 03 46 03 54 03 46 03 48 03 39 03 4A 03 57 03 55 03 27 03 4E 03 38 03 3C 03 31 03 3F 03 36 03 44 03 33 03 57 03 42 03 3A 03 47 03 3B 03 51 03 4E 03 41 03 38 03 31 03 45 03 55 03 48 03 3F 03 37 03 38 03 48 03 35 03 3B 03 4D 03 3C 03 50 03 2F 03 43 03 32 03 32 03 36 03 3C 03 45 03 4C 03 3C 03 43 03 3D 03 3F 03 42 03 3B 03 30 03 33 03 3C 03 4A 03 4B 03 48 03 53 03 45 03 2F 03 46 03 3F 03 23 C8 99
15:50:42.823 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1D 01 00 64 08 85 07 52 07 38 06 C4 06 98 06 A9 06 05 05 C3 05 3A 04 5E 04 58 03 F5 03 8F 03 7B 03 58 03 51 03 4A 03 30 03 5A 03 4F 03 4E 03 3F 03 3B 03 25 03 45 03 51 03 30 03 4D 03 3C 03 49 03 47 03 44 03 40 03 2E 03 56 03 3B 03 37 03 34 03 57 03 54 03 46 03 3C 03 2F 03 42 03 39 03 3B 03 3C 03 5B 03 4F 03 3A 03 36 03 3D 03 4E 03 4B 03 57 03 4D 03 46 03 47 03 5D 03 37 03 20 03 4B 03 52 03 49 03 48 03 49 03 3F 03 48 03 4B 03 44 03 37 03 48 03 42 03 3B 03 39 03 35 03 59 03 49 03 40 03 44 03 2F 03 2B 03 57 03 49 03 3F 03 4B 03 3E 03 3E 03 42 03 3D 03 43 03 38 03 5B 03 46 03 42 03 40 03 2D 03 55 03 39 03 3F FD 5D
15:50:42.854 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1D 02 00 64 08 D2 07 A1 06 7E 06 80 06 82 05 57 05 76 05 8C 05 F7 04 D5 04 88 04 1E 03 ED 03 81 03 5F 03 48 03 67 03 42 03 42 03 53 03 49 03 3A 03 37 03 2F 03 50 03 3E 03 40 03 38 03 38 03 4E 03 38 03 43 03 48 03 44 03 4F 03 82 03 79 03 81 03 69 03 6E 03 8B 03 7D 03 7E 03 86 03 84 03 77 03 7C 03 70 03 94 03 7C 03 82 03 8B 03 73 03 76 03 86 03 8E 03 7C 03 74 03 71 03 89 03 66 03 90 03 93 03 7D 03 7C 03 8C 03 90 03 78 03 81 03 80 03 91 03 89 03 73 03 8B 03 51 03 52 03 35 03 3F 03 49 03 3D 03 41 03 4D 03 4C 03 42 03 59 03 2C 03 55 03 48 03 2B 03 3C 03 56 03 44 03 45 03 52 03 4B 03 47 03 4B 03 3B 03 4B 03 43 5D F7
15:50:42.868 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1D 03 00 64 08 A1 08 4B 07 4D 06 C3 06 8F 05 EE 05 7D 05 D1 05 A3 05 64 04 B7 03 CB 04 89 03 B7 03 62 03 6E 03 5F 03 54 03 46 03 48 03 38 03 41 03 51 03 42 03 4B 03 36 03 41 03 47 03 42 03 4C 03 3E 03 44 03 4F 03 39 03 3C 03 3A 03 54 03 4F 03 3C 03 3F 03 46 03 46 03 48 03 40 03 3F 03 5E 03 4A 03 47 03 50 03 36 03 4E 03 55 03 47 03 43 03 4D 03 39 03 3A 03 38 03 43 03 57 03 45 03 46 03 4A 03 37 03 35 03 4B 03 44 03 4A 03 51 03 45 03 39 03 49 03 56 03 56 03 45 03 37 03 3F 03 42 03 38 03 48 03 40 03 4D 03 37 03 48 03 46 03 45 03 45 03 4E 03 49 03 62 03 39 03 2C 03 4C 03 3F 03 56 03 56 03 35 03 47 03 40 03 5B FA C5
15:50:42.899 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1D 04 00 64 07 3F 07 09 06 B5 05 CB 05 E8 05 EF 05 56 05 A4 05 91 04 FB 04 0C 03 FD 03 8B 03 54 03 43 03 43 03 44 03 5B 03 4E 03 44 03 32 03 50 03 4F 03 3A 03 32 03 3D 03 2E 03 3D 03 42 03 43 03 47 03 49 03 37 03 4F 03 5F 03 4C 03 57 03 3F 03 4F 03 43 03 3E 03 31 03 63 03 57 03 4A 03 44 03 5C 03 59 03 4C 03 51 03 5D 03 37 03 50 03 38 03 3F 03 3E 03 3E 03 49 03 44 03 3D 03 4F 03 48 03 2B 03 5C 03 31 03 3C 03 47 03 4F 03 45 03 35 03 44 03 4A 03 67 03 51 03 3D 03 4C 03 4A 03 44 03 38 03 43 03 4F 03 4E 03 3F 03 4D 03 4E 03 4F 03 41 03 4A 03 4B 03 47 03 53 03 49 03 3D 03 59 03 55 03 64 03 5A 03 3D 03 45 03 39 BF 67
15:50:42.929 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1D 05 00 64 07 88 06 77 06 D7 06 4C 06 02 05 F0 05 40 05 81 05 61 04 C4 04 60 03 6C 03 6F 03 6C 03 E1 03 6F 03 4F 03 49 03 44 03 62 03 54 03 4F 03 46 03 48 03 34 03 36 03 3D 03 39 03 56 03 5E 03 52 03 59 03 4D 03 3A 03 5A 03 48 03 3E 03 48 03 50 03 5F 03 5D 03 5C 03 59 03 42 03 3E 03 47 03 5F 03 51 03 5C 03 4B 03 4E 03 38 03 4F 03 50 03 4A 03 34 03 39 03 46 03 6A 03 62 03 55 03 39 03 43 03 4F 03 43 03 35 03 41 03 40 03 43 03 68 03 50 03 52 03 44 03 4C 03 50 03 46 03 4B 03 52 03 54 03 51 03 55 03 44 03 41 03 40 03 46 03 48 03 4E 03 5B 03 6C 03 4E 03 42 03 42 03 40 03 4A 03 40 03 47 03 4A 03 57 03 5C 03 5E 15 2D
15:50:42.956 dir=RX prefix=raa: len=8 hex=72 61 61 3A 00 00 43 5E
15:50:43.453 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1E 00 00 64 08 80 08 AE 08 F5 09 26 08 BD 08 76 07 EE 06 D8 06 D4 06 9F 06 A0 06 70 06 31 05 F4 05 8B 05 49 05 10 04 C2 04 9C 04 43 03 D9 03 81 03 6D 03 4F 03 4F 03 57 03 4E 03 52 03 47 03 47 03 39 03 44 03 48 03 41 03 41 03 41 03 34 03 31 03 30 03 36 03 48 03 34 03 4A 03 3D 03 4B 03 40 03 4D 03 3A 03 2F 03 56 03 53 03 48 03 3A 03 49 03 50 03 4B 03 3F 03 46 03 41 03 3F 03 46 03 30 03 67 03 3B 03 45 03 3F 03 4C 03 46 03 2D 03 43 03 25 03 31 03 3E 03 43 03 3A 03 39 03 3A 03 45 03 45 03 53 03 34 03 2F 03 32 03 4C 03 4A 03 35 03 47 03 49 03 3F 03 59 03 52 03 3B 03 47 03 44 03 43 03 41 03 46 03 36 03 31 03 43 F4 F8
15:50:43.484 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1E 01 00 64 08 84 07 4D 07 3B 06 C7 06 A0 06 A1 06 03 05 C6 05 45 04 64 04 36 04 08 03 95 03 88 03 49 03 53 03 40 03 61 03 41 03 57 03 4A 03 4A 03 62 03 2F 03 3F 03 3E 03 3C 03 41 03 28 03 4C 03 30 03 36 03 3E 03 4A 03 64 03 4A 03 35 03 3E 03 30 03 46 03 3D 03 53 03 33 03 39 03 4E 03 38 03 48 03 32 03 48 03 49 03 3F 03 3B 03 4B 03 49 03 50 03 32 03 48 03 4D 03 47 03 4C 03 40 03 40 03 45 03 3F 03 45 03 4F 03 3E 03 56 03 48 03 38 03 43 03 3B 03 5D 03 59 03 3D 03 4A 03 36 03 3D 03 4E 03 3E 03 49 03 4B 03 4A 03 2F 03 3F 03 54 03 44 03 56 03 53 03 43 03 42 03 2E 03 2E 03 49 03 41 03 58 03 3B 03 65 03 37 03 3F 62 31
15:50:43.515 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1E 02 00 64 08 43 07 36 06 7E 06 83 06 7E 05 68 05 72 05 9B 06 02 04 E1 04 7F 04 3B 03 D5 03 93 03 67 03 48 03 5D 03 34 03 42 03 3C 03 41 03 37 03 41 03 61 03 57 03 4B 03 5A 03 49 03 92 03 79 03 80 03 8F 03 6C 03 7F 03 7C 03 85 03 9C 03 86 03 80 03 80 03 76 03 86 03 78 03 82 03 74 03 7F 03 6F 03 8D 03 84 03 8D 03 93 03 8B 03 86 03 7A 03 77 03 7A 03 85 03 83 03 90 03 82 03 8E 03 76 03 81 03 7A 03 A4 03 7F 03 75 03 52 03 35 03 60 03 52 03 4E 03 46 03 3F 03 1E 03 51 03 55 03 4C 03 40 03 39 03 3F 03 4E 03 43 03 33 03 35 03 4F 03 43 03 55 03 42 03 58 03 52 03 44 03 4A 03 4F 03 52 03 47 03 58 03 49 03 49 03 50 A9 80
15:50:43.543 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1E 03 00 64 09 37 08 D5 07 B7 07 1B 06 EC 06 32 05 C9 06 0F 05 EE 05 9A 04 C5 03 BC 04 8E 03 9D 03 6C 03 6C 03 47 03 43 03 4C 03 53 03 61 03 39 03 52 03 43 03 3C 03 39 03 26 03 43 03 39 03 4A 03 53 03 50 03 45 03 2F 03 46 03 2D 03 3C 03 47 03 54 03 5B 03 41 03 3D 03 41 03 5B 03 56 03 4D 03 51 03 4E 03 44 03 38 03 33 03 30 03 53 03 4E 03 3E 03 34 03 46 03 51 03 57 03 4B 03 3A 03 55 03 5C 03 3E 03 4F 03 50 03 44 03 42 03 31 03 4D 03 3D 03 43 03 3C 03 35 03 68 03 28 03 32 03 3E 03 3E 03 4B 03 48 03 51 03 2D 03 3E 03 41 03 49 03 36 03 34 03 4C 03 35 03 4A 03 43 03 40 03 41 03 4E 03 42 03 4E 03 41 03 42 03 45 F0 A2
15:50:43.573 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1E 04 00 64 07 45 07 10 06 BF 05 DA 05 F0 05 EF 05 5A 05 9A 05 8D 04 EA 04 2E 03 AD 03 89 03 3A 03 3D 03 44 03 52 03 5B 03 55 03 53 03 55 03 76 03 50 03 4F 03 4F 03 59 03 4D 03 47 03 40 03 52 03 61 03 59 03 47 03 43 03 46 03 37 03 27 03 3B 03 57 03 45 03 42 03 3D 03 4F 03 46 03 49 03 4C 03 57 03 52 03 4F 03 3D 03 3F 03 52 03 40 03 3A 03 43 03 61 03 50 03 44 03 49 03 44 03 52 03 62 03 50 03 3E 03 49 03 46 03 4D 03 4F 03 3E 03 5E 03 47 03 55 03 44 03 4F 03 50 03 56 03 42 03 5F 03 51 03 51 03 3D 03 48 03 47 03 4B 03 52 03 4D 03 65 03 5B 03 62 03 51 03 59 03 52 03 3C 03 49 03 35 03 37 03 5C 03 6C 03 74 03 5D 5B 80
15:50:43.603 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1E 05 00 64 07 8A 06 72 06 DD 06 54 05 F6 05 F0 05 59 05 7C 05 73 04 A7 04 52 03 7F 03 8F 03 65 03 D2 03 68 03 47 03 58 03 66 03 57 03 61 03 66 03 41 03 42 03 48 03 4C 03 5E 03 63 03 57 03 52 03 69 03 58 03 5C 03 3B 03 54 03 54 03 37 03 46 03 45 03 5D 03 53 03 5F 03 4F 03 51 03 38 03 46 03 54 03 4B 03 5E 03 59 03 46 03 44 03 3F 03 38 03 2E 03 4A 03 51 03 4F 03 50 03 72 03 45 03 52 03 4E 03 3F 03 59 03 3F 03 52 03 58 03 52 03 51 03 56 03 4A 03 51 03 56 03 40 03 4B 03 6A 03 53 03 58 03 4B 03 50 03 42 03 61 03 39 03 5D 03 53 03 4E 03 50 03 60 03 40 03 4B 03 68 03 46 03 5A 03 3A 03 4E 03 53 03 44 03 57 03 52 54 3C
15:50:43.633 dir=RX prefix=raa: len=8 hex=72 61 61 3A 00 00 43 5E
15:50:43.980 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1F 00 00 64 08 7C 08 BD 08 FE 09 22 08 B7 08 76 07 ED 06 D5 06 CF 06 A0 06 9D 06 6D 06 2B 05 EA 05 86 05 3C 05 06 04 C8 04 A2 04 54 03 F3 03 9D 03 73 03 68 03 46 03 52 03 38 03 59 03 47 03 30 03 4E 03 50 03 44 03 2F 03 3B 03 2B 03 41 03 26 03 31 03 51 03 37 03 36 03 46 03 47 03 49 03 44 03 5F 03 47 03 47 03 4C 03 42 03 46 03 46 03 44 03 3E 03 33 03 50 03 39 03 30 03 38 03 4B 03 41 03 43 03 34 03 4D 03 41 03 69 03 52 03 39 03 2C 03 43 03 4F 03 43 03 43 03 36 03 3A 03 2F 03 49 03 5A 03 37 03 3E 03 46 03 33 03 4E 03 46 03 2E 03 4B 03 39 03 3B 03 26 03 2F 03 35 03 53 03 4B 03 43 03 45 03 43 03 57 03 41 03 37 C2 0D
15:50:44.009 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1F 01 00 64 08 85 07 51 07 3D 06 C7 06 97 06 A7 06 0F 05 BF 05 16 04 59 04 3B 04 0D 03 A0 03 68 03 66 03 51 03 3F 03 49 03 48 03 4C 03 42 03 4B 03 4D 03 5A 03 3F 03 48 03 47 03 26 03 4C 03 3E 03 51 03 3F 03 39 03 4C 03 39 03 42 03 2C 03 4A 03 44 03 33 03 32 03 54 03 38 03 4B 03 3F 03 40 03 52 03 63 03 3E 03 44 03 37 03 3C 03 3B 03 2C 03 4B 03 3F 03 41 03 45 03 44 03 4D 03 49 03 2B 03 34 03 39 03 44 03 40 03 3E 03 43 03 46 03 4B 03 4B 03 4B 03 37 03 46 03 36 03 50 03 3F 03 44 03 34 03 34 03 2B 03 3C 03 48 03 4B 03 36 03 4D 03 3A 03 31 03 48 03 37 03 42 03 4D 03 57 03 36 03 36 03 38 03 4F 03 45 03 4C 03 42 38 CB
15:50:44.039 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1F 02 00 64 08 D6 07 30 06 6D 06 85 06 86 05 64 05 64 05 8D 05 F7 04 D2 04 7A 04 2A 03 EB 03 8C 03 68 03 57 03 4A 03 40 03 41 03 48 03 4F 03 3D 03 3C 03 4F 03 49 03 4C 03 4D 03 48 03 49 03 45 03 39 03 3F 03 40 03 4C 03 85 03 84 03 7B 03 7A 03 86 03 9E 03 80 03 8C 03 81 03 76 03 7C 03 7F 03 83 03 6C 03 85 03 7F 03 7E 03 7F 03 8A 03 79 03 81 03 86 03 87 03 7B 03 8E 03 7F 03 86 03 81 03 82 03 84 03 8F 03 80 03 94 03 8B 03 8B 03 97 03 8C 03 8B 03 74 03 44 03 4A 03 56 03 47 03 53 03 4C 03 52 03 50 03 42 03 3A 03 65 03 3A 03 57 03 52 03 39 03 56 03 3C 03 1A 03 2F 03 42 03 3D 03 3B 03 42 03 25 03 41 03 4B 03 58 A1 AD
15:50:44.069 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1F 03 00 64 09 37 08 D9 07 BD 07 18 06 EB 06 2F 05 C4 06 0C 05 E5 05 A0 04 DF 03 D4 04 98 03 9C 03 7B 03 7A 03 62 03 58 03 46 03 51 03 44 03 4F 03 43 03 52 03 4D 03 4B 03 36 03 44 03 3C 03 48 03 33 03 4A 03 4F 03 45 03 31 03 3C 03 36 03 38 03 3F 03 45 03 3E 03 34 03 42 03 37 03 5B 03 4C 03 48 03 3A 03 53 03 54 03 33 03 2A 03 51 03 67 03 38 03 4E 03 47 03 49 03 20 03 40 03 45 03 45 03 2E 03 41 03 45 03 53 03 4E 03 4B 03 3F 03 38 03 41 03 4B 03 4D 03 43 03 54 03 48 03 59 03 4A 03 36 03 30 03 37 03 50 03 44 03 58 03 4A 03 4F 03 38 03 4E 03 35 03 38 03 43 03 3D 03 41 03 47 03 4E 03 51 03 6D 03 39 03 3D 03 44 DD D4
15:50:44.099 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1F 04 00 64 07 37 07 0B 06 B0 05 C5 05 F2 05 E5 05 5A 05 98 05 8F 04 E9 03 DC 03 CA 03 73 03 55 03 4F 03 44 03 43 03 5A 03 32 03 38 03 3E 03 49 03 41 03 5F 03 50 03 47 03 62 03 48 03 4D 03 58 03 56 03 53 03 57 03 46 03 41 03 2B 03 5A 03 4D 03 45 03 48 03 44 03 59 03 4D 03 43 03 4F 03 51 03 5A 03 52 03 3E 03 51 03 49 03 3F 03 45 03 38 03 56 03 5C 03 4A 03 41 03 52 03 46 03 46 03 47 03 4B 03 3E 03 40 03 51 03 5A 03 4B 03 45 03 41 03 3E 03 3C 03 50 03 4D 03 52 03 4E 03 43 03 4A 03 45 03 4E 03 3B 03 48 03 4D 03 2C 03 3A 03 46 03 46 03 46 03 40 03 5D 03 38 03 3C 03 53 03 3C 03 55 03 48 03 49 03 6C 03 72 03 5D 9C 30
15:50:44.129 dir=RX prefix=reb: len=210 hex=72 65 62 3A 1F 05 00 64 07 90 06 7C 06 D8 06 54 06 07 05 E5 05 67 05 97 05 7A 04 C0 04 39 03 A7 03 AE 03 63 03 CE 03 56 03 4F 03 63 03 66 03 56 03 4B 03 62 03 55 03 54 03 52 03 36 03 3D 03 65 03 34 03 49 03 4D 03 57 03 5A 03 35 03 48 03 41 03 37 03 4D 03 3E 03 40 03 5D 03 46 03 5A 03 5C 03 45 03 4D 03 3C 03 52 03 3F 03 4B 03 62 03 5F 03 51 03 5A 03 3F 03 5E 03 2E 03 50 03 5D 03 5A 03 5E 03 61 03 41 03 4A 03 4E 03 4C 03 55 03 4B 03 59 03 55 03 6D 03 6C 03 51 03 51 03 45 03 3A 03 4B 03 64 03 57 03 56 03 68 03 63 03 4B 03 58 03 2D 03 49 03 49 03 48 03 5C 03 48 03 50 03 44 03 61 03 56 03 2E 03 40 03 3A 03 63 03 41 03 4A AD D9
15:50:44.157 dir=RX prefix=raa: len=8 hex=72 61 61 3A 00 00 43 5E
15:50:48.826 dir=RX prefix=rsn: len=8 hex=72 73 6E 3A 10 26 A3 8D
15:50:48.901 dir=RX prefix=reb: len=210 hex=72 65 62 3A 20 00 00 64 08 7F 08 B5 08 F9 09 25 08 BB 08 7A 07 F2 06 D5 06 CE 06 9F 06 9B 06 6D 06 2E 05 EC 05 8A 05 44 05 10 04 B8 04 A2 04 3A 03 EA 03 9C 03 83 03 50 03 3C 03 49 03 57 03 51 03 5E 03 42 03 3C 03 3B 03 3D 03 46 03 3B 03 5D 03 48 03 48 03 3B 03 2C 03 42 03 32 03 43 03 40 03 3F 03 47 03 39 03 35 03 37 03 41 03 4E 03 2D 03 4D 03 36 03 47 03 3F 03 44 03 33 03 4C 03 3C 03 53 03 5A 03 3A 03 41 03 40 03 4B 03 53 03 40 03 47 03 4E 03 3D 03 38 03 32 03 42 03 37 03 3F 03 4F 03 2D 03 4A 03 42 03 44 03 3B 03 38 03 35 03 4A 03 4F 03 42 03 50 03 35 03 49 03 4C 03 5C 03 4E 03 48 03 45 03 4C 03 3B 03 54 03 3C 03 45 E8 96
15:50:48.960 dir=RX prefix=reb: len=210 hex=72 65 62 3A 20 01 00 64 08 87 07 50 07 3E 06 CB 06 A5 06 A5 05 F8 05 CF 05 37 04 7D 04 3A 04 23 03 C3 03 71 03 66 03 41 03 55 03 3F 03 39 03 39 03 2E 03 40 03 3C 03 52 03 46 03 4C 03 28 03 45 03 4B 03 47 03 46 03 5C 03 2E 03 4A 03 37 03 48 03 3E 03 2E 03 49 03 4E 03 4B 03 55 03 35 03 3F 03 43 03 56 03 2F 03 3A 03 37 03 35 03 44 03 41 03 32 03 35 03 4F 03 3E 03 3D 03 4C 03 52 03 47 03 40 03 45 03 51 03 4F 03 52 03 47 03 39 03 46 03 49 03 44 03 5C 03 3E 03 36 03 35 03 39 03 40 03 4B 03 34 03 49 03 65 03 4B 03 3E 03 4F 03 3C 03 4D 03 38 03 83 03 7C 03 75 03 7E 03 80 03 73 03 80 03 6F 03 75 03 77 03 75 03 8F 03 8F 03 86 B6 12
15:50:48.997 dir=RX prefix=reb: len=210 hex=72 65 62 3A 20 02 00 64 08 D4 07 A3 06 DD 06 DF 06 D9 05 A0 05 C6 05 CE 06 45 05 01 04 AA 04 3B 03 F1 03 A9 03 6B 03 34 03 55 03 4C 03 5F 03 50 03 3A 03 3F 03 41 03 44 03 56 03 41 03 4E 03 5F 03 3A 03 39 03 38 03 33 03 3C 03 53 03 41 03 34 03 57 03 56 03 60 03 40 03 44 03 34 03 44 03 4B 03 47 03 40 03 5A 03 48 03 4B 03 4C 03 41 03 3B 03 46 03 5A 03 36 03 54 03 3A 03 37 03 42 03 67 03 59 03 53 03 4A 03 46 03 47 03 5A 03 5F 03 45 03 32 03 48 03 3E 03 4C 03 53 03 44 03 47 03 40 03 4F 03 46 03 38 03 44 03 4B 03 54 03 46 03 48 03 4E 03 61 03 3E 03 3E 03 3F 03 42 03 62 03 38 03 36 03 3F 03 2F 03 51 03 49 03 69 03 5F 03 55 19 1C
15:50:49.024 dir=RX prefix=reb: len=210 hex=72 65 62 3A 20 03 00 64 09 35 08 D8 07 BD 07 15 06 E8 06 2C 05 DD 06 08 05 E0 05 96 04 DE 03 E5 04 8E 03 B1 03 73 03 7C 03 6E 03 66 03 3F 03 5B 03 49 03 3A 03 46 03 42 03 3A 03 2C 03 35 03 32 03 39 03 4F 03 4F 03 47 03 33 03 4D 03 3D 03 35 03 42 03 35 03 47 03 57 03 4A 03 35 03 3F 03 4B 03 34 03 50 03 49 03 50 03 26 03 40 03 53 03 5D 03 4D 03 46 03 43 03 3C 03 39 03 49 03 54 03 47 03 52 03 46 03 2E 03 3C 03 38 03 59 03 53 03 40 03 45 03 44 03 34 03 45 03 49 03 49 03 38 03 58 03 48 03 4E 03 54 03 38 03 59 03 35 03 4E 03 33 03 49 03 3A 03 44 03 38 03 4A 03 4C 03 5C 03 4B 03 3D 03 57 03 4A 03 4E 03 42 03 3B 03 3E 03 42 72 B0
15:50:49.049 dir=RX prefix=reb: len=210 hex=72 65 62 3A 20 04 00 64 07 45 07 12 06 A3 05 BE 05 E5 05 DE 05 5A 05 AC 05 A3 04 E8 04 2D 03 C5 03 6E 03 51 03 4C 03 4E 03 58 03 72 03 59 03 5B 03 3E 03 4D 03 60 03 53 03 43 03 47 03 2C 03 3F 03 3A 03 58 03 63 03 40 03 3C 03 50 03 43 03 59 03 49 03 53 03 57 03 39 03 50 03 43 03 62 03 52 03 3C 03 46 03 32 03 51 03 40 03 43 03 4E 03 3A 03 4E 03 2C 03 52 03 38 03 4B 03 49 03 48 03 4E 03 50 03 38 03 43 03 57 03 43 03 4A 03 2D 03 44 03 52 03 56 03 44 03 53 03 35 03 35 03 32 03 65 03 37 03 4B 03 41 03 3B 03 4C 03 43 03 34 03 46 03 45 03 45 03 39 03 3F 03 49 03 47 03 40 03 63 03 45 03 53 03 38 03 3C 03 4F 03 4B 03 46 03 38 16 B8
15:50:49.080 dir=RX prefix=reb: len=210 hex=72 65 62 3A 20 05 00 64 07 95 06 6E 06 D8 06 51 05 FF 05 E9 05 73 05 8A 05 5E 04 AD 04 5A 03 9F 03 8B 03 68 03 CC 03 60 03 50 03 51 03 66 03 5A 03 4B 03 53 03 4B 03 4E 03 4B 03 42 03 4E 03 4C 03 61 03 4E 03 54 03 5A 03 62 03 56 03 4F 03 4C 03 58 03 4F 03 58 03 41 03 43 03 4F 03 30 03 57 03 60 03 39 03 3C 03 5B 03 5F 03 4F 03 57 03 44 03 49 03 40 03 42 03 4D 03 55 03 49 03 52 03 5F 03 50 03 3C 03 48 03 56 03 61 03 4E 03 59 03 49 03 5C 03 45 03 4B 03 49 03 3E 03 7F 03 56 03 52 03 44 03 60 03 51 03 45 03 63 03 50 03 43 03 56 03 57 03 59 03 56 03 63 03 46 03 47 03 4A 03 4A 03 5C 03 53 03 54 03 4A 03 55 03 4A 03 52 03 45 EC 5F
15:50:49.108 dir=RX prefix=raa: len=8 hex=72 61 61 3A 00 00 43 5E
15:50:49.201 dir=RX prefix=rim: len=188 hex=72 69 6D 3A 00 0F 00 3A 00 1E 10 22 FF F9 00 00 00 05 00 3F 00 1C 10 20 FF F9 00 00 00 05 00 40 00 1B 10 1F FF FA 00 01 00 05 00 3E 00 1E 10 1F FF FA 00 00 00 05 00 41 00 1D 10 20 FF FA 00 00 00 04 00 3F 00 1E 10 20 FF F9 00 01 00 04 00 3E 00 1E 10 20 FF FA 00 01 00 05 00 3B 00 1C 10 1D FF FA 00 00 00 05 00 3E 00 1B 10 1F FF FA 00 00 00 05 00 3E 00 19 10 1F FF FA 00 00 00 05 00 3D 00 19 10 24 FF F9 00 01 00 05 00 3B 00 1B 10 21 FF FA 00 00 00 05 00 3A 00 1C 10 22 FF FA 00 01 00 04 00 3D 00 1C 10 20 FF FA 00 01 00 05 00 41 00 1C 10 1C FF FA 00 01 00 05 6C F9
# stopped 15:50:50.871 — 82 packets
+12
View File
@@ -0,0 +1,12 @@
# RawBleLogger session — started 16:14:00.349
# Format: HH:mm:ss.SSS dir=RX prefix=XXX len=N hex=AA BB ...
16:14:01.077 dir=RX prefix=rfv: len=18 hex=72 66 76 3A 56 42 54 46 57 30 31 32 30 00 00 00 7A 73
16:14:09.373 dir=RX prefix=reb: len=210 hex=72 65 62 3A 09 00 00 64 04 66 04 69 04 74 04 5C 04 5A 04 4D 03 B4 03 56 03 4D 03 59 03 5B 03 4C 03 57 03 42 03 59 03 48 03 54 03 44 03 36 03 2D 03 3F 03 3C 03 3F 03 39 03 4D 03 3A 03 43 03 40 03 3F 03 39 03 4B 03 3D 03 50 03 46 03 40 03 3A 03 55 03 39 03 40 03 33 03 35 03 3C 03 4D 03 4C 03 44 03 2D 03 40 03 39 03 44 03 49 03 3E 03 61 03 40 03 3D 03 56 03 35 03 42 03 43 03 41 03 3E 03 2F 03 45 03 42 03 52 03 54 03 4B 03 26 03 3E 03 65 03 32 03 51 03 52 03 42 03 2E 03 47 03 37 03 3F 03 3A 03 53 03 4C 03 25 03 3D 03 33 03 44 03 56 03 3C 03 4E 03 53 03 43 03 5C 03 37 03 42 03 51 03 45 03 53 03 51 03 5A 03 4A 03 43 03 2B FE 90
16:14:09.406 dir=RX prefix=reb: len=210 hex=72 65 62 3A 09 01 00 64 04 6F 04 84 04 92 04 72 04 62 04 78 03 D1 03 62 03 36 03 4A 03 54 03 42 03 39 03 47 03 50 03 43 03 31 03 2C 03 35 03 41 03 42 03 3C 03 3D 03 46 03 33 03 44 03 43 03 42 03 43 03 58 03 5B 03 41 03 32 03 5D 03 41 03 35 03 2B 03 50 03 2E 03 3D 03 59 03 3A 03 38 03 35 03 5B 03 47 03 37 03 3D 03 40 03 2E 03 3E 03 35 03 45 03 4C 03 43 03 4D 03 51 03 49 03 48 03 34 03 4A 03 28 03 50 03 43 03 39 03 3F 03 42 03 47 03 43 03 45 03 28 03 45 03 66 03 49 03 44 03 3A 03 35 03 58 03 48 03 4A 03 57 03 68 03 47 03 2F 03 39 03 4E 03 4B 03 3B 03 3A 03 55 03 5C 03 3D 03 3C 03 58 03 30 03 4B 03 51 03 3A 03 43 03 37 2E E0
16:14:09.435 dir=RX prefix=reb: len=210 hex=72 65 62 3A 09 02 00 64 04 6A 04 66 04 7F 04 74 04 64 04 72 03 D2 03 68 03 5D 03 56 03 4F 03 43 03 31 03 28 03 3D 03 40 03 3E 03 3A 03 38 03 3A 03 43 03 38 03 3E 03 51 03 51 03 2A 03 35 03 4D 03 54 03 59 03 43 03 45 03 4E 03 31 03 20 03 59 03 50 03 2F 03 49 03 4D 03 3C 03 43 03 45 03 2B 03 46 03 4F 03 3D 03 39 03 3D 03 34 03 39 03 46 03 53 03 3A 03 3A 03 40 03 36 03 42 03 41 03 32 03 46 03 34 03 42 03 3B 03 3C 03 45 03 2B 03 52 03 2F 03 4D 03 3A 03 36 03 40 03 46 03 42 03 36 03 3C 03 55 03 4F 03 4C 03 57 03 50 03 40 03 36 03 39 03 59 03 3A 03 39 03 3A 03 36 03 3D 03 49 03 3E 03 3C 03 2F 03 56 03 37 03 3D 03 4D 03 4D 9A AE
16:14:09.470 dir=RX prefix=reb: len=210 hex=72 65 62 3A 09 03 00 64 04 51 04 5D 04 6A 04 5F 04 47 04 55 03 C4 03 50 03 66 03 5C 03 3F 03 32 03 5E 03 3B 03 40 03 47 03 44 03 4A 03 34 03 30 03 45 03 49 03 42 03 44 03 49 03 4B 03 55 03 4D 03 4E 03 4B 03 41 03 39 03 55 03 48 03 55 03 3D 03 51 03 4C 03 41 03 3B 03 3D 03 37 03 41 03 4E 03 4D 03 51 03 41 03 44 03 3B 03 45 03 5F 03 52 03 43 03 40 03 41 03 3F 03 4C 03 3B 03 35 03 40 03 40 03 3C 03 49 03 3B 03 3D 03 4D 03 3D 03 48 03 2D 03 55 03 4C 03 42 03 43 03 3A 03 52 03 3A 03 42 03 48 03 5B 03 47 03 51 03 4C 03 35 03 47 03 4C 03 5F 03 52 03 3D 03 54 03 43 03 48 03 3D 03 41 03 40 03 40 03 55 03 40 03 3D 03 3E 03 3B 26 EF
16:14:09.494 dir=RX prefix=reb: len=210 hex=72 65 62 3A 09 04 00 64 04 80 04 72 04 91 04 82 04 55 04 6D 03 C8 03 37 03 47 03 48 03 3B 03 3C 03 3F 03 3E 03 49 03 53 03 46 03 37 03 4F 03 35 03 39 03 4F 03 4A 03 3F 03 5B 03 21 03 46 03 3D 03 34 03 4A 03 62 03 45 03 4C 03 4E 03 25 03 37 03 47 03 3B 03 50 03 35 03 38 03 52 03 41 03 44 03 50 03 4B 03 4A 03 4C 03 42 03 2D 03 40 03 42 03 44 03 35 03 4E 03 58 03 3A 03 2B 03 41 03 38 03 5C 03 47 03 3D 03 41 03 52 03 3D 03 2B 03 4C 03 47 03 42 03 42 03 3F 03 31 03 46 03 56 03 48 03 41 03 41 03 3B 03 38 03 47 03 46 03 40 03 3B 03 5E 03 4A 03 64 03 44 03 6D 03 55 03 47 03 3B 03 53 03 42 03 43 03 36 03 45 03 26 03 3C 03 4D EC C0
16:14:09.523 dir=RX prefix=reb: len=210 hex=72 65 62 3A 09 05 00 64 04 58 04 58 04 61 04 42 04 28 04 3E 03 C7 03 62 03 54 03 4C 03 60 03 41 03 46 03 43 03 50 03 4B 03 47 03 53 03 41 03 4C 03 39 03 37 03 33 03 40 03 23 03 3F 03 51 03 47 03 5C 03 5F 03 4F 03 4C 03 60 03 48 03 4F 03 33 03 36 03 52 03 4F 03 33 03 46 03 4C 03 3E 03 3D 03 43 03 43 03 55 03 42 03 3A 03 50 03 32 03 58 03 46 03 34 03 59 03 49 03 45 03 54 03 4E 03 4F 03 47 03 3C 03 4F 03 49 03 4D 03 42 03 33 03 40 03 50 03 50 03 5D 03 61 03 4F 03 49 03 3F 03 42 03 49 03 41 03 3C 03 4A 03 3A 03 3C 03 4A 03 37 03 58 03 48 03 50 03 4E 03 49 03 45 03 4B 03 54 03 53 03 50 03 37 03 46 03 46 03 3F 03 42 03 40 B9 36
16:14:09.552 dir=RX prefix=raa: len=8 hex=72 61 61 3A 00 00 43 5E
16:14:09.571 dir=RX prefix=rim: len=152 hex=72 69 6D 3A 00 0C 0B DD E5 84 FD 33 01 5F EF F5 16 2A 09 76 E4 17 FE A4 01 07 DB 86 15 DF 09 F2 DC FC FB 45 00 1D A5 1C 15 AA 0C 42 DE 51 FD AE 03 93 C2 9A 14 50 09 AD DD E2 FD 94 FD E2 F8 05 09 BC 08 A9 E0 92 FA CB F7 0E 06 5F 05 72 07 F6 E2 54 FB 6F EF BB 0E B7 02 ED 07 6A E2 4D FA 77 EE 74 06 5C 00 8D 06 93 E1 0F FA 36 F0 8D 05 73 00 15 07 3D E0 01 FB EC EB 3B 02 1D FC 79 0A 25 E0 80 F7 6B EF 53 08 98 03 67 09 1F E0 D5 F7 C5 03 D0 16 E0 0F B0 C0 1F
# stopped 16:14:16.363 — 9 packets
+159
View File
@@ -0,0 +1,159 @@
timestamp_ms,type,posture,isWalking,pitch,wmean,wstd,accMag,gyroMag,alarm_event,annotation
1782277825446,CYCLE,NON_LYING,false,32.55,13.61,3.77,1.002,13.42,,
1782277826416,CYCLE,NON_LYING,false,31.36,10.09,4.73,1.010,5.00,,
1782277827574,CYCLE,NON_LYING,false,29.45,6.65,2.56,1.005,5.30,,
1782277828431,CYCLE,NON_LYING,false,30.85,5.93,3.38,1.009,2.39,,
1782277829513,CYCLE,NON_LYING,false,32.39,4.70,3.73,1.006,1.65,,
1782277830563,CYCLE,NON_LYING,false,33.15,3.27,1.98,1.002,1.64,,
1782277831494,CYCLE,NON_LYING,false,33.59,2.94,1.84,1.003,0.54,,
1782277832542,CYCLE,NON_LYING,false,33.60,3.73,2.52,1.007,1.90,,
1782277833546,CYCLE,NON_LYING,false,33.58,5.48,3.40,1.005,0.50,,
1782277834582,CYCLE,NON_LYING,false,34.57,6.55,3.80,1.000,0.72,,
1782277835570,CYCLE,NON_LYING,false,34.15,6.48,3.66,1.001,0.71,,
1782277836591,CYCLE,NON_LYING,false,35.46,7.42,4.28,1.006,8.20,,
1782277837812,CYCLE,NON_LYING,false,40.61,4.88,5.08,1.006,0.55,,
1782277838837,CYCLE,NON_LYING,false,40.37,1.57,0.90,1.004,1.59,,
1782277840001,CYCLE,NON_LYING,false,42.08,1.46,0.88,1.004,0.67,,
1782277841024,CYCLE,NON_LYING,false,44.47,3.93,3.48,1.004,6.77,,
1782277842013,CYCLE,NON_LYING,false,44.88,3.75,3.65,1.004,0.60,,
1782277843048,CYCLE,NON_LYING,false,44.76,0.63,0.31,1.004,0.44,,
1782277844023,CYCLE,NON_LYING,false,44.95,0.62,0.17,1.004,0.54,,
1782277845028,CYCLE,NON_LYING,false,45.93,0.72,0.21,1.003,0.57,,
1782277846087,CYCLE,NON_LYING,false,45.35,0.75,0.21,1.004,0.68,,
1782277847089,CYCLE,NON_LYING,false,43.82,4.29,3.83,1.006,6.71,,
1782277848111,CYCLE,NON_LYING,false,37.78,16.02,10.71,1.012,23.58,,
1782277849117,CYCLE,NON_LYING,false,28.12,36.85,16.62,1.025,47.45,,
1782277850147,CYCLE,LYING,false,12.59,47.30,9.73,1.009,41.16,,
1782277851178,CYCLE,LYING,false,6.61,42.74,8.61,1.016,38.80,,
1782277852162,CYCLE,LYING,false,-8.60,28.92,15.05,1.015,6.55,,
1782277852782,ANNOTATION,,,0.00,0.00,0.00,0.000,0.00,,LIE
1782277853210,CYCLE,LYING,false,-6.18,9.38,10.57,1.009,0.67,,
1782277854150,CYCLE,LYING,false,-6.65,1.86,1.09,1.009,2.24,,
1782277855224,CYCLE,LYING,false,-6.17,2.43,0.98,1.008,1.21,,
1782277856238,CYCLE,LYING,false,-9.13,2.23,0.99,1.009,1.46,,
1782277857251,CYCLE,LYING,false,-9.40,1.39,1.03,1.010,0.33,,
1782277858298,CYCLE,LYING,false,-9.02,1.92,1.53,1.007,2.38,,
1782277859300,CYCLE,LYING,false,-10.04,2.17,1.41,1.010,1.07,,
1782277860322,CYCLE,LYING,false,-8.57,2.27,1.94,1.010,2.74,,
1782277861335,CYCLE,LYING,false,-5.22,2.95,1.89,1.010,2.30,,
1782277862350,CYCLE,LYING,false,-6.45,2.22,1.21,1.011,1.01,,
1782277862945,ANNOTATION,,,0.00,0.00,0.00,0.000,0.00,,LIE
1782277863354,CYCLE,LYING,false,-9.22,1.31,0.85,1.010,0.32,,
1782277864386,CYCLE,LYING,false,-5.48,8.30,9.97,1.002,14.78,,
1782277865396,CYCLE,LYING,false,22.86,25.46,13.03,1.013,34.72,,
1782277866406,ALARM,,,0.00,0.00,0.00,0.000,0.00,wakeup_alarm_lying_16s,
1782277866405,CYCLE,NON_LYING,false,69.64,49.64,21.34,0.953,46.81,,
1782277867426,CYCLE,NON_LYING,false,87.73,36.97,21.00,0.997,18.43,,
1782277868467,CYCLE,NON_LYING,false,65.87,23.80,10.06,1.023,11.97,,
1782277869499,CYCLE,NON_LYING,false,79.19,59.12,56.95,0.960,40.02,,
1782277870490,CYCLE,NON_LYING,false,76.81,52.21,61.19,1.001,9.38,,
1782277870893,ANNOTATION,,,0.00,0.00,0.00,0.000,0.00,,STAND
1782277871510,CYCLE,NON_LYING,false,75.82,5.91,4.55,0.996,2.04,,
1782277872550,CYCLE,NON_LYING,false,75.61,2.76,0.66,0.995,3.13,,
1782277873563,CYCLE,NON_LYING,false,76.15,3.72,2.31,0.998,3.31,,
1782277874577,CYCLE,NON_LYING,false,75.25,2.93,2.64,0.997,1.25,,
1782277875576,CYCLE,NON_LYING,false,75.37,1.26,0.73,0.997,0.86,,
1782277876603,CYCLE,NON_LYING,false,75.17,0.90,0.48,0.997,0.51,,
1782277877613,CYCLE,NON_LYING,false,74.91,0.93,0.39,0.997,0.84,,
1782277878639,CYCLE,NON_LYING,false,74.79,0.79,0.36,0.997,0.23,,
1782277879641,CYCLE,NON_LYING,false,74.60,0.62,0.19,0.997,0.57,,
1782277880673,CYCLE,NON_LYING,false,74.45,0.76,0.25,0.997,0.85,,
1782277881685,CYCLE,NON_LYING,false,74.31,0.77,0.35,0.997,0.13,,
1782277882710,CYCLE,NON_LYING,false,74.23,0.61,0.41,0.997,0.49,,
1782277883728,CYCLE,NON_LYING,false,74.17,0.67,0.34,0.997,0.58,,
1782277884754,CYCLE,NON_LYING,false,74.15,0.78,0.20,0.996,0.70,,
1782277885776,CYCLE,NON_LYING,false,73.92,0.78,0.19,0.997,0.69,,
1782277886775,CYCLE,NON_LYING,false,74.25,5.54,5.65,0.996,9.39,,
1782277887801,CYCLE,NON_LYING,false,74.37,6.96,4.64,0.994,2.18,,
1782277888807,CYCLE,NON_LYING,false,74.58,2.53,1.55,0.997,0.90,,
1782277889850,CYCLE,NON_LYING,false,74.47,1.55,0.77,0.992,1.12,,
1782277890831,CYCLE,NON_LYING,false,78.01,4.63,3.19,0.998,7.53,,
1782277891882,CYCLE,NON_LYING,false,66.37,53.32,48.31,1.031,92.97,,
1782277892874,CYCLE,NON_LYING,false,77.70,133.90,39.89,1.037,165.24,,
1782277893910,CYCLE,NON_LYING,false,69.35,121.11,54.35,1.108,49.86,,
1782277894919,CYCLE,NON_LYING,false,64.59,92.44,40.73,1.062,96.59,,
1782277895929,CYCLE,NON_LYING,false,68.48,85.01,40.62,1.044,47.66,,
1782277896934,ALARM,,,0.00,0.00,0.00,0.000,0.00,walking_start,
1782277896934,CYCLE,WALKING,true,71.55,66.19,27.17,1.076,46.45,,
1782277898081,CYCLE,WALKING,true,77.38,70.97,31.36,0.863,55.78,,
1782277899069,CYCLE,WALKING,true,77.21,88.48,33.97,0.861,105.41,,
1782277900069,CYCLE,WALKING,true,74.37,95.63,29.19,0.915,70.24,,
1782277901074,CYCLE,WALKING,true,77.86,68.83,31.65,0.876,23.57,,
1782277902111,CYCLE,WALKING,true,80.44,79.48,34.06,0.948,87.94,,
1782277903114,CYCLE,WALKING,true,77.72,89.16,25.29,0.982,54.11,,
1782277904122,CYCLE,WALKING,true,72.62,59.70,25.54,1.070,23.00,,
1782277905142,CYCLE,WALKING,true,78.30,50.33,20.62,1.080,30.10,,
1782277906155,CYCLE,WALKING,true,74.44,52.98,19.24,1.109,32.59,,
1782277907167,CYCLE,WALKING,true,69.39,42.43,16.67,0.966,19.71,,
1782277907184,ANNOTATION,,,0.00,0.00,0.00,0.000,0.00,,WALK↑
1782277908202,CYCLE,WALKING,true,66.67,45.57,26.23,0.897,23.26,,
1782277909207,CYCLE,WALKING,true,73.22,52.03,32.56,1.016,32.64,,
1782277910257,CYCLE,WALKING,true,73.78,81.91,48.01,1.043,114.00,,
1782277911235,CYCLE,WALKING,true,66.64,109.12,30.79,0.994,100.06,,
1782277912250,CYCLE,WALKING,true,80.63,69.93,40.26,1.112,13.62,,
1782277913276,CYCLE,WALKING,true,78.98,42.48,24.09,0.986,18.77,,
1782277914205,CYCLE,WALKING,true,79.00,50.81,24.89,0.883,36.06,,
1782277915309,CYCLE,WALKING,true,76.95,69.73,32.89,0.902,74.90,,
1782277916327,CYCLE,WALKING,true,72.27,73.62,28.13,1.018,49.76,,
1782277917370,CYCLE,WALKING,true,74.03,54.25,19.15,1.079,29.05,,
1782277918381,CYCLE,WALKING,true,69.22,39.39,18.99,1.072,18.84,,
1782277919378,CYCLE,WALKING,true,68.92,36.14,18.40,0.986,23.28,,
1782277920367,ANNOTATION,,,0.00,0.00,0.00,0.000,0.00,,WALK↓
1782277920413,CYCLE,WALKING,true,78.25,25.22,19.70,0.992,6.82,,
1782277921409,CYCLE,WALKING,true,77.53,6.97,5.57,0.997,3.08,,
1782277922430,CYCLE,WALKING,true,77.50,2.73,0.84,0.997,1.99,,
1782277923446,CYCLE,WALKING,true,78.03,3.00,1.35,0.998,3.73,,
1782277924479,CYCLE,WALKING,true,76.34,37.12,34.08,0.985,68.97,,
1782277925509,CYCLE,WALKING,true,68.15,68.12,9.24,1.023,64.64,,
1782277926499,CYCLE,WALKING,true,71.43,53.93,21.19,0.954,37.85,,
1782277927525,CYCLE,WALKING,true,81.69,47.74,20.07,1.003,49.60,,
1782277928523,CYCLE,WALKING,true,64.73,74.40,35.37,1.045,85.60,,
1782277929563,CYCLE,WALKING,true,11.98,103.50,43.68,1.051,111.16,,
1782277930566,ALARM,,,0.00,0.00,0.00,0.000,0.00,walking_end,
1782277930566,CYCLE,LYING,false,-4.17,60.56,61.09,1.008,9.19,,
1782277931585,CYCLE,LYING,false,-6.04,6.32,3.66,1.008,3.02,,
1782277932470,ANNOTATION,,,0.00,0.00,0.00,0.000,0.00,,SIT
1782277932613,CYCLE,LYING,false,-7.22,2.37,1.31,1.011,1.13,,
1782277933627,CYCLE,LYING,false,-5.08,14.51,20.54,1.173,26.26,,
1782277934635,CYCLE,NON_LYING,false,85.02,54.38,20.27,1.044,36.69,,
1782277935668,CYCLE,NON_LYING,false,80.83,56.34,22.86,0.922,43.36,,
1782277936683,CYCLE,NON_LYING,false,77.04,66.94,24.26,0.925,53.71,,
1782277937722,CYCLE,NON_LYING,false,75.87,77.19,19.20,0.860,47.96,,
1782277938731,CYCLE,NON_LYING,false,76.17,78.95,25.12,0.892,67.98,,
1782277939766,CYCLE,NON_LYING,false,85.96,69.91,32.43,0.906,42.55,,
1782277940770,ALARM,,,0.00,0.00,0.00,0.000,0.00,walking_start,
1782277940770,CYCLE,WALKING,true,82.39,72.64,37.39,0.958,61.39,,
1782277941774,CYCLE,WALKING,true,77.03,79.54,39.02,0.900,57.75,,
1782277942791,CYCLE,WALKING,true,74.52,67.80,29.18,0.922,52.14,,
1782277943802,CYCLE,WALKING,true,52.05,55.44,22.96,1.024,26.38,,
1782277944829,CYCLE,WALKING,true,65.04,26.10,31.51,0.996,2.02,,
1782277945849,CYCLE,WALKING,true,64.65,2.01,0.82,0.995,0.78,,
1782277946864,CYCLE,WALKING,true,65.75,6.45,6.24,0.999,9.43,,
1782277947853,CYCLE,WALKING,true,63.36,17.13,8.26,0.977,21.78,,
1782277948917,CYCLE,WALKING,true,51.36,17.35,7.42,0.994,11.17,,
1782277949909,CYCLE,WALKING,true,47.69,23.58,12.95,0.971,31.78,,
1782277950939,CYCLE,WALKING,true,76.51,88.18,71.08,0.863,135.74,,
1782277951975,CYCLE,WALKING,true,46.67,85.57,73.05,1.009,26.40,,
1782277952971,CYCLE,WALKING,true,54.28,27.73,6.55,1.010,22.45,,
1782277954044,CYCLE,WALKING,true,53.25,20.44,7.75,1.001,14.99,,
1782277955003,CYCLE,WALKING,true,52.17,14.09,5.95,1.005,12.26,,
1782277956065,CYCLE,WALKING,true,54.74,7.20,6.19,1.003,1.79,,
1782277957073,CYCLE,WALKING,true,54.59,1.20,0.71,1.004,0.47,,
1782277958099,ALARM,,,0.00,0.00,0.00,0.000,0.00,walking_end,
1782277958099,CYCLE,NON_LYING,false,54.32,0.87,0.44,1.003,0.95,,
1782277959111,CYCLE,NON_LYING,false,54.26,0.97,0.32,1.002,0.68,,
1782277960167,CYCLE,NON_LYING,false,54.25,0.95,0.23,1.002,1.09,,
1782277961216,CYCLE,NON_LYING,false,54.14,0.81,0.38,1.003,0.35,,
1782277962206,CYCLE,NON_LYING,false,54.22,0.54,0.24,1.003,0.54,,
1782277963205,CYCLE,NON_LYING,false,54.17,0.64,0.17,1.003,0.66,,
1782277964209,CYCLE,NON_LYING,false,54.08,0.65,0.16,1.003,0.54,,
1782277965258,CYCLE,NON_LYING,false,54.71,2.55,2.07,1.002,4.32,,
1782277966256,CYCLE,NON_LYING,false,55.67,3.15,1.60,1.003,1.71,,
1782277967319,CYCLE,NON_LYING,false,57.39,8.73,10.62,1.020,13.60,,
1782277968325,CYCLE,NON_LYING,false,54.33,12.20,9.64,0.994,5.53,,
1782277969346,CYCLE,NON_LYING,false,56.86,9.98,4.80,0.991,6.85,,
1782277970365,CYCLE,NON_LYING,false,57.87,11.24,3.46,0.971,3.32,,
1782277971387,CYCLE,NON_LYING,false,57.40,12.16,5.15,0.965,2.34,,
1782277972400,CYCLE,NON_LYING,false,57.48,13.40,6.27,0.993,4.11,,
1782277973426,ALARM,,,0.00,0.00,0.00,0.000,0.00,walking_start,
1782277973426,CYCLE,WALKING,true,58.11,13.65,6.14,1.027,2.76,,
1 timestamp_ms type posture isWalking pitch wmean wstd accMag gyroMag alarm_event annotation
2 1782277825446 CYCLE NON_LYING false 32.55 13.61 3.77 1.002 13.42
3 1782277826416 CYCLE NON_LYING false 31.36 10.09 4.73 1.010 5.00
4 1782277827574 CYCLE NON_LYING false 29.45 6.65 2.56 1.005 5.30
5 1782277828431 CYCLE NON_LYING false 30.85 5.93 3.38 1.009 2.39
6 1782277829513 CYCLE NON_LYING false 32.39 4.70 3.73 1.006 1.65
7 1782277830563 CYCLE NON_LYING false 33.15 3.27 1.98 1.002 1.64
8 1782277831494 CYCLE NON_LYING false 33.59 2.94 1.84 1.003 0.54
9 1782277832542 CYCLE NON_LYING false 33.60 3.73 2.52 1.007 1.90
10 1782277833546 CYCLE NON_LYING false 33.58 5.48 3.40 1.005 0.50
11 1782277834582 CYCLE NON_LYING false 34.57 6.55 3.80 1.000 0.72
12 1782277835570 CYCLE NON_LYING false 34.15 6.48 3.66 1.001 0.71
13 1782277836591 CYCLE NON_LYING false 35.46 7.42 4.28 1.006 8.20
14 1782277837812 CYCLE NON_LYING false 40.61 4.88 5.08 1.006 0.55
15 1782277838837 CYCLE NON_LYING false 40.37 1.57 0.90 1.004 1.59
16 1782277840001 CYCLE NON_LYING false 42.08 1.46 0.88 1.004 0.67
17 1782277841024 CYCLE NON_LYING false 44.47 3.93 3.48 1.004 6.77
18 1782277842013 CYCLE NON_LYING false 44.88 3.75 3.65 1.004 0.60
19 1782277843048 CYCLE NON_LYING false 44.76 0.63 0.31 1.004 0.44
20 1782277844023 CYCLE NON_LYING false 44.95 0.62 0.17 1.004 0.54
21 1782277845028 CYCLE NON_LYING false 45.93 0.72 0.21 1.003 0.57
22 1782277846087 CYCLE NON_LYING false 45.35 0.75 0.21 1.004 0.68
23 1782277847089 CYCLE NON_LYING false 43.82 4.29 3.83 1.006 6.71
24 1782277848111 CYCLE NON_LYING false 37.78 16.02 10.71 1.012 23.58
25 1782277849117 CYCLE NON_LYING false 28.12 36.85 16.62 1.025 47.45
26 1782277850147 CYCLE LYING false 12.59 47.30 9.73 1.009 41.16
27 1782277851178 CYCLE LYING false 6.61 42.74 8.61 1.016 38.80
28 1782277852162 CYCLE LYING false -8.60 28.92 15.05 1.015 6.55
29 1782277852782 ANNOTATION 0.00 0.00 0.00 0.000 0.00 LIE
30 1782277853210 CYCLE LYING false -6.18 9.38 10.57 1.009 0.67
31 1782277854150 CYCLE LYING false -6.65 1.86 1.09 1.009 2.24
32 1782277855224 CYCLE LYING false -6.17 2.43 0.98 1.008 1.21
33 1782277856238 CYCLE LYING false -9.13 2.23 0.99 1.009 1.46
34 1782277857251 CYCLE LYING false -9.40 1.39 1.03 1.010 0.33
35 1782277858298 CYCLE LYING false -9.02 1.92 1.53 1.007 2.38
36 1782277859300 CYCLE LYING false -10.04 2.17 1.41 1.010 1.07
37 1782277860322 CYCLE LYING false -8.57 2.27 1.94 1.010 2.74
38 1782277861335 CYCLE LYING false -5.22 2.95 1.89 1.010 2.30
39 1782277862350 CYCLE LYING false -6.45 2.22 1.21 1.011 1.01
40 1782277862945 ANNOTATION 0.00 0.00 0.00 0.000 0.00 LIE
41 1782277863354 CYCLE LYING false -9.22 1.31 0.85 1.010 0.32
42 1782277864386 CYCLE LYING false -5.48 8.30 9.97 1.002 14.78
43 1782277865396 CYCLE LYING false 22.86 25.46 13.03 1.013 34.72
44 1782277866406 ALARM 0.00 0.00 0.00 0.000 0.00 wakeup_alarm_lying_16s
45 1782277866405 CYCLE NON_LYING false 69.64 49.64 21.34 0.953 46.81
46 1782277867426 CYCLE NON_LYING false 87.73 36.97 21.00 0.997 18.43
47 1782277868467 CYCLE NON_LYING false 65.87 23.80 10.06 1.023 11.97
48 1782277869499 CYCLE NON_LYING false 79.19 59.12 56.95 0.960 40.02
49 1782277870490 CYCLE NON_LYING false 76.81 52.21 61.19 1.001 9.38
50 1782277870893 ANNOTATION 0.00 0.00 0.00 0.000 0.00 STAND
51 1782277871510 CYCLE NON_LYING false 75.82 5.91 4.55 0.996 2.04
52 1782277872550 CYCLE NON_LYING false 75.61 2.76 0.66 0.995 3.13
53 1782277873563 CYCLE NON_LYING false 76.15 3.72 2.31 0.998 3.31
54 1782277874577 CYCLE NON_LYING false 75.25 2.93 2.64 0.997 1.25
55 1782277875576 CYCLE NON_LYING false 75.37 1.26 0.73 0.997 0.86
56 1782277876603 CYCLE NON_LYING false 75.17 0.90 0.48 0.997 0.51
57 1782277877613 CYCLE NON_LYING false 74.91 0.93 0.39 0.997 0.84
58 1782277878639 CYCLE NON_LYING false 74.79 0.79 0.36 0.997 0.23
59 1782277879641 CYCLE NON_LYING false 74.60 0.62 0.19 0.997 0.57
60 1782277880673 CYCLE NON_LYING false 74.45 0.76 0.25 0.997 0.85
61 1782277881685 CYCLE NON_LYING false 74.31 0.77 0.35 0.997 0.13
62 1782277882710 CYCLE NON_LYING false 74.23 0.61 0.41 0.997 0.49
63 1782277883728 CYCLE NON_LYING false 74.17 0.67 0.34 0.997 0.58
64 1782277884754 CYCLE NON_LYING false 74.15 0.78 0.20 0.996 0.70
65 1782277885776 CYCLE NON_LYING false 73.92 0.78 0.19 0.997 0.69
66 1782277886775 CYCLE NON_LYING false 74.25 5.54 5.65 0.996 9.39
67 1782277887801 CYCLE NON_LYING false 74.37 6.96 4.64 0.994 2.18
68 1782277888807 CYCLE NON_LYING false 74.58 2.53 1.55 0.997 0.90
69 1782277889850 CYCLE NON_LYING false 74.47 1.55 0.77 0.992 1.12
70 1782277890831 CYCLE NON_LYING false 78.01 4.63 3.19 0.998 7.53
71 1782277891882 CYCLE NON_LYING false 66.37 53.32 48.31 1.031 92.97
72 1782277892874 CYCLE NON_LYING false 77.70 133.90 39.89 1.037 165.24
73 1782277893910 CYCLE NON_LYING false 69.35 121.11 54.35 1.108 49.86
74 1782277894919 CYCLE NON_LYING false 64.59 92.44 40.73 1.062 96.59
75 1782277895929 CYCLE NON_LYING false 68.48 85.01 40.62 1.044 47.66
76 1782277896934 ALARM 0.00 0.00 0.00 0.000 0.00 walking_start
77 1782277896934 CYCLE WALKING true 71.55 66.19 27.17 1.076 46.45
78 1782277898081 CYCLE WALKING true 77.38 70.97 31.36 0.863 55.78
79 1782277899069 CYCLE WALKING true 77.21 88.48 33.97 0.861 105.41
80 1782277900069 CYCLE WALKING true 74.37 95.63 29.19 0.915 70.24
81 1782277901074 CYCLE WALKING true 77.86 68.83 31.65 0.876 23.57
82 1782277902111 CYCLE WALKING true 80.44 79.48 34.06 0.948 87.94
83 1782277903114 CYCLE WALKING true 77.72 89.16 25.29 0.982 54.11
84 1782277904122 CYCLE WALKING true 72.62 59.70 25.54 1.070 23.00
85 1782277905142 CYCLE WALKING true 78.30 50.33 20.62 1.080 30.10
86 1782277906155 CYCLE WALKING true 74.44 52.98 19.24 1.109 32.59
87 1782277907167 CYCLE WALKING true 69.39 42.43 16.67 0.966 19.71
88 1782277907184 ANNOTATION 0.00 0.00 0.00 0.000 0.00 WALK↑
89 1782277908202 CYCLE WALKING true 66.67 45.57 26.23 0.897 23.26
90 1782277909207 CYCLE WALKING true 73.22 52.03 32.56 1.016 32.64
91 1782277910257 CYCLE WALKING true 73.78 81.91 48.01 1.043 114.00
92 1782277911235 CYCLE WALKING true 66.64 109.12 30.79 0.994 100.06
93 1782277912250 CYCLE WALKING true 80.63 69.93 40.26 1.112 13.62
94 1782277913276 CYCLE WALKING true 78.98 42.48 24.09 0.986 18.77
95 1782277914205 CYCLE WALKING true 79.00 50.81 24.89 0.883 36.06
96 1782277915309 CYCLE WALKING true 76.95 69.73 32.89 0.902 74.90
97 1782277916327 CYCLE WALKING true 72.27 73.62 28.13 1.018 49.76
98 1782277917370 CYCLE WALKING true 74.03 54.25 19.15 1.079 29.05
99 1782277918381 CYCLE WALKING true 69.22 39.39 18.99 1.072 18.84
100 1782277919378 CYCLE WALKING true 68.92 36.14 18.40 0.986 23.28
101 1782277920367 ANNOTATION 0.00 0.00 0.00 0.000 0.00 WALK↓
102 1782277920413 CYCLE WALKING true 78.25 25.22 19.70 0.992 6.82
103 1782277921409 CYCLE WALKING true 77.53 6.97 5.57 0.997 3.08
104 1782277922430 CYCLE WALKING true 77.50 2.73 0.84 0.997 1.99
105 1782277923446 CYCLE WALKING true 78.03 3.00 1.35 0.998 3.73
106 1782277924479 CYCLE WALKING true 76.34 37.12 34.08 0.985 68.97
107 1782277925509 CYCLE WALKING true 68.15 68.12 9.24 1.023 64.64
108 1782277926499 CYCLE WALKING true 71.43 53.93 21.19 0.954 37.85
109 1782277927525 CYCLE WALKING true 81.69 47.74 20.07 1.003 49.60
110 1782277928523 CYCLE WALKING true 64.73 74.40 35.37 1.045 85.60
111 1782277929563 CYCLE WALKING true 11.98 103.50 43.68 1.051 111.16
112 1782277930566 ALARM 0.00 0.00 0.00 0.000 0.00 walking_end
113 1782277930566 CYCLE LYING false -4.17 60.56 61.09 1.008 9.19
114 1782277931585 CYCLE LYING false -6.04 6.32 3.66 1.008 3.02
115 1782277932470 ANNOTATION 0.00 0.00 0.00 0.000 0.00 SIT
116 1782277932613 CYCLE LYING false -7.22 2.37 1.31 1.011 1.13
117 1782277933627 CYCLE LYING false -5.08 14.51 20.54 1.173 26.26
118 1782277934635 CYCLE NON_LYING false 85.02 54.38 20.27 1.044 36.69
119 1782277935668 CYCLE NON_LYING false 80.83 56.34 22.86 0.922 43.36
120 1782277936683 CYCLE NON_LYING false 77.04 66.94 24.26 0.925 53.71
121 1782277937722 CYCLE NON_LYING false 75.87 77.19 19.20 0.860 47.96
122 1782277938731 CYCLE NON_LYING false 76.17 78.95 25.12 0.892 67.98
123 1782277939766 CYCLE NON_LYING false 85.96 69.91 32.43 0.906 42.55
124 1782277940770 ALARM 0.00 0.00 0.00 0.000 0.00 walking_start
125 1782277940770 CYCLE WALKING true 82.39 72.64 37.39 0.958 61.39
126 1782277941774 CYCLE WALKING true 77.03 79.54 39.02 0.900 57.75
127 1782277942791 CYCLE WALKING true 74.52 67.80 29.18 0.922 52.14
128 1782277943802 CYCLE WALKING true 52.05 55.44 22.96 1.024 26.38
129 1782277944829 CYCLE WALKING true 65.04 26.10 31.51 0.996 2.02
130 1782277945849 CYCLE WALKING true 64.65 2.01 0.82 0.995 0.78
131 1782277946864 CYCLE WALKING true 65.75 6.45 6.24 0.999 9.43
132 1782277947853 CYCLE WALKING true 63.36 17.13 8.26 0.977 21.78
133 1782277948917 CYCLE WALKING true 51.36 17.35 7.42 0.994 11.17
134 1782277949909 CYCLE WALKING true 47.69 23.58 12.95 0.971 31.78
135 1782277950939 CYCLE WALKING true 76.51 88.18 71.08 0.863 135.74
136 1782277951975 CYCLE WALKING true 46.67 85.57 73.05 1.009 26.40
137 1782277952971 CYCLE WALKING true 54.28 27.73 6.55 1.010 22.45
138 1782277954044 CYCLE WALKING true 53.25 20.44 7.75 1.001 14.99
139 1782277955003 CYCLE WALKING true 52.17 14.09 5.95 1.005 12.26
140 1782277956065 CYCLE WALKING true 54.74 7.20 6.19 1.003 1.79
141 1782277957073 CYCLE WALKING true 54.59 1.20 0.71 1.004 0.47
142 1782277958099 ALARM 0.00 0.00 0.00 0.000 0.00 walking_end
143 1782277958099 CYCLE NON_LYING false 54.32 0.87 0.44 1.003 0.95
144 1782277959111 CYCLE NON_LYING false 54.26 0.97 0.32 1.002 0.68
145 1782277960167 CYCLE NON_LYING false 54.25 0.95 0.23 1.002 1.09
146 1782277961216 CYCLE NON_LYING false 54.14 0.81 0.38 1.003 0.35
147 1782277962206 CYCLE NON_LYING false 54.22 0.54 0.24 1.003 0.54
148 1782277963205 CYCLE NON_LYING false 54.17 0.64 0.17 1.003 0.66
149 1782277964209 CYCLE NON_LYING false 54.08 0.65 0.16 1.003 0.54
150 1782277965258 CYCLE NON_LYING false 54.71 2.55 2.07 1.002 4.32
151 1782277966256 CYCLE NON_LYING false 55.67 3.15 1.60 1.003 1.71
152 1782277967319 CYCLE NON_LYING false 57.39 8.73 10.62 1.020 13.60
153 1782277968325 CYCLE NON_LYING false 54.33 12.20 9.64 0.994 5.53
154 1782277969346 CYCLE NON_LYING false 56.86 9.98 4.80 0.991 6.85
155 1782277970365 CYCLE NON_LYING false 57.87 11.24 3.46 0.971 3.32
156 1782277971387 CYCLE NON_LYING false 57.40 12.16 5.15 0.965 2.34
157 1782277972400 CYCLE NON_LYING false 57.48 13.40 6.27 0.993 4.11
158 1782277973426 ALARM 0.00 0.00 0.00 0.000 0.00 walking_start
159 1782277973426 CYCLE WALKING true 58.11 13.65 6.14 1.027 2.76
Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

+2 -2
View File
@@ -5,13 +5,13 @@ plugins {
} }
android { android {
namespace = "com.example.medilightv2android" namespace = "com.medithings.vesiscan"
compileSdk { compileSdk {
version = release(36) version = release(36)
} }
defaultConfig { defaultConfig {
applicationId = "com.example.medilightv2android" applicationId = "com.medithings.vesiscan"
minSdk = 24 minSdk = 24
targetSdk = 36 targetSdk = 36
versionCode = 27 versionCode = 27
@@ -1,4 +1,4 @@
package com.example.medilightv2android package com.medithings.vesiscan
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -19,6 +19,6 @@ class ExampleInstrumentedTest {
fun useAppContext() { fun useAppContext() {
// Context of the app under test. // Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.medilightv2android", appContext.packageName) assertEquals("com.medithings.vesiscan", appContext.packageName)
} }
} }
@@ -1,14 +1,14 @@
package com.example.medilightv2android package com.medithings.vesiscan
import android.content.Context import android.content.Context
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
import com.example.medilightv2android.managers.NirsManager import com.medithings.vesiscan.managers.NirsManager
import com.example.medilightv2android.models.* import com.medithings.vesiscan.models.*
import com.example.medilightv2android.services.* import com.medithings.vesiscan.services.*
enum class AppScreen { enum class AppScreen {
ONBOARDING, CONSENT, REGISTRATION, HOME, SENSOR_SELECT, DEVICE_SCAN, ONBOARDING, CONSENT, REGISTRATION, HOME, SENSOR_SELECT, DEVICE_SCAN,
@@ -121,7 +121,7 @@ class AppState(private val context: Context) {
fun deviceConnected() { fun deviceConnected() {
isDeviceConnected = true isDeviceConnected = true
// 임상 모드에서 BLE 연결 시 ClinicalHome으로 복귀 (Personalization 우회) // 임상 모드에서 BLE 연결 시 ClinicalHome으로 복귀 (Personalization 우회)
if (com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow) { if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow) {
currentScreen = AppScreen.CLINICAL_HOME currentScreen = AppScreen.CLINICAL_HOME
return return
} }
@@ -1,4 +1,4 @@
package com.example.medilightv2android package com.medithings.vesiscan
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
@@ -20,34 +20,34 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import app.rive.runtime.kotlin.core.Rive import app.rive.runtime.kotlin.core.Rive
import com.example.medilightv2android.services.KeychainService import com.medithings.vesiscan.services.KeychainService
import com.example.medilightv2android.services.NotificationService import com.medithings.vesiscan.services.NotificationService
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.ui.theme.Medilightv2androidTheme import com.medithings.vesiscan.ui.theme.Medilightv2androidTheme
import com.example.medilightv2android.ui.views.calibration.CalibrationView import com.medithings.vesiscan.ui.views.calibration.CalibrationView
import com.example.medilightv2android.ui.views.connection.DeviceScanView import com.medithings.vesiscan.ui.views.connection.DeviceScanView
import com.example.medilightv2android.ui.views.history.MeasurementHistoryView import com.medithings.vesiscan.ui.views.history.MeasurementHistoryView
import com.example.medilightv2android.ui.views.home.HomeView import com.medithings.vesiscan.ui.views.home.HomeView
import com.example.medilightv2android.ui.views.monitoring.PlacementGuideView import com.medithings.vesiscan.ui.views.monitoring.PlacementGuideView
import com.example.medilightv2android.ui.views.monitoring.PiezoMonitoringView import com.medithings.vesiscan.ui.views.monitoring.PiezoMonitoringView
import com.example.medilightv2android.ui.views.monitoring.VivamyoMonitoringView import com.medithings.vesiscan.ui.views.monitoring.VivamyoMonitoringView
import com.example.medilightv2android.ui.views.monitoring.UrineCameraScreen import com.medithings.vesiscan.ui.views.monitoring.UrineCameraScreen
import com.example.medilightv2android.ui.views.monitoring.VoidingDiaryView import com.medithings.vesiscan.ui.views.monitoring.VoidingDiaryView
import com.example.medilightv2android.ui.views.onboarding.OnboardingView import com.medithings.vesiscan.ui.views.onboarding.OnboardingView
import com.example.medilightv2android.ui.views.personalization.PiezoPersonalizationView import com.medithings.vesiscan.ui.views.personalization.PiezoPersonalizationView
import com.example.medilightv2android.ui.views.pin.PinMode import com.medithings.vesiscan.ui.views.pin.PinMode
import com.example.medilightv2android.ui.views.pin.PinView import com.medithings.vesiscan.ui.views.pin.PinView
import com.example.medilightv2android.ui.views.registration.RegistrationView import com.medithings.vesiscan.ui.views.registration.RegistrationView
import com.example.medilightv2android.ui.views.consent.ConsentView import com.medithings.vesiscan.ui.views.consent.ConsentView
import com.example.medilightv2android.ui.views.reminder.ReminderSettingsView import com.medithings.vesiscan.ui.views.reminder.ReminderSettingsView
import com.example.medilightv2android.ui.views.sensorselect.SensorSelectView import com.medithings.vesiscan.ui.views.sensorselect.SensorSelectView
import com.example.medilightv2android.ui.views.clinical.ClinicalHomeView import com.medithings.vesiscan.ui.views.clinical.ClinicalHomeView
import com.example.medilightv2android.ui.views.clinical.ClinicalLiveView import com.medithings.vesiscan.ui.views.clinical.ClinicalLiveView
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
/** 사용자가 선택한 앱 언어 적용 — Activity 생성 전에 Locale wrap. */ /** 사용자가 선택한 앱 언어 적용 — Activity 생성 전에 Locale wrap. */
override fun attachBaseContext(newBase: android.content.Context) { override fun attachBaseContext(newBase: android.content.Context) {
super.attachBaseContext(com.example.medilightv2android.services.LocalePref.wrap(newBase)) super.attachBaseContext(com.medithings.vesiscan.services.LocalePref.wrap(newBase))
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -106,28 +106,28 @@ fun MedilightApp(modifier: Modifier = Modifier) {
// DeviceScan Back: 임상 흐름이면 ClinicalHome으로, 아니면 HOME // DeviceScan Back: 임상 흐름이면 ClinicalHome으로, 아니면 HOME
AppScreen.DEVICE_SCAN -> AppScreen.DEVICE_SCAN ->
appState.currentScreen = appState.currentScreen =
if (com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow) if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow)
AppScreen.CLINICAL_HOME AppScreen.CLINICAL_HOME
else AppScreen.HOME else AppScreen.HOME
AppScreen.PIEZO_PERSONALIZATION -> appState.currentScreen = AppScreen.DEVICE_SCAN AppScreen.PIEZO_PERSONALIZATION -> appState.currentScreen = AppScreen.DEVICE_SCAN
// 임상 모드 측정 중이면 endMeasurement → ClinicalHome 복귀 // 임상 모드 측정 중이면 endMeasurement → ClinicalHome 복귀
AppScreen.PLACEMENT_GUIDE -> AppScreen.PLACEMENT_GUIDE ->
if (com.example.medilightv2android.services.ClinicalSessionStore.currentSession != null) { if (com.medithings.vesiscan.services.ClinicalSessionStore.currentSession != null) {
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context) com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context)
appState.currentScreen = AppScreen.CLINICAL_HOME appState.currentScreen = AppScreen.CLINICAL_HOME
} else appState.backFromPlacementGuide() } else appState.backFromPlacementGuide()
AppScreen.PIEZO_MONITORING -> AppScreen.PIEZO_MONITORING ->
if (com.example.medilightv2android.services.ClinicalSessionStore.currentSession != null) { if (com.medithings.vesiscan.services.ClinicalSessionStore.currentSession != null) {
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context) com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context)
appState.currentScreen = AppScreen.CLINICAL_HOME appState.currentScreen = AppScreen.CLINICAL_HOME
} else appState.currentScreen = AppScreen.PLACEMENT_GUIDE } else appState.currentScreen = AppScreen.PLACEMENT_GUIDE
AppScreen.CLINICAL_HOME -> { AppScreen.CLINICAL_HOME -> {
com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = false com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow = false
appState.currentScreen = AppScreen.HOME appState.currentScreen = AppScreen.HOME
} }
AppScreen.CLINICAL_LIVE -> { AppScreen.CLINICAL_LIVE -> {
// 측정 폴더 finalize 후 ClinicalHome 복귀 // 측정 폴더 finalize 후 ClinicalHome 복귀
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context) com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context)
appState.currentScreen = AppScreen.CLINICAL_HOME appState.currentScreen = AppScreen.CLINICAL_HOME
} }
// 모니터링 하위 화면 → 모니터링 // 모니터링 하위 화면 → 모니터링
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ble package com.medithings.vesiscan.ble
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.bluetooth.* import android.bluetooth.*
@@ -8,7 +8,7 @@ import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Log import android.util.Log
import com.example.medilightv2android.BuildConfig import com.medithings.vesiscan.BuildConfig
import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import java.util.UUID import java.util.UUID
@@ -57,7 +57,7 @@ class BleManager private constructor(private val context: Context) {
@Volatile private var txCharacteristic: BluetoothGattCharacteristic? = null @Volatile private var txCharacteristic: BluetoothGattCharacteristic? = null
@Volatile private var rxCharacteristic: BluetoothGattCharacteristic? = null @Volatile private var rxCharacteristic: BluetoothGattCharacteristic? = null
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
val debugLogger = com.example.medilightv2android.services.BleDebugLogger.getInstance(context) val debugLogger = com.medithings.vesiscan.services.BleDebugLogger.getInstance(context)
private var scanTimer: Runnable? = null private var scanTimer: Runnable? = null
private var batteryTimer: Runnable? = null private var batteryTimer: Runnable? = null
private var batteryRetryTimer: Runnable? = null private var batteryRetryTimer: Runnable? = null
@@ -299,7 +299,7 @@ class BleManager private constructor(private val context: Context) {
logw { "removeBond failed: ${e.message}" } logw { "removeBond failed: ${e.message}" }
} }
} }
com.example.medilightv2android.services.KnownDeviceStore.remove(context, address) com.medithings.vesiscan.services.KnownDeviceStore.remove(context, address)
debugLogger.info("DEVICE_UNREGISTERED $address") debugLogger.info("DEVICE_UNREGISTERED $address")
} }
@@ -326,7 +326,7 @@ class BleManager private constructor(private val context: Context) {
/** 저장된 마지막 기기에 자동 연결 시도 */ /** 저장된 마지막 기기에 자동 연결 시도 */
fun autoConnectLastDevice() { fun autoConnectLastDevice() {
if (isConnected.value) return if (isConnected.value) return
val recent = com.example.medilightv2android.services.KnownDeviceStore.mostRecent(context) ?: return val recent = com.medithings.vesiscan.services.KnownDeviceStore.mostRecent(context) ?: return
debugLogger.info("AUTO_CONNECT attempting ${recent.name} (${recent.address})") debugLogger.info("AUTO_CONNECT attempting ${recent.name} (${recent.address})")
lastConnectedAddress = recent.address lastConnectedAddress = recent.address
scheduleAutoReconnect() scheduleAutoReconnect()
@@ -340,7 +340,7 @@ class BleManager private constructor(private val context: Context) {
connectionTimer?.let { handler.removeCallbacks(it) } connectionTimer?.let { handler.removeCallbacks(it) }
connectionTimer = null connectionTimer = null
bluetoothGatt?.disconnect() bluetoothGatt?.disconnect()
com.example.medilightv2android.services.BleForegroundService.stop(context) com.medithings.vesiscan.services.BleForegroundService.stop(context)
} }
fun disconnectAndUnbond() { fun disconnectAndUnbond() {
@@ -348,7 +348,7 @@ class BleManager private constructor(private val context: Context) {
cancelAutoReconnect() cancelAutoReconnect()
stopWatchdog() stopWatchdog()
stopBatteryPolling() stopBatteryPolling()
com.example.medilightv2android.services.BleForegroundService.stop(context) com.medithings.vesiscan.services.BleForegroundService.stop(context)
connectionTimer?.let { handler.removeCallbacks(it) } connectionTimer?.let { handler.removeCallbacks(it) }
connectionTimer = null connectionTimer = null
@@ -386,7 +386,7 @@ class BleManager private constructor(private val context: Context) {
// 저장된 기기 정보 삭제 — known device list 에서도 제거 // 저장된 기기 정보 삭제 — known device list 에서도 제거
try { try {
device?.let { dev -> device?.let { dev ->
com.example.medilightv2android.services.KnownDeviceStore.remove(context, dev.address) com.medithings.vesiscan.services.KnownDeviceStore.remove(context, dev.address)
} }
} catch (_: Exception) {} } catch (_: Exception) {}
@@ -900,9 +900,9 @@ class BleManager private constructor(private val context: Context) {
isConnected.value = true isConnected.value = true
connectedDeviceName.value = try { gatt.device.name ?: "Unknown" } catch (_: Exception) { "Unknown" } connectedDeviceName.value = try { gatt.device.name ?: "Unknown" } catch (_: Exception) { "Unknown" }
// Auto-detect device preset + endian from name // Auto-detect device preset + endian from name
com.example.medilightv2android.managers.PiezoHW.autoDetectPreset(connectedDeviceName.value) com.medithings.vesiscan.managers.PiezoHW.autoDetectPreset(connectedDeviceName.value)
piezoCollector.forceBigEndian = connectedDeviceName.value.startsWith("VBT") piezoCollector.forceBigEndian = connectedDeviceName.value.startsWith("VBT")
logd { "Device preset: ${com.example.medilightv2android.managers.PiezoHW.presetName}, endian: ${if (piezoCollector.forceBigEndian) "BE" else "LE"} (from '${connectedDeviceName.value}')" } logd { "Device preset: ${com.medithings.vesiscan.managers.PiezoHW.presetName}, endian: ${if (piezoCollector.forceBigEndian) "BE" else "LE"} (from '${connectedDeviceName.value}')" }
lastConnectedAddress = gatt.device.address lastConnectedAddress = gatt.device.address
reconnectAttempt = 0 reconnectAttempt = 0
@@ -911,9 +911,9 @@ class BleManager private constructor(private val context: Context) {
// Clinical 흐름에서만 KnownDeviceStore 영속화. 일반 사용자는 // Clinical 흐름에서만 KnownDeviceStore 영속화. 일반 사용자는
// 매 세션 fresh scan + pair — 저장 0개. // 매 세션 fresh scan + pair — 저장 0개.
if (com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow) { if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow) {
try { try {
com.example.medilightv2android.services.KnownDeviceStore.add( com.medithings.vesiscan.services.KnownDeviceStore.add(
context, gatt.device.address, connectedDeviceName.value context, gatt.device.address, connectedDeviceName.value
) )
} catch (_: Exception) {} } catch (_: Exception) {}
@@ -1030,8 +1030,8 @@ class BleManager private constructor(private val context: Context) {
} catch (_: Exception) { false } } catch (_: Exception) { false }
logd { "requestConnectionPriority(HIGH) → $priorityOk" } logd { "requestConnectionPriority(HIGH) → $priorityOk" }
debugLogger.info("CONN_PRIORITY HIGH requested (ok=$priorityOk)") debugLogger.info("CONN_PRIORITY HIGH requested (ok=$priorityOk)")
com.example.medilightv2android.services.AdcCsvLogger.newSession() com.medithings.vesiscan.services.AdcCsvLogger.newSession()
com.example.medilightv2android.services.BleForegroundService.start(context) com.medithings.vesiscan.services.BleForegroundService.start(context)
startBatteryPolling() startBatteryPolling()
startWatchdog() startWatchdog()
sendDeviceInfoQuery() sendDeviceInfoQuery()
@@ -1105,7 +1105,7 @@ class BleManager private constructor(private val context: Context) {
private fun processReceivedData(data: ByteArray) { private fun processReceivedData(data: ByteArray) {
lastRxTimestamp = System.currentTimeMillis() lastRxTimestamp = System.currentTimeMillis()
// Raw BLE capture (디버그 — 사용자가 토글로 enable 했을 때만 writes) // Raw BLE capture (디버그 — 사용자가 토글로 enable 했을 때만 writes)
com.example.medilightv2android.services.RawBleLogger.write(data) com.medithings.vesiscan.services.RawBleLogger.write(data)
val prefix = String(data, 0, minOf(4, data.size), Charsets.US_ASCII) val prefix = String(data, 0, minOf(4, data.size), Charsets.US_ASCII)
logd { "Received: $prefix (${data.size} bytes)" } logd { "Received: $prefix (${data.size} bytes)" }
when (prefix) { when (prefix) {
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ble package com.medithings.vesiscan.ble
object CRC16 { object CRC16 {
private const val POLYNOMIAL: Int = 0x1021 private const val POLYNOMIAL: Int = 0x1021
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ble package com.medithings.vesiscan.ble
/** /**
* IMU 6축 raw 샘플 (Accel xyz + Gyro xyz). * IMU 6축 raw 샘플 (Accel xyz + Gyro xyz).
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ble package com.medithings.vesiscan.ble
/** /**
* Collects multi-packet Piezo echo responses: reb: → (red:) → raa: * Collects multi-packet Piezo echo responses: reb: → (red:) → raa:
@@ -16,12 +16,12 @@
* *
* 기존 PlacementGuide computePlacementGuide(...) 와 병행 — V1/V2 토글로 분기. * 기존 PlacementGuide computePlacementGuide(...) 와 병행 — V1/V2 토글로 분기.
*/ */
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.walldetect.MethodDResult import com.medithings.vesiscan.walldetect.MethodDResult
import com.example.medilightv2android.walldetect.MethodDRunner import com.medithings.vesiscan.walldetect.MethodDRunner
import com.example.medilightv2android.walldetect.algo.methodd.MethodDParams import com.medithings.vesiscan.walldetect.algo.methodd.MethodDParams
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
@@ -1,4 +1,4 @@
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
@@ -1,4 +1,4 @@
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import kotlin.math.abs import kotlin.math.abs
@@ -1,4 +1,4 @@
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
@@ -1,4 +1,4 @@
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.sqrt import kotlin.math.sqrt
@@ -1,4 +1,4 @@
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
/** /**
* Green Zone 전체 파이프라인의 공유 상수 — Single Source of Truth. * Green Zone 전체 파이프라인의 공유 상수 — Single Source of Truth.
@@ -1,6 +1,6 @@
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import com.example.medilightv2android.ble.ImuSample import com.medithings.vesiscan.ble.ImuSample
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.atan2 import kotlin.math.atan2
import kotlin.math.sqrt import kotlin.math.sqrt
@@ -13,9 +13,9 @@
* ≤ threshold → NON_LYING (앉음/섬) * ≤ threshold → NON_LYING (앉음/섬)
* threshold default = 25°, dev 모드 설정에서 변경 가능. * threshold default = 25°, dev 모드 설정에서 변경 가능.
*/ */
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import com.example.medilightv2android.ble.ImuSample import com.medithings.vesiscan.ble.ImuSample
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.atan import kotlin.math.atan
import kotlin.math.sqrt import kotlin.math.sqrt
@@ -1,8 +1,8 @@
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import com.example.medilightv2android.models.NirsConstants import com.medithings.vesiscan.models.NirsConstants
import com.example.medilightv2android.models.NirsMagResponse import com.medithings.vesiscan.models.NirsMagResponse
import com.example.medilightv2android.models.NirsOxyResult import com.medithings.vesiscan.models.NirsOxyResult
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.ln import kotlin.math.ln
import kotlin.math.max import kotlin.math.max
@@ -1,13 +1,13 @@
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import com.example.medilightv2android.models.NirsMagResponse import com.medithings.vesiscan.models.NirsMagResponse
import com.example.medilightv2android.models.NirsMcjPacket import com.medithings.vesiscan.models.NirsMcjPacket
import com.example.medilightv2android.models.NirsConstants import com.medithings.vesiscan.models.NirsConstants
import com.example.medilightv2android.BuildConfig import com.medithings.vesiscan.BuildConfig
import com.example.medilightv2android.models.NirsOxyResult import com.medithings.vesiscan.models.NirsOxyResult
class NirsManager private constructor() { class NirsManager private constructor() {
companion object { companion object {
@@ -1,6 +1,6 @@
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import com.example.medilightv2android.walldetect.core.WdConfig import com.medithings.vesiscan.walldetect.core.WdConfig
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.hypot import kotlin.math.hypot
@@ -484,7 +484,7 @@ fun estimateBladderVolume6ch(
val lateralWalls = PiezoHW.lateralCh.map { if (it < allWalls.size) allWalls[it] else null } val lateralWalls = PiezoHW.lateralCh.map { if (it < allWalls.size) allWalls[it] else null }
// 2026-07-01: algorithm 팀 최신 표준 (piezophantomtest 4830e7c) — lr_ratio_override=1.0 // 2026-07-01: algorithm 팀 최신 표준 (piezophantomtest 4830e7c) — lr_ratio_override=1.0
// Phantom 검증: computed lr 은 6채널 HW 한계로 -38% 오차. Dev panel 로 전환 가능. // Phantom 검증: computed lr 은 6채널 HW 한계로 -38% 오차. Dev panel 로 전환 가능.
val lrRatio = com.example.medilightv2android.managers.GreenZoneConstants.lrRatioOverride val lrRatio = com.medithings.vesiscan.managers.GreenZoneConstants.lrRatioOverride
?: computeLrRatio(centerWalls, lateralWalls, sensorZMm = PiezoHW.sensorZMmAll) ?: computeLrRatio(centerWalls, lateralWalls, sensorZMm = PiezoHW.sensorZMmAll)
return estimateBladderVolume( return estimateBladderVolume(
walls = centerWalls, walls = centerWalls,
@@ -1,6 +1,6 @@
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import com.example.medilightv2android.ble.PiezoChannelData import com.medithings.vesiscan.ble.PiezoChannelData
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@@ -1,4 +1,4 @@
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
@@ -1,4 +1,4 @@
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
/** /**
* UrinAI (UrinGateKeeper) — 소변(액체) 존재 판정 엔진. * UrinAI (UrinGateKeeper) — 소변(액체) 존재 판정 엔진.
@@ -15,7 +15,7 @@
* // 매 posture 갱신 시: * // 매 posture 갱신 시:
* detector.update(currentPosture, System.currentTimeMillis()) * detector.update(currentPosture, System.currentTimeMillis())
*/ */
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
class WakeupDetector( class WakeupDetector(
/** 알람 발동을 위해 직전 LYING 상태로 유지되어야 하는 최소 시간 (초). */ /** 알람 발동을 위해 직전 LYING 상태로 유지되어야 하는 최소 시간 (초). */
@@ -18,9 +18,9 @@
* 입력: 매 mtb cycle (≈1초 주기) 마다 IMU sample 리스트 + 현재 pitch + 시각 * 입력: 매 mtb cycle (≈1초 주기) 마다 IMU sample 리스트 + 현재 pitch + 시각
* 출력: 현재 walking 상태 (Boolean) + 진단 정보 * 출력: 현재 walking 상태 (Boolean) + 진단 정보
*/ */
package com.example.medilightv2android.managers package com.medithings.vesiscan.managers
import com.example.medilightv2android.ble.ImuSample import com.medithings.vesiscan.ble.ImuSample
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.sqrt import kotlin.math.sqrt
@@ -1,4 +1,4 @@
package com.example.medilightv2android.measure package com.medithings.vesiscan.measure
data class CCPosition( data class CCPosition(
val cc: Int, val cc: Int,
@@ -1,4 +1,4 @@
package com.example.medilightv2android.measure package com.medithings.vesiscan.measure
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
@@ -6,7 +6,7 @@ import android.util.Log
import com.google.mlkit.vision.common.InputImage import com.google.mlkit.vision.common.InputImage
import com.google.mlkit.vision.text.TextRecognition import com.google.mlkit.vision.text.TextRecognition
import com.google.mlkit.vision.text.latin.TextRecognizerOptions import com.google.mlkit.vision.text.latin.TextRecognizerOptions
import com.example.medilightv2android.measure.CCPosition import com.medithings.vesiscan.measure.CCPosition
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -1,4 +1,4 @@
package com.example.medilightv2android.measure package com.medithings.vesiscan.measure
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
@@ -1,4 +1,4 @@
package com.example.medilightv2android.measure package com.medithings.vesiscan.measure
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
@@ -1,4 +1,4 @@
package com.example.medilightv2android.models package com.medithings.vesiscan.models
data class BladderLevel( data class BladderLevel(
var currentLevel: Int = 0, var currentLevel: Int = 0,
@@ -1,4 +1,4 @@
package com.example.medilightv2android.models package com.medithings.vesiscan.models
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
@@ -1,4 +1,4 @@
package com.example.medilightv2android.models package com.medithings.vesiscan.models
import java.util.Date import java.util.Date
import java.util.UUID import java.util.UUID
@@ -1,4 +1,4 @@
package com.example.medilightv2android.models package com.medithings.vesiscan.models
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@@ -1,4 +1,4 @@
package com.example.medilightv2android.models package com.medithings.vesiscan.models
data class NirsMcjPacket( data class NirsMcjPacket(
val battery: Int, val battery: Int,
@@ -16,7 +16,7 @@ data class NirsMcjPacket(
fun parse(data: ByteArray): NirsMcjPacket? { fun parse(data: ByteArray): NirsMcjPacket? {
if (data.size < 72) { if (data.size < 72) {
if (com.example.medilightv2android.BuildConfig.DEBUG) { if (com.medithings.vesiscan.BuildConfig.DEBUG) {
android.util.Log.e(TAG, "parse: data too small: ${data.size} < 72") android.util.Log.e(TAG, "parse: data too small: ${data.size} < 72")
} }
return null return null
@@ -42,7 +42,7 @@ data class NirsMcjPacket(
for (i in 0 until 24) { for (i in 0 until 24) {
val offset = base + 20 + (i * 2) val offset = base + 20 + (i * 2)
if (offset + 1 >= data.size) { if (offset + 1 >= data.size) {
if (com.example.medilightv2android.BuildConfig.DEBUG) { if (com.medithings.vesiscan.BuildConfig.DEBUG) {
android.util.Log.e(TAG, "parse: LED[$i] out of bounds: offset=${offset+1} >= size=${data.size}") android.util.Log.e(TAG, "parse: LED[$i] out of bounds: offset=${offset+1} >= size=${data.size}")
} }
return null return null
@@ -50,7 +50,7 @@ data class NirsMcjPacket(
ledValues[i] = u16(offset) ledValues[i] = u16(offset)
} }
if (com.example.medilightv2android.BuildConfig.DEBUG) { if (com.medithings.vesiscan.BuildConfig.DEBUG) {
android.util.Log.d(TAG, "parse OK: battery=$battery led[0..5]=${ledValues.take(6)}") android.util.Log.d(TAG, "parse OK: battery=$battery led[0..5]=${ledValues.take(6)}")
} }
@@ -1,4 +1,4 @@
package com.example.medilightv2android.models package com.medithings.vesiscan.models
enum class Posture(val displayName: String) { enum class Posture(val displayName: String) {
STANDING("Standing"), STANDING("Standing"),
@@ -1,4 +1,4 @@
package com.example.medilightv2android.models package com.medithings.vesiscan.models
enum class SensorMode(val displayName: String) { enum class SensorMode(val displayName: String) {
NIRS("NIRS"), NIRS("NIRS"),
@@ -1,4 +1,4 @@
package com.example.medilightv2android.models package com.medithings.vesiscan.models
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@@ -1,4 +1,4 @@
package com.example.medilightv2android.models package com.medithings.vesiscan.models
enum class Sex { MALE, FEMALE } enum class Sex { MALE, FEMALE }
@@ -1,4 +1,4 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.os.Environment import android.os.Environment
import java.io.File import java.io.File
@@ -63,15 +63,15 @@ object AdcCsvLogger {
val timestamp = timeFmt.format(Date()) val timestamp = timeFmt.format(Date())
val volStr = volumeMl?.let { "%.1f".format(it) } ?: "" val volStr = volumeMl?.let { "%.1f".format(it) } ?: ""
val lrStr = "%.2f".format(lrRatio) val lrStr = "%.2f".format(lrRatio)
val analyzer = com.example.medilightv2android.managers.PiezoEchoAnalyzer.shared val analyzer = com.medithings.vesiscan.managers.PiezoEchoAnalyzer.shared
val thrStr = if (analyzer.useAdaptiveThreshold && analyzer.lastOtsuThreshold > 0) val thrStr = if (analyzer.useAdaptiveThreshold && analyzer.lastOtsuThreshold > 0)
"%.0f".format(analyzer.lastOtsuThreshold) else "%.0f".format(com.example.medilightv2android.managers.GreenZoneConstants.lowEchoAmp) "%.0f".format(analyzer.lastOtsuThreshold) else "%.0f".format(com.medithings.vesiscan.managers.GreenZoneConstants.lowEchoAmp)
val dpsStr = "%.3f".format(com.example.medilightv2android.managers.PiezoHW.distancePerSample) val dpsStr = "%.3f".format(com.medithings.vesiscan.managers.PiezoHW.distancePerSample)
val sgStr = if (analyzer.useSgFilter) "ON" else "OFF" val sgStr = if (analyzer.useSgFilter) "ON" else "OFF"
val clinicalLabel = ClinicalSessionStore.currentLabel() // 일반 모드면 "" val clinicalLabel = ClinicalSessionStore.currentLabel() // 일반 모드면 ""
// BLE 펌웨어 버전 (연결 안 됐으면 "") // BLE 펌웨어 버전 (연결 안 됐으면 "")
val fwVersion = com.example.medilightv2android.ble.BleManager.current?.firmwareVersion?.value ?: "" val fwVersion = com.medithings.vesiscan.ble.BleManager.current?.firmwareVersion?.value ?: ""
java.io.FileWriter(file, !isNew).buffered().use { writer -> java.io.FileWriter(file, !isNew).buffered().use { writer ->
if (isNew) { if (isNew) {
@@ -1,4 +1,4 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@@ -1,4 +1,4 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.app.Notification import android.app.Notification
import android.app.NotificationChannel import android.app.NotificationChannel
@@ -11,8 +11,8 @@ import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.PowerManager import android.os.PowerManager
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import com.example.medilightv2android.MainActivity import com.medithings.vesiscan.MainActivity
import com.example.medilightv2android.R import com.medithings.vesiscan.R
/** /**
* BLE 연결 유지를 위한 Foreground Service. * BLE 연결 유지를 위한 Foreground Service.
@@ -25,8 +25,8 @@ class BleForegroundService : Service() {
companion object { companion object {
const val CHANNEL_ID = "vesiscan_ble_channel" const val CHANNEL_ID = "vesiscan_ble_channel"
const val NOTIFICATION_ID = 1001 const val NOTIFICATION_ID = 1001
const val ACTION_START = "com.example.medilightv2android.BLE_START" const val ACTION_START = "com.medithings.vesiscan.BLE_START"
const val ACTION_STOP = "com.example.medilightv2android.BLE_STOP" const val ACTION_STOP = "com.medithings.vesiscan.BLE_STOP"
fun start(context: Context) { fun start(context: Context) {
// 배터리 최적화 제외 요청 제거 — 다른 페이지로 이동되는 UX 문제 // 배터리 최적화 제외 요청 제거 — 다른 페이지로 이동되는 UX 문제
@@ -1,10 +1,10 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.content.Context import android.content.Context
import android.os.Environment import android.os.Environment
import com.example.medilightv2android.ble.ImuSample import com.medithings.vesiscan.ble.ImuSample
import com.example.medilightv2android.ble.PiezoChannelData import com.medithings.vesiscan.ble.PiezoChannelData
import com.example.medilightv2android.models.ClinicalSession import com.medithings.vesiscan.models.ClinicalSession
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import java.io.File import java.io.File
@@ -59,16 +59,16 @@ object ClinicalSessionStore {
/** 다음 측정 시 기본값으로 자동 채울 사용자 입력 — 같은 피험자/검사자 여러 측정 시 편의 */ /** 다음 측정 시 기본값으로 자동 채울 사용자 입력 — 같은 피험자/검사자 여러 측정 시 편의 */
var lastExaminer: String = "" var lastExaminer: String = ""
var lastNotes: String = "" var lastNotes: String = ""
var lastSubjectType: com.example.medilightv2android.models.SubjectType = var lastSubjectType: com.medithings.vesiscan.models.SubjectType =
com.example.medilightv2android.models.SubjectType.PHANTOM com.medithings.vesiscan.models.SubjectType.PHANTOM
var lastSubject: String = "" // 카테고리 내 식별자 (예: "500mL", "S001") var lastSubject: String = "" // 카테고리 내 식별자 (예: "500mL", "S001")
var lastTrueVolumeMl: String = "" // 문자열로 보관 (입력 폼과 동일 형식) var lastTrueVolumeMl: String = "" // 문자열로 보관 (입력 폼과 동일 형식)
var lastAbdomenThicknessMm: String = "" var lastAbdomenThicknessMm: String = ""
// 회의 결정: Step/Posture 마지막 선택 유지 — 매번 0cm로 리셋되는 불편 제거 // 회의 결정: Step/Posture 마지막 선택 유지 — 매번 0cm로 리셋되는 불편 제거
var lastPosture: com.example.medilightv2android.models.ClinicalPosture = var lastPosture: com.medithings.vesiscan.models.ClinicalPosture =
com.example.medilightv2android.models.ClinicalPosture.SUPINE com.medithings.vesiscan.models.ClinicalPosture.SUPINE
var lastStep: com.example.medilightv2android.models.ClinicalStep = var lastStep: com.medithings.vesiscan.models.ClinicalStep =
com.example.medilightv2android.models.ClinicalStep.ALIGN_0CM com.medithings.vesiscan.models.ClinicalStep.ALIGN_0CM
/** End 시점에 measurement.json 통합 생성용 — 측정 중 사이클 누적 */ /** End 시점에 measurement.json 통합 생성용 — 측정 중 사이클 누적 */
private val cyclesBuffer = mutableListOf<MeasurementCycle>() private val cyclesBuffer = mutableListOf<MeasurementCycle>()
@@ -186,7 +186,7 @@ object ClinicalSessionStore {
put("android_release", android.os.Build.VERSION.RELEASE) put("android_release", android.os.Build.VERSION.RELEASE)
put("android_sdk", android.os.Build.VERSION.SDK_INT) put("android_sdk", android.os.Build.VERSION.SDK_INT)
// VBT 디바이스 정보 (mid?/rid: 응답 파싱값) — 분석 시 펌웨어별 데이터 grouping용 // VBT 디바이스 정보 (mid?/rid: 응답 파싱값) — 분석 시 펌웨어별 데이터 grouping용
val ble = com.example.medilightv2android.ble.BleManager.getInstance(context) val ble = com.medithings.vesiscan.ble.BleManager.getInstance(context)
val fw = ble.firmwareVersion.value val fw = ble.firmwareVersion.value
val hw = ble.hardwareVersion.value val hw = ble.hardwareVersion.value
val sn = ble.serialNumber.value val sn = ble.serialNumber.value
@@ -224,7 +224,7 @@ object ClinicalSessionStore {
// meta: writeMeta()와 동일 내용 포함 (단독 파일로 자족 가능) // meta: writeMeta()와 동일 내용 포함 (단독 파일로 자족 가능)
// alignment 모드 → dataType=002, 그 외 = 001 (기존 measurement) // alignment 모드 → dataType=002, 그 외 = 001 (기존 measurement)
val effectiveDataType = if (s.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT) val effectiveDataType = if (s.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT)
"002" else DATA_TYPE "002" else DATA_TYPE
val meta = JSONObject().apply { val meta = JSONObject().apply {
put("data_type", effectiveDataType) put("data_type", effectiveDataType)
@@ -254,7 +254,7 @@ object ClinicalSessionStore {
put("app_version_name", try { put("app_version_name", try {
context.packageManager.getPackageInfo(context.packageName, 0).versionName ?: "unknown" context.packageManager.getPackageInfo(context.packageName, 0).versionName ?: "unknown"
} catch (_: Exception) { "unknown" }) } catch (_: Exception) { "unknown" })
val ble = com.example.medilightv2android.ble.BleManager.current val ble = com.medithings.vesiscan.ble.BleManager.current
ble?.firmwareVersion?.value?.takeIf { it.isNotEmpty() }?.let { put("firmware_version", it) } ble?.firmwareVersion?.value?.takeIf { it.isNotEmpty() }?.let { put("firmware_version", it) }
ble?.hardwareVersion?.value?.takeIf { it.isNotEmpty() }?.let { put("hardware_version", it) } ble?.hardwareVersion?.value?.takeIf { it.isNotEmpty() }?.let { put("hardware_version", it) }
ble?.serialNumber?.value?.takeIf { it.isNotEmpty() }?.let { put("serial_number", it) } ble?.serialNumber?.value?.takeIf { it.isNotEmpty() }?.let { put("serial_number", it) }
@@ -1,6 +1,6 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import com.example.medilightv2android.ble.ImuSample import com.medithings.vesiscan.ble.ImuSample
import java.io.File import java.io.File
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
@@ -38,7 +38,7 @@ object ImuCsvLogger {
val scanId = AdcCsvLogger.lastScanId // piezo adc.csv와 매칭용 val scanId = AdcCsvLogger.lastScanId // piezo adc.csv와 매칭용
val timestamp = timeFmt.format(Date()) val timestamp = timeFmt.format(Date())
val clinicalLabel = ClinicalSessionStore.currentLabel() val clinicalLabel = ClinicalSessionStore.currentLabel()
val fwVersion = com.example.medilightv2android.ble.BleManager.current?.firmwareVersion?.value ?: "" val fwVersion = com.medithings.vesiscan.ble.BleManager.current?.firmwareVersion?.value ?: ""
file.bufferedWriter().use { _ -> } // ensure exists file.bufferedWriter().use { _ -> } // ensure exists
java.io.FileWriter(file, !isNew).buffered().use { writer -> java.io.FileWriter(file, !isNew).buffered().use { writer ->
@@ -1,4 +1,4 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
@@ -1,4 +1,4 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.content.Context import android.content.Context
import org.json.JSONArray import org.json.JSONArray
@@ -13,7 +13,7 @@
* Android 13+ 의 per-app locale API (AppCompatDelegate.setApplicationLocales) 와 * Android 13+ 의 per-app locale API (AppCompatDelegate.setApplicationLocales) 와
* 무관하게 Configuration override 방식으로 모든 SDK 에서 동작. * 무관하게 Configuration override 방식으로 모든 SDK 에서 동작.
*/ */
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.content.Context import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
@@ -1,8 +1,8 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import com.example.medilightv2android.models.MeasurementRecord import com.medithings.vesiscan.models.MeasurementRecord
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
@@ -1,4 +1,4 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
@@ -70,7 +70,7 @@ class MeasurementLogService private constructor(private val context: Context) {
val clinical = ClinicalSessionStore.currentLabel() val clinical = ClinicalSessionStore.currentLabel()
if (clinical.isNotEmpty()) put("clinical_label", clinical) if (clinical.isNotEmpty()) put("clinical_label", clinical)
// BLE 펌웨어 버전 (연결 시 mid?/rid: 응답에서 받음) // BLE 펌웨어 버전 (연결 시 mid?/rid: 응답에서 받음)
val fw = com.example.medilightv2android.ble.BleManager.current?.firmwareVersion?.value val fw = com.medithings.vesiscan.ble.BleManager.current?.firmwareVersion?.value
if (!fw.isNullOrEmpty()) put("firmware_version", fw) if (!fw.isNullOrEmpty()) put("firmware_version", fw)
} }
@@ -136,7 +136,7 @@ class MeasurementLogService private constructor(private val context: Context) {
val clinical = ClinicalSessionStore.currentLabel() val clinical = ClinicalSessionStore.currentLabel()
if (clinical.isNotEmpty()) put("clinical_label", clinical) if (clinical.isNotEmpty()) put("clinical_label", clinical)
// BLE 펌웨어 버전 // BLE 펌웨어 버전
val fw = com.example.medilightv2android.ble.BleManager.current?.firmwareVersion?.value val fw = com.medithings.vesiscan.ble.BleManager.current?.firmwareVersion?.value
if (!fw.isNullOrEmpty()) put("firmware_version", fw) if (!fw.isNullOrEmpty()) put("firmware_version", fw)
} }
appendLog(entry, "placements.jsonl") appendLog(entry, "placements.jsonl")
@@ -1,9 +1,9 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.content.Context import android.content.Context
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
import com.example.medilightv2android.models.SensorMode import com.medithings.vesiscan.models.SensorMode
class MeasurementService private constructor(context: Context) { class MeasurementService private constructor(context: Context) {
companion object { companion object {
@@ -1,4 +1,4 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
@@ -6,8 +6,8 @@ import android.content.Context
import android.os.Build import android.os.Build
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.models.UrgencyLevel import com.medithings.vesiscan.models.UrgencyLevel
class NotificationService private constructor(private val context: Context) { class NotificationService private constructor(private val context: Context) {
companion object { companion object {
@@ -23,7 +23,7 @@
* *
* 분석: CSV → Excel / python pandas → ANNOTATION 과 CYCLE 의 walking 전이 대조. * 분석: CSV → Excel / python pandas → ANNOTATION 과 CYCLE 의 walking 전이 대조.
*/ */
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.content.Context import android.content.Context
import android.os.Environment import android.os.Environment
@@ -9,10 +9,10 @@
* saveAll(context) — slider 변경 시 호출 → 현재 GreenZoneConstants → SharedPreferences * saveAll(context) — slider 변경 시 호출 → 현재 GreenZoneConstants → SharedPreferences
* resetAll(context) — 사용자가 reset 누름 → defaults 로 복원 * resetAll(context) — 사용자가 reset 누름 → defaults 로 복원
*/ */
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.content.Context import android.content.Context
import com.example.medilightv2android.managers.GreenZoneConstants import com.medithings.vesiscan.managers.GreenZoneConstants
object PostureTuningPrefs { object PostureTuningPrefs {
@@ -10,7 +10,7 @@
* 사용: startCapture() / stopCapture() 토글. 활성화 시 BleManager.processReceivedData * 사용: startCapture() / stopCapture() 토글. 활성화 시 BleManager.processReceivedData
* 가 매 notification 마다 write() 호출. * 가 매 notification 마다 write() 호출.
*/ */
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.os.Environment import android.os.Environment
import java.io.File import java.io.File
@@ -1,4 +1,4 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.app.AlarmManager import android.app.AlarmManager
import android.app.NotificationChannel import android.app.NotificationChannel
@@ -15,7 +15,7 @@ import android.os.Vibrator
import android.os.VibratorManager import android.os.VibratorManager
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import java.util.Calendar import java.util.Calendar
class ReminderService private constructor(private val context: Context) { class ReminderService private constructor(private val context: Context) {
@@ -1,6 +1,6 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import com.example.medilightv2android.ble.PiezoChannelData import com.medithings.vesiscan.ble.PiezoChannelData
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
@@ -1,8 +1,8 @@
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import com.example.medilightv2android.models.* import com.medithings.vesiscan.models.*
import com.google.gson.Gson import com.google.gson.Gson
class UserStorage private constructor(context: Context) { class UserStorage private constructor(context: Context) {
@@ -4,7 +4,7 @@
* 사용자가 "설정 탭" 에서 toggle on/off → 일어남 감지 시 빨간 팝업. * 사용자가 "설정 탭" 에서 toggle on/off → 일어남 감지 시 빨간 팝업.
* LYING 유지 시간 임계 (default 3 min) 도 함께. * LYING 유지 시간 임계 (default 3 min) 도 함께.
*/ */
package com.example.medilightv2android.services package com.medithings.vesiscan.services
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
@@ -1,9 +1,9 @@
package com.example.medilightv2android.services.labdb package com.medithings.vesiscan.services.labdb
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
@@ -1,6 +1,6 @@
package com.example.medilightv2android.services.labdb package com.medithings.vesiscan.services.labdb
import com.example.medilightv2android.services.KeychainService import com.medithings.vesiscan.services.KeychainService
/** /**
* labdb (https://labdb.medithings.net) 자격 증명 저장소. * labdb (https://labdb.medithings.net) 자격 증명 저장소.
@@ -1,4 +1,4 @@
package com.example.medilightv2android.services.labdb package com.medithings.vesiscan.services.labdb
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
@@ -4,7 +4,7 @@
* MEDiThings Inc. * MEDiThings Inc.
* All rights reserved. * All rights reserved.
*/ */
package com.example.medilightv2android.speech package com.medithings.vesiscan.speech
import android.util.Log import android.util.Log
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -4,7 +4,7 @@
* MEDiThings Inc. * MEDiThings Inc.
* All rights reserved. * All rights reserved.
*/ */
package com.example.medilightv2android.speech package com.medithings.vesiscan.speech
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@@ -4,7 +4,7 @@
* MEDiThings Inc. * MEDiThings Inc.
* All rights reserved. * All rights reserved.
*/ */
package com.example.medilightv2android.speech package com.medithings.vesiscan.speech
/** /**
* Local (offline) parser that extracts a volume in milliliters from speech-recognition text. * Local (offline) parser that extracts a volume in milliliters from speech-recognition text.
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.components package com.medithings.vesiscan.ui.components
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -22,8 +22,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
/** /**
* 배터리 잔량 경고 배너 — PlacementGuide / PiezoMonitoring 상단. * 배터리 잔량 경고 배너 — PlacementGuide / PiezoMonitoring 상단.
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.components package com.medithings.vesiscan.ui.components
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
@@ -13,8 +13,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import app.rive.runtime.kotlin.RiveAnimationView import app.rive.runtime.kotlin.RiveAnimationView
import app.rive.runtime.kotlin.core.Fit import app.rive.runtime.kotlin.core.Fit
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.models.UrgencyLevel import com.medithings.vesiscan.models.UrgencyLevel
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlin.random.Random import kotlin.random.Random
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.components package com.medithings.vesiscan.ui.components
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@@ -13,7 +13,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.ui.theme.MlPrimary import com.medithings.vesiscan.ui.theme.MlPrimary
enum class BleReconnectionState { enum class BleReconnectionState {
DISCONNECTED, RECONNECTING, FAILED DISCONNECTED, RECONNECTING, FAILED
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.components package com.medithings.vesiscan.ui.components
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
@@ -14,7 +14,7 @@ import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.example.medilightv2android.models.UrgencyLevel import com.medithings.vesiscan.models.UrgencyLevel
@Composable @Composable
fun DonutChartView( fun DonutChartView(
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.components package com.medithings.vesiscan.ui.components
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -26,8 +26,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
/** /**
@@ -15,7 +15,7 @@
* UX 톤: * UX 톤:
* "1회 터치 후 조정" 패턴 — 의도된 조작만 허용. * "1회 터치 후 조정" 패턴 — 의도된 조작만 허용.
*/ */
package com.example.medilightv2android.ui.components package com.medithings.vesiscan.ui.components
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@@ -39,7 +39,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.example.medilightv2android.R import com.medithings.vesiscan.R
@Composable @Composable
fun LockableSlider( fun LockableSlider(
@@ -5,7 +5,7 @@
* measurement, newest at the bottom, monospace, long-press to select spans * measurement, newest at the bottom, monospace, long-press to select spans
* across entries. Copy puts the full log on the system clipboard. * across entries. Copy puts the full log on the system clipboard.
*/ */
package com.example.medilightv2android.ui.components package com.medithings.vesiscan.ui.components
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.theme package com.medithings.vesiscan.ui.theme
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.theme package com.medithings.vesiscan.ui.theme
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.gestures.detectTapGestures
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.theme package com.medithings.vesiscan.ui.theme
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.theme package com.medithings.vesiscan.ui.theme
import androidx.compose.material3.Typography import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.calibration package com.medithings.vesiscan.ui.views.calibration
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@@ -22,13 +22,13 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
import com.example.medilightv2android.managers.NirsManager import com.medithings.vesiscan.managers.NirsManager
import com.example.medilightv2android.models.NirsMagResponse import com.medithings.vesiscan.models.NirsMagResponse
import com.example.medilightv2android.ui.components.BladdyIdleRiveView import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
@Composable @Composable
fun CalibrationView(appState: AppState) { fun CalibrationView(appState: AppState) {
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.clinical package com.medithings.vesiscan.ui.views.clinical
import android.widget.Toast import android.widget.Toast
import androidx.compose.foundation.background import androidx.compose.foundation.background
@@ -23,15 +23,15 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppScreen import com.medithings.vesiscan.AppScreen
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
import com.example.medilightv2android.models.* import com.medithings.vesiscan.models.*
import com.example.medilightv2android.services.ClinicalSessionStore import com.medithings.vesiscan.services.ClinicalSessionStore
import com.example.medilightv2android.services.labdb.LabdbClient import com.medithings.vesiscan.services.labdb.LabdbClient
import com.example.medilightv2android.services.labdb.LabdbCredentials import com.medithings.vesiscan.services.labdb.LabdbCredentials
import com.example.medilightv2android.services.labdb.LabdbUploader import com.medithings.vesiscan.services.labdb.LabdbUploader
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
/** /**
@@ -397,7 +397,7 @@ fun ClinicalHomeView(appState: AppState) {
// 측정 대상 분류 — Phantom/Human/ETC 버튼 (회의 결정) // 측정 대상 분류 — Phantom/Human/ETC 버튼 (회의 결정)
LabeledSegmented( LabeledSegmented(
label = "Subject Type", label = "Subject Type",
options = com.example.medilightv2android.models.SubjectType.values().toList(), options = com.medithings.vesiscan.models.SubjectType.values().toList(),
selected = subjectType, selected = subjectType,
onSelect = { subjectType = it } onSelect = { subjectType = it }
) { it.label } ) { it.label }
@@ -492,7 +492,7 @@ fun ClinicalHomeView(appState: AppState) {
subjectType = subjectType, subject = subject.trim(), subjectType = subjectType, subject = subject.trim(),
trueVolumeMl = trueVolText.toDoubleOrNull(), trueVolumeMl = trueVolText.toDoubleOrNull(),
abdomenThicknessMm = abdomenText.toDoubleOrNull(), abdomenThicknessMm = abdomenText.toDoubleOrNull(),
mode = com.example.medilightv2android.models.SessionMode.MEASUREMENT, mode = com.medithings.vesiscan.models.SessionMode.MEASUREMENT,
) )
) )
appState.currentScreen = AppScreen.CLINICAL_LIVE appState.currentScreen = AppScreen.CLINICAL_LIVE
@@ -517,9 +517,9 @@ fun ClinicalHomeView(appState: AppState) {
subjectType = subjectType, subject = subject.trim(), subjectType = subjectType, subject = subject.trim(),
trueVolumeMl = trueVolText.toDoubleOrNull(), trueVolumeMl = trueVolText.toDoubleOrNull(),
abdomenThicknessMm = abdomenText.toDoubleOrNull(), abdomenThicknessMm = abdomenText.toDoubleOrNull(),
mode = com.example.medilightv2android.models.SessionMode.ALIGNMENT, mode = com.medithings.vesiscan.models.SessionMode.ALIGNMENT,
// 현재 dev 토글된 algo 그대로 — V1 (default) 또는 V2. // 현재 dev 토글된 algo 그대로 — V1 (default) 또는 V2.
alignmentAlgo = com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo.name, alignmentAlgo = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo.name,
) )
) )
appState.enterAlignmentSession() appState.enterAlignmentSession()
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.clinical package com.medithings.vesiscan.ui.views.clinical
import android.widget.Toast import android.widget.Toast
import androidx.compose.foundation.Canvas import androidx.compose.foundation.Canvas
@@ -25,17 +25,17 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppScreen import com.medithings.vesiscan.AppScreen
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
import com.example.medilightv2android.ble.ImuSample import com.medithings.vesiscan.ble.ImuSample
import com.example.medilightv2android.ble.PiezoChannelData import com.medithings.vesiscan.ble.PiezoChannelData
import com.example.medilightv2android.managers.ImuAnalysis import com.medithings.vesiscan.managers.ImuAnalysis
import com.example.medilightv2android.services.AdcCsvLogger import com.medithings.vesiscan.services.AdcCsvLogger
import com.example.medilightv2android.services.ClinicalSessionStore import com.medithings.vesiscan.services.ClinicalSessionStore
import com.example.medilightv2android.services.ImuCsvLogger import com.medithings.vesiscan.services.ImuCsvLogger
import com.example.medilightv2android.services.MeasurementLogService import com.medithings.vesiscan.services.MeasurementLogService
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@@ -79,7 +79,7 @@ fun ClinicalLiveView(appState: AppState) {
var pendingPiezo by remember { mutableStateOf<List<PiezoChannelData>?>(null) } var pendingPiezo by remember { mutableStateOf<List<PiezoChannelData>?>(null) }
// V4.1 wall detection — 채널별 ant/post peak 표시용 (사내 테스트 가시화 요청) // V4.1 wall detection — 채널별 ant/post peak 표시용 (사내 테스트 가시화 요청)
val v41 = remember { com.example.medilightv2android.walldetect.V41Detector() } val v41 = remember { com.medithings.vesiscan.walldetect.V41Detector() }
var channelWalls by remember { mutableStateOf<List<Pair<Int, Int>?>>(List(6) { null }) } var channelWalls by remember { mutableStateOf<List<Pair<Int, Int>?>>(List(6) { null }) }
DisposableEffect(Unit) { DisposableEffect(Unit) {
@@ -91,13 +91,13 @@ fun ClinicalLiveView(appState: AppState) {
val adcMatrix = (0 until 6).map { ch -> val adcMatrix = (0 until 6).map { ch ->
channels.find { it.channel == ch }?.buffer?.map { it.toInt() } ?: List(100) { 0 } channels.find { it.channel == ch }?.buffer?.map { it.toInt() } ?: List(100) { 0 }
} }
val probe = com.example.medilightv2android.walldetect.dto.ProbeProfileDto( val probe = com.medithings.vesiscan.walldetect.dto.ProbeProfileDto(
name = com.example.medilightv2android.managers.PiezoHW.presetName, name = com.medithings.vesiscan.managers.PiezoHW.presetName,
rMm = 50.2, anteriorAnchorMm = 32.0, rMm = 50.2, anteriorAnchorMm = 32.0,
fsHz = 537500, cMmPerUs = 1.54, fsHz = 537500, cMmPerUs = 1.54,
anglesDeg = com.example.medilightv2android.managers.PiezoHW.degreeAll.toList() anglesDeg = com.medithings.vesiscan.managers.PiezoHW.degreeAll.toList()
) )
val sweepInput = com.example.medilightv2android.walldetect.dto.SweepInput( val sweepInput = com.medithings.vesiscan.walldetect.dto.SweepInput(
requestId = "clinical_${System.currentTimeMillis()}", requestId = "clinical_${System.currentTimeMillis()}",
timestampMs = System.currentTimeMillis(), timestampMs = System.currentTimeMillis(),
deviceId = bleManager.connectedDeviceName.value, deviceId = bleManager.connectedDeviceName.value,
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.connection package com.medithings.vesiscan.ui.views.connection
import android.Manifest import android.Manifest
import android.content.pm.PackageManager import android.content.pm.PackageManager
@@ -34,15 +34,15 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.ble.BleDevice import com.medithings.vesiscan.ble.BleDevice
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
import com.example.medilightv2android.models.SensorMode import com.medithings.vesiscan.models.SensorMode
import com.example.medilightv2android.services.KnownDevice import com.medithings.vesiscan.services.KnownDevice
import com.example.medilightv2android.services.KnownDeviceStore import com.medithings.vesiscan.services.KnownDeviceStore
import com.example.medilightv2android.ui.components.BladdyIdleRiveView import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
@@ -55,7 +55,7 @@ fun DeviceScanView(appState: AppState) {
var permissionsGranted by remember { mutableStateOf(false) } var permissionsGranted by remember { mutableStateOf(false) }
// Clinical 흐름에서만 다중 기기 저장/표시 — 일반 사용자는 fresh scan & pair. // Clinical 흐름에서만 다중 기기 저장/표시 — 일반 사용자는 fresh scan & pair.
val isClinicalFlow = com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow val isClinicalFlow = com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow
var knownDevices by remember { var knownDevices by remember {
mutableStateOf(if (isClinicalFlow) KnownDeviceStore.getAll(context) else emptyList()) mutableStateOf(if (isClinicalFlow) KnownDeviceStore.getAll(context) else emptyList())
} }
@@ -287,7 +287,7 @@ fun DeviceScanView(appState: AppState) {
Button( Button(
onClick = { onClick = {
appState.isDeviceConnected = true appState.isDeviceConnected = true
appState.currentScreen = com.example.medilightv2android.AppScreen.PIEZO_PERSONALIZATION appState.currentScreen = com.medithings.vesiscan.AppScreen.PIEZO_PERSONALIZATION
}, },
modifier = Modifier.fillMaxWidth().height(48.dp), modifier = Modifier.fillMaxWidth().height(48.dp),
shape = RoundedCornerShape(12.dp), shape = RoundedCornerShape(12.dp),
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.consent package com.medithings.vesiscan.ui.views.consent
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@@ -15,13 +15,13 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.services.UserStorage import com.medithings.vesiscan.services.UserStorage
import com.example.medilightv2android.ui.components.BladdyIdleRiveView import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
@Composable @Composable
fun ConsentView(appState: AppState) { fun ConsentView(appState: AppState) {
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.history package com.medithings.vesiscan.ui.views.history
import androidx.compose.foundation.Canvas import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background import androidx.compose.foundation.background
@@ -31,11 +31,11 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.models.* import com.medithings.vesiscan.models.*
import com.example.medilightv2android.services.MeasurementHistoryStore import com.medithings.vesiscan.services.MeasurementHistoryStore
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.home package com.medithings.vesiscan.ui.views.home
import android.widget.Toast import android.widget.Toast
import androidx.compose.foundation.background import androidx.compose.foundation.background
@@ -28,12 +28,12 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.ui.components.BladdyIdleRiveView import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
@Composable @Composable
fun HomeView(appState: AppState) { fun HomeView(appState: AppState) {
@@ -147,7 +147,7 @@ fun HomeView(appState: AppState) {
// Dev 모드 한정 — Clinical R&D Mode 진입 // Dev 모드 한정 — Clinical R&D Mode 진입
if (appState.isDevMode) { if (appState.isDevMode) {
Button( Button(
onClick = { appState.currentScreen = com.example.medilightv2android.AppScreen.CLINICAL_HOME }, onClick = { appState.currentScreen = com.medithings.vesiscan.AppScreen.CLINICAL_HOME },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 32.dp) .padding(horizontal = 32.dp)
@@ -166,7 +166,7 @@ fun HomeView(appState: AppState) {
// 언어 선택 다이얼로그 — 시스템 / 한국어 / English. 변경 시 Activity recreate. // 언어 선택 다이얼로그 — 시스템 / 한국어 / English. 변경 시 Activity recreate.
if (showLanguageDialog) { if (showLanguageDialog) {
val curMode = com.example.medilightv2android.services.LocalePref.getMode(context) val curMode = com.medithings.vesiscan.services.LocalePref.getMode(context)
var selected by remember { mutableStateOf(curMode) } var selected by remember { mutableStateOf(curMode) }
AlertDialog( AlertDialog(
onDismissRequest = { showLanguageDialog = false }, onDismissRequest = { showLanguageDialog = false },
@@ -174,9 +174,9 @@ fun HomeView(appState: AppState) {
text = { text = {
Column { Column {
listOf( listOf(
com.example.medilightv2android.services.LocalePref.Mode.SYSTEM to stringResource(R.string.language_system_default), com.medithings.vesiscan.services.LocalePref.Mode.SYSTEM to stringResource(R.string.language_system_default),
com.example.medilightv2android.services.LocalePref.Mode.KO to stringResource(R.string.language_korean), com.medithings.vesiscan.services.LocalePref.Mode.KO to stringResource(R.string.language_korean),
com.example.medilightv2android.services.LocalePref.Mode.EN to stringResource(R.string.language_english), com.medithings.vesiscan.services.LocalePref.Mode.EN to stringResource(R.string.language_english),
).forEach { (mode, label) -> ).forEach { (mode, label) ->
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
@@ -197,7 +197,7 @@ fun HomeView(appState: AppState) {
}, },
confirmButton = { confirmButton = {
TextButton(onClick = { TextButton(onClick = {
com.example.medilightv2android.services.LocalePref.setMode(context, selected) com.medithings.vesiscan.services.LocalePref.setMode(context, selected)
showLanguageDialog = false showLanguageDialog = false
// Activity recreate → attachBaseContext 다시 호출 → 새 locale 적용 // Activity recreate → attachBaseContext 다시 호출 → 새 locale 적용
(context as? android.app.Activity)?.recreate() (context as? android.app.Activity)?.recreate()
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.monitoring package com.medithings.vesiscan.ui.views.monitoring
import android.widget.Toast import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
@@ -21,11 +21,11 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.measure.VoidingRecord import com.medithings.vesiscan.measure.VoidingRecord
import com.example.medilightv2android.measure.VoidingRecordStore import com.medithings.vesiscan.measure.VoidingRecordStore
import com.example.medilightv2android.speech.SpeechRecognizerManager import com.medithings.vesiscan.speech.SpeechRecognizerManager
import com.example.medilightv2android.speech.VolumeParser import com.medithings.vesiscan.speech.VolumeParser
/** /**
* Catheterize 바텀시트 — 수기/음성/카메라 3가지 입력 * Catheterize 바텀시트 — 수기/음성/카메라 3가지 입력
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.monitoring package com.medithings.vesiscan.ui.views.monitoring
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@@ -6,7 +6,7 @@ import android.util.Log
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import com.example.medilightv2android.AppScreen import com.medithings.vesiscan.AppScreen
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.foundation.Canvas import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background import androidx.compose.foundation.background
@@ -42,23 +42,23 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
import com.example.medilightv2android.ble.PiezoChannelData import com.medithings.vesiscan.ble.PiezoChannelData
import com.example.medilightv2android.managers.PiezoEchoAnalyzer import com.medithings.vesiscan.managers.PiezoEchoAnalyzer
import com.example.medilightv2android.managers.PiezoConstants import com.medithings.vesiscan.managers.PiezoConstants
import com.example.medilightv2android.managers.GreenZoneConstants import com.medithings.vesiscan.managers.GreenZoneConstants
import com.example.medilightv2android.managers.PiezoHW import com.medithings.vesiscan.managers.PiezoHW
import com.example.medilightv2android.managers.estimateBladderVolume6ch import com.medithings.vesiscan.managers.estimateBladderVolume6ch
import com.example.medilightv2android.models.BladderLevel import com.medithings.vesiscan.models.BladderLevel
import com.example.medilightv2android.models.UrgencyLevel import com.medithings.vesiscan.models.UrgencyLevel
import com.example.medilightv2android.services.ScanLogStore import com.medithings.vesiscan.services.ScanLogStore
import com.example.medilightv2android.ui.components.BladdyRiveView import com.medithings.vesiscan.ui.components.BladdyRiveView
import com.example.medilightv2android.ui.components.DonutChartView import com.medithings.vesiscan.ui.components.DonutChartView
import com.example.medilightv2android.ui.components.LockableSlider import com.medithings.vesiscan.ui.components.LockableSlider
import com.example.medilightv2android.ui.components.ScanLogDialog import com.medithings.vesiscan.ui.components.ScanLogDialog
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import kotlin.math.roundToInt import kotlin.math.roundToInt
@@ -132,21 +132,21 @@ fun PiezoMonitoringView(appState: AppState) {
val analyzer = remember { PiezoEchoAnalyzer.shared } val analyzer = remember { PiezoEchoAnalyzer.shared }
// Posture (flowchart-based, IMU polling — Phase 1) + Wakeup/Walking detector (Phase 2) // Posture (flowchart-based, IMU polling — Phase 1) + Wakeup/Walking detector (Phase 2)
var currentPosture by remember { mutableStateOf(com.example.medilightv2android.managers.Posture.UNKNOWN) } var currentPosture by remember { mutableStateOf(com.medithings.vesiscan.managers.Posture.UNKNOWN) }
var showWakeupAlarm by remember { mutableStateOf(false) } // 주황 — LYING → NON_LYING/WALKING var showWakeupAlarm by remember { mutableStateOf(false) } // 주황 — LYING → NON_LYING/WALKING
var wakeupAlarmElapsedSec by remember { mutableStateOf(0L) } var wakeupAlarmElapsedSec by remember { mutableStateOf(0L) }
var showWalkingAlarm by remember { mutableStateOf(false) } // 빨강 — NON_LYING → WALKING var showWalkingAlarm by remember { mutableStateOf(false) } // 빨강 — NON_LYING → WALKING
val walkingDetector = remember { com.example.medilightv2android.managers.WalkingDetector() } val walkingDetector = remember { com.medithings.vesiscan.managers.WalkingDetector() }
val wakeupDetector = remember { val wakeupDetector = remember {
com.example.medilightv2android.managers.WakeupDetector( com.medithings.vesiscan.managers.WakeupDetector(
lyingDurationSec = com.example.medilightv2android.services.WakeupAlarmPrefs.lyingDurationSec(context) lyingDurationSec = com.medithings.vesiscan.services.WakeupAlarmPrefs.lyingDurationSec(context)
).apply { ).apply {
onWakeup = { elapsed -> onWakeup = { elapsed ->
if (com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context)) { if (com.medithings.vesiscan.services.WakeupAlarmPrefs.isEnabled(context)) {
wakeupAlarmElapsedSec = elapsed wakeupAlarmElapsedSec = elapsed
showWakeupAlarm = true showWakeupAlarm = true
} }
com.example.medilightv2android.services.PostureEventLogger.logAlarm( com.medithings.vesiscan.services.PostureEventLogger.logAlarm(
System.currentTimeMillis(), System.currentTimeMillis(),
"wakeup_alarm_lying_${elapsed}s" "wakeup_alarm_lying_${elapsed}s"
) )
@@ -317,7 +317,7 @@ fun PiezoMonitoringView(appState: AppState) {
val fullChannels = channels.filter { it.buffer.size >= 20 } val fullChannels = channels.filter { it.buffer.size >= 20 }
if (fullChannels.size >= 6) { if (fullChannels.size >= 6) {
val sortedBuffers = channels.sortedBy { it.channel }.map { it.buffer } val sortedBuffers = channels.sortedBy { it.channel }.map { it.buffer }
val detachResult = com.example.medilightv2android.managers.DetachmentDetection.detect(sortedBuffers) val detachResult = com.medithings.vesiscan.managers.DetachmentDetection.detect(sortedBuffers)
if (detachResult.isDetached) { if (detachResult.isDetached) {
if (!wasDetached) { if (!wasDetached) {
Log.w("PiezoMonitor", "DETACHED mean=${"%.1f".format(detachResult.meanAbs)} std=${"%.1f".format(detachResult.stdVal)}") Log.w("PiezoMonitor", "DETACHED mean=${"%.1f".format(detachResult.meanAbs)} std=${"%.1f".format(detachResult.stdVal)}")
@@ -341,28 +341,28 @@ fun PiezoMonitoringView(appState: AppState) {
val validChannels = channels.filter { it.isValid } val validChannels = channels.filter { it.isValid }
val allChannelsReceived = channels.filter { it.buffer.size >= 20 }.size >= 6 val allChannelsReceived = channels.filter { it.buffer.size >= 20 }.size >= 6
if (validChannels.isNotEmpty() && allChannelsReceived) { if (validChannels.isNotEmpty() && allChannelsReceived) {
val method = com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod val method = com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod
val analyzerA = com.example.medilightv2android.managers.PiezoEchoAnalyzerA.shared val analyzerA = com.medithings.vesiscan.managers.PiezoEchoAnalyzerA.shared
var methodCBvMl: Double? = null var methodCBvMl: Double? = null
val methodLabel: String val methodLabel: String
when (method) { when (method) {
com.example.medilightv2android.managers.DetectionMethod.METHOD_C -> { com.medithings.vesiscan.managers.DetectionMethod.METHOD_C -> {
methodLabel = "C" methodLabel = "C"
// V4.1 detector // V4.1 detector
val v41 = com.example.medilightv2android.walldetect.V41Detector() val v41 = com.medithings.vesiscan.walldetect.V41Detector()
val adcMatrix = (0 until 6).map { ch -> val adcMatrix = (0 until 6).map { ch ->
val chData = channels.find { it.channel == ch } val chData = channels.find { it.channel == ch }
chData?.buffer?.map { it.toInt() } ?: List(100) { 0 } chData?.buffer?.map { it.toInt() } ?: List(100) { 0 }
} }
val probe = com.example.medilightv2android.walldetect.dto.ProbeProfileDto( val probe = com.medithings.vesiscan.walldetect.dto.ProbeProfileDto(
name = com.example.medilightv2android.managers.PiezoHW.presetName, name = com.medithings.vesiscan.managers.PiezoHW.presetName,
rMm = 50.2, anteriorAnchorMm = 32.0, rMm = 50.2, anteriorAnchorMm = 32.0,
fsHz = 537500, cMmPerUs = 1.54, fsHz = 537500, cMmPerUs = 1.54,
anglesDeg = com.example.medilightv2android.managers.PiezoHW.degreeAll.toList() anglesDeg = com.medithings.vesiscan.managers.PiezoHW.degreeAll.toList()
) )
val sweepInput = com.example.medilightv2android.walldetect.dto.SweepInput( val sweepInput = com.medithings.vesiscan.walldetect.dto.SweepInput(
requestId = "measure_${System.currentTimeMillis()}", requestId = "measure_${System.currentTimeMillis()}",
timestampMs = System.currentTimeMillis(), timestampMs = System.currentTimeMillis(),
deviceId = bleManager.connectedDeviceName.value, deviceId = bleManager.connectedDeviceName.value,
@@ -395,7 +395,7 @@ fun PiezoMonitoringView(appState: AppState) {
Log.d("PiezoMonitor", " CH${ch.ch}[C]: ant=${ch.antIdx} post=${ch.postIdx} chord=${ch.chordMm?.let { "%.1f".format(it) }}mm") Log.d("PiezoMonitor", " CH${ch.ch}[C]: ant=${ch.antIdx} post=${ch.postIdx} chord=${ch.chordMm?.let { "%.1f".format(it) }}mm")
} }
} }
com.example.medilightv2android.managers.DetectionMethod.METHOD_A -> { com.medithings.vesiscan.managers.DetectionMethod.METHOD_A -> {
methodLabel = "A" methodLabel = "A"
val channelResults = validChannels.map { analyzerA.analyzeChannel(it.buffer, it.channel) } val channelResults = validChannels.map { analyzerA.analyzeChannel(it.buffer, it.channel) }
for (ch in channelResults) { for (ch in channelResults) {
@@ -407,14 +407,14 @@ fun PiezoMonitoringView(appState: AppState) {
if (ch.isValid && ch.result != null) Log.d("PiezoMonitor", " CH${ch.channel}[A]: ant=${ch.result.ant} post=${ch.result.post} urine=${ch.result.urineLen}") if (ch.isValid && ch.result != null) Log.d("PiezoMonitor", " CH${ch.channel}[A]: ant=${ch.result.ant} post=${ch.result.post} urine=${ch.result.urineLen}")
} }
} }
com.example.medilightv2android.managers.DetectionMethod.METHOD_D -> { com.medithings.vesiscan.managers.DetectionMethod.METHOD_D -> {
// 2026-06-30: Detection + BV 통합. MethodDRunner 로 6채널 raw → walls. // 2026-06-30: Detection + BV 통합. MethodDRunner 로 6채널 raw → walls.
methodLabel = "D" methodLabel = "D"
val signals = (0..5).map { ch -> val signals = (0..5).map { ch ->
val cd = channels.find { it.channel == ch } val cd = channels.find { it.channel == ch }
cd?.buffer?.map { it.toDouble() }?.toDoubleArray() ?: DoubleArray(0) cd?.buffer?.map { it.toDouble() }?.toDoubleArray() ?: DoubleArray(0)
} }
val dets = com.example.medilightv2android.walldetect.MethodDRunner val dets = com.medithings.vesiscan.walldetect.MethodDRunner
.detectMultichannel(signals) .detectMultichannel(signals)
for (i in 0..5) { for (i in 0..5) {
val r = dets.getOrNull(i) val r = dets.getOrNull(i)
@@ -443,10 +443,10 @@ fun PiezoMonitoringView(appState: AppState) {
totalWallCount = allWalls.count { it != null } totalWallCount = allWalls.count { it != null }
// ADC 로그 저장 — allWalls (선택된 Method) 기준으로 통일 // ADC 로그 저장 — allWalls (선택된 Method) 기준으로 통일
val logService = com.example.medilightv2android.services.MeasurementLogService.getInstance(context) val logService = com.medithings.vesiscan.services.MeasurementLogService.getInstance(context)
val channelLogs = (0..5).map { ch -> val channelLogs = (0..5).map { ch ->
val w = allWalls[ch] val w = allWalls[ch]
com.example.medilightv2android.services.ChannelLogEntry( com.medithings.vesiscan.services.ChannelLogEntry(
channel = ch, channel = ch,
ant = w?.first, ant = w?.first,
post = w?.second, post = w?.second,
@@ -456,7 +456,7 @@ fun PiezoMonitoringView(appState: AppState) {
} }
val rawADC = channels.sortedBy { it.channel }.map { it.buffer } val rawADC = channels.sortedBy { it.channel }.map { it.buffer }
val bvMethodSetting = com.example.medilightv2android.managers.GreenZoneConstants.bvMethod val bvMethodSetting = com.medithings.vesiscan.managers.GreenZoneConstants.bvMethod
// ── Ant-offset adjustment for BV calculation ─────────────────────────────── // ── Ant-offset adjustment for BV calculation ───────────────────────────────
// The user-facing setting is a non-negative magnitude in mm. BV calculation // The user-facing setting is a non-negative magnitude in mm. BV calculation
// subtracts it from each channel's anterior wall index (probe-ward shift). // subtracts it from each channel's anterior wall index (probe-ward shift).
@@ -467,13 +467,13 @@ fun PiezoMonitoringView(appState: AppState) {
val antOffsetSamples = val antOffsetSamples =
if (antOffsetMm != 0) if (antOffsetMm != 0)
(antOffsetMm.toDouble() / (antOffsetMm.toDouble() /
com.example.medilightv2android.managers.PiezoHW.distancePerSample).toInt() com.medithings.vesiscan.managers.PiezoHW.distancePerSample).toInt()
else 0 else 0
// 2026-06-30: BvMethod.METHOD_D 시 Method D walls 사용. 단 detection 이 // 2026-06-30: BvMethod.METHOD_D 시 Method D walls 사용. 단 detection 이
// 이미 METHOD_D 면 allWalls 가 곧 Method D → recompute 생략. // 이미 METHOD_D 면 allWalls 가 곧 Method D → recompute 생략.
val useMethodDBv = bvMethodSetting == com.example.medilightv2android.managers.BvMethod.METHOD_D val useMethodDBv = bvMethodSetting == com.medithings.vesiscan.managers.BvMethod.METHOD_D
val detectionIsMethodD = method == com.example.medilightv2android.managers.DetectionMethod.METHOD_D val detectionIsMethodD = method == com.medithings.vesiscan.managers.DetectionMethod.METHOD_D
val sourceAllWalls: List<Pair<Int, Int>?> = if (useMethodDBv && !detectionIsMethodD) { val sourceAllWalls: List<Pair<Int, Int>?> = if (useMethodDBv && !detectionIsMethodD) {
val signals = (0..5).map { ch -> val signals = (0..5).map { ch ->
val cd = channels.find { it.channel == ch } val cd = channels.find { it.channel == ch }
@@ -482,10 +482,10 @@ fun PiezoMonitoringView(appState: AppState) {
if (signals.all { it.isEmpty() }) allWalls if (signals.all { it.isEmpty() }) allWalls
// 2026-07-02: NEW BV lib (piezophantomtest 4830e7c) lumen_inset_frac=0.15 // 2026-07-02: NEW BV lib (piezophantomtest 4830e7c) lumen_inset_frac=0.15
// MethodDResult 의 (ls, le) 로 벽을 lumen 안쪽으로 15% 이동. // MethodDResult 의 (ls, le) 로 벽을 lumen 안쪽으로 15% 이동.
else com.example.medilightv2android.walldetect.MethodDRunner else com.medithings.vesiscan.walldetect.MethodDRunner
.detectMultichannel(signals) .detectMultichannel(signals)
.map { r -> r?.let { .map { r -> r?.let {
com.example.medilightv2android.managers.applyLumenInsetOne( com.medithings.vesiscan.managers.applyLumenInsetOne(
it.ant, it.post, it.lowStart, it.lowEnd it.ant, it.post, it.lowStart, it.lowEnd
) )
} } } }
@@ -498,8 +498,8 @@ fun PiezoMonitoringView(appState: AppState) {
} }
val effectiveCenterWalls = (0..3).count { effectiveAllWalls[it] != null } val effectiveCenterWalls = (0..3).count { effectiveAllWalls[it] != null }
val useV41Bv = method == com.example.medilightv2android.managers.DetectionMethod.METHOD_C val useV41Bv = method == com.medithings.vesiscan.managers.DetectionMethod.METHOD_C
&& bvMethodSetting == com.example.medilightv2android.managers.BvMethod.V41 && bvMethodSetting == com.medithings.vesiscan.managers.BvMethod.V41
&& methodCBvMl != null && methodCBvMl != null
&& antOffsetSamples == 0 && antOffsetSamples == 0
&& effectiveCenterWalls >= 4 // center 4 모두 필요 && effectiveCenterWalls >= 4 // center 4 모두 필요
@@ -510,7 +510,7 @@ fun PiezoMonitoringView(appState: AppState) {
bleManager.debugLogger.measurementResult(methodCBvMl, 1.0, totalWallCount, bleManager.debugLogger.measurementResult(methodCBvMl, 1.0, totalWallCount,
(0..5).map { allWalls[it]?.let { w -> w.second - w.first } ?: 0 }) (0..5).map { allWalls[it]?.let { w -> w.second - w.first } ?: 0 })
logService.logMeasurement(methodCBvMl, channelLogs, rawADC) logService.logMeasurement(methodCBvMl, channelLogs, rawADC)
com.example.medilightv2android.services.AdcCsvLogger.log(rawADC, methodCBvMl) com.medithings.vesiscan.services.AdcCsvLogger.log(rawADC, methodCBvMl)
} else if (effectiveCenterWalls >= 4) { } else if (effectiveCenterWalls >= 4) {
// 검증 로그 — ant offset 비활성(0)이 아닐 때 chord 변화 출력 // 검증 로그 — ant offset 비활성(0)이 아닐 때 chord 변화 출력
if (antOffsetSamples != 0) { if (antOffsetSamples != 0) {
@@ -534,18 +534,18 @@ fun PiezoMonitoringView(appState: AppState) {
(0..5).map { allWalls[it]?.let { w -> w.second - w.first } ?: 0 }, (0..5).map { allWalls[it]?.let { w -> w.second - w.first } ?: 0 },
otsuThreshold = analyzer.lastOtsuThreshold) otsuThreshold = analyzer.lastOtsuThreshold)
logService.logMeasurement(bvResult.volumeMl, channelLogs, rawADC) logService.logMeasurement(bvResult.volumeMl, channelLogs, rawADC)
com.example.medilightv2android.services.AdcCsvLogger.log(rawADC, bvResult.volumeMl, bvResult.lrRatio) com.medithings.vesiscan.services.AdcCsvLogger.log(rawADC, bvResult.volumeMl, bvResult.lrRatio)
} }
} else if (totalWallCount > 0) { } else if (totalWallCount > 0) {
Log.w("PiezoMonitor", "No center channels: center=0 total=$totalWallCount/6") Log.w("PiezoMonitor", "No center channels: center=0 total=$totalWallCount/6")
bleManager.debugLogger.warn("BV_SKIP scan=${com.example.medilightv2android.services.AdcCsvLogger.lastScanId} center=0 total=$totalWallCount/6") bleManager.debugLogger.warn("BV_SKIP scan=${com.medithings.vesiscan.services.AdcCsvLogger.lastScanId} center=0 total=$totalWallCount/6")
com.example.medilightv2android.services.AdcCsvLogger.log(rawADC, null) com.medithings.vesiscan.services.AdcCsvLogger.log(rawADC, null)
} }
} else { } else {
Log.d("PiezoMonitor", "No valid channels — volume unchanged") Log.d("PiezoMonitor", "No valid channels — volume unchanged")
bleManager.debugLogger.warn("BV_FAIL scan=${com.example.medilightv2android.services.AdcCsvLogger.lastScanId} no valid channels") bleManager.debugLogger.warn("BV_FAIL scan=${com.medithings.vesiscan.services.AdcCsvLogger.lastScanId} no valid channels")
val failADC = channels.sortedBy { it.channel }.map { it.buffer } val failADC = channels.sortedBy { it.channel }.map { it.buffer }
com.example.medilightv2android.services.AdcCsvLogger.log(failADC, null) com.medithings.vesiscan.services.AdcCsvLogger.log(failADC, null)
} }
// allWalls를 UI state에 저장 (ChannelPanel에서 사용) // allWalls를 UI state에 저장 (ChannelPanel에서 사용)
@@ -754,8 +754,8 @@ fun PiezoMonitoringView(appState: AppState) {
// Posture event 로깅 — 검증용 CSV (앱 진입 시 새 파일) // Posture event 로깅 — 검증용 CSV (앱 진입 시 새 파일)
// + 사용자 튜닝 임계값 SharedPreferences 에서 로드 // + 사용자 튜닝 임계값 SharedPreferences 에서 로드
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
com.example.medilightv2android.services.PostureTuningPrefs.loadAll(context) com.medithings.vesiscan.services.PostureTuningPrefs.loadAll(context)
com.example.medilightv2android.services.PostureEventLogger.startSession(context) com.medithings.vesiscan.services.PostureEventLogger.startSession(context)
} }
// IMU polling + 자세 분류 — msp 명령 (rsp: 응답, IMU-only). // IMU polling + 자세 분류 — msp 명령 (rsp: 응답, IMU-only).
@@ -766,12 +766,12 @@ fun PiezoMonitoringView(appState: AppState) {
LaunchedEffect(isConnected, isDemoMode) { LaunchedEffect(isConnected, isDemoMode) {
Log.d("ImuDbg", "LaunchedEffect start isConnected=$isConnected isDemoMode=$isDemoMode") Log.d("ImuDbg", "LaunchedEffect start isConnected=$isConnected isDemoMode=$isDemoMode")
if (isDemoMode) { if (isDemoMode) {
currentPosture = com.example.medilightv2android.managers.Posture.LYING currentPosture = com.medithings.vesiscan.managers.Posture.LYING
return@LaunchedEffect return@LaunchedEffect
} }
var unknownStreak = 0 var unknownStreak = 0
bleManager.imuCollector.onComplete = { samples -> bleManager.imuCollector.onComplete = { samples ->
val r = com.example.medilightv2android.managers.ImuPostureClassifier.classify(samples) val r = com.medithings.vesiscan.managers.ImuPostureClassifier.classify(samples)
val nowMs = System.currentTimeMillis() val nowMs = System.currentTimeMillis()
// Walking detector — pitch 가 valid 일 때만 의미. acc gate fail 시 그대로 update (wmean/wstd 계산 + 시간 grace 처리). // Walking detector — pitch 가 valid 일 때만 의미. acc gate fail 시 그대로 update (wmean/wstd 계산 + 시간 grace 처리).
val walkSnap = walkingDetector.update(samples, r.pitchDeg, nowMs) val walkSnap = walkingDetector.update(samples, r.pitchDeg, nowMs)
@@ -779,34 +779,34 @@ fun PiezoMonitoringView(appState: AppState) {
// Composite posture — WALKING 이 UNKNOWN/NON_LYING 보다 우선 (자체 게이트 신뢰) // Composite posture — WALKING 이 UNKNOWN/NON_LYING 보다 우선 (자체 게이트 신뢰)
val composite = when { val composite = when {
isWalkingNow -> com.example.medilightv2android.managers.Posture.WALKING isWalkingNow -> com.medithings.vesiscan.managers.Posture.WALKING
r.posture == com.example.medilightv2android.managers.Posture.UNKNOWN -> com.example.medilightv2android.managers.Posture.UNKNOWN r.posture == com.medithings.vesiscan.managers.Posture.UNKNOWN -> com.medithings.vesiscan.managers.Posture.UNKNOWN
else -> r.posture // LYING or NON_LYING else -> r.posture // LYING or NON_LYING
} }
if (composite != com.example.medilightv2android.managers.Posture.UNKNOWN) { if (composite != com.medithings.vesiscan.managers.Posture.UNKNOWN) {
currentPosture = composite currentPosture = composite
wakeupDetector.update(composite) wakeupDetector.update(composite)
unknownStreak = 0 unknownStreak = 0
} else { } else {
unknownStreak++ unknownStreak++
if (unknownStreak >= 3) currentPosture = com.example.medilightv2android.managers.Posture.UNKNOWN if (unknownStreak >= 3) currentPosture = com.medithings.vesiscan.managers.Posture.UNKNOWN
} }
// Walking 시작 전이 (NON_WALKING → WALKING) — critical 알람 (alarm enabled 시) // Walking 시작 전이 (NON_WALKING → WALKING) — critical 알람 (alarm enabled 시)
if (isWalkingNow && !prevIsWalking) { if (isWalkingNow && !prevIsWalking) {
if (com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context)) { if (com.medithings.vesiscan.services.WakeupAlarmPrefs.isEnabled(context)) {
showWalkingAlarm = true showWalkingAlarm = true
} }
com.example.medilightv2android.services.PostureEventLogger.logAlarm(nowMs, "walking_start") com.medithings.vesiscan.services.PostureEventLogger.logAlarm(nowMs, "walking_start")
} }
if (!isWalkingNow && prevIsWalking) { if (!isWalkingNow && prevIsWalking) {
com.example.medilightv2android.services.PostureEventLogger.logAlarm(nowMs, "walking_end") com.medithings.vesiscan.services.PostureEventLogger.logAlarm(nowMs, "walking_end")
} }
prevIsWalking = isWalkingNow prevIsWalking = isWalkingNow
// CSV logging — 검증용 // CSV logging — 검증용
com.example.medilightv2android.services.PostureEventLogger.logCycle( com.medithings.vesiscan.services.PostureEventLogger.logCycle(
nowMs, composite.name, isWalkingNow, nowMs, composite.name, isWalkingNow,
r.pitchDeg, walkSnap.wmean, walkSnap.wstd, r.accMag, r.gyroMagDps, r.pitchDeg, walkSnap.wmean, walkSnap.wstd, r.accMag, r.gyroMagDps,
) )
@@ -961,8 +961,8 @@ fun PiezoMonitoringView(appState: AppState) {
val quickVol = if (lastVolumeMl > 0) lastVolumeMl.toInt() else appState.estimatedVolume val quickVol = if (lastVolumeMl > 0) lastVolumeMl.toInt() else appState.estimatedVolume
Surface( Surface(
onClick = { onClick = {
com.example.medilightv2android.measure.VoidingRecordStore.add( com.medithings.vesiscan.measure.VoidingRecordStore.add(
context, com.example.medilightv2android.measure.VoidingRecord( context, com.medithings.vesiscan.measure.VoidingRecord(
volume = quickVol, method = "catheterize" volume = quickVol, method = "catheterize"
) )
) )
@@ -1021,8 +1021,8 @@ fun PiezoMonitoringView(appState: AppState) {
TextButton(onClick = { TextButton(onClick = {
val vol = volumeText.toIntOrNull() val vol = volumeText.toIntOrNull()
if (vol != null && vol in 1..1000) { if (vol != null && vol in 1..1000) {
com.example.medilightv2android.measure.VoidingRecordStore.add( com.medithings.vesiscan.measure.VoidingRecordStore.add(
context, com.example.medilightv2android.measure.VoidingRecord(volume = vol, method = "manual") context, com.medithings.vesiscan.measure.VoidingRecord(volume = vol, method = "manual")
) )
appState.resetLevel() appState.resetLevel()
android.widget.Toast.makeText(context, context.getString(R.string.registered_diary), android.widget.Toast.LENGTH_SHORT).show() android.widget.Toast.makeText(context, context.getString(R.string.registered_diary), android.widget.Toast.LENGTH_SHORT).show()
@@ -1038,7 +1038,7 @@ fun PiezoMonitoringView(appState: AppState) {
if (showVoiceInput) { if (showVoiceInput) {
var voiceResult by remember { mutableStateOf<String?>(null) } var voiceResult by remember { mutableStateOf<String?>(null) }
var isListening by remember { mutableStateOf(false) } var isListening by remember { mutableStateOf(false) }
var speechMgr by remember { mutableStateOf<com.example.medilightv2android.speech.SpeechRecognizerManager?>(null) } var speechMgr by remember { mutableStateOf<com.medithings.vesiscan.speech.SpeechRecognizerManager?>(null) }
DisposableEffect(Unit) { onDispose { speechMgr?.destroy() } } DisposableEffect(Unit) { onDispose { speechMgr?.destroy() } }
@@ -1047,14 +1047,14 @@ fun PiezoMonitoringView(appState: AppState) {
if (androidx.core.content.ContextCompat.checkSelfPermission(context, android.Manifest.permission.RECORD_AUDIO) if (androidx.core.content.ContextCompat.checkSelfPermission(context, android.Manifest.permission.RECORD_AUDIO)
== android.content.pm.PackageManager.PERMISSION_GRANTED) { == android.content.pm.PackageManager.PERMISSION_GRANTED) {
isListening = true isListening = true
speechMgr = com.example.medilightv2android.speech.SpeechRecognizerManager( speechMgr = com.medithings.vesiscan.speech.SpeechRecognizerManager(
context = context, context = context,
onResult = { candidates -> onResult = { candidates ->
isListening = false isListening = false
val parsed = com.example.medilightv2android.speech.VolumeParser.parseBest(candidates) val parsed = com.medithings.vesiscan.speech.VolumeParser.parseBest(candidates)
if (parsed != null) { if (parsed != null) {
com.example.medilightv2android.measure.VoidingRecordStore.add( com.medithings.vesiscan.measure.VoidingRecordStore.add(
context, com.example.medilightv2android.measure.VoidingRecord(volume = parsed.volumeMl, method = "voice") context, com.medithings.vesiscan.measure.VoidingRecord(volume = parsed.volumeMl, method = "voice")
) )
appState.resetLevel() appState.resetLevel()
android.widget.Toast.makeText(context, context.getString(R.string.registered_ml, parsed.volumeMl), android.widget.Toast.LENGTH_SHORT).show() android.widget.Toast.makeText(context, context.getString(R.string.registered_ml, parsed.volumeMl), android.widget.Toast.LENGTH_SHORT).show()
@@ -1168,19 +1168,19 @@ fun PiezoMonitoringView(appState: AppState) {
// Dev mode 에서만 노출 (legacy 유지) — 일반 사용자에겐 숨김. // Dev mode 에서만 노출 (legacy 유지) — 일반 사용자에겐 숨김.
if (appState.isDevMode) { if (appState.isDevMode) {
var rawBleCapturing by remember { var rawBleCapturing by remember {
mutableStateOf(com.example.medilightv2android.services.RawBleLogger.isCapturing) mutableStateOf(com.medithings.vesiscan.services.RawBleLogger.isCapturing)
} }
IconButton( IconButton(
onClick = { onClick = {
if (rawBleCapturing) { if (rawBleCapturing) {
val f = com.example.medilightv2android.services.RawBleLogger.stopCapture() val f = com.medithings.vesiscan.services.RawBleLogger.stopCapture()
val n = com.example.medilightv2android.services.RawBleLogger.count val n = com.medithings.vesiscan.services.RawBleLogger.count
rawBleCapturing = false rawBleCapturing = false
android.widget.Toast.makeText(context, android.widget.Toast.makeText(context,
"Raw BLE: $n packets saved to ${f?.name}", "Raw BLE: $n packets saved to ${f?.name}",
android.widget.Toast.LENGTH_LONG).show() android.widget.Toast.LENGTH_LONG).show()
} else { } else {
val f = com.example.medilightv2android.services.RawBleLogger.startCapture() val f = com.medithings.vesiscan.services.RawBleLogger.startCapture()
rawBleCapturing = true rawBleCapturing = true
android.widget.Toast.makeText(context, android.widget.Toast.makeText(context,
"Raw BLE capture started → ${f.name}", "Raw BLE capture started → ${f.name}",
@@ -1256,8 +1256,8 @@ fun PiezoMonitoringView(appState: AppState) {
// BLE 끊김 banner는 사내 테스트 피드백으로 제거됨 — 백그라운드 자동 재연결만 유지. // BLE 끊김 banner는 사내 테스트 피드백으로 제거됨 — 백그라운드 자동 재연결만 유지.
// 펌웨어 구버전 경고 // 펌웨어 구버전 경고
com.example.medilightv2android.ui.components.FirmwareWarningBanner(bleManager) com.medithings.vesiscan.ui.components.FirmwareWarningBanner(bleManager)
com.example.medilightv2android.ui.components.BatteryWarningBanner(bleManager) com.medithings.vesiscan.ui.components.BatteryWarningBanner(bleManager)
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
LaunchedEffect(showSettings) { LaunchedEffect(showSettings) {
@@ -1306,22 +1306,22 @@ fun PiezoMonitoringView(appState: AppState) {
label = "posture-chip" label = "posture-chip"
) { posture -> ) { posture ->
val icon = when (posture) { val icon = when (posture) {
com.example.medilightv2android.managers.Posture.LYING -> Icons.Default.Hotel com.medithings.vesiscan.managers.Posture.LYING -> Icons.Default.Hotel
com.example.medilightv2android.managers.Posture.NON_LYING -> Icons.Default.AccessibilityNew com.medithings.vesiscan.managers.Posture.NON_LYING -> Icons.Default.AccessibilityNew
com.example.medilightv2android.managers.Posture.WALKING -> Icons.Default.DirectionsWalk com.medithings.vesiscan.managers.Posture.WALKING -> Icons.Default.DirectionsWalk
com.example.medilightv2android.managers.Posture.UNKNOWN -> Icons.Default.HelpOutline com.medithings.vesiscan.managers.Posture.UNKNOWN -> Icons.Default.HelpOutline
} }
val tint = when (posture) { val tint = when (posture) {
com.example.medilightv2android.managers.Posture.LYING -> Color(0xFF2196F3) com.medithings.vesiscan.managers.Posture.LYING -> Color(0xFF2196F3)
com.example.medilightv2android.managers.Posture.NON_LYING -> Color(0xFF4CAF50) com.medithings.vesiscan.managers.Posture.NON_LYING -> Color(0xFF4CAF50)
com.example.medilightv2android.managers.Posture.WALKING -> Color(0xFFD32F2F) com.medithings.vesiscan.managers.Posture.WALKING -> Color(0xFFD32F2F)
com.example.medilightv2android.managers.Posture.UNKNOWN -> Color(0xFF616161) // 진한 회색 — 가시성 확보 com.medithings.vesiscan.managers.Posture.UNKNOWN -> Color(0xFF616161) // 진한 회색 — 가시성 확보
} }
val label = when (posture) { val label = when (posture) {
com.example.medilightv2android.managers.Posture.LYING -> stringResource(R.string.piezo_posture_lying) com.medithings.vesiscan.managers.Posture.LYING -> stringResource(R.string.piezo_posture_lying)
com.example.medilightv2android.managers.Posture.NON_LYING -> stringResource(R.string.piezo_posture_upright) com.medithings.vesiscan.managers.Posture.NON_LYING -> stringResource(R.string.piezo_posture_upright)
com.example.medilightv2android.managers.Posture.WALKING -> stringResource(R.string.piezo_posture_walking) com.medithings.vesiscan.managers.Posture.WALKING -> stringResource(R.string.piezo_posture_walking)
com.example.medilightv2android.managers.Posture.UNKNOWN -> stringResource(R.string.piezo_posture_detecting) com.medithings.vesiscan.managers.Posture.UNKNOWN -> stringResource(R.string.piezo_posture_detecting)
} }
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
@@ -1458,8 +1458,8 @@ fun PiezoMonitoringView(appState: AppState) {
Button( Button(
onClick = { onClick = {
val quickVol = if (lastVolumeMl > 0) lastVolumeMl.toInt() else appState.estimatedVolume val quickVol = if (lastVolumeMl > 0) lastVolumeMl.toInt() else appState.estimatedVolume
com.example.medilightv2android.measure.VoidingRecordStore.add( com.medithings.vesiscan.measure.VoidingRecordStore.add(
context, com.example.medilightv2android.measure.VoidingRecord( context, com.medithings.vesiscan.measure.VoidingRecord(
volume = quickVol, method = "catheterize" volume = quickVol, method = "catheterize"
) )
) )
@@ -1847,22 +1847,22 @@ fun PiezoMonitoringView(appState: AppState) {
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding)) HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
// Detection Method A/B/C // Detection Method A/B/C
var selectedMethod by remember { mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod) } var selectedMethod by remember { mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod) }
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text("Detection", fontSize = labelSize, fontWeight = FontWeight.SemiBold) Text("Detection", fontSize = labelSize, fontWeight = FontWeight.SemiBold)
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
val methods = listOf( val methods = listOf(
com.example.medilightv2android.managers.DetectionMethod.METHOD_A to "A", com.medithings.vesiscan.managers.DetectionMethod.METHOD_A to "A",
com.example.medilightv2android.managers.DetectionMethod.METHOD_B to "B", com.medithings.vesiscan.managers.DetectionMethod.METHOD_B to "B",
com.example.medilightv2android.managers.DetectionMethod.METHOD_C to "C", com.medithings.vesiscan.managers.DetectionMethod.METHOD_C to "C",
com.example.medilightv2android.managers.DetectionMethod.METHOD_D to "D" com.medithings.vesiscan.managers.DetectionMethod.METHOD_D to "D"
) )
val colors = listOf(Color(0xFF9C27B0), MlPrimary, Color(0xFFFF5722), Color(0xFF7C3AED)) val colors = listOf(Color(0xFF9C27B0), MlPrimary, Color(0xFFFF5722), Color(0xFF7C3AED))
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
methods.forEachIndexed { idx, (m, label) -> methods.forEachIndexed { idx, (m, label) ->
val sel = selectedMethod == m val sel = selectedMethod == m
Button( Button(
onClick = { selectedMethod = m; com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod = m }, onClick = { selectedMethod = m; com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod = m },
modifier = Modifier.height(32.dp), modifier = Modifier.height(32.dp),
shape = RoundedCornerShape(8.dp), shape = RoundedCornerShape(8.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
@@ -1880,21 +1880,21 @@ fun PiezoMonitoringView(appState: AppState) {
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding)) HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
// BV Method (Frustum / V41) // BV Method (Frustum / V41)
var selectedBvMethod by remember { mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.bvMethod) } var selectedBvMethod by remember { mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.bvMethod) }
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text("BV", fontSize = labelSize, fontWeight = FontWeight.SemiBold) Text("BV", fontSize = labelSize, fontWeight = FontWeight.SemiBold)
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
val bvMethods = listOf( val bvMethods = listOf(
com.example.medilightv2android.managers.BvMethod.FRUSTUM to "Frustum", com.medithings.vesiscan.managers.BvMethod.FRUSTUM to "Frustum",
com.example.medilightv2android.managers.BvMethod.V41 to "V41", com.medithings.vesiscan.managers.BvMethod.V41 to "V41",
com.example.medilightv2android.managers.BvMethod.METHOD_D to "Method D" com.medithings.vesiscan.managers.BvMethod.METHOD_D to "Method D"
) )
val bvColors = listOf(MlPrimary, Color(0xFFFF5722), Color(0xFF7C3AED)) val bvColors = listOf(MlPrimary, Color(0xFFFF5722), Color(0xFF7C3AED))
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
bvMethods.forEachIndexed { idx, (m, label) -> bvMethods.forEachIndexed { idx, (m, label) ->
val sel = selectedBvMethod == m val sel = selectedBvMethod == m
Button( Button(
onClick = { selectedBvMethod = m; com.example.medilightv2android.managers.GreenZoneConstants.bvMethod = m }, onClick = { selectedBvMethod = m; com.medithings.vesiscan.managers.GreenZoneConstants.bvMethod = m },
modifier = Modifier.height(32.dp), modifier = Modifier.height(32.dp),
shape = RoundedCornerShape(8.dp), shape = RoundedCornerShape(8.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
@@ -1913,7 +1913,7 @@ fun PiezoMonitoringView(appState: AppState) {
// 2026-07-01: lr_ratio override (algorithm 팀 4830e7c 표준) // 2026-07-01: lr_ratio override (algorithm 팀 4830e7c 표준)
var lrFixed by remember { var lrFixed by remember {
mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.lrRatioOverride != null) mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.lrRatioOverride != null)
} }
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text("lr=1.0 fixed", fontSize = labelSize, fontWeight = FontWeight.SemiBold) Text("lr=1.0 fixed", fontSize = labelSize, fontWeight = FontWeight.SemiBold)
@@ -1921,7 +1921,7 @@ fun PiezoMonitoringView(appState: AppState) {
Switch(checked = lrFixed, Switch(checked = lrFixed,
onCheckedChange = { onCheckedChange = {
lrFixed = it lrFixed = it
com.example.medilightv2android.managers.GreenZoneConstants.lrRatioOverride = com.medithings.vesiscan.managers.GreenZoneConstants.lrRatioOverride =
if (it) 1.0 else null if (it) 1.0 else null
}, },
colors = SwitchDefaults.colors(checkedTrackColor = MlPrimary)) colors = SwitchDefaults.colors(checkedTrackColor = MlPrimary))
@@ -1970,7 +1970,7 @@ fun PiezoMonitoringView(appState: AppState) {
LockableSlider( LockableSlider(
value = pitchThrVal, value = pitchThrVal,
onValueChange = { pitchThrVal = it; GreenZoneConstants.pitchLyingThreshold = it onValueChange = { pitchThrVal = it; GreenZoneConstants.pitchLyingThreshold = it
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) }, com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context) },
valueRange = 10f..70f, valueRange = 10f..70f,
steps = 11, steps = 11,
colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary) colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)
@@ -1980,7 +1980,7 @@ fun PiezoMonitoringView(appState: AppState) {
// Wakeup Alarm toggle (Personalization 페이지 와 동일 prefs) // Wakeup Alarm toggle (Personalization 페이지 와 동일 prefs)
var wakeupEnabled by remember { var wakeupEnabled by remember {
mutableStateOf(com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context)) mutableStateOf(com.medithings.vesiscan.services.WakeupAlarmPrefs.isEnabled(context))
} }
Row(verticalAlignment = Alignment.CenterVertically, Row(verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()) { modifier = Modifier.fillMaxWidth()) {
@@ -1993,7 +1993,7 @@ fun PiezoMonitoringView(appState: AppState) {
checked = wakeupEnabled, checked = wakeupEnabled,
onCheckedChange = { onCheckedChange = {
wakeupEnabled = it wakeupEnabled = it
com.example.medilightv2android.services.WakeupAlarmPrefs.setEnabled(context, it) com.medithings.vesiscan.services.WakeupAlarmPrefs.setEnabled(context, it)
}, },
colors = SwitchDefaults.colors(checkedTrackColor = Color(0xFFD32F2F)) colors = SwitchDefaults.colors(checkedTrackColor = Color(0xFFD32F2F))
) )
@@ -2002,7 +2002,7 @@ fun PiezoMonitoringView(appState: AppState) {
// Wakeup 알람 발동을 위한 LYING 유지 시간 (dev 조절 가능) // Wakeup 알람 발동을 위한 LYING 유지 시간 (dev 조절 가능)
var lyingDurVal by remember { var lyingDurVal by remember {
mutableStateOf( mutableStateOf(
com.example.medilightv2android.services.WakeupAlarmPrefs.lyingDurationSec(context).toFloat() com.medithings.vesiscan.services.WakeupAlarmPrefs.lyingDurationSec(context).toFloat()
) )
} }
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
@@ -2021,7 +2021,7 @@ fun PiezoMonitoringView(appState: AppState) {
onValueChange = { onValueChange = {
lyingDurVal = it lyingDurVal = it
val sec = it.toInt() val sec = it.toInt()
com.example.medilightv2android.services.WakeupAlarmPrefs.setLyingDurationSec(context, sec) com.medithings.vesiscan.services.WakeupAlarmPrefs.setLyingDurationSec(context, sec)
wakeupDetector.lyingDurationSec = sec wakeupDetector.lyingDurationSec = sec
}, },
valueRange = 5f..600f, // 5초 ~ 10분 valueRange = 5f..600f, // 5초 ~ 10분
@@ -2046,7 +2046,7 @@ fun PiezoMonitoringView(appState: AppState) {
onValueChange = { onValueChange = {
pollIntervalVal = it pollIntervalVal = it
GreenZoneConstants.posturePollIntervalMs = (it * 1000).toLong() GreenZoneConstants.posturePollIntervalMs = (it * 1000).toLong()
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
}, },
valueRange = 1f..15f, // 1초 ~ 15초 valueRange = 1f..15f, // 1초 ~ 15초
steps = 0, steps = 0,
@@ -2066,7 +2066,7 @@ fun PiezoMonitoringView(appState: AppState) {
} }
LockableSlider(value = walkPitchVal, onValueChange = { LockableSlider(value = walkPitchVal, onValueChange = {
walkPitchVal = it; GreenZoneConstants.walkingMinPitchDeg = it walkPitchVal = it; GreenZoneConstants.walkingMinPitchDeg = it
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
}, valueRange = 20f..70f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)) }, valueRange = 20f..70f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
var walkStartWmean by remember { mutableStateOf(GreenZoneConstants.walkingStartWmean) } var walkStartWmean by remember { mutableStateOf(GreenZoneConstants.walkingStartWmean) }
@@ -2077,7 +2077,7 @@ fun PiezoMonitoringView(appState: AppState) {
} }
LockableSlider(value = walkStartWmean, onValueChange = { LockableSlider(value = walkStartWmean, onValueChange = {
walkStartWmean = it; GreenZoneConstants.walkingStartWmean = it walkStartWmean = it; GreenZoneConstants.walkingStartWmean = it
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
}, valueRange = 1f..30f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)) }, valueRange = 1f..30f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
var walkStartWstd by remember { mutableStateOf(GreenZoneConstants.walkingStartWstd) } var walkStartWstd by remember { mutableStateOf(GreenZoneConstants.walkingStartWstd) }
@@ -2088,7 +2088,7 @@ fun PiezoMonitoringView(appState: AppState) {
} }
LockableSlider(value = walkStartWstd, onValueChange = { LockableSlider(value = walkStartWstd, onValueChange = {
walkStartWstd = it; GreenZoneConstants.walkingStartWstd = it walkStartWstd = it; GreenZoneConstants.walkingStartWstd = it
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
}, valueRange = 0.5f..10f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)) }, valueRange = 0.5f..10f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
var walkKeepWmean by remember { mutableStateOf(GreenZoneConstants.walkingKeepWmean) } var walkKeepWmean by remember { mutableStateOf(GreenZoneConstants.walkingKeepWmean) }
@@ -2099,7 +2099,7 @@ fun PiezoMonitoringView(appState: AppState) {
} }
LockableSlider(value = walkKeepWmean, onValueChange = { LockableSlider(value = walkKeepWmean, onValueChange = {
walkKeepWmean = it; GreenZoneConstants.walkingKeepWmean = it walkKeepWmean = it; GreenZoneConstants.walkingKeepWmean = it
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
}, valueRange = 0.5f..30f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)) }, valueRange = 0.5f..30f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
// Walking 시간 변수 (sec) // Walking 시간 변수 (sec)
@@ -2111,7 +2111,7 @@ fun PiezoMonitoringView(appState: AppState) {
} }
LockableSlider(value = walkStartHold, onValueChange = { LockableSlider(value = walkStartHold, onValueChange = {
walkStartHold = it; GreenZoneConstants.walkingStartHoldMs = (it * 1000).toLong() walkStartHold = it; GreenZoneConstants.walkingStartHoldMs = (it * 1000).toLong()
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
}, valueRange = 0.5f..10f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)) }, valueRange = 0.5f..10f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
var walkKeepHold by remember { mutableStateOf(GreenZoneConstants.walkingKeepHoldMs / 1000f) } var walkKeepHold by remember { mutableStateOf(GreenZoneConstants.walkingKeepHoldMs / 1000f) }
@@ -2122,7 +2122,7 @@ fun PiezoMonitoringView(appState: AppState) {
} }
LockableSlider(value = walkKeepHold, onValueChange = { LockableSlider(value = walkKeepHold, onValueChange = {
walkKeepHold = it; GreenZoneConstants.walkingKeepHoldMs = (it * 1000).toLong() walkKeepHold = it; GreenZoneConstants.walkingKeepHoldMs = (it * 1000).toLong()
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
}, valueRange = 0.5f..10f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)) }, valueRange = 0.5f..10f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
var walkWindow by remember { mutableStateOf(GreenZoneConstants.walkingWindowMs / 1000f) } var walkWindow by remember { mutableStateOf(GreenZoneConstants.walkingWindowMs / 1000f) }
@@ -2133,7 +2133,7 @@ fun PiezoMonitoringView(appState: AppState) {
} }
LockableSlider(value = walkWindow, onValueChange = { LockableSlider(value = walkWindow, onValueChange = {
walkWindow = it; GreenZoneConstants.walkingWindowMs = (it * 1000).toLong() walkWindow = it; GreenZoneConstants.walkingWindowMs = (it * 1000).toLong()
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
}, valueRange = 0.5f..5f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)) }, valueRange = 0.5f..5f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding)) HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
@@ -2149,7 +2149,7 @@ fun PiezoMonitoringView(appState: AppState) {
} }
LockableSlider(value = accMagMin, onValueChange = { LockableSlider(value = accMagMin, onValueChange = {
accMagMin = it; GreenZoneConstants.postureAccMagMin = it accMagMin = it; GreenZoneConstants.postureAccMagMin = it
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
}, valueRange = 0.3f..1.0f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)) }, valueRange = 0.3f..1.0f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
var accMagMax by remember { mutableStateOf(GreenZoneConstants.postureAccMagMax) } var accMagMax by remember { mutableStateOf(GreenZoneConstants.postureAccMagMax) }
@@ -2160,7 +2160,7 @@ fun PiezoMonitoringView(appState: AppState) {
} }
LockableSlider(value = accMagMax, onValueChange = { LockableSlider(value = accMagMax, onValueChange = {
accMagMax = it; GreenZoneConstants.postureAccMagMax = it accMagMax = it; GreenZoneConstants.postureAccMagMax = it
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
}, valueRange = 1.0f..3.0f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)) }, valueRange = 1.0f..3.0f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding)) HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
@@ -2168,7 +2168,7 @@ fun PiezoMonitoringView(appState: AppState) {
// Reset to defaults — 모든 threshold 를 default 로 복원 + prefs 저장. // Reset to defaults — 모든 threshold 를 default 로 복원 + prefs 저장.
OutlinedButton( OutlinedButton(
onClick = { onClick = {
com.example.medilightv2android.services.PostureTuningPrefs.resetAll(context) com.medithings.vesiscan.services.PostureTuningPrefs.resetAll(context)
android.widget.Toast.makeText(context, android.widget.Toast.makeText(context,
"Defaults restored — close & reopen Settings to refresh sliders", "Defaults restored — close & reopen Settings to refresh sliders",
android.widget.Toast.LENGTH_LONG).show() android.widget.Toast.LENGTH_LONG).show()
@@ -2201,7 +2201,7 @@ fun PiezoMonitoringView(appState: AppState) {
for ((tag, label) in annotateLabels) { for ((tag, label) in annotateLabels) {
Button( Button(
onClick = { onClick = {
com.example.medilightv2android.services.PostureEventLogger.annotate(tag) com.medithings.vesiscan.services.PostureEventLogger.annotate(tag)
android.widget.Toast.makeText(context, android.widget.Toast.makeText(context,
"Marked: $label", android.widget.Toast.LENGTH_SHORT).show() "Marked: $label", android.widget.Toast.LENGTH_SHORT).show()
}, },
@@ -2281,7 +2281,7 @@ fun PiezoMonitoringView(appState: AppState) {
Text(stringResource(R.string.piezo_settings_app), fontSize = 13.sp, color = MlSecondaryText) Text(stringResource(R.string.piezo_settings_app), fontSize = 13.sp, color = MlSecondaryText)
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
Text( Text(
com.example.medilightv2android.BuildConfig.VERSION_NAME, com.medithings.vesiscan.BuildConfig.VERSION_NAME,
fontSize = 13.sp, fontSize = 13.sp,
fontWeight = FontWeight.SemiBold, fontWeight = FontWeight.SemiBold,
color = MlPrimary, color = MlPrimary,
@@ -2378,7 +2378,7 @@ fun PiezoMonitoringView(appState: AppState) {
Button(onClick = { Button(onClick = {
showRealignPrompt = false showRealignPrompt = false
autoFailCount = 0 autoFailCount = 0
appState.currentScreen = com.example.medilightv2android.AppScreen.PLACEMENT_GUIDE appState.currentScreen = com.medithings.vesiscan.AppScreen.PLACEMENT_GUIDE
}) { Text(stringResource(R.string.piezo_realign_button)) } }) { Text(stringResource(R.string.piezo_realign_button)) }
}, },
dismissButton = { dismissButton = {
@@ -2443,11 +2443,11 @@ private fun ChannelPanel(
} }
} else { } else {
// Zone indicator // Zone indicator
val curMethod = com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod val curMethod = com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod
val analyzerAPanel = com.example.medilightv2android.managers.PiezoEchoAnalyzerA.shared val analyzerAPanel = com.medithings.vesiscan.managers.PiezoEchoAnalyzerA.shared
val analyses = lastMultiChannelResult.map { chData -> val analyses = lastMultiChannelResult.map { chData ->
when (curMethod) { when (curMethod) {
com.example.medilightv2android.managers.DetectionMethod.METHOD_A -> analyzerAPanel.analyzeChannel(chData.buffer, chData.channel) com.medithings.vesiscan.managers.DetectionMethod.METHOD_A -> analyzerAPanel.analyzeChannel(chData.buffer, chData.channel)
else -> analyzer.analyzeChannel(chData.buffer, chData.channel) else -> analyzer.analyzeChannel(chData.buffer, chData.channel)
} }
} }
@@ -2509,7 +2509,7 @@ private fun ChannelPanel(
// Per-channel waveforms // Per-channel waveforms
for (chData in lastMultiChannelResult.filter { it.buffer.isNotEmpty() }) { for (chData in lastMultiChannelResult.filter { it.buffer.isNotEmpty() }) {
val chAnalysis = when (curMethod) { val chAnalysis = when (curMethod) {
com.example.medilightv2android.managers.DetectionMethod.METHOD_A -> analyzerAPanel.analyzeChannel(chData.buffer, chData.channel) com.medithings.vesiscan.managers.DetectionMethod.METHOD_A -> analyzerAPanel.analyzeChannel(chData.buffer, chData.channel)
else -> analyzer.analyzeChannel(chData.buffer, chData.channel) else -> analyzer.analyzeChannel(chData.buffer, chData.channel)
} }
@@ -2537,8 +2537,8 @@ private fun ChannelPanel(
fontSize = 10.sp, fontWeight = FontWeight.SemiBold, color = Color.Cyan fontSize = 10.sp, fontWeight = FontWeight.SemiBold, color = Color.Cyan
) )
Spacer(modifier = Modifier.width(4.dp)) Spacer(modifier = Modifier.width(4.dp))
val dps = com.example.medilightv2android.managers.PiezoHW.distancePerSample val dps = com.medithings.vesiscan.managers.PiezoHW.distancePerSample
val offset = com.example.medilightv2android.managers.PiezoHW.delayOffsetMm val offset = com.medithings.vesiscan.managers.PiezoHW.delayOffsetMm
Text( Text(
"(${"%.0f".format(offset + antIdx * dps)}–${"%.0f".format(offset + postIdx * dps)}mm)", "(${"%.0f".format(offset + antIdx * dps)}–${"%.0f".format(offset + postIdx * dps)}mm)",
fontSize = 9.sp, color = MlSecondaryText fontSize = 9.sp, color = MlSecondaryText
@@ -2804,13 +2804,13 @@ private fun BleDebugPanel(bleManager: BleManager) {
) { ) {
for (entry in entries) { for (entry in entries) {
val color = when (entry.level) { val color = when (entry.level) {
com.example.medilightv2android.services.BleDebugLogger.Level.TX -> Color(0xFF64B5F6) com.medithings.vesiscan.services.BleDebugLogger.Level.TX -> Color(0xFF64B5F6)
com.example.medilightv2android.services.BleDebugLogger.Level.RX -> Color(0xFF81C784) com.medithings.vesiscan.services.BleDebugLogger.Level.RX -> Color(0xFF81C784)
com.example.medilightv2android.services.BleDebugLogger.Level.ERROR -> Color.Red com.medithings.vesiscan.services.BleDebugLogger.Level.ERROR -> Color.Red
com.example.medilightv2android.services.BleDebugLogger.Level.WARN -> Color(0xFFFFB74D) com.medithings.vesiscan.services.BleDebugLogger.Level.WARN -> Color(0xFFFFB74D)
com.example.medilightv2android.services.BleDebugLogger.Level.RSSI -> Color(0xFFFFD54F) com.medithings.vesiscan.services.BleDebugLogger.Level.RSSI -> Color(0xFFFFD54F)
com.example.medilightv2android.services.BleDebugLogger.Level.CONN -> Color(0xFFCE93D8) com.medithings.vesiscan.services.BleDebugLogger.Level.CONN -> Color(0xFFCE93D8)
com.example.medilightv2android.services.BleDebugLogger.Level.INFO -> Color.White com.medithings.vesiscan.services.BleDebugLogger.Level.INFO -> Color.White
} }
Text( Text(
entry.toLogLine(), entry.toLogLine(),
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.monitoring package com.medithings.vesiscan.ui.views.monitoring
import android.util.Log import android.util.Log
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
@@ -44,17 +44,17 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.withStyle import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppScreen import com.medithings.vesiscan.AppScreen
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
import com.example.medilightv2android.ble.PiezoChannelData import com.medithings.vesiscan.ble.PiezoChannelData
import com.example.medilightv2android.managers.DetachmentDetection import com.medithings.vesiscan.managers.DetachmentDetection
import com.example.medilightv2android.managers.PiezoEchoAnalyzer import com.medithings.vesiscan.managers.PiezoEchoAnalyzer
import com.example.medilightv2android.managers.PiezoHW import com.medithings.vesiscan.managers.PiezoHW
import com.example.medilightv2android.managers.UrinAI import com.medithings.vesiscan.managers.UrinAI
import com.example.medilightv2android.services.MeasurementLogService import com.medithings.vesiscan.services.MeasurementLogService
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
/** /**
* Sensor Alignment Guide -- shown after BLE connection, before measurement. * Sensor Alignment Guide -- shown after BLE connection, before measurement.
@@ -80,8 +80,8 @@ fun PlacementGuideView(appState: AppState) {
var phaseHoldHint by remember { mutableStateOf("") } // 강제 힌트 var phaseHoldHint by remember { mutableStateOf("") } // 강제 힌트
val channelDetected = remember { mutableStateListOf(false, false, false, false, false, false) } val channelDetected = remember { mutableStateListOf(false, false, false, false, false, false) }
val channelUrineLen = remember { mutableStateListOf(0, 0, 0, 0, 0, 0) } val channelUrineLen = remember { mutableStateListOf(0, 0, 0, 0, 0, 0) }
val isSweepMode = com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode == val isSweepMode = com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode ==
com.example.medilightv2android.managers.PlacementGuideMode.SWEEP com.medithings.vesiscan.managers.PlacementGuideMode.SWEEP
var directionHint by remember { mutableStateOf( var directionHint by remember { mutableStateOf(
if (isSweepMode) context.getString(R.string.placement_sweep_initial) if (isSweepMode) context.getString(R.string.placement_sweep_initial)
else context.getString(R.string.placement_initial_hint) else context.getString(R.string.placement_initial_hint)
@@ -96,16 +96,16 @@ fun PlacementGuideView(appState: AppState) {
var greenFailCount by remember { mutableIntStateOf(0) } // GREEN 이탈 디바운스 var greenFailCount by remember { mutableIntStateOf(0) } // GREEN 이탈 디바운스
var lastChannelData by remember { mutableStateOf<List<PiezoChannelData>>(emptyList()) } var lastChannelData by remember { mutableStateOf<List<PiezoChannelData>>(emptyList()) }
// 최근 IMU 샘플 (15개, ODR 50Hz, ~300ms 분량). 자세 판정/흔들림 감지/임상 로그용. // 최근 IMU 샘플 (15개, ODR 50Hz, ~300ms 분량). 자세 판정/흔들림 감지/임상 로그용.
var lastImuSamples by remember { mutableStateOf<List<com.example.medilightv2android.ble.ImuSample>>(emptyList()) } var lastImuSamples by remember { mutableStateOf<List<com.medithings.vesiscan.ble.ImuSample>>(emptyList()) }
var lastWallResults by remember { mutableStateOf<List<Pair<Int, Int>?>>(List(6) { null }) } var lastWallResults by remember { mutableStateOf<List<Pair<Int, Int>?>>(List(6) { null }) }
var debounceCount by remember { mutableIntStateOf(0) } var debounceCount by remember { mutableIntStateOf(0) }
var lastGuidePhase by remember { mutableStateOf(PlacementPhase.VERTICAL) } var lastGuidePhase by remember { mutableStateOf(PlacementPhase.VERTICAL) }
var lastHintChangeMs by remember { mutableStateOf(0L) } var lastHintChangeMs by remember { mutableStateOf(0L) }
// V2 alignment (alignment.py 포팅) — dev 토글로 활성화. // V2 alignment (alignment.py 포팅) — dev 토글로 활성화.
val v2Aligner = remember { com.example.medilightv2android.managers.RollingAligner() } val v2Aligner = remember { com.medithings.vesiscan.managers.RollingAligner() }
// SWEEP 모드용 sphere-fit state // SWEEP 모드용 sphere-fit state
val rTracker = remember { com.example.medilightv2android.managers.BladderSeekRTracker() } val rTracker = remember { com.medithings.vesiscan.managers.BladderSeekRTracker() }
var currentRMm by remember { mutableStateOf<Double?>(null) } var currentRMm by remember { mutableStateOf<Double?>(null) }
var bestRMm by remember { mutableStateOf(0.0) } var bestRMm by remember { mutableStateOf(0.0) }
var sagittalArgMaxCh by remember { mutableStateOf<Int?>(null) } var sagittalArgMaxCh by remember { mutableStateOf<Int?>(null) }
@@ -127,13 +127,13 @@ fun PlacementGuideView(appState: AppState) {
// V2 (4-stage Method D) 는 R&D/clinical alignment session 전용. // V2 (4-stage Method D) 는 R&D/clinical alignment session 전용.
// 일반 사용자 flow (Home → Start → Personalization → PlacementGuide) 는 V1 사용. // 일반 사용자 flow (Home → Start → Personalization → PlacementGuide) 는 V1 사용.
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
val sess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession val sess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession
val isClinicalAlign = !appState.placementFromMonitoring && val isClinicalAlign = !appState.placementFromMonitoring &&
sess != null && sess != null &&
sess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT sess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT
com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo =
if (isClinicalAlign) com.example.medilightv2android.managers.AlignmentAlgo.V2 if (isClinicalAlign) com.medithings.vesiscan.managers.AlignmentAlgo.V2
else com.example.medilightv2android.managers.AlignmentAlgo.V1 else com.medithings.vesiscan.managers.AlignmentAlgo.V1
v2Aligner.reset() v2Aligner.reset()
// Clinical alignment session 진입 시 — 자동으로 scan 시작 (Step 0 baseline 캡쳐). // Clinical alignment session 진입 시 — 자동으로 scan 시작 (Step 0 baseline 캡쳐).
// waitingForStart 는 true 유지 — 사용자는 여전히 Start 눌러 알고리즘 시작 결정. // waitingForStart 는 true 유지 — 사용자는 여전히 Start 눌러 알고리즘 시작 결정.
@@ -256,10 +256,10 @@ fun PlacementGuideView(appState: AppState) {
// Clinical alignment session 진입한 경우 — 저장 후 Clinical Home 으로. // Clinical alignment session 진입한 경우 — 저장 후 Clinical Home 으로.
// (PiezoMonitoring / Personalization 으로 떨어지지 않게) // (PiezoMonitoring / Personalization 으로 떨어지지 않게)
// Back / Skip 도 endMeasurement → measurement.json + labdb 자동 업로드 (Complete 와 동일). // Back / Skip 도 endMeasurement → measurement.json + labdb 자동 업로드 (Complete 와 동일).
val curSess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession val curSess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession
if (curSess != null && curSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT) { if (curSess != null && curSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT) {
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context) com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context)
com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = true com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow = true
appState.currentScreen = AppScreen.CLINICAL_HOME appState.currentScreen = AppScreen.CLINICAL_HOME
} else { } else {
appState.backFromPlacementGuide() appState.backFromPlacementGuide()
@@ -279,10 +279,10 @@ fun PlacementGuideView(appState: AppState) {
// Skip — top bar 우측 (유일한 Skip 진입점) // Skip — top bar 우측 (유일한 Skip 진입점)
TextButton(onClick = { TextButton(onClick = {
isContinuousMode = false isContinuousMode = false
val curSess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession val curSess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession
if (curSess != null && curSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT) { if (curSess != null && curSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT) {
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context) com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context)
com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = true com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow = true
appState.currentScreen = AppScreen.CLINICAL_HOME appState.currentScreen = AppScreen.CLINICAL_HOME
} else { } else {
appState.placementComplete() appState.placementComplete()
@@ -311,9 +311,9 @@ fun PlacementGuideView(appState: AppState) {
} }
// 펌웨어 구버전 경고 // 펌웨어 구버전 경고
com.example.medilightv2android.ui.components.FirmwareWarningBanner(bleManager) com.medithings.vesiscan.ui.components.FirmwareWarningBanner(bleManager)
// 배터리 잔량 경고 (<15%) // 배터리 잔량 경고 (<15%)
com.example.medilightv2android.ui.components.BatteryWarningBanner(bleManager) com.medithings.vesiscan.ui.components.BatteryWarningBanner(bleManager)
Box(modifier = Modifier.fillMaxSize()) { Box(modifier = Modifier.fillMaxSize()) {
Column( Column(
@@ -435,7 +435,7 @@ fun PlacementGuideView(appState: AppState) {
) { ) {
// 1) 하복부 일러스트 (배경 — 박스 가득) // 1) 하복부 일러스트 (배경 — 박스 가득)
Image( Image(
painter = painterResource(id = com.example.medilightv2android.R.drawable.body_silhouette), painter = painterResource(id = com.medithings.vesiscan.R.drawable.body_silhouette),
contentDescription = stringResource(R.string.placement_body_desc), contentDescription = stringResource(R.string.placement_body_desc),
modifier = Modifier.matchParentSize(), modifier = Modifier.matchParentSize(),
contentScale = ContentScale.FillBounds contentScale = ContentScale.FillBounds
@@ -444,14 +444,14 @@ fun PlacementGuideView(appState: AppState) {
val sensorBitmap = remember { val sensorBitmap = remember {
android.graphics.BitmapFactory.decodeResource( android.graphics.BitmapFactory.decodeResource(
context.resources, context.resources,
com.example.medilightv2android.R.drawable.sensor_device, com.medithings.vesiscan.R.drawable.sensor_device,
).asImageBitmap() ).asImageBitmap()
} }
// 방향 화살표 PNG (132x112, 우향). 회전 + tint 로 4방향 + 색감 통일. // 방향 화살표 PNG (132x112, 우향). 회전 + tint 로 4방향 + 색감 통일.
val arrowBitmap = remember { val arrowBitmap = remember {
android.graphics.BitmapFactory.decodeResource( android.graphics.BitmapFactory.decodeResource(
context.resources, context.resources,
com.example.medilightv2android.R.drawable.arrow_transparent, com.medithings.vesiscan.R.drawable.arrow_transparent,
).asImageBitmap() ).asImageBitmap()
} }
Canvas(modifier = Modifier.fillMaxSize()) { Canvas(modifier = Modifier.fillMaxSize()) {
@@ -575,17 +575,17 @@ fun PlacementGuideView(appState: AppState) {
) { ) {
// V2 활성 시 5-stage step indicator, 아니면 V1 의 3-stage. // V2 활성 시 5-stage step indicator, 아니면 V1 의 3-stage.
// 2026-07-01: FINAL_CONFIRM phase 추가 (feature/tab-navigation 동기화). // 2026-07-01: FINAL_CONFIRM phase 추가 (feature/tab-navigation 동기화).
val isV2Active = com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo == val isV2Active = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo ==
com.example.medilightv2android.managers.AlignmentAlgo.V2 com.medithings.vesiscan.managers.AlignmentAlgo.V2
// 2026-07-02: CENTER_OPTIMIZE 추가 (5-stage → 6-stage) // 2026-07-02: CENTER_OPTIMIZE 추가 (5-stage → 6-stage)
val (currentStepIdx, totalSteps) = if (isV2Active) { val (currentStepIdx, totalSteps) = if (isV2Active) {
val idx = when (v2Aligner.phase) { val idx = when (v2Aligner.phase) {
com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.INITIAL_ACCUM -> 0 com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.INITIAL_ACCUM -> 0
com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.VERTICAL_CLIMB -> 1 com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.VERTICAL_CLIMB -> 1
com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.CH3_STABILIZE -> 2 com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.CH3_STABILIZE -> 2
com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.CENTER_OPTIMIZE -> 3 com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.CENTER_OPTIMIZE -> 3
com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.LR_BALANCE -> 4 com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.LR_BALANCE -> 4
com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.FINAL_CONFIRM -> 5 com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.FINAL_CONFIRM -> 5
} }
idx to 6 idx to 6
} else { } else {
@@ -634,13 +634,13 @@ fun PlacementGuideView(appState: AppState) {
} }
if (appState.isDevMode && lastImuSamples.isNotEmpty()) { if (appState.isDevMode && lastImuSamples.isNotEmpty()) {
val posture = remember(lastImuSamples) { val posture = remember(lastImuSamples) {
com.example.medilightv2android.managers.ImuAnalysis.estimatePosture(lastImuSamples) com.medithings.vesiscan.managers.ImuAnalysis.estimatePosture(lastImuSamples)
} }
val shake = remember(lastImuSamples) { val shake = remember(lastImuSamples) {
com.example.medilightv2android.managers.ImuAnalysis.shakeRmsDps(lastImuSamples) com.medithings.vesiscan.managers.ImuAnalysis.shakeRmsDps(lastImuSamples)
} }
val tilt = remember(lastImuSamples) { val tilt = remember(lastImuSamples) {
com.example.medilightv2android.managers.ImuAnalysis.tiltDegrees(lastImuSamples) com.medithings.vesiscan.managers.ImuAnalysis.tiltDegrees(lastImuSamples)
} }
Text( Text(
"IMU: $posture · tilt=${"%.0f".format(tilt)}° · shake=${"%.1f".format(shake)}dps", "IMU: $posture · tilt=${"%.0f".format(tilt)}° · shake=${"%.1f".format(shake)}dps",
@@ -720,7 +720,7 @@ fun PlacementGuideView(appState: AppState) {
val detected = if (ch < channelDetected.size) channelDetected[ch] else false val detected = if (ch < channelDetected.size) channelDetected[ch] else false
val wallPair = if (ch < lastWallResults.size) lastWallResults[ch] else null val wallPair = if (ch < lastWallResults.size) lastWallResults[ch] else null
val showWalls = if (wallPair != null) { val showWalls = if (wallPair != null) {
com.example.medilightv2android.managers.LowEchoResult( com.medithings.vesiscan.managers.LowEchoResult(
ant = wallPair.first, post = wallPair.second, ant = wallPair.first, post = wallPair.second,
lowStart = wallPair.first, lowEnd = wallPair.second, lowStart = wallPair.first, lowEnd = wallPair.second,
lowMean = 0.0, urineLen = wallPair.second - wallPair.first, lowMean = 0.0, urineLen = wallPair.second - wallPair.first,
@@ -746,8 +746,8 @@ fun PlacementGuideView(appState: AppState) {
if (chData != null && chData.buffer.isNotEmpty()) { if (chData != null && chData.buffer.isNotEmpty()) {
// V2 활성 시 RollingAligner 의 10-cycle 평균 신호로 표시 → // V2 활성 시 RollingAligner 의 10-cycle 평균 신호로 표시 →
// 알고리즘 입력 신호와 그래프 일치 (실제 측정 시 보는 화면). // 알고리즘 입력 신호와 그래프 일치 (실제 측정 시 보는 화면).
val isV2 = com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo == val isV2 = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo ==
com.example.medilightv2android.managers.AlignmentAlgo.V2 com.medithings.vesiscan.managers.AlignmentAlgo.V2
val avgRaw = if (isV2) v2Aligner.lastAvg?.getOrNull(ch) else null val avgRaw = if (isV2) v2Aligner.lastAvg?.getOrNull(ch) else null
PlacementWaveformChart( PlacementWaveformChart(
buffer = chData.buffer, buffer = chData.buffer,
@@ -806,26 +806,26 @@ fun PlacementGuideView(appState: AppState) {
val MIN_URINE_LEN_PLACEMENT = 12 val MIN_URINE_LEN_PLACEMENT = 12
val method = com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod val method = com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod
val analyzerA = com.example.medilightv2android.managers.PiezoEchoAnalyzerA.shared val analyzerA = com.medithings.vesiscan.managers.PiezoEchoAnalyzerA.shared
for (ch in channels) { for (ch in channels) {
if (ch.buffer.isNotEmpty() && ch.channel < 6) { if (ch.buffer.isNotEmpty() && ch.channel < 6) {
when (method) { when (method) {
com.example.medilightv2android.managers.DetectionMethod.METHOD_C -> { com.medithings.vesiscan.managers.DetectionMethod.METHOD_C -> {
val v41 = com.example.medilightv2android.walldetect.V41Detector() val v41 = com.medithings.vesiscan.walldetect.V41Detector()
val adcSingle = listOf(ch.buffer.map { it.toInt() }) val adcSingle = listOf(ch.buffer.map { it.toInt() })
val probe = com.example.medilightv2android.walldetect.dto.ProbeProfileDto( val probe = com.medithings.vesiscan.walldetect.dto.ProbeProfileDto(
name = com.example.medilightv2android.managers.PiezoHW.presetName, name = com.medithings.vesiscan.managers.PiezoHW.presetName,
rMm = 50.2, anteriorAnchorMm = 32.0, rMm = 50.2, anteriorAnchorMm = 32.0,
fsHz = 537500, cMmPerUs = 1.54, fsHz = 537500, cMmPerUs = 1.54,
anglesDeg = com.example.medilightv2android.managers.PiezoHW.degreeAll.toList() anglesDeg = com.medithings.vesiscan.managers.PiezoHW.degreeAll.toList()
) )
// V4.1은 6ch 입력 필요 — 현재 채널만 해당 위치에, 나머지 빈 값 // V4.1은 6ch 입력 필요 — 현재 채널만 해당 위치에, 나머지 빈 값
val adcMatrix = (0 until 6).map { i -> val adcMatrix = (0 until 6).map { i ->
if (i == ch.channel) ch.buffer.map { it.toInt() } else List(100) { 0 } if (i == ch.channel) ch.buffer.map { it.toInt() } else List(100) { 0 }
} }
val input = com.example.medilightv2android.walldetect.dto.SweepInput( val input = com.medithings.vesiscan.walldetect.dto.SweepInput(
requestId = "placement", timestampMs = System.currentTimeMillis(), requestId = "placement", timestampMs = System.currentTimeMillis(),
deviceId = "", sweepSeq = 0, probe = probe, adc = adcMatrix deviceId = "", sweepSeq = 0, probe = probe, adc = adcMatrix
) )
@@ -841,7 +841,7 @@ fun PlacementGuideView(appState: AppState) {
} }
Log.d("PlacementGuide", "CH${ch.channel}[C] ant=${chResult?.antIdx} post=${chResult?.postIdx}") Log.d("PlacementGuide", "CH${ch.channel}[C] ant=${chResult?.antIdx} post=${chResult?.postIdx}")
} }
com.example.medilightv2android.managers.DetectionMethod.METHOD_A -> { com.medithings.vesiscan.managers.DetectionMethod.METHOD_A -> {
val analysis = analyzerA.analyzeChannel(ch.buffer, ch.channel) val analysis = analyzerA.analyzeChannel(ch.buffer, ch.channel)
Log.d("PlacementGuide", "CH${ch.channel}[A] valid=${analysis.isValid} urine=${analysis.result?.urineLen ?: 0}") Log.d("PlacementGuide", "CH${ch.channel}[A] valid=${analysis.isValid} urine=${analysis.result?.urineLen ?: 0}")
if (analysis.isValid && analysis.result != null && analysis.result.urineLen >= MIN_URINE_LEN_PLACEMENT) { if (analysis.isValid && analysis.result != null && analysis.result.urineLen >= MIN_URINE_LEN_PLACEMENT) {
@@ -864,7 +864,7 @@ fun PlacementGuideView(appState: AppState) {
} }
// postMaxIdx 필터: 후벽이 이 샘플 이상이면 바닥반사로 판단 → 제거 // postMaxIdx 필터: 후벽이 이 샘플 이상이면 바닥반사로 판단 → 제거
val postMax = com.example.medilightv2android.managers.GreenZoneConstants.postMaxIdx val postMax = com.medithings.vesiscan.managers.GreenZoneConstants.postMaxIdx
for (ch in 0..5) { for (ch in 0..5) {
val w = allWalls[ch] val w = allWalls[ch]
if (w != null && w.second > postMax) { if (w != null && w.second > postMax) {
@@ -903,8 +903,8 @@ fun PlacementGuideView(appState: AppState) {
bleManager.debugLogger.warn("DETACHED mean=${"%.1f".format(detachResult.meanAbs)} std=${"%.1f".format(detachResult.stdVal)}") bleManager.debugLogger.warn("DETACHED mean=${"%.1f".format(detachResult.meanAbs)} std=${"%.1f".format(detachResult.stdVal)}")
Log.w("PlacementGuide", "DETACHED mean=${ Log.w("PlacementGuide", "DETACHED mean=${
"%.1f".format(detachResult.meanAbs)} std=${"%.1f".format(detachResult.stdVal)}") "%.1f".format(detachResult.meanAbs)} std=${"%.1f".format(detachResult.stdVal)}")
} else if (com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo == } else if (com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo ==
com.example.medilightv2android.managers.AlignmentAlgo.V2) { com.medithings.vesiscan.managers.AlignmentAlgo.V2) {
// ═══ V2 alignment (alignment.py 포팅, method_d 기반) ═══ // ═══ V2 alignment (alignment.py 포팅, method_d 기반) ═══
// Clinical alignment session + waitingForStart 일 땐 알고리즘 skip — // Clinical alignment session + waitingForStart 일 땐 알고리즘 skip —
// baseline cycles 만 누적 (Start 누르기 전 자동 phase 진행 차단). // baseline cycles 만 누적 (Start 누르기 전 자동 phase 진행 차단).
@@ -941,20 +941,20 @@ fun PlacementGuideView(appState: AppState) {
directionHint = localizedMsg directionHint = localizedMsg
// STOP 액션은 두 경우 — CH3_STABILIZE 의 "위치 유지" (still in progress) vs // STOP 액션은 두 경우 — CH3_STABILIZE 의 "위치 유지" (still in progress) vs
// LR_BALANCE 의 "정렬 완료" (truly done). 후자만 finalStop 으로 GREEN lock. // LR_BALANCE 의 "정렬 완료" (truly done). 후자만 finalStop 으로 GREEN lock.
val finalStop = st.action == com.example.medilightv2android.managers.AlignAction.STOP && val finalStop = st.action == com.medithings.vesiscan.managers.AlignAction.STOP &&
v2Aligner.phase == com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.LR_BALANCE v2Aligner.phase == com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.LR_BALANCE
directionIcon = when (st.action) { directionIcon = when (st.action) {
com.example.medilightv2android.managers.AlignAction.MOVE_UP -> "arrow.up" com.medithings.vesiscan.managers.AlignAction.MOVE_UP -> "arrow.up"
com.example.medilightv2android.managers.AlignAction.MOVE_DOWN -> "arrow.down" com.medithings.vesiscan.managers.AlignAction.MOVE_DOWN -> "arrow.down"
com.example.medilightv2android.managers.AlignAction.MOVE_LEFT -> "arrow.left" com.medithings.vesiscan.managers.AlignAction.MOVE_LEFT -> "arrow.left"
com.example.medilightv2android.managers.AlignAction.MOVE_RIGHT -> "arrow.right" com.medithings.vesiscan.managers.AlignAction.MOVE_RIGHT -> "arrow.right"
com.example.medilightv2android.managers.AlignAction.PROBE_LR -> "" // ↔ — 한쪽 화살표 안 어울림. msg 의 ↔ 만 표시 com.medithings.vesiscan.managers.AlignAction.PROBE_LR -> "" // ↔ — 한쪽 화살표 안 어울림. msg 의 ↔ 만 표시
com.example.medilightv2android.managers.AlignAction.STOP -> if (finalStop) "checkmark.circle" else "" com.medithings.vesiscan.managers.AlignAction.STOP -> if (finalStop) "checkmark.circle" else ""
null -> "" null -> ""
} }
placementScore = when { placementScore = when {
finalStop -> 100 finalStop -> 100
st.action == com.example.medilightv2android.managers.AlignAction.STOP -> 60 // CH3_STABILIZE 유지 중 st.action == com.medithings.vesiscan.managers.AlignAction.STOP -> 60 // CH3_STABILIZE 유지 중
else -> 40 else -> 40
} }
if (finalStop) { if (finalStop) {
@@ -970,14 +970,14 @@ fun PlacementGuideView(appState: AppState) {
} // end of !waitingForStart V2 algorithm } // end of !waitingForStart V2 algorithm
} else { } else {
// Sphere-fit 계산 (SWEEP 모드에서 사용, 다른 모드에서는 무시됨) // Sphere-fit 계산 (SWEEP 모드에서 사용, 다른 모드에서는 무시됨)
val fitResult = com.example.medilightv2android.managers.BladderSphereSeek val fitResult = com.medithings.vesiscan.managers.BladderSphereSeek
.fitSagittalCircle(allWalls, detected) .fitSagittalCircle(allWalls, detected)
val rStatus = rTracker.submit(fitResult?.radiusMm) val rStatus = rTracker.submit(fitResult?.radiusMm)
currentRMm = rStatus.currentR currentRMm = rStatus.currentR
bestRMm = rStatus.bestR bestRMm = rStatus.bestR
sagittalArgMaxCh = com.example.medilightv2android.managers.BladderSphereSeek sagittalArgMaxCh = com.medithings.vesiscan.managers.BladderSphereSeek
.sagittalArgMaxCh(allWalls, detected) .sagittalArgMaxCh(allWalls, detected)
val coronalResult = com.example.medilightv2android.managers.BladderSphereSeek val coronalResult = com.medithings.vesiscan.managers.BladderSphereSeek
.computeCoronalLateral(allWalls, detected) .computeCoronalLateral(allWalls, detected)
lateralOffsetMm = coronalResult?.lateralOffsetMm lateralOffsetMm = coronalResult?.lateralOffsetMm
@@ -1112,11 +1112,11 @@ fun PlacementGuideView(appState: AppState) {
// Phase 라벨 — V2 활성이면 V2 4-stage phase, 아니면 V1 placementPhase. // Phase 라벨 — V2 활성이면 V2 4-stage phase, 아니면 V1 placementPhase.
// Step 0 (Start 전 baseline) 은 alignment session 에서만 명시. // Step 0 (Start 전 baseline) 은 alignment session 에서만 명시.
val isV2 = com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo == val isV2 = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo ==
com.example.medilightv2android.managers.AlignmentAlgo.V2 com.medithings.vesiscan.managers.AlignmentAlgo.V2
val clinSess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession val clinSess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession
val isClinAlign = clinSess != null && val isClinAlign = clinSess != null &&
clinSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT clinSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT
val phaseLabel = when { val phaseLabel = when {
isClinAlign && waitingForStart -> "STEP_0_BASELINE" isClinAlign && waitingForStart -> "STEP_0_BASELINE"
isV2 -> v2Aligner.phase.name isV2 -> v2Aligner.phase.name
@@ -1136,10 +1136,10 @@ fun PlacementGuideView(appState: AppState) {
// 임상 모드에서는 raw ADC도 adc.csv에 자동 저장. // 임상 모드에서는 raw ADC도 adc.csv에 자동 저장.
if (clinSess != null) { if (clinSess != null) {
val rawADC = channels.sortedBy { it.channel }.map { it.buffer } val rawADC = channels.sortedBy { it.channel }.map { it.buffer }
com.example.medilightv2android.services.AdcCsvLogger.log(rawADC, null) com.medithings.vesiscan.services.AdcCsvLogger.log(rawADC, null)
// Alignment session 진행 중이면 measurement.json 용 frame 누적. // Alignment session 진행 중이면 measurement.json 용 frame 누적.
if (clinSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT) { if (clinSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT) {
com.example.medilightv2android.services.ClinicalSessionStore.addAlignmentFrame( com.medithings.vesiscan.services.ClinicalSessionStore.addAlignmentFrame(
piezo = channels, piezo = channels,
imu = lastImuSamples, imu = lastImuSamples,
// Step 0 baseline / V2 phase / V1 phase 통일된 라벨 사용 // Step 0 baseline / V2 phase / V1 phase 통일된 라벨 사용
@@ -1159,8 +1159,8 @@ fun PlacementGuideView(appState: AppState) {
bleManager.imuCollector.onComplete = { imuSamples -> bleManager.imuCollector.onComplete = { imuSamples ->
handler.post { handler.post {
lastImuSamples = imuSamples lastImuSamples = imuSamples
if (com.example.medilightv2android.services.ClinicalSessionStore.currentSession != null) { if (com.medithings.vesiscan.services.ClinicalSessionStore.currentSession != null) {
com.example.medilightv2android.services.ImuCsvLogger.log(imuSamples) com.medithings.vesiscan.services.ImuCsvLogger.log(imuSamples)
} }
} }
} }
@@ -1241,16 +1241,16 @@ fun PlacementGuideView(appState: AppState) {
} }
// Start Scanning / Complete Alignment 버튼 — clinical alignment 모드면 후자 // Start Scanning / Complete Alignment 버튼 — clinical alignment 모드면 후자
val curClinSess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession val curClinSess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession
val isClinicalAlign = curClinSess != null && val isClinicalAlign = curClinSess != null &&
curClinSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT curClinSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT
if (!waitingForStart) Button( if (!waitingForStart) Button(
onClick = { onClick = {
isContinuousMode = false isContinuousMode = false
if (isClinicalAlign) { if (isClinicalAlign) {
// endMeasurement → measurement.json finalize + labdb 자동 업로드 // endMeasurement → measurement.json finalize + labdb 자동 업로드
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context) com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context)
com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = true com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow = true
appState.currentScreen = AppScreen.CLINICAL_HOME appState.currentScreen = AppScreen.CLINICAL_HOME
} else { } else {
appState.placementComplete() appState.placementComplete()
@@ -1300,21 +1300,21 @@ fun PlacementGuideView(appState: AppState) {
) { ) {
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) { Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
// Method A/B/C // Method A/B/C
var selectedMethod by remember { mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod) } var selectedMethod by remember { mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod) }
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text("Detection", fontSize = 14.sp, fontWeight = FontWeight.SemiBold) Text("Detection", fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
val methods = listOf( val methods = listOf(
com.example.medilightv2android.managers.DetectionMethod.METHOD_A to "A", com.medithings.vesiscan.managers.DetectionMethod.METHOD_A to "A",
com.example.medilightv2android.managers.DetectionMethod.METHOD_B to "B", com.medithings.vesiscan.managers.DetectionMethod.METHOD_B to "B",
com.example.medilightv2android.managers.DetectionMethod.METHOD_C to "C" com.medithings.vesiscan.managers.DetectionMethod.METHOD_C to "C"
) )
val colors = listOf(Color(0xFF9C27B0), MlPrimary, Color(0xFFFF5722)) val colors = listOf(Color(0xFF9C27B0), MlPrimary, Color(0xFFFF5722))
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
methods.forEachIndexed { idx, (m, label) -> methods.forEachIndexed { idx, (m, label) ->
val sel = selectedMethod == m val sel = selectedMethod == m
Button( Button(
onClick = { selectedMethod = m; com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod = m }, onClick = { selectedMethod = m; com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod = m },
modifier = Modifier.height(32.dp), modifier = Modifier.height(32.dp),
shape = RoundedCornerShape(8.dp), shape = RoundedCornerShape(8.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
@@ -1332,14 +1332,14 @@ fun PlacementGuideView(appState: AppState) {
HorizontalDivider() HorizontalDivider()
// Guide mode (Gradient / Boundary / SWEEP) // Guide mode (Gradient / Boundary / SWEEP)
var selectedGuide by remember { mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode) } var selectedGuide by remember { mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode) }
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text("Guide", fontSize = 14.sp, fontWeight = FontWeight.SemiBold) Text("Guide", fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
val guideModes = listOf( val guideModes = listOf(
com.example.medilightv2android.managers.PlacementGuideMode.SIMPLE to "Gradient", com.medithings.vesiscan.managers.PlacementGuideMode.SIMPLE to "Gradient",
com.example.medilightv2android.managers.PlacementGuideMode.BOUNDARY to "Boundary", com.medithings.vesiscan.managers.PlacementGuideMode.BOUNDARY to "Boundary",
com.example.medilightv2android.managers.PlacementGuideMode.SWEEP to "SWEEP" com.medithings.vesiscan.managers.PlacementGuideMode.SWEEP to "SWEEP"
) )
val guideColors = listOf(MlPrimary, Color(0xFFFF5722), Color(0xFF7C3AED)) val guideColors = listOf(MlPrimary, Color(0xFFFF5722), Color(0xFF7C3AED))
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
@@ -1348,7 +1348,7 @@ fun PlacementGuideView(appState: AppState) {
Button( Button(
onClick = { onClick = {
selectedGuide = mode selectedGuide = mode
com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode = mode com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode = mode
}, },
modifier = Modifier.height(32.dp), modifier = Modifier.height(32.dp),
shape = RoundedCornerShape(8.dp), shape = RoundedCornerShape(8.dp),
@@ -1368,14 +1368,14 @@ fun PlacementGuideView(appState: AppState) {
// Alignment 알고리즘 V1/V2 // Alignment 알고리즘 V1/V2
var selectedAlgo by remember { var selectedAlgo by remember {
mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo) mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo)
} }
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text("Alignment", fontSize = 14.sp, fontWeight = FontWeight.SemiBold) Text("Alignment", fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
val algoModes = listOf( val algoModes = listOf(
com.example.medilightv2android.managers.AlignmentAlgo.V1 to "V1 (legacy)", com.medithings.vesiscan.managers.AlignmentAlgo.V1 to "V1 (legacy)",
com.example.medilightv2android.managers.AlignmentAlgo.V2 to "V2 (new)", com.medithings.vesiscan.managers.AlignmentAlgo.V2 to "V2 (new)",
) )
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
algoModes.forEach { (algo, label) -> algoModes.forEach { (algo, label) ->
@@ -1383,8 +1383,8 @@ fun PlacementGuideView(appState: AppState) {
Button( Button(
onClick = { onClick = {
selectedAlgo = algo selectedAlgo = algo
com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo = algo com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo = algo
if (algo == com.example.medilightv2android.managers.AlignmentAlgo.V2) { if (algo == com.medithings.vesiscan.managers.AlignmentAlgo.V2) {
v2Aligner.reset() v2Aligner.reset()
} }
}, },
@@ -1410,7 +1410,7 @@ fun PlacementGuideView(appState: AppState) {
Text("Threshold", fontSize = 14.sp, fontWeight = FontWeight.SemiBold) Text("Threshold", fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Text( Text(
if (otsuEnabled) "Otsu: ${"%.0f".format(analyzer.lastOtsuThreshold)}" else "${"%.0f".format(com.example.medilightv2android.managers.GreenZoneConstants.lowEchoAmp)}", if (otsuEnabled) "Otsu: ${"%.0f".format(analyzer.lastOtsuThreshold)}" else "${"%.0f".format(com.medithings.vesiscan.managers.GreenZoneConstants.lowEchoAmp)}",
fontSize = 13.sp, fontWeight = FontWeight.Bold, fontSize = 13.sp, fontWeight = FontWeight.Bold,
color = if (otsuEnabled) Color(0xFF4CAF50) else Color(0xFFFF9800) color = if (otsuEnabled) Color(0xFF4CAF50) else Color(0xFFFF9800)
) )
@@ -1426,7 +1426,7 @@ fun PlacementGuideView(appState: AppState) {
HorizontalDivider() HorizontalDivider()
// Post Max Index (바닥반사 무시 경계) // Post Max Index (바닥반사 무시 경계)
var postMaxVal by remember { mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.postMaxIdx.toFloat()) } var postMaxVal by remember { mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.postMaxIdx.toFloat()) }
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Text("Post Max", fontSize = 14.sp, fontWeight = FontWeight.SemiBold) Text("Post Max", fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
@@ -1434,7 +1434,7 @@ fun PlacementGuideView(appState: AppState) {
} }
Slider( Slider(
value = postMaxVal, value = postMaxVal,
onValueChange = { postMaxVal = it; com.example.medilightv2android.managers.GreenZoneConstants.postMaxIdx = it.toInt() }, onValueChange = { postMaxVal = it; com.medithings.vesiscan.managers.GreenZoneConstants.postMaxIdx = it.toInt() },
valueRange = 50f..95f, valueRange = 50f..95f,
steps = 8, steps = 8,
colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary) colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)
@@ -1651,10 +1651,10 @@ data class PlacementGuideResult(
// CV threshold는 기기 preset에 따라 다름 // CV threshold는 기기 preset에 따라 다름
private val DEFAULT_CV_THR: Double private val DEFAULT_CV_THR: Double
get() = when (com.example.medilightv2android.managers.PiezoHW.activePreset) { get() = when (com.medithings.vesiscan.managers.PiezoHW.activePreset) {
com.example.medilightv2android.managers.PiezoHW.DevicePreset.V0 -> 0.07 com.medithings.vesiscan.managers.PiezoHW.DevicePreset.V0 -> 0.07
com.example.medilightv2android.managers.PiezoHW.DevicePreset.V1, com.medithings.vesiscan.managers.PiezoHW.DevicePreset.V1,
com.example.medilightv2android.managers.PiezoHW.DevicePreset.V2 -> 0.10 com.medithings.vesiscan.managers.PiezoHW.DevicePreset.V2 -> 0.10
else -> 0.08 else -> 0.08
} }
private const val DEFAULT_LR_DEV_THR = 0.20 private const val DEFAULT_LR_DEV_THR = 0.20
@@ -1727,10 +1727,10 @@ private fun computePlacementGuide(
// ═══ 1단계: 상하 탐색 ═══ // ═══ 1단계: 상하 탐색 ═══
if (currentPhase == PlacementPhase.VERTICAL) { if (currentPhase == PlacementPhase.VERTICAL) {
val guideMode = com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode val guideMode = com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode
// ═══ SWEEP 모드 (CKLaw): top-down sweep → Ch3 dropout → pull-back ═══ // ═══ SWEEP 모드 (CKLaw): top-down sweep → Ch3 dropout → pull-back ═══
if (guideMode == com.example.medilightv2android.managers.PlacementGuideMode.SWEEP) { if (guideMode == com.medithings.vesiscan.managers.PlacementGuideMode.SWEEP) {
val vs = verticalState ?: VerticalState() val vs = verticalState ?: VerticalState()
val prev = vs.lastDetectedCount val prev = vs.lastDetectedCount
vs.lastDetectedCount = centerDetected vs.lastDetectedCount = centerDetected
@@ -2054,8 +2054,8 @@ private fun computePlacementGuide(
} }
// R-peak gate (SWEEP 모드에서만 적용) // R-peak gate (SWEEP 모드에서만 적용)
val isSweep = com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode == val isSweep = com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode ==
com.example.medilightv2android.managers.PlacementGuideMode.SWEEP com.medithings.vesiscan.managers.PlacementGuideMode.SWEEP
val rPeakOk = !isSweep || currentRMm == null || bestRMm <= 0.0 || val rPeakOk = !isSweep || currentRMm == null || bestRMm <= 0.0 ||
(bestRMm - currentRMm) <= 1.5 (bestRMm - currentRMm) <= 1.5
val isPass = cv <= cvThr && lrPass && rPeakOk && edgePass val isPass = cv <= cvThr && lrPass && rPeakOk && edgePass
@@ -2159,7 +2159,7 @@ private fun PlacementWaveformChart(
val denoised = analyzer.denoise(raw) val denoised = analyzer.denoise(raw)
val maxVal = 2500f val maxVal = 2500f
val thrVal = if (analyzer.useAdaptiveThreshold && analyzer.lastOtsuThreshold > 0) val thrVal = if (analyzer.useAdaptiveThreshold && analyzer.lastOtsuThreshold > 0)
analyzer.lastOtsuThreshold.toFloat() else com.example.medilightv2android.managers.GreenZoneConstants.lowEchoAmp analyzer.lastOtsuThreshold.toFloat() else com.medithings.vesiscan.managers.GreenZoneConstants.lowEchoAmp
Canvas(modifier = modifier.clip(RoundedCornerShape(4.dp))) { Canvas(modifier = modifier.clip(RoundedCornerShape(4.dp))) {
val w = size.width val w = size.width
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.monitoring package com.medithings.vesiscan.ui.views.monitoring
import android.Manifest import android.Manifest
import android.content.pm.PackageManager import android.content.pm.PackageManager
@@ -35,11 +35,11 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.measure.SimpleMeasureService import com.medithings.vesiscan.measure.SimpleMeasureService
import com.example.medilightv2android.measure.VoidingRecord import com.medithings.vesiscan.measure.VoidingRecord
import com.example.medilightv2android.measure.VoidingRecordStore import com.medithings.vesiscan.measure.VoidingRecordStore
import com.example.medilightv2android.measure.YoloDetector import com.medithings.vesiscan.measure.YoloDetector
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.monitoring package com.medithings.vesiscan.ui.views.monitoring
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@@ -29,14 +29,14 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
import com.example.medilightv2android.managers.NirsManager import com.medithings.vesiscan.managers.NirsManager
import com.example.medilightv2android.models.NirsMcjPacket import com.medithings.vesiscan.models.NirsMcjPacket
import com.example.medilightv2android.models.NirsOxyResult import com.medithings.vesiscan.models.NirsOxyResult
import com.example.medilightv2android.ui.components.BladdyIdleRiveView import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
import kotlin.random.Random import kotlin.random.Random
@Composable @Composable
@@ -84,7 +84,7 @@ fun VivamyoMonitoringView(appState: AppState) {
if (packet != null) { if (packet != null) {
nirsManager.processMcjPacket(packet) nirsManager.processMcjPacket(packet)
} else { } else {
if (com.example.medilightv2android.BuildConfig.DEBUG) { if (com.medithings.vesiscan.BuildConfig.DEBUG) {
android.util.Log.e("VivamyoMonitor", "NirsMcjPacket.parse returned null! data.size=${data.size}") android.util.Log.e("VivamyoMonitor", "NirsMcjPacket.parse returned null! data.size=${data.size}")
} }
} }
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.monitoring package com.medithings.vesiscan.ui.views.monitoring
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@@ -20,12 +20,12 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.measure.VoidingRecord import com.medithings.vesiscan.measure.VoidingRecord
import com.example.medilightv2android.measure.VoidingRecordStore import com.medithings.vesiscan.measure.VoidingRecordStore
import com.example.medilightv2android.ui.theme.MlCardBackground import com.medithings.vesiscan.ui.theme.MlCardBackground
import com.example.medilightv2android.ui.theme.MlPrimary import com.medithings.vesiscan.ui.theme.MlPrimary
import com.example.medilightv2android.ui.theme.MlSecondaryText import com.medithings.vesiscan.ui.theme.MlSecondaryText
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.onboarding package com.medithings.vesiscan.ui.views.onboarding
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@@ -16,10 +16,10 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.ui.components.BladdyIdleRiveView import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
@Composable @Composable
fun OnboardingView(appState: AppState) { fun OnboardingView(appState: AppState) {
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.personalization package com.medithings.vesiscan.ui.views.personalization
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@@ -25,11 +25,11 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.ble.BleManager import com.medithings.vesiscan.ble.BleManager
import com.example.medilightv2android.ui.components.BladdyIdleRiveView import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
import kotlin.math.roundToInt import kotlin.math.roundToInt
/** /**
@@ -338,7 +338,7 @@ private fun WakeupAlarmCard() {
val context = LocalContext.current val context = LocalContext.current
var enabled by androidx.compose.runtime.remember { var enabled by androidx.compose.runtime.remember {
androidx.compose.runtime.mutableStateOf( androidx.compose.runtime.mutableStateOf(
com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context) com.medithings.vesiscan.services.WakeupAlarmPrefs.isEnabled(context)
) )
} }
Card( Card(
@@ -370,7 +370,7 @@ private fun WakeupAlarmCard() {
checked = enabled, checked = enabled,
onCheckedChange = { onCheckedChange = {
enabled = it enabled = it
com.example.medilightv2android.services.WakeupAlarmPrefs.setEnabled(context, it) com.medithings.vesiscan.services.WakeupAlarmPrefs.setEnabled(context, it)
}, },
colors = androidx.compose.material3.SwitchDefaults.colors( colors = androidx.compose.material3.SwitchDefaults.colors(
checkedTrackColor = Color(0xFFD32F2F) checkedTrackColor = Color(0xFFD32F2F)
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.pin package com.medithings.vesiscan.ui.views.pin
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@@ -12,10 +12,10 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.services.UserStorage import com.medithings.vesiscan.services.UserStorage
import com.example.medilightv2android.ui.components.BladdyIdleRiveView import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
enum class PinMode { SETUP, ENTER } enum class PinMode { SETUP, ENTER }
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.pin package com.medithings.vesiscan.ui.views.pin
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@@ -20,8 +20,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.ui.theme.MlCardBackground import com.medithings.vesiscan.ui.theme.MlCardBackground
@Composable @Composable
fun ShuffledKeypad( fun ShuffledKeypad(
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.registration package com.medithings.vesiscan.ui.views.registration
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
@@ -18,11 +18,11 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.models.Sex import com.medithings.vesiscan.models.Sex
import com.example.medilightv2android.ui.components.BladdyIdleRiveView import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
@Composable @Composable
fun RegistrationView(appState: AppState) { fun RegistrationView(appState: AppState) {
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.reminder package com.medithings.vesiscan.ui.views.reminder
import android.content.Intent import android.content.Intent
import android.provider.Settings import android.provider.Settings
@@ -20,10 +20,10 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.services.ReminderService import com.medithings.vesiscan.services.ReminderService
import com.example.medilightv2android.ui.components.LockableSlider import com.medithings.vesiscan.ui.components.LockableSlider
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -1,4 +1,4 @@
package com.example.medilightv2android.ui.views.sensorselect package com.medithings.vesiscan.ui.views.sensorselect
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@@ -22,11 +22,11 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.medilightv2android.AppState import com.medithings.vesiscan.AppState
import com.example.medilightv2android.R import com.medithings.vesiscan.R
import com.example.medilightv2android.models.SensorMode import com.medithings.vesiscan.models.SensorMode
import com.example.medilightv2android.ui.components.BladdyIdleRiveView import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
import com.example.medilightv2android.ui.theme.* import com.medithings.vesiscan.ui.theme.*
@Composable @Composable
fun SensorSelectView(appState: AppState) { fun SensorSelectView(appState: AppState) {
@@ -15,9 +15,9 @@
* own anatomical gate already drops genuinely-bad detections. This layer * own anatomical gate already drops genuinely-bad detections. This layer
* just surfaces "this channel's reading just jumped, double-check". * just surfaces "this channel's reading just jumped, double-check".
*/ */
package com.example.medilightv2android.walldetect package com.medithings.vesiscan.walldetect
import com.example.medilightv2android.walldetect.dto.ChannelResult import com.medithings.vesiscan.walldetect.dto.ChannelResult
import kotlin.math.abs import kotlin.math.abs
class DetectionSanity( class DetectionSanity(
@@ -4,7 +4,7 @@
* Project: CharlesKWONsLaw — wall-detect live compare * Project: CharlesKWONsLaw — wall-detect live compare
* All rights reserved. * All rights reserved.
*/ */
package com.example.medilightv2android.walldetect package com.medithings.vesiscan.walldetect
object DetectorIds { object DetectorIds {
const val V2 = "v2" const val V2 = "v2"
@@ -13,14 +13,14 @@
* 인터페이스는 WallDetector 와 무관 — alignment.py 가 channels[i].urine_len 만 * 인터페이스는 WallDetector 와 무관 — alignment.py 가 channels[i].urine_len 만
* 필요로 하므로 가벼운 단일-함수 API 로 유지. * 필요로 하므로 가벼운 단일-함수 API 로 유지.
*/ */
package com.example.medilightv2android.walldetect package com.medithings.vesiscan.walldetect
import com.example.medilightv2android.walldetect.algo.methodd.MethodDParams import com.medithings.vesiscan.walldetect.algo.methodd.MethodDParams
import com.example.medilightv2android.walldetect.algo.methodd.MethodDPreprocessing import com.medithings.vesiscan.walldetect.algo.methodd.MethodDPreprocessing
import com.example.medilightv2android.walldetect.algo.methodd.MethodDSpan import com.medithings.vesiscan.walldetect.algo.methodd.MethodDSpan
import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect
import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect.CType import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect.CType
import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect.Side import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect.Side
import kotlin.math.max import kotlin.math.max
data class MethodDResult( data class MethodDResult(

Some files were not shown because too many files have changed in this diff Show More