From 6534f3d87ca07d4c748bb17691c1bed53c8edccd Mon Sep 17 00:00:00 2001
From: dulibo1 <dulibo1@xiaomi.com>
Date: Thu, 10 Aug 2023 13:27:57 +0800
Subject: [PATCH] add batterydump tool for dump the battery info

Signed-off-by: dulibo1 <dulibo1@xiaomi.com>
---
 testing/batterydump/Kconfig       |  29 +++
 testing/batterydump/Make.defs     |  23 +++
 testing/batterydump/Makefile      |  30 +++
 testing/batterydump/batterydump.c | 325 ++++++++++++++++++++++++++++++
 4 files changed, 407 insertions(+)
 create mode 100644 testing/batterydump/Kconfig
 create mode 100644 testing/batterydump/Make.defs
 create mode 100644 testing/batterydump/Makefile
 create mode 100644 testing/batterydump/batterydump.c

diff --git a/testing/batterydump/Kconfig b/testing/batterydump/Kconfig
new file mode 100644
index 000000000..61d9b16e7
--- /dev/null
+++ b/testing/batterydump/Kconfig
@@ -0,0 +1,29 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+#
+config TESTING_BATTERYDUMP
+	tristate "Battery dump for test"
+	default n
+	---help---
+		Enable the battery dump
+
+if TESTING_BATTERYDUMP
+
+config TESTING_BATTERYDUMP_PROGNAME
+	string "Program name"
+	default "batterydump"
+	---help---
+		This is the name of the program that will be used when the NSH ELF
+		program is installed.
+
+config TESTING_BATTERYDUMP_PRIORITY
+	int "Battery dump task priority"
+	default 100
+
+config TESTING_BATTERYDUMP_STACKSIZE
+	int "Battery dump stack size"
+	default DEFAULT_TASK_STACKSIZE
+
+endif
diff --git a/testing/batterydump/Make.defs b/testing/batterydump/Make.defs
new file mode 100644
index 000000000..4f5db37fd
--- /dev/null
+++ b/testing/batterydump/Make.defs
@@ -0,0 +1,23 @@
+############################################################################
+# apps/testing/batterydump/Make.defs
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+ifneq ($(CONFIG_TESTING_BATTERYDUMP),)
+CONFIGURED_APPS += $(APPDIR)/testing/batterydump
+endif
diff --git a/testing/batterydump/Makefile b/testing/batterydump/Makefile
new file mode 100644
index 000000000..00549b141
--- /dev/null
+++ b/testing/batterydump/Makefile
@@ -0,0 +1,30 @@
+############################################################################
+# apps/testing/batterydump/Makefile
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+PROGNAME  = $(CONFIG_TESTING_BATTERYDUMP_PROGNAME)
+PRIORITY  = $(CONFIG_TESTING_BATTERYDUMP_PRIORITY)
+STACKSIZE = $(CONFIG_TESTING_BATTERYDUMP_STACKSIZE)
+MODULE    = $(CONFIG_TESTING_BATTERYDUMP)
+
+MAINSRC = batterydump.c
+
+include $(APPDIR)/Application.mk
diff --git a/testing/batterydump/batterydump.c b/testing/batterydump/batterydump.c
new file mode 100644
index 000000000..7ef02faa6
--- /dev/null
+++ b/testing/batterydump/batterydump.c
@@ -0,0 +1,325 @@
+/****************************************************************************
+ * apps/testing/batterydump/batterydump.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <nuttx/power/battery_gauge.h>
+#include <nuttx/power/battery_charger.h>
+#include <nuttx/power/battery_monitor.h>
+#include <nuttx/power/battery_ioctl.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum
+{
+    CHIP_TYPE_CHARGER = 0,
+    CHIP_TYPE_GAUGE,
+    CHIP_TYPE_MONITOR,
+    CHIP_TYPE_MAX,
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static bool g_should_exit = false;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void usage(void)
+{
+  printf("batterydump [arguments...] <command>\n");
+  printf("\t[-h      ]  batterydump commands help\n");
+  printf("\t[-t   val]  0:charger 1:gauge 2:monitor\n");
+  printf("\t[-f      ]  poll the battery state and dump\n");
+
+  printf(" command:\n");
+  printf("\t<batttery_node_name> ex:"
+         "/dev/charge/goldfish_battery\n");
+}
+
+static void exit_handler(int signo)
+{
+  g_should_exit = true;
+}
+
+static void dump_charger(int fd, uint32_t mask)
+{
+  int status = 0;
+  int health = 0;
+  bool online = 0;
+  int vol = 0;
+  int protocol = 0;
+  int ret = 0;
+
+  ret = ioctl(fd, BATIOC_STATE, (unsigned long)&status);
+  if (ret < 0)
+    {
+        printf("BATIOC_STATE failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_ONLINE, (unsigned long)&online);
+  if (ret < 0)
+    {
+      printf("BATIOC_ONLINE failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_HEALTH, (unsigned long)&health);
+  if (ret < 0)
+    {
+      printf("BATIOC_HEALTH failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_GET_VOLTAGE, (unsigned long)&vol);
+  if (ret < 0)
+    {
+      printf("BATIOC_GET_VOLTAGE failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_GET_PROTOCOL, (unsigned long)&protocol);
+  if (ret < 0)
+    {
+      printf("BATIOC_GET_PROTOCOL failed %d", ret);
+    }
+
+  printf("mask:%"PRIx32", state:%d, online:%d, health:%d,"
+         " vol:%d, protocol:%d\n",
+         mask, status, online, health, vol, protocol);
+  return;
+}
+
+static void dump_gauge(int fd, uint32_t mask)
+{
+  int ret = 0;
+  int state = 0;
+  bool online = false;
+  b16_t cap = 0;
+  b16_t vol = 0;
+  b16_t current = 0;
+  b8_t temp = 0;
+
+  ret = ioctl(fd, BATIOC_STATE, (unsigned long)&state);
+  if (ret < 0)
+    {
+      printf("BATIOC_STATE failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_ONLINE, (unsigned long)&online);
+  if (ret < 0)
+    {
+      printf("BATIOC_ONLINE failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_VOLTAGE, (unsigned long)&vol);
+  if (ret < 0)
+    {
+      printf("BATIOC_VOLTAGE failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_CAPACITY, (unsigned long)&cap);
+  if (ret < 0)
+    {
+      printf("BATIOC_CAPACITY failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_CURRENT, (unsigned long)&current);
+  if (ret < 0)
+    {
+       printf("BATIOC_CURRENT failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_TEMPERATURE, (unsigned long)&temp);
+  if (ret < 0)
+    {
+      printf("BATIOC_TEMPERATURE failed %d", ret);
+    }
+
+  printf("mask:%"PRIx32", state:%d, online:%d, vol:%f, capacity:%"
+         PRIi32"%%, current:%f, temperature:%f\n",
+         mask, state, online, b16tof(vol), b16toi(cap),
+         b16tof(current), b8tof(temp));
+  return;
+}
+
+static void dump_monitor(int fd, uint32_t mask)
+{
+  int status = 0;
+  int health = 0;
+  bool online = 0;
+  int vol = 0;
+  int coulomb = 0;
+  int ret = 0;
+  struct battery_monitor_current_s current;
+
+  ret = ioctl(fd, BATIOC_STATE, (unsigned long)&status);
+  if (ret < 0)
+    {
+      printf("BATIOC_STATE failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_ONLINE, (unsigned long)&online);
+  if (ret < 0)
+    {
+      printf("BATIOC_ONLINE failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_HEALTH, (unsigned long)&health);
+  if (ret < 0)
+    {
+      printf("BATIOC_HEALTH failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_VOLTAGE, (unsigned long)&vol);
+  if (ret < 0)
+    {
+      printf("BATIOC_VOLTAGE failed %d", ret);
+    }
+
+  ret = ioctl(fd, BATIOC_COULOMBS, (unsigned long)&coulomb);
+  if (ret < 0)
+    {
+       printf("BATIOC_COULOMBS failed %d", ret);
+    }
+
+  memset(&current, 0, sizeof(struct battery_monitor_current_s));
+  ret = ioctl(fd, BATIOC_CURRENT, (unsigned long)&current);
+  if (ret < 0)
+    {
+       printf("BATIOC_CURRENT failed %d", ret);
+    }
+
+  printf("mask:%"PRIx32", state:%d, online:%d, vol:%d, coulombs:%d, "
+         "current:%"PRIi32", measurement time:%"PRIu32"\n",
+         mask, status, online, vol, coulomb, current.current,
+         current.time);
+  return;
+}
+
+static void dump_battery(int fd, int chiptype, uint32_t mask)
+{
+  switch (chiptype)
+  {
+  case CHIP_TYPE_CHARGER:
+    dump_charger(fd, mask);
+    break;
+  case CHIP_TYPE_GAUGE:
+    dump_gauge(fd, mask);
+    break;
+  case CHIP_TYPE_MONITOR:
+    dump_monitor(fd, mask);
+    break;
+  default:
+    break;
+  }
+
+  return;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int main(int argc, char *argv[])
+{
+  struct pollfd fds;
+  int pollen = 0;
+  int fd = -1;
+  int chiptype = CHIP_TYPE_MAX;
+  uint32_t mask = 0;
+  int ret = 0;
+
+  if (argc <= 1)
+    {
+      usage();
+      return -EINVAL;
+    }
+
+  if (signal(SIGINT, exit_handler) == SIG_ERR)
+    {
+      return -errno;
+    }
+
+  g_should_exit = false;
+  while ((ret = getopt(argc, argv, "t:fh")) != EOF)
+    {
+      switch (ret)
+        {
+          case 'f':
+            pollen = 1;
+            break;
+          case 't':
+            chiptype = strtoul(optarg, NULL, 10);
+            break;
+          case 'h':
+          default:
+            usage();
+            return -EINVAL;
+        }
+    }
+
+  if (optind >= argc || chiptype >= CHIP_TYPE_MAX)
+    {
+      usage();
+      return -EINVAL;
+    }
+
+  fd = open(argv[optind], O_RDWR | O_NONBLOCK);
+  if (fd < 0)
+    {
+      printf("Failed to open device:%s, ret:%s\n",
+             argv[optind], strerror(errno));
+      return -errno;
+    }
+
+  dump_battery(fd, chiptype, 0);
+  fds.fd = fd;
+  fds.events = POLLIN;
+
+  while (pollen && !g_should_exit)
+    {
+      if (poll(&fds, 1, -1) > 0)
+        {
+          read(fds.fd, &mask, sizeof(uint32_t));
+          dump_battery(fds.fd, chiptype, mask);
+        }
+    }
+
+  return 0;
+}