This project is a collection of former (and some new) projects connected together to make an APRS digipeater, which doubles as an APRS weather station, with PE1RXF telemetry server capabilities.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

696 lines
29 KiB

10 months ago
#include <string.h>
#include <ctype.h>
#include "LLP.h"
#include "protocol/HDLC.h"
#include "util/CRC-CCIT.h"
#include "../hardware/AFSK.h"
#define DISABLE_INTERLEAVE false
#define PASSALL false
#define STRIP_HEADERS true
// The GET_BIT macro is used in the interleaver
// and deinterleaver to access single bits of a
// byte.
inline bool GET_BIT(uint8_t byte, int n) { return (byte & (1 << (8-n))) == (1 << (8-n)); }
// We need an indicator to tell us whether we
// should send a parity byte. This happens
// whenever two normal bytes of data has been
// sent. We also keep the last sent byte in
// memory because we need it to calculate the
// parity byte.
static bool sendParityBlock = false;
static uint8_t lastByte = 0x00;
LLPAddress broadcast_address;
void llp_decode(LLPCtx *ctx) {
if (ctx->hook) {
size_t length = ctx->frame_len;
uint8_t *buffer = (uint8_t*)&ctx->buf;
size_t padding = buffer[LLP_HEADER_SIZE-1];
size_t address_size = 2*sizeof(LLPAddress);
#if STRIP_HEADERS
uint8_t strip_headers = 1;
#else
uint8_t strip_headers = 0;
#endif
size_t subtraction = (address_size + (LLP_HEADER_SIZE - address_size))*strip_headers + padding;
ctx->frame_len = length - subtraction - LLP_CHECKSUM_SIZE;
for (int i = 0; i < ctx->frame_len; i++) {
#if STRIP_HEADERS
buffer[i] = buffer[i+subtraction];
#else
if ( i >= LLP_HEADER_SIZE ) {
buffer[i] = buffer[i+padding];
} else {
buffer[i] = buffer[i];
}
#endif
}
ctx->hook(ctx);
}
}
void llp_poll(LLPCtx *ctx) {
int c;
#if DISABLE_INTERLEAVE
while ((c = fgetc(ctx->ch)) != EOF) {
if (!ctx->escape && c == HDLC_FLAG) {
if (ctx->frame_len >= LLP_MIN_FRAME_LENGTH) {
if (PASSALL || ctx->crc_in == LLP_CRC_CORRECT) {
#if OPEN_SQUELCH == true
LED_RX_ON();
#endif
llp_decode(ctx);
}
}
ctx->sync = true;
ctx->crc_in = CRC_CCIT_INIT_VAL;
ctx->frame_len = 0;
continue;
}
if (!ctx->escape && c == HDLC_RESET) {
ctx->sync = false;
continue;
}
if (!ctx->escape && c == LLP_ESC) {
ctx->escape = true;
continue;
}
if (ctx->sync) {
if (ctx->frame_len < LLP_MAX_FRAME_LENGTH) {
ctx->buf[ctx->frame_len++] = c;
ctx->crc_in = update_crc_ccit(c, ctx->crc_in);
} else {
ctx->sync = false;
}
}
ctx->escape = false;
}
#else
while ((c = fgetc(ctx->ch)) != EOF) {
/////////////////////////////////////////////
// Start of forward error correction block //
/////////////////////////////////////////////
if ((ctx->sync && (c != LLP_ESC )) || (ctx->sync && (ctx->escape && (c == LLP_ESC || c == HDLC_FLAG || c == HDLC_RESET)))) {
// We have a byte, increment our read counter
ctx->readLength++;
// Check if we have read 12 bytes. If we
// have, we should now have a block of two
// data bytes and a parity byte. This block
if (ctx->readLength % LLP_INTERLEAVE_SIZE == 0) {
// If the last character in the block
// looks like a control character, we
// need to set the escape indicator to
// false, since the next byte will be
// read immediately after the FEC
// routine, and thus, the normal reading
// code will not reset the indicator.
if (c == LLP_ESC || c == HDLC_FLAG || c == HDLC_RESET) ctx->escape = false;
// The block is interleaved, so we will
// first put the received bytes in the
// deinterleaving buffer
for (int i = 1; i < LLP_INTERLEAVE_SIZE; i++) {
ctx->interleaveIn[i-1] = ctx->buf[ctx->frame_len-(LLP_INTERLEAVE_SIZE-i)];
}
ctx->interleaveIn[LLP_INTERLEAVE_SIZE-1] = c;
// We then deinterleave the block
llpDeinterleave(ctx);
// Adjust the packet length, since we will get
// parity bytes in the data buffer with block
// sizes larger than 3
ctx->frame_len -= LLP_INTERLEAVE_SIZE/3 - 1;
// For each 3-byte block in the deinterleaved
// bytes, we apply forward error correction
for (int i = 0; i < LLP_INTERLEAVE_SIZE; i+=3) {
// We now calculate a parity byte on the
// received data.
// Deinterleaved data bytes
uint8_t a = ctx->interleaveIn[i];
uint8_t b = ctx->interleaveIn[i+1];
// Deinterleaved parity byte
uint8_t p = ctx->interleaveIn[i+2];
ctx->calculatedParity = llpParityBlock(a, b);
// By XORing the calculated parity byte
// with the received parity byte, we get
// what is called the "syndrome". This
// number will tell us if we had any
// errors during transmission, and if so
// where they are. Using Hamming code, we
// can only detect single bit errors in a
// byte though, which is why we interleave
// the data, since most errors will usually
// occur in bursts of more than one bit.
// With 2 data byte interleaving we can
// correct 2 consecutive bit errors.
uint8_t syndrome = ctx->calculatedParity ^ p;
if (syndrome == 0x00) {
// If the syndrome equals 0, we either
// don't have any errors, or the error
// is unrecoverable, so we don't do
// anything
} else {
// If the syndrome is not equal to 0,
// there is a problem, and we will try
// to correct it. We first need to split
// the syndrome byte up into the two
// actual syndrome numbers, one for
// each data byte.
uint8_t syndromes[2];
syndromes[0] = syndrome & 0x0f;
syndromes[1] = (syndrome & 0xf0) >> 4;
// Then we look at each syndrome number
// to determine what bit in the data
// bytes to correct.
for (int i = 0; i < 2; i++) {
uint8_t s = syndromes[i];
uint8_t correction = 0x00;
if (s == 1 || s == 2 || s == 4 || s == 8) {
// This signifies an error in the
// parity block, so we actually
// don't need any correction
continue;
}
// The following determines what
// bit to correct according to
// the syndrome value.
if (s == 3) correction = 0x01;
if (s == 5) correction = 0x02;
if (s == 6) correction = 0x04;
if (s == 7) correction = 0x08;
if (s == 9) correction = 0x10;
if (s == 10) correction = 0x20;
if (s == 11) correction = 0x40;
if (s == 12) correction = 0x80;
// And finally we apply the correction
if (i == 1) a ^= correction;
if (i == 0) b ^= correction;
// This is just for testing purposes.
// Nice to know when corrections were
// actually made.
if (s != 0) ctx->correctionsMade += 1;
}
}
// We now update the checksum of the packet
// with the deinterleaved and possibly
// corrected bytes.
ctx->crc_in = update_crc_ccit(a, ctx->crc_in);
ctx->crc_in = update_crc_ccit(b, ctx->crc_in);
ctx->buf[ctx->frame_len-(LLP_DATA_BLOCK_SIZE)+((i/3)*2)] = a;
ctx->buf[ctx->frame_len-(LLP_DATA_BLOCK_SIZE-1)+((i/3)*2)] = b;
}
continue;
}
}
/////////////////////////////////////////////
// End of forward error correction block //
/////////////////////////////////////////////
if (!ctx->escape && c == HDLC_FLAG) {
if (ctx->frame_len >= LLP_MIN_FRAME_LENGTH) {
if (PASSALL || ctx->crc_in == LLP_CRC_CORRECT) {
#if OPEN_SQUELCH == true
LED_RX_ON();
#endif
llp_decode(ctx);
}
}
ctx->sync = true;
ctx->crc_in = CRC_CCIT_INIT_VAL;
ctx->frame_len = 0;
ctx->readLength = 0;
ctx->correctionsMade = 0;
continue;
}
if (!ctx->escape && c == HDLC_RESET) {
ctx->sync = false;
continue;
}
if (!ctx->escape && c == LLP_ESC) {
ctx->escape = true;
continue;
}
if (ctx->sync) {
if (ctx->frame_len < LLP_MAX_FRAME_LENGTH) {
ctx->buf[ctx->frame_len++] = c;
} else {
ctx->sync = false;
}
}
ctx->escape = false;
}
#endif
}
static void llp_putchar(LLPCtx *ctx, uint8_t c) {
if (c == HDLC_FLAG || c == HDLC_RESET || c == LLP_ESC) fputc(LLP_ESC, ctx->ch);
fputc(c, ctx->ch);
}
static void llp_sendchar(LLPCtx *ctx, uint8_t c) {
llpInterleave(ctx, c);
ctx->crc_out = update_crc_ccit(c, ctx->crc_out);
if (sendParityBlock) {
uint8_t p = llpParityBlock(lastByte, c);
llpInterleave(ctx, p);
}
lastByte = c;
sendParityBlock ^= true;
}
void llp_sendaddress(LLPCtx *ctx, LLPAddress *address) {
llp_sendchar(ctx, address->network >> 8);
llp_sendchar(ctx, address->network & 0xff);
llp_sendchar(ctx, address->host >> 8);
llp_sendchar(ctx, address->host & 0xff);
}
void llp_broadcast(LLPCtx *ctx, const void *_buf, size_t len) {
llp_send(ctx, &broadcast_address, _buf, len);
}
void llp_send(LLPCtx *ctx, LLPAddress *dst, const void *_buf, size_t len) {
ctx->ready_for_data = false;
ctx->interleaveCounter = 0;
ctx->crc_out = CRC_CCIT_INIT_VAL;
uint8_t *buffer = (uint8_t*)_buf;
LLPHeader header;
memset(&header, 0, sizeof(header));
LLPAddress *localAddress = ctx->address;
header.src.network = localAddress->network;
header.src.host = localAddress->host;
header.dst.network = dst->network;
header.dst.host = dst->host;
header.flags = 0x00;
header.padding = (len + LLP_HEADER_SIZE + LLP_CRC_SIZE) % LLP_DATA_BLOCK_SIZE;
if (header.padding != 0) {
header.padding = LLP_DATA_BLOCK_SIZE - header.padding;
}
// Transmit the HDLC_FLAG to signify start of TX
fputc(HDLC_FLAG, ctx->ch);
// Transmit source & destination addresses
llp_sendaddress(ctx, &header.src);
llp_sendaddress(ctx, &header.dst);
// Transmit header flags & padding count
llp_sendchar(ctx, header.flags);
llp_sendchar(ctx, header.padding);
// Transmit padding
while (header.padding--) {
llp_sendchar(ctx, 0x00);
}
// Transmit payload
while (len--) {
llp_sendchar(ctx, *buffer++);
}
// Send CRC checksum
uint8_t crcl = (ctx->crc_out & 0xff) ^ 0xff;
uint8_t crch = (ctx->crc_out >> 8) ^ 0xff;
llp_sendchar(ctx, crcl);
llp_sendchar(ctx, crch);
// And transmit a HDLC_FLAG to signify
// end of the transmission.
fputc(HDLC_FLAG, ctx->ch);
ctx->ready_for_data = true;
}
void llp_sendRaw(LLPCtx *ctx, const void *_buf, size_t len) {
ctx->ready_for_data = false;
ctx->crc_out = CRC_CCIT_INIT_VAL;
fputc(HDLC_FLAG, ctx->ch);
const uint8_t *buf = (const uint8_t *)_buf;
while (len--) llp_putchar(ctx, *buf++);
uint8_t crcl = (ctx->crc_out & 0xff) ^ 0xff;
uint8_t crch = (ctx->crc_out >> 8) ^ 0xff;
llp_putchar(ctx, crcl);
llp_putchar(ctx, crch);
fputc(HDLC_FLAG, ctx->ch);
ctx->ready_for_data = true;
}
void llp_init(LLPCtx *ctx, LLPAddress *address, FILE *channel, llp_callback_t hook) {
memset(ctx, 0, sizeof(*ctx));
ctx->ch = channel;
ctx->hook = hook;
ctx->address = address;
ctx->crc_in = ctx->crc_out = CRC_CCIT_INIT_VAL;
ctx->ready_for_data = true;
memset(&broadcast_address, 0, sizeof(broadcast_address));
broadcast_address.network = LLP_ADDR_BROADCAST;
broadcast_address.host = LLP_ADDR_BROADCAST;
}
// This function calculates and returns a parity
// byte for two input bytes. The parity byte is
// used for correcting errors in the transmission.
// The error correction algorithm is a standard
// (12,8) Hamming code.
inline bool BIT(uint8_t byte, int n) { return ((byte & _BV(n-1))>>(n-1)); }
uint8_t llpParityBlock(uint8_t first, uint8_t other) {
uint8_t parity = 0x00;
parity = ((BIT(first, 1) ^ BIT(first, 2) ^ BIT(first, 4) ^ BIT(first, 5) ^ BIT(first, 7))) +
((BIT(first, 1) ^ BIT(first, 3) ^ BIT(first, 4) ^ BIT(first, 6) ^ BIT(first, 7))<<1) +
((BIT(first, 2) ^ BIT(first, 3) ^ BIT(first, 4) ^ BIT(first, 8))<<2) +
((BIT(first, 5) ^ BIT(first, 6) ^ BIT(first, 7) ^ BIT(first, 8))<<3) +
((BIT(other, 1) ^ BIT(other, 2) ^ BIT(other, 4) ^ BIT(other, 5) ^ BIT(other, 7))<<4) +
((BIT(other, 1) ^ BIT(other, 3) ^ BIT(other, 4) ^ BIT(other, 6) ^ BIT(other, 7))<<5) +
((BIT(other, 2) ^ BIT(other, 3) ^ BIT(other, 4) ^ BIT(other, 8))<<6) +
((BIT(other, 5) ^ BIT(other, 6) ^ BIT(other, 7) ^ BIT(other, 8))<<7);
return parity;
}
// Following is the functions responsible
// for interleaving and deinterleaving
// blocks of data. The interleaving table
// for 3-byte interleaving is also included.
// The table for 12-byte is much simpler,
// and should be inferable from looking
// at the function.
///////////////////////////////
// Interleave-table (3-byte) //
///////////////////////////////
//
// Non-interleaved:
// aaaaaaaa bbbbbbbb cccccccc
// 12345678 12345678 12345678
// M L
// S S
// B B
//
// Interleaved:
// abcabcab cabcabca bcabcabc
// 11144477 22255578 63336688
//
///////////////////////////////
void llpInterleave(LLPCtx *ctx, uint8_t byte) {
ctx->interleaveOut[ctx->interleaveCounter] = byte;
ctx->interleaveCounter++;
if (!DISABLE_INTERLEAVE) {
if (ctx->interleaveCounter == LLP_INTERLEAVE_SIZE) {
// We have the bytes we need for interleaving
// in the buffer and are ready to interleave them.
uint8_t a = (GET_BIT(ctx->interleaveOut[0], 1) << 7) +
(GET_BIT(ctx->interleaveOut[1], 1) << 6) +
(GET_BIT(ctx->interleaveOut[3], 1) << 5) +
(GET_BIT(ctx->interleaveOut[4], 1) << 4) +
(GET_BIT(ctx->interleaveOut[6], 1) << 3) +
(GET_BIT(ctx->interleaveOut[7], 1) << 2) +
(GET_BIT(ctx->interleaveOut[9], 1) << 1) +
(GET_BIT(ctx->interleaveOut[10],1));
llp_putchar(ctx, a);
uint8_t b = (GET_BIT(ctx->interleaveOut[0], 2) << 7) +
(GET_BIT(ctx->interleaveOut[1], 2) << 6) +
(GET_BIT(ctx->interleaveOut[3], 2) << 5) +
(GET_BIT(ctx->interleaveOut[4], 2) << 4) +
(GET_BIT(ctx->interleaveOut[6], 2) << 3) +
(GET_BIT(ctx->interleaveOut[7], 2) << 2) +
(GET_BIT(ctx->interleaveOut[9], 2) << 1) +
(GET_BIT(ctx->interleaveOut[10],2));
llp_putchar(ctx, b);
uint8_t c = (GET_BIT(ctx->interleaveOut[0], 3) << 7) +
(GET_BIT(ctx->interleaveOut[1], 3) << 6) +
(GET_BIT(ctx->interleaveOut[3], 3) << 5) +
(GET_BIT(ctx->interleaveOut[4], 3) << 4) +
(GET_BIT(ctx->interleaveOut[6], 3) << 3) +
(GET_BIT(ctx->interleaveOut[7], 3) << 2) +
(GET_BIT(ctx->interleaveOut[9], 3) << 1) +
(GET_BIT(ctx->interleaveOut[10],3));
llp_putchar(ctx, c);
uint8_t d = (GET_BIT(ctx->interleaveOut[0], 4) << 7) +
(GET_BIT(ctx->interleaveOut[1], 4) << 6) +
(GET_BIT(ctx->interleaveOut[3], 4) << 5) +
(GET_BIT(ctx->interleaveOut[4], 4) << 4) +
(GET_BIT(ctx->interleaveOut[6], 4) << 3) +
(GET_BIT(ctx->interleaveOut[7], 4) << 2) +
(GET_BIT(ctx->interleaveOut[9], 4) << 1) +
(GET_BIT(ctx->interleaveOut[10],4));
llp_putchar(ctx, d);
uint8_t e = (GET_BIT(ctx->interleaveOut[0], 5) << 7) +
(GET_BIT(ctx->interleaveOut[1], 5) << 6) +
(GET_BIT(ctx->interleaveOut[3], 5) << 5) +
(GET_BIT(ctx->interleaveOut[4], 5) << 4) +
(GET_BIT(ctx->interleaveOut[6], 5) << 3) +
(GET_BIT(ctx->interleaveOut[7], 5) << 2) +
(GET_BIT(ctx->interleaveOut[9], 5) << 1) +
(GET_BIT(ctx->interleaveOut[10],5));
llp_putchar(ctx, e);
uint8_t f = (GET_BIT(ctx->interleaveOut[0], 6) << 7) +
(GET_BIT(ctx->interleaveOut[1], 6) << 6) +
(GET_BIT(ctx->interleaveOut[3], 6) << 5) +
(GET_BIT(ctx->interleaveOut[4], 6) << 4) +
(GET_BIT(ctx->interleaveOut[6], 6) << 3) +
(GET_BIT(ctx->interleaveOut[7], 6) << 2) +
(GET_BIT(ctx->interleaveOut[9], 6) << 1) +
(GET_BIT(ctx->interleaveOut[10],6));
llp_putchar(ctx, f);
uint8_t g = (GET_BIT(ctx->interleaveOut[0], 7) << 7) +
(GET_BIT(ctx->interleaveOut[1], 7) << 6) +
(GET_BIT(ctx->interleaveOut[3], 7) << 5) +
(GET_BIT(ctx->interleaveOut[4], 7) << 4) +
(GET_BIT(ctx->interleaveOut[6], 7) << 3) +
(GET_BIT(ctx->interleaveOut[7], 7) << 2) +
(GET_BIT(ctx->interleaveOut[9], 7) << 1) +
(GET_BIT(ctx->interleaveOut[10],7));
llp_putchar(ctx, g);
uint8_t h = (GET_BIT(ctx->interleaveOut[0], 8) << 7) +
(GET_BIT(ctx->interleaveOut[1], 8) << 6) +
(GET_BIT(ctx->interleaveOut[3], 8) << 5) +
(GET_BIT(ctx->interleaveOut[4], 8) << 4) +
(GET_BIT(ctx->interleaveOut[6], 8) << 3) +
(GET_BIT(ctx->interleaveOut[7], 8) << 2) +
(GET_BIT(ctx->interleaveOut[9], 8) << 1) +
(GET_BIT(ctx->interleaveOut[10],8));
llp_putchar(ctx, h);
uint8_t p = (GET_BIT(ctx->interleaveOut[2], 1) << 7) +
(GET_BIT(ctx->interleaveOut[2], 5) << 6) +
(GET_BIT(ctx->interleaveOut[5], 1) << 5) +
(GET_BIT(ctx->interleaveOut[5], 5) << 4) +
(GET_BIT(ctx->interleaveOut[8], 1) << 3) +
(GET_BIT(ctx->interleaveOut[8], 5) << 2) +
(GET_BIT(ctx->interleaveOut[11],1) << 1) +
(GET_BIT(ctx->interleaveOut[11],5));
llp_putchar(ctx, p);
uint8_t q = (GET_BIT(ctx->interleaveOut[2], 2) << 7) +
(GET_BIT(ctx->interleaveOut[2], 6) << 6) +
(GET_BIT(ctx->interleaveOut[5], 2) << 5) +
(GET_BIT(ctx->interleaveOut[5], 6) << 4) +
(GET_BIT(ctx->interleaveOut[8], 2) << 3) +
(GET_BIT(ctx->interleaveOut[8], 6) << 2) +
(GET_BIT(ctx->interleaveOut[11],2) << 1) +
(GET_BIT(ctx->interleaveOut[11],6));
llp_putchar(ctx, q);
uint8_t s = (GET_BIT(ctx->interleaveOut[2], 3) << 7) +
(GET_BIT(ctx->interleaveOut[2], 7) << 6) +
(GET_BIT(ctx->interleaveOut[5], 3) << 5) +
(GET_BIT(ctx->interleaveOut[5], 7) << 4) +
(GET_BIT(ctx->interleaveOut[8], 3) << 3) +
(GET_BIT(ctx->interleaveOut[8], 7) << 2) +
(GET_BIT(ctx->interleaveOut[11],3) << 1) +
(GET_BIT(ctx->interleaveOut[11],7));
llp_putchar(ctx, s);
uint8_t t = (GET_BIT(ctx->interleaveOut[2], 4) << 7) +
(GET_BIT(ctx->interleaveOut[2], 8) << 6) +
(GET_BIT(ctx->interleaveOut[5], 4) << 5) +
(GET_BIT(ctx->interleaveOut[5], 8) << 4) +
(GET_BIT(ctx->interleaveOut[8], 4) << 3) +
(GET_BIT(ctx->interleaveOut[8], 8) << 2) +
(GET_BIT(ctx->interleaveOut[11],4) << 1) +
(GET_BIT(ctx->interleaveOut[11],8));
llp_putchar(ctx, t);
ctx->interleaveCounter = 0;
}
} else {
if (ctx->interleaveCounter == LLP_INTERLEAVE_SIZE) {
for (int i = 0; i < LLP_INTERLEAVE_SIZE; i++) {
llp_putchar(ctx, ctx->interleaveOut[i]);
}
ctx->interleaveCounter = 0;
}
}
}
void llpDeinterleave(LLPCtx *ctx) {
uint8_t a = (GET_BIT(ctx->interleaveIn[0], 1) << 7) +
(GET_BIT(ctx->interleaveIn[1], 1) << 6) +
(GET_BIT(ctx->interleaveIn[2], 1) << 5) +
(GET_BIT(ctx->interleaveIn[3], 1) << 4) +
(GET_BIT(ctx->interleaveIn[4], 1) << 3) +
(GET_BIT(ctx->interleaveIn[5], 1) << 2) +
(GET_BIT(ctx->interleaveIn[6], 1) << 1) +
(GET_BIT(ctx->interleaveIn[7], 1));
uint8_t b = (GET_BIT(ctx->interleaveIn[0], 2) << 7) +
(GET_BIT(ctx->interleaveIn[1], 2) << 6) +
(GET_BIT(ctx->interleaveIn[2], 2) << 5) +
(GET_BIT(ctx->interleaveIn[3], 2) << 4) +
(GET_BIT(ctx->interleaveIn[4], 2) << 3) +
(GET_BIT(ctx->interleaveIn[5], 2) << 2) +
(GET_BIT(ctx->interleaveIn[6], 2) << 1) +
(GET_BIT(ctx->interleaveIn[7], 2));
uint8_t p = (GET_BIT(ctx->interleaveIn[8], 1) << 7) +
(GET_BIT(ctx->interleaveIn[9], 1) << 6) +
(GET_BIT(ctx->interleaveIn[10],1) << 5) +
(GET_BIT(ctx->interleaveIn[11],1) << 4) +
(GET_BIT(ctx->interleaveIn[8], 2) << 3) +
(GET_BIT(ctx->interleaveIn[9], 2) << 2) +
(GET_BIT(ctx->interleaveIn[10],2) << 1) +
(GET_BIT(ctx->interleaveIn[11],2));
uint8_t c = (GET_BIT(ctx->interleaveIn[0], 3) << 7) +
(GET_BIT(ctx->interleaveIn[1], 3) << 6) +
(GET_BIT(ctx->interleaveIn[2], 3) << 5) +
(GET_BIT(ctx->interleaveIn[3], 3) << 4) +
(GET_BIT(ctx->interleaveIn[4], 3) << 3) +
(GET_BIT(ctx->interleaveIn[5], 3) << 2) +
(GET_BIT(ctx->interleaveIn[6], 3) << 1) +
(GET_BIT(ctx->interleaveIn[7], 3));
uint8_t d = (GET_BIT(ctx->interleaveIn[0], 4) << 7) +
(GET_BIT(ctx->interleaveIn[1], 4) << 6) +
(GET_BIT(ctx->interleaveIn[2], 4) << 5) +
(GET_BIT(ctx->interleaveIn[3], 4) << 4) +
(GET_BIT(ctx->interleaveIn[4], 4) << 3) +
(GET_BIT(ctx->interleaveIn[5], 4) << 2) +
(GET_BIT(ctx->interleaveIn[6], 4) << 1) +
(GET_BIT(ctx->interleaveIn[7], 4));
uint8_t q = (GET_BIT(ctx->interleaveIn[8], 3) << 7) +
(GET_BIT(ctx->interleaveIn[9], 3) << 6) +
(GET_BIT(ctx->interleaveIn[10],3) << 5) +
(GET_BIT(ctx->interleaveIn[11],3) << 4) +
(GET_BIT(ctx->interleaveIn[8], 4) << 3) +
(GET_BIT(ctx->interleaveIn[9], 4) << 2) +
(GET_BIT(ctx->interleaveIn[10],4) << 1) +
(GET_BIT(ctx->interleaveIn[11],4));
uint8_t e = (GET_BIT(ctx->interleaveIn[0], 5) << 7) +
(GET_BIT(ctx->interleaveIn[1], 5) << 6) +
(GET_BIT(ctx->interleaveIn[2], 5) << 5) +
(GET_BIT(ctx->interleaveIn[3], 5) << 4) +
(GET_BIT(ctx->interleaveIn[4], 5) << 3) +
(GET_BIT(ctx->interleaveIn[5], 5) << 2) +
(GET_BIT(ctx->interleaveIn[6], 5) << 1) +
(GET_BIT(ctx->interleaveIn[7], 5));
uint8_t f = (GET_BIT(ctx->interleaveIn[0], 6) << 7) +
(GET_BIT(ctx->interleaveIn[1], 6) << 6) +
(GET_BIT(ctx->interleaveIn[2], 6) << 5) +
(GET_BIT(ctx->interleaveIn[3], 6) << 4) +
(GET_BIT(ctx->interleaveIn[4], 6) << 3) +
(GET_BIT(ctx->interleaveIn[5], 6) << 2) +
(GET_BIT(ctx->interleaveIn[6], 6) << 1) +
(GET_BIT(ctx->interleaveIn[7], 6));
uint8_t s = (GET_BIT(ctx->interleaveIn[8], 5) << 7) +
(GET_BIT(ctx->interleaveIn[9], 5) << 6) +
(GET_BIT(ctx->interleaveIn[10],5) << 5) +
(GET_BIT(ctx->interleaveIn[11],5) << 4) +
(GET_BIT(ctx->interleaveIn[8], 6) << 3) +
(GET_BIT(ctx->interleaveIn[9], 6) << 2) +
(GET_BIT(ctx->interleaveIn[10],6) << 1) +
(GET_BIT(ctx->interleaveIn[11],6));
uint8_t g = (GET_BIT(ctx->interleaveIn[0], 7) << 7) +
(GET_BIT(ctx->interleaveIn[1], 7) << 6) +
(GET_BIT(ctx->interleaveIn[2], 7) << 5) +
(GET_BIT(ctx->interleaveIn[3], 7) << 4) +
(GET_BIT(ctx->interleaveIn[4], 7) << 3) +
(GET_BIT(ctx->interleaveIn[5], 7) << 2) +
(GET_BIT(ctx->interleaveIn[6], 7) << 1) +
(GET_BIT(ctx->interleaveIn[7], 7));
uint8_t h = (GET_BIT(ctx->interleaveIn[0], 8) << 7) +
(GET_BIT(ctx->interleaveIn[1], 8) << 6) +
(GET_BIT(ctx->interleaveIn[2], 8) << 5) +
(GET_BIT(ctx->interleaveIn[3], 8) << 4) +
(GET_BIT(ctx->interleaveIn[4], 8) << 3) +
(GET_BIT(ctx->interleaveIn[5], 8) << 2) +
(GET_BIT(ctx->interleaveIn[6], 8) << 1) +
(GET_BIT(ctx->interleaveIn[7], 8));
uint8_t t = (GET_BIT(ctx->interleaveIn[8], 7) << 7) +
(GET_BIT(ctx->interleaveIn[9], 7) << 6) +
(GET_BIT(ctx->interleaveIn[10],7) << 5) +
(GET_BIT(ctx->interleaveIn[11],7) << 4) +
(GET_BIT(ctx->interleaveIn[8], 8) << 3) +
(GET_BIT(ctx->interleaveIn[9], 8) << 2) +
(GET_BIT(ctx->interleaveIn[10],8) << 1) +
(GET_BIT(ctx->interleaveIn[11],8));
ctx->interleaveIn[0] = a;
ctx->interleaveIn[1] = b;
ctx->interleaveIn[2] = p;
ctx->interleaveIn[3] = c;
ctx->interleaveIn[4] = d;
ctx->interleaveIn[5] = q;
ctx->interleaveIn[6] = e;
ctx->interleaveIn[7] = f;
ctx->interleaveIn[8] = s;
ctx->interleaveIn[9] = g;
ctx->interleaveIn[10] = h;
ctx->interleaveIn[11] = t;
}