backup
parent
33092db4ce
commit
ff973d6274
|
@ -158,6 +158,7 @@ void Error_Handler(void);
|
|||
#define SOM_POWER_EN_GPIO_Port GPIOD
|
||||
#define SOM_SHUTDOWN_REQ_Pin GPIO_PIN_5
|
||||
#define SOM_SHUTDOWN_REQ_GPIO_Port GPIOD
|
||||
#define SOM_SHUTDOWN_REQ_EXTI_IRQn EXTI9_5_IRQn
|
||||
#define SOM_SLEEP_WAKE_Pin GPIO_PIN_6
|
||||
#define SOM_SLEEP_WAKE_GPIO_Port GPIOD
|
||||
#define SOM_FORCE_RECOVERY_Pin GPIO_PIN_7
|
||||
|
|
|
@ -21,8 +21,8 @@ typedef enum
|
|||
typedef struct
|
||||
{
|
||||
struct{
|
||||
sta_t last_sta; //last system state
|
||||
sta_t sta; //current system state
|
||||
sta_t next_sta; //current system state
|
||||
bool power_btn; //开关是否被按下
|
||||
bool custom_btn;
|
||||
bool pwr_led;
|
||||
|
|
|
@ -60,6 +60,7 @@ void EXTI0_IRQHandler(void);
|
|||
void EXTI3_IRQHandler(void);
|
||||
void DMA1_Channel1_IRQHandler(void);
|
||||
void ADC1_2_IRQHandler(void);
|
||||
void EXTI9_5_IRQHandler(void);
|
||||
void TIM1_UP_IRQHandler(void);
|
||||
void I2C1_EV_IRQHandler(void);
|
||||
void I2C1_ER_IRQHandler(void);
|
||||
|
|
|
@ -75,10 +75,10 @@ const osThreadAttr_t IWDGRefreshTask_attributes = {
|
|||
.priority = (osPriority_t) osPriorityHigh,
|
||||
.stack_size = 128 * 4
|
||||
};
|
||||
/* Definitions for ButtonDetect */
|
||||
osThreadId_t ButtonDetectHandle;
|
||||
const osThreadAttr_t ButtonDetect_attributes = {
|
||||
.name = "ButtonDetect",
|
||||
/* Definitions for EventDetect */
|
||||
osThreadId_t EventDetectHandle;
|
||||
const osThreadAttr_t EventDetect_attributes = {
|
||||
.name = "EventDetect",
|
||||
.priority = (osPriority_t) osPriorityLow,
|
||||
.stack_size = 128 * 4
|
||||
};
|
||||
|
@ -111,7 +111,7 @@ const osThreadAttr_t SOMPowerManageTask_attributes = {
|
|||
void StartDefaultTask(void *argument);
|
||||
void StartLedBlinkTask(void *argument);
|
||||
void StartIWDGRefreshTask(void *argument);
|
||||
void StartButtonDetect(void *argument);
|
||||
void StartEventDetect(void *argument);
|
||||
void StartCoulombRead(void *argument);
|
||||
void StartStateSwitchTask(void *argument);
|
||||
void StartSOMPowerManageTask(void *argument);
|
||||
|
@ -155,8 +155,8 @@ void MX_FREERTOS_Init(void) {
|
|||
/* creation of IWDGRefreshTask */
|
||||
IWDGRefreshTaskHandle = osThreadNew(StartIWDGRefreshTask, NULL, &IWDGRefreshTask_attributes);
|
||||
|
||||
/* creation of ButtonDetect */
|
||||
ButtonDetectHandle = osThreadNew(StartButtonDetect, NULL, &ButtonDetect_attributes);
|
||||
/* creation of EventDetect */
|
||||
EventDetectHandle = osThreadNew(StartEventDetect, NULL, &EventDetect_attributes);
|
||||
|
||||
/* creation of CoulombRead */
|
||||
CoulombReadHandle = osThreadNew(StartCoulombRead, NULL, &CoulombRead_attributes);
|
||||
|
@ -245,7 +245,7 @@ void StartLedBlinkTask(void *argument)
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{//sleep mode
|
||||
for(uint16_t i=0;i<25;i++)
|
||||
{//20 light level
|
||||
for(uint16_t j=0;j<3;j++)
|
||||
|
@ -296,67 +296,59 @@ void StartIWDGRefreshTask(void *argument)
|
|||
/* USER CODE END StartIWDGRefreshTask */
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Header_StartButtonDetect */
|
||||
/* USER CODE BEGIN Header_StartEventDetect */
|
||||
/**
|
||||
* @brief Function implementing the ButtonDetect thread.
|
||||
* @brief Function implementing the EventDetect thread.
|
||||
* @param argument: Not used
|
||||
* @retval None
|
||||
*/
|
||||
/* USER CODE END Header_StartButtonDetect */
|
||||
void StartButtonDetect(void *argument)
|
||||
/* USER CODE END Header_StartEventDetect */
|
||||
void StartEventDetect(void *argument)
|
||||
{
|
||||
/* USER CODE BEGIN StartButtonDetect */
|
||||
|
||||
/* USER CODE BEGIN StartEventDetect */
|
||||
/* Infinite loop */
|
||||
for(;;)
|
||||
{
|
||||
|
||||
if(NaviKit.sys.power_btn == true)
|
||||
{//power btn has been pushed
|
||||
osDelay(1000);
|
||||
if(NaviKit.sys.power_btn == true)
|
||||
{//power btn has been pushed more than 1000 ms
|
||||
// while(NaviKit.sys.power_btn == true);//wait to release button
|
||||
// while(NaviKit.sys.power_btn == true);//wait to release button
|
||||
if(NaviKit.sys.sta == runing)
|
||||
{//system is runing now, user request to shutdown
|
||||
NaviKit.sys.sta = shutdown;
|
||||
NaviKit.sys.next_sta = shutdown;
|
||||
}
|
||||
else if(NaviKit.sys.sta == shutdown)
|
||||
{//system is shutdown now , user request to power on
|
||||
NaviKit.sys.sta = runing;
|
||||
NaviKit.sys.next_sta = runing;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//sleep mode is unused
|
||||
// if(NaviKit.sys.sta == runing)
|
||||
// NaviKit.sys.sta = sleep;
|
||||
// else if(NaviKit.sys.sta == sleep)
|
||||
// NaviKit.sys.sta = runing;
|
||||
}
|
||||
else
|
||||
{
|
||||
//sleep mode is unused
|
||||
// if(NaviKit.sys.sta == runing)
|
||||
// NaviKit.sys.sta = sleep;
|
||||
// else if(NaviKit.sys.sta == sleep)
|
||||
// NaviKit.sys.sta = runing;
|
||||
}
|
||||
}
|
||||
if(NaviKit.sys.custom_btn == true )
|
||||
{//custom button has been pushed
|
||||
osDelay(1000);
|
||||
if(NaviKit.sys.custom_btn == true )
|
||||
{//custom button has been pushed over 1000 ms
|
||||
// while(NaviKit.sys.custom_btn == true);//wait to release button
|
||||
if(NaviKit.sys.sta == runing)
|
||||
{
|
||||
//restart usb3.0 gigabit ethernet controler
|
||||
HAL_GPIO_WritePin(SOC_U3_GEC_PWR_CTL_GPIO_Port,SOC_U3_GEC_PWR_CTL_Pin,GPIO_PIN_RESET);
|
||||
// HAL_GPIO_WritePin(SOC_U3_HOST_PWR_CTL_GPIO_Port,SOC_U3_HOST_PWR_CTL_Pin, GPIO_PIN_RESET);
|
||||
Beep(50);
|
||||
osDelay(1000);
|
||||
HAL_GPIO_WritePin(SOC_U3_GEC_PWR_CTL_GPIO_Port,SOC_U3_GEC_PWR_CTL_Pin,GPIO_PIN_SET);
|
||||
// HAL_GPIO_WritePin(SOC_U3_HOST_PWR_CTL_GPIO_Port,SOC_U3_HOST_PWR_CTL_Pin, GPIO_PIN_RESET);
|
||||
Beep(50);
|
||||
}
|
||||
NaviKit.sys.next_sta = shutdown;
|
||||
else if(NaviKit.sys.sta == shutdown)
|
||||
NaviKit.sys.next_sta = runing;
|
||||
}
|
||||
}
|
||||
|
||||
osDelay(10);
|
||||
osDelay(10);
|
||||
}
|
||||
/* USER CODE END StartButtonDetect */
|
||||
/* USER CODE END StartEventDetect */
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Header_StartCoulombRead */
|
||||
|
@ -404,26 +396,28 @@ void StartStateSwitchTask(void *argument)
|
|||
/* Infinite loop */
|
||||
for(;;)
|
||||
{
|
||||
NaviKit.sys.last_sta = NaviKit.sys.sta;
|
||||
osDelay(10);
|
||||
if(NaviKit.sys.last_sta != NaviKit.sys.sta)
|
||||
switch(NaviKit.sys.sta)
|
||||
osDelay(1);
|
||||
if(NaviKit.sys.next_sta != NaviKit.sys.sta)
|
||||
{
|
||||
case shutdown:
|
||||
{//only from runing state
|
||||
if(NaviKit.sys.last_sta == runing)
|
||||
enter_shutdown_state();
|
||||
}break;
|
||||
case runing:
|
||||
{//from sleep and shutdown state
|
||||
enter_runing_state();
|
||||
}break;
|
||||
case sleep:
|
||||
{//only form runing state
|
||||
if(NaviKit.sys.last_sta == runing)
|
||||
enter_sleep_state();
|
||||
switch(NaviKit.sys.next_sta)
|
||||
{
|
||||
case shutdown:
|
||||
{//only from runing state
|
||||
if(NaviKit.sys.sta == runing)
|
||||
enter_shutdown_state();
|
||||
}break;
|
||||
case runing:
|
||||
{//from sleep and shutdown state
|
||||
enter_runing_state();
|
||||
}break;
|
||||
case sleep:
|
||||
{//only form runing state
|
||||
if(NaviKit.sys.sta == runing)
|
||||
enter_sleep_state();
|
||||
|
||||
}break;
|
||||
}break;
|
||||
}
|
||||
NaviKit.sys.sta = NaviKit.sys.next_sta;
|
||||
}
|
||||
}
|
||||
/* USER CODE END StartStateSwitchTask */
|
||||
|
@ -443,6 +437,18 @@ void StartSOMPowerManageTask(void *argument)
|
|||
for(;;)
|
||||
{
|
||||
osDelay(1);
|
||||
|
||||
// //module request to stop
|
||||
// if(HAL_GPIO_ReadPin(SOM_SHUTDOWN_REQ_GPIO_Port,SOM_SHUTDOWN_REQ_Pin) == GPIO_PIN_SET)
|
||||
// {
|
||||
// //1.the last step of normal power off process
|
||||
// //2.Thermal shutdown
|
||||
// //3.vdd_in's wave more than 5% of 5.0V
|
||||
//
|
||||
//
|
||||
// HAL_GPIO_WritePin(SOM_POWER_EN_GPIO_Port,SOM_POWER_EN_Pin,GPIO_PIN_RESET);
|
||||
// }
|
||||
|
||||
}
|
||||
/* USER CODE END StartSOMPowerManageTask */
|
||||
}
|
||||
|
@ -451,28 +457,8 @@ void StartSOMPowerManageTask(void *argument)
|
|||
/* USER CODE BEGIN Application */
|
||||
|
||||
|
||||
//power off by button pushed
|
||||
void force_sys_stop()
|
||||
{
|
||||
|
||||
|
||||
Beep(40);
|
||||
}
|
||||
|
||||
//module request to stop
|
||||
void sys_stop()
|
||||
{
|
||||
if(HAL_GPIO_ReadPin(SOM_SHUTDOWN_REQ_GPIO_Port,SOM_SHUTDOWN_REQ_Pin) == GPIO_PIN_SET)
|
||||
{
|
||||
//1.the last step of normal power off process
|
||||
//2.Thermal shutdown
|
||||
//3.vdd_in's wave more than 5% of 5.0V
|
||||
|
||||
|
||||
HAL_GPIO_WritePin(SOM_POWER_EN_GPIO_Port,SOM_POWER_EN_Pin,GPIO_PIN_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void enter_shutdown_state()
|
||||
{
|
||||
|
@ -481,12 +467,6 @@ void enter_shutdown_state()
|
|||
|
||||
HAL_GPIO_WritePin(SOM_POWER_EN_GPIO_Port ,SOM_POWER_EN_Pin, GPIO_PIN_RESET); osDelay(100);
|
||||
|
||||
// for(uint8_t i=0;i<100;i++)
|
||||
// {
|
||||
// if(HAL_GPIO_ReadPin(SOM_SHUTDOWN_REQ_GPIO_Port,SOM_SHUTDOWN_REQ_Pin))
|
||||
// osDelay(10);
|
||||
// }
|
||||
|
||||
HAL_GPIO_WritePin(SOC_U3_HUB_PWR_CTL_GPIO_Port,SOC_U3_HUB_PWR_CTL_Pin, GPIO_PIN_RESET); osDelay(100);
|
||||
HAL_GPIO_WritePin(SOC_U2_HUB_PWR_CTL_GPIO_Port,SOC_U2_HUB_PWR_CTL_Pin, GPIO_PIN_RESET); osDelay(100);
|
||||
HAL_GPIO_WritePin(SOC_U3_HOST_PWR_CTL_GPIO_Port,SOC_U3_HOST_PWR_CTL_Pin, GPIO_PIN_RESET); osDelay(100);
|
||||
|
@ -544,14 +524,12 @@ void enter_sleep_state()
|
|||
HAL_GPIO_WritePin(SYS_FAN_CTL_1_GPIO_Port,SYS_FAN_CTL_1_Pin,GPIO_PIN_RESET); osDelay(100);
|
||||
HAL_GPIO_WritePin(SYS_FAN_CTL_2_GPIO_Port,SYS_FAN_CTL_2_Pin,GPIO_PIN_RESET); osDelay(100);
|
||||
HAL_GPIO_WritePin(SYS_FAN_CTL_3_GPIO_Port,SYS_FAN_CTL_3_Pin,GPIO_PIN_RESET); osDelay(100);
|
||||
|
||||
|
||||
}
|
||||
void enter_runing_state()
|
||||
{
|
||||
|
||||
printf("Enter to runing state \n");
|
||||
Beep(200);
|
||||
printf("Enter to runing state \n");
|
||||
Beep(200);
|
||||
|
||||
HAL_GPIO_WritePin(PMB_PS_ON_GPIO_Port ,PMB_PS_ON_Pin, GPIO_PIN_SET); osDelay(100);
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ void MX_GPIO_Init(void)
|
|||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = SOM_SHUTDOWN_REQ_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(SOM_SHUTDOWN_REQ_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
|
@ -177,6 +177,9 @@ void MX_GPIO_Init(void)
|
|||
HAL_NVIC_SetPriority(EXTI3_IRQn, 5, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
|
||||
|
||||
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 5, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
|
||||
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
@ -189,7 +192,24 @@ void Beep(uint32_t time_ms)
|
|||
}
|
||||
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
|
||||
{
|
||||
if(GPIO_Pin==SYS_POWER_BTN_Pin)
|
||||
if(GPIO_Pin == SOM_SHUTDOWN_REQ_Pin)
|
||||
{
|
||||
if(HAL_GPIO_ReadPin(SOM_SHUTDOWN_REQ_GPIO_Port, SOM_SHUTDOWN_REQ_Pin)==GPIO_PIN_SET)
|
||||
{//Rising edge trigger
|
||||
NaviKit.som.shutdown_req = true;
|
||||
if(NaviKit.sys.sta == runing)
|
||||
{
|
||||
NaviKit.sys.next_sta = shutdown;
|
||||
printf("enter shutdown mode... \n");
|
||||
}
|
||||
}
|
||||
if(HAL_GPIO_ReadPin(SOM_SHUTDOWN_REQ_GPIO_Port, SOM_SHUTDOWN_REQ_Pin)==GPIO_PIN_RESET)
|
||||
{//falling edge trigger
|
||||
NaviKit.som.shutdown_req = false;
|
||||
}
|
||||
|
||||
}
|
||||
else if(GPIO_Pin == SYS_POWER_BTN_Pin)
|
||||
{
|
||||
if(HAL_GPIO_ReadPin(SYS_POWER_BTN_GPIO_Port, SYS_POWER_BTN_Pin)==GPIO_PIN_SET)
|
||||
{//Rising edge trigger
|
||||
|
|
|
@ -11,5 +11,5 @@ NaviKit_t NaviKit;
|
|||
void NaviKit_var_init()
|
||||
{
|
||||
NaviKit.sys.sta = shutdown;
|
||||
NaviKit.sys.last_sta = shutdown;
|
||||
NaviKit.sys.next_sta = shutdown;
|
||||
}
|
||||
|
|
|
@ -263,6 +263,20 @@ void ADC1_2_IRQHandler(void)
|
|||
/* USER CODE END ADC1_2_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles EXTI line[9:5] interrupts.
|
||||
*/
|
||||
void EXTI9_5_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN EXTI9_5_IRQn 0 */
|
||||
|
||||
/* USER CODE END EXTI9_5_IRQn 0 */
|
||||
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);
|
||||
/* USER CODE BEGIN EXTI9_5_IRQn 1 */
|
||||
|
||||
/* USER CODE END EXTI9_5_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles TIM1 update interrupt.
|
||||
*/
|
||||
|
|
|
@ -1027,7 +1027,7 @@ void HAL_PCD_IRQHandler(PCD_HandleTypeDef *hpcd)
|
|||
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
|
||||
hpcd->SuspendCallback(hpcd);
|
||||
#else
|
||||
//HAL_PCD_SuspendCallback(hpcd);
|
||||
HAL_PCD_SuspendCallback(hpcd);
|
||||
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
|
||||
}
|
||||
__HAL_PCD_CLEAR_FLAG(hpcd, USB_OTG_GINTSTS_USBSUSP);
|
||||
|
|
|
@ -40,12 +40,12 @@ Dma.ADC1.0.Priority=DMA_PRIORITY_LOW
|
|||
Dma.ADC1.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority
|
||||
Dma.Request0=ADC1
|
||||
Dma.RequestsNb=1
|
||||
FREERTOS.FootprintOK=false
|
||||
FREERTOS.FootprintOK=true
|
||||
FREERTOS.HEAP_NUMBER=4
|
||||
FREERTOS.INCLUDE_xTaskGetCurrentTaskHandle=1
|
||||
FREERTOS.INCLUDE_xTaskGetHandle=1
|
||||
FREERTOS.IPParameters=Tasks01,configMAX_TASK_NAME_LEN,configUSE_TICKLESS_IDLE,INCLUDE_xTaskGetCurrentTaskHandle,INCLUDE_xTaskGetHandle,configUSE_APPLICATION_TASK_TAG,FootprintOK,configUSE_IDLE_HOOK,configUSE_TICK_HOOK,configUSE_MALLOC_FAILED_HOOK,configGENERATE_RUN_TIME_STATS,configUSE_STATS_FORMATTING_FUNCTIONS,configUSE_TRACE_FACILITY,HEAP_NUMBER,configTOTAL_HEAP_SIZE
|
||||
FREERTOS.Tasks01=defaultTask,24,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;LedBlinkTask,8,128,StartLedBlinkTask,Default,NULL,Dynamic,NULL,NULL;IWDGRefreshTask,40,128,StartIWDGRefreshTask,Default,NULL,Dynamic,NULL,NULL;ButtonDetect,8,128,StartButtonDetect,Default,NULL,Dynamic,NULL,NULL;CoulombRead,8,128,StartCoulombRead,Default,NULL,Dynamic,NULL,NULL;StateSwitchTask,8,128,StartStateSwitchTask,Default,NULL,Dynamic,NULL,NULL;SOMPowerManageTask,8,128,StartSOMPowerManageTask,Default,NULL,Dynamic,NULL,NULL
|
||||
FREERTOS.Tasks01=defaultTask,24,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;LedBlinkTask,8,128,StartLedBlinkTask,Default,NULL,Dynamic,NULL,NULL;IWDGRefreshTask,40,128,StartIWDGRefreshTask,Default,NULL,Dynamic,NULL,NULL;EventDetect,8,128,StartEventDetect,Default,NULL,Dynamic,NULL,NULL;CoulombRead,8,128,StartCoulombRead,Default,NULL,Dynamic,NULL,NULL;StateSwitchTask,8,128,StartStateSwitchTask,Default,NULL,Dynamic,NULL,NULL;SOMPowerManageTask,8,128,StartSOMPowerManageTask,Default,NULL,Dynamic,NULL,NULL
|
||||
FREERTOS.configGENERATE_RUN_TIME_STATS=0
|
||||
FREERTOS.configMAX_TASK_NAME_LEN=32
|
||||
FREERTOS.configTOTAL_HEAP_SIZE=8192
|
||||
|
@ -157,6 +157,7 @@ NVIC.DMA1_Channel1_IRQn=true\:5\:0\:false\:true\:true\:9\:true\:false\:true
|
|||
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.EXTI0_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true
|
||||
NVIC.EXTI3_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true
|
||||
NVIC.EXTI9_5_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true
|
||||
NVIC.FLASH_IRQn=true\:5\:0\:false\:true\:true\:3\:true\:true\:true
|
||||
NVIC.ForceEnableDMAVector=true
|
||||
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
|
@ -368,7 +369,7 @@ PD4.Signal=GPIO_Output
|
|||
PD5.GPIOParameters=GPIO_Label
|
||||
PD5.GPIO_Label=SOM_SHUTDOWN_REQ
|
||||
PD5.Locked=true
|
||||
PD5.Signal=GPIO_Input
|
||||
PD5.Signal=GPXTI5
|
||||
PD6.GPIOParameters=PinState,GPIO_Label
|
||||
PD6.GPIO_Label=SOM_SLEEP_WAKE
|
||||
PD6.Locked=true
|
||||
|
@ -509,6 +510,8 @@ SH.GPXTI0.0=GPIO_EXTI0
|
|||
SH.GPXTI0.ConfNb=1
|
||||
SH.GPXTI3.0=GPIO_EXTI3
|
||||
SH.GPXTI3.ConfNb=1
|
||||
SH.GPXTI5.0=GPIO_EXTI5
|
||||
SH.GPXTI5.ConfNb=1
|
||||
UART4.IPParameters=VirtualMode
|
||||
UART4.VirtualMode=Asynchronous
|
||||
USART1.IPParameters=VirtualMode
|
||||
|
|
Loading…
Reference in New Issue