#include "wspr.h" #include #include #include #include const uint8_t WSPR_SYNC[WSPR_LENGTH] PROGMEM = { 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 }; static inline uint8_t wspr_call_char(char c) { c = toupper(c); if(c >= '0' && c <= '9') { return c - '0'; } else if(c >= 'A' && c <= 'Z') { return 10 + (c - 'A'); } // Turn everything else to space else { return 36; } } static inline uint8_t wspr_loc_char(char c) { c = toupper(c); if(c >= '0' && c <= '9') { return c - '0'; } else if(c >= 'A' && c <= 'R') { return c - 'A'; } // Everthing else becomes 9/I else { return 9; } } static inline uint8_t wspr_power(uint8_t power) { if(power > 60) { return 60; } return power; } const uint8_t WSPR_POWER_LOC_BITS = 22; uint64_t wspr_message(char *call, char *loc, uint8_t power) { uint32_t m, n; n = wspr_call_char(call[0]); n = n * 36 + wspr_call_char(call[1]); n = n * 10 + wspr_call_char(call[2]); n = n * 27 + wspr_call_char(call[3]) - 10; n = n * 27 + wspr_call_char(call[4]) - 10; n = n * 27 + wspr_call_char(call[5]) - 10; m = 179 - 10 * wspr_loc_char(loc[0]) - wspr_loc_char(loc[2]); m = m * 180 + 10 * wspr_loc_char(loc[1]) + wspr_loc_char(loc[3]); m = m * 128 + wspr_power(power) + 64; return ((uint64_t) n) << WSPR_POWER_LOC_BITS | m; } const uint32_t WSPR_FEC_TAPS1 = 0xF2D05351; const uint32_t WSPR_FEC_TAPS2 = 0xE4613C47; uint8_t wspr_parity32(uint32_t x) { x ^= x >> 16; x ^= x >> 8; x ^= x >> 4; x ^= x >> 2; x ^= x >> 1; return x & 1; } void wspr_fec(uint64_t msg, uint8_t *output) { memset(output, 0, WSPR_LENGTH); uint32_t reg = 0; for(uint8_t i = 0; i < 81; i++) { uint8_t bit = 0; if(i < 50) { bit = (msg >> (50 - i - 1)) & 1; } reg = (reg << 1) | bit; uint32_t tabs1 = reg & WSPR_FEC_TAPS1; uint32_t tabs2 = reg & WSPR_FEC_TAPS2; output[i * 2] = wspr_parity32(tabs1); output[i * 2 + 1] = wspr_parity32(tabs2); } } uint8_t wspr_reverse_bits(uint8_t bits) { //https://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/AVR-Built_002din-Functions.html return __builtin_avr_insert_bits (0x01234567, bits, 0); } void wspr_interleave(uint8_t *input, uint8_t *output) { uint8_t p = 0; uint8_t i = 0; while(p < WSPR_LENGTH) { uint8_t rev_i = wspr_reverse_bits(i); if(rev_i < WSPR_LENGTH) { output[rev_i] = input[p]; p++; } i++; } } void wspr_add_sync(uint8_t *symbols) { for(uint8_t i = 0; i < WSPR_LENGTH; i++) { symbols[i] = pgm_read_byte(&(WSPR_SYNC[i])) + 2 * symbols[i]; } } void wspr_encode(char *call, char *loc, uint8_t power, uint8_t *buffer) { uint8_t tmp_buffer[WSPR_LENGTH]; uint64_t msg = wspr_message(call, loc, power); wspr_fec(msg, tmp_buffer); wspr_interleave(tmp_buffer, buffer); wspr_add_sync(buffer); } // For PLL with 800MHz const struct si5351_params WSPR_SYMBOLS[4] = { // 7040100.000000: 113 + 44687 / 70401 // actual: 7040100.000000 {14033, 17455, 70401}, // 7040101.464844: 113 + 447801 / 705503 // actual: 7040101.464844 {14033, 172785, 705503}, // 7040102.929688: 113 + 38515 / 60682 // actual: 7040102.929688 {14033, 14678, 60682}, // 7040104.394531: 113 + 123233 / 194166 // actual: 7040104.394531 {14033, 46378, 194166}, }; const uint16_t WSPR_PERIOD = 683; void wspr_transmit(enum si5351_multisynth synth, uint8_t *msg) { si5351_ms_enable_output(synth); for(uint8_t i = 0; i < WSPR_LENGTH; i++) { uint8_t sym = msg[i]; si5351_ms_write_params(synth, WSPR_SYMBOLS[sym]); _delay_ms(WSPR_PERIOD); } si5351_ms_disable_output(synth); }