rtlsdr-wsprd/wsprd/wsprd_utils.c

370 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"
// FIXME -- 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] = "", 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;
}
strcpy(call, 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 *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[3];
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, "%2d", 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);
memset(call, 0, strlen(callsign) + 1);
memset(loc, 0, strlen(grid) + 1);
memset(pwr, 0, 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 || nu == 10) { // make sure power is OK
ihash = nhash(callsign, strlen(callsign), (uint32_t)146);
strcpy(hashtab + ihash * 13, callsign);
} else {
noprint = 1;
}
memset(call, 0, strlen(callsign) + 1);
memset(loc, 0, 1);
memset(pwr, 0, 2 + 1);
strncat(call, callsign, strlen(callsign));
strncat(call, "\0", 1);
strncat(loc, "\0", 1);
strncat(pwr, cdbm, 2);
strncat(pwr, "\0", 1);
}
} else if (ntype < 0) {
ndbm = -(ntype + 1);
memset(grid6, 0, sizeof(char) * 7);
strncat(grid6, callsign + 5, 1);
strncat(grid6, callsign, 5);
int nu = ndbm % 10;
if ((nu == 0 || nu == 3 || nu == 7 || nu == 10) &&
(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]) ) ) {
ihash = nhash(callsign, strlen(callsign), (uint32_t)146);
strcpy(hashtab + ihash * 13, callsign);
} else {
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, strlen(callsign) + 1);
memset(loc, 0, strlen(grid6) + 1);
memset(pwr, 0, 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;
}