8-разрядный код Морзе

?v=1

По просьбе одного из любителей применения Щ-кодов в электронных поделках возникла необходимость написать функцию (подпрограмму, процедуру), которая будет издавать трель из последовательности точек и тире. В коде Морзе длина символа может быть от 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.

© Habrahabr.ru