Search

[가이드] Toss Serial Port Protocol

0. 개정 이력

버 전
내 용
일 자
1.0
신규 작성
2025.4.15

1. 소개

이 문서에서는 토스플레이스의 Front와 타사 POS 기기들 간의 직렬 통신을 하는데 있어 프로토콜을 정의합니다.

2. 용어 정리

직렬 통신(Serial Bus): 연속적으로 통신 채널으로 한 번에 하나의 비트 단위로 데이터를 전송하는 과정
RS-232: 직렬 통신 방식의 하드웨어 인터페이스. 일반적으로 직렬 포트(Serial Port)라 불립니다.
패킷(Packet): 다수의 데이터를 전송 할 때, 보내고 받는 데이터의 형식
TX: Transmitter. 전송자
RX: Receiver. 수신자
TSPP: Toss Serial Port Protocol

3. 패킷 정의

DATA

STX
SEQ
PAYLOAD
ETX
CRC
0x10 0x02 2 Byte
1 Byte
N Byte
0x10 0x03 2 Byte
4 Byte
데이터를 주고받는데 사용하는 패킷 입니다.
STX (2 Byte)
시작 부호
0x10 0x02 고정값
STX를 만나면 패킷을 읽기 시작합니다.
SEQ(1 Byte)
순차 번호
0~256 까지의 값으로 패킷 송신마다 1씩 증가시킵니다.
256 까지 도달한 경우 다시 0부터 시작합니다.
PAYLOAD (N Byte)
가변길이의 데이터로 JSON 포맷으로 구성되어 있습니다.
이스케이핑 처리
STX, ETX와 겹치지 않기 위해 이스케이핑 처리가 필요합니다.
데이터에 0x10 값이 있다면 하나를 더 추가해 0x10 0x10 을 만들어 이스케이핑 처리합니다.
원본 데이터 0x0f 0x07 0x10 0x02 0x66 0x12 0x10 이스케이핑 처리된 데이터 0x0f 0x07 0x10 0x10 0x02 0x66 0x12 0x10 0x10
Scala
복사
ETX (2 Byte)
종료 부호
0x10 0x03 고정값
ETX를 만났을때 패킷 읽기를 종료하고, 패킷을 읽기 시작한 STX부터 ETX 까지를 한 패킷으로 취급합니다.
CRC (4 Byte)
순환 중복 검사. 전송된 데이터에 오류가 있는지 확인하는데 사용됩니다.
CRC-32 사용
“STX + SEQ + DATA + ETX” 합쳐서 CRC-32로 계산한 체크섬(4 Bytes)을 붙입니다.
RX는 수신한 “STX + SEQ + DATA + ETX”를 합쳐서 체크섬을 계산하고 CRC가 동일한지 검사합니다.
예시
원본 데이터 0x0f 0x07 0x66 0x12 0x10 이스케이핑 처리된 데이터 0x0f 0x07 0x66 0x12 0x10 0x10 패킷 │ STX │ SEQ │ DATA │ ETX │ CRC │ ├───────────┼────────┼───────────────────────────────┼───────────┼─────────────────────┤ │ 0x10 0x020x120x0f 0x07 0x66 0x12 0x10 0x100x10 0x030x04 0x4c 0x7c 0x6e
Scala
복사

ACK

ACK
순차 번호
0x10 0x06 (2 Bytes)
1 Bytes
ACK 패킷은 수신 측에서 데이터를 정상적으로 받았을 때 송신 측으로 응답합니다.
ACK (2 Byte)
0x10 0x06 고정값
순차 번호 (1 Byte)
수신 받은 데이터 패킷의 SEQ를 입력합니다.
예시
│ ACK │ SEQ │ ├───────────┼────────┤ │ 0x10 0x060x12
Scala
복사

NAK

NAK
순차 번호
0x10 0x15 (2 Bytes)
1 Bytes
NAK 패킷은 수신 측에서 데이터를 정상적으로 받지 못하였을 때 송신 측으로 응답합니다. 예를들어 수신 받은 데이터의 CRC가 일치하지 않는 경우 NAK을 응답합니다.
NAK (2 Byte)
0x10 0x15 고정값
순차 번호 (1 Byte)
수신 받은 데이터 패킷의 SEQ를 입력합니다.
예시
│ NAK │ SEQ │ ├───────────┼────────┤ │ 0x10 0x150x12
Scala
복사

4. 통신 과정

신뢰성 있는 통신

통신 과정에서 신뢰성을 보장하기 위해 RX(수신자)는 TX(전송자)에게서 받은 패킷이 정상이라면 ACK을, 비정상이라면 NAK을 TX로 패킷을 전송합니다. TX는 NAK을 받으면 문제가 있는 패킷을 재전송하여 패킷의 유실을 방지할 수 있습니다. 이 때, 순차성을 보장하기 위해 각 패킷에 담긴 SEQ 값을 이용합니다.
RX는 TX에게서 패킷을 받으면 정상 유무를 확인한다. 정상이면 ACK을 비정상이면 NAK을 응답한다. 이 때 정상 유무는 CRC로 확인할 수 있다.
TX는 NAK을 받았을 때 문제가 있는 패킷을 재전송한다. 이 때 어떤 패킷이 문제가 있었는지 확인하기 위해 SEQ 값을 이용하면 순차성을 보장할 수 있다.

ACK 응답

sequenceDiagram
  participant TX
  participant RX
  TX->>RX: DATA 1
  RX->>TX: ACK 1
  TX->>RX: DATA 2
  RX->>TX: ACK 2
Mermaid
복사
TX가 RX로 DATA 패킷을 보냈을 때 RX가 정상적으로 수신한 경우, RX는 ACK 패킷을 TX로 보내어 정상 수신하였음을 응답합니다.
TX는 DATA 패킷을 보낸 후 ACK 패킷을 받을 때까지 다음 송신을 대기하므로 순차성을 보장할 수 있습니다. 예를들어 위의 예시에서 DATA 1, DATA 2 두 개의 패킷을 RX는 순차적으로 받을 수 있습니다.

NAK 응답

sequenceDiagram
  participant TX
  participant RX
  TX->>RX: DATA
  note right of RX: CRC 검사 실패
  RX->>TX: NAK
Mermaid
복사
TX가 RX로 DATA 패킷을 보냈을 때 RX가 수신하였는데 CRC 검사 실패, 파싱 오류 등 문제가 발생하였을 때, RX는 NAK 패킷을 TX로 보내어 비정상 수신하였음을 응답합니다.
TX는 NAK을 받으면 패킷을 재전송하여 오류 복구를 할 수 있습니다.

Timeout 처리

TX 또는 RX에서 패킷을 일정 시간 동안 처리하지 못하면 Timeout 처리가 필요합니다. 2가지 상황이 존재합니다.
TX가 패킷을 보내고 일정 시간 내에 ACK 또는 NAK 응답을 받지 못하였을 때
정상 혹은 비정상적인 통신이더라도 RX는 TX에게 통신에 대한 응답을 보낼 수 있어야 합니다. 정상인 경우 ACK, 비정상인 경우 NAK을 응답합니다. TX는 RX에게서 응답을 받을 때까지 무작정 기다릴 수 없으니, 일정 시간 동안 응답을 받지 못하였을 때 Timeout 처리를 해야합니다.
RX가 STX를 읽은 후부터 일정 시간 내에 ETX를 읽지 못하였을 때

5. 테스트 케이스

RX

Basic
10020068656c6c6f1003b7c04072 -> DATA(seq: 00, payload: 68656c6c6f) 100607 -> ACK(seq: 07) 101523 -> NAK(seq: 23)
Plain Text
복사
Interrupted : 전송 중에 새로운 패킷 전송
10020068656c6c6f10020148454c4c4f1003eac5ba9c -> DATA(seq: 01, payload: 48454c4c4f)
Plain Text
복사
잘못된 CRC 패킷
10020048656c6c6f1003b7c04072 -> CRCFailed(seq: 00)
Plain Text
복사
Escape 처리 예외케이스
1002000f07101002661210101003baece28d -> DATA(seq: 00, payload: 0f071002661210) * 주의1 : 빨간색 1002 가 STX로 인식되면 안됨 * 주의2 : 파란색 1003 는 ETX로 인식되어야 함
Plain Text
복사
종합테스트
DATA, ACK, NAK 패킷을 랜덤하게 여러번 할당
패킷은 모두 온전함. 중간에 끊기는 경우는 없음
DATA 의 payload 에는 alphanumeric 과 ‘0x10’ 이 들어감
주의사항 : SEQ 에 0x10, CRC에 0x10 가 나올 수 있어서 다음 패킷과 연결될 경우 이스케이핑으로 잘못 인식될 수 있음
case1 : numData = 87, numAck = 89, numNak = 81
case2 : numData = 84, numAck = 80, numNak = 93
case3 : numData = 92, numAck = 78, numNak = 87

TX

CRC 계산 테스트
68656c6c6f -> 10020068656c6c6f1003b7c04072
Plain Text
복사
Sequence overflow 테스트
데이터 Transmit을 0xff(255)번 반복 (seq: 0xfe) assert1 : 256번째 Transmit 의 seq == 0xff 인지 assert2 : 257번째 Transmit 의 seq == 0x00 인지
Plain Text
복사
Encode Payload 테스트
0f071002661210 -> 1002000f07101002661210101003baece28d
Plain Text
복사

6. TSPP 데이터 예시 (JSON포맷)

포스 → 프론트 요청
{ "name": "requestPayment", "data": { "type": "USE", "totalPrice": 39000, // 결제 상품 금액 "availableAmount": 5420, // 보유 포인트 "minAvailableAmount": 1000 // 최소 사용 포인트 } }
JavaScript
복사
프론트 → 포스 응답
{ "name": "respondPoint", "data": { "type": "USE", "inputAmount": 2000, // 고객이 사용하겠다고 입력한 포인트 } }
JavaScript
복사

7. 결제 구성도

sequenceDiagram 
  participant POS
  participant Toss Front
  participant VAN 
  participant 카드사
  
  POS ->> Toss Front : 결제 요청 (TSPP)
  note over Toss Front : 카드 리딩 
  note over Toss Front : 결제 전문 생성
  Toss Front ->> VAN : 결제 승인 요청
  VAN ->> 카드사 : 결제 승인 요청 
  카드사 ->> VAN : 결제 승인 응답
  VAN ->> Toss Front : 결제 승인 응답
  Toss Front ->> POS : 결제 응답 (TSPP)
   
Mermaid
복사