|
|
| (9 intermediate revisions by the same user not shown) |
| Line 1: |
Line 1: |
| <html lang="en">
| |
| <head>
| |
| <meta charset="UTF-8">
| |
| <title>Telemetry Packet Parser</title>
| |
| <style>
| |
| body { font-family: Arial, sans-serif; }
| |
| textarea { width: 100%; height: 100px; 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; text-align: left; }
| |
| th { background-color: #680022; color: white; }
| |
| </style>
| |
| </head>
| |
| <body>
| |
|
| |
|
| <h2>Telemetry Packet Parser</h2>
| |
| <textarea id="hexInput" placeholder="Paste packet here..."></textarea><br>
| |
| <button onclick="parseTelemetry()">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(byte =>
| |
| parseInt(byte, 16).toString(2).padStart(8, '0')).join('');
| |
| }
| |
|
| |
| 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 resultBody = document.querySelector("#resultTable tbody");
| |
| resultBody.innerHTML = "";
| |
|
| |
| if (!hex || !hex.startsWith("24")) {
| |
| alert("Invalid packet");
| |
| 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>
| |
| </body>
| |
| </html>
| |