mini pc に Ubuntu 24.04 を入れる

家族用の mini pc が手狭になったので退役させて新しい mini pc を購入しました。

MINISFORUM の3万円程度だったと思うのですが、CPU スペックはこんな感じ

外観…というか後ろ姿はこんな感じです。

中味が Windows 10 なのですが、CPU の関係で Windows 11 にアップデートができません。そのまま廃棄してもよいのですが、いったん Ubuntu を入れてみようということです。

USB で Ubuntu を起動させる

実は直接 Ubuntu を mini PC に入れたかったのですが、その方法がなかなか見つかりませんでした。何故か USB メモリから起動するサイトはたくさんあるのですが。

Ubuntuのインストール用のUSBメモリを作成する方法 | kantan-prog https://kantan-prog.com/ubuntu-install-usb/

起動用の DVD を作ってもよいけど面倒くさいし、ひとまず USB 起動でよいか、ということで Windows 上で USB メモリで起動する Ubuntu を作成します。BIOS を設定して、USB から起動させれば Ubuntu を動かせる環境の完成です。

直接 PC から Ubuntu を起動させる

で「USB メモリ起動でもよいか」と思っていたのですが、実はUbuntuのインストーラーがUbuntuのデスクトップに配置されていたのですね。なるほど、そういう訳で、USB メモリから起動した Ubuntu から PC 本体に Ubuntu を入れます。

なんじゃ、つまりは2段階で Ubuntu を起動すればよかったわけです。

  1. 一旦、Windows から USB メモリ起動の Ubuntu を作成する
  2. USB メモリ起動の Ubuntu から PC 本体へ Ubuntu をインストールする

Windows からリモートデスクトップ接続する

Ubuntu へは Windows 11 からリモートデスクトップ接続ができます。以前は VNC でつなげていたのですが、リモートデスクトップ接続ができるようになって便利です。と言いますか、現在の Ubuntu 24.04 では VNC が無くなってリモートデスクトップ接続がデフォルトになっています。ややこしいですね。

第819回 Ubuntu 24.04 LTSのリモートデスクトップを深掘りする | gihyo.jp hうtps://gihyo.jp/admin/serial/01/ubuntu-recipe/0819

で、24.04 では、リモートデスクトップの設定場所が変わっていて「システム」→「RemoteDesktop」の中にあります。

「Desktop Sharing」と「リモートログイン」の2つのタブがあるのですが、Windowsから接続するリモートデスクトップは「リモートログイン」のほうです。ポート番号がRDPの3389番になっています。

もうひとつの「Desktop Sharing」のほうは画面共有方式のほうで、3390番になっています。通常はこっちのほうでつなげるようなのですが、Windows のほうは 3389ポートがデフォルトなので多分「リモートログイン」でつなげるのが正しそうです。実際に、それでしか繋がらないし。

何に使うかと言うと、ひとまずマイクラサーバーの移行と Blazor 本書きですね。

カテゴリー: 開発 | mini pc に Ubuntu 24.04 を入れる はコメントを受け付けていません

イーロン・マスクの示す「目標設定」と「権限移譲」について

とある Youtuber(かな?)の動画にイーロン・マスクの経営方法に関しての話がありました。そこで「権限移譲」の話がでてきたので、ちょっと記録をのこしておきます。

How Elon Musk Gets So Much Done – Marc Andreessen

ここで話している マーク・アンドリーセン氏は「イーロン・マスク氏と仕事をしたことはないが~」と明言しているので、実際のマスク氏がどういう考えで経営をしているのか不明ではあるのですが、アンドリーセン氏から見た良い点を語っているという視点でみてください。

マーク・アンドリーセンって名前を聞いたことがあるような無いような気がしていたのですが、モザイクやネットスケープの創始者プログラマですね。現在は投資活動が専門のようです。

https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%BC%E3%82%AF%E3%83%BB%E3%82%A2%E3%83%B3%E3%83%89%E3%83%AA%E3%83%BC%E3%82%BB%E3%83%B3

そういう意味ではプログラマ的な視点でもあるのかも。

目標設定

Youtubeの動画をざっと見たところ(字幕を日本語にして)、肝となるのがトップダウンによる明確な目標設定と、現場で自由に実行できるようにする権限移譲が重要です。

株式会社の最終目的は「儲けること」というな訳ですが、単純に「儲ける」にしても手段が色々あります。イーロン・マスク氏がどう考えているか分かりませんが、少なくとも赤字を垂れ流しながら福祉活動をするという訳ではなさそうです。そういう意味では一般的な株式会社ととしての目標設定(売上とか販売シェアとか)があるでしょう。

トップの仕事として何らかの具体的な数値目標を立てることも重要ではありますが、彼ほどたくさんの会社を持っていれば(これは孫正義氏もそうだと思うのですが)、手持ちの複数の会社を組み合わせてより利益を上げる方向を考えます。まあ、そのために大手の会社は買収をしたりグループ会社を作ったりするわけで、全体としての最適化を図るわけですね。

そう、部分最適化ではなくて全体最適化です。マスク氏が持つ会社あるいはマスク氏の周辺にあるアメリカ合衆国という国も含めて、マスク氏は最適化を図ろうと考えるわけです。このあたり、トランプ氏の思考回路も似た感じで、トランプ氏が持っている株や会社がうまく業績があがるようにアメリカ合衆国やその周辺の国を動かそうとします。実に分かりやすい「アメリカ第一主義」の発想です。この発想の良い悪いは別として、この発想の仕方からみると、マスク氏やトランプ氏の行動は予測しやすいと考えられます。特に、マスク氏のほうは自らの嫌悪感ではなく合理的に進める傾向が強いので、これも予測しやすいです。もちろん、予測しやすいからと言って同じようにできるわけではありません。同じようにできるのはマスク氏の胆力と献身性(自らの考えに献身するという意味で)に原動力があります。

そういうなかで手持ちの会社=つまりはカードを最適に動かすための「目標設定」を考えます。アンドリーセン氏が言う「ボトルネックを見つけるのうまい」というのはそういうところです。目標が明確になっているので、その障害となっているものを取り除く、あるいは弱いところにサポートしていく合理性をマスク氏は持っています。

これ、TOC(制約理論)の考え方そのものなんだけど、アンドリーセン氏や Youtube のインテビュアが知っているかわからないのですが、制約理論自体は MBA の教科書に載っている位なので、おそらく知っています。気づいているかどうかはわからないけど。

権限移譲

合理的な思考ができれば目標設定ができあがります。いや、合理的ではなくても目標設定ぐらいは誰しもができるでしょう。例えば、「来年の年末には宝くじ1億円をあてる」という具体的な目標を設定することは簡単です。これを達成するための手段が不可能ってだけで、具体的な目標を立てるのはそう難しくはありません。「売上○○億円を達成する」とか「アイドルになる」とか「今年は○○キロ減量する」とかいうのも似たような感じです。

要は、どうやって目標を達成するのか?という道筋を作らないといけないのです。

「今年は○○キロ減量する」という個人的な目標は自分で動かないといけないし、自分が動けばいいので達成は可能そうですね。NHKの減量コーナーは運動や諸々をみながら自らが動くことになります。

しかし、マスク氏のように多くの会社を持っている場合はどうでしょう?それぞれの会社に対して具体的な目標設定をしたところで、果たして彼はそれぞれの会社にいちいち口を出さないといけないのでしょうか?

実は、この手の組織論に堀江氏をはじめとする「フラットな組織論」というのが流行った時期があります。社長が社員という二階層だけにして、社長がひとりひとりの社員の活動をメールなどを受けてさばくという会社のシステムです。このフラットな組織がうまくいったのかどうかはよくわかりませんが、社長のマンパワーに依存しているのは確かなことです。社長の時間は24時間しかありませんから、どう効率よく動いても24時間しかありません。フラットな組織は中間層を排除してしまって、全体の組織が社長の手足のようにスピード感あふれる動きかたが出来る…というように見えますが、それは社長の24時間に達するまででしかありません。あるいは、社長の能力を会社は越えられないのです。ある意味、社長の能力までは会社は成長しますが、それ以上にはなりません。

まあ、そうなるので、一定の金銭を得た後は投資家は投資に走る(金が金を生むという仕組み)わけですが、マスク氏の場合は自社に投資をするという別な形に効率化を推し進めていきます。

つまりは、マスク氏が全体の最適化の図を描き、手持ちの会社の目標設定をした後は、その目標を達成するための手段を会社自体に「権限移譲」するわけです。目標が達成できればよいし、達成できなければ目標を達成するための手段を考えます。ボトルネックを一緒に探したり、そもそもの目標設定を達成可能なものに書き換えたりするわけです。

この権限移譲の考え方はリッツカールトンのクレドに近いです。ホテルのリッツカールトンでは、スタッフに相応の自由に活用できる金額を申し渡しています。お客を助けるためにスタッフの自由意志によって会社の予算が自由に使える訳です。ある程度の上限は決まっていますが、自由裁量の幅が他とは違います。このためにホテルに滞在しているお客に対してサービスの自由度が大きくなっています。

フラットな組織は一見、中間層がなくなって決断がスピーディになる(社長と社員が直結するので)ように見えますが、先に言ったように社長の24時間運用が上限になります。それ以上になると、社員からの問い合わせが待ち行列に入ってしまいますね。

ところが、リッツカールトン方式になるとホテルのスタッフの自由裁量によりホテルのオーナーや総支配人の許可を得ずに、お客へのサービスを提供できます。決裁権がスタッフ/社員側にあるというわけです。

これを大手の会社やグループ会社に拡大してみましょう。トップのオーナーであるマスク氏の意向をや目標設定ををクレドに書き込み、グループ会社の社員に渡したとしましょう。到底それはうまくいきそうにありません。社員が善人であるという前提も必要ではありますが、現場で動いている社員がうまく動けるようにマネジメントする層が必要なのです。この中間層が「知識創造企業」で云うところの「ミドル」という層です。中間管理職と言ってもいいし、プロジェクトマネージャと言ってもいいし、スクラムマスターと言ってもいいです。

つまりは現場が現場で動き、トップはトップで全体最適化を図るように目標設定をする。そして、中間のミドルマネジメント層がトップより「権限移譲」された決裁権などを利用して、現場の取り纏めや外渉などを行います。現場の人が外渉や調達までするのは大変ですからね。そこのあたりはPMBOKに書かれているところです。

中間層と現場の選定

目標設定と権限移譲の組み合わせなんだが、これには「きちんと仕事をする」という前提が必要になる。例えば「リモートで在宅勤務にしている社員がサボるのではないか?」とか「チームでのサボりをなくすために日報を提出させよう」とか考えてはいけません。というか、そいう社員やスタッフが社内に存在してはいけないのです。

なので、ある人にとっては「とてもそんな組織はうまくいかないよ」という見方もありますが、ある人にとっては「結果さえ出ればいいんだから、可能だよ」という見方もあります。でもって、マスク氏が選定しているのは後者なわけです。

これは組織論の話であって、人権だとか国民だとかという話ではありません。あくまで会社という組織つまりは中途採用などを含めて、なんらかの選定があって会社が成り立っているわけです。その選定さえた人材だけでグループ会社を作って、それに対して目標設定をして全体最適化をイーロン・マスク氏は廻しているわけです。

理屈はわかるし、うまくやればできそうでしょ?実際マスク氏はできているわけですが、私自身がその組織に入りたいかと言うと(入れるかと言う問題もあるけどw)、

という気持ちです。スターリンクもテスラも魅力的な商品ではあるけれど、そこで働きたいかどうかは別ですよね。日本の場合はもう少し別のやり方もあるし、大きな会社でなんやかやと中間層や現場で働きたいわけでもないし。ちょっとずつ首を突っ込んでは来たけど、もうちょっと別のやり方もあります。

とはいえ、アンドリーセン氏から見たマスク氏の経営術は実に合理的なもので、あるい意味でプログラマ的でありソフトウェアエンジニアとして共感できる部分が多いです。特にスペースXの開発アプローチは、従来のモックアップ&試験の繰り返し違い(実は、トヨタでも大量のモックアップを作る方式にシフトしているけど)、ソフトウェアテスト的にスクラッチビルドを高速に繰り返して発展させる成功例ですから。資金力があればこそなんですが。

参考文献

TOC(制約理論)やボトルネックの理解に

リッツカールトンのクレド、権限移譲の方法

スクラム、ミドル・マネジメントの考え方

確か、MBA マネジメントにCCPMとか制約理論が載っていたはず。

カテゴリー: 開発 | イーロン・マスクの示す「目標設定」と「権限移譲」について はコメントを受け付けていません

烈烈布神社に参拝して集団心理の毀損と進化に至る話

新年あけましておめでとう御座います。ぐらいは書いておこうと思いつつ、現代思想2025年1月版のロスト・セオリー(絶滅した理論)に興味をそそられたので記録しておきましょう。最近、ブログ書きに戻ろうとしているのはツイッターのX化もあるし、散漫に残しているだけではどこかに散ってしまいそうだからという理由もある。もちろん、以前と同じく「moonmile 〇〇」という形で Google で検索すれば自分のブログが引っかかるので、全文検索替わりになるというのもある。Google検索のAIはあいかわず当てにはならないのだけど、自分のブログの特殊なものも拾ってくれるのもいいのではないだろうか?

烈烈布神社に参拝する

年末年始に実家に帰ると近場の烈烈布神社に参拝することにしている。以前は、車で北海道神宮神宮まで行っていたのだが、父が亡くなってからは私自身が免許を持っていないし、まあ近場でよいだろうという感じになっている。

初詣の神社参拝は鉄道会社の宣伝という話もあるけど、それは遠地の観光地化された神社の話であって、近場の神社に参る場合にはそれ以前からある。どれ以前かは知らなけど、少なくとも明治以前も神社があったはずだし、初詣の習慣は江戸時代にもあっただろう。

初詣に行かないとダメというわけではない。別にいかなくてもいいのだが、ちょっとした切っ掛けがあるときには面倒でなければ行っておいたほうがよい。つまりは、

「今年は初詣に行かなかったから、この仕事がうまくいかなかったかも」

という憂いを避けるためである。「仕事」の部分は、学業でも受験でも就活でも構わない。これは、実際に子の大学生に言った話であるが、「それならば」という形で重い腰を上げさせることに成功している。罰があたるわけでもなく、ご利益があるわけでもなく、個人的な「憂い」を払拭するために初詣に行くのだ。

烈々布神社の歴史

烈々布神社の歴史であるが、当然のことながら明治以降である。函館の五稜郭があったり札幌の屯田兵があったりして、徐々に札幌の町を広げた結果が、今の烈々布神社ともいえる。

https://hokkaidojinjacho.jp/%E7%83%88%E3%80%85%E5%B8%83%E7%A5%9E%E7%A4%BE

天照の御霊がどれほど広く届くかわからないが(少なくとも日本全土には即なのかもしれない、よくわからんw)、菅原道真公も入っていてなんだかよくわからない感じになっている。ただし、氏子(たぶん、開拓民の子孫と思われる、かつ地元の企業)もそこそこいるので、神社としての体裁以上ものは備わっている。

ただし、見ての通り明治以降の建立なので、歴史的な価値はまるでない。神話的に意味もあるかどうかも微妙なところである。門前に建立されている石碑も昭和のものなので、比較的新しい。

しかし、なぜここに「初詣」することができるのか?というのを心理的に読み解いてみようというのが、今回のブログ記事の主旨である。そう、おわかりのように暇なのだ。

神社へのいたずら書きを考察する

神社の架空性を問うだけでは詰まらないので、去年あった靖国神社へのいたずら書きをあわせて考えてみよう。

靖国神社 落書き事件 14歳の中国人少年に逮捕状 落書き見つかった当日に中国帰国 | NHK | 事件 https://www3.nhk.or.jp/news/html/20241121/k10014645201000.html

「礼拝所不敬罪」とかにあたるらしいのだが、いわゆる公共物損壊の罪だろう。礼拝所不敬罪という意味だと、いわゆる尊属殺人を想起させるわけで、公共物としては神社仏閣であろうと通常の公共物(区役所とか公園とか)と同じ列に据えてもよいはずだ。しかし、なぜか、不敬罪という形でワンランク上の罪をかぶせようとしたがるし、一般的には不敬罪であろうという思い強い。私も直感的には不敬罪にあたるだろうと感じてしまう。

しかし、ちょっと考えなおしてみよう。不敬罪という言い方をするが、何に対して不敬なのだろうか?靖国神社自身に対してなのか、靖国神社で奉られている英霊に対してなのか、それとも靖国神社をたたえている人たちに対してなのか?ここを分解してみようという試みである。

靖国神社を烈々布神社に置き換えてみよう。烈々布神社にいたずら書きがされたときにどうなるだろう。一般的な神社仏閣に対していたずら書きをさえたときには、たしかに礼拝所という特別な場所(何に対して特別であるかは、後述する)への公共物損壊には違いないが、靖国神社ほど怒るとは思えないし、それほどニュースとして広まらないだろう。場合によっては、天照や道真公を毀損されたとも言えなくもないが、そこまで考えて怒る人は、烈々布神社の氏子ぐらいなものだろう。

靖国神社には氏子相当の人が多い(いわゆる、戦没者が安置されている、とされるので。戦没者でも安置されない場合もあるけど)と勘がられるので、氏子という意味では烈々布神社よりも多くてニュース性が高いかもしれない。しかし、靖国神社へのいたずら書きは単に氏子が多いという問題以外のところにある。つまり、別のものを毀損されたとほとんどの日本人が感じるからだ。もちろん、毀損されたと感じない日本人もいるわけで、今回はそれは例外としてとらえておく。まあ、ニュースになったという事実からして、それなりに「事件性」があるとということだ。

偶像崇拝と組織進化論

靖国神社が一般的な概念として偶像崇拝であることは間違いない。仏教も仏陀の教えそのものだけでなく仏像をあがめることも多いので偶像崇拝である。イスラム教ではないが、偶像にはちょっとした価値がでてきてしまう。偶像そのものに価値がでてきてしまう。

偶像としては芸術的な価値もあるのだが、ここでは靖国神社自身の価値を考えてみよう。狭い範囲でいえば、いたずら書きされた石碑そのものと言ってよい。

現代芸術もそうだが、芸術対象や宗教的な対象そのものには価値がない。話がずれるが、「壺」だった、壺自身に価値があるわけではない(価値があるとして売られているが)。とある宗教的な意味(芸術的でもいいし、かつての持ち主でもいいし、芸術家自身がつけた解釈自身でもよい)。ときどき、Xに流れてくる「バナナをキャンバスに貼り付けた」だけでも構わない。金銭的な価値というものはそういうものだし、それぐらいの価値しかない。

じゃあ、石碑自身には価値がないが、これにいたずら書きをされたときに、何が毀損されるかというと、石碑をあがめている人達になる。いわゆる、氏子が最初にあがるわけだが、靖国神社の場合は氏子だけに限らない。いわゆる、右翼的な積極的な靖国崇拝者もいれば、なんちゃってネット右翼のコスプレ団体かもしれないし、戦時を抜けてきた老人かもしれないし、漠然と日本の神社のくくりとして靖国神社を毀損されたという漠然とした厭らしさかもしれない。

ここでは、より消極的な「漠然とした厭らしさ」に焦点をあてていこう。

普段は積極的に靖国神社に行こうとは思わないが、靖国神社の石碑にいたずら書きをされるとちょっと嫌な感じがする、という程度のことである。でも、この「ちょっと嫌な感じがする」はどこからくるのだろうか?

同じように、たいていの日本人が知らない烈烈布神社の何かの石碑に同じようにいたずら書きをされたと仮定しよう。そうすると、感じるだろうか?別になんとも感じない場合もあるけど、ちょっと嫌な感じがする人が多いと思う(ここはアンケートなどでフィールド調査しないといけないところだが、思考実験で済ますw)

つまり、日常の中で特に意識はしていないが、神社というものが毀損されるとちょっと嫌な感じがするわけである。とくに「神社」を崇拝しているわけではない(崇拝する場合もあるけど)が、漠然とした偶像崇拝を神社という形で存在させることができるぐらいには許容しているわけである。同じものに、神社の鳥居がある。これはよく言われるように、小便をさせない場所に鳥居の記号を書いて避けさせるぐらいいは、呪術的な効果がある。そう、この呪術的な部分と「ちょっと嫌な感じがする」というのは同根であるのだ。

神社あるいは仏閣をそこかしこに配置させるだけの心の余裕を日本人は持ち続け現在にいたる。もちろん、明治の初期の廃仏毀釈があるので一筋縄ではいかないが、単純化して現在では神社仏閣を毀損しない程度の集団に日本はなっている、ということが靖国神社のいたずら書きの事件から読み取ることができる。

そこで、日本人の魂とか言ってしまうと速攻陰謀論になってしまうので、組織進化学の話につなげていこう。組織進化という視点では、いっていの集団には一定のゆるいルールが存在し、そのルールを尊重する人たちが集まって組織を担っているのである。「ゆるいルール」というのが重要で、これが厳しい罰則付きのルールであると村八分や外乱の取り込みができなくなって組織を継続して存続させることができなくなってしまう。「ゆるいルール」というのは、組織外にあるルールさえも少し取り込むことができるという緩さ必要になる。

つまりは、日本という組織(国ではなく、自分は日本人であるという意図的な従属の関係?あるいは承認意識?)をまとめているものひとつとして、「神社に対してなにかいたずらをしてはいけない」という共通認識があり、それが緩いルールになっていて、不敬罪というのを認める形になってるということである。「不敬罪」というのが、昔の尊属殺人罪ほど強い印象を与えないのはそのためだろう。尊属殺人は儒教の教えもあるだろうが、西洋でのエディプス・コンプレックス論にもでてくるので、東洋に限った話ではない。

おまけ、男女という枠組みを外す

ここでは「女性への痴漢」という言葉を出したが、言い直せば「人への痴漢」である。女性への痴漢があれば、男性への痴漢もある、さらにその中間もあるのだから、性別や年齢に限らず「人への痴漢」行為はあかんだろう、というのが共通認識になればよいのだ。

だから、Xでよく出てくる「男が~」「女が~」という言葉に敏感に反応してしまいがちなのは、そこが男性あるいは女性というカテゴリー/セグメントに無意識に分けてしまっているのが問題なのであって、これをヒトというひとつのカテゴリにしてしまうと問題が少なくなる。このあたりは類型論と特性論(精神分析と臨床心理学)に属するので、日を改めて書くことにしよう。

カテゴリー: 開発 | 烈烈布神社に参拝して集団心理の毀損と進化に至る話 はコメントを受け付けていません

年末なので五行思想でコンピュータサイエンスを解説してみよう

もともとの発端はここから。五芒星か六芒星が一部で流行っているらしいので、どうせならば本格的にやりましょう、という発想。

実は、個人的に陰陽道とか五行思想には詳しい(趣味レベルですが)ので、けっこうイケる感じではあります。

ざっと、次のところまでつなげておきましょう。

参考文献

いきなり本格的なものを読むとつらいので、次の2冊からスタートするといいです。

シム・フースイは風水をテーマにしたミステリー小説です。荒俣宏が書いているので、安全に風水ワールドを観察できます。

禁止目録は五行機関がでてくるところまででいいです。アニメの第1シーズンだけでもいいけど、基本的な用語がでてきるので、それでも十分だったりします。

五行思想

いきなり、陰陽道につながっても怪しいだけなので、鍼灸のところからスタートしましょう。安倍晴明とか陰陽道からスタートしてしまうと、単なる幻魔大戦の雰囲気になってしまうので(ラノベ的にはそれでもよいけど)、もっと現実的に五行が使われているところからいきます。

要するに、『「木・火・土・金・水」という「五行」によって』のところがキーポイントで、「木火土金水」という5つの要素で東洋医学のツボや健康などを見ていきます。「木火土金水」は、色でいれば「緑赤黄白黒」か「青赤黄白黒」です。古来より緑/青が混在されるので、どちらでも構いません。

いわゆる、三原色に白と黒を混ぜて5つにするわけですね。光の三原色、ものの色の三原色とありますが、とにかく5つになることが重要です。

相合・相克とありますが、これもどうということはありません。理論的な根拠はなくて、あてはめて後付けしているだけです。あるいは、相合・相克っぽいものを、五行にあてはめてなにかとこじつけをします。

これをコンピュータにあてはめると、このようになります。

よく、コンピューターサイエンスでは、

  • 演算装置(CPU)
  • メモリ
  • 入力装置(キーボード、マウス)
  • 出力装置(モニタ、プリンタ)
  • 補助記憶装置(HDD、SSD、データベース)

が使われます。最近はこれにネットワークを付け加えて六芒星…じゃなくて、6個の分野に分けることが多いのですが、ここは五行思想に従って5つのまま使いましょう。

なんとなく、相合・相克ができたら完成です!

五行大儀

この適当に5つに分けるというのは、私のオリジナルではありません。実は「五行大儀」(あるいは五行大義)という本に書いてあります。

なにかと、物事を5つに分けて分類すると便利ですというパタン・ランゲージみたいな本です。

先の「木火土金水」だけでなくて、色とか味とか様々なものを5つに分類します。5という家数に特に意味があるわけではありません。慣習的に5つに分けるという話です。

なので、方角であっても「東西南北」の4つに「中央」を加えて5つにするとか、味を5味にするとか(甘味、酸味、塩味、苦味、うま味)のように分けるとかします。味の場合は、先に五味があって、味蕾を探すという逆転現象が起こっています。5つ分ける元ネタはだいたいこれが原点です。戦隊もののゴレンジャーとかもそれですね。

陰陽道と易経

陰陽道は「陰」と「陽」を用いて2つに分類するところからスタートします。太極図が示すように陰陽は二つで一体であるし、どちらが上とか下とかいうわけではありません。

陰陽思想自体は世界各国にどこにでもあります。男女であったり性器の形であったり、白と黒であったり、真偽(True/False)であったり、二値のあらゆるものは陰陽思想が発祥です。

この事象を陰陽/正負/真偽にわけて二分岐させたものが、陰陽道であったり易経であったりします。いわゆる占いですね。何かの事象に対して、判断をYesとNoに分けて考えるわけです。何故なに思考は5行思想にあわせて、5回やることにしていますが。易経の六十四卦は2の6条で6回分岐します。これは、卦を3本と3本に分けて混ぜるので計6本になるわけですね。

そんなわけで、易経では未来を64分割して予想します。この考えた方はリスク管理の基本でもあります。リスクを判断するときに発生する割合をYes/Noなどで分けていって、最終的に5,6回ほど判断していけばいいわけで、最終的に大きなリスクやきわめて高い確率で起こる事象ということが分かってきます。同じパターンでプロジェクトの予想もできます。ぜひ、易経をプロジェクト管理に利用してみてください。

さらに、陰陽道では方角の示すことができるので、先の五行コンピュータサイエンスと合わせると、どの部位にトラブルが発生しそうか、あるいは設計に力をいれないといけないかを確認できます。これにより、禁書目録などであるように、玄武などの色を配置してトラブルをさけたりモジュールの強化をすることができますね。これも陰陽道の盤を買って試してみてください。

老子

老子の道教も外せません。かつて、物理学者が道教にはまってしまったように、コンピュータサイエンスを道教に嵌めるのも容易です。

量子力学のスピンやカラー、チャームなどの用語は道教が由来ですし、道教が先の発見者…ということにしておきましょう。ファンタジー味が増すので。

攻殻機動隊の第1巻の最後に出てくるスピンの話とか、仙術超攻殻ORION」に出てくるアマテラスなどの登場人物も無縁ではありません。ぜひ、古事記を読み通してください。日本書紀のほうはまあいいです。ファンタジー味が少ないので。

そんなわけで、道教のタオイズムは物理業界では一定のブームでした。いまはどうかわからないのですが、50歳オーバーの人には非常になじみが強いし、それ以前の物理学者は実際にインドに行って修行をしてしまうぐらいのでオカルトな世界に足を突っ込んでいるので、いまの陰謀論やらなんたらを笑えません。

老子を読むと、色即是空とか、陰陽の玄とか出てくるのでぜひ活用してみましょう。

あと、儒教由来の孔子に対抗するために、老子の道教を持っておくと便利です。先祖崇拝の儒教はなかなか呪縛が多いので、対抗で道教を持ち出すといいです。

具体的にコンピュータサイエンスに活用する例

基本章情報処理的に五行思想や易経を使ってみましょう。先に例を出した演算装置のあてはめやプロジェクト管理だけでなく、いろいろなところに活用…といいますか、こじつけができますw

  • プロジェクト計画を立てるとき、要件定義/設計/実装/試験/運用の5つに分ける
  • コードを書くときに、ベースとなる「土」の部分の共通基盤/ライブラリから作り始める
  • 「土」を肥沃にするためのは、人を教育する「木」が必要となる
  • 五行の「金」は必要ですね。まさしく予算!
  • イテレーション開発のPDCAに対して、「何か」を加えて5つにしいて、サイクルにする。
  • 陰陽の遺伝子を螺旋にしてイテレーション開発する。イテレーションの形は、つまりは螺旋でドリルで、グレンラガンである!

いかがでしょう?いろいろ幅が広がりますよ。

余談ですが、サーバーマシンには落ちないように交通安全のお札を張っておくとよいですよ。

カテゴリー: 開発 | 年末なので五行思想でコンピュータサイエンスを解説してみよう はコメントを受け付けていません

ソフトウェア開発で「生産性」を使うときに注意すること

このあたりの生産性の問題は、リモートワークと社内出社の双方に意見の食い違いがあり、佐藤氏のいう「誰かが顧客要件をキチンとまとめ~」に掛かってきているのかな、というのがある。

著作を出しているので、こっちも踏まえて議論を残しておこう。

主に議論になりそうなのは、第3章からの具体的な開発プロジェクトの話になる。ここの中でリモートとか設計とかコミュニケーションの話がでてくるので、それでよいだろう。

第三部では「現場で役に立つ周辺知識」としてマネジメントの話がでてくる。

  • 第9章 チームビルディング
  • 第10章 設計
  • 第11章 Gitによるリポジトリ管理

ということで前半の技術的な要素(ReactやDjango)とは違い、それらのWebアプリを具体的にどのように会社で開発しているのか?という紹介に近いものになる。

書籍の中には、アジャイル開発、イテレーション開発のような一般的なソフトウェア開発の用語はでてきるのだが「スクラム」や「PMBOK」のような用語はでてこない。これはあえて外したのか、既存のスクラムとはやり方が異なるために「スクラム」という用語を外したのかどうかはわからない。が、第9章や第10章を読む限り、

  • 開発自体はアジャイル開発でやっている模様
  • 顧客とのやり取りやプロジェクトメンバとの情報共有のため文書を積極的に作っている
  • 実際のタスク管理や進捗管理はチケット方式を使っている模様
  • プロジェクトメンバは5名程度で、単独ではない。あるいは大人数(100名とか)ではない。

ということがわかる。

一般的にアジャイル開発でのスクラムやXPなどがうまく回る人数として5~10名程度というものがある。それ以上になると、スクラムチームを分割して別途プロダクトオーナー(社内であればプロダクト・マネージャとか)が担うということなる。これは社内開発=製品開発なのか、受託開発を含めた請負であるのかにもよる。また、本格的な顧客参加型のスクラムチームであるのかにも依るだろう。

なので、「実装に学ぶフルスタック~」にあるソフトウェア開発が適当であるかどうかは、時と場合による。逆に言えば、株式会社オープントーンでは、この方式でうまくいっているという事例となる。

「誰かが顧客要件をキチンとまとめ~」の部分の生産性を考える

先のツイートから伺い知るに、既にチケット化されているものに対して自宅などを使ったリモート環境ではうまく生産性を上げることはできるが、それ依然のチケット化する工程において(設計や要件定義など?)ではリモートワークでは難しいのではないか?という話だろう。第9,10章を読むと、「他メンバーの課題・問題を感知しにくくなる」や「リモートでは仕様書の文書化を意識的に取り組む必要ある」という書き方があるので、プロジェクト内での情報共有や相互のサポートに難点が感じられたのであろう。また、「タスクマネジメントしづらい」という点を挙げていて、手が空いている人にタスクをうまく割り振りにくいという書き方もされている。つまりは、暇な人と忙しい人の見わけがリモートワークでは見つけづらいという難点をあげている。

ここの点からいえば、チケット駆動であれば本日こなすチケットを自らが取りに行くという方式がとられるし、スクラムであればスクラムミーティングというものが存在する。リーダーあるいはマネージャがタスクを割り振るのではなく、メンバー自らがタスクを取りに行くのだ。このあたり、スクラムの手法に沿っていないゆえの懸念点のような気もするのが、うまくいっているのであれば別に大丈夫なのだ。

論点は、それ以前のチケットを作るときの問題となるだろう。

顧客要件をまとめる、おそらく要件定義をまとめたり設計をまとめたりした段階で、WBSに落としていると思われる。この割り振りを誰がするのか?という話になると思うのだが、一般的なアジャイル開発(特にスクラム)の場合は、

  • 顧客の達成目標がプロダクトオーナー=顧客自身が立てる
  • スクラムマスターが、達成目標を適宜ピックアップして、スプリントする
  • スプリントの中で、チームのメンバーがタスクに落とす

という手順になる。なので、チケット(あるいはWBS)に落とすのはメンバー自身だし、つまりは顧客要件=達成目標をブレークダウンするのは、スクラムマスターとメンバーの共同作業となる。

が、先のようにマネージャが顧客の達成目標(つまりは要件定義など)をブレークダウンしようとすると、そのWBSを誰がやるのか?=マネージャがやる、WBSをどうやって計画通りに割り振るのか=マネージャがやる、というスタイルにならざるを得ず、そのために「誰かが顧客要件をキチンとまとめ~」という誰か=マネージャという主張となってしまう。

どうやら、このツイートを受け取った開発者(マネージャも含む?)の意見が分かれるのは、この部分で、

  • チケットはマネージャが作成し、メンバーに割り振る
  • 達成目標はメンバーがブレークダウンして、メンバー自身がチケットを受け取る

という開発スタイルの違いに他ならない。

ゆえに、そこの「生産性」も違ってしまうのだ。

では、プログラマ自身の生産性はどうなのか?

プログラマはプログラムを書くことだけが仕事ではないが、主な仕事はプログラムを書くことだ。昨今では、いろいろな仕事を平行で動かすことも必要なのだが、まあ、最終的にコードを書かないとソフトウェアというものは動かないのは確かだ。

まあ、例外的にノーコードっていう方法もあるけど、それはまた別の機会に。

で、私のツイートした「正直言うと~」の部分を解説しておこう。要するに、ソフトウェア開発のスタイルで、一番高速にモノができあがるのは「ウォーターフォール開発/計画駆動」であることを忘れてはいけない。これには異論があるだろうが、つまりは

  • 事前に完全な計画ができあがること
  • 計画通りのタスクを分割できること
  • タスクは計画通りに進み、手戻りや遅延がないこと

が、最高速にプロダクトができあがっていく計画駆動の条件となる。つまりは、自動車工場におけるオートメーションをソフトウェア開発に応用すればよい。ソフトウェア開発の大量生産工場のできあがりである!

のだが、そんなことは不可能だ。ということは皆わかっている。今では皆わかっているが、かつてはそうしていたのだ。丁寧な設計書や丁寧なフローチャートや綿密なレビューを繰り返していたのだ。

で、実際のところ、長期では難しいのが1週間程度あるいは2,3日程度の短期間であれば、この計画駆動は実に高速に動く。

これが「正直に言うと~」の前半の部分である。

後半の部分は、実際このようなキリキリに詰めた状態だと、うまくいくのいくのだが、非常に疲れるのである。疲労困憊だし、何度も続けてできるわけではない。最終的な納品直前に馬鹿力を発揮できるぐらいである。

なので、トップスピードを保つことはほとんどやらない。特にアクセルを踏むが、たいていの場合は、ブレーキのほうを踏んだままだ…と前に進まないので、オートマの自動走行位のスピードの気持ちでやることが多い。

それって、生産性が悪いんじゃないですかね?という意見もあるだろうが、長期的に見ればこのほうが生産性がよいのだ。体の故障は少ないし、他の人の気配り(手伝いやアイデアだしなど)の余裕ができる。つまり「ゆとりの法則」ができるわけだ。きちきちの作業をやるだけでは、ピースは全く動かなくなっていまう。ある程度の余裕がないとチームはうまく動かない。

わたしの場合は、フリーで仕事を受けることになるので、多数の仕事が平行で走る。シングルタスクの最速スピードよりもマルチタスクのスレッド操作のほうが遅くなるのは IT 屋では周知の事実だと思う。思うが、実際のところは

  • お客からの回答待ちなどで、こっちに待ち時間が発生する
  • 開発が先にできあがっても、お客の都合でリリースなどで待たされることが多い
  • 協力しているメンバーの進捗スピードなどで、待たされることも多い

ということで、結構な確率で「待ち」が挟まってくる。この場合、会社に居れば、待ちの状態でぼんやりと椅子に座っているのも可能(だとまずいんだけど)なのだが、リモートワークをやっていると、じゃあ気分を変えて別のに手をつけておくか、という形にできるわけだ。

ある程度、開発力があればシングルタスクで仕事をやるよりも、ある程度のマルチタスクのほうが作業効率がよいことがわかるだろう。新人レベルならばひとつの仕事べったりのほうがいいだろうが、ある程度年季が入ったプログラマならば、マルチでやらないとちょっと無駄が多いわけですよ。

アジャイル開発スクラムやチケット駆動、PMBOKの基本的なところは下記の本に書いたので、それを入口にして本格的なスクラムやPMBOKの書籍にあたってみてください。もちろん、いきなり「アジャイル開発スクラム」にあたるのもよいです。

カテゴリー: 開発 | ソフトウェア開発で「生産性」を使うときに注意すること はコメントを受け付けていません

GoFとMVCパターンと、ソフトウェア工学のデザインパターンのその後を私見で

せっかくなので、ソフトウェア工学における私がみつけたパターンをいくつか書いておきます。

原著の「Design Patterns」

いわゆる「GoF本」です。「デザパタ」と略されることもあるのですが、巷のデザインパターンの本と区別が付きづらいので「GoF本」で通しています。

日本語訳でもいいのですが、手元には原著のKindle版があります。Kindleってことは、だいぶん後に買ったので、当時(1994年)に読んだわけではありません。日本でのデザインパターンブームが2000年頃(だったっけ?)なので、原著(あるいは訳本)を読まないままデザインパターンを知った或いは覚えた人も多いと思います。私の入り口もそれですね。

ただ、それだけだとコード寄りになってしまうので、いったん原著にあたっておくといいです。が、中身がC++なのでC++が読めないと辛いです。確か、Javaへの翻訳本もあるはずなのですが、GoF本の発端自体が、C++あるいはMVCパターンによるアプリケーション開発の現場からの抽出なので、当時のC++の状況がわからないと読み込めません。いまのJavaやC#だと、GoFの各種パターンが言語仕様に組み込まれた状態になってしまっているので、そのまま読んでも「何でこんなややこしいことになっているの?」としか見えません。

2016年の自分のブログ記事ですが ふと GoF のデザインパターンを再考しておく で GoF パターンを C# で検証しなおしたものがあります。

同時期の Smalltalk best practice patterns

先の GoF 本と同時期に出たケント・ベック氏の書いた本です。買ったのは随分後なので、当時がどういう状況だったのかはよくわかりません。結構高いので、参考までに持っておくというので良いです。

GoF 本と同じく「パターン」と書かれていますが、GoF とは異なり、アレクサンダー氏の「パタン・ランゲージ」を元にしている訳ではありません。UMLのクラス図もありません。コードがSmalltalkで書かれているので、これに慣れていないと読み取れません。

という難点がありますが、ケント・ベックが書いたということと、オブジェクト指向(クラス構造であれメッセージングであれ)を語る上で Smalltalk は外せないので持っています。持っていますが、私としては Smalltalk でオブジェクト指向を語る気はありません。どちらかというと、クラス構造としてのオブジェクト指向(C++やJavaなど)寄りのところで過ごして来たので、別の流れもあるということですね。

ちなみに、メッセージングのほうのオブジェクト指向は Web APIの呼び出しにてかなり実現されていると考えられます。HTTPプロトコルのステータス無し、Cookie等によるステータスの付与、物理的時間的に遠地にあるファンクションのコールなど、Smalltalk の語るオブジェクト指向が別系統でも実現されつつあるかなぁと。つーか、それで十分ではないか、その先に行きましょうよ、って感じですね。

ちなみにその先のパターンに関しては後述します。

追記しておくと、冒頭にある MVCパターンの論文はここにあります。

https://ics.uci.edu/~dfredmil/ics227-SQ04/papers/KrasnerPope88.pdf

大本のデザインパターンとしての「パタン・ランゲージ」

デザインパターンブームの元ネタの「パタン・ランゲージ」です。ご存じ、アレグザンダー氏の著書で高いので、ひと苦労です。しかも、コードじゃなくて建築の話です。

これも2000年のデザインパターンブームのときには買わなかったのですが、のちに購入しました。やっぱり原点をあたってみないとわからないということで。

この中で書かれていることから読み取ると、

パターンの原点であるアレクサンダー著「パタン・ランゲージ」では、現在ある構造物(都市とか商店街とか)を観察すると、部分的な構造物が組み合わさって現在の良い状態があることわかる。逆に、部品の良い組み合わせ、つまりパターンを作っておけば、良い結果を得られやすいのではないか?という発想です。
なので、当時のMVC パターンで作られた数々の完成物、更に成功している製品を眺めた時に、内部構造としてGoFで書かれたようなパターンを見出す事ができた、故にGoFパターンを使うと成功しやすい、という帰納的解法と思われます。

というのが私の結論です。

なので、建築のパターンやソフトウェア工学のパターンを、構造物(あるいはクラス)作成の効率化や、アプリオリ的に構造物とその組み合わせ(≒パターン)をしておけば良い結果が得られる、という思いこみは間違いです。

歴史的に良い結果(建造物の寿命や商店街の活性化、ソフトウェアの寿命など)を得られてきたものを分解してみると、ところどころに良いパターンが潜んでいるということです。この良いパターンや組み合わせを使うことによって、最終的に良い結果が得られる可能性が高いということですね。ここは帰納法的な思考になります。「帰納法」を出して来たのは、ちょうど統計学再入門を読んでいるところなので、当時は「経験上、よくわからないがうまくいくパターンがあるので、温故知新を用いて使ってみよう」という具合です。

私が、よく先人の知恵とか温故知新とか書くのはそれです。

GoF 本あるいはデザインパターンのその先へ

ここから本題です。いまさら GoF のパターンを学んでも仕方がないです。というか鵜呑みにしても、先に書いた通りプログラム言語仕様の中に組み込まれているものが多くて、原著を読んで C++ で読み込んでもたいして知識が得られるわけではありません。

個人的には、組み込みシステムや別途スマホアプリに応用が効くので、ひと通り知っておいて設計に活かすのがベターなのですが、C++ や Smalltalk を学び直して読み込む必要はないかなぁと思っています。

デザインパターンというと「アナリシスパターン」や「ドメイン駆動設計」あたりに走ってしまいがちになるのですが、実はもっとその先があります。

というかですね。アレクサンダーの著書である「パタン・ランゲージ」の派生を追っていくと、他の分野にも応用できると主張されている節がある。

実際、アレグサンダー自身が当時のソフトウェア業界(1994年)に講演をしているので、そこの別業界としての接点があります。

じゃあ、GoF の各種のコードあるいは周辺のデザインパターンのコードではなくて、もっと広い意味で都市計画とか商店街とか人の導線とかいう意味で、ソフトウェア工学に「パターン」は何を与えていたかというと、

「Garbage Collection」では、ガベージコレクションの世代交代が実装されている。今だとGC では当たり前なんだけど、単純な GC だと頻繁に配置側が発生していまうので、利用している世代を分ける。いわゆる、利用する頻度によって分類するという分け方です。これは、キャッシュとか予約発券システムとかに使われているパターン。 単純にキャッシュするのではなく、頻度に対して分布を作るところにパターンがある。

画像の深層学習で一掃されてしまったが「Toward Category-Lravel Object Recognition」というアイデアがあった。特徴量を導き出して、相互の距離を計測して画像認識に使う技で Google とかもやっていました。結果的に、隠れ層を使った7層程度の深層学習(Deep Learning)のほうが効率が良いことになったので、このあたりの実装はなくなってしまったのだが、特徴量的な考え方は統計学とか主要因分析にも応用されているし(おそらく、この当時の画像認識の研究が統計学の応用だろうし)、その後の報酬関数(フィードバックシステム)のパターンがこの当時からあります。生成AIもこのあたりの延長と言える。

こちらは工業デザインのパターンということで、ノーマン著「誰のためのデザイン」。現在は認知科学として捉えるべきなのか?単なるエモーショナルな流行デザインに過ぎないのか不明なんところではあるけど(いわゆるグローバルデザインの話になる)、それでも一種のパターンに従えば、利用者の落とし穴を防ぐことができる。これこそパターン・ランゲージの応用例と言える。
ソフトウェア工学として、一時期UIデザインにも取り入られた筈なのだが、iOS7からのフラットデザインから以降、それが本質的に誰のためのデザインなのかわからなくなっているところがある。個人的には、高齢者カスタムのかんたんスマホのUIとかはいいと思うんですけどね。設定がごちゃごちゃなのはいただけないが、ガラケーっぽいUIに揃えてあるのは、ガラケー主流だった高齢者にはよいデザインだと思う。誰が?という意味では、「高齢者」が使うわけですから。

「コンピュータの中の人口社会」に書かれているエージェントシステムは、ソフトウェア工学のなかで MVC パターンと同じぐらい重要なデザインパターンと思われる。全体を統括的に扱うのではなく、個々のオブジェクトを独立してプロセスやスレッドで動かすというパターン。まさしく、オブジェクト指向による「オブジェクト」の実現なわけだが、それぞれを独立して動かすことにより、相互の影響を環境値として与えることができるのがミソ。いわゆる、品質工学などでいう外乱を内部特性を区別できるシステムである。

エージェントシステムの発想は遺伝的プログラミングとか並列処理とかいろいろ発想が効くので知っておくとよいパターンです。

まとめとしてのパターン

そんな訳で、ソフトウェアにおけるパターンはなにもコーディングに限らないので、システム全体の構築やユーザーの利用動向、UIの作成、PMBOKによるプロジェクト管理、DevOpsやテスト駆動による価値の制御(スループットや計測)などいろいろな場面でパターンがあります。細かい単位のプラクティスではなくて、大局としてのパターン、つまりは軍事ドクトリンに近いのです。みなさま、応用しては如何でしょうか?

といういうブログパターンで〆てみるテスト。

カテゴリー: 開発 | GoFとMVCパターンと、ソフトウェア工学のデザインパターンのその後を私見で はコメントを受け付けていません

GPT4o に技術マニュアルから実装コードを模索する話(C2340R5でデバイス名を変更編)

生成AIを使ってコード生成をし始めて半年ぐらい経つわけですが、「いろいろなコード生成が自動的にできるよ!」という話よりも、実際に目の前のコードをどうやって生成していくのか?うまく動くようにAIが生成したコードをどうやって人(=自分)が修正していくのか?がプログラマには当面の課題になります。

まあ、どうやってChatGPTあるいはCopilotを使って、コード書きを促進させるか?という実例ですね。WEB アプリケーションのように巷に情報が溢れているならばまだしも、組み込みのような情報が閉鎖的(でもないのだけど)で少ない場合にはどうするのか?という例でもあります。実際のところ、ブロック崩しとか顔認識AIのような既にコードがある場合にはそれをコピペすれば言い訳で、ほどよく WEB サイトに散らばっているならば大丈夫なんですが、完全に未知なコード(少なくとも自分にとっては「未知」の状態)の場合には、ちょっと困るわけです。

C2340R5でBLEのデバイス名を変更したい

未知の人には完全に未知だと思います。まずは、「C2340R5」ってのが何なのかを調べないといけません。BLEを知っていればいいのだけど、デバイス名は何なのか、ぐらいは知っておいて欲しいものですが、まあ、そこからスタートしましょう。

ちなみに、CC2340R5 ってのは Bluetooth が入っている組み込み用のボードですね。ESP32 が入っている M5Stack 系で Bluetooth/BLE を扱えば結構情報が多いのですが、Texas Insturuments の CC23xx 系のボードだと情報が少ないのです。まあ、フォーラムがあるだけマシなのと、マニュアルが揃っているのでなんとかなりそうではあります。

https://www.ti.com/product/CC2340R5

実は SimpleLink というライブラリが TI から提供されていて、これに結構書いてあります。書いてはあるのですが、じゃあ「BLEのデバイス名を変更する」方法は書いていないのが難点ではあります(ほんとうのところ、書いていないのではなくて、デバイス名を変更する方法がない、ということなのですが)。

SWCU193 User guide | TI.com https://www.ti.com/document-viewer/lit/html/swcu193

初手は素直に聞いてみる

AIに質問をするときに「目的」と「手段」をうまく切り分けないと変な回答が出てくることが多いのですが、ひとまず初手としては素直に聞いてみるのがいちばんです。ぴったりとした答えがでてくればそれでよいし、まあ違ったとしたらそれを踏み台にして探索を続ければいいのです。

実はですね、この模索を再現しようと思って、初手に「C2340R5でBLEのデバイス名を変更したい」を再び入力したら、正解が出てくるんですよ。実は、SimpleLink のライブラリには動的にデバイス名を変更する API がなくて、BLE のアドバタイズ部分を再起動するしかありません。しかも配信するデバイス名は上記のように直書きになっているので、自前でバイト単位で書き出さなければ(memcpy使うけど)いけないのです。

まあ、このコードを見て「デバイス名が変更できる」と分かるには、その模索がってこそなのですが。

以下は、以前出した間違ったChatGTPの回答を上げておきます。

ChatGPT にマニュアルの PDF を入れる

ChatGPT にはファイルアップロードして、その中を優先的に探索してくれる機能があるので、それを使います。

初期値は英語になっているようですが、次のプロンプトで「日本語で。」というと日本語が主になります。

いろいろと探索する

前回の場合は「simplelink でデバイス名を変更するには?」で質問しています。この手の質問は、初手は漠然とした「目的」を示したほうがよいです。最終的には実装するための「手段」を探すことになるのですが、いきなり手段を示してしまうと、それ以外の手段を探すのが難しくなりがちです(人間の頭的に)。なので、最初は何もわからない振りをして、ChatGPTに尋ね、少し手間がかかりますが掘り込み方式で進めます。

  • TGAP_DEVICE_NAME という定義はどこにもない

  • GGS_DEVICE_NAME_ATT はあるが、デバイス名は変更されない。

  • GAPRole_SetParameter は存在しない。

  • BLEAppUtil_setAdvData は存在していない。

そんな訳で、なかなか正解に辿り着けません。実は、最初の質問ででてきたscanRespDataの書き換えが正解で、なんとか API 経由で書き換えようとしていたのですが、そんな API は存在しなくて、直接データを書き換えて BLEAppUtil_advStart で BLE のアドバタイズを再起動しないといけないのです。

仕方がないので、初期設定されているアドバタイズデータを書き換える

実は TI のプログラムは Code Composer Studio の *.syscfg というファイルを使っています。これが設定ファイルになっていて、各種設定をコード出力しているのです。Code Composer Studio でデバイス名(ble.deviceName)を書き換えると、うまく書き換わるわけで、そのあたりから更にコードを見ていきます。

最終的には BLEAppUtil_AdvInit_t 構造体があって、ここで初期設定されているのが肝です。コメントを見ると Sysconfig から変換されていることがわかるし、const struct になっているので、実にそれっぽいです。

//! Advertise param, needed for each advertise set, Generate by Sysconfig
const BLEAppUtil_AdvInit_t advSetInitParamsSet_1 =
{
    /* Advertise data and length */
    .advDataLen        = sizeof(advData1),
    .advData           = advData1,

    /* Scan respond data and length */
    .scanRespDataLen   = sizeof(scanResData1),
    .scanRespData      = scanResData1,

    .advParam          = &advParams1
};

まずは、const のままでは書き換えられないのでコードを修正します。

//! Advertise param, needed for each advertise set, Generate by Sysconfig
BLEAppUtil_AdvInit_t advSetInitParamsSet_1 =
{
    /* Advertise data and length */
    .advDataLen        = sizeof(advData1),
    .advData           = advData1,

    /* Scan respond data and length */
    .scanRespDataLen   = sizeof(scanResData1),
    .scanRespData      = scanResData1,

    .advParam          = &advParams1
};

その後に、appMain 関数の先頭で advDataLen と advData を書き換えます。

    // デバイス名の変更
    static uint8_t deviceName[] = "BLE-TEST";

    uint8_t deviceNameLen = strlen((const char*)deviceName);
    static uint8_t scanResData[32];
    uint8_t scanResDataLen = 0;
    scanResData[0] = strlen((const char*)deviceName) + 1;
    scanResData[1] = GAP_ADTYPE_LOCAL_NAME_COMPLETE;
    memcpy(&scanResData[2], deviceName, deviceNameLen);
    scanResData[2+deviceNameLen] = 0x02;
    scanResData[3+deviceNameLen] = GAP_ADTYPE_POWER_LEVEL;
    scanResData[4+deviceNameLen] = 0x00;
    scanResDataLen = 5 + deviceNameLen;

    memcpy( attDeviceName, deviceName, deviceNameLen+1 );
    // memcpy( scanResData1 + 2, deviceName, deviceNameLen );
    extern BLEAppUtil_AdvInit_t advSetInitParamsSet_1;
    advSetInitParamsSet_1.scanRespData = scanResData;
    advSetInitParamsSet_1.scanRespDataLen = scanResDataLen;

動的に変更したい場合は、BLEAppUtil_advStop でいったん止めてから BLEAppUtil_advStart すれば OK です。

ChatGPT の回答では、起動時の BLEAppUtil_advStart しか出て来ないのでなかなか正解に辿り着けないのですが、実は「動的に BLE のデバイス名を変えるにはどうすればいいですか?」と質問すると、かなりイイ線までいきます。

void updateDeviceName(const char* newDeviceName)
{
    // 新しいデバイス名を格納(長さチェックを含む)
    size_t nameLen = strlen(newDeviceName);
    if (nameLen > MAX_DEVICE_NAME_LEN)
    {
        nameLen = MAX_DEVICE_NAME_LEN;
    }
    strncpy(deviceName, newDeviceName, nameLen);

    // スキャンレスポンスデータを更新
    uint8_t scanRespData[] =
    {
        nameLen + 1,  // データ長
        GAP_ADTYPE_LOCAL_NAME_COMPLETE,  // デバイス名のタイプ
        // デバイス名データ
    };

    // デバイス名をコピー(新しい名前で上書き)
    memcpy(&scanRespData[2], deviceName, nameLen);

    // BLEアドバタイズ設定を更新
    BLEAppUtil_AdvInit_t advParams = {
        .advParamLegacy = { ... },  // 他のパラメータを設定
        .scanResponseData = scanRespData,  // 更新されたスキャンレスポンスデータをセット
    };

    // 既存のアドバタイズを停止
    BLEAppUtil_advStop();

    // 新しいアドバタイズを開始
    BLEAppUtil_advStart();
}

BLEAppUtil_AdvInit_t advParams が何処で使われているのか?(実際には BLEAppUtil_advStart の中身なんですが)、というのが不明なのでこのコードではうまくいかないのですが、先に説明した const struct BLEAppUtil_AdvInit_t までたどり着いています。

AI でコード出力をする場合、マニュアルにないコードは探せません。逆に言えば、マニュアルにあるコードならば結構な確率で探し出してくれます。数々の回答のコード(間違ってはいるけれども)もかつてのコードかもしれないし、うまく類推しているコードでしょう。

AI でコード出力と言うと「5分でなんとか」方式が多いので、あっという間に作れる雰囲気がありますが、実際のところはかなり違います。まあ、それでも何も分からないところがから、最初の下調べをしてくれてマニュアルからなんとなく導き出してくれるところは便利ですね。当然のことながら、コンパイルも含めて動作確認は人の手でやらないと無理なので、そのあたりで動作確認は必須なところです。

カテゴリー: 開発 | GPT4o に技術マニュアルから実装コードを模索する話(C2340R5でデバイス名を変更編) はコメントを受け付けていません

M5Stack で iBeacon を飛ばす(PlatformIO環境)

iBeacon をスマホで受信するテストしているときに、iBeacon 自体がないので困ることはありませんか?いや、困ってなくても作ってみるのがお勧めです。

たまに作ろうと思うと、ググってもうまく引っ掛からない(iBeaconを受信するツールはあるのですが、発信するほうはあまりないので)、自分のブログに残しておきます。

platformio.ini

初代の m5stack の platformio,ini は次の通り。m5stick cplus とかを使う場合は適宜かえておきます。

[env:m5stack-core-esp32]
platform = espressif32
board = m5stack-core-esp32
framework = arduino
monitor_speed = 115200

lib_deps = 
    m5stack/M5Stack@^0.3.9

RTOS を使わない場合

RTOS を使わずに framework の android で setup/loop 関数を使って作ります。iBeacon を発信するツールとして使いたいときはこれで十分です。

#include <M5Stack.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <M5Stack.h>

static BLEServer *pServer ;
static BLEAdvertising *advertising ;

#define BEACON_UUID "12345678-1111-2222-3333-56789abcdef0"
#define BEACON_MAJOR 0x0001
#define BEACON_MINOR 0x0001
#define BEACON_POWER 0xC5  // Measured power (at 1 meter distance)

void init_beacon() {
  BLEAdvertisementData ibeaconData;
  // 12345678-1111-2222-3333-56789abcdef0
  char UUID[] = { 
    0x12, 0x34, 0x56, 0x78, 
    0x11, 0x11, 
    0x22, 0x22, 
    0x33, 0x33, 
    0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 
    0x00};
    int major = BEACON_MAJOR ;
    int minor = BEACON_MINOR ;
    int txPower = BEACON_POWER;

    ibeaconData.setFlags(0x1A);
    std::string strServiceData = "";
    strServiceData += (char)0x4c;  // apple 
    strServiceData += (char)0x00;  // apple 
    strServiceData += (char)0x02;  // apple 
    strServiceData += (char)0x15;  // apple
    strServiceData += UUID ;
    strServiceData += (char)(major >> 8);    // major
    strServiceData += (char)(major & 0xFF);  // major
    strServiceData += (char)(minor >> 8);    // minor
    strServiceData += (char)(minor & 0xFF);  // minor
    strServiceData += (char)txPower;  // 
    ibeaconData.setManufacturerData(strServiceData);

    // アドバタイズの設定
    advertising = BLEDevice::getAdvertising();
    advertising->setAdvertisementData(ibeaconData);
    advertising->setScanResponse(false);

}

// Arduinoのsetup関数
void setup() {
    // M5Stack の初期化
    M5.begin();
    Serial.begin(115200);

    BLEDevice::init("M5Stack");
    BLEServer *pServer = BLEDevice::createServer();
    init_beacon();

    // taskBeacon 内で start している
    // 実は start 1回だけではうまくいかないことが多く、
    // start/stop を繰り返す必要がある
    // advertising->start();
}

// Arduinoのloop関数
void loop() {
    // メインタスクのループ
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(10, 10);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.setTextSize(2);
    M5.Lcd.print("Hello, M5Stack with FreeRTOS! ");
    M5.Lcd.print(BEACON_UUID);
    Serial.println("Hello, M5Stack with FreeRTOS! ");
    // vTaskDelay(pdMS_TO_TICKS(3000));  // 3秒待機
    advertising->start();
    delay(3000);
    advertising->stop();
    delay(3000);
}

iBeacon で送信するサービスUUIDは、Apple の 0x004c となっていて、内部データとして iBeacon として送信したい UUID(12345678-1111-2222-3333-56789abcdef0)を設定しています。本来ならば、BEACON_UUID から 16 bytes のデータを作るところでが、面倒なので UUID 配列に詰め込んでいます。ちなみに 0x1502 は特性ID(キャラクタリスティック)のようなもので固定値です。

このコードでは、init_beacon 関数内でビーコンの発信設定をしているので、advertising->start(); を 1回だけ呼び出せばビーコンが送信されるような気もするのですが、うまくいきません。

これが BLEAdvertising クラスの仕様なのか、M5Stack の制限なのか(あるいは手元の M5Stack が不調なのか)わかりませんが、loop 関数にあるように、ある程度の間隔で start/stop を繰り返してやらないと iBeacon のデータが飛びません。

iBeacon が無事飛んでいると、次のように別のツールで動作確認ができます。

これは dotnet で作ったツールで、こんなコードで動かしています。

using System;
using System.Collections.Generic;
using System.Linq;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Storage.Streams;

// BLEのスキャナ
BluetoothLEAdvertisementWatcher watcher;
// MACアドレスの保持(ランダムなので意味はない)
List<ulong> maclist = new List<ulong>();

Main(args);

void Main(string[] args)
{
    Console.WriteLine("Folkbears iBeaconCheck");

    watcher = new BluetoothLEAdvertisementWatcher()
    {
        ScanningMode = BluetoothLEScanningMode.Passive
    };
    // スキャンしたときのコールバックを設定
    watcher.Received += Watcher_Received;
    // スキャン開始
    watcher.Start();
    // キーが押されるまで待つ
    Console.WriteLine("Press any key to continue");
    Console.ReadLine();
}

void Watcher_Received(
    BluetoothLEAdvertisementWatcher sender,
    BluetoothLEAdvertisementReceivedEventArgs args)
{

    var uuids = args.Advertisement.ServiceUuids;
    var mac = string.Join(":",
                BitConverter.GetBytes(args.BluetoothAddress).Reverse()
                .Select(b => b.ToString("X2"))).Substring(6);
    var name = args.Advertisement.LocalName;
    var rssi = args.RawSignalStrengthInDBm;
    var time = args.Timestamp.ToString("yyyy/MM/dd HH:mm:ss.fff");
    

    if ( args.Advertisement.ManufacturerData.Count > 0)
    {
        var data = args.Advertisement.ManufacturerData[0];
        if ( data.CompanyId == 0x004c && data.Data.Length >= 23)
        {
            byte[] ibeacon = new byte[data.Data.Length];
            DataReader.FromBuffer(data.Data).ReadBytes(ibeacon);
            if (ibeacon[0] == 0x02 && ibeacon[1] == 0x15)
            {
                byte[] uuid = ibeacon[2..18];
                byte[] major = ibeacon[18..20];
                byte[] minor = ibeacon[20..22];
                byte txpower = ibeacon[22];

                int majorvalue = major[0] * 256 + major[1];
                int minorvalue = minor[0] * 256 + minor[1];
                Console.WriteLine($"{time} [{tohex(uuid)}] {rssi} dBm {mac} "
                    + string.Format("{0:x04}", majorvalue) + " "
                    + string.Format("{0:x04}", minorvalue) + " "
                    );
            }
        }
    }
    string tohex( byte[] data )
    {
        return BitConverter.ToString(data).Replace("-", "").ToLower();
    }
}

*.csproj ファイルはこんな感じです。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

RTOS を使う場合

先のコードでは iBeacon の発信と停止を loop 内で制御しましたが、RTOS を使えばタスク内で記述ができます。

#include <M5Stack.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <M5Stack.h>

static BLEServer *pServer ;
static BLEAdvertising *advertising ;

// タスクの定義
void task1(void *pvParameters) {
    while (1) {
        Serial.println("Hello from Task 1");
        vTaskDelay(pdMS_TO_TICKS(1000));  // 1秒待機
    }
}

void task2(void *pvParameters) {
    while (1) {
        Serial.println("Hello from Task 2");
        vTaskDelay(pdMS_TO_TICKS(2000));  // 2秒待機
    }
}

void taskBeacon(void *pvParameters) {
    while (1) {
        Serial.println("task beacon start");
        advertising->start();
        vTaskDelay(pdMS_TO_TICKS(3000));  // 3秒待機
        Serial.println("task beacon stop");
        advertising->stop();
        vTaskDelay(pdMS_TO_TICKS(10000));  // 10秒待機
    }
}

#define BEACON_UUID "12345678-1111-2222-3333-56789abcdef0"
#define BEACON_MAJOR 0x0001
#define BEACON_MINOR 0x0001
#define BEACON_POWER 0xC5  // Measured power (at 1 meter distance)

void init_beacon() {
  BLEAdvertisementData ibeaconData;
  // 12345678-1111-2222-3333-56789abcdef0
  char UUID[] = { 
    0x12, 0x34, 0x56, 0x78, 
    0x11, 0x11, 
    0x22, 0x22, 
    0x33, 0x33, 
    0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 
    0x00};
    int major = BEACON_MAJOR ;
    int minor = BEACON_MINOR ;
    int txPower = BEACON_POWER;

    ibeaconData.setFlags(0x1A);
    std::string strServiceData = "";
    strServiceData += (char)0x4c;  // apple 
    strServiceData += (char)0x00;  // apple 
    strServiceData += (char)0x02;  // apple 
    strServiceData += (char)0x15;  // apple
    strServiceData += UUID ;
    strServiceData += (char)(major >> 8);    // major
    strServiceData += (char)(major & 0xFF);  // major
    strServiceData += (char)(minor >> 8);    // minor
    strServiceData += (char)(minor & 0xFF);  // minor
    strServiceData += (char)txPower;  // 
    ibeaconData.setManufacturerData(strServiceData);

    // アドバタイズの設定
    advertising = BLEDevice::getAdvertising();
    advertising->setAdvertisementData(ibeaconData);
    advertising->setScanResponse(false);
}

// Arduinoのsetup関数
void setup() {
    // M5Stack の初期化
    M5.begin();
    Serial.begin(115200);

    BLEDevice::init("M5Stack");
    BLEServer *pServer = BLEDevice::createServer();
    init_beacon();

    // taskBeacon 内で start している
    // 実は start 1回だけではうまくいかないことが多く、
    // start/stop を繰り返す必要がある
    // advertising->start();

    // タスクの作成
    xTaskCreate(&task1, "task1", 2048, NULL, 5, NULL);
    xTaskCreate(&task2, "task2", 2048, NULL, 5, NULL);
    xTaskCreate(&taskBeacon, "taskBeacon", 2048, NULL, 5, NULL);
}

// Arduinoのloop関数
void loop() {
    // メインタスクのループ
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(10, 10);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.setTextSize(2);
    M5.Lcd.print("Hello, M5Stack with FreeRTOS! ");
    M5.Lcd.print(BEACON_UUID);
    Serial.println("Hello, M5Stack with FreeRTOS! ");
    vTaskDelay(pdMS_TO_TICKS(3000));  // 3秒待機
}

ここでは、task1, task2, taskBeacon という3つのタスクが同時に動いています。優先度が同じなので、並列で動いているのですが、優先度を変えれば iBeacon 発信のタスクだけ優先して動かすことも可能でしょう(実験までしていませんが)。

先の iBeacon の発信/停止の切り替えは loop 関数から taskBeacon 内に移動しています。

m5stackの画面はこんな感じです。

カテゴリー: 開発 | M5Stack で iBeacon を飛ばす(PlatformIO環境) はコメントを受け付けていません

M5Stack で RTOS を試すときに main.cpp で動作させること

M5Stackシリーズを使うと、内部で ESP32のチップが使わているのでWi-FiやBluetooth周りのテストをするのに非常に便利です。手元の BLE 関係の通信も、いったん M5Stack で試し実装をしてみてスマホで動作確認をしてから、専用ボードに書き込むと動作がわかりやすいですよね。

手元でTIのボードを使ってBLE通信をしているのですが、そこでRTOSを使うことになっています。なぜRTOSを使うことになったのかはさておき、最近では AWS から FreeRTOSが配布されているので、これの準じたサンプルコードがあちこちで配布されています。当然ながらTIでも配布されているので、これを参考に作ります。

で、各ボードでのRTOS対応のコードは結構な職人プログラマが整備しているので、うまいことRTOSの説明や動きを解説することができあません。せっかくRTOSという統一されたOSのAPIを使っているわけですが、それぞれのボードに対応した専用関数で置き換えられているので(これはこれで仕事上は便利)コーディングがしやすいのですが、まあ、内部でどう動いているのか不可解なところがあるので、できることならば生のRTOSのAPIを叩いて試しておきたい。

ちなみに、私の場合 μiTronで仕事をしたことがあるのでリアルタイムOSまわりの動きはわかるのですが、RTOSのほうは初見ですね。

VSCode で PlatformIO を使う。

以前はESP32の開発環境を整えるのが一苦労だったのですが、最近は VSCode に「PlatformIO」という拡張をいれるだけで十分です。コンパイラ諸々をインストールしてくれます。

VSCode-PlatformIO IDEを使って、ESP32の開発環境を構築およびLチカ https://zenn.dev/kotaproj/articles/esp32_vscode_pio

デバッガ機能等便利なものが多いのですが、私の場合は Arduino IDE の上位互換機能があれば十分なので、build と upload だけあれば十分なところです。

Arduino IDE の場合はコード補完機能(インテリセンス機能)が効かないのでコーディングに苦労することが多いのですが、VSCode だと補完が効くし、GitHub Copilot を入れた現状だとかなりの部分をコード補完してくるので便利ですね。

RTOS対応のプロジェクトを作る

RTOSを使ってプログラミングをするのに、何かライブラリを入れないといけないのでは?と思いますが、実は ESP32の「espidf」というフレームワークには既に、RTOSのAPIが含まれています。他のボードだと結構苦労しそうな感じなのですが、少なくともM5StackシリーズでRTOSをやるときは特に追加のライブラリは必要ありません。

手元にあるのが、初期のm5stackなのでBoardには「M5Stack Core ESP32」を選択します。

ここでは、Framework に「Espidf」を選択していますが、実は「Arduino」でも構いません。どういうライブラリの構造かわかりませんが、ここで指定する「Arduino」のほうにもRTOSのライブラリが入っています。

最初、m5stackでRTOSプログラミングをするときのサンプルコードが、「Espidf」が多かったので、これにしたのが以下の躓きの始まりです。結論から言えば、(おそらくライブラリの容量の関係)「Arduino」で問題がないと思われます。

platformio.ini を比較する

プロジェクトを作成したら platformio.ini を確認しておきます。ここでフレームワークの指定やライブラリの追加ができます。

Framework が 「Espidf」の場合

[env:m5stack-core-esp32]
platform = espressif32
board = m5stack-core-esp32
framework = espidf

Framework が Arduino の場合

[env:m5stack-core-esp32]
platform = espressif32
board = m5stack-core-esp32
framework = arduino

platformio.ini の中身は framework のところ以外は変わりません。

ただし、このままでは M5.Lcd のような、モニタを使ったコードが書けないので、lib_deps を追加しておきます。これで M5.* 系のライブラリが自動でインストールされます。

[env:m5stack-core-esp32]
platform = espressif32
board = m5stack-core-esp32
framework = arduino

lib_deps = 
    m5stack/M5Stack@^0.3.9

ChatGPT に RTOS を使ったサンプルコードを書いて貰う。

実は GPT4o を使うと、ほどよく M5Satck を使って RTOS のサンプルコードを書いてくれます。

以下は、提案してもらったコードなのですが、実はビルドができません。

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_system.h>
#include <esp_log.h>
#include <M5Stack.h>

// ログタグの定義
static const char *TAG = "main";

// タスクの定義
void task1(void *pvParameters) {
    while (1) {
        ESP_LOGI(TAG, "Hello from Task 1");
        vTaskDelay(pdMS_TO_TICKS(1000));  // 1秒待機
    }
}

void task2(void *pvParameters) {
    while (1) {
        ESP_LOGI(TAG, "Hello from Task 2");
        vTaskDelay(pdMS_TO_TICKS(2000));  // 2秒待機
    }
}

// メイン関数
void app_main(void) {
    // M5Stack の初期化
    M5.begin();

    // タスクの作成
    xTaskCreate(&task1, "task1", 2048, NULL, 5, NULL);
    xTaskCreate(&task2, "task2", 2048, NULL, 5, NULL);

    // メインタスクのループ
    while (1) {
        M5.Lcd.fillScreen(BLACK);
        M5.Lcd.setCursor(10, 10);
        M5.Lcd.setTextColor(WHITE);
        M5.Lcd.setTextSize(2);
        M5.Lcd.print("Hello, M5Stack with FreeRTOS!");
        vTaskDelay(pdMS_TO_TICKS(3000));  // 3秒待機
    }
}

error “This library only supports boards with ESP32 processor.”

なエラーが M5Stack.h 内で出ています。

よくわからないので、framework が「Arduino」のほうに、main.c をコピーすると以下のようなエラーがでます。

“class” がないというエラーなのですが、実は main.c をそのままコピーしたので C言語で扱われているからです。なので、main.cpp にして C++ でコンパイルされるようにします。

実は SD.h がないとか諸々エラーになることもあるのですが、結論としては main.c のままなのが原因で、main.cpp にすれば ok です。

コンパイルは順調に進むのですが、最後のリンクで失敗します。

どうやら、

  • framework が espidf のときはC言語で、app_main がエントリー関数(俗にいうmain関数)
  • framework が ArduinoのときはC++で、setup と loop が呼び出される

という違いがあるようですね。TI のサンプルコードが C言語のほうの *.c に限られていたので、Arduinoのほうが C++ のほうの *.cpp に統一されていたのを忘れていました、というオチです。

で、最終的には以下のコードで動くようになります。

#include <M5Stack.h>

// タスクの定義
void task1(void *pvParameters) {
    while (1) {
        Serial.println("Hello from Task 1");
        vTaskDelay(pdMS_TO_TICKS(1000));  // 1秒待機
    }
}

void task2(void *pvParameters) {
    while (1) {
        Serial.println("Hello from Task 2");
        vTaskDelay(pdMS_TO_TICKS(2000));  // 2秒待機
    }
}

// Arduinoのsetup関数
void setup() {
    // M5Stack の初期化
    M5.begin();
    Serial.begin(115200);

    // タスクの作成
    xTaskCreate(&task1, "task1", 2048, NULL, 5, NULL);
    xTaskCreate(&task2, "task2", 2048, NULL, 5, NULL);
}

// Arduinoのloop関数
void loop() {
    // メインタスクのループ
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(10, 10);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.setTextSize(2);
    M5.Lcd.print("Hello, M5Stack with FreeRTOS!");
    vTaskDelay(pdMS_TO_TICKS(3000));  // 3秒待機
}


先頭部分の「freertos/FreeRTOS.h」あたりは、M5Stack.h から自動的にインクルードされているらしく必要ありません。RTOS 特有の関数としては、タスク生成の xTaskCreate の部分で、これが呼び出せていれば RTOS でビルドできています。

This page describes the RTOS xTaskCreate() FreeRTOS API function which is part of the RTOS task control API. FreeRTOS is a professional grade, small footprint, open source RTOS for microcontrollers. https://www.freertos.org/a00125.html

アップロードして動作させる

アップロードでして動作させると m5stack のモニタに「Hello, M5Stack with FreeRTOS!」の表示がでて、シリアルポートには、以下のような2つのタスクが交互っぽい形で動いていることがわかります。

ここまでで半日費やしてしまったので力尽きて、何をやろうとしていたのか忘れてしまいました。まあ、いいんですが。

後日、BLE通信のコードをちょっと入れ込んで試しおくつもりです。

余談

ちなみに、これらのサンプルコードは ChatGPT の GPT4o を使って尋ねているのですが、最終的に main.c と main.cpp に気付いた部分はこれになります。

いやいやいや、そもそも ESP-IDF フレームワークと Arduinoフレームワークを混在させてきたのは君なんですが!をぐっとこらえてw

まあ、それでも GPT4o を使って、何度も「このコードだと動かないのですが、どうしたらいいですか?」を繰り返している訳で。なかなか一発で解決にはなりませんね。

それでも最初のスタートダッシュは生成AIを使うと便利です。

カテゴリー: 開発 | M5Stack で RTOS を試すときに main.cpp で動作させること はコメントを受け付けていません

CrawdStrike 関係で Windows のカーネルドライバーの動きを少し解説

NHK の解説

【最新】システム障害 マイクロソフトは「サービスは回復」と発表 影響は一部で継続も収束にむかう | NHK | 航空 https://www3.nhk.or.jp/news/html/20240720/k10014517151000.html

Microsoft からの復旧手順

KB5042421: CrowdStrike issue impacting Windows endpoints causing an 0x50 or 0x7E error message on a blue screen – Microsoft Support https://support.microsoft.com/en-us/topic/kb5042421-crowdstrike-issue-impacting-windows-endpoints-causing-an-0x50-or-0x7e-error-message-on-a-blue-screen-b1c700e0-7317-4e95-aeee-5d67dd35b92f

Recovery options for Azure Virtual Machines (VM) affected by CrowdStrike Falcon agent – Microsoft Community Hub https://techcommunity.microsoft.com/t5/azure-compute-blog/recovery-options-for-azure-virtual-machines-vm-affected-by/ba-p/4196798

どのようにNULLポインタアクセスなのか?

画面キャプチャだけ抜き出し。

このツイートでは、00000000 0000009c ゆえに NULL ポインタアクセスという指摘になっているが、(確か)実際は Windows 起動時はリアルモードで実行されるので DS レジスタが有効になっていて DS:009c がアクセスされる。つまり 002b:009c から DWORD の 4バイトの読み込みでアクセスエラーとなっているので、NULL ポインタアクセスとは限らない(まあ、この DS が間違っている可能性もあるので)。ここは私も見逃したところのなので、特に言及はしない(私が間違っている可能性あるし)以下はひとつの考察である。

アセンブリコードを見ると、

mov r9d,dword [r8] ds:002b:00000000`0000009c=????????

r8 レジスタが示すメモリつまり [002b:009c] なんだけど、きちんとデータセグメントにあるっぽいのに、read access error を起こしているのはかなり変な状況になっている感じがする。

が!!!、再考すると、

  • カーネルドライバは「プロテクトモード」で動いている
  • セグメントレジスタの値(特にcs=0010, ss=0018, ds=002bなど)は、プロテクトモードのGDT内のエントリを指している可能性が高い。

とのことなので、これは「プロテクトモード」っぽい。

となると、先のツイートにあるように、なんらかの変数A(配列の先頭と思われる)に対して「オフセットで、0x9cの場所を参照しようとしている。つまり

DWORD x = A[ 0x9c ] ;

みたいなコードで、DWORD(4バイト)読み込みをしようとしているのだが、最初の変数 A が NULL ポインタなので(おそらく初期化漏れ)、アクセスエラーを発生している。大抵のメモリでは、先頭 0x1000 位が NULL ポインタチェック用に用意されていることが多く、それに引っ掛かったのだろう。

DWORD *A = 0x00 ;
// ここで変数 A の初期化漏れ
DWORD x = A[ 0x9c ] ;

この部分、変数 A の初期化漏れを Rust で回避できるかどうかなんだけど、Rust の場合は初期化していない変数を利用しようとするとコンパイルエラーになるので、これは回避できるかも。

「インサイド Windows」下巻の第12章より

ここの「ドライバー実行環境(DXE)」のときに、既にプロテクトモードになっているそうだ。なので、リアルモードのセグメント化でつかう DS レジスタは、既に GDT を示しているのだけなので、00000000 0000009c がフラットなアドレスと指定される。メモリを示すときはこんな小さなアドレスを示すことはないので、配列の先頭を示すアドレスの初期化漏れ(しかもわざわざ 0x00 が入っていた)と考えるのが正しい。

参考先

Windows カーネルドライバーって Visual Studio のプロジェクトテンプレートにあるらしく、結構便利になっている。

Write a Hello World Windows Driver (KMDF) – Windows drivers | Microsoft Learn https://learn.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/writing-a-very-small-kmdf–driver

追記 2024/07/25

Technical Details: Falcon Update for Windows Hosts | CrowdStrike https://www.crowdstrike.com/blog/falcon-update-for-windows-hosts-technical-details/

名前付きパイプの読み取りで失敗して、C-00000291-*.sys の読み込みあたりでエラーが発声しているので、Although Channel Files end with the SYS extension, they are not kernel drivers. カーネルドライバーではないよ、という理由らしい。C-00000291-*.sys ファイルを消すと正常動作するので、読み取り先のデータ領域っぽい(多分、ファイルをオープンして、メモリマップドしていると思う)ので間違いではないが、NULLポインタエラーの否定にはなっていないし、おそらく

  • C-00000291-*.sys ファイルが新規に追加される
  • C-00000291-*.sys ファイルをオープンする。
  • 名前付きパイプでアクセスする(大抵はメモリマップドである)
  • このときに NULL チェックを怠ったか、C-00000291-*.sys の先が NULL 書き込みされていたかでアクセスエラー発生

という手順だろう。

ほぼ100%再現性があるっぽいので(何万台というレベルで発生いるため)、これ最初に動作確認したのか?が危ぶまれるのだが CrawdStrike社としてはどうなのだろうか?

単体テストというか、リリース前の運用テストをスキップしてしまった感じがする。

カテゴリー: 開発 | CrawdStrike 関係で Windows のカーネルドライバーの動きを少し解説 はコメントを受け付けていません