Hatena::ブログ(Diary)

Okiraku Programming RSSフィード Twitter

2016-11-09 SLコマンド on touch bar

SLコマンド on touch bar

新しいMacBook Proのtouch barで走るSLコマンド作りました

(touch barシュミレータでしか動作確認してませんが。)


https://raw.githubusercontent.com/NeoCat/sl_on_touchbar/master/sample.png


D


オリジナルのようにオプション(-a, -l, -F)には対応していません。


ソース(Swift)は以下。ビルド済みのバイナリも入ってます。

https://github.com/NeoCat/sl_on_touchbar

なおビルドシミュレータの動作にはmacOS Sierra 10.12.2 beta (16C41b)以降、XCode 8.2 beta以降が必要です。


slが走っている間はウィンドウのフォーカスが奪われるので、実質何も操作できなくなります。端末しか占拠しない普通のSLコマンド以上にうざいです。


これは、touch barに何か出すにはアプリケーションのウィンドウを手前に出している必要があるため。

普通のSLコマンドのような使用感を得るために、UIElement=YESにしてDockアイコンが出ないようにしたアプリケーションを起動してサイズ0×0のウィンドウをこっそり開くことで、touch barへの描画権を得ています。こいつが常に手前に出るせいでフォーカスが奪われるというわけです。


SL画像の差し替え [11/16追記]

「長い列車写真」の情報をコメントでいただいたので、touch barにこの写真を流せるようにしました。

slコマンドの引数か、環境変数 SL_IMAGE のいずれかに写真ファイル(高さを60ピクセルにしてください)へのパスを設定しておくと、そのファイルの画像が使われます。

f:id:NeoCat:20161116015813p:image

参考: https://github.com/avatsaev/touchbar_nyancat

2016-10-12 ESP8266でNATでWi-Fiを中継する

ESP8266でNAT(NAPT)でWi-Fiを中継する

ESP8266(ESP-WROOM-02)を最近よく使っています。

ESP8266を使ったセンサを、Wi-Fiアクセスポイントから遠い、直接電波の届きにくい場所に置きたかったため、ESP8266をもう一つ使ってWi-Fiの到達範囲を拡張する中継機にした(といってもブリッジではなくNAPTルータ)という話です。

f:id:NeoCat:20161012055701p:image


とその前に軽くESP8266について紹介しておくと…(もう知ってる方は読み飛ばしてください)


ESP8266の紹介

ESP8266は無線LANモジュールです。購入した状態では外部のマイコンからATコマンド制御できます。が、LX106という32bit MCUを搭載しており、このモジュール単体でArduino IDEからプログラミングして動作させることが可能です。この方が圧倒的に便利なので、私自身はATコマンドで使ったことはありません。

しかも安価(単体なら400円台)ですし、ESP-WROOM-02は技適も取得していて安心して使え、AVRと比べて高性能(CPUクロック80〜160MHz, 4MBフラッシュ, 36KB RAM)。アナログ入力も1ch搭載していて、センサ・アクチュエータ等を簡単ネットワーク接続できるので非常に便利です。


Arduinoとして利用する方法は下記などが参考になります。

技適済み格安高性能Wi-FiモジュールESP8266をArduinoIDEを使ってIoT開発する為の環境準備を10分でやる方法 - Qiita


なお開発時はモジュール単体よりも、下記のようなブレークアウトボード・開発ボードを購入するのが良いでしょう。特にESPr DeveloperはUSBを接続するだけでいきなり開発が始められ、シリアル変換や書き込みモード設定など気にしなくて済むので非常に楽です(お値段はしますが)。

ESP-WROOM-02ピッチ変換済みモジュール《フル版》 - スイッチサイエンス

ESPr Developer(ピンソケット実装済) - スイッチサイエンス


ちなみにシリアルスケッチを書き込むと、ファームウェアが大きいため*1転送に少し時間がかかりますが、Wi-Fi経由で高速にアップロードすることも可能です。

ESP-WROOM-02 + ArduinoOTAでスケッチのWiFi経由アップロード - Qiita


他にもLua等でもプログラミング可能ファームウェアもあります。

ESP8266(ESP-WROOM-02)自分的まとめ - 半空洞男女関係


Wi-Fiのモード

ESP8266は、自身Wi-FiアクセスポイントになるWIFI_APモード、既設のWi-Fiアクセスポイントに接続するWIFI_STAモードの両方をサポートしています。

しかしこれ以外にWIFI_AP_STAという、他のアクセスポイントに接続しつつ、同時に自分アクセスポイントとして他のクライアントからのWi-Fi接続を受け付けるということができます。(ちなみにArduino化した直後のデフォルトではこのモードになっているため、明示的にモード指定していないと ESP_xxxxxx というSSIDが発信されています。APのON/OFFやSSID等の設定はフラッシュに不揮発に保存され、前回の値が電源ONに設定されます。)


モードの切り替えは以下のようにWiFi.mode()を使用します。

const char *ssid = "ParentAP";
const char *password = "********";

const char *ap_ssid = "ESPap";
const char *ap_password = "ESPap_password";
...
  WiFi.mode(WIFI_AP_STA);  // モード設定

  WiFi.softAP(ap_ssid, ap_password);  // APのSSID・パスワード設定
  IPAddress myIP = WiFi.softAPIP();   // APとしてのIPアドレスを取得。デフォルトは 192.168.4.1 ?
  Serial.print("AP IP address: ");
  Serial.println(myIP);

  WiFi.begin(ssid, password);  // 別のAPに接続

子端末になるESP8266では、上記のap_ssidに対してWiFi.begin()で接続することになります。こうすると以下のような接続状態になります。

 親AP(192.168.10.1) <=> (192.168.10.x) ESP8266 (AP: 192.168.4.1) <=> (192.168.4.y)子端末

なお、親と子で別のサブネットアドレスになっていないと(少なくとも親ネットワーク側からは)通信不能となるのでご注意を。


IPアドレスDHCP自動的に設定されます(静的に指定もできます)。

また、ESP8266WiFiMultiを使って複数の接続先SSID指定しておけば、接続できる方に自動接続するということも可能です。詳しくはWiFiMultiというサンプルスケッチを見てください。

Wi-Fi中継の方法

APクライアントに同時接続できるということは、Wi-Fi中継機として使えるのでは?と思うわけですが、そのままでは中継機能(IP_FORWARD)は無効化されており、SDKに含まれるIPスタック(lwip)の設定を変更する必要があります。

参考: ESP8266 lwip IP_FORWARD/routing - ESP8266 Developer Zone


これにより、親APネットワークとESP8266 APネットワークの間でパケットが転送されるようになります。しかし、これだけでは親APやそのネットワーク内の各端末に「192.168.4.0/24 にアクセスするには 192.168.10.x をルータとして使う」というルーティング情報を設定しないと、通信が行えません(子端末からのパケットはESP8266がデフォルトゲートウェイになるので設定しなくとも親APネットワークに出て行けますが、その応答パケットが戻っていくためのルーティング情報を設定しないと応答が得られません)。


この設定を不要にする方法として、普通のルータで使われている方式としてNAT(正確にはNAPT)があります。子端末から親ネットワークに出ていく際にソースアドレスをESP8266のもの(192.168.10.x)に書き換えておき、逆にこれに対する応答パケットが来た際には適切に子端末宛てに書き換えるというものです。(戻り先を特定するためにはセッション管理が必要になります。)


なお他にネットワークブリッジとして機能させることも考えられますが、こちらは色々ルーティングに改造を加えないと難しい気がして手を出していません。


NATを実装する

esp8266のSDKのlwipをざっと眺めたところ、NAT機能はないようでしたので、自分で実装してみました。


変更の内容はGitHubに置いてあります。

https://github.com/NeoCat/esp8266-Arduino/commit/4108c8dbced7769c75bcbb9ed880f1d3f178bcbe

上記のバグ修正コミット

https://github.com/NeoCat/esp8266-Arduino/commit/634dfb5f60e902c681c95712bc7455e24773667d


ボードマネージャ等でESP8266のライブラリを導入している場合は、以下のパッチを当てることで対応できます。

https://gist.github.com/NeoCat/da3c141813980edaa256ad351cab3a2c (バグ修正コミットを含む差分)


上記からRaw(またはDownload ZIP)でパッチを適当な場所に保存し、Macであれば端末から

$ cd ~/Library/Arduino15/packages/esp8266
$ patch -p1 < (保存した場所)/0001-Adds-NAPT-and-port-mapping-functionality-to-esp8266-.patch

とすればパッチ適用できます。適用後、lwipを再コンパイルする必要があります。

$ cd hardware/esp8266/2.3.0/tools
$ ln -s ../../../../tools/xtensa-lx106-elf-gcc/1.20.0-* xtensa-lx106-elf
$ cd sdk/lwip/src
$ make && make release  #=> intalled to ../../lib/liblwip_gcc.a

パッチ適用したら、Arduinoスケッチ内で以下のようにすることでNAT有効化できます。

#define IP_PROTO_TCP     6
#define IP_PROTO_UDP     17
// SDKに追加した関数のプロトタイプ宣言
extern "C" {
  void ip_napt_enable(unsigned long addr, int enable);
  void ip_portmap_add(byte proto, unsigned long maddr, unsigned short mport,
                      unsigned long daddr, unsigned short dport);
  bool ip_portmap_remove(byte proto, unsigned short mport);
}
...
    // WiFi.begin等の後で
    ip_napt_enable(WiFi.softAPIP(), 1);

これ以降、子端末からのTCP/UDP/ICMP(pingのみ)のパケットは親ネットワークアドレス変更の上で転送され、応答も対応付けてアドレス変換されます。

なおTCP, UDP送信ポート番号(1024以上)も重複を避けるために変換対象になります。


ネットワークから子端末のTCP/UDPサーバアクセスするためには、ESP8266の特定ポートを子端末にマッピングする必要があります。このためにはスケッチから、

        ip_portmap_add(IP_PROTO_TCP, WiFi.localIP(), 8080,
                                     IPAddress(192,168,4,3), 80);

のように、対象プロトコル(TCPまたはUDP)、ESP8266上のマッピングするポート、転送先となる子端末のIPアドレスポート指定します。

この例では、親ネットワークから 192.168.10.x:8080 にアクセスすると、子端末192.168.4.3の80番ポート(Webサーバ)に接続できます。

ポートマッピングを解除するには、以下のようにします。

        ip_portmap_remove(IP_PROTO_TCP, 8080);

なお実装上、1つの宛先(アドレス+ポート)に対しては1つのポートしかマッピングできず、同一の宛先を複数ポートにマップすると動作がおかしくなるのでご注意ください。


制限事項

*1ネットワークスタック等のファームウェアも含まれているため

2016-09-23 keyhacでNICOLA配列

keyhacでNICOLA配列を実現する

macOS Sierraにアップデートしたところ、キー配列をカスタマイズするKarabinerが利用できなくなってしまいました。


Karabinerは非常に様々なカスタマイズに対応していたため、不便な思いをしている人も多そう。

私はNICOLA配列(いわゆる親指シフト入力)で日本語を入力するのにKarabinerを使っていたのですが、これができなくなっていました。

親指シフトは同時押し(シフトキーを押しながら文字キーを押すだけでなく、文字キーを押してからシフトキーを押し下げても良い)が特徴のため、単純なキーの置き換えだけができるツールでは再現ができません。

そんな折、以下のページでkeyhacという、Pythonで高度にキー配列をカスタマイズできるツールを知りました。


macOS SierraでKarabinerが動かなくて困っている人に贈る代替ソフトウェア


Keyhac - Pythonによる柔軟なキーカスタマイズツール - craftware


これならというわけで、JIS配列キーボードローマ字設定の環境向けにNICOLA配列を実現する設定を書いてみました。設定といっても普通にPythonプログラムです。この記事も、これでNICOLA配列にした状態で書いています。

設定の仕方

keyhacを起動し、メニューバーに表示されたアイコンメニューから"設定の編集"を選ぶと、TextEditで設定ファイルが開きます。そこに、本記事末尾のコードコピペして上書きします。デフォルトの設定はいろんな機能のサンプルが入っていて意図しない動作になったりするので消すか無効化したほうがいいでしょう。

なお、TextEditは勝手にクォート("")を“”などと置き換えてしまうので、編集自動置換→スマート引用符の設定は切ってから編集したほうがいいでしょう。

シフトキーの設定は SHIFT_KEY = ["左親指シフトキー", "右親指シフトキー"] のように書きます。キーの名称は、keyhacのメニューから"端末を表示"し、同じくメニューから"内部ログ ON"にしてタイプしてみれば確認できます。

設定を書いたら保存して、再度メニューから"設定のリロード"を選べば準備完了です。


使い方

かなキーを押すとNICOLA配列有効化され、英数キーを押すと無効化されます。

親指シフトキーは同時押しが可能です。具体的には、親指シフトキーの押下前後40ms以内に文字キーが押されると一回だけ効くようになっています。文字キーの後でシフトキーを押下した場合に対応するため、文字キー単体で入力された場合は最大40msだけキーダウンが遅延されます(キーアップするか親指シフトキーが押されれば直ちに入力されます)。この判定時間はSHIFT_MSとSHIFT_DURATIONを両方とも変更することで、個々人の好みに合わせて調整が可能です。

一応これでそれなりに機能しているようですが、文字キー → 親指シフトキー → 文字キー と高速打鍵すると意図しない方の文字シフトが効いたりすることも稀にあるため、まだ改善余地があるかもしれません*1


さらなるカスタマイズ…

キー配列TABLE という辞書編集することでカスタマイズが可能です。各文字に対して/(スラッシュ)区切りで'シフトなし/左親指シフト/右親指シフト'という順にローマ字表記、または""でくくったキー名を書くようになっています。頑張ればorz配列等にも対応できるはずです。

この設定は下記のNICOLA-J配列を参考にしてますが、"[", "]", "^", "\" キーはそのままにしてあります。

http://nicola.sunicom.co.jp/image/nicola-j-implementation-sample.png


なおドキュメントはメニューのヘルプで見られますが、delayedCall などの一部の低レベルの機能は載っていないので、そういう細かい部分はkeyhacやその下位ライブラリのpyauto, ctkitのソースを見る必要があるかもしれません。

GitHub - crftwr/keyhac: python based key customization utility

GitHub - crftwr/pyauto: windows low-level feature library

GitHub - crftwr/ckit: craftware's base library


設定ファイル

https://gist.github.com/NeoCat/d7233e3130110c0fe6122d32610e4d50

*1文字キーを離す前に親指シフトキーを押した場合、どう判定するべきかが難しいところ。近い方の文字キーにすべきなのかもしれませんが、これを実現するには入力をタイマーで遅延させる必要があり、かなり複雑なことになりそう……。

2016-08-20 USB直結のスクリーンセーバーブロッカー

2016-06-23 マイナンバーカードでSSHしてみた

マイナンバーカードでSSHしてみた

マイナンバーカードでSSHする - AAA Blog


という記事が出ていたので、マイナンバーカードを使ったSSHログインLinux上でやってみました。環境は出たばっかりのFedora 24です。

カードリーダーは、上記の記事のような非接触式ではなく、接触式のICカードリーダー NTTCom SCR3310を利用しました。



まずは必要なパッケージをインストールカードリーダーUSB接続し、スマートカードデーモンpcscdを起動します。

$ sudo dnf install openssl-devel readline-devel zlib-devel pcsc-lite pcsc-lite-devel pcsc-lite-ccid pcsc-tools
$ sudo systemctl start pcscd

開発中の個人番号カード対応版OpenSCをcloneしてきて、ビルドインストールします。

$ git clone https://github.com/jpki/OpenSC.git
$ cd OpenSC
$ ./bootstrap
$ ./configure
$ make
$ sudo make install

ではカードをセットして、公開鍵を読み出しましょう。カードの裏表を間違えないように注意(ICチップの端子のある面が上)。間違ってると読めないというエラーになります。。

$ pkcs15-tool --read-ssh-key 1
Using reader with a card: NTT Communications Corp. SCR3310-NTTCom USB SmartCard Reader [Vendor Interface] 00 00
ssh-rsa *******...... User Authentication Certificate
zsh: bus error  sudo =pkcs15-tool --read-ssh-key 1

ってなんかバスエラーを起こしました。がとりあえず読めたから気にしない(何


これをコピペしてSSHサーバの ~/.ssh/authorized_keys に追加します。同一マシンローカルホスト)でもいいでしょう。


そうしておいて、ビルドしたOpenSCのPKCSモジュール指定してSSHログインしてみると...

$ ssh 192.168.xx.yy -I /usr/local/lib/opensc-pkcs11.so
Enter PIN for 'JPKI (User Authentication PIN)': **** ← 公的個人認証用の4桁のPIN番号
Last login: Fri Jun 24 00:37:23 2016 from 192.168.xx.zz
$ 

無事ログインできました。


なおPIN番号は3回間違えると閉塞されてしまい役所手続きが必要になるのでご注意を。。

(3種類ある4桁の暗証番号のうちの、利用者証明電子証明書の(マイナポータルへのログインコンビニでの公的証明書の交付などで使う)PIN番号です。)


他に

$ pkcs15-tool -c 

認証証明書シリアル番号などを確認したり、

$ pkcs15-tool -r 1 

認証証明書情報を読み出し、ファイルコピペして(リダイレクトするとSEGVするせいで書き出されない…)

$ openssl x509 -text -noout -in <ファイル名>

などとすると有効期限や発行者情報自治体とか)が確認できます。認証証明書の方にはマイナンバーはもちろん、住所や氏名などは入っていないことが確認できます。