2015-05-27 09:08:28 -04:00
|
|
|
/*
|
|
|
|
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 "wsprd_utils.h"
|
|
|
|
|
|
|
|
#ifndef int32_t
|
|
|
|
#define int32_t int
|
|
|
|
#endif
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-06-17 22:24:06 -04:00
|
|
|
int unpackcall( int32_t ncall, char *call )
|
2015-05-27 09:08:28 -04:00
|
|
|
{
|
|
|
|
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];
|
2016-09-16 15:38:18 -04:00
|
|
|
|
2015-05-27 09:08:28 -04:00
|
|
|
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';
|
|
|
|
}
|
|
|
|
}
|
2015-06-17 22:24:06 -04:00
|
|
|
} else {
|
|
|
|
return 0;
|
2015-05-27 09:08:28 -04:00
|
|
|
}
|
2015-06-17 22:24:06 -04:00
|
|
|
return 1;
|
2015-05-27 09:08:28 -04:00
|
|
|
}
|
|
|
|
|
2015-06-17 22:24:06 -04:00
|
|
|
int unpackgrid( int32_t ngrid, char *grid)
|
2015-05-27 09:08:28 -04:00
|
|
|
{
|
|
|
|
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");
|
2015-06-17 22:24:06 -04:00
|
|
|
return 0;
|
2015-05-27 09:08:28 -04:00
|
|
|
}
|
2015-06-17 22:24:06 -04:00
|
|
|
return 1;
|
2015-05-27 09:08:28 -04:00
|
|
|
}
|
|
|
|
|
2015-06-15 22:47:51 -04:00
|
|
|
int unpackpfx( int32_t nprefix, char *call)
|
2015-05-27 09:08:28 -04:00
|
|
|
{
|
2016-08-29 13:02:16 -04:00
|
|
|
char nc, pfx[4]={'\0'}, tmpcall[7];
|
2015-05-27 09:08:28 -04:00
|
|
|
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;
|
|
|
|
}
|
2016-08-29 13:02:16 -04:00
|
|
|
|
|
|
|
char * p = strrchr(pfx,' ');
|
|
|
|
strcpy(call, p ? p + 1 : pfx);
|
2015-05-27 09:08:28 -04:00
|
|
|
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);
|
|
|
|
}
|
2015-06-15 22:47:51 -04:00
|
|
|
else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
2015-05-27 09:08:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2015-07-25 19:48:53 -04:00
|
|
|
int doublecomp(const void* elem1, const void* elem2)
|
|
|
|
{
|
|
|
|
if(*(const double*)elem1 < *(const double*)elem2)
|
|
|
|
return -1;
|
|
|
|
return *(const double*)elem1 > *(const double*)elem2;
|
|
|
|
}
|
|
|
|
|
2015-05-27 09:08:28 -04:00
|
|
|
int floatcomp(const void* elem1, const void* elem2)
|
|
|
|
{
|
|
|
|
if(*(const float*)elem1 < *(const float*)elem2)
|
|
|
|
return -1;
|
|
|
|
return *(const float*)elem1 > *(const float*)elem2;
|
|
|
|
}
|
|
|
|
|
2015-07-25 19:48:53 -04:00
|
|
|
int unpk_(signed char *message, char *hashtab, char *call_loc_pow, char *callsign)
|
2015-05-27 09:08:28 -04:00
|
|
|
{
|
|
|
|
int n1,n2,n3,ndbm,ihash,nadd,noprint=0;
|
|
|
|
char grid[5],grid6[7],cdbm[3];
|
|
|
|
|
|
|
|
unpack50(message,&n1,&n2);
|
2015-06-17 22:24:06 -04:00
|
|
|
if( !unpackcall(n1,callsign) ) return 1;
|
|
|
|
if( !unpackgrid(n2, grid) ) return 1;
|
2015-05-27 09:08:28 -04:00
|
|
|
int ntype = (n2&127) - 64;
|
|
|
|
callsign[12]=0;
|
|
|
|
grid[4]=0;
|
2016-09-16 15:38:18 -04:00
|
|
|
|
2015-05-27 09:08:28 -04:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
2015-06-15 22:47:51 -04:00
|
|
|
|
2015-05-27 09:08:28 -04:00
|
|
|
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);
|
2015-06-10 10:48:26 -04:00
|
|
|
ihash=nhash(callsign,strlen(callsign),(uint32_t)146);
|
2015-07-25 19:48:53 -04:00
|
|
|
strcpy(hashtab+ihash*13,callsign);
|
2015-05-27 09:08:28 -04:00
|
|
|
} else {
|
|
|
|
nadd=nu;
|
|
|
|
if( nu > 3 ) nadd=nu-3;
|
|
|
|
if( nu > 7 ) nadd=nu-7;
|
|
|
|
n3=n2/128+32768*(nadd-1);
|
2015-06-15 22:47:51 -04:00
|
|
|
if( !unpackpfx(n3,callsign) ) return 1;
|
2015-05-27 09:08:28 -04:00
|
|
|
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
|
2015-06-10 10:48:26 -04:00
|
|
|
ihash=nhash(callsign,strlen(callsign),(uint32_t)146);
|
2015-07-25 19:48:53 -04:00
|
|
|
strcpy(hashtab+ihash*13,callsign);
|
2015-05-27 09:08:28 -04:00
|
|
|
} else noprint=1;
|
|
|
|
}
|
|
|
|
} else if ( ntype < 0 ) {
|
|
|
|
ndbm=-(ntype+1);
|
|
|
|
memset(grid6,0,sizeof(char)*7);
|
2016-08-29 13:02:08 -04:00
|
|
|
size_t len=strlen(callsign);
|
|
|
|
strncat(grid6,callsign+len-1,1);
|
|
|
|
strncat(grid6,callsign,len-1);
|
2015-05-27 09:08:28 -04:00
|
|
|
int nu=ndbm%10;
|
2016-08-29 13:02:08 -04:00
|
|
|
if ((nu != 0 && nu != 3 && nu != 7 && nu != 10) ||
|
|
|
|
!isalpha(grid6[0]) || !isalpha(grid6[1]) ||
|
|
|
|
!isdigit(grid6[2]) || !isdigit(grid6[3])) {
|
2015-05-27 09:08:28 -04:00
|
|
|
// 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]) ) ) {
|
2016-08-29 13:02:08 -04:00
|
|
|
noprint=1;
|
|
|
|
}
|
2015-05-27 09:08:28 -04:00
|
|
|
|
|
|
|
ihash=(n2-ntype-64)/128;
|
2015-07-25 19:48:53 -04:00
|
|
|
if( strncmp(hashtab+ihash*13,"\0",1) != 0 ) {
|
|
|
|
sprintf(callsign,"<%s>",hashtab+ihash*13);
|
2015-05-27 09:08:28 -04:00
|
|
|
} 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);
|
|
|
|
|
|
|
|
|
|
|
|
// I don't know what to do with these... They show up as "A000AA" grids.
|
|
|
|
if( ntype == -64 ) noprint=1;
|
|
|
|
}
|
|
|
|
return noprint;
|
|
|
|
}
|