| 
									
										
										
										
											2021-05-24 02:09:38 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: Apache-2.0 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-12-07 14:18:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <ctype.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-21 13:07:34 +08:00
										 |  |  | #include "sdkconfig.h"
 | 
					
						
							|  |  |  | #include "esp_types.h"
 | 
					
						
							| 
									
										
										
										
											2016-12-07 14:18:10 +08:00
										 |  |  | #include "esp_log.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-13 18:02:45 +08:00
										 |  |  | #include "soc/rtc_periph.h"
 | 
					
						
							|  |  |  | #include "soc/syscon_periph.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-14 16:33:46 +08:00
										 |  |  | #include "soc/rtc.h"
 | 
					
						
							| 
									
										
										
										
											2019-06-06 10:57:29 +08:00
										 |  |  | #include "soc/periph_defs.h"
 | 
					
						
							| 
									
										
										
										
											2016-12-07 14:18:10 +08:00
										 |  |  | #include "freertos/FreeRTOS.h"
 | 
					
						
							| 
									
										
										
										
											2017-03-02 16:13:30 +08:00
										 |  |  | #include "freertos/semphr.h"
 | 
					
						
							| 
									
										
										
										
											2017-07-18 19:57:28 +08:00
										 |  |  | #include "freertos/timers.h"
 | 
					
						
							| 
									
										
										
										
											2017-06-02 17:47:23 +08:00
										 |  |  | #include "esp_intr_alloc.h"
 | 
					
						
							|  |  |  | #include "sys/lock.h"
 | 
					
						
							|  |  |  | #include "driver/rtc_cntl.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef NDEBUG
 | 
					
						
							|  |  |  | // Enable built-in checks in queue.h in debug builds
 | 
					
						
							|  |  |  | #define INVARIANTS
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-03-14 17:29:32 +08:00
										 |  |  | #include "sys/queue.h"
 | 
					
						
							| 
									
										
										
										
											2017-06-02 17:47:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-07 14:18:10 +08:00
										 |  |  | portMUX_TYPE rtc_spinlock = portMUX_INITIALIZER_UNLOCKED; | 
					
						
							| 
									
										
										
										
											2019-07-25 23:11:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-02 17:47:23 +08:00
										 |  |  | /*---------------------------------------------------------------
 | 
					
						
							|  |  |  |                         INTERRUPT HANDLER | 
					
						
							|  |  |  | ---------------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct rtc_isr_handler_ { | 
					
						
							|  |  |  |     uint32_t mask; | 
					
						
							|  |  |  |     intr_handler_t handler; | 
					
						
							|  |  |  |     void* handler_arg; | 
					
						
							|  |  |  |     SLIST_ENTRY(rtc_isr_handler_) next; | 
					
						
							|  |  |  | } rtc_isr_handler_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SLIST_HEAD(rtc_isr_handler_list_, rtc_isr_handler_) s_rtc_isr_handler_list = | 
					
						
							|  |  |  |         SLIST_HEAD_INITIALIZER(s_rtc_isr_handler_list); | 
					
						
							|  |  |  | portMUX_TYPE s_rtc_isr_handler_list_lock = portMUX_INITIALIZER_UNLOCKED; | 
					
						
							|  |  |  | static intr_handle_t s_rtc_isr_handle; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void rtc_isr(void* arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint32_t status = REG_READ(RTC_CNTL_INT_ST_REG); | 
					
						
							|  |  |  |     rtc_isr_handler_t* it; | 
					
						
							| 
									
										
										
										
											2019-03-25 16:07:04 +05:30
										 |  |  |     portENTER_CRITICAL_ISR(&s_rtc_isr_handler_list_lock); | 
					
						
							| 
									
										
										
										
											2017-06-02 17:47:23 +08:00
										 |  |  |     SLIST_FOREACH(it, &s_rtc_isr_handler_list, next) { | 
					
						
							|  |  |  |         if (it->mask & status) { | 
					
						
							| 
									
										
										
										
											2019-03-25 16:07:04 +05:30
										 |  |  |             portEXIT_CRITICAL_ISR(&s_rtc_isr_handler_list_lock); | 
					
						
							| 
									
										
										
										
											2017-06-02 17:47:23 +08:00
										 |  |  |             (*it->handler)(it->handler_arg); | 
					
						
							| 
									
										
										
										
											2019-03-25 16:07:04 +05:30
										 |  |  |             portENTER_CRITICAL_ISR(&s_rtc_isr_handler_list_lock); | 
					
						
							| 
									
										
										
										
											2017-06-02 17:47:23 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-03-25 16:07:04 +05:30
										 |  |  |     portEXIT_CRITICAL_ISR(&s_rtc_isr_handler_list_lock); | 
					
						
							| 
									
										
										
										
											2017-06-02 17:47:23 +08:00
										 |  |  |     REG_WRITE(RTC_CNTL_INT_CLR_REG, status); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-16 16:33:30 +07:00
										 |  |  | static esp_err_t rtc_isr_ensure_installed(void) | 
					
						
							| 
									
										
										
										
											2017-06-02 17:47:23 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     esp_err_t err = ESP_OK; | 
					
						
							|  |  |  |     portENTER_CRITICAL(&s_rtc_isr_handler_list_lock); | 
					
						
							|  |  |  |     if (s_rtc_isr_handle) { | 
					
						
							|  |  |  |         goto out; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     REG_WRITE(RTC_CNTL_INT_ENA_REG, 0); | 
					
						
							|  |  |  |     REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX); | 
					
						
							|  |  |  |     err = esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, 0, &rtc_isr, NULL, &s_rtc_isr_handle); | 
					
						
							|  |  |  |     if (err != ESP_OK) { | 
					
						
							|  |  |  |         goto out; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock); | 
					
						
							|  |  |  |     return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, uint32_t rtc_intr_mask) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     esp_err_t err = rtc_isr_ensure_installed(); | 
					
						
							|  |  |  |     if (err != ESP_OK) { | 
					
						
							|  |  |  |         return err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rtc_isr_handler_t* item = malloc(sizeof(*item)); | 
					
						
							|  |  |  |     if (item == NULL) { | 
					
						
							|  |  |  |         return ESP_ERR_NO_MEM; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     item->handler = handler; | 
					
						
							|  |  |  |     item->handler_arg = handler_arg; | 
					
						
							|  |  |  |     item->mask = rtc_intr_mask; | 
					
						
							|  |  |  |     portENTER_CRITICAL(&s_rtc_isr_handler_list_lock); | 
					
						
							|  |  |  |     SLIST_INSERT_HEAD(&s_rtc_isr_handler_list, item, next); | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     rtc_isr_handler_t* it; | 
					
						
							|  |  |  |     rtc_isr_handler_t* prev = NULL; | 
					
						
							|  |  |  |     bool found = false; | 
					
						
							|  |  |  |     portENTER_CRITICAL(&s_rtc_isr_handler_list_lock); | 
					
						
							|  |  |  |     SLIST_FOREACH(it, &s_rtc_isr_handler_list, next) { | 
					
						
							|  |  |  |         if (it->handler == handler && it->handler_arg == handler_arg) { | 
					
						
							|  |  |  |             if (it == SLIST_FIRST(&s_rtc_isr_handler_list)) { | 
					
						
							|  |  |  |                 SLIST_REMOVE_HEAD(&s_rtc_isr_handler_list, next); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 SLIST_REMOVE_AFTER(prev, next); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             found = true; | 
					
						
							| 
									
										
										
										
											2018-07-11 21:31:23 +08:00
										 |  |  |             free(it); | 
					
						
							| 
									
										
										
										
											2017-06-02 17:47:23 +08:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         prev = it; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock); | 
					
						
							|  |  |  |     return found ? ESP_OK : ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  | } |