summaryrefslogtreecommitdiff
path: root/cesar/tools/sniffer_phy/src/lowlevel.c
blob: 5531f2fc275d49d099b85efb364b7478aaa8b747 (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
/* Cesar project {{{
 *
 * Copyright (C) 2010 Spidcom
 *
 * <<<Licence>>>
 *
 * }}} */
/**
 * \file    src/lowlevel.c
 * \brief   Low level sniffer functions.
 * \ingroup sniffer_phy
 *
 * Handle FC and PB reception in ISR context and unlist them in DSR context.
 *
 * Received data is forwarded to MME layer to be sent to sniffer client.
 */
#include "common/std.h"

#include "hal/phy/phy.h"
#include "hal/arch/arch.h"
#include "lib/slist.h"

#include "inc/context.h"

static bool ARCH_ILRAM
lowlevel_rx_fc_cb (void *user, u32 rx_date, const u32 *fc_av)
{
    sniffer_phy_t *ctx = user;
    dbg_assert (ctx);
    /* Prepare hardware. */
    phy_rx_prepare_short (ctx->lowlevel.phy);
    /* Take a block to record the FC. */
    if (ctx->lowlevel.pool_size)
    {
        blk_t *blk = slist_pop_front (ctx->lowlevel.pool_, paste_size);
        lowlevel_rx_desc_t *desc = PARENT_OF (lowlevel_rx_desc_t, blk, blk);
        lowlevel_rx_t *rx = desc->rx;
        /* Fill FC information. */
        rx->date = rx_date;
        rx->fc10 = phy_rx_fc10 (ctx->lowlevel.phy);
        rx->fc10_bad_crc = rx->fc10 == (u32) -1;
        if (fc_av)
        {
            rx->fc[0] = fc_av[0];
            rx->fc[1] = fc_av[1];
            rx->fc[2] = fc_av[2];
            rx->fc[3] = fc_av[3];
            rx->fc_bad_crc = false;
        }
        else
        {
            rx->fc[0] = (u32) -1;
            rx->fc[1] = (u32) -1;
            rx->fc[2] = (u32) -1;
            rx->fc[3] = (u32) -1;
            rx->fc_bad_crc = true;
        }
        /* Enlist RX descriptor. */
        slist_push_back (ctx->lowlevel.rx_, desc);
    }
    /* Restart RX now. */
    phy_rx_activate (ctx->lowlevel.phy, true, 0, true);
    /* Ask a DSR. */
    return true;
}

static bool
lowlevel_access_cb (void *user)
{
    /* This interrupt is not used in sniffer. */
    dbg_assert_default ();
    return false;
}

static bool
lowlevel_access_conf_cb (void *user)
{
    /* This interrupt is not used in sniffer. */
    dbg_assert_default ();
    return false;
}

static bool ARCH_ILRAM
lowlevel_pbdma_cb (void *user, u32 status_word)
{
    /* This interrupt is not used yet in sniffer. */
    dbg_assert_default ();
    return false;
}

static bool
lowlevel_tx_false_alarm_cb (void *user)
{
    /* This interrupt is not implemented in hardware! */
    dbg_assert_default ();
    return false;
}

static void
lowlevel_deferred_cb (void *user)
{
    sniffer_phy_t *ctx = user;
    dbg_assert (ctx);
    /* Unlist RX MPDU descriptors. */
    while (!slist_empty (ctx->lowlevel.rx_, paste))
    {
        /* Extract MPDU. */
        uint flags = arch_isr_lock ();
        lowlevel_rx_desc_t *desc = slist_pop_front (ctx->lowlevel.rx_);
        arch_isr_unlock (flags);
        /* TODO: give to MME layer. */
        slist_push_back (ctx->lowlevel.pool_, &desc->blk, paste_size);
    }
}

void
lowlevel_init (sniffer_phy_t *ctx)
{
    static tonemask_info_t tonemask_info;
    dbg_assert (ctx);
    /* Initialise context. */
    slist_init (ctx->lowlevel.pool_, paste_size);
    slist_init (ctx->lowlevel.rx_, paste);
    /* Initialise tonemask information. */
    ctx->lowlevel.tonemask_info = &tonemask_info;
    tonemask_default (ctx->lowlevel.tonemask_info->tonemask);
    tonemask_update (ctx->lowlevel.tonemask_info);
    /* Initialise Phy. */
    ctx->lowlevel.phy = phy_init (ctx, lowlevel_rx_fc_cb, lowlevel_access_cb,
                                  lowlevel_access_conf_cb, lowlevel_pbdma_cb,
                                  lowlevel_tx_false_alarm_cb,
                                  lowlevel_deferred_cb);
    /* Allocate pool. */
    blk_t *first, *last;
    first = blk_alloc_desc_range (LOWLEVEL_POOL_SIZE, &last);
    slist_push_back_range (ctx->lowlevel.pool_, first, last,
                           LOWLEVEL_POOL_SIZE, paste_size);
}

void
lowlevel_activate (sniffer_phy_t *ctx, bool state)
{
    dbg_assert (ctx);
    if (state)
    {
        /* Program tonemask. */
        phy_set_tonemask (
            ctx->lowlevel.phy,
            ARCH_CPU_TO_DMA (ctx->lowlevel.tonemask_info->tonemask),
            ctx->lowlevel.tonemask_info->carrier_nb);
        /* Set RX mode. */
        phy_rx_param (ctx->lowlevel.phy, PHY_FC_MODE_HYBRID_1);
    }
    /* Change RX state. */
    phy_rx_activate (ctx->lowlevel.phy, true, 0, state);
}