supply-daemon.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-02-25 GuEe-GUI the first version
  9. * 2026-03-27 Evlers support builds without DM names and improve logging
  10. */
  11. #include <rtdevice.h>
  12. #define DBG_TAG "power_supply.daemon"
  13. #define DBG_LVL DBG_INFO
  14. #include <rtdbg.h>
  15. #ifdef RT_USING_PM
  16. static rt_bool_t low_power_mode = RT_FALSE;
  17. static rt_uint8_t raw_pm_run_mode = PM_RUN_MODE_MAX;
  18. static rt_uint8_t raw_pm_sleep_mode = PM_RUN_MODE_MAX;
  19. static rt_uint8_t last_pm_sleep_mode;
  20. #endif
  21. static rt_err_t daemon_power_supply_notify(struct rt_power_supply_notifier *notifier,
  22. struct rt_power_supply *psy)
  23. {
  24. union rt_power_supply_property_val propval;
  25. rt_uint32_t voltage_now, voltage_min, voltage_max;
  26. if (!rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_CAPACITY, &propval))
  27. {
  28. goto _capacity_check;
  29. }
  30. if (rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_VOLTAGE_NOW, &propval))
  31. {
  32. return -RT_ENOSYS;
  33. }
  34. voltage_now = propval.intval / 1000000;
  35. if (rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_VOLTAGE_MIN, &propval))
  36. {
  37. return -RT_ENOSYS;
  38. }
  39. voltage_min = propval.intval / 1000000;
  40. if (rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_VOLTAGE_MAX, &propval))
  41. {
  42. return -RT_ENOSYS;
  43. }
  44. voltage_max = propval.intval / 1000000;
  45. propval.intval = (voltage_now - voltage_min) * 100 / (voltage_max - voltage_min);
  46. _capacity_check:
  47. if (propval.intval >= 80)
  48. {
  49. rt_bool_t full_power = propval.intval == 100;
  50. if (rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_STATUS, &propval))
  51. {
  52. return -RT_ENOSYS;
  53. }
  54. if (propval.intval == RT_POWER_SUPPLY_STATUS_CHARGING)
  55. {
  56. if (full_power)
  57. {
  58. LOG_I("%s: Power is full", rt_power_supply_name(psy));
  59. }
  60. else
  61. {
  62. LOG_I("%s: Power is sufficient", rt_power_supply_name(psy));
  63. }
  64. }
  65. }
  66. else if (propval.intval <= 20)
  67. {
  68. #ifdef RT_USING_PM
  69. rt_uint8_t pm_sleep_mode;
  70. struct rt_pm *pm = rt_pm_get_handle();
  71. RT_ASSERT(pm != RT_NULL);
  72. low_power_mode = RT_TRUE;
  73. if (raw_pm_run_mode == PM_RUN_MODE_MAX)
  74. {
  75. raw_pm_run_mode = pm->run_mode;
  76. }
  77. if (raw_pm_sleep_mode == PM_SLEEP_MODE_MAX)
  78. {
  79. last_pm_sleep_mode = raw_pm_sleep_mode = pm->sleep_mode;
  80. }
  81. pm_sleep_mode = pm->sleep_mode;
  82. #endif /* RT_USING_PM */
  83. if (propval.intval <= 5)
  84. {
  85. do {
  86. #ifdef RT_USING_PM
  87. if (pm_sleep_mode != PM_SLEEP_MODE_SHUTDOWN && propval.intval > 1)
  88. {
  89. pm_sleep_mode = PM_SLEEP_MODE_SHUTDOWN;
  90. break;
  91. }
  92. #endif
  93. if (!rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_SCOPE, &propval) &&
  94. propval.intval == RT_POWER_SUPPLY_SCOPE_SYSTEM)
  95. {
  96. LOG_E("%s: Power is critical, poweroff now", rt_power_supply_name(psy));
  97. rt_hw_cpu_shutdown();
  98. }
  99. } while (0);
  100. LOG_E("%s: Power is critical", rt_power_supply_name(psy));
  101. }
  102. else if (propval.intval <= 10)
  103. {
  104. #ifdef RT_USING_PM
  105. pm_sleep_mode = PM_SLEEP_MODE_STANDBY;
  106. rt_pm_run_enter(PM_RUN_MODE_LOW_SPEED);
  107. #endif
  108. }
  109. else if (propval.intval <= 15)
  110. {
  111. #ifdef RT_USING_PM
  112. pm_sleep_mode = PM_SLEEP_MODE_DEEP;
  113. rt_pm_run_enter(PM_RUN_MODE_MEDIUM_SPEED);
  114. #endif
  115. }
  116. else if (propval.intval <= 20)
  117. {
  118. #ifdef RT_USING_PM
  119. pm_sleep_mode = PM_SLEEP_MODE_LIGHT;
  120. rt_pm_run_enter(PM_RUN_MODE_NORMAL_SPEED);
  121. #endif
  122. LOG_W("%s: Power is low", rt_power_supply_name(psy));
  123. }
  124. #ifdef RT_USING_PM
  125. if (pm_sleep_mode != last_pm_sleep_mode)
  126. {
  127. rt_pm_release(last_pm_sleep_mode);
  128. rt_pm_request(pm_sleep_mode);
  129. last_pm_sleep_mode = pm_sleep_mode;
  130. }
  131. #endif /* RT_USING_PM */
  132. }
  133. else
  134. {
  135. #ifdef RT_USING_PM
  136. if (low_power_mode)
  137. {
  138. rt_pm_release(last_pm_sleep_mode);
  139. rt_pm_request(raw_pm_sleep_mode);
  140. rt_pm_run_enter(raw_pm_run_mode);
  141. low_power_mode = RT_FALSE;
  142. }
  143. #endif /* RT_USING_PM */
  144. }
  145. return RT_EOK;
  146. }
  147. static int power_supply_daemon_init(void)
  148. {
  149. static struct rt_power_supply_notifier daemon_notifier;
  150. daemon_notifier.callback = daemon_power_supply_notify;
  151. rt_power_supply_notifier_register(&daemon_notifier);
  152. return 0;
  153. }
  154. INIT_ENV_EXPORT(power_supply_daemon_init);