Use file library of libsyscommon
[platform/adaptation/emulator/device-manager-plugin-emul.git] / hw / battery / battery.c
1 /*
2  * device-node
3  *
4  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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 <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <linux/limits.h>
25 #include <dirent.h>
26
27 #include <hal/device/hal-battery-interface.h>
28 #include <hal/hal-common-interface.h>
29 #include <libsyscommon/file.h>
30
31 #include "../dbus.h"
32 #include "common.h"
33
34 #define BATTERY_BUS      "org.tizen.system.deviced"
35 #define BATTERY_OBJECT   "/Org/Tizen/System/DeviceD/SysNoti"
36 #define BATTERY_IFACE    BATTERY_BUS".SysNoti"
37 #define BATTERY_SIGNAL   "power_supply"
38
39 #define FILE_BATTERY_CAPACITY "/sys/class/power_supply/battery/capacity"
40 #define FILE_BATTERY_CHARGER_ONLINE "/sys/devices/platform/jack/charger_online"
41 #define FILE_BATTERY_CHARGE_FULL "/sys/class/power_supply/battery/charge_full"
42 #define FILE_BATTERY_CHARGE_NOW "/sys/class/power_supply/battery/charge_now"
43
44 static struct signal_data {
45         BatteryUpdated updated_cb;
46         void *data;
47 } sdata = { 0, };
48
49 static int id; /* signal handler id */
50
51 static int get_power_source(int online, char **src)
52 {
53         if (!src)
54                 return -EINVAL;
55
56         switch (online) {
57         case 2:
58                 *src = POWER_SOURCE_AC;
59                 break;
60         case 4:
61                 *src = POWER_SOURCE_USB;
62                 break;
63         default:
64                 *src = POWER_SOURCE_NONE;
65                 break;
66         }
67
68         return 0;
69 }
70
71 static void signal_delivered(GDBusConnection *conn,
72                 const gchar *sender,
73                 const gchar *object,
74                 const gchar *iface,
75                 const gchar *signal,
76                 GVariant *parameters,
77                 gpointer user_data)
78 {
79         struct battery_info info;
80         int num, ret;
81         char *sig, *capacity, *status, *health, *online, *present;
82         char *val;
83
84         if (strncmp(signal, BATTERY_SIGNAL, sizeof(BATTERY_SIGNAL)))
85                 return;
86
87         _I("POWER_SUPPLY uevent is delivered");
88
89         if (!sdata.updated_cb) {
90                 _E("POWER_SUPPLY callback is NULL");
91                 return;
92         }
93
94         g_variant_get(parameters, "(sisssss)", &sig, &num,
95                         &capacity, &status, &health, &online, &present);
96
97         info.name = BATTERY_HARDWARE_DEVICE_ID;
98         info.status = status;
99         info.health = health;
100         info.online = atoi(online);
101         info.present = atoi(present);
102         info.capacity = atoi(capacity);
103
104         if (!strncmp(status, "Charging", strlen(status))) {
105                 info.current_now = 1000; /* uA */
106                 info.current_average = 1000; /* uA */
107         } else {
108                 info.current_now = -1000; /* uA */
109                 info.current_average = -1000; /* uA */
110         }
111
112         ret = get_power_source(info.online, &val);
113         if (ret < 0)
114                 goto out;
115         info.power_source = val;
116
117         sdata.updated_cb(&info, sdata.data);
118
119 out:
120         free(status);
121         free(health);
122         free(online);
123         free(present);
124         free(capacity);
125 }
126
127 static int battery_register_changed_event(
128                 BatteryUpdated updated_cb, void *data)
129 {
130         int ret;
131
132         if (sdata.updated_cb) {
133                 _E("update callback is already registered");
134                 return -EEXIST;
135         }
136
137         ret = register_dbus_signal(BATTERY_OBJECT,
138                         BATTERY_IFACE, BATTERY_SIGNAL,
139                         signal_delivered, &sdata, &id);
140         if (ret < 0) {
141                 _E("Failed to register signal");
142                 return -ENOMEM;
143         }
144
145         sdata.updated_cb = updated_cb;
146         sdata.data = data;
147
148         return ret;
149 }
150
151 static void battery_unregister_changed_event(
152                 BatteryUpdated updated_cb)
153 {
154         unregister_dbus_signal(&id);
155         sdata.updated_cb = NULL;
156         sdata.data = NULL;
157 }
158
159 static int battery_get_current_state(
160                 BatteryUpdated updated_cb, void *data)
161 {
162         int ret;
163         struct battery_info info;
164         char *status;
165         char *val;
166         char capacity_str[8];
167         char charger_str[8];
168         char charge_full_str[8];
169         char charge_now_str[8];
170         int capacity, charger, charge_full, charge_now;
171
172         if (!updated_cb)
173                 return -EINVAL;
174
175         info.name = BATTERY_HARDWARE_DEVICE_ID;
176
177         ret = sys_get_str(FILE_BATTERY_CAPACITY, capacity_str, sizeof(capacity_str));
178         if (ret < 0) {
179                 _E("Failed to get value of (%s, %d)", FILE_BATTERY_CAPACITY, ret);
180                 return ret;
181         }
182
183         /* When the TW emulator first accesses /sys/class/power_supply/battery/capacity,
184            it sometimes returns an empty string. */
185         if (capacity_str[0] == 0) {
186                 _E("/sys/class/power_supply/battery/capacity returns null string, retry read it again");
187                 ret = sys_get_str(FILE_BATTERY_CAPACITY, capacity_str, sizeof(capacity_str));
188                 if (ret < 0) {
189                          _E("Failed to get value of (%s, %d)", FILE_BATTERY_CAPACITY, ret);
190                          return ret;
191                 }
192         }
193
194         ret = sys_get_str(FILE_BATTERY_CHARGER_ONLINE, charger_str, sizeof(charger_str));
195         if (ret < 0) {
196                 _E("Failed to get value of (%s, %d)", FILE_BATTERY_CHARGER_ONLINE, ret);
197                 return ret;
198         }
199         ret = sys_get_str(FILE_BATTERY_CHARGE_FULL, charge_full_str, sizeof(charge_full_str));
200         if (ret < 0) {
201                 _E("Failed to get value of (%s, %d)", FILE_BATTERY_CHARGE_FULL, ret);
202                 return ret;
203         }
204         ret = sys_get_str(FILE_BATTERY_CHARGE_NOW, charge_now_str, sizeof(charge_now_str));
205         if (ret < 0) {
206                 _E("Failed to get value of (%s, %d)", FILE_BATTERY_CHARGE_NOW, ret);
207                 return ret;
208         }
209
210         capacity = atoi(capacity_str);
211         charger = atoi(charger_str);
212         charge_full = atoi(charge_full_str);
213         charge_now = atoi(charge_now_str);
214
215         if (charge_full == 1)
216                 status = "Full";
217         else if (charge_now == 1)
218                 status = "Charging";
219         else
220                 status = "Discharging";
221         info.status = status;
222
223         info.health = "Good";
224         info.online = charger + 1;
225         info.present = 1;
226         info.capacity = capacity;
227
228         if (charge_now == 1) {
229                 info.current_now = 1000; /* uA */
230                 info.current_average = 1000; /* uA */
231         } else {
232                 info.current_now = -1000; /* uA */
233                 info.current_average = -1000; /* uA */
234         }
235
236         /* Since there are no nodes for
237          * voltage_now, voltage_average, temperature
238          * in the emulator,
239          * use values similar to TM1.
240          */
241         info.voltage_now = 4000000;
242         info.voltage_average = 4000000;
243
244         info.temperature = 30;
245
246         ret = get_power_source(info.online, &val);
247         if (ret < 0)
248                 return ret;
249         info.power_source = val;
250
251         updated_cb(&info, data);
252
253         return 0;
254 }
255
256 static int battery_init(void **data)
257 {
258         hal_backend_battery_funcs *battery_funcs;
259
260         battery_funcs = calloc(1, sizeof(hal_backend_battery_funcs));
261         if (!battery_funcs)
262                 return -ENOMEM;
263
264         battery_funcs->register_changed_event = battery_register_changed_event;
265         battery_funcs->unregister_changed_event = battery_unregister_changed_event;
266         battery_funcs->get_current_state = battery_get_current_state;
267
268         *data = (void *)battery_funcs;
269
270         return 0;
271 }
272
273 static int battery_exit(void *data)
274 {
275         if (!data)
276                 return 0;
277
278         free(data);
279         return 0;
280 }
281
282 hal_backend EXPORT hal_backend_device_battery_data = {
283         .name = "battery",
284         .vendor = "EMUL",
285         .abi_version = HAL_ABI_VERSION_TIZEN_6_5,
286         .init = battery_init,
287         .exit = battery_exit,
288 };