# V2G EXI 구현 가이드

## 📋 개요

V2G (Vehicle-to-Grid) EXI 인코딩/디코딩을 구현하기 위한 완전한 개발자 가이드입니다. 바이트별 구조, 비트 단위 분석, 개발 순서를 포함합니다.

## 🎯 구현 목표

- **100% VC2022 C 호환성**: 바이트 단위 완전 동일
- **멀티플랫폼**: C, VC2022, .NET Core
- **18개 V2G 메시지 타입 완전 지원**

## 📊 EXI 바이너리 구조 완전 분석

### test5.exi 바이트별 분석 (CurrentDemandReq)

```
바이트 위치: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ...
헥스 데이터: 80 98 02 10 50 90 8C 0C 0C 0E 0C 50 D1 00 32 01 ...
총 크기: 43 바이트 (순수 EXI, 네트워크 헤더 없음)
```

#### 바이트 0: EXI 헤더 (0x80)
```
비트 구조: 10000000
의미: EXI 매직 넘버, 모든 EXI 파일은 이 바이트로 시작
구현: writeEXIHeader() 함수에서 생성
```

#### 바이트 1: Document Choice (0x98)  
```
비트 구조: 10011000
분해:
  1 (1비트) = V2G_Message 존재 플래그
  0011000 (7비트) = Document choice 76 (decimal)
의미: V2G_Message를 포함하는 EXI Document
구현: encodeNBitUnsignedInteger(stream, 7, 76)
```

#### 바이트 2-3: Grammar States (0x02 0x10)
```
바이트 2 (0x02): 00000010
  0 (1비트) = Grammar 256: Header START_ELEMENT
  0 (1비트) = Grammar 257: Body START_ELEMENT  
  000010 (6비트) = 패딩 + 다음 바이트로 이어짐

바이트 3 (0x10): 00010000
  00010000 (8비트) = SessionID 인코딩 시작
```

#### 바이트 4-11: SessionID (BINARY_HEX, 8바이트)
```
원본 문자열: "ABB00081"
ASCII 바이트: 41 42 42 30 30 30 38 31
EXI 압축 결과: 50 90 8C 0C 0C 0E 0C 50

압축 과정:
  - 길이 인코딩: encodeUnsignedInteger16(8)
  - 바이트 데이터 인코딩: encodeBytes()
  - BINARY_HEX 타입으로 처리
```

#### 바이트 12: Body Choice + Grammar Start (0xD1)
```
비트 구조: 11010001
분해:
  110100 (6비트) = Body choice 13 (CurrentDemandReq)
  01 (2비트) = Grammar 273, 274 상태 전환
```

#### 바이트 13-15: DC_EVStatus (0x00 0x32 0x01)
```
구조:
  EVReady: true (1비트)
  EVErrorCode: 0 (가변길이)
  EVRESSSOC: 100 (가변길이, 100%)
  
비트 패킹:
  0x00: EVReady=1, EVErrorCode=0 시작
  0x32: EVErrorCode 완료, EVRESSSOC 시작  
  0x01: EVRESSSOC=100 완료
```

#### 바이트 16-18: EVTargetCurrent (0x86 0x00 0x20)
```
PhysicalValue 구조:
  Multiplier: 0 (3비트, offset +3 → 인코딩값 3)
  Unit: 3 (A, 3비트)
  Value: 1 (16비트 signed integer)

비트 분해:
  START_ELEMENT(Multiplier) + CHARACTERS + 값 3 + EE
  START_ELEMENT(Unit) + CHARACTERS + 값 3 + EE  
  START_ELEMENT(Value) + CHARACTERS + 값 1 + EE
  END_ELEMENT
```

#### 바이트 19-22: EVMaximumVoltageLimit (0x18 0x81 0xAE 0x06)
```
PhysicalValue:
  Multiplier: 0 → 인코딩값 3
  Unit: 4 (V) 
  Value: 471

실제 값: 471 * 10^0 = 471V
```

#### 바이트 23-26: EVMaximumCurrentLimit (0x01 0x86 0x0C 0x80)
```
PhysicalValue:
  Multiplier: 0 → 인코딩값 3
  Unit: 3 (A)
  Value: 100

실제 값: 100 * 10^0 = 100A
```

#### 바이트 27-29: EVMaximumPowerLimit (0x61 0x40 0xC8)
```
PhysicalValue:
  Multiplier: 3 → 인코딩값 6  
  Unit: 5 (W)
  Value: 50

실제 값: 50 * 10^3 = 50,000W = 50kW
```

#### 바이트 30: ChargingComplete (0x01)
```
Grammar 278: 2비트 choice = 1 (ChargingComplete 선택)
Boolean 값: true
비트 구조: 00000001
```

#### 바이트 31-33: RemainingTimeToFullSoC (0x03 0x08 0x00)
```
PhysicalValue:
  Multiplier: 0
  Unit: 2 (s, 초)
  Value: 0

실제 값: 0초 (이미 완전 충전)
```

#### 바이트 34-36: RemainingTimeToBulkSoC (0x00 0x61 0x00)
```
PhysicalValue:
  Multiplier: 0
  Unit: 2 (s)
  Value: 0

실제 값: 0초 (벌크 충전도 완료)
```

#### 바이트 37-40: EVTargetVoltage (0x00 0x18 0x81 0x98)
```
PhysicalValue:
  Multiplier: 0
  Unit: 4 (V)
  Value: 460

실제 값: 460V (목표 전압)
```

#### 바이트 41-42: END_ELEMENT + 패딩 (0x06 0x00)
```
Grammar 3: END_ELEMENT (1비트)
나머지: 0으로 패딩하여 바이트 경계 맞춤
```

## 🔧 구현 단계별 가이드

### 1단계: BitStream 구현

#### 핵심 구조체
```c
typedef struct {
    uint8_t* data;      // 바이트 배열
    size_t* pos;        // 현재 위치 포인터
    uint8_t buffer;     // 비트 버퍼 (0-255)
    uint8_t capacity;   // 남은 비트 수 (0-8)
} bitstream_t;
```

#### writeBits 함수 (핵심)
```c
int writeBits(bitstream_t* stream, size_t nbits, uint32_t val) {
    if (nbits <= stream->capacity) {
        // 단순 케이스: 현재 버퍼에 맞음
        val = val << (stream->capacity - nbits);
        stream->buffer = stream->buffer | ((uint8_t)val);
        stream->capacity -= nbits;
        
        if (stream->capacity == 0) {
            stream->data[(*stream->pos)++] = stream->buffer;
            stream->buffer = 0;
            stream->capacity = 8;
        }
    }
    else {
        // 복잡 케이스: 바이트 경계 넘어감
        while (nbits > stream->capacity) {
            nbits -= stream->capacity;
            uint8_t val1 = (uint8_t)(val >> nbits);
            
            stream->buffer |= val1;
            stream->data[(*stream->pos)++] = stream->buffer;
            
            val &= (((uint32_t)1 << nbits) - 1);
            stream->buffer = 0;
            stream->capacity = 8;
        }
        
        if (nbits > 0) {
            val = val << (stream->capacity - nbits);
            stream->buffer |= (uint8_t)val;
            stream->capacity -= nbits;
        }
    }
    return 0;
}
```

### 2단계: 기본 인코딩 함수들

#### Boolean 인코딩
```c
int encodeBoolean(bitstream_t* stream, int b) {
    return writeBits(stream, 1, b ? 1 : 0);
}
```

#### N비트 부호없는 정수
```c
int encodeNBitUnsignedInteger(bitstream_t* stream, size_t nbits, uint32_t val) {
    return writeBits(stream, nbits, val);
}
```

#### 가변길이 부호없는 정수
```c
int encodeUnsignedInteger16(bitstream_t* stream, uint16_t val) {
    if (val < 128) {
        return writeBits(stream, 8, val);
    } else {
        writeBits(stream, 8, 0x80 | (val >> 8));
        return writeBits(stream, 8, val & 0xFF);
    }
}
```

#### 16비트 signed integer (핵심)
```c
int encodeInteger16(bitstream_t* stream, int16_t val) {
    // 부호 비트 (1비트)
    if (val < 0) {
        encodeBoolean(stream, 1);
        val = (int16_t)((-val) - 1);
    } else {
        encodeBoolean(stream, 0);
    }
    
    // 크기를 가변길이 부호없는 정수로 인코딩
    return encodeUnsignedInteger16(stream, (uint16_t)val);
}
```

### 3단계: Grammar State 구현

#### Grammar State 매핑
```c
typedef enum {
    GRAMMAR_256 = 256,  // V2G_Message Header
    GRAMMAR_257 = 257,  // V2G_Message Body
    GRAMMAR_273 = 273,  // CurrentDemandReq start
    GRAMMAR_274 = 274,  // EVTargetCurrent
    GRAMMAR_275 = 275,  // Optional elements (3-bit)
    GRAMMAR_276 = 276,  // After EVMaxVoltage (3-bit)
    GRAMMAR_277 = 277,  // After EVMaxCurrent (2-bit)
    GRAMMAR_278 = 278,  // After EVMaxPower (2-bit)
    GRAMMAR_280 = 280,  // After ChargingComplete (2-bit)
    GRAMMAR_281 = 281,  // After RemainingTimeFullSoC (2-bit)
    GRAMMAR_282 = 282,  // After RemainingTimeBulkSoC (1-bit)
    GRAMMAR_3 = 3       // END_ELEMENT
} GrammarState;
```

#### Choice 비트 수 계산
```c
int getChoiceBits(GrammarState state) {
    switch(state) {
        case GRAMMAR_275: return 3;  // 5개 선택지 (0-4)
        case GRAMMAR_276: return 3;  // 4개 선택지 (0-3)  
        case GRAMMAR_277: return 2;  // 3개 선택지 (0-2)
        case GRAMMAR_278: return 2;  // 2개 선택지 (0-1)
        case GRAMMAR_280: return 2;  // 3개 선택지 (0-2)
        case GRAMMAR_281: return 2;  // 3개 선택지 (0-2)
        case GRAMMAR_282: return 1;  // 2개 선택지 (0-1)
        default: return 1;           // 기본값
    }
}
```

### 4단계: PhysicalValue 인코딩

#### 완전한 구현
```c
int encode_PhysicalValue(bitstream_t* stream, PhysicalValue* pv) {
    // START_ELEMENT(Multiplier)
    encodeNBitUnsignedInteger(stream, 1, 0);
    encodeNBitUnsignedInteger(stream, 1, 0);  // CHARACTERS[3BIT]
    encodeNBitUnsignedInteger(stream, 3, (uint32_t)(pv->Multiplier + 3));
    encodeNBitUnsignedInteger(stream, 1, 0);  // EE
    
    // START_ELEMENT(Unit)
    encodeNBitUnsignedInteger(stream, 1, 0);
    encodeNBitUnsignedInteger(stream, 1, 0);  // CHARACTERS[ENUM]
    encodeNBitUnsignedInteger(stream, 3, pv->Unit);
    encodeNBitUnsignedInteger(stream, 1, 0);  // EE
    
    // START_ELEMENT(Value)  
    encodeNBitUnsignedInteger(stream, 1, 0);
    encodeNBitUnsignedInteger(stream, 1, 0);  // CHARACTERS[INTEGER]
    encodeInteger16(stream, pv->Value);
    encodeNBitUnsignedInteger(stream, 1, 0);  // EE
    
    // END_ELEMENT
    encodeNBitUnsignedInteger(stream, 1, 0);
    
    return 0;
}
```

### 5단계: 메시지별 구현

#### CurrentDemandReq 완전 구현
```c
int encode_CurrentDemandReq(bitstream_t* stream, CurrentDemandReqType* req) {
    int grammar = 273;
    
    while (grammar != 3) {
        switch(grammar) {
            case 273:
                // DC_EVStatus (mandatory)
                encodeNBitUnsignedInteger(stream, 1, 0);
                encode_DC_EVStatus(stream, &req->DC_EVStatus);
                grammar = 274;
                break;
                
            case 274:
                // EVTargetCurrent (mandatory)
                encodeNBitUnsignedInteger(stream, 1, 0);
                encode_PhysicalValue(stream, &req->EVTargetCurrent);
                grammar = 275;
                break;
                
            case 275:
                // 3비트 choice (5개 옵션)
                if (req->EVMaximumVoltageLimit_isUsed) {
                    encodeNBitUnsignedInteger(stream, 3, 0);
                    encode_PhysicalValue(stream, &req->EVMaximumVoltageLimit);
                    grammar = 276;
                } else if (req->EVMaximumCurrentLimit_isUsed) {
                    encodeNBitUnsignedInteger(stream, 3, 1);
                    encode_PhysicalValue(stream, &req->EVMaximumCurrentLimit);
                    grammar = 277;
                } else if (req->EVMaximumPowerLimit_isUsed) {
                    encodeNBitUnsignedInteger(stream, 3, 2);
                    encode_PhysicalValue(stream, &req->EVMaximumPowerLimit);
                    grammar = 278;
                } else {
                    // ChargingComplete (기본값)
                    encodeNBitUnsignedInteger(stream, 3, 4);
                    encodeNBitUnsignedInteger(stream, 1, 0);  // CHARACTERS[BOOLEAN]
                    encodeBoolean(stream, req->ChargingComplete);
                    encodeNBitUnsignedInteger(stream, 1, 0);  // EE
                    grammar = 280;
                }
                break;
                
            case 278:
                // 2비트 choice - BulkCharging 무시
                // ChargingComplete로 바로 이동
                encodeNBitUnsignedInteger(stream, 2, 1);
                encodeNBitUnsignedInteger(stream, 1, 0);
                encodeBoolean(stream, req->ChargingComplete);
                encodeNBitUnsignedInteger(stream, 1, 0);
                grammar = 280;
                break;
                
            // ... 다른 grammar states
                
            case 3:
                // END_ELEMENT
                encodeNBitUnsignedInteger(stream, 1, 0);
                break;
        }
    }
    
    return 0;
}
```

## 🔄 디코딩 구현 가이드

### 1단계: BitStream 읽기

#### readBits 함수
```c
int readBits(bitstream_t* stream, size_t nbits, uint32_t* val) {
    *val = 0;
    
    while (nbits > 0) {
        if (stream->capacity == 0) {
            if (*stream->pos >= stream->size) return -1;
            stream->buffer = stream->data[(*stream->pos)++];
            stream->capacity = 8;
        }
        
        int bitsToRead = (nbits < stream->capacity) ? nbits : stream->capacity;
        
        *val = (*val << bitsToRead) | 
               ((stream->buffer >> (stream->capacity - bitsToRead)) & 
                ((1 << bitsToRead) - 1));
        
        stream->capacity -= bitsToRead;
        nbits -= bitsToRead;
    }
    
    return 0;
}
```

### 2단계: 타입별 디코딩

#### Integer16 디코딩
```c
int decodeInteger16(bitstream_t* stream, int16_t* val) {
    uint32_t sign;
    readBits(stream, 1, &sign);
    
    uint16_t magnitude;
    decodeUnsignedInteger16(stream, &magnitude);
    
    if (sign) {
        *val = -((int16_t)magnitude + 1);
    } else {
        *val = (int16_t)magnitude;
    }
    
    return 0;
}
```

### 3단계: Grammar 기반 디코딩

#### 동적 Grammar 처리
```c
int decode_CurrentDemandReq(bitstream_t* stream, CurrentDemandReqType* req) {
    int grammar = 273;
    
    while (grammar != 3) {
        switch(grammar) {
            case 275: {
                uint32_t choice;
                readBits(stream, 3, &choice);  // 3비트 choice
                
                switch(choice) {
                    case 0:
                        req->EVMaximumVoltageLimit_isUsed = 1;
                        decode_PhysicalValue(stream, &req->EVMaximumVoltageLimit);
                        grammar = 276;
                        break;
                    case 1:
                        req->EVMaximumCurrentLimit_isUsed = 1;
                        decode_PhysicalValue(stream, &req->EVMaximumCurrentLimit);
                        grammar = 277;
                        break;
                    // ... 다른 choices
                }
                break;
            }
        }
    }
    
    return 0;
}
```

## 🛠️ 구현 우선순위

### Phase 1: 핵심 인프라 (필수)
1. **BitStream 구현**: writeBits/readBits 완벽 구현
2. **기본 타입**: Boolean, Integer16, UnsignedInteger 
3. **EXI 헤더**: writeEXIHeader/readEXIHeader
4. **Grammar States**: 상태 머신 기본 구조

### Phase 2: CurrentDemand 메시지 (검증용)
1. **CurrentDemandReq**: 가장 복잡한 메시지, 테스트 데이터 있음
2. **CurrentDemandRes**: Response 메시지 
3. **test5.exi 완벽 재현**: 43바이트 바이너리 매칭

### Phase 3: 추가 메시지 타입
1. **세션 관리**: SessionSetup, ServiceDiscovery
2. **DC 충전**: CableCheck, PreCharge, PowerDelivery
3. **확장 기능**: Authorization, ChargingStatus

## 🔍 디버깅 가이드

### 바이트별 검증 방법
```c
void debug_compare_bytes(uint8_t* expected, uint8_t* actual, size_t size) {
    printf("위치  예상  실제  차이\n");
    for (size_t i = 0; i < size; i++) {
        char diff = (expected[i] == actual[i]) ? ' ' : '*';
        printf("%02zu:   %02X    %02X   %c\n", i, expected[i], actual[i], diff);
        if (expected[i] != actual[i]) {
            printf("     비트: %08b vs %08b\n", expected[i], actual[i]);
        }
    }
}
```

### Grammar State 추적
```c
#define DEBUG_GRAMMAR(state, choice, bits) \
    printf("Grammar %d: choice %d (%d-bit)\n", state, choice, bits)
```

### 성공 조건
1. **test5.exi 완전 매칭**: 43바이트 바이너리 동일
2. **라운드트립 테스트**: EXI → XML → EXI 완벽 복원
3. **모든 메시지 타입**: 18개 V2G 메시지 지원

---

이 가이드를 따라 구현하면 VC2022 C 구현과 100% 호환되는 V2G EXI 코덱을 개발할 수 있습니다.