Orange Pi で .NET Core を動かそう

このエントリーは C# Advent Calendar 2017 – Qiita の 8日目のエントリーです。前のエントリーは atsushieno さんの libsoundio-sharpとPInvokeGeneratorについて – ものがたり です。

Orange Pi とは何か?

端的に言えば、Raspberry Pi 互換機です。ラズパイのように40本のGPIOが設定してあったり、マウスやキーボードに繋げるためのUSBコネクタがあったり、モニタに繋げるための HDMI があったりします。

Orangepi http://www.orangepi.org/

互換機であるならば、普通にRaspberry Piを買った/使ったほうがいいだろうという話もありますが(実際に初心者的には無難なラズパイ3を薦めるところですが)、まあ、2台め3台目…n台目となると値段の関係もあって、格安な互換機を買うの面白いところです。

詳しく言えば、ラズパイ3とは大きさが違ったり、メモリ量が違ったり、場合によってはラズパイ3よりも性能が良かったりするので、実際に業務として使う分には慎重な比較が必要なのでしょうが、複数のボードを使ってあれこれ試したいときにはこういう冒険もよいでしょう。

Orange Pi に OS を入れる

Orange Pi One には Allwinner H3(ARM Cortex-A7) という CPU が乗っかっています。ラズパイにも ARM が乗っているし、巷の Android スマートフォンにも ARM が乗っかっています。Intel CPU との違いは主に消費電力が低いということですね。最近では Intel CPU もほどよく低電力で動きますが(Lattepanda が 5V2.2A 程度で動いている)、Orange Pi のような ARM CPU の場合は 5V2A 以下で動いています。まあ、最近のラズパイ3となると 2.4A 程度ないとうまく起動できなかったり、機械学習で GPU をフルに使おうとすると 5V2A の範囲では電力不足で落ちてしまったりするので、どちらの CPU を使うのか?というのは単体では選択の予定が出て来るのですが。

それはさておき、ラズパイには Raspbian という Linux な OS を入れますが、Orange Pi には armbian? https://www.armbian.com/ を入れます。Orange Pi の本家から OS がダウンロードできるハズなのですが、どうもダウンロードスピードが遅いのと、root なパスワードが分からない!!! のでw armbian を使います。Raspbian は Debian ベースですが、Orange Pi には Ubuntu を入れることになります。

root/1234 で入れるので、passwd でパスワードを変更しておきましょう :) そのあとはターミナルで扱えるように

adduser ユーザー名
gpasswd -a ユーザー名 sudo

で、自分で使うユーザーを作っておいて sudo できるようにしておきます。そうすると root を使う必要がなくなりますからね。

image

Tera Term からログインできるようになると、こんな風になります。

image

実際に動作しているところは、こんな感じです。「響け!ユーフォニアム 北宇治高校吹奏楽部、波乱の第二章」の文庫本よりも小さいですね。

 

.NET Core 2.0 をインストールする

さて、やっとこさ本題です。実は Orange Pi One を選択したのは、.NET Core 2.0 を動かしたかったからなのです。実は .NET Core 2.0 の動作環境は、ARMv7 以上が必要でして、更に格安な Raspberry Pi Zero の場合は ARMv6(ARM1176JZF-S)なので、.NET Core の対象外なんですよね(https://ja.wikipedia.org/wiki/Raspberry_Pi)。勿論、Raspberry Pi Zero に普通に Raspbian を入れて gcc や Python を使ってもいいのですが。そこは「.NET Core を動かす」という手段と目的を敢えて取り違えるということで。そうそう、mono は動くはずなので、apt-get install mono-complete すれば .NET 環境は即整います。

Intel な Ubuntu の環境で .NET Core を揃えるには、Prerequisites for .NET Core on Linux | Microsoft Docs を参照に必要なライブラリをインストールしていきます。最後に dotnet-sdk-2.0.0 をインストールしてセルフビルド環境を整えます。

しかし、現時点では ARM の .NET Core は提供されていません。正確に言えば「セルフビルド環境が提供されていないが、実行環境は用意されています」という状態です。妙な状態ではありますが、

  1. PC のクロス環境で ARM 版をビルドする
  2. ARM 環境にアセンブリをコピーして実行する

の2段階を踏むと、ラズパイ3やOrange Piなどの ARM 環境でも .NET Core を動かせるようになります。この環境ですが、先ごろ発表された Windows 10 for ARM によって解消されるのではないかなと期待しています。

まず、必要なライブラリをインストールします。

sudo apt-get install libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev libcurl4-openssl-dev libssl-dev uuid-dev unzip

通常ならばこの後に、sudo apt-get install dotnet-sdk-2.0.0 するところですが、ARM 環境なので必要ありません。逆に言えば、Intel な Linux 環境でも実行環境のみ用意するのであれば、dotnet-sdk-2.0.0 自体は必要ないという訳です。

.NET Core 2.0 でビルドする

いわゆる Hello World な C# プログラムを作って .NET Core 2.0 でビルドしてみましょう。PC の環境で .

dotnet new console -n hello

を実行します。

image

ひな型となる hello プログラムができるので、ARM 用に

dotnet publish -r linux-arm

でビルドをします。-r linux-arm で実行する環境を指定して、publish で全てのアセンブリを生成させます。

image

通常は、hello.dll しかないところですが、publish にしたので、その他のアセンブリ(*.dll)やライブラリ(*.so)がひとつのフォルダーにコピーされています。

image

これを winscp などで、Orange Pi 上にコピーします。

image

実は、必要なアセンブリやライブラリは Orange Pi 側で適切なパスを通してやれば全てをコピーする必要はないのですが、色々面倒なのでごっそりコピーしてしまいます。

.NET Core 2.0 な環境で実行する

Orange Pi 側で、実行ファイル hello に実行権限を付けます。

chmod +x hello

そして実行

./hello

image

単純に hello world しかでないコンソールなものですが、これで .NET Core 2.0 な環境で動いています。

この現象で何がわかるかというと、

  • Orange Pi(あるいはRaspberry Pi)には、.NET なパッケージをインストールしていない。
  • PC でクロスコンパイラしたアセンブリを Orange Pi にコピーするだけで、Orange Pi 上で実行ができる。

ところです。まあ、実際のところは、libicu-dev やらなにやらをインストールしているので開発環境がインストールされてはいるのですが(このあたり dev 付きじゃないほうで環境を整えることはできるんでしょうか?)、比較的 Linux な環境を肥大化させないで済むという利点はありますよね。

あと、重たいコンパイル/ビルドな処理を、PC 側でのクロス開発環境で済ませることができます。この場合は、クロス開発環境を Windows の PC 上で行いましたが、Intel な Ubuntu 上とか macOS な環境でも実行は可能なはずです(ここのあたりは試していない)。

Linux & .NET Core で何をする?

基本、.NET Core でできるものは mono でもできるので、Linux や Rasbian 上で .NET Core じゃないと駄目っていう話はないのですが、

  • ASP.NET Core + .NET Core の組み合わせで Linux 上で常駐(デーモン)化させる。
  • Python + C言語ライブラリや、Node.js + ライブラリの組み合わせで動作しているものを、.NET Core + ライブラリの組み合わせに置き換えられる

というメリットがあります。このあたり Azure や AWS を使ってクラウド化してしまうほうが良いというパターンもありますが、

  • 頻繁に該当 API を呼び出す必要ある。
  • そもそも、ネットワークが細い(LoRaWANとか)

場合にはローカルのライブラリを呼び出すのが必須条件になります。そういったチープなメモリとチープなCPU(Orange Pi等を見る限り、全然チープではありませんが)な環境で何かを動かすときに有効な手段です。勿論、これ以下で動かす場合には、そもそも Linux などの OS を動かすことなく(mbed OS とかあるけど)別な方法をとりますよね。

ちなみに、ラズパイやOrange Piのような ARM CPU 上では Visual Studio Code が動きません。Intel Linux だと動くので、仮想上の Ubuntu 上では使ってみたりするのですが、いまのところは PC でクロスビルド → Raspberry Pi/Orange Pi に転送、という手段を取っています。そういう意味では、セルフ環境がラズパイ上に無くてもあまり苦になりません。

 

簡単な *.so を呼び出してみる

というわけで、Linux 上で .NET Core な環境で閉じてしまってはあまり意味がないので、自前の C API ライブラリを作ってそれを呼び出してみましょう。OpenCV を呼び出したり、機械学習っぽいライブラリを呼び出す例でもいいのですが、OpenCV だと OpenCvSharp を使うのが手っ取り早かったり、機械学習や ROS のほうは私自身がまで実験中なので手が出なかった(苦笑)というのもあるので、まあ、自前の C API ライブラリということで。

Orange Pi 上で fibo.c を作ります。まあ、コンソールなので vi で。

image

g++ でコンパイルします。

g++ -c fibo.c
g++ -shared fibo.o -o libfibo.so

fibo.c の中の fibo 関数が C# へエクスポートされる C API になります。Windows 上の DLL だとあれこれと設定しないと駄目なんですが、Linux に限ってしまえば extern “C” を付けるだけで十分です。

C# 側の hello.cs を fibo 関数を呼び出すようにします。

using System;

namespace hello
{
 class Program
 {
  static void Main(string[] args)
  {
   Console.WriteLine("Hello World!");

   for ( int n=1; n<=10; n++ ) {
    int ans = fibo( n );
    Console.WriteLine( $"{n} -> {ans}");
   }
  }
  [global::System.Runtime.InteropServices.DllImport("fibo", EntryPoint="fibo")]
  public static extern int fibo( int max );
 }
}

これを windows 上で dotnet publish -r linux-arm でクロスビルドして Orange Pi 上へ転送。

*.so ファイルは、hello と同じ場所から呼べるように ln -s しておくと便利です。

image

./hello で実行すれば、C API で作った自前のフィボナッチ関数が呼び出されていることがわかりますね。実際にあれこれやる場合は、構造体の問題とか文字コードの問題とかがあるので色々とややこしいのですが、C# と C API の連携が比較的簡単なことがわかります。つまりは、既存の C API のライブラリがあれば、いちいち C# に直す必要はなくて適当な dlimport を使って連携が可能な訳です。

 

dllimport のおまけ

C/C++ と C# の相互運用のあたりで swig を含めて改めて分かったのですが、実は dllimport は共有ファイルの名称は自動的に変換してくれるのですね。Interop with Native Libraries | Mono をみると、dllimport(“fibo”) と書いた場合は、

  • Windows 上では fibo.dll が呼び出される
  • Linux 上では libfibo.so が呼び出される
  • macOS 上では libfibo.dylib

な形で呼び変えてくれます。当然、.NET Core もこれに倣っていてファイル名を環境によって変えてくれます。

 

お次は、matarillo さんの「Null 非許容な参照型」ということで。

さらにおまけ

Xamarin なカレンダーにちょうど dllimport な話があるので、こちらも。

DllImport クロスプラットフォーム nuget パッケージ作成方法(unitypackage もあるよ!) – Qiita
https://qiita.com/TNaruto/items/ac36d87fed07e80ee8be

 

カテゴリー: 開発, C# | Orange Pi で .NET Core を動かそう はコメントを受け付けていません

SWIG の文字列(string)の扱いが少しややこしいので、Marshal.* を使ってみるテスト

内部コードを std::string/char * にするか std::wstring/wchar_t * にするかで、SWIG の挙動が変わるような感じなので、その前段階のテスト

戻り値をstring型にする SWIG の技

C#側からみればC++のDLLから文字列を取得したい場合、GetName( const char *, int ) としてバッファを渡すよりも、string GetName() な形で、string 型を返して欲しいわけです。そうなると、dllimport の部分も

 [DllImport("hellodll", EntryPoint = "GetNameStr")]
 static extern string GetNameStr();

な形にしておきたいところですよね。しかし、これはできません。戻り値は string に自動変換してくれないんですね。

不思議なことに、SWIG の場合は戻り値に string を使えて、まあこんな風に string 型を渡したり受け取ったりできます。

    var hello = new Hello();

    hello.SetName("Tomoaki Masuda");
    var name = hello.GetName();
    Console.WriteLine($"name: {name}");

当然のことながら、これは Hello クラス内でラップしている訳で、

  public string GetName() {
    string ret = helloswigPINVOKE.Hello_GetName(swigCPtr);
    return ret;
  }

となっていますが、dllimport を見ると、下記のようになっていて、string 型を返しています。

  [global::System.Runtime.InteropServices.DllImport("helloswig", EntryPoint="CSharp_Hello_GetName")]
  public static extern string Hello_GetName(global::System.Runtime.InteropServices.HandleRef jarg1);

dllimport で string 型を返しているので、どういうトリックになっているのかとコードを追ってみると、

  protected class SWIGStringHelper {

    public delegate string SWIGStringDelegate(string message);
    static SWIGStringDelegate stringDelegate = new SWIGStringDelegate(CreateString);

    [global::System.Runtime.InteropServices.DllImport("helloswig", EntryPoint="SWIGRegisterStringCallback_helloswig")]
    public static extern void SWIGRegisterStringCallback_helloswig(SWIGStringDelegate stringDelegate);

    static string CreateString(string cString) {
      return cString;
    }

    static SWIGStringHelper() {
      SWIGRegisterStringCallback_helloswig(stringDelegate);
    }
  }

文字列専用のヘルパークラスがあって、string 型を戻すときは

  1. C++ 側でここで設定されているデリゲート関数を呼び出す。
  2. C# 側であらかじめ string なデータを作る。
  3. C++ 側から、string なデータのポインタを返す。
  4. これを C# 側で string 型で受けて string として利用する。

というなかなか興味深いことをやっています。Python とか Java のコードは追っていないのですが、これは冗長ではあるけど、C#(.NETの世界)のマネージなメモリ空間でデータを扱えるようにする良い手段ですよね。

って、ことまでは分かったのですが、じゃあここの「冗長」な部分は、本来の C# ならばどうするのか?ってのが次です。

C#側でMarshal.PtrToStringAnsiを使う

サンプルコードは、

moonmile/hellodll: C++ の DLL から const char *, wchar_t * を読み込むテスト
https://github.com/moonmile/hellodll

にあります。
C++ の内部的には、std::string あるいは std::wstring を使っている状態で、C# へのインターフェースに、char * あるいは wchar_t * を使うという想定ですね。

– hellodll : C++ の共有ライブラリ
– hello : C# から hellodll を呼び出し
– helloCore: .NET Core から hellodll の呼び出し
– helloStd, helloStdCore : .NET Standard で hellodll を呼び出し、それを .NET Core で利用するパターン

C++ 側ではこんな(乱暴な)感じで、インターフェースを作っておきます。単純な文字列の受け渡しなので、_str や _wstr の中身は C# 側では弄らず、C++ 側でのみ弄るという想定です。C# で弄ったときは、あらためて SetNameStr(char *) のように文字列を渡して貰えばいいのです。

#include <string>
static std::string _str = "";
static std::wstring _wstr = L"";
extern "C" {
	__declspec(dllexport) int __stdcall Add(int x, int y) {
		return x + y;
	}

	__declspec(dllexport) void __stdcall SetNameStr(char *t) {
		_str = std::string(t);
	}
	__declspec(dllexport) char * __stdcall GetNameStr() {
		return (char*)_str.c_str();
	}
	__declspec(dllexport) void __stdcall SetNameWStr(const wchar_t *t) {
		_wstr = std::wstring(t);
	}
	__declspec(dllexport) const wchar_t * __stdcall GetNameWStr() {
		return _wstr.c_str();
	}
}

これを C# 側で受けると、こんな感じになります。C# から渡すときは string が使えるけど、C++ から貰うときは IntPtr で受けます。

 [DllImport("hellodll", EntryPoint = "SetNameStr")]
 static extern void SetNameStr(string t);
 [DllImport("hellodll", EntryPoint = "GetNameStr")]
 static extern IntPtr GetNameStr();
 [DllImport("hellodll", EntryPoint = "SetNameWStr", CharSet = CharSet.Unicode)]
 static extern void SetNameWStr(string t);
 [DllImport("hellodll", EntryPoint = "GetNameWStr", CharSet = CharSet.Unicode)]
 static extern IntPtr GetNameWStr();

IntPtr で受けた値を、Marshal.PtrToStringAnsi あるいは、Marshal.PtrToStringUni で変換します。char * と wchar_t * に対応するわけです。

  string s = "こんにちは C++ の世界";
  SetNameStr(s);
  var s1 = Marshal.PtrToStringAnsi(GetNameStr());

でもって、いちいち文字列を貰うたびに Marshal.PtrToStringAnsi を使うのは面倒なおで、次のようにヘルパークラスを作っておいて、

public class HelloDll
{
    public static void SetNameStr(string s) { _SetNameStr(s); }
    public static string GetNameStr() { return Marshal.PtrToStringAnsi(_GetNameStr()); }
    public static void SetNameWStr(string s) { _SetNameWStr(s); }
    public static string GetNameWStr() { return Marshal.PtrToStringUni(_GetNameWStr()); }


    [DllImport("hellodll", EntryPoint = "SetNameStr")]
    static extern void _SetNameStr(string t);
    [DllImport("hellodll", EntryPoint = "GetNameStr")]
    static extern IntPtr _GetNameStr();
    [DllImport("hellodll", EntryPoint = "SetNameWStr", CharSet = CharSet.Unicode)]
    static extern void _SetNameWStr(string t);
    [DllImport("hellodll", EntryPoint = "GetNameWStr", CharSet = CharSet.Unicode)]
    static extern IntPtr _GetNameWStr();
}

対応する static メソッドを呼び出せばよいのです。

string s = "こんにちは C++ の世界";
HelloDll.SetNameStr(s);
var s1 = Marshal.PtrToStringAnsi(GetNameStr());
Console.WriteLine(s1);

一見、ヘルパークラスは冗長な感じがしますが、インテリセンスが効くことと、名前空間などで区切ることができる、C++の短い名前をC#の長い名前に直すことができる、というメリットがあります。
少し高速さには掛けますが、所詮 C++/C# 変換しているところで遅くなっているので、そこは気にしないことにします。

C++と.NET Standard/Core の関係

試しに、.NET Standard を経由してみたのが、helloStd, helloStdCore のプロジェクトです。

一度、.NET Standard のクラスライブラリを作成しておいて、

public class HelloDll
{
    public static void SetNameStr(string s) { _SetNameStr(s); }
    public static string GetNameStr() { return Marshal.PtrToStringAnsi(_GetNameStr()); }
    public static void SetNameWStr(string s) { _SetNameWStr(s); }
    public static string GetNameWStr() { return Marshal.PtrToStringUni(_GetNameWStr()); }


    [DllImport("hellodll", EntryPoint = "SetNameStr")]
    static extern void _SetNameStr(string t);
    [DllImport("hellodll", EntryPoint = "GetNameStr")]
    static extern IntPtr _GetNameStr();
    [DllImport("hellodll", EntryPoint = "SetNameWStr", CharSet = CharSet.Unicode)]
    static extern void _SetNameWStr(string t);
    [DllImport("hellodll", EntryPoint = "GetNameWStr", CharSet = CharSet.Unicode)]
    static extern IntPtr _GetNameWStr();
}

.NET Core から .NET Standard のクラスライブラリを参照設定させて実行というスタイルです。

static void Main(string[] args)
{
    Console.WriteLine("Test helloCoreStd");
    string s = "こんにちは C++ の世界";

    HelloDll.SetNameStr(s);
    var s1 = HelloDll.GetNameStr();
    Console.WriteLine(s1);

    HelloDll.SetNameWStr(s + " in Unicode");
    var s2 = HelloDll.GetNameWStr();
    Console.WriteLine(s2);
    Console.WriteLine("end");
}

先の、.NET Core から C++ 直接呼出しと何が違うのかというと、いったん .NET Standard で包むことによって、.NET Core 以外の環境で動作ができるという話です。C++ のライブラリは環境ごとにビルドして配布(Windows/Ubuntu/Raspberry Piのように)する必要はありますが、.NET Standard のクラスライブラリはそのまま各種の .NET 開発環境で利用できるという訳ですね。所謂、インターフェースクラスの代わりになります。
そうなると、このクラス(アセンブリ)を利用して、Xamarin.Android/iOS で利用することも可能という話です。そうすると、自前の小さな C++ ライブラリをいちいち C# に書き替えることなく(あるいは Marshal.* や unsafe を駆使することなく)スマートフォン環境に組み込めるのではないかな、と思ったり。このあたりは、もう少し見ていかないといけませんが。

カテゴリー: 開発, C#, C++ | SWIG の文字列(string)の扱いが少しややこしいので、Marshal.* を使ってみるテスト はコメントを受け付けていません

SWIG を使って C++ のクラスを C# で読み込む方法

FFFTP2 のライブラリ化の前調査として、C++ のクラスに書き替えたときに、.NETから呼び出すことができるだろうか?というのを調べていました。基本 C# から C/C++ を呼び出すときは dllimport を使う訳ですが、これは「Cインターフェース」を使っているので、C++のクラスを直接呼び出すことはしていません。なので、C++の場合は、一度Cのインターフェースに直して呼び出さないといけないですよね。OpenCvSharp の場合も、OpenCV を呼び出すときに、dllimport を使っていますが、ひとつひとつ C インターフェスに直して組み替えています。ここの手間がなんとも言えないのと、将来的に C++ の構造が変わったときにはこの部分を手作業で直さないといけませんよね(実際 OpenCV2 から OpenCV3 の変換のときに発生している問題で)。となれば、Xamarin.Android のバインド機能よろしく、*.jar ファイルから適当な C# のクラスを吐き出すような仕組みが欲しいところです。

本式にやるならば? CppSharp っぽいのですが https://github.com/mono/CppSharp どうやら「棘の道」だそうなので、ちょっと避けて、SWIG http://swig.org/ を試しています。
以前、Python から Cライブラリを呼び出すのに SWIG を使う話をちらっと聞いた後に、それ以降調べていなかったのですが、どうやら C++ にも対応しています。

SWIGのwindows版をダウンロード

Visual Studio 2017 で作業をするので、windows 版を落とします。https://sourceforge.net/projects/swig/files/ にある swigwin のほうをダウンロードして展開すると、swig.exe と変換インターフェースがある Lib/*.i 等がでてきます。

ここでは C/C++ を C# に変換するので、Lib/charp/*.i が使われますね。

サンプル

サンプルは http://github.com/moonmile/helloswig にあります。

– helloswig : Visual Studio で作った C++ の DLL プロジェクト
– hello : DLL を利用する C# プロジェクト

hello プロジェクトは可搬性を確認するために、.NET Core プロジェクトで作ってあります。Windows 上のみで動かす場合や Linux 上で mono を使う場合は .NET Framework のプロジェクトでも可能です。Windows 上のみで動作を考えるならば、DLL は MFC DLL でも動作します。

helloswig プロジェクト

helloswig.cpp に実体を定義します。これは DLL 内で動くコードですね。

#include "stdafx.h"
#include "helloswig.h"

Hello::Hello() : _name("") {}

void Hello::SetName(const char *name ) {
	_name = std::string(name);
}

const char * Hello::GetName() {
	return _name.c_str();
}

int Hello::Add(int x, int y) { return x + y; }
int Hello::Mul(int x, int y) { return x * y; }

helloswig.h は外部インターフェースです。

#pragma once
#include <string>
class Hello
{
private:
	std::string _name;
public:
	Hello();
	void SetName(const char *name);
	const char *GetName();
	int Add(int x, int y);
	int Mul(int x, int y);
};

SWIG の場合、デフォルトでヘッダファイルの全てのクラス&全てのメソッドが公開対象になるので、この部分はエクスポート用のものを作ったほうがよいかもしれません。後、異なる環境でビルドすることを考えると windows.h などの読み込みはできないので、結構「綺麗なヘッダファイル」が必要かもしれません。

#pragma once
#include <string>
class Hello
{
private:
	std::string _name;
public:
	Hello();
	void SetName(const char *name);
	const char *GetName();
	int Add(int x, int y);
	int Mul(int x, int y);
};

helloswig.i は、SWIG で取り込むための設定ファイルです。%module の部分が DLL の名前(C#側の dllimport で指定されます)。%include が公開するための C++ インターフェスです。

/* File : helloswig.i */
%module helloswig

%{
#include "helloswig.h"
%}

/* Let's just grab the original header file here */
%include "helloswig.h"

*.i ファイルはそのままではビルドできないので、swig.exe を呼び出すようにします。
ファイルのプロパティで、「カスタムビルドツール」を指定して、

コマンドラインと出力ファイルを指定します。

swig.exe のパスは環境によって合わせてください。swig.exe のあるフォルダの Lib フォルダーから設定済みの *.i ファイルを読み込むようです。

echo Invoking SWIG...
echo on
..\swig.exe -c++ -csharp "%(FullPath)"
%40echo off

一度、ビルドを通すと helloswig_wrap.cxx のようなラップをしたクラスが作成されます。中身を見ると解るのですが、一度 C インターフェースに直してしています。

...
#ifdef __cplusplus
extern "C" {
#endif

SWIGEXPORT void * SWIGSTDCALL CSharp_new_Hello() {
  void * jresult ;
  Hello *result = 0 ;
  
  result = (Hello *)new Hello();
  jresult = (void *)result; 
  return jresult;
}


SWIGEXPORT void SWIGSTDCALL CSharp_Hello_SetName(void * jarg1, char * jarg2) {
  Hello *arg1 = (Hello *) 0 ;
  char *arg2 = (char *) 0 ;
  
  arg1 = (Hello *)jarg1; 
  arg2 = (char *)jarg2; 
  (arg1)->SetName((char const *)arg2);
}
...

これと同時に、helloswigPINVOKE.cs のような C# 側でインポートするクラスが作られます。

...
  [global::System.Runtime.InteropServices.DllImport("helloswig", EntryPoint="CSharp_new_Hello")]
  public static extern global::System.IntPtr new_Hello();

  [global::System.Runtime.InteropServices.DllImport("helloswig", EntryPoint="CSharp_Hello_SetName")]
  public static extern void Hello_SetName(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2);

  [global::System.Runtime.InteropServices.DllImport("helloswig", EntryPoint="CSharp_Hello_GetName")]
  public static extern string Hello_GetName(global::System.Runtime.InteropServices.HandleRef jarg1);
...

hello プロジェクト

C# 側は、もともと何もないクラスですが、C++ プロジェクト(helloswigプロジェクト)
で作成した *.cs ファイル(Hello.cs, helloswig.cs, helloswigPINVOKE.cs)を追加します。

Program.cs

using System;

namespace hello
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello swig world.");

            var hello = new Hello();
            hello.SetName("Tomoaki Masuda");
            var name = hello.GetName();
            Console.WriteLine($"name: {name}");

            hello.SetName("Jhon doe");
            name = hello.GetName();
            Console.WriteLine($"name: {name}");

            int x = 10;
            int y = 20;
            Console.WriteLine($"{x} + {y} = {hello.Add(x, y)}");
            Console.WriteLine($"{x} * {y} = {hello.Mul(x, y)}");

            Console.WriteLine("end");
        }
    }
}

C# 側の main コードは、通常に C# のコードになります。
SWIG で出力した C# コードをいちいち追加しないといけないのですが、まあそのあたりはバッチ処理をするとかリンクで解決するとかできるでしょう。

ビルドして実行する

.NET Core でインポートできる DLL は x64 のみなので、そのあたりを注意しながら実行ファイルを作ります。

  1. C++プロジェクト(helloswig)を x64/Debug あるいは x64/Release でビルド.
  2. C#プロジェクト(hello)をビルド。.NET Core なのでコマンドラインから dotnet build でも ok です。
  3. 作成した dll を .NET Core の実行ファイルの場所にコピー(bin/Debug/netcoreapp2.0/ にコピー)
  4. dotnet run する。

Ubuntu環境でビルド実行する

さて、Windows 環境で動作が確認できたので、Ubuntuに持って行って動かしてみましょう。コードをごっそりと Ubuntu に持って行って、共有ファイルを作成するための Makefile を作ります。

all: libhelloswig.so

libhelloswig.so: helloswig.o
	g++ -sharad helloswig.o helloswig_wrap.o -o libhelloswig.so
helloswig.o: helloswig.cpp
	g++ -c helloswig.cpp
helloswig_wrap.o: helloswig_wrap.cpp
	g++ -c helloswig_wrap.cpp

あまりに久々だったので、ベタな makefile ですが、まあこれで libhelloswig.so がビルドできます。
本来ならば、ubuntu 上で swig を動かしてラップする C# コードを吐き出すところですが、既に Windows 上で作成しているので再利用します。ちなみに、ubuntu 上では「sudo apt-get install swig」で SWIG がインストール可能です。

libhelloswig.so ファイルを指定するために LD_LIBRARY_PATH を設定して dotnet run します。

export LD_LIBRARY_PATH=~/swig/helloswig

ここで、ちょっと面白いのは .NET Core で DllImport を使うと、Windows の場合は「helloswig.dll」を参照し、Ubuntu 上では「libhelloswig.so」を参照するところですね。こんため、Windows の SWIG で出力した C# ラッパーがそのまま Ubuntu でも使えます。

  [global::System.Runtime.InteropServices.DllImport("helloswig", EntryPoint="CSharp_new_Hello")]
  public static extern global::System.IntPtr new_Hello();

共有ファイルに lib を付けておくと便利です。

Raspberry Pi上で実行する

では、ラズパイ上で動かしてみましょう。Raspberry Piでは、.NET Core がビルドできないのであらかじめ Windows 側で C# コードをビルドしておきます。

dotnet publish -r linux-arm

C++ のプロジェクトはRaspberry Pi上で make します。

これで、

– Windows
– Ubuntu
– Raspberry Pi

の3つの環境で、.NET Core + SWIG + C++ライブラリが同じソースで動作ができました。

SWIGの難点

SWIG自体は、C# へのコンバートだけでなく、JavaやPythonなどへのコンバートがサポートされているので、色々な言語で活用ができます。まあ、小さな自前の C/C++ ライブラリを Python などで使う分にはこれでいけそうな気がするのですが、Windows上の複雑なライブラリをコンバートしようとすると難しそうな点がいくつかあります。

– Windows.h などの Unix 系にないインクルードファイルは読み込めない
– LPCTSTR などの定義が読み込めない(別途定義が必要)
– 文字列系のインターフェースは const char * か wchar_t に限られる?

最後のひとつは、std_string.i や std_wstring.i のインターフェースはあるのですが、SWIGTYPE_p_std__string.cs や SWIGTYPE_p_wchar_t.cs のような独自なクラスが作られるのでちょっと違う感じなんですよね。ただし、const char * は string に変換されるので、dllimport の仕組みのままのようです。ただし、このあたりは独自に *.i ファイルを作ればよいので、ピンポイントで std::string から string に変換するとか、std::wstring からコード変換するとかはできそうな感じなのですが。このあたりは別途調査。

カテゴリー: 開発, C#, C++ | SWIG を使って C++ のクラスを C# で読み込む方法 はコメントを受け付けていません

格安ラズパイ互換機の Orange Pi One を活用する

ラズパイ互換機の一覧がイイ感じでまとまっていたので、死蔵していた Orange Pi One を引っ張り出して samba まで使えるようにしてみた経過です。

「Raspberry Pi」より強力なシングルボードコンピュータ20選–競合製品の長所と短所 – TechRepublic Japan
https://japan.techrepublic.com/article/35108435.htm

Raspberry Pi Zero W が1,000円程度で手に入るようになったので、以前より「格安」感は薄れていますが、ラズパイ3と同等レベル(あるいはそれ以上)のスペックを求めるときと、1個ではなく大量に使いたい(5個以上とか)ときには有効でしょう。1個だけ使う場合は、資料が多いラズパイを使ったほうが無難です。

100個以上使って製品化する場合には、専用の回路を組むとか、長期的な供給源の問題もありますが、まあ、あれこれと買ってみて試してみたい場合には結構よい手段です。大抵のものは、Raspbian 互換や Ubuntu が動くようになっています。また、中華製の組み込みボードは Android が動くものが多いので、別な使い方ができます。どちらにせよ、Unux 系コマンドを打つのに苦労が無ければ、それなりに使えます。

Orange Pi One とは

orange pi one – Orangepi http://www.orangepi.org/orangepione/

USBが1つしかない格安ラズパイ互換ボードです。aliexpress で直販していて、送料込みで、1,500円程度でしょうか。電源が、micro USB ではないのが難点ですが、4mm ジャックは SONY の PSP で使われているものなので 100 円ショップでも売っています。
内部メモリは 512MB しかないので、ちょうどラズパイAあたりのものと同じです。GPU などの高スペックが必要ないサーバー機に適しているでしょう。カメラをつなげる端子もないのもそれですよね。
特に、製品化や技適を気にしない実験施設であれば、orange pi zero もお薦めです。zerro のほうは WiFi/BT が内蔵しているので、無線化が可能です。ただし、少し試してみたところ WiFi が不安定(おそらく熱暴走っぽいところ)なので、大量なデータを流すものには向いていません。ですが、one も zero も非常に小さいので、ラズパイ2/3では難しい小物の電子工作に活用できそうです。

OSのダウンロード先

本家の http://www.orangepi.org/downloadresources/ から Raspbian互換がダウンロードできて、ラズパイと同様に micro SD カードに焼き込みができます。で、起動はできるんですが…実は、このパスワードが何処にも書いていない!!! pi/raspberry じゃないらしいんですよね。何度やっても駄目なので諦めて armbian を入れます。

armbian
https://www.armbian.com/download/

armbian は、有志が arm 関連の OS を公開しているところです。主に Ubuntu が使われていますが、たまに Android もあります。この中から、orange pi one を探して出して、「Ubuntu server」のほうをダウンロードします。

まあ、Desktop を入れて Scratch を使うのもいいのですが容量が少なくて済むので、今回は server 版を入れています。

起動

Armbian を起動して、ターミナルから接続するとこんな感じになります。

SSH は最初から有効になっているので、IP を調べて root/1234 でログインします。初回にパスワードを変更したあと、

adduser ユーザー名
gpasswd -a ユーザー名 sudo

として、自分のユーザーで sudo できるようにしておくと便利です。
CPU は常に50度以上になるので火傷には気を付けてください。まあ、指で触るとちょっと熱い程度なんですけど。何かフルで動かす場合には、ヒートシンクを付けたほうが良いのですが、そこまでフルに動かすことはないと思うので普段は大丈夫です。
後で試しますが、opencv をビルドするようなフルの場合には熱暴走をしたりします。そういうときは、10円玉で簡易ヒートシンクにするか(銅なので熱伝導率が高い)、扇風機に当てておけばokでしょう。

.NET Core 2.0 を動かしてみる

CPU がラズパイ2/3と同じ arm7v 系なので、.net core が動きます。

ラズパイの時と同じように PC 上で linux-arm を付けてビルドして、DLL を orange pi one 上にコピーします。
ラズパイに .NET Core 2.0 の動作環境を作るときは、

俺のラズパイ2で.NET Core 2.0が動くまで | Moonmile Solutions Blog http://www.moonmile.net/blog/archives/8732

を参考にしてください。

ファイル共有は、winscp を使ってもよいですし、samba でもよいでしょう。
1個しかないUSBにSSDを繋げて、samba をインストールすると簡易NASのできあがりです。

ひょっとするとラズパイ3よりも電力消費が低いので、電気代が安くなるかもしれません(微々たるものですが)。

この後は?

GPIOが付いているので、Wiring などを使ってLチカをするのもありなのですが、今回はちょっと Tensorflow の練習をしようと思って、opencv のダウンロードからスタート。

まっさらなUbuntu16.04LTSにOpenCV3.1とopencv_contribをインストール – Qiita https://qiita.com/schwalbe1996/items/cfa9fde7ea2b825e4e6b
Raspberry Pi 深層学習ライブラリで物体認識(Keras with TensorFlow・Open CV) – Qiita https://qiita.com/PonDad/items/c5419c164b4f2efee368

を参考にしながらインストール中です。

カテゴリー: 開発, 組み込みボード | 格安ラズパイ互換機の Orange Pi One を活用する はコメントを受け付けていません

ラズパイ2でNASを作る

以前から、業務PC内で動いていたファイルサーバーなのですが、去年あたりから別のPCから共有フォルダーが見れなくなって(業務PCから家庭用PCは見れる)、共有自体が変な状態になっていました。ここ数日あれこれと弄って悩んではいたんですが、面倒なので NAS にしてしまおうということで、ラズパイでNASを作ります。

NAS とはいえ、簡単なファイル置き場です。主に動画ファイルが置いてあるわけで、Windows PC からフォルダが見れればok。ということは、Linux + Samba で設定するだけで十分なので、仕組みは簡単です。

準備したもの

HDD は家庭用なので RAID などは組まず、ちょっと不調気味だった PC から 2TB の 3.5 インチ HDD を取り外して使いました。共有フォルダが不調だったので、業務/家庭用PCに二重化されてしまったファイルをひとつにまとめることができるので、トータルの容量が減ります。あと、ラズパイは余っていた Raspberry Pi 2 を使います。転送スピードが必要なので、有線 LAN を使うし、ファイルサーバーとして起動するだけなのでモニタやキーボードも必要ありません。

買ったのは、変換アダプタ 1,700円也のみです。後述しますが、プラモデルの空き箱で代用です。

3.5 インチの HDD は、駆動に 5Vと12V が必要となるため、アダプタ付きの変換ケーブルが必要になります。ノートブックで使われる 2.5 インチの HDD あるいは SSD は 5V のみで動くので PC の給電のみで駆動します(ブートディスクは電力が必要となるので、無理なのですが、後からマウントするだけならば給電の5Vだけで十分です)。これは Raspberry Pi の USB でも問題なく動きます。

 

Raspbian で準備する

Raspbian を micro SD に焼いて、マウントできる準備をします。ラズパイで作るファイルサーバーは、Linux で読み込めるように再フォーマットが必要だったのですが、ntfs-3g というパッケージを入れると NTFS でフォーマットしたストレージを読み込めるようになります。

以下、簡単な手順です。

  • PC で HDD を NTFS 形式でフォーマット
    • ボリューム名を「hdd1」のように変更しておく。
  • micro SD に Raspbian をインストール
    • boot ドライブに “ssh” というファイルを置く(sshが有効になる)
  • ラズパイで起動
    • passwd でパスワード変更。緩いパスワードを使いたいときは raspi-config を使ってパスワードを変更すれば ok.
    • raspi-config でホスト名を “raspberry” から “naspi” 変えておく
    • sudo apt-get update
    • sudo apt-get upgrade
    • sudo apt-get avahi-daemon (既にインストール済みかも)
    • reboot
  • HDD を変換アダプタでラズパイに繋げる
    • /media/pi/hdd1 のように自動でマウントされる。
  • sudo apt-get install samba
    • /etc/samba/smb.conf を編集する

[hdd1]
path      = /media/pi/hdd1
read only = No
guest ok  = Yes
force user= pi

  • reboot するか、sudo /etc/init.d/samba restart する。

こうすると、Windows の pc から、\\naspi.local\hdd1 でアクセスが可能になります。

ケースを作る

ほどよく動作確認ができたら、自前のケースを作ります。

image

image

作るというほどでもありません。単に空き箱に入れているだけですね。

おまけ

この映像なNASサーバーにアクセスするのに、いちいち \\nasipi.local\hdd1 なんてのを探っていては面倒なので、Windows 10 で標準についている「映画&テレビ」のアプリで、フォルダを追加します。

image

そうすると、ライブラリの「ビデオ」フォルダに追加されて、各動画ファイルをサムネール付きで参照できるようになります。

image

このライブラリのビデオフォルダは、UWP アプリから直接参照できる、Windows.Storage.KnownFolders.VideosLibrary から安全にアクセスできます…というトリックがあってですね。これは後日。

ちなみに、消費電力としては、ラズパイ+HDDのみなのでかなり低くなります。通常時で 6.0W 映像配信時に 6.9W ぐらいです。

カテゴリー: RaspberryPi | ラズパイ2でNASを作る はコメントを受け付けていません

学研ワールドアイとLattepandaの組み合わせを模索する

先日、学研ワールドアイという球体型ディスプレイ(実際は半球)を買いました。Amazon | 学研 Gakken ニューワールドアイ 地球儀を超えた無限の情報量 NEW WORLD EYE 通販 元値が、4万円近いものが、1万円ちょっとで投げ売りされています。おそらく見切り品なんだと思うのですが、よくわかりません。教材用のものらしく、学校で使うような教材がついています。

解像度は640×480 で、そのうちの480×480が球体のモニタに表示されています。ピントをうまく調節しても荒い感じになります。

image

これは、Amazon Fire TV から出力しているところです。HDMI の mini ポートが付いているので変換器を百均で買って付けました。

Lattepanda と組み合わせる

通常の HDMI が使えるので、ノートPC などからも出せる訳ですが、どうせならばワンセットで展示ができそうなパターンを考えてみました。ラズパイで出すのも良いのですが、グラフィック関係がお手軽に出せそうなところで、Lattepanda を使ってみます。

image

Lattepanda に Winodws 10 を入れて、通常の Windows PC のように使えます。手元にあるのは、メモリが2GB、内部ストレージが32GBのものですが、UWP アプリとかをインストールして動かす分に十分です。初回のインストール時に 32GB の micro SD カードが必要になりますが、一度インストールした後には外部ストレージ(つまりDドライブ)として使うことができます。

Wallpaper Engine との組み合わせ

Wallpaper Engine は Steam にある壁紙ツールです。きれいな壁紙を Windows の背景として動かすことができます。で、それをそのまま動かしたのが、↓です。

壁紙自体は球体に添っている訳ではないので、ゆがみますが、まあ結構おもしろいですよね。お手軽に動画の展示ができます。

Live 2D を動かす

Windows 上で Live 2D を動かすことができます。Live 2D Viewer 自体がちょっと重い感じですが、いったん動かしてしまえば、まあ行ける感じ

動きがぎこちない感じは Adobe Air が重たいためかもしれません。球体でもゆがまないように、顔を真ん中に配置するのがコツです。

MMD を動かす

MikuMikuDance をインストールして再生してみます。画面が狭いのでちょっと起動までが大変ですが、それなりに動きます。画像が荒くなっているのは、解像度のせいでししょう。

 

あまり、重たい感じがなくて結構スムースに動きます。

OpenSiv3D を動かす

OpenSiv3D は、グラフィックを C++ で手軽に作れる環境です。マウスを使った操作もできるのですが、球体モニタにマウスはなかなか難しいので、蝶が飛んでいるようなサンプルがあったので動かしてみたものです。

 

これは結構いい感じで動きますね。バックを黒にして走馬燈のようなものができそうです。

 

Lattepanda との組み合わせで何がいいのか?

ラズパイや Nano Pi でもいいのですが、要は球体モニタの横に大仰な PC を置かなくてよい、というメリットがあります。HDMI ケーブルの長さの問題もあるので、モニタ横には小さな組み込みボードのようがいいかなと。Wi-Fi を使うようにしてあるので、電源用の USB ケーブルと、球体モニタへの HDMI ケーブルだけが必要になります。キーボード&マウスも無線ですね。

あと、Lattepanda に Windows 10 Pro を入れておくと(付属のものは Home なのでアップグレードしてあります)リモートデスクトップで繋げることができます。リモートデスクトップで各種の設定を調節して、その後で球体モニタに表示させるという感じ。これは、ラズパイでもできます。

今度は、480×480 の球体に合わせて画像を補正して、綺麗に球面に合うように映像を表示させていきましょう…という計算をしなければ。

カテゴリー: 開発 | 学研ワールドアイとLattepandaの組み合わせを模索する はコメントを受け付けていません

今更ながら VPS を借りました

ここのブログは bluehost.com を使って運営していますが、あれこれな .NET な実験は Azure 上でやっていました。何度か仮想OSを Azure 上に組んでみたりしたのですが、Visual Studio を動かすにはパワーがたりなく(Visual Studio Codeならいいかもしれませんね)、Windows Server を置いて活用するほどでもなく、かといって Linux をインストールして LAMP で使うぐらいだったら格安のレンタルホストで良いわけで。暫く、ローカルの VMWare で Unbutu + Redmine を入れて .NET Core アクセスをあれこれやっていたのですが、やっぱり Redmine は外にあったほうがよいだろうということで、VPS です。

image

場所は、VPS(仮想専用サーバー)|さくらインターネット の 1G のプランですがね。HDD にして 100GB 使えるようにするので大抵のものは相乗りできます。月額が1,000弱なので、Azure で仮想OSを作るよりも安く済みます。逆に言えば、スペック的に拡張する予定のある場合は、AWSなりAzureなりを借りるほうがいいのでしょうが、そもそも拡張する必要がない小規模なものは VPS で十分だと思われます。(と、ここで落とし穴に後で気付くのですが、それは最後に)

Ubuntu 16.04 + Redmine 環境を作る

さくらのVPSは、初期状態で CentOS 6 が入っているのですが、このままだと .NET Core が動かない(.NET Core は CentOS 7 以降が対象)のと、普段 Linux 環境で慣れているのが Ubuntu なので、Ubuntu 16.04 をインストールし直します。カスタムで iso イメージをアップロードしてインストールもできるようですが、さっくりと作るために事前にさくらが用意してくれている os イメージで入れてしまいます。

初期ユーザー名は ubuntu 、パスワードは自分でいれたもので、teraterm でさっくりと繋がります。

Redmine のインストールは以下を参考に、

おそらく、LAMP 環境を整えてから Redmine を入れる手順のほうが楽だと思います。最終的には wordpress が相乗りになるだろうし。実際、自分も wordpress を入れたので。

なんだかんだと、半日位かかりましたが、redmine と wordpress の動作確認まで ok.

http://openccpm.com/ でアクセスできます。

.net core 2.0 の環境をインストール .NET and C# | Get Started in 10 Minutes します。

image

OS は Ubuntu 16.04 なので、手順に従えばすんなりインストールできます。2.0 から VB でも作れるようになりましたが、まあ、目的は F# です。web pi でバックグラウンドにある redmine を叩くために、ASP.NET Core Web App MVC で作れば ok ですね。

Azure の Mobile App のようなものを作らねば

でもって、これで今まで手元で実験していた ASP.NET な F# が動くね、とは思ったのですが、良く考えたら手元のは「Mobile App」で作っていたんですよね。Azure の場合、適当なタイミングで起動くれる(?)けど、自前の VPS の場合はきちんとクライアントからの要求を待ってないんといけません。まあ、単純にデーモンにすればいいだけなんですが、そうなるとあれこれ立ち上げているうちに変なゾンビ状態になりはしないかと…

image

どちらにせよ、いきなり本番環境(っぽい)VPS 上で動かすのは問題があるので、ローカル Ubuntu(VMWare上ですが)でテストしておいて VPS のほうは持って行くわけです。そうなると、

  • スタンドアローン動く .NET Core な ASP.NET Core を一式持って行って実行
  • Docker パッケージを作って転送

な感じがベターでしょう、という思いに至った訳です。Docker って主に開発環境構築に使っていたけど、VPS と組み合わせるとちっこいサービスをぽちぽちと切り替えるマネージャ的役割を担わせるのもいいんだなと。

カテゴリー: 開発, OpenCCPM | 今更ながら VPS を借りました はコメントを受け付けていません

Xamarinプログラミング入門 C#によるiOS、Androidアプリケーション開発の基本ができました

Xamarinプログラミング入門 C#によるiOS、Androidアプリケーション開発の基本
https://www.amazon.co.jp/dp/4822253503

正月頃からちまちまと書いていた Xamarin 本がやっとこさ出版に至りました。

image

3月末に Visual Studio 2017 がリリースされ、Xamarin.Forms の Master-Detail のテンプレートが変わってしまったものだから、サンプルの作りを全面的に改訂。この際なので、あれこれと手直して秋口まで延ばして貰いました。本来は de:code 2017 に間に合わせたかったんですけどね。さすがに無理でした(苦笑)。

内容とコンセプト

詳細な目次は、日経BP書店|商品詳細 - Xamarinプログラミング入門 を見てもらうとして、執筆時のコンセプトは、

  • Xamarin.Android/iOS/Forms の動作原理を知り、シミュレータを含めた動作環境を構築する。
  • スマートフォン(iOS/Android)の開発が主となるので、Xamarin.iOSとXamarin.Androidもターゲットに入れる。
  • 前回、タイミング的に入れることができなかった Xamarin.Forms を「共通化のベース」として入れる。
  • と同時に、ロジックを共通化&外出しすることで TDD の手法が使える。

なところです。

なので、C#の文法の説明は一切しない(「独習C#」などで学習済みであることが前提です)、Windows Phone は本書のターゲットでありません(販売台数的にこれは仕方がないです)。

ただ、巻末に私の趣味的に、UWPアプリの作り方と Android Things の使い方の解説があります。このあたりも見てもらうと、目指すところとしての Xamarin/mono/.NET Core/.NET Standard がなんとなく想像できると思います。

前回は、Xamarin 自体が紹介も含めていたので(当時有料であったし)、サンプルプログラムとしてパズルゲームにしましたが意外と不評なので(苦笑)、今回は Master-Detail 型の ToDo アプリにしてあります。ToDo アプリ自体は、Xamarin.Forms のサンプルにあるのですが、本書のサンプルは、ToDo の新規追加と更新、そして Azure を使うところを2段階で解説しています。

分厚い Xamarin.Forms 本 よりももっと手に入れやすく(値段的に)という企画であったのと、この本も含めていくつかの Xamarin 本の企画を想定していたので、それらとは違う仕組みにしてあります。なので、お財布には優しくありませんが!両方買っても大丈夫ですよ。

ちなみに、ちょっと古めですが参考資料として Xamarin Mobile Application Development for iOS などの洋書を使っています。Xamarin.iOS/Android については、基本的なところは変わらないのと、どうせコードで把握することが多いので洋書にあたってしまったほうが情報の入りは早いです。

サンプルコード

日経BP社のサイト 日経BP書店|商品詳細 - Xamarinプログラミング入門 からサンプルコードがダウンロードができます。

でもって、ベゾルド本に倣い(と、最近のMicrosoft関係のOSS化に倣い)、github https://github.com/moonmile/xamarin-samples でもサンプルコードを公開しています。更新の早い Xamarin.Forms に完全に追随できないかもしれませんが、ちまちまと更新はしていこうかと思っています。

カテゴリー: Xamarin | Xamarinプログラミング入門 C#によるiOS、Androidアプリケーション開発の基本ができました はコメントを受け付けていません

中学校のあふれそうな中間試験勉強のためにタイムマネジメントを活用する

娘が中学校に入ったので、学校では中間試験、期末試験が行われるようになりました。その各試験の前のに「試験前の対策」と称していろいろなプリントやら提出物が課せられるわけですが、この分量が並ではない!そもそも、試験対策のための勉強ができないほど課題提出を持てめてしまうのはどういうことなの?

ということを Twitter で愚痴ろうと思ったわけですが、ちょっと対策を含めてブログにしておきます。この課題の多さ、1学期の中間、期末、夏休み、そして2学期の中間、となり4度目なので、おおまかな対策は立てることができました、というお裾分けでもあります。いわゆる「マネジメント」の分野なんですけどね。

そもそも課題が多い

課題が多い理由としては「試験前に勉強しない子でも、強制的に勉強するように」という方針らしいのですが、そもそもが、課題の多さ自体に疲労してしまうのではないか?という疑問があります。また、各教師が全体の課題のトータルを把握しているのか、という問題があります。

image

「課題が多い」ことに対して、保護者の立場であれこれ言うことはできないので(学校の方針でもあるし)、じゃあ、この多くの課題をどうやってこなすのか?と同時に、どうやって試験勉強をするのか?を考えていきましょう。

スケジュール表を作る…だけではだめ

学校からは、こんな感じのスケジュール表が配られて、予定と実績を書き込む、そして教師がチェックするというプリントが配られますが、これではだめです。できる子はいいんでしょうが、先のように多くの課題を抱えてしまってあふれてしまっている子は途方に暮れてしまいます。

image

この手の話は、IT業界のプロジェクトでもよくある話で、「課題や実装すべき機能が多すぎて、どこから手をつけたらよいかわからない」というものです。しかも、期限が決まっているパターンですね。仕事の場合は、そもそもの課題の量を調節する手段をとれるのですが、学校に提出する課題/プリントの量は、交渉の余地はありません。やるか、やらないかというパターンですね。溢れてしまっている場合は、半分だけやるという方法もありますが、ここでは「ひと通りやる」ことを目標に考えていきます。

全体の課題の数を書き出す

最初に、課題の数をかき出します。一応、渡された一覧で「数」はわかるはずなのですが、実感が伴わないので付箋に書き出します。付箋にすると、枚数で勘定ができるようになるので、何枚あるのかとうボリューム感が捉えられます。

image

すべての課題を付箋に書き出したら、

  • 簡単なタスク
  • 重たいタスク
  • ほどほどのタスク

の3つに分けます。簡単なタスクは、教科書をひと通り読むとか、1枚だけのプリントみたいなものです。重たいタスクは、2,3時間掛かりそうなものです。細かく分けても仕方がないので、大中小の3つに分類します。

その中から重たいタスクに注力します。

image

いわゆる「パレートの法則」で、上位20%をめやすに取り出します。そうすると、重たいタスクの数が判明し、計画が立てやすくなります。

重たいタスクには

  • 大まかな学習時間の予想を記述
  • いつ課題をこなすのかを日付で記入

します。このベースとなる、重たいタスクを中心に据えて、まわりの軽いタ50を空き時間なり、適当な制限時間(30分や50分単位)にまとめて課題をこなしていきます。

タイムマネジメントの活用

この手法は、いわゆる時間製薬のある「タイムマネジメント」と制限時間で遅延を計測する「タイムボックスを利用したマネジメント」の合わせ技です。仕事でも使えますよね…というか、そもそも仕事用です。

この手のマネジメント手法は、学校での学習でも使えるので大いに使うことが肝心です。うちの子も、小5,6の夏休みからあれこれやって、中1のこの時期にやって自分で付箋を掛けるようになりました(まあ、方法は毎度教えないとダメなんですけど)。中2になったら自分でできるようになるだろうか?

カテゴリー: 雑談 | 中学校のあふれそうな中間試験勉強のためにタイムマネジメントを活用する はコメントを受け付けていません

Android内のユーザーデータを探る

Android でアプリケーションが入っている場所は /data/data になるのだが、実機だとルート化する必要もありいくつか面倒なので、Nano Pi K2 に Android を入れて、その micro SD カードを使うことにする。

このカードを既存の Linux マシンに USB メモリとして認識させる。手元に Raspberry Pi があるので、認識させたのがこれ。ラズパイの場合は /media/pi にマウントされるようで、ここの /media/pi/userdata/data がそれにあたる。

image

例えば、マギレコの場合は com.aniplex.magireco 内を調べる。これらのフォルダーは root になっているので、su でルートになるか、sudo で調べるとよい。

後からダウンロードする場合は、別のフォルダーなのだろうが、マギレコの live2D は、com.aniplex.magireco/files/madomagi/resource/image_native/live2d にあるので、適宜コピーして PC 上で動かすことができる。

image

保存データは、userdata/media/0/Android/data にあるような気がする。歌マクロスの com.dena.a12024374 内に3Dデータが入っていると思うのだが、ちょっと分からない。

image

ふと見ると、etc の下に il2cpp が入っているので、中身は C# で書いているのかもしれない。

image

jp.showgate.girlsundpanzer はガルパンで、中身は Unity のデータが入っているとか。

ひとまず、メモ書き程度に。

カテゴリー: Android | Android内のユーザーデータを探る はコメントを受け付けていません