본문 바로가기
Network

CAN DBC 파일을 코드로 변환하는 오픈소스

by Embedded.AI 2024. 8. 10.
반응형

CAN DBC 파일을 코드로 변환하는 오픈소스: CODERDBC

 

자동차 산업에서 CAN(Controller Area Network) 통신은 차량 내 전자 제어 장치(ECU) 간의 실시간 데이터 통신을 위한 중요한 프로토콜 입니다. 하지만 DBC(Database CAN)파일을 코드화 하는 것을 매우 번거롭습니다. 이 포스팅에서 dbc 파일을 C 코드로 자동 변환해주는 오픈소스 도구, CODERDBC를 사용해보고 실행 결과를 정리합니다.

DBC 파일이란?

DBC 파일은 CAN 네트워크의 모든 메시지와 신호를 정의하는 텍스트 기반 파일입니다. 이 파일은 CAN 버스 상의 모든 통신 규격을 상세히 기술합니다. 다음은 DBC 파일의 한 메시지 예시입니다.

BO_ 333 UTEST_2: 8 BCM
 SG_ U8_TEST_1 : 39|8@0+ (1,0) [0|255] ""  BMS
 SG_ U7_TEST_1 : 47|7@0+ (1,-255) [-255|-128] ""  BMS
 SG_ ValTest : 30|2@0+ (1,0) [0|3] "c"  ESP,BMS
 SG_ U28_TEST_1 : 0|28@1+ (1,0) [0|4294967295] ""  ESP,BMS

이 예제에서:

  • BO_ 333 UTEST_2: 8 BCM는 ID가 333인 8바이트 길이의 UTEST_2 메시지를 정의하며, BCM(Body Control Module)에서 전송됩니다.
  • SG_로 시작하는 줄들은 각 신호를 정의합니다.

예를 들어, U8_TEST_1을 자세히 살펴보면:

  • 39|8@0+: 39번째 비트에서 시작하는 8비트 길이의 빅 엔디안, 부호 없는 값
  • (1,0): 스케일 1, 오프셋 0
  • [0|255]: 최소값 0, 최대값 255
  • BMS: 이 신호를 수신하는 ECU

CODERDBC: DBC to C 변환기

CODERDBC는 이러한 DBC 파일을 파싱하여 사용 가능한 C 코드로 변환합니다. 주요 기능은 다음과 같습니다:

  1. 메시지와 신호에 대한 구조체 생성
  2. 패킹/언패킹 함수 자동 생성
  3. ID 기반 메시지 라우팅 로직 구현
  4. 값 테이블을 열거형으로 변환

사용 방법

CODERDBC를 사용하는 방법은 다음과 같습니다.

GitHub에서 CODERDBC 클론하고 빌드합니다.

$ git clone https://github.com/astand/c-coderdbc.git
$ cd c-coderdbc
$ cmake -S src -B build cmake --build build --config release

이 저장소에 포함된 예제 test.dbc로 부터 코드를 생성합니다.

$ ./build/coderdbc -dbc ./test/testdb.dbc -out /home/makepluscode/c-coderdbc/out/ -drvname drivedb  -nodeutils -rw -driverdir -gendate

out 디렉토리에 생성된 폴더와 파일의 내용은 다음과 같습니다.

$ tree ./out/
./out/
├── butl
│   ├── test-binutil.c
│   └── test-binutil.h
├── conf
│   ├── dbccodeconf.h
│   └── test-config.h
├── drivedb
│   ├── butl
│   │   ├── bcm_drivedb-binutil.c
│   │   ├── bcm_drivedb-binutil.h
│   │   ├── bms_drivedb-binutil.c
│   │   ├── bms_drivedb-binutil.h
│   │   ├── eps_drivedb-binutil.c
│   │   ├── eps_drivedb-binutil.h
│   │   ├── esp_drivedb-binutil.c
│   │   └── esp_drivedb-binutil.h
│   ├── conf
│   │   ├── dbccodeconf.h
│   │   └── drivedb-config.h
│   ├── inc
│   │   └── canmonitorutil.h
│   ├── lib
│   │   ├── drivedb-fmon.h
│   │   ├── drivedb.c
│   │   └── drivedb.h
│   └── usr
│       └── drivedb-fmon.c
├── inc
│   └── canmonitorutil.h
├── lib
│   ├── test-fmon.h
│   ├── test.c
│   └── test.h
└── usr
    └── test-fmon.c

11 directories, 24 files

생성된 코드 분석: UTEST_2 메시지의 예

CODERDBC가 위의 UTEST_2 메시지에 대해 생성하는 코드를 살펴보겠습니다:

구조체 정의

typedef struct
{
    uint8_t U8_TEST_1;
    int8_t U7_TEST_1;
    uint8_t ValTest;
    uint32_t U28_TEST_1;
} UTEST_2_t;

이 구조체는 DBC 파일의 각 신호를 C 데이터 타입으로 매핑합니다.

언패킹 함수

uint32_t Unpack_UTEST_2_testdb(UTEST_2_t* _m, const uint8_t* _d)
{
    uint32_t _id = 333;

    _m->U8_TEST_1 = (_d[4] >> 7) | (_d[5] << 1);
    _m->U7_TEST_1 = (int8_t)(((_d[5] >> 7) | (_d[6] << 1)) & 0x7F) - 255;
    _m->ValTest = (_d[3] >> 6) & 0x03;
    _m->U28_TEST_1 = (_d[0] >> 2) | 
                     (_d[1] << 6) | 
                     (_d[2] << 14) | 
                     ((_d[3] & 0x3F) << 22);

    return _id;
}

이 함수는 원시 CAN 데이터를 파싱하여 구조체에 저장합니다. 각 라인은 DBC 파일의 비트 레이아웃을 정확히 반영합니다:

  • U8_TEST_1: 5번째와 6번째 바이트에 걸쳐 있는 8비트를 추출합니다.
  • U7_TEST_1: 6번째와 7번째 바이트에서 7비트를 추출하고 255를 뺍니다 (오프셋 적용).
  • ValTest: 4번째 바이트의 상위 2비트를 추출합니다.
  • U28_TEST_1: 첫 4바이트에 걸쳐 있는 28비트를 리틀 엔디안 형식으로 추출합니다.

수신 함수에서의 사용

uint32_t testdb_Receive(testdb_rx_t* _m, const uint8_t* _d, uint32_t _id, uint8_t dlc_)
{
    uint32_t recid = 0;
    if (_id == 333) {
        recid = Unpack_UTEST_2_testdb(&(_m->UTEST_2), _d);
    }
    // ... 다른 메시지 처리
    return recid;
}

이 함수는 수신된 CAN 메시지의 ID를 확인하고 해당하는 언패킹 함수를 호출합니다. 결론적으로 오픈 소스로 제공되는 CODERDBC는 커뮤니티의 지속적인 개선과 확장이 가능하다는 점에서도 큰 장점을 가집니다.

관련링크

CODERDBC에 대해 더 자세히 알아보고 싶거나 직접 사용해 보고 싶다면 다음 링크를 참조하세요.

반응형