# Roomfit 체크섬 계산 가이드

**Last Updated**: 2026-04-01

## 개요

이 문서는 Roomfit 제어 프로토콜에서 사용하는 체크섬 계산 방법을 정리합니다. 현재 repo에서는 `roomfit_protocol` 패키지의 `PacketBuilder`가 이 규칙의 기준 구현입니다.

## 체크섬의 목적

체크섬(Checksum)은 데이터 무결성을 검증하기 위한 값으로, 전송 과정에서 발생할 수 있는 오류를 감지하는 데 사용됩니다. Roomfit 장치는 각 블루투스 패킷에 체크섬을 포함하여 명령이 올바르게 전송되었는지 확인합니다.

## 패킷 구조

Roomfit 장치의 블루투스 패킷은 다음과 같은 구조를 가집니다:

```
[0xFF, 0xFF, Size, Command, Data..., Checksum]
```

- **헤더(2바이트)**: 항상 [0xFF, 0xFF]
- **크기(1바이트)**: 명령어 코드(1) + 데이터(n) + 체크섬(1)
- **명령어 코드(1바이트)**: 실행할 명령 코드
- **데이터(0~n바이트)**: 명령에 필요한 데이터 (옵션)
- **체크섬(1바이트)**: 크기부터 데이터까지의 합에 대한 검증 값

## 체크섬 계산 공식

Roomfit 장치의 체크섬은 다음 공식으로 계산됩니다:

```
Checksum = (256 - (sum % 256) + 2) % 256
```

여기서 `sum`은 크기 필드부터 마지막 데이터 바이트까지의 합입니다.

### 계산 단계

1. 패킷의 크기 필드부터 마지막 데이터 바이트까지 모든 값을 합산
2. 합계를 256으로 나눈 나머지 계산
3. 256에서 나머지를 뺌
4. 결과에 2를 더함 (Roomfit 프로토콜 특화)
5. 결과를 다시 256으로 나눈 나머지 계산

### 계산 예시

**GetSystemInfoCommand 패킷**: `[0xFF, 0xFF, 0x02, 0x06, 0xFA]`

1. 합산: 0x02 + 0x06 = 0x08
2. 나머지: 0x08 % 256 = 8
3. 256 - 8 = 248 (0xF8)
4. 248 + 2 = 250 (0xFA)
5. 250 % 256 = 250 (0xFA)

## PacketBuilder 사용

체크섬 계산과 packet 생성은 `roomfit_protocol`의 `PacketBuilder`를 사용합니다.

### packet 생성

```dart
final packet = PacketBuilder.build(commandCode, data);
```

### packet 검증

```dart
final isValid = PacketBuilder.isValid(packet);
```

### command code 추출

```dart
final commandCode = PacketBuilder.commandOf(packet);
```

## 예제

### 1. 데이터가 없는 명령

**GetVoltageCommand**: `[0xFF, 0xFF, 0x02, 0x05, 0xFB]`

- 합산: 0x02 + 0x05 = 0x07
- 계산: (256 - (7 % 256) + 2) % 256 = 0xFB

```dart
final packet = PacketBuilder.build(CommandCodes.getVoltage, const []);
```

### 2. 데이터가 있는 명령

**SetWeightPowerCommand(onOff: 1)**: `[0xFF, 0xFF, 0x03, 0x65, 0x01, 0x99]`

- 합산: 0x03 + 0x65 + 0x01 = 0x69
- 계산: (256 - (105 % 256) + 2) % 256 = 0x99

```dart
final packet = PacketBuilder.build(CommandCodes.weightOnOff, [0x01]);
```

### 3. 복합 데이터 명령

**SetWeightModeCommand(leftMode: 0, rightMode: 0)**: `[0xFF, 0xFF, 0x04, 0x68, 0x00, 0x00, 0x94]`

- 합산: 0x04 + 0x68 + 0x00 + 0x00 = 0x6C
- 계산: (256 - (108 % 256) + 2) % 256 = 0x94

```dart
final packet = PacketBuilder.build(CommandCodes.modeChange, [0x00, 0x00]);
```

## 명령 클래스에서 사용

명령 패턴 구현 시, 명령 클래스에서는 다음과 같이 패킷을 생성합니다:

```dart
class SampleCommand extends Command {
  final int param;

  SampleCommand(this.param);

  @override
  String get name => 'Sample Command';

  @override
  int get code => 0x70;

  @override
  List<int> encodeData() => [param];
}
```

## 주의사항

1. **일관성 유지**: 모든 명령에서 동일한 체크섬 계산 방식 사용
2. **오프셋 적용**: +2 오프셋은 Roomfit 장치 특화 요구사항이므로 반드시 적용
3. **범위 확인**: 계산 과정에서 바이트 오버플로우 방지 (0-255 범위 유지)
4. **헤더 제외**: 체크섬 계산 시 헤더([0xFF, 0xFF])는 제외

## 체크섬 검증

수신된 패킷의 체크섬 검증은 다음과 같이 수행합니다:

```dart
final isValid = PacketBuilder.isValid(receivedPacket);
```

## 체크섬 계산 문제 해결

체크섬 계산이 예상과 다를 경우 다음을 확인하세요:

1. **헤더 포함 여부**: 체크섬 계산에 헤더가 포함되었는지 확인
2. **시작 인덱스**: 계산 시작 인덱스가 크기 필드(인덱스 2)부터인지 확인
3. **+2 오프셋**: Roomfit 특화 오프셋 적용 여부 확인
4. **모듈로 연산**: 256으로 나눈 나머지 계산이 올바른지 확인

## 참고 자료

- [mcu-protocol.md](./mcu-protocol.md)
- [mcu-compatibility-matrix.md](./mcu-compatibility-matrix.md)
