← 전체 글
SECS/GEM/약 11분 읽기/— 조회

보고서를 지금 읽고 싶을 때 S6F19를 보내면, 이 장비는 S6F0을 돌려준다

재접속 후 보고서를 바로 읽으려고 S6F19와 S6F15를 보냈다. 통신 게이트는 열려 있었는데 둘 다 S6F0으로 끊겼다. 실제 소켓 캡처 기록이다.

SECS/GEMMESSCADATroubleshootingChecklists

호스트가 끊겼다가 다시 붙으면 장비의 현재 값을 모른다. 다음 S6F11을 기다리면 되지만, 그 이벤트가 언제 또 뜰지는 장비가 정한다. 로트 하나가 끝날 때까지 안 뜰 수도 있다. 그래서 보고서를 지금 당장 읽는 메시지를 찾게 되고, SECS-II에 그 자리는 두 개 있다. RPTID 하나를 지정하는 S6F19, CEID 하나를 지정하는 S6F15. 둘 다 보냈다. 둘 다 S6F0으로 끊겼다. 통신 게이트는 그 전에 열어 뒀다.

호스트의 S6F19와 S6F15에는 장비가 S6F0으로 답하고, 같은 소켓의 S1F3에는 S1F4로 값 네 개를 답한다 호스트장비 S6F19 — RPTID 100 S6F0 S6F15 — CEID 1102 S6F0 S1F3 — SVID 101 S1F4 — L[4] 보고서 단위만 abort

캡처

시뮬레이터의 passive listener에 소켓을 직접 열고 보냈다. API가 아니라 소켓이다. 장비 쪽 로그에 RX가 찍혀야 실제로 선을 탄 것이다.

TX Select.req   00 00 00 0A 00 0B 00 00 00 01 00 00 00 01
RX Select.rsp   00 00 00 0A 00 0B 00 00 00 02 00 00 00 01

Select Status는 바이트 3의 00이다. 세션은 SELECTED로 올라갔다.

TX S1F13 W      00 00 00 0C 00 0B 81 0D 00 00 00 00 00 02 01 00
RX S1F14        00 00 00 37 00 0B 01 0E 00 00 00 00 00 02 01 02 21 01 00
                01 02 41 15 56 58 2D 39 30 30 30 20 50 6C 61 73 6D 61 20 45 74 63 68 65 72
                41 0D 53 45 43 53 47 45 4D 2D 31 2E 34 2E 31

이 한 쌍이 이 글의 전제다. 21 01 00은 B[1] 0 — COMMACK 0이다. E30의 통신 게이트가 열렸고, commState는 COMMUNICATING이 됐다. 뒤에 나오는 S6F0은 게이트 탓이 아니다. 게이트가 닫혀 있을 때 모든 데이터 메시지가 SxF0으로 돌아오는 쪽은 별도로 다룬 적이 있다.

TX S6F19 W      00 00 00 10 00 0B 86 13 00 00 00 00 00 03 B1 04 00 00 00 64
RX S6F0         00 00 00 0A 00 0B 06 00 00 00 00 00 00 03

바이트 2가 86이다. 상위 1비트가 W-bit, 나머지가 Stream 6. 바이트 3은 13 = 19. 본문 B1 04 00 00 00 64는 아이템 하나다. B1의 상위 6비트가 44, 즉 U4이고 하위 2비트가 1이라 길이 바이트는 한 개, 그 값이 04니까 4바이트. RPTID 100이다.

답은 14바이트짜리 헤더뿐이다. 바이트 2의 06은 W-bit가 꺼진 Stream 6, 바이트 3은 00 — function 0. E5에서 function 0은 트랜잭션 abort다. SystemBytes 00 00 00 03은 요청 것을 그대로 돌려줬다.

TX S6F15 W      00 00 00 10 00 0B 86 0F 00 00 00 00 00 04 B1 04 00 00 04 4E
RX S6F0         00 00 00 0A 00 0B 06 00 00 00 00 00 00 04

0F은 15, 본문은 U4 00 00 04 4E = CEID 1102다. 같은 S6F0.

여기가 중요하다. CEID 1102는 이 장비에 실제로 있는 이벤트다. Process Complete이고, 장비 상태에 등록돼 있다. RPTID 100은 반대로 내가 아무 데도 정의하지 않은 번호다. 있는 ID와 없는 ID에 똑같은 답이 왔다. 그러니까 이 S6F0은 "그 ID 없다"는 뜻이 아니다. 함수 자체에 대한 거절이다.

TX S1F3 W       00 00 00 12 00 0B 81 03 00 00 00 00 00 05 01 01 B1 04 00 00 00 65
RX S1F4         00 00 00 34 00 0B 01 04 00 00 00 00 00 05 01 04
                41 07 45 78 65 63 75 74 65
                81 08 40 50 5B 85 1E B8 51 EC
                81 08 40 1D F5 C2 8F 5C 28 F6
                41 09 45 54 43 48 5F 42 41 53 45

같은 소켓, 같은 세션, 2ms 뒤. 이쪽은 답이 온다. 01 01 B1 04 00 00 00 65는 L,1 { U4 101 } — SVID 101 하나를 물었다. 돌아온 건 01 04, 원소 네 개다. 41 07은 7바이트 ASCII Execute, 81 08은 8바이트 F8이고 40 50 5B 85 1E B8 51 EC는 IEEE 754 배정도로 65.43, 다음 것은 7.49다. 마지막은 ASCII ETCH_BASE.

하나 물었는데 네 개가 왔다. 이 listener가 SVID 목록을 해석하지 않고 가진 변수를 전부 돌려주기 때문이고, 그 동작은 S1F11 쪽 글에서 따로 짚었다. 지금 이 글에서 S1F4가 증명하는 건 하나다. 소켓은 멀쩡하고 게이트는 열려 있다.

S6F0은 무응답이 아니다

호스트 코드에서 이 둘을 같은 칸에 넣으면 진단이 망가진다.

돌아온 것언제 알게 되나뜻
S6F0즉시장비가 그 function을 거절했다
아무것도 안 옴T3 만료 후답이 유실됐거나 상대가 멈췄다

위 캡처에서 S6F19를 쓴 시각과 S6F0이 찍힌 시각은 같은 밀리초다. T3를 기다린 적이 없다. T3는 E37의 기본값 45초이고, 타이머 쪽은 따로 정리해 뒀다. 호스트 로그에 "S6F19 실패"만 남기면 둘이 구분되지 않는다. function 0을 받았다는 사실을 그대로 적어야 한다.

그러면 재접속 후에 뭘 하나

S6F19가 없는 장비를 전제로 설계하는 쪽이 맞다. 보고서를 보고서 단위로 읽는 길이 막혔다는 뜻이고, 남는 건 호스트가 직접 펼치는 것이다.

  • RPTID와 VID의 매핑은 어차피 호스트가 만든 것이다. S2F33으로 정의를 내려보낸 쪽이 호스트니까, 그 표는 호스트 DB에 있어야 한다. 장비에 되물을 일이 아니다. 정의를 내려보내는 순서 문제는 S2F33/S2F35/S2F37 글에 있다.
  • 복구할 때는 그 표를 펼쳐 VID 목록으로 바꾸고 S1F3을 쏜다. 답은 보고서가 아니라 값의 나열이고, 보고서 모양으로 다시 묶는 건 호스트 몫이다.
  • S1F3으로 읽은 값에는 샘플 시각이 없다. S6F11이 실어 주던 "이 이벤트 시점의 값"이 아니라 지금 값이다. 이 차이를 섞으면 트레이스가 틀어진다.
  • S6F19를 쓸 생각이면 통합 테스트가 아니라 장비 붙이는 첫날에 한 번 쏴 보고 답을 기록해 둔다. S6F0이면 거기서 설계가 갈린다.

확인하지 못한 것

S6F16과 S6F20의 본문 모양은 이번에 하나도 확인하지 못했다. 본문이 아예 돌아오지 않았으니 확인할 바이트가 없다. E5가 규정하는 그 두 메시지의 아이템 구조를 쓸 일이 있으면 손에 있는 사본을 봐야 한다.

E30이 S6F15와 S6F19를 필수 기능으로 두는지, 아니면 선택 기능으로 두는지도 문서로 확인하지 못했다. 이 listener가 구현하지 않았다는 사실만 확인했다.

그리고 이건 listener 하나의 동작이다. S6F20을 제대로 돌려주는 장비도 있고, 그런 장비를 만나면 위의 설계는 그냥 더 안전한 쪽일 뿐 틀린 게 아니다. 반대로 S6F19에 기대어 복구 경로를 짰다면, S6F0을 돌려주는 장비 한 대가 그 경로를 전부 지운다.

위 프레임은 전부 공개된 SECS/GEM 시뮬레이터의 passive listener에 소켓을 열어 주고받은 것이다. 본인 드라이버로 S6F19를 한 번 쏴 보면, 호스트 스택이 function 0을 에러로 올리는지 타임아웃으로 올리는지 바로 보인다. 그게 알아볼 값어치가 있는 부분이다.