1 /**
2   ******************************************************************************
3   * @file    ll_sys_dp_slp.c
4   * @author  MCD Application Team
5   * @brief   Link Layer IP system interface deep sleep management
6   ******************************************************************************
7   * @attention
8   *
9   * Copyright (c) 2022 STMicroelectronics.
10   * All rights reserved.
11   *
12   * This software is licensed under terms that can be found in the LICENSE file
13   * in the root directory of this software component.
14   * If no LICENSE file comes with this software, it is provided AS-IS.
15   *
16   ******************************************************************************
17   */
18 
19 #include "linklayer_plat.h"
20 #include "ll_sys.h"
21 #include "ll_intf_cmn.h"
22 
23 /* Link Layer deep sleep status */
24 uint8_t is_Radio_DeepSleep = 0U;
25 
26 /* Link Layer deep sleep timer */
27 os_timer_id radio_dp_slp_tmr_id = NULL;
28 
29 /* Link Layer deep sleep state */
30 ll_sys_dp_slp_state_t linklayer_dp_slp_state = LL_SYS_DP_SLP_DISABLED;
31 
32 /**
33   * @brief  Initialize resources to handle deep sleep entry/exit
34   * @param  None
35   * @retval LL_SYS status
36   */
ll_sys_dp_slp_init(void)37 ll_sys_status_t ll_sys_dp_slp_init(void)
38 {
39   ll_sys_status_t return_status = LL_SYS_ERROR;
40 
41   /* Create link layer timer for handling IP DEEP SLEEP mode */
42   radio_dp_slp_tmr_id = os_timer_create((t_timer_callbk)ll_sys_dp_slp_wakeup_evt_clbk, os_timer_once, NULL);
43 
44   /* Set priority of deep sleep timer */
45   os_timer_set_prio(radio_dp_slp_tmr_id, hg_prio_tmr);
46 
47   if (radio_dp_slp_tmr_id != NULL)
48   {
49     return_status = LL_SYS_OK;
50   }
51 
52   return return_status;
53 }
54 
55 /**
56   * @brief  Link Layer deep sleep status getter
57   * @param  None
58   * @retval Link Layer deep sleep state
59   */
ll_sys_dp_slp_get_state(void)60 ll_sys_dp_slp_state_t ll_sys_dp_slp_get_state(void)
61 {
62   return linklayer_dp_slp_state;
63 }
64 
65 /**
66   * @brief  The Link Layer IP enters deep sleep mode
67   * @param  dp_slp_duration    deep sleep duration in us
68   * @retval LL_SYS status
69   */
ll_sys_dp_slp_enter(uint32_t dp_slp_duration)70 ll_sys_status_t ll_sys_dp_slp_enter(uint32_t dp_slp_duration){
71   ble_stat_t cmd_status;
72   int32_t os_status = GENERAL_FAILURE;
73   ll_sys_status_t return_status = LL_SYS_ERROR;
74 
75   /* Check if deep sleep timer has to be started */
76   if(dp_slp_duration < LL_DP_SLP_NO_WAKEUP)
77   {
78     /* Start deep sleep timer */
79     os_status = os_timer_start(radio_dp_slp_tmr_id, LL_INTERNAL_TMR_US_TO_STEPS(dp_slp_duration));
80   }
81 
82   else
83   {
84     /* No timer started */
85     os_status = SUCCESS;
86   }
87 
88   if(os_status == SUCCESS)
89   {
90     /* Switch Link Layer IP to DEEP SLEEP mode */
91     cmd_status = ll_intf_cmn_le_set_dp_slp_mode(DEEP_SLEEP_ENABLE);
92     if(cmd_status == SUCCESS){
93       linklayer_dp_slp_state = LL_SYS_DP_SLP_ENABLED;
94       return_status = LL_SYS_OK;
95     }
96   }
97 
98   return return_status;
99 }
100 
101 /**
102   * @brief  The Link Layer IP exits deep sleep mode
103   * @param  None
104   * @retval LL_SYS status
105   */
ll_sys_dp_slp_exit(void)106 ll_sys_status_t ll_sys_dp_slp_exit(void){
107   ble_stat_t cmd_status;
108   ll_sys_status_t return_status = LL_SYS_ERROR;
109 
110   /* Disable radio interrupt */
111   LINKLAYER_PLAT_DisableRadioIT();
112 
113   if(linklayer_dp_slp_state == LL_SYS_DP_SLP_DISABLED)
114   {
115     /* Radio not in sleep mode */
116     return_status = LL_SYS_OK;
117   }
118   else
119   {
120     /* Stop the deep sleep wake-up timer if running */
121     if(os_get_tmr_state(radio_dp_slp_tmr_id) != (os_timer_state)osTimerStopped)
122     {
123       os_timer_stop(radio_dp_slp_tmr_id);
124     }
125 
126     /* Switch Link Layer IP to SLEEP mode (by deactivate DEEP SLEEP mode) */
127     cmd_status = ll_intf_cmn_le_set_dp_slp_mode(DEEP_SLEEP_DISABLE);
128     if(cmd_status == SUCCESS)
129     {
130       linklayer_dp_slp_state = LL_SYS_DP_SLP_DISABLED;
131       return_status = LL_SYS_OK;
132     }
133   }
134 
135   /* Re-enable radio interrupt */
136   LINKLAYER_PLAT_EnableRadioIT();
137 
138   return return_status;
139 }
140 
141 /**
142   * @brief  Link Layer deep sleep wake-up timer callback
143   * @param  ptr_arg    pointer passed through the callback
144   * @retval LL_SYS status
145   */
ll_sys_dp_slp_wakeup_evt_clbk(void const * ptr_arg)146 void ll_sys_dp_slp_wakeup_evt_clbk(void const *ptr_arg){
147   int32_t os_status;
148 
149   /* Stop the Link Layer IP DEEP SLEEP wake-up timer */
150   os_status = os_timer_stop(radio_dp_slp_tmr_id);
151   if(os_status != SUCCESS){
152     return;
153   }
154 
155   /* Link Layer IP exits from DEEP SLEEP mode */
156   ll_sys_dp_slp_exit();
157 }
158