読者です 読者をやめる 読者になる 読者になる

opamp_sando's blog

クソザコが割りと適当なことを書くためにある備忘録です。あとたまに普通の日記も書きます

windows向けにlibarchive3.2.1をビルドした

windows

libarchive 3.2以前で脆弱性があるのもあって久々にビルドし直してみた(Windowsでも影響するか知らんけど)。
最近なんだかんだで常用OSがWindows10とArchLinuxになったのでwindowsでtarが動くと便利。

Download libarchive 3.2.1

SharedでビルドしたのでDLLが必要。とりあえずうちで動かして言われたやつは追加しているけど、環境によっては 更に追加でいくつか必要かもしれない(mingw周りのやつとか)

scratchnote.elを作った

emacs emacslisp

Emacsで気軽にメモできればいいなと思って即席でscratchnoteなるものを作った。scratch-popというEmacs Lispに触発されているけど、こちらはメモを取る事前提でデフォルトでバッファはorg-modeになっている。
scratchバッファのモードを変える手もあるが、あちらはあちらでEmacs Lisp用のバッファとして使いたいので分けている。

gist.github.com

ファイルをrequireして適当な設定を書く必要がある。

;;; configuration sample 
;; 基本設定
(require 'scratchnote)
(global-set-key (kbd "C-c m") 'scratchnote-pop)
;; 内容の永続化
(scratchnote-restore)
(add-hook 'kill-emacs-hook 'scratchnote-save)

scratchnote-restoreとscratchnote-saveを実行すると、予め設定してある保存先にメモバッファの内容を保存したり、逆にファイルから内容を復帰したりできる。上のように起動時と終了時に自動でrestoreとsaveを呼び出すようにすることで内容を自動で永続化させることができる。

初めてのCFFI

CL

初めてCFFIを使ってみた。わかりやすくするために、自分で作った特に何の役にも絶たない共有ライブラリの関数をCommon Lispで呼び出してみた。

とりあえずCで適当なヘッダーとC言語ファイルを作る。

以下がtestlib.h

#ifndef TESTLIB_H
#define TESTLIB_H
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct hogehoge {
  char first[128];
  char last[128];
};

typedef struct hogehoge hoge_d;

void helloworld(char* name);

hoge_d* init_hogehoge(char* first,char* last);

void hello(hoge_d *data);

#endif

次のがtestlib.c

#include"testlib.h"

void helloworld(char* name){
  printf("hello %s\n",name);
}

hoge_d* init_hogehoge(char* first,char* last){
  hoge_d* data = (hoge_d*)malloc(sizeof(hoge_d));
  strcpy(data->first,first);
  strcpy(data->last,last);
  return data;
}

void hello(hoge_d *data){
  printf("hello %s %s\n",data->first,data->last);
}

コンパイルしてsoファイルを作る。

$ gcc -shared testlib.c -o libtestlib.so -fPIC

ここまでできたらCommon LispのREPLに入って呼び出してみる。
まずは準備をする。

> (ql:quickload :cffi)
> (defpackage :cffi-test (:use :common-lisp :cffi))
> (in-package :cffi-test)

次にライブラリを探すディレクトリを指定する。どうやらforeign-library-directoriesを設定したらいいようだ。
stringかpathnameか何かで指定できるようだが、pathnameならディレクトリ形式で指定する。

> (setf *foreign-library-directories* (list #p"/path/to/so/dir/"))

そして、ライブラリを定義する。

(define-foreign-library libtestlib 
  (:unix (:default "libtestlib"))
  (:t (:default "libtestlib")))

定義したら読み込む。

> (use-foreign-library libtestlib)

これで全部の準備ができたので、defcfunでCの関数を定義していく。

> (defcfun ("helloworld" helloworld) :void (name :string))

まず、名前を渡してhello worldするだけの関数を呼び出す。上のように定義するとhelloworldという名前でCommon LispからC言語で定義したhelloworld関数を呼び出せるようになる。

> (helloworld "opamp")

ポインタや複数引数も難なくできた。

> (defcfun ("init_hogehoge" init-hogehoge) :pointer (first :string last :string))
> (defcfun ("hello" hello) :void (data :pointer))

これで

> (defvar *p* (init-hogehoge "opamp" "sando"))
> (hello *p*) ; "hello opamp sando"と表示される

参考資料

https://common-lisp.net/project/cffi/manual/cffi-manual.html

http://bis83gb.hatenadiary.jp/entry/2013/06/29/132421

https://common-lisp.net/project/cffi/manual/html_node/_002aforeign_002dlibrary_002ddirectories_002a.html

UEFIでWindowsとArchLinuxのデュアルブートをやってみたよ

ArchLinux Windows

1年間貯金したお金でようやく新しいPCを組むことができた。今までは全部完成品を買っていたけど今回が初めての自作。メモリを間違えてDDR3を買うというトラブルがあったのは内緒。(もっと目立つように書いててほしいものだ。まあ誰が悪いって自分が悪いが...)
今日はそんなPCにWindowsとArchLinuxをデュアルブートした話。タイトルの通り完全にUEFIでどちらもブートした。間違えたところや悩んだところだけ大まかにメモする。

マザボASUS H170M-PLUSを使った(参考までに)。

マザボUEFI BIOSの設定について

この設定についてはマザボによって異なるので一概にこうとは言えないが、ポイントとしては

  • セキュアブートをOFF
  • CSMの設定でUEFIのみで起動するようにする

ArchLinuxのInstall ISOもそうだが、最近のWindowsはマシンがUEFI対応ならUEFIで起動・インストールしようとする。CSMの設定によっては旧来のBISO式のセットアップが優先され、それで起動してしまうことがあるのでそうならないように注意。それでインストールしてしまった場合、再インストールする以外にUEFI方式に変換する方法はないようだ。

Windowsをセットアップ

きちんとUEFI形式でWindowsをセットアップする。パーミッションを分ける画面でESPなどのパーミッションが作られないようであればレガシーモードで起動していると思われるのでUEFI BIOSの設定を見直す必要がある。

インストールは通常の手順通り行うが、デュアルブートのためのもう一方のOSが入るストレージ分は容量を開けておくと良い。

また、セットアップ後にすぐにWindows認証せず、デュアルブート環境が完全に構築されてからWindows認証を行うことをおすすめする。Windows認証には回数に上限があるようなので、何度も認証するようなことになれば自動認証できなくなり、電話するしかなくなる。(昔WindowsXPを何度も再インストールしてその状態になったことがある)

ArchLinuxのセットアップ

ArchLinuxのセットアップは概ね通常の手順通りで良い。ただしブートローダにはsystemd-bootと呼ばれる標準搭載のものを使うと良い。grubでもできなくはないが、こちらのほうが圧倒的に簡単な気がする。systemd-bootは標準で入っているので最近のisoファイルを利用しているならば追加でインストールする必要はない。また、"/boot"はESPパーティションをマウントするべき。

$ mount /dev/sdaX /mnt/boot # ただし/dev/sdaXはESP

systemd-bootの詳細はArchWikiを参照

systemd-bootは書いているようにWindowsUEFIのBoot Managerを自動で発見し認識するようなので、先にWindowsを入れていれば特に設定をしなくてもWindowsを起動できる。また、archlinuxのエントリーはデフォルトではないので手動で書く必要がある。

systemd-bootのストレージへのインストールは次のようにする。

$ bootctl --path=/boot install

これ1つですべてインストールができる(設定ができるとは言っていない)
efibootmgrで確認すればわかるが、優先順位もsystemd-bootが最優先に自動的に変更される。

次はArchWikiにもあるように"$esp/loader/loader.conf"を設定する。

default archlinux
timeout 3

今回はデュアルブートが前提なので、ブートするOSの選択肢を出すためにtimeoutを設定する。また、デフォルトは初期状態では適当な記号が入っているが上のようにarchlinuxとした。

続いて、"$esp/loader/entries/archlinux.conf"を作成して以下のように記述する。以下は一例なのでまるまるコピーしても動かない。
また、ファイル名が先ほどのloader.confのdefaultで指定される名前になるので、ファイル名とdefaultの値は一致させておく。

title          Arch Linux
linux          /vmlinuz-linux
initrd         /initramfs-linux.img
options        root=PARTUUID=*********************** rw

アスタリスクのところは以下のコマンドで調べる。

$ blkid -s PARTUUID -o value /dev/sdaX # /dev/sdaXはルートパーティション

うちの環境はルートパーティションの暗号化を行ったので、optionsは更に以下のようになった。

options cryptdevice=PARTUUID=<PARTUUID>:<mapped-name> root=UUID=<luks-UUID> quiet rw

この辺はすべてArchWikiの抜粋だが、少しわかりにくかったので追記しておく。 まず、上のPARTUUIDは先ほどのblkidコマンドのようにすることで調べることができる。これは純粋に"/dev/sdaX"のように暗号化済みの直のルートパーティションを指定する。
次の"root=UUID...."のUUIDはwikiにもあるように「復号化済み」すなわち/dev/mapper以下に配置されるようなスペシャルファイルのUUIDを記述する。つまり以下のようなコマンドで調べる。

$ blkid -s UUID -o value /dev/mapper/hogehoge

hogehogeは人によって異なる。ルートパーティションのディスクを暗号化する場合は、mkinitcpio.confの設定も行う必要があるが、これはwiki通りで悩まずできるので割愛する。

それと、今回のPCは全部SSDで構成しているのでArchLinuxの場合は手動でTRIMを有効化したりする必要がある。しなくても動くけどSSDを傷めつけることになると思うので入れたほうがいい。

終わり

再起動後にメニューが表示され、WindowsとArchLinuxの両方が起動できることが確認できたら終了となる。
ここまでできて初めてWindowsの認証やドライバのインストールをするのが多分一番効率がよくて安全だと思う。

自分好みのauto-completeの補完の挙動設定

emacs

忘れないようにメモ。

(setq ac-auto-start 1)
(setq ac-use-menu-map t)
(setq ac-delay 0.8)
(setq ac-auto-show-menu 2)
(setq ac-use-fuzzy)

大体こんな感じで書いておくと、入力を邪魔されることなく自動補完ができる気がする。delayなどの時間は要調整。 この設定では、何かしらのキーで呼び出さなくても自動で補完が動くようになっているが、ac-delayなどで遅延させているので スラスラ入力しているときなどは補完が発生しない。もちろん手動で補完を呼び出すこともできる。
これで例えばorgモードで表を編集しているときに、次の表に移ろうとTabを押しても補完が動いて不本意な入力をしてしまうことがない。

Arduinoを使ってリモコンの赤外線の受信テスト

arduino ArchLinux

最近何か作りたくてしょうがないので、次に手元に合った赤外線受信センサーと赤外線LEDを使って遠隔操作できるリモコンを作ってみることにした。とはいえ、よくわからないのでまずはArduinoを使ってリモコン信号を受信し、パソコンでそれを眺めてみることにする。実際に何か作るときはArduinoじゃなくてマイコンを直接触ると思う(arduinoは一応講義で使う可能性があるからね)。

環境

ということで、Arduinoとコンピュータの環境は次のような感じ

まあ、いつものって感じです。次に使った部品

コンデンサなどはセンサモジュールの電源安定化のため。

回路

組んだ回路に関しては、回路図を書くのがめんどくさいので以下の動画を参照。2:43ごろの回路をほぼそのまま利用させていただきました。

赤外線通信のすすめ【紹介編】 ‐ ニコニコ動画:GINZA

Arduinoの環境構築

ArchLinuxでArduinoの環境を整えて見ました。以前講義でArduinoを使った時に整えたけど、大分放置されIDEのバージョンは古く、手抜き工事ゆえのrootじゃないと書き込めないという欠陥仕様なのでArchWikiを見てちゃんと構築する。

https://wiki.archlinuxjp.org/index.php/Arduino

まず、yaourtを使ってAURからarduinoをインストール。

$ yaourt -S arduino

次に、インストール最後にも表示されるようにuucpとlockグループにアカウントを追加。

$ (sudo) gpasswd -a opamp uucp
$ (sudo) gpasswd -a opamp lock

これでグループ情報を適用させるために再起動または再ログインするとarduinoコマンドからArduino IDEが利用できるようになる。
wikiにはcdc_acmモジュールをロードすると書いているけどうちの場合はすでにロードされていた。

lsmodなどを使って確認することができる。

$ lsmod

ロードされてない場合はwikiの通りロードしてみる。

これで構築は完了。

プログラムを書く

今回は定番のIRremoteというライブラリを用いて簡単にArduinoで赤外線リモコンの信号を受信してみる。
どうやら最新のArduino IDEにはそれらしきライブラリが標準であるようだが、どうもこれを使うとコンパイルでコケるのでgithubからダウンロードしたものを使う。ダウンロードは「Releases」から「IRremote.zip」を落とす。
今回は2.0.1BETAのバージョンを利用した。

[f:id:opamp_sando:20151025020644p:plain]

(↑なんか何回写真を貼り直してもちゃんと表示されないんだけど)

で、ダウンロードしたらArduino IDEのメニューバーの「スケッチ」から「include library」を選んで「Add ZIP Library」を選択。ここで先ほどダウンロードしたらzipファイルを選択すれば良いようだ。

ということで実際のコードは以下のようになった。

#include <IRremote.h>
 
const int RECV_PIN = 2;
IRrecv irrecv(RECV_PIN);

decode_results results;

void setup(){
  irrecv.enableIRIn();
  Serial.begin(9600);
}

void loop(){
  if (irrecv.decode(&results)) {
    Serial.print(results.value, HEX);
    Serial.print(" (");
    Serial.print(results.bits, DEC);
    Serial.println(" bits)");
    Serial.print("Raw (");
    Serial.print(results.rawlen, DEC);
    Serial.print("): ");
    
    for (int i = 0; i < results.rawlen; i++) {
      if ((i % 2) == 1){
        Serial.print(results.rawbuf[i]*USECPERTICK, DEC);
      }else{
        Serial.print(-(int)results.rawbuf[i]*USECPERTICK, DEC);
      }
      Serial.print(" ");
    }
    
    Serial.println("\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    irrecv.resume(); // Receive the next value
  }
}

書き込めない場合は「ツール」のボードやポート設定が正しいかを確認してみると良い。

動かしてみた

実際に動かして、適当に部屋の照明のリモコンやらエアコンのリモコンやらを近づけてボタンを押した。結果はシリアル通信で返ってくる。

f:id:opamp_sando:20151025022001p:plain

なお、このデータを送信はしてないので本当に合っているのかは謎。

ところでhatenaって時々画像やリンクを貼っても反映されずに写ったりして意味不明なんだけどこれワシが悪いんか?

参考資料

http://deviceplus.jp/hobby/entry023/

http://www.nicovideo.jp/watch/sm20908757

ありがとうございました。

JSONデータを取得してhighcharts.jsを使った簡単なグラフ表示

javascript php postgresql

ということでPostgreSQLのテーブルデータを取得してJSONにした後、highcharts.jsを使ってブラウザ上にグラフを書いてみる。
あんまり関係ないかもしれないが、一応書いておくとWebサーバーにはlighttpdを使用し、phpは5.6.14を使用。PostgreSQLは9.4.5。

使うデータについて

以下のようなデータがPostgreSQLに入っている。何のデータかというと、自室の室温データである。
DB設計には疎いのでどうなのかわからないが、主キーはtimeになっている。timeは見ての通りタイムゾーンなしのtimestamp型でvalueはreal型。

> select time,value from temp;
            time            |  value  
----------------------------+---------
 2015-10-22 08:00:01.296074 |  24.385
 2015-10-22 09:00:01.261014 |  24.385
 2015-10-22 10:00:01.242508 |  24.385
 2015-10-22 11:00:01.410739 |  24.385
 2015-10-22 12:00:01.417759 |  24.385
 2015-10-22 13:00:01.439453 |  24.385
 2015-10-22 14:00:01.42983  |  24.385
 2015-10-22 15:00:01.418064 |  24.385
 2015-10-22 16:00:01.289062 |  24.385
 2015-10-22 17:00:01.174973 |  24.385
 2015-10-22 18:00:01.471065 |  24.385
 2015-10-22 19:00:02.50445  | 24.0131
 2015-10-22 20:00:01.269953 | 22.7116
 2015-10-22 21:00:01.169438 | 22.7116
 2015-10-22 22:00:01.165112 | 22.7116
 2015-10-22 23:00:01.165317 | 22.7116
 2015-10-23 00:00:01.170476 | 22.7116
 2015-10-23 01:00:01.171914 | 23.6413
 2015-10-23 02:00:01.16925  |  24.385
 2015-10-23 03:00:01.163014 | 25.8725
 2015-10-23 04:00:01.164198 |   27.36
 2015-10-23 05:00:01.168548 | 26.6162
 2015-10-23 06:00:01.167475 | 25.8725
 2015-10-23 07:00:01.166736 | 25.8725
 2015-10-23 08:00:01.170006 |  24.385
 2015-10-23 09:00:01.165955 | 25.8725
 2015-10-23 10:00:01.166001 | 23.6413
 2015-10-23 11:00:01.170822 |  24.385
 2015-10-23 12:00:01.197592 |  24.385
 2015-10-23 13:00:01.338696 | 24.5709
 2015-10-23 14:00:01.416016 | 25.8725
 2015-10-23 15:00:01.398318 | 25.8725
 2015-10-23 16:00:01.400292 | 25.8725
 2015-10-23 17:00:01.250604 | 25.8725
 2015-10-23 18:00:01.185805 | 24.9428

データの取得とJSONへの変換

まず、これをHTML中のJavaScriptから呼び出せるようにするためにphpを使ってJSONに変換する。
timestampはJavaScriptのDateを使って処理しやすいようにSELECTの時点でUNIX時間に変換しておく。

<?php
$dsn = 'pgsql:dbname=db host=postgres port=5432';
$user = 'username';
$password = 'password';

try{
    $dbh = new PDO($dsn, $user, $password);
    $sql = 'SELECT extract(epoch from time) AS unixtime,value from temp';
    $stt = $dbh->query($sql);
    $tempData = array();
    while($row = $stt->fetch(PDO::FETCH_ASSOC)){
        $tempData[]=array(
            'time'=>$row['unixtime'],
            'temp'=>$row['value'],
        );
    }
    header('Content-type: application/json');
    echo json_encode($tempData);
}catch (PDOException $e){
    print('Error:'.$e->getMessage());
    die();
}

$dbh = null;

これを適当なディレクトリに配置すると、このphpにアクセスすることで先ほどのテーブルの情報がすべてJSONに変換されて取得できる。先ほどのテーブルは1時間毎の室温なので、長期保存すると膨大な量になり重たくなることが考えられるので、必要なら取得量をSQLを発行する時点で抑えればいい気がする。(今回はしないけど)

グラフを書く

highcharts.jsを使ってグラフを書く。htmlはindex.htmlなど適当な名前で先ほど作ったphpと同じディレクトリに入れた。

<!DOCTYPE html>
<html>
  <head>
    <title>室温情報</title>
    <meta charset="utf-8">
    <script type="text/javascript" src="public/js/jquery.min.js"></script>
    <script src="public/js/highcharts/highcharts.js"></script>
    <script src="public/js/highcharts/modules/data.js"></script>
    <script src="public/js/highcharts/modules/exporting.js"></script>
    <script type="text/javascript" src="public/js/index.js"></script>
  </head>
  <body>
    <div id="screen"></div>
  </body>
</html>

次に、htmlから読み込むJavaScriptファイルは以下のように書いて、public/js/index.jsに入れた。なお、highcharts.jsなど必要なJavaScriptファイルも同じようにpublic/js/以下に保存している。

Highcharts.setOptions({
    global : {
        useUTC : false
    }
});

$(document).ready(function(){
    httpObj = new XMLHttpRequest();
    httpObj.open("get", "data.php", true);

    httpObj.onload = function(){
        var rtn = [];
        var tdata = JSON.parse(this.responseText);
        tdata.forEach(function(i){
            rtn.push([(new Date(Number(i.time) * 1000)).getTime(),Number(i.temp)]);
        });

        var chart = new Highcharts.Chart({
            chart :{renderTo: "screen",type: "line"},
            title :{text: "自宅の気温データ"},
            xAxis: {
                type: 'datetime',
                title: {text: "日時"}
            },
            yAxis :{title: {text: "気温[℃]"},min: -10,max: 50},
            series: [{name: "室温", data: rtn}]
        });
    };
    httpObj.send(null);
});

最終的なファイル配置はこんな感じ

.
├── data.php
├── index.html
└── public
    └── js
        └── index.js

終わり

これで表示したらこんな感じ

f:id:opamp_sando:20151024040153p:plain

とりあえず最低限度表示させてみた。もうすこしいろいろ凝りたいところではある。 でもまだデータ自体が少ないので一ヶ月くらいしてデータが集まった頃にまた改良するかな

ちなみに自分が見れればいいと思ってFirefoxくらいでしか動作確認してないのでどの程度他のブラウザでも動くかは不明。

参考資料

http://www.highcharts.com/

http://qiita.com/fantm21/items/891192da1a095e94c9e1

http://www.phpbook.jp/tutorial/pdo/index4.html

http://d.hatena.ne.jp/litt/20070904/p1

http://www.openspc2.org/reibun/javascript2/JSON/parse/0001/

http://blogs.yahoo.co.jp/montabross/67516003.html

http://so-zou.jp/web-app/tech/programming/javascript/grammar/object/date.htm

Firefox ブラウザ無料ダウンロード