Skip to content

Instantly share code, notes, and snippets.

@eurocat2k
Last active July 24, 2024 18:01
Show Gist options
  • Save eurocat2k/7aff787a1f300837e29e3bc36e072ab9 to your computer and use it in GitHub Desktop.
Save eurocat2k/7aff787a1f300837e29e3bc36e072ab9 to your computer and use it in GitHub Desktop.
I5N 6 bit character string - ASTERIX cat048, cat062,etc.. data fields encoded such method - encoding, decoding algorithms written in C.
/**
* @brief demonstrates ICAO 6-bit encoding, decoding strings
*/
int main(void) {
uint8_t id[8] = {'M', 'A', 'H', '6', '1', '0', ' ', ' '};
uint8_t decoded[8] = {0};
uint8_t encoded[6] = {0};
//
printf("chartab_size = %zu\n", chartab_size);
// encoding
encode_callsign(id, 8, encoded, 6);
printf("encoded:");
for (int i = 0; i < 6; i += 1) {
printf("%3.02x", encoded[i]);
}
printf("\n");
// decoding
decode_callsign(decoded, 6, encoded, 8);
printf("decoded:");
for (int i = 0; i < 8; i += 1) {
printf("%3.02x", decoded[i]);
}
printf("\n");
printf("decoded id: %.*s\n", 8, decoded);
//
return 0;
}
#include <stdio.h>
#include <stdint.h>
/**
* SixBit ASCII (used by AIS)[5] character table
* 0 1 2 3 4 5 6 7 8 9 A B C D E F
* ---------------------------------
* 0x | @ A B C D E F G H I J K L M N O
* 1x | P Q R S T U V W X Y Z [ \ ] ^ _
* 2x |SP ! " # $ % & ' ( ) * + , - . /
* 3x | 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
*/
static const uint8_t chartab[] = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ##### ###############0123456789######";
static const size_t chartab_size = sizeof(chartab) / sizeof(chartab[0]);
/**
* @brief returns the index of character in the chartab array
* @param ch the character to be indexed
* @return index if found, -1 otherwise
*/
int indexOf(int ch) {
int i = 0;
for (; i < chartab_size; i += 1) {
if (ch == chartab[i]) {
break;
}
}
if (chartab[i] == '#') {
return -1;
}
return i;
}
/**
* @desc encodes 8 bits ASCII string - with fixed 8 characters long (SPACE used for padding) -
* into 6 bits encoded AIS string.
* @param src the ASCII string 8 characters long - ALPHABETS and NUMBERS plus SPACE - the valid
* character inputs.
* @param slen the length of the input string - which shall be 8, 16, 32 (2^N where N >= 3) -
* but ICAO callsigns maximum 8 characters long by default.
* @param dst the pointer to the encoded string with fixed 6 or 12 or 24...etc, but because
* we are encoding ICAO callsigns with 8 characters long, therefore 6 octets is enough.
* @param dlen the encoed buffer size - 6 by thefault.
*/
void encode_callsign(const void *src, size_t slen, void *dst, size_t dlen) {
// no size check at this time, we assume that callsign is 8 characters long
// therefore the encoded buffer shall be 6 octets long...
// encoding
uint8_t *decoded = (uint8_t *)src;
uint8_t *encoded = (uint8_t *)dst;
// encoding
for (int i = 0, j = 0; i < 8; i += 4, j += 3) {
encoded[j] = ((indexOf(decoded[i]) << 2) | (indexOf(decoded[i + 1]) & 0x30) >> 4);
encoded[j + 1] = ((indexOf(decoded[i + 1]) & 0x0f) << 4 | (indexOf(decoded[i + 2]) & 0x3f) >> 2);
encoded[j + 2] = ((indexOf(decoded[i + 2]) & 0x03) << 6 | indexOf(decoded[i + 3]));
}
}
void decode_callsign(const void *src, size_t slen, void *dst, size_t dlen) {
uint8_t *decoded = (uint8_t *)dst;
uint8_t *encoded = (uint8_t *)src;
// decoding
for (int i = 0, j = 0; i < 6; i += 3, j += 4) {
decoded[j] = chartab[encoded[i] >> 2];
decoded[j + 1] = chartab[(encoded[i] & 0x3) << 4 | (encoded[i + 1] & 0xf0) >> 4];
decoded[j + 2] = chartab[(encoded[i + 1] & 0x0f) << 2 | (encoded[i + 2] & 0xC0) >> 6];
decoded[j + 3] = chartab[(encoded[i + 2] & 0x3f)];
}
}
@eurocat2k
Copy link
Author

eurocat2k commented Jul 24, 2024

I5N Character table

       0 1 2 3 4 5 6 7 8 9 A B C D E F
     +---------------------------------
 0x0 | @ A B C D E F G H I J K L M N O
 0x1 | P Q R S T U V W X Y Z [ \ ] ^ _
 0x2 |SP ! " # $ % & ' ( ) * + , - . /
 0x3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ?

Valid characters for ICAO decoding/encoding

       0 1 2 3 4 5 6 7 8 9 A B C D E F
     +---------------------------------
 0x0 | # A B C D E F G H I J K L M N O
 0x1 | P Q R S T U V W X Y Z # # # # #
 0x2 |SP # # # # # # # # # # # # # # #
 0x3 | 0 1 2 3 4 5 6 7 8 9 # # # # # #

'#' character represents invalid character

During encoding, the encoded 6 bit characters will refer to the ASCII code index in the chartab array.

However decoding will use the ASCII character in the chartab array at the given index - what the 6 bit encoded character defines.

Bit manipulation needed during both encoding and decoding the strings.

Encoding bitmanipulations

6 octets 6 bit encoded ASCII (8 char) string: AAAAAA BBBBBB CCCCCC DDDDDD EEEEEE .. HHHHHH - each represents an index value in hex
 1st octet         2nd octet         3rd octet         4th octet         5th octet         6th octet
7 6 5 4 3 2 1 0   7 6 5 4 3 2 1 0   7 6 5 4 3 2 1 0   7 6 5 4 3 2 1 0   7 6 5 4 3 2 1 0   7 6 5 4 3 2 1 0
---------------   ---------------   ---------------   ---------------   ---------------   ---------------
A A A A A A B B   B B B B C C C C   C C D D D D D D   E E E E E E F F   F F F F G G G G   G G H H H H H H

To obtain AAAAAA, we need to '>>' 2 right the first octet.
To obtain BBBBBB, we need to mask 1st octet with 0x3 then '<<' 4 then '|' with 2nd octet which masked with 0xf0 and '>>' 4
To obtain CCCCCC we need to mask 2nd octet with 0x0f, then '<<' 2 then '|' with 3rd octet which masked 0xc0 and '>>' 6.
To obtain DDDDDD we simply apply 0x3f on 3rd octet.

The next 4 octets - EEEEEE, FFFFFF, GGGGGG, HHHHHH - need to be processed as above.

Decoding bitmanipulations

During the decoding process the bitmanipulations are the same as above, however at this time we are going to
use these manipulations to identify the indexes in the encoded array which - in our case - has 6 octets.
To be able to get all 8 callsign characters we need to dissect the encoded octets using the same bit manipulations as before but now on the source buffer.

Example result

Callsign to be encoded: "MAH610  " - or as an array - [ 'M', 'A', 'H', '6', '1', '0', ' ', ' ' ]
encoded: 34 12 36 c7 08 20
decoded: 4d 41 48 36 31 30 20 20
decoded id: "MAH610  "

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