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