Telemetry Packet: Difference between revisions
No edit summary |
No edit summary |
||
| Line 191: | Line 191: | ||
</pre> | </pre> | ||
<html> | <html lang="en"> | ||
< | <head> | ||
<textarea id="hexInput" placeholder="Paste | <meta charset="UTF-8"> | ||
<title>Telemetry Packet Parser</title> | |||
<style> | |||
body { font-family: Arial, sans-serif; padding: 20px; } | |||
textarea { width: 100%; height: 100px; font-family: monospace; } | |||
button { | |||
padding: 10px 20px; | |||
margin-top: 10px; | |||
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; text-align: left; } | |||
th { background-color: #680022; color: white; } | |||
</style> | |||
</head> | |||
<body> | |||
<h2>Telemetry Packet Parser</h2> | |||
<textarea id="hexInput" placeholder="Paste HEX packet here..."></textarea><br> | |||
<button onclick="parseTelemetry()">Parse Packet</button> | <button onclick="parseTelemetry()">Parse Packet</button> | ||
<h3>Parsed Output:</h3> | |||
<table id="resultTable"> | <table id="resultTable"> | ||
<thead><tr><th>Field</th><th>Value</th></tr></thead> | <thead><tr><th>Field</th><th>Value</th></tr></thead> | ||
<tbody></tbody> | <tbody></tbody> | ||
</table> | </table> | ||
<script> | <script> | ||
function hexToBits(hex){return hex.match(/.{1,2}/g).map( | function hexToBits(hex) { | ||
function bitsToInt(bits){return parseInt(bits,2)} | return hex.match(/.{1,2}/g).map(byte => | ||
function bitsToSignedInt(bits){let | parseInt(byte, 16).toString(2).padStart(8, '0')).join(''); | ||
function | } | ||
function parseTelemetry(){ | |||
function bitsToInt(bits) { | |||
return parseInt(bits, 2); | |||
} | |||
function bitsToSignedInt(bits) { | |||
let value = parseInt(bits, 2); | |||
const max = Math.pow(2, bits.length); | |||
return value >= max / 2 ? value - max : value; | |||
} | |||
function bigIntFromBits(bits) { | |||
return BigInt('0b' + bits).toString(); | |||
} | |||
function parseTelemetry() { | |||
const hex = document.getElementById("hexInput").value.trim().toLowerCase(); | const hex = document.getElementById("hexInput").value.trim().toLowerCase(); | ||
const | const resultBody = document.querySelector("#resultTable tbody"); | ||
if(!hex.startsWith("24")) | resultBody.innerHTML = ""; | ||
const | |||
const | if (!hex || !hex.startsWith("24")) { | ||
alert("Invalid packet! Must start with '24'"); | |||
return; | |||
} | |||
const bits = hexToBits(hex); | |||
const output = (label, value) => { | |||
const row = document.createElement("tr"); | |||
row.innerHTML = `<td>${label}</td><td>${value}</td>`; | |||
resultBody.appendChild(row); | |||
}; | |||
const fields = [ | |||
["Start Byte", 0, 8], ["Data Length", 8, 20], ["No. of Packets", 20, 25], | |||
["IMEI", 25, 75], ["Packet Type", 75, 80], ["Packet Status", 80, 81], | |||
["Frame Number", 81, 97], ["Alert ID", 97, 102], ["Operator", 102, 106], | |||
["Signal Strength", 106, 111], ["MCC", 111, 121], ["MNC", 121, 131], | |||
["Cell ID", 131, 147], ["LAC", 147, 163], ["Fix Status", 163, 164], | |||
["Latitude", 164, 193], ["NS Indication", 193, 194], ["Longitude", 194, 223], | |||
["EW Indication", 223, 224], ["HDOP", 224, 234], ["PDOP", 234, 244], | |||
["Speed", 244, 259], ["Altitude", 259, 274], ["Power Status", 274, 275], | |||
["Ignition Status", 275, 276], ["Immobilizer Status", 276, 277], | |||
["Tamper", 277, 278], ["Supply Voltage", 278, 288], ["Internal Battery Voltage", 288, 294], | |||
["Fuel Sensor Status 1", 294, 295], ["Fuel Percentage 1", 295, 305], | |||
["Fuel Sensor Value 1", 305, 321], ["Fuel Sensor Status 2", 321, 322], | |||
["Fuel Percentage 2", 322, 332], ["Fuel Sensor Value 2", 332, 348], | |||
["Fuel Sensor Status 3", 348, 349], ["Fuel Percentage 3", 349, 359], | |||
["Fuel Sensor Value 3", 359, 375], ["Analog Input 1", 375, 385], | |||
["Analog Input 2", 385, 395], ["Digital Input 1", 395, 396], | |||
["Digital Input 2", 396, 397], ["Digital Output 1", 397, 398], | |||
["Digital Output 2", 398, 399], ["Temperature Sensor Status 1", 399, 400], | |||
["Temperature 1", 400, 412], ["Temperature Sensor Status 2", 412, 413], | |||
["Temperature 2", 413, 425], ["Temperature Sensor Status 3", 425, 426], | |||
["Temperature 3", 426, 438], ["Humidity", 438, 445], ["Odometer", 445, 480], | |||
["DateTime UTC", 480, 512], ["TimeZone", 512, 520] | |||
]; | |||
let tempDateTime = 0; | |||
for (const [label, start, end] of fields) { | |||
const val = bits.slice(start, end); | |||
switch (label) { | |||
case "IMEI": | |||
output(label, bigIntFromBits(val)); | |||
break; | |||
case "Latitude": | |||
case "Longitude": | |||
output(label, bitsToInt(val) / 1e6); | |||
break; | |||
case "HDOP": | |||
case "PDOP": | |||
output(label, bitsToInt(val) / 100); | |||
break; | |||
case "Speed": | |||
output(label, bitsToInt(val) / 100); | |||
break; | |||
case "Altitude": | |||
case "Supply Voltage": | |||
case "Internal Battery Voltage": | |||
case "Fuel Percentage 1": | |||
case "Fuel Percentage 2": | |||
case "Fuel Percentage 3": | |||
case "Analog Input 1": | |||
case "Analog Input 2": | |||
output(label, bitsToInt(val) / 10); | |||
break; | |||
case "Temperature 1": | |||
case "Temperature 2": | |||
case "Temperature 3": | |||
output(label, bitsToSignedInt(val) / 10); | |||
break; | |||
case "DateTime UTC": | |||
tempDateTime = bitsToInt(val); | |||
const utc = new Date(tempDateTime * 1000); | |||
output("DateTime (UTC)", utc.toISOString()); | |||
break; | |||
case "TimeZone": | |||
const tz = bitsToSignedInt(val); | |||
const offsetMin = tz * 15; | |||
const sign = offsetMin >= 0 ? "+" : "-"; | |||
const h = Math.floor(Math.abs(offsetMin) / 60); | |||
const m = Math.abs(offsetMin % 60); | |||
output("TimeZone", `${offsetMin} mins = UTC${sign}${h}:${m.toString().padStart(2, '0')}`); | |||
const localTime = new Date((tempDateTime + offsetMin * 60) * 1000); | |||
const formatted = localTime.toISOString().replace("T", " ").replace(".000Z", ""); | |||
output("DateTime (Local Time)", formatted); | |||
break; | |||
default: | |||
output(label, bitsToInt(val)); | |||
} | |||
} | |||
} | } | ||
</script> | </script> | ||
</body> | |||
</html> | </html> | ||
Revision as of 07:02, 16 July 2025
| Field | Size (bits) | Bit Range | Description | Breakdown |
|---|---|---|---|---|
| Header (10 bytes) | ||||
| Start byte | 8 | 0–7 | Starting character $ (ASCII value 36) | $ |
| Data length | 12 | 08–19 | 2-byte length of the data following the header | |
| Num of data packets | 5 | 20–24 | Number of packets (0–32) | 0–32 |
| IMEI | 50 | 25–74 | Unique device identifier | e.g., 887744556677882 |
| packet type | 5 | 75–79 | Integer type:
| |
| Data (= 55 bytes × number of packets) | ||||
| Packet Status | 1 | — | Type of packet | |
| Frame Number | 16 | — | Frame number | |
| AlertID | 8 | — | Alert identifier | |
| Operator | 4 | — | Network operator | 00-Airtel, 01-BSNL, 02-VI, 04-JIO |
| Signal Strength | 5 | — | Signal strength | Integer (0–31) |
| MCC | 10 | — | Mobile country code | Integer |
| MNC | 6 | — | Mobile network code | Integer |
| Cell Id | 16 | — | Cell tower ID | Integer |
| Location Area Code | 16 | — | Location area code | Integer |
| Fix_status | 1 | — | GPS fix status | 0: No fix, 1: Valid Fix |
| Start byte | 1 | — | Latitude coordinate | Divide by 1,000,000 for float value |
| NS_Indication | 1 | — | N or S | 0: N, 1: S |
| Longitude | 29 | — | Longitude coordinate | Divide by 1,000,000 for float value |
| EW_Indication | 1 | — | East/West Indication | 0: E, 1: W |
| HDOP | 10 | — | Horizontal dilution | Divide by 10 for float value |
| PDOP | 10 | — | Position dilution | Divide by 10 for float value |
| Speed | 10 | — | Speed in km/h | Divide by 10 for float value |
| Altitude | 15 | — | Altitude in meters | Divide by 10 for float value |
| Power Status | 1 | — | Power connection status | 0: Power disconnected, 1: Power connected |
| Ignition Status | 1 | — | Ignition status | 0: OFF, 1: ON |
| Immobilizer Status | 1 | — | Immobilizer status | 0: OFF, 1: ON |
| Tamper | 1 | — | Wire Tamper detection | 0: Tamper clear, 1: Tamper alert ON |
| Supply Voltage | 6 | — | External battery voltage | Divide by 10 for float value |
| Internal Battery Voltage | 6 | — | Internal battery voltage | Divide by 10 for float value |
| Fuel SensorValue 1 | 16 | — | Fuel sensor value | Divide by 10 if float |
| Fuel Percentage 1 | 16 | — | Fuel level percentage | Divide by 10 for float value |
| Fuel SensorValue 2 | 16 | — | Fuel sensor value | Divide by 10 if float |
| Fuel Percentage 2 | 16 | — | Fuel level percentage | Divide by 10 for float value |
| Fuel SensorValue 3 | 16 | — | Fuel sensor value | Divide by 10 if float |
| Fuel Percentage 3 | 16 | — | Fuel level percentage | Divide by 10 for float value |
| Analog Input | 10 | — | Analog input | Divide by 10 for float value |
| Analog Input 1 | 10 | — | Analog input 1 | Divide by 10 for float value |
| Digital Input 1 | 1 | — | Digital input 1 | 0 or 1 |
| Digital Input 2 | 1 | — | Digital input 2 | 0 or 1 |
| Digital Output 1 | 1 | — | Digital output 1 | 0 or 1 |
| Digital Output 2 | 1 | — | Digital output 2 | 0 or 1 |
| Temperature sensor status 1 | 1 | — | Status of temperature sensor 1 | 1 if connected, 0 if not connected |
| Temperature 1 | 12 | — | Temperature in °C | Signed, divide by 10 |
| Temperature sensor status 2 | 1 | — | Status of temperature sensor 2 | 1 if connected, 0 if not connected |
| Temperature 2 | 12 | — | Temperature in °C | Signed, divide by 10 |
| Temperature sensor status 3 | 1 | — | Status of temperature sensor 3 | 1 if connected, 0 if not connected |
| Temperature 3 | 12 | — | Temperature in °C | Signed, divide by 10 |
| Humidity | 8 | — | Humidity percentage | |
| Odometer | 35 | — | Odometer value in meters | |
| DateTime UTC | 32 | — | Timestamp | UTC time in seconds |
| TimeZone | 8 | — |
Timezone in quarter-hours (e.g., 22 = +5:30). Each unit = 15 mins. Value 22 = 22 × 15 mins = 330 mins = +5:30 Range: -48 to 56, 2's complement || | |
| Tail | ||||
| End Character | 8 | 0–7 | Starting character * (ASCII value 42) | * |
| CRC | 8 | 8–15 | 8-bit XOR CRC of data starting from $ to * (excluding $ and *) | |
Sample Packet
HEX "240370e2400e60e3ad81801b0cfaca0be02541c2000000000000000000000000000000009800000000000000000000000000000000000000000000006875e9e5162a05"
{
"imei": 864218069278060,
"packet_type": 1,
"no_packets": 1,
"packet_status": 1,
"frame_number": 54,
"alert_id": 3,
"operator": 3,
"signal_strength": 29,
"mcc": 404, "mnc": 95,
"cell_id": 298,
"lac": 3600,
"fix_status": 0,
"latitude": 0.0,
"latitude_dir": 0,
"longitude": 0.0,
"longitude_dir": 0,
"hdop": 0.0,
"pdop": 0.0,
"speed": 0.0,
"altitude": 0.0,
"power": 0,
"ignition": 0,
"immobilizer": 0,
"tamper": 0,
"supply_volatge": 0.0,
"internal_battery_volatge": 3.8,
"fuel_sensor_status_1": 0,
"fuel_percentage_1": 0.0,
"fuel_value_sensor_1": 0,
"fuel_sensor_status_2": 0,
"fuel_percentage_2": 0.0,
"fuel_value_sensor_2": 0,
"fuel_sensor_status_3": 0,
"fuel_percentage_3": 0.0,
"fuel_value_sensor_3": 0,
"analog_input1": 0.0,
"analog_input2": 0.0,
"digital_input1": 0,
"digital_input2": 0,
"digital_output1": 0,
"digital_output2": 0,
"temp_sensor_status_1": 0,
"temperature_1": 0.0,
"temp_sensor_status_2": 0,
"temperature_2": 0.0,
"temp_sensor_status_3": 0,
"temperature_3": 0.0,
"humidity": 0,
"odometer": 0,
"dateTime": 1752558053,
"timezone": 22,
"dateTime_tz": "2025-07-15 11:10:53",
"error_code": 0
}
Telemetry Packet Parser
Parsed Output:
| Field | Value |
|---|