Device Configuration Packet: Difference between revisions
No edit summary |
No edit summary |
||
| Line 293: | Line 293: | ||
} | } | ||
</pre> | </pre> | ||
<html lang="en"> | |||
<head> | |||
<meta charset="UTF-8" /> | |||
<title>Device Configuration Packet Parser</title> | |||
<style> | |||
body { font-family: Arial, sans-serif; padding: 20px; } | |||
textarea { width: 100%; height: 120px; font-family: monospace; } | |||
button { | |||
padding: 10px 20px; border-radius: 20px; font-weight: bold; | |||
background-color: #680022; color: white; border: none; cursor: pointer; | |||
} | |||
button:hover { background-color: #4c0019; } | |||
table { width: 100%; border-collapse: collapse; margin-top: 20px; } | |||
th, td { border: 1px solid #ccc; padding: 8px; } | |||
th { background-color: #680022; color: white; } | |||
</style> | |||
</head> | |||
<body> | |||
<h2>Device Configuration Packet Parser</h2> | |||
<textarea id="packetInput" placeholder="Paste Device Configuration hex packet here..."></textarea><br> | |||
<button onclick="parsePacket()">Parse Packet</button> | |||
<h3>Parsed Output:</h3> | |||
<table id="resultTable"> | |||
<thead><tr><th>Field</th><th>Value</th></tr></thead> | |||
<tbody></tbody> | |||
</table> | |||
<script> | |||
function hexToBits(hex) { | |||
return hex.match(/.{1,2}/g).map(b => parseInt(b, 16).toString(2).padStart(8, '0')).join(''); | |||
} | |||
function bitsToInt(bits) { | |||
return parseInt(bits, 2); | |||
} | |||
function bitsToSignedInt(bits) { | |||
const val = parseInt(bits, 2); | |||
const max = 1 << bits.length; | |||
return val >= max / 2 ? val - max : val; | |||
} | |||
function bitsToAscii(bits) { | |||
return bits.match(/.{8}/g).map(b => String.fromCharCode(parseInt(b, 2))).join('').replace(/\0/g, '').trim(); | |||
} | |||
function parseMobile(bits) { | |||
const isWithCountryCode = bits[0] === '1'; | |||
const number = BigInt('0b' + bits.slice(1)).toString(); | |||
return isWithCountryCode ? `+${number}` : number; | |||
} | |||
function parsePacket() { | |||
const hex = document.getElementById('packetInput').value.trim().toLowerCase(); | |||
const resultBody = document.querySelector("#resultTable tbody"); | |||
resultBody.innerHTML = ""; | |||
if (!hex.startsWith("24")) { | |||
alert("Invalid Packet"); | |||
return; | |||
} | |||
const bits = hexToBits(hex); | |||
const show = (key, value) => { | |||
const row = document.createElement("tr"); | |||
row.innerHTML = `<td>${key}</td><td>${value}</td>`; | |||
resultBody.appendChild(row); | |||
}; | |||
show("Start Byte", hex.slice(0, 2)); | |||
show("Packet Type", bitsToInt(bits.slice(75, 80))); | |||
const imei = BigInt('0b' + bits.slice(25, 75)).toString(); | |||
show("IMEI", imei); | |||
const timestamp = bitsToInt(bits.slice(80, 112)); | |||
const timezoneRaw = bitsToSignedInt(bits.slice(112, 120)); | |||
const offsetMins = timezoneRaw * 15; | |||
const localDate = new Date((timestamp + offsetMins * 60) * 1000).toISOString().replace("T", " ").replace(".000Z", ""); | |||
show("DateTime", timestamp); | |||
show("TimeZone", `UTC${offsetMins >= 0 ? '+' : ''}${offsetMins / 60}`); | |||
show("DateTime (Local Time)", localDate); | |||
show("IgnitionSource", bitsToInt(bits.slice(120, 122))); | |||
show("CellOperator", bitsToInt(bits.slice(122, 126))); | |||
show("FuelSensorCount", bitsToInt(bits.slice(126, 128))); | |||
show("FuelSensorName", bitsToInt(bits.slice(128, 132))); | |||
show("FuelSensorBaudrate", bitsToInt(bits.slice(132, 144))); | |||
show("FuelSensorMode", bitsToInt(bits.slice(144, 146))); | |||
show("OneWireStatus", bitsToInt(bits.slice(146, 147))); | |||
show("OneWireType", bitsToInt(bits.slice(147, 150))); | |||
show("OneWireSensorCount", bitsToInt(bits.slice(150, 153))); | |||
show("OdometerMode", bitsToInt(bits.slice(153, 154))); | |||
show("SpeedThreshold", bitsToInt(bits.slice(154, 163))); | |||
show("HAT", bitsToInt(bits.slice(163, 175))); | |||
show("HBT", bitsToInt(bits.slice(175, 187))); | |||
show("RTT", bitsToInt(bits.slice(187, 196))); | |||
show("TAT", bitsToInt(bits.slice(196, 205))); | |||
show("ImmobilizerStatus", bitsToInt(bits.slice(205, 206))); | |||
show("ImmobilizerSpeed", bitsToInt(bits.slice(206, 215))); | |||
show("DigitalInStatus", bitsToInt(bits.slice(215, 219))); | |||
show("DigitalOutStatus", bitsToInt(bits.slice(219, 221))); | |||
show("AnalogInStatus", bitsToInt(bits.slice(221, 223))); | |||
show("SMSM1", parseMobile(bits.slice(223, 274))); | |||
show("SMSM2", parseMobile(bits.slice(274, 325))); | |||
show("NOOfIP", bitsToInt(bits.slice(325, 328))); | |||
show("IMMOBSrc", bitsToInt(bits.slice(328, 331))); | |||
const apnLen = bitsToInt(bits.slice(331, 336)); | |||
const apnBits = bits.slice(336, 336 + apnLen * 8); | |||
show("APN", bitsToAscii(apnBits)); | |||
// End Byte and CRC (last 2 bytes) | |||
const endByte = hex.slice(-4, -2); | |||
const crc = hex.slice(-2); | |||
show("End Byte", String.fromCharCode(parseInt(endByte, 16))); | |||
show("CRC", `0x${crc}`); | |||
show("CRC Status", "Valid (not implemented)"); // CRC logic can be added | |||
} | |||
</script> | |||
</body> | |||
</html> | |||
Revision as of 05:37, 22 July 2025
| Field | Size (bits) | Bit Range | Description | Breakdown |
|---|---|---|---|---|
| Header | ||||
| Start byte | 8 | 0 - 7 | Starting character $ | ASCII value 36 |
| Data length | 12 | 8 - 19 | 2-byte length of the data following the header | |
| Number of data packets | 5 | 20 - 24 | Number of packets | 0–32 |
| IMEI | 50 | 25 - 74 | Unique device identifier | |
| Packet Type | 5 | 75 - 79 | Type of packet | 02 - OTA Packet |
| Data | ||||
| Time | 32 | UTC Timestamp | UTC time in seconds | |
| Timezone | 8 | Timezone in quarter-hours | 22 = +5:30 (22 × 15min = 330min = 5.5hr) | |
| IGN Source | 2 | Source of ignition detection | 0 - IGN PIN, 1 – Vibration, 2 - Voltage, 3 - GPS | |
| Cell Operator | 4 | |||
| Fuel Sensor Count | 2 | Number of fuel sensors | ||
| Fuel Sensor Name | 4 | Refer sheet Enums | ||
| Fuel Sensor Baudrate | 12 | up to 115200 | ||
| Fuel Sensor Mode | 2 | |||
| Onewire Status | 1 | Enable or disable | ||
| Onewire Sensor Type | 3 | |||
| Onewire Sensor Count | 3 | |||
| Odometer Mode | 1 | 0 or 1 (Accumulated or Differential) | ||
| Speed Threshold | 9 | 0–360 | ||
| HAT | 12 | 50–3500 | ||
| HBT | 12 | 50–3500 | ||
| RTT | 9 | 5–480 | ||
| Tilt Angle Threshold | 9 | 5–359 | ||
| Immobilizer Status | 1 | |||
| Immobilizer Speed | 9 | |||
| Digital Input Status | 4 | 3 | ||
| Digital Output Status | 2 | 0–3 | ||
| Analog Input Status | 2 | 0 or 1 | ||
| SMS M1 | 51 | MSB 1 - country code included, MSB 0 - no country code | Remaining 50 bits = mobile number | |
| SMS M2 | 51 | Same format as SMS M1 | ||
| Number of IPs | 3 | 0–5 | ||
| IMOBSRC | 3 | |||
| APN Length | 5 | Length in bytes | ||
| APN | Variable | Access Point Name | Length defined by APN length | |
| Tail | ||||
| End Character | 8 | 0 - 7 | Ending character * | ASCII value 42 |
| CRC | 8 | 8 - 15 | XOR CRC from $ to * | Excludes $ and * |
OTA Packet (Type 4)
{
"HEX": "240280e1cabd09208ca46822dde6160c00000006400400002168280000357c8b071280000000000002084d324d49534146452a6a",
"ai_status": 0,
"apn": 77,
"apn_length": 8,
"cell_op": 3,
"dateTime": 1747115494,
"dateTime_tz": "2025-05-13 11:21:34.000",
"di_status": 0,
"do_status": 0,
"fs_baudrate": 0,
"fs_count": 0,
"fs_mode": 0,
"fs_name": 0,
"hat": 1,
"hbt": 0,
"ign_source": 0,
"imbz_status": 2,
"imei": 860187062240357,
"immobilizer_speed": 20,
"imobsrc": 0,
"insert_time": "Tue, 13 May 2025 05:51:37 GMT",
"no_ips": 2,
"odometer_mode": 0,
"onewire_count": 0,
"onewire_status": 0,
"onewire_type": 0,
"packetType": 4,
"rtt": 1,
"send_time": "2025-05-13 11:21:34",
"sms_m1": 918891011146,
"sms_m2": 0,
"speed_threshold": 25,
"tilt_angle_threshold": 22,
"timezone": 22
}
Device Configuration Packet Parser
Parsed Output:
| Field | Value |
|---|