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?
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.
I had a similar need for reusable code involving mutexes. The way the macros are defined in cmsis_os.h make that difficult, but after some study it appears all that's needed is a control block of uint32_t[4] and a temporary pointer.
The osMutexDef(x) goes away, as does osMutex(x). I've replaced those with:
typedef struct _osMutexCb { uint32_t cb[4]; // this is the actual control block void *pCb; // pointer to the control block. Only needed during osMutexCreate } osMutexCb_t;
You should be able to allocate space for that statically or dynamically, as many of them as you need.
I've created a wrapper for the create. This could also be done as a macro or inline, but I have some portability issues with the latter.
osMutexId osMutexCreate2(osMutexCb_t *MutexCb) { MutexCb->pCb = (void *) MutexCb->cb; return osMutexCreate((const osMutexDef_t *) &MutexCb->pCb); }
The other mutex functions only use the osMutexId (which is just a pointer to the control block, so why couldn't osMutexCreate just use it in the first place?). Duh.
That's an awfully lot of monkey motion for a relatively simple thing. It's also a redundant level of indirection where we're sending osMutexCreate a pointer to a pointer. In the standard cmsis syntax using osMutexDef macro, that pointer space is only used once for the create. I tested this using an auto variable, demonstrating it does not need to be retained.
The old Keil programmers would have never permanently wasted those 4 bytes, or the redundant level of indirection. They were careful of CPU clocks and space efficiency.
I've seen some claims posted here that the standard osMutexDef() and osMutex() macros make code more readable. Nonsense. Wrapping a simple block of storage in a macro that references a typedef is less readable, not more. It took several hours to conclude that all you needed was 16 bytes of storage and send osMutexCreate a pointer to a pointer to that storage and you're finished.
I'm at a loss to understand why Keil created these macros that make it difficult to write reusable code. The only reasonable answer might be that programmers will be less likely to "lose" control blocks by deallocating them from dynamic memory, or some other accident.
Ok. But they could have easily protected dumb programmers by retaining the control block within OS static memory and allocating it during mutex create. Yes, that would mean a fixed number of mutexes would be allowed, but that's no different than the static memory allocated for the stack, or the fixed number of threads, etc.
The bottom line is cmsis should have been similar to other OSes, and allow programmers to control their own mutexes and other OS objects. This would make portability and re-learning issues easier. I'm sure whomever designed this thing believes they were doing someone a favor. Sorry, no. It made things much more difficult, and in the end I've just rewritten a chunk of cmsis_os.h to let me do what I need to do. No doubt I'll rewrite more of it. That's time I've wasted merely because the convoluted multi-layer syntax in cmsis_os_h wouldn't allow me to do what is easily done with other OSes.