cmsis_os.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. /*
  2. ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
  3. This file is part of ChibiOS.
  4. ChibiOS is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. ChibiOS is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. /*
  16. Concepts and parts of this file have been contributed by Andre R.
  17. */
  18. /**
  19. * @file cmsis_os.c
  20. * @brief CMSIS RTOS module code.
  21. *
  22. * @addtogroup CMSIS_OS
  23. * @{
  24. */
  25. #include "cmsis_os.h"
  26. #include <string.h>
  27. /*===========================================================================*/
  28. /* Module local definitions. */
  29. /*===========================================================================*/
  30. /*===========================================================================*/
  31. /* Module exported variables. */
  32. /*===========================================================================*/
  33. int32_t cmsis_os_started;
  34. /*===========================================================================*/
  35. /* Module local types. */
  36. /*===========================================================================*/
  37. /*===========================================================================*/
  38. /* Module local variables. */
  39. /*===========================================================================*/
  40. static memory_pool_t sempool;
  41. static semaphore_t semaphores[CMSIS_CFG_NUM_SEMAPHORES];
  42. static memory_pool_t timpool;
  43. static struct os_timer_cb timers[CMSIS_CFG_NUM_TIMERS];
  44. /*===========================================================================*/
  45. /* Module local functions. */
  46. /*===========================================================================*/
  47. /**
  48. * @brief Virtual timers common callback.
  49. */
  50. static void timer_cb(void const *arg) {
  51. osTimerId timer_id = (osTimerId)arg;
  52. timer_id->ptimer(timer_id->argument);
  53. if (timer_id->type == osTimerPeriodic) {
  54. chSysLockFromISR();
  55. chVTDoSetI(&timer_id->vt, TIME_MS2I(timer_id->millisec),
  56. (vtfunc_t)timer_cb, timer_id);
  57. chSysUnlockFromISR();
  58. }
  59. }
  60. /*===========================================================================*/
  61. /* Module exported functions. */
  62. /*===========================================================================*/
  63. /**
  64. * @brief Kernel initialization.
  65. */
  66. osStatus osKernelInitialize(void) {
  67. cmsis_os_started = 0;
  68. chSysInit();
  69. chThdSetPriority(HIGHPRIO);
  70. chPoolObjectInit(&sempool, sizeof(semaphore_t), chCoreAllocAligned);
  71. chPoolLoadArray(&sempool, semaphores, CMSIS_CFG_NUM_SEMAPHORES);
  72. chPoolObjectInit(&timpool, sizeof(struct os_timer_cb), chCoreAllocAligned);
  73. chPoolLoadArray(&timpool, timers, CMSIS_CFG_NUM_TIMERS);
  74. return osOK;
  75. }
  76. /**
  77. * @brief Kernel start.
  78. */
  79. osStatus osKernelStart(void) {
  80. cmsis_os_started = 1;
  81. chThdSetPriority(NORMALPRIO);
  82. return osOK;
  83. }
  84. /**
  85. * @brief Creates a thread.
  86. */
  87. osThreadId osThreadCreate(const osThreadDef_t *thread_def, void *argument) {
  88. size_t size;
  89. size = thread_def->stacksize == 0 ? CMSIS_CFG_DEFAULT_STACK :
  90. thread_def->stacksize;
  91. return (osThreadId)chThdCreateFromHeap(0,
  92. THD_WORKING_AREA_SIZE(size),
  93. thread_def->name,
  94. NORMALPRIO+thread_def->tpriority,
  95. (tfunc_t)thread_def->pthread,
  96. argument);
  97. }
  98. /**
  99. * @brief Thread termination.
  100. * @note The thread is not really terminated but asked to terminate which
  101. * is not compliant.
  102. */
  103. osStatus osThreadTerminate(osThreadId thread_id) {
  104. if (thread_id == osThreadGetId()) {
  105. /* Note, no memory will be recovered unless a cleaner thread is
  106. implemented using the registry.*/
  107. chThdExit(0);
  108. }
  109. chThdTerminate(thread_id);
  110. chThdWait((thread_t *)thread_id);
  111. return osOK;
  112. }
  113. /**
  114. * @brief Change thread priority.
  115. * @note This can interfere with the priority inheritance mechanism.
  116. */
  117. osStatus osThreadSetPriority(osThreadId thread_id, osPriority newprio) {
  118. thread_t * tp = (thread_t *)thread_id;
  119. chSysLock();
  120. /* Changing priority.*/
  121. #if CH_CFG_USE_MUTEXES
  122. if ((tp->prio == tp->realprio) || ((tprio_t)newprio > tp->prio))
  123. tp->prio = (tprio_t)newprio;
  124. tp->realprio = (tprio_t)newprio;
  125. #else
  126. tp->prio = (tprio_t)newprio;
  127. #endif
  128. /* The following states need priority queues reordering.*/
  129. switch (tp->state) {
  130. #if CH_CFG_USE_MUTEXES | \
  131. CH_CFG_USE_CONDVARS | \
  132. (CH_CFG_USE_SEMAPHORES && CH_CFG_USE_SEMAPHORES_PRIORITY) | \
  133. (CH_CFG_USE_MESSAGES && CH_CFG_USE_MESSAGES_PRIORITY)
  134. #if CH_CFG_USE_MUTEXES
  135. case CH_STATE_WTMTX:
  136. #endif
  137. #if CH_CFG_USE_CONDVARS
  138. case CH_STATE_WTCOND:
  139. #endif
  140. #if CH_CFG_USE_SEMAPHORES && CH_CFG_USE_SEMAPHORES_PRIORITY
  141. case CH_STATE_WTSEM:
  142. #endif
  143. #if CH_CFG_USE_MESSAGES && CH_CFG_USE_MESSAGES_PRIORITY
  144. case CH_STATE_SNDMSGQ:
  145. #endif
  146. /* Re-enqueues tp with its new priority on the queue.*/
  147. queue_prio_insert(queue_dequeue(tp),
  148. (threads_queue_t *)tp->u.wtobjp);
  149. break;
  150. #endif
  151. case CH_STATE_READY:
  152. #if CH_DBG_ENABLE_ASSERTS
  153. /* Prevents an assertion in chSchReadyI().*/
  154. tp->state = CH_STATE_CURRENT;
  155. #endif
  156. /* Re-enqueues tp with its new priority on the ready list.*/
  157. chSchReadyI(queue_dequeue(tp));
  158. break;
  159. }
  160. /* Rescheduling.*/
  161. chSchRescheduleS();
  162. chSysUnlock();
  163. return osOK;
  164. }
  165. /**
  166. * @brief Create a timer.
  167. */
  168. osTimerId osTimerCreate(const osTimerDef_t *timer_def,
  169. os_timer_type type,
  170. void *argument) {
  171. osTimerId timer = chPoolAlloc(&timpool);
  172. chVTObjectInit(&timer->vt);
  173. timer->ptimer = timer_def->ptimer;
  174. timer->type = type;
  175. timer->argument = argument;
  176. return timer;
  177. }
  178. /**
  179. * @brief Start a timer.
  180. */
  181. osStatus osTimerStart(osTimerId timer_id, uint32_t millisec) {
  182. if ((millisec == 0) || (millisec == osWaitForever))
  183. return osErrorValue;
  184. timer_id->millisec = millisec;
  185. chVTSet(&timer_id->vt, TIME_MS2I(millisec), (vtfunc_t)timer_cb, timer_id);
  186. return osOK;
  187. }
  188. /**
  189. * @brief Stop a timer.
  190. */
  191. osStatus osTimerStop(osTimerId timer_id) {
  192. chVTReset(&timer_id->vt);
  193. return osOK;
  194. }
  195. /**
  196. * @brief Delete a timer.
  197. */
  198. osStatus osTimerDelete(osTimerId timer_id) {
  199. chVTReset(&timer_id->vt);
  200. chPoolFree(&timpool, (void *)timer_id);
  201. return osOK;
  202. }
  203. /**
  204. * @brief Send signals.
  205. */
  206. int32_t osSignalSet(osThreadId thread_id, int32_t signals) {
  207. int32_t oldsignals;
  208. syssts_t sts = chSysGetStatusAndLockX();
  209. oldsignals = (int32_t)thread_id->epending;
  210. chEvtSignalI((thread_t *)thread_id, (eventmask_t)signals);
  211. chSysRestoreStatusX(sts);
  212. return oldsignals;
  213. }
  214. /**
  215. * @brief Clear signals.
  216. */
  217. int32_t osSignalClear(osThreadId thread_id, int32_t signals) {
  218. eventmask_t m;
  219. chSysLock();
  220. m = thread_id->epending & (eventmask_t)signals;
  221. thread_id->epending &= ~(eventmask_t)signals;
  222. chSysUnlock();
  223. return (int32_t)m;
  224. }
  225. /**
  226. * @brief Wait for signals.
  227. */
  228. osEvent osSignalWait(int32_t signals, uint32_t millisec) {
  229. osEvent event;
  230. sysinterval_t timeout = (millisec == osWaitForever ?
  231. TIME_INFINITE : (millisec == 0 ? TIME_IMMEDIATE :
  232. TIME_MS2I(millisec)));
  233. if (signals == 0)
  234. event.value.signals = (uint32_t)chEvtWaitAnyTimeout(ALL_EVENTS, timeout);
  235. else
  236. event.value.signals = (uint32_t)chEvtWaitAllTimeout((eventmask_t)signals,
  237. timeout);
  238. /* Type of event.*/
  239. if (event.value.signals == 0)
  240. event.status = osEventTimeout;
  241. else
  242. event.status = osEventSignal;
  243. return event;
  244. }
  245. /**
  246. * @brief Create a semaphore.
  247. * @note @p semaphore_def is not used.
  248. * @note Can involve memory allocation.
  249. */
  250. osSemaphoreId osSemaphoreCreate(const osSemaphoreDef_t *semaphore_def,
  251. int32_t count) {
  252. (void)semaphore_def;
  253. semaphore_t *sem = chPoolAlloc(&sempool);
  254. chSemObjectInit(sem, (cnt_t)count);
  255. return sem;
  256. }
  257. /**
  258. * @brief Wait on a semaphore.
  259. */
  260. int32_t osSemaphoreWait(osSemaphoreId semaphore_id, uint32_t millisec) {
  261. sysinterval_t timeout = (millisec == osWaitForever ?
  262. TIME_INFINITE : (millisec == 0 ? TIME_IMMEDIATE :
  263. TIME_MS2I(millisec)));
  264. msg_t msg = chSemWaitTimeout((semaphore_t *)semaphore_id, timeout);
  265. switch (msg) {
  266. case MSG_OK:
  267. return osOK;
  268. case MSG_TIMEOUT:
  269. return osErrorTimeoutResource;
  270. }
  271. return osErrorResource;
  272. }
  273. /**
  274. * @brief Release a semaphore.
  275. */
  276. osStatus osSemaphoreRelease(osSemaphoreId semaphore_id) {
  277. syssts_t sts = chSysGetStatusAndLockX();
  278. chSemSignalI((semaphore_t *)semaphore_id);
  279. chSysRestoreStatusX(sts);
  280. return osOK;
  281. }
  282. /**
  283. * @brief Deletes a semaphore.
  284. * @note After deletion there could be references in the system to a
  285. * non-existent semaphore.
  286. */
  287. osStatus osSemaphoreDelete(osSemaphoreId semaphore_id) {
  288. chSemReset((semaphore_t *)semaphore_id, 0);
  289. chPoolFree(&sempool, (void *)semaphore_id);
  290. return osOK;
  291. }
  292. /**
  293. * @brief Create a mutex.
  294. * @note @p mutex_def is not used.
  295. * @note Can involve memory allocation.
  296. */
  297. osMutexId osMutexCreate(const osMutexDef_t *mutex_def) {
  298. (void)mutex_def;
  299. binary_semaphore_t *mtx = chPoolAlloc(&sempool);
  300. chBSemObjectInit(mtx, false);
  301. return mtx;
  302. }
  303. /**
  304. * @brief Wait on a mutex.
  305. */
  306. osStatus osMutexWait(osMutexId mutex_id, uint32_t millisec) {
  307. sysinterval_t timeout = (millisec == osWaitForever ?
  308. TIME_INFINITE : (millisec == 0 ? TIME_IMMEDIATE :
  309. TIME_MS2I(millisec)));
  310. msg_t msg = chBSemWaitTimeout((binary_semaphore_t *)mutex_id, timeout);
  311. switch (msg) {
  312. case MSG_OK:
  313. return osOK;
  314. case MSG_TIMEOUT:
  315. return osErrorTimeoutResource;
  316. }
  317. return osErrorResource;
  318. }
  319. /**
  320. * @brief Release a mutex.
  321. */
  322. osStatus osMutexRelease(osMutexId mutex_id) {
  323. syssts_t sts = chSysGetStatusAndLockX();
  324. chBSemSignalI((binary_semaphore_t *)mutex_id);
  325. chSysRestoreStatusX(sts);
  326. return osOK;
  327. }
  328. /**
  329. * @brief Deletes a mutex.
  330. * @note After deletion there could be references in the system to a
  331. * non-existent semaphore.
  332. */
  333. osStatus osMutexDelete(osMutexId mutex_id) {
  334. chSemReset((semaphore_t *)mutex_id, 0);
  335. chPoolFree(&sempool, (void *)mutex_id);
  336. return osOK;
  337. }
  338. /**
  339. * @brief Create a memory pool.
  340. * @note The pool is not really created because it is allocated statically,
  341. * this function just re-initializes it.
  342. */
  343. osPoolId osPoolCreate(const osPoolDef_t *pool_def) {
  344. chPoolObjectInit(pool_def->pool, (size_t)pool_def->item_sz, NULL);
  345. chPoolLoadArray(pool_def->pool, pool_def->items, (size_t)pool_def->pool_sz);
  346. return (osPoolId)pool_def->pool;
  347. }
  348. /**
  349. * @brief Allocate an object.
  350. */
  351. void *osPoolAlloc(osPoolId pool_id) {
  352. void *object;
  353. syssts_t sts = chSysGetStatusAndLockX();
  354. object = chPoolAllocI((memory_pool_t *)pool_id);
  355. chSysRestoreStatusX(sts);
  356. return object;
  357. }
  358. /**
  359. * @brief Allocate an object clearing it.
  360. */
  361. void *osPoolCAlloc(osPoolId pool_id) {
  362. void *object;
  363. object = chPoolAllocI((memory_pool_t *)pool_id);
  364. memset(object, 0, pool_id->object_size);
  365. return object;
  366. }
  367. /**
  368. * @brief Free an object.
  369. */
  370. osStatus osPoolFree(osPoolId pool_id, void *block) {
  371. syssts_t sts = chSysGetStatusAndLockX();
  372. chPoolFreeI((memory_pool_t *)pool_id, block);
  373. chSysRestoreStatusX(sts);
  374. return osOK;
  375. }
  376. /**
  377. * @brief Create a message queue.
  378. * @note The queue is not really created because it is allocated statically,
  379. * this function just re-initializes it.
  380. */
  381. osMessageQId osMessageCreate(const osMessageQDef_t *queue_def,
  382. osThreadId thread_id) {
  383. /* Ignoring this parameter for now.*/
  384. (void)thread_id;
  385. if (queue_def->item_sz > sizeof (msg_t))
  386. return NULL;
  387. chMBObjectInit(queue_def->mailbox,
  388. queue_def->items,
  389. (size_t)queue_def->queue_sz);
  390. return (osMessageQId) queue_def->mailbox;
  391. }
  392. /**
  393. * @brief Put a message in the queue.
  394. */
  395. osStatus osMessagePut(osMessageQId queue_id,
  396. uint32_t info,
  397. uint32_t millisec) {
  398. msg_t msg;
  399. sysinterval_t timeout = (millisec == osWaitForever ?
  400. TIME_INFINITE : (millisec == 0 ? TIME_IMMEDIATE :
  401. TIME_MS2I(millisec)));
  402. if (port_is_isr_context()) {
  403. /* Waiting makes no sense in ISRs so any value except "immediate"
  404. makes no sense.*/
  405. if (millisec != 0)
  406. return osErrorValue;
  407. chSysLockFromISR();
  408. msg = chMBPostI((mailbox_t *)queue_id, (msg_t)info);
  409. chSysUnlockFromISR();
  410. }
  411. else
  412. msg = chMBPostTimeout((mailbox_t *)queue_id, (msg_t)info, timeout);
  413. return msg == MSG_OK ? osOK : osEventTimeout;
  414. }
  415. /**
  416. * @brief Get a message from the queue.
  417. */
  418. osEvent osMessageGet(osMessageQId queue_id,
  419. uint32_t millisec) {
  420. msg_t msg;
  421. osEvent event;
  422. sysinterval_t timeout = (millisec == osWaitForever ?
  423. TIME_INFINITE : (millisec == 0 ? TIME_IMMEDIATE :
  424. TIME_MS2I(millisec)));
  425. event.def.message_id = queue_id;
  426. if (port_is_isr_context()) {
  427. /* Waiting makes no sense in ISRs so any value except "immediate"
  428. makes no sense.*/
  429. if (millisec != 0) {
  430. event.status = osErrorValue;
  431. return event;
  432. }
  433. chSysLockFromISR();
  434. msg = chMBFetchI((mailbox_t *)queue_id, (msg_t*)&event.value.v);
  435. chSysUnlockFromISR();
  436. }
  437. else {
  438. msg = chMBFetchTimeout((mailbox_t *)queue_id, (msg_t*)&event.value.v, timeout);
  439. }
  440. /* Returned event type.*/
  441. event.status = msg == MSG_OK ? osEventMessage : osEventTimeout;
  442. return event;
  443. }
  444. /** @} */