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