콘텐츠로 이동
무료 평가 시작

pdcomm-vserial 명령과 랩 파일

pdcomm-vserial은 랩(lab)을 검사하고 실행하는 명령줄 프로그램입니다. 랩의 개념은 가상 시리얼 포트의 개념에서 설명합니다.

명령 하는 일
pdcomm-vserial run --config <파일> 랩을 시작하고 표준 입력의 제어 명령을 처리합니다.
pdcomm-vserial check --config <파일> 랩 파일을 검사만 합니다. 올바르면 {"valid":true}를 출력합니다.
pdcomm-vserial pair [--instant] [--link-a <경로>] [--link-b <경로>] 의사 터미널 두 개를 널 모뎀으로 이은 랩을 바로 시작합니다. 기본 9600bps 8N1, realistic 진행입니다. --instant는 지연 없이 전달합니다.
pdcomm-vserial daemon --config <파일> 서비스로 실행합니다. 표준 입력을 읽지 않고 SIGTERM이나 SIGINT를 받으면 랩을 정리하고 끝납니다. macOS와 Linux에서만 동작합니다.
pdcomm-vserial ports list Windows: 설치한 포트를 보여 줍니다.
pdcomm-vserial ports install --inf <INF> [--count N] [--first-com N] Windows: 포트가 N개(기본 2)가 될 때까지 만들고 드라이버를 설치합니다. 관리자 권한이 필요합니다.
pdcomm-vserial ports remove Windows: 포트 장치를 모두 지웁니다. 관리자 권한이 필요합니다.
pdcomm-vserial ports uninstall Windows: 포트, 드라이버 패키지, 필터 서비스를 모두 지웁니다. 관리자 권한이 필요합니다.
pdcomm-vserial --help, --version 사용법이나 버전을 표준 출력에 씁니다.

종료 코드는 다음과 같습니다.

코드 의미
0 성공했습니다. 랩은 정상적으로 멈췄습니다.
1 랩 파일 오류, 포트 열기 실패 같은 오류입니다. 표준 오류에 pdcomm-vserial: <원인>을 씁니다.
2 명령이나 옵션이 잘못되었습니다. 표준 오류에 사용법을 씁니다.

run과 pair는 랩이 준비되면 표준 출력에 포트 목록 한 줄을 씁니다.

{"ports":[{"backend":"pty","link":"/tmp/pdcomm-plc","node":"plc","path":"/dev/ttys011"},{"backend":"pty","link":"/tmp/pdcomm-hmi","node":"hmi","path":"/dev/ttys016"}],"ready":true}
필드 의미
node 노드 이름
backend pty, driver, tcp_server, rfc2217_server
path 응용 프로그램이 여는 장치 경로. 의사 터미널과 Linux 드라이버 포트에 있습니다.
link link로 만든 심볼릭 링크
listen TCP 서버가 실제로 수신 대기하는 주소. 포트 0을 지정하면 운영체제가 고른 포트가 나옵니다.

그 뒤 표준 입력의 각 줄을 JSON 명령 하나로 처리하고 한 줄로 응답합니다.

명령 응답
{"command":"ports"} {"ok":true,"ports":[…]}
{"command":"inject","node":"b","fault":{"xor":1}} {"ok":true}
{"command":"attach","node":"a","attached":false} {"ok":true}. false는 케이블 분리, true는 연결입니다.
{"command":"stop"} 응답 없이 랩을 멈추고 끝납니다. 입력 끝(EOF)도 같습니다.

fault에는 "drop", {"xor": <0~255>}, {"error": "parity"}(parity, framing, overrun, break), {"noise": {"byte": <0~255>, "error": null}}을 씁니다. 잘못된 명령에는 {"ok":false,"error":"…"}로 응답하고 랩은 계속 실행합니다.

랩 파일은 1MiB 이하의 JSON입니다. 모르는 필드가 있으면 오류로 거부합니다. 오타가 조용히 무시되지 않습니다.

null-modem.json
{
"engine": {
"pacing": "realistic",
"nodes": [
{"name": "plc", "port": {"line": {"baud": 19200, "data_bits": 8, "parity": "even", "stop_bits": "1"}}},
{"name": "hmi", "port": {"line": {"baud": 19200, "data_bits": 8, "parity": "even", "stop_bits": "1"}}}
],
"media": [{"kind": "null_modem", "a": "plc", "b": "hmi"}]
},
"ports": [
{"node": "plc", "backend": {"type": "pty", "link": "/tmp/pdcomm-plc"}},
{"node": "hmi", "backend": {"type": "pty", "link": "/tmp/pdcomm-hmi"}}
],
"trace": "null-modem-trace.jsonl"
}
필드 설명
engine 필수. 진행 방식, 노드, 매체를 정의합니다.
ports 노드를 끝점에 연결하는 바인딩 목록. 노드마다 하나까지 둡니다.
trace 회선 사건을 JSON Lines로 쓸 파일 경로. 상대 경로는 현재 폴더 기준입니다.
allow_remote true면 루프백이 아닌 주소에서 TCP 서버를 엽니다. 기본값은 false입니다.
bridges 노드를 원격 RFC 2217 장치 서버에 잇는 목록
driver Linux 드라이버 제어 장치 경로. 기본값은 /dev/pdcomm-vserial입니다.
필드 설명
pacing realistic(기본) 또는 instant
nodes 노드 목록
media 매체 목록. kind가 null_modem, loopback, four_wire, two_wire 중 하나입니다.
{"name": "master",
"port": {"line": {"baud": 9600, "data_bits": 8, "parity": "none", "stop_bits": "2"},
"flow": "none",
"rts_toggle": {"on_send": true, "delay_before_ns": 0, "delay_after_ns": 0, "rx_during_tx": false}},
"attach": {"driver_enable": {"rts": {"asserted": true}}, "echo": false},
"faults": {"seed": 7, "flip_ppm": 1000, "latency_ns": 200000, "jitter_ns": 50000},
"rx_fifo": {"trigger": 1, "idle_chars": 4}}
필드 설명
name 필수. 랩 안에서 고유한 이름
port.line baud(116000000), data_bits(58), parity, stop_bits("1", "1.5", "2"). 랩이 시작할 때의 회선 설정입니다.
port.flow none, rts_cts, xon_xoff
port.rts_toggle 송신마다 RTS를 자동으로 올리고 내립니다. 지연(나노초)과 송신 중 수신(rx_during_tx)을 지정합니다.
attach.driver_enable 버스 송신 조건: "always", "auto", {"rts": {"asserted": true}}
attach.echo 송신 중에도 자기 문자를 받습니다.
attach.fixed_inputs 상대와 관계없이 켜 둘 입력 신호(cts, dsr, dcd, ri)
faults 확률 결함과 지연: seed, drop_ppm, flip_ppm, parity_ppm, framing_ppm, overrun_ppm, noise_ppm, latency_ns, jitter_ns
rx_fifo 수신 FIFO. 기본 {"trigger": 14, "idle_chars": 4}, null이면 문자마다 전달합니다.
backend 필드
{"type": "pty", "link": "/tmp/pdcomm-plc"} link는 선택입니다. 의사 터미널 경로에 고정 링크를 만들고 랩이 멈추면 지웁니다.
{"type": "driver", "index": 0} 설치한 드라이버의 포트 번호(0~63)
{"type": "tcp_server", "listen": "127.0.0.1:7002"} 원시 TCP. 회선 설정은 랩 파일의 값으로 고정됩니다. 클라이언트는 하나만 받습니다.
{"type": "rfc2217_server", "listen": "127.0.0.1:7001"} RFC 2217 서버. 클라이언트가 회선 설정과 신호를 바꿉니다.

다음 랩은 노드 device를 RFC 2217 서버로, 노드 app을 의사 터미널로 열고 두 노드를 널 모뎀으로 잇습니다.

rfc2217-server.json
{
"engine": {
"pacing": "realistic",
"nodes": [{"name": "device"}, {"name": "app"}],
"media": [{"kind": "null_modem", "a": "device", "b": "app"}]
},
"ports": [
{"node": "device", "backend": {"type": "rfc2217_server", "listen": "127.0.0.1:7001"}},
{"node": "app", "backend": {"type": "pty", "link": "/tmp/pdcomm-app"}}
]
}
터미널 창
pdcomm-vserial run --config rfc2217-server.json

RFC 2217 클라이언트라면 무엇이든 127.0.0.1:7001에 연결합니다. 예를 들어 pyserial이 설치된 Python으로 다음을 실행하면 /tmp/pdcomm-app을 연 응용 프로그램이 hello를 받습니다.

터미널 창
python3 -c 'import serial; s = serial.serial_for_url("rfc2217://127.0.0.1:7001", baudrate=9600, timeout=1); s.write(b"hello\n")'

클라이언트가 속도를 바꾸면 device 노드의 설정이 바뀝니다. 응용 프로그램 쪽 설정과 다르면 실제 회선처럼 깨진 문자가 도착합니다.

bridges는 로컬 노드를 다른 곳의 RFC 2217 서버에 연결합니다. 시리얼 장치 서버(device server)에 꽂은 실제 장비를 로컬 포트처럼 쓸 때 사용합니다. 브리지 노드는 포트 바인딩이 있고 매체에는 연결하지 않습니다.

{
"engine": {"nodes": [{"name": "remote", "port": {"line": {"baud": 9600}}}]},
"ports": [{"node": "remote", "backend": {"type": "pty", "link": "/tmp/pdcomm-bridge"}}],
"bridges": [{"node": "remote", "rfc2217": "127.0.0.1:7001"}]
}

rfc2217에는 장치 서버의 호스트:포트를 씁니다. 응용 프로그램이 /tmp/pdcomm-bridge에서 바꾼 속도, 형식, 신호, 브레이크가 원격 포트로 전달됩니다.

check와 run은 다음 오류를 냅니다.

메시지 원인
unknown field `prot`, expected one of `name`, `port`, … 필드 이름이 틀렸습니다.
invalid virtual serial configuration: duplicate node a 노드 이름이 겹칩니다.
invalid virtual serial configuration: node a is wired twice 한 노드를 매체 두 개에 연결했습니다.
invalid virtual serial configuration: a two-wire bus needs at least two nodes 2선식 버스의 노드가 부족합니다.
invalid virtual serial configuration: baud rate must be between 1 and 16000000 속도가 범위를 벗어났습니다.
invalid virtual serial configuration: data bits must be between 5 and 8 데이터 비트가 범위를 벗어났습니다.
port binds unknown node x 바인딩의 node가 노드 목록에 없습니다.
node a is bound twice 한 노드에 바인딩이 두 개 있습니다.
driver port 64 is invalid or bound twice 드라이버 포트 번호가 0~63을 벗어났거나 겹칩니다.
0.0.0.0:7002 is not a loopback address; set allow_remote to expose it 외부 주소로 공개하려면 allow_remote가 필요합니다.
bridge node a needs a port binding, no wiring, and one bridge 브리지 노드의 조건을 지키지 않았습니다.
configuration exceeds one MiB 파일이 1MiB를 넘습니다.

실행 중 오류는 도구 문제 해결을 참고합니다.