2016年3月9日水曜日

[RaspberryPi]日本語が文字化けした時の対処方法+Chromiumのインストール


1.Raspi-configの設定
 「Innternnatiolisation Options」
   ↓
 Change Locale
   ↓
 ja_JP.UTF-8をチェックしてデフォルト言語に選択


2.日本語化アプリのインストール
$ sudo apt-get install -y ttf-kochi-gothic xfonts-intl-japanese xfonts-intl-japanese-big xfonts-kaname uim uim-anthy jfbterm


3.Chromiumをインストール
$ wget http://launchpadlibrarian.net/199573270/chromium-browser_41.0.2272.76-0ubuntu0.14.04.1.1076_armhf.deb
$ wget http://launchpadlibrarian.net/199573282/chromium-codecs-ffmpeg-extra_41.0.2272.76-0ubuntu0.14.04.1.1076_armhf.deb
$ wget http://launchpadlibrarian.net/199573279/chromium-codecs-ffmpeg_41.0.2272.76-0ubuntu0.14.04.1.1076_armhf.deb
$ wget http://launchpadlibrarian.net/199549151/chromium-browser-l10n_41.0.2272.76-0ubuntu0.14.04.1.1076_all.deb

$ sudo dpkg -i chromium-browser_41.0.2272.76-0ubuntu0.14.04.1.1076_armhf.deb chromium-codecs-ffmpeg_41.0.2272.76-0ubuntu0.14.04.1.1076_armhf.deb chromium-codecs-ffmpeg-extra_41.0.2272.76-0ubuntu0.14.04.1.1076_armhf.deb chromium-browser-l10n_41.0.2272.76-0ubuntu0.14.04.1.1076_all.deb




参照URL
http://start-now.link/100/archives/1930

2016年3月8日火曜日

[RaspberryPi]VPNServerを立てる

VPNサーバーとは
 外部から安全に特定のネットワークへアクセスするサービスを提供するサーバーの事です。

どういう時に導入するの?
 外から自宅のネットワークにアクセスしたい時などは直接複数のポートを開けば良いのだが
セキュリティーホールは開いたポート先のサービス毎に存在することになるので管理が大変だが
VPNサーバーを立てると、外から見えるのはVPNサーバーのポート1つだけになるので
セキュリティーホールはVPNサーバー1つだけとなり、管理がしやすく安全になります。


導入手順
 1.SoftEtherをダウンロードする。


 にアクセスして、

  SoftEhter VPN(Freeware)
   ↓
  SoftEhter VPN Server
   ↓
  Linux
   ↓
  ARM EABI(32bit)

  を選び、最新イメージのダウンロードURLをコピーする。

  $ wget http://jp.softether-download.com/files/softether/v4.19-9605-beta-2016.03.06-tree/Linux/SoftEther_VPN_Server/32bit_-_ARM_EABI/softether-vpnserver-v4.19-9605-beta-2016.03.06-linux-arm_eabi-32bit.tar.gz
    $ tar zxf softether-vpnserver-v4.19-9605-beta-2016.03.06-linux-arm_eabi-32bit.tar.gz
    $ cd vpnserver


 2.コンパイルする。
    $ sudo make

    ~ライセンスについて聞かれるので承諾する。~


 2.起動時に実行するように設定する。
  まずはvpnserverをシステム側に移動させる
    $ cd ..
    $ sudo mv vpnserver /usr/local/
    $ cd /usr/local/vpnserver
    $ sudo chmod 600 *
    $ sudo chmod 700 vpncmd
    $ sudo chmod 700 vpmserver

  次に起動に必要なファイルを作成
    $ sudo vim /etc/init.d/vpnserver
#!/bin/sh
### BEGIN INIT INFO
# Provides:                     vpnserver
# Required-Start:               $local_fs $network
# Required-Stop:                $local_fs $network
# Default-Start:                2 3 4 5
# Default-Stop:                 0 1 6
# Short-Description:            SoftEther VPN 1.0 RC2
# Description:                  Start vpnserver daemon SoftEther VPN 1.0 Server
### END INIT INFO

DAEMON=/usr/local/vpnserver/vpnserver
LOCK=/var/lock/vpnserver

. /lib/lsb/init-functions

test -x $DAEMON || exit 0

case "$1" in
start)
sleep 3
log_daemon_msg "Starting SoftEther VPN 1.0 Server" "vpnserver"
$DAEMON start >/dev/null 2>&1
touch $LOCK
log_end_msg 0
sleep 3

;;

stop)
log_daemon_msg "Stopping SoftEther VPN 1.0 Server" "vpnserver"
$DAEMON stop >/dev/null 2>&1
rm $LOCK
log_end_msg 0
sleep 2

;;

restart)
$DAEMON stop
sleep 2

$DAEMON start
sleep 5

;;

status)
    if [ -e $LOCK ]
    then
        echo "vpnserver is running."
    else
        echo "vpnserver is not running."
    fi
;;
*)

echo "Usage: $0 {start|stop|restart|status}"
exit 1
esac
exit 0


    $ sudo vim /etc/systemd/system/vpnserver.service
[Unit]
Description=SoftEther VPN Server
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/vpnserver/vpnserver start
ExecStop=/usr/local/vpnserver/vpnserver stop

[Install]
WantedBy=multi-user.target

    $ sudo chmod +x /etc/init.d/vpnserver
  $ sudo systemctl start vpnserver
  $ sudo systemctl enable vpnserver


 3.ブリッジする
  $ sudo apt-get install bridge-utils
    $ sudo vim /etc/network/interfaces
# loopback
auto lo
iface lo inet loopback

# Ethernet port
auto eth0
iface eth0 inet manual

# Bridge interface
auto br0
iface br0 inet dhcp
bridge_ports eth0

#その他
allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp


 4.再起動して自動起動しているか確認する。
    $ sudo reboot
    $ sudo service vpnserver status


 5.外からアクセスできるようルータ側の設定を行う
   SoftEhterは
          TCPの449と2222
          UDPの500と4500
   を使うのでポートを開けておく。


参考URL


2016年3月4日金曜日

[RaspberryPi]Asteriskを使う(3)Systemdで起動設定編

Jessieだとinitではなくsystemdになっていてインストール時にサービス登録されているのかな?って調べてみると登録されていなかった。。

ということで起動時にasteriskが立ち上がるように設定する事にした。


参考にしたサイトはここ。

http://www.voip-info.jp/index.php/BeagleBone_Black_Asterisk


$ cd /etc/systemd/system
$ sudo vim asterisk.service
---
[Unit]
Description=Asterisk Open Source PBX
After=network.target

[Service]
Type=forking
ExecStart=/usr/sbin/asterisk -U asterisk -G asterisk

[Install]
WantedBy=multi-user.target
---


$ sudo ln -s /usr/lib/systemd/
$ sudo ln -s /usr/lib/systemd/
$ sudo ln -s /lib/systemd/system/asterisk.service /etc/systemd/system/multi-user.target.wants/asterisk.service
$ sudo systemctl enable asterisk
$ sudo systemctl start asterisk


再起動して以下のコマンドで動作しているか確認。
ps -ef|grep asterisk
systemctl|grep asterisk

[RaspberryPi]Asteriskを使う(2)G729インストール編


音声コーデックG729をインストールする。


参考にしたサイトは以下のところです。
https://smallhacks.wordpress.com/2014/01/13/using-asterisk-g-729-with-asterisk-on-raspberry-pi-or-other-arm-device/
http://www.adeleda.com/compiling-g729-codecs-for-arm-on-raspberry-pi-b-with-bcg729-en.html
https://disqus.com/home/discussion/adeleda/compiling_g729_codecs_for_arm_on_raspberry_pi_b_with_bcg729/


それらをまとめて一発でインストールできるようにした手順は以下の通り。


sudo wget http://download-mirror.savannah.gnu.org/releases/linphone/plugins/sources/bcg729-1.0.1.tar.gz
sudo ./configure --libdir=/lib
sudo make
sudo make install

sudo wget http://asterisk.hosting.lv/src/asterisk-g72x-1.3.tar.bz2
sudo bzip2 -dc asterisk-g72x-1.3.tar.bz2 | sudo tar xvf -
sudo apt-get install autoconf automake libtool autoconf-doc libtool-doc
cd asterisk-g72x-1.3
sudo ./autogen.sh
sudo ./configure --with-bcg729 --with-asterisk-includes=/usr/include --with-asterisk130
sudo make
sudo make install




最後は動作確認
asterisk -vvvvr
# core restart gracefully

これでG729の項目が表示されていればOK。

[Raspberrypi]Asteriskを使う(1)インストール編

asteriskを使う

簡単にインストールする場合は

 apt-get install asterisk -y


でインストールできるんだけど光電話パッチを入れたりしたかったので
2016.03.03時点の最新ソースからビルドを行ってみた。

http://www.voip-info.jp/index.php/Asterisk_13

上記リンクを参考に進めようと思うが、
記事の内容はredhat向けに書かれているで、本記事でdebian向けに書きなおした
インストール手順を書いていく。

(光電話パッチは2014年時点のものでも問題なくパッチ当てができました)


sudo apt-get install -y subversion libncurses5-dev uuid-dev libjansson-dev libxml2-dev libsqlite3-dev libbluetooth-dev
sudo apt-get install -y libsqlite3-dev libncurses5-dev bison libssl-dev libnewt-dev zlib1g-dev procps gcc make binutils doxygen g++ libxml2-dev

sudo groupadd -g 5060 asterisk
sudo useradd -g 5060 -u 5060 -d /var/lib/asterisk -s /sbin/nologin asterisk
cd /usr/local/src/
sudo wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-13-current.tar.gz
sudo tar zxf asterisk-13.7.2.tar.gz
cd asterisk-13.7.2/
sudo wget http://ftp.voip-info.jp/asterisk/patch/local/13/chan_sip_hikarihgw.141202-01.patch
sudo patch -p0 < chan_sip_hikarihgw.141202-01.patch
sudo ./contrib/scripts/get_mp3_source.sh
sudo ./contrib/scripts/get_swagger_ui.sh
sudo ./configure

日本語音声ファイルをインストールする
sudo make menuselect


sudo make
sudo make install
sudo make sample
sudo make config


自動起動になっているか確認
sudo chkconfig asterisk --list


この後はG.729コーデックのインストールとか初期設定編へと続く。


2016年3月2日水曜日

[RaspberryPi]有機液晶OLED SSD1331を使ってみる



RaspberryPiで何かいい液晶がないか探してみたら
SPI通信で表示できる有機液晶SSD1331というものを見つけた。
値段は送料込みで11$くらいなので1300円くらい。



製品仕様
サイズ:0.96インチ
解像度:96*64
発色:65k
ドライバIC:ssd1331

ピン配置GND: Power ground
VCC:2.8-5.5V power supply
D0: CLK clock
D1: MOSI data
RST: Reset
DC: data / command
CS: chip-select signal


誰かサンプルプログラムを書いていないか検索してみたら、やはりいました。
https://www.raspberrypi.org/forums/viewtopic.php?t=126811&p=871760

ここから行き着いた先はGithub



【配線図】

RaspberryPiのピンの始まりを間違えないように確認して、



液晶とこんな感じに接続する。
完全なSPI通信出ない気がするけど、今回は動作確認なので同じ配線にする。


GithubにあるPythonのソースコードをダウンロードして

$ python clock.py

実行してみると、、、




動いたー!





初期不良じゃなくてよかった。
しかも結構明るくて良い。
あとなぜか電源ラインVCCを外してもそれなりに画面写ってました(笑)

2016年2月29日月曜日

ラズベリーパイ4周年記念にRaspberry Pi3 Model B debut!

ラズベリーパイが4周年記念ということでRaspberryZero出て半年も立たずに次も出るのRaspberryPi3が出てきた。
今回の目玉は、、、

・Wifi 2.4GHz搭載
 →今まで占有してたUSBポートが1つ空きます。

・Bluetooth4.1搭載
 →Bluetooth対応キーボードやマウスがそのまま流用できそう

・CPUがCortex-A7からCortex-A53へアップグレード
 単純に言えば64Bit対応になった事が一番大きい。
 どの程度の性能かというと初期のAtomより少し高く肩を並べるくらい。

 変化点を見ていくと、、、
 →Cortex-A53とは、2012年にbig.LITTLEコアで省エネと高パフォーマンスを両立しようと
   打ち出された省エネ側のCPUコアである。
 →SIMD命令のNEONに対応などがされている。
 →64Bit命令セットを対応することで、64Bitバイナリを実行するときは、
  32Bit命令セットの負債を捨ててよりシンプルな構成になるので若干の速度アップがあるかも。
 →アーキテクチャ側の変更でインオーダー処理している部分が今までは同時2発行が
   限定的だったが、限定的でなくなるので処理性能がアップする。(若干)

・消費電力がアップ
 →推奨が5V2.5Aなので、タブレット以上の電源が必要になりそう。


性能も上がって無線機能も標準搭載して値段は据え置き。
また5000円代で買えるのが嬉しい。

販売はRSコンポーネントかPimoroniで行うのでZEROが入手出来ないけど
手元にあるRPiのバージョンアップという名目で1つどうでしょうか。


個人的には
RaspberryPi3 もしくは
RaspberryPi Zero + ESP6288(Wifi+GPIO) or ESP32(Wifi+BTLE) という
メインCPUにRPI 、UI側を担当 
サブCPUにESP5288で通信処理もお任せするような構成もいいかなと思う。

2016年2月26日金曜日

[Windows10]VAIO内臓のBluetoothが使えない

・BluetoothドライバがWindows10に対応していない。
 VAIOで使われているBluetoothのICは「qualcomm atheros AR3012」というもので
調べてみるとWindows8.1までしか対応していないようです。


・対応していなくても使いたい。
 ネットで調べてみると、BluetoothアダプタとBluetooth Suiteという2種類のものがあるようです。

最悪Bluetoothアダプタの方を対応しておけば最低限のBluetoothプロトコルは使えるようになります。
A2DPなどのプロトコルに対応するにはBluetooth Suiteが対応していなければならないようです。

調べてみると、ここで非公式で配布しているようです。

 http://alldrivers.ucoz.net/news/qualcomm_atheros_ar301x_ar9462_qca9565_bluetooth_suite_version_10_0_1_4/2015-11-01-786

※非対応のドライバを使うので十分確認してから、自己責任でお願いします。


まずは、「プログラムのアンインストールまたは変更」で既にインストール済みのQualComm Atheros Bluetooth Suiteを削除します。

次にダウンロードしてきたSuiteをインストールします。

これでおしまい。


これで一応ですが、使えるようになりました。


2016年2月15日月曜日

ロボットアームのXYZ座標の計算式


去年からやっているロボットアームの位置制御でX,Y,Z座標からモーターの角度を計算する式で一番シンプルなものができたのでメモ。



条件:水平方向に動くモータが1つ、垂直方向に動くモーターが2個あるロボットアームのとき

それぞれの部位の名称を

 ・付け根を肩(垂直軸Base、水平軸Shoulder)、
 ・中間を肘(Elbow)、
 ・先端を手首(Wrist)

かつ腕の長さが等分であると定義する。


上記条件において、手首WristのX、Y、Z座標を与えた時それぞれの角度を求める式。(決定版)

///
/// ShoulderとElbowの長さが一緒なら二等辺三角形で計算式を解く
///
///
///
///
public void Calc(double x, double y, double z)
{
var h = Math.Sqrt(x * x + y * y);
var k = Math.Sqrt(h * h + z * z);
var pa = Math.Atan(z / h);
var pb = Math.Acos(k / 2.0);

X = x;
Y = y;
Z = z;
ThetaBase = Math.Atan(y / x);
ThetaShoulder = pa + pb;
ThetaElbow = -2.0 * pb;
}

腕の関節の長さが一緒なら二等辺三角形になる。
そうすることで何が嬉しいかというと、2等辺三角形の公式が使えるので
辺の長さを無視する事が出来る。
つまり、XYZ座標から斜辺kを求めれば全ての角度が計算できる事を意味している。


ロボットをこれからやろうと思った人はぜひ、参考にしてください。

2016年2月11日木曜日

Android Stdioでアプリ開発(1)

AndroidStudioで本格的にアプリを作ろうと思い、
備忘録としてメモを残しておく。

今回、第1回は開発環境の使い方から画面の作り方までをまとめておく。


【ダウンロード&インストール】
 ここではダウンロードURLだけ紹介。

 ・AndroidStdio本体のダウンロードURL
  http://developer.android.com/intl/ja/sdk/index.html

 
 インストールして新規プロジェクトを作ったらまずやることは、
 左メニューにあるソリューションのコンボックスを「Project Files」にする。



【覚えておくべきフォルダー構成】

app
 java
  com.example.name.myapplication
    ココにソースファイル
  res
    drawable
      画像ファイルを置く
    layout
      画面レイアウトファイル


この3か所。
・ソースファイルと画面レイアウトは別フォルダになっている。
・画像データはdrawableフォルダに格納する。

この2点を覚えておく。


【覚えておくと楽なショートカット】
・CTRL+F9 ・・・ビルド
・SHIFT+F10 ・・・実行
・ALT+ENTER ・・・足りないimportやコンストラクタ処理を作成
・CTRL+O ・・・Overloadメソッドを作成

これだけ覚えておけばある程度エディタを使いこなせると思う。



【画面の作り方】
 スマホアプリは画面が小さいこともあってデスクトップアプリのように自由なレイアウトを行う事ができない。
 ページごとにテーマを決めて、画面遷移を作って、
 画面だけのモックアップアプリを作ることがスマホアプリの開発の流れになる。
 これが世間でいうUI/UXといわれる部分である。
 良いアプリでも似たアプリが沢山あるから、
 使いにくいアプリはユーザーに捨てられるという事なんでしょうね。

レイアウトにある要素は以下の7つ。
・Layouts
・Widgets
・Text Fields
・Containers
・Date&Time
・Expert
・Custom

レイアウトは、横一列、縦一列を広く設置するのに使う。
また、レイアウトの中に部品を設置できたり、
Viewクラス経由でオリジナルの画面を作ったりすることができる。
なのでレイアウトはとても重要なので覚えておくべき。


ざっくりとした画面の作り方。
1.レイアウトを設置する。
  プロパティ画面で使う項目は、
   layout:width
   layout:height
   gravity
   id

2.画面割りが決まったら「id」を付けていく。
  idを付けないとプログラムから操作できない。


【Viewクラスの作り方】
1.ソースコードを新規作成したら、

 import android.view.View;

を追加する。

2.クラスにViewを継承すること。

 public class exampleView extends View {
     ...
 }

3.コンストラクタはクラス名にカーソルを置いて、ALT+Kボタンを押すとコンストラクタを自動生成できる。


4.OnDrawなどを作りたいときはCTRL+Oボタンを押す。


【レイアウトに反映する方法】
 MainActivityクラスを開いて、コンストラクタ内にコードを書く。
手順は、作ったViewクラスを生成したらレイアウトに登録する。

 exampleView view = exampleView(this);
  LinearLayout layout = (LinearLayout)findViewById(R.id.exampleLayout);
  layout.addView(view);


コードはこんな感じ。
Viewを生成して張り付けるレイアウトを取ってきて、ビューを登録する。
やりたい事3つで3行。
これはおまじないみたいに覚えておこう。


余談。
「R」←これはリソースのRと思ってOK。
画面レイアウトのIDや画像ファイルなどを参照する場合に使うので
リソース使いたいなあーって思ったら「R」


第2回へ続く。

2016年1月24日日曜日

Rx亜種を作ってみた(2)


前回のRx亜種を実装してみたからの続き。

前回はデザインパターンである、オブザーバーパターンとステートパターンを組み合わせて実装してみた。

今回はその発展形でIEnumerable型のyieldを活用してスケジューラ機能を備えた構造に仕上げてみた。
そのついでにIObserver、IObservableインターフェースは使わずOnNextでIEnumerable型を返すよう改造したIReactiveインターフェースを使うようにした。

まだ改良の余地はあるけど、方針は
 Stateパターン+Iteratorパターン
 Observerパターン+Iteratorパターン
これを合成したReactiveなもにに仕上げる。
できたらOnNextする前にLINQを挟んで処理できるようになればいいかなって考えているけど、yield returnした後の結果をどうやって受け取ればいいんだ~?
(そもそも内向きの処理でLINQを使おうとしてるのが間違いなんだろうけど。)



using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    /// <summary>
    /// スケジューラー
    /// 123123123 13 1 なし ...終了したタスクはリストから外れる
    /// var s = new Schedular();
    /// s.EnQueue(OnNext(value))
    /// </summary>
    public class Schedular
    {
        object _lock { get; } = new object();
        Queue<IEnumerator> queue { get; } = new Queue<IEnumerator>();
        public Task Dispach()
        {
            return Task.Run
                (() =>
                {
                    IEnumerator que;
                    while (true)
                    {
                        while (0 < queue.Count)
                        {
                            lock(_lock)
                            {                                
                                que = queue.Dequeue();
                            }
                            if (que.MoveNext())
                            {
                                lock (_lock)
                                {
                                    queue.Enqueue(que);
                                }
                            }
                            Thread.Sleep(0);
                        }
                        Thread.Sleep(1);
                    }
                });
        }

        public void Attach(IEnumerator value)
        {
            lock(_lock)
            {
                queue.Contains(value);
            }
        }
    }

    /// <summary>
    /// Push型インターフェース
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IReactive<T> : IDisposable
    {
        LinkedList<T> Follows { get; }
        LinkedList<T> Followers { get; }
        IEnumerable<Func<T, bool>> OnNext(T value);
        void OnError(Exception error);
        void OnCompleted();
        void Subscribe(IReactive<T> observer);
    }

    /// <summary>
    /// フォロー・フォロワーのリンクリスト
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class LinkedList<T> : IEnumerable<IReactive<T>>
    {
        List<IReactive<T>> users { get; } = new List<IReactive<T>>();
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
        public IEnumerator<IReactive<T>> GetEnumerator() => users.GetEnumerator();
        public void Add(IReactive<T> value) => users.Add(value);
        public void AddRange(LinkedList<T> list) => users.AddRange(list.users);
        public void Remove(IReactive<T> value) => users.Remove(value);
        public void Clear() => users.Clear();

        //並行に処理していく 123123123
        public IEnumerable<Func<T, bool>> OnParallel(T parameter)
        {
            var queue = new Queue<IEnumerator<Func<T, bool>>>();
            foreach (var follower in users)
                queue.Enqueue(follower.OnNext(parameter).GetEnumerator());

            while (0 < queue.Count)
            {
                var que = queue.Dequeue();
                if (que.MoveNext())
                {
                    queue.Enqueue(que);
                    yield return que.Current;
                }
            }
        }

        //木構造を順番に処理していく 111222333
        public IEnumerable<Func<T, bool>> OnSerial(T parameter)
        {
            foreach (var follower in users)
                foreach (var que in follower.OnNext(parameter))
                    yield return que;
        }

    }

    /// <summary>
    /// 関数内の関数をデリゲート化してステートマシンに見立てて実行(ステートパターン)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class StateMachine<T>
    {
        public Func<T, bool> Current => methods[SeqNo];
        Func<T, bool>[] methods { get; }
        int SeqNo { get; set; } = 0;
        int JumpSeqNo { get; set; } = -1;

        /// <summary>
        /// コンストラクタ処理
        /// </summary>
        public StateMachine()
        {
            methods = GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.InvokeMethod)
            .Where(_ => _.ReturnType == typeof(bool) && 1 == _.GetParameters().Length)
            .Where(_ => (_.GetParameters()[0].ParameterType == typeof(T)))
            .Select(_ => (Func<T, bool>)_.CreateDelegate(typeof(Func<T, bool>), this))
            .ToArray();
        }

        /// <summary>
        /// 次の処理関数を指定する
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        protected bool Jump(Func<T, bool> state)
        {
            for (var i = 0; i < methods.Length; i++)
            {
                if (state == methods[i])
                {
                    JumpSeqNo = i;
                    return true;
                }
            }
            throw new Exception("遷移先が見つからない");
        }

        /// <summary>
        /// 実行ポジション移動(Fetch)
        /// </summary>
        /// <returns></returns>
        bool Fetch()
        {
            if (0 > JumpSeqNo)
            {
                SeqNo++;
            }
            else
            {
                SeqNo = JumpSeqNo;
                JumpSeqNo = -1;
            }
            return (0 <= SeqNo) && (SeqNo < methods.Length);
        }

        /// <summary>
        /// 時間軸ありのシーケンス実行
        /// </summary>
        /// <param name="value"></param>
        /// <returns>True=条件を満たした False=条件を満たしていない</returns>
        protected IEnumerable<Func<T, bool>> Exexute(T value)
        {
            SeqNo = 0;
            do
            {
                while (!Current(value))
                    yield return Current;
            } while (Fetch());
        }
    }

    /// <summary>
    /// ステートマシンベースクラス(Observerパターン)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class Workflow<T> : StateMachine<T>, IReactive<T>
    {
        public LinkedList<T> Follows { get; } = new LinkedList<T>();
        public LinkedList<T> Followers { get; } = new LinkedList<T>();
        public virtual void OnCompleted() { }
        public virtual void OnError(Exception error) { throw error; }
        public virtual IEnumerable<Func<T, bool>> OnNext(T value)
        {
            foreach (var exe in Exexute(value))
                yield return exe;
            foreach (var exe in Followers.OnParallel(value))
                yield return exe;
        }

        /// <summary>
        /// 購読開始
        /// </summary>
        /// <param name="follower"></param>
        public void Subscribe(IReactive<T> follower)
        {
            Followers.Add(follower);    //自分のフォロワーリストに登録
            follower.Follows.Add(this); //相手のフォローリストに登録
        }

        /// <summary>
        /// 購読解除
        /// </summary>
        public void Dispose()
        {
            //A -> B(自信) -> C の時、Bを削除したとき
            //A -> C となるようにリストを操作
            foreach (var follow in Follows)
            {
                follow.Followers.Remove(this);      //フォローのフォロワーリストから自分をを削除
                follow.Followers.AddRange(Followers);
            }
            foreach (var _ in Followers)
            {
                _.Follows.Remove(this);             //フォロワーのフォローリストから自分をを削除
                _.Follows.AddRange(Follows);
            }

            Follows.Clear();
            Followers.Clear();
        }

    }

}



使い方は以下のようになる。




using System;

namespace ConsoleApplication1
{
    public class AFunc1 : Workflow<int>
    {
        int a = 0;
        bool F1(int parameter)
        {
            //Console.WriteLine($"Func11={parameter}");
            return false;// Jump(F2);
        }
        bool F2(int parameter)
        {
            Console.WriteLine($"Func12={parameter}");
            parameter++;
            return (++a % 2) == 0;
        }
    }

    public class AFunc2 : Workflow<int>
    {
        int a = 0;
        bool F1(int parameter)
        {
            Console.WriteLine($"Func21={parameter}");
            return (++a % 2) == 0;
        }
        bool F2(int parameter)
        {
            Console.WriteLine($"Func22={parameter}");
            parameter++;
            return (++a % 2) == 0;
        }
    }

    public class AFunc3 : Workflow<int>
    {
        int a = 0;
        bool F1(int parameter)
        {
            Console.WriteLine($"Func31={parameter}");
            return true;
        }
        bool F2(int parameter)
        {
            Console.WriteLine($"Func32={parameter}");
            return true;
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            var f1 = new AFunc1();
            var f2 = new AFunc2();
            var f3 = new AFunc3();

            //f1.Subscribe(f2);
            //f2.Subscribe(f3);

            var a = f1.OnNext(1).GetEnumerator();
            var dt1 = DateTime.Now;
            for (var i = 0; i < 10000000; i++)
            {
                a.MoveNext();
            }
            var dt2 = DateTime.Now;
            Console.WriteLine((dt2 - dt1).TotalMilliseconds);
            //foreach(var a in f1.OnNext(1))
            //    Console.WriteLine($">>>>>>>>>>>>>{a.Method.ReflectedType.Name}:{a.Method.Name}");

            Console.WriteLine("-----");
            Console.ReadKey();
        }
    }
}

Rx亜種を実装してみた

前回はRx入門について書いてみた。

記事にすることでRxについて理解は深まったけど、C#ではいらないんじゃないかなって思えてきた。
Javascriptなら有用な手段かもしれないけどね。。って感じに。
という心境なので今回はRxの処理についてもう少し深い話を進めていきたいと思う。

LINQについて
 使ったことがあればわかると思うが、データの一連処理を行う事ができるとても便利なもの。


Rx(Observer+Observable)+LINQについて
 RXは受動的なので、イベント引数や値がプッシュされて初めて動き出す。
そこでLINQを使うとイベント引数や値の条件をLINQで設定できる。これが良いようだ。


RxのHotとColdについて
 Hotはセンサーのようなもの。状態変化したら情報発信(OnNext)するだけのようなもの。
 ColdはLINQでつないだパイプ的なもの。
 HotもColdも共通して受動的に動くので、
 Hotの場合は定周期で実行したり、Coldの場合は使いたいときにOnNextを呼んで動かす。


データフローについて
 1つずつ値をプッシュして分岐するところで、同じ値をプッシュしたり交互に割り振ったりすることが可能。実際に使う場合は同じ値を全体にプッシュする方だと思う。

色々突き詰めていくとOnNextがすべて。

具体的に説明すると、
まずObservableクラスを作る

  OnNextで値をプッシュ→OnNext→OnNext→・・・→OnCompleted
 
  例外はOnError

という処理構造が木構造でできているのである。

OnNextは左から右へと値をプッシュ&LINQで条件式が挿入できる感じで
OnCompletedは大体がDisposeみたいに使われる。
OnErrorは例外なので説明省略。


値をプッシュ→何らかの処理→Subscribe{OnNext、OnCompleted、OnError}で処理が実行される。

値をフィードバックしたい時どうするの?って思うが、
最初の発端がイベントからスタートなので値を状態に反映させるだけ、
反映された結果のフィードバックは別で行われるというざっくりした切り分けになっている。
そうすることでイベントを呼び出したスレッドで何もかもやってしまおうって考えはどうなの?って思うけど省略しておく。

話を戻してさっきの仕組みを普通に書いてみると

void func1(int value)
{
    try
    {
        if(条件式1) ; // OnNext=Trueなら次へ
        {
            if(条件式2)
            {
                OnCompleted();
            }
        }catch (Exception ex)
        {
        }
    }
}
実際はOnNext部分とかDelegateで処理を挿入するので少し変わるけど、基本構造はこんなものだ。

なんかObserverパターンを使うことで小難しくなってしまう場合があるんじゃないかって疑問がでてきたわけだ。

ということでObserverパターンを簡素化したもので実装してみた。

基本構造は
 WorkerクラスとDispatcher クラスがいる。
 Dispatcherクラスは、自クラス内にあるシーケンス処理をRefrectionで呼び出して処理実行する。StateパターンのDelegate版
  TrueならOnNext、Falseなら実行しない。 
  ここでDelegateしたOnNext部分とLINQ部分の処理をまとめた。
 WorkerクラスはObserverパターンの簡素版、1:Nになるようにした。
 この辺りはツイッターをイメージするとわかりやすいのでフォローとフォロワーで変数名を定義してある。
 ちなみにColdとHotの説明をしたけど、Hotは定周期タスクに登録して定期的に実行して変化があればOnNextしてもらえればいいので概念だけわかっていればOK。
出力条件はDispatchクラスがやってくれるし、下のコードで特に問題なさそう。


    public class Dispatcher<T>
    {
        Func<T, bool>[] methods { get; }
        int SeqNo { get; set; } = 0;
        int JumpSeqNo { get; set; } = -1;

        public Dispatcher()
        {
            methods = GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.InvokeMethod)
            .Where(_ => _.ReturnType == typeof(bool) && 1 == _.GetParameters().Length)
            .Where(_ => (_.GetParameters()[0].ParameterType == typeof(T)))
            .Select(_ => (Func<T, bool>)_.CreateDelegate(typeof(Func<T, bool>), this))
            .ToArray();
        }
        protected bool Jump(Func<T, bool> state)
        {
            for (var i = 0; i < methods.Length; i++)
            {
                if (state == methods[i])
                {
                    JumpSeqNo = i;
                    return true;
                }
            }
            throw new Exception("遷移先が見つからない");
        }

        protected bool Dispatch(T value)
        {
            SeqNo = -1;
            while (Next())
            {
                if (!methods[SeqNo](value))
                    return false;
            }
            return true;
        }

        bool Next()
        {
            if (0 > JumpSeqNo)
            {
                SeqNo++;
            }
            else
            {
                SeqNo = JumpSeqNo;
                JumpSeqNo = -1;
            }
            return (0 <= SeqNo) && (SeqNo < methods.Length);
        }
    }

    public class Worker<T> : Dispatcher<T>, IDisposable
    {
        internal Worker<T> follow { get; set; } = null;
        internal List<Worker<T>> followers { get; } = new List<Worker<T>>();

        public void SubScribe(Worker<T> follower)
        {
            if(null != follower.follow) throw new Exception("複数フォローできません");
            followers.Add(follower);
            follower.follow = this;
        }

        public bool OnNext(T value)
        {
            if (Dispatch(value))
                return followers.TrueForAll(_ => _.OnNext(value));
            return false;
        }

        public void Dispose()
        {
            follow.followers.Remove(this);
            follow = null;
            followers.ForEach(_ => _.follow = null);
            followers.Clear();
        }
    }


使い方はこんな感じ


    class Worker1 : Worker<int>
    {
        bool Func1(int value)
        {
            Console.WriteLine($"Func11={value}");
            return Jump(Func2);
        }

        bool Func2(int value)
        {
            Console.WriteLine($"Func12={value}");
            return true;
        }
    }

    class Worker2 : Worker<int>
    {
        bool Func1(int value)
        {
            var ret = 0 == value % 2;
            Console.WriteLine($"Func21={ret}");
            return ret;
        }

        bool Func2(int value)
        {
            var ret = 0 != value % 3;
            Console.WriteLine($"Func22={ret}");
            return ret;
        }
    }

    class Worker3 : Worker<int>
    {
        bool Func1(int value)
        {
            Console.WriteLine($"Func31={value}");
            return true;
        }

    }
    class Program
 {
        static void Test(int i)
        {
            var proc1 = new Worker1();
            var proc2 = new Worker2();
            var proc3 = new Worker3();

            proc1.SubScribe(proc2);
            proc1.SubScribe(proc3);


            proc1.OnNext(2);
            proc2.Dispose();

            proc1.OnNext(2);
            proc3.Dispose();

            proc1.OnNext(2);
            proc1.SubScribe(proc2);

            proc1.OnNext(2);
            proc1.SubScribe(proc3);

            proc1.OnNext(2);
        }
    }

2016年1月22日金曜日

[C#] Reactive Extension入門(Rx)

Reactive Extension入門

 Rx入門を何回読んでも難しい。
ネット上の記事をみているとみんなが揃って良いと書いてあるのでステマ?って気がするし理解が進まない。
ということで自分でも記事を書いてみる事にしました。
最初にいっておくとRxを完全に理解しつくせていません。


そもそもRxって何なの?
 OvserverパターンをベースにLinQ化できるもの。


Observerパターンとは何か?
 Observer(監視役)ーObservable(労働者)の関係が1:Nの時に有用であり
労働者が監視役へ通知{OnNext、OnCompleted、OnError}するといった考えである。


Rxにすると?
 イベントが発生するとObservable(労働者)が動き、結果をObserver(監視役)へ通知する。
このオブザーバーパターンの性質をLINQ化できるようになる。


メリットは?
 イベント→Observable(労働者が何らかの処理の行う)→結果(OnNext, OnError, OnComplete)を返し
 さらに次の動作へ引き継がれていく連鎖が出来上がる。
 まるでドミノ倒しのように1つのイベントから連鎖反応が起きるのがメリットだと思う。


使い道は?
 例えばメール受信したら他のメールアドレスへ転送するとかができる。
  メール:Observable
  転送処理:Observer

としたときの実装は、

 「メール」は、受信したらOnNextを呼ぶ
 「転送処理」は、OnNextが呼ばれたら転送処理を実行

というようになる。

転送処理は「メールを受信したら」の続きを行いたいので、
 メールに対してSubscribe(購読)しておく。

すると、メール受信したら
 Observer側OnNextが呼ばれるので、メール受信したらの転送するという処理ができあがる。

こういった使い道が有用なケースであり、
LinQの技術を合わせることでWhereなどが使えるようになるのがとても良さそう。


イケてないと思うのは?
 初見、個人的にイケていないなと思った点を書くと、だれが処理するの?ってところ。
Observerでメール受信したよって、みんなに通知するのはOK。
が、しかしOnNextの中に転送処理が入ってると
メール受信したよってOnNextで通知して続けて転送処理も行うので
イベント出した人が一連の処理を行っているのがとても気になる。
一連の処理の塊があってイベント出したらその人が最後までやり遂げる必要が出てくる。

さっきのメールの例をあげると、
郵便屋さんがある宅にはがきを届けたついでに秘書のやるようなやってしまう。そんなところ。
(RxではIEnumerableインターフェイスを使ってスケジューラで処理させることでうまく解決してるんだろうけどね。)


処理の流れについて

 イベント
  ↓
 Observable
  ↓
 (Observer兼Observableの二役)
  ↓
  …
  ↓
 Observer(OnComplate、OnNext、OnError)


最初はObservableなオブジェクトで始まり、
中間は板挟みの監視し監視される立場なので両方の性質を持ち合わせていて、最後はObserverで終える。
中間を省いて考えればイベント入力で結果が返ってくる仕組みになっているのが分かるだろう。
この一連の処理をLinQで処理するのでIEnumerableインターフェイスを追加してあげると
Foreachで処理を回せるようになり、それが後々のスケジューラとなる。


実装例

今回ツイッターのタイムライン情報を見てフォロワーのAさんとBさんがRTするという例を
自作Subjectで実装してみた。
これで仕組みが理解できた気がする。

 public class Subject<T> : IObserver<T>, IObservable<T>, IDisposable, IEnumerable
 {
  protected Queue<T> EventQueue { get; } = new Queue<T>();    // events
  internal List<Subject<T>> follows { get; } = new List<Subject<T>>();  // observable
  internal List<Subject<T>> followers { get; } = new List<Subject<T>>(); // observer
  public virtual void OnCompleted() => followers.ForEach(_ => _.OnCompleted());
  public virtual void OnError(Exception error) => followers.ForEach(_ => _.OnError(error));
  public virtual void OnNext(T value) => followers.ForEach(_ => _.OnNext(value));
  public virtual IEnumerator GetEnumerator()
  {
   if (0 == EventQueue.Count)
    yield break;
   while (0 < EventQueue.Count)
   {
    var queue = EventQueue.Dequeue();
    followers.ForEach(_ => _.OnNext(queue));
    yield return this;
   }
   followers.ForEach(_ => _.OnCompleted());
  }
  public IDisposable Subscribe(IObserver<T> observer)
  {
   //購読すると、自分のフォローリストに追加、相手のフォロワーリストに追加
   var _observer = (Subject<T>)observer;
   followers.Add(_observer);       // フォロワーを受け入れる
   _observer.follows.Add(this);    // 相手側のフォローにも登録
   return (IDisposable)observer;
  }
  public void Dispose()
  {
   //フォロー(observable)・フォロワー(observer)の関係を破棄する
   follows.ForEach(_ => _.followers.Remove(this)); //フォローした人フォロワーリストから自身を削除
   followers.ForEach(_ => _.follows.Remove(this)); //フォロワーしてくれた人のフォローリストから自身を削除
   followers.Clear();
   follows.Clear();
  }
  //無条件永久ループ
  public Task MainLoop() =>
    Task.Run(() =>
    {
     while (true)
     {
      foreach (var _ in this)
       Thread.Sleep(0);
      Thread.Sleep(1);
     }
    });
 }

 public class Timeline : Subject<string>
 {
  /// <summary>
  /// 受信データがあったときの処理
  /// </summary>
  /// <returns></returns>
  public override IEnumerator GetEnumerator()
  {
   Console.WriteLine("\r\n---------------------------");
   while (0 < timelines.Count)
   {
    var message = timelines.Dequeue();
    Console.WriteLine($"TL上の新着メッセージ:{message}");
    OnNext(message);
   }
   yield break;
  }
  Queue<string> timelines { get; } = new Queue<string>();
  public void Send(string message) => timelines.Enqueue(message);
 }

 public class RTer : Subject<string>
 {
  string UserName { get; }

  public RTer(string userName)
  {
   UserName = userName;
  }

  public override void OnNext(string value)
  {
   Console.WriteLine($"{UserName}: {value}のツイートをRTした");
  }
 }


 class Program
 {
  static void Main(string[] args)
  {
   var tl = new Timeline();
   var u1 = new RTer("Aさん");
   var u2 = new RTer("Bさん");

   tl.Send("Hello");
   foreach (var _ in tl) ;

   tl.Subscribe(u1);
   tl.Send("World");
   foreach (var _ in tl) ;

   tl.Subscribe(u2);
   tl.Send("foo");
   foreach (var _ in tl) ;

   u2.Dispose();
   tl.Send("bar");
   foreach (var _ in tl) ;
  }
 }
}



Androider