Windows 10 IoT CoreをはじめとするUWPアプリでBLEデバイスを扱う

先ずは、IoT Kitハンズオントレーニング のデバイス側で、Windows 10 IoT CoreのUWPアプリ(Windows 10 PCでも実施可能)とTexas InstrumentsのSensor Tag(CC2541、CC2650)の組合せを追加したことをお知らせします。https://github.com/ms-iotkithol-jp/IoTKitHoLV3 のWinIoTCoreTIIoTHubAppフォルダーに入っているソリューション一式がそれです。TI Sensor TagをデバイスやPCとペアリングすれば、あとは、WpfEmuIoTHubAppと同じ要領で自学自習可能ですので、TI Sensor Tag持っている人は是非試してみてください。一般のPC、Raspberry Pi3やDragonBoardなどBLE対応のデバイスであれば特にBLEのドングルなどなくても実習可能です。 さて本題です。このアプリを作っている過程で、BLEデバイスにアクセスするためのWindows Runtime APIの使い方でてこずりました。ライブラリー群は、非同期メソッドなので、await 句を付けてコールすれば通常は問題なく使えるのですが、HandsOn.csファイルの中で、普通のやり方をやっても実行がブロックされて戻ってきません。では、Taskのまま受けて、Wait()で待って、結果をResultで受け取って…を試してみたら、デバッガーで一行一行ステップバイステップで動かすと、一応動くのですが、一気通貫で実行しようとすると、Wait()から帰ってこない!最悪のパターンだ…どうしよう、ってな状況になってしまいました。しかしなぁ…サンプルでは動いてるしなぁ…何が違うの? と考えて動くものと動かないものを比較した結果、解が得られました。どうやら、UWPアプリとして作ったプロジェクトの中ではawaitやWait()がうまく動かないらしく、UWPアプリプロジェクトを作った時に出来上がるソリューションに、別途UWPクラスライブラリプロジェクトを作って追加、そのクラスライブラリ上にBLEデバイスにアクセスするFindAllAsyncやらなんやらをコールするコードを置くとうまく動くんですな。Gitに挙げているサンプルもそういう作りになっています。 ってことで、await機能しないじゃん、なにこれ?…と首をかしげてる皆さん、この方法試してみてください。 ではでは

0

デスクトップアプリでWindows Runtime APIをコールする(センサーとか)

前から、デスクトップアプリからWindows Runtime API(の一部)を呼び出せるのは知っていたのですが、最近、本当にコールする必要が生じたので、やり方をここに書いておきます。 ※この投稿はストアアプリより、デスクトップアプリの方が良いです…という話ではありません。使えるWinRT APIは一部だし、セキュリティ、パフォーマンスなどストアアプリで使った方がいいので、なるべくストアアプリを使うことをお勧めします。 Windows Runtime APIを使おうとするのは、Visual Studioで、”Windowsデスクトップ”→”WPFアプリケーション”プロジェクトテンプレートで作ったプロジェクトです。このプロジェクトは本来.NET FrameworkのAPIを使用します。 プロジェクトファイル(C#なら*.csproj)をテキストエディタ等で開きます。 <Project>…</Project>という記述がありますね。その中に<PropertyGroup>…</PropertyGroup>という定義がいっぱいあります。これらに並べて、   <PropertyGroup>    <TargetPlatformVersion>8.0</TargetPlatformVersion>  </PropertyGroup> を入れます。 プロジェクトをVSで再度開きます。 参照設定に、以下のパスに存在する、Windows.winmd というファイルを追加します。 C:\Program Files (x86)\Windows Kits\8.1\References\CommonConfiguration\Neutral ※32ビットOSの場合は、”Program Files\Windows Kits… これで設定は終わり。 例えば、加速度センサーなら、 var accelerometer = Windows.Devices.Sensors.Accelerometer.GetDefault(); と、こんな風に取り出すことができます。但し、イベントを”+=”の様な普通の形式では使うことはできません。  

2

Philips hueをWindows ストアアプリから制御する

de:code 14等で紹介した、Philips hueをコントロールするストアアプリのサンプルを公開します。 http://eg-sample-filedowload.azurewebsites.net/FileDownload/GetFile?id=RemoteLightControlTemplate ストアアプリのプロジェクトテンプレート形式で公開しているので、ダウンロードしたZIPファイルを、各自のVisual Studio 2013フォルダー(Projectsフォルダーのあるところ)の Templates\ProjectTemplates\Visual C# というフォルダーにコピーして、Visual Studio 2013を起動し、新規プロジェクト作成で、 Remote Light Control Appを選んでプロジェクトを作成してください。UI部分を作りかえれば、ほぼ、ストアに申請可能な形式です。この中に、UDP Multicast Group通信によるUPNPのSSDPプロトコルや、hueを見つけるコード、REST APIアクセスなどすべてあるので、是非、参考にしてくださいね。 ※あくまでもサンプルコードです。利用は各自の責任において行ってください。利用したことにより発生するいかなる責任も負いませんのでご承知おきください。    

0

Windows ストアアプリでUPnPデバイスを発見する

UPnP(Universal Plug and Play)対応のデバイスをWindows ストアプリで発見する方法を紹介します。UPnPアプリを発見するプロトコルであるSSDPを使ってデバイスの定義を取得する方法です。DLNA対応機器や、Philips Hueなど、この解説を使ってアドレスを取得することができます。 SSDPは、UDPのMulticast Group通信を使っており、ストアアプリでは、DatagramSocketを使用します。 DatagramSocket ssdpSocket = new DatagramSocket(); と、データグラムソケットを一つ作成します。そして、データグラムソケットに、UPnPデバイスからの応答を受け取るためのハンドラ―を登録します。 ssdpSocket.MessageReceived += ssdpSocket_MessageReceived; SSDPは、239.255.255.250、1900というグループアドレス、グループポートを使います。この情報を使ってマルチキャストグループにジョインします。     var ssdpGroup = new HostName(“239.255.255.250”);    string ssdpGroupPort = “1900”;    await ssdpSocket.BindEndpointAsync(null, “”);    ssdpSocket.JoinMulticastGroup(); そして、SSDPの規約に従った、デバイス発見の為の送信メッセージを組立て送信します。     string discoverPacket = “M-SEARCH * HTTP/1.1\r\n”;    discoverPacket += “HOST: ” + ssdpGroup .DisplayName +”:” + ssdpGroupPort + “\r\n”;    discoverPacket += “ST: upnp:rootdevice\r\n”;    discoverPacket += “MAN: \”ssdp:discover\”\r\n”;    discoverPacket…

0

Windows 8.1 ストアアプリからWinUSBを通じて.NET Gadgeteerと連携する

最近、Windows 8.1 の周辺機器連携に関する記事を書いていますが、今回は、UsbDeviceクラスを使って、.NET Gadgeteerとシリアル通信する方法を紹介します。 使った製品は、 ELECOM製、UC-SGT(RS232C USB変換ケーブル) FEZ Spider (.NET Micro Frameworkが動くARM7ボード) FEZシリーズのRS232Cボード FEZシリーズの加速度センサーなど です。手元にあったものを使ってみました。 以前もこのブログで紹介していますが、ELECOM製UC-SGTケーブルは、ELECOMさんからWinUSBクラスで認識するためのソフトウェアを、 http://www2.elecom.co.jp/search/link/search.asp?group=/cable/usb/uc-s/gt/&link_type=3 から、公開していただいているので、予め、Windows 8.1 PCにこのソフトウェアを当てておきます。 写真の様に、UC-SGTケーブルと、FEZ SpiderのRS232Cボードを、RS232Cヌルモデムケーブル経由でつなぎます。 これで、UC-SGTケーブルをWindows 8.1 PCのUSBポートにつなげば、ストアアプリとFEZ Spiderボードの間でシリアル通信ができます。この時、UC-SGTケーブルを介してつながったデバイスは、Communication Device Classで接続されます。 FEZ Spider側は、 こんな風にボードをつなぎます。左下のボードがRS232Cボードです。送受信プログラムは、Program クラスの ProgramStartedメソッドで、以下の初期設定コードを追加             rs232.Initialize();            rs232.serialPort.DataReceived += serialPort_DataReceived; します。DataReceivedイベントに登録しているハンドラは、         void serialPort_DataReceived(GT.Interfaces.Serial sender, System.IO.Ports.SerialData data)        {            int bytes = rs232.serialPort.BytesToRead;            byte[] buffer = new byte[bytes];           …

2

Bluetooth SPP(Rfcomm)双方向通信

前のポストで、Windows 8.1の新機能、Bluetooth Serial Port Profileを介して接続するデバイスとの通信方法について、基本を説明しました。 実際のデバイスとのデータ通信では、ハンドシェーク的なコマンドの送信だけでなく、単に送るだけのコマンドあり、デバイスの方から任意のタイミングで送信してくる通知もあります。例えばLego Mindstormsとの通信の場合もそうです。 .NET FrameworkのSerialPortクラスにはデータ受信を知るためのイベントハンドラが用意されていたり、Threadを駆使したマルチスレッドプログラミングでこなせました。WinRT APIでは、これらの方法は使えないので、別のパターンが必要です。 このポストでは、非同期プログラミングの仕組みと、タスク間の同期をとるManualResetEventクラスを使います。Lego Mindstorms NXTとの通信を例として説明します。 通知は任意の時点で送信されてきます。応答コマンドはPCから応答付コマンドを送信した時その応答として送信されてきます。デバイスから送られてくる送信を常に受信するループを用意します。PCから応答付コマンドを送信する場合、データ送信後に待ちにはいり、受信ループ側ではデータパケットを受信した時、通知か応答付コマンドの応答かを判断し、応答であればデータ送信後の待ちを解除する、通知であればバッファリング、もしくは、イベントを発行するなどでロジックを組めば、うまく動きます。 先ず、以下のメンバー変数、メソッドを用意します。     private ManualResetEvent mre = new ManualResetEvent( false );    private byte lastCommandSent;    private List<byte[]> receivedMessages = new List<byte[]>();     private async Task DataReceive(StreamSocket socket)    {        DataReader dataReader = new DataReader(socket.InputStream);        while (btSocket != null)        {            var loadResult = await dataReader.LoadAsync(2);            byte[]…

1

Windows 8.1ストアアプリでBluetooth 2.0接続周辺デバイスと通信する

Windows 8.1で強化されたWinRT APIによる周辺デバイス連携に関するポスト、第一弾です。 Bluetooth 2.0でPCにリモート接続され、仮想COMポートにマップされてシリアル通信する周辺デバイスは沢山あります。このポストでは、WinRT APIを使って、このような周辺デバイスと通信する方法を解説します。 Bluetooth 2.0デバイスと通信するには、手動でWindows 8.1 PCと周辺デバイスのペアリングが必要です。Windows 8.1では、設定チャーム→PC設定の変更→PCとデバイス→Bluetoothで、つなぎたいデバイスとペアリングができます。 プログラムの流れは、以下の通りです。 つなぎたいデバイスに関するRfcommDeviceServiceを検索 見つけたRfcommDeviceServiceを基にStreamSocketを作成 通信用のDataWriterとDataReaderを作成 DataWriter、DataReaderでデータを送受信 具体的なコードを以下に説明していきます。以下の名前空間に対するusing宣言をしておいてください。 using Windows.Devices.Enumeration;using Windows.Devices.Bluetooth.Rfcomm;using Windows.Networking.Sockets;using Windows.Storage.Streams; 1. つなぎたいデバイスに関するRfcommDeviceServiceを検索 通信するデバイスの名前は、”NXT”とします。     RfcommDeviceService deviceService;    var servicesInfos = await DeviceInformation.FindAllAsync(        RfcommDeviceSrevice.GetDeviceSelector(RfcommServiceId.SerialPort));    foreach (var serviceInfo in serviceInfos)    {        if (serviceInfo.Name == “NXT”)        {            deviceService = await RfcommDeviceService.FromIdAsync(serviceInfo.Id);            break;        }    } これで、Bluetooth 2.0で接続するためのDeviceServiceを取得できました。 2.見つけたRfcommDeviceServiceを基にStreamSocketを作成    …

2

WinRT APIによるセンサー利用

自分のブログを振り返ってみて、あれ?WinRT APIのセンサー系に関する投稿が無い!!…ってことで、WinRT APIによるセンサープログラミングの解説です。 Windows 8のタブレットでは、WinRT APIを通じて以下の7つのセンサーを利用したプログラミングが可能です。 Accelerometer: 加速度センサー Gyrometer: ジャイロセンサー Compass: コンパス LightSensor: 照度センサー Inclinometer: 傾斜計 SimpleOrientationSensor: シンプルな方向センサー OrientationSensor: 方向センサー これらはWindows.Devices.Sensors 名前空間で提供されるクラス群です。これらのクラスを使ってタブレットの姿勢や向いている方向、動き、周囲の明るさをアプリケーションのシナリオに取り込むことができるわけです。各センサーから得られる値の種別は、センサー毎に異なりますが、全て同じ流儀で計測値を取得できます。Accelerometerを例に、センサープログラミングのパターンを説明しますね。 まず、センサーへの参照の取り出し方です。 var mySensor = Windows.Devices.Sensors.Accelerometer.GetDefault(); 各センサーのクラスにはGetDefault()という名前のスタティックメソッドが用意されています。このメソッドをコールすることにより、センサーへの参照が取得できます。残念ながら全てのWindows 8 PCにセンサーが装備されているわけではありません。センサーが装備されていないPCでこのコードを実行すると、nullが返されます。センサーを活用するアプリを開発する場合には、センサーが装備されていない場合の考慮も必要です。ストア申請で、「アプリにはセンサーが必要」と明記するか、キーボードやマウスによる代替入力手段を用意するかしておきましょう。勿論、センサーが装備されていない場合(GetDefaultでnullが返された場合)に、不用意にmySensorにアクセスしないようにnullチェックを入れる必要があります。 センサーが計測したデータを取得する方法は二種類あります。一つはセンサーの計測値が必要な時点で計測値を要求する方法で、もう一つは、センサーがデータを計測した時点でイベントハンドラで計測値を受ける方法です。前者のコードは以下のようになります。 if (myAccel != null){    var reading = mySensor.GetCurrentReading(); 各センサーのクラスには、必ずGetCurrentReading()というメソッドが用意されていて(※SimpleOrientationSensorを除く)、このメソッドをコールすることにより、センサー計測値を参照したいときに値を取り出すことができます。Accelerometerクラスの場合、このメソッドが返すのはAccelerometerReadingという型の変数です。他のセンサーの場合も、クラス名にReadingという接尾詞がついた型が用意されています。AccelerometerReadingの場合は、X、Y、Zというプロパティが定義されていて、それぞれX方向、Y方向、Z方向の加速度が格納されています。 次に、センサーがデータを計測した時点でのイベントハンドラで計測値を受ける方法ですが、  if (mySensor != null) {    mySensor.ReadingChanged += mySensor_ReadingChanged; } とイベントハンドラを登録します。前者と同様、各センサーのクラスには、ReadingChangedというイベントが用意されています(※SimpleOrientationSensorを除く) 登録したイベントハンドラは、 void mySensor_ReadingChanged(Windows.Devices.Sensors.Accelerometer sender, Windows.Devices.Sensors.AccelerometerReadingChangedEventArgs args){    var reading = args.Reading;    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, ()…

0

Build 2013でのWindows 8.1 + 周辺デバイスコンテンツ紹介

先月(2013年6月)サンフランシスコで開催されたBuild 2013。Windows 8.1に関する様々な技術情報が発信されました。このブログでは、Windows ストアアプリで数多あるWindows対応周辺機器との連携用に追加された、Win RT API(Windows Runtime API)を紹介します。先ずはざっくり関連セッションを紹介し、その後、このブログで、各セッションの話題を深堀していこうと思っております。 先ずは、2-023 Building Apps That Connect with Devices をご覧ください。このセッションでは、Windowsに対応する様々な周辺機器とストアアプリが連携する基本事項が紹介されています。 関連セッションとしては、 3-025 Building Windows apps that use scanners いわゆる、イメージスキャナーとの連携方法 2-041 Strongauthentication: Building apps that leverage virtual smart cards in enterprise, BYOD, and consumer environmentsスマートカードを使ったストアアプリ 3-029 How to point-of-sale devies in your appバーコードや磁気カードリーダーをストアアプリで使う 2-9110 Biometrics-fingerprints for apps指紋認証 3-9034 Using Geolocation…

1

WinRT APIでJSONフォーマットをデシリアライズする方法

前に投稿した、WinRT APIでJSONフォーマットをでシリアライズする方法 の続編です。   シリアライズしたいJSONのフォーマットが、 {“__type”:”UserTypeA:#UserTypeNS”,”Properties”:{“PropertyX”:”ValueX”, “PropertyY”:”ValueY”},”DataPackets”:[{“__type”:”UserTypeB:#UserTypeNS”,”PropertyA”:”ValueA”,”PropertyB”:”ValueB”}],”Values”:[“1″,”2″,”5”]} といったような形式をとる場合のデシリアライズロジックを紹介します。 先ず、JSONのデータを表現するクラスを定義します。 namespace UserTypeNS{     [DataContract]    public class UserTypeA    {        [DataMember]        public List<UserTypeB> DataPacketA;        [DataMember]        public List<int> Values;    }     [DataContract]    public class UserTypeB    {        [DataMember]        public string PropertyA;        [DataMember]        public string PropertyB;    }     [DataContract]    public class PropertiesType    {        [DataMember]        public string PropertyX;        [DataMember]        public string PropertyY;    }}…

0