이 프로그램은
PortDock Simulator 는 PC 를 «가짜 장비» 로 만들어, 실제 장비 없이 상위 프로그램(마스터·HMI·검사 프로그램)을 시험하는 도구입니다.
받은 데이터가 규칙에 맞으면 정해 둔 응답을 돌려주고, 장비처럼 먼저 상태 보고·하트비트를 보낼 수도 있습니다.
시리얼(COM), TCP 서버, TCP 클라이언트, UDP 네 가지 방식으로 동작합니다.
처음 쓰는 순서
- 1. 왼쪽 «연결 방식» 을 고르고 포트·주소를 넣습니다.
- 2. «+ 규칙 추가» 로 규칙을 만듭니다: «받으면» 패턴, «응답» 내용, 필요하면 체크섬·줄 끝·지연. 규칙이 하나도 없으면 [Modbus RTU 03 응답] [SCPI *IDN? 응답] [에코(받은 것 그대로)] 예제 버튼으로 시작할 수 있습니다.
- 3. «시작» 을 누릅니다. 상위 프로그램에서 요청을 보내면 맞는 규칙이 응답하고, 아래 «통신 기록» 에 찍힙니다.
- 4. 규칙별 «응답한 횟수» 로 어떤 규칙이 몇 번 답했는지 확인합니다.
화면 구성
- 왼쪽: «연결 방식», 포트·주소, «프레임 구분», «시작»/«멈춤», 상태, «파일로 계속 저장».
- 가운데 위: «응답 규칙» 카드들, «끝 문자 떼고 비교»·«안 맞은 요청 기록(NO MATCH)», «횟수 초기화», «규칙 묶음 저장»·«규칙 묶음 불러오기».
- 그 아래: «장비가 먼저 보내기» 접기(평소 접힘, 반복을 켜면 펼쳐짐).
- 맨 아래: «통신 기록»(시각·RX ◀ / TX ▶ / EV·상대 주소·내용), HEX/ASCII 전환, «지우기».
- 머리줄 📌: 항상 위 — 이 창을 다른 창 위에 늘 보이게 합니다(설정의 «항상 위» 와 같음).
- 창 제목에 지금 상태가 나옵니다(예: «COM3 115200 8N1 · 연결됨 ● REC — PortDock Serial»). 작업 표시줄에서 어느 창이 어느 포트인지 알 수 있습니다.
- 창 너비가 900px 이하(화면 반쪽 맞춤 등)면 왼쪽 연결 설정 칸이 접히고, 위에 요약 줄과 «⚙ 연결 설정»·연결 버튼이 나옵니다. «⚙ 연결 설정» 으로 펼치고 ✕ 나 바깥을 눌러 닫습니다.
연결 방식
- «시리얼(COM)»: «포트»·«속도(bps)»·«패리티» 를 고릅니다. 데이터 비트 8, 정지 비트 1, 흐름 제어 없음으로 엽니다. USB 를 뽑았다 꽂으면 저절로 다시 엽니다.
- «TCP 서버 (상대가 접속)»: «주소»(보통 0.0.0.0)와 «포트» 로 기다립니다. 상위 프로그램이 이 PC 로 접속하는 경우입니다. 받은 접속에 각각 응답합니다.
- «TCP 클라이언트 (상대에 접속)»: «접속할 곳» 의 주소·포트로 접속합니다. 상위 프로그램이 서버로 기다리는 경우입니다. 끊기면 다시 접속합니다.
- «UDP»: «받을 포트» 로 받고, 응답은 보낸 쪽으로 돌려줍니다. «보낼 곳» 은 장비가 먼저 보낼 때 아직 받은 것이 없으면 쓰입니다. 브로드캐스트 주소(255.255.255.255, x.x.x.255)로 보내려면 시작 전에 «브로드캐스트 허용» 을 켜세요.
- 실행 중에는 연결 방식·포트·주소·속도를 바꿀 수 없습니다(🔒). 멈추고 바꾸세요. 프레임 구분·응답 규칙·비교 옵션은 실행 중에도 바로 적용됩니다.
- 재접속 대기·멈춤 상태줄에는 마지막 실패 이유가 함께 나옵니다.
- 시리얼인데 포트가 없으면 «시작» 이 잠깁니다.
프레임 구분
규칙은 «한 덩어리(프레임)» 단위로 비교합니다. 그래서 받은 바이트를 어디서 끊을지 정합니다(UDP 는 데이터그램 하나가 한 덩어리라 필요 없음).
- «끊김 시간(조용한 간격)»: «끊김 시간(ms)» 동안 아무것도 안 오면 끊습니다. Modbus RTU 같은 바이너리 프로토콜에 맞습니다.
- «끝 문자»: «끝 문자(HEX)»(예: 0A, 0D 0A)가 오면 끊습니다. 끝 문자가 안 와도 «끊김 시간(ms)» 이 지나면 내보냅니다. ASCII 명령에 맞습니다. 처음 고르면 끝 문자 0A(LF)·끊김 시간 50ms 로 시작합니다.
- «끝 문자(HEX)» 는 «0D 0A», «0D0A», «CR LF»·«CRLF» 처럼 써도 됩니다. 칸 아래에 «해석: 0D 0A (2바이트)» 처럼 읽은 결과가, 읽을 수 없으면 빨갛게 이유가 나옵니다. 비어 있으면 끊김 시간으로만 끊는다고 알려 줍니다.
- 실행 중에 바꿔도 바로 적용됩니다.
응답 규칙
카드 하나가 규칙 하나입니다. 위에서부터 차례로 비교해 처음 맞는 규칙 하나만 응답합니다. 맞는 규칙이 없으면 아무 응답도 하지 않습니다.
- 체크박스: 규칙 켜기·끄기. 끈 규칙은 건너뜁니다.
- 이름: 기록에 «AUTO 이름» 으로 남고 응답 횟수도 이름으로 셉니다. 이름이 겹치면 경고가 나옵니다.
- «받으면»: 패턴 방식(HEX/ASCII), «정확히»(프레임 전체가 같아야 함) 또는 «포함»(프레임 안 어딘가에 있으면 됨), 패턴. ASCII 면 «와일드카드» 체크가 붙습니다(아래 «와일드카드»).
- 새 규칙(«+ 규칙 추가»)은 바로 위 규칙의 방식 — 받기 HEX/ASCII·정확히/포함, 응답 HEX/ASCII·체크섬·줄 끝 — 을 물려받습니다. 와일드카드는 늘 꺼진 채 시작합니다.
- 통신 기록의 RX 줄(또는 «NO MATCH» 줄)을 오른쪽 버튼으로 누르고 «이 요청으로 규칙 만들기» 를 고르면 그 바이트로 규칙을 만들고 응답 칸으로 갑니다. 글자면 ASCII·글자 그대로(끝 CR·LF 는 빼고 응답 줄 끝으로), Modbus RTU 면 CRC 자리를 «**» 로 하고 응답 체크섬을 CRC16 Modbus 로, Modbus TCP 면 트랜잭션 ID 를 «?? ??» 로 둡니다. «**» 같은 무엇이든 받는 규칙이 있으면 그 위에 넣습니다.
- «끝 문자 떼고 비교»(기본 켬): 받은 프레임 끝의 끝 문자와 뒤쪽 CR·LF 를 떼고 비교합니다. 그래서 «정확히» 패턴에 줄 끝을 적지 않아도 됩니다. 끄면 받은 바이트 그대로 비교합니다.
- «안 맞은 요청 기록(NO MATCH)»(기본 켬): 어떤 규칙에도 맞지 않은 요청을 통신 기록에 «NO MATCH» 사건(EV)으로 남깁니다.
- «응답»: 응답 방식(HEX/ASCII), 응답 내용, «체크섬», «줄 끝 붙이기», «지연»(ms, 0~600000).
- 응답은 «내용 + 체크섬 + 줄 끝» 순으로 만듭니다. 체크섬은 응답 내용 전체로 계산합니다. 내용에 {req 0..1}·{counter}·{rand 0..9}·{time}·{crc …} 같은 자리를 쓰면 받을 때마다 채웁니다(아래 «응답 템플릿»).
- «▸ 자세히»: 지연 범위(흔들림)·N번째마다·확률로 무응답, 응답 여러 개 돌리기, 예시 요청으로 응답 미리보기(아래 «장애 흉내·응답 돌리기»).
- ↑ «위로(먼저 검사)», ↓ «아래로», ✕ «삭제»(확인 창 대신 5초 동안 알림의 «되돌리기» 로 같은 자리에 되살림). 응답의 HEX↔ASCII 를 바꾸면 같은 바이트의 새 표기로 바뀝니다.
- 규칙을 고치면 실행 중에도 바로 적용됩니다. 패턴·응답이 틀린 규칙은 카드가 빨갛게 되고 아래에 이유가 나오며, 그 규칙만 빠지고 나머지 규칙은 동작합니다(«틀린 규칙 N개는 빼고 동작합니다»).
- 규칙은 프로그램을 껐다 켜도 남아 있습니다.
와일드카드
- HEX: «??» = 아무 바이트 1개, «**» = 아무 바이트 0개 이상.
- ASCII 는 규칙마다 «와일드카드» 체크로 정합니다. 끄면(새 규칙의 기본) ?·* 도 글자 그대로 비교합니다 — SCPI «*IDN?» 를 그대로 쓰면 «*IDN?» 에만 맞고 «XIDN!» 에는 맞지 않습니다.
- 켜면 «?» = 아무 글자 1개, «*» = 0개 이상입니다. 켠 채 ?·* 글자 자체를 맞추려면 «\x3F»(?)·«\x2A»(*) 로 쓰세요. 켠 규칙의 패턴에 ?·* 가 있으면 노란 알림줄과 [와일드카드 끄기] 가 나옵니다.
- 이 체크가 생기기 전(10/18 이전)에 저장한 규칙은 켜진 채로 읽어 동작이 바뀌지 않습니다. «\r»·«\n»·«\xNN» 이스케이프는 어느 쪽이든 씁니다.
- 예: «01 03 ?? ?? 00 01 **» = 주소 1·기능 03·아무 시작 주소·개수 1, 뒤의 CRC 는 무엇이든.
- 예: ASCII «포함» + «STATUS?» — 와일드카드를 끄면 «STATUS?» 글자가 있을 때만, 켜면 «STATUS» 다음에 아무 글자 1개가 있으면(물음표가 아니어도) 맞습니다.
- «**» 하나만 있는 규칙은 무엇이든 받습니다. 맨 아래에 두면 «그 밖의 모든 요청» 에 대한 기본 응답(예: NAK)이 됩니다.
응답 템플릿 ({…} 자리)
응답 칸에 {…} 자리를 쓰면 받을 때마다 채워 보냅니다. HEX·ASCII 어느 쪽에도 쓰고, 칸 옆 «자리 넣기» 로 커서 자리에 넣을 수 있습니다.
- {req} 요청 전체 · {req 0..1} 요청 0~1번 바이트(끝 포함) · {req 6} 한 바이트 · {req 2..} 2번부터 끝까지 · {req -2..-1} 끝에서 2바이트(음수는 끝에서, -1 = 마지막).
- {counter} 이 규칙이 지금까지 응답한 횟수(0부터) 1바이트 · {counter 2}·{counter 4} 바이트 수 · 뒤에 le 면 리틀 엔디언(기본 빅 엔디언) · {counter dec} 10진 글자. «횟수 초기화» 로 0 부터 다시.
- {rand 0..100} 그 사이(끝 포함) 무작위 값(크기는 최댓값에 맞춰 1·2·4바이트) · {rand 0..1000 2 le} 크기·순서 지정 · {rand 10..99 dec} 10진 글자.
- {time} 지금 시각 «HH:MM:SS» 글자 · {time %Y-%m-%d %H:%M:%S} 형식 지정 · {unix} 유닉스 초 · {unix ms} 밀리초.
- {crc 종류} 이 자리 앞의 모든 바이트로 계산한 체크섬을 여기에 · {crc bcc 1..-1} 범위 지정(체크섬 자리를 뺀 응답 바이트 기준) · 끝에 swap 이면 바이트 순서 뒤집기. 종류: crc16-modbus·crc16-ccitt·crc16-xmodem·crc8·lrc·bcc·sum8·sum16·crc32.
- 순서: 자리 채우기 → {crc} 자리 → 규칙의 «체크섬»(전체에) → «줄 끝». 그래서 «01 03 02 {req 4..5}» + 체크섬 CRC16 Modbus 도, «01 03 02 {req 4..5} {crc crc16-modbus}» 도 같은 결과입니다.
- 예) Modbus TCP 보유 레지스터 2개 읽기 응답 — 받으면 «?? ?? 00 00 00 06 ?? 03 **», 응답 «{req 0..1} 00 00 00 07 {req 6} 03 04 00 64 00 C8». 트랜잭션 ID(0~1번)와 MBAP Unit ID(6번, 국번)를 요청 그대로 돌려줘서 마스터가 짝을 맞춥니다. MBAP 에는 CRC 가 없으므로 체크섬은 «없음».
- 예) 시퀀스 번호가 붙는 장비 — «ACK {counter dec}\r\n»(ASCII). 예) STX…ETX 뒤 BCC — «02 {req 1..-2} 03 {crc bcc 1..-1}».
- 요청이 짧아 {req 9} 같은 자리를 채울 수 없으면 보내지 않고 통신 기록에 «AUTO 이름 — 요청 범위 …» 를 남깁니다. 알려진 이름(req·counter·rand·time·unix·crc)이 아닌 { 는 글자 그대로 나갑니다(예: {"ok":1}). «{req» 같은 글자를 그대로 보내려면 ASCII 에서 \x7B 로 쓰세요.
- «자세히» 의 «예시 요청» 에 요청을 적으면(패턴과 같은 HEX/ASCII) 규칙에 맞는지와 실제로 나갈 응답 바이트를 바로 보여 줍니다. 횟수 0·무작위 예시 값으로 채운 것이라 실제 값은 매번 다릅니다.
장애 흉내·응답 돌리기
규칙 카드의 «▸ 자세히» 를 펼치면 상위 프로그램의 시간 초과·재시도·상태 변화 처리를 시험할 수 있습니다. 켜 둔 것은 카드 아래 작은 표시(«지연 10~50ms», «3번째마다 버림» 등)로 늘 보입니다.
- «지연 범위»: 처음 값~끝 값(ms) 사이에서 매번 무작위로 늦게 답합니다(흔들림). 끝 값이 처음 값 이하이면 처음 값으로 고정 지연. 기록에 «AUTO 이름 +37ms» 처럼 실제 지연이 남습니다.
- «N번째마다 무응답»: 이 규칙에 맞은 N번째·2N번째… 요청에는 답하지 않습니다(0 = 끔). «확률(%)로 무응답»: 그 확률로 답하지 않습니다. 버린 요청은 «DROP 이름 — …» 사건 줄로 남고 응답 횟수에는 들어가지 않습니다.
- «응답 돌리기»: «+ 응답 추가» 로 응답을 여러 개 두면 맞을 때마다 «차례로»(1 → 2 → … → 1) 또는 «무작위» 로 바꿔 보냅니다. 장비 상태(대기 → 동작 → 완료)가 바뀌는 흉내에 씁니다. 기록에 «AUTO 이름 [2/3]» 처럼 몇 번째 응답인지 남습니다.
- «차례로» 와 {counter} 는 규칙의 응답 횟수를 씁니다 — «횟수 초기화» 로 처음부터. 규칙을 고쳐도(이름이 같으면) 이어서 셉니다.
규칙 경고
- «무엇이든 받아서 아래 규칙은 응답하지 않습니다»: «**» 같은 규칙이 다른 규칙보다 위에 있습니다. ↓ 로 맨 아래로 옮기세요.
- «위 규칙과 패턴이 같아 응답하지 않는 규칙»: 같은 패턴이 위에 있어 아래 규칙은 영영 쓰이지 않습니다.
- «이름이 같은 규칙»: 응답 횟수가 합쳐져 구분이 안 됩니다. 이름을 바꾸세요.
응답 횟수와 규칙 묶음
- 카드마다 «응답한 횟수» 가 나옵니다. «횟수 초기화» 로 0 으로 되돌립니다.
- «규칙 묶음 저장»: 규칙 전체와 연결 방식·포트·주소(브로드캐스트 포함)·프레임 구분·비교 옵션·«장비가 먼저 보내기» 내용·반복 간격을 한 JSON 파일(프로필)로 저장합니다. 장비·시험마다 만들어 두세요.
- «규칙 묶음 불러오기»: 지금 규칙·설정을 바꿀지 먼저 묻고, 파일 내용으로 바꿉니다. 실행 중이면 연결 설정은 빼고 불러옵니다. 예전 파일(규칙·프레임 구분만)도 읽으며, 파일에 없는 설정은 그대로 둡니다. 형식이 틀리면 «규칙 묶음 파일 형식이 틀립니다» 가 나오고 그대로 둡니다.
장비가 먼저 보내기
장비가 요청 없이 보내는 상태 보고·하트비트·알람을 흉내 냅니다. 응답 규칙과는 따로이며, 규칙 칸으로 오해하지 않게 평소에는 접혀 있습니다(접힌 제목에 지금 내용, 반복 중이면 «1000 ms 마다 보내는 중»). 반복을 켜면 저절로 펼쳐지고, 열고 닫은 상태는 기억합니다.
- HEX/ASCII, 내용, «체크섬», «줄 끝 붙이기» 를 정하고 «보내기» 를 누릅니다. 아래에 실제로 나갈 바이트가 보입니다.
- 내용에 응답 템플릿을 쓸 수 있습니다(10/19): {counter dec} 는 보낸 횟수(시작할 때마다 0부터), {rand 0..100 dec} 는 무작위 값, {time}·{unix ms} 는 시각, {crc …} 는 체크섬 — 보낼 때마다 새로 채웁니다(«응답 템플릿» 절, {req} 는 요청이 없어 못 씀). 아래 «보낼 바이트» 는 예시 값입니다. 예) «{rand 20..25 dec}.{rand 0..9 dec},{counter dec}» + 줄 끝 CR LF + 반복 100ms → PortDock Plot 으로 그래프.
- «반복(ms)» 을 체크하면 정한 간격(10ms 이상)으로 계속 보냅니다. 상대가 아직 없거나 끊겼으면 그 차례만 건너뛰고 «상대를 기다리는 중» 을 보이며, 상대가 붙으면 이어서 보냅니다. 체크를 끄거나 «멈춤» 을 눌러야 꺼집니다.
- 보내는 곳: 시리얼은 그 포트, TCP 서버는 접속한 모든 상대, TCP 클라이언트는 접속한 상대, UDP 는 마지막으로 보내온 쪽(없으면 «보낼 곳»).
- 시작 전에는 «보내기»·«반복» 이 잠깁니다.
- HEX↔ASCII 를 바꾸면 입력 내용이 같은 바이트의 새 표기로 바뀝니다(예: «41 54 0D 0A» ↔ «AT» + CR LF 이스케이프). 못 읽는 내용이면 글자는 그대로 두고 알림줄에 이유가 나옵니다.
- 바꿀 때 체크섬이 켜져 있으면 확인 창 대신 알림줄에 «체크섬 … 이 켜져 있습니다» 와 «체크섬 끄기» 버튼이 나옵니다.
통신 기록
- RX ◀ 받은 것, TX ▶ 보낸 것(규칙 응답·먼저 보내기), EV 사건(시작·접속·끊김·«AUTO 규칙이름» 등).
- RX 줄·«NO MATCH» 줄의 오른쪽 버튼 메뉴 «이 요청으로 규칙 만들기» 로 받은 요청을 옮겨 적지 않고 규칙을 만듭니다(위 «응답 규칙»).
- HEX/ASCII 버튼으로 보기 방식을 바꿉니다. 맨 아래에 있으면 새 줄을 따라 내려가고, 위로 올려 보면 멈춥니다.
- «파일로 계속 저장»: 시작한 뒤에 파일을 고르면 그때부터 모든 줄을 계속 씁니다. «저장 멈춤» 으로 끝냅니다.
- 따라가기: 맨 아래에 있을 때만 새 줄을 따라 내려갑니다. 위로 굴리면 멈추고(새 줄이 와도 읽던 자리 그대로) 오른쪽 아래에 «↓ 맨 아래로 (새 줄 n)» 이 나옵니다. 누르거나 End, 또는 맨 아래까지 굴리면 다시 따라갑니다.
- 줄 고르기: 누르면 그 줄, Shift+누르기는 범위, Ctrl+누르기는 하나씩 더하기·빼기. 줄을 눌러도 따라가기는 꺼지지 않습니다.
- 오른쪽 버튼 메뉴: 줄 복사 · HEX 복사 · ASCII 복사 · HEX + ASCII 복사 · C 배열로 복사({0x01, 0x03}) · 다시 보내기(TX 줄 — 그 바이트 그대로). 내용 복사(HEX·ASCII·C 배열)는 사건 줄(EV)을 빼고 한 줄에 한 프레임씩 씁니다.
설정(⚙)
- «언어»·«테마»·«글자 크기»·«로그 시각 표시»·«화면에 남길 줄 수».
- «연결하면 자동으로 파일 로그 시작»: «자동 로그 폴더» 를 고르면 시작할 때마다 자동으로 저장합니다.
- «연결·기록 중에 창을 닫으려 하면 묻기».
- «설정 내보내기»·«설정 가져오기»: 화면 설정을 JSON 파일로 옮깁니다. 규칙은 «규칙 묶음 저장» 으로 따로 옮깁니다.
- «항상 위»: 이 창을 다른 창 위에 늘 보이게 합니다(머리줄 📌 과 같은 값).
- «모두 펼치기(전문가 화면)»: 평소 접어 두는 칸(고급 연결·받기 설정·장애 주입·통계·찾는 방법·트리거·자동응답 등)을 펼친 채 보입니다. 켜 둔 채 하나를 접으면 이번 실행 동안만 접힙니다. 끄면 칸마다 기억해 둔 열림 상태로 돌아갑니다.
단축키·팁
- F4: 시작·멈춤(왼쪽 버튼과 같음).
- Ctrl+L: 화면 기록 지우기(파일 로그는 그대로).
- Ctrl+Shift+L: 파일로 계속 저장 켜기·끄기.
- Esc: 반복 보내기 멈춤(입력칸 밖에서 — 입력칸 안의 Esc 는 그 칸의 동작).
- End: 로그 맨 아래로 가서 다시 따라가기.
- Ctrl+C: 고른 로그 줄을 «시각 방향 내용» 으로 복사(지금 보기대로). 입력칸 안에서는 보통 복사.
- F1 또는 화면의 ? 버튼: 이 도움말. Esc 로 닫습니다.
- 숫자 칸: ↑/↓ 1씩, Shift+↑/↓ 10씩, PageUp/PageDown 100씩, 칸을 누른 뒤 마우스 휠. 속도 칸은 ↑/↓ 로 목록의 다음·앞 속도.
- 대화상자·우클릭 메뉴가 열려 있거나 한글을 조합하는 중에는 단축키가 동작하지 않습니다.
- 칸에 마우스를 올리면 말풍선으로 설명이 나옵니다.
- 같은 PC 에서 시험하려면: TCP 는 서버 127.0.0.1 로, 시리얼은 가상 COM 쌍(com0com 등)으로 상위 프로그램과 연결합니다.
- 응답 지연으로 상위 프로그램의 타임아웃 처리를, 일부러 틀린 응답으로 오류 처리를 시험할 수 있습니다.
문제 해결
- 응답이 안 나감: 규칙이 켜져 있는지, 패턴 방식(HEX/ASCII)·«정확히/포함» 이 맞는지, 위에 «**» 규칙이 있는지 보세요. 통신 기록의 RX 줄과 패턴을 비교하세요. «안 맞은 요청 기록» 을 켜 두면 안 맞은 요청마다 «NO MATCH» 줄이 남고, 그 줄의 오른쪽 버튼으로 바로 규칙을 만들 수 있습니다. 엉뚱한 요청에 답하면 ASCII 규칙의 «와일드카드» 가 켜져 있지 않은지 보세요.
- 요청이 둘로 쪼개지거나 합쳐짐: «프레임 구분» 과 «끊김 시간(ms)» 을 조정하세요.
- 시리얼 포트가 안 열림: 다른 프로그램이 쓰고 있는지 확인하세요.
- TCP 서버에 접속이 안 됨: 윈도우 방화벽 허용, 포트, 상위 프로그램이 접속하는 IP 를 확인하세요.
- 프로그램이 안 열림: Microsoft Edge WebView2 가 필요합니다(윈도우 11 은 기본 포함).