From d17c48183d1816decddfdc9822ba9df4baf0edf4 Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Sun, 14 Jun 2015 15:21:50 +0000 Subject: [PATCH] Actually add the new wsprsim files this time. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5608 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- lib/wsprd/unpk.c.obsolete | 124 ++++++++++++++++ lib/wsprd/wsprsim.c | 202 +++++++++++++++++++++++++ lib/wsprd/wsprsim_utils.c | 304 ++++++++++++++++++++++++++++++++++++++ lib/wsprd/wsprsim_utils.h | 28 ++++ 4 files changed, 658 insertions(+) create mode 100644 lib/wsprd/unpk.c.obsolete create mode 100644 lib/wsprd/wsprsim.c create mode 100644 lib/wsprd/wsprsim_utils.c create mode 100644 lib/wsprd/wsprsim_utils.h diff --git a/lib/wsprd/unpk.c.obsolete b/lib/wsprd/unpk.c.obsolete new file mode 100644 index 000000000..fae2bcf8b --- /dev/null +++ b/lib/wsprd/unpk.c.obsolete @@ -0,0 +1,124 @@ +/* the routine unpk() is not in wsprd_utils.c */ +#include +#include +#include +#include +#include +#include +#include + +#include "wsprd_utils.h" + +unsigned int nhash_( const void *key, size_t length, uint32_t initval); + +void unpk_(signed char message[], int *nhashtab, char call_loc_pow[]) +{ + int i,n1,n2,n3,ndbm,ihash,nadd,noprint,nh; + char callsign[13],grid[5],grid6[7],cdbm[3]; + static char hashtab[32768][13]; + FILE *fhash; + + if(*nhashtab==1) { + char line[80], hcall[12]; + if( (fhash=fopen("hashtable.txt","r+")) ) { + while (fgets(line, sizeof(line), fhash) != NULL) { + sscanf(line,"%d %s",&nh,hcall); + strcpy(*hashtab+nh*13,hcall); + } + } else { + fhash=fopen("hashtable.txt","w+"); + } + fclose(fhash); + return; + } + + if(*nhashtab==2) { + fhash=fopen("hashtable.txt","w"); + for (i=0; i<32768; i++) { + if( strncmp(hashtab[i],"\0",1) != 0 ) { + fprintf(fhash,"%5d %s\n",i,*hashtab+i*13); + } + } + fclose(fhash); + return; + } + + unpack50(message,&n1,&n2); + unpackcall(n1,callsign); + unpackgrid(n2, grid); + 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); + unpackpfx(n3,callsign); + 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); + ihash=nhash_(callsign,strlen(callsign),(uint32_t)146); + strcpy(*hashtab+ihash*13,callsign); + noprint=0; + } + } else if ( ntype < 0 ) { + ndbm=-(ntype+1); + memset(grid6,0,sizeof(char)*7); + strncat(grid6,callsign+5,1); + strncat(grid6,callsign,5); + ihash=(n2-ntype-64)/128; + if( strncmp(hashtab[ihash],"\0",1) != 0 ) { + sprintf(callsign,"<%s>",hashtab[ihash]); + } 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); + + noprint=0; + +// I don't know what to do with these... They show up as "A000AA" grids. + if( ntype == -64 ) noprint=1; + } + // printf("\nUnpacked in C: %s\n",call_loc_pow); +} diff --git a/lib/wsprd/wsprsim.c b/lib/wsprd/wsprsim.c new file mode 100644 index 000000000..40bb6d67c --- /dev/null +++ b/lib/wsprd/wsprsim.c @@ -0,0 +1,202 @@ +/* + File name: wsprsim.c (first committed to wsjtx June 13, 2015) + */ +#include +#include +#include +#include + +#include "wsprsim_utils.h" +#include "wsprd_utils.h" +#include "fano.h" + +int printdata=0; + +void usage() { + printf("Usage: wsprsim [options] message\n"); + printf(" message format: \"K1ABC FN42 33\"\n"); + printf(" \"PJ4/K1ABC 33\"\n"); + printf(" \" FK52UD 33\"\n"); + printf("Options:\n"); + printf(" -c (print channel symbols)\n"); + printf(" -d (print packed data with zero tail - 11 bytes)\n"); + printf(" -o filename (write a c2 file with this name)\n"); + printf(" -s x (x is snr of signal that is written to .c2 file)\n"); + printf("\n"); + printf(" e.g. ./wsprsim -cds -28 -o 150613_1920.c2 \"K1ABC FN42 33\"\n"); + printf(" then ./wsprd 150613_1920.c2\n"); +} + +int add_signal_vector(float f0, float t0, float amp, unsigned char* symbols + , double* isig, double* qsig) +{ + int i, j, ii, idelay; + double phi=0.0, twopidt, df, dt, dphi; + twopidt=8.0*atan(1.0)/375.0; + df=375.0/256.0; + dt=1/375.0; + idelay=t0/dt; + + for (i=0; i<162; i++) { + dphi=twopidt*(f0 + ( (double)symbols[i]-1.5)*df ); + for ( j=0; j<256; j++ ) { + ii=idelay+256*i+j; + isig[ii]=isig[ii]+amp*cos(phi); + qsig[ii]=qsig[ii]+amp*sin(phi); + phi=phi+dphi; + } + } + return 1; +} + +char* tobinary(int x) +{ + static char b[33]; + b[0] = '\0'; + + long unsigned int z; + for (z = 0x80000000; z > 0; z >>= 1) + { + strcat(b, ((x & z) == z) ? "1" : "0"); + } + + return b; +} + +double gaussrand() +{ + static double V1, V2, S; + static int phase = 0; + double X; + + if(phase == 0) { + do { + double U1 = (double)rand() / RAND_MAX; + double U2 = (double)rand() / RAND_MAX; + + V1 = 2 * U1 - 1; + V2 = 2 * U2 - 1; + S = V1 * V1 + V2 * V2; + } while(S >= 1 || S == 0); + + X = V1 * sqrt(-2 * log(S) / S); + } else + X = V2 * sqrt(-2 * log(S) / S); + + phase = 1 - phase; + + return X; +} + +unsigned long writec2file(char *c2filename, int trmin, double freq + , double *idat, double *qdat) +{ + int i; + float buffer[2*45000]; + memset(buffer,0,sizeof(float)*2*45000); + FILE *fp; + + fp = fopen(c2filename,"wb"); + if( fp == NULL ) { + fprintf(stderr, "Could not open c2 file '%s'\n", c2filename); + return 0; + } + unsigned long nwrite = fwrite(c2filename,sizeof(char),14,fp); + nwrite = fwrite(&trmin, sizeof(int), 1, fp); + nwrite = fwrite(&freq, sizeof(double), 1, fp); + + for(i=0; i<45000; i++) { + buffer[2*i]=idat[i]; + buffer[2*i+1]=-qdat[i]; + } + + nwrite = fwrite(buffer, sizeof(float), 2*45000, fp); + if( nwrite == 2*45000 ) { + return nwrite; + } else { + return 0; + } +} + + +//******************************************************************** +int main(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + int i, c, printchannel=0; + float snr=50.0; + char *message, *c2filename; + // message length is 22 characters + message=malloc(sizeof(char)*23); + c2filename=malloc(sizeof(char)*15); + memset(c2filename,0,sizeof(char)*15); + + while ( (c = getopt(argc, argv, "cdo:s:")) !=-1 ) { + switch (c) { + case 'c': + printchannel=1; + case 'd': + printdata=1; + case 'o': + c2filename = optarg; + break; + case 's': + snr = (float)atoi(optarg); + break; + } + } + + if( optind+1 > argc ) { + usage(); + return 0; + } else { + message=argv[optind]; + } + + unsigned char channel_symbols[162]; + get_wspr_channel_symbols(message, channel_symbols); + + if( printchannel ) { + printf("Channel symbols:\n"); + for (i=0; i<162; i++) { + printf("%d ",channel_symbols[i]); + } + printf("\n"); + } + + // add noise, then signal + double isig[45000], qsig[45000]; + memset(isig,0,sizeof(double)*45000); + memset(qsig,0,sizeof(double)*45000); + + if( snr < 40 ) { + // snr in 375Hz is 8.2 dB higher than in 2500 Hz. + snr=snr+8.2; + snr=pow(10,snr/20.0)*pow(2,0.5); + + for (i = 0; i<45000; i++) { + isig[i]=isig[i]+gaussrand(); + qsig[i]=qsig[i]+gaussrand(); + } + } else { + snr=1.0; + } + + float f0, t0; + f0=0.0; + t0=1.0; + add_signal_vector(f0, t0, snr, channel_symbols, isig, qsig); + + if( strlen(c2filename) >0 ) { + // write a .c2 file + double carrierfreq=10.1387; + int wsprtype=2; + if( strlen(c2filename) != 14 ) { + strcpy(c2filename,"000000_0001.c2"); + } + printf("Writing %s\n",c2filename); + writec2file(c2filename, wsprtype, carrierfreq, isig, qsig); + } + return 1; +} diff --git a/lib/wsprd/wsprsim_utils.c b/lib/wsprd/wsprsim_utils.c new file mode 100644 index 000000000..be3fd6ce7 --- /dev/null +++ b/lib/wsprd/wsprsim_utils.c @@ -0,0 +1,304 @@ +/* + 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; +} diff --git a/lib/wsprd/wsprsim_utils.h b/lib/wsprd/wsprsim_utils.h new file mode 100644 index 000000000..168964fc5 --- /dev/null +++ b/lib/wsprd/wsprsim_utils.h @@ -0,0 +1,28 @@ +#ifndef WSPRSIM_UTILS_H +#define WSPRSIM_UTILS_H + +#include +#include +#include +#include +#include +#include +#include + +extern int printdata; + +char get_locator_character_code(char ch); + +char get_callsign_character_code(char ch); + +long unsigned int pack_grid4_power(char *grid4, int power); + +long unsigned int pack_call(char *callsign); + +void pack_prefix(char *callsign, int32_t *n, int32_t *m, int32_t *nadd ); + +void interleave(unsigned char *sym); + +int get_wspr_channel_symbols(char* message, unsigned char* symbols); + +#endif