酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

Windows Mobileで赤外線通信を制御する

赤外線通信は、人間の目に見えない赤外線でデータ通信を行います。.NET Compact Frameworkでは、System.Net.IrDA アセンブリを参照する事で、ハードウェアの差異を意識せずに赤外線通信を行う事が可能です。サンプルアプリを作成しながら、赤外線通信を利用したデータの送受信処理についてをご紹介します。

赤外線通信アプリの作成

このサンプルアプリは、入力したテキストの送信と受信を行います。赤外線通信はデバイス間の通信なので、実際に実施するにあたり最低でも送信用と受信用にWindows Mobile端末が2台必要となります。

赤外線通信可能なデバイスIDを一覧表示したコンボボックス、送信する文字列を入力、または受信したデータを表示するためのテキストボックスと、赤外線通信でデータの送信と受信を行うボタンをそれぞれ配置します。

f:id:ch3cooh393:20140817151431p:plain

通信可能なデバイスの表示

まずは初期化処理を行います。コードの説明に移る前に、赤外線デバイスを制御するアセンブリSystem.Net.IrDA.dllを参照しておきます。赤外線通信可能なデバイスを探索させる為に、使用するIrDAClientクラスのインスタンスをアプリ起動時に作成し、終了時に破棄します。

public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();
  }

  // 赤外線通信を制御するクライアントクラス
  private System.Net.Sockets.IrDAClient irClient = null;

  // 通信の際に使用するサービス名
  private string irServiceName = "IrDASample";

  private void Form1_Load(object sender, EventArgs e)
  {
    // IrDAデバイスの接続を開始する
    irClient = new System.Net.Sockets.IrDAClient();
  }

  private void Form1_Closing(object sender, CancelEventArgs e)
  {
    // IrDAデバイスの接続を切断します
    if (irClient != null) irClient.Close();
  }

  private void btnSearch_Click(object sender, EventArgs e)
  {
    // 発見したIrDAデバイスを取得します
    System.Net.Sockets.IrDADeviceInfo[] irDevices = irClient.DiscoverDevices(2);

    // IrDAデバイスを発見できなかった場合、送信は行いません
    if (irDevices.Length == 0) return;

    // リストボックスへデバイスの一覧を表示
    listBox1.Items.Clear();
    listBox1.DisplayMember = "DeviceName";
    foreach (System.Net.Sockets.IrDADeviceInfo info in irDevices)
    {
      listBox1.Items.Add(info);
    }
    listBox1.SelectedIndex = 0;
  }
}

次にデバイスの探索の処理です。赤外線通信可能なデバイスを探索し、コンボボックスへ表示させるSearchDevicesメソッドを用意しました。「Search」ボタンのClickイベントハンドラ内でこのメソッドを呼びます。

IrDAClientクラスのDiscoverDevicesメソッドで、赤外線通信に対応したデバイスの検索を DiscoverDevicesメソッドで取得します。取得したデバイスのIDをコンボボックスへ表示させます。このメソッドは、各デバイスの情報を提供するIrDADeviceInfoの配列を返します。

private void btnSearch_Click(object sender, EventArgs e)
{
  // 発見したIrDAデバイスを取得します
  System.Net.Sockets.IrDADeviceInfo[] irDevices = irClient.DiscoverDevices(2);    
  // IrDAデバイスを発見できなかった場合、送信は行いません
  if (irDevices.Length == 0) return;
  
  // リストボックスへデバイスの一覧を表示
  listBox1.Items.Clear();
  listBox1.DisplayMember = "DeviceName";
  foreach (System.Net.Sockets.IrDADeviceInfo info in irDevices)
  {
    listBox1.Items.Add(info);
  }
  listBox1.SelectedIndex = 0;
}

データの送信処理

通信可能なデバイスの一覧が取得出来ましたので、赤外線を使用したデータ送信を行うためのサンプルコードを以下に示します。

リストボックスに格納されているデバイスの識別子と、サンプルアプリ内部で統一したサービスの名前を用いてエンドポイントを指定し、デバイス間の接続を要求します。

private void btnSend_Click(object sender, EventArgs e)
{
  // コンボボックスで選択しているデバイスのIDを取得する
  System.Net.Sockets.IrDADeviceInfo info 
      = (System.Net.Sockets.IrDADeviceInfo)listBox1.SelectedItem;
  
  // IrDAデバイスと接続を行います
  try {
    // IrDAデバイスの接続を開始する
    irClient = new System.Net.Sockets.IrDAClient();
  
    System.Net.IrDAEndPoint irEndP
        = new System.Net.IrDAEndPoint(info.DeviceID, irServiceName);
    irClient.Connect(irEndP);
  } catch (Exception ex ) {
    MessageBox.Show("Connect Error!!\r\n" + ex.Message);
    return;
  }
  
  // 送信するテキストをバイト配列に変換
  byte[] bytes = System.Text.Encoding.UTF8.GetBytes(textBoxSend.Text);
  int sendLength = bytes.Length;
              
  // 通信先のデバイスに対してデータを送信します
  using (System.IO.Stream strm = irClient.GetStream())
  {
    // テキストのサイズを16bitのバイト配列としてストリームへ書き込む
    byte[] length = BitConverter.GetBytes(sendLength);
    strm.Write(length, 0, length.Length);
    
    // テキストをストリームへ書き込む
    strm.Write(bytes, 0, bytes.Length);
  }
}

データの受信処理

IrDAListenerクラスのStartメソッドで通信相手からの接続要求を待ちます。接続要求を受け取った後は、相手クライアントからのレスポンスを赤外線経由にて受け取ります。

private void btnReceive_Click(object sender, EventArgs e)
{
  // コンボボックスで選択しているデバイスのIDを取得する
  System.Net.Sockets.IrDADeviceInfo info
      = (System.Net.Sockets.IrDADeviceInfo)listBox1.SelectedItem;
  
  // IrDAデバイスと接続を待ちます
  try
  {
    System.Net.IrDAEndPoint irEndP
        = new System.Net.IrDAEndPoint(info.DeviceID, irServiceName);
    System.Net.Sockets.IrDAListener irListen 
        = new System.Net.Sockets.IrDAListener(irEndP);

    // 接続要求待ちの開始
    irListen.Start();
    irClient = irListen.AcceptIrDAClient();
  }
  catch (Exception ex)
  {
    MessageBox.Show("Connect Error!!\r\n" + ex.Message);
    return;
  }
  
  // 相手クライアントからのレスポンスを受け取ります。
  using (System.IO.Stream strm = irClient.GetStream())
  {
    int numRead = 0;
    int numToRead = 0;
    
    // 先頭4バイトを読み取る
    numToRead = 4;
    byte[] sizeBuf = new byte[4];
    while (numToRead > 0)
    {
      int offset = sizeBuf.Length - numToRead;
      numRead = strm.Read(sizeBuf, offset, numToRead);
      numToRead -= numRead;
    }
    
    // 受信するデータのサイズを取得する
    uint dataSize = BitConverter.ToUInt32(sizeBuf, 0);
    
    // データの受信します
    numToRead = (int)dataSize;
    byte[] dataBuf = new byte[numToRead];
    while (numToRead > 0)
    {
      int readSize = Math.Min(dataBuf.Length, numToRead);
      numRead = strm.Read(dataBuf, dataBuf.Length - numToRead, readSize);
      numToRead -= numRead;
    }
    
    // 受信したデータを文字列エンコードしてテキストボックスに表示する
    textBoxReceive.Text 
        = System.Text.Encoding.UTF8.GetString(dataBuf, 0, dataBuf.Length );
  }
}

赤外線以外の無線通信

スマートフォンに搭載されている無線通信の代表格として、赤外線以外では標準で登載されることの多いBluetoothと無線LANですが、.NET CFにはBluetoothや無線LANのデバイスを操作するためのクラスが用意されていません。

基本的にP/Invokeを介して処理させる為、列挙体や構造体等の定義を行いWIN32API関数にてデバイスの制御を行う必要があります。ここではOpenNETCFを使用して簡単にBluetoothの制御を行ってみましょう。

下記のコードでは、Bluetoothデバイスの有効にします。OpenNETCF.WindowsMobile名前空間のBluetoothRadioクラスを使用するので、OpenNETCF.WindowsMobile.dllのアセンブリを参照しておいて下さい。

private OpenNETCF.WindowsMobile.BluetoothRadio m_btRadio; 
private void BluetoothStateON()
{
  OpenNETCF.WindowsMobile.Radios radios
    = OpenNETCF.WindowsMobile.Radios.GetRadios();
  foreach (OpenNETCF.WindowsMobile.IRadio radio in radios)
  {
    // Bluetooth以外のデバイスなら何もしない
    if (!radio is OpenNETCF.WindowsMobile.BluetoothRadio)
    {
      continue;
    }
    
    m_btRadio = radio as OpenNETCF.WindowsMobile.BluetoothRadio;
    
    if (m_btRadio.RadioState != OpenNETCF.WindowsMobile.RadioState.On)
    {
      // Bluetoothデバイスを有効にする
      m_btRadio.RadioState = OpenNETCF.WindowsMobile.RadioState.On;
      
      System.Threading.Thread.Sleep(5000);
    }
  }
  radios.Refresh();
}

既にペアリング済みの端末間であれば、COMポートの通信にてデータの送受信が可能です。また同じようにBluetoothRadioクラスではなくWifiRadioクラスを使用するだけで無線LANデバイスを制御する事が可能です。

関連記事

Windows Mobile(.NET Compact Framework)を使ってアプリ開発する際に逆引きとしてお使いください。