-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCoTask.h
More file actions
261 lines (228 loc) · 9.5 KB
/
CoTask.h
File metadata and controls
261 lines (228 loc) · 9.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#ifndef __COTASK_H__
#define __COTASK_H__
/*************************************Include********************************************/
#include <stdint.h>
#include <stdio.h>
/**********************************Macro Setting****************************************/
// <<< Use Configuration Wizard in Context Menu >>>
// <h> CoTask configurations and settings
// <o> Define FREQ_OF_TICK_COLCK <10-2000:1>
// <i> Default: 1000, The Frequency of the timer which support the tick.
#define FREQ_OF_TICK_COLCK 1000
// <q> Enable Semaphore Support
// <i> Default: 1, Enable or disable semaphore support for CoTask
#define COTASK_SEMAPHORE_ENABLE 1
// <q> Enable Utilization Monitoring
// <i> Default: 1, Enable or disable task utilization monitoring
#define COTASK_UTILIZATION_ENABLE 0
// </h>
// <<< end of configuration section >>>
/*************************************TypeDefs********************************************/
typedef enum {
E_DELAY_STATE_FINISH = 0x00, // 延时完成状态
E_DELAY_STATE, // 单纯延时状态
#if(COTASK_SEMAPHORE_ENABLE==1)
E_WAIT_SEM_DELAY_STATE, // 等待信号量的延时
E_WAIT_SEM_DELAY_TIMEOUT, // 等待信号量的延时超时
#endif
} EDelayState;
typedef struct _cotask CoTask;
typedef uint8_t (*CoTaskFun)(CoTask* p_cotask); // Task function type
#if(COTASK_SEMAPHORE_ENABLE==1)
typedef uint8_t CoTaskSemaphore; //cotask的信号量,最多支持释放256个
#endif
struct _cotask
{
struct _cotask *next; // Pointer to the next task in the linked list
#if(COTASK_SEMAPHORE_ENABLE==1)
CoTaskSemaphore* wait_semaphore; // 等待信号量的释放
#endif
CoTaskFun task_callback; // Task callback function
uint16_t delay_tick; // delay tick counter
uint16_t cotask_state; //yeild出去的状态(行号)
EDelayState delay_flag:8; // Delay flag
};
/*************************************MacroFunction****************************************/
//毫秒到TICK的换算
#define MS2TICK(ms) ((ms)*(FREQ_OF_TICK_COLCK)/1000)
//进入每个CoTask调函数域内,需要在进入回调函数中马上调用
#define COTASK_ENTER switch(p_cotask->cotask_state) { case 0:
//退出每个CoTask调函数域内,需要在退出回调函数时调用
#define COTASK_EXIT } p_cotask->cotask_state = 0; return 1;
//在CoTask中调用,会马上退出,并在tick时刻后重新回到退出地方重新运行
// (当然此时不能有另外的CoTask占用着MCU运行, 如果有CoTask占用着MCU,那只有等待它释放MCU才可以)
#define COTASK_AWIAT_TICK(tick_of_delay) \
do { \
p_cotask->cotask_state= __LINE__; \
p_cotask->delay_flag = E_DELAY_STATE;/*进入延时状态*/ \
p_cotask->delay_tick = tick_of_delay;/*延时时间,单位 tick*/ \
return 0; \
case __LINE__:; \
} while(0)
#if(COTASK_SEMAPHORE_ENABLE==1)
//在任何地方都能调用,用于释放一个信号量
#define COTASK_RELEASE_SEM(sem)\
do{ \
if(sem < 255)sem++; \
}while(0)
//在CoTask回调函数中调用,等待一个信号量,
//当有信号量释放时,如果此时MCU没有被其他CoTask占用运行,会进入该回调函数,从等待处往后执行
#define COTASK_AWAIT_SEM(sem) \
do{ \
p_cotask->cotask_state= __LINE__; \
p_cotask->wait_semaphore = &sem; \
return 0; \
case __LINE__:; \
}while(0)
//在CoTask回调函数中调用,等待一个信号量,并设置了超时时间
//当有信号量释放时,如果此时MCU没有被其他CoTask占用运行,会进入该回调函数,从等待处往后执行
//即使没有信号量释放,只要过了超时时间,且MCU没有被其他CoTask占用运行,也会进入该回调函数,从等待处往后执行
//在等待该信号量后,可以使用@ COTASK_WAIT_SEM_IS_TIMEOUT 这个宏函数检查是否是等待信号量超时
#define COTASK_AWAIT_SEM_UNTIL(sem, tick_of_delay) \
do { \
p_cotask->cotask_state= __LINE__; \
p_cotask->delay_flag = E_WAIT_SEM_DELAY_STATE;/*进入延时状态*/ \
p_cotask->wait_semaphore = &(sem); \
p_cotask->delay_tick = tick_of_delay;/*延时时间,单位 tick*/ \
return 0; \
case __LINE__:; \
} while(0)
//在CoTask回调函数中调用,检查等待信号量有没有超时
#define COTASK_WAIT_SEM_IS_TIMEOUT(sem) (p_cotask->delay_flag == E_WAIT_SEM_DELAY_TIMEOUT)
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*************************************ExtendFunction****************************************/
uint8_t CoTask_Create(CoTask * ptask, CoTaskFun task_callback);
uint8_t CoTask_Delete(CoTask * ptask);
uint8_t CoTask_Proc(void);
uint8_t CoTask_Tick(void);
#if(COTASK_UTILIZATION_ENABLE==1)
float CoTask_GetUtilization(void);
#endif
/*************************************FunctionImplememnt****************************************/
//由于COTASK实现上不需要提供接口函数,所以,建议直接将这个实现放在中断函数文件中,方便中断函数调用CoTask_Tick()
#ifdef COTASK_IMPLEMENT
//全局静态变量
static CoTask * haedptr = NULL; //CoTask 列表头指针
#if(COTASK_UTILIZATION_ENABLE==1)
static uint8_t utilization_flag_intask = 0; //用于粗略计算利用率的flag//在task执行前至1,执行结束后至0
static uint16_t utilization_counter_1s = 0; //用于粗略计算利用率的counter(用来计时1s钟的counter)
static uint16_t utilization_counter_intask = 0; //用于粗略计算利用率的counter(用来计时有多少时间在task执行过程中)
static float utilization = 0; //用于存储当前的利用率
float CoTask_GetUtilization(void){
return utilization;
}
#endif
//具体函数实现
uint8_t CoTask_Create(CoTask * ptask, CoTaskFun task_callback)
{
if (ptask == NULL || task_callback == NULL) {
return 1; // 返回1表示无效参数
}
ptask->delay_flag = E_DELAY_STATE_FINISH;
ptask->delay_tick = 0;
ptask->cotask_state = 0;
#if(COTASK_SEMAPHORE_ENABLE==1)
ptask->wait_semaphore = NULL;
#endif
ptask->task_callback = task_callback;
// 头插法
if (haedptr == NULL) {
haedptr = ptask; // First task
} else {
ptask->next = haedptr;
haedptr = ptask; // Insert at the head of the list
}
return 0; // Success
}
uint8_t CoTask_Delete(CoTask * ptask){
if(ptask == NULL){
return 1; // 返回1表示无效参数
}
if(ptask == haedptr){ // If the task to be deleted is the head of
haedptr = ptask->next; // Move the head to the next task
} else {
CoTask* p = haedptr;
while(p->next != NULL){
if(p->next == ptask){ // Find the task to be deleted
p->next = p->next->next; // Delete the task
return 0; // Success
}
p = p->next;
}
}
return 1; //没有找到ptask,无法删除,返回删除失败
}
uint8_t CoTask_Tick(void)
{
CoTask *current = haedptr;
while (current != NULL) {
#if(COTASK_SEMAPHORE_ENABLE==1)
if (current->delay_flag == E_DELAY_STATE || \
current->delay_flag == E_WAIT_SEM_DELAY_STATE) {
#else
if (current->delay_flag == E_DELAY_STATE){
#endif
if(current->delay_tick != 0){ //时间还没有到期的话
current->delay_tick--;
}else { //延时时间到期
if(current->delay_flag == E_DELAY_STATE) //普通延时到期
current->delay_flag = E_DELAY_STATE_FINISH; // 标志普通延时完成
#if(COTASK_SEMAPHORE_ENABLE==1)
else if(current->delay_flag == E_WAIT_SEM_DELAY_STATE) //等待信号量延时到期
current->delay_flag = E_WAIT_SEM_DELAY_TIMEOUT; // 标志等待量超时
#endif
}
}
current = current->next; // Move to the next task
}
#if(COTASK_UTILIZATION_ENABLE==1)
if(utilization_flag_intask)
utilization_counter_intask++;
utilization_counter_1s++;
if(utilization_counter_1s == MS2TICK(1000)){ //计时达到一秒的话
utilization = (utilization_counter_intask*1.0)/utilization_counter_1s;
utilization_counter_intask = 0;
utilization_counter_1s = 0;
}
#endif
return 0; // Success
}
uint8_t CoTask_Proc(void)
{
CoTask *current = haedptr;
while (current != NULL) {
#if(COTASK_SEMAPHORE_ENABLE==1)
if((current->wait_semaphore != NULL && *(current->wait_semaphore) != 0) /*有信号量释放了*/ \
|| current->delay_flag == E_DELAY_STATE_FINISH /*单纯延时完成了*/ \
|| current->delay_flag == E_WAIT_SEM_DELAY_TIMEOUT /*等待信号量超时了*/ ){
if(current->wait_semaphore != NULL && *(current->wait_semaphore) != 0){ //如果是获取到信号量进入的回调
(*(current->wait_semaphore))--; //获取一个信号量
current->delay_flag = E_DELAY_STATE_FINISH;
current->delay_tick = 0;
current->wait_semaphore = NULL; //不再获取该信号量
}
#else
if(current->delay_flag == E_DELAY_STATE_FINISH /*单纯延时完成了*/){
#endif
if (current->task_callback != NULL) {
#if(COTASK_UTILIZATION_ENABLE==1)
utilization_flag_intask = 1;
#endif
current->task_callback(current); // Call the task callback function
#if(COTASK_UTILIZATION_ENABLE==1)
utilization_flag_intask = 0;
#endif
}
}
current = current->next; // Move to the next task
}
return 0; // Success
}
#endif
#ifdef __cplusplus
}
#endif
#endif