summaryrefslogtreecommitdiff
path: root/cesar/ce/rx/bitloading/fsm/src/fsm.c
blob: 2e0a183b919ad0104be85a38993f953dfab27c24 (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
/* Cesar project {{{
 *
 * Copyright (C) 2009 Spidcom
 *
 * <<<Licence>>>
 *
 * }}} */
/**
 * \file    ce/rx/bitloading/fsm/src/fsm.c
 * \brief   CE RX Bit loading FSM internal functions.
 * \ingroup ce_rx
 *
 * Functions to work with the FSM: init, transition.
 */
#include "common/std.h"

#include "ce/rx/bitloading/fsm/fsm.h"
#include "inc/tables.h"
#include "ce/rx/inc/trace.h"
#include "ce/rx/bitloading/inc/intervals.h"
#include "ce/debug/gpio/gpio.h"

void
ce_rx_bl_fsm_handle_event (ce_rx_t *ce_rx, sta_t *sta, ce_rx_bl_fsm_event_type_t e,
                           ce_rx_bitloading_fsm_event_param_t data)
{
    /* Check parameters. */
    dbg_assert (sta);
    dbg_assert (data.measure);
    ce_rx_bl_fsm_state_t *fsm;
    if (data.measure->fsm_id == CE_RX_MEASURE_NO_INTERVAL)
        fsm = &sta->ce_rx_bt.fsm;
    else
    {
        dbg_assert (sta->intervals);
        fsm = &sta->intervals->intervals[data.measure->fsm_id]->fsm;
    }
    ce_rx_bl_fsm_state_t old_fsm = *fsm;

    dbg_assert (*fsm < CE_RX_BL_FSM_STATE_NB);
    dbg_assert (e < CE_RX_BL_FSM_EVENT_TYPE_NB);

    /* Get transition. */
    ce_rx_bl_fsm_transition_t tr = ce_rx_bl_fsm_transition_table[*fsm][e];
    /* A non managed event is an error. */
    dbg_assert (tr);
    /* Run transition. */
    ce_rx_bl_fsm_branch_t br = tr (ce_rx, sta, data);
    dbg_assert (((br >> 16) & 0xff) == *fsm);
    dbg_assert (((br >> 8) & 0xff) == e);
    *fsm = br & 0xff;

    /* Trace transition. */
    if (old_fsm != *fsm)
        CE_RX_TRACE (FSM_FROM_TO, sta->tei,
                     data.measure->fsm_id, old_fsm, e, *fsm);

    if (data.measure->fsm_id == CE_RX_MEASURE_NO_INTERVAL)
        ce_debug_gpio_event
            (CE_DEBUG_GPIO_EVENT_CE_RX_BL_FSM_IDLE + sta->ce_rx_bt.fsm, true);
    ce_debug_gpio_event
        (CE_DEBUG_GPIO_EVENT_CE_RX_BL_MEASURE_NONE, false);
}

ce_rx_bl_fsm_event_type_t
ce_rx_bl_fsm_measure_to_event (sta_t *sta,
                               ce_rx_bitloading_fsm_event_param_t data)
{
    dbg_assert (sta);

    /* Prepare event types.
     * We create a array of two dimensions:
     * First dimension: is measure for intervals or global ?
     * Second dimension: Data, Sound complete or not. */
    int has_interval, type;
    static const ce_rx_bl_fsm_event_type_t event_tab[2][3] =
    {
        {
            CE_RX_BL_FSM_EVENT_TYPE_data,
            CE_RX_BL_FSM_EVENT_TYPE_sound,
            CE_RX_BL_FSM_EVENT_TYPE_sound_completed
        },
        {
            CE_RX_BL_FSM_EVENT_TYPE_interval_data,
            CE_RX_BL_FSM_EVENT_TYPE_interval_sound,
            CE_RX_BL_FSM_EVENT_TYPE_interval_sound_completed
        }
    };

    /* Get measure. */
    ce_rx_measure_mbox_t *measure = data.measure;
    dbg_assert (measure);

    /* Is this measure a Sound ? */
    if (measure->rx_params.sound)
    {
        if (measure->rx_params.sound_complete)
            type = CE_RX_FSM_MEASURE_TO_EVENT_TYPE_SOUND_COMPLETED;
        else
            type = CE_RX_FSM_MEASURE_TO_EVENT_TYPE_SOUND;
    }
    /* This is a data. */
    else
        type = CE_RX_FSM_MEASURE_TO_EVENT_TYPE_DATA;

    /* Get interval information. */
    int interval;
    s16 start_date_atu, end_date_atu;
    /* Global by default. */
    has_interval = CE_RX_FSM_MEASURE_TO_EVENT_TYPE_GLOBAL;
    measure->fsm_id = CE_RX_MEASURE_NO_INTERVAL;
    /* Interval's research is only done if received measure is a data or a
     * sound or sound complete with a SRC indicating that it is directed to
     * an interval. Other SRCs should be handled by global FSM, even if they
     * are received on a specific interval. */
    if (type == CE_RX_FSM_MEASURE_TO_EVENT_TYPE_DATA
        || measure->rx_params.sound_src == TONEMAP_SRC_INTERVAL_UNAVAILABLE
        || measure->rx_params.sound_src == TONEMAP_SRC_INTERVAL_UNUSABLE)
    {
        ce_rx_bl_intervals_measure_to_date (&measure->rx_params,
                                            &start_date_atu, &end_date_atu);
        interval = ce_rx_bl_intervals_measure_to_interval (sta->rx_tonemaps,
                                                           start_date_atu,
                                                           end_date_atu);
        if (interval != CE_RX_MEASURE_NO_INTERVAL)
        {
            /* We are on an interval. */
            has_interval = CE_RX_FSM_MEASURE_TO_EVENT_TYPE_INTERVAL;
            measure->fsm_id = interval % ce_rx_bl_intervals_fsm_count_;
        }
        else if (type != CE_RX_FSM_MEASURE_TO_EVENT_TYPE_DATA)
        {
            /* Indicate that sound frame received is directed to an interval
             * but let the global fsm handle it as we can not match this
             * actual interval. */
            has_interval = CE_RX_FSM_MEASURE_TO_EVENT_TYPE_INTERVAL;
        }
    }

    return event_tab[has_interval][type];
}