Sync with Tizen 2.4(v1.1.38)
[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                 p_entry = strtok(p_entry, " .");        // status                       "%x"
104                 if (p_entry != NULL)
105                         sscanf(p_entry, "%x", &status);
106                 p_entry = strtok(NULL, " .");           // Quality link         "%d"
107                 if (p_entry != NULL)
108                         sscanf(p_entry, "%d", &link);
109                 p_entry = strtok(NULL, " .");           // Quality level        "%d"
110                 if (p_entry != NULL)
111                         sscanf(p_entry, "%d", &rssi_dbm);
112                 p_entry = strtok(NULL, " .");           // Quality noise        "%d"
113                 if (p_entry != NULL)
114                         sscanf(p_entry, "%d", &noise);
115
116                 /* No need to read */
117                 /*
118                 p_entry = strtok(NULL, " .");           // Discarded nwid       "%lu"
119                 sscanf(p_entry, "%lu", &nwid);
120                 p_entry = strtok(NULL, " .");           // Discarded crypt      "%lu"
121                 sscanf(p_entry, "%lu", &crypt);
122                 p_entry = strtok(NULL, " .");           // Discarded frag       "%lu"
123                 sscanf(p_entry, "%lu", &frag);
124                 p_entry = strtok(NULL, " .");           // Discarded retry      "%lu"
125                 sscanf(p_entry, "%lu", &retry);
126                 p_entry = strtok(NULL, " .");           // Discarded misc       "%lu"
127                 sscanf(p_entry, "%lu", &misc);
128                 p_entry = strtok(NULL, " .");           // Discarded missed     "%lu"
129                 sscanf(p_entry, "%lu", &missed);
130                 */
131
132                 break;
133         }
134
135 endline:
136         fclose(fp);
137         netconfig_wifi_rssi = rssi_dbm;
138
139         return rssi_dbm;
140 }
141
142 int netconfig_wifi_rssi_level(const int rssi_dbm)
143 {
144         int snr_level = 0;
145
146         /* Wi-Fi Signal Strength Display
147          *
148          * Excellent :  -63 ~
149          * Good:                -74 ~ -64
150          * Weak:                -82 ~ -75
151          * Very weak:           ~ -83
152          */
153         if (rssi_dbm >= -63)
154                 snr_level = 4;
155         else if (rssi_dbm >= -74)
156                 snr_level = 3;
157         else if (rssi_dbm >= -82)
158                 snr_level = 2;
159         else
160                 snr_level = 1;
161
162         return snr_level;
163 }
164
165 static void __netconfig_wifi_set_rssi_level(const int snr_level)
166 {
167         static int last_snr_level = 0;
168
169         if (snr_level != last_snr_level) {
170                 netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, snr_level);
171                 last_snr_level = snr_level;
172         }
173 }
174
175 static void __netconfig_wifi_data_activity_booster(int level)
176 {
177         gboolean reply = FALSE;
178         GVariant *params = NULL;
179         int level1 = 1;
180         int level2 = 2;
181         int level3 = 3;
182
183         int lock = 2000;
184         int unlock = 0;
185
186         static int old_level = 0;
187
188         if (level < 0)
189                 return;
190
191         if (level > 0) {
192                 /* enable booster */
193                 switch(level) {
194                 case 1:
195                         params = g_variant_new("(ii)", level1, lock);
196                         break;
197                 case 2:
198                         params = g_variant_new("(ii)", level2, lock);
199                         break;
200                 case 3:
201                         params = g_variant_new("(ii)", level3, lock);
202                         break;
203                 default:
204                         ERR("Invalid level");
205                         return;
206                 }
207
208                 reply = netconfig_invoke_dbus_method_nonblock(
209                                 "org.tizen.system.deviced",
210                                 "/Org/Tizen/System/DeviceD/PmQos",
211                                 "org.tizen.system.deviced.PmQos",
212                                 "WifiThroughput",
213                                 params,
214                                 NULL);
215                 if (reply != TRUE)
216                         return;
217         }
218
219         /* disable previous booster */
220         if (old_level == 0 || old_level == level)
221                 return;
222
223         switch(old_level) {
224         case 1:
225                 params = g_variant_new("(ii)", level1, unlock);
226                 break;
227         case 2:
228                 params = g_variant_new("(ii)", level2, unlock);
229                 break;
230         case 3:
231                 params = g_variant_new("(ii)", level3, unlock);
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         old_level = level;
249 }
250
251 static void __netconfig_wifi_update_indicator(void)
252 {
253         static int last_transfer_state = 0;
254         static guint64 netconfig_wifi_tx_bytes = 0;
255         static guint64 netconfig_wifi_rx_bytes = 0;
256         static int booster_tic = 0;
257         static int old_level = 0;
258         int booster_level = 0;
259         guint64 tx, rx, tx_diff, rx_diff;
260         int transfer_state;
261
262         if (netconfig_wifi_get_bytes_statistics(&tx, &rx) == TRUE) {
263                 tx_diff = tx - netconfig_wifi_tx_bytes;
264                 rx_diff = rx - netconfig_wifi_rx_bytes;
265
266                 if (tx_diff > 0) {
267                         if (rx_diff > 0)
268                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TXRX;
269                         else
270                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_TX;
271                 } else {
272                         if (rx_diff > 0)
273                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_RX;
274                         else
275                                 transfer_state = VCONFKEY_WIFI_TRANSFER_STATE_NONE;
276                 }
277
278                 if (transfer_state != last_transfer_state) {
279                         netconfig_set_vconf_int(VCONFKEY_WIFI_TRANSFER_STATE, transfer_state);
280                         last_transfer_state = transfer_state;
281                 }
282
283                 /* NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER */
284                 if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1 ||
285                         rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL1)
286                         booster_level = 1;
287                 else if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2 ||
288                                 rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL2)
289                         booster_level = 2;
290                 else if (tx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3 ||
291                                 rx_diff >= NETCONFIG_WIFI_DATA_ACTIVITY_BOOSTER_LEVEL3)
292                         booster_level = 3;
293
294                 if (old_level == booster_level) {
295                         if (--booster_tic <= 0) {
296                                 __netconfig_wifi_data_activity_booster(booster_level);
297
298                                 booster_tic = 2;
299                         }
300                 } else {
301                         __netconfig_wifi_data_activity_booster(booster_level);
302
303                         if (booster_level > 0)
304                                 booster_tic = 2;
305                         else
306                                 booster_tic = 0;
307                 }
308
309                 old_level = booster_level;
310
311                 netconfig_wifi_tx_bytes = tx;
312                 netconfig_wifi_rx_bytes = rx;
313         }
314 }
315
316 static gboolean __wifi_indicator_monitor(gpointer data)
317 {
318         int rssi_dbm = 0;
319         int snr_level = 0;
320         int pm_state = VCONFKEY_PM_STATE_NORMAL;
321
322         if (wifi_state_get_service_state() != NETCONFIG_WIFI_CONNECTED)
323                 return FALSE;
324
325         /* In case of LCD off, we don't need to update Wi-Fi indicator */
326         vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
327         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
328                 return TRUE;
329
330         rssi_dbm = __netconfig_wifi_update_and_get_rssi();
331         //INFO("%d dbm", rssi_dbm);
332         snr_level = netconfig_wifi_rssi_level(rssi_dbm);
333         __netconfig_wifi_set_rssi_level(snr_level);
334
335         __netconfig_wifi_update_indicator();
336
337         return TRUE;
338 }
339
340 void netconfig_wifi_indicator_start(void)
341 {
342         INFO("Start Wi-Fi indicator");
343
344         netconfig_set_vconf_int(VCONFKEY_WIFI_STRENGTH, VCONFKEY_WIFI_STRENGTH_MAX);
345         netconfig_start_timer_seconds(WIFI_INDICATOR_INTERVAL, __wifi_indicator_monitor, NULL, &netconfig_wifi_indicator_timer);
346 }
347
348 void netconfig_wifi_indicator_stop(void)
349 {
350         INFO("Stop Wi-Fi indicator");
351
352         netconfig_stop_timer(&netconfig_wifi_indicator_timer);
353
354         netconfig_wifi_rssi = VCONFKEY_WIFI_SNR_MIN;
355 }