|
| 1 | +/* |
| 2 | + * System specific implementation |
| 3 | + * |
| 4 | + * Copyright (c) 2016 Christopher Haster |
| 5 | + * Distributed under the MIT license |
| 6 | + */ |
| 7 | +#ifndef EQUEUE_PLATFORM_H |
| 8 | +#define EQUEUE_PLATFORM_H |
| 9 | + |
| 10 | +#ifdef __cplusplus |
| 11 | +extern "C" { |
| 12 | +#endif |
| 13 | + |
| 14 | +#include <stdbool.h> |
| 15 | + |
| 16 | +// Currently supported platforms |
| 17 | +// |
| 18 | +// Uncomment to select a supported platform or reimplement this file |
| 19 | +// for a specific target. |
| 20 | +//#define EQUEUE_PLATFORM_POSIX |
| 21 | +//#define EQUEUE_PLATFORM_WINDOWS |
| 22 | +//#define EQUEUE_PLATFORM_MBED |
| 23 | +//#define EQUEUE_PLATFORM_FREERTOS |
| 24 | + |
| 25 | +// Try to infer a platform if none was manually selected |
| 26 | +#if !defined(EQUEUE_PLATFORM_POSIX) \ |
| 27 | + && !defined(EQUEUE_PLATFORM_WINDOWS) \ |
| 28 | + && !defined(EQUEUE_PLATFORM_MBED) \ |
| 29 | + && !defined(EQUEUE_PLATFORM_FREERTOS) |
| 30 | +#if defined(__unix__) |
| 31 | +#define EQUEUE_PLATFORM_POSIX |
| 32 | +#elif defined(_WIN32) |
| 33 | +#define EQUEUE_PLATFORM_WINDOWS |
| 34 | +#elif defined(__MBED__) |
| 35 | +#define EQUEUE_PLATFORM_MBED |
| 36 | +#else |
| 37 | +#warning "Unknown platform! Please update equeue_platform.h" |
| 38 | +#endif |
| 39 | +#endif |
| 40 | + |
| 41 | +// Platform includes |
| 42 | +#if defined(EQUEUE_PLATFORM_POSIX) |
| 43 | +#include <pthread.h> |
| 44 | +#elif defined(EQUEUE_PLATFORM_WINDOWS) |
| 45 | +#include <windows.h> |
| 46 | +#elif defined(EQUEUE_PLATFORM_FREERTOS) |
| 47 | +#include "FreeRTOS.h" |
| 48 | +#include "semphr.h" |
| 49 | +#endif |
| 50 | + |
| 51 | + |
| 52 | +// Platform millisecond counter |
| 53 | +// |
| 54 | +// Return a tick that represents the number of milliseconds that have passed |
| 55 | +// since an arbitrary point in time. The granularity does not need to be at |
| 56 | +// the millisecond level, however the accuracy of the equeue library is |
| 57 | +// limited by the accuracy of this tick. |
| 58 | +// |
| 59 | +// Must intentionally overflow to 0 after 2^32-1 |
| 60 | +unsigned equeue_tick(void); |
| 61 | + |
| 62 | + |
| 63 | +// Platform mutex type |
| 64 | +// |
| 65 | +// The equeue library requires at minimum a non-recursive mutex that is |
| 66 | +// safe in interrupt contexts. The mutex section is help for a bounded |
| 67 | +// amount of time, so simply disabling interrupts is acceptable |
| 68 | +// |
| 69 | +// If irq safety is not required, a regular blocking mutex can be used. |
| 70 | +#if defined(EQUEUE_PLATFORM_POSIX) |
| 71 | +typedef pthread_mutex_t equeue_mutex_t; |
| 72 | +#elif defined(EQUEUE_PLATFORM_WINDOWS) |
| 73 | +typedef CRITICAL_SECTION equeue_mutex_t; |
| 74 | +#elif defined(EQUEUE_PLATFORM_MBED) |
| 75 | +typedef unsigned equeue_mutex_t; |
| 76 | +#elif defined(EQUEUE_PLATFORM_FREERTOS) |
| 77 | +typedef UBaseType_t equeue_mutex_t; |
| 78 | +#endif |
| 79 | + |
| 80 | +// Platform mutex operations |
| 81 | +// |
| 82 | +// The equeue_mutex_create and equeue_mutex_destroy manage the lifetime |
| 83 | +// of the mutex. On error, equeue_mutex_create should return a negative |
| 84 | +// error code. |
| 85 | +// |
| 86 | +// The equeue_mutex_lock and equeue_mutex_unlock lock and unlock the |
| 87 | +// underlying mutex. |
| 88 | +int equeue_mutex_create(equeue_mutex_t *mutex); |
| 89 | +void equeue_mutex_destroy(equeue_mutex_t *mutex); |
| 90 | +void equeue_mutex_lock(equeue_mutex_t *mutex); |
| 91 | +void equeue_mutex_unlock(equeue_mutex_t *mutex); |
| 92 | + |
| 93 | + |
| 94 | +// Platform semaphore type |
| 95 | +// |
| 96 | +// The equeue library requires a binary semaphore type that can be safely |
| 97 | +// signaled from interrupt contexts and from inside a equeue_mutex section. |
| 98 | +// |
| 99 | +// The equeue_signal_wait is relied upon by the equeue library to sleep the |
| 100 | +// processor between events. Spurious wakeups have no negative-effects. |
| 101 | +// |
| 102 | +// A counting semaphore will also work, however may cause the event queue |
| 103 | +// dispatch loop to run unnecessarily. For that matter, equeue_signal_wait |
| 104 | +// may even be implemented as a single return statement. |
| 105 | +#if defined(EQUEUE_PLATFORM_POSIX) |
| 106 | +typedef struct equeue_sema { |
| 107 | + pthread_mutex_t mutex; |
| 108 | + pthread_cond_t cond; |
| 109 | + bool signal; |
| 110 | +} equeue_sema_t; |
| 111 | +#elif defined(EQUEUE_PLATFORM_WINDOWS) |
| 112 | +typedef HANDLE equeue_sema_t; |
| 113 | +#elif defined(EQUEUE_PLATFORM_MBED) && defined(MBED_CONF_RTOS_PRESENT) |
| 114 | +typedef unsigned equeue_sema_t[8]; |
| 115 | +#elif defined(EQUEUE_PLATFORM_MBED) |
| 116 | +typedef volatile int equeue_sema_t; |
| 117 | +#elif defined(EQUEUE_PLATFORM_FREERTOS) |
| 118 | +typedef struct equeue_sema { |
| 119 | + SemaphoreHandle_t handle; |
| 120 | + StaticSemaphore_t buffer; |
| 121 | +} equeue_sema_t; |
| 122 | +#endif |
| 123 | + |
| 124 | +// Platform semaphore operations |
| 125 | +// |
| 126 | +// The equeue_sema_create and equeue_sema_destroy manage the lifetime |
| 127 | +// of the semaphore. On error, equeue_sema_create should return a negative |
| 128 | +// error code. |
| 129 | +// |
| 130 | +// The equeue_sema_signal marks a semaphore as signalled such that the next |
| 131 | +// equeue_sema_wait will return true. |
| 132 | +// |
| 133 | +// The equeue_sema_wait waits for a semaphore to be signalled or returns |
| 134 | +// immediately if equeue_sema_signal had been called since the last |
| 135 | +// equeue_sema_wait. The equeue_sema_wait returns true if it detected that |
| 136 | +// equeue_sema_signal had been called. |
| 137 | +int equeue_sema_create(equeue_sema_t *sema); |
| 138 | +void equeue_sema_destroy(equeue_sema_t *sema); |
| 139 | +void equeue_sema_signal(equeue_sema_t *sema); |
| 140 | +bool equeue_sema_wait(equeue_sema_t *sema, int ms); |
| 141 | + |
| 142 | + |
| 143 | +#ifdef __cplusplus |
| 144 | +} |
| 145 | +#endif |
| 146 | + |
| 147 | +#endif |
0 commit comments