2008年3月28日金曜日

Python: PaSoRiでSuicaの履歴を読み出す

このブログ記事をはてなブックマークに追加

Rubyを使ってPaSoRi経由でSuicaの乗車履歴を取得し、GoogleMapsやGoogleEarthで表示するって記事でPaSoRiなるものを知った。Edyもオサイフケータイも使ってないし、FeliCaについてはまったく興味がなかったのでスルーしてたんだけどこれは面白そう。早速、SONY RC-S320 非接触ICカードリーダ/ライタ PaSoRi 「パソリ」を買ってきていじってみた。因みに値段は約3000円。

まず、PaSoRiを読み出すためのライブラリとしてfelicaliblibpasoriなどがあったのでこれらを調べてみると、どうやらPythonで利用するためにはCで拡張モジュールを書かないとダメそうで、ちょっと面倒だなと思っていたが、FeliCa の Id を python で読むというページを見つけて、Pythonのctypesモジュールを使えば拡張無しでできそうなことを知る。

で、上記のサイトなどを参考にざざっとプログラムを書いてみた。ライブラリはWindowsを使っていることもあってfelicalibを選択。プログラムを実行させるには、このライブラリと駅コード情報が必要となる。路線・駅コード一覧・登録から、Excel形式ファイルを落としてきて、それの駅線・駅コード一覧のページをCSV形式に変換しておく(StationCode.csv)。店舗情報やバス情報の取得については、コードも増えるし面倒なので割愛。でも簡単に入れられるハズ。

実行すると以下のような履歴をすべて出力する。

改札機 運賃支払(改札出場) 2008年01月14日 赤羽駅 王子駅 8920円 改札機 運賃支払(改札出場) 2008年01月14日 王子駅 赤羽駅 9070円

ああ、面白かった。以下、ソース。

追記: バグ修正改良版については、Python: PaSoRiでSuicaの履歴を読み出す・その後を参照のこと。

#!/usr/bin/env python # -*- coding: shift_jis -*- """ read_felica.py by nox Suicaの履歴を出力するプログラム. """ from ctypes import * POLLING_ANY = 0xffff POLLING_SUICA = 0x0003 POLLING_EDY = 0xfe00 SERVICE_SUICA = 0x090f SERVICE_EDY = 0x170f # 端末種. TERMINAL = {3: "精算機", 4: "携帯型端末", 5: "車載端末", 7: "券売機", 8: "券売機", 9: "入金機", 18: "券売機", 20: "券売機等", 21: "券売機等", 22: "改札機", 23: "簡易改札機", 24: "窓口端末", 25: "窓口端末", 26: "改札端末", 27: "携帯電話", 28: "乗継精算機", 29: "連絡改札機", 31: "簡易入金機", 70: "VIEW ALTTE", 72: "VIEW ALTTE", 199: "物販端末", 200: "自販機" } # 処理. PROCESS = { 1: "運賃支払(改札出場)", 2: "チャージ", 3: "券購(磁気券購入)", 4: "精算", 5: "精算 (入場精算)", 6: "窓出 (改札窓口処理)", 7: "新規 (新規発行)", 8: "控除 (窓口控除)", 13: "バス (PiTaPa系)", 15: "バス (IruCa系)", 17: "再発 (再発行処理)", 19: "支払 (新幹線利用)", 20: "入A (入場時オートチャージ)", 21: "出A (出場時オートチャージ)", 31: "入金 (バスチャージ)", 35: "券購 (バス路面電車企画券購入)", 70: "物販", 72: "特典 (特典チャージ)", 73: "入金 (レジ入金)", 74: "物販取消", 75: "入物 (入場物販)", 198: "物現 (現金併用物販)", 203: "入物 (入場現金併用物販)", 132: "精算 (他社精算)", 133: "精算 (他社入場精算)" } def read_station_code(fname): global STATION_CODE STATION_CODE = {} data = [l.strip().split(",") for l in file(fname) if l[0] in ("0", "1", "2")] for d in data: STATION_CODE[tuple(map(lambda x: int(x, 16), d[0:3]))] = (d[4], d[5]) def read_felica(): flib = cdll.felicalib flib.pasori_open.restype = c_void_p pasori = flib.pasori_open() flib.pasori_init(pasori) flib.felica_polling.restype = c_void_p felica = flib.felica_polling(pasori, POLLING_SUICA, 0, 0) # Suicaを読む. # 履歴の読み出し. data = [] d = create_string_buffer(16) i = 0 while flib.felica_read_without_encryption02(felica, SERVICE_SUICA, 0, i, d) == 0: data.append(string_at(pointer(d), 16)) i += 1 flib.pasori_close(pasori) return data def parse_data(d): term = ord(d[0]) # 端末種. proc = ord(d[1]) # 処理. date = map(ord, d[4:6]) # 日付. year = (date[0] >> 1) + 2000 month = ((date[0] & 1) << 3) + (date[1] >> 5) day = date[1] & (1<<5) - 1 in_line = ord(d[6]) # 入線区. in_sta = ord(d[7]) # 入駅順. out_line = ord(d[8]) # 出線区. out_sta = ord(d[9]) # 出駅順. balance = map(ord, d[10:12]) # 残高. num = map(ord, d[12:15]) # 連番. region = ord(d[15]) # リージョン. if TERMINAL.has_key(term): print TERMINAL[term], else: print "不明", if PROCESS.has_key(proc): print PROCESS[proc], else: print "不明", print "%4d年%02d月%02d日" % (year, month, day), if proc in (70, 73, 74, 75, 198, 203): # 物販. hour = in_line >> 3 min = (in_line & (2<<3) - 1) << 1 + in_sta >> 7 sec = (in_sta & (2<<5) - 1) * 2 print "%02d時%02d分%02d秒" % (hour, min, sec), print "物販", elif proc in (13, 15, 31, 35): # バス. out_line = map(ord, d[6:8]) out_sta = map(ord, d[8:10]) print "バス", else: if region == 0: if in_line < 0x80: area = 0 # JR線. else: area = 1 # 関東公営・私鉄. else: area = 2 # 関西公営・私鉄. if term not in (0xc7, 0xc8, 0x05): if STATION_CODE.has_key((area, in_line, in_sta)): print "%s駅" % STATION_CODE[(area, in_line, in_sta)][1], else: print "不明", if STATION_CODE.has_key((area, out_line, out_sta)): print "%s駅" % STATION_CODE[(area, out_line, out_sta)][1], else: print "不明", print "%d円" % (balance[1] * 256 + balance[0]), print def main(): read_station_code("StationCode.csv") data = read_felica() for d in data: parse_data(d) if __name__ == "__main__": main()

続きを読む...

2008年3月25日火曜日

C++: OpenGLで正十二面体を回転させる

このブログ記事をはてなブックマークに追加

どう書く?orgにポリゴン表示のお題があるのだが、なんとなく時機を逸してしまった感があるのでここで。でも投稿を見た限り、どれもOpenGL使ってないなぁ。真っ先に挙がると思っていたのだが。

ここでは、OpenGL(GL/GLU/GLUT)を使って正十二面体を回転させている。ちょっと変更するだけで、マウス操作を加えたり、タイマー関数を利用したりできる。言語は敢えてC++で。GLUT使うなら本当はCの方がシックリ来るけど。コンパイルはWindowsだろうが、Linuxだろうが問題ないはず。

以下、ソースコード。

#include <GL/gl.h> #include <GL/glu.h> #include <GL/glut.h> class Rotate3D { private: static GLdouble m_matrix[16]; static double m_spin; static void Draw(); static void Rotate(GLdouble, GLdouble, GLdouble); static void Display(); static void SpinDisplay(); static void Reshape(int, int); public: Rotate3D() { } virtual ~Rotate3D() { } void Init(); }; GLdouble Rotate3D::m_matrix[16]; double Rotate3D::m_spin = 0.0; void Rotate3D::Draw(void) { glColor3d(0.5, 0.5, 0.5); glutSolidDodecahedron(); } void Rotate3D::Rotate(GLdouble x, GLdouble y, GLdouble z) { glTranslated(0.0, 0.0, -10.0); glRotated(x, 1.0, 0.0, 0.0); glRotated(y, 0.0, 1.0, 0.0); glRotated(z, 0.0, 0.0, 1.0); glTranslated(0.0, 0.0, 10.0); } void Rotate3D::Display(void) { glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Rotate(m_spin, m_spin, m_spin); glMultMatrixd(m_matrix); Draw(); glGetDoublev(GL_MODELVIEW_MATRIX, m_matrix); glutSwapBuffers(); } void Rotate3D::SpinDisplay(void) { m_spin = 0.1; glutPostRedisplay(); } void Rotate3D::Reshape(int w, int h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 100.0); } void Rotate3D::Init(void) { glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(300, 300); glutInitWindowPosition(100, 100); glutCreateWindow("Rotate3D"); glViewport(0, 0, 300, 300); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); glLoadIdentity(); gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glGetDoublev(GL_MODELVIEW_MATRIX, m_matrix); glutDisplayFunc(Display); glutReshapeFunc(Reshape); glutIdleFunc(SpinDisplay); } int main() { Rotate3D rotate3d; rotate3d.Init(); glutMainLoop(); return 0; }

続きを読む...

2008年3月24日月曜日

TeXの数式を簡単にEPSやJPEGなどの画像データに変換する方法

このブログ記事をはてなブックマークに追加

TeX wiki TeXの数式をDTPソフトによりメモ。

pLaTex一式(Ghostscript関連含む)がインストール済みのこと。EPSではなくJPEGなどの画像データに変換したい場合はImageMagickがインストール済みのこと。

上記のような数式を作りたい場合、以下のようなTeXテキストファイルを作成する(ここではeq.tex)。

\documentclass[12pt]{jarticle} \begin{document} \thispagestyle{empty} \[ \mathrm{RMSD} = \sqrt{\frac{1}{N}\sum_{i=1}^N{\delta_i^2}} \] \end{document}

上記のTeXファイルを、

platex eq.tex

としてDVIファイルを作成する。

dvipsでEPSファイルに変換。

dvips -E -Ppdf -x 5000 eq.dvi -o eq.eps

EPSのアウトラインを取る。

Windows:
gswin32c -dSAFER -q -dBATCH -dNOPAUSE -sDEVICE=epswrite -dEPSCrop -r9600 -sOutputFile=eq2.eps eq.eps

Lunix:
eps2eps eq.eps eq2.eps

EPSファイルをJPEGファイルに変換したい場合は以下を実行。

convert eq2.eps eq2.jpg

目的に合わせて、eq2.epsやep2.jpgを利用する。

Windowsなら、以下のようなコマンドスクリプト(ここではconvert_eq.cmdとして保存)を作っておけば、

convert_eq.cmd eq

これで変換できる。

platex %1.tex dvips -E -Ppdf -x 5000 %1.dvi -o %1.eps gswin32c -dSAFER -q -dBATCH -dNOPAUSE -sDEVICE=epswrite -dEPSCrop -r9600 -sOutputFile=%1_2.eps %1.eps convert %1_2.eps %1_2.jpg

Linuxも同様にシェルスクリプトを作成する。

続きを読む...

2008年3月14日金曜日

騒音を約99%カットするノイズキャンセリングヘッドホン

このブログ記事をはてなブックマークに追加

世界初、ノイズキャンセリング機能をデジタル化
周囲の騒音を約99%低減するノイズキャンセリングヘッドホン発売


騒音を約99%カットするノイズキャンセリング(以下、NC)ヘッドホンMDR-NC500Dがソニーから4月21日に発売されるらしい。NCヘッドホンの性能は騒音のカットだけではなく、音質や装着感も大きなウェイトを占めるので実際のモノを見るまでは何ともいえないが、良いものであれば約5万円の価格は高くはないし、買ってしまうかも。

因みに今使っているのは、BoseのQuietComfort2とSennheiserのPXC300、それにソニーのMDR-NC022だ。ソニーも前に比べれば随分まともになってきていると思う。QuietComfort2は今もよく使っているが、PXC300はMDR-NC022を使うようになってからほとんど使っていないな。コンパクトだといっても電源部分などが嵩張るのがきつい。

まあ、MDR-NC500Dについては発売してから調べてみようと思う。

続きを読む...

2008年3月13日木曜日

ActionScript 3.0で鏡文字

このブログ記事をはてなブックマークに追加

ずいぶん前からActionScript 3.0(以下、AS3)を覚えようと思っているのだが、未だに手付かずの状態だ。それでも少しぐらいは触っておこうと思ったので、前回のShootNumbersに引き続き、入力したテキストをそのまま鏡文字で出力するFlashアプリを作ってみた。こんなのは初歩の初歩だと思うが、AS3については素人であるので致し方ない。

ところで、Flashはこのブログの投稿記事に埋め込められないので、サイドバーの一番下に入れてみた。大したプログラムでもないのでそのうち外すかも。

で、問題の中身だが、AS3の流儀なんてほとんど知らないので、妙なコーディングしているかもしれない。その辺は勘弁して欲しい。キャレットの表示などを入れたりしたら思ったよりもコード量が増えてしまった。うーむ。肝心なのは、フォントをEmbedで埋め込む必要があることだろう。埋め込まないと文字の反転や回転ができない。

以下に示すソースコードを mxmlc MirrorImagedText.as として、コンパイルすればswfファイルを作成できる。使い方は普通にキーボードから文字を打ち込めばよい。バックスペース、改行が可能。マウス左クリックで全消去。

MirrorImagedChar.as

// MirrorImagedChar class by nox package { import flash.display.Sprite; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import flash.utils.Timer; import flash.events.TimerEvent; public class MirrorImagedChar extends Sprite { [Embed(systemFont='Courier New', fontName='myFont', mimeType='application/x-font' )] private static const myFont:Class; private var text_format:TextFormat = new TextFormat(); private var text_field_list:Array = new Array(); private var text_width_list:Array = new Array(); private var text_width:Number = 0; private var text_height:Number = 0; private var caret:TextField = new TextField(); private var blink_timer:Timer = new Timer(250); private function InitTextFormat():void { text_format.color = 0x00ff00; text_format.size = 14; text_format.font = "myFont"; } private function InitTextField(tf:TextField):void { tf.antiAliasType = flash.text.AntiAliasType.ADVANCED; tf.autoSize = TextFieldAutoSize.LEFT; tf.selectable = false; tf.embedFonts = true; tf.width = 300; tf.defaultTextFormat = text_format; } private function InitCaret():void { blink_timer.start(); blink_timer.addEventListener(TimerEvent.TIMER, CaretBlinker); addChild(caret); InitTextField(caret); caret.text = "_"; ShowCaret(); } private function CaretBlinker(event:TimerEvent):void { caret.visible = !caret.visible; } private function ShowCaret():void { caret.x = text_width; caret.y = text_height; } public function Print(str:String):void { var tf:TextField = new TextField(); InitTextField(tf); tf.text = str; tf.scaleX = -1.0; // for Mirror-Image if (str.charCodeAt(0) == 13) { text_width_list.push(text_width); text_width = 0; text_height += tf.textHeight; } else if (tf.textWidth < 0.001) return; text_field_list.push(tf); addChild(tf); tf.x = text_width + tf.width; // with (scaleX = -1.0) tf.y = text_height; text_width += tf.textWidth; ShowCaret(); } public function Backspace():void { var tf:TextField; if (text_field_list.length > 0) { tf = text_field_list.pop(); removeChild(tf); } else return; if (text_width > 0.001) text_width -= tf.textWidth; else if (text_width_list.length > 0) { text_width = text_width_list.pop(); text_height -= tf.textHeight; } ShowCaret(); } public function Clear():void { for each (var tf:TextField in text_field_list) removeChild(tf); text_field_list = []; text_width = 0; text_height = 0; ShowCaret(); } public function MirrorImagedChar() { InitTextFormat(); InitCaret(); } } }

MirrorImagedText.as

// MirrorImagedText class package { import flash.display.Sprite; import flash.events.*; [SWF(backgroundColor="0x000000", width="200", height="150", framerate="30")] public class MirrorImagedText extends Sprite { private var mic:MirrorImagedChar = new MirrorImagedChar(); private function InputChar(event:KeyboardEvent):void { if (event.keyCode == 8 || event.keyCode == 46) mic.Backspace() else mic.Print(String.fromCharCode(event.charCode)); } private function ClickHandler(event:MouseEvent):void { mic.Clear(); } public function MirrorImagedText() { stage.addEventListener(KeyboardEvent.KEY_DOWN, InputChar); stage.addEventListener(MouseEvent.CLICK, ClickHandler); addChild(mic); } } }

続きを読む...

2008年3月10日月曜日

GCCでSSEを使ったプログラミング

このブログ記事をはてなブックマークに追加

先日、GCCでIntelのSSEを使う話が出たのでメモ。

MMX: mmintric.h SSE: xmmintric.h SSE2: emmintric.h SSE3: pmmintric.h SSSE3: tmmintric.h

ついでにモトローラのAltiVecでは以下の通り。

AltiVec: altivec.h

上記をインクルードすればそれぞれで固有の命令が使える。何れにしろ、SIMDのプログラミングは面倒。因みに、PS3ではaltivec.hを利用してプログラミングしていくことになる。

続きを読む...

C++0x: ワーキングドラフト

このブログ記事をはてなブックマークに追加

C++0xのワーキングドラフトが2月に出ていた。

Working Draft, Standard for Programming Language C++

基本的に以前のC++とは互換性を取るようなので、今まで通りのコーディングでほとんどの場合、問題ないみたい。いろいろ便利に、安全に使える工夫がされているようだ。

ぱらぱらと流し読みしてみたけど、スレッド関連のユーティリティも入っている。時代も変わったものだなぁ…。

続きを読む...

2008年3月6日木曜日

PGP/GPGを薦めたいが…

このブログ記事をはてなブックマークに追加

個人情報漏洩などのセキュリティ問題が深刻になってきているが、それを防ぐための一つの手段として暗号化がある。特にメールの暗号化は重要だ。仕事で個人情報を含む文書をメールで送ったときにもし間違ったアドレスにでも送ろうものなら一大事である。このようなときでも暗号化してあれば安心だ。

ではどのようにして暗号化すればよいか。たとえばWindowsに付属しているOutlook Expressなどでは、暗号化のための仕組みが組み込まれている。しかし、これはデジタル署名が必要であり有料なのだ。もっと手軽に無料で利用できる仕組みは無いものか。実はある。それがPGP/GPGだ。PGPはPretty Good Privacyの略で、Philip Zimmermannが開発した暗号化ソフトウェアだ。一方、GPGはGnu Privacy Guardの略で、GnuPGとも呼ばれている。OpenPGPに準拠した無料の暗号化ソフトウェア(GPL)である。PGPとGPGの違いは、PGPは商用で利用するには有料であるが、特許を持つ暗号化アルゴリズムなども利用できる。GPGの方は商用で利用する場合でも無料であるが、特許に抵触するアルゴリズムは採用していない。個人的にはGPGを利用している。Linuxでは普通に使われているし、Windowsでも問題なく導入できる。

しかし、いくら優れた暗号化ソフトウェアであっても、周りが使っていなかったら意味が無い。暗号化して送っても読めないからだ。署名を入れても、それが正しいかどうか分からない。以前、インターネット上の電子メールが出始めた頃に電子メールアカウントを取得したのだが、アカウントを持っている知人がいなかったのでまったく無意味であったが、それと同じ状況だ。

なら、周りの人にもGPGを薦めれば良いかと思うのだが、ある理由で薦めにくいのだ。導入・使用方法が分かりづらいのである。ある程度コンピュータに詳しい人ならばまったく問題ないのだが、そうでないとちょっと面倒だ。PGPの公式サイトではWindowsのバイナリファイルも置いてあるが、それで使えるのはGUI版ではなくコマンドライン版である(個人的にはGUIよりもコマンドラインのほうが使いやすいと思っているが…)。

また、メールソフト自体が手軽にPGP/GPGを使えない場合が多い。GPGで暗号化したテキストをカット&ペーストで貼り付けたり、届いた暗号化メールからテキストを落として、コマンドラインで復号化したりするのはこの上なく面倒だ。もちろん、メールソフトによっては対応していたり、アドオンがあったりする。自分はThunderbirdを使っているので、Enigmailを利用している。便利だ。

そんなわけで、周りには薦めづらい。しかし、PGP/GPG対応のメールソフトなら使い勝手は悪くないし、何より人に覗き見されない安心感もある。暗号化されていない普通の平文のメールなんて誰かに常に覗き見されていると思ったほうがいいぐらいだ。安心感を得たい人はちょっと頑張って導入して欲しい。gpg/pgp/gnupgなどでネット上の検索をすればいくつかサイトがヒットする。使う人が増えれば増えるほど使い勝手は良くなってくるはずだ。

続きを読む...

2008年3月4日火曜日

自動ログアウトを回避する

このブログ記事をはてなブックマークに追加

csh系の場合。

unset autologout

これだけ。

続きを読む...

2008年3月3日月曜日

Willcomが新しいモバイルコミュニケーションマシンを開発

このブログ記事をはてなブックマークに追加

メモ。Intelのモバイル機器向けCPU、Atomを搭載したWindows Vistaマシンになるそうだ。2008年6月提供予定。

新しいモバイルコミュニケーションマシンの開発について

OSやCPUはなんでも良いので、とにかくサクサク動くものが欲しい。Vistaってところが不安だが…。いくら機能が充実していてもモッサリ動作では紙と鉛筆にすら劣ると思う。

続きを読む...