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.h"
22 #if defined(MAC)
23 #include "platform.h"
24 #endif
25 
26 /* Link Layer deep sleep status */
27 uint8_t is_Radio_DeepSleep = 0U;
28 
29 /* Link Layer deep sleep timer */
30 os_timer_id radio_dp_slp_tmr_id = NULL;
31 
32 /* Link Layer deep sleep state */
33 ll_sys_dp_slp_state_t linklayer_dp_slp_state = LL_SYS_DP_SLP_DISABLED;
34 
35 /**
36   * @brief  Initialize resources to handle deep sleep entry/exit
37   * @param  None
38   * @retval LL_SYS status
39   */
ll_sys_dp_slp_init(void)40 ll_sys_status_t ll_sys_dp_slp_init(void)
41 {
42   ll_sys_status_t return_status = LL_SYS_ERROR;
43 
44   /* Create link layer timer for handling IP DEEP SLEEP mode */
45   radio_dp_slp_tmr_id = os_timer_create((t_timer_callbk)ll_sys_dp_slp_wakeup_evt_clbk, os_timer_once, NULL);
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 = GENERAL_FAILURE;
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 #if defined(BLE)
92     /* BLE & Concurrent use case */
93     cmd_status = ll_intf_le_set_dp_slp_mode(DEEP_SLEEP_ENABLE);
94 #elif defined(MAC)
95     if (radio_set_dp_slp_mode(DEEP_SLEEP_ENABLE) == OT_ERROR_NONE)
96     {
97       cmd_status = SUCCESS;
98     }
99 #else
100  #error "neither MAC not BLE defined"
101 #endif
102     if(cmd_status == SUCCESS){
103       linklayer_dp_slp_state = LL_SYS_DP_SLP_ENABLED;
104       return_status = LL_SYS_OK;
105     }
106   }
107 
108   return return_status;
109 }
110 
111 /**
112   * @brief  The Link Layer IP exits deep sleep mode
113   * @param  None
114   * @retval LL_SYS status
115   */
ll_sys_dp_slp_exit(void)116 ll_sys_status_t ll_sys_dp_slp_exit(void){
117   ble_stat_t cmd_status = GENERAL_FAILURE;
118   ll_sys_status_t return_status = LL_SYS_ERROR;
119 
120   /* Disable radio interrupt */
121   LINKLAYER_PLAT_DisableRadioIT();
122 
123   if(linklayer_dp_slp_state == LL_SYS_DP_SLP_DISABLED)
124   {
125     /* Radio not in sleep mode */
126     return_status = LL_SYS_OK;
127   }
128   else
129   {
130     /* Stop the deep sleep wake-up timer if running */
131     if(os_get_tmr_state(radio_dp_slp_tmr_id) != (os_timer_state)osTimerStopped)
132     {
133       os_timer_stop(radio_dp_slp_tmr_id);
134     }
135 
136     /* Switch Link Layer IP to SLEEP mode (by deactivate DEEP SLEEP mode) */
137 #if defined(BLE)
138     /* BLE & Concurrent use case */
139     cmd_status = ll_intf_le_set_dp_slp_mode(DEEP_SLEEP_DISABLE);
140 #elif defined(MAC)
141     if (radio_set_dp_slp_mode(DEEP_SLEEP_DISABLE) == OT_ERROR_NONE)
142     {
143       cmd_status = SUCCESS;
144     }
145 #else
146  #error "neither MAC not BLE defined"
147 #endif
148     if(cmd_status == SUCCESS)
149     {
150       linklayer_dp_slp_state = LL_SYS_DP_SLP_DISABLED;
151       return_status = LL_SYS_OK;
152     }
153   }
154 
155   /* Re-enable radio interrupt */
156   LINKLAYER_PLAT_EnableRadioIT();
157 
158   return return_status;
159 }
160 
161 /**
162   * @brief  Link Layer deep sleep wake-up timer callback
163   * @param  ptr_arg    pointer passed through the callback
164   * @retval LL_SYS status
165   */
ll_sys_dp_slp_wakeup_evt_clbk(void const * ptr_arg)166 void ll_sys_dp_slp_wakeup_evt_clbk(void const *ptr_arg){
167   int32_t os_status = GENERAL_FAILURE;
168 
169   /* Stop the Link Layer IP DEEP SLEEP wake-up timer */
170   os_status = os_timer_stop(radio_dp_slp_tmr_id);
171   if(os_status != SUCCESS){
172     return;
173   }
174 
175   /* Link Layer IP exits from DEEP SLEEP mode */
176   ll_sys_dp_slp_exit();
177 }
178