2012-12-06 16:36:46

by Simon Wunderlich

[permalink] [raw]
Subject: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

This patch(set) is the second iteration of the request for comments for
upcoming spectral scan feature. It adds spectral scan control and dump
features to debugfs. When the open questions regarding interpretation
are answered, I would like to build an interface to nl80211/mac80211.
Please see the open questions below, every hint is kindly appreciated. :)

This feature has been enabled for AR92xx and AR93xx based chipsets.
We've also written a visual evaluation program for these samples (see
screenshot [1] and sourcecode [2]).

Many details are not known due to the fact that I don't have access to
Atheros specifications and details. Many things are done by guessing
and might be wrong. I'm therefore requesting help from Qualcomm/Atheros
guys to confirm or correct my findings. Apart from that, after
discussion I think we could integrate this patchset to allow other
people to work on this as well, even if it is experimental now.

Questions from my end:
1. There are many TODOs/Comments in the patches regarding details,
please answer if you can. :)
2. The output format is very Atheros-dependent. If my finding that
byte n-4 is some kind of offset/exponent, I'd integrate this in
the debugfs output as well
3. The data length varies pretty much, there might be some false
positives/PHY errors which are not FFT data - what should be
the correct length?
4. Is there any special handling for HT40? At least the proprietary
driver symbol names suggest so [3]

(Possible) further work:
1. Integrate this patchset, confirm/correct findings
2. If anyone would like: Atheros proprietary driver seems to
support some kind of classification [3] (is this microwave? cordless
phone? whatever?)
3. If other devices also offer spectral scan support: define a
common interface to use it (not debugfs).

Changes to RFCv1:
* remove nl80211/mac80211 stuff for now, to build a proper interface
after intepretation/output stabilized
* split spectral scan call into config, trigger and wait call, which can
be called as desired (or depending on the mode)
* use relay(fs) to stream spectral scan results (thanks for the hint Felix),
this seems to be much cleaner - as long as we stay in debugfs

[1] http://packetmixer.de/sdl_spec_scan2.png
[2] https://github.com/simonwunderlich/FFT_eval
[3] http://www.wehavemorefun.de/fritzbox/Ath_spectral.ko#Symbole

Simon Wunderlich (1):
ath9k: add spectral scan feature

drivers/net/wireless/ath/ath9k/ar9002_phy.c | 52 ++++++++++
drivers/net/wireless/ath/ath9k/ar9003_phy.c | 52 ++++++++++
drivers/net/wireless/ath/ath9k/ath9k.h | 36 +++++++
drivers/net/wireless/ath/ath9k/debug.c | 148 +++++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/debug.h | 5 +
drivers/net/wireless/ath/ath9k/hw.h | 26 +++++
drivers/net/wireless/ath/ath9k/init.c | 6 ++
drivers/net/wireless/ath/ath9k/mac.h | 7 +-
drivers/net/wireless/ath/ath9k/main.c | 97 ++++++++++++++++++
drivers/net/wireless/ath/ath9k/recv.c | 28 +++++
10 files changed, 455 insertions(+), 2 deletions(-)

--
1.7.10.4



2012-12-18 16:02:56

by Zefir Kurtisi

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

On 12/18/2012 02:46 PM, Simon Wunderlich wrote:
> [...]
>
> Yes, that helped very much, especially the varying data part was something I had no
> clue about. This might also fix the "weird high numbers in the middle of the dump"
> problem I was seeing.
>
If you mean the bin at center frequency, it is because spectral is blind there. To
remove discontinuity, that bin is interpolated, see line
+ // DC value is invalid -> interpolate
+ *dc_pwr = (dc_pwr[-1] + dc_pwr[1]) / 2;

> I'll change the patch according to your explanations, so that only 56 byte data samples
> are returned (at least for HT20).
>
> Thank you very much!
> Simon
>

Good luck!
Zefir

2012-12-14 00:31:01

by Tobias Steinicke

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

Hello Felix and Simon,

I play with it since a while, but without proper results. Your patch
set, Simon helps a lot.

Thanks.

Am 14.12.2012 00:04, schrieb Felix Fietkau:
> On 2012-12-13 11:06 PM, Simon Wunderlich wrote:
>> Hey Felix,
>>
>> thanks, this looks like exactly what I was hoping for!
>>
>>>>> 2. The output format is very Atheros-dependent. If my finding that
>>>>> byte n-4 is some kind of offset/exponent, I'd integrate this in
>>>>> the debugfs output as well
>>> Here's my understanding of the data format:
>>>
>>> HT20:
>>> 56 bytes bin magnitude data (8 bits per bin)
>>> 3 bytes bin maximum values (see below)
>>> 1 byte exponent:
>>> [3:0] - number of bits to shift the magnitude data
>>>
>>
>> Now that is exactly what I was looking for! So shifting the data makes it some
>> kind of exponent, so I wasn't so wrong. :D
>>
>> BTW, does the 56 byte ever change, or may it happen that there is something in front
>> of the FFT bins? or in the middle? I still see different data lengths, and the
>> format looks pretty fixed to me. In theory:
>> * 56 bytes FFT bins
>> * 3 bytes maximum values
>> * 1 byte exponent
>> * 3 byte radar trailer (with bwinfo etc)
>>
>> Thoughts? I'll check my data again, too.
> I don't know about the data length, I haven't run any tests myself.
The data length should be between 62 and 65 bytes for HT20 and between
137 and 140 bytes for HT40. But most of the time I see only 62 for HT20.
>
>>> HT40:
>>> 128 bytes bin magnitude data (64 lower bins, 64 upper bins)
>>> 3 bytes lower bin maximum values (see below)
>>> 3 bytes upper bin maximum values (see below)
>>> 1 byte exponent (like HT20)
>>
>> I have not experimented in HT40 mode yet, but we should add that too. :)
>>>
>>> Bin maximum values:
>>> Byte 1: [1:0] - max_magnitude[1:0]
>>> [7:2] - bitmap_weight[5:0]
>>> Byte 2: [7:0] - max_magnitude[9:2]
>>> Byte 3: [5:0] - max_index[5:0]
>>> [7:6] - max_magnitude[11:10]
>>>
>>
>> OK - not sure what "weight" means, max_magnitude might be the highest of the
>> FFT bins? What "index" is max_index?
> No idea.
>
>> BTW, the FFT bins/magnitude values, are these absolute values or logarithmic
>> values? I'd guess it's absolute from the look of it (applying log() makes it
>> "look better" in the visualization), but not sure.
> I also think it's probably absolute.
>
>>>>> 3. If other devices also offer spectral scan support: define a
>>>>> common interface to use it (not debugfs).
>>> Makes sense. The data should be in an extensible binary format that can
>>> also cover vendor specific extra information. One suggestion would be to
>>> prefix the FFT message data with a netlink-style TLV header describing
>>> the message format (using an enum for data types and an enum for fields,
>>> both of which we can extend if we need to add more data).
>>> That way userspace can use the header to figure out the message size and
>>> can ignore any fields that it does not support.
>>
>> Yeah, sounds good. Although I'm still not sure how we could compose the
>> userspace interface. We might want to configure things like:
>> * count, interval, endless mode?
>> * trigger for a scan
>> * listen for samples (endlessly?) ...
>>
>> The recent patch contains a control file and a listen file - maybe we could
>> have similar commands for iw?
> Let's come up with a proper prototype using the intended data format via
> debugfs in the driver before we add support to nl80211 and iw.
>
>> Also I'm not sure if the performance is very good for the case that we want
>> to stream a lot of samples. About the data format, keeping it somewhat flexible
>> for adding fields in the future is a good idea IMHO.
> I think the TLV header struct description + fixed length messages is
> good for performance. The header only has to be sent once at the
> beginning of the stream, and the conversion to the struct format + the
> relay can be quite fast.
>
>> Also as the exponent seems to be confirmed now, I'd directly apply it to the FFT
>> values when giving it to userspace, like FFT_bin[i] << exponent (if this is the
>> correct form)
> Yes, userspace shouldn't have to deal with that.
>
> - Felix
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>

Tobias


2012-12-18 13:46:23

by Simon Wunderlich

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

Hey Zefir,

On Tue, Dec 18, 2012 at 12:08:57PM +0100, Zefir Kurtisi wrote:
> On 12/13/2012 03:07 PM, Simon Wunderlich wrote:
> > Hey there,
> >
> > just to bump the issue again - isn't there anyone here who can answer
> > some of these questions?
> >
> > [...]
> >
> > Thanks a lot!
> > Simon
> >
> Note: removed John, Johannes and Juoni from CC, since this is ath9k specific
>
>
> Hi Simon,
>
> I have a spectral scanning module up and running in an AR9590 based system and can
> provide you some relevant observations and experiences I made.

Cool, thanks a lot for adding more puzzle pieces to this one! This is very helpful!
>
>
> First off: forget about 40MHz for now. It is either not working at all or way too
> unstable (tested with 9280, 9380, 9580).

Thanks for the warning, I won't waste time on that for now then and post a HT20
only version to begin with.

>
> In 20MHz mode, spectral data is provided in the following format:
>
> +#define SPECTRAL_HT20_NUM_BINS 56
> +#define SPECTRAL_HT20_DC_INDEX (SPECTRAL_HT20_NUM_BINS / 2)
> +#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ht20_fft_packet) + 3)
> +
> +struct ht20_mag_data {
> + u8 all_bins1;
> + u8 max_mag_bits29;
> + u8 all_bins2;
> + u8 max_exp;
> +} __attribute__((packed));
> +
> +struct ht20_fft_packet {
> + u8 bin[SPECTRAL_HT20_NUM_BINS];
> + struct ht20_mag_data mag_data;
> +} __attribute__((packed));
> +
>
> When spectral data is ready, the length is sometimes reported incorrectly, valid
> values are between (SPECTRAL_HT20_TOTAL_DATA_LEN - 1) and
> (SPECTRAL_HT20_TOTAL_DATA_LEN + 2), my code snipped to check the validity is:

OK, this matches with my data (55-58 byte of "spectral data") ...
>
> +static s8 fix_rssi_inv_only(u8 rssi_val)
> +{
> + if (rssi_val == 128)
> + rssi_val = 0;
> + return (s8) rssi_val;
> +}
> +
> +#define SPECTRAL_SCAN_BITMASK 0x10
> +
> +/*
> + * check PHY-error for spectral
> + */
> +bool process_spectral_phyerr(struct ath_softc *sc, void *data,
> + struct ath_rx_status *rs, u64 mactime)
> +{
> + u16 datalen;
> + char *vdata_end;
> + struct ath_hw *ah = sc->sc_ah;
> + struct ath_spectral_scanner *ass = ah->spectral_scanner;
> + struct ath_spectral_data *sd = &ass->spectral_data;
> + u8 pulse_bw_info;
> + s8 rssi;
> + struct spectral_ht20_msg *msg;
> +
> + sd->stats.total_phy_errors++;
> +
> + if (rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) {
> + sd->stats.drop_non_spectral++;
> + return false;
> + }
> +
> + datalen = rs->rs_datalen;
> + if (datalen > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) {
> + sd->stats.drop_len_overflow++;
> + return false;
> + }
> + if (datalen < SPECTRAL_HT20_TOTAL_DATA_LEN - 1) {
> + sd->stats.drop_len_underflow++;
> + return false;
> + }
> +
> + vdata_end = (char *)data + datalen;
> + pulse_bw_info = vdata_end[-1];
> +
> + if (!(pulse_bw_info & SPECTRAL_SCAN_BITMASK)) {
> + sd->stats.drop_non_spectral++;
> + return false;
> + }
> +
> + rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
> +
> + sd->stats.descriptors_processed++;
> +
> + ath_process_spectraldata_ht20(ah, data, datalen, rssi, mactime, msg);
> +
> + sd->run_stats.last_tstamp = mactime;
> + sd->run_stats.spectral_packets++;
> +
> + return true;
> +}
>
> As for the incorrect data, there are 4 cases to consider:
> 1) data length is correct => take the 56 bins as is
> 2) data length is 1 less => duplicate the first bin
> 3) data length is 2 more => remove bins 30 and 32
> 4) data length is 1 more => combine 2) + 3)

... didn't see THAT coming. But that explains it very well how to
handle these varying data lengths. Although I wonder how this can happen.
I guess there are some chip-internal reasons ...

>
> The code snippet to handle this post-processing is:
>
> +static s8 fix_max_index(u8 max_index)
> +{
> + s8 maxindex = max_index;
> + if (max_index > 32)
> + maxindex |= 0xe0;
> + else
> + maxindex &= ~0xe0;
> + maxindex += 29;
> + return maxindex;
> +}
> +
> +static void ath_process_spectraldata_ht20(struct ath_hw *ah, u8 *vdata,
> + u16 datalen, s8 rssi, u64 fulltsf,
> + struct spectral_ht20_msg *nl_msg)
> +{
> + struct ath_spectral_data *sd = &ah->spectral_scanner->spectral_data;
> + u8 *vdata_end = (char*)vdata + datalen;
> + u8 *msg_bin = nl_msg->bin;
> + struct ht20_mag_data *mag = (struct ht20_mag_data *) (vdata_end - 7);
> +
> + switch(datalen - SPECTRAL_HT20_TOTAL_DATA_LEN) {
> + case 0:
> + // correct length
> + memcpy(msg_bin, vdata, SPECTRAL_HT20_NUM_BINS);
> + sd->stats.datalen_ok++;
> + break;
> + case -1:
> + // missing the first byte -> duplicate first as byte 0 and 1
> + msg_bin[0] = vdata[0];
> + memcpy(msg_bin + 1, vdata, SPECTRAL_HT20_NUM_BINS - 1);
> + sd->stats.datalen_m1++;
> + break;
> + case 2:
> + // MAC added 2 extra bytes at bin 30 and 32
> + memcpy(msg_bin, vdata, 30);
> + msg_bin[30] = vdata[31];
> + memcpy(msg_bin + 31, vdata + 33, SPECTRAL_HT20_NUM_BINS - 31);
> + sd->stats.datalen_p2++;
> + break;
> + case 1:
> + // MAC added 2 extra bytes AND first byte missing
> + msg_bin[0] = vdata[0];
> + memcpy(msg_bin + 1, vdata, 30);
> + msg_bin[31] = vdata[31];
> + memcpy(msg_bin + 32, vdata + 33, SPECTRAL_HT20_NUM_BINS - 32);
> + sd->stats.datalen_p2m1++;
> + break;
> + }
> +
> + /* global data */
> + nl_msg->freq = sd->center_freq;
> + nl_msg->rssi = rssi;
> + nl_msg->noise_floor = ah->noise; //ah->caldata->nfCalHist[0].privNF;
> + nl_msg->tstamp = fulltsf;
> +
> + /* extract magnitude scaling data */
> + nl_msg->max_magnitude = (mag->max_mag_bits29 << 2) |
> + ((mag->all_bins1 & 0xc0) >> 6) |
> + ((mag->all_bins2 & 0x03) << 10);
> + nl_msg->bitmap_weight = mag->all_bins1 & 0x3f;
> + nl_msg->max_index = fix_max_index(mag->all_bins2 & 0x3f);
> + nl_msg->max_exp = mag->max_exp & 0x0f;
> +}

Thanks a lot for sharing!

>
> In my system the post-processed FFT raw data is transferred via a netlink
> interface to a spectral_proxy, that forwards it to a connected host for real-time
> inspection and visualization.
>
> The interpretation of the data is as follows: the reported values are given as
> magnitudes, which need to be scaled and converted to absolute power values based
> on the packet's noise floor and RSSI values as follows:
> bin_sum = 10*log(sum[i=1..56](b(i)^2)
> power(i) = noise_floor + RSSI + 10*log(b(i)^2) - bin_sum
>

Ah, very nice. My intepretation code actually looks similar, different factors
and different summing thou. With the fixes in the data (as above) and this, the
visualization will hopefully become clearer. :)

I'll fix my visualization program [1] accordingly.

[1] https://github.com/simonwunderlich/FFT_eval/wiki

> The code fragment to convert magnitude to absolute power values looks like this
> (assuming you transferred the FFT and magnitude data to user space):
> bool convert_data(struct spectral_ht20_msg *msg)
> +{
> + u_int8_t *bin_pwr = msg->bin;
> + u_int8_t *dc_pwr = msg->bin + SPECTRAL_NUM_BINS / 2;
> + int pwr_count = SPECTRAL_NUM_BINS;
> + int8_t rssi = msg->rssi;
> + int8_t max_scale = 1 << msg->max_exp;
> + int16_t max_mag = msg->max_magnitude;
> + int i;
> + int nf0 = msg->noise_floor;
> +
> + float bsum = 0.0;
> +
> + // DC value is invalid -> interpolate
> + *dc_pwr = (dc_pwr[-1] + dc_pwr[1]) / 2;
> +
> + for (i = 0; i < pwr_count; i++)
> + bsum += (bin_pwr[i] * max_scale) * (bin_pwr[i] * max_scale);
> + bsum = log10f(bsum) * 10;
> +
> + for (i = 0; i < pwr_count; i++) {
> + float pwr_val;
> + int16_t val = bin_pwr[i];
> +
> + if (val == 0)
> + val = 1;
> +
> + pwr_val = 20 * log10f((float) val * max_scale);
> + pwr_val += nf0 + rssi - bsum;
> +
> + val = pwr_val;
> + bin_pwr[i] = val;
> + }
> + return true;
> +}
>
>
> That's it, now you should be able to feed the raw data to whatever visualization,
> statistics and classification back-ends.
>
>
> Hope this helps somewhat. My implementation is quite application specific (like
> operational only as monitor, dedicated netlink interface, proxy-forwarding, etc.)
> and not usable for the generic user. That's why I am not posting it here and
> polluting the mailing list. If you (or anybody else out there) would like to test
> it as proof-of-concept, I can provide you the complete OpenWRT integration.

Yes, that helped very much, especially the varying data part was something I had no
clue about. This might also fix the "weird high numbers in the middle of the dump"
problem I was seeing.

I'll change the patch according to your explanations, so that only 56 byte data samples
are returned (at least for HT20).

Thank you very much!
Simon


Attachments:
(No filename) (8.34 kB)
signature.asc (198.00 B)
Digital signature
Download all attachments

2012-12-31 07:48:38

by Adrian Chadd

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

Hi all,

Simon - I've reviewed your code a bit.

You're not (yet) shifting the magnitude values over as needed before
trying to extract the channel power out of it all.

Specifically:

* each bin has a 7 bit value;
* the bin value is scaled by max_exp;
* there's a max magnitude value which I don't think you need for
spectral FFT reports; only radar FFT reports (since in radar FFT
reports, the reported FFT bins are between 0..7/8ths of the maximum
magnitude value)

You're not scaling the data by max_exp in your FFT dump program, so
the values aren't entirely correct.
Are you doing it in the kernel code?

I've just finished my first pass at this and plotting whatever values
I get from the spectral data frames. I'll post more updates as I
find/fix more bugs.

Thanks,



Adrian

2012-12-13 22:07:05

by Simon Wunderlich

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

Hey Felix,

thanks, this looks like exactly what I was hoping for!

On Thu, Dec 13, 2012 at 06:25:31PM +0100, Felix Fietkau wrote:
> On 2012-12-13 3:07 PM, Simon Wunderlich wrote:
> > Hey there,
> >
> > just to bump the issue again - isn't there anyone here who can answer
> > some of these questions?
> >
> > Adrian gave me some hints, but the FFT format is still completely unclear
> > - I would really like to integrate/fix things before bringing this patch(set)
> > to the next level.
> >
> > I'm begging all the Qualcomm/Atheros-affiliated guys on the list to have
> > a look on the questions below and help me out here. :)
> >
> > Thanks a lot!
> > Simon
> >
> > On Thu, Dec 06, 2012 at 05:36:07PM +0100, Simon Wunderlich wrote:
> >> This patch(set) is the second iteration of the request for comments for
> >> upcoming spectral scan feature. It adds spectral scan control and dump
> >> features to debugfs. When the open questions regarding interpretation
> >> are answered, I would like to build an interface to nl80211/mac80211.
> >> Please see the open questions below, every hint is kindly appreciated. :)
> >>
> >> This feature has been enabled for AR92xx and AR93xx based chipsets.
> >> We've also written a visual evaluation program for these samples (see
> >> screenshot [1] and sourcecode [2]).
> >>
> >> Many details are not known due to the fact that I don't have access to
> >> Atheros specifications and details. Many things are done by guessing
> >> and might be wrong. I'm therefore requesting help from Qualcomm/Atheros
> >> guys to confirm or correct my findings. Apart from that, after
> >> discussion I think we could integrate this patchset to allow other
> >> people to work on this as well, even if it is experimental now.
> >>
> >> Questions from my end:
> >> 1. There are many TODOs/Comments in the patches regarding details,
> >> please answer if you can. :)
> >
> > See code comments, e.g. regarding phy error type which are not defined
> > in the headers, etc.
> Here's how to detect usable PHY error reports: Check for PHY error types
> RADAR (5), FALSE_RADAR_EXT (24) or SPECTRAL (38). If it's 38, no further
> validation is necessary. In the other cases, check the last byte
> (bwinfo). If it has bit 4 set, the data is usable for spectral.
>

So 38 is spectral then? Then this is confirmed, I'll extend/correct the
ath9k_phyerr enum appropriately. Didn't know that anyone can
come on "ATH9K_PHYERR_FALSE_RADAR_EXT", I have never seen this on my
hardware, but can add it just to be sure.

I guess the last 3 (radar) bytes are always used to "encapsulate" the
data, also for phyerr 38? I'll then always check bit 4. :)

> >> 2. The output format is very Atheros-dependent. If my finding that
> >> byte n-4 is some kind of offset/exponent, I'd integrate this in
> >> the debugfs output as well
> Here's my understanding of the data format:
>
> HT20:
> 56 bytes bin magnitude data (8 bits per bin)
> 3 bytes bin maximum values (see below)
> 1 byte exponent:
> [3:0] - number of bits to shift the magnitude data
>

Now that is exactly what I was looking for! So shifting the data makes it some
kind of exponent, so I wasn't so wrong. :D

BTW, does the 56 byte ever change, or may it happen that there is something in front
of the FFT bins? or in the middle? I still see different data lengths, and the
format looks pretty fixed to me. In theory:
* 56 bytes FFT bins
* 3 bytes maximum values
* 1 byte exponent
* 3 byte radar trailer (with bwinfo etc)

Thoughts? I'll check my data again, too.


> HT40:
> 128 bytes bin magnitude data (64 lower bins, 64 upper bins)
> 3 bytes lower bin maximum values (see below)
> 3 bytes upper bin maximum values (see below)
> 1 byte exponent (like HT20)

I have not experimented in HT40 mode yet, but we should add that too. :)
>
> Bin maximum values:
> Byte 1: [1:0] - max_magnitude[1:0]
> [7:2] - bitmap_weight[5:0]
> Byte 2: [7:0] - max_magnitude[9:2]
> Byte 3: [5:0] - max_index[5:0]
> [7:6] - max_magnitude[11:10]
>

OK - not sure what "weight" means, max_magnitude might be the highest of the
FFT bins? What "index" is max_index?

BTW, the FFT bins/magnitude values, are these absolute values or logarithmic
values? I'd guess it's absolute from the look of it (applying log() makes it
"look better" in the visualization), but not sure.


> >> 3. The data length varies pretty much, there might be some false
> >> positives/PHY errors which are not FFT data - what should be
> >> the correct length?
> See above.
>
> >> 4. Is there any special handling for HT40? At least the proprietary
> >> driver symbol names suggest so [3]
> >
> > -> this one is solved: yes, there is. it has more FFT bins. Although
> > I didn't see that yet (I doubt they are the "small" variations I have seen,
> > like up to 4 byte, I'd expect like double frame size).
> See above.
>

Yup, thanks for the detailed explanation!

> >> (Possible) further work:
> >> 1. Integrate this patchset, confirm/correct findings
> >> 2. If anyone would like: Atheros proprietary driver seems to
> >> support some kind of classification [3] (is this microwave? cordless
> >> phone? whatever?)
> That should be done in userspace.
>

I agree.

> >> 3. If other devices also offer spectral scan support: define a
> >> common interface to use it (not debugfs).
> Makes sense. The data should be in an extensible binary format that can
> also cover vendor specific extra information. One suggestion would be to
> prefix the FFT message data with a netlink-style TLV header describing
> the message format (using an enum for data types and an enum for fields,
> both of which we can extend if we need to add more data).
> That way userspace can use the header to figure out the message size and
> can ignore any fields that it does not support.

Yeah, sounds good. Although I'm still not sure how we could compose the
userspace interface. We might want to configure things like:
* count, interval, endless mode?
* trigger for a scan
* listen for samples (endlessly?) ...

The recent patch contains a control file and a listen file - maybe we could
have similar commands for iw?

Also I'm not sure if the performance is very good for the case that we want
to stream a lot of samples. About the data format, keeping it somewhat flexible
for adding fields in the future is a good idea IMHO.

Also as the exponent seems to be confirmed now, I'd directly apply it to the FFT
values when giving it to userspace, like FFT_bin[i] << exponent (if this is the
correct form)

> I hope this helps.

Definitely! That was what I was hoping for! Thanks for sharing this info. :)

Cheers,
Simon


Attachments:
(No filename) (6.54 kB)
signature.asc (198.00 B)
Digital signature
Download all attachments

2012-12-31 14:47:19

by Adrian Chadd

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

On 31 December 2012 00:46, Simon Wunderlich
<[email protected]> wrote:

>> Your frame length logic is OK for the short spectral scan reports, but
>> not useful for the longer aggregate reports (short_rpt=0 IIRC.)
>
> Yeah, I've always used short_rpt=1 AFAIR.
>>
>> Here there's >1 FFT report in a frame, _and_ it could be corrupted,
>> _and_ it could be short.
>
> That sounds like a lot of fun :P

Yeah. Ew.

> Before asking questions, I'll wait for your userland lib and see what
> it does. I've seen some longer frames as well occasionally when starting
> to play with spectral, but didn't care too much as I didn't know how to
> handle it. Anyway, I prefer hiding the corrupt and messy part and only
> pass "clean data" to userspace, at least with the Linux implementation.

I'm taking the opposite approach - I'll pass the PHY error frames up
to userland untouched (and with extra radiotap vendor info like
per-chain RSSI/NF calibration values) and do the fixups in userland.

The only fixups I'd do in kernel is stuff that requires register
hackery to do. Otherwise I have to replace the driver each time I want
to change/extend/fix something.

I'm doing the same with radar pulse handling - it's exposed via
bpf/radiotap the same way that any other frame is. Userland can then
just see what kind of packet it is by inspecting the radiotap header
and do what it needs to.

> If you have some code handling and/or correct these long dataframes, I'd
> be happy to integrate it if possible.

Well right now I'm just trying to finish writing a thin layer to
decode (and make sure I'm decoding the correct data!) before I worry
about finding/fixing corrupted frames.
I'll try to commit what I have thus far to FreeBSD today/tomorrow but
I also have real work to get done.

I've taken your code and broken it out a bit to support multiple data
sources, rather than just a hard-coded single data source from a file.
That way I can (in theory) just add a FreeBSD data source and
represent data as you need.

Also, yes - I'm using whatever your FFT_eval code in userland is. :-)



Adrian

2012-12-13 23:04:15

by Felix Fietkau

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

On 2012-12-13 11:06 PM, Simon Wunderlich wrote:
> Hey Felix,
>
> thanks, this looks like exactly what I was hoping for!
>
>> >> 2. The output format is very Atheros-dependent. If my finding that
>> >> byte n-4 is some kind of offset/exponent, I'd integrate this in
>> >> the debugfs output as well
>> Here's my understanding of the data format:
>>
>> HT20:
>> 56 bytes bin magnitude data (8 bits per bin)
>> 3 bytes bin maximum values (see below)
>> 1 byte exponent:
>> [3:0] - number of bits to shift the magnitude data
>>
>
> Now that is exactly what I was looking for! So shifting the data makes it some
> kind of exponent, so I wasn't so wrong. :D
>
> BTW, does the 56 byte ever change, or may it happen that there is something in front
> of the FFT bins? or in the middle? I still see different data lengths, and the
> format looks pretty fixed to me. In theory:
> * 56 bytes FFT bins
> * 3 bytes maximum values
> * 1 byte exponent
> * 3 byte radar trailer (with bwinfo etc)
>
> Thoughts? I'll check my data again, too.
I don't know about the data length, I haven't run any tests myself.

>> HT40:
>> 128 bytes bin magnitude data (64 lower bins, 64 upper bins)
>> 3 bytes lower bin maximum values (see below)
>> 3 bytes upper bin maximum values (see below)
>> 1 byte exponent (like HT20)
>
> I have not experimented in HT40 mode yet, but we should add that too. :)
>>
>> Bin maximum values:
>> Byte 1: [1:0] - max_magnitude[1:0]
>> [7:2] - bitmap_weight[5:0]
>> Byte 2: [7:0] - max_magnitude[9:2]
>> Byte 3: [5:0] - max_index[5:0]
>> [7:6] - max_magnitude[11:10]
>>
>
> OK - not sure what "weight" means, max_magnitude might be the highest of the
> FFT bins? What "index" is max_index?
No idea.

> BTW, the FFT bins/magnitude values, are these absolute values or logarithmic
> values? I'd guess it's absolute from the look of it (applying log() makes it
> "look better" in the visualization), but not sure.
I also think it's probably absolute.

>> >> 3. If other devices also offer spectral scan support: define a
>> >> common interface to use it (not debugfs).
>> Makes sense. The data should be in an extensible binary format that can
>> also cover vendor specific extra information. One suggestion would be to
>> prefix the FFT message data with a netlink-style TLV header describing
>> the message format (using an enum for data types and an enum for fields,
>> both of which we can extend if we need to add more data).
>> That way userspace can use the header to figure out the message size and
>> can ignore any fields that it does not support.
>
> Yeah, sounds good. Although I'm still not sure how we could compose the
> userspace interface. We might want to configure things like:
> * count, interval, endless mode?
> * trigger for a scan
> * listen for samples (endlessly?) ...
>
> The recent patch contains a control file and a listen file - maybe we could
> have similar commands for iw?
Let's come up with a proper prototype using the intended data format via
debugfs in the driver before we add support to nl80211 and iw.

> Also I'm not sure if the performance is very good for the case that we want
> to stream a lot of samples. About the data format, keeping it somewhat flexible
> for adding fields in the future is a good idea IMHO.
I think the TLV header struct description + fixed length messages is
good for performance. The header only has to be sent once at the
beginning of the stream, and the conversion to the struct format + the
relay can be quite fast.

> Also as the exponent seems to be confirmed now, I'd directly apply it to the FFT
> values when giving it to userspace, like FFT_bin[i] << exponent (if this is the
> correct form)
Yes, userspace shouldn't have to deal with that.

- Felix

2012-12-16 03:48:05

by Adrian Chadd

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

Let's just get the API working and expose those frames to userland;
then we can start playing with things in more depth.

I'll go dig up the radar FFT formats too in a minute and see what I can do.



Adrian

2012-12-13 17:25:41

by Felix Fietkau

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

On 2012-12-13 3:07 PM, Simon Wunderlich wrote:
> Hey there,
>
> just to bump the issue again - isn't there anyone here who can answer
> some of these questions?
>
> Adrian gave me some hints, but the FFT format is still completely unclear
> - I would really like to integrate/fix things before bringing this patch(set)
> to the next level.
>
> I'm begging all the Qualcomm/Atheros-affiliated guys on the list to have
> a look on the questions below and help me out here. :)
>
> Thanks a lot!
> Simon
>
> On Thu, Dec 06, 2012 at 05:36:07PM +0100, Simon Wunderlich wrote:
>> This patch(set) is the second iteration of the request for comments for
>> upcoming spectral scan feature. It adds spectral scan control and dump
>> features to debugfs. When the open questions regarding interpretation
>> are answered, I would like to build an interface to nl80211/mac80211.
>> Please see the open questions below, every hint is kindly appreciated. :)
>>
>> This feature has been enabled for AR92xx and AR93xx based chipsets.
>> We've also written a visual evaluation program for these samples (see
>> screenshot [1] and sourcecode [2]).
>>
>> Many details are not known due to the fact that I don't have access to
>> Atheros specifications and details. Many things are done by guessing
>> and might be wrong. I'm therefore requesting help from Qualcomm/Atheros
>> guys to confirm or correct my findings. Apart from that, after
>> discussion I think we could integrate this patchset to allow other
>> people to work on this as well, even if it is experimental now.
>>
>> Questions from my end:
>> 1. There are many TODOs/Comments in the patches regarding details,
>> please answer if you can. :)
>
> See code comments, e.g. regarding phy error type which are not defined
> in the headers, etc.
Here's how to detect usable PHY error reports: Check for PHY error types
RADAR (5), FALSE_RADAR_EXT (24) or SPECTRAL (38). If it's 38, no further
validation is necessary. In the other cases, check the last byte
(bwinfo). If it has bit 4 set, the data is usable for spectral.

>> 2. The output format is very Atheros-dependent. If my finding that
>> byte n-4 is some kind of offset/exponent, I'd integrate this in
>> the debugfs output as well
Here's my understanding of the data format:

HT20:
56 bytes bin magnitude data (8 bits per bin)
3 bytes bin maximum values (see below)
1 byte exponent:
[3:0] - number of bits to shift the magnitude data

HT40:
128 bytes bin magnitude data (64 lower bins, 64 upper bins)
3 bytes lower bin maximum values (see below)
3 bytes upper bin maximum values (see below)
1 byte exponent (like HT20)

Bin maximum values:
Byte 1: [1:0] - max_magnitude[1:0]
[7:2] - bitmap_weight[5:0]
Byte 2: [7:0] - max_magnitude[9:2]
Byte 3: [5:0] - max_index[5:0]
[7:6] - max_magnitude[11:10]

>> 3. The data length varies pretty much, there might be some false
>> positives/PHY errors which are not FFT data - what should be
>> the correct length?
See above.

>> 4. Is there any special handling for HT40? At least the proprietary
>> driver symbol names suggest so [3]
>
> -> this one is solved: yes, there is. it has more FFT bins. Although
> I didn't see that yet (I doubt they are the "small" variations I have seen,
> like up to 4 byte, I'd expect like double frame size).
See above.

>> (Possible) further work:
>> 1. Integrate this patchset, confirm/correct findings
>> 2. If anyone would like: Atheros proprietary driver seems to
>> support some kind of classification [3] (is this microwave? cordless
>> phone? whatever?)
That should be done in userspace.

>> 3. If other devices also offer spectral scan support: define a
>> common interface to use it (not debugfs).
Makes sense. The data should be in an extensible binary format that can
also cover vendor specific extra information. One suggestion would be to
prefix the FFT message data with a netlink-style TLV header describing
the message format (using an enum for data types and an enum for fields,
both of which we can extend if we need to add more data).
That way userspace can use the header to figure out the message size and
can ignore any fields that it does not support.

I hope this helps.

- Felix

2012-12-14 00:31:01

by Adrian Chadd

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

Hi,

So the payload length will be based on HT20 vs HT40, but also the
spectral scan FFT config. You can specify how many samples to take
each time and whether to gather them "short" or "not short" time
interval.

So fiddle around with the number of samples in the FFT config and
you'll see different sized payloads.

Since Felix has just posted the spectral scan FFT format, we may as
well post the radar FFT format. :)



Adrian

2012-12-28 03:11:14

by Adrian Chadd

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

On 18 December 2012 05:46, Simon Wunderlich
<[email protected]> wrote:

>> As for the incorrect data, there are 4 cases to consider:
>> 1) data length is correct => take the 56 bins as is
>> 2) data length is 1 less => duplicate the first bin
>> 3) data length is 2 more => remove bins 30 and 32
>> 4) data length is 1 more => combine 2) + 3)
>
> ... didn't see THAT coming. But that explains it very well how to
> handle these varying data lengths. Although I wonder how this can happen.
> I guess there are some chip-internal reasons ...

It's a known problem. It's fixed in later silicon.

But yes, that's quite a bit of analysis by Zefir to classify and
repair those samples. Good work!


Adrian

2012-12-31 08:40:36

by Simon Wunderlich

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

Hello Adrian,

On Sun, Dec 30, 2012 at 11:48:36PM -0800, Adrian Chadd wrote:
> Hi all,
>
> Simon - I've reviewed your code a bit.

Cool, thanks a lot! Since you are replying to v2, I hope you are
aware that I posted a v3 version[1] already?

[1] http://thread.gmane.org/gmane.linux.kernel.wireless.general/101735
>
> You're not (yet) shifting the magnitude values over as needed before
> trying to extract the channel power out of it all.
>
> Specifically:
>
> * each bin has a 7 bit value;
> * the bin value is scaled by max_exp;
> * there's a max magnitude value which I don't think you need for
> spectral FFT reports; only radar FFT reports (since in radar FFT
> reports, the reported FFT bins are between 0..7/8ths of the maximum
> magnitude value)
>
> You're not scaling the data by max_exp in your FFT dump program, so
> the values aren't entirely correct.
> Are you doing it in the kernel code?

In the latest patchset I'm doing scaling already in the kernel driver.
I haven't done this in the v2 patchset yet, something for scaling
was included in the then-corresponding FFT dump program. As I'm using
the new format now with the pre-processed and scaled dumps from the
kernel, this code has been removed in my FFT dump program. :)

>
> I've just finished my first pass at this and plotting whatever values
> I get from the spectral data frames. I'll post more updates as I
> find/fix more bugs.

Cool! What kind of tool do you use for plotting? Maybe we can use
something (my simple program, yours, whatever) for both Linux and
FreeBSD?

Thanks as always for the feedback!

Cheers,
Simon


Attachments:
(No filename) (1.57 kB)
signature.asc (198.00 B)
Digital signature
Download all attachments

2012-12-31 05:33:08

by Adrian Chadd

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

Hi,

I'm just going through and hacking on this now for FreeBSD (and
userland decoding, rather than kernel side decoding.)

Your frame length logic is OK for the short spectral scan reports, but
not useful for the longer aggregate reports (short_rpt=0 IIRC.)

Here there's >1 FFT report in a frame, _and_ it could be corrupted,
_and_ it could be short.

I'm just writing a userland library now to start parsing and
correcting these. It's likely that I can use your logic for the short
spectral reports, but I won't be able to use them for the longer
aggregate reports. We'll need to find some other way to determine that
they've been corrupted and just toss/correct as appropriate.

Thanks for digging into this!



Adrian

On 18 December 2012 03:08, Zefir Kurtisi <[email protected]> wrote:
> On 12/13/2012 03:07 PM, Simon Wunderlich wrote:
>> Hey there,
>>
>> just to bump the issue again - isn't there anyone here who can answer
>> some of these questions?
>>
>> [...]
>>
>> Thanks a lot!
>> Simon
>>
> Note: removed John, Johannes and Juoni from CC, since this is ath9k specific
>
>
> Hi Simon,
>
> I have a spectral scanning module up and running in an AR9590 based system and can
> provide you some relevant observations and experiences I made.
>
>
> First off: forget about 40MHz for now. It is either not working at all or way too
> unstable (tested with 9280, 9380, 9580).
>
> In 20MHz mode, spectral data is provided in the following format:
>
> +#define SPECTRAL_HT20_NUM_BINS 56
> +#define SPECTRAL_HT20_DC_INDEX (SPECTRAL_HT20_NUM_BINS / 2)
> +#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ht20_fft_packet) + 3)
> +
> +struct ht20_mag_data {
> + u8 all_bins1;
> + u8 max_mag_bits29;
> + u8 all_bins2;
> + u8 max_exp;
> +} __attribute__((packed));
> +
> +struct ht20_fft_packet {
> + u8 bin[SPECTRAL_HT20_NUM_BINS];
> + struct ht20_mag_data mag_data;
> +} __attribute__((packed));
> +
>
> When spectral data is ready, the length is sometimes reported incorrectly, valid
> values are between (SPECTRAL_HT20_TOTAL_DATA_LEN - 1) and
> (SPECTRAL_HT20_TOTAL_DATA_LEN + 2), my code snipped to check the validity is:
>
> +static s8 fix_rssi_inv_only(u8 rssi_val)
> +{
> + if (rssi_val == 128)
> + rssi_val = 0;
> + return (s8) rssi_val;
> +}
> +
> +#define SPECTRAL_SCAN_BITMASK 0x10
> +
> +/*
> + * check PHY-error for spectral
> + */
> +bool process_spectral_phyerr(struct ath_softc *sc, void *data,
> + struct ath_rx_status *rs, u64 mactime)
> +{
> + u16 datalen;
> + char *vdata_end;
> + struct ath_hw *ah = sc->sc_ah;
> + struct ath_spectral_scanner *ass = ah->spectral_scanner;
> + struct ath_spectral_data *sd = &ass->spectral_data;
> + u8 pulse_bw_info;
> + s8 rssi;
> + struct spectral_ht20_msg *msg;
> +
> + sd->stats.total_phy_errors++;
> +
> + if (rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) {
> + sd->stats.drop_non_spectral++;
> + return false;
> + }
> +
> + datalen = rs->rs_datalen;
> + if (datalen > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) {
> + sd->stats.drop_len_overflow++;
> + return false;
> + }
> + if (datalen < SPECTRAL_HT20_TOTAL_DATA_LEN - 1) {
> + sd->stats.drop_len_underflow++;
> + return false;
> + }
> +
> + vdata_end = (char *)data + datalen;
> + pulse_bw_info = vdata_end[-1];
> +
> + if (!(pulse_bw_info & SPECTRAL_SCAN_BITMASK)) {
> + sd->stats.drop_non_spectral++;
> + return false;
> + }
> +
> + rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
> +
> + sd->stats.descriptors_processed++;
> +
> + ath_process_spectraldata_ht20(ah, data, datalen, rssi, mactime, msg);
> +
> + sd->run_stats.last_tstamp = mactime;
> + sd->run_stats.spectral_packets++;
> +
> + return true;
> +}
>
> As for the incorrect data, there are 4 cases to consider:
> 1) data length is correct => take the 56 bins as is
> 2) data length is 1 less => duplicate the first bin
> 3) data length is 2 more => remove bins 30 and 32
> 4) data length is 1 more => combine 2) + 3)
>
> The code snippet to handle this post-processing is:
>
> +static s8 fix_max_index(u8 max_index)
> +{
> + s8 maxindex = max_index;
> + if (max_index > 32)
> + maxindex |= 0xe0;
> + else
> + maxindex &= ~0xe0;
> + maxindex += 29;
> + return maxindex;
> +}
> +
> +static void ath_process_spectraldata_ht20(struct ath_hw *ah, u8 *vdata,
> + u16 datalen, s8 rssi, u64 fulltsf,
> + struct spectral_ht20_msg *nl_msg)
> +{
> + struct ath_spectral_data *sd = &ah->spectral_scanner->spectral_data;
> + u8 *vdata_end = (char*)vdata + datalen;
> + u8 *msg_bin = nl_msg->bin;
> + struct ht20_mag_data *mag = (struct ht20_mag_data *) (vdata_end - 7);
> +
> + switch(datalen - SPECTRAL_HT20_TOTAL_DATA_LEN) {
> + case 0:
> + // correct length
> + memcpy(msg_bin, vdata, SPECTRAL_HT20_NUM_BINS);
> + sd->stats.datalen_ok++;
> + break;
> + case -1:
> + // missing the first byte -> duplicate first as byte 0 and 1
> + msg_bin[0] = vdata[0];
> + memcpy(msg_bin + 1, vdata, SPECTRAL_HT20_NUM_BINS - 1);
> + sd->stats.datalen_m1++;
> + break;
> + case 2:
> + // MAC added 2 extra bytes at bin 30 and 32
> + memcpy(msg_bin, vdata, 30);
> + msg_bin[30] = vdata[31];
> + memcpy(msg_bin + 31, vdata + 33, SPECTRAL_HT20_NUM_BINS - 31);
> + sd->stats.datalen_p2++;
> + break;
> + case 1:
> + // MAC added 2 extra bytes AND first byte missing
> + msg_bin[0] = vdata[0];
> + memcpy(msg_bin + 1, vdata, 30);
> + msg_bin[31] = vdata[31];
> + memcpy(msg_bin + 32, vdata + 33, SPECTRAL_HT20_NUM_BINS - 32);
> + sd->stats.datalen_p2m1++;
> + break;
> + }
> +
> + /* global data */
> + nl_msg->freq = sd->center_freq;
> + nl_msg->rssi = rssi;
> + nl_msg->noise_floor = ah->noise; //ah->caldata->nfCalHist[0].privNF;
> + nl_msg->tstamp = fulltsf;
> +
> + /* extract magnitude scaling data */
> + nl_msg->max_magnitude = (mag->max_mag_bits29 << 2) |
> + ((mag->all_bins1 & 0xc0) >> 6) |
> + ((mag->all_bins2 & 0x03) << 10);
> + nl_msg->bitmap_weight = mag->all_bins1 & 0x3f;
> + nl_msg->max_index = fix_max_index(mag->all_bins2 & 0x3f);
> + nl_msg->max_exp = mag->max_exp & 0x0f;
> +}
>
> In my system the post-processed FFT raw data is transferred via a netlink
> interface to a spectral_proxy, that forwards it to a connected host for real-time
> inspection and visualization.
>
> The interpretation of the data is as follows: the reported values are given as
> magnitudes, which need to be scaled and converted to absolute power values based
> on the packet's noise floor and RSSI values as follows:
> bin_sum = 10*log(sum[i=1..56](b(i)^2)
> power(i) = noise_floor + RSSI + 10*log(b(i)^2) - bin_sum
>
> The code fragment to convert magnitude to absolute power values looks like this
> (assuming you transferred the FFT and magnitude data to user space):
> bool convert_data(struct spectral_ht20_msg *msg)
> +{
> + u_int8_t *bin_pwr = msg->bin;
> + u_int8_t *dc_pwr = msg->bin + SPECTRAL_NUM_BINS / 2;
> + int pwr_count = SPECTRAL_NUM_BINS;
> + int8_t rssi = msg->rssi;
> + int8_t max_scale = 1 << msg->max_exp;
> + int16_t max_mag = msg->max_magnitude;
> + int i;
> + int nf0 = msg->noise_floor;
> +
> + float bsum = 0.0;
> +
> + // DC value is invalid -> interpolate
> + *dc_pwr = (dc_pwr[-1] + dc_pwr[1]) / 2;
> +
> + for (i = 0; i < pwr_count; i++)
> + bsum += (bin_pwr[i] * max_scale) * (bin_pwr[i] * max_scale);
> + bsum = log10f(bsum) * 10;
> +
> + for (i = 0; i < pwr_count; i++) {
> + float pwr_val;
> + int16_t val = bin_pwr[i];
> +
> + if (val == 0)
> + val = 1;
> +
> + pwr_val = 20 * log10f((float) val * max_scale);
> + pwr_val += nf0 + rssi - bsum;
> +
> + val = pwr_val;
> + bin_pwr[i] = val;
> + }
> + return true;
> +}
>
>
> That's it, now you should be able to feed the raw data to whatever visualization,
> statistics and classification back-ends.
>
>
> Hope this helps somewhat. My implementation is quite application specific (like
> operational only as monitor, dedicated netlink interface, proxy-forwarding, etc.)
> and not usable for the generic user. That's why I am not posting it here and
> polluting the mailing list. If you (or anybody else out there) would like to test
> it as proof-of-concept, I can provide you the complete OpenWRT integration.
>
>
> Cheers,
> Zefir
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2012-12-06 16:36:46

by Simon Wunderlich

[permalink] [raw]
Subject: [RFCv2] ath9k: add spectral scan feature

Adds the spectral scan feature for ath9k. AR92xx and AR93xx chips
are supported for now. The spectral scan is triggered by configuring
a mode through a debugfs control file. Samples can be gathered via
another relay debugfs file.

Essentially, to try it out:

echo chanscan > /sys/kernel/debug/ieee80211/phy0/ath9k/spectral_scan_ctl
iw dev wlan0 scan
cat /sys/kernel/debug/ieee80211/phy0/ath9k/spectral_scan0
echo disable > /sys/kernel/debug/ieee80211/phy0/ath9k/spectral_scan_ctl

This feature is still experimental. After parameters have been
confirmed, the debugfs can be replaced by an nl80211/mac80211 interface.

The special "chanscan" mode is used to perform spectral scan while
mac80211 is scanning for channels. To allow this,
sw_scan_start/complete() ops have been added.

Signed-off-by: Simon Wunderlich <[email protected]>
Signed-off-by: Mathias Kretschmer <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9002_phy.c | 52 ++++++++++
drivers/net/wireless/ath/ath9k/ar9003_phy.c | 52 ++++++++++
drivers/net/wireless/ath/ath9k/ath9k.h | 36 +++++++
drivers/net/wireless/ath/ath9k/debug.c | 148 +++++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/debug.h | 5 +
drivers/net/wireless/ath/ath9k/hw.h | 26 +++++
drivers/net/wireless/ath/ath9k/init.c | 6 ++
drivers/net/wireless/ath/ath9k/mac.h | 7 +-
drivers/net/wireless/ath/ath9k/main.c | 97 ++++++++++++++++++
drivers/net/wireless/ath/ath9k/recv.c | 28 +++++
10 files changed, 455 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index 846dd79..50584df 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -555,6 +555,55 @@ static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
}

+void ar9002_hw_spectral_scan_config(struct ath_hw *ah,
+ struct ath_spec_scan *param)
+{
+ if (!param->enabled) {
+ REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_ENABLE);
+ return;
+ }
+ REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
+
+ if (param->short_repeat)
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+ else
+ REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_COUNT, param->count);
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period);
+
+ return;
+}
+
+static void ar9002_hw_spectral_scan_trigger(struct ath_hw *ah)
+{
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
+ /* Activate spectral scan */
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_ACTIVE);
+}
+
+static void ar9002_hw_spectral_scan_wait(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ /* Poll for spectral scan complete */
+ if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_ACTIVE,
+ 0, AH_WAIT_TIMEOUT)) {
+ ath_err(common, "spectral scan wait failed\n");
+ return;
+ }
+}
+
void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
@@ -571,6 +620,9 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)

ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get;
ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set;
+ ops->spectral_scan_config = ar9002_hw_spectral_scan_config;
+ ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger;
+ ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait;

ar9002_hw_set_nf_limits(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index ce19c09..e3d5a5b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -1450,6 +1450,55 @@ set_rfmode:
return 0;
}

+static void ar9003_hw_spectral_scan_config(struct ath_hw *ah,
+ struct ath_spec_scan *param)
+{
+ if (!param->enabled) {
+ REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_ENABLE);
+ return;
+ }
+
+ REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
+
+ if (param->short_repeat)
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+ else
+ REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_COUNT, param->count);
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period);
+
+ return;
+}
+
+static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah)
+{
+ /* Activate spectral scan */
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_ACTIVE);
+
+}
+static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ /* Poll for spectral scan complete */
+ if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_ACTIVE,
+ 0, AH_WAIT_TIMEOUT)) {
+ ath_err(common, "spectral scan wait failed\n");
+ return;
+ }
+}
+
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
@@ -1483,6 +1532,9 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv;
+ ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
+ ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger;
+ ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait;

ar9003_hw_set_nf_limits(ah);
ar9003_hw_set_radar_conf(ah);
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 86e26a1..ae3e593 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -675,6 +675,23 @@ struct ath9k_vif_iter_data {
int nadhocs; /* number of adhoc vifs */
};

+/* enum spectral_mode:
+ *
+ * @SPECTRAL_DISABLED: spectral mode is disabled
+ * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
+ * something else.
+ * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
+ * is performed manually.
+ * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels
+ * during a channel scan.
+ */
+enum spectral_mode {
+ SPECTRAL_DISABLED = 0,
+ SPECTRAL_BACKGROUND,
+ SPECTRAL_MANUAL,
+ SPECTRAL_CHANSCAN,
+};
+
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
@@ -743,6 +760,10 @@ struct ath_softc {
u8 ant_tx, ant_rx;
struct dfs_pattern_detector *dfs_detector;
u32 wow_enabled;
+ /* relay(fs) channel for spectral scan */
+ struct rchan *rfs_chan_spec_scan;
+ enum spectral_mode spectral_mode;
+ int scanning;

#ifdef CONFIG_PM_SLEEP
atomic_t wow_got_bmiss_intr;
@@ -751,6 +772,17 @@ struct ath_softc {
#endif
};

+#define FFT_DATA_MAX_SIZE 128
+struct fft_sample {
+ struct list_head list;
+ u16 freq;
+ u8 rssi;
+ u8 ext_rssi;
+ u8 noise;
+ u8 data[FFT_DATA_MAX_SIZE];
+ s16 size;
+};
+
void ath9k_tasklet(unsigned long data);
int ath_cabq_update(struct ath_softc *);

@@ -773,6 +805,10 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
void ath9k_reload_chainmask_settings(struct ath_softc *sc);

bool ath9k_uses_beacons(int type);
+void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw);
+int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
+ enum spectral_mode spectral_mode);
+

#ifdef CONFIG_ATH9K_PCI
int ath_pci_init(void);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 13ff9ed..161b3e9 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
+#include <linux/relay.h>
#include <asm/unaligned.h>

#include "ath9k.h"
@@ -966,6 +967,145 @@ static const struct file_operations fops_recv = {
.llseek = default_llseek,
};

+static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ char *mode = "";
+ unsigned int len;
+
+ switch (sc->spectral_mode) {
+ case SPECTRAL_DISABLED:
+ mode = "disable";
+ break;
+ case SPECTRAL_BACKGROUND:
+ mode = "background";
+ break;
+ case SPECTRAL_CHANSCAN:
+ mode = "chanscan";
+ break;
+ case SPECTRAL_MANUAL:
+ mode = "manual";
+ break;
+ }
+ len = strlen(mode);
+ return simple_read_from_buffer(user_buf, count, ppos, mode, len);
+}
+
+static ssize_t write_file_spec_scan_ctl(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+
+ if (strncmp("trigger", buf, 7) == 0) {
+ ath9k_spectral_scan_trigger(sc->hw);
+ } else if (strncmp("background", buf, 9) == 0) {
+ ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
+ ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
+ } else if (strncmp("chanscan", buf, 8) == 0) {
+ ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN);
+ ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
+ } else if (strncmp("manual", buf, 6) == 0) {
+ ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL);
+ ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
+ } else if (strncmp("disable", buf, 7) == 0) {
+ ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED);
+ ath_dbg(common, CONFIG, "spectral scan: disabled\n");
+ } else {
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static const struct file_operations fops_spec_scan_ctl = {
+ .read = read_file_spec_scan_ctl,
+ .write = write_file_spec_scan_ctl,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static struct dentry *create_buf_file_handler(const char *filename,
+ struct dentry *parent,
+ umode_t mode,
+ struct rchan_buf *buf,
+ int *is_global)
+{
+ struct dentry *buf_file;
+
+ buf_file = debugfs_create_file(filename, mode, parent, buf,
+ &relay_file_operations);
+ *is_global = 1;
+ return buf_file;
+}
+
+static int remove_buf_file_handler(struct dentry *dentry)
+{
+ debugfs_remove(dentry);
+
+ return 0;
+}
+
+void ath_debug_send_fft_sample(struct ath_softc *sc,
+ struct fft_sample *fft_sample)
+{
+ char buf[800];
+ int i, len;
+
+ if (!sc->rfs_chan_spec_scan)
+ return;
+
+ /* print some additional information, like frequency, rssi, */
+ len = sprintf(buf, "%04d %03d %03d %03d ",
+ fft_sample->freq, fft_sample->rssi,
+ fft_sample->ext_rssi, fft_sample->noise);
+
+ /* wouldn't be able to fill header and data */
+ if ((len + 5 * fft_sample->size + 1) > sizeof(buf))
+ return;
+
+ /* TODO: anyone with the spectral scan specs, please confirm/explain!
+ *
+ * the last 7 bytes seem to have a special meaning.
+ *
+ * byte 0 to n-8: spectral scan data, length varies
+ * byte n-1: this might be bwinfo according to DFS, usually 0x10 or
+ * 0x11
+ * byte n-2: always 0 in my dumps, pulse-length-ext in dfs code
+ * byte n-3: always 0 on my AR9003, mostly 15, 16 or something bigger
+ * on my AR9002
+ * byte n-4: appears to be some kind of offset (exponent?)
+ * byte n-5: no clue
+ * byte n-6: no clue, but appears to have something to do with RSSI
+ * byte n-7: lower 6 bit seem to hold some value which is higher on
+ * AR9002 when there is no real signal
+ */
+
+ /* dump the packet content here */
+ for (i = 0; i < fft_sample->size; i++)
+ len += sprintf(&buf[len], "0x%02x ", fft_sample->data[i]);
+ len += sprintf(&buf[len], "\n");
+
+ relay_write(sc->rfs_chan_spec_scan, buf, len);
+}
+
+static struct rchan_callbacks rfs_spec_scan_cb = {
+ .create_buf_file = create_buf_file_handler,
+ .remove_buf_file = remove_buf_file_handler,
+};
+
+
static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -1780,6 +1920,14 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_base_eeprom);
debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_modal_eeprom);
+ sc->rfs_chan_spec_scan = relay_open("spectral_scan",
+ sc->debug.debugfs_phy,
+ 262144, 4, &rfs_spec_scan_cb,
+ NULL);
+ debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, sc,
+ &fops_spec_scan_ctl);
+
#ifdef CONFIG_ATH9K_MAC_DEBUG
debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_samps);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 72d4893..396ff75 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -23,6 +23,7 @@

struct ath_txq;
struct ath_buf;
+struct fft_sample;

#ifdef CONFIG_ATH9K_DEBUGFS
#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
@@ -323,6 +324,10 @@ void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct dentry *dir);
+
+void ath_debug_send_fft_sample(struct ath_softc *sc,
+ struct fft_sample *fft_sample);
+
#else

#define RX_STAT_INC(c) /* NOP */
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 3636dab..bee40f6 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -659,6 +659,24 @@ struct ath_hw_private_ops {
};

/**
+ * struct ath_spec_scan - parameters for Atheros spectral scan
+ *
+ * @enabled: enable/disable spectral scan
+ * @short_repeat: enable/disable short repeat mode
+ * @count: number of scan results requested
+ * @period: TBD
+ * @fft_period: TBD
+ *
+ */
+struct ath_spec_scan {
+ bool enabled;
+ bool short_repeat;
+ u8 count;
+ u8 period;
+ u8 fft_period;
+};
+
+/**
* struct ath_hw_ops - callbacks used by hardware code and driver code
*
* This structure contains callbacks designed to to be used internally by
@@ -666,6 +684,10 @@ struct ath_hw_private_ops {
*
* @config_pci_powersave:
* @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
+ *
+ * @spectral_scan_config: set parameters for spectral scan and enable/disable it
+ * @spectral_scan_trigger: trigger a spectral scan run
+ * @spectral_scan_wait: wait for a spectral scan run to finish
*/
struct ath_hw_ops {
void (*config_pci_powersave)(struct ath_hw *ah,
@@ -686,6 +708,10 @@ struct ath_hw_ops {
void (*antdiv_comb_conf_set)(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf);
void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable);
+ void (*spectral_scan_config)(struct ath_hw *ah,
+ struct ath_spec_scan *param);
+ void (*spectral_scan_trigger)(struct ath_hw *ah);
+ void (*spectral_scan_wait)(struct ath_hw *ah);
};

struct ath_nf_limits {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 80cae53..07a49cc 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/ath9k_platform.h>
#include <linux/module.h>
+#include <linux/relay.h>

#include "ath9k.h"

@@ -882,6 +883,11 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
if (sc->dfs_detector != NULL)
sc->dfs_detector->exit(sc->dfs_detector);

+ if (sc->rfs_chan_spec_scan) {
+ relay_close(sc->rfs_chan_spec_scan);
+ sc->rfs_chan_spec_scan = NULL;
+ }
+
kfree(sc->sc_ah);
sc->sc_ah = NULL;
}
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 4a745e6..5cad975 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -225,8 +225,11 @@ enum ath9k_phyerr {
ATH9K_PHYERR_HT_CRC_ERROR = 34,
ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 35,
ATH9K_PHYERR_HT_RATE_ILLEGAL = 36,
-
- ATH9K_PHYERR_MAX = 37,
+ ATH9K_PHYERR_FFT_REPORT = 38, /* can anyone with the specs
+ * confirm this please?
+ * Obviously AR9003 only.
+ */
+ ATH9K_PHYERR_MAX = 39,
};

struct ath_desc {
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index be30a9a..e4b7fe0 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1075,6 +1075,83 @@ static void ath9k_disable_ps(struct ath_softc *sc)
ath_dbg(common, PS, "PowerSave disabled\n");
}

+void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ u32 rxfilter;
+
+ if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
+ ath_err(common, "spectrum analyzer not implemented on this hardware\n");
+ return;
+ }
+
+ ath9k_ps_wakeup(sc);
+ rxfilter = ath9k_hw_getrxfilter(ah);
+ ath9k_hw_setrxfilter(ah, rxfilter |
+ ATH9K_RX_FILTER_PHYRADAR |
+ ATH9K_RX_FILTER_PHYERR);
+
+ /* TODO: usually this should not be neccesary, but for some reason
+ * (or in some mode?) the trigger must be called after the
+ * configuration, otherwise the register will have its values reset
+ * (on my ar9220 to value 0x01002310)
+ */
+ ath9k_spectral_scan_config(hw, sc->spectral_mode);
+ ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
+ ath9k_ps_restore(sc);
+}
+
+int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
+ enum spectral_mode spectral_mode)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_spec_scan param;
+
+ if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
+ ath_err(common, "spectrum analyzer not implemented on this hardware\n");
+ return -1;
+ }
+
+ /* NOTE: this will generate a few samples ... lacking documentation,
+ * I'm not really sure what these parameters mean.
+ */
+ param.enabled = 1;
+ param.short_repeat = 1;
+ param.count = 8;
+ param.period = 0xFF;
+ param.fft_period = 0xF;
+
+ switch (spectral_mode) {
+ case SPECTRAL_DISABLED:
+ param.enabled = 0;
+ break;
+ case SPECTRAL_BACKGROUND:
+ /* send endless parameters.
+ * TODO: is this really useful for "background"?
+ */
+ param.count = 0xFF;
+ break;
+ case SPECTRAL_CHANSCAN:
+ break;
+ case SPECTRAL_MANUAL:
+ break;
+ default:
+ return -1;
+ }
+
+ ath9k_ps_wakeup(sc);
+ ath9k_hw_ops(ah)->spectral_scan_config(ah, &param);
+ ath9k_ps_restore(sc);
+
+ sc->spectral_mode = spectral_mode;
+
+ return 0;
+}
+
static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath_softc *sc = hw->priv;
@@ -1188,6 +1265,11 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
*/
if (old_pos >= 0)
ath_update_survey_nf(sc, old_pos);
+
+ /* perform spectral scan if requested. */
+ if (sc->scanning && sc->spectral_mode == SPECTRAL_CHANSCAN)
+ ath9k_spectral_scan_trigger(hw);
+
}

if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@ -2238,6 +2320,19 @@ static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
}

#endif
+static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+
+ sc->scanning = 1;
+}
+
+static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+
+ sc->scanning = 0;
+}

struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
@@ -2284,4 +2379,6 @@ struct ieee80211_ops ath9k_ops = {
.sta_add_debugfs = ath9k_sta_add_debugfs,
.sta_remove_debugfs = ath9k_sta_remove_debugfs,
#endif
+ .sw_scan_start = ath9k_sw_scan_start,
+ .sw_scan_complete = ath9k_sw_scan_complete,
};
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 6aafbb7..6f3fde6 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -15,6 +15,7 @@
*/

#include <linux/dma-mapping.h>
+#include <linux/relay.h>
#include "ath9k.h"
#include "ar9003_mac.h"

@@ -1034,6 +1035,28 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
rxs->flag &= ~RX_FLAG_DECRYPTED;
}

+static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
+ struct ath_rx_status *rs)
+{
+#ifdef CONFIG_ATH_DEBUG
+ struct ath_hw *ah = sc->sc_ah;
+ struct fft_sample fft_sample;
+
+ /* too short or too long data is probably something else */
+ if (rs->rs_datalen < 30 || rs->rs_datalen > FFT_DATA_MAX_SIZE)
+ return;
+
+ fft_sample.freq = ah->curchan->chan->center_freq;
+ fft_sample.size = rs->rs_datalen;
+ fft_sample.rssi = rs->rs_rssi_ctl0;
+ fft_sample.ext_rssi = rs->rs_rssi_ext0;
+ fft_sample.noise = ah->noise;
+ memcpy(fft_sample.data, (u8 *)hdr, fft_sample.size);
+
+ ath_debug_send_fft_sample(sc, &fft_sample);
+#endif
+}
+
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
{
struct ath_buf *bf;
@@ -1131,6 +1154,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
rxs->mactime += 0x100000000ULL;

+ if ((rs.rs_status & ATH9K_RXERR_PHY) &&
+ (rs.rs_phyerr == ATH9K_PHYERR_RADAR ||
+ rs.rs_phyerr == ATH9K_PHYERR_FFT_REPORT))
+ ath_process_fft(sc, hdr, &rs);
+
retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
rxs, &decrypt_error);
if (retval)
--
1.7.10.4


2012-12-18 11:18:18

by Zefir Kurtisi

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

On 12/13/2012 03:07 PM, Simon Wunderlich wrote:
> Hey there,
>
> just to bump the issue again - isn't there anyone here who can answer
> some of these questions?
>
> [...]
>
> Thanks a lot!
> Simon
>
Note: removed John, Johannes and Juoni from CC, since this is ath9k specific


Hi Simon,

I have a spectral scanning module up and running in an AR9590 based system and can
provide you some relevant observations and experiences I made.


First off: forget about 40MHz for now. It is either not working at all or way too
unstable (tested with 9280, 9380, 9580).

In 20MHz mode, spectral data is provided in the following format:

+#define SPECTRAL_HT20_NUM_BINS 56
+#define SPECTRAL_HT20_DC_INDEX (SPECTRAL_HT20_NUM_BINS / 2)
+#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ht20_fft_packet) + 3)
+
+struct ht20_mag_data {
+ u8 all_bins1;
+ u8 max_mag_bits29;
+ u8 all_bins2;
+ u8 max_exp;
+} __attribute__((packed));
+
+struct ht20_fft_packet {
+ u8 bin[SPECTRAL_HT20_NUM_BINS];
+ struct ht20_mag_data mag_data;
+} __attribute__((packed));
+

When spectral data is ready, the length is sometimes reported incorrectly, valid
values are between (SPECTRAL_HT20_TOTAL_DATA_LEN - 1) and
(SPECTRAL_HT20_TOTAL_DATA_LEN + 2), my code snipped to check the validity is:

+static s8 fix_rssi_inv_only(u8 rssi_val)
+{
+ if (rssi_val == 128)
+ rssi_val = 0;
+ return (s8) rssi_val;
+}
+
+#define SPECTRAL_SCAN_BITMASK 0x10
+
+/*
+ * check PHY-error for spectral
+ */
+bool process_spectral_phyerr(struct ath_softc *sc, void *data,
+ struct ath_rx_status *rs, u64 mactime)
+{
+ u16 datalen;
+ char *vdata_end;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_spectral_scanner *ass = ah->spectral_scanner;
+ struct ath_spectral_data *sd = &ass->spectral_data;
+ u8 pulse_bw_info;
+ s8 rssi;
+ struct spectral_ht20_msg *msg;
+
+ sd->stats.total_phy_errors++;
+
+ if (rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) {
+ sd->stats.drop_non_spectral++;
+ return false;
+ }
+
+ datalen = rs->rs_datalen;
+ if (datalen > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) {
+ sd->stats.drop_len_overflow++;
+ return false;
+ }
+ if (datalen < SPECTRAL_HT20_TOTAL_DATA_LEN - 1) {
+ sd->stats.drop_len_underflow++;
+ return false;
+ }
+
+ vdata_end = (char *)data + datalen;
+ pulse_bw_info = vdata_end[-1];
+
+ if (!(pulse_bw_info & SPECTRAL_SCAN_BITMASK)) {
+ sd->stats.drop_non_spectral++;
+ return false;
+ }
+
+ rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
+
+ sd->stats.descriptors_processed++;
+
+ ath_process_spectraldata_ht20(ah, data, datalen, rssi, mactime, msg);
+
+ sd->run_stats.last_tstamp = mactime;
+ sd->run_stats.spectral_packets++;
+
+ return true;
+}

As for the incorrect data, there are 4 cases to consider:
1) data length is correct => take the 56 bins as is
2) data length is 1 less => duplicate the first bin
3) data length is 2 more => remove bins 30 and 32
4) data length is 1 more => combine 2) + 3)

The code snippet to handle this post-processing is:

+static s8 fix_max_index(u8 max_index)
+{
+ s8 maxindex = max_index;
+ if (max_index > 32)
+ maxindex |= 0xe0;
+ else
+ maxindex &= ~0xe0;
+ maxindex += 29;
+ return maxindex;
+}
+
+static void ath_process_spectraldata_ht20(struct ath_hw *ah, u8 *vdata,
+ u16 datalen, s8 rssi, u64 fulltsf,
+ struct spectral_ht20_msg *nl_msg)
+{
+ struct ath_spectral_data *sd = &ah->spectral_scanner->spectral_data;
+ u8 *vdata_end = (char*)vdata + datalen;
+ u8 *msg_bin = nl_msg->bin;
+ struct ht20_mag_data *mag = (struct ht20_mag_data *) (vdata_end - 7);
+
+ switch(datalen - SPECTRAL_HT20_TOTAL_DATA_LEN) {
+ case 0:
+ // correct length
+ memcpy(msg_bin, vdata, SPECTRAL_HT20_NUM_BINS);
+ sd->stats.datalen_ok++;
+ break;
+ case -1:
+ // missing the first byte -> duplicate first as byte 0 and 1
+ msg_bin[0] = vdata[0];
+ memcpy(msg_bin + 1, vdata, SPECTRAL_HT20_NUM_BINS - 1);
+ sd->stats.datalen_m1++;
+ break;
+ case 2:
+ // MAC added 2 extra bytes at bin 30 and 32
+ memcpy(msg_bin, vdata, 30);
+ msg_bin[30] = vdata[31];
+ memcpy(msg_bin + 31, vdata + 33, SPECTRAL_HT20_NUM_BINS - 31);
+ sd->stats.datalen_p2++;
+ break;
+ case 1:
+ // MAC added 2 extra bytes AND first byte missing
+ msg_bin[0] = vdata[0];
+ memcpy(msg_bin + 1, vdata, 30);
+ msg_bin[31] = vdata[31];
+ memcpy(msg_bin + 32, vdata + 33, SPECTRAL_HT20_NUM_BINS - 32);
+ sd->stats.datalen_p2m1++;
+ break;
+ }
+
+ /* global data */
+ nl_msg->freq = sd->center_freq;
+ nl_msg->rssi = rssi;
+ nl_msg->noise_floor = ah->noise; //ah->caldata->nfCalHist[0].privNF;
+ nl_msg->tstamp = fulltsf;
+
+ /* extract magnitude scaling data */
+ nl_msg->max_magnitude = (mag->max_mag_bits29 << 2) |
+ ((mag->all_bins1 & 0xc0) >> 6) |
+ ((mag->all_bins2 & 0x03) << 10);
+ nl_msg->bitmap_weight = mag->all_bins1 & 0x3f;
+ nl_msg->max_index = fix_max_index(mag->all_bins2 & 0x3f);
+ nl_msg->max_exp = mag->max_exp & 0x0f;
+}

In my system the post-processed FFT raw data is transferred via a netlink
interface to a spectral_proxy, that forwards it to a connected host for real-time
inspection and visualization.

The interpretation of the data is as follows: the reported values are given as
magnitudes, which need to be scaled and converted to absolute power values based
on the packet's noise floor and RSSI values as follows:
bin_sum = 10*log(sum[i=1..56](b(i)^2)
power(i) = noise_floor + RSSI + 10*log(b(i)^2) - bin_sum

The code fragment to convert magnitude to absolute power values looks like this
(assuming you transferred the FFT and magnitude data to user space):
bool convert_data(struct spectral_ht20_msg *msg)
+{
+ u_int8_t *bin_pwr = msg->bin;
+ u_int8_t *dc_pwr = msg->bin + SPECTRAL_NUM_BINS / 2;
+ int pwr_count = SPECTRAL_NUM_BINS;
+ int8_t rssi = msg->rssi;
+ int8_t max_scale = 1 << msg->max_exp;
+ int16_t max_mag = msg->max_magnitude;
+ int i;
+ int nf0 = msg->noise_floor;
+
+ float bsum = 0.0;
+
+ // DC value is invalid -> interpolate
+ *dc_pwr = (dc_pwr[-1] + dc_pwr[1]) / 2;
+
+ for (i = 0; i < pwr_count; i++)
+ bsum += (bin_pwr[i] * max_scale) * (bin_pwr[i] * max_scale);
+ bsum = log10f(bsum) * 10;
+
+ for (i = 0; i < pwr_count; i++) {
+ float pwr_val;
+ int16_t val = bin_pwr[i];
+
+ if (val == 0)
+ val = 1;
+
+ pwr_val = 20 * log10f((float) val * max_scale);
+ pwr_val += nf0 + rssi - bsum;
+
+ val = pwr_val;
+ bin_pwr[i] = val;
+ }
+ return true;
+}


That's it, now you should be able to feed the raw data to whatever visualization,
statistics and classification back-ends.


Hope this helps somewhat. My implementation is quite application specific (like
operational only as monitor, dedicated netlink interface, proxy-forwarding, etc.)
and not usable for the generic user. That's why I am not posting it here and
polluting the mailing list. If you (or anybody else out there) would like to test
it as proof-of-concept, I can provide you the complete OpenWRT integration.


Cheers,
Zefir


2012-12-16 04:06:48

by Adrian Chadd

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

The formats are as follows. Please note that if a pulse terminates
during an FFT, the final entry may be truncated. So yes, you may not
always get an integer multiple of the relevant frame length.

Note that you shift each of the readings by max_exp to get a total
reading. max_index and max_magnitude I think are just derived from the
existing dataset; they're just a shortcut for software so it doesn't
have to parse the whole frame looking for the peak.

Static 20 mode:

0 bin -28 magnitude[7:0] = (|i| + |q|) >> max_exp
1 bin -27 magnitude[7:0] = (|i| + |q|) >> max_exp
2 - 53 ?
54 bin 26 magnitude[7:0] = (|i| + |q|) >> max_exp
55 bin 27 magnitude[7:0] = (|i| + |q|) >> max_exp
56 [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
57 [7:0]: all bins max_magnitude[9:2]
58 [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
59 [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)

Dynamic 20/40 mode:

0 bin -64 magnitude[7:0] = (|i| + |q|) >> max_exp or power (in dBm)
1 bin -63 magnitude[7:0] = (|i| + |q|) >> max_exp or power (in dBm)
2 - 125 ?
126 bin 62 magnitude[7:0] = (|i| + |q|) >> max_exp or power (in dBm)
127 bin 63 magnitude[7:0] = (|i| + |q|) >> max_exp or power (in dBm)
128 [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
Baseband DFS 2 (Radar) Micro-Architecture
129 [7:0]: lower bins max_magnitude[9:2]
130 [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
131 [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
132 [7:0]: upper bins max_magnitude[9:2]
133 [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
134 [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)

Ok, now for radar it's a tad different. There's a bit that is set if
the signal is above a certain threshold. If so, the bit is set to 1.
There's also a 3 bit magnitude value which is calculated against the
maximum magnitude value (floor(m(i) * 8 / max magnitude.)

This is optimised for digestion by radar code looking to identify
whether a longer pulse is a radar chirp (moving in frequency over
time) or not.

Static 20:

0 [3:0]: bin -28 {bitmap, quantized magnitude[2:0]}
[7:4]: bin -27 {bitmap, quantized magnitude[2:0]}
1 [3:0]: bin -26 {bitmap, quantized magnitude[2:0]}
[7:4]: bin -25 {bitmap, quantized magnitude[2:0]}
2 - 25 ?
26 [3:0]: bin 24 {bitmap, quantized magnitude[2:0]}
[7:4]: bin 25 {bitmap, quantized magnitude[2:0]}
27 [3:0]: bin 26 {bitmap, quantized magnitude[2:0]}
[7:4]: bin 27 {bitmap, quantized magnitude[2:0]}
28 [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
29 [7:0]: all bins max_magnitude[9:2]
30 [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}

Dynamic 20/40:

0 [3:0]: bin -64 {bitmap, quantized magnitude[2:0]}
[7:4]: bin -63 {bitmap, quantized magnitude[2:0]}
1 [3:0]: bin -62 {bitmap, quantized magnitude[2:0]}
[7:4]: bin -61 {bitmap, quantized magnitude[2:0]}
2 - 61 ?
62 [3:0]: bin 60 {bitmap, quantized magnitude[2:0]}
[7:4]: bin 61 {bitmap, quantized magnitude[2:0]}
63 [3:0]: bin 62 {bitmap, quantized magnitude[2:0]}
[7:4]: bin 63 {bitmap, quantized magnitude[2:0]}
64 [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
65 [7:0]: lower bins max_magnitude[9:2]
66 [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
67 [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
68 [7:0]: upper bins max_magnitude[9:2]
69 [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}

There you are. Please, go forth, write some open source code that
grabs this data and plots it in meaningful ways.



Adrian

2012-12-13 14:08:02

by Simon Wunderlich

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

Hey there,

just to bump the issue again - isn't there anyone here who can answer
some of these questions?

Adrian gave me some hints, but the FFT format is still completely unclear
- I would really like to integrate/fix things before bringing this patch(set)
to the next level.

I'm begging all the Qualcomm/Atheros-affiliated guys on the list to have
a look on the questions below and help me out here. :)

Thanks a lot!
Simon

On Thu, Dec 06, 2012 at 05:36:07PM +0100, Simon Wunderlich wrote:
> This patch(set) is the second iteration of the request for comments for
> upcoming spectral scan feature. It adds spectral scan control and dump
> features to debugfs. When the open questions regarding interpretation
> are answered, I would like to build an interface to nl80211/mac80211.
> Please see the open questions below, every hint is kindly appreciated. :)
>
> This feature has been enabled for AR92xx and AR93xx based chipsets.
> We've also written a visual evaluation program for these samples (see
> screenshot [1] and sourcecode [2]).
>
> Many details are not known due to the fact that I don't have access to
> Atheros specifications and details. Many things are done by guessing
> and might be wrong. I'm therefore requesting help from Qualcomm/Atheros
> guys to confirm or correct my findings. Apart from that, after
> discussion I think we could integrate this patchset to allow other
> people to work on this as well, even if it is experimental now.
>
> Questions from my end:
> 1. There are many TODOs/Comments in the patches regarding details,
> please answer if you can. :)

See code comments, e.g. regarding phy error type which are not defined
in the headers, etc.

> 2. The output format is very Atheros-dependent. If my finding that
> byte n-4 is some kind of offset/exponent, I'd integrate this in
> the debugfs output as well

still unclear.

> 3. The data length varies pretty much, there might be some false
> positives/PHY errors which are not FFT data - what should be
> the correct length?

still unclear.

> 4. Is there any special handling for HT40? At least the proprietary
> driver symbol names suggest so [3]

-> this one is solved: yes, there is. it has more FFT bins. Although
I didn't see that yet (I doubt they are the "small" variations I have seen,
like up to 4 byte, I'd expect like double frame size).

>
> (Possible) further work:
> 1. Integrate this patchset, confirm/correct findings
> 2. If anyone would like: Atheros proprietary driver seems to
> support some kind of classification [3] (is this microwave? cordless
> phone? whatever?)
> 3. If other devices also offer spectral scan support: define a
> common interface to use it (not debugfs).
>
> Changes to RFCv1:
> * remove nl80211/mac80211 stuff for now, to build a proper interface
> after intepretation/output stabilized
> * split spectral scan call into config, trigger and wait call, which can
> be called as desired (or depending on the mode)
> * use relay(fs) to stream spectral scan results (thanks for the hint Felix),
> this seems to be much cleaner - as long as we stay in debugfs
>
> [1] http://packetmixer.de/sdl_spec_scan2.png
> [2] https://github.com/simonwunderlich/FFT_eval
> [3] http://www.wehavemorefun.de/fritzbox/Ath_spectral.ko#Symbole
>
> Simon Wunderlich (1):
> ath9k: add spectral scan feature
>
> drivers/net/wireless/ath/ath9k/ar9002_phy.c | 52 ++++++++++
> drivers/net/wireless/ath/ath9k/ar9003_phy.c | 52 ++++++++++
> drivers/net/wireless/ath/ath9k/ath9k.h | 36 +++++++
> drivers/net/wireless/ath/ath9k/debug.c | 148 +++++++++++++++++++++++++++
> drivers/net/wireless/ath/ath9k/debug.h | 5 +
> drivers/net/wireless/ath/ath9k/hw.h | 26 +++++
> drivers/net/wireless/ath/ath9k/init.c | 6 ++
> drivers/net/wireless/ath/ath9k/mac.h | 7 +-
> drivers/net/wireless/ath/ath9k/main.c | 97 ++++++++++++++++++
> drivers/net/wireless/ath/ath9k/recv.c | 28 +++++
> 10 files changed, 455 insertions(+), 2 deletions(-)
>
> --
> 1.7.10.4
>
>


Attachments:
(No filename) (4.01 kB)
signature.asc (198.00 B)
Digital signature
Download all attachments

2012-12-17 13:22:44

by Simon Wunderlich

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

Hello Adrian,

thank you for posting this and the explanation!

On Sat, Dec 15, 2012 at 08:06:47PM -0800, Adrian Chadd wrote:
> The formats are as follows. Please note that if a pulse terminates
> during an FFT, the final entry may be truncated. So yes, you may not
> always get an integer multiple of the relevant frame length.

OK - my data is mostly in the range of 55-58 bytes (see below), sometimes
I got some longer packets, but I'm currently dropping them.
The variation still puzzles me though.

>
> Note that you shift each of the readings by max_exp to get a total
> reading. max_index and max_magnitude I think are just derived from the
> existing dataset; they're just a shortcut for software so it doesn't
> have to parse the whole frame looking for the peak.

Ah ok, that makes sense. Thanks for the clarification. :)
>
> Static 20 mode:
>
> 0 bin -28 magnitude[7:0] = (|i| + |q|) >> max_exp
> 1 bin -27 magnitude[7:0] = (|i| + |q|) >> max_exp
> 2 - 53 …
> 54 bin 26 magnitude[7:0] = (|i| + |q|) >> max_exp
> 55 bin 27 magnitude[7:0] = (|i| + |q|) >> max_exp

I've checked my data again: On my AR9280 in 2.4GHz, I get 55 or 57 bytes plus
7 "special bytes" (4 bytes meta info plus 3 bytes "radar trailer?"). In 5 GHz
and on my AR9380 in both bands, it is always either 56 or 58 bytes. The number
of bytes comes from rs_datalen from the rx_status struct as found in the patch
sent earlier.

So to summarise, what I currently get:
* 55-58 bytes of "data"
* 4 bytes of meta-information (as you provided)
* 3 bytes of "radar trailer" (bwinfo and such)

The variation in the data puzzles me, I've already checked bit 4 in bwinfo
as Felix suggested. Is there any other "header" to the DFS data? Or should I
just skip the first few bytes and always use the last 55 bytes? At least from the
distribution, all of these numbers look like normal data and not a bitfield.
Ideas welcome. :)

I've also noticed that the middle of the data (like data[28]) is usually higher
than the rest - this might be the carrier, or something alike?

> 56 [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
> 57 [7:0]: all bins max_magnitude[9:2]
> 58 [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
> 59 [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
>
> Dynamic 20/40 mode:
>
> 0 bin -64 magnitude[7:0] = (|i| + |q|) >> max_exp or power (in dBm)
> 1 bin -63 magnitude[7:0] = (|i| + |q|) >> max_exp or power (in dBm)
> 2 - 125 …
> 126 bin 62 magnitude[7:0] = (|i| + |q|) >> max_exp or power (in dBm)
> 127 bin 63 magnitude[7:0] = (|i| + |q|) >> max_exp or power (in dBm)
> 128 [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
> Baseband DFS 2 (Radar) Micro-Architecture
> 129 [7:0]: lower bins max_magnitude[9:2]
> 130 [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
> 131 [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
> 132 [7:0]: upper bins max_magnitude[9:2]
> 133 [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
> 134 [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)

Thanks again, also for posting the radar packet format! I'll play a little bit more
with spectral for now ...

Cheers,
Simon


Attachments:
(No filename) (3.14 kB)
signature.asc (198.00 B)
Digital signature
Download all attachments

2012-12-17 18:48:38

by Adrian Chadd

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

... did the original mail from me _make_ it to the ath9k list?



Adrian


On 17 December 2012 05:22, Simon Wunderlich
<[email protected]> wrote:
> Hello Adrian,
>
> thank you for posting this and the explanation!
>
> On Sat, Dec 15, 2012 at 08:06:47PM -0800, Adrian Chadd wrote:
>> The formats are as follows. Please note that if a pulse terminates
>> during an FFT, the final entry may be truncated. So yes, you may not
>> always get an integer multiple of the relevant frame length.
>
> OK - my data is mostly in the range of 55-58 bytes (see below), sometimes
> I got some longer packets, but I'm currently dropping them.
> The variation still puzzles me though.
>
>>
>> Note that you shift each of the readings by max_exp to get a total
>> reading. max_index and max_magnitude I think are just derived from the
>> existing dataset; they're just a shortcut for software so it doesn't
>> have to parse the whole frame looking for the peak.
>
> Ah ok, that makes sense. Thanks for the clarification. :)
>>
>> Static 20 mode:
>>
>> 0 bin -28 magnitude[7:0] = (|i| + |q|) >> max_exp
>> 1 bin -27 magnitude[7:0] = (|i| + |q|) >> max_exp
>> 2 - 53 ?
>> 54 bin 26 magnitude[7:0] = (|i| + |q|) >> max_exp
>> 55 bin 27 magnitude[7:0] = (|i| + |q|) >> max_exp
>
> I've checked my data again: On my AR9280 in 2.4GHz, I get 55 or 57 bytes plus
> 7 "special bytes" (4 bytes meta info plus 3 bytes "radar trailer?"). In 5 GHz
> and on my AR9380 in both bands, it is always either 56 or 58 bytes. The number
> of bytes comes from rs_datalen from the rx_status struct as found in the patch
> sent earlier.
>
> So to summarise, what I currently get:
> * 55-58 bytes of "data"
> * 4 bytes of meta-information (as you provided)
> * 3 bytes of "radar trailer" (bwinfo and such)
>
> The variation in the data puzzles me, I've already checked bit 4 in bwinfo
> as Felix suggested. Is there any other "header" to the DFS data? Or should I
> just skip the first few bytes and always use the last 55 bytes? At least from the
> distribution, all of these numbers look like normal data and not a bitfield.
> Ideas welcome. :)
>
> I've also noticed that the middle of the data (like data[28]) is usually higher
> than the rest - this might be the carrier, or something alike?
>
>> 56 [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
>> 57 [7:0]: all bins max_magnitude[9:2]
>> 58 [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
>> 59 [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
>>
>> Dynamic 20/40 mode:
>>
>> 0 bin -64 magnitude[7:0] = (|i| + |q|) >> max_exp or power (in dBm)
>> 1 bin -63 magnitude[7:0] = (|i| + |q|) >> max_exp or power (in dBm)
>> 2 - 125 ?
>> 126 bin 62 magnitude[7:0] = (|i| + |q|) >> max_exp or power (in dBm)
>> 127 bin 63 magnitude[7:0] = (|i| + |q|) >> max_exp or power (in dBm)
>> 128 [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
>> Baseband DFS 2 (Radar) Micro-Architecture
>> 129 [7:0]: lower bins max_magnitude[9:2]
>> 130 [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
>> 131 [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
>> 132 [7:0]: upper bins max_magnitude[9:2]
>> 133 [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
>> 134 [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
>
> Thanks again, also for posting the radar packet format! I'll play a little bit more
> with spectral for now ...
>
> Cheers,
> Simon
>
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.10 (GNU/Linux)
>
> iEYEARECAAYFAlDPHJgACgkQrzg/fFk7axYhoQCgzBT/lTIObkmz7MoishNsDo5l
> yZ0AoIdp5kUjCglz32/HkyfeBmD49729
> =PXP+
> -----END PGP SIGNATURE-----
>

2012-12-31 08:46:46

by Simon Wunderlich

[permalink] [raw]
Subject: Re: [RFCv2] Add spectral scan support for Atheros AR92xx/AR93xx

Hey Adrian,

On Sun, Dec 30, 2012 at 09:33:06PM -0800, Adrian Chadd wrote:
> Hi,
>
> I'm just going through and hacking on this now for FreeBSD (and
> userland decoding, rather than kernel side decoding.)

Cool!

>
> Your frame length logic is OK for the short spectral scan reports, but
> not useful for the longer aggregate reports (short_rpt=0 IIRC.)

Yeah, I've always used short_rpt=1 AFAIR.
>
> Here there's >1 FFT report in a frame, _and_ it could be corrupted,
> _and_ it could be short.

That sounds like a lot of fun :P

>
> I'm just writing a userland library now to start parsing and
> correcting these. It's likely that I can use your logic for the short
> spectral reports, but I won't be able to use them for the longer
> aggregate reports. We'll need to find some other way to determine that
> they've been corrupted and just toss/correct as appropriate.
>
> Thanks for digging into this!

Before asking questions, I'll wait for your userland lib and see what
it does. I've seen some longer frames as well occasionally when starting
to play with spectral, but didn't care too much as I didn't know how to
handle it. Anyway, I prefer hiding the corrupt and messy part and only
pass "clean data" to userspace, at least with the Linux implementation.

If you have some code handling and/or correct these long dataframes, I'd
be happy to integrate it if possible.

Thanks!
Simon


Attachments:
(No filename) (1.37 kB)
signature.asc (198.00 B)
Digital signature
Download all attachments