1 /*
2  * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 
8 /*****************************************************************************
9  *
10  *  Filename:      btc_sm.c
11  *
12  *  Description:   Generic BTC state machine API
13  *
14  *****************************************************************************/
15 #include "common/bt_target.h"
16 #include "common/bt_defs.h"
17 #include "osi/allocator.h"
18 #include "btc/btc_common.h"
19 #include "btc/btc_sm.h"
20 
21 #if BTC_SM_INCLUDED
22 /*****************************************************************************
23 **  Constants & Macros
24 ******************************************************************************/
25 /*****************************************************************************
26 **  Local type definitions
27 ******************************************************************************/
28 typedef struct {
29     btc_sm_state_t         state;
30     btc_sm_handler_t       *p_handlers;
31 } btc_sm_cb_t;
32 
33 /*****************************************************************************
34 **  Static variables
35 ******************************************************************************/
36 
37 /*****************************************************************************
38 **  Static functions
39 ******************************************************************************/
40 
41 /*****************************************************************************
42 **  Externs
43 ******************************************************************************/
44 
45 /*****************************************************************************
46 **  Functions
47 ******************************************************************************/
48 
49 /*****************************************************************************
50 **
51 ** Function     btc_sm_init
52 **
53 ** Description  Initializes the state machine with the state handlers
54 **              The caller should ensure that the table and the corresponding
55 **              states match. The location that 'p_handlers' points to shall
56 **              be available until the btc_sm_shutdown API is invoked.
57 **
58 ** Returns      Returns a pointer to the initialized state machine handle.
59 **
60 ******************************************************************************/
61 
btc_sm_init(const btc_sm_handler_t * p_handlers,btc_sm_state_t initial_state)62 btc_sm_handle_t btc_sm_init(const btc_sm_handler_t *p_handlers, btc_sm_state_t initial_state)
63 {
64     btc_sm_cb_t *p_cb;
65 
66     if (p_handlers == NULL) {
67         BTC_TRACE_ERROR("%s : p_handlers is NULL", __FUNCTION__);
68         return NULL;
69     }
70 
71     p_cb = (btc_sm_cb_t *)osi_malloc(sizeof(btc_sm_cb_t));
72     p_cb->state = initial_state;
73     p_cb->p_handlers = (btc_sm_handler_t *)p_handlers;
74 
75     /* Send BTC_SM_ENTER_EVT to the initial state */
76     p_cb->p_handlers[initial_state](BTC_SM_ENTER_EVT, NULL);
77 
78     return (btc_sm_handle_t)p_cb;
79 }
80 
81 /*****************************************************************************
82 **
83 ** Function     btc_sm_shutdown
84 **
85 ** Description  Tears down the state machine
86 **
87 ** Returns      None
88 **
89 ******************************************************************************/
btc_sm_shutdown(btc_sm_handle_t handle)90 void btc_sm_shutdown(btc_sm_handle_t handle)
91 {
92     btc_sm_cb_t *p_cb = (btc_sm_cb_t *)handle;
93 
94     if (p_cb == NULL) {
95         BTC_TRACE_ERROR("%s : Invalid handle", __FUNCTION__);
96         return;
97     }
98     osi_free(p_cb);
99 }
100 
101 /*****************************************************************************
102 **
103 ** Function     btc_sm_get_state
104 **
105 ** Description  Fetches the current state of the state machine
106 **
107 ** Returns      Current state
108 **
109 ******************************************************************************/
btc_sm_get_state(btc_sm_handle_t handle)110 btc_sm_state_t btc_sm_get_state(btc_sm_handle_t handle)
111 {
112     btc_sm_cb_t *p_cb = (btc_sm_cb_t *)handle;
113 
114     if (p_cb == NULL) {
115         BTC_TRACE_ERROR("%s : Invalid handle", __FUNCTION__);
116         return 0;
117     }
118 
119     return p_cb->state;
120 }
121 
122 /*****************************************************************************
123 **
124 ** Function     btc_sm_dispatch
125 **
126 ** Description  Dispatches the 'event' along with 'data' to the current state handler
127 **
128 ** Returns      BT_STATUS_SUCCESS on success
129 **              BT_STATUS_UNHANDLED if event was not processed
130 **              BT_STATUS_FAIL otherwise
131 **
132 ******************************************************************************/
btc_sm_dispatch(btc_sm_handle_t handle,btc_sm_event_t event,void * data)133 bt_status_t btc_sm_dispatch(btc_sm_handle_t handle, btc_sm_event_t event,
134                             void *data)
135 {
136     bt_status_t status = BT_STATUS_SUCCESS;
137 
138     btc_sm_cb_t *p_cb = (btc_sm_cb_t *)handle;
139 
140     if (p_cb == NULL) {
141         BTC_TRACE_ERROR("%s : Invalid handle", __FUNCTION__);
142         return BT_STATUS_FAIL;
143     }
144 
145     if (p_cb->p_handlers[p_cb->state](event, data) == FALSE) {
146         return BT_STATUS_UNHANDLED;
147     }
148 
149     return status;
150 }
151 
152 /*****************************************************************************
153 **
154 ** Function     btc_sm_change_state
155 **
156 ** Description  Make a transition to the new 'state'. The 'BTC_SM_EXIT_EVT'
157 **              shall be invoked before exiting the current state. The
158 **              'BTC_SM_ENTER_EVT' shall be invoked before entering the new state
159 **
160 ** Returns      BT_STATUS_SUCCESS on success
161 **              BT_STATUS_UNHANDLED if event was not processed
162 **              BT_STATUS_FAIL otherwise
163 **
164 ******************************************************************************/
btc_sm_change_state(btc_sm_handle_t handle,btc_sm_state_t state)165 bt_status_t btc_sm_change_state(btc_sm_handle_t handle, btc_sm_state_t state)
166 {
167     bt_status_t status = BT_STATUS_SUCCESS;
168     btc_sm_cb_t *p_cb = (btc_sm_cb_t *)handle;
169 
170     if (p_cb == NULL) {
171         BTC_TRACE_ERROR("%s : Invalid handle", __FUNCTION__);
172         return BT_STATUS_FAIL;
173     }
174 
175     /* Send exit event to the current state */
176     if (p_cb->p_handlers[p_cb->state](BTC_SM_EXIT_EVT, NULL) == FALSE) {
177         status = BT_STATUS_UNHANDLED;
178     }
179 
180     /* Change to the new state */
181     p_cb->state = state;
182 
183     /* Send enter event to the new state */
184     if (p_cb->p_handlers[p_cb->state](BTC_SM_ENTER_EVT, NULL) == FALSE) {
185         status = BT_STATUS_UNHANDLED;
186     }
187 
188     return status;
189 }
190 
191 #endif /* #if BTC_SM_INCLUDED */
192