/* ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio. This file is part of ChibiOS. ChibiOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ChibiOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * @file sb/user/sbapi.h * @brief ARMv7-M sandbox user API macros and structures. * * @addtogroup ARMV7M_SANDBOX_USERAPI * @{ */ #ifndef SBUSER_H #define SBUSER_H #include "sberr.h" /*===========================================================================*/ /* Module constants. */ /*===========================================================================*/ /*===========================================================================*/ /* Module pre-compile time settings. */ /*===========================================================================*/ /*===========================================================================*/ /* Derived constants and error checks. */ /*===========================================================================*/ /*===========================================================================*/ /* Module data structures and types. */ /*===========================================================================*/ /** * @brief Type of system time counter. */ typedef uint32_t systime_t; /** * @brief Type of system time interval. */ typedef uint32_t sysinterval_t; /** * @brief Type of a wide time conversion variable. */ typedef uint64_t time_conv_t; /** * @brief Type of time in microseconds. */ typedef uint32_t time_usecs_t; /** * @brief Type of time in milliseconds. */ typedef uint32_t time_msecs_t; /** * @brief Type of time in seconds. */ typedef uint32_t time_secs_t; /** * @brief Type of a message. */ typedef uint32_t msg_t; /** * @brief Type of an event mask. */ typedef uint32_t eventmask_t; /** * @brief Type of event flags. */ typedef uint32_t eventflags_t; /** * @brief Type of a sandbox API internal state variables. */ typedef struct { /** * @brief System tick frequency. */ time_conv_t frequency; } sbapi_state_t; /*===========================================================================*/ /* Module macros. */ /*===========================================================================*/ /** * @name Messages-related macros * @{ */ #define MSG_OK (msg_t)0 #define MSG_TIMEOUT (msg_t)-1 #define MSG_RESET (msg_t)-2 /** @} */ /** * @name Events-related macros * @{ */ #define ALL_EVENTS ((eventmask_t)-1) #define EVENT_MASK(eid) ((eventmask_t)1 << (eventmask_t)(eid)) /** @} */ /** * @name Time and intervals related macros * @{ */ #define TIME_IMMEDIATE ((sysinterval_t)0) #define TIME_INFINITE ((sysinterval_t)-1) #define TIME_MAX_INTERVAL ((sysinterval_t)-2) #define TIME_MAX_SYSTIME ((systime_t)-1) /** @} */ /** * @name SVC instruction wrappers. * @{ */ #define __syscall0(x) \ asm volatile ("svc " #x : : : "memory") #define __syscall0r(x) \ register uint32_t r0 asm ("r0"); \ asm volatile ("svc " #x : "=r" (r0) : : "memory") #define __syscall1r(x, p1) \ register uint32_t r0 asm ("r0") = (uint32_t)(p1); \ asm volatile ("svc " #x : "=r" (r0) : "r" (r0) : "memory") #define __syscall2r(x, p1, p2) \ register uint32_t r0 asm ("r0") = (uint32_t)(p1); \ register uint32_t r1 asm ("r1") = (uint32_t)(p2); \ asm volatile ("svc " #x : "=r" (r0) : "r" (r0), "r" (r1) : "memory") #define __syscall3r(x, p1, p2, p3) \ register uint32_t r0 asm ("r0") = (uint32_t)(p1); \ register uint32_t r1 asm ("r1") = (uint32_t)(p2); \ register uint32_t r2 asm ("r2") = (uint32_t)(p3); \ asm volatile ("svc " #x : "=r" (r0) : "r" (r0), "r" (r1), \ "r" (r2) : "memory") #define __syscall4r(x, p1, p2, p3, p4) \ register uint32_t r0 asm ("r0") = (uint32_t)(p1); \ register uint32_t r1 asm ("r1") = (uint32_t)(p2); \ register uint32_t r2 asm ("r2") = (uint32_t)(p3); \ register uint32_t r3 asm ("r3") = (uint32_t)(p4); \ asm volatile ("svc " #x : "=r" (r0) : "r" (r0), "r" (r1), \ "r" (r2), "r" (r3) : "memory") /** @} */ /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ extern sbapi_state_t sb; #ifdef __cplusplus extern "C" { #endif void sbApiInit(void); #ifdef __cplusplus } #endif /*===========================================================================*/ /* Module inline functions. */ /*===========================================================================*/ /** * @brief Posix-style file open. * * @param[in] pathname file to be opened * @param[in] flags open mode * @return The file descriptor or an error. */ static inline uint32_t sbFileOpen(const char *pathname, uint32_t flags) { __syscall3r(0, SB_POSIX_OPEN, pathname, flags); return r0; } /** * @brief Posix-style file close. * * @param[in] fd file descriptor * @return Operation result. */ static inline uint32_t sbFileClose(uint32_t fd) { __syscall2r(0, SB_POSIX_CLOSE, fd); return r0; } /** * @brief Posix-style file read. * * @param[in] fd file descriptor * @param[out] buf buffer pointer * @param[in] count number of bytes * @return The number of bytes really transferred or an error. */ static inline size_t sbFileRead(uint32_t fd, uint8_t *buf, size_t count) { __syscall4r(0, SB_POSIX_READ, fd, buf, count); return (size_t)r0; } /** * @brief Posix-style file write. * * @param[in] fd file descriptor * @param[in] buf buffer pointer * @param[in] count number of bytes * @return The number of bytes really transferred or an error. */ static inline size_t sbFileWrite(uint32_t fd, const uint8_t *buf, size_t count) { __syscall4r(0, SB_POSIX_WRITE, fd, buf, count); return (size_t)r0; } /** * @brief Posix-style file seek. * * @param[in] fd file descriptor * @param[in] offset file offset * @param[in] whence operation mode * @return Operation result. */ static inline uint32_t sbFileSeek(uint32_t fd, uint32_t offset, uint32_t whence) { __syscall4r(0, SB_POSIX_LSEEK, fd, offset, whence); return (size_t)r0; } /** * @brief Terminates the sandbox. * * @param[in] msg The exit message. * * @api */ static inline void sbExit(msg_t msg) { __syscall1r(1, msg); } /** * @brief Returns the system time. * * @return The current system time. */ static inline systime_t sbGetSystemTime(void) { __syscall0r(2); return (systime_t)r0; } /** * @brief Returns the system time frequency. * * @return The system time frequency. */ static inline uint32_t sbGetFrequency(void) { __syscall0r(3); return (uint32_t)r0; } /** * @brief Suspends the invoking thread for the specified interval. * * @param[in] interval the delay in system ticks * * @api */ static inline void sbSleep(sysinterval_t interval) { __syscall1r(4, interval); } /** * @brief Suspends the invoking thread until the system time arrives to the * specified value. * @note The system time is assumed to be between @p start and @p next * else the call is assumed to have been called outside the * allowed time interval, in this case no sleep is performed. * * @param[in] prev absolute system time of the previous deadline * @param[in] next absolute system time of the next deadline * @return the @p next parameter * * @api */ static inline void sbSleepUntil(systime_t prev, systime_t next) { __syscall2r(5, prev, next); } /** * @brief Waits for a message. * * @return The received message. */ static inline msg_t sbMsgWait(void) { __syscall0r(6); return (uint32_t)r0; } /** * @brief Replies to a message. * * @param[in] msg the reply message * * @api */ static inline uint32_t sbMsgReply(msg_t msg) { __syscall1r(7, msg); return (uint32_t)r0; } /** * @brief Waits for exactly one of the specified events. * @details The function waits for one event among those specified in * @p events to become pending then the event is cleared and returned. * @note One and only one event is served in the function, the one with the * lowest event id. The function is meant to be invoked into a loop * in order to serve all the pending events.
* This means that Event Listeners with a lower event identifier have * an higher priority. * * @param[in] events events that the function should wait * for, @p ALL_EVENTS enables all the events * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @return The mask of the lowest event id served and cleared. * @retval 0 if the operation has timed out. * * @api */ static inline eventmask_t sbEventWaitOneTimeout(eventmask_t events, sysinterval_t timeout) { __syscall2r(8, events, timeout); return (uint32_t)r0; } /** * @brief Waits for any of the specified events. * @details The function waits for any event among those specified in * @p events to become pending then the events are cleared and * returned. * * @param[in] events events that the function should wait * for, @p ALL_EVENTS enables all the events * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @return The mask of the served and cleared events. * @retval 0 if the operation has timed out. * * @api */ static inline eventmask_t sbEventWaitAnyTimeout(eventmask_t events, sysinterval_t timeout) { __syscall2r(9, events, timeout); return (uint32_t)r0; } /** * @brief Waits for all the specified events. * @details The function waits for all the events specified in @p events to * become pending then the events are cleared and returned. * * @param[in] events events that the function should wait * for, @p ALL_EVENTS requires all the events * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @return The mask of the served and cleared events. * @retval 0 if the operation has timed out. * * @api */ static inline eventmask_t sbEventWaitAllTimeout(eventmask_t events, sysinterval_t timeout) { __syscall2r(10, events, timeout); return (uint32_t)r0; } /** * @brief Signals all the Event Listeners registered on the specified Event * Source. * * @param[in] flags the flags set to be added to the listener flags mask * * @api */ static inline uint32_t sbEventBroadcastFlags(eventflags_t flags) { __syscall1r(11, flags); return (uint32_t)r0; } /** * @brief Seconds to time interval. * @details Converts from seconds to system ticks number. * @note The result is rounded upward to the next tick boundary. * * @param[in] secs number of seconds * @return The number of ticks. * * @special */ static inline sysinterval_t sbTimeS2I(time_secs_t secs) { time_conv_t ticks; ticks = (time_conv_t)secs * sb.frequency; /* sbDbgAssert(ticks <= (time_conv_t)TIME_MAX_INTERVAL, "conversion overflow");*/ return (sysinterval_t)ticks; } /** * @brief Milliseconds to time interval. * @details Converts from milliseconds to system ticks number. * @note The result is rounded upward to the next tick boundary. * * @param[in] msec number of milliseconds * @return The number of ticks. * * @special */ static inline sysinterval_t sbTimeMS2I(time_msecs_t msec) { time_conv_t ticks; ticks = (((time_conv_t)msec * sb.frequency) + (time_conv_t)999) / (time_conv_t)1000; /* chDbgAssert(ticks <= (time_conv_t)TIME_MAX_INTERVAL, "conversion overflow");*/ return (sysinterval_t)ticks; } /** * @brief Microseconds to time interval. * @details Converts from microseconds to system ticks number. * @note The result is rounded upward to the next tick boundary. * * @param[in] usec number of microseconds * @return The number of ticks. * * @special */ static inline sysinterval_t sbTimeUS2I(time_usecs_t usec) { time_conv_t ticks; ticks = (((time_conv_t)usec * sb.frequency) + (time_conv_t)999999) / (time_conv_t)1000000; /* chDbgAssert(ticks <= (time_conv_t)TIME_MAX_INTERVAL, "conversion overflow");*/ return (sysinterval_t)ticks; } /** * @brief Time interval to seconds. * @details Converts from system interval to seconds. * @note The result is rounded up to the next second boundary. * * @param[in] interval interval in ticks * @return The number of seconds. * * @special */ static inline time_secs_t sbTimeI2S(sysinterval_t interval) { time_conv_t secs; secs = ((time_conv_t)interval + sb.frequency - (time_conv_t)1) / sb.frequency; /* sbDbgAssert(secs < (time_conv_t)((time_secs_t)-1), "conversion overflow");*/ return (time_secs_t)secs; } /** * @brief Time interval to milliseconds. * @details Converts from system interval to milliseconds. * @note The result is rounded up to the next millisecond boundary. * * @param[in] interval interval in ticks * @return The number of milliseconds. * * @special */ static inline time_msecs_t sbTimeI2MS(sysinterval_t interval) { time_conv_t msecs; msecs = (((time_conv_t)interval * (time_conv_t)1000) + sb.frequency - (time_conv_t)1) / sb.frequency; /* sbDbgAssert(msecs < (time_conv_t)((time_msecs_t)-1), "conversion overflow");*/ return (time_msecs_t)msecs; } /** * @brief Time interval to microseconds. * @details Converts from system interval to microseconds. * @note The result is rounded up to the next microsecond boundary. * * @param[in] interval interval in ticks * @return The number of microseconds. * * @special */ static inline time_usecs_t sbTimeI2US(sysinterval_t interval) { time_conv_t usecs; usecs = (((time_conv_t)interval * (time_conv_t)1000000) + sb.frequency - (time_conv_t)1) / sb.frequency; /* sbDbgAssert(usecs <= (time_conv_t)((time_usecs_t)-1), "conversion overflow");*/ return (time_usecs_t)usecs; } /** * @brief Adds an interval to a system time returning a system time. * * @param[in] systime base system time * @param[in] interval interval to be added * @return The new system time. * * @xclass */ static inline systime_t sbTimeAddX(systime_t systime, sysinterval_t interval) { return systime + (systime_t)interval; } /** * @brief Subtracts two system times returning an interval. * * @param[in] start first system time * @param[in] end second system time * @return The interval representing the time difference. * * @xclass */ static inline sysinterval_t sbTimeDiffX(systime_t start, systime_t end) { return (sysinterval_t)((systime_t)(end - start)); } /** * @brief Checks if the specified time is within the specified time range. * @note When start==end then the function returns always true because the * whole time range is specified. * * @param[in] time the time to be verified * @param[in] start the start of the time window (inclusive) * @param[in] end the end of the time window (non inclusive) * @retval true current time within the specified time window. * @retval false current time not within the specified time window. * * @xclass */ static inline bool sbTimeIsInRangeX(systime_t time, systime_t start, systime_t end) { return (bool)((systime_t)((systime_t)time - (systime_t)start) < (systime_t)((systime_t)end - (systime_t)start)); } /** * @brief Delays the invoking thread for the specified number of seconds. * @note The specified time is rounded up to a value allowed by the real * system tick clock. * * @param[in] secs time in seconds * * @api */ static inline void sbSleepSeconds(time_secs_t secs) { sbSleep(sbTimeS2I(secs)); } /** * @brief Delays the invoking thread for the specified number of * milliseconds. * @note The specified time is rounded up to a value allowed by the real * system tick clock. * * @param[in] msecs time in milliseconds * * @api */ static inline void sbSleepMilliseconds(time_msecs_t msecs) { sbSleep(sbTimeMS2I(msecs)); } /** * @brief Delays the invoking thread for the specified number of * microseconds. * @note The specified time is rounded up to a value allowed by the real * system tick clock. * * @param[in] usecs time in microseconds * * @api */ static inline void sbSleepMicroseconds(time_usecs_t usecs) { sbSleep(sbTimeUS2I(usecs)); } #endif /* SBUSER_H */ /** @} */