/* * Copyright 2020 Google LLC * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include /** * @brief Collect the values for several channels * * @param dev Sensor device to read from * @param ... any number of pairs of arguments: * first is the sensor channel to read (-1 to terminate the list) * second is a pointer to the struct sensor_value to put it in * @return 0 on success * @return negative error code from sensor API on failure */ static int get_channels(const struct device *dev, ...) { va_list ptr; int i; va_start(ptr, dev); for (i = 0;; i++) { int chan; struct sensor_value *val; int err; chan = va_arg(ptr, int); if (chan == -1) { break; } val = va_arg(ptr, struct sensor_value *); err = sensor_channel_get(dev, chan, val); if (err < 0) { va_end(ptr); return err; } } va_end(ptr); return 0; } /* battery */ static int cmd_battery(const struct shell *shell, size_t argc, char **argv) { struct sensor_value temp, volt, current, i_desired, charge_remain; struct sensor_value charge, v_desired, v_design, cap, nom_cap; struct sensor_value full, empty; const struct device *const dev = DEVICE_DT_GET(DT_ALIAS(battery)); bool allowed; int err; if (!device_is_ready(dev)) { shell_error(shell, "Device not ready (%s)", argv[1]); return -ENODEV; } err = sensor_sample_fetch(dev); if (err < 0) { shell_error(shell, "Failed to read sensor: %d", err); } err = get_channels(dev, SENSOR_CHAN_GAUGE_TEMP, &temp, SENSOR_CHAN_GAUGE_VOLTAGE, &volt, SENSOR_CHAN_GAUGE_AVG_CURRENT, ¤t, SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE, &v_desired, SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT, &i_desired, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE, &charge, SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE, &v_design, SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY, &charge_remain, SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY, &cap, SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY, &nom_cap, SENSOR_CHAN_GAUGE_TIME_TO_FULL, &full, SENSOR_CHAN_GAUGE_TIME_TO_EMPTY, &empty, -1); if (err < 0) { return err; } shell_fprintf(shell, SHELL_NORMAL, "Temp: %.1d.%02d C\n", temp.val1, temp.val2 / 10000); shell_fprintf(shell, SHELL_NORMAL, "V: %5d.%02d V\n", volt.val1, volt.val2 / 10000); shell_fprintf(shell, SHELL_NORMAL, "V-desired: %d.%02d V\n", v_desired.val1, v_desired.val2 / 10000); shell_fprintf(shell, SHELL_NORMAL, "I: %d mA", current.val1); if (current.val1 > 0) { shell_fprintf(shell, SHELL_NORMAL, " (CHG)"); } else if (current.val1 < 0) { shell_fprintf(shell, SHELL_NORMAL, " (DISCHG)"); } shell_fprintf(shell, SHELL_NORMAL, "\n"); shell_fprintf(shell, SHELL_NORMAL, "I-desired: %5d mA\n", i_desired.val1); allowed = i_desired.val1 && v_desired.val2 && charge.val1 < 100; shell_fprintf(shell, SHELL_NORMAL, "Charging: %sAllowed\n", allowed ? "" : "Not "); shell_fprintf(shell, SHELL_NORMAL, "Charge: %d %%\n", charge.val1); shell_fprintf(shell, SHELL_NORMAL, "V-design: %d.%02d V\n", v_design.val1, v_design.val2 / 10000); shell_fprintf(shell, SHELL_NORMAL, "Remaining: %d mA\n", charge_remain.val1); shell_fprintf(shell, SHELL_NORMAL, "Cap-full: %d mA\n", cap.val1); shell_fprintf(shell, SHELL_NORMAL, "Design: %d mA\n", nom_cap.val1); shell_fprintf(shell, SHELL_NORMAL, "Time full: %dh:%02d\n", full.val1 / 60, full.val1 % 60); shell_fprintf(shell, SHELL_NORMAL, "Time empty: %dh:%02d\n", empty.val1 / 60, empty.val1 % 60); return 0; } SHELL_CMD_REGISTER(battery, NULL, "Battery status", cmd_battery);