Hello,
I'd like to write some reusabel code module to handle e.g. UART ports. Therefore I'd like to create a variable number (based on some kind of define...) of threads dealing with UART port 1,2,3 ... since it is possible to declare CMSIS-RTOS threads with a variable number of instances it could look like this:
#define UART_PORT_NUM 3 osThreadDef(uart_thread, osPriorityNormal, UART_PORT_NUM, 0)
my problem: If I need any kind of inter-thread communication (ITC) object, like mutexes or mail queues, for each of this threads I don't know how to declare them, since osMailQDef, osMutexDef and so on, are not designed with a "variable" number of instances...
Any suggestions?
Here is 1 exammple - very specific to Keil's CMSIS RTOS implementation.
namespace OsRTX { // uint32_t os_mutex_cb_##name[4] = { 0 }; becomes.. struct Mutex { uint32_t _private_[4]; }; } class OsMutex { private: OsRTX::Mutex m_rtxMutex; osMutexId m_MutexId; void Create() { osMutexDef_t temp; // Note: not all osDef_t items can be temporary temp.mutex = &m_rtxMutex; m_MutexId = osMutecCreate( (const osMutexDef_t *) &temp); } public: OsMutex() { Create(); } // Initialized at construction! // Note: not all os items can be initialized // before the OS is running. ~OsMutex() {} osStatus Wait(uint32_t millis) { return osMutexWait(m_MutexId, millis); } osStatus Release() { return osMutexRelease(m_MutexId); } }; // 2 Instances of Mutex Objects OsMutex Uart1Mutex; osMutex Uart2Mutex; // Usage status = Uart1Mutex.Wait(100); status = Uart1Mutex.Release();
You can do something like this
class Uart : public UartBase { UART* m_uart; OsMutex m_mutex; public: Uart(UART* uart) : m_uart(uart) {} ~Uart() {} osStatus Acquire(uint32_t millis) { return m_mutex.Wait(millis); } osStatus Release() }; Uart GPS_Uart(UART1); Uart GSM_Uart(UART2); Uart Debug_Uart(UART3);
Combining MANY items you can
Class GenericObjectUsingTaskAndUart { static const uint32_t mbxitems = 10; UartBase *m_uart; OsThread A1; OsThread A2; // Usually the object IS-A thread, but if you want multiple threads // tied together, you would have the class contain them... OsMbx<mbxitems,DataType_t> InQueue// Mailbox with 10 entries of type DataType_t public: GenericObjectUsingTaskAndUart(UartBase *uart) : m_uart(uart) {} ~GenericObjectUsingTaskAndUart() {} osStatus InitTask() { // Init and start threads, other stuff, that must happen // After OS is running. Could break into InitTask and Start } OsMbxBase<DataType_t> *GetInQueue() { return &InQueue; } }; // We now have an object that contains what it needs and knows about then, but is not // specifically tied to something GenericObjectUsingTaskAndUart Gen1(UART1); GenericObjectUsingTaskAndUart Gen2(UART2); GenericObjectUsingTaskAndUart Gen3(UART3);
You may create objects for every os item type (mailbox,message,timer,thread) They can be generically combined in any way imagined (for good or bad)
This is just an example for thought. I am not suggesting that it is a way anyone should use it. Just posting it as an actual answer the original question. I am certainly not requesting any kind of critique.
Ok, that's what I need, thank you! I have to adapt it (I forgot to mention, that I am using C, the mentioned C++ thread was just to demonstrate, that there is a need for such an implementation) I was also thinking about avoiding the typical osXyzDef() macros and to do all the stuff manually. The only question, which you also have mentioned in your comment: Is it really save/recommendable to create the osXyzDef_t structures (e.g. osMutexDef_t) temporary? The macros are creating them as const, so I thought, the kernel needs it that way.
See my example for just supplying a struct to the tread, informing it what queues etc to associate with.
It is not at all safe to just make them temporary.
View all questions in Keil forum