1 /*
2 * Copyright (c) 2023 Alvaro Garcia Gomez <maxpowel@gmail.com>
3 * Copyright (c) 2025 Philipp Steiner <philipp.steiner1987@gmail.com>
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include "zephyr/sys/util.h"
9 #include <zephyr/kernel.h>
10 #include <zephyr/device.h>
11 #include <zephyr/devicetree.h>
12 #include <zephyr/drivers/fuel_gauge.h>
13
14 #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(app);
17
fuel_gauge_prop_to_str(enum fuel_gauge_prop_type prop)18 const char *fuel_gauge_prop_to_str(enum fuel_gauge_prop_type prop)
19 {
20 switch (prop) {
21 case FUEL_GAUGE_AVG_CURRENT:
22 return "FUEL_GAUGE_AVG_CURRENT";
23 case FUEL_GAUGE_CURRENT:
24 return "FUEL_GAUGE_CURRENT";
25 case FUEL_GAUGE_CHARGE_CUTOFF:
26 return "FUEL_GAUGE_CHARGE_CUTOFF";
27 case FUEL_GAUGE_CYCLE_COUNT:
28 return "FUEL_GAUGE_CYCLE_COUNT";
29 case FUEL_GAUGE_CONNECT_STATE:
30 return "FUEL_GAUGE_CONNECT_STATE";
31 case FUEL_GAUGE_FLAGS:
32 return "FUEL_GAUGE_FLAGS";
33 case FUEL_GAUGE_FULL_CHARGE_CAPACITY:
34 return "FUEL_GAUGE_FULL_CHARGE_CAPACITY";
35 case FUEL_GAUGE_PRESENT_STATE:
36 return "FUEL_GAUGE_PRESENT_STATE";
37 case FUEL_GAUGE_REMAINING_CAPACITY:
38 return "FUEL_GAUGE_REMAINING_CAPACITY";
39 case FUEL_GAUGE_RUNTIME_TO_EMPTY:
40 return "FUEL_GAUGE_RUNTIME_TO_EMPTY";
41 case FUEL_GAUGE_RUNTIME_TO_FULL:
42 return "FUEL_GAUGE_RUNTIME_TO_FULL";
43 case FUEL_GAUGE_SBS_MFR_ACCESS:
44 return "FUEL_GAUGE_SBS_MFR_ACCESS";
45 case FUEL_GAUGE_ABSOLUTE_STATE_OF_CHARGE:
46 return "FUEL_GAUGE_ABSOLUTE_STATE_OF_CHARGE";
47 case FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE:
48 return "FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE";
49 case FUEL_GAUGE_TEMPERATURE:
50 return "FUEL_GAUGE_TEMPERATURE";
51 case FUEL_GAUGE_VOLTAGE:
52 return "FUEL_GAUGE_VOLTAGE";
53 case FUEL_GAUGE_SBS_MODE:
54 return "FUEL_GAUGE_SBS_MODE";
55 case FUEL_GAUGE_CHARGE_CURRENT:
56 return "FUEL_GAUGE_CHARGE_CURRENT";
57 case FUEL_GAUGE_CHARGE_VOLTAGE:
58 return "FUEL_GAUGE_CHARGE_VOLTAGE";
59 case FUEL_GAUGE_STATUS:
60 return "FUEL_GAUGE_STATUS";
61 case FUEL_GAUGE_DESIGN_CAPACITY:
62 return "FUEL_GAUGE_DESIGN_CAPACITY";
63 case FUEL_GAUGE_DESIGN_VOLTAGE:
64 return "FUEL_GAUGE_DESIGN_VOLTAGE";
65 case FUEL_GAUGE_SBS_ATRATE:
66 return "FUEL_GAUGE_SBS_ATRATE";
67 case FUEL_GAUGE_SBS_ATRATE_TIME_TO_FULL:
68 return "FUEL_GAUGE_SBS_ATRATE_TIME_TO_FULL";
69 case FUEL_GAUGE_SBS_ATRATE_TIME_TO_EMPTY:
70 return "FUEL_GAUGE_SBS_ATRATE_TIME_TO_EMPTY";
71 case FUEL_GAUGE_SBS_ATRATE_OK:
72 return "FUEL_GAUGE_SBS_ATRATE_OK";
73 case FUEL_GAUGE_SBS_REMAINING_CAPACITY_ALARM:
74 return "FUEL_GAUGE_SBS_REMAINING_CAPACITY_ALARM";
75 case FUEL_GAUGE_SBS_REMAINING_TIME_ALARM:
76 return "FUEL_GAUGE_SBS_REMAINING_TIME_ALARM";
77 case FUEL_GAUGE_MANUFACTURER_NAME:
78 return "FUEL_GAUGE_MANUFACTURER_NAME";
79 case FUEL_GAUGE_DEVICE_NAME:
80 return "FUEL_GAUGE_DEVICE_NAME";
81 case FUEL_GAUGE_DEVICE_CHEMISTRY:
82 return "FUEL_GAUGE_DEVICE_CHEMISTRY";
83 case FUEL_GAUGE_CURRENT_DIRECTION:
84 return "FUEL_GAUGE_CURRENT_DIRECTION";
85 case FUEL_GAUGE_STATE_OF_CHARGE_ALARM:
86 return "FUEL_GAUGE_STATE_OF_CHARGE_ALARM";
87 case FUEL_GAUGE_LOW_VOLTAGE_ALARM:
88 return "FUEL_GAUGE_LOW_VOLTAGE_ALARM";
89 default:
90 return "Unknown fuel gauge property";
91 }
92 }
93
main(void)94 int main(void)
95 {
96 const struct device *const dev = DEVICE_DT_GET(DT_ALIAS(fuel_gauge0));
97 int ret = 0;
98
99 if (dev == NULL) {
100 LOG_ERR("no device found.");
101 return 0;
102 }
103
104 if (!device_is_ready(dev)) {
105 LOG_ERR("Error: Device \"%s\" is not ready; check the driver initialization logs "
106 "for errors.",
107 dev->name);
108 return 0;
109 }
110
111 LOG_INF("Found device \"%s\"", dev->name);
112
113 {
114 LOG_INF("Test-Read generic fuel gauge properties to verify which are supported");
115 LOG_INF("Info: not all properties are supported by all fuel gauges!");
116
117 fuel_gauge_prop_t test_props[] = {
118 FUEL_GAUGE_AVG_CURRENT,
119 FUEL_GAUGE_CURRENT,
120 FUEL_GAUGE_CHARGE_CUTOFF,
121 FUEL_GAUGE_CYCLE_COUNT,
122 FUEL_GAUGE_CONNECT_STATE,
123 FUEL_GAUGE_FLAGS,
124 FUEL_GAUGE_FULL_CHARGE_CAPACITY,
125 FUEL_GAUGE_PRESENT_STATE,
126 FUEL_GAUGE_REMAINING_CAPACITY,
127 FUEL_GAUGE_RUNTIME_TO_EMPTY,
128 FUEL_GAUGE_RUNTIME_TO_FULL,
129 FUEL_GAUGE_SBS_MFR_ACCESS,
130 FUEL_GAUGE_ABSOLUTE_STATE_OF_CHARGE,
131 FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE,
132 FUEL_GAUGE_TEMPERATURE,
133 FUEL_GAUGE_VOLTAGE,
134 FUEL_GAUGE_SBS_MODE,
135 FUEL_GAUGE_CHARGE_CURRENT,
136 FUEL_GAUGE_CHARGE_VOLTAGE,
137 FUEL_GAUGE_STATUS,
138 FUEL_GAUGE_DESIGN_CAPACITY,
139 FUEL_GAUGE_DESIGN_VOLTAGE,
140 FUEL_GAUGE_SBS_ATRATE,
141 FUEL_GAUGE_SBS_ATRATE_TIME_TO_FULL,
142 FUEL_GAUGE_SBS_ATRATE_TIME_TO_EMPTY,
143 FUEL_GAUGE_SBS_ATRATE_OK,
144 FUEL_GAUGE_SBS_REMAINING_CAPACITY_ALARM,
145 FUEL_GAUGE_SBS_REMAINING_TIME_ALARM,
146 FUEL_GAUGE_MANUFACTURER_NAME,
147 FUEL_GAUGE_DEVICE_NAME,
148 FUEL_GAUGE_DEVICE_CHEMISTRY,
149 FUEL_GAUGE_CURRENT_DIRECTION,
150 FUEL_GAUGE_STATE_OF_CHARGE_ALARM,
151 FUEL_GAUGE_LOW_VOLTAGE_ALARM,
152 };
153
154 union fuel_gauge_prop_val test_vals[ARRAY_SIZE(test_props)];
155
156 for (size_t i = 0; i < ARRAY_SIZE(test_props); i++) {
157
158 if (test_props[i] == FUEL_GAUGE_MANUFACTURER_NAME) {
159 struct sbs_gauge_manufacturer_name mfg_name;
160
161 ret = fuel_gauge_get_buffer_prop(dev, FUEL_GAUGE_MANUFACTURER_NAME,
162 &mfg_name, sizeof(mfg_name));
163 if (ret == -ENOTSUP) {
164 LOG_INF("Property \"%s\" is not supported",
165 fuel_gauge_prop_to_str(test_props[i]));
166 } else if (ret < 0) {
167 LOG_ERR("Error: cannot get property \"%s\": %d",
168 fuel_gauge_prop_to_str(test_props[i]), ret);
169 } else {
170 LOG_INF("Property \"%s\" is supported",
171 fuel_gauge_prop_to_str(test_props[i]));
172 LOG_INF("Manufacturer name: %s",
173 mfg_name.manufacturer_name);
174 }
175 } else if (test_props[i] == FUEL_GAUGE_DEVICE_NAME) {
176 struct sbs_gauge_device_name dev_name;
177
178 ret = fuel_gauge_get_buffer_prop(dev, FUEL_GAUGE_DEVICE_NAME,
179 &dev_name, sizeof(dev_name));
180 if (ret == -ENOTSUP) {
181 LOG_INF("Property \"%s\" is not supported",
182 fuel_gauge_prop_to_str(test_props[i]));
183 } else if (ret < 0) {
184 LOG_ERR("Error: cannot get property \"%s\": %d",
185 fuel_gauge_prop_to_str(test_props[i]), ret);
186 } else {
187 LOG_INF("Property \"%s\" is supported",
188 fuel_gauge_prop_to_str(test_props[i]));
189 LOG_INF("Device name: %s", dev_name.device_name);
190 }
191 } else if (test_props[i] == FUEL_GAUGE_DEVICE_CHEMISTRY) {
192 struct sbs_gauge_device_chemistry device_chemistry;
193
194 ret = fuel_gauge_get_buffer_prop(dev, FUEL_GAUGE_DEVICE_CHEMISTRY,
195 &device_chemistry,
196 sizeof(device_chemistry));
197 if (ret == -ENOTSUP) {
198 LOG_INF("Property \"%s\" is not supported",
199 fuel_gauge_prop_to_str(test_props[i]));
200 } else if (ret < 0) {
201 LOG_ERR("Error: cannot get property \"%s\": %d",
202 fuel_gauge_prop_to_str(test_props[i]), ret);
203 } else {
204 LOG_INF("Property \"%s\" is supported",
205 fuel_gauge_prop_to_str(test_props[i]));
206 LOG_INF("Device chemistry: %s",
207 device_chemistry.device_chemistry);
208 }
209 } else {
210 /* For all other properties, use the generic get_props function */
211
212 ret = fuel_gauge_get_props(dev, &test_props[i], &test_vals[i], 1);
213
214 if (ret == -ENOTSUP) {
215 LOG_INF("Property \"%s\" is not supported",
216 fuel_gauge_prop_to_str(test_props[i]));
217 } else if (ret < 0) {
218 LOG_ERR("Error: cannot get property \"%s\": %d",
219 fuel_gauge_prop_to_str(test_props[i]), ret);
220 } else {
221 LOG_INF("Property \"%s\" is supported",
222 fuel_gauge_prop_to_str(test_props[i]));
223
224 switch (test_props[i]) {
225 case FUEL_GAUGE_AVG_CURRENT:
226 LOG_INF(" Avg current: %d",
227 test_vals[i].avg_current);
228 break;
229 case FUEL_GAUGE_CURRENT:
230 LOG_INF(" Current: %d", test_vals[i].current);
231 break;
232 case FUEL_GAUGE_CYCLE_COUNT:
233 LOG_INF(" Cycle count: %" PRIu32,
234 test_vals[i].cycle_count);
235 break;
236 case FUEL_GAUGE_CONNECT_STATE:
237 LOG_INF(" Connect state: 0x%" PRIx32,
238 test_vals[i].connect_state);
239 break;
240 case FUEL_GAUGE_FLAGS:
241 LOG_INF(" Flags: 0x%" PRIx32, test_vals[i].flags);
242 break;
243 case FUEL_GAUGE_FULL_CHARGE_CAPACITY:
244 LOG_INF(" Full charge capacity: %" PRIu32,
245 test_vals[i].full_charge_capacity);
246 break;
247 case FUEL_GAUGE_PRESENT_STATE:
248 LOG_INF(" Present state: %d",
249 test_vals[i].present_state);
250 break;
251 case FUEL_GAUGE_REMAINING_CAPACITY:
252 LOG_INF(" Remaining capacity: %" PRIu32,
253 test_vals[i].remaining_capacity);
254 break;
255 case FUEL_GAUGE_RUNTIME_TO_EMPTY:
256 LOG_INF(" Runtime to empty: %" PRIu32,
257 test_vals[i].runtime_to_empty);
258 break;
259 case FUEL_GAUGE_RUNTIME_TO_FULL:
260 LOG_INF(" Runtime to full: %" PRIu32,
261 test_vals[i].runtime_to_full);
262 break;
263 case FUEL_GAUGE_SBS_MFR_ACCESS:
264 LOG_INF(" SBS MFR access: %" PRIu16,
265 test_vals[i].sbs_mfr_access_word);
266 break;
267 case FUEL_GAUGE_ABSOLUTE_STATE_OF_CHARGE:
268 LOG_INF(" Absolute state of charge: %" PRIu8,
269 test_vals[i].absolute_state_of_charge);
270 break;
271 case FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE:
272 LOG_INF(" Relative state of charge: %" PRIu8,
273 test_vals[i].relative_state_of_charge);
274 break;
275 case FUEL_GAUGE_TEMPERATURE:
276 LOG_INF(" Temperature: %" PRIu16,
277 test_vals[i].temperature);
278 break;
279 case FUEL_GAUGE_VOLTAGE:
280 LOG_INF(" Voltage: %d", test_vals[i].voltage);
281 break;
282 case FUEL_GAUGE_SBS_MODE:
283 LOG_INF(" SBS mode: %" PRIu16,
284 test_vals[i].sbs_mode);
285 break;
286 case FUEL_GAUGE_CHARGE_CURRENT:
287 LOG_INF(" Charge current: %" PRIu32,
288 test_vals[i].chg_current);
289 break;
290 case FUEL_GAUGE_CHARGE_VOLTAGE:
291 LOG_INF(" Charge voltage: %" PRIu32,
292 test_vals[i].chg_voltage);
293 break;
294 case FUEL_GAUGE_STATUS:
295 LOG_INF(" Status: 0x%" PRIx16,
296 test_vals[i].fg_status);
297 break;
298 case FUEL_GAUGE_DESIGN_CAPACITY:
299 LOG_INF(" Design capacity: %" PRIu16,
300 test_vals[i].design_cap);
301 break;
302 case FUEL_GAUGE_DESIGN_VOLTAGE:
303 LOG_INF(" Design voltage: %" PRIx16,
304 test_vals[i].design_volt);
305 break;
306 case FUEL_GAUGE_SBS_ATRATE:
307 LOG_INF(" SBS at rate: %" PRIi16,
308 test_vals[i].sbs_at_rate);
309 break;
310 case FUEL_GAUGE_SBS_ATRATE_TIME_TO_FULL:
311 LOG_INF(" SBS at rate time to full: %" PRIu16,
312 test_vals[i].sbs_at_rate_time_to_full);
313 break;
314 case FUEL_GAUGE_SBS_ATRATE_TIME_TO_EMPTY:
315 LOG_INF(" SBS at rate time to empty: %" PRIu16,
316 test_vals[i].sbs_at_rate_time_to_empty);
317 break;
318 case FUEL_GAUGE_SBS_ATRATE_OK:
319 LOG_INF(" SBS at rate ok: %d",
320 test_vals[i].sbs_at_rate_ok);
321 break;
322 case FUEL_GAUGE_SBS_REMAINING_CAPACITY_ALARM:
323 LOG_INF(" SBS remaining capacity alarm: %" PRIu16,
324 test_vals[i].sbs_remaining_capacity_alarm);
325 break;
326 case FUEL_GAUGE_SBS_REMAINING_TIME_ALARM:
327 LOG_INF(" SBS remaining time alarm: %" PRIu16,
328 test_vals[i].sbs_remaining_time_alarm);
329 break;
330 case FUEL_GAUGE_CURRENT_DIRECTION:
331 LOG_INF(" Current direction: %" PRIu16,
332 test_vals[i].current_direction);
333 break;
334 case FUEL_GAUGE_STATE_OF_CHARGE_ALARM:
335 LOG_INF(" State of charge alarm: %" PRIu8,
336 test_vals[i].state_of_charge_alarm);
337 break;
338 case FUEL_GAUGE_LOW_VOLTAGE_ALARM:
339 LOG_INF(" Low voltage alarm: %" PRIu32,
340 test_vals[i].low_voltage_alarm);
341 break;
342 }
343 }
344 }
345 }
346 }
347
348 LOG_INF("Polling fuel gauge data 'FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE' & "
349 "'FUEL_GAUGE_VOLTAGE'");
350
351 while (1) {
352 fuel_gauge_prop_t poll_props[] = {
353 FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE,
354 FUEL_GAUGE_VOLTAGE,
355 };
356
357 union fuel_gauge_prop_val poll_vals[ARRAY_SIZE(poll_props)];
358
359 ret = fuel_gauge_get_props(dev, poll_props, poll_vals, ARRAY_SIZE(poll_props));
360
361 if (ret < 0) {
362 LOG_ERR("Error: cannot get properties");
363 } else {
364 LOG_INF("Fuel gauge data: Charge: %d%%, Voltage: %dmV",
365 poll_vals[0].relative_state_of_charge, poll_vals[1].voltage / 1000);
366 }
367
368 k_sleep(K_MSEC(5000));
369 }
370 return 0;
371 }
372