Change signal level policy
[platform/core/connectivity/net-config.git] / src / wifi-indicator.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
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
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <sys/ioctl.h>
25 #include <netinet/in.h>
26 #include <netinet/ip.h>
27 #include <linux/wireless.h>
28 #include <vconf.h>
29 #include <vconf-keys.h>
30
31 #include "log.h"
32 #include "util.h"
33 #include "netdbus.h"
34 #include "wifi-state.h"
35 #include "network-state.h"
36 #include "network-statistics.h"
37 #include "netsupplicant.h"
38 #include "wifi-indicator.h"
39
40 #define VCONFKEY_WIFI_SNR_MIN   -89
41
42 #if !defined TIZEN_WEARABLE
43 #define WIFI_INDICATOR_INTERVAL 1
44 #else
45 #define WIFI_INDICATOR_INTERVAL 10
46 #endif
47
48 #if defined TIZEN_WEARABLE
49 #define NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1     (19200 * 1024)
50 #define NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2     (2560 * 1024)
51 #define NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3     (1536 * 1024)
52 #else
53 #define NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1     (19200 * 1024)
54 #define NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2     (7680 * 1024)
55 #define NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3     (3840 * 1024)
56 #endif
57 #define NETCONFIG_PROCWIRELESS                                  "/proc/net/wireless"
58
59 static int netconfig_wifi_rssi = VCONFKEY_WIFI_SNR_MIN;
60 static guint netconfig_wifi_indicator_timer = 0;
61
62 int netconfig_wifi_get_rssi(void)
63 {
64         return netconfig_wifi_rssi;
65 }
66
67 static int __netconfig_wifi_update_and_get_rssi(void)
68 {
69         char *if_path = NULL;
70         GVariant *message = NULL;
71         GVariant *value = NULL;
72         gchar *key;
73         GVariantIter *iter;
74         GVariant *variant;
75         gint32 key_value;
76         int rssi_dbm = VCONFKEY_WIFI_SNR_MIN;
77
78         if_path = netconfig_wifi_get_supplicant_interface();
79         if (if_path == NULL) {
80                 ERR("Fail to get wpa_supplicant DBus path");
81                 return 0;
82         }
83
84         message = netconfig_invoke_dbus_method(SUPPLICANT_SERVICE, if_path,
85                         SUPPLICANT_INTERFACE ".Interface", "SignalPoll", NULL);
86         if (message == NULL) {
87                 ERR("Fail to get SignalPoll from wpa_supplicant");
88                 g_free(if_path);
89                 return 0;
90         }
91
92         g_variant_get(message, "(v)", &value);
93
94         g_variant_get(value, "a{sv}", &iter);
95         while (g_variant_iter_loop(iter, "{sv}", &key, &variant)) {
96                 key_value = g_variant_get_int32(variant);
97
98                 if (g_strcmp0(key, "rssi") == 0) {
99                         rssi_dbm = (int)key_value;
100                         DBG("Currently signal dbm value [%d]", rssi_dbm);
101                         g_variant_unref(variant);
102                         g_free(key);
103                         break;
104                 }
105         }
106
107         g_variant_iter_free(iter);
108
109         if (value)
110                 g_variant_unref(value);
111
112         g_variant_unref(message);
113
114         g_free(if_path);
115
116         netconfig_wifi_rssi = rssi_dbm;
117
118         return rssi_dbm;
119 }
120
121 static int __netconfig_wifi_convert_dbm_to_level_24(int rssi_dbm)
122 {
123         int rssi_level = 0;
124
125         /* Wi-Fi Signal Strength Display (for 2.4G (dB))
126          *
127          * Excellent :     ~ -63
128          * Good      : -64 ~ -74
129          * Weak      : -75 ~ -82
130          * Very weak : -83 ~ -88
131          * No signal : -89 ~
132          */
133
134         if (rssi_dbm >= -63)
135                 rssi_level = 4;
136         else if (rssi_dbm >= -74)
137                 rssi_level = 3;
138         else if (rssi_dbm >= -82)
139                 rssi_level = 2;
140         else if (rssi_dbm >= -88)
141                 rssi_level = 1;
142         else
143                 rssi_level = 0;
144
145         return rssi_level;
146 }
147
148 static int __netconfig_wifi_convert_dbm_to_level_50(int rssi_dbm)
149 {
150         int rssi_level = 0;
151
152         /* Wi-Fi Signal Strength Display (for 5G (dB))
153          *
154          * Excellent :     ~ -72
155          * Good      : -73 ~ -78
156          * Weak      : -79 ~ -83
157          * Very weak : -84 ~ -88
158          * No signal : -89 ~
159          */
160
161         if (rssi_dbm >= -72)
162                 rssi_level = 4;
163         else if (rssi_dbm >= -78)
164                 rssi_level = 3;
165         else if (rssi_dbm >= -83)
166                 rssi_level = 2;
167         else if (rssi_dbm >= -88)
168                 rssi_level = 1;
169         else
170                 rssi_level = 0;
171
172         return rssi_level;
173 }
174
175 int netconfig_wifi_rssi_level(const int rssi_dbm)
176 {
177         int snr_level = 0;
178         int freq = 0;
179         int ret = 0;
180
181         ret = netconfig_vconf_get_int("memory/private/wifi/frequency", &freq);
182
183         if (!ret && freq > 4900)
184                 snr_level = __netconfig_wifi_convert_dbm_to_level_50(rssi_dbm);
185         else
186                 snr_level = __netconfig_wifi_convert_dbm_to_level_24(rssi_dbm);
187
188         return snr_level;
189 }
190
191 static void __netconfig_wifi_set_rssi_level(const int snr_level)
192 {
193         static int last_snr_level = 0;
194
195         if (snr_level != last_snr_level) {
196                 netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, snr_level);
197                 last_snr_level = snr_level;
198         }
199 }
200
201 static void __netconfig_wifi_data_activity_booster(int level)
202 {
203         gboolean reply = FALSE;
204         GVariant *params = NULL;
205         int level1 = 1;
206         int level2 = 2;
207         int level3 = 3;
208
209         int lock = 2000;
210         int unlock = 0;
211
212         static int old_level = 0;
213
214         if (level < 0)
215                 return;
216
217         if (level > 0) {
218                 /* enable booster */
219                 switch (level) {
220                 case 1:
221                         params = g_variant_new("(ii)", level1, lock);
222                         break;
223                 case 2:
224                         params = g_variant_new("(ii)", level2, lock);
225                         break;
226                 case 3:
227                         params = g_variant_new("(ii)", level3, lock);
228                         break;
229                 default:
230                         ERR("Invalid level");
231                         return;
232                 }
233
234                 reply = netconfig_invoke_dbus_method_nonblock(
235                                 "org.tizen.system.deviced",
236                                 "/Org/Tizen/System/DeviceD/PmQos",
237                                 "org.tizen.system.deviced.PmQos",
238                                 "WifiThroughput",
239                                 params,
240                                 NULL);
241                 if (reply != TRUE)
242                         return;
243         }
244
245         /* disable previous booster */
246         if (old_level == 0 || old_level == level)
247                 return;
248
249         switch (old_level) {
250         case 1:
251                 params = g_variant_new("(ii)", level1, unlock);
252                 break;
253         case 2:
254                 params = g_variant_new("(ii)", level2, unlock);
255                 break;
256         case 3:
257                 params = g_variant_new("(ii)", level3, unlock);
258                 break;
259         default:
260                 ERR("Invalid level");
261                 return;
262         }
263
264         reply = netconfig_invoke_dbus_method_nonblock(
265                         "org.tizen.system.deviced",
266                         "/Org/Tizen/System/DeviceD/PmQos",
267                         "org.tizen.system.deviced.PmQos",
268                         "WifiThroughput",
269                         params,
270                         NULL);
271         if (reply != TRUE)
272                 return;
273
274         old_level = level;
275 }
276
277 static void __netconfig_wifi_update_indicator(void)
278 {
279         static int last_transfer_state = 0;
280         static guint64 netconfig_wifi_tx_bytes = 0;
281         static guint64 netconfig_wifi_rx_bytes = 0;
282         static int booster_tic = 0;
283         static int old_level = 0;
284         int booster_level = 0;
285         guint64 tx, rx, tx_diff, rx_diff;
286         int transfer_state;
287
288         if (netconfig_wifi_get_bytes_statistics(&tx, &rx) == TRUE) {
289                 tx_diff = tx - netconfig_wifi_tx_bytes;
290                 rx_diff = rx - netconfig_wifi_rx_bytes;
291
292                 if (tx_diff > 0) {
293                         if (rx_diff > 0)
294                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TXRX;
295                         else
296                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TX;
297                 } else {
298                         if (rx_diff > 0)
299                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_RX;
300                         else
301                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_NONE;
302                 }
303
304                 if (transfer_state != last_transfer_state) {
305                         netconfig_set_vconf_int(VCONFKEY_WIFI_TRANSFER_STATE, transfer_state);
306                         last_transfer_state = transfer_state;
307                 }
308
309                 /* NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER */
310                 if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1 ||
311                         rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1)
312                         booster_level = 1;
313                 else if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2 ||
314                                 rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2)
315                         booster_level = 2;
316                 else if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3 ||
317                                 rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3)
318                         booster_level = 3;
319
320                 if (old_level == booster_level) {
321                         if (--booster_tic <= 0) {
322                                 __netconfig_wifi_data_activity_booster(booster_level);
323
324                                 booster_tic = 2;
325                         }
326                 } else {
327                         __netconfig_wifi_data_activity_booster(booster_level);
328
329                         if (booster_level > 0)
330                                 booster_tic = 2;
331                         else
332                                 booster_tic = 0;
333                 }
334
335                 old_level = booster_level;
336
337                 netconfig_wifi_tx_bytes = tx;
338                 netconfig_wifi_rx_bytes = rx;
339         }
340 }
341
342 static gboolean __wifi_indicator_monitor(gpointer data)
343 {
344         int rssi_dbm = 0;
345         int snr_level = 0;
346         int pm_state = VCONFKEY_PM_STATE_NORMAL;
347
348         if (wifi_state_get_service_state() != NETCONFIG_WIFI_CONNECTED)
349                 return FALSE;
350
351         /* In case of LCD off, we don't need to update Wi-Fi indicator */
352         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
353         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
354                 return TRUE;
355
356         rssi_dbm = __netconfig_wifi_update_and_get_rssi();
357         /* INFO("%d dbm", rssi_dbm); */
358         snr_level = netconfig_wifi_rssi_level(rssi_dbm);
359         __netconfig_wifi_set_rssi_level(snr_level);
360
361         __netconfig_wifi_update_indicator();
362
363         return TRUE;
364 }
365
366 void netconfig_wifi_indicator_start(void)
367 {
368         INFO("Start Wi-Fi indicator");
369
370         netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, VCONFKEY_WIFI_STRENGTH_MAX);
371         netconfig_start_timer_seconds(WIFI_INDICATOR_INTERVAL, __wifi_indicator_monitor, NULL, &netconfig_wifi_indicator_timer);
372 }
373
374 void netconfig_wifi_indicator_stop(void)
375 {
376         INFO("Stop Wi-Fi indicator");
377
378         netconfig_stop_timer(&netconfig_wifi_indicator_timer);
379
380         netconfig_wifi_rssi = VCONFKEY_WIFI_SNR_MIN;
381 }