SECS/GEM 문제 해결
이 장은 PDComm SECS/GEM SDK와 시뮬레이터를 쓰다가 막혔을 때 원인을 좁히는 순서를 설명합니다. 오류 코드의 뜻은 상태 코드와 오류에, 연결과 타이머 문제는 연결과 시간 초과에 정리되어 있습니다.
어느 단계에서 멈췄는지 먼저 확인합니다
섹션 제목: “어느 단계에서 멈췄는지 먼저 확인합니다”SECS/GEM 통신은 다음 순서로 진행합니다. 각 단계가 끝나야 다음 단계로 넘어갑니다.
프로그램 시작 ─> TCP 연결 ─> HSMS Select ─> GEM 통신 수립 ─> 요청과 응답(라이브러리 로드) tcp=1,2,5 tcp=3 → 4 gem=1 → 3 RESULT ...튜토리얼 예제(pdcomm-tutorial, PDComm.Tutorial)에서 state를 입력하면 현재 단계가 숫자로 나옵니다.
STATE tcp=4 gem=1tcp는 HSMS 연결 상태입니다. 0 Stopped, 1 Connecting, 2 Listening, 3 NotSelected, 4 Selected, 5 RetryWait입니다.gem은 GEM 통신 상태입니다. 0 Disconnected, 1 NotCommunicating, 2 WaitingAck, 3 Communicating입니다.
C# 예제는 같은 값을 이름으로 출력합니다(STATE tcp=Selected gem=NotCommunicating). 시뮬레이터 GUI에서는 Overview 작업공간의 TCP TRANSPORT, HSMS SELECTION, GEM COMMUNICATION 카드가 같은 정보를 보여 줍니다.
통신 기록이 더 필요하면 진단 로그(diagnostics log)를 켭니다. 방법은 실패 진단과 피드백에 있습니다.
증상별 점검표
섹션 제목: “증상별 점검표”| 증상 | 먼저 확인할 것 | 다음으로 확인할 것 |
|---|---|---|
| 프로그램이 시작하자마자 라이브러리를 찾지 못합니다. | 운영체제와 CPU 아키텍처가 SDK 묶음과 같은지 확인합니다. 네이티브 라이브러리(native library) 위치를 지정했는지 확인합니다. Windows는 PATH, Linux는 LD_LIBRARY_PATH입니다. macOS는 빌드할 때 -Wl,-rpath로 sdk/lib를 넣습니다. |
Windows C++ 프로그램은 x64 Visual C++ 런타임이 필요합니다. macOS에서는 dyld: Library not loaded: @rpath/libpdcomm_ffi.dylib가 rpath 누락을 뜻합니다. |
C# 프로그램이 PdcommRuntime.Initialize에서 실패합니다. |
네이티브 라이브러리의 절대 경로를 넘겼는지 확인합니다. 경로가 틀리면 System.DllNotFoundException이 납니다. |
NotSupportedException은 PDComm.dll과 네이티브 라이브러리의 ABI 버전이 맞지 않는다는 뜻입니다. 같은 SDK 묶음의 두 파일을 함께 씁니다. |
| 시뮬레이터가 Qt 플랫폼 플러그인을 찾지 못합니다. | simulator 폴더 전체를 그대로 복사했는지 확인합니다. 플러그인과 고지 파일도 함께 있어야 합니다. |
다른 Qt 설치의 QT_PLUGIN_PATH, QTDIR 환경 변수가 설정되어 있으면 지웁니다. 화면이 없는 Linux 서버에서는 headless 시뮬레이터를 씁니다. |
Passive 쪽이 tcp=2(Listening)에서 멈춥니다. |
상대 Active 프로그램이 같은 IP 주소와 포트로 실행 중인지 확인합니다. | 양쪽이 모두 Passive인지, 방화벽이 포트를 막는지 확인합니다. |
Active 쪽이 tcp=5(RetryWait)를 반복합니다. |
상대가 그 포트에서 기다리는지 확인합니다. 아무도 없으면 연결 거부(connection refused)가 납니다. | 연결이 거부됨을 참고합니다. |
TCP는 연결됐지만 tcp=3(NotSelected)에서 넘어가지 않습니다. |
상대가 Select.req에 답하지 않아 T6 시간이 지났는지 로그를 봅니다. | 상대 장비에 이미 다른 Host가 연결되어 있는지 확인합니다. Selected가 되지 않음을 참고합니다. |
tcp=4(Selected)인데 gem=1(NotCommunicating)입니다. |
Host가 S1F13 통신 수립을 요청했는지 확인합니다. 튜토리얼에서는 establish, GUI에서는 Establish communication입니다. |
S1F13이 T3 뒤 실패하면 세션 ID(session ID)가 같은지 확인합니다. PDComm은 S1F13을 자동으로 다시 보내지 않습니다. |
values 결과가 비었거나 예상과 다릅니다. |
상대 장비에 등록된 ID인지 확인합니다. 시뮬레이터 기본 Equipment는 SVID 1001, 1002, 튜토리얼 Equipment는 SVID 1, 2입니다. | 없는 ID는 길이 0인 항목으로 돌아옵니다. 예를 들어 values 9의 응답은 SECS-II 01 01 01 00입니다. |
COMMAND ERROR ... InvalidState가 나옵니다. |
현재 상태에서 할 수 없는 요청입니다. 예를 들어 통신 수립 전에 values를 보내거나 establish를 두 번 보낸 경우입니다. |
역할이 맞는지, 시작 전에만 할 수 있는 설정을 시작 후에 호출하지 않았는지 확인합니다. |
COMMAND ERROR ... Backpressure가 나옵니다. |
응답을 기다리는 요청이 한도(연결당 32개)에 찼거나 이벤트 큐가 찼습니다. | 이벤트를 계속 꺼내 처리하고 응답이나 실패 결과가 온 뒤 다시 보냅니다. 무한히 재시도하지 않습니다. |
StaleToken이 나옵니다. |
재연결 전 세대(generation)의 토큰이나 이벤트를 쓰고 있습니다. | 재연결 뒤에는 새 요청으로 흐름을 다시 시작합니다. |
요청 결과가 RESULT kind=3(Failed)입니다. |
실패 이유가 T3 시간 초과인지, 상대가 F0으로 중단(abort)했는지, 연결이 끊겼는지 구분합니다. | 상태 코드와 오류와 T3 응답 시간 초과를 참고합니다. |
| 특정 요청이 매번 T3 뒤 실패하고, 얼마 뒤 모든 요청이 실패합니다. | 상대 애플리케이션이 처리하지 않은 W1 메시지에 응답하지 않는지 확인합니다. | 처리하지 않은 W1 메시지에는 F0으로라도 응답해야 합니다. 처리되지 않은 메시지를 참고합니다. |
모든 호출이 Poisoned를 반환합니다. |
끝점(endpoint) 안에서 예기치 않은 오류가 잡혀 끝점이 더 이상 쓸 수 없습니다. | 끝점을 해제하고 새로 만듭니다. 재현 절차와 로그를 함께 문의합니다. |
| SECS-I 끝점이 Fault 이벤트를 냅니다. | 읽기·쓰기 콜백(callback)이 막히지 않고 바로 돌아오는지, 반환한 바이트 수가 버퍼 크기 이하인지 확인합니다. | 콜백 안에서 끝점 함수를 다시 호출하지 않습니다. 끝점은 만든 스레드에서만 씁니다. SECS-I 가상 쌍을 참고합니다. |
| 로그에 요청 수락만 있고 결과가 없습니다. | 요청 접수(acceptance)와 상대의 응답은 다릅니다. 응답 결과(RESULT kind=2)나 실패 결과(kind=3)가 왔는지 확인합니다. |
장비의 실제 동작 완료는 별도 이벤트나 값으로 확인합니다. ACK 0은 요청을 받았다는 뜻이지 작업이 끝났다는 뜻이 아닙니다. |
GUI의 버튼이 비활성(disabled)이면 버튼의 도움말과 작업공간 아래쪽 안내 문구를 먼저 읽습니다. 상태를 맞추기 전에 같은 동작을 반복하면 요청이 여러 개 쌓일 수 있습니다.
최소 재현 순서
섹션 제목: “최소 재현 순서”문제를 좁히려면 한 번에 한 가지만 바꿉니다.
- 같은 SDK 묶음의 예제와 시뮬레이터를 씁니다. 다른 묶음의
PDComm.dll이나 네이티브 라이브러리를 섞지 않습니다. - 이전 세션과 프로세스를 모두 끝내고 새 포트에서 시작합니다.
- 기본 설정(Transport fault는 Normal)으로 통신 수립,
identity,values만 실행합니다. - 성공하면 확인하려는 기능 하나만 더합니다. 처음 실패한 입력, 시각, 상태를 적습니다.
- 같은 영역을 headless 시뮬레이터의 시나리오나 예제 프로그램으로 다시 실행합니다. 다른 환경의 성공 결과로 처음 실패 기록을 덮어쓰지 않습니다.
quit, Stop,DisposeAsync로 정리하고 프로세스 종료 코드를 확인합니다.
진단 로그를 켠 상태로 3–5단계를 실행하면 원인을 찾기 쉽습니다. 로그 설정은 실패 진단과 피드백을 참고합니다.
문의할 때 보낼 정보
섹션 제목: “문의할 때 보낼 정보”다음 정보를 모읍니다.
- 실행한 콘솔의 출력, 오류 메시지, 종료 코드
- GUI나 MCP에서 내보낸 trace JSON 파일
- 진단 로그(JSONL) 파일과
written,dropped,write_errors값 - 사용한 네이티브 라이브러리의 SHA-256 해시
해시와 실행 환경은 다음 명령으로 확인합니다.
# Linuxsha256sum "$PDCOMM_SDK/lib/libpdcomm_ffi.so"# macOSshasum -a 256 "$PDCOMM_SDK/lib/libpdcomm_ffi.dylib"dotnet --infouname -aGet-FileHash "$Sdk\lib\pdcomm_ffi.dll" -Algorithm SHA256dotnet --info로그와 trace에는 메시지 본문(body)이 들어가지 않습니다. 그래도 장비 이름, Lot ID, 레시피 이름 같은 비공개 정보가 있으면 가린 뒤 보내고, 무엇을 가렸는지 함께 적습니다. 원본은 직접 보관합니다.
다음 양식을 복사해 채웁니다.
SDK 묶음 버전과 네이티브 라이브러리 SHA-256:운영체제와 CPU 아키텍처:언어와 컴파일러 또는 dotnet 버전:따라 한 문서와 단계:내 프로그램의 역할과 모드 / 상대의 역할과 모드:주소(IP:port)와 HSMS 세션 ID:MCP를 썼다면 session_id, generation, revision:시작 전 상태와 카탈로그 또는 프로필:입력한 명령, 누른 버튼, 또는 최소 코드:기대한 응답이나 값:실제 응답, 오류 메시지, 종료 코드:재현 빈도와 처음 발생 시각:로그와 trace 파일 이름, SHA-256:다른 경로(headless 시나리오, 예제 프로그램)의 결과:요청 사항:관련 문서
섹션 제목: “관련 문서”- 상태 코드와 오류: C, C++, .NET의 상태 코드와 GEM 결과, HSMS 이벤트 코드를 정리합니다.
- 연결과 시간 초과: 연결 거부, 포트 충돌, T3·T5·T6·T7·T8을 실제 로그와 함께 설명합니다.
- 실패 진단과 피드백:
PDCOMM_LOG진단 로그와pdcomm_logging_configure를 다룹니다. - headless 시뮬레이터: 화면 없이 시나리오로 문제를 재현합니다.