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