diff --git a/utils/gl-puli-mcu/Config.in b/utils/gl-puli-mcu/Config.in new file mode 100644 index 0000000000..315526c08d --- /dev/null +++ b/utils/gl-puli-mcu/Config.in @@ -0,0 +1,12 @@ +choice + depends on PACKAGE_gl-puli-mcu + + prompt "GL.iNet target" + default GL_PULI_MCU_XE300 + + config GL_PULI_MCU_XE300 + bool "GL.iNet XE300 (Puli)" + + config GL_PULI_MCU_XE3000 + bool "GL.iNet XE3000 (Puli AX)" +endchoice diff --git a/utils/gl-puli-mcu/Makefile b/utils/gl-puli-mcu/Makefile index d33e9288f3..b1da42c777 100644 --- a/utils/gl-puli-mcu/Makefile +++ b/utils/gl-puli-mcu/Makefile @@ -1,24 +1,40 @@ include $(TOPDIR)/rules.mk PKG_NAME:=gl-puli-mcu -PKG_VERSION:=1 +PKG_VERSION:=2 PKG_RELEASE:=1 PKG_MAINTAINER:=Nuno Goncalves PKG_LICENSE:=GPL-3.0-or-later +PKG_CONFIG_DEPENDS:= \ + CONFIG_GL_PULI_MCU_XE300 \ + CONFIG_GL_PULI_MCU_XE3000 + include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/cmake.mk +define Package/gl-puli-mcu/config + source "$(SOURCE)/Config.in" +endef + define Package/gl-puli-mcu SECTION:=utils CATEGORY:=Utilities - TITLE:=GL.iNet GL-XE300 (Puli) power monitoring support - DEPENDS:=+kmod-usb-serial-ch341 +libubus +libubox + TITLE:=GL.iNet power monitoring support + DEPENDS:=+CONFIG_GL_PULI_MCU_XE300:kmod-usb-serial-ch341 +libubus +libubox + MENU:=1 endef +ifeq ($(CONFIG_GL_PULI_MCU_XE300),y) + TARGET_CFLAGS+=-DGL_TARGET=1 +endif +ifeq ($(CONFIG_GL_PULI_MCU_XE3000),y) + TARGET_CFLAGS+=-DGL_TARGET=2 +endif + define Package/gl-puli-mcu/description - Interfaces with GL-XE300 (Puli) power monitoring MCU over + Interfaces with GL.iNet Puli family power monitoring MCU over a USB to UART adapter present on the device and provides battery SOC, temperature, charging state and cycle count at ubus battery/info. diff --git a/utils/gl-puli-mcu/src/gl-puli-mcu.c b/utils/gl-puli-mcu/src/gl-puli-mcu.c index 6cf4f2abde..da7d7db839 100644 --- a/utils/gl-puli-mcu/src/gl-puli-mcu.c +++ b/utils/gl-puli-mcu/src/gl-puli-mcu.c @@ -26,6 +26,17 @@ #include #include +#define GL_TARGET_XE300 1 +#define GL_TARGET_XE3000 2 + +#if GL_TARGET == GL_TARGET_XE300 +#define MCU_PORT "/dev/ttyUSB0" +#elif GL_TARGET == GL_TARGET_XE3000 +#define MCU_PORT "/dev/ttyS1" +#else +#error Please define GL_TARGET! +#endif /* GL_TARGET */ + static struct ustream_fd stream; static struct ubus_auto_conn conn; static struct blob_buf b; @@ -39,6 +50,9 @@ struct Battery bool set; } battery; +#if GL_TARGET == GL_TARGET_XE300 +// MCU status returns something like: +// {OK},100,275,1,0 static bool process(char *read) { @@ -66,6 +80,65 @@ process(char *read) return false; return true; } +#elif GL_TARGET == GL_TARGET_XE3000 +static bool +get_int_value(const char *read, const char *key, int *int_value, char **new_end) +{ + char *from = NULL; + + from = strstr(read, key); + if ((!from) || (from != read)) + { + return false; + } + from = (char *)read + strlen(key); + *int_value = strtol(from, new_end, 10); + if (from == *new_end) + { + return false; + } + + return true; +} + +// MCU status returns something like: +// {"code":0,"capacity":100,"temp":28,"chg_state":1,"charge_cycle":0} +static bool +process(char *read) +{ + int int_value = 0; + char *to = NULL; + + if ((read[0] != '{') || + (!get_int_value(&read[1], "\"code\":", &int_value, &to)) || + (int_value != 0)) + { + return false; + } + if (!get_int_value(to + 1, "\"capacity\":", &int_value, &to)) + { + return false; + } + battery.soc = int_value; + if (!get_int_value(to + 1, "\"temp\":", &int_value, &to)) + { + return false; + } + battery.temperature = (float) int_value; + if (!get_int_value(to + 1, "\"chg_state\":", &int_value, &to)) + { + return false; + } + battery.charging = (bool) int_value; + if (!get_int_value(to + 1, "\"charge_cycle\":", &int_value, &to)) + { + return false; + } + battery.cycles = (uint16_t) int_value; + + return true; +} +#endif /* GL_TARGET */ static int consume(struct ustream *s, char **a) @@ -202,7 +275,7 @@ main(int argc, char **argv) conn.cb = ubus_connect_handler; ubus_auto_connect(&conn); - if (serial_open("/dev/ttyUSB0") < 0) + if (serial_open(MCU_PORT) < 0) return -1; serial_query_timer.cb = serial_query_handler;