diff --git a/2026-06-23_155020_raw.log b/2026-06-23_155020_raw.log new file mode 100644 index 0000000..5725230 --- /dev/null +++ b/2026-06-23_155020_raw.log @@ -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 diff --git a/2026-06-23_161400_raw.log b/2026-06-23_161400_raw.log new file mode 100644 index 0000000..828a7a7 --- /dev/null +++ b/2026-06-23_161400_raw.log @@ -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 diff --git a/2026-06-24_141023.csv b/2026-06-24_141023.csv new file mode 100644 index 0000000..f22bf6d --- /dev/null +++ b/2026-06-24_141023.csv @@ -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,, diff --git a/allignmentflowchart.png b/allignmentflowchart.png new file mode 100644 index 0000000..97139c6 Binary files /dev/null and b/allignmentflowchart.png differ diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c77b488..8c9c190 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -5,13 +5,13 @@ plugins { } android { - namespace = "com.example.medilightv2android" + namespace = "com.medithings.vesiscan" compileSdk { version = release(36) } defaultConfig { - applicationId = "com.example.medilightv2android" + applicationId = "com.medithings.vesiscan" minSdk = 24 targetSdk = 36 versionCode = 27 diff --git a/app/src/androidTest/java/com/example/medilightv2android/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/medithings/vesiscan/ExampleInstrumentedTest.kt similarity index 82% rename from app/src/androidTest/java/com/example/medilightv2android/ExampleInstrumentedTest.kt rename to app/src/androidTest/java/com/medithings/vesiscan/ExampleInstrumentedTest.kt index 547b891..b308d53 100644 --- a/app/src/androidTest/java/com/example/medilightv2android/ExampleInstrumentedTest.kt +++ b/app/src/androidTest/java/com/medithings/vesiscan/ExampleInstrumentedTest.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android +package com.medithings.vesiscan import androidx.test.platform.app.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -19,6 +19,6 @@ class ExampleInstrumentedTest { fun useAppContext() { // Context of the app under test. val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.example.medilightv2android", appContext.packageName) + assertEquals("com.medithings.vesiscan", appContext.packageName) } } \ No newline at end of file diff --git a/app/src/main/java/com/example/medilightv2android/AppState.kt b/app/src/main/java/com/medithings/vesiscan/AppState.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/AppState.kt rename to app/src/main/java/com/medithings/vesiscan/AppState.kt index 5007fae..3792c52 100644 --- a/app/src/main/java/com/example/medilightv2android/AppState.kt +++ b/app/src/main/java/com/medithings/vesiscan/AppState.kt @@ -1,14 +1,14 @@ -package com.example.medilightv2android +package com.medithings.vesiscan import android.content.Context import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import com.example.medilightv2android.ble.BleManager -import com.example.medilightv2android.managers.NirsManager -import com.example.medilightv2android.models.* -import com.example.medilightv2android.services.* +import com.medithings.vesiscan.ble.BleManager +import com.medithings.vesiscan.managers.NirsManager +import com.medithings.vesiscan.models.* +import com.medithings.vesiscan.services.* enum class AppScreen { ONBOARDING, CONSENT, REGISTRATION, HOME, SENSOR_SELECT, DEVICE_SCAN, @@ -121,7 +121,7 @@ class AppState(private val context: Context) { fun deviceConnected() { isDeviceConnected = true // 임상 모드에서 BLE 연결 시 ClinicalHome으로 복귀 (Personalization 우회) - if (com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow) { + if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow) { currentScreen = AppScreen.CLINICAL_HOME return } diff --git a/app/src/main/java/com/example/medilightv2android/MainActivity.kt b/app/src/main/java/com/medithings/vesiscan/MainActivity.kt similarity index 74% rename from app/src/main/java/com/example/medilightv2android/MainActivity.kt rename to app/src/main/java/com/medithings/vesiscan/MainActivity.kt index 8ef93be..1299a5f 100644 --- a/app/src/main/java/com/example/medilightv2android/MainActivity.kt +++ b/app/src/main/java/com/medithings/vesiscan/MainActivity.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android +package com.medithings.vesiscan import android.os.Bundle import androidx.activity.ComponentActivity @@ -20,34 +20,34 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import app.rive.runtime.kotlin.core.Rive -import com.example.medilightv2android.services.KeychainService -import com.example.medilightv2android.services.NotificationService -import com.example.medilightv2android.R -import com.example.medilightv2android.ui.theme.Medilightv2androidTheme -import com.example.medilightv2android.ui.views.calibration.CalibrationView -import com.example.medilightv2android.ui.views.connection.DeviceScanView -import com.example.medilightv2android.ui.views.history.MeasurementHistoryView -import com.example.medilightv2android.ui.views.home.HomeView -import com.example.medilightv2android.ui.views.monitoring.PlacementGuideView -import com.example.medilightv2android.ui.views.monitoring.PiezoMonitoringView -import com.example.medilightv2android.ui.views.monitoring.VivamyoMonitoringView -import com.example.medilightv2android.ui.views.monitoring.UrineCameraScreen -import com.example.medilightv2android.ui.views.monitoring.VoidingDiaryView -import com.example.medilightv2android.ui.views.onboarding.OnboardingView -import com.example.medilightv2android.ui.views.personalization.PiezoPersonalizationView -import com.example.medilightv2android.ui.views.pin.PinMode -import com.example.medilightv2android.ui.views.pin.PinView -import com.example.medilightv2android.ui.views.registration.RegistrationView -import com.example.medilightv2android.ui.views.consent.ConsentView -import com.example.medilightv2android.ui.views.reminder.ReminderSettingsView -import com.example.medilightv2android.ui.views.sensorselect.SensorSelectView -import com.example.medilightv2android.ui.views.clinical.ClinicalHomeView -import com.example.medilightv2android.ui.views.clinical.ClinicalLiveView +import com.medithings.vesiscan.services.KeychainService +import com.medithings.vesiscan.services.NotificationService +import com.medithings.vesiscan.R +import com.medithings.vesiscan.ui.theme.Medilightv2androidTheme +import com.medithings.vesiscan.ui.views.calibration.CalibrationView +import com.medithings.vesiscan.ui.views.connection.DeviceScanView +import com.medithings.vesiscan.ui.views.history.MeasurementHistoryView +import com.medithings.vesiscan.ui.views.home.HomeView +import com.medithings.vesiscan.ui.views.monitoring.PlacementGuideView +import com.medithings.vesiscan.ui.views.monitoring.PiezoMonitoringView +import com.medithings.vesiscan.ui.views.monitoring.VivamyoMonitoringView +import com.medithings.vesiscan.ui.views.monitoring.UrineCameraScreen +import com.medithings.vesiscan.ui.views.monitoring.VoidingDiaryView +import com.medithings.vesiscan.ui.views.onboarding.OnboardingView +import com.medithings.vesiscan.ui.views.personalization.PiezoPersonalizationView +import com.medithings.vesiscan.ui.views.pin.PinMode +import com.medithings.vesiscan.ui.views.pin.PinView +import com.medithings.vesiscan.ui.views.registration.RegistrationView +import com.medithings.vesiscan.ui.views.consent.ConsentView +import com.medithings.vesiscan.ui.views.reminder.ReminderSettingsView +import com.medithings.vesiscan.ui.views.sensorselect.SensorSelectView +import com.medithings.vesiscan.ui.views.clinical.ClinicalHomeView +import com.medithings.vesiscan.ui.views.clinical.ClinicalLiveView class MainActivity : ComponentActivity() { /** 사용자가 선택한 앱 언어 적용 — Activity 생성 전에 Locale wrap. */ 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?) { @@ -106,28 +106,28 @@ fun MedilightApp(modifier: Modifier = Modifier) { // DeviceScan Back: 임상 흐름이면 ClinicalHome으로, 아니면 HOME AppScreen.DEVICE_SCAN -> appState.currentScreen = - if (com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow) + if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow) AppScreen.CLINICAL_HOME else AppScreen.HOME AppScreen.PIEZO_PERSONALIZATION -> appState.currentScreen = AppScreen.DEVICE_SCAN // 임상 모드 측정 중이면 endMeasurement → ClinicalHome 복귀 AppScreen.PLACEMENT_GUIDE -> - if (com.example.medilightv2android.services.ClinicalSessionStore.currentSession != null) { - com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context) + if (com.medithings.vesiscan.services.ClinicalSessionStore.currentSession != null) { + com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context) appState.currentScreen = AppScreen.CLINICAL_HOME } else appState.backFromPlacementGuide() AppScreen.PIEZO_MONITORING -> - if (com.example.medilightv2android.services.ClinicalSessionStore.currentSession != null) { - com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context) + if (com.medithings.vesiscan.services.ClinicalSessionStore.currentSession != null) { + com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context) appState.currentScreen = AppScreen.CLINICAL_HOME } else appState.currentScreen = AppScreen.PLACEMENT_GUIDE AppScreen.CLINICAL_HOME -> { - com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = false + com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow = false appState.currentScreen = AppScreen.HOME } AppScreen.CLINICAL_LIVE -> { // 측정 폴더 finalize 후 ClinicalHome 복귀 - com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context) + com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context) appState.currentScreen = AppScreen.CLINICAL_HOME } // 모니터링 하위 화면 → 모니터링 diff --git a/app/src/main/java/com/example/medilightv2android/ble/BleManager.kt b/app/src/main/java/com/medithings/vesiscan/ble/BleManager.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/ble/BleManager.kt rename to app/src/main/java/com/medithings/vesiscan/ble/BleManager.kt index bd0f53f..8c65e02 100644 --- a/app/src/main/java/com/example/medilightv2android/ble/BleManager.kt +++ b/app/src/main/java/com/medithings/vesiscan/ble/BleManager.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ble +package com.medithings.vesiscan.ble import android.annotation.SuppressLint import android.bluetooth.* @@ -8,7 +8,7 @@ import android.os.Build import android.os.Handler import android.os.Looper import android.util.Log -import com.example.medilightv2android.BuildConfig +import com.medithings.vesiscan.BuildConfig import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf 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 rxCharacteristic: BluetoothGattCharacteristic? = null 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 batteryTimer: Runnable? = null private var batteryRetryTimer: Runnable? = null @@ -299,7 +299,7 @@ class BleManager private constructor(private val context: Context) { 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") } @@ -326,7 +326,7 @@ class BleManager private constructor(private val context: Context) { /** 저장된 마지막 기기에 자동 연결 시도 */ fun autoConnectLastDevice() { 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})") lastConnectedAddress = recent.address scheduleAutoReconnect() @@ -340,7 +340,7 @@ class BleManager private constructor(private val context: Context) { connectionTimer?.let { handler.removeCallbacks(it) } connectionTimer = null bluetoothGatt?.disconnect() - com.example.medilightv2android.services.BleForegroundService.stop(context) + com.medithings.vesiscan.services.BleForegroundService.stop(context) } fun disconnectAndUnbond() { @@ -348,7 +348,7 @@ class BleManager private constructor(private val context: Context) { cancelAutoReconnect() stopWatchdog() stopBatteryPolling() - com.example.medilightv2android.services.BleForegroundService.stop(context) + com.medithings.vesiscan.services.BleForegroundService.stop(context) connectionTimer?.let { handler.removeCallbacks(it) } connectionTimer = null @@ -386,7 +386,7 @@ class BleManager private constructor(private val context: Context) { // 저장된 기기 정보 삭제 — known device list 에서도 제거 try { device?.let { dev -> - com.example.medilightv2android.services.KnownDeviceStore.remove(context, dev.address) + com.medithings.vesiscan.services.KnownDeviceStore.remove(context, dev.address) } } catch (_: Exception) {} @@ -900,9 +900,9 @@ class BleManager private constructor(private val context: Context) { isConnected.value = true connectedDeviceName.value = try { gatt.device.name ?: "Unknown" } catch (_: Exception) { "Unknown" } // 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") - 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 reconnectAttempt = 0 @@ -911,9 +911,9 @@ class BleManager private constructor(private val context: Context) { // Clinical 흐름에서만 KnownDeviceStore 영속화. 일반 사용자는 // 매 세션 fresh scan + pair — 저장 0개. - if (com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow) { + if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow) { try { - com.example.medilightv2android.services.KnownDeviceStore.add( + com.medithings.vesiscan.services.KnownDeviceStore.add( context, gatt.device.address, connectedDeviceName.value ) } catch (_: Exception) {} @@ -1030,8 +1030,8 @@ class BleManager private constructor(private val context: Context) { } catch (_: Exception) { false } logd { "requestConnectionPriority(HIGH) → $priorityOk" } debugLogger.info("CONN_PRIORITY HIGH requested (ok=$priorityOk)") - com.example.medilightv2android.services.AdcCsvLogger.newSession() - com.example.medilightv2android.services.BleForegroundService.start(context) + com.medithings.vesiscan.services.AdcCsvLogger.newSession() + com.medithings.vesiscan.services.BleForegroundService.start(context) startBatteryPolling() startWatchdog() sendDeviceInfoQuery() @@ -1105,7 +1105,7 @@ class BleManager private constructor(private val context: Context) { private fun processReceivedData(data: ByteArray) { lastRxTimestamp = System.currentTimeMillis() // 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) logd { "Received: $prefix (${data.size} bytes)" } when (prefix) { diff --git a/app/src/main/java/com/example/medilightv2android/ble/CRC16.kt b/app/src/main/java/com/medithings/vesiscan/ble/CRC16.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/ble/CRC16.kt rename to app/src/main/java/com/medithings/vesiscan/ble/CRC16.kt index 689b2ba..7b84e68 100644 --- a/app/src/main/java/com/example/medilightv2android/ble/CRC16.kt +++ b/app/src/main/java/com/medithings/vesiscan/ble/CRC16.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ble +package com.medithings.vesiscan.ble object CRC16 { private const val POLYNOMIAL: Int = 0x1021 diff --git a/app/src/main/java/com/example/medilightv2android/ble/ImuPacketCollector.kt b/app/src/main/java/com/medithings/vesiscan/ble/ImuPacketCollector.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/ble/ImuPacketCollector.kt rename to app/src/main/java/com/medithings/vesiscan/ble/ImuPacketCollector.kt index cac90b2..0ca2870 100644 --- a/app/src/main/java/com/example/medilightv2android/ble/ImuPacketCollector.kt +++ b/app/src/main/java/com/medithings/vesiscan/ble/ImuPacketCollector.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ble +package com.medithings.vesiscan.ble /** * IMU 6축 raw 샘플 (Accel xyz + Gyro xyz). diff --git a/app/src/main/java/com/example/medilightv2android/ble/PiezoPacketCollector.kt b/app/src/main/java/com/medithings/vesiscan/ble/PiezoPacketCollector.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/ble/PiezoPacketCollector.kt rename to app/src/main/java/com/medithings/vesiscan/ble/PiezoPacketCollector.kt index 1f3fe8d..9feaaf7 100644 --- a/app/src/main/java/com/example/medilightv2android/ble/PiezoPacketCollector.kt +++ b/app/src/main/java/com/medithings/vesiscan/ble/PiezoPacketCollector.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ble +package com.medithings.vesiscan.ble /** * Collects multi-packet Piezo echo responses: reb: → (red:) → raa: diff --git a/app/src/main/java/com/example/medilightv2android/managers/AlignmentAdvisorV2.kt b/app/src/main/java/com/medithings/vesiscan/managers/AlignmentAdvisorV2.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/managers/AlignmentAdvisorV2.kt rename to app/src/main/java/com/medithings/vesiscan/managers/AlignmentAdvisorV2.kt index 006f979..a5848ab 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/AlignmentAdvisorV2.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/AlignmentAdvisorV2.kt @@ -16,12 +16,12 @@ * * 기존 PlacementGuide computePlacementGuide(...) 와 병행 — V1/V2 토글로 분기. */ -package com.example.medilightv2android.managers +package com.medithings.vesiscan.managers -import com.example.medilightv2android.R -import com.example.medilightv2android.walldetect.MethodDResult -import com.example.medilightv2android.walldetect.MethodDRunner -import com.example.medilightv2android.walldetect.algo.methodd.MethodDParams +import com.medithings.vesiscan.R +import com.medithings.vesiscan.walldetect.MethodDResult +import com.medithings.vesiscan.walldetect.MethodDRunner +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDParams import kotlin.math.abs import kotlin.math.max diff --git a/app/src/main/java/com/example/medilightv2android/managers/BackReflection.kt b/app/src/main/java/com/medithings/vesiscan/managers/BackReflection.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/managers/BackReflection.kt rename to app/src/main/java/com/medithings/vesiscan/managers/BackReflection.kt index f8431e5..7b6e08d 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/BackReflection.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/BackReflection.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.managers +package com.medithings.vesiscan.managers import kotlin.math.abs import kotlin.math.max diff --git a/app/src/main/java/com/example/medilightv2android/managers/BladderSeekRTracker.kt b/app/src/main/java/com/medithings/vesiscan/managers/BladderSeekRTracker.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/managers/BladderSeekRTracker.kt rename to app/src/main/java/com/medithings/vesiscan/managers/BladderSeekRTracker.kt index 9aaefbe..e56e87d 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/BladderSeekRTracker.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/BladderSeekRTracker.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.managers +package com.medithings.vesiscan.managers import kotlin.math.abs diff --git a/app/src/main/java/com/example/medilightv2android/managers/BladderSphereSeek.kt b/app/src/main/java/com/medithings/vesiscan/managers/BladderSphereSeek.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/managers/BladderSphereSeek.kt rename to app/src/main/java/com/medithings/vesiscan/managers/BladderSphereSeek.kt index 8d585f5..45cd231 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/BladderSphereSeek.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/BladderSphereSeek.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.managers +package com.medithings.vesiscan.managers import kotlin.math.cos import kotlin.math.sin diff --git a/app/src/main/java/com/example/medilightv2android/managers/DetachmentDetection.kt b/app/src/main/java/com/medithings/vesiscan/managers/DetachmentDetection.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/managers/DetachmentDetection.kt rename to app/src/main/java/com/medithings/vesiscan/managers/DetachmentDetection.kt index 112dd1c..af217dc 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/DetachmentDetection.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/DetachmentDetection.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.managers +package com.medithings.vesiscan.managers import kotlin.math.abs import kotlin.math.sqrt diff --git a/app/src/main/java/com/example/medilightv2android/managers/GreenZoneConstants.kt b/app/src/main/java/com/medithings/vesiscan/managers/GreenZoneConstants.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/managers/GreenZoneConstants.kt rename to app/src/main/java/com/medithings/vesiscan/managers/GreenZoneConstants.kt index 282ea23..948579f 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/GreenZoneConstants.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/GreenZoneConstants.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.managers +package com.medithings.vesiscan.managers /** * Green Zone 전체 파이프라인의 공유 상수 — Single Source of Truth. diff --git a/app/src/main/java/com/example/medilightv2android/managers/ImuAnalysis.kt b/app/src/main/java/com/medithings/vesiscan/managers/ImuAnalysis.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/managers/ImuAnalysis.kt rename to app/src/main/java/com/medithings/vesiscan/managers/ImuAnalysis.kt index dcd2e1f..b1c8e23 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/ImuAnalysis.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/ImuAnalysis.kt @@ -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.atan2 import kotlin.math.sqrt diff --git a/app/src/main/java/com/example/medilightv2android/managers/ImuPostureClassifier.kt b/app/src/main/java/com/medithings/vesiscan/managers/ImuPostureClassifier.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/managers/ImuPostureClassifier.kt rename to app/src/main/java/com/medithings/vesiscan/managers/ImuPostureClassifier.kt index cbee3a4..8f6b3af 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/ImuPostureClassifier.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/ImuPostureClassifier.kt @@ -13,9 +13,9 @@ * ≤ threshold → NON_LYING (앉음/섬) * 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.atan import kotlin.math.sqrt diff --git a/app/src/main/java/com/example/medilightv2android/managers/NirsCalcEngine.kt b/app/src/main/java/com/medithings/vesiscan/managers/NirsCalcEngine.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/managers/NirsCalcEngine.kt rename to app/src/main/java/com/medithings/vesiscan/managers/NirsCalcEngine.kt index 2054362..2bfe6ce 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/NirsCalcEngine.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/NirsCalcEngine.kt @@ -1,8 +1,8 @@ -package com.example.medilightv2android.managers +package com.medithings.vesiscan.managers -import com.example.medilightv2android.models.NirsConstants -import com.example.medilightv2android.models.NirsMagResponse -import com.example.medilightv2android.models.NirsOxyResult +import com.medithings.vesiscan.models.NirsConstants +import com.medithings.vesiscan.models.NirsMagResponse +import com.medithings.vesiscan.models.NirsOxyResult import kotlin.math.abs import kotlin.math.ln import kotlin.math.max diff --git a/app/src/main/java/com/example/medilightv2android/managers/NirsManager.kt b/app/src/main/java/com/medithings/vesiscan/managers/NirsManager.kt similarity index 89% rename from app/src/main/java/com/example/medilightv2android/managers/NirsManager.kt rename to app/src/main/java/com/medithings/vesiscan/managers/NirsManager.kt index 220963f..4e3d7b8 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/NirsManager.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/NirsManager.kt @@ -1,13 +1,13 @@ -package com.example.medilightv2android.managers +package com.medithings.vesiscan.managers import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf -import com.example.medilightv2android.models.NirsMagResponse -import com.example.medilightv2android.models.NirsMcjPacket -import com.example.medilightv2android.models.NirsConstants -import com.example.medilightv2android.BuildConfig -import com.example.medilightv2android.models.NirsOxyResult +import com.medithings.vesiscan.models.NirsMagResponse +import com.medithings.vesiscan.models.NirsMcjPacket +import com.medithings.vesiscan.models.NirsConstants +import com.medithings.vesiscan.BuildConfig +import com.medithings.vesiscan.models.NirsOxyResult class NirsManager private constructor() { companion object { diff --git a/app/src/main/java/com/example/medilightv2android/managers/PiezoBVEstimator.kt b/app/src/main/java/com/medithings/vesiscan/managers/PiezoBVEstimator.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/managers/PiezoBVEstimator.kt rename to app/src/main/java/com/medithings/vesiscan/managers/PiezoBVEstimator.kt index 8a19732..3dd40ac 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/PiezoBVEstimator.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/PiezoBVEstimator.kt @@ -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.cos import kotlin.math.hypot @@ -484,7 +484,7 @@ fun estimateBladderVolume6ch( val lateralWalls = PiezoHW.lateralCh.map { if (it < allWalls.size) allWalls[it] else null } // 2026-07-01: algorithm 팀 최신 표준 (piezophantomtest 4830e7c) — lr_ratio_override=1.0 // 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) return estimateBladderVolume( walls = centerWalls, diff --git a/app/src/main/java/com/example/medilightv2android/managers/PiezoEchoAnalyzer.kt b/app/src/main/java/com/medithings/vesiscan/managers/PiezoEchoAnalyzer.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/managers/PiezoEchoAnalyzer.kt rename to app/src/main/java/com/medithings/vesiscan/managers/PiezoEchoAnalyzer.kt index 182d24a..f8f9e19 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/PiezoEchoAnalyzer.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/PiezoEchoAnalyzer.kt @@ -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.max import kotlin.math.min diff --git a/app/src/main/java/com/example/medilightv2android/managers/PiezoEchoAnalyzerA.kt b/app/src/main/java/com/medithings/vesiscan/managers/PiezoEchoAnalyzerA.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/managers/PiezoEchoAnalyzerA.kt rename to app/src/main/java/com/medithings/vesiscan/managers/PiezoEchoAnalyzerA.kt index a587b8e..617e1e7 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/PiezoEchoAnalyzerA.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/PiezoEchoAnalyzerA.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.managers +package com.medithings.vesiscan.managers import kotlin.math.abs import kotlin.math.max diff --git a/app/src/main/java/com/example/medilightv2android/managers/UrinAI.kt b/app/src/main/java/com/medithings/vesiscan/managers/UrinAI.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/managers/UrinAI.kt rename to app/src/main/java/com/medithings/vesiscan/managers/UrinAI.kt index 5ee990f..b817693 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/UrinAI.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/UrinAI.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.managers +package com.medithings.vesiscan.managers /** * UrinAI (UrinGateKeeper) — 소변(액체) 존재 판정 엔진. diff --git a/app/src/main/java/com/example/medilightv2android/managers/WakeupDetector.kt b/app/src/main/java/com/medithings/vesiscan/managers/WakeupDetector.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/managers/WakeupDetector.kt rename to app/src/main/java/com/medithings/vesiscan/managers/WakeupDetector.kt index 2dbc795..c3f3be4 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/WakeupDetector.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/WakeupDetector.kt @@ -15,7 +15,7 @@ * // 매 posture 갱신 시: * detector.update(currentPosture, System.currentTimeMillis()) */ -package com.example.medilightv2android.managers +package com.medithings.vesiscan.managers class WakeupDetector( /** 알람 발동을 위해 직전 LYING 상태로 유지되어야 하는 최소 시간 (초). */ diff --git a/app/src/main/java/com/example/medilightv2android/managers/WalkingDetector.kt b/app/src/main/java/com/medithings/vesiscan/managers/WalkingDetector.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/managers/WalkingDetector.kt rename to app/src/main/java/com/medithings/vesiscan/managers/WalkingDetector.kt index 341d5b3..f06c242 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/WalkingDetector.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/WalkingDetector.kt @@ -18,9 +18,9 @@ * 입력: 매 mtb cycle (≈1초 주기) 마다 IMU sample 리스트 + 현재 pitch + 시각 * 출력: 현재 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.sqrt diff --git a/app/src/main/java/com/example/medilightv2android/measure/CCPosition.kt b/app/src/main/java/com/medithings/vesiscan/measure/CCPosition.kt similarity index 70% rename from app/src/main/java/com/example/medilightv2android/measure/CCPosition.kt rename to app/src/main/java/com/medithings/vesiscan/measure/CCPosition.kt index 5978d5d..42786f2 100644 --- a/app/src/main/java/com/example/medilightv2android/measure/CCPosition.kt +++ b/app/src/main/java/com/medithings/vesiscan/measure/CCPosition.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.measure +package com.medithings.vesiscan.measure data class CCPosition( val cc: Int, diff --git a/app/src/main/java/com/example/medilightv2android/measure/SimpleMeasureService.kt b/app/src/main/java/com/medithings/vesiscan/measure/SimpleMeasureService.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/measure/SimpleMeasureService.kt rename to app/src/main/java/com/medithings/vesiscan/measure/SimpleMeasureService.kt index 6871857..73f9d55 100644 --- a/app/src/main/java/com/example/medilightv2android/measure/SimpleMeasureService.kt +++ b/app/src/main/java/com/medithings/vesiscan/measure/SimpleMeasureService.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.measure +package com.medithings.vesiscan.measure import android.graphics.Bitmap import android.graphics.Color @@ -6,7 +6,7 @@ import android.util.Log import com.google.mlkit.vision.common.InputImage import com.google.mlkit.vision.text.TextRecognition 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.suspendCancellableCoroutine import kotlinx.coroutines.withContext diff --git a/app/src/main/java/com/example/medilightv2android/measure/VoidingRecord.kt b/app/src/main/java/com/medithings/vesiscan/measure/VoidingRecord.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/measure/VoidingRecord.kt rename to app/src/main/java/com/medithings/vesiscan/measure/VoidingRecord.kt index 8c7c0d1..fae894f 100644 --- a/app/src/main/java/com/example/medilightv2android/measure/VoidingRecord.kt +++ b/app/src/main/java/com/medithings/vesiscan/measure/VoidingRecord.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.measure +package com.medithings.vesiscan.measure import android.content.Context import android.content.SharedPreferences diff --git a/app/src/main/java/com/example/medilightv2android/measure/YoloDetector.kt b/app/src/main/java/com/medithings/vesiscan/measure/YoloDetector.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/measure/YoloDetector.kt rename to app/src/main/java/com/medithings/vesiscan/measure/YoloDetector.kt index ef23ddb..d59e0d3 100644 --- a/app/src/main/java/com/example/medilightv2android/measure/YoloDetector.kt +++ b/app/src/main/java/com/medithings/vesiscan/measure/YoloDetector.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.measure +package com.medithings.vesiscan.measure import android.content.Context import android.graphics.Bitmap diff --git a/app/src/main/java/com/example/medilightv2android/models/BladderLevel.kt b/app/src/main/java/com/medithings/vesiscan/models/BladderLevel.kt similarity index 93% rename from app/src/main/java/com/example/medilightv2android/models/BladderLevel.kt rename to app/src/main/java/com/medithings/vesiscan/models/BladderLevel.kt index c34f110..d591738 100644 --- a/app/src/main/java/com/example/medilightv2android/models/BladderLevel.kt +++ b/app/src/main/java/com/medithings/vesiscan/models/BladderLevel.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.models +package com.medithings.vesiscan.models data class BladderLevel( var currentLevel: Int = 0, diff --git a/app/src/main/java/com/example/medilightv2android/models/ClinicalSession.kt b/app/src/main/java/com/medithings/vesiscan/models/ClinicalSession.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/models/ClinicalSession.kt rename to app/src/main/java/com/medithings/vesiscan/models/ClinicalSession.kt index 1433382..9f0847d 100644 --- a/app/src/main/java/com/example/medilightv2android/models/ClinicalSession.kt +++ b/app/src/main/java/com/medithings/vesiscan/models/ClinicalSession.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.models +package com.medithings.vesiscan.models import java.text.SimpleDateFormat import java.util.Date diff --git a/app/src/main/java/com/example/medilightv2android/models/MeasurementRecord.kt b/app/src/main/java/com/medithings/vesiscan/models/MeasurementRecord.kt similarity index 94% rename from app/src/main/java/com/example/medilightv2android/models/MeasurementRecord.kt rename to app/src/main/java/com/medithings/vesiscan/models/MeasurementRecord.kt index bec5337..ebcedec 100644 --- a/app/src/main/java/com/example/medilightv2android/models/MeasurementRecord.kt +++ b/app/src/main/java/com/medithings/vesiscan/models/MeasurementRecord.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.models +package com.medithings.vesiscan.models import java.util.Date import java.util.UUID diff --git a/app/src/main/java/com/example/medilightv2android/models/NirsConstants.kt b/app/src/main/java/com/medithings/vesiscan/models/NirsConstants.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/models/NirsConstants.kt rename to app/src/main/java/com/medithings/vesiscan/models/NirsConstants.kt index b0a23f0..e9eaae2 100644 --- a/app/src/main/java/com/example/medilightv2android/models/NirsConstants.kt +++ b/app/src/main/java/com/medithings/vesiscan/models/NirsConstants.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.models +package com.medithings.vesiscan.models import androidx.compose.ui.graphics.Color diff --git a/app/src/main/java/com/example/medilightv2android/models/NirsData.kt b/app/src/main/java/com/medithings/vesiscan/models/NirsData.kt similarity index 92% rename from app/src/main/java/com/example/medilightv2android/models/NirsData.kt rename to app/src/main/java/com/medithings/vesiscan/models/NirsData.kt index 1465ca4..f7db6b0 100644 --- a/app/src/main/java/com/example/medilightv2android/models/NirsData.kt +++ b/app/src/main/java/com/medithings/vesiscan/models/NirsData.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.models +package com.medithings.vesiscan.models data class NirsMcjPacket( val battery: Int, @@ -16,7 +16,7 @@ data class NirsMcjPacket( fun parse(data: ByteArray): NirsMcjPacket? { 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") } return null @@ -42,7 +42,7 @@ data class NirsMcjPacket( for (i in 0 until 24) { val offset = base + 20 + (i * 2) 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}") } return null @@ -50,7 +50,7 @@ data class NirsMcjPacket( 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)}") } diff --git a/app/src/main/java/com/example/medilightv2android/models/PiezoSettings.kt b/app/src/main/java/com/medithings/vesiscan/models/PiezoSettings.kt similarity index 94% rename from app/src/main/java/com/example/medilightv2android/models/PiezoSettings.kt rename to app/src/main/java/com/medithings/vesiscan/models/PiezoSettings.kt index af13036..7e990e6 100644 --- a/app/src/main/java/com/example/medilightv2android/models/PiezoSettings.kt +++ b/app/src/main/java/com/medithings/vesiscan/models/PiezoSettings.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.models +package com.medithings.vesiscan.models enum class Posture(val displayName: String) { STANDING("Standing"), diff --git a/app/src/main/java/com/example/medilightv2android/models/SensorMode.kt b/app/src/main/java/com/medithings/vesiscan/models/SensorMode.kt similarity index 65% rename from app/src/main/java/com/example/medilightv2android/models/SensorMode.kt rename to app/src/main/java/com/medithings/vesiscan/models/SensorMode.kt index 47a1415..fcc86f7 100644 --- a/app/src/main/java/com/example/medilightv2android/models/SensorMode.kt +++ b/app/src/main/java/com/medithings/vesiscan/models/SensorMode.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.models +package com.medithings.vesiscan.models enum class SensorMode(val displayName: String) { NIRS("NIRS"), diff --git a/app/src/main/java/com/example/medilightv2android/models/UrgencyLevel.kt b/app/src/main/java/com/medithings/vesiscan/models/UrgencyLevel.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/models/UrgencyLevel.kt rename to app/src/main/java/com/medithings/vesiscan/models/UrgencyLevel.kt index 172849f..a17bfe2 100644 --- a/app/src/main/java/com/example/medilightv2android/models/UrgencyLevel.kt +++ b/app/src/main/java/com/medithings/vesiscan/models/UrgencyLevel.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.models +package com.medithings.vesiscan.models import androidx.compose.ui.graphics.Color diff --git a/app/src/main/java/com/example/medilightv2android/models/User.kt b/app/src/main/java/com/medithings/vesiscan/models/User.kt similarity index 83% rename from app/src/main/java/com/example/medilightv2android/models/User.kt rename to app/src/main/java/com/medithings/vesiscan/models/User.kt index b335200..ff7e9b7 100644 --- a/app/src/main/java/com/example/medilightv2android/models/User.kt +++ b/app/src/main/java/com/medithings/vesiscan/models/User.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.models +package com.medithings.vesiscan.models enum class Sex { MALE, FEMALE } diff --git a/app/src/main/java/com/example/medilightv2android/services/AdcCsvLogger.kt b/app/src/main/java/com/medithings/vesiscan/services/AdcCsvLogger.kt similarity index 88% rename from app/src/main/java/com/example/medilightv2android/services/AdcCsvLogger.kt rename to app/src/main/java/com/medithings/vesiscan/services/AdcCsvLogger.kt index e5060b7..64fbd2a 100644 --- a/app/src/main/java/com/example/medilightv2android/services/AdcCsvLogger.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/AdcCsvLogger.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.os.Environment import java.io.File @@ -63,15 +63,15 @@ object AdcCsvLogger { val timestamp = timeFmt.format(Date()) val volStr = volumeMl?.let { "%.1f".format(it) } ?: "" 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) - "%.0f".format(analyzer.lastOtsuThreshold) else "%.0f".format(com.example.medilightv2android.managers.GreenZoneConstants.lowEchoAmp) - val dpsStr = "%.3f".format(com.example.medilightv2android.managers.PiezoHW.distancePerSample) + "%.0f".format(analyzer.lastOtsuThreshold) else "%.0f".format(com.medithings.vesiscan.managers.GreenZoneConstants.lowEchoAmp) + val dpsStr = "%.3f".format(com.medithings.vesiscan.managers.PiezoHW.distancePerSample) val sgStr = if (analyzer.useSgFilter) "ON" else "OFF" val clinicalLabel = ClinicalSessionStore.currentLabel() // 일반 모드면 "" // 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 -> if (isNew) { diff --git a/app/src/main/java/com/example/medilightv2android/services/BleDebugLogger.kt b/app/src/main/java/com/medithings/vesiscan/services/BleDebugLogger.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/services/BleDebugLogger.kt rename to app/src/main/java/com/medithings/vesiscan/services/BleDebugLogger.kt index ff2a1f2..bb1d393 100644 --- a/app/src/main/java/com/example/medilightv2android/services/BleDebugLogger.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/BleDebugLogger.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.content.Context import android.content.Intent diff --git a/app/src/main/java/com/example/medilightv2android/services/BleForegroundService.kt b/app/src/main/java/com/medithings/vesiscan/services/BleForegroundService.kt similarity index 94% rename from app/src/main/java/com/example/medilightv2android/services/BleForegroundService.kt rename to app/src/main/java/com/medithings/vesiscan/services/BleForegroundService.kt index 9177723..8ca4524 100644 --- a/app/src/main/java/com/example/medilightv2android/services/BleForegroundService.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/BleForegroundService.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.app.Notification import android.app.NotificationChannel @@ -11,8 +11,8 @@ import android.os.Build import android.os.IBinder import android.os.PowerManager import androidx.core.app.NotificationCompat -import com.example.medilightv2android.MainActivity -import com.example.medilightv2android.R +import com.medithings.vesiscan.MainActivity +import com.medithings.vesiscan.R /** * BLE 연결 유지를 위한 Foreground Service. @@ -25,8 +25,8 @@ class BleForegroundService : Service() { companion object { const val CHANNEL_ID = "vesiscan_ble_channel" const val NOTIFICATION_ID = 1001 - const val ACTION_START = "com.example.medilightv2android.BLE_START" - const val ACTION_STOP = "com.example.medilightv2android.BLE_STOP" + const val ACTION_START = "com.medithings.vesiscan.BLE_START" + const val ACTION_STOP = "com.medithings.vesiscan.BLE_STOP" fun start(context: Context) { // 배터리 최적화 제외 요청 제거 — 다른 페이지로 이동되는 UX 문제 diff --git a/app/src/main/java/com/example/medilightv2android/services/ClinicalSessionStore.kt b/app/src/main/java/com/medithings/vesiscan/services/ClinicalSessionStore.kt similarity index 93% rename from app/src/main/java/com/example/medilightv2android/services/ClinicalSessionStore.kt rename to app/src/main/java/com/medithings/vesiscan/services/ClinicalSessionStore.kt index 7a72c67..79ff296 100644 --- a/app/src/main/java/com/example/medilightv2android/services/ClinicalSessionStore.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/ClinicalSessionStore.kt @@ -1,10 +1,10 @@ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.content.Context import android.os.Environment -import com.example.medilightv2android.ble.ImuSample -import com.example.medilightv2android.ble.PiezoChannelData -import com.example.medilightv2android.models.ClinicalSession +import com.medithings.vesiscan.ble.ImuSample +import com.medithings.vesiscan.ble.PiezoChannelData +import com.medithings.vesiscan.models.ClinicalSession import org.json.JSONArray import org.json.JSONObject import java.io.File @@ -59,16 +59,16 @@ object ClinicalSessionStore { /** 다음 측정 시 기본값으로 자동 채울 사용자 입력 — 같은 피험자/검사자 여러 측정 시 편의 */ var lastExaminer: String = "" var lastNotes: String = "" - var lastSubjectType: com.example.medilightv2android.models.SubjectType = - com.example.medilightv2android.models.SubjectType.PHANTOM + var lastSubjectType: com.medithings.vesiscan.models.SubjectType = + com.medithings.vesiscan.models.SubjectType.PHANTOM var lastSubject: String = "" // 카테고리 내 식별자 (예: "500mL", "S001") var lastTrueVolumeMl: String = "" // 문자열로 보관 (입력 폼과 동일 형식) var lastAbdomenThicknessMm: String = "" // 회의 결정: Step/Posture 마지막 선택 유지 — 매번 0cm로 리셋되는 불편 제거 - var lastPosture: com.example.medilightv2android.models.ClinicalPosture = - com.example.medilightv2android.models.ClinicalPosture.SUPINE - var lastStep: com.example.medilightv2android.models.ClinicalStep = - com.example.medilightv2android.models.ClinicalStep.ALIGN_0CM + var lastPosture: com.medithings.vesiscan.models.ClinicalPosture = + com.medithings.vesiscan.models.ClinicalPosture.SUPINE + var lastStep: com.medithings.vesiscan.models.ClinicalStep = + com.medithings.vesiscan.models.ClinicalStep.ALIGN_0CM /** End 시점에 measurement.json 통합 생성용 — 측정 중 사이클 누적 */ private val cyclesBuffer = mutableListOf() @@ -186,7 +186,7 @@ object ClinicalSessionStore { put("android_release", android.os.Build.VERSION.RELEASE) put("android_sdk", android.os.Build.VERSION.SDK_INT) // 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 hw = ble.hardwareVersion.value val sn = ble.serialNumber.value @@ -224,7 +224,7 @@ object ClinicalSessionStore { // meta: writeMeta()와 동일 내용 포함 (단독 파일로 자족 가능) // 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 val meta = JSONObject().apply { put("data_type", effectiveDataType) @@ -254,7 +254,7 @@ object ClinicalSessionStore { put("app_version_name", try { context.packageManager.getPackageInfo(context.packageName, 0).versionName ?: "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?.hardwareVersion?.value?.takeIf { it.isNotEmpty() }?.let { put("hardware_version", it) } ble?.serialNumber?.value?.takeIf { it.isNotEmpty() }?.let { put("serial_number", it) } diff --git a/app/src/main/java/com/example/medilightv2android/services/ImuCsvLogger.kt b/app/src/main/java/com/medithings/vesiscan/services/ImuCsvLogger.kt similarity index 92% rename from app/src/main/java/com/example/medilightv2android/services/ImuCsvLogger.kt rename to app/src/main/java/com/medithings/vesiscan/services/ImuCsvLogger.kt index 779453b..897c764 100644 --- a/app/src/main/java/com/example/medilightv2android/services/ImuCsvLogger.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/ImuCsvLogger.kt @@ -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.text.SimpleDateFormat import java.util.Date @@ -38,7 +38,7 @@ object ImuCsvLogger { val scanId = AdcCsvLogger.lastScanId // piezo adc.csv와 매칭용 val timestamp = timeFmt.format(Date()) 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 java.io.FileWriter(file, !isNew).buffered().use { writer -> diff --git a/app/src/main/java/com/example/medilightv2android/services/KeychainService.kt b/app/src/main/java/com/medithings/vesiscan/services/KeychainService.kt similarity index 95% rename from app/src/main/java/com/example/medilightv2android/services/KeychainService.kt rename to app/src/main/java/com/medithings/vesiscan/services/KeychainService.kt index f2d1c46..1ac3482 100644 --- a/app/src/main/java/com/example/medilightv2android/services/KeychainService.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/KeychainService.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.content.Context import android.content.SharedPreferences diff --git a/app/src/main/java/com/example/medilightv2android/services/KnownDeviceStore.kt b/app/src/main/java/com/medithings/vesiscan/services/KnownDeviceStore.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/services/KnownDeviceStore.kt rename to app/src/main/java/com/medithings/vesiscan/services/KnownDeviceStore.kt index a9eeb64..73c0072 100644 --- a/app/src/main/java/com/example/medilightv2android/services/KnownDeviceStore.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/KnownDeviceStore.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.content.Context import org.json.JSONArray diff --git a/app/src/main/java/com/example/medilightv2android/services/LocalePref.kt b/app/src/main/java/com/medithings/vesiscan/services/LocalePref.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/services/LocalePref.kt rename to app/src/main/java/com/medithings/vesiscan/services/LocalePref.kt index 2c0a842..e20e1f2 100644 --- a/app/src/main/java/com/example/medilightv2android/services/LocalePref.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/LocalePref.kt @@ -13,7 +13,7 @@ * Android 13+ 의 per-app locale API (AppCompatDelegate.setApplicationLocales) 와 * 무관하게 Configuration override 방식으로 모든 SDK 에서 동작. */ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.content.Context import android.content.res.Configuration diff --git a/app/src/main/java/com/example/medilightv2android/services/MeasurementHistoryStore.kt b/app/src/main/java/com/medithings/vesiscan/services/MeasurementHistoryStore.kt similarity index 93% rename from app/src/main/java/com/example/medilightv2android/services/MeasurementHistoryStore.kt rename to app/src/main/java/com/medithings/vesiscan/services/MeasurementHistoryStore.kt index 00920ea..2cac6d5 100644 --- a/app/src/main/java/com/example/medilightv2android/services/MeasurementHistoryStore.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/MeasurementHistoryStore.kt @@ -1,8 +1,8 @@ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.content.Context 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.reflect.TypeToken diff --git a/app/src/main/java/com/example/medilightv2android/services/MeasurementLogService.kt b/app/src/main/java/com/medithings/vesiscan/services/MeasurementLogService.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/services/MeasurementLogService.kt rename to app/src/main/java/com/medithings/vesiscan/services/MeasurementLogService.kt index 5793754..d73a00c 100644 --- a/app/src/main/java/com/example/medilightv2android/services/MeasurementLogService.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/MeasurementLogService.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.content.Context import android.os.Build @@ -70,7 +70,7 @@ class MeasurementLogService private constructor(private val context: Context) { val clinical = ClinicalSessionStore.currentLabel() if (clinical.isNotEmpty()) put("clinical_label", clinical) // 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) } @@ -136,7 +136,7 @@ class MeasurementLogService private constructor(private val context: Context) { val clinical = ClinicalSessionStore.currentLabel() if (clinical.isNotEmpty()) put("clinical_label", clinical) // 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) } appendLog(entry, "placements.jsonl") diff --git a/app/src/main/java/com/example/medilightv2android/services/MeasurementService.kt b/app/src/main/java/com/medithings/vesiscan/services/MeasurementService.kt similarity index 90% rename from app/src/main/java/com/example/medilightv2android/services/MeasurementService.kt rename to app/src/main/java/com/medithings/vesiscan/services/MeasurementService.kt index e8a7288..86cb906 100644 --- a/app/src/main/java/com/example/medilightv2android/services/MeasurementService.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/MeasurementService.kt @@ -1,9 +1,9 @@ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.content.Context import androidx.compose.runtime.mutableStateOf -import com.example.medilightv2android.ble.BleManager -import com.example.medilightv2android.models.SensorMode +import com.medithings.vesiscan.ble.BleManager +import com.medithings.vesiscan.models.SensorMode class MeasurementService private constructor(context: Context) { companion object { diff --git a/app/src/main/java/com/example/medilightv2android/services/NotificationService.kt b/app/src/main/java/com/medithings/vesiscan/services/NotificationService.kt similarity index 94% rename from app/src/main/java/com/example/medilightv2android/services/NotificationService.kt rename to app/src/main/java/com/medithings/vesiscan/services/NotificationService.kt index 371416c..c9faea2 100644 --- a/app/src/main/java/com/example/medilightv2android/services/NotificationService.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/NotificationService.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.app.NotificationChannel import android.app.NotificationManager @@ -6,8 +6,8 @@ import android.content.Context import android.os.Build import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat -import com.example.medilightv2android.R -import com.example.medilightv2android.models.UrgencyLevel +import com.medithings.vesiscan.R +import com.medithings.vesiscan.models.UrgencyLevel class NotificationService private constructor(private val context: Context) { companion object { diff --git a/app/src/main/java/com/example/medilightv2android/services/PostureEventLogger.kt b/app/src/main/java/com/medithings/vesiscan/services/PostureEventLogger.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/services/PostureEventLogger.kt rename to app/src/main/java/com/medithings/vesiscan/services/PostureEventLogger.kt index e3153ac..2a32c3a 100644 --- a/app/src/main/java/com/example/medilightv2android/services/PostureEventLogger.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/PostureEventLogger.kt @@ -23,7 +23,7 @@ * * 분석: CSV → Excel / python pandas → ANNOTATION 과 CYCLE 의 walking 전이 대조. */ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.content.Context import android.os.Environment diff --git a/app/src/main/java/com/example/medilightv2android/services/PostureTuningPrefs.kt b/app/src/main/java/com/medithings/vesiscan/services/PostureTuningPrefs.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/services/PostureTuningPrefs.kt rename to app/src/main/java/com/medithings/vesiscan/services/PostureTuningPrefs.kt index 7791ddd..dc28b54 100644 --- a/app/src/main/java/com/example/medilightv2android/services/PostureTuningPrefs.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/PostureTuningPrefs.kt @@ -9,10 +9,10 @@ * saveAll(context) — slider 변경 시 호출 → 현재 GreenZoneConstants → SharedPreferences * resetAll(context) — 사용자가 reset 누름 → defaults 로 복원 */ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.content.Context -import com.example.medilightv2android.managers.GreenZoneConstants +import com.medithings.vesiscan.managers.GreenZoneConstants object PostureTuningPrefs { diff --git a/app/src/main/java/com/example/medilightv2android/services/RawBleLogger.kt b/app/src/main/java/com/medithings/vesiscan/services/RawBleLogger.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/services/RawBleLogger.kt rename to app/src/main/java/com/medithings/vesiscan/services/RawBleLogger.kt index 8ab12d0..6efe97a 100644 --- a/app/src/main/java/com/example/medilightv2android/services/RawBleLogger.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/RawBleLogger.kt @@ -10,7 +10,7 @@ * 사용: startCapture() / stopCapture() 토글. 활성화 시 BleManager.processReceivedData * 가 매 notification 마다 write() 호출. */ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.os.Environment import java.io.File diff --git a/app/src/main/java/com/example/medilightv2android/services/ReminderService.kt b/app/src/main/java/com/medithings/vesiscan/services/ReminderService.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/services/ReminderService.kt rename to app/src/main/java/com/medithings/vesiscan/services/ReminderService.kt index 9dc403f..e19b4ab 100644 --- a/app/src/main/java/com/example/medilightv2android/services/ReminderService.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/ReminderService.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.app.AlarmManager import android.app.NotificationChannel @@ -15,7 +15,7 @@ import android.os.Vibrator import android.os.VibratorManager import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat -import com.example.medilightv2android.R +import com.medithings.vesiscan.R import java.util.Calendar class ReminderService private constructor(private val context: Context) { diff --git a/app/src/main/java/com/example/medilightv2android/services/ScanLogStore.kt b/app/src/main/java/com/medithings/vesiscan/services/ScanLogStore.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/services/ScanLogStore.kt rename to app/src/main/java/com/medithings/vesiscan/services/ScanLogStore.kt index 9e874a6..2c5c671 100644 --- a/app/src/main/java/com/example/medilightv2android/services/ScanLogStore.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/ScanLogStore.kt @@ -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.StateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/app/src/main/java/com/example/medilightv2android/services/UserStorage.kt b/app/src/main/java/com/medithings/vesiscan/services/UserStorage.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/services/UserStorage.kt rename to app/src/main/java/com/medithings/vesiscan/services/UserStorage.kt index f98a7be..aaa7ef1 100644 --- a/app/src/main/java/com/example/medilightv2android/services/UserStorage.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/UserStorage.kt @@ -1,8 +1,8 @@ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.content.Context import android.content.SharedPreferences -import com.example.medilightv2android.models.* +import com.medithings.vesiscan.models.* import com.google.gson.Gson class UserStorage private constructor(context: Context) { diff --git a/app/src/main/java/com/example/medilightv2android/services/WakeupAlarmPrefs.kt b/app/src/main/java/com/medithings/vesiscan/services/WakeupAlarmPrefs.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/services/WakeupAlarmPrefs.kt rename to app/src/main/java/com/medithings/vesiscan/services/WakeupAlarmPrefs.kt index af39624..609e80d 100644 --- a/app/src/main/java/com/example/medilightv2android/services/WakeupAlarmPrefs.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/WakeupAlarmPrefs.kt @@ -4,7 +4,7 @@ * 사용자가 "설정 탭" 에서 toggle on/off → 일어남 감지 시 빨간 팝업. * LYING 유지 시간 임계 (default 3 min) 도 함께. */ -package com.example.medilightv2android.services +package com.medithings.vesiscan.services import android.content.Context import android.content.SharedPreferences diff --git a/app/src/main/java/com/example/medilightv2android/services/labdb/LabdbClient.kt b/app/src/main/java/com/medithings/vesiscan/services/labdb/LabdbClient.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/services/labdb/LabdbClient.kt rename to app/src/main/java/com/medithings/vesiscan/services/labdb/LabdbClient.kt index 1392cd9..73bd81f 100644 --- a/app/src/main/java/com/example/medilightv2android/services/labdb/LabdbClient.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/labdb/LabdbClient.kt @@ -1,9 +1,9 @@ -package com.example.medilightv2android.services.labdb +package com.medithings.vesiscan.services.labdb import android.content.Context import android.os.Build import android.util.Log -import com.example.medilightv2android.ble.BleManager +import com.medithings.vesiscan.ble.BleManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import okhttp3.MediaType.Companion.toMediaType diff --git a/app/src/main/java/com/example/medilightv2android/services/labdb/LabdbCredentials.kt b/app/src/main/java/com/medithings/vesiscan/services/labdb/LabdbCredentials.kt similarity index 92% rename from app/src/main/java/com/example/medilightv2android/services/labdb/LabdbCredentials.kt rename to app/src/main/java/com/medithings/vesiscan/services/labdb/LabdbCredentials.kt index d7bb686..ce009d8 100644 --- a/app/src/main/java/com/example/medilightv2android/services/labdb/LabdbCredentials.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/labdb/LabdbCredentials.kt @@ -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) 자격 증명 저장소. diff --git a/app/src/main/java/com/example/medilightv2android/services/labdb/LabdbUploader.kt b/app/src/main/java/com/medithings/vesiscan/services/labdb/LabdbUploader.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/services/labdb/LabdbUploader.kt rename to app/src/main/java/com/medithings/vesiscan/services/labdb/LabdbUploader.kt index b69f973..af8f60b 100644 --- a/app/src/main/java/com/example/medilightv2android/services/labdb/LabdbUploader.kt +++ b/app/src/main/java/com/medithings/vesiscan/services/labdb/LabdbUploader.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.services.labdb +package com.medithings.vesiscan.services.labdb import android.content.Context import android.util.Log diff --git a/app/src/main/java/com/example/medilightv2android/speech/HfVolumeExtractor.kt b/app/src/main/java/com/medithings/vesiscan/speech/HfVolumeExtractor.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/speech/HfVolumeExtractor.kt rename to app/src/main/java/com/medithings/vesiscan/speech/HfVolumeExtractor.kt index 88f0296..72c53c3 100644 --- a/app/src/main/java/com/example/medilightv2android/speech/HfVolumeExtractor.kt +++ b/app/src/main/java/com/medithings/vesiscan/speech/HfVolumeExtractor.kt @@ -4,7 +4,7 @@ * MEDiThings Inc. * All rights reserved. */ -package com.example.medilightv2android.speech +package com.medithings.vesiscan.speech import android.util.Log import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/example/medilightv2android/speech/SpeechRecognizerManager.kt b/app/src/main/java/com/medithings/vesiscan/speech/SpeechRecognizerManager.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/speech/SpeechRecognizerManager.kt rename to app/src/main/java/com/medithings/vesiscan/speech/SpeechRecognizerManager.kt index 89452a7..ac0c571 100644 --- a/app/src/main/java/com/example/medilightv2android/speech/SpeechRecognizerManager.kt +++ b/app/src/main/java/com/medithings/vesiscan/speech/SpeechRecognizerManager.kt @@ -4,7 +4,7 @@ * MEDiThings Inc. * All rights reserved. */ -package com.example.medilightv2android.speech +package com.medithings.vesiscan.speech import android.content.Context import android.content.Intent diff --git a/app/src/main/java/com/example/medilightv2android/speech/VolumeParser.kt b/app/src/main/java/com/medithings/vesiscan/speech/VolumeParser.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/speech/VolumeParser.kt rename to app/src/main/java/com/medithings/vesiscan/speech/VolumeParser.kt index 7eee4ef..fd0c618 100644 --- a/app/src/main/java/com/example/medilightv2android/speech/VolumeParser.kt +++ b/app/src/main/java/com/medithings/vesiscan/speech/VolumeParser.kt @@ -4,7 +4,7 @@ * MEDiThings Inc. * 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. diff --git a/app/src/main/java/com/example/medilightv2android/ui/components/BatteryWarningBanner.kt b/app/src/main/java/com/medithings/vesiscan/ui/components/BatteryWarningBanner.kt similarity index 95% rename from app/src/main/java/com/example/medilightv2android/ui/components/BatteryWarningBanner.kt rename to app/src/main/java/com/medithings/vesiscan/ui/components/BatteryWarningBanner.kt index 8ad175f..f4bb9f1 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/components/BatteryWarningBanner.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/components/BatteryWarningBanner.kt @@ -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.layout.Column @@ -22,8 +22,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.R -import com.example.medilightv2android.ble.BleManager +import com.medithings.vesiscan.R +import com.medithings.vesiscan.ble.BleManager /** * 배터리 잔량 경고 배너 — PlacementGuide / PiezoMonitoring 상단. diff --git a/app/src/main/java/com/example/medilightv2android/ui/components/BladdyRiveView.kt b/app/src/main/java/com/medithings/vesiscan/ui/components/BladdyRiveView.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/ui/components/BladdyRiveView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/components/BladdyRiveView.kt index 79d3787..05f826e 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/components/BladdyRiveView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/components/BladdyRiveView.kt @@ -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.size @@ -13,8 +13,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import app.rive.runtime.kotlin.RiveAnimationView import app.rive.runtime.kotlin.core.Fit -import com.example.medilightv2android.R -import com.example.medilightv2android.models.UrgencyLevel +import com.medithings.vesiscan.R +import com.medithings.vesiscan.models.UrgencyLevel import kotlinx.coroutines.delay import kotlin.random.Random diff --git a/app/src/main/java/com/example/medilightv2android/ui/components/BleDisconnectionBanner.kt b/app/src/main/java/com/medithings/vesiscan/ui/components/BleDisconnectionBanner.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/ui/components/BleDisconnectionBanner.kt rename to app/src/main/java/com/medithings/vesiscan/ui/components/BleDisconnectionBanner.kt index 3a04ab4..9dab01c 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/components/BleDisconnectionBanner.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/components/BleDisconnectionBanner.kt @@ -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.layout.* @@ -13,7 +13,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.ui.theme.MlPrimary +import com.medithings.vesiscan.ui.theme.MlPrimary enum class BleReconnectionState { DISCONNECTED, RECONNECTING, FAILED diff --git a/app/src/main/java/com/example/medilightv2android/ui/components/DonutChartView.kt b/app/src/main/java/com/medithings/vesiscan/ui/components/DonutChartView.kt similarity index 95% rename from app/src/main/java/com/example/medilightv2android/ui/components/DonutChartView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/components/DonutChartView.kt index ea10b19..6f4fa01 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/components/DonutChartView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/components/DonutChartView.kt @@ -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.tween @@ -14,7 +14,7 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics 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 fun DonutChartView( diff --git a/app/src/main/java/com/example/medilightv2android/ui/components/FirmwareWarningBanner.kt b/app/src/main/java/com/medithings/vesiscan/ui/components/FirmwareWarningBanner.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/ui/components/FirmwareWarningBanner.kt rename to app/src/main/java/com/medithings/vesiscan/ui/components/FirmwareWarningBanner.kt index 2dd35fc..d00d3a7 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/components/FirmwareWarningBanner.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/components/FirmwareWarningBanner.kt @@ -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.layout.Column @@ -26,8 +26,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.R -import com.example.medilightv2android.ble.BleManager +import com.medithings.vesiscan.R +import com.medithings.vesiscan.ble.BleManager import kotlinx.coroutines.delay /** diff --git a/app/src/main/java/com/example/medilightv2android/ui/components/LockableSlider.kt b/app/src/main/java/com/medithings/vesiscan/ui/components/LockableSlider.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/ui/components/LockableSlider.kt rename to app/src/main/java/com/medithings/vesiscan/ui/components/LockableSlider.kt index 81c31d5..8881e5c 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/components/LockableSlider.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/components/LockableSlider.kt @@ -15,7 +15,7 @@ * UX 톤: * "1회 터치 후 조정" 패턴 — 의도된 조작만 허용. */ -package com.example.medilightv2android.ui.components +package com.medithings.vesiscan.ui.components import androidx.compose.foundation.layout.Row 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.res.stringResource import androidx.compose.ui.unit.dp -import com.example.medilightv2android.R +import com.medithings.vesiscan.R @Composable fun LockableSlider( diff --git a/app/src/main/java/com/example/medilightv2android/ui/components/ScanLogDialog.kt b/app/src/main/java/com/medithings/vesiscan/ui/components/ScanLogDialog.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/ui/components/ScanLogDialog.kt rename to app/src/main/java/com/medithings/vesiscan/ui/components/ScanLogDialog.kt index cc7f152..5689f89 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/components/ScanLogDialog.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/components/ScanLogDialog.kt @@ -5,7 +5,7 @@ * measurement, newest at the bottom, monospace, long-press to select spans * 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.ClipboardManager diff --git a/app/src/main/java/com/example/medilightv2android/ui/theme/Color.kt b/app/src/main/java/com/medithings/vesiscan/ui/theme/Color.kt similarity index 92% rename from app/src/main/java/com/example/medilightv2android/ui/theme/Color.kt rename to app/src/main/java/com/medithings/vesiscan/ui/theme/Color.kt index 1499dc0..563572d 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/theme/Color.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/theme/Color.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ui.theme +package com.medithings.vesiscan.ui.theme import androidx.compose.ui.graphics.Color diff --git a/app/src/main/java/com/example/medilightv2android/ui/theme/DesignTokens.kt b/app/src/main/java/com/medithings/vesiscan/ui/theme/DesignTokens.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/ui/theme/DesignTokens.kt rename to app/src/main/java/com/medithings/vesiscan/ui/theme/DesignTokens.kt index fba1ea4..25fb5d1 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/theme/DesignTokens.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/theme/DesignTokens.kt @@ -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.foundation.gestures.detectTapGestures diff --git a/app/src/main/java/com/example/medilightv2android/ui/theme/Theme.kt b/app/src/main/java/com/medithings/vesiscan/ui/theme/Theme.kt similarity index 95% rename from app/src/main/java/com/example/medilightv2android/ui/theme/Theme.kt rename to app/src/main/java/com/medithings/vesiscan/ui/theme/Theme.kt index 9f4c480..544080d 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/theme/Theme.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/theme/Theme.kt @@ -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.lightColorScheme diff --git a/app/src/main/java/com/example/medilightv2android/ui/theme/Type.kt b/app/src/main/java/com/medithings/vesiscan/ui/theme/Type.kt similarity index 95% rename from app/src/main/java/com/example/medilightv2android/ui/theme/Type.kt rename to app/src/main/java/com/medithings/vesiscan/ui/theme/Type.kt index 408e4f3..deb10ea 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/theme/Type.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/theme/Type.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ui.theme +package com.medithings.vesiscan.ui.theme import androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/calibration/CalibrationView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/calibration/CalibrationView.kt similarity index 94% rename from app/src/main/java/com/example/medilightv2android/ui/views/calibration/CalibrationView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/calibration/CalibrationView.kt index 8825d13..a1043bf 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/calibration/CalibrationView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/calibration/CalibrationView.kt @@ -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.Looper @@ -22,13 +22,13 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.AppState -import com.example.medilightv2android.R -import com.example.medilightv2android.ble.BleManager -import com.example.medilightv2android.managers.NirsManager -import com.example.medilightv2android.models.NirsMagResponse -import com.example.medilightv2android.ui.components.BladdyIdleRiveView -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.R +import com.medithings.vesiscan.ble.BleManager +import com.medithings.vesiscan.managers.NirsManager +import com.medithings.vesiscan.models.NirsMagResponse +import com.medithings.vesiscan.ui.components.BladdyIdleRiveView +import com.medithings.vesiscan.ui.theme.* @Composable fun CalibrationView(appState: AppState) { diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/clinical/ClinicalHomeView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/clinical/ClinicalHomeView.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/ui/views/clinical/ClinicalHomeView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/clinical/ClinicalHomeView.kt index bc9a08b..79c3f8c 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/clinical/ClinicalHomeView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/clinical/ClinicalHomeView.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ui.views.clinical +package com.medithings.vesiscan.ui.views.clinical import android.widget.Toast 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.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.AppScreen -import com.example.medilightv2android.AppState -import com.example.medilightv2android.ble.BleManager -import com.example.medilightv2android.models.* -import com.example.medilightv2android.services.ClinicalSessionStore -import com.example.medilightv2android.services.labdb.LabdbClient -import com.example.medilightv2android.services.labdb.LabdbCredentials -import com.example.medilightv2android.services.labdb.LabdbUploader -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppScreen +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.ble.BleManager +import com.medithings.vesiscan.models.* +import com.medithings.vesiscan.services.ClinicalSessionStore +import com.medithings.vesiscan.services.labdb.LabdbClient +import com.medithings.vesiscan.services.labdb.LabdbCredentials +import com.medithings.vesiscan.services.labdb.LabdbUploader +import com.medithings.vesiscan.ui.theme.* import kotlinx.coroutines.launch /** @@ -397,7 +397,7 @@ fun ClinicalHomeView(appState: AppState) { // 측정 대상 분류 — Phantom/Human/ETC 버튼 (회의 결정) LabeledSegmented( label = "Subject Type", - options = com.example.medilightv2android.models.SubjectType.values().toList(), + options = com.medithings.vesiscan.models.SubjectType.values().toList(), selected = subjectType, onSelect = { subjectType = it } ) { it.label } @@ -492,7 +492,7 @@ fun ClinicalHomeView(appState: AppState) { subjectType = subjectType, subject = subject.trim(), trueVolumeMl = trueVolText.toDoubleOrNull(), abdomenThicknessMm = abdomenText.toDoubleOrNull(), - mode = com.example.medilightv2android.models.SessionMode.MEASUREMENT, + mode = com.medithings.vesiscan.models.SessionMode.MEASUREMENT, ) ) appState.currentScreen = AppScreen.CLINICAL_LIVE @@ -517,9 +517,9 @@ fun ClinicalHomeView(appState: AppState) { subjectType = subjectType, subject = subject.trim(), trueVolumeMl = trueVolText.toDoubleOrNull(), abdomenThicknessMm = abdomenText.toDoubleOrNull(), - mode = com.example.medilightv2android.models.SessionMode.ALIGNMENT, + mode = com.medithings.vesiscan.models.SessionMode.ALIGNMENT, // 현재 dev 토글된 algo 그대로 — V1 (default) 또는 V2. - alignmentAlgo = com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo.name, + alignmentAlgo = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo.name, ) ) appState.enterAlignmentSession() diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/clinical/ClinicalLiveView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/clinical/ClinicalLiveView.kt similarity index 94% rename from app/src/main/java/com/example/medilightv2android/ui/views/clinical/ClinicalLiveView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/clinical/ClinicalLiveView.kt index 14d8646..571c000 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/clinical/ClinicalLiveView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/clinical/ClinicalLiveView.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ui.views.clinical +package com.medithings.vesiscan.ui.views.clinical import android.widget.Toast 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.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.AppScreen -import com.example.medilightv2android.AppState -import com.example.medilightv2android.ble.BleManager -import com.example.medilightv2android.ble.ImuSample -import com.example.medilightv2android.ble.PiezoChannelData -import com.example.medilightv2android.managers.ImuAnalysis -import com.example.medilightv2android.services.AdcCsvLogger -import com.example.medilightv2android.services.ClinicalSessionStore -import com.example.medilightv2android.services.ImuCsvLogger -import com.example.medilightv2android.services.MeasurementLogService -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppScreen +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.ble.BleManager +import com.medithings.vesiscan.ble.ImuSample +import com.medithings.vesiscan.ble.PiezoChannelData +import com.medithings.vesiscan.managers.ImuAnalysis +import com.medithings.vesiscan.services.AdcCsvLogger +import com.medithings.vesiscan.services.ClinicalSessionStore +import com.medithings.vesiscan.services.ImuCsvLogger +import com.medithings.vesiscan.services.MeasurementLogService +import com.medithings.vesiscan.ui.theme.* import kotlinx.coroutines.delay import kotlin.math.max import kotlin.math.min @@ -79,7 +79,7 @@ fun ClinicalLiveView(appState: AppState) { var pendingPiezo by remember { mutableStateOf?>(null) } // 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(6) { null }) } DisposableEffect(Unit) { @@ -91,13 +91,13 @@ fun ClinicalLiveView(appState: AppState) { val adcMatrix = (0 until 6).map { ch -> channels.find { it.channel == ch }?.buffer?.map { it.toInt() } ?: List(100) { 0 } } - val probe = com.example.medilightv2android.walldetect.dto.ProbeProfileDto( - name = com.example.medilightv2android.managers.PiezoHW.presetName, + val probe = com.medithings.vesiscan.walldetect.dto.ProbeProfileDto( + name = com.medithings.vesiscan.managers.PiezoHW.presetName, rMm = 50.2, anteriorAnchorMm = 32.0, 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()}", timestampMs = System.currentTimeMillis(), deviceId = bleManager.connectedDeviceName.value, diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/connection/DeviceScanView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/connection/DeviceScanView.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/ui/views/connection/DeviceScanView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/connection/DeviceScanView.kt index 99e0def..1104dee 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/connection/DeviceScanView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/connection/DeviceScanView.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ui.views.connection +package com.medithings.vesiscan.ui.views.connection import android.Manifest 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.sp import androidx.core.content.ContextCompat -import com.example.medilightv2android.AppState -import com.example.medilightv2android.R -import com.example.medilightv2android.ble.BleDevice -import com.example.medilightv2android.ble.BleManager -import com.example.medilightv2android.models.SensorMode -import com.example.medilightv2android.services.KnownDevice -import com.example.medilightv2android.services.KnownDeviceStore -import com.example.medilightv2android.ui.components.BladdyIdleRiveView -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.R +import com.medithings.vesiscan.ble.BleDevice +import com.medithings.vesiscan.ble.BleManager +import com.medithings.vesiscan.models.SensorMode +import com.medithings.vesiscan.services.KnownDevice +import com.medithings.vesiscan.services.KnownDeviceStore +import com.medithings.vesiscan.ui.components.BladdyIdleRiveView +import com.medithings.vesiscan.ui.theme.* import java.text.SimpleDateFormat import java.util.Date import java.util.Locale @@ -55,7 +55,7 @@ fun DeviceScanView(appState: AppState) { var permissionsGranted by remember { mutableStateOf(false) } // Clinical 흐름에서만 다중 기기 저장/표시 — 일반 사용자는 fresh scan & pair. - val isClinicalFlow = com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow + val isClinicalFlow = com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow var knownDevices by remember { mutableStateOf(if (isClinicalFlow) KnownDeviceStore.getAll(context) else emptyList()) } @@ -287,7 +287,7 @@ fun DeviceScanView(appState: AppState) { Button( onClick = { 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), shape = RoundedCornerShape(12.dp), diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/consent/ConsentView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/consent/ConsentView.kt similarity index 95% rename from app/src/main/java/com/example/medilightv2android/ui/views/consent/ConsentView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/consent/ConsentView.kt index f70a2c4..25ce461 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/consent/ConsentView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/consent/ConsentView.kt @@ -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.clickable @@ -15,13 +15,13 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource 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.sp -import com.example.medilightv2android.AppState -import com.example.medilightv2android.services.UserStorage -import com.example.medilightv2android.ui.components.BladdyIdleRiveView -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.services.UserStorage +import com.medithings.vesiscan.ui.components.BladdyIdleRiveView +import com.medithings.vesiscan.ui.theme.* @Composable fun ConsentView(appState: AppState) { diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/history/MeasurementHistoryView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/history/MeasurementHistoryView.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/ui/views/history/MeasurementHistoryView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/history/MeasurementHistoryView.kt index 1852f03..0d05ca8 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/history/MeasurementHistoryView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/history/MeasurementHistoryView.kt @@ -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.background @@ -31,11 +31,11 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.AppState -import com.example.medilightv2android.R -import com.example.medilightv2android.models.* -import com.example.medilightv2android.services.MeasurementHistoryStore -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.R +import com.medithings.vesiscan.models.* +import com.medithings.vesiscan.services.MeasurementHistoryStore +import com.medithings.vesiscan.ui.theme.* import java.text.SimpleDateFormat import java.util.* diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/home/HomeView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/home/HomeView.kt similarity index 89% rename from app/src/main/java/com/example/medilightv2android/ui/views/home/HomeView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/home/HomeView.kt index f8c22c7..fc4fbbc 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/home/HomeView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/home/HomeView.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ui.views.home +package com.medithings.vesiscan.ui.views.home import android.widget.Toast 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.res.stringResource 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.sp -import com.example.medilightv2android.AppState -import com.example.medilightv2android.ui.components.BladdyIdleRiveView -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.ui.components.BladdyIdleRiveView +import com.medithings.vesiscan.ui.theme.* @Composable fun HomeView(appState: AppState) { @@ -147,7 +147,7 @@ fun HomeView(appState: AppState) { // Dev 모드 한정 — Clinical R&D Mode 진입 if (appState.isDevMode) { Button( - onClick = { appState.currentScreen = com.example.medilightv2android.AppScreen.CLINICAL_HOME }, + onClick = { appState.currentScreen = com.medithings.vesiscan.AppScreen.CLINICAL_HOME }, modifier = Modifier .fillMaxWidth() .padding(horizontal = 32.dp) @@ -166,7 +166,7 @@ fun HomeView(appState: AppState) { // 언어 선택 다이얼로그 — 시스템 / 한국어 / English. 변경 시 Activity recreate. 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) } AlertDialog( onDismissRequest = { showLanguageDialog = false }, @@ -174,9 +174,9 @@ fun HomeView(appState: AppState) { text = { Column { listOf( - com.example.medilightv2android.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.example.medilightv2android.services.LocalePref.Mode.EN to stringResource(R.string.language_english), + com.medithings.vesiscan.services.LocalePref.Mode.SYSTEM to stringResource(R.string.language_system_default), + com.medithings.vesiscan.services.LocalePref.Mode.KO to stringResource(R.string.language_korean), + com.medithings.vesiscan.services.LocalePref.Mode.EN to stringResource(R.string.language_english), ).forEach { (mode, label) -> Row( verticalAlignment = Alignment.CenterVertically, @@ -197,7 +197,7 @@ fun HomeView(appState: AppState) { }, confirmButton = { TextButton(onClick = { - com.example.medilightv2android.services.LocalePref.setMode(context, selected) + com.medithings.vesiscan.services.LocalePref.setMode(context, selected) showLanguageDialog = false // Activity recreate → attachBaseContext 다시 호출 → 새 locale 적용 (context as? android.app.Activity)?.recreate() diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/CatheterizeSheet.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/CatheterizeSheet.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/ui/views/monitoring/CatheterizeSheet.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/CatheterizeSheet.kt index 1cc0cec..4d578f5 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/CatheterizeSheet.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/CatheterizeSheet.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ui.views.monitoring +package com.medithings.vesiscan.ui.views.monitoring import android.widget.Toast 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.sp import androidx.core.content.ContextCompat -import com.example.medilightv2android.R -import com.example.medilightv2android.measure.VoidingRecord -import com.example.medilightv2android.measure.VoidingRecordStore -import com.example.medilightv2android.speech.SpeechRecognizerManager -import com.example.medilightv2android.speech.VolumeParser +import com.medithings.vesiscan.R +import com.medithings.vesiscan.measure.VoidingRecord +import com.medithings.vesiscan.measure.VoidingRecordStore +import com.medithings.vesiscan.speech.SpeechRecognizerManager +import com.medithings.vesiscan.speech.VolumeParser /** * Catheterize 바텀시트 — 수기/음성/카메라 3가지 입력 diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/PiezoMonitoringView.kt similarity index 91% rename from app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/PiezoMonitoringView.kt index 6999e6a..a7dc339 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/PiezoMonitoringView.kt @@ -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.Looper @@ -6,7 +6,7 @@ import android.util.Log import androidx.compose.runtime.rememberCoroutineScope import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -import com.example.medilightv2android.AppScreen +import com.medithings.vesiscan.AppScreen import androidx.compose.material3.OutlinedTextField import androidx.compose.foundation.Canvas 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.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.AppState -import com.example.medilightv2android.ble.BleManager -import com.example.medilightv2android.ble.PiezoChannelData -import com.example.medilightv2android.managers.PiezoEchoAnalyzer -import com.example.medilightv2android.managers.PiezoConstants -import com.example.medilightv2android.managers.GreenZoneConstants -import com.example.medilightv2android.managers.PiezoHW -import com.example.medilightv2android.managers.estimateBladderVolume6ch -import com.example.medilightv2android.models.BladderLevel -import com.example.medilightv2android.models.UrgencyLevel -import com.example.medilightv2android.services.ScanLogStore -import com.example.medilightv2android.ui.components.BladdyRiveView -import com.example.medilightv2android.ui.components.DonutChartView -import com.example.medilightv2android.ui.components.LockableSlider -import com.example.medilightv2android.ui.components.ScanLogDialog -import com.example.medilightv2android.R -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.ble.BleManager +import com.medithings.vesiscan.ble.PiezoChannelData +import com.medithings.vesiscan.managers.PiezoEchoAnalyzer +import com.medithings.vesiscan.managers.PiezoConstants +import com.medithings.vesiscan.managers.GreenZoneConstants +import com.medithings.vesiscan.managers.PiezoHW +import com.medithings.vesiscan.managers.estimateBladderVolume6ch +import com.medithings.vesiscan.models.BladderLevel +import com.medithings.vesiscan.models.UrgencyLevel +import com.medithings.vesiscan.services.ScanLogStore +import com.medithings.vesiscan.ui.components.BladdyRiveView +import com.medithings.vesiscan.ui.components.DonutChartView +import com.medithings.vesiscan.ui.components.LockableSlider +import com.medithings.vesiscan.ui.components.ScanLogDialog +import com.medithings.vesiscan.R +import com.medithings.vesiscan.ui.theme.* import androidx.compose.ui.res.stringResource import kotlin.math.roundToInt @@ -132,21 +132,21 @@ fun PiezoMonitoringView(appState: AppState) { val analyzer = remember { PiezoEchoAnalyzer.shared } // 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 wakeupAlarmElapsedSec by remember { mutableStateOf(0L) } 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 { - com.example.medilightv2android.managers.WakeupDetector( - lyingDurationSec = com.example.medilightv2android.services.WakeupAlarmPrefs.lyingDurationSec(context) + com.medithings.vesiscan.managers.WakeupDetector( + lyingDurationSec = com.medithings.vesiscan.services.WakeupAlarmPrefs.lyingDurationSec(context) ).apply { onWakeup = { elapsed -> - if (com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context)) { + if (com.medithings.vesiscan.services.WakeupAlarmPrefs.isEnabled(context)) { wakeupAlarmElapsedSec = elapsed showWakeupAlarm = true } - com.example.medilightv2android.services.PostureEventLogger.logAlarm( + com.medithings.vesiscan.services.PostureEventLogger.logAlarm( System.currentTimeMillis(), "wakeup_alarm_lying_${elapsed}s" ) @@ -317,7 +317,7 @@ fun PiezoMonitoringView(appState: AppState) { val fullChannels = channels.filter { it.buffer.size >= 20 } if (fullChannels.size >= 6) { 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 (!wasDetached) { 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 allChannelsReceived = channels.filter { it.buffer.size >= 20 }.size >= 6 if (validChannels.isNotEmpty() && allChannelsReceived) { - val method = com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod - val analyzerA = com.example.medilightv2android.managers.PiezoEchoAnalyzerA.shared + val method = com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod + val analyzerA = com.medithings.vesiscan.managers.PiezoEchoAnalyzerA.shared var methodCBvMl: Double? = null val methodLabel: String when (method) { - com.example.medilightv2android.managers.DetectionMethod.METHOD_C -> { + com.medithings.vesiscan.managers.DetectionMethod.METHOD_C -> { methodLabel = "C" // 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 chData = channels.find { it.channel == ch } chData?.buffer?.map { it.toInt() } ?: List(100) { 0 } } - val probe = com.example.medilightv2android.walldetect.dto.ProbeProfileDto( - name = com.example.medilightv2android.managers.PiezoHW.presetName, + val probe = com.medithings.vesiscan.walldetect.dto.ProbeProfileDto( + name = com.medithings.vesiscan.managers.PiezoHW.presetName, rMm = 50.2, anteriorAnchorMm = 32.0, 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()}", timestampMs = System.currentTimeMillis(), 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") } } - com.example.medilightv2android.managers.DetectionMethod.METHOD_A -> { + com.medithings.vesiscan.managers.DetectionMethod.METHOD_A -> { methodLabel = "A" val channelResults = validChannels.map { analyzerA.analyzeChannel(it.buffer, it.channel) } 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}") } } - com.example.medilightv2android.managers.DetectionMethod.METHOD_D -> { + com.medithings.vesiscan.managers.DetectionMethod.METHOD_D -> { // 2026-06-30: Detection + BV 통합. MethodDRunner 로 6채널 raw → walls. methodLabel = "D" val signals = (0..5).map { ch -> val cd = channels.find { it.channel == ch } cd?.buffer?.map { it.toDouble() }?.toDoubleArray() ?: DoubleArray(0) } - val dets = com.example.medilightv2android.walldetect.MethodDRunner + val dets = com.medithings.vesiscan.walldetect.MethodDRunner .detectMultichannel(signals) for (i in 0..5) { val r = dets.getOrNull(i) @@ -443,10 +443,10 @@ fun PiezoMonitoringView(appState: AppState) { totalWallCount = allWalls.count { it != null } // 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 w = allWalls[ch] - com.example.medilightv2android.services.ChannelLogEntry( + com.medithings.vesiscan.services.ChannelLogEntry( channel = ch, ant = w?.first, post = w?.second, @@ -456,7 +456,7 @@ fun PiezoMonitoringView(appState: AppState) { } 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 ─────────────────────────────── // 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). @@ -467,13 +467,13 @@ fun PiezoMonitoringView(appState: AppState) { val antOffsetSamples = if (antOffsetMm != 0) (antOffsetMm.toDouble() / - com.example.medilightv2android.managers.PiezoHW.distancePerSample).toInt() + com.medithings.vesiscan.managers.PiezoHW.distancePerSample).toInt() else 0 // 2026-06-30: BvMethod.METHOD_D 시 Method D walls 사용. 단 detection 이 // 이미 METHOD_D 면 allWalls 가 곧 Method D → recompute 생략. - val useMethodDBv = bvMethodSetting == com.example.medilightv2android.managers.BvMethod.METHOD_D - val detectionIsMethodD = method == com.example.medilightv2android.managers.DetectionMethod.METHOD_D + val useMethodDBv = bvMethodSetting == com.medithings.vesiscan.managers.BvMethod.METHOD_D + val detectionIsMethodD = method == com.medithings.vesiscan.managers.DetectionMethod.METHOD_D val sourceAllWalls: List?> = if (useMethodDBv && !detectionIsMethodD) { val signals = (0..5).map { ch -> val cd = channels.find { it.channel == ch } @@ -482,10 +482,10 @@ fun PiezoMonitoringView(appState: AppState) { if (signals.all { it.isEmpty() }) allWalls // 2026-07-02: NEW BV lib (piezophantomtest 4830e7c) lumen_inset_frac=0.15 // MethodDResult 의 (ls, le) 로 벽을 lumen 안쪽으로 15% 이동. - else com.example.medilightv2android.walldetect.MethodDRunner + else com.medithings.vesiscan.walldetect.MethodDRunner .detectMultichannel(signals) .map { r -> r?.let { - com.example.medilightv2android.managers.applyLumenInsetOne( + com.medithings.vesiscan.managers.applyLumenInsetOne( 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 useV41Bv = method == com.example.medilightv2android.managers.DetectionMethod.METHOD_C - && bvMethodSetting == com.example.medilightv2android.managers.BvMethod.V41 + val useV41Bv = method == com.medithings.vesiscan.managers.DetectionMethod.METHOD_C + && bvMethodSetting == com.medithings.vesiscan.managers.BvMethod.V41 && methodCBvMl != null && antOffsetSamples == 0 && effectiveCenterWalls >= 4 // center 4 모두 필요 @@ -510,7 +510,7 @@ fun PiezoMonitoringView(appState: AppState) { bleManager.debugLogger.measurementResult(methodCBvMl, 1.0, totalWallCount, (0..5).map { allWalls[it]?.let { w -> w.second - w.first } ?: 0 }) 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) { // 검증 로그 — ant offset 비활성(0)이 아닐 때 chord 변화 출력 if (antOffsetSamples != 0) { @@ -534,18 +534,18 @@ fun PiezoMonitoringView(appState: AppState) { (0..5).map { allWalls[it]?.let { w -> w.second - w.first } ?: 0 }, otsuThreshold = analyzer.lastOtsuThreshold) 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) { 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") - com.example.medilightv2android.services.AdcCsvLogger.log(rawADC, null) + bleManager.debugLogger.warn("BV_SKIP scan=${com.medithings.vesiscan.services.AdcCsvLogger.lastScanId} center=0 total=$totalWallCount/6") + com.medithings.vesiscan.services.AdcCsvLogger.log(rawADC, null) } } else { 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 } - com.example.medilightv2android.services.AdcCsvLogger.log(failADC, null) + com.medithings.vesiscan.services.AdcCsvLogger.log(failADC, null) } // allWalls를 UI state에 저장 (ChannelPanel에서 사용) @@ -754,8 +754,8 @@ fun PiezoMonitoringView(appState: AppState) { // Posture event 로깅 — 검증용 CSV (앱 진입 시 새 파일) // + 사용자 튜닝 임계값 SharedPreferences 에서 로드 LaunchedEffect(Unit) { - com.example.medilightv2android.services.PostureTuningPrefs.loadAll(context) - com.example.medilightv2android.services.PostureEventLogger.startSession(context) + com.medithings.vesiscan.services.PostureTuningPrefs.loadAll(context) + com.medithings.vesiscan.services.PostureEventLogger.startSession(context) } // IMU polling + 자세 분류 — msp 명령 (rsp: 응답, IMU-only). @@ -766,12 +766,12 @@ fun PiezoMonitoringView(appState: AppState) { LaunchedEffect(isConnected, isDemoMode) { Log.d("ImuDbg", "LaunchedEffect start isConnected=$isConnected isDemoMode=$isDemoMode") if (isDemoMode) { - currentPosture = com.example.medilightv2android.managers.Posture.LYING + currentPosture = com.medithings.vesiscan.managers.Posture.LYING return@LaunchedEffect } var unknownStreak = 0 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() // Walking detector — pitch 가 valid 일 때만 의미. acc gate fail 시 그대로 update (wmean/wstd 계산 + 시간 grace 처리). val walkSnap = walkingDetector.update(samples, r.pitchDeg, nowMs) @@ -779,34 +779,34 @@ fun PiezoMonitoringView(appState: AppState) { // Composite posture — WALKING 이 UNKNOWN/NON_LYING 보다 우선 (자체 게이트 신뢰) val composite = when { - isWalkingNow -> com.example.medilightv2android.managers.Posture.WALKING - r.posture == com.example.medilightv2android.managers.Posture.UNKNOWN -> com.example.medilightv2android.managers.Posture.UNKNOWN + isWalkingNow -> com.medithings.vesiscan.managers.Posture.WALKING + r.posture == com.medithings.vesiscan.managers.Posture.UNKNOWN -> com.medithings.vesiscan.managers.Posture.UNKNOWN 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 wakeupDetector.update(composite) unknownStreak = 0 } else { 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 시) if (isWalkingNow && !prevIsWalking) { - if (com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context)) { + if (com.medithings.vesiscan.services.WakeupAlarmPrefs.isEnabled(context)) { showWalkingAlarm = true } - com.example.medilightv2android.services.PostureEventLogger.logAlarm(nowMs, "walking_start") + com.medithings.vesiscan.services.PostureEventLogger.logAlarm(nowMs, "walking_start") } if (!isWalkingNow && prevIsWalking) { - com.example.medilightv2android.services.PostureEventLogger.logAlarm(nowMs, "walking_end") + com.medithings.vesiscan.services.PostureEventLogger.logAlarm(nowMs, "walking_end") } prevIsWalking = isWalkingNow // CSV logging — 검증용 - com.example.medilightv2android.services.PostureEventLogger.logCycle( + com.medithings.vesiscan.services.PostureEventLogger.logCycle( nowMs, composite.name, isWalkingNow, 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 Surface( onClick = { - com.example.medilightv2android.measure.VoidingRecordStore.add( - context, com.example.medilightv2android.measure.VoidingRecord( + com.medithings.vesiscan.measure.VoidingRecordStore.add( + context, com.medithings.vesiscan.measure.VoidingRecord( volume = quickVol, method = "catheterize" ) ) @@ -1021,8 +1021,8 @@ fun PiezoMonitoringView(appState: AppState) { TextButton(onClick = { val vol = volumeText.toIntOrNull() if (vol != null && vol in 1..1000) { - com.example.medilightv2android.measure.VoidingRecordStore.add( - context, com.example.medilightv2android.measure.VoidingRecord(volume = vol, method = "manual") + com.medithings.vesiscan.measure.VoidingRecordStore.add( + context, com.medithings.vesiscan.measure.VoidingRecord(volume = vol, method = "manual") ) appState.resetLevel() 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) { var voiceResult by remember { mutableStateOf(null) } var isListening by remember { mutableStateOf(false) } - var speechMgr by remember { mutableStateOf(null) } + var speechMgr by remember { mutableStateOf(null) } 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) == android.content.pm.PackageManager.PERMISSION_GRANTED) { isListening = true - speechMgr = com.example.medilightv2android.speech.SpeechRecognizerManager( + speechMgr = com.medithings.vesiscan.speech.SpeechRecognizerManager( context = context, onResult = { candidates -> isListening = false - val parsed = com.example.medilightv2android.speech.VolumeParser.parseBest(candidates) + val parsed = com.medithings.vesiscan.speech.VolumeParser.parseBest(candidates) if (parsed != null) { - com.example.medilightv2android.measure.VoidingRecordStore.add( - context, com.example.medilightv2android.measure.VoidingRecord(volume = parsed.volumeMl, method = "voice") + com.medithings.vesiscan.measure.VoidingRecordStore.add( + context, com.medithings.vesiscan.measure.VoidingRecord(volume = parsed.volumeMl, method = "voice") ) appState.resetLevel() 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 유지) — 일반 사용자에겐 숨김. if (appState.isDevMode) { var rawBleCapturing by remember { - mutableStateOf(com.example.medilightv2android.services.RawBleLogger.isCapturing) + mutableStateOf(com.medithings.vesiscan.services.RawBleLogger.isCapturing) } IconButton( onClick = { if (rawBleCapturing) { - val f = com.example.medilightv2android.services.RawBleLogger.stopCapture() - val n = com.example.medilightv2android.services.RawBleLogger.count + val f = com.medithings.vesiscan.services.RawBleLogger.stopCapture() + val n = com.medithings.vesiscan.services.RawBleLogger.count rawBleCapturing = false android.widget.Toast.makeText(context, "Raw BLE: $n packets saved to ${f?.name}", android.widget.Toast.LENGTH_LONG).show() } else { - val f = com.example.medilightv2android.services.RawBleLogger.startCapture() + val f = com.medithings.vesiscan.services.RawBleLogger.startCapture() rawBleCapturing = true android.widget.Toast.makeText(context, "Raw BLE capture started → ${f.name}", @@ -1256,8 +1256,8 @@ fun PiezoMonitoringView(appState: AppState) { // BLE 끊김 banner는 사내 테스트 피드백으로 제거됨 — 백그라운드 자동 재연결만 유지. // 펌웨어 구버전 경고 - com.example.medilightv2android.ui.components.FirmwareWarningBanner(bleManager) - com.example.medilightv2android.ui.components.BatteryWarningBanner(bleManager) + com.medithings.vesiscan.ui.components.FirmwareWarningBanner(bleManager) + com.medithings.vesiscan.ui.components.BatteryWarningBanner(bleManager) val scrollState = rememberScrollState() LaunchedEffect(showSettings) { @@ -1306,22 +1306,22 @@ fun PiezoMonitoringView(appState: AppState) { label = "posture-chip" ) { posture -> val icon = when (posture) { - com.example.medilightv2android.managers.Posture.LYING -> Icons.Default.Hotel - com.example.medilightv2android.managers.Posture.NON_LYING -> Icons.Default.AccessibilityNew - com.example.medilightv2android.managers.Posture.WALKING -> Icons.Default.DirectionsWalk - com.example.medilightv2android.managers.Posture.UNKNOWN -> Icons.Default.HelpOutline + com.medithings.vesiscan.managers.Posture.LYING -> Icons.Default.Hotel + com.medithings.vesiscan.managers.Posture.NON_LYING -> Icons.Default.AccessibilityNew + com.medithings.vesiscan.managers.Posture.WALKING -> Icons.Default.DirectionsWalk + com.medithings.vesiscan.managers.Posture.UNKNOWN -> Icons.Default.HelpOutline } val tint = when (posture) { - com.example.medilightv2android.managers.Posture.LYING -> Color(0xFF2196F3) - com.example.medilightv2android.managers.Posture.NON_LYING -> Color(0xFF4CAF50) - com.example.medilightv2android.managers.Posture.WALKING -> Color(0xFFD32F2F) - com.example.medilightv2android.managers.Posture.UNKNOWN -> Color(0xFF616161) // 진한 회색 — 가시성 확보 + com.medithings.vesiscan.managers.Posture.LYING -> Color(0xFF2196F3) + com.medithings.vesiscan.managers.Posture.NON_LYING -> Color(0xFF4CAF50) + com.medithings.vesiscan.managers.Posture.WALKING -> Color(0xFFD32F2F) + com.medithings.vesiscan.managers.Posture.UNKNOWN -> Color(0xFF616161) // 진한 회색 — 가시성 확보 } val label = when (posture) { - com.example.medilightv2android.managers.Posture.LYING -> stringResource(R.string.piezo_posture_lying) - com.example.medilightv2android.managers.Posture.NON_LYING -> stringResource(R.string.piezo_posture_upright) - com.example.medilightv2android.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.LYING -> stringResource(R.string.piezo_posture_lying) + com.medithings.vesiscan.managers.Posture.NON_LYING -> stringResource(R.string.piezo_posture_upright) + com.medithings.vesiscan.managers.Posture.WALKING -> stringResource(R.string.piezo_posture_walking) + com.medithings.vesiscan.managers.Posture.UNKNOWN -> stringResource(R.string.piezo_posture_detecting) } Row( verticalAlignment = Alignment.CenterVertically, @@ -1458,8 +1458,8 @@ fun PiezoMonitoringView(appState: AppState) { Button( onClick = { val quickVol = if (lastVolumeMl > 0) lastVolumeMl.toInt() else appState.estimatedVolume - com.example.medilightv2android.measure.VoidingRecordStore.add( - context, com.example.medilightv2android.measure.VoidingRecord( + com.medithings.vesiscan.measure.VoidingRecordStore.add( + context, com.medithings.vesiscan.measure.VoidingRecord( volume = quickVol, method = "catheterize" ) ) @@ -1847,22 +1847,22 @@ fun PiezoMonitoringView(appState: AppState) { HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding)) // 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) { Text("Detection", fontSize = labelSize, fontWeight = FontWeight.SemiBold) Spacer(modifier = Modifier.weight(1f)) val methods = listOf( - com.example.medilightv2android.managers.DetectionMethod.METHOD_A to "A", - com.example.medilightv2android.managers.DetectionMethod.METHOD_B to "B", - com.example.medilightv2android.managers.DetectionMethod.METHOD_C to "C", - com.example.medilightv2android.managers.DetectionMethod.METHOD_D to "D" + com.medithings.vesiscan.managers.DetectionMethod.METHOD_A to "A", + com.medithings.vesiscan.managers.DetectionMethod.METHOD_B to "B", + com.medithings.vesiscan.managers.DetectionMethod.METHOD_C to "C", + com.medithings.vesiscan.managers.DetectionMethod.METHOD_D to "D" ) val colors = listOf(Color(0xFF9C27B0), MlPrimary, Color(0xFFFF5722), Color(0xFF7C3AED)) Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { methods.forEachIndexed { idx, (m, label) -> val sel = selectedMethod == m 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), shape = RoundedCornerShape(8.dp), colors = ButtonDefaults.buttonColors( @@ -1880,21 +1880,21 @@ fun PiezoMonitoringView(appState: AppState) { HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding)) // 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) { Text("BV", fontSize = labelSize, fontWeight = FontWeight.SemiBold) Spacer(modifier = Modifier.weight(1f)) val bvMethods = listOf( - com.example.medilightv2android.managers.BvMethod.FRUSTUM to "Frustum", - com.example.medilightv2android.managers.BvMethod.V41 to "V41", - com.example.medilightv2android.managers.BvMethod.METHOD_D to "Method D" + com.medithings.vesiscan.managers.BvMethod.FRUSTUM to "Frustum", + com.medithings.vesiscan.managers.BvMethod.V41 to "V41", + com.medithings.vesiscan.managers.BvMethod.METHOD_D to "Method D" ) val bvColors = listOf(MlPrimary, Color(0xFFFF5722), Color(0xFF7C3AED)) Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { bvMethods.forEachIndexed { idx, (m, label) -> val sel = selectedBvMethod == m 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), shape = RoundedCornerShape(8.dp), colors = ButtonDefaults.buttonColors( @@ -1913,7 +1913,7 @@ fun PiezoMonitoringView(appState: AppState) { // 2026-07-01: lr_ratio override (algorithm 팀 4830e7c 표준) 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) { Text("lr=1.0 fixed", fontSize = labelSize, fontWeight = FontWeight.SemiBold) @@ -1921,7 +1921,7 @@ fun PiezoMonitoringView(appState: AppState) { Switch(checked = lrFixed, onCheckedChange = { lrFixed = it - com.example.medilightv2android.managers.GreenZoneConstants.lrRatioOverride = + com.medithings.vesiscan.managers.GreenZoneConstants.lrRatioOverride = if (it) 1.0 else null }, colors = SwitchDefaults.colors(checkedTrackColor = MlPrimary)) @@ -1970,7 +1970,7 @@ fun PiezoMonitoringView(appState: AppState) { LockableSlider( value = pitchThrVal, onValueChange = { pitchThrVal = it; GreenZoneConstants.pitchLyingThreshold = it - com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) }, + com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context) }, valueRange = 10f..70f, steps = 11, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary) @@ -1980,7 +1980,7 @@ fun PiezoMonitoringView(appState: AppState) { // Wakeup Alarm toggle (Personalization 페이지 와 동일 prefs) var wakeupEnabled by remember { - mutableStateOf(com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context)) + mutableStateOf(com.medithings.vesiscan.services.WakeupAlarmPrefs.isEnabled(context)) } Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { @@ -1993,7 +1993,7 @@ fun PiezoMonitoringView(appState: AppState) { checked = wakeupEnabled, onCheckedChange = { wakeupEnabled = it - com.example.medilightv2android.services.WakeupAlarmPrefs.setEnabled(context, it) + com.medithings.vesiscan.services.WakeupAlarmPrefs.setEnabled(context, it) }, colors = SwitchDefaults.colors(checkedTrackColor = Color(0xFFD32F2F)) ) @@ -2002,7 +2002,7 @@ fun PiezoMonitoringView(appState: AppState) { // Wakeup 알람 발동을 위한 LYING 유지 시간 (dev 조절 가능) var lyingDurVal by remember { mutableStateOf( - com.example.medilightv2android.services.WakeupAlarmPrefs.lyingDurationSec(context).toFloat() + com.medithings.vesiscan.services.WakeupAlarmPrefs.lyingDurationSec(context).toFloat() ) } Row(verticalAlignment = Alignment.CenterVertically) { @@ -2021,7 +2021,7 @@ fun PiezoMonitoringView(appState: AppState) { onValueChange = { lyingDurVal = it val sec = it.toInt() - com.example.medilightv2android.services.WakeupAlarmPrefs.setLyingDurationSec(context, sec) + com.medithings.vesiscan.services.WakeupAlarmPrefs.setLyingDurationSec(context, sec) wakeupDetector.lyingDurationSec = sec }, valueRange = 5f..600f, // 5초 ~ 10분 @@ -2046,7 +2046,7 @@ fun PiezoMonitoringView(appState: AppState) { onValueChange = { pollIntervalVal = it GreenZoneConstants.posturePollIntervalMs = (it * 1000).toLong() - com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) + com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context) }, valueRange = 1f..15f, // 1초 ~ 15초 steps = 0, @@ -2066,7 +2066,7 @@ fun PiezoMonitoringView(appState: AppState) { } LockableSlider(value = walkPitchVal, onValueChange = { 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)) var walkStartWmean by remember { mutableStateOf(GreenZoneConstants.walkingStartWmean) } @@ -2077,7 +2077,7 @@ fun PiezoMonitoringView(appState: AppState) { } LockableSlider(value = walkStartWmean, onValueChange = { 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)) var walkStartWstd by remember { mutableStateOf(GreenZoneConstants.walkingStartWstd) } @@ -2088,7 +2088,7 @@ fun PiezoMonitoringView(appState: AppState) { } LockableSlider(value = walkStartWstd, onValueChange = { 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)) var walkKeepWmean by remember { mutableStateOf(GreenZoneConstants.walkingKeepWmean) } @@ -2099,7 +2099,7 @@ fun PiezoMonitoringView(appState: AppState) { } LockableSlider(value = walkKeepWmean, onValueChange = { 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)) // Walking 시간 변수 (sec) @@ -2111,7 +2111,7 @@ fun PiezoMonitoringView(appState: AppState) { } LockableSlider(value = walkStartHold, onValueChange = { 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)) var walkKeepHold by remember { mutableStateOf(GreenZoneConstants.walkingKeepHoldMs / 1000f) } @@ -2122,7 +2122,7 @@ fun PiezoMonitoringView(appState: AppState) { } LockableSlider(value = walkKeepHold, onValueChange = { 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)) var walkWindow by remember { mutableStateOf(GreenZoneConstants.walkingWindowMs / 1000f) } @@ -2133,7 +2133,7 @@ fun PiezoMonitoringView(appState: AppState) { } LockableSlider(value = walkWindow, onValueChange = { 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)) HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding)) @@ -2149,7 +2149,7 @@ fun PiezoMonitoringView(appState: AppState) { } LockableSlider(value = accMagMin, onValueChange = { 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)) var accMagMax by remember { mutableStateOf(GreenZoneConstants.postureAccMagMax) } @@ -2160,7 +2160,7 @@ fun PiezoMonitoringView(appState: AppState) { } LockableSlider(value = accMagMax, onValueChange = { 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)) HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding)) @@ -2168,7 +2168,7 @@ fun PiezoMonitoringView(appState: AppState) { // Reset to defaults — 모든 threshold 를 default 로 복원 + prefs 저장. OutlinedButton( onClick = { - com.example.medilightv2android.services.PostureTuningPrefs.resetAll(context) + com.medithings.vesiscan.services.PostureTuningPrefs.resetAll(context) android.widget.Toast.makeText(context, "Defaults restored — close & reopen Settings to refresh sliders", android.widget.Toast.LENGTH_LONG).show() @@ -2201,7 +2201,7 @@ fun PiezoMonitoringView(appState: AppState) { for ((tag, label) in annotateLabels) { Button( onClick = { - com.example.medilightv2android.services.PostureEventLogger.annotate(tag) + com.medithings.vesiscan.services.PostureEventLogger.annotate(tag) android.widget.Toast.makeText(context, "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) Spacer(modifier = Modifier.weight(1f)) Text( - com.example.medilightv2android.BuildConfig.VERSION_NAME, + com.medithings.vesiscan.BuildConfig.VERSION_NAME, fontSize = 13.sp, fontWeight = FontWeight.SemiBold, color = MlPrimary, @@ -2378,7 +2378,7 @@ fun PiezoMonitoringView(appState: AppState) { Button(onClick = { showRealignPrompt = false 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)) } }, dismissButton = { @@ -2443,11 +2443,11 @@ private fun ChannelPanel( } } else { // Zone indicator - val curMethod = com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod - val analyzerAPanel = com.example.medilightv2android.managers.PiezoEchoAnalyzerA.shared + val curMethod = com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod + val analyzerAPanel = com.medithings.vesiscan.managers.PiezoEchoAnalyzerA.shared val analyses = lastMultiChannelResult.map { chData -> 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) } } @@ -2509,7 +2509,7 @@ private fun ChannelPanel( // Per-channel waveforms for (chData in lastMultiChannelResult.filter { it.buffer.isNotEmpty() }) { 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) } @@ -2537,8 +2537,8 @@ private fun ChannelPanel( fontSize = 10.sp, fontWeight = FontWeight.SemiBold, color = Color.Cyan ) Spacer(modifier = Modifier.width(4.dp)) - val dps = com.example.medilightv2android.managers.PiezoHW.distancePerSample - val offset = com.example.medilightv2android.managers.PiezoHW.delayOffsetMm + val dps = com.medithings.vesiscan.managers.PiezoHW.distancePerSample + val offset = com.medithings.vesiscan.managers.PiezoHW.delayOffsetMm Text( "(${"%.0f".format(offset + antIdx * dps)}–${"%.0f".format(offset + postIdx * dps)}mm)", fontSize = 9.sp, color = MlSecondaryText @@ -2804,13 +2804,13 @@ private fun BleDebugPanel(bleManager: BleManager) { ) { for (entry in entries) { val color = when (entry.level) { - com.example.medilightv2android.services.BleDebugLogger.Level.TX -> Color(0xFF64B5F6) - com.example.medilightv2android.services.BleDebugLogger.Level.RX -> Color(0xFF81C784) - com.example.medilightv2android.services.BleDebugLogger.Level.ERROR -> Color.Red - com.example.medilightv2android.services.BleDebugLogger.Level.WARN -> Color(0xFFFFB74D) - com.example.medilightv2android.services.BleDebugLogger.Level.RSSI -> Color(0xFFFFD54F) - com.example.medilightv2android.services.BleDebugLogger.Level.CONN -> Color(0xFFCE93D8) - com.example.medilightv2android.services.BleDebugLogger.Level.INFO -> Color.White + com.medithings.vesiscan.services.BleDebugLogger.Level.TX -> Color(0xFF64B5F6) + com.medithings.vesiscan.services.BleDebugLogger.Level.RX -> Color(0xFF81C784) + com.medithings.vesiscan.services.BleDebugLogger.Level.ERROR -> Color.Red + com.medithings.vesiscan.services.BleDebugLogger.Level.WARN -> Color(0xFFFFB74D) + com.medithings.vesiscan.services.BleDebugLogger.Level.RSSI -> Color(0xFFFFD54F) + com.medithings.vesiscan.services.BleDebugLogger.Level.CONN -> Color(0xFFCE93D8) + com.medithings.vesiscan.services.BleDebugLogger.Level.INFO -> Color.White } Text( entry.toLogLine(), diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PlacementGuideView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/PlacementGuideView.kt similarity index 91% rename from app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PlacementGuideView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/PlacementGuideView.kt index fbab1af..f25b587 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PlacementGuideView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/PlacementGuideView.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ui.views.monitoring +package com.medithings.vesiscan.ui.views.monitoring import android.util.Log 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.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.AppScreen -import com.example.medilightv2android.AppState -import com.example.medilightv2android.R -import com.example.medilightv2android.ble.BleManager -import com.example.medilightv2android.ble.PiezoChannelData -import com.example.medilightv2android.managers.DetachmentDetection -import com.example.medilightv2android.managers.PiezoEchoAnalyzer -import com.example.medilightv2android.managers.PiezoHW -import com.example.medilightv2android.managers.UrinAI -import com.example.medilightv2android.services.MeasurementLogService -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppScreen +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.R +import com.medithings.vesiscan.ble.BleManager +import com.medithings.vesiscan.ble.PiezoChannelData +import com.medithings.vesiscan.managers.DetachmentDetection +import com.medithings.vesiscan.managers.PiezoEchoAnalyzer +import com.medithings.vesiscan.managers.PiezoHW +import com.medithings.vesiscan.managers.UrinAI +import com.medithings.vesiscan.services.MeasurementLogService +import com.medithings.vesiscan.ui.theme.* /** * Sensor Alignment Guide -- shown after BLE connection, before measurement. @@ -80,8 +80,8 @@ fun PlacementGuideView(appState: AppState) { var phaseHoldHint by remember { mutableStateOf("") } // 강제 힌트 val channelDetected = remember { mutableStateListOf(false, false, false, false, false, false) } val channelUrineLen = remember { mutableStateListOf(0, 0, 0, 0, 0, 0) } - val isSweepMode = com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode == - com.example.medilightv2android.managers.PlacementGuideMode.SWEEP + val isSweepMode = com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode == + com.medithings.vesiscan.managers.PlacementGuideMode.SWEEP var directionHint by remember { mutableStateOf( if (isSweepMode) context.getString(R.string.placement_sweep_initial) else context.getString(R.string.placement_initial_hint) @@ -96,16 +96,16 @@ fun PlacementGuideView(appState: AppState) { var greenFailCount by remember { mutableIntStateOf(0) } // GREEN 이탈 디바운스 var lastChannelData by remember { mutableStateOf>(emptyList()) } // 최근 IMU 샘플 (15개, ODR 50Hz, ~300ms 분량). 자세 판정/흔들림 감지/임상 로그용. - var lastImuSamples by remember { mutableStateOf>(emptyList()) } + var lastImuSamples by remember { mutableStateOf>(emptyList()) } var lastWallResults by remember { mutableStateOf?>>(List(6) { null }) } var debounceCount by remember { mutableIntStateOf(0) } var lastGuidePhase by remember { mutableStateOf(PlacementPhase.VERTICAL) } var lastHintChangeMs by remember { mutableStateOf(0L) } // 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 - val rTracker = remember { com.example.medilightv2android.managers.BladderSeekRTracker() } + val rTracker = remember { com.medithings.vesiscan.managers.BladderSeekRTracker() } var currentRMm by remember { mutableStateOf(null) } var bestRMm by remember { mutableStateOf(0.0) } var sagittalArgMaxCh by remember { mutableStateOf(null) } @@ -127,13 +127,13 @@ fun PlacementGuideView(appState: AppState) { // V2 (4-stage Method D) 는 R&D/clinical alignment session 전용. // 일반 사용자 flow (Home → Start → Personalization → PlacementGuide) 는 V1 사용. LaunchedEffect(Unit) { - val sess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession + val sess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession val isClinicalAlign = !appState.placementFromMonitoring && sess != null && - sess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT - com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo = - if (isClinicalAlign) com.example.medilightv2android.managers.AlignmentAlgo.V2 - else com.example.medilightv2android.managers.AlignmentAlgo.V1 + sess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT + com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo = + if (isClinicalAlign) com.medithings.vesiscan.managers.AlignmentAlgo.V2 + else com.medithings.vesiscan.managers.AlignmentAlgo.V1 v2Aligner.reset() // Clinical alignment session 진입 시 — 자동으로 scan 시작 (Step 0 baseline 캡쳐). // waitingForStart 는 true 유지 — 사용자는 여전히 Start 눌러 알고리즘 시작 결정. @@ -256,10 +256,10 @@ fun PlacementGuideView(appState: AppState) { // Clinical alignment session 진입한 경우 — 저장 후 Clinical Home 으로. // (PiezoMonitoring / Personalization 으로 떨어지지 않게) // Back / Skip 도 endMeasurement → measurement.json + labdb 자동 업로드 (Complete 와 동일). - val curSess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession - if (curSess != null && curSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT) { - com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context) - com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = true + val curSess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession + if (curSess != null && curSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT) { + com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context) + com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow = true appState.currentScreen = AppScreen.CLINICAL_HOME } else { appState.backFromPlacementGuide() @@ -279,10 +279,10 @@ fun PlacementGuideView(appState: AppState) { // Skip — top bar 우측 (유일한 Skip 진입점) TextButton(onClick = { isContinuousMode = false - val curSess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession - if (curSess != null && curSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT) { - com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context) - com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = true + val curSess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession + if (curSess != null && curSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT) { + com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context) + com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow = true appState.currentScreen = AppScreen.CLINICAL_HOME } else { 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%) - com.example.medilightv2android.ui.components.BatteryWarningBanner(bleManager) + com.medithings.vesiscan.ui.components.BatteryWarningBanner(bleManager) Box(modifier = Modifier.fillMaxSize()) { Column( @@ -435,7 +435,7 @@ fun PlacementGuideView(appState: AppState) { ) { // 1) 하복부 일러스트 (배경 — 박스 가득) 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), modifier = Modifier.matchParentSize(), contentScale = ContentScale.FillBounds @@ -444,14 +444,14 @@ fun PlacementGuideView(appState: AppState) { val sensorBitmap = remember { android.graphics.BitmapFactory.decodeResource( context.resources, - com.example.medilightv2android.R.drawable.sensor_device, + com.medithings.vesiscan.R.drawable.sensor_device, ).asImageBitmap() } // 방향 화살표 PNG (132x112, 우향). 회전 + tint 로 4방향 + 색감 통일. val arrowBitmap = remember { android.graphics.BitmapFactory.decodeResource( context.resources, - com.example.medilightv2android.R.drawable.arrow_transparent, + com.medithings.vesiscan.R.drawable.arrow_transparent, ).asImageBitmap() } Canvas(modifier = Modifier.fillMaxSize()) { @@ -575,17 +575,17 @@ fun PlacementGuideView(appState: AppState) { ) { // V2 활성 시 5-stage step indicator, 아니면 V1 의 3-stage. // 2026-07-01: FINAL_CONFIRM phase 추가 (feature/tab-navigation 동기화). - val isV2Active = com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo == - com.example.medilightv2android.managers.AlignmentAlgo.V2 + val isV2Active = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo == + com.medithings.vesiscan.managers.AlignmentAlgo.V2 // 2026-07-02: CENTER_OPTIMIZE 추가 (5-stage → 6-stage) val (currentStepIdx, totalSteps) = if (isV2Active) { val idx = when (v2Aligner.phase) { - com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.INITIAL_ACCUM -> 0 - com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.VERTICAL_CLIMB -> 1 - com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.CH3_STABILIZE -> 2 - com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.CENTER_OPTIMIZE -> 3 - com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.LR_BALANCE -> 4 - com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.FINAL_CONFIRM -> 5 + com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.INITIAL_ACCUM -> 0 + com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.VERTICAL_CLIMB -> 1 + com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.CH3_STABILIZE -> 2 + com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.CENTER_OPTIMIZE -> 3 + com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.LR_BALANCE -> 4 + com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.FINAL_CONFIRM -> 5 } idx to 6 } else { @@ -634,13 +634,13 @@ fun PlacementGuideView(appState: AppState) { } if (appState.isDevMode && lastImuSamples.isNotEmpty()) { val posture = remember(lastImuSamples) { - com.example.medilightv2android.managers.ImuAnalysis.estimatePosture(lastImuSamples) + com.medithings.vesiscan.managers.ImuAnalysis.estimatePosture(lastImuSamples) } val shake = remember(lastImuSamples) { - com.example.medilightv2android.managers.ImuAnalysis.shakeRmsDps(lastImuSamples) + com.medithings.vesiscan.managers.ImuAnalysis.shakeRmsDps(lastImuSamples) } val tilt = remember(lastImuSamples) { - com.example.medilightv2android.managers.ImuAnalysis.tiltDegrees(lastImuSamples) + com.medithings.vesiscan.managers.ImuAnalysis.tiltDegrees(lastImuSamples) } Text( "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 wallPair = if (ch < lastWallResults.size) lastWallResults[ch] else null val showWalls = if (wallPair != null) { - com.example.medilightv2android.managers.LowEchoResult( + com.medithings.vesiscan.managers.LowEchoResult( ant = wallPair.first, post = wallPair.second, lowStart = wallPair.first, lowEnd = wallPair.second, lowMean = 0.0, urineLen = wallPair.second - wallPair.first, @@ -746,8 +746,8 @@ fun PlacementGuideView(appState: AppState) { if (chData != null && chData.buffer.isNotEmpty()) { // V2 활성 시 RollingAligner 의 10-cycle 평균 신호로 표시 → // 알고리즘 입력 신호와 그래프 일치 (실제 측정 시 보는 화면). - val isV2 = com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo == - com.example.medilightv2android.managers.AlignmentAlgo.V2 + val isV2 = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo == + com.medithings.vesiscan.managers.AlignmentAlgo.V2 val avgRaw = if (isV2) v2Aligner.lastAvg?.getOrNull(ch) else null PlacementWaveformChart( buffer = chData.buffer, @@ -806,26 +806,26 @@ fun PlacementGuideView(appState: AppState) { val MIN_URINE_LEN_PLACEMENT = 12 - val method = com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod - val analyzerA = com.example.medilightv2android.managers.PiezoEchoAnalyzerA.shared + val method = com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod + val analyzerA = com.medithings.vesiscan.managers.PiezoEchoAnalyzerA.shared for (ch in channels) { if (ch.buffer.isNotEmpty() && ch.channel < 6) { when (method) { - com.example.medilightv2android.managers.DetectionMethod.METHOD_C -> { - val v41 = com.example.medilightv2android.walldetect.V41Detector() + com.medithings.vesiscan.managers.DetectionMethod.METHOD_C -> { + val v41 = com.medithings.vesiscan.walldetect.V41Detector() val adcSingle = listOf(ch.buffer.map { it.toInt() }) - val probe = com.example.medilightv2android.walldetect.dto.ProbeProfileDto( - name = com.example.medilightv2android.managers.PiezoHW.presetName, + val probe = com.medithings.vesiscan.walldetect.dto.ProbeProfileDto( + name = com.medithings.vesiscan.managers.PiezoHW.presetName, rMm = 50.2, anteriorAnchorMm = 32.0, fsHz = 537500, cMmPerUs = 1.54, - anglesDeg = com.example.medilightv2android.managers.PiezoHW.degreeAll.toList() + anglesDeg = com.medithings.vesiscan.managers.PiezoHW.degreeAll.toList() ) // V4.1은 6ch 입력 필요 — 현재 채널만 해당 위치에, 나머지 빈 값 val adcMatrix = (0 until 6).map { i -> 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(), 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}") } - com.example.medilightv2android.managers.DetectionMethod.METHOD_A -> { + com.medithings.vesiscan.managers.DetectionMethod.METHOD_A -> { val analysis = analyzerA.analyzeChannel(ch.buffer, ch.channel) 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) { @@ -864,7 +864,7 @@ fun PlacementGuideView(appState: AppState) { } // postMaxIdx 필터: 후벽이 이 샘플 이상이면 바닥반사로 판단 → 제거 - val postMax = com.example.medilightv2android.managers.GreenZoneConstants.postMaxIdx + val postMax = com.medithings.vesiscan.managers.GreenZoneConstants.postMaxIdx for (ch in 0..5) { val w = allWalls[ch] 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)}") Log.w("PlacementGuide", "DETACHED mean=${ "%.1f".format(detachResult.meanAbs)} std=${"%.1f".format(detachResult.stdVal)}") - } else if (com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo == - com.example.medilightv2android.managers.AlignmentAlgo.V2) { + } else if (com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo == + com.medithings.vesiscan.managers.AlignmentAlgo.V2) { // ═══ V2 alignment (alignment.py 포팅, method_d 기반) ═══ // Clinical alignment session + waitingForStart 일 땐 알고리즘 skip — // baseline cycles 만 누적 (Start 누르기 전 자동 phase 진행 차단). @@ -941,20 +941,20 @@ fun PlacementGuideView(appState: AppState) { directionHint = localizedMsg // STOP 액션은 두 경우 — CH3_STABILIZE 의 "위치 유지" (still in progress) vs // LR_BALANCE 의 "정렬 완료" (truly done). 후자만 finalStop 으로 GREEN lock. - val finalStop = st.action == com.example.medilightv2android.managers.AlignAction.STOP && - v2Aligner.phase == com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.LR_BALANCE + val finalStop = st.action == com.medithings.vesiscan.managers.AlignAction.STOP && + v2Aligner.phase == com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.LR_BALANCE directionIcon = when (st.action) { - com.example.medilightv2android.managers.AlignAction.MOVE_UP -> "arrow.up" - com.example.medilightv2android.managers.AlignAction.MOVE_DOWN -> "arrow.down" - com.example.medilightv2android.managers.AlignAction.MOVE_LEFT -> "arrow.left" - com.example.medilightv2android.managers.AlignAction.MOVE_RIGHT -> "arrow.right" - com.example.medilightv2android.managers.AlignAction.PROBE_LR -> "" // ↔ — 한쪽 화살표 안 어울림. msg 의 ↔ 만 표시 - com.example.medilightv2android.managers.AlignAction.STOP -> if (finalStop) "checkmark.circle" else "" + com.medithings.vesiscan.managers.AlignAction.MOVE_UP -> "arrow.up" + com.medithings.vesiscan.managers.AlignAction.MOVE_DOWN -> "arrow.down" + com.medithings.vesiscan.managers.AlignAction.MOVE_LEFT -> "arrow.left" + com.medithings.vesiscan.managers.AlignAction.MOVE_RIGHT -> "arrow.right" + com.medithings.vesiscan.managers.AlignAction.PROBE_LR -> "" // ↔ — 한쪽 화살표 안 어울림. msg 의 ↔ 만 표시 + com.medithings.vesiscan.managers.AlignAction.STOP -> if (finalStop) "checkmark.circle" else "" null -> "" } placementScore = when { 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 } if (finalStop) { @@ -970,14 +970,14 @@ fun PlacementGuideView(appState: AppState) { } // end of !waitingForStart V2 algorithm } else { // Sphere-fit 계산 (SWEEP 모드에서 사용, 다른 모드에서는 무시됨) - val fitResult = com.example.medilightv2android.managers.BladderSphereSeek + val fitResult = com.medithings.vesiscan.managers.BladderSphereSeek .fitSagittalCircle(allWalls, detected) val rStatus = rTracker.submit(fitResult?.radiusMm) currentRMm = rStatus.currentR bestRMm = rStatus.bestR - sagittalArgMaxCh = com.example.medilightv2android.managers.BladderSphereSeek + sagittalArgMaxCh = com.medithings.vesiscan.managers.BladderSphereSeek .sagittalArgMaxCh(allWalls, detected) - val coronalResult = com.example.medilightv2android.managers.BladderSphereSeek + val coronalResult = com.medithings.vesiscan.managers.BladderSphereSeek .computeCoronalLateral(allWalls, detected) lateralOffsetMm = coronalResult?.lateralOffsetMm @@ -1112,11 +1112,11 @@ fun PlacementGuideView(appState: AppState) { // Phase 라벨 — V2 활성이면 V2 4-stage phase, 아니면 V1 placementPhase. // Step 0 (Start 전 baseline) 은 alignment session 에서만 명시. - val isV2 = com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo == - com.example.medilightv2android.managers.AlignmentAlgo.V2 - val clinSess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession + val isV2 = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo == + com.medithings.vesiscan.managers.AlignmentAlgo.V2 + val clinSess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession val isClinAlign = clinSess != null && - clinSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT + clinSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT val phaseLabel = when { isClinAlign && waitingForStart -> "STEP_0_BASELINE" isV2 -> v2Aligner.phase.name @@ -1136,10 +1136,10 @@ fun PlacementGuideView(appState: AppState) { // 임상 모드에서는 raw ADC도 adc.csv에 자동 저장. if (clinSess != null) { 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 누적. - if (clinSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT) { - com.example.medilightv2android.services.ClinicalSessionStore.addAlignmentFrame( + if (clinSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT) { + com.medithings.vesiscan.services.ClinicalSessionStore.addAlignmentFrame( piezo = channels, imu = lastImuSamples, // Step 0 baseline / V2 phase / V1 phase 통일된 라벨 사용 @@ -1159,8 +1159,8 @@ fun PlacementGuideView(appState: AppState) { bleManager.imuCollector.onComplete = { imuSamples -> handler.post { lastImuSamples = imuSamples - if (com.example.medilightv2android.services.ClinicalSessionStore.currentSession != null) { - com.example.medilightv2android.services.ImuCsvLogger.log(imuSamples) + if (com.medithings.vesiscan.services.ClinicalSessionStore.currentSession != null) { + com.medithings.vesiscan.services.ImuCsvLogger.log(imuSamples) } } } @@ -1241,16 +1241,16 @@ fun PlacementGuideView(appState: AppState) { } // 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 && - curClinSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT + curClinSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT if (!waitingForStart) Button( onClick = { isContinuousMode = false if (isClinicalAlign) { // endMeasurement → measurement.json finalize + labdb 자동 업로드 - com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context) - com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = true + com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context) + com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow = true appState.currentScreen = AppScreen.CLINICAL_HOME } else { appState.placementComplete() @@ -1300,21 +1300,21 @@ fun PlacementGuideView(appState: AppState) { ) { Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) { // 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) { Text("Detection", fontSize = 14.sp, fontWeight = FontWeight.SemiBold) Spacer(modifier = Modifier.weight(1f)) val methods = listOf( - com.example.medilightv2android.managers.DetectionMethod.METHOD_A to "A", - com.example.medilightv2android.managers.DetectionMethod.METHOD_B to "B", - com.example.medilightv2android.managers.DetectionMethod.METHOD_C to "C" + com.medithings.vesiscan.managers.DetectionMethod.METHOD_A to "A", + com.medithings.vesiscan.managers.DetectionMethod.METHOD_B to "B", + com.medithings.vesiscan.managers.DetectionMethod.METHOD_C to "C" ) val colors = listOf(Color(0xFF9C27B0), MlPrimary, Color(0xFFFF5722)) Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { methods.forEachIndexed { idx, (m, label) -> val sel = selectedMethod == m 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), shape = RoundedCornerShape(8.dp), colors = ButtonDefaults.buttonColors( @@ -1332,14 +1332,14 @@ fun PlacementGuideView(appState: AppState) { HorizontalDivider() // 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) { Text("Guide", fontSize = 14.sp, fontWeight = FontWeight.SemiBold) Spacer(modifier = Modifier.weight(1f)) val guideModes = listOf( - com.example.medilightv2android.managers.PlacementGuideMode.SIMPLE to "Gradient", - com.example.medilightv2android.managers.PlacementGuideMode.BOUNDARY to "Boundary", - com.example.medilightv2android.managers.PlacementGuideMode.SWEEP to "SWEEP" + com.medithings.vesiscan.managers.PlacementGuideMode.SIMPLE to "Gradient", + com.medithings.vesiscan.managers.PlacementGuideMode.BOUNDARY to "Boundary", + com.medithings.vesiscan.managers.PlacementGuideMode.SWEEP to "SWEEP" ) val guideColors = listOf(MlPrimary, Color(0xFFFF5722), Color(0xFF7C3AED)) Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { @@ -1348,7 +1348,7 @@ fun PlacementGuideView(appState: AppState) { Button( onClick = { selectedGuide = mode - com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode = mode + com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode = mode }, modifier = Modifier.height(32.dp), shape = RoundedCornerShape(8.dp), @@ -1368,14 +1368,14 @@ fun PlacementGuideView(appState: AppState) { // Alignment 알고리즘 V1/V2 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) { Text("Alignment", fontSize = 14.sp, fontWeight = FontWeight.SemiBold) Spacer(modifier = Modifier.weight(1f)) val algoModes = listOf( - com.example.medilightv2android.managers.AlignmentAlgo.V1 to "V1 (legacy)", - com.example.medilightv2android.managers.AlignmentAlgo.V2 to "V2 (new)", + com.medithings.vesiscan.managers.AlignmentAlgo.V1 to "V1 (legacy)", + com.medithings.vesiscan.managers.AlignmentAlgo.V2 to "V2 (new)", ) Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { algoModes.forEach { (algo, label) -> @@ -1383,8 +1383,8 @@ fun PlacementGuideView(appState: AppState) { Button( onClick = { selectedAlgo = algo - com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo = algo - if (algo == com.example.medilightv2android.managers.AlignmentAlgo.V2) { + com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo = algo + if (algo == com.medithings.vesiscan.managers.AlignmentAlgo.V2) { v2Aligner.reset() } }, @@ -1410,7 +1410,7 @@ fun PlacementGuideView(appState: AppState) { Text("Threshold", fontSize = 14.sp, fontWeight = FontWeight.SemiBold) Spacer(modifier = Modifier.width(8.dp)) 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, color = if (otsuEnabled) Color(0xFF4CAF50) else Color(0xFFFF9800) ) @@ -1426,7 +1426,7 @@ fun PlacementGuideView(appState: AppState) { HorizontalDivider() // 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) { Text("Post Max", fontSize = 14.sp, fontWeight = FontWeight.SemiBold) Spacer(modifier = Modifier.width(8.dp)) @@ -1434,7 +1434,7 @@ fun PlacementGuideView(appState: AppState) { } Slider( 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, steps = 8, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary) @@ -1651,10 +1651,10 @@ data class PlacementGuideResult( // CV threshold는 기기 preset에 따라 다름 private val DEFAULT_CV_THR: Double - get() = when (com.example.medilightv2android.managers.PiezoHW.activePreset) { - com.example.medilightv2android.managers.PiezoHW.DevicePreset.V0 -> 0.07 - com.example.medilightv2android.managers.PiezoHW.DevicePreset.V1, - com.example.medilightv2android.managers.PiezoHW.DevicePreset.V2 -> 0.10 + get() = when (com.medithings.vesiscan.managers.PiezoHW.activePreset) { + com.medithings.vesiscan.managers.PiezoHW.DevicePreset.V0 -> 0.07 + com.medithings.vesiscan.managers.PiezoHW.DevicePreset.V1, + com.medithings.vesiscan.managers.PiezoHW.DevicePreset.V2 -> 0.10 else -> 0.08 } private const val DEFAULT_LR_DEV_THR = 0.20 @@ -1727,10 +1727,10 @@ private fun computePlacementGuide( // ═══ 1단계: 상하 탐색 ═══ 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 ═══ - if (guideMode == com.example.medilightv2android.managers.PlacementGuideMode.SWEEP) { + if (guideMode == com.medithings.vesiscan.managers.PlacementGuideMode.SWEEP) { val vs = verticalState ?: VerticalState() val prev = vs.lastDetectedCount vs.lastDetectedCount = centerDetected @@ -2054,8 +2054,8 @@ private fun computePlacementGuide( } // R-peak gate (SWEEP 모드에서만 적용) - val isSweep = com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode == - com.example.medilightv2android.managers.PlacementGuideMode.SWEEP + val isSweep = com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode == + com.medithings.vesiscan.managers.PlacementGuideMode.SWEEP val rPeakOk = !isSweep || currentRMm == null || bestRMm <= 0.0 || (bestRMm - currentRMm) <= 1.5 val isPass = cv <= cvThr && lrPass && rPeakOk && edgePass @@ -2159,7 +2159,7 @@ private fun PlacementWaveformChart( val denoised = analyzer.denoise(raw) val maxVal = 2500f 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))) { val w = size.width diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/UrineCameraScreen.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/UrineCameraScreen.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/ui/views/monitoring/UrineCameraScreen.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/UrineCameraScreen.kt index bae1902..4486ee2 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/UrineCameraScreen.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/UrineCameraScreen.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ui.views.monitoring +package com.medithings.vesiscan.ui.views.monitoring import android.Manifest 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.viewinterop.AndroidView import androidx.core.content.ContextCompat -import com.example.medilightv2android.R -import com.example.medilightv2android.measure.SimpleMeasureService -import com.example.medilightv2android.measure.VoidingRecord -import com.example.medilightv2android.measure.VoidingRecordStore -import com.example.medilightv2android.measure.YoloDetector +import com.medithings.vesiscan.R +import com.medithings.vesiscan.measure.SimpleMeasureService +import com.medithings.vesiscan.measure.VoidingRecord +import com.medithings.vesiscan.measure.VoidingRecordStore +import com.medithings.vesiscan.measure.YoloDetector import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/VivamyoMonitoringView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/VivamyoMonitoringView.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/ui/views/monitoring/VivamyoMonitoringView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/VivamyoMonitoringView.kt index f3f2f02..41d4e9f 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/VivamyoMonitoringView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/VivamyoMonitoringView.kt @@ -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.Looper @@ -29,14 +29,14 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.AppState -import com.example.medilightv2android.R -import com.example.medilightv2android.ble.BleManager -import com.example.medilightv2android.managers.NirsManager -import com.example.medilightv2android.models.NirsMcjPacket -import com.example.medilightv2android.models.NirsOxyResult -import com.example.medilightv2android.ui.components.BladdyIdleRiveView -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.R +import com.medithings.vesiscan.ble.BleManager +import com.medithings.vesiscan.managers.NirsManager +import com.medithings.vesiscan.models.NirsMcjPacket +import com.medithings.vesiscan.models.NirsOxyResult +import com.medithings.vesiscan.ui.components.BladdyIdleRiveView +import com.medithings.vesiscan.ui.theme.* import kotlin.random.Random @Composable @@ -84,7 +84,7 @@ fun VivamyoMonitoringView(appState: AppState) { if (packet != null) { nirsManager.processMcjPacket(packet) } 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}") } } diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/VoidingDiaryView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/VoidingDiaryView.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/ui/views/monitoring/VoidingDiaryView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/VoidingDiaryView.kt index ab318f3..041a082 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/VoidingDiaryView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/VoidingDiaryView.kt @@ -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.layout.* @@ -20,12 +20,12 @@ import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.R -import com.example.medilightv2android.measure.VoidingRecord -import com.example.medilightv2android.measure.VoidingRecordStore -import com.example.medilightv2android.ui.theme.MlCardBackground -import com.example.medilightv2android.ui.theme.MlPrimary -import com.example.medilightv2android.ui.theme.MlSecondaryText +import com.medithings.vesiscan.R +import com.medithings.vesiscan.measure.VoidingRecord +import com.medithings.vesiscan.measure.VoidingRecordStore +import com.medithings.vesiscan.ui.theme.MlCardBackground +import com.medithings.vesiscan.ui.theme.MlPrimary +import com.medithings.vesiscan.ui.theme.MlSecondaryText import java.text.SimpleDateFormat import java.util.* diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/onboarding/OnboardingView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/onboarding/OnboardingView.kt similarity index 90% rename from app/src/main/java/com/example/medilightv2android/ui/views/onboarding/OnboardingView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/onboarding/OnboardingView.kt index e0bca0a..e5be65f 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/onboarding/OnboardingView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/onboarding/OnboardingView.kt @@ -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.layout.* @@ -16,10 +16,10 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.AppState -import com.example.medilightv2android.R -import com.example.medilightv2android.ui.components.BladdyIdleRiveView -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.R +import com.medithings.vesiscan.ui.components.BladdyIdleRiveView +import com.medithings.vesiscan.ui.theme.* @Composable fun OnboardingView(appState: AppState) { diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/personalization/PiezoPersonalizationView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/personalization/PiezoPersonalizationView.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/ui/views/personalization/PiezoPersonalizationView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/personalization/PiezoPersonalizationView.kt index a9a243d..2d980de 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/personalization/PiezoPersonalizationView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/personalization/PiezoPersonalizationView.kt @@ -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.Looper @@ -25,11 +25,11 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.AppState -import com.example.medilightv2android.R -import com.example.medilightv2android.ble.BleManager -import com.example.medilightv2android.ui.components.BladdyIdleRiveView -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.R +import com.medithings.vesiscan.ble.BleManager +import com.medithings.vesiscan.ui.components.BladdyIdleRiveView +import com.medithings.vesiscan.ui.theme.* import kotlin.math.roundToInt /** @@ -338,7 +338,7 @@ private fun WakeupAlarmCard() { val context = LocalContext.current var enabled by androidx.compose.runtime.remember { androidx.compose.runtime.mutableStateOf( - com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context) + com.medithings.vesiscan.services.WakeupAlarmPrefs.isEnabled(context) ) } Card( @@ -370,7 +370,7 @@ private fun WakeupAlarmCard() { checked = enabled, onCheckedChange = { enabled = it - com.example.medilightv2android.services.WakeupAlarmPrefs.setEnabled(context, it) + com.medithings.vesiscan.services.WakeupAlarmPrefs.setEnabled(context, it) }, colors = androidx.compose.material3.SwitchDefaults.colors( checkedTrackColor = Color(0xFFD32F2F) diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/pin/PinView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/pin/PinView.kt similarity index 93% rename from app/src/main/java/com/example/medilightv2android/ui/views/pin/PinView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/pin/PinView.kt index aafeb1f..6872ca8 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/pin/PinView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/pin/PinView.kt @@ -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.layout.* @@ -12,10 +12,10 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.AppState -import com.example.medilightv2android.services.UserStorage -import com.example.medilightv2android.ui.components.BladdyIdleRiveView -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.services.UserStorage +import com.medithings.vesiscan.ui.components.BladdyIdleRiveView +import com.medithings.vesiscan.ui.theme.* enum class PinMode { SETUP, ENTER } diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/pin/ShuffledKeypad.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/pin/ShuffledKeypad.kt similarity index 94% rename from app/src/main/java/com/example/medilightv2android/ui/views/pin/ShuffledKeypad.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/pin/ShuffledKeypad.kt index 3902299..0bf7552 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/pin/ShuffledKeypad.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/pin/ShuffledKeypad.kt @@ -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.clickable @@ -20,8 +20,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.R -import com.example.medilightv2android.ui.theme.MlCardBackground +import com.medithings.vesiscan.R +import com.medithings.vesiscan.ui.theme.MlCardBackground @Composable fun ShuffledKeypad( diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/registration/RegistrationView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/registration/RegistrationView.kt similarity index 95% rename from app/src/main/java/com/example/medilightv2android/ui/views/registration/RegistrationView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/registration/RegistrationView.kt index fb41334..84e0ae8 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/registration/RegistrationView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/registration/RegistrationView.kt @@ -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.border @@ -18,11 +18,11 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.AppState -import com.example.medilightv2android.R -import com.example.medilightv2android.models.Sex -import com.example.medilightv2android.ui.components.BladdyIdleRiveView -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.R +import com.medithings.vesiscan.models.Sex +import com.medithings.vesiscan.ui.components.BladdyIdleRiveView +import com.medithings.vesiscan.ui.theme.* @Composable fun RegistrationView(appState: AppState) { diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/reminder/ReminderSettingsView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/reminder/ReminderSettingsView.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/ui/views/reminder/ReminderSettingsView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/reminder/ReminderSettingsView.kt index 81ab45f..bd81d33 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/reminder/ReminderSettingsView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/reminder/ReminderSettingsView.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android.ui.views.reminder +package com.medithings.vesiscan.ui.views.reminder import android.content.Intent 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.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.R -import com.example.medilightv2android.services.ReminderService -import com.example.medilightv2android.ui.components.LockableSlider -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.R +import com.medithings.vesiscan.services.ReminderService +import com.medithings.vesiscan.ui.components.LockableSlider +import com.medithings.vesiscan.ui.theme.* @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/sensorselect/SensorSelectView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/sensorselect/SensorSelectView.kt similarity index 92% rename from app/src/main/java/com/example/medilightv2android/ui/views/sensorselect/SensorSelectView.kt rename to app/src/main/java/com/medithings/vesiscan/ui/views/sensorselect/SensorSelectView.kt index b935c29..c0d2597 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/sensorselect/SensorSelectView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/sensorselect/SensorSelectView.kt @@ -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.clickable @@ -22,11 +22,11 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.medilightv2android.AppState -import com.example.medilightv2android.R -import com.example.medilightv2android.models.SensorMode -import com.example.medilightv2android.ui.components.BladdyIdleRiveView -import com.example.medilightv2android.ui.theme.* +import com.medithings.vesiscan.AppState +import com.medithings.vesiscan.R +import com.medithings.vesiscan.models.SensorMode +import com.medithings.vesiscan.ui.components.BladdyIdleRiveView +import com.medithings.vesiscan.ui.theme.* @Composable fun SensorSelectView(appState: AppState) { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/DetectionSanity.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/DetectionSanity.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/walldetect/DetectionSanity.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/DetectionSanity.kt index 46a8600..94fc389 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/DetectionSanity.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/DetectionSanity.kt @@ -15,9 +15,9 @@ * own anatomical gate already drops genuinely-bad detections. This layer * 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 class DetectionSanity( diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/DetectorIds.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/DetectorIds.kt similarity index 84% rename from app/src/main/java/com/example/medilightv2android/walldetect/DetectorIds.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/DetectorIds.kt index 3d3bea2..ff1546e 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/DetectorIds.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/DetectorIds.kt @@ -4,7 +4,7 @@ * Project: CharlesKWONsLaw — wall-detect live compare * All rights reserved. */ -package com.example.medilightv2android.walldetect +package com.medithings.vesiscan.walldetect object DetectorIds { const val V2 = "v2" diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/MethodDDetector.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/MethodDDetector.kt similarity index 94% rename from app/src/main/java/com/example/medilightv2android/walldetect/MethodDDetector.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/MethodDDetector.kt index ded0ca1..6492cc3 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/MethodDDetector.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/MethodDDetector.kt @@ -13,14 +13,14 @@ * 인터페이스는 WallDetector 와 무관 — alignment.py 가 channels[i].urine_len 만 * 필요로 하므로 가벼운 단일-함수 API 로 유지. */ -package com.example.medilightv2android.walldetect +package com.medithings.vesiscan.walldetect -import com.example.medilightv2android.walldetect.algo.methodd.MethodDParams -import com.example.medilightv2android.walldetect.algo.methodd.MethodDPreprocessing -import com.example.medilightv2android.walldetect.algo.methodd.MethodDSpan -import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect -import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect.CType -import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect.Side +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDParams +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDPreprocessing +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDSpan +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect.CType +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect.Side import kotlin.math.max data class MethodDResult( diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/MethodDRunner.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/MethodDRunner.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/walldetect/MethodDRunner.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/MethodDRunner.kt index 2504af6..d4bda61 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/MethodDRunner.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/MethodDRunner.kt @@ -18,16 +18,16 @@ * 출력 컨트랙트: alignment.py 가 `dets[i].urine_len` 만 의존 → * MethodDResult.urineLen 또는 null 의 List 로 충분. */ -package com.example.medilightv2android.walldetect +package com.medithings.vesiscan.walldetect -import com.example.medilightv2android.managers.AlignmentConstants -import com.example.medilightv2android.managers.PiezoHW -import com.example.medilightv2android.walldetect.algo.methodd.MethodDParams -import com.example.medilightv2android.walldetect.algo.methodd.MethodDPreprocessing -import com.example.medilightv2android.walldetect.algo.methodd.MethodDTgc -import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect -import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect.CType -import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect.Side +import com.medithings.vesiscan.managers.AlignmentConstants +import com.medithings.vesiscan.managers.PiezoHW +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDParams +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDPreprocessing +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDTgc +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect.CType +import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect.Side import kotlin.math.abs import kotlin.math.cos import kotlin.math.min as kmin diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/SweepStabilizer.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/SweepStabilizer.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/walldetect/SweepStabilizer.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/SweepStabilizer.kt index 1696e4b..4c139a8 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/SweepStabilizer.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/SweepStabilizer.kt @@ -32,7 +32,7 @@ * The contract: "I either pass the live sample through unchanged, * or replace it with the temporal median of recent good values." */ -package com.example.medilightv2android.walldetect +package com.medithings.vesiscan.walldetect import kotlin.math.abs diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/V2Detector.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/V2Detector.kt similarity index 88% rename from app/src/main/java/com/example/medilightv2android/walldetect/V2Detector.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/V2Detector.kt index 4c26a74..09bd675 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/V2Detector.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/V2Detector.kt @@ -15,15 +15,15 @@ * 6. post > POST_MAX_IDX → back-half retry * 7. urine_len ≥ 3 required */ -package com.example.medilightv2android.walldetect +package com.medithings.vesiscan.walldetect -import com.example.medilightv2android.walldetect.algo.DetectLumenFirst -import com.example.medilightv2android.walldetect.algo.Geometry -import com.example.medilightv2android.walldetect.algo.SubsampleRefine -import com.example.medilightv2android.walldetect.dto.ChannelResult -import com.example.medilightv2android.walldetect.dto.DetectionResult -import com.example.medilightv2android.walldetect.dto.DetectionSummary -import com.example.medilightv2android.walldetect.dto.SweepInput +import com.medithings.vesiscan.walldetect.algo.DetectLumenFirst +import com.medithings.vesiscan.walldetect.algo.Geometry +import com.medithings.vesiscan.walldetect.algo.SubsampleRefine +import com.medithings.vesiscan.walldetect.dto.ChannelResult +import com.medithings.vesiscan.walldetect.dto.DetectionResult +import com.medithings.vesiscan.walldetect.dto.DetectionSummary +import com.medithings.vesiscan.walldetect.dto.SweepInput import kotlin.math.sqrt class V2Detector : WallDetector { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/V41Detector.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/V41Detector.kt similarity index 91% rename from app/src/main/java/com/example/medilightv2android/walldetect/V41Detector.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/V41Detector.kt index c80cb29..e0e5cb4 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/V41Detector.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/V41Detector.kt @@ -98,34 +98,34 @@ * `docs/BV-CALCULATION-DESIGN.md`. * ═════════════════════════════════════════════════════════════════════════ */ -package com.example.medilightv2android.walldetect +package com.medithings.vesiscan.walldetect -import com.example.medilightv2android.walldetect.algo.AnatomicalGate -import com.example.medilightv2android.walldetect.algo.BModeScore -import com.example.medilightv2android.walldetect.algo.BvEstimation -import com.example.medilightv2android.walldetect.algo.BvFromSphere -import com.example.medilightv2android.walldetect.algo.ChordConsensus -import com.example.medilightv2android.walldetect.algo.Clipping -import com.example.medilightv2android.walldetect.algo.ContrastAux -import com.example.medilightv2android.walldetect.algo.DetectLumenFirst -import com.example.medilightv2android.walldetect.algo.Geometry -import com.example.medilightv2android.walldetect.algo.ImpulseReject -import com.example.medilightv2android.walldetect.algo.PeakDetection -import com.example.medilightv2android.walldetect.algo.SphereFit2Step -import com.example.medilightv2android.walldetect.algo.SubsampleRefine -import com.example.medilightv2android.walldetect.algo.WaveletDenoise -import com.example.medilightv2android.walldetect.core.WdConfig -import com.example.medilightv2android.walldetect.dto.ChannelResult -import com.example.medilightv2android.walldetect.dto.DetectionResult -import com.example.medilightv2android.walldetect.dto.DetectionSummary -import com.example.medilightv2android.walldetect.dto.IntRange2 -import com.example.medilightv2android.walldetect.dto.ScoreSubscores -import com.example.medilightv2android.walldetect.dto.SweepInput -import com.example.medilightv2android.walldetect.dto.V41Diagnostics -import com.example.medilightv2android.walldetect.dto.V41SphereFit -import com.example.medilightv2android.walldetect.dto.Vec3 -import com.example.medilightv2android.walldetect.dto.WaveletCoefs -import com.example.medilightv2android.walldetect.dto.WaveletEnergyRatio +import com.medithings.vesiscan.walldetect.algo.AnatomicalGate +import com.medithings.vesiscan.walldetect.algo.BModeScore +import com.medithings.vesiscan.walldetect.algo.BvEstimation +import com.medithings.vesiscan.walldetect.algo.BvFromSphere +import com.medithings.vesiscan.walldetect.algo.ChordConsensus +import com.medithings.vesiscan.walldetect.algo.Clipping +import com.medithings.vesiscan.walldetect.algo.ContrastAux +import com.medithings.vesiscan.walldetect.algo.DetectLumenFirst +import com.medithings.vesiscan.walldetect.algo.Geometry +import com.medithings.vesiscan.walldetect.algo.ImpulseReject +import com.medithings.vesiscan.walldetect.algo.PeakDetection +import com.medithings.vesiscan.walldetect.algo.SphereFit2Step +import com.medithings.vesiscan.walldetect.algo.SubsampleRefine +import com.medithings.vesiscan.walldetect.algo.WaveletDenoise +import com.medithings.vesiscan.walldetect.core.WdConfig +import com.medithings.vesiscan.walldetect.dto.ChannelResult +import com.medithings.vesiscan.walldetect.dto.DetectionResult +import com.medithings.vesiscan.walldetect.dto.DetectionSummary +import com.medithings.vesiscan.walldetect.dto.IntRange2 +import com.medithings.vesiscan.walldetect.dto.ScoreSubscores +import com.medithings.vesiscan.walldetect.dto.SweepInput +import com.medithings.vesiscan.walldetect.dto.V41Diagnostics +import com.medithings.vesiscan.walldetect.dto.V41SphereFit +import com.medithings.vesiscan.walldetect.dto.Vec3 +import com.medithings.vesiscan.walldetect.dto.WaveletCoefs +import com.medithings.vesiscan.walldetect.dto.WaveletEnergyRatio import kotlin.math.sqrt class V41Detector( diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/WallDetector.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/WallDetector.kt similarity index 92% rename from app/src/main/java/com/example/medilightv2android/walldetect/WallDetector.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/WallDetector.kt index 0aa202f..d78663d 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/WallDetector.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/WallDetector.kt @@ -23,10 +23,10 @@ * • Thread-safe: a single instance can be called from multiple coroutines * • `gainDb`: V2 scales LOW_ECHO_AMP by 10^(-gainDb/20); V4.1 ignores it (Q4) */ -package com.example.medilightv2android.walldetect +package com.medithings.vesiscan.walldetect -import com.example.medilightv2android.walldetect.dto.DetectionResult -import com.example.medilightv2android.walldetect.dto.SweepInput +import com.medithings.vesiscan.walldetect.dto.DetectionResult +import com.medithings.vesiscan.walldetect.dto.SweepInput interface WallDetector { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/AnatomicalGate.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/AnatomicalGate.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/AnatomicalGate.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/AnatomicalGate.kt index 1f9c74c..ec0280a 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/AnatomicalGate.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/AnatomicalGate.kt @@ -17,10 +17,10 @@ * Beam-angle correction uses Snell-refracted angles (PROBE.DEGREE / DEGREE_LR), * NOT the mechanical CAD angles (MECH_DEGREE / MECH_DEGREE_LR). */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo -import com.example.medilightv2android.walldetect.core.WdConfig -import com.example.medilightv2android.walldetect.core.WdProbe +import com.medithings.vesiscan.walldetect.core.WdConfig +import com.medithings.vesiscan.walldetect.core.WdProbe import kotlin.math.cos object AnatomicalGate { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/BModeScore.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/BModeScore.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/BModeScore.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/BModeScore.kt index f894c1e..b6957c1 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/BModeScore.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/BModeScore.kt @@ -31,7 +31,7 @@ * ≥ 0.15 → low * else → zero */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo import kotlin.math.abs import kotlin.math.min diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/BvEstimation.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/BvEstimation.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/BvEstimation.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/BvEstimation.kt index cc4c995..1c06a0e 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/BvEstimation.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/BvEstimation.kt @@ -17,11 +17,11 @@ * • LR ratio: single-chord only when one lateral; mean of both ratios when * both laterals are present (simplified vs py2 3-chord offset-aware). */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo -import com.example.medilightv2android.walldetect.core.WdConfig -import com.example.medilightv2android.walldetect.core.WdProbe -import com.example.medilightv2android.walldetect.dto.BvDispatchResult +import com.medithings.vesiscan.walldetect.core.WdConfig +import com.medithings.vesiscan.walldetect.core.WdProbe +import com.medithings.vesiscan.walldetect.dto.BvDispatchResult import kotlin.math.PI import kotlin.math.abs import kotlin.math.cbrt @@ -112,7 +112,7 @@ object BvEstimation { val withConsensus = primary.copy( trustedChannels = consensus.trusted.sorted(), rejectedChannels = consensus.rejected.map { - com.example.medilightv2android.walldetect.dto.RejectedChannel( + com.medithings.vesiscan.walldetect.dto.RejectedChannel( it.ch, it.chord.toFloat(), it.reason, ) }, diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/BvFromSphere.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/BvFromSphere.kt similarity index 87% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/BvFromSphere.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/BvFromSphere.kt index f282eee..cf92da8 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/BvFromSphere.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/BvFromSphere.kt @@ -6,9 +6,9 @@ * Mirror of study/wall_detect_verify/js/algo/bv_from_sphere.js (1:1). * V4 canonical BV from sphere radius (mm) → mL. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo -import com.example.medilightv2android.walldetect.core.WdConfig +import com.medithings.vesiscan.walldetect.core.WdConfig object BvFromSphere { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/ChordConsensus.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/ChordConsensus.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/ChordConsensus.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/ChordConsensus.kt index b65f265..a758cfb 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/ChordConsensus.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/ChordConsensus.kt @@ -28,7 +28,7 @@ * CASE D (N≥3): Tukey isolated-outlier rejection — drop channels with * |chord_i − median| > k_mad · 1.4826 · MAD (default k_mad = 2.0). */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo import kotlin.math.PI import kotlin.math.abs diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/Clipping.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/Clipping.kt similarity index 94% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/Clipping.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/Clipping.kt index 9bc683a..fd4e533 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/Clipping.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/Clipping.kt @@ -7,9 +7,9 @@ * Dead-zone projection ψ_T(z)=max(z,T) + log envelope (dB). * Reference: Donoho (1995) soft-thresholding; py4/clipping.py. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo -import com.example.medilightv2android.walldetect.core.WdNumeric +import com.medithings.vesiscan.walldetect.core.WdNumeric import kotlin.math.log10 import kotlin.math.max diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/ContrastAux.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/ContrastAux.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/ContrastAux.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/ContrastAux.kt index fe9aa64..1a66339 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/ContrastAux.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/ContrastAux.kt @@ -16,9 +16,9 @@ * > 0 → low * else → zero */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo -import com.example.medilightv2android.walldetect.core.WdConfig +import com.medithings.vesiscan.walldetect.core.WdConfig import kotlin.math.max import kotlin.math.min diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/Denoising.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/Denoising.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/Denoising.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/Denoising.kt index 0cdcf28..72134f1 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/Denoising.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/Denoising.kt @@ -7,7 +7,7 @@ * Savitzky-Golay (5,2) FIR with polynomial edge interpolation. * Mirror of py4/denoising.sg_smooth (and py2/denoising.sg_smooth — 1:1 numerically). */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo object Denoising { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/DetectLumenFirst.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/DetectLumenFirst.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/DetectLumenFirst.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/DetectLumenFirst.kt index 9bc1425..841a728 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/DetectLumenFirst.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/DetectLumenFirst.kt @@ -11,9 +11,9 @@ * Mode.Adaptive → V4.1: lumen mask = sg ≤ median(OS-CFAR(sg)) [PR-4] * Mode.Scalar(value) → arbitrary scalar threshold (used by §3 7-method comparison) */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo -import com.example.medilightv2android.walldetect.core.WdNumeric +import com.medithings.vesiscan.walldetect.core.WdNumeric object DetectLumenFirst { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/Geometry.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/Geometry.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/Geometry.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/Geometry.kt index 6fed688..d5fa552 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/Geometry.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/Geometry.kt @@ -6,10 +6,10 @@ * Subset of study/wall_detect_verify/js/algo/geometry_v2_30deg.js (sampleToMm only). * Full geometry (wallIdxToXyz, 12 wall points) lands in PR-6 (sphere fit). */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo -import com.example.medilightv2android.walldetect.core.WdConfig -import com.example.medilightv2android.walldetect.core.WdProbe +import com.medithings.vesiscan.walldetect.core.WdConfig +import com.medithings.vesiscan.walldetect.core.WdProbe import kotlin.math.cos import kotlin.math.sin diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/ImpulseReject.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/ImpulseReject.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/ImpulseReject.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/ImpulseReject.kt index 9823b78..3e190a9 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/ImpulseReject.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/ImpulseReject.kt @@ -24,7 +24,7 @@ * pipeline: lumen-bump cleaning needs to know where the lumen is; without * Pass 1 wall localisation the Hampel filter has no anchor. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo import kotlin.math.abs diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/MedianFilter.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/MedianFilter.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/MedianFilter.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/MedianFilter.kt index 55cce9b..d1462bf 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/MedianFilter.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/MedianFilter.kt @@ -60,7 +60,7 @@ * Edge handling * Symmetric reflection (Gonzalez-Woods 2017 §3.4) at both ends. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo object MedianFilter { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/MorphClose.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/MorphClose.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/MorphClose.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/MorphClose.kt index 9b460c4..d316137 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/MorphClose.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/MorphClose.kt @@ -23,7 +23,7 @@ * kept available for future use (e.g. larger structuring elements with * length-aware decimation). */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo object MorphClose { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/MultiModeBv.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/MultiModeBv.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/MultiModeBv.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/MultiModeBv.kt index e37cf1c..b194d97 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/MultiModeBv.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/MultiModeBv.kt @@ -18,7 +18,7 @@ * Two trust criteria coexist — UI tier comes from BModeScore, mode selection * comes from ContrastAux. See DESIGN §1 footnote. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo object MultiModeBv { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/Otsu.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/Otsu.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/Otsu.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/Otsu.kt index 608b04a..f98580c 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/Otsu.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/Otsu.kt @@ -7,7 +7,7 @@ * 1-D Otsu binary threshold — k-means(k=2) equivalent on a histogram. * Used by detect_low_echo to derive an adaptive LOW_ECHO_AMP per signal. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo object Otsu { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/PeakDetection.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/PeakDetection.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/PeakDetection.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/PeakDetection.kt index a1bebb2..4f7fc76 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/PeakDetection.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/PeakDetection.kt @@ -6,7 +6,7 @@ * Mirror of study/wall_detect_verify/js/algo/peak_detection.js (1:1). * Strict local maxima + prominence + valley walks (py4/peak_detection style). */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo import kotlin.math.max import kotlin.math.min diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/PlateauDetector.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/PlateauDetector.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/PlateauDetector.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/PlateauDetector.kt index 91c788a..88988fa 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/PlateauDetector.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/PlateauDetector.kt @@ -16,7 +16,7 @@ * 7. final segment = (left_peak+1, right_peak-1) * 8. merge_overlapping + merge_adjacent_regions */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo import kotlin.math.abs import kotlin.math.max diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/Py2Helpers.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/Py2Helpers.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/Py2Helpers.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/Py2Helpers.kt index a55374c..3a14001 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/Py2Helpers.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/Py2Helpers.kt @@ -15,7 +15,7 @@ * NumPy median (even-length → mean of two middle values) is reproduced * faithfully, since robust_z drives the per-sample plateau score. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo import kotlin.math.abs import kotlin.math.ceil diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SgSmoothGeneric.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SgSmoothGeneric.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/SgSmoothGeneric.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/SgSmoothGeneric.kt index ee8f213..7a44cb7 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SgSmoothGeneric.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SgSmoothGeneric.kt @@ -13,7 +13,7 @@ * 수치 검증: * (7,3) 내부 커널 = [-2, 3, 6, 7, 6, 3, -2] / 21 (표준 SG 7-3 좌표) */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo import kotlin.math.abs diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SingleChannelBv.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SingleChannelBv.kt similarity index 95% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/SingleChannelBv.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/SingleChannelBv.kt index d9b6c5f..3b2596b 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SingleChannelBv.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SingleChannelBv.kt @@ -9,9 +9,9 @@ * Sphere assumption: chord ≡ 2R, so BV = (4/3)π(c/2)³. * §11 Mode B fallback for the small-bladder regime. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo -import com.example.medilightv2android.walldetect.core.WdConfig +import com.medithings.vesiscan.walldetect.core.WdConfig import kotlin.math.cbrt object SingleChannelBv { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SpanUtils.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SpanUtils.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/SpanUtils.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/SpanUtils.kt index 8be86db..18e8a59 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SpanUtils.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SpanUtils.kt @@ -6,7 +6,7 @@ * Mirror of study/wall_detect_verify/js/algo/span_utils.js (1:1). * Contiguous boolean spans + close-span merge with peak guard. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo object SpanUtils { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SphereFit2Step.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SphereFit2Step.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/SphereFit2Step.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/SphereFit2Step.kt index 50e3074..afcc3bd 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SphereFit2Step.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SphereFit2Step.kt @@ -15,7 +15,7 @@ * constZ → circle (drop z, xy plane) * else → sphere (3D) */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo import kotlin.math.abs import kotlin.math.sqrt diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SphereKasa.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SphereKasa.kt similarity index 95% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/SphereKasa.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/SphereKasa.kt index 99e818f..cef28b7 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SphereKasa.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SphereKasa.kt @@ -13,9 +13,9 @@ * Kasa I., "A circle fitting procedure and its error analysis", * IEEE Trans Instrum Meas IM-25(1):8–14, 1976. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo -import com.example.medilightv2android.walldetect.core.WdLinalg +import com.medithings.vesiscan.walldetect.core.WdLinalg import kotlin.math.max import kotlin.math.sqrt diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SphereLm.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SphereLm.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/SphereLm.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/SphereLm.kt index 99191b6..0b9b800 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SphereLm.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SphereLm.kt @@ -13,9 +13,9 @@ * Levenberg K. (1944) Quart. Appl. Math. 2:164–168. * Marquardt D. (1963) SIAM J. Appl. Math. 11:431–441. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo -import com.example.medilightv2android.walldetect.core.WdLinalg +import com.medithings.vesiscan.walldetect.core.WdLinalg import kotlin.math.sqrt object SphereLm { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/StaLta.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/StaLta.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/StaLta.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/StaLta.kt index 9641c2f..d470b77 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/StaLta.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/StaLta.kt @@ -30,7 +30,7 @@ * Defaults (Trnkoczy 2012 §8.1.2): Nsta=3, Nlta=30 — tuned for short- * duration impulse (1-3 samples) in stationary background noise. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo import kotlin.math.max import kotlin.math.min diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SubsampleRefine.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SubsampleRefine.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/SubsampleRefine.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/SubsampleRefine.kt index f809bed..82b35c4 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/SubsampleRefine.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/SubsampleRefine.kt @@ -12,7 +12,7 @@ * δ = ½ · (y[idx-1] − y[idx+1]) / (y[idx-1] − 2·y[idx] + y[idx+1]) * |δ| ≤ 0.5 when idx is a strict local extremum (else fall back to integer idx). */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo import kotlin.math.abs diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/ThresholdOsCfar.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/ThresholdOsCfar.kt similarity index 93% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/ThresholdOsCfar.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/ThresholdOsCfar.kt index fb7136a..ae45177 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/ThresholdOsCfar.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/ThresholdOsCfar.kt @@ -18,10 +18,10 @@ * OSCFAR_RANK = 0.4 (40th percentile in window-without-CUT) * OSCFAR_SCALE = 1.05 (5% safety margin above the rank percentile) */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo -import com.example.medilightv2android.walldetect.core.WdConfig -import com.example.medilightv2android.walldetect.core.WdNumeric +import com.medithings.vesiscan.walldetect.core.WdConfig +import com.medithings.vesiscan.walldetect.core.WdNumeric import kotlin.math.max import kotlin.math.min diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/WallSelect.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/WallSelect.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/WallSelect.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/WallSelect.kt index d1b512a..7a2b8e8 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/WallSelect.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/WallSelect.kt @@ -7,7 +7,7 @@ * V2 prominence-based wall selection with other_edge inner clamp. * Mirror of py2/low_echo_detection_method_b._select_wall_by_prominence. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo import kotlin.math.abs import kotlin.math.max diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/WaveletDenoise.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/WaveletDenoise.kt similarity index 99% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/WaveletDenoise.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/WaveletDenoise.kt index 890c16b..9a3c21f 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/WaveletDenoise.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/WaveletDenoise.kt @@ -21,7 +21,7 @@ * Convention: details[0] = level 1 (highest freq), details[L-1] = level L * (lowest detail / nearest to approx). approx is stored separately. */ -package com.example.medilightv2android.walldetect.algo +package com.medithings.vesiscan.walldetect.algo import kotlin.math.abs import kotlin.math.ceil diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDParams.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDParams.kt similarity index 96% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDParams.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDParams.kt index 7ef3a83..453b9cd 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDParams.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDParams.kt @@ -4,7 +4,7 @@ * 모든 디폴트값을 python 과 동일하게 유지. 튜닝 근거 주석은 원본 참조. * 각도 보정(otsu_ratio × cos(angle))은 호출부(MethodDRunner)에서 곱함. */ -package com.example.medilightv2android.walldetect.algo.methodd +package com.medithings.vesiscan.walldetect.algo.methodd data class MethodDParams( val otsuRatio: Double = 0.88, diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDPreprocessing.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDPreprocessing.kt similarity index 82% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDPreprocessing.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDPreprocessing.kt index bff3c8e..acff3e0 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDPreprocessing.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDPreprocessing.kt @@ -7,10 +7,10 @@ * Python config_6ch.SG_WIN=7, SG_POLY=3 — V4.1 의 (5,2) 하드코딩 커널과 분리. * 일반화된 SgSmoothGeneric 으로 호출 (any window, polyorder 지원). */ -package com.example.medilightv2android.walldetect.algo.methodd +package com.medithings.vesiscan.walldetect.algo.methodd -import com.example.medilightv2android.walldetect.algo.MedianFilter -import com.example.medilightv2android.walldetect.algo.SgSmoothGeneric +import com.medithings.vesiscan.walldetect.algo.MedianFilter +import com.medithings.vesiscan.walldetect.algo.SgSmoothGeneric object MethodDPreprocessing { const val SG_WIN = 7 // config_6ch.SG_WIN diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDSpan.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDSpan.kt similarity index 95% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDSpan.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDSpan.kt index b126bf7..a581d3e 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDSpan.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDSpan.kt @@ -14,10 +14,10 @@ * heavy primary; heavy 가 fail 하거나 끝까지 흐르면 light 로 재시도. * light 의 Otsu separability < min_light_separability 이면 fallback 거부. */ -package com.example.medilightv2android.walldetect.algo.methodd +package com.medithings.vesiscan.walldetect.algo.methodd -import com.example.medilightv2android.walldetect.algo.Otsu -import com.example.medilightv2android.walldetect.algo.SpanUtils +import com.medithings.vesiscan.walldetect.algo.Otsu +import com.medithings.vesiscan.walldetect.algo.SpanUtils object MethodDSpan { diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDTgc.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDTgc.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDTgc.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDTgc.kt index 1500510..9a1b3d8 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDTgc.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDTgc.kt @@ -15,7 +15,7 @@ * * 입력은 (n_ch, n_samples) 단일 scan. method_d 가 heavy/light 각각에 호출. */ -package com.example.medilightv2android.walldetect.algo.methodd +package com.medithings.vesiscan.walldetect.algo.methodd import kotlin.math.abs diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDWallSelect.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDWallSelect.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDWallSelect.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDWallSelect.kt index e506f1e..f1ccaf6 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/algo/methodd/MethodDWallSelect.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/algo/methodd/MethodDWallSelect.kt @@ -14,9 +14,9 @@ * shoulder 는 prom_gate(min_shoulder_prom) 더 strict, * score 에 (1+shoulder_score_handicap) deadband 페널티 → peak 와 동률 토글 차단. */ -package com.example.medilightv2android.walldetect.algo.methodd +package com.medithings.vesiscan.walldetect.algo.methodd -import com.example.medilightv2android.walldetect.algo.PeakDetection +import com.medithings.vesiscan.walldetect.algo.PeakDetection import kotlin.math.abs import kotlin.math.pow diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/core/Config.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/core/Config.kt similarity index 98% rename from app/src/main/java/com/example/medilightv2android/walldetect/core/Config.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/core/Config.kt index 3b246b7..3954ed4 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/core/Config.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/core/Config.kt @@ -6,7 +6,7 @@ * Mirror of study/wall_detect_verify/js/core/config.js (1:1). * 상수 변경 금지 — 정의가 바뀌면 V2/V4.1 골든 테스트가 깨집니다. */ -package com.example.medilightv2android.walldetect.core +package com.medithings.vesiscan.walldetect.core object WdConfig { const val SG_WIN = 5 diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/core/Linalg.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/core/Linalg.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/walldetect/core/Linalg.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/core/Linalg.kt index 636f88a..7e93e1c 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/core/Linalg.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/core/Linalg.kt @@ -7,7 +7,7 @@ * Small dense linear-algebra helpers (Gauss-Jordan solve with partial pivoting). * Used by sphere_kasa / sphere_lm. */ -package com.example.medilightv2android.walldetect.core +package com.medithings.vesiscan.walldetect.core import kotlin.math.abs import kotlin.math.sqrt diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/core/Numeric.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/core/Numeric.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/walldetect/core/Numeric.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/core/Numeric.kt index f202773..53a5ab4 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/core/Numeric.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/core/Numeric.kt @@ -8,7 +8,7 @@ * * 정밀도: 내부 계산은 Double로 수행 (JS는 모두 double). 호출자가 Float 으로 다운캐스트. */ -package com.example.medilightv2android.walldetect.core +package com.medithings.vesiscan.walldetect.core import kotlin.math.ceil import kotlin.math.floor diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/dto/BvDispatchResult.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/BvDispatchResult.kt similarity index 97% rename from app/src/main/java/com/example/medilightv2android/walldetect/dto/BvDispatchResult.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/dto/BvDispatchResult.kt index 23a0779..47a95b2 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/dto/BvDispatchResult.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/BvDispatchResult.kt @@ -7,7 +7,7 @@ * docs/BV-CALCULATION-DESIGN.md). Replaces the sphere-only `v41Sphere.bvMl` * for the primary "BV" metric while sphere fit stays for cross-check. */ -package com.example.medilightv2android.walldetect.dto +package com.medithings.vesiscan.walldetect.dto data class BvDispatchResult( diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/dto/ChannelResult.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/ChannelResult.kt similarity index 92% rename from app/src/main/java/com/example/medilightv2android/walldetect/dto/ChannelResult.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/dto/ChannelResult.kt index c9be15a..b174f9f 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/dto/ChannelResult.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/ChannelResult.kt @@ -6,7 +6,7 @@ * Per-channel detector result. Schema is identical for V2 and V4.1. * V2 결과는 v41Diag 가 항상 null. */ -package com.example.medilightv2android.walldetect.dto +package com.medithings.vesiscan.walldetect.dto data class ChannelResult( diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/dto/DetectionResult.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/DetectionResult.kt similarity index 91% rename from app/src/main/java/com/example/medilightv2android/walldetect/dto/DetectionResult.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/dto/DetectionResult.kt index 3e84b0e..7bacbd5 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/dto/DetectionResult.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/DetectionResult.kt @@ -6,7 +6,7 @@ * Top-level detector output. Identical schema for V2 and V4.1. * Only `algorithm` / `algorithmVersion` differ; all other field names match. */ -package com.example.medilightv2android.walldetect.dto +package com.medithings.vesiscan.walldetect.dto data class DetectionResult( diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/dto/DetectionSummary.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/DetectionSummary.kt similarity index 93% rename from app/src/main/java/com/example/medilightv2android/walldetect/dto/DetectionSummary.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/dto/DetectionSummary.kt index 2178931..0086922 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/dto/DetectionSummary.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/DetectionSummary.kt @@ -6,7 +6,7 @@ * Sweep-level summary. Schema identical for V2 and V4.1. * V4.1-only fields are null in V2 results. */ -package com.example.medilightv2android.walldetect.dto +package com.medithings.vesiscan.walldetect.dto data class DetectionSummary( diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/dto/SweepInput.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/SweepInput.kt similarity index 92% rename from app/src/main/java/com/example/medilightv2android/walldetect/dto/SweepInput.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/dto/SweepInput.kt index e9f1837..00e87c2 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/dto/SweepInput.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/SweepInput.kt @@ -6,7 +6,7 @@ * Common input DTO for both V2 and V4.1 detectors. * 두 detector 가 동일 입력을 받는다는 drift-zero 보장의 단일 source. */ -package com.example.medilightv2android.walldetect.dto +package com.medithings.vesiscan.walldetect.dto data class SweepInput( diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/dto/V41Diagnostics.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/V41Diagnostics.kt similarity index 95% rename from app/src/main/java/com/example/medilightv2android/walldetect/dto/V41Diagnostics.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/dto/V41Diagnostics.kt index 93a4718..c6d1826 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/dto/V41Diagnostics.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/V41Diagnostics.kt @@ -6,7 +6,7 @@ * V4.1-only per-channel diagnostics carrier. * V2 결과에서는 ChannelResult.v41Diag = null. 스키마 자체는 양쪽 동일. */ -package com.example.medilightv2android.walldetect.dto +package com.medithings.vesiscan.walldetect.dto data class V41Diagnostics( diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/dto/V41SphereFit.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/V41SphereFit.kt similarity index 91% rename from app/src/main/java/com/example/medilightv2android/walldetect/dto/V41SphereFit.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/dto/V41SphereFit.kt index c5345fd..06e1fa8 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/dto/V41SphereFit.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/V41SphereFit.kt @@ -6,7 +6,7 @@ * V4.1-only sweep-level sphere fit + BV result. * Q5: gated < 4 인 sweep 에서는 null (JS sphere_fit_2step.js 와 동일). */ -package com.example.medilightv2android.walldetect.dto +package com.medithings.vesiscan.walldetect.dto data class V41SphereFit( diff --git a/app/src/main/java/com/example/medilightv2android/walldetect/dto/Vec3.kt b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/Vec3.kt similarity index 83% rename from app/src/main/java/com/example/medilightv2android/walldetect/dto/Vec3.kt rename to app/src/main/java/com/medithings/vesiscan/walldetect/dto/Vec3.kt index eb7c48f..d99c31d 100644 --- a/app/src/main/java/com/example/medilightv2android/walldetect/dto/Vec3.kt +++ b/app/src/main/java/com/medithings/vesiscan/walldetect/dto/Vec3.kt @@ -3,7 +3,7 @@ * Author: Charles KWON OhJun * Project: CharlesKWONsLaw — wall-detect live compare */ -package com.example.medilightv2android.walldetect.dto +package com.medithings.vesiscan.walldetect.dto data class Vec3(val x: Float, val y: Float, val z: Float) diff --git a/app/src/test/java/com/example/medilightv2android/ExampleUnitTest.kt b/app/src/test/java/com/medithings/vesiscan/ExampleUnitTest.kt similarity index 88% rename from app/src/test/java/com/example/medilightv2android/ExampleUnitTest.kt rename to app/src/test/java/com/medithings/vesiscan/ExampleUnitTest.kt index 1a64b05..115b46a 100644 --- a/app/src/test/java/com/example/medilightv2android/ExampleUnitTest.kt +++ b/app/src/test/java/com/medithings/vesiscan/ExampleUnitTest.kt @@ -1,4 +1,4 @@ -package com.example.medilightv2android +package com.medithings.vesiscan import org.junit.Test diff --git a/app/src/test/java/com/example/medilightv2android/walldetect/V41DetectorCH4Test.kt b/app/src/test/java/com/medithings/vesiscan/walldetect/V41DetectorCH4Test.kt similarity index 97% rename from app/src/test/java/com/example/medilightv2android/walldetect/V41DetectorCH4Test.kt rename to app/src/test/java/com/medithings/vesiscan/walldetect/V41DetectorCH4Test.kt index ca8ebda..2e05f48 100644 --- a/app/src/test/java/com/example/medilightv2android/walldetect/V41DetectorCH4Test.kt +++ b/app/src/test/java/com/medithings/vesiscan/walldetect/V41DetectorCH4Test.kt @@ -1,7 +1,7 @@ -package com.example.medilightv2android.walldetect +package com.medithings.vesiscan.walldetect -import com.example.medilightv2android.walldetect.dto.ProbeProfileDto -import com.example.medilightv2android.walldetect.dto.SweepInput +import com.medithings.vesiscan.walldetect.dto.ProbeProfileDto +import com.medithings.vesiscan.walldetect.dto.SweepInput import org.junit.Test /** @@ -48,7 +48,7 @@ class V41DetectorCH4Test { println(" tier(sweep) : ${result.summary.tier} scoreMean=${result.summary.scoreMean}") println(" chordMmMean : ${result.summary.chordMmMean} std=${result.summary.chordMmStd}") println(" v41Sphere : ${result.summary.v41Sphere?.let { "R=${it.radiusMm}mm BV=${it.bvMl}mL n=${it.nPoints}" } ?: "—(gated<4)"}") - println(" bvDispatch : ${result.summary.bvDispatch?.let { "method=${it.methodChosen} bv=${it.bvMl}mL" } ?: "—"}") + println(" bvDispatch : ${result.summary.bvDispatch?.let { "method=${it.method} bv=${it.bvMl}mL" } ?: "—"}") println() println(" CH | ant post | gated | score tier | sContrast tier | antMm postMm chord") println(" ---+-----------+-------+--------------+---------------------+----------------------") diff --git a/docs/FLAVOR_DEMO_STABLE.md b/docs/FLAVOR_DEMO_STABLE.md index 9581fb9..2fb8929 100644 --- a/docs/FLAVOR_DEMO_STABLE.md +++ b/docs/FLAVOR_DEMO_STABLE.md @@ -9,7 +9,7 @@ | 항목 | demo | dev | |---|---|---| | 목적 | 시연/검증 — 결과 재현성 보장 | 개발 진행 — 모든 신규 기능/실험 | -| applicationId | `com.example.medilightv2android.demo` | `com.example.medilightv2android` | +| applicationId | `com.medithings.vesiscan.demo` | `com.medithings.vesiscan` | | 표시명 | VesiScan Demo | VesiScan Dev | | versionName suffix | `-demo` | (없음) | | BuildConfig.IS_DEMO | `true` | `false` | @@ -152,12 +152,12 @@ git add app/src/demo/ && git commit -m "Demo flavor: refresh freeze to v1.1" ```kotlin // 예: dev에만 Clinical 메뉴 노출 -if (com.example.medilightv2android.BuildConfig.IS_DEMO.not()) { +if (com.medithings.vesiscan.BuildConfig.IS_DEMO.not()) { Button(onClick = { goClinicalHome() }) { Text("Clinical R&D") } } // 예: demo에서는 항상 fixed parameter -val maxVolume = if (com.example.medilightv2android.BuildConfig.IS_DEMO) { +val maxVolume = if (com.medithings.vesiscan.BuildConfig.IS_DEMO) { 500 // 동결 기본값 } else { appState.piezoSettings.maxVolume // 사용자 조정 허용 diff --git a/illustnewpage!.png b/illustnewpage!.png new file mode 100644 index 0000000..936028b Binary files /dev/null and b/illustnewpage!.png differ diff --git a/ppt/alignment_mode_presentation_outline.md b/ppt/alignment_mode_presentation_outline.md new file mode 100644 index 0000000..1a4ff0b --- /dev/null +++ b/ppt/alignment_mode_presentation_outline.md @@ -0,0 +1,451 @@ +# Sensor Alignment Mode — 발표 자료 outline + +## 슬라이드 구조 (총 15-18장 권장) + +--- + +### 슬라이드 1: 제목 +**Sensor Alignment Mode** +방광 측정용 6채널 piezo 센서의 자동 정렬 가이드 + +- VesiScan-Basic 앱 +- 발표자: 장동우 +- 2026-06-30 + +--- + +### 슬라이드 2: Why Alignment Matters + +**문제: 센서 위치가 살짝만 어긋나도 BV 측정 정확도 급락** + +| 정렬 오차 | center wall 검출 | BV bias | 임상 결과 | +|---|---|---|---| +| 0 cm (정렬) | 100% | ±10% | 정확 | +| 2 cm 오프셋 | 40% | +50% (lateral fail → lr=1.0) | 과대 | +| 3 cm 오프셋 | 31% | +40% | 과대 | +| 4 cm 오프셋 | 13% | -120 mL | 측정 불가 | + +→ **임상 적용 = alignment 가 first-class problem** + +(실측 데이터: kai SUPINE 195 mL, 2 devices × 5 alignments × 31 cycles) + +--- + +### 슬라이드 3: Hardware Background + +**6채널 piezo 센서 배치 (정면 단면도)** + +``` + ┌─────────────────┐ + │ 센서 패드 (probe)│ + │ │ + │ CH0 ● (top, 20.1mm 위) + │ CH1 ● (12.8mm 위) + │ CH2 ● (7.0mm 위) + │ CH3 ● (basis, 0mm) + │ CH4● ●CH5 (lateral, ±10mm 좌우) + └─────────────────┘ +``` + +- **Center channels (CH0-3)**: SI (superior-inferior, 위-아래) 축 +- **Lateral channels (CH4-5)**: LR (left-right) 축 +- 각 channel = 펄스 송신 → 에코 수신 → ant/post wall index 검출 +- 100 samples / channel, ~1.98 mm/sample + +--- + +### 슬라이드 4: 정렬의 목표 + +**좋은 측정을 위한 sensor 위치 조건:** + +1. **CH3 (가장 아래) 가 방광 위에 있어야** (anatomical anchor) + - CH3 미검출 → 센서가 치골 아래 (방광 못 봄) + - CH3 검출 → 방광 lower pole 위치 확인됨 + +2. **모든 center channel (CH0-3) 이 방광 단면 위에 있어야** + - 일부만 검출 → 방광 edge 에 걸침 → BV 계산 부정확 + +3. **Lateral (CH4, CH5) 이 좌우 균형:** + - |u4 - u5| ≤ 8 samples (~16mm) 면 균형 + - 차이 크면 한쪽으로 치우침 + +이 3 조건을 **실시간 자동 가이드** 로 충족시키는 게 alignment mode 의 역할. + +--- + +### 슬라이드 5: V1 vs V2 비교 + +| | V1 (legacy) | V2 (Method D) | +|---|---|---| +| **알고리즘** | computePlacementGuide (단발) | RollingAligner + AlignGuide4Stage | +| **데이터 누적** | 1 cycle 즉시 판단 | N-cycle sliding window 평균 | +| **Phase** | 없음 (score 0~100 단일) | 5-phase state machine | +| **노이즈 robust** | 약함 (cycle 마다 score flap) | 강함 (10-cycle 평균 후 결정) | +| **임상 적용** | 일반 사용자 home use | clinical R&D / 정밀 측정 | + +**현재 default:** 일반 사용자 = V1, 임상 clinical session = V2 + +발표 focus = **V2 (Method D)** + +--- + +### 슬라이드 6: V2 전체 흐름 + +``` +[BLE 연결] → [Personalization] → [Placement V2 진입] → [4-Phase 진행] → [측정] + ↓ + 매 cycle mtb 송신 (~1Hz) + ↓ + 6채널 raw + IMU 응답 + ↓ + RollingAligner (sliding window) + ↓ + MethodDRunner.detectMultichannel + ↓ + AlignGuide4Stage (state machine) + ↓ + AdvisorState (action, hint, msg) + ↓ + UI 화살표 + 텍스트 표시 +``` + +--- + +### 슬라이드 7: RollingAligner — 데이터 누적 + +**왜 평균을 내는가?** + +Single cycle 데이터의 noise: +- per-cycle wall index 변동: ±5 samples (~10mm) +- per-cycle BV 변동: ±50 mL +- → 매 cycle 판단하면 화살표 마구 흔들림 + +**Sliding window 평균:** +- Window size = N cycles (phase 별 조정) +- Buffer 6채널 × 100 sample 그대로 평균 → "avg" signal +- avg → MethodDRunner 통과 → 안정적 wall 위치 + +```kotlin +fun push(raw6) { + buf.addLast(raw6) + while (buf.size > windowSize) buf.removeFirst() + val avg = average(buf) // 6 × 100 평균 + val dets = MethodDRunner.detectMultichannel(avg) + ... +} +``` + +**Window size:** +- INITIAL_ACCUM / VERTICAL / CH3_STABILIZE: **10** +- LR_BALANCE: **5** (반응성 우선) +- FINAL_CONFIRM: **5** (재확인) + +--- + +### 슬라이드 8: Method D — Wall Detection Algorithm + +**Per-channel pipeline:** + +``` +raw signal (100 samples) + ↓ +1. Heavy SG denoise (강한 smoothing — wall 위치용) +2. Light SG denoise (약한 smoothing — peak 보존) + ↓ +3. TGC pipeline (Time Gain Compensation) + - depth attenuation 보정 + - adaptive ratio_min = 0.1 + ↓ +4. OS-CFAR detector (ordered statistic — constant false alarm) + - cos(beam_angle) 로 otsu_ratio per channel 보정 + - urine span detection (low-echo 구간 찾기) + - shoulder prominence γ = 1.5 + ↓ +5. Cross-channel ant tie-break (in-place) + - 이웃 채널의 ant 후보들 비교 + - top1/top2 ratio < 1.3 OR z-position |Δ| < 8mm + - → 같은 depth 의 ant 우선 선택 (해부학 일관성) + ↓ +MethodDResult { ant, post, urineLen, score } +``` + +**Python `for_app_share` reference 와 1:1 정렬** (2026-06-30 commit b733d4f). + +--- + +### 슬라이드 9: AlignGuide4Stage — 4-Phase 상태 기계 + +``` +┌────────────────────────────────────────────────────────────┐ +│ │ +│ ① INITIAL_ACCUM (10 cycles) │ +│ "잠시 그대로 두세요 (n/10)" │ +│ 데이터 누적만, 아직 판단 X │ +│ ↓ │ +│ ② VERTICAL_CLIMB │ +│ CH3 미검출 → "↑ 위로 조금씩 올리세요" │ +│ CH3 3 연속 검출 → 다음 │ +│ ↓ │ +│ ③ CH3_STABILIZE (10 cycles) │ +│ CH3 안정 유지 확인 │ +│ CH3 잃음 → ②로 복귀 │ +│ bestCenterSet 저장 │ +│ ↓ │ +│ ④ LR_BALANCE │ +│ lost channel → ↑/↓ 회복 (3 연속 lost 필요) │ +│ |u4-u5| ≤ 8 → 균형, ⑤ 진입 │ +│ |u4-u5| > 8 → ← or → 작은쪽으로 │ +│ ↓ │ +│ ⑤ FINAL_CONFIRM (5 cycles) │ +│ buf clear → fresh 5 cycle 누적 │ +│ |u4-u5| ≤ 8 유지 → "✓ 정렬 완료!" │ +│ 실패 → ④로 │ +│ │ +└────────────────────────────────────────────────────────────┘ +``` + +--- + +### 슬라이드 10: Phase 1 — INITIAL_ACCUM + +**역할:** RollingAligner buffer 를 10 cycles 채우기. + +**왜 필요한가?** +- buffer 1개 frame 만 있으면 평균 = single cycle (noise 그대로) +- 10 frame 평균 → σ가 √10 ≈ 3배 감소 + +**UI:** +- 화살표 없음 +- "잠시 그대로 두세요 (5/10)" 진행률 표시 +- 사용자는 그냥 가만히 들고 있기 + +**기간:** ~10초 (1Hz × 10 cycles) + +--- + +### 슬라이드 11: Phase 2 — VERTICAL_CLIMB + +**역할:** CH3 (가장 아래 채널) 가 방광 위에 오도록 유도. + +**Logic:** +```kotlin +if (!s.ch3) { + verticalHitStreak = 0 // false detection 거부 + return MOVE_UP // "↑ 위로 조금씩" +} +verticalHitStreak++ +if (verticalHitStreak < 3) { + return STOP // "✓ 확인 중 (n/3)" +} +phase = CH3_STABILIZE +``` + +**핵심:** +- CH3 3 회 연속 검출되어야 다음 phase +- 1회만 검출 (false echo 가능성) → 일시 멈춤 + 확인 중 + +**UI:** +- 화살표: ↑ +- 메시지: "위로 조금씩 올리세요" / "확인 중 (n/3)" + +--- + +### 슬라이드 12: Phase 3 — CH3_STABILIZE + +**역할:** CH3 가 안정적으로 잡힌 위치인지 10 cycles 확인. + +**Logic:** +```kotlin +if (!s.ch3) { + phase = VERTICAL_CLIMB // 잃음 → 처음으로 + return +} +stabilizeCount++ +if (stabilizeCount >= 10) { + bestCenterSet = curSet // 현재 잡힌 채널 set 저장 + phase = LR_BALANCE +} +``` + +**핵심:** +- bestCenterSet 저장: 이 시점 잡힌 center channel (예: {1, 2, 3} 또는 {0, 1, 2, 3}) +- 이후 LR_BALANCE 에서 이 set 유지 여부 확인 + +**UI:** +- 화살표: ✓ (멈춰 있어요) +- 메시지: "좋아요! 그 위치 유지 (n/10)" + +--- + +### 슬라이드 13: Phase 4 — LR_BALANCE (좌우 균형) + +**역할:** lateral channel (CH4, CH5) 의 신호 차이로 좌우 균형 잡기. + +**Logic 1 — 채널 lost 감지:** +```kotlin +val lost = bestCenterSet - curSet +if (lost.isNotEmpty()) { + lostStreak++ + if (lostStreak >= 3) { // hysteresis (6/30 추가) + if (3 in lost) return MOVE_UP // CH3 잃음 → 위 + else return MOVE_DOWN // 다른 채널 잃음 → 아래 + } + return STOP // noise, 무시 +} else { + lostStreak = 0 +} +``` + +**Logic 2 — 좌우 균형:** +```kotlin +val imbal = abs(u4 - u5) +if (imbal <= 8) { // LAT_TOL (~16mm) + phase = FINAL_CONFIRM + return STOP "✓ 균형 도달" +} +if (u4 < u5) return MOVE_RIGHT // CH4 신호 짧음 → 우측이 멀음 +else return MOVE_LEFT // CH5 신호 짧음 → 좌측이 멀음 +``` + +**Deadband:** 방향 반전 시 imbal 이 이전 + 3 이상 증가 + 2 연속 → 반전 (oscillation 차단) + +--- + +### 슬라이드 14: Phase 5 — FINAL_CONFIRM + +**역할:** 마지막 5 cycles 로 정렬 안정성 재확인. + +**Logic:** +```kotlin +buf.clear() // RollingAligner buffer 초기화 (fresh window) +finalConfirmCount = 0 + +// 5 cycles 동안 imbal ≤ 8 유지하면 STOP +while (finalConfirmCount < 5) { + if (imbal > 8 || ch3 lost) { + phase = LR_BALANCE // 실패 → 복귀 + return + } + finalConfirmCount++ + return STOP "✓ 최종 확인 중 (n/5)" +} +return STOP "✓ 정렬 완료 — 측정 가능" +``` + +**핵심:** +- buf clear → 이전 cycles 영향 제거 +- 5 fresh cycles 로 안정성 재검증 +- 실패 시 LR_BALANCE 로 즉시 복귀 + +--- + +### 슬라이드 15: 최근 개선 (2026-06-30) + +**1. lost streak hysteresis (50b8620, b2546d1)** + +문제: 실측 데이터 (244 cycle 정렬 세션) 분석: +- LR_BALANCE 에서 |u4-u5| 항상 8 이하 (좌우 균형 OK) +- 하지만 CH1, CH3 가 cycle 마다 15%, 12% 노이즈 깜빡임 +- 매 cycle `lost` 감지 → 화살표 띄움 → 다음 cycle 복구 → STOP 반복 +- **사용자 체감: "어디로 옮길지 모르겠음"** + +해결: 같은 채널이 3 연속 commit 에서 lost 여야 회복 모드. +- 화살표 flap rate 55% → ~5% 예상 + +--- + +**2. 그래프 ↔ 알고리즘 일치 (9e52019, 886d403)** + +문제: +- 그래프: real-time single cycle raw ADC +- 알고리즘 입력: 10-cycle averaged signal +- 사용자가 그래프 보면서 "wall 보이는데 알고리즘 미검출" 또는 반대 + +해결: V2 활성 시 그래프도 RollingAligner.lastAvg 사용. +- `PlacementWaveformChart(overrideRaw = avgRaw)` +- 알고리즘 입력 == 시각화 신호 == 사용자 판단 + +--- + +### 슬라이드 16: 실측 검증 — kai 195 mL ALIGNMENT 세션 + +**11 sessions: 2 devices × 5 alignments × ~31 cycles** + +| Step | center detect % | BV bias | +|---|---|---| +| 0 cm | 70% | -36 mL | +| 1 cm | 62% | -28 | +| 2 cm | 40% | +55 (lr=1.0 fallback) | +| 3 cm | 31% | +42 | +| 4 cm | 13% | -120 (fail) | + +**Key finding:** +- Method D 자체는 정상 동작 (0 cm: center 70%, 1 cm: 62%) +- 2 cm 부터는 detection 불완전 → BV 부정확 +- **alignment 가 충실히 0-1 cm 수렴해야 임상 정확도 보장** + +→ V2 의 4-phase 가 0-1 cm 자동 수렴하는지가 핵심 검증 포인트 + +--- + +### 슬라이드 17: 알고리즘 파라미터 (Tunable) + +`AlignmentConstants.kt`: +- `LAT_TOL = 8` samples (~16mm) — 좌우 균형 허용 오차 +- `ANT_TIEBREAK_RATIO = 1.3` — cross-channel ant tiebreak +- `ANT_NEARFIELD_TOL_MM = 8.0` + +`AlignGuide4Stage.kt`: +- `accumKVertical = 10` cycles +- `accumKLateral = 5` cycles +- `accumKConfirm = 5` cycles +- `verticalHitRequired = 3` +- `lrReverseDeadband = 3` samples +- `lrReverseConsecutive = 2` +- `lostStreakRequired = 3` ← **신규 (6/30)** +- `finalConfirmTarget = 5` + +`MethodDParams.kt`: +- `oscfarWin = 9` (이전 5) +- `shoulderPromGamma = 1.5` (이전 1.0) +- `otsuRatio` per channel = base × cos(angle) + +dev mode 에서 슬라이더로 실시간 튜닝 가능. + +--- + +### 슬라이드 18: 결론 + 향후 과제 + +**현재 상태:** +- V2 (Method D) 4-phase 알고리즘 안정 동작 +- 실측 데이터로 검증 완료 (kai 11 sessions) +- 최근 lost streak / 그래프 일치 개선 +- Python reference 와 1:1 정렬 + +**향후 검증/개선:** +1. **임상 N=20+ 환자** 데이터로 alignment 수렴률 / 시간 측정 +2. **3 cm 이상에서도 측정 거부** logic 강화 (현재는 측정 진행됨) +3. **자동 measurement 트리거** — 정렬 완료 시 사용자 액션 없이 측정 시작 +4. **alignment 실패 mode** 처리 — 30초 내 수렴 못 하면 가이드 다이얼로그 +5. **POSTURE-aware** — supine 외 자세에서 alignment 동작 검증 + +--- + +## 추가 자료 (appendix) + +### A. 코드 위치 +- `app/.../managers/AlignmentAdvisorV2.kt` — main state machine +- `app/.../walldetect/MethodDRunner.kt` — wall detection +- `app/.../walldetect/algo/methodd/` — Method D internals +- `app/.../ui/views/monitoring/PlacementGuideView.kt` — UI 통합 + +### B. 검증 툴 +- `tools/analyze_csv.py` — App CSV → Python pipeline 비교 +- ablation mode: DPS / lr_floor 등 각 fix 영향 + +### C. 관련 commits +- `02bed02` (appshare) — Method D 02bed02 원본 +- `64c15a8` (demo) — Method D 02bed02 Kotlin 포팅 +- `b733d4f` (feature) — BV Python 1:1 정렬 +- `50b8620` (feature) — lost streak hysteresis +- `9e52019` — 그래프 10-cycle 평균 표시 diff --git a/ppt/새 폴더/20260612_093849.jpg b/ppt/새 폴더/20260612_093849.jpg new file mode 100644 index 0000000..74255c4 Binary files /dev/null and b/ppt/새 폴더/20260612_093849.jpg differ diff --git a/ppt/새 폴더/_design_dump.txt b/ppt/새 폴더/_design_dump.txt new file mode 100644 index 0000000..8f15f7a --- /dev/null +++ b/ppt/새 폴더/_design_dump.txt @@ -0,0 +1,738 @@ +FILE: 주간보고서_dwjang_20260604.pptx +SLIDE SIZE: W=14630400 H=8229600 EMU | W=16.00in H=9.00in +SLIDE COUNT: 7 + +LAYOUTS: + [0] 0. 제목 슬라이드 + [1] 0. 제목 반전 슬라이드 + [2] 1. 빈 화면 + [3] 1. 빈 반전 화면 + [4] 2. 목차 슬라이드 + [5] 2. 목차 반전 슬라이드 + +====================================================================== +SLIDE 1 + layout: 0. 제목 반전 슬라이드 + background: type=BACKGROUND (5) + shape_count: 2 + - shape name='TextBox 1' type=TEXT_BOX (17) autoshape= + geom: L=6620256 T=3749039 W=2785378 H=584775 EMU | L=7.24in T=4.10in W=3.05in H=0.64in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=False mL=0 mR=91440 mT=45720 mB=45720 + text(60)='주간 진행 보고' + p0 lvl=0 align=None - text='주간 진행 보고' + r0 font='나눔고딕 ExtraBold' sz=32.0 b=True i=None c=inherit t='주간 ' + r1 font='나눔고딕 ExtraBold' sz=32.0 b=True i=None c=inherit t='진행' + r2 font='나눔고딕 ExtraBold' sz=32.0 b=True i=None c=inherit t=' ' + r3 font='나눔고딕 ExtraBold' sz=32.0 b=True i=None c=inherit t='보고' + - shape name='TextBox 2' type=TEXT_BOX (17) autoshape= + geom: L=6620256 T=4572000 W=3346429 H=369332 EMU | L=7.24in T=5.00in W=3.66in H=0.40in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=False mL=0 mR=91440 mT=45720 mB=45720 + text(60)='2026-06-01 (월) ~ 06-05 (금)' + p0 lvl=0 align=None - text='2026-06-01 (월) ~ 06-05 (금)' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#55606C t='2026-06-01 (월) ~ 06-0' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#55606C t='5' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#55606C t=' (' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#55606C t='금' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#55606C t=')' + +====================================================================== +SLIDE 2 + layout: 1. 빈 화면 + background: type=BACKGROUND (5) + shape_count: 4 + - shape name='TextBox 1' type=TEXT_BOX (17) autoshape= + geom: L=402336 T=173736 W=6236208 H=457200 EMU | L=0.44in T=0.19in W=6.82in H=0.50in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=False mL=0 mR=91440 mT=0 mB=45720 + text(60)='Android App 진행 보고' + p0 lvl=0 align=None - text='Android App 진행 보고' + r0 font='나눔고딕 ExtraBold' sz=24.0 b=True i=None c=inherit t='Android App 진행 보고' + - shape name='TextBox 3' type=TEXT_BOX (17) autoshape= + geom: L=603504 T=868680 W=13240512 H=3842077 EMU | L=0.66in T=0.95in W=14.48in H=4.20in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=True mL=0 mR=91440 mT=45720 mB=45720 + text(60)='테스트 페이지 + labdb 업로드 + BLE/IMU 파싱 준비 | • 모바일 앱 테스트용 페이지 구현 |' + p0 lvl=0 align=None - text='테스트 페이지 + labdb 업로드 + BLE/IMU 파싱 준비' + r0 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='테스트' + r1 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' ' + r2 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='페이지' + r3 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' + ' + r4 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='labdb' + r5 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' ' + r6 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='업로드' + r7 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' + BLE/IMU ' + r8 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='파싱' + r9 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' ' + r10 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='준비' + p1 lvl=0 align=None - text='• 모바일 앱 테스트용 페이지 구현' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='모바일' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' 앱 ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='테스트용' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='페이지' + r6 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r7 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='구현' + p2 lvl=1 align=None - text='– Clinical Measurement 모드 — 라벨 입력 + 6채널 라이브 시각화' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– Clinical Measurement ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='모드' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' — ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='라벨' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='입력' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' + 6채널 ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='라이브' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='시각화' + p3 lvl=1 align=None - text='– 폴더 단위 저장 (Downloads/VesiScan_Sessions/)' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='폴더' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='단위' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='저장' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' (Downloads/' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='VesiScan_Sessions' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='/)' + p4 lvl=0 align=None - text='• labdb 업로드 기능 (Phase A+B)' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='labdb' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='업로드' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='기능' + r6 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' (Phase A+B)' + p5 lvl=1 align=None - text='– EncryptedSharedPreferences로 apiKey 안전 보관' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='EncryptedSharedPreferences로' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='apiKey' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='안전' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='보관' + p6 lvl=1 align=None - text='– register → admin 승인 → /upload/json' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– register → admin ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='승인' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' → /upload/' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='json' + p7 lvl=1 align=None - text='– End Session 시 자동 업로드 + 폴더 내 .uploaded 마커 + 수동 재시도 버튼' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– End Session 시 ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='자동' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='업로드' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' + ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='폴더' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' 내 .uploaded ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='마커' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' + ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='수동' + r10 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r11 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='재시도' + r12 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r13 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='버튼' + p8 lvl=0 align=None - text='• BLE 명령어 수정 및 IMU 파싱 추가' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• BLE ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='명령어' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='수정' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' 및 IMU ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='파싱' + r6 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r7 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='추가' + p9 lvl=1 align=None - text='– rim: 응답 188B (15 samples × 12B) BE int16 파싱' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– rim: ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='응답' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' 188B (15 samples × 12B) BE int16 ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='파싱' + p10 lvl=1 align=None - text='– ImuPacketCollector — Accel ±4g (1/8192 LSB), Gyro ±500dps' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='ImuPacketCollector' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' — Accel ±4g (1/8192 LSB), Gyro ±500dps ' + - shape name='AutoShape 2' type=AUTO_SHAPE (1) autoshape= + geom: L=7162800 T=3962400 W=304800 H=304800 EMU | L=7.83in T=4.33in W=0.33in H=0.33in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=TOP (1) wrap=True mL=91440 mR=91440 mT=45720 mB=45720 + text(60)='' + p0 lvl=0 align=None - text='' + - shape name='그림 6' type=PICTURE (13) autoshape= + geom: L=9247388 T=297454 W=3157605 H=6841479 EMU | L=10.11in T=0.33in W=3.45in H=7.48in + line: color=inherit width_pt=None + +====================================================================== +SLIDE 3 + layout: 1. 빈 화면 + background: type=BACKGROUND (5) + shape_count: 5 + - shape name='TextBox 1' type=TEXT_BOX (17) autoshape= + geom: L=402336 T=173736 W=6236208 H=457200 EMU | L=0.44in T=0.19in W=6.82in H=0.50in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=False mL=0 mR=91440 mT=0 mB=45720 + text(60)='Android App 진행 보고' + p0 lvl=0 align=None - text='Android App 진행 보고' + r0 font='나눔고딕 ExtraBold' sz=24.0 b=True i=None c=inherit t='Android App 진행 보고' + - shape name='TextBox 3' type=TEXT_BOX (17) autoshape= + geom: L=603504 T=868680 W=13240512 H=4306307 EMU | L=0.66in T=0.95in W=14.48in H=4.71in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=True mL=0 mR=91440 mT=45720 mB=45720 + text(60)='labdb 통합 정리 | • dataType "001" JSON 저장 및 표시 | – 내부 임상 R&D ' + p0 lvl=0 align=None - text='labdb 통합 정리' + r0 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='labdb' + r1 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' ' + r2 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='통합' + r3 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' ' + r4 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='정리' + p1 lvl=0 align=None - text='• dataType "001" JSON 저장 및 표시' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='dataType' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' "001" JSON ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='저장' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' 및 ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='표시' + p2 lvl=1 align=None - text='– 내부 임상 R&D 구분용 — 외부 일반 VesiScan "000"과 분리' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='내부' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='임상' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' R&D ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='구분용' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' — ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='외부' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='일반' + r10 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r11 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='VesiScan' + r12 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' "000"과 ' + r13 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='분리' + p3 lvl=1 align=None - text='– meta.json / measurement.json 양쪽에 data_type 필드 노출' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='meta.json' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' / ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='measurement.json' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='양쪽에' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='data_type' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='필드' + r10 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r11 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='노출' + p4 lvl=0 align=None - text='• labdb 웹에서 raw JSON 다운로드 가능' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='labdb' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='웹에서' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' raw JSON ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='다운로드' + r6 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r7 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='가능' + p5 lvl=1 align=None - text='– (raw 외 별도 처리 영역은 web 담당 — 미수정)' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– (raw 외 ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='별도' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='처리' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='영역은' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' web ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='담당' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' — ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='미수정' + r10 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=')' + p6 lvl=0 align=None - text='• 웹 프론트엔드 wall detection 알고리즘 V4.1로 변경' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• 웹 ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='프론트엔드' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' wall detection ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='알고리즘' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' V4.1로 ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='변경' + p7 lvl=0 align=None - text='• raw JSON 파일명에 session ID 포함 + 메타데이터 저장' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• raw JSON ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='파일명에' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' session ID ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='포함' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' + ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='메타데이터' + r6 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r7 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='저장' + p8 lvl=1 align=None - text='– 파일명만으로 측정 식별, examiner / posture / step / true_volume' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='파일명만으로' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='측정' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='식별' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=', examiner / posture / step / ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='true_volume' + p9 lvl=0 align=None - text='• PostgreSQL JSONB NULL byte 500 에러 해결' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• PostgreSQL JSONB NULL byte 500 ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='에러 해결' + p10 lvl=1 align=None - text='– 서버 /var/log/labdb.log 직접 확인 → BLE rid: 응답의 trailing NULL이' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='서버' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' /var/log/labdb.log ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='직접' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='확인' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' → BLE rid: ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='응답의' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' trailing ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='NULL이' + r10 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r11 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='원인' + p11 lvl=1 align=None - text='– BLE 파싱 + LabdbClient 양쪽에 재귀 sanitizer 추가' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– BLE ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='파싱' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' + ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='LabdbClient' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='양쪽에' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='재귀' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' sanitizer ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='추가' + - shape name='그림 7' type=PICTURE (13) autoshape= + geom: L=9135186 T=3057935 W=5076573 H=4302985 EMU | L=9.99in T=3.34in W=5.55in H=4.71in + line: color=inherit width_pt=None + - shape name='그림 9' type=PICTURE (13) autoshape= + geom: L=7075214 T=582514 W=3633182 H=2356549 EMU | L=7.74in T=0.64in W=3.97in H=2.58in + line: color=inherit width_pt=None + - shape name='그림 12' type=PICTURE (13) autoshape= + geom: L=10834869 T=582514 W=3393195 H=2356549 EMU | L=11.85in T=0.64in W=3.71in H=2.58in + line: color=inherit width_pt=None + +====================================================================== +SLIDE 4 + layout: 1. 빈 화면 + background: type=BACKGROUND (5) + shape_count: 3 + - shape name='TextBox 1' type=TEXT_BOX (17) autoshape= + geom: L=402336 T=173736 W=6236208 H=457200 EMU | L=0.44in T=0.19in W=6.82in H=0.50in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=False mL=0 mR=91440 mT=0 mB=45720 + text(60)='Android App 진행 보고' + p0 lvl=0 align=None - text='Android App 진행 보고' + r0 font='나눔고딕 ExtraBold' sz=24.0 b=True i=None c=inherit t='Android App 진행 보고' + - shape name='TextBox 3' type=TEXT_BOX (17) autoshape= + geom: L=603504 T=868680 W=13240512 H=5781070 EMU | L=0.66in T=0.95in W=14.48in H=6.32in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=True mL=0 mR=91440 mT=45720 mB=45720 + text(60)='펌웨어 업데이트 대응 — reb 패킷 신구조 (208B → 210B) | • payload 앞에 ch_in' + p0 lvl=0 align=None - text='펌웨어 업데이트 대응 — reb 패킷 신구조 (208B → 210B)' + r0 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='펌웨어' + r1 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' ' + r2 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='업데이트' + r3 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' ' + r4 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='대응' + r5 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' — reb ' + r6 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='패킷' + r7 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' ' + r8 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='신구조' + r9 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' (208B → 210B)' + p1 lvl=0 align=None - text='• payload 앞에 ch_info 2B 추가 = [ch_session 1B] + [ch_num 1B]' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• payload ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='앞에' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='ch_info' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' 2B ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='추가' + r6 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' = [' + r7 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='ch_session' + r8 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' 1B] + [' + r9 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='ch_num' + r10 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' 1B]' + p2 lvl=1 align=None - text='– [tag 4B][ch_info 2B][num_sample 2B][adc 200B][crc 2B]' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– [tag 4B][' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='ch_info' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' 2B][' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='num_sample' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' 2B][' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='adc' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' 200B][' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='crc' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' 2B]' + p3 lvl=0 align=None - text='• 채널/세션 정보로 측정 set 식별' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='채널' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='/' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='세션' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='정보로' + r6 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r7 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='측정' + r8 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' set ' + r9 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='식별' + p4 lvl=1 align=None - text='– 동일 ch_session = 한 측정 set으로 6개 reb 묶음' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='동일' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='ch_session' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' = 한 ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='측정' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='set으로' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' 6개 reb ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='묶음' + p5 lvl=1 align=None - text='– ch_num으로 채널 직접 indexing (도착 순서 의존 폐기)' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='ch_num으로' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='채널' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='직접' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' indexing (' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='도착' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='순서' + r10 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r11 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='의존' + r12 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r13 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='폐기' + r14 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=')' + p6 lvl=0 align=None - text='• 누락/불일치 측정 set 자동 폐기' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='누락' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='/' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='불일치' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='측정' + r6 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' set ' + r7 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='자동' + r8 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r9 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='폐기' + p7 lvl=1 align=None - text='– session 불일치 / 중복 ch_num / 6채널 중 일부 누락 → 해당 set drop' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– session ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='불일치' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' / ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='중복' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='ch_num' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' / 6채널 중 ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='일부' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='누락' + r10 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' → ' + r11 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='해당' + r12 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' set drop' + p8 lvl=1 align=None - text='– 다음 정상 set만 처리' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='다음' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='정상' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='set만' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='처리' + p9 lvl=0 align=None - text='• 한 곳 수정으로 전 화면 적용' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• 한 곳 ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='수정으로' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' 전 ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='화면' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='적용' + p10 lvl=1 align=None - text='– 도넛차트(maa?) · placement · 임상(mtb?) 모두 동일 collector' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='도넛차트' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='(maa?) · placement · ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='임상' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='(' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='mtb' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='?) ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='모두' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='동일' + r10 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' collector' + p11 lvl=1 align=None - text='– PiezoPacketCollector 한 군데만 신구조로 재작성' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='PiezoPacketCollector' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' 한 ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='군데만' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='신구조로' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='재작성' + p12 lvl=0 align=None - text='• Sensor 측정 시 IMU 값 — 가장 오래된 것 → 가장 최근 것으로 수정' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• Sensor ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='측정' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' 시 IMU 값 — ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='가장' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='오래된' + r6 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' 것 → ' + r7 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='가장' + r8 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r9 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='최근' + r10 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r11 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='것으로' + r12 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r13 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='수정' + p13 lvl=1 align=None - text='– FIFO 첫 샘플 사용 버그 → 측정 순간 자세 반영을 위해 마지막 샘플로' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– FIFO 첫 ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='샘플' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='사용' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='버그' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' → ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='측정' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='순간' + r10 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r11 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='자세' + r12 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r13 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='반영을' + r14 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r15 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='위해' + r16 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r17 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='마지막' + r18 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r19 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='샘플로' + p14 lvl=1 align=None - text='' + p15 lvl=1 align=None - text='총 15개 받는데 맨 처음 들어온거는 더 적을 수 있음.' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='총 ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='15' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='개 받는데 맨 처음 ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='들어온거는' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='더 적을 수 있음' + r6 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='.' + p16 lvl=1 align=None - text='마지막으로 받은 imu값(최신) 을 센서 측정 당시의 imu로 이해하면 될것.' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='마지막으로 받은 ' + r1 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='imu' + r2 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='값' + r3 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='(' + r4 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='최신' + r5 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t=') ' + r6 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='을 센서 측정 당시의 ' + r7 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='imu' + r8 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='로 이해하면 ' + r9 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='될것' + r10 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='.' + - shape name='그림 5' type=PICTURE (13) autoshape= + geom: L=8661917 T=1550078 W=2991267 H=4534533 EMU | L=9.47in T=1.70in W=3.27in H=4.96in + line: color=inherit width_pt=None + +====================================================================== +SLIDE 5 + layout: 1. 빈 화면 + background: type=BACKGROUND (5) + shape_count: 3 + - shape name='TextBox 1' type=TEXT_BOX (17) autoshape= + geom: L=402336 T=173736 W=6236208 H=457200 EMU | L=0.44in T=0.19in W=6.82in H=0.50in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=False mL=0 mR=91440 mT=0 mB=45720 + text(60)='Android App 진행 보고' + p0 lvl=0 align=None - text='Android App 진행 보고' + r0 font='나눔고딕 ExtraBold' sz=24.0 b=True i=None c=inherit t='Android App 진행 보고' + - shape name='TextBox 3' type=TEXT_BOX (17) autoshape= + geom: L=603504 T=868680 W=13240512 H=6858000 EMU | L=0.66in T=0.95in W=14.48in H=7.50in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=True mL=0 mR=91440 mT=45720 mB=45720 + text(60)='ClinicalLive — V4.1 Wall Peak 오버레이 (사내 가시화 요청) | • 사내 임상 테스' + p0 lvl=0 align=None - text='ClinicalLive — V4.1 Wall Peak 오버레이 (사내 가시화 요청)' + r0 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='ClinicalLive — V4.1 Wall Peak 오버레이 (사내 가' + p1 lvl=0 align=None - text='• 사내 임상 테스트 진행자 요청 — 실시간 peak 위치 가시화' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• 사내 임상 테스트 진행자 요청 — 실시간 peak 위치 가시화' + p2 lvl=0 align=None - text='• V4.1 wall detection (walldetect.V41Detector)을 매 mtb 사이클마다' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• V4.1 wall detection (walldetect.V41De' + p3 lvl=1 align=None - text='– 입력: 6채널 raw ADC + ProbeProfileDto (PiezoMonitoring과 동일 설정' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– 입력: 6채널 raw ADC + ProbeProfileDto (Pi' + p4 lvl=1 align=None - text='– 출력: 채널별 antIdx(전벽) / postIdx(후벽) Int?' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– 출력: 채널별 antIdx(전벽) / postIdx(후벽) Int?' + p5 lvl=1 align=None - text='– runCatching으로 감싸 detection 실패가 측정 자체에 영향 없도록' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– runCatching으로 감싸 detection 실패가 측정 자체에' + p6 lvl=0 align=None - text='• 표시' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• 표시' + p7 lvl=1 align=None - text='– 그래프 위 세로선 마커 — ant=green, post=orange (alpha 0.75)' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– 그래프 위 세로선 마커 — ant=green, post=orange' + p8 lvl=1 align=None - text='– 채널 헤더 우측 "a{antIdx} p{postIdx}" 컬러 텍스트' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– 채널 헤더 우측 "a{antIdx} p{postIdx}" 컬러 텍스' + p9 lvl=1 align=None - text='– 기존 raw max peak 숫자도 그대로 유지' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– 기존 raw max peak 숫자도 그대로 유지' + p10 lvl=0 align=None - text='• 저장 데이터는 변경 없음' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• 저장 데이터는 변경 없음' + p11 lvl=1 align=None - text='– measurement.json / labdb payload는 그대로 raw ADC' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– measurement.json / labdb payload는 그대로' + p12 lvl=1 align=None - text='– V4.1 결과는 화면 표시 전용 — 알고리즘 변경 시 같은 데이터로 재분석' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– V4.1 결과는 화면 표시 전용 — 알고리즘 변경 시 같은 데이터로' + - shape name='그림 4' type=PICTURE (13) autoshape= + geom: L=7315200 T=3161841 W=6946073 H=3101503 EMU | L=8.00in T=3.46in W=7.60in H=3.39in + line: color=inherit width_pt=None + +====================================================================== +SLIDE 6 + layout: 1. 빈 화면 + background: type=BACKGROUND (5) + shape_count: 4 + - shape name='TextBox 1' type=TEXT_BOX (17) autoshape= + geom: L=402336 T=173736 W=6236208 H=457200 EMU | L=0.44in T=0.19in W=6.82in H=0.50in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=False mL=0 mR=91440 mT=0 mB=45720 + text(60)='Android App 진행 보고' + p0 lvl=0 align=None - text='Android App 진행 보고' + r0 font='나눔고딕 ExtraBold' sz=24.0 b=True i=None c=inherit t='Android App 진행 보고' + - shape name='TextBox 3' type=TEXT_BOX (17) autoshape= + geom: L=603504 T=868680 W=13240512 H=5586145 EMU | L=0.66in T=0.95in W=14.48in H=6.11in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=True mL=0 mR=91440 mT=45720 mB=45720 + text(60)='사내 테스트 피드백 반영 — UX 정리 3건 및 오류 수정 | • 도넛차트 색깔 일관성 fix | – 증' + p0 lvl=0 align=None - text='사내 테스트 피드백 반영 — UX 정리 3건 및 오류 수정' + r0 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='사내' + r1 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' ' + r2 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='테스트' + r3 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' ' + r4 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='피드백' + r5 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' ' + r6 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='반영' + r7 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' — UX ' + r8 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='정리' + r9 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' 3건' + r10 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t=' ' + r11 font='나눔고딕 ExtraBold' sz=28.0 b=True i=None c=#222A33 t='및 오류 수정' + p1 lvl=0 align=None - text='• 도넛차트 색깔 일관성 fix' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='도넛차트' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='색깔' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='일관성' + r6 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' fix' + p2 lvl=1 align=None - text='– 증상: Single scan 309ml(노란색) 후 Auto scan 에서 색깔만 초록색으로 바뀌는 오' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='증상' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=': Single scan 309ml(' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='노란색' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=') 후 Auto scan ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='에서' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='색깔만' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='초록색으로' + r10 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r11 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='바뀌는 오류' + p3 lvl=2 align=None - text='· 표시값(maxVolumeMl)과 색깔(lastVolumeMl) source 불일치' + r0 font='나눔고딕' sz=13.0 b=False i=None c=#55606C t='· ' + r1 font='나눔고딕' sz=13.0 b=False i=None c=#55606C t='표시값' + r2 font='나눔고딕' sz=13.0 b=False i=None c=#55606C t='(' + r3 font='나눔고딕' sz=13.0 b=False i=None c=#55606C t='maxVolumeMl' + r4 font='나눔고딕' sz=13.0 b=False i=None c=#55606C t=')과 ' + r5 font='나눔고딕' sz=13.0 b=False i=None c=#55606C t='색깔' + r6 font='나눔고딕' sz=13.0 b=False i=None c=#55606C t='(' + r7 font='나눔고딕' sz=13.0 b=False i=None c=#55606C t='lastVolumeMl' + r8 font='나눔고딕' sz=13.0 b=False i=None c=#55606C t=') source ' + r9 font='나눔고딕' sz=13.0 b=False i=None c=#55606C t='불일치' + p4 lvl=1 align=None - text='– 수정: bladderLevel 업데이트도 maxVolumeMl 기준으로 통일' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='수정' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=': ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='bladderLevel' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='업데이트도' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='maxVolumeMl' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='기준으로' + r10 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r11 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='통일' + p5 lvl=0 align=None - text='• Setup 화면 Auto Scan Interval 카드 추가' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• Setup ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='화면' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' Auto Scan Interval ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='카드' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' ' + r5 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='추가' + p6 lvl=1 align=None - text='– PiezoPersonalizationView에 신규 카드 — 600~5000ms 슬라이더 + ±200m' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='PiezoPersonalizationView에' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='신규' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='카드' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' — 600~5000ms ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='슬라이더' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' + ±200ms ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='스테퍼' + p7 lvl=1 align=None - text='– 기존 MaxVolume / CatheterThreshold 카드와 동일 톤, 3카드 verticalSc' + r0 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='기존' + r2 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='MaxVolume' + r4 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' / ' + r5 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='CatheterThreshold' + r6 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r7 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='카드와' + r8 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' ' + r9 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='동일' + r10 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t=' 톤, 3카드 ' + r11 font='나눔고딕' sz=15.0 b=False i=None c=#222A33 t='verticalScroll' + p8 lvl=0 align=None - text='• BLE 끊김 banner 제거 — Silent Reconnect' + r0 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='• BLE ' + r1 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='끊김' + r2 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' banner ' + r3 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t='제거' + r4 font='나눔고딕' sz=18.0 b=True i=None c=#1E88E5 t=' — Silent Reconnect' + p9 lvl=1 align=None - text='– PiezoMonitoring / VivamyoMonitoring 양쪽 banner 표시 제거' + r0 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='PiezoMonitoring' + r2 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t=' ' + r3 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='/ ' + r4 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='VivamyoMonitoring' + r5 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t=' 양쪽 ' + r6 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='banner ' + r7 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='표시 제거' + p10 lvl=1 align=None - text='– BleManager.scheduleAutoReconnect()가 이미 백그라운드 재연결 시도' + r0 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='BleManager.scheduleAutoReconnect' + r2 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='()' + r3 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='가 이미 백그라운드 ' + r4 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='재연결' + r5 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t=' 시도' + p11 lvl=1 align=None - text='– 측정 일시정지 / 배터리 폴링 재시작 등 다른 처리는 그대로 유지' + r0 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='– ' + r1 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='측정 일시정지 ' + r2 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='/ ' + r3 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='배터리 ' + r4 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t='폴링' + r5 font='나눔고딕' sz=15.0 b=None i=None c=#222A33 t=' 재시작 등 다른 처리는 그대로 유지' + p12 lvl=0 align=None - text='• 첫 연결시 배터리 잔량 표시가 안되는 오류 수정' + r0 font='나눔고딕' sz=None b=True i=None c=#1E88E5 t='• ' + r1 font='나눔고딕' sz=None b=True i=None c=#1E88E5 t='첫 ' + r2 font='나눔고딕' sz=None b=True i=None c=#1E88E5 t='연결시' + r3 font='나눔고딕' sz=None b=True i=None c=#1E88E5 t=' 배터리 잔량 표시가 안되는 오류 수정' + p13 lvl=0 align=None - text='' + p14 lvl=0 align=None - text='' + p15 lvl=0 align=None - text='' + - shape name='그림 5' type=PICTURE (13) autoshape= + geom: L=2457674 T=5771838 W=6630325 H=1743318 EMU | L=2.69in T=6.31in W=7.25in H=1.91in + line: color=inherit width_pt=None + - shape name='그림 7' type=PICTURE (13) autoshape= + geom: L=10593990 T=1256249 W=2486422 H=5387248 EMU | L=11.59in T=1.37in W=2.72in H=5.89in + line: color=inherit width_pt=None + +====================================================================== +SLIDE 7 + layout: 1. 빈 화면 + background: type=BACKGROUND (5) + shape_count: 1 + - shape name='TextBox 1' type=TEXT_BOX (17) autoshape= + geom: L=6243111 T=3530025 W=2144177 H=584775 EMU | L=6.83in T=3.86in W=2.34in H=0.64in + fill: type=BACKGROUND (5) + line: color=inherit width_pt=None + textframe: anchor=None wrap=False mL=0 mR=91440 mT=45720 mB=45720 + text(60)='감사합니다' + p0 lvl=0 align=None - text='감사합니다' + r0 font='나눔고딕 ExtraBold' sz=32.0 b=True i=None c=inherit t='감사합니다' diff --git a/ppt/새 폴더/_dump_design.py b/ppt/새 폴더/_dump_design.py new file mode 100644 index 0000000..dcc2338 --- /dev/null +++ b/ppt/새 폴더/_dump_design.py @@ -0,0 +1,264 @@ +"""Extract exact visual design info from the reference PPTX into _design_dump.txt.""" +from pathlib import Path +import sys + +from pptx import Presentation +from pptx.util import Emu +from pptx.dml.color import RGBColor +from pptx.enum.shapes import MSO_SHAPE_TYPE +from pptx.oxml.ns import qn + +PPT_DIR = Path(__file__).parent +SRC = PPT_DIR / "주간보고서_dwjang_20260604.pptx" +OUT = PPT_DIR / "_design_dump.txt" + + +def emu_to_in(v): + try: + return f"{Emu(v).inches:.2f}" + except Exception: + return "?" + + +def fmt_xy(left, top, width, height): + return ( + f"L={left} T={top} W={width} H={height} EMU | " + f"L={emu_to_in(left)}in T={emu_to_in(top)}in " + f"W={emu_to_in(width)}in H={emu_to_in(height)}in" + ) + + +def color_from_fill(fill): + """Best-effort extraction of solid fill color as hex.""" + try: + if fill.type is None: + return "none/inherit" + # 1 = SOLID per MSO_FILL_TYPE + if int(fill.type) == 1: + fc = fill.fore_color + try: + rgb = fc.rgb + if rgb is not None: + return f"#{str(rgb)}" + except Exception: + pass + try: + return f"theme:{fc.theme_color}" + except Exception: + pass + return f"type={fill.type}" + except Exception as e: + return f"err:{e.__class__.__name__}" + + +def color_from_line(line): + try: + c = line.color + try: + rgb = c.rgb + if rgb is not None: + return f"#{str(rgb)}" + except Exception: + pass + try: + return f"theme:{c.theme_color}" + except Exception: + return "inherit" + except Exception: + return "n/a" + + +def run_color(run): + try: + c = run.font.color + try: + rgb = c.rgb + if rgb is not None: + return f"#{str(rgb)}" + except Exception: + pass + try: + return f"theme:{c.theme_color}" + except Exception: + return "inherit" + except Exception: + return "inherit" + + +def slide_bg(slide): + """Try to read slide background fill.""" + try: + bg = slide.background + return color_from_fill(bg.fill) + except Exception as e: + return f"err:{e.__class__.__name__}" + + +def shape_type_name(shape): + try: + st = shape.shape_type + if st is None: + return "None" + return str(st) + except Exception: + return "?" + + +def autoshape_kind(shape): + try: + return str(shape.auto_shape_type) + except Exception: + return "" + + +def dump_text_frame(tf, out_lines, indent=" "): + for pi, para in enumerate(tf.paragraphs): + lvl = para.level + align = para.alignment + # Detect bullet via pPr/buChar/buAutoNum + pPr = para._pPr + bullet = "-" + if pPr is not None: + if pPr.find(qn("a:buNone")) is not None: + bullet = "noBul" + elif pPr.find(qn("a:buChar")) is not None: + bc = pPr.find(qn("a:buChar")) + bullet = f"buChar={bc.get('char')!r}" + elif pPr.find(qn("a:buAutoNum")) is not None: + bullet = "buAutoNum" + runs_info = [] + full_txt = "" + for r in para.runs: + t = r.text or "" + full_txt += t + f = r.font + runs_info.append({ + "text": t, + "name": f.name, + "size": (f.size.pt if f.size else None), + "bold": f.bold, + "italic": f.italic, + "color": run_color(r), + }) + snippet = full_txt[:60].replace("\n", " ") + out_lines.append( + f"{indent}p{pi} lvl={lvl} align={align} {bullet} text={snippet!r}" + ) + for ri, info in enumerate(runs_info): + tt = info["text"][:40].replace("\n", " ") + out_lines.append( + f"{indent} r{ri} font={info['name']!r} sz={info['size']} " + f"b={info['bold']} i={info['italic']} c={info['color']} t={tt!r}" + ) + + +def dump_shape(shape, out_lines, indent=" "): + name = shape.name + st = shape_type_name(shape) + kind = autoshape_kind(shape) if st == "MSO_SHAPE_TYPE.AUTO_SHAPE (1)" else "" + try: + left, top, width, height = shape.left, shape.top, shape.width, shape.height + except Exception: + left = top = width = height = None + out_lines.append( + f"{indent}- shape name={name!r} type={st} autoshape={kind}" + ) + out_lines.append(f"{indent} geom: {fmt_xy(left, top, width, height)}") + + # Fill + try: + if shape.has_text_frame or st.startswith("MSO_SHAPE_TYPE.AUTO_SHAPE") or st == "MSO_SHAPE_TYPE.TEXT_BOX (17)": + fill_c = color_from_fill(shape.fill) + out_lines.append(f"{indent} fill: {fill_c}") + except Exception: + pass + + # Line + try: + line = shape.line + lc = color_from_line(line) + try: + lw = line.width + lw_pt = (lw / 12700) if lw else None + except Exception: + lw_pt = None + out_lines.append(f"{indent} line: color={lc} width_pt={lw_pt}") + except Exception: + pass + + # Picture + if st == "MSO_SHAPE_TYPE.PICTURE (13)": + try: + img = shape.image + out_lines.append( + f"{indent} picture: ext={img.ext} sha1={img.sha1[:10]} " + f"size_bytes={len(img.blob)} filename={getattr(img, 'filename', None)!r}" + ) + except Exception as e: + out_lines.append(f"{indent} picture: err={e}") + + # Text + if shape.has_text_frame: + tf = shape.text_frame + # vertical anchor + try: + va = tf.vertical_anchor + except Exception: + va = None + try: + wrap = tf.word_wrap + except Exception: + wrap = None + out_lines.append( + f"{indent} textframe: anchor={va} wrap={wrap} " + f"mL={tf.margin_left} mR={tf.margin_right} mT={tf.margin_top} mB={tf.margin_bottom}" + ) + # Full text first 60 chars + full = (shape.text_frame.text or "").replace("\n", " | ") + out_lines.append(f"{indent} text(60)={full[:60]!r}") + dump_text_frame(tf, out_lines, indent=indent + " ") + + # Group + if st == "MSO_SHAPE_TYPE.GROUP (6)": + out_lines.append(f"{indent} group children:") + for child in shape.shapes: + dump_shape(child, out_lines, indent=indent + " ") + + +def main(): + prs = Presentation(SRC) + lines = [] + lines.append(f"FILE: {SRC.name}") + lines.append( + f"SLIDE SIZE: W={prs.slide_width} H={prs.slide_height} EMU | " + f"W={emu_to_in(prs.slide_width)}in H={emu_to_in(prs.slide_height)}in" + ) + lines.append(f"SLIDE COUNT: {len(prs.slides)}") + lines.append("") + # Layouts available + lines.append("LAYOUTS:") + for i, lay in enumerate(prs.slide_layouts): + lines.append(f" [{i}] {lay.name}") + lines.append("") + # Master fonts / theme colors (best effort) + try: + theme_xml = prs.slide_masters[0].element.getroottree() + except Exception: + pass + + for si, slide in enumerate(prs.slides, start=1): + lines.append("=" * 70) + lines.append(f"SLIDE {si}") + lines.append(f" layout: {slide.slide_layout.name}") + lines.append(f" background: {slide_bg(slide)}") + lines.append(f" shape_count: {len(slide.shapes)}") + for shp in slide.shapes: + dump_shape(shp, lines, indent=" ") + lines.append("") + + OUT.write_text("\n".join(lines), encoding="utf-8") + print(f"WROTE: {OUT} lines={len(lines)}") + + +if __name__ == "__main__": + main() diff --git a/ppt/새 폴더/build_weekly_report.py b/ppt/새 폴더/build_weekly_report.py new file mode 100644 index 0000000..97fc70c --- /dev/null +++ b/ppt/새 폴더/build_weekly_report.py @@ -0,0 +1,439 @@ +""" +주간보고서 자동 생성 — 2026-06-08(월) ~ 06-12(금) 작업분. + +기존 양식 (주간보고서_dwjang_20260604.pptx) 의 슬라이드 마스터/레이아웃을 +그대로 가져다 쓰고, 컨텐츠만 교체. + +디자인 규칙 (기존 양식에서 추출): +- 16:9 화이트 마스터, 별도 헤더바/배경 데코 없음 (텍스트만) +- 컨텐츠 슬라이드 좌상단 "Android App 진행 보고" 24pt ExtraBold 러닝헤더 +- 본문 textbox: L=0.66" T=0.95" W=14.48" + · 제목 28pt ExtraBold #222A33 + · L1 "• " + 두 칸 · 18pt Bold + accent blue #1E88E5 + · L2 "– " + 두 칸 · 15pt regular #222A33 + · L3 "· " + 여섯 칸 · 13pt regular #55606C +- 스크린샷은 본문 우측 또는 하단에 카드/테두리 없이 배치 +""" +from pathlib import Path +from copy import deepcopy +from lxml import etree +from pptx import Presentation +from pptx.util import Inches, Pt, Emu +from pptx.dml.color import RGBColor +from pptx.enum.text import PP_ALIGN + +PPT_DIR = Path(__file__).parent +TEMPLATE = PPT_DIR / "주간보고서_dwjang_20260604.pptx" +OUT_PATH = PPT_DIR / "주간보고서_dwjang_20260611.pptx" + +# 팔레트 (정확한 추출) +COLOR_TEXT = RGBColor(0x22, 0x2A, 0x33) +COLOR_TEXT_SUB = RGBColor(0x55, 0x60, 0x6C) +COLOR_ACCENT = RGBColor(0x1E, 0x88, 0xE5) + +FONT_BODY = "나눔고딕" +FONT_HEAD = "나눔고딕 ExtraBold" + + +# ────────────────────────────────────────────────────────────── +# Helper: 기존 slide 다 지우기 +# ────────────────────────────────────────────────────────────── +def clear_slides(prs): + """Presentation 의 모든 슬라이드를 제거 + dangling slide part 도 drop.""" + sld_id_lst = prs.slides._sldIdLst + prs_part = prs.part + # rId → slide part 매핑 수집 + to_drop_rids = [] + for sld_id in list(sld_id_lst): + rid = sld_id.get( + '{http://schemas.openxmlformats.org/officeDocument/2006/relationships}id' + ) + if rid: + to_drop_rids.append(rid) + sld_id_lst.remove(sld_id) + # 관련 part 와 rel 제거 + for rid in to_drop_rids: + # part_related_by_id → 슬라이드 part 가져오기 + try: + prs_part.drop_rel(rid) + except KeyError: + pass + + +# ────────────────────────────────────────────────────────────── +# 텍스트 설정 유틸 +# ────────────────────────────────────────────────────────────── +def set_run(run, text, *, font=FONT_BODY, size=14, bold=False, + color=COLOR_TEXT): + run.text = text + run.font.name = font + # ea/cs 폰트도 같이 — 나눔고딕 깨짐 방지 + rPr = run._r.get_or_add_rPr() + # eastAsia + ea = rPr.find('{http://schemas.openxmlformats.org/drawingml/2006/main}ea') + if ea is None: + ea = etree.SubElement(rPr, '{http://schemas.openxmlformats.org/drawingml/2006/main}ea') + ea.set('typeface', font) + cs = rPr.find('{http://schemas.openxmlformats.org/drawingml/2006/main}cs') + if cs is None: + cs = etree.SubElement(rPr, '{http://schemas.openxmlformats.org/drawingml/2006/main}cs') + cs.set('typeface', font) + run.font.size = Pt(size) + run.font.bold = bold + if color is not None: + run.font.color.rgb = color + + +def add_textbox(slide, left, top, width, height): + tb = slide.shapes.add_textbox(left, top, width, height) + tf = tb.text_frame + tf.word_wrap = True + tf.margin_left = Inches(0.05) + tf.margin_right = Inches(0.05) + tf.margin_top = Inches(0.0) + tf.margin_bottom = Inches(0.0) + return tb, tf + + +def add_running_header(slide): + """좌상단 '주간 진행 보고 — Android App' 러닝헤더.""" + tb, tf = add_textbox(slide, Inches(0.44), Inches(0.19), + Inches(8), Inches(0.5)) + p = tf.paragraphs[0] + p.alignment = PP_ALIGN.LEFT + run = p.add_run() + set_run(run, "Android App 진행 보고", + font=FONT_HEAD, size=24, bold=True, color=COLOR_TEXT) + + +def add_slide_title(tf, title_text): + """본문 textbox 첫 문단으로 슬라이드 타이틀.""" + p = tf.paragraphs[0] + p.alignment = PP_ALIGN.LEFT + run = p.add_run() + set_run(run, title_text, font=FONT_HEAD, size=28, bold=True, + color=COLOR_TEXT) + + +def add_bullets(tf, lines): + """lines = [(level, text)] 레벨별 prefix/폰트/컬러 자동.""" + for level, text in lines: + p = tf.add_paragraph() + p.alignment = PP_ALIGN.LEFT + p.level = 0 # 우리는 모든 indent 를 prefix 로 처리 (양식과 동일) + run = p.add_run() + if level == 0: + prefix = "• " + size = 18; bold = True; color = COLOR_ACCENT + elif level == 1: + prefix = "– " + size = 15; bold = False; color = COLOR_TEXT + else: + prefix = "· " + size = 13; bold = False; color = COLOR_TEXT_SUB + set_run(run, prefix + text, font=FONT_BODY, size=size, bold=bold, + color=color) + + +def add_spacer(tf, count=1, size=18): + for _ in range(count): + p = tf.add_paragraph() + run = p.add_run() + set_run(run, "", font=FONT_BODY, size=size) + + +def add_caption(slide, text, left, top, width): + tb, tf = add_textbox(slide, left, top, width, Inches(0.32)) + p = tf.paragraphs[0] + p.alignment = PP_ALIGN.CENTER + run = p.add_run() + set_run(run, text, font=FONT_BODY, size=11, color=COLOR_TEXT_SUB) + + +def fit_picture(slide, path, left, top, max_w, max_h, *, phone=True): + """폰(1080:2340) 또는 태블릿(1200:1920) 비율 유지하며 박스 안에 fit.""" + if not path.exists(): + return None + aspect = (1080 / 2340) if phone else (1200 / 1920) + if max_w / max_h > aspect: + h = max_h + w = int(h * aspect) + else: + w = max_w + h = int(w / aspect) + cx = left + (max_w - w) // 2 + cy = top + (max_h - h) // 2 + return slide.shapes.add_picture(str(path), cx, cy, w, h) + + +# ────────────────────────────────────────────────────────────── +# 슬라이드 빌더 +# ────────────────────────────────────────────────────────────── +def build_title_slide(prs): + # Layout 0 = "0. 제목 반전 슬라이드" + layout = prs.slide_layouts[0] + s = prs.slides.add_slide(layout) + + # 제목 plchldr 위치는 기존 양식에 따라 우측 텍스트 블록 + # 기존: L=7.24" T=2.95" W=8.32" H=2.05" + tb, tf = add_textbox(s, Inches(7.24), Inches(2.95), + Inches(8.32), Inches(2.05)) + p = tf.paragraphs[0] + p.alignment = PP_ALIGN.LEFT + run = p.add_run() + set_run(run, "주간 진행 보고", font=FONT_HEAD, size=32, bold=True, + color=COLOR_TEXT) + + # 부제 (날짜) L=7.24" T=5.00" + tb2, tf2 = add_textbox(s, Inches(7.24), Inches(5.00), + Inches(8.32), Inches(0.6)) + p2 = tf2.paragraphs[0] + p2.alignment = PP_ALIGN.LEFT + run2 = p2.add_run() + set_run(run2, "2026-06-08 (월) ~ 06-12 (금)", + font=FONT_BODY, size=18, bold=True, color=COLOR_TEXT_SUB) + return s + + +def build_content_slide(prs, title, bullets, *, body_h=Inches(7.5), + pics=None, captions=None): + """ + title: slide title (28pt) + bullets: [(level, text), ...] + pics: optional list of (path, left_in, top_in, w_in, h_in, phone_bool) + captions: optional list of (text, left_in, top_in, w_in) + """ + layout = prs.slide_layouts[1] # 1. 빈 화면 + s = prs.slides.add_slide(layout) + add_running_header(s) + # 본문 textbox + tb, tf = add_textbox(s, Inches(0.66), Inches(0.95), + Inches(14.48), body_h) + add_slide_title(tf, title) + add_spacer(tf, 1) + add_bullets(tf, bullets) + # 그림 + if pics: + for (path, left, top, w, h, phone) in pics: + fit_picture(s, path, Inches(left), Inches(top), + Inches(w), Inches(h), phone=phone) + if captions: + for (text, left, top, w) in captions: + add_caption(s, text, Inches(left), Inches(top), Inches(w)) + return s + + +def build_closing_slide(prs): + layout = prs.slide_layouts[1] + s = prs.slides.add_slide(layout) + # 정중앙 "감사합니다" + tb, tf = add_textbox(s, Inches(6.83), Inches(3.86), + Inches(4.5), Inches(1.0)) + p = tf.paragraphs[0] + p.alignment = PP_ALIGN.CENTER + run = p.add_run() + set_run(run, "감사합니다", font=FONT_HEAD, size=32, bold=True, + color=COLOR_TEXT) + return s + + +# ────────────────────────────────────────────────────────────── +# 메인 +# ────────────────────────────────────────────────────────────── +prs = Presentation(str(TEMPLATE)) +clear_slides(prs) + +# Slide 1 — Title +build_title_slide(prs) + +# Slide 2 — 핵심 요약 +build_content_slide(prs, + title="이번 주 핵심 요약 — 탭 navigation · 설정 통합 · BLE 안정성", + bullets=[ + (0, "4탭 셸 Navigation 도입 (Home / 측정 / 이력 / 설정)"), + (1, "기존 시퀀셜 화면 흐름 → 탭 기반 재편, sub-tab 으로 세부 화면 통합"), + (1, "탭 셸 노출 화면 / 위저드 풀스크린 분기 정책"), + (0, "이력 / 설정 탭 통합"), + (1, "이력 — 측정 + 배뇨일지 sub-tab"), + (1, "설정 — 개인화 + 알림 + 앱 정보 sub-tab"), + (1, "PiezoMonitoring overlay 의 user 설정은 모두 설정 탭으로 이동 (중복 제거)"), + (0, "BLE 안정성 — 다중 기기 페어링 (Clinical 한정) + 펌웨어 호환 체크"), + (1, "KnownDeviceStore — Clinical 흐름에서만 저장, 일반 사용자는 매 세션 fresh scan"), + (1, "Disconnect / Delete Pairing 분리 (회의 피드백 반영)"), + (1, "펌웨어 < VBTFW0118 / mid? 미응답 시 경고 배너 · mfv? fallback"), + (0, "Polish · Bug fix"), + (1, "첫 설치 시 Consent 화면 노출 fix · Dev Tools 영역 dev 모드 전용"), + (1, "설정 탭 개인화 카드 컴팩트 모드 (한 화면에 3카드 fit)"), + ], +) + +# Slide 3 — 4탭 셸 +build_content_slide(prs, + title="4탭 셸 Navigation 도입 — MainShell + 자동 라우팅", + bullets=[ + (0, "탭 셸 노출 화면 (showsTabShell)"), + (1, "HOME, PIEZO_MONITORING, MEASUREMENT_HISTORY, VOIDING_DIARY, SETTINGS"), + (1, "선택 탭은 현재 AppScreen 으로부터 자동 도출 — 별도 state 없음"), + (0, "탭 셸 숨김 (풀스크린 가이드형)"), + (1, "측정 위저드 — DeviceScan / Personalization / PlacementGuide / URINE_CAMERA"), + (1, "사전 화면 — Onboarding / Consent / Registration / PIN / Calibration"), + (1, "Clinical R&D 흐름 — ClinicalHome / ClinicalLive (별도 컨텍스트 보존)"), + (0, "탭별 진입 동작"), + (1, "Home → goHome() · NirsManager stop + demo state cleanup 포함"), + (1, "측정 → startFromHome() · 연결되어 있으면 PIEZO_MONITORING, 아니면 DEVICE_SCAN"), + (1, "이력 → HistoryTabView · 측정 sub-tab 진입"), + (1, "설정 → SettingsTabView · 개인화 sub-tab 진입"), + (0, "BackHandler 정정 — 셸 화면 Back 시 PIEZO_MONITORING → HOME 자연 복귀"), + ], + body_h=Inches(7.5), + pics=[ + (PPT_DIR / "Screenshot_20260611_165624_VesiScan Demo.jpg", + 11.0, 1.1, 4.4, 7.5, True), + ], + captions=[ + ("Home 탭 · 4탭 셸 적용 화면", 11.0, 8.6, 4.4), + ], +) + +# Slide 4 — 이력 탭 통합 +build_content_slide(prs, + title="이력 탭 통합 — MeasurementHistory + VoidingDiary", + bullets=[ + (0, "신규 HistoryTabView · SingleChoiceSegmentedButtonRow 로 sub-tab 전환"), + (1, "측정 — piezo 센서 측정 기록 (기존 History / Trends 내부 탭 유지)"), + (1, "배뇨일지 — 수동 입력 기록 (24h 의료지표 카드 포함)"), + (0, "기존 화면 정리"), + (1, "MeasurementHistoryView — 상단 바 (Back + 타이틀) 제거"), + (1, "VoidingDiaryView — Scaffold / TopAppBar / onBack 제거"), + (1, "탭 셸이 헤더 제공 → 화면 내 중복 헤더 모두 정리"), + (0, "라우팅 단순화"), + (1, "AppScreen.MEASUREMENT_HISTORY → 측정 sub-tab"), + (1, "AppScreen.VOIDING_DIARY → 배뇨일지 sub-tab"), + (1, "둘 다 HistoryTabView 진입점, initial sub-tab 만 다름"), + ], + body_h=Inches(7.0), + pics=[ + (PPT_DIR / "Screenshot_20260611_165644_VesiScan Demo.jpg", + 8.7, 1.1, 3.3, 7.5, True), + (PPT_DIR / "Screenshot_20260611_165648_VesiScan Demo.jpg", + 12.1, 1.1, 3.3, 7.5, True), + ], + captions=[ + ("측정 sub-tab", 8.7, 8.6, 3.3), + ("배뇨일지 sub-tab", 12.1, 8.6, 3.3), + ], +) + +# Slide 5 — 설정 탭 통합 +build_content_slide(prs, + title="설정 탭 통합 — 개인화 + 알림 + 앱 정보", + bullets=[ + (0, "신규 SettingsTabView · 3 sub-tab"), + (1, "개인화 — Max Volume / Catheter Threshold / Auto Scan Interval (+dev: Ant Offset)"), + (1, "알림 — ON/OFF · 간격 · 시간대 · 사운드/진동/팝업 (Reminder)"), + (1, "앱 정보 — 앱 버전 · 기기 연결 · 펌웨어 · (dev) Serial · Unpair"), + (0, "embedded 플래그로 위저드 / 설정 모드 분기"), + (1, "위저드 (embedded=false): 헤더 + Bladdy + Continue 버튼"), + (1, "설정 탭 (embedded=true): 카드만 노출, 컴팩트 사이즈, LaunchedEffect 로 자동 저장"), + (0, "Disconnect / Delete Pairing 분리"), + (1, "Disconnect (회색) — bond 유지, 다음 측정 시 PIN 없이 빠른 재연결"), + (1, "Delete Pairing (빨강) — 확인 다이얼로그 후 unbond + known list 제거 (destructive)"), + ], + body_h=Inches(7.0), + pics=[ + (PPT_DIR / "Screenshot_20260611_165653_VesiScan Demo.jpg", + 8.0, 1.1, 2.4, 7.5, True), + (PPT_DIR / "Screenshot_20260611_165657_VesiScan Demo.jpg", + 10.5, 1.1, 2.4, 7.5, True), + (PPT_DIR / "Screenshot_20260611_165701_VesiScan Demo.jpg", + 13.0, 1.1, 2.4, 7.5, True), + ], + captions=[ + ("개인화", 8.0, 8.6, 2.4), + ("알림", 10.5, 8.6, 2.4), + ("앱 정보", 13.0, 8.6, 2.4), + ], +) + +# Slide 6 — BLE 안정성 +build_content_slide(prs, + title="BLE 안정성 — Clinical 다중 기기 + 펌웨어 호환 체크", + bullets=[ + (0, "KnownDeviceStore — JSON 리스트로 다중 기기 영속화"), + (1, "getAll / add / remove / mostRecent · 구 단일 키 자동 마이그레이션"), + (1, "Clinical 흐름 (ClinicalSessionStore.inClinicalFlow) 에서만 저장"), + (1, "일반 사용자: 매 세션 fresh scan + pair · 저장 0개"), + (0, "DeviceScanView 2섹션 (Clinical 전용)"), + (1, "Saved Devices — 카드 탭 = PIN 없이 즉시 재연결 · 휴지통 = Delete Pairing"), + (1, "New Devices — 스캔된 기기 중 known 에 없는 것만"), + (0, "펌웨어 호환 체크"), + (1, "BleManager.MIN_FIRMWARE_BUILD = 118 · parseFirmwareBuild() 끝자리 숫자 비교"), + (1, "FirmwareWarningBanner — 구버전 (주황) / 응답 없음 (빨강) / 정상 (숨김)"), + (1, "rid: 파서 fixed-width 12B 슬라이스 보정 + mfv? 4초 후 fallback"), + ], + body_h=Inches(6.5), + pics=[ + # 펌웨어 경고 배너 실제 작동 (가로 태블릿) + (PPT_DIR / "Screenshot_20260611-154306.png", + 9.5, 1.1, 6.0, 5.5, False), + ], + captions=[ + ("펌웨어 경고 배너 작동 — VBTFW0116 → VBTFW0118 권장 안내", 9.5, 6.75, 6.0), + ], +) + +# Slide 7 — Bug fix / Polish +build_content_slide(prs, + title="Bug fix · Polish — Consent 화면 / Dev Tools / 컴팩트", + bullets=[ + (0, "Consent 화면 — 첫 설치 시 정상 노출 fix"), + (1, "기존 버그: completeOnboarding() 가 hasConsented=true 자동 마킹 → CONSENT 스킵"), + (1, "수정: hasConsented 자동 마킹 제거 · loadState 분기에 !hasConsented 추가"), + (1, "정상 흐름: ONBOARDING → CONSENT → REGISTRATION → PIN_SETUP → HOME"), + (0, "Dev Tools 영역 gating (PiezoMonitoring)"), + (1, "Logs & Charts 토글 + ChannelPanel / BleDebugPanel / Scan Log → isDevMode 한정"), + (1, "일반 사용자: Spot / Catheterize 액션 영역까지만 노출 (간결)"), + (0, "설정 탭 개인화 카드 — 컴팩트 모드"), + (1, "embedded=true 시 카드 padding / 폰트 / Stepper 크기 절반 수준"), + (1, "3카드 (dev 면 4카드) 한 화면 내 fit"), + ], + body_h=Inches(6.5), + pics=[ + (PPT_DIR / "Screenshot_20260611_165608_VesiScan Demo.jpg", + 9.5, 1.1, 3.0, 7.5, True), + (PPT_DIR / "Screenshot_20260611_165613_VesiScan Demo.jpg", + 12.7, 1.1, 3.0, 7.5, True), + ], + captions=[ + ("Consent 상단", 9.5, 8.6, 3.0), + ("Consent — 의료정보 동의", 12.7, 8.6, 3.0), + ], +) + +# Slide 8 — 결과물 / 다음 주 +build_content_slide(prs, + title="결과물 정리 · 다음 주 계획", + bullets=[ + (0, "feature/tab-navigation · 14 커밋 (master 5100616 → b427fab+)"), + (1, "Stage 1 — 4탭 셸 + 라우팅 (MainShell + AppScreen.SETTINGS)"), + (1, "Stage 2 — 이력 탭 sub-tab 통합 (HistoryTabView)"), + (1, "Stage 3 — 설정 탭 sub-tab 통합 (SettingsTabView + embedded mode)"), + (1, "Stage 4 — PiezoMonitoring 상단 바 · overlay 정리"), + (1, "BLE — 다중 기기 (Clinical) · Disconnect/Delete 분리 · 펌웨어 호환 체크"), + (0, "demo-final cherry-pick (1.1.0-design → 1.1.1-design)"), + (1, "BLE 안정성 패치만 backport — 다중 기기 + 펌웨어 호환 + rid 파서 fix"), + (0, "신규 문서 — docs/APP_STRUCTURE.md"), + (1, "탭 다이어그램 · AppScreen 카탈로그 · 핵심 파일 위치 · Back 분기표"), + (0, "다음 주 계획"), + (1, "디바이스 검증 — 일반/dev 모드 전체 흐름 풀 테스트 · Clinical 다중 기기 스위치"), + (1, "머지 정책 — feature/tab-navigation → master 머지 시점 결정"), + (1, "UX 폴리시 — Registration 필드 점검 · 빈 상태 onboarding 안내"), + ], +) + +# Slide 9 — 감사합니다 +build_closing_slide(prs) + +prs.save(str(OUT_PATH)) +print(f"Saved: {OUT_PATH}") +print(f"Slides: {len(prs.slides)}")