FlashAirに見つけたバグっぽい挙動を記入
古いファームウェアにある不具合は、アップデートで解消しますので、アップデートをしてください。
http://www.toshiba-personalstorage.net/support/dow...
古いファームウェアにある不具合は、アップデートで解消しますので、アップデートをしてください。
http://www.toshiba-personalstorage.net/support/dow...
秋月DIPボードの挙動が、fa.spiを使った時だけ妙 + mode切り替えをすると動くことがある
という話を聞いたので、mode切り替えだけで出力が切り替わるのかを調査。
初期状態
SCK = HIGH(Hi-Z)
MOSI = HIGH(Hi-Z)
INT = HIGH(Hi-Z)
SS = HIGH(Hi-Z)
MISO = HIGH(Hi-Z)
fa.spi("init")
SCK = LOW
MOSI = LOW
INT = HIGH(Hi-Z)
SS = HIGH
MISO = HIGH(Hi-Z)
→defaultではモード3とリファレンスに書いてあるが、どうみてもmode3ではない。
ただ、1度空readをするとmode3らしき挙動になる。
また、モードを切り替えてもinitするとまた戻される。
fa.spi("mode",0)
SCK = LOW
MOSI = LOW
INT = HIGH(Hi-Z)
SS = HIGH
MISO = HIGH(Hi-Z)
fa.spi("mode",1)
SCK = LOW
MOSI = LOW
INT = HIGH(Hi-Z)
SS = HIGH
MISO = HIGH(Hi-Z)
fa.spi("mode",2)
SCK = HIGH (時折LOWのまま)
MOSI = LOW
INT = HIGH(Hi-Z)
SS = HIGH
MISO = HIGH(Hi-Z)
fa.spi("mode",3)
SCK = HIGH (時折LOWのまま)
MOSI = LOW
INT = HIGH(Hi-Z)
SS = HIGH
MISO = HIGH(Hi-Z)
・結論
切り替わった。
ただし、時折切り替わり不良を起こしているらしき状態がある。
(mode3なのにSCKがLなど。cs切り替えでも発生する)
その場合、いくら切り替えても治らない。(極稀に治る。)
ただ、fa.spi("read")とでもして送信処理をさせれば、必ず切り替わる。
CSの前、もしくは後に空読みを入れると、不安定さが解消するようです。
参考:Lua:fa.spiサンプル
CSが反映されないことがあるバグ(or仕様)が影響し、
連続したパケットとして認識されていた可能性が高いです。
ソフトSPIで動いていたのは、このバグ(or仕様)がないためだと考えられます
という話を聞いたので、mode切り替えだけで出力が切り替わるのかを調査。
初期状態
SCK = HIGH(Hi-Z)
MOSI = HIGH(Hi-Z)
INT = HIGH(Hi-Z)
SS = HIGH(Hi-Z)
MISO = HIGH(Hi-Z)
fa.spi("init")
SCK = LOW
MOSI = LOW
INT = HIGH(Hi-Z)
SS = HIGH
MISO = HIGH(Hi-Z)
→defaultではモード3とリファレンスに書いてあるが、どうみてもmode3ではない。
ただ、1度空readをするとmode3らしき挙動になる。
また、モードを切り替えてもinitするとまた戻される。
fa.spi("mode",0)
SCK = LOW
MOSI = LOW
INT = HIGH(Hi-Z)
SS = HIGH
MISO = HIGH(Hi-Z)
fa.spi("mode",1)
SCK = LOW
MOSI = LOW
INT = HIGH(Hi-Z)
SS = HIGH
MISO = HIGH(Hi-Z)
fa.spi("mode",2)
SCK = HIGH (時折LOWのまま)
MOSI = LOW
INT = HIGH(Hi-Z)
SS = HIGH
MISO = HIGH(Hi-Z)
fa.spi("mode",3)
SCK = HIGH (時折LOWのまま)
MOSI = LOW
INT = HIGH(Hi-Z)
SS = HIGH
MISO = HIGH(Hi-Z)
・結論
切り替わった。
ただし、時折切り替わり不良を起こしているらしき状態がある。
(mode3なのにSCKがLなど。cs切り替えでも発生する)
その場合、いくら切り替えても治らない。(極稀に治る。)
ただ、fa.spi("read")とでもして送信処理をさせれば、必ず切り替わる。
CSの前、もしくは後に空読みを入れると、不安定さが解消するようです。
参考:Lua:fa.spiサンプル
CSが反映されないことがあるバグ(or仕様)が影響し、
連続したパケットとして認識されていた可能性が高いです。
ソフトSPIで動いていたのは、このバグ(or仕様)がないためだと考えられます
→解消済み
FlashAirでスクリプトを書いていると、こういうことが起きます。
これらは、FlashAirがフリーズした場合に発生します。
ちなみに私は、DSiを電源供給用に使っていて、音楽を再生していたら
スクリプトを実行した途端音楽が壊れてガチでビビりました。
また、503エラー、403エラー、応答にやたら時間がかかる、などの場合、
同様のメモリエラーが起きています。(フリーズ寸前です)
→単純に深い場合
FlashAirはメモリが小さいため、関数の中で関数を呼び出す、というのを繰り返すと、よくフリーズします。
特に、fa.requestはフリーズしやすく、また普通の関数でもフリーズします。
メモリの空き状態によってフリーズする条件が変わるので、結構困りますが、関数を深くしないということに気を付ければ
大分引っかかりにくくなります。
例1. fa.requestの場合
function f()
f()
この場合、
1.fa.requestを呼び出す階層を減らす (functionで囲わない)
2.tostring周辺の演算を先にしておく(公式のサンプルではそうなっています)
というのが挙げられます。
改善例
function f()
f()
例2. 普通の関数でも
function f(i)
print("HTTP/1.1 200 OK\n")
print("OK")
f(f(f(f(f(f(f(0)))))))
これはさすがにないだろ、と思われるかもしれませんが、
これは毎度必ずフリーズする条件を探った結果で、他のスクリプトの実行後などでは
f(f(0))でもフリーズすることがまれにあります。
もちろん、同じ関数でなく、f1(f2(0))でも起きますし、先のfa.requestのように、関数の処理内で関数を呼び出しても落ちることがあります。
関数は多くても3階層くらいまでにしたほうがいいでしょう。
FlashAirでスクリプトを書いていると、こういうことが起きます。
- 突然Webサーバーにつながらなくなった
- インターネットにつながらなくなった(インターネット同時接続モードのとき)
- 突然ping応答がなくなった
- デジカメがSDカードエラーを吐いた(しかも差し込みなおすと治るが、スクリプトが動く条件になると再発する)
- 差し込んだ機械がフリーズした
- PCから読み込みも書き込みもできなくなった
- ファイルが破損した
- フォーマットが必要になった
これらは、FlashAirがフリーズした場合に発生します。
ちなみに私は、DSiを電源供給用に使っていて、音楽を再生していたら
スクリプトを実行した途端音楽が壊れてガチでビビりました。
また、503エラー、403エラー、応答にやたら時間がかかる、などの場合、
同様のメモリエラーが起きています。(フリーズ寸前です)
→単純に深い場合
FlashAirはメモリが小さいため、関数の中で関数を呼び出す、というのを繰り返すと、よくフリーズします。
特に、fa.requestはフリーズしやすく、また普通の関数でもフリーズします。
メモリの空き状態によってフリーズする条件が変わるので、結構困りますが、関数を深くしないということに気を付ければ
大分引っかかりにくくなります。
例1. fa.requestの場合
function f()
mes = "" b,c,h = fa.request{url = "http://example.com/", headers = {["Content-Length"] = tostring(string.len(mes))}} print("HTTP/1.1 200 OK\n") print("OK")end
f()
この場合、
1.fa.requestを呼び出す階層を減らす (functionで囲わない)
2.tostring周辺の演算を先にしておく(公式のサンプルではそうなっています)
というのが挙げられます。
改善例
function f()
mes = "" len = tostring(string.len(mes)) b,c,h = fa.request{url = "http://example.com/", headers = {["Content-Length"] = len}} print("HTTP/1.1 200 OK\n") print("OK")end
f()
例2. 普通の関数でも
function f(i)
print(i) return i+1end
print("HTTP/1.1 200 OK\n")
print("OK")
f(f(f(f(f(f(f(0)))))))
これはさすがにないだろ、と思われるかもしれませんが、
これは毎度必ずフリーズする条件を探った結果で、他のスクリプトの実行後などでは
f(f(0))でもフリーズすることがまれにあります。
もちろん、同じ関数でなく、f1(f2(0))でも起きますし、先のfa.requestのように、関数の処理内で関数を呼び出しても落ちることがあります。
関数は多くても3階層くらいまでにしたほうがいいでしょう。
→解消済み
dofileという、外部のスクリプトを読み込む機能がありますが、なぜかフリーズします。使わない方が安全です。
loadfileで関数として読み込むのはフリーズしにくいですが、前述の関数階層が-1されるので、注意してください。
requireも同じく外部からスクリプトを読み込む機能があります。
で、このrequireを使って2KB以上のスクリプトを読み込むと、その場では正常に動きますが
string.byteを呼び出すとフリーズします。他の関数でもフリーズするかもしれません。
回避策は、requireで読み込むサイズを1KB以下に抑えるか、requireを使わずスクリプトに直書きすることです。
FlashAirは最低8GBも容量がありますから、使わない手はない。富豪的に行きましょう。
...かと思いきや、べた書きでも18KBくらいで頭打ちになります。
dofileという、外部のスクリプトを読み込む機能がありますが、なぜかフリーズします。使わない方が安全です。
loadfileで関数として読み込むのはフリーズしにくいですが、前述の関数階層が-1されるので、注意してください。
requireも同じく外部からスクリプトを読み込む機能があります。
で、このrequireを使って2KB以上のスクリプトを読み込むと、その場では正常に動きますが
string.byteを呼び出すとフリーズします。他の関数でもフリーズするかもしれません。
回避策は、requireで読み込むサイズを1KB以下に抑えるか、requireを使わずスクリプトに直書きすることです。
FlashAirは最低8GBも容量がありますから、使わない手はない。富豪的に行きましょう。
...かと思いきや、べた書きでも18KBくらいで頭打ちになります。
→解消済み
fa.requestは3KBまでしか受信できません。これは公式の仕様です。はい。終わりです。
では、大きなファイルを受信するにはどうするかというと、HTTPGetFileを使用しますが、これまた曲者です。
FlashAirをいじってわかったこと。より。
fa.HTTPGetFileは、アクセス先のサーバーによって(条件不明)、
・正常に受信できる
・受信に成功するが、先頭と末端にゴミがつく
・受信失敗ということになるが、なぜか連番拡張子なしのファイルが生成され、
中身はゴミ付きの目的のデータ
・受信に失敗する
の4パターンがある。
詳しく検証していないが、ゴミはチャンクストリームそのものの可能性もある。
です。
正常に受信できたのは以下です。
・http://192.168.1.3/ (BJDで立てた自鯖)
・http://example.com/
・http://lashair-developers.com/ja/
正常に受信できなかったのは以下です。
・http://www.google.co.jp/
・http://ja.wikipedia.org/
f=fa.HTTPGetFile("http://www.google.co.jp/","test.htm")
の場合。
中身は
「8000
<!doctype html><html
〜省略〜
</body></html>
」
となる。先頭にゴミが付き、末端に空行がつく。
また、これは指示したtest.htmではなく、別の連番ファイルに保存される。(受信可否は失敗となっている)
f=fa.HTTPGetFile("http://ja.m.wikipedia.org/wiki/A","test.htm")の場合、
f=1で受信成功だが、test.htmの中身が
「008000
<!DOCTYPE html>
<html lang="ja"
〜省略〜
</body>
</html>
/spa」となる。
明らかに先頭と末端に余計なごみが付いている。また、一部の文字が化ける。
これらより、HTTPGetFileは極力使わない方がよさそうだということがわかる。
そもそも。SDカード内にファイルを生成すること自体が極めて高確率でFAT破壊を引き起こす。
(電源のみ供給した場合を除く)ので、やらない方がいい。
fa.requestは3KBまでしか受信できません。これは公式の仕様です。はい。終わりです。
では、大きなファイルを受信するにはどうするかというと、HTTPGetFileを使用しますが、これまた曲者です。
FlashAirをいじってわかったこと。より。
fa.HTTPGetFileは、アクセス先のサーバーによって(条件不明)、
・正常に受信できる
・受信に成功するが、先頭と末端にゴミがつく
・受信失敗ということになるが、なぜか連番拡張子なしのファイルが生成され、
中身はゴミ付きの目的のデータ
・受信に失敗する
の4パターンがある。
詳しく検証していないが、ゴミはチャンクストリームそのものの可能性もある。
です。
正常に受信できたのは以下です。
・http://192.168.1.3/ (BJDで立てた自鯖)
・http://example.com/
・http://lashair-developers.com/ja/
正常に受信できなかったのは以下です。
・http://www.google.co.jp/
・http://ja.wikipedia.org/
f=fa.HTTPGetFile("http://www.google.co.jp/","test.htm")
の場合。
中身は
「8000
<!doctype html><html
〜省略〜
</body></html>
」
となる。先頭にゴミが付き、末端に空行がつく。
また、これは指示したtest.htmではなく、別の連番ファイルに保存される。(受信可否は失敗となっている)
f=fa.HTTPGetFile("http://ja.m.wikipedia.org/wiki/A","test.htm")の場合、
f=1で受信成功だが、test.htmの中身が
「008000
<!DOCTYPE html>
<html lang="ja"
〜省略〜
</body>
</html>
/spa」となる。
明らかに先頭と末端に余計なごみが付いている。また、一部の文字が化ける。
これらより、HTTPGetFileは極力使わない方がよさそうだということがわかる。
そもそも。SDカード内にファイルを生成すること自体が極めて高確率でFAT破壊を引き起こす。
(電源のみ供給した場合を除く)ので、やらない方がいい。
→解消済み
a.luaというスクリプトがFlashAirのルートにあるとき、
http://flashair/a.lua?b
と渡してあげれば、arg[1]で引数"b"が取り出せる。
では、この引数は何文字まで付けられるのか。
RFC上は制限がないが、このメモリの少ないFlashAirではそんなことはない。
一般的にはURL全体で255文字とか、2048文字とか言われているが、
結論から言うと、自身の名前+?(セパレータ)も含めて、142文字までで、それ以上は打ち切られる。
また、引数の末端には0x0Aがくっつく、はず。地味に邪魔なので注意。
142文字以上を入れると、末端に不可視の制御文字が紛れ込む。正直邪魔なので、それ以下の長さにした方がいい。
さらに長く、200文字くらい入れると、メモリ破壊を起こすらしく、Webサーバー機能が停止する(503/403もしくは応答なし)
javascriptなどから生成して送るときは要注意。
a.luaというスクリプトがFlashAirのルートにあるとき、
http://flashair/a.lua?b
と渡してあげれば、arg[1]で引数"b"が取り出せる。
では、この引数は何文字まで付けられるのか。
RFC上は制限がないが、このメモリの少ないFlashAirではそんなことはない。
一般的にはURL全体で255文字とか、2048文字とか言われているが、
結論から言うと、自身の名前+?(セパレータ)も含めて、142文字までで、それ以上は打ち切られる。
また、引数の末端には0x0Aがくっつく、はず。地味に邪魔なので注意。
142文字以上を入れると、末端に不可視の制御文字が紛れ込む。正直邪魔なので、それ以下の長さにした方がいい。
さらに長く、200文字くらい入れると、メモリ破壊を起こすらしく、Webサーバー機能が停止する(503/403もしくは応答なし)
javascriptなどから生成して送るときは要注意。
→解消済み
print(arg[1]) と書かれたスクリプトを呼び出しただけの場合で、
URLの長さが129文字の状態で実行すると、260回のアクセスでフリーズする。
これは、連続でなく、電源を入れてからの累計である。
また、複雑なスクリプトの場合、40回程度呼び出しただけでフリーズする場合がある。
つまり、利用者アンケートのようなものを記録するHTMLフォームを作った場合、40人程度でフリーズして
FlashAirを再起動するまで受け付けない、ということがあるということである。
幸いなことに、フリーズするのはLua実行機能のみで、普通のファイルを配布する機能としてのWebブラウザや
SDカードとしての機能は生きているので、その辺の心配は不要であるが。
print(arg[1]) と書かれたスクリプトを呼び出しただけの場合で、
URLの長さが129文字の状態で実行すると、260回のアクセスでフリーズする。
これは、連続でなく、電源を入れてからの累計である。
また、複雑なスクリプトの場合、40回程度呼び出しただけでフリーズする場合がある。
つまり、利用者アンケートのようなものを記録するHTMLフォームを作った場合、40人程度でフリーズして
FlashAirを再起動するまで受け付けない、ということがあるということである。
幸いなことに、フリーズするのはLua実行機能のみで、普通のファイルを配布する機能としてのWebブラウザや
SDカードとしての機能は生きているので、その辺の心配は不要であるが。
コメントをかく