1 /*
2  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <stdbool.h>
11 #include "freertos/FreeRTOS.h"
12 #include "esp_attr.h"
13 #include "esp_freertos_hooks.h"
14 #include "esp_cpu.h"
15 
16 #include "sdkconfig.h"
17 
18 #if CONFIG_PM_ENABLE
19 #include "esp_pm.h"
20 #include "esp_private/pm_impl.h"
21 #endif
22 
23 //We use just a static array here because it's not expected many components will need
24 //an idle or tick hook.
25 #define MAX_HOOKS 8
26 
27 static portMUX_TYPE hooks_spinlock = portMUX_INITIALIZER_UNLOCKED;
28 static esp_freertos_idle_cb_t idle_cb[portNUM_PROCESSORS][MAX_HOOKS]={0};
29 static esp_freertos_tick_cb_t tick_cb[portNUM_PROCESSORS][MAX_HOOKS]={0};
30 
esp_vApplicationTickHook(void)31 void IRAM_ATTR esp_vApplicationTickHook(void)
32 {
33     int n;
34     int core = xPortGetCoreID();
35     for (n=0; n<MAX_HOOKS; n++) {
36         if (tick_cb[core][n]!=NULL) {
37             tick_cb[core][n]();
38         }
39     }
40 }
41 
esp_vApplicationIdleHook(void)42 void esp_vApplicationIdleHook(void)
43 {
44     bool can_go_idle=true;
45     int core = xPortGetCoreID();
46     for (int n = 0; n < MAX_HOOKS; n++) {
47         if (idle_cb[core][n] != NULL && !idle_cb[core][n]()) {
48             can_go_idle = false;
49         }
50     }
51     if (!can_go_idle) {
52         return;
53     }
54 
55 #ifdef CONFIG_PM_ENABLE
56     esp_pm_impl_idle_hook();
57     esp_pm_impl_waiti();
58 #else
59     esp_cpu_wait_for_intr();
60 #endif
61 
62 
63 }
64 
esp_register_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t new_idle_cb,UBaseType_t cpuid)65 esp_err_t esp_register_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t new_idle_cb, UBaseType_t cpuid)
66 {
67     if(cpuid >= portNUM_PROCESSORS){
68         return ESP_ERR_INVALID_ARG;
69     }
70     portENTER_CRITICAL(&hooks_spinlock);
71     for(int n = 0; n < MAX_HOOKS; n++){
72         if (idle_cb[cpuid][n]==NULL) {
73             idle_cb[cpuid][n]=new_idle_cb;
74             portEXIT_CRITICAL(&hooks_spinlock);
75             return ESP_OK;
76         }
77     }
78     portEXIT_CRITICAL(&hooks_spinlock);
79     return ESP_ERR_NO_MEM;
80 }
81 
esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb)82 esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb)
83 {
84     return esp_register_freertos_idle_hook_for_cpu(new_idle_cb, xPortGetCoreID());
85 }
86 
esp_register_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t new_tick_cb,UBaseType_t cpuid)87 esp_err_t esp_register_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t new_tick_cb, UBaseType_t cpuid)
88 {
89     if(cpuid >= portNUM_PROCESSORS){
90         return ESP_ERR_INVALID_ARG;
91     }
92     portENTER_CRITICAL(&hooks_spinlock);
93     for(int n = 0; n < MAX_HOOKS; n++){
94         if (tick_cb[cpuid][n]==NULL) {
95             tick_cb[cpuid][n]=new_tick_cb;
96             portEXIT_CRITICAL(&hooks_spinlock);
97             return ESP_OK;
98         }
99     }
100     portEXIT_CRITICAL(&hooks_spinlock);
101     return ESP_ERR_NO_MEM;
102 }
103 
esp_register_freertos_tick_hook(esp_freertos_tick_cb_t new_tick_cb)104 esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t new_tick_cb)
105 {
106     return esp_register_freertos_tick_hook_for_cpu(new_tick_cb, xPortGetCoreID());
107 }
108 
esp_deregister_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t old_idle_cb,UBaseType_t cpuid)109 void esp_deregister_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t old_idle_cb, UBaseType_t cpuid)
110 {
111     if(cpuid >= portNUM_PROCESSORS){
112         return;
113     }
114     portENTER_CRITICAL(&hooks_spinlock);
115     for(int n = 0; n < MAX_HOOKS; n++){
116         if(idle_cb[cpuid][n] == old_idle_cb) idle_cb[cpuid][n] = NULL;
117     }
118     portEXIT_CRITICAL(&hooks_spinlock);
119 }
120 
esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb)121 void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb)
122 {
123     portENTER_CRITICAL(&hooks_spinlock);
124     for(int m = 0; m < portNUM_PROCESSORS; m++) {
125         esp_deregister_freertos_idle_hook_for_cpu(old_idle_cb, m);
126     }
127     portEXIT_CRITICAL(&hooks_spinlock);
128 }
129 
esp_deregister_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t old_tick_cb,UBaseType_t cpuid)130 void esp_deregister_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t old_tick_cb, UBaseType_t cpuid)
131 {
132     if(cpuid >= portNUM_PROCESSORS){
133         return;
134     }
135     portENTER_CRITICAL(&hooks_spinlock);
136     for(int n = 0; n < MAX_HOOKS; n++){
137         if(tick_cb[cpuid][n] == old_tick_cb) tick_cb[cpuid][n] = NULL;
138     }
139     portEXIT_CRITICAL(&hooks_spinlock);
140 }
141 
esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb)142 void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb)
143 {
144     portENTER_CRITICAL(&hooks_spinlock);
145     for(int m = 0; m < portNUM_PROCESSORS; m++){
146         esp_deregister_freertos_tick_hook_for_cpu(old_tick_cb, m);
147     }
148     portEXIT_CRITICAL(&hooks_spinlock);
149 }
150