summaryrefslogtreecommitdiff
path: root/cesar/cp/beacon/src/beacon_discover.c
blob: cab626400793d5abfaffb6e3015d685efc755f98 (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
/* Cesar project {{{
 *
 * Copyright (C) 2008 Spidcom
 *
 * <<<Licence>>>
 *
 * }}} */
/**
 * \file    cp/beacon/src/beacon_discover.c
 * \brief   Beacon discover process.
 * \ingroup cp_beacon
 *
 * Function to compute the interval between the one no request shall be done.
 * In this max discover period, all the station including the CCo shall send a
 * discover beacon.
 * For the station their are choose by the CCo using the network of its AVLN.
 *
 * \warn At 50Hz only 250 beacon period exists in the interval of Max Discover
 * Period provided by the HP_AV specification which is equal to 10 seconds.
 * 10s / 40e-3s = 250.
 */
#include "common/std.h"
#include "string.h"

#include "cp/fsm/fsm.h"

#include "cp/beacon/inc/beacon.h"
#include "cp/beacon/discover.h"
#include "cp/inc/context.h"

/**
 * Compute the interval in beacon periods.
 * \param  ctx  the module context.
 *
 * This function compute the interval between the one no discover beacon shall
 * be request. If the value compute is 0 it corresponds to a request each
 * beacon period including the CCo.
 *
 * This shall use the value in the PWL module to know how many beacon periods
 * are available to discover all the station of the AVLN (impossible at 50Hz).
 * This shall request the number of station in the network (query the station
 * manager for that) and divide it by discover_period_max_bp in the PWL
 * module.
 */
void
cp_beacon_discover_compute_interval (cp_t *ctx)
{
    dbg_assert (ctx);
    cp_net_t *our_net = cp_sta_mgr_get_our_avln (ctx);
    u32 bp = bsu_aclf_beacon_period_tck (ctx->bsu_aclf);
    dbg_assert (bp);
    ctx->beacon.discover.discover_interval_bp =
        MAC_MS_TO_TCK (MAC_SEC_TO_MS(CP_DISCOVER_PERIOD_MAX_S)) /
        (bp * (cp_net_get_num_stas (ctx, our_net) + 1));
}

/** Initialise
 * \param  ctx  the module context.
 */
void
cp_beacon_discover_init (cp_t *ctx)
{
    dbg_assert (ctx);
    memset (&ctx->beacon.discover, 0, sizeof (cp_beacon_discover_t));
    cp_beacon_discover_compute_interval (ctx);
}

void
cp_beacon_discover_uninit (cp_t *ctx)
{
    dbg_assert (ctx);
}

/**
 * Get the next station to request the discover beacon.
 * \param  ctx  the module context.
 * \param  net  the network.
 * \param  tei  the TEI variable to store the TEI to request.
 * \return  true  if the station is found, false otherwise.
 *
 * This will interrogate sta_mgr to get the STA corresponding to the TEI in
 * range (discover.tei_last, MAC_TEI_STA_MAX).
 */
static inline bool
cp_beacon_discover_need_to_request__find_next_sta (cp_t *ctx, cp_net_t *net,
                                                   cp_tei_t * tei)
{
    cp_beacon_discover_t *discover = &ctx->beacon.discover;
    bool sta_found = false;
    cp_tei_t i;
    cp_sta_t *sta;
    /* Always start from the previous TEI requested, the current discover
     * procedure is not ended yet. */
    for (i = discover->tei_last + 1;
         i <= MAC_TEI_STA_MAX  && !sta_found;
         i++)
    {
        sta = cp_sta_mgr_sta_get_assoc (ctx, net, i);
        if (sta)
        {
            discover->tei_last = *tei = i;
            slab_release (sta);
            sta_found = true;
        }
    }
    return sta_found;
}

/**
 * Verify if any request shall be done.
 * \param  ctx  the module context.
 * \param  tei  The TEI to request. 0 = The CCo shall send a discover beacon.
 * \return  true if a discover bentry shall be added to the beacon, false
 * otherwise.
 *
 */
bool
cp_beacon_discover_need_to_request (cp_t *ctx, cp_tei_t * tei)
{
    cp_beacon_discover_t *discover;
    dbg_assert (ctx);
    dbg_assert (tei);
    discover = &ctx->beacon.discover;
    if (cp_sta_own_data_get_cco_status (ctx) == false)
        return false;
    discover->countdown_bp --;
    // Verify countdown.
    // see discover-need-to-request.dot file for the machine state in the doc
    // directory.
    if (discover->countdown_bp <= 0)
    {
        cp_tei_t own_tei = cp_sta_own_data_get_tei (ctx);
        bool sta_found = false;
        cp_sta_t *sta;
        /* Compute the interval to request the discover beacon from the
         * stations of our AVLN. */
        cp_beacon_discover_compute_interval (ctx);
        discover->countdown_bp = discover->discover_interval_bp;
        cp_net_t *net = cp_sta_mgr_get_our_avln (ctx);
        if (discover->tei_last == own_tei)
        {
            sta = cp_net_sta_get_first (ctx, net, CP_NET_STA_ASSOC);
            if (sta)
            {
                discover->tei_last = *tei = cp_sta_get_tei (sta);
                slab_release (sta);
                sta_found = true;
            }
        }
        /* Try to get the last station requested. */
        else if (discover->tei_last != MAC_TEI_UNASSOCIATED)
        {
            sta = cp_sta_mgr_sta_get_assoc (ctx, net, discover->tei_last);
            if (sta)
            {
                sta = cp_net_sta_get_next (ctx, net, sta);
                if (sta)
                {
                    discover->tei_last = *tei = cp_sta_get_tei (sta);
                    slab_release (sta);
                    sta_found = true;
                }
            }
            else
                sta_found =
                    cp_beacon_discover_need_to_request__find_next_sta (
                        ctx, net, tei);
        }
        else
            sta_found = cp_beacon_discover_need_to_request__find_next_sta (
                ctx, net, tei);
        /* Last station of the AVLN has been requested and no more stations
         * are available i.e. there is no station in the AVLN with a greater
         * tei_last. */
        if (sta_found == false)
        {
            discover->tei_last = *tei = own_tei;
            /* All stations have been requested to send a discover
             * beacon. Discover procedure is ended, post the event in the FSM.
             */
            cp_fsm_post_new_event (ctx, bare,
                                   HANDOVER_DISCOVER_PROCESS_DONE);
        }
        return true;
    }
    return false;
}