Implement local LE features adapter property
[platform/core/connectivity/bluetooth-frwk.git] / bt-oal / common / oal-event-dispatcher.c
1 /*
2  * bluetooth-frwk
3  *
4  * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *              http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19 #define _OAL_EVENT_DISPATCHER_C_
20
21 #include <stdio.h>
22 #include <glib.h>
23 #include <dlog.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "oal-hardware.h"
28 #include "oal-event.h"
29 #include "oal-utils.h"
30 #include "oal-manager.h"
31
32 #define EVENT_TRACE(fmt, args...) {LOG_(LOG_ID_SYSTEM, DLOG_INFO, "OAL_EVENT", GREEN(fmt), ##args); \
33         LOG_(LOG_ID_MAIN, DLOG_INFO, LOG_TAG, GREEN("[OAL_EVENT]"fmt), ##args); }
34
35 typedef struct {
36         int event;
37         gsize size;
38         gpointer event_data;
39 } event_t;
40
41 static GMainContext *event_thread_context;
42 static oal_event_callback event_handler_cb;
43 GMainLoop *event_loop;
44
45 void _bt_event_dispatcher_deinit()
46 {
47         BT_DBG("+");
48         if (event_loop) {
49                 BT_DBG("OAL event loop guit");
50                 g_main_loop_quit(event_loop);
51         }
52
53         BT_DBG("-");
54 }
55
56 static gpointer __event_handler_loop(gpointer user_data)
57 {
58         gboolean ret = FALSE;
59
60         /* Set up the thread�s context and run it forever. */
61         g_main_context_push_thread_default(event_thread_context);
62
63         event_loop = g_main_loop_new(event_thread_context, FALSE);
64         do {
65                 ret = oal_lib_init(NULL);
66                 if (ret == FALSE)
67                         BT_WARN("oal_lib_init failed, trying again...");
68         } while (ret == FALSE);
69
70         g_main_loop_run(event_loop);
71         BT_DBG("OAL event loop quited");
72
73         if (event_loop) {
74                 g_main_loop_unref(event_loop);
75                 event_loop = NULL;
76         }
77
78         g_main_context_pop_thread_default(event_thread_context);
79         g_main_context_unref(event_thread_context);
80
81         return NULL;
82 }
83
84 static void event_data_free(event_t *event_info)
85 {
86         if (event_info->event_data)
87                 g_free(event_info->event_data);
88         g_slice_free(event_t, event_info);
89 }
90
91 /* Convert an idle callback into a call to dispatch_idle(). */
92 static gboolean dispatch_idle(gpointer user_data)
93 {
94         event_t *event_info = user_data;
95         BT_DBG("+");
96
97         if (NULL == event_handler_cb)
98                 BT_ERR("Upstream handler not registered");
99         else
100                 (*event_handler_cb)(event_info->event, event_info->event_data, event_info->size);
101
102         BT_DBG("-");
103         return G_SOURCE_REMOVE;
104 }
105
106 static gboolean need_same_context(oal_event_t event)
107 {
108         gboolean ret;
109
110         switch (event) {
111         default:
112                 ret = FALSE;
113                 break;
114         }
115         return ret;
116 }
117
118 void _bt_event_dispatcher_init(oal_event_callback cb)
119 {
120         event_handler_cb = cb;
121         BT_DBG("+");
122         /* Spawn a background thread and pass it a reference to its
123          * GMainContext. Retain a reference for use in this thread
124          * too. */
125         event_thread_context = g_main_context_new();
126         g_thread_new("OALEventScheduler", __event_handler_loop, NULL);
127 }
128
129 void send_event_no_trace(oal_event_t event, gpointer event_data, gsize len)
130 {
131         event_t *event_info;
132
133         /* Create a data closure to pass all the desired variables
134          * between threads. */
135         event_info = g_slice_new0(event_t);
136         event_info->event = event;
137         event_info->size = len;
138         event_info->event_data = event_data;
139         /* Invoke the function. */
140
141         if (need_same_context(event)) {
142                 BT_INFO("Without context change");
143                 dispatch_idle(event_info);
144                 event_data_free(event_info);
145         } else
146                 g_main_context_invoke_full(event_thread_context,
147                                 G_PRIORITY_DEFAULT, dispatch_idle,
148                                 event_info,
149                                 (GDestroyNotify) event_data_free);
150 }
151
152 void send_event_bda_trace(oal_event_t event, gpointer event_data, gsize len, bt_address_t *address)
153 {
154         if (event != OAL_EVENT_BLE_REMOTE_DEVICE_FOUND) {
155                 if (address) {
156                         bdstr_t bdstr;
157                         EVENT_TRACE("[%s] %s", bdt_bd2str(address, &bdstr), str_event[event]);
158                 } else
159                         EVENT_TRACE(" %s", str_event[event]);
160         }
161         send_event_no_trace(event, event_data, len);
162 }
163
164 void send_event(oal_event_t event, gpointer event_data, gsize len)
165 {
166         send_event_bda_trace(event, event_data, len, NULL);
167 }
168 #undef _OAL_EVENT_DISPATCHER_C_