DragonBoard 410c(Debian)で日本語音声合成(Open JTalk)のTTSしてみる

DragonBoard 410c(Debian)で日本語音声合成(Open JTalk)のTTSしてみる

前回のエントリで音声の出力ができるようになったDragonBoard。この機能を元にOpen JTalkを用いた音声合成を行ってみたいと思います。

Open JTalk - HMM-based Text-to-Speech System

以下の過去エントリを参考にしていきます。

OpenJTalk関連 uepon.hatenadiary.com

Bluetoothスピーカー関連 uepon.hatenadiary.com

Open JTalkのインストー

Open JTalkMMDAgentをインストールします。

$ sudo apt-get install open-jtalk open-jtalk-mecab-naist-jdic htsengine libhtsengine-dev hts-voice-nitech-jp-atr503-m001
$ wget http://downloads.sourceforge.net/project/mmdagent/MMDAgent_Example/MMDAgent_Example-1.6/MMDAgent_Example-1.6.zip
$ unzip MMDAgent_Example-1.6.zip
$ sudo cp -R MMDAgent_Example-1.6/Voice/mei /usr/share/hts-voice/

一度行っているので迷うことはありませんでした。

TTSを実行するシェルを編集する

Open JTalkのパラメータを設定し実行するシェルスクリプトを編集します。

$ vim jtalk.sh

【jtalk.sh】

#!/bin/bash

# HTSVOICE=/usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice
HTSVOICE=/usr/share/hts-voice/mei/mei_normal.htsvoice

voice=`tempfile`
option="-m $HTSVOICE \
  -s 16000 \
  -p 100 \
  -a 0.03 \
  -u 0.0 \
  -jm 1.0 \
  -jf 1.0 \
  -x /var/lib/mecab/dic/open-jtalk/naist-jdic \
  -ow $voice"

if [ -z "$1" ] ; then
        open_jtalk $option
else
        if [ -f "$1" ] ; then
                open_jtalk $option $1
        else
                echo "$1" | open_jtalk $option
        fi
fi

aplay -q $voice
rm $voice

編集が終わったら実行権限を与えます。

$ chmod 755 jtalk.sh

これで準備完了です。

TTSの実行

ここまで終わったので実際に実行させてみます。 コンソール上から以下の様に話したい文章を引数として与えます。

$ ./jtalk.sh こんにちは、今日は雨が降っているなか、お越しい
ただき、ありがとうございます
$ ./jtalk.sh 最大級のパワフルボディ!ダリラガーン!ダゴズバ
ーン!
$ ./jtalk.sh ドリーミングガール、恋のシミュレーション。乙女
はいつも、ときめきクライシス。

正常に動作できたようです。

【動画】

youtu.be

おわりに

思ったよりすんなりOpen JTalkを導入できました。 これでDragonBoardでも音声でアナウンスするようなものは簡単にできそうですね!

DragonBoard 410c(Debian)でPechatを使用してみる(Bluetooth経由の音声出力)

DragonBoard 410c(Debian)でPechatを使用してみる

DragonBoardの唯一困った点は音声出力のpinがデフォルトではないことかなと思います。 できれば、このあたりもついていると良かったかなと。最近は音声認識や自動音声や音声による操作もあるので、こういう方向もアクセスできるといいなあと思ったり。

ただ、DragonBoardにはBluetoothがついているのでBluetooth用の音声機器は接続できます。以前のエントリでRaspberryPiでBluetoothスピーカーのPechatを使用してみました。 一応無事には接続し使用できたのですが、XからのGUI経由でしか設定できなかったので、微妙な感じでした。そのリベンジも兼ねてDrabgonBoardでも設定をチャレンジしてみます。

uepon.hatenadiary.com

ちなみに結論に急ぎたい方は回答編まですっ飛ばしてください。

DragonBoardでBluetooth-音声デバイス設定を行う

一応、前提とする環境を確認します。OSのディストリビューションを確認します。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 9.0 (stretch)
Release:        9.0
Codename:       stretch

もちろん、Debianですが、自分が使用したOSイメージはdragonboard410c_sdcard_install_debian-233.zipです。最新ではなく一つ古いバージョンかなと思います。(特にこだわりがなければ最新イメージのほうがいいかなと思います。)

Documentation - 96Boards

音声デバイスとしての制御はPulseAudioを使用するので、pulseaudio関係のパッケージのインストール状況も確認します。

$ dpkg -l | grep pulse
ii  libpulse-mainloop-glib0:arm64                 10.0-1                            arm64        PulseAudio client libraries (glib support)
ii  libpulse0:arm64                               10.0-1                            arm64        PulseAudio client libraries
ii  libpulsedsp:arm64                             10.0-1                            arm64        PulseAudio OSS pre-load library
ii  pulseaudio                                    10.0-1                            arm64        PulseAudio sound server
ii  pulseaudio-module-bluetooth                   10.0-1                            arm64        Bluetooth module for PulseAudio sound server
ii  pulseaudio-utils                              10.0-1                            arm64        Command line tools for the PulseAudio sound server
ii  xmms2-plugin-pulse                            0.8+dfsg-18 

デフォルトでインストールも完了しています。

Bluetoothの接続を確認する

あとはCLIからBluetoothの接続をおこなってみます。Bluetoothの確認用コマンドはbluetoothctlです。

$ sudo bluetoothctl -a
[NEW] Controller 00:00:00:00:XX:XX linaro-alip [default]
Agent registered
[bluetooth]# scan on
Discovery started
[CHG] Controller 00:00:00:00:XX:XX Discovering: yes
[NEW] Device CC:30:80:00:XX:XX Pechat-00F8A1
[NEW] Device AE:12:42:3B:XX:XX 36bde7-bt
[CHG] Device AE:12:42:3B:FF:12 RSSI: -86
[bluetooth]# pair CC:30:80:00:XX:XX
Attempting to pair with CC:30:80:00:XX:XX
[CHG] Device CC:30:80:00:XX:XX Connected: yes
[CHG] Device CC:30:80:00:XX:XX UUIDs: 00001101-0000-1000-8000-00805f9b34fb
[CHG] Device CC:30:80:00:XX:XX UUIDs: 0000110b-0000-1000-8000-00805f9b34fb
[CHG] Device CC:30:80:00:XX:XX ServicesResolved: yes
[CHG] Device CC:30:80:00:XX:XX Paired: yes
Pairing successful
[CHG] Device CC:30:80:00:XX:XX ServicesResolved: no
[CHG] Device CC:30:80:00:XX:XX Connected: no
[bluetooth]# connect CC:30:80:00:XX:XX
Attempting to connect to CC:30:80:00:XX:XX
[CHG] Device CC:30:80:00:XX:XX Connected: yes
Connection successful
[CHG] Device CC:30:80:00:XX:XX ServicesResolved: yes
[CHG] Device AE:12:42:3B:XX:XX RSSI: -87
[CHG] Device AE:12:42:3B:XX:XX RSSI: -74
[Pechat-00F8A1]# quit
Agent unregistered
[DEL] Controller 00:00:00:00:XX:XX linaro-alip [default]

無事にペアリングもコネクトもできました。あとはServiceの設定などを行うのみです。以下はほとんどRaspberryPiのときのエントリーそのままになります。RaspberryPiでは失敗していたのでかなり不安ではありますが…

/etc/systemd/system/pulseaudio.serviceファイルを作成

$ sudo vim /etc/systemd/system/pulseaudio.service

【/etc/systemd/system/pulseaudio.service】

[Unit]
Description=Pulse Audio

[Service]
Type=simple
ExecStart=/usr/bin/pulseaudio --system --disallow-exit --disable-shm

[Install]
WantedBy=multi-user.target

/etc/dbus-1/system.d/pulseaudio-bluetooth.confファイルを作成

$ sudo vim /etc/dbus-1/system.d/pulseaudio-bluetooth.conf

【/etc/dbus-1/system.d/pulseaudio-bluetooth.conf】

<busconfig>

  <policy user="pulse">
    <allow send_destination="org.bluez"/> 
  </policy>

</busconfig>

以上で設定ファイルの編集は終了となります。

pulseaudioサービスの設定

最後に起動時に自動的に設定をされるようにサービスの開始と有効化を行っておきます。

$ sudo systemctl start pulseaudio.service
$ sudo systemctl enable pulseaudio.service

これで完了です。 あとは先程と同じくBluetoothの状態の確認をしますが、基本無事にコネクトができているので一安心です。

後は音声が正常に再生されればいいのですが…

$ aplay /usr/share/sounds/alsa/Front_Center.wav
Playing WAVE '/usr/share/sounds/alsa/Front_Center.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Mono

あれ? エラーは出ないが、音がならない…RaspberryPiとは違う状況…

最初はmixserの設定で音量が下がっているのかなと思ったのですが、そんなこともなくさすがに微妙な感じになってしまいました。

仕方ないのでサービスはストップし、起動時は無効にすることにします。

$ sudo systemctl stop pulseaudio.service
$ sudo systemctl disable pulseaudio.service

回答編

結局、コマンドラインからの設定は成功しませんでした。(RaspberryPiでもうまく行っていなかったので、こちらがそのままの方法でうまくいくとは思いませんでしたが。)

最後にXを使用してBluetoothの設定を行ってみます。(事前にPechatの電源は入れておいてください。)

まずは、Xの下部のメニューバーをクリックし【設定】→【KDEシステム設定】を選択します。すると設定のダイアログウインドウが開きます。

f:id:ueponx:20170624101410j:plain

その中から【ネットワーク】→【Bluetooth】を選択します。

f:id:ueponx:20170624101422j:plain

するとBluetoothで接続されたデバイスの一覧が表示されます。 画面上にPechatが表示されているのがわかるかと思います。

f:id:ueponx:20170624101443j:plain

一覧からPechatを選択してみます。

f:id:ueponx:20170624101452j:plain

するとダイアログの右側にヘッドフォンの画像が表示されます。 その画面中のTrustedの部分にマウスでチェックをしてみます。

f:id:ueponx:20170624101502j:plain

その後、ダイアログ右側にある【Connect】をクリックします。 接続がうまくいくとボダンの文字はDisconnectという文字列に変更します。

f:id:ueponx:20170624101511j:plain

一応この時点でもaplayコマンドで音がなりませんでした。さすがに八方塞がりかと思ってしまうのですが、今度は下部のメニューバーをクリックし、【サウンドとビデオ】→【PluseAudio Volume Control】を選択します。

f:id:ueponx:20170624101520j:plain

選択後に開いだダイアログの【Output Device】を確認すると本体側(B410c)の設定とPechat側の設定が存在することがわかります。問題はなさそうでもあったので、この時点でaplayコマンドで再生させるのですが、問題はなさそうでしたが音声はなりませんでした。そのため、今度は本体側の外してみます。【Configure】タブを選択しD410cの【Profile】をOffに変更します。

f:id:ueponx:20170624101529j:plain

特に問題はなさそうですが、以前音声デバイスの優先順位の設定をしていたときに、優先度が異なると音声がならないということがあったことをふと思い出しました。

f:id:ueponx:20170624101537j:plain f:id:ueponx:20170624101544j:plain

ペアリングさせなおすのですが、これで問題はなく設定は完了になりそうです。

音声の再生

$ aplay /usr/share/sounds/alsa/Front_Center.wav
Playing WAVE '/usr/share/sounds/alsa/Front_Center.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Mono

音声が再生されました。やっと正常に動作します。 再起動時などにはペアリングなどは解除されるので起動時に再度Pechatの電源ボタンをOnにしてペアリングさせてあげれば問題はないかなと思います。

おわりに

やっぱり、コマンドラインからの設定はうまく行かず…。Xからの設定でうまくいっているので事実上問題はないのですが…残念です。現在の自分の能力ではそこまでということか。トホホ。

DragonBoard 410c(Debian)でGPIOプログラミング(Python編)

DragonBoard 410c(Debian)でGPIOプログラミング(Python編)

前回まではC言語でGPIOを触っていましたが、流石に最近はpythonとかnode.jsで触りたいですね。

uepon.hatenadiary.com

uepon.hatenadiary.com

折角、pythonのラッパーもインストールしてあるのでpython編となります。 早速サンプルを眺めてみます。

#!/usr/bin/python
import time

from gpio_96boards import GPIO

GPIO_A = GPIO.gpio_id('GPIO_A')
pins = (
    (GPIO_A, 'out'),
)

def blink(gpio):
    for i in range(5):
        gpio.digital_write(GPIO_A, GPIO.HIGH)
        time.sleep(i)
        gpio.digital_write(GPIO_A, GPIO.LOW)
        time.sleep(1)

if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser(
        description='Blink LED on GPIO A (pin 23)')
    args = parser.parse_args()

    with GPIO(pins) as gpio:
        blink(gpio)

基本はLチカなので実行すればGPIO_A(GPIO 23pin)に接続したLEDが点灯します。

$ sudo python blink.py

サンプルのままなので実行に関しては特に問題はありません。部分を見ていきます。

モジュールの読み込み

from gpio_96boards import GPIO

gpio_96boarsがモジュールになるようです。

GPIOのピンの指定

GPIO_Aを指定します。変数名もGPIO_Aなので少しわかりにくいかも。

GPIO_A = GPIO.gpio_id('GPIO_A')

指定したPINとIN/OUTのディレクションをタプルとして保存します。

pins = (
    (GPIO_A, 'out'),
)

出力

設定したタプルに対して値を書き込む処理となります。

gpio.digital_write(GPIO_A, GPIO.HIGH)

ここでは引数のgpioが先程のタプルであるpinsに相当します。 digital_write()で値を書き込むことになります。最初はなんで引数にGPIO_Aを渡さなければいけないのか謎があったのですが、タプルの中に複数のGPIOの設定を入れればいいのかと思って納得しました。

引数にはタプルので指定したGPIOと値をいれると出力ができます。C言語とは少し違う印象ですが、割りと冗長性も少なくできるのでわかりやすいです。

入力

今度は入力になりますが、出力と同様に

  1. GPIOのピンの指定
  2. GPIOからの入力

というステップになります。

出力と入力の対比をしたほうが理解がし易いかなと思います。

GPIO_A = GPIO.gpio_id('GPIO_A')
GPIO_C = GPIO.gpio_id('GPIO_C')
pins = (
    (GPIO_A, 'out'),
    (GPIO_C, 'in'),
)

ピンの設定はまんま同じですが、ディレクションに関してはタプルの中に書いていくことになります。複数のピンがあると冗長性が少なくなるのがこれでわかるかと思います。

入力に関しては

t = gpio.digital_read(GPIO_C)

こんな感じになると思います。取得した値はGPIO.HIGHとGPIO.LOWとなります。

ということでGPIO_Cのタクトスイッチを押したら、GPIO_Aに接続したLEDが点灯するサンプルをかいてみました。C言語編のソースをpythonに移植しています。

#!/usr/bin/python
import time
from gpio_96boards import GPIO

usleep = lambda x: time.sleep(x/1000000.0)


GPIO_A = GPIO.gpio_id('GPIO_A')
GPIO_C = GPIO.gpio_id('GPIO_C')
pins = (
    (GPIO_A, 'out'),
    (GPIO_C, 'in'),
)

def blink(gpio):
    led_state = GPIO.HIGH
    last_t = GPIO.LOW
    while True:
        t = gpio.digital_read(GPIO_C)
        if (t and (not last_t)) :
            gpio.digital_write(GPIO_A, led_state)
            usleep(100000)
            if led_state == GPIO.HIGH:
                led_state = GPIO.LOW
            else:
                led_state = GPIO.HIGH
        last_t = t
        usleep(1)

if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser(
        description='Blink LED on GPIO A (pin 23)')
    args = parser.parse_args()

    with GPIO(pins) as gpio:
        blink(gpio)

C言語編同様にタクトスイッチでON/OFFができるようになりました。起動時の引数を付けたときのusageメッセージはめんどくさいかったので直してませんw。

終わりに

これでC言語でもpythonでもGPIOの入力・出力ができるようになりました。C言語でも同じことはできるのですが、やっぱりpythonの方が作りやすいかなと思いました。

もうそろそろ作品ぽいものを作らないと行けないのですが、アイデアがちょっとまだまとまっていないのでどうすれば…。

DragonBoard 410c(Debian)でGPIOプログラミング(C言語編):少し解決

DragonBoard 410c(Debian)でGPIOプログラミング(C言語編):少し解決

前回のエントリではなかなかタクトスイッチを使ったGPIOの入力処理がうまく行かず途中で中断してしまいました。

タクトスイッチの回路をArduinoで動作するか試したり、プログラムを直したりとしていましたが、状況は好転しませんでした。

uepon.hatenadiary.com

ふと思い、GPIO_Bが原因?ではないかと思いGPIO_Cに変更してみました。 あと、タクトスイッチを押したらLEDが点灯する様にソースも編集しました。

【blink.c】

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <gpio.h>

#define LED "GPIO-A"
#define TOUCH "GPIO-C"

int main()
{
        int x;
        int t = 0;
        int last_t = 0;
        int led_state = HIGH;

        if(gpio_open(gpio_id(LED), "out")){
                return (-1);
        }
        if (gpio_open(gpio_id(TOUCH), "in")){
                return(-1);
        }

        while(1){
                t = digitalRead(gpio_id(TOUCH));
                if (t && !last_t){
                        digitalWrite(gpio_id(LED), led_state);
                        usleep(100000);
                        if(led_state == HIGH){
                                led_state = LOW;
                                printf("HIGH\n");
                        } else {
                                led_state = HIGH;
                                printf("LOW\n");
                        }
                }
                last_t = t;
                usleep(1);
        }

        digitalWrite(gpio_id(LED), LOW);
        return EXIT_SUCCESS;
}

入力処理

入力に使用するGPIOのピンをTOUCHとしておき、方向を"in"とすればオープンは完了です。

if (gpio_open(gpio_id(TOUCH), "in")){
                return(-1);
        }

入力値の取得はdigitalRead()となります。引数にピン番号を与えることでOKです。値はintで帰ってきますが、HIGHtおLOWでも判別ができるようになっています。

                t = digitalRead(gpio_id(TOUCH));

ではあらためて、makeして実行してみると…

$ make
gcc -DPACKAGE_NAME=\"96BoardsGPIO\" -DPACKAGE_TARNAME=\"96boardsgpio\" -DPACKAGE_VERSION=\"0.1\" -DPACKAGE_STRING=\"96BoardsGPIO\ 0.1\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"96boardsgpio\" -DVERSION=\"0.1\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -I.    -l96BoardsGPIO -g -O2 -MT blink-blink.o -MD -MP -MF .deps/blink-blink.Tpo -c -o blink-blink.o `test -f 'blink.c' || echo './'`blink.c
mv -f .deps/blink-blink.Tpo .deps/blink-blink.Po
/bin/bash ../libtool  --tag=CC   --mode=link gcc -l96BoardsGPIO -g -O2   -o blink blink-blink.o  -lsoc
libtool: link: gcc -g -O2 -o blink blink-blink.o  -l96BoardsGPIO -lsoc
$ sudo ./blink
HIGH
LOW
HIGH
LOW
HIGH
LOW
^C

あれ?すんなり動きました。

動作中の動画は後日追記します。

動作状況の動画になります。

youtu.be

おわりに

GPIO_Bが動かないのは原因がわかりませんが、一応動いたので今回のエントリーとしては解決とします。GPIOのピンごとの設定ってあるんでしょうかね。

DragonBoard 410c(Debian)でGPIOプログラミング(C言語編):課題あり

DragonBoard 410c(Debian)でGPIOプログラミング(C言語編)

以前のエントリーでは、設定まで行うまででした。そこで今回は動作確認を行ったサンプルのソースを確認していこうと思います。

先日ソースからインストールを行った96BoardsGPIOのexampleディレクトリにサンプルはあります。

ドキュメント関係もこちらがいいかなと思います。

github.com

念のためピンアサインも

https://az835927.vo.msecnd.net/sites/iot/Resources/images/PinMappings/DB_Pinout.png

C言語

exampleディレクトリにあるblink.cファイルを開きます。

このプログラムの処理としては以下のような手順になっています。

  1. GPIOのポート指定(といってもポート番号の設定だけ)
  2. 指定したGPIOポートのオープン(open()のような使い方をする模様)
  3. 指定したGPIOポートへのRead/Write(exampleではLチカなのでwriteのみ)

こんな感じになります。なんとなくの印象ですがシステムコールopen()の引数にPathがないような使い方で良いようです。

ではソースを眺めてみます。

【example/blink.c】

#include <stdio.h>

/* 96BoardsGPIO header file */
#include <gpio.h>

/* Just make the pin numbers easier to remember */

int main(int argc, char * argv[])
{
        int x;
        unsigned int gpio_a = gpio_id("GPIO_A");
        /*
         * GPIO_A can also be looked up with:
         *  gpio_a = gpio_by_letter('A');
         *  gpio_a = gpio_by_pin(23);
         */

        // Open the GPIO for use.  Do so by pin number on the
        // Low Speed Expansion Connector.
        if (!gpio_open(gpio_a, "out")) {
                for (x=0; x<10; x++) {
                        digitalWrite(gpio_a, HIGH);
                        usleep(500000);
                        digitalWrite(gpio_a, LOW);
                        usleep(500000);
                }
        } else {
                fprintf(stderr, "Unable to open GPIO_A\n");
                return -1;
        }

        return 0;
}

include部分

いちばん重要なincludeの部分はgpio用のヘッダファイルをincludeファイルします。 この中ではlibsocのヘッダファイルもincludeされていますのでこれだけでいいようです。

/* 96BoardsGPIO header file */
#include <gpio.h>

GPIOのポート指定

あとは、ほぼ上記の手順そのままですが、GPIOのポート指定では3タイプの指定が可能のようです。

        unsigned int gpio_a = gpio_id("GPIO_A");
        /*
         * GPIO_A can also be looked up with:
         *  gpio_a = gpio_by_letter('A');
         *  gpio_a = gpio_by_pin(23);
         */

GPIO_Aのような指定、ポートに割り当てられている文字の指定、ダイレクトにGPIOのpinナンバーの指定、この3つのうちのどれかを指定することになります。 自分が開発を行うのであれば、ピン番号を直接指定するほうが楽かなと思いますけど、96Boards仕様のボードでのソースの移植を行うのであればサンプルと同じ方がいいのかなと思います。動作は同じようです。

指定したGPIOポートのオープン

if (!gpio_open(gpio_a, "out")) {

使用するGPIOのポートとin/outの方向を指定してgpio_open()を呼び出します。

出力処理

                        digitalWrite(gpio_a, HIGH);
                        //略
                        digitalWrite(gpio_a, LOW);
                        //略

あとは、GPIOのピンに対してHIGH/LOWを指定すれば出力が行われます。

make

そのファイルをmakeしてみると以下のようなWarningが発生しますが、成功します。

$ make
gcc -DPACKAGE_NAME=\"96BoardsGPIO\" -DPACKAGE_TARNAME=\"96boardsgpio\" -DPACKAGE_VERSION=\"0.1\" -DPACKAGE_STRING=\"96BoardsGPIO\ 0.1\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"96boardsgpio\" -DVERSION=\"0.1\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -I.    -l96BoardsGPIO -g -O2 -MT blink-blink.o -MD -MP -MF .deps/blink-blink.Tpo -c -o blink-blink.o `test -f 'blink.c' || echo './'`blink.c
blink.c: In function ‘main’:
blink.c:24:4: warning: implicit declaration of function ‘usleep’ [-Wimplicit-function-declaration]
    usleep(500000);
    ^~~~~~
mv -f .deps/blink-blink.Tpo .deps/blink-blink.Po
/bin/bash ../libtool  --tag=CC   --mode=link gcc -l96BoardsGPIO -g -O2   -o blink blink-blink.o  -lsoc
libtool: link: gcc -g -O2 -o blink blink-blink.o  -l96BoardsGPIO -lsoc

usleep()が明示的に宣言されてないよっていう感じなので宣言をすればWarningはなくなると思います。具体的にはinclude部分で#include <unistd.h>を追加すればOKです。

【修正前】

#include <stdio.h>

/* 96BoardsGPIO header file */
#include <gpio.h>

【修正後】

#include <stdio.h>
#include <unistd.h>

/* 96BoardsGPIO header file */
#include <gpio.h>

変更すると

$ make
gcc -DPACKAGE_NAME=\"96BoardsGPIO\" -DPACKAGE_TARNAME=\"96boardsgpio\" -DPACKAGE_VERSION=\"0.1\" -DPACKAGE_STRING=\"96BoardsGPIO\ 0.1\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"96boardsgpio\" -DVERSION=\"0.1\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -I.    -l96BoardsGPIO -g -O2 -MT blink-blink.o -MD -MP -MF .deps/blink-blink.Tpo -c -o blink-blink.o `test -f 'blink.c' || echo './'`blink.c
mv -f .deps/blink-blink.Tpo .deps/blink-blink.Po
/bin/bash ../libtool  --tag=CC   --mode=link gcc -l96BoardsGPIO -g -O2   -o blink blink-blink.o  -lsoc
libtool: link: gcc -g -O2 -o blink blink-blink.o  -l96BoardsGPIO -lsoc

Warningはなくなりました。

入力

digitalWrite()でLチカができたので今度は入力もやってみたいなあと思いました。

#include <stdio.h>
#include <unistd.h>

#include <gpio.h>

int main(int argc, char * argv[])
{
        int x;
        int v;
        unsigned int gpio_b = gpio_id("GPIO_B");

        if (!gpio_open(gpio_b, "in")) {
                for (x=0; x<3; x++) {
            v = digitalRead(gpio_b);
                        if (v != -1){
                                if (v == HIGH){
                                        printf("HIGH\n");
                                }
                                else {
                                        printf("LOW\n");
                                }
                        }
                        usleep(500000);
                }
        } else {
                fprintf(stderr, "Unable to open GPIO_B\n");
                return -1;
        }

        return 0;
}

このようなファイルにしてタクトスイッチの状態を調べたのですが、どうしてもうまくいきません。値が固定になっているような気がします。スイッチを押しても離してもHIGHのままで、スイッチ回路を諦めてGNDに直結してもNGでした。

$ make ; sudo ./blink
HIGH
HIGH
HIGH

GPIO_Bを使用していたのでもしかしてGPIOのピン側に問題があるのかなと思い、output側でテストすると問題なくLチカはできました。

その後、同じプログラムを実行すると

$ sudo ./blink
LOW
LOW
LOW

今度は固定的にLOWのままになってしまいました。起動時はHIGHで、変更があった際にはそのあとの値が保持されている様です。

ちょっと自分にはお手上げ感ありです。 inputのサンプル実験している人も見当たらず。うーん。

おわりに

Lチカが終わったので結構安心していたのですが、入力に関してはまだうまく行っていません。もう少し調べたいと思います。

【自分だけではなかった…】DragonBoard 410c(Debian)の定期的なリブート対策

DragonBoard 410c(Debian)の定期的なリブート対策

どうもDragonBoardでリブートが頻発するのは自分だけの現象ではなかったようです。 Facebookでも同じ現象の方が多くなってきているようです(?)

このエントリーは過去のエントリーからの継続ネタになります。概ねの解決編となります。

uepon.hatenadiary.com

uepon.hatenadiary.com

しかし、Bluetoothをオフにして、HDMIも接続しなければほとんどリブートしないみたいですね。syslogの内容でvblank time outという部分みると、もしかしたらHDMIの方が原因なのかも…?

前回のエントリーではこういう感じで締めくくってみたのですが、実際に実験をしてみました。

Bluetoothを有効化する

Bluetoothを無効化していたので、まずは有効化させます。

$ sudo systemctl enable bluetooth.service
$ sudo systemctl start bluetooth.service

HDMIを外す

そして、本体からMHDMIケーブルを外して再起動します。

$ tail -f /var/log/messages

一応、syslogを確認しながら長時間動作を確認します。 開始から一日以上経ちましたが、安定して動作しているようです。

原因は…

本当の原因はHDMI側の処理だったのかなと思います。

自分の場合、実際にはヘッドレスな運用をすることがほとんどなので、これであれば問題ないかなと思いました。とはいうもののXを使いたいということはたまにあります。例えば、OpenCVなどで画像を表示したいという場合などです。

そこでWindowsリモートデスクトップ接続からも使えるようにします。

リモートデスクトップ接続の設定を行う。

過去に行ったRaspberryPiでの設定をベースに行います。

uepon.hatenadiary.com

念のため、x11vncのパッケージがあるか確認します。

$ sudo apt-chache search x11vnc
ssvnc - Enhanced TightVNC viewer with SSL/SSH tunnel helper
x11vnc - VNC server to allow remote access to an existing X session
x11vnc-data - data files for x11vnc

無事存在していました。ではインストール作業を行います。

$ sudo apt-get install xrdp
$ sudo apt-get install x11vnc

これでOKです。

x11vncの設定

VNC接続用のパスワードファイルを作成します。

$ x11vnc -storepasswd
Enter VNC password: 
Verify password:    
Write password to /home/linaro/.vnc/passwd?  [y]/n 
Password written to: /home/linaro/.vnc/passwd

これで準備は完了です。コマンドラインからx11vncを起動します。-usepwは先程作成したパスワードファイルを使用するという意味になります。

$ x11vnc -usepw
03/06/2017 09:46:46 -usepw: found /home/linaro/.vnc/passwd
03/06/2017 09:46:46 x11vnc version: 0.9.13 lastmod: 2011-08-10  pid: 2998
03/06/2017 09:46:46 XOpenDisplay("") failed.
03/06/2017 09:46:46 Trying again with XAUTHLOCALHOSTNAME=localhost ...
03/06/2017 09:46:46 
03/06/2017 09:46:46 *** XOpenDisplay failed. No -display or DISPLAY.
03/06/2017 09:46:46 *** Trying ":0" in 4 seconds.  Press Ctrl-C to abort.
03/06/2017 09:46:46 *** 1 2 3 4 
03/06/2017 09:46:50 *** XOpenDisplay of ":0" successful.
03/06/2017 09:46:50 
03/06/2017 09:46:50 Using X display :0
03/06/2017 09:46:50 rootwin: 0x205 reswin: 0x2200001 dpy: 0xe4366350
03/06/2017 09:46:50 
03/06/2017 09:46:50 ------------------ USEFUL INFORMATION ------------------
03/06/2017 09:46:50 X DAMAGE available on display, using it for polling hints.
03/06/2017 09:46:50   To disable this behavior use: '-noxdamage'
03/06/2017 09:46:50 
03/06/2017 09:46:50   Most compositing window managers like 'compiz' or 'beryl'
03/06/2017 09:46:50   cause X DAMAGE to fail, and so you may not see any screen
03/06/2017 09:46:50   updates via VNC.  Either disable 'compiz' (recommended) or
03/06/2017 09:46:50   supply the x11vnc '-noxdamage' command line option.
03/06/2017 09:46:50 
03/06/2017 09:46:50 Wireframing: -wireframe mode is in effect for window moves.
03/06/2017 09:46:50   If this yields undesired behavior (poor response, painting
03/06/2017 09:46:50   errors, etc) it may be disabled:
03/06/2017 09:46:50    - use '-nowf' to disable wireframing completely.
03/06/2017 09:46:50    - use '-nowcr' to disable the Copy Rectangle after the
03/06/2017 09:46:50      moved window is released in the new position.
03/06/2017 09:46:50   Also see the -help entry for tuning parameters.
03/06/2017 09:46:50   You can press 3 Alt_L's (Left "Alt" key) in a row to 
03/06/2017 09:46:50   repaint the screen, also see the -fixscreen option for
03/06/2017 09:46:50   periodic repaints.
03/06/2017 09:46:50 
03/06/2017 09:46:50 XFIXES available on display, resetting cursor mode
03/06/2017 09:46:50   to: '-cursor most'.
03/06/2017 09:46:50   to disable this behavior use: '-cursor arrow'
03/06/2017 09:46:50   or '-noxfixes'.
03/06/2017 09:46:50 using XFIXES for cursor drawing.
03/06/2017 09:46:50 GrabServer control via XTEST.
03/06/2017 09:46:50 
03/06/2017 09:46:50 Scroll Detection: -scrollcopyrect mode is in effect to
03/06/2017 09:46:50   use RECORD extension to try to detect scrolling windows
03/06/2017 09:46:50   (induced by either user keystroke or mouse input).
03/06/2017 09:46:50   If this yields undesired behavior (poor response, painting
03/06/2017 09:46:50   errors, etc) it may be disabled via: '-noscr'
03/06/2017 09:46:50   Also see the -help entry for tuning parameters.
03/06/2017 09:46:50   You can press 3 Alt_L's (Left "Alt" key) in a row to 
03/06/2017 09:46:50   repaint the screen, also see the -fixscreen option for
03/06/2017 09:46:50   periodic repaints.
03/06/2017 09:46:50 
03/06/2017 09:46:50 XKEYBOARD: number of keysyms per keycode 10 is greater
03/06/2017 09:46:50   than 4 and 100 keysyms are mapped above 4.
03/06/2017 09:46:50   Automatically switching to -xkb mode.
03/06/2017 09:46:50   If this makes the key mapping worse you can
03/06/2017 09:46:50   disable it with the "-noxkb" option.
03/06/2017 09:46:50   Also, remember "-remap DEAD" for accenting characters.
03/06/2017 09:46:50 
03/06/2017 09:46:50 X FBPM extension not supported.
03/06/2017 09:46:50 X display is capable of DPMS.
03/06/2017 09:46:50 --------------------------------------------------------
03/06/2017 09:46:50 
03/06/2017 09:46:50 Default visual ID: 0x21
03/06/2017 09:46:50 Read initial data from X display into framebuffer.
03/06/2017 09:46:50 initialize_screen: fb_depth/fb_bpp/fb_Bpl 24/32/4096
03/06/2017 09:46:50 
03/06/2017 09:46:50 X display :0 is 32bpp depth=24 true color
03/06/2017 09:46:50 
03/06/2017 09:46:50 Autoprobing TCP port 
03/06/2017 09:46:50 Autoprobing selected TCP port 5900
03/06/2017 09:46:50 Autoprobing TCP6 port 
03/06/2017 09:46:50 Autoprobing selected TCP6 port 5900
03/06/2017 09:46:50 listen6: bind: Address already in use
03/06/2017 09:46:50 Not listening on IPv6 interface.
03/06/2017 09:46:50 fb read rate: 91 MB/sec
03/06/2017 09:46:50 fast read: reset -wait  ms to: 10
03/06/2017 09:46:50 fast read: reset -defer ms to: 10
03/06/2017 09:46:50 The X server says there are 16 mouse buttons.
03/06/2017 09:46:50 screen setup finished.
03/06/2017 09:46:50 

The VNC desktop is:      linaro-alip:0
PORT=5900

******************************************************************************
Have you tried the x11vnc '-ncache' VNC client-side pixel caching feature yet?

The scheme stores pixel data offscreen on the VNC viewer side for faster
retrieval.  It should work with any VNC viewer.  Try it by running:

    x11vnc -ncache 10 ...

One can also add -ncache_cr for smooth 'copyrect' window motion.
More info: http://www.karlrunge.com/x11vnc/faq.html#faq-client-caching

これで接続準備ができましたので接続テストを行います。

リモートデスクトップ接続ツールを起動して

f:id:ueponx:20170603145950p:plain

無事に接続ができるとxrdpの接続画面が表示されます。

f:id:ueponx:20170603150146p:plain

Session : vnc-any IP : DragonboadのIPアドレス port : 5900 password : 先程設定したパスワード

と入力して【OK】ボタンをクリックします。

f:id:ueponx:20170603150836p:plain

無事に接続できました。(画面は接続後ターミナルを立ち上げてみています) あとは、自動で起動するように設定を行っていきます。 とりあえず、Ctrl+cでx11vncを終了します。

設定ファイルを生成します。

$ mkdir /home/linaro/.config/autostart/
$ vim /home/linaro/.config/autostart/x11vnc.desktop

【x11vnc.desktop】

[Desktop Entry]
Encoding=UTF-8
Type=Application
Name=X11VNC
Comment=
Exec=x11vnc -forever -display :0 -rfbauth /home/linaro/.vnc/passwd
StartupNotify=false
Terminal=false
Hidden=false

これでOKです。後は自動ログインの設定を行えば問題ないのですが、RaspberryPiの様にraspi-configで設定ができないのですが…何もしなくても再起動するとx11vncが起動していました。ターミナルからのログインはしていません。

なんとかこれでXが使用できるようになりました。

おわりに

無事にXも使えるし、Bluetoothも使えるようになりました。これでおおよその問題も解決できたかなと思います。

ただ、リモートで使うXがRaspberryPiよりもかなり遅く感じます。

DragonBoard 410c(Debian)の再起動の原因を調べる

DragonBoard 410c(Debian)の再起動の原因を調べる

以前、DragonBoard 410cの再起動が定期的に発生する事象があって、Bluetoothの機能を停止したら治った(収まった)というエントリーを書きました。

uepon.hatenadiary.com

その後コミュニティで以下のようなログが出ると死ぬよって話がありました。自分はsyslogのとり方などは詳しくないのであらためて調べることにしました。

[ 5088.293666] msm 1a00000.mdss: vblank time out, crtc=0
[ 5088.357655] msm 1a00000.mdss: vblank time out, crtc=0

ちなみに自分がDragonBoard死んだかどうかを確認するときにつかっていたのはbashのループとか、watchコマンドでした。以下は10秒おきにコマンドをdate実行する例です。

bashでループさせる場合】

$ while true; do date; sleep 10s; done

【watchを使う場合】

$ watch -n 10 date

ググって以下のコマンドがいいかなと思いました。

$ tail -f /var/log/messages

あとはTeratermのログ記録モードにしておけば再起動したおおよその時刻がわかります。自分のDragonBoardも以下のようなログとともに再起度していたので原因は同じ様です。

Jun  1 22:41:23 linaro-alip kernel: [  383.872879] random: crng init done
Jun  1 22:46:41 linaro-alip kernel: [  701.710271] msm 1a00000.mdss: vblank time out, crtc=0
Jun  1 22:46:41 linaro-alip kernel: [  701.766224] msm 1a00000.mdss: vblank time out, crtc=0

終わりに

しかし、Bluetoothをオフにして、HDMIも接続しなければほとんどリブートしないみたいですね。

syslogの内容でvblank time outという部分みると、もしかしたらHDMIの方が原因なのかも…?