モールス信号に挑戦

micro:bit でモールス信号送信したくて、その前に Delphi でロジック考えた際の記録

## 基本ルール

- 扱うのはアルファベット (A - Z) の 26 文字のみ
- micro:bit を想定しているので、2 つのボタンでトン・ツーを表現する
- 文字と文字の間は 1 ~ 2 秒あける
- 単語の終了は 3 秒以上あける
- 単語終了したらメモに表示する
- Clear ボタンを押したらトン・ツーをリセット

モールス符号は、[wikipedia](https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%BC%E3%83%AB%E3%82%B9%E7%AC%A6%E5%8F%B7) に掲載されている欧文モールス符号のアルファベットを使います

micro:bit を想定しているので、長押しの検知ではなく 2 つのボタンを使用して表現するルールを考えたらこんなルールになりました

実際 micro:bit 側では、AB ふたつのボタンと、AB のボタン同時押し、シェイクを使って、文字と単語の構成等々を行いましたが、先にロジック的なものができていたので、実装は楽でした

## 変換テーブルを作ったほうがいいよなぁ..
micro:bit は配列を定義できるので、アルファベットと、トン(A)ツー(B)を表した配列テーブルを作成するのが良さそうだ 

|モールス符号|アルファベット|  
|:------|:------|
|AB|A|
|BAAA|B|
|BABA|C|
|BAA|D|
|A|E|
|AABA|F|
|BBA|G|
|AAAA|H|
|AA|I|
|ABBB|J|
|BAB|K|
|ABAA|L|
|BB|M|
|BA|N|
|BBB|O|
|ABBA|P|
|BBAB|Q|
|ABA|R|
|AAA|S|
|B|T|
|AAB|U|
|AAAB|V|
|ABB|W|
|BAAB|X|
|BABB|Y|
|BBAA|Z|

## 文字間や単語の終了の判断はタイマー使おーっと
最初は、自分でカウントしようかと思っていましたが、タイマー使ったほうが楽じゃんってことに気が付いた

## 設計画面はこんなの
Timer の Interval プロパティはそれぞれ 1000と 3000をセット、また Timer の Enabled プロパティはそれぞれ False にします
![qiita01.png](https://qiita-image-store.s3.amazonaws.com/0/164551/a1a2369f-af1f-891a-1461-73097a66ebe9.png)

## サンプルコード

```delphi
unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.ScrollBox,
  FMX.Memo, FMX.Controls.Presentation, FMX.StdCtrls;

type
  TMorse = Record  // 変換テーブル
    xWord: string;
    xAlpha: string;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Memo1: TMemo;
    Timer1: TTimer;
    Timer2: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Timer2Timer(Sender: TObject);
  private
    // mWord はトンツー(AB)文字列を格納
    // mLine は変換した文字列を格納
    // mMorse は変換テーブル
    mWord, mLine: string;
    const mMorse: Array[0..25] of TMorse = (
      (xWord: 'AB'  ; xAlpha: 'A'),
      (xWord: 'BAAA'; xAlpha: 'B'),
      (xWord: 'BABA'; xAlpha: 'C'),
      (xWord: 'BAA' ; xAlpha: 'D'),
      (xWord: 'A'   ; xAlpha: 'E'),
      (xWord: 'AABA'; xAlpha: 'F'),
      (xWord: 'BBA' ; xAlpha: 'G'),
      (xWord: 'AAAA'; xAlpha: 'H'),
      (xWord: 'AA'  ; xAlpha: 'I'),
      (xWord: 'ABBB'; xAlpha: 'J'),
      (xWord: 'BAB' ; xAlpha: 'K'),
      (xWord: 'ABAA'; xAlpha: 'L'),
      (xWord: 'BB'  ; xAlpha: 'M'),
      (xWord: 'BA'  ; xAlpha: 'N'),
      (xWord: 'BBB' ; xAlpha: 'O'),
      (xWord: 'ABBA'; xAlpha: 'P'),
      (xWord: 'BBAB'; xAlpha: 'Q'),
      (xWord: 'ABA' ; xAlpha: 'R'),
      (xWord: 'AAA' ; xAlpha: 'S'),
      (xWord: 'B'   ; xAlpha: 'T'),
      (xWord: 'AAB' ; xAlpha: 'U'),
      (xWord: 'AAAB'; xAlpha: 'V'),
      (xWord: 'ABB' ; xAlpha: 'W'),
      (xWord: 'BAAB'; xAlpha: 'X'),
      (xWord: 'BABB'; xAlpha: 'Y'),
      (xWord: 'BBAA'; xAlpha: 'Z')
    );
    { private 宣言 }
  public
    { public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
begin
  // タイマー停止
  Timer1.Enabled := False;
  Timer2.Enabled := False;
  // トン = A を設定
  mWord := mWord + 'A';
  // タイマー始動
  Timer1.Enabled := True;
  Timer2.Enabled := True;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  // タイマー停止
  Timer1.Enabled := False;
  Timer2.Enabled := False;
  // ツー = B を設定
  mWord := mWord + 'B';
  // タイマー始動
  Timer1.Enabled := True;
  Timer2.Enabled := True;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  // タイマー停止
  Timer1.Enabled := False;
  Timer2.Enabled := False;
  // トンツー文字クリア
  mWord := '';
  // タイマー始動
  Timer1.Enabled := True;
  Timer2.Enabled := True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  i: integer;
begin
// 1 秒以上空いたら変換を行なう
// タイマー停止
  Timer1.Enabled := False;
// 変換テーブルと付き合わせて変換
  for i := 0 to 25 do begin
    if mWord = mMorse[i].xWord  then begin
      mLine := mLine + mMorse[i].xAlpha;
      mWord := '';
    end;
  end;
end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
// 3 秒以上空いたら単語終了
// タイマー停止
  Timer1.Enabled := False;
  Timer2.Enabled := False;
// 単語をメモに表示
  Memo1.Lines.Add(mLine);
  mLine := '';
end;

end.
```
mWord と mLine の最初の初期化をさらっと忘れていますw

## 動かしてみた
![qiita001.gif](https://qiita-image-store.s3.amazonaws.com/0/164551/73e1695e-158c-92d7-7497-6dcb04d5bade.gif)

SOSを送信しています

さて、これを踏まえて micro:bit 側が作れるか？