2016-06-11 21:34:36 +00:00
|
|
|
/*
|
|
|
|
Functions used by wsprsim
|
|
|
|
*/
|
2017-06-23 16:34:23 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
2021-12-04 04:08:36 +00:00
|
|
|
#include "./wsprsim_utils.h"
|
|
|
|
#include "./wsprd_utils.h"
|
|
|
|
#include "./nhash.h"
|
|
|
|
#include "./fano.h"
|
2016-06-11 21:34:36 +00:00
|
|
|
|
|
|
|
char get_locator_character_code(char ch) {
|
2021-12-04 20:19:06 +00:00
|
|
|
if (ch >= 48 && ch <= 57) { // 0-9
|
|
|
|
return ch - 48;
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
if (ch == 32) { // space
|
2016-06-11 21:34:36 +00:00
|
|
|
return 36;
|
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
if (ch >= 65 && ch <= 82) { // A-Z
|
|
|
|
return ch - 65;
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
char get_callsign_character_code(char ch) {
|
2021-12-04 20:19:06 +00:00
|
|
|
if (ch >= 48 && ch <= 57) { // 0-9
|
|
|
|
return ch - 48;
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
if (ch == 32) { // space
|
2016-06-11 21:34:36 +00:00
|
|
|
return 36;
|
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
if (ch >= 65 && ch <= 90) { // A-Z
|
|
|
|
return ch - 55;
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
long unsigned int pack_grid4_power(char *grid4, int power) {
|
|
|
|
long unsigned int m;
|
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
m = (179 - 10 * grid4[0] - grid4[2]) * 180 + 10 * grid4[1] + grid4[3];
|
|
|
|
m = m * 128 + power + 64;
|
2016-06-11 21:34:36 +00:00
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
long unsigned int pack_call(char *callsign) {
|
|
|
|
int i;
|
|
|
|
long unsigned int n;
|
|
|
|
char call6[6];
|
2021-12-04 20:19:06 +00:00
|
|
|
memset(call6, 32, sizeof(char) * 6);
|
2016-06-11 21:34:36 +00:00
|
|
|
// callsign is 6 characters in length. Exactly.
|
|
|
|
int call_len = strlen(callsign);
|
2021-12-04 20:19:06 +00:00
|
|
|
if (call_len > 6) {
|
2016-06-11 21:34:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
if (isdigit(*(callsign + 2))) {
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
if (callsign[i] == 0) {
|
|
|
|
call6[i] = 32;
|
2016-06-11 21:34:36 +00:00
|
|
|
} else {
|
2021-12-04 20:19:06 +00:00
|
|
|
call6[i] = *(callsign + i);
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
} else if (isdigit(*(callsign + 1))) {
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
if (i == 0 || callsign[i - 1] == 0) {
|
|
|
|
call6[i] = 32;
|
2016-06-11 21:34:36 +00:00
|
|
|
} else {
|
2021-12-04 20:19:06 +00:00
|
|
|
call6[i] = *(callsign + i - 1);
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
call6[i] = get_callsign_character_code(call6[i]);
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
|
|
|
n = call6[0];
|
2021-12-04 20:19:06 +00:00
|
|
|
n = n * 36 + call6[1];
|
|
|
|
n = n * 10 + call6[2];
|
|
|
|
n = n * 27 + call6[3] - 10;
|
|
|
|
n = n * 27 + call6[4] - 10;
|
|
|
|
n = n * 27 + call6[5] - 10;
|
2016-06-11 21:34:36 +00:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
void pack_prefix(char *callsign, int32_t *n, int32_t *m, int32_t *nadd) {
|
2016-06-11 21:34:36 +00:00
|
|
|
int i;
|
|
|
|
char *call6;
|
2021-12-04 20:19:06 +00:00
|
|
|
call6 = malloc(sizeof(char) * 6);
|
|
|
|
memset(call6, 32, sizeof(char) * 6);
|
|
|
|
int i1 = strcspn(callsign, "/");
|
2016-06-11 21:34:36 +00:00
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
if (callsign[i1 + 2] == 0) {
|
|
|
|
// single char suffix
|
|
|
|
for (i = 0; i < i1; i++) {
|
|
|
|
call6[i] = callsign[i];
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
*n = pack_call(call6);
|
|
|
|
*nadd = 1;
|
|
|
|
int nc = callsign[i1 + 1];
|
|
|
|
if (nc >= 48 && nc <= 57) {
|
|
|
|
*m = nc - 48;
|
|
|
|
} else if (nc >= 65 && nc <= 90) {
|
|
|
|
*m = nc - 65 + 10;
|
2016-06-11 21:34:36 +00:00
|
|
|
} else {
|
2021-12-04 20:19:06 +00:00
|
|
|
*m = 38;
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
*m = 60000 - 32768 + *m;
|
|
|
|
} else if (callsign[i1 + 3] == 0) {
|
|
|
|
// two char suffix
|
|
|
|
for (i = 0; i < i1; i++) {
|
|
|
|
call6[i] = callsign[i];
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
*n = pack_call(call6);
|
|
|
|
*nadd = 1;
|
|
|
|
*m = 10 * (callsign[i1 + 1] - 48) + (callsign[i1 + 2] - 48);
|
|
|
|
*m = 60000 + 26 + *m;
|
2016-06-11 21:34:36 +00:00
|
|
|
} else {
|
2021-12-04 20:19:06 +00:00
|
|
|
char *pfx = strtok(callsign, "/");
|
|
|
|
call6 = strtok(pfx, " "); // FIXME-CHECK
|
|
|
|
*n = pack_call(call6);
|
|
|
|
int plen = strlen(pfx);
|
|
|
|
if (plen == 1) {
|
|
|
|
*m = 36;
|
|
|
|
*m = 37 * (*m) + 36;
|
|
|
|
} else if (plen == 2) {
|
|
|
|
*m = 36;
|
2016-06-11 21:34:36 +00:00
|
|
|
} else {
|
2021-12-04 20:19:06 +00:00
|
|
|
*m = 0;
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
for (i = 0; i < plen; i++) {
|
2016-06-11 21:34:36 +00:00
|
|
|
int nc = callsign[i];
|
2021-12-04 20:19:06 +00:00
|
|
|
if (nc >= 48 && nc <= 57) {
|
|
|
|
nc = nc - 48;
|
|
|
|
} else if (nc >= 65 && nc <= 90) {
|
|
|
|
nc = nc - 65 + 10;
|
2016-06-11 21:34:36 +00:00
|
|
|
} else {
|
2021-12-04 20:19:06 +00:00
|
|
|
nc = 36;
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
*m = 37 * (*m) + nc;
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
*nadd = 0;
|
|
|
|
if (*m > 32768) {
|
|
|
|
*m = *m - 32768;
|
|
|
|
*nadd = 1;
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void interleave(unsigned char *sym) {
|
|
|
|
unsigned char tmp[162];
|
|
|
|
unsigned char p, i, j;
|
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
p = 0;
|
|
|
|
i = 0;
|
|
|
|
while (p < 162) {
|
|
|
|
j = ((i * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
|
|
|
|
if (j < 162) {
|
|
|
|
tmp[j] = sym[p];
|
|
|
|
p = p + 1;
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
i = i + 1;
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
for (i = 0; i < 162; i++) {
|
|
|
|
sym[i] = tmp[i];
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
int get_wspr_channel_symbols(char *rawmessage, char *hashtab, unsigned char *symbols) {
|
|
|
|
int m = 0, n = 0, ntype = 0;
|
2016-06-11 21:34:36 +00:00
|
|
|
int i, j, ihash;
|
2021-12-04 20:19:06 +00:00
|
|
|
unsigned char pr3[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 nu[10] = {0, -1, 1, 0, -1, 2, 1, 0, -1, 1};
|
2016-06-11 21:34:36 +00:00
|
|
|
char *callsign, *grid, *powstr;
|
|
|
|
char grid4[5], message[23];
|
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
memset(message, 0, sizeof(char) * 23);
|
|
|
|
i = 0;
|
|
|
|
while (rawmessage[i] != 0 && i < 23) {
|
|
|
|
message[i] = rawmessage[i];
|
2016-06-11 21:34:36 +00:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
int i1 = strcspn(message, " ");
|
|
|
|
int i2 = strcspn(message, "/");
|
|
|
|
int i3 = strcspn(message, "<");
|
|
|
|
int i4 = strcspn(message, ">");
|
|
|
|
int mlen = strlen(message);
|
2016-06-11 21:34:36 +00:00
|
|
|
|
|
|
|
// Use the presence and/or absence of "<" and "/" to decide what
|
|
|
|
// type of message. No sanity checks! Beware!
|
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
if ((i1 > 3) & (i1 < 7) & (i2 == mlen) & (i3 == mlen)) {
|
2016-06-11 21:34:36 +00:00
|
|
|
// Type 1 message: K9AN EN50 33
|
|
|
|
// xxnxxxx xxnn nn
|
2021-12-04 20:19:06 +00:00
|
|
|
callsign = strtok(message, " ");
|
|
|
|
grid = strtok(NULL, " ");
|
|
|
|
powstr = strtok(NULL, " ");
|
2016-06-11 21:34:36 +00:00
|
|
|
int power = atoi(powstr);
|
|
|
|
n = pack_call(callsign);
|
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
grid4[i] = get_locator_character_code(*(grid + i));
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
m = pack_grid4_power(grid4, power);
|
2016-06-11 21:34:36 +00:00
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
} else if (i3 == 0 && i4 < mlen) {
|
2016-06-11 21:34:36 +00:00
|
|
|
// Type 3: <K1ABC> EN50WC 33
|
|
|
|
// <PJ4/K1ABC> FK52UD 37
|
|
|
|
// send hash instead of callsign to make room for 6 char grid.
|
|
|
|
// if 4-digit locator is specified, 2 spaces are added to the end.
|
2021-12-04 20:19:06 +00:00
|
|
|
callsign = strtok(message, "<> ");
|
|
|
|
grid = strtok(NULL, " ");
|
|
|
|
powstr = strtok(NULL, " ");
|
2016-06-11 21:34:36 +00:00
|
|
|
int power = atoi(powstr);
|
2021-12-04 20:19:06 +00:00
|
|
|
if (power < 0) power = 0;
|
|
|
|
if (power > 60) power = 60;
|
|
|
|
power = power + nu[power % 10];
|
|
|
|
ntype = -(power + 1);
|
|
|
|
ihash = nhash(callsign, strlen(callsign), (uint32_t)146);
|
|
|
|
m = 128 * ihash + ntype + 64;
|
2016-06-11 21:34:36 +00:00
|
|
|
|
|
|
|
char grid6[6];
|
2021-12-04 20:19:06 +00:00
|
|
|
memset(grid6, 32, sizeof(char) * 6);
|
|
|
|
j = strlen(grid);
|
|
|
|
for (i = 0; i < j - 1; i++) {
|
|
|
|
grid6[i] = grid[i + 1];
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
2021-12-04 20:19:06 +00:00
|
|
|
grid6[5] = grid[0];
|
|
|
|
n = pack_call(grid6);
|
|
|
|
} else if (i2 < mlen) { // just looks for a right slash
|
2016-06-11 21:34:36 +00:00
|
|
|
// Type 2: PJ4/K1ABC 37
|
2021-12-04 20:19:06 +00:00
|
|
|
callsign = strtok(message, " ");
|
|
|
|
if (strlen(callsign) < i2) return 0; // guards against pathological case
|
|
|
|
powstr = strtok(NULL, " ");
|
2016-06-11 21:34:36 +00:00
|
|
|
int power = atoi(powstr);
|
2021-12-04 20:19:06 +00:00
|
|
|
if (power < 0) power = 0;
|
|
|
|
if (power > 60) power = 60;
|
|
|
|
power = power + nu[power % 10];
|
2016-06-11 21:34:36 +00:00
|
|
|
int n1, ng, nadd;
|
|
|
|
pack_prefix(callsign, &n1, &ng, &nadd);
|
2021-12-04 20:19:06 +00:00
|
|
|
ntype = power + 1 + nadd;
|
|
|
|
m = 128 * ng + ntype + 64;
|
|
|
|
n = n1;
|
2016-06-11 21:34:36 +00:00
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// pack 50 bits + 31 (0) tail bits into 11 bytes
|
|
|
|
unsigned char it, data[11];
|
2021-12-04 20:19:06 +00:00
|
|
|
memset(data, 0, sizeof(char) * 11);
|
|
|
|
it = 0xFF & (n >> 20);
|
|
|
|
data[0] = it;
|
|
|
|
it = 0xFF & (n >> 12);
|
|
|
|
data[1] = it;
|
|
|
|
it = 0xFF & (n >> 4);
|
|
|
|
data[2] = it;
|
|
|
|
it = ((n & (0x0F)) << 4) + ((m >> 18) & (0x0F));
|
|
|
|
data[3] = it;
|
|
|
|
it = 0xFF & (m >> 10);
|
|
|
|
data[4] = it;
|
|
|
|
it = 0xFF & (m >> 2);
|
|
|
|
data[5] = it;
|
|
|
|
it = (m & 0x03) << 6;
|
|
|
|
data[6] = it;
|
|
|
|
data[7] = 0;
|
|
|
|
data[8] = 0;
|
|
|
|
data[9] = 0;
|
|
|
|
data[10] = 0;
|
2016-06-11 21:34:36 +00:00
|
|
|
|
|
|
|
// make sure that the 11-byte data vector is unpackable
|
|
|
|
// unpack it with the routine that the decoder will use and display
|
|
|
|
// the result. let the operator decide whether it worked.
|
2021-12-04 20:19:06 +00:00
|
|
|
// char hashtab[32768][13];
|
|
|
|
// memset(hashtab,0,sizeof(char)*32768*13);
|
2016-06-11 21:34:36 +00:00
|
|
|
|
|
|
|
char *check_call_loc_pow, *check_callsign, *call, *loc, *pwr;
|
2021-12-04 20:19:06 +00:00
|
|
|
check_call_loc_pow = malloc(sizeof(char) * 23);
|
|
|
|
check_callsign = malloc(sizeof(char) * 13);
|
|
|
|
call = malloc(sizeof(char) * 13);
|
|
|
|
loc = malloc(sizeof(char) * 7);
|
|
|
|
pwr = malloc(sizeof(char) * 3);
|
2016-06-11 21:34:36 +00:00
|
|
|
signed char check_data[11];
|
2021-12-04 20:19:06 +00:00
|
|
|
memcpy(check_data, data, sizeof(char) * 11);
|
|
|
|
unpk_(check_data, hashtab, check_call_loc_pow, call, loc, pwr, check_callsign);
|
|
|
|
// printf("Will decode as: %s\n",check_call_loc_pow);
|
2016-06-11 21:34:36 +00:00
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
unsigned int nbytes = 11; // The message with tail is packed into 11 bytes.
|
|
|
|
unsigned int nencoded = (nbytes * 2 * 8); // This is how much encode() writes
|
2016-06-11 21:34:36 +00:00
|
|
|
unsigned char channelbits[nencoded];
|
2021-12-04 20:19:06 +00:00
|
|
|
memset(channelbits, 0, sizeof(char) * nencoded);
|
2016-06-11 21:34:36 +00:00
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
encode(channelbits, data, nbytes);
|
2016-06-11 21:34:36 +00:00
|
|
|
|
|
|
|
interleave(channelbits);
|
|
|
|
|
2021-12-04 20:19:06 +00:00
|
|
|
for (i = 0; i < 162; i++) {
|
|
|
|
symbols[i] = 2 * channelbits[i] + pr3[i];
|
2016-06-11 21:34:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|