578 строки
18 KiB
C
578 строки
18 KiB
C
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT license.
|
|
|
|
#ifndef PLATFORM_API_H_
|
|
#define PLATFORM_API_H_
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include "status/rot_status.h"
|
|
|
|
|
|
/* This file contains the platform abstraction API that can be used to decouple code from the
|
|
* environment in which it will be run. If the platform provides native functions that provide
|
|
* exactly the required functionality (such as in stdlib), they can be mapped via a macro in the
|
|
* platform.h file. Otherwise, the platform port will need to provide a suitable implementation
|
|
* of the function. */
|
|
|
|
|
|
/* The timer callback prototype needs to be defined prior to including platform.h since the platform
|
|
* ports will need to use this type with the platform_timer definition. */
|
|
|
|
/**
|
|
* Callback function prototype used when timers are executed.
|
|
*
|
|
* @param context Calling context to pass to the timer handler.
|
|
*/
|
|
typedef void (*timer_callback) (void *context);
|
|
|
|
|
|
/* Include specifics for the platform port. */
|
|
#include "platform.h"
|
|
|
|
|
|
/* Generic error codes that can be used for platform API failures. */
|
|
#define PLATFORM_INVALID_ARGUMENT 0
|
|
#define PLATFORM_NO_MEMORY 1
|
|
#define PLATFORM_FAILURE 2
|
|
#define PLATFORM_UNSUPPORTED 3
|
|
|
|
|
|
/*******************************
|
|
* Memory management routines.
|
|
*******************************/
|
|
|
|
#ifndef platform_malloc
|
|
/**
|
|
* Dynamically allocate a block of memory. Equivalent to the stdlib 'malloc' call.
|
|
*
|
|
* @param size The amount of memory to allocate.
|
|
*
|
|
* @return A pointer to the allocated block of memory or null if the memory could not be allocated.
|
|
*/
|
|
void* platform_malloc (size_t size);
|
|
#endif
|
|
|
|
#ifndef platform_calloc
|
|
/**
|
|
* Dynamically allocate an array of memory and initialize the memory to zero. Equivalent to the
|
|
* stdlib 'calloc' call.
|
|
*
|
|
* @param nmemb The number of elements to allocate.
|
|
* @param size The size of each element.
|
|
*
|
|
* @return A pointer to the allocated block of memory or null if the memory could not be allocated.
|
|
*/
|
|
void* platform_calloc (size_t nmemb, size_t size);
|
|
#endif
|
|
|
|
#ifndef platform_realloc
|
|
/**
|
|
* Change the size of a previously allocated block of memory. Equivalent to the stdlib 'realloc'
|
|
* call.
|
|
*
|
|
* This function only exists to support the unit testing framework and should not be used in
|
|
* production code. It is not guaranteed that every platform can support this capability.
|
|
*
|
|
* @param ptr A pointer to the memory that should be resized.
|
|
* @param size The new size of the allocated memory.
|
|
*
|
|
* @return A pointer to the allocated block of memory or null if the memory could not be resized.
|
|
*/
|
|
void* platform_realloc (void *ptr, size_t size);
|
|
#endif
|
|
|
|
#ifndef platform_free
|
|
/**
|
|
* Free a previously allocated block of memory. Equivalent to the stdlib 'free' call.
|
|
*
|
|
* @param ptr A pointer to the memory that should be freed.
|
|
*/
|
|
void free (void *ptr);
|
|
#endif
|
|
|
|
|
|
/**************************
|
|
* Byte order conversion.
|
|
**************************/
|
|
|
|
#ifndef platform_htonl
|
|
/**
|
|
* Convert a 32-bit integer from host byte order to network byte order (big endian).
|
|
*
|
|
* @param hostlong Integer in host byte order.
|
|
*
|
|
* @return Integer in network byte order.
|
|
*/
|
|
uint32_t platform_htonl (uint32_t hostlong);
|
|
#endif
|
|
|
|
#ifndef platform_htons
|
|
/**
|
|
* Convert a 16-bit integer from host byte order to network byte order (big endian).
|
|
*
|
|
* @param hostshort Integer in host byte order.
|
|
*
|
|
* @return Integer in network byte order.
|
|
*/
|
|
uint32_t platform_htons (uint32_t hostshort);
|
|
#endif
|
|
|
|
|
|
/*****************************
|
|
* Sleep and system time.
|
|
*****************************/
|
|
|
|
/**
|
|
* Module defined for timeout and clock error codes. The actual error codes will vary based on the
|
|
* platform, but the error will be reported with the same module ID.
|
|
*/
|
|
#define PLATFORM_TIMEOUT_ERROR(code) ROT_ERROR (ROT_MODULE_PLATFORM_TIMEOUT, code)
|
|
|
|
|
|
#ifndef PLATFORM_CLOCK_RESOLUTION
|
|
/**
|
|
* The resolution of the clock implementation for the platform. This is the minimum duration that
|
|
* can be measured and is the minimum time that will be used for timeouts.
|
|
*
|
|
* If the platform doesn't override this value, it defaults to a 1 millisecond resolution.
|
|
*/
|
|
#define PLATFORM_CLOCK_RESOLUTION 1
|
|
#endif
|
|
|
|
|
|
#ifndef platform_msleep
|
|
/**
|
|
* Sleep for a specified number of milliseconds.
|
|
*
|
|
* It is guaranteed that at least the specified time will elapse before this functions returns, but
|
|
* there are no guarantees about how close the specified this will happen.
|
|
*
|
|
* @param msec The number of milliseconds to sleep.
|
|
*/
|
|
void platform_msleep (uint32_t msec);
|
|
#endif
|
|
|
|
#ifndef platform_init_timeout
|
|
/**
|
|
* Initialize a clock structure to represent the time at which a timeout expires.
|
|
*
|
|
* @param msec The number of milliseconds to use for the timeout.
|
|
* @param timeout The timeout to initialize.
|
|
*
|
|
* @return 0 if the timeout was initialized successfully or an error code.
|
|
*/
|
|
int platform_init_timeout (uint32_t msec, platform_clock *timeout);
|
|
#endif
|
|
|
|
#ifndef platform_increase_timeout
|
|
/**
|
|
* Increase the amount of time for an existing timeout.
|
|
*
|
|
* The clock structure must already have been initialized with {@link platform_init_timeout} to set
|
|
* the original timeout. Other usage results in undefined behavior.
|
|
*
|
|
* @param msec The number of milliseconds to increase the timeout expiration by. This is not the
|
|
* total timeout from when timeout was initialized. It is just the increment to apply to the
|
|
* existing timeout.
|
|
* @param timeout The timeout to update.
|
|
*
|
|
* @return 0 if the timeout was updated successfully or an error code.
|
|
*/
|
|
int platform_increase_timeout (uint32_t msec, platform_clock *timeout);
|
|
#endif
|
|
|
|
#ifndef platform_has_timeout_expired
|
|
/**
|
|
* Determine if the specified timeout has expired.
|
|
*
|
|
* This should only be used with clock structures initialized by {@link platform_init_timeout}.
|
|
* Other usage results in undefined behavior.
|
|
*
|
|
* @param timeout The timeout to check.
|
|
*
|
|
* @return 1 if the timeout has expired, 0 if it has not, or an error code.
|
|
*/
|
|
int platform_has_timeout_expired (const platform_clock *timeout);
|
|
#endif
|
|
|
|
#ifndef platform_get_timeout_remaining
|
|
/**
|
|
* Get the amount of time remaining before a timeout expires.
|
|
*
|
|
* This should only be used with clock structures initialized by {@link platform_init_timeout}.
|
|
* Other usage results in undefined behavior.
|
|
*
|
|
* @param timeout The timeout to check.
|
|
* @param msec Output for he number of milliseconds remaining until the timeout expires. If the
|
|
* timeout has already expired, this will be 0.
|
|
*
|
|
* @return 0 if the remaining time was successfully determined or an error code.
|
|
*/
|
|
int platform_get_timeout_remaining (const platform_clock *timeout, uint32_t *msec);
|
|
#endif
|
|
|
|
|
|
#ifndef platform_init_current_tick
|
|
/**
|
|
* Initialize a clock structure to represent the current time in way that can be compared against.
|
|
* This will use the same time source that used to manage timeouts.
|
|
*
|
|
* @param currtime Output for the current system time.
|
|
*
|
|
* @return 0 if the current time was initialized successfully or an error code.
|
|
*/
|
|
int platform_init_current_tick (platform_clock *currtime);
|
|
#endif
|
|
|
|
#ifndef platform_get_duration
|
|
/**
|
|
* Get the time that has elapsed between two clock instances.
|
|
*
|
|
* This is intended to measure small durations. Very long durations may not be accurately
|
|
* calculated due to value limitations and/or overflow.
|
|
*
|
|
* There are a few defined use-cases for this function:
|
|
* 1. Calculating the elapsed time between two times, both of which have been initialized with
|
|
* {@link platform_init_current_tick}.
|
|
* 2. Determining how much time has elapsed since a timeout has expired. This only works with
|
|
* expired timeouts, and that argument must be the starting point for the calculation.
|
|
* 3. Calculating the difference between the expiration times of two timeouts, both of which
|
|
* have been initialized with {@link platform_init_timeout}.
|
|
*
|
|
* Using this function with any other combination of clock instances results in undefined behavior.
|
|
* Checking unexpired timeouts must be done using {@link platform_has_timeout_expired} and
|
|
* {@link platform_get_timeout_remaining}.
|
|
*
|
|
* In all cases the start time must be earlier than the end time. Passing a clock instance with
|
|
* start and end times swapped results in undefined behavior.
|
|
*
|
|
* @param start The start time for the time duration calculation.
|
|
* @param end The end time for the time duration calculation.
|
|
*
|
|
* @return The elapsed time, in milliseconds. If either clock is null, the elapsed time will be 0.
|
|
*/
|
|
uint32_t platform_get_duration (const platform_clock *start, const platform_clock *end);
|
|
#endif
|
|
|
|
|
|
/*************************
|
|
* Mutex operations.
|
|
*************************/
|
|
|
|
/**
|
|
* Module defined for mutex error codes. The actual error codes will vary based on the platform,
|
|
* but the error will be reported with the same module ID.
|
|
*/
|
|
#define PLATFORM_MUTEX_ERROR(code) ROT_ERROR (ROT_MODULE_PLATFORM_MUTEX, code)
|
|
|
|
#ifndef platform_mutex_init
|
|
/**
|
|
* Initialize a mutex.
|
|
*
|
|
* This mutex may not support recursive locking. If recursive locking is required,
|
|
* {@link platform_recursive_mutex_init} must be used instead.
|
|
*
|
|
* @param mutex The mutex to initialize.
|
|
*
|
|
* @return 0 if the mutex was successfully initialized or an error code.
|
|
*/
|
|
int platform_mutex_init (platform_mutex *mutex);
|
|
#endif
|
|
|
|
#ifndef platform_mutex_free
|
|
/**
|
|
* Free a mutex.
|
|
*
|
|
* This must only be called for mutex instances initalized with {@link platform_mutex_init}.
|
|
*
|
|
* @param mutex The mutex to free.
|
|
*
|
|
* @return 0 if the mutex was freed or an error code.
|
|
*/
|
|
int platform_mutex_free (platform_mutex *mutex);
|
|
#endif
|
|
|
|
#ifndef platform_mutex_lock
|
|
/**
|
|
* Acquire the mutex lock.
|
|
*
|
|
* This must only be called for mutex instances initalized with {@link platform_mutex_init}.
|
|
*
|
|
* @param mutex The mutex to lock.
|
|
*
|
|
* @return 0 if the mutex was successfully locked or an error code.
|
|
*/
|
|
int platform_mutex_lock (platform_mutex *mutex);
|
|
#endif
|
|
|
|
#ifndef platform_mutex_unlock
|
|
/**
|
|
* Release the mutex lock.
|
|
*
|
|
* This must only be called for mutex instances initalized with {@link platform_mutex_init}.
|
|
*
|
|
* @param mutex The mutex to unlock.
|
|
*
|
|
* @return 0 if the mutex was successfully unlocked or an error code.
|
|
*/
|
|
int platform_mutex_unlock (platform_mutex *mutex);
|
|
#endif
|
|
|
|
|
|
#ifndef platform_recursive_mutex_init
|
|
/**
|
|
* Initialize a mutex that supports recursive locking.
|
|
*
|
|
* @param mutex The mutex to initialize.
|
|
*
|
|
* @return 0 if the mutex was successfully initialized or an error code.
|
|
*/
|
|
int platform_recursive_mutex_init (platform_mutex *mutex);
|
|
#endif
|
|
|
|
#ifndef platform_recursive_mutex_free
|
|
/**
|
|
* Free a recursive mutex.
|
|
*
|
|
* This must only be called for mutex instances initalized with
|
|
* {@link platform_recursive_mutex_init}.
|
|
*
|
|
* @param mutex The mutex to free.
|
|
*
|
|
* @return 0 if the mutex was freed or an error code.
|
|
*/
|
|
int platform_recursive_mutex_free (platform_mutex *mutex);
|
|
#endif
|
|
|
|
#ifndef platform_recursive_mutex_lock
|
|
/**
|
|
* Acquire the recursive mutex lock.
|
|
*
|
|
* This must only be called for mutex instances initalized with
|
|
* {@link platform_recursive_mutex_init}.
|
|
*
|
|
* @param mutex The mutex to lock.
|
|
*
|
|
* @return 0 if the mutex was successfully locked or an error code.
|
|
*/
|
|
int platform_recursive_mutex_lock (platform_mutex *mutex);
|
|
#endif
|
|
|
|
#ifndef platform_recursive_mutex_unlock
|
|
/**
|
|
* Release the recursive mutex lock. This must be called the same number of times as
|
|
* {@link platform_recursive_mutex_lock} was called in order to fully release the lock.
|
|
*
|
|
* This must only be called for mutex instances initalized with
|
|
* {@link platform_recursive_mutex_init}.
|
|
*
|
|
* @param mutex The mutex to unlock.
|
|
*
|
|
* @return 0 if the mutex was successfully unlocked or an error code.
|
|
*/
|
|
int platform_recursive_mutex_unlock (platform_mutex *mutex);
|
|
#endif
|
|
|
|
|
|
/***********************************
|
|
* Timer scheduling and management
|
|
***********************************/
|
|
|
|
/**
|
|
* Module defined for timer error codes. The actual error codes will vary based on the platform,
|
|
* but the error will be reported with the same module ID.
|
|
*/
|
|
#define PLATFORM_TIMER_ERROR(code) ROT_ERROR (ROT_MODULE_PLATFORM_TIMER, code)
|
|
|
|
#ifndef platform_timer_create
|
|
/**
|
|
* Create a timer that is not yet armed.
|
|
*
|
|
* @param timer The container for the created timer.
|
|
* @param callback The function to call when the timer expires.
|
|
* @param context The context to pass to the notification function.
|
|
*
|
|
* @return 0 if the timer was created or an error code.
|
|
*/
|
|
int platform_timer_create (platform_timer *timer, timer_callback callback, void *context);
|
|
#endif
|
|
|
|
#ifndef platform_timer_arm_one_shot
|
|
/**
|
|
* Start a timer that will call the notification function once on expiration. If additional
|
|
* notifications are required, the timer must be rearmed.
|
|
*
|
|
* Calling this on an already armed timer will restart the timer with the specified timeout.
|
|
*
|
|
* @param timer The timer to start.
|
|
* @param ms_timeout The timeout to wait for timer expiration, in milliseconds.
|
|
*
|
|
* @return 0 if the timer has started or an error code.
|
|
*/
|
|
int platform_timer_arm_one_shot (platform_timer *timer, uint32_t ms_timeout);
|
|
#endif
|
|
|
|
#ifndef platform_timer_disarm
|
|
/**
|
|
* Stop a timer and prevent the notification from being called. The timer instance remains valid
|
|
* and can rearmed.
|
|
*
|
|
* @param timer The timer to stop.
|
|
*
|
|
* @return 0 if the timer is stopped or an error code.
|
|
*/
|
|
int platform_timer_disarm (platform_timer *timer);
|
|
#endif
|
|
|
|
#ifndef platform_timer_delete
|
|
/**
|
|
* Stop a timer and prevent the notification from being called. The timer instance will be deleted
|
|
* and cannot be reused without calling {@link platform_timer_create}.
|
|
*
|
|
* A timer instance must never be deleted from within the context of the event callback.
|
|
*
|
|
* @param timer The timer to delete.
|
|
*/
|
|
void platform_timer_delete (platform_timer *timer);
|
|
#endif
|
|
|
|
|
|
/*************************
|
|
* Semaphore operations
|
|
*************************/
|
|
|
|
/**
|
|
* Module defined for semaphore error codes. The actual error codes will vary based on the
|
|
* platform, but the error will be reported with the same module ID.
|
|
*/
|
|
#define PLATFORM_SEMAPHORE_ERROR(code) ROT_ERROR (ROT_MODULE_PLATFORM_SEMAPHORE, code)
|
|
|
|
#ifndef platform_semaphore_init
|
|
/**
|
|
* Initialize a semaphore.
|
|
*
|
|
* There are no assertions on what type of semaphore is created. It could equally be a binary or
|
|
* counting semaphore. Semaphore usage should not be designed to require specific semaphore
|
|
* capabilities beyond what the platform API provides.
|
|
*
|
|
* @param sem The semaphore to initialize.
|
|
*
|
|
* @return 0 if the semaphore was initialized successfully or an error code.
|
|
*/
|
|
int platform_semaphore_init (platform_semaphore *sem);
|
|
#endif
|
|
|
|
#ifndef platform_semaphore_free
|
|
/**
|
|
* Free a semaphore.
|
|
*
|
|
* @param sem The semaphore to free.
|
|
*/
|
|
void platform_semaphore_free (platform_semaphore *sem);
|
|
#endif
|
|
|
|
#ifndef platform_semaphore_post
|
|
/**
|
|
* Signal a semaphore from the context of a normal thread or task.
|
|
*
|
|
* Some platforms have different requirements for signaling semaphores from task vs. interrupt
|
|
* context. This call must only be used to signal semaphores from task context. Use
|
|
* platform_semaphore_post_from_isr to signal from interrupt context.
|
|
*
|
|
* @param sem The semaphore to signal.
|
|
*
|
|
* @return 0 if the semaphore was signaled successfully or an error code.
|
|
*/
|
|
int platform_semaphore_post (platform_semaphore *sem);
|
|
#endif
|
|
|
|
#ifndef platform_semaphore_post_from_isr
|
|
/**
|
|
* Signal a semaphore from the context of an interrupt service routine (ISR).
|
|
*
|
|
* Some platforms have different requirements for signaling semaphores from task vs. interrupt
|
|
* context. This call must only be used to signal semaphores from interrupt context. Use
|
|
* platform_semaphore_post to signal from task context.
|
|
*
|
|
* @param sem The semaphore to signal.
|
|
*
|
|
* @return 0 if the semaphore was signaled successfully or an error code.
|
|
*/
|
|
int platform_semaphore_post_from_isr (platform_semaphore *sem);
|
|
#endif
|
|
|
|
#ifndef platform_semaphore_wait
|
|
/**
|
|
* Wait for a semaphore to be signaled. This will block until either the semaphore is signaled or
|
|
* the timeout expires. If the semaphore is already signaled, it will return immediately.
|
|
*
|
|
* @param sem The semaphore to wait on.
|
|
* @param ms_timeout The amount of time to wait for the semaphore to be signaled, in milliseconds.
|
|
* Specifying at timeout of 0 will cause the call to block indefinitely.
|
|
*
|
|
* @return 0 if the semaphore was signaled, 1 if the timeout expired, or an error code.
|
|
*/
|
|
int platform_semaphore_wait (platform_semaphore *sem, uint32_t ms_timeout);
|
|
#endif
|
|
|
|
#ifndef platform_semaphore_try_wait
|
|
/**
|
|
* Check the state of the semaphore and return immediately. If the semaphore was signaled, checking
|
|
* the state will consume the signal.
|
|
*
|
|
* @param sem The semaphore to check.
|
|
*
|
|
* @return 0 if the semaphore was signaled, 1 if it was not, or an error code.
|
|
*/
|
|
int platform_semaphore_try_wait (platform_semaphore *sem);
|
|
#endif
|
|
|
|
#ifndef platform_semaphore_reset
|
|
/**
|
|
* Reset a semaphore to the unsignaled state.
|
|
*
|
|
* @param sem The semaphore to reset.
|
|
*
|
|
* @return 0 if the semaphore was reset successfully or an error code.
|
|
*/
|
|
int platform_semaphore_reset (platform_semaphore *sem);
|
|
#endif
|
|
|
|
|
|
/*************************
|
|
* Task and OS control
|
|
*************************/
|
|
|
|
/**
|
|
* Module defined for OS and task control error codes. The actual error codes will vary based on
|
|
* the platform, but the error will be reported with the same module ID.
|
|
*/
|
|
#define PLATFORM_OS_ERROR(code) ROT_ERROR (ROT_MODULE_PLATFORM_OS, code)
|
|
|
|
#ifndef platform_suspend_scheduler
|
|
/**
|
|
* Suspend the OS scheduler to ensure no task context switches happen, leaving the currently running
|
|
* task executing. Depending on the platform, this may cause interrupts to be disabled.
|
|
*
|
|
* Every call must be paired with a call to platform_os_resume_scheduler to enable task switching
|
|
* again.
|
|
*
|
|
* @return 0 if the OS task scheduler was suspended or an error code.
|
|
*/
|
|
int platform_os_suspend_scheduler (void);
|
|
#endif
|
|
|
|
#ifndef platform_resume_scheduler
|
|
/**
|
|
* Resume the OS scheduler, enabling task context switching. Depending on the platform, this may
|
|
* immediately cause a context switch.
|
|
*
|
|
* @return 0 if the OS task scheduler was resumed or an error code.
|
|
*/
|
|
int platform_os_resume_scheduler (void);
|
|
#endif
|
|
|
|
|
|
#endif /* PLATFORM_API_H_ */
|