Line 176:
Line 176:
</pre>
</pre>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Device Info 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;
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; }
th, td { border: 1px solid #ccc; padding: 8px; text-align: left; }
th { background-color: #680022; color: white; }
</style>
</head>
<body>
<h2>Device Info Packet Parser</h2>
<textarea id="packetInput" placeholder="Paste 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(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 bitsToAscii(bits) {
return bits.match(/.{8}/g).map(b => String.fromCharCode(parseInt(b, 2))).join('').trim();
}
function parseImeiFromHex(hex, byteStart, byteEnd) {
const bcd = hex.slice(byteStart * 2, byteEnd * 2);
return bcd.replace(/f/gi, '').split('').join('');
}
function parsePacket() {
const hex = document.getElementById('packetInput').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);
};
// IMEI from hex BCD (7 to 14 = 8 bytes = 16 hex chars)
const imei = parseImeiFromHex(hex, 25, 75);
output("IMEI", imei);
const packetType = bitsToInt(bits.slice(75, 80));
output("Packet Type", packetType);
// Timestamp and timezone
const tsBits = bits.slice(80, 112);
const timezoneBits = bits.slice(112, 120);
const ts = bitsToInt(tsBits);
const timezoneRaw = bitsToSignedInt(timezoneBits);
const offsetMin = timezoneRaw * 15;
const sign = offsetMin >= 0 ? "+" : "-";
const h = Math.floor(Math.abs(offsetMin) / 60);
const m = Math.abs(offsetMin % 60);
const localDate = new Date((ts + offsetMin * 60) * 1000);
const localStr = localDate.toISOString().replace("T", " ").replace(".000Z", "");
output("DateTime (Epoch)", ts);
output("TimeZone", `${offsetMin} mins = UTC${sign}${h}:${m.toString().padStart(2, '0')}`);
output("DateTime (Local Time)", localStr);
// ASCII Fields
const asciiFields = [
["ICCID", 120, 279],
["VID", 280, 311],
["CMFV Name", 312, 351],
["CMFV Version", 352, 431],
["CMFV Build", 432, 471],
["MCUA Name", 472, 511],
["MCUA Version", 512, 591],
["MCUA Build", 592, 631],
["MCUB Name", 632, 671],
["MCUB Version", 672, 751],
["MCUB Build", 752, 791],
["VN", 792, 871],
["HWINFO", 872, 959]
];
for (const [label, start, end] of asciiFields) {
const value = bitsToAscii(bits.slice(start, end + 1));
output(label, value);
}
output("Error Code", 0);
}
</script>
</body>
</html>
<html lang="en">
<html lang="en">
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
Number of data packets
5
20–24
Number of packets (0–32)
0–32
IMEI
50
25–74
Unique device identifier
Packet type
5
75–79
Type of packet
00 - Device Info
Data
Time
32
UTC Timestamp
UTC time in seconds
Time Zone
8
Timezone in quarter-hours (e.g., 22 = +5:30), quarter-hour increment means each unit represents 15 minutes. The value 22 represents 22 quarter hours. Ranges from -48 to 56, negative timezone to 2's complement representation
eg: 22 (+5:30) → 22×15=330 minutes → 330÷60=5.5 hours → 5 hours and 30 minutes
ICCID
160
20 Bytes, Character string
8991000903297069053F
VID
32
4 Bytes, Character string
TRAN
CELLULAR_MODULE_FV NAME
40
5 Bytes, Character string
TSPJT
CELLULAR_MODULE_FV VERSION
80
10 Bytes, Character string
XX.YY.ZZZZ
CELLULAR_MODULE_FV BUILD NO
40
5 Bytes, Character string
YYDDD
MCU_APP_MODULE_FV NAME
40
5 Bytes, Character string
TSPJT
MCU_APP_MODULE_FV VERSION
80
10 Bytes, Character string
XX.YY.ZZZZ
MCU_APP_MODULE_FV BUILD NO
40
5 Bytes, Character string
YYDDD
MCU_BTL_MODULE_FV NAME
40
5 Bytes, Character string
TSPJT
MCU_BTL_MODULE_FV VERSION
80
10 Bytes, Character string
XX.YY.ZZZZ
MCU_BTL_MODULE_FV BUILD NO
40
5 Bytes, Character string
YYDDD
VN
80
10 Bytes, Character string
KL07CP8490
HWINFO
88
11 Bytes, Character string
PCB-0220-AB
Tail(2 Bytes)
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 : "2406e0e21aeb7abfd58068778b681638393931393530393132393633373932393833355452414e545344344720332e20302e202020342020202030545344345220332e20302e202020332020202030545344524220332e20302e202020312020202030585858585858585858585043422d303236312d41412ab9"
{"imei": 862942074896044,
"packet_type": 0, "no_packets": 1, "dateTime": 1752664936, "timezone": 22, "dateTime_tz": "2025-07-16 16:52:16", "iccid": "89919509129637929835", "vid": "TRAN", "cmfv_name": "TSD4G", "cmfv_version": " 3. 0. 4", "cmfv_build": " 0", "mcua_name": "TSD4R", "mcua_version": " 3. 0. 3", "mcua_build": " 0", "mcub_name": "TSDRB", "mcub_version": " 3. 0. 1", "mcub_build": " 0", "vn": "XXXXXXXXXX", "hwinfo_build": "PCB-0261-AA", "error_code": 0, "raw_data": }
Device Info Packet Parser
Device Info Packet Parser
Parse Packet
Parsed Output: