/* WSPR encoding module All the encoding is done here Thanks to K1JT, G4JNT and PE1NZZ for publishing helping infos. Encoding process is in 5 steps: * bits packing of user message in 50 bits * store the 50 bits in 11 bytes (88 bits and only 81 useful for FEC) * convolutionnal encoding with two pariy generators (-> 162 bits) * interleaving of the 162 bits with bit-reverse technique * synchronisation with a pseudo-random vector to obtain the 162 symbols defining one frequency of 4. F8CHK 29/03/2011 */ #include #include #include #include #include "uart1.h" // terminal UART definitions #include "SDR_Cube.h" // board & processor specific definitions #include "SDR_Cube_globals.h" // global data #include "wspr.h" // wspr definitions and functions #include "gps.h" // Globals variables char wspr_message[20]; // user beacon message to encode (ex: F8CHK JN09 30) unsigned char wspr_symbols[162] = {0}, // contains 162 finals symbols wspr_encoded = 0; // to know that a message has been encoded extern gps_infos GPS; void Code_msg(unsigned long int *N, unsigned long int *M) { unsigned long int n, m; unsigned int i, j, power, callsign_length; char callsign[7] = {0}, // user callsign string locator[7] = {0}, // user locator string power_str[3]= {0}; // user power string strcpy(callsign," "); // fill with spaces i = 0; while (wspr_message[i] != ' ') { callsign[i] = wspr_message[i]; // extract callsign i++; } callsign_length = i; i++; j = 0; while (wspr_message[i] != ' ') { if(cal.calval.gps_sync && GPS.valid) // locator coming from GPS receiver wspr_message[i] = GPS.locator[j]; locator[j++] = wspr_message[i++]; // or from user message } locator[j] = 0; i++; j = 0; while (wspr_message[i] != 0) power_str[j++] = wspr_message[i++]; // extract power power_str[j]= 0 ; power = atoi(power_str); // power needs to be an integer // Place a space in first position if third character is not a digit if (!isdigit(callsign [2])) { for (i = callsign_length ; i > 0; i--) callsign [i] = callsign [i -1]; callsign [0] = ' '; } // callsign encoding: // numbers have a value between 0 and 9 // and letters a value between 10 and 35 // space a value of 36 if (callsign[0] == ' ') // first character of callsign n = 36; // can be space else if ((callsign[0] >= '0') & (callsign[0] <= '9')) // a number n = callsign[0] - '0'; else n = callsign[0] - 'A' + 10; // or letter if (callsign[1] == ' ') // second character n = n * 36 + 36; else if ((callsign[1] >= '0') & (callsign[1] <= '9')) n = n * 36 + callsign[1] - '0'; else n = n * 36 + callsign[1] - 'A' + 10; n = n * 10 + (callsign [2] - '0'); // only number (0-9) for (i = 3;i < 6;i++) // last 3 characters can only be spaces or letter { if (callsign[i] == ' ') n = 27 * n + 26; else n = 27 * n + callsign[i] - 'A'; } // Locator encoding m = (179 - 10 * (locator[0] - 65) - (locator[2]- 48)) * 180 + 10 * (locator[1] - 65) + locator[3] - 48; // Power encoding m = m * 128 + power + 64; *N = n; // return values *M = m; } void Pack_msg(unsigned long int N, unsigned long int M, unsigned char c[]) { // Bit packing // Store in 11 characters because we need 81 bits for FEC correction c[0] = N >> 20; // Callsign c[1] = N >> 12; c[2] = N >> 4; c[3] = N ; c[3] = c[3] << 4; c[3] = c[3] | (M >> 18); // locator and power c[4] = M >> 10; c[5] = M >> 2; c[6] = M & 0x03; c[6] = c[6] << 6; c[7] = 0; // always at 0 c[8] = 0; c[9] = 0; c[10] = 0; } int Find_parity(unsigned long int reg) { unsigned int count; count = 0; while (reg) { if(reg % 2) count++; // count number of bits at 1 reg = reg >> 1; } if (count % 2) // if number of bit at one is odd return 1; // to get an even parity else return 0; } void Generate_parity(unsigned char c[], unsigned char symbols[]) { unsigned long int Reg = 0, // 32 bits shift register result; int i,j,k; k = 0; for (j = 0; j < 11; j++) // each byte { for (i = 7; i >= 0; i--) { Reg = (Reg << 1); // shift and Reg = Reg | (c[j] >> i); // enter each bit result = Reg & POLYNOM_1; // first polynom symbols[k++] = Find_parity(result); result = Reg & POLYNOM_2; // second polynom symbols[k++] = Find_parity(result); } // end of each bit (32) loop } // end of each byte (11) loop } void Interleave(unsigned char symbols[], unsigned char symbols_interleaved[]) { int i,j,k,l,P; P = 0; while (P < 162) { for (k = 0; k <= 255; k++) // bits reverse, ex: 0010 1110 --> 0111 0100 { i = k; j = 0; for (l = 7; l >=0; l--) // hard work is done here... { j = j | (i & 0x01) << l; i = i >> 1; } if (j < 162) symbols_interleaved[j] = symbols [P++]; // range in interleaved table } } // end of while, interleaved table is full } void Synchronise(unsigned char symbols_interleaved[], unsigned char symbols_wspr[]) { unsigned int sync_word [162]={ 1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0,0,1,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,0, 0,0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0, 1,1,0,0,0,1,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,1,1,1,0,1,1,0,0,1,1,0,1,0,0,0,1, 1,1,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,0,0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0.0,0 }; int i; for (i = 0;i < 162; i++) symbols_wspr[i] = sync_word[i] + 2 * symbols_interleaved[i]; } void code_wspr() { unsigned char c_packed[11], // for bit packing, contains 81 bits useful symbols_parity [176] = {0}, // contains 2*81 usefuls parity bits symbols_interleaved [162] = {0}; // contains parity bits after interleaving unsigned long N, // for callsign M; // for locator and power // int i; Code_msg(&N, &M); Pack_msg (N, M, c_packed); Generate_parity (c_packed, symbols_parity); Interleave (symbols_parity, symbols_interleaved); Synchronise (symbols_interleaved, wspr_symbols); wspr_encoded = 1; // a message has been encoded putst1("\n\r>WSPR encoding ok\n\r"); // print symbols for verification // i = 0; // while (i < 162) // { // sprintf(pbuf,"%d ",wspr_symbols[i++]); // putst1(pbuf); // // if (i % 30 == 0) // putst1("\n\r"); // } }