1 #include "wspr.hh"
2 #include <iostream>
3 
4 
isValid() const5 bool sdr::WSPRMessage::isValid() const {
6   char call[23], loc[23], pwr[23];
7 
8   const char *ptr = msg, *call_ptr = msg;
9   for(; (*ptr)!=' ' ; ptr++) {}
10   strncpy(call, call_ptr, ptr-call_ptr);
11   call[ptr-call_ptr] = 0; ptr++;
12 
13   const char *loc_ptr = ptr;
14   for(; (*ptr)!=' '; ptr++) {}
15   strncpy(loc, loc_ptr, ptr-loc_ptr);
16   loc[ptr-loc_ptr] = 0; ptr++;
17 
18   const char *pwr_ptr = ptr;
19   for(; (*ptr)!=' '; ptr++) {}
20   strncpy(pwr, pwr_ptr, ptr-pwr_ptr);
21   pwr[ptr-pwr_ptr] = 0;
22 
23   return (4 == strlen(loc)) || (6 == strlen(loc));
24 }
25 
26 std::string
callsign() const27 sdr::WSPRMessage::callsign() const {
28   char call[23];
29 
30   const char *ptr = msg, *call_ptr = msg;
31   for(; (*ptr)!=' ' ; ptr++) {}
32   strncpy(call, call_ptr, ptr-call_ptr);
33   call[ptr-call_ptr] = 0;
34 
35   return call;
36 }
37 
38 
39 std::string
locator() const40 sdr::WSPRMessage::locator() const {
41   char loc[23];
42 
43   const char *ptr = msg;
44   for(; (*ptr)!=' ' ; ptr++) {}
45   ptr++;
46 
47   const char *loc_ptr = ptr;
48   for(; (*ptr)!=' '; ptr++) {}
49   strncpy(loc, loc_ptr, ptr-loc_ptr);
50   loc[ptr-loc_ptr] = 0;
51   return loc;
52 }
53 
power() const54 int sdr::WSPRMessage::power() const {
55   char pwr[23];
56 
57   const char *ptr = msg;
58   for(; (*ptr)!=' ' ; ptr++) {} ptr++;
59   for(; (*ptr)!=' ' ; ptr++) {} ptr++;
60 
61   const char *pwr_ptr = ptr;
62   for(; (*ptr)!=' '; ptr++) {}
63   strncpy(pwr, pwr_ptr, ptr-pwr_ptr);
64   pwr[ptr-pwr_ptr] = 0;
65 
66   return atoi(pwr);
67 }
68 
powerW() const69 float sdr::WSPRMessage::powerW() const {
70   char pwr[23];
71 
72   const char *ptr = msg;
73   for(; (*ptr)!=' ' ; ptr++) {} ptr++;
74   for(; (*ptr)!=' ' ; ptr++) {} ptr++;
75 
76   const char *pwr_ptr = ptr;
77   for(; (*ptr)!=' '; ptr++) {}
78   strncpy(pwr, pwr_ptr, ptr-pwr_ptr);
79   pwr[ptr-pwr_ptr] = 0;
80 
81   return std::pow(10, atof(pwr)/10)/1000;
82 }
83 
84 
85 /*
86  * This function is basically a C re-implementation of the mept162 Fortran routine of the
87  * original WSPR code.
88  */
89 void
wspr_decode(const Buffer<int16_t> & in,std::list<WSPRMessage> & msgs,double Fbfo)90 sdr::wspr_decode(const Buffer<int16_t> &in, std::list<WSPRMessage> &msgs, double Fbfo)
91 {
92   float psd[513];    // Average power spectrum (+/- 256, incl 0, hence 256 + 1 + 256 elments)
93   for (int i=0; i<513; i++) { psd[i] = 0; }
94 
95   cmplx_t *c2 = new cmplx_t[65536];
96   for (int i=0; i<65536; i++) { c2[i].re=0; c2[i].im=0;}
97 
98   int npts=in.size(), nbfo=Fbfo, jz;
99   mix162_(reinterpret_cast<int16_t *>(in.data()), &npts, &nbfo, c2, &jz, psd);
100 
101   float sstf[5*275]; // 5x275 - column major
102   int kz = 0;        // (out) The number of signal candidates found
103   jz = 45000;
104   sync162_(c2, &jz, psd, sstf, &kz);
105 
106   if (0 >= kz) { delete[] c2; return; }
107 
108   cmplx_t *c3 = new cmplx_t[45000];
109   cmplx_t *c4 = new cmplx_t[45000];
110 
111   // For every candidate found
112   for (int k=0; k<kz; k++)
113   {
114     float snrsync = sstf[5*k+0];
115     float snrx    = sstf[5*k+1];
116     float dtx     = sstf[5*k+2];
117     float dfx     = sstf[5*k+3];
118     float drift   = sstf[5*k+4];
119 
120     // Fix frequency drift, store result into c3
121     float a[5] = { -dfx, float(-0.5*drift), 0.0, 0.0, 0.0 };
122     int jz = 45000;
123     for (int i=0; i<45000; i++) { c3[i].re=0; c3[i].im=0; }
124     twkfreq_(c2, c3, &jz, a);
125 
126     // Decode signal
127     char message[22];
128     for (size_t i=0; i<22; i++) { message[i] = 0; }
129 
130     int minsync = 1; int nsync = round(snrsync);
131     if (nsync < 0) { nsync = 0; }
132 
133     float minsnr = -33; int nsnrx = round(snrx);
134     if (nsnrx < minsnr) { nsnrx = minsnr; }
135     if ((nsync < minsync) || (nsnrx < minsnr)) {
136       continue;
137     }
138 
139     float dt = 1./375;
140     for (int idt=0; idt<=128; idt++) {
141       int ii = (idt+1)/2;
142       if (idt%2) { ii = -ii; }
143       int i1 = round((dtx+2.0)/dt) + ii-1; // Start index for synced symbols.
144       for (int i=0; i<45000; i++) { c4[i].re=0; c4[i].im=0; }
145       if (i1 >= 0) {
146         for (int i=i1; i<jz; i++) { c4[i-i1] = c3[i]; }
147       } else {
148         for (int i=0; i<(jz+i1-1); i++) { c4[i+2-i1] = c3[i]; }
149       }
150       int ncycles=0, nerr=0;
151       int metric[512]; int nc4=45000;
152       decode162_(c4, &nc4, message, &ncycles, metric, &nerr);
153       // Check message and store in list
154       if (strncmp("      ", message, 6) && strncmp("000AAA", message, 6)) {
155         WSPRMessage msg;
156         msg.df = dfx; msg.dt = dtx; msg.snr = snrx;
157         memcpy(msg.msg, message, 22);
158         msgs.push_back(msg);
159         break;
160       }
161     }
162   }
163 
164   delete[] c3;
165   delete[] c4;
166 }
167 
168 
169 double
loc_dist(const std::string & loc_a,const std::string & loc_b)170 sdr::loc_dist(const std::string &loc_a, const std::string &loc_b) {
171   int Dmiles, Dkm, nAz=0, nEl=0, nHotAz, nHotABetter;
172   double utch=0;
173   char locA[6]; char locB[6];
174   for (size_t i=0; i<6; i++) { locA[i] = locB[i] = ' '; }
175   memcpy(locA, loc_a.c_str(), std::min(size_t(6),loc_a.size()));
176   memcpy(locB, loc_b.c_str(), std::min(size_t(6),loc_b.size()));
177   azdist_(locA, locB, &utch, &nAz, &nEl, &Dmiles, &Dkm, &nHotAz, &nHotABetter);
178   return Dkm;
179 }
180 
181 void
loc2deg(const std::string & loc,float & lon,float & lat)182 sdr::loc2deg(const std::string &loc, float &lon, float &lat) {
183   char grid[6];
184   memcpy(grid, "      ", 6);
185   memcpy(grid, loc.c_str(), std::min(size_t(6), loc.length()));
186   grid2deg_(grid, &lon, &lat);
187 }
188 
189 std::string
deg2loc(float lon,float lat)190 sdr::deg2loc(float lon, float lat) {
191   char grid[6];
192   memcpy(grid, "      ", 6);
193   deg2grid_(&lon, &lat, grid);
194   return grid;
195 }
196