Fork me on GitHub
Tutorials / Examples / Morse Code Trainer

Morse Code Trainer

Ported from Alex Zhornyak's SCXML tutorial collection.

This ports Alex Zhornyak's Qt SCXML Morse Code Trainer EcmaScript example. The SCXML statechart distinguishes dot, dash, short pause, and long pause timing, while the React panel provides a browser keyer and decoded transcript.

Decoded text
 
Current code
 
Signals
 

Hardware demo

SCXML source

<scxml datamodel="ecmascript"
       name="ScxmlMorse"
       version="1.0"
       xmlns="http://www.w3.org/2005/07/scxml">
  <datamodel>
    <data expr="''" id="buffer"/>
    <data expr="''" id="symbol"/>
    <data id="codeReference">{
      "-----"  : "0",
      ".----"  : "1",
      "..---"  : "2",
      "...--"  : "3",
      "....-"  : "4",
      "....."  : "5",
      "-...."  : "6",
      "--..."  : "7",
      "---.."  : "8",
      "----."  : "9",
      ".-"     : "a",
      "-..."   : "b",
      "-.-."   : "c",
      "-.."    : "d",
      "."      : "e",
      "..-."   : "f",
      "--."    : "g",
      "...."   : "h",
      ".."     : "i",
      ".---"   : "j",
      "-.-"    : "k",
      ".-.."   : "l",
      "--"     : "m",
      "-."     : "n",
      "---"    : "o",
      ".--."   : "p",
      "--.-"   : "q",
      ".-."    : "r",
      "..."    : "s",
      "-"      : "t",
      "..-"    : "u",
      "...-"   : "v",
      ".--"    : "w",
      "-..-"   : "x",
      "-.--"   : "y",
      "--.."   : "z",
      ".-.-.-" : ".",
      "--..--" : ",",
      "..--.." : "?",
      "-.-.--" : "!",
      "-....-" : "-",
      "-..-."  : "/",
      ".--.-." : "@",
      "-.--."  : "(",
      "-.--.-" : ")"
    }</data>
  </datamodel>

  <state id="event_processor" initial="entry_point">
    <transition event="input.restart" target="event_processor"/>

    <state id="entry_point">
      <onentry>
        <assign expr="''" location="buffer"/>
      </onentry>
      <transition event="device.press" target="pressed"/>
    </state>

    <state id="released" initial="initial">
      <transition event="device.press" target="pressed"/>
      <state id="initial">
        <onentry>
          <send delay="300ms" event="short_pause_timeout" id="short_pause_timeout"/>
        </onentry>
        <onexit>
          <cancel sendid="short_pause_timeout"/>
        </onexit>
        <transition event="short_pause_timeout" target="short_pause"/>
      </state>

      <state id="short_pause">
        <onentry>
          <send delay="700ms" event="long_pause_timeout" id="long_pause_timeout"/>
          <send event="short_pause"/>
        </onentry>
        <onexit>
          <cancel sendid="long_pause_timeout"/>
        </onexit>
        <transition event="long_pause_timeout" target="long_pause"/>
      </state>

      <state id="long_pause">
        <onentry>
          <script><![CDATA[
symbol = codeReference[buffer]

while (symbol === undefined && buffer.length) {
    buffer = buffer.slice(0, -1)
    symbol = codeReference[buffer]
}
          ]]></script>
          <send event="out.symbol">
            <content expr="symbol"/>
          </send>
          <assign expr="''" location="buffer"/>
        </onentry>
      </state>
    </state>

    <state id="pressed" initial="sending_dot">
      <state id="sending_dot">
        <onentry>
          <send delay="300ms" event="dash-timeout" id="dash-timeout"/>
        </onentry>
        <onexit>
          <cancel sendid="dash-timeout"/>
        </onexit>
        <transition event="dash-timeout" target="sending_dash"/>
        <transition event="device.release" target="released">
          <send event="dot"/>
          <assign expr="buffer + '.'" location="buffer"/>
        </transition>
      </state>

      <state id="sending_dash">
        <transition event="device.release" target="released">
          <send event="dash"/>
          <assign expr="buffer + '-'" location="buffer"/>
        </transition>
      </state>
    </state>
  </state>
</scxml>