WSJT-X/lib/wsprd/wsprd_utils.c
Bill Somerville c2c982dba9 Fix an issue with hashing compound callsigns with prefixes shorter than 3 characters
git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@7044 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
2016-08-29 17:02:16 +00:00

339 lines
9.1 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 "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);
}
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 *call_loc_pow, 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);
} 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;
}
} else if ( ntype < 0 ) {
ndbm=-(ntype+1);
memset(grid6,0,sizeof(char)*7);
size_t len=strlen(callsign);
strncat(grid6,callsign+len-1,1);
strncat(grid6,callsign,len-1);
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]) ) ) {
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);
// I don't know what to do with these... They show up as "A000AA" grids.
if( ntype == -64 ) noprint=1;
}
return noprint;
}