shokai / arduino_firmata

Arduino Firmata protocol implementation on Ruby
http://shokai.github.io/arduino_firmata
MIT License
104 stars 23 forks source link

support Sysex command #14

Closed shokai closed 11 years ago

shokai commented 11 years ago

実装するもの

PC-Firmata間で2byte以上のデータをやりとりする時に使う。StandardFirmataではArduino→PCへのDIGITAL_MESSAGE, ANALOG_MESSAGE, REPORT_VERSIONで使われている。 自作のコマンドを実行させるのにも使われる。

[START_SYSEX, コマンド名, 7bitを32個分のデータ, END_SYSEX] を1セットとして送信する。 http://firmata.org/wiki/V2.1ProtocolDetails#Sysex_Message_Format

/* Generic Sysex Message
 * 0     START_SYSEX (0xF0)
 * 1     sysex command (0x00-0x7F)
 * x     between 0 and MAX_DATA_BYTES 7-bit bytes of arbitrary data
 * last  END_SYSEX (0xF7)
 */

MAX_DATA_BYTESは /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata/Firmata.h で定義されている。 デフォルトで7bitのデータを最大32個送れる。

#define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages

既に定義されているsysex command。0x00-0x0Fはユーザが自分のアプリ内で定義していいらしい。

// extended command set using sysex (0-127/0x00-0x7F)
/* 0x00-0x0F reserved for user-defined commands */
#define SERVO_CONFIG            0x70 // set max angle, minPulse, maxPulse, freq
#define STRING_DATA             0x71 // a string message with 14-bits per char
#define SHIFT_DATA              0x75 // a bitstream to/from a shift register
#define I2C_REQUEST             0x76 // send an I2C read/write request
#define I2C_REPLY               0x77 // a reply to an I2C read request
#define I2C_CONFIG              0x78 // config I2C settings such as delay times and power pins
#define EXTENDED_ANALOG         0x6F // analog write (PWM, Servo, etc) to any pin
#define PIN_STATE_QUERY         0x6D // ask for a pin's current mode and value
#define PIN_STATE_RESPONSE      0x6E // reply with pin's current mode and value
#define CAPABILITY_QUERY        0x6B // ask for supported modes and resolution of all pins
#define CAPABILITY_RESPONSE     0x6C // reply with supported modes and resolution
#define ANALOG_MAPPING_QUERY    0x69 // ask for mapping of analog to pin numbers
#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info
#define REPORT_FIRMWARE         0x79 // report name and version of the firmware
#define SAMPLING_INTERVAL       0x7A // set the poll rate of the main loop
#define SYSEX_NON_REALTIME      0x7E // MIDI Reserved for non-realtime messages
#define SYSEX_REALTIME          0x7F // MIDI Reserved for realtime messages
// these are DEPRECATED to make the naming more consistent
#define FIRMATA_STRING          0x71 // same as STRING_DATA
#define SYSEX_I2C_REQUEST       0x76 // same as I2C_REQUEST
#define SYSEX_I2C_REPLY         0x77 // same as I2C_REPLY
#define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL

現在のgem内での実装

arduino_firmata gemでは、START_SYSEXとEND_SYSEXが const.rbで定義されてる https://github.com/shokai/arduino_firmata/blob/master/lib/arduino_firmata/const.rb

module ArduinoFirmata
  START_SYSEX     = 0xF0 # start a MIDI SysEx message
  END_SYSEX       = 0xF7 # end a MIDI SysEx message
end

ArduinoFirmata::Arduino::write関数はprivateにしてある。 PC→Arduinoへsysexコマンドを送る関数を作る必要アリ。 Arduino→PCにコマンドが来た時のイベントも登録できるようにしたい。

Arduino側にSysexコマンドを登録する

/Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata/Firmata.cpp にあるattach関数にsysex command (0x00-0x7F)を引数として、コールバックを登録する。

http://firmata.org/wiki/V2.1ProtocolDetails#Sysex_Message_Format を見ると、0x00~0x0Fはユーザが自由に使って良い様に予約されているんだけど、登録しても現在Arduino IDEに付属しているFirmata.cpp内では呼び出されるように実装されてない。

方法は2つで、

  1. SysexのSTRING_DATAコマンドが来た時のイベントを登録する
  2. Sysexを受信した時の関数を登録する

のどちらか。

1. STRING_DATA (0x71)コマンドが来た時のイベントを登録

STRING_DATAは自作アプリで使える。

STRING_DATA (0x71)はFirmata.cpp内でコールバックとして登録できるようになっているが、Arduino IDE付属のStandardFirmata.inoからは使われていない。

スケッチ例のEchoStringで使ってる。

#include <Firmata.h>

byte analogPin;

void stringCallback(char *myString)
{
    Firmata.sendString(myString);
}

void sysexCallback(byte command, byte argc, byte*argv)
{   
    Firmata.sendSysex(command, argc, argv);
}

void setup()
{   
    Firmata.setFirmwareVersion(0, 1);
    Firmata.attach(STRING_DATA, stringCallback);
    Firmata.attach(START_SYSEX, sysexCallback);
    Firmata.begin(57600);
}

void loop()
{   
    while(Firmata.available()) {
        Firmata.processInput();
    }
}

2. Sysexを受信した時のコールバック関数を登録

StandardFirmataの void sysexCallback(byte command, byte argc, byte *argv) 関数内のswitch文に書き足すといい。 I2C関係はここで定義されている。

参考になる

shokai commented 11 years ago

PC→Arduinoにsysexコマンドを送れるようになった

受信も作ろう