ath5k: keep beacon RSSI average
authorBruno Randolf <br1@einfach.org>
Thu, 25 Mar 2010 05:49:25 +0000 (14:49 +0900)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 31 Mar 2010 18:39:09 +0000 (14:39 -0400)
Keep an exponentially weighted moving average of the beacon RSSI in our BSS.
It will be used by the ANI implementation.

The averaging algorithm is copied from rt2x00, Thanks :)

Signed-off-by: Bruno Randolf <br1@einfach.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/base.c

index 6334294f5f131ceaaf55f23372b8782a8418a5bd..cefd28d5deee443eaa137e2a5151354010cc569f 100644 (file)
@@ -992,6 +992,15 @@ struct ath5k_nfcal_hist
        s16 nfval[ATH5K_NF_CAL_HIST_MAX];       /* last few noise floors */
 };
 
+/**
+ * struct avg_val - Helper structure for average calculation
+ * @avg: contains the actual average value
+ * @avg_weight: is used internally during calculation to prevent rounding errors
+ */
+struct ath5k_avg_val {
+       int avg;
+       int avg_weight;
+};
 
 /***************************************\
   HARDWARE ABSTRACTION LAYER STRUCTURE
@@ -1096,6 +1105,9 @@ struct ath5k_hw {
 
        struct ath5k_nfcal_hist ah_nfcal_hist;
 
+       /* average beacon RSSI in our BSS (used by ANI) */
+       struct ath5k_avg_val    ah_beacon_rssi_avg;
+
        /* noise floor from last periodic calibration */
        s32                     ah_noise_floor;
 
@@ -1305,4 +1317,27 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
        return retval;
 }
 
+#define AVG_SAMPLES    8
+#define AVG_FACTOR     1000
+
+/**
+ * ath5k_moving_average -  Exponentially weighted moving average
+ * @avg: average structure
+ * @val: current value
+ *
+ * This implementation make use of a struct ath5k_avg_val to prevent rounding
+ * errors.
+ */
+static inline struct ath5k_avg_val
+ath5k_moving_average(const struct ath5k_avg_val avg, const int val)
+{
+       struct ath5k_avg_val new;
+       new.avg_weight = avg.avg_weight  ?
+               (((avg.avg_weight * ((AVG_SAMPLES) - 1)) +
+                       (val * (AVG_FACTOR))) / (AVG_SAMPLES)) :
+               (val * (AVG_FACTOR));
+       new.avg = new.avg_weight / (AVG_FACTOR);
+       return new;
+}
+
 #endif
index f60d84f9c55f622a6998bc4a80468aba4bee5ee3..ba2fad23a7a5844defcddcaf50c7caf7bde7dea9 100644 (file)
@@ -1803,6 +1803,25 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
        }
 }
 
+static void
+ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi)
+{
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+       struct ath5k_hw *ah = sc->ah;
+       struct ath_common *common = ath5k_hw_common(ah);
+
+       /* only beacons from our BSSID */
+       if (!ieee80211_is_beacon(mgmt->frame_control) ||
+           memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0)
+               return;
+
+       ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg,
+                                                     rssi);
+
+       /* in IBSS mode we should keep RSSI statistics per neighbour */
+       /* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */
+}
+
 /*
  * Compute padding position. skb must contains an IEEE 802.11 frame
  */
@@ -2022,6 +2041,8 @@ accept:
 
                ath5k_debug_dump_skb(sc, skb, "RX  ", 0);
 
+               ath5k_update_beacon_rssi(sc, skb, rs.rs_rssi);
+
                /* check beacons in IBSS mode */
                if (sc->opmode == NL80211_IFTYPE_ADHOC)
                        ath5k_check_ibss_tsf(sc, skb, rxs);