T90 프로토콜

장비 ↔ SW 사이의 TCP 바이너리 와이어 포맷. 모든 구조체는 Little-Endian, packed (1-byte alignment).

0. 트랜스포트

프로토콜
TCP
엔디안
Little-Endian
정렬
__attribute__((packed))
프레임 경계
헤더 packet_size (8바이트 헤더 포함 총 바이트)
기본 포트
31024 (PDF 미명시 — 현장 관행)

1. 패킷 타입 상수

#define PACKET_TYPE_SCOPE_SET    0x77770010   SW→장비  SCOPE 설정
#define PACKET_TYPE_PQN_SET      0x77770020   SW→장비  PQN 설정
#define PACKET_TYPE_HW_SET       0x77770030   SW→장비  HW 설정
#define PACKET_TYPE_MSG          0x77770100   양방향   명령/상태/에러
#define PACKET_TYPE_SCOPE_DATA   0x77771000   장비→SW  SCOPE 측정 데이터
#define PACKET_TYPE_PQN_DATA     0x77772000   장비→SW  PQN 측정 데이터

2. MSG 코드

#define MSG_SCOPE_SET_ERROR      0x00000010   // SCOPE_SET 응답 (에러 없어도 돌아옴)
#define MSG_PQN_SET_ERROR        0x00000020   // PQN_SET 응답
#define MSG_HW_SET_ERROR         0x00000030   // HW_SET 응답
#define MSG_SEND_DATA_START      0x00000100   // 수집 시작
#define MSG_SEND_DATA_STOP       0x00000200   // 수집 중지
#define MSG_ALIVE                0x00000400   // Keep-alive (Rev 4 추가)
#define MSG_NET_CFG_SET          0x00001000   // 장비 MAC/IP 설정
#define MSG_NET_CFG_INFO         0x00002000   // 장비 MAC/IP 조회
#define MSG_SELF_SYNC_ENABLE     0x00003000   // 자체 싱크 On/Off
#define MSG_REBOOT               0x10000000   // 장비 재부팅

모든 명령 MSG 는 장비가 동일 msg 값으로 ACK한다. SET 패킷은 대응하는 MSG_*_SET_ERROR 로 ACK 되며 에러가 없어도 돌아온다(error=0).

3. 공통 헤더

typedef struct {
    unsigned int packet_type;   // §1 상수 중 하나
    unsigned int packet_size;   // 헤더 포함 총 바이트
} __attribute__((packed)) PACKET_HEADER;     // 8 byte

4. SCOPE_SET_PACKET (392 byte)

typedef struct {
    unsigned int ch_group;      // 0~7      기본 0
    unsigned int ch_on;         // 0/1      기본 1
    unsigned int trig_on;       // 0/1      기본 0
    unsigned int trig_type;     // 1~3      기본 3   bit0=H매칭, bit1=L매칭
    int          trig_h_lv;     // -2048~2047  기본 2047
    int          trig_l_lv;     // -2048~2047  기본 -2048
    unsigned int trig_depth;    // 0~2047   기본 500
    unsigned int trig_pos;      // 0~depth  기본 250
    unsigned int filter_on;     // 0/1      기본 0
    unsigned int filter_type;   // 0/1/2/3  기본 2  LPF/HPF/BPF/BSF
    float        freq;          // 1.0~49.0 기본 25.0
    float        bandwidth;     // 1.0~10.0 기본 1.0
} __attribute__((packed)) SCOPE_CH_PARAM;    // 48 byte

typedef struct {
    PACKET_HEADER  header;
    SCOPE_CH_PARAM ch_param[8];
} __attribute__((packed)) SCOPE_SET_PACKET;  // 8 + 48*8 = 392 byte

5. PQN_SET_PACKET (360 byte)

typedef struct {
    unsigned int ch_on;
    unsigned int offset;               // 0~2047    기본 0
    unsigned int gating_on;            // 0/1       기본 0
    unsigned int gating_src;           // 0~7       0~3ch=3, 4~7ch=7
    unsigned int gating_thd;           // 0~2047    기본 2047
    unsigned int gating_prd;           // 0~65535   기본 10000   단위 10ns
    unsigned int pre_gating_len_sel;   // 0~10      기본 10      단위 1µs
    unsigned int filter_on;
    unsigned int filter_type;
    float        freq;
    float        bandwidth;
} __attribute__((packed)) PQN_CH_PARAM;      // 44 byte

typedef struct {
    PACKET_HEADER header;
    PQN_CH_PARAM  ch_param[8];
} __attribute__((packed)) PQN_SET_PACKET;    // 8 + 44*8 = 360 byte

6. HW_SET_PACKET (88 byte)

typedef struct {
    PACKET_HEADER header;
    unsigned int  sync_sel;            // 0=int, 1=ext         기본 0
    unsigned int  sync_gain;           // 1~7                  기본 2
    float         sync_freq;           // 20.00~300.00 Hz      기본 60.00
    unsigned int  num_of_cycle;        // 5~60   (1주기=256샘플)  기본 5
    unsigned int  adc_data_invert[8];  // 0/1                  기본 0
    unsigned int  ch_gain[8];          // 1~60                 기본 27
} __attribute__((packed)) HW_SET_PACKET;     // 88 byte

7. MSG_PACKET (272 byte) — 양방향

typedef struct {
    PACKET_HEADER header;
    unsigned int  msg;                 // §2 의 MSG_* 중 하나
    unsigned int  error;               // 응답시 에러 코드, 송신시 0
    char          padding[256];
} __attribute__((packed)) MSG_PACKET;        // 272 byte

padding 의 사용

MSGpadding 사용
MSG_NET_CFG_SET / MSG_NET_CFG_INFO [0..5] = MAC, [6..9] = IP, 나머지 0
MSG_SELF_SYNC_ENABLE [0..3] = 'T','-','9','0' (84,45,57,48), [4] = 0/1, 나머지 0
그 외모두 0

8. SCOPE_DATA_PACKET (가변 길이)

typedef struct {
    PACKET_HEADER header;       // packet_size = 24 + trig_depth*2
    unsigned int  ch_number;    // 0~7
    int           phase;        // 위상, 60Hz면 max 1_666_666 (16.67ms / 10ns), 못잡으면 -1
    int           cycle_index;  // PQN과 매칭용
    float         sync_freq;    // 못잡으면 -1
    // 뒤에 int16 샘플 trig_depth개
} __attribute__((packed)) SCOPE_DATA_PACKET;

각도 변환

각도 = phase × (sync_freq × 360) / 156_250_000
       (60Hz일 때) = phase / 1_666_666 × 360

9. PQN_DATA_PACKET (가변 길이)

typedef struct {
    PACKET_HEADER header;       // packet_size = 20 + buffer_size*2
    unsigned int  ch_number;    // 0~7 입력, 8 = sync
    int           cycle_index;
    float         sync_freq;
    // 뒤에 uint16 bin 데이터 buffer_size개
} __attribute__((packed)) PQN_DATA_PACKET;

중요: 8번 채널(sync)의 PQN 패킷은 PQN_CH_PARAM 에서 모든 채널의 ch_on=0 으로 설정해도 항상 SW로 전송된다.

10. ERROR 코드

#define ERROR_NO_ERR                                    0

// SCOPE_SET (10000~10120)
#define ERROR_SCOPE_SET_PACKET_LEN_WRONG                10000
#define ERROR_SCOPE_SET_CH_GROUP_VALUE_INVALID          10010
#define ERROR_SCOPE_SET_CH_ON_VALUE_INVALID             10020
#define ERROR_SCOPE_SET_TRIG_ON_VALUE_INVALID           10030
#define ERROR_SCOPE_SET_TRIG_TYPE_VALUE_INVALID         10040
#define ERROR_SCOPE_SET_TRIG_HIGH_LEVEL_VALUE_INVALID   10050
#define ERROR_SCOPE_SET_TRIG_LOW_LEVEL_VALUE_INVALID    10060
#define ERROR_SCOPE_SET_TRIG_DEPTH_VALUE_INVALID        10070
#define ERROR_SCOPE_SET_TRIG_POS_VALUE_INVALID          10080
#define ERROR_SCOPE_SET_FILTER_ON_VALUE_INVALID         10090
#define ERROR_SCOPE_SET_FILTER_TYPE_VALUE_INVALID       10100
#define ERROR_SCOPE_SET_FREQ_VALUE_INVALID              10110
#define ERROR_SCOPE_SET_BANDWIDTH_VALUE_INVALID         10120

// PQN_SET (20000~20110)
#define ERROR_PQN_SET_PACKET_LEN_WRONG                  20000
#define ERROR_PQN_SET_CH_ON_VALUE_INVALID               20010
#define ERROR_PQN_SET_OFFSET_VALUE_INVALID              20020
// ... (가이드 PDF §6 전체 표 참조)

// HW_SET (30000~30060)
#define ERROR_HW_SET_PACKET_LEN_WRONG                   30000
#define ERROR_HW_SET_SYNC_SEL_VALUE_INVALID             30010
// ...

// NET_CFG (90010~90020)
#define ERROR_NET_CFG_IP_VALUE_INVALID                  90010
#define ERROR_NET_CFG_IP_CHANGE_FAILED                  90020

// SELF_SYNC (100100~100120)
#define ERROR_SELF_SYNC_ENABLE_DENIED                   100100
#define ERROR_SELF_SYNC_ENABLE_VALUE_INVALID            100110
#define ERROR_SELF_SYNC_ENABLE_RETURN_INVALID           100120

10.1 채널 번호 오프셋 규칙

CH_* ~ BANDWIDTH_* 범위 에러는 에러값 + 채널번호(0~7) 로 반환.

예) 3번 채널의 ch_on 값이 잘못 → ERROR_SCOPE_SET_CH_ON_VALUE_INVALID + 3 = 10023

디코드 의사코드:
  base      = err - (err % 10)   // 10023 → 10020
  ch_offset = err - base         // 10023 → 3

10.2 IP 옥텟 오프셋 규칙

잘못된 옥텟 (a.b.c.d)error
a90010
b90011
c90012
d90013

유효성: a/b/c/d 모두 255 불가, a와 d는 0/1 불가. 허용 예 2.0.0.2.

리비전 이력

Rev변경
0초안
1HW_SET_PACKET 변경 / ERROR 코드 변경
2sync 주파수 범위 변경 / 제한값 삭제 / buffer_size → num_of_cycle / IP 변경 실패 에러값 추가
3sync 주파수 범위 변경 / MSG_SELF_SYNC_ENABLE 추가
3.1오타 수정
4MSG_ALIVE 패킷 추가
5오타 수정

원본: docs/T90패킷가이드_Rev5.pdf. 참조: Old/.../libs/network/a1protocol.h. 흐름은 → 패킷 흐름.