1

Beagle Board rev.BにUbuntu9.04 ARM版をインストール

既に9.04を動かしてたんだけど、Arduinoにつないだセンサーの値をずっと読ませていたらkernel panicになってブート不能になっていたので再インストールした。大量のセクタエラーが出ていたので、SDカードに何度も書き込みすぎて壊れた気がする。

前回のインストール方法はメモを取っておいたんだけど、公開されていたrootfsが削除されていてインストール方法も変わっていたのでメモしなおしておく。
同じ9.04なのにUSBシリアル変換チップのFT232RLやemobileや、300GBのUSB外付けHDDが接続できた。ファームウェアをアップデートしたからか、Ubuntuのせいかは不明。

USBメモリとemobileを接続して動いているところ
beagleboard + emobile

WiFiとmoxaとUSBメモリ
USBメモリ、WiFi、moxaを接続

手順

  1. Beagle Boardのファームウェアをアップデート
  2. SDカードにパーティションを切る
  3. Ubuntu9.04 ARM版のrootfsを作る
  4. uImageを作る
  5. boot.scrを作る
  6. UbuntuをSDカードに書き込む
  7. 起動する
  8. emobileやWiFi、Arduino、USB外付けHDDとかを接続してみる

■Beagle Boardの起動手順おさらい
まずボード自体のファームウェアがあって、専用シリアルケーブルで接続して設定できる。ファームウェアはSDカードにu-boot.binという名前にして入れておくとアップデートできる。色々改善されてるみたいなので今回は最初にアップデートしておいた。

起動は、まずボードのファームウェア→第1パーティションのboot.scr→第1パーティションのuImage→第2パーティションのLinux OS
の順で行われる。
uImageはOS毎に違う物を使う。第2パーティションのOSは自分でビルドして作る物で、rootfsとも呼ばれる。

つまりboot.scrとuImageとrootfsを用意して、SDカードに書き込まなければならない。
ARM用イメージをビルドするツールはLinuxでしか動かないのと、ファイルシステムの関係でここから先の作業は全てUbuntuデスクトップマシンで行った。でもVMWareのUbuntでも問題なくできる。


■Beagle Boardのファームウェアをアップデート
新しいSDカードを用意して、先頭に50MB程度のFAT32パーティションを切る。
SDカードのフォーマットはUbuntuのgpartedでやった。

http://elinux.org/BeagleBoardUbuntu#Upgrade_U-Bootに書いてあるとおりにやればいい

SDカードは/media/boot に自動的にマウントされた。
されなかったら
sudo mkdir /media/boot
sudo mount /dev/sdb1 /media/boot
でマウントする。

アップグレード用のu-boot.binをSDカードの第1パーティションに置く。
wget http://rcn-ee.net/deb/tools/u-boot-beagleboard-2009.08+r37+gitr1590f84007e2b50ad346a482fff89195cb04ff4e-r37.bin
sudo mv u-boot-beagleboard-2009.08+r37+gitr1590f84007e2b50ad346a482fff89195cb04ff4e-r37.bin /media/boot/u-boot.bin
sudo umount /media/boot

Beagle Boardの基板上のシリアルポートピンに専用のケーブルで接続してから、電源を入れる。
WindowsならTeraterm、MacならZTerm、Linuxならminicomで接続するといい。

で、u-boot.binを読ませてファームをアップグレードするのだけど俺の使ってるのはrev.Bなので、命令名がwikiに掲載されているのとはちょっと違った。helpコマンドで出てくるのを参考にしてこう打ち込んだ
U-Bootのアップグレード – 橋本詳解より
mmcinit
fatload mmc 0:1 0x80300000 u-boot.bin
nand unlock
nand ecc sw
nand erase 80000 160000
nand write 0x80300000 80000 160000
nand erase 260000 20000
reset


■SDカードにパーティションを切る
Ubuntuマシンを持ってるので、gpartedでSDカードを3つのパーティションに分けた。4GBのSDカードを使った。あんまり怪しいメーカーのは使わない方がよさそう。
先頭から順に
  • FAT32で100MB程度、名前はboot
  • ext3で3GBちょっと、名前はubuntu
  • swapで700MBぐらい
のパーティションを作ったと思う。


■Ubuntu9.04 ARM版のrootfsを作る
http://elinux.org/BeagleBoardUbuntuを参考にビルドする。

rootstockの最新版をダウンロードしてきて、rootstockのバイナリを手に入れる。
sudo apt-get install qemu
wget http://ports.ubuntu.com/pool/main/d/debootstrap/debootstrap_1.0.20~jaunty1_all.deb
sudo dpkg -i debootstrap_1.0.20~jaunty1_all.deb
wget http://launchpad.net/project-rootstock/trunk/0.1/+download/rootstock-0.1.3.tar.gz
tar -zxvf rootstock-0.1.3.tar.gz
cd rootstock-0.1.3


ARM用ubuntu9.04(jaunty)のビルド。4GBのSDカードに作った3GBのパーティションに入れるのでimagesizeで指定している。
sudo ./rootstock --fqdn beagleboard --login ubuntu --password ubuntu --imagesize 3G --seed gcc,make,linux-firmware,wireless-tools,usbutils --dist jaunty --serial ttyS2 --kernel-image http://rcn-ee.net/deb/kernel/beagle/jaunty/v2.6.29-58cf2f1-oer44.1/linux-image-2.6.29-oer44.1_1.0jaunty_armel.deb
デスクトップ環境が欲しければ、–seedにubuntu-desktopやxfce4を追加指定する。

それなりに時間がかかる。CPU2.7GHzの環境で2時間ぐらいかかった。
これでarmel-rootfs-[日付].tgzとvmlinuz-2.6.29-oer44.1できる。vmlinuz-*はuImageを作るのに使う。


■uImageを作る
vmlinuz-*からuImageを作る。
sudo apt-get install uboot-mkimage
which mkimage
mkimage -A arm -O linux -T kernel -C none -a 0x80008000 -e 0x80008000 -n "Linux" -d ./vmlinuz-* ./uImage
できた。


■boot.scrを作る
ブートスクリプトを作る。

ubuntu.cmd というテキストファイルを作る
setenv bootcmd 'mmc init; fatload mmc 0:1 0x80300000 uImage; bootm 0x80300000'
setenv bootargs 'console=ttyS2,115200n8 console=tty0 root=/dev/mmcblk0p2 rootwait rootfstype=ext3 ro vram=12M omapfb.mode=dvi:1024x767MR-16@60'
boot
dvi:の所の解像度は自分の画面環境に合わせないと出ない。


beagle boardのbootパーティションに書き込むバイナリ形式にする
mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "Ubuntu 9.04" -d ./ubuntu.cmd ./ubuntu.scr



■UbuntuをSDカードに書き込む
SDカードを刺したらマウントされると思うけど、手動マウントの場合
sudo mkdir /media/boot
sudo mkidr /media/ubuntu
sudo mount /dev/sdb1 /media/boot
sudo mount /dev/sdb2 /media/ubuntu
でマウント。

uImage, ubuntu.scr, rootfsの3つを書き込む
sudo cp uImage /media/boot/
sudo cp ubuntu.scr /media/boot/boot.scr
sudo tar xfp armel-rootfs-*.tgz -C /media/ubuntu


最初からキーボードは認識するが、ネットワークに接続できないとemacsがインストールできないので、SDカード上でUbuntuの設定をいじっておく。
/media/ubuntu/etc/netowrk/interfaces を編集
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
これでUSBイーサネットアダプタが認識する。


/media/ubuntu/etc/fstab を編集。swapを有効にする
proc /proc proc defaults 0 0
/dev/mmcblk0p3 swap swap defaults 0 0

取り外す
cd /media/boot
sync
cd /media
sudo umount /media/boot
cd /media/ubuntu
sync
cd /media
sudo umount /media/ubuntu
うちのSDカードリーダだと手動でsyncしないとなかなか書き込んでくれなかった


■起動する
USBにハブ経由でLANとキーボードを接続、HDMIで画面も起動、SDカードを入れてbeagle boardを起動する。
念のためにシリアルケーブルを接続しておいて見ておいた方がいい。カウントダウンを10秒待つか自分でbootって打ちこんでUbuntu9.04を起動させる。

rootstockでイメージ作った時に指定したusername,passwordでログインする。
パスワードを変更してsshdを起動すれば、あとは普通のLinuxとして使える。


■emobileやWiFi、Arduino、USB外付けHDDとかを接続してみる
USBデバイスがちゃんと認識するようになったのでいろいろできる。特にHDDかUSBメモリを付けてそっちに作業領域とswapを置くと、SDカードが壊れる事が少なくなってよいかもしれない。

0

Cでgearman workerを書いてRubyのclientから呼び出す

gearmandをソースからインストールして、Cライブラリのlibgearmanが使えるようになった。

これでC言語でworkerを作ってRubyのclientから呼び出せる。環境はUbuntu9.04とgearmand0.11


■Cでworkerを書く
str_reverseというアビリティを持つworkerを作る。
ほぼAPIドキュメントのままだが、jobの引数を受け取るのと、値を返せるようにがんばった。ジョブ失敗した時とかのエラー処理全然書いてない。たぶんenum gearman_return_tを返せばいいんだろうけど

strreverse-worker.c

// 文字列をreverseして返すworker
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libgearman/gearman.h>

void *job_str_reverse(gearman_job_st *job, void *cb_arg, size_t *result_size,
       gearman_return_t *ret_ptr)
{
  char *str = (char *)gearman_job_workload(job);
  int len = strlen(str);
  printf("str:%s  length:%d\n", str, len);

  char reverse[len];
  for(int i = 0; i < len; i++){
    reverse[i] = str[len-i-1]; // 文字列を逆にする
  }

  char *result = strdup(reverse); // 結果の文字列はコピーしてポインタで返す
  *result_size= gearman_job_workload_size(job);
  *ret_ptr= GEARMAN_SUCCESS;
  return result;
}


int main(int argc, char *argv[])
{
  gearman_return_t ret;
  gearman_worker_st worker;

  gearman_worker_create(&worker);
  gearman_worker_add_server(&worker, "127.0.0.1", 7003);
  gearman_worker_add_function(&worker, "str_reverse", 0, job_str_reverse, NULL);
  
  while(1) gearman_worker_work(&worker); // ジョブ登録したらループで待つ

  gearman_worker_free(&worker);
  return 0;
}


Makefile
# Linux用Makefile
SRC = strreverse-worker.c
DST = strreverse-worker

prefix=/usr/local
INCPATH=$(prefix)/include
LIBPATH=$(prefix)/lib

GEAR_LIBS=$(LIBPATH)/libgearman.a

all:
g++ -O $(SRC) -o $(DST) -I$(INCPATH)/libgearman -L. -L$(LIBPATH) $(GEAR_LIBS)
makeするとstrreverse-workerができる。


■Rubyでclientを書く
xing-gearman-serverを使うといい

client書く。実行時引数を一つずつstr_reverseに登録するclient。
strreverse-client.rb
#!/usr/bin/env ruby
require 'rubygems'
require 'gearman'

c = Gearman::Client.new(['localhost:7003'])
taskset = Gearman::TaskSet.new(c)

ARGV.each{|str|
  puts "add task #{str}"
  task = Gearman::Task.new('str_reverse', str)
  task.on_complete{|result|
    puts "return: #{str} => #{result}" # 文字列が逆になって返ってくる
  }
  taskset.add_task(task)
}
taskset.wait(100) # wait 100(sec)


■動かしてみる
worker動かす
./strreverse-worker

clientから3つ文字列登録
ruby strreverse-client.rb hello konitiwa asdfhujiko

すると文字列返ってくる
add task hello
add task konitiwa
return: hello => olleh
add task asdfhujiko
return: konitiwa => awitinok
return: asdfhujiko => okijuhfdsa

worker側の標準出力はこうなってた
str:hello  length:5
str:konitiwa length:8
str:asdfhujiko length:10


workerを3つバックグラウンドで起動しておく
./strreverse-worker&
./strreverse-worker&
./strreverse-worker&


凄い勢いで処理されてるので非同期になってるのかよくわからない
ruby strreverse-client.rb hello konitiwa asdfhujiko aaiiaaiiaaii hogehogehogehoge mmmasdffajkl23rwdfv ahsdga9sd8uf9p8u nbjkasdoif98pu
add task hello
add task konitiwa
return: hello => olleh
add task asdfhujiko
return: konitiwa => awitinok
add task aaiiaaiiaaii
return: asdfhujiko => okijuhfdsa
add task hogehogehogehoge
return: aaiiaaiiaaii => iiaaiiaaiiaa
add task mmmasdffajkl23rwdfv
return: hogehogehogehoge => egohegohegohegoh
add task ahsdga9sd8uf9p8u
return: mmmasdffajkl23rwdfv => vfdwr32lkjaffdsammm
add task nbjkasdoif98pu
return: ahsdga9sd8uf9p8u => vfdu8p9fu8ds9agd
return: nbjkasdoif98pu => vfdu8up89fiods

1

Rubyでwavファイルをいじる WavFile.rbを作った

gemにしました → 橋本商会 wavファイルをRubyで編集する

*****

Rubyでwavファイルを操作するためにWavFile.rbを作った。スピーカから音を鳴らすのではなくて、wavファイルそのものをいじって合成したりつなげたり、逆再生や左右反転させたりした後ファイルに書き出す為に作った。

packやunpackを使ってRubyでバイナリを読み書きする部分でかなり苦戦したけど、WAVファイル – MoonRock@MoonRock/A mere diary (2002-2)(7年も前に同じような事やってる!)がすごく参考になった。attr_accessorとかも知らなかったから勉強になった。


http://shokai.org/projects/ruby-wavfile/にサンプルを色々置いておく。


例えば、逆再生のwavファイルを作るコードはこう書ける
reverseWav.rb

#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
# wavファイルを逆再生にして保存する
# ステレオの場合、左右チャンネルが入れ替わってしまうがまあいい
require File.dirname(__FILE__) + '/WavFile'

if ARGV.size < 2
  puts 'ruby reverseWav.rb input.rb output.wav'
  exit 1
end

f = open(ARGV.shift)
format, chunks = WavFile::readAll(f)
f.close

puts format.to_s

dataChunk = nil
chunks.each{|c|
  puts "#{c.name} #{c.size}"
  dataChunk = c if c.name == 'data' # 波形の入っているchunkを探す
}
if dataChunk == nil
  puts 'no data chunk'
  exit 1
end

# 波形をいじる
bit = 's*' if format.bitPerSample == 16 # int16_t
bit = 'c*' if format.bitPerSample == 8 # signed char
wavs = dataChunk.data.unpack(bit) # 16bit or 8bitずつbinaryから読み出し
dataChunk.data = wavs.reverse.pack(bit) # 逆再生、binaryに戻す

open(ARGV.shift, "w"){|out|
  WavFile::write(out, format, [dataChunk])
}
波形部分をRubyの配列として取り出して処理する。ファイルに戻す部分はWavFile.rbがやってくれるようにした。

実行
ruby reverseWav.rb test.wav reverse.wav
結果
フォーマットID: 1
チャンネル数: 1
サンプリングレート: 8000 (Hz)
byte per sec: 16000
bit per sample: 16
ブロックサイズ: 2
data 4077172



主にできる事と、処理の手順はこんな感じ
  1. wavファイルのファイルヘッダ、フォーマットチャンク、データチャンクをメモリに読み込む。WavFile.rbではファイルヘッダとフォーマットチャンクをまとめて管理するためにWavFile::Formatクラスを作ってある。
  2. データチャンクを波形として扱う処理は時前でやってください。ステレオ・モノラルやbpsなどのフォーマットが全て読み込まれているのでそんなに大変ではないはず。format.bitPerSampleやunpackを使う。ただしCPUのエンディアンが違うとおかしくなるかも。
  3. 最後にいじったデータチャンクをpackでバイト列に戻して、ファイルヘッダと合わせてwavファイルに戻す。


上の例ではWavFile::readAllを使ってフォーマットと全チャンクを読み込んでいるけど、wavファイルにはデータチャンク(波形)以外のチャンクもある。でもデータチャンクとフォーマットさえあれば後は必要ない場合が多いので、フォーマットとデータチャンクのみを取り出す関数も用意してある。
require 'WavFile'
File.open("test.wav"){|file|
  format = WavFile::readFormat(file)
  dataChunk = WavFile::readDataChunk(file)
}

タプルを使ってこう受け取る事もできる
format, dataChunk = WavFile::read(file)

wavファイルへ保存
open("out.wav"){|out|
  WavFile.write(out, format, [dataChunk])
}


他にも色々やった。下にいくほど新しい。
上の方はWavFile.rbのバージョンが古い頃の物なので読み書きまわりが少し違うかもしれないが、解説が書いてあるので列挙しておく。最新のWavFile.rbで動くコードはリポジトリに置いておく


wavファイルの扱いについては、C言語で書かれたこの本を参考にした。この本ではファイルを先頭からseekして逐次処理して結果をwavファイルとして書き込んでいる。
でもwavファイルなんて数百MB程度だから、WavFile.rbではメモリ上で処理した方が後々便利そうだから今回は富豪的に全部メモリに読み込むようにした。
WAVプログラミング—C言語で学ぶ音響処理
北山 洋幸
カットシステム
売り上げランキング: 160207
おすすめ度の平均: 3.0
2 C言語初心者向けでわかりやすいが本格的な音響処理はいまいち
3 分かりやすいが…
4 あまり見かけないジャンルの本ですね



作ってる時に大変だったのは音を出さないとデバッグできないので電車の中で作業するためにイヤホンは必須。
バイナリとRubyのオブジェクトとのやりとりの部分は音で聞いてもなんだかわからない時もあるので、putsで波形を数字としてdumpしてエクセルで描画すると原因がすぐわかる。

0

FT232RLのEEPROMをすごい勢いで書き込む

俺はこの手順で効率よく大量に書き込んでいます


まずデバイスマネージャとMProgを起動して並べる。MProgにはEEPROMをloadしておく。
83f5648ab664ddc5a963416810c1f4ba.png


ターゲットのボードをUSBケーブルに刺す。

するとWindowsが「新しいハードウェアが見つかりました」と報告してくる。
14fe5d204e7bb00ffcc3707cfa10c1b5.png

このまま待っているとデバイスドライバのインストーラが起動してしまうので、
MProgからEEPROMを書き込む。だいたいwindowsのデバイス認識音がしてから3秒後にwriteする。


インストーラより先に書き込み成功すると、インストーラが起動しない。
あらかじめターゲットデバイスのドライバをインストールしてあれば、「使用準備ができました」になる
501a7c01d5793951465148ff1252debd.png


デバイスマネージャで「USB Serial Port」が増えている事を確認。
b361d82d4b05be6b382cbe633eecea07.png

デバイスをUSBケーブルから抜いて、次のデバイスにEEPROMを書き込む。

0

iPhoneからMac経由でdocomoケータイにアドレス帳をコピー

docomoの普通の携帯電話を買ったが、iPhoneからdocomoへのアドレス帳移行の手段が無い。

windowsのiTunesでiPhoneから読み込み→csv形式でドコモdatalinkで携帯電話に転送
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1124847736
という手段があるが、iTunesで読み込む時にoutlookがなければ駄目。windowsアドレス帳形式はドコモdatalinkで転送できない。


今回はiPhone→MacのiTunesでAddress Bookに読み込み→「グループのvcardを書き出し(vcf形式で)」→メールで携帯電話に転送
という手段で移行した。

ただし

  • 検索しやすいようにiPhoneでは読み仮名をローマ字で入力してたが、docomoはカタカナのみ対応
  • vcf形式は1ファイルに複数のvcardを保持できるはずなのに、SH-02Aは先頭のvcardしか読み込んでくれない
  • メールに同時に添付できるファイル数は10個まで

なので読み仮名は全部無くなったし、10個ずつ添付して登録したから面倒だった。


まず、一つのvcfファイルに複数のアドレス帳が入っていても全部読み込める機種なら、MacのAddress Bookからvcfで書き出して
nkf -s phone-addr.vcf > phone-addr-sjis.vcf
でshift jisに文字コードを変えれば読み込めるはず。(そういう機種があるならば)


ファイルを分割するためにスクリプトを書いた
convert-vcard-mac-docomo.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'kconv'

if ARGV.size < 2
puts 'error! 入力ファイルと出力先ディレクトリ名を指定してください'
puts 'ruby convert-vcard-mac-docomo.rb /path/to/input/file.vcf /path/to/output/dir/'
exit 1
end
input = ARGV.shift
output = ARGV.shift
puts output += "/" if !(output =~ /\/$/)

delimiter = "BEGIN:VCARD"
cards = open(input).read.split(/#{delimiter}/m)
cards.shift # 1件目いらない

for i in 0...cards.size do
puts card = delimiter+cards[i]
puts "-"*10
open(output+"#{i}.vcf","w"){|f|
f.puts card.tosjis
}
end

mkdir ~/vcards
ruby convert-vcard-mac-docomo.rb ~/phone-addr.vcf ~/vcards/
で ~/vcards/にたくさんファイルができるので、10件ずつメールに添付して送って登録した。
指が憑かれた。


後で気づいたが、読み仮名はsjisで
SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:ʼヨミガナ;;;;
と書いておくと読み込めるみたい。
俺の場合ローマ字→カタカナに変換しないとならなかったので面倒だが、suikyoを使えば楽にできるかもしれない。