#![allow(unused_variables)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(dead_code)]
#![allow(static_mut_refs)]
use core::ffi::c_void;
use core::ptr;
use crate::config::*;
use crate::kernel::list::*;
use crate::kernel::queue::*;
use crate::kernel::tasks::*;
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
use crate::memory::{pvPortMalloc, vPortFree};
use crate::types::*;
use crate::{
traceENTER_pcTimerGetName, traceENTER_pvTimerGetTimerID, traceENTER_uxTimerGetReloadMode,
traceENTER_vTimerSetReloadMode, traceENTER_vTimerSetTimerID, traceENTER_xTimerCreateStatic,
traceENTER_xTimerCreateTimerTask, traceENTER_xTimerGenericCommandFromISR,
traceENTER_xTimerGenericCommandFromTask, traceENTER_xTimerGetExpiryTime,
traceENTER_xTimerGetPeriod, traceENTER_xTimerGetReloadMode, traceENTER_xTimerGetStaticBuffer,
traceENTER_xTimerGetTimerDaemonTaskHandle, traceENTER_xTimerIsTimerActive,
traceRETURN_pcTimerGetName, traceRETURN_pvTimerGetTimerID, traceRETURN_uxTimerGetReloadMode,
traceRETURN_vTimerSetReloadMode, traceRETURN_vTimerSetTimerID, traceRETURN_xTimerCreateStatic,
traceRETURN_xTimerCreateTimerTask, traceRETURN_xTimerGenericCommandFromISR,
traceRETURN_xTimerGenericCommandFromTask, traceRETURN_xTimerGetExpiryTime,
traceRETURN_xTimerGetPeriod, traceRETURN_xTimerGetReloadMode,
traceRETURN_xTimerGetStaticBuffer, traceRETURN_xTimerGetTimerDaemonTaskHandle,
traceRETURN_xTimerIsTimerActive, traceTIMER_COMMAND_RECEIVED, traceTIMER_COMMAND_SEND,
traceTIMER_CREATE, traceTIMER_EXPIRED,
};
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
use crate::{traceENTER_xTimerCreate, traceRETURN_xTimerCreate};
#[cfg(feature = "trace-facility")]
use crate::{
traceENTER_uxTimerGetTimerNumber, traceENTER_vTimerSetTimerNumber,
traceRETURN_uxTimerGetTimerNumber, traceRETURN_vTimerSetTimerNumber,
};
#[cfg(feature = "pend-function-call")]
use crate::{
traceENTER_xTimerPendFunctionCall, traceENTER_xTimerPendFunctionCallFromISR,
tracePEND_FUNC_CALL, tracePEND_FUNC_CALL_FROM_ISR, traceRETURN_xTimerPendFunctionCall,
traceRETURN_xTimerPendFunctionCallFromISR,
};
const tmrNO_DELAY: TickType_t = 0;
const tmrMAX_TIME_BEFORE_OVERFLOW: TickType_t = !0;
pub const configTIMER_SERVICE_TASK_NAME: &[u8] = b"Tmr Svc\0";
const tmrSTATUS_IS_ACTIVE: u8 = 0x01;
const tmrSTATUS_IS_STATICALLY_ALLOCATED: u8 = 0x02;
const tmrSTATUS_IS_AUTORELOAD: u8 = 0x04;
pub const tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR: BaseType_t = -2;
pub const tmrCOMMAND_EXECUTE_CALLBACK: BaseType_t = -1;
pub const tmrCOMMAND_START_DONT_TRACE: BaseType_t = 0;
pub const tmrCOMMAND_START: BaseType_t = 1;
pub const tmrCOMMAND_RESET: BaseType_t = 2;
pub const tmrCOMMAND_STOP: BaseType_t = 3;
pub const tmrCOMMAND_CHANGE_PERIOD: BaseType_t = 4;
pub const tmrCOMMAND_DELETE: BaseType_t = 5;
pub const tmrFIRST_FROM_ISR_COMMAND: BaseType_t = 6;
pub const tmrCOMMAND_START_FROM_ISR: BaseType_t = 6;
pub const tmrCOMMAND_RESET_FROM_ISR: BaseType_t = 7;
pub const tmrCOMMAND_STOP_FROM_ISR: BaseType_t = 8;
pub const tmrCOMMAND_CHANGE_PERIOD_FROM_ISR: BaseType_t = 9;
pub type TimerCallbackFunction_t = unsafe extern "C" fn(TimerHandle_t);
#[cfg(feature = "tick-64bit")]
pub type PendedFunctionParameter_t = u64;
#[cfg(not(feature = "tick-64bit"))]
pub type PendedFunctionParameter_t = u32;
pub type PendedFunction_t = unsafe extern "C" fn(*mut c_void, PendedFunctionParameter_t);
const _: () = assert!(
core::mem::size_of::<PendedFunctionParameter_t>() >= core::mem::size_of::<TickType_t>()
);
#[repr(C)]
pub struct xTIMER {
pub pcTimerName: *const u8,
pub xTimerListItem: ListItem_t,
pub xTimerPeriodInTicks: TickType_t,
pub pvTimerID: *mut c_void,
pub pxCallbackFunction: TimerCallbackFunction_t,
#[cfg(feature = "trace-facility")]
pub uxTimerNumber: UBaseType_t,
pub ucStatus: u8,
}
pub type Timer_t = xTIMER;
#[repr(C)]
#[derive(Clone, Copy)]
pub struct TimerParameter_t {
pub xMessageValue: TickType_t,
pub pxTimer: *mut Timer_t,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CallbackParameters_t {
pub pxCallbackFunction: PendedFunction_t,
pub pvParameter1: *mut c_void,
pub ulParameter2: PendedFunctionParameter_t,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub union DaemonTaskMessageUnion {
pub xTimerParameters: TimerParameter_t,
#[cfg(feature = "pend-function-call")]
pub xCallbackParameters: CallbackParameters_t,
}
#[repr(C)]
pub struct DaemonTaskMessage_t {
pub xMessageID: BaseType_t,
pub u: DaemonTaskMessageUnion,
}
#[repr(transparent)]
pub struct StaticTimer_t {
_storage: core::mem::MaybeUninit<Timer_t>,
}
impl StaticTimer_t {
pub const fn new() -> Self {
Self {
_storage: core::mem::MaybeUninit::uninit(),
}
}
}
const _: () = assert!(core::mem::size_of::<StaticTimer_t>() == core::mem::size_of::<Timer_t>());
const _: () = assert!(core::mem::align_of::<StaticTimer_t>() == core::mem::align_of::<Timer_t>());
static mut xActiveTimerList1: List_t = List_t::new();
static mut xActiveTimerList2: List_t = List_t::new();
static mut pxCurrentTimerList: *mut List_t = ptr::null_mut();
static mut pxOverflowTimerList: *mut List_t = ptr::null_mut();
static mut xTimerQueue: QueueHandle_t = ptr::null_mut();
static mut xTimerTaskHandle: TaskHandle_t = ptr::null_mut();
static mut pxTimerTaskTCBBuffer: *mut StaticTask_t = ptr::null_mut();
static mut pxTimerTaskStackBuffer: *mut StackType_t = ptr::null_mut();
static mut uxTimerTaskStackSize: configSTACK_DEPTH_TYPE = 0;
static mut xStaticTimerQueue: StaticQueue_t = StaticQueue_t::new();
const TIMER_QUEUE_STORAGE_SIZE: usize =
configTIMER_QUEUE_LENGTH as usize * core::mem::size_of::<DaemonTaskMessage_t>();
static mut ucStaticTimerQueueStorage: [u8; TIMER_QUEUE_STORAGE_SIZE] =
[0; TIMER_QUEUE_STORAGE_SIZE];
static mut xLastTime: TickType_t = 0;
pub unsafe fn vTimerSetTimerTaskMemory(
pxTaskTCBBuffer: *mut StaticTask_t,
pxTaskStackBuffer: *mut StackType_t,
uxStackSize: configSTACK_DEPTH_TYPE,
) -> BaseType_t {
if pxTaskTCBBuffer.is_null() || pxTaskStackBuffer.is_null() || uxStackSize == 0 {
return pdFAIL;
}
taskENTER_CRITICAL();
let xReturn = if xTimerTaskHandle.is_null() {
pxTimerTaskTCBBuffer = pxTaskTCBBuffer;
pxTimerTaskStackBuffer = pxTaskStackBuffer;
uxTimerTaskStackSize = uxStackSize;
pdPASS
} else {
pdFAIL
};
taskEXIT_CRITICAL();
xReturn
}
pub unsafe fn xTimerCreateTimerTask() -> BaseType_t {
let mut xReturn: BaseType_t = pdFAIL;
traceENTER_xTimerCreateTimerTask!();
prvCheckForValidListAndQueue();
unsafe {
if !xTimerQueue.is_null() {
if !pxTimerTaskTCBBuffer.is_null()
&& !pxTimerTaskStackBuffer.is_null()
&& uxTimerTaskStackSize > 0
{
xTimerTaskHandle = xTaskCreateStatic(
prvTimerTask,
configTIMER_SERVICE_TASK_NAME.as_ptr(),
uxTimerTaskStackSize,
ptr::null_mut(),
configTIMER_TASK_PRIORITY,
pxTimerTaskStackBuffer,
pxTimerTaskTCBBuffer,
);
if !xTimerTaskHandle.is_null() {
xReturn = pdPASS;
}
} else {
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
{
xReturn = xTaskCreate(
prvTimerTask,
configTIMER_SERVICE_TASK_NAME.as_ptr(),
configTIMER_TASK_STACK_DEPTH,
ptr::null_mut(),
configTIMER_TASK_PRIORITY,
&mut xTimerTaskHandle,
);
}
#[cfg(not(any(feature = "alloc", feature = "heap-4", feature = "heap-5")))]
{
xReturn = pdFAIL;
}
}
}
}
traceRETURN_xTimerCreateTimerTask!(xReturn);
xReturn
}
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
pub unsafe fn xTimerCreate(
pcTimerName: *const u8,
xTimerPeriodInTicks: TickType_t,
xAutoReload: BaseType_t,
pvTimerID: *mut c_void,
pxCallbackFunction: TimerCallbackFunction_t,
) -> TimerHandle_t {
traceENTER_xTimerCreate!(
pcTimerName,
xTimerPeriodInTicks,
xAutoReload,
pvTimerID,
pxCallbackFunction
);
if xTimerPeriodInTicks == 0 {
traceRETURN_xTimerCreate!(ptr::null_mut::<Timer_t>());
return ptr::null_mut();
}
let pxNewTimer: *mut Timer_t =
unsafe { pvPortMalloc(core::mem::size_of::<Timer_t>()) as *mut Timer_t };
if pxNewTimer != ptr::null_mut() {
prvInitialiseNewTimer(
pcTimerName,
xTimerPeriodInTicks,
xAutoReload,
pvTimerID,
pxCallbackFunction,
pxNewTimer,
0,
);
}
traceRETURN_xTimerCreate!(pxNewTimer);
pxNewTimer as TimerHandle_t
}
pub unsafe fn xTimerCreateStatic(
pcTimerName: *const u8,
xTimerPeriodInTicks: TickType_t,
xAutoReload: BaseType_t,
pvTimerID: *mut c_void,
pxCallbackFunction: TimerCallbackFunction_t,
pxTimerBuffer: *mut StaticTimer_t,
) -> TimerHandle_t {
traceENTER_xTimerCreateStatic!(
pcTimerName,
xTimerPeriodInTicks,
xAutoReload,
pvTimerID,
pxCallbackFunction,
pxTimerBuffer
);
if pxTimerBuffer.is_null() || xTimerPeriodInTicks == 0 {
traceRETURN_xTimerCreateStatic!(ptr::null_mut::<Timer_t>());
return ptr::null_mut();
}
#[cfg(debug_assertions)]
{
let static_size = core::mem::size_of::<StaticTimer_t>();
let timer_size = core::mem::size_of::<Timer_t>();
configASSERT(static_size == timer_size);
}
let pxNewTimer: *mut Timer_t = pxTimerBuffer as *mut Timer_t;
if pxNewTimer != ptr::null_mut() {
prvInitialiseNewTimer(
pcTimerName,
xTimerPeriodInTicks,
xAutoReload,
pvTimerID,
pxCallbackFunction,
pxNewTimer,
tmrSTATUS_IS_STATICALLY_ALLOCATED,
);
}
traceRETURN_xTimerCreateStatic!(pxNewTimer);
pxNewTimer as TimerHandle_t
}
pub unsafe fn xTimerGenericCommandFromTask(
xTimer: TimerHandle_t,
xCommandID: BaseType_t,
xOptionalValue: TickType_t,
pxHigherPriorityTaskWoken: *mut BaseType_t,
xTicksToWait: TickType_t,
) -> BaseType_t {
let mut xReturn: BaseType_t = pdFAIL;
traceENTER_xTimerGenericCommandFromTask!(
xTimer,
xCommandID,
xOptionalValue,
pxHigherPriorityTaskWoken,
xTicksToWait
);
unsafe {
let xCommandIsValid = xCommandID == tmrCOMMAND_START_DONT_TRACE
|| xCommandID == tmrCOMMAND_START
|| xCommandID == tmrCOMMAND_RESET
|| xCommandID == tmrCOMMAND_STOP
|| xCommandID == tmrCOMMAND_CHANGE_PERIOD
|| xCommandID == tmrCOMMAND_DELETE;
if xTimerQueue != ptr::null_mut() && xTimer != ptr::null_mut() && xCommandIsValid {
let mut xMessage: DaemonTaskMessage_t = core::mem::zeroed();
xMessage.xMessageID = xCommandID;
xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
xMessage.u.xTimerParameters.pxTimer = xTimer as *mut Timer_t;
let xPeriodIsValid = xCommandID != tmrCOMMAND_CHANGE_PERIOD || xOptionalValue != 0;
if xPeriodIsValid {
let xTicksToWaitActual = if xTaskGetSchedulerState() == taskSCHEDULER_RUNNING {
xTicksToWait
} else {
tmrNO_DELAY
};
xReturn = xQueueSendToBack(
xTimerQueue,
&xMessage as *const _ as *const c_void,
xTicksToWaitActual,
);
}
traceTIMER_COMMAND_SEND!(xTimer, xCommandID, xOptionalValue, xReturn);
}
}
traceRETURN_xTimerGenericCommandFromTask!(xReturn);
xReturn
}
pub unsafe fn xTimerGenericCommandFromISR(
xTimer: TimerHandle_t,
xCommandID: BaseType_t,
xOptionalValue: TickType_t,
pxHigherPriorityTaskWoken: *mut BaseType_t,
_xTicksToWait: TickType_t,
) -> BaseType_t {
let mut xReturn: BaseType_t = pdFAIL;
traceENTER_xTimerGenericCommandFromISR!(
xTimer,
xCommandID,
xOptionalValue,
pxHigherPriorityTaskWoken,
_xTicksToWait
);
unsafe {
let xCommandIsValid = xCommandID == tmrCOMMAND_START_FROM_ISR
|| xCommandID == tmrCOMMAND_RESET_FROM_ISR
|| xCommandID == tmrCOMMAND_STOP_FROM_ISR
|| xCommandID == tmrCOMMAND_CHANGE_PERIOD_FROM_ISR;
if xTimerQueue != ptr::null_mut() && xTimer != ptr::null_mut() && xCommandIsValid {
let mut xMessage: DaemonTaskMessage_t = core::mem::zeroed();
xMessage.xMessageID = xCommandID;
xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
xMessage.u.xTimerParameters.pxTimer = xTimer as *mut Timer_t;
let xPeriodIsValid =
xCommandID != tmrCOMMAND_CHANGE_PERIOD_FROM_ISR || xOptionalValue != 0;
if xPeriodIsValid {
xReturn = xQueueSendToBackFromISR(
xTimerQueue,
&xMessage as *const _ as *const c_void,
pxHigherPriorityTaskWoken,
);
}
traceTIMER_COMMAND_SEND!(xTimer, xCommandID, xOptionalValue, xReturn);
}
}
traceRETURN_xTimerGenericCommandFromISR!(xReturn);
xReturn
}
#[inline(always)]
pub unsafe fn xTimerGenericCommand(
xTimer: TimerHandle_t,
xCommandID: BaseType_t,
xOptionalValue: TickType_t,
pxHigherPriorityTaskWoken: *mut BaseType_t,
xTicksToWait: TickType_t,
) -> BaseType_t {
if xCommandID < tmrFIRST_FROM_ISR_COMMAND {
xTimerGenericCommandFromTask(
xTimer,
xCommandID,
xOptionalValue,
pxHigherPriorityTaskWoken,
xTicksToWait,
)
} else {
xTimerGenericCommandFromISR(
xTimer,
xCommandID,
xOptionalValue,
pxHigherPriorityTaskWoken,
xTicksToWait,
)
}
}
pub fn xTimerGetTimerDaemonTaskHandle() -> TaskHandle_t {
traceENTER_xTimerGetTimerDaemonTaskHandle!();
unsafe {
configASSERT(xTimerTaskHandle != ptr::null_mut());
traceRETURN_xTimerGetTimerDaemonTaskHandle!(xTimerTaskHandle);
xTimerTaskHandle
}
}
pub unsafe fn xTimerGetPeriod(xTimer: TimerHandle_t) -> TickType_t {
let pxTimer = xTimer as *mut Timer_t;
traceENTER_xTimerGetPeriod!(xTimer);
configASSERT(xTimer != ptr::null_mut());
let xReturn = unsafe { (*pxTimer).xTimerPeriodInTicks };
traceRETURN_xTimerGetPeriod!(xReturn);
xReturn
}
pub unsafe fn vTimerSetReloadMode(xTimer: TimerHandle_t, xAutoReload: BaseType_t) {
let pxTimer = xTimer as *mut Timer_t;
traceENTER_vTimerSetReloadMode!(xTimer, xAutoReload);
configASSERT(xTimer != ptr::null_mut());
taskENTER_CRITICAL();
unsafe {
if xAutoReload != pdFALSE {
(*pxTimer).ucStatus |= tmrSTATUS_IS_AUTORELOAD;
} else {
(*pxTimer).ucStatus &= !tmrSTATUS_IS_AUTORELOAD;
}
}
taskEXIT_CRITICAL();
traceRETURN_vTimerSetReloadMode!();
}
pub unsafe fn xTimerGetReloadMode(xTimer: TimerHandle_t) -> BaseType_t {
let pxTimer = xTimer as *mut Timer_t;
let xReturn: BaseType_t;
traceENTER_xTimerGetReloadMode!(xTimer);
configASSERT(xTimer != ptr::null_mut());
taskENTER_CRITICAL();
unsafe {
if ((*pxTimer).ucStatus & tmrSTATUS_IS_AUTORELOAD) == 0 {
xReturn = pdFALSE;
} else {
xReturn = pdTRUE;
}
}
taskEXIT_CRITICAL();
traceRETURN_xTimerGetReloadMode!(xReturn);
xReturn
}
pub unsafe fn uxTimerGetReloadMode(xTimer: TimerHandle_t) -> UBaseType_t {
traceENTER_uxTimerGetReloadMode!(xTimer);
let uxReturn = xTimerGetReloadMode(xTimer) as UBaseType_t;
traceRETURN_uxTimerGetReloadMode!(uxReturn);
uxReturn
}
pub unsafe fn xTimerGetExpiryTime(xTimer: TimerHandle_t) -> TickType_t {
let pxTimer = xTimer as *mut Timer_t;
traceENTER_xTimerGetExpiryTime!(xTimer);
configASSERT(xTimer != ptr::null_mut());
let xReturn = unsafe { listGET_LIST_ITEM_VALUE(ptr::addr_of!((*pxTimer).xTimerListItem)) };
traceRETURN_xTimerGetExpiryTime!(xReturn);
xReturn
}
pub unsafe fn pcTimerGetName(xTimer: TimerHandle_t) -> *const u8 {
let pxTimer = xTimer as *mut Timer_t;
traceENTER_pcTimerGetName!(xTimer);
configASSERT(xTimer != ptr::null_mut());
let pcName = unsafe { (*pxTimer).pcTimerName };
traceRETURN_pcTimerGetName!(pcName);
pcName
}
pub unsafe fn xTimerIsTimerActive(xTimer: TimerHandle_t) -> BaseType_t {
let pxTimer = xTimer as *mut Timer_t;
let xReturn: BaseType_t;
traceENTER_xTimerIsTimerActive!(xTimer);
configASSERT(xTimer != ptr::null_mut());
taskENTER_CRITICAL();
unsafe {
if ((*pxTimer).ucStatus & tmrSTATUS_IS_ACTIVE) == 0 {
xReturn = pdFALSE;
} else {
xReturn = pdTRUE;
}
}
taskEXIT_CRITICAL();
traceRETURN_xTimerIsTimerActive!(xReturn);
xReturn
}
pub unsafe fn pvTimerGetTimerID(xTimer: TimerHandle_t) -> *mut c_void {
let pxTimer = xTimer as *mut Timer_t;
traceENTER_pvTimerGetTimerID!(xTimer);
configASSERT(xTimer != ptr::null_mut());
let pvReturn: *mut c_void;
taskENTER_CRITICAL();
unsafe {
pvReturn = (*pxTimer).pvTimerID;
}
taskEXIT_CRITICAL();
traceRETURN_pvTimerGetTimerID!(pvReturn);
pvReturn
}
pub unsafe fn vTimerSetTimerID(xTimer: TimerHandle_t, pvNewID: *mut c_void) {
let pxTimer = xTimer as *mut Timer_t;
traceENTER_vTimerSetTimerID!(xTimer, pvNewID);
configASSERT(xTimer != ptr::null_mut());
taskENTER_CRITICAL();
unsafe {
(*pxTimer).pvTimerID = pvNewID;
}
taskEXIT_CRITICAL();
traceRETURN_vTimerSetTimerID!();
}
pub unsafe fn xTimerGetStaticBuffer(
xTimer: TimerHandle_t,
ppxTimerBuffer: *mut *mut StaticTimer_t,
) -> BaseType_t {
let pxTimer = xTimer as *mut Timer_t;
let xReturn: BaseType_t;
traceENTER_xTimerGetStaticBuffer!(xTimer, ppxTimerBuffer);
configASSERT(xTimer != ptr::null_mut());
configASSERT(ppxTimerBuffer != ptr::null_mut());
unsafe {
if ((*pxTimer).ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED) != 0 {
*ppxTimerBuffer = pxTimer as *mut StaticTimer_t;
xReturn = pdTRUE;
} else {
xReturn = pdFALSE;
}
}
traceRETURN_xTimerGetStaticBuffer!(xReturn);
xReturn
}
pub unsafe fn vTimerResetState() {
unsafe {
xTimerQueue = ptr::null_mut();
xTimerTaskHandle = ptr::null_mut();
}
}
#[cfg(feature = "trace-facility")]
pub unsafe fn uxTimerGetTimerNumber(xTimer: TimerHandle_t) -> UBaseType_t {
traceENTER_uxTimerGetTimerNumber!(xTimer);
let uxReturn = unsafe { (*(xTimer as *mut Timer_t)).uxTimerNumber };
traceRETURN_uxTimerGetTimerNumber!(uxReturn);
uxReturn
}
#[cfg(feature = "trace-facility")]
pub unsafe fn vTimerSetTimerNumber(xTimer: TimerHandle_t, uxTimerNumber: UBaseType_t) {
traceENTER_vTimerSetTimerNumber!(xTimer, uxTimerNumber);
unsafe {
(*(xTimer as *mut Timer_t)).uxTimerNumber = uxTimerNumber;
}
traceRETURN_vTimerSetTimerNumber!();
}
#[cfg(feature = "pend-function-call")]
pub unsafe fn xTimerPendFunctionCallFromISR(
xFunctionToPend: PendedFunction_t,
pvParameter1: *mut c_void,
ulParameter2: PendedFunctionParameter_t,
pxHigherPriorityTaskWoken: *mut BaseType_t,
) -> BaseType_t {
traceENTER_xTimerPendFunctionCallFromISR!(
xFunctionToPend,
pvParameter1,
ulParameter2,
pxHigherPriorityTaskWoken
);
if unsafe { xTimerQueue.is_null() } {
traceRETURN_xTimerPendFunctionCallFromISR!(pdFAIL);
return pdFAIL;
}
let mut xMessage: DaemonTaskMessage_t = unsafe { core::mem::zeroed() };
xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR;
xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
let xReturn = unsafe {
xQueueSendFromISR(
xTimerQueue,
&xMessage as *const _ as *const c_void,
pxHigherPriorityTaskWoken,
)
};
tracePEND_FUNC_CALL_FROM_ISR!(xFunctionToPend, pvParameter1, ulParameter2, xReturn);
traceRETURN_xTimerPendFunctionCallFromISR!(xReturn);
xReturn
}
#[cfg(feature = "pend-function-call")]
pub unsafe fn xTimerPendFunctionCall(
xFunctionToPend: PendedFunction_t,
pvParameter1: *mut c_void,
ulParameter2: PendedFunctionParameter_t,
xTicksToWait: TickType_t,
) -> BaseType_t {
traceENTER_xTimerPendFunctionCall!(xFunctionToPend, pvParameter1, ulParameter2, xTicksToWait);
unsafe {
configASSERT(xTimerQueue != ptr::null_mut());
if xTimerQueue.is_null() {
traceRETURN_xTimerPendFunctionCall!(pdFAIL);
return pdFAIL;
}
}
let mut xMessage: DaemonTaskMessage_t = unsafe { core::mem::zeroed() };
xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK;
xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
let xReturn = unsafe {
xQueueSendToBack(
xTimerQueue,
&xMessage as *const _ as *const c_void,
xTicksToWait,
)
};
tracePEND_FUNC_CALL!(xFunctionToPend, pvParameter1, ulParameter2, xReturn);
traceRETURN_xTimerPendFunctionCall!(xReturn);
xReturn
}
fn prvInitialiseNewTimer(
pcTimerName: *const u8,
xTimerPeriodInTicks: TickType_t,
xAutoReload: BaseType_t,
pvTimerID: *mut c_void,
pxCallbackFunction: TimerCallbackFunction_t,
pxNewTimer: *mut Timer_t,
mut ucStatus: u8,
) {
configASSERT(xTimerPeriodInTicks > 0);
prvCheckForValidListAndQueue();
if xAutoReload != pdFALSE {
ucStatus |= tmrSTATUS_IS_AUTORELOAD;
}
unsafe {
ptr::write(
pxNewTimer,
Timer_t {
pcTimerName,
xTimerListItem: ListItem_t::new(),
xTimerPeriodInTicks,
pvTimerID,
pxCallbackFunction,
#[cfg(feature = "trace-facility")]
uxTimerNumber: 0,
ucStatus,
},
);
vListInitialiseItem(ptr::addr_of_mut!((*pxNewTimer).xTimerListItem));
}
traceTIMER_CREATE!(pxNewTimer);
}
fn prvCheckForValidListAndQueue() {
taskENTER_CRITICAL();
unsafe {
if xTimerQueue == ptr::null_mut() {
vListInitialise(ptr::addr_of_mut!(xActiveTimerList1));
vListInitialise(ptr::addr_of_mut!(xActiveTimerList2));
pxCurrentTimerList = ptr::addr_of_mut!(xActiveTimerList1);
pxOverflowTimerList = ptr::addr_of_mut!(xActiveTimerList2);
xTimerQueue = xQueueCreateStatic(
configTIMER_QUEUE_LENGTH,
core::mem::size_of::<DaemonTaskMessage_t>() as UBaseType_t,
ucStaticTimerQueueStorage.as_mut_ptr(),
&mut xStaticTimerQueue,
);
#[cfg(feature = "queue-registry")]
if !xTimerQueue.is_null() {
vQueueAddToRegistry(xTimerQueue, b"TmrQ\0".as_ptr());
}
}
}
taskEXIT_CRITICAL();
}
extern "C" fn prvTimerTask(pvParameters: *mut c_void) {
let mut xNextExpireTime: TickType_t;
let mut xListWasEmpty: BaseType_t = pdFALSE;
let _ = pvParameters;
loop {
xNextExpireTime = prvGetNextExpireTime(&mut xListWasEmpty);
prvProcessTimerOrBlockTask(xNextExpireTime, xListWasEmpty);
prvProcessReceivedCommands();
}
}
fn prvGetNextExpireTime(pxListWasEmpty: *mut BaseType_t) -> TickType_t {
let xNextExpireTime: TickType_t;
unsafe {
*pxListWasEmpty = listLIST_IS_EMPTY(pxCurrentTimerList);
if *pxListWasEmpty == pdFALSE {
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY(pxCurrentTimerList);
} else {
xNextExpireTime = 0;
}
}
xNextExpireTime
}
fn prvSampleTimeNow(pxTimerListsWereSwitched: *mut BaseType_t) -> TickType_t {
let xTimeNow: TickType_t;
xTimeNow = xTaskGetTickCount();
unsafe {
if xTimeNow < xLastTime {
prvSwitchTimerLists();
*pxTimerListsWereSwitched = pdTRUE;
} else {
*pxTimerListsWereSwitched = pdFALSE;
}
xLastTime = xTimeNow;
}
xTimeNow
}
fn prvSwitchTimerLists() {
let mut xNextExpireTime: TickType_t;
unsafe {
while listLIST_IS_EMPTY(pxCurrentTimerList) == pdFALSE {
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY(pxCurrentTimerList);
prvProcessExpiredTimer(xNextExpireTime, tmrMAX_TIME_BEFORE_OVERFLOW);
}
let pxTemp = pxCurrentTimerList;
pxCurrentTimerList = pxOverflowTimerList;
pxOverflowTimerList = pxTemp;
}
}
fn prvProcessTimerOrBlockTask(xNextExpireTime: TickType_t, xListWasEmpty: BaseType_t) {
let mut xTimerListsWereSwitched: BaseType_t = pdFALSE;
unsafe { vTaskSuspendAll() };
unsafe {
let xTimeNow = prvSampleTimeNow(&mut xTimerListsWereSwitched);
if xTimerListsWereSwitched == pdFALSE {
if (xListWasEmpty == pdFALSE) && (xNextExpireTime <= xTimeNow) {
xTaskResumeAll();
prvProcessExpiredTimer(xNextExpireTime, xTimeNow);
} else {
let mut xListWasEmptyNow = xListWasEmpty;
if xListWasEmptyNow != pdFALSE {
xListWasEmptyNow = listLIST_IS_EMPTY(pxOverflowTimerList);
}
let xTicksToWait = if xListWasEmptyNow != pdFALSE {
portMAX_DELAY
} else {
xNextExpireTime.wrapping_sub(xTimeNow)
};
vQueueWaitForMessageRestricted(xTimerQueue, xTicksToWait, xListWasEmptyNow);
if xTaskResumeAll() == pdFALSE {
portYIELD_WITHIN_API();
}
}
} else {
xTaskResumeAll();
}
}
}
fn prvInsertTimerInActiveList(
pxTimer: *mut Timer_t,
xNextExpiryTime: TickType_t,
xTimeNow: TickType_t,
xCommandTime: TickType_t,
) -> BaseType_t {
let mut xProcessTimerNow: BaseType_t = pdFALSE;
unsafe {
listSET_LIST_ITEM_VALUE(
ptr::addr_of_mut!((*pxTimer).xTimerListItem),
xNextExpiryTime,
);
listSET_LIST_ITEM_OWNER(
ptr::addr_of_mut!((*pxTimer).xTimerListItem),
pxTimer as *mut c_void,
);
if xNextExpiryTime <= xTimeNow {
if xTimeNow.wrapping_sub(xCommandTime) >= (*pxTimer).xTimerPeriodInTicks {
xProcessTimerNow = pdTRUE;
} else {
vListInsert(
pxOverflowTimerList,
ptr::addr_of_mut!((*pxTimer).xTimerListItem),
);
}
} else {
if (xTimeNow < xCommandTime) && (xNextExpiryTime >= xCommandTime) {
xProcessTimerNow = pdTRUE;
} else {
vListInsert(
pxCurrentTimerList,
ptr::addr_of_mut!((*pxTimer).xTimerListItem),
);
}
}
}
xProcessTimerNow
}
fn prvReloadTimer(pxTimer: *mut Timer_t, mut xExpiredTime: TickType_t, xTimeNow: TickType_t) {
unsafe {
while prvInsertTimerInActiveList(
pxTimer,
xExpiredTime.wrapping_add((*pxTimer).xTimerPeriodInTicks),
xTimeNow,
xExpiredTime,
) != pdFALSE
{
xExpiredTime = xExpiredTime.wrapping_add((*pxTimer).xTimerPeriodInTicks);
traceTIMER_EXPIRED!(pxTimer);
((*pxTimer).pxCallbackFunction)(pxTimer as TimerHandle_t);
}
}
}
fn prvProcessExpiredTimer(xNextExpireTime: TickType_t, xTimeNow: TickType_t) {
unsafe {
let pxTimer = listGET_OWNER_OF_HEAD_ENTRY(pxCurrentTimerList) as *mut Timer_t;
uxListRemove(ptr::addr_of_mut!((*pxTimer).xTimerListItem));
if ((*pxTimer).ucStatus & tmrSTATUS_IS_AUTORELOAD) != 0 {
prvReloadTimer(pxTimer, xNextExpireTime, xTimeNow);
} else {
(*pxTimer).ucStatus &= !tmrSTATUS_IS_ACTIVE;
}
traceTIMER_EXPIRED!(pxTimer);
((*pxTimer).pxCallbackFunction)(pxTimer as TimerHandle_t);
}
}
fn prvProcessReceivedCommands() {
let mut xMessage: DaemonTaskMessage_t = unsafe { core::mem::zeroed() };
let mut pxTimer: *mut Timer_t;
let mut xTimerListsWereSwitched: BaseType_t = pdFALSE;
unsafe {
while xQueueReceive(
xTimerQueue,
&mut xMessage as *mut _ as *mut c_void,
tmrNO_DELAY,
) != pdFAIL
{
#[cfg(feature = "pend-function-call")]
{
if xMessage.xMessageID < 0 {
let pxCallback = &xMessage.u.xCallbackParameters;
(pxCallback.pxCallbackFunction)(
pxCallback.pvParameter1,
pxCallback.ulParameter2,
);
}
}
if xMessage.xMessageID >= 0 {
pxTimer = xMessage.u.xTimerParameters.pxTimer;
if pxTimer != ptr::null_mut() {
if listIS_CONTAINED_WITHIN(
ptr::null_mut(),
ptr::addr_of!((*pxTimer).xTimerListItem),
) == pdFALSE
{
uxListRemove(ptr::addr_of_mut!((*pxTimer).xTimerListItem));
}
traceTIMER_COMMAND_RECEIVED!(
pxTimer,
xMessage.xMessageID,
xMessage.u.xTimerParameters.xMessageValue
);
let xTimeNow = prvSampleTimeNow(&mut xTimerListsWereSwitched);
match xMessage.xMessageID {
x if x == tmrCOMMAND_START
|| x == tmrCOMMAND_START_FROM_ISR
|| x == tmrCOMMAND_RESET
|| x == tmrCOMMAND_RESET_FROM_ISR =>
{
(*pxTimer).ucStatus |= tmrSTATUS_IS_ACTIVE;
let xNextExpiryTime = xMessage
.u
.xTimerParameters
.xMessageValue
.wrapping_add((*pxTimer).xTimerPeriodInTicks);
if prvInsertTimerInActiveList(
pxTimer,
xNextExpiryTime,
xTimeNow,
xMessage.u.xTimerParameters.xMessageValue,
) != pdFALSE
{
if ((*pxTimer).ucStatus & tmrSTATUS_IS_AUTORELOAD) != 0 {
prvReloadTimer(pxTimer, xNextExpiryTime, xTimeNow);
} else {
(*pxTimer).ucStatus &= !tmrSTATUS_IS_ACTIVE;
}
traceTIMER_EXPIRED!(pxTimer);
((*pxTimer).pxCallbackFunction)(pxTimer as TimerHandle_t);
}
}
x if x == tmrCOMMAND_STOP || x == tmrCOMMAND_STOP_FROM_ISR => {
(*pxTimer).ucStatus &= !tmrSTATUS_IS_ACTIVE;
}
x if x == tmrCOMMAND_CHANGE_PERIOD
|| x == tmrCOMMAND_CHANGE_PERIOD_FROM_ISR =>
{
(*pxTimer).ucStatus |= tmrSTATUS_IS_ACTIVE;
(*pxTimer).xTimerPeriodInTicks =
xMessage.u.xTimerParameters.xMessageValue;
configASSERT((*pxTimer).xTimerPeriodInTicks > 0);
prvInsertTimerInActiveList(
pxTimer,
xTimeNow.wrapping_add((*pxTimer).xTimerPeriodInTicks),
xTimeNow,
xTimeNow,
);
}
x if x == tmrCOMMAND_DELETE => {
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
{
if ((*pxTimer).ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED) == 0 {
vPortFree(pxTimer as *mut c_void);
} else {
(*pxTimer).ucStatus &= !tmrSTATUS_IS_ACTIVE;
}
}
#[cfg(not(any(
feature = "alloc",
feature = "heap-4",
feature = "heap-5"
)))]
{
(*pxTimer).ucStatus &= !tmrSTATUS_IS_ACTIVE;
}
}
_ => {
}
}
}
}
}
}
}
#[inline(always)]
pub unsafe fn xTimerStart(xTimer: TimerHandle_t, xTicksToWait: TickType_t) -> BaseType_t {
xTimerGenericCommand(
xTimer,
tmrCOMMAND_START,
xTaskGetTickCount(),
ptr::null_mut(),
xTicksToWait,
)
}
#[inline(always)]
pub unsafe fn xTimerStop(xTimer: TimerHandle_t, xTicksToWait: TickType_t) -> BaseType_t {
xTimerGenericCommand(xTimer, tmrCOMMAND_STOP, 0, ptr::null_mut(), xTicksToWait)
}
#[inline(always)]
pub unsafe fn xTimerChangePeriod(
xTimer: TimerHandle_t,
xNewPeriod: TickType_t,
xTicksToWait: TickType_t,
) -> BaseType_t {
xTimerGenericCommand(
xTimer,
tmrCOMMAND_CHANGE_PERIOD,
xNewPeriod,
ptr::null_mut(),
xTicksToWait,
)
}
#[inline(always)]
pub unsafe fn xTimerDelete(xTimer: TimerHandle_t, xTicksToWait: TickType_t) -> BaseType_t {
xTimerGenericCommand(xTimer, tmrCOMMAND_DELETE, 0, ptr::null_mut(), xTicksToWait)
}
#[inline(always)]
pub unsafe fn xTimerReset(xTimer: TimerHandle_t, xTicksToWait: TickType_t) -> BaseType_t {
xTimerGenericCommand(
xTimer,
tmrCOMMAND_RESET,
xTaskGetTickCount(),
ptr::null_mut(),
xTicksToWait,
)
}
#[inline(always)]
pub unsafe fn xTimerStartFromISR(
xTimer: TimerHandle_t,
pxHigherPriorityTaskWoken: *mut BaseType_t,
) -> BaseType_t {
xTimerGenericCommand(
xTimer,
tmrCOMMAND_START_FROM_ISR,
xTaskGetTickCountFromISR(),
pxHigherPriorityTaskWoken,
0,
)
}
#[inline(always)]
pub unsafe fn xTimerStopFromISR(
xTimer: TimerHandle_t,
pxHigherPriorityTaskWoken: *mut BaseType_t,
) -> BaseType_t {
xTimerGenericCommand(
xTimer,
tmrCOMMAND_STOP_FROM_ISR,
0,
pxHigherPriorityTaskWoken,
0,
)
}
#[inline(always)]
pub unsafe fn xTimerChangePeriodFromISR(
xTimer: TimerHandle_t,
xNewPeriod: TickType_t,
pxHigherPriorityTaskWoken: *mut BaseType_t,
) -> BaseType_t {
xTimerGenericCommand(
xTimer,
tmrCOMMAND_CHANGE_PERIOD_FROM_ISR,
xNewPeriod,
pxHigherPriorityTaskWoken,
0,
)
}
#[inline(always)]
pub unsafe fn xTimerResetFromISR(
xTimer: TimerHandle_t,
pxHigherPriorityTaskWoken: *mut BaseType_t,
) -> BaseType_t {
xTimerGenericCommand(
xTimer,
tmrCOMMAND_RESET_FROM_ISR,
xTaskGetTickCountFromISR(),
pxHigherPriorityTaskWoken,
0,
)
}
#[cfg(test)]
mod tests {
use super::*;
extern "C" fn callback(_xTimer: TimerHandle_t) {}
#[cfg(feature = "pend-function-call")]
extern "C" fn pended_callback(
_pvParameter1: *mut c_void,
_ulParameter2: PendedFunctionParameter_t,
) {
}
#[test]
fn static_timer_storage_matches_internal_layout() {
assert_eq!(
core::mem::size_of::<StaticTimer_t>(),
core::mem::size_of::<Timer_t>()
);
assert_eq!(
core::mem::align_of::<StaticTimer_t>(),
core::mem::align_of::<Timer_t>()
);
}
#[test]
fn zero_period_static_timer_is_rejected_before_initialisation() {
let mut storage = StaticTimer_t::new();
let timer = unsafe {
xTimerCreateStatic(
b"zero\0".as_ptr(),
0,
pdTRUE,
ptr::null_mut(),
callback,
&mut storage,
)
};
assert!(timer.is_null());
}
#[cfg(feature = "pend-function-call")]
#[test]
fn pended_call_fails_cleanly_before_timer_queue_initialisation() {
unsafe {
vTimerResetState();
assert_eq!(
xTimerPendFunctionCallFromISR(
pended_callback,
ptr::null_mut(),
PendedFunctionParameter_t::MAX,
ptr::null_mut(),
),
pdFAIL,
);
}
}
#[cfg(feature = "port-test")]
#[test]
fn zero_period_change_is_rejected_without_mutating_timer() {
crate::port::test_port_reset();
unsafe { vTimerResetState() };
let mut storage = StaticTimer_t::new();
let timer = unsafe {
xTimerCreateStatic(
b"period\0".as_ptr(),
10,
pdFALSE,
ptr::null_mut(),
callback,
&mut storage,
)
};
assert!(!timer.is_null());
unsafe {
assert_eq!(xTimerChangePeriod(timer, 0, 0), pdFAIL);
assert_eq!(xTimerGetPeriod(timer), 10);
}
unsafe { vTimerResetState() };
}
#[cfg(feature = "port-test")]
#[test]
fn generic_commands_reject_unknown_ids_before_queueing() {
crate::port::test_port_reset();
unsafe { vTimerResetState() };
let mut storage = StaticTimer_t::new();
let timer = unsafe {
xTimerCreateStatic(
b"command\0".as_ptr(),
10,
pdFALSE,
ptr::null_mut(),
callback,
&mut storage,
)
};
assert!(!timer.is_null());
assert_eq!(
unsafe { xTimerGenericCommandFromTask(timer, BaseType_t::MIN, 0, ptr::null_mut(), 0) },
pdFAIL,
);
crate::port::test_port_set_inside_interrupt(true);
let isr_result =
unsafe { xTimerGenericCommandFromISR(timer, BaseType_t::MAX, 0, ptr::null_mut(), 0) };
crate::port::test_port_set_inside_interrupt(false);
assert_eq!(isr_result, pdFAIL);
unsafe { vTimerResetState() };
}
#[cfg(feature = "port-test")]
#[test]
fn obsolete_start_dont_trace_command_is_ignored_by_daemon() {
crate::port::test_port_reset();
unsafe { vTimerResetState() };
let mut storage = StaticTimer_t::new();
let timer = unsafe {
xTimerCreateStatic(
b"obsolete\0".as_ptr(),
10,
pdFALSE,
ptr::null_mut(),
callback,
&mut storage,
)
};
assert!(!timer.is_null());
assert_eq!(
unsafe {
xTimerGenericCommandFromTask(
timer,
tmrCOMMAND_START_DONT_TRACE,
0,
ptr::null_mut(),
0,
)
},
pdPASS,
);
prvProcessReceivedCommands();
assert_eq!(unsafe { xTimerIsTimerActive(timer) }, pdFALSE);
unsafe { vTimerResetState() };
}
#[cfg(all(feature = "port-test", feature = "queue-registry"))]
#[test]
fn timer_queue_uses_the_pinned_registry_name() {
crate::port::test_port_reset();
unsafe { vTimerResetState() };
let mut storage = StaticTimer_t::new();
let timer = unsafe {
xTimerCreateStatic(
b"registry\0".as_ptr(),
10,
pdFALSE,
ptr::null_mut(),
callback,
&mut storage,
)
};
assert!(!timer.is_null());
let name = unsafe { pcQueueGetName(xTimerQueue) };
assert!(!name.is_null());
assert_eq!(unsafe { core::slice::from_raw_parts(name, 4) }, b"TmrQ");
unsafe {
vQueueUnregisterQueue(xTimerQueue);
vTimerResetState();
}
}
}