ESP32-WROOM-SOLO でトラブった件

TL;DR

WROOM-SOLOチップを使う場合、とりあえず動かすには PlatformIO で ESP-IDF を選択して sdkconfig.h を次のように変更する必要がある。

  • 「#define CONFIG_FREERTOS_UNICORE 1」の行を追加
  • 「#define」行のうち「_CPU1」を含むもの、および「_PINNED_TO_CORE_0」を含むものを削除

※間違えて「_PINNED_TO_CORE 0」(CORE と 0 の間が「_」でなく半角スペース)を消さないよう注意

長文版

前回書いてからだいぶ経ったなぁと思いつつ最終更新日を見たら一年も経過していて愕然とした新年最初の月(の終わり)でございます。

久々に電子工作のネタを思い付いたので bluetooth LE の使えるワンチップマイコンの ESP32-WROOM を購入したのですが、カタログを見ながら毎度のごとく下手な考えで「ちょっと安価なシングルコア版かぁ、こっちが買いだな。」とやって要らぬ苦労をしたという話です。

くだんの ESP32-WROOM チップ自体は有名なので、変種の -SOLO についての情報もある『だろう』と思って調べもせずに購入してしまったのです。それがこれから始まる苦難の道への第一歩であるとも知らずに…

問題が発覚したのは注文の翌々日、商品が届いたその日でした。
一緒に頼んだブレッドボード用のブレイクアウト基板に WROOM-SOLO をハンダづけし、arduino-IDE でサンプルスケッチの Blink (いわゆる L チカ)を書き込んで走らせたその時、シリアルモニタに驚愕すべき文字列が表われたのです!

原文

E (98) cpu_start: Running on single core chip, but application is built with dual core support.
E (99) cpu_start: Please enable CONFIG_FREERTOS_UNICORE option in menuconfig.
abort() was called at PC 0x4008274e on core 0

萌訳

べ、別に双頭人向けのマニュアルが読めないわけじゃないのよ!
でも、あんたがどうしても単頭人版も用意したいって言うなら、特別にそっちも読んであげてもいいわ!

「…ま、まあ CPU コア数が違うんだから、設定項目くらいあるか。うん、考えてみれば当然だよなぁ、ははは…」と呟きつつ、指示通りにシェルから make menuconfig を実行すると『make.exe”: *** No rule to make target `menuconfig’. Stop.』という非情なエラー表示が…

しかし、これはまだ序の口でした…

この直後に起こった闘いは、かの有名な「血と硝煙の七日間」として後世で語られるものとなったのです。

…が、紙幅の都合により、ここではダイジェストでお送りします。

  • arduino-IDE で別ボード名の設定を次々と試しては希望を砕かれ、失意のうちにマンハッタン隔離区画(通称 The division)にてマディソン野戦病院から医師を保護する作戦に召集
  • google 神の託宣を求めるも主流のデュアルコア派に関する情報しか得られず途方に暮れる中、リンカーン・トンネル検問所に追い詰められた部隊の救出に従事
  • データシートの解読を試みるも求めるものは見付からず、直後にマンハッタンの地下死体安置所から技師のポール・ローズを連れ出す作戦を遂行
  • PlatformIO 環境に変えてみても arduino 版は動かず、絶望にうめきながらハドソン難民キャンプからクリーナーズを排除
  • ESP-IDF 版では 4秒だけ動いてリセットが繰り返されるという怪奇現象に悩まされつつ、ブロードウェイの商業施設にて汚染源と推測されるドル札を調査
  • ようやく Linux 仮想マシン上にて動くバイナリが make できる事をつきとめ、 祝賀イベントと称してクリーナーズの火炎弾生産現場を襲撃
  • ついに Windows の PlatformIO での設定方法が判明した喜びでハイになった勢いで、タイムズスクエアの継電器をライカーズギャングから奪還

このときの携行火器はショットガンとサブマシンガン、 何度も半死半生になりながら仲間の援護射撃の下、イチかバチかの敵陣特攻を繰り返したと伝えられています。
…って話題が入れ替わってますね、はい。

というわけで、なんとかマトモに動く目処が付いたので忘れないうちに駄文記録を残しているところです。

オマケ:-SOLO 用設定のデフォルト化

新規プロジェクトで用意される sdkconfig.h の テンプレートを探したところ、grep して辿り着いた ~/.platformio/platforms/espressif32/builder/frameworks/espidf.py を見た限りでは espressif32/examples/*/src/sdkconfig.h を探して見付かったどれかをコピーしてくるようなので、次の手順で毎回の sdkconfig.h の変更を回避する事にしました。

  1. examples フォルダ内にあるサンプルを別フォルダに移動する
  2. サンプルの一つである espidf-blink フォルダ以下を examples にコピーして戻す
  3. 唯一のテンプレート候補である examples/espidf-blink/src/sdkconfig.h に次の変更を行う
    1. 次の一行を追加「#define CONFIG_FREERTOS_UNICORE 1」
    2. 以下のいずれかを含む行を削除
      1. 「_CPU1」
      2. 「_PINNED_TO_CORE_0」(CORE と 0 の間はアンダーバー記号)

ちなみにデュアルコア版 WROOM は変更後の設定でも(単一コアモードで)動きます。
※ESP32-WROOM 自体ではなく、変種の ESP32-WROVER-B で確認しました

Laravel で FixedMidashi を使う時

よくある話ですが、Web アプリでテーブルの上側(列ヘッダ)と左側(行ヘッダ)を固定したまま残りをスクロールしたい状況になりまして、検索して FixedMidashi JS ライブラリに辿り着きました。
これが非常によく出来ていて、使い方が簡単なのに見事に動作するという優れ物です。
心配していた bootstrap3 との併用も難無くクリアしてくれました。

しかしながら Laravel で動かすのに一点だけ手間取ってしまいました。
と言っても FixedMidashi 側に問題があったわけではなく、Laravel Mix でアセットコンパイルしたら動かなかったという話です。
最初試すのに public/js フォルダに置いた時には動いていたので、原因に辿り着くまで1時間くらい唸ってました。
最終的には mix.js や mix.scripts で処理するのではなく mix.copy を使って単純にコピーすることで解決しました。

いつも通り備忘録という名目でデータの海に一滴追加しておくことにします。

開発に SQLite を使う時の注意点

皆さんは Web アプリの RDBMS には何を使っていますか?
巷では MySQL(MariaDB)、Oracle、PostgreSQL あたりが主流と聞きます。

しかし、これらを開発時に使うのはセットアップが面倒ですよね?
はい、そこ「Docker 使え」とか言わない。

面倒なので SQLite を使ってしまう時ありませんか?
え、使わない?ここは「使う」って言う所ですよ。空気読んでください。

というわけで(無理矢理ですが) SQLite で開発する時のトラップ注意点です。

一言で済みます。「データ型が INTEGER、REAL、TEXT、BLOB しかない!」のです。
つまり DATE とか TIME とか TIMESTAMP とかが無いのです。
まあ、他に DECIMAL とか BOOLEAN も使えませんが今回は見なかったことにします。

よって、SQL 文で日付形式や時間形式の演算および比較ができません。
…ええ、お察しの通り色々コード書いてから気付きましたとも。
指定日を含む期間を探す関数のテストを書いた時に判明しましたよ…
なまじ(文字列型としての)比較が期待通り動くものだから発覚が遅れました。

これから PostgreSQL を準備して再テスト&書き直しです。
Twelve factor app 10.開発/本番一致の意味が身に染みました。
願わくば、この記事が誰かの転ばぬ先の杖になると良いのですが。

gitprep の docker 化

前略
クラウド(ようやく)始めました。

「そうだ、Gitprep 入れてみよう!」
→ セットアップでエラー
→ いろいろ試してもエラー
…サーバ引っ越しの度にこんなエラー地獄では耐えられません。

「そうだ、Docker 使おう!」
→ perl イメージある
→ mojolicious イメージある
→ ソースコード足せば動く?

(3時間経過)

「や、やっと動いた…」
→ 他にも同じ苦労をする人がいるかも…(← いません)
→ 公開しなきゃ
→ ウェブログに投稿だ!

(1時間経過)

「記事書けたけど Dockerfile より短い…何故?」 ← 今ここ
作ったファイルはこちら

こっそり quickutil を使ってみた

トラブってたのを一つ前の記事に書いたわけですが、今度は調査メモです。

ネットを彷徨っていたところ quickutil の記事を見付けまして、色々試してみたんですよ。
まあ、公式サイトの http://quickutil.org/ の方で「under maintainance」って書いてあるので駄目元だったんですが。
なんとなく動いた感じなので方法をコッソリと書いておこうかと。
もちろん、やる場合には自己責任です。っていうかメンテ明けまで待つのが正しい態度ですよね…

使うだけなら次のようにすればいいです。
あらかじめ quicklisp を使えるようにしておいて下さい。
使いたいユーティリティは :shuffle だとします。適宜、置き換え願います。
リストを渡すので、一度に複数でも大丈夫のようです。

;; 準備
(ql:quickload 'quickutil)
;; 利用のための宣言(引数はキーワードのリストらしい)
(qtlc:utilize-utilities '(:shuffle))

;; 利用は "qtl:ユーティリティ名" で呼び出す模様
(qtl:shuffle '(3 2 1))

なお、ユーティリティのリストは以下で見られました。

;; 準備
(ql:quickload 'quickutil-utilities)

;; 全部
(qtl-utl:all-utilities)
;; カテゴリの一覧
(qtl-utl:all-categories)
;; カテゴリ内にあるユーティリティの一覧(例では integers カテゴリ)
(qtl-utl:utils-in-category :integers)

Use at your own risk!

いきなり slime が動かなくなった件

原因は不明ながら、slime が急にエラーで動かなくなってしまったので経過をメモ。
(思い出しながら書いているので、あやふやな部分あり)

検索したサイトを見ながら popwin の設定やら ac-slime のインストールやらをしていたら、ある時 M-x slime するとエラーするようになってしまった。
※正確には swank サーバへの接続待ちのままになった。表示通りに M-x slime-abort-connection するとキャンセルされて REPL には入れる。

その状態で (require 'asdf) (require 'alexandria) すると /usr/share/common-lisp/source/cl-asdf/build/asdf-TMP.lisp が FILE OPEN エラーになってデバッガに入ってしまった。
emacs を終了してコンソールから直接 sbcl で実行しても同じエラーになった。

~/.cache/common-lisp/ を削除してみたが直らず。
apt で slime と cl-asdf を再インストールしてもダメ。

以前に作成した以下のファイルを削除したら slime は起動するようになった。

;;;; ~/.config/common-lisp/source-registry.conf
(:source-registry
  (:tree "~/quicklisp/dists/")
  :INHERIT-CONFIGURATION)


require もエラーしなくなった… はず。ただ、相変らず (require 'alexandria) の返り値が nil だったのでダメかと思って作業を継続した。
この時点で最終結果と同じ状態に戻っていたのかもしれない。
(require 'asdf) の返り値が nil だったかは覚えていない。

その後、~/quicklisp/ も削除して slime から (load "/usr/share/cl-quicklisp/quicklisp.lisp") (quicklisp-quickstart:install) で再インストールしてみた。
ここで (ql:quickload 'alexandria) するとインストールが行われ、(alexandria:lastcar '(a b c)) が動作した。
そのまま更に (ql:add-to-init-file) を実行して設定ファイル(sbcl だったので ~/.sbclrc)に quicklisp の自動ロードを設定した。
一旦 emacs を再起動し、require するも返り値は nil のまま。
コンソールから sbcl でやっても同じく nil が返っていたが、何の気なしに alexandria:lastcar をやってみたら動作した。

ふと思い付いて .sbclrc の quicklisp 設定をコメントアウトしてから、コンソールで (require 'alexandria) したらエラーになった。
そのまま (load "~/quicklisp/setup.lisp") したところ alexandria:lastcar が動作した。

quicklisp 設定をコメントアウトしたままの状態で ~/.config/common-lisp/source-registry.conf をエラー前に戻してみた。
そうしたら (require 'alexandria) がエラーせずに nil を返し、alexandria:lastcar も動作するようになった。

元々は .sbclrc の quicklisp 設定はコメントアウトされていたので、結局エラー前と同じ設定に戻ったことになる。
経過から見るとキャッシュを壊していた確率が高いが、問題の原因は特定できず…
とりあえず動作するので、まあいいかと。

最終的にはコンソールでも slime でも以下のように動いている。
(行頭に「?>」があるのがプロンプトと入力内容で、次のプロンプトまでが出力)

?> (require 'asdf)
("ASDF" "asdf" "UIOP" "uiop")

?> (alexandria:lastcar '(a b c))
※以下のエラーが発生した
debugger invoked on a SB-INT:SIMPLE-READER-PACKAGE-ERROR in thread
#:
Package ALEXANDRIA does not exist.

Stream: #

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.

(SB-IMPL::READER-FIND-PACKAGE "ALEXANDRIA" #)

※ 0 でデバッガを終了してトップレベルに戻る

?> (require 'alexandria)
nil

?> (alexandria:lastcar '(a b c))
c

以上。

persp-mode を設定してみた(ついでに helm も)

えー、今回は common lisp のコードを書こうと思ったらキーバインドが気になって、init.el を編集してるうちに elisp パッケージ探しに走ってしまい、気が付いたらリファレンスを見ながら elisp を書いていたという yak shaving の最たるものになってしまいました。
なので、せめて動いたコード片だけでも載せておこうと思います。

以下は persp-mode で新規パースペクティブを作成した時(厳密にはバッファがないパースペクティブに切り替えた時)にバッファを選択して登録する設定です。
毎度おなじみ rubikitch 様のサイトからコピーして、四苦八苦しながら希望する動作になるよう改造(改悪?)しました。
ホント、いつもお世話になってます。密度の濃い情報ありがとうございます。 > rubikitch 様
設定した persp-mode のバージョンは 20161226.2218 です。

;;; persp-mode 設定
(setq persp-add-on-switch-or-display t)
(persp-mode 1)
;;; 新規パースペクティブ作成時に追加するバッファを選択する
(defun persp-register-buffers () ; 関数名変更
  (interactive)
  (dolist (bufname (condition-case _
                       (helm-comp-read
                        "Buffers: "
                        (mapcar 'buffer-name (buffer-list))
                        :must-match t
                        :marked-candidates t)
                     (quit nil)))
    (persp-add-buffer (get-buffer bufname))))
;; ここから追加分
(defun persp-register-buffers-if-empty (mode)
  (interactive)
  (if (null (persp-buffer-list)) ; パースペクティブのバッファが空の時だけ
      (persp-register-buffers))) ; 上のバッファ選択関数を呼ぶ
(add-hook 'persp-activated-functions 'persp-register-buffers-if-empty) ; フック名が変わった?

それから、persp-mode 用の helm アクションも見様見真似で作ってみました。
いちおう動いているようですが、使用は自己責任でお願いします。

(defun helm-persp-add-buffer (buffer-or-name)
  (persp-add-buffer (helm-marked-candidates)))
(defun helm-persp-kill-buffer (buffer-or-name)
  (persp-kill-buffer (helm-marked-candidates)))
(setq helm-type-buffer-actions
      (append helm-type-buffer-actions
              '(("Add buffer(s) to perspective" . helm-persp-add-buffer)
                ("Kill buffer(s) from perspective." . helm-persp-kill-buffer))))

以上です。

nodoka で右 Shift キーが効かなかった件

昨日に引き続きキーカスタマイズのネタです。

実は Windows で Emacs 似のキーバインドを使いたいために nodoka というユーティリティを使っているんです。
で、今まで気付いては忘れてた挙動に「右 Shift キーでは Shift されない」というのがありました。

今回よく調べてみたところ、nodoka を一時停止すると問題無く Shift されるので、設定が原因だろうと色々試しました。
調査とログのダイアログを駆使して探った結果、下のような設定で無事に動きました。


# 右 Shift のキー名を定義
def key E0RightShift E0RShift = E0-0x36
# 右 Shift を 左 Shift とみなす
def subst E0RShift = LShift
# 仮想キーの Shift が押されるように設定
keymap Global
mod shift += E0RShift
key *E0RShift = *LShift
# nodoka を使いたくないキーマップ(KeymapDefault)にも適用
keymap KeymapDefault
mod shift += E0RShift
key *E0RShift = *LShift

これはマニュアル(カスタマイズ詳細)中央あたりの次の部分を参考にしました。

なお、右シフトキーが使えないことは致命的なので、ホスト側の のどか設定ファイルでは、window RemoteDesktop /mstsc\.exe/ を記述し、ホスト側でのキー入れ替えは無いことにして、リモート側のどかの設定ファイルでは、下記のような設定をすると良いでしょう。

def key E0RightShift E0RShift = E0-0x36

mod shift += E0RShift

key *E0RShift = *LShift

カスタマイズまわりはハマると面倒ですね。

Putty 経由の Emacs で C-M-S-v が入らない件(未解決)

今回は Emacs です。
以前から使ってはいたのですが、ここを参考に設定しなおしてみようかと思いまして。

とりあえず Ubuntu Linux の仮想マシンを用意して Putty でログインして Emacs をいじっていました。
で、サンプルの通りにキーバインド「C-,」を割り当てて使ってみると動きません。
現在の割り当てを調べる「C-h c C-,」を使ったところ、どうも「C-,」が Linux に入っていないようでした。

この問題については最終的にこのサイトを参考にして解決できました。

該当ページ中から「xterm風定義」リンクを辿ると他のキー一覧もあります。
その中でカンマを示す「VKey188」の行ですが、以下(4番目が \033[27;6;60~)が正しいのではないかと思います。
VKey188=\054,<,\033[27;5;44~,\033[27;6;60~,\033\054,\033<,\033[27;13;44~,\033[27;14;60~

引き続いて「C-M-v」の別ウィンドウスクロールの逆方向版を「C-M-S-v」(Shift を追加する)に割り当てようとしましたが、こちらは解決できませんでした。
「C-,」と同様に「VKey…」を追加すればいいかと思って下のように色々試したのですがダメでした。

試した内容

  • VKey86=,,,,,,,\033[27;14;118~
  • VKey86=,,,,,,,\033[27;14;86~
  • VKey86=,,,,,,,\033[27;14;v~
  • VKey86=,,,,,,,\033[27;14;V~
  • VKey86=,,,,,,,\033[27;5;118~
  • VKey86=,,,,,,,\033[27;5;86~
  • VKey86=,,,,,,,\033[27;5;v~
  • VKey86=,,,,,,,\033[27;5;V~

カンマ区切りのキーコード出力部の内容は 「\033[27;≪修飾コード≫;≪キーコード≫~」だろうと思っています。
この中にある「27」は多分 Escape キーの VKey コードでしょう。

どれも思うようにいかなかったので、現在はエスケープシーケンスの規則を調査中です。
参考サイトに書いてある気もしますが、英語を読むのが面倒なので Try&Error で頑張ります。

参考サイト

ちなみに「C-,」問題は nadoka で「key C-Comma = &SendText("\e[27;5;44~")」でも解決できましたが、対象文字列を入れる時に一文字ずつ(少しだけ)ウェイトがかかって微妙な気分になるので止めました…

コードのスタイルを統一するなら EditorConfig

複数の作業環境を渡り歩いてソースコードを編集することって結構ありますよね?
こんな時、新しく編集した部分だけインデント文字(タブかスペース)やオフセットが変わってしまって、手作業でスタイルを合わせる破目になった経験があるでしょう。
テキストエディタが同じなら作業前に設定ファイルをコピーすればなんとかなりますが、違うエディタだと設定に使った時間の方がコーディング時間より長くなったという悲劇(笑い話?)も聞きます。

そんな時に頼りになる最終兵器 EditorConfig を発見しました。
共通の設定ファイルを用意しておけば、エディタにプラグインを入れるだけで同じスタイルで書けるようにしてくれます。
設定できる項目はインデント文字、オフセット幅、改行文字、文字コード等です。
ディレクトリを遡りながら設定ファイルを探すので、スタイルがプロジェクトごとに違っていても対応できます。

興味がわいた方は、分かりやすい説明がここにあるので参照してみてください。

参考

  • 公式サイトはここ
  • Emacs 用プラグインは Github