/* 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 . */ #include #include #include #include #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: 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; }