みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

OpenCV3 ArUcoサンプルのビルド

OpenCV3ではopencv_contributeというリポジトリOpenCVを使用して作成されたライブラリがモジュールとして収録されている。 この中にAR向けマーカー認識ライブラリのArUcoがある。

opencv_contrib/modules/arucoにはCMakeLists.txtが存在するが、これはArUcoそのものをビルドするためのものであるため、 サンプルのビルドには使用できない。

次のファイルをopencv_contrib/modules/aruco/samplesに置く。

ここでは、create_board.cppcalibrate_camera.cppをビルドしている。

サンプルの実行例を下記に示す。

$ ./create_board -w=4 -h=3 -d=10 -l=100 -s=30 -m=30 --si test.png
$ ./calibrate_camera  -w=4 -h=3 -d=10 -l=0.03 -s=0.01 --ci=1 ./test.xml

パラメータは適当。

create_boardキャリブレーションに使用するマーカーボードを作成。 calibrate_cameraキャリブレーションを実行する。

create_boardのサイズ指定がピクセル単位なのに対し、calibrate_cameraのサイズ指定はメートル単位となっている。 これはキャリブレーションを印刷したボードで行うことを想定しているためだろう。

DragonBoard 410cでYocto

DragonBoard 410cを借りることができた。 実はかなり前から借りていたのだが、個人的に忙しく触る時間が作れないでいた。

このボードは、RaspberryPi3よりも前に出回っていて、かつ、Cortext-A53をコアに搭載しており、WifiBluetoothオンボード。 借りたボードは技適取得済みという、なんとまぁ、RPi3より前に手元にあったのなら、なぜ、RPi3よりも前に遊び倒していないのかという代物。

しかも!配布されているLinuxOSのイメージはAArch64!なので、現状32bit版OSしか配布されていないRPi3よりも先に64bitの世界が体験できる。

オフィシャルで配布されているOSは、AndroidLinux(Linaro)だが、もちろんここではYoctoのイメージを焼いてみる。

イメージの作成

ここでYoctoのイメージの作成手順が公開されている。

筆者はUbuntu 15.04で作業している。

依存パッケージ

参考にしたサイトでは、以下のパッケージをインストールする様に書いてあるが、 筆者の環境では、明示的にインストールした覚えがないがインストール済みになっていた。

$ sudo apt-get install git
$ sudo apt-get install whiptail
$ sudo apt-get install dialog

それ以外では、Yoctoを使用するための最低限の環境をインストールする必要がある。

$ sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib \
    build-essential chrpath libsdl1.2-dev xterm

repoのインストール

DragonBoardのYocto環境の構築ではrepoコマンドを使用している。

repoは複数のgitのリポジトリを一括で管理できるコマンドで、主にAndroidの開発で見かける事が多いが、一部他のメーカーのボードでYocto環境を構築する際にも使用されている。

$ mkdir -p ${HOME}/bin
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ${HOME}/bin/repo
$ chmod a+x ${HOME}/bin/repo
$ export PATH=${HOME}/bin:${PATH}

Ubuntu 15.04では、${HOME}/.profileで コード 1 の様に記述されているため、 ${HOME}/binが存在すると、自動的にPATHに含まれる様になっているようだ。

コード 1: .profile(抜粋)
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

作業ディレクト

筆者は${HOME}/work/yoctoで作業している。

$ cd ${HOME}/work/yocto
$ mkdir oe-qcom && cd oe-qcom
$ repo init -u https://github.com/96boards/oe-rpb-manifest.git -b jethro
$ repo sync
$ source setup-environment build

bitbake

基本的に、oe-qcomの場合は、local.confやbblayers.confの設定は、 setup-environmentがやってくれているため、そのままbitbakeを実行することができる。

$ bitbake rpb-console-image

イメージの書き込み

tmp-rpb-glibc/deploy/images/dragonboard-410cに作られた次の2つのファイルを書き込む。

  1. rpb-console-image-dragonboard-410c.ext4.gz
  2. boot-dragonboard-410c.img

fastbootのインストール

イメージの書き込みにはfastbootを使用する。Ubuntu 15.04では次のコマンドを実行してインストールする。

$ sudo apt-get install -y android-tools-fastboot

ボードの電源を切った状態で、J4コネクタ(図 1)にUSBケーブルを接続し、PCのUSBポートと接続します。次に S4ボタン(図 2)を押しながら電源を入れ、数秒後に離す。

f:id:mickey_happygolucky:20160605173942j:plain

図 1:J4コネクタ

f:id:mickey_happygolucky:20160605173952j:plain

図 2:S4ボタン

以下のコマンドを実行して、fastbootからデバイスが見えているか確認する。

$ sudo fastboot devices

バイスが見えている場合は、以下のように8桁の16進数が表示される。

$ sudo fastboot devices
11e02318    fastboot

ブートローダのダウンロードとパーティション設定

eMMCのパーティション設定を行うためにここからブートローダのファイルをダウンロードする必要がある。

wgetで取得する場合は、以下のコマンドを実行する。

$ wget http://builds.96boards.org/releases/dragonboard410c/linaro/rescue/latest/dragonboard410c_bootloader_emmc_linux-46.zip

zip形式で圧縮されているので、次のコマンドで解凍する。

$ unzip -d bootloader dragonboard410c_bootloader_emmc_linux-46.zip

PCとボードが接続された状態で、解凍したファイルの中にあるflashallを実行する。

$ cd bootloader
$ sudo ./flashall

イメージの書き込み

次のコマンドを実行し、ルートファイルシステムカーネルイメージを書き込む。

$ cd ${HOME}/work/yocto/oe-qcom/build/tmp-rpb-glibc/deploy/images/dragonboard-410c
$ gzip -d < rpb-console-image-dragonboard-410c.ext4.gz > rpb-console-image-dragonboard-410c.ext4
$ sudo fastboot flash rootfs rpb-console-image-dragonboard-410c.ext4
$ sudo fastboot flash boot boot-dragonboard-410c.img

起動

電源を切り、J4コネクタからUSBのケーブルを抜いて、電源を再度投入するとOSが起動する。(図 3)

f:id:mickey_happygolucky:20160605173937j:plain

図 3:ブート画面

recipetoolの使い方(yoctoでmjpg-streamer)

raspberrypiにUVCカメラをつけて、HTTPでストリーミングを行いたいと考えた。 mjpg-streamerを使用することにしたが、 mjpg-streamerはレシピ化されていないため、レシピを自作する必要があった。^1

recipetoolの使用

レシピを作成する場合、ゼロから作成することもできるが、recipetoolを使用して雛形を作成することができる。

recipetoolを実行するにはbitbakeと同様にoe-init-build-envをsourceコマンド等で読み込んでおく必要がある。 作業ディレクトリは%HOME/work/yocto/rpiとする。

$ cd %HOME/work/yocto/rpi
$ source poky/oe-init-build-env build_webcam

mjpg-streamerのレシピを作成するには以下のコマンドを実行する。

$ recipetool create -o mjpg-streamer_git.bb --src-subdir=mjpg-streamer-experimental https://github.com/jacksonliam/mjpg-streamer.git

recipatoolはプロジェクトの中身を解析して、そのプロジェクトで使用しているautomakeやcmakeなどのビルドシステムに対応したレシピの雛形を生成する。 デフォルトではビルドシステムのソースディレクトリ=プロジェクトのルートディレクトリとして解析を行うが、mjpg-streamerではmjpg-streamer-experimentalがソースディレクトリとなっている。 その場合は--src-subdir=mjpg-streamer-experimentalオプションでソースディレクトリを指定することができる。

生成されたレシピは コード 1 のようになる。

コード 1: recipetoolで生成されたレシピ
# Recipe created by recipetool
# This is the basis of a recipe and may need further editing in order to be fully functional.
# (Feel free to remove these comments when editing.)
#
# WARNING: the following LICENSE and LIC_FILES_CHKSUM values are best guesses - it is
# your responsibility to verify that the values are complete and correct.
#
# NOTE: multiple licenses have been detected; if that is correct you should separate
# these in the LICENSE value using & if the multiple licenses all apply, or | if there
# is a choice between the multiple licenses. If in doubt, check the accompanying
# documentation to determine which situation is applicable.
LICENSE = "GPLv2 Unknown"
LIC_FILES_CHKSUM = "file://LICENSE;md5=751419260aa954499f7abaabaa882bbe \
                    file://www/LICENSE.txt;md5=713496289346a6c1c265f0e1f615ecd0"

SRC_URI = "git://github.com/jacksonliam/mjpg-streamer.git;protocol=https"

# Modify these as desired
PV = "1.0+git${SRCPV}"
SRCREV = "${AUTOREV}"

S = "${WORKDIR}/git/${BPN}-experimental"

# NOTE: unable to map the following CMake package dependencies: OpenCV Numpy Gphoto2
# NOTE: the following library dependencies are unknown, ignoring: v4l2
#       (this is based on recipes that have previously been built and packaged)
DEPENDS = "libjpeg-turbo libsdl"

inherit cmake python-dir

# Specify any options you want to pass to cmake using EXTRA_OECMAKE:
EXTRA_OECMAKE = ""

mjpg-streamerはcmakeでビルドしているためinherit cmakeとなっている。 その他、依存関係なども自動的に解決されている。

レシピのビルド

生成されたレシピがビルドできるかどうかbitbakeを実行してみる。

meta-webcamの作成

recipetoolで生成したmjpg-streamer_git.bbはビルドディレクトリである%HOME/work/yocto/rpi/build_webcamに格納されている。 これはどのレイヤにも属していない状態であるため、bitbakeの対象にならない。 そこで、作業用のレイヤmeta-webcamを作成し、mjpg-streamer_git.bbを含めるようにする。

下記の手順で作成する。

$ cd $HOME/work/yocto/rpi/build_webcam
$ mkdir -p $HOME/work/yocto/rpi/poky/meta-webcam/conf
$ mkdir -p $HOME/work/yocto/rpi/poky/meta-webcam/recipes-multimedia/mjpg-streamer
$ mv ./mjpg-streamer_git.bb $HOME/work/yocto/rpi/poky/meta-webcam/recipes-multimedia/mjpg-streamer
$ cat << 'EOF' > $HOME/work/yocto/rpi/poky/meta-webcam/conf/layer.conf
# We have a conf and classes directory, append to BBPATH
BBPATH .= ":${LAYERDIR}"

# We have a recipes directory containing .bb and .bbappend files, add to BBFILES
BBFILES += "${LAYERDIR}/recipes*/*/*.bb \
            ${LAYERDIR}/recipes*/*/*.bbappend"

BBFILE_COLLECTIONS += "webcam"
BBFILE_PATTERN_webcam := "^${LAYERDIR}/"
BBFILE_PRIORITY_webcam = "10"

LAYERDEPENDS_webcam = "core"
EOF

レイヤの構成は下記のツリーの様になる。

meta-webcam
├── conf
│   └── layer.conf
└── recipes-multimedia
    └── mjpg-streamer
        └── mjpg-streamer_git.bb

bblayers.conf

bblayers.confはbitbakeがビルド対象とするレイヤを定義する。

以下の手順で、bblayers.confの内容を置き換える。

$ cd $HOME/work/yocto/rpi/build_webcam
$ mv ./conf/bblayers.conf ./conf/bblayers.conf.bak
$ cat << 'EOF' > ./conf/bblayers.conf
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"

BBPATH = "${TOPDIR}"
BBFILES ?= ""

LAYERSTOP = "${TOPDIR}/.."

BBLAYERS ?= " \
  ${LAYERSTOP}/poky/meta \
  ${LAYERSTOP}/poky/meta-poky \
  ${LAYERSTOP}/poky/meta-yocto-bsp \
  ${LAYERSTOP}/poky/meta-raspberrypi \
  ${LAYERSTOP}/poky/meta-webcam \
  "
EOF

local.conf

local.confは生成されたそのままの状態では、qemux86向けのイメージを作成するようになっているため、 raspberrypi向けのイメージが作成されるようにする。

コード 2 の内容をlocal.confの先頭の方に追加する。

コード 2: local.conf(抜粋)
MACHINE ?= "raspberrypi"
BB_NUMBER_THREADS ?= "${@oe.utils.cpu_count()}"
PARALLEL_MAKE ?= "-j ${@oe.utils.cpu_count()}"
GPU_MEM = "128"
DL_DIR ?= "${HOME}/work/yocto/downloads"

IMAGE_INSTALL_append = " mjpg-streamer"

bitbake実行

$ cd $HOME/work/yocto/rpi/build_webcam
$ bitbake mjpg-streamer

この時点でエラーが発生しなければ、ビルドまでは成功している。

以下の手順で結果を確認する。

$ cd tmp/work/arm1176jzfshf-vfp-poky-linux-gnueabi/mjpg-streamer/1.0+gitAUTOINC+2bd6f2c28d-r0/
$ tree ./image

treeの結果を以下に示す。

./image
└── usr
    ├── bin
    │   └── mjpg_streamer
    ├── lib
    │   └── mjpg-streamer
    │       ├── input_file.so
    │       ├── input_http.so
    │       ├── input_uvc.so
    │       ├── output_file.so
    │       ├── output_http.so
    │       ├── output_rtsp.so
    │       ├── output_udp.so
    │       └── output_viewer.so
    └── share
        └── mjpg-streamer
            └── www
                ├── JQuerySpinBtn.css
                ├── JQuerySpinBtn.js
                ├── LICENSE.txt
                ├── bodybg.gif
                ├── cambozola.jar
                ├── control.htm
                ├── example.jpg
                ├── favicon.ico
                ├── favicon.png
                ├── fix.css
                ├── functions.js
                ├── index.html
                ├── java.html
                ├── java_control.html
                ├── java_simple.html
                ├── javascript.html
                ├── javascript_motiondetection.html
                ├── javascript_simple.html
                ├── jquery.js
                ├── jquery.rotate.js
                ├── jquery.ui.core.min.js
                ├── jquery.ui.custom.css
                ├── jquery.ui.tabs.min.js
                ├── jquery.ui.widget.min.js
                ├── rotateicons.png
                ├── sidebarbg.gif
                ├── spinbtn_updn.gif
                ├── static.html
                ├── static_simple.html
                ├── stream.html
                ├── stream_simple.html
                ├── style.css
                └── videolan.html

無事にビルドおよび、ローカルへのインストールは成功している。 しかし、このままではOSイメージのRootFSへ反映されない。

インストールされたファイルをRootFSへ反映されるようにするためには、 レシピでFILES_${PN}を定義する。

また、bitbakeした時にLicense関連でエラーが発生しているので、GPLv2 UnknownからGPLv2に変更する。

それらの修正を行った、一応の完成版のmjpg-streamer_git.bbを lst:mjpg_streamer_git_bb に示す。

コード 3: mjpg-streamer\_git.bb(完成版)
# Recipe created by recipetool
# This is the basis of a recipe and may need further editing in order to be fully functional.
# (Feel free to remove these comments when editing.)
#
# WARNING: the following LICENSE and LIC_FILES_CHKSUM values are best guesses - it is
# your responsibility to verify that the values are complete and correct.
#
# NOTE: multiple licenses have been detected; if that is correct you should separate
# these in the LICENSE value using & if the multiple licenses all apply, or | if there
# is a choice between the multiple licenses. If in doubt, check the accompanying
# documentation to determine which situation is applicable.
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://LICENSE;md5=751419260aa954499f7abaabaa882bbe \
                    file://www/LICENSE.txt;md5=713496289346a6c1c265f0e1f615ecd0"

SRC_URI = "git://github.com/jacksonliam/mjpg-streamer.git;protocol=https"

# Modify these as desired
PV = "1.0+git${SRCPV}"
SRCREV = "${AUTOREV}"

S = "${WORKDIR}/git/${BPN}-experimental"

# NOTE: unable to map the following CMake package dependencies: OpenCV Numpy Gphoto2
# NOTE: the following library dependencies are unknown, ignoring: v4l2
#       (this is based on recipes that have previously been built and packaged)
DEPENDS = "libjpeg-turbo libsdl"

inherit cmake python-dir

# Specify any options you want to pass to cmake using EXTRA_OECMAKE:
EXTRA_OECMAKE = ""

FILES_${PN} = "${bindir}/* \
           ${libdir}/* \
           ${datadir}/* \
           ${sysconfdir}* \
        "

イメージの作成

以下のコマンドを実行してOSイメージを作成する。

$ bitbake rpi-basic-image

イメージの書き込み

ddコマンドでrpi-basic-image-raspberrypi.rpi-sdimgをSDカードに書き込む。

sudo dd if=tmp/deploy/images/raspberrypi/rpi-basic-image-raspberrypi.rpi-sdimg of=/dev/sdb bs=40M

実行

UVCカメラを接続したraspberrypiをSDカードのイメージで起動する。

ログインしたあと、以下のコマンドでmjpg-streamerを実行する。

mjpg_streamer -i "input_uvc.so -y" -o "output_http.so -w /usr/share/mjpg-streamer/www"

ブラウザでhttp://XXX.XXX.XXX.XXX:8080/?action=streamにアクセスして、カメラの映像が表示されれば成功。

XXX.XXX.XXX.XXXはraspberrypiのIPアドレス

raspberrypi2でMPDサーバ その2

raspberrypi2+DACでMPDサーバを作成する。

今回は作成済みレイヤの使用方法。

レイヤを作成する方法はこちら

機能(おさらい)

  • windows10で共有しているフォルダから音楽ファイルを参照
  • MPDサーバで音楽ファイルを再生
  • SYSTEMDを使用
  • ネットワーク設定にはconnmanを使用

DAC(おさらい)

今回はこのDACを使用する。

システム構成(おさらい)

ネットワークを含めたシステムの構成を 図 1 に示す。

f:id:mickey_happygolucky:20160524012104p:plain

図 1:システム構成

yocto環境

作業に使用するレイヤのブランチとバージョンを 表 1 に示す。 各レイヤは下記のブランチを取得し作業する。

作業に使用するレイヤのブランチとバージョンを 表 1 に示す。

表 1: レイヤのブランチとバージョン

レイヤ ブランチ バージョン URL
poky krogoth 2.1 git://git.yoctoproject.org/poky.git
meta-openembedded krogoth 2.1 git://git.openembedded.org/meta-openembedded
meta-raspberrypi master - git://git.yoctoproject.org/meta-raspberrypi
meta-hifiberry-rpi master - https://github.com/mickey-happygolucky/meta-hifiberry-rpi.git
meta-mpd-server master - https://github.com/mickey-happygolucky/meta-mpd-server.git

作業ディレクトリ

作業は~/work/yocto/rpiで行う。

ベース環境の作成

ベース環境の手順を示す。

  1. 作業ディレクトリ(\~/work/yocto/rpi)の作成
  2. pokyのダウンロード
  3. meta-openembeddedのダウンロード
  4. meta-raspberrypiのダウンロード
  5. meta-hifiberryp-rpiのダウンロード
  6. meta-mpd-serverのダウンロード

下記のように実行する。

$ mkdir mkdir -p ~/work/yocto/rpi && cd ~/work/yocto/rpi
$ git clone git://git.yoctoproject.org/poky.git -b krogoth && cd poky
$ git clone git://git.openembedded.org/meta-openembedded -b krogoth
$ git clone git://git.yoctoproject.org/meta-raspberrypi
$ git clone https://github.com/mickey-happygolucky/meta-hifiberry-rpi.git
$ git clone https://github.com/mickey-happygolucky/meta-mpd-server.git

bitbakeの準備

次のコマンドを実行し、bitbakeするために必要な設定を行う。

$ cd ~/work/yocto/rpi
$ source poky/oe-init-build-env build

bblayers.conf

bblayers.confはbitbakeがビルド対象とするレイヤを定義する。

MPDサーバをビルドするため、自動生成されたbblayers.confを コード 1 の内容にまるごと置き換える。

コード 1: bblayers.conf
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"

BBPATH = "${TOPDIR}"
BBFILES ?= ""

LAYERSTOP = "${TOPDIR}/.."

BBLAYERS ?= " \
  ${LAYERSTOP}/poky/meta \
  ${LAYERSTOP}/poky/meta-poky \
  ${LAYERSTOP}/poky/meta-yocto-bsp \
  ${LAYERSTOP}/poky/meta-raspberrypi \
  ${LAYERSTOP}/poky/meta-mpd-server \
  ${LAYERSTOP}/poky/meta-hifiberry-rpi \
  ${LAYERSTOP}/poky/meta-openembedded/meta-oe \
  ${LAYERSTOP}/poky/meta-openembedded/meta-python \
  ${LAYERSTOP}/poky/meta-openembedded/meta-networking \
  ${LAYERSTOP}/poky/meta-openembedded/meta-multimedia \
  "

local.conf

local.confはターゲットマシンの設定やインストールするレシピの追加、その他様々な設定を記述することができる。

通常は、自動生成されたものにマシンの設定とレシピの追加を行うことが多い。

自動生成されたlocal.confの先頭の方に コード 2 の内容を追加する。

コード 2: local.conf(抜粋)
MACHINE ?= "raspberrypi2"
BB_NUMBER_THREADS ?= "${@oe.utils.cpu_count()}"
PARALLEL_MAKE ?= "-j ${@oe.utils.cpu_count()}"
GPU_MEM = "128"
DL_DIR ?= "${HOME}/work/yocto/downloads"

# use systemd instead of sysvinit
DISTRO_FEATURES_append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

# # systemd-timesyncd
NTP_SERVER = "ntp.nict.jp"

## cifs mount
IMAGE_INSTALL_append = " cifs-utils cifs-mount-networkd"
CIFS_SHARED_DIR = "//192.168.1.60/Music"
CIFS_MOUNT_DIR = "/mnt/nas"
CIFS_USER = "USERNAME"
CIFS_PASSWD = "PASSWORD"
CIFS_VERS = "3.0"

# mpd
LICENSE_FLAGS_WHITELIST = "commercial"
IMAGE_INSTALL_append = " mpd"

#  connman
IMAGE_INSTALL_append = " connman \
                         connman-wait-online \
                         connman-ipv4-conf \
"

# static IPv4 address for connman
CONNMAN_IPv4 = "192.168.1.55/255.255.255.0"
CONNMAN_IPv4_NS = "192.168.1.1"

# Enable I2C
ENABLE_I2C = "1"

# DAC S/PDIF
HIFIBERRY_DIGI = "1"

# MPD Music Directory
IMAGE_INSTALL_append = " mpd-musicdir"
MPD_MUSIC_DIR = "/mnt/nas"

# misc
IMAGE_INSTALL_append = " alsa-utils file"

CIFS_USER = "USERNAME"およびCIFS_PASSWD = "PASSWORD"は環境により適宜書き変えること。

bitbakeの実行

下記の要領で、bitbakeを実行する。

$ cd ~/work/yocto/rpi/build
$ bitbake rpi-basic-image

build/tmp/deploy/images/raspberrypi2にOSイメージファイルrpi-basic-image-raspberrypi2.rpi-sdimgが生成される。

イメージの書き込み

ddコマンドでrpi-basic-image-raspberrypi2.rpi-sdimgをSDカードに書き込む。

sudo dd if=tmp/deploy/images/raspberrypi2/rpi-basic-image-raspberrypi2.rpi-sdimg of=/dev/sdb bs=40M

/dev/sdbは環境により適宜書き換える。間違うとPCのデータが破壊されて泣く事になるので注意すること。

起動

イメージを書き込んだSDカードをRPi2に挿入し電源をONする。

connman-wait-online.serviceについて

connman-wait-online.serviceをenableする。

$ systemctl enable connman-wait-online.service
$ sync

connman-wait-online.serviceが実行されないと起動時の共有フォルダのマウントに失敗するため、 MPDも意図したとおり音楽ファイルを参照できない。

connman-wait-online.serviceをenableしたあと、RPi2を再起動する。

raspberrypi2でMPDサーバ

raspberrypi2+DACでMPDサーバを作成する。

今回は作成済みレイヤの使用方法ではなく、レイヤを作成する方法をまとめてみる。 作成済みレイヤの使用方法はこちら

機能

  • windows10で共有しているフォルダから音楽ファイルを参照
  • MPDサーバで音楽ファイルを再生
  • SYSTEMDを使用
  • ネットワーク設定にはconnmanを使用

DAC

今回はこのDACを使用する。

システム構成

ネットワークを含めたシステムの構成を 図 1 に示す。

f:id:mickey_happygolucky:20160524012104p:plain

図 1:システム構成

yocto環境

作業に使用するレイヤのブランチとバージョンを 表 1 に示す。

表 1: レイヤのブランチとバージョン

レイヤ ブランチ バージョン URL
poky krogoth 2.1 git://git.yoctoproject.org/poky.git
meta-openembedded krogoth 2.1 git://git.openembedded.org/meta-openembedded
meta-raspberrypi master - git://git.yoctoproject.org/meta-raspberrypi
meta-hifiberry-rpi master - https://github.com/mickey-happygolucky/meta-hifiberry-rpi.git

作業ディレクトリ

作業は~/work/yocto/rpiで行う。

ディレクトリの構成

\~/work/yocto/rpi以下の構成を以下に示す。

.
├── build
└── poky
    ├── meta-openembedded
    ├── meta-raspberrypi
    └── meta-hifiberry-rpi

poky以下は追加するレイヤのみ記載している。

ベース環境の作成

ベース環境の手順を示す。

  1. 作業ディレクトリ(\~/work/yocto/rpi)の作成
  2. pokyのダウンロード
  3. meta-openembeddedのダウンロード
  4. meta-raspberrypiのダウンロード
  5. meta-hifiberryp-rpiのダウンロード

下記のように実行する。

$ mkdir mkdir -p ~/work/yocto/rpi && cd ~/work/yocto/rpi
$ git clone git://git.yoctoproject.org/poky.git -b krogoth && cd poky
$ git clone git://git.openembedded.org/meta-openembedded -b krogoth
$ git clone git://git.yoctoproject.org/meta-raspberrypi
$ git clone https://github.com/mickey-happygolucky/meta-hifiberry-rpi.git

MPD用レイヤ

MPDサーバ向けのレイヤとしてmeta-mpd-serverを作成する。

下記のコマンドを実行し作業用のディレクトリを作成する。

$ mkdir -p ~/work/yocto/rpi/poky/meta-mpd-server

layer.conf

レイヤとしてbitbakeに認識させるためにはlayer.confが必要になる。

layer.confはmeta-mpd-server/conf以下に配置される必要がある。

下記の要領でまず、空のlayer.confファイルを作成する。

$ mkdir -p ~/work/yocto/rpi/poky/meta-mpd-server/conf
$ touch ~/work/yocto/rpi/poky/meta-mpd-server/conf/layer.conf

layer.confをエディタで開き コード 1 の内容にに編集し、保存する。

コード 1: layer.conf
# We have a conf and classes directory, append to BBPATH
BBPATH .= ":${LAYERDIR}"

# We have a recipes directory containing .bb and .bbappend files, add to BBFILES
BBFILES += "${LAYERDIR}/recipes*/*/*.bb \
            ${LAYERDIR}/recipes*/*/*.bbappend"

BBFILE_COLLECTIONS += "mpd-server"
BBFILE_PATTERN_mpd-server := "^${LAYERDIR}/"
BBFILE_PRIORITY_mpd-server = "10"

LAYERDEPENDS_mpd-server = "raspberrypi"

LAYERDEPENDS_mpd-server = "raspberrypi"の行で、meta-mpd-serverがmeta-raspberrypiに依存していることを明示している。

この時点でmeta-mpd-serverは以下のような構成になる。

./meta-mpd-server
└── conf
    └── layer.conf

ネットワーク設定

今回はサーバマシンなので、IPアドレスを固定で割り振りたい。 OSイメージがbitbakeで生成された時点で静的なIPアドレスを設定されるようにレシピを作成する。

レシピ名はconnman-ipv4-conf.bbとする。レシピは役割ごとに分類されたフォルダに配置する。connman-ipv4-conf.bbは以下のように配置する。

recipes-connectivity
└── connman
    └── connman-ipv4-conf.bb

下記のようにコマンドを実行し空のレシピファイルを作成する。

$ mkdir -p ~/work/yocto/rpi/poky/meta-mpd-server/recipes-connectivity/connman
$ touch ~/work/yocto/rpi/poky/meta-mpd-server/recipes-connectivity/connman/connman-ipv4-conf.bb

エディタでconnman-ipv4-conf.bbを開き、コード 2 の内容に編集し保存する。

コード 2: connman-ipv4-conf.bb
SUMMARY = "Connman config to static IPv4 address setup wired interface"
DESCRIPTION = "ConnMan configuration to set up to Wired network interface"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

FILES_${PN} = "${localstatedir}/*"

#                IP Address     / subnet mask
# CONNMAN_IPv4 = xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx

IPv4CFGF = "${D}${localstatedir}/lib/connman/wired.config"

do_install() {
    if [ -n "${CONNMAN_IPv4}" ] ; then
    install -d ${D}${localstatedir}/lib/connman

    echo "[global]" > ${IPv4CFGF}
    echo "Name = Wired" >> ${IPv4CFGF}
    echo "Description = Wired network configuration" >> ${IPv4CFGF}
    echo "" >> ${IPv4CFGF}
    echo "[service_ether]" >> ${IPv4CFGF}
    echo "Type = ethernet" >> ${IPv4CFGF}
    echo "IPv4 = ${CONNMAN_IPv4}" >> ${IPv4CFGF}
    
    if [ -n "${CONNMAN_IPv4_NS}" ] ; then
        echo "Nameservers = ${CONNMAN_IPv4_NS}" \
         >> ${D}${localstatedir}/lib/connman/wired.config
    fi
    else
    install -d ${D}${localstatedir}/lib/connman
    touch ${D}${localstatedir}/dummy
    fi
}

このレシピによって、RPi2上に/lib/connman/wired.configが作成され、有線接続のネットワーク設定が行われる。

固定IPアドレスを指定するには、local.confに下記のように記述する。

CONNMAN_IPv4 = 192.168.1.100/255.255.255.0

この例ではIPアドレス192.168.1.100、サブネットマスク255.255.255.0に設定している。

共有フォルダ設定

Windows 10の共有フォルダ

Windows10の共有フォルダをマウントするには下記のようにする。

$ mount -t cifs -ousername=USERNAME,password=PASSWORD,vers=3.0 //machine_name/shared_folder /mnt/point

ポイントはvers=3.0で、これをオプションに指定しないと、下記のようにエラーになってしまう。

mount: mounting //machine_name/shared_folder on /mnt/point failed: Input/output error

vers=の指定は、jethroのcifs-utilsでは認識されないため、少なくともWindows10の共有フォルダをマウントしたい場合は、krogothかmasterを使用する必要がある。

Windows8については筆者の環境がないため試せないが、もしかすると状況は同じかもしれない。 Windows7に関してはvers=は必要なかった。

共有フォルダ設定レシピ

OSイメージがbitbakeで生成された時点で指定の共有フォルダがマウントされるようにレシピを作成する。

レシピ名はcifs-mount-networkd.bbとする。

cifs-mount-networkd.bbは以下のように配置する。

recipes-connectivity
└── samba
    └── cifs-mount-networkd.bb

下記のようにコマンドを実行し空のレシピファイルを作成する。

$ mkdir -p ~/work/yocto/rpi/poky/meta-mpd-server/recipes-connectivity/samba
$ touch ~/work/yocto/rpi/poky/meta-mpd-server/recipes-connectivity/samba/cifs-mount-networkd.bb

エディタでcifs-mount-networkd.bbを開き、コード 3 の内容に編集し保存する。

コード 3: cifs-mount-networkd.bb
SUMMARY = "Mount CIFS at boot"
DESCRIPTION = "Generate a mount unit file to mount remote via cifs at boot."
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

inherit systemd

MOUNT_NAME = "${@ '${CIFS_MOUNT_DIR}'.replace('/', '-')[1:]}"
CIFS_MOUNT_UNIT = "${D}${sysconfdir}/systemd/system/${MOUNT_NAME}.mount"

SYSTEMD_SERVICE_${PN} = "${MOUNT_NAME}.mount"

do_install() {
    if [ -n "${CIFS_SHARED_DIR}" -a -n ${CIFS_MOUNT_DIR} ] ; then
        install -d ${D}${sysconfdir}/systemd/system

    if [ ${CIFS_SEC_NTLM} = "1" ] ; then
       SEC=",sec=ntlm"
    else
       SEC=""
    fi

    if [ -n ${CIFS_VERS} ] ; then
       VERS=",vers=${CIFS_VERS}"
    else
       VERS=""
    fi

    echo "[Unit]" > ${CIFS_MOUNT_UNIT}
    echo "Description=Mount Share at boot" >> ${CIFS_MOUNT_UNIT}
    echo "Requires=connman.service" >> ${CIFS_MOUNT_UNIT}
        echo "After=connman-wait-online.service" >> ${CIFS_MOUNT_UNIT}
    echo "" >> ${CIFS_MOUNT_UNIT}
    echo "[Mount]" >> ${CIFS_MOUNT_UNIT}
    echo "What=${CIFS_SHARED_DIR}" >> ${CIFS_MOUNT_UNIT}
    echo "Where=${CIFS_MOUNT_DIR}" >> ${CIFS_MOUNT_UNIT}
    echo "Options=username=${CIFS_USER},password=${CIFS_PASSWD},iocharset=utf8,rw,x-systemd.automount${SEC}${VERS}" >> ${CIFS_MOUNT_UNIT}
    echo "Type=cifs" >> ${CIFS_MOUNT_UNIT}
    echo "TimeoutSec=30" >> ${CIFS_MOUNT_UNIT}
    echo "" >> ${CIFS_MOUNT_UNIT}
    echo "[Install]" >> ${CIFS_MOUNT_UNIT}
    echo "WantedBy=multi-user.target" >> ${CIFS_MOUNT_UNIT}
    fi
}

共有フォルダをマウントするにはlocal.confに下記のように記述する。

CIFS_SHARED_DIR = "//machine_name/shared_folder"
CIFS_MOUNT_DIR = "/mnt/point"
CIFS_USER = "USERNAME"
CIFS_PASSWD = "PASSWORD"
CIFS_VERS = "3.0"

CIFS_VERSによりオプションにvers=を設定する。

cifs-mount-networkd.bbでは、複数の共有フォルダのマウントを指定することはできない。

MPD設定

MPDのサウンドデバイスの設定を既存から、DAC向けに変更する必要がある。 そのためにはmpd.confの記述を変更する必要があるが、mpd.confのインストールはmpd_0.19.10.bbで行っている。

bbappendを使用すると既存のレシピを直接変更せずに挙動を変更することができる。 ここではmpd_%.bbappendを作成する。%はバージョンをワイルドカード指定している。

bbappendは元になるbbと同じ構成になるように配置する。

mpd_%.bbappendは以下のようになる。

recipes-multimedia
└── musicpd
    └── mpd_%.bbappend

下記のようにコマンドを実行し空のレシピファイルを作成する。

$ mkdir -p ~/work/yocto/rpi/poky/meta-mpd-server/recipes-multimedia/musicpd
$ touch ~/work/yocto/rpi/poky/meta-mpd-server/recipes-multimedia/musicpd/mpd_%.bbappend

エディタでmpd_%.bbappendを開き、コード 4 の内容に編集し保存する。

コード 4: mpd\_%.bbappend
SYSTEMD_SERVICE_${PN}_remove = "mpd.socket"
FILES_${PN} += "${systemd_unitdir}/system/mpd.socket"

PACKAGECONFIG_append = " id3tag"

do_install_append() {
    if [ "${HIFIBERRY_DIGI}" = "1" ] ; then
       echo 'audio_output {' >> ${D}/${sysconfdir}/mpd.conf
       echo '        type            "alsa"' >> ${D}/${sysconfdir}/mpd.conf
       echo '        name            "MyAlsa"' >> ${D}/${sysconfdir}/mpd.conf
       echo '        device          "hw:0,0"' >> ${D}/${sysconfdir}/mpd.conf
       echo '        mixer_control   "Digital"' >> ${D}/${sysconfdir}/mpd.conf
       echo '}' >> ${D}/${sysconfdir}/mpd.conf
    fi
    if [ "${HIFIBERRY_DAC}" = "1" -o "${HIFIBERRY_DACPLUS}" = "1" ] ; then
       echo 'audio_output {' >> ${D}/${sysconfdir}/mpd.conf
       echo '        type            "alsa"' >> ${D}/${sysconfdir}/mpd.conf
       echo '        name            "MyAlsa"' >> ${D}/${sysconfdir}/mpd.conf
       echo '        device          "hw:0,0"' >> ${D}/${sysconfdir}/mpd.conf
       echo '}' >> ${D}/${sysconfdir}/mpd.conf
    fi
}

PACKAGECONFIG_append = " id3tag"の行がないとmp3ファイルが正しくDBに登録されない。 これは、mp3タグの解析が有効にならないため。

音源ディレクトリの設定

mpdはmpd.confのmusic_directoryで指定されたディレクトリ以下にある音楽ファイルを再生する。

このディレクトリをマウント済みのWindowsの共有フォルダを参照する。 mpd_0.19.bbにより、music_directoryは/var/lib/mpd/musicに設定されている。

今回は共有フォルダをマウントしている/mnt/nasシンボリックリンク/var/lib/mpd/musicに作成するアプローチを取る。

そのためのレシピmpd-musicdir_0.1.bbを作成する。

レシピの構成

レシピの構成は以下のようになる。

recipes-multimedia
└── musicpd
    ├── mpd-musicdir
    │   ├── mpd-musicdir.service
    │   └── replace-mpd-musicdir.sh
    └── mpd-musicdir_0.1.bb

シンボリックリンクの作成はreplace-mpd-musicdir.shで行う。 そして、システム起動時にmpd-musicdir.serviceにより、replace-mpd-musicdir.shを実行するようにしている。

下記の要領で空のファイルを作成する。

$ mkdir -p ~/work/yocto/rpi/poky/meta-mpd-server/recipes-multimedia/musicpd/mpd-musicdir
$ touch ~/work/yocto/rpi/poky/meta-mpd-server/recipes-multimedia/musicpd/mpd-musicdir_0.1.bb
$ touch ~/work/yocto/rpi/poky/meta-mpd-server/recipes-multimedia/musicpd/mpd-musicdir/mpd-musicdir.service
$ touch ~/work/yocto/rpi/poky/meta-mpd-server/recipes-multimedia/musicpd/mpd-musicdir/replace-mpd-musicdir.sh

まず、エディタでmpd-musicdir_0.1.bbを開き コード 5 の内容に編集、保存する。

コード 5: mpd-musicdir\_0.1.bb
SUMMARY = "Replace mpd music directory."
DESCRIPTION = "Generate a unit file to replace music directory."
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

inherit systemd

RDPENDS = "mpd"

SRC_URI = "file://mpd-musicdir.service \
       file://replace-mpd-musicdir.sh \
"

FILES_${PN} = "${sysconfdir}/systemd/system/* \
           ${bindir}/* \
"

CIFS_MOUNT_NAME = "${@ '${CIFS_MOUNT_DIR}'.replace('/', '-')[1:]}"
MPD_MUSICDIR_UNIT = "${D}${sysconfdir}/systemd/system/mpd-musicdir.service"
SYSTEMD_SERVICE_${PN} = "mpd-musicdir.service"

do_install() {
    if [ -n "${MPD_MUSIC_DIR}" ] ; then
       install -d ${D}${sysconfdir}/systemd/system
       install -m 0644 ${WORKDIR}/mpd-musicdir.service ${D}${sysconfdir}/systemd/system
       if [ -n "${CIFS_MOUNT_NAME}" ] ; then
          sed -i 's|Before=mpd.service|Before=mpd.service\nAfter=${CIFS_MOUNT_NAME}.mount|' \
          ${MPD_MUSICDIR_UNIT}
       fi

       install -d ${D}${bindir}
       install -m 0755 ${WORKDIR}/replace-mpd-musicdir.sh ${D}${bindir}
       sed -i -e 's|MPD_MUSIC_DIR_SRC=""|MPD_MUSIC_DIR_SRC="${MPD_MUSIC_DIR}"|' \
           ${D}${bindir}//replace-mpd-musicdir.sh
    fi
}

次に、mpd-musicdir.serviceをエディタで コード 6 の内容に編集する。

コード 6: mpd-musicdir.service
[Unit]
Description="Replace MPD Musid Directory"
Before=mpd.service

[Service]
Type=oneshot
ExecStart=/usr/bin/replace-mpd-musicdir.sh

[Install]
WantedBy=multi-user.target

最後に、replace-mpd-musicdir.shをエディタで コード 7 のように編集する。

コード 7: replace-mpd-musicdir.sh
#!/bin/sh

MPD_MUSIC_DIR_SRC=""
MPD_MUSIC_DIR_DST="/var/lib/mpd/music"

if [ -d ${MPD_MUSIC_DIR_DST} ] ; then
    rmdir ${MPD_MUSIC_DIR_DST}
fi

if [ -d "${MPD_MUSIC_DIR_SRC}" ] ; then
    ln -s "${MPD_MUSIC_DIR_SRC}" "${MPD_MUSIC_DIR_DST}"
else
    echo "${MPD_MUSIC_DIR_SRC} is not directory."
    exit 1
fi

echo "done."

bitbakeの準備

OSイメージを作成するためにbitbakeを実行するが、その前に書きコマンドでbitbakeを実行するために必要な設定を行う。

$ cd ~/work/yocto/rpi
$ source poky/oe-init-build-env build

実行後、buildディレクトリが生成され、自動的に移動される。

生成されたbuildディレクトリは以下のような構成になっている。

./build
└── conf
    ├── bblayers.conf
    ├── local.conf
    └── templateconf.cfg

conf以下のファイルは自動生成されたもので、この内、bblayers.confとlocal.confは修正する必要がある。

bblayers.conf

bblayers.confはbitbakeがビルド対象とするレイヤを定義する。

MPDサーバをビルドするため、自動生成されたbblayers.confを コード 8 の内容にまるごと置き換える。

コード 8: bblayers.conf
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"

BBPATH = "${TOPDIR}"
BBFILES ?= ""

LAYERSTOP = "${TOPDIR}/.."

BBLAYERS ?= " \
  ${LAYERSTOP}/poky/meta \
  ${LAYERSTOP}/poky/meta-poky \
  ${LAYERSTOP}/poky/meta-yocto-bsp \
  ${LAYERSTOP}/poky/meta-raspberrypi \
  ${LAYERSTOP}/poky/meta-mpd-server \
  ${LAYERSTOP}/poky/meta-hifiberry-rpi \
  ${LAYERSTOP}/poky/meta-openembedded/meta-oe \
  ${LAYERSTOP}/poky/meta-openembedded/meta-python \
  ${LAYERSTOP}/poky/meta-openembedded/meta-networking \
  ${LAYERSTOP}/poky/meta-openembedded/meta-multimedia \
  "

local.conf

local.confはターゲットマシンの設定やインストールするレシピの追加、その他様々な設定を記述することができる。

通常は、自動生成されたものにマシンの設定とレシピの追加を行うことが多い。

自動生成されたlocal.confの先頭の方に コード 9 の内容を追加する。

コード 9: local.conf(抜粋)
MACHINE ?= "raspberrypi2"
BB_NUMBER_THREADS ?= "${@oe.utils.cpu_count()}"
PARALLEL_MAKE ?= "-j ${@oe.utils.cpu_count()}"
GPU_MEM = "128"
DL_DIR ?= "${HOME}/work/yocto/downloads"

# use systemd instead of sysvinit
DISTRO_FEATURES_append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

# # systemd-timesyncd
NTP_SERVER = "ntp.nict.jp"

## cifs mount
IMAGE_INSTALL_append = " cifs-utils cifs-mount-networkd"
CIFS_SHARED_DIR = "//192.168.1.60/Music"
CIFS_MOUNT_DIR = "/mnt/nas"
CIFS_USER = "USERNAME"
CIFS_PASSWD = "PASSWORD"
CIFS_VERS = "3.0"

# mpd
LICENSE_FLAGS_WHITELIST = "commercial"
IMAGE_INSTALL_append = " mpd"

#  connman
IMAGE_INSTALL_append = " connman \
                         connman-wait-online \
                         connman-ipv4-conf \
"

# static IPv4 address for connman
CONNMAN_IPv4 = "192.168.1.55/255.255.255.0"
CONNMAN_IPv4_NS = "192.168.1.1"

# Enable I2C
ENABLE_I2C = "1"

# DAC S/PDIF
HIFIBERRY_DIGI = "1"

# MPD Music Directory
IMAGE_INSTALL_append = " mpd-musicdir"
MPD_MUSIC_DIR = "/mnt/nas"

# misc
IMAGE_INSTALL_append = " alsa-utils file"

bitbakeの実行

下記の要領で、bitbakeを実行する。

$ cd ~/work/yocto/rpi/build
$ bitbake rpi-basic-image

下記のディレクトリに、OSイメージファイルrpi-basic-image-raspberrypi2.rpi-sdimgが生成される。

build/tmp/deploy/images/raspberrypi2

イメージの書き込み

ddコマンドでrpi-basic-image-raspberrypi2.rpi-sdimgをSDカードに書き込む。

sudo dd if=tmp/deploy/images/raspberrypi2/rpi-basic-image-raspberrypi2.rpi-sdimg of=/dev/sdb bs=40M

起動

イメージを書き込んだSDカードをRPi2に挿入し電源をONする。

connman-wait-online.serviceについて

本来であれば、connman.incの下記の行によってサービスがenableされ、システム起動時に実行されるようになるはずだが、

SYSTEMD_SERVICE_${PN}-wait-online = "connman-wait-online.service"

現状では、おそらくpokyの不具合によりdisabledの状態になっている。

そのため、下記のようにして、connman-wait-online.serviceをenableする必要がある。

$ systemctl enable connman-wait-online.service
$ sync

connman-wait-online.serviceが実行されないと起動時の共有フォルダのマウントに失敗するため、 MPDも意図したとおり音楽ファイルを参照できない。

connman-wait-online.serviceをenableしたあと、RPi2を再起動する。

接続

クライアントはAndroid端末からMPDroidで接続する。

Ubuntu 15.04でtextlint

Twitterでtextlintが良さげと流れてきたので、Ubuntu15.04に導入してみる。

npmでインストールするのだが、apt-getでインストールされるバージョンでは古く、多少手順が必要だったためメモっておく。

npmのインストール

Ubuntuに最新のNode.jsを難なくインストールするの手順でnpmの最新版をインストールする。

  1. apt-getでnodejsとnpmをインストールする。
  2. npmでnパッケージをインストールする。
  3. nパッケージでnodeをインストールする。
  4. apt-getでインストールしたnodejsとnpmを削除する。

実際には以下のような感じになる。

$ sudo apt-get install -y nodejs npm
$ sudo npm cache clean
$ sudo npm install n -g
$ sudo n stable
$ sudo ln -sf /usr/local/bin/node /usr/bin/node
$ sudo apt-get purge -y nodejs npm

apt-getのnodejsとnpmは/usr/binにインストールされるが、 nパッケージの実行ファイルは/usr/local/binにインストールされる。

textlintのインストール

textlint 6.0リリース。--fixでの自動修正に対応にまとまったインストール手順が載っていたので、参考にする。

textlintとルールプリセットのインストール

以下のコマンドでtextlint本体と3つのルールプリセットをインストールする。

$ cd ~/
$ npm i -D textlint textlint-rule-preset-jtf-style textlint-rule-spellcheck-tech-word textlint-rule-common-misspellings

インストールするルールプリセットは次の3つ。

  1. preset-jtf-style
  2. spellcheck-tech-word
  3. common-misspellings

これらは--fixによる自動修正に対応している。

設定ファイルの作成

以下のコマンドで空の.textlintrcが作成される。

$ $(npm bin)/textlint --init

$(npm bin)でnpmでインストールされたコマンドのパスを解決する。

生成されたファイルを以下の内容に編集する。

{
  "rules": {
    "preset-jtf-style": true,
    "spellcheck-tech-word": true,
    "common-misspellings": true
  }
}

textlintの実行

実行してみる。

$ $(npm bin)/textlint ./textlint.md

結果

/home/mickey/memo/textlint.md
   3:1   ✓ error  twitter => Twitter                                          spellcheck-tech-word
  52:48  ✓ error  原則として、全角文字と半角文字の間にスペースを入れません。  preset-jtf-style/3.1.1.全角文字と半角文字の間

✖ 2 problems (2 errors, 0 warnings)
✓ 2 fixable problems.
Try to run: $ textlint --fix [file]

すばらしい。