Skip to content

Instantly share code, notes, and snippets.

@NT7S
Created September 25, 2015 02:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NT7S/8b03beade73e499c6bf1 to your computer and use it in GitHub Desktop.
Save NT7S/8b03beade73e499c6bf1 to your computer and use it in GitHub Desktop.
My unoptimized implementation of the WSPR encoding process
#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