supply_cmd.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*
  2. * Copyright (c) 2006-2026, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2026-03-27 Evlers first version
  9. */
  10. #include <rtdevice.h>
  11. #if defined(RT_USING_CONSOLE) && defined(RT_USING_MSH)
  12. const char * const type_str[] =
  13. {
  14. [RT_POWER_SUPPLY_TYPE_UNKNOWN] = "UnKnown",
  15. [RT_POWER_SUPPLY_TYPE_BATTERY] = "Battery",
  16. [RT_POWER_SUPPLY_TYPE_UPS] = "UPS",
  17. [RT_POWER_SUPPLY_TYPE_MAINS] = "Mains",
  18. [RT_POWER_SUPPLY_TYPE_USB_SDP] = "USB SDP",
  19. [RT_POWER_SUPPLY_TYPE_USB_DCP] = "USB DCP",
  20. [RT_POWER_SUPPLY_TYPE_USB_CDP] = "USB CDP",
  21. [RT_POWER_SUPPLY_TYPE_USB_ACA] = "USB ACA",
  22. [RT_POWER_SUPPLY_TYPE_USB_TYPE_C] = "USB TypeC",
  23. [RT_POWER_SUPPLY_TYPE_USB_PD] = "USB PD",
  24. [RT_POWER_SUPPLY_TYPE_USB_PD_DRP] = "USB PD DRP",
  25. [RT_POWER_SUPPLY_TYPE_USB_PD_PPS] = "USB PD PPS",
  26. [RT_POWER_SUPPLY_TYPE_WIRELESS] = "Wireless",
  27. };
  28. const char * const status_str[] =
  29. {
  30. [RT_POWER_SUPPLY_STATUS_UNKNOWN] = "UnKnown",
  31. [RT_POWER_SUPPLY_STATUS_CHARGING] = "Charging",
  32. [RT_POWER_SUPPLY_STATUS_DISCHARGING] = "Discharging",
  33. [RT_POWER_SUPPLY_STATUS_NOT_CHARGING] = "Not Charging",
  34. [RT_POWER_SUPPLY_STATUS_FULL] = "Full",
  35. };
  36. const char * const charge_type_str[] =
  37. {
  38. [RT_POWER_SUPPLY_CHARGE_TYPE_UNKNOWN] = "Unknown",
  39. [RT_POWER_SUPPLY_CHARGE_TYPE_NONE] = "None",
  40. [RT_POWER_SUPPLY_CHARGE_TYPE_TRICKLE] = "Trickle",
  41. [RT_POWER_SUPPLY_CHARGE_TYPE_FAST] = "Fast",
  42. [RT_POWER_SUPPLY_CHARGE_TYPE_STANDARD] = "Standard",
  43. [RT_POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE] = "Adaptive",
  44. [RT_POWER_SUPPLY_CHARGE_TYPE_CUSTOM] = "Custom",
  45. [RT_POWER_SUPPLY_CHARGE_TYPE_LONGLIFE] = "Longlife",
  46. [RT_POWER_SUPPLY_CHARGE_TYPE_BYPASS] = "Bypass",
  47. };
  48. const char * const health_str[] =
  49. {
  50. [RT_POWER_SUPPLY_HEALTH_UNKNOWN] = "Unknown",
  51. [RT_POWER_SUPPLY_HEALTH_GOOD] = "Good",
  52. [RT_POWER_SUPPLY_HEALTH_OVERHEAT] = "Overheat",
  53. [RT_POWER_SUPPLY_HEALTH_DEAD] = "Dead",
  54. [RT_POWER_SUPPLY_HEALTH_OVERVOLTAGE] = "Overvoltage",
  55. [RT_POWER_SUPPLY_HEALTH_UNSPEC_FAILURE] = "Unspec Failure",
  56. [RT_POWER_SUPPLY_HEALTH_COLD] = "Cold",
  57. [RT_POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE] = "Watchdog Timer Expire",
  58. [RT_POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE] = "Safety Timer Expire",
  59. [RT_POWER_SUPPLY_HEALTH_OVERCURRENT] = "Overcurrent",
  60. [RT_POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED] = "Calibration Required",
  61. [RT_POWER_SUPPLY_HEALTH_WARM] = "Warm",
  62. [RT_POWER_SUPPLY_HEALTH_COOL] = "Cool",
  63. [RT_POWER_SUPPLY_HEALTH_HOT] = "Hot",
  64. [RT_POWER_SUPPLY_HEALTH_NO_BATTERY] = "No Battery",
  65. };
  66. const char * const tech_str[] =
  67. {
  68. [RT_POWER_SUPPLY_TECHNOLOGY_UNKNOWN] = "UnKnown",
  69. [RT_POWER_SUPPLY_TECHNOLOGY_NiMH] = "NiMH",
  70. [RT_POWER_SUPPLY_TECHNOLOGY_LION] = "LION",
  71. [RT_POWER_SUPPLY_TECHNOLOGY_LIPO] = "LIPO",
  72. [RT_POWER_SUPPLY_TECHNOLOGY_LiFe] = "LiFe",
  73. [RT_POWER_SUPPLY_TECHNOLOGY_NiCd] = "NiCd",
  74. [RT_POWER_SUPPLY_TECHNOLOGY_LiMn] = "LiMn",
  75. };
  76. const char * const capacity_level_str[] =
  77. {
  78. [RT_POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN] = "Unknown",
  79. [RT_POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL] = "Critical",
  80. [RT_POWER_SUPPLY_CAPACITY_LEVEL_LOW] = "Low",
  81. [RT_POWER_SUPPLY_CAPACITY_LEVEL_NORMAL] = "Normal",
  82. [RT_POWER_SUPPLY_CAPACITY_LEVEL_HIGH] = "High",
  83. [RT_POWER_SUPPLY_CAPACITY_LEVEL_FULL] = "Full",
  84. };
  85. const char * const scope_str[] =
  86. {
  87. [RT_POWER_SUPPLY_SCOPE_UNKNOWN] = "Unknown",
  88. [RT_POWER_SUPPLY_SCOPE_SYSTEM] = "System",
  89. [RT_POWER_SUPPLY_SCOPE_DEVICE] = "Device",
  90. };
  91. enum power_supply_prop_dump_type
  92. {
  93. POWER_SUPPLY_PROP_DUMP_INT = 0,
  94. POWER_SUPPLY_PROP_DUMP_ENUM,
  95. POWER_SUPPLY_PROP_DUMP_STR,
  96. };
  97. struct power_supply_prop_desc
  98. {
  99. enum rt_power_supply_property prop;
  100. const char *name;
  101. const char *label;
  102. const char *unit;
  103. enum power_supply_prop_dump_type type;
  104. const char * const *str_tab;
  105. rt_size_t str_tab_size;
  106. };
  107. static const struct power_supply_prop_desc g_power_supply_prop_desc[] =
  108. {
  109. {RT_POWER_SUPPLY_PROP_ONLINE, "online", "online:", RT_NULL, POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  110. {RT_POWER_SUPPLY_PROP_PRESENT, "present", "present:", RT_NULL, POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  111. {RT_POWER_SUPPLY_PROP_AUTHENTIC, "authentic", "authentic:", RT_NULL, POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  112. {RT_POWER_SUPPLY_PROP_STATUS, "status", "status:", RT_NULL, POWER_SUPPLY_PROP_DUMP_ENUM, status_str, sizeof(status_str) / sizeof(status_str[0])},
  113. {RT_POWER_SUPPLY_PROP_CHARGE_TYPE, "charge_type", "charge type:", RT_NULL, POWER_SUPPLY_PROP_DUMP_ENUM, charge_type_str, sizeof(charge_type_str) / sizeof(charge_type_str[0])},
  114. {RT_POWER_SUPPLY_PROP_HEALTH, "health", "health:", RT_NULL, POWER_SUPPLY_PROP_DUMP_ENUM, health_str, sizeof(health_str) / sizeof(health_str[0])},
  115. {RT_POWER_SUPPLY_PROP_SCOPE, "scope", "scope:", RT_NULL, POWER_SUPPLY_PROP_DUMP_ENUM, scope_str, sizeof(scope_str) / sizeof(scope_str[0])},
  116. {RT_POWER_SUPPLY_PROP_CAPACITY, "capacity", "capacity:", "%", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  117. {RT_POWER_SUPPLY_PROP_CAPACITY_LEVEL, "capacity_level", "capacity level:", RT_NULL, POWER_SUPPLY_PROP_DUMP_ENUM, capacity_level_str, sizeof(capacity_level_str) / sizeof(capacity_level_str[0])},
  118. {RT_POWER_SUPPLY_PROP_VOLTAGE_NOW, "voltage_now", "voltage now:", "uV", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  119. {RT_POWER_SUPPLY_PROP_VOLTAGE_AVG, "voltage_avg", "voltage avg:", "uV", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  120. {RT_POWER_SUPPLY_PROP_CURRENT_NOW, "current_now", "current now:", "uA", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  121. {RT_POWER_SUPPLY_PROP_CURRENT_AVG, "current_avg", "current avg:", "uA", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  122. {RT_POWER_SUPPLY_PROP_POWER_NOW, "power_now", "power now:", "uW", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  123. {RT_POWER_SUPPLY_PROP_POWER_AVG, "power_avg", "power avg:", "uW", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  124. {RT_POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, "input_voltage_limit", "input voltage limit:", "uV", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  125. {RT_POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, "input_current_limit", "input current limit:", "uA", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  126. {RT_POWER_SUPPLY_PROP_INPUT_POWER_LIMIT, "input_power_limit", "input power limit:", "uW", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  127. {RT_POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, "constant_charge_voltage", "constant charge voltage:", "uV", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  128. {RT_POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, "constant_charge_voltage_max", "constant charge voltage max:", "uV", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  129. {RT_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, "constant_charge_current", "constant charge current:", "uA", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  130. {RT_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, "constant_charge_current_max", "constant charge current max:", "uA", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  131. {RT_POWER_SUPPLY_PROP_TEMP, "temp", "temp:", "mC", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  132. {RT_POWER_SUPPLY_PROP_TEMP_AMBIENT, "temp_ambient", "temp ambient:", "mC", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  133. {RT_POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, "time_to_empty_now", "time to empty now:", "s", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  134. {RT_POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, "time_to_full_now", "time to full now:", "s", POWER_SUPPLY_PROP_DUMP_INT, RT_NULL, 0},
  135. {RT_POWER_SUPPLY_PROP_MODEL_NAME, "model_name", "model name:", RT_NULL, POWER_SUPPLY_PROP_DUMP_STR, RT_NULL, 0},
  136. {RT_POWER_SUPPLY_PROP_MANUFACTURER, "manufacturer", "manufacturer:", RT_NULL, POWER_SUPPLY_PROP_DUMP_STR, RT_NULL, 0},
  137. {RT_POWER_SUPPLY_PROP_SERIAL_NUMBER, "serial_number", "serial number:", RT_NULL, POWER_SUPPLY_PROP_DUMP_STR, RT_NULL, 0},
  138. };
  139. #ifdef FINSH_USING_OPTION_COMPLETION
  140. static struct msh_cmd_opt power_supply_msh_options[] =
  141. {
  142. {0, RT_NULL, RT_NULL},
  143. };
  144. #endif
  145. static const struct power_supply_prop_desc *power_supply_find_prop_desc(const char *name)
  146. {
  147. rt_size_t i;
  148. if (!name)
  149. {
  150. return RT_NULL;
  151. }
  152. for (i = 0; i < sizeof(g_power_supply_prop_desc) / sizeof(g_power_supply_prop_desc[0]); ++i)
  153. {
  154. if (!rt_strcmp(g_power_supply_prop_desc[i].name, name))
  155. {
  156. return &g_power_supply_prop_desc[i];
  157. }
  158. }
  159. return RT_NULL;
  160. }
  161. static struct rt_power_supply *power_supply_find_by_name(const char *name)
  162. {
  163. struct rt_power_supply **nodes;
  164. struct rt_power_supply *result = RT_NULL;
  165. rt_size_t count = 0;
  166. rt_size_t i;
  167. if (!name)
  168. {
  169. return RT_NULL;
  170. }
  171. nodes = rt_power_supply_snapshot(&count);
  172. if (!nodes)
  173. {
  174. return RT_NULL;
  175. }
  176. for (i = 0; i < count; ++i)
  177. {
  178. const char *dev_name = rt_power_supply_name(nodes[i]);
  179. if (!rt_strcmp(dev_name, name))
  180. {
  181. result = nodes[i];
  182. rt_ref_get(&result->ref);
  183. break;
  184. }
  185. }
  186. rt_power_supply_snapshot_free(nodes, count);
  187. return result;
  188. }
  189. static rt_err_t power_supply_dump_one_property(struct rt_power_supply *psy,
  190. const struct power_supply_prop_desc *desc,
  191. rt_bool_t print_unsupported)
  192. {
  193. union rt_power_supply_property_val val = {};
  194. rt_err_t err;
  195. err = rt_power_supply_get_property(psy, desc->prop, &val);
  196. if (err != RT_EOK)
  197. {
  198. if (print_unsupported)
  199. {
  200. rt_kprintf("%-30s <unsupported>\n", desc->label);
  201. }
  202. return err;
  203. }
  204. if (desc->type == POWER_SUPPLY_PROP_DUMP_STR)
  205. {
  206. rt_kprintf("%-30s %s\n", desc->label, val.strval ? val.strval : "<null>");
  207. return RT_EOK;
  208. }
  209. if (desc->type == POWER_SUPPLY_PROP_DUMP_ENUM)
  210. {
  211. if ((val.intval >= 0) && ((rt_size_t)val.intval < desc->str_tab_size) && desc->str_tab[val.intval])
  212. {
  213. rt_kprintf("%-30s %s\n", desc->label, desc->str_tab[val.intval]);
  214. }
  215. else
  216. {
  217. rt_kprintf("%-30s %d\n", desc->label, val.intval);
  218. }
  219. return RT_EOK;
  220. }
  221. if (desc->unit)
  222. {
  223. rt_kprintf("%-30s %d %s\n", desc->label, val.intval, desc->unit);
  224. }
  225. else
  226. {
  227. rt_kprintf("%-30s %d\n", desc->label, val.intval);
  228. }
  229. return RT_EOK;
  230. }
  231. static void power_supply_dump_known_property_names(void)
  232. {
  233. rt_size_t i;
  234. rt_kputs("Known properties:\n");
  235. for (i = 0; i < sizeof(g_power_supply_prop_desc) / sizeof(g_power_supply_prop_desc[0]); ++i)
  236. {
  237. rt_kprintf(" %s\n", g_power_supply_prop_desc[i].name);
  238. }
  239. }
  240. static void power_supply_dump_battery_info(struct rt_power_supply *psy)
  241. {
  242. if (psy->battery_info)
  243. {
  244. struct rt_power_supply_battery_info *info = psy->battery_info;
  245. rt_kprintf("technology: %s\n", tech_str[info->technology]);
  246. rt_kprintf("energy full design: %u uWh\n", info->energy_full_design_uwh);
  247. rt_kprintf("charge full design: %u uAh\n", info->charge_full_design_uah);
  248. rt_kprintf("voltage design range: %u~%u uV\n", info->voltage_min_design_uv, info->voltage_max_design_uv);
  249. rt_kprintf("precharge current: %u uA\n", info->precharge_current_ua);
  250. rt_kprintf("charge term current: %u uA\n", info->charge_term_current_ua);
  251. rt_kprintf("charge restart voltage: %u uV\n", info->charge_restart_voltage_uv);
  252. rt_kprintf("constant charge current max: %u uA\n", info->constant_charge_current_max_ua);
  253. rt_kprintf("constant charge voltage max: %u uV\n", info->constant_charge_voltage_max_uv);
  254. rt_kprintf("temp ambient alert range: %+d.%u~%+d.%u C\n",
  255. info->temp_ambient_alert_min / 1000, rt_abs(info->temp_ambient_alert_min) % 1000,
  256. info->temp_ambient_alert_max / 1000, rt_abs(info->temp_ambient_alert_max) % 1000);
  257. rt_kprintf("temp alert range: %+d.%u~%+d.%u C\n",
  258. info->temp_alert_min / 1000, rt_abs(info->temp_alert_min) % 1000,
  259. info->temp_alert_max / 1000, rt_abs(info->temp_alert_max) % 1000);
  260. rt_kprintf("temp range: %+d.%u~%+d.%u C\n",
  261. info->temp_min / 1000, rt_abs(info->temp_min) % 1000,
  262. info->temp_max / 1000, rt_abs(info->temp_max) % 1000);
  263. }
  264. }
  265. static void power_supply_dump_properties(struct rt_power_supply *psy)
  266. {
  267. rt_size_t i;
  268. for (i = 0; i < sizeof(g_power_supply_prop_desc) / sizeof(g_power_supply_prop_desc[0]); ++i)
  269. {
  270. power_supply_dump_one_property(psy, &g_power_supply_prop_desc[i], RT_FALSE);
  271. }
  272. }
  273. static int power_supply_do_list(void)
  274. {
  275. struct rt_power_supply **nodes;
  276. rt_size_t count = 0;
  277. rt_size_t i;
  278. nodes = rt_power_supply_snapshot(&count);
  279. if (!nodes || !count)
  280. {
  281. return 0;
  282. }
  283. for (i = 0; i < count; ++i)
  284. {
  285. rt_kprintf("%s %s\n", rt_power_supply_name(nodes[i]), type_str[nodes[i]->type]);
  286. power_supply_dump_properties(nodes[i]);
  287. power_supply_dump_battery_info(nodes[i]);
  288. }
  289. rt_power_supply_snapshot_free(nodes, count);
  290. return 0;
  291. }
  292. static int power_supply_do_show(const char *name)
  293. {
  294. struct rt_power_supply *psy = power_supply_find_by_name(name);
  295. if (!psy)
  296. {
  297. rt_kprintf("power_supply: device '%s' not found\n", name ? name : "<null>");
  298. return -RT_ERROR;
  299. }
  300. rt_kprintf("%s %s\n", rt_power_supply_name(psy), type_str[psy->type]);
  301. power_supply_dump_properties(psy);
  302. power_supply_dump_battery_info(psy);
  303. rt_power_supply_put(psy);
  304. return RT_EOK;
  305. }
  306. static int power_supply_do_get(const char *name, const char *prop_name)
  307. {
  308. struct rt_power_supply *psy = power_supply_find_by_name(name);
  309. const struct power_supply_prop_desc *desc = power_supply_find_prop_desc(prop_name);
  310. int ret;
  311. if (!psy)
  312. {
  313. rt_kprintf("power_supply: device '%s' not found\n", name ? name : "<null>");
  314. return -RT_ERROR;
  315. }
  316. if (!desc)
  317. {
  318. rt_kprintf("power_supply: unknown property '%s'\n", prop_name ? prop_name : "<null>");
  319. power_supply_dump_known_property_names();
  320. rt_power_supply_put(psy);
  321. return -RT_EINVAL;
  322. }
  323. ret = power_supply_dump_one_property(psy, desc, RT_TRUE);
  324. rt_power_supply_put(psy);
  325. return ret;
  326. }
  327. static int power_supply(int argc, char **argv)
  328. {
  329. if (argc == 2 && !rt_strcmp(argv[1], "list"))
  330. {
  331. return power_supply_do_list();
  332. }
  333. if (argc == 3 && !rt_strcmp(argv[1], "show"))
  334. {
  335. return power_supply_do_show(argv[2]);
  336. }
  337. if (argc == 4 && !rt_strcmp(argv[1], "get"))
  338. {
  339. return power_supply_do_get(argv[2], argv[3]);
  340. }
  341. rt_kputs("Usage:\n");
  342. rt_kputs(" power_supply list\n");
  343. rt_kputs(" power_supply show <name>\n");
  344. rt_kputs(" power_supply get <name> <property>\n");
  345. return RT_EOK;
  346. }
  347. MSH_CMD_EXPORT(power_supply, power supply helper use power_supply list);
  348. #endif /* RT_USING_CONSOLE && RT_USING_MSH */