1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 
16 #include <stdint.h>
17 #include <stdlib.h>
18 #include <stdbool.h>
19 #include "freertos/FreeRTOS.h"
20 #include "esp_attr.h"
21 #include "esp_freertos_hooks.h"
22 
23 #include "sdkconfig.h"
24 #include "esp_pm.h"
25 #include "esp_private/pm_impl.h"
26 
27 //We use just a static array here because it's not expected many components will need
28 //an idle or tick hook.
29 #define MAX_HOOKS 8
30 
31 static portMUX_TYPE hooks_spinlock = portMUX_INITIALIZER_UNLOCKED;
32 static esp_freertos_idle_cb_t idle_cb[portNUM_PROCESSORS][MAX_HOOKS]={0};
33 static esp_freertos_tick_cb_t tick_cb[portNUM_PROCESSORS][MAX_HOOKS]={0};
34 
esp_vApplicationTickHook(void)35 void IRAM_ATTR esp_vApplicationTickHook(void)
36 {
37     int n;
38     int core = xPortGetCoreID();
39     for (n=0; n<MAX_HOOKS; n++) {
40         if (tick_cb[core][n]!=NULL) {
41             tick_cb[core][n]();
42         }
43     }
44 }
45 
esp_vApplicationIdleHook(void)46 void esp_vApplicationIdleHook(void)
47 {
48     bool can_go_idle=true;
49     int core = xPortGetCoreID();
50     for (int n = 0; n < MAX_HOOKS; n++) {
51         if (idle_cb[core][n] != NULL && !idle_cb[core][n]()) {
52             can_go_idle = false;
53         }
54     }
55     if (!can_go_idle) {
56         return;
57     }
58 
59 #ifdef CONFIG_PM_ENABLE
60     esp_pm_impl_idle_hook();
61 #endif
62 
63     esp_pm_impl_waiti();
64 }
65 
esp_register_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t new_idle_cb,UBaseType_t cpuid)66 esp_err_t esp_register_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t new_idle_cb, UBaseType_t cpuid)
67 {
68     if(cpuid >= portNUM_PROCESSORS){
69         return ESP_ERR_INVALID_ARG;
70     }
71     portENTER_CRITICAL(&hooks_spinlock);
72     for(int n = 0; n < MAX_HOOKS; n++){
73         if (idle_cb[cpuid][n]==NULL) {
74             idle_cb[cpuid][n]=new_idle_cb;
75             portEXIT_CRITICAL(&hooks_spinlock);
76             return ESP_OK;
77         }
78     }
79     portEXIT_CRITICAL(&hooks_spinlock);
80     return ESP_ERR_NO_MEM;
81 }
82 
esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb)83 esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb)
84 {
85     return esp_register_freertos_idle_hook_for_cpu(new_idle_cb, xPortGetCoreID());
86 }
87 
esp_register_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t new_tick_cb,UBaseType_t cpuid)88 esp_err_t esp_register_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t new_tick_cb, UBaseType_t cpuid)
89 {
90     if(cpuid >= portNUM_PROCESSORS){
91         return ESP_ERR_INVALID_ARG;
92     }
93     portENTER_CRITICAL(&hooks_spinlock);
94     for(int n = 0; n < MAX_HOOKS; n++){
95         if (tick_cb[cpuid][n]==NULL) {
96             tick_cb[cpuid][n]=new_tick_cb;
97             portEXIT_CRITICAL(&hooks_spinlock);
98             return ESP_OK;
99         }
100     }
101     portEXIT_CRITICAL(&hooks_spinlock);
102     return ESP_ERR_NO_MEM;
103 }
104 
esp_register_freertos_tick_hook(esp_freertos_tick_cb_t new_tick_cb)105 esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t new_tick_cb)
106 {
107     return esp_register_freertos_tick_hook_for_cpu(new_tick_cb, xPortGetCoreID());
108 }
109 
esp_deregister_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t old_idle_cb,UBaseType_t cpuid)110 void esp_deregister_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t old_idle_cb, UBaseType_t cpuid)
111 {
112     if(cpuid >= portNUM_PROCESSORS){
113         return;
114     }
115     portENTER_CRITICAL(&hooks_spinlock);
116     for(int n = 0; n < MAX_HOOKS; n++){
117         if(idle_cb[cpuid][n] == old_idle_cb) idle_cb[cpuid][n] = NULL;
118     }
119     portEXIT_CRITICAL(&hooks_spinlock);
120 }
121 
esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb)122 void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb)
123 {
124     portENTER_CRITICAL(&hooks_spinlock);
125     for(int m = 0; m < portNUM_PROCESSORS; m++) {
126         esp_deregister_freertos_idle_hook_for_cpu(old_idle_cb, m);
127     }
128     portEXIT_CRITICAL(&hooks_spinlock);
129 }
130 
esp_deregister_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t old_tick_cb,UBaseType_t cpuid)131 void esp_deregister_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t old_tick_cb, UBaseType_t cpuid)
132 {
133     if(cpuid >= portNUM_PROCESSORS){
134         return;
135     }
136     portENTER_CRITICAL(&hooks_spinlock);
137     for(int n = 0; n < MAX_HOOKS; n++){
138         if(tick_cb[cpuid][n] == old_tick_cb) tick_cb[cpuid][n] = NULL;
139     }
140     portEXIT_CRITICAL(&hooks_spinlock);
141 }
142 
esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb)143 void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb)
144 {
145     portENTER_CRITICAL(&hooks_spinlock);
146     for(int m = 0; m < portNUM_PROCESSORS; m++){
147         esp_deregister_freertos_tick_hook_for_cpu(old_tick_cb, m);
148     }
149     portEXIT_CRITICAL(&hooks_spinlock);
150 }
151