2016/08/31

[c/c++]私のC言語 (9) - ローカル変数を宣言する位置

C99からだと思うが、変数の宣言位置がどこでもよくなった。
ローカル変数の話なのだが、あれ、用語としては宣言と定義のどっちだ?

・・・K&Rでは「変数の宣言」になっているから、宣言としておこう。
と書いたものの、externの説明では「外部変数の定義」と書いているな。
付録の「宣言」のところには「メモリを確保する宣言は定義と呼ばれる」と書かれている。
つまり、"宣言"の特殊形が"定義"ということか。

もう1冊持っていた「C言語 重要用語解説」では、以下の"宣言"を"定義"と呼ぶそうだ。

  • オブジェクトに対しては、そのオブジェクトの記憶域を確保する宣言
  • 関数に対しては、関数本体を含む宣言
  • 列挙定数またはtypedef名に対しては、その識別子の宣言

んで、その下に「"int i;"のようなオブジェクトの定義は一般的には宣言と呼ぶ傾向にある」と記載してあった。
なんだよ、傾向って。。。

確かに私の中でも、static変数は「定義」って感じがするけど、ローカル変数は「宣言」で済ませたい気持ちがある。
スタックポインタをずらすだけだからだろうか?

というわけで、ここでは「宣言」にしておくので、各自の用語定義で読み直してほしい。


宣言位置はC++がそうだったからあまり気にしていなかったのだが、ANSI-Cなどはブロックの先頭で行う言語仕様だったからそうしていた。
今は「C99で書いてます」と言っておけば、使う時になって宣言すればよいので、気持ちとしては楽だ。

私は、ローカル変数の宣言時に強制的に初期化するのが嫌でねぇ。。。
後で書き換えられない可能性があるならよいけど、書き換えられるのがわかっているなら省きたい。
それだったら、使用する直前に宣言して、同時に代入してしまった方が無難だ。

ただ、変数の戻り値ret、みたいな変数はあちこちで使うので、これはブロックの先頭に書くね。

 

switch文の中でしか使わない変数の場合は、ちょっと揺れる。
ブロックを作るか、switch文の外に宣言しておくか。。。
caseの中にブロックを書くと、インデントをどうするか悩むのだ。
私は、caseをインデントしない派なので、こんな感じになってしまう。

switch (calc_val) {
case 1:
    {
        int a = calc_val * rand();
        ...
    }
    break;

別によいのだけど、せっかくcaseをインデントさせなくて浅めにしたいのに、ブロックで深くなるともったいない、とも思ってしまうのだ。

じゃあ外に書けばいいやん、となるけど、その変数ってここでしか使わないのに・・・と、こっちはこっちで気持ちが微妙になる。


forのループ変数をその場で定義するのは、よくやる。

for (int loop = 0; loop < 10; loop++) {
   ...
}

ただ、途中でbreakしたかどうかを知りたいときは、抜けた後で変数の数を見たいから、外で宣言することになる。

それだったら、最初から外で宣言すればいいやん、と思われそうだけど、うーん、あまりそれは好きじゃないのだよなぁ。
理由が説明できないのだが、forを終わったらスタックポインタが戻るから、とかか?
でもレジスタに割り当てられることもしばしばだから。。。

うん、さっきのswitchと同じで、単に好みの問題だな。

2016/08/30

[c/c++]私のC言語 (8) - メモリの確保

小さいシステムで、メモリがぎりぎりになるようなときの事前計算が非常に苦手です。
ほどほどに余裕があればよいのですが、足りない=マイコンの変更=コストアップ!なので、ぎりぎりになりそうなくらいであれば、その前から大きめのRAMを持つマイコンにしてもらうようにしています。

だって!
後から変更がきかないのですもの!!

その時は、試作する段階があり、その段階でサイズがあまり空いていなかったのでこのRAMサイズでは厳しいよなー、というのがわかり、大きめにしてもらいました。

しかし、その段階では通常アプリの仕様もわかっていないことが多いので、「どのくらい?」と聞かれても困ります。
それに、作っている途中で要求が変わってきたり、回避できない現象が出たりするので、「間に合うかも」のサイズで実装を開始するのはよろしくないと思います。

部品代が上がると製品コストに直結するので、嫌がる人も多いのですが、じゃあそのために(ハード以外で)費やされたコストをどこで回収するのか?ということになります。

もし、最終的に足りないならば、結局ハードを変更することになるので、最初からハードを変更していた方が議論するコストなどを考えずに済みます。
ハードを変えずにRAMの消費を減らすとなると、組み込み屋さんのソースコードはそこまで無駄食いをするようなコードを書かないので、元々余力(=減らす力)はあまりなさそうに思います。

どうせこのあと、不具合だとか仕様変更とかでやることが増えるんでしょう?と思うと、あんまりピッチリしたコードを書くよりも、遊びを持たせて余裕がある作りにしておいた方が安全じゃないか、と思いつつあります。

いや、昔は、そんな余裕のあることを言っていられないほどメモリが少なくてね。。。


ということで、だいたいこういうことにしています。

  • ハードがまだ確定していない場合は、めいっぱいメモリが取れる(マイコンを使ってもらえる)ようにがんばる
  • ハードが確定していて、メモリが少ないなら、がんばってメモリを使わないようにする
    • 機能削減も視野に入れよう

うん、がんばるところが違いますな。
そして、後者の方が大変なのは、だいたいわかります。。。
でも、前者ができない場合もあるでしょう。

そんなこんなありますが、このレベルでは圧縮が効かないので、何とかするしかありません。
つらいですね。。。

[git]一時的なリリースは一時的なブランチへ

新しい酒は新しい革袋で、みたいな感じだが、全然違う話だ。

新しい酒は新しい革袋に盛れ - 故事ことわざ辞典

 

gitで、こんな運用をしていた。
通常は開発ブランチで、リリースするときだけリリースブランチにマージしている。
一人でやっているので、そこまできっちりしてなくてもよいのだが、いざというときのためにね。

image

なので、リリース直後は、だいたい開発ブランチとリリースブランチが同じになっている。
違うのは、リリース時にはリリース用のバージョンを振り直すくらいか。

 

今回、いろいろ試したいということで、少し違ったものをちょこちょこ作っていって、このパターンを残して後はいいや、ということになった。
ちなみに、開発ブランチのものも「開発版」ということでリリースすることがあり、この×がついているものもリリースしてpushされている(revertなどせず、実際は残っている)。

image

じゃあ、ということで古いやつをマージしてリリースした。
そこまではよかった。

これまでのマージ直後は、開発ブランチもリリースブランチも、gitのグラフで見ると同じポイントを指していたのだが、これが分かれてしまった。
今思えば、×がついたものをrevertしてからリリースブランチとマージすればよかったように思うが、pushしてしまったので後の祭りだ。
開発ブランチに移動して、リリースブランチの方をマージしたのだが、コンフリクトして修正するため、やはりブランチが分かれてしまう。。

 

別に開発ブランチを捨てて新しく作ってもよいのだけど、今からでもうまくやる方法はあるのだろうか?
反省としては、一時的に作ると予めわかっているのなら、一時的なブランチを作った方がよいだろう、ということだ。

今回は、またいつか会える日も来るさ、とクールに別れようと思う。

[c/c++]私のC言語 (7) - 構造体の初期化

だんだん「私の」がどうでもよくなってきた。。。
さっきやっていて、気付いた話だ。

構造体のメンバを初期化していた。
全部のメンバを初期化したいわけではなかったので、ちまちま代入させていたのだが、初期化子としてメンバ名を指定するタイプもあったことを思い出した。
「指定初期化子」と呼ぶらしい。
GCC拡張っぽい書き方だが、C99で採用されたようだ。

 

そっちで書いた方がサイズが小さくなるかと思ったが、結果的には増えていた。
なんでじゃ?と思い、代入していた頃に戻して、構造体の初期化で「={0}」を追加すると同じサイズになった。
なるほどねぇ。

今回試したのは、メンバが4つくらいしかないため、ちまちま代入させた方がサイズが小さくなるけれども、0を代入するような初期化であれば「={0}」なり指定初期化子なりを使った方がサイズが小さくなるかもしれない。

昔いくつか見たときには、「={0}」ってmemset()に変換されていたけど、今はどうなんだろうね?
標準ライブラリを組み込まないときに「memsetがない」って怒られたときは、訳がわからなかったぞ。。。

2016/08/27

[nfc]iPhoneに載るのか?

前に、NFC Forumの記事を読んで、iPhoneにFeliCaってのは考えづらいよなぁ、という感想で終わらせた。
hiro99ma blog: [nfc]NFC Forumジャパンミーティングの記事がよくわからん

 

が、最近、こういう記事がちらほら見られた。

iPhoneがおサイフケータイ(FeliCa) に対応か。Apple Payが間もなく日本上陸 - Engadget Japanese

ほう。
もし載るのだったら、ジャパンミーティングの報告よりもずいぶん前から話が進んでいたのだろう。

 

ただまあ、こういうのは、蓋を開けるまでわからないからねぇ。。。
とりあえず私は懐疑派で、もし出てきたら「やっぱり勘が外れたのかぁ」と思うことにしよう。

RC-S390もそうだし、wenaもそうなのだけど、iOSがけっこう優先されているな、と思ったのだ。
優先されているというか、AndroidでもできそうなのにiOSしか対応していないな、と。
まあ、関係あるのか知らんけどね。


もし載せるのだったら、今と同じ、オンボードでチップを載せることになるのかな。
モバイルFeliCaチップと、あとはメモリとアンテナか。

カード型は読み取られるだけだから電源はいらないけど、モバイル型はチップを動かすので電源がいる。
詳しくないけど、R/W機能がないなら、出力はそこまでがんばらなくても良さそうだから、今のままでよいのかな?
そして、チャージをアプリから行うしくみがいるので、そういうSDKも販売していたと思う。
ハードの改造もいるし、アプリの開発もいるのだ。

 

新しく電子マネーを携帯端末で使えるようにしようとしたら、そういう端末側だけじゃなくて、店舗で読み取ってもらうR/W作ったり配布したり、サーバだとかセキュリティとか、たぶんうじゃうじゃやることがあるのだろう。
そういうのは大変なので、あまりやっているところがないのだと思う。

そこら辺を、もし海外の業者がやるんだったらどうなるのか、という一例として見るのが面白いのかもしれんです。

2016/08/26

[c/c++]私のC言語 (6) - 整形

C言語は、書き方が自由だ。
スペースだったりタブだったり、改行を入れたり入れなかったり。
インデントだって、けっこう人それぞれだ。

それはそれでよいと思うのだが、自分のスタイルじゃないソースコードを読むのは、けっこう苦痛である。
そういうとき、整形ツールで整形させるとよいだろう。

私は、これを使っている。
http://astyle.sourceforge.net/

 

たとえば、括弧の位置については、こういうオプションがある。
http://astyle.sourceforge.net/astyle.html#_Bracket_Style_Options
私はk&rかなぁ、と思ったが、stroustrupとの違いは何だろう?
namespaceやclassはk&rでは対象外と言うことかな。

1行でも括弧を付けてほしいので、これをつける。
http://astyle.sourceforge.net/astyle.html#_add-brackets

スペースかハードタブかは、お好みだな。
私の最近の流行りは、スペースだ。
http://astyle.sourceforge.net/astyle.html#_Tab_Options

2016/08/25

[c/c++]私のC言語 (5) - FFF

私は、だいたい実装するとユニットテストをしている。

実機ではなかなか通しにくいルートだけど、通ったときの動作は見ておきたい、という場合によいし、コードを書き換えた後でテストを通し、前との違いを比較する場合にも良い。

テストを作るのは面倒で時間はかかるのだが、自分の書いたものが期待通りかどうかを知るためにもやっておきたいものだ。

gccはカバレッジを取るためのビルドができるので、通ったことがないかどうかを目視しやすい。
一度通ったルートはカウントアップされるだけなので、このときにここを通った、というのには向かないのだが、それを知りたければ1つだけテストを書いて実行すれば良いだけだ。


意図通りのルートを通したいとなると、標準関数やドライバも意図通りの値を返してほしい。
が、それは難しいので、スタブやらモックやらを作る。
私は、それをFFFというフレームワークを使ってやっている。

meekrosoft/fff: A testing micro framework for creating function test doubles

検索して探すときは「fff fake」などで出てくるだろう。
使っている人の例もあるので、そっちの方がわかりやすいかも。

 


まず、githubからcloneしよう。
今の最新は3cd33edだ。
私の環境は、cygwinである。

こんなソースを書いたとしよう。
ソースファイルべた書きで済まぬ。。。

my_open(), my_close(), my_access()の3つがある。
my_open()とmy_close()UARTのオープン/クローズのイメージ。
my_access()は、コマンドを送信するとレスポンスが返ってくるデバイスがつながっていて、1回のコマンド送信に対してレスポンスを2回に分けてチェックしながら受信する、という想定だ。
ファイルディスクリプタは、static変数sfdで保持しておく。


#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

static int sfd = -1;

int my_open(const char *pTty)
{
    if (sfd != -1) {
        return -100;
    }

    int fd = open(pTty, O_RDWR);
    if (fd == -1) {
        return -1;
    }
    sfd = fd;
    return sfd;
}

void my_close(void)
{
    close(sfd);
    sfd = -1;
}

int my_access(void)
{
    const uint8_t WRT[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };

    uint8_t buf[20];
    ssize_t sz;
   
    sz = write(sfd, WRT, sizeof(WRT));
    if (sz != sizeof(WRT)) {
        return -2;
    }

    sz = read(sfd, buf, 5);
    if ((sz != 5) || (buf[4] != 0xff)) {
        return -3;
    }
    sz = read(sfd, &buf[5], 3);
    if ((sz != 3) || (buf[7] != 0x35)) {
        return -4;
    }

    return 0;
}


まず、my_open()のテストをするとしよう。

最初にsfdが-1以外かどうかをチェックして、オープン済みなら終わらせる。
次にopen()を呼んで、戻り値が-1だったら、エラーとして終わる。
それ以外なら、sfdに保存して終わる。

というわけで、ここでやりたいのは、

  • sfdを-1以外にして、-100が返ってくるのを確認する
  • sfdを-1にして、open()が-1を返すようにし、-1が返ってくるのを確認する
  • sfdを-1にして、open()が-1以外を返すようにし、その値が返ってくるのを確認する

という3つだ。
これを、FFFを使ったテストコードにすると、こうなる。

TEST_F(test, open_1)
{
    sfd = 3;

    int fd = my_open("/dev/ttyS1");

    ASSERT_EQ(-100, fd);
}

TEST_F(test, open_2)
{
    sfd = -1;

    open_fake.return_val = -1;

    int fd = my_open("/dev/ttyS1");

    ASSERT_EQ(-1, fd);
}

TEST_F(test, open_3)
{
    sfd = -1;

    open_fake.return_val = 5;

    int fd = my_open("/dev/ttyS1");

    ASSERT_EQ(5, fd);
}

長くなるので省略しているが、これよりも前の部分がある。
実はそこで、テスト対象のソースファイルをincludeしている。
だから、直接sfdが扱えるのだ。
なんとなく邪道じゃろう?
でも、楽なのだよ。

open_fake.return_val、というのは、関数をモック化する手続きをしておくと、<関数名>_fakeという構造体ができるようになっていて、そのreturn_valという変数だ。
これに値を入れておくと、その値が戻り値になってくれる。

ASSERT_EQ()は、FFFではなくGoogle Testが提供するものだ。
FFFはGoogle Testと併用しやすくなっている。


では、my_access()みたいにread()を何度も呼び出すタイプはどうするか?
いくつかやりかたはあるのだが、戻り値も変える、引数で返す値も返るとなると、自分でモックを定義した方が簡単だと思っている。

たとえば、戻り値が0になるテストだと、こういう感じだ。

TEST_F(test, access_1)
{
    sfd = 5;

    class dummy {
    public:
        static ssize_t read(int fd, void *p, size_t sz) {
            static int count = 0;
            int ret = -1;
            uint8_t* buf = (uint8_t *)p;
            switch (count) {
            case 0:
                ret = 5;
                buf[4] = 0xff;
                break;
            case 1:
                ret = 3;
                buf[2] = 0x35;
                break;
            default:
                assert(0);
            }
            count++;
            return ret;
        }
    };

    write_fake.return_val = 5;
    read_fake.custom_fake = dummy::read;

    int ret = my_access();

    ASSERT_EQ(0, ret);
}

read_fake.custom_fakeはデフォルトがNULLで、その場合はreturn_valの値を返す(配列で順番に値を返してもらうようにもできる)。
設定すると、その関数が呼ばれる。

今回は、dummyクラスのread()を呼ぶようにしている。
普通の関数にしても良いのだが、テストごとに定義していると名前の重複が発生して面倒になりそうだから、こういう形にしている。


今回作ったものは、ここに置いた。
https://github.com/hirokuma/fff_examples

作ったのは、func., test_func.cppと、Makefileをいじっただけだ。
それ以外のものは、FFFからコピーしただけである。

慣れるまでは使いづらいかもしれないが、いくつか作って自分の作り方を蓄積させておくと、だんだん楽になっていくかもしれない。

[nrf52]大きいNDEFデータにすると不安定だ

nRF52832は、Type2 Tagとして動作することができる。

Type2 Tagとは、MIFARE Ultralightみたいなやつだ。
以下、ULと略す。
ちなみに、Ultralight Cというのもあって、そっちはセキュリティ機能があるらしい。
NXPに申請しないと資料をもらえないようなので、詳しくは知らない。

 

サンプルを動かして、AndroidアプリのNXP TagInfoで読み取った方はわかるだろうが、普通のタグに比べると読み取りに時間がかなりかかる。
これはタグのエミュレーションに時間がかかっているわけではなく、データが多いためだ。

たとえば、よく見かけるNTAG203では48ブロック分しかないのだが、nRF52832のnRF5 SDK v11.0.0では256ブロック分あるのだ。
1ブロック4バイトなので、1KB。

このサイズは、タグとしてはなかなかない。
MIFARE Classicは、1Kとか4Kとかが普通だったけど、Type2 Tagなんかは小さいものが多いのだ。

まあ、通常は使うブロックだけ読めばよいので、使い勝手に違いはないだろう。


せっかく大きいデータが使えるので、大きいデータを流してみよう。
大きいデータと言えば、やはり画像だろう。
PNGデータを作って、TNF=0x02、MediaTypeがimage/pngのNDEFデータを作ってみた。

が・・・Androidで読ませても、なんか毎回データが違う。

不安定なのか?と思い、Windows10 + PaSoRiで読込ませた。
幸いWindows10はNDEFを解釈してくれるので、画像ファイルとして保存してくれた。

が・・・。
こちらも、毎回結果が違う。

image

原因がどこら辺にあるのかはわからないけど、大きいデータは使わない方がよいということはわかった。

2016/08/24

[nrf52]Android 7じゃないとNFCペアリングはうまくいかないの?

Nordicブログには珍しく、新しいAndroidのことが記事になっていた。
うちのNexus5は対象から外れたらしいのだが、7用のドライバだけでも提供してくれたら自分でビルドして遊んでみるのだけどなぁ。

nRF52832 and Android Nougat – simple and secure touch-to-pair.

英語なので読み飛ばそうと思ったのだが、気になる一文を見つけた。

support for Bluetooth pairing with NFC using the out-of-band (OOB) method is included.

んん??
もうちょっと読んでみた。

In fact, we have had examples to do NFC pairing using the OOB method in our nRF5 SDK for quite a while and it worked with Android Nougat “out-of-the-box”.

「out of the box」は、Raspberry Piのところでも出てきたが、すぐに使える、という意味だ。
つまり、なんもせんでもAndroid 7だったらSDKに入っているNFCペアリングのサンプルが使えるよ、という意味だろう。

なんだよ、動かないってわかっていたのかよ!!

確かに、私の調べでも、Androidがタイミングを変えてくれない限りはどうしようもない、というところだったのだけど。。。
どこかで、Nexus5は対応しているような記述があったような気がしたのだが、今探しても見つからない。

うぅぅぅ。。。

 

とにかく、今までのでは動かない、というのは間違っていなかったので、それでよしとしよう。

[mbed]mbed OSはRTOSなのか?

しばらく前に、mbed OS 5がリリースされた。
今はもう5.1だが、メジャーバージョンアップだ。。。というか、OSの2と3を足して5らしい。

Introducing mbed OS 5 | mbed

 

FreeRTOSを調べていたので、そういえばmbed OSはRTOSなのだっけ?と気になった。
まあ、組み込みのOSでRTOSじゃなかったら、使うことは無さそうな気がするので、たぶんそうだろう。

リアルタイムオペレーティングシステム - Wikipedia
ここに列挙されているだけでもたくさんあるな。
私が使ったことがあるのは、わずかだ。

 

mbed OSはどうなのか調べようと思ったが、mbed blogの一番最初に「RTOS」と書いてある。
だから、RTOSなのだろう。


mbed OS | mbed

こちらを見ると、CMSIS-RTOS RTXをベースにしている、と書かれている。
元はCで書かれているので、C++でラッパされているのだろうか?
そうらしい

試しに、LED点滅サンプルをインポートした。

image

mbed-os」のようだ。
URLはgithubだったけど、移動したのかしら?

githubのReleasesは、こう。

image

コンパイラのリビジョンは、こう。

image

なので、今の私はmbed OS 5.1.2を使っているのだろう。

 

書いてあるソースは、こんだけ。

image

ビルドすると、こんなもの。

image

 

KeilとSTM32CubeF4を使って、RTXを使ったLED点滅サンプルを作ってみた。

Program Size: Code=7624 RO-data=552 RW-data=80 ZI-data=3344 

うーん、mbed OSは周辺機器制御の部分がリンク時でもそぎ落とせないのかな?
Keilで試したいところだが、このサイズだと無料版ではリンクできないのだ。

ARM-GCC版をexportさせようとしたけど、どうにもうまくいかない。
Code Sourcery版もダメだ。LPCXpressoはグレーアウトされてるし。


あー、今はmbed CLIというのがオフラインコンパイル手段としてあるのか。
でもなんか、説明が長いぞ。。。

また今度だな。


mbed OS 5.1風のThreadにすると、こういう書き方になりそうだ。

void task_led()
{
    while (true) {
        led1 = !led1;
        Thread::wait(500);
    }
}

int main() {
    Thread th;
   
    th.start(task_led);
    while (true) {}
}

Threadでwarningが出ていたから、気になったのだよ。
Thread.hはこうで「MBED_DEPRECATED_SINCE()」の定義を使うとwarningが出ていたようだ。
マクロでこういうことできるんだ。。。

コンストラクタで指定するのではなく、start()で指定してほしいらしい。
型のmbed::Callback<void()>がよくわからんのだが、引数無し、戻り値voidというシグネイチャという意味なのだろうか。

 

値を渡したい場合は、これでよいのかな。

void task_led(int *wt)
{
    int waittime = *wt;
    while (true) {
        led1 = !led1;
        Thread::wait(waittime);
    }
}

int main() {
    Thread th;

    int wt = 1000;
    th.start(&wt, task_led);
    while (true) {}
}

[win10]初めての再起動通知

Windows10 の Anniversary Updateでアクティブ時間が採用されてから、初めて再起動通知が来た。
これは、記念に残しておかねば。

image

うちのアクティブ時間は、こういう設定です。

image

が、終了時間を変更して、30分後にしてみた。
今が11時半なので10分後くらいにしたいのだが、分は00しか指定できなかった。

image

さあ、どうなる??
30分後にご期待を。

いかにも作業中に終了時間を迎えたかのように、Excelとテキストエディタは未保存のままにしておこう。


(つづきは12時以降)

現在、12:03。
まだ再起動しようとしていない。
12:13。
まだ大丈夫。

ここまではずっとPCを動かしていたので、昼ご飯を食べるために手を休めよう。

13:03。
まだ生きている。。。
もしかして、再起動要求後にアクティブ時間を変更しても意味が無いのだろうか?

image

よかろう、試してやる。
1分後だ!

image

 

ちょうど13:06に再起動された。
「再起動しますか?」もないし、未保存のファイルの確認も出ず、再起動された。

再起動後、ログインするとExcelは自動保存済みの状況で開いたが、テキストファイルは・・・あ、このテキストエディタ(EmEditor)は未保存状態のまま終了することができるので、そのまま復帰してくれた。

そんな感じなので、自動保存する機能がないものは、残らないんじゃなかろうか?


ちなみに、このアップデートでmbedのNUCLEOがドライブとして見えるようになった。
よかったよかった。

2016/08/23

[c/c++]私のC言語 (4)

ふだん使っているから、ネタが困ったときに何とかなるだろうと題材にしたけど、ネタがないときはないものだ。。。


for文から抜けたいことがある。

for (int lp = 0; lp < 100; lp++) {
  if (lp == 50) {
    break;
  }
}

「じゃあ50までのforにしろよ」と思われそうだが、まあ、題材としてだから気にしないでおくれ。

このように1重ならまだよいのだけど、多重になると嫌になってくる。

for (int lp1 = 0; lp1 < 100; lp1++) {
  for (int lp2 = 0; lp2 < 10; lp2++) {
    if (lp == 50) {
      ★ここで、lp1からも抜けたい
    }
  }
}

このくらいだったら、lp1を100とかにしてbreakするかな。
でも、前後に処理が入っていると、このまま流したくない場合も出てくる。
そういうのを避けるためにif文書いて。。。とやっていくのは、あまり好きではない。
Javaだと、breakにラベルが使えるからいいよなぁ。

そう考えると、breakだって書いていないラベルに向けてジャンプするようなものだし、switch-caseのbreakもそうだろう。
だったら、変にゴチャゴチャしたソースになるくらいだったらgotoで抜けた方がわかりやすいんじゃなかろうか、と思っている。

  for (int lp1 = 0; lp1 < 100; lp1++) {
    for (int lp2 = 0; lp2 < 10; lp2++) {
      if (lp == 50) {
        //★ここで、lp1からも抜けたい
        goto EXIT_FOR;
      }
    }
  }
EXIT_FOR:
  ...

goto禁止のところも多いし、下手したらswitch-case以外はbreak禁止というところもある(あった)。
goto使うのを嫌う人も多いので、まあそういうのは押しつけないのだけど、こういうのでgoto使いたい人がいるのくらいは許容してほしいなあ、と思うのだ。

 

でも、コードレビューする人からすると、いちいちそんな細かいところまでチェックしてたら時間が足りないから「もうgoto禁止!」と言ってしまいたい気持ちもわかる。
だから、staticじゃないグローバル変数とgotoは申請制度にして、こういう理由で使ってますよーっていうのが自分で言えるようであれば使ってよい、くらいがよいのではなかろうか。

うち?
うちは私がルールだから、よほどのことがない限りはOKだよ。
gotoを許可するのは、多重ループから抜けるのが面倒なときか、エラー処理のときかな。

2016/08/22

[c/c++]私のC言語 (3)

今日、軽量Rubyのフォーラムに行ってきた。
誰でも参加可能だったのだ。

 

軽量Ruby(mruby)は、組み込み機器向けというのもあるが、組み込んで使うという意味合いもあるそうだ。
なんというか、Luaみたいな使い方だ。

私なんかは、組み込み機器だったらC/C++でやればいいじゃないの、と思うのだけど、今日のフォーラムで聞いていると「C言語はできないけどRubyなら社員ができる」みたいな状況もあるようだった。
なるほど、そういうことですか。。。

 

C言語で書く機会というのは、どんどん減っていると思うから、Rubyがよいかどうかは別として、当然の流れなのかもしれない。
組み込み機器を扱う以上、どこかはハードウェアに特化したところが出てくるが、それも含めてメーカーから提供されでもしたら、私はやることが無くなってしまいそうだ。

昔は「そういう時代が来たら、書かなくてよくなるねぇ」なんて思っていたけど、いまや飯の種だし、他に熟練したものがないから、すがって生きていくしかない。
会社員だったら、知識を生かしてアドバイスに回る、などということができたのかもしれないけど、個人だとそういうのができない。。

 

まだ、すがっていられる余力があるうちに、生き延びそうな道を探しておきたいところだ。
C言語はなくならないと思うけど、私のところにC言語の仕事が来るかどうかは別の話だからね。

そういうわけでAndroidをやったりしたが、これから流行るかもしれなくてやっている人が少ない、というやつの方が、需要が出てきたら参入しやすそうではないか。
まあ、「これから」が来ないかもしれないけど。。。

さて、mrubyはどうなるだろうか?
年末にはmruby/cをリリースしたいということだったが、そっちだと今の組み込み機器でも使えるものがあるだろう。
mrubyだと、小さい組み込み機器ではRAMが足りないので今は無理だけど、時代は進むからねぇ。

どこに勝負をかけるか悩みどころだが、C/C++は捨てないぞ!

2016/08/21

[FreeRTOS]音を鳴らす

せっかくなので、音も鳴らしてみた(github)。

うちにあったのは、京セラの圧電スピーカだった。
圧電なんとかって、全部ブザーかと思っていたのだが、電池をつないでなるのがブザーで、ちゃんと制御せんといかんのがスピーカーだとか。

これを、片方をNUCLEOのPWM/D9に、片方をGNDに突っ込んだ。
電気的によいのかはわからないが、音は出る。

 

まあ、細かいことはさておき、PWMで周波数を変えるとちゃんと音程が変わったので、満足だ。
音だけのアップロードをどうやってよいかわからないので、ファイルを置いた。
動画さえ入れれば、YouTubeでもよいらしいが。。。
https://drive.google.com/open?id=0B2_3hJpJ5Ui2cHhuM0FLbV94OG8

イメージはこの音なのだが、まあだいたいこんなもんだろう。
人造人間キカイダー ギルの笛の音 - YouTube

 

今回は、SW入力でON/OFFするタスクと、音程を制御するタスクの構成にした。
PWMなので、OFFのときはPWMを止めればよいのだが、そうすると音程タスクの方で音楽が進んでしまうので、Suspended状態にすることにした。
スケジューラ開始前にもSuspendしているが、ちゃんと止まっているようだ。
たぶん期待通りだと思うが、時間計測をしていないので、どの辺で停止したのかよくわかっていない。

OSを使っていると、音程を制御するのは楽だった。
音程の設定をして、流したいだけの間vTaskDelay()するだけだからだ。
改めて、OSは楽をするためだけに導入するものだ、と認識した。

 

しかし、こういう単調な音は、テストしている間がきつかった。
何かが破壊されてしまいそうだったよ。。。

2016/08/20

[nrf52]HRSサンプルのFreeRTOS版は何をしているのか

私のイメージでは、になるが、OSがあるんだったら機能ごとなどにタスク分けして使うもんじゃなかろうか、と思っている。
そうでなければ、OSのフレームワークを使うことで便利になる何かがあるはず。

nRF5 SDK v11.0.0のHRSサンプルは後者のようだ。


まず、普通のHRSサンプルではmain()から呼んでいる処理を、タスク側で呼ぶようにしている。
main()でやるのは、セマフォやタスクの生成とスケジューラの開始だ。

それ以外の構成は、普通のHRSサンプルとそれほど変わらない。
DFUなんかは外してあるが、わざとなのか、単に入れなかっただけか。
DFUが入ることでRTOSの邪魔になる、あるいはRTOSがDFUの邪魔になるというのは、ないと思う。
だから、DFUが入っていないサンプルにFreeRTOSを突っ込んだのではなかろうか。

 

タスクは1つだけで、通常やっているのはxSemaphoreTake()とintern_softdevice_events_execute()。
Takeで待ち合わせ状態になり、誰かがGiveすると解除になるようだ。
なんだっけ、TakeがPで、GiveがVか。

intern_softdevice_events_execute()は初めて見たが、softdevice_handler.cが持っている。
中でm_ble_evt_handler()などが見えるので、これが自分のところのon_ble_evt()を呼び出す契機になるのか。

ただ、GAPというかAdvertisingはなさそうだ。
経路が違うのかな?
いや、ble_advertising.cにon_ble_evt()があるので、m_ble_evt_handler()で呼び分けられているのか。

タスクになったからといって、on_ble_evt()などに違いはなさそうに見える。


大きく違うのは、タイマハンドラか。
xTimerCreate()を使っているが、これはSoftware Timersという分類になっている。
今まで、タスクからDelayやDelayUntilを呼んで定期処理にしていたが、こっちはタイマサービスのコンテキストで呼び出すから、そういうAPIは呼んだらいかん。

サンプルでも、やっているのはnRF5 SDKのAPIを使っているだけだ。
うーん、じゃああまりサンプルとしてはRTOSの魅力を出せていないけれど、サンプルにそれを求めるのは酷か。

 

ちょっと気にしているのは、キューに突っ込んだりすると割込禁止にしていたので、BLEとして影響があるんじゃなかろうか、というところだ。
SoftDeviceとOSって、相性が悪いと思うのだよねぇ。。。
無線チップが別になっていれば、うちはうち、よそはよそ、でよいのかもしれんが。

[勉]FreeRTOS (9) - 完

ぐだぐだになりそうなので、ここでFreeRTOS編を終わらせることにした。

おおざっぱなブロック図は、こちら。
Vcc1が3.3Vではダメなのだけど、NUCLEOは5Vも出ているのでそれを使うことにした。

image

 

NUCLEOの接続は、こう。
「VOL」は、ポテンショメーターでADCし、「EN」はPWM出力している。

image

 

タスク構成は、こうなっているはず。

image

 

ソースはこちら
Src/main.cくらいしか変更しておらず、あとはSTM32CubeF4の出力を使っている。


だいたい期待通りに動作していると思う。

めんどくさいことをしていないというのもあるが、FreeRTOSはこの程度であればあまり苦も無く使えた。
そう思って本番で使うと苦労するのかもしれんけど、使ってみてもよいかな、と思わせてくれる。

ESP8266のRTOS版もFreeRTOSを使っているのだけど、いまはV7.5.2ベースみたいだ。
NonOS版だと、Linuxのread()みたいに、受信サイズがたまるまで待たせる、という処理が書けなかったので、やってみたい気もする。
まあ、また今度だ。

[勉]FreeRTOS (8)

ADCで値が取れるようになったので、ちょっと寄り道して、ログを出力するルートを変更しておきたい。

今はVolTaskからUARTドライバを呼び出して直接出力させているのだが、これをUartTask経由で出せるようにしたいのだ。
そうしないと、各タスクがログを好き勝手に出してしまって、何が何だかわからなくなりそうだからだ。

目標としては、こういう感じだ。

image


このイメージになりそうなので、間にキューを置いている。
キュー制御用API関数の使い方

タスク生成と同じようにしてキューを生成し、ハンドル値をグローバル変数にとっておいて、各タスクはそのハンドルを使って書いたり読んだりするようだ。
あれ、ハンドルはみんなで使うようだけど、排他はいらないのかい?

こちらを読むと、MUTEXを使わずにキューで処理するやり方が書いてあるので、キューであれば排他はいらないようだ。
排他制御(MUTEX)の使い方

なんでだろう?
xQueueSend()の中身であるxQueueGenericSend()を見ると、かなり最初の方でtaskENTER_CRITICAL()を呼んでいる。
つまり、誰か最初に呼んだ人がディスパッチ禁止にするわけだ。
キューを使うときはタスク間通信が主で、だったら排他がいるから自動でやっておくか、というところか。
ディスパッチ禁止は移植対象で、ARMの場合はBASEPRIをいじって割込みを禁止させるみたい。

おおざっぱだけど、割り込み処理用にAPIが別にあるものは、内部でディスパッチ禁止処理を行うようになっていると思っていてよいのだろう。

 

受ける方のxQueueRecive()はタイムアウトを指定できて、無限にしておくとキューにたまるまでは待ってくれるようだ。

変更したプロジェクトは、こちら
案外、あっさりと動いてくれた。

今頃気付いたが、FreeRTOSはドライバレベルについてはOSで面倒を見ないから、別マイコンに移植するつもりがあるなら自分でやることになるんだな。
まあ、最近は他のマイコンに載せるといっても同系列のマイコンだったりするので、そこに時間を掛けるよりもさっさと作れてしまうほうがありがたいかも。

2016/08/19

[勉]FreeRTOS (7)

さて、FreeRTOSで定周期処理をやろう。

 

タスク制御用API関数とタスクの作り方 - 電子工作室

こちらによると、vTaskDelay()で処理中に待たせる方法と、vTaskDelayUntil()でタスク自体を一定周期で起動する方法があるらしい。

vTaskDelay()は、その場でtick分待つだけなので、間に割込みされても、その分は気付かず、また戻ってきてから待つことになる。
それに対してvTaskDelayUntil()は、呼び出す周期を設定するようになっているので、割り込みされようとカウントしてくれるらしい。

「今から1秒寝ます!」と、「1秒ごとに目覚ましが鳴るので、それまで寝ます!」の違いか。
だいたいは後者の方が同じタイミングになって良いけど、その前の処理は次のタイミングの前に終わっていてほしい、というのはあるな。


1秒おきにA0ポートをADCして、2ビット落とした値をUART出力させるようにした(github)。

いやあ、ここまでに時間がかなりかかった。
ADCは連続モードで最初に開始させて、あとは取得するだけにしようとしたのだが、

  • 連続モードにしても1回しか変換してくれない
  • 値が変

と2つ問題があった。
どちらもFreeRTOSではなく、STM32の使い方だ。

前者は、おそらくEnd Of Conversion Selectionの設定だと思う。
リファレンスもではCONTビットを立てればよいように書かれていたのだが、デフォルトの「single channel conversion」のままだと、そちらが優先されて終わってしまうようなのだ。
ドキュメントで見落としたかな?

image

後者は・・・単純な設定ミスだ。
A0の設定をしていたつもりで、ずっとA1の方を設定していたので、オープンにしたままのA1から読み取っても毎回不定になっていたというだけだ。
いやぁ、ミステリー小説にありそうな、大元から違っている、というトリックですな。

 

1秒ちょうどか確認したいけど、TeraTermのログでは1秒くらいだけど、このくらいだとよくわからんですな。
もうちょっと処理がゴチャゴチャしていて、遅延しそうってくらいにならんとわからんだろうから、今回は深追いすまい。

[勉]FreeRTOS (6)

Arduinoでモーターを動かせたので、その回路をそのままNUCLEO-F411REで使ってみよう。
NUCLEOはArduinoと同じピン配置のコネクタを持っているので、そのまま移し替えられるはずだ。

D9はPC7、A0はPA0だ。
PA0はAnalog_GPIOだとして、PC7はどれにすればよいのだ?

image

STM32では、PWMはタイマの項目になるらしい。
http://visualgdb.com/tutorials/arm/stm32/pwm/

Duty比は、PeriodとPulseで決まるらしい。

image

この設定だと、こうなった。

image

93.028 ÷ (93.028 + 139.97) = 40%くらい

200 ÷ 500 = 40%

おお、比率はあってる。
プリスケーラの40000は、まねしただけなのだけど、どういう関係なのだ?

STM32F4 PWM tutorial with TIMERs - STM32F4 Discovery
タイマのtickが、デフォルト周波数 / (prescaler+1)になる。
TIM3は、APB1につながっているので、デフォルト周波数はAPB1のものになろう。

image

などと探すまでも無く、Clock ConfigurationにTimer clocksが載っていた。
今は84MHzになっている。

image

tick = 84MHz / (40001) = 2100Hzくらい

PWM周波数=tick / (Period+1)なので、

pwm = 2100くらい / 501 = 4.19Hzくらい

4.19Hzは239msecくらいだ。
93.028 + 139.97は233msecくらいで、5msecくらい違うのだが、誤差の範囲でよいのか?
tick換算すると10tickくらいになってしまうのだが。

値が適当すぎたので、もうちょっと計算しやすい値にしよう。

image

tick = APB1 / (Prescaler+1) = 84MHz / 8400 = 10kHz
PWM = tick / (Counter Period+1) = 10kHz / 500 = 20Hz
周期 = 1 / 20Hz = 50msec
Duty比 = Pulse / (Counter Period+1) = 200 / 500 = 40%

で、1周期50msec、Hなのは50msecの40%で20msecになるはず!

image

19.54ms + 29.311ms = 48.9msecくらいなので、ちょっと短いか。。。
元が内蔵16MHzだと、そこまで精度が出ないということか?

image

最大4%くらいか。
短い方に振れると、50msecが48msecくらいになるな。
うん、こんなもんとしておこう。

ここまでのソースは、こちら


機器の構成は、こうなる。

image

SWはチャタリングするし、ポテンショメーターも値がバタバタするので、ヒステリシスを持たせたい。

 

今はタスクの先頭でPWM開始を行っているだけだが、SW2つとADCもここに集めてしまって、input/output用タスクにした方がよいだろうか。

あるいは、ここはタスク間通信で制御要求されたものをoutputするだけにして、inputは別タスクにした方がよいだろうか。

inputのごとにそれぞれタスクを作るというやり方もある。

image

 

タスクが多くなるとメモリも使うし、ディスパッチが増えて効率が悪くなる。
かといって1つのタスクに機能を詰め込むと、OS使ってるのにわかりづらい…となってしまう。
難しいねぇ。

このくらいだったらどれでもよさそうなので、SWとVOLをタスク分けしてみようか。
SWは同じタイミングで全部読み取りたいけど、VOLとはタイミングを変えたいのだ。
1つにまとめてもできるけど、まあ、分けた方がきれいな気がする。

私の設計って、いつもながら適当よね。。。

 

というわけで、次回は定周期で値を読み取るタスクにしていこう。

[excel]Anti-BeaconでBing IPsをImmunizeすると、オンライン画像が検索できない

お仕事で使っているPCなので、あんまりトラッキングされない方がいいんだろうなあ、と思い、こちらで紹介してあったアプリをインストールした。

【レビュー】Windows 10のトラッキング機能をワンクリックでまとめて停止「Spybot Anti-Beacon」 - 窓の杜

何も考えず、全部OFFにしていたのだが、Excel2013で「オンライン画像の挿入」ができなくなっていた。

image

どうも、この項目をImmunizeするとダメみたいだ。

image

immusizeとなってるけど、spell checkで怒られているから、immunizeなのかな?

 

大丈夫な情報なのかそうじゃないのか、素人はわからないから、とりあえずOFFにしてしまうのだよ。。
そして、今回みたいにエラーになって気付くけど、どれが悪いんだかわからないのだ。

こういう仕事をしているとコンピュータ関係になんでも詳しいだろうと思われるけど、知ってることしか知らないのだ。

Arduinoでモーターを動かそう

いきなりだが、モーターを動かしたくなった。
唐突で、済まん。

今まで、マイコン制御でモーターを動かす、というのをやったことがないのだ。
夏休み(?)の最後に、自由研究としてやっておこう。


昨日、知人にこれを紹介してもらった。
モーター・リレー・ブザー制御入門 [ SU-1204 ]|製品情報 | エレキット

PDFが日本語で親切なのだが、シールドを購入するとなると今週にはできないな。。。
とあきらめそうだったのだが、そういえばArduinoをキットで購入したときに、モーターを動かす課題があったのを思いだした。

英語の本なので読むのに時間はかかるのだが、絵がちゃんとしてるし、こういう図になっているからこの英語はこうだろう、と読み解くことができる。
本も厚みがあって、なんかよい装丁だ。

モーターの課題は"Zoetrope"だ。
日本語だと「回転のぞき絵」らしいが、専用の単語があるとは。

image

モーターを直接GPIOに挿しても動かせない、というのはなんとなくわかっている。
電流が足りなくて、動かした瞬間にマイコンを動かせなくなってリセットがかかるんだとか。
エレキットPDFには「壊れる」と書いてあるので、やらない方がよさそうだ。

直接挿せないので、間に入ってもらう。
それが、ここではL293D、というチップだ。
チップというか、ICですな。
キット本では"H-Bridge"と書かれている。
エレキットPDFでは、モーターを動かす回路(モータードライバー回路)がH型になるので、Hブリッジ回路と呼ばれる、と説明されている。
H形鋼みたいなものか。

 

Hブリッジの説明はエレキットPDFのp.26に載っている。
トランジスタが4つあり、そのON/OFF組み合わせで電流の流れる方向が決まって、回転する方向が制御できるという代物だ。

ブレーキもできるそうだ。
なんとなく、モーターは回転するしかできないから、今の方向と逆に動かすのがブレーキかと思ったのだけど、そうではないようだ。
ちゃんと、入力をOFFにしただけよりも早く止まるらしいから、ブレーキなんだな。

フリップフロップじゃないけど、禁止状態というのもある。
この組み合わせは設定したらいかん、というやつだ。
壊れるかもしれないので、やらんごとせないかん。


L293DはST(pdf)やTIでデータシートが出てきた。
キットに付属しているのは、よく見えないけどTIじゃなかろうか。

1A-1Yと2A-2Y、3A-3Yと4A-4Yが組になっていて、AがInput、YがOutputだ。

image

image

1Aが2ピン、2Aが7ピンなので、これらがArduinoにつながっている。
1Yが3ピン、2Yが6ピンなので、これらがモーターにつながっている。
VCC1はArduinoの5V、VCC2は電池の9Vにつながっている。

1,2EN(1ピン)はArduinoにつながっている。
これがHだと、出力はH/Lのどちらかになる。
だからずっとHでよいかなー、と思っていたのだけど、そうではないんだ。

TIのデータシートの、この図が近いのかな?

image

ENをLにすると、とりあえずブレーキがかかる、という考え方でよかろうか。

なんか、Hi-Zってイメージしにくいのよねぇ。。。
上のFUNCTION TABLEだって、Z=high impedanceといいつつ、括弧してoffって書いてあるから、じゃあひっくるめてLでいいやん!と思ってしまうのだ。

電気的に絶縁状態だから、プルアップしていればHに、プルダウンしていればLになるというのはわかるのだけど、キット本ではどっちもしていない。
データシートも(off)と書いているから、つながない場合はプルダウンしていますよ、という読み方をすればよいのか。
EN1,2は1A-1Yと2A-2Yの両方にかかるから、EN1,2をLにすると、1Yと2YがL扱いになって、ブレーキがかかる、と。

こういうのをスラスラっと読めるようになるといいなあ、といつも思うのだが、ここまで考えないとまだわからないのだ。

 

さっき、Hブリッジ回路は禁止状態があると書いたが、こういうICはその状態を内部で起こせないようになっているようだ。
だから、そっちは心配しなくてよさそう。


というわけで、EN1,2がHだったら、1A,2AにH/Lが違うように入力させると回転するはずだ。

しかしキット本の回路では、プッシュスイッチが2つと、ポテンショメーターが1つつながっている。
スイッチはモーターの回転方向とON/OFF、ポテンショメーターは速度だそうだ。
速度を変えるということは、えーっと、PWMか。

アプリの方は2ページにわたって説明されている。
そんなに難しいわけでは無い。

  • setup()でGPIOの方向設定と、EN1,2をLにしておく。
  • loop()でスイッチ2つの状態とポテンショメータのAD値を取得
    • ON/OFFスイッチが押されたら、動作フラグをトグル
    • 方向スイッチが押されたら、1A,2Aをそれぞれ逆にする
    • 動作フラグがONだったらポテンショメータのAD値をEN1,2に出力、OFFだったら0出力

あれ、PWMじゃなかったのか?
EN1,2はArduinoの9ピンにつながっている。
ソースではpinMode()でOUTPUT指定だけになっているけど、これでPWMになるのか?
でも、setup()ではdigitalWrite()してて、loop()ではanalogWrite()してる。。。

ああ、analogWrite()はPWMという意味なのか。
ということは、毎回analogWrite()が呼ばれるとPWMの設定をし直しているか、あるいは内部で状態を持っていて切り替わったときだけPWMの設定をしているのだろう。
なんとなく後者だと思うから、setup()でもanalogWrite()した方が時間のばらつきが無くてよいんじゃなかろうか。


そんなこんなで、まずはモーターを動かすことができた。
アプリを適当に実装したせいで動かなかったり、スイッチがブレッドボードにうまく挿せずにチャタリングしまくったりしたが、そういうのは恥ずかしいので省略だ。

今回の例ではEN1,2をPWMにすることで速度調整したけど、A1,A2のH側をPWMにすることもできるはずだ。
まあ、そうするとPWMが2ポートいるから、EN1,2の方が楽か。

2016/08/18

[esp8266]includeがないのよねぇ

espmissingincludes.h How long this will continue?!! - ESP8266 Developer Zone

あっはっは。
確かに、私もそう思う。

 

いつの頃からか、SDKのAPIがincludeしてもダメで、自分でプロトタイプ宣言を書かないとmissingになってリンクまでたどり着けなくなったのだ。
コンパイルだけの問題で、ライブラリには入っているので、リンクはできる。

直接参照しているAPIならまだよいけど、実はマクロになっていて変換しているだけだったりすると、引数の型がわからなかったりして、大変だったのだ。

メジャーバージョンが変わったけどまだそういう作業がいるから、いつまでこの状況は続くんだー!というお怒りが伝わってきますな。

[勉]FreeRTOS (5)

そろそろ本業が開始できるようになってFreeRTOSシリーズを打ち切る、という状況になってほしいのだが。。。
もうちょっとやります。


http://www.freertos.org/RTOS-idle-task.html

自分が作ったタスクが1つでも、その1つがSuspended状態になったら誰かが表に出てくることになる。
その誰かがIdleタスクだろう。

vTaskStartScheduler()を呼ぶと、その中で自動的に生成している。
一番優先度が低いので、普通は動かずにReady状態になっている。

さっきは「誰かが表に出てくる」と書いたが、どうやらタスクが削除されてメモリを解放するという役割を負っているようだ。
前回のvTaskDelete()が、それらしい。

2つくらいやり方があるようなので、興味があれば見てみるとよいだろう。
tasks.cも一緒に追った方がわかりやすそうだ。

 

タスクについては、これで一周したようだ。
タスクと似たようなものとしてコルーチン(Co-Routine)もあるようだけど、そっちはいいや。
タスクとコルーチンの違いの説明に「very small devices」とあるけど、ARMは小さくないと思うのだ。
いるときが出てきたら、読もう。


タスクの次は、何を読もうか?
使いたいとしたら、こういうところか。

  • タイマ処理
  • タスク間通信
  • メモリのこと
  • 排他
  • 割込み

盛りだくさんだけど、タスクが1つだったらOS使わなくてよいだろうし、タスクが複数だったらタスク間の通信がいるし、メモリも動的にとったり共有したりするし、そしたら排他もいるし、と、全部いるはずだ。

[勉]FreeRTOS (4)

前のサンプルで気になったのだが、osDelay()はタスクが動いていると見なされるのだろうか?
見なすのであれば、それよりも優先度の低いタスクにはディスパッチしないはずだ。

defaultTaskをosPriorityHigh、uartTaskをosPriorityNormalにしたところ、どちらも動いたが、StartDefaultTask()でosDelay()をコメントアウトするとUARTログが出なくなった。

ということは、osDelay()は優先度の高いタスクが「ちょっと今なら別タスクが動いてもいいよ」というときにも使えるということだろう。
あるいは、優先度が高くてもosDelay()が入るとディスパッチされる可能性がある、ということになる。


タスクの状態は4つある。

  • Running
    • ちょうど今、動いている
  • Ready
    • 動こうと思えば動けるのだが、他のタスクが動いているので待っている
  • Blocked
    • 何かの要因によって待たされている(vTaskDelay()など)
    • この状態の時、プロセッサの資源は消費しない
  • Suspended
    • Blockedに似ている
    • 直接Runningになることはできないが、vTaskResume()でReadyになることはできる


(説明図)

vTaskSuspend()を呼ぶとどの状態からでもSuspendedになりそうだが、Running状態にならないと実行自体できないんじゃなかろうか?
あるいは、タスク名を指定して実行とかができるとか?

まあ、これは疑問のまま残しておこう。


http://www.freertos.org/implementing-a-FreeRTOS-task.html

タスクの実装なのだが、vTaskDelete()などがSTM32CubeF4で作った方には出てこなかった。

コメントの箇所を読んでみると、returnさせようとしちゃいかん、さもなくばexitせよ、などと書かれている。
exitといっても、exit()ではなく、vTaskDelete()で後片付けをしてから抜けろよ、ということらしい。

 

arm - STM32 freertos thread is not working - Stack Overflow
ここのコメントに、osThreadDef()なんかはFreeRTOSの提供物じゃないよ、と書かれていた。
grepすると、確かに無い。
STM32CubeF4だと、Source/CMSIS_RTOS/cmsis_os.hの中にあった。

便利でよかったのだけど、標準じゃ無いなら、FreeRTOSを使ってみるという観点からすると困るな。
ひとまず、今のサンプルを置き換えた

[win10]コンテキストメニューが左側になってしまった

いつの間にか、コンテキストメニューがマウスの左側に出るようになっていた。
その中のメニュー展開も、左側に出てしまう。
私は右利きなので、右側になっていてほしいのだが・・・。

 

右クリックのメニューが左側に表示されてしまうのを直す方法 | mikanmike ~Sub Blog~
こちらの、レジストリを変更する方法をやったあと、再ログインしたら直った。

いつ、こうなったのかが記憶にない。
Table PC設定に関係しているようなので、一時的にペンタブをつないだときに、勝手に変更されたのかもしれない。
でも、けっこう前だよなぁ。。。気付かなかっただけか。。。

 

Windows10のTabletPC.cplでは、それっぽい設定項目がなかった。

imageimage

[勉]FreeRTOS (3)

前回の、ほぼ素のままのソースをビルドした結果を残しておこう。

text    data     bss     dec     hex filename
11336      16   17328   28680    7008 build/FreeRTOS1.elf

BSS、こんなに??
17KB近く使ってるじゃないか。。。

NUCLEOに載っているF411RETは、SRAMが128KBもあるので、まだ余裕があるといえばあるのだが、FreeRTOSとはいえ使いすぎじゃ無いか?

 

いや、待て。
新規プロジェクト生成直後で、FreeRTOS無しの場合を見ておこう。

text    data     bss     dec     hex filename
4812      12    1572    6396    18fc build/original.elf

ほぼ空なのに1.5KBも使っているのが気になるが、けっこうなサイズをFreeRTOSが確保することがわかった。
1.5KBも、ヒープサイズで0x200、スタックサイズとして0x400確保ししているためのようだ(STM32F411RETx_FLASH.ldの_Min_Heap_Sizeと_Min_Stack_Sizeだろう)。

 

FreeRTOSを使う場合も、ヒープとスタックは同じだけ確保している。
ただ、別途FreeRTOS用のヒープ領域を0x3c00確保しているので、もしFreeRTOS以外でヒープを使わないのであれば、Min_Heap_Sizeは0にしてよいのかもしれない(FreeRTOSが立ち上がるところで使うかもしれないので、断言はできんが。。)。

スタックもタスクごとに持たないとダメなんじゃなかろうか?
OSが無いなら、今実行しているメインスレッドのスタックと、割込みで実行するときのスタックがあれば済むだろうけど、メインスレッドのところが複数タスクになるので、それぞれのタスクでスタックを持っておかないとダメだろう、という考えだ。

FreeRTOSConfig.hにconfigMINIMAL_STACK_SIZEという定義があったから、これがスタックサイズなのだろう。
128だった。
その下にconfigTOTAL_HEAP_SIZEが15360で定義してあり、イコール0x3C00だ。

そういう感じで、configファイルに定義したものが反映されていくようだ。


FreeRTOS - Quick start guide

ソースを取ってきて、Demoでも動かしてみよう、くらいしか書かれてない。。。
それ以外はリンク先をいろいろ見るようだが、PDFを売っているようなので本来はそっちを読んでほしいのだろう。

 

しかたないので、main.cを見ていく。
タスク生成しているのは、これだろう。

osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

defaultTaskHandleはosThreadId型なのでわかるし、StartDefaultTask()も関数があるのでわかる。
では、このヘッダにも定義がないdefaultTaskというのは何だ?

あー、osThreadDefはマクロだ。

const osThreadDef_t os_thread_def_##name = \
{ #name, (thread), (priority), (instances), (stacksz)  }

ここだと、

const osThreadDef_t os_thread_def_defaultTask =
{ "defaultTask", StartDefaultTask, osPriorityNormal, 0, 128 };

defaultTaskHandle = osThreadCreate(&os_thread_def_defaultTask, NULL);

となる。
マクロで#を使うと、ダブルクォーテーションで展開されるんだな。

そしてosKernelStart()でカーネルが起動される、と。
main()はその後どうするかというと、無限ループになっている。
タイマ割込でラウンドロビンするのであれば、ここはWFIで寝かしてしまってもよいのだろうか?

__WFI()を入れてみたが、見て目には変わらないようだ。
ロジアナで点滅間隔を見てみるくらいしないとわからないかもね。

image

10msec間隔にしたが、まあこんなものか。
じゃあ、WFIした方がよいのかな?

あ、nRF5 SDKのサンプルを見ると、whileループしているのは同じだが、ループに入るとエラーハンドラが呼ばれるようになっている。
つまり、OSを終了しないと呼ばれないから、何があってもあまり関係ないということか。。。

開始するとIDLEタスクが作られているようだから、何もしていないときに無限ループで待つのではなく、IDLEタスクが実行されるだけか。

INCLUDE_xTaskGetIdleTaskHandleが1だと、IDLEタスクのハンドラを取得できるらしいが、IDLEタスクの関数を見ても何をやってるのかさっぱりわからん。。。


では、まねしてみよう。

まずはタスクを追加する。
今回は、UART2に送信を行うタスクにする(github)。

osThreadDef(uartTask, StartUartTask, osPriorityNormal, 0, 128);
osThreadCreate(osThread(uartTask), NULL);

名前が違うだけで、やっていることは同じですな。

起動されるタスクは、こう(github)。

void StartUartTask(void const * argument)
{
  /* Infinite loop */
  for(;;)
  {
    HAL_UART_Transmit(&huart2, "Hello!\r\n", 8, 200);
    osDelay(500);
  }
}

"Hello!"の出力を、500msec間隔で行うだけだ。
これで動いた。

uITRONだと、configurationファイルを書いてコンパイルするけど、FreeRTOSはヘッダファイルに書いてソースで作るだけのようだ。
これを静的にできるようになったのがV9なのかな?

2016/08/17

Windows10 Anniversary Updateをしたら、FAT12が見えない?

[2016/08/24]
今日行われたWindows Updateを行ったら、直ったようだ。

[2016/08/17]

さっき、NUCLEOをWindows10に接続したら、ドライブとしては見えるけれども容量を認識してないようだった。

そういえば、と思い、16MBのSDカードがあったので、USBカードリーダーに挿してみた。
やはり、同じような症状だ。

なんとなくだけど、FAT12が見えないんじゃなかろうか?
2GBのSDカードにしたら見えたし。
FAT12は20MBくらいまでらしいから、fdiskでパーティションを切って試してみればわかるのかもしれんが、まあよかろう。


NUCLEOの場合、ST-Linkというデバッガも一緒に付いているので、そっち経由でアクセスすることができる。
多少面倒だが、致命的ではないだろう。
持ってないけど、NordicのDKシリーズなんかも、J-Linkが見えるから、同じようなものか。

 

手っ取り早いのは、VirtualBoxなどにLinuxをインストールして、そっち経由でアクセスする方法だろうか。
たぶんファイルシステムのところだろうから、Windows10を経由しないなら大丈夫な気がする。

[勉]FreeRTOS (2)

前回は概要をさらっただけなので、今回はもう少し中身を見ていこう。

 

私が持っている、STM32F411REが搭載されてNUCLEO-F411REを使おうかと思ったのだが・・・。

STM32Cube BSP with FreeRTOS for STM32 ARM Cortex-M
STM32CubeMX

なんと、FreeRTOS対応のSTM32Cubeがあるんだと!
「テスト開始!」っていわれて解答用紙を見たら、既に答が書いてあった気分だ。

まあ、移植する作業からやるつもりもなかったし、よしとしよう。


ステップ1は、STのホームページからSTM32Cubeをダウンロードする。
今の最新は、4.16.0だ。

あれ、STM32CubeMXはEclipseのプラグインのようだ。
以前はスタンドアローンだった気がするのだが、記憶違いか。。。

ああ、STM32Cubeは、F1とかF4でまたダウンロード先が分かれているんだ。
私はSTM32CubeF4ということになる。
この辺、ちょっと紛らわしいな。。。

STM32CubeF4を解凍すると、こっちはプロジェクトやらドキュメントやらの一式だった。
STM32CubeMXはインストーラが入っていた。Windows, Linux, Macの全部が入っているようだ。

まずは、STM32CubeMXをインストールする。


ステップ2では、STM32CubeMXを起動する。
"Help > New Libraries Manager"を選択すると、ダイアログが表示させる。
Firmware Packageの一覧が表示されるので、私は「STM32CubeF4 Releases」の一番上(1.13.0)をチェックして"Install Now"。

なんかエラーが出た。

image

よくわからないので、左下の"From Local..."で、先ほどダウンロードしたSTM32CubeF4のzipファイルを指定する。

そうすると、もごもごやってインストールされる。


ステップ3は、プロジェクトの作成。

CubeMXの画面に戻って、左から"New Project"をクリック。
そうするとダイアログが表示される。
手順ではMCUから順番に選択していくのだが、今回はNUCLEOなのでBoard Selectorタブで選ぶ。

image

UARTが出てこないけど、そういうのは設定済みでよいのか。
まあ、CubeMXで設定できるだろう。


ステップ4は、ピンの設定。
ステップ5は、周辺の設定。
ステップは8まであるのだが、あとはCubeMXの使い方になっていくので、ここでは省略する。

Pinoutタブの項目には最初からFreeRTOSが入っているので、これをチェックすればうまいことやってくれるのだろう。

image

 

プロジェクトの設定をしてからソース生成してもらうのだが、その辺りは自分の環境に合わせよう。
私はGCCでやりたいので、ToolchainをSW4STM32にして、Makefileに変換するスクリプトを作ってくれている方がいるので、それを使うことにした。

変換して出てきたMakefileは、Windowsのコマンドプロンプトではうまくいかなかったが、cygwinでは通った。
Windowsの時に何かコマンドが見つからなかったようなのだが、まあいいや。


これで、ビルドできる環境だけは整った。
ただ、実際に何か動かさないと、ビルドできても動くかどうかわからない。。。

自動生成されたソースはいろいろあるが、ユーザ用はここだろう。

image

その4つのソースファイルのうち、下2つは初期関係なので省略。
main.cはいろいろ書けるようになっているが、タスクを起動する様子がうかがえるので、StartDefaultTask()にLEDを点滅する処理を書けば、そこまで動いているか確認できそうな雰囲気がある。

/* StartDefaultTask function */
void StartDefaultTask(void const * argument)
{

  /* USER CODE BEGIN 5 */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END 5 */
}

使っているBlogエディタが、プラグインに対応できていないので、ソースコードはそのままだ。
見にくくて済まない。。。

まあ、このソースを見た感じでは、osDelay(1)が1msecか1secかわからないけど待つだけだろう。
コメントでBEGIN~ENDがあるのは、その間にユーザコードを埋め込むようにしておかないと、CubeMXで設定を変更して自動生成し直したときに消えてしまうのだ。

void StartDefaultTask(void const * argument)
{

  /* USER CODE BEGIN 5 */
  /* Infinite loop */
  for(;;)
  {
    HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
    osDelay(1);
  }
  /* USER CODE END 5 */
}

さあ、どうなる?
・・・
・・・・・
NUCLEOをWindows10がMass Storageとして認識しなくなってる。。。
いや、ドライブとしては見えているけど、ファイルシステムが見えていないのかな?
NUCLOEは、たしかFAT12だったと思う。

どうも、Anniversary Updateを行ってから接続できなくなったという情報が多い。
うーん、ST-Link Utilityからだったら焼けるだろうか?

焼けた。
けど、LEDは点灯しっぱなし。


eclipse + GDB OpenOCD Debuggingでやってみる。
たぶんOpenOCDは、ねむいさんスペシャルだったと思う。

一発目は、Config optionsがどーたらこーたらというエラーになった。
たしかに何も設定していない。
こちらを見ながら、-sと-fを指定。

image

意外なことに、これで動いた。
main()の頭で止まる。
ステップして動く。
おお、動いているじゃないか!

では、StartDefaultTask()にブレークを張ってrun。。。来てるじゃないか!
ステップ実行してLEDは、点灯。
osDelay(1)。
またステップ実行してLEDは、消灯。
動いてるじゃないか!

ということは、osDelay(1)は1msecで、速すぎてわからなかったというだけか。
では、1000くらいにして焼き直すと。。。おお、点滅している!
点滅しているぞ!

こういう「開通おめでたう」みたいなときが、一番楽しいですな。


今回は、STM32F411が搭載されたNUCLEOと、STM32CubeMXを使って、FreeRTOSのタスクが1つ動くテンプレートをそのまま使ってLED点滅をさせるところまで動かせた。

大したことをさせていないからだとは思うが、思ったよりもあっさり動いた。
FreeRTOSが動いたことよりも、CubeMXのソースを使ってeclipse+OpenOCDでデバッグまでできることが確認できたことの方が私としてはよかった。

あまり深入りするつもりはないのだが、さすがにテンプレートそのままでは「動かせた」というのはおこがましいので、せめて自分でタスクをもう1つつくって両方動いてくれることを確認したいところだ。

[勉]FreeRTOS (1)

組み込み向けのOSというと、RTOSが思いつく。
そうではないOSは、Linuxだったり、自作だったりすると思う。

RTOSの有名どころは、こういうところか。

ThreadXなんて知らなかったのだけど、最近ニュースに出ていたFuchsiaの記事で出ていたのでね。
ARMに絞れば、RTXもある。

eCosというのもあったなぁ、とWikipediaを見たら、あれはずいぶん前に終わってしまったのですな。
でも、本家では昨年の年末にニュースが出ているので、メンテナンスは続けられているようだ。

 

とまあ、調べていけばきりがないほど出てくるRTOSだが、私がよく使っているNordicのマイコンがFreeRTOSをサポートしているので、それを見ていこう(RTXはまだexperimental扱い)。

Nordicの人も、多くの場合RTOSは使わなくて済むとことが多かった、と書かれているように、SoftDeviceとSDKがあるとあまり使いたいと思う気持ちはない。
ただ、nRF52くらいまでいくと、あれこれ考えるくらいだったらタスク分けしてしまえ、と思うかもしれないしね。


まず、バージョンから確認しておこう。

  • 2016/05/25 V9.0.0
  • 2016/03/30 V8.2.3
  • 2015/08/14 V8.2.2
  • 2015/03/24 V8.2.1
  • 2015/01/16 V8.2.0

このくらいでいいかな。
リリースノートはこちらだ。テキストでちょっと読みにくいが、V9系になって大きく追加されたのは、これららしい。

  • tasks, semaphores, queues, timers and event groups can now be created using statically allocated memory, so without any calls to pvPortMalloc()
    • タスクなどが静的に作れるようになりました?
  • Added the xTaskAbortDelay() API function which allows one task to force another task to immediately leave the Blocked state, even if the event the blocked task is waiting for has not occurred, or the blocked task's timeout has not expired.
    • タスクの待ち状態が解除されなくても強制的にディスパッチするAPIができましたよ?

まあ、V8系を知っていないと意味がない情報だが、どのバージョンを使いたいかの指針にはなるかも(V9のアップデート情報はここにあった)。
V9.0.0で「All ARM Cortex-M3/4F/7 ports」とCortex-M移植が進んでいるようだから、私はV9の方を使いたいかもしれん。
ただ、NordicのnRF5 SDK v11.0.0では、V8.2.1をベースに移植したものだった。


では、ホームページに書いてある特徴を列挙しよう。

  • 12年もやってる
  • RTOSのマーケットリーダーだ!
  • 商用でもプロプライエタリなソースコードの公開をせずに無料で使える
  • IP infringementリスクがない(?)

使う側としての特徴も書かれている。

  • バイナリイメージは6K~12KBくらい
  • 機能いっぱい
  • カーネル部分はCソース3ファイルだけとシンプル
  • サポートフォーラムがある

他にもいろいろ書かれているのだが、まあよかろう。


さて、あとは使い方なのだが、一から調べたくないので先人の資料を読む。

FreeRTOSの全体構成 - 電子工作室

  • 移植するファイルはportable/ にまとまっている
  • 環境設定はFreeRTOSConfig.h

 

では、V8.2.1を見てみよう。

image

Plusは追加機能のサンプルなのかな。
こちらには「Free commercial licenses」とあるので、マークがついているものは特定のユーザに限っては商用利用無料ということだろうか。

NordicのnRF5 SDK v11.0.0も同じような構成だが、少し違う。

  • FreeRTOS-Plusがない
  • portableフォルダが2つあり、上層にはコンパイラとCMSIS、下層にはMemMangだけがある
    • マイコン差分は上層のportableにあるようだ。

 

Nordicのサンプルを見比べて使い方を把握しようと思ったのだが、DFUに対応していないなどちょっと違いがある。
いきなりNordicチップだとよくわからないので、手頃そうなSTM32F4のボードを使ってみるか。
何が手頃かというと、LEDが付いていて、OSのHello Wolrd的な「タスクでLED点滅」をやりやすいのだ。

2016/08/16

[c/c++]私のC言語 (2)

第2回 よく使う型

最近、特にコンパイルオプションの指定や、コンパイラの指定もされないことが多いので、C99でやっている。
というと詳しい人のように見えるが、「//でコメントしてもよい」とか「boolやuint8_tを使ってもよい」程度だ。

 

私にとってC99がうれしかったのは、uint8_tみたいにビット幅指定の型ができたことだ。
自分でtypedefするのも面倒だし。

組み込みの人だと、intは使わず幅を固定するという人が多いのですが、私はけっこう適当です。
intはコンパイラがうまいことサイズを決めてくれるはずなので、ループのような一時的な変数だったり、メモリがある環境でフラグ変数を用意するときなんかは、ときどきintを使っている。

それだったらstdint.hにあるint_fastN_t系を使えばいいじゃないか、と言われそうで、それはそうなのだが。。。
うん、めんどうなのだ。

 

なんか、移植性を考慮してもねぇ、ということが多くて。
マイコンは32bitばかりだし、他の環境で動くアプリじゃないとなると、あまり人間ががんばらない方がいいんじゃないか、と思ったのです。
以前使っていたマイコンが、符号付き/符号無しで変換命令があるタイプだったので、悩むくらいだったらintにしとこう、と。

最近はマイコンが速いし、メモリもそこそこ多いので、難しいことをしなくても動くのが助かるところ。
普段たいへんなんだから、こういうところは楽をしたいのだ。
回らない可能性があるならlongとかにしとけばいいや、くらいな。

intにしておけば、とりあえず一番速くなるサイズを選んでくれる。
くれるはず。。。はずだよね?


気になったので、int_fastN_t系のサイズをcygwin64 gccで見てみた(unsignedも同じサイズだった)。

int_fast8_t : 1
int_fast16_t : 8
int_fast32_t : 8
int_fast64_t : 8
int : 4

・・・。
K&R本では「通常ホスト計算機の自然な整数サイズ」とあるのに、話が違うじゃないか。
「自然=一番扱いやすい」と思っていたけど、そうじゃないということか?
まあ、32bit環境だったら16と32とintは4バイトになりそうだけど。

そして、int_fast8_tは1バイトなんだ。。
私のイメージでは、CPUの汎用レジスタのサイズが一番扱いやすいサイズなのだ。
だから、16~64までが8バイトなのはまだよいのだが、それだったらint_fast8_tも8バイトになってほしかったのだ。

 

よく使っているARMだとどうかと思って検索したが、int_fast8_tはint8_tのtypedefになるようなので、やはり1バイトだ。
じゃあ、アセンブラレベルで見たらどう違うんだろう、とarm-none-eabi-gccで見てみたが、uint_fast8_tの変数でもuint_fast32_tの変数でもコードに違いがない。

自動変数だからかと思い、ポインタにしてメモリ書込にしたのだが、やはりコードに違いがない。
最適化されて消えているわけでもなさそうなのだが、8bit分の書込みと32bit分の書込みは、さすがに違うんじゃないかと思うのだが、何か書き方が悪いんだろうか。。。

あ、fastじゃない型名にしたら差が現れた。
32bitだとstrだが、8bitだとstrbになる。。。

ああ、さっきネットで検索したint_fast8_tはLLVMのものだったけど、インストールしているarm-none-eabi-gccのstdint.hを見るとこうなっていた。

#ifdef __INT_FAST8_TYPE__
  typedef __INT_FAST8_TYPE__ int_fast8_t;
  typedef __UINT_FAST8_TYPE__ uint_fast8_t;
#define __int_fast8_t_defined 1
#elif __STDINT_EXP(INT_MAX) >= 0x7f
  typedef signed int int_fast8_t;
  typedef unsigned int uint_fast8_t;
#define __int_fast8_t_defined 1
#endif

当たり前だけど、幅を固定したいのにfastとかleast系の型を使ってはいかん、ということだ。
そして、ARMにはバイトアクセス命令があるから、1バイトアクセスしても負担はない、ということか。

だから、私が思ってた「intを使っておけば最速」というのは、そう一概にも言えないよ、となる。
8bit以内だったら、intでもuint8_tでも速度としては同じになるから、自動変数だったらそこまでこだわらなくてよいけど、グローバルで持っておくんだったらuint8_tでもよいだろう。
まあ、アラインメントもあるから、多少うまく並べた方がよいとは思うが。


[c/c++]私のC言語 (1)

[c/c++]私のC言語 (1)

気力がないときでも書けるようなシリーズを作ろう、と思い立ち、普段使っているC言語のことを書くことにした。
なるべく記事は毎日書きたいのだけど、今やっている仕事のことは書けないし、記事に書くまでもないようなことをやっていることも多いので、そういうときの逃げがほしいのだ。

コーディングは、たぶん9割以上C言語でやっているので、ネタとしては困りにくいんじゃなかろうか、と思ったのだ。


第1回 組み込みとC言語

社会人になってからは医療機器メーカーだったのでC言語などで組み込みソフトウェア開発をやっていたので、もう組み込みソフトウェア開発専用で生きている。
ちょっと、他のこともできないとまずいな。。。とは思うけど、飯の種としてはこれしかないのだ。

たまに、JavaやC#をやったりすると、メモリを直接操作したい。。。と思う。
あまり他の言語に詳しいわけじゃないけど、メモリを直接操作するのは危ないから、新しい言語はそうさせないようになっていってるんじゃなかろうか。

JavaはJVM、C#は.NET Frameworkの上で動く前提だと思うから、小さいマイコンでは動かすのは難しいだろうが、そういうのがない言語であればメモリ操作さえなければ組込用であっても使えるんじゃなかろうか?

ただ、組み込みで「Hello, World!」といっても、よくてUART経由で出力させることになるだろうから、どうやってUART制御する?ということになって、OSが載っているわけでもないから自分で作るか、となる。
そうなってくると、UARTのレジスタがあるメモリを直接操作したいので、C/C++以外だとちょっと厳しいんじゃなかろうか、と思うのであった。

 

「組み込み」と書いたけど、方面によってやってることがいろいろ違うと思う。
たぶん「WEBアプリ」とひとくくりにまとめたらいかんのと同じようなもんだろう。

私は、比較的小さな、卓上で動く程度のサイズのものが多い。
工場で動くロボットや、自動車内で使うようなお仕事はやっていない。受託だし。
小さいと、電池で動くか、ACアダプタで動かすようなものになる。
そういうなると、電池があまり減らないようにとか、連続で使っても熱くならないのがいいとか、そういうことが気になってくる。

 

何が言いたかったかというと、同じC言語を使うにしても、扱う装置によってノウハウが違うので、自分でずっと普通だと思っていたやり方が、違う装置になって通用しない!みたいなこともあるだろうなあ、と思ったのだ。
お客さんによっても要望が違ったりするし。

なので、これからときどき「私のC言語」ということで書いていくけど、そういう人もいるのね、くらいで思ってもらえればいいな、と防御線を張ったのでした。

[勉]make

夏休みぼけしているので、makeというかMakefileについて復習しよう。

このブログを読んでいたのだが、自分が変数代入やコマンドを書いたりするくらいしかやってないことに気付いたので、使いそうな内容だけ復習というか覚えるというか、勉強しようという気になったのだ。
Getting More Out of Make


addprefix

こんなMakefileを作ってみた。

DBG_DIR := ./_debug
SRC := main.c
OBJ := $(SRC:.c=.o)
DBG_OBJ := $(addprefix $(DBG_DIR)/, $(OBJ))
$(info DBG_OBJ=$(DBG_OBJ))

実行すると、こうだ。
DBG_OBJ=./_debug/main.o

じゃあ、これでいいやん!と思ったのだ。

DBG_OBJ := $(DBG_DIR)/$(OBJ)

まあ、SRCがこれだったら別に良いのだが、普通はこんな感じだろう。

SRC := func1.c func2.c main.c

これを、addprefixを使わずに各オブジェクトの先頭に$(DBG_DIR)を付けようとしたら、できるのかもしれないけど大ごとになりそうだ。
addprefixだと、
DBG_OBJ=./_debug/func1.o ./_debug/func2.o ./_debug/main.o
と、ちゃんとそれぞれにつけてくれる。

この技を知らなかったので、自作したMakefileは.oファイルがソースと同じところにできるのであった。。


$(info)

Makefileがうまく動いてくれないときで、とりあえず変数がどうなっているのかを見たいときに使っている。

これを知るまではターゲットでechoさせていたけど、$(info)はターゲット外に書けるので気が楽になった。


.PHONY

使ったことが無い。。。
「偽りのターゲット」で、ターゲットと同じ名前のファイルがあると実行しなくなるので、「これはファイルじゃないんですよ」ということを宣言するみたいだ。

やってみよう。

Makefile:
    @echo Hello Makefile!

$ make Makefile
make: 'Makefile' is up to date.

ふむ、実行されない。

.PHONY: Makefile
Makefile:
    @echo Hello Makefile!

$ make Makefile
Hello Makefile!
make: Nothing to be done for 'Makefile'.

なるほど、実行された。
習慣的に付けるか、困ってから付けるか、だな。


=と:=

私はいつも=で代入しているのだが、NordicのMakefileだと:=と=を使い分けているような気がする。

Makefile で代入の扱い - Qiita

その場で値を評価するか、使用時に評価するからしい。

ifeq ($(VALUE_TEST),y)
HELLO (代入) "hello"
else
HELLO (代入) "bye"
endif

all:
    VALUE_TEST=y
    @echo $(HELLO)

これで、:=だとすぐに代入されるから、VALUE_TESTがyでないので"bye"になり、=だと実行時に評価するから"hello"にな。。。。ならない!
どっちも"bye"になった。

なので、動的というのは、そういう動的ではない、ということだ。

 

all: VALUE_TEST := y
all:
    @echo $(HELLO)

HELLO = value=$(VALUE_TEST)
$(info HELLO=$(HELLO))

$ make all
HELLO=value=
value=y

こういう動的なのだ。
地の文(?)の$(info)の段階では、まだVALUE_TESTは空なので、「value=」しか見えない。
しかしallの中ではyが代入されるので「value=y」になる。

動的というか、:=はその場で評価するが、=は式ごと保持するので、使う段階で評価されるということですな。
こういうタイプは、$(info)で見てもわからないということか。。


$なんとか

よく使うけど、覚えられず、いつもまねしている。
それが$のついた変数だ。
自動変数、と呼ぶらしい。

$@, $%, $<, $?, $^, $+, $*、と、数は7つしかない。
覚えられないのは、覚えようとしていないからか。。。

 

SRC := func1.c func2.c main.c
all: $(SRC)
    @echo "@="$@
    @echo "%="$%
    @echo "<="$<
    @echo "?="$?
    @echo "^="$^
    @echo "+="$+
    @echo "*="$*

これを実行すると、ターゲットfunc1.cを処理するルールがない、と怒られた。
確かにないのだが、touchで空ファイルを作ると怒られなかった。
これが「暗黙のルール」というやつだろうから、.PHONYで対抗した。

.PHONY: func1.c func2.c main.c
SRC := func1.c func2.c main.c
all: $(SRC)
    @echo "@="$@
    @echo "%="$%
    @echo "<="$<
    @echo "?="$?
    @echo "^="$^
    @echo "+="$+
    @echo "*="$*

@=all
%=
<=func1.c
?=func1.c func2.c main.c
^=func1.c func2.c main.c
+=func1.c func2.c main.c
*=

同じように、func1.cのルールを作った。

.PHONY: func1.c func2.c main.c
SRC := func1.c func2.c main.c
all: $(SRC)
    @echo "@="$@
    @echo "%="$%
    @echo "<="$<
    @echo "?="$?
    @echo "^="$^
    @echo "+="$+
    @echo "*="$*

func1.c:
    @echo "func1 @="$@
    @echo "func1 %="$%
    @echo "func1 <="$<
    @echo "func1 ?="$?
    @echo "func1 ^="$^
    @echo "func1 +="$+
    @echo "func1 *="$*

func1 @=func1.c
func1 %=
func1 <=
func1 ?=
func1 ^=
func1 +=
func1 *=func1

@=all
%=
<=func1.c
?=func1.c func2.c main.c
^=func1.c func2.c main.c
+=func1.c func2.c main.c
*=

$@はわかりやすい。
ターゲットの名前だ。

$<もなんとなくわかるのだが、func1.cターゲットの場合には出てこない。
あくまで「依存関係の先頭」だから、依存するものが無いから出てこないのだ。
しかし、使い道はなんだ?

main.o: main.c
    $(CC) -o $@ -c $<

なるほど、オブジェクト名がターゲットで、それと依存関係を持つのはmain.cだから、コンパイルするファイル名は$<ということか。
もう少し一般的にすると、こうらしい。

%.o: %.c
    $(CC) -o $@ -c $<

nRF5 SDKのexamplesでは、こういう書き方をしていた。

$(OBJECT_DIRECTORY)/%.o: %.c
    @echo Compiling file: $(notdir $<)
    $(NO_ECHO)$(CC) $(CFLAGS) $(INC_PATHS) -c -o $@ $<

 

$?, $^, $+も「依存関係の」だ。
$^と$+は依存関係を全部並べるタイプで、$?は更新された依存関係だけを並べるタイプだ。
今回はallという偽ターゲットだから、$?で全部出ているのだろうか?

残りは、使う機会があれば覚えよう。
$%がアーカイブ用で、$*は語幹らしい。


gcc -MMなど

これは、NordicのMakefileでは使われていない。
gccのコマンドなのだけど、依存関係をMakefileがわかる形式で出力するオプションだ。
Nordicブログでは、各ソースファイルごとに依存関係のファイルを作っているようだが、私は1つの依存関係ファイルに追加していくタイプだった。
個別にした方が融通は利きやすいのかな?

依存関係がほしいのは、主にソースファイルとヘッダファイルの紐付けだ。
今のexamplesだと依存関係がわからないので、ヘッダファイルが更新されてもビルドをしてくれないのだ。
Nordicのexamplesだと、最初にcleanしてからビルドするので、毎回時間がかかるのだ(大した時間じゃないけど)。


abspath

これは、addprefixと同じく関数だ。
名前の通り、相対パスなどを絶対パスに置き換えてくれる。

が、これがcygwinと相性が悪いようだ。
cygwinというか、Windows版のgccコンパイラと、というか。
コマンドプロンプトでmakeするときはファイルを見つけてくれるのだが、Cygwinでmakeするとファイルが見つからないのだ。
たぶん「/cygpath/~」の形式になるからだろう。
コンパイラはcygwinの世界以外からやってきてるから、知らないはずだ。

cygpathを使えばいいよ、ということらしいが、そうするとLinuxで使えなくなるし。
GNU Win32のmakeを使うのが楽そうだ。
コンパイラはShift-JIS出力だから文字化けするが、まあそこは許容するしかあるまい。


自分が使いそうなものを書き出してみたが、いくつかパターンを作って置いて、テンプレートとして持っておくのが良い気がする。

自動的に作ってくれるスクリプトや、automakeもあるのだが、スクリプトだと自分の気に入った配置になってないことがあるし(変更すればいいのだけど)、automakeはちょっと大ごと過ぎる気がする。
cmakeもたまに見るけど、あれは楽なんだろうか?

楽をしたいだけなのだが、間違いがあっても困るし、時間をあまり掛けたいわけじゃない。。と、いつもうろうろ考えてしまいます。

2016/08/11

[nrf52]Centralしていく (5) - 完

nRF5 SDK v11.0.0のble_app_hrs_cサンプルを見ていくシリーズ。
たぶん最終回だ。


前回、HRSPeripheralとのBLE接続を行うようにしたので、ble_evt_dispatch()でイベント処理を有効にした
これでmain.cは、ログの追加以外はオリジナルと同じになった。

 

HRSとBASのイベントハンドラを有効にしたのだが、これはどちらもSDKが提供しているので、独自で実装している箇所はない。
だから、おそらくコールバックする設定をinitでやってるんじゃないか。

あった。

SDKが提供しているハンドラの中では、BLE_GATTC_EVT_HVXやBLE_GATTC_EVT_WRITE_RSPなどのイベントをさばいている。
WRITE_RESなんかは、コールバックされないようだけど、中でsd_ble_gattc_write()を呼ぶようだ。
でも、これってWriteするAPIじゃないのか?

HRSでWriteがMandatoryなのは、Control Pointだ。
現在はリセットだけなのかな。
ble_hrs.cを見ると、WriteではCCCDの処理しかしていないし、Characteristic自体がConditionalだから、ble_hrs_cもWriteはCCCDしか意識していないのでコールバックしない、ということか。

Write without Responseの場合はBLE_EVT_TX_COMPLETEが発生し、そうでなければBLE_GATTC_EVT_WRITE_RSPが発生するらしい。
CCCD書込みでNotificationを有効にする場合、この順で呼ばれる。

ble_hrs_c_hrm_notif_enable()

cccd_configure()

tx_buffer_process(WRITE_REQ)

sd_ble_gattc_write()

これはわかる。
しかし、BLE_GATTC_EVT_WRITE_RSPの場合はこうなると思うのだ。

ble_hrs_c_on_ble_evt()

on_write_rsp()

tx_buffer_process(WRITE_REQ ??)

sd_ble_gattc_write()

WRITE_REQかどうかははっきりしないが、誰も変数に書込む人がいないので、維持されるはず。。。

あー、tx_buffer_process()の頭にあるindexの比較ではじかれるのかな?
バッファは8つ分あって、送信するときはcccd_configure()でm_tx_insert_indexが指すバッファに代入してインクリメントし、送信が成功したらm_tx_indexもインクリメントする。
WRITE_RSPイベントのときはインデックスは操作せずにtx_buffer_process()を呼ぶから、同じ値なので処理はしない。
もしcccd_configure()のルートで送信したときに失敗していたらm_tx_indexはインクリメントされないので、WRITE_RSPイベントの時にはインデックスが不一致なので再送される、と。

難しいよ!



HRSでReadのイベントがないのは、ReadするCharacteristicのBody Sensor LocationがOptionalだからだろう。
つまり、積極的にアプリが処理しないといけないのはNotification受信時だけとなる。

そういう目線でHRSのハンドラを見てみよう。
処理しているイベントは2つ。
BLE_HRS_C_EVT_DISCOVERY_COMPLETEとBLE_HRS_C_EVT_HRM_NOTIFICATION。

 

BLE_HRS_C_EVT_DISCOVERY_COMPLETEはイベントなのだが、サービスが見つかった、というイベントだ。
これは、db_disc_handler()から呼ばれる。
このハンドラはble_db_discovery_init()で登録している。
そして、db自体のハンドラはble_evt_dispatch()で他のイベントと一緒に並んでいる。
なのでまあ、BLE接続後のイベントは一緒くたということだな。

サービスが見つかったら、まずはNotificationを有効にせねば、ということでble_hrs_c_hrm_notif_enable()を呼んでいる。

 

BLE_HRS_C_EVT_HRM_NOTIFICATIONは、受信した値をログ出力するだけだ。
まあ、他にやれることがないしね。


Notificationされるのは、Heart Rate MeasurementというCharacteristic。
最初のバイトが、どのデータを含んでいるかのビットを立てるようになっていて、あとはそれに従ってデータが詰まっているだけのようだ。
Heart Rateだけは有無ビットがないので、必須なのだろう。
まあ、Heart RateサービスなのにHeart Rateが入ってなかったら、困るわね。

徐脈というか、脈が欠ける人はR-R間隔もほしいかも。
HRだけじゃわからないのよねぇ。


BLE接続後のことだけ書いたが、接続されたときのイベント処理も忘れてはいかんだろう。
BLE_GAP_EVT_CONNECTEDだ。

ここで、ハンドル値をHRSとBASに教えて、紐付けしているのだろう。

 

じゃあ切断の時はBLE_GAP_EVT_DISCONNECTEDかと思うと、そうではなくDM_EVT_DISCONNECTIONだ。
PeripheralだとGAPの方は切断された一番最後辺りに呼ばれて、DMの方が先に呼ばれていたと思う。
切断されてしまってからじゃ遅いよ、ということか。。。
でも、対称性がないからちょっとイヤなので、「今から切れます」イベントもGAPに来てくれるとうれしい。そんなのないけど。

CONNECTEDで紐付けしたハンドル値は、ble_hrs_cやble_bas_cの中で勝手に忘れるようになっている。
自分でサービスを作るときには忘れないようにせねば。

 

DMのDISCONNECTIONが何をしているかというと、スキャンの再開のようだ。
このサンプルでは1台しかPeripheralを接続しないので、切断したらスキャンが始まる。
スキャンの開始なんかGAPのDISCONNECTEDで始める方が良いような気がするのだけど、ここでよいってことなんだ。

まあ、Centralは相手が複数いるから、接続可能台数に達していない場合は常にスキャンしていることになるのか。
その上のDM_EVT_CONNECTIONでも台数未満だったらscan_start()してるし。


駆け足で見ていったCentralだったけど、よくわかってないことも多い。
こういうのは、実際に作りながらやってみるとよいのだろう。

BDSがCentral側のサービスもテンプレートを作ってくれるとよいのだけどなぁ。。。

[nrf52]Centralしていく (4)

前回(3)は、on_ble_evt()でBLE_GAP_EVT_ADV_REPORTイベントを拾えば、Advertisingで何が来ているのかは読めそうだ、というところまでだった。


それでは、コメントアウトしていたところを復活させよう。
adv_report_parse()が成功した後の、UUIDを見つけた後の動作だ。

forで見つけたUUIDを検索して、0x180Dが入っていればスキャンを停止させている。
sd_ble_gap_scan_stop()が失敗するのはスキャンさせていないときくらいらしいから、通常はこのタイミングでエラーにならないのだろう(ユーザ操作による停止とクロスしたときとかかな?)。

 

一般的に、受信よりも送信の方が電力がいると思う。
しかし、送信は一瞬で良いけど、受信はタイミングがわからない場合、待ち続けないといけない。
nRF5xのPeripheralは、Advertisingをble_advertising_init()のble_adv_fast_intervalなどで設定した時間のうちに3ch分送信するようになっていたと思う。
Core v4.2の図を見ると、Intervalの頭でぽんぽんぽん、と3発打つようだ。

image

 

Centralではsd_ble_gap_scan_start()のintervalとwindowで指定するようだ。
intervalとwindowは2.5msec~10.24secの間で設定可能。
intervalが長く、windowが短くなると、消費電力は減るけどPeripheralを捕まえにくくなるんだろう。
このサンプルでは、intervalは100msec、windowは50msecになっているので、こういうイメージで良いのかな?

image

 

では、もしPeripheralのintervalが100msecだったら、タイミングがあえばCentralから捕捉できなくなるのだろうか?
あー、それを防ぐために、Advertising Intervalはこういう式になっているのか([Vol 6, Part B, 4.4.2.2])。

image

advDelayは0~10msecのランダム値なので、受信間隔と幅が固定でも、いつかは捕捉されるだろう、ということか。

image

AndroidとNFCペアリングしようとしても、デバイス名が出てくるときと来ないときがあるのは、このランダム性が関係しているのかも。


その後、スキャンパラメータのselectiveとp_whitelistを変更している。
この値はスキャン開始前に設定するのだが、ペアリングしているかどうかで値が違う。
スキャン後に設定する値は、ペアリングしていないときの値だ。
そして、sd_ble_gap_connect()で接続している。

selectiveビットが立っているなら、アドレスはNULL指定らしい。
だから、アドレスとしてスキャンしたものを使うためにselectiveを0にしているのだろうか?
だったら、p_whitelistはそのままでも良い気がするのだけど、これは「current active whitelist is to be used」が理由なのか。

 

わからん、わからんのだ・・・・。
Centralがどうやるとどう振る舞うのかがわかっていない。
multilink_centralやuart_cを見ると、スキャンパラメータは固定値だし。
はて、どうしたものか。。。

一旦忘れて、BLE接続した後の動作を見ることにしよう。


関係ない話だが、NordicのSDKサイトがInfocenter系になってから探しづらい。。
個人的には、SDKだけでもDoxygenの方が探しやすくて良かったのだけど、ローカルで良いから構築できないものだろうか。

2016/08/10

[c/c++]TeraTermの出力に色を付ける

ログ出力させるマクロを書いていたのだが、ふっと、エラーレベルは赤で出力させたい、と思った。
ターゲットはBeagleBone Greenで、UART出力(/dev/ttyS0)をUSBシリアル変換してWindows上のTeraTermで見ている。

他の環境がわからないので、TeraTermで出力を見た場合に限定しておく。


「teraterm エスケープシーケンス」で検索するといくつも出てくるので、こちらを参考にした。
エスケープシーケンスを体感する - ザリガニが見ていた...。

こんなマクロを用意し、

#define LOG_COL_RED     "\e[31m"
#define LOG_COL_END     "\e[m"

こういう感じでログ出力にした。

#define LOGD0(s) printf(LOG_COL_RED "E/%s:%d: " s LOG_COL_END)

RTTViewerで色を出すと見やすいときがあるので、負担にならないならいいんじゃないかな、と思う。
まあ、解釈してくれないとゴミっぽく見えるので一長一短ではあるのだが。。。


ついでに(?)、makeでのecho出力も色を付けてみよう。
これは、黄色文字だ。

@echo -e "\033[0;93m"Hello!"\033[0m"

「-e」がないと、色が出ずにそのまま解釈されてしまった。

TeraTermのエスケープシーケンスルールとは違うようだ。
でも、TeraTermで黄色に見えるから、意味が同じで、表し方が違うだけなのだと思う。

makeの出力はたくさん出てくるから、背景に色を付けるタイプの方が見逃しにくいかもしれない。
私はMakefileを書くのが上手にならないので、こう書いたらいいよ、というのが説明できないのだ。
すまぬ。。。

 

こっちは、colormake、というmakeのラッパがあるよ、ということらしい。
今回はcygwinで見ているから確認してないけど、そういうのがあるんですな。
bash - How Can I highlight the warning and error lines in the make output? - Stack Overflow

[nfc]マイナンバーカードでSSHできるらしい (3) - 中断

SSHのところまでやるのは面倒そうなので、マイナンバーカードから公開鍵を取ってくるのと、署名したデータを公開鍵で復号するところだけやってみよう。
これなら、OpenSSLがあればできるはずだ。

 

マイナンバーカードを作るときには4つの暗証番号を作っている。

  1. 署名用電子証明書暗証番号
  2. 利用者証明電子証明書暗証番号
  3. 住民基本台帳用暗証番号
  4. 券面事項入力補助用暗証番号

マイナンバーカードでSSHする - AAA Blog
こちらの「署名プロトコル」では、PIN番号が4桁の暗証番号をASCIIで、と書いてある。
1番は文字列だったので違うとして、2~4番のどれだろう?
3つとも同じ数字でも良いようだったのだけど、せっかくだから別々にしたのだ。

ファイルシステムからすると、住基APが3番で、券面事項確認APと券面事項人力補助APが4番だろうか。
となると、消去法で2番となる。
実行時も「User Authentication PIN」となっているから、利用者の方だろう。
総務省のPDFでは、JPKI-APの暗証番号は2種類あるように書かれているので、1番と2番がそれだろう。
1番を使う場合は、PDFを見ていると、情報を得るためのお金がいるような気がする。

 

http://www.soumu.go.jp/kojinbango_card/kojinninshou-01.html
ここを読むと、いわゆる電子署名で使うのが1番、本人の確認で使うのが2番のようだ。
しかし、利用者証明書の方は、自由なデータを符号化するのではなく、公開鍵+電子証明書を利用者証明書秘密鍵で符号化するようだ。

では、あのサイトで署名に使っているPKCS1形式のハッシュ値、というのは、なんだろうか?
下の方にはPKCS#11 APIと書かれているが、それとは別ということか。
そういう細かいところまでは書かれていないから、ソースファイルを読まないといかんのか。。。

しかし「公的」というくらいだから、実は一般的な仕様書があるんじゃなかろうか?
まずは、そこから探してみよう。


PKCS#1は、RSAとハッシュを使って電子署名を行うアルゴリズムらしい。
http://www.atmarkit.co.jp/ait/articles/0607/11/news113_2.html
ということは、やはり署名の話ではあるようだ。
ならば、入れるメッセージは自由だと思う。

 

公的個人認証サービス利用のための民間事業者向けガイドライン1.1版PDF
これのp.13を見ると、電子利用者証明を使うのは「文書を伴わないアクセス」となっているから、やはり文書を入れられないということか。
p.11の方には「公開鍵+電子証明書」が自分であることを証明するデータと書かれている。

p.11では、電子署名のしくみはもともとあるのだが、その中身は「基本4情報を含む」ものが入っている。
基本4情報は「氏名、住所、生年月日、性別」だ(証明書の期限は5回目の誕生日だから、生年月日はわからないけど誕生日はわかってしまうんだけどね)。
だから、それは民間には開放しにくいけど、新規の方は基本4情報が入っていないから、インターネットのログイン程度でも使ってもらって構わないということか。

 

ということからすると、どういうデータかわからなかった「PKCS1形式のハッシュ値」というのは、「公開鍵+電子証明書(基本4情報を含まない)」をPKCS1形式でハッシュ値にしたものなのかな。

でも、p.12の例2を見ると、利用者証明用電子証明書を使っているけど暗号文などが入っているのよねぇ。
それだったら、どういうデータを突っ込んでも、とりあえず秘密鍵で符号化してくれそうな気もするのだ。
もしかしたら、それ自体がPKCS1形式なのかもしれんが。。。どうなのだろう。


JPKIを利用するアプリをインストールして情報を確認すると、sha256フィンガープリント、という情報があった。
64文字あるので、32バイト分→256bitって、そのままだった。。。

適当なデータを突っ込むか、それっぽいデータを突っ込むか考えたが、このフィンガープリントがそれっぽい感じがするので、よいのではなかろうか。

 

・・・あれ。
そういえば、公開鍵はどうやって取得したらいいんだろう?
pkcs15-toolというツールを使ってid_rsa.pubに出力しているけど、これをカードからどうやって読み込んでいるかの情報は書かれていない。。

これ以上進めるには、公的個人認証APの仕様が公開されないと難しい。
実際にアクセスして解析するという手段もなくはないのだが、今回は止めておこう。

[esp8266]NonOS SDK v2.0.0のパッチ(2016/08/09)

先日リリースされたESP8266 NonOS SDK v2.0.0だが、パッチが公開されていた。

http://bbs.espressif.com/viewtopic.php?t=2529&p=8350#p8350

接続が遅い件の対応と、system_phy_freq_trace_enable()というAPIの追加らしいです。
まだv2.0.0を動かしていないので、ピンと来てはいないです。。

 

注意書きもいろいろあるので、読んだ方がよさそう。
温度が80度以下じゃないと発振子の特性があるからねー、とか。
意外と高温までいけるんですな。

2016/08/09

Windows10のアップデートをしたらTTClockが起動しなくなった→V3.0で対応!

[2016/11/07]
V3.0からWindows10で動くようになりました(情報ありがとうございます)。

 

タスクトレイに表示される時計に日付と秒数がほしいので、ふだんはTTClockでカスタマイズをしている。
http://chihiro718.jpn.org/JPN/software/TTClock.html

 

最近、ClassicShellがv4.3.0になり、先にClassicShellが起動しているとTTClockが起動しなくなるという現象が出た。
まあ、これはスタートアップの順番を決めるアプリがあったので、それでしのぐことができた。

 

が、さきほどWindows10のアップデート(Anniversary Updateというやつですな)を行うと、もうTTClock自体が起動できなくなってしまった。。。

image

こういうエラーが出る。

image

うーむ。。。

 

7+ Taskbar Tweaker for Windows 10 Anniversary Update: early alpha version - RaMMicHaeL's Blog
7+ Taskbar Tweakerがやってくれそうな感じがするのだが、donateしないとAnniversary Update版をダウンロードできなさそうだ。


2016/08/10追記

Windows10 に Anniversary Update を適用したら tclock が動かなくなってしまったので,代わりに T-Clock というのを使用中.: とり茶

おお、そういうのがあるんだ!
使ってみると、動きました。
タスクバーの高さが低いままでも2行で日付表示してくれるところもうれしい。
β2版のようなのだが、まずはこれで十分です。