8-разрядный код Морзе
По просьбе одного из любителей применения Щ-кодов в электронных поделках возникла необходимость написать функцию (подпрограмму, процедуру), которая будет издавать трель из последовательности точек и тире. В коде Морзе длина символа может быть от 1 знака (буквы Е и Т) до 9 знаков (триграф SOS). Что передавать вышеназванной функции в качестве параметра? Если вам не в тягость условия лицензии приглашаю познакомиться с процессом запихивания кода Морзе в 1 байт.
В коде Морзе наиболее часто применяются символы длиной 1–6 знаков.
; . Ee Ее Ёё
; - Tt Тт
; .. Ii Ии
; .- Aa Аа
; -. Nn Нн
; -- Mm Мм
; ... Ss Сс
; ..- Uu Уу
; .-. Rr Рр
; .-- Ww Вв
; -.. Dd Дд
; -.- Kk Кк
; --. Gg Гг
; --- Oo Оо
; .... Hh Хх
; ...- Vv Жж
; ..-. Ff Фф
; ..-- Юю
; .-.. Ll Лл
; .-.- Яя [AA] digraph UNKNOWN STATION
; .--. Pp Пп
; .--- Jj Йй
; -... Bb Бб
; -..- Xx Ьь Ъъ
; -.-. Cc Цц
; -.-- Yy Ыы
; --.. Zz Зз
; --.- Qq Щщ
; ---. Чч
; ---- Шш
; .---- 1
; ..--- 2
; ...-- 3
; ....- 4
; ..... 5
; -.... 6
; --... 7
; ---.. 8
; ----. 9
; ----- 0
; ..-.. Ээ
; ..-.- [INT] trigraph - military network question marker
; -..-. Slash/Fraction Bar [/]
; -.--. Parenthesis (Open)
; .-... [AS] digraph - Ampersand (or "Wait") [&]
; -...- [BT] digraph - Double Dash = or --
; .-.-. Plus sign [+]
; .-.-. [AR] digraph - New Page Signal
; -.-.- Starting Signal
; ...-. Understood
; .--.-. Ъъ
; .-.-.- Period [.]
; --..-- Comma [,]
; ..--.. [UD] digraph Question Mark [?]
; .----. Apostrophe [']
; -.-.-- [KW] digraph - Exclamation Point [!]
; -.--.- Parenthesis (Close)
; ---... Colon [:]
; -.-.-. Semicolon [;]
; -....- Hyphen, Minus Sign [-]
; ..--.- Underscore [_]
; .-..-. Quotation mark ["]
; .--.-. [AC] digraph - At Sign [@]
; ...-.- End of work
; ...-..- [SX] digraph - Dollar sign [$]
; ........ [HH] digraph - Error/correction
; ...---... [SOS] trigraph
Эти символы будем помещать в 8-разрядный аргумент. Байт должен содержать последовательность знаков (от 1 до 6) и их количество (также от 1 до 6). Последовательность знаков должна быть выровнена по младшему или старшему биту для удобства проталкивания во флаг переноса (Carry) командами сдвига. Получаем два варианта расположения счетчика (c) и последовательности (s) знаков:
; arg[s, x, x, x, x, c, c, c] — 1 знак
; arg[s, s, x, x, x, c, c, c] — 2 знака
; arg[s, s, s, x, x, c, c, c] — 3 знака
; arg[s, s, s, s, x, c, c, c] — 4 знака
; arg[s, s, s, s, s, c, c, c] — 5 знаков
; arg[s, s, s, s, s, s/c, c, c] — 6 знаков
; arg[c, c, c, x, x, x, x, s] — 1 знак
; arg[c, c, c, x, x, x, s, s] — 2 знака
; arg[c, c, c, x, x, s, s, s] — 3 знака
; arg[c, c, c, x, s, s, s, s] — 4 знака
; arg[c, c, c, s, s, s, s, s] — 5 знаков
; arg[c, c, c/s, s, s, s, s, s] — 6 знаков
В первом варианте при максимальной длине последовательности 6-й знак накладывается на старший бит счетчика.
Во втором варианте при максимальной длине последовательности 1-й знак накладывается на младший бит счетчика. В данном случае младший бит счетчика можно считать незначащим, так как за максимальное значение счетчика (6) можно принять обе комбинации 110 и 111. При значении счетчика 5 и меньше значащие знаки не накладывается на разряды счетчика.
Выбираем второй вариант. Называем точки нулями, тире — единицами. Так как последовательность знаков выровнена по младшему биту аргумента последовательность знаков располагаем в обратном порядке для проталкивания сдвигом вправо. Получаем кодировку аргумента:
; arg[c2, c1, c0/s6, s5, s4, s3, s2, s1]
В коде Морзе за единичный временной интервал принята длительность точки. Длительность тире — 3 интервала. Пауза между знаками внутри символа — 1 интервал. Пауза между символами — 4 интервала. Пауза между словами — 7 интервалов. Для сообщения функции, что не надо отрабатывать знаки, а только паузу введем комбинацию:
; arg[0, 0, 0, 0, 0, 0, 0, 0]
Приняв аргумент arg[c2, c1, c0/s6, s5, s4, s3, s2, s1] функция должна извлечь из него счетчик и последовательность, «отпиликать» символ и завершить его паузой длительностью 3 интервала.
Для формирования паузы между словами передаем функции аргумент arg[0, 0, 0, 0, 0, 0, 0, 0]. Функция должна в дополнение к постпаузе длительностью 3 интервала от предыдущего символа отработать паузу длительностью 4 интервала (итого 7 интервалов).
Для извлечения счетчика функция должна сдвинуть копию содержимого arg вправо на 5 битов, применить маску И (00000111), приравнять счетчик к 6 если равен 7. Далее пошаговыми сдвигами вправо извлечь знаки из оригинала arg. Если »0» — точка: 1 интервал beep, 1 интервал пауза. Если »1» — тире: 3 интервала beep, 1 интервал пауза. После отработки последнего знака — 2 интервала пауза. Если arg=0: только пауза длительностью 4 интервала.
Даная 8-разрядная кодировка покрывает все символы и диграфы Морзе длиной от 1 до 6 знаков. Рассмотрим примеры:
; . Ee Ее Ёё arg[0, 0, 1, x, x, x, x, 0]
; - Tt Тт arg[0, 0, 1, x, x, x, x, 1]
; .. Ii Ии arg[0, 1, 0, x, x, x, 0, 0]
; .- Aa Аа arg[0, 1, 0, x, x, x, 1, 0]
; -. Nn Нн arg[0, 1, 0, x, x, x, 0, 1]
; -- Mm Мм arg[0, 1, 0, x, x, x, 1, 1]
; ... Ss Сс arg[0, 1, 1, x, x, 0, 0, 0]
; ..- Uu Уу arg[0, 1, 1, x, x, 1, 0, 0]
; .-. Rr Рр arg[0, 1, 1, x, x, 0, 1, 0]
; .-- Ww Вв arg[0, 1, 1, x, x, 1, 1, 0]
; -.. Dd Дд arg[0, 1, 1, x, x, 0, 0, 1]
; -.- Kk Кк arg[0, 1, 1, x, x, 1, 0, 1]
; --. Gg Гг arg[0, 1, 1, x, x, 0, 1, 1]
; --- Oo Оо arg[0, 1, 1, x, x, 1, 1, 1]
; .... Hh Хх arg[1, 0, 0, x, 0, 0, 0, 0]
; ...- Vv Жж arg[1, 0, 0, x, 1, 0, 0, 0]
; ..-. Ff Фф arg[1, 0, 0, x, 0, 1, 0, 0]
; ..-- Юю arg[1, 0, 0, x, 1, 1, 0, 0]
; .-.. Ll Лл arg[1, 0, 0, x, 0, 0, 1, 0]
; .-.- Яя arg[1, 0, 0, x, 1, 0, 1, 0]
; .--. Pp Пп arg[1, 0, 0, x, 0, 1, 1, 1]
; .--- Jj Йй arg[1, 0, 0, x, 1, 1, 1, 0]
; -... Bb Бб arg[1, 0, 0, x, 0, 0, 0, 1]
; -..- Xx Ьь Ъъ arg[1, 0, 0, x, 1, 0, 0, 1]
; -.-. Cc Цц arg[1, 0, 0, x, 0, 1, 0, 1]
; -.-- Yy Ыы arg[1, 0, 0, x, 1, 1, 0, 1]
; --.. Zz Зз arg[1, 0, 0, x, 0, 0, 1, 1]
; --.- Qq Щщ arg[1, 0, 0, x, 1, 0, 1, 1]
; ---. Чч arg[1, 0, 0, x, 0, 1, 1, 1]
; ---- Шш arg[1, 0, 0, x, 1, 1, 1, 1]
; .---- 1 arg[1, 0, 1, 1, 1, 1, 1, 0]
; ..--- 2 arg[1, 0, 1, 1, 1, 1, 0, 0]
; ...-- 3 arg[1, 0, 1, 1, 1, 0, 0, 0]
; ....- 4 arg[1, 0, 1, 1, 0, 0, 0, 0]
; ..... 5 arg[1, 0, 1, 0, 0, 0, 0, 0]
; -.... 6 arg[1, 0, 1, 0, 0, 0, 0, 1]
; --... 7 arg[1, 0, 1, 0, 0, 0, 1, 1]
; ---.. 8 arg[1, 0, 1, 0, 0, 1, 1, 1]
; ----. 9 arg[1, 0, 1, 0, 1, 1, 1, 1]
; ----- 0 arg[1, 0, 1, 1, 1, 1, 1, 1]
; ..-.. Ээ arg[1, 0, 1, 0, 0, 1, 0, 0]
; ..-.- [INT] arg[1, 0, 1, 1, 0, 1, 0, 0]
; -..-. [/] arg[1, 0, 1, 0, 1, 0, 0, 1]
; -.--. Parenthesis arg[1, 0, 1, 1, 0, 1, 1, 0]
; .-... [&] arg[1, 0, 1, 0, 0, 0, 1, 0]
; -...- [=] arg[1, 0, 1, 1, 0, 0, 0, 1]
; .-.-. [+] arg[1, 0, 1, 0, 1, 0, 1, 0]
; -.-.- Starting Signal arg[1, 0, 1, 1, 0, 1, 0, 1]
; ...-. Understood arg[1, 0, 1, 0, 1, 0, 0, 0]
; .--.-. Ъъ arg[1, 1, 0, 1, 0, 1, 1, 0]
; .-.-.- [.] arg[1, 1, 1, 0, 1, 0, 1, 0]
; --..-- [,] arg[1, 1, 1, 1, 0, 0, 1, 1]
; ..--.. [?] arg[1, 1, 0, 0, 1, 1, 0, 0]
; .----. ['] arg[1, 1, 0, 1, 1, 1, 1, 0]
; -.-.-- [!] arg[1, 1, 1, 1, 0, 1, 0, 1]
; -.--.- Parenthesis arg[1, 1, 1, 0, 1, 1, 0, 1]
; ---... [:] arg[1, 1, 0, 0, 0, 1, 1, 1]
; -.-.-. [;] arg[1, 1, 0, 1, 0, 1, 0, 1]
; -....- [-] arg[1, 1, 1, 0, 0, 0, 0, 1]
; ..--.- [_] arg[1, 1, 1, 0, 1, 1, 0, 0]
; .-..-. ["] arg[1, 1, 0, 1, 0, 0, 1, 0]
; .--.-. [@] arg[1, 1, 0, 1, 0, 1, 1, 0]
; ...-.- End of work arg[1, 1, 1, 0, 1, 0, 0, 0]
Если присмотреться к тому, что осталось в сухом остатке:
; ...-..- Dollar sign [$] [SX] digraph
; ........ Error/correction [HH] digraph or [EEEEEEEE]
; ...---... [SOS]
логично было бы внести дополнительную функцию void dot3woPostPause () после которой отработать [X](-…-), [5](…) или [:](---…).
Для полноты картины рассмотрим «сложный» путь. Для отработки диграфов и триграфов Морзе длиной более 6 знаков необходимо внести дополнение в кодировку с целью отработки «лишних» знаков без межсимвольной паузы (без постпаузы длительностью 2 интервала после «лишних» знаков).
Количество «лишних» знаков от 1 до 3. Разрядность счетчика 2. Расположим счетчик в разрядах arg[4,3], а последовательность в разрядах arg[2,1,0]:
; arg[0, 0, 0, c1, c0, s3, s2, s1]
При arg[7,6,5]=000 для извлечения счетчика функция должна сдвинуть копию содержимого arg вправо на 3 бита, применить маску И (00000011). Далее пошаговыми сдвигами вправо извлечь знаки из оригинала arg. Если »0» — точка: 1 интервал beep, 1 интервал пауза. Если »1» — тире: 3 интервала beep, 1 интервал пауза. После отработки последнего знака не добавляются какие либо дополнительные паузы.
Теперь чтобы отработать «длинный» символ надо сначала обработать знаки без постпаузы потом знаки с постпаузой. Для этого нужны два 8-разрядных аргумента. Суммарное количество знаков в аргументах должно соответствовать длине символа:
; ...-..- Dollar sign [$] [SX] digraph
; arg1[0, 0, 0, 0, 1, x, x, 0] arg2[1, 1, 1, 0, 0, 1, 0, 0]
; arg1[0, 0, 0, 1, 0, x, 0, 0] arg2[1, 0, 1, 1, 0, 0, 1, 0]
; arg1[0, 0, 0, 1, 1, 0, 0, 0] arg2[1, 0, 0, x, 1, 0, 0, 1]
;
; ........ Error/correction [HH] digraph or [EEEEEEEE]
; arg1[0, 0, 0, 1, 0, x, 0, 0] arg2[1, 1, 0, 0, 0, 0, 0, 0]
; arg1[0, 0, 0, 1, 1, 0, 0, 0] arg2[1, 0, 1, 0, 0, 0, 0, 0]
;
; ...---... [SOS]
; arg1[0, 0, 0, 1, 1, 0, 0, 0] arg2[1, 1, 0, 0, 0, 1, 1, 1]
Упаковка символов кода Морзе в 8-разрядный код может быть реализована на разных языках программирования и на разных платформах. Для Макса (любителя Щ-кодов) приготовил исходный код «рыбы» на STM8 asm.