1 /***************************************************************************//**
2  * @file
3  * @brief Power Manager API definition.
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #ifndef SL_POWER_MANAGER_H
32 #define SL_POWER_MANAGER_H
33 
34 #ifndef SL_POWER_MANAGER_DEBUG
35 #include "sl_power_manager_config.h"
36 #endif
37 #include "sl_slist.h"
38 #include "sl_status.h"
39 #include "sl_sleeptimer.h"
40 #include "sl_enum.h"
41 
42 #include "em_core_generic.h"
43 
44 #include <stdbool.h>
45 #include <stdint.h>
46 
47 #ifdef __cplusplus
48 extern "C" {
49 #endif
50 
51 /***************************************************************************//**
52  * @addtogroup power_manager Power Manager
53  *
54  * @details Power manager is a platform level software module that manages
55  * the system's energy modes. Its main purpose is to transition the system to a
56  * low energy mode when the processor has nothing to execute. The energy mode the
57  * system will transition to is determined each time the system goes to sleep
58  * using requirements. These requirements are set by the different software modules
59  * (drivers, stacks, application code, etc...). Power manager also ensures a
60  * strict control of some power hungry resources such as the high frequency
61  * external oscillator (normally called HFXO). Power manager also
62  * offers a notification mechanism through which any piece of software module can be
63  * notified of energy mode transitions through callbacks.
64  *
65  * @note Sleep Driver is deprecated. Use Power Manager for all sleep-related
66  *       operations. See <a href="https://www.silabs.com/documents/
67  *       public/application-notes/
68  *       an1358-migrating-from-sleep-driver-to-power-manager.pdf">AN1358:
69  *       Migrating from Sleep Driver to Power Manager</a> for information on how
70  *       to migrate from Sleep Driver to Power Manager.
71  * @note Emlib EMU functions EMU_EnterEM1()/EMU_EnterEM2()/EMU_EnterEM3() must not
72  *       be used when the Power Manager is present. The Power Manager module must be
73  *       the one deciding at which EM level the device sleeps to ensure the application
74  *       properly works. Using both at the same time could lead to undefined behavior
75  *       in the application.
76  *
77  * @details
78  * ## Initialization
79  *
80  *   Power manager must be initialized prior to any call to power manager API.
81  *   If sl_system is used, only sl_system_init() must be called, otherwise
82  *   sl_power_manager_init() must be called manually. Note that power manager
83  *   must be initialized after the clock(s), when initialized manually, as the
84  *   power manager check which oscillators are used during the initialization phase.
85  *
86  * ## Add and remove requirements
87  *
88  *   The drivers should add and remove energy mode requirements, at runtime, on the
89  *   lowest energy mode for them depending on their state. When calling
90  *   sl_power_manager_sleep(), the lowest possible Energy mode will be automatically
91  *   selected.
92  *
93  *   It is possible to add and remove requirements from ISR. If a specific energy mode
94  *   is required in the ISR, but not required to generate the interrupt, a requirement
95  *   on the energy mode can be added from the ISR. It is guaranteed that the associated
96  *   clock will be active once sl_power_manager_add_requirement() returns. The EM
97  *   requirement can be also be removed from an ISR.
98  *
99  * ## Subscribe to events
100  *
101  *   It possible to get notified when the system transition from a power level to
102  *   another power level. This can allow to do some operations depending on which level
103  *   the system goes, such as saving/restoring context.
104  *
105  * ## Sleep
106  *
107  *   When the software has no more operation and only need to wait for an event, the
108  *   software must call sl_power_manager_sleep(). This is automatically done when the
109  *   kernel is present, but it needs to be called from the super loop in a baremetal
110  *   project.
111  *
112  * ## Query callback functions
113  *
114  * ### Is OK to sleep
115  *
116  *   Between the time `sl_power_manager_sleep` is called and the MCU is really put
117  *   in a lower Energy mode, it is possible that an ISR occur and require the system
118  *   to resume at that time instead of sleeping. So a callback is called in a critical
119  *   section to validate that the MCU can go to sleep.
120  *
121  *   In case of an application that runs on an RTOS, the RTOS will take care of determining
122  *   if it is ok to sleep. In case of a baremetal application, the function `sl_power_manager_is_ok_to_sleep()`
123  *   will be generated automatically by Simplicity Studio's wizard.
124  *   The function will look at multiple software modules from the SDK to take a decision.
125  *   The application can contribute to the decision by defining the function `app_is_ok_to_sleep()`.
126  *   If any of the software modules (including the application via `app_is_ok_to_sleep()`) return false,
127  *   the process of entering in sleep will be aborted.
128  *
129  * ### Sleep on ISR exit
130  *
131  *   When the system enters sleep, the only way to wake it up is via an interrupt or
132  *   exception. By default, power manager will assume that when an interrupt
133  *   occurs and the corresponding ISR has been executed, the system must not go back
134  *   to sleep. However, in the case where all the processing related to this interrupt
135  *   is performed in the ISR, it is possible to go back to sleep by using this hook.
136  *
137  *   In case of an application that runs on an RTOS, the RTOS will take care of determining
138  *   if the system can go back to sleep on ISR exit. Power manager will ensure the system resumes
139  *   its operations as soon as a task is resumed, posted or that its delay expires.
140  *   In case of a baremetal application, the function `sl_power_manager_sleep_on_isr_exit()` will be generated
141  *   automatically by Simplicity Studio's wizard. The function will look at multiple software modules from the SDK
142  *   to take a decision. The application can contribute to the decision by defining the
143  *   function `app_sleep_on_isr_exit()`.
144  *   The generated function will take a decision based on the value returned by the different software modules
145  *   (including the application via `app_sleep_on_isr_exit()`):
146  *
147  *   `SL_POWER_MANAGER_IGNORE`: if the software module did not cause the system wakeup and/or doesn't want to contribute to the decision.
148  *   `SL_POWER_MANAGER_SLEEP`: if the software module did cause the system wakeup, but the system should go back to sleep.
149  *   `SL_POWER_MANAGER_WAKEUP`: if the software module did cause the system wakeup, and the system should not go back to sleep.
150  *
151  *   If any software module returned `SL_POWER_MANAGER_SLEEP` and none returned `SL_POWER_MANAGER_WAKEUP`,
152  *   the system will go back to sleep. Any other combination will cause the system not to go back to sleep.
153  *
154  * ### Debugging feature
155  *
156  *   By setting the configuration define SL_POWER_MANAGER_DEBUG to 1, it is possible
157  *   to record the requirements currently set and their owner. It is possible to print
158  *   at any time a table that lists all the added requirements and their owner. This
159  *   table can be printed by caling the function
160  *   sl_power_manager_debug_print_em_requirements().
161  *   Make sure to add the following define
162  *   ```
163  *   #define CURRENT_MODULE_NAME "<Module printable name here>"
164  *   ```
165  *   to any application code source file that adds and removes requirements.
166  *
167  * ## Usage Example
168  *
169  * ```
170  * #define EM_EVENT_MASK_ALL  (SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM0   \
171  *                             | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM0  \
172  *                             | SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM1 \
173  *                             | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM1  \
174  *                             | SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM2 \
175  *                             | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM2  \
176  *                             | SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM3 \
177  *                             | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM3)
178  *
179  * sl_power_manager_em_transition_event_handle_t event_handle;
180  * sl_power_manager_em_transition_event_info_t event_info = {
181  *   .event_mask = EM_EVENT_MASK_ALL,
182  *   .on_event = my_events_callback,
183  * }
184  *
185  * void main(void)
186  * {
187  *   // Initialize power manager; not needed if sl_system_init() is used.
188  *   sl_power_manager_init();
189  *
190  *   // Limit sleep level to EM1
191  *   sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
192  *
193  *   // Subscribe to all event types; get notified for every power transition.
194  *   sl_power_manager_subscribe_em_transition_event(&event_handle, &event_info);
195  *   while (1) {
196  *     // Actions
197  *     [...]
198  *     if (completed) {
199  *        // Remove energy mode requirement, can go to EM2 or EM3 now, depending on the configuration
200  *        sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
201  *     }
202  *
203  *     // Sleep to lowest possible energy mode; This call is not needed when using the kernel.
204  *     sl_power_manager_sleep();
205  *     // Will resume after an interrupt or exception
206  *   }
207  * }
208  *
209  * void my_events_callback(sl_power_manager_em_t from,
210  *                         sl_power_manager_em_t to)
211  * {
212  *   printf("Event:%s-%s\r\n", string_lookup_table[from], string_lookup_table[to]);
213  * }
214  * ```
215  *
216  * @{
217  ******************************************************************************/
218 
219 // -----------------------------------------------------------------------------
220 // Defines
221 
222 // Current module name for debugging features
223 #ifndef CURRENT_MODULE_NAME
224 #define CURRENT_MODULE_NAME "Anonymous"            ///< current module name
225 #endif
226 
227 // Power transition events
228 #define SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM0     (1 << 0)                                  ///< sl power manager event transition entering em0
229 #define SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM0      (1 << 1)                                  ///< sl power manager event transition leaving em0
230 #define SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM1     (1 << 2)                                  ///< sl power manager event transition entering em1
231 #define SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM1      (1 << 3)                                  ///< sl power manager event transition leaving em1
232 #define SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM2     (1 << 4)                                  ///< sl power manager event transition entering em2
233 #define SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM2      (1 << 5)                                  ///< sl power manager event transition leaving em2
234 #define SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM3     (1 << 6)                                  ///< sl power manager event transition entering em3
235 #define SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM3      (1 << 7)                                  ///< sl power manager event transition leaving em3
236 
237 // -----------------------------------------------------------------------------
238 // Data Types
239 
240 /// @brief Energy modes
241 typedef  enum  {
242   SL_POWER_MANAGER_EM0 = 0,   ///< Run Mode (Energy Mode 0)
243   SL_POWER_MANAGER_EM1,       ///< Sleep Mode (Energy Mode 1)
244   SL_POWER_MANAGER_EM2,       ///< Deep Sleep Mode (Energy Mode 2)
245   SL_POWER_MANAGER_EM3,       ///< Stop Mode (Energy Mode 3)
246   SL_POWER_MANAGER_EM4,       ///< Shutoff Mode (Energy Mode 4)
247 } sl_power_manager_em_t;
248 
249 /// @brief Mask of all the event(s) to listen to.
250 typedef uint32_t sl_power_manager_em_transition_event_t;
251 
252 /***************************************************************************//**
253  * Typedef for the user supplied callback function which is called when
254  * an energy mode transition occurs.
255  *
256  * @param from Energy mode we are leaving.
257  * @param to   Energy mode we are entering.
258  ******************************************************************************/
259 typedef void (*sl_power_manager_em_transition_on_event_t)(sl_power_manager_em_t from,
260                                                           sl_power_manager_em_t to);
261 
262 /// @brief Struct representing energy mode transition event information
263 typedef struct {
264   const sl_power_manager_em_transition_event_t event_mask;  ///< Mask of the transitions on which the callback should be called.
265   const sl_power_manager_em_transition_on_event_t on_event; ///< Function that must be called when the event occurs.
266 } sl_power_manager_em_transition_event_info_t;
267 
268 /// @brief Struct representing energy mode transition event handle
269 typedef struct {
270   sl_slist_node_t node;                               ///< List node.
271   sl_power_manager_em_transition_event_info_t *info;  ///< Handle event info.
272 } sl_power_manager_em_transition_event_handle_t;
273 
274 /// On ISR Exit Hook answer
SL_ENUM(sl_power_manager_on_isr_exit_t)275 SL_ENUM(sl_power_manager_on_isr_exit_t) {
276   SL_POWER_MANAGER_IGNORE = (1UL << 0UL),     ///< The module did not trigger an ISR and it doesn't want to contribute to the decision
277   SL_POWER_MANAGER_SLEEP  = (1UL << 1UL),     ///< The module was the one that caused the system wakeup and the system SHOULD go back to sleep
278   SL_POWER_MANAGER_WAKEUP = (1UL << 2UL),     ///< The module was the one that caused the system wakeup and the system MUST NOT go back to sleep
279 };
280 
281 // -----------------------------------------------------------------------------
282 // Internal Prototypes only to be used by Power Manager module
283 void sli_power_manager_update_em_requirement(sl_power_manager_em_t em,
284                                              bool  add);
285 
286 // To make sure that we are able to optimize out the string argument when the
287 // debug feature is disable, we use a pre-processor macro resulting in a no-op.
288 // We also make sure to always have a definition for the function regardless if
289 // the debug feature is enable or not for binary compatibility.
290 #if (SL_POWER_MANAGER_DEBUG == 1)
291 void sli_power_manager_debug_log_em_requirement(sl_power_manager_em_t em,
292                                                 bool                  add,
293                                                 const char            *name);
294 #else
295 #define sli_power_manager_debug_log_em_requirement(em, add, name) /* no-op */
296 #endif
297 
298 // -----------------------------------------------------------------------------
299 // Prototypes
300 
301 /***************************************************************************//**
302  * Initialize Power Manager module.
303  * @return Status code
304  ******************************************************************************/
305 sl_status_t sl_power_manager_init(void);
306 
307 /***************************************************************************//**
308  * Sleep at the lowest allowed energy mode.
309  *
310  * @note Must not be called from ISR
311  * @par
312  * @note This function will expect and call a callback with the following
313  *       signature: `bool sl_power_manager_is_ok_to_sleep(void)`.
314  *
315  * @note This function can be used to cancel a sleep action and handle the
316  *       possible race condition where an ISR that would cause a wakeup is
317  *       triggered right after the decision to call sl_power_manager_sleep()
318  *       has been made.
319  *
320  * @note This function must not be called with interrupts disabled.
321  *
322  * Usage example:
323  *
324  * ```c
325  * void main(void)
326  * {
327  *   sl_power_manager_init();
328  *   while (1) {
329  *     tick();
330  *     sl_power_manager_sleep();
331  *   }
332  * }
333  * ```
334  ******************************************************************************/
335 void sl_power_manager_sleep(void);
336 
337 /***************************************************************************//**
338  * Adds requirement on given energy mode.
339  *
340  * @param em  Energy mode to add the requirement to:
341  *            - ::SL_POWER_MANAGER_EM1
342  *            - ::SL_POWER_MANAGER_EM2
343  ******************************************************************************/
sl_power_manager_add_em_requirement(sl_power_manager_em_t em)344 __STATIC_INLINE void sl_power_manager_add_em_requirement(sl_power_manager_em_t em)
345 {
346   CORE_DECLARE_IRQ_STATE;
347 
348   CORE_ENTER_CRITICAL();
349   sli_power_manager_update_em_requirement(em, true);
350 
351   sli_power_manager_debug_log_em_requirement(em, true, (const char *)CURRENT_MODULE_NAME);
352   CORE_EXIT_CRITICAL();
353 }
354 
355 /***************************************************************************//**
356  * Removes requirement on given energy mode.
357  *
358  * @param em  Energy mode to remove the requirement to:
359  *            - ::SL_POWER_MANAGER_EM1
360  *            - ::SL_POWER_MANAGER_EM2
361  ******************************************************************************/
sl_power_manager_remove_em_requirement(sl_power_manager_em_t em)362 __STATIC_INLINE void sl_power_manager_remove_em_requirement(sl_power_manager_em_t em)
363 {
364   CORE_DECLARE_IRQ_STATE;
365 
366   CORE_ENTER_CRITICAL();
367   sli_power_manager_update_em_requirement(em, false);
368 
369   sli_power_manager_debug_log_em_requirement(em, false, (const char *)CURRENT_MODULE_NAME);
370   CORE_EXIT_CRITICAL();
371 }
372 
373 /***************************************************************************//**
374  * Registers a callback to be called on given Energy Mode transition(s).
375  *
376  * @param event_handle  Event handle (no initialization needed).
377  *
378  * @param event_info    Event info structure that contains the event mask and the
379  *                      callback that must be called.
380  *
381  * @note Adding and removing requirement(s) from a callback on a transition event
382  *       is not supported.
383  *
384  * @note The parameters passed must be persistent, meaning that they need to survive
385  *       until the callback fires.
386  *
387  * Usage example:
388  *
389  * ```c
390  * #define EM_EVENT_MASK_ALL      (  SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM0 \
391  *                                 | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM0  \
392  *                                 | SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM1 \
393  *                                 | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM1  \
394  *                                 | SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM2 \
395  *                                 | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM2  \
396  *                                 | SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM3 \
397  *                                 | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM3)
398  *
399  * sl_power_manager_em_transition_event_handle_t event_handle;
400  * sl_power_manager_em_transition_event_info_t event_info = {
401  *   .event_mask = EM_EVENT_MASK_ALL,
402  *   .on_event = my_callback,
403  * };
404  *
405  * void my_callback(sl_power_manager_em_t from,
406  *                  sl_power_manager_em_t to)
407  * {
408  *   [...]
409  * }
410  *
411  * void main(void)
412  * {
413  *   sl_power_manager_init();
414  *   sl_power_manager_subscribe_em_transition_event(&event_handle, &event_info);
415  * }
416  * ```
417  ******************************************************************************/
418 void sl_power_manager_subscribe_em_transition_event(sl_power_manager_em_transition_event_handle_t     *event_handle,
419                                                     const sl_power_manager_em_transition_event_info_t *event_info);
420 
421 /***************************************************************************//**
422  * Unregisters an event callback handle on Energy mode transition.
423  *
424  * @param event_handle  Event handle which must be unregistered (must have been
425  *                      registered previously).
426  *
427  * @note  An EFM_ASSERT is thrown if the handle is not found.
428  ******************************************************************************/
429 void sl_power_manager_unsubscribe_em_transition_event(sl_power_manager_em_transition_event_handle_t *event_handle);
430 
431 /***************************************************************************//**
432  * Get configurable overhead value for early restore time in Sleeptimer ticks
433  * when a schedule wake-up is set.
434  *
435  * @return  Current overhead value for early restore time.
436  *
437  * @note This function will do nothing when a project contains the
438  *       power_manager_no_deepsleep component, which configures the
439  *       lowest energy mode as EM1.
440  ******************************************************************************/
441 int32_t sl_power_manager_schedule_wakeup_get_restore_overhead_tick(void);
442 
443 /***************************************************************************//**
444  * Set configurable overhead value for early restore time in Sleeptimer ticks
445  * used for schedule wake-up.
446  * Must be called after initialization else the value will be overwritten.
447  *
448  * @param overhead_tick Overhead value to set for early restore time.
449  *
450  * @note The overhead value can also be negative to remove time from the restore
451  *       process.
452  *
453  * @note This function will do nothing when a project contains the
454  *       power_manager_no_deepsleep component, which configures the
455  *       lowest energy mode as EM1.
456  ******************************************************************************/
457 void sl_power_manager_schedule_wakeup_set_restore_overhead_tick(int32_t overhead_tick);
458 
459 /***************************************************************************//**
460  * Get configurable minimum off-time value for schedule wake-up in Sleeptimer
461  * ticks.
462  *
463  * @return  Current minimum off-time value for schedule wake-up.
464  *
465  * @note  Turning on external high frequency clock, such as HFXO, requires more
466  *        energy since we must supply higher current for the wake-up.
467  *        Therefore, when an 'external high frequency clock enable' is scheduled
468  *        in 'x' time, there is a threshold 'x' value where turning off the clock
469  *        is not worthwhile since the energy consumed by taking into account the
470  *        wake-up will be greater than if we just keep the clock on until the next
471  *        scheduled clock enabled. This threshold value is what we refer as the
472  *        minimum off-time.
473  *
474  * @note This function will do nothing when a project contains the
475  *       power_manager_no_deepsleep component, which configures the
476  *       lowest energy mode as EM1.
477  ******************************************************************************/
478 uint32_t sl_power_manager_schedule_wakeup_get_minimum_offtime_tick(void);
479 
480 /***************************************************************************//**
481  * Set configurable minimum off-time value for schedule wake-up in Sleeptimer
482  * ticks.
483  *
484  * @param minimum_offtime_tick  minimum off-time value to set for schedule
485  *                              wake-up.
486  *
487  * @note  Turning on external high frequency clock, such as HFXO, requires more
488  *        energy since we must supply higher current for the wake-up.
489  *        Therefore, when an 'external high frequency clock enable' is scheduled
490  *        in 'x' time, there is a threshold 'x' value where turning off the clock
491  *        is not worthwhile since the energy consumed by taking into account the
492  *        wake-up will be greater than if we just keep the clock on until the next
493  *        scheduled clock enabled. This threshold value is what we refer as the
494  *        minimum off-time.
495  *
496  * @note This function will do nothing when a project contains the
497  *       power_manager_no_deepsleep component, which configures the
498  *       lowest energy mode as EM1.
499  ******************************************************************************/
500 void sl_power_manager_schedule_wakeup_set_minimum_offtime_tick(uint32_t minimum_offtime_tick);
501 
502 /***************************************************************************//**
503  * Enable or disable fast wake-up in EM2 and EM3
504  *
505  * @param enable True False variable act as a switch for this api
506  *
507  * @note Will also update the wake up time from EM2 to EM0.
508  *
509  * @note This function will do nothing when a project contains the
510  *       power_manager_no_deepsleep component, which configures the
511  *       lowest energy mode as EM1.
512  ******************************************************************************/
513 void sl_power_manager_em23_voltage_scaling_enable_fast_wakeup(bool enable);
514 
515 /**************************************************************************//**
516  * Determines if the HFXO interrupt was part of the last wake-up and/or if
517  * the HFXO early wakeup expired during the last ISR
518  * and if it was the only timer to expire in that period.
519  *
520  * @return true if power manager sleep can return to sleep,
521  *         false otherwise.
522  *
523  * @note This function will always return false in case a requirement
524  *       is added on SL_POWER_MANAGER_EM1, since we will
525  *       never sleep at a lower level than EM1.
526  *****************************************************************************/
527 bool sl_power_manager_is_latest_wakeup_internal(void);
528 
529 /** @} (end addtogroup power_manager) */
530 
531 #ifdef __cplusplus
532 }
533 #endif
534 
535 #endif // SL_POWER_MANAGER_H
536