I'm trying to simplify the creation of "orthogonal component".
I was faced with the need to break the base way of inheritance within your framework for events creation.
In such case, QEvt is based as second filed of struct.
I want to use Q_NEW and QF_gc to create events dynamically, but these functions require QEvt as first element to work correctly.
Q_NEW fills the event signal, pool id and reference counter from the start of mem block returned by mem pool, so that data will be written to owner field, and that is incorrect. For the Q_NEW I can workaround by using "custom event constructor" and simple memory move to move QEvt data filled by Q_NEW from the start of struct to the place, where the QEvt data must be located.
And then I have to clean the event properly. QF_gc function requires the QEvt address (QEvt*) as argument to process the memory cleanup. And also QF_gc function requires the QEvt address as the start address of memory block.
To workaround last requirement I suggest to add simple fix into QMPool_put:
voidQMPool_put(QMPool*constme,void*b,uint_fast8_tconstqs_id){QF_CRIT_STAT_/**@pre# free blocks cannot exceed the total # blocks and*theblockpointermustbefromthispool.*/Q_REQUIRE_ID(200,(me->nFree<me->nTot)&&QF_PTR_RANGE_(b,me->start,me->end));(void)qs_id;/*unusedparameter(outsideQ_SPYbuildconfiguration)*/QF_CRIT_E_();/*Fix:Movetothestartaddressofcurrentblock*/b=&((uint8_t*)b)[-(((unsignedint)b)%me->blockSize)];/*Fix*/((QFreeBlock*)b)->next=(QFreeBlock*)me->free_head;/*linkintolist*/me->free_head=b;/*setasnewheadofthefreelist*/++me->nFree;/*onemorefreeblockinthispool*/QS_BEGIN_NOCRIT_PRE_(QS_QF_MPOOL_PUT,qs_id)QS_TIME_PRE_();/*timestamp*/QS_OBJ_PRE_(me);/*thismemorypool*/QS_MPC_PRE_(me->nFree);/*thenumberoffreeblocksinthepool*/QS_END_NOCRIT_PRE_()QF_CRIT_X_();}
What do you think about it?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This obviously destroys the inheritance relationship between your MyEvt and the QEvt base class, and therefore it breaks everything else.
It is not unusual for the events intended for "Orthogonal Components" to carry the ID of the component. But this is typically the payload (event parameters) and I don't understand why you need to put it necessarily as the first member of your event subclass.
What do you think about it?
For these reasons, I can't really like it, can I? I would really look hard for alternatives before doing something like that. This includes foregoing QP entirely and going with something else, because if you do this, you might just as well throw the whole framework out.
--MMS
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It is not unusual for the events intended for "Orthogonal Components" to carry the ID of the component. But this is typically the payload (event parameters) and I don't understand why you need to put it necessarily as the first member of your event subclass.
I don't really want to use a large number of switches to determine which of the orthogonal HSM belongs to a particular event. I want to encapsulate each HSM (orthogonal component) as reusable module, wich can be used inside other many other AO's. Also, I do not want to reveal the details of the signals that exist in each of the modules (QSignal enum for each component is private and defined in .c file)
I can't follow the rule of inheritance "QEvt first" and put the QHsm* owner as last field. Because resultant size of QEvt inheritors may be different (for example QTimeEvt). So I took exactly this approach.
If at any time I need to extend my orthogonal component with an additional module, I do not have to change the behavior of the main event handler.
In my case, the code for the main event handler is always the same. OrthogonalDispatcher_Dispatch Function
QTimeEvt can be subclassed as well, so you could add the owner member in the subclass.
In any case, I would probably name that member "recipient" rather than "owner":
One restriction with QTimeEvts or subclasses of them is that they can NOT be allocated dynamically. This means that the only option for them is static allocation, but because they cannot be dynamic, they should NOT be shared.
--MMS
Last edit: Quantum Leaps 2021-07-28
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
They are static, but still require proper dispatching.
How can I do it?
For example, I am using 3 HSM inside one AO. Each HSM may contain at least one QTimeEvt or more. For each QTimeEvt I define separate signal in enum as it requires.
These HSM modules are reused by multiple different AO.
I don't want to make definition of HSM's signals as public. They shall be encapsulated inside each module in implementation file (*.c).
Can you suggest how to reuse ready-made HSM across multiple different AO?
Last edit: Artem Dovhal 2021-07-28
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This question is about managing your signal space, which is a broader issue than just signals used by Orthogonal Components.
Well, assuming 16-bit signal space, you have 64K unique signals to work with. I'm sure you can carve out of several signals that are off limits to the other parts of the application, so they can be used inside your reusable Orthogonal Components.
Alternatively, you can reuse the same numeric signal values in each component. The uniqueness requirement is only within a scope of a single state machine, so different state machines can use the same numerical values of signals for different purposes.
But even though the signal reuse is a theoretical possibility, I prefer to work with unique signals that are used for one purpose only. This is easier to debug. And the signal space is so big that there are no compelling reasons to overload signals.
--MMS
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
In this case, you have to transfer all possible signals that exist in the project into one common header file. This creates some inconvenience when making changes to individual parts of the system and a general dependence of each module on this file appears. I would like to have full encapsulation and independence of modules from each other. So I came up with the idea that I have already described in this post.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
No, you don't have to use the most primitive signal management policy. This is done in the examples just because they are so simple. But in a more complex project you can invent many other ways of more intelligent management of your signals.
For example, you can divide your 64K signal space into "signal groups" (say 1000 signals each, which is plenty). This means that your "common header file" contains an enumeration of those "signal groups", which will be offsets:
The sub-modules then define specific (private) signals based on those offsets. These enumerations don't need to be exposed globally, so your other modules don't need to recompile if you change the private signals. I hope you get the idea.
I would like to extend/follow up on this thread regarding the use of timer events that extend the QTimeEvt "class". Specifically, if I extend the QTimeEvt to include an id of some sort, can I use the same time evt with same signal enum but different IDs at the same time. For example, if I have 3 HSMs where this timer is being handled, can I post arm the same timer with different IDs for 2 of the HSMs at the same time?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Time events in QP are currently available only as static events, meaning that for all intents and purposes they must be immutable. For this reason, you cannot change the attributes of a time event, such as its signal or the associated active object, after the constructor.
The same exact limitation applies to the derived time events (subclasses of QTimeEvt), because all these events are still static. This means that all attributes, including the attributes added through inheritance, must be unchanging after the constructor.
I hope that this argumentation answers all your questions. (The answers are No and No).
--MMS
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hello, Miro!
I'm trying to simplify the creation of "orthogonal component".
I was faced with the need to break the base way of inheritance within your framework for events creation.
In such case, QEvt is based as second filed of struct.
I want to use Q_NEW and QF_gc to create events dynamically, but these functions require QEvt as first element to work correctly.
Q_NEW fills the event signal, pool id and reference counter from the start of mem block returned by mem pool, so that data will be written to owner field, and that is incorrect. For the Q_NEW I can workaround by using "custom event constructor" and simple memory move to move QEvt data filled by Q_NEW from the start of struct to the place, where the QEvt data must be located.
And then I have to clean the event properly. QF_gc function requires the QEvt address (QEvt*) as argument to process the memory cleanup. And also QF_gc function requires the QEvt address as the start address of memory block.
To workaround last requirement I suggest to add simple fix into QMPool_put:
What do you think about it?
This obviously destroys the inheritance relationship between your
MyEvt
and theQEvt
base class, and therefore it breaks everything else.It is not unusual for the events intended for "Orthogonal Components" to carry the ID of the component. But this is typically the payload (event parameters) and I don't understand why you need to put it necessarily as the first member of your event subclass.
For these reasons, I can't really like it, can I? I would really look hard for alternatives before doing something like that. This includes foregoing QP entirely and going with something else, because if you do this, you might just as well throw the whole framework out.
--MMS
I don't really want to use a large number of switches to determine which of the orthogonal HSM belongs to a particular event. I want to encapsulate each HSM (orthogonal component) as reusable module, wich can be used inside other many other AO's. Also, I do not want to reveal the details of the signals that exist in each of the modules (QSignal enum for each component is private and defined in .c file)
I can't follow the rule of inheritance "QEvt first" and put the QHsm* owner as last field. Because resultant size of QEvt inheritors may be different (for example QTimeEvt). So I took exactly this approach.
If at any time I need to extend my orthogonal component with an additional module, I do not have to change the behavior of the main event handler.
In my case, the code for the main event handler is always the same. OrthogonalDispatcher_Dispatch Function
Why can this not work:
typedef struct OrthogonalEvt_s {
QEvt super;
QHsm* owner;
} OrthogonalEvt;
Can you suggest how to deal with QTimeEvt in such manner?
QTimeEvt
can be subclassed as well, so you could add theowner
member in the subclass.In any case, I would probably name that member "recipient" rather than "owner":
One restriction with QTimeEvts or subclasses of them is that they can NOT be allocated dynamically. This means that the only option for them is static allocation, but because they cannot be dynamic, they should NOT be shared.
--MMS
Last edit: Quantum Leaps 2021-07-28
They are static, but still require proper dispatching.
How can I do it?
For example, I am using 3 HSM inside one AO. Each HSM may contain at least one QTimeEvt or more. For each QTimeEvt I define separate signal in enum as it requires.
These HSM modules are reused by multiple different AO.
I don't want to make definition of HSM's signals as public. They shall be encapsulated inside each module in implementation file (*.c).
Can you suggest how to reuse ready-made HSM across multiple different AO?
Last edit: Artem Dovhal 2021-07-28
This question is about managing your signal space, which is a broader issue than just signals used by Orthogonal Components.
Well, assuming 16-bit signal space, you have 64K unique signals to work with. I'm sure you can carve out of several signals that are off limits to the other parts of the application, so they can be used inside your reusable Orthogonal Components.
Alternatively, you can reuse the same numeric signal values in each component. The uniqueness requirement is only within a scope of a single state machine, so different state machines can use the same numerical values of signals for different purposes.
But even though the signal reuse is a theoretical possibility, I prefer to work with unique signals that are used for one purpose only. This is easier to debug. And the signal space is so big that there are no compelling reasons to overload signals.
--MMS
In this case, you have to transfer all possible signals that exist in the project into one common header file. This creates some inconvenience when making changes to individual parts of the system and a general dependence of each module on this file appears. I would like to have full encapsulation and independence of modules from each other. So I came up with the idea that I have already described in this post.
No, you don't have to use the most primitive signal management policy. This is done in the examples just because they are so simple. But in a more complex project you can invent many other ways of more intelligent management of your signals.
For example, you can divide your 64K signal space into "signal groups" (say 1000 signals each, which is plenty). This means that your "common header file" contains an enumeration of those "signal groups", which will be offsets:
The sub-modules then define specific (private) signals based on those offsets. These enumerations don't need to be exposed globally, so your other modules don't need to recompile if you change the private signals. I hope you get the idea.
Of course, you can come up with other signal management policies. The point is that you have many ways to do this.
--MMS
I would like to extend/follow up on this thread regarding the use of timer events that extend the QTimeEvt "class". Specifically, if I extend the QTimeEvt to include an id of some sort, can I use the same time evt with same signal enum but different IDs at the same time. For example, if I have 3 HSMs where this timer is being handled, can I post arm the same timer with different IDs for 2 of the HSMs at the same time?
Time events in QP are currently available only as static events, meaning that for all intents and purposes they must be immutable. For this reason, you cannot change the attributes of a time event, such as its signal or the associated active object, after the constructor.
The same exact limitation applies to the derived time events (subclasses of
QTimeEvt
), because all these events are still static. This means that all attributes, including the attributes added through inheritance, must be unchanging after the constructor.I hope that this argumentation answers all your questions. (The answers are No and No).
--MMS
Yeah, I kinda figured that I am trying to cheat by using the same time event for multiple things at the same time but thanks for the clarification.