/* Functions used by wsprsim */ #include "wsprsim_utils.h" #include "wsprd_utils.h" #include "nhash.h" #include "fano.h" char get_locator_character_code(char ch) { if( ch >=48 && ch <=57 ) { //0-9 return ch-48; } if( ch == 32 ) { //space return 36; } if( ch >= 65 && ch <= 82 ) { //A-Z return ch-65; } return -1; } char get_callsign_character_code(char ch) { if( ch >=48 && ch <=57 ) { //0-9 return ch-48; } if( ch == 32 ) { //space return 36; } if( ch >= 65 && ch <= 90 ) { //A-Z return ch-55; } return -1; } long unsigned int pack_grid4_power(char *grid4, int power) { long unsigned int m; m=(179-10*grid4[0]-grid4[2])*180+10*grid4[1]+grid4[3]; m=m*128+power+64; return m; } long unsigned int pack_call(char *callsign) { int i; long unsigned int n; char call6[6]; memset(call6,32,sizeof(char)*6); // callsign is 6 characters in length. Exactly. int call_len = strlen(callsign); if( call_len > 6 ) { return 0; } if( isdigit(*(callsign+2)) ) { for (i=0; i<6; i++) { call6[i]=*(callsign+i); } } else if( isdigit(*(callsign+1)) ) { for (i=0; i<5; i++) { if( callsign[i] != 0 ) { call6[i+1]=*(callsign+i); } } } for (i=0; i<6; i++) { call6[i]=get_callsign_character_code(call6[i]); } n = call6[0]; n = n*36+call6[1]; n = n*10+call6[2]; n = n*27+call6[3]-10; n = n*27+call6[4]-10; n = n*27+call6[5]-10; return n; } void pack_prefix(char *callsign, int32_t *n, int32_t *m, int32_t *nadd ) { int i; char *call6; call6=malloc(sizeof(char)*6); memset(call6,32,sizeof(char)*6); int i1=strcspn(callsign,"/"); if( callsign[i1+2] == 0 ) { //single char suffix for (i=0; i= 48 && nc <= 57 ) { *m=nc-48; } else if ( nc >= 65 && nc <= 90 ) { *m=nc-65+10; } else { *m=38; } *m=60000-32768+*m; } else if( callsign[i1+3]==0 ) { //two char suffix for (i=0; i= 48 && nc <= 57 ) { nc=nc-48; } else if ( nc >= 65 && nc <= 90 ) { nc=nc-65+10; } else { nc=36; } *m=37*(*m)+nc; } *nadd=0; if( *m > 32768 ) { *m=*m-32768; *nadd=1; } } } void interleave(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[j]=sym[p]; p=p+1; } i=i+1; } for (i=0; i<162; i++) { sym[i]=tmp[i]; } } int get_wspr_channel_symbols(char* message, unsigned char* symbols) { int m=0, n=0, ntype=0; int i, j, ihash; unsigned char pr3[162]= {1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0, 0,1,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1, 0,0,0,0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,0,1, 1,0,1,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1, 0,0,1,0,1,1,0,0,0,1,1,0,1,0,1,0,0,0,1,0, 0,0,0,0,1,0,0,1,0,0,1,1,1,0,1,1,0,0,1,1, 0,1,0,0,0,1,1,1,0,0,0,0,0,1,0,1,0,0,1,1, 0,0,0,0,0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0, 0,0}; int nu[10]={0,-1,1,0,-1,2,1,0,-1,1}; char *callsign, *grid, *powstr; char grid4[5]; int i1=strcspn(message," "); int i2=strcspn(message,"/"); int i3=strcspn(message,"<"); int i4=strcspn(message,">"); int mlen=strlen(message); // Use the presence and/or absence of "<" and "/" to decide what // type of message. No sanity checks! Beware! if( (i1>3) & (i1<6) & (i2==mlen) & (i3==mlen) ) { // Type 1 message: K9AN EN50 33 // xxnxxxx xxnn nn const char s[2]=" "; callsign = strtok(message,s); grid = strtok(NULL,s); powstr = strtok(NULL,s); int power = atoi(powstr); n = pack_call(callsign); for (i=0; i<4; i++) { grid4[i]=get_locator_character_code(*(grid+i)); } m = pack_grid4_power(grid4,power); } else if ( i3 == 0 && i4 < mlen ) { // Type 3: EN50WC 33 // FK52UD 37 // send hash instead of callsign to make room for 6 char grid. // if 4-digit locator is specified, 2 spaces are added to the end. callsign=strtok(message,"<> "); grid=strtok(NULL," "); powstr=strtok(NULL," "); int power = atoi(powstr); if( power < 0 ) power=0; if( power > 60 ) power=60; power=power+nu[power%10]; ntype=-(power+1); ihash=nhash(callsign,strlen(callsign),(uint32_t)146); m=128*ihash + ntype + 64; char grid6[6]; memset(grid6,32,sizeof(char)*6); j=strlen(grid); for(i=0; i 60 ) power=60; power=power+nu[power%10]; int n1, ng, nadd; pack_prefix(callsign, &n1, &ng, &nadd); ntype=power + 1 + nadd; m=128*ng+ntype+64; n=n1; } else { printf("Error: bad message format\n"); return 0; } // pack 50 bits + 31 (0) tail bits into 11 bytes unsigned char it, data[11]; memset(data,0,sizeof(char)*11); it=0xFF & (n>>20); data[0]=it; it=0xFF & (n>>12); data[1]=it; it=0xFF & (n>>4); data[2]=it; it= ((n&(0x0F))<<4) + ((m>>18)&(0x0F)); data[3]=it; it=0xFF & (m>>10); data[4]=it; it=0xFF & (m>>2); data[5]=it; it=(m & 0x03)<<6 ; data[6]=it; data[7]=0; data[8]=0; data[9]=0; data[10]=0; if( printdata ) { printf("Data is :"); for (i=0; i<11; i++) { printf("%02X ",data[i]); } printf("\n"); } // make sure that the 11-byte data vector is unpackable // unpack it with the routine that the decoder will use and display // the result. let the operator decide whether it worked. char hashtab[32768][13]; memset(hashtab,0,sizeof(char)*32768*13); char *check_call_loc_pow, *check_callsign; check_call_loc_pow=malloc(sizeof(char)*23); check_callsign=malloc(sizeof(char)*13); signed char check_data[11]; memcpy(check_data,data,sizeof(char)*11); unpk_(check_data,hashtab,check_call_loc_pow,check_callsign); printf("Will decode as: %s\n",check_call_loc_pow); unsigned int nbytes=11; // The message with tail is packed into 11 bytes. unsigned int nencoded=162; unsigned char channelbits[nencoded]; memset(channelbits,0,sizeof(char)*nencoded); encode(channelbits,data,nbytes); interleave(channelbits); for (i=0; i<162; i++) { symbols[i]=2*channelbits[i]+pr3[i]; } return 1; }