OpenSSH for WindowsでSSHログインすると管理者権限になる件。

Windows 10 1809とOpenSSH。その2で、
管理者モードになっています。これは多分 sshd_config でなんとかしないといけないんだと思いますが、これはまあそのうち。
などと書いたままペンディングになっている件です。

sshd_config もよく眺めてみたんですが、どうもこれじゃないっぽい。とすると SSHD.EXE を実行している Windows サービス側のパーミッション関係かな、と考えてみました。

そこで、ノーマルモードで SSHD.EXE を起動してみると、
C:\Users\kats$ c:\Windows\System32\OpenSSH\sshd
Could not load host key: __PROGRAMDATA__\\ssh/ssh_host_rsa_key
Could not load host key: __PROGRAMDATA__\\ssh/ssh_host_ecdsa_key
Could not load host key: __PROGRAMDATA__\\ssh/ssh_host_ed25519_key
sshd: no hostkeys available -- exiting.
みたいなことになります。
ファイル自体は存在するので、読み取りパーミッションの関係でエラーになっています。検索してみると、OpenSSH utility scripts to fix file permissionsというページがありました。FixHostFilePermissions.ps1 などの PowerShell スクリプトでパーミッションを適切に設定する、というユーティリティです。
これはどうも一緒にインストールされているわけではないらしく、https://github.com/PowerShell/openssh-portable/blob/latestw_all/contrib/win32/openssh/FixHostFilePermissions.ps1に現物があります。

実行するには OpenSSHUtils.psm1 というPowerShell モジュールも必要のようで、一緒にダウンロードしておきます。

PowerShell から FixHostFilePermissions.ps1 を起動してみると、
Current owner: ''. 'NT AUTHORITY\SYSTEM' should own 'C:\ProgramData\ssh\ssh_host_ecdsa_key'.
Shall I set the file owner?
[Y] はい(Y)  [A] すべて続行(A)  [N] いいえ(N)  [L] すべて無視(L)  [S] 中断(S)  [?] ヘルプ (既定値は "Y"): 
みたいなプロンプトがでてきます。ということは、これを実行するには PowerShell も管理者権限で起動していないといけません。

XXX: write me

電子レンジのこびりつき掃除。

もう10年くらい使ってる電子レンジなんですが、わりとラップをしないで温めとかしている関係で、焼き魚とか唐揚げとかが「ぼんっ」というような音とともに中でハネるため、結構汚れていました。シリコンプラスチックのレンジ蓋なんかも使ってるんですが、どうしても飛び跳ねます。

作業前の写真は撮っていないのですが、醤油的なシミとか焦げが壁に飛び跳ねてこびりつき、ちょくちょく拭き掃除などしていても取り切れない汚れが固まっていました。

昨日、チキンドリアをオーブンで焼いたら、それまで色が薄くて目立たなかった汚れがしっかりと(焦げて)浮き出てきて、こりゃちゃんと掃除しないと、ということでスチームクリーナーとセスキ炭酸で結構きれいにはなったんですが、頑固なこびりつきがまだ残っていました。
庫内にセスキ炭酸パウダーをばらまき霧吹きで水を吹いてから、タオルをゆるく絞ってかぶせ、レンジで温めて放置して溶かし出したりしましたが、どうにも頑固です。

ボツボツと黒い点になっているのがこびりついた焦げ付き汚れです。

これはもう、ヘラでこそげ落とすしかないなということで、ホームセンターで買ってきました。Inoue のカーボンはがしヘラ。

金属のヘラだと確実に焦げはこそげますが、レンジの中が傷だらけになってしまいます。なのでカーボンプラスチック製の当たりの柔らかいヘラを使ってこそげ落としていきます。あらかじめセスキ炭酸スプレーを吹いて、水気を与えてしばらくしてから行います。
ヘラで丁寧にこそいでいくと、どうにかきれいになりました。

忘れがちなのが天井部分に飛び跳ねた汚れですが、こちらはゆるく絞ったタオルを入れてレンチンし、しばらく置くとわりときれいに拭き取れます。が、こびりついてしまったものはやっぱりヘラでこそげ落とすしかないのでしょうね。

MercurialとGoogleドライブ。

バージョン管理下にあるプロジェクトを複数のPCで使いたいときに、Google ドライブや OneDrive、Dropbox などのファイル同期系のサービスを使ってはいけません。というのを見つけたのでメモ。

Hg Mercurial over Google Drive issueにありました。

DO NOT under any circumstances use any kind of file-level synchronization tool, such as Dropbox, Google Drive, OneDrive, Jottacloud, or any other such tool, to synchronize distributed version control repositories between computers. These tools only detect conflicts on a file-level and does not treat a repository (which is a collection of files and folders) as a unit that needs to have integrity together. Basically you've committed or changed something in your repository on a different computer before Google Drive had a chance to bring it up to date. – Lasse Vågsæther Karlsen May 30 '18 at 7:13

どのような状況であろうと、分散型バージョンコントロールリポジトリを複数のコンピュータ間で同期するために、Dropbox、Googleドライブ、OneDrive、Jottacloudのようないかなる種類のファイルレベルの同期ツールを使ってはいけません。これらのツールはファイルレベルの衝突を検出するだけで、整合性を保つために必要なユニットとしてリポジトリ(ファイルとフォルダの集合)を取り扱うことをしません。(最後の文はよくわからなかった)

ということで、せめて同期機能のないネットワークドライブにしましょうね、ということのようです。

Googleドライブで特定のフォルダをリポジトリとして使用し、そこを同期対象外にすればいいのかな。

もうひとつ興味深い記事を見つけたのでこれもメモ。
Git and Mercurial - Compare and Contrast

自分のメールアドレスから来るスパム。

自分は WAKWAK にもアカウントを持っていて、Google のアカウントを作る前はそちらがメインでした。メーリングリストやネットニュースなどはそちらのアカウントで利用してたりしたんですが、もうほとんど使っていません。ただ、第2メールアカウントとして念のために残している形です。そのあたりでのメール構成は bogofilterのデータベースの再構築。 でもちょっと触れています。

そして、~/.mailfilter にてふるい分けから生き残ったメールは、すべて gmail のほうに cc しています。

今回、bogofilter をすり抜け、gmail のスキャンにて怪しいと判定されたメールが届きました。

メールヘッダは下記のようになっていました。
Received: from xuqolaze.com (ip116-13.metrotvnews.tv [103.61.116.13] (may be forged)) by xx.wakwak.com (8.15.2/8.15.2/2018-12-07) with SMTP id x2QNvKOQ022049 for <xxxxxx@xx.wakwak.com>; Wed, 27 Mar 2019 08:57:25 +0900
Received: from unknown (56.35.236.179) by mx.reskind.net with SMTP; Tue, 26 Mar 2019 19:45:10 -0400
Received: from [154.42.37.249] by smtp.mixedthings.net with SMTP; Tue, 26 Mar 2019 19:29:30 -0400
Received: from nntp.pinxodet.net [161.31.175.115] by relay-x.misswldrs.com with NNFMP; Tue, 26 Mar 2019 19:29:01 -0400
Message-ID: <EC540080.1D3DBBF0@xuqolaze.com>
発信元のタイムゾーンは -0400 で、これは大西洋標準時(あるいはアメリカ東海岸時間)で、アメリカの東の一番端っことかカナダのケベック州、ブラジルの一部というあたりです。ただ、これがただちにSPAMの送信者かどうかはわかりませんが。

で、本文の冒頭には、
Hello,

As you may have noticed, I sent this email from your email account (if you didn't see, check the from email id). In other words, I have full access to your email account.

I infected you with a malware a few months back when you visited an adult site, and since then, I have been observing your actions. The malware gave me full access and control over your system, meaning, I can see everything on your screen, turn on your camera or microphone, and you won't even notice about it. I also have access to all your contacts.

とありました。まあ、メールアカウントにフルアクセスされたとしても、それうちのサーバじゃないしで済んじゃうんですが。

内容的には「あなたがPCでビデオを見ている様子を、あなたのPCのウェブカムで撮影したので、これをバラされたくなければビットコインアカウントに905ドル振り込め」という極めて幼稚な振り込め詐欺です。

もう一度書きますけど、メールアカウントにフルアクセスされたとしてもそれうちのサーバじゃないのでうちのシステムには入れないし、そもそもうちのシステムにはウェブカムついてないし。
でもって最後に
Filing a complaint will not do any good because this email cannot be tracked. I have not made any mistakes.

If I find that you have shared this message with someone else, I will immediately send the video to all of your contacts.

Take care!
だそうで、まあなんというか。Google のアカウントが侵入されたなら慌てもしますが、これじゃあ慌てろという方が無理のような。

RLogin+OpenSSH+Nyagosで画面が消去される件。

OpenSSH for Windows と RLogin でシェルに Nyagos を指定しているのですが、接続直後になにかメッセージを表示した後で消去され、Nyagos の開始メッセージが表示されます。

なにが表示されているのか気になったので、RLogin で起動直後からログファイルに吐き出すようにしてみました。

Buon Giorno!
This is SSH server CHIYO7000.
Have fun!
\e[2J\e[?25l\e[m\e[H

\e[H\e]0;c:\apps\nyagos\nyagos.exe \g\e[?25h \e[H\e[?25lNihongo Yet Another GOing Shell 4.4.1_1-windows-amd64 by go1.11.5\e[66X\e[66C
(c) 2014-2019 NYAOS.ORG \e[85X\e[85C

最初の3行は、OpenSSH に出力されるようにした Welcome メッセージです。デフォルトの英語と区別しやすいように挨拶はイタリア語にしてあります。

そのあと、以下のようにエスケープシーケンスを出力しています。エスケープシーケンスはエスケープシーケンス一覧を参照しました。
  1. \e[2J - 全画面消去
  2. \e[?25l - カーソルを非表示
  3. \e[m - すべての文字属性を解除
  4. \e[H - カーソルを原点に移動(?)
ここまではたぶんOpenSSHからの出力でしょうか。次にNyagos前後です。
  1. \e[H - カーソルを原点に移動
  2. \e]0;c:\apps\nyagos\nyagos.exe \g - ウィンドウタイトルを "c:\apps\nyagos\nyagos.exe" に変更
  3. \e[?25h - カーソルを表示
  4. \e[66X - 現在のカーソル位置から66文字消去
  5. \e[66C - カーソルを66桁右に移動
  6. \e[85X - 現在のカーソル位置から85文字消去
  7. \e[85C - カーソルを85桁右に移動

エスケープシーケンスのみ抜き出してみましたが、特に意味のあることはやっていないようです。が、最初の全画面消去はいらない気がします。SSHで接続しているんだから、むしろ残しておいてほしい感じです。残す方法があるのかどうかはちょっと調べてみます。

Mercurialのサブリポジトリ。

最近はずっと Mercurial を使っているのですが、うかつにも CVS と同じような気持ちで、リポジトリツリーの下にリポジトリを作ってしまいました。言ってみれば、入れ子のリポジトリです。

ところが TortoiseHG の "View File Status" や Workbench の表示がうまくいきません。あるはずのファイルがリストに表示されなくなってしまいました。

Mercurial には入れ子のリポジトリである Subrepository という機能があるようです。ところがそのページには、"This is considered a feature of last resort." と書かれています。最後の行楽地(楽園?)という意味ではなくて、"last resort" は「最後の手段」というような意味になります。"a weapon of last resort" というのは「最終兵器」のことだそうで。ということで、「サブリポジトリというのは最後の手段なので、できるだけ使わないほうがいい」ということのようです。

ちなみに Mercurial で Last Resort と考えられているのは、"Subrepositories"、"largefiles"、"keywords"、"EOL translation"、"Static HTTP" の5つのようです。
These features are all at odds with Mercurial's core design, and will therefore always present some difficulties in terms of performance, ease of use, and integration. As such, when using them, you won't get the best possible Mercurial experience. Due to our compatibility rules, these features will continue to exist — but we want to make you aware that there are often better alternatives.

互換性の観点から機能としては存在し続けるけど、もっといい方法があるはずなのでそっちを検討して、ということのようです。subrepository については、
3. But I need to have managed subprojects!
Again, don't be so sure. Significant projects like Mozilla that have tons of dependencies do just fine without using subrepos. Most smaller projects will almost certainly be better off without using subrepos. This is not true for all projects, however, so we've made them available as an option. Be sure to follow our recommendations for best results.
Mozilla みたいな何十もの依存関係をもつ重要なプロジェクトでも、一つのリポジトリでうまくやってるし、ほとんどの小さいプロジェクトはサブリポジトリを使わないほうがうまくいくはずだし、すべてに当てはまるわけではないから機能としては利用できるようにするけど、推奨する方法も検討してみて、という感じ。

ということで、サブリポジトリは使えるけど、使わないほうがいいよということのようです。

参考までに引用しておくと、main リポジトリの下に nested リポジトリを作成する場合には、
$ hg init main
$ cd main
$ hg init nested
という構造にしておいて、次に nested を ".hgsub" ファイルに記述します。
$ echo nested = nested > .hgsub
$ hg add .hgsub
'=' の左側がワーキングディレクトリ、右側がソースの参照元(pull元)です。

それはさておき。
となると、入れ子に作ってしまったリポジトリを、変更履歴をそのままに親に統合する方法を探るのがよさそうです。探したら、StackOverflow で2つほど引っかかりました。How to combine two projects in Mercurial?Merge two mercurial repositories without breaking file history です。

これによれば、親リポジトリにて hg pull --force [subrepo] するということのようです。Mercurial Wikiにも説明がありました。MergingUnrelatedRepositories
これによれば、「つじつまの合わない履歴になる可能性があるから推奨はできないけど、以下のようにすればできるよ」ということで、
hg clone REPO1 work         # First pull from both repos...
 cd work
 hg pull -f REPO2
 hg merge                    # Then simply merge.
 hg commit
その一方で、
On the other hand, if you're doing this in order to stop using two separate repositories, just hg push REPO1 and you're finished.
ともあり、REPO2(子供)のほうから REPO1(親)に push するだけでいいよ、だそうです。

hg serveで日本語が化けた件。

hg serve で Mercurial の HTTPインタフェースが使えるということを聞いて、早速やってみたところ、日本語が文字化けしていました。

Chrome でページソースを眺めると、diffstat で「更新ファイル数」とか「追加 xx行」とかの部分が化けているようです。この部分の文字エンコーディングは ShiftJIS になっているようでした。ただ、ページの言語を ShiftJIS に直したとしてもコミットメッセージなどは(日本語の場合には) UTF-8 で書いているので化けることは化けます。

ローカルで立ち上げたページには http://localhost:8000/help/config というヘルプページがあるのですが、これがまた日本語表示されてるっぽいけど文字化けしています。上記と同様です。ちなみに環境変数 LANG は "ja_JP.UTF-8" を指定しています。

ということで Mercurial のドキュメントを見てみると、どうやら ~/.hgrc に "[web]" というセクションを作り、そこに "encoding = UTF-8" と入れることで文字エンコーディングを指定できるようです。
早速試してみると文字化けが直りました。

--追記--
実はこれだけではだめっぽくて、全部 UTF-8 で動かすには環境変数 HGENCODING=UTF-8 を指定する必要があるようです。また、UTF-8 ファイル名を使いたい場合には fixutf8 エクステンションを組み込む必要があるようですが、3年前に更新が停止しているようです。
それから、HGENCODING の設定は、ロケール指定の "ja_JP" をつけるとエラーになりました。どうやら "UTF-8" のみでいいようです。

--追記の追記--
HGENCODING=UTF-8 すると、hg help の日本語表示が化けるようになってしまいました。
ちょっとこのあたり、デタラメを書いてる可能性もあるので、内容をちゃんと確認していく予定です。

最終的にMSYS2へ。

Windows上でのUNIX系ツールですが、なんだか常に紆余曲折というかフラフラしているので、自分なりの考え方をまとめておこうと思います。ということで自分用メモ。1年後に「あれ?どうしてこっちを選んだんだっけ?」とかならないように。

やりたいことと前提条件。
  1. Windows の CMD.EXE 上で 'ls' や 'grep' したい。
  2. Neovim/Vim をコンソールでも使いたい。
  3. Windows 上で zsh を使いたい。
  4. できれば タイリング型コンソールで作業したい。でもって zsh か Nyagos なんかがその上で動けば素敵。
  5. Neovim/Vim では Denite.nvim なんかも使いたいので Python3 は必須。
  6. Neovim/Vim のプラグイン管理で Dein.vim を使っているので、Git が使えないとまずい。
  7. LaTeX は TeXLive のものを使う。
  8. Python3 は公式のものを使う。
  9. Perl はなんでもいいけど、Neovim/Vim の Dein.vim で使う Git がちゃんと使えること。
Git リポジトリを Python から使う Dulwich (ダルウィッチまたはダリジ)というプロジェクトもあるようで、もしかしたらこれでもいいかもしれません。が、Dein.vim は Git を要求しているようです。

4の項目があるので、「タイリング型ターミナルエミュレータでSHELLを指定できるもの」かつ「256色表示可能であること」の条件で、RLogin を使うことは既定です。そして、OpenSSH for Windows を使えば SHELL を変更することができて、RLogin から Nyagos を呼び出して使うことができることは確認済みです。なので、これまで SSH サービスを動かしていた Cygrunserv は不要になります。

これまで Cygwin64 を使っていましたが、そういうわけで積極的に Cygwin64 を選択する必要はなくなりました。
すると、MSYS2 と Cygwin64 と Git for Windows が横並びになるわけですが、
  • Cygwin64
    • cygwin-1.dll を必ず呼び出す必要がある。
    • C:ドライブを指定する場合に /cygdrive/c などの形式になる。
    • cygdrive の部分は /etc/fstab で変更できる。
    • Dein.vim での動作で Git でのパスの扱いがうまくいかなかった記憶がある。
    • パッケージマネージャは setup
  • MSYS2
    • Windows ネイティブバイナリと msys-2.0.dll を呼び出すバイナリがある。
    • C:ドライブを指定する場合に /c という形で参照できる。
    • パッケージマネージャは pacman
  • Git for Windows
    • MSYS2 と同じだが、同梱の msys-2.0.dll を呼び出すため、MSYS2 とは共存しないほうがよい。
というような感じでしょうか。

なので MSYS2 に切り替えてしばらく様子見です。

MercurialとPython3。

https://www.mercurial-scm.org/wiki/Python3によれば、
1. Status
We have been testing by installing default mercurial on our system using Python 3. Most of the things work correctly. Things which don't work can be found at BetaBugs section below.

We are planning to mark hg 5.0 which is scheduled for May 1 as Python 3 beta release.
だそうです。

Bloggerでhighlight.jsを使う。

BloggerでSyntaxHighlighterを使う。SyntaxHighlighter を使ってみているんですが、どうも重たいようなので、軽いと評判のhighlight.jsに切り替えてみようかな、と思いました。

Usageを参照するといろいろと使い方が書いてあり、Getting highlight.jsに詳細の説明があります。CDNJS からホスティングされているようなので、このままいけるかな。
CDNJS を使う場合には、以下のコードを </head> タグの前に入れてやればいいようです。
<link rel="stylesheet"
      href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
実際には CDNJS からスクリプトタグとしてコピー&ペーストしていく形になります。
必要なのは、CDNJSのリストで一番上にある highlight.min.js。それから languages にある言語設定ファイル、下の方にある styles のスタイルファイルになります。
スタイルファイルのデモは、highlight.js demoにあるので、好きなスタイルを選べばよいでしょう。
最後に initHighlightingOnLoad() を呼び出します。

<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/highlight.min.js" integrity="sha256-aYTdUrn6Ow1DDgh5JTc3aDGnnju48y/1c8s1dgkYPQ8=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/styles/tomorrow-night-eighties.min.css" integrity="sha256-VeRq5fe7DQWoI4BTnuxQBub1iKtAtH4J69kUO3fD288=" crossorigin="anonymous" />
<script>hljs.initHighlightingOnLoad();</script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/languages/bash.min.js" integrity="sha256-zXrlim8wsIvcEFjsD3THiAfTvtPZifqx8q0rxegiWQc=" crossorigin="anonymous"></script>

こんな感じで用意しておいて、これを使います。"integrity" のところは、万が一 CDNJS で改竄された場合にセキュリティを確保するために入れています。
これでできるかな?

以下に highlight.js の pre でコードを載せてみます。
#include <stdio.h>
void main(void) {
    printf("Hello, World!\n");
}
どうやらちゃんと機能しているようです。
ただ、行番号についてはポリシーとしてサポートしていない、ということが説明されていました。

まとめてみると、
  • Crayon Syntax Highlighter
    ツールバーが出てコピーコードなどが利用できる。機能がリッチ。でも重たい。
  • SyntaxHighlighter
    ツールバーが出ない。コピーはマウスでセレクト&コピー。行番号が使える。
  • highlight.js
    シンプルでとても軽い。でも行番号もツールバーも出ない。
という感じでしょうか。

VSCodeで整形する。

テキストファイルの整形というと二種類あって、72桁で並べ替える、というようなものと、特定の記法に従ってプログラムの論理構造を整理する、というようなものに分かれます。

72桁の方はぶら下がり、追い出し、ハイフネーションなどなどいろいろな処理があります。一方プログラムの方は、それぞれの言語で推奨されるコーディング規約であったりプロジェクトでの決まりであったりといろいろと方言があります。

で、話は変わって、これまではここで SyntaxHighlighter を使ってコードを表示するようにしていました。これは CDN を利用することで、外からコードを引いてきてブラウザ側で整形させるというものです。

でもやっぱり WordPress を使っていたときの Crayon Syntax Highligher のほうがいいなと思うので、ちょっとあがいてみることにしたんですが…。

Cryayon Syntax Highlighter for Bloggerのページにそれっぽいことが書いてあったので、まずはそこから crayon-min.css をダウンロードして中身を見てみることにしました。が…改行コードが入っていない css ファイル…。

そこで、それを一旦保存して、VSCode で整形してみることにしました。(もちろん Neovim とかでもいいんですが)
VSCode で読み込んで折返しをやめたところです。読みづらいです。

そこで、 ALT + SHIFT + F(VSCode の整形ショートカット) を押します。すると、画面右下にポップアップがでました。
なにそれすごい、という感じです。「できません」じゃなくて「インストールする?」というのはすごく親切。早速 "Install Formatter" ボタンをクリックすると、
こんなん出ました。
一番上の "CSS Formatter" は 22万以上もダウンロードされていて☆4つです。特にこだわりもないのでこれにしてみます。

インストールしたので、再度 ALT + SHIFT + F してみると、サッ!と整形してくれました。先頭のコメント部分はそのままでしたが。
いくつかエラーも出ているようですが、これで読みやすくなりました。

こて先クリーナーの真鍮たわし。

はんだごては白光の FX-951 を使ってるんですが、これは標準ではこて先クリーナーとしてスポンジが付属しています。ただ、水を含ませたスポンジではクリーニングする際にもこて先が冷えてしまい、なかなかきれいになりません。そこで自分は 599B という天文ドーム型のものをセットで購入して使用しています。ついでに言えば FA-400 という吸煙器も購入しています。

ところでこの 599B ですが、中に真鍮製のクリーニング用たわしが入っています。真鍮製なのはこて先に傷をつけにくいからで、真鍮(黄銅)の柔らかいたわしで汚れをこそげ落とす格好で使います。このたわし、使っているとだんだんと体積が減ってきてへたってしまうのですが、ときどきもみほぐしてちゃんと汚れが落ちるようにする必要があります。いよいよだめになってきたら交換するのですが、1つで300円弱と、わりと高いのです。

真鍮たわしということはわかっているので、同等のものならいいじゃん、と思って調べてみると、スチールたわしの有名所のボンスターがカールケートゴールドというのを出していました。30g と 50g があるようなので、599B のたわしを測ってみるとぴったり 30g でした。これだと、モノタロウでは119円です。モノタロウでは3500円以上の買い物で送料無料になるので、今度なにかあったときに合わせて注文してみようと思います。

VSCodeでPICのプロジェクトを編集する。

MPLAB X IDE + MCC で作成したプロジェクトを、Visual Studio Code でいじろうとしたときに、インテリセンスとエラーチェックでたくさん引っかかってきたので設定を変更したお話。

VSCode でワークスペースにプロジェクトディレクトリを追加して、そのワークスペースのプロパティをいじることでインクルードなどをプロジェクト単位で設定できます。

プロジェクトごとに MCU は違ったりするので、必要に応じて書き換える必要がありますが、以下のようにすることでインテリセンスが静かになりました。
  • まず、プロジェクト直下に ".vscode" というディレクトリを作成します。
  • そこに "c_cpp_properties.json" という名前でファイルを作成します。
  • 以下の内容を "c_cpp_properties.json" に保存します。

{
    "configurations": [
        {
            "name": "XC8-2.05-c99",
            "includePath": [
                "${workspaceFolder}",
                "C:/Program Files (x86)/Microchip/xc8/v2.05/pic/include",
                "C:/Program Files (x86)/Microchip/xc8/v2.05/pic/include/c99"
            ],
            "defines": [
                "__XC8",
                "__PICC__",
                "_16F18346"
            ],
            "intelliSenseMode": "gcc-x64",
            "browse": {
                "path": [
                    "${workspaceFolder}",
                    "C:/Program Files (x86)/Microchip/xc8/v2.05/pic/include",
                    "C:/Program Files (x86)/Microchip/xc8/v2.05/pic/include/c99"
                ],
                "databaseFilename": "",
                "limitSymbolsToIncludedHeaders": true
            },
            "cStandard": "c99",
            "cppStandard": "c++17"
        }
    ],
    "version": 4
}

参考にしたのはc_cpp_properties.json Reference Guideです。

このうち、XC8 のバージョンによってディレクトリ名が変わるのでその部分と、"defines" の中で MCU 名を定義しておかないと適切にマクロを展開してくれないので、プロジェクトごとに見直す必要があるでしょう。

Python.orgのバグトラッカー。

バグトラッカーというか、イシュートラッカーとしてサーバなしで使えるようなのはないかな、と考えて、ふと Python.org は何使ってるんだろうと見てみたところ、Roundup Issue Tracker というのを使っていました。

Issue というのは「問題、課題」のことで、「認識され、分析され、解決されるべき事柄」という意味に取れると思います。イシュートラッカーというのはこの3つのステップをそれぞれ管理できることが最低限必要だと考えますが、Roundup ではどこまでできるのでしょうか。
  • bug tracking and TODO list management (the classic installation)
  • customer help desk support (with a wizard for the phone answerers, linking to networking, system and development issue trackers)
  • issue management for IETF working groups
  • sales lead tracking
  • conference paper submission and double-blind referee management
  • weblogging (well, almost :)
インストールの必須要件には、特に難しいことは書いていません。
Python 2.7以降(ただし3ではない)と anydbm モジュール、だそうです。ただし、64bit Windows の場合には、32bit Pythonのインストールが必要とのこと。なぜなら Roundup のインストーラは 64bit Python のレジストリキーを検出できないから、だそうです。

オプションとして、pytz(タイムゾーン定義)、RDBMS(MySQLなど)、全文検索などなどがあるようですが、基本的には PyPi からインストールするだけ、みたいです。

Roundup はいくつかの分離したパーツに分かれているようです。Roundup trackers がコア部分、Roundup support code(たぶんライブラリ?)、Roundup scripts が e-mailゲートウェイ、HTTPサーバ、管理ツールなどです。

ていうか、Python 2.7 ですか。うーん。

RLogin+Nyagosで遊んでみる。

Windows 10 1809とOpenSSH。その2で、OpenSSH for Windows をサービスとして起動し、そのうえで sshd から起動するシェルを Nyagos にしてみました。

RLogin にこだわっているのは、
  • タイリング型のコンソールエミュレータなので、一つのウィンドウで複数のコンソールが同時に見られる。
  • ConEmu ではできない 256 カラーモードがちゃんと表示できる。
という点です。
しかも RLogin はタイリング型でかつタブ型です。複数のコンソールの切り替えを上部のタブでできるし、コンソールの中で nvim などの CUI ベースのエディタを開いて作業することもできます。かつ、256色表示ができるので nvim の colorscheme も自由に設定できます。

256色表示は ConEmu でもできないことはないのですが、これを有効にするとスクロールバッファがとれないという制限があります。スクロールバーで逆スクロールするとカラー表示がリセットされてしまうのと、nvim のファイルタイプごとの設定や強調表示もうまく反映されません。

ただ、コマンドプロンプトの色が赤いのは「管理者モード」で Nyagos が動いている状態なので、これを通常モードで動かす方法を現在模索中です。UNIX でいえば root ログイン状態ですから、いろいろとやばいので。

MPLAB X IDEにDoxygenを組み込む。

プログラムのドキュメンテーションというと、まず最初に Doxygen が思い浮かぶ人も多いかと思います。もちろん pydoc や Javadoc という、言語固有のツールもあるわけですが、そうは言っても C言語だと Doxygen が最も多く使われているのではないでしょうか。

C に限らず、ソースコードはコメントやメモをしっかり残しておかないとあとでわからなくなるというのはよく言われていることで、そういう点でもコミットする際にはその都度、ある程度コメントを整備したり、API リファレンスを作ったりしておかないと、あとでまとめてやろうとしてもすでに記憶の彼方で「あれ、なんでこんなことしてるんだっけ?」というのが出てきたりします。

ということで MPLAB X IDE で Doxygen を使うためのセットアップを行います。

まずはプラグイン。

"Doxygen Integrator" というのがあるので、これを選択してインストールします。インストールが終わると IDE の再起動が求められるので、再起動します。

次に Doxygen とツール類のインストールです。
Doxygen はダウンロードページから GUIベースのインストーラが提供されていて、これは64bit版も含んでいるようです。
関数などの依存関係のグラフは GraphViz で描画しますので、必要があればダウンロードしてインストールします。現時点では graphviz-2.38.msi があるようです。

Doxygen の Installing the binaries on Windowsを見ると、GraphViz は推奨、また PDF 出力まで行いたければ LaTeX と Ghostscript もインストールしましょうと書いてあります。

インストールが終わったら、IDE のプラグインの管理ページで設定を行います。"Tools" → "Options" → "Plugins" で、"Doxygen Integrator" のタブです。

ここでは Doxygen の exe ファイルを指定しておけばOKです。

Doxygen をインストールすると、"Doxywizard" というウィザード形式の GUI フロントエンドもインストールされるので、これを使ってプロジェクトの設定などを行い、Doxyfile という config ファイルをプロジェクトごとに作成しておけば、そのとおりに生成してくれます。さらにここではプロジェクトロゴも指定できるので、必要があれば指定します。

Doxygen でのドキュメントの生成は、IDE からだとプロジェクトを右クリックして現れるメニューから "Create Doxygen" を実行します。

html ファイルと一緒に latex ファイルも生成してくれるようなので、LaTeX(TeXLive)が適切にインストールされていれば make.bat で PDF まで生成してくれます。
あとはドキュメントを書いていくだけです。

Cygwin64からMingw-w64に引っ越す。

OpenSSH for Windows を使って Nyagos が RLogin 上で動くなら、もう Cygwin64 は不要です。でもそうは言っても 'ls' とか 'zsh' とか 'diff' とかは使いたいし、テキストファイルを加工したり自動処理したりするのは UNIX 系のツールに軍配が上がります。
Pythonとか使えばいいじゃん、というのは置いといて。

もうひとつ、Cygwin64 ではプロセスを表示する 'ps' コマンドが、Cygwin 上のものしか対象にしていない、というのもちょっと不便なところ。Mingw-w64 にしたら Windows のプロセスも見えるのかどうかはわかりませんが。あと、Neovim の 64bit Qt GUI をビルドするのも Cygwin ではできません(と思った)。

Mingw-w64 では zsh は用意されていないようだけれど、なければビルドすればいいじゃん、ということで Cygwin64 から乗り換えです。

まず、mingw-w64のサイトからインストーラをダウンロードします。

いきなりいろんなバージョンがあって、頭の中はパニックです。どれがいいの?
2018年9月17日に、Mingw-w64 の バージョン 6.0.0 がリリースされていますが、上記ダウンロードページでは、MingW-W64-builds は GCC / Mingw-w64 Version が 7.2.0/5.0.3 となっています。まあ別に最新バージョンじゃなくても使えればいいんですが。

MSYS2 は、Mingw-w64 とは似て非なるもので、Mingw-w64 が Windows バイナリを生成するのに対して、MSYS2 は MSYS2バイナリを生成します。するとやっぱり 'ps' でプロセスが表示されない、という問題は残りそうなので、ここは MingW-W64-builds を使うことにします。するといきなり SourceForge へのリンクが出てきて、そこをクリックすると MinGW-w64 - for 32 and 64 bit Windowsのページに飛んで、ダウンロードが始まります。

ダウンロードしたインストーラを起動すると、バージョン(たぶんgccのバージョン?)とかアーキテクチャとかスレッドとか例外とかを選択するダイアログが出てきます。ここは以下のように設定しました。
スレッドが win32 なのは、Qt が Win32 スレッドをサポートしているようだ、という情報を見つけたからです。できればなるべくネイティブのほうが嬉しいので。

Next を押すとインストールパスが出てきますが、ここは自分環境なので c:\Appsの下に入れてしまいます。ちょっとパスが長いですが。

すると、インストールするファイルをダウンロードしてきて、7zip で指定された場所に展開するようです。


終わりました。
PATH の通っている c:\cygwin64c:\cygwin64-- などとして PATH から除外してからコマンドプロンプトを立ち上げてみると、gcc のバージョンは 7.1.0 でした。え?てっきり8.1.0だと思ったんですが…。まあいいけど。

何がインストールされたのか、を確認してみたら、bunutils と gcc だけのようで、bash はおろか make すらありません。あれれ、そういうもんだっけ?
ちょっとどうすればいいのか、考えてみます。

Windows 10 1809とOpenSSH。その2

OpenSSH for Windowsのインストールが終わり、サーバが起動しているので早速ログインしてみます。ちなみにインストール編はこちら
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

PS C:\Users\kats> ssh kats@localhost
Windowsのパスワードでちゃんと入れました。なんかいきなり管理者モードになったコマンドプロンプトが出てきましたけど。

次に鍵とパスフレーズで入れるかどうか試してみます。
まずは「サービス」メニューから "OpenSSH" を停止して、sshd_config をいじります。
# To disable tunneled clear text passwords, change to no here!
-#PasswordAuthentication yes
+PasswordAuthentication no
 #PermitEmptyPasswords no
としてパスワードを禁止します。このファイルは管理者モードでないと編集できないので、一旦デスクトップなどにコピーしてそれを編集し、コピーで戻せばよいでしょう。
変更し終えたら「サービス」から "OpenSSH" を起動して接続してみます。
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

PS C:\Users\kats> ssh kats@localhost
kats@localhost: Permission denied (publickey,keyboard-interactive).
いきなり拒否されました。あふん。

サービスを一旦停止して sshd をデバッグモードで起動します。
接続してみるとエラーで弾かれますが、ログをみるとどうやら authorized_key が見つからないから追い返しとくね、みたいな感じです。

ということで、Windows 用に鍵ファイルを生成してみました。
$ ssh-keygen -t ed25519
現時点で最強といわれる Ed25519 を指定します。
ちなみに鍵ファイルの置き場所は %USERPROFILE%\.ssh でいいようです。

生成された鍵ファイルのうち、id_ed25519.pub の内容をそのまま authorized_keys ファイルにコピペします。まだ存在していなければ、ファイルを丸ごとコピペして名前を変えればOKです。

これでパスフレーズの入力プロンプトが出てきて、接続できました。

ただ、authorized_keys のユーザ名はログインしたいシステムのユーザ名と一致している必要があるようで、もしも Windows と UNIX のユーザ名が異なっているとログインできません。とりあえず RLogin などを使いたいだけならばそれでいいのかもしれませんが、UNIX系と共通で鍵ファイルを使いたいときには困ったことになります。
ともあれ、Windows上で鍵ファイルを生成してログインはできるようです。

そこからもう一歩進んで、シェルを変更してみます。

Configuring the default shell for OpenSSH in Windowsを見ると、レジストリに登録することでシェルを変更することができるようです。なのでこれを Nyagos に変更してみます。
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force
となっているのを、
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Apps\nyagos\nyagos.exe" -PropertyType String -Force
にしてみます。

コンソールをキャプチャしてもわからないので貼りませんが、結論から言うと問題なくできました。これで RLogin で Nyagos が使えるようになりそうです。一応タスクマネージャーでは以下のようになっていました。
Naygos と ssh がコンソールの下にあるのがわかると思います。

ここまでできたらあともう一歩です。
RLogin を起動して、サーバエントリを追加します。
これで接続すると…

リサイズなどでモニョモニョっと動いたりしますが、ちゃんとこれで動いています。特に動作がのろいということもないようです。
ただ、プロンプトの色が赤いことから分かる通り管理者モードになっています。これは多分 sshd_config でなんとかしないといけないんだと思いますが、これはまあそのうち。

Windows 10 1809とOpenSSH。

Cygwin を使って、Windows 上での sshd の動作を見ていたんですが、コンソールから whereis したら、
$ whereis sshd
sshd: /usr/sbin/sshd.exe /mnt/c/WINDOWS/System32/OpenSSH/sshd.exe /mnt/c/Program Files/Git/usr/bin/sshd.exe /usr/share/man/man8/sshd.8.gz
などと出てきてびっくり。
Git はともかく、自分では Cygwin 以外に OpenSSH をインストールした覚えはないのに、なぜか \Windows\System32\OpenSSH なんていう場所にあります。なにそれという感じです。

調べてみると、Installation of OpenSSH For Windows Server 2019 and Windows 10というページが見つかりました。
Windows 10 1809 と Windows Server 2019 ではインストール可能な機能として構成されるようになった、みたいなことが書いてあります。

SSHクライアントの方は 1809 でインストールされているようですが、SSHサーバのほうは明示的にインストールが必要なようです。
「アプリと機能」の中にある「オプション機能の管理」に進みます。

「機能の追加」をクリックします。
すると「OpenSSHサーバー」が出てきます。

インストールすると、上記のディレクトリにサーバが追加されました。
"sshd.exe" "sftp-service.exe" "sshd_config_default" という3つのファイルのようです。

…これ、もしかしてcygwinいらなくなるんじゃね?という思いがふつふつと。
RLogin とか ConEmu を使って自分の PC に SSH ログインしてシェルをタイリング(タブではなくて画面分割)できるコンソールで作業できるのでは。そもそも Cygwin の sshd を使ってログインしてもシェルとして Nyagos とかは使えなかったので、これは試してみる価値があるかもしれません。

ということで sshd_config_default を見てみます。
#HostKey __PROGRAMDATA__/ssh/ssh_host_rsa_key
#HostKey __PROGRAMDATA__/ssh/ssh_host_dsa_key
#HostKey __PROGRAMDATA__/ssh/ssh_host_ecdsa_key
#HostKey __PROGRAMDATA__/ssh/ssh_host_ed25519_key
どうやら c:\ProgramData\ssh 以下に鍵ファイルや設定ファイルがあるようです。そこを開いてみると、
いつインストールされたのかわかりませんが、すでに鍵ファイルなどがありました。しかも sshd_config ファイルまであります。
鍵の暗号方式にはいくつかの種類がありますが、RSA が使えるようになったので DSA はもはや不要、RSAでも2048bit以下はダメで、使うなら4096bit以上、それよりは ECDSA か、さらに強度の高い Ed25519 が推奨、ということになっています。
外部に晒す環境であれば、最低でも "PasswordAuthentication" は "no" にしなくてはいけませんが、まずは実験なのでデフォルトのままにしておきます。使えると分かれば "no" にします。

まずは Windows の「サービス」から Cygwin の sshd を起動しないようにします。うちの場合には Cygwin xinetd を停止して無効にしておきます。

次に、Initial Configuration of SSH Serverにあるように、PowerShell を管理者モードで起動して sshd をサービスとして登録します。
Start-Service sshd
# OPTIONAL but recommended:
Set-Service -Name sshd -StartupType 'Automatic'
# Confirm the Firewall rule is configured. It should be created automatically by setup. 
Get-NetFirewallRule -Name *ssh*
# There should be a firewall rule named "OpenSSH-Server-In-TCP", which should be enabled

コマンドプロンプトアイコンを右クリックすると「管理者として実行」というメニューが出るので、管理者モードのコマンドプロンプトを開いて PowerShell を起動していますが、ちゃんと登録できたようです。「サービス」を開いて確認すると登録されています。

どうやらインストールは終わったようなので、次は接続編です。

bogofilterのデータベースの再構築。

おうちサーバについてちょっと触れたのは、プロバイダ(wakwak)で受信するメールのSPAM振り分け処理をおうちサーバでやっているからなのですが、最近またこぼれて、というかすり抜けてくるSPAMメールが固定化されてきているので、データベースを作り直しました。

プロバイダ側にもSPAM検出の機能はありますが、注意していないとHAMの誤判定で大事なメールをロスト、とかあると困りますので、一旦全部フェッチする、という戦略です。

まず構成ですが、プロバイダ→おうちサーバのfetchmailでフェッチ→mailfilterでSPAM判定処理→受信箱 という形になっています。おうちサーバで courier-imap4 と courier-pop3 を動かし、受信箱は Maildir 形式です。
mailfilter(maildrop)では、特定のメールアドレスからのメールはSPAMフィルタに通さずにふるい分け、その他のメールは nkfで強制UTF-8化→mecabで分かち書き→bogofilterに通してSPAM判定→reformailでヘッダに細工→maildropでフォルダに振り分け という処理をしています。
判定自体はメールそのものには手を加えないので、すべて UTF-8 にしてから判定処理を行い、その判定結果を元のメールヘッダに追加することにしています。なので、bogofilter に学習させるときにも、すべて UTF-8 にしてから単語登録させています。

bogofilter は NetBSD の package システムでインストールする際に、
PKG_OPTIONS.bogofilter=tokyocabinet
して、検索用のデータベースは tokyocabinet にしています。

そこまではいいとして、じゃあ学習(training)はどうするか、ですが、以下のようなシェルスクリプトを使っています。

#!/usr/pkg/bin/bash

if [ $# -lt 2 ]; then
    echo "number of args: $#"
    echo "usage: `basename $0` [ham|spam] directories..."
    echo "at least two arguments must be specified."
    echo "The first argument must be one of [ham|spam],"
    echo "and the second must be directory, not file."
    exit 1
fi

DIC=/usr/pkg/lib/mecab/dic/jumandic
#DIC=/usr/pkg/lib/mecab/dic/ipadic
#DIC=/usr/pkg/lib/mecab/dic/naist-jdic

shopt -s nocasematch

if [[ $1 == "ham" ]]; then
    ARG="-n"
elif [[ $1 == "spam" ]]; then
    ARG="-s"
else
    echo "usage: `basename $0` [ham|spam] directories..."
    echo "the argument must be one of [ham|spam]."
    exit 1
fi

if [ ! -d $2 ]; then
    echo "usage: `basename $0` [ham|spam] directories..."
    echo "at least one directory must be specified."
    echo "and it must be directory, not file."
    exit 1
fi

shift

for dir in $* ; do
    for i in $dir/* ; do
        GUESS="`nkf --guess=1 $i`"
        case $GUESS in
        ISO-2022-JP)
            nkf -J -w $i | mecab -d $DIC -Owakati | bogofilter $ARG
            ;;
        Shift_JIS)
            nkf -S -w $i | mecab -d $DIC -Owakati | bogofilter $ARG
            ;;
        CP932)
            nkf -S -w $i | mecab -d $DIC -Owakati | bogofilter $ARG
            ;;
        EUC-JP)
            nkf -E -w $i | mecab -d $DIC -Owakati | bogofilter $ARG
            ;;
        UTF-8)
            mecab -d $DIC -Owakati $i | bogofilter $ARG
            ;;
        *)
            bogofilter $ARG -B $i
            ;;
        esac
    done
done
まあ無駄な処理、といか全部 nkf -w でいいじゃん、という話もありますが、一応日本語とそれ以外を分けたほうがいいかな、というのと、少しでも処理を軽くしたほうがいいかな、というのでこうしています。

時々こういう処理をしないと、誤判定のメールを再学習させてもあまり改善されず誤判定が繰り返されることがあるので、定常的に同じようなメールを誤判定することが続いたらデータベースを削除して作り直すことにしています。

ちなみに上記の学習をさせるために、SPAMメールもHAM(SPAMじゃない)メールもディスクの肥やしではないけれど保存してあります。ただ、SPAMメールで使われる単語などの傾向は年代によっても変わるようなので、もしも誤判定が増えたり同じメールを何度学習させても間違えるときにはデータベースの再構築が有効だと思います。

うちの場合にはSPAMが平均して月に1200通くらい配信されてきますが、bogofilterの学習には単語数で2000語以上、メール数で500以上は食わせたほうがよいようなので、最近3ヶ月程度を食わせれば十分です。

おうちサーバの功罪。

おうちサーバというのは、UNIX系で遊んでいた人にとってみればいわば憧れみたいなもので、自分でドメインを取得してサーバを立てて、メールとかウェブサービスとかどこからでも自宅にアクセスできるとか、まあそんな感じである意味自己満足の世界なわけですが。もちろん、自己満足だけじゃなくて有意義なサービスを提供したりしている人もいるでしょうけれど。

ただ、最近思うのです。おうちサーバの寿命について考えてしまうのです。

おうちでサーバを立てるということは、つまり管理者は自分。持続性はよほどのことがない限り一代限りです。
すると、そのサーバで提供していたサービスも、管理者の消滅とともに消えることになります。たとえそこに人類にとって有益な情報があったとしても。

自分も、憧れだったドメインを取得しておうちサーバを運用していますが、もしや外部のクラウドサービス的なものに切り替えられるならそのほうがいいのでは、などと考えてしまうこともあります。

ブログやWikiなどで書き溜めた情報もたくさんあります。技術的な情報は古くなると相対的に価値は低くなっていくものですが、一方で古い情報がなくなってしまうというのも問題があります。ファンタジー物などでよくある「古くから言い伝えられている禁忌」が忘れ去られて…みたいな感じで。それがいつ、どのような形で必要になるのかは現時点では判断できませんが、可能性ということで言えばどんな情報でも意味がないとは言えないでしょう。

そうすると、おうちサーバはあくまで「技術的な好奇心」を満足させ、あるいは向上させるのには有意義ですが、その成果はどこか永続的な場所に置いておくべきではないか、などと考えてしまうのです。

枯れた開発ツール。

PIC開発をしていて、最新の Microchip MPLAB X IDE 5.15 にアップグレードしてみたんですが、ICD3 の調子がおかしいのです。
まず、動作が異様に遅い気がします。これは書き込みもデバッグも。4.15 でやっていたときにはこんなことはなかったのですが。
それから MCU がフリーズします。正常に動作するときもあるし、しないときもあります。それまで動いていたコードが、build & write したら動かなくなったり。とにかく動きがおかしいのです。

そこで、アンインストールしていなかった 4.15 を使って書き込みしてみると、シュッと終わります。早いです。おかしいです。しかもちゃんと動きます。
もしかしたら ICD3 のファームウェアバージョンかもしれないと思ったんですが、ICD3 のファームウェアは単体ではダウンロードできないようで、過去のバージョンの MPLAB X IDE をダウンロード、インストールして書き換えないとだめなようです。

XC8 コンパイラと IDE のバージョンは特に関連はありませんが、ICD3 や PICkit3 などのデバッガ/プログラマのファームウェアと IDE との関連はあるようです。
ただ、XC8 も AVR にも対応?するようになったようで、ここはやっぱり 1.45 に戻しておこうと思います。
おそらくですが、AVR への対応を ICD3 ファームウェアに取り込んだことでなにか不具合が起きているのかもしれませんね。

過去のバージョンの IDE は、MPLAB Ecosystem Downloads Archiveから入手できるようになっています。

それぞれのバージョンでのファームウェアの場所は、C:\Program Files (x86)\Microchip\MPLABX\v4.xx\mplab_platform\mplablibs\modules\ext\ICD3.jar のなかにアーカイブされているようです。なので、この jar ファイルを展開してみればバージョンが分かります。
手元にある範囲では、

4.15 -> ICD3 FW 01.51.08
4.20 -> ICD3 FW 01.51.12
5.15 -> ICD3 FW 01.55.01

となっていました。

4.20 でやってみたところどうやら調子がいいようなので、5.15 はやめて 4.20 を使うことにします。やっぱり新しいバージョンというのはごにょごにょ。タイトルの「枯れた」というのは悪い意味ではなく、「十分に使われてバグ出しが終わっている」という意味です。

それにしても、開発ツール系のバージョンによる不具合というのは、わりといちばん最後まで可能性として考慮されないので、原因を探るのに思い切り遠回りしてしまいますね。

Cygwin 3.x。

3月5日に Cygwin 3.0.2 がリリースされたようです。

Cygwin version
The most recent version of the Cygwin DLL is 3.0.1.

Note that Cygwin version 2.5.2 was the last version supporting Windows XP and Server 2003. (Instructions for obtaining that version)

3.0.0のリリースは見逃していたんですが、WinXPをサポートしているのは 2.5.2 までで、2.5.2 の Cygwin をインストールするならこっちを見てね、だそうです。

What changed:
-------------

- Windows 10 1803 or later and WSL installed:

Starting with 3.0.0, mkdir(2) automatically created directories within
the Cygwin installation dir as case sensitive. This badly breaks
interoperability with remote machines trying to access these dirs.
Therefore, disable this as default. You can still create case-sensitive
dirs via `chattr +C ...'

3.0.2 では Windows 10 1803 以降でかつ WSL がインストールされている場合に、mkdir(2) でケースセンシティブなディレクトリ作成を行っていたのを、デフォルトではしないようにしたようです。3.0.0-1 のリリースノートはこれですかね。

鉄ユニクロネジ。

インパクトドライバで鉄・ユニクロネジが千切れたので、インパクトドライバでちょっと硬めの木にネジを打つときには、ステンレスのコーススレッドなどを使いましょう。
普通のドリルドライバならユニクロでもよさそうです。

ボッシュのコードレスインパクトドライバでネジが切れちゃいましたよ…とほほ。

CuriosityでmTouchを試してみる。その11 ボタンの詳細設定

正直、mTouch でここまでネタが続くとは思っていなかったんですが、結構奥が深いですね。

さて、ここまでやってきた mTouch ですが、現状の設定ではボタンをホールドすると裏で定期的に動いているキャリブレーションが働いて、「ボタンの容量が定常状態である」と判断し、「ボタンはタッチされていない」と判定されてしまいます。これは内部で MTOUCH_BUTTON_PRESSTIMEOUT に定義された回数のカウンタ値で動作しているようです。

ということで、MCC のドキュメントから、ボタンの詳細設定について和訳してみます。元のドキュメントはmTouch® Button/Proximity Sensor Configurationです。

The Button or Proximity Sensor is an abstraction layer over the physical sensor which decouples the signal acquisition module and the decoding module. The benefit of this abstraction is that, regardless of what acquisition method is being used for the sensor, the Button or Proximity Sensor decoding works the same way.

ボタンあるいは近接センサは物理センサ上の抽象レイヤで、信号取得モジュールとデコードモジュールを分離するものである。この抽象化の利点は、センサに対する取得メソッドがどうであれ、ボタンあるいは近接センサのデコードが同じ方法で動作することである。
(ちょっと意味がわかりません…)

Common Button/Proximity Sensor Configuration

Interface Method

The mTouch Sensing Solutions library allows your application code to obtain button/proximity sensor status in two ways: through a callback function or through polling. There are examples of how to use these two methods in the "Step by Step Example" section.

mTouchセンシングソリューションライブラリは、アプリケーションにボタン/近接センサの状態を利用できる2つの方法を提供する: コールバック関数またはポーリングである。「ステップバイステップ例」セクションにはこの2つのメソッドの利用法がある。

Press/Activation Timeout

Press/Activation Timeout is a mechanism used to release a stuck proximity sensor. If a button/proximity sensor is pressed or activated for a number of consecutive counts, the button’s or proximity sensor's state will be reset. Each button/proximity sensor has its own time-out counter to track the press time. The underlying press time-out counter will increment each time the MTOUCH_Service_Mainloop() call is performed. The counts parameter acts as a threshold to each button’s or proximity sensor's press time-out counter. Upon the time-out’s counter exceeding the counts value, the button/proximity sensor state will be reset.

プレス/アクティベーションタイムアウトは、近接センサが固まった(動作しなくなった)のをリリースするためのメカニズムである。もしボタン/近接センサが一定の連続カウント時間押されあるいは活性化されることが続いたときに、ボタンあるいは近接センサの状態がリセットされる。それぞれのボタン/近接センサは押下時間を測定するための独自のタイムカウンタを持っている。タイムアウトカウンタは MTOUCH_Service_Mainloop() が呼ばれるたびに加算される。(MCC設定の)カウントパラメータはそれぞれのボタン/近接センサのタイムアウトカウンタのスレッショルドとして振る舞い、タイムアウトカウンタがこのカウント値を超えた場合には、ボタン/近接センサの状態がリセットされる。

Negative Capacitance Recovery

Enabling this feature allows the quick recovery of a button’s or proximity's baseline if negative capacitance is detected. The negative capacitance means the baseline value is greater than the reading for a button. The consecutive decodes parameter specifies the number of consecutive decoding cycles (MTOUCH_Service_Mainloop() call) with negative capacitance that the program has to detect before resetting the button/proximity state.

この機能を有効にすると、負の容量が検出されたときにボタンまたは近接のベースラインを速やかに復帰させることができる。負の容量とは、ボタンの読み値よりもベースラインの値が大きい状態を指す。連続的なデコードパラメータは、プログラムがボタン/近接状態のリセットをする前に検出しなくてはならない連続した負の容量のデコードサイクル(MTOUCH_Service_Mainloop()の呼び出し)の数を指定する。

Reading Filter

To minimize the impact of impulse noise, the sensor output goes through a low-pass filter. The output of the filter is the reading of the button/proximity sensor. A higher filter level setting provides an improved signal-to-noise ratio (SNR) under noisy conditions while increasing the total time for measurement, possibly resulting in increased power consumption and response time.

インパルスノイズの影響を最小化するため、センサ出力はローパスフィルタを通過する。フィルタの出力はボタン/近接センサの読み値である。より高いフィルタレベルが設定されると信号-ノイズ比(SNR)を改善するが、ノイズの多い環境下での測定時間が増加し、おそらく消費電力と応答時間が増大する。

Deviation Integration Filter

To help the sensitivity of the proximity sensor, a deviation integrator is used. A larger gain value results in more sensitivity.

近接センサの感度を改善するため、偏差値積分が使用される。ゲイン値を大きくすると、感度が増大する。
(よく意味がわかりません)

Median Filter

To gain a greater SNR for the proximity sensor, a median filter can be used after the reading filter. The value of the median filter window decides how much historical data will be stored. Similar to the reading filter, a higher value provides more noise immunity but longer response time.

近接センサでより大きなSNRを得るために、読み値フィルタのあとでメディアンフィルタを使用することができる。メディアンフィルタウィンドウの値は、いくつの過去データを保存するかを決定する。読み値フィルタと同様に、高い値はノイズ除去に優れるが応答時間が伸びる。

Debounce

To prevent multiple detect events for a single touch action, a debounce algorithm is used. The algorithm works in a similar manner to debounce on a mechanical pushbutton. The Count parameter defines the number of consecutive touches that exceed the detect threshold. Once the consecutive touch count is exceeded the touch is reported as valid. If any single touch does not exceed the touch threshold while the debounce algorithm is running then the consecutive touch count is reset to and the debounce algorithm will restart. The debounce algorithm is applied to both touch/press debounce and release debounce for buttons/proximity sensors.

シングルタッチ動作での複数のイベント検出を防ぐため、デバウンスアルゴリズムが使用される。アルゴリズムはメカ的プッシュボタンのでバウンスと同様の働きをする。カウントパラメータは検出閾値を超えた連続タッチの数を定義する。連続タッチのカウントが閾値を超えたら、タッチが有効とレポートされる。デバウンスアルゴリズムが動作しているときにシングルタッチがタッチ閾値を超えない場合には、連続タッチカウントはリセットされてデバウンスアルゴリズムが再起動される。デバウンスアルゴリズムはボタン/近接センサでのタッチ/プレスデバウンスとリリースデバウンスの両方に適用される。

Suspend / Disable

Individual buttons and proximity sensors can now be suspended or disabled by application code.
  • Use MTOUCH_Button_Disable() / MTOUCH_Proximity_Disable() to disable a button / proximity sensor. A disabled button/proximity sensor will stop its sensor scanning and baseline updating.
  • Use MTOUCH_Button_Suspend() / MTOUCH_Proximity_Suspend() to suspend a button/proximity sensor. A suspended button/proximity sensor will stop its sensor scanning but will scan periodically for baseline updating.
  • Use MTOUCH_Button_Resume() / MTOUCH_Proximity_Resume() to reactivate a disabled/suspended button / proximity sensor. The button/proximity sensor will continue with the existing sensor configuration.

個々のボタンと近接センサはアプリケーションコードからサスペンドあるいは無効にできる。(以下略)

Reburst

Reburst is used to improve the system response time while resolving detect state for both buttons and proximity sensors. When a sensor threshold is exceeded, multiple measurements are taken on that sensor to resolve the detect status. Sensors that are not part of the AKSGroup or may be disabled to reduce the processing time. Three modes for Reburst are used:
  • Reburst All : No sensor suspension takes place, all sensors reburst to determine detect status.
  • Reburst Unresolved : Reburst sensors only part of same AKS Group, all others suspended (reduced processing).
  • Reburst None : standard acquisition only.

リバーストはボタンと近接センサの両方で状態検出を解決する際のシステム応答時間を改善する。センサ閾値を超えた際に、状態検出のために当該センサに対して複数の計測がなされる。処理時間を削減するために、AKSグループに属さない、あるいは無効化されたセンサ。リバーストには3つのモードがある。(以下略 - というか文章が不明瞭)

Hysteresis

Hysteresis provides a band gap for detect thresholds when moving between detect and no detect states. It is expressed as a percentage of the detect threshold. Once a sensor goes into detect, the threshold level is reduced (by the hysteresis % value). This prevents sensor dither in and out of detect if the signal level is close to original threshold level.

ヒステリシスは検出およち非検出状態の間で移行する際の検出閾値のバンドギャップを提供する。(以下略)

Individual Button/Proximity Sensor Configuration

Name

This input field allows you to modify the name of the selected button/proximity sensor. This name can be used in the code to reference this button/proximity sensor.

(省略)

Sensor

This selection box allows you to select a hardware sensor to be associated with this button. A hardware sensor can be associated with multiple buttons/proximity sensors. For example, if you want to achieve proximity detection and touch detection on the same physical sensor, this sensor can be associated with a button and a proximity sensor.

この選択ボックスはこのボタンに関連付けるハードウェアセンサを選択する。ハードウェアセンサは複数のボタン/近接センサに関連付けることができる。たとえば、近接検出とタッチ検出を同じ物理センサで実現したいときには、このセンサをボタンと近接センサの両方に関連付けられる。

Threshold

The signal deviation is defined as the difference between a button’s reading and the baseline value. The threshold input field allows you to determine the press threshold value for signal deviation before the button will be in the pressed state. The release threshold is 50% of the press threshold so that there is a hysteresis to release the button.

(省略)

Deviation Scaling

The signal deviation will be scaled down from a signed 16-bit integer to a signed 8-bit. If the deviation after scaling down is greater than 127, then the value will be clipped to 127 (0x7F). The deviation scaling parameter controls how many bits will shift to the right. The smaller the value is, the more sensitive the button will get. The goal is to shift the scaled-down deviation to be a value between 64 and 127 when the button is pressed, in order to get the full dynamic range.

(省略)

AKS Group

AKS® stands for Adjacent Key Suppression. In designs where the sensors are placed close together or configured for high sensitivity, multiple buttons might report a detection simultaneously. To allow applications to determine the intended single touch, the mTouch library makes it possible to configure multiple buttons/proximity sensors in an AKS group. When a group of buttons/proximity sensors is in the same AKS group, only the first strongest button/proximity sensor will report detection. The button/proximity sensor continues to report detection until its deviation or delta falls below its detection threshold. As long as this sensor is in the pressed state, no other button/proximity sensors in the same AKS group will report detection even if another button/proximity sensor's deviation becomes stronger in the same AKS group.

AKSとは隣接キー抑制のこと。センサ同士が近い状態に配置され、あるいは高感度に設定された場合、複数のボタンが同時に検出されたことをレポートするかもしれない。(以下略)

Individual Hysteresis

The common hysteresis levels can be replaced for each button/proximity sensor by activating the individual hysteresis checkbox. Then a hysteresis level can be selected from the dropdown menu. Other sensors will be assigned the common hysteresis level unless they are also modified.

共通ヒステリシスレベルは個別のヒステリシスチェックボックを有効にすることでボタン/近接センサごとに上書きできる。(以下略)

という感じでしょうか。以下略の部分は必要な人は頑張ってください。

CuriosityでmTouchを試してみる。その10 TIMER0編(2)

とりあえずなんとかできそうなアタリがついたところで、やってみたいと思います。

まずは mTouch CVD で AFA を有効にしたソースを生成します。このとき、TIMER4 や TIMER6 を使うので、プロジェクトに追加して適切に設定しておきます。
また TIMER2 の身代わりとなる TIMER0 も追加して、割り込みを有効にするように設定しておきます。

すると、mTouch 専用に 設定された tmr2.[ch] と、tmr0/4/6.[ch] が出力されているはずですなのでこれをいじります。同時に mtouch_sensor.[ch] もいじります。

まず最初に、生成されたファイルをコミットして差分が取れるようにしておきます。

次に tmr0.c を tmr2.c と同様の内容になっているかチェックします。すでに MCC で設定しているので、動作としては同じことができるはずです。もしも設定が違っていたら、データシートとにらみ合いながら修正します。

終わったら mtouch_sensor.c です。
tmr2.h をインクルードしているところを、tmr0.h に変更します。
TMR2_LoadPeriodRegister() は TMR0_Reload() に変更します。
TMR2 のところをすべて TMR0 に変更します。
また、T2CONbits.T2CKPS を T0CON1bits.T0CKPS に変更します。
diff -r d49f637e026f mcc_generated_files/interrupt_manager.c
--- a/mcc_generated_files/interrupt_manager.c Fri Mar 01 13:34:06 2019 +0900
+++ b/mcc_generated_files/interrupt_manager.c Sat Mar 02 08:50:47 2019 +0900
@@ -58,11 +58,7 @@
     }
     else if(INTCONbits.PEIE == 1)
     {
-        if(PIE1bits.TMR2IE == 1 && PIR1bits.TMR2IF == 1)
-        {
-            TMR2_ISR();
-        } 
-        else if(PIE1bits.TMR1IE == 1 && PIR1bits.TMR1IF == 1)
+        if(PIE1bits.TMR1IE == 1 && PIR1bits.TMR1IF == 1)
         {
             TMR1_ISR();
         } 
diff -r d49f637e026f mcc_generated_files/mtouch/mtouch_sensor.c
--- a/mcc_generated_files/mtouch/mtouch_sensor.c Fri Mar 01 13:34:06 2019 +0900
+++ b/mcc_generated_files/mtouch/mtouch_sensor.c Sat Mar 02 08:50:47 2019 +0900
@@ -37,7 +37,7 @@
 #include 
 #include 
 
-#include "../tmr2.h"
+#include "../tmr0.h"
 
 #include "mtouch_sensor.h"
 #include "mtouch_sensor_scan.h"
@@ -177,7 +177,7 @@
  */
 void MTOUCH_Sensor_Scan_Initialize(void)
 {
-    T2CONbits.T2CKPS = 0x0;
+    T0CON1bits.T0CKPS = 0x0;
 
     ADCON0 = (uint8_t)0;                            /* overwrite the ADC configuration for mTouch scan */
     ADCON1 = (uint8_t)( 0x1<<7 | 0x2<<4 | 0x0 );
@@ -311,9 +311,9 @@
     sensor_globalFlags.packet_done = 0;
     packet_noise = 0;
     
-    TMR2_SetInterruptHandler(Sensor_Acq_ExecuteScan);  /* Use timer2 to schedule the scan */
-    TMR2_LoadPeriodRegister(sample_period);
-    TMR2_StartTimer();
+    TMR0_SetInterruptHandler(Sensor_Acq_ExecuteScan);  /* Use timer0 to schedule the scan */
+    TMR0_Reload(sample_period);
+    TMR0_StartTimer();
     
     sensor_globalFlags.interrupted = false;
     
@@ -329,7 +329,7 @@
     } while(sensor_globalFlags.packet_done == 0);
 
 
-    TMR2_StopTimer();
+    TMR0_StopTimer();
     ADCON0 = ADCON0_temp;       /* restore the previous ADC configuration */
     ADCON1 = ADCON1_temp;
     ADACT = ADACT_temp;
@@ -630,4 +630,4 @@
     {
        mtouch_sensor[name].oversampling =  (mtouch_sensor_packetcounter_t)(value);
     }
-}
\ No newline at end of file
+}
diff -r d49f637e026f mcc_generated_files/tmr2.c
--- a/mcc_generated_files/tmr2.c Fri Mar 01 13:34:06 2019 +0900
+++ b/mcc_generated_files/tmr2.c Sat Mar 02 08:50:47 2019 +0900
@@ -55,8 +55,6 @@
   Section: Global Variables Definitions
 */
 
-void (*TMR2_InterruptHandler)(void);
-
 /**
   Section: TMR2 APIs
 */
@@ -71,17 +69,11 @@
     // TMR2 0; 
     TMR2 = 0x00;
 
-    // Clearing IF flag before enabling the interrupt.
+    // Clearing IF flag.
     PIR1bits.TMR2IF = 0;
 
-    // Enabling TMR2 interrupt.
-    PIE1bits.TMR2IE = 1;
-
-    // Set Default Interrupt Handler
-    TMR2_SetInterruptHandler(TMR2_DefaultInterruptHandler);
-
-    // T2CKPS 1:1; T2OUTPS 1:1; TMR2ON on; 
-    T2CON = 0x04;
+    // T2CKPS 1:64; T2OUTPS 1:1; TMR2ON on; 
+    T2CON = 0x07;
 }
 
 void TMR2_StartTimer(void)
@@ -116,28 +108,17 @@
    PR2 = periodVal;
 }
 
-void TMR2_ISR(void)
+bool TMR2_HasOverflowOccured(void)
 {
-
-    // clear the TMR2 interrupt flag
-    PIR1bits.TMR2IF = 0;
-
-    if(TMR2_InterruptHandler)
+    // check if  overflow has occurred by checking the TMRIF bit
+    bool status = PIR1bits.TMR2IF;
+    if(status)
     {
-        TMR2_InterruptHandler();
+        // Clearing IF flag.
+        PIR1bits.TMR2IF = 0;
     }
+    return status;
 }
-
-
-void TMR2_SetInterruptHandler(void (* InterruptHandler)(void)){
-    TMR2_InterruptHandler = InterruptHandler;
-}
-
-void TMR2_DefaultInterruptHandler(void){
-    // add your TMR2 interrupt custom code
-    // or set custom function using TMR2_SetInterruptHandler()
-}
-
 /**
   End of File
 */
\ No newline at end of file
diff -r d49f637e026f mcc_generated_files/tmr2.h
--- a/mcc_generated_files/tmr2.h Fri Mar 01 13:34:06 2019 +0900
+++ b/mcc_generated_files/tmr2.h Sat Mar 02 08:50:47 2019 +0900
@@ -291,76 +291,38 @@
 
 /**
   @Summary
-    Timer Interrupt Service Routine
+    Boolean routine to poll or to check for the match flag on the fly.
 
   @Description
-    Timer Interrupt Service Routine is called by the Interrupt Manager.
+    This function is called to check for the timer match flag.
+    This function is used in timer polling method.
 
   @Preconditions
-    Initialize  the TMR2 module with interrupt before calling this isr.
+    Initialize  the TMR2 module before calling this routine.
 
   @Param
     None
 
   @Returns
-    None
-*/
-void TMR2_ISR(void);
-
-/**
-  @Summary
-    Set Timer Interrupt Handler
-
-  @Description
-    This sets the function to be called during the ISR
-
-  @Preconditions
-    Initialize  the TMR2 module with interrupt before calling this.
-
-  @Param
-    Address of function to be set
-
-  @Returns
-    None
-*/
- void TMR2_SetInterruptHandler(void (* InterruptHandler)(void));
-
-/**
-  @Summary
-    Timer Interrupt Handler
-
-  @Description
-    This is a function pointer to the function that will be called during the ISR
+    true - timer match has occurred.
+    false - timer match has not occurred.
 
-  @Preconditions
-    Initialize  the TMR2 module with interrupt before calling this isr.
-
-  @Param
-    None
-
-  @Returns
-    None
-*/
-extern void (*TMR2_InterruptHandler)(void);
-
-/**
-  @Summary
-    Default Timer Interrupt Handler
+  @Example
+    
+    while(1)
+    {
+        // check the match flag
+        if(TMR2_HasOverflowOccured())
+        {
+            // Do something else...
 
-  @Description
-    This is the default Interrupt Handler function
-
-  @Preconditions
-    Initialize  the TMR2 module with interrupt before calling this isr.
-
-  @Param
-    None
-
-  @Returns
-    None
+            // Reload the TMR2 value
+            TMR2_Reload();
+        }
+    }
+    
 */
-void TMR2_DefaultInterruptHandler(void);
-
+bool TMR2_HasOverflowOccured(void);
 
  #ifdef __cplusplus  // Provide C++ Compatibility
 
これだけでいいはずなので、コンパイルしてみます。
いくつか警告が出ていますが、これはエラーチェックを厳密にしているためのようで、変更前のプロジェクトでも同様の警告が出ていたので無視します。

で、結論ですが、ちゃんと動きました。オシロスコープでも、mTouch 波形はタイミングを調整されて出ているのが確認できました。

バイナリライブラリでなにか処理をされていたら手が出ないかなとも考えていたのですが、すべてCソースレベルで実現されているようです。Cソースながら中身はインラインアセンブラで組まれている関数もありましたが、問題ないようです。

ということで、mTouch で専有されているピリオドタイマを開放して、TIMER0 をピリオドタイマに割り当てることはできました。これによって TIMER2/4/6 を自分の目的に割り当てることもできるようになりました。

ChocolateyとScoop。

Windowsでアプリケーションをインストールするときに、pacmanとかrpm、あるいはaptのようなパッケージマネージャを使うと楽になるんじゃ、みたいな話で、Chocolateyというのもがあるのは知っていたんですが、Scoopというのもあるのを見つけました。

PowerShell 3 以降と .NETFramework 4.5 以降が必要なようですが、コマンドラインからアプリの管理ができるようです。

So What?には、なんでScoopなのさ、という疑問に答えるような問答があります。
もしもあなたが、
  • プログラマか開発者である。
  • PCのセットアップに、山ほどあるウェブサイトに行ってダウンロードしてクリックしまくるようなことをしたくない。
  • 特にGitようなツールの場合にはコマンドラインで快適に操作するほうがいい。
  • UNIXツールに馴染みがあってWindows上にももっとそういうのがあったらいいと思ってる。
  • apt-getやHomebrewを使ったときに「こりゃすげぇ」と思う。
ならば、Scoopはそういう人を念頭にデザインされている。

というようなことが書いてあります。
いろいろ制限もあるようですが、そういうのもあるということで。

CuriosityでmTouchを試してみる。その9 TIMER0編(1)

Data Visualizerを使ってデータを可視化する件はとりあえず置いといて。

mTouchはお仕着せのまま使うと簡単に使えることがわかりましたが、一方でMCCでのコード生成に「そうじゃなくて」という要望を加えるとなると、ちょっとハードルが高いですね。なにより "Generate" ボタンを押すと、生成されていたすべてのコードがチェックされ、変更があれば上書きされてしまうようですし。

自分の場合、PIC16F18346 にて mTouch を使いながら、同時にピリオドタイマが3つ欲しいという仕様を実現したいのです。そうなると、TIMER2/4/6 は3つとも同じ仕様なのでコードも基本部分は共通化できます。もちろんレジスタや割り込みフラグの位置などは違っていますが、流れとしては同じです。ところが MCC の mTouch では同じようにピリオドレジスタを実現できる TIMER0 は選択できません。

機械的コード生成を汎用的に考えるなら、PICの機種間で共通の TIMER2/4/6 のみに絞ったコードを生成するのは理にかなっていますから、これはしかたないとは思いますが、同時に自由度もなくなってしまっています。

それでも TIMER0 をピリオドタイマとして使いたければ、一旦生成されたコードを手作業でいじるしかありません。
ということで以下のようにやってみます。ただ、これはできるかどうかの実装テストなので簡単に。
  1. まずMCCでシステム設定、ペリフェラル、ピン割当などを行う。できればクロック設定や割り込みについても指定しておく。
  2. MCCでコード生成をする。
  3. バージョン管理システムにコードを登録する。
  4. コードをいじる。
MPLAB X IDEには、バージョン管理プラグインとして Git、Mercurial、Subversion がインストールされているので、それぞれ外部にツールがあれば利用できます。MPLAB X IDE Version ControlのページにUsing Mercurial Support in NetBeans IDEなどのリンクがあり、MPLAB X IDEのベースとなっているNetBeans IDEでのプラグインの使い方のページに飛んでいます。このページの右上のメニューから日本語を選べば、日本語の解説ページも参照できます。

で、方針は決まった感じですが、その前にまずは AFA(Automatic Frequency Adaptation)の機能をある程度把握しておかないと、無駄なことをやってしまう可能性があります。
The Automatic Frequency Adaptation (AFA) section allows you to enable the advanced noise immunity algorithm. The automatic frequency adaptation routine continuously tracks the amount of noise that is on each sensor and chooses a new scan frequency intelligently to avoid noise frequency and its harmonics. The routine requires an 8-bit timer to precisely control the scanning frequency for non-ADCC parts implementation. Due to this requirement, mTouch® will take ownership of the first available 8-bit timer module by default, if one is available when the automatic frequency adaptation routine is enabled.

「AFAによって高度なノイズ除去アルゴリズムを利用可能になります。自動周波数適応(AFA)ルーチンは、それぞれのセンサのノイズの総量を継続的に追いかけ、ノイズ周波数とその倍音成分を除去するための新たなスキャン周波数を賢く選択します。ルーチンはADCC以外の実装におけるスキャン周波数を精密に制御するための8bitタイマを必要とします。この必要条件によって、AFAルーチンが選択されたときには、mTouchはデフォルトで最初に利用可能な8bitタイマモジュールを専有するようになっています。」

という感じです。ADCCというのがよくわかりませんが、もしかしてADCのtypoかと思って調べてみたら Analog-to-Digital Converter with Computation だそうです。Computationは数値処理ですから、ADCとそれに伴う計算ということですね。
CVD方式のmTouchアルゴリズムでは、プリチャージとアクイジション期間、ADCサンプリングを繰り返すシーケンスと、そのシーケンスを起動するサイクルを制御するのと二種類があると思いますが、ノイズ除去に効くのはどちらでしょうね。ちょっとAPIリストとかも眺めてたんですが、端的な説明はありませんでした。とりあえず、ピリオドタイマでスキャン周波数を精密に決定する、という用途らしいので、TIMER0 でも使える、と踏んで進みます。

まず、TIMER0とTIMER2のレジスタを比較してみます。

TIMER0 TIMER2/4/6
COUNT
REGISTER
TMR0L TMRx
PERIOD
REGISTER
TMR0H カウントはTMR0L PRx カウントはTMRx
CONTROL
REGISTER 0
T0CON0 TxCON
bit7 T0EN bit7 '0’
bit6 '0’ bit6 TxOUTPS3 ポストスケーラ
1/1~1/16
bit5 T0OUT (RO) bit5 TxOUTPS2
bit4 T016BIT bit4 TxOUTPS1
bit3 T0OUTPS3 ポストスケーラ
1/1~1/16
bit3 TxOUTPS0
bit2 T0OUTPS2 bit2 TMRxON
bit1 T0OUTPS1 bit1 TxCKPS1 プリスケーラ
1,4,16,64
bit0 T0OUTPS0 bit0 TxCKPS0
CONTROL
REGISTER 1
T0CON1
bit7 T0CS2 クロックソース選択 FOSC/4のみ
bit6 T0CS1
bit5 T0CS0
bit4 T0ASYNC
bit3 T0CKPS3 プリスケーラ
1~32768
bit2 T0CKPS2
bit1 T0CKPS1
bit0 T0CKPS0
INTERRUPT
FLAG
REGISTER
PIR0 TMR0IF bit
PIR1/2 TMRxIF bit
INTERRUPT
ENABLE
REGISTER
PIE0 TMR0IE bit PIE1/2 TMRxEN bit
こうしてみると、クロックソース、プリスケーラ、ポストスケーラ、モード設定などが異なりますが、あとはカウントレジスタとピリオドレジスタのみなので、理論的にはできないことはなさそうです。
あとは実装がどうなっているのか、それを変更することができるのか、という点がポイントになりそうです。

mTouch の AFA(TIMER2を使用)を有効にした状態で MCC でソースを生成して眺めてみます。
TIMER2 関係は mtouch_sensor.c にありました。

まず、
#include "../tmr2.h"
でヘッダファイルを読み込んでいます。
次に、MTOUCH_Sensor_Scan_Initialize() で、TIMER2 のプリスケーラを指定しています。
/*
 * =======================================================================
 * MTOUCH_SensorScan_Initialize
 * =======================================================================
 *  initialization for ADC and Timer module
 */
void MTOUCH_Sensor_Scan_Initialize(void)
{
    T2CONbits.T2CKPS = 0x0;

    ADCON0 = (uint8_t)0;                            /* overwrite the ADC configuration for mTouch scan */
    ADCON1 = (uint8_t)( 0x1<<7 | 0x2<<4 | 0x0 );
    ADACT = (uint8_t)0;
}
そして、Sensor_Acq_ExecutePacket() で
/*
 * =======================================================================
 * Sensor_Acq_ExecutePacket()
 * =======================================================================
 */
static enum mtouch_sensor_error Sensor_Acq_ExecutePacket(mtouch_sensor_t* sensor)
{
    /* software CVD with AFA requires interrupt enabled */
    if(!(INTCONbits.GIE & INTCONbits.PEIE))
        return MTOUCH_SENSOR_ERROR_interrupt_notEnabled;
        
    enum mtouch_sensor_error        error = MTOUCH_SENSOR_ERROR_none;
    uint8_t ADCON0_temp;
    uint8_t ADCON1_temp;
    uint8_t ADACT_temp;
    

    ADCON0_temp = ADCON0;       /* store the current ADC configuration */
    ADCON1_temp = ADCON1;
    ADACT_temp = ADACT;
    MTOUCH_Sensor_Scan_Initialize();
    
                 
    Sensor_setScanFunction(sensor);  /* Setup the scan function */

    currentScannSensor = sensor->sensor_name;
    packet_counter  = sensor->oversampling;
    packet_sample = 0;
    sensor_globalFlags.packet_done = 0;
    packet_noise = 0;
    
    TMR2_SetInterruptHandler(Sensor_Acq_ExecuteScan);  /* Use timer2 to schedule the scan */
    TMR2_LoadPeriodRegister(sample_period);
    TMR2_StartTimer();
    
    sensor_globalFlags.interrupted = false;
    
    /* Perform packet samples */
    do
    {
        while(PIR1bits.ADIF == 0) 
        {
            if(sensor_globalFlags.packet_done == (uint8_t)1)
                break;
        }
        PIR1bits.ADIF = 0;    
    } while(sensor_globalFlags.packet_done == 0);


    TMR2_StopTimer();
    ADCON0 = ADCON0_temp;       /* restore the previous ADC configuration */
    ADCON1 = ADCON1_temp;
    ADACT = ADACT_temp;
    
    if(sensor_globalFlags.interrupted)
    {
        error = MTOUCH_SENSOR_ERROR_interruptedScan;
    }
    
    return error;
}
という処理を行っています。スタート、ストップ、ピリオドレジスタへのロードはいいとして、割り込みハンドラに Sensor_Acq_ExecuteScan() を割り当てているのでこれを追いかけてみます。
/*
 * =======================================================================
 * Sensor_Acq_ExecuteScan()
 * =======================================================================
 * Perform a single sample on the sensor. This is a local function and
 * requires that the ExecutePacket() function guarantees the correct PIC
 * and scanning configuration.
 *
 * This function is written to be independent of mainloop vs ISR context.
 */
static void Sensor_Acq_ExecuteScan(void)
{
    while(ADCON0bits.ADGO); 
    
    mtouch_sensor_adcsample_t result = ADRES;       /* result from previous scan */
    static mtouch_sensor_adcsample_t last_a,last_b;

    if(sensor_globalFlags.packet_done)
        return;
    
    if (packet_counter != (uint8_t)0)
    {
        #pragma switch time
        switch(packet_counter & 0x01)
        {
            case 0: Sensor_scanA();break;
            case 1: Sensor_scanB();break;
            default: break;
        }
        /* Accumulate previous sample result during the ADC conversion */
        if(packet_counter!=mtouch_sensor[currentScannSensor].oversampling)
        {
            if(packet_counter & 0x01)
            {    
                result = PIC_ADC_RESOLUTION - result;
                packet_noise += (mtouch_sensor_packetsample_t)abs(last_a-result);
                last_a = result;
            }
            else
            {
                packet_noise += (mtouch_sensor_packetsample_t)abs(last_b-result);
                last_b = result;
            }
            packet_sample += result;
        }
        packet_counter--;
    }
    else
    {
        packet_sample += result;
        packet_noise += (mtouch_sensor_packetsample_t)abs(last_b-result);
        sensor_globalFlags.packet_done = (uint8_t)1;
    }
}
長くなるのでコードは畳んでいますが、どうやらここではタイマをいじってはいないようです。 次に tmr2.c を眺めてみます。
/**
  Section: Global Variables Definitions
*/

void (*TMR2_InterruptHandler)(void);

/**
  Section: TMR2 APIs
*/

void TMR2_Initialize(void)
{
    // Set TMR2 to the options selected in the User Interface

    // PR2 255; 
    PR2 = 0xFF;

    // TMR2 0; 
    TMR2 = 0x00;

    // Clearing IF flag before enabling the interrupt.
    PIR1bits.TMR2IF = 0;

    // Enabling TMR2 interrupt.
    PIE1bits.TMR2IE = 1;

    // Set Default Interrupt Handler
    TMR2_SetInterruptHandler(TMR2_DefaultInterruptHandler);

    // T2CKPS 1:1; T2OUTPS 1:1; TMR2ON on; 
    T2CON = 0x04;
}
void TMR2_ISR(void)
{

    // clear the TMR2 interrupt flag
    PIR1bits.TMR2IF = 0;

    if(TMR2_InterruptHandler)
    {
        TMR2_InterruptHandler();
    }
}


void TMR2_SetInterruptHandler(void (* InterruptHandler)(void)){
    TMR2_InterruptHandler = InterruptHandler;
}

void TMR2_DefaultInterruptHandler(void){
    // add your TMR2 interrupt custom code
    // or set custom function using TMR2_SetInterruptHandler()
}
あたりで割り込み処理などを行っています。

ということは、この辺をいじってやればなんとかなるかもしれません。

というあたりで次回に続きます。

Vimの補完プラグインをインストール。その4

Vimの補完プラグインをインストール。その3 で、 ddc-tabnine が使えそうです、などと書いたのですが、早速やってみました。 まず、tabnineのバイナリを用意しないといけません。がどうにもTabNineのサイトがわかりにくいので、 tabnine-nvim にあるダ...