Skip to content

Instantly share code, notes, and snippets.

@eurocat2k
Last active November 23, 2023 12:11
Show Gist options
  • Save eurocat2k/5e4e4199a1ede407aeb4e21e43bef949 to your computer and use it in GitHub Desktop.
Save eurocat2k/5e4e4199a1ede407aeb4e21e43bef949 to your computer and use it in GitHub Desktop.
I5N six bit encoded message decoder in JS
// An Asterix cat48 data from a PCAP file
// 0000 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
// 0010 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
// 0020 .. .. .. .. .. .. .. .. .. .. 30 00 1f fd c1 02
// 0030 16 0d 6f 4c 75 a8 45 9c 28 c3 0f 93 06 18 4d 24
// 0040 60 5d a6 b1 e3 48 20 00 fd
// in case we would like to use static code table - ignored characters replaced by hashtag
let sixbitstable = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ##### ###############0123456789######";
// the 6 bit encoded aircraft ID can be found in the line
// 0040 .. 5d a6 b1 e3 48 20 .. ..
let enc = [0x5d, 0xa6, 0xb1, 0xe3, 0x48, 0x20 ];
let alen = enc.length;
let output = [];
let isStatic = false;
// decode
for (let i = 0, j = 0; i < alen; i += 3) {
// first sextet from a triple octets represents first octet of the quad word
// - first of second part of the 8 octets length aircraft ID
let v0 = enc[i] >> 2;
// second second sextet encodes second character of the first or second quad word
let v1 = ((enc[i] & 0x03) << 4) | (enc[i + 1] >> 4);
// third sectet encodes third character of the first or second quad word
let v2 = ((enc[i + 1] & 0x0f) << 2) | (enc[i + 2] >> 6);
// fourth sectet encodes third character of the first or second quad word
let v3 = (enc[i + 2] & 0x3f);
//
if (isStatic) {
// short form
console.log({v0: sixbitstable[v0], v1: sixbitstable[v1], v2: sixbitstable[v2], v3: sixbitstable[v3]});
output[j] = sixbitstable[v0]; j += 1;
output[j] = sixbitstable[v1]; j += 1;
output[j] = sixbitstable[v2]; j += 1;
output[j] = sixbitstable[v3]; j += 1;
} else {
// descriptive form
if (v0 >= 1 && v0 <= 26) { // if sextet value is in range 1..26 (inclusively) - they are A-Z characters
v0 = String.fromCharCode(v0 + 64); // therefore we need to add 64 to each to obtain ASCII codes
} else if (v0 >= 48 && v0 <= 57) { // if sectet is in range 48..57, they are ASCII numbers, leave them
v0 = String.fromCharCode(v0);
} else if (v0 == 32) { // if sectet equals to 32, it is ASCII SPACE, leave it
v0 = String.fromCharCode(v0);
} else {
v0 = '#';
}
output[j] = v0; j += 1;
if (v1 >= 1 && v1 <= 26) {
v1 = String.fromCharCode(v1 + 64);
} else if (v1 >= 48 && v1 <= 57) {
v1 = String.fromCharCode(v1);
} else if (v1 == 32) {
v1 = String.fromCharCode(v1);
} else {
v1 = '#';
}
output[j] = v1; j += 1;
if (v2 >= 1 && v2 <= 26) {
v2 = String.fromCharCode(v2 + 64);
} else if (v2 >= 48 && v2 <= 57) {
v2 = String.fromCharCode(v2);
} else if (v2 == 32) {
v2 = String.fromCharCode(v2);
} else {
v2 = '#';
}
output[j] = v2; j += 1;
if (v3 >= 1 && v3 <= 26) {
v3 = String.fromCharCode(v3 + 64);
} else if (v3 >= 48 && v3 <= 57) {
v3 = String.fromCharCode(v3);
} else if (v3 == 32) {
v3 = String.fromCharCode(v3);
} else {
v3 = '#';
}
output[j] = v3; j += 1;
console.log({v0, v1, v2, v3, output: output.join('')});
}
// print out
}
// print the output only
console.log({aircraft_Id: output.join('')});
console.log({
decodedLen: output.length,
decodedBits: output.length * 8,
extrabits: output.length * 2,
encodedbits: ((output.length * 8) - (output.length * 2)),
encodedLength: (((output.length * 8) - (output.length * 2)) / 8)
});
// encode
let decodedLen, decodedBits, extrabits, encodedbits, encodedLength, encoded, tmp, input;
decodedLen = output.length;
decodedBits = output.length * 8;
extrabits = output.length * 2;
encodedbits = ((output.length * 8) - (output.length * 2));
encodedLength = (((output.length * 8) - (output.length * 2)) / 8);
encoded = [], tmp = Array(3);
input = output.join('');
for (let i = 0, j = 0; i < decodedLen; i += 4) {
let t0, t1, t2, t3;
t0 = sixbitstable.indexOf(input[j+i]);
t1 = sixbitstable.indexOf(input[j+1+i]);
t2 = sixbitstable.indexOf(input[j+2+i]);
t3 = sixbitstable.indexOf(input[j+3+i]);
// pack into six bits
tmp[0] = t0 << 2;
tmp[0] |= t1 >> 4
tmp[1] = (t1 & 0x0f) << 4;
tmp[1] |= t2 >> 2;
tmp[2] = (t2 & 0x0f) << 4;
tmp[2] |= t3;
encoded = encoded.concat(tmp);
console.log({t0:`0x${t0.toString(16)}`, t1:`0x${t1.toString(16)}`, t2:`0x${t2.toString(16)}`, t3: `0x${t3.toString(16)}`, tmp: tmp.map(e => `0x${e.toString(16)}`)});
}
console.log({
decodedLen: output.length,
decodedBits: output.length * 8,
extrabits: output.length * 2,
encodedbits: ((output.length * 8) - (output.length * 2)),
encodedLength: (((output.length * 8) - (output.length * 2)) / 8),
encoded: encoded.map(e => `0x${e.toString(16)}`),
tmp: tmp.map(e => `0x${e.toString(16)}`)
});
@eurocat2k
Copy link
Author

eurocat2k commented Nov 22, 2023

Simple way(s) to decode 6 bit encoded aircraft ID from ADSB or Asterix CAT048 radar data message.

We can use static method - using sixbittable - slightly straight forward, or the if,else if,else method. Latter describes the decoding well.

We would expect the following output:

[Running] node "/home/system/src/PKGS/i5n/src/i5n.js"
{ v0: 'W', v1: 'Z', v2: 'Z', v3: '1', output: 'WZZ1' }
{ v0: '8', v1: '4', v2: ' ', v3: ' ', output: 'WZZ184  ' }
{ aircraft_Id: 'WZZ184  ' }
{
  decodedLen: 8,
  decodedBits: 64,
  extrabits: 16,
  encodedbits: 48,
  encodedLength: 6
}
{
  t0: '0x17',
  t1: '0x1a',
  t2: '0x1a',
  t3: '0x31',
  tmp: [ '0x5d', '0xa6', '0xb1' ]
}
{
  t0: '0x38',
  t1: '0x34',
  t2: '0x20',
  t3: '0x20',
  tmp: [ '0xe3', '0x48', '0x20' ]
}
{
  decodedLen: 8,
  decodedBits: 64,
  extrabits: 16,
  encodedbits: 48,
  encodedLength: 6,
  encoded: [ '0x5d', '0xa6', '0xb1', '0xe3', '0x48', '0x20' ],
  tmp: [ '0xe3', '0x48', '0x20' ]
}

[Done] exited with code=0 in 0.057 seconds

or WZZ184 as callsign and its 6 bits encoded octets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment