ThinkPad 起動時に出る PowerMgr.exe の 0x0000007E エラーを解決
ThinkPad T495s の起動時に、PowerMgr.exe が「0x0000007E 指定されたモジュールが見つかりません。」というエラーが出るようになりました。正確な時期は定かでないですが、BIOS アップデートか Windows 10 2004 へのアップデートをした後と思われます。
powermgr 0x0000007e error | ノートPCのQ&A【OKWAVE】 によると全世界的にも報告があるとのこと。さらには Lenovo Vantage の「デバイス設定」ページの右側にある「バッテリー状態」にもエラーメッセージが出ているとのこと。見てみると確かに、バッテリー容量表示の下に次のようなメッセージが。
Lenovo Power Manager ドライバーがインストールされていないか、正しく機能していません。Windows Update を実行するか、手動でここからインストールしてください。インストール後に、コンピュータを再起動します。
Lenovo のフォーラムをいくつか見てみると、暫定的な解決法が載っていました。
自分の環境(以下)ではうまくいきました。
- PC: ThinkPad T495s
- OS: Windows 10 バージョン 2004 (OSビルド 19041.508)
- Lenovo Power Manager のドライバーのバージョン: 10.0.127.0
保証はできませんが、他の誰かの参考になるよう、やった手順を記録しておきます。上記のフォーラムに書いてあったやり方と同じです。同じバージョンのドライバーをアンインストール→インストールしただけですが、それで治りました。
- Lenovo Settings Power Manager for Windows 10 (Version 1703 or Later) - ThinkPad - GB から Lenovo Settings Power Manager (n1fup87w.exe) と README (n1fup87w.txt) をダウンロード。
- README の supported models 一覧に、自分の機種が載っているかどうか確認。載っていなかったらここでやめておく。
- Windows キーと X (エックス) を同時に押した後、表示されるリストの中から「デバイス マネージャー」」をクリック。
- デバイスマネージャーが開く。「システム デバイス」の中の「Lenovo Power Manager」を右クリックして「プロパティ」をクリック。
- Lenovo Power Managerのプロパティが開く。「ドライバー」タブを開いて「バージョン」を確認。自分の場合は最新版と同じ 10.0.127.0 でした。
- 同じ画面の「デバイスのアンインストール」ボタンをクリック。
- デバイスのアンインストールが表示される。「このデバイスのドライバーソフトウェアを削除します。」にチェックを付けて、「アンインストール」ボタンをクリック。
- Power Manager がアンインストールされる。デバイスマネージャーから Lenovo Power Manager が消える。
- ダウンロードしておいた Lenovo Settings Power Manager (n1fup87w.exe) を実行し、表示に従ってインストール。
- デバイスマネージャーの「操作」>「ハードウェア変更のスキャン」を押して、Lenovo Power Manager が復活したことが確認できます。
- PC を再起動する。起動後、一瞬例のエラーメッセージが表示されたが、自動的に消えた。その後は出ていないみたい。Lenovo Vantage の「デバイス設定」>「バッテリー状態」のエラーメッセージも消えていました。
勝手に暗くなる ThinkPad X220t
悩めるドイツ単身赴任(1): インターネット
はじめに
ドイツへの単身赴任で困ったこと悩んだことを記録していくことにした。いつか何かの役に立つかもしれない。まずはインターネット接続の悩みから。
ドイツのインターネット事情
ドイツではブロードバンド契約のほとんどに最低契約期間が設けられている。たいていの場合、二年以内に解約した場合にはペナルティ(違約金)が発生する。僕の滞在予定期間ははじめから一年を切っていたのでペナルティ覚悟で契約せざるを得ないのだが、このペナルティの具体的な内容がよく分からなかった。契約後の工事に時間を要するとの忠告もあり、店舗まで足を運んだものの結局契約を思いとどまることになった。#問題はドイツ語の不自由な僕自身にもあるのだけど…
プリペイドなモバイルインターネット
同僚に相談したところ、代替手段としてプリペイド SIM を使ったモバイルインターネットを薦められた。これはプリペイドの名の通り、あらかじめお金をチャージしておくことで、チャージされた金額分だけ利用可能、それ以上は課金されないという種類のサービスだ。チャージ済の SIM カードを USB モデムやモバイルルータに挿すことで利用する。有線接続に比べると速度は出ないが、いつ止めても違約金が発生しないし、工事も不要でお手軽だ。
複数のキャリア (T-mobile, vodafone, O2, E-plus) と MVNO (FONIC, Blau, Congstar などなど) から、それぞれ複数のプリペイドプランが提供されており、少々分かりにくい。これまでに2つ試してみたのでここにメモしておく。
まとめ
FONIC Internet-Tagesflatrate | T-mobile Xtra web'n'walk DayFlat | |
---|---|---|
一日の支払い | 2.50 ユーロ | 4.95 ユーロ |
一月の支払い上限 | 25 ユーロ | 上限なし |
通信量の上限 | 500MB/日, 5GB/月 | 1GB,2GB/日 |
上限超過時の制限 | 64kbps | 384kbps (1GB超), 64kbps (2GB超) |
VoIP(Skype等)の利用 | 可能 | 契約上禁止 |
使用回線 | O2 | T-mobile |
参考(一月31日間利用時の支払い額) | 25 ユーロ | 153.45 ユーロ |
ここ3ヶ月ほど FONIC を使い続けてきたが、速度が安定しない日が多くなってきたため最近は T-mobile をメインに使っている。でも一日5ユーロは厳しい…
その1: FONIC Surf-Stick (FONIC Internet-Tagesflatrate)
http://www.fonic.de/html/prepaid-surf-stick-fuer-mobiles-internet.html
FONIC は O2 の回線を利用した MVNO。
プリペイド SIM カードが付いた USB モデムをSurf-Stick という名のパッケージで提供している。
家電量販店はもちろん、スーパーマーケットでも売られている。
パッケージの値段は 29.95 ユーロ。1日分の無料通信料が含まれている。
利用開始のためにはインターネットでアクティベート作業が必要。
https://www.fonic.de/selfcare/servlet/ActivationInfo に接続して SIM の番号や個人情報の入力をしなければならない。
付属のプリペイド SIM は Internet-Tagesflatrate (一日定額インターネット) プランにセットされている。一日の使用料は 2.50 ユーロ。接続を開始するとチャージから 2.50 ユーロが引かれ、その日の 23:59 までは追加金なしで利用可能になる。
ただし一日の通信量が 500 MB を超えると、それ以降は日付が変わるまで帯域制限がかかって最大 64 kbps でしか通信できなくなる。
その2: T-mobile Xtra web'n'walk DayFlat
http://www.t-mobile.de/tarife/0,10821,17773-_1081,00.html
T-mobile はドイツの大手通信キャリア。カバー範囲が広く、O2 に比べて安定しているという噂を聞いて試しに購入してみた。
T-mobile の店舗に行ってモバイルルータ用のプリペイド SIM が欲しいと伝えて出てきたものが Xtra web'n'walk DayFlat プラン。
一日の使用料は 4.95 ユーロ。FONIC と同様、0:00-23:59 の間 4.95 ユーロぽっきりで利用可能。
一日の通信料が 1 GB を超えると通信速度が 384 kbps に制限され、2GB を超えた時点で 64 kbps に絞られる。制限はその日限り。
ただし T-mobile は VoIP, P2P, テザリングなどの利用を許可していない(注意書きに明記されている)。
特に利用ポートやプロトコルに制限がかかっているわけではないので使おうと思えば使えてしまうが…
EP121 と firefox4
ASUS のスレートPC である Eee Slate EP121 を購入。
ブラウザとして firefox 4 を入れてみたが、デフォルト設定のままだとタッチ操作が不便極まりない。あれこれググった結果、以下の設定で多少快適になった。
アドレスバーに about:config と入力し、設定値の一部を以下のように変更する。
browser.gesture.pinch.out.shift=cmd_fullZoomReset
browser.gesture.pinch.out=cmd_fullZoomEnlarge
browser.gesture.pinch.in.shift=cmd_fullZoomReset
browser.gesture.pinch.in=cmd_fullZoomReduce
browser.gesture.twist.threshold=15
browser.gesture.twist.right=Browser:ForwardOrForwardDuplicate
browser.gesture.twist.left=Browser:BackOrBackDuplicate
上記の設定で、
二本指を広げたり狭めたりするとズームイン・アウトされ、
二本指を左右に(15度以上)回転させるとページを戻ったり進んだりできるようになった。
本当は macbook みたく三本指のスワイプで戻る進むを実現したかったが、うまくいかなかったので回転操作で代用した。windows では三本指スワイプって使えないんだっけ?
Eee note EA800 と Eee Note Sync の対話をキャプチャしてみた (2)
日本アジアカップ優勝おめでとう!
EA800 の解析事情
ここで外からちまちま TCP でつっついている間に、海外では EA800 を開腹して中の Micro SD を取り出すなどして解析が進められているらしい。
EA800のfirmwareが解析中 その1 | OSAKANA TAROのメモ帳
そのうち独自ファームウェアまで作られそうな勢いだ。熱い。
ファイルのダウンロード
あいにく手元に工具や SD カードリーダーが無いので、とりあえず外からつっつくのを続けてみたいと思う。色々試してみた結果、EA800 内のファイルをダウンロードする方法は概ね理解できた。大まかな流れとしては、xmlfile コマンドを使って EA800 内にあるファイルのリストを取得し、リストに載っている各ファイルを downloadfile コマンドでダウンロード、とすれば良さそうだ。
python スクリプト
2010-02-05 追記: フォルダIDに対応するパスが判明したのでソース先頭のコメント部に追記した
#!/usr/bin/env python #-*- coding: utf-8 -*- # # ea800_downloader.py # # Usage: python ea800_downloader.py FOLDER_ID OUT_DIR # # FOLDER_ID: ダウンロードしたいフォルダの ID (下記参照) # # | ID | folder path | # |----+------------------------------------| # | 0 | /eTablet/var/ebook | # | 2 | /eTablet/var/photos | # | 4 | /eTablet/var/enotes | # | 8 | ? | # | 12 | /eTablet/etc/db | # | 14 | /eTablet/etc/template | # | 31 | /eTablet | # | 32 | /usr/local/eTablet/bin | # | 33 | /eTablet/etc | # | 34 | /eTablet/var | # | 35 | /usr/local/eTablet/lib | # | 37 | /usr/local/eTablet/bin/ebookreader | # # OUT_DIR: ダウンロードしたフォルダの格納先ディレクトリ # OUT_DIR ディレクトリの直下に files と xmlfiles の 2 つのディレクトリを作り、 # files ディレクトリにはダウンロードしたファイルを格納し、 # xmlfiles ディレクトリにはファイルのリスト(XML形式)を格納する。 import sys import os import socket import xml.etree.ElementTree as etree import hashlib BUF_SIZE = 8192 class Connection(object): """ Simple wrapper class for Raw TCP connection. Refer to: http://docs.python.org/howto/sockets.html Attributes: - _sock """ def __init__(self, address): self._sock = socket.socket() self._sock.connect(address) def send(self, op): totalsent = 0 op = op.encode("utf-8") op_size = len(op) while totalsent < op_size: sent = self._sock.send(op) if sent == 0: raise RuntimeError, \ "socket connection broken" totalsent = totalsent + sent def recv(self, size=1): read = 0 buf = [] while read < size: data = self._sock.recv(BUF_SIZE) if data == "": raise RuntimeError, \ "socket connection broken" read = read + len(data) buf.append(data) return "".join(buf) def close(self): self._sock.close() class Downloader(object): """ File downloader for Eee Note EA800. Attributes: - _cs - _ds - _files_folder - _xmlfiles_folder """ def __init__(self, out_dir): # connect to command socket self._cs = Connection(("169.254.2.1", 20000)) # recieve welcome message self._cs.recv() # connect to data socket self._ds = Connection(("169.254.2.1", 20001)) # recieve welcome message self._cs.recv() self._files_folder = os.path.join(out_dir, "files") self._xmlfiles_folder = os.path.join(out_dir, "xmlfiles") def close(self): # close both connections self._ds.close() self._cs.close() def _md5sum(self, data): m = hashlib.md5() m.update(data) return m.hexdigest() def downloadfile(self, folder_id, path): """execute 'downloadfile' command""" # send "downloadfile" request op = "downloadfile\n%d\nPath=%s\n\\n::\\n" % (folder_id, path) self._cs.send(op) # receive "downloadfilereturnvalue" response res = self._cs.recv() res_list = res.split(b"\n") assert res_list[0] == "downloadfilereturnvalue", "not correct response" # extract status and file_size from "downloadfilereturnvalue" response status = res_list[1] file_size = int(res_list[2]) md5 = res_list[3][4:] # drop first 4 character "md5=" assert file_size > 0, "file_size is not positive integer" # prepare file and directory to output data outfile_path = os.path.join(self._files_folder, "%02d" % folder_id, path.lstrip("/")) outfile_dir = os.path.dirname(outfile_path) try: os.makedirs(outfile_dir) except OSError: pass # output data to local directory data = self._ds.recv(file_size) assert self._md5sum(data) == md5, "MD5 check sum invalid" outfile = open(outfile_path, "wb") outfile.write(data) outfile.close() print "downloaded: %s" % path def listfile(self, folder_id): """execute 'listfile' command""" # send "listfile" request op = "listfile\n%d\n\\n::\\n" % folder_id self._cs.send(op) # receive "listfilereturnvalue" response res = self._cs.recv() res_list = res.split(b"\n") assert res_list[0] == "listfilereturnvalue" # extract status and file_size from "listfilereturnvalue" response status = res_list[1] file_size = res_list[2] if file_size.endswith("\\n::\\n"): file_size = file_size[:-6] file_size = int(file_size) assert file_size > 0 # output data to console data = self._ds.recv(file_size) print data def xmlfile(self, folder_id): """execute 'xmlfile' command""" # send "xmlfile" request op = "xmlfile\n%d\n\\n::\\n" % folder_id self._cs.send(op) # receive "xmlfilereturnvalue" response res = self._cs.recv() res_list = res.split(b"\n") assert res_list[0] == "xmlfilereturnvalue" # extract status and file_size from "xmlfilereturnvalue" response status = res_list[1] file_size = res_list[2] file_size = int(file_size) assert file_size > 0 # prepare file and directory to output data outfile_path = os.path.join(self._xmlfiles_folder, "%02d.xml" % folder_id) try: os.makedirs(self._xmlfiles_folder) except OSError: pass # output data to local directory outfile = open(outfile_path, "wb") data = self._ds.recv(file_size) outfile.write(data) outfile.close() # parse xmlfile tree = etree.parse(outfile_path) return tree def downloadfolder(self, folder_id): """recursive download files in a folder""" tree = self.xmlfile(folder_id) self._traversal_and_download(tree.getroot(), u"", folder_id) def _traversal_and_download(self, elm, folder_name, folder_id): if elm.tag == "file": path = folder_name + u"/" + elm.get("name") try: self.downloadfile(folder_id, path) except AssertionError, e: print e else: for child in elm.getchildren(): self._traversal_and_download(child, elm.get("name", u""), folder_id) if __name__ == "__main__": folder_id = int(sys.argv[1]) out_dir = sys.argv[2] d = Downloader(out_dir) d.downloadfolder(folder_id) d.close()
利用例
例えばコマンドプロンプトで
python ea800_downloader.py 4 C:\tmp\eeenote
とすれば、フォルダID = 4 のフォルダ (/eTablet/etc/enotes) 内のファイルが C:\tmp\eeenote\files\12 内にダウンロードされます。
ただし自分用に適当に作ったものですので、何が起こっても責任は取れません。ファイルを削除してしまうようなことは無いと思いますが、ご利用は自己責任でお願いします。
org-mode はやっぱり便利
Emacs の org-mode はやはり便利だ。構造化文書を書くための機能が充実している。今回久しぶりに はてな でブログを書くにあたっては、下記サイトを参考に org-mode で下書きを作った。
org-modeからはてなダイアリーに投稿するelispを書いた
http://d.hatena.ne.jp/r_takaishi/20100211/1265888107
simple-hatena-mode を導入していなかったのと、個人的な都合もあって以下のように変更して使った。
(defvar org-export-hatena-notation-section '("^\\* \\([^\t\n\r\f]*\\)\n\\[.*$" "* \\1")) (defvar org-export-hatena-notation-subsection '("^\\*\\* \\([^\t\n\r\f]*\\)$" "** \\1")) (defvar org-export-hatena-notation-subsubsection '("^\\*\\*\\* \\([^\t\n\r\f]*\\)$" "*** \\1")) (defvar org-export-hatena-notation-quote '("[ ]*#\\+BEGIN_QUOTE[ \t]*" ">>" "[ ]*#\\+END_QUOTE" "<<")) (defvar org-export-hatena-notation-super-pre '("[ ]*#\\+BEGIN_EXAMPLE[ \t]*" ">||" "[ ]*#\\+END_EXAMPLE" "||<")) (defvar org-export-hatena-notation-src '("[ ]*#\\+BEGIN_SRC[ \t]*\\([^\t\n\r\f]*\\)" ">|\\1|" "[ ]*#\\+END_SRC" "||<")) (defvar org-export-hatena-temp-buffer-name "*Org Hatena Export*") (defun org-export-hatena-section (notation) (goto-char (point-min)) (while (re-search-forward (nth 0 notation) nil t) (replace-match (nth 1 notation)))) (defun org-export-hatena-begin-to-end (notation) (goto-char (point-min)) (while (re-search-forward (nth 0 notation) nil t) (replace-match (nth 1 notation))) (goto-char (point-min)) (while (re-search-forward (nth 2 notation) nil t) (replace-match (nth 3 notation)))) (defun org-export-hatena (beg end) (interactive "r") (let ((diary (buffer-substring beg end)) (begin-to-end `(,org-export-hatena-notation-quote ,org-export-hatena-notation-super-pre ,org-export-hatena-notation-src)) (section `(,org-export-hatena-notation-section ,org-export-hatena-notation-subsection ,org-export-hatena-notation-subsubsection)) (buffer (get-buffer-create (generate-new-buffer-name org-export-hatena-temp-buffer-name)))) (set-buffer buffer) (insert diary) (mapc (function org-export-hatena-begin-to-end) begin-to-end) (mapc (function org-export-hatena-section) section) (switch-to-buffer-other-window buffer)))
上記を .emacs に追記した。変換リージョンを選択して M-x org-export-hatena とすれば、はてな記法に変換されたものが *Org Hatena Export* というテンポラリバッファに格納される。これをコピペしてブラウザからはてなへ投稿。ほんとは simple-hatena-mode を導入して投稿まで自動化させるべきですね。
Eee note EA800 と Eee Note Sync の対話をキャプチャしてみた (1)
前置き
Eee Note EA800 とは
台湾から ASUS 社の Eee note EA800 (以後 EA800 と呼ぶ)を輸入して三週間ほど経過した。EA800 はモノクロ液晶を使った電子ノート端末である。付属のスタイラスペンを使って、こんな具合にノートを取ることができるすぐれものだ。
Eee Note Sync とは
Eee Note Sync は、EA800 に付属する Windows PC との同期用アプリケーションである。Eee Note Sync を使うことで、電子書籍や電子ノートなどのデータを PC と EA800 との間で送受信できる。しかしその機能は十分とは言い難い。特に電子ノートに関しては、できるのはページデータ(gif)とメタデータ(xml)を CAB で圧縮したもの(.nte という拡張子のファイルになる)を PC へエクスポートして、同 .nte ファイルを EA800 へインポートすることだけ。PC上での閲覧や、ページの差し替え並べ替え、ノートの分割合併など、個人的に欲しかった機能はことごとく無い。せめて .nte ファイルが zip だったらもう少し取り回しが楽なんだけど。
EA800 を PC へ接続した際の通信内容
EA800 を PC へ接続した際に、PC (Eee Note Sync) と EA800 の間でどのような通信が行われるかを調べてみた。
EA800 を PC へ接続する
付属の USB ケーブルを使って EA800 を PC へ接続すると、以下のようにして Ethernet ネットワークが構築される。
- EA800 と Windows XP マシン (以下 PC と呼ぶ) を USB 接続
- EA800 の画面上に選択肢が表示されるので 「Eee Note Sync同歩模式」(Eee Note Sync との同期)を選択する
初回接続時であれば、ここでドライバや Eee Note Sync が PC へインストールされる(※ドライバや Eee Note Sync のインストールは「安装Eee Note Sync以及…」を選んだときのみ実行されるのでこれは嘘でした)- PC が EA800 を RNDIS device として認識する
- PC と EA800 が(仮想的な) Ethernet ネットワークで接続される
- EA800 は IP アドレス 169.254.2.1 を名乗る。EA800 内では DHCP サーバが起動している
- PC が EA800 内の DHCP サーバへ IP アドレスの払出しを要求。EA800 に IP アドレス 169.254.2.3 が与えられる
Eee Note Sync が EA800 を検知する
EA800 が PC に接続されたことを Eee Note Sync が検知する (おそらく Ping を使って)
コネクションの確立開始
Eee Note Sync は EA800 の接続を検知すると、「制御用コネクション」と「データ用コネクション」2つのコネクションの確立を試みる。後述するように、Eee Note Sync と EA800 との通信は「制御用」と「データ用」の2つのコネクションを使って行われる。FTP のようである。
制御用コネクションの確立
まず、制御用コネクション確立までの通信を以下に示す。なお、以降、[->] で PC (Eee Note Sync) から EA800 へのメッセージ送信を示し、[<-] で、EA800 から PC へのメッセージ送信を表すこととする。
- [->] Eee Note Sync が適当な空きポート(ここでは TCP 1331 とする)から、EA800 の TCP 20000 ポートへ接続を試みる (普通の TCP 3-way Handshake)
- [<-] EA800 の TCP 20000 ポートから、Eee Note Sync の TCP 1331 ポートへレスポンスが返る
commandconnectreturnvalue welcome to connect the server. server version 1.0(2010-07-16 10:00:00) version 3.0(2010-7-28 18:00)\n::\n
改行文字には 0x0a (LF) が使われている。また、メッセージの終端を示すための記号には "\n::\n" が使われているようだ。ここで "\n" は文字通り 0x5c ("\") と 0x6e ("n") であって、改行文字 (0x0a) を表すものではないので注意。また、メッセージの末尾には 0x0a (LF) は付かない。
データ用コネクションの確立
続いてデータ用のコネクションが確立される。
- [->] Eee Note Sync が適当な空きポート(ここでは TCP 1332 とする)から、EA800 の TCP 20001 ポートへ接続を試みる (普通の TCP 3-way Handshake)
- [<-] EA800 の TCP 20001 ポートから、Eee Note Sync の TCP 1332 ポートへレスポンスが返る
dataconnectreturnvalue welcome to connect the server data socket. server version 1.0(2010-07-16 10:00:00) version 3.0(2010-7-28 18:00)\n::\n
ログイン
2つのコネクション確立が終わると、制御用のコネクションを使って、Eee Note Sync から EA800 へログイン要求が送信される。
- [->] Eee Note Sync が制御用コネクション上で EA800 へログイン要求メッセージを送信
login 1 \n::\n
"1" の意味は不明。
- [<-] EA800 が Eee Note Sync へ応答メッセージを送信
loginreturnvalue 0 username=ASUS EeeNote passwd=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx version=1.0.1.36 \n::\n
なんとこちらからパスワードを入力する前に、EA800 からパスワードが送られてきた。さすがに平文では無いようだが。
Eee Note Sync 上にパスワードダイアログが表示される
このタイミングで、Eee Note Sync 上にパスワードの入力を促すダイアログが表示される。正しいパスワードを入力すると、特に通信は発生せず次のステップへ進む。このことから察するに、パスワードの検証は EA800 内で行われるのではなく、EA800 からパスワードに関する情報を受けとった Eee Note Sync が代理で検証を行っているようだ。
ちなみに、EA800 のセキュリティ設定でパスワードによる保護を有効にしていない場合は、EA800 から送信される passwd は空となり、Eee Note Sync 上でのパスワードダイアログも表示されない。
システム情報の取得
ログインが成功すると、Eee Note Sync から EA800 に対してシステム情報の取得要求が送信される。
- [->] Eee Note Sync が制御用コネクション上でシステム情報要求メッセージを送信
systeminfo -1 \n::\n
ここも "-1" の意味は不明。
- [<-] EA800 からシステム情報が送信される。
systeminforeturnvalue Internal SD 181 3049 6% External SD N/A Device Name ASUS EeeNote Device UUID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx fwboot V1.0.1 kernelrom V1.0.1.71 TW 0000 \n::\n
key, value, ..., key, value が改行で区切られているだけのようだ。ここで得られた情報が Eee Note Sync の "System Info" タブで表示されるのだろう。
ファイルリストの取得
続いて、EA800 内の DB ファイルリスト(ファイル一覧)が取得される。DB ファイルというのは、ノートとページの関係や作成日時などのメタデータを管理するファイルであり、実体は sqlite の .db ファイルである。このことから EA800 内のデータは sqlite で管理されていると考えられる。
- [->] Eee Note Sync が制御用コネクション上で DB ファイルリストの取得要求を送信する。
listfile 12 \n::\n
"12" の意味は不明。 "12" はリストの取得対象となるフォルダを示すIDである。後述するように、EA800 内のフォルダには ID が振られていて、"12" は DB ファイルリストを格納するフォルダの ID となっている。イメージ的には shell 上で "ls 12" をしてファイルリストを取得しているのに近いかな。
- [<-] EA800 から制御用コネクションを使って応答メッセージが返る。このメッセージに DB ファイルリスト自体は含まれない。
listfilereturnvalue 1 257\n::\n
"1" も "257" も何を指すものかは分からない。 "1" はおそらくステータスコード(成功を示す)"。"257" はファイルリストのサイズ。
- [<-] ファイルリスト自体は *データ用* コネクションを使って EA800 から Eee Note Sync へ送信される。
4096 12 stickymemodata.db 798084\n10240 12 voicedata.db 798084\n285 12 DBVerionInfo.inf 798084\n368640 12 ebookdata.db 798084\n16384 12 phonebookdata.db 798084\n6144 12 tagdata.db 798084\n1046528 12 notedata.db 798084\n62464 12 photodata.db 798084\n
メッセージの中身(ファイルリスト)は、ファイルサイズ、謎の数字(12)、ファイル名、謎の数字(798084)、改行(0x0a)、区切り文字("\n")、の 6 つの値を 1 セットとして、ファイルの数だけ(ここでは 8 つ)のセットが結合されて送られる。
ここで取得されるリストには、以下の 8 つのファイルが掲載された。
- stickymemodata.db
- voicedata.db
- DBVerionInfo.inf
- ebookdata.db
- phonebookdata.db
- tagdata.db
- notedata.db
- photodata.db
DBファイルのダウンロード
Eee Note Sync はリストに載っている 8 つの DB ファイルそれぞれについて、ダウンロードを実行する。
- [->] まず、Eee Note Sync は制御用コネクションを使って、stickymemodata.db のダウンロードを要求する。
downloadfile 12 Path=stickymemodata.db \n::\n
"12" の意味は不明。 "12" は前述した通り DB フォルダの ID。
- [<-] EA800 は制御用コネクションを使って応答する。
downloadfilereturnvalue 1 4096 md5=66c9a2dbf2041239700795efe2448c87 \n::\n
ファイル stickymemodata.db のサイズ(4096)とハッシュ値(66c9a...)が含まれている。"1" の意味は不明。 "1" はおそらく成功を示すステータスコード。
- [<-] EA800 はデータ用コネクションを使って、stickymemodata.db の内容を送信する。
SQLite format 3... [stickymemodata.db ファイルの実体]
- 以下、同様の処理が、残りの 7 つのファイルそれぞれについて繰り返される。
- voicedata.db のダウンロード
downloadfile 12 Path=voicedata.db \n::\n
downloadfilereturnvalue 1 10240 md5=7ab5ea8cd345f06f7b44ccf177e970d9 \n::\n
- DBVerionInfo.inf のダウンロード
downloadfile 12 Path=DBVerionInfo.inf \n::\n
downloadfilereturnvalue 1 285 md5=b12b4341a96dd901bf5867568a09f5f1 \n::\n
- ebookdata.db のダウンロード
downloadfile 12 Path=ebookdata.db \n::\n
downloadfilereturnvalue 1 368640 md5=3199fa4a8e270a352805c3123a7a5aea \n::\n
- phonebookdata.db のダウンロード
downloadfile 12 Path=phonebookdata.db \n::\n
downloadfilereturnvalue 1 16384 md5=488502c85dafbff66cea58dceebb2e76 \n::\n
- tagdata.db のダウンロード
downloadfile 12 Path=tagdata.db \n::\n
downloadfilereturnvalue 1 6144 md5=43a5f7851af89ffd1d637c02af4dbc5e \n::\n
- notedata.db のダウンロード
downloadfile 12 Path=notedata.db \n::\n
downloadfilereturnvalue 1 1046528 md5=39202016cf5ee1b30f5ba0f04cf03edd \n::\n
- photodata.db のダウンロード
downloadfile 12 Path=photodata.db \n::\n
downloadfilereturnvalue 1 62464 md5=07156c4dfef0bb9e9d51c1b56b20d4fa \n::\n
ファイルダウンロード完了
8 つのファイル全てのダウンロードが終わると、Eee Note Sync から EA800 へダウンロード完了を示すメッセージが送信される。
- [->] Eee Note Sync は制御用コネクションを使って、EA800 へダウンロード完了を示すメッセージを送信する。
downloaddbcompleted 0 13 0001-01-01 00:00:00 -1\n\n::\n
"0", "13", "-1" の意味は不明。日付も謎。
ここまでで、PC 内の C:\Documents and Settings\[ユーザ名]\My Documents\EeeNote\[UUID下12桁]\tempdatabase フォルダに、上記の 8 つのファイルがダウンロードされている。Eee Note Sync も内部で sqlite を使ってこれらのファイルに含まれるメタデータを参照するのだと思う。
とりあえずここまで
引き続き、電子ノートデータのダウンロードとアップロード部分を調べてみたい。