簡単ですが、Defi ADVANCE の通信プロコトルについて調べたので書いておきます。
全部のプロトコルを調べたわけではありませんので、ご参考レベルにしてください。
(詳細を調べる気力がないので、詳細を知っている人がいたら教えていただけると嬉しいです)
ちなみに、過去にメーターを動かす実験をしています。この情報で、メーターを動かすくらいはできるはずです。
https://minkara.carview.co.jp/userid/2407630/blog/38798741/
◆物理結線について
Defi ADVANCE シリーズのコントロールユニットとメーターは、4本の線で結線されています。
そして、説明書などにも記載があるように、相互通信(双方向通信)です。
Defi Link は片方向の通信で、コントローラーからデータが一方的に送られるだけでしたが、ADVANCE は異なります。
具体的な結線は、以下の通りです。
黒線 ・・・ GND
赤線 ・・・ メーターからのデータ線(コントローラーが受信)
白線 ・・・ コントローラーからのデータ線(メーターが受信)
黄線 ・・・ 12V 電源
◆通信プロトコルその1
通信は RS232C 準拠の形式で、Defi LINK と同じです。
具体的には、以下の通りです。
通信速度: 19200bps
データ長: 8bit
パリティ: 偶数パリティ
ストップビット: 1bit
◆通信プロトコルその2
ADVANCE は機能が豊富なので、Defi LINK よりもプロトコルは複雑です。
ちなみに、アラームと調光の機能については解析していませんので、必要な方はご自分で解析をお願いします。
①初期化
IGNによってコントローラの電源を入れると、まずはコントローラーからメーターの初期化のパケットが流れます。(1回)
具体的には、下のようなものです(Cの配列で表現しています)。
uint8_t openGauge0[] = {0, 0xFF, 0xFF, 1, 1, 1, 4, 0, 1, 0xD8, 0, 0, 0, 1, 0xF4, 9, 3, 0, 0, 0, 1, 4, 0, 5, 1, 0};
おそらく、 00FF FF0x がパケットの区切りになっていると思います。
詳細は不明です。00FF がパケットの終わりで FF0x がパケットの開始なのか、00FF FF0x がパケットの開始なのか定かではありませんが、00FF FF0x を発信しておけばパケットの頭とみなされるようです。
②初期化その2
次に、以下のパケットがコントローラーから流されます。(同じものが 4、5回流れます)
uint8_t openGauge1[] = {0, 0xFF, 0xFF, 1, 0x11, 1, 4, 0, 1, 0xD8, 0, 0, 0, 1, 0xF4, 9, 3, 0, 0, 0, 1, 4, 0, 5, 1, 0};
③初期化その3
次は、以下です。x の部分(24番目)が 2 から 13 まで、1ずつカウントアップしていき、それぞれ 5回ずつです。
{0, 0xFF, 0xFF, 1, 0x11, 1, 4, 0, 1, 0xD8, 0, 0, 0, 1, 0xF4, 9, 3, 0, 0, 0, 1, 4, 0, 5, x, 0};
④初期化その4(メーター接続問い合わせ)
その次は、以下です。
メーターの接続状態を問い合わせているものと思われます。
各メーターには種類によってIDが振られているようで、自分が接続の問い合わせを受信したら、メータ自身が返信します。
xの部分は、1から7で一つずつカウントアップしていき、それぞれ 5回流れます。xの部分がメーターの ID だと思われます。
{0, 0xFF, 0xFF, 1, 0x21, 1, 4, 0, 1, 0xD8, 0, 0, 0, 1, 0xF4, 9, 3, 0, 0, 0, 1, 4, 0, 5, 0, x};
メーターの IDは、BOOST、TACO、FUEL PRESS などのメーターの種類に割り振られているものと思われます。
メーターは自分自身に接続の問い合わせがあった場合に、以下を返信します。
{0, 0xFF, 0xFF, 0x0A, y, 0, 0}
y の部分が、メーターから返信されるメーターの ID だと思われます。
具体的には、以下の通りです。(記載のないものは、メーターを持っていないので調べようがなく、わかりません。)
0x01 ・・・ BOOST METER
0x06 ・・・ TACO METER(80φ)
0x09 ・・・ OIL PRESS METER
0x0B ・・・ OIL TEMP METER
0x0C ・・・ WATER TEMP METER
⑤オープニング
次はオープニングのパケットが送られます。100回です。
{0, 0xFF, 0xFF, 1, 0x31, 1, 4, 0, 1, 0xD8, 0, 0, 0, 1, 0xF4, 9, 3, 0, 0, 0, 1, 4, 0, 5, 0, 0};
5番目のデータ 0x31 の部分が 0x30 だとオープニング A になり、0x31 だとオープニング B だと思います。(実験はしていません。)
ここまでで、初期化は終了です。
あとは、データのパケットが流れます。
⑥データパケット
データのパケットは1種類です。1つのパケットに全てのメーターのデータが入っています。(Defi LINK ではデータごとに1つのパケットでした。)
具体的には、以下のようなものです。
uint8_t dataGauge[] = {0, 0xFF, 0xFF, 3, 0, 1, 0, 0, 1, 0xD8, 0, 0, 0, 0, 0, 0, 0xEC, 3, 0x10, 0x10, 0, 0, 0x9F, 1, 0, 0, 0, 0, 0x74, 0, 0, 0, 0, 0};
15から28番目のデータが、メーターの数値のデータです。
15, 16番目が TACO METER です。(ビッグエンディアンです。LSB MSB の順です。)
17, 18番目が、BOOST
19, 20番目が、OIL PRESS
21, 22番目が、FUEL PRESS(推測)
23, 24番目が、OIL TEMP
25, 26番目が、WATER TEMP
27, 28番目が、EXT. TEMP(推測)
TACO は数値がそのまま PRM です。
BOOST は、1000(10進)がメーター盤の0.0、2000が1.0です。(盤面×1000+1000が値)
OIL PRESS は、1000が1.0、2000が2.0です。(盤面×1000が値)
FUEL PRESS は未確認ですが、おそらくOIL PRESS と同じだと思われます。
OIL TEMP は、2000が 100℃です(盤面×20が値)
WATER TEMP は、OIL TEMP と同様です。
EXT. TEMP も OIL TEMP と同じではないかと思います(推測)。
29から33が、メーターとセンサーが接続されているかの状態フラグです。
センサーが接続されていないがメーターが接続されている場合は、エラーになってブザーが鳴ると思います。
29 TACO?
30 ???
31 上位が OIL PRESS, 下位が BOOST
32 上位が OIL TEMP、下位が FUEL PRESS
33 上位が EXT.TEMP?、下位が WATAER TEMP
フラグの値は、
接続なしが 5
センサーのみ接続ありが 1
メーター、センサー双方接続ありが 0 です。
(コントローラーを偽装する場合は、全部0にしておけば問題ないようです)
なお、10バイト目の 0xD8 となっているところがメーターの明るさのデータだと思います。詳細は確認していませんが、ここを変えると明るさが変わります。
⑦クロージング
電源OFF時は、以下のパケットです。
{0, 0xFF, 0xFF, 2}; 1回
{1, 0xFF, 0xFF, 2}; 1回
{0x21, 0xFF, 0xFF, 2}; 105回(これがエンディングアニメーションと思われます。)
{0x51}; 1回
ご参考に、Arduino で試したプログラムを貼っておきます。
[code]
#include <CustomSoftwareSerial.h>
#define SIZEM(a) (sizeof((a)) / sizeof((a[0])))
#define delayT 5
CustomSoftwareSerial* customSerial; // Declare serial
uint8_t openGauge0[] = {0, 0xFF, 0xFF, 1, 1, 1, 4, 0, 1, 0xD8, 0, 0, 0, 1, 0xF4, 9, 3, 0, 0, 0, 1, 4, 0, 5, 1, 0}; //23
uint8_t openGauge1[] = {0, 0xFF, 0xFF, 1, 0x11, 1, 4, 0, 1, 0xD8, 0, 0, 0, 1, 0xF4, 9, 3, 0, 0, 0, 1, 4, 0, 5, 1, 0};
uint8_t dataGauge[] = {0, 0xFF, 0xFF, 3, 0, 1, 0, 0, 1, 0xD8, 0, 0, 0, 0, 0, 0, 0xEC, 3, 0x10, 0x10, 0, 0, 0x9F, 1, 0, 0, 0, 0, 0x74, 0, 0, 0, 0, 0}; //31
uint8_t closeGauge[] = {0, 0xFF, 0xFF, 2};
uint8_t endGauge[] = {0x51};
void sendOpen(void) {
// 0 set
Serial.println("0 set");
sendData(openGauge0, SIZEM(openGauge0));
delay(5);
// 1st set
Serial.println("1st set");
openGauge1[4] = 0x11;
openGauge1[24] = 1;
openGauge1[25] = 0;
for(int i = 0; i < 4; i++) {
sendData(openGauge1, SIZEM(openGauge1));
delay(delayT);
}
for(int i = 2; i < 14; i++) {
openGauge1[24] = i;
for(int j = 0; j < 5; j++) {
sendData(openGauge1, SIZEM(openGauge1));
delay(delayT);
}
}
// 2nd set (May be DETECT Gauge)
Serial.println("2nd set");
openGauge1[4] = 0x21;
openGauge1[24] = 0;
for(int i = 1; i < 8; i++) {
openGauge1[25] = i;
for(int j = 0; j < 5; j++) {
sendData(openGauge1, SIZEM(openGauge1));
//delay(2);
for (; customSerial->available(); ) {
//Serial.write(customSerial->read());
Serial.println(customSerial->read(), HEX);
}
}
}
// 3rd set (May be OPENING DEMO)
Serial.println("3rd set");
openGauge1[4] = 0x31;
openGauge1[24] = 0;
openGauge1[25] = 0;
for(int i = 0; i < 100; i++) {
sendData(openGauge1, SIZEM(openGauge1));
delay(delayT);
}
}
void sendClose(void) {
Serial.println("Close 0");
closeGauge[0] = 0;
sendData(closeGauge, SIZEM(closeGauge));
Serial.println("Close 1");
closeGauge[0] = 1;
sendData(closeGauge, SIZEM(closeGauge));
//delay(delayT);
Serial.println("Close 2");
closeGauge[0] = 0x11;
for(int i = 0; i < 105; i++) {
sendData(closeGauge, SIZEM(closeGauge));
//delay(delayT);
}
Serial.println("Close 3");
closeGauge[0] = 0x21;
for(int i = 0; i < 55; i++) {
sendData(closeGauge, SIZEM(closeGauge));
//delay(delayT);
}
Serial.println("Close End");
sendData(endGauge, SIZEM(endGauge));
}
void sendData(uint8_t dat[], int siz) {
for(int i = 0; i < siz; i++) {
customSerial->write(dat[i]);
}
}
// Init value
void setup() {
Serial.begin(19200);
delay(10);
Serial.println("Start Setup");
customSerial = new CustomSoftwareSerial(7, 6); // rx, tx
customSerial->begin(19200, CSERIAL_8E1); // Baud rate: 19200
delay(100);
Serial.println("Opening start");
sendOpen();
Serial.println("Opening end");
}
void loop() {
//static uint16_t l = 0;
//static uint16_t minus = 10;
static uint16_t ii = 1;
static uint16_t i;
//if (customSerial->available())
// Serial.write(customSerial->read());
if (Serial.available()) {
i = Serial.parseInt();
}
// customSerial->write(Serial.read());
//} else {
// Send data
if(i != 0L) {
if(i == 9999L){
sendClose();
i = 0;
} else {
// TACO 80
dataGauge[15] = i >> 8; // MSB
dataGauge[14] = i & 0xFF; // LSB
// BOOST
dataGauge[17] = i >> 8; // MSB
dataGauge[16] = i & 0xFF; // LSB
// OIL PRESS
dataGauge[19] = i >> 8; // MSB
dataGauge[18] = i & 0xFF; // LSB
// FUEL PRESS
dataGauge[21] = i >> 8; // MSB
dataGauge[20] = i & 0xFF; // LSB
// OIL TEMP
dataGauge[23] = i >> 8; // MSB
dataGauge[22] = i & 0xFF; // LSB
// WATER TEMP
dataGauge[25] = i >> 8; // MSB
dataGauge[24] = i & 0xFF; // LSB
// EXT. TEMP
dataGauge[27] = i >> 8; // MSB
dataGauge[26] = i & 0xFF; // LSB
// ILLMINATION
//dataGauge[9] = i & 0xFF; // MSB
//dataGauge[8] = i & 0xFF; // LSB
}
}
sendData(dataGauge, SIZEM(dataGauge));
//}
//}
ii = ii + 1;
//delay(delayT);
}
[/code]
追記(2023/10/7):
当時のメモを貼っておきます。
追記です。(2025/6/4)
メーターに送られるデータは、全てが垂れ流されている訳ではありません。
センサーが接続されているという条件だけでなく、初期化時のメーター接続問い合わせで応答を返したメーターに対するデータだけが送信されます。
ですので、メーターを接続していない場合はそのままではデータが取れません。
初期化時の問い合わせに応答してあげる必要があります。