sstea備忘録

日々のPCライフのメモ、備忘録、及びそれに類推する何か。
記載内容に間違い等を発見された場合はコッソリ教えてください... → sstea<a>aol.jp (<a> を @ に変えてください)


続、Raspberry Pi をジョイスティックで操作する


前回からの続きになります。
前回、Raspberry Piでジョイスティックの入力検出する jsinputd デーモンを作りました。
今回は jsinputd デーモンを使用し、ジョイスティックによりRaspberry Piに実際にアクションさせてみたいと思います。

jsinputd デーモン、及びスクリプトは全て /home/pi/local/bin/ に置いてあるという前提で、下記は記述しています。新しく作成するスクリプトも同ディレクトリに置きます。

◆ジョイスティックのキー入力判定とアクション
ジョイスティックのどのボタンが押された時に、どういうアクションを行なうかを書いたファイルが下記です。

jscmd.sh
#!/bin/bash

JSFILE=$1

update_input() {
    js=(`cat ${JSFILE}`)
    bt_left=${js[0]}
    bt_down=${js[1]}
    bt_right=${js[2]}
    bt_up=${js[3]}
    bt_L1=${js[4]}
    bt_R1=${js[5]}
    bt_L2=${js[6]}
    bt_R2=${js[7]}
    bt_select=${js[8]}
    bt_start=${js[9]}
    bt_L3=${js[10]}
    bt_R3=${js[11]}
    st_LH=${js[13]}
    st_LV=${js[14]}
    st_RH=${js[15]}
    st_RV=${js[16]}
    st_crossH=${js[17]}
    st_crossV=${js[18]}
}

joystick_command() {
    if [ ${bt_start} -eq 1 ] && [ ${bt_select} -eq 1 ] &&
       [ ${bt_L1} -eq 1 ] && [ ${bt_R1} -eq 1 ] &&
       [ ${bt_L2} -eq 1 ] && [ ${bt_R2} -eq 1 ]; then
        /home/pi/local/bin/talk.sh "Shutdownします"
        sudo shutdown -h now
        exit 0
    fi

    if [ ${bt_start} -eq 1 ]; then
        /home/pi/local/bin/jihou.sh &
    fi
}

update_input
joystick_command

ソフトで1つ目に検出するボタンがジョイスティックの実際のどのボタンに対応するか(startボタンなのか、L1ボタンなのか)は、使用するジョイスティック毎に異なりますので、まずは update_input にてそれぞれ対応する変数に入れています。

joystick_command の部分が実際のアクション定義部分です。

上記例では、start+select+L1+L2+R1+R2 の同時押しで、Raspberry Piをシャットダウンします。
またその旨を音声出力しています。
もう一つのコマンドはstart ボタンだけを押した場合で、その時の時間をお知らせします。
talk.sh や jihou.sh は前々回に作成したスクリプトです。

この部分の追加、カスタマイズはお好きにどうぞ。
(拡張版を↓おまけ2に用意しました。)

# 最初 "#!/bin/sh" としていたのですが、
# "js=(`cat ${JSFILE}`)" という書き方が、"#!/bin/sh" だと駄目のようでした。
# とりあえずですが、#!/bin/bash 固定としておきます。

jsmonitor.sh
#!/bin/sh

JSDEV=$1
JSFILE=$2

while [ `cut -f1 -d. /proc/uptime` -lt 20 ]; do
    sleep 1
done

/home/pi/local/bin/jsinputd ${JSDEV} ${JSFILE} &

sleep 0.5

while inotifywait -qq -e modify ${JSFILE}
do
    /home/pi/local/bin/jscmd.sh ${JSFILE}
done

ジョイスティック入力検出のための jsinputd デーモンをバックグラウンド起動し、デーモンの出力ファイルに変更があった時(=キー入力に変更があった時)だけ jscmd.sh が呼ばれます。
キー入力に変化がない場合(無入力状態、またはキーを押しっぱなしの場合)は inotifywait により待ち状態となります。

jsinputd の実行の後に 0.5 秒の sleep を入れているのは、デーモンが動作し出力ファイルが作成されるのを待つためです。
一番最初の while の中の sleep は気にしないでください。(↓◆おまけ1で補足します。)

上記スクリプトを取ってきて、実行権限を与えます。
$ cd /home/pi/local/bin/

$ curl -O http://sstea.blog.jp/raspi/script/jscmd.sh
$ curl -O http://sstea.blog.jp/raspi/script/jsmonitor.sh

$ chmod 755 jscmd.sh jsmonitor.sh
実行してみます。
$ ./jsmonitor.sh /dev/input/js0 /tmp/jsinput
意図通りに動くか確認してみましょう。
jscmd.sh で jihou.sh をバックグラウンド実行させているので、start ボタンを連打しても、ちゃんと押した回数、時間報告してくれます。、

# 上記 jsmonitor.sh は Ctrl-C で終了しても、バックグラウンドで動いている jsinputd は終了しません。
# "killall jsinputd" してあげてください。
# もしくはUSBアダプタを抜いてやると終了します。

◆jsmonitor.shの自動起動
毎回、自分で jsmonitor.sh を実行するのは面倒なので自動的に起動させたいですが、起動時に自動実行させても起動時点でUSBアダプタが刺さっていない(起動後に挿す場合とか)と、どのみち自分で実行する必要があります。

幸いにも Linux には udev というデバイスのプラグアンドプレイに合わせて処理を行なわさせる機構が備わっています。(正直、udev はあまり詳しくないですが。。。)

jsevent.sh
#!/bin/sh

JSFILE=/tmp/jsinput

if [ $1 = "add" ]; then
    /home/pi/local/bin/jsmonitor.sh ${DEVNAME} ${JSFILE} &
elif [ $1 = "remove" ]; then
    rm -f ${JSFILE}
fi
ジョイスティックの抜き差し時に、上記 jsevent.sh を実行する udev のルールを追加してみましょう。

/etc/udev/rules.d/99-joystick.rules
SUBSYSTEMS=="input", KERNEL=="js[0-9]", ACTION=="add", RUN="/home/pi/local/bin/jsevent.sh add"
SUBSYSTEMS=="input", KERNEL=="js[0-9]", ACTION=="remove", RUN="/home/pi/local/bin/jsevent.sh remove"

上記ルールを下記コマンドにより追加します。
$ curl -O http://sstea.blog.jp/raspi/script/jsevent.sh
$ chmod 755 jsevent.sh

$ curl -O http://sstea.blog.jp/raspi/script/99-joystick.rules
$ sudo mv 99-joystick.rules /etc/udev/rules.d/99-joystick.rules
udev をリスタートします。
$ sudo service udev restart
これで完成です。
USBアダプタのプラグアンドプレイに合わせて、jsmonitor.sh を実行できるようになりました。

# ちなみに jsevent.sh の DEVNAME ですが、環境変数として設定されるようです。
# おそらく "udevadm info --query=property --name=/dev/input/js0" で
# 表示されるパラメータが使用可能だと思います。

◆おまけ1
udev ルールでプラグアンドプレイに合わせてスクリプトを実行するようにしたわけですが、プラグアンドプレイ時は問題なかったのですが、当初は起動時からUSBアダプタが刺さっている場合に問題がありました。

jsinputd が /tmp/jsinput ファイルを作成するのですが、起動時点で既にUSBアダプタが刺さっている場合、なぜかファイル作成に失敗していたのです。

いろいろデバッグした結果、推測も混じりますが、以下の事が分かりました。
起動時に既に条件を満たしたudevルールがある場合、他の初期化が完了する前の結構早い段階で実行されるようです。(fstab のマウント等より先のようです。)
そのため、まだファイルシステムがread onlyの状態(remount前)に書き込みをしようとして失敗しているようでした。(remountが終わっても、/tmp を ramdisk 化しているため、tmpfs のマウント前の /tmp に書き出していた場合もありました。)

単純に sleep 10 とかを入れて、初期化完了待ちをしようかと思いましたが、そうするとプラグアンドプレイ時に、それだけ待たされてしまいます。
苦肉の策としてですが、起動時からの時間が20秒経っていなければ、20秒経つまで待ちにするという sleep を入れました。
その結果、起動時からUSBアダプタが刺さっている場合でも、プラグアンドプレイ時でも期待した動作をするようになりました。

◆おまけ2
上記の jscmd.sh ではボタンの押しっぱなしによる連続入力が検出できません。
それを検出できるようにした拡張版が↓です。
また mpc 関連の操作ができるようにコマンドを追加しました。

jscmd2.sh
#!/bin/bash

JSFILE=$1

update_input() {
    :  (省略)
}

joystick_command() {
    if [ ${bt_start} -eq 1 ] && [ ${bt_select} -eq 1 ] &&
       [ ${bt_L1} -eq 1 ] && [ ${bt_R1} -eq 1 ] &&
       [ ${bt_L2} -eq 1 ] && [ ${bt_R2} -eq 1 ]; then
        /home/pi/local/bin/talk.sh "Shutdownします"
        sudo shutdown -h now
        exit 0
    fi
    if [ ${bt_L3} -eq 1 ] && [ ${bt_R3} -eq 1 ] &&
       [ ${bt_L1} -eq 1 ] && [ ${bt_R1} -eq 1 ] &&
       [ ${bt_L2} -eq 1 ] && [ ${bt_R2} -eq 1 ]; then
        /home/pi/local/bin/talk.sh "Rebootします"
        sudo reboot
        exit 0
    fi


    if [ ${bt_start} -eq 1 ]; then
        /home/pi/local/bin/jihou.sh &
        WAIT=5
        return 1

    fi

    if [ ${bt_right} -eq 1 ]; then
        mpc toggle
        exit 0
    fi
    if [ ${bt_down} -eq 1 ]; then
        mpc stop
        exit 0
    fi

    if [ ${bt_L1} -eq 1 ]; then
        mpc prev
        WAIT=5
        return 1
    fi
    if [ ${bt_R1} -eq 1 ]; then
        mpc next
        WAIT=5
        return 1
    fi

    if [ ${st_LH} -ne 0 ]; then
        if [ ${st_LH} -lt 0 ]; then
            mpc seek -1
        else
            mpc seek +1
        fi
        return 1
    fi
    if [ ${st_crossV} -ne 0 ]; then
        if [ ${st_crossV} -lt 0 ]; then
            mpc volume +10
        else
            mpc volume -10
        fi
        return 1
    fi

    return 0

}

while [ 1 ]; do
    input=`cat ${JSFILE}`
    if [ "${input}" != "${prev_input}" ]; then
        prev_input=${input}
        WAIT=0
    fi
    if [ ${WAIT} -ne 0 ]; then
        WAIT=$((${WAIT} - 1))
        sleep 0.1
        continue
    fi


    update_input
    joystick_command
    if [ $? -eq 0 ]; then
        break
    fi
done

update_input に関しては変更ありませんので、元スクリプトを参照。
$ cd /home/pi/local/bin/

$ curl -O http://sstea.blog.jp/raspi/script/jscmd2.sh
$ mv jscmd2.sh jscmd.sh

$ chmod 755 jscmd.sh

Raspberry Pi をジョイスティックで操作する

前回、Raspberry Pi で音を鳴らしてみましたが、今度はインターフェースの改善を試みたいと思います。

Raspberry Pi を操作するのにこれまでは TeraTerm でSSH接続して操作してきましたが、ホストマシンを立ち上げる必要もあり、Raspberry Pi の電源を落とすのにも一苦労(という程の苦労でもないのですが)します。

かと言って、Raspberry Pi に電源スイッチを(物理的に)増設するほどでもない。
何よりソフトソフトしていたいのです。(半田ゴテとかとは無縁の人なので。自分は。)

◆Raspberry Pi にジョイスティックを接続
一昔前に、PS3 の純正ジョイスティックのボタンがヘタってきたために買ったジョイスティック(GAMETECH ワイヤレスバトルパッドターボ3)がありましたので、それでどうにかしたいと思います。

# ジョイスティック?ジョイパッド?ゲームパッド?コントローラ?
# ちなみにアレは何て呼ぶのが正解なんでしょうか?
# とりあえずここではジョイスティックで統一しておきます。

ワイヤレスバトルパッドターボ3 はUSBの無線アダプタと、コントローラとに分かれています。
現在のうちの Raspberry Pi は↓のような構成になっています。緑色に光ってるのが無線アダプタです。

ss_rpi_connect01

このジョイスティックの無線アダプタであるUSBを接続したところ、
/var/log/messages に下記のようなログが出てました。
usb 1-1.2: new full-speed USB device number 10 using dwc_otg
usb 1-1.2: New USB device found, idVendor=1915, idProduct=001e
usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-1.2: Product: PS3 wireless GAME PAD
usb 1-1.2: Manufacturer: ACRUX
input: ACRUX PS3 wireless GAME PAD as /devices/platform/bcm2708_usb/usb1/1-1/1-1.2/1-1.2:1.0/0003:1915:001E.0006/input/input5
hid-generic 0003:1915:001E.0006: input,hidraw0: USB HID v1.11 Gamepad [ACRUX PS3 wireless GAME PAD] on usb-bcm2708_usb-1.2/input0
また、/dev/input/js0 が増えました。
ここまでは何もしていないですが、正常に認識できているようです。

◆理想のジョイスティックキー入力検出を求めて...
さて、これだけだと、ジョイスティックのボタンをポチポチ押しても、無反応です。
少し Google 先生と相談です。。。

pygame という python のモジュールでジョイスティックの入力が取得可能らしいですね。。。
python... 馴染みがないし、分かりませーん。C とシェルくらいしかまともには使えませーん。

その他、いくつか試してみましたが、、、
キー入力をポーリングで検出するのはどうにかしたいですねー。

sleep しながらループしないと top コマンドで CPU 使用率が100%です。
→ sleep 時間が長いと CPU 使用率は下がるが、キー入力を取りこぼす。
     キー入力の反応が悪く、キモチ悪い。
→ sleep 時間が短いと、キー入力の反応はいいものの、CPU 使用率が上がる。
     0.1秒 sleep だとこの処理だけで、CPU 使用率が 10~20% いってしまいます。
     また、反応がいいとはいいつつも、0.1秒 sleep でも少し違和感を感じました。

Raspberry Pi はただでさえ貧相なCPUなので、キー入力がない時は素直に寝ていて欲しいです。
(待ち受け(idle) 時は1%だってCPUを使って欲しくないのです。)

◆Raspberry Pi でのジョイスティックのキー入力検出
自分の求める要件としては、下記4点です。
・ボタンを押した時の動作はシェルで好きに書く事ができる(カスタマイズが可能)。
・キー同時押しが検出可能。(L1+L2+R1+R2+Start+Select でシャットダウンしたいからです。)
・ポーリングでのキー入力検出ではなくて、イベントドリブン(キー入力がある時だけ起きてくる)のがいい。
・キー入力の反応がサクサク。違和感を感じない。

もう少し頑張って探そうかとも思いましたが、どうせ頑張るなら自分で作る方向のベクトルで頑張った方がいろいろ近道かと思い、いろいろ参考にしつつ C で作ってみる事にしました。

自作したジョイスティック入力検出デーモン(jsinputd と命名)が下記です。(結構、真面目に書きました。)
$ curl -O http://sstea.blog.jp/raspi/csrc/jsinputd.c
下記で Raspberry Pi 上でもビルドできると思います。-DDEBUG はなくても可。
(もちろんホスト側のクロスコンパイラでクロスビルドでも全然問題ありません。)
$ gcc jsinputd.c -o jsinputd -O2 -DDEBUG

jsinputd.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/joystick.h>

#ifdef DEBUG
#define ERROR(...)    (fprintf(stderr, "<JSINPUTD:E> " __VA_ARGS__), -1)
#else /* !DEBUG */
#define ERROR(...)    (-1)
#endif /* !DEBUG */

struct joystick_struct {
    int fd;
    unsigned char nr_buttons;
    unsigned char nr_sticks;
    short *button;    /* button[nr_buttons] */
    short *stick;    /* stick[nr_sticks] */
    char *input;    /* input[nr_btn * 2 + nr_stk * 7 + 1] */
};

static int joystick_output(struct joystick_struct *js, const char *out_file);
static int joystick_get_input(struct joystick_struct *js);
static int joystick_get_info(struct joystick_struct *js);
static int joystick_init(struct joystick_struct *js, const char *dev_file);
static void joystick_exit(struct joystick_struct *js);
static void joystick_main(const char *dev_file, const char *out_file);

static int joystick_output(struct joystick_struct *js, const char *out_file)
{
    FILE *fp = stdout;
    unsigned char i, nr_btn, nr_stk;

    if (out_file != NULL) {
        fp = fopen(out_file, "w");
        if (fp == NULL) {
            return ERROR("fopen(%s)\n", out_file);
        }
    }

    nr_btn = js->nr_buttons;
    nr_stk = js->nr_sticks;

    for (i = 0; i < nr_btn; i++) {
        sprintf(&js->input[i * 2], "%2d", js->button[i] ? 1 : 0);
    }
    for (i = 0; i < nr_stk; i++) {
        sprintf(&js->input[nr_btn * 2 + i * 7], "%7d", js->stick[i]);
    }
    js->input[nr_btn * 2 + nr_stk * 7] = '\0';

    fprintf(fp, "%s\n", js->input);

    if (out_file != NULL) {
        fclose(fp);
    }

    return 0;
}

static int joystick_get_input(struct joystick_struct *js)
{
    int ret;
    struct js_event ev;
    unsigned char num;

    do {
        ret = read(js->fd, &ev, sizeof(struct js_event));
        if (ret != sizeof(struct js_event)) {
            return ERROR("read : %d\n", ret);
        }
    } while (ev.type & JS_EVENT_INIT);

    num = ev.number;
    switch (ev.type) {
    case JS_EVENT_BUTTON:
        if (num < js->nr_buttons) {
            js->button[num] = ev.value;
        }
        break;
    case JS_EVENT_AXIS:
        if (num < js->nr_sticks) {
            js->stick[num] = ev.value;
        }
        break;
    default:
        break;
    }

    return 0;
}

static int joystick_get_info(struct joystick_struct *js)
{
    int ret, fd = js->fd;
#ifdef DEBUG
    char name[64];
#endif /* DEBUG */


    ret = ioctl(fd, JSIOCGBUTTONS, &js->nr_buttons);
    if (ret < 0) {
        return ERROR("ioctl(JSIOCGBUTTONS)\n");
    }
    ret = ioctl(fd, JSIOCGAXES, &js->nr_sticks);
    if (ret < 0) {
        return ERROR("ioctl(JSIOCGAXES)\n");
    }
#ifdef DEBUG
    ret = ioctl(fd, JSIOCGNAME(sizeof(name)), &name);
    if (ret < 0) {
        return ERROR("ioctl(JSIOCGNAME)\n");
    }
    printf("name=\"%s\", buttons=%d, sticks=%d\n", name, js->nr_buttons, js->nr_sticks);
#endif /* DEBUG */


    return 0;
}

static int joystick_init(struct joystick_struct *js, const char *dev_file)
{
    int ret, array_size;
    unsigned char nr_btn, nr_stk;
    unsigned char *p;

    ret = open(dev_file, O_RDONLY);
    if (ret < 0) {
        return ERROR("open(%s)\n", dev_file);
    }
    js->fd = ret;

    ret = joystick_get_info(js);
    if (ret < 0) {
        close(js->fd);
        return ret;
    }
    nr_btn = js->nr_buttons;
    nr_stk = js->nr_sticks;

    array_size = (nr_btn + nr_stk) * sizeof(short);
    p = malloc(array_size + nr_btn * 2 + nr_stk * 7 + 1);
    if (p == NULL) {
        close(js->fd);
        return ERROR("malloc\n");
    }
    js->button = (short *)p;
    js->stick = (short *)&p[nr_btn * sizeof(short)];
    js->input = (char *)&p[array_size];

    return 0;
}

static void joystick_exit(struct joystick_struct *js)
{
    free(js->button);
    close(js->fd);
}

static void joystick_main(const char *dev_file, const char *out_file)
{
    struct joystick_struct js;

    if (joystick_init(&js, dev_file) == 0) {
        do {
            if (joystick_output(&js, out_file) < 0) {
                break;
            }
        } while (joystick_get_input(&js) == 0);

        joystick_exit(&js);
    }
}

/*
 * arg1 : device file (default is /dev/input/js0)
 * arg2 : output file (default is stdout)
 */

int main(int argc, char **argv)
{
    char *dev_file = "/dev/input/js0";
    char *out_file = NULL;

    if (argc >= 2) {
        dev_file = argv[1];
    }
    if (argc >= 3) {
        out_file = argv[2];
    }

    joystick_main(dev_file, out_file);

    return ERROR("exit\n");
}

使用方法としては、
・第一引数にデバイスファイル(省略時は /dev/input/js0)
・第二引数に出力ファイル(省略時は標準出力)
を指定する感じです。
→ "Usage: jsinputd [device-file] [output-file]"

出力フォーマットは ボタン入力は 0 か 1、スティック入力は -32767 ~ 32767 の範囲で出力します。
順番はボタン0、ボタン1・・・とボタンの数だけ出力し、次いでスティック0からスティックの数分出力されます。

とりあえず、引数なしで実行。
$ ./jsinputd
name="ACRUX PS3 wireless GAME PAD", buttons=13, sticks=6
 0 0 0 0 0 0 0 0 0 0 0 0 0      0      0      0      0      0      0
Start ボタンを押したまま、Select ボタンを押して離して、その後 Start ボタンを離した場合。
下記のようにキー入力に変化があった時だけ動作し、出力が出ます。
結構ヌルサクでいい感じです!!(そして、無操作時は CPU 負荷 0 です!)
$ ./jsinputd
name="ACRUX PS3 wireless GAME PAD", buttons=13, sticks=6
 0 0 0 0 0 0 0 0 0 0 0 0 0      0      0      0      0      0      0
 0 0 0 0 0 0 0 0 0 1 0 0 0      0      0      0      0      0      0
 0 0 0 0 0 0 0 0 1 1 0 0 0      0      0      0      0      0      0
 0 0 0 0 0 0 0 0 0 1 0 0 0      0      0      0      0      0      0
 0 0 0 0 0 0 0 0 0 0 0 0 0      0      0      0      0      0      0


ちなみに、ジョイスティックの無線アダプタを Raspberry Pi から抜くと、ioctl で失敗し、終了します。
それ以外だと、基本的には Ctrl-C で中断しない限り、終了しません。

◆ジョイスティックのキー入力検出結果の取り込み

後は、上記で作成した jsinputd の出力結果をシェルで取り込めば、やりたい事は出来そうです。
標準出力に出されても困るので、/tmp/jsinput にでも出力させておこうと思っています。
この jsinputd の出力結果である /tmp/jsinput をシェルで取り込んでアレヤコレヤするわけです。

jsinputd デーモンは起動時にでも、バックグラウンド実行させておく想定です。
("./jsinputd /dev/input/js0 /tmp/jsinput &" みたいな感じで実行すればいいだけです。上記の想定で、ああいうインターフェースにしました。)

ただし、シェルから /tmp/jsinput を取り込むのに、ポーリングしながら読み込んだのでは本末転倒です。

幸いにも、ファイルに変化があった時だけ通知するという inotify という仕組みが Linux カーネルにはあり、それをシェルから利用できるツールがあります。
まずは inotify-tools をインストールしておきましょう。
$ sudo apt-get install -y inotify-tools

ちょっと長くなってきたので、続きは次回

Raspberry Pi で音を出してみる

手元に USBスピーカー(iBUFFALO BSSP25U)があったので、それを接続し Raspberry Pi から音を出してみたいと思います。

◆Raspberry Pi にUSBスピーカーを接続
まずUSBスピーカーを接続し、認識しているか確認します。
$ cat /proc/asound/cards
 0 [ALSA           ]: bcm2835 - bcm2835 ALSA
                      bcm2835 ALSA
 1 [MicroII        ]: USB-Audio - Audio Advantage MicroII
                      C-Media INC. Audio Advantage MicroII at usb-bcm2708_usb-1.3, full speed

ちゃんと認識しています。
が、USB-Audio が二つ目になっているので、このままではUSBスピーカーからは音は出ません。

/etc/modprobe.d/alsa-base.conf の snd-usb-audio の行をコメントアウトします。
#options snd-usb-audio index=-2

いったん、モジュールをアンロードし、再ロードします。
$ sudo alsa unload
$ sudo modprobe snd_usb_audio
$ sudo modprobe snd_bcm2835

USB-Audio が一つ目になっているのを確認します。
$ cat /proc/asound/cards
 0 [MicroII        ]: USB-Audio - Audio Advantage MicroII
                      C-Media INC. Audio Advantage MicroII at usb-bcm2708_usb-1.3, full speed
 1 [ALSA           ]: bcm2835 - bcm2835 ALSA
                      bcm2835 ALSA

◆Raspberry Pi にしゃべってもらう

まずは、AquesTalk Pi (http://www.a-quest.com/products/aquestalkpi.html) から aquestalkpi-20130827.tar.gz をダウンロードしてきます。

それを raspberry pi 上で展開します。
$ mkdir /home/pi/local/
$ cd /home/pi/local/
$ tar xvzf aquestalkpi-20130827.tar.gz
下記を実行。
$ aquestalkpi/AquesTalkPi hello | aplay
しゃべったー!!

$ mkdir /home/pi/local/bin/
$ cd /home/pi/local/bin/
talk.sh という名前のシェルスクリプトを書いてみました。
#!/bin/sh

TALK=/home/pi/local/aquestalkpi/AquesTalkPi

${TALK} -s 120 "$*" | aplay 2> /dev/null

上記をコピペするなり、curl コマンドで取るなりします。
$ curl -O http://sstea.blog.jp/raspi/script/talk.sh
実行権限を付与します。
$ chmod 755 talk.sh
引数で渡した言葉をしゃべってくれるという簡単なシェルスクリプトです。ちゃんと動いてます。
$ ./talk.sh hello

今度は、時間をお知らせしてくれるシェルスクリプトを書いてみます。

jihou.sh
#!/bin/sh

time=`date "+%-H時、%-M分、%-S秒になりました"`

/home/pi/local/bin/talk.sh ${time}

上記をコピペするなり、curl コマンドで取るなりします。
$ curl -O http://sstea.blog.jp/raspi/script/jihou.sh
実行権限を付与します。
$ chmod 755 jihou.sh
今の時間を知らせてくれます。
$ ./jihou.sh

これで、毎時間の5分前にお知らせ、というような事も cron に登録すれば出来るようになりました。
$ crontab -e
とし、末尾に下記を追加して終了します。
  55 * * * * /home/pi/local/bin/jihou.sh

◆Raspberry Pi で音楽を鳴らす
Music Player Daemon (MPD) をインストールします。
$ sudo apt-get install mpd mpc

以前に作成した /etc/init.d/init-ramdisk に追記しておきます。
#!/bin/sh
### BEGIN INIT INFO
# Provides:       init-ramdisk
# Required-Start: $local_fs
# Required-Stop:  $local_fs
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
### END INIT INFO

chmod 775 /var/log
mkdir -p /var/log/ConsoleKit/
mkdir -p /var/log/fsck/
mkdir -p /var/log/apt/
mkdir -p /var/log/ntpstats/
mkdir -p /var/log/samba/
mkdir -p /var/log/mpd/
chown root.ntp /var/log/ntpstats/
chown root.adm /var/log/samba/
touch /var/log/lastlog
touch /var/log/wtmp
touch /var/log/btmp
touch /var/log/mpd/mpd.log
chown root.utmp /var/log/lastlog
chown root.utmp /var/log/wtmp
chown root.utmp /var/log/btmp

music ディレクトリに適当な音楽ファイルを放り込む。
(デフォルトだと /var/lib/mpd/music/)

曲登録。
$ mpc update
$ mpc ls | mpc add
再生。おぉー、音楽、鳴りました。
$ mpc play
次の曲。
$ mpc next
設定とかもいろいろあります。詳細は "mpc help" で。
$ mpc volume 80
$ mpc repeat on

ここで一つ問題が。
mpd で音楽再生中に AquesTalk Pi でおしゃべりさせようとしても、しゃべってくれません。。。

/etc/mpd.conf の下記をコメントアウトすると音楽再生中でもおしゃべりしてくれました。声、少し小さい気がしますが。
audio_output {
    type        "alsa"
    name        "My ALSA Device"
#    device        "hw:0,0"    # optional
    format        "44100:16:2"    # optional
    mixer_device    "default"    # optional
    mixer_control    "PCM"        # optional
    mixer_index    "0"        # optional
}
ついでに下記をコメントアウトすることで、ベロベロ出てたエラーもなくなりました。
#bind_to_address   "localhost"


    次回は、ジョイスティックを繋いで操作出来るようにしてみたいと思います。


◆おまけ1
MPD にはスマホからでもアクセスできます。
世の中では MPD クライアントソフトがたくさん作られていて、スマホ用のアプリも例外なくあります。

自分もいくつか試してみて、Droid MPD Client が自分には合ってそうだったので、Xperia Z3 に入れています。

◆おまけ2
USBスピーカーを接続したまま電源入れると、起動時にプツプツ言って、立ち上がらない時がありました。

何でか結構悩みましたが、電力足りてないのか
/boot/config.txt の末尾に下記を追加したら安定しました。
safe_mode_gpio=4
max_usb_current=1


Raspberry Pi のディスクイメージを一から作る

前回カーネルも差し替えたので、以前の記事を見ながらディスクイメージのバックアップを取ろうかと思ったのですが、以前に構築した Linux Mint の仮想環境で、VirtualBox が(なぜか)ホスト側に挿した microSD カードリーダをうまく認識してくれませんでした。
仕方がないので、ディスクイメージをコネコネして、パーティションのリサイズやら何やらを行なったディスクイメージを作成することにしました。
gparted でリサイズしようと思ったんですが、アレ?イメージファイルだと、何故かリサイズ出来ないですね。。。

ちなみに、前回カーネルを差し替えたものに加えて、
NTP設定不要デーモンの停止、RAMディスクの使用、SWAPの停止、を行なっています。
SD使用量の節約のため日本語化等は見送りました。
ディスク使用量は半分弱といったところです。
$ df
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/root        3671884 1623100   1849424  47% /
devtmpfs          219996       0    219996   0% /dev
tmpfs              44836     336     44500   1% /run
tmpfs               5120       0      5120   0% /run/lock
tmpfs              89660       0     89660   0% /run/shm
/dev/mmcblk0p1     57288   10200     47088  18% /boot
tmpfs              32768       0     32768   0% /tmp
tmpfs              32768     112     32656   1% /var/log

◆ディスクイメージのベースの作成
"Win32 Disk Imager" を使用して、microSD のディスクイメージを Read し、仮想環境からも見える共有フォルダに入れておきます。以下、仮想環境の Linux Mint での操作になります。
(以下、ディスクイメージを rpi.img というファイル名で取得したとして記載しています。)
$ fdisk -l /media/sf_shared/rpi.img
ディスク /media/sf_shared/rpi.img: 3951 MB, 3951034368 バイト
ヘッド 255, セクタ 63, シリンダ 480, 合計 7716864 セクタ
Units = セクタ数 of 1 * 512 = 512 バイト
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
ディスク識別子: 0x0009bf4f

                デバイス ブート    始点      終点  ブロック   Id  システム
/media/sf_shared/rpi.img1          8192    122879    57344    c  W95 FAT32 (LBA)
/media/sf_shared/rpi.img2        122880   7716863  3796992   83  Linux

まずは、作成するディスクイメージのサイズを決めます。
今回は4GBのmicroSDをしようしているので、半分の2GBにしてみようと思います。

まず、空のファイルをイレモノとして作ります。
元のサイズの半分にした値
  (7716863 + 1) / 2 = 3858432
をcountに指定します。
$ export IMGFILE=/media/sf_shared/new.img

$ dd if=/dev/zero of=${IMGFILE} count=3858432 bs=512
これで、単にゼロ埋めされた2GBのファイルが出来上がりました。
# ちなみに、fdisk の表示される値と単位を合わせる意味で bs=512 としていますが、
# bs を(8倍の) 4096 とかにした方が、ファイルの作成時間は短くなります。
# その場合、count は(8分の1の)482304 とする必要があります。
# 詳細は↓おまけ1参照

パーティションテーブルを作成し、パーティションを2つ作成します。
fdisk コマンドで対話モードで設定しても全然問題ないんですが、表現が難しいので下記のようなコマンドにしておきます。(凄く見にくいですが、$'\n' が改行と思ってください。)
$ echo o$'\n'w | fdisk ${IMGFILE}
$ echo n$'\n'p$'\n'$'\n'8192$'\n'122879$'\n'w | fdisk ${IMGFILE}
$ echo n$'\n'p$'\n'$'\n'122880$'\n'3858431$'\n'w | fdisk ${IMGFILE}
$ echo t$'\n'1$'\n'c$'\n'w | fdisk ${IMGFILE}

これでガワだけは出来ました。
$ fdisk -l ${IMGFILE}

ディスク /media/sf_shared/new.img: 1975 MB, 1975517184 バイト
ヘッド 255, セクタ 63, シリンダ 240, 合計 3858432 セクタ
Units = セクタ数 of 1 * 512 = 512 バイト
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
ディスク識別子: 0x0177f305

                デバイス ブート    始点      終点  ブロック   Id  システム
/media/sf_shared/new.img1          8192    122879    57344    c  W95 FAT32 (LBA)
/media/sf_shared/new.img2        122880   3858431  1867776   83  Linux

# 最初はこのディスクイメージを "sudo kpartx -v -a ${IMGFILE}" して、
# "mkfs.ext4 /dev/mapper/loop0p2" とかして直接フォーマットしようとしたんですが、
# 何かうまく出来なくてmountも出来ないので、下記のような手順を踏む事にしました。

◆各パーティションイメージの作成
それぞれ
  (122879 + 1) - 8192 = 114688
  (3858431 + 1) - 122880 = 3735552
の値を指定し、各パーティションのイメージファイルを作成します。
$ dd if=/dev/zero of=boot.img count=114688 bs=512
$ dd if=/dev/zero of=rootfs.img count=3735552 bs=512
それぞれフォーマットします。
$ mkfs.vfat boot.img
$ mkfs.ext4 -F rootfs.img

元のイメージディスクをマウントします。
$ mkdir old1/ old2/ new1/ new2/
$ sudo kpartx -v -a /media/sf_shared/rpi.img
$ sudo mount /dev/mapper/loop0p1 old1/
$ sudo mount /dev/mapper/loop0p2 old2/
元のイメージディスクの中身をそれぞれ全コピーします。
$ sudo mount boot.img new1/
$ sudo mount rootfs.img new2/
$ sudo cp -a old1/* new1/
$ sudo cp -a old2/* new2/
その他変更等(.bash_history や /var/cache/* の削除等)、やりたければやって、気が済めばアンマウントします。
$ sudo umount new1/
$ sudo umount new2/
元のイメージディスクをアンマウントします。
$ sudo umount old1/
$ sudo umount old2/
$ sudo kpartx -d /media/sf_shared/rpi.img
$ rmdir old1/ old2/ new1/ new2/

◆ディスクイメージとして結合
ベースのディスクイメージの各パーティションを置き換えて出来上がりです。
$ dd if=boot.img of=${IMGFILE} seek=8192 bs=512
$ cat rootfs.img >> ${IMGFILE}
これを "Win32 Disk Imager" で microSD に書き込めば、いつでもこの環境に復帰できます。
ちなみに、このディスクイメージは圧縮したら 400MB 弱になりました。

◆おまけ1

dd コマンドでは "bs=512, count=2048" でも、"bs=1024, count =1024" でも、どちらでも 1MB (bs * count) の読み書きを行なう、という事には変わりありません。では動きとしてはどう違うのでしょうか?

dd コマンドでは、if で指定したファイルから bs 単位で read し、of で指定したファイルに bs 単位で write を行う、という操作を count 回数分繰り返します。
つまり bs 単位の read, write システムコールを count 回発行しているのです。

以下のように、strace で観察するとよく分かります。
$ strace dd if=/dev/zero of=dummy count=100 bs=512
execve("/bin/dd", ["dd", "if=/dev/zero", "of=dummy", "count=100", "bs=512"], [/* 48 vars */]) = 0
brk(0)                                  = 0x9cf4000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
            :
open("/dev/zero", O_RDONLY|O_LARGEFILE) = 3
dup2(3, 0)                              = 0
close(3)                                = 0
_llseek(0, 0, [0], SEEK_CUR)            = 0
open("dummy", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
dup2(3, 1)                              = 1
close(3)                                = 0
clock_gettime(CLOCK_MONOTONIC, {238, 286988438}) = 0
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512) = 512
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512) = 512
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512) = 512
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512) = 512
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512) = 512
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512) = 512

            :

Raspbian(2015-02)のLinuxカーネルを差し替える

前記事で新バージョン(2015-02-16-raspbian-wheezy)の Raspbian をインストールしたので、Linuxカーネルも差し替えたいと思います。
以下、以前に書いた、この辺を見ながらクロスビルドしました。

微妙に手順変わってます。。。

◆カーネル/ローダブルモジュールのビルド

カーネルのクロスビルドには以前作った環境を使います。
以下、ホスト環境での操作になります。

git からLinuxカーネルのソースを取得します。
$ cd /home/mint/raspi/
$ git clone https://github.com/raspberrypi/linux.git
$ cd linux/
$ git checkout -b rpi-3.19.y remotes/origin/rpi-3.19.y
現時点の最新カーネルバージョンは 3.19.1 でした。(もうすぐ 4.0 になりますね。)

Raspberry Pi 実機上から取得したカーネルコンフィグをベースに、デバッグ関連、プロファイル関連のコンフィグを無効化したカーネルコンフィグ(これ)を使用します。(機能的にはデフォルトを維持してます。圧縮形式は lz4 に変更してますが。)

$ export ARCH=arm
$ export CROSS_COMPILE=arm-linux-gnueabihf-
$ cd /home/mint/raspi/linux/

上記のカスタマイズしたコンフィグを.config として linux ディレクトリ直下に置きます。
$ curl http://sstea.blog.jp/raspi/kbuild/kconfig-rpi-3.19.1 > .config
デフォルトのコンフィグを使用する場合は↓のようにしてもいいです。
$ make bcmrpi_defconfig

カーネルをビルドします。(コア数に応じて -j2 とかお好みで付けてあげてください)
$ make dtbs zImage modules
$ make modules_install INSTALL_MOD_PATH=../out/  INSTALL_MOD_STRIP=--strip-unneeded

前までは zImage を kernel.img にリネームするだけで問題ありませんでしたが、
dtb 使うようになってから、もう一工程、下記作業が必要になったようです。
(ここめっちゃ悩みました。詳細は↓おまけ1参照。
  mkknlimg は "git clone https://github.com/raspberrypi/tools.git" で取ってきた中にあります。)
$ cd /home/mint/raspi/
$ tools/mkimage/mkknlimg --dtok linux/arch/arm/boot/zImage out/kernel.img
dtb ファイル(bcm2708-rpi-b-plus.dtb)もコピーしておきます。
$ cp -p linux/arch/arm/boot/dts/bcm2708-rpi-b-plus.dtb out/

dtbファイルとkernel.img とローダブルモジュール郡を圧縮し、Raspberry Pi に持っていきます。
(まあ、このあたりは好きな方法で持っていってもらえればいいんですが。)
$ tar cvjf new.tar.bz2 out/

$ scp -p new.tar.bz2 pi@192.168.0.100:~
# IPアドレス部分は Raspberry Pi のIPアドレスを指定

◆クロスビルドしたLinuxカーネルへの差し替え
以下、Raspberry Pi 側での操作になります。

dtbファイルとカーネルイメージを差し替えます。
$ tar xvjf new.tar.bz2

$ sudo cp out/bcm2708-rpi-b-plus.dtb /boot/
$ sudo cp out/kernel.img /boot/
新しいカーネルバージョンのローダブルモジュールを展開します。
$ sudo cp -a out/lib/firmware/* /lib/firmware/
$ sudo cp -a out/lib/modules/3.19.1+/ /lib/modules/
リブートし、新しいカーネルの起動確認を行ないます。
$ reboot

もはや不要になったファイルは削除しておこうと思います。(必須ではないです)
$ sudo rm -rf /lib/modules/3.18.9+/ /lib/modules/3.18.9-v7+/
$ sudo rm -rf /boot.bak/

使用しない dtb ファイルや カーネルイメージファイルも削除していいですよね?
(自分が使用しているのは Raspberry Pi Model B+ モデルですので、下記ファイルは使用していません。)
$ sudo rm /boot/bcm2708-rpi-b.dtb /boot/bcm2709-rpi-2-b.dtb /boot/kernel7.img
$ df
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/root        3671884 1723412   1749112  50% /
devtmpfs          219996       0    219996   0% /dev
tmpfs              44836     452     44384   2% /run
tmpfs               5120       0      5120   0% /run/lock
tmpfs              89660       0     89660   0% /run/shm
/dev/mmcblk0p1     57288   10200     47088  18% /boot

◆おまけ1

以前のように、クロスビルドしたlinuxカーネルの zImage ファイルを kernel.img とリネームだけして、Raspberry Pi のカーネルを差し替えてみたんですが、どうも dtb ファイルを認識していないように思います。
ブートログにちらほらエラーも見えますし。
/boot/bcm2708-rpi-b-plus.dtb ファイルは確かに存在するのですが。
(ブートログは /var/log/messages で確認できます。)
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Initializing cgroup subsys cpuacct
[    0.000000] Linux version 3.19.1+ (mint@Mint) (gcc version 4.8.3 20140106 (prerelease) (crosstool-NG linaro-1.13.1-4.8-2014.01 - Linaro GCC 2013.11) ) #1 PREEMPT Sat Mar 14 22:50:58 JST 2015
[    0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
[    0.000000] Machine: BCM2708
[    0.000000] cma: Reserved 8 MiB at 0x1b800000
[    0.000000] Memory policy: Data cache writeback
            :

試しに、/boot/config.txt の末尾に
device_tree=bcm2708-rpi-b-plus.dtb
と追加し、リブートしてみたところ、
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Initializing cgroup subsys cpuacct
[    0.000000] Linux version 3.19.1+ (mint@Mint) (gcc version 4.8.3 20140106 (prerelease) (crosstool-NG linaro-1.13.1-4.8-2014.01 - Linaro GCC 2013.11) ) #1 PREEMPT Sat Mar 14 22:50:58 JST 2015
[    0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
[    0.000000] Machine model: Raspberry Pi Model B Plus
[    0.000000] cma: Reserved 8 MiB at 0x1b800000
[    0.000000] Memory policy: Data cache writeback
            :
dtb ファイル認識してますね。。。

どうして、デフォルトのカーネルイメージは config.txt に何も記載がなくても、ちゃんと正しい dtb ファイルを認識できてるんでしょうか?
カーネルバージョンの差か、コンフィグ変えたからか、とか考えていろいろ試してみたんですが、どうも関係なさそうです。
カーネルイメージに何か情報を付与してんじゃねーの?と思って、オリジナルのkernel.imgをバイナリエディタで開いてみると、、、
末尾に何か付いてますね。。。文字列が読めます。
圧縮イメージなのに読める文字列があるって事は、圧縮後に付与されたって事です。

zImageファイルはImageファイルを圧縮して自己展開プログラムを先頭にくっつけたファイルで、自分が知る限り末尾にこんな情報はくっつかないので、外部ツールなりでzImageにこの情報を付与する加工を加えているように思います。

カーネルイメージ生成手順、何か増えてんのか?と思って https://github.com/raspberrypi/tools の中をいろいろ見てると mkknlimg とかいうそれらしいのがありました。

で、コレ使って kernel.img 作ってみると、、、

$ mkknlimg --dtok zImage kernel.img
config.txt を弄らなくても、いけましたー。

◆おまけ2
CONFIG_KALLSYMS を無効化しようとして毎回、迷子になるのでメモ。

[1] CONFIG_LATENCYTOP と CONFIG_FTRACE を無効化

  Kernel hacking  --->
  [ ] Latency measuring infrastructure
  [ ] Tracers  ----

[2] CONFIG_KPROBES を無効化
  General setup  --->
  [ ] Kprobes

[3] KALLSYMS_ALL がようやく変更可能になるので無効化
  General setup  --->
  -*- Configure standard kernel features (expert users)  --->
  [ ]   Load all symbols for debugging/ksymoops

◆おまけ3
dtb (device tree blob)
ファイルは dts (device tree source)ファイルから生成されますが、dtb ファイルから dts ファイルに戻す事もできます。
Linux ツリーの中に dtc (device tree compiler)が入っています。

下記、コマンドで dtb ファイルから dts ファイルを取得できます。
$ cd /home/mint/raspi/
$ linux/scripts/dtc/dtc -I dtb -O dts ./bcm2708-rpi-b-plus.dtb > ./out.dts

Raspbian(2015-02)の環境を構築する

Raspbian が何やら新しいバージョンになっているようなので、環境を構築し直してみようと思います。

以下、以前に書いたここや、このあたりを参考にしつつ再構築しました。
(おおっ!? 備忘録として役立っているではないですか)

設定順序等を再構成し、いろいろ補完を行ないリメイクしました。
細かーい説明とかは端折ったりしてるかも。以前の記事も参照のこと。。。

◆新バージョン Raspbian の書き込み
http://www.raspberrypi.org/downloads/ から Raspbian のイメージファイル(2015-02-16-raspbian-wheezy.zip)をダウンロードし、Win32DiskImager (http://sourceforge.jp/projects/sfnet_win32diskimager/) により、microSD に書き込みます。
(とりあえず今回は4GBのmicroSDを使用しました。)

◆初期設定
書き込み後、最初の起動時に、コンフィグレーション画面が立ち上がりますので、

  microSDのパーティションの拡張。
1 Expand Filesystem

  タイムゾーンに日本(東京)を選択。
4 Internationalisation Options
->I2 Change Timezon
  ->Asia
    ->Tokyo

  キーボードレイアウトに日本語キーボードを選択。
4 Internationalisation Options
->I3 Change Keyboard Layout
  ->Generic 105-key (intl) PC
    ->Other
      ->Japanese
        ->Japanese - Japanese (OADG 109A)
    ->The default for the keyboard layout
      ->No compose key
        ->Yes

  オーバークロック(お好みで)
7 Overclock
->Medium

◆不要パッケージの削除

下記がインストール直後の状態です。1GB弱しか空きがありません。
$ df
Filesystem     1K-blocks    Used Available Use% Mounted on
rootfs           3671884 2479420    993104  72% /
/dev/root        3671884 2479420    993104  72% /
devtmpfs          218604       0    218604   0% /dev
tmpfs              44576     232     44344   1% /run
tmpfs               5120       0      5120   0% /run/lock
tmpfs              89140       0     89140   0% /run/shm
/dev/mmcblk0p1     57288   14720     42568  26% /boot
基本的には以前、に削除したのと同じパッケージを削除しました。(お好みでどうぞ)
何個か追加で削除してますが。(回路シミュレータの smartsim とか。。。)
(インストールされているパッケージは "dpkg -l" で確認できます。)
$ sudo apt-get autoremove -y wolfram-engine scratch sonic-pi
$ sudo apt-get autoremove -y python-minecraftpi python-pygame
$ sudo apt-get autoremove -y idle idle3
$ sudo apt-get autoremove -y netsurf-common dillo
$ sudo apt-get autoremove -y smartsim
$ sudo apt-get autoremove -y pistore debian-reference-common
$ sudo apt-get autoremove -y libraspberrypi-doc

$ sudo apt-get autoremove -y man manpages man-db
$ sudo apt-get autoremove -y git git-man
$ sudo apt-get autoremove -y galculator
$ sudo apt-get autoremove -y weston
$ sudo apt-get autoremove -y gdb gdbserver
$ rm -rf /home/pi/python_games/
$ sudo rmdir /usr/local/games/ /usr/games/

それなりに空きが出来たと思います。

$ df
Filesystem     1K-blocks    Used Available Use% Mounted on
rootfs           3671884 1770044   1702480  52% /
/dev/root        3671884 1770044   1702480  52% /
devtmpfs          218604       0    218604   0% /dev
tmpfs              44576     232     44344   1% /run
tmpfs               5120       0      5120   0% /run/lock
tmpfs              89140       0     89140   0% /run/shm
/dev/mmcblk0p1     57288   14720     42568  26% /boot

◆ファームウェア・カーネル/パッケージのアップデート
2015-02-16-raspbian-wheezy のカーネルバージョンは 3.18.7 のようです。
$ uname -r
3.18.7+
/boot の下を見てみると、デバイスツリーのファイル等が以前より増えています。
(あんまりデバイスツリー好きじゃないんですが、、、世の中の流れですね。。。)

ファームウェアのアップデートを行い、完了後リブートします。
$ sudo rpi-update
$ sudo reboot
リブート後、ちゃんとカーネルバージョンが変わっています。
$ uname -r
3.18.9+

古いバージョンのモジュールは不要なので、削除しておきます。
$ sudo rm -rf /lib/modules/3.18.7+/ /lib/modules/3.18.7-v7+/

サンプルプログラムも削除します。(お好みで。ビルドして一度サンプルを実行してみてもいいと思います。)
$ sudo rm -rf /opt/vc/src/hello_pi/

その他のパッケージもアップデートします。

$ sudo apt-get update
$ sudo apt-get upgrade

まだ半分くらいの空きがあります。
$ df
Filesystem     1K-blocks    Used Available Use% Mounted on
rootfs           3671884 1766000   1706524  51% /
/dev/root        3671884 1766000   1706524  51% /
devtmpfs          218644       0    218644   0% /dev
tmpfs              44584     244     44340   1% /run
tmpfs               5120       0      5120   0% /run/lock
tmpfs              89160       0     89160   0% /run/shm
/dev/mmcblk0p1     57288   14760     42528  26% /boot

◆sambaの初期設定
ネットワーク経由で Raspberry Pi とファイルのやりとりを行なうために、sambaの設定を行ないます。
(ホストマシンでクロスビルドしたカーネルイメージを持ってくるためです。)

$ sudo apt-get install samba chkconfig

    /etc/samba/smb.conf を編集。
[global]
dos charset = CP932
unix charset = UTF-8

ファイル末尾に以下を追加。
    : (略)
[pi]

path = /home/pi
writable = yes
guest ok = yes
browsable = yes
force user = pi
create mode = 0777
direcory mode = 0777

次回は 2015-02-16-raspbian-wheezy 用のLinuxカーネルを差し替えます。

演算子/errno/シグナル/システムコール 一覧表

プログラム、Linux 関連の各種テーブル早見表。

Linux カーネルのソースコードは↓下記サイトで確認可能。
  https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/

  https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/

表の作成は↓下記サイトにお世話になりました。
http://styleme.jp/tool/xls2html/

◆演算順序(C言語)

優先度 演算子 説明 評価順序
1 ( ) 括弧
[ ] 配列要素
. メンバ参照演算子
-> アロー演算子
2 & アドレス演算子
* 間接演算子
~ ビット反転
! 論理否定
+ プラス符号
- マイナス符号
++ インクリメント
-- デクリメント
sizeof サイズ
(cast) キャスト
3 * 乗算
/ 除算
% 剰余
4 + 加算
- 減算
5 << 左シフト
>> 右シフト
6 < より小さい
<= 以下
> より大きい
>= 以上
7 == 等しい
!= 等しくない
8 & ビット論理積
9 ^ ビット排他的論理和
10 | ビット論理和
11 && 論理積
12 || 論理和
13 ? : 三項演算子
14 = 代入演算子
*=
/=
%=
+=
-=
<<=
>>=
^=
&=
|=
15 , コンマ演算子

◆Linux errno
linux 3.19.3 の下記ファイルを参照し、作成。
- include/uapi/asm-generic/errno-base.h
- include/uapi/asm-generic/errno.h
- include/linux/errno.h

エラー番号 マクロ
コメント
1 EPERM Operation not permitted
2 ENOENT No such file or directory
3 ESRCH No such process
4 EINTR Interrupted system call
5 EIO I/O error
6 ENXIO No such device or address
7 E2BIG Argument list too long
8 ENOEXEC Exec format error
9 EBADF Bad file number
10 ECHILD No child processes
11 EAGAIN Try again
12 ENOMEM Out of memory
13 EACCES Permission denied
14 EFAULT Bad address
15 ENOTBLK Block device required
16 EBUSY Device or resource busy
17 EEXIST File exists
18 EXDEV Cross-device link
19 ENODEV No such device
20 ENOTDIR Not a directory
21 EISDIR Is a directory
22 EINVAL Invalid argument
23 ENFILE File table overflow
24 EMFILE Too many open files
25 ENOTTY Not a typewriter
26 ETXTBSY Text file busy
27 EFBIG File too large
28 ENOSPC No space left on device
29 ESPIPE Illegal seek
30 EROFS Read-only file system
31 EMLINK Too many links
32 EPIPE Broken pipe
33 EDOM Math argument out of domain of func
34 ERANGE Math result not representable
35 EDEADLK Resource deadlock would occur
36 ENAMETOOLONG File name too long
37 ENOLCK No record locks available
38 ENOSYS Function not implemented
39 ENOTEMPTY Directory not empty
40 ELOOP Too many symbolic links encountered
EAGAIN(11) EWOULDBLOCK Operation would block
42 ENOMSG No message of desired type
43 EIDRM Identifier removed
44 ECHRNG Channel number out of range
45 EL2NSYNC Level 2 not synchronized
46 EL3HLT Level 3 halted
47 EL3RST Level 3 reset
48 ELNRNG Link number out of range
49 EUNATCH Protocol driver not attached
50 ENOCSI No CSI structure available
51 EL2HLT Level 2 halted
52 EBADE Invalid exchange
53 EBADR Invalid request descriptor
54 EXFULL Exchange full
55 ENOANO No anode
56 EBADRQC Invalid request code
57 EBADSLT Invalid slot
EDEADLK(35) EDEADLOCK
59 EBFONT Bad font file format
60 ENOSTR Device not a stream
61 ENODATA No data available
62 ETIME Timer expired
63 ENOSR Out of streams resources
64 ENONET Machine is not on the network
65 ENOPKG Package not installed
66 EREMOTE Object is remote
67 ENOLINK Link has been severed
68 EADV Advertise error
69 ESRMNT Srmount error
70 ECOMM Communication error on send
71 EPROTO Protocol error
72 EMULTIHOP Multihop attempted
73 EDOTDOT RFS specific error
74 EBADMSG Not a data message
75 EOVERFLOW Value too large for defined data type
76 ENOTUNIQ Name not unique on network
77 EBADFD File descriptor in bad state
78 EREMCHG Remote address changed
79 ELIBACC Can not access a needed shared library
80 ELIBBAD Accessing a corrupted shared library
81 ELIBSCN .lib section in a.out corrupted
82 ELIBMAX Attempting to link in too many shared libraries
83 ELIBEXEC Cannot exec a shared library directly
84 EILSEQ Illegal byte sequence
85 ERESTART Interrupted system call should be restarted
86 ESTRPIPE Streams pipe error
87 EUSERS Too many users
88 ENOTSOCK Socket operation on non-socket
89 EDESTADDRREQ Destination address required
90 EMSGSIZE Message too long
91 EPROTOTYPE Protocol wrong type for socket
92 ENOPROTOOPT Protocol not available
93 EPROTONOSUPPORT Protocol not supported
94 ESOCKTNOSUPPORT Socket type not supported
95 EOPNOTSUPP Operation not supported on transport endpoint
96 EPFNOSUPPORT Protocol family not supported
97 EAFNOSUPPORT Address family not supported by protocol
98 EADDRINUSE Address already in use
99 EADDRNOTAVAIL Cannot assign requested address
100 ENETDOWN Network is down
101 ENETUNREACH Network is unreachable
102 ENETRESET Network dropped connection because of reset
103 ECONNABORTED Software caused connection abort
104 ECONNRESET Connection reset by peer
105 ENOBUFS No buffer space available
106 EISCONN Transport endpoint is already connected
107 ENOTCONN Transport endpoint is not connected
108 ESHUTDOWN Cannot send after transport endpoint shutdown
109 ETOOMANYREFS Too many references: cannot splice
110 ETIMEDOUT Connection timed out
111 ECONNREFUSED Connection refused
112 EHOSTDOWN Host is down
113 EHOSTUNREACH No route to host
114 EALREADY Operation already in progress
115 EINPROGRESS Operation now in progress
116 ESTALE Stale file handle
117 EUCLEAN Structure needs cleaning
118 ENOTNAM Not a XENIX named type file
119 ENAVAIL No XENIX semaphores available
120 EISNAM Is a named type file
121 EREMOTEIO Remote I/O error
122 EDQUOT Quota exceeded
123 ENOMEDIUM No medium found
124 EMEDIUMTYPE Wrong medium type
125 ECANCELED Operation Canceled
126 ENOKEY Required key not available
127 EKEYEXPIRED Key has expired
128 EKEYREVOKED Key has been revoked
129 EKEYREJECTED Key was rejected by service
130 EOWNERDEAD Owner died
131 ENOTRECOVERABLE State not recoverable
132 ERFKILL Operation not possible due to RF-kill
133 EHWPOISON Memory page has hardware error
512 ERESTARTSYS
513 ERESTARTNOINTR
514 ERESTARTNOHAND restart if no handler..
515 ENOIOCTLCMD No ioctl command
516 ERESTART_RESTARTBLOCK restart by calling sys_restart_syscall
517 EPROBE_DEFER Driver requests probe retry
518 EOPENSTALE open found a stale dentry
519
-

520
-

521 EBADHANDLE Illegal NFS file handle
522 ENOTSYNC Update synchronization mismatch
523 EBADCOOKIE Cookie is stale
524 ENOTSUPP Operation is not supported
525 ETOOSMALL Buffer or request is too small
526 ESERVERFAULT An untranslatable error occurred
527 EBADTYPE Type not supported by server
528 EJUKEBOX Request initiated, but will not complete before timeout
529 EIOCBQUEUED iocb queued, will get completion event


◆シグナル
linux 3.19.3 の下記ファイルを参照し、作成。
- include/uapi/asm-generic/signal.h

シグナル番号 マクロ 備考
1 SIGHUP
2 SIGINT
3 SIGQUIT
4 SIGILL
5 SIGTRAP
6 SIGABRT / SIGIOT
7 SIGBUS
8 SIGFPE
9 SIGKILL マスク不可
10 SIGUSR1
11 SIGSEGV
12 SIGUSR2
13 SIGPIPE
14 SIGALRM
15 SIGTERM
16 SIGSTKFLT
17 SIGCHLD
18 SIGCONT
19 SIGSTOP マスク不可
20 SIGTSTP
21 SIGTTIN
22 SIGTTOU
23 SIGURG
24 SIGXCPU
25 SIGXFSZ
26 SIGVTALRM
27 SIGPROF
28 SIGWINCH
29 SIGIO /*SIGLOST*/
SIGIO(29) SIGPOLL
30 SIGPWR
31 SIGSYS / SIGUNUSED

◆Linux システムコール
linux 3.19.3 の下記ファイルを参照し作成。
- arch/arm/include/uapi/asm/unistd.h

システムコール番号 シンボル
コメント
0 restart_syscall
1 exit
2 fork
3 read
4 write
5 open
6 close
7 - 7 was sys_waitpid
8 creat
9 link
10 unlink
11 execve
12 chdir
13 time
14 mknod
15 chmod
16 lchown
17 - 17 was sys_break
18 - 18 was sys_stat
19 lseek
20 getpid
21 mount
22 umount
23 setuid
24 getuid
25 stime
26 ptrace
27 alarm
28 - 28 was sys_fstat
29 pause
30 utime
31 - 31 was sys_stty
32 - 32 was sys_gtty
33 access
34 nice
35 - 35 was sys_ftime
36 sync
37 kill
38 rename
39 mkdir
40 rmdir
41 dup
42 pipe
43 times
44 - 44 was sys_prof
45 brk
46 setgid
47 getgid
48 - 48 was sys_signal
49 geteuid
50 getegid
51 acct
52 umount2
53 - 53 was sys_lock
54 ioctl
55 fcntl
56 - 56 was sys_mpx
57 setpgid
58 - 58 was sys_ulimit
59 - 59 was sys_olduname
60 umask
61 chroot
62 ustat
63 dup2
64 getppid
65 getpgrp
66 setsid
67 sigaction
68 - 68 was sys_sgetmask
69 - 69 was sys_ssetmask
70 setreuid
71 setregid
72 sigsuspend
73 sigpending
74 sethostname
75 setrlimit
76 getrlimit Back compat 2GB limited rlimit
77 getrusage
78 gettimeofday
79 settimeofday
80 getgroups
81 setgroups
82 select
83 symlink
84 - 84 was sys_lstat
85 readlink
86 uselib
87 swapon
88 reboot
89 readdir
90 mmap
91 munmap
92 truncate
93 ftruncate
94 fchmod
95 fchown
96 getpriority
97 setpriority
98 - 98 was sys_profil
99 statfs
100 fstatfs
101 - 101 was sys_ioperm
102 socketcall
103 syslog
104 setitimer
105 getitimer
106 stat
107 lstat
108 fstat
109 - 109 was sys_uname
110 - 110 was sys_iopl
111 vhangup
112 - 112 was sys_idle
113 syscall syscall to call a syscall!
114 wait4
115 swapoff
116 sysinfo
117 ipc
118 fsync
119 sigreturn
120 clone
121 setdomainname
122 uname
123 - 123 was sys_modify_ldt
124 adjtimex
125 mprotect
126 sigprocmask
127 - 127 was sys_create_module
128 init_module
129 delete_module
130 - 130 was sys_get_kernel_syms
131 quotactl
132 getpgid
133 fchdir
134 bdflush
135 sysfs
136 personality
137 - 137 was sys_afs_syscall
138 setfsuid
139 setfsgid
140 _llseek
141 getdents
142 _newselect
143 flock
144 msync
145 readv
146 writev
147 getsid
148 fdatasync
149 _sysctl
150 mlock
151 munlock
152 mlockall
153 munlockall
154 sched_setparam
155 sched_getparam
156 sched_setscheduler
157 sched_getscheduler
158 sched_yield
159 sched_get_priority_max
160 sched_get_priority_min
161 sched_rr_get_interval
162 nanosleep
163 mremap
164 setresuid
165 getresuid
166 - 166 was sys_vm86
167 - 167 was sys_query_module
168 poll
169 nfsservctl
170 setresgid
171 getresgid
172 prctl
173 rt_sigreturn
174 rt_sigaction
175 rt_sigprocmask
176 rt_sigpending
177 rt_sigtimedwait
178 rt_sigqueueinfo
179 rt_sigsuspend
180 pread64
181 pwrite64
182 chown
183 getcwd
184 capget
185 capset
186 sigaltstack
187 sendfile
188 - 188 reserved
189 - 189 reserved
190 vfork
191 ugetrlimit SuS compliant getrlimit
192 mmap2
193 truncate64
194 ftruncate64
195 stat64
196 lstat64
197 fstat64
198 lchown32
199 getuid32
200 getgid32
201 geteuid32
202 getegid32
203 setreuid32
204 setregid32
205 getgroups32
206 setgroups32
207 fchown32
208 setresuid32
209 getresuid32
210 setresgid32
211 getresgid32
212 chown32
213 setuid32
214 setgid32
215 setfsuid32
216 setfsgid32
217 getdents64
218 pivot_root
219 mincore
220 madvise
221 fcntl64
222 - 222 for tux
223 - 223 is unused
224 gettid
225 readahead
226 setxattr
227 lsetxattr
228 fsetxattr
229 getxattr
230 lgetxattr
231 fgetxattr
232 listxattr
233 llistxattr
234 flistxattr
235 removexattr
236 lremovexattr
237 fremovexattr
238 tkill
239 sendfile64
240 futex
241 sched_setaffinity
242 sched_getaffinity
243 io_setup
244 io_destroy
245 io_getevents
246 io_submit
247 io_cancel
248 exit_group
249 lookup_dcookie
250 epoll_create
251 epoll_ctl
252 epoll_wait
253 remap_file_pages
254 - 254 for set_thread_area
255 - 255 for get_thread_area
256 set_tid_address
257 timer_create
258 timer_settime
259 timer_gettime
260 timer_getoverrun
261 timer_delete
262 clock_settime
263 clock_gettime
264 clock_getres
265 clock_nanosleep
266 statfs64
267 fstatfs64
268 tgkill
269 utimes
270 arm_fadvise64_64
271 pciconfig_iobase
272 pciconfig_read
273 pciconfig_write
274 mq_open
275 mq_unlink
276 mq_timedsend
277 mq_timedreceive
278 mq_notify
279 mq_getsetattr
280 waitid
281 socket
282 bind
283 connect
284 listen
285 accept
286 getsockname
287 getpeername
288 socketpair
289 send
290 sendto
291 recv
292 recvfrom
293 shutdown
294 setsockopt
295 getsockopt
296 sendmsg
297 recvmsg
298 semop
299 semget
300 semctl
301 msgsnd
302 msgrcv
303 msgget
304 msgctl
305 shmat
306 shmdt
307 shmget
308 shmctl
309 add_key
310 request_key
311 keyctl
312 semtimedop
313 vserver
314 ioprio_set
315 ioprio_get
316 inotify_init
317 inotify_add_watch
318 inotify_rm_watch
319 mbind
320 get_mempolicy
321 set_mempolicy
322 openat
323 mkdirat
324 mknodat
325 fchownat
326 futimesat
327 fstatat64
328 unlinkat
329 renameat
330 linkat
331 symlinkat
332 readlinkat
333 fchmodat
334 faccessat
335 pselect6
336 ppoll
337 unshare
338 set_robust_list
339 get_robust_list
340 splice
341 arm_sync_file_range sync_file_range2
342 tee
343 vmsplice
344 move_pages
345 getcpu
346 epoll_pwait
347 kexec_load
348 utimensat
349 signalfd
350 timerfd_create
351 eventfd
352 fallocate
353 timerfd_settime
354 timerfd_gettime
355 signalfd4
356 eventfd2
357 epoll_create1
358 dup3
359 pipe2
360 inotify_init1
361 preadv
362 pwritev
363 rt_tgsigqueueinfo
364 perf_event_open
365 recvmmsg
366 accept4
367 fanotify_init
368 fanotify_mark
369 prlimit64
370 name_to_handle_at
371 open_by_handle_at
372 clock_adjtime
373 syncfs
374 sendmmsg
375 setns
376 process_vm_readv
377 process_vm_writev
378 kcmp
379 finit_module
380 sched_setattr
381 sched_getattr
382 renameat2
383 seccomp
384 getrandom
385 memfd_create
386 bpf
387 execveat

シェルスクリプト/Makefile/LKM 等サンプル

各種プログラム、Makefile サンプル。

◆シェルサンプル
shell/test.sh
#!/bin/bash

# ./test.sh 1 "2 3" 4

TMPFILE=/tmp/test

init() {
        if [ -f ${TMPFILE} ]; then
                rm -f ${TMPFILE}
        elif [ -e ${TMPFILE} ]; then
                exit 1
        fi

        touch ${TMPFILE}
        if [ $? -ne 0 ]; then
                exit 1
        fi
}

main() {
        local arg
        local i=0

        for arg in "$@"; do
                echo ${arg} >> ${TMPFILE}
                list[${i}]=${arg}
                i=$((${i} + 1))
        done

        i=0
        while [ ${i} -lt ${#list[@]} ]; do
                echo ${list[${i}]}
                i=$((${i} + 1))
        done

        list2=(`cat ${TMPFILE}`)
        for i in "${list[@]}"; do
                echo ${i}
        done

        while read line; do
                echo ${line}
        done < ${TMPFILE}
}

init
main "$@"

◆Makefileサンプル
csrc/Makefile

CC=gcc
CFLAGS ?= -O2 -Wall
LDFLAGS ?=

OBJS=main.o
TARGET=test

.PHONY: all clean
all: $(TARGET)

$(TARGET): $(OBJS)
        $(CC) -o $@ $^ $(LDFLAGS)

debug:
        $(MAKE) -C . CFLAGS="$(CFLAGS) -DDEBUG"

.c.o:
        $(CC) -c $< $(CFLAGS)

clean:
        $(RM) $(TARGET) $(OBJS)
上記サンプル↓
$ curl -O http://sstea.blog.jp/raspi/csrc/Makefile

csrc/main.c

#include <stdio.h>

#ifdef DEBUG
#define DEBUG(...)    printf("<DEBUG> " __VA_ARGS__)
#else /* !DEBUG */
#define DEBUG(...)    do { } while (0)
#endif /* !DEBUG */

int main(int argc, char **argv)
{
    DEBUG("hello\n");
    return 0;
}

◆Linux LKM(ローダブルカーネルモジュール)サンプル
kbuild/Makefile (KDIR は場合によっては任意に変更)
obj-y := test/

KDIR ?= /lib/module/$(shell uname -r)/build
PWD := $(shell pwd)

EXTRA_CFLAGS =

modules:
    make -C $(KDIR) M=$(PWD) V=1 modules

clean:
    make -C $(KDIR) M=$(PWD) V=1 clean
上記サンプル↓
$ curl -O http://sstea.blog.jp/raspi/kbuild/Makefile

kbuild/test/Makefile
obj-m:= test.o

test-objs := test_base.o
test-objs に.oファイルを複数指定することで、複数ファイルから1つのローダブルカーネルモジュール(.koファイル)を作成可能。

kbuild/test/test_base.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

static int __init test_init(void)
{
    printk("test_init\n");
    return 0;
}
module_init(test_init);

static void __exit test_exit(void)
{
    printk("test_exit\n");
}
module_exit(test_exit);

はじめてのスマホ(環境構築週間)

◆Xperia Z3 スマホ環境、構築中...

とりあえずスマホを買ったので、買った当日中に、最低限、電話とメールだけは試行しておきました。
仕事に支障出るとまずいので。
あと、Wifi の設定。
家のネットインフラはほぼ有線オンリーなんで、追々、調べて設定見直します。

次に手を付けたのが、通信関連とバッテリー関連。
一応、一ヶ月の通信量に制限かけられてるので、何をしたらどれくらいの通信量になるか、感覚を知るために。
バッテリーも、何をしたらどれくらい減るものなのか、感覚を知るために。
(ガラケー生活が長かったので、、、)

いろいろ調べた結果、「通信量モニター」というのと「Battery Mix」というのを入れてみる。

特に深くは考えずにアンチウィルスソフトはAVGのを入れときました。
ファイラーは何個見てみましたがESファイルエクスプローラーが自分には合いそうと思ったのでこれを入れました。

いろいろ不要そうなプリインストールアプリはアンインストール、または無効化。

◆リモートデスクトップAndroidアプリ
あとはいざと言う時のために、外から家PCに繋ぎたいので、リモートデスクトップアプリを選定中。。。

リモートデスクトップ用のポート番号は変更済み。ルータのポートマッピングも設定済み。
他のPCからリモートデスクトップ出来るのは確認済みの環境。

以下、試してみた感想。
ホスト側でVLCで動画を再生してみてリモートデスクトップしてどれくらいリアルタイム性があるのか。

- Microsoft Remote Desktop
  本命。だったのだが、たまにカクツク。
  音も鳴るが、ちょいちょい飛ぶ。
  リモート中はホストマシンは操作できなくなる。(ログイン画面になる)

- Chrome リモート デスクトップ
  次の本命。結構サクサク動く。
  ポートとか空けてなくても外から普通に繋げそう。
  ただ、音が鳴らない。。。
  リモート中もホストマシンは変わらず操作できる。
  あと、家PCはデュアルディスプレイなので、リモート画面が横に凄く長い。
  (二画面並んだ画面が一画面としてスマホに表示される)

- PocketCloud リモートデスクトップ
  あまり印象に残っていない。
  カクツいたので、自分の中では候補から早々に消えた。

- Splashtop 2 Remote Desktop
  サクサク動く。音も鳴る。これいい!!
  リモート中もホストマシンは変わらず操作できる。
  「インターネット経由でのアクセス」は有料プラグイン(?)で対応、みたいな事書いてあったが、
  IPアドレスの入力設定をしたら、3G経由でも普通に繋がった。
  (ただし、よそのwifi(公衆無線LANスポットとか)からは無理でした。
    → 後日、VPN 環境を構築することで、公衆無線LANスポットからも繋がりました。)

聞いたことないソフトだったがSplashtopが第一候補。次点がGoogleのやつ、の二択になりました。

Raspberry Pi のディスクイメージをバックアップする

ここまで環境設定をいろいろやってきました。

しかし、機能的には何も嬉しい事をしてません。
ここからは、いろいろインストールしたりとかしようと思っていますが、一旦ここでこの環境をセーブしておきたいと思います。

何か失敗してやり直したいと思うかも知れませんし、ファイルシステム破損してしまった時とかに、再度環境構築するのは面倒くさいですし、、、

本当のところは、現在使っているclass 4のmicro SDカードからclass 10のmicro SDカードに引越してみて、起動時間がどうなるか見てみたい、というのが一番だったりするのですが。。。

単純にディスクイメージを吸い出すだけでもいいのですが、それだとmicroSDのサイズのディスクイメージが出来てしまいます。
(32GBのmicroSDを使用していると使用/未使用を問わず32GBのディスクイメージファイルになります。)
圧縮すれば未使用部分は縮むのですが、それでも個人的にはディスクイメージファイル自体に縮んでいて欲しいのです。(容量の小さいmicroSDに引越し出来ないし)

ディスクイメージの引越しについて、ディスクイメージを弄くり倒して行なう別解を用意しました。
(ホストマシンに直接カードリーダが繋げない、gparted使えない、などの環境でも引越し可能なはずです。)

◆ rootfs パーティションを縮小
まず、Linux ホストマシンに Raspberry Pi で使用していたmicroSDを挿します。
以前に Linux Mint の仮想環境をVirtualBoxで作成したので、今回はそれを使おうと思います。

Linux ホストマシンで gparted を使用します。ないならインストールします。
$ sudo apt-get install gparted

gparted を使用し、Raspberry Pi の rootfs パーティション(2個目のパーティション)を適当なサイズに縮小します。

ss_vbox_gparted

◆ ディスクイメージの出力
Raspberryp Pi 用microSD が /dev/sdb として認識されているものとして以下、記載します。

$ sudo fdisk -l /dev/sdb
とすると、
デバイス ブート      始点        終点     ブロック  Id  システム
/dev/sdb1            2048      262143      130048    6  FAT16
/dev/sdb2          262144     5439487     2588672   83  Linux
というように表示されたとします。
ここで、二個目のパーティションの終点の数値が最終セクタ番号になります。

なので、サイズとしては +1 した値を指定します。
$ sudo dd if=/dev/sdb of=/media/sf_shared/raspi.img count=5439488 bs=512
これでディスクイメージファイルが /media/sf_shared/raspi.img として出力されます。

◆ディスクイメージをマウントする
$ sudo kpartx -v -a /media/sf_shared/raspi.img
とすると、下記のような表示が出ると思います。
この時に表示された loop デバイスを使用します。(この例では loop0 を使用します)
add map loop0p1 (252:0): 0 260096 linear /dev/loop0 2048
add map loop0p2 (252:1): 0 5177344 linear /dev/loop0 262144

下記のようにすることで、Raspberry Pi 用のディスクイメージの rootfs パーティションを /mnt/ にマウントできます。
$ sudo mount /dev/mapper/loop0p2 /mnt/
◆ディスクイメージの中身を編集
せっかくマウントしたので、中をいじってみたいと思います。

bashの履歴ファイルを削除しておきましょう。
$ rm /mnt/home/pi/.bash_history
$ touch /mnt/home/pi/.bash_history

キャッシュもたぶん消しても大丈夫と思います。
(debconf ディレクトリは残しておいた方がよさそうです。apt 時に何かワーニング出ました。。。)
$ sudo rm -rf /mnt/var/cache/*
$ sudo mkdir /mnt/var/cache/debconf/

ディスクイメージの圧縮時に圧縮率が高まるように、未使用領域をゼロ埋めしておきます。
(下記のように実行することで空き容量がなくなるまで、中身が0で埋まったdummyというファイルを作成しています)
$ sudo dd if=/dev/zero of=/mnt/dummy bs=4096
$ sudo rm /mnt/dummy

◆ディスクイメージをアンマウントする

$ sudo umount /mnt/
$ sudo kpartx -d /media/sf_shared/raspi.img

◆おまけ1

Win32DiskImager で普通にディスクイメージを吸い出してもいいと思います。
上記を参考に、応用すれば必要部分のみのディスクイメージにすることが出来ます。

gparted は、コマンドラインで起動する場合、パラメータにデバイス意外にもイメージファイルを指定することができます。(イメージファイルの場合は、リサイズは出来ませんが...)
$ sudo gparted イメージファイル

また、下記のようにすることで、イメージファイルを必要部分のみ切り出すことができます。
$ sudo dd if=イメージ1 of=イメージ2 count=必要セクタ数 bs=512

◆おまけ2

ちにみにclass 4のmicro SDカードからclass 10のmicro SDカードに変えてみましたが、起動時間は3秒ほど早くなっただけでした。(もう少し期待してたんですが。)


今回作成したディスクイメージは dd コマンド、または Win32DiskImager で microSD に書き込むことで、環境をいつでもリストア出来ます。

次回からは、心おきなく Raspberry Pi をいじくることが出来ますね。

プライバシーポリシー
当サイトでは、Googleを含む第三者配信事業者や広告ネットワークが配信する広告を掲載しています。
当サイトでは、アクセス情報に基づいた適切な広告表示、及びトラフィックデータ収集のためにCookieを使用しています。
ユーザーはCookieの無効化により、これらの情報の提供を拒否する事ができます。
スポンサーリンク
記事検索
スポンサーリンク