Mbed OS version of IoT.js implementation running on GR-PEACH
ビルド方法
ビルド環境セットアップ
Host PC要件 : Ubuntu 16.04 (64-bit)
1. 以下のコマンドを実行し、下表に示すツールをインストールします。
$ sudo apt update $ sudo apt upgrade $ sudo apt install [Package]
Package | Version |
build-essential | 12.1ubuntu2 |
gyp | 0.1+20150913git1f374df9-1ubuntu1 |
mercurial | 3.7.3-1ubuntu1 |
cmake | 3.5.1-1ubuntu3 |
git | 1:2.7.4-0ubuntu1.4 |
python2.7 | 2.7.12-1ubuntu016.04.3 |
valgrind | 1:3.11.0-1ubuntu4.2 |
python-pip | 8.1.1-2ubuntu0.4 |
2. 以下のコマンドを実行してMbed OS用ビルドツール mbed CLIをインストールします。
$ sudo -H pip install mbed-cli
3. GNU Arm Embedded Toolchainをインストールします。
- 下記URLからLinux用パッケージ (gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2) をダウンロードしてください。
https://developer.arm.com/-/media/Files/downloads/gnu-rm/6-2017q2/gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2?revision=2cc92fb5-3e0e-402d-9197-bdfc8224d8a5?product=GNU%20Arm%20Embedded%20Toolchain,64-bit,,Linux,6-2017-q2-update
- ダウンロードしたファイルを任意のディレクトリに展開します。
(以下、展開先を${TOOLCHAIN}と記載します)
tar xjf gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2
- ツールチェインのパスを設定します。
環境変数を使用する場合
$ export GCC_ARM_ROOT=${TOOLCHAIN}/gcc-arm-none-eabi-6-2017-q2-update/bin $ export PATH=$GCC_ARM_ROOT:$PATH
mbed CLIで指定する場合
$ mbed config -G GCC_ARM_PATH $GCC_ARM_ROOT
iotjs環境のビルド
1. 本プログラムのクローン
下記コマンドを実行し、本プログラムをクローンしてください。
$ hg clone https://HinoNaka@os.mbed.com/users/HinoNaka/code/GR-PEACH_mbed-os-iotjs/
クローンが正常に終了すると、GR-PEACH_mbed-os-iotjs という名称のディレクトリが生成されますので、下記コマンドで当該ディレクトリへ移動してください。
$ cd GR-PEACH_mbed-os-iotjs
(Optional)
GR-PEACH-mbed-os-iotjsディレクトリを指す環境変数 ROOTを設定してください。以降の記載は本環境変数が設定されているものとします。
$ export ROOT=$(PWD)
2. 作業用ディレクトリ(e.g. work)を作成し、当該ディレクトリに移動してください。
$ mkdir -p work $ cd work
(Optional)
作業用ディレクトリを指す環境変数 WORK を設定してください。以降の記載は本環境変数 が設定されているものとします。
$ export WORK=$(PWD)
3. iotjsのソースツリーを取得します。
$ git clone https://github.com/pando-project/iotjs
クローンが正常に終了するとiotjsというディレクトリが生成されますので、当該ディレクトリに移動してください。
$cd iotjs
コミットID: acae9c8b2d40e7598b8d39b630b79113ce880a7e を取得します。
(下記例では、あわせてposixというブランチを作成し、当該ブランチへ切り替えています)
$ git checkout -b posix acae9c8b2d40e7598b8d39b630b79113ce880a7e
4. mbed-osセットアップ
Mbed OSソースツリーを格納するフォルダを生成し、当該フォルダへ移動します。
$ mkdir -p $(WORK)/iotjs/src/platform/mbedos5 $ cd $(WORK)/iotjs/src/platform/mbedos5
Mbed OSのソースツリーをクローンします。
$ git clone -b mbed-os-5.9 https://github.com/ARMmbed/mbed-os.git
クローンが正常に終了するとmbed-osというディレクトリが生成されますので、当該ディレクトリに移動してください。
$ cd mbed-os
コミットID: 50bd61a4a72332baa6b1bac6caccb44dc5423309 を取得します。
(下記例では、あわせてposixというブランチを作成し、当該ブランチへ切り替えています)
$ git checkout -b posix 50bd61a4a72332baa6b1bac6caccb44dc5423309
5. sd-driverの取得
下記コマンドでmbedos5ディレクトリへ移動します。
$ cd $(WORK)/iotjs/src/platform/mbedos5
sd-driverをクローンします。
$ git clone https://github.com/ARMmbed/sd-driver.git
クローンが正常終了するとsd-driverディレクトリが生成されますので、当該ディレクトリへ移動します。
$ cd sd-driver
コミットID: c8ae38fb291e086232566b0f1372cfb69c277e84 を取得します。
(下記例では、あわせてposixというブランチを作成し、当該ブランチへ切り替えています)
$ git checkout -b posix c8ae38fb291e086232566b0f1372cfb69c277e84
6. mbed-gr-libsの取得
下記コマンドでmbedos5ディレクトリへ移動します。
$ cd $(WORK)/iotjs/src/platform/mbedos5
mbed-gr-libsをクローンします。
$ git clone https://github.com/d-kato/mbed-gr-libs
クローンが正常終了するとmbed-gr-libsディレクトリが生成されますので、当該ディレクトリへ移動します。
$ cd mbed-gr-libs
コミットID: d921d611d596ecaebaab49070ef82450c583309c を取得します。
(下記例では、あわせてposixというブランチを作成し、当該ブランチへ切り替えています)
$ git checkout -b posix d921d611d596ecaebaab49070ef82450c583309c
7. AsciiFONTの取得
下記コマンドでmbedos5ディレクトリへ移動します。
$ cd $(WORK)/iotjs/src/platform/mbedos5
AsciiFONTライブラリを追加します。
$ mbed add https://os.mbed.com/teams/Renesas/code/AsciiFont/
8. iotjs環境のビルド
下記コマンドでiotjs環境のビルドディレクトリに移動し、ビルドを実行します。
$ cd $(WORK)/iotjs $ ./tools/build.py --no-snapshot
9. GR-PEACH用コードのコピー
(Optional) 既存のiotjs環境に上書きする場合、下記コマンドを実行してください。
$ rm -rf $(WORK)/iotjs/deps/posix $ rm -rf $(WORK)/iotjs/src/ext-modules $ rm -rf $(WORK)/iotjs/src/platform/mbedos5/iotjs_def.h
下記コマンドでGR-PEACH用コードをコピーします。
$ cp -pr $(ROOT)/src/iotjs/* $(WORK)/iotjs/
10. lwipパッチ適用
以下コマンドでlwipパッチを適用します。
$ cd $(WORK)/iotjs/src/platform/mbedos5/mbed-os $ git apply lwip_improve.patch
11. ESP32 TRNG対応パッチ適用
以下コマンドでESP32のTRNGを活用するためのパッチを適用します。
$ cd $(WORK)/iotjs/src/platform/mbedos5/mbed-os $ git apply trng_support.patch
12. Mbed OS版iotjs環境のビルド
下記コマンドを実行してMbed OS版iotjs環境をビルドします。
(リリースビルドの場合)
$ cd $(WORK)/iotjs/src/platform/mbedos5 $ make clean; make DEBUG=0
(デバッグビルドの場合)
$ cd $(WORK)/iotjs/src/platform/mbedos5 $ make clean; make DEBUG=1
13. ビルドが正常に終了すると、以下の通りバイナリが生成されます。
(リリースビルドの場合)
$ ls -l ${WORK}/iotjs/src/platform/mbedos5/BUILD/RZ_A1H/GCC_ARM-RELEASE/iotjs.bin
(デバッグビルドの場合)
$ ls -l ${WORK}/iotjs/src/platform/mbedos5/BUILD/RZ_A1H/GCC_ARM-DEBUG/iotjs.bin
実行方法
1. GR-PEACHにmicro SDカードを挿入します。
2. GR-PEACHのEthernetポートから遠い側のUSBポートとHost PCをマイクロUSBケーブルで接続します。
3. Host PCでGR-PEACHが『mbed:』ドライブとして認識されたら、iotjs.binをmbedドライブにコピーします。
4. ターミナルS/Wを立上げ、『mbed Serial Port』と接続します。
シリアルポートは下記設定としてください。
Baud rate | 115200 | |||
Data | 8 bit | |||
Parity | none | |||
Stop | 1 bit | |||
Flow control | none |
5. 正常に書込みが終了したらGR-PEACHのRESETボタンを押下します。
6. ターミナルS/W上に下記メッセージが表示されます。
7. Enterキーを押下してコード入力モードに移行します。
8. 実行するJavascriptコードをターミナルソフトウェアに貼り付けてEnterキーを押下すると、実行開始します。Javascriptコード例については、test/case.txtを参照ください。
test/case.txt
- Committer:
- Osamu Nakamura
- Date:
- 2019-07-18
- Revision:
- 4:52c937978bb3
- Parent:
- 1:c3d69f309845
File content as of revision 4:52c937978bb3:
■テストケースについて 次の行で囲まれた部分がそれぞれのテストケースになります。 //boc ---------- (BeginOfCode) //eoc ---------- (EndOfCode) ・使用例) 1)下記の //boc の *前行* から //eoc の *次行* までをクリップボードにコピーしておきます。 //boc ---------- (BeginOfCode) console.log("001"); //eoc ---------- (EndOfCode) 2)GR-Peach をリセット(or BREAK信号を送信)します。 ※ GR-Peach には *必ず* microSD カードをセットしておいてください。 IoT.js for mbed-os... mbed-os version: 5.9.3 build timestamp: MMM DD YYYY HH:MM:SS input js fullpath here: 3)[Enter]キーを送信して、コードの入力モードに移行します。 input javascript code here: 4)クリップボードの内容を貼り付けると処理が始まります。(手入力でもOK) input javascript code here: //boc ---------- (BeginOfCode) console.log("001"); //eoc ---------- (EndOfCode) ------- POSIX[ 1][thr0] -->clock_getres(clk_id=6, res=0x2005aae4) ------- POSIX[ 2][thr0] <--clock_getres(clk_id=6, res={0.001000000}) = 0(errno:0) ------- POSIX[ 3][thr0] -->clock_gettime(clk_id=6, tp=0x2005aae4) : : ■いくつかのテストケース //boc ---------- (BeginOfCode) //■ process.platform が "mbedos" か確認 console.log( 'platform = ' + process.platform ); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ process 環境表示テスト console.log( 'platform' + JSON.stringify( process, null, " " ) ); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ カレントパスのテスト console.log('current path: "' + process.cwd() + '"'); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ console 表示テスト (UTF8) console.log("001"); console.log("002", "002"); var val = "string"; console.log("003", val); val = 123; console.log("004", val); val = 3.14; console.log("005", val); console.log("nihongo", "UTF8"); console.log("nihongo", "日本語", "UTF8"); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ JSON.stringify、JSON.parse のテスト var obj = {abc:10, pi:3.14, str:"moji"}; var json = JSON.stringify(obj); console.log( json ); var copy = JSON.parse(json); console.log( copy ); console.log( JSON.stringify(copy) ); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ chdir のテスト function CHECK( number, val, must_be) { console.log( 'check', number, ': must be', must_be, ':', val == must_be ? 'OK' : 'NG' ); } var currentPath = process.cwd(); console.log('currentPath', process.cwd()); try { process.chdir('/sd'); } catch(err) { console.log('invalid path'); } console.log('currentPath', process.cwd()); CHECK(1, process.cwd(), '/sd'); process.chdir(currentPath); console.log('currentPath', process.cwd()); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ Buffer のテスト (linux版と結果が同じであること) var buf = new Buffer('hello world', 'ascii'); console.log(buf.toString('hex')); // Prints: 68656c6c6f20776f726c64 console.log(buf.toString('base64')); // Prints: aGVsbG8gd29ybGQ= //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ setTimeout() のテスト setTimeout( function() { console.log( new Date().getTime(), 'kita' ); }, 3000); console.log( new Date().getTime(), 'setTimeout started'); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ setInterval() のテスト var count = 0; var tid = setInterval( function() { console.log( new Date().getTime(), 'setInterval kita' ); if( ++ count >= 5 ) clearInterval( tid ); }, 1000); console.log( new Date().getTime(), 'setInterval started'); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ setTimeout(), setInterval() のテスト setTimeout( function() { console.log( new Date().getTime(), 'setTimeout1 kita' ); }, 3500); console.log( new Date(), 'setTimeout1 started'); setTimeout( function() { console.log( new Date().getTime(), 'setTimeout2 kita' ); }, 5500); console.log( new Date().getTime(), 'setTimeout2 started'); var count = 0; var tid = setInterval( function() { console.log( new Date().getTime(), 'setInterval kita' ); if( ++ count >= 5 ) clearInterval( tid ); }, 2000); console.log( new Date().getTime(), 'setInterval started'); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ fs モジュールのテスト (同期) var fs = require('fs'); var fname = "/sd/_temp_code.js"; var stat = fs.statSync(fname); console.log( JSON.stringify(stat) ); console.log( fs.readFileSync(fname) ); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ 正規表現のテスト var re = /(\w+)\s(\w+)/; var str = 'John Smith'; var newstr = str.replace(re, '$2, $1'); console.log(newstr); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ 文字列分割テスト var text = 'Some text\nAnd some more\r\nAnd yet\rThis is the end'; var lines = text.split(/\r\n|\r|\n/); console.log(lines); // logs [ 'Some text', 'And some more', 'And yet', 'This is the end' ] //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ 多国語テスト var text = 'Образец text на русском языке'; var regex = /[\u0400-\u04FF]+/g; var match = regex.exec(text); console.log(match[0]); // logs 'Образец' console.log(regex.lastIndex); // logs '7' var match2 = regex.exec(text); console.log(match2[0]); // logs 'на' [did not log 'text'] console.log(regex.lastIndex); // logs '15' // and so on //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) //■ 文字列操作テスト var url = 'http://xxx.domain.com'; console.log(/[^.]+/.exec(url)[0].substr(7)); // logs 'xxx' //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) // ■EventEmitterテスト var EventEmitter = require('events').EventEmitter; function asyncFunc() { var ev = new EventEmitter; console.log('in asyncFunc'); setTimeout(function () { ev.emit('done', 'foo', 'bar'); }, 1000); return ev; } var async = asyncFunc(); async.on('done', function(arg1, arg2) { console.log(arg1, arg2); }); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) // ■streamテスト var Readable = require('stream').Readable; function CHECK( number, val, must_be) { console.log( 'check', number, ': must be', must_be, ':', val == must_be ? 'OK' : 'NG' ); } var readable1 = new Readable(); var d = ""; var e = ""; readable1.on('error', function(err) { e += "."; }); readable1.on('data', function(data) { d += data.toString(); }); readable1.on('end', function() { e += 'e'; }); readable1.pause(); readable1.push('abcde'); readable1.push('12345'); CHECK(1, d, ''); CHECK(2, e, ''); readable1.resume(); CHECK(3, d, 'abcde12345'); CHECK(4, e, ''); readable1.push('a'); readable1.push('1'); readable1.push('b'); readable1.push('2'); CHECK(5, d, 'abcde12345a1b2'); CHECK(6, e, ''); CHECK(7, readable1.isPaused(), false); readable1.pause(); CHECK(8, d, 'abcde12345a1b2'); CHECK(9, e, ''); CHECK(10, readable1.isPaused(), true); // Pause the readable again. This should do nothing. readable1.pause(); CHECK(11, readable1.isPaused(), true); readable1.push('c'); readable1.push('3'); readable1.push('d'); readable1.push('4'); CHECK(12, d, 'abcde12345a1b2'); CHECK(13, e, ''); readable1.resume(); CHECK(14, d, 'abcde12345a1b2c3d4'); CHECK(15, e, ''); readable1.push(null); CHECK(16, d, 'abcde12345a1b2c3d4'); CHECK(17, e, 'e'); readable1.push('push after eof'); CHECK(18, d, 'abcde12345a1b2c3d4'); CHECK(19, e, 'e.'); // Create a readable stream without the new keyword. var readable2 = Readable({encoding: 'utf8'}); // Read with irregular parameters from an empty stream. CHECK(20, readable2.read(-2), null); CHECK(21, readable2.read(0), null); readable2.push('qwerty'); CHECK(22, readable2.read(6), 'qwerty'); // Throw not implemented Error when we trying to read less length data. readable2.push('new-data'); var readable3 = new Readable(); var readable3End = false; var paused = false; var str = 'test'; readable3.on('data', function(data) { CHECK(23, paused, true); CHECK(24, data, str); }); readable3.on('end', function() { readable3End = true; }); readable3.pause(); readable3.push(str); readable3.push(null); setTimeout(function() { paused = true; readable3.resume(); }, 1000); process.on('exit', function() { CHECK(25, readable2 instanceof Readable, true); CHECK(26, readable3End, true); }); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) // ■ dns モジュールの簡易テスト var dns = require('dns'); dns.lookup('www.google.co.jp', function(err, address, family) { console.log('www.google.co.jp -> address: %j family: IPv%s', address, family); }); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) // ■ nic モジュールの簡易テスト var nic = require('nic'); // 一覧取得 var nics = nic.enumerate(); // 一覧確認 console.log( Object.keys( nics ).length + "個のNICが搭載されています" ); var index = 0; Object.keys( nics ).forEach( function(key) { console.log( ++ index + "個目は:" + key ); }); // 使い方 var eth0 = nics["ETHERNET"]; if( eth0 ) { eth0.ifup(); // use DHCP eth0.ntpdate({ server:"ntp.nict.jp" }); console.log( JSON.stringify( eth0.ifconfig() ) ); console.log( new Date().toString() ); } var wifi = nics["WIFI_BP3595"]; if( wifi ) { wifi.ifup( { wifi: { ssid: "<SSID>", password: "<PASSWORD>", security: "WPA_WPA2" // 候補:WEP, WPA, WPA2, WPA_WPA2 }, ip: "192.168.10.123", netmask: "255.255.255.0", gateway: "192.168.10.1", dns: "8.8.8.8" }); wifi.ntpdate(); console.log( JSON.stringify( wifi.ifconfig() ) ); console.log( new Date().toString() ); } //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) // ■ http クライアントのテスト var cli = require('http'); require('fixup')('http'); cli.get({ host: 'www.google.com' }, function(res) { console.log( 'res.statusCode', res.statusCode); res.on('data', function(chunk) { console.log( chunk.toString() ); }); res.on('end', function() { console.log( 'end' ); }); }); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) // ■ https クライアントのテスト var cli = require('https'); require('fixup')('https'); cli.get({ host: 'www.google.com' }, function(res) { console.log( 'res.statusCode', res.statusCode); res.on('data', function(chunk) { console.log( chunk.toString() ); }); res.on('end', function() { console.log( 'end' ); }); }); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) // ■ カメラ入力をJPEGファイルに保存する var video = require('video'); var jpeg = require('jpeg'); var fs = require('fs'); var AlignedBuffer = require('aligned_buffer').AlignedBuffer; var width = 480; var height = 272; var video_format = 'ycbcr422'; var pixel_bytes = 2; var alignment = 32; var video_buf = new AlignedBuffer(width * height * pixel_bytes, alignment); var camera_config = { width : width, height : height, format : video_format, type : 'ov7725' }; var jpeg_config = { width : width, height : height, format : video_format }; var interval = 1*1000; // 画像保存周期(ms) var count = 10; // 保存する画像ファイル数 // カメラの初期化 video.openCMOSCamera(camera_config, function(err, video_source){ if(err) { console.log(err); return; } // 映像の取り込み開始 video_source.start(video_buf, function(err) { if(err) { console.log(err); return; } // interval の周期で count 数のJPEG画像を保存 var i = 0; var timer = setInterval(function() { if(i >= count) { clearInterval(timer); video_source.stopSync(); // 映像の取り込み停止 video_source.closeSync(); // カメラリソースの解放 return; } jpeg_config.bitmap = new AlignedBuffer(video_buf, alignment); var jpeg_data = jpeg.encodeSync(jpeg_config); fs.writeFileSync('/sd/image' + i + '.jpg', jpeg_data.toBuffer()); console.log('/sd/image' + i + '.jpg'); i++; }, interval); }); }); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) // ■ LCDのグラフィックス描画テスト var display = require('display'); var Graphics = require('graphics').Graphics; var AlignedBuffer = require('aligned_buffer').AlignedBuffer; var width = 480; var height = 272; var pixel_bytes = 2; var alignment = 32; var buf_size = width * height * pixel_bytes; var lcd_config = { type : '4.3inch' }; // レイヤー0用フレームバッファ初期化 var format0 = 'rgb565'; var buf0 = new AlignedBuffer(buf_size, alignment); var graphics0 = new Graphics({buf:buf0, width:width, height:height, format:format0}); graphics0.drawRect(0,0,width,height,0xFFFF,true); // 全領域を白で塗りつぶし // レイヤー1用フレームバッファ初期化 var format1 = 'argb4444'; var buf1 = new AlignedBuffer(buf_size, alignment); var graphics1 = new Graphics({buf:buf1, width:width, height:height, format:format1}); graphics1.drawRect(0,0,width,height,0x0000,true); // 全領域を完全透過 var interval = 1*1000; // LCD表示切り替え周期(ms) // LCDの初期化 display.openLCD(lcd_config, function(err, lcd) { if(err) { console.log(err); return; } var i = 0; var timer = setInterval(function(){ switch(i) { case 0: // レイヤー0の表示を開始(白背景) lcd.startSync(0, graphics0.frameBuffer, format0); break; case 1: // レイヤー1の表示を開始(白背景に赤の円) graphics1.drawCircle(100,100,50,0xFF00,true); lcd.startSync(1, graphics1.frameBuffer, format1); break; case 2: // レイヤー0のフレームバッファを切り替え(青背景に赤の円) var new_buf0 = new AlignedBuffer(buf_size, alignment); var new_graphics0 = new Graphics({buf:new_buf0, width:width, height:height, format:format0}); new_graphics0.drawRect(0,0,width,height,0x001F,true); // 全領域を青で塗りつぶし lcd.updateSync(0, new_graphics0.frameBuffer); break; case 3: // レイヤー0の表示を停止(黒背景に赤の円) lcd.stopSync(0); break; case 4: // レイヤー1の表示を停止(黒背景) lcd.stopSync(1); break; default: // LCDリソースの解放 lcd.closeSync(); clearInterval(timer); break; } i++; }, interval); }); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) // ■ カメラ入力をGoogle Vision APIに送信し、検出結果をLCDに描画するテスト var display = require('display'); var video = require('video'); var jpeg = require('jpeg'); var https = require('https'); var AlignedBuffer = require('aligned_buffer').AlignedBuffer; var Graphics = require('graphics').Graphics; require('fixup')('https'); var width = 480; var height = 272; var video_format = 'ycbcr422'; var pixel_bytes = 2; var alignment = 32; var video_buf = new AlignedBuffer(width * height * pixel_bytes, alignment); var result_format = 'argb4444'; var result_color = 0xF00F; var result_pixel_bytes = 2; var lcd_config = { type : '4.3inch' }; var camera_config = { width : width, height : height, format : video_format, type : 'ov7725' }; var jpeg_config = { width : width, height : height, format : video_format }; var key = 'key=<your APIKey>'; var timeout = 10*1000; var detection_type = 'FACE_DETECTION'; //var detection_type = 'OBJECT_LOCALIZATION'; var lcd; display.openLCD(lcd_config, function(err, lcd_) { console.log('LCD Open Callback'); if(!err) { lcd = lcd_; lcd.start(0, video_buf, video_format, function(err){ if(!err) console.log('LCD Layer 0 Start'); else console.log(err); }); console.log('Camera Open Start'); video.openCMOSCamera(camera_config, function(err, video_source){ if(!err) { video_source.start(video_buf, function(){ console.log('Camera Start'); // 10秒後にJPEGエンコード開始 setTimeout(function() { console.log('JPEG Encode Start'); video_source.stopSync(); jpeg_config.bitmap = new AlignedBuffer(video_buf, alignment); jpeg.encode(jpeg_config, function(err, data) { console.log('JPEG Encode Callback'); if(!err && data) { use_google_vision_api(data.toBuffer().toString('base64')); } else { console.log(err); } }); }, timeout); }); } else { console.log(err); } }); } else { console.log(err); } }); console.log('LCD Open Start'); function use_google_vision_api(image) { var host = 'vision.googleapis.com'; var port = 443; var path = '/v1/images:annotate'; var data = '{"requests":[{"image":{"content":"' + image + '"},"features":[{"type":"' + detection_type + '"}]},]}'; var options = { host: host, port: port, path: path + '?' + key, method: 'POST', headers: { 'Host': host + ':' + port, 'Content-Type': 'application/json', 'Content-Length': data.length } }; var req = https.request(options, function(res) { var body = ''; console.log( 'res.statusCode', res.statusCode); res.on('data',function(chunk) { body += chunk; }); res.on('end',function() { console.log(body); drawResult(JSON.parse(body)); }); }); req.on( 'error', function( e ) { console.log( 'error' ); console.log( e.message ); }); req.writeEntire = function(data, block_size) { block_size = block_size || 1024; for(var i = 0; i < data.length; i += block_size) { this.write(data.slice(i, i + block_size)); } }; req.writeEntire(data); req.end(); } function drawResult(res) { switch(detection_type) { case 'FACE_DETECTION': drawFace(res); break; case 'OBJECT_LOCALIZATION': drawObject(res); break; default: break; } } function drawObject(res) { var result_buf = new AlignedBuffer(width*height*result_pixel_bytes, alignment); var result = new Graphics({buf:result_buf, width:width, height:height, format:result_format}); result.drawRect(0, 0, width, height, 0x0000, true); // response format // https://cloud.google.com/vision/docs/reference/rest/v1/images/annotate?hl=ja#LocalizedObjectAnnotation var objects = res.responses[0].localizedObjectAnnotations; objects.forEach(function(e, index){ var rect = e.boundingPoly.normalizedVertices; rect.forEach(function(e) { e.x *= width; e.y *= height; }); result.drawRect(rect[0].x, rect[0].y, rect[1].x - rect[0].x, rect[3].y - rect[0].y, result_color, false); result.drawText(e.name, rect[0].x + 1, rect[0].y + 1, 1, result_color, 0x0000); }); lcd.startSync(2, result.frameBuffer, result_format); } function drawFace(res) { var result_buf = new AlignedBuffer(width*height*result_pixel_bytes, alignment); var result = new Graphics({buf:result_buf, width:width, height:height, format:result_format}); result.drawRect(0, 0, width, height, 0x0000, true); var background_buf = new AlignedBuffer(width*height*result_pixel_bytes, alignment); var background_format = 'rgb565'; var background = new Graphics({buf : background_buf, width:width, height:height, format:background_format}); background.drawRect(0, 0, width, height, 0xFFFF, true); result.drawPolyline = function ( positions, close, color ) { for(var i = 0; i < positions.length - 1; i++) { this.drawLine(positions[i].x, positions[i].y, positions[i+1].x, positions[i+1].y, color); } if(close) { this.drawLine(positions[positions.length-1].x, positions[positions.length-1].y, positions[0].x, positions[0].y, color); } }; // response format // https://cloud.google.com/vision/docs/reference/rest/v1/images/annotate?hl=ja#FaceAnnotation res.responses[0].faceAnnotations.forEach(function(faceAnnotation){ var landmarks = faceAnnotation.landmarks; landmarks.findIndex = function(type) { var ret; this.forEach(function(e, index) { if(e.type == type) ret = index; }); return ret; }; var outline = []; outline.push(landmarks[landmarks.findIndex('LEFT_EAR_TRAGION')].position); outline.push(landmarks[landmarks.findIndex('CHIN_LEFT_GONION')].position); outline.push(landmarks[landmarks.findIndex('CHIN_GNATHION')].position); outline.push(landmarks[landmarks.findIndex('CHIN_RIGHT_GONION')].position); outline.push(landmarks[landmarks.findIndex('RIGHT_EAR_TRAGION')].position); result.drawPolyline(outline, false, result_color); var left_eyeblow = []; left_eyeblow.push(landmarks[landmarks.findIndex('LEFT_OF_LEFT_EYEBROW')].position); left_eyeblow.push(landmarks[landmarks.findIndex('LEFT_EYEBROW_UPPER_MIDPOINT')].position); left_eyeblow.push(landmarks[landmarks.findIndex('RIGHT_OF_LEFT_EYEBROW')].position); result.drawPolyline(left_eyeblow, false, result_color); var right_eyeblow = []; right_eyeblow.push(landmarks[landmarks.findIndex('LEFT_OF_RIGHT_EYEBROW')].position); right_eyeblow.push(landmarks[landmarks.findIndex('RIGHT_EYEBROW_UPPER_MIDPOINT')].position); right_eyeblow.push(landmarks[landmarks.findIndex('RIGHT_OF_RIGHT_EYEBROW')].position); result.drawPolyline(right_eyeblow, false, result_color); var left_eye = []; left_eye.push(landmarks[landmarks.findIndex('LEFT_EYE_TOP_BOUNDARY')].position); left_eye.push(landmarks[landmarks.findIndex('LEFT_EYE_RIGHT_CORNER')].position); left_eye.push(landmarks[landmarks.findIndex('LEFT_EYE_BOTTOM_BOUNDARY')].position); left_eye.push(landmarks[landmarks.findIndex('LEFT_EYE_LEFT_CORNER')].position); result.drawPolyline(left_eye, true, result_color); var eye = landmarks[landmarks.findIndex('LEFT_EYE')].position result.drawCircle(eye.x, eye.y, 2, result_color, true); eye = landmarks[landmarks.findIndex('RIGHT_EYE')].position result.drawCircle(eye.x, eye.y, 2, result_color, true); var right_eye = []; right_eye.push(landmarks[landmarks.findIndex('RIGHT_EYE_TOP_BOUNDARY')].position); right_eye.push(landmarks[landmarks.findIndex('RIGHT_EYE_RIGHT_CORNER')].position); right_eye.push(landmarks[landmarks.findIndex('RIGHT_EYE_BOTTOM_BOUNDARY')].position); right_eye.push(landmarks[landmarks.findIndex('RIGHT_EYE_LEFT_CORNER')].position); result.drawPolyline(right_eye, true, result_color); var nose = []; nose.push(landmarks[landmarks.findIndex('NOSE_BOTTOM_LEFT')].position); nose.push(landmarks[landmarks.findIndex('NOSE_TIP')].position); nose.push(landmarks[landmarks.findIndex('NOSE_BOTTOM_RIGHT')].position); nose.push(landmarks[landmarks.findIndex('NOSE_BOTTOM_CENTER')].position); nose.push(landmarks[landmarks.findIndex('NOSE_BOTTOM_LEFT')].position); nose.push(landmarks[landmarks.findIndex('MIDPOINT_BETWEEN_EYES')].position); nose.push(landmarks[landmarks.findIndex('NOSE_BOTTOM_RIGHT')].position); result.drawPolyline(nose, false, result_color); var mouth = []; mouth.push(landmarks[landmarks.findIndex('MOUTH_LEFT')].position); mouth.push(landmarks[landmarks.findIndex('UPPER_LIP')].position); mouth.push(landmarks[landmarks.findIndex('MOUTH_RIGHT')].position); mouth.push(landmarks[landmarks.findIndex('LOWER_LIP')].position); mouth.push(landmarks[landmarks.findIndex('MOUTH_LEFT')].position); mouth.push(landmarks[landmarks.findIndex('MOUTH_CENTER')].position); mouth.push(landmarks[landmarks.findIndex('MOUTH_RIGHT')].position); result.drawPolyline(mouth, false, result_color); }); lcd.start(2, result.frameBuffer, result_format, function(){ console.log('lcd start callback'); setTimeout(function(){ lcd.startSync(1, background.frameBuffer, background_format); lcd.stopSync(0); }, timeout); }); } //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) // ■ ランダムグラフィックス描画テスト var display = require('display'); var Graphics = require('graphics').Graphics; var AlignedBuffer = require('aligned_buffer').AlignedBuffer; var width = 480; var height = 272; var graphics_format = 'rgb565'; var text_format = 'argb4444'; var pixel_bytes = 2; var alignment = 32; var color_mask = 0xFFFF; var text_color = 0xF000; var text_background = 0xFFFF; var buf_size = width * height * pixel_bytes; var interval = 10; var count = 500; var lcd_config = { type : '4.3inch' }; var graphcis_buf = new AlignedBuffer(buf_size, alignment); var canvas = new Graphics({buf:graphcis_buf, width:width, height:height, format:graphics_format}); canvas.drawRect(0,0,width,height,0xFFFF,true); var text_buf = new AlignedBuffer(buf_size, alignment); var text = new Graphics({buf:text_buf, width:width, height:height, format:text_format}); text.drawRect(0,0,width,height,0x0000,true); var start_index = 0; var drawRandomGraphics = [ { type : "Line", func : drawRandomLine }, { type : "Rectangle", func : drawRandomRect }, { type : "Arc", func : drawRandomArc }, { type : "Circle", func : drawRandomCircle }, { type : "Ellipse", func : drawRandomEllipse }, { type : "Polygon", func : drawRandomPolygon } ]; function drawRandomLine(g) { var sx = Math.floor(Math.random() * width); var sy = Math.floor(Math.random() * height); var ex = Math.floor(Math.random() * width); var ey = Math.floor(Math.random() * height); var color = Math.floor(Math.random() * color_mask); g.drawLine(sx, sy, ex, ey, color); } function drawRandomRect(g) { var x = Math.floor(Math.random() * width); var y = Math.floor(Math.random() * height); var w = Math.floor(Math.random() * width); var h = Math.floor(Math.random() * height); var color = Math.floor(Math.random() * color_mask); var fill = Math.round(Math.random()); g.drawRect(x, y, w, h, color, fill); } function drawRandomArc(g) { var x = Math.floor(Math.random() * width); var y = Math.floor(Math.random() * height); var radius = Math.floor(Math.random() * height); var start = Math.floor(Math.random() * 360); var end = Math.floor(Math.random() * 360); var color = Math.floor(Math.random() * color_mask); g.drawArc(x, y, radius, start, end, color); } function drawRandomCircle(g) { var x = Math.floor(Math.random() * width); var y = Math.floor(Math.random() * height); var radius = Math.floor(Math.random() * height); var color = Math.floor(Math.random() * color_mask); var fill = Math.round(Math.random()); g.drawCircle(x, y, radius, color, fill); } function drawRandomEllipse(g) { var cx = Math.floor(Math.random() * width); var cy = Math.floor(Math.random() * height); var rx = Math.floor(Math.random() * height); var ry = Math.floor(Math.random() * height); var color = Math.floor(Math.random() * color_mask); var fill = Math.round(Math.random()); g.drawEllipse(cx, cy, rx, ry, color, fill); } function drawRandomPolygon(g) { var x = Math.floor(Math.random() * width); var y = Math.floor(Math.random() * height); var radius = Math.floor(Math.random() * height); var sides = Math.floor(Math.random() * 10) + 3; var color = Math.floor(Math.random() * color_mask); var fill = Math.round(Math.random()); g.drawPolygon(x, y, radius, sides, color, fill); } display.openLCD(lcd_config, function(err, lcd) { if(!err) { lcd.startSync(0, canvas.frameBuffer, graphics_format); lcd.startSync(1, text.frameBuffer, text_format); var draw = function(index) { var type = drawRandomGraphics[index].type; canvas.drawRect(0, 0, width, height, 0xFFFF, true); text.drawRect(0, 0, width, height, 0x0000, true); text.drawText('Draw Random ' + type, 0, 0, 2, text_color, text_background); var timer = setInterval(function() { drawRandomGraphics[index].func(canvas); }, interval); setTimeout(function() { clearInterval(timer); if(++index < drawRandomGraphics.length) { draw(index); } }, interval * count); } draw(start_index); } }); //eoc ---------- (EndOfCode) //boc ---------- (BeginOfCode) // ■ JPEG画像の連続表示テスト // 事前に contents_microSD.zip を解凍し、frames フォルダを microSD カード直下に // コピーしてください var display = require('display'); var jpeg = require('jpeg'); var fs = require('fs'); var AlignedBuffer = require('aligned_buffer').AlignedBuffer; var Graphics = require('graphics').Graphics; var width = 480; var height = 272; var format = 'rgb565'; var pixel_bytes = 2; var alignment = 32; var buf = new AlignedBuffer(width * height * pixel_bytes, alignment); var canvas = new Graphics({buf:buf, width:width, height:height, format:format}); canvas.drawRect(0,0,width,height,0xFFFF,true); var lcd_config = { type : '4.3inch' }; var file_num = 14315; display.openLCD(lcd_config, function(err, lcd) { if(!err) { lcd.start(0, canvas.frameBuffer, format, function() { var i = 1; var interval = setInterval(function() { if(i > file_num) { clearInterval(interval); return; } body(i++); }, 1); }); } else { console.log(err); } }); function body(i) { var dir = ('000' + Math.floor(i / 100)).slice(-3); var file = ('00000' + i).slice(-5) + '.jpg'; var path = '/sd/frames/' + dir + '/' + file; var jpeg_data = new AlignedBuffer(fs.readFileSync(path), alignment); var decode_config = { width : 384, height : 216, format : format }; var image = jpeg.decodeSync(jpeg_data, decode_config); canvas.drawImage(image, 48, 28); } //eoc ---------- (EndOfCode)