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