ArduinoでもWinIoTでもそのまま使えるライブラリを作るテクニック

Make an Arduino library for Windows IoT Core
大阪日本橋の電子パーツショップ・デジットの200円LCD「AM50288H」。かつては段ボールいっぱいに入っているのを見かけていたのですが、最近では残りもわずかとなってきました。そんなじわじわ売れゆくLCDを見て、昔紹介したプログラミング記事を改良したい気持ちに駆られたので、今回は題名の通りのプログラミングテクニックをご紹介します。このノウハウを使って「これはWindows IoT Coreで作ったライブラリーのソースだけど、Arduinoでも手を加えることなく、すぐに使えるよ」とPRすれば、より多くの開発者の注目を集められるかも!?

まずは、「AM50288H」を制御するC#コードをArduinoライブラリーとして動作することを意識して、C++言語で書き直してみます。VC++独自拡張の「#pragma once」を使用しない、「#include <arduino.h>」を追加する二点を守れば、ArduinoでもWindows IoT Coreでも動作するコードが記述できます。以下のコード例は一部割愛しているので、すべてのコードをご覧になりたい方はこのページの最下部にあるリンクから入手してください。
libAM50288H.h
// libAM50288H.h
#ifndef __AM50288H_H__
#define __AM50288H_H__

#include <arduino.h>

class AM50288H
{
private:
    enum SegmentBit
    {
    }
    const static int Digits = 8;
    const static int Segments = 14;
    const static int DinsLen = 142;
    const SegmentBit segarray[Digits][Segments] = {
        {...},
        {...}
    };

    byte ple, pdin, psck = 0xFF;
    byte dins[DinsLen];

public:
    AM50288H();
    AM50288H(byte pinLE, byte pinDIN, byte pinSCK);
    ~AM50288H();

    void setPins(byte pinLE, byte pinDIN, byte pinSCK);
    void begin();
    void update();
    void clear();
};

#endif __AM50288H_H__
以下の写真はこのC++クラスをArduino IDEのスケッチに書きこみ、実行した例です(このスケッチも"sketch_am50288h.ino"としてサンプルに含まれています)。動作確認ができたら、Windows IoT Coreに組み込んでみましょう。
ArduinoはC++言語がベースなので、Windows IoT CoreではC++/CXランタイムライブラリとしてプロジェクトを作成します。プロジェクトを作ったら、先のクラスをプロジェクトに追加し、ランタイムライブラリの仕様内に収まるようにラッパークラスを作ります。ちなみに、C言語のenumはランタイムライブラリとの互換性がないため、橋渡しのためのC++/CXとしてのenumを必要に応じて用意する必要があるのですが、これにFlags属性を加える際は「 : unsigned int」の一文がないとエラーになる点に注意しましょう。
AM50288H.h
// AM50288H.h
#pragma once

#include "libAM50288H.h"

namespace Tnksoft {
namespace AM50288H {
    public enum class Mark
    {
    };

    [Platform::Metadata::Flags]
    public enum class SegmentPosition : unsigned int
    {
    };

    public ref class AM50288H sealed
    {
    private:
        ::AM50288H _am; //Arduino向けのオリジナルクラス
    public:
        AM50288H();
        void begin(byte pinLE, byte pinDIN, byte pinSCK);
        void update();
        void clear();
    };
}
}
AM50288H.cpp
#include "AM50288H.h"

namespace Tnksoft {
namespace AM50288H {
    AM50288H::AM50288H()
    {
    }

    void AM50288H::begin(byte pinLE, byte pinDIN, byte pinSCK)
    {
        _am.setPins(pinLE, pinDIN, pinSCK);
        _am.begin();
    }

    void AM50288H::update()
    {
        _am.update();
    }

    void AM50288H::clear()
    {
        _am.clear();
    }
}
}
今回は「Tnksoft.AM50288」という名前空間でランタイムクラスを定義したので、プロジェクトプロパティの「Windowsメタデータファイル」の項目を変更するがあり、このライブラリーの場合は「$(OutDir)Tnksoft.AM50288H.winmd」となります。
ビルドに成功したら、このランタイムライブラリをDMAPドライバーで稼働するUWPアプリで参照すれば、機器の制御が簡単かつ高速に行えるようになります。
AM50288HDemo.cpp
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml;
using Tnksoft.AM50288H;

namespace AM50288HDemo
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            amh = new AM50288H();
            // GPIO5 = 29, GPIO6 = 31, GPIO13 = 33 on Raspberry Pi
            amh.begin(29, 31, 33);
        }
    }
}
2017/05/30