Approved content

The content below is provided by a partner.

bsiever/pxt-morse 2.0.0 GitHub

morse=github:bsiever/pxt-morse
clicks=github:bsiever/microbit-pxt-clicks

Morse Code: Keying-in, Decoding, and Encoding

This extension can decode and encode dots/dashes of Morse Code as well as manage the detection of keying-in of Morse code.

The term “dit” is sometimes used rather than dot. And “dah” rather than dash.

Keying

“Keying” refers to keying in the dots, dashes, and the important silences that occur. The keying blocks, [morse.keyDown()] and [morse.keyUp()], are used to indicate when a key is pressed and released. Key presses and releases will automatically be decoded, first to dots and dashes and then, following an appropriate “silence”, a code letter or number if it’s a valid code (the sequence of dots and dashes will be provided for invalid codes).

Standard Morse code timing expects:

This extension uses four timing values to decode key presses:

If the duration of time between [morse.keyDown()] and [morse.keyUp()] is:

If, following a [morse.keyUp()], there is no [morse.keyDown()] for more than [morse.maxBetweenSymbolTime()], any successful dots and dashes are treated as a letter and [morse.onCodeSelected()] is executed.
If, following a [morse.keyUp()], there is no [morse.keyDown()] for more than [morse.maxBetweenLetterTime()], any successful dots/dashes are treated as a letter and [morse.onCodeSelected()] is executed. The code will be a space (" ") to indicate the gap between words.

By default the timing is comparable to a dit that lasts about 160ms, but requiring an extra long gap between words:

Keying with the built-in buttons may be easier if the Button Clicks extension’s on button down and on button up blocks are used.

Key Down

morse.keyDown() : void

The Morse code key has been pressed.

Key Up

morse.keyUp() : void

The Morse code key has been released.

Set Dot and Dash Times / Timing

morse.setMaxDurationDotDash(dotTime: number, dashTime: number) {

Set the maximum time (in milliseconds) of dots and dashes.

Get the Max Dot Time

morse.maxDotTime()

Provides the current maximum dot time.

Get the Max Dot Time

morse.maxDashTime()

Provides the current maximum dash time.

Set Silence Between Symbols Letters Times / Timing

morse.setMaxSilenceBetweenSymbolsLetters(symbolTime: number, letterTime: number) 

Set the maximum time (in millisecondes) of slience allowed between symbols (dots/dashes) and letters of a word.

Get the Maximum Between Symbol Time

morse.maxBetweenSymbolTime()

Provides the current maximum time allowed between symbols (dots and dashes) before considering the sequence of dots/dashes completed. When this time is exceeded any preceeding dots and dashes are decoded and [morse.onCodeSelected()] is executed.

Get the Maximum Between Letter Time

morse.maxBetweenLetterTime()

Provides the current maximum time before considering the preceeding letters to be completed That is, before being considered a space between words or end of transmissions. When this time is exceeded [morse.onCodeSelected()] is executed and the code will be a space (" ").

Reset Key timing

morse.resetTiming() : void

Reset the timing of keying. This ignores any current key up/down activities.

A reset may be needed if timing parameters are changed while in the midst of keying in a symbol. Resetting decoding may also be needed.

Identifying when individual symbols (dots, dashes, silences) are Keyed In

morse.onNewSymbol(handler: (symbol: string) => void)

The symbol will indicate the which symbol has been detected/entered:

Decoding

Decoding refers to decoding a sequence of dots, dashes, and silences into letters based on Morse code.

Dot

morse.dot() : void

Register that a complete “dot” has happened.

Dash

morse.dash() : void

Register that a complete “dash” has happened.

Silence

morse.silence(kind?: morse.Silence) : void

Register that a silence between the key being pressed (down) has happened:

Silences are needed

A morse.Silence.InterLetter or morse.Silence.InterWord is required to detect a letter.

Reset Decoding

morse.resetDecoding() : void

Reset dash/dot processing. That is, start at the beginning as though nothing had been keyed in.

On Code Selected

morse.onCodeSelected(handler: (code: string, sequence: string) => void) 

A code has been selected (following a morse.Silence.InterLetter or a morse.Silence.InterWord). A valid code will be represented with a valid Morse character. An invalid Morse code will be indicated with a code that is a question mark (?). sequence will be the sequence of dots and dashes in the code. If there’s an end-of-word silence ([morse.silence(morse.Silence.InterWord)]), the code will be a space (" ") and the sequence will be empty.

Note that several codes are unused by traditional Morse code. In these cases the code will be ? and the sequence will indicate the sequence of dots and dashes. This extension will track the first seven (7) dots/dashes. Any more than 7 will be ignored.

Unused codes include:

Peek at the current Code

morse.peekCode()

Provide the code described by the currently entered dots and dashes. Note that the current code is not compelte until a suitable silence has occurred.

For example, if a single dot was entered, [morse.peekCode()] would return an E, which is represented by a single dot. If a second dot is entered before any sufficient “silence”, it would then return a O, which is represented by two dots. Etc.

Peek at the current sequence

morse.peekSequence()

Provide the sequence of dots and dashes that is currently entered but not yet complete (there hasn’t yet been a sufficient silence).

A maximum of seven symbols are stored. Any more than seven will be ignored.

Encoding

Encoding refers to converting letters and spaces to Morse code.

Encoding text as Morse Code

morse.encode(characters: string) : string 

The given string will be converted to a represntation of Morse code using dots (.), dashes (-), spaces indicating gaps between the symbols for a letter, and underscores indicating the gaps between words.

For example, [morse.encode("SOS SOS")] would return "... --- ..._... --- ...".

Examples

Morse Code Trainer

This example can help you learn the “code” part of Morse code without the key timing.

For example, the code for the letter U is “..-“. To practice entering a “U” you would press button A twice, then button B, then A+B. The screen should show the “U”.

input.onButtonPressed(Button.A, function () {
    morse.dot()
    basic.showLeds(`
        . . . . .
        . . . . .
        . . # . .
        . . . . .
        . . . . .
        `)
    basic.pause(200)
    basic.clearScreen()
})
morse.onCodeSelected(function (code, sequence) {
    basic.showString("" + (code))
})

input.onButtonPressed(Button.AB, function () {
    basic.showIcon(IconNames.Yes)
    morse.silence(morse.Silence.InterLetter)
})
input.onButtonPressed(Button.B, function () {
    morse.dash()
    basic.showLeds(`
        . . . . .
        . . . . .
        # # # # #
        . . . . .
        . . . . .
        `)
    basic.pause(200)
    basic.clearScreen()
})

Key Timing Trainer

This example allows you to practice the timing of key presses/releases for Morse code:

Start practicing by trying to prefect the dot and dash times of individual letters:

The example uses a special form of showString to ensure it’s shown fast enough to keep up with Morse code entry. This version of “Show String” isn’t available as a block, so it is placed in a function that can be used from blocks.

This example requires the Button clicks extension to detect when button A is pressed ([morse.keyDown()]) and released ([morse.keyUp()]).

// Show a string "now" without a delay / scrolling
function showStringNow (theString: string) {
    basic.showString(theString, 0)
}
morse.onCodeSelected(function (code, sequence) {
    // Make silences visible.
    if (code == " ") {
        code = "_"
    }
    serial.writeLine("Code: " + code)
    showStringNow(code)
})
buttonClicks.onButtonUp(buttonClicks.AorB.A, function () {
    morse.keyUp()
})
// Show dot/dash
morse.onNewSymbol(function (newSymbol) {
    serial.writeLine(newSymbol)
    showStringNow(newSymbol)
})
buttonClicks.onButtonDown(buttonClicks.AorB.A, function () {
    morse.keyDown()
})
input.onButtonPressed(Button.B, function () {
    morse.resetTiming()
    morse.resetDecoding()
})
morse.setMaxDurationDotDash(
200,
1000
)
morse.setMaxSilenceBetweenSymbolsLetters(
500,
2000
)

Morse Code Keying Trainer

This example can be used to practice keying in Morse code. It will show the code letter for the current sequence of dots/dashes that were entered with button A. It will “flash” when the code is completed/accepted (that is, after a long enough silence to indicate the end of the letter).

For example, after a single dot is entered it will show “E” until either: 1) Another dot/dash occurs or 2) Enough time has elapsed to consider the current letter to be done. If a second “dot” is keyed in before the time is up (now at “..”), it will display an “I”. Etc.

// Show a string "now" without a delay / scrolling
function showStringNow (theString: string) {
    basic.showString(theString, 0)
}
morse.onCodeSelected(function (code, sequence) {
    showStringNow(code)
    game.addScore(1)
})
buttonClicks.onButtonUp(buttonClicks.AorB.A, function () {
    morse.keyUp()
})
morse.onNewSymbol(function (newSymbol) {
    if (newSymbol == "-" || newSymbol == ".") {
        showStringNow(morse.peekCode())
    }
})
buttonClicks.onButtonDown(buttonClicks.AorB.A, function () {
    morse.keyDown()
})
morse.setMaxDurationDotDash(
200,
1000
)
morse.setMaxSilenceBetweenSymbolsLetters(
500,
2000
)

The example uses a special form of showString to ensure it’s shown fast enough to keep up with Morse code entry. This version of “Show String” isn’t available as a block, so it is placed in a function that can be used from blocks.

This example requires the Button clicks extension to detect when button A is pressed ([morse.keyDown()]) and released ([morse.keyUp()]).

Challenges

  1. Use radio extensions to recieve Morse code from remote “keys”.
  2. Combine this with the Bluetooth HID extension (micro:bit v2 only) to create a Morse Code keybaord!
  3. Create a program that uses tones to play the dots/dashes as they are being keyed in.

Extras

Here’s a fun “tone trainer” to practice decoding Morse code yourself (v2 micro:bit only): Tone Trainer w/ Voice. You can modify the codes in the start to practice just a few Morse codes characters at a time.

Acknowledgements

This was inspired by the work of “grandpaBond” on the Micro:bit Developer Slack Forum, who created this fantastic example to help kids learn Morse Code: https://makecode.microbit.org/24561-13529-14704-94719.

Icon based on Font Awesome icon 0xF141 SVG.

Misc.

I develop micro:bit extensions in my spare time to support activities I’m enthusiastic about, like summer camps and science curricula. You are welcome to become a sponsor of my micro:bit work (one time or recurring payments), which helps offset equipment costs: here. Any support at all is greatly appreciated!

Supported targets

for PXT/microbit

makeCodeRender(“{{ site.makecode.home_url }}”, “{{ site.github.owner_name }}/{{ site.github.repository_name }}”);

morse=github:bsiever/pxt-morse#v2.0.0