Created
September 25, 2015 02:29
-
-
Save NT7S/8b03beade73e499c6bf1 to your computer and use it in GitHub Desktop.
My unoptimized implementation of the WSPR encoding process
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <ctype.h> | |
uint8_t wspr_code(char c) | |
{ | |
/* Validate the input then return the proper integer code */ | |
// Return 255 as an error code if the char is not allowed | |
if(isdigit(c)) | |
{ | |
return (uint8_t)(c - 48); | |
} | |
else if(c == ' ') | |
{ | |
return 36; | |
} | |
else if(c >= 'A' && c <= 'Z') | |
{ | |
return (uint8_t)(c - 55); | |
} | |
else | |
{ | |
return 255; | |
} | |
} | |
int main(int argc, char *argv[]) | |
{ | |
char callsign[7] = "NT7S"; | |
char locator[5] = "CN85"; | |
uint8_t power = 27; | |
char symbol_table[163]; | |
/* Callsign validation and padding */ | |
// If only the 2nd character is a digit, then pad with a space. | |
// If this happens, then the callsign will be truncated if it is | |
// longer than 5 characters. | |
if((callsign[1] >= '0' && callsign[1] <= '9') && (callsign[2] < '0' || callsign[2] > '9')) | |
{ | |
memmove(callsign + 1, callsign, 5); | |
callsign[0] = ' '; | |
} | |
// Now the 3rd charcter in the callsign must be a digit | |
if(callsign[2] < '0' || callsign[2] > '9') | |
{ | |
return 1; | |
} | |
// Ensure that the only allowed characters are digits and | |
// uppercase letters | |
uint8_t i; | |
for(i = 0; i < 6; i++) | |
{ | |
callsign[i] = toupper(callsign[i]); | |
if(!(isdigit(callsign[i]) || isupper(callsign[i]))) | |
{ | |
callsign[i] = ' '; | |
} | |
} | |
/* Grid locator validation */ | |
for(i = 0; i < 4; i++) | |
{ | |
locator[i] = toupper(locator[i]); | |
if(!(isdigit(locator[i]) || (locator[i] >= 'A' && locator[i] <= 'R'))) | |
{ | |
return 1; | |
} | |
} | |
/* Power level validation */ | |
if(power > 60) | |
{ | |
return 1; | |
} | |
printf("%s %s %d\n\n", callsign, locator, power); | |
/* | |
for(i = 0; i < 6; i++) | |
{ | |
printf("%d ", wspr_code(callsign[i])); | |
} | |
printf("\n"); | |
for(i = 0; i < 4; i++) | |
{ | |
printf("%d ", wspr_code(locator[i])); | |
} | |
printf("\n\n"); | |
*/ | |
/* Now let's find the M and N values */ | |
uint32_t n, m; | |
n = wspr_code(callsign[0]); | |
n = n * 36 + wspr_code(callsign[1]); | |
n = n * 10 + wspr_code(callsign[2]); | |
n = n * 27 + (wspr_code(callsign[3]) - 10); | |
n = n * 27 + (wspr_code(callsign[4]) - 10); | |
n = n * 27 + (wspr_code(callsign[5]) - 10); | |
m = ((179 - 10 * (locator[0] - 'A') - (locator[2] - '0')) * 180) + | |
(10 * (locator[1] - 'A')) + (locator[3] - '0'); | |
m = (m * 128) + power + 64; | |
//printf("N: %lu\nM: %lu\n\n", n, m); | |
/* Bit packing */ | |
uint8_t c[10]; | |
// Callsign is 28 bits, locator/power is 22 bits. | |
// A little less work to start with the least-significant bits | |
c[3] = (uint8_t)((n & 0x0f) << 4); | |
n = n >> 4; | |
c[2] = (uint8_t)(n & 0xff); | |
n = n >> 8; | |
c[1] = (uint8_t)(n & 0xff); | |
n = n >> 8; | |
c[0] = (uint8_t)(n & 0xff); | |
c[6] = (uint8_t)((m & 0x03) << 6); | |
m = m >> 2; | |
c[5] = (uint8_t)(m & 0xff); | |
m = m >> 8; | |
c[4] = (uint8_t)(m & 0xff); | |
m = m >> 8; | |
c[3] = c[3] | (uint8_t)(m & 0x0f); | |
c[7] = 0; | |
c[8] = 0; | |
c[9] = 0; | |
c[10] = 0; | |
/* | |
for(i = 0; i < 11; i++) | |
{ | |
printf("c[%d]: %x\n", i, c[i]); | |
} | |
printf("\n\n"); | |
*/ | |
/* Convolutional encoding */ | |
// Parity bits are generated from clocking our packed bits into | |
// a LFSR. | |
uint8_t s[162]; | |
uint32_t reg_0, reg_1, reg_temp; | |
uint8_t j, k, input_bit, parity_bit; | |
uint8_t bit_count = 0; | |
for(i = 0; i < 11; i++) | |
{ | |
for(j = 0; j < 8; j++) | |
{ | |
// Set input bit according the MSB of current element | |
input_bit = (((c[i] << j) & 0x80) == 0x80) ? 1 : 0; | |
//printf("%d %d %x\n", i, j, input_bit); | |
// Shift both registers and put in the new input bit | |
reg_0 = reg_0 << 1; | |
reg_1 = reg_1 << 1; | |
reg_0 |= (uint32_t)input_bit; | |
reg_1 |= (uint32_t)input_bit; | |
// AND Register 0 with feedback taps, calculate parity | |
reg_temp = reg_0 & 0xf2d05351; | |
parity_bit = 0; | |
for(k = 0; k < 32; k++) | |
{ | |
parity_bit = parity_bit ^ (reg_temp & 0x01); | |
reg_temp = reg_temp >> 1; | |
} | |
s[bit_count] = parity_bit; | |
bit_count++; | |
// AND Register 1 with feedback taps, calculate parity | |
reg_temp = reg_1 & 0xe4613c47; | |
parity_bit = 0; | |
for(k = 0; k < 32; k++) | |
{ | |
parity_bit = parity_bit ^ (reg_temp & 0x01); | |
reg_temp = reg_temp >> 1; | |
} | |
s[bit_count] = parity_bit; | |
bit_count++; | |
if(bit_count >= 162) | |
{ | |
break; | |
} | |
} | |
} | |
/* | |
for(i = 0; i < 162; i++) | |
{ | |
printf("%u ", s[i]); | |
} | |
printf("\n\n"); | |
*/ | |
/* Interleaving */ | |
uint8_t d[162]; | |
uint8_t rev, index_temp; | |
i = 0; | |
for(j = 0; j < 255; j++) | |
{ | |
// Bit reverse the index | |
index_temp = j; | |
rev = 0; | |
for(k = 0; k < 8; k++) | |
{ | |
if(index_temp & 0x01) | |
{ | |
rev = rev | (1 << (7 - k)); | |
} | |
index_temp = index_temp >> 1; | |
} | |
if(rev < 162) | |
{ | |
d[rev] = s[i]; | |
//printf("d[%d] = s[%d]\n", rev, i); | |
i++; | |
} | |
if(i >= 162) | |
{ | |
break; | |
} | |
} | |
/* | |
for(i = 0; i < 162; i++) | |
{ | |
printf("%u", d[i]); | |
} | |
printf("\n\n"); | |
*/ | |
/* Merge with sync vector */ | |
const uint8_t sync_vector[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}; | |
for(i = 0; i < 162; i++) | |
{ | |
s[i] = sync_vector[i] + (2 * d[i]); | |
} | |
printf("Channel Symbols:\n"); | |
for(i = 0; i < 162; i++) | |
{ | |
printf("%u", s[i]); | |
} | |
printf("\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment