1 /*
2 * Copyright (c) 2021 Chipsea Technologies (Shenzhen) Corp., Ltd. All rights reserved.
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 #include <stdlib.h>
16 #include <string.h>
17 #include "al_rtos.h"
18 #include "dbg_assert.h"
19 #include "co_main.h"
20 #include "sleep_api.h"
21 #include "reg_sysctrl.h"
22 #include "sysctrl_api.h"
23 #include "gpadc_api.h"
24 #include "pwrkey_api.h"
25 #include "dbg.h"
26 #define COTIMER_DEBUG_PRINTF(fmt, ...) //dbg(fmt, ##__VA_ARGS__)
27 #define MAX_LOCAL_BATT_VAULE 4200//mV
28 #define MIN_LOCAL_BATT_VAULE 3300//mV
29 #define CO_BATT_CHECK_TIME_IN_ACTIVE 10000//10s
30 #define CO_BATT_CHECK_TIME_IN_SLEEP 30000//30s
31 #define CO_BATT_REG_CALLBACK_NUM 4
32
33 #ifndef max
34 #define max(a,b) (((a) > (b)) ? (a) : (b))
35 #endif /* max */
36
37 #ifndef min
38 #define min(a,b) (((a) < (b)) ? (a) : (b))
39 #endif /* min */
40
41
42 static TimerHandle_t co_main_timer = NULL;
43 static struct co_list co_main_time_list;
44 static rtos_task_handle co_main_task_handle = NULL;
45 static rtos_queue co_main_evt_queue = NULL;
46 static CO_EVT_HANDLER_T evt_handler[CO_MODUAL_NUM] = {NULL,};
47 #if CO_MAIN_AUTO_POWER_DOWEN
48 static co_timer *co_batt_check_timer = NULL;
49 static co_main_batt_reg_cb_t co_batt_reg_cb[CO_BATT_REG_CALLBACK_NUM] = {NULL,};
50 static uint8_t co_batt_reg_cb_num = 0;
51 #endif
co_event_send(CO_MODUAL_EVENT * msg_src,bool isr)52 int co_event_send(CO_MODUAL_EVENT *msg_src, bool isr)
53 {
54 int res = 0;
55 if(!co_main_evt_queue)
56 return 1;
57 res = rtos_queue_write(co_main_evt_queue, msg_src, 0, isr);
58 if (res) {
59 return -1;
60 }
61 return 0;
62 }
63
co_event_get(CO_MODUAL_EVENT * msg_p)64 int co_event_get(CO_MODUAL_EVENT* msg_p)
65 {
66 int res = rtos_queue_read(co_main_evt_queue, msg_p, -1, false);
67 if (res) {
68 return -1;
69 }
70 return 0;
71 }
72
RTOS_TASK_FCT(co_main_task)73 static RTOS_TASK_FCT(co_main_task)
74 {
75 if (pwrctrl_pwrmd_cpusys_sw_record_getf() >= CPU_SYS_POWER_DOWN) {
76 #if PLF_AON_SUPPORT
77 co_timer_restore();
78 #endif
79 }
80 while (1) {
81 CO_MODUAL_EVENT msg;
82 int res = co_event_get(&msg);
83 if (res == 0) {
84 if(msg.mod_id < CO_MODUAL_NUM){
85 if (evt_handler[msg.mod_id]){
86 evt_handler[msg.mod_id](&(msg.mod_evt));
87 }
88 }
89 } else {
90 dbg("co_main_task mbox get err\n");
91 }
92 }
93 }
94 /**
95 ****************************************************************************************
96 * @brief * basic timer function for co_timer .Users don't have to pay attention to it
97 ****************************************************************************************
98 */
co_main_timer_start(uint32_t t)99 void co_main_timer_start(uint32_t t)
100 {
101 rtos_timer_change_period(co_main_timer, t, 0);
102 }
103 /**
104 ****************************************************************************************
105 * @brief * basic timer function for co_timer .Users don't have to pay attention to it
106 ****************************************************************************************
107 */
co_main_timer_cancel(void)108 void co_main_timer_cancel(void)
109 {
110 rtos_timer_stop(co_main_timer,0);
111 }
112 /**
113 ****************************************************************************************
114 * @brief * basic timer function for co_timer .Users don't have to pay attention to it
115 ****************************************************************************************
116 */
co_main_timer_notify(void)117 static void co_main_timer_notify(void)
118 {
119 CO_MODUAL_EVENT msg;
120 int res = 0;
121 msg.mod_id = CO_MODUAL_TIMER;
122 res = co_event_send(&msg, false);
123 ASSERT_ERR(res == 0 || res == 1);
124 }
125 /**
126 ****************************************************************************************
127 * @brief * basic timer function for co_timer .Users don't have to pay attention to it
128 ****************************************************************************************
129 */
co_main_timer_cb(TimerHandle_t xTimer)130 static void co_main_timer_cb( TimerHandle_t xTimer )
131 {
132 co_main_timer_notify();
133 }
134 /**
135 ****************************************************************************************
136 * @brief * basic timer function for co_timer .Users don't have to pay attention to it
137 ****************************************************************************************
138 */
co_main_timer_init(void)139 static void co_main_timer_init(void)
140 {
141 if (co_main_timer == NULL)
142 co_main_timer = rtos_timer_create("co_main_timer",\
143 10000,pdFALSE,NULL,co_main_timer_cb);
144 co_list_init(&co_main_time_list);
145 }
146 /**
147 ****************************************************************************************
148 * @brief * basic timer function for co_timer .Users don't have to pay attention to it
149 ****************************************************************************************
150 */
co_timer_list_reset(void)151 static void co_timer_list_reset(void)
152 {
153 uint16_t list_len = 0;
154 uint32_t elapsed_time;
155 uint32_t min_duration = (uint32_t)(-1);
156 struct co_list_hdr *element = NULL;
157 co_timer *current_timer;
158 uint32_t time_now = rtos_now(false);
159
160 list_len = co_list_size(&co_main_time_list);
161 if(list_len){
162 element = co_main_time_list.first;
163 while(element != NULL){
164 current_timer = (co_timer *)element;
165 elapsed_time = time_now - current_timer->time_start;
166 if(elapsed_time < current_timer->time_duration){
167 min_duration = min(min_duration,(current_timer->time_duration - elapsed_time));
168 }
169 element = element->next;
170 }
171 }
172 COTIMER_DEBUG_PRINTF("duration %d ,now 0x%x\n",min_duration,time_now);
173 if(min_duration < (uint32_t)(-1)){
174 co_main_timer_start(min_duration);
175 }else{
176 co_main_timer_cancel();
177 }
178 }
179 /**
180 ****************************************************************************************
181 * co_timer_start
182 *
183 * @brief * It is described by co_main.h
184 *
185 ****************************************************************************************
186 */
co_timer_start(co_timer ** timer,uint32_t duration,void * cb_param,co_timer_callback cb,uint32_t is_period)187 void co_timer_start(co_timer **timer, uint32_t duration, void *cb_param, co_timer_callback cb, uint32_t is_period)
188 {
189 co_timer *tmp_timer = NULL;
190 uint16_t list_len = 0;
191 uint8_t is_in_list = 0;
192 if(timer == NULL || cb == NULL){
193 COTIMER_DEBUG_PRINTF("co_timer error\n");
194 ASSERT_ERR(0);
195 return;
196 }
197 COTIMER_DEBUG_PRINTF("%s timer 0x%x\n",__func__,timer);
198 list_len = co_list_size(&co_main_time_list);
199 if(list_len){
200 struct co_list_hdr *tmp_list_hdr = co_main_time_list.first;
201 while(tmp_list_hdr != NULL){
202 co_timer *_cur_timer = (co_timer *)tmp_list_hdr;
203 COTIMER_DEBUG_PRINTF("%s timer 0x%x ,timer_addr 0x%x\n",__func__,_cur_timer,_cur_timer->timer_addr);
204 if(_cur_timer->timer_addr == (uint32_t)timer){
205 is_in_list = 1;
206 COTIMER_DEBUG_PRINTF("%s timer is in list\n",__func__);
207 }
208 tmp_list_hdr = tmp_list_hdr->next;
209 }
210 }
211 if(is_in_list == 0){
212 tmp_timer = (co_timer *)rtos_malloc(sizeof(co_timer));
213 COTIMER_DEBUG_PRINTF("%s tmp_timer alloc 0x%x,cb 0x%x\n",__func__,tmp_timer,cb);
214 if(tmp_timer){
215 *timer = tmp_timer;
216 tmp_timer->cb = cb;
217 tmp_timer->cb_param = cb_param;
218 tmp_timer->timer_addr = (uint32_t)timer;
219 tmp_timer->time_duration = duration;
220 tmp_timer->time_start = rtos_now(false);
221 tmp_timer->is_period = is_period;
222 }else{
223 COTIMER_DEBUG_PRINTF("co_timer malloc error\n");
224 ASSERT_ERR(0);
225 return;
226 }
227 co_list_push_back(&co_main_time_list,&tmp_timer->node);
228 }
229 co_timer_list_reset();
230 }
231 /**
232 ****************************************************************************************
233 * co_timer_stop
234 *
235 * @brief * It is described by co_main.h
236 *
237 ****************************************************************************************
238 */
co_timer_stop(co_timer * timer)239 void co_timer_stop(co_timer *timer)
240 {
241 co_timer *current_timer;
242 struct co_list_hdr *prev_element = NULL;
243 struct co_list_hdr *element = NULL;
244 uint16_t list_len = 0;
245 if(timer == NULL ){
246 COTIMER_DEBUG_PRINTF("co_timer stop error\n");
247 ASSERT_ERR(0);
248 return;
249 }
250
251 list_len = co_list_size(&co_main_time_list);
252 if(list_len){
253 element = co_main_time_list.first;
254 while(element != NULL){
255 current_timer = (co_timer *)element;
256 if(current_timer == timer){
257 co_list_remove(&co_main_time_list,prev_element,element);
258 rtos_free(current_timer);
259 COTIMER_DEBUG_PRINTF("%s tmp_timer free 0x%x\n",__func__,current_timer);
260 co_timer_list_reset();
261 break;
262 }
263 prev_element = element;
264 element = element->next;
265 }
266 }
267 }
268 /**
269 ****************************************************************************************
270 * @brief * basic timer function for co_timer .Users don't have to pay attention to it
271 ****************************************************************************************
272 */
co_timer_list_check(void)273 static void co_timer_list_check(void)
274 {
275 co_timer *current_timer;
276 struct co_list_hdr *prev_element = NULL;
277 struct co_list_hdr *element = NULL;
278 uint16_t list_len = 0;
279 uint8_t time_done = 0;
280 uint32_t elapsed_time;
281 uint32_t time_now = rtos_now(false);
282
283 list_len = co_list_size(&co_main_time_list);
284 if(list_len){
285 element = co_main_time_list.first;
286 COTIMER_DEBUG_PRINTF("%s 0x%x,0x%x\n",__func__,time_now,element);
287 while(element != NULL){
288 current_timer = (co_timer *)element;
289 elapsed_time = time_now - current_timer->time_start;
290 if(elapsed_time >= current_timer->time_duration){
291 co_timer_callback cb = current_timer->cb;
292 void* cb_param = current_timer->cb_param;
293 COTIMER_DEBUG_PRINTF("%s tmp_timer free 0x%x ,cb 0x%x\n",__func__,current_timer,cb);
294 if(current_timer->is_period){
295 current_timer->time_start = time_now;
296 }else{
297 co_list_remove(&co_main_time_list,prev_element,element);
298 rtos_free(current_timer);
299 }
300 if(cb){
301 cb(cb_param);
302 }
303 time_done = 1;
304 break;
305 }
306 prev_element = element;
307 element = element->next;
308 }
309 if(time_done){
310 co_main_timer_notify();
311 co_timer_list_reset();
312 }
313 }
314 }
315 /**
316 ****************************************************************************************
317 * @brief * basic timer function for co_timer .Users don't have to pay attention to it
318 ****************************************************************************************
319 */
co_timer_handle_process(CO_EVENT * evt)320 static bool co_timer_handle_process(CO_EVENT *evt)
321 {
322 co_timer_list_check();
323 return true;
324 }
325
co_main_evt_handler_rigister(CO_MODUAL_ID_T mod_id,CO_EVT_HANDLER_T handler)326 int co_main_evt_handler_rigister(CO_MODUAL_ID_T mod_id, CO_EVT_HANDLER_T handler)
327 {
328 if (mod_id>=CO_MODUAL_NUM) {
329 return -1;
330 }
331 evt_handler[mod_id] = handler;
332 return 0;
333 }
334 #if CO_MAIN_AUTO_POWER_DOWEN
co_main_batt_register_cb(co_main_batt_reg_cb_t callback)335 void co_main_batt_register_cb(co_main_batt_reg_cb_t callback)
336 {
337 uint8_t ret = 0;
338 for(uint8_t i = 0; i < CO_BATT_REG_CALLBACK_NUM; i++){
339 if(co_batt_reg_cb[i] == NULL && callback){
340 co_batt_reg_cb[i] = callback;
341 co_batt_reg_cb_num++;
342 ret = 1;
343 break;
344 }
345 }
346 if(ret == 0){
347 TRACE("batt cb reg error!\n");
348 }
349 }
350
co_main_batt_get_lvl(void)351 static uint8_t co_main_batt_get_lvl(void)
352 {
353 int volt_mv = 0;
354 uint8_t batt_level = 0;// batt level will in 0~9,when value is 0 ,it will run power down process.
355
356 volt_mv = gpadc_measure(GPADC_TYPE_VBAT);
357
358 if(volt_mv < MIN_LOCAL_BATT_VAULE){
359 return batt_level;
360 }
361 if(volt_mv >= MAX_LOCAL_BATT_VAULE){
362 batt_level = 9;
363 return batt_level;
364 }
365 batt_level = (uint8_t)(((volt_mv-MIN_LOCAL_BATT_VAULE)*10)/(MAX_LOCAL_BATT_VAULE-MIN_LOCAL_BATT_VAULE));
366 return batt_level;
367 }
368
co_main_batt_check_timer(void * cb_param)369 static void co_main_batt_check_timer(void *cb_param)
370 {
371 uint8_t batt_level = 0;
372
373 batt_level = co_main_batt_get_lvl();
374 TRACE("batt_level = %x\n",batt_level);
375 co_batt_check_timer = NULL;
376 if(batt_level){
377 co_timer_start(&co_batt_check_timer,CO_BATT_CHECK_TIME_IN_ACTIVE,NULL,co_main_batt_check_timer,0);
378 for(uint8_t i = 0; i < co_batt_reg_cb_num; i++){
379 if(co_batt_reg_cb[i]){
380 co_batt_reg_cb[i](APP_MSG_BATT|(uint32_t)batt_level);
381 }
382 }
383 // notify some task current batt level.
384 }else{
385 //need power down or notify some task to do some process before power down.
386 if(co_batt_reg_cb_num){
387 for(uint8_t i = 0; i < co_batt_reg_cb_num; i++){
388 if(co_batt_reg_cb[i]){
389 if(co_batt_reg_cb_num - 1 == i)
390 co_batt_reg_cb[i](APP_MSG_POWER_DOWN|(uint32_t)batt_level);
391 else
392 co_batt_reg_cb[i](APP_MSG_LOW_POWER|(uint32_t)batt_level);
393 }
394 }
395 }else{
396 pmic_chip_shutdown();
397 }
398 }
399 }
400
co_main_batt_timer_change(uint8_t is_sleep)401 static void co_main_batt_timer_change(uint8_t is_sleep)
402 {
403 uint32_t duration = 0;
404
405 if(is_sleep)
406 duration = CO_BATT_CHECK_TIME_IN_SLEEP;
407 else
408 duration = CO_BATT_CHECK_TIME_IN_ACTIVE;
409
410 if(co_batt_check_timer){
411 co_timer_stop(co_batt_check_timer);
412 co_batt_check_timer = NULL;
413 co_timer_start(&co_batt_check_timer,duration,NULL,co_main_batt_check_timer,0);
414 }
415 }
416
co_main_batt_timer_init(void)417 static void co_main_batt_timer_init(void)
418 {
419 uint32_t pwrmd = pwrctrl_pwrmd_cpusys_sw_record_getf();
420
421 if (pwrmd == CPU_SYS_POWER_ON_RESET) {
422 if(co_batt_check_timer == NULL){
423 co_timer_start(&co_batt_check_timer,CO_BATT_CHECK_TIME_IN_ACTIVE,NULL,co_main_batt_check_timer,0);
424 }
425 }
426 }
427 #endif
428
429 #if PLF_AON_SUPPORT
430 static uint32_t co_main_timer_min_duration = (uint32_t)-1;
431 #define TIMER_LIST_SLEEP_ENTRY_MAX 5
432 co_timer co_timer_list_sleep_entry[TIMER_LIST_SLEEP_ENTRY_MAX];
433 PRIVATE_HOST_ARRAY_DECLARE(G0RTOS, co_timer, TIMER_LIST_SLEEP_ENTRY_MAX, co_timer_list_sleep_entry);
434
435 uint8_t co_timer_lp_level = CO_TIMER_LP_LEVEL_HIBERNATE;
436
co_timer_save(void)437 void co_timer_save(void)
438 {
439 uint16_t list_len = 0;
440 list_len = co_list_size(&co_main_time_list);
441
442 COTIMER_DEBUG_PRINTF("%s list_len 0x%x\n",__func__,list_len);
443 memset(&co_timer_list_sleep_entry[0],0,sizeof(co_timer_list_sleep_entry));
444 if(list_len){
445 uint8_t i = 0;
446 struct co_list_hdr *element = NULL;
447 co_timer *current_timer;
448 element = co_main_time_list.first;
449 COTIMER_DEBUG_PRINTF("%s element 0x%x\n",__func__,element);
450 while(element != NULL){
451 current_timer = (co_timer *)element;
452 memcpy(&co_timer_list_sleep_entry[i++],current_timer,sizeof(co_timer));
453 element = element->next;
454 if(i == TIMER_LIST_SLEEP_ENTRY_MAX){
455 break;
456 }
457 }
458 }
459 memcpy(&backup_co_timer_list_sleep_entry[0], &co_timer_list_sleep_entry[0], sizeof(co_timer_list_sleep_entry));
460 }
461
co_timer_restore(void)462 void co_timer_restore(void)
463 {
464 co_timer *tmp_timer = NULL;
465 co_timer *cur_timer = NULL;
466
467 memcpy(&co_timer_list_sleep_entry[0], &backup_co_timer_list_sleep_entry[0], sizeof(co_timer_list_sleep_entry));
468 for(uint8_t i = 0; i < TIMER_LIST_SLEEP_ENTRY_MAX; i++){
469 COTIMER_DEBUG_PRINTF("%s timer_addr 0x%x\n",__func__,co_timer_list_sleep_entry[i].timer_addr);
470 if(co_timer_list_sleep_entry[i].timer_addr){
471 cur_timer = &co_timer_list_sleep_entry[i];
472 tmp_timer = (co_timer *)rtos_malloc(sizeof(co_timer));
473 COTIMER_DEBUG_PRINTF("%s tmp_timer alloc 0x%x\n",__func__,tmp_timer);
474 if(tmp_timer){
475 *((co_timer **)cur_timer->timer_addr) = tmp_timer;
476 tmp_timer->cb = cur_timer->cb;
477 tmp_timer->cb_param = cur_timer->cb_param;
478 tmp_timer->timer_addr = cur_timer->timer_addr;
479 tmp_timer->time_duration = cur_timer->time_duration;
480 tmp_timer->time_start = cur_timer->time_start;
481 tmp_timer->is_period = cur_timer->is_period;
482 COTIMER_DEBUG_PRINTF("%d, 0x%x, 0x%x\n",tmp_timer->time_duration,tmp_timer->time_start,tmp_timer->cb);
483 }else{
484 COTIMER_DEBUG_PRINTF("co_timer malloc error\n");
485 ASSERT_ERR(0);
486 return;
487 }
488 co_list_push_back(&co_main_time_list,&tmp_timer->node);
489 //co_timer_lp_level = CO_TIMER_LP_LEVEL_ACTIVE;
490 }
491 }
492 co_main_timer_notify();
493 }
494
co_timer_sleep_level_set(POWER_MODE_LEVEL_T level)495 void co_timer_sleep_level_set(POWER_MODE_LEVEL_T level)
496 {
497 if (level == PM_LEVEL_ACTIVE) {
498 co_timer_lp_level = CO_TIMER_LP_LEVEL_ACTIVE;
499 }else{
500 co_timer_lp_level = CO_TIMER_LP_LEVEL_HIBERNATE;
501 }
502 }
503
co_timer_is_sleep_allowed(void)504 int co_timer_is_sleep_allowed(void)
505 {
506 int ret = 0;
507 uint16_t list_len = 0;
508 uint32_t elapsed_time;
509 uint32_t min_duration = (uint32_t)(-1);
510 struct co_list_hdr *element = NULL;
511 co_timer *current_timer;
512 uint32_t time_now = rtos_now(false);
513
514
515 do {
516 if (co_timer_lp_level == CO_TIMER_LP_LEVEL_HIBERNATE) {
517 list_len = co_list_size(&co_main_time_list);
518 if ( list_len == 0 ) {
519 ret = 1;
520 break;
521 } else {
522 element = co_main_time_list.first;
523 while(element != NULL){
524 current_timer = (co_timer *)element;
525 elapsed_time = time_now - current_timer->time_start;
526 if(elapsed_time < current_timer->time_duration){
527 min_duration = min(min_duration,(current_timer->time_duration - elapsed_time));
528 }
529 element = element->next;
530 }
531
532 COTIMER_DEBUG_PRINTF("m_d %d\n",min_duration);
533 if(min_duration >= CO_TIMER_ALLOW_MIN_SLEEP_DURATION){
534 ret = 1;
535 co_main_timer_min_duration = min_duration;
536 break;
537 }
538 }
539 }
540 } while (0);
541
542 return ret;
543 }
544
get_co_main_timer_min_duration(void)545 uint32_t get_co_main_timer_min_duration(void)
546 {
547 return co_main_timer_min_duration;
548 }
549
co_timer_sleep_indicate(POWER_MODE_LEVEL_T level)550 void co_timer_sleep_indicate(POWER_MODE_LEVEL_T level)
551 {
552 //todo
553 #if CO_MAIN_AUTO_POWER_DOWEN
554 co_main_batt_timer_change(1);
555 #endif
556 }
557
co_timer_wakeup_indicate(void)558 void co_timer_wakeup_indicate(void)
559 {
560 //todo
561 #if CO_MAIN_AUTO_POWER_DOWEN
562 co_main_batt_timer_change(0);
563 #endif
564 }
565
co_timer_sleep_entry_init(void)566 void co_timer_sleep_entry_init(void)
567 {
568 uint32_t pwrmd = pwrctrl_pwrmd_cpusys_sw_record_getf();
569
570 if (pwrmd == CPU_SYS_POWER_ON_RESET) {
571 sleep_entry_t co_timer_sleep_entry = {
572 co_timer_sleep_level_set,
573 co_timer_is_sleep_allowed,
574 co_timer_sleep_indicate,
575 co_timer_wakeup_indicate,
576 };
577 sleep_entry_register(&co_timer_sleep_entry);
578 }
579 }
580 #endif /* PLF_AON_SUPPORT */
581
co_main_init(void)582 void co_main_init(void)
583 {
584 co_main_timer_init();
585 co_main_evt_handler_rigister(CO_MODUAL_TIMER,co_timer_handle_process);
586 #if PLF_AON_SUPPORT
587 co_timer_sleep_entry_init();
588 #endif
589 #if CO_MAIN_AUTO_POWER_DOWEN
590 co_main_batt_timer_init();
591 #endif
592 // create the co main evt queue
593 if (rtos_queue_create(sizeof(CO_MODUAL_EVENT), CO_EVT_MAX, &co_main_evt_queue)) {
594 dbg("failed to create co_main_mbox\n");
595 return;
596 }
597 // Create the co main task
598 if (rtos_task_create(co_main_task, "CO_TASK", CO_TASK,
599 TASK_STACK_SIZE_CO_MAIN, NULL, TASK_PRIORITY_CO_MAIN, &co_main_task_handle)) {
600 dbg("failed to create co_main_task\n");
601 rtos_queue_delete(co_main_evt_queue);
602 co_main_evt_queue = NULL;
603 return;
604 }
605 }
606
607