Last active
June 22, 2016 13:20
-
-
Save gabonator/7150910 to your computer and use it in GitHub Desktop.
Garmin HUD protocol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CString Hex(int n) | |
{ | |
CString str; | |
str.Format( _T("%02x"), n ); | |
return str; | |
} | |
void SendHud(unsigned char* pBuf, int nLen) | |
{ | |
CArray<int> arrPacket; | |
arrPacket.Add( 0x10 ); | |
arrPacket.Add( 0x7b ); | |
arrPacket.Add( nLen+6 ); | |
arrPacket.Add( nLen ); | |
arrPacket.Add( 0x00 ); | |
arrPacket.Add( 0x00 ); | |
arrPacket.Add( 0x00 ); | |
arrPacket.Add( 0x55 ); | |
arrPacket.Add( 0x15 ); | |
for ( int i=0; i<nLen; i++) | |
arrPacket.Add( pBuf[i] ); | |
//crc | |
unsigned int nCrc = 0; | |
for ( int i=1; i<arrPacket.GetSize(); i++) | |
nCrc += arrPacket[i]; | |
nCrc = (-(int)nCrc) & 0xff; | |
arrPacket.Add( nCrc ); | |
arrPacket.Add( 0x10 ); | |
arrPacket.Add( 0x03 ); | |
CString strPacket; | |
for ( int i=0; i<arrPacket.GetSize(); i++) | |
{ | |
strPacket += Hex( arrPacket[i] ); | |
// stuffing | |
if ( i > 0 && i < arrPacket.GetSize()-2 && arrPacket[i] == 0x10 ) | |
strPacket += Hex( arrPacket[i] ); | |
} | |
bt.Send( strPacket ); | |
} | |
int Digit(int n) | |
{ | |
n = n % 10; | |
if ( n == 0 ) | |
return 10; | |
return n; | |
} | |
void SetTime(int nH, int nM) | |
{ | |
bool bColon = true; | |
bool bFlag = false; | |
bool bTraffic = true; | |
unsigned char arr[] = {0x05, | |
bTraffic ? 0xff : 0x00, | |
Digit(nH/10), Digit(nH), bColon ? 0xff : 0x00, | |
Digit(nM/10), Digit(nM), bFlag ? 0x00 : 0xff, 0x00}; | |
SendHud(arr, sizeof(arr)); | |
} | |
void SetDistance(int nDist) | |
{ | |
enum { | |
None = 0, | |
Metres = 1, | |
Kilometres = 3, | |
Miles = 5 | |
} units = Metres; | |
bool bDecimal = false; | |
unsigned char arr[] = {0x03, | |
Digit(nDist/1000), Digit(nDist/100), Digit(nDist/10), bDecimal ? 0xff : 0x00, Digit(nDist), (int)units}; | |
SendHud(arr, sizeof(arr)); | |
} | |
void SetDirection(int nDir) | |
{ | |
enum { | |
SharpRight = 0x02, | |
Right = 0x04, | |
EasyRight = 0x08, | |
Straight = 0x10, | |
EasyLeft = 0x20, | |
Left = 0x40, | |
SharpLeft = 0x80 | |
} eOutAngle = EasyRight; | |
unsigned char arr[] = {0x01, 0x01, 0x00, (int)eOutAngle}; | |
SendHud(arr, sizeof(arr)); | |
} | |
void SetLanes( CString strLanes ) | |
{ | |
for (int i=strLanes.GetLength(); i < 6; i++ ) | |
if (i&1) | |
strLanes = _T(" ") + strLanes; | |
else | |
strLanes = strLanes + _T(" "); | |
int nOutline = 0, nArrow = 0; | |
for ( int i=0; i<6; i++) | |
{ | |
char ch = (char)strLanes[i]; | |
if (ch == '0' || ch == '1') | |
nOutline |= 1<<(6-i); | |
if (ch == '1') | |
nArrow |= 1<<(6-i); | |
} | |
unsigned char arr[] = {0x02, nOutline, nArrow}; | |
SendHud(arr, sizeof(arr)); | |
} | |
void SetSpeedWarning(int nSpeed, int nLimit) | |
{ | |
bool bSpeeding = true; | |
bool bIcon = true; | |
unsigned char arr[] = {0x06, | |
(nSpeed/100)%10, Digit(nSpeed/10), Digit(nSpeed), 0xff, | |
(nLimit/100)%10, Digit(nLimit/10), Digit(nLimit), bSpeeding ? 0xff : 0x00, bIcon ? 0xff : 0x00}; | |
SendHud(arr, sizeof(arr)); | |
} | |
void ShowCameraIcon() | |
{ | |
unsigned char arr[] = {0x04, 0x01}; | |
SendHud( arr, sizeof(arr) ); | |
} | |
void ShowGpsLabel() | |
{ | |
unsigned char arr[] = {0x07, 0x01}; | |
SendHud( arr, sizeof(arr) ); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int ZD(int n) | |
{ | |
if (n==0) return 10; | |
return n; | |
} | |
void _SetTime(int nHr, int nMin) | |
{ | |
CArray<int>arrPacket; | |
// preamble | |
static unsigned char a =0; | |
arrPacket.Add(0x10); arrPacket.Add(0x7b); arrPacket.Add(0x0f); arrPacket.Add(0x09); arrPacket.Add(0x00); arrPacket.Add(0x00); arrPacket.Add(0x00); | |
arrPacket.Add(0x55); arrPacket.Add(0x15); arrPacket.Add(0x05); arrPacket.Add(0x00); | |
arrPacket.Add((nHr/10)%10); arrPacket.Add(ZD(nHr%10)); arrPacket.Add(0xff); arrPacket.Add(ZD((nMin/10)%10)); arrPacket.Add(ZD(nMin%10)); arrPacket.Add(0x00); arrPacket.Add(0xff); | |
//\10\7b\0f\09\00\00\00\55\15\05\00\00\08\ff\01\0a\00\ff\ed\10\03 | |
// crc | |
int nCrc = 0; | |
for (int i=0; i<arrPacket.GetSize(); i++) nCrc += arrPacket[i]; | |
nCrc = (0x10+(-nCrc))&0xff; | |
arrPacket.Add(nCrc); | |
// terminator | |
arrPacket.Add(0x10); arrPacket.Add(0x03); | |
CString strBuf; | |
for (int i=0; i<arrPacket.GetSize(); i++) strBuf += CString::FormatInline( _T("%02x"), arrPacket[i] ); | |
CString strRequest = CString::FormatInline( _T("$JS: Driver.HudRequest(\"%s\");\n"), strBuf); | |
CLowDevice::DeviceTerminalSend( strRequest ); | |
} | |
void _SetDistance(int nDistance ) | |
{ | |
CArray<int>arrPacket; | |
// preamble | |
arrPacket.Add(0x10); arrPacket.Add(0x7b); arrPacket.Add(0x0d); arrPacket.Add(0x07); arrPacket.Add(0x00); arrPacket.Add(0x00); arrPacket.Add(0x00); arrPacket.Add(0x55); arrPacket.Add(0x15); arrPacket.Add(0x03); arrPacket.Add(0x00); | |
// numeric | |
if ( nDistance < 100 && nDistance >= 0 ) | |
{ | |
arrPacket.Add(0x00);arrPacket.Add(nDistance/10);arrPacket.Add(0x00);arrPacket.Add(0x0a);arrPacket.Add(0x01); | |
} | |
if ( nDistance < 1000 && nDistance >= 100 ) | |
{ | |
arrPacket.Add(nDistance/100);arrPacket.Add(_ZD((nDistance/10)%10));arrPacket.Add(/*(nDistance/10)%10*/ 0x00);arrPacket.Add(/*0x0a*/ _ZD(nDistance%10));arrPacket.Add(0x01); | |
} | |
if ( nDistance < 10000 && nDistance >= 1000 ) | |
{ | |
int nZ = (nDistance / 10000)%10; | |
int nA = (nDistance / 1000)%10; | |
int nB = (nDistance / 100)% 10; | |
if (nB == 0) nB = 10; // desatinna bodka // jednotky (3=km, 5=mi) | |
arrPacket.Add(nZ);arrPacket.Add(nA);arrPacket.Add(0xff);arrPacket.Add(nB);arrPacket.Add(0x03); | |
} | |
// crc | |
int nCrc = 0; | |
for (int i=1; i<arrPacket.GetSize(); i++) nCrc += arrPacket[i]; | |
nCrc = (-nCrc)&0xff; | |
arrPacket.Add(nCrc); | |
// terminator | |
arrPacket.Add(0x10); arrPacket.Add(0x03); | |
CString strBuf; | |
for (int i=0; i<arrPacket.GetSize(); i++) strBuf += CString::FormatInline( _T("%02x"), arrPacket[i] ); | |
CString strRequest = CString::FormatInline( _T("$JS: Driver.HudRequest(\"%s\");\n"), strBuf); | |
CLowDevice::DeviceTerminalSend( strRequest ); | |
} | |
void _SetDirection(int nDir) | |
{ | |
CArray<int>arrPacket; | |
// nDistance = 900; | |
// preable | |
static unsigned char a =0; | |
arrPacket.Add(0x10); arrPacket.Add(0x7b); arrPacket.Add(0x0a); arrPacket.Add(0x04); arrPacket.Add(0x00); arrPacket.Add(0x00); arrPacket.Add(0x00); | |
arrPacket.Add(0x55); arrPacket.Add(0x15); arrPacket.Add(0x01); arrPacket.Add(0x01); | |
//arrPacket.Add(0x41); arrPacket.Add(0x40); // dolava | |
//arrPacket.Add(0x21); arrPacket.Add(0x20); // trochu dolava | |
//arrPacket.Add(0x05); arrPacket.Add(0x80); // ostro dolava | |
//arrPacket.Add(0x05); arrPacket.Add(0x04); // doprava | |
//arrPacket.Add(0x11); arrPacket.Add(0x10); arrPacket.Add(0x10); // rovno | |
switch (nDir) | |
{ | |
case CJunctionEntry::DirectionLeft: | |
case CJunctionEntry::DirectionExitLeft:arrPacket.Add(0x41); arrPacket.Add(0x40); break; | |
//case CJunctionEntry::DirectionSharpLeft: | |
case CJunctionEntry::DirectionEasyLeft: arrPacket.Add(0x21); arrPacket.Add(0x20); break; | |
//case CJunctionEntry::DirectionEnd: | |
//case CJunctionEntry::DirectionOutOfRoute: | |
case CJunctionEntry::DirectionExitRight: | |
case CJunctionEntry::DirectionEasyRight: | |
case CJunctionEntry::DirectionSharpRight: | |
case CJunctionEntry::DirectionRight: arrPacket.Add(0x05); arrPacket.Add(0x04); break; | |
case CJunctionEntry::DirectionSharpLeft: arrPacket.Add(0x05); arrPacket.Add(0x80); break; | |
case CJunctionEntry::DirectionKeepLeft: | |
case CJunctionEntry::DirectionKeepRight: | |
case CJunctionEntry::DirectionFollow: | |
case CJunctionEntry::DirectionStraight: arrPacket.Add(0x11); arrPacket.Add(0x10); arrPacket.Add(0x10); break; | |
default: | |
return; | |
// arrPacket.Add(0x00); arrPacket.Add(0x00); | |
} | |
/* | |
camera: | |
arrPacket.Add(0x10); arrPacket.Add(0x7b); arrPacket.Add(0x0a); arrPacket.Add(0x04); arrPacket.Add(0x00); arrPacket.Add(0x00); arrPacket.Add(0x00); | |
arrPacket.Add(0x55); arrPacket.Add(0x15); | |
arrPacket.Add(0x04); arrPacket.Add(0x01); arrPacket.Add(0x11); arrPacket.Add(0x10); arrPacket.Add(0x10); | |
01 ** 11 10 10: priamo, horna sipka, rb 180, pravy finish | |
** 01 11 10 10: ikony, GPS | |
*/ | |
// crc | |
int nCrc = 0; | |
for (int i=0; i<arrPacket.GetSize(); i++) nCrc += arrPacket[i]; | |
if ( arrPacket.GetSize() == 14 ) | |
nCrc = (0x20+(-nCrc))&0xff; | |
else | |
nCrc = (0x10+(-nCrc))&0xff; | |
arrPacket.Add(nCrc); | |
// terminator | |
arrPacket.Add(0x10); arrPacket.Add(0x03); | |
CString strBuf; | |
for (int i=0; i<arrPacket.GetSize(); i++) strBuf += CString::FormatInline( _T("%02x"), arrPacket[i] ); | |
CString strRequest = CString::FormatInline( _T("$JS: Driver.HudRequest(\"%s\");\n"), strBuf); | |
CLowDevice::DeviceTerminalSend( strRequest ); | |
} | |
void _SetLanes( CString strMask ) | |
{ BYTE bA = 0x15, bB = 0x02; | |
bA = 0; | |
bB = 0; | |
for ( int i=0; i<6; i++) | |
{ | |
char ch = strMask[i]; | |
if (ch == '0' || ch == '1') | |
bA |= 1<<(6-i); | |
if (ch == '1') | |
bB |= 1<<(6-i); | |
} | |
//\10\7b\09\03\00\00\00\55\15\02\1c\04\ed\10\03 | |
// 10 7b 09 03 00 00 00 55 1c 04 7e 0e 78 10 03 | |
CArray<int>arrPacket; | |
// preable | |
arrPacket.Add(0x10); arrPacket.Add(0x7b); arrPacket.Add(0x09); arrPacket.Add(0x03); arrPacket.Add(0x00); arrPacket.Add(0x00); arrPacket.Add(0x00); | |
arrPacket.Add(0x55); arrPacket.Add(0x15); arrPacket.Add(0x02); | |
arrPacket.Add(bA); arrPacket.Add(bB); | |
// crc | |
int nCrc = 0; | |
for (int i=0; i<arrPacket.GetSize(); i++) nCrc += arrPacket[i]; | |
nCrc = (0x20+0xf0+(-nCrc))&0xff; | |
arrPacket.Add(nCrc); | |
// terminator | |
arrPacket.Add(0x10); arrPacket.Add(0x03); | |
CString strBuf; | |
for (int i=0; i<arrPacket.GetSize(); i++) strBuf += CString::FormatInline( _T("%02x"), arrPacket[i] ); | |
CString strRequest = CString::FormatInline( _T("$JS: Driver.HudRequest(\"%s\");\n"), strBuf); | |
CLowDevice::DeviceTerminalSend( strRequest ); | |
} | |
void _SetSpeedWarn(int nSpd, int nLim, BOOL32 bWarn) | |
{ | |
if ( nSpd == 0 && nLim == 0 ) | |
return; | |
//\10\7b\10\10\0a\00\00\00\55\15\06\00\05\0a\ff\00\05\0a\00\ff\df\10\03 | |
//107b10100a00000055150600050aff00050a00ffdf1003 | |
CArray<int>arrPacket; | |
arrPacket.Add(0x10); arrPacket.Add(0x7b); arrPacket.Add(0x10); arrPacket.Add(0x10); arrPacket.Add(0x0a); arrPacket.Add(0x00); arrPacket.Add(0x00); arrPacket.Add(0x00); | |
arrPacket.Add(0x55); arrPacket.Add(0x15); | |
arrPacket.Add(0x06); arrPacket.Add((nSpd/100)%10); arrPacket.Add((nSpd/10)%10); arrPacket.Add(0x0a); | |
arrPacket.Add(0xff); arrPacket.Add((nLim/100)%10); arrPacket.Add((nLim/10)%10); arrPacket.Add(0x0a); | |
arrPacket.Add(bWarn); arrPacket.Add(0xff); | |
// crc | |
int nCrc = 0; | |
for (int i=0; i<arrPacket.GetSize(); i++) nCrc += arrPacket[i]; | |
nCrc = (0x20+(-nCrc))&0xff; | |
arrPacket.Add(nCrc); | |
// terminator | |
arrPacket.Add(0x10); arrPacket.Add(0x03); | |
CString strBuf; | |
for (int i=0; i<arrPacket.GetSize(); i++) strBuf += CString::FormatInline( _T("%02x"), arrPacket[i] ); | |
CString strRequest = CString::FormatInline( _T("$JS: Driver.HudRequest(\"%s\");\n"), strBuf); | |
CLowDevice::DeviceTerminalSend( strRequest ); | |
} |
sample sniffed frames:
10 7b 0d 07 00 00 00 55 15 03 00 00 09 00 0a 01 f0 10 03
10 7b 0d 07 00 00 00 55 15 03 00 00 08 00 0a 01 f1 10 03
10 7b 0d 07 00 00 00 55 15 03 00 00 07 00 0a 01 f2 10 03
10 7b 08 02 00 00 00 55 15 07 00 0a 10 03
10 7b 08 02 00 00 00 55 15 04 00 0d 10 03
10 7b 0a 04 00 00 00 55 15 01 01 41 40 8a 10 03
10 7b 10 10 0a 00 00 00 55 15 06 00 05 0a ff 00 05 0a 00 ff df 10 03
description of garmin protocol, stuffing and crc:
http://www8.garmin.com/support/commProtocol.html
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
packet structure: { 0x10 0x47 (packet_len: 1 byte) (data_len: 4 bytes) data: { 55 15 ... } (crc: 1 byte) 0x10 0x03 }
packet_len = data_len+6
set arrival time "Hh:Mm": 05 00 (HH) (hh) ff (MM) (mm) 00 ff
set distance "X0 m": 03 00 00 (XX) 00 0a 01
set distance "XYZ m": 03 00 (XX) (YY) 00 (ZZ) 01
set distance "XY.Z km": 03 00 (XX) (YY) ff (ZZ) 03
set distance "XY.Z mi": 03 00 (XX) (YY) ff (ZZ) 05
set direction XY: 01 01 (XX) (YY)
left 41 40
right 05 04
sharp right 05 80
straight 11 10
set lanes: XY: 02 (XX) (YY)
bits of XX: "dots/outline/outline/outline/outline/outline/outline/dots"
bits of YY: "none/arrow/arrow/arrow/arrow/arrow/arrow/none"
set speed warning XYZ/PQR kmh: 06 (XX) (YY) (ZZ) ff (PP) (QQ) (RR) 00 ff
set speed warning with alert: 06 (XX) (YY) (ZZ) ff (PP) (QQ) (RR) 01 ff
two consecutive 10 10 are caused by stuffing, do not include both in CRC calculation
for displaying zero digit use 0x0A instead of 0x00 which shows an empty digit