.ioc
#MicroXplorer Configuration settings - do not modify
File.Version=6
IWDG.IPParameters=Reload
IWDG.Reload=1000
KeepUserPlacement=false
Mcu.Family=STM32F1
Mcu.IP0=IWDG
Mcu.IP1=NVIC
Mcu.IP2=RCC
Mcu.IP3=RTC
Mcu.IP4=SYS
Mcu.IP5=USART1
Mcu.IPNb=6
Mcu.Name=STM32F103C(8-B)Tx
Mcu.Package=LQFP48
Mcu.Pin0=PC14-OSC32_IN
Mcu.Pin1=PC15-OSC32_OUT
Mcu.Pin10=VP_RTC_VS_RTC_Calendar
Mcu.Pin11=VP_RTC_No_RTC_Output
Mcu.Pin12=VP_SYS_VS_Systick
Mcu.Pin2=PD0-OSC_IN
Mcu.Pin3=PD1-OSC_OUT
Mcu.Pin4=PA9
Mcu.Pin5=PA10
Mcu.Pin6=PA13
Mcu.Pin7=PA14
Mcu.Pin8=VP_IWDG_VS_IWDG
Mcu.Pin9=VP_RTC_VS_RTC_Activate
Mcu.PinsNb=13
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F103C8Tx
MxCube.Version=4.26.1
MxDb.Version=DB.4.0.261
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
NVIC.RTC_Alarm_IRQn=true\:0\:0\:false\:false\:true\:true
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false
NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false
NVIC.USART1_IRQn=true\:0\:0\:false\:false\:true\:true
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false
PA10.Mode=Asynchronous
PA10.Signal=USART1_RX
PA13.Mode=Serial_Wire
PA13.Signal=SYS_JTMS-SWDIO
PA14.Mode=Serial_Wire
PA14.Signal=SYS_JTCK-SWCLK
PA9.Mode=Asynchronous
PA9.Signal=USART1_TX
PC14-OSC32_IN.Mode=LSE-External-Oscillator
PC14-OSC32_IN.Signal=RCC_OSC32_IN
PC15-OSC32_OUT.Mode=LSE-External-Oscillator
PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
PCC.Checker=false
PCC.Line=STM32F103
PCC.MCU=STM32F103C(8-B)Tx
PCC.PartNumber=STM32F103C8Tx
PCC.Seq0=0
PCC.Series=STM32F1
PCC.Temperature=25
PCC.Vdd=3.3
PD0-OSC_IN.Mode=HSE-External-Oscillator
PD0-OSC_IN.Signal=RCC_OSC_IN
PD1-OSC_OUT.Mode=HSE-External-Oscillator
PD1-OSC_OUT.Signal=RCC_OSC_OUT
PinOutPanel.RotationAngle=0
ProjectManager.AskForMigrate=true
ProjectManager.BackupPrevious=false
ProjectManager.CompilerOptimize=6
ProjectManager.ComputerToolchain=false
ProjectManager.CoupleFile=true
ProjectManager.CustomerFirmwarePackage=
ProjectManager.DefaultFWLocation=true
ProjectManager.DeletePrevious=true
ProjectManager.DeviceId=STM32F103C8Tx
ProjectManager.FirmwarePackage=STM32Cube FW_F1 V1.6.1
ProjectManager.FreePins=false
ProjectManager.HalAssertFull=false
ProjectManager.HeapSize=0x200
ProjectManager.KeepUserCode=true
ProjectManager.LastFirmware=true
ProjectManager.LibraryCopy=0
ProjectManager.MainLocation=Src
ProjectManager.PreviousToolchain=
ProjectManager.ProjectBuild=false
ProjectManager.ProjectFileName=TimeCtrler.ioc
ProjectManager.ProjectName=TimeCtrler
ProjectManager.StackSize=0x400
ProjectManager.TargetToolchain=MDK-ARM V5
ProjectManager.ToolChainLocation=
ProjectManager.UnderRoot=false
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_USART1_UART_Init-USART1-false-HAL-true,4-MX_RTC_Init-RTC-false-HAL-true,5-MX_IWDG_Init-IWDG-false-HAL-true
RCC.ADCFreqValue=36000000
RCC.AHBFreq_Value=72000000
RCC.APB1CLKDivider=RCC_HCLK_DIV2
RCC.APB1Freq_Value=36000000
RCC.APB1TimFreq_Value=72000000
RCC.APB2Freq_Value=72000000
RCC.APB2TimFreq_Value=72000000
RCC.FCLKCortexFreq_Value=72000000
RCC.FamilyName=M
RCC.HCLKFreq_Value=72000000
RCC.IPParameters=ADCFreqValue,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,MCOFreq_Value,PLLCLKFreq_Value,PLLMCOFreq_Value,PLLMUL,PLLSourceVirtual,RTCClockSelection,RTCFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,TimSysFreq_Value,USBFreq_Value,VCOOutput2Freq_Value
RCC.MCOFreq_Value=72000000
RCC.PLLCLKFreq_Value=72000000
RCC.PLLMCOFreq_Value=36000000
RCC.PLLMUL=RCC_PLL_MUL9
RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE
RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
RCC.RTCFreq_Value=32768
RCC.SYSCLKFreq_VALUE=72000000
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
RCC.TimSysFreq_Value=72000000
RCC.USBFreq_Value=72000000
RCC.VCOOutput2Freq_Value=8000000
RTC.Hours=12
RTC.IPParameters=Hours,Minutes,Seconds,WeekDay,Month,Year
RTC.Minutes=59
RTC.Month=RTC_MONTH_DECEMBER
RTC.Seconds=59
RTC.WeekDay=RTC_WEEKDAY_TUESDAY
RTC.Year=20
USART1.IPParameters=VirtualMode
USART1.VirtualMode=VM_ASYNC
VP_IWDG_VS_IWDG.Mode=IWDG_Activate
VP_IWDG_VS_IWDG.Signal=IWDG_VS_IWDG
VP_RTC_No_RTC_Output.Mode=RTC_OUT_NO
VP_RTC_No_RTC_Output.Signal=RTC_No_RTC_Output
VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
VP_RTC_VS_RTC_Calendar.Mode=RTC_Calendar
VP_RTC_VS_RTC_Calendar.Signal=RTC_VS_RTC_Calendar
VP_SYS_VS_Systick.Mode=SysTick
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
board=custom
main.h
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT(c) 2020 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H__
#define __MAIN_H__
/* Includes ------------------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private define ------------------------------------------------------------*/
/* ########################## Assert Selection ############################## */
/**
* @brief Uncomment the line below to expanse the "assert_param" macro in the
* HAL drivers code
*/
/* #define USE_FULL_ASSERT 1U */
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
extern "C" {
#endif
void _Error_Handler(char *, int);
#define Error_Handler() _Error_Handler(__FILE__, __LINE__)
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H__ */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
main.c
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT(c) 2020 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_hal.h"
#include "iwdg.h"
#include "rtc.h"
#include "usart.h"
#include "gpio.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
*
* @retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_RTC_Init();
MX_IWDG_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInit;
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE
|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @param file: The file name as string.
* @param line: The line in file as a number.
* @retval None
*/
void _Error_Handler(char *file, int line)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
while(1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
stm32f1xx_it.c
/**
******************************************************************************
* @file stm32f1xx_it.c
* @brief Interrupt Service Routines.
******************************************************************************
*
* COPYRIGHT(c) 2020 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include "stm32f1xx.h"
#include "stm32f1xx_it.h"
/* USER CODE BEGIN 0 */
#include "sys.h"
#include "timer.h"
/* USER CODE END 0 */
/* External variables --------------------------------------------------------*/
extern RTC_HandleTypeDef hrtc;
extern UART_HandleTypeDef huart1;
/******************************************************************************/
/* Cortex-M3 Processor Interruption and Exception Handlers */
/******************************************************************************/
/**
* @brief This function handles Non maskable interrupt.
*/
void NMI_Handler(void)
{
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
/* USER CODE END NonMaskableInt_IRQn 0 */
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
/* USER CODE END NonMaskableInt_IRQn 1 */
}
/**
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
printf("HardFault");
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
/* USER CODE BEGIN HardFault_IRQn 1 */
/* USER CODE END HardFault_IRQn 1 */
}
/**
* @brief This function handles Memory management fault.
*/
void MemManage_Handler(void)
{
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
/* USER CODE END MemoryManagement_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
/* USER CODE END W1_MemoryManagement_IRQn 0 */
}
/* USER CODE BEGIN MemoryManagement_IRQn 1 */
/* USER CODE END MemoryManagement_IRQn 1 */
}
/**
* @brief This function handles Prefetch fault, memory access fault.
*/
void BusFault_Handler(void)
{
/* USER CODE BEGIN BusFault_IRQn 0 */
/* USER CODE END BusFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_BusFault_IRQn 0 */
/* USER CODE END W1_BusFault_IRQn 0 */
}
/* USER CODE BEGIN BusFault_IRQn 1 */
/* USER CODE END BusFault_IRQn 1 */
}
/**
* @brief This function handles Undefined instruction or illegal state.
*/
void UsageFault_Handler(void)
{
/* USER CODE BEGIN UsageFault_IRQn 0 */
/* USER CODE END UsageFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_UsageFault_IRQn 0 */
/* USER CODE END W1_UsageFault_IRQn 0 */
}
/* USER CODE BEGIN UsageFault_IRQn 1 */
/* USER CODE END UsageFault_IRQn 1 */
}
/**
* @brief This function handles System service call via SWI instruction.
*/
void SVC_Handler(void)
{
/* USER CODE BEGIN SVCall_IRQn 0 */
/* USER CODE END SVCall_IRQn 0 */
/* USER CODE BEGIN SVCall_IRQn 1 */
/* USER CODE END SVCall_IRQn 1 */
}
/**
* @brief This function handles Debug monitor.
*/
void DebugMon_Handler(void)
{
/* USER CODE BEGIN DebugMonitor_IRQn 0 */
/* USER CODE END DebugMonitor_IRQn 0 */
/* USER CODE BEGIN DebugMonitor_IRQn 1 */
/* USER CODE END DebugMonitor_IRQn 1 */
}
/**
* @brief This function handles Pendable request for system service.
*/
void PendSV_Handler(void)
{
/* USER CODE BEGIN PendSV_IRQn 0 */
/* USER CODE END PendSV_IRQn 0 */
/* USER CODE BEGIN PendSV_IRQn 1 */
/* USER CODE END PendSV_IRQn 1 */
}
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
HAL_SYSTICK_IRQHandler();
/* USER CODE BEGIN SysTick_IRQn 1 */
RA_Task();
static uint8_t ctr=0;
if(ctr<(1000/HZ))
{
ctr++;
}
else
{
ctr=0;
jiffies_64+=1;
timer_update(&timer_base);
}
/* USER CODE END SysTick_IRQn 1 */
}
/******************************************************************************/
/* STM32F1xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file (startup_stm32f1xx.s). */
/******************************************************************************/
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
/**
* @brief This function handles RTC alarm interrupt through EXTI line 17.
*/
void RTC_Alarm_IRQHandler(void)
{
/* USER CODE BEGIN RTC_Alarm_IRQn 0 */
/* USER CODE END RTC_Alarm_IRQn 0 */
HAL_RTC_AlarmIRQHandler(&hrtc);
/* USER CODE BEGIN RTC_Alarm_IRQn 1 */
/* USER CODE END RTC_Alarm_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
sys.h
#ifndef __SYS_H__
#define __SYS_H__
#include "stm32f1xx.h"
#include "stm32f1xx_hal.h"
#include "list.h"
#define my_assert_param(expr) ((expr) ? (void)0U : my_assert_failed((uint8_t *)__FILE__, __LINE__))
inline void my_assert_failed(uint8_t* file, uint32_t line)
{
printf("file:%s\r\nline:%d",file,line);
}
typedef void (*VOID_FUNC)(void);
typedef struct RA
{
VOID_FUNC func;
uint32_t tickstart;//起始时间
uint32_t wait_ms;//等待时间
uint32_t cycle_index;//循环次数
}RA_st;
typedef struct IC
{
VOID_FUNC func;
uint32_t cycle_index;//循环次数
}IC_st;
typedef struct IC_Tab
{
IC_st **IC_table;
uint8_t tabsize;
uint8_t counter;//注册个数计数
}IC_Tab_st;
extern HAL_TickFreqTypeDef uwTickFreq;
int8_t Run_Aftertimer_creat(VOID_FUNC func,uint32_t wait_ms,uint8_t index,uint32_t cycle_index);
int8_t Run_Aftertimer_release(uint8_t index);
void RA_Task(void);
int8_t Interrupt_Callback_creat(IC_Tab_st *IC_Tab,VOID_FUNC func,uint8_t index,uint32_t cycle_index);
int8_t Interrupt_Callback_release(IC_Tab_st *IC_Tab,uint8_t index);
int8_t Interrupt_Callback_Tab_creat(IC_Tab_st *IC_Tab,uint8_t tabsize);
int8_t Interrupt_Callback_Tab_release(IC_Tab_st *IC_Tab);
void IC_Task(IC_Tab_st *IC_Tab);
#endif
sys.c
#include "sys.h"
#include <stdlib.h>
/*******************************Run_Aftertimer*********************************/
#define RA_TABLE_SIZE 5
RA_st *RA_table[RA_TABLE_SIZE]={NULL};
int8_t Run_Aftertimer_register(RA_st *ra,uint8_t index)
{
/*index为0时自动分配index*/
if(index==0)
{
for(int i=1;i<RA_TABLE_SIZE;i++)
{
if(RA_table[i]==NULL)
{
index=i;
}
if(i>=RA_TABLE_SIZE)
{
free(ra);
return -1;
}
}
}
if(RA_table[index]!=NULL)
{
free(ra);
return -1;
}
RA_table[index]=ra;
RA_table[index]->tickstart = HAL_GetTick();
/* Add a freq to guarantee minimum wait */
if (RA_table[index]->wait_ms < HAL_MAX_DELAY)
{
RA_table[index]->wait_ms += (uint32_t)(uwTickFreq);
}
return index;
}
int8_t Run_Aftertimer_creat(VOID_FUNC func,uint32_t wait_ms,uint8_t index,uint32_t cycle_index)
{
if(RA_table[index]!=NULL)
{
return -1;
}
RA_st *ra=malloc(sizeof(RA_st));
ra->func=func;
ra->wait_ms=wait_ms;
ra->cycle_index=cycle_index;
return Run_Aftertimer_register(ra,index);
}
int8_t Run_Aftertimer_release(uint8_t index)
{
__set_PRIMASK(1); /* 禁止全局中断*/
if(RA_table[index]==NULL)
{
__set_PRIMASK(0); /* 使能全局中断 */
return -1;
}
/*释放内存*/
free(RA_table[index]);
RA_table[index]=NULL;
__set_PRIMASK(0); /* 使能全局中断 */
return 0;
}
void RA_Task()
{
for(int i=1;i<RA_TABLE_SIZE;i++)
{
if(RA_table[i]==NULL)
continue;
if ((HAL_GetTick() - RA_table[i]->tickstart) >= RA_table[i]->wait_ms)
{
RA_table[i]->func();
if(RA_table[i]->cycle_index==1)
{
/*释放内存*/
free(RA_table[i]);
RA_table[i]=NULL;
continue;
}
RA_table[i]->tickstart = HAL_GetTick();
if(RA_table[i]->cycle_index!=0)
{
RA_table[i]->cycle_index--;
}
}
}
}
/*******************************中断任务*********************************/
int8_t Interrupt_Callback_register(IC_Tab_st *IC_Tab,IC_st *ic,uint8_t index)
{
/*错误判断*/
/*index为0时自动分配index*/
if(index==0)
{
for(int i=1;i<IC_Tab->tabsize;i++)
{
if(IC_Tab->IC_table[i]==NULL)
{
index=i;
}
if(i>=IC_Tab->tabsize)
{
free(ic);
return -1;
}
}
}
/*该位置已被使用*/
if(IC_Tab->IC_table[index]!=NULL)
{
free(ic);
return -1;
}
/*正文*/
IC_Tab->counter++;
IC_Tab->IC_table[index]=ic;
return index;
}
int8_t Interrupt_Callback_creat(IC_Tab_st *IC_Tab,VOID_FUNC func,uint8_t index,uint32_t cycle_index)
{
/*错误判断*/
/*Tab未创建*/
if(IC_Tab->IC_table==NULL)
{
return -1;
}
/*该位置已被使用*/
if(IC_Tab->IC_table[index]!=NULL)
{
return -1;
}
/*正文*/
IC_st *ic=malloc(sizeof(IC_st));
if(ic==NULL)return -1;
ic->func=func;
ic->cycle_index=cycle_index;
return Interrupt_Callback_register(IC_Tab,ic,index);
}
int8_t Interrupt_Callback_release(IC_Tab_st *IC_Tab,uint8_t index)
{
__set_PRIMASK(1); /* 禁止全局中断*/
/*错误判断*/
/*该位置为NULL不用释放*/
if(IC_Tab->IC_table[index]==NULL)
{
__set_PRIMASK(0); /* 使能全局中断 */
return -1;
}
/*index为0(不支持一次释放全部)*/
if(index==0)
{
__set_PRIMASK(0); /* 使能全局中断 */
return -1;
}
/*正文*/
/*释放内存*/
IC_Tab->counter--;
free(IC_Tab->IC_table[index]);
IC_Tab->IC_table[index]=NULL;
__set_PRIMASK(0); /* 使能全局中断 */
return 0;
}
int8_t Interrupt_Callback_Tab_creat(IC_Tab_st *IC_Tab,uint8_t tabsize)
{
/*错误判断*/
/*Tab已经创建*/
if(IC_Tab->IC_table!=NULL)
{
return -1;
}
/*tabsize不满足要求*/
if(tabsize==0)
{
return -1;
}
/*正文*/
tabsize+=1;
IC_Tab->tabsize=tabsize;
IC_Tab->IC_table=malloc(tabsize*sizeof(IC_st *));
if(IC_Tab==NULL)return -1;
return tabsize;
}
int8_t Interrupt_Callback_Tab_release(IC_Tab_st *IC_Tab)
{
__set_PRIMASK(1); /* 禁止全局中断*/
/*错误判断*/
/*未创建Tab或重复释放*/
if(IC_Tab->IC_table==NULL)
{
__set_PRIMASK(0); /* 使能全局中断 */
return -1;
}
/*Tab中还有未释放的项目*/
if(IC_Tab->counter!=0)
{
__set_PRIMASK(0); /* 使能全局中断 */
return -1;
}
/*正文*/
/*释放内存*/
free(IC_Tab->IC_table);
IC_Tab->IC_table=NULL;
IC_Tab->tabsize=0;
__set_PRIMASK(0); /* 使能全局中断 */
return 0;
}
void IC_Task(IC_Tab_st *IC_Tab)
{
for(int i=1;i<IC_Tab->tabsize;i++)
{
if(IC_Tab->IC_table[i]==NULL)
continue;
IC_Tab->IC_table[i]->func();
if(IC_Tab->IC_table[i]->cycle_index==1)
{
/*释放内存*/
free(IC_Tab->IC_table[i]);
IC_Tab->IC_table[i]=NULL;
continue;
}
if(IC_Tab->IC_table[i]->cycle_index!=0)
{
IC_Tab->IC_table[i]->cycle_index--;
}
}
}
debug.h
#ifndef _DEBUG_H
#define _DEBUG_H
#include "stdio.h"
#include "stm32f1xx.h"
#include "main.h"
#include "usart.h"
/**
* @brief DEBUG 常量文本索引
*/
enum DEBUG
{
DEBUG_TEXT_INFO, /* debug信息 */
DEBUG_TEXT_CMD_TOO_LONG, /* 命令过长 */
DEBUG_TEXT_BACK, /* 退格 */
DEBUG_TEXT_INPUT_HEAD, /* 输入前置打印 */
DEBUG_TEXT_HELP, /* help 命令打印 */
DEBUG_TEXT_CMD_UNKNOWN, /* 未知命令类型 */
};
extern uint8_t byTmpData;
extern const char *pDebugText[];
void debug_analyze(void);
#endif /* DEBUG_H */
debug.c
#include "debug.h"
#include "string.h"
#define DEBUG_BUFF_SIZE 36
uint8_t byDebugBuff[DEBUG_BUFF_SIZE];
uint8_t byTmpData;
static uint8_t byCurrentDebugCursor = 0;
int dwTmpPara[6];
int i;
const char *pDebugText[] =
{
// [DEBUG_TEXT_INFO] =
"\r\n======================================================================"
"\r\n= (C) COPYRIGHT 2020 STMicroelectronics ="
"\r\n= ="
"\r\n= STM32F4xx Application For Motion (Version xxxxx) ="
"\r\n= ="
"\r\n= By Alight Team ="
"\r\n======================================================================\r\n",
// [DEBUG_TEXT_CMD_TOO_LONG] =
"\r\nCommand is too long\r\n",
// [DEBUG_TEXT_BACK] =
"\b \b",
// [DEBUG_TEXT_INPUT_HEAD] =
">",
// [DEBUG_TEXT_HELP] =
"\r\nCommand List :"
"\r\nreboot reset mcu"
"\r\nsm step motor control(speed angle break)"
"\r\npm push motor control(speed time break)"
"\r\nhelp show command info\r\n",
// [DEBUG_TEXT_CMD_UNKNOWN] =
"\r\nCommand unknown\r\n"
};
/*
*********************************************************************************************************
* 函 数 名: debug_analyze
* 功能说明: DEBUG数据解析
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void debug_analyze(void)
{
if('\b' == byTmpData)
{
if(byCurrentDebugCursor <= 0)
{
byCurrentDebugCursor = 0;
}
else
{
printf("%s", pDebugText[DEBUG_TEXT_BACK]);
byCurrentDebugCursor--;
}
return;
}
if('\r' == byTmpData || '\n' == byTmpData)
{
byDebugBuff[byCurrentDebugCursor] = '\0';
if(0 == byCurrentDebugCursor)
{
printf("\r\n");
}
else if(strcmp("reboot", (const char *)byDebugBuff) == 0)
{
HAL_NVIC_SystemReset();
printf("\r\nreset mcu\r\n");
}
else if(strncmp("sm", (const char *)byDebugBuff,strlen("sm")) == 0)
{
sscanf((const char *)byDebugBuff, "sm %d %d %d",&dwTmpPara[0],&dwTmpPara[1],&dwTmpPara[2]);
printf("\r\n%d,%d,%d\r\n",dwTmpPara[0],dwTmpPara[1],dwTmpPara[2]);
}
else if(strcmp("help", (const char *)byDebugBuff) == 0)
{
printf("%s",pDebugText[DEBUG_TEXT_HELP]);
}
else
{
printf("%s",pDebugText[DEBUG_TEXT_CMD_UNKNOWN]);
}
byCurrentDebugCursor = 0;
printf("%s", pDebugText[DEBUG_TEXT_INPUT_HEAD]);
}
else
{
HAL_UART_Transmit(&huart1,&byTmpData,1,0xff);
byDebugBuff[byCurrentDebugCursor] = byTmpData;
byCurrentDebugCursor++;
if(byCurrentDebugCursor >= DEBUG_BUFF_SIZE)
{
byCurrentDebugCursor = 0;
printf("%s", pDebugText[DEBUG_TEXT_CMD_TOO_LONG]);
printf("%s", pDebugText[DEBUG_TEXT_INPUT_HEAD]);
}
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
UNUSED(huart);
debug_analyze();
HAL_UART_Receive_IT(&huart1,&byTmpData,1);
}
/*添加了GNU extensions后会默认定义__GNUC__,使得printf不正确,所以这里去掉该定义*/
#undef __GNUC__
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
app.h
#ifndef __APP_H__
#define __APP_H__
#include "stm32f1xx.h"
#include "stm32f1xx_hal.h"
#include "sys.h"
#include "list.h"
#include "timer.h"
#define READ 0
#define WRITE 1
#define IS_GPOUP(__GROUP__) ((__GROUP__>GROUP_BEGIN)&&(__GROUP__<GROUP_END))
#define IS_TIMING_TYPE(__TYPE__) ((__TYPE__>TIMING_TYPE_BEGIN)&&(__TYPE__<TIMING_TYPE_END))
#define IS_REMIND_TYPE(__TYPE__) ((__TYPE__>REMIND_TYPE_BEGIN)&&(__TYPE__<REMIND_TYPE_END))
/*分组*/
enum group
{
GROUP_BEGIN,
STUDY,
WORK,
DRINK,
PILLS, //吃药
GROUP_END
};
/*闹钟类型*/
enum timing_type
{
TIMING_TYPE_BEGIN,
ONCE, //只响一次
CYCLE_DAY, //每天循环
TIMING_TYPE_END
};
/*提醒类型*/
enum remind_type
{
REMIND_TYPE_BEGIN,
DEBUG,
BEEP,
REMIND_TYPE_END
};
struct alarm
{
struct timer_list timer;
enum timing_type ttype;
enum remind_type rtype;
char *info;
struct list_head node;
};
/*时间段*/
struct time_area
{
uint32_t start;
uint32_t end;
};
/*循环模式数据结构*/
struct cycle
{
uint32_t cycle; //循环周期
uint32_t cnt; //循环内部计数值
struct time_area ta;
};
struct tobject
{
enum group group;
enum timing_type type;
uint32_t moment;
struct cycle cycle;
struct list_head node;
};
#endif
app.c
#include "app.h"
#include "stdlib.h"
#include "string.h"
#define DEFAULT_GROUP STUDY
#define DEFAULT_TYPE MOMENT
#define DEFAULT_MOMENT 10
#define DEFAULT_CYCLE 10
LIST_HEAD(alarm_list);
static void alarm_timer_handler(unsigned long data)
{
struct alarm *alm=(struct alarm *)data;
switch((uint8_t)alm->rtype)
{
case DEBUG:
printf("%s\r\n",alm->info);
break;
case BEEP:
break;
}
switch((uint8_t)alm->ttype)
{
case CYCLE_DAY:
mod_timer(&(alm->timer),jiffies + 24*60*60*HZ);
break;
}
}
int alarm_creat(enum remind_type rtype,enum timing_type ttype,char *info)
{
struct alarm *alm;
my_assert_param(IS_TIMING_TYPE(ttype));
alm=malloc(sizeof(struct alarm));
if(alm==NULL)return -1;
alm->rtype=rtype;
alm->ttype=ttype;
alm->info=info;
init_timer(&(alm->timer));
alm->timer.function = alarm_timer_handler;
alm->timer.expires = jiffies + HZ;
alm->timer.data=(unsigned long)alm;
add_timer(&(alm->timer));
list_add_tail(&(alm->node),&(alarm_list));
}
void alarm_delete(struct alarm *alm)
{
del_timer(&(alm->timer));
list_del(&(alm->node));
free(alm);
}
void alarm_setup(struct alarm *alm)
{
}
timer.h
#ifndef _LINUX_TIMER_H
#define _LINUX_TIMER_H
#include "list.h"
#include "typecheck.h"
#include "stm32f1xx.h"
#include "stm32f1xx_hal.h"
#define HZ 100
#define time_after(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)(b) - (long)(a) < 0))
#define time_before(a,b) time_after(b,a)
#define time_after_eq(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)(a) - (long)(b) >= 0))
#define time_before_eq(a,b) time_after_eq(b,a)
#define INDEX(N) ((base->timer_jiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK)
#define CONFIG_BASE_SMALL 0
#define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6)
#define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 8)
#define TVN_SIZE (1 << TVN_BITS)
#define TVR_SIZE (1 << TVR_BITS)
#define TVN_MASK (TVN_SIZE - 1)
#define TVR_MASK (TVR_SIZE - 1)
struct timer_list {
struct list_head entry;//用于把一组定时器组成一个链表
unsigned long expires;//指出了该定时器的到期时刻,也就是期望定时器到期时刻的jiffies计数值
struct tvec_base *base;//每个cpu拥有一个自己的用于管理定时器的tvec_base结构,该字段指向该定时器所属的cpu所对应tvec_base结构
void (*function)(unsigned long);//指向一个可执行函数。当定时器到期时,内核就执行function所指定的函数
unsigned long data;//data域则被内核用作function函数的调用参数
};
struct tvec {
struct list_head vec[TVN_SIZE];
};
struct tvec_root {
struct list_head vec[TVR_SIZE];
};
struct tvec_base {
//spinlock_t lock;
struct timer_list *running_timer;//指向当前cpu正在处理的定时器所对应的timer_list结构
unsigned long timer_jiffies;//表示当前cpu定时器所经历过的jiffies数,大多数情况下,该值和jiffies计数值相等,当cpu的idle状态连续持续了多个jiffies时间时,当退出idle状态时,jiffies计数值就会大于该字段,在接下来的tick中断后,定时器系统会让该字段的值追赶上jiffies值
unsigned long next_timer;//指向该cpu下一个即将到期的定时器
struct tvec_root tv1;
struct tvec tv2;
struct tvec tv3;
struct tvec tv4;
struct tvec tv5;
};
#define TIMER_INITIALIZER(_function, _expires, _data) {.entry = { .prev = NULL },.function = _function,.expires = _expires,.data = _data,.base = &timer_base}
#define DEFINE_TIMER(_name, _function, _expires, _data) struct timer_list _name = TIMER_INITIALIZER(_function, _expires, _data)
static inline void set_running_timer(struct tvec_base *base,
struct timer_list *timer)
{
base->running_timer = timer;
}
static inline void detach_timer(struct timer_list *timer,
int clear_pending)
{
struct list_head *entry = &timer->entry;
//debug_deactivate(timer);
__list_del(entry->prev, entry->next);
if (clear_pending)
entry->next = NULL;
entry->prev = LIST_POISON2;
}
#define jiffies *pjiffies
extern unsigned long jiffies;
extern uint64_t jiffies_64;
extern uint32_t sys_start_rtc_time;
extern struct tvec_base timer_base;
void init_timers(void);
void timer_update(struct tvec_base *base);
#define init_timer(timer)\
init_timer_key((timer), NULL)
void init_timer_key(struct timer_list *timer,
const char *name);
int mod_timer(struct timer_list *timer, unsigned long expires);
void add_timer(struct timer_list *timer);
int del_timer(struct timer_list * timer);
static inline void setup_timer_key(struct timer_list * timer,
const char *name,
void (*function)(unsigned long),
unsigned long data)
{
timer->function = function;
timer->data = data;
init_timer_key(timer, name);
}
#define setup_timer(timer, fn, data)\
setup_timer_key((timer), NULL, (fn), (data))
#endif
timer.c
/*默认情况下,没有使能CONFIG_BASE_SMALL,TVR_SIZE的大小是256,TVN_SIZE的大小则是64,当需要节省内存空间时,也可以使能CONFIG_BASE_SMALL,这时TVR_SIZE的大小是64,TVN_SIZE的大小则是16,以下的讨论我都是基于没有使能CONFIG_BASE_SMALL的情况。当有一个新的定时器要加入时,系统根据定时器到期的jiffies值和timer_jiffies字段的差值来决定该定时器被放入tv1至tv5中的哪一个数组中*/
#include "timer.h"
#include "rtc.h"
#ifndef __ARMEB__
unsigned long *pjiffies=((unsigned long *)(&jiffies_64));
#else
unsigned long *pjiffies=((unsigned long *)(&jiffies_64))+4;
#endif
uint64_t jiffies_64=0;
struct tvec_base timer_base;
uint32_t sys_start_rtc_time;
static struct timer_list rtc_timer;
/**
* @brief Read the time counter available in RTC_CNT registers.
* @param hrtc pointer to a RTC_HandleTypeDef structure that contains
* the configuration information for RTC.
* @retval Time counter
*/
static uint32_t RTC_ReadTimeCounter(RTC_HandleTypeDef* hrtc)
{
uint16_t high1 = 0U, high2 = 0U, low = 0U;
uint32_t timecounter = 0U;
high1 = READ_REG(hrtc->Instance->CNTH & RTC_CNTH_RTC_CNT);
low = READ_REG(hrtc->Instance->CNTL & RTC_CNTL_RTC_CNT);
high2 = READ_REG(hrtc->Instance->CNTH & RTC_CNTH_RTC_CNT);
if (high1 != high2)
{ /* In this case the counter roll over during reading of CNTL and CNTH registers,
read again CNTL register then return the counter value */
timecounter = (((uint32_t) high2 << 16U) | READ_REG(hrtc->Instance->CNTL & RTC_CNTL_RTC_CNT));
}
else
{ /* No counter roll over during reading of CNTL and CNTH registers, counter
value is equal to first value of CNTL and CNTH */
timecounter = (((uint32_t) high1 << 16U) | low);
}
return timecounter;
}
void init_timers()
{
//读取RTC
sys_start_rtc_time=RTC_ReadTimeCounter(&hrtc);
for(int i=0;i<TVR_SIZE;i++)
{
INIT_LIST_HEAD(&(timer_base.tv1.vec[i]));
}
for(int i=0;i<TVN_SIZE;i++)
{
INIT_LIST_HEAD(&(timer_base.tv2.vec[i]));
}
for(int i=0;i<TVN_SIZE;i++)
{
INIT_LIST_HEAD(&(timer_base.tv3.vec[i]));
}
for(int i=0;i<TVN_SIZE;i++)
{
INIT_LIST_HEAD(&(timer_base.tv4.vec[i]));
}
for(int i=0;i<TVN_SIZE;i++)
{
INIT_LIST_HEAD(&(timer_base.tv5.vec[i]));
}
}
static void call_timer_fn(struct timer_list *timer, void (*fn)(unsigned long),
unsigned long data)
{
fn(data);
}
//确定要插入的链表数组以及数组的哪一项链表中
static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
{
unsigned long expires = timer->expires;
unsigned long idx = expires - base->timer_jiffies;//也即timer->expires-base->timer_jiffies,差值范围可以大致判断属于哪一个分组
struct list_head *vec;
if (idx < TVR_SIZE) { //tv1
int i = expires & TVR_MASK;
vec = base->tv1.vec + i;
} else if (idx < 1 << (TVR_BITS + TVN_BITS)) { //tv2
int i = (expires >> TVR_BITS) & TVN_MASK;
vec = base->tv2.vec + i;
} else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) { //tv3
int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
vec = base->tv3.vec + i;
} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) { //tv4
int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
vec = base->tv4.vec + i;
} else if ((signed long) idx < 0) {//异常处理,随机取了一个0~255之间的数值
/*
* Can happen if you add a timer with expires == jiffies,
* or you set a timer to go off in the past
*/
vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK);
} else {
int i;
/* If the timeout is larger than 0xffffffff on 64-bit
* architectures then we use the maximum timeout:
*/
if (idx > 0xffffffffUL) {
idx = 0xffffffffUL;
expires = idx + base->timer_jiffies;
}
i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
vec = base->tv5.vec + i; //tv5
}
/*
* Timers are FIFO:
*/
list_add_tail(&timer->entry, vec);//相同vec的timer采取FIFO策略
}
//定时器的到期时的迁移代码
//参数index为事先计算好的高一级tv的需要迁移的数组索引
static int cascade(struct tvec_base *base, struct tvec *tv, int index)
{
/* cascade all the timers from tv up one level */
struct timer_list *timer, *tmp;
struct list_head tv_list;
list_replace_init(tv->vec + index, &tv_list);//用tv_list替换tv->vec+index表头,将tv->vec+index重新初始化,即为空,链表不会有timer存在。
/*
* We are removing _all_ timers from the list, so we
* don't have to detach them individually.
*/
list_for_each_entry_safe(timer, tmp, &tv_list, entry) {//遍历刚取出的tv_list里的timer
//BUG_ON(tbase_get_base(timer->base) != base);
internal_add_timer(base, timer);//重新加入到定时器系统中,实际上将会迁移到下一级的tv数组中
}
return index;
}
static inline void __run_timers(struct tvec_base *base)
{
struct timer_list *timer;
//spin_lock_irq(&base->lock);
while (time_after_eq(jiffies, base->timer_jiffies)) {//同步jiffies,在NO_HZ情况下,base->timer_jiffies可能落后不止一个tick
struct list_head work_list;
struct list_head *head = &work_list;
int index = base->timer_jiffies & TVR_MASK;//计算到期定时器链表在tv1中的索引
/*
* Cascade timers:
*/
if (!index && //index为0时,表示有进位到tv2
(!cascade(base, &(base->tv2), INDEX(0))) && //返回为0时,表示有进位到tv3
(!cascade(base, &(base->tv3), INDEX(1))) && //返回为0时,表示有进位到tv4
!cascade(base, &(base->tv4), INDEX(2))) //返回为0时,表示有进位到tv5
cascade(base, &(base->tv5), INDEX(3)); //从低位到高位逐级进位的迁移,在进位时将高位timer_list插入到低位
++base->timer_jiffies;//该cpu定时器系统运行时间递增一个tick
list_replace_init(base->tv1.vec + index, &work_list);//取出到期的定时器链表
while (!list_empty(head)) {//遍历所有的到期定时器
void (*fn)(unsigned long);
unsigned long data;
timer = list_first_entry(head, struct timer_list,entry);
fn = timer->function;
data = timer->data;
set_running_timer(base, timer);//标记正在处理的定时器
detach_timer(timer, 1);
//spin_unlock_irq(&base->lock);
call_timer_fn(timer, fn, data);//调用定时器的回调函数
//spin_lock_irq(&base->lock);
}
}
set_running_timer(base, NULL);
//spin_unlock_irq(&base->lock);
}
void timer_update(struct tvec_base *base)
{
if (time_after_eq(jiffies, base->timer_jiffies))
__run_timers(base);
}
static void __init_timer(struct timer_list *timer,
const char *name)
{
timer->entry.next = NULL;
timer->base = &timer_base;
}
void init_timer_key(struct timer_list *timer,
const char *name)
{
__init_timer(timer, name);
}
static inline int timer_pending(const struct timer_list * timer)
{
return timer->entry.next != NULL;
}
static inline int
__mod_timer(struct timer_list *timer, unsigned long expires)
{
struct tvec_base *base;
int ret = 0;
base=timer->base;
if (timer_pending(timer)) {
detach_timer(timer, 0);
if (timer->expires == base->next_timer)
base->next_timer = base->timer_jiffies;
ret = 1;
} else {}
timer->expires = expires;
if (time_before(timer->expires, base->next_timer))
base->next_timer = timer->expires;
internal_add_timer(base, timer);
return ret;
}
int mod_timer(struct timer_list *timer, unsigned long expires)
{
/*
* This is a common optimization triggered by the
* networking code - if the timer is re-modified
* to be the same thing then just return:
*/
if (timer_pending(timer) && timer->expires == expires)
return 1;
return __mod_timer(timer, expires);
}
void add_timer(struct timer_list *timer)
{
mod_timer(timer, timer->expires);
}
/**
* del_timer - deactive a timer.
* @timer: the timer to be deactivated
*
* del_timer() deactivates a timer - this works on both active and inactive
* timers.
*
* The function returns whether it has deactivated a pending timer or not.
* (ie. del_timer() of an inactive timer returns 0, del_timer() of an
* active timer returns 1.)
*/
int del_timer(struct timer_list *timer)
{
struct tvec_base *base;
int ret = 0;
if (timer_pending(timer)) {
detach_timer(timer, 1);
if (timer->expires == base->next_timer)
base->next_timer = base->timer_jiffies;
ret = 1;
}
return ret;
}
list.h
/*此代码移植自linux kernel*/
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
#include "mytype.h"
#include "stm32f1xx.h"
#include "stm32f1xx_hal.h"
#define LIST_POISON1 NULL
#define LIST_POISON2 NULL
#define prefetch(x) x
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
#ifndef CONFIG_DEBUG_LIST
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
#else
extern void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next);
#endif
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/
#ifndef CONFIG_DEBUG_LIST
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
#else
extern void list_del(struct list_head *entry);
#endif
/**
* list_replace - replace old entry by new one
* @old : the element to be replaced
* @new : the new element to insert
*
* If @old was empty, it will be overwritten.
*/
static inline void list_replace(struct list_head *old,
struct list_head *new)
{
new->next = old->next;
new->next->prev = new;
new->prev = old->prev;
new->prev->next = new;
}
static inline void list_replace_init(struct list_head *old,
struct list_head *new)
{
list_replace(old, new);
INIT_LIST_HEAD(old);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_move - delete from one list and add as another's head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del(list->prev, list->next);
list_add(list, head);
}
/**
* list_move_tail - delete from one list and add as another's tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add_tail(list, head);
}
/**
* list_is_last - tests whether @list is the last entry in list @head
* @list: the entry to test
* @head: the head of the list
*/
static inline int list_is_last(const struct list_head *list,
const struct list_head *head)
{
return list->next == head;
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
/**
* list_empty_careful - tests whether a list is empty and not being modified
* @head: the list to test
*
* Description:
* tests whether a list is empty _and_ checks that no other CPU might be
* in the process of modifying either member (next or prev)
*
* NOTE: using list_empty_careful() without synchronization
* can only be safe if the only activity that can happen
* to the list entry is list_del_init(). Eg. it cannot be used
* if another CPU could re-list_add() it.
*/
static inline int list_empty_careful(const struct list_head *head)
{
struct list_head *next = head->next;
return (next == head) && (next == head->prev);
}
/**
* list_rotate_left - rotate the list to the left
* @head: the head of the list
*/
static inline void list_rotate_left(struct list_head *head)
{
struct list_head *first;
if (!list_empty(head)) {
first = head->next;
list_move_tail(first, head);
}
}
/**
* list_is_singular - tests whether a list has just one entry.
* @head: the list to test.
*/
static inline int list_is_singular(const struct list_head *head)
{
return !list_empty(head) && (head->next == head->prev);
}
static inline void __list_cut_position(struct list_head *list,
struct list_head *head, struct list_head *entry)
{
struct list_head *new_first = entry->next;
list->next = head->next;
list->next->prev = list;
list->prev = entry;
entry->next = list;
head->next = new_first;
new_first->prev = head;
}
/**
* list_cut_position - cut a list into two
* @list: a new list to add all removed entries
* @head: a list with entries
* @entry: an entry within head, could be the head itself
* and if so we won't cut the list
*
* This helper moves the initial part of @head, up to and
* including @entry, from @head to @list. You should
* pass on @entry an element you know is on @head. @list
* should be an empty list or a list you do not care about
* losing its data.
*
*/
static inline void list_cut_position(struct list_head *list,
struct list_head *head, struct list_head *entry)
{
if (list_empty(head))
return;
if (list_is_singular(head) &&
(head->next != entry && head != entry))
return;
if (entry == head)
INIT_LIST_HEAD(list);
else
__list_cut_position(list, head, entry);
}
static inline void __list_splice(const struct list_head *list,
struct list_head *prev,
struct list_head *next)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
first->prev = prev;
prev->next = first;
last->next = next;
next->prev = last;
}
/**
* list_splice - join two lists, this is designed for stacks
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void list_splice(const struct list_head *list,
struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head, head->next);
}
/**
* list_splice_tail - join two lists, each list being a queue
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void list_splice_tail(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head->prev, head);
}
/**
* list_splice_init - join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static inline void list_splice_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head, head->next);
INIT_LIST_HEAD(list);
}
}
/**
* list_splice_tail_init - join two lists and reinitialise the emptied list
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* Each of the lists is a queue.
* The list at @list is reinitialised
*/
static inline void list_splice_tail_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head->prev, head);
INIT_LIST_HEAD(list);
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* list_first_entry - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
pos = pos->next)
/**
* __list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*
* This variant differs from list_for_each() in that it's the
* simplest possible list iteration code, no prefetching is done.
* Use this for code that knows the list to be very short (empty
* or 1 entry) most of the time.
*/
#define __list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* list_for_each_prev - iterate over a list backwards
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*/
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
pos = pos->prev)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop cursor.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
* @pos: the &struct list_head to use as a loop cursor.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_prev_safe(pos, n, head) \
for (pos = (head)->prev, n = pos->prev; \
prefetch(pos->prev), pos != (head); \
pos = n, n = pos->prev)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_reverse - iterate backwards over list of given type.
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member); \
prefetch(pos->member.prev), &pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
/**
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
* @pos: the type * to use as a start point
* @head: the head of the list
* @member: the name of the list_struct within the struct.
*
* Prepares a pos entry for use as a start point in list_for_each_entry_continue().
*/
#define list_prepare_entry(pos, head, member) \
((pos) ? : list_entry(head, typeof(*pos), member))
/**
* list_for_each_entry_continue - continue iteration over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* Continue to iterate over list of given type, continuing after
* the current position.
*/
#define list_for_each_entry_continue(pos, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_continue_reverse - iterate backwards from the given point
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* Start to iterate over list of given type backwards, continuing after
* the current position.
*/
#define list_for_each_entry_continue_reverse(pos, head, member) \
for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
prefetch(pos->member.prev), &pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
/**
* list_for_each_entry_from - iterate over list of given type from the current point
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* Iterate over list of given type, continuing from current position.
*/
#define list_for_each_entry_from(pos, head, member) \
for (; prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
* list_for_each_entry_safe_continue - continue list iteration safe against removal
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* Iterate over list of given type, continuing after current point,
* safe against removal of list entry.
*/
#define list_for_each_entry_safe_continue(pos, n, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
* list_for_each_entry_safe_from - iterate over list from current point safe against removal
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* Iterate over list of given type from current point, safe against
* removal of list entry.
*/
#define list_for_each_entry_safe_from(pos, n, head, member) \
for (n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
* list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* Iterate backwards over list of given type, safe against removal
* of list entry.
*/
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member), \
n = list_entry(pos->member.prev, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
/**
* list_safe_reset_next - reset a stale list_for_each_entry_safe loop
* @pos: the loop cursor used in the list_for_each_entry_safe loop
* @n: temporary storage used in list_for_each_entry_safe
* @member: the name of the list_struct within the struct.
*
* list_safe_reset_next is not safe to use in general if the list may be
* modified concurrently (eg. the lock is dropped in the loop body). An
* exception to this is if the cursor element (pos) is pinned in the list,
* and list_safe_reset_next is called after re-taking the lock and before
* completing the current iteration of the loop body.
*/
#define list_safe_reset_next(pos, n, member) \
n = list_entry(pos->member.next, typeof(*pos), member)
/*
* Double linked lists with a single pointer list head.
* Mostly useful for hash tables where the two pointer list head is
* too wasteful.
* You lose the ability to access the tail in O(1).
*/
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next, **pprev;
};
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
h->next = NULL;
h->pprev = NULL;
}
static inline int hlist_unhashed(const struct hlist_node *h)
{
return !h->pprev;
}
static inline int hlist_empty(const struct hlist_head *h)
{
return !h->first;
}
static inline void __hlist_del(struct hlist_node *n)
{
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
*pprev = next;
if (next)
next->pprev = pprev;
}
static inline void hlist_del(struct hlist_node *n)
{
__hlist_del(n);
n->next = LIST_POISON1;
n->pprev = LIST_POISON2;
}
static inline void hlist_del_init(struct hlist_node *n)
{
if (!hlist_unhashed(n)) {
__hlist_del(n);
INIT_HLIST_NODE(n);
}
}
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
h->first = n;
n->pprev = &h->first;
}
/* next must be != NULL */
static inline void hlist_add_before(struct hlist_node *n,
struct hlist_node *next)
{
n->pprev = next->pprev;
n->next = next;
next->pprev = &n->next;
*(n->pprev) = n;
}
static inline void hlist_add_after(struct hlist_node *n,
struct hlist_node *next)
{
next->next = n->next;
n->next = next;
next->pprev = &n->next;
if(next->next)
next->next->pprev = &next->next;
}
/*
* Move a list from one list head to another. Fixup the pprev
* reference of the first entry if it exists.
*/
static inline void hlist_move_list(struct hlist_head *old,
struct hlist_head *new)
{
new->first = old->first;
if (new->first)
new->first->pprev = &new->first;
old->first = NULL;
}
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_for_each(pos, head) \
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
pos = pos->next)
#define hlist_for_each_safe(pos, n, head) \
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
pos = n)
/**
* hlist_for_each_entry - iterate over list of given type
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry(tpos, pos, head, member) \
for (pos = (head)->first; \
pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_continue(tpos, pos, member) \
for (pos = (pos)->next; \
pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_from - iterate over a hlist continuing from current point
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_from(tpos, pos, member) \
for (; pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @n: another &struct hlist_node to use as temporary storage
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
for (pos = (head)->first; \
pos && ({ n = pos->next; 1; }) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = n)
#endif
mytype.h
#ifndef __MYTYPE_H__
#define __MYTYPE_H__
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif
typecheck.h
#ifndef TYPECHECK_H_INCLUDED
#define TYPECHECK_H_INCLUDED
/*
* Check at compile time that something is of a particular type.
* Always evaluates to 1 so you may use it easily in comparisons.
*/
#define typecheck(type,x) \
({ type __dummy; \
typeof(x) __dummy2; \
(void)(&__dummy == &__dummy2); \
1; \
})
/*
* Check at compile time that 'function' is a certain type, or is a pointer
* to that type (needs to use typedef for the function type.)
*/
#define typecheck_fn(type,function) \
({ typeof(type) __tmp = function; \
(void)__tmp; \
})
#endif /* TYPECHECK_H_INCLUDED */