36cf86e80a7cc1efbd2f7d800b0c2b1734b59ce3
[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         FILE *fp;
70         char buf[512];
71         char *p_ifname = NULL, *p_entry = NULL;
72         int rssi_dbm = VCONFKEY_WIFI_SNR_MIN;
73
74         fp = fopen(NETCONFIG_PROCWIRELESS, "r");
75         if (fp == NULL) {
76                 ERR("Failed to open %s", NETCONFIG_PROCWIRELESS);
77                 return rssi_dbm;
78         }
79
80         /* skip the first and second line */
81         if (fgets(buf, sizeof(buf), fp) == NULL ||
82                         fgets(buf, sizeof(buf), fp) == NULL)
83                 goto endline;
84
85         while (fgets(buf, sizeof(buf), fp)) {
86                 unsigned int status = 0;
87                 int link = 0;
88                 int noise = 0;
89                 /* No need to read */
90                 /*
91                 unsigned long nwid, crypt, frag, retry, misc, missed;
92                 */
93
94                 p_ifname = buf;
95                 while (*p_ifname == ' ') p_ifname++;
96                 p_entry = strchr(p_ifname, ':');
97                 if (p_entry == NULL)
98                         goto endline;
99                 *p_entry++ = '\0';
100
101                 if (g_strcmp0(p_ifname, WIFI_IFNAME) != 0)
102                         continue;
103
104                 /* read wireless status */
105                 char *saveptr;
106                 p_entry = strtok_r(p_entry, " .", &saveptr);
107
108                 /* status "%x" */
109                 if (p_entry != NULL)
110                         status = (int)strtol(p_entry, NULL, 16);
111
112                 p_entry = strtok_r(NULL, " .", &saveptr);
113
114                 /* Quality link "%d" */
115                 if (p_entry != NULL)
116                         link = (int)strtol(p_entry, NULL, 10);
117
118                 p_entry = strtok_r(NULL, " .", &saveptr);
119
120                 /* Quality level "%d" */
121                 if (p_entry != NULL)
122                         rssi_dbm = (int)strtol(p_entry, NULL, 10);
123
124                 p_entry = strtok_r(NULL, " .", &saveptr);
125
126                 /* Quality noise "%d" */
127                 if (p_entry != NULL)
128                         noise = (int)strtol(p_entry, NULL, 10);
129
130                 DBG("status(%x) link(%d) rssi_dbm(%d) noise(%d)",
131                         status, link, rssi_dbm, noise);
132
133                 /* No need to read */
134                 /*
135                 p_entry = strtok(NULL, " .");           // Discarded nwid       "%lu"
136                 sscanf(p_entry, "%lu", &nwid);
137                 p_entry = strtok(NULL, " .");           // Discarded crypt      "%lu"
138                 sscanf(p_entry, "%lu", &crypt);
139                 p_entry = strtok(NULL, " .");           // Discarded frag       "%lu"
140                 sscanf(p_entry, "%lu", &frag);
141                 p_entry = strtok(NULL, " .");           // Discarded retry      "%lu"
142                 sscanf(p_entry, "%lu", &retry);
143                 p_entry = strtok(NULL, " .");           // Discarded misc       "%lu"
144                 sscanf(p_entry, "%lu", &misc);
145                 p_entry = strtok(NULL, " .");           // Discarded missed     "%lu"
146                 sscanf(p_entry, "%lu", &missed);
147                 */
148
149                 break;
150         }
151
152 endline:
153         fclose(fp);
154         netconfig_wifi_rssi = rssi_dbm;
155
156         return rssi_dbm;
157 }
158
159 int netconfig_wifi_rssi_level(const int rssi_dbm)
160 {
161         int snr_level = 0;
162
163         /* Wi-Fi Signal Strength Display
164          *
165          * Excellent :  -63 ~
166          * Good:                -74 ~ -64
167          * Weak:                -82 ~ -75
168          * Very weak:           ~ -83
169          */
170         if (rssi_dbm >= -63)
171                 snr_level = 4;
172         else if (rssi_dbm >= -74)
173                 snr_level = 3;
174         else if (rssi_dbm >= -82)
175                 snr_level = 2;
176         else
177                 snr_level = 1;
178
179         return snr_level;
180 }
181
182 static void __netconfig_wifi_set_rssi_level(const int snr_level)
183 {
184         static int last_snr_level = 0;
185
186         if (snr_level != last_snr_level) {
187                 netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, snr_level);
188                 last_snr_level = snr_level;
189         }
190 }
191
192 static void __netconfig_wifi_data_activity_booster(int level)
193 {
194         gboolean reply = FALSE;
195         GVariant *params = NULL;
196         int level1 = 1;
197         int level2 = 2;
198         int level3 = 3;
199
200         int lock = 2000;
201         int unlock = 0;
202
203         static int old_level = 0;
204
205         if (level < 0)
206                 return;
207
208         if (level > 0) {
209                 /* enable booster */
210                 switch (level) {
211                 case 1:
212                         params = g_variant_new("(ii)", level1, lock);
213                         break;
214                 case 2:
215                         params = g_variant_new("(ii)", level2, lock);
216                         break;
217                 case 3:
218                         params = g_variant_new("(ii)", level3, lock);
219                         break;
220                 default:
221                         ERR("Invalid level");
222                         return;
223                 }
224
225                 reply = netconfig_invoke_dbus_method_nonblock(
226                                 "org.tizen.system.deviced",
227                                 "/Org/Tizen/System/DeviceD/PmQos",
228                                 "org.tizen.system.deviced.PmQos",
229                                 "WifiThroughput",
230                                 params,
231                                 NULL);
232                 if (reply != TRUE)
233                         return;
234         }
235
236         /* disable previous booster */
237         if (old_level == 0 || old_level == level)
238                 return;
239
240         switch (old_level) {
241         case 1:
242                 params = g_variant_new("(ii)", level1, unlock);
243                 break;
244         case 2:
245                 params = g_variant_new("(ii)", level2, unlock);
246                 break;
247         case 3:
248                 params = g_variant_new("(ii)", level3, unlock);
249                 break;
250         default:
251                 ERR("Invalid level");
252                 return;
253         }
254
255         reply = netconfig_invoke_dbus_method_nonblock(
256                         "org.tizen.system.deviced",
257                         "/Org/Tizen/System/DeviceD/PmQos",
258                         "org.tizen.system.deviced.PmQos",
259                         "WifiThroughput",
260                         params,
261                         NULL);
262         if (reply != TRUE)
263                 return;
264
265         old_level = level;
266 }
267
268 static void __netconfig_wifi_update_indicator(void)
269 {
270         static int last_transfer_state = 0;
271         static guint64 netconfig_wifi_tx_bytes = 0;
272         static guint64 netconfig_wifi_rx_bytes = 0;
273         static int booster_tic = 0;
274         static int old_level = 0;
275         int booster_level = 0;
276         guint64 tx, rx, tx_diff, rx_diff;
277         int transfer_state;
278
279         if (netconfig_wifi_get_bytes_statistics(&tx, &rx) == TRUE) {
280                 tx_diff = tx - netconfig_wifi_tx_bytes;
281                 rx_diff = rx - netconfig_wifi_rx_bytes;
282
283                 if (tx_diff > 0) {
284                         if (rx_diff > 0)
285                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TXRX;
286                         else
287                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TX;
288                 } else {
289                         if (rx_diff > 0)
290                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_RX;
291                         else
292                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_NONE;
293                 }
294
295                 if (transfer_state != last_transfer_state) {
296                         netconfig_set_vconf_int(VCONFKEY_WIFI_TRANSFER_STATE, transfer_state);
297                         last_transfer_state = transfer_state;
298                 }
299
300                 /* NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER */
301                 if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1 ||
302                         rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1)
303                         booster_level = 1;
304                 else if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2 ||
305                                 rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2)
306                         booster_level = 2;
307                 else if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3 ||
308                                 rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3)
309                         booster_level = 3;
310
311                 if (old_level == booster_level) {
312                         if (--booster_tic <= 0) {
313                                 __netconfig_wifi_data_activity_booster(booster_level);
314
315                                 booster_tic = 2;
316                         }
317                 } else {
318                         __netconfig_wifi_data_activity_booster(booster_level);
319
320                         if (booster_level > 0)
321                                 booster_tic = 2;
322                         else
323                                 booster_tic = 0;
324                 }
325
326                 old_level = booster_level;
327
328                 netconfig_wifi_tx_bytes = tx;
329                 netconfig_wifi_rx_bytes = rx;
330         }
331 }
332
333 static gboolean __wifi_indicator_monitor(gpointer data)
334 {
335         int rssi_dbm = 0;
336         int snr_level = 0;
337         int pm_state = VCONFKEY_PM_STATE_NORMAL;
338
339         if (wifi_state_get_service_state() != NETCONFIG_WIFI_CONNECTED)
340                 return FALSE;
341
342         /* In case of LCD off, we don't need to update Wi-Fi indicator */
343         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
344         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
345                 return TRUE;
346
347         rssi_dbm = __netconfig_wifi_update_and_get_rssi();
348         /* INFO("%d dbm", rssi_dbm); */
349         snr_level = netconfig_wifi_rssi_level(rssi_dbm);
350         __netconfig_wifi_set_rssi_level(snr_level);
351
352         __netconfig_wifi_update_indicator();
353
354         return TRUE;
355 }
356
357 void netconfig_wifi_indicator_start(void)
358 {
359         INFO("Start Wi-Fi indicator");
360
361         netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, VCONFKEY_WIFI_STRENGTH_MAX);
362         netconfig_start_timer_seconds(WIFI_INDICATOR_INTERVAL, __wifi_indicator_monitor, NULL, &netconfig_wifi_indicator_timer);
363 }
364
365 void netconfig_wifi_indicator_stop(void)
366 {
367         INFO("Stop Wi-Fi indicator");
368
369         netconfig_stop_timer(&netconfig_wifi_indicator_timer);
370
371         netconfig_wifi_rssi = VCONFKEY_WIFI_SNR_MIN;
372 }