재규어/랜드로버 CCF 오류 발생 시 원인 분석과 대응
재규어/랜드로버 차량 코딩 중 문제가 발생했다. 가장 중요한 CCF(자동차 구성 파일)의 정의가 잘못되어 있었던 것. 국내 재규어/랜드로버를 직접 코딩하는 사람들이 많지 않아 문제가 발생했을 때 도움을 받기 쉽지 않다는 아쉬움이 있다. 이 포스트는 재규어/랜드로버를 코딩하며 발생할 수 있는 문제와 해결 방법을 공유하고자 작성하는 것이며, SDD 뿐만 아니라 PathFinder도 대상에 포함된다.
이 문제는 AHBA를 활성화 하며 추가적으로 LKA/LDW를 사용하려고 노력하다 발생했었다.
목록의 값이 잘못 설정 되어 있는 경우
다음 예제는 스티어링(핸들) 정보를 수정할 때 발견한 문제다.
자동 주차 보조 기능이 있는 차량은 파워 스티어링 타입(Power Steering Type)의 기본 값이 0x08 (Electric power steering with external angle control only)이다. LKA(Lane Keep Assist)가 있는 차량들은 0x0A (Electric power steering with external angle and torque control)이 기본이다.
LKA를 활성화하기 위해 이 항목을 0x0A로 바꿨지만 적용에 실패했다. 이유인 즉 모노-카메라인 HCMB에서는 LDW까지만 가능하다는 것. 그래서 기본 값(0x08 = default value)으로 회귀하려고 했지만, 0x07로만 돌아가는 문제가 발생했다. 이유는? 0x07 / 0x08의 ID 값(@MCP_EPS_1)이 동일하기 때문에 0x08로 수정해도 선행 값인 0x07로 수정되었던 것.
이건 재랜의 명백한 실수다. 0x08의 ID는 @MCP_EPS_1이 아닌 @MCP_EPS_2가 되어야 한다. 아래 XML의 Option값을 살펴보면 1>1>3>4로 되어있는 걸 발견할 수 있다.
상식적으로 ID는 주요 식별자 이기 때문에 중첩되어선 안된다. 순서를 보면 1>2>3>4가 맞다. 실제로 두 번째 값을 2로 바꾸면 정상적으로 반영할 수 있다. 이 정도는 저 같은 아마추어도 쉽게 발견 가능한 부분이었다.
비트(bit) 마스크(mask)가 잘못 정의 되어 있는 경우
치명적인 문제이면서 수준이 높은 부분이다. 프로그래머라면 어렵지 않게 이해할 수 있을 거라 생각하지만 이유를 알지 못하는 상황에서 어려운 것은 매한가지 일 거다.
Intelligent cruise control은 “MultiCAN 503″에 위치하며, 이 그룹에는 3가지 항목(Parameter)이 있고, 이들의 기본 값은 다음과 같다.
Byte_Bit | Byte | Bit | Lable | Default value |
502_502_000_002 | 502 | 000~002 | Connectivity | 0x01 |
502_502_003_005 | 502 | 003~005 | Connect information status | 0x49 |
502_502_006_007 | 502 | 006~007 | Intelligent cruise control | 0x40 |
목표는 Intelligent cruise control(502_502_006_007)의 값을 0x40(Not Fitted)에서 0x80(Fitted)로 수정하는 거다. 그런데, 이 항목을 수정하면 0x40이 아닌 0xC9(C9)로 수정될 뿐만 아니라, 바로 위 항목 Connect information status 조차 0xC9(C9)로 수정되어 버리는 문제가 발생한다.
이 값을 기본 값으로 수정하려고 하면 두 가지 이상한 부분을 맞이하게 된다.
- Connect information status 0x49를 선택할 수 없다.
- 0x49(C9)는 존재하는 값이 아니다.
XML 파일을 열어보면 1/2번에 대한 의구심은 커질 수밖에 없다.
물론 선택할 수 없는 값은 Option 값 강제 정의(=추가)를 하면 일반적으로 사용 가능하다.
그런데 문제가 생겼다. 수정 후 CCF를 다시 확인해 보면 둘 다 0xC9(C9)로 돌아가 있던 것. 이 값을 임의의 값으로 수정하고 업데이트를 해도 큰 변화는 없었다. 문제는 이들 값이 클러스터에 영향을 미쳐 클러스터에 알 수 없는 오류가 표시된다. (오른쪽 서클 안에 아무 내용이 표시되지 않는 문제)
Connect information status의 기본 값 자체에 문제가 있음을 발견할 수 있다. 0x49는 Byte의 3-7 Bits내에서 표현될 수 없는 값이기 때문이다. 0x49를 바이너리로 바꾸게 되면 01001001입니다. (1 Byte = 8 bit 이기 때문에 자릿수가 8자리임) 이 값에 대한 이해는 아래 URL을 참고하자.
0x49는 01001001이면서 십진수 73이다. 십진수 49를 바이너리로 표현하면 0011001인 0x31이다. 이 값을 사용할 수 있는지 여부는 XML에 정의되어 있는 항목별 mask에 있다.
(비트 마스크, 바이너리 순서)
- 0-2 0x07 00 000 111 (오른쪽 끝 3자리만 사용. 2^2+2^1+1=7)
- 3-5 0xF8 11 111 000 (3-5가 아닌 5비트를 모두 정의하고 있음)
- 6-7 0xC0 11 000 000 (마지막 2비트만)
1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
여기서 3-5비트와 6-7비트가 겹치는 걸 발견할 수 있다. 때문에, Intelligent cruise control을 수정해도 바로 위의 값이 함께 수정될 수밖에 없었던 거다. (=동기화)
0-2비트를 끄고(1-on, 0-off) 3-5의 값을 정리해 보자. 모두 바이너리(2진수)라는 걸 가정하고 생각하자. 선택할 수 있는 2개의 값을 바이너리로 바꾸면.
0x80 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 2^3=8 |
0x20 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 2^5=20 |
이번엔 6-7의 값을 정리해보자.
0x40 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 2^6 |
0x80 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
6-7의 0x80(Intelligent cruise control fitted)을 선언하기 위해서는 4비트(5번째 자리)가 1이어야 한다. 이 경우 위에서 언급한. 아래의 초록색과 겹친다.
mask | 0xF8 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
3-5 | 0x80 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
왜 C9(0xC9)가 표현되었는지 실마리가 풀리기 시작한다. 0xC9를 바이너리로 표현하면 다음과 같다.
- 0xC9 11001 000
1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
2^7 | 2^6 | 0 | 0 | 2^3 | 0 | 0 | 0 |
비트 0-2는 마스크에 의해 시프트 되기 때문에 무시해도 상관없으므로 생각해야 하는 값은 3-7만 고려하면 되며, 이 값은 11001이다. 나는 다음 두 값을 기본 상태로 변경하기를 원했다. 그러나, 우선 Connect information status에 49라는 항목이 없으므로 먼저 비활성화하는 걸 목표로 했다.
Connect information status
- 3-5 0x08 00001 000 (=CI Not Active)
Intelligent cruise control
- 6-7 0x40 01000 000 (@J_QV_NOTFITTED)
이 두 값이 씌워질 때는 결합되기 때문에 01001의 값으로 기록 되어야 하나, Intelligent cruise control에서 사용하는 01은 Connect information status가 선점하고 있기 때문에 11001로 기록되고 있는 것을 짐작할 수 있다. (7 bit가 1인 이유는 mask에서 7이 ON 상태이기 때문)
왜 C9가 나왔는지 알 수 있게 되었다.
Connect information status가 Intelligent cruise control로 오버플로우 하는 문제를 막기 위해선 Connect information status의 mask를 조절할 필요가 있다. Intelligent cruise control의 6-7은 문제가 없기 때문에 Connect information status만 수정하자.
3-5 비트의 모든 값을 사용한다 가정하면 00 111 000을 역으로 16진수로 바꾸면 0x38이다.
- 0xF8 > 0x38 (00 111 000)
Connect information status에 0x49를 입력할 수 있을까? 가능합니다. 단, 전제조건이 있다. 값이 중첩되었을 때의 경우의 수다.
- 0x49 01 001 001 = 73(10진수)
- (오른쪽) 001 = Connectivity(502_502_000_002)가 0x01 이어야 함 = 000 000 001 이기 때문
- (왼쪽) 01 = Intelligent cruise control(502_502_006_007)가 0x40 이어야 함 = 01000 000 이기 때문
이제 Option을 추가하면 끝이다.
즉 default value인 49를 입력했을 때 Intelligent cruise control은 FITTED가 될 수 없고, Connectivity가 3G/4G가 선택될 수가 없다. 상호 보완적 값이라는 건데 왜 이 값이 49로 입력되어 있는지는 아무도 모른다.
프로그램을 개발하는 입장에서 값을 정의할 때 2가지 방법이 있는데, 가이던스를 먼저 만들고 선언하는 것과 선언 후 가이던스를 만드는 방법이다. 현재의 경우 값을 먼저 정의했는데, mask가 잘못됐으니, 후-정책 설계가 잘못되었다는 가설을 세워 볼 수 있다.
왜 지금까지 이런 문제가 없었던 것일까? 두 가지 경우의 수를 생각해볼 수 있다.
- 해당 차종의 502바이트는 사용하지 않는다.
- 502바이트를 사용하는 차량은 mask가 다르다.
CCF 수정은 변경된 데이터만 입력하기 때문에 변경되지 않은 데이터는 어떤 값으로 정의되어 있어도 상관 없다. 최근 발매되는 차량안 LKA와 Telematics모듈이 탑재되어 있기 때문이 Connectivity 값이 지정 되어 있을 것이고 변경할 이유가 없으니 아마도 모른게 아닐까 싶은데.
PathFinder는 SDD보다 좀더 보수적으로 접근하기 때문에 정의되지 않은 기능을 강제로 켜거나 끌 수 없지만, PathFinder 역시 CCF를 수정하려면 결국 XML 형태로 추출되는 만큼 같은 문제는 얼마든지 발생할 확률이 있다는걸 생각해 볼 필요가 있다.
사용하지 않는 값이 전장에 영향을 미치는 경우가 있기 때문에 … 발생하면 맨붕 터진다.