-
Notifications
You must be signed in to change notification settings - Fork 4
/
ft8mon.cc
177 lines (153 loc) · 4.64 KB
/
ft8mon.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//
// decode FT8 from a sound card
//
// Robert Morris, AB1HL
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <vector>
#include <time.h>
#include <string.h>
#include <mutex>
#include <map>
#include <string>
#include <thread>
#include "snd.h"
#include "util.h"
#include "unpack.h"
#include "ft8.h"
#include "fft.h"
#ifdef USE_HPSDR
#include "hpsdr.h"
#endif
std::mutex cycle_mu;
volatile int cycle_count;
time_t saved_cycle_start;
std::map<std::string,bool> cycle_already;
//
// a91 is 91 bits -- 77 plus the 14-bit CRC.
//
int
hcb(int *a91, double hz0, double hz1, double off,
const char *comment, double snr, int pass,
int correct_bits)
{
std::string msg = unpack(a91);
cycle_mu.lock();
if(cycle_already.count(msg) > 0){
// already decoded this message on this cycle
cycle_mu.unlock();
return 1; // 1 => already seen, don't subtract.
}
cycle_already[msg] = true;
cycle_count += 1;
cycle_mu.unlock();
struct tm result;
gmtime_r(&saved_cycle_start, &result);
printf("%02d%02d%02d %3d %3d %5.2f %6.1f %s\n",
result.tm_hour,
result.tm_min,
result.tm_sec,
(int)snr,
correct_bits,
off - 0.5,
hz0,
msg.c_str());
fflush(stdout);
return 2; // 2 => new decode, do subtract.
}
void
usage()
{
fprintf(stderr, "Usage: ft8mon -card card channel\n");
#ifdef USE_AIRSPYHF
fprintf(stderr, " ft8mon -card airspy serial,mhz\n");
#endif
fprintf(stderr, " ft8mon -levels card channel\n");
fprintf(stderr, " ft8mon -list\n");
fprintf(stderr, " ft8mon -file xxx.wav ...\n");
exit(1);
}
int
main(int argc, char *argv[])
{
int hints[2] = { 2, 0 }; // CQ
double budget = 5; // compute for this many seconds per cycle
extern int fftw_type;
fftw_type = FFTW_ESTIMATE; // rather than FFTW_MEASURE
extern int nthreads;
nthreads = 4; // multi-core
if(argc == 4 && strcmp(argv[1], "-card") == 0){
int wanted_rate = 12000;
SoundIn *sin = SoundIn::open(argv[2], argv[3], wanted_rate);
sin->start();
int rate = sin->rate();
while(1){
// sleep until 14 seconds into the next 15-second cycle.
double tt = now();
long long cycle_start = tt - ((long long)tt % 15);
if(tt - cycle_start >= 14){
double ttt_start;
// asking for no more than 15 seconds of samples in order
// to avoid missing in fftw plan cache.
// the "1" asks for the most recent 15 seconds of samples,
// not the oldest buffered. it causes samples before the
// most recent 15 seconds to be discarded.
std::vector<double> samples = sin->get(15 * rate, ttt_start, 1);
// ttt_start is UNIX time of samples[0].
double ttt_end = ttt_start + samples.size() / rate;
cycle_start = ((long long) (ttt_end / 15)) * 15;
// sample # of 0.5 seconds into the 15-second cycle.
long long nominal_start = samples.size() - rate * (ttt_end - cycle_start - 0.5);
if(nominal_start >= 0 && nominal_start + 10*rate < (int) samples.size()){
struct tm result;
time_t tx = cycle_start;
gmtime_r(&tx, &result);
printf("%02d:%02d:%02d decodes: %d\n",
result.tm_hour,
result.tm_min,
result.tm_sec,
cycle_count);
// make samples exactly 15 seconds, to make
// fftw plan caching more effective.
samples.resize(15 * rate, 0.0);
cycle_mu.lock();
cycle_count = 0;
saved_cycle_start = cycle_start; // for hcb() callback
cycle_already.clear();
cycle_mu.unlock();
entry(samples.data(), samples.size(), nominal_start, rate,
150,
3600, // 2900,
hints, hints, budget, budget, hcb,
0, (struct cdecode *) 0);
}
sleep(2);
}
usleep(100 * 1000); // 0.1 seconds
}
} else if(argc == 4 && strcmp(argv[1], "-levels") == 0){
SoundIn *sin = SoundIn::open(argv[2], argv[3], 12000);
sin->start();
sin->levels();
} else if(argc >= 3 && strcmp(argv[1], "-file") == 0){
for(int ii = 2; ii < argc; ii++){
// the .wav file should start at an even 15-second boundary.
int rate;
std::vector<double> s = readwav(argv[ii], rate);
entry(s.data(), s.size(), 0.5 * rate, rate,
150,
3600, // 2900,
hints, hints, budget, budget, hcb,
0, (struct cdecode *) 0);
}
extern void fft_stats();
// fft_stats();
} else if(argc == 2 && strcmp(argv[1], "-list") == 0){
snd_list();
} else {
usage();
}
}