kopia lustrzana https://github.com/Guenael/rtlsdr-wsprd
355 wiersze
11 KiB
C
355 wiersze
11 KiB
C
/*
|
|
This file is part of program wsprd, a detector/demodulator/decoder
|
|
for the Weak Signal Propagation Reporter (WSPR) mode.
|
|
|
|
File name: wsprd_utils.c
|
|
|
|
Copyright 2001-2015, Joe Taylor, K1JT
|
|
|
|
Most of the code is based on work by Steven Franke, K9AN, which
|
|
in turn was based on earlier work by K1JT.
|
|
|
|
Copyright 2014-2015, Steven Franke, K9AN
|
|
|
|
License: GNU GPL v3
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
#include "./nhash.h"
|
|
#include "./wsprd_utils.h"
|
|
|
|
// EVAL -- Replace strcpy & strncpy by strcpy to prevent possible buffer overflow
|
|
// #pragma GCC diagnostic ignored "-Wstringop-overflow"
|
|
// #pragma GCC diagnostic ignored "-Wstringop-truncation"
|
|
|
|
void unpack50(signed char *dat, int32_t *n1, int32_t *n2) {
|
|
int32_t i, i4;
|
|
|
|
i = dat[0];
|
|
i4 = i & 255;
|
|
*n1 = i4 << 20;
|
|
|
|
i = dat[1];
|
|
i4 = i & 255;
|
|
*n1 = *n1 + (i4 << 12);
|
|
|
|
i = dat[2];
|
|
i4 = i & 255;
|
|
*n1 = *n1 + (i4 << 4);
|
|
|
|
i = dat[3];
|
|
i4 = i & 255;
|
|
*n1 = *n1 + ((i4 >> 4) & 15);
|
|
*n2 = (i4 & 15) << 18;
|
|
|
|
i = dat[4];
|
|
i4 = i & 255;
|
|
*n2 = *n2 + (i4 << 10);
|
|
|
|
i = dat[5];
|
|
i4 = i & 255;
|
|
*n2 = *n2 + (i4 << 2);
|
|
|
|
i = dat[6];
|
|
i4 = i & 255;
|
|
*n2 = *n2 + ((i4 >> 6) & 3);
|
|
}
|
|
|
|
int unpackcall(int32_t ncall, char *call) {
|
|
char c[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
|
|
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
|
'U', 'V', 'W', 'X', 'Y', 'Z', ' '};
|
|
int32_t n;
|
|
int i;
|
|
char tmp[7];
|
|
|
|
n = ncall;
|
|
strcpy(call, "......");
|
|
if (n < 262177560) {
|
|
i = n % 27 + 10;
|
|
tmp[5] = c[i];
|
|
n = n / 27;
|
|
i = n % 27 + 10;
|
|
tmp[4] = c[i];
|
|
n = n / 27;
|
|
i = n % 27 + 10;
|
|
tmp[3] = c[i];
|
|
n = n / 27;
|
|
i = n % 10;
|
|
tmp[2] = c[i];
|
|
n = n / 10;
|
|
i = n % 36;
|
|
tmp[1] = c[i];
|
|
n = n / 36;
|
|
i = n;
|
|
tmp[0] = c[i];
|
|
tmp[6] = '\0';
|
|
// remove leading whitespace
|
|
for (i = 0; i < 5; i++) {
|
|
if (tmp[i] != c[36])
|
|
break;
|
|
}
|
|
sprintf(call, "%-6s", &tmp[i]);
|
|
// remove trailing whitespace
|
|
for (i = 0; i < 6; i++) {
|
|
if (call[i] == c[36]) {
|
|
call[i] = '\0';
|
|
}
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int unpackgrid(int32_t ngrid, char *grid) {
|
|
char c[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
|
|
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
|
'U', 'V', 'W', 'X', 'Y', 'Z', ' '};
|
|
int dlat, dlong;
|
|
|
|
ngrid = ngrid >> 7;
|
|
if (ngrid < 32400) {
|
|
dlat = (ngrid % 180) - 90;
|
|
dlong = (ngrid / 180) * 2 - 180 + 2;
|
|
if (dlong < -180)
|
|
dlong = dlong + 360;
|
|
if (dlong > 180)
|
|
dlong = dlong + 360;
|
|
int nlong = 60.0 * (180.0 - dlong) / 5.0;
|
|
int n1 = nlong / 240;
|
|
int n2 = (nlong - 240 * n1) / 24;
|
|
grid[0] = c[10 + n1];
|
|
grid[2] = c[n2];
|
|
|
|
int nlat = 60.0 * (dlat + 90) / 2.5;
|
|
n1 = nlat / 240;
|
|
n2 = (nlat - 240 * n1) / 24;
|
|
grid[1] = c[10 + n1];
|
|
grid[3] = c[n2];
|
|
} else {
|
|
strcpy(grid, "XXXX");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int unpackpfx(int32_t nprefix, char *call) {
|
|
char nc, pfx[4] = {'\0'}, tmpcall[7];
|
|
int i;
|
|
int32_t n;
|
|
|
|
strcpy(tmpcall, call);
|
|
if (nprefix < 60000) {
|
|
// add a prefix of 1 to 3 characters
|
|
n = nprefix;
|
|
for (i = 2; i >= 0; i--) {
|
|
nc = n % 37;
|
|
if ((nc >= 0) & (nc <= 9)) {
|
|
pfx[i] = nc + 48;
|
|
} else if ((nc >= 10) & (nc <= 35)) {
|
|
pfx[i] = nc + 55;
|
|
} else {
|
|
pfx[i] = ' ';
|
|
}
|
|
n = n / 37;
|
|
}
|
|
|
|
char *p = strrchr(pfx, ' ');
|
|
strcpy(call, p ? p + 1 : pfx);
|
|
strncat(call, "/", 1);
|
|
strncat(call, tmpcall, strlen(tmpcall));
|
|
|
|
} else {
|
|
// add a suffix of 1 or 2 characters
|
|
nc = nprefix - 60000;
|
|
if ((nc >= 0) & (nc <= 9)) {
|
|
pfx[0] = nc + 48;
|
|
strcpy(call, tmpcall);
|
|
strncat(call, "/", 1);
|
|
strncat(call, pfx, 1);
|
|
} else if ((nc >= 10) & (nc <= 35)) {
|
|
pfx[0] = nc + 55;
|
|
strcpy(call, tmpcall);
|
|
strncat(call, "/", 1);
|
|
strncat(call, pfx, 1);
|
|
} else if ((nc >= 36) & (nc <= 125)) {
|
|
pfx[0] = (nc - 26) / 10 + 48;
|
|
pfx[1] = (nc - 26) % 10 + 48;
|
|
strcpy(call, tmpcall);
|
|
strncat(call, "/", 1);
|
|
strncat(call, pfx, 2);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void deinterleave(unsigned char *sym) {
|
|
unsigned char tmp[162];
|
|
unsigned char p, i, j;
|
|
|
|
p = 0;
|
|
i = 0;
|
|
while (p < 162) {
|
|
j = ((i * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
|
|
if (j < 162) {
|
|
tmp[p] = sym[j];
|
|
p = p + 1;
|
|
}
|
|
i = i + 1;
|
|
}
|
|
for (i = 0; i < 162; i++) {
|
|
sym[i] = tmp[i];
|
|
}
|
|
}
|
|
|
|
// used by qsort
|
|
int doublecomp(const void *elem1, const void *elem2) {
|
|
if (*(const double *)elem1 < *(const double *)elem2)
|
|
return -1;
|
|
return *(const double *)elem1 > *(const double *)elem2;
|
|
}
|
|
|
|
int floatcomp(const void *elem1, const void *elem2) {
|
|
if (*(const float *)elem1 < *(const float *)elem2)
|
|
return -1;
|
|
return *(const float *)elem1 > *(const float *)elem2;
|
|
}
|
|
|
|
int unpk_(signed char *message, char *hashtab, char *loctab, char *call_loc_pow, char *call, char *loc, char *pwr, char *callsign) {
|
|
int n1, n2, n3, ndbm, ihash, nadd, noprint = 0;
|
|
char grid[5], grid6[7], cdbm[4];
|
|
|
|
unpack50(message, &n1, &n2);
|
|
if (!unpackcall(n1, callsign))
|
|
return 1;
|
|
if (!unpackgrid(n2, grid))
|
|
return 1;
|
|
int ntype = (n2 & 127) - 64;
|
|
callsign[12] = 0;
|
|
grid[4] = 0;
|
|
|
|
/*
|
|
Based on the value of ntype, decide whether this is a Type 1, 2, or
|
|
3 message.
|
|
* Type 1: 6 digit call, grid, power - ntype is positive and is a member
|
|
of the set {0,3,7,10,13,17,20...60}
|
|
* Type 2: extended callsign, power - ntype is positive but not
|
|
a member of the set of allowed powers
|
|
* Type 3: hash, 6 digit grid, power - ntype is negative.
|
|
*/
|
|
|
|
if ((ntype >= 0) && (ntype <= 62)) {
|
|
int nu = ntype % 10;
|
|
if (nu == 0 || nu == 3 || nu == 7) {
|
|
ndbm = ntype;
|
|
memset(call_loc_pow, 0, sizeof(char) * 23);
|
|
sprintf(cdbm, "%02d", ndbm);
|
|
strncat(call_loc_pow, callsign, strlen(callsign));
|
|
strncat(call_loc_pow, " ", 1);
|
|
strncat(call_loc_pow, grid, 4);
|
|
strncat(call_loc_pow, " ", 1);
|
|
strncat(call_loc_pow, cdbm, 2);
|
|
strncat(call_loc_pow, "\0", 1);
|
|
ihash = nhash(callsign, strlen(callsign), (uint32_t)146);
|
|
strcpy(hashtab + ihash * 13, callsign);
|
|
strcpy(loctab + ihash * 5, grid);
|
|
|
|
memset(call, 0, sizeof(char) * strlen(callsign) + 1);
|
|
memset(loc, 0, sizeof(char) * strlen(grid) + 1);
|
|
memset(pwr, 0, sizeof(char) * 2 + 1);
|
|
strncat(call, callsign, strlen(callsign));
|
|
strncat(call, "\0", 1);
|
|
strncat(loc, grid, strlen(grid));
|
|
strncat(loc, "\0", 1);
|
|
strncat(pwr, cdbm, 2);
|
|
strncat(pwr, "\0", 1);
|
|
} else {
|
|
nadd = nu;
|
|
if (nu > 3) nadd = nu - 3;
|
|
if (nu > 7) nadd = nu - 7;
|
|
n3 = n2 / 128 + 32768 * (nadd - 1);
|
|
if (!unpackpfx(n3, callsign)) return 1;
|
|
ndbm = ntype - nadd;
|
|
memset(call_loc_pow, 0, sizeof(char) * 23);
|
|
sprintf(cdbm, "%2d", ndbm);
|
|
strncat(call_loc_pow, callsign, strlen(callsign));
|
|
strncat(call_loc_pow, " ", 1);
|
|
strncat(call_loc_pow, cdbm, 2);
|
|
strncat(call_loc_pow, "\0", 1);
|
|
int nu = ndbm % 10;
|
|
if (nu == 0 || nu == 3 || nu == 7) { // make sure power is OK
|
|
ihash = nhash(callsign, strlen(callsign), (uint32_t)146);
|
|
strcpy(hashtab + ihash * 13, callsign);
|
|
} else
|
|
noprint = 1;
|
|
}
|
|
} else if (ntype < 0) {
|
|
ndbm = -(ntype + 1);
|
|
memset(grid6, 0, sizeof(char) * 7);
|
|
// size_t len=strlen(callsign);
|
|
size_t len = 6;
|
|
strncat(grid6, callsign + len - 1, 1);
|
|
strncat(grid6, callsign, len - 1);
|
|
int nu = ndbm % 10;
|
|
if ((nu != 0 && nu != 3 && nu != 7) ||
|
|
!isalpha(grid6[0]) || !isalpha(grid6[1]) ||
|
|
!isdigit(grid6[2]) || !isdigit(grid6[3])) {
|
|
// not testing 4'th and 5'th chars because of this case: <PA0SKT/2> JO33 40
|
|
// grid is only 4 chars even though this is a hashed callsign...
|
|
// isalpha(grid6[4]) && isalpha(grid6[5]) ) ) {
|
|
noprint = 1;
|
|
}
|
|
|
|
ihash = (n2 - ntype - 64) / 128;
|
|
if (strncmp(hashtab + ihash * 13, "\0", 1) != 0) {
|
|
sprintf(callsign, "<%s>", hashtab + ihash * 13);
|
|
} else {
|
|
sprintf(callsign, "%5s", "<...>");
|
|
}
|
|
|
|
memset(call_loc_pow, 0, sizeof(char) * 23);
|
|
sprintf(cdbm, "%2d", ndbm);
|
|
strncat(call_loc_pow, callsign, strlen(callsign));
|
|
strncat(call_loc_pow, " ", 1);
|
|
strncat(call_loc_pow, grid6, strlen(grid6));
|
|
strncat(call_loc_pow, " ", 1);
|
|
strncat(call_loc_pow, cdbm, 2);
|
|
strncat(call_loc_pow, "\0", 1);
|
|
|
|
memset(call, 0, sizeof(char) * strlen(callsign) + 1);
|
|
memset(loc, 0, sizeof(char) * strlen(grid6) + 1);
|
|
memset(pwr, 0, sizeof(char) * 2 + 1);
|
|
strncat(call, callsign, strlen(callsign));
|
|
strncat(call, "\0", 1);
|
|
strncat(loc, grid6, strlen(grid6));
|
|
strncat(loc, "\0", 1);
|
|
strncat(pwr, cdbm, 2);
|
|
strncat(pwr, "\0", 1);
|
|
|
|
// I don't know what to do with these... They show up as "A000AA" grids.
|
|
if (ntype == -64)
|
|
noprint = 1;
|
|
}
|
|
return noprint;
|
|
}
|