Hi Mike, Thanks a lot for your interest and attention to detail. Indeed, the details of the "history" example have changed over the years to demonstrate both types of history (shallow and deep, see attached state diagram). And you are right; these changes made the ToasterOven behave in a way that a real appliance should not behave (the oven should never turn on after pressing OFF). You have several options to fix that: Your choice to make the doorOpen:OFF transition go straight to the "off" state...
Hi Mike, Thanks a lot for your interest and attention to detail. Indeed, the details of the "history" example have changed over the years to demonstrate both types of history (shallow and deep, see attached state machine, see attached state diagram). And you are right; these changes made the ToasterOven behave in a way that a real appliance should not behave (the oven should never turn on after pressing OFF). You have several options to fix that: Your choice to make the doorOpen:OFF transition go...
I know this is almost 3 years old but I saw the same problem. It didn't make any sense that if the toaster if off that it should be turned on simply by opening and closing the door. It should stay off. My fix: Signal OFF from the doorOpen state should just transition directly to the off state in doorClosed (not using history). Signal CLOSE in doorOpen transitions to history (placed on doorClosed not heating, and is not shallow).
Hi fellas, Great topic! :D https://doorstop.readthedocs.io/ (not IBM's product; this is 100% FLOSS , git-friendly, actively maintained) Cheers
Hi Mark, As a commercial licensee, please contact Quantum Leaps support (support@state-machine.com) for the QSPY source code. --MMS
We use qspy on a Raspberry Pi and have always built a Linux binary for arm64 for this purpose. Up until qtools version 7.4.1, the complete source code for building qspy was available. Since version 8, it is no longer publicly available. Would it therefore please be possible to publish a linux binary for arm64 in addition to the x86_64 linux binary?
Makes sense. Thanks!
Hi Modo, Your 10-step plan sounds a bit complicated. It seems that you prefer the very traditional code partitioning, so just do that. Specifically, instead of manually "removing the delimit portions that QM controls", just generate the traditional header files (.h/.hpp) with your class declarations ( $declare {} directives). Then simply include those QM-generated headers in your external source files (.cpp). QM doesn't need to "know" about those source files at all, so you can manage them completely...
Hi Modo, Your 10-step plan sounds a bit complicated. It seems that you prefer the very traditional code partitioning, so just do that. Specifically, instead of manually "removing the delimit portions that QM controls", just generate the traditional header files (.h/.hpp) with your class declarations ( $declare {} directives). Then simply include those QM-generated headers in your external source files (.cpp). QM doesn't need to "know" about those source files at all, so you can manage them completely...
Hi Miro, Thank you for the quick response! This answer gave me further insight to the flexibility/functionality of QM. My team and I are looking to see how the development process using outside IDEs (notepad++/vscode) would "feel" To give an example, this would be look for QM using QPCPP. Create an operation (or set of operations) with parameter(s) for a class, but leave the code portion blank. Create an external file to capture functions that belong to said class. In the external file, use the generative...
Hi Modo, QM allows you to organize your code any way you see fit (see QM code engineering philosophy). Consequently, you can implement all/most/some actions and/or guards on your state machines as (member) functions of your state machine class. You can then implement those functions in any number of files: completely outside QM or within QM as regular files or external files. If the implementation files are outside QM, they won't be obviously overwritten when QM re-generates code. If the files are...
solved! Decided to just do it the way suggested by the link I posted. Thanks!
I do enjoy the convenience of the code generation abilities of QM. I'm wondering if it's possible to have QM stub out functions on external files, then on those external files add the code, and upon further generation (maybe adding another function or something) the code written within the function is not overwritten. Thanks!
Hi, thank you so much for the detailed explanation! I have to say, I really liked the “dining philosophers” analogy — I hadn’t even thought about applying the DPP pattern to my scenario, but it actually makes perfect sense here! Definitely a clever way to coordinate access to the shared resource. Thanks a lot for the insight and for pointing me in the right direction! 🙌 Giulio
Hi Giulio, First, let me clarify that if your sensors can permanently overwhelm your communication bandwidth (RS-485 in your case), no software design is going to fix it. Unfortunately, even QP cannot pull off such magic. Now, your problem seems to me two-fold. First, you worry about event pools, meaning that you have a buffering problem. Second, you think about coordinating the sensor components, which is a coordination problem. Regarding coordination, your SensorManager seems to be the ideal candidate....
Hi Giulio, First, let me clarify that if your sensors can permanently overwhelm your communication bandwidth (RS-485 in your case), no software design is going to fix it. Unfortunately, even QP cannot pull off such magic. Now, your problem seems to me two-fold. First, you worry about event pools, meaning that you have a buffering problem. Second, you think about coordinating the sensor components, which is a coordination problem. Regarding coordination, your SensorManager seems to be the ideal candidate....
Hi everyone, I’d like your advice on an architectural issue. I have 40 “sensors” connected over an RS‑485 bus. For each sensor I have an orthogonal state machine inside a dedicated AO (let’s call it SensorManager). I also have a separate AO responsible for managing the RS‑485 serial interface. The problem: Each of the 40 sensor state machines may need to send a Modbus request, which means they would post an event to the AO that handles the serial line. However, I cannot allow all 40 sensors to request...
here is version
Manage External Tools Parser Error C:\\qp\\qpc
Okay, thank you very much! :)
Okay, thank you very much! :)
Hi dillang, Thank you for reporting. Indeed, the poke() command works currently differently in qview than in qutest, but it would be better if they were consistent. This was fixed in QView 8.1.3 just uploaded to PyPi. You can upgrade to this version by typing: pip install qview --upgrade And here is an example of using peek()/poke() # example of a custom command def cust_command(self): string_to_inject = "StringContents" QView.current_obj(QView.OBJ_AP, "my_string_length") QView.poke(0, 2, pack("<H",...
Hi there, I've been using the poke function in qutest and qview applications to inject values into static global variables. It seems like they both need to be called differently between qutest and qview scripts and I was wondering if I had set something up incorrectly or was using them wrong. e.g. in my .c file I have defined static variables: static uint8_t my_string[128]; static uint16_t my_string_length; and I have added both of these to the object dictionary: QS_OBJ_DICTIONARY(my_string); QS_OBJ_DICTIONARY(&my_string_length);...
rt_err_t rt_sched_lock ( rt_sched_lock_level_t * plvl ) Lock the system scheduler. /* Parameters plvl Pointer to the object where lock level stores to Returns rt_err_t RT_EOK on success -RT_EINVAL if plvl is NULL Note This function has both MP version and UP version. */ Hi, Dr Samek, Yes, plvl is a pointer to store local irq level not a given level to lock scheduler.
Also I reviewed the code of rt-thread (scheduler_mp.c for MP mode) and I feel like it doesn't support locking the scheduler to a given priority level. I'm not RT-Thread expert, but my quick glance at the documentation shows that RT-Thread seems to support selective scheduler locking to the specified level. Please take a look at the following thread management functions: rt_err_t rt_sched_lock(rt_sched_lock_level_t * plv) rt_err_t rt_sched_unlock(rt_sched_lock_level_t level) rt_err_t rt_sched_unlock_n_resched(rt_sched_lock_level_t...
Hi, Dr Samek, I reviewed QActive_publish_ part. My understanding of QF_SCHED_LOCK_ and QF_SCHED_UNLOCK_ is that before all message dispatches are completed, the active objects that may receive dispatched events should not be scheduled. void QActive_publish_( ... if (QPSet_notEmpty(&subscrList)) { /* any subscribers? */ /* the highest-prio subscriber */ uint_fast8_t p = QPSet_findMax(&subscrList); QActive *a = QActive_registry_[p]; QF_SCHED_STAT_ QF_SCHED_LOCK_(a->prio); /* lock the scheduler up to...
Wrong assertion in qep_hsm.
Fixed in QP/C/C++ 8.1.2, where ascrutinizedll assertions have been scruitinized and tested (100% MC/DC). --MMS
Horizontal navigation/panning with shift + scroll wheel only works in left direction
Fixed in QM 7.0.2. --MMS
QTimeEvt_noActive() behaves incorrectly in QP/C/C++ 8.1.0
Fixed in QP/C/C++ 8.1.2 --MMS
For context, I am currently trying to convert a Rhapsody Model into a QM model in order to see how painful of a process it is going to be. I understand that it would be in my best interest to develop with a "QM first" paradigm, but at this point in time it's in my best interest to start with a Rhapsody model and try to replicate it in QM. Examples are attached as QM_example and Rhapsody_example. The model is a simple dishwasher example offered by a class from Rhapsody. There's a state called Active,...
QPCPP 8.1.1 build errors with -Wsign-conversion
Fixed in QP/C++ 8.1.2. --MMS
QP 8.1.1, file qsafe.h compilation errors
Fixed in QP/C 8.1.2. --MMS
QM 7.0.1 tab title bug
Fixed in QM 7.0.2. --MMS
Hi Borut, Alignment is part of the type, so you might try to specify the type as __ALIGNED(4) uint8_t. --MMS
Generated by QM wo __ALIGNED(4) ........ typedef struct { // protected: QActive super; // public: QTimeEvt timeEvt; QTimeEvt unlockTmo; uint8_t pos; uint16_t delay[13]; uint8_t bcoIdx; uint8_t m95op; uint16_t m95Token; bool m95Busy; M95Op m95LastOp; uint32_t m95LastAddr; uint32_t m95LastLen; (__ALIGNED(4) uint8_t m95Buf[sizeof(CiaNvData)]; // ← HERE) ????? CiaNvData nv; char settingsPw[32]; bool settings_unlocked; char pendingPw[32]; bool expectConfirm; CiaMode mode; } Cia; How to add __ALIGNED(4)...
Generated by QM wo __ALIGNED(4) ........ typedef struct { // protected: QActive super; // public: QTimeEvt timeEvt; QTimeEvt unlockTmo; uint8_t pos; uint16_t delay[13]; uint8_t bcoIdx; uint8_t m95op; uint16_t m95Token; bool m95Busy; M95Op m95LastOp; uint32_t m95LastAddr; uint32_t m95LastLen; (__ALIGNED(4) uint8_t m95Buf[sizeof(CiaNvData)]; // ← HERE) ????? CiaNvData nv; char settingsPw[32]; bool settings_unlocked; char pendingPw[32]; bool expectConfirm; CiaMode mode; } Cia; How to add __ALIGNED(4)...
Add customizable callbacks around the RTC steps
Speaking of the wishes to the HW team, apart from one or two GPIO pins for timing, you should always request the TX/RX pins for the UART for tracing/debugging. All these pins don't need to be populated in the production boards but at least the test points should be provided. --MMS
Thanks! That did the trick.
@Nik: As a general rule, if the ST HAL API has a timeout, then it is blocking. For example, if I look at: https://github.com/STMicroelectronics/stm32l4xx-hal-driver/blob/f8e66b7f8db10809f91a4360c154b6304fab06ba/Inc/stm32l4xx_hal_i2c.h We see that the methods/functions are grouped by "Blocking mode: Polling" or "Non-Blocking mode: Interrupt" or "Non-Blocking mode: DMA". You should be able to search for those comments in the above example. When using QP/C or QP/C++, avoid the blocking methods, as noted...
Hi Nik, My question is, how would you go about detecting every last bit of blocking code? Real-time programming is not necessarily about "detecting every last bit of blocking (or polling) code", but generally you are supposed to know how long things take in your software. This "inconvenient truth" applies to all real-time systems, regardless if based on a superloop, RTOS, or event-driven framework like QP. To this end (knowing how long things take), avoidance of blocking makes your life easier because...
Hi Mark, I'm not sure why your compiler rejects _Static_assert because it should be generally supported. But you're right that it would be better to use static_assert or Q_ASSERT_STATIC(), which is defined in all QP/C++ ports (typically as static_assert). Anyway, the error comes from the qpcpp.hpp header file, which is the backward-compatibility layer. Specifically, this static assertion informs you that the event signals are no longer configurable, but if you still use the deprecated Q_SIGNAL_SIZE,...
Hi Mark, I'm not sure why your compiler rejects _Static_assert because it should be generally supported. But you're right that it would be better to use static_assert or Q_ASSERT_STATIC(), which is defined in all QP/C++ ports (typically as static_assert). Anyway, the error comes from the qpcpp.hpp header file, which is the backward-compatibility layer. Specifically, this static assertion informs you that the event signals are no longer configurable, but if you still use the deprecated Q_SIGNAL_SIZE,...
Hi Miro, I'm trying out QPCPP in Version 8.1.2 in one of our projects. In line 48 of qpcpp.hpp there is a _Static_assert which in my project results in a compiler error: "expected constructor, destructor, or type conversion before '(' token*". Adding #include <sys/cdefs.h> or changing to static_assert resolves the error. Is there a reason why _Static_assert is used instead of static_assert? cppreference.com says "_Static_assert is a deprecated spelling that is kept for compatibility." Best regards,...
I understand the recommendation is to eliminate every last bit of blocking. - longer than system tick -> events - shorter than system tick -> peripherals My question is, how would you go about detecting every last bit of blocking code? Of course if you understand 100% of the code you will not have trouble identifying blocking. What about when using a library like stm32_hal_i2c? You could search the functions for delay calls or loops but it is easy to miss some blocking. I was thinking you could identify...
Hi guruprasad, To run QUTest on any embedded target board, you need a way to communicate with that target. Embedded targets communicate with the QSPY host utility via UART, and the specifics of this communication are implemented in the qutest_port.c file. In other words, the CPU type (ESP32 or other) does not matter. Rather, you need to know which UART you wish to use for the QSPY communication and then you need to implement the following customization callbacks: QS_onStartup() QS_onCleanup() QS_onReset()...
Hi guruprasad, To run QUTest on any embedded target board, you need a way to communicate with that target. Embedded targets communicate with the QSPY host utility via UART, and the specifics of this communication are implemented in the qutest_port.c file. In other words, the CPU type (ESP32 or other) does not matter. Rather, you need to know which UART you wish to use for the QSPY communication and then you need to implement the following customization callbacks: QS_onStartup() QS_onCleanup() QS_onReset()...
Hi, i have already run qutest on host , same way i want to run qutest on esp32 please guide me with steps to achieve qutest on esp32 to run qutest on esp32 does it require qutest_port.c ??? i cannot find qutest_port.c in qp version 6.9.3 please help. Regards, Guruprasad
Hi Gene, WWMD? Well, I would just use the existing QP event management. I mean, event parameters (payload) are the data buffers managed by QP, so why not use them for DMA directly? Specifically, I would define a UART event class as something like this: typedef struct { QEvt super; // inherit QEvt uint8_t buffer[256]; // big enough for the largest expected message uint16_t nbytes; // actual number of bytes in this event } UART_Evt; Then in your UART "driver", I would dynamically allocate such a UART_Evt,...
Hi Gene, WWMD? Well, I would just use the existing QP event management. I mean, event parameters (payload) are the data buffers managed by QP, so why not use them for DMA directly? Specifically, I would define a UART event class as something like this: typedef struct { QEvt super; // inherit QEvt uint8_t buffer[256]; // big enough for the largest expected message uint16_t nbytes; // actual number of bytes in this event } UART_Evt; Then in your UART "driver", I would dynamically allocate such a UART_Evt,...
When I've done this in the past, I used a STM32H7A3 which has character match functionality built in to the UART DMA hardware. Luckily, all my devices end their messages with a LF. All I have to do is program the LF character into the character match register, request a DMA transfer with more bytes than I ever expect to receive and I get an interrupt when the LF shows up regardless of how many bytes I requested. All the interrupt handler does is stuff the LF terminated message and a timestamp into...
When I've done this in the past, I used a STM32H7A3 which has character match functionality built in to the UART DMA hardware. Luckily, all my devices end their messages with a LF. All I have to do is program the LF character into the character match register, request a DMA transfer with more bytes than I ever expect to receive and I get an interrupt when the LF shows up regardless of how many bytes I requested. All the interrupt handler does is stuff the LF terminated message and a timestamp into...
Good suggestions. I did not understand how the "external files" feature worked until now. I'll definitely make better use of that. For more appropriate partitioning, I definitly have some room for improvement there. Is there some guiding principles you recommend I read?
Hi BigRedHDL, Perhaps this issue could be addressed by partitioning the code appropriately? For example, you might package more complex actions and maybe guards in your state machines as separate functions (typically member functions of the state-machine/active-object class). Then you can put the implementation of all such action-functions in a separate file, which could be completely outside QM. Then you could use any editor you like, with code-completion, to edit the action functions. I assume...
I'd like to get other peoples thoughts on how they use QM with their development environment. Personally, I love how QM gives me a concise picture of the state machine and to me it is much easier to navigate than scrolling around the code file. However, in my most recent project I also had a lot of times where code completion and LLMs were invaluable which then introduces this friction of editing the code in the generated file, copying it out and into the QM diagram and regenerating it. I was very...
I'd like to get other peoples thoughts on how they use QM with their development environment. Personally, I love how QM gives me a concise picture of the state machine and to me it is much easier to navigate than scrolling around the code file. However, in my most recent project I also had a lot of times where code completion and LLMs were invaluable which then introduces this friction of editing the code in the generated file, copying it out and into the QM diagram and regenerating it. I was very...
Thanks, I'll try both ways.
Awesome, looking forward to the next version.