AthSpectralScan.cc
Go to the documentation of this file.
1 //
2 // Copyright (c) 2020 Fraunhofer Institute for Applied Information Technology (FIT)
3 // Network Research Group (NET)
4 // Schloss Birlinghoven, 53754 Sankt Augustin, GERMANY
5 // Contact: support@wiback.org
6 //
7 // This file is part of the SENF code tree.
8 // It is licensed under the 3-clause BSD License (aka New BSD License).
9 // See LICENSE.txt in the top level directory for details or visit
10 // https://opensource.org/licenses/BSD-3-Clause
11 //
12 
13 
14 #include "AthSpectralScan.hh"
15 
16 // Custom includes
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
21 #include <senf/Utils/membind.hh>
22 #include <senf/Utils/String.hh>
23 
24 #define prefix_
25 //-/////////////////////////////////////////////////////////////////////////////////////////////////
26 
27 static void dummy(std::uint64_t tsft, std::uint16_t frequency, unsigned numBins, void * spectralSample)
28 {
29 }
30 
32  : spectralEvent_("spectralScan_" + phyName, senf::membind( &senf::emu::AthSpectralScan::handleSpectralEvent, this)),
33  callback_(dummy),
34  frequency_(0),
35  frequencyOffset_(0),
36  spectralFrames_(0),
37  spectralValidSamples_(0),
38  spectralUnknown_(0),
39  spectralTruncated_(0),
40  spectralFrequencyMismatch_(0)
41 {
42  spectralPath_ = "/sys/kernel/debug/ieee80211/" + phyName + "/ath9k";
43  if (access(spectralPath_.c_str(), O_RDONLY) != 0)
44  spectralPath_ = "/sys/kernel/debug/ieee80211/" + phyName + "/ath10k";
45 
46  if (is_ath9k()) {
47  spectralPeriod(4);
49  spectralShortRepeat(true);
50  } else {
51  // for 20Mhz: 64 bins
52  // for 40Mhz: 128 bins
53  // for 80Mhz: 256 bins (might not work)
54  spectralBins(64);
55  }
56  spectralCount(128);
57 }
58 
60 {
61  disable();
62 }
63 
65  const
66 {
67  return access(spectralPath_.c_str(), O_RDONLY) == 0;
68 }
69 
71  const
72 {
73  return spectralPath_.find("ath9k") != std::string::npos;
74 }
75 
77  const
78 {
79  return spectralPath_.find("ath10k") != std::string::npos;
80 }
81 
82 
84 {
85  spectralSetting("spectral_scan_ctl", "disable");
86  frequency_ = 0;
87  frequencyOffset_ = 0;
88  callback_ = dummy;
89 
90  if(spectralHandle_) {
91  spectralEvent_.disable();
92  // flush any remaining samples
93  char buf[4096];
94  while (read(spectralHandle_.fd(), buf, sizeof(buf)) > 0);
95  spectralHandle_.close();
96  }
97 }
98 
99 prefix_ void senf::emu::AthSpectralScan::frequency(std::uint32_t freq, std::uint32_t bandwidth, std::int32_t offset)
100 {
101  if (!spectralHandle_) {
102  frequency_ = 0;
103  frequencyOffset_ = 0;
104  callback_ = dummy;
105  return;
106  }
107 
108  if (bandwidth > 0) {
109  switch (bandwidth) {
110  case 20:
111  spectralBins(64);
112  break;
113  case 40:
114  spectralBins(128);
115  break;
116  case 80:
117  // this might not work !!!
118  spectralBins(256);
119  break;
120  default:
121  spectralBins(64);
122  break;
123  }
124  }
125 
126  frequencyOffset_ = offset;
127 
128  frequency_ = freq;
129  spectralSetting("spectral_scan_ctl", "trigger");
130 }
131 
132 prefix_ void senf::emu::AthSpectralScan::handleSpectralEvent(int _dummy_)
133 {
134  unsigned burst(64);
135 
136  while(SENF_LIKELY(burst-- > 0)) {
137  spectralFrames_++;
139  size_t rd;
140  if (SENF_LIKELY((rd = read(spectralHandle_.fd(), &tlv, sizeof(tlv))) == sizeof(tlv))) {
141  switch (tlv.type) {
142  case ATH_FFT_SAMPLE_HT20:
143  {
144  fft_sample_ht20 ht20;
145  ht20.tlv = tlv;
146  signed length (std::min(be16toh(tlv.length), std::uint16_t(sizeof(ht20) - sizeof(tlv))));
147  if (SENF_LIKELY(read(spectralHandle_.fd(), ((char*)&ht20) + sizeof(tlv), length) == length)) {
148  if (SENF_LIKELY(be16toh(ht20.freq) == frequency_)) {
149  spectralValidSamples_++;
150  callback_(be64toh(ht20.tsf), be16toh(ht20.freq) + frequencyOffset_, SPECTRAL_HT20_NUM_BINS, &ht20);
151  } else {
152  spectralFrequencyMismatch_++;
153  }
154  } else {
155  spectralTruncated_++;
156  burst = 0;
157  }
158  }
159  break;
161  {
162  fft_sample_ht20_40 ht20_40;
163  ht20_40.tlv = tlv;
164  signed length (std::min(be16toh(tlv.length), std::uint16_t(sizeof(ht20_40) - sizeof(tlv))));
165  if (SENF_LIKELY(read(spectralHandle_.fd(), ((char*)&ht20_40) + sizeof(tlv), length) == length)) {
166  if (SENF_LIKELY(be16toh(ht20_40.freq) == frequency_)) {
167  spectralValidSamples_++;
168  callback_(be64toh(ht20_40.tsf), be16toh(ht20_40.freq) + frequencyOffset_, SPECTRAL_HT20_40_NUM_BINS, &ht20_40);
169  } else {
170  spectralFrequencyMismatch_++;
171  }
172  } else {
173  spectralTruncated_++;
174  burst = 0;
175  }
176  }
177  break;
179  {
180  char buf[1024]; // fft_sample_ath10k has avariable length, depending on the number bins
181  fft_sample_ath10k *ath10k = (fft_sample_ath10k *) buf;
182  std::uint16_t offset (0); // offset from actual center freq
183  ath10k->tlv = tlv;
184  signed length (std::min(be16toh(tlv.length), std::uint16_t(sizeof(buf) - sizeof(tlv))));
185  if (SENF_LIKELY(read(spectralHandle_.fd(), ((char*)ath10k) + sizeof(tlv), length) == length)) {
186  if (ath10k->chan_width_mhz == 44) // 40 MHz
187  offset = 10;
188  if (ath10k->chan_width_mhz == 88) // 80 MHz
189  offset = 30;
190  if (SENF_LIKELY(be16toh(ath10k->freq1) == frequency_ + offset)) {
191  signed numBins (length + sizeof(tlv) - sizeof(*ath10k));
192  if (numBins > 0) {
193  spectralValidSamples_++;
194  callback_(be64toh(ath10k->tsf), be16toh(ath10k->freq1) + frequencyOffset_, std::min(numBins, SPECTRAL_ATH10K_MAX_NUM_BINS), ath10k);
195  } else {
196  spectralTruncated_++;
197  burst = 0;
198  }
199  } else {
200  spectralFrequencyMismatch_++;
201  }
202  } else {
203  spectralTruncated_++;
204  burst = 0;
205  }
206  }
207  break;
208  default:
209  spectralUnknown_++;
210  break;
211  }
212  } else {
213  if (rd > 0) {
214  spectralTruncated_++;
215  }
216  burst = 0;
217  }
218  }
219 }
220 
222  const
223 {
224  int cfd;
225  if ((cfd = open( (spectralPath_ + "/" + option).c_str(), O_RDONLY)) != -1) {
226  char buf[128]; int rd;
227  if ((rd = read(cfd, buf, sizeof((buf)))) > 0) {
228  buf[rd] = 0;
229  return atoi(buf);
230  }
231  }
232 
233  return unsigned(-1);
234 }
235 
236 prefix_ bool senf::emu::AthSpectralScan::spectralSetting( std::string option, std::string value)
237 {
238  int cfd;
239  if ((cfd = open( (spectralPath_ + "/" + option).c_str(), O_WRONLY)) != -1) {
240  bool rtn (write(cfd, value.c_str(), value.size()) == signed(value.size()));
241  close(cfd);
242  return rtn;
243  }
244 
245  return false;
246 }
247 
248 prefix_ bool senf::emu::AthSpectralScan::spectralSetting( std::string option, unsigned value)
249 {
250  return spectralSetting(option, senf::str(value));
251 }
252 
254 {
255  if (spectralEvent_.enabled()) {
256  disable();
257  }
258 
259  int dfd;
260  if ((dfd = open((spectralPath_ + "/spectral_scan0").c_str(), O_RDONLY|O_NONBLOCK)) == -1) {
261  return false;
262  }
263 
264  spectralHandle_.SetFd(dfd);
265  spectralEvent_.handle(spectralHandle_);
266  spectralEvent_.events( senf::scheduler::FdEvent::EV_READ);
267  spectralEvent_.enable();
268 
269  spectralSetting("spectral_scan_ctl", "background");
270  spectralSetting("spectral_scan_ctl", "trigger");
271 
272  spectralFrames_ = spectralValidSamples_ = spectralFrequencyMismatch_ = spectralTruncated_ = spectralUnknown_ = 0;
273 
274  callback_ = cb;
275 
276  return true;
277 }
278 
280 {
281  os << (is_ath9k() ? "ath9k" : "ath10k") << (spectralEvent_.enabled() ? " enabled: " : " disabled: ") << "fd " << spectralHandle_.fd()
282  << ", frames total " << spectralFrames_ << ", valid samples " << spectralValidSamples_
283  << ", frequency mismatch " << spectralFrequencyMismatch_
284  << ", truncated " << spectralTruncated_ << ", unknown type " << spectralUnknown_ << std::endl;
285 }
286 
288  const
289 {
290  return spectralSetting("spectral_period");
291 }
292 
294  const
295 {
296  return spectralSetting("spectral_fft_period");
297 }
298 
300  const
301 {
302  return spectralSetting("spectral_short_repeat");
303 }
304 
306  const
307 {
308  return spectralSetting("spectral_count");
309 }
310 
312  const
313 {
314  return spectralSetting("spectral_bins");
315 }
316 
318 {
319  return !is_ath9k() or spectralSetting("spectral_period", v);
320 }
321 
323 {
324  return !is_ath9k() or spectralSetting("spectral_fft_period", v);
325 }
326 
328 {
329  return !is_ath9k() or spectralSetting("spectral_short_repeat", v);
330 }
331 
333 {
334  return spectralSetting("spectral_count", v);
335 }
336 
338 {
339  return !is_ath10k() or spectralSetting("spectral_bins", v);
340 }
341 
342 
343 //-/////////////////////////////////////////////////////////////////////////////////////////////////
344 #undef prefix_
#define SPECTRAL_HT20_40_NUM_BINS
unsigned spectralShortRepeat() const
unsigned spectralCount() const
FdEvent & events(int events)
#define prefix_
unsigned spectralFFTPeriod() const
#define SENF_LIKELY(x)
boost::function< R(Args)> membind(R(T::*fn)(Args), T *ob)
std::int32_t min
struct fft_sample_tlv tlv
bool callback(AthSpectralScanCallback const &cb)
#define SPECTRAL_ATH10K_MAX_NUM_BINS
struct fft_sample_tlv tlv
std::function< void(std::uint64_t tsft, std::uint16_t frequency, unsigned numBins, void *spectralSample)> AthSpectralScanCallback
int fd() const
struct fft_sample_tlv tlv
bool spectralSetting(std::string option, std::string value)
FdEvent & handle(Handle const &handle)
void frequency(std::uint32_t freq, std::uint32_t bandwidth, std::int32_t offset=0)
#define SPECTRAL_HT20_NUM_BINS
AthSpectralScan(std::string phyName)
struct fft_sample_tlv tlv
virtual void close()
void stats(std::ostream &os)
__be16 freq
__be16 length
unsigned spectralPeriod() const