aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--os/kernel/include/ch.h1
-rw-r--r--os/kernel/include/chdynamic.h67
-rw-r--r--os/kernel/include/chthreads.h27
-rw-r--r--os/kernel/src/chdynamic.c190
-rw-r--r--os/kernel/src/chsys.c2
-rw-r--r--os/kernel/src/chthreads.c172
-rw-r--r--readme.txt2
-rw-r--r--todo.txt19
8 files changed, 287 insertions, 193 deletions
diff --git a/os/kernel/include/ch.h b/os/kernel/include/ch.h
index 07fc070d1..24b669333 100644
--- a/os/kernel/include/ch.h
+++ b/os/kernel/include/ch.h
@@ -84,6 +84,7 @@
#include "chheap.h"
#include "chmempools.h"
#include "chthreads.h"
+#include "chdynamic.h"
#include "chregistry.h"
#include "chinline.h"
#include "chqueues.h"
diff --git a/os/kernel/include/chdynamic.h b/os/kernel/include/chdynamic.h
new file mode 100644
index 000000000..76de4ae09
--- /dev/null
+++ b/os/kernel/include/chdynamic.h
@@ -0,0 +1,67 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file chdynamic.h
+ * @brief Dynamic threads macros and structures.
+ *
+ * @addtogroup dynamic_threads
+ * @{
+ */
+
+#ifndef _CHDYNAMIC_H_
+#define _CHDYNAMIC_H_
+
+#if CH_USE_DYNAMIC || defined(__DOXYGEN__)
+
+/*
+ * Module dependencies check.
+ */
+#if CH_USE_DYNAMIC && !CH_USE_WAITEXIT
+#error "CH_USE_DYNAMIC requires CH_USE_WAITEXIT"
+#endif
+#if CH_USE_DYNAMIC && !CH_USE_HEAP && !CH_USE_MEMPOOLS
+#error "CH_USE_DYNAMIC requires CH_USE_HEAP and/or CH_USE_MEMPOOLS"
+#endif
+
+/*
+ * Dynamic threads APIs.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+ Thread *chThdAddRef(Thread *tp);
+ void chThdRelease(Thread *tp);
+#if CH_USE_HEAP
+ Thread *chThdCreateFromHeap(MemoryHeap *heapp, size_t size,
+ tprio_t prio, tfunc_t pf, void *arg);
+#endif
+#if CH_USE_MEMPOOLS
+ Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
+ tfunc_t pf, void *arg);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CH_USE_DYNAMIC */
+
+#endif /* _CHDYNAMIC_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chthreads.h b/os/kernel/include/chthreads.h
index e862c8c1a..677f0be58 100644
--- a/os/kernel/include/chthreads.h
+++ b/os/kernel/include/chthreads.h
@@ -28,16 +28,6 @@
#ifndef _CHTHREADS_H_
#define _CHTHREADS_H_
-/*
- * Module dependencies check.
- */
-#if CH_USE_DYNAMIC && !CH_USE_WAITEXIT
-#error "CH_USE_DYNAMIC requires CH_USE_WAITEXIT"
-#endif
-#if CH_USE_DYNAMIC && !CH_USE_HEAP && !CH_USE_MEMPOOLS
-#error "CH_USE_DYNAMIC requires CH_USE_HEAP and/or CH_USE_MEMPOOLS"
-#endif
-
/**
* @extends ThreadsQueue
*
@@ -211,19 +201,14 @@ typedef msg_t (*tfunc_t)(void *);
#ifdef __cplusplus
extern "C" {
#endif
- Thread *init_thread(Thread *tp, tprio_t prio);
+ Thread *_thread_init(Thread *tp, tprio_t prio);
+#if CH_DBG_FILL_THREADS
+ void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v);
+#endif
Thread *chThdCreateI(void *wsp, size_t size,
tprio_t prio, tfunc_t pf, void *arg);
Thread *chThdCreateStatic(void *wsp, size_t size,
tprio_t prio, tfunc_t pf, void *arg);
-#if CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_HEAP
- Thread *chThdCreateFromHeap(MemoryHeap *heapp, size_t size,
- tprio_t prio, tfunc_t pf, void *arg);
-#endif
-#if CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_MEMPOOLS
- Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
- tfunc_t pf, void *arg);
-#endif
tprio_t chThdSetPriority(tprio_t newprio);
Thread *chThdResume(Thread *tp);
void chThdTerminate(Thread *tp);
@@ -231,10 +216,6 @@ extern "C" {
void chThdSleepUntil(systime_t time);
void chThdYield(void);
void chThdExit(msg_t msg);
-#if CH_USE_DYNAMIC
- Thread *chThdAddRef(Thread *tp);
- void chThdRelease(Thread *tp);
-#endif
#if CH_USE_WAITEXIT
msg_t chThdWait(Thread *tp);
#endif
diff --git a/os/kernel/src/chdynamic.c b/os/kernel/src/chdynamic.c
new file mode 100644
index 000000000..fba8a0278
--- /dev/null
+++ b/os/kernel/src/chdynamic.c
@@ -0,0 +1,190 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file chdynamic.c
+ * @brief Dynamic threads code.
+ *
+ * @addtogroup dynamic_threads
+ * @details Dynamic threads related APIs and services.
+ * @{
+ */
+
+#include "ch.h"
+
+#if CH_USE_DYNAMIC || defined(__DOXYGEN__)
+
+/**
+ * @brief Adds a reference to a thread object.
+ * @pre The configuration option @p CH_USE_DYNAMIC must be enabled in order
+ * to use this function.
+ *
+ * @param[in] tp pointer to the thread
+ * @return The same thread pointer passed as parameter
+ * representing the new reference.
+ *
+ * @api
+ */
+Thread *chThdAddRef(Thread *tp) {
+
+ chSysLock();
+ chDbgAssert(tp->p_refs < 255, "chThdAddRef(), #1", "too many references");
+ tp->p_refs++;
+ chSysUnlock();
+ return tp;
+}
+
+/**
+ * @brief Releases a reference to a thread object.
+ * @details If the references counter reaches zero <b>and</b> the thread
+ * is in the @p THD_STATE_FINAL state then the thread's memory is
+ * returned to the proper allocator.
+ * @pre The configuration option @p CH_USE_DYNAMIC must be enabled in order
+ * to use this function.
+ * @note Static threads are not affected.
+ *
+ * @param[in] tp pointer to the thread
+ *
+ * @api
+ */
+void chThdRelease(Thread *tp) {
+ trefs_t refs;
+
+ chSysLock();
+ chDbgAssert(tp->p_refs > 0, "chThdRelease(), #1", "not referenced");
+ refs = --tp->p_refs;
+ chSysUnlock();
+
+ /* If the references counter reaches zero then the memory can be returned
+ to the proper allocator. Of course static threads are not affected.*/
+ if (refs == 0) {
+ switch (tp->p_flags & THD_MEM_MODE_MASK) {
+#if CH_USE_HEAP
+ case THD_MEM_MODE_HEAP:
+ chHeapFree(tp);
+ break;
+#endif
+#if CH_USE_MEMPOOLS
+ case THD_MEM_MODE_MEMPOOL:
+ chPoolFree(tp->p_mpool, tp);
+ break;
+#endif
+ }
+ }
+}
+
+#if CH_USE_HEAP || defined(__DOXYGEN__)
+/**
+ * @brief Creates a new thread allocating the memory from the heap.
+ * @pre The configuration options @p CH_USE_DYNAMIC and @p CH_USE_HEAP
+ * must be enabled in order to use this function.
+ * @note A thread can terminate by calling @p chThdExit() or by simply
+ * returning from its main function.
+ * @note The memory allocated for the thread is not released when the thread
+ * terminates but when a @p chThdWait() is performed.
+ *
+ * @param[in] heapp heap from which allocate the memory or @p NULL for the
+ * default heap
+ * @param[in] size size of the working area to be allocated
+ * @param[in] prio the priority level for the new thread
+ * @param[in] pf the thread function
+ * @param[in] arg an argument passed to the thread function. It can be
+ * @p NULL.
+ * @return The pointer to the @p Thread structure allocated for
+ * the thread into the working space area.
+ * @retval NULL if the memory cannot be allocated.
+ *
+ * @api
+ */
+Thread *chThdCreateFromHeap(MemoryHeap *heapp, size_t size,
+ tprio_t prio, tfunc_t pf, void *arg) {
+ void *wsp;
+ Thread *tp;
+
+ wsp = chHeapAlloc(heapp, size);
+ if (wsp == NULL)
+ return NULL;
+
+#if CH_DBG_FILL_THREADS
+ memfill((uint8_t *)wsp, (uint8_t *)wsp + sizeof(Thread), THREAD_FILL_VALUE);
+ memfill((uint8_t *)wsp + sizeof(Thread),
+ (uint8_t *)wsp + size, STACK_FILL_VALUE);
+#endif
+
+ chSysLock();
+ tp = chThdCreateI(wsp, size, prio, pf, arg);
+ tp->p_flags = THD_MEM_MODE_HEAP;
+ chSchWakeupS(tp, RDY_OK);
+ chSysUnlock();
+ return tp;
+}
+#endif /* CH_USE_HEAP */
+
+#if CH_USE_MEMPOOLS || defined(__DOXYGEN__)
+/**
+ * @brief Creates a new thread allocating the memory from the specified
+ * memory pool.
+ * @pre The configuration options @p CH_USE_DYNAMIC and @p CH_USE_MEMPOOLS
+ * must be enabled in order to use this function.
+ * @note A thread can terminate by calling @p chThdExit() or by simply
+ * returning from its main function.
+ * @note The memory allocated for the thread is not released when the thread
+ * terminates but when a @p chThdWait() is performed.
+ *
+ * @param[in] mp pointer to the memory pool object
+ * @param[in] prio the priority level for the new thread
+ * @param[in] pf the thread function
+ * @param[in] arg an argument passed to the thread function. It can be
+ * @p NULL.
+ * @return The pointer to the @p Thread structure allocated for
+ * the thread into the working space area.
+ * @retval NULL if the memory pool is empty.
+ *
+ * @api
+ */
+Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
+ tfunc_t pf, void *arg) {
+ void *wsp;
+ Thread *tp;
+
+ chDbgCheck(mp != NULL, "chThdCreateFromMemoryPool");
+
+ wsp = chPoolAlloc(mp);
+ if (wsp == NULL)
+ return NULL;
+
+#if CH_DBG_FILL_THREADS
+ memfill((uint8_t *)wsp, (uint8_t *)wsp + sizeof(Thread), THREAD_FILL_VALUE);
+ memfill((uint8_t *)wsp + sizeof(Thread),
+ (uint8_t *)wsp + mp->mp_object_size, STACK_FILL_VALUE);
+#endif
+
+ chSysLock();
+ tp = chThdCreateI(wsp, mp->mp_object_size, prio, pf, arg);
+ tp->p_flags = THD_MEM_MODE_MEMPOOL;
+ tp->p_mpool = mp;
+ chSchWakeupS(tp, RDY_OK);
+ chSysUnlock();
+ return tp;
+}
+#endif /* CH_USE_MEMPOOLS */
+
+#endif /* CH_USE_DYNAMIC */
+
+/** @} */
diff --git a/os/kernel/src/chsys.c b/os/kernel/src/chsys.c
index a567b73da..9d3ec1929 100644
--- a/os/kernel/src/chsys.c
+++ b/os/kernel/src/chsys.c
@@ -88,7 +88,7 @@ void chSysInit(void) {
#endif
/* Now this instructions flow becomes the main thread.*/
- setcurrp(init_thread(&mainthread, NORMALPRIO));
+ setcurrp(_thread_init(&mainthread, NORMALPRIO));
currp->p_state = THD_STATE_CURRENT;
chSysEnable();
diff --git a/os/kernel/src/chthreads.c b/os/kernel/src/chthreads.c
index 00f9704aa..65468a3b2 100644
--- a/os/kernel/src/chthreads.c
+++ b/os/kernel/src/chthreads.c
@@ -67,7 +67,7 @@
*
* @notapi
*/
-Thread *init_thread(Thread *tp, tprio_t prio) {
+Thread *_thread_init(Thread *tp, tprio_t prio) {
tp->p_prio = prio;
tp->p_state = THD_STATE_SUSPENDED;
@@ -103,13 +103,18 @@ Thread *init_thread(Thread *tp, tprio_t prio) {
return tp;
}
-#if CH_DBG_FILL_THREADS
-static void memfill(uint8_t *startp, uint8_t *endp, uint8_t v) {
+#if CH_DBG_FILL_THREADS || defined(__DOXYGEN__)
+/**
+ * @brief Memory fill utility.
+ *
+ * @notapi
+ */
+void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v) {
while (startp < endp)
*startp++ = v;
}
-#endif
+#endif /* CH_DBG_FILL_THREADS */
/**
* @brief Creates a new thread into a static memory area.
@@ -144,7 +149,7 @@ Thread *chThdCreateI(void *wsp, size_t size,
(prio <= HIGHPRIO) && (pf != NULL),
"chThdCreateI");
SETUP_CONTEXT(wsp, size, pf, arg);
- return init_thread(tp, prio);
+ return _thread_init(tp, prio);
}
/**
@@ -178,102 +183,6 @@ Thread *chThdCreateStatic(void *wsp, size_t size,
return tp;
}
-#if CH_USE_DYNAMIC && CH_USE_HEAP
-/**
- * @brief Creates a new thread allocating the memory from the heap.
- * @pre The configuration options @p CH_USE_DYNAMIC and @p CH_USE_HEAP
- * must be enabled in order to use this function.
- * @note A thread can terminate by calling @p chThdExit() or by simply
- * returning from its main function.
- * @note The memory allocated for the thread is not released when the thread
- * terminates but when a @p chThdWait() is performed.
- *
- * @param[in] heapp heap from which allocate the memory or @p NULL for the
- * default heap
- * @param[in] size size of the working area to be allocated
- * @param[in] prio the priority level for the new thread
- * @param[in] pf the thread function
- * @param[in] arg an argument passed to the thread function. It can be
- * @p NULL.
- * @return The pointer to the @p Thread structure allocated for
- * the thread into the working space area.
- * @retval NULL if the memory cannot be allocated.
- *
- * @api
- */
-Thread *chThdCreateFromHeap(MemoryHeap *heapp, size_t size,
- tprio_t prio, tfunc_t pf, void *arg) {
- void *wsp;
- Thread *tp;
-
- wsp = chHeapAlloc(heapp, size);
- if (wsp == NULL)
- return NULL;
-
-#if CH_DBG_FILL_THREADS
- memfill((uint8_t *)wsp, (uint8_t *)wsp + sizeof(Thread), THREAD_FILL_VALUE);
- memfill((uint8_t *)wsp + sizeof(Thread),
- (uint8_t *)wsp + size, STACK_FILL_VALUE);
-#endif
-
- chSysLock();
- tp = chThdCreateI(wsp, size, prio, pf, arg);
- tp->p_flags = THD_MEM_MODE_HEAP;
- chSchWakeupS(tp, RDY_OK);
- chSysUnlock();
- return tp;
-}
-#endif /* CH_USE_DYNAMIC && CH_USE_HEAP */
-
-#if CH_USE_DYNAMIC && CH_USE_MEMPOOLS
-/**
- * @brief Creates a new thread allocating the memory from the specified
- * memory pool.
- * @pre The configuration options @p CH_USE_DYNAMIC and @p CH_USE_MEMPOOLS
- * must be enabled in order to use this function.
- * @note A thread can terminate by calling @p chThdExit() or by simply
- * returning from its main function.
- * @note The memory allocated for the thread is not released when the thread
- * terminates but when a @p chThdWait() is performed.
- *
- * @param[in] mp pointer to the memory pool object
- * @param[in] prio the priority level for the new thread
- * @param[in] pf the thread function
- * @param[in] arg an argument passed to the thread function. It can be
- * @p NULL.
- * @return The pointer to the @p Thread structure allocated for
- * the thread into the working space area.
- * @retval NULL if the memory pool is empty.
- *
- * @api
- */
-Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
- tfunc_t pf, void *arg) {
- void *wsp;
- Thread *tp;
-
- chDbgCheck(mp != NULL, "chThdCreateFromMemoryPool");
-
- wsp = chPoolAlloc(mp);
- if (wsp == NULL)
- return NULL;
-
-#if CH_DBG_FILL_THREADS
- memfill((uint8_t *)wsp, (uint8_t *)wsp + sizeof(Thread), THREAD_FILL_VALUE);
- memfill((uint8_t *)wsp + sizeof(Thread),
- (uint8_t *)wsp + mp->mp_object_size, STACK_FILL_VALUE);
-#endif
-
- chSysLock();
- tp = chThdCreateI(wsp, mp->mp_object_size, prio, pf, arg);
- tp->p_flags = THD_MEM_MODE_MEMPOOL;
- tp->p_mpool = mp;
- chSchWakeupS(tp, RDY_OK);
- chSysUnlock();
- return tp;
-}
-#endif /* CH_USE_DYNAMIC && CH_USE_MEMPOOLS */
-
/**
* @brief Changes the running thread priority level then reschedules if
* necessary.
@@ -435,67 +344,6 @@ void chThdExit(msg_t msg) {
chSchGoSleepS(THD_STATE_FINAL);
}
-#if CH_USE_DYNAMIC || defined(__DOXYGEN__)
-/**
- * @brief Adds a reference to a thread object.
- * @pre The configuration option @p CH_USE_DYNAMIC must be enabled in order
- * to use this function.
- *
- * @param[in] tp pointer to the thread
- * @return The same thread pointer passed as parameter
- * representing the new reference.
- *
- * @api
- */
-Thread *chThdAddRef(Thread *tp) {
-
- chSysLock();
- chDbgAssert(tp->p_refs < 255, "chThdAddRef(), #1", "too many references");
- tp->p_refs++;
- chSysUnlock();
- return tp;
-}
-
-/**
- * @brief Releases a reference to a thread object.
- * @details If the references counter reaches zero <b>and</b> the thread
- * is in the @p THD_STATE_FINAL state then the thread's memory is
- * returned to the proper allocator.
- * @pre The configuration option @p CH_USE_DYNAMIC must be enabled in order
- * to use this function.
- * @note Static threads are not affected.
- *
- * @param[in] tp pointer to the thread
- *
- * @api
- */
-void chThdRelease(Thread *tp) {
- trefs_t refs;
-
- chSysLock();
- chDbgAssert(tp->p_refs > 0, "chThdRelease(), #1", "not referenced");
- refs = --tp->p_refs;
- chSysUnlock();
-
- /* If the references counter reaches zero then the memory can be returned
- to the proper allocator. Of course static threads are not affected.*/
- if (refs == 0) {
- switch (tp->p_flags & THD_MEM_MODE_MASK) {
-#if CH_USE_HEAP
- case THD_MEM_MODE_HEAP:
- chHeapFree(tp);
- break;
-#endif
-#if CH_USE_MEMPOOLS
- case THD_MEM_MODE_MEMPOOL:
- chPoolFree(tp->p_mpool, tp);
- break;
-#endif
- }
- }
-}
-#endif /* CH_USE_DYNAMIC */
-
#if CH_USE_WAITEXIT || defined(__DOXYGEN__)
/**
* @brief Blocks the execution of the invoking thread until the specified
diff --git a/readme.txt b/readme.txt
index 6c4ab58e3..d8b987abd 100644
--- a/readme.txt
+++ b/readme.txt
@@ -65,6 +65,8 @@
*****************************************************************************
*** 2.1.4 ***
+- CHANGE: Separated dynamic threads code into dedicated files: chdynamic.c
+ and chdynamic.h.
- Added SPI driver to the STM8 documentation, it was missing.
*** 2.1.3 ***
diff --git a/todo.txt b/todo.txt
index 59eee785e..edb6a1c9f 100644
--- a/todo.txt
+++ b/todo.txt
@@ -42,7 +42,7 @@ N Evaluate if to add a synchronous API to the UART driver, eventually do so.
* Reorganization of the STM32 family port-level support.
* Remove preprocessor directives from the assembler files and restore the
RIDE7 build files in the STM32 demo.
-- Evaluate moving dynamic APIs into a separate source file.
+* Move dynamic APIs into a separate source file.
X STM8L official HAL support, it will have to be separated from the STM8S/STM8A
HAL because it is very different.
X Shared ISR management.
@@ -50,22 +50,28 @@ X STM8L official HAL support, it will have to be separated from the STM8S/STM8A
X STM8L-Discovery demo.
- Realign the STM8 port to the new STM8L one as options, naming conventions
and general solutions.
-X Add the STM32F100 (Value Line) to the official STM32 HAL support.
+- Improved support in the STM32 HAL support for multiple sub-families. Do
+ not check for the family in the various drivers but simply check for
+ switch macros like STM32_HAS_USART3, STM32_HAS_SPI3. This what the
+ drivers will not need changes when adding new sub-families.
+X Add the STM32F100 (Value Line) sub-family to the official STM32 HAL support.
- STM32VL-Discovery demo.
X Except for the above, bug fixing only until the 2.2.0 release.
Within 2.3.x (hopefully)
- Resist doing more changes and optimizations to the kernel.
+- Add a switch to enable/disable the priority inheritance algorithm in mutexes.
X File System infrastructure.
- Official FatFs wrapper using the new infrastructure, dedicated test suite.
-X I2C device driver class support and at least one implementation (test
- hardware missing).
+X Transactional flash file system implementation.
+X I2C device driver class support and at least one implementation.
+- Switch for turning off priority inheritance protocol on mutexes.
- Serial over UART complex driver driver, evaluate from the performance
results if to make obsolete the current dedicated Serial driver.
- Shared DMA channels support in the STM32/STM8L HALs.
-- New device driver models: RTC, WDG, DAC, USB, Systick, Battery Monitor.
+- New device driver models: Clock, Systick, RTC, WDG, DAC, USB, Power Monitor.
- MAC driver for STM32F107 (hardware missing).
-- Device drivers for STM8/STM8L (SPI, ADC, PWM, bring it on par with STM32).
+- Device drivers for STM8/STM8L (ADC, PWM, bring them on par with STM32).
- Support for more compilers (ARMCMx only initially).
- Support for not just Makefiles (Ride7, Crossworks etc).
- Batch testing of the ARM7/ARMCMx port using OpenOCD, with reports.
@@ -76,7 +82,6 @@ X I2C device driver class support and at least one implementation (test
- Threads Pools manager in the library.
Later but within 2.x.x
-- Transactional file system.
- Dedicated TCP/IP stack.
? ISO7816 driver over UART driver, both reader and card side (hardware
missing).