VitalRecorder
A free software to record and analyze biosignal waveforms and vital signs from GE® (Solar 8000®, Dash, Bx50®), Philips® (Intellivue®), Drager® (Infinity®, Nihon Kohden® (PSM®, Primus®), Maquet® (Flow-i®, Servo-i®) ventilators, Fresenius Kabi® (Orchestra®, Agilia®, and Link+®), BBraun® syringe pumps, Medtronic® BIS®, Masimo® Root®, DataQ® ADCs, etc. (Full list of supported devices)The use of the VitalRecorder program is completely free. Download and try the latest version.
(Downloaded 181,626 times since Feb 2017)
OS:
Version:
View All Versions
1.18.48
1.18.48 Fixed: VR 이 먼저 실행된 상태에서 Philips Intellivue 모니터를 나중에 켜면 웨이브가 영원히 수집되지 않던 문제 (VR 재시작 전까지 모니터로 아무 요청도 안 나감). 원인: Intellivue::open() 은 assoc_req 를 딱 한 번 보내는데, 시리얼(MIB)/UDP 는 모니터가 꺼져 있어도 포트가 열리므로 이 요청이 응답 없이 사라진다. Philips 는 자기가 먼저 말을 걸지 않는 프로토콜이고, 첫 수신이 있어야 디바이스 상태가 OPENING→ACTIVE 로 승격되는데 수신이 없으니 OPENING 에 고정 - DEVICE::restart_thread_func 워치독은 is_closed(재오픈)/is_active(read_timeout 30s) 두 분기만 있어 OPENING 은 어느 쪽에도 안 걸림 → assoc 재전송도 재시작도 영원히 없음. 수정: Intellivue 에 assoc 재시도 스레드 추가 - 세션 확립(MDS_CREAT 수신, m_bSessionUp atomic 플래그) 전까지 5초 간격으로 assoc_req 재전송, 최근 5초 내 수신이 있으면(assoc 진행 중) 재전송 보류. 모니터를 나중에 켜도 최대 5초 내 연결. 세션 확립 후에는 재시도 루프 종료 - 기존 동작(AB_SPDU 시 재연결, read_timeout 재시작)과 충돌 없음. 모니터가 켜져 있던 기존 시나리오는 첫 assoc_req 에 바로 응답하므로 동작 변화 없음 - 0-impact.
1.18.47
1.18.47 Fixed: 파일 업로드(및 Http 클래스를 쓰는 모든 경로 - upload_vital, getvr 업데이트체크, ADT 조회, 필터서버)가 SERVER_IP/UPLOAD_SERVER_IP 에 "https://host:port" 풀 URL 형식을 넣으면 "Couldn't resolve host name" 으로 전부 실패하던 문제. 원인은 src/Https.cpp 의 Http 생성자 - 1.18.46 의 wss.cpp 수정과 동일한 버그의 나머지 반쪽. 첫 콜론을 포트 구분자로 오인해 "https://eicuvital.ywmc.or.kr:4432" 입력 시 m_strHost 가 문자 그대로 "https" 가 되어 DNS 조회 실패 (웹모니터링 wss 는 1.18.46 에서 이미 수정되어 정상, 파일 업로드만 실패하는 비대칭 발생 - 현장에서는 업로드 루프의 실패시 break 정책과 겹쳐 "베드명에 # 가 있으면 전송이 안 된다" 로 오인 관찰됨. 실제로는 # 파일이 디렉토리 순서상 항상 첫 시도라 거기서 host 오류로 중단 → 뒤 파일 전체가 막힌 것. 베드명 특수문자는 업로드 URL 과 무관). 수정: Http 생성자에 wss 와 동일한 선행 스킴(https/http) 파싱 추가 - 스킴이 TLS 여부를 결정 (포트 무관, 4432 같은 커스텀 포트에서 https 정상), "https://host" 포트 생략 시 443, 경로 붙은 입력도 host 만 추출. 기존 "host" / "host:443" 형식은 종전과 완전 동일 동작 - 0-impact. Windows(WinINet)/Linux(curl) 공통 생성자라 모든 플랫폼에 적용.
1.18.46
1.18.46 Fixed: WSSClient 가 "https/wss 스킴 + 비표준 포트" 조합을 제대로 처리하지 못하던 문제 (커스텀 포트의 wss 서버에 연결 불가). 원인은 src/wss.cpp 의 WSSClient 생성자 두 곳 - (1) SERVER_IP 파싱이 첫 콜론을 포트 구분자로 써서 "https://host:4432" 를 넣으면 "https" 의 콜론을 먼저 잡아 m_host 가 "https" 가 되고 포트 파싱이 깨져 getaddrinfo 실패, (2) m_secure = (m_port == 443) 로 TLS 여부를 오직 포트 443 여부로만 판단해 4432 같은 커스텀 포트는 무조건 평문 ws 로 붙어 wss 전용 서버에서 실패. 수정: 생성자가 선행 URL 스킴(https/wss/http/ws)을 먼저 파싱해 스킴이 있으면 스킴이 TLS 를 결정(포트 무관)하고, 스킴이 없으면 기존 포트 443 휴리스틱을 유지(하위호환). 이제 SERVER_IP=https://eicuvital.ywmc.or.kr:4432 (또는 wss://...) 형식이 비표준 포트에서도 wss 로 정상 연결되며, SNI/인증서 검증은 도메인(m_host)을 쓰므로 와일드카드 인증서도 정상 매칭. 기존 host / host:443 설정은 종전대로 secure 유지 - 0-impact.
1.18.45
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
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.48
1.18.48 Fixed: VR 이 먼저 실행된 상태에서 Philips Intellivue 모니터를 나중에 켜면 웨이브가 영원히 수집되지 않던 문제 (VR 재시작 전까지 모니터로 아무 요청도 안 나감). 원인: Intellivue::open() 은 assoc_req 를 딱 한 번 보내는데, 시리얼(MIB)/UDP 는 모니터가 꺼져 있어도 포트가 열리므로 이 요청이 응답 없이 사라진다. Philips 는 자기가 먼저 말을 걸지 않는 프로토콜이고, 첫 수신이 있어야 디바이스 상태가 OPENING→ACTIVE 로 승격되는데 수신이 없으니 OPENING 에 고정 - DEVICE::restart_thread_func 워치독은 is_closed(재오픈)/is_active(read_timeout 30s) 두 분기만 있어 OPENING 은 어느 쪽에도 안 걸림 → assoc 재전송도 재시작도 영원히 없음. 수정: Intellivue 에 assoc 재시도 스레드 추가 - 세션 확립(MDS_CREAT 수신, m_bSessionUp atomic 플래그) 전까지 5초 간격으로 assoc_req 재전송, 최근 5초 내 수신이 있으면(assoc 진행 중) 재전송 보류. 모니터를 나중에 켜도 최대 5초 내 연결. 세션 확립 후에는 재시도 루프 종료 - 기존 동작(AB_SPDU 시 재연결, read_timeout 재시작)과 충돌 없음. 모니터가 켜져 있던 기존 시나리오는 첫 assoc_req 에 바로 응답하므로 동작 변화 없음 - 0-impact.
1.18.47
1.18.47 Fixed: 파일 업로드(및 Http 클래스를 쓰는 모든 경로 - upload_vital, getvr 업데이트체크, ADT 조회, 필터서버)가 SERVER_IP/UPLOAD_SERVER_IP 에 "https://host:port" 풀 URL 형식을 넣으면 "Couldn't resolve host name" 으로 전부 실패하던 문제. 원인은 src/Https.cpp 의 Http 생성자 - 1.18.46 의 wss.cpp 수정과 동일한 버그의 나머지 반쪽. 첫 콜론을 포트 구분자로 오인해 "https://eicuvital.ywmc.or.kr:4432" 입력 시 m_strHost 가 문자 그대로 "https" 가 되어 DNS 조회 실패 (웹모니터링 wss 는 1.18.46 에서 이미 수정되어 정상, 파일 업로드만 실패하는 비대칭 발생 - 현장에서는 업로드 루프의 실패시 break 정책과 겹쳐 "베드명에 # 가 있으면 전송이 안 된다" 로 오인 관찰됨. 실제로는 # 파일이 디렉토리 순서상 항상 첫 시도라 거기서 host 오류로 중단 → 뒤 파일 전체가 막힌 것. 베드명 특수문자는 업로드 URL 과 무관). 수정: Http 생성자에 wss 와 동일한 선행 스킴(https/http) 파싱 추가 - 스킴이 TLS 여부를 결정 (포트 무관, 4432 같은 커스텀 포트에서 https 정상), "https://host" 포트 생략 시 443, 경로 붙은 입력도 host 만 추출. 기존 "host" / "host:443" 형식은 종전과 완전 동일 동작 - 0-impact. Windows(WinINet)/Linux(curl) 공통 생성자라 모든 플랫폼에 적용.
1.18.46
1.18.46 Fixed: WSSClient 가 "https/wss 스킴 + 비표준 포트" 조합을 제대로 처리하지 못하던 문제 (커스텀 포트의 wss 서버에 연결 불가). 원인은 src/wss.cpp 의 WSSClient 생성자 두 곳 - (1) SERVER_IP 파싱이 첫 콜론을 포트 구분자로 써서 "https://host:4432" 를 넣으면 "https" 의 콜론을 먼저 잡아 m_host 가 "https" 가 되고 포트 파싱이 깨져 getaddrinfo 실패, (2) m_secure = (m_port == 443) 로 TLS 여부를 오직 포트 443 여부로만 판단해 4432 같은 커스텀 포트는 무조건 평문 ws 로 붙어 wss 전용 서버에서 실패. 수정: 생성자가 선행 URL 스킴(https/wss/http/ws)을 먼저 파싱해 스킴이 있으면 스킴이 TLS 를 결정(포트 무관)하고, 스킴이 없으면 기존 포트 443 휴리스틱을 유지(하위호환). 이제 SERVER_IP=https://eicuvital.ywmc.or.kr:4432 (또는 wss://...) 형식이 비표준 포트에서도 wss 로 정상 연결되며, SNI/인증서 검증은 도메인(m_host)을 쓰므로 와일드카드 인증서도 정상 매칭. 기존 host / host:443 설정은 종전대로 secure 유지 - 0-impact.
1.18.45
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
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.48
1.18.48 Fixed: VR 이 먼저 실행된 상태에서 Philips Intellivue 모니터를 나중에 켜면 웨이브가 영원히 수집되지 않던 문제 (VR 재시작 전까지 모니터로 아무 요청도 안 나감). 원인: Intellivue::open() 은 assoc_req 를 딱 한 번 보내는데, 시리얼(MIB)/UDP 는 모니터가 꺼져 있어도 포트가 열리므로 이 요청이 응답 없이 사라진다. Philips 는 자기가 먼저 말을 걸지 않는 프로토콜이고, 첫 수신이 있어야 디바이스 상태가 OPENING→ACTIVE 로 승격되는데 수신이 없으니 OPENING 에 고정 - DEVICE::restart_thread_func 워치독은 is_closed(재오픈)/is_active(read_timeout 30s) 두 분기만 있어 OPENING 은 어느 쪽에도 안 걸림 → assoc 재전송도 재시작도 영원히 없음. 수정: Intellivue 에 assoc 재시도 스레드 추가 - 세션 확립(MDS_CREAT 수신, m_bSessionUp atomic 플래그) 전까지 5초 간격으로 assoc_req 재전송, 최근 5초 내 수신이 있으면(assoc 진행 중) 재전송 보류. 모니터를 나중에 켜도 최대 5초 내 연결. 세션 확립 후에는 재시도 루프 종료 - 기존 동작(AB_SPDU 시 재연결, read_timeout 재시작)과 충돌 없음. 모니터가 켜져 있던 기존 시나리오는 첫 assoc_req 에 바로 응답하므로 동작 변화 없음 - 0-impact.
1.18.47
1.18.47 Fixed: 파일 업로드(및 Http 클래스를 쓰는 모든 경로 - upload_vital, getvr 업데이트체크, ADT 조회, 필터서버)가 SERVER_IP/UPLOAD_SERVER_IP 에 "https://host:port" 풀 URL 형식을 넣으면 "Couldn't resolve host name" 으로 전부 실패하던 문제. 원인은 src/Https.cpp 의 Http 생성자 - 1.18.46 의 wss.cpp 수정과 동일한 버그의 나머지 반쪽. 첫 콜론을 포트 구분자로 오인해 "https://eicuvital.ywmc.or.kr:4432" 입력 시 m_strHost 가 문자 그대로 "https" 가 되어 DNS 조회 실패 (웹모니터링 wss 는 1.18.46 에서 이미 수정되어 정상, 파일 업로드만 실패하는 비대칭 발생 - 현장에서는 업로드 루프의 실패시 break 정책과 겹쳐 "베드명에 # 가 있으면 전송이 안 된다" 로 오인 관찰됨. 실제로는 # 파일이 디렉토리 순서상 항상 첫 시도라 거기서 host 오류로 중단 → 뒤 파일 전체가 막힌 것. 베드명 특수문자는 업로드 URL 과 무관). 수정: Http 생성자에 wss 와 동일한 선행 스킴(https/http) 파싱 추가 - 스킴이 TLS 여부를 결정 (포트 무관, 4432 같은 커스텀 포트에서 https 정상), "https://host" 포트 생략 시 443, 경로 붙은 입력도 host 만 추출. 기존 "host" / "host:443" 형식은 종전과 완전 동일 동작 - 0-impact. Windows(WinINet)/Linux(curl) 공통 생성자라 모든 플랫폼에 적용.
1.18.46
1.18.46 Fixed: WSSClient 가 "https/wss 스킴 + 비표준 포트" 조합을 제대로 처리하지 못하던 문제 (커스텀 포트의 wss 서버에 연결 불가). 원인은 src/wss.cpp 의 WSSClient 생성자 두 곳 - (1) SERVER_IP 파싱이 첫 콜론을 포트 구분자로 써서 "https://host:4432" 를 넣으면 "https" 의 콜론을 먼저 잡아 m_host 가 "https" 가 되고 포트 파싱이 깨져 getaddrinfo 실패, (2) m_secure = (m_port == 443) 로 TLS 여부를 오직 포트 443 여부로만 판단해 4432 같은 커스텀 포트는 무조건 평문 ws 로 붙어 wss 전용 서버에서 실패. 수정: 생성자가 선행 URL 스킴(https/wss/http/ws)을 먼저 파싱해 스킴이 있으면 스킴이 TLS 를 결정(포트 무관)하고, 스킴이 없으면 기존 포트 443 휴리스틱을 유지(하위호환). 이제 SERVER_IP=https://eicuvital.ywmc.or.kr:4432 (또는 wss://...) 형식이 비표준 포트에서도 wss 로 정상 연결되며, SNI/인증서 검증은 도메인(m_host)을 쓰므로 와일드카드 인증서도 정상 매칭. 기존 host / host:443 설정은 종전대로 secure 유지 - 0-impact.
1.18.45
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
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.40
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
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
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
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.48
1.18.48 Fixed: VR 이 먼저 실행된 상태에서 Philips Intellivue 모니터를 나중에 켜면 웨이브가 영원히 수집되지 않던 문제 (VR 재시작 전까지 모니터로 아무 요청도 안 나감). 원인: Intellivue::open() 은 assoc_req 를 딱 한 번 보내는데, 시리얼(MIB)/UDP 는 모니터가 꺼져 있어도 포트가 열리므로 이 요청이 응답 없이 사라진다. Philips 는 자기가 먼저 말을 걸지 않는 프로토콜이고, 첫 수신이 있어야 디바이스 상태가 OPENING→ACTIVE 로 승격되는데 수신이 없으니 OPENING 에 고정 - DEVICE::restart_thread_func 워치독은 is_closed(재오픈)/is_active(read_timeout 30s) 두 분기만 있어 OPENING 은 어느 쪽에도 안 걸림 → assoc 재전송도 재시작도 영원히 없음. 수정: Intellivue 에 assoc 재시도 스레드 추가 - 세션 확립(MDS_CREAT 수신, m_bSessionUp atomic 플래그) 전까지 5초 간격으로 assoc_req 재전송, 최근 5초 내 수신이 있으면(assoc 진행 중) 재전송 보류. 모니터를 나중에 켜도 최대 5초 내 연결. 세션 확립 후에는 재시도 루프 종료 - 기존 동작(AB_SPDU 시 재연결, read_timeout 재시작)과 충돌 없음. 모니터가 켜져 있던 기존 시나리오는 첫 assoc_req 에 바로 응답하므로 동작 변화 없음 - 0-impact.
1.18.47
1.18.47 Fixed: 파일 업로드(및 Http 클래스를 쓰는 모든 경로 - upload_vital, getvr 업데이트체크, ADT 조회, 필터서버)가 SERVER_IP/UPLOAD_SERVER_IP 에 "https://host:port" 풀 URL 형식을 넣으면 "Couldn't resolve host name" 으로 전부 실패하던 문제. 원인은 src/Https.cpp 의 Http 생성자 - 1.18.46 의 wss.cpp 수정과 동일한 버그의 나머지 반쪽. 첫 콜론을 포트 구분자로 오인해 "https://eicuvital.ywmc.or.kr:4432" 입력 시 m_strHost 가 문자 그대로 "https" 가 되어 DNS 조회 실패 (웹모니터링 wss 는 1.18.46 에서 이미 수정되어 정상, 파일 업로드만 실패하는 비대칭 발생 - 현장에서는 업로드 루프의 실패시 break 정책과 겹쳐 "베드명에 # 가 있으면 전송이 안 된다" 로 오인 관찰됨. 실제로는 # 파일이 디렉토리 순서상 항상 첫 시도라 거기서 host 오류로 중단 → 뒤 파일 전체가 막힌 것. 베드명 특수문자는 업로드 URL 과 무관). 수정: Http 생성자에 wss 와 동일한 선행 스킴(https/http) 파싱 추가 - 스킴이 TLS 여부를 결정 (포트 무관, 4432 같은 커스텀 포트에서 https 정상), "https://host" 포트 생략 시 443, 경로 붙은 입력도 host 만 추출. 기존 "host" / "host:443" 형식은 종전과 완전 동일 동작 - 0-impact. Windows(WinINet)/Linux(curl) 공통 생성자라 모든 플랫폼에 적용.
1.18.46
1.18.46 Fixed: WSSClient 가 "https/wss 스킴 + 비표준 포트" 조합을 제대로 처리하지 못하던 문제 (커스텀 포트의 wss 서버에 연결 불가). 원인은 src/wss.cpp 의 WSSClient 생성자 두 곳 - (1) SERVER_IP 파싱이 첫 콜론을 포트 구분자로 써서 "https://host:4432" 를 넣으면 "https" 의 콜론을 먼저 잡아 m_host 가 "https" 가 되고 포트 파싱이 깨져 getaddrinfo 실패, (2) m_secure = (m_port == 443) 로 TLS 여부를 오직 포트 443 여부로만 판단해 4432 같은 커스텀 포트는 무조건 평문 ws 로 붙어 wss 전용 서버에서 실패. 수정: 생성자가 선행 URL 스킴(https/wss/http/ws)을 먼저 파싱해 스킴이 있으면 스킴이 TLS 를 결정(포트 무관)하고, 스킴이 없으면 기존 포트 443 휴리스틱을 유지(하위호환). 이제 SERVER_IP=https://eicuvital.ywmc.or.kr:4432 (또는 wss://...) 형식이 비표준 포트에서도 wss 로 정상 연결되며, SNI/인증서 검증은 도메인(m_host)을 쓰므로 와일드카드 인증서도 정상 매칭. 기존 host / host:443 설정은 종전대로 secure 유지 - 0-impact.
1.18.45
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
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.
Apple Silicon (arm64) only · Requires macOS 11 or later · Developer ID signed & notarized
Download Raspberry Pi Image
Preinstalled SD card image (.img.xz) · Flash to an SD card with Raspberry Pi Imager or balenaEtcher
If you use the VitalRecorder in your research, please cite the following publication:
Lee HC, Jung CW. VitalRecorder-a free research tool for automatic recording of
high-resolution time-synchronised physiological data from multiple anaesthesia devices. Sci Rep.
2018 Jan 24;8(1):1527. doi:
10.1038/s41598-018-20062-4. Available from: https://www.nature.com/articles/s41598-018-20062-4