lp6m’s blog

いろいろかきます

Ubuntu on ZYBO Z7-20からPCam 5Cの映像を取得したい(成功)

前回Ubuntu on ZYBO Z7-20からPCam 5Cの映像を取得したい(失敗) - lp6m’s blogの続き。成功したのでまとめておく。

やったこと

前回なぜかyavtaコマンドで画像の取得ができなかった。
Xilinx Forumに質問した。
https://forums.xilinx.com/t5/Embedded-Linux/can-t-get-image-from-PCam-5C-on-Ubuntu-running-on-ZYBO-Z7-20/m-p/882879#M28057

どうやら以下のコマンドでは画像の取得ができた。なぜyavtaだとダメなのかは不明。

v4l2-ctl -d /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat=YUYV --stream-mmap --stream-count=1 --stream-to=test.raw

とりあえずこれで取得できるので、v4l2-ctlコマンドの実装を参考にC++コードを記述する。
コードは以下。
Get image from PCam 5C on Ubuntu running on ZYBO-Z7-20 · GitHub

Ubuntu on ZYBOでapt-get upgrade, apt-get update, apt-get install g++ gccしておく。
特に外部ライブラリを使用しないのでg++ cam.ccでビルドできる。PcamはUbuntu起動前に接続しておく。

以下のおまじないコマンドを叩く

sudo media-ctl -d /dev/media0 -V '"ov5640 2-003c":0 [fmt:UYVY/'1920x1080'@1/'15' field:none]'
sudo media-ctl -d /dev/media0 -V '"43c60000.mipi_csi2_rx_subsystem":0 [fmt:UYVY/'1920x1080' field:none]'
$ ./a.out
bus_info	: platform:video_cap:0
card		: video_cap output 0
driver	: xilinx-vipp
version	: 264448
reqbuf.count : 3
buf.length : 1
buf.m.offset : 3195409312
buf.m.planes[j].length : 4147200
buffers[i].start[j] : 0xb687e000
buf.length : 1
buf.m.offset : 3195409312
buf.m.planes[j].length : 4147200
buffers[i].start[j] : 0xb6489000
buf.length : 1
buf.m.offset : 3195409312
buf.m.planes[j].length : 4147200
buffers[i].start[j] : 0xb6094000
r : 0
store image in array....
write data...

画像が取得できた!
得られたYUYV形式のcamdata.datファイルは以下のPythonコードでpng画像に変換できる。
Convert Raw YUYV image from PCam 5C to png · GitHub

python test.py camdata.dat out.png

Pythonコード内のRGBへの変換が間違っているらしく、緑っぽい画像が出力されるかも・・)

勉強したこと

  • 上に書いたおまじないコマンドは何なのか

これは、V4L2 SubDeviceそれぞれに使用するフォーマットを教えている。SubDeviceに設定されたフォーマットは以下のコマンドで確認できる。

$media-ctl /dev/video0 -p
Media controller API version 4.9.0

Media device information
------------------------
driver          xilinx-video
model           Xilinx Video Composite Device
serial          
bus info        
hw revision     0x0
driver version  4.9.0

Device topology
- entity 1: video_cap output 0 (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video0
	pad0: Sink
		<- "43c60000.mipi_csi2_rx_subsystem":0 [ENABLED]

- entity 5: ov5640 2-003c (1 pad, 1 link)
            type V4L2 subdev subtype Sensor flags 0
            device node name /dev/v4l-subdev0
	pad0: Source
		[fmt:UYVY/1920x1080 field:none]
		-> "43c60000.mipi_csi2_rx_subsystem":1 [ENABLED]

- entity 7: 43c60000.mipi_csi2_rx_subsystem (2 pads, 2 links)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev1
	pad0: Source
		[fmt:UYVY/1920x1080 field:none]
		-> "video_cap output 0":0 [ENABLED]
	pad1: Sink
		[fmt:UYVY/1920x1080 field:none]
		<- "ov5640 2-003c":0 [ENABLED]

V4L2 SubDevice参考:https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/dev-subdev.html
きちんとPCam(OV5640) -> MIPI_CSI2_RX_SubSystem -> video_capにデータが流れるようになっていることがわかる。
この接続はPetaLinuxプロジェクトのデバイスツリー(project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi)内でremote-endpointで指定されている。
以下、system-user.dtsi一部抜粋

&axi_iic_0 {
	...
	ov5640: camera@3c {
		compatible = "ovti,ov5640";
		...
		port {
			ov5640_to_mipi_csi2: endpoint {
				remote-endpoint = <&mipi_csi2_from_ov5640>;
				...
			};
		};
	};
};

&amba_pl {
	video_cap {
		compatible = "xlnx,video";
		dmas = <&v_frmbuf_wr_0 0>;
		...
		ports {
			...
			port@0 {
				...
				vcap_in: endpoint {
					remote-endpoint = <&mipi_csi2_out>;
				};
			};
		};
	};
};


&mipi_csi2_rx_subsystem_0 {
	compatible = "xlnx,mipi-csi2-rx-subsystem-2.0";
	...
	ports {
		...

		port@0 {
			reg = <0>;
			xlnx,video-format = <XVIP_VF_YUV_422>;
			xlnx,video-width = <8>;
			mipi_csi2_out: endpoint {
				remote-endpoint = <&vcap_in>;
			};
		};
		port@1 {
			reg = <1>;
			xlnx,video-format = <XVIP_VF_YUV_422>;
			xlnx,video-width = <8>;
			mipi_csi2_from_ov5640: endpoint {
				...
				remote-endpoint = <&ov5640_to_mipi_csi2>;
			};

		};

	};
};	

これができたのが8月末。
第8回 相磯秀夫杯 FPGAデザインコンテストではこれを使用した。
FPGAでは何の画像処理も行っていない状態で、ソフトウェアに頑張らせた。

次はFrame Buffer Write IPをVDMAに置き換えて、HLSコアを挿入する。
VDMAに置き換えるところまでは昨日できた。
ブログが書くのが下手で、わかってる人しかわからない記事になってしまった気がするけど。。

Ubuntu on ZYBO Z7-20からPCam 5Cの映像を取得したい(失敗)

Digilent社製ZYBO Z7-20でUbuntuを動作させ、PCamの映像を取得したい。
store.digilentinc.com
store.digilentinc.com

git cloneしてサンプルを試す:成功

Petalinuxツールを使用してZYBO上で動作するLinuxカーネル・rootfsを作成することができる。
Digilentgithubにサンプルがあるのでこれをcloneする。
github.com

デフォルトではRAMにrootfsを展開する設定(initramfs)になっているので、githubのREADMEのBoot the newly built files from SDに書いてあるとおりに、SD Bootに変更・system-user.dtsi のbootargsを変更した。

第一パーティションカーネルとイメージ(BOOT.BIN・image.ub)をコピー
第二パーティションにROOTFSをコピー(images/linus/rootfs.tar.gzを展開)

起動確認、githubのREADMEに書いてあるとおりのコマンドでPCamからの映像を取得成功

width=1920
height=1080
rate=15
media-ctl -d /dev/media0 -V '"ov5640 2-003c":0 [fmt:UYVY/'"$width"x"$height"'@1/'"$rate"' field:none]'
media-ctl -d /dev/media0 -V '"43c60000.mipi_csi2_rx_subsystem":0 [fmt:UYVY/'"$width"x"$height"' field:none]'
v4l2-ctl -d /dev/video0 --set-fmt-video=width="$width",height="$height",pixelformat='YUYV'
yavta -c14 -f YUYV -s "$width"x"$height" -F /dev/video0

rootfsをUbuntuに変更

Petalinuxでビルドしたrootfsではapt-getなどのパッケージ管理システムを使用することができない。
ARM用にビルドされたUbuntuのrootfsをダウンロードしてarmhf-rootfs-ubuntu-xenial.tar を第二パーティションに展開
参考;ZYBO-Z7を用いたLチカ(Ubuntu16.04編) - aster_ismの工作室

wget https://rcn-ee.com/rootfs/eewiki/minfs/ubuntu-16.04.3-minimal-armhf-2017-10-07.tar.xz

Ubuntuの起動確認・必要なソフトウェアのインストール

Ubuntuの起動を確認。

v4l-utilsをインストール

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install v4l-utils

※電源が不安定になりapt-get upgrade中にボードが再起動することがあるので、補助電源をボードに接続する・電流が大きいものを使用するなどして対処

yavtaのインストール・yavtaはapt-getでは入らない

sudo apt-get install build-essential
git clone https://github.com/fastr/yavta
cd yavta
make

*画像取得(失敗)
sudoをつけた以下のコマンドを実行

width=1920
height=1080
rate=15
sudo media-ctl -d /dev/media0 -V '"ov5640 2-003c":0 [fmt:UYVY/'"$width"x"$height"'@1/'"$rate"' field:none]'
sudo media-ctl -d /dev/media0 -V '"43c60000.mipi_csi2_rx_subsystem":0 [fmt:UYVY/'"$width"x"$height"' field:none]'
v4l2-ctl -d /dev/video0 --set-fmt-video=width="$width",height="$height",pixelformat='YUYV'
./yavta/yavta -c14 -f YUYV -s "$width"x"$height" -F /dev/video0

yavtaを実行するとエラーが起きる。

Error opening device /dev/video0: neither video capture nor video output supported.

yavtaの実装を見て調べたところ、 yavta.cの121行目でioctl()を使ってデバイスの属性を取得した際にカメラの属性が取得できていない

原因究明

必要なドライバがロードされていないのでは?と思いdmesgやls /sys/moduleの結果を比較したが特に理由は見つからない・・・

また、petalinux-config -c kernelによるカーネルの設定でXilinx Video IPのドライバを、カーネルにビルトインする設定からモジュールに変更してみた。
ビルドしたpetalinuxのrootfsの/libフォルダ内に読み込むべきドライバが生成されるので、それらをubuntuの/libにコピーしてみた。しかし、同様にエラーでカメラの映像を取得することができない・・・

dmesgおよびls /sys/moduleの結果をpetalinuxのときとUbuntuのとき両方を貼っておく。

  • 成功したほうのdmesg

petalinux_dmesg.log · GitHub

  • 失敗したほうのdmesg

ubuntu_dmesg.log · GitHub

  • 成功したほうのls /sys/module

petalinux_sys_module.log · GitHub

  • 失敗したほうのls /sys/module

ubuntu_sys_module.log · GitHub

AR# 50826 『ブロックRAM から OCM へのキャッシュ コヒーレントの CDMA 転送 』を試した

HW関連の研究室でZynq All Programmable SoCを触っています。
正直Xilinxのマニュアルは難しすぎてよくわからない・・・体系的に学べるといいのだけれど。

オンチップメモリ(OCM)への書き込みをテストするために調べていたら、以下のページが見つかった。
https://japan.xilinx.com/support/answers/50826.htmljapan.xilinx.com


今回はこれを試してみた。自分なりの解釈とかのメモを残す。

このアプリケーションは何か

このアプリケーションはBRAMの64箇所に0x01から0x40の値を、OCMの64箇所に0xCDの値をセットした後、CDMA(Central Direct Memory Access)を使用してBRAMからOCMへデータを送信する。送信後OCMの64箇所の値が0x01から0x40になっていれば成功。

CDMA

メモリマップされたアドレス間でデータの送受信を行うコントローラ。プロトコルはAXI4/AXI4-Liteが使用できる。

BRAM

FPGA上に配置することができるRAM。BRAM Generator IPがBRAM本体で、データの送受信はBRAM Controllerで動作させる。

OCM

256KBのオンチップメモリがPS上のAPU内に存在する。ACPポートは直接ここにつながっている?(よくわかっていない)

手順(いつものやつ。この本とかに詳しく書いています。)

1. プロジェクトをダウンロードしてVivadoで開いてビットストリーム生成
2. Export HardwareしてSDK(SDSoC)起動
3. File -> New -> Application Projectを選択、Hello Worldプロジェクトを作成し、添付されているhello_axi_cdma.cの内容をhelloworld.cにコピペ
4. Xilinx Toolsを開いてProgrammable FPGAを選択してビットストリーム書き込み
5. Build Allして実行用のelfファイル作成。右クリックしてRun As -> Launch On Hardware (System Debugger)を選択。
6. TeraTermなどから出力を確認(ポートレート115200に設定)

これで動けばよかったのだけど動かなかった。OCMの値全てが0xCDのままになっていた。

修正箇所

結論から言えば、サンプルソースの53行目を

Xil_SetTlbAttributes(0xFFF00000,0x14c0e);

から

Xil_SetTlbAttributes(0xFFF00000,0x14de2);

に修正。
 あるいは、Xil_SetTlbAttributes(0xFFF00000,0x14c0e);をコメントアウトし、
CDMAによる転送が終了した後の121行目などに、

Xil_DCacheInvalidateRange(dstCPU, 64*8);

を挿入。

Xil_SetTlbAttributesとは何か

色々調べてみると、TRM(テクニカルリファレンスマニュアル)UG585の73ページ図3-5にページエントリのフォーマットが書いてある。
またココによると図のSectionの欄が空欄になっているけどSuperSectionと同じらしい。
TEX[2:0], C, Bなどのビットが大切らしい。DomainとかXNとかnGは謎パラメタ・・・

Xil_SetTlbAttributesはキャッシュのポリシーなどを変更するための関数であるということがわかった。
0x14c0eは2進表記で0001_0100_1100_0000_1110 C=1 B=1 キャッシュ属性は「ライトバック、書き込み割り当てなし」
これだとキャッシュが有効になっているのでCDMAが成功していてもアプリケーションは古い値を参照してしまう。
0x14de2は2進表記で0001_0100_1101_1110_0010 C=0 B=0 キャッシュ属性は「キャッシュ不可」
キャッシュを切ることによってアプリケーションは正しい値を参照することができる。

CDMAやDMAを使用したとき、古い値を参照しないように気を付ける必要があるらしい。
DMAを使用したときは Xil_SetTlbAttributesなんて使っていなかったなと思って、Xil_DCacheInvalidateRangeを試したところ、これでもOKだった。
この関数だと、指定したアドレス範囲のデータに関してのみキャッシュが無効化され、新しい値が参照されるようになる。

その他

DMAを使用したときはVivadoでビットストリームを生成したときに出力されるドライバファイルxaxidma.h内で宣言される関数XAxiDma_SimpleTransferを使用してデータ送受信を行っていた。このサンプルアプリケーションにはそのような関数が含まれておらず、最初は意味がわからなかった。
CDMAのリファレンスを読んでみたところ解決した。
CDMAの制御レジスタを直接変更することでエラー割り込み、終了割り込みの有効化・送受信先アドレスの設定・データ転送開始を制御している。

また、ダウンロードしたサンプルのデザインを実行しても動かなかったので、手作業で回路を作り直した。
Vivado内でBRAMを配置した際にBRAMのサイズが変更できずに困っていたところ、以下のようなリンクを発見した。
https://forums.xilinx.com/t5/Design-Entry/how-to-edit-bram-controller-bram-memory-size/td-p/637284
BRAM GeneratorのWidthとDepthの欄はマスター側によって自動的に決まると書いてあった。
BRAMコントローラでBRAMのサイズを変更できないな~と思っていたら、Address EditorでBRAMコントローラに与えるアドレス範囲を変更することでBRAMのサイズが変更できる。

コード

Xilinxのサンプルコードを修正・コメント文を追加したものをおいておきます。
gist.github.com

分からないことも多いまま試行錯誤しているので、間違っているところなどあれば教えてください。

ICPC2017国内予選に参加しました

久々にブログを書いた
1年前:
lp6m.hatenablog.com

2年前:
lp6m.hatenablog.com

去年と同じメンバーで出た。チーム名はfoldLeft.
特に練習もしていないので自分は簡単な問題を解こうとおもっていた。
自分はABを通してチームメイトがCDを解いた。D解けるのすごい。
46位/368チームでした 2桁になれたのはチームメイトのおかげ。

勉強しないとな~

UbuntuやElementary OSでスリープ後に画面の明るさが変更できないのを解消できた

先日気が狂ってmacOSを消した.
UbuntuベースのElementary OSというOSをインストールした.
なんかスリープ後に画面の明るさが調節できなくてつらかったのでググりまくった.
いろんな情報がでてきたけどどれもダメでつらいなあとおもっていたら,今日はやっとみつけることができた.

まずココに同じ問題が書かれてる.
MacBookAir6-2/Trusty - Community Help Wiki

Mac用にドライバを書いてくれた人がいるみたい.インストールしようとした.READMEにしたがってすすめていく.
make installで以下のようなエラーがでて失敗する.

- SSL error:02001002:system library:fopen:No such file or directory: bss_file.c:175
- SSL error:2006D080:BIO routines:BIO_new_file:no such file: bss_file.c:178
sign-file: certs/signing_key.pem: No such file or directory

つらいと思ってしらべたら、同じのがあった.
github.com
make installできないときは,checkinstallってのを使えばいいらしい.
sudo apt install checkinstall
mba6x_blのディレクトリ内でcheckinstallのコマンドを叩く. なんかパッケージの説明をかけとか言われるので「Macのがめんの明るさ設定する」って書いた.
そしたらディレクトリ内にdebが作成された.checkinstallってのはdebを生成するコマンドらしい?
最後にsudo -i dpkg ~.debでインストール.
READMEに書いてる最後の手順のsudo modprobe mba6x_bl をしたらちゃんと反映された.

たぶんいまのところ動いてるっぽいのでよかった.インターネットすばらしいしMacのドライバかけるのすごい.

おわり.

Yahoo!ボックス からファイルを一括ダウンロードするスクリプト

Yahoo!ボックスとかいうオンラインストレージサービスがあるらしい。
info.box.yahoo.co.jp
アプリが終了してブラウザから1つ1つダウンロードするしかないらしい。助けてくれ!と友人に頼まれた。
しばらくChromeデベロッパーツールで眺めていると、ファイル情報をJSONでやりとりしているだけなようなので、書いた。

はじめはRuby の Mechanize を使って Yahoo! JAPAN にログインする - kaosf’s diaryを参考にしてログイン処理をしていたが、途中からログインできなくなった。Mechanizeだと今どのような状態なのかがわかりにくいので、Selenium-webdriverを使って再現してみると、文字認証を求められていた。
探してみるとrubyでYahoo Japanにログインする。Cookie発行してもらう - それマグで!のような情報がでてきたので、使わせていただいた。
(微妙にCAPCHAのURLの種類が違ったのでそのへんだけ書き換えたりした)
2016/12/30 Windows環境で動作させると,txt以外がファイルが壊れるとの指摘をいただきました。訂正しました。

#参考:http://takuya-1st.hatenablog.jp/entry/20121018/1350587902
#!/usr/bin/env ruby
#coding:utf-8
require 'rubygems'
require 'mechanize'
require 'open-uri'
require 'net/http'
require 'uri'

OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

Id       = 'XXXXXXXXXXXXXXXX'
Password = '****************'
cookie_jar_yaml_path = 'yahoo.yaml'
#Yahoo!ログイン
agent = Mechanize.new
agent.user_agent_alias = 'Windows IE 7'
agent.get('https://login.yahoo.co.jp/config/login?.src=www&.done=http://www.yahoo.co.jp')
agent.page.form_with(name: 'login_form') do |form|
	form.field_with(name: 'login').value = Id
	form.field_with(name: 'passwd').value = Password
	# agent.page.body =~ /\("\.albatross"\)\[0\]\.value = "(.*)"/
	# form.field_with(name: '.albatross').value = $1
	form.click_button
end

#CAPTHCA
str = agent.page.body.match( %r!"https://captcha.yahoo.co.jp:443/[^"]+!).to_s.gsub(/"/,"")
puts str
open(str) do |file|
  open("captcha#{Time.now.to_i}.jpg", "w+b") do |out|
    out.write(file.read)
  end
end
capthca = ''
$stdout.print 'enter captcha:'
captcha = $stdin.readline
puts "i got captcha#{captcha}"
agent.page.forms.first.fields_with(:type=>"text").first.value=captcha
agent.page.forms.first.submit

#CAPTHCA後の再ログイン
f=agent.page.forms[0]
f.fields_with( :name=>"login")[0].value=Id
f.fields_with( :name=>"passwd")[0].value=Password
f.submit


puts agent.page.body.to_s.toutf8

agent.cookie_jar.save_as(cookie_jar_yaml_path)
File.expand_path cookie_jar_yaml_path

これを実行すると、ログイン情報のクッキーがyahoo.yamlというファイルに出力される.

次に、Yahoo!ボックスからファイルを一括ダウンロードするスクリプトを実行する

#Yahoo! Box Downloader
require 'mechanize'
require 'nokogiri'
require 'kconv'
require 'scanf'
require 'date'
require 'uri'
require 'json'
require 'erb'
require 'net/http'
require 'open-uri'
include ERB::Util

cookie_jar_yaml_path = 'yahoo.yaml' #ログイン情報のクッキーを保存したファイル
filenum_of_page = 100 #一度に読み込むファイル数 20,50,100のどれか

#Yahoo!Boxへアクセス
agent = Mechanize.new
agent.user_agent_alias = 'Windows IE 7'
agent.cookie_jar.load(cookie_jar_yaml_path)
page = agent.get('https://box.yahoo.co.jp/user/viewer')	


#Javascriptの文字列からsid,uniqid,crumb,appidを取り出す
tmp_rst = page.search('script')[0]

user_parmsstr = tmp_rst.to_s.split("\n")[2].split(',')
crumb_parameter = tmp_rst.to_s.split("\n")[3].split(',')
appid_parameter = tmp_rst.to_s.split("\n")[4].split(',')

sid = user_parmsstr[0].scanf("    User  = {\'sid\':\"%s\"")[0].to_s
topuniqid = user_parmsstr[1].scanf(" \'uniqid\':\"%s\"},")[0].to_s
crumb = crumb_parameter[1].scanf("'bcrumb':\"%s")[0].to_s
appid = appid_parameter[0].scanf("\t\t'appid':\'%s")[0].to_s
puts appid
#scanfうまくいかないのでうしろの"を消す 正規表現ちゃんとかくべき^^;
sid = sid[0,topuniqid.index("\"",2)+1]
topuniqid = topuniqid[0,topuniqid.index("\"",2)]
crumb = crumb[0,crumb.index("\"",2)]
appid = appid[0,appid.index("'",2)]
puts "sid = #{sid}"
puts "uniqid = #{topuniqid}"
puts "crumb = #{crumb}"
puts "appid = #{appid}"

#ここから巡回してファイルをダウンロード	
folderList = Array.new
folderList.push(topuniqid)
#folderListが空になるまで巡回する
while folderList.size != 0 do
	#folderListから一つ取り出す
	nowuniqid = folderList.pop
	#そのフォルダ内のファイルのリストが書かれたJSONを取得する
	urlstr = "https://box.yahoo.co.jp/api/v1/filelist/" + sid + "/" + nowuniqid + "?_=" + DateTime.now.strftime('%Q').to_s + "&"
	urlstr << "results=#{filenum_of_page}&start=1&output=json&sort=%2Bname&filetype=both&meta=1&thumbnail=1&tree=1&sharemembercount=1&ownerinfo=1&boxcrumb="
	urlstr << url_encode(crumb)
	agent.get(urlstr)
	jsonstr = JSON.parse(agent.page.body.to_s)
	# 複数ページが存在する場合はまず全ページたどってファイル情報を入手
	filenum = jsonstr['ObjectList']['TotalResultsAvailable'].to_s
	unless jsonstr['ObjectList']['Object'] == nil
		jsonstr['ObjectList']['Object'].each do |object|
			type = object['Type'].to_s
			name = object['Name'].to_s
			uniqid = object['UniqId'].to_s
			dlurl = object['Url'].to_s
			path = "." + object['Path'].to_s #パスの先頭にドットをつけないとうまく相対パスにならない
			#ファイルかフォルダかで処理を分岐
			if(type == 'file') then
				dlurl << "?appid=#{appid}&error_redirect=1&done=https%3A%2F%2Fbox.yahoo.co.jp%2Ferror%2Fdownload_error&boxcrumb="
				dlurl << url_encode(crumb)
				#dlurlからリダイレクトされたURLを取得 これがダウンロードリンク
				agent.get(dlurl)
				redirect_link = agent.page.uri.to_s
				#ファイルを保存
				#File.write(path, Net::HTTP.get(URI.parse(redirect_link)))
				open(redirect_link) do |file|
					open(path, "w+b") do |out|
						out.write(file.read)
					end
				end
				puts "Download #{path}"
			elsif(type == 'dir') then
				#folderListに追加してあとで巡回
				folderList.push(uniqid)
				Dir.mkdir(path)
			end
		end
	end
end

詳しく解説してもたぶん需要なさそうなので、コードはりつけておしまい。
sleepをはさんで、負荷かけないようにしてつかいましょう。

一応gistこちらも修正しました[2016/12/30]

https://gist.github.com/lp6m/5913c1ef770f75825b00081a6ed7f671
https://gist.github.com/lp6m/a4e927963e218884e2a843e40e7a22b5

FPGAを買った。

計算機科学実験及演習3(ハードウェア)FPGAを触った。パイプライン処理くらいはつくったけどバグがでてしまってソートコンテスト出れなかった。
FPGA面白いな~と思って実験でつかってるボードが何円するのか調べたら10万以上してびっくりした。

これを買って組み立ててほんのすこしだけ触った。
https://twitter.com/lp6m/status/755416445589164032

で、友達がもうちょっと7セグとかスイッチとか標準装備してるやつ買おうって言ったので便利そうだし買った。
https://twitter.com/lp6m/status/757829385953042432

www.terasic.com.tw

試験が終わったら色々やってみたい。夏休みにどこまでいじれるかな。