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

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=1
  • tcp는 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)이면 버튼의 도움말과 작업공간 아래쪽 안내 문구를 먼저 읽습니다. 상태를 맞추기 전에 같은 동작을 반복하면 요청이 여러 개 쌓일 수 있습니다.

문제를 좁히려면 한 번에 한 가지만 바꿉니다.

  1. 같은 SDK 묶음의 예제와 시뮬레이터를 씁니다. 다른 묶음의 PDComm.dll이나 네이티브 라이브러리를 섞지 않습니다.
  2. 이전 세션과 프로세스를 모두 끝내고 새 포트에서 시작합니다.
  3. 기본 설정(Transport fault는 Normal)으로 통신 수립, identity, values만 실행합니다.
  4. 성공하면 확인하려는 기능 하나만 더합니다. 처음 실패한 입력, 시각, 상태를 적습니다.
  5. 같은 영역을 headless 시뮬레이터의 시나리오나 예제 프로그램으로 다시 실행합니다. 다른 환경의 성공 결과로 처음 실패 기록을 덮어쓰지 않습니다.
  6. quit, Stop, DisposeAsync로 정리하고 프로세스 종료 코드를 확인합니다.

진단 로그를 켠 상태로 3–5단계를 실행하면 원인을 찾기 쉽습니다. 로그 설정은 실패 진단과 피드백을 참고합니다.

다음 정보를 모읍니다.

  • 실행한 콘솔의 출력, 오류 메시지, 종료 코드
  • GUI나 MCP에서 내보낸 trace JSON 파일
  • 진단 로그(JSONL) 파일과 written, dropped, write_errors 값
  • 사용한 네이티브 라이브러리의 SHA-256 해시

해시와 실행 환경은 다음 명령으로 확인합니다.

터미널 창
# Linux
sha256sum "$PDCOMM_SDK/lib/libpdcomm_ffi.so"
# macOS
shasum -a 256 "$PDCOMM_SDK/lib/libpdcomm_ffi.dylib"
dotnet --info
uname -a
터미널 창
Get-FileHash "$Sdk\lib\pdcomm_ffi.dll" -Algorithm SHA256
dotnet --info

로그와 trace에는 메시지 본문(body)이 들어가지 않습니다. 그래도 장비 이름, Lot ID, 레시피 이름 같은 비공개 정보가 있으면 가린 뒤 보내고, 무엇을 가렸는지 함께 적습니다. 원본은 직접 보관합니다.

다음 양식을 복사해 채웁니다.

SDK 묶음 버전과 네이티브 라이브러리 SHA-256:
운영체제와 CPU 아키텍처:
언어와 컴파일러 또는 dotnet 버전:
따라 한 문서와 단계:
내 프로그램의 역할과 모드 / 상대의 역할과 모드:
주소(IP:port)와 HSMS 세션 ID:
MCP를 썼다면 session_id, generation, revision:
시작 전 상태와 카탈로그 또는 프로필:
입력한 명령, 누른 버튼, 또는 최소 코드:
기대한 응답이나 값:
실제 응답, 오류 메시지, 종료 코드:
재현 빈도와 처음 발생 시각:
로그와 trace 파일 이름, SHA-256:
다른 경로(headless 시나리오, 예제 프로그램)의 결과:
요청 사항: