1 /***************************************************************************//**
2 * \file cybt_platform_freertos.c
3 *
4 * \brief
5 * Implementation for BT porting interface on FreeRTOS
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2018-2019 Cypress Semiconductor Corporation
10 * SPDX-License-Identifier: Apache-2.0
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 *     http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *******************************************************************************/
24 #include "cyabs_rtos.h"
25 #include "cyhal_lptimer.h"
26 #include "cycfg.h"
27 #include "cybt_platform_task.h"
28 #include "cybt_platform_interface.h"
29 #include "cybt_platform_trace.h"
30 #include "cybt_platform_internal.h"
31 
32 /******************************************************************************
33  *                                Constants
34  ******************************************************************************/
35 #define NOT_IN_ISR             (false)
36 #define IN_ISR                 (true)
37 #define ENABLE_EVENT           (true)
38 #define DISABLE_EVENT          (false)
39 
40 /*****************************************************************************
41  *                           Type Definitions
42  *****************************************************************************/
43 
44 
45 /******************************************************************************
46  *                           Variables Definitions
47  ******************************************************************************/
48 #ifdef DISABLE_LPTIMER
49 static cy_timer_t stack_timer;
50 #else
51 static cyhal_lptimer_t stack_timer;
52 #endif
53 
54 /******************************************************************************
55  *                          Function Declarations
56  ******************************************************************************/
57 extern cybt_result_t cybt_platform_msg_to_bt_task(const uint16_t msg, bool is_from_isr);
58 
59 /******************************************************************************
60  *                           Function Definitions
61  ******************************************************************************/
cybt_platform_get_tick_count_us(void)62 uint64_t cybt_platform_get_tick_count_us(void)
63 {
64 #ifdef DISABLE_LPTIMER
65     static cy_time_t last_time_in_ms = 0;
66     static uint64_t abs_time_cnt_in_us_hi = 0;
67     cy_time_t cur_time_in_ms;
68     uint64_t cur_time_in_ms64 = 0;
69     uint64_t cur_time_in_us64 = 0;
70 
71     cy_rtos_get_time(&cur_time_in_ms);
72 
73     if(cur_time_in_ms < last_time_in_ms)
74     {
75         abs_time_cnt_in_us_hi += 0x100000000;
76     }
77 
78     last_time_in_ms = cur_time_in_ms;
79 
80     cur_time_in_ms64 = cur_time_in_ms + abs_time_cnt_in_us_hi;
81     cur_time_in_us64 = (cur_time_in_ms64 * 1000);
82     return (cur_time_in_us64);
83 #else
84     static uint64_t   abs_tick_cnt_hi = 0;
85     static uint32_t   last_tick_cnt = 0;
86     static uint64_t   lptick_remainder = 0;
87 
88     uint32_t          cur_time_in_lpticks = 0;
89     uint64_t          cur_time_in_lpticks64 = 0;
90     uint64_t          cur_time_in_us = 0;
91     uint64_t          temp_cnt64 = 0;
92 
93     cur_time_in_lpticks = cyhal_lptimer_read(&stack_timer);
94 
95     if (cur_time_in_lpticks < last_tick_cnt)
96     {
97         abs_tick_cnt_hi += 0x100000000;
98     }
99 
100     last_tick_cnt = cur_time_in_lpticks;
101     cur_time_in_lpticks64 = cur_time_in_lpticks + abs_tick_cnt_hi;
102 
103     // convert tick to us
104     temp_cnt64 = cur_time_in_lpticks64 * 1000000;
105     cur_time_in_us = temp_cnt64 / CY_CFG_SYSCLK_CLKLF_FREQ_HZ;
106 
107     lptick_remainder += temp_cnt64 - (cur_time_in_us * CY_CFG_SYSCLK_CLKLF_FREQ_HZ);
108     if(lptick_remainder > CY_CFG_SYSCLK_CLKLF_FREQ_HZ)
109     {
110         cur_time_in_us += 1;
111         lptick_remainder -= CY_CFG_SYSCLK_CLKLF_FREQ_HZ;
112     }
113 
114     return cur_time_in_us;
115 #endif
116 }
117 
cybt_platform_set_next_timeout(uint64_t abs_tick_us_to_expire)118 void cybt_platform_set_next_timeout(uint64_t abs_tick_us_to_expire)
119 {
120     uint64_t curr_time_in_us = cybt_platform_get_tick_count_us();
121     uint64_t time_to_expire_in_us = abs_tick_us_to_expire - curr_time_in_us;
122 
123     if(abs_tick_us_to_expire <= curr_time_in_us)
124     {
125         cybt_platform_msg_to_bt_task(BT_EVT_TIMEOUT, NOT_IN_ISR);
126         return;
127     }
128 #ifdef DISABLE_LPTIMER
129     {
130         cy_rslt_t result;
131         cy_time_t next_timeout = (cy_time_t)(time_to_expire_in_us/1000);
132 
133         /* No need to stop this timer, internally FREE-RTOS restarting the timer
134          * Leaving reminder (~1ms), Its ok verified */
135         result = cy_rtos_start_timer(&stack_timer, next_timeout);
136         if(CY_RSLT_SUCCESS != result)
137         {
138             MAIN_TRACE_DEBUG("timer failed to start %u\n", next_timeout);
139         }
140     }
141 #else
142     {
143         uint32_t time_to_expire_in_lpticks;
144 
145         // convert us to tick
146         time_to_expire_in_lpticks = ((time_to_expire_in_us * CY_CFG_SYSCLK_CLKLF_FREQ_HZ) + 1000000 - 1) / 1000000;
147 
148         cyhal_lptimer_enable_event(&stack_timer, CYHAL_LPTIMER_COMPARE_MATCH, CYHAL_ISR_PRIORITY_DEFAULT, ENABLE_EVENT);
149         cyhal_lptimer_set_delay(&stack_timer, time_to_expire_in_lpticks);
150     }
151 #endif
152 }
153 
154 #ifndef DISABLE_LPTIMER
platform_stack_lptimer_cback(void * callback_arg,cyhal_lptimer_event_t event)155 static void platform_stack_lptimer_cback(void *callback_arg, cyhal_lptimer_event_t event)
156 #else
157 static void platform_stack_timer_callback(cy_timer_callback_arg_t arg)
158 #endif
159 {
160 #ifdef DISABLE_LPTIMER
161     /* Will be called from TmrSVC rtos thread context and not from ISR context */
162     cybt_platform_msg_to_bt_task(BT_EVT_TIMEOUT, NOT_IN_ISR);
163 #else
164     cyhal_lptimer_enable_event(&stack_timer, CYHAL_LPTIMER_COMPARE_MATCH, CYHAL_ISR_PRIORITY_DEFAULT, DISABLE_EVENT);
165     cybt_platform_msg_to_bt_task(BT_EVT_TIMEOUT, IN_ISR);
166 #endif
167 }
168 
cybt_platform_stack_timer_init(void)169 void cybt_platform_stack_timer_init(void)
170 {
171 #ifdef DISABLE_LPTIMER
172     cy_rtos_init_timer(&stack_timer, CY_TIMER_TYPE_ONCE, platform_stack_timer_callback, (cy_timer_callback_arg_t)NULL);
173 #else
174     cyhal_lptimer_init(&stack_timer);
175     cyhal_lptimer_enable_event(&stack_timer, CYHAL_LPTIMER_COMPARE_MATCH, CYHAL_ISR_PRIORITY_DEFAULT, DISABLE_EVENT);
176     cyhal_lptimer_register_callback(&stack_timer, &platform_stack_lptimer_cback, NULL);
177 #endif
178 }
179 
cybt_platform_stack_timer_deinit(void)180 void cybt_platform_stack_timer_deinit(void)
181 {
182 #ifdef DISABLE_LPTIMER
183     cy_rtos_deinit_timer(&stack_timer);
184 #else
185     cyhal_lptimer_free(&stack_timer);
186 #endif
187 }
188