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