sql2arduinoコンパイラを作った話

# はじめに

この記事は、岩手県立大学アドベントカレンダー2015 10日目の記事です。

今回はSQLをArduinoのソースコードに変換するコンパイラを作った話です。

Arduinoは、AVRマイコンと入出力ポートを備えた基板、C++風のArduino言語とそれの統合開発環境から構成されるシステムです。

習得が容易なArduino言語とソースコードの編集やコンパイラ、基板への書き込み機能を備えたIDEが提供されているためプロトタイプ開発に向いているプラットフォームともいえます。

Arduinoの入出力ポートに照度センサを接続して以下のようなコードを記述すれば、照度を取得することができます。

```
/*
  AnalogReadSerial
  Reads an analog input on pin 0, prints the result to the serial monitor.
  Graphical representation is available using serial plotter (Tools > Serial Plotter menu)
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

  This example code is in the public domain.
*/

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // print out the value you read:
  Serial.println(sensorValue);
  delay(1);        // delay in between reads for stability
}
```

このコードを見たとき、Arduinoをデータベースと見立てればSQLからArduinoのソースコード
を生成できるのでないかと考えました。
ユーザから見ると「一定間隔で特定の入出力ポートの値がX以上のときの値を取得したい」となり、Arduinoから見ると「一定間隔で特定の入出力ポートの値がX以上のとき値をシリアルポートに出力する」となります。
これくらいの条件であればSQLのSELECT文で実装できそうです。
また、センサーネットワークの分野でお馴染みの[TinyDB](http://graphics.stanford.edu/courses/cs321-05-fall/Readings/p122-madden-TinyDB.pdf)の考え方も参考にしました。

# 実装

今回はJavaで実装しました。
最終的なソースコードは[GitHub](https://github.com/arthur87/Arno)にあります。

例えば、以下のようなSQL文を考えます。

```sql:sample.sql
select din11,ain20 from arduino where (din1 = 0 and din2 <=1 ) or din3 != 9
```

これは`(din1の値が0かつdin2の値が1以下)またはdin3の値が9でないときdin11の値とain20の値を選択する`ということになります。
din1はデジタルピン1、ain20はアナログピン20と意味です。

このSQLをArduino言語に変換します。
はじめにSQLの構文が正しいか確認します。構文解析にはjsqlparser（com.github.jsqlparser）を利用しました。

今回は単純なSELECT文のみのサポートするため、SELECT文に特定の予約語を含んでいる場合やUPDATEやINSERTからはじまる文はエラーにしています。

構文が正しいか確認したあと、列名に該当するデジタルピンとアナログピンを抽出します。
列名に指定できる値は、din1からdin20とain1からain20です。
それ以外を指定した場合はエラーとなります。

WHERE句は`and`と`or`をArduino言語の`&&`と`||`に変換すればそのまま使えることがわかります。

デジタルピンとアナログピン、WHERE句を使って以下のようなソースコードを生成することができます。

```c:example
// select din11,ain20 from arduino where (din1 = 0 and din2 <=1 ) or din3 != 9

void setup() {
  Serial.begin(9600);
  pinMode(1, INPUT);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(11, INPUT);
}

void loop() {
  int din1 = digitalRead(1);
  int din2 = digitalRead(2);
  int din3 = digitalRead(3);
  int din11 = digitalRead(11);
  int ain20 = analogRead(20);
  if( (din1 == 0 && din2 <= 1) || din3 != 9 ) {
    Serial.print("[ ");
    Serial.print(din11);
    Serial.print(" ");
    Serial.print(ain20);
    Serial.print(" ");
    Serial.print("]");
  }
  delay(1000);
}
```

# おわりに

`Serial.begin(9600);`や`delay(1000);`の引数の値を変えたい場合を考えました。
最初はSQLの予約語で代替になるものを探しましたが、該当しそうなものはありませんでした。
またSQLに新しい予約語を`select ain1 from arduino delay 2000`のように追加しようと思いましたが、大変な作業になるため諦めました。

結局はコンパイラオプションにすることにしました。

```bash
$ java -jar Arno.jar -i "select din11,ain20 from arduino where (din1 = 0 and din2 <=1 ) or din3 != 9" -speed 19200 -delay 2000
````

`-speed` を指定するとSerial.begin(speed)を変更することができます。 省略した場合は9600です。
`-delay` を指定するとdelay(ms)を変更することができます。 省略した場合は1000です。