3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Android の音楽再生とLED表示の連携

Last updated at Posted at 2016-08-09

前の記事では、音楽再生サービスを拡張して、定期的に歌唱パターンを通知するようにしました。
通知を受信して、LED を点灯させる部分を作っていきます。

受信する通知は、メンバーごとの歌唱パート(0は歌っていない)という情報になります。
これをもとに、LED を光らせていきます。

受信した情報を元に、適切な位置の LED を適切な色で点灯させるために、BLE Nano 側のプログラムも拡張していきます。
そして、Android 側の BLE GATT 通信アプリで、拡張した BLE Nano 側の仕様に合わせて、データを送信していきます。

BLE Nano の拡張

表示したい色(メンバー・カラー)は決まっているので、BLE Nano 側で色テーブルを持たせ、通信量を減らします。

番号
0 消灯
1
2
: :
7

そして、Android と通信するバイト列データにいくつかのパターンを作って、ON/OFF 以外の制御をできるようにしていきます。
制御する内容としては、次の3つを用意していきます。

  • 制御する LED の個数を指定
  • 各 LED の色番号 (Byte列)
  • 表示する色の指定

簡単なデータは送らないので、こんな感じの簡単なパターンにしました。

先頭4文字 内容
ledn LEDの個数
ledd 色番号のバイト列
leds 色番号と色(R,G,B値)

本当なら、LED の個数は、表示機器側(BLE Nano 側)が持ち、表示機器側からスマートフォンに通知するのかなと思います。
ただ、BLE Nano はそこそこ高価なので、 LED の構成が違ういろんな表示機器に対して使い回したいので、今は、スマートフォンから BLE Nano に対して個数を指定する形にしています。

また、LED の点灯色の指定するには、色番号のバイト列を送ります。
1番目のバイトが1番目の LED の色番号、2番目のバイトが2番目の LED の色番号となり、LED の個数分の番号を送ります。

また、色テーブルは、調整のしやすさも考えてスマートフォン側からも書き換えられるようにしています。

mainc.cpp
void writeCharCallback(const GattCharacteristicWriteCBParams *params)
{
  if(params->charHandle == writeChar.getValueHandle()) {
    if (params->len >= 4){
      if ((params->data[0] == 'l') && (params->data[1] == 'e') && (params->data[2] == 'd')){
        switch(params->data[3]){
        case 'd':
          for (i = 4; i < params->len; i++) {
            if (i - 4 >= m_strip.num_leds) break;
            int idx = params->data[i];
            if (idx > COLOR_MAX) continue;
            neopixel_set_color(&m_strip, i-4, color_table[idx][0], color_table[idx][1], color_table[idx][2]);
          }
          break;
        case 'n': 
          leds_per_strip = params->data[4];
          m_strip.num_leds = leds_per_strip;
          for (i = 0; i < leds_per_strip; i++) neopixel_set_color(&m_strip, i, 0, 0, 0);
          break;
        case 's':
          uint8_t idx = params->data[4];
          if ((idx < 0) || (idx > COLOR_MAX)) break;
          color_table[idx][0] = params->data[5];
          color_table[idx][1] = params->data[6];
          color_table[idx][2] = params->data[7];
          break;
        }
      }
    }
  }
}

BLE Nano 側のコードはこんな感じです。
受信したデータを解析して、LED に色をセットしたり、個数を変更したり、色テーブルを更新したりしています。

GATT 通信アプリに LED 制御信号送信を追加

音楽再生サービスから受信した intent をもとに、LED 点灯の制御信号を送信します。
(LED 数の指定と、色テーブルの色指定に関するコードは割愛しています)

DeviceActivity.java
  protected void onCreate(Bundle savedInstanceState) {
   :
    IntentFilter filter = new IntentFilter("com.example.android.remotecontrol.ACTION_STATE_CHANGED");
    receiver = new BroadcastReceiver() {
      public void onReceive(Context context, Intent intent) {
        lightLED(intent);
      }
    };
    registerReceiver(receiver, filter);
   :
  }

  private void lightLED(Intent intent) {
    if (intent.getBooleanExtra("Update", false)) {
      if ( isConnected() ) {
        WriteBytes = new byte[4+mLEDNUM];
        WriteBytes[0]  = 'l';
        WriteBytes[1]  = 'e';
        WriteBytes[2]  = 'd';
        WriteBytes[3]  = 'd';
        WriteBytes[4]  = (intent.getIntExtra("v0", 0) > 0) ? (byte) 1 : 0;
        WriteBytes[5]  = (intent.getIntExtra("v1", 0) > 0) ? (byte) 2 : 0;
        WriteBytes[6]  = (intent.getIntExtra("v2", 0) > 0) ? (byte) 3 : 0;
        WriteBytes[7]  = (intent.getIntExtra("v3", 0) > 0) ? (byte) 4 : 0;
        WriteBytes[8]  = (intent.getIntExtra("v4", 0) > 0) ? (byte) 5 : 0;
        WriteBytes[9]  = (intent.getIntExtra("v5", 0) > 0) ? (byte) 6 : 0;
        WriteBytes[10] = (intent.getIntExtra("v6", 0) > 0) ? (byte) 7 : 0;
        sendData(WriteBytes);
      }
    }
  } 

onCreate の中で、intent を受信すると制御信号を送信する lightLED() を呼び出すコードを追加します。

そして、lightLED() では、受信した intent から getXXXExtras メソッドでデータを取り出し、制御信号を作っていきます。
"Update" が true の場合に、点灯パターンを変更するために、色番号を BLE Nano に送信します。
そこで、送信するバイト列 WriteBytes に、送信データを作成していきます。
まず、前半 4 バイトに 'ledd' を格納し、その後ろに各 LED の色番号を格納していきます。
intent で受信した "v0" → 1番目、"v1" → 2番目というように LED を割り当てろこととし、色番号もそれぞれ 1~7 を割り当てることとします。
"v0" ~ "v6" に対して、getIntExtra メソッドで取得した値が 0 以上 (つまり、どこかの高さを歌っている) 場合には色番号を、0 の場合に 0 を WriteBytes[] に格納していきます。
そして、sendData() で、作成したバイト列を送信します。

(isConnected() は BLE で接続中かどうかを返すメソッド、sendData() はキャラクタリスティックを書き込むメソッドです。
詳細は割愛させてください)

これで、音楽再生に連動して LED を点灯することができるようなりました。

今のところ LED の位置に対して色が固定で、うまく使いきれてません。
どう表現したら面白いのか? は、まだまだこれから模索したいと思います。

今回は、1人1人のデータを別々に持たせていますが、まとめる方法もあります。
各タイミングごとの全 LED の色番号のバイト列をそのまま JSON データとして用意します。
音楽再生サービスから GATT 通信アプリに intent 経由でバイト列を渡します。
そして、受信したデータ列に 'ledd' という文字列を追加して BLE Nano に送信します。

目次のページにリンクしたデモは、LED が 16個なので、この方法で作っています。

ここで、ファームやアプリなどソフト側の話は一度終わって、回路や箱を作っていく話にしたいと思います。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?