Jump to content

drjdpowell

Members
  • Posts

    1,964
  • Joined

  • Last visited

  • Days Won

    171

Posts posted by drjdpowell

  1. I'm probably missing something obvious but I can't seem to do the following:

    Imagine I have a class tree with parent, children, grandchildren, etc. How do I take two objects in on parent wires and tell if one object is a child of the other?

    So for example, if Parent P has Children A and B, with grandchildren A1 and A2 of A, and B1 and B2 of B, I want a subVI (with two "P" inputs) that if comparing A and A1 returns "true", but if passed a B and A1 returns false.

    -- James

  2. Both methods require that the module have some way of discovering what Msgs it cares about or what specific waveform module it is.

    This will create some additional coding to make the module more intelligent.

    The benefit IMHO is you have a very loosely coupled, more reusable, debug able, testable module.

    Aside from the framework parent class dependencies, Each module is stand alone and totally independent of its caller or callees.

    It's up to the module developer to figure out how to register, react and send the correct Msgs.

    Have you considered adding some kind of optional local scoping to your framework? Sort of a "local router subnet". If you had the option of specifying a local scope when registering to send or receive a specific message (such as string like "UI subnet") you could easily set up an arbitrary number of Waveform Generators under different scopes, communicating independently with different modules, without needing to extend the code of any module. Local scoping could also increase the flexibility of your framework, allowing more hierarchal "module-submodule" relationships in addition to stand-alone modules.

    -- James

  3. My acquisition device outputs 4.096V @ 15 mA and I need to control a 24V solenoid valve which draws 167mA with 144 Ω.

    Note: I have a 24V source and I need to open/close this valve once in 48 hours.

    Can I only use a 5V relay for this task or do I risk any damage to the acquisition device? Should I go with a transistor then?

    You should be able to us a 5V input SSR. Something like this Cyrdom CN024D05.

    • Like 1
  4. Modules are totally autonomous and can connect and disconnect from the framework at run time without affecting other Modules. The Module is responsible for connecting and disconnecting to and from the framework and is not dependent on its caller for anything. Modules have no knowledge of each other only the Msgs they deal with.

    Msgs are Global in scope and are usable by all Modules. Any Module is allowed to ship or receive a defined Msg. Msgs and Routers are the only two things that connect Modules to each other making this framework very loosely coupled.

    Question: what if I wanted two or more of the same module. Say, I wanted to make your "Waveform Module" reentrant and use it in two different ways in my application, with the "UI Module" interacting with Waveform Module A, and, let's say, "Simulated Temperature Readings" (STR) Module interacting with Waveform Module B. Is there a way to direct the messages to only the correct module (UI to/from A and STR to/from B)? If not, I would not be able to operate A and B independently, as they both act on start/stop messages from either of the other two modules.

    -- James

  5. Unless I'm missing something, these are pretty fundamentally different patterns. The Symbio one focuses on method calls to by-reference objects [aka synchronous messages] while the Active Object focuses on message passing and announcements [aka asynchronous messages]. Although the two can be mixed, there's a huge amount of distinction in how to build up an application from scratch depending upon which one you're relying upon. I would not call these the same thing at all.

    Am I correct in my analysis here?

    Having just watched Mike's video it seems he is mostly using asynchronous messaging (via a User Event in his example Active Object). He is using a DVR to allow some of his API methods to modify the active object's private data, and those are synchronous (but fast).

    My (perhaps mistaken) impression of the differences of Mike's Active Object to mine are:

    1) He uses a specific reply channel for all responses from the AO (a queue in his “Send Message To Process” Method Template), while I use multiple reply channels, provided with the incoming messages themselves or "registered" as an Observer. This means (correct me if I'm wrong) that VIs based on the “Send Message To Process” template would not work properly if multiple were called simultaneously in parallel, as there is no mechanism to route the separate replies to the correct VI.

    2) He uses bare User events and queues, while I wrap all communication as "Messengers". This will hopefully allow me to substitute network communication when I get the chance to develop it, without needing to modify my active objects internally. I've been following the philosophy that the active objects should know the bare minimum about the specify communication channels they are using. My example AO given in the first post, for example, only knows that it is using a "Receive-type" incoming messenger (which could easily be TCP-based instead of queue-based), and knows nothing at all about it's outgoing communication (which could be queues, TCP, shared variables, notifiers, etc., and can be several processes instead of just one).

    3) His active objects are interfaced with by an associated API, while I build messages to send to mine via the generic API of the parent "Send" class. This is a minor difference as he could just use his “Send Message To Process” Template, unmodified, to send messages, and I could easily create wrapper API VIs. I'm not sure which is a better way to do things.

    -- James

  6. What I have started doing is to wire the parent message class to my get message VIs and do the cast in there. For me it seems too tedious to have to do the casting everytime that I get a message.

    I made the same design choice in my own version of object messaging. Though I'm also not sure if there isn't a problem with this way of doing things. One possible advantage of having a VI take the parent class is that you have the option of handling more than one message type. For example, the VI to get a String might work for both a String message type and a Variant message type, where the variant contains a string.

    -- James

  7. Your example shows three different loops: the controller, the spectrometer, and the handler. Assuming sequencing--not synchronization--is the goal, you can accomplish that using asynchronous messages and a state machine in the control loop. Make the response messages from the spectrometer and the handler act as triggers for the state transitions, and then in the next state you'd send the next message in the sequence. It's a little bit more to set up on the front end, and state machine execution flow is a little more abstract than sequentially connected wires. On the other hand, I think the second option is more self-contained and less prone to unforeseen interactions. It also has the advantage that you don't have to invent alternative communication channels to work around the problem of blocking your control loop's input queue.

    The alternative communication channel is done: an easy-to-use "Observer Registry" as illustrated in my active object design. Also, although my active object template is a simple queued message handler, one can use more complex designs like a producer-consumer, where the producer loop monitors the input queue and a "Sequencer" consumer does the synchronous calls to the spectrometer and sample handler. Then if the producer were to receive an "Abort" message, say, from the UI it could send "abort" to the spectrometer and sample handler, which would then error-out the synchronous call from the Sequencer. Admittedly, the need to keep the synchronous stuff away from the input queue receiver does illustrate your and mje's point about being careful with synchronous calls.

    -- James (off on vacation and internetless for the next week)

  8. Following on the "Self-addressed Stamped Envelopes" topic, I'd like to present a design of an Active Object using my messaging library. This template has the ability to both "reply" to messages and to allow "observers" to register for event updates. I haven't used this template yet (just wrote the observer-registration part yesterday) and I would appreciate any feedback before I use it in a real-world project (which I'll be doing after a weeks vacation).

    The example object, "PP Template" does the following:

    Responds to "Current Time?" with a text string of the current time.

    Sets the format string for the time by the command "SetTimeFormat"

    Starts generating "TimeUpdate" messages periodically on the period given in the command "AutoGenerateTime"

    Allows external processes to register as observers of the following events:

    "SetTimeFormat" received

    "Current Time" issued

    "TimeUpdate" issued

    "Macro: Exit" received (this is the shutdown command for the active object)

    All error messages

    Here is how a higher-level VI might create ("launch") and communicate with "PP Template":

    post-18176-0-00763100-1311861159_thumb.p

    In this example we launch "PP Template", register a Message Logger (another active object) as observer of all published events, send a nonsense message "Blah Blah" just to demonstrate error handling, set the time format, and query "Current Time?" first synchronously(*), then asynchronously with the message reply going to the "Asynchronous Receiver" loop. Then we register "Asynchronous Receiver" as an observer of TimeUpdate events (and set the autogenerate time of these events). On pushing the "stop" button, "PP Template" is sent a "Macro: Exit" command to shut down.

    Here's what the Message Logger receives when we run this VI:

    post-18176-0-14882000-1311861819_thumb.p

    And here is the VI dynamically launched VI at the heart of the active object. It's basically a message handler with eight cases; three of the cases handle the three commands, then there is a timeout case, an error handling case, a shutdown case, an "ignore null messages" case (not shown), and a default case to catch unhandled commands (and spelling errors). The way receiver timeout and errors feed into the message case structure is stolen from Daklu's Lapdog messaging library.

    post-18176-0-21972200-1311860551_thumb.p

    Some details of communication with the active object:

    post-18176-0-15356800-1311860453_thumb.p

    1) The object is launched by dynamically calling the PP Template.vi, setting it's "Startup Message" control via a VI Server call, and then doing some handshaking messages between "Launch.vi" and the "Startup" and "Acknowledge Startup" VI's. This creates the incoming command messenger for the process (in this case it is a queue based messenger, but there is an alternate "Startup" VI for a User-Event-based messenger). Calling a "Send" or "Query" method on the active object calls the same method on the command messenger. There are two startup modes: when started as an "autoshutdown slave", the messenger is created inside the Launch.vi, which means that if the main VI goes idle, the queue reference will become invalid, which triggers a "MSRReceiverError" that shuts down the launched VI ("Message Logger" in the above example shuts down in this way). The other way creates the Messenger inside the "Startup" VI, making the active object independant of the Launching process.

    2) Observer registration is handled by an "ObsReg" by-ref object, with two methods: "Registration", which filters out and acts on registration commands, maintaining a list of all observers for each event message (and sets for all events and all error events), and "Notify Observers", which accepts messages and sends them to all observers registered for them. Thus, it is extremely easy to publish new event types; just package a message for the event and pass it to "Notify Observers".

    3) Reply-based communication involves a "return address" (a messenger or other active object reference) to be attached to the message, and the active object using a "Reply" VI to respond (in synchronous communication, the "Query" VI creates a single-use response queue to receive the reply). For error handling, the Reply VI will package any error in it's error terminal as an error message and send this to the return address (this is in addition to an observers being notified of the error).

    -- James

    (*) Please note the potential problems of synchronous communication brought up by mje.

    • Like 1
  9. In practice I find asynchronous mechanisms like the one James just posted to almost always be preferable to a synchronous request.

    Synchronous ONLY is perhaps not a good idea, but synchronous messaging is good for synchronizing things. As an example, suppose I had a spectrometer and a sample handler for deploying samples to be measured. I might want to deploy a calibration sample, THEN calibrate the spectrometer, THEN deploy a sample to be measured, and THEN measure the spectrum of the sample. This would be trivially easy to do with four synchronous queries chained together by their error terminals. If either spectrometer or sample handler had a problem it would return an error message as its reply (such error appear on the error-out terminal of the Query VI).

    post-18176-0-95651200-1311782888_thumb.p

    Of course, if either component needs to signal something immediately there needs to be a dedicated channel. In which case, neither my synchronous nor asynchronous "reply" examples work, since in both cases the communication channel is a part of the received message. I've been developing a third communication mode as part of a "Active Object" template: registering for event updates (the OOP "Observer Pattern") that would work for this. All three modes should be useful and can be used on the same active object.

    -- James

  10. Second, there are a lot of cool features that can be added to a messaging framework, but... these features come at the cost of additional complexity. The complexity is found not only in how the framework internals are implemented, but is also often found in how the framework is used--its api. This can present a significant barrier to entry for new users, especially if they do not have experience using LVOOP. If the messaging system is intended for a small group of co-workers it's probably not a big deal. New employees can ask around to get clarification on how it works and how to use it. It might be too complicated if you're hoping to release it to a broader audience. My "ideal" messaging framework is one small enough to be picked up easily, light enough to be suitable for small projects, and flexible enough to be able to adapt it to more complex situations.

    I agree, and I've been trying to design my messaging system in that way, so that one can use it for simple things without having to understand everything that might be done with it. My original design goal was to be able to have processes that send messages without having to know whether the messages are being sent by queue, or notifier, or user event, or UDP or TCP. And for processes that receive messages to be able to transparently use network communication (TCP etc.) in place of local communication. That makes things simpler, not more complicated. And my initial goal for the Parallel Processes is to have a simple template for creating "speak-only-when-spoken-to" simple active objects that can be "queried" by higher-level processes. Thus the synchronous, command-reply communication (shown below with text-varient messages) was the first thing I developed (which lead to the idea of having each message carry it's own reply method):

    post-18176-0-48682500-1311586737_thumb.p

    I find this synchronous communication to be more clear and simple to use than asynchronous. I probably shouldn't have first introduced my messaging design with the complex example of my first post, as one would start out (and perhaps end) with much simpler uses.

    Third, passing queues as message data can be very, very useful. If I have a lot of data going from one component to another that is far away on the hierarchy, I'll set up dedicated data "pipe" between them to avoid overloading the control message queues. However, too much direct messaging between components makes it very hard to understand how all the components are interacting. I get a lot of value out of having all the message routing information and slave interactions contained in the mediator loop. It is relatively easy to page through the message handling cases in the mediator loop and understand what conditions messages are forwarded to other slaves and what conditions they are handled differently.

    Getting back to the more complex example of my first post, although the messaging is direct from A to B, all the routing and slave interactions are setup by the main VI.

    Also, I have found one of the harder things in debugging asynchronous messaging is figuring out where unexpected messages originated. (I use a "Source:MessageName" notation to help with that.) With hierarchical messaging I *know* the message must have come from the master, so I open that vi and figure out what triggers the message. I can rinse and repeat through the hierarchy until I find what caused the unexpected message to be sent. With direct messaging it's much harder to trace a message back to its source.

    In my system, one can look at the creator of the process to see who is passed the wire representing the ability to communicate with that process (hopefully, there are only a limited number of such potential message senders). And I'm hoping my "Message Logger" can be developed into a useful debugging tool. Below, I've modified the Logger to add some tracing information (the call chain of the process sending the message and the message timestamp).

    post-18176-0-17775500-1311591884_thumb.p

    -- James

  11. In fact I have my own architecture which does pretty much the same thing you have done (don't we all have our own it seems now a days):

    Yes, I nearly titled this conversation "Yet another messaging system". biggrin.gif

    Looking at your "MessagePump" loop, I can see the great similarity, just with different terminology. My "MSG" message class contains a label (your "message identifier") and a "Send" object (your "Callback"); children of MSG add "Data" (your "parameters") of various kinds (the example I gave used a text-data message). "Send" is a virtual class, who's central method, "Send.vi", does nothing, but it's various children override Send.vi with different communication methods or other functionality. So far, I have Queue and User-Event "Messengers" (hopefully to be extended in future to a network-enabled TCP messenger); "Parallel Process", an active-object design that uses the messengers for communication; and "ObserverSet", an extension of Send intended for allowing multiple processes to receive ("observe") the same message.

    Here's an extension of my first example, where I've added a Message Logger (Parallel Process) that "observes" the messages to both processes A and B:

    post-18176-0-23809400-1311339340_thumb.p

    post-18176-0-73008200-1311339716_thumb.p

    Note that I made no changes to A, B or the Controller Loop; none of these processes are aware of the existence of the Message Logger.

    I've been experimenting with what kind of interesting functionality I can build into the Messaging system itself, while using only quite simple processes to message between. Here's a further modification of to example where I replace the "Controller" Loop with a "Metronome" parallel process that sends "MetronomeTick" messages periodically to the ObserverSet registered with it. I've used the ability of Observers to substitute an alternate message to have Metronome send the "SendTimeString" message to process A.

    post-18176-0-78517600-1311342369_thumb.p

    Note that A, B and Metronome know practically nothing about each other. They don't use any compatible message labels and they don't know what underlying communication method they are using. Metronome needs to "send" updates to its ObserverSet, but doesn't know anything about the number or nature of observers, or that it's messages are being rewritten. I had originally started writing a parallel process that maintained arrays of registered observers, with arrays of alternate message labels, but realized that all this functionality could be built into a extension of the "Send" messaging class, and thus added for free to any (much simpler) process that can register one "Send" object for updates.

    *A word about synchronous messaging (where a message is sent, and the sender blocks until a reply is obtained): Be very careful. Deadlock is very easy if you introduce circular dependencies, I've pretty much learned to avoid any form of synchronous messaging, even though it's easily done with the reply-to mechanism.

    In a hierarchal master-slave tree structure, like Daklu suggested, there is less potential for circular dependancies, as any synchronous messaging would always be from master to slave. And, of course, one needs a timeout error; here's my synchronous "query":

    post-18176-0-70834500-1311343507_thumb.p

    -- James

  12. Hello,The recent posts about "Message Routing" has inspired me to mention a variation on this idea. In particular, I am thinking of Daklu's description of his "Slave Loops" that only communicate with their masters (requiring the master to "mediate" communication between slaves), and Mark Balla's Message Routing Architecture.

    I have been working on my own LVOOP Messaging system, one in which there aren't specified "output" channels; instead, each message can contain the method to rely or respond to it. Sort of a self-addressed, stamped envelope. This allows one to build a "hierarchical tree of master/slave loops" as Daklu suggests, but with the ability to direct messages to thier final recipient without mediation. A simple example:

    post-18176-0-88887300-1311257202_thumb.p

    In this example, the Controller (master) sends a message to Process A (label="SendTimeString") with the attached reply address (command queue) of Process B, along with an alternate label, "CurrentTime", to be used for the reply message.

    Thus, Process A directly sends a message to Process B, with no mediating or routing processes in between, yet without either process knowing anything at all about each other (they don'y even use the same message labels). The Controller sets up the communication link between A and B, but doesn't itself need to handle the message.

    One can extend this into an "Observer pattern", where the Controller registers Process B as an observer of Process A's regularly occurring "TimeString" events, (complete with message relabeling to "CurrentTime"), again with neither A nor B having to know anything about each other.

    -- James

    • Like 1
  13. I often worry that I come across as an arrogant know-it-all descending from the mountain top to bless the unwashed masses with my wisdom.

    I don't think you give that impression.

    Any chance you could post it? Don't worry about the spit and polish or completenesss--I'm interested in seeing your state machine implementation.

    It's not even close to complete (the four-hour time limit would be a killer), but I can show the statemachine with a case that is; the "Main Menu" when the user selects the "Fast Cash $50" option (see attachment).

    I'm also curious what differences (if any) you noticed in your dev process or your code by implementing it as a state machine instead of a QSM. I know what *I* think about state machines vs. QSMs, but it might just be the way my brain is wired.

    [ironically, certification exams are one of the few places where I do recommend using a QSM. The problems are broken down in a way that assumes a QSM implementation and given the time constraints it's easier to go with the flow.]

    I found the ATM problem to be obviously calling for a state machine; it practically defines all the states for you. The problem equally seems to call for some LVOOP, again practically defining all the classes: "User Console" and "Account Database", with children "Simulated Console" and "Simulated Database" (ready for the eventual replacement with "Physical Console" and "Enterprise Database").

    If I were to use a JKI-SM (though I wouldn't be allowed the template on the exam), I might instead have had "Macros" such as...

    "// Main Menu

    Card Slot >> disable

    Keypad >> disable

    Menu State >> Main

    Display Message >> Main Menu

    Wait for User Input

    Process Main Menu Input"

    ... with the "Process Main Menu Input" calling (if the User pushed this button) "Fast Cash $50", which would call "Withdrawal >> Complete".

    The QSM version would not be terrible but would be clearly poorer than a true SM. But this problem is very clearly definable as a statemachine. Most programs I write involve "do the task requested before returning to idle", with the complexity of the task being more easily broken down into sub-tasks than states. For complex tasks, JKI-style macros are quite clear and they're quick to write compared to wiring up subVIs. The subVI option is clearer than JKI-SM frames, and I can appreciate some of the other advantages you point out, but the real reasons I've started to use subVI's more and more lately is the advantages of OOP classes and dynamic dispatch.

    BTW, what do you think of the provided example solution to the ATM example test? The one where it's done with Action Engines.

    -- James

    post-18176-0-99622900-1308833118_thumb.p

    • Like 2
  14. One of the problems with the QSM's poor name is that it doesn't give a clear idea of what it actually is.

    Hi Daklu,

    Another of the problems with the bad "QSM" name is that there are many conversations where someone brings up "QSM" and it triggers comment about their flaws as true state machines, "state diagrams" and such, WITHOUT ascertaining if the original use of the QSM pattern was anything to do with "different responses to the same message depending its current state". I suspect most use (and certainly better use) is more similar to what you use your message handler for. It may even be intended (dare I say it) as a structure for programing without separating the UI from the rest of the code! We lesser programmers tend to do that. So I did get the mistaken impression that people were suggesting true state machines for all sorts of purposes that seemed to me to be a poor fit.

    2. An unhealthy reluctance to create sub vis.

    You might be right. I think (lest I'm mistaken) that a QSM like JKI's is interchangeable with a QMH with appropriate subVIs (and the JKI-SM can meet your three conditions for QMHs). In my own use of the JKI-SM, my first uses definitely were flawed by too little use of subVI's, while lately I use a mix of mostly subVIs for low-level operations and frames of the case structure for higher-level ones. Your argument that case structures, loops and subVI's is clearer than a queue for complex processes is a much better one than your state-machine related criticisms; now your talking about what people use "QSMs" for.

    -- James

  15. Hi Daklu,

    Most of your criticism of the (badly named) "QSM" is all down to the flawed design of using the same queue for messages to the QSM and "states" (really operations) within the QSM. This flaw may be common, but it is not inherent to QSMs, and templates such as the "JKI statemachine" don't have it. There is no asynchronicity in a properly designed QSM (your point 4), nor do producer loops directly initiate QSM "states" (point 1). As to better separation of the UI (point 3), I'm not sure ignoring messages is all that great an idea (I have visions of the annoyance my Users will have after pressing "start", and coming back 5 hours later to find the equipment just sitting there).

    Point 2 is complicated since a QSM isn't actually a state machine and thus isn't a good way to implement a complex state diagram. But how good is a true state machine at implementing a complex flow chart? Aren't you making the same error as "QSM for everything" people by suggesting "true state machine for everything"? Is a hammer a useless tool just because people have mislabeled it as a type of saw?

    -- James

    By the way, here's an example (LV2009) of similar Harel state machine behavior without using objects. The main differences between this and the object implementation are that there is no state specific data or error handling in this example. The example also doesn't have any execution actions other than monitoring messages from the user.

    post-7603-0-46442900-1307737629_thumb.pn

    A couple things worth noting:

    1. The producer loop does not directly initiate state transitions. It sends a message to the state machine requesting a state transition, which the state machine will do if a valid transition is requested. If an invalid transition is requested the state machine ignores the message, though in the past I have sent debug or status messages to the UI to let the user know what is happening. Allowing producer loops to directly control state transitions is IMO the single biggest flaw in the traditional QSM. You have to break that link if you want to create more robust and scalable code.

    2. Using a "real" state machine means all my transition logic *has* to be contained in the state machine loop instead of distributed across several loops. It's way easier to verify that my code correctly implements the state diagram and way harder for other developers to use the state machine loop incorrectly. There is simply no way for a rogue producer to initiate a transition that violates the conditions defined by the state machine.

    3. This model provides better separation from the UI. I have often seen devs disable front panel controls to prevent invalid transitions when using a QSM. I usually ran into synchronization issues when tried that--controls wouldn't always be enabled or disabled at the right time. Here I don't have to worry about that--the state machine just ignores the message. If I want to disable a control I'll have the UI display loop do that in response to the state transition messages sent by the state machine. (Not shown in the example.)

    4. It's ridiculously easy (and safe) to have multiple producers controlling the same state machine loop. Just give the new producer a reference to the state machine's input queue and start sending it messages. Asynchronicity is not an issue as far as the state machine is concerned. (Try that with a QSM! :D)

    ------------

    When I wrap everything in classes the concept seems more complicated that it really is. I hope this example helps people understand the core functionality at work and why I think it's time for the Labview community to move away from the QSM (unless you're taking a certification exam.)

    If anyone feels like comparing implementations I'm curious what a traditional QSM looks like that has this same behavior.

  16. Personally, I would recommend people starting to use QSMs take some time to learn the difference between a state diagram and a flowchart and explore consequences of choosing one over the other.

    The flowchart tends to seem more intuitive to me for what I'm doing, so the badly-named QSM is good for me. Admittedly, this may be just a lack, on my part, of a clear understanding of the value of state diagrams.

    -- James

  17. Any ideas?

    Only thoughts:

    -- I would separate the changing of frames of reference (AB in A-frame --> AB in B-frame) from the inverting of the vector (since the later is then trivial)

    -- shouldn't the change of reference frame involve two relative angles? rather that the single angle your code snippet seems to have?

    -- James

  18. I'm still fairly well convinced the QSM pattern shown here is not a very good design for anything other than NI's exams or prototype (read: throwaway) code, but I've written much on that already and won't repeat myself here.

    post-7603-0-73028800-1307588161_thumb.pn

    That is a flawed design, due to the use of the same queue for both internal operations of the lower loop and incoming messages from the event structure in the upper loop, leading to indeterminacy in the order of operations. Good design always uses separate queues. I, personally, would recommend anyone starting to use "QSMs" (how about "Queued Operation Machines", QOM?) to use a good template such as the JKI statemachine toolkit to avoid these types of design mistakes (which I sadly recall making myself).

    -- James

  19. For the benefit of Dannyt and others reading, "Queued State Machines" such as the JKI state machine are misnamed in that they are not actually state machines. True state machines are a different concept, and are what Paul_at_Lowell and Daklu are talking about. QSMs are more like queued command or queued operation machines, and thus the concept of a "macro" set of commands applies.

    -- James

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.