1 /*
2 * Copyright 2020 Google LLC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/shell/shell.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/sensor.h>
13
14 /**
15 * @brief Collect the values for several channels
16 *
17 * @param dev Sensor device to read from
18 * @param ... any number of pairs of arguments:
19 * first is the sensor channel to read (-1 to terminate the list)
20 * second is a pointer to the struct sensor_value to put it in
21 * @return 0 on success
22 * @return negative error code from sensor API on failure
23 */
get_channels(const struct device * dev,...)24 static int get_channels(const struct device *dev, ...)
25 {
26 va_list ptr;
27 int i;
28
29 va_start(ptr, dev);
30 for (i = 0;; i++) {
31 int chan;
32 struct sensor_value *val;
33 int err;
34
35 chan = va_arg(ptr, int);
36 if (chan == -1) {
37 break;
38 }
39 val = va_arg(ptr, struct sensor_value *);
40 err = sensor_channel_get(dev, chan, val);
41 if (err < 0) {
42 va_end(ptr);
43 return err;
44 }
45 }
46
47 va_end(ptr);
48 return 0;
49 }
50
51 /* battery */
cmd_battery(const struct shell * sh,size_t argc,char ** argv)52 static int cmd_battery(const struct shell *sh, size_t argc, char **argv)
53 {
54 struct sensor_value temp, volt, current, i_desired, charge_remain;
55 struct sensor_value charge, v_desired, v_design, cap, nom_cap;
56 struct sensor_value full, empty;
57 const struct device *const dev = DEVICE_DT_GET(DT_ALIAS(battery));
58 bool allowed;
59 int err;
60
61 if (!device_is_ready(dev)) {
62 shell_error(sh, "Device not ready (%s)", argv[1]);
63 return -ENODEV;
64 }
65
66 err = sensor_sample_fetch(dev);
67 if (err < 0) {
68 shell_error(sh, "Failed to read sensor: %d", err);
69 }
70
71 err = get_channels(dev,
72 SENSOR_CHAN_GAUGE_TEMP, &temp,
73 SENSOR_CHAN_GAUGE_VOLTAGE, &volt,
74 SENSOR_CHAN_GAUGE_AVG_CURRENT, ¤t,
75 SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE, &v_desired,
76 SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT,
77 &i_desired,
78 SENSOR_CHAN_GAUGE_STATE_OF_CHARGE, &charge,
79 SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE, &v_design,
80 SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY,
81 &charge_remain,
82 SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY, &cap,
83 SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY, &nom_cap,
84 SENSOR_CHAN_GAUGE_TIME_TO_FULL, &full,
85 SENSOR_CHAN_GAUGE_TIME_TO_EMPTY, &empty,
86 -1);
87 if (err < 0) {
88 return err;
89 }
90
91 shell_fprintf(sh, SHELL_NORMAL, "Temp: %.1d.%02d C\n", temp.val1,
92 temp.val2 / 10000);
93 shell_fprintf(sh, SHELL_NORMAL, "V: %5d.%02d V\n", volt.val1,
94 volt.val2 / 10000);
95 shell_fprintf(sh, SHELL_NORMAL, "V-desired: %d.%02d V\n",
96 v_desired.val1, v_desired.val2 / 10000);
97 shell_fprintf(sh, SHELL_NORMAL, "I: %d mA", current.val1);
98 if (current.val1 > 0) {
99 shell_fprintf(sh, SHELL_NORMAL, " (CHG)");
100 } else if (current.val1 < 0) {
101 shell_fprintf(sh, SHELL_NORMAL, " (DISCHG)");
102 }
103 shell_fprintf(sh, SHELL_NORMAL, "\n");
104 shell_fprintf(sh, SHELL_NORMAL, "I-desired: %5d mA\n",
105 i_desired.val1);
106 allowed = i_desired.val1 && v_desired.val2 && charge.val1 < 100;
107 shell_fprintf(sh, SHELL_NORMAL, "Charging: %sAllowed\n",
108 allowed ? "" : "Not ");
109 shell_fprintf(sh, SHELL_NORMAL, "Charge: %d %%\n", charge.val1);
110 shell_fprintf(sh, SHELL_NORMAL, "V-design: %d.%02d V\n",
111 v_design.val1, v_design.val2 / 10000);
112 shell_fprintf(sh, SHELL_NORMAL, "Remaining: %d mA\n",
113 charge_remain.val1);
114 shell_fprintf(sh, SHELL_NORMAL, "Cap-full: %d mA\n", cap.val1);
115 shell_fprintf(sh, SHELL_NORMAL, "Design: %d mA\n", nom_cap.val1);
116 shell_fprintf(sh, SHELL_NORMAL, "Time full: %dh:%02d\n",
117 full.val1 / 60, full.val1 % 60);
118 shell_fprintf(sh, SHELL_NORMAL, "Time empty: %dh:%02d\n",
119 empty.val1 / 60, empty.val1 % 60);
120
121 return 0;
122 }
123
124 SHELL_CMD_REGISTER(battery, NULL, "Battery status", cmd_battery);
125