/* * TelemEncoding.c * Fox-1 telemetry encoder January 2014 Phil Karn KA9Q This file has two external functions: void update_rs(unsigned char parity[32],unsigned char data); int encode_8b10b(int *state,int data). update_rs() is the Reed-Solomon encoder. Its first argument is the 32-byte encoder shift register, the second is the 8-bit data byte being encoded. It updates the shift register in place and returns void. At the end of each frame, it contains the parities ready for transmission, starting with parity[0]. Be sure to zero this array before each new frame! encode_8b10b() is the 8b10b encoder. Its first argument is a pointer to a single integer with the 1-bit encoder state (the current run disparity, or RD). Initialize it to 0 JUST ONCE at startup (not between frames). The second argument is the data byte being encoded. It updates the state and returns an integer containing the 10-bit encoded word, right justified. Transmit this word from left to right. The data argument is an int so it can hold the special value -1 to indicate end of frame; it generates the 8b10b control word K.28.5, which is used as an inter-frame flag. Some assert() calls are made to verify legality of arguments. These can be turned off in production code. sample frame transmission code: unsigned char data[64]; // Data block to be sent unsigned char parity[32]; // RS parities void transmit_word(int); // User provided transmit function: 10 bits of data in bits 9....0 int state,i; state = 0; // Only once at startup, not between frames memset(parity,0,sizeof(parity); // Do this before every frame // Transmit the data, updating the RS encoder for(i=0;i<64;i++){ update_rs(parity,data[i]); transmit_word(encode_8b10b(&state,data[i]); } // get the RS parities for(i=0;i<32;i++) transmit_word(encode_8b10b(&state,parity[i]); transmit_word(encode_8b10b(&state,-1); // Transmit end-of-frame flag */ #include //#include "Fox.h" #include "TelemEncoding.h" #include #include #ifndef NULL #define NULL ((void *)0) #endif #define NN (0xff) // Frame size in symbols #define A0 (NN) // special value for log(0) // GF Antilog lookup table table static unsigned char CCSDS_alpha_to[NN+1] = { 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x87,0x89,0x95,0xad,0xdd,0x3d,0x7a,0xf4, 0x6f,0xde,0x3b,0x76,0xec,0x5f,0xbe,0xfb,0x71,0xe2,0x43,0x86,0x8b,0x91,0xa5,0xcd, 0x1d,0x3a,0x74,0xe8,0x57,0xae,0xdb,0x31,0x62,0xc4,0x0f,0x1e,0x3c,0x78,0xf0,0x67, 0xce,0x1b,0x36,0x6c,0xd8,0x37,0x6e,0xdc,0x3f,0x7e,0xfc,0x7f,0xfe,0x7b,0xf6,0x6b, 0xd6,0x2b,0x56,0xac,0xdf,0x39,0x72,0xe4,0x4f,0x9e,0xbb,0xf1,0x65,0xca,0x13,0x26, 0x4c,0x98,0xb7,0xe9,0x55,0xaa,0xd3,0x21,0x42,0x84,0x8f,0x99,0xb5,0xed,0x5d,0xba, 0xf3,0x61,0xc2,0x03,0x06,0x0c,0x18,0x30,0x60,0xc0,0x07,0x0e,0x1c,0x38,0x70,0xe0, 0x47,0x8e,0x9b,0xb1,0xe5,0x4d,0x9a,0xb3,0xe1,0x45,0x8a,0x93,0xa1,0xc5,0x0d,0x1a, 0x34,0x68,0xd0,0x27,0x4e,0x9c,0xbf,0xf9,0x75,0xea,0x53,0xa6,0xcb,0x11,0x22,0x44, 0x88,0x97,0xa9,0xd5,0x2d,0x5a,0xb4,0xef,0x59,0xb2,0xe3,0x41,0x82,0x83,0x81,0x85, 0x8d,0x9d,0xbd,0xfd,0x7d,0xfa,0x73,0xe6,0x4b,0x96,0xab,0xd1,0x25,0x4a,0x94,0xaf, 0xd9,0x35,0x6a,0xd4,0x2f,0x5e,0xbc,0xff,0x79,0xf2,0x63,0xc6,0x0b,0x16,0x2c,0x58, 0xb0,0xe7,0x49,0x92,0xa3,0xc1,0x05,0x0a,0x14,0x28,0x50,0xa0,0xc7,0x09,0x12,0x24, 0x48,0x90,0xa7,0xc9,0x15,0x2a,0x54,0xa8,0xd7,0x29,0x52,0xa4,0xcf,0x19,0x32,0x64, 0xc8,0x17,0x2e,0x5c,0xb8,0xf7,0x69,0xd2,0x23,0x46,0x8c,0x9f,0xb9,0xf5,0x6d,0xda, 0x33,0x66,0xcc,0x1f,0x3e,0x7c,0xf8,0x77,0xee,0x5b,0xb6,0xeb,0x51,0xa2,0xc3,0x00, }; // GF log lookup table. Special value represents log(0) static unsigned char CCSDS_index_of[NN+1] = { A0, 0, 1, 99, 2,198,100,106, 3,205,199,188,101,126,107, 42, 4,141,206, 78,200,212,189,225,102,221,127, 49,108, 32, 43,243, 5, 87,142,232,207,172, 79,131,201,217,213, 65,190,148,226,180, 103, 39,222,240,128,177, 50, 53,109, 69, 33, 18, 44, 13,244, 56, 6,155, 88, 26,143,121,233,112,208,194,173,168, 80,117,132, 72, 202,252,218,138,214, 84, 66, 36,191,152,149,249,227, 94,181, 21, 104, 97, 40,186,223, 76,241, 47,129,230,178, 63, 51,238, 54, 16, 110, 24, 70,166, 34,136, 19,247, 45,184, 14, 61,245,164, 57, 59, 7,158,156,157, 89,159, 27, 8,144, 9,122, 28,234,160,113, 90, 209, 29,195,123,174, 10,169,145, 81, 91,118,114,133,161, 73,235, 203,124,253,196,219, 30,139,210,215,146, 85,170, 67, 11, 37,175, 192,115,153,119,150, 92,250, 82,228,236, 95, 74,182,162, 22,134, 105,197, 98,254, 41,125,187,204,224,211, 77,140,242, 31, 48,220, 130,171,231, 86,179,147, 64,216, 52,176,239, 38, 55, 12, 17, 68, 111,120, 25,154, 71,116,167,193, 35, 83,137,251, 20, 93,248,151, 46, 75,185, 96, 15,237, 62,229,246,135,165, 23, 58,163, 60,183, }; // Only half the coefficients are given here because the // generator polynomial is palindromic; G0 = G32, G1 = G31, etc. // Only G16 is unique static unsigned char CCSDS_poly[] = { 0,249, 59, 66, 4, 43,126,251, 97, 30, 3,213, 50, 66,170, 5, 24, }; static inline int modnn(int x){ while (x >= NN) { x -= NN; x = (x >> 8) + (x & NN); } return x; } // Update Reed-Solomon encoder // parity -> 32-byte reed-solomon encoder state; clear this to zero before each frame void update_rs( unsigned char parity[32], // 32-byte encoder state; zero before each frame unsigned char c) // Current data byte to update { unsigned char feedback; int j,t; assert(parity != NULL); feedback = CCSDS_index_of[c ^ parity[0]]; if(feedback != A0){ // only if feedback is non-zero // Take advantage of palindromic polynomial to halve the multiplies // Do G1...G15, which is the same as G17...G31 for(j=1;j<(int)(NP/2);j++){ t = CCSDS_alpha_to[modnn(feedback + CCSDS_poly[j])]; parity[j] ^= t; parity[NP-j] ^= t; } // Do G16, which is used in only parity[16] t = CCSDS_alpha_to[modnn(feedback + CCSDS_poly[j])]; parity[j] ^= t; } // shift left memmove(&parity[0],&parity[1],NP-1); // G0 is 1 in alpha form, 0 in index form; don't need to multiply by it parity[NP-1] = CCSDS_alpha_to[feedback]; //taskYIELD(); } #define SYNC (0x0fa) // K.28.5, RD=-1 void write_little_endian(unsigned int word, int num_bytes, FILE *wav_file) { unsigned buf; while(num_bytes>0) { buf = word & 0xff; fwrite(&buf, 1,1, wav_file); num_bytes--; word >>= 8; } }