Particle.io Argonで詰まった点
Particle.ioで購入できるParticle ArgonというWi-Fi機能付きマイコンボード*1と最近格闘している。そのうち、悩んだりした点をメモとして残す。
目次
Firmwareをv1.2.1→v.1.4.1へとアップデート後、再起動する度Wi-Fi設定が保存されず消える
1日くらい原因が分からず困っていた。
【症状】
【原因】
- Bootloaderかsoftdeviceの更新漏れ
- 確認方法としては、Particle CLIで
$particle serial inspect
を実行。FAILした項目について修正
【対処法】
- Device-OSのgithubからbootloader等の.binファイルを取得
- Particle CLIで
particle flash --serial <bootloader>.bin
で書き込み(githubのRelease Noteに方法が記載されている)
(なぜ$particle update
でbootloaderが更新されなかったのかは分からないが)
【その他】
- ダウングレードする際は、先にUser applicationもdowngradeした後のOSバージョンで動くようコンパイル・書き込みしておくべき?
v1.2.1→v1.4.1へとアップデート後、bootloader等を更新する前後の$particle serial inspect
の結果を、以下に示す。Dependencyで示されたversionと、Bootloaderのバージョンがズレていたことが分かる。
前
D:\Users\
\Desktop\1.2.1\argon\release>particle serial inspect
Platform: 12 - Argon
Modules
Bootloader module #0 - version 311, main location, 49152 bytes max size
Integrity: PASS
Address Range: PASS
Platform: PASS
Dependencies: PASS
System module #1 - version 1404, main location, 671744 bytes max size
Integrity: PASS
Address Range: PASS
Platform: PASS
Dependencies: FAIL
Bootloader module #0 - version 501
Radio stack module #0 - version 202
User module #1 - version 6, main location, 131072 bytes max size
UUID: DA2E920A883A1D6D53FCE0F96C8A9C148C3DD980989964EAC610D336964C1CFA
Integrity: PASS
Address Range: PASS
Platform: PASS
Dependencies: PASS
System module #1 - version 1213
NCP module #0 - version 5, main location, 1536000 bytes max size
Integrity: PASS
Address Range: PASS
Platform: PASS
Dependencies: PASS
Radio stack module #0 - version 202, main location, 192512 bytes max size
Integrity: PASS
Address Range: PASS
Platform: PASS
Dependencies: PASS
D:\Users\\Desktop\1.2.1\argon\release>
後
C:\Users\
>particle serial inspect
Platform: 12 - Argon
Modules
Bootloader module #0 - version 501, main location, 49152 bytes max size
Integrity: PASS
Address Range: PASS
Platform: PASS
Dependencies: PASS
System module #1 - version 1404, main location, 671744 bytes max size
Integrity: PASS
Address Range: PASS
Platform: PASS
Dependencies: PASS
Bootloader module #0 - version 501
Radio stack module #0 - version 202
User module #1 - version 6, main location, 131072 bytes max size
UUID: DA2E920A883A1D6D53FCE0F96C8A9C148C3DD980989964EAC610D336964C1CFA
Integrity: PASS
Address Range: PASS
Platform: PASS
Dependencies: PASS
System module #1 - version 1213
NCP module #0 - version 5, main location, 1536000 bytes max size
Integrity: PASS
Address Range: PASS
Platform: PASS
Dependencies: PASS
Radio stack module #0 - version 202, main location, 192512 bytes max size
Integrity: PASS
Address Range: PASS
Platform: PASS
Dependencies: PASS
C:\Users\>
電源を入れるとListening modeに入る
自分が知りうる限りでは以下のどちらかが原因。
- ネットワーク設定がおかしい(→スマフォのアプリから設定)
- setupが完了したフラグが設定されていない(→下で解説)
2.だが、基本的には以下の公式ページを参照。
要点としては、基本的にはsetup完了フラグがupdate時に付与されるが、ならない時もたまにある(手動アップデートした場合等)。ページにあるようなプログラムを一度書き込めば解消する。
その他
- ArgonのLi-Poコネクタは恐らくJST PHコネクタ(2mmピッチ)
- WebIDEよりParticle CLIの方が扱いやすい(WebIDEでは、コンパイルメッセージが操作をすると消えてしまうが、Particle CLIではそうはならない。また、ファイルを複数使用可能)
- Listening-modeのon/off等、モードの切替は
$particle usb
コマンドで可能 - Serial通信を見る際は
$particle serial monitor
- Wi-Fi設定は
$particle serial wifi
$particle doctor
はMesh device(Argon等)に対応していない、らしい
Stringのc_str()を誤って使っていた
ParticleのStringがstd::string(std::basic_string
int register_to_cloud(){ unsigned int retval = 0; bool is_success = false; // setctrl<number>の登録 const char* name1 = (String("setctrl") + String(this_class_identify_id)).c_str(); Log.info("register_to_cloud() try : %s", name1); is_success = Particle.function(name1_s, &Channel::change_controllability, this); retval |= static_cast<unsigned int>(is_success); if (!is_success){ Log.info("register_to_cloud() failed : %s", name1_s); } else { Log.info("register_to_cloud() succeeded : %s", name1_s); } }
Ideoneで再現すると次のような感じ。文字列"Hello world"が正しく表示されない:https://ideone.com/HFXHPH
【原因】
- 一時オブジェクト(String)のメンバ変数へのポインタを使っていた
詳細
(String("setctrl") + String(this_class_identify_id))
は一時オブジェクトであり、その寿命はconst char* name1
の代入式だけ- 一方、(少なくとも)std::basic_string
のc_str()は、privateなメンバ変数である配列へのポインタを返す(下記ソースコード参考)*2。 - そのため、代入式以降は
name1
の参照先がStringの文字列と一致するとは限らない*3。
【参考】
- 一時オブジェクトの寿命等について*4: 一時オブジェクトの寿命と右辺値参照、ムーブセマンティクスのお話 - Qiita
- std::basic_string
について:libstdc++: basic_string.h Source File
// 21.3 Template class basic_string template<typename _CharT, typename _Traits, typename _Alloc> class basic_string { typedef typename _Alloc::template rebind<_CharT>::other _CharT_alloc_type; // Use empty-base optimization: http://www.cantrip.org/emptyopt.html struct _Alloc_hider : _Alloc { _Alloc_hider(_CharT* __dat, const _Alloc& __a) : _Alloc(__a), _M_p(__dat) { } _CharT* _M_p; // The actual data. }; private: // Data Members (private): mutable _Alloc_hider _M_dataplus; _CharT* _M_data() const { return _M_dataplus._M_p; } _CharT* _M_data(_CharT* __p) { return (_M_dataplus._M_p = __p); } // String operations: /** * @brief Return const pointer to null-terminated contents. * * This is a handle to internal data. Do not modify or dire things may * happen. */ const _CharT* c_str() const { return _M_data(); } };