summaryrefslogtreecommitdiff
path: root/cesar/bsu/aclf/src
diff options
context:
space:
mode:
authorNélio Laranjeiro2011-01-19 17:06:47 +0100
committerNélio Laranjeiro2011-02-01 13:38:30 +0100
commit907f71b7161e412e5b74623664251eb4a6c262dd (patch)
tree94690d766fb368c2a000c5633b9dd688f8a46df8 /cesar/bsu/aclf/src
parentd69425fccc2c4e4c978b8f5c0acd347d002d6cf7 (diff)
bsu/aclf: better synchronization between the STA and the CCo, closes #2256
Supported frequencies: - 48.42Hz to 51.68Hz for 50Hz PowerLine (1000000 +/- BTO_MAX ticks). - 57.74Hz to 62.44Hz for 60Hz PowerLine (833333 +/- BTO_MAX ticks). Modifications: - BSU_ACLF_SET_FREQUENCY: - does not set the beacon period value. - set the maximum/minimum beacon period tick corresponding to the frequency found. - 6th beacon_period computed by the STA i.e. bpsd[6] += bpsd[5] - bpsd[4].
Diffstat (limited to 'cesar/bsu/aclf/src')
-rw-r--r--cesar/bsu/aclf/src/aclf.c135
-rw-r--r--cesar/bsu/aclf/src/bpsd.c4
2 files changed, 90 insertions, 49 deletions
diff --git a/cesar/bsu/aclf/src/aclf.c b/cesar/bsu/aclf/src/aclf.c
index 4816c043de..38f2a68490 100644
--- a/cesar/bsu/aclf/src/aclf.c
+++ b/cesar/bsu/aclf/src/aclf.c
@@ -22,9 +22,8 @@
do { \
*((bsu_aclf_frequency_t*) &ctx->frequency) \
= BSU_ACLF_FREQ_ ## freq ## HZ; \
- *((bsu_aclf_bp_t*) &ctx->bp) = BSU_ACLF_BP_ ## freq ## HZ_TCK; \
- *((uint*) &ctx->zc) = BSU_ACLF_ZC_ ## freq ## HZ_TCK; \
- ctx->beacon_period = ctx->bp; \
+ *((bsu_aclf_bp_t*) &ctx->beacon_period_theo_tck) \
+ = BSU_ACLF_BP_ ## freq ## HZ_TCK; \
} while (0)
/** WP History coefficient value. */
@@ -34,25 +33,57 @@
static bsu_aclf_t bsu_aclf_global;
/**
+ * Truncate the beacon period ticks computed to be suitable for BTOs.
+ * \param ctx the module context.
+ *
+ * The objective is to provide a BTO with the correct value allowing the STA
+ * to synchronise correctly.
+ * Norm EN50160 inform that the 50Hz PowerLine may have some variation on the
+ * frequency reaching +/- 15% for non interconnected PowerLine system.
+ * This means that the 50Hz PowerLine frequency have a range value from 42.5Hz
+ * to 57.5Hz. BTOs only allow a range from 48.42Hz to 51.68Hz.
+ * This function will do the same for both frequencies i.e. 50 and 60Hz.
+ */
+static void
+bsu_aclf_truncate_beacon_period (bsu_aclf_t *ctx)
+{
+ uint clk_min_tck =
+ ctx->beacon_period_theo_tck
+ - BITS_ONES (HPAV_BEACON_BTO_VALID_BITS);
+ uint clk_max_tck =
+ ctx->beacon_period_theo_tck
+ + BITS_ONES (HPAV_BEACON_BTO_VALID_BITS);
+ /* Special cases for cable mode. */
+ if (ctx->beacon_period_tck == 0)
+ ctx->beacon_period_tck = BSU_ACLF_BP_50HZ_TCK;
+ else if (ctx->beacon_period_tck > clk_max_tck)
+ ctx->beacon_period_tck = clk_max_tck;
+ else if (ctx->beacon_period_tck < clk_min_tck)
+ ctx->beacon_period_tck = clk_min_tck;
+}
+
+/**
* Compute the beacon period duration from the AC Line frequency variation.
* \param ctx the module context.
*/
-static inline void
+static void
bsu_aclf_compute_beacon_period_from_acl (bsu_aclf_t *ctx)
{
- u32 newzc, diff;
- dbg_assert (ctx);
- newzc = phy_clock_get_zero_cross_captured_date (ctx->phy);
- diff = (newzc - ctx->date) % (ctx->bp + 10000);
- ctx->date = newzc;
- if (diff <= 3 * ctx->zc)
+ uint zc_interval_tck = ctx->beacon_period_tck / 2;
+ u32 zero_cross_date = phy_clock_get_zero_cross_captured_date (ctx->phy);
+ u32 zc_diff_tck = zero_cross_date - ctx->zero_cross_last_date;
+ if (zc_diff_tck)
{
- float div;
- div = ((float)diff / (float)ctx->zc);
- diff = (4 - div) * ctx->zc + diff;
+ /* Compute the number of zero cross since the last read value. */
+ uint zc_nb =
+ (zc_diff_tck + zc_interval_tck / 2) / zc_interval_tck;
+ uint bp_tck = 2 * zc_diff_tck / zc_nb;
+ ctx->beacon_period_tck +=
+ BSU_ACLF_WP * ((int)bp_tck - (int)ctx->beacon_period_tck);
+ bsu_aclf_truncate_beacon_period (ctx);
+ /* Store the last zero crossing date. */
+ ctx->zero_cross_last_date = zero_cross_date;
}
- /* Using a Wp value with k = 4. */
- ctx->beacon_period += BSU_ACLF_WP * ((s32) diff - (s32)ctx->beacon_period);
}
/**
@@ -72,8 +103,12 @@ bsu_aclf_shift_beacon_period_start_date (bsu_aclf_t *ctx)
{
for (i = 0; i < BSU_ACLF_BPSD_NB - 1; i++)
ctx->bpsd[i] = ctx->bpsd[i+1];
- ctx->bpsd[i] += ctx->bp;
- ctx->beacon_period = ctx->bpsd[1] - ctx->bpsd[0];
+ /* For the last beacon period start date, add the difference of the
+ * previous one, this should help the station to keep a
+ * synchronisation near the CCo's clock even if it miss 5 beacons. */
+ ctx->bpsd[BSU_ACLF_BPSD_NB - 1] +=
+ ctx->bpsd[BSU_ACLF_BPSD_NB - 2] - ctx->bpsd[BSU_ACLF_BPSD_NB - 3];
+ ctx->beacon_period_tck = ctx->bpsd[1] - ctx->bpsd[0];
}
}
@@ -97,7 +132,7 @@ bsu_aclf_ac_compute_beacon_period_start_date (bsu_aclf_t *ctx)
{
ctx->bpsd[0] = now;
for (i = 1; i < BSU_ACLF_BPSD_NB; i++)
- ctx->bpsd[i] = ctx->bpsd[i-1] + ctx->beacon_period;
+ ctx->bpsd[i] = ctx->bpsd[i-1] + ctx->beacon_period_tck;
}
/* Compute only if the current beacon period is over. */
else if (lesseq_mod2p32 (ctx->bpsd[1], now))
@@ -107,14 +142,14 @@ bsu_aclf_ac_compute_beacon_period_start_date (bsu_aclf_t *ctx)
ctx->bpsd[i] = ctx->bpsd[i+1];
/* Add on the last beacon period start date the beacon period
* estimated. */
- ctx->bpsd[BSU_ACLF_BPSD_NB - 1] += ctx->beacon_period;
+ ctx->bpsd[BSU_ACLF_BPSD_NB - 1] += ctx->beacon_period_tck;
}
/* Compute the BTO using the theoretical beacon period value.
* BTO is computed from bpsd[1]. */
bts = ctx->bpsd[1];
for (i = 0; i < HPAV_BEACON_BTO_NB; i++)
{
- bto = ctx->bpsd[i+2] - ctx->bpsd[i+1] - ctx->bp;
+ bto = ctx->bpsd[i+2] - ctx->bpsd[i+1] - ctx->beacon_period_theo_tck;
/* Does bto overflowed ? */
if (ABS(bto) >> 15 == 0)
ctx->bto[i] = bto;
@@ -151,32 +186,36 @@ bsu_aclf_timer_event (void *user_data)
void
bsu_aclf_acl_frequency_detection (bsu_aclf_t *ctx)
{
- u32 wait_date, newzc = 0, diff = 0;
- dbg_assert (ctx);
- dbg_assert (ctx->phy);
- /* Compute the date until the one it should wait the new zc. It waits a
- * little bit more than a 50Hz zero cross. */
- wait_date = phy_date () + BSU_ACLF_ZC_50HZ_TCK + 1000;
- /* Special behavior for some unit tests and maximus. */
+ uint diff_zc_tck;
u32 now = phy_date ();
- if (now != phy_date ())
+ u32 zero_cross_new_date, zero_cross_date, wait_until_date;
+ /* Get the last zero cross date from hardware. */
+ zero_cross_date = zero_cross_new_date =
+ phy_clock_get_zero_cross_captured_date (ctx->phy);
+ /* Protection for maximus. */
+ if (less_mod2p32 (now, phy_date ()))
{
- /* Wait actively on Zero Cross change for 250 000 ticks. */
- for (newzc = ctx->date =
- phy_clock_get_zero_cross_captured_date (ctx->phy);
- less_mod2p32 (phy_date (), wait_date)
- && newzc == ctx->date;
- newzc = phy_clock_get_zero_cross_captured_date (ctx->phy))
- ;
- /* compute the difference between the two zc. */
- diff = newzc - ctx->date;
+ /* Catch the first zero cross.
+ * If the frequency does not change the expiration should stop
+ * the loop. */
+ wait_until_date = phy_date () + MAC_MS_TO_TCK (50);
+ while (lesseq_mod2p32 (phy_date (), wait_until_date)
+ && zero_cross_new_date == zero_cross_date)
+ zero_cross_new_date =
+ phy_clock_get_zero_cross_captured_date (ctx->phy);
}
- if (diff == 0 || diff >= BSU_ACLF_ZC_55HZ_TCK)
+ /* Compute the beacon period from the zero crossing.
+ * Beacon period is twice the zero crossing. Zero crossing is only
+ * store by hardware on a rising edge of the PowerLine cycle.*/
+ diff_zc_tck = zero_cross_new_date - zero_cross_date;
+ ctx->beacon_period_tck = 2 * diff_zc_tck;
+ if (diff_zc_tck == 0
+ || ctx->beacon_period_tck >= BSU_ACLF_BP_55HZ_TCK)
BSU_ACLF_SET_FREQUENCY (50);
else
BSU_ACLF_SET_FREQUENCY (60);
- ctx->beacon_period = ctx->bp;
- ctx->date = newzc;
+ ctx->zero_cross_last_date = zero_cross_new_date;
+ bsu_aclf_truncate_beacon_period (ctx);
}
/**
@@ -189,10 +228,10 @@ bsu_aclf_clear (bsu_aclf_t *ctx)
uint i;
for (i = 0; i < COUNT (ctx->bpsd); i++)
ctx->bpsd[i] = 0;
- ctx->beacon_period = ctx->bp;
+ ctx->beacon_period_tck = ctx->beacon_period_theo_tck;
for (i = 0; i < COUNT (ctx->bto); i++)
ctx->bto[i] = 0;
- ctx->date = 0;
+ ctx->zero_cross_last_date = 0;
ctx->aclsc = false;
}
@@ -233,15 +272,17 @@ bsu_aclf_compute_beacon_period_start_date (bsu_aclf_t *ctx, const u32 bts_ntb,
ctx->bto[i] = bto[i];
/* BTO is valid use it to compute. */
if (bto[i] != HPAV_BEACON_BTO_INVALID)
- ctx->bpsd[i+1] = ctx->bpsd[i] + ctx->bp + bto[i];
- /* BTO is not valid, STA assumes the beacon period start date has
- * no offset (FIXME: Good idea ?) */
+ ctx->bpsd[i+1] =
+ ctx->bpsd[i] + ctx->beacon_period_theo_tck + bto[i];
+ /* BTO is not valid, take the difference from the previous beacon
+ * period. */
else
- ctx->bpsd[i+1] = ctx->bpsd[i] + ctx->bp;
+ ctx->bpsd[i+1] += ctx->bpsd[i] - ctx->bpsd[i-1];
}
else
- ctx->bpsd[i+1] = ctx->bpsd[i] + ctx->bp;
+ ctx->bpsd[i+1] += ctx->bpsd[i] - ctx->bpsd[i-1];
}
+ ctx->beacon_period_tck = ctx->bpsd[1] - ctx->bpsd[0];
}
void
diff --git a/cesar/bsu/aclf/src/bpsd.c b/cesar/bsu/aclf/src/bpsd.c
index 273bf58c74..14080e1ea7 100644
--- a/cesar/bsu/aclf/src/bpsd.c
+++ b/cesar/bsu/aclf/src/bpsd.c
@@ -39,12 +39,12 @@ u32
bsu_aclf_beacon_period_tck (bsu_aclf_t *ctx)
{
dbg_assert (ctx);
- return ctx->bpsd[1] - ctx->bpsd[0];
+ return ctx->beacon_period_tck;
}
u32
bsu_aclf_beacon_period_atu (bsu_aclf_t *ctx)
{
dbg_assert (ctx);
- return MAC_TCK_TO_ATU (ctx->bpsd[1] - ctx->bpsd[0]);
+ return MAC_TCK_TO_ATU (ctx->beacon_period_tck);
}