340 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			340 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);
 | |
|         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 && 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;
 | |
| }
 | 
