VitalRecorder – All Versions
You can browse all available versions by OS and download any version directly.
Total downloads since Feb 2017: 179,896
| Version | Date | Changes | |
|---|---|---|---|
| 1.18.45 | 2026-06-16 | 1.18.45 Fixed: Windows VR 에서 사용자가 외부에서 vr.conf 를 멀티베드 설정으로 교체 후 VR 을 재실행하면, 첫 실행에서는 멀티탭이 정상 생성되지만 다음 실행에서 모든 탭이 사라지던 문제. 원인은 VRApp.cpp:1110 의 VRCODE 미설정 분기 — 새 vr.conf 가 VRCODE 라인을 포함하지 않으면 load_settings() 가 신규 VRCODE 를 issue_code() 로 발급하고 즉시 save_settings() 를 호출하는데, 이 시점은 load_settings() 가 파싱한 베드들이 로컬 newbeds 벡터에만 있고 아직 m_pdisps 로 옮겨지기 전 (set_beds(newbeds) 는 initialize() 가 load_settings 반환 후 라인 1328 에서 호출). 결과: save_settings() 가 빈 m_pdisps 를 iterate 하며 vr.conf 를 글로벌 설정만으로 덮어써 모든 [BED/...] 섹션이 디스크에서 사라짐. 첫 실행은 메모리의 newbeds 로 UI 멀티탭이 그려져 정상으로 보이지만 (사용자가 "멀티탭은 정상적으로 생성되지만" 으로 표현), VR 종료/재실행 시 디스크 conf 에는 BED 섹션이 없으므로 다음 load_settings 가 빈 베드 리스트를 반환 → 탭 전부 사라짐. 수정: VRApp.h 에 m_vrcode_newly_issued bool 플래그 추가, load_settings 의 즉시 save 를 플래그 set 만 으로 교체, initialize() 의 set_beds(newbeds) 직후 (m_pdisps 가 채워진 시점) 플래그가 켜져 있으면 한 번만 save_settings() 호출 → BED 섹션이 정상 직렬화됨. Linux/Pi 분기 (m_serial_number 가 채워져 있는 경우) 는 원래도 save 안 했으므로 영향 없음, VRCODE 가 이미 conf 에 있는 모든 기존 deployment 도 분기 미진입으로 0-impact. m_conf_from_stdin / m_bDebug 모드는 save_settings 내부에서 이미 early return 이라 그대로 안전. MFC + Qt 빌드 모두 통과 (이번 변경 관련 0 warning). | |
| 1.18.44 | 2026-06-12 | 1.18.44: vr.conf FHIR=1 모드 추가 (자체 FHIR 수신서버 대상 실시간 푸시) + VS 2026 / 새 OpenSSL 인스톨러 빌드 환경 호환 shim. (1) sendweb_thread_func 의 기존 HL7/JSON 양분 분기 (VRApp.cpp:2466) 옆에 bFHIR 분기 추가. 1초 tick 마다 한 vrcode 의 모든 방 Observation 을 하나의 FHIR R4 collection Bundle 로 묶어 기존 WSS 채널로 push (gzip + WSSClient 인프라 그대로 재사용). MLLP 같은 신규 transport 안 도입 — FHIR R5 Subscription 의 websocket channel type 과 동형이라 표준 부합. (2) DISPLAY::get_fhir + TRACK::get_fhir 신규. v2 (vitaldb-fhir-v2) 와 동일한 reference-only 패턴 (Patient.id = m_patient_id, Encounter.id = vrcode-bedname-startsec, Observation.subject/encounter = relative reference) + hybrid keyframe: 첫 tick / m_patient_id 변경 / get_start_time() 변경 / 5분 경과 중 하나라도 발생 시 다음 tick Bundle 에 Patient + Encounter resource 를 inline. 그 외 tick 은 Observation 만. 수신서버가 도중에 새로 connect 해도 최대 5분 안에 자동 동기화 (keyframe heartbeat). DISPLAY 에 m_fhir_pt_sent_at/m_fhir_pt_last_id/m_fhir_enc_last_start 3개 멤버 추가 (m_setting_sent 패턴 그대로 per-display). (3) Observation 인코딩: NUM 은 effectiveDateTime + valueQuantity 각 데이터 포인트당 한 entry, WAV 은 effectivePeriod + valueSampledData (period=1000/srate ms, factor=1, origin=0, data=공백구분 floats) 한 entry. CO2/AWP wav 는 기존 get_json 처럼 25Hz 다운샘플 유지. NUM 은 m_montype 기반 LOINC 매핑 15개 등록 (ECG_HR/PLETH_HR=8867-4, PLETH_SPO2=59408-5, NIBP/IABP SBP/DBP/MBP=8480-6/8462-4/8478-0, BT=8310-5, RR=9279-1, etCO2=19891-1, CVP=8556-0, FETAL_HR=11627-3) + VR 자체 코드 시스템 (https://vitaldb.net/fhir/CodeSystem/track, code = dname/tname) 항상 동반. m_patient_id 미설정 (PATIENT_ID_UNSET) 시 anon-vrcode-bedname identifier 로 fallback. (4) Bundle wrapper: VRApp 가 방별 entries 를 콤마로 합쳐 {resourceType:Bundle, type:collection, timestamp:iso8601Z, entry:[...]} 로 wrap, 기존 gzip → WSS pipeline 동일. ISO 8601 UTC 헬퍼는 std::gmtime_s/gmtime_r 인라인. FHIR id 안전화 (A-Za-z0-9-.) 64자 제한 lambda 각 함수에 inline. (5) 빌드 환경 호환성: VRQt/CMakeLists.txt 에 _SILENCE_EXPERIMENTAL_COROUTINE_DEPRECATION_WARNINGS 추가 — VS 2026 (MSVC 14.51+) 의 STL 이 <experimental/coroutine> deprecation 을 warning → hard static_assert 로 바꾼 것이 cppwinrt 의 winrt::* (Serial.cpp 의 Bluetooth LE) 를 끌어오는 모든 TU 에서 컴파일 실패 시켜서, build_mfc.py 가 이미 CL env 로 주입하던 것과 동치 shim 을 Qt 쪽에도. (6) VRQt/CMakeLists.txt 의 OpenSSL link 경로 시프트. 새 OpenSSL 인스톨러가 libssl_static.lib / libcrypto_static.lib 를 lib/VC/x64/{MT,MTd}/ 에 두고 v1.x 의 libssl64MT.lib / libcrypto64MT.lib 네이밍과 lib/VC/static 경로를 깬다. build_mfc.py 의 %LOCALAPPDATA%/openssl-compat 패턴 (옛 이름으로 복사한 사본 폴더) 을 그대로 따라 CMakeLists 도 그 폴더가 있으면 우선, 없으면 옛 lib/VC/static 으로 fallback. 부트스트랩 스크립트는 build_mfc.py 의 docstring 참조 (한 줄). MFC + Qt + RPi + Ubuntu CLI + AppImage 빌드 모두 통과. 동작 영향: vr.conf 에 FHIR=1 추가 안 한 기존 deployment 는 sendweb 가 종전 JSON 모드 그대로 (HL7=1 만 분기보다 우선) — 0-impact migration. | |
| 1.18.43 | 2026-05-21 | 1.18.43: 멀티베드 console (PACU 10베드 Pi) syslog noise 80,500/hr → ~1,400/hr (-98.3%), cpu_usage 측정 1.16.12 (9f26e36) 이후 8년치 영구 -1 버그 수정, 멀티베드 환경 베드 식별용 [bedname / devicename] 로그 prefix 도입. 동기는 PACU production Pi (1.18.40) 4일치 syslog 분석 — 1.24M 라인 중 vr 라인 836K, idle 8시간 평균 시간당 80,500 라인 (베드 10 × 1초마다 "Waiting for next patient" × syslog 2x 중복). (1) VRApp.cpp:2696-2710 timer_thread_func 의 cpu usage 계산이 `if (totalcpu && m_cpu_total_last && totalcpu > m_cpu_total_last)` 가드 안에서만 m_cpu_total_last 갱신해 첫 호출 시 m_cpu_total_last=0 → else 분기 → -1 → m_cpu_total_last 갱신 안 됨 → 영원히 false → 영원히 -1 데드락. PACU 1,048 샘플 100% -1 실측 확인. m_cpu_total_last/m_cpu_used_last 갱신을 if 밖으로 빼서 첫 호출만 baseline 으로 -1, 두 번째 (60s 후) 부터 정상 측정. /proc/stat 의 iowait/irq/softirq 까지 7개 필드 fscanf 로 정확도 ±5% 개선. 부수: 같은 함수의 cpu_temp 가 `temp / 1000` int 나눗셈으로 소수점 절단되어 PACU 측정값이 정수 50/51/...,/58 9종만 출력 (millidegree 정밀도 손실) → `temp / 1000.0f` 로 fix. ram 계산은 `(totalram + totalswap) * mem_unit` 결과에 다시 mem_unit 곱하던 차원 혼용 (Linux 가 mem_unit=1 이라 우연히 정상 동작했지만 dimensionally wrong) → `(units1 + units2) * mem_unit` 로 정정 + underflow 가드. (2) DISPLAY::log(string/printf) + DEVICE::log(string/printf) 멤버 추가. DISPLAY::log 는 `[bedname] msg`, DEVICE::log 는 m_pdisp 위임 없이 직접 `[bedname / devicename] msg` 한 줄 prefix (nested `[bed] [dev]` 보다 가독성 우선). m_pdisp 또는 bedname null 케이스 safe fallback. (3) show_msg 의 console path TRACE 를 log() 로 교체 → "Waiting for next patient" 자동 [bedname] prefix. ADT patient id unset 도 log() 로. (4) 이미 수동으로 get_bedname() 을 인자로 넘기던 8군데 (DISPLAY ptcon_thread_func / add_trk / add_dev / del_dev / cut-recording, Device add_rec 콜백, FILT stop, VRApp add_tab/del_tab) 를 log() 로 전환 — 이중 prefix 방지 + 일관성. Serial::reading_thread / tcp_thread / open_socket waiting / timeout / interrupted / got-client 6군데 DEVICE::log() 전환 → `[bedname / Intellivue]` 등 자동 prefix, 멀티탭 환경에서 어느 베드 어느 device 출처인지 즉시 식별. (5) wss 재시도 폭주 throttle. WSSClient 에 m_verbose (debug step 로그 게이트) + m_dt_last_err_log (60s window) 추가. connect() 내부 step-by-step TRACE 4개 ("connecting" / "connect error" / "connected") 는 m_verbose 가드, 최종 "wss connect error" 는 60s window throttle (첫 줄 즉시, 그 다음 60s 1회). connect 성공 path 에서 throttle reset 으로 다음 disconnect → 첫 에러 즉시 로깅. sendweb_thread_func 의 "connecting websocket server" 호출자 라인도 같은 60s window, m_bDebug 면 verbose 활성화. PACU idle 8h 측정 7,024/hr (4종 × 1,756) → 약 60/hr (-99%). (6) "Waiting for next patient" / "ADT patient id unset" 의 60s throttle 자체는 feature/wav-mem-retention 브랜치 ptcon_thread_func 재구성 (b75928f 시리즈) 에서 이미 들어가 있어 이 릴리즈에 자동 포함. 종합 영향: idle 시간당 syslog 라인 80,500 → ~1,400 (-98.3%), active 시간당 14,900 → ~700 (-95%). 진단 측면: cpu_usage 가 부활하면서 웹모니터링 json 의 cpu_usage 필드도 한 번도 안 채워지던 게 정상 전송 (VRApp.cpp:2499 의 `if (m_cpu_usage > 0)` 가드가 영원히 false 였음). 별건: syslog 라인 2× 중복은 application 측이 아니라 rsyslog imuxsock + imjournal + journald.ForwardToSyslog=yes 의 Debian Bookworm 전형 misconfig — admin 측 fix (rsyslog.conf 에서 imjournal 주석 처리 + restart) 로 추가 50% 감소 가능 (별도 문서). MFC + Qt + Pi (RPI64) + Ubuntu CLI 빌드 모두 통과. | |
| 1.18.41 | 2026-05-13 | 1.18.41 Hotfix: TCP-server protocol-initiator device (Intellivue/S5/Datex/Hamilton/MPS/Agilia/IAP) 가 open() 직후 보내는 첫 패킷이 wire 에 안 나가던 회귀. 1.18.34 의 PortRouter refactor 가 Serial::open_socket() 의 8초 handoff blocking 을 제거하고 비동기 모델로 전환했는데, protocol-initiator 의 open() 코드가 m_sock=INVALID 상태에서 write 를 시도해 silent fail (Linux 는 m_fd=0 이라 false 반환). Intellivue 케이스 production journald 의 Pi → ESP TX 700K~3M bytes 는 monitor 측 abort 로 늦게 트리거된 AB_SPDU_SI recovery assoc_req 후 request_thread 의 정상 polling 트래픽이지만 일부 베드 (abort 없는 monitor) 는 recovery 도 안 되어 영구 silent (RX 300 bytes). 수정 방향: open() 의 옛 contract ("return 시점에 통신 가능") 복구. (1) Serial::open_socket() TCP-server 분기가 PortRouter::subscribe 후 m_sock_cv 로 첫 client handoff 까지 block (timeout = device read_timeout, 기본 30s) — 옛 모델 그대로. lock_and_open 이 false 면 다음 tick 에서 retry. close 신호로 abort 가능. (2) Serial::close() 는 PortRouter::unsubscribe 안 함 — subscribe 는 device 생애 동안 sticky 라 read_timeout 으로 인한 close→re-open 사이클 동안 listen socket 이 유지되어 1.18.29/1.18.34 의 anti-churn 이익 보존. unsubscribe 는 ~Serial() 에서만. (3) Per-device lifecycle thread (DEVICE::m_thread_restart): 각 device 가 자기 open/close/timeout 재시작을 별도 thread 에서 관리. 옛 모델의 DISPLAY::bed_manager 가 베드의 모든 device 를 sequential iterate 하던 구조에선 한 device 의 blocking open() 이 같은 베드의 다른 device 의 lifecycle 을 차단했는데, per-device thread 로 분리하여 멀티 device 베드도 병렬 진행. add_dev 에서 start_lifecycle, del_dev / ~DISPLAY 에서 stop_lifecycle. (4) Serial::tcp_thread_func 단순화 — outer m_sock_cv wait 패턴 (1.18.34/1.18.39 가 추가했던 것) 제거. open_socket 이 m_sock valid 보장하므로 reader thread 시작 시점에 simple inner recv loop 만. accept_handoff 의 replace (zombie cleanup) 케이스는 recv error 후 m_sock 변경 확인 + retry 로 처리. (5) reading_thread_func 의 `else if (m_sock != INVALID_SOCKET) tcp_thread_func();` 가드 복원 (1.18.39 가 제거). (6) Serial::write 의 silent-fail 케이스에 WARN trace 추가 — 미래 동종 회귀 즉시 노출. (7) PortRouter::subscribe 가 같은 (port, type) 에서 같은 IP filter 또는 둘 이상 catch-all 발견 시 reject (config 실수 원천 차단, 옛 WARN-only 동작 강화). (8) DISPLAY::bed_manager_thread_func 의 restart 블록 제거 — ptcon + adt 만 담당. "Waiting for next patient" TRACE 가 Linux/console 에서 1초 → 60초마다 throttle (별개 journald 부풀림 fix). 영향 범위: Intellivue / S5 / Datex / Hamilton / MPS / Agilia / IAP TCP-server 모드 베드 전부. 1.18.34 이후 우회 방법은 race-win 케이스 (VRN 이 PortRouter::subscribe 직후 connect) 외엔 없었음. MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.40 | 2026-05-12 | Hotfix: Drager Medibus 프로토콜 사용 베드에서 1.15.11 이후 vr.service 가 SIGSEGV 로 무한 재시작하던 문제. 1.15.10 (a8c7b2a) 의 "Sampling rate estimation" 리팩터링이 m_ptrk_awp/awf/co2 트랙을 add_trks() 에서의 eager 생성 (default srate=62.5Hz) 에서 realtime data 100 샘플 모인 후 lazy 생성으로 바꿨는데, Medibus 핸드셰이크 순서 (0x51 ICC → 0x52 DeviceID → 0x53 RealtimeConfig 응답 → 0x54 → realtime data 시작) 상 0x53 응답 핸들러 (Drager.cpp:295-307) 가 트랙들이 아직 nullptr 인 시점에 `ptrk->m_srate = 1000000.0/interval` 로 NULL 역참조 → 즉시 SEGV. 그 베드의 vr.service 가 systemd Restart=on-failure 로 재시작 → 다시 connect → 동일 0x53 패킷 받고 동일 SEGV → 무한 루프 (journald 로그상 restart counter 61 까지 누적, code=killed status=11/SEGV). 1.15.9 까진 트랙이 add_trks() 에서 생성되어 0x53 도착 시 항상 non-NULL 이라 안전했음. 수정: (a) add_trks() 에서 m_ptrk_awp/awf/co2 eager 생성 복원 (srate=62.5Hz default) — 0x53 는 ptrk->m_srate 만 갱신 (트랙 재생성 X). (b) on_received() 의 lazy creation + packet-timing srate 추정 블록 제거 — 0x53 가 권위 있는 srate 소스이고 packet 타이밍 기반 추정은 network jitter 에 약해 불안정. (c) 0x53 핸들러에 `if (interval > 0)` guard 추가 — 페이로드 깨졌을 때 div-by-zero / inf srate 방지. 영향 범위: Drager Primus / Apollo / Perseus / Fabius 등 Medibus 사용 마취기 전부. 우회 방법은 1.15.9 다운그레이드 외엔 없었음 (그 베드의 모든 데이터 유실 + 환자 모니터링 불가). MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.39 | 2026-05-08 | Fixed: PortRouter (TCP server) 모드에서 reader thread 가 startup 시점에 죽어 client 데이터를 영구히 못 받던 문제. 1.18.34 (9bd252f) 의 PortRouter refactor 가 m_sock 세팅을 dispatch 시점으로 옮겼는데 reading_thread_func (Serial.cpp:354) 의 가드 `else if (m_sock != INVALID_SOCKET) tcp_thread_func();` 는 옛 모델 (open 시점 이미 connect 완료) 가정 그대로라 — 시작 직후 m_sock=INVALID 면 tcp_thread_func 진입 안 하고 reader thread 즉시 종료. 이후 VRN 이 connect → PortRouter::dispatch → accept_handoff 가 m_sock 채우고 m_sock_cv.notify_all() → 그러나 wait 중인 reader 가 없음 (이미 죽음) → kernel recv buffer 에만 데이터 적재. 증상은 ss -tn state established 의 Recv-Q 가 0 이 아닌 값 (수백 bytes) 으로 누적, 베드 화면에는 데이터 안 들어옴. 그 베드의 VRN 이 Serial::open() 의 PortRouter::subscribe 직후~reader thread spawn 사이의 짧은 윈도우 안에 connect 한 경우만 우연히 정상 동작 (race-win). 수정: 가드 제거 — TCP 분기에 항상 진입. tcp_thread_func 자체에 이미 m_sock_cv outer-wait 루프가 있어 m_sock 이 INVALID 인 동안 dispatch 가 깨워줄 때까지 안전하게 대기. Pi 핫스팟에 VRN 여러 대 (e.g. 10.42.0.21~25) 를 같은 (4343, Philips:Intellivue) 키로 묶고 IP filter 로 라우팅하는 시나리오에서 가장 자주 노출. Added: 진단 로그 보강 — PortRouter::accept_loop 의 accept 이벤트, dispatch 의 라우팅 결정 (ip_specific/catch_all subs 수, 어느 dev 가 받았는지), subscribe/unsubscribe 의 entry 생성/append/destroy, reading_thread / tcp_thread 의 시작·wait·wake 라이프사이클 — 이전엔 모두 m_bDebug 게이트 안에 있어서 production journald 에서 안 보였는데, 이제 항상 출력 (이번 같은 dispatch routing 문제 진단을 production 에서 바로 가능). MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.38 | 2026-05-08 | Fixed: 웹모니터링 우클릭 → 디바이스 세팅 (websocket edit_bed 명령) 으로 베드의 device/filter 를 변경할 때 베드 이름이 매번 "_2" suffix 로 자동 리네임되어 vr.conf (Pi: /data/vr.conf) 에 잘못된 이름으로 저장되던 문제. 원인은 1.18.22 (cda8aa5) 에서 add_bed 에 추가된 bedname dedup ("최후 방어선" 으로 forward_frame auto-create / 수동 편집된 conf 의 중복 이름 처리용). edit_bed 핸들러는 옛 pdel 이 m_pdisps 에 그대로 있는 상태에서 같은 bedname 으로 new DISPLAY 를 add_bed 하고 그 다음 del_bed(pdel) 하는 순서였는데, add_bed 가 dup 감지해 새 pdisp 를 bedname_2 로 자동 리네임 → save_settings 가 [BED/bedname_2] 로 직렬화 → 사용자 입장에선 "설정 적용 안됨" 으로 보였다. 추가로 옛/새 DISPLAY 가 잠깐 m_pdisps 에 공존하면서 같은 device 포트를 동시에 들고 있으려 해 로그가 dup 으로 찍히는 부수 증상도 있었음. 수정: del_bed(pdel) 를 add_bed(pdisp) 보다 앞으로 이동 — 옛 베드의 device 포트가 깨끗이 release 된 뒤 새 pdisp 가 같은 포트를 reopen, dedup 발동 안 함. 다른 베드의 recording 은 영향 없음 (인메모리 hot swap 설계 유지). 부수: edit_bed 핸들러의 데드 코드 (`break` 뒤의 unreachable olddevs populate 루프 + `if (olddevs.find(name) == olddevs.end())` 항상-true 래퍼) 정리. edit_conf 와 save_settings 는 손대지 않음. MFC + Qt + Pi (RPI64) 빌드 모두 통과. | |
| 1.18.37 | 2026-05-08 | Refactored: 필터 다이얼로그의 python 런타임 — pyvital → openvital 0.3.0 로 교체 + 동봉 python.zip 슬림화. 핵심 동기 셋: (1) pyvital 0.6.0 이 tensorflow+torch+keras 를 hard-dep 으로 끌어들여 PyPI upgrade 가 사실상 깨짐, (2) 기존 zip 121 MB 안에 botocore/aiobotocore/s3fs/pyarrow/pandas/aiohttp 등 vitaldb 클라우드 업로드용 deps 가 ~250 MB unpacked 차지 — 필터 서버는 한 번도 쓴 적 없는 dead weight, (3) sanic 25.x 의 multi-process worker 가 openvital __main__.py 를 fork 후 재import 하면서 worker 가 module-top app instance 를 못 찾아 "Sanic app name not found" 로 죽음 — 단순 endpoint 2개 로컬호스트 서버에 async stack 자체가 과함. 해결: openvital 0.3.0 (commit b6f445b) 가 sanic 을 stdlib http.server (BaseHTTPRequestHandler + HTTPServer) 로 50 LOC 재작성 — wire protocol (GET / 필터목록 JSON, POST /<modname> gzip 본문) 동일해 VR 클라이언트 변경 0줄. 단일 스레드로 기존 sanic event loop semantics (cfgs/default_cfgs lock-free 변경) 보존. build_python_zip.py (NEW) 가 Python 3.11.9 embed + numpy + openecg + openvital (local checkout 우선, fallback PyPI) 만으로 27 MB zip 빌드 — 기존 121 MB 대비 78% 감소. ML 필터 (sv_dlapco/abp_hpi/ecg_classifier/ecg_beat_noise_detector) 는 [Hybrid 모델] 사용자가 Add filter 다이얼로그의 "Install ML filters" 버튼 누를 때 silent pip install openvital[all] (cmd 창 미노출 — VRApp::install_pip_package + run_pip_silent 이 자체 progress 다이얼로그에 stdout heartbeat 흘림). 버튼 라벨은 "Upgrade pyvital" → "Install ML filters" 로 의도 명시. openvital __main__.py 가 missing extras 를 graceful skip 하므로 base 환경에서도 11개 필터 (ECG QRS detector, HRV, MTWA, annotator, eeg_fft, nirs_cox, pkpd_3comp, pleth_dpop/ptt/pvi, resp_compliance) 즉시 사용 가능. Migration: 기존 사용자의 user_dir/python 폴더는 pyvital + 옛 deps 가 그대로 남아있고 vitaldb.net/python.zip 만 새로 올리면 (a) 기존 폴더 삭제 후 install_python 으로 새 zip 받으면 깔끔, (b) 폴더 유지 시 server 가 openvital 못 찾아 필터 다이얼로그 에러 → release note 에 명시 필요. MFC + Qt 양쪽 코드: VRGui.rc 의 IDC_UPGRADE 버튼 라벨 + DlgAddFilter.cpp 의 dist-info prefix 매칭 (pyvital- 8자 → openvital- 10자) + QtDlgAddFilter.cpp 도 동일 변경 + onUpgrade 가 cmd /k QProcess::startDetached 대신 theApp.install_pip_package("openvital[all]") 호출 (Linux Qt 빌드는 #ifdef _WIN32 가드). VRApp.cpp:318 의 python -m pyvital → -m openvital. install_pip_package 는 anonymous namespace 의 is_safe_pkg_spec 화이트리스트 검증 + run_pip_silent (CreateProcessA + CREATE_NO_WINDOW + 자식 stdout pipe) + CDlgProgress / QtDlgProgress 자체 progress UI. 빌드 검증: python -m openvital 이 GET / 로 11 필터 반환, sanic import 부재 확인. zip 27.5 MB. | |
| 1.18.36 | 2026-05-07 | Fixed: 3-파티션 레이아웃 (boot/rootfs/data) 에서 websocket edit_conf / update 명령이 read-only fs 로 실패하던 문제. vr.conf 는 /data 폴더가 있으면 /data/vr.conf 로 자동 정착 — get_conf_path() 가 write target 으로 결정, load_settings() 는 primary 가 없으면 legacy /boot/firmware/vr.conf 또는 /boot/vr.conf 에서 fallback read 후 다음 save 부터 primary 로 자동 이전 (마이그레이션 step 없음, legacy 파일은 read-only fs 라 무해). binary update (upgrade_now) 는 RAII BootRwGuard 가 dirname(module_path) 를 잠시 rw remount, scope 종료 시 sync() + MS_REMOUNT|MS_RDONLY 로 자동 ro 복귀 — vfat 노출 윈도우 최소화 + exception/return 어디서든 복구 보장. statvfs ST_RDONLY 검사로 이미 rw 인 fs (x86 dev) 에서는 no-op, non-Linux (macOS) 는 stub 으로 통과. save_settings() 의 silent EROFS 실패가 TRACE 로 가시화 (이전엔 무시되어 conf 수정 안 먹는 원인 추적 불가). 부수: PortRouter.cpp 가 commit 9bd252f 이후 CMakeLists 의 RPI sources 목록에서 누락되어 Pi 빌드 link 에러 — 추가. | |
| 1.18.35 | 2026-05-01 | Added: alarm parsing for Mindray HL7 (eGateway ORU^R40) and Nihon Kohden (NealTime HL7GW + ORF, BSM serial D-port, EGA UDP) - emits ALARM_STATUS / ALARM_MESSAGE / ALARM_PRIORITY tracks (same 3-track schema already used by Philips IntelliVue, GE Solar/Dash, GE/Datex S5); type info preserved via [T]/[A]/[ARR] message prefixes; Mindray facet 1/5/6/7 walker with 92-entry MDC+MNDRY alarm code lookup; NK HL7GW parses OBR-4=EVENT with arrhythmia/technical disambiguation by OBX-5; NK BSM serial decodes per-parameter * flags (edge-triggered to avoid 1Hz flooding) plus 32-bit Table 9 arrhythmia bitmap, D19 alarm-suspend nibble, and the VPC CODE byte; NK EGA UDP extracts Priority + Tech Alarm + Arrhythmia from JSON Vital Sign packets with edge-trigger cache for start/end inference; ACK^R40 reply added for Mindray alert messages; simulators gained periodic alarm cycling for end-to-end smoke testing | |
| 1.18.34 | 2026-04-27 | Added: Linux Desktop Qt GUI build (VRQt) - first GUI build for Linux distributed as a self-contained AppImage (~32MB, Qt6 runtime + libGL/libEGL/libGLX/libOpenGL/libGLESv2/libGLdispatch bundled inside) so users on minimal Ubuntu/Debian/Fedora can run it without installing Qt or GL system packages; tested on AWS clean Ubuntu 22.04 cloud image; build via build_ubuntu_appimage.py which is now invoked by deploy.py; Fixed: Linux Qt right-side device/filter panels rendered with white background below cards because the inner listWidget did not autoFillBackground from parent palette on Linux Qt (Windows/macOS implicitly inherit, X11/Wayland do not); explicit stylesheet on listWidget; Added: Linux installation section in user manuals (EN/KO/ZH/ES) covering AppImage chmod+run flow and dialout group note for serial/USB device access | |
| 1.18.33 | 2026-04-25 | Fixed: Demo device never started since 1.18.11 (bed_manager skipped empty port_name as passive but Demo has no port and still needs lock_and_open); Fixed: Qt fit-to-window button rendered at top-left (0,0) instead of right-aligned in bottom nav bar; Fixed: Qt crash when closing tab / deleting device / deleting filter - paint dereferenced freed pointer before panel timer rebuilt items (added MFC-style stale-pointer guard to QtDeviceItem and QtFilterItem); Added: macOS DMG main window now shown on launch (restoreWindowPos had no Mac/Linux branch); Added: macOS Homebrew dylibs (openssl) bundled in Contents/Frameworks; Added: macOS .app bundle now notarized + stapled (drag-to-Applications no longer needs xattr -cr on first launch); Changed: Qt MSI ~1MB smaller (dropped unused iconengines and imageformats plugins) | |
| 1.18.32 | 2026-04-23 | Fixed: same-port multi-client TCP - primary now runs a continuous accept loop and hands off each connection to the matching sub by IP filter (previously second connection got rejected/listened closed); Added: @IP and #keyword port filters are now mutually exclusive per bed (IP wins, keyword dropped with WARN); Added: WARN log when two beds on the same port share an identical IP filter; Added: catch-all primary keeps its single connection and rejects extras (preserves broadcast mode) | |
| 1.18.31 | 2026-04-22 | Added: drug slot shows DOSE_AMOUNT (mg etc) in preference to VOL (mL) when available; Added: DOSE_RATE / DOSE_AMOUNT montypes bound to BBraun tracks for monitor view; Added: HL7 MDC_DOSE_DRUG_DELIV_TOTAL unit picked up dynamically from UCUM | |
| 1.18.30 | 2026-04-21 | Changed: monitor view pump layout - 8 slots with CE or RATE (CE-less pumps show infused volume as small annotation); Reverted: BBraun minimal=1 (1.18.29) - was dropping data from file, monitor view redesign handles display clutter instead | |
| 1.18.29 | 2026-04-21 | Fixed: BBraun multi-rack auto-tab data drop, primary TCP churn, save_settings lock race, TCP reader spin on peer close; Added: BBraun minimal=1 option (display only drug name / rate / volume) | |
| 1.18.28 | 2026-04-20 | Fixed: vr.conf on Pi/Linux now looked up next to executable (supports /boot/firmware); deploy.py --store auto-submits MSIX to Microsoft Store | |
| 1.18.27 | 2026-04-18 | Fixed: vital file periodic flush (5000s→5s bug), Fit-to-Window icon redesigned to match navigation button style | |
| 1.18.26 | 2026-04-18 | Fixed: periodic .vital file flush interval was 5000 seconds instead of 5 (unit-bug since comment said seconds but value was milliseconds). Data now actually reaches disk every 5 s during recording instead of only on close. | |
| 1.18.25 | 2026-04-18 | Fixed: BBraun HL7 rec_timeout raised 10s→60s to prevent primary churn during DoseLink R42→R01 phase transition and long idle periods | |
| 1.18.24 | 2026-04-18 | Fixed: GUI silently exits when another recorder running (now falls back to viewer mode), .vital file association written to HKCU (no admin required, auto-updates exe path on every run) | |
| 1.18.23 | 2026-04-18 | Fixed: atof decimal-separator bug on non-English Windows locales (rates <1.0 recorded as 0 in Norwegian/German/French etc.), BBraun HL7 pump limit raised from 8 to 16 | |
| 1.18.22 | 2026-04-18 | Fixed: multi-bed TCP port bind race on restart (Mindray/BBraun HL7 auto-reconnect without manual Add device) | |
| 1.18.21 | 2026-04-18 | Fixed: port name filter (#keyword@ip) lost on save, BBraun HL7 VMD-block parsing with single dt, Fit-to-Window button sizing (MFC) and added to Qt | |
| 1.18.20 | 2026-04-15 | BBraun: comprehensive protocol parsing (dose rate, infusion time, syringe, weight, drug amounts, delivery status) | |
| 1.18.19 | 2026-04-13 | Fixed: BBraun HL7 multi-pump identification (rack serial filtering), multi-bed forwarding, port filter parsing | |
| 1.18.18 | 2026-04-10 | Added: GE alarm limits, S5 alarm/ext3/ext1 parsing | |
| 1.18.17 | 2026-04-04 | Changed: TRACE debug-only guard, show_msg for file errors, deploy sequential builds | |
| 1.18.16 | 2026-04-04 | Added: TCP port filtering (#keyword@ip), frame forwarding for multi-bed. Fixed: --debug conf file mistaken as vital file, device type ambiguity in forwarding | |
| 1.18.15 | 2026-04-04 | Changed: Port to Port Name, keyword filter AND/OR (#kw1 kw2#kw3), IP postfix matching (@10.1), MEKICS SerialFramed | |
| 1.18.14 | 2026-04-03 | Added: TCP port filtering (#keyword@ip), Fixed: devtypes not sent on boot | |
| 1.18.13 | 2026-04-02 | Changed: Covidien company name to Medtronic (BIS, INVOS) | |
| 1.18.12 | 2026-04-02 | Bug Fixed: NihonKohden EGA SpO2 waveform not displayed (channel name mapping) | |
| 1.18.11 | 2026-03-31 | Added: Mindray HL7 multi-bed separation via PV1, auto-tab creation for EGA/Mindray | |
| 1.18.10 | 2026-03-31 | Added: HL7 ZBR segment now includes ver, os, arch, dgmt | |
| 1.18.8 | 2026-03-25 | Added: --demo mode for console operation with demo signals | |
| 1.18.7 | 2026-03-25 | Added: --console mode for headless operation on Windows | |
| 1.18.6 | 2026-03-25 | Added: Mindray eGateway HL7 protocol (IHE PCD-01, HL7 v2.6 over MLLP, waveform + numeric + infusion pump) | |
| 1.18.4 | 2026-03-24 | Added: BBraun SpaceCom HL7 protocol (HL7 v2.6 over MLLP, TCP server mode) | |
| 1.18.3 | 2026-03-24 | Added: HL7 OBX-14 per-track dtstart, ZBR segment with dtcase/dtapp timestamps | |
| 1.18.2 | 2026-03-24 | Added: HL7 ZBR segment with dtcase (recording start) and dtapp (app start) timestamps | |
| 1.18.1 | 2026-03-23 | Fixed: HL7 OBX-3 format (code^device/track@srate), OBX-7 refrange (min^max), NA null sample gaps | |
| 1.17.6 | 2026-03-22 | Bug fixed: Resource ID conflicts WiX installer cleanup | |
| 1.17.5 | 2026-03-21 | Bug fixed: Vital packed file loading MFC device button icon padding | |
| 1.17.4 | 2026-03-19 | Bug fixed: NirsitON EEG 250Hz VRQt device minimize/rename | |
| 1.17.3 | 2026-03-18 | Bug fixed: BBraun protocol NirsitON protocol VRQt | |
| 1.17.2 | 2026-03-14 | Added: NirsitOn NDI protocol support. | |
| 1.17.1 | 2026-03-12 | Added: VRQt | |
| 1.16.13 | 2026-03-07 | Added: New Setup File with VRQt | |
| 1.16.12 | 2026-03-06 | Added: Vector Type Icons | |
| 1.16.10 | 2026-03-02 | Bug fixed: Autodetecting BBraun Stuffing feature. | |
| 1.16.8 | 2026-02-27 | Bug fixed: Masimo IAP protocol. | |
| 1.16.6 | 2026-02-13 | Added: Servo-u ventilator protocol | |
| 1.16.5 | 2026-02-09 | Bug Fixed: NihonKohden HL7GW Pleth waveform gain correction. | |
| 1.16.4 | 2026-01-20 | Bug Fixed: Serial communication. | |
| 1.16.3 | 2026-01-14 | Bug Fixed: Masimo IAP Protocol. | |
| 1.16.2 | 2026-01-03 | Added: BLE Support for Movesense devices on Raspberry Pi | |
| 1.16.1 | 2026-01-01 | Added: BLE Support for Movesense devices on Raspberry Pi and Linux versions. | |
| 1.16.0 | 2025-12-31 | Added: BLE Support for Movesense devices | |
| 1.15.16 | 2025-09-18 | Bug Fixed: Restoring last window position. | |
| 1.15.15 | 2025-09-05 | Added: CPU optimization Bug fixed: Masimo IAP protocol. | |
| 1.15.14 | 2025-09-04 | Added: CPU optimization | |
| 1.15.13 | 2025-09-04 | Bug Fixed: Masimo IAP Protocol. | |
| 1.15.12 | 2025-09-04 | Bug Fixed: Hardware handshake for Link+ connection. | |
| 1.15.11 | 2025-09-01 | Added: Recording alarm messages for Drager anesthesia machines | |
| 1.15.10 | 2025-07-14 | Bug Fixed: Sampling rate estimation in Medibus protocol. | |
| 1.15.9 | 2025-06-03 | Bug Fixed: EEG waveform labels from Philips monitors. | |
| 1.15.8 | 2025-05-26 | Added: EM_UPLOAD option to upload vital files to server immediately | |
| 1.15.7 | 2025-05-26 | Bug Fixed: Websocket connection error | |
| 1.15.6 | 2025-05-19 | Bug Fixed: S5 checksum error | |
| 1.15.5 | 2025-04-17 | Bug Fixed: saving the raw data | |
| 1.15.4 | 2025-04-15 | Added: Recording alarms from Philips monitor | |
| 1.15.3 | 2025-04-14 | Bug fixed: saving the raw data | |
| 1.15.2 | 2025-03-12 | Fixed: bug in opening file | |
| 1.15.1 | 2025-01-30 | Supporting for Fresenius Kabi Conox, Minor Bug fixes | |
| 1.14.13 | 2025-01-18 | Fixed bug in handling non-ascii filepath | |
| 1.14.12 | 2024-11-20 | Fixed: bug in 64bit ARM Architecture | |
| 1.14.11 | 2024-10-24 | Added: feature for updating to a specific version | |
| 1.14.10 | 2024-10-22 | Fixed: bug in json streamming | |
| 1.14.9 | 2024-10-17 | Added: montype for drug rates | |
| 1.14.6 | 2024-09-20 | Added: montype for drug rates | |
| 1.14.5 | 2024-09-13 | Added: auto cutting by any of hr or spo2 | |
| 1.14.4 | 2024-09-12 | Fixed: bug in serial port mapping | |
| 1.14.3 | 2024-09-10 | Added: temperature monitoring Fixed: bug in cpu usage calculation | |
| 1.14.2 | 2024-08-29 | Added: DI-245 protocol | |
| 1.14.1 | 2024-07-26 | Added: GE cardiac output parameters | |
| 1.14.0 | 2024-07-25 | Added: GE Canvas device | |
| 1.13.10 | 2024-07-17 | Fixed: NirsitOn protocol bug | |
| 1.13.9 | 2024-06-27 | Bug fix for file loading | |
| 1.13.8 | 2024-06-05 | Bug fix for file loading | |
| 1.13.7 | 2024-06-04 | Bug fix for file loading | |
| 1.13.6 | 2024-06-03 | Bug fix for the NirsitOn+ protocols with 32Hz | |
| 1.13.5 | 2024-05-30 | Added support for the NirsitOn+ protocols with 32Hz | |
| 1.13.4 | 2024-05-23 | Added fetal heart rate and uterine activity | |
| 1.13.3 | 2024-05-23 | Tested for BIS vista protocol | |
| 1.13.2 | 2024-04-26 | Support for BIS vista protocol | |
| 1.13.1 | 2024-04-26 | Support for BIS vista protocol | |
| 1.12.12 | 2024-04-09 | Deployment script updated | |
| 1.12.11 | 2024-04-06 | Deployment script updated | |
| 1.12.10 | 2024-02-25 | Deployment script updated | |
| 1.12.8.0 | 2024-02-25 | Added support for GE Coro fetal monitor | |
| 1.12.8 | 2024-02-25 | Added support for GE Coro fetal monitor | |
| 1.12.7.0 | 2024-02-24 | Added support for GE Coro fetal monitor | |
| 1.12.6.0 | 2024-01-05 | Minor bug fix | |
| 1.12.5.0 | 2023-12-22 | Minor bug fix | |
| 1.12.4.0 | 2023-12-22 | Minor bug fix Added support of Pleth(Left, Right) and Aortic pressure for the Intellivue protocol Added option for the cut by heart rate Added option for setting the waveform by its name - Intellivue: I, II, III, V, aVR, aVL, avF, MCL, MCL1, V1, V2, V3, V4, V5, V6, PLETH, ABP, ART, CVP, FAP, PAP, ICP, EEG, CO2, RESP, AWF, AWP - S5: ECG1, ECG2, EEGBIS, EEGENT, EEGENT400, IABP1, IABP2, IABP3, IABP4, IABP5, IABP6, IABP7, IABP8, EEG1, EEG2, PLETH, CO2, O2, N2O, AWP | |
| 1.12.1.0 | 2023-12-11 | Minor bug fixes Improvement of the Bx50 protocol Improvement of the NIHONKOHDEN protocol | |
| 1.12.0.0 | 2023-12-05 | Supported protocol for Drager B1x5M. | |
| 1.11.20.0 | 2023-11-07 | Supported protocol for Daiwha TCI pump. | |
| 1.11.19.0 | 2023-10-23 | Additional pleth waveforms for the Philips protocol Minor Bug fixes | |
| 1.11.18.0 | 2023-09-14 | Bug fix for EGA protocol Minor Bug fixes | |
| 1.11.17.0 | 2023-09-08 | Bug fix for EGA protocol | |
| 1.11.16.0 | 2023-08-30 | Bug fix for EGA protocol | |
| 1.11.15.0 | 2023-08-29 | Bug fix for EGA protocol | |
| 1.11.14.0 | 2023-08-29 | Bug fix for EGA protocol | |
| 1.11.13.0 | 2023-08-28 | Bug fix for EGA protocol | |
| 1.11.12.0 | 2023-08-08 | EGA protocol supported PulsioFlex protocol supported | |
| 1.11.11.0 | 2023-07-12 | Fixed bug for TOFCuff | |
| 1.11.10.0 | 2023-06-01 | Fixed bug for VitalConnect | |
| 1.11.9.0 | 2023-05-30 | Fixed bug for BUTTON | |
| 1.11.8.0 | 2023-05-27 | Fixed bug for MEKICS Fixed bug for remote update | |
| 1.11.7.0 | 2023-05-24 | Added support for NirsitOn+ | |
| 1.11.6.0 | 2023-05-23 | Added support for NirsitOn+ | |
| 1.11.5.0 | 2023-05-22 | Added support for NirsitOn+ | |
| 1.11.4.0 | 2023-05-22 | Added support for NirsitOn+ | |
| 1.11.3.0 | 2023-05-21 | Added support for SNUSensor | |
| 1.11.2.0 | 2023-05-16 | Added support for SNUSensor | |
| 1.11.1.0 | 2023-05-03 | Added support for TOFcuff | |
| 1.11.0.0 | 2023-03-29 | Added support for TOFcuff | |
| 1.10.21.0 | 2023-02-16 | Added support for TOFcuff | |
| 1.10.20.0 | 2023-02-05 | Added support for file cutting based on SpO2 | |
| 1.10.19.0 | 2023-01-12 | Added support for file cutting based on SpO2 | |
| 1.10.18.0 | 2022-12-16 | Added support for AU protocol | |
| 1.10.17.0 | 2022-12-16 | Added support for AU protocol | |
| 1.10.16.0 | 2022-12-14 | Added support for AU protocol | |
| 1.10.15.0 | 2022-12-12 | Added support for AU protocol | |
| 1.10.14.0 | 2022-12-08 | Added support for AU protocol | |
| 1.10.13.0 | 2022-12-07 | Added support for AU protocol | |
| 1.10.12.0 | 2022-12-05 | Added support for AU protocol | |
| 1.10.11.0 | 2022-12-05 | Added support for AU protocol | |
| 1.10.10.0 | 2022-12-02 | Added support for AU protocol | |
| 1.10.9.0 | 2022-12-01 | Fixed bug for Link+ protocol | |
| 1.10.8.0 | 2022-11-29 | Fixed bug for Servo-i Ventilator Fixed bug for Hamilton Ventilator | |
| 1.10.7.0 | 2022-11-08 | Improved support for Nihon kohden ADT | |
| 1.10.6.0 | 2022-11-04 | Improved support for Nihon kohden HL7GW | |
| 1.10.4.0 | 2022-11-02 | Hamiltonian ventilator supported | |
| 1.10.3.0 | 2022-10-21 | Hamiltonian ventilator supported | |
| 1.10.2.0 | 2022-10-14 | Hamiltonian ventilator supported | |
| 1.10.0.0 | 2022-09-15 | Minor bug fix Added input dialog for patient ID when intranet server is used | |
| 1.9.11.0 | 2022-07-29 | Minor bug fix Added input dialog for patient ID when intranet server is used | |
| 1.9.10.0 | 2022-06-26 | Minor bug fix Added input dialog for patient ID when intranet server is used | |
| 1.9.9.0 | 2022-06-03 | Minor bug fix Added input dialog for patient ID when intranet server is used | |
| 1.9.8.0 | 2022-05-17 | Minor bug fix VitalSync compatible with VitalDB Platform API | |
| 1.9.7.0 | 2022-03-25 | Display patient id on the title bar Support for barcode reader Minor bug fix | |
| 1.9.6.0 | 2022-03-25 | Additional Parameter (RPVI) for Masimo Root Bug fix for VitlaUtils | |
| 1.9.4.0 | 2022-03-10 | Batch running of filter on VitalUtils | |
| 1.9.3.0 | 2022-03-09 | Local filter server as default Python Installer | |
| 1.9.2.0 | 2022-02-17 | Added ABP montype to ClearSight | |
| 1.9.1.0 | 2022-02-16 | Supported MedibusX protocol | |
| 1.9.0.0 | 2022-02-14 | Supported LiDCO protocol | |
| 1.8.22.0 | 2022-02-10 | Added filter server running on localhost Moved VC setting dialog to the Setting dialog Fixed minor bugs | |
| 1.8.21.1 | 2022-02-07 | Fixed a bug with the Intellivue | |
| 1.8.21.0 | 2022-01-21 | Fixed a bug with the Intellivue | |
| 1.8.20.1 | 2022-01-15 | Fixed a bug with the Intellivue | |
| 1.8.20.0 | 2022-01-13 | Requesting O2 and N2O waves to the Bx50. Fixed a bug with the channel names of FIO2 and FIO2 of the Bx50. | |
| 1.8.19.5 | 2021-12-17 | Bug fix for Intellivue protorol | |
| 1.8.19.4 | 2021-12-09 | Bug fix for Intellivue protorol | |
| 1.8.19.0 | 2021-11-15 | Bug fix for Intellivue protorol | |
| 1.8.18.0 | 2021-10-09 | New Installer | |
| 1.8.17.2 | 2021-10-06 | New Installer |
| Version | Date | Changes | |
|---|---|---|---|
| 1.18.40 | 2026-05-12 | Hotfix: Drager Medibus 프로토콜 사용 베드에서 1.15.11 이후 vr.service 가 SIGSEGV 로 무한 재시작하던 문제. 1.15.10 (a8c7b2a) 의 "Sampling rate estimation" 리팩터링이 m_ptrk_awp/awf/co2 트랙을 add_trks() 에서의 eager 생성 (default srate=62.5Hz) 에서 realtime data 100 샘플 모인 후 lazy 생성으로 바꿨는데, Medibus 핸드셰이크 순서 (0x51 ICC → 0x52 DeviceID → 0x53 RealtimeConfig 응답 → 0x54 → realtime data 시작) 상 0x53 응답 핸들러 (Drager.cpp:295-307) 가 트랙들이 아직 nullptr 인 시점에 `ptrk->m_srate = 1000000.0/interval` 로 NULL 역참조 → 즉시 SEGV. 그 베드의 vr.service 가 systemd Restart=on-failure 로 재시작 → 다시 connect → 동일 0x53 패킷 받고 동일 SEGV → 무한 루프 (journald 로그상 restart counter 61 까지 누적, code=killed status=11/SEGV). 1.15.9 까진 트랙이 add_trks() 에서 생성되어 0x53 도착 시 항상 non-NULL 이라 안전했음. 수정: (a) add_trks() 에서 m_ptrk_awp/awf/co2 eager 생성 복원 (srate=62.5Hz default) — 0x53 는 ptrk->m_srate 만 갱신 (트랙 재생성 X). (b) on_received() 의 lazy creation + packet-timing srate 추정 블록 제거 — 0x53 가 권위 있는 srate 소스이고 packet 타이밍 기반 추정은 network jitter 에 약해 불안정. (c) 0x53 핸들러에 `if (interval > 0)` guard 추가 — 페이로드 깨졌을 때 div-by-zero / inf srate 방지. 영향 범위: Drager Primus / Apollo / Perseus / Fabius 등 Medibus 사용 마취기 전부. 우회 방법은 1.15.9 다운그레이드 외엔 없었음 (그 베드의 모든 데이터 유실 + 환자 모니터링 불가). MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.37 | 2026-05-08 | Refactored: 필터 다이얼로그의 python 런타임 — pyvital → openvital 0.3.0 로 교체 + 동봉 python.zip 슬림화. 핵심 동기 셋: (1) pyvital 0.6.0 이 tensorflow+torch+keras 를 hard-dep 으로 끌어들여 PyPI upgrade 가 사실상 깨짐, (2) 기존 zip 121 MB 안에 botocore/aiobotocore/s3fs/pyarrow/pandas/aiohttp 등 vitaldb 클라우드 업로드용 deps 가 ~250 MB unpacked 차지 — 필터 서버는 한 번도 쓴 적 없는 dead weight, (3) sanic 25.x 의 multi-process worker 가 openvital __main__.py 를 fork 후 재import 하면서 worker 가 module-top app instance 를 못 찾아 "Sanic app name not found" 로 죽음 — 단순 endpoint 2개 로컬호스트 서버에 async stack 자체가 과함. 해결: openvital 0.3.0 (commit b6f445b) 가 sanic 을 stdlib http.server (BaseHTTPRequestHandler + HTTPServer) 로 50 LOC 재작성 — wire protocol (GET / 필터목록 JSON, POST /<modname> gzip 본문) 동일해 VR 클라이언트 변경 0줄. 단일 스레드로 기존 sanic event loop semantics (cfgs/default_cfgs lock-free 변경) 보존. build_python_zip.py (NEW) 가 Python 3.11.9 embed + numpy + openecg + openvital (local checkout 우선, fallback PyPI) 만으로 27 MB zip 빌드 — 기존 121 MB 대비 78% 감소. ML 필터 (sv_dlapco/abp_hpi/ecg_classifier/ecg_beat_noise_detector) 는 [Hybrid 모델] 사용자가 Add filter 다이얼로그의 "Install ML filters" 버튼 누를 때 silent pip install openvital[all] (cmd 창 미노출 — VRApp::install_pip_package + run_pip_silent 이 자체 progress 다이얼로그에 stdout heartbeat 흘림). 버튼 라벨은 "Upgrade pyvital" → "Install ML filters" 로 의도 명시. openvital __main__.py 가 missing extras 를 graceful skip 하므로 base 환경에서도 11개 필터 (ECG QRS detector, HRV, MTWA, annotator, eeg_fft, nirs_cox, pkpd_3comp, pleth_dpop/ptt/pvi, resp_compliance) 즉시 사용 가능. Migration: 기존 사용자의 user_dir/python 폴더는 pyvital + 옛 deps 가 그대로 남아있고 vitaldb.net/python.zip 만 새로 올리면 (a) 기존 폴더 삭제 후 install_python 으로 새 zip 받으면 깔끔, (b) 폴더 유지 시 server 가 openvital 못 찾아 필터 다이얼로그 에러 → release note 에 명시 필요. MFC + Qt 양쪽 코드: VRGui.rc 의 IDC_UPGRADE 버튼 라벨 + DlgAddFilter.cpp 의 dist-info prefix 매칭 (pyvital- 8자 → openvital- 10자) + QtDlgAddFilter.cpp 도 동일 변경 + onUpgrade 가 cmd /k QProcess::startDetached 대신 theApp.install_pip_package("openvital[all]") 호출 (Linux Qt 빌드는 #ifdef _WIN32 가드). VRApp.cpp:318 의 python -m pyvital → -m openvital. install_pip_package 는 anonymous namespace 의 is_safe_pkg_spec 화이트리스트 검증 + run_pip_silent (CreateProcessA + CREATE_NO_WINDOW + 자식 stdout pipe) + CDlgProgress / QtDlgProgress 자체 progress UI. 빌드 검증: python -m openvital 이 GET / 로 11 필터 반환, sanic import 부재 확인. zip 27.5 MB. | |
| 1.18.33 | 2026-04-25 | Fixed: Demo device never started since 1.18.11 (bed_manager skipped empty port_name as passive but Demo has no port and still needs lock_and_open); Fixed: Qt fit-to-window button rendered at top-left (0,0) instead of right-aligned in bottom nav bar; Fixed: Qt crash when closing tab / deleting device / deleting filter - paint dereferenced freed pointer before panel timer rebuilt items (added MFC-style stale-pointer guard to QtDeviceItem and QtFilterItem); Added: macOS DMG main window now shown on launch (restoreWindowPos had no Mac/Linux branch); Added: macOS Homebrew dylibs (openssl) bundled in Contents/Frameworks; Added: macOS .app bundle now notarized + stapled (drag-to-Applications no longer needs xattr -cr on first launch); Changed: Qt MSI ~1MB smaller (dropped unused iconengines and imageformats plugins) | |
| 1.18.31 | 2026-04-22 | Added: drug slot shows DOSE_AMOUNT (mg etc) in preference to VOL (mL) when available; Added: DOSE_RATE / DOSE_AMOUNT montypes bound to BBraun tracks for monitor view; Added: HL7 MDC_DOSE_DRUG_DELIV_TOTAL unit picked up dynamically from UCUM |
| Version | Date | Changes | |
|---|---|---|---|
| 1.15.10 | 2025-07-14 | Bug Fixed: Sampling rate estimation in Medibus protocol. | |
| 1.15.9 | 2025-06-03 | Bug Fixed: EEG waveform labels from Philips monitors. | |
| 1.15.8 | 2025-05-26 | Added: EM_UPLOAD option to upload vital files to server immediately | |
| 1.15.7 | 2025-05-26 | Bug Fixed: Websocket connection error | |
| 1.15.6 | 2025-05-19 | Bug Fixed: S5 checksum error | |
| 1.15.5 | 2025-04-17 | Bug Fixed: saving the raw data | |
| 1.15.4 | 2025-04-15 | Added: Recording alarms from Philips monitor | |
| 1.15.3 | 2025-04-14 | Bug fixed: saving the raw data | |
| 1.15.2 | 2025-03-12 | Fixed: bug in opening file | |
| 1.15.1 | 2025-01-30 | Supporting for Fresenius Kabi Conox, Minor Bug fixes | |
| 1.14.13 | 2025-01-18 | Fixed bug in handling non-ascii filepath | |
| 1.14.12 | 2024-11-20 | Fixed: bug in 64bit ARM Architecture | |
| 1.14.11 | 2024-10-24 | Added: feature for updating to a specific version | |
| 1.14.10 | 2024-10-22 | Fixed: bug in json streamming | |
| 1.14.9 | 2024-10-17 | Added: montype for drug rates | |
| 1.14.6 | 2024-09-20 | Added: montype for drug rates | |
| 1.14.5 | 2024-09-13 | Added: auto cutting by any of hr or spo2 | |
| 1.14.4 | 2024-09-12 | Fixed: bug in serial port mapping | |
| 1.14.3 | 2024-09-10 | Added: temperature monitoring Fixed: bug in cpu usage calculation | |
| 1.14.2 | 2024-08-29 | Added: DI-245 protocol | |
| 1.14.1 | 2024-07-26 | Added: GE cardiac output parameters | |
| 1.14.0 | 2024-07-25 | Added: GE Canvas device | |
| 1.13.10 | 2024-07-17 | Fixed: NirsitOn protocol bug | |
| 1.13.9 | 2024-06-27 | Bug fix for file loading | |
| 1.13.8 | 2024-06-05 | Bug fix for file loading | |
| 1.13.7 | 2024-06-04 | Bug fix for file loading | |
| 1.13.6 | 2024-06-03 | Bug fix for the NirsitOn+ protocols with 32Hz | |
| 1.13.5 | 2024-05-30 | Added support for the NirsitOn+ protocols with 32Hz | |
| 1.13.4 | 2024-05-23 | Added fetal heart rate and uterine activity | |
| 1.13.3 | 2024-05-23 | Tested for BIS vista protocol | |
| 1.13.2 | 2024-04-26 | Support for BIS vista protocol | |
| 1.13.1 | 2024-04-26 | Support for BIS vista protocol | |
| 1.12.12 | 2024-04-09 | Deployment script updated | |
| 1.12.11 | 2024-04-06 | Deployment script updated | |
| 1.12.10 | 2024-02-25 | Deployment script updated | |
| 1.12.8 | 2024-02-25 | Added support for GE Coro fetal monitor | |
| 1.12.7.0 | 2024-02-24 | Added support for GE Coro fetal monitor | |
| 1.12.6.0 | 2024-01-05 | Minor bug fix | |
| 1.12.5.0 | 2023-12-22 | Minor bug fix | |
| 1.12.4.0 | 2023-12-22 | Minor bug fix Added support of Pleth(Left, Right) and Aortic pressure for the Intellivue protocol Added option for the cut by heart rate Added option for setting the waveform by its name - Intellivue: I, II, III, V, aVR, aVL, avF, MCL, MCL1, V1, V2, V3, V4, V5, V6, PLETH, ABP, ART, CVP, FAP, PAP, ICP, EEG, CO2, RESP, AWF, AWP - S5: ECG1, ECG2, EEGBIS, EEGENT, EEGENT400, IABP1, IABP2, IABP3, IABP4, IABP5, IABP6, IABP7, IABP8, EEG1, EEG2, PLETH, CO2, O2, N2O, AWP | |
| 1.12.3.0 | 2023-12-12 | Minor bug fixes Improvement of the Bx50 protocol Improvement of the NIHONKOHDEN protocol | |
| 1.12.2.0 | 2023-12-11 | Minor bug fixes Improvement of the Bx50 protocol Improvement of the NIHONKOHDEN protocol | |
| 1.12.1.0 | 2023-12-11 | Minor bug fixes Improvement of the Bx50 protocol Improvement of the NIHONKOHDEN protocol | |
| 1.12.0.0 | 2023-12-05 | Supported protocol for Drager B1x5M. | |
| 1.11.20.0 | 2023-11-07 | Supported protocol for Daiwha TCI pump. | |
| 1.11.18.0 | 2023-09-14 | Bug fix for EGA protocol Minor Bug fixes | |
| 1.11.17.0 | 2023-09-08 | Bug fix for EGA protocol | |
| 1.11.11.0 | 2023-07-12 | Fixed bug for TOFCuff | |
| 1.11.10.0 | 2023-06-01 | Fixed bug for VitalConnect | |
| 1.11.9.0 | 2023-05-30 | Fixed bug for BUTTON | |
| 1.11.8.0 | 2023-05-27 | Fixed bug for MEKICS Fixed bug for remote update | |
| 1.11.7.0 | 2023-05-24 | Added support for NirsitOn+ | |
| 1.11.6.0 | 2023-05-23 | Added support for NirsitOn+ | |
| 1.11.4.0 | 2023-05-22 | Added support for NirsitOn+ | |
| 1.11.3.0 | 2023-05-21 | Added support for SNUSensor | |
| 1.11.1.0 | 2023-05-03 | Added support for TOFcuff | |
| 1.10.19.0 | 2023-01-12 | Added support for file cutting based on SpO2 | |
| 1.10.17.0 | 2022-12-16 | Added support for AU protocol | |
| 1.10.15.0 | 2022-12-12 | Added support for AU protocol | |
| 1.10.13.0 | 2022-12-07 | Added support for AU protocol | |
| 1.10.11.0 | 2022-12-05 | Added support for AU protocol | |
| 1.10.10.0 | 2022-12-02 | Added support for AU protocol | |
| 1.10.9.0 | 2022-12-01 | Fixed bug for Link+ protocol | |
| 1.10.8.0 | 2022-11-29 | Fixed bug for Servo-i Ventilator Fixed bug for Hamilton Ventilator | |
| 1.10.7.0 | 2022-11-08 | Improved support for Nihon kohden ADT | |
| 1.10.6.0 | 2022-11-04 | Improved support for Nihon kohden HL7GW | |
| 1.10.4.0 | 2022-11-02 | Hamiltonian ventilator supported | |
| 1.10.3.0 | 2022-10-21 | Hamiltonian ventilator supported | |
| 1.10.2.0 | 2022-10-14 | Hamiltonian ventilator supported | |
| 1.10.1.0 | 2022-10-07 | Minor bug fix Added input dialog for patient ID when intranet server is used | |
| 1.10.0.0 | 2022-09-15 | Minor bug fix Added input dialog for patient ID when intranet server is used | |
| 1.9.11.0 | 2022-07-29 | Minor bug fix Added input dialog for patient ID when intranet server is used | |
| 1.9.10.0 | 2022-06-26 | Minor bug fix Added input dialog for patient ID when intranet server is used | |
| 1.9.8.0 | 2022-05-17 | Minor bug fix VitalSync compatible with VitalDB Platform API | |
| 1.9.7.0 | 2022-03-25 | Display patient id on the title bar Support for barcode reader Minor bug fix | |
| 1.9.6.0 | 2022-03-25 | Additional Parameter (RPVI) for Masimo Root Bug fix for VitlaUtils | |
| 1.9.2.0 | 2022-02-17 | Added ABP montype to ClearSight | |
| 1.9.1.0 | 2022-02-16 | Supported MedibusX protocol | |
| 1.9.0.0 | 2022-02-14 | Supported LiDCO protocol | |
| 1.8.22.0 | 2022-02-10 | Added filter server running on localhost Moved VC setting dialog to the Setting dialog Fixed minor bugs | |
| 1.8.21.1 | 2022-02-07 | Fixed a bug with the Intellivue | |
| 1.8.21.0 | 2022-01-21 | Fixed a bug with the Intellivue | |
| 1.8.20.1 | 2022-01-15 | Fixed a bug with the Intellivue | |
| 1.8.20.0 | 2022-01-13 | Requesting O2 and N2O waves to the Bx50. Fixed a bug with the channel names of FIO2 and FIO2 of the Bx50. | |
| 1.8.19.6 | 2021-12-24 | ADT_SERVER_IP | |
| 1.8.19.5 | 2021-12-17 | Bug fix for Intellivue protorol |
| Version | Date | Changes | |
|---|---|---|---|
| 1.18.45 | 2026-06-16 | 1.18.45 Fixed: Windows VR 에서 사용자가 외부에서 vr.conf 를 멀티베드 설정으로 교체 후 VR 을 재실행하면, 첫 실행에서는 멀티탭이 정상 생성되지만 다음 실행에서 모든 탭이 사라지던 문제. 원인은 VRApp.cpp:1110 의 VRCODE 미설정 분기 — 새 vr.conf 가 VRCODE 라인을 포함하지 않으면 load_settings() 가 신규 VRCODE 를 issue_code() 로 발급하고 즉시 save_settings() 를 호출하는데, 이 시점은 load_settings() 가 파싱한 베드들이 로컬 newbeds 벡터에만 있고 아직 m_pdisps 로 옮겨지기 전 (set_beds(newbeds) 는 initialize() 가 load_settings 반환 후 라인 1328 에서 호출). 결과: save_settings() 가 빈 m_pdisps 를 iterate 하며 vr.conf 를 글로벌 설정만으로 덮어써 모든 [BED/...] 섹션이 디스크에서 사라짐. 첫 실행은 메모리의 newbeds 로 UI 멀티탭이 그려져 정상으로 보이지만 (사용자가 "멀티탭은 정상적으로 생성되지만" 으로 표현), VR 종료/재실행 시 디스크 conf 에는 BED 섹션이 없으므로 다음 load_settings 가 빈 베드 리스트를 반환 → 탭 전부 사라짐. 수정: VRApp.h 에 m_vrcode_newly_issued bool 플래그 추가, load_settings 의 즉시 save 를 플래그 set 만 으로 교체, initialize() 의 set_beds(newbeds) 직후 (m_pdisps 가 채워진 시점) 플래그가 켜져 있으면 한 번만 save_settings() 호출 → BED 섹션이 정상 직렬화됨. Linux/Pi 분기 (m_serial_number 가 채워져 있는 경우) 는 원래도 save 안 했으므로 영향 없음, VRCODE 가 이미 conf 에 있는 모든 기존 deployment 도 분기 미진입으로 0-impact. m_conf_from_stdin / m_bDebug 모드는 save_settings 내부에서 이미 early return 이라 그대로 안전. MFC + Qt 빌드 모두 통과 (이번 변경 관련 0 warning). | |
| 1.18.44 | 2026-06-12 | 1.18.44: vr.conf FHIR=1 모드 추가 (자체 FHIR 수신서버 대상 실시간 푸시) + VS 2026 / 새 OpenSSL 인스톨러 빌드 환경 호환 shim. (1) sendweb_thread_func 의 기존 HL7/JSON 양분 분기 (VRApp.cpp:2466) 옆에 bFHIR 분기 추가. 1초 tick 마다 한 vrcode 의 모든 방 Observation 을 하나의 FHIR R4 collection Bundle 로 묶어 기존 WSS 채널로 push (gzip + WSSClient 인프라 그대로 재사용). MLLP 같은 신규 transport 안 도입 — FHIR R5 Subscription 의 websocket channel type 과 동형이라 표준 부합. (2) DISPLAY::get_fhir + TRACK::get_fhir 신규. v2 (vitaldb-fhir-v2) 와 동일한 reference-only 패턴 (Patient.id = m_patient_id, Encounter.id = vrcode-bedname-startsec, Observation.subject/encounter = relative reference) + hybrid keyframe: 첫 tick / m_patient_id 변경 / get_start_time() 변경 / 5분 경과 중 하나라도 발생 시 다음 tick Bundle 에 Patient + Encounter resource 를 inline. 그 외 tick 은 Observation 만. 수신서버가 도중에 새로 connect 해도 최대 5분 안에 자동 동기화 (keyframe heartbeat). DISPLAY 에 m_fhir_pt_sent_at/m_fhir_pt_last_id/m_fhir_enc_last_start 3개 멤버 추가 (m_setting_sent 패턴 그대로 per-display). (3) Observation 인코딩: NUM 은 effectiveDateTime + valueQuantity 각 데이터 포인트당 한 entry, WAV 은 effectivePeriod + valueSampledData (period=1000/srate ms, factor=1, origin=0, data=공백구분 floats) 한 entry. CO2/AWP wav 는 기존 get_json 처럼 25Hz 다운샘플 유지. NUM 은 m_montype 기반 LOINC 매핑 15개 등록 (ECG_HR/PLETH_HR=8867-4, PLETH_SPO2=59408-5, NIBP/IABP SBP/DBP/MBP=8480-6/8462-4/8478-0, BT=8310-5, RR=9279-1, etCO2=19891-1, CVP=8556-0, FETAL_HR=11627-3) + VR 자체 코드 시스템 (https://vitaldb.net/fhir/CodeSystem/track, code = dname/tname) 항상 동반. m_patient_id 미설정 (PATIENT_ID_UNSET) 시 anon-vrcode-bedname identifier 로 fallback. (4) Bundle wrapper: VRApp 가 방별 entries 를 콤마로 합쳐 {resourceType:Bundle, type:collection, timestamp:iso8601Z, entry:[...]} 로 wrap, 기존 gzip → WSS pipeline 동일. ISO 8601 UTC 헬퍼는 std::gmtime_s/gmtime_r 인라인. FHIR id 안전화 (A-Za-z0-9-.) 64자 제한 lambda 각 함수에 inline. (5) 빌드 환경 호환성: VRQt/CMakeLists.txt 에 _SILENCE_EXPERIMENTAL_COROUTINE_DEPRECATION_WARNINGS 추가 — VS 2026 (MSVC 14.51+) 의 STL 이 <experimental/coroutine> deprecation 을 warning → hard static_assert 로 바꾼 것이 cppwinrt 의 winrt::* (Serial.cpp 의 Bluetooth LE) 를 끌어오는 모든 TU 에서 컴파일 실패 시켜서, build_mfc.py 가 이미 CL env 로 주입하던 것과 동치 shim 을 Qt 쪽에도. (6) VRQt/CMakeLists.txt 의 OpenSSL link 경로 시프트. 새 OpenSSL 인스톨러가 libssl_static.lib / libcrypto_static.lib 를 lib/VC/x64/{MT,MTd}/ 에 두고 v1.x 의 libssl64MT.lib / libcrypto64MT.lib 네이밍과 lib/VC/static 경로를 깬다. build_mfc.py 의 %LOCALAPPDATA%/openssl-compat 패턴 (옛 이름으로 복사한 사본 폴더) 을 그대로 따라 CMakeLists 도 그 폴더가 있으면 우선, 없으면 옛 lib/VC/static 으로 fallback. 부트스트랩 스크립트는 build_mfc.py 의 docstring 참조 (한 줄). MFC + Qt + RPi + Ubuntu CLI + AppImage 빌드 모두 통과. 동작 영향: vr.conf 에 FHIR=1 추가 안 한 기존 deployment 는 sendweb 가 종전 JSON 모드 그대로 (HL7=1 만 분기보다 우선) — 0-impact migration. | |
| 1.18.43 | 2026-05-21 | 1.18.43: 멀티베드 console (PACU 10베드 Pi) syslog noise 80,500/hr → ~1,400/hr (-98.3%), cpu_usage 측정 1.16.12 (9f26e36) 이후 8년치 영구 -1 버그 수정, 멀티베드 환경 베드 식별용 [bedname / devicename] 로그 prefix 도입. 동기는 PACU production Pi (1.18.40) 4일치 syslog 분석 — 1.24M 라인 중 vr 라인 836K, idle 8시간 평균 시간당 80,500 라인 (베드 10 × 1초마다 "Waiting for next patient" × syslog 2x 중복). (1) VRApp.cpp:2696-2710 timer_thread_func 의 cpu usage 계산이 `if (totalcpu && m_cpu_total_last && totalcpu > m_cpu_total_last)` 가드 안에서만 m_cpu_total_last 갱신해 첫 호출 시 m_cpu_total_last=0 → else 분기 → -1 → m_cpu_total_last 갱신 안 됨 → 영원히 false → 영원히 -1 데드락. PACU 1,048 샘플 100% -1 실측 확인. m_cpu_total_last/m_cpu_used_last 갱신을 if 밖으로 빼서 첫 호출만 baseline 으로 -1, 두 번째 (60s 후) 부터 정상 측정. /proc/stat 의 iowait/irq/softirq 까지 7개 필드 fscanf 로 정확도 ±5% 개선. 부수: 같은 함수의 cpu_temp 가 `temp / 1000` int 나눗셈으로 소수점 절단되어 PACU 측정값이 정수 50/51/...,/58 9종만 출력 (millidegree 정밀도 손실) → `temp / 1000.0f` 로 fix. ram 계산은 `(totalram + totalswap) * mem_unit` 결과에 다시 mem_unit 곱하던 차원 혼용 (Linux 가 mem_unit=1 이라 우연히 정상 동작했지만 dimensionally wrong) → `(units1 + units2) * mem_unit` 로 정정 + underflow 가드. (2) DISPLAY::log(string/printf) + DEVICE::log(string/printf) 멤버 추가. DISPLAY::log 는 `[bedname] msg`, DEVICE::log 는 m_pdisp 위임 없이 직접 `[bedname / devicename] msg` 한 줄 prefix (nested `[bed] [dev]` 보다 가독성 우선). m_pdisp 또는 bedname null 케이스 safe fallback. (3) show_msg 의 console path TRACE 를 log() 로 교체 → "Waiting for next patient" 자동 [bedname] prefix. ADT patient id unset 도 log() 로. (4) 이미 수동으로 get_bedname() 을 인자로 넘기던 8군데 (DISPLAY ptcon_thread_func / add_trk / add_dev / del_dev / cut-recording, Device add_rec 콜백, FILT stop, VRApp add_tab/del_tab) 를 log() 로 전환 — 이중 prefix 방지 + 일관성. Serial::reading_thread / tcp_thread / open_socket waiting / timeout / interrupted / got-client 6군데 DEVICE::log() 전환 → `[bedname / Intellivue]` 등 자동 prefix, 멀티탭 환경에서 어느 베드 어느 device 출처인지 즉시 식별. (5) wss 재시도 폭주 throttle. WSSClient 에 m_verbose (debug step 로그 게이트) + m_dt_last_err_log (60s window) 추가. connect() 내부 step-by-step TRACE 4개 ("connecting" / "connect error" / "connected") 는 m_verbose 가드, 최종 "wss connect error" 는 60s window throttle (첫 줄 즉시, 그 다음 60s 1회). connect 성공 path 에서 throttle reset 으로 다음 disconnect → 첫 에러 즉시 로깅. sendweb_thread_func 의 "connecting websocket server" 호출자 라인도 같은 60s window, m_bDebug 면 verbose 활성화. PACU idle 8h 측정 7,024/hr (4종 × 1,756) → 약 60/hr (-99%). (6) "Waiting for next patient" / "ADT patient id unset" 의 60s throttle 자체는 feature/wav-mem-retention 브랜치 ptcon_thread_func 재구성 (b75928f 시리즈) 에서 이미 들어가 있어 이 릴리즈에 자동 포함. 종합 영향: idle 시간당 syslog 라인 80,500 → ~1,400 (-98.3%), active 시간당 14,900 → ~700 (-95%). 진단 측면: cpu_usage 가 부활하면서 웹모니터링 json 의 cpu_usage 필드도 한 번도 안 채워지던 게 정상 전송 (VRApp.cpp:2499 의 `if (m_cpu_usage > 0)` 가드가 영원히 false 였음). 별건: syslog 라인 2× 중복은 application 측이 아니라 rsyslog imuxsock + imjournal + journald.ForwardToSyslog=yes 의 Debian Bookworm 전형 misconfig — admin 측 fix (rsyslog.conf 에서 imjournal 주석 처리 + restart) 로 추가 50% 감소 가능 (별도 문서). MFC + Qt + Pi (RPI64) + Ubuntu CLI 빌드 모두 통과. | |
| 1.18.41 | 2026-05-13 | 1.18.41 Hotfix: TCP-server protocol-initiator device (Intellivue/S5/Datex/Hamilton/MPS/Agilia/IAP) 가 open() 직후 보내는 첫 패킷이 wire 에 안 나가던 회귀. 1.18.34 의 PortRouter refactor 가 Serial::open_socket() 의 8초 handoff blocking 을 제거하고 비동기 모델로 전환했는데, protocol-initiator 의 open() 코드가 m_sock=INVALID 상태에서 write 를 시도해 silent fail (Linux 는 m_fd=0 이라 false 반환). Intellivue 케이스 production journald 의 Pi → ESP TX 700K~3M bytes 는 monitor 측 abort 로 늦게 트리거된 AB_SPDU_SI recovery assoc_req 후 request_thread 의 정상 polling 트래픽이지만 일부 베드 (abort 없는 monitor) 는 recovery 도 안 되어 영구 silent (RX 300 bytes). 수정 방향: open() 의 옛 contract ("return 시점에 통신 가능") 복구. (1) Serial::open_socket() TCP-server 분기가 PortRouter::subscribe 후 m_sock_cv 로 첫 client handoff 까지 block (timeout = device read_timeout, 기본 30s) — 옛 모델 그대로. lock_and_open 이 false 면 다음 tick 에서 retry. close 신호로 abort 가능. (2) Serial::close() 는 PortRouter::unsubscribe 안 함 — subscribe 는 device 생애 동안 sticky 라 read_timeout 으로 인한 close→re-open 사이클 동안 listen socket 이 유지되어 1.18.29/1.18.34 의 anti-churn 이익 보존. unsubscribe 는 ~Serial() 에서만. (3) Per-device lifecycle thread (DEVICE::m_thread_restart): 각 device 가 자기 open/close/timeout 재시작을 별도 thread 에서 관리. 옛 모델의 DISPLAY::bed_manager 가 베드의 모든 device 를 sequential iterate 하던 구조에선 한 device 의 blocking open() 이 같은 베드의 다른 device 의 lifecycle 을 차단했는데, per-device thread 로 분리하여 멀티 device 베드도 병렬 진행. add_dev 에서 start_lifecycle, del_dev / ~DISPLAY 에서 stop_lifecycle. (4) Serial::tcp_thread_func 단순화 — outer m_sock_cv wait 패턴 (1.18.34/1.18.39 가 추가했던 것) 제거. open_socket 이 m_sock valid 보장하므로 reader thread 시작 시점에 simple inner recv loop 만. accept_handoff 의 replace (zombie cleanup) 케이스는 recv error 후 m_sock 변경 확인 + retry 로 처리. (5) reading_thread_func 의 `else if (m_sock != INVALID_SOCKET) tcp_thread_func();` 가드 복원 (1.18.39 가 제거). (6) Serial::write 의 silent-fail 케이스에 WARN trace 추가 — 미래 동종 회귀 즉시 노출. (7) PortRouter::subscribe 가 같은 (port, type) 에서 같은 IP filter 또는 둘 이상 catch-all 발견 시 reject (config 실수 원천 차단, 옛 WARN-only 동작 강화). (8) DISPLAY::bed_manager_thread_func 의 restart 블록 제거 — ptcon + adt 만 담당. "Waiting for next patient" TRACE 가 Linux/console 에서 1초 → 60초마다 throttle (별개 journald 부풀림 fix). 영향 범위: Intellivue / S5 / Datex / Hamilton / MPS / Agilia / IAP TCP-server 모드 베드 전부. 1.18.34 이후 우회 방법은 race-win 케이스 (VRN 이 PortRouter::subscribe 직후 connect) 외엔 없었음. MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.40 | 2026-05-12 | Hotfix: Drager Medibus 프로토콜 사용 베드에서 1.15.11 이후 vr.service 가 SIGSEGV 로 무한 재시작하던 문제. 1.15.10 (a8c7b2a) 의 "Sampling rate estimation" 리팩터링이 m_ptrk_awp/awf/co2 트랙을 add_trks() 에서의 eager 생성 (default srate=62.5Hz) 에서 realtime data 100 샘플 모인 후 lazy 생성으로 바꿨는데, Medibus 핸드셰이크 순서 (0x51 ICC → 0x52 DeviceID → 0x53 RealtimeConfig 응답 → 0x54 → realtime data 시작) 상 0x53 응답 핸들러 (Drager.cpp:295-307) 가 트랙들이 아직 nullptr 인 시점에 `ptrk->m_srate = 1000000.0/interval` 로 NULL 역참조 → 즉시 SEGV. 그 베드의 vr.service 가 systemd Restart=on-failure 로 재시작 → 다시 connect → 동일 0x53 패킷 받고 동일 SEGV → 무한 루프 (journald 로그상 restart counter 61 까지 누적, code=killed status=11/SEGV). 1.15.9 까진 트랙이 add_trks() 에서 생성되어 0x53 도착 시 항상 non-NULL 이라 안전했음. 수정: (a) add_trks() 에서 m_ptrk_awp/awf/co2 eager 생성 복원 (srate=62.5Hz default) — 0x53 는 ptrk->m_srate 만 갱신 (트랙 재생성 X). (b) on_received() 의 lazy creation + packet-timing srate 추정 블록 제거 — 0x53 가 권위 있는 srate 소스이고 packet 타이밍 기반 추정은 network jitter 에 약해 불안정. (c) 0x53 핸들러에 `if (interval > 0)` guard 추가 — 페이로드 깨졌을 때 div-by-zero / inf srate 방지. 영향 범위: Drager Primus / Apollo / Perseus / Fabius 등 Medibus 사용 마취기 전부. 우회 방법은 1.15.9 다운그레이드 외엔 없었음 (그 베드의 모든 데이터 유실 + 환자 모니터링 불가). MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.39 | 2026-05-08 | Fixed: PortRouter (TCP server) 모드에서 reader thread 가 startup 시점에 죽어 client 데이터를 영구히 못 받던 문제. 1.18.34 (9bd252f) 의 PortRouter refactor 가 m_sock 세팅을 dispatch 시점으로 옮겼는데 reading_thread_func (Serial.cpp:354) 의 가드 `else if (m_sock != INVALID_SOCKET) tcp_thread_func();` 는 옛 모델 (open 시점 이미 connect 완료) 가정 그대로라 — 시작 직후 m_sock=INVALID 면 tcp_thread_func 진입 안 하고 reader thread 즉시 종료. 이후 VRN 이 connect → PortRouter::dispatch → accept_handoff 가 m_sock 채우고 m_sock_cv.notify_all() → 그러나 wait 중인 reader 가 없음 (이미 죽음) → kernel recv buffer 에만 데이터 적재. 증상은 ss -tn state established 의 Recv-Q 가 0 이 아닌 값 (수백 bytes) 으로 누적, 베드 화면에는 데이터 안 들어옴. 그 베드의 VRN 이 Serial::open() 의 PortRouter::subscribe 직후~reader thread spawn 사이의 짧은 윈도우 안에 connect 한 경우만 우연히 정상 동작 (race-win). 수정: 가드 제거 — TCP 분기에 항상 진입. tcp_thread_func 자체에 이미 m_sock_cv outer-wait 루프가 있어 m_sock 이 INVALID 인 동안 dispatch 가 깨워줄 때까지 안전하게 대기. Pi 핫스팟에 VRN 여러 대 (e.g. 10.42.0.21~25) 를 같은 (4343, Philips:Intellivue) 키로 묶고 IP filter 로 라우팅하는 시나리오에서 가장 자주 노출. Added: 진단 로그 보강 — PortRouter::accept_loop 의 accept 이벤트, dispatch 의 라우팅 결정 (ip_specific/catch_all subs 수, 어느 dev 가 받았는지), subscribe/unsubscribe 의 entry 생성/append/destroy, reading_thread / tcp_thread 의 시작·wait·wake 라이프사이클 — 이전엔 모두 m_bDebug 게이트 안에 있어서 production journald 에서 안 보였는데, 이제 항상 출력 (이번 같은 dispatch routing 문제 진단을 production 에서 바로 가능). MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.38 | 2026-05-08 | Fixed: 웹모니터링 우클릭 → 디바이스 세팅 (websocket edit_bed 명령) 으로 베드의 device/filter 를 변경할 때 베드 이름이 매번 "_2" suffix 로 자동 리네임되어 vr.conf (Pi: /data/vr.conf) 에 잘못된 이름으로 저장되던 문제. 원인은 1.18.22 (cda8aa5) 에서 add_bed 에 추가된 bedname dedup ("최후 방어선" 으로 forward_frame auto-create / 수동 편집된 conf 의 중복 이름 처리용). edit_bed 핸들러는 옛 pdel 이 m_pdisps 에 그대로 있는 상태에서 같은 bedname 으로 new DISPLAY 를 add_bed 하고 그 다음 del_bed(pdel) 하는 순서였는데, add_bed 가 dup 감지해 새 pdisp 를 bedname_2 로 자동 리네임 → save_settings 가 [BED/bedname_2] 로 직렬화 → 사용자 입장에선 "설정 적용 안됨" 으로 보였다. 추가로 옛/새 DISPLAY 가 잠깐 m_pdisps 에 공존하면서 같은 device 포트를 동시에 들고 있으려 해 로그가 dup 으로 찍히는 부수 증상도 있었음. 수정: del_bed(pdel) 를 add_bed(pdisp) 보다 앞으로 이동 — 옛 베드의 device 포트가 깨끗이 release 된 뒤 새 pdisp 가 같은 포트를 reopen, dedup 발동 안 함. 다른 베드의 recording 은 영향 없음 (인메모리 hot swap 설계 유지). 부수: edit_bed 핸들러의 데드 코드 (`break` 뒤의 unreachable olddevs populate 루프 + `if (olddevs.find(name) == olddevs.end())` 항상-true 래퍼) 정리. edit_conf 와 save_settings 는 손대지 않음. MFC + Qt + Pi (RPI64) 빌드 모두 통과. | |
| 1.18.37 | 2026-05-08 | Refactored: 필터 다이얼로그의 python 런타임 — pyvital → openvital 0.3.0 로 교체 + 동봉 python.zip 슬림화. 핵심 동기 셋: (1) pyvital 0.6.0 이 tensorflow+torch+keras 를 hard-dep 으로 끌어들여 PyPI upgrade 가 사실상 깨짐, (2) 기존 zip 121 MB 안에 botocore/aiobotocore/s3fs/pyarrow/pandas/aiohttp 등 vitaldb 클라우드 업로드용 deps 가 ~250 MB unpacked 차지 — 필터 서버는 한 번도 쓴 적 없는 dead weight, (3) sanic 25.x 의 multi-process worker 가 openvital __main__.py 를 fork 후 재import 하면서 worker 가 module-top app instance 를 못 찾아 "Sanic app name not found" 로 죽음 — 단순 endpoint 2개 로컬호스트 서버에 async stack 자체가 과함. 해결: openvital 0.3.0 (commit b6f445b) 가 sanic 을 stdlib http.server (BaseHTTPRequestHandler + HTTPServer) 로 50 LOC 재작성 — wire protocol (GET / 필터목록 JSON, POST /<modname> gzip 본문) 동일해 VR 클라이언트 변경 0줄. 단일 스레드로 기존 sanic event loop semantics (cfgs/default_cfgs lock-free 변경) 보존. build_python_zip.py (NEW) 가 Python 3.11.9 embed + numpy + openecg + openvital (local checkout 우선, fallback PyPI) 만으로 27 MB zip 빌드 — 기존 121 MB 대비 78% 감소. ML 필터 (sv_dlapco/abp_hpi/ecg_classifier/ecg_beat_noise_detector) 는 [Hybrid 모델] 사용자가 Add filter 다이얼로그의 "Install ML filters" 버튼 누를 때 silent pip install openvital[all] (cmd 창 미노출 — VRApp::install_pip_package + run_pip_silent 이 자체 progress 다이얼로그에 stdout heartbeat 흘림). 버튼 라벨은 "Upgrade pyvital" → "Install ML filters" 로 의도 명시. openvital __main__.py 가 missing extras 를 graceful skip 하므로 base 환경에서도 11개 필터 (ECG QRS detector, HRV, MTWA, annotator, eeg_fft, nirs_cox, pkpd_3comp, pleth_dpop/ptt/pvi, resp_compliance) 즉시 사용 가능. Migration: 기존 사용자의 user_dir/python 폴더는 pyvital + 옛 deps 가 그대로 남아있고 vitaldb.net/python.zip 만 새로 올리면 (a) 기존 폴더 삭제 후 install_python 으로 새 zip 받으면 깔끔, (b) 폴더 유지 시 server 가 openvital 못 찾아 필터 다이얼로그 에러 → release note 에 명시 필요. MFC + Qt 양쪽 코드: VRGui.rc 의 IDC_UPGRADE 버튼 라벨 + DlgAddFilter.cpp 의 dist-info prefix 매칭 (pyvital- 8자 → openvital- 10자) + QtDlgAddFilter.cpp 도 동일 변경 + onUpgrade 가 cmd /k QProcess::startDetached 대신 theApp.install_pip_package("openvital[all]") 호출 (Linux Qt 빌드는 #ifdef _WIN32 가드). VRApp.cpp:318 의 python -m pyvital → -m openvital. install_pip_package 는 anonymous namespace 의 is_safe_pkg_spec 화이트리스트 검증 + run_pip_silent (CreateProcessA + CREATE_NO_WINDOW + 자식 stdout pipe) + CDlgProgress / QtDlgProgress 자체 progress UI. 빌드 검증: python -m openvital 이 GET / 로 11 필터 반환, sanic import 부재 확인. zip 27.5 MB. | |
| 1.18.36 | 2026-05-07 | Fixed: 3-파티션 레이아웃 (boot/rootfs/data) 에서 websocket edit_conf / update 명령이 read-only fs 로 실패하던 문제. vr.conf 는 /data 폴더가 있으면 /data/vr.conf 로 자동 정착 — get_conf_path() 가 write target 으로 결정, load_settings() 는 primary 가 없으면 legacy /boot/firmware/vr.conf 또는 /boot/vr.conf 에서 fallback read 후 다음 save 부터 primary 로 자동 이전 (마이그레이션 step 없음, legacy 파일은 read-only fs 라 무해). binary update (upgrade_now) 는 RAII BootRwGuard 가 dirname(module_path) 를 잠시 rw remount, scope 종료 시 sync() + MS_REMOUNT|MS_RDONLY 로 자동 ro 복귀 — vfat 노출 윈도우 최소화 + exception/return 어디서든 복구 보장. statvfs ST_RDONLY 검사로 이미 rw 인 fs (x86 dev) 에서는 no-op, non-Linux (macOS) 는 stub 으로 통과. save_settings() 의 silent EROFS 실패가 TRACE 로 가시화 (이전엔 무시되어 conf 수정 안 먹는 원인 추적 불가). 부수: PortRouter.cpp 가 commit 9bd252f 이후 CMakeLists 의 RPI sources 목록에서 누락되어 Pi 빌드 link 에러 — 추가. | |
| 1.18.35 | 2026-05-01 | Added: alarm parsing for Mindray HL7 (eGateway ORU^R40) and Nihon Kohden (NealTime HL7GW + ORF, BSM serial D-port, EGA UDP) - emits ALARM_STATUS / ALARM_MESSAGE / ALARM_PRIORITY tracks (same 3-track schema already used by Philips IntelliVue, GE Solar/Dash, GE/Datex S5); type info preserved via [T]/[A]/[ARR] message prefixes; Mindray facet 1/5/6/7 walker with 92-entry MDC+MNDRY alarm code lookup; NK HL7GW parses OBR-4=EVENT with arrhythmia/technical disambiguation by OBX-5; NK BSM serial decodes per-parameter * flags (edge-triggered to avoid 1Hz flooding) plus 32-bit Table 9 arrhythmia bitmap, D19 alarm-suspend nibble, and the VPC CODE byte; NK EGA UDP extracts Priority + Tech Alarm + Arrhythmia from JSON Vital Sign packets with edge-trigger cache for start/end inference; ACK^R40 reply added for Mindray alert messages; simulators gained periodic alarm cycling for end-to-end smoke testing | |
| 1.18.34 | 2026-04-27 | Added: Linux Desktop Qt GUI build (VRQt) - first GUI build for Linux distributed as a self-contained AppImage (~32MB, Qt6 runtime + libGL/libEGL/libGLX/libOpenGL/libGLESv2/libGLdispatch bundled inside) so users on minimal Ubuntu/Debian/Fedora can run it without installing Qt or GL system packages; tested on AWS clean Ubuntu 22.04 cloud image; build via build_ubuntu_appimage.py which is now invoked by deploy.py; Fixed: Linux Qt right-side device/filter panels rendered with white background below cards because the inner listWidget did not autoFillBackground from parent palette on Linux Qt (Windows/macOS implicitly inherit, X11/Wayland do not); explicit stylesheet on listWidget; Added: Linux installation section in user manuals (EN/KO/ZH/ES) covering AppImage chmod+run flow and dialout group note for serial/USB device access | |
| 1.18.33 | 2026-04-25 | Fixed: Demo device never started since 1.18.11 (bed_manager skipped empty port_name as passive but Demo has no port and still needs lock_and_open); Fixed: Qt fit-to-window button rendered at top-left (0,0) instead of right-aligned in bottom nav bar; Fixed: Qt crash when closing tab / deleting device / deleting filter - paint dereferenced freed pointer before panel timer rebuilt items (added MFC-style stale-pointer guard to QtDeviceItem and QtFilterItem); Added: macOS DMG main window now shown on launch (restoreWindowPos had no Mac/Linux branch); Added: macOS Homebrew dylibs (openssl) bundled in Contents/Frameworks; Added: macOS .app bundle now notarized + stapled (drag-to-Applications no longer needs xattr -cr on first launch); Changed: Qt MSI ~1MB smaller (dropped unused iconengines and imageformats plugins) | |
| 1.18.32 | 2026-04-23 | Fixed: same-port multi-client TCP - primary now runs a continuous accept loop and hands off each connection to the matching sub by IP filter (previously second connection got rejected/listened closed); Added: @IP and #keyword port filters are now mutually exclusive per bed (IP wins, keyword dropped with WARN); Added: WARN log when two beds on the same port share an identical IP filter; Added: catch-all primary keeps its single connection and rejects extras (preserves broadcast mode) | |
| 1.18.31 | 2026-04-22 | Added: drug slot shows DOSE_AMOUNT (mg etc) in preference to VOL (mL) when available; Added: DOSE_RATE / DOSE_AMOUNT montypes bound to BBraun tracks for monitor view; Added: HL7 MDC_DOSE_DRUG_DELIV_TOTAL unit picked up dynamically from UCUM | |
| 1.18.30 | 2026-04-21 | Changed: monitor view pump layout - 8 slots with CE or RATE (CE-less pumps show infused volume as small annotation); Reverted: BBraun minimal=1 (1.18.29) - was dropping data from file, monitor view redesign handles display clutter instead | |
| 1.18.29 | 2026-04-21 | Fixed: BBraun multi-rack auto-tab data drop, primary TCP churn, save_settings lock race, TCP reader spin on peer close; Added: BBraun minimal=1 option (display only drug name / rate / volume) | |
| 1.18.28 | 2026-04-20 | Fixed: vr.conf on Pi/Linux now looked up next to executable (supports /boot/firmware); deploy.py --store auto-submits MSIX to Microsoft Store | |
| 1.18.27 | 2026-04-18 | Fixed: vital file periodic flush (5000s→5s bug), Fit-to-Window icon redesigned to match navigation button style | |
| 1.18.26 | 2026-04-18 | Fixed: periodic .vital file flush interval was 5000 seconds instead of 5 (unit-bug since comment said seconds but value was milliseconds). Data now actually reaches disk every 5 s during recording instead of only on close. | |
| 1.18.25 | 2026-04-18 | Fixed: BBraun HL7 rec_timeout raised 10s→60s to prevent primary churn during DoseLink R42→R01 phase transition and long idle periods | |
| 1.18.24 | 2026-04-18 | Fixed: GUI silently exits when another recorder running (now falls back to viewer mode), .vital file association written to HKCU (no admin required, auto-updates exe path on every run) | |
| 1.18.23 | 2026-04-18 | Fixed: atof decimal-separator bug on non-English Windows locales (rates <1.0 recorded as 0 in Norwegian/German/French etc.), BBraun HL7 pump limit raised from 8 to 16 | |
| 1.18.22 | 2026-04-18 | Fixed: multi-bed TCP port bind race on restart (Mindray/BBraun HL7 auto-reconnect without manual Add device) | |
| 1.18.21 | 2026-04-18 | Fixed: port name filter (#keyword@ip) lost on save, BBraun HL7 VMD-block parsing with single dt, Fit-to-Window button sizing (MFC) and added to Qt | |
| 1.18.20 | 2026-04-15 | BBraun: comprehensive protocol parsing (dose rate, infusion time, syringe, weight, drug amounts, delivery status) | |
| 1.18.19 | 2026-04-13 | Fixed: BBraun HL7 multi-pump identification (rack serial filtering), multi-bed forwarding, port filter parsing | |
| 1.18.18 | 2026-04-10 | Added: GE alarm limits, S5 alarm/ext3/ext1 parsing | |
| 1.18.17 | 2026-04-04 | Changed: TRACE debug-only guard, show_msg for file errors, deploy sequential builds | |
| 1.18.16 | 2026-04-04 | Added: TCP port filtering (#keyword@ip), frame forwarding for multi-bed. Fixed: --debug conf file mistaken as vital file, device type ambiguity in forwarding | |
| 1.18.15 | 2026-04-04 | Changed: Port to Port Name, keyword filter AND/OR (#kw1 kw2#kw3), IP postfix matching (@10.1), MEKICS SerialFramed | |
| 1.18.14 | 2026-04-03 | Added: TCP port filtering (#keyword@ip), Fixed: devtypes not sent on boot | |
| 1.18.13 | 2026-04-02 | Changed: Covidien company name to Medtronic (BIS, INVOS) | |
| 1.18.12 | 2026-04-02 | Bug Fixed: NihonKohden EGA SpO2 waveform not displayed (channel name mapping) | |
| 1.18.11 | 2026-03-31 | Added: Mindray HL7 multi-bed separation via PV1, auto-tab creation for EGA/Mindray | |
| 1.18.10 | 2026-03-31 | Added: HL7 ZBR segment now includes ver, os, arch, dgmt | |
| 1.18.8 | 2026-03-25 | Added: --demo mode for console operation with demo signals | |
| 1.18.7 | 2026-03-25 | Added: --console mode for headless operation on Windows | |
| 1.18.6 | 2026-03-25 | Added: Mindray eGateway HL7 protocol (IHE PCD-01, HL7 v2.6 over MLLP, waveform + numeric + infusion pump) | |
| 1.18.4 | 2026-03-24 | Added: BBraun SpaceCom HL7 protocol (HL7 v2.6 over MLLP, TCP server mode) | |
| 1.18.3 | 2026-03-24 | Added: HL7 OBX-14 per-track dtstart, ZBR segment with dtcase/dtapp timestamps | |
| 1.18.2 | 2026-03-24 | Added: HL7 ZBR segment with dtcase (recording start) and dtapp (app start) timestamps | |
| 1.18.1 | 2026-03-23 | Fixed: HL7 OBX-3 format (code^device/track@srate), OBX-7 refrange (min^max), NA null sample gaps | |
| 1.17.6 | 2026-03-22 | Bug fixed: Resource ID conflicts WiX installer cleanup | |
| 1.17.5 | 2026-03-21 | Bug fixed: Vital packed file loading MFC device button icon padding | |
| 1.17.4 | 2026-03-19 | Bug fixed: NirsitON EEG 250Hz VRQt device minimize/rename | |
| 1.17.3 | 2026-03-18 | Bug fixed: BBraun protocol NirsitON protocol VRQt | |
| 1.17.2 | 2026-03-14 | Added: NirsitOn NDI protocol support. | |
| 1.17.1 | 2026-03-12 | Added: VRQt | |
| 1.16.13 | 2026-03-07 | Added: New Setup File with VRQt | |
| 1.16.12 | 2026-03-06 | Added: Vector Type Icons | |
| 1.16.10 | 2026-03-02 | Bug fixed: Autodetecting BBraun Stuffing feature. | |
| 1.16.8 | 2026-02-27 | Bug fixed: Masimo IAP protocol. | |
| 1.16.6 | 2026-02-13 | Added: Servo-u ventilator protocol | |
| 1.16.5 | 2026-02-09 | Bug Fixed: NihonKohden HL7GW Pleth waveform gain correction. | |
| 1.16.4 | 2026-01-20 | Bug Fixed: Serial communication. | |
| 1.16.3 | 2026-01-14 | Bug Fixed: Masimo IAP Protocol. | |
| 1.16.2 | 2026-01-03 | Added: BLE Support for Movesense devices on Raspberry Pi | |
| 1.16.1 | 2026-01-01 | Added: BLE Support for Movesense devices on Raspberry Pi and Linux versions. | |
| 1.16.0 | 2025-12-31 | Added: BLE Support for Movesense devices | |
| 1.15.16 | 2025-09-18 | Bug Fixed: Restoring last window position. | |
| 1.15.15 | 2025-09-05 | Added: CPU optimization Bug fixed: Masimo IAP protocol. | |
| 1.15.14 | 2025-09-04 | Added: CPU optimization | |
| 1.15.13 | 2025-09-04 | Bug Fixed: Masimo IAP Protocol. | |
| 1.15.12 | 2025-09-04 | Bug Fixed: Hardware handshake for Link+ connection. | |
| 1.15.11 | 2025-09-01 | Added: Recording alarm messages for Drager anesthesia machines | |
| 1.15.10 | 2025-07-14 | Bug Fixed: Sampling rate estimation in Medibus protocol. | |
| 1.15.9 | 2025-06-03 | Bug Fixed: EEG waveform labels from Philips monitors. | |
| 1.15.8 | 2025-05-26 | Added: EM_UPLOAD option to upload vital files to server immediately | |
| 1.15.7 | 2025-05-26 | Bug Fixed: Websocket connection error | |
| 1.15.6 | 2025-05-19 | Bug Fixed: S5 checksum error | |
| 1.15.5 | 2025-04-17 | Bug Fixed: saving the raw data | |
| 1.15.4 | 2025-04-15 | Added: Recording alarms from Philips monitor | |
| 1.15.3 | 2025-04-14 | Bug fixed: saving the raw data | |
| 1.15.2 | 2025-03-12 | Fixed: bug in opening file | |
| 1.15.1 | 2025-01-30 | Supporting for Fresenius Kabi Conox, Minor Bug fixes | |
| 1.14.13 | 2025-01-18 | Fixed bug in handling non-ascii filepath | |
| 1.14.12 | 2024-11-20 | Fixed: bug in 64bit ARM Architecture | |
| 1.14.11 | 2024-10-24 | Added: feature for updating to a specific version | |
| 1.14.10 | 2024-10-22 | Fixed: bug in json streamming | |
| 1.14.9 | 2024-10-17 | Added: montype for drug rates |
| Version | Date | Changes | |
|---|---|---|---|
| 1.18.45 | 2026-06-16 | 1.18.45 Fixed: Windows VR 에서 사용자가 외부에서 vr.conf 를 멀티베드 설정으로 교체 후 VR 을 재실행하면, 첫 실행에서는 멀티탭이 정상 생성되지만 다음 실행에서 모든 탭이 사라지던 문제. 원인은 VRApp.cpp:1110 의 VRCODE 미설정 분기 — 새 vr.conf 가 VRCODE 라인을 포함하지 않으면 load_settings() 가 신규 VRCODE 를 issue_code() 로 발급하고 즉시 save_settings() 를 호출하는데, 이 시점은 load_settings() 가 파싱한 베드들이 로컬 newbeds 벡터에만 있고 아직 m_pdisps 로 옮겨지기 전 (set_beds(newbeds) 는 initialize() 가 load_settings 반환 후 라인 1328 에서 호출). 결과: save_settings() 가 빈 m_pdisps 를 iterate 하며 vr.conf 를 글로벌 설정만으로 덮어써 모든 [BED/...] 섹션이 디스크에서 사라짐. 첫 실행은 메모리의 newbeds 로 UI 멀티탭이 그려져 정상으로 보이지만 (사용자가 "멀티탭은 정상적으로 생성되지만" 으로 표현), VR 종료/재실행 시 디스크 conf 에는 BED 섹션이 없으므로 다음 load_settings 가 빈 베드 리스트를 반환 → 탭 전부 사라짐. 수정: VRApp.h 에 m_vrcode_newly_issued bool 플래그 추가, load_settings 의 즉시 save 를 플래그 set 만 으로 교체, initialize() 의 set_beds(newbeds) 직후 (m_pdisps 가 채워진 시점) 플래그가 켜져 있으면 한 번만 save_settings() 호출 → BED 섹션이 정상 직렬화됨. Linux/Pi 분기 (m_serial_number 가 채워져 있는 경우) 는 원래도 save 안 했으므로 영향 없음, VRCODE 가 이미 conf 에 있는 모든 기존 deployment 도 분기 미진입으로 0-impact. m_conf_from_stdin / m_bDebug 모드는 save_settings 내부에서 이미 early return 이라 그대로 안전. MFC + Qt 빌드 모두 통과 (이번 변경 관련 0 warning). | |
| 1.18.44 | 2026-06-12 | 1.18.44: vr.conf FHIR=1 모드 추가 (자체 FHIR 수신서버 대상 실시간 푸시) + VS 2026 / 새 OpenSSL 인스톨러 빌드 환경 호환 shim. (1) sendweb_thread_func 의 기존 HL7/JSON 양분 분기 (VRApp.cpp:2466) 옆에 bFHIR 분기 추가. 1초 tick 마다 한 vrcode 의 모든 방 Observation 을 하나의 FHIR R4 collection Bundle 로 묶어 기존 WSS 채널로 push (gzip + WSSClient 인프라 그대로 재사용). MLLP 같은 신규 transport 안 도입 — FHIR R5 Subscription 의 websocket channel type 과 동형이라 표준 부합. (2) DISPLAY::get_fhir + TRACK::get_fhir 신규. v2 (vitaldb-fhir-v2) 와 동일한 reference-only 패턴 (Patient.id = m_patient_id, Encounter.id = vrcode-bedname-startsec, Observation.subject/encounter = relative reference) + hybrid keyframe: 첫 tick / m_patient_id 변경 / get_start_time() 변경 / 5분 경과 중 하나라도 발생 시 다음 tick Bundle 에 Patient + Encounter resource 를 inline. 그 외 tick 은 Observation 만. 수신서버가 도중에 새로 connect 해도 최대 5분 안에 자동 동기화 (keyframe heartbeat). DISPLAY 에 m_fhir_pt_sent_at/m_fhir_pt_last_id/m_fhir_enc_last_start 3개 멤버 추가 (m_setting_sent 패턴 그대로 per-display). (3) Observation 인코딩: NUM 은 effectiveDateTime + valueQuantity 각 데이터 포인트당 한 entry, WAV 은 effectivePeriod + valueSampledData (period=1000/srate ms, factor=1, origin=0, data=공백구분 floats) 한 entry. CO2/AWP wav 는 기존 get_json 처럼 25Hz 다운샘플 유지. NUM 은 m_montype 기반 LOINC 매핑 15개 등록 (ECG_HR/PLETH_HR=8867-4, PLETH_SPO2=59408-5, NIBP/IABP SBP/DBP/MBP=8480-6/8462-4/8478-0, BT=8310-5, RR=9279-1, etCO2=19891-1, CVP=8556-0, FETAL_HR=11627-3) + VR 자체 코드 시스템 (https://vitaldb.net/fhir/CodeSystem/track, code = dname/tname) 항상 동반. m_patient_id 미설정 (PATIENT_ID_UNSET) 시 anon-vrcode-bedname identifier 로 fallback. (4) Bundle wrapper: VRApp 가 방별 entries 를 콤마로 합쳐 {resourceType:Bundle, type:collection, timestamp:iso8601Z, entry:[...]} 로 wrap, 기존 gzip → WSS pipeline 동일. ISO 8601 UTC 헬퍼는 std::gmtime_s/gmtime_r 인라인. FHIR id 안전화 (A-Za-z0-9-.) 64자 제한 lambda 각 함수에 inline. (5) 빌드 환경 호환성: VRQt/CMakeLists.txt 에 _SILENCE_EXPERIMENTAL_COROUTINE_DEPRECATION_WARNINGS 추가 — VS 2026 (MSVC 14.51+) 의 STL 이 <experimental/coroutine> deprecation 을 warning → hard static_assert 로 바꾼 것이 cppwinrt 의 winrt::* (Serial.cpp 의 Bluetooth LE) 를 끌어오는 모든 TU 에서 컴파일 실패 시켜서, build_mfc.py 가 이미 CL env 로 주입하던 것과 동치 shim 을 Qt 쪽에도. (6) VRQt/CMakeLists.txt 의 OpenSSL link 경로 시프트. 새 OpenSSL 인스톨러가 libssl_static.lib / libcrypto_static.lib 를 lib/VC/x64/{MT,MTd}/ 에 두고 v1.x 의 libssl64MT.lib / libcrypto64MT.lib 네이밍과 lib/VC/static 경로를 깬다. build_mfc.py 의 %LOCALAPPDATA%/openssl-compat 패턴 (옛 이름으로 복사한 사본 폴더) 을 그대로 따라 CMakeLists 도 그 폴더가 있으면 우선, 없으면 옛 lib/VC/static 으로 fallback. 부트스트랩 스크립트는 build_mfc.py 의 docstring 참조 (한 줄). MFC + Qt + RPi + Ubuntu CLI + AppImage 빌드 모두 통과. 동작 영향: vr.conf 에 FHIR=1 추가 안 한 기존 deployment 는 sendweb 가 종전 JSON 모드 그대로 (HL7=1 만 분기보다 우선) — 0-impact migration. | |
| 1.18.43 | 2026-05-21 | 1.18.43: 멀티베드 console (PACU 10베드 Pi) syslog noise 80,500/hr → ~1,400/hr (-98.3%), cpu_usage 측정 1.16.12 (9f26e36) 이후 8년치 영구 -1 버그 수정, 멀티베드 환경 베드 식별용 [bedname / devicename] 로그 prefix 도입. 동기는 PACU production Pi (1.18.40) 4일치 syslog 분석 — 1.24M 라인 중 vr 라인 836K, idle 8시간 평균 시간당 80,500 라인 (베드 10 × 1초마다 "Waiting for next patient" × syslog 2x 중복). (1) VRApp.cpp:2696-2710 timer_thread_func 의 cpu usage 계산이 `if (totalcpu && m_cpu_total_last && totalcpu > m_cpu_total_last)` 가드 안에서만 m_cpu_total_last 갱신해 첫 호출 시 m_cpu_total_last=0 → else 분기 → -1 → m_cpu_total_last 갱신 안 됨 → 영원히 false → 영원히 -1 데드락. PACU 1,048 샘플 100% -1 실측 확인. m_cpu_total_last/m_cpu_used_last 갱신을 if 밖으로 빼서 첫 호출만 baseline 으로 -1, 두 번째 (60s 후) 부터 정상 측정. /proc/stat 의 iowait/irq/softirq 까지 7개 필드 fscanf 로 정확도 ±5% 개선. 부수: 같은 함수의 cpu_temp 가 `temp / 1000` int 나눗셈으로 소수점 절단되어 PACU 측정값이 정수 50/51/...,/58 9종만 출력 (millidegree 정밀도 손실) → `temp / 1000.0f` 로 fix. ram 계산은 `(totalram + totalswap) * mem_unit` 결과에 다시 mem_unit 곱하던 차원 혼용 (Linux 가 mem_unit=1 이라 우연히 정상 동작했지만 dimensionally wrong) → `(units1 + units2) * mem_unit` 로 정정 + underflow 가드. (2) DISPLAY::log(string/printf) + DEVICE::log(string/printf) 멤버 추가. DISPLAY::log 는 `[bedname] msg`, DEVICE::log 는 m_pdisp 위임 없이 직접 `[bedname / devicename] msg` 한 줄 prefix (nested `[bed] [dev]` 보다 가독성 우선). m_pdisp 또는 bedname null 케이스 safe fallback. (3) show_msg 의 console path TRACE 를 log() 로 교체 → "Waiting for next patient" 자동 [bedname] prefix. ADT patient id unset 도 log() 로. (4) 이미 수동으로 get_bedname() 을 인자로 넘기던 8군데 (DISPLAY ptcon_thread_func / add_trk / add_dev / del_dev / cut-recording, Device add_rec 콜백, FILT stop, VRApp add_tab/del_tab) 를 log() 로 전환 — 이중 prefix 방지 + 일관성. Serial::reading_thread / tcp_thread / open_socket waiting / timeout / interrupted / got-client 6군데 DEVICE::log() 전환 → `[bedname / Intellivue]` 등 자동 prefix, 멀티탭 환경에서 어느 베드 어느 device 출처인지 즉시 식별. (5) wss 재시도 폭주 throttle. WSSClient 에 m_verbose (debug step 로그 게이트) + m_dt_last_err_log (60s window) 추가. connect() 내부 step-by-step TRACE 4개 ("connecting" / "connect error" / "connected") 는 m_verbose 가드, 최종 "wss connect error" 는 60s window throttle (첫 줄 즉시, 그 다음 60s 1회). connect 성공 path 에서 throttle reset 으로 다음 disconnect → 첫 에러 즉시 로깅. sendweb_thread_func 의 "connecting websocket server" 호출자 라인도 같은 60s window, m_bDebug 면 verbose 활성화. PACU idle 8h 측정 7,024/hr (4종 × 1,756) → 약 60/hr (-99%). (6) "Waiting for next patient" / "ADT patient id unset" 의 60s throttle 자체는 feature/wav-mem-retention 브랜치 ptcon_thread_func 재구성 (b75928f 시리즈) 에서 이미 들어가 있어 이 릴리즈에 자동 포함. 종합 영향: idle 시간당 syslog 라인 80,500 → ~1,400 (-98.3%), active 시간당 14,900 → ~700 (-95%). 진단 측면: cpu_usage 가 부활하면서 웹모니터링 json 의 cpu_usage 필드도 한 번도 안 채워지던 게 정상 전송 (VRApp.cpp:2499 의 `if (m_cpu_usage > 0)` 가드가 영원히 false 였음). 별건: syslog 라인 2× 중복은 application 측이 아니라 rsyslog imuxsock + imjournal + journald.ForwardToSyslog=yes 의 Debian Bookworm 전형 misconfig — admin 측 fix (rsyslog.conf 에서 imjournal 주석 처리 + restart) 로 추가 50% 감소 가능 (별도 문서). MFC + Qt + Pi (RPI64) + Ubuntu CLI 빌드 모두 통과. | |
| 1.18.41 | 2026-05-13 | 1.18.41 Hotfix: TCP-server protocol-initiator device (Intellivue/S5/Datex/Hamilton/MPS/Agilia/IAP) 가 open() 직후 보내는 첫 패킷이 wire 에 안 나가던 회귀. 1.18.34 의 PortRouter refactor 가 Serial::open_socket() 의 8초 handoff blocking 을 제거하고 비동기 모델로 전환했는데, protocol-initiator 의 open() 코드가 m_sock=INVALID 상태에서 write 를 시도해 silent fail (Linux 는 m_fd=0 이라 false 반환). Intellivue 케이스 production journald 의 Pi → ESP TX 700K~3M bytes 는 monitor 측 abort 로 늦게 트리거된 AB_SPDU_SI recovery assoc_req 후 request_thread 의 정상 polling 트래픽이지만 일부 베드 (abort 없는 monitor) 는 recovery 도 안 되어 영구 silent (RX 300 bytes). 수정 방향: open() 의 옛 contract ("return 시점에 통신 가능") 복구. (1) Serial::open_socket() TCP-server 분기가 PortRouter::subscribe 후 m_sock_cv 로 첫 client handoff 까지 block (timeout = device read_timeout, 기본 30s) — 옛 모델 그대로. lock_and_open 이 false 면 다음 tick 에서 retry. close 신호로 abort 가능. (2) Serial::close() 는 PortRouter::unsubscribe 안 함 — subscribe 는 device 생애 동안 sticky 라 read_timeout 으로 인한 close→re-open 사이클 동안 listen socket 이 유지되어 1.18.29/1.18.34 의 anti-churn 이익 보존. unsubscribe 는 ~Serial() 에서만. (3) Per-device lifecycle thread (DEVICE::m_thread_restart): 각 device 가 자기 open/close/timeout 재시작을 별도 thread 에서 관리. 옛 모델의 DISPLAY::bed_manager 가 베드의 모든 device 를 sequential iterate 하던 구조에선 한 device 의 blocking open() 이 같은 베드의 다른 device 의 lifecycle 을 차단했는데, per-device thread 로 분리하여 멀티 device 베드도 병렬 진행. add_dev 에서 start_lifecycle, del_dev / ~DISPLAY 에서 stop_lifecycle. (4) Serial::tcp_thread_func 단순화 — outer m_sock_cv wait 패턴 (1.18.34/1.18.39 가 추가했던 것) 제거. open_socket 이 m_sock valid 보장하므로 reader thread 시작 시점에 simple inner recv loop 만. accept_handoff 의 replace (zombie cleanup) 케이스는 recv error 후 m_sock 변경 확인 + retry 로 처리. (5) reading_thread_func 의 `else if (m_sock != INVALID_SOCKET) tcp_thread_func();` 가드 복원 (1.18.39 가 제거). (6) Serial::write 의 silent-fail 케이스에 WARN trace 추가 — 미래 동종 회귀 즉시 노출. (7) PortRouter::subscribe 가 같은 (port, type) 에서 같은 IP filter 또는 둘 이상 catch-all 발견 시 reject (config 실수 원천 차단, 옛 WARN-only 동작 강화). (8) DISPLAY::bed_manager_thread_func 의 restart 블록 제거 — ptcon + adt 만 담당. "Waiting for next patient" TRACE 가 Linux/console 에서 1초 → 60초마다 throttle (별개 journald 부풀림 fix). 영향 범위: Intellivue / S5 / Datex / Hamilton / MPS / Agilia / IAP TCP-server 모드 베드 전부. 1.18.34 이후 우회 방법은 race-win 케이스 (VRN 이 PortRouter::subscribe 직후 connect) 외엔 없었음. MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.40 | 2026-05-12 | Hotfix: Drager Medibus 프로토콜 사용 베드에서 1.15.11 이후 vr.service 가 SIGSEGV 로 무한 재시작하던 문제. 1.15.10 (a8c7b2a) 의 "Sampling rate estimation" 리팩터링이 m_ptrk_awp/awf/co2 트랙을 add_trks() 에서의 eager 생성 (default srate=62.5Hz) 에서 realtime data 100 샘플 모인 후 lazy 생성으로 바꿨는데, Medibus 핸드셰이크 순서 (0x51 ICC → 0x52 DeviceID → 0x53 RealtimeConfig 응답 → 0x54 → realtime data 시작) 상 0x53 응답 핸들러 (Drager.cpp:295-307) 가 트랙들이 아직 nullptr 인 시점에 `ptrk->m_srate = 1000000.0/interval` 로 NULL 역참조 → 즉시 SEGV. 그 베드의 vr.service 가 systemd Restart=on-failure 로 재시작 → 다시 connect → 동일 0x53 패킷 받고 동일 SEGV → 무한 루프 (journald 로그상 restart counter 61 까지 누적, code=killed status=11/SEGV). 1.15.9 까진 트랙이 add_trks() 에서 생성되어 0x53 도착 시 항상 non-NULL 이라 안전했음. 수정: (a) add_trks() 에서 m_ptrk_awp/awf/co2 eager 생성 복원 (srate=62.5Hz default) — 0x53 는 ptrk->m_srate 만 갱신 (트랙 재생성 X). (b) on_received() 의 lazy creation + packet-timing srate 추정 블록 제거 — 0x53 가 권위 있는 srate 소스이고 packet 타이밍 기반 추정은 network jitter 에 약해 불안정. (c) 0x53 핸들러에 `if (interval > 0)` guard 추가 — 페이로드 깨졌을 때 div-by-zero / inf srate 방지. 영향 범위: Drager Primus / Apollo / Perseus / Fabius 등 Medibus 사용 마취기 전부. 우회 방법은 1.15.9 다운그레이드 외엔 없었음 (그 베드의 모든 데이터 유실 + 환자 모니터링 불가). MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.39 | 2026-05-08 | Fixed: PortRouter (TCP server) 모드에서 reader thread 가 startup 시점에 죽어 client 데이터를 영구히 못 받던 문제. 1.18.34 (9bd252f) 의 PortRouter refactor 가 m_sock 세팅을 dispatch 시점으로 옮겼는데 reading_thread_func (Serial.cpp:354) 의 가드 `else if (m_sock != INVALID_SOCKET) tcp_thread_func();` 는 옛 모델 (open 시점 이미 connect 완료) 가정 그대로라 — 시작 직후 m_sock=INVALID 면 tcp_thread_func 진입 안 하고 reader thread 즉시 종료. 이후 VRN 이 connect → PortRouter::dispatch → accept_handoff 가 m_sock 채우고 m_sock_cv.notify_all() → 그러나 wait 중인 reader 가 없음 (이미 죽음) → kernel recv buffer 에만 데이터 적재. 증상은 ss -tn state established 의 Recv-Q 가 0 이 아닌 값 (수백 bytes) 으로 누적, 베드 화면에는 데이터 안 들어옴. 그 베드의 VRN 이 Serial::open() 의 PortRouter::subscribe 직후~reader thread spawn 사이의 짧은 윈도우 안에 connect 한 경우만 우연히 정상 동작 (race-win). 수정: 가드 제거 — TCP 분기에 항상 진입. tcp_thread_func 자체에 이미 m_sock_cv outer-wait 루프가 있어 m_sock 이 INVALID 인 동안 dispatch 가 깨워줄 때까지 안전하게 대기. Pi 핫스팟에 VRN 여러 대 (e.g. 10.42.0.21~25) 를 같은 (4343, Philips:Intellivue) 키로 묶고 IP filter 로 라우팅하는 시나리오에서 가장 자주 노출. Added: 진단 로그 보강 — PortRouter::accept_loop 의 accept 이벤트, dispatch 의 라우팅 결정 (ip_specific/catch_all subs 수, 어느 dev 가 받았는지), subscribe/unsubscribe 의 entry 생성/append/destroy, reading_thread / tcp_thread 의 시작·wait·wake 라이프사이클 — 이전엔 모두 m_bDebug 게이트 안에 있어서 production journald 에서 안 보였는데, 이제 항상 출력 (이번 같은 dispatch routing 문제 진단을 production 에서 바로 가능). MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.38 | 2026-05-08 | Fixed: 웹모니터링 우클릭 → 디바이스 세팅 (websocket edit_bed 명령) 으로 베드의 device/filter 를 변경할 때 베드 이름이 매번 "_2" suffix 로 자동 리네임되어 vr.conf (Pi: /data/vr.conf) 에 잘못된 이름으로 저장되던 문제. 원인은 1.18.22 (cda8aa5) 에서 add_bed 에 추가된 bedname dedup ("최후 방어선" 으로 forward_frame auto-create / 수동 편집된 conf 의 중복 이름 처리용). edit_bed 핸들러는 옛 pdel 이 m_pdisps 에 그대로 있는 상태에서 같은 bedname 으로 new DISPLAY 를 add_bed 하고 그 다음 del_bed(pdel) 하는 순서였는데, add_bed 가 dup 감지해 새 pdisp 를 bedname_2 로 자동 리네임 → save_settings 가 [BED/bedname_2] 로 직렬화 → 사용자 입장에선 "설정 적용 안됨" 으로 보였다. 추가로 옛/새 DISPLAY 가 잠깐 m_pdisps 에 공존하면서 같은 device 포트를 동시에 들고 있으려 해 로그가 dup 으로 찍히는 부수 증상도 있었음. 수정: del_bed(pdel) 를 add_bed(pdisp) 보다 앞으로 이동 — 옛 베드의 device 포트가 깨끗이 release 된 뒤 새 pdisp 가 같은 포트를 reopen, dedup 발동 안 함. 다른 베드의 recording 은 영향 없음 (인메모리 hot swap 설계 유지). 부수: edit_bed 핸들러의 데드 코드 (`break` 뒤의 unreachable olddevs populate 루프 + `if (olddevs.find(name) == olddevs.end())` 항상-true 래퍼) 정리. edit_conf 와 save_settings 는 손대지 않음. MFC + Qt + Pi (RPI64) 빌드 모두 통과. | |
| 1.18.37 | 2026-05-08 | Refactored: 필터 다이얼로그의 python 런타임 — pyvital → openvital 0.3.0 로 교체 + 동봉 python.zip 슬림화. 핵심 동기 셋: (1) pyvital 0.6.0 이 tensorflow+torch+keras 를 hard-dep 으로 끌어들여 PyPI upgrade 가 사실상 깨짐, (2) 기존 zip 121 MB 안에 botocore/aiobotocore/s3fs/pyarrow/pandas/aiohttp 등 vitaldb 클라우드 업로드용 deps 가 ~250 MB unpacked 차지 — 필터 서버는 한 번도 쓴 적 없는 dead weight, (3) sanic 25.x 의 multi-process worker 가 openvital __main__.py 를 fork 후 재import 하면서 worker 가 module-top app instance 를 못 찾아 "Sanic app name not found" 로 죽음 — 단순 endpoint 2개 로컬호스트 서버에 async stack 자체가 과함. 해결: openvital 0.3.0 (commit b6f445b) 가 sanic 을 stdlib http.server (BaseHTTPRequestHandler + HTTPServer) 로 50 LOC 재작성 — wire protocol (GET / 필터목록 JSON, POST /<modname> gzip 본문) 동일해 VR 클라이언트 변경 0줄. 단일 스레드로 기존 sanic event loop semantics (cfgs/default_cfgs lock-free 변경) 보존. build_python_zip.py (NEW) 가 Python 3.11.9 embed + numpy + openecg + openvital (local checkout 우선, fallback PyPI) 만으로 27 MB zip 빌드 — 기존 121 MB 대비 78% 감소. ML 필터 (sv_dlapco/abp_hpi/ecg_classifier/ecg_beat_noise_detector) 는 [Hybrid 모델] 사용자가 Add filter 다이얼로그의 "Install ML filters" 버튼 누를 때 silent pip install openvital[all] (cmd 창 미노출 — VRApp::install_pip_package + run_pip_silent 이 자체 progress 다이얼로그에 stdout heartbeat 흘림). 버튼 라벨은 "Upgrade pyvital" → "Install ML filters" 로 의도 명시. openvital __main__.py 가 missing extras 를 graceful skip 하므로 base 환경에서도 11개 필터 (ECG QRS detector, HRV, MTWA, annotator, eeg_fft, nirs_cox, pkpd_3comp, pleth_dpop/ptt/pvi, resp_compliance) 즉시 사용 가능. Migration: 기존 사용자의 user_dir/python 폴더는 pyvital + 옛 deps 가 그대로 남아있고 vitaldb.net/python.zip 만 새로 올리면 (a) 기존 폴더 삭제 후 install_python 으로 새 zip 받으면 깔끔, (b) 폴더 유지 시 server 가 openvital 못 찾아 필터 다이얼로그 에러 → release note 에 명시 필요. MFC + Qt 양쪽 코드: VRGui.rc 의 IDC_UPGRADE 버튼 라벨 + DlgAddFilter.cpp 의 dist-info prefix 매칭 (pyvital- 8자 → openvital- 10자) + QtDlgAddFilter.cpp 도 동일 변경 + onUpgrade 가 cmd /k QProcess::startDetached 대신 theApp.install_pip_package("openvital[all]") 호출 (Linux Qt 빌드는 #ifdef _WIN32 가드). VRApp.cpp:318 의 python -m pyvital → -m openvital. install_pip_package 는 anonymous namespace 의 is_safe_pkg_spec 화이트리스트 검증 + run_pip_silent (CreateProcessA + CREATE_NO_WINDOW + 자식 stdout pipe) + CDlgProgress / QtDlgProgress 자체 progress UI. 빌드 검증: python -m openvital 이 GET / 로 11 필터 반환, sanic import 부재 확인. zip 27.5 MB. | |
| 1.18.36 | 2026-05-07 | Fixed: 3-파티션 레이아웃 (boot/rootfs/data) 에서 websocket edit_conf / update 명령이 read-only fs 로 실패하던 문제. vr.conf 는 /data 폴더가 있으면 /data/vr.conf 로 자동 정착 — get_conf_path() 가 write target 으로 결정, load_settings() 는 primary 가 없으면 legacy /boot/firmware/vr.conf 또는 /boot/vr.conf 에서 fallback read 후 다음 save 부터 primary 로 자동 이전 (마이그레이션 step 없음, legacy 파일은 read-only fs 라 무해). binary update (upgrade_now) 는 RAII BootRwGuard 가 dirname(module_path) 를 잠시 rw remount, scope 종료 시 sync() + MS_REMOUNT|MS_RDONLY 로 자동 ro 복귀 — vfat 노출 윈도우 최소화 + exception/return 어디서든 복구 보장. statvfs ST_RDONLY 검사로 이미 rw 인 fs (x86 dev) 에서는 no-op, non-Linux (macOS) 는 stub 으로 통과. save_settings() 의 silent EROFS 실패가 TRACE 로 가시화 (이전엔 무시되어 conf 수정 안 먹는 원인 추적 불가). 부수: PortRouter.cpp 가 commit 9bd252f 이후 CMakeLists 의 RPI sources 목록에서 누락되어 Pi 빌드 link 에러 — 추가. | |
| 1.18.35 | 2026-05-01 | Added: alarm parsing for Mindray HL7 (eGateway ORU^R40) and Nihon Kohden (NealTime HL7GW + ORF, BSM serial D-port, EGA UDP) - emits ALARM_STATUS / ALARM_MESSAGE / ALARM_PRIORITY tracks (same 3-track schema already used by Philips IntelliVue, GE Solar/Dash, GE/Datex S5); type info preserved via [T]/[A]/[ARR] message prefixes; Mindray facet 1/5/6/7 walker with 92-entry MDC+MNDRY alarm code lookup; NK HL7GW parses OBR-4=EVENT with arrhythmia/technical disambiguation by OBX-5; NK BSM serial decodes per-parameter * flags (edge-triggered to avoid 1Hz flooding) plus 32-bit Table 9 arrhythmia bitmap, D19 alarm-suspend nibble, and the VPC CODE byte; NK EGA UDP extracts Priority + Tech Alarm + Arrhythmia from JSON Vital Sign packets with edge-trigger cache for start/end inference; ACK^R40 reply added for Mindray alert messages; simulators gained periodic alarm cycling for end-to-end smoke testing | |
| 1.18.34 | 2026-04-27 | Added: Linux Desktop Qt GUI build (VRQt) - first GUI build for Linux distributed as a self-contained AppImage (~32MB, Qt6 runtime + libGL/libEGL/libGLX/libOpenGL/libGLESv2/libGLdispatch bundled inside) so users on minimal Ubuntu/Debian/Fedora can run it without installing Qt or GL system packages; tested on AWS clean Ubuntu 22.04 cloud image; build via build_ubuntu_appimage.py which is now invoked by deploy.py; Fixed: Linux Qt right-side device/filter panels rendered with white background below cards because the inner listWidget did not autoFillBackground from parent palette on Linux Qt (Windows/macOS implicitly inherit, X11/Wayland do not); explicit stylesheet on listWidget; Added: Linux installation section in user manuals (EN/KO/ZH/ES) covering AppImage chmod+run flow and dialout group note for serial/USB device access | |
| 1.18.33 | 2026-04-25 | Fixed: Demo device never started since 1.18.11 (bed_manager skipped empty port_name as passive but Demo has no port and still needs lock_and_open); Fixed: Qt fit-to-window button rendered at top-left (0,0) instead of right-aligned in bottom nav bar; Fixed: Qt crash when closing tab / deleting device / deleting filter - paint dereferenced freed pointer before panel timer rebuilt items (added MFC-style stale-pointer guard to QtDeviceItem and QtFilterItem); Added: macOS DMG main window now shown on launch (restoreWindowPos had no Mac/Linux branch); Added: macOS Homebrew dylibs (openssl) bundled in Contents/Frameworks; Added: macOS .app bundle now notarized + stapled (drag-to-Applications no longer needs xattr -cr on first launch); Changed: Qt MSI ~1MB smaller (dropped unused iconengines and imageformats plugins) | |
| 1.18.32 | 2026-04-23 | Fixed: same-port multi-client TCP - primary now runs a continuous accept loop and hands off each connection to the matching sub by IP filter (previously second connection got rejected/listened closed); Added: @IP and #keyword port filters are now mutually exclusive per bed (IP wins, keyword dropped with WARN); Added: WARN log when two beds on the same port share an identical IP filter; Added: catch-all primary keeps its single connection and rejects extras (preserves broadcast mode) | |
| 1.18.31 | 2026-04-22 | Added: drug slot shows DOSE_AMOUNT (mg etc) in preference to VOL (mL) when available; Added: DOSE_RATE / DOSE_AMOUNT montypes bound to BBraun tracks for monitor view; Added: HL7 MDC_DOSE_DRUG_DELIV_TOTAL unit picked up dynamically from UCUM | |
| 1.18.30 | 2026-04-21 | Changed: monitor view pump layout - 8 slots with CE or RATE (CE-less pumps show infused volume as small annotation); Reverted: BBraun minimal=1 (1.18.29) - was dropping data from file, monitor view redesign handles display clutter instead | |
| 1.18.29 | 2026-04-21 | Fixed: BBraun multi-rack auto-tab data drop, primary TCP churn, save_settings lock race, TCP reader spin on peer close; Added: BBraun minimal=1 option (display only drug name / rate / volume) | |
| 1.18.28 | 2026-04-20 | Fixed: vr.conf on Pi/Linux now looked up next to executable (supports /boot/firmware); deploy.py --store auto-submits MSIX to Microsoft Store | |
| 1.18.27 | 2026-04-18 | Fixed: vital file periodic flush (5000s→5s bug), Fit-to-Window icon redesigned to match navigation button style | |
| 1.18.26 | 2026-04-18 | Fixed: periodic .vital file flush interval was 5000 seconds instead of 5 (unit-bug since comment said seconds but value was milliseconds). Data now actually reaches disk every 5 s during recording instead of only on close. | |
| 1.18.25 | 2026-04-18 | Fixed: BBraun HL7 rec_timeout raised 10s→60s to prevent primary churn during DoseLink R42→R01 phase transition and long idle periods | |
| 1.18.24 | 2026-04-18 | Fixed: GUI silently exits when another recorder running (now falls back to viewer mode), .vital file association written to HKCU (no admin required, auto-updates exe path on every run) | |
| 1.18.23 | 2026-04-18 | Fixed: atof decimal-separator bug on non-English Windows locales (rates <1.0 recorded as 0 in Norwegian/German/French etc.), BBraun HL7 pump limit raised from 8 to 16 | |
| 1.18.22 | 2026-04-18 | Fixed: multi-bed TCP port bind race on restart (Mindray/BBraun HL7 auto-reconnect without manual Add device) | |
| 1.18.21 | 2026-04-18 | Fixed: port name filter (#keyword@ip) lost on save, BBraun HL7 VMD-block parsing with single dt, Fit-to-Window button sizing (MFC) and added to Qt | |
| 1.18.20 | 2026-04-15 | BBraun: comprehensive protocol parsing (dose rate, infusion time, syringe, weight, drug amounts, delivery status) | |
| 1.18.19 | 2026-04-13 | Fixed: BBraun HL7 multi-pump identification (rack serial filtering), multi-bed forwarding, port filter parsing | |
| 1.18.18 | 2026-04-10 | Added: GE alarm limits, S5 alarm/ext3/ext1 parsing | |
| 1.18.17 | 2026-04-04 | Changed: TRACE debug-only guard, show_msg for file errors, deploy sequential builds | |
| 1.18.16 | 2026-04-04 | Added: TCP port filtering (#keyword@ip), frame forwarding for multi-bed. Fixed: --debug conf file mistaken as vital file, device type ambiguity in forwarding | |
| 1.18.15 | 2026-04-04 | Changed: Port to Port Name, keyword filter AND/OR (#kw1 kw2#kw3), IP postfix matching (@10.1), MEKICS SerialFramed | |
| 1.18.14 | 2026-04-03 | Added: TCP port filtering (#keyword@ip), Fixed: devtypes not sent on boot | |
| 1.18.13 | 2026-04-02 | Changed: Covidien company name to Medtronic (BIS, INVOS) | |
| 1.18.12 | 2026-04-02 | Bug Fixed: NihonKohden EGA SpO2 waveform not displayed (channel name mapping) | |
| 1.18.11 | 2026-03-31 | Added: Mindray HL7 multi-bed separation via PV1, auto-tab creation for EGA/Mindray | |
| 1.18.10 | 2026-03-31 | Added: HL7 ZBR segment now includes ver, os, arch, dgmt | |
| 1.18.8 | 2026-03-25 | Added: --demo mode for console operation with demo signals | |
| 1.18.7 | 2026-03-25 | Added: --console mode for headless operation on Windows | |
| 1.18.6 | 2026-03-25 | Added: Mindray eGateway HL7 protocol (IHE PCD-01, HL7 v2.6 over MLLP, waveform + numeric + infusion pump) | |
| 1.18.4 | 2026-03-24 | Added: BBraun SpaceCom HL7 protocol (HL7 v2.6 over MLLP, TCP server mode) | |
| 1.18.3 | 2026-03-24 | Added: HL7 OBX-14 per-track dtstart, ZBR segment with dtcase/dtapp timestamps | |
| 1.18.2 | 2026-03-24 | Added: HL7 ZBR segment with dtcase (recording start) and dtapp (app start) timestamps | |
| 1.18.1 | 2026-03-23 | Fixed: HL7 OBX-3 format (code^device/track@srate), OBX-7 refrange (min^max), NA null sample gaps | |
| 1.17.6 | 2026-03-22 | Bug fixed: Resource ID conflicts WiX installer cleanup | |
| 1.17.5 | 2026-03-21 | Bug fixed: Vital packed file loading MFC device button icon padding | |
| 1.17.4 | 2026-03-19 | Bug fixed: NirsitON EEG 250Hz VRQt device minimize/rename | |
| 1.17.3 | 2026-03-18 | Bug fixed: BBraun protocol NirsitON protocol VRQt | |
| 1.17.2 | 2026-03-14 | Added: NirsitOn NDI protocol support. | |
| 1.17.1 | 2026-03-12 | Added: VRQt | |
| 1.16.13 | 2026-03-07 | Added: New Setup File with VRQt | |
| 1.16.12 | 2026-03-06 | Added: Vector Type Icons | |
| 1.16.10 | 2026-03-02 | Bug fixed: Autodetecting BBraun Stuffing feature. | |
| 1.16.8 | 2026-02-27 | Bug fixed: Masimo IAP protocol. | |
| 1.16.4 | 2026-01-20 | Bug Fixed: Serial communication. | |
| 1.16.3 | 2026-01-14 | Bug Fixed: Masimo IAP Protocol. | |
| 1.16.2 | 2026-01-03 | Added: BLE Support for Movesense devices on Raspberry Pi | |
| 1.16.1 | 2026-01-01 | Added: BLE Support for Movesense devices on Raspberry Pi and Linux versions. | |
| 1.16.0 | 2025-12-31 | Added: BLE Support for Movesense devices | |
| 1.15.16 | 2025-09-18 | Bug Fixed: Restoring last window position. | |
| 1.15.15 | 2025-09-05 | Added: CPU optimization Bug fixed: Masimo IAP protocol. | |
| 1.15.14 | 2025-09-04 | Added: CPU optimization | |
| 1.15.13 | 2025-09-04 | Bug Fixed: Masimo IAP Protocol. | |
| 1.15.12 | 2025-09-04 | Bug Fixed: Hardware handshake for Link+ connection. | |
| 1.15.11 | 2025-09-01 | Added: Recording alarm messages for Drager anesthesia machines | |
| 1.15.10 | 2025-07-14 | Bug Fixed: Sampling rate estimation in Medibus protocol. | |
| 1.15.9 | 2025-06-03 | Bug Fixed: EEG waveform labels from Philips monitors. | |
| 1.15.8 | 2025-05-26 | Added: EM_UPLOAD option to upload vital files to server immediately | |
| 1.15.7 | 2025-05-26 | Bug Fixed: Websocket connection error | |
| 1.15.6 | 2025-05-19 | Bug Fixed: S5 checksum error | |
| 1.15.5 | 2025-04-17 | Bug Fixed: saving the raw data | |
| 1.15.4 | 2025-04-15 | Added: Recording alarms from Philips monitor | |
| 1.15.3 | 2025-04-14 | Bug fixed: saving the raw data | |
| 1.15.2 | 2025-03-12 | Fixed: bug in opening file | |
| 1.15.1 | 2025-01-30 | Supporting for Fresenius Kabi Conox, Minor Bug fixes | |
| 1.14.13 | 2025-01-18 | Fixed bug in handling non-ascii filepath | |
| 1.14.12 | 2024-11-20 | Fixed: bug in 64bit ARM Architecture | |
| 1.14.11 | 2024-10-24 | Added: feature for updating to a specific version | |
| 1.14.10 | 2024-10-22 | Fixed: bug in json streamming | |
| 1.14.9 | 2024-10-17 | Added: montype for drug rates | |
| 1.14.6 | 2024-09-20 | Added: montype for drug rates | |
| 1.14.5 | 2024-09-13 | Added: auto cutting by any of hr or spo2 | |
| 1.14.4 | 2024-09-12 | Fixed: bug in serial port mapping |
| Version | Date | Changes | |
|---|---|---|---|
| 1.18.45 | 2026-06-16 | 1.18.45 Fixed: Windows VR 에서 사용자가 외부에서 vr.conf 를 멀티베드 설정으로 교체 후 VR 을 재실행하면, 첫 실행에서는 멀티탭이 정상 생성되지만 다음 실행에서 모든 탭이 사라지던 문제. 원인은 VRApp.cpp:1110 의 VRCODE 미설정 분기 — 새 vr.conf 가 VRCODE 라인을 포함하지 않으면 load_settings() 가 신규 VRCODE 를 issue_code() 로 발급하고 즉시 save_settings() 를 호출하는데, 이 시점은 load_settings() 가 파싱한 베드들이 로컬 newbeds 벡터에만 있고 아직 m_pdisps 로 옮겨지기 전 (set_beds(newbeds) 는 initialize() 가 load_settings 반환 후 라인 1328 에서 호출). 결과: save_settings() 가 빈 m_pdisps 를 iterate 하며 vr.conf 를 글로벌 설정만으로 덮어써 모든 [BED/...] 섹션이 디스크에서 사라짐. 첫 실행은 메모리의 newbeds 로 UI 멀티탭이 그려져 정상으로 보이지만 (사용자가 "멀티탭은 정상적으로 생성되지만" 으로 표현), VR 종료/재실행 시 디스크 conf 에는 BED 섹션이 없으므로 다음 load_settings 가 빈 베드 리스트를 반환 → 탭 전부 사라짐. 수정: VRApp.h 에 m_vrcode_newly_issued bool 플래그 추가, load_settings 의 즉시 save 를 플래그 set 만 으로 교체, initialize() 의 set_beds(newbeds) 직후 (m_pdisps 가 채워진 시점) 플래그가 켜져 있으면 한 번만 save_settings() 호출 → BED 섹션이 정상 직렬화됨. Linux/Pi 분기 (m_serial_number 가 채워져 있는 경우) 는 원래도 save 안 했으므로 영향 없음, VRCODE 가 이미 conf 에 있는 모든 기존 deployment 도 분기 미진입으로 0-impact. m_conf_from_stdin / m_bDebug 모드는 save_settings 내부에서 이미 early return 이라 그대로 안전. MFC + Qt 빌드 모두 통과 (이번 변경 관련 0 warning). | |
| 1.18.44 | 2026-06-12 | 1.18.44: vr.conf FHIR=1 모드 추가 (자체 FHIR 수신서버 대상 실시간 푸시) + VS 2026 / 새 OpenSSL 인스톨러 빌드 환경 호환 shim. (1) sendweb_thread_func 의 기존 HL7/JSON 양분 분기 (VRApp.cpp:2466) 옆에 bFHIR 분기 추가. 1초 tick 마다 한 vrcode 의 모든 방 Observation 을 하나의 FHIR R4 collection Bundle 로 묶어 기존 WSS 채널로 push (gzip + WSSClient 인프라 그대로 재사용). MLLP 같은 신규 transport 안 도입 — FHIR R5 Subscription 의 websocket channel type 과 동형이라 표준 부합. (2) DISPLAY::get_fhir + TRACK::get_fhir 신규. v2 (vitaldb-fhir-v2) 와 동일한 reference-only 패턴 (Patient.id = m_patient_id, Encounter.id = vrcode-bedname-startsec, Observation.subject/encounter = relative reference) + hybrid keyframe: 첫 tick / m_patient_id 변경 / get_start_time() 변경 / 5분 경과 중 하나라도 발생 시 다음 tick Bundle 에 Patient + Encounter resource 를 inline. 그 외 tick 은 Observation 만. 수신서버가 도중에 새로 connect 해도 최대 5분 안에 자동 동기화 (keyframe heartbeat). DISPLAY 에 m_fhir_pt_sent_at/m_fhir_pt_last_id/m_fhir_enc_last_start 3개 멤버 추가 (m_setting_sent 패턴 그대로 per-display). (3) Observation 인코딩: NUM 은 effectiveDateTime + valueQuantity 각 데이터 포인트당 한 entry, WAV 은 effectivePeriod + valueSampledData (period=1000/srate ms, factor=1, origin=0, data=공백구분 floats) 한 entry. CO2/AWP wav 는 기존 get_json 처럼 25Hz 다운샘플 유지. NUM 은 m_montype 기반 LOINC 매핑 15개 등록 (ECG_HR/PLETH_HR=8867-4, PLETH_SPO2=59408-5, NIBP/IABP SBP/DBP/MBP=8480-6/8462-4/8478-0, BT=8310-5, RR=9279-1, etCO2=19891-1, CVP=8556-0, FETAL_HR=11627-3) + VR 자체 코드 시스템 (https://vitaldb.net/fhir/CodeSystem/track, code = dname/tname) 항상 동반. m_patient_id 미설정 (PATIENT_ID_UNSET) 시 anon-vrcode-bedname identifier 로 fallback. (4) Bundle wrapper: VRApp 가 방별 entries 를 콤마로 합쳐 {resourceType:Bundle, type:collection, timestamp:iso8601Z, entry:[...]} 로 wrap, 기존 gzip → WSS pipeline 동일. ISO 8601 UTC 헬퍼는 std::gmtime_s/gmtime_r 인라인. FHIR id 안전화 (A-Za-z0-9-.) 64자 제한 lambda 각 함수에 inline. (5) 빌드 환경 호환성: VRQt/CMakeLists.txt 에 _SILENCE_EXPERIMENTAL_COROUTINE_DEPRECATION_WARNINGS 추가 — VS 2026 (MSVC 14.51+) 의 STL 이 <experimental/coroutine> deprecation 을 warning → hard static_assert 로 바꾼 것이 cppwinrt 의 winrt::* (Serial.cpp 의 Bluetooth LE) 를 끌어오는 모든 TU 에서 컴파일 실패 시켜서, build_mfc.py 가 이미 CL env 로 주입하던 것과 동치 shim 을 Qt 쪽에도. (6) VRQt/CMakeLists.txt 의 OpenSSL link 경로 시프트. 새 OpenSSL 인스톨러가 libssl_static.lib / libcrypto_static.lib 를 lib/VC/x64/{MT,MTd}/ 에 두고 v1.x 의 libssl64MT.lib / libcrypto64MT.lib 네이밍과 lib/VC/static 경로를 깬다. build_mfc.py 의 %LOCALAPPDATA%/openssl-compat 패턴 (옛 이름으로 복사한 사본 폴더) 을 그대로 따라 CMakeLists 도 그 폴더가 있으면 우선, 없으면 옛 lib/VC/static 으로 fallback. 부트스트랩 스크립트는 build_mfc.py 의 docstring 참조 (한 줄). MFC + Qt + RPi + Ubuntu CLI + AppImage 빌드 모두 통과. 동작 영향: vr.conf 에 FHIR=1 추가 안 한 기존 deployment 는 sendweb 가 종전 JSON 모드 그대로 (HL7=1 만 분기보다 우선) — 0-impact migration. | |
| 1.18.43 | 2026-05-21 | 1.18.43: 멀티베드 console (PACU 10베드 Pi) syslog noise 80,500/hr → ~1,400/hr (-98.3%), cpu_usage 측정 1.16.12 (9f26e36) 이후 8년치 영구 -1 버그 수정, 멀티베드 환경 베드 식별용 [bedname / devicename] 로그 prefix 도입. 동기는 PACU production Pi (1.18.40) 4일치 syslog 분석 — 1.24M 라인 중 vr 라인 836K, idle 8시간 평균 시간당 80,500 라인 (베드 10 × 1초마다 "Waiting for next patient" × syslog 2x 중복). (1) VRApp.cpp:2696-2710 timer_thread_func 의 cpu usage 계산이 `if (totalcpu && m_cpu_total_last && totalcpu > m_cpu_total_last)` 가드 안에서만 m_cpu_total_last 갱신해 첫 호출 시 m_cpu_total_last=0 → else 분기 → -1 → m_cpu_total_last 갱신 안 됨 → 영원히 false → 영원히 -1 데드락. PACU 1,048 샘플 100% -1 실측 확인. m_cpu_total_last/m_cpu_used_last 갱신을 if 밖으로 빼서 첫 호출만 baseline 으로 -1, 두 번째 (60s 후) 부터 정상 측정. /proc/stat 의 iowait/irq/softirq 까지 7개 필드 fscanf 로 정확도 ±5% 개선. 부수: 같은 함수의 cpu_temp 가 `temp / 1000` int 나눗셈으로 소수점 절단되어 PACU 측정값이 정수 50/51/...,/58 9종만 출력 (millidegree 정밀도 손실) → `temp / 1000.0f` 로 fix. ram 계산은 `(totalram + totalswap) * mem_unit` 결과에 다시 mem_unit 곱하던 차원 혼용 (Linux 가 mem_unit=1 이라 우연히 정상 동작했지만 dimensionally wrong) → `(units1 + units2) * mem_unit` 로 정정 + underflow 가드. (2) DISPLAY::log(string/printf) + DEVICE::log(string/printf) 멤버 추가. DISPLAY::log 는 `[bedname] msg`, DEVICE::log 는 m_pdisp 위임 없이 직접 `[bedname / devicename] msg` 한 줄 prefix (nested `[bed] [dev]` 보다 가독성 우선). m_pdisp 또는 bedname null 케이스 safe fallback. (3) show_msg 의 console path TRACE 를 log() 로 교체 → "Waiting for next patient" 자동 [bedname] prefix. ADT patient id unset 도 log() 로. (4) 이미 수동으로 get_bedname() 을 인자로 넘기던 8군데 (DISPLAY ptcon_thread_func / add_trk / add_dev / del_dev / cut-recording, Device add_rec 콜백, FILT stop, VRApp add_tab/del_tab) 를 log() 로 전환 — 이중 prefix 방지 + 일관성. Serial::reading_thread / tcp_thread / open_socket waiting / timeout / interrupted / got-client 6군데 DEVICE::log() 전환 → `[bedname / Intellivue]` 등 자동 prefix, 멀티탭 환경에서 어느 베드 어느 device 출처인지 즉시 식별. (5) wss 재시도 폭주 throttle. WSSClient 에 m_verbose (debug step 로그 게이트) + m_dt_last_err_log (60s window) 추가. connect() 내부 step-by-step TRACE 4개 ("connecting" / "connect error" / "connected") 는 m_verbose 가드, 최종 "wss connect error" 는 60s window throttle (첫 줄 즉시, 그 다음 60s 1회). connect 성공 path 에서 throttle reset 으로 다음 disconnect → 첫 에러 즉시 로깅. sendweb_thread_func 의 "connecting websocket server" 호출자 라인도 같은 60s window, m_bDebug 면 verbose 활성화. PACU idle 8h 측정 7,024/hr (4종 × 1,756) → 약 60/hr (-99%). (6) "Waiting for next patient" / "ADT patient id unset" 의 60s throttle 자체는 feature/wav-mem-retention 브랜치 ptcon_thread_func 재구성 (b75928f 시리즈) 에서 이미 들어가 있어 이 릴리즈에 자동 포함. 종합 영향: idle 시간당 syslog 라인 80,500 → ~1,400 (-98.3%), active 시간당 14,900 → ~700 (-95%). 진단 측면: cpu_usage 가 부활하면서 웹모니터링 json 의 cpu_usage 필드도 한 번도 안 채워지던 게 정상 전송 (VRApp.cpp:2499 의 `if (m_cpu_usage > 0)` 가드가 영원히 false 였음). 별건: syslog 라인 2× 중복은 application 측이 아니라 rsyslog imuxsock + imjournal + journald.ForwardToSyslog=yes 의 Debian Bookworm 전형 misconfig — admin 측 fix (rsyslog.conf 에서 imjournal 주석 처리 + restart) 로 추가 50% 감소 가능 (별도 문서). MFC + Qt + Pi (RPI64) + Ubuntu CLI 빌드 모두 통과. | |
| 1.18.41 | 2026-05-13 | 1.18.41 Hotfix: TCP-server protocol-initiator device (Intellivue/S5/Datex/Hamilton/MPS/Agilia/IAP) 가 open() 직후 보내는 첫 패킷이 wire 에 안 나가던 회귀. 1.18.34 의 PortRouter refactor 가 Serial::open_socket() 의 8초 handoff blocking 을 제거하고 비동기 모델로 전환했는데, protocol-initiator 의 open() 코드가 m_sock=INVALID 상태에서 write 를 시도해 silent fail (Linux 는 m_fd=0 이라 false 반환). Intellivue 케이스 production journald 의 Pi → ESP TX 700K~3M bytes 는 monitor 측 abort 로 늦게 트리거된 AB_SPDU_SI recovery assoc_req 후 request_thread 의 정상 polling 트래픽이지만 일부 베드 (abort 없는 monitor) 는 recovery 도 안 되어 영구 silent (RX 300 bytes). 수정 방향: open() 의 옛 contract ("return 시점에 통신 가능") 복구. (1) Serial::open_socket() TCP-server 분기가 PortRouter::subscribe 후 m_sock_cv 로 첫 client handoff 까지 block (timeout = device read_timeout, 기본 30s) — 옛 모델 그대로. lock_and_open 이 false 면 다음 tick 에서 retry. close 신호로 abort 가능. (2) Serial::close() 는 PortRouter::unsubscribe 안 함 — subscribe 는 device 생애 동안 sticky 라 read_timeout 으로 인한 close→re-open 사이클 동안 listen socket 이 유지되어 1.18.29/1.18.34 의 anti-churn 이익 보존. unsubscribe 는 ~Serial() 에서만. (3) Per-device lifecycle thread (DEVICE::m_thread_restart): 각 device 가 자기 open/close/timeout 재시작을 별도 thread 에서 관리. 옛 모델의 DISPLAY::bed_manager 가 베드의 모든 device 를 sequential iterate 하던 구조에선 한 device 의 blocking open() 이 같은 베드의 다른 device 의 lifecycle 을 차단했는데, per-device thread 로 분리하여 멀티 device 베드도 병렬 진행. add_dev 에서 start_lifecycle, del_dev / ~DISPLAY 에서 stop_lifecycle. (4) Serial::tcp_thread_func 단순화 — outer m_sock_cv wait 패턴 (1.18.34/1.18.39 가 추가했던 것) 제거. open_socket 이 m_sock valid 보장하므로 reader thread 시작 시점에 simple inner recv loop 만. accept_handoff 의 replace (zombie cleanup) 케이스는 recv error 후 m_sock 변경 확인 + retry 로 처리. (5) reading_thread_func 의 `else if (m_sock != INVALID_SOCKET) tcp_thread_func();` 가드 복원 (1.18.39 가 제거). (6) Serial::write 의 silent-fail 케이스에 WARN trace 추가 — 미래 동종 회귀 즉시 노출. (7) PortRouter::subscribe 가 같은 (port, type) 에서 같은 IP filter 또는 둘 이상 catch-all 발견 시 reject (config 실수 원천 차단, 옛 WARN-only 동작 강화). (8) DISPLAY::bed_manager_thread_func 의 restart 블록 제거 — ptcon + adt 만 담당. "Waiting for next patient" TRACE 가 Linux/console 에서 1초 → 60초마다 throttle (별개 journald 부풀림 fix). 영향 범위: Intellivue / S5 / Datex / Hamilton / MPS / Agilia / IAP TCP-server 모드 베드 전부. 1.18.34 이후 우회 방법은 race-win 케이스 (VRN 이 PortRouter::subscribe 직후 connect) 외엔 없었음. MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.40 | 2026-05-12 | Hotfix: Drager Medibus 프로토콜 사용 베드에서 1.15.11 이후 vr.service 가 SIGSEGV 로 무한 재시작하던 문제. 1.15.10 (a8c7b2a) 의 "Sampling rate estimation" 리팩터링이 m_ptrk_awp/awf/co2 트랙을 add_trks() 에서의 eager 생성 (default srate=62.5Hz) 에서 realtime data 100 샘플 모인 후 lazy 생성으로 바꿨는데, Medibus 핸드셰이크 순서 (0x51 ICC → 0x52 DeviceID → 0x53 RealtimeConfig 응답 → 0x54 → realtime data 시작) 상 0x53 응답 핸들러 (Drager.cpp:295-307) 가 트랙들이 아직 nullptr 인 시점에 `ptrk->m_srate = 1000000.0/interval` 로 NULL 역참조 → 즉시 SEGV. 그 베드의 vr.service 가 systemd Restart=on-failure 로 재시작 → 다시 connect → 동일 0x53 패킷 받고 동일 SEGV → 무한 루프 (journald 로그상 restart counter 61 까지 누적, code=killed status=11/SEGV). 1.15.9 까진 트랙이 add_trks() 에서 생성되어 0x53 도착 시 항상 non-NULL 이라 안전했음. 수정: (a) add_trks() 에서 m_ptrk_awp/awf/co2 eager 생성 복원 (srate=62.5Hz default) — 0x53 는 ptrk->m_srate 만 갱신 (트랙 재생성 X). (b) on_received() 의 lazy creation + packet-timing srate 추정 블록 제거 — 0x53 가 권위 있는 srate 소스이고 packet 타이밍 기반 추정은 network jitter 에 약해 불안정. (c) 0x53 핸들러에 `if (interval > 0)` guard 추가 — 페이로드 깨졌을 때 div-by-zero / inf srate 방지. 영향 범위: Drager Primus / Apollo / Perseus / Fabius 등 Medibus 사용 마취기 전부. 우회 방법은 1.15.9 다운그레이드 외엔 없었음 (그 베드의 모든 데이터 유실 + 환자 모니터링 불가). MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.39 | 2026-05-08 | Fixed: PortRouter (TCP server) 모드에서 reader thread 가 startup 시점에 죽어 client 데이터를 영구히 못 받던 문제. 1.18.34 (9bd252f) 의 PortRouter refactor 가 m_sock 세팅을 dispatch 시점으로 옮겼는데 reading_thread_func (Serial.cpp:354) 의 가드 `else if (m_sock != INVALID_SOCKET) tcp_thread_func();` 는 옛 모델 (open 시점 이미 connect 완료) 가정 그대로라 — 시작 직후 m_sock=INVALID 면 tcp_thread_func 진입 안 하고 reader thread 즉시 종료. 이후 VRN 이 connect → PortRouter::dispatch → accept_handoff 가 m_sock 채우고 m_sock_cv.notify_all() → 그러나 wait 중인 reader 가 없음 (이미 죽음) → kernel recv buffer 에만 데이터 적재. 증상은 ss -tn state established 의 Recv-Q 가 0 이 아닌 값 (수백 bytes) 으로 누적, 베드 화면에는 데이터 안 들어옴. 그 베드의 VRN 이 Serial::open() 의 PortRouter::subscribe 직후~reader thread spawn 사이의 짧은 윈도우 안에 connect 한 경우만 우연히 정상 동작 (race-win). 수정: 가드 제거 — TCP 분기에 항상 진입. tcp_thread_func 자체에 이미 m_sock_cv outer-wait 루프가 있어 m_sock 이 INVALID 인 동안 dispatch 가 깨워줄 때까지 안전하게 대기. Pi 핫스팟에 VRN 여러 대 (e.g. 10.42.0.21~25) 를 같은 (4343, Philips:Intellivue) 키로 묶고 IP filter 로 라우팅하는 시나리오에서 가장 자주 노출. Added: 진단 로그 보강 — PortRouter::accept_loop 의 accept 이벤트, dispatch 의 라우팅 결정 (ip_specific/catch_all subs 수, 어느 dev 가 받았는지), subscribe/unsubscribe 의 entry 생성/append/destroy, reading_thread / tcp_thread 의 시작·wait·wake 라이프사이클 — 이전엔 모두 m_bDebug 게이트 안에 있어서 production journald 에서 안 보였는데, 이제 항상 출력 (이번 같은 dispatch routing 문제 진단을 production 에서 바로 가능). MFC + Qt + Pi (RPI64) + Ubuntu Qt + AppImage 빌드 모두 통과. | |
| 1.18.38 | 2026-05-08 | Fixed: 웹모니터링 우클릭 → 디바이스 세팅 (websocket edit_bed 명령) 으로 베드의 device/filter 를 변경할 때 베드 이름이 매번 "_2" suffix 로 자동 리네임되어 vr.conf (Pi: /data/vr.conf) 에 잘못된 이름으로 저장되던 문제. 원인은 1.18.22 (cda8aa5) 에서 add_bed 에 추가된 bedname dedup ("최후 방어선" 으로 forward_frame auto-create / 수동 편집된 conf 의 중복 이름 처리용). edit_bed 핸들러는 옛 pdel 이 m_pdisps 에 그대로 있는 상태에서 같은 bedname 으로 new DISPLAY 를 add_bed 하고 그 다음 del_bed(pdel) 하는 순서였는데, add_bed 가 dup 감지해 새 pdisp 를 bedname_2 로 자동 리네임 → save_settings 가 [BED/bedname_2] 로 직렬화 → 사용자 입장에선 "설정 적용 안됨" 으로 보였다. 추가로 옛/새 DISPLAY 가 잠깐 m_pdisps 에 공존하면서 같은 device 포트를 동시에 들고 있으려 해 로그가 dup 으로 찍히는 부수 증상도 있었음. 수정: del_bed(pdel) 를 add_bed(pdisp) 보다 앞으로 이동 — 옛 베드의 device 포트가 깨끗이 release 된 뒤 새 pdisp 가 같은 포트를 reopen, dedup 발동 안 함. 다른 베드의 recording 은 영향 없음 (인메모리 hot swap 설계 유지). 부수: edit_bed 핸들러의 데드 코드 (`break` 뒤의 unreachable olddevs populate 루프 + `if (olddevs.find(name) == olddevs.end())` 항상-true 래퍼) 정리. edit_conf 와 save_settings 는 손대지 않음. MFC + Qt + Pi (RPI64) 빌드 모두 통과. | |
| 1.18.37 | 2026-05-08 | Refactored: 필터 다이얼로그의 python 런타임 — pyvital → openvital 0.3.0 로 교체 + 동봉 python.zip 슬림화. 핵심 동기 셋: (1) pyvital 0.6.0 이 tensorflow+torch+keras 를 hard-dep 으로 끌어들여 PyPI upgrade 가 사실상 깨짐, (2) 기존 zip 121 MB 안에 botocore/aiobotocore/s3fs/pyarrow/pandas/aiohttp 등 vitaldb 클라우드 업로드용 deps 가 ~250 MB unpacked 차지 — 필터 서버는 한 번도 쓴 적 없는 dead weight, (3) sanic 25.x 의 multi-process worker 가 openvital __main__.py 를 fork 후 재import 하면서 worker 가 module-top app instance 를 못 찾아 "Sanic app name not found" 로 죽음 — 단순 endpoint 2개 로컬호스트 서버에 async stack 자체가 과함. 해결: openvital 0.3.0 (commit b6f445b) 가 sanic 을 stdlib http.server (BaseHTTPRequestHandler + HTTPServer) 로 50 LOC 재작성 — wire protocol (GET / 필터목록 JSON, POST /<modname> gzip 본문) 동일해 VR 클라이언트 변경 0줄. 단일 스레드로 기존 sanic event loop semantics (cfgs/default_cfgs lock-free 변경) 보존. build_python_zip.py (NEW) 가 Python 3.11.9 embed + numpy + openecg + openvital (local checkout 우선, fallback PyPI) 만으로 27 MB zip 빌드 — 기존 121 MB 대비 78% 감소. ML 필터 (sv_dlapco/abp_hpi/ecg_classifier/ecg_beat_noise_detector) 는 [Hybrid 모델] 사용자가 Add filter 다이얼로그의 "Install ML filters" 버튼 누를 때 silent pip install openvital[all] (cmd 창 미노출 — VRApp::install_pip_package + run_pip_silent 이 자체 progress 다이얼로그에 stdout heartbeat 흘림). 버튼 라벨은 "Upgrade pyvital" → "Install ML filters" 로 의도 명시. openvital __main__.py 가 missing extras 를 graceful skip 하므로 base 환경에서도 11개 필터 (ECG QRS detector, HRV, MTWA, annotator, eeg_fft, nirs_cox, pkpd_3comp, pleth_dpop/ptt/pvi, resp_compliance) 즉시 사용 가능. Migration: 기존 사용자의 user_dir/python 폴더는 pyvital + 옛 deps 가 그대로 남아있고 vitaldb.net/python.zip 만 새로 올리면 (a) 기존 폴더 삭제 후 install_python 으로 새 zip 받으면 깔끔, (b) 폴더 유지 시 server 가 openvital 못 찾아 필터 다이얼로그 에러 → release note 에 명시 필요. MFC + Qt 양쪽 코드: VRGui.rc 의 IDC_UPGRADE 버튼 라벨 + DlgAddFilter.cpp 의 dist-info prefix 매칭 (pyvital- 8자 → openvital- 10자) + QtDlgAddFilter.cpp 도 동일 변경 + onUpgrade 가 cmd /k QProcess::startDetached 대신 theApp.install_pip_package("openvital[all]") 호출 (Linux Qt 빌드는 #ifdef _WIN32 가드). VRApp.cpp:318 의 python -m pyvital → -m openvital. install_pip_package 는 anonymous namespace 의 is_safe_pkg_spec 화이트리스트 검증 + run_pip_silent (CreateProcessA + CREATE_NO_WINDOW + 자식 stdout pipe) + CDlgProgress / QtDlgProgress 자체 progress UI. 빌드 검증: python -m openvital 이 GET / 로 11 필터 반환, sanic import 부재 확인. zip 27.5 MB. | |
| 1.18.36 | 2026-05-07 | Fixed: 3-파티션 레이아웃 (boot/rootfs/data) 에서 websocket edit_conf / update 명령이 read-only fs 로 실패하던 문제. vr.conf 는 /data 폴더가 있으면 /data/vr.conf 로 자동 정착 — get_conf_path() 가 write target 으로 결정, load_settings() 는 primary 가 없으면 legacy /boot/firmware/vr.conf 또는 /boot/vr.conf 에서 fallback read 후 다음 save 부터 primary 로 자동 이전 (마이그레이션 step 없음, legacy 파일은 read-only fs 라 무해). binary update (upgrade_now) 는 RAII BootRwGuard 가 dirname(module_path) 를 잠시 rw remount, scope 종료 시 sync() + MS_REMOUNT|MS_RDONLY 로 자동 ro 복귀 — vfat 노출 윈도우 최소화 + exception/return 어디서든 복구 보장. statvfs ST_RDONLY 검사로 이미 rw 인 fs (x86 dev) 에서는 no-op, non-Linux (macOS) 는 stub 으로 통과. save_settings() 의 silent EROFS 실패가 TRACE 로 가시화 (이전엔 무시되어 conf 수정 안 먹는 원인 추적 불가). 부수: PortRouter.cpp 가 commit 9bd252f 이후 CMakeLists 의 RPI sources 목록에서 누락되어 Pi 빌드 link 에러 — 추가. | |
| 1.18.35 | 2026-05-01 | Added: alarm parsing for Mindray HL7 (eGateway ORU^R40) and Nihon Kohden (NealTime HL7GW + ORF, BSM serial D-port, EGA UDP) - emits ALARM_STATUS / ALARM_MESSAGE / ALARM_PRIORITY tracks (same 3-track schema already used by Philips IntelliVue, GE Solar/Dash, GE/Datex S5); type info preserved via [T]/[A]/[ARR] message prefixes; Mindray facet 1/5/6/7 walker with 92-entry MDC+MNDRY alarm code lookup; NK HL7GW parses OBR-4=EVENT with arrhythmia/technical disambiguation by OBX-5; NK BSM serial decodes per-parameter * flags (edge-triggered to avoid 1Hz flooding) plus 32-bit Table 9 arrhythmia bitmap, D19 alarm-suspend nibble, and the VPC CODE byte; NK EGA UDP extracts Priority + Tech Alarm + Arrhythmia from JSON Vital Sign packets with edge-trigger cache for start/end inference; ACK^R40 reply added for Mindray alert messages; simulators gained periodic alarm cycling for end-to-end smoke testing | |
| 1.18.34 | 2026-04-27 | Added: Linux Desktop Qt GUI build (VRQt) - first GUI build for Linux distributed as a self-contained AppImage (~32MB, Qt6 runtime + libGL/libEGL/libGLX/libOpenGL/libGLESv2/libGLdispatch bundled inside) so users on minimal Ubuntu/Debian/Fedora can run it without installing Qt or GL system packages; tested on AWS clean Ubuntu 22.04 cloud image; build via build_ubuntu_appimage.py which is now invoked by deploy.py; Fixed: Linux Qt right-side device/filter panels rendered with white background below cards because the inner listWidget did not autoFillBackground from parent palette on Linux Qt (Windows/macOS implicitly inherit, X11/Wayland do not); explicit stylesheet on listWidget; Added: Linux installation section in user manuals (EN/KO/ZH/ES) covering AppImage chmod+run flow and dialout group note for serial/USB device access | |
| 1.18.33 | 2026-04-25 | Fixed: Demo device never started since 1.18.11 (bed_manager skipped empty port_name as passive but Demo has no port and still needs lock_and_open); Fixed: Qt fit-to-window button rendered at top-left (0,0) instead of right-aligned in bottom nav bar; Fixed: Qt crash when closing tab / deleting device / deleting filter - paint dereferenced freed pointer before panel timer rebuilt items (added MFC-style stale-pointer guard to QtDeviceItem and QtFilterItem); Added: macOS DMG main window now shown on launch (restoreWindowPos had no Mac/Linux branch); Added: macOS Homebrew dylibs (openssl) bundled in Contents/Frameworks; Added: macOS .app bundle now notarized + stapled (drag-to-Applications no longer needs xattr -cr on first launch); Changed: Qt MSI ~1MB smaller (dropped unused iconengines and imageformats plugins) |