[2012/8/25追記]本記事の内容は古くなっています。
最新の情報は mpod mother board をご覧ください。
外観
使い方
まず、本機のUSBコネクタをパソコンにつなげます。
USBメモリの中身が見えるので、トップのフォルダに"netusbm.cfg"というテキストファイルを作成し、自分のPicasaウェブアルバムの特定のアルバムのURLを記述します。
本機にダウンロードさせたい写真は、ここで指定したアルバムに保存しておくようにします。
また、同じフォルダに"DCIM"という空のフォルダも作っておきます。
フォトフレームは、この"DCIM"フォルダの下にある画像を探すので、本機はダウンロードした画像をこのフォルダに保存します。
ここまで準備ができたら、EtherNetケーブルを本機に接続し、パソコンからUSBコネクタを取り外し、そのUSBケーブルをフォトフレームに繋げます。
フォトフレームの電源を入れると、本機の中のUSBメモリがマウントされ、画像を読み込もうとしますが、最初は画像が無いので何も表示されないか、エラー画面などが出ると思います。
ここで、本機の上面にあるスイッチを押すと、フォトフレームからUSBメモリがアンマウントされ、mbed側に接続されます。mbedはEtherNet経由で画像を収集し、完了したらUSBメモリを再びフォトフレーム側に接続します。フォトフレーム側はUSBメモリの接続を検知し、保存されている画像を表示し始めるはずです。
回路図
ケース加工
mbedとUSBコネクタ、RJ45コネクタ、USBメモリを入れるため、かなり窮屈です。
もともとmbedについているUSBコネクタとリセットスイッチがケースと干渉するので、写真のように内部を彫刻刀で削りました。
また、スイッチを外に出すための穴を開けています。
回路実装
mbed用のコネクタの間にUSBメモリを配置し、さらに基板を切り欠いてUSB-BコネクタとRJ45コネクタをホットメルトで固定しています。
USBメモリ用のUSB-Aコネクタの配置が窮屈で、USBメモリが取り外し不可能になってしまいました。USBメモリは約2000円と高価ですが、仕方なく本機専用としました。
ソフトウェア
以下に示すのが、私が書いた部分です。
これ以外に、以下のライブラリも利用しています。
・EtherNetIf
・FATFileSystem
・HTTPClient
・MSCUsbHost
なお、動作を優先させたため、リファクタリングの余地が多分に残っていますので、その点ご了承ください。
Picasaから送られるHTMLから、画像ファイルのURLだけを抜き出すため、ステートマシンによる簡単なパーサを作りました。
URLの部分は、以下の様な特徴的な文字列が並びます。
厳密には検出のための条件をもっと増やした方が良いかもしれませんが、個人で使う分にはこれで十分です。当然のことながら、Googleが仕様を変更したら、パーサも設計し直す必要があります。
今回はパーサを独自に作りましたが、もし汎用の正規表現ライブラリで良いのがあれば、それを使った方が良いでしょう。私はC言語で使える正規表現ライブラリをひとつ評価しましたが、使い勝手が自分の要求には合わなかったので、自作しました。
まとめ
mbedを使ってディジタルフォトフレームに手を加えずにネットワーク対応しました。
このような用途にmbedはうってつけです。HTTP、USBホストなどの有用なライブラリが揃っているからです。
今回、これらのライブラリが無ければ、ここまで辿り着けなかったことでしょう。
ライブラリを提供してくださった皆様には、大変感謝しております。ありがとうございました。
製作してから、この文章を書くまで、半年以上が経過してしまいました。この点は反省。
次回からは、作ったらすぐにドキュメントにまとめるようにしたいと思います。
お約束
このドキュメントに書かれている内容について、正確になるよう筆者は努力しますが、保証はできません。
もし、間違いなどを発見されましたら、ご指摘頂ければ幸いです。
このドキュメントに起因するいかなる損害についても、筆者は一切の責任を負いません。
ご利用になる場合は、各位にて十分な検証を行うようにお願いします。
また、本ドキュメントに関する著作権は筆者に帰属するものとします。
ただし、ドキュメントの内容は自由に複製したり、改変して使用して頂いても構いません。
最新の情報は mpod mother board をご覧ください。
概要
USBメモリのインタフェースを備えるディジタルフォトフレームを、フォトフレーム側への改造をせずにネットワーク対応させます。
概念図
このような目的に使える、ネットワークとUSBの両方を備える便利なデバイス、と言えば、もちろんmbedでしょう。
ネットワークは、パルストランス付きのRJ45コネクタをmbedに繋ぐだけ。
USBメモリをUSBスイッチ(FSUSB30MUX:フェアチャイルドセミコンダクタ)を介してmbedとフォトフレームに接続し、mbedからの制御信号によりUSBメモリの接続先を「mbedのUSBホスト」と「フォトフレーム」とに切り替えて使用します。
最初は、mbed自身のファーム格納領域であるUSB mass strageを間借りして写真も保存しようと思いましたが、容量が約2MBと小さく、たくさんの写真を保存するには適していないため、このような構成にしています。
この構成では、フォトフレーム側からは本機はただのUSBメモリとして見えるため、フォトフレームには一切手を加えずに済むのが特徴です。USBスイッチがmbed側に倒れている時は、フォトフレームからUSBメモリが抜き取られたのと同じ状態です。
外観
使い方
まず、本機のUSBコネクタをパソコンにつなげます。
USBメモリの中身が見えるので、トップのフォルダに"netusbm.cfg"というテキストファイルを作成し、自分のPicasaウェブアルバムの特定のアルバムのURLを記述します。
http://picasaweb.google.com/********/********?authkey=***********#
また、同じフォルダに"DCIM"という空のフォルダも作っておきます。
フォトフレームは、この"DCIM"フォルダの下にある画像を探すので、本機はダウンロードした画像をこのフォルダに保存します。
ここまで準備ができたら、EtherNetケーブルを本機に接続し、パソコンからUSBコネクタを取り外し、そのUSBケーブルをフォトフレームに繋げます。
フォトフレームの電源を入れると、本機の中のUSBメモリがマウントされ、画像を読み込もうとしますが、最初は画像が無いので何も表示されないか、エラー画面などが出ると思います。
ここで、本機の上面にあるスイッチを押すと、フォトフレームからUSBメモリがアンマウントされ、mbed側に接続されます。mbedはEtherNet経由で画像を収集し、完了したらUSBメモリを再びフォトフレーム側に接続します。フォトフレーム側はUSBメモリの接続を検知し、保存されている画像を表示し始めるはずです。
部品表
項目 | メーカ | 型番 | 価格 (円) | 数量 | 備考 |
---|---|---|---|---|---|
ディジタル フォトフレーム | kodak | EasyShare P725 | 0 | 1 |
会社の新年会ビンゴ景品
|
USBメモリ | Buffalo | RUF2PS4GBK | 2000 | 1 |
作品全体のサイズを小さくするため、
小型のUSBメモリを選択した |
コントローラ | NXP | mbed NXP LPC1768 | 6000 | 1 | ― |
USBスイッチ | Fairchild | FSUSB30MUX | 160 | 1 |
Digi-Keyで購入したため
2000円の送料が必要 |
RJ45コネクタ | ― | ― | 360 | 1 | ― |
USBコネクタ | ― | Bメス (receptacle) | 160 | 1 |
フォトフレーム接続用
|
USBコネクタ | ― | Aメス (receptacle) | 130 | 1 |
USBメモリ接続用
|
ケース | テイシン電機 | TB-51B | 120 | 1 |
D40×W70×H25
|
回路図
ケース加工
mbedとUSBコネクタ、RJ45コネクタ、USBメモリを入れるため、かなり窮屈です。
もともとmbedについているUSBコネクタとリセットスイッチがケースと干渉するので、写真のように内部を彫刻刀で削りました。
また、スイッチを外に出すための穴を開けています。
回路実装
mbed用のコネクタの間にUSBメモリを配置し、さらに基板を切り欠いてUSB-BコネクタとRJ45コネクタをホットメルトで固定しています。
USBメモリ用のUSB-Aコネクタの配置が窮屈で、USBメモリが取り外し不可能になってしまいました。USBメモリは約2000円と高価ですが、仕方なく本機専用としました。
ソフトウェア
以下に示すのが、私が書いた部分です。
これ以外に、以下のライブラリも利用しています。
・EtherNetIf
・FATFileSystem
・HTTPClient
・MSCUsbHost
なお、動作を優先させたため、リファクタリングの余地が多分に残っていますので、その点ご了承ください。
main.cpp
#include "mbed.h" #include "MSCFileSystem.h" #include "EthernetNetIf.h" #include "HTTPClient.h" #include "picasaUrlParser.h" #define URL_BUF_SIZE (100) DigitalOut led(LED1); DigitalInOut usbsel(p8); DigitalIn startsw(p9); EthernetNetIf eth; HTTPClient http; HTTPResult result; bool completed = false; void request_callback(HTTPResult r) { result = r; completed = true; } int main(void) { printf("EtherIF Setting up...\n"); EthernetErr ethErr = eth.setup(); if (ethErr) { printf("Error %d in setup.\n", ethErr); return -1; } printf("EtherIF Setup OK\n\n"); while (1) { usbsel.output(); usbsel = 1; led = !led; completed = false; while (1) { if (startsw == 0) { break; } } usbsel = 0; led = !led; usbsel.input(); { char url[URL_BUF_SIZE]; // Mount flash drive under the name "msc" MSCFileSystem msc = MSCFileSystem("msc"); // Read the target URL from configuration file. FILE *fpcfg = fopen("/msc/netusbm.cfg", "r"); fgets(url, URL_BUF_SIZE, fpcfg); fclose(fpcfg); url[strlen(url)-1] = '\0'; // Create parser FILE *fplist = fopen("/msc/url_list.txt", "w"); picasaUrlParser* parser = picasaUrlParser_create(fplist); HTTPStream stream; char BigBuf[512 + 1] = {0}; stream.readNext((byte*)BigBuf, 512); printf("%s\n", url); HTTPResult r = http.get(url, &stream, request_callback); while (!completed) { Net::poll(); //Polls the Networking stack if (stream.readable()) { BigBuf[stream.readLen()] = 0; int i = 0; while (0 != BigBuf[i]) { picasaUrlParser_setChar(parser, BigBuf[i]); i++; } stream.readNext((byte*)BigBuf, 512); } } printf("--------------\n"); if (result == HTTP_OK) { printf("Read completely\n\n"); } else { printf("Error %d\n\n", result); } // delete parser picasaUrlParser_destroy(parser); fclose(fplist); fplist = fopen("/msc/url_list.txt", "r"); if (fplist == NULL) { error("Could not open file for read\n"); } int j=0; char target[128]; while (NULL != fgets(target, 128, fplist)) { char* tmp = target; while ('\n' != *tmp) { tmp++; } *tmp = '\0'; printf("%s\n", target); char filename[64]; sprintf(filename, "/msc/DCIM/img%03d.jpg", j); printf("filename : %s\n", filename); HTTPFile fpimg = HTTPFile (filename); // Request a page and store it into a file. HTTPResult r2 = http.get(target, &fpimg); if (r2 == HTTP_OK) { printf("Read completely\n\n"); } else { printf("Error %d\n\n", r2); } // Close the file. fpimg.clear(); j++; } fclose(fplist); // Work is done! } } return 0; }
Picasaから送られるHTMLから、画像ファイルのURLだけを抜き出すため、ステートマシンによる簡単なパーサを作りました。
URLの部分は、以下の様な特徴的な文字列が並びます。
[{"url":"http://lh5.ggpht.com/(中略)/IMGP0486.JPG","height":1200,"width":1600,"type":"image/jpeg"}]こういった文字列を含むファイル全体を、1文字ずつパーサに流し込んで行き、あるところで
[{"url":"を検出したらURLの読み取りを開始し、次に
"を検出したらURLの終了だと判断します。
厳密には検出のための条件をもっと増やした方が良いかもしれませんが、個人で使う分にはこれで十分です。当然のことながら、Googleが仕様を変更したら、パーサも設計し直す必要があります。
今回はパーサを独自に作りましたが、もし汎用の正規表現ライブラリで良いのがあれば、それを使った方が良いでしょう。私はC言語で使える正規表現ライブラリをひとつ評価しましたが、使い勝手が自分の要求には合わなかったので、自作しました。
picasaUrlParser.h
#ifndef PICASAURLPARSER_HEADER_DEFINED #define PICASAURLPARSER_HEADER_DEFINED #include "FATFileSystem.h" #define MAX_URL_LEN (128) typedef enum { initalized, judge1, judge2, judge3, judge4, judge5, judge6, judge7, judge8, parsing }picasaUrlParserState; typedef struct { int iPos; char url[MAX_URL_LEN]; picasaUrlParserState state; FILE* fpurl; }picasaUrlParser; picasaUrlParser* picasaUrlParser_create(FILE* fp); void picasaUrlParser_destroy(picasaUrlParser* pThis); void picasaUrlParser_setChar(picasaUrlParser* pThis, char target); #endif /* PICASAURLPARSER_HEADER_DEFINED */
picasaUrlParser.cpp
#include <stdio.h> #include <stdlib.h> #include "picasaUrlParser.h" picasaUrlParser* picasaUrlParser_create(FILE* fp) { picasaUrlParser* pThis; pThis = (picasaUrlParser*)malloc(sizeof(picasaUrlParser)); if (NULL == pThis) { printf("Memory Allocation Error.\n"); while (1) { //Do nothing } } pThis->iPos = 0; pThis->state = initalized; pThis->fpurl = fp; return pThis; } void picasaUrlParser_destroy(picasaUrlParser* pThis) { if (NULL == pThis) { while (1) { //Do nothing } } free(pThis); return; } void picasaUrlParser_setChar(picasaUrlParser* pThis, char target) { if (NULL == pThis) { while (1) { //Do nothing } } switch (pThis->state) { case initalized: if ('[' == target) { pThis->state = judge1; } break; case judge1: if ('{' == target) { pThis->state = judge2; } else { pThis->state = initalized; } break; case judge2: if ('"' == target) { pThis->state = judge3; } else { pThis->state = initalized; } break; case judge3: if ('u' == target) { pThis->state = judge4; } else { pThis->state = initalized; } break; case judge4: if ('r' == target) { pThis->state = judge5; } else { pThis->state = initalized; } break; case judge5: if ('l' == target) { pThis->state = judge6; } else { pThis->state = initalized; } break; case judge6: if ('"' == target) { pThis->state = judge7; } else { pThis->state = initalized; } break; case judge7: if (':' == target) { pThis->state = judge8; } else { pThis->state = initalized; } break; case judge8: if ('"' == target) { pThis->state = parsing; } else { pThis->state = initalized; } break; case parsing: if ('"' != target) { pThis->url[pThis->iPos] = target; (pThis->iPos)++; } else { pThis->url[pThis->iPos] = '\0'; fprintf(pThis->fpurl, "%s\n", pThis->url); pThis->iPos=0; pThis->state = initalized; } break; default: break; } return; }
まとめ
mbedを使ってディジタルフォトフレームに手を加えずにネットワーク対応しました。
このような用途にmbedはうってつけです。HTTP、USBホストなどの有用なライブラリが揃っているからです。
今回、これらのライブラリが無ければ、ここまで辿り着けなかったことでしょう。
ライブラリを提供してくださった皆様には、大変感謝しております。ありがとうございました。
製作してから、この文章を書くまで、半年以上が経過してしまいました。この点は反省。
次回からは、作ったらすぐにドキュメントにまとめるようにしたいと思います。
お約束
このドキュメントに書かれている内容について、正確になるよう筆者は努力しますが、保証はできません。
もし、間違いなどを発見されましたら、ご指摘頂ければ幸いです。
このドキュメントに起因するいかなる損害についても、筆者は一切の責任を負いません。
ご利用になる場合は、各位にて十分な検証を行うようにお願いします。
また、本ドキュメントに関する著作権は筆者に帰属するものとします。
ただし、ドキュメントの内容は自由に複製したり、改変して使用して頂いても構いません。
0 件のコメント:
コメントを投稿