summaryrefslogtreecommitdiff
path: root/cesar/ce/rx/cp/src/cp.c
blob: 0adabdadcf0a9a2590320cf9aa0c85ba28608890 (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
/* Cesar project {{{
 *
 * Copyright (C) 2009 Spidcom
 *
 * <<<Licence>>>
 *
 * }}} */
/**
 * \file    ce/rx/cp/src/cp.c
 * \brief   Interface to use the CE RX in the CP context.
 * \ingroup ce_rx
 */
#include "common/std.h"

#include "cp/inc/context.h"
#include "cp/sta/mgr/sta_mgr.h"
#include "ce/rx/cp/mme.h"
#include "ce/rx/inc/rx.h"
#include "ce/rx/cp/inc/cp.h"
#include "ce/rx/cp/cp.h"
#include "ce/rx/cp/mbox.h"
#include "cp/fsm/fsm.h"

void
ce_rx_cp_set_cp_signal_work_callback (ce_rx_t *ce_rx,
                                      ce_rx_cp_signal_work_t cb, cp_t *ctx)
{
    /* Check parameters. */
    dbg_assert (ce_rx);
    dbg_assert (cb);
    dbg_assert (ctx);

    ce_rx->cp_ctx = ctx;
    ce_rx->cp_cb = cb;
}

void
ce_rx_cp_init (ce_rx_t *ce_rx)
{
    /* Check parameter. */
    dbg_assert (ce_rx);

    /* Initialize the mailbox between the CP and the CE RX. */
    mbox_init (&ce_rx->cp_mbox);
    /* Initialize the allocator for the CP mailbox. */
    slab_cache_init (&ce_rx->cp_mbox_cache, "ce_rx_cp",
                     sizeof (ce_rx_cp_mbox_t), NULL);
}

void
ce_rx_cp_uninit (ce_rx_t *ce_rx)
{
    /* Check parameters. */
    dbg_assert (ce_rx);

    /* Clean the mailbox. */
    mbox_node_t *node;
    ce_rx_cp_mbox_t *work;
    while ((node = mbox_try_get (&ce_rx->cp_mbox)))
    {
        /* Convert. */
        work = PARENT_OF (ce_rx_cp_mbox_t, mbox_node, node);
        /* Delete. */
        slab_release (work);
    }
    /* Clean. */
    mbox_uninit (&ce_rx->cp_mbox);
}

void
ce_rx_cp_send_mme_new_tone_map (ce_rx_t *ce_rx, sta_t *peer, u8 new_tmi,
                                u8 old_tmi, bool initial_ce)
{
    /* Check parameters. */
    dbg_assert (ce_rx);
    dbg_assert (peer);
    dbg_assert (new_tmi == 0 || TONEMAP_INDEX_IS_NEGOTIATED (new_tmi));
    dbg_assert (old_tmi == 0 || TONEMAP_INDEX_IS_NEGOTIATED (old_tmi));

    if (ce_rx->cp_ctx)
    {
        CE_RX_TRACE (SEND_TONEMAP, peer->tei, new_tmi, old_tmi, initial_ce);
        /* Create a new work. */
        ce_rx_cp_mbox_t *work =
            ce_rx_cp_mbox_node_tonemap (ce_rx, peer->tei, peer->rx_tonemaps,
                                        new_tmi, old_tmi, initial_ce);
        /* Add it to the list. */
        mbox_put (&ce_rx->cp_mbox, &work->mbox_node);
        /* Post a flag for the CP. */
        ce_rx->cp_cb (ce_rx->cp_ctx);
    }
}

void
ce_rx_cp_send_mme_refresh_tmi_list (ce_rx_t *ce_rx, sta_t *peer)
{
    /* Check parameters. */
    dbg_assert (ce_rx);
    dbg_assert (peer);

    if (ce_rx->cp_ctx)
    {
        CE_RX_TRACE (SEND_TONEMAP_REFRESH, peer->tei);
        /* Create a new work. */
        ce_rx_cp_mbox_t *work =
            ce_rx_cp_mbox_node_refresh_tmi (ce_rx, peer->tei, peer->rx_tonemaps);
        /* Add it to the list. */
        mbox_put (&ce_rx->cp_mbox, &work->mbox_node);
        /* Post a flag for the CP. */
        ce_rx->cp_cb (ce_rx->cp_ctx);
    }
}

void
ce_rx_cp_run_work (cp_t *ctx)
{
    /* Check parameter. */
    dbg_assert (ctx);

    /* Get the CE RX context. */
    ce_rx_t *ce_rx = ctx->ce_rx;
    dbg_assert (ce_rx);
    /* Get my net. */
    cp_net_t *my_net = cp_sta_mgr_get_our_avln (ctx);
    /* Get a mbox node */
    mbox_node_t *node;
    /* Maybe we have more than one mail do deal with.
     * FIXME: In this case, we can maybe have a different behaviour: for
     * example, this mean the CP is quite late, so we can maybe drop some
     * work... If we implement this behaviour, we need to thing about it
     * carefully! */
    while ((node = mbox_try_get (&ce_rx->cp_mbox)))
    {
        dbg_assert (node);
        ce_rx_cp_mbox_t *work = PARENT_OF (ce_rx_cp_mbox_t, mbox_node, node);

        /* Get the STA. */
        cp_sta_t *cp_sta = cp_sta_mgr_sta_get_assoc (ctx, my_net, work->tei);
        /* If the station is now longer associated with us since the CE wanted
         * to send the tone map, we do not need to send the tone map. */
        if (cp_sta)
        {
            /* Get the MAC store STA. */
            sta_t *sta = mac_store_sta_get (ctx->mac_store, work->tei);
            dbg_assert (sta);
            dbg_assert (sta->rx_tonemaps);

            if (!work->new_tmi)
            {
                /* No new TMI or ROBO. */
                ce_rx_mme_refresh_tone_map_list (ctx, cp_sta, work->tmi_list,
                                                 work->default_tmi,
                                                 &work->intervals_list,
                                                 sta->rx_tonemaps);
            }
            else
            {
                /* Send the new tone map. */
                ce_rx_cp_mme_send_tone_map (ctx, cp_sta, work->tmi_list,
                                            work->default_tmi,
                                            &work->intervals_list, work->new_tmi,
                                            work->old_tmi, sta->rx_tonemaps,
                                            work->initial_ce);
            }
            /* If initial CE is set, this is the first communication with
             * an associated STA. */
            if (work->initial_ce)
            {
                /* Post an event to the CP FSM. */
                cp_fsm_post_new_event (ctx, sta, first_com_with_assoc_sta,
                                       my_net, cp_sta);
            }

            /* Clean. */
            blk_release (sta);
            slab_release (cp_sta);
        }
        slab_release (work);
    }
}