2017年5月28日日曜日

Shift-JISの使用範囲


 MS ゴシックで表示できるShift-JISの文字(上の画像は隙間を埋めるように移動しているので、正しい配置ではないことに注意)。

 誰か欲しがるかもしれないので、というかみらいのじぶんが使いたくなると思うので、Shift-JISで使用されている範囲を整数配列にしてみた。ジャグ配列だが、1つめが行数、2つ目がXの開始値、3つ目がXの終了値で、XY共に0-255の256個、YがMSBでXがLSB、という感じ。

 目視で確認してるので、間違ってたらごめんね。

 ちゃんと仕様とか調べれば出てくるんだろうなぁ。

 ほんとは文字列のテーブルにして検索できるようにしたかったけど力尽きた。そっちはどこかのサイトのシフトJISコード表でやってくださいorz


 最初の方に日本の元号の記号があるんだけど、明治・大正・昭和は並んでて、平成だけ飛んでるのが面白い。JISコードが最初に作られたのは昭和の時代で、その後に年号が変わってから平成が追加された、っぽい感じ。普通に考えると年号は数十年単位で変わっていくのだから、昭和の次に余裕を付けておいたほうが拡張性があるし、実際文字コードはスカスカなのでそうすることもできたはず。でもそうせずに、次の年号は別の場所に飛んでいる。年号が変わることを考えるとか恐れ多い!みたいな話があったんだろうか。
 ちなみに明治から昭和までの3個は規則増加だが、平成は明治の前にある。なので明治・大正・昭和の記号を文字列の最初につけて文字コードでソートした場合、明治の前に平成が来ることになる。せっかくなら昭和の後ろに追加すればよかったのに。
 さらに蛇足だが、平成の隣(前)は数個の空きがある。なので50-200年くらいは余裕がありそう。ただし明治から昭和がインクリメントなのに対し、平成以降はデクリメントで、ちょっと面倒っぽい。
 さらにさらに蛇足だが、Unicodeでは平成から明治までが連続している。ただし平成の隣に空きはないっぽい。

2017/05/29:修正
 0x7Fを例外で対応していたけど、うまく動かないことがあるらしいのでテーブルで対応。

文字コード沼

 マイコンでフォントを扱おうと思っていて、どうやるのが楽かなーって。
 既存のビットマップフォントを流用するのが一番楽なんだろうけど、ほとんどの文字はShift JIS(あるいはJIS)で、ソースコードをUTF-8に移行している身としてはいちいちUnicodeにして、更にShift JISにして、場合によってはそこから更にJISに変換して、という、マイコンで行うにはかなり面倒な処理が必要。
 ということで、Unicodeで一発で行けないかな、と思ってC#でUnicodeの一覧を出して、SJISの全角文字に含まれている文字は背景を赤に塗ってみた。


 傾向としては最初の方に記号やひらがなが有り、途中に漢字、最後の方に全角アルファベット、という感じらしい。日本の漢字の前には中国の漢字があり、日本語の後ろにはハングルがあるらしい(いわゆるCJKの並び)。
 漢字は21000文字くらいが収録されていて、1byte8pxのビットマップだと、656KiBが必要。他に記号やら色々あるので、700kB前後といったところか。
 STBee F4miniはFlashが1MBあるので、日本の漢字と記号だけなら全部収まりそう。とはいえ、プログラムに使う領域が無くなるのでは本末転倒なわけで。


 とりあえずSJISに含まれる文字をUnicodeの2バイトとビットマップの32バイトのテーブルにして、UnicodeでソートしてROMに格納、二分探索でフォントを探す、みたいな流れになるのかなぁ。でもSJISの文字をすべて持つならUnicodeからIndexに変換するテーブルも持ったほうが早いかも。これならUTF-8の文字列からUnicodeにデコードし、それをテーブルのIndexとして使い、BitmapテーブルのIndexを得る、みたいな流れ。これだと一番重い処理はUTF-8のデコードで、あとは簡単なポインタの演算で済みそう。ただしIndexテーブルを全部持つと128KiBで、J以外のCKを除けば64KiBくらいかな。結構でかい。が、1MiBのマイコンならよゆー。
 

 どうも今やってるヤツが8bitコンピュータとか16bitコンピュータのグラフィック周りの再発明らしくて、その頃の資料がほしいけど、30年近く前のマシンなのか。当然インターネットもないような時代なので、リアルタイムで試行錯誤してるブログやらがネットに漂ってるわけがない。インターネットにはインターネットが普及して以降の情報しか残らないのだッ。タイムマシンはタイムマシンが出来て以降の時代にしか戻れない、みたいな話(?)。

 STM32F4の性能だとファミコンからスーファミ、ゲームボーイあたりの計算能力は余裕で超えてるけど、LSIで高速化してるような部分も全部ソフトでやる必要があるし、ROMをソフトウェアエミュレーションするのも大変だろうから、FPGAのようなモドキを作るのは大変そう。
 秋月で売ってる単色のメモリ液晶でテトリスくらいなら余裕の処理能力だろうけど、それならSTBee Miniだって十分足りるだろうし。となるとPSP液晶か、という流れだけど、そこまで来るとF4でもメモリが足りない。4倍でスケーリングしてRGB8色かBW4色あたりならできるんだろうけど、それもなぁ。
 そっちの方もやってみたいけど、手持ちのPSP液晶、なんか逆接して壊したような記憶があるので、ジャンク覚悟であの配線量を作るのはちょっと嫌だなぁ。


/*
 はいふりOVA、何日か前に届いて見ました。良かった。良かった、くらいの感想しか出てこないほんわかした感じの話。コメンタリーも良かったよ。
 実在する風景がかなり出てきているようだけど、現地から一番遠い両極端の片側に住んでる身としては全然関係ないし。。

 はいふりのキャラでバトルシップをコミカライズした薄い本が読みたいなーと思う今日このごろ。映画のキャラの再配置ですべてできるわけではないけど、かなりいいとこいけそうなんだよね。NOAAのデータは情報好きのタブを使うとか、対物ライフルは砲術科に撃たせるとか。
 あとネイビーミッションっぽい感じでイージスシステムを指揮するゲームをやりたい。久しぶりにネイビーミッションをやったけど、航空機が出てくると見張員の報告がうるさくて状況認識が正常にできなくなる。でも戦闘指揮が確立する前はあんな感じななろうなぁ。
 戦略シミュレーションとかは考える範囲が広すぎて大変なので、戦術シミュレーションとか作戦シミュレーションみたいなカテゴリのゲームが出てこないかな。Arma3は作戦指揮ができるけど、でも自分で指揮してても結局AIを後方において自分が前に出てるし、そもそも作戦指揮もできてない可能性が。。
*/

2017年5月27日土曜日

妄想:パーツクリーナー缶サット

 北海道だと缶サットよりSPeC(Space ProvE Contest)と言うべきなんだけど。

 ふとパーツクリーナーを眺めてたら、これで缶サット作ったら面白そうだな、と思った。直径は350ml缶と同じで、長さが2.5倍くらいある。ということで体積(容積)も2.5倍。去年のSPeCレギュレーションでは全長が35cmまでなので、ちょうどパーツクリーナーが入る。レギュでは直径が15cmまでなので、約7cmの缶は2本まで入る。レギュがあと1cmか2cmほど大きければ3本入るのだが。

 パーツクリーナー缶だと、長さがあるので、一端にパラシュートなりストリーマーなりをつければ垂直に安定させやすそう。となると下端にカメラをつければ地上の撮影に有利かも。また細長い形状ではアンテナの設置にも有利。パーツクリーナー缶の大きさのダイポールアンテナだと430MHzあたりなので、アマチュア無線帯が使えるかな。クロスダイポールだと水平偏波の無指向性になる。充分に仰角が取れるなら円偏波にしてもいい。姿勢が安定してるので、円偏波アンテナは効くかも。

 細長い円筒をパラシュートで落とすとなると、見た目的にはソノブイっぽい。でもアレは海面以下が仕事場であって、SPeCとはちょっと違う。

 どちらかと言うと、Nulkaのほうが近いかも。こっちは垂直に飛び上がった筒が固体燃料である程度の時間浮遊しているらしい。となると、パーツクリーナー缶にも固体燃料なりコールドガスなりで減速とかしても面白いかも。モデルロケットとか並べれば浮遊もできるかもしれないけど、そこまでやると自分で飛び上がれよという話になる。
 大きさ的にはEDFが入りそうだし、容量もあるからLiPoとかも充分入るかも。となると展開翼を追加したいな。でもそうなるとまんまトマホークミサイルになってしまう。


 やはりパーツクリーナー缶は衛星軌道に入れるのが良いと思う。重力傾斜で地上を指向できるから、カメラに有利だし、円偏波のUHFアンテナを搭載できる。金属管なので紫外線等の弱いエネルギーはある程度遮蔽できそう。とりあえず大きな問題は電力収支が大変なことか。円筒の表面に貼れる耐放射線のソーラーパネル。HTVなんかも円筒形状に貼ってるけど、アレは直径がデカイので多角形に近似できる。でもパーツクリーナー缶だと四角形に近似する必要がありそう。となるとすでに円筒じゃないぞという。
 解決策としては、パドルで10x10x30cmの角型形状を作って、それを介して3Uキューブサットとして打ち上げ、放出後はパドルを展開して、みたいな感じ。


 ということでちょっと作ってみた。あぁ、こういうところでペンタブを使うべきなのか。。

 左側が展開前、右側が展開後。重力傾斜とかどういうめかにずむなのかわかってないのでてきとー。
 画像下側が地球側で、その方向にカメラが有り、アンテナやパドルもそのあたりに一塊になってる。
 缶の長さを35cmにしてしまったので3Uに収まらないけど、キニシナイ。
「打ち上げてくれるロケットがないって?ならロケットも作ればいいじゃないか!」
 この形状の利点って何があるかなーって考えると、あんまり思いつかないのだけど、長さを利用して焦点距離の長い光学系を積むとかどうだろうか。といっても口径は50mm程度だし、長いと言ってもそれほどでもないので、あんまり分解能は稼げなさそう。逆に空間が光学系に支配されるデメリットが大きいかも。

***

 去年のSPeCは技術交流会が8月初め、打ち上げが10月初めだったので、そのスケジュールで行くとするとあと2ヶ月ほどで技術交流会となる。そろそろレギュレーションとか確定しないとまずいんじゃね? どっかに出てるのかな。でも去年もWeb告知が出たのって技術交流会の直前だった気がするし、そういう時間感覚なのかな。

 そろそろ缶サット、もとい、SPeCもやってみたいけど、一人でネチネチ考えてても良いミッションが思いつかない。

2017年5月26日金曜日

sscanfのバグ?

 安易に「バグ」というと、「仕様かもしれないだろ!製作者に問い合わせしたのか!?」と突っ込まれたりするらしいので、「謎の挙動」あたりにしておこうかと思いますが。

 char str[] = "hoge 1 2 3"という文字列が有った時に、int i, x, y; uint8_t z;という変数があり、i = sscanf(str + 5, "%d %d %hhu", &x, &y, &z);とした場合、i, x, y, zがそれぞれ3, 0, 2, 3となるとてもふしぎな現象がarm-none-eabi-gccで発生しました。詳細なバージョンは覚えてませんが、4系と5系で発生しています。

 ちなみに、int i, x, y, z;で、フォーマットが"%d %d %d"の場合は問題なく3, 1, 2, 3という結果になります。
 さらに蛇足ですが、一旦"%d %d %d"で変換した場合は、uint8_tを含む"%d %d %hhu"でも問題なく変換できるようです。
 sscanfの実装は見たことがありませんが、なんとなく静的変数の初期値の問題っぽい気がします。一番有り得そうなのは僕が書き換えたリンカスクリプトかなーという気もしますが。

 まぁ、一番手っ取り早い方法は全部intで受け取ることかな、と思います。いちいちビット幅とか気にしないでいいですし、どうせスタックから取ってすぐ開放するんですからメモリ使用量とかも気にしないで(ゲフンゲフン


 どうでもいいですが、「sscanf バグ」でググると、scanfはバッファオーバーランを防げないから使うな、みたいな泥仕合が展開されているようです。
 個人的にはwikipediaに書いてある方法で変数に読み込みつつ、あとでsscanfでパース、というのが楽でいいかなと思います。そんなこと言い始めるとセキュリティ云々とか悪意のあるものが云々とかいろいろ噴出するんでしょうけども。。。

 printfやscanfのフォーマットは、表示するフォーマットと、使用する変数を別の部分で管理できるので、楽だと思っています。C#のConsole.Writeのような方法では変数とフォーマットが複雑に入り混じって面倒です。でもprintfだとどの変数がどこに入って、というのを考える必要があるし、後続の言語でprintfやscanfのようなフォーマットがマイナーになってるからには万人から支持されている方法ではないんだろうなぁとも思います。


 ということで、「よくわからないなぞのきょどう」の話でした(ばぐじゃないよっ!

2017年5月25日木曜日

待ち時間をタイマで生成


 MMCの転送待ちに、タイマでタイミング生成を併用してみました。
 CMD17でシングルブロックリードを開始すると、カードが実際にデータを送ってくるまでにはある程度の待ち時間があるわけですが、これが結構長いので、単純にソフトウェアループを行うとちょっともったいないです。ということでTIMとセマフォを使って数百マイクロ秒のディレイを行い、その間はOSにリソースを返すようにしました。ディレイ中はIdleHookでトグルしているピンが動いているのを確認しているので、予想通りに動いているようです。

 ま、このカードの場合はディレイが1msecを超えてるのでOSに待たせても良いんですけどねorz

 今回は250usのディレイですが、ISRやらセマフォやらタスク切り替えやらで15usほどかかるようです。それでも他にリソースが渡っている時間のほうが長いと思うので、たぶん効果はあると思います。そんなキチキチのプログラムを作ってるのか、という問題はさておき。

 今回はTIM7を使いました。TIM7(と6)はOC/ICが搭載されておらず、トリガの接続も極めて限定的です。実質的に、TIM6/7はタイマ割り込みでソフトウェアのタイミングを作るか、DACの変換トリガに使うか、の2種類しか用途がありません。DACは今のところ使う予定がありませんし、他のTIMにも接続されているのでイザとなればそちらを使えます。ということで7を使いました。ちなみに6は似たような理由で他のソフトウェアタイミング生成に使用済みです。

 STM32のタイマは痒いところに手が届かない感じですが、それでもSTBee F4miniに乗ってる405RGではタイマが14個もありますから、かなり大胆に使えると思います。
 ただし、一部のタイマを除いて、ほとんどはアップカウントしかできない点に注意が必要です。今回の場合はタイマを0xFFFFで初期化しておき、TIMx->CNT = 0xFFFF - 待ち時間 として設定しました(なお、プリスケーラはマイコンの動作周波数[MHz]に設定してあるので、1クロック1usecです)。

2017年5月24日水曜日

妄想:Kindle OH!

 こういうでゔぁいすがほしいなー、という妄想。

 A4サイズの電子ペーパーが100枚(One Hundred page)重なった電子ペーパーデバイス。内蔵電池は無しで、スタンドアロンでの書き換えはできない。USBでPCに接続するとプリンタとして認識され、最初に印刷した100ページ分が表示される。
 オプションでグリップを追加でき、グリップにはLED照明アームがついていて暗いところでも読めるようになる。また、無線LANを内蔵していて、スマートフォンからの印刷が可能。もちろんインターネット接続がある無線LANならamaz○nで買った本を読むことも可能。表示の変更が終わればグリップを外しても表示は持続。
 内蔵ストレージorSDカードでいくつかの文書を持ち歩く、というのもできそう。グリップにはボタンが幾つかついていて、そのボタンで文書を選択するとか。
 設計次第では、複数のKin○le OHをバインダークリップで組み合わせて200ページ、300ページ、といったページ数も可能だと思う。とはいえだいぶ大きい(&重い)モノになるはずなので、複数個組み合わせるよりは個別で読みたいページを含む端末を見るほうが楽そう。

 今の電子リーダーはシーケンシャルリードには便利だけど、ランダムリードがかなりつらい。ということでこういうデバイスが欲しいなぁと思う次第。
 とはいえ、いくら位になるのか。単純計算でKindle PWの倍の面積が100枚とすると300万円くらいか。使用する電子ペーパーが100倍だとしても、売れる量が100分の1なら量産効果は出ない。100分の1も売れるはずがないから、実際の材料単価は上がるはず。使用する電子機器が100分の1になったとしても、あんまり変わらない気がする。
 20万円くらいなら、大量の紙を消費している界隈には売れるかも?10万円くらいなら個人で買える人も多そう。5万円くらいならだいぶ便利だと思う。
 グリップ付きで10万円くらいだと、内蔵ストレージにマンガを2000冊くらい入れればKindleと紙の差分でペイできるかも。「マンガなんてそんな何回も読まねーよ」という人もいるかもしれないが、ちょっとした移動時間に2000冊の中から自由に読んでいいよ、となると読みたくなる人もいるかもよ?今までの紙だと本棚にしまった後はわざわざ取り出して読むのは面倒かもしれないが、常に手元にあるならその面倒はなくなるわけで。

 基本的にページ移動は電子ペーパーをめくることで行うけど、電子ペーパーの隅1箇所にタッチセンサを付けておけば、100冊の表紙を表示して、ざーっと見ていって、読みたい本があればそのページをタッチして選択、10秒位待てばその本が読めるようになる、といったことも可能になる。でもどれくらい便利なのかはやってみないとわからないなぁ。
 タッチセンサが1ページ6分割くらいできるなら、A4のページに6冊分くらいのサムネイルを表示して600冊の表紙を見れる。10分割なら1000冊、20分割なら2000冊で、画面切り替えの待ち時間なしに内蔵された本の表紙をすべて見れる。20分割は小さいと思うけど、Kindle PWのサムネイルも似たような大きさだと思う。


 こういうでゔぁいす、amazonから発売されないかなー。

2017年5月22日月曜日

インデックスカラー

 C#でBitmapをインデックスカラーに変換するのは、Bitmap.Clone(Rectangle, PixelFormat)で、Arg2にFormat8bppIndexedとかを指定すればいい。他にも、4bppや2bpp、1bppも指定できる。ちなみに1bppは白黒の2値画像となる(ネタバレ)。

 Bitmap.CloneでIndexedに変換した場合、以下のカラーパレットが使われる。
たぶん固定値で、変化はしないはず。実際に使われているのは16x14で224色となる。

 Bitmap.Paletteを書き換えればIndexに対するColorを変更することができるが、もちろんIndexとPaletteの関係は変化しないから、単純に色が変わるだけとなる。
 ちらっと試した限りでは自前のPaletteで減色することはできないらしい。そもそも、自分でPaletteを用意できるなら、実際の減色まですべて実装すべき、ということなのだろう。差の評価や拡散によっても再現度はかなり変わるから、自前で作れというのはもっともだと思う。

 それと、帯域が制限されてる回線で画像データを送りたいので、8bppにしてから簡単なランレングスで圧縮してみた。アニメのワンシーンを評価に使うと、画面が一色のときで2%程度、普段が40%前後、状況によって70%くらいの容量となった(ただ簡単にエンコードを書いただけで、デコードも試してないので正しくエンコードされているか不明)。
 減色のアルゴリズムはいくつか有って、グラデーションは閾値を超えるまで同じ色を続けるタイプや、複数の色を並べて見た目上の色をグラデーションさせたりという違いが有る。C#では前者を使っているが、ランレングスでは前者のほうが相性がいい。後者だとグラデーションでは頻繁に値が変化するので、もっと効率のいい圧縮方法を使う必要がある。

 入力画像毎にパレットを生成しなおせば、多少は再現度の高い圧縮が可能なはずだが、1つのパレットを使い続けていれば、最初に1回だけパレットを転送すればいいという利点がある。8bppのパレットを素直に転送すると768バイトになるが、100px四方の8bppは10kB程度で、圧縮して60%くらいまで減らせば6kBになる。そうするとパレットデータが1割くらいを占めるので、かなりデカい。

 そもそもPNGを使えよとか、JPEGを使えよ、という話もあるだろうけど、転送先がワンチップマイコンだったりすると、いちいち展開するのが面倒。今回は相手の処理の都合でインデックスカラーが欲しかったので、JPEGとかで帯域を節約するよりも、減色処理のほうが負荷が高そうということで、8bppBMPを転送することにした。


 そういえば、WinXPとかのペイントで8bppで保存するとかなり劣化したけど、Win7あたりからかなり改善したよなーと思って、Win10のペイントで保存してみたら、かなり劣化した。あれれぇ~~、おかしいなぁ~~。

***

 気がついたらもうこんな時間。ここ2週間くらいはかなり早く寝てたんだけど、急に位相ロックが外れた。夜は涼しくて良いねぇ。静かだし。虫やカエルがうるさいけど。