summaryrefslogtreecommitdiff
path: root/cesar/ce/rx/bitloading/src/intervals.c
blob: e536cfa02f484aaf728bc471d1c3ca8594c4d394 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/* Cesar project {{{
 *
 * Copyright (C) 2009 Spidcom
 *
 * <<<Licence>>>
 *
 * }}} */
/**
 * \file    ce/rx/bitloading/src/intervals.c
 * \brief   CE/RX Intervals related functions.
 * \ingroup ce_rx_bl
 */

#include "common/std.h"
#include "lib/blk.h"
#include "lib/utils.h"
#include "mac/common/tonemap.h"
#include "mac/common/timings.h"
#include "ce/rx/bitloading/inc/bitloading.h"
#include "ce/rx/bitloading/intervals.h"
#include "ce/rx/bitloading/inc/intervals.h"
#include "ce/rx/cp/inc/cp.h"
#include "ce_rx_bl_fsm_defs.h"

u8 ce_rx_bl_intervals_fsm_count_ = 6;
u8 ce_rx_bl_intervals_repetition_count_ = 4;

u32
ce_rx_bl_intervals_get_tmi_used_list (sta_t *sta, bool check_default)
{
    /* Check parameters. */
    dbg_assert (sta);

    ce_rx_bitloading_intervals_t *its = sta->intervals;
    tonemaps_t *tms = sta->rx_tonemaps;
    u32 i, result = 0;

    /* Check tonemap used as default one. */
    if (check_default && tms->default_tmi < TONEMAP_INDEX_NB)
        result |= (1 << tms->default_tmi);
    /* Check tonemaps used on different intervals. */
    for (i = 0; i < ce_rx_bl_intervals_fsm_count_; i++)
    {
        if (its->tmi[i] < TONEMAP_INDEX_NB)
            result |= (1 << its->tmi[i]);
    }

    return result;
}

void
ce_rx_bl_intervals_measure_to_date (pbproc_rx_params_t *rx_param,
                                    s16 *start_date_atu,
                                    s16 *end_date_atu)
{
    dbg_assert (rx_param);
    dbg_assert (start_date_atu);
    dbg_assert (end_date_atu);

    /* Estimate the start date.
     * As we don't know how in which mode we are, we take an average of hybrid
     * and AV modes. */
    u32 average_tck = ((MAC_PREAMBLE_HYBRID_TCK + MAC_FC_10_TCK + MAC_FC_AV_TCK)
                       + (MAC_PREAMBLE_TCK + MAC_FC_AV_TCK)) / 2;
    *start_date_atu = MAC_TCK_TO_ATU (
        ((s32) (rx_param->preamble_ntb - rx_param->beacon_period_start_ntb))
        + average_tck);

    /* Estimate the end date. */
    *end_date_atu = *start_date_atu + MAC_TCK_TO_ATU (rx_param->fl_tck);

    /* Check we didn't have overflowed. */
    dbg_assert (*start_date_atu < *end_date_atu);
}

int
ce_rx_bl_intervals_measure_to_interval (tonemaps_t *tms,
                                        s16 mea_start,
                                        s16 mea_end)
{
    dbg_assert (tms);
    dbg_assert (tms->intervals);
    dbg_assert (mea_start < mea_end);

    tonemap_intervals_t *ints = tms->intervals;

    if (!ints->intervals_nb)
        return -1;

    /* We take the middle of the measure and see in which interval it is
     * supposed to be. */
    s16 mea_middle = (mea_start + mea_end) / 2;
    if (mea_middle <= 0)
        return -1;

    /* Measure middle is contained in this interval. */
    u8 int_num = tonemap_interval_find (tms, mea_middle);

    /* If we are not located in an interval, the measure is after the last
     * offset (our beacon period may not be perfect). We may consider this
     * measure as global. */
    if (int_num >= ints->intervals_nb)
        return -1;

    /* Get the start/end date of this interval. */
    /* We remove 1 because the date correspond to the next interval. */
    s16 int_end = ints->interval[int_num].end_offset_atu - 1;
    s16 int_start;
    if (int_num == 0)
        int_start = 0;
    else
        int_start = ints->interval[int_num - 1].end_offset_atu;
    dbg_assert (int_start < int_end);

    /* Check the measure didn't shifted too much. */
    if (mea_end > int_end
        && mea_end - int_end > MAC_TCK_TO_ATU (MAC_TM_TOLERANCE_TCK))
        return -1;
    if (mea_start < int_start
        && int_start - mea_start > MAC_TCK_TO_ATU (MAC_TM_TOLERANCE_TCK))
        return -1;

    return int_num;
}

void
ce_rx_bl_intervals_update_tmi (sta_t *sta, const bsu_aclf_bp_t bp_tck)
{
    dbg_assert (sta);
    dbg_assert (sta->intervals);

    int i;
    u8 res;
    ce_rx_bitloading_intervals_t *its = sta->intervals;

    u16 bp_atu = MAC_TCK_TO_ATU (bp_tck);
    int total_ints = ce_rx_bl_intervals_fsm_count_
        * ce_rx_bl_intervals_repetition_count_;

    mac_interval_clear (sta->rx_tonemaps);
    for (i = 0; i < total_ints - 1; i++)
    {
        res = mac_interval_append (
            sta->rx_tonemaps,
            bp_atu * (i + 1) / total_ints,
            its->tmi[i % ce_rx_bl_intervals_fsm_count_]);
        dbg_assert (res == i + 1);
    }
    /* Last interval duration is increased to fit with max theoretical beacon
     * period duration. */
    res = mac_interval_append (
        sta->rx_tonemaps,
        bp_atu + MAC_TCK_TO_ATU (HPAV_BEACON_BTO_MAX_TCK),
        its->tmi[(total_ints - 1) % ce_rx_bl_intervals_fsm_count_]);
    dbg_assert (res == total_ints);
    mac_interval_commit_changes (sta->rx_tonemaps, ce_rx_bl_intervals_fsm_count_);
}

void
ce_rx_bl_intervals_update_default_tm (sta_t *sta)
{
    dbg_assert (sta);
    dbg_assert (sta->intervals);
    dbg_assert (sta->rx_tonemaps);

    ce_rx_bitloading_intervals_t *bl_ints = sta->intervals;
    tonemaps_t *tms = sta->rx_tonemaps;

    uint i;
    bool use_robo = false;
    bool use_default = false;
    uint old_default_tmi = tms->default_tmi;

    /* If some intervals are currently restarting, we must determine what
     * impact it will have on future default tonemap. */
    for (i = 0; i < ce_rx_bl_intervals_fsm_count_; i++)
    {
        if (bl_ints->tmi[i] == TONEMAP_SRC_INTERVAL_UNAVAILABLE
            || bl_ints->tmi[i] == TONEMAP_SRC_INTERVAL_UNUSABLE)
        {
            use_default = true;
            if (bl_ints->intervals[i]->default_robo == true)
            {
                use_robo = true;
                break;
            }
        }
    }

    /* Now, update default tonemap with an existing one or by computing
     * a specific one. */
    if (use_robo)
        tms->default_tmi = PHY_MOD_ROBO;
    else
    {
        uint new_default_tmi = 0;
        u32 tm_list = ce_rx_bl_intervals_get_tmi_used_list (sta, use_default);

        if (BITS_ONES_COUNT (tm_list) == 1)
        {
            /* If only one tonemap to use, set it directly as default one. */
            while (tm_list != 1)
            {
                tm_list >>= 1;
                new_default_tmi++;
            }
            tms->default_tmi = new_default_tmi;
        }
        else
        {
            /* TODO: if needed, include default tmi in tm_used_list. Then
             * compute new tonemap from the ones included in tm_used_list
             * (see #3880). */
        }
    }

    /* Remove old default tonemap if it is unused. */
    if (tms->default_tmi != old_default_tmi
        && !(ce_rx_bl_intervals_get_tmi_used_list (sta, true)
             & (1 << old_default_tmi))
        && TONEMAP_INDEX_IS_NEGOTIATED (old_default_tmi))
    {
        tonemap_disable (tms, old_default_tmi);
    }
}

void
ce_rx_bl_intervals_reset (ce_rx_t *ce_rx, sta_t *sta, int fsm_id)
{
    dbg_assert (ce_rx);
    dbg_assert (ce_rx->aclf);
    dbg_assert (sta);
    dbg_assert (sta->intervals);
    dbg_assert (sta->rx_tonemaps);
    dbg_assert (fsm_id >= 0 && fsm_id < ce_rx_bl_intervals_fsm_count_);

    ce_rx_bitloading_t *bl = sta->intervals->intervals[fsm_id];
    u8 *tmi = &sta->intervals->tmi[fsm_id];
    u8 old_tmi = *tmi;

    /* Set sound flag for this interval. */
    *tmi = TONEMAP_INDEX_INTERVAL_UNAVAILABLE;

    /* Update default tonemap. */
    ce_rx_bl_intervals_update_default_tm (sta);

    /* Mark the intervals TMI to be released if this fsm had negotiated
     * its own tone map. */
    if (!(ce_rx_bl_intervals_get_tmi_used_list (sta, true) & (1 << old_tmi))
        && TONEMAP_INDEX_IS_NEGOTIATED (old_tmi))
        tonemap_disable (sta->rx_tonemaps, old_tmi);

    /* Reset high PB error rate counter. */
    bl->high_pb_error_rate_frame_counter = 0;
    /* Reset BER sliding means. */
    ce_rx_bl_ber_sliding_mean_reset (bl);

    /* Rebuild intervals.  */
    ce_rx_bl_intervals_update_tmi (sta, ce_rx->aclf->beacon_period_tck);
    /* Send refresh TMI list with intervals. */
    ce_rx_cp_send_mme_refresh_tmi_list (ce_rx, sta);
}

void
ce_rx_bl_intervals_start (ce_rx_t *ce_rx, sta_t *sta)
{
    dbg_assert (ce_rx);
    dbg_assert (ce_rx->aclf);
    dbg_assert (sta);
    dbg_assert (sta->rx_tonemaps);

    /* Check the interval is large enough to send one pb in ROBO.
     * This check is correct if all intervals have the same size;
     * this will not work with dynamic intervals. */
    dbg_assert (
       ce_rx->mac_config->tonemask_info.tonemap_robo[PHY_MOD_ROBO].one_pb_data_tck
       <= (ce_rx->aclf->beacon_period_theo_tck + HPAV_BEACON_BTO_MAX_TCK)
          / (ce_rx_bl_intervals_repetition_count_ * ce_rx_bl_intervals_fsm_count_)
          + HPAV_BEACON_BTO_MAX_TCK);

    /* Allocate intervals structure. */
    sta->intervals = ce_rx_bl_intervals_alloc (sta->rx_tonemaps->default_tmi);
    /* Construct intervals.  */
    ce_rx_bl_intervals_update_tmi (sta, ce_rx->aclf->beacon_period_tck);
    /* Send refresh TMI list with intervals. */
    ce_rx_cp_send_mme_refresh_tmi_list (ce_rx, sta);
}