2021-09-28 20:46:19 +02:00
|
|
|
#include <lsf_decode.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <base40.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <crc16.h>
|
|
|
|
#include <spdlog/spdlog.h>
|
|
|
|
|
|
|
|
bool M17CheckCRC(uint8_t* data, int len) {
|
|
|
|
// TODO: Implement
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* M17DataTypesTxt[4] = {
|
|
|
|
"Unknown",
|
|
|
|
"Data",
|
|
|
|
"Voice",
|
|
|
|
"Voice & Data"
|
|
|
|
};
|
|
|
|
|
|
|
|
const char* M17EncryptionTypesTxt[4] = {
|
|
|
|
"None",
|
|
|
|
"AES",
|
|
|
|
"Scrambler",
|
|
|
|
"Unknown"
|
|
|
|
};
|
|
|
|
|
|
|
|
M17LSF M17DecodeLSF(uint8_t* _lsf) {
|
|
|
|
M17LSF lsf;
|
|
|
|
|
|
|
|
// Extract CRC
|
|
|
|
lsf.rawCRC = 0;
|
|
|
|
for (int i = 0; i < 16; i++) {
|
2021-12-19 22:11:44 +01:00
|
|
|
lsf.rawCRC |= (((uint16_t)_lsf[(i + 48 + 48 + 16 + 112) / 8] >> (7 - (i % 8))) & 1) << (15 - i);
|
2021-09-28 20:46:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check CRC
|
|
|
|
mobilinkd::CRC16 crc16;
|
|
|
|
crc16.reset();
|
|
|
|
for (int i = 0; i < 28; i++) {
|
|
|
|
crc16(_lsf[i]);
|
|
|
|
}
|
|
|
|
if (crc16.get() != lsf.rawCRC) {
|
|
|
|
lsf.valid = false;
|
|
|
|
return lsf;
|
|
|
|
}
|
|
|
|
lsf.valid = true;
|
|
|
|
|
|
|
|
|
|
|
|
// Extract DST
|
|
|
|
lsf.rawDst = 0;
|
|
|
|
for (int i = 0; i < 48; i++) {
|
2021-12-19 22:11:44 +01:00
|
|
|
lsf.rawDst |= (((uint64_t)_lsf[i / 8] >> (7 - (i % 8))) & 1) << (47 - i);
|
2021-09-28 20:46:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Extract SRC
|
|
|
|
lsf.rawSrc = 0;
|
|
|
|
for (int i = 0; i < 48; i++) {
|
2021-12-19 22:11:44 +01:00
|
|
|
lsf.rawSrc |= (((uint64_t)_lsf[(i + 48) / 8] >> (7 - (i % 8))) & 1) << (47 - i);
|
2021-09-28 20:46:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Extract TYPE
|
|
|
|
lsf.rawType = 0;
|
|
|
|
for (int i = 0; i < 16; i++) {
|
2021-12-19 22:11:44 +01:00
|
|
|
lsf.rawType |= (((uint16_t)_lsf[(i + 48 + 48) / 8] >> (7 - (i % 8))) & 1) << (15 - i);
|
2021-09-28 20:46:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Extract META
|
|
|
|
memcpy(lsf.meta, &_lsf[14], 14);
|
|
|
|
|
|
|
|
// Decode DST
|
|
|
|
if (lsf.rawDst == 0) {
|
|
|
|
lsf.dst = "Invalid";
|
|
|
|
}
|
|
|
|
else if (lsf.rawDst <= 262143999999999) {
|
|
|
|
char buf[128];
|
|
|
|
decode_callsign_base40(lsf.rawDst, buf);
|
|
|
|
lsf.dst = buf;
|
|
|
|
}
|
|
|
|
else if (lsf.rawDst == 0xFFFFFFFFFFFF) {
|
|
|
|
lsf.dst = "Broadcast";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
char buf[128];
|
|
|
|
sprintf(buf, "%" PRIX64, lsf.rawDst);
|
|
|
|
lsf.dst = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decode SRC
|
|
|
|
if (lsf.rawSrc == 0 || lsf.rawSrc == 0xFFFFFFFFFFFF) {
|
|
|
|
lsf.src = "Invalid";
|
|
|
|
}
|
|
|
|
else if (lsf.rawSrc <= 262143999999999) {
|
|
|
|
char buf[128];
|
|
|
|
decode_callsign_base40(lsf.rawSrc, buf);
|
|
|
|
lsf.src = buf;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
char buf[128];
|
|
|
|
sprintf(buf, "%" PRIX64, lsf.rawSrc);
|
|
|
|
lsf.src = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decode TYPE
|
|
|
|
lsf.isStream = (lsf.rawType >> 0) & 0b1;
|
|
|
|
lsf.dataType = (M17DataType)((lsf.rawType >> 1) & 0b11);
|
|
|
|
lsf.encryptionType = (M17EncryptionType)((lsf.rawType >> 3) & 0b11);
|
|
|
|
lsf.encryptionSubType = (lsf.rawType >> 5) & 0b11;
|
|
|
|
lsf.channelAccessNum = (lsf.rawType >> 7) & 0b1111;
|
|
|
|
|
|
|
|
return lsf;
|
|
|
|
}
|