encoding CATS packets inline. Still need to support GPS and NodeInfo whiskers

pull/86/head
Stephen D 2024-03-06 23:43:46 -04:00
rodzic 1ee2710a57
commit 720afc2a92
16 zmienionych plików z 460 dodań i 9 usunięć

Wyświetl plik

@ -0,0 +1,34 @@
#include <stdint.h>
#include "cats.h"
#include "crc.h"
#include "whiten.h"
#include "ldpc.h"
#include "interleaver.h"
cats_packet cats_create(uint8_t *data)
{
cats_packet c = {.data = data, .len = 0};
return c;
}
// This makes changes to packet->data.
// Don't call it more than once, and don't use
// the packet after calling!
size_t cats_fully_encode(cats_packet packet, uint8_t *out)
{
// 0. CRC
int new_len = cats_append_crc(packet.data, packet.len);
// 1. whiten
cats_whiten(packet.data, new_len);
// 2. ldpc
new_len = cats_ldpc_encode(packet.data, new_len);
// 3. length
out[0] = new_len;
out[1] = new_len >> 8;
// 4. interleave
cats_interleave(out + 2, packet.data, new_len);
return new_len + 2;
}

Wyświetl plik

@ -0,0 +1,15 @@
#ifndef __CATS_H
#define __CATS_H
#include <stdint.h>
#include <stddef.h>
typedef struct _cats_packet {
uint8_t *data;
size_t len;
} cats_packet;
cats_packet cats_create(uint8_t *payload);
size_t cats_fully_encode(cats_packet packet, uint8_t *out);
#endif

Wyświetl plik

@ -0,0 +1,32 @@
#include "crc.h"
uint16_t calc_crc(uint8_t *data, size_t length);
size_t cats_append_crc(uint8_t *data, size_t len)
{
uint16_t crc = calc_crc(data, len);
data[len++] = crc;
data[len++] = crc >> 8;
return len;
}
// https://stackoverflow.com/questions/69850602/converting-c-to-java-for-crc16-ibm-sdlc
uint16_t calc_crc(uint8_t *data, size_t length)
{
uint8_t *ptr = data;
uint8_t crcbyte1 = 0xFF;
uint8_t crcbyte2 = 0xFF;
for (int i = 0; i < length; i++) {
uint8_t r1 = *ptr++ ^ crcbyte2;
r1 = (r1 << 4) ^ r1;
crcbyte2 = (r1 << 4) | (r1 >> 4);
crcbyte2 = (crcbyte2 & 0x0F ) ^ crcbyte1;
crcbyte1 = r1;
r1 = (r1 << 3) | (r1 >> 5);
crcbyte2 = crcbyte2 ^ (r1 & 0xF8);
crcbyte1 = crcbyte1 ^ (r1 & 0x07);
}
return ~((crcbyte1 << 8) | crcbyte2);
}

Wyświetl plik

@ -0,0 +1,9 @@
#ifndef __CATS_CRC_H
#define __CATS_CRC_H
#include <stdint.h>
#include <stddef.h>
size_t cats_append_crc(uint8_t *data, size_t len);
#endif

Wyświetl plik

@ -0,0 +1,45 @@
#include <stdbool.h>
#include "interleaver.h"
static inline bool get_bit(uint8_t *arr, size_t i);
static inline void set_bit(uint8_t *arr, size_t i, bool value);
void cats_interleave(uint8_t *dest, uint8_t *src, size_t len)
{
size_t bit_len = len * 8;
size_t out_i = 0;
for(int i = 0; i < 32; i++) {
for(int j = 0; j < bit_len; j += 32) {
if(i + j >= bit_len) {
continue;
}
set_bit(dest, out_i, get_bit(src, i + j));
out_i++;
}
}
}
static inline bool get_bit(uint8_t *arr, size_t i)
{
size_t byte_idx = i / 8;
int bit_idx = 7 - (i % 8);
return (arr[byte_idx] >> bit_idx) & 1;
}
static inline void set_bit(uint8_t *arr, size_t i, bool value)
{
size_t byte_idx = i / 8;
int bit_idx = 7 - (i % 8);
if(value) {
arr[byte_idx] |= 1 << bit_idx;
}
else {
arr[byte_idx] &= ~(1 << bit_idx);
}
}

Wyświetl plik

@ -0,0 +1,9 @@
#ifndef __CATS_INTERLEAVER_H
#define __CATS_INTERLEAVER_H
#include <stdint.h>
#include <stddef.h>
void cats_interleave(uint8_t *dest, uint8_t *src, size_t len);
#endif

Wyświetl plik

@ -0,0 +1,91 @@
#include <assert.h>
#include <string.h>
#include "ldpc.h"
#include "ldpc_matrices.h"
#define GET_BIT(byte, bit) (((byte) & (1 << (7-(bit)))) != 0)
#define SET_BIT(byte, bit) (byte |= 1 << 7-bit)
#define CLEAR_BIT(byte, bit) (byte &= ~(1 << 7-bit))
#define FLIP_BIT(byte, bit) (byte ^= (1 << (7 - bit)))
cats_ldpc_code_t *cats_ldpc_pick_code(int len)
{
if(128 <= len)
return &tm2048;
else if(32 <= len)
return &tc512;
else if(16 <= len)
return &tc256;
else
return &tc128;
}
// returns # of bytes written to parity_out
size_t cats_ldpc_encode_chunk(uint8_t *data, cats_ldpc_code_t *code, uint8_t *parity_out)
{
// Code parameters
int k = code->k;
int r = code->n - code->k;
int b = code->circulant_size;
const uint64_t* gc = code->matrix;
int rowLen = r/64;
memset(parity_out, 0x00, (code->k)/8);
for (int offset = 0; offset < b; offset++) {
for (int crow = 0; crow < k/b; crow++) {
int bit = crow*b + offset;
if(GET_BIT(data[bit/8], bit%8)) {
for (int idx = 0; idx < rowLen; idx++) {
uint64_t circ = gc[(crow*rowLen)+idx];
for(int j = 0; j < 8; j++) {
parity_out[idx*8 + j] ^= (uint8_t)(circ >> ((7 - j) * 8));
}
}
}
}
for (int block = 0; block < r/b; block++) {
uint8_t* parityblock = &parity_out[block*b/8];
uint8_t carry = parityblock[0] >> 7;
for (int x = (b/8)-1; x >= 0; x--) {
uint8_t c = parityblock[x] >> 7;
parityblock[x] = (parityblock[x] << 1) | carry;
carry = c;
}
}
}
return k / 8;
}
size_t cats_ldpc_encode(uint8_t *data, size_t len)
{
// Didn't implement the 512-byte LDPC variant - unnecessary and uses a lot of space
// This means we can only encode up to 511 bytes
assert(len < 512);
uint8_t parity[128];
// Split data into blocks and encode each block
int i = 0;
while(i < len) {
cats_ldpc_code_t *code = cats_ldpc_pick_code(len - i);
int k = code->k;
uint8_t chunk[code->n / 8];
memset(chunk, 0xAA, k/8);
memcpy(chunk, data + i, (len-i < k/8) ? (len-i) : (k/8));
size_t parity_len = cats_ldpc_encode_chunk(chunk, code, parity);
memcpy(data + len + i, parity, parity_len); // Parity
i += parity_len;
}
int new_len = (len*2) + (i-len) + 2; // (Data+Parity) + (Padded parity) + length
data[new_len - 2] = len;
data[new_len - 1] = len >> 8;
return new_len;
}

Wyświetl plik

@ -0,0 +1,9 @@
#ifndef __CATS_LDPC_H
#define __CATS_LDPC_H
#include <stdint.h>
#include <stddef.h>
size_t cats_ldpc_encode(uint8_t *data, size_t len);
#endif

Wyświetl plik

@ -0,0 +1,95 @@
#include <stdint.h>
#include <stdlib.h>
#include "ldpc_matrices.h"
cats_ldpc_code_t tc128 = {
.n = 128,
.k = 64,
.punctured_bits = 0,
.bf_working_len = 128 + 0,
.circulant_size = 128/8,
.matrix = tc128_matrix,
.matrix_len = 4
};
cats_ldpc_code_t tc256 = {
.n = 256,
.k = 128,
.punctured_bits = 0,
.bf_working_len = 256 + 0,
.circulant_size = 256/8,
.matrix = tc256_matrix,
.matrix_len = 8
};
cats_ldpc_code_t tc512 = {
.n = 512,
.k = 256,
.punctured_bits = 0,
.bf_working_len = 512 + 0,
.circulant_size = 512/8,
.matrix = tc512_matrix,
.matrix_len = 16
};
cats_ldpc_code_t tm2048 = {
.n = 2048,
.k = 1024,
.punctured_bits = 512,
.bf_working_len = 2048 + 512,
.circulant_size = 512/4,
.matrix = tm2048_matrix,
.matrix_len = 128
};
const uint64_t tc128_matrix[] = {
0x0E69166BEF4C0BC2, 0x7766137EBB248418, 0xC480FEB9CD53A713, 0x4EAA22FA465EEA11
};
const uint64_t tc256_matrix[] = {
0x73F5E8390220CE51, 0x36ED68E9F39EB162, 0xBAC812C0BCD24379, 0x4786D9285A09095C,
0x7DF83F76A5FF4C38, 0x8E6C0D4E025EB712, 0xBAA37B3260CB31C5, 0xD0F66A31FAF511BC
};
const uint64_t tc512_matrix[] = {
0x1D21794A22761FAE, 0x59945014257E130D, 0x74D6054003794014, 0x2DADEB9CA25EF12E,
0x60E0B6623C5CE512, 0x4D2C81ECC7F469AB, 0x20678DBFB7523ECE, 0x2B54B906A9DBE98C,
0xF6739BCF54273E77, 0x167BDA120C6C4774, 0x4C071EFF5E32A759, 0x3138670C095C39B5,
0x28706BD045300258, 0x2DAB85F05B9201D0, 0x8DFDEE2D9D84CA88, 0xB371FAE63A4EB07E
};
const uint64_t tm2048_matrix[] = {
0xCFA794F49FA5A0D8, 0x8BB31D8FCA7EA8BB, 0xA7AE7EE8A68580E3, 0xE922F9E13359B284,
0x91F72AE8F2D6BF78, 0x30A1F83B3CDBD463, 0xCE95C0EC1F609370, 0xD7E791C870229C1E,
0x71EF3FDF60E28784, 0x78934DB285DEC9DC, 0x0E95C103008B6BCD, 0xD2DAF85CAE732210,
0x8326EE83C1FBA56F, 0xDD15B2DDB31FE7F2, 0x3BA0BB43F83C67BD, 0xA1F6AEE46AEF4E62,
0x565083780CA89ACA, 0xA70CCFB4A888AE35, 0x1210FAD0EC9602CC, 0x8C96B0A86D3996A3,
0xC0B07FDDA73454C2, 0x5295F72BD5004E80, 0xACCF973FC30261C9, 0x90525AA0CBA006BD,
0x9F079F09A405F7F8, 0x7AD98429096F2A7E, 0xEB8C9B13B84C06E4, 0x2843A47689A9C528,
0xDAAA1A175F598DCF, 0xDBAD426CA43AD479, 0x1BA78326E75F38EB, 0x6ED09A45303A6425,
0x48F42033B7B9A051, 0x49DC839C90291E98, 0x9B2CEBE50A7C2C26, 0x4FC6E7D674063589,
0xF5B6DEAEBF72106B, 0xA9E6676564C17134, 0x6D5954558D235191, 0x50AAF88D7008E634,
0x1FA962FBAB864A5F, 0x867C9D6CF4E087AA, 0x5D7AA674BA4B1D8C, 0xD7AE9186F1D3B23B,
0x047F112791EE97B6, 0x3FB7B58FF3B94E95, 0x93BE39A6365C66B8, 0x77AD316965A72F5B,
0x1B58F88E49C00DC6, 0xB35855BFF228A088, 0x5C8ED47B61EEC66B, 0x5004FB6E65CBECF3,
0x77789998FE80925E, 0x0237F570E04C5F5B, 0xED677661EB7FC382, 0x5AB5D5D968C0808C,
0x2BDB828B19593F41, 0x671B8D0D41DF136C, 0xCB47553C9B3F0EA0, 0x16CC1554C35E6A7D,
0x97587FEA91D2098E, 0x126EA73CC78658A6, 0xADE19711208186CA, 0x95C7417A15690C45,
0xBE9C169D889339D9, 0x654C976A85CFD9F7, 0x47C4148E3B4712DA, 0xA3BAD1AD71873D3A,
0x1CD630C342C5EBB9, 0x183ADE9BEF294E8E, 0x7014C077A5F96F75, 0xBE566C866964D01C,
0xE72AC43A35AD2166, 0x72EBB3259B77F9BB, 0x18DA8B09194FA1F0, 0xE876A080C9D6A39F,
0x809B168A3D88E8E9, 0x3D995CE5232C2DC2, 0xC7CFA44A363F628A, 0x668D46C398CAF96F,
0xD57DBB24AE27ACA1, 0x716F8EA1B8AA1086, 0x7B7796F4A86F1FD5, 0x4C7576AD01C68953,
0xE75BE79902448236, 0x8F069658F7AAAFB0, 0x975F3AF795E78D25, 0x5871C71B4F4B77F6,
0x65CD9C359BB2A82D, 0x5353E007166BDD41, 0x2C5447314DB027B1, 0x0B130071AD0398D1,
0xDE19BC7A6BBCF6A0, 0xFF021AABF12920A5, 0x58BAED484AF89E29, 0xD4DBC170CEF1D369,
0x4C330B2D11E15B5C, 0xB3815E09605338A6, 0x75E3D1A3541E0E28, 0x4F6556D68D3C8A9E,
0xE5BB3B297DB62CD2, 0x907F09996967A0F4, 0xFF33AEEE2C8A4A52, 0xFCCF5C39D355C39C,
0x5FE5F09ABA6BCCE0, 0x2A73401E5F87EAC2, 0xD75702F4F57670DF, 0xA70B1C002F523EEA,
0x6CE1CE2E05D420CB, 0x867EC0166B8E53A9, 0x9DF9801A1C33058D, 0xD116A0AE7278BBB9,
0x4CF0B0C792DD8FDB, 0x3ECEAE6F2B7F663D, 0x106A1C296E47C14C, 0x1498B045D57DEFB5,
0x968F6D8C790263C3, 0x53CF307EF90C1F21, 0x66E6B632F6614E58, 0x267EF096C37718A3,
0x3D46E5D10E993EB6, 0xDF81518F885EDA1B, 0x6FF518FD48BB8E9D, 0xDBED4AC0F4F5EB89,
0xBCC64D21A65DB379, 0xABE2E4DC21F109FF, 0x2EC0CE7B5D40973D, 0x13ECF713B01C6F10
};

Wyświetl plik

@ -0,0 +1,26 @@
#ifndef __CATS_LDPC_MATRICES_H
#define __CATS_LDPC_MATRICES_H
typedef struct cats_ldpc_code {
// Code length (data+parity)
int n;
// Data length in bits
int k;
int punctured_bits;
int bf_working_len;
size_t circulant_size;
size_t matrix_len;
const uint64_t* matrix;
} cats_ldpc_code_t;
extern cats_ldpc_code_t tc128;
extern cats_ldpc_code_t tc256;
extern cats_ldpc_code_t tc512;
extern cats_ldpc_code_t tm2048;
extern const uint64_t tc128_matrix[];
extern const uint64_t tc256_matrix[];
extern const uint64_t tc512_matrix[];
extern const uint64_t tm2048_matrix[];
#endif

Wyświetl plik

@ -0,0 +1,26 @@
#include <string.h>
#include <assert.h>
#include "whisker.h"
void cats_append_identification_whisker(cats_packet *packet, char *callsign, uint8_t ssid, uint16_t icon)
{
packet->data[packet->len++] = 0x00; // type = identidication
size_t callsign_len = strlen(callsign);
packet->data[packet->len++] = callsign_len + 3; // len
packet->data[packet->len++] = icon & 0xFF; // icon
packet->data[packet->len++] = (icon >> 8) & 0xFF; // icon
memcpy(packet->data + packet->len, callsign, callsign_len); //callsign
packet->len += callsign_len;
packet->data[packet->len++] = ssid; // ssid
}
void cats_append_comment_whisker(cats_packet *packet, char *comment)
{
packet->data[packet->len++] = 0x03; // type = comment
size_t comment_len = strlen(comment);
assert(comment_len <= 255);
packet->data[packet->len++] = comment_len;
memcpy(packet->data + packet->len, comment, comment_len);
packet->len += comment_len;
}

Wyświetl plik

@ -0,0 +1,11 @@
#ifndef __WHISKER_H
#define __WHISKER_H
#include <stdint.h>
#include "cats.h"
void cats_append_identification_whisker(cats_packet *packet, char *callsign, uint8_t ssid, uint16_t icon);
void cats_append_comment_whisker(cats_packet *packet, char *message);
#endif

Wyświetl plik

@ -0,0 +1,36 @@
#include <stdbool.h>
#include "whiten.h"
uint8_t lfsr_byte(uint16_t *state);
void lfsr(uint16_t *state);
void cats_whiten(uint8_t *data, uint8_t len)
{
uint16_t state = 0xE9CF;
for(int i = 0; i < len; i++) {
uint8_t b = lfsr_byte(&state);
data[i] ^= b;
}
}
uint8_t lfsr_byte(uint16_t *state)
{
uint8_t out = 0;
for(int i = 7; i >= 0; i--) {
out |= (*state & 1) << i;
lfsr(state);
}
return out;
}
void lfsr(uint16_t *state)
{
bool lsb = *state & 1;
*state >>= 1;
if(lsb) {
*state ^= 0xB400;
}
}

Wyświetl plik

@ -0,0 +1,9 @@
#ifndef __CATS_WHITEN_H
#define __CATS_WHITEN_H
#include <stddef.h>
#include <stdint.h>
void cats_whiten(uint8_t *data, uint8_t len);
#endif

Wyświetl plik

@ -342,8 +342,8 @@
* CATS mode settings
*/
#define CATS_CALLSIGN CALLSIGN
#define CATS_SSID 0
#define CATS_ICON 0
#define CATS_SSID 24
#define CATS_ICON 8237
#define CATS_COMMENT "I am a radiosonde. Hear me meow!"
// Schedule transmission every N seconds, counting from beginning of an hour (based on GPS time). Set to zero to disable time sync.

Wyświetl plik

@ -1,9 +1,12 @@
#include <stdint.h>
#include <stdlib.h>
#include "config.h"
#include "telemetry.h"
#include "payload.h"
#include "log.h"
#include "codecs/cats/cats.h"
#include "codecs/cats/whisker.h"
#define CATS_PREAMBLE_BYTE 0x55
#define CATS_PREAMBLE_LENGTH 4
@ -20,19 +23,20 @@ uint16_t radio_cats_encode(uint8_t *payload, uint16_t length, telemetry_data *te
}
// sync word
// TODO can clean this up!
for(int i = 0; i < CATS_SYNC_WORD_LENGTH; i++) {
int j = CATS_SYNC_WORD_LENGTH - i - 1;
*(cur++) = (CATS_SYNC_WORD & (0xFF << (j * 8))) >> (j * 8);
}
// data - todo fix this
uint8_t msg[] = {140, 0, 163, 12, 172, 77, 255, 254, 201, 107, 102, 245, 143, 108, 185, 202, 207, 194, 243, 54, 138, 46, 62, 36, 41, 70, 203, 43, 32, 76, 254, 214, 159, 124, 132, 48, 135, 189, 2, 147, 188, 229, 24, 195, 194, 177, 162, 193, 105, 140, 31, 11, 51, 214, 51, 206, 150, 112, 105, 73, 234, 161, 46, 10, 93, 79, 68, 145, 150, 25, 185, 46, 166, 86, 190, 116, 218, 236, 204, 161, 28, 57, 3, 1, 46, 90, 207, 253, 69, 133, 62, 36, 173, 20, 220, 49, 12, 222, 0, 251, 73, 46, 57, 188, 62, 122, 142, 35, 144, 187, 27, 215, 75, 128, 189, 147, 76, 41, 53, 203, 30, 234, 222, 52, 73, 206, 209, 233, 81, 173, 58, 179, 194, 172, 207, 220, 169, 32, 24, 196, 40, 44};
uint8_t *data = malloc(length);
cats_packet packet = cats_create(data);
cats_append_identification_whisker(&packet, CATS_CALLSIGN, CATS_SSID, CATS_ICON);
cats_append_comment_whisker(&packet, message);
int len = cats_fully_encode(packet, cur);
free(data);
for(int i = 0; i < sizeof(msg); i++) {
(*cur++) = msg[i];
}
return (uint16_t)(cur - payload);
return (uint16_t)(CATS_PREAMBLE_LENGTH + CATS_SYNC_WORD_LENGTH + len);
}
payload_encoder radio_cats_payload_encoder = {