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