これはAkerun Advent Calendar5日目の記事です。
はじめに
Photosynthという会社は Akerun という入退室管理システムを提供しています。 ハードウェアからクラウドまで一気通貫で自社開発している、スタートアップでは数少ない会社のひとつです。
書いてる人
Akerunの中の人です。元は大手電機メーカーで組み込みやってました。Photosynthにジョインしてからは ファームウェアやったりアーキテクトしたりいろいろやってます。
この記事
※個人の主観です。
私がWebエンジニアたちと一緒にプロダクト開発をしてみて感じたギャップに基づき、組み込みエンジニアの特異な性質について書いてみました。
共感する部分があれば、ふふっと鼻で笑ってやってください。
プログラミング・設計編
状態を持たせる設計をする
組み込み屋さんは状態をもたせる設計を好みます。
A) Hogeの状態でメソッドを実行するとFugaする B) hogeHogeの状態で同じメソッドを実行すると無視する
など、状態によって処理を分岐します。ちゃんと理由があります。これはハードウェアは基本的に状態を持っていることに起因します。わかりやすい例だと、電源がONかOFFかが状態。ONのときは処理するがOFFのときは無視されますね。
一方でwebAPIを設計するときはリクエストに対して常に一定のレスポンスを返すことを期待する設計をとることが多いと思います。
お互いの思想を尊重した設計をとる必要があります。
ステートマシン大好き
状態を多用するので、ステートマシンを実装することが非常に多いです。100%です(自分調べ
UMLをみんな読み書きできると思ってる
設計はシーケンス図とクラス図(モジュール構成図)、ステートマシン図から始まります。シーケンス書かないとか設計じゃな
駆け出しの頃はIT専科さんにはお世話になりました。
数値の上限をとても気にする
変数には必ずサイズがあるので特に上限値を気にします。値が128や256に達するかとか、とても重要です。 連番で発行するidの上限でよく喧嘩します。
負値になりえるのか気にする
符号なし変数を多用するので、実装後に急に負の値が仕様に出てくるとキレます。切実です。
符号なし変数を使う理由は、同じサイズで上限が大きくなるからです。
符号あり1Byte: -128〜127 符号なし1Byte: 0〜255
理由がなければ符号なしを使います。
小数がでてくると青ざめる
リソースがプアなマイコンでは特に小数を扱えません。
実際には、整数部分と小数部分を別変数で定義する実装で対応したり。
わかりやすさよりもリソースを優先しなくてはならない(したい)
以下にもうすこし細分化します
1バイトに複数のパラメータを突っ込む
1Byteの中で、1bitずつ(もしくは複数bitまとめて)意味をもたせます。
フラグなど、booleanなら最大8つ入ります。
例えば
成功失敗:boolean 結果:0-100までの値
を格納したい場合、
offset | size | param |
---|---|---|
0 | 1bit | 成功 |
1bit | 7bit | 結果 |
というルールを決めて1Byteに入れてしまいます。理由はサイズを小さくするためです。 少ないメモリで処理したい場合や、通信で流れるサイズを小さくしたい場合に多用します。
パラメータのやり取りを文字でやらない
理由は主にサイズです。
文字(string)型はサイズが大きいのです。1文字あたり1Byteも必要です。しかも{}や""なども文字です。そして文字列の最後は塗る終端\0が入るのでこれも1バ(ry
たとえば
成功:boolean 結果:0-100までの値
というパラメータ群を送りたい場合、
JSON:{"success":true,"result":100}
で30Byte必要ですが、先程でてきた
offset | size | param |
---|---|---|
0 | 1bit | 成功 |
1bit | 7bit | 結果 |
というルールを決めれば1Byteに入ってしまうのです。
パースについては、近年便利なライブラリが出てきたのであまり気にしなくて良くなってきました。
相手が論理演算できることを期待する
上記の理由から、やりとりする相手に論理演算を要求します。
上で示した1Byteの値から値をパースするには
success = a & 0x01 result = (a & 0x0e) >> 1
という実装してね?と web屋さんに要求します。悪気はないです。
掛け算・割り算をビットシフトでやりがち
hoge * 2 : `hoge << 1` hoge / 4 : `hoge >> 2`
理由は演算スピードと、あとは好みです。
nilなんてない
レガシーな組み込みの世界では NULLと0が同値です。 なので未定義であることを示す値をあえて定義します。変数の上限値0xff(255)を使うことが多いです。
#define NIL (0xff) if (a == NIL) { // エラー処理 }
マイコンやフラッシュメモリでも、未使用のメモリ領域は0xffが書かれていることが多いです。
型がないと不安
型がない言語は気持ち悪いですね(個人の感想です
変数がメモリにマップされるかわからないと落ち着かない
ほんとにメモリ確保されてるのか、生存期間とかが明確じゃないと怖くて使えません。
確率的におこるバグと闘う
組み込みでは、確率的に起こるバグがあるので、数万オーダーのテスト(エイジングやヒートランと呼びます)を回します。 Webではあまりないんですってね。
言語編
石
マイコンやSoCのことを石と呼びます。石ころで遊んでるわけではないです。
治具
治具という言葉はとても広義ですが、石にプログラムを書き込む器具を治具と読んだりします。
API
APIというと、構成モジュール間の呼び出しIFを指します。
curlで叩くアレをカジュアルにAPIと呼ぶことに慣れるのに時間がかかりました。
16進数をしゃべる
イチエフ(1f) とか サンナナ(37) といった表現を使います。16進数です。
あ、デバッグダンプは16進数で出してあげてください。
16進数から2進数を暗算する
16進数をみると2進数がすぐにわかります。変態だからではありません。1Byteに複数のパラメータが含まれることがあるので、値を知るには2進数表記を知る必要があるからです。どのbitが立っているかわかる、とも表現します。気持ち悪いとか言わないでください。
バイナリを読む
組み込みの世界ではコンパイラによって処理が意図しなくなってしまったりすることがあります。差分を見るために、ビルドしてできたバイナリを直接比較したり読んだりすることがあります。気持ち悪いとか言わないでください。
弱点編
静電気に弱い
ハードウェアを扱うので静電気に敏感です。開発機が死んで途方にくれます。割とあります。ピカチュウ。
乾燥に弱い
以下同文
EOLに弱い
ベンダーロックインせざるを得ないこともあるのですが、SoCが変わると死にます。
webエンジニアと働いてみて
めちゃめちゃ楽しい ✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌
おわり
他にもたくさんありますが、このくらいにしておきます。 最近はIoTもすっかり当たり前化してきているので、組み込みエンジニアと仕事をする機会も多いと思います。 これを読んで「組み込みの人って16進でしゃべるんでしょ?」など話題をつくってもらえたら嬉しいです。
一緒にプロダクト開発するエンジニア募集してます!