/* This code is free to use */
/* Kire Pudsje, May 2015 */
#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h> // htonl
// table assumes previous state is 0, use bitwise invert of values otherwise
const uint16_t bmc_lookup[] = {
0xcccc, 0xcccd, 0xcccb, 0xccca, 0xccd3, 0xccd2, 0xccd4, 0xccd5,
0xccb3, 0xccb2, 0xccb4, 0xccb5, 0xccac, 0xccad, 0xccab, 0xccaa,
0xcd33, 0xcd32, 0xcd34, 0xcd35, 0xcd2c, 0xcd2d, 0xcd2b, 0xcd2a,
0xcd4c, 0xcd4d, 0xcd4b, 0xcd4a, 0xcd53, 0xcd52, 0xcd54, 0xcd55,
0xcb33, 0xcb32, 0xcb34, 0xcb35, 0xcb2c, 0xcb2d, 0xcb2b, 0xcb2a,
0xcb4c, 0xcb4d, 0xcb4b, 0xcb4a, 0xcb53, 0xcb52, 0xcb54, 0xcb55,
0xcacc, 0xcacd, 0xcacb, 0xcaca, 0xcad3, 0xcad2, 0xcad4, 0xcad5,
0xcab3, 0xcab2, 0xcab4, 0xcab5, 0xcaac, 0xcaad, 0xcaab, 0xcaaa,
0xd333, 0xd332, 0xd334, 0xd335, 0xd32c, 0xd32d, 0xd32b, 0xd32a,
0xd34c, 0xd34d, 0xd34b, 0xd34a, 0xd353, 0xd352, 0xd354, 0xd355,
0xd2cc, 0xd2cd, 0xd2cb, 0xd2ca, 0xd2d3, 0xd2d2, 0xd2d4, 0xd2d5,
0xd2b3, 0xd2b2, 0xd2b4, 0xd2b5, 0xd2ac, 0xd2ad, 0xd2ab, 0xd2aa,
0xd4cc, 0xd4cd, 0xd4cb, 0xd4ca, 0xd4d3, 0xd4d2, 0xd4d4, 0xd4d5,
0xd4b3, 0xd4b2, 0xd4b4, 0xd4b5, 0xd4ac, 0xd4ad, 0xd4ab, 0xd4aa,
0xd533, 0xd532, 0xd534, 0xd535, 0xd52c, 0xd52d, 0xd52b, 0xd52a,
0xd54c, 0xd54d, 0xd54b, 0xd54a, 0xd553, 0xd552, 0xd554, 0xd555,
0xb333, 0xb332, 0xb334, 0xb335, 0xb32c, 0xb32d, 0xb32b, 0xb32a,
0xb34c, 0xb34d, 0xb34b, 0xb34a, 0xb353, 0xb352, 0xb354, 0xb355,
0xb2cc, 0xb2cd, 0xb2cb, 0xb2ca, 0xb2d3, 0xb2d2, 0xb2d4, 0xb2d5,
0xb2b3, 0xb2b2, 0xb2b4, 0xb2b5, 0xb2ac, 0xb2ad, 0xb2ab, 0xb2aa,
0xb4cc, 0xb4cd, 0xb4cb, 0xb4ca, 0xb4d3, 0xb4d2, 0xb4d4, 0xb4d5,
0xb4b3, 0xb4b2, 0xb4b4, 0xb4b5, 0xb4ac, 0xb4ad, 0xb4ab, 0xb4aa,
0xb533, 0xb532, 0xb534, 0xb535, 0xb52c, 0xb52d, 0xb52b, 0xb52a,
0xb54c, 0xb54d, 0xb54b, 0xb54a, 0xb553, 0xb552, 0xb554, 0xb555,
0xaccc, 0xaccd, 0xaccb, 0xacca, 0xacd3, 0xacd2, 0xacd4, 0xacd5,
0xacb3, 0xacb2, 0xacb4, 0xacb5, 0xacac, 0xacad, 0xacab, 0xacaa,
0xad33, 0xad32, 0xad34, 0xad35, 0xad2c, 0xad2d, 0xad2b, 0xad2a,
0xad4c, 0xad4d, 0xad4b, 0xad4a, 0xad53, 0xad52, 0xad54, 0xad55,
0xab33, 0xab32, 0xab34, 0xab35, 0xab2c, 0xab2d, 0xab2b, 0xab2a,
0xab4c, 0xab4d, 0xab4b, 0xab4a, 0xab53, 0xab52, 0xab54, 0xab55,
0xaacc, 0xaacd, 0xaacb, 0xaaca, 0xaad3, 0xaad2, 0xaad4, 0xaad5,
0xaab3, 0xaab2, 0xaab4, 0xaab5, 0xaaac, 0xaaad, 0xaaab, 0xaaaa
};
// On the teensy, this is just a single assembly function
uint32_t rbit(uint32_t v)
{
uint32_t r = 0;
for (int i = 0; i < 32; i++) {
r = (r << 1) | (v & 1);
v >>= 1;
}
return r;
}
inline uint32_t parity(uint32_t v) __attribute__((always_inline));
inline uint32_t parity(uint32_t v)
{
v ^= v >> 1;
v ^= v >> 2;
v = (v & 0x11111111ul) * 0x11111111ul;
return (v >> 28) & 1;
}
static void inline bmc_encode(uint32_t *dest, uint16_t sample, uint16_t preamble) __attribute__((always_inline));
static void inline bmc_encode(uint32_t *dest, uint16_t sample, uint16_t preamble)
{
uint32_t bmc1, bmc2, bmc3, val;
val = rbit((sample << 4) | (parity(sample) << 23));
bmc1 = bmc_lookup[(val >> 24) & 0xff];
dest[0] = (preamble << 16) | (bmc1 & 0xffff);
bmc2 = bmc_lookup[(val >> 16) & 0xff] ^ -(bmc1 & 1);
bmc3 = bmc_lookup[(val >> 8) & 0xff] ^ -(bmc2 & 1);
dest[1] = (bmc2 << 16) | (bmc3 & 0xffff);
}
int main(void) {
int cnt = 1;
bool left = true;
uint16_t sample, preamble;
uint32_t dest[2];
while (fread(&sample, 2, 1, stdin))
{
cnt--;
if (left) {
if (cnt == 0) {
cnt = 192;
preamble = 0xe8cc;
}
else
preamble = 0xe2cc;
}
else
preamble = 0xe4cc;
bmc_encode(dest, sample, preamble);
left = !left;
// flip because of byte order when writing to disk
dest[0] = htonl(dest[0]);
dest[1] = htonl(dest[1]);
fwrite(dest, 8, 1, stdout);
}
return 0;
}