i've startet using SC and came quite far creating a GUI and Worker Script. Now i'm stuck and need some help.
I want to communicate with a device over serial wire. I need to send a message and wait for the device to answer, then pick up parts of the answer and send some repsonse back, depending on it.
What is the best way of doing this?
I guess sending with "write()" and then looping until an answer comes back (synchronous wait) is not a good way to do this...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Yes, got it meanwhile. Took a bit to get into the working principle... also, i'm not a JS programmer, only got some low level knowledge about PHP, C, C++, Python.
BTW: With SC, you created an absolute outstanding and excellent product, congrats!
Last edit: devnull 2024-01-17
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I build an automotive serial sniffer tool (single wire UART). It utilizes several modes like "sniff traffic", "program keys/sensors", "receive sensors", "receive keys", send arbitrary frames, etc. I use a state-machine for those.
The serial data from the UART is put into an buffer using the serialPort.readyReadSignal.connect() method. This just puts in data read from UART into an global array. An overflow-counter prevents it from getting too big (like a ring-buffer).
Depending on the mode, it do several things.
In "sniff traffic" mode, it just polls the buffer for new data, check if there is a valid frame received and displays it's meaning in a text-widget, used as a console. The other modes send to some data themselfs and interact with the peer on the UART.
The main loop is the state-machine processor, which simply waits for events to trigger a transition to another state. Each state has it's on service handler routine which is called every iteration of the state-machine loop.
As SC does not like blocking code in the script (code must come to an end), i realized this with an timer. So the timers period is the state-machines clock-cycle.
The events to trigger a state transition are send from button click-handler code.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2024-01-19
Sounds good. But you could trigger your statemachine from the serial port slot function. Then you wouldn't need a timer.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm not that familar with statemachines, just learning. But from now it seems that i don't need a loop at all.
Let's play this scenario:
* I have a machine which can connect and disconnect from an serial port
* The initial status of my machine is "disconnected". The other status is "connected".
* To communicate with a serial port, my machine needs to transition from "disconnected" to "connected". Let's call this transition "connecting".
* To stop communication my machine needs to transition from "connected" back to "disconnected". Let's call this transition "disconnecting"
* When the machine is connected, some UI elements should be enabled, and disabled if the machine is no longer connected.
* At last we need to define which transition can happen in which status and what target status this should involve. This is:
* In status "disconnected" the transition "connecting" cause status "connected"
* In status "connected" the transition "disconnecting" cause status "disconnected"
That all sounds fairly easy and logical. But now how to implement those?
The transitions are usually triggered by events. In my case let's imagine we have two buttons, one called "Connect" and one called "Disconnect". The click-handler of each button calls the corresponding transition:
* connectButton.click(transition("connecting"))
* disconnectButton.click(transition("disconnecting"))
The logic of the statemachine prevents from executing the connect-button event twice, as in status "connected" there is no transition called "connecting".
Now, how and where to add the code for doing the actions?
One prerequisite of connecting to a serialport is that such a port must be available and selected (if there are more than one). In other words: if there is not port choosen, the transition should not take place.
The code for going to the next status should be within the action() handler of the corresponding transition. Means, that if the machine do "connecting", which is a transition of the status "disconnected", it executes code to get connected. Something like:
If that code fails, e.g. because "port" is undefined or could not be used, the transition itself should fail and the machine stays in it's current status. Alternatively, the coder may want to put the machine in some "error" status instead. In this case, the programmer could trigger another transition within the current one, but with the "error" target.
If all go well, the target status is now "connected", which does not mean anything, it's just a status, no code will be executed. Code is only executed on transition. But what if one like to execute some code if the machine enteres this status? Ok, it could also be put into the transition code, but what if the target status could be reached by many transitions? Do they all need a copy of that code?
Therefore some addition actions could be added, which executes code on existing a current status and entering a new one. Let's add them to our machine definition:
Voilá, now we could add the prerequisite code into connected.onEnter() or disconnected.onExit()? If it can't leave the status, it should stay in it (onExit), or if it can enter a status (onEnter) it should also stay where it is. Both would work, but if you put it into onEnter() of the target status, you might do it many times, whereas the onExit() of the current status is only needed once. So we put it in there:
The other way around, going from some status into "disconnected", we should also put the code to disconnect from the serial port into the onEnter() handler of the disconnected status.
Hello,
i've startet using SC and came quite far creating a GUI and Worker Script. Now i'm stuck and need some help.
I want to communicate with a device over serial wire. I need to send a message and wait for the device to answer, then pick up parts of the answer and send some repsonse back, depending on it.
What is the best way of doing this?
I guess sending with "write()" and then looping until an answer comes back (synchronous wait) is not a good way to do this...
Hi,
you should use the signal/slot mechanism.
Yes, got it meanwhile. Took a bit to get into the working principle... also, i'm not a JS programmer, only got some low level knowledge about PHP, C, C++, Python.
BTW: With SC, you created an absolute outstanding and excellent product, congrats!
Last edit: devnull 2024-01-17
thx :-)
I build an automotive serial sniffer tool (single wire UART). It utilizes several modes like "sniff traffic", "program keys/sensors", "receive sensors", "receive keys", send arbitrary frames, etc. I use a state-machine for those.
The serial data from the UART is put into an buffer using the serialPort.readyReadSignal.connect() method. This just puts in data read from UART into an global array. An overflow-counter prevents it from getting too big (like a ring-buffer).
Depending on the mode, it do several things.
In "sniff traffic" mode, it just polls the buffer for new data, check if there is a valid frame received and displays it's meaning in a text-widget, used as a console. The other modes send to some data themselfs and interact with the peer on the UART.
The main loop is the state-machine processor, which simply waits for events to trigger a transition to another state. Each state has it's on service handler routine which is called every iteration of the state-machine loop.
As SC does not like blocking code in the script (code must come to an end), i realized this with an timer. So the timers period is the state-machines clock-cycle.
The events to trigger a state transition are send from button click-handler code.
Sounds good. But you could trigger your statemachine from the serial port slot function. Then you wouldn't need a timer.
I'm not that familar with statemachines, just learning. But from now it seems that i don't need a loop at all.
Let's play this scenario:
* I have a machine which can connect and disconnect from an serial port
* The initial status of my machine is "disconnected". The other status is "connected".
* To communicate with a serial port, my machine needs to transition from "disconnected" to "connected". Let's call this transition "connecting".
* To stop communication my machine needs to transition from "connected" back to "disconnected". Let's call this transition "disconnecting"
* When the machine is connected, some UI elements should be enabled, and disabled if the machine is no longer connected.
* At last we need to define which transition can happen in which status and what target status this should involve. This is:
* In status "disconnected" the transition "connecting" cause status "connected"
* In status "connected" the transition "disconnecting" cause status "disconnected"
Expressed as meta-code this could look like:
That all sounds fairly easy and logical. But now how to implement those?
The transitions are usually triggered by events. In my case let's imagine we have two buttons, one called "Connect" and one called "Disconnect". The click-handler of each button calls the corresponding transition:
* connectButton.click(transition("connecting"))
* disconnectButton.click(transition("disconnecting"))
The logic of the statemachine prevents from executing the connect-button event twice, as in status "connected" there is no transition called "connecting".
Now, how and where to add the code for doing the actions?
One prerequisite of connecting to a serialport is that such a port must be available and selected (if there are more than one). In other words: if there is not port choosen, the transition should not take place.
The code for going to the next status should be within the action() handler of the corresponding transition. Means, that if the machine do "connecting", which is a transition of the status "disconnected", it executes code to get connected. Something like:
If that code fails, e.g. because "port" is undefined or could not be used, the transition itself should fail and the machine stays in it's current status. Alternatively, the coder may want to put the machine in some "error" status instead. In this case, the programmer could trigger another transition within the current one, but with the "error" target.
If all go well, the target status is now "connected", which does not mean anything, it's just a status, no code will be executed. Code is only executed on transition. But what if one like to execute some code if the machine enteres this status? Ok, it could also be put into the transition code, but what if the target status could be reached by many transitions? Do they all need a copy of that code?
Therefore some addition actions could be added, which executes code on existing a current status and entering a new one. Let's add them to our machine definition:
Voilá, now we could add the prerequisite code into connected.onEnter() or disconnected.onExit()? If it can't leave the status, it should stay in it (onExit), or if it can enter a status (onEnter) it should also stay where it is. Both would work, but if you put it into onEnter() of the target status, you might do it many times, whereas the onExit() of the current status is only needed once. So we put it in there:
The other way around, going from some status into "disconnected", we should also put the code to disconnect from the serial port into the onEnter() handler of the disconnected status.
Last edit: devnull 2024-01-20