ARToolkitのセットアップメモ

ARToolkitで開発してみようと思い立ったのでセットアップの自分メモ。

工学ナビ – 「攻殻機動隊」「電脳コイル」の世界を実現! – ARToolKitを使った拡張現実感プログラミング

工学ナビの中の人の研究と周辺 ゼロからはじめるARToolKit on VisualC++ 2008 Express Edition

VC++ 2008 Express EditionでARToolkitをビルドしてみる – やざわラボ Wiki

Visual C++ 2008 Express Editionを使ったのですが、1番目のサイトの情報そのままで大体はOK。

サンプルの実行は3番目のサイトにあるように、「デバッグ」-「新しいインスタンスを開始」でsimpleLiteとか実行できます。

うっかりハマったのは、Dataフォルダの置き場所。というか、実行したいサンプルのそれぞれのオプションに

「デバッグ」-「作業ディレクトリ」 – ARToolkit/binの絶対パス

を書かないとダメだったんですね。さもなくば、ARToolKit\examples\simpleLiteの下にDataフォルダ置いてください。

あと、DSVLはバイナリが公開されているので、ダウンロードしてくれば自分でビルドする必要なし。


PythonでMIDI出力をしてみる

既存のPythonで作ったWindowsアプリケーションにMIDI出力を組み込む用事があったので、実験してみました。

参考サイトはこちら。

sulume blog» ブログアーカイブ » python で MIDI を使う

MIDIIO.dllというのはおーぷんMIDIぷろじぇくとで公開されているMIDIメッセージ入出力用ライブラリです。

これもダウンロードして、pyファイルと同じ場所に置いておきます。

で、ソースコードはこちら。

import ctypes
import time

midiiolib = ctypes.windll.LoadLibrary(r".\MIDIIO.dll")

c_deviceName = ctypes.create_string_buffer(32)

midiiolib.MIDIOut_GetDeviceName(0, c_deviceName, 32)
midiout = midiiolib.MIDIOut_Open(c_deviceName.value)

c_mess = ctypes.create_string_buffer(3)
c_mess.value = '\x90\x3C\x64'

midiiolib.MIDIOut_PutMIDIMessage(midiout, c_mess.value, 3)

time.sleep(3)

midiiolib.MIDIOut_Close(midiout)

説明することもあまりないですが、8行目のMIDIOut_GetDeviceNameで、MIDI出力の先頭のデバイスの名前を先に取得します。

で、その名前を使ってMIDIOut_Openで出力デバイスを開きます。

11~12行目ではノートを作成します。とりあえずドの音でも鳴らしておきます。この辺もMIDIIO.dllに入っていたドキュメントのサンプルと同じ。

あとはMIDIOut_PutMIDIMessageで出力するだけです。

ちゃんと閉じておかないと、次回音が鳴らなかったりする(オープンに失敗します)ので、MIDIOut_Closeで閉じておきましょう。

実験として、ちょっと長いデータを指定してみる。

import ctypes
import time

midiiolib = ctypes.windll.LoadLibrary(r".\MIDIIO.dll")

c_deviceName = ctypes.create_string_buffer(32)

midiiolib.MIDIOut_GetDeviceName(0, c_deviceName, 32)
midiout = midiiolib.MIDIOut_Open(c_deviceName.value)

notes = ['\x90\x3C\x64',
         '\x90\x3E\x64',
         '\x90\x40\x64',
         '\x90\x41\x64',
         '\x90\x43\x64',
         '\x90\x45\x64',
         '\x90\x47\x64',
         '\x90\x48\x64']

c_mess = ctypes.create_string_buffer(3)

for note in notes:
    c_mess.value = note

    midiiolib.MIDIOut_PutMIDIMessage(midiout, c_mess.value, 3)
    time.sleep(0.5)

time.sleep(1.0)

midiiolib.MIDIOut_Close(midiout)

和音を鳴らしてみるテスト。

import ctypes
import time

midiiolib = ctypes.windll.LoadLibrary(r".\MIDIIO.dll")

c_deviceName = ctypes.create_string_buffer(32)

midiiolib.MIDIOut_GetDeviceName(0, c_deviceName, 32)
midiout = midiiolib.MIDIOut_Open(c_deviceName.value)

notes = ['\x90\x3C\x64',
         '\x90\x40\x64',
         '\x90\x43\x64']

c_mess = ctypes.create_string_buffer(3)

for note in notes:
    c_mess.value = note

    midiiolib.MIDIOut_PutMIDIMessage(midiout, c_mess.value, 3)

time.sleep(3.0)

midiiolib.MIDIOut_Close(midiout)

とりあえずこれだけできれば満足なので終了。


ネットワークドライブからデータを全部バックアップする

TeraStationのHDDが1台故障したので、交換を前に中身を全部バックアップする必要がありました。

ちなみに以前同じような症状でRAID崩壊させたことがあるので今回は慎重に…

共有フォルダのルートがたくさんあるので、それをいかに簡単にコピーするかがキモ。

共有フォルダ自体はコピーしようとドラッグアンドドロップすると、ショートカットが作られてしまう。

やりたいことは、PCを使ってLAN内のNASからデータを全部コピーして、ローカルに接続してあるUSB HDDにバックアップすること。

で、robocopyコマンドというのが便利っぽいので使ってみた。使ったOSはWindows Vista。標準コマンド?

まずは対象のフォルダ名一覧の取得から。

C:\> net view \\NAS

みたいにすると、フォルダ一覧が文字情報として取れます。

で、robocopy。

robocopyでフォルダをバックアップ/同期させる - @IT

どうやらrsyncみたいに使えるよう。

C:\> robocopy /mir \\NAS\dir1 C:\Backup\dir1

という感じで書けば対象ディレクトリの中身をミラーリングコピーしてくれます。

ちなみに受け側ディレクトリは作っておかなくても勝手に作ってくれます。

というわけで、先ほどのnet viewの結果を流し込んだコマンドリストを作ってbatファイルに保存して、実行。

全部きれいにバックアップできました。

今xcopyって推奨されてないんですね。知らなかった。


FON2202をFailSafeモードで復旧させる

前回FON2202にカスタムファームを入れようとして失敗して、何もできなくなっていた状況の続き。ファームウェアを強制的に上書きする方法がありました。

前回:FON2202のファームウェアのビルド : blog.loadlimit – digital matter –

lostmanさんにコメント欄でFONの復旧方法を教えていただいたので実践。
作業は概ね以下の通り。

(鬱とSEと)コンピュータ: FON2202のFailSafeモード

Failsafe Mode – FON Wiki Beta

Wikiでは有線をおすすめされているので、有線で試してみました。
というより、無線でやったらなぜか成功しなかったので…

  1. とりあえず電源が入っている場合は、ACアダプタを外してください。
  2. LANケーブルをPCとFONのCOMPUTERポートに直結します。他は何も繋がず。
  3. FONの底面にある赤いボタンを先の細いもので押します。
  4. 押しながらACアダプタを繋ぎます。
  5. 15秒くらいそのまま待って、ボタンを離します。
  6. IPはDHCPで配られます。配られるまで1分以上かかるかも。気長に待つ。
  7. ランプが色々光ったあと、POWERとWIRELESSが同時にオレンジで点滅するようになったらFailsafeモード突入成功。

ちなみに配られるIPは192.168.1.x/255.255.255.0なので、他のネットワークアダプタが同じ範囲を使っていないか注意。

IP取得成功するとこんな感じ。

Ethernet adapter ローカル エリア接続:

        Connection-specific DNS Suffix  . : lan
        IP Address. . . . . . . . . . . . : 192.168.1.193
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 192.168.1.1

で、 http://192.168.1.1/ にアクセス。

ユーザ名とパスワードを求められるので、ユーザ名に「admin」、パスワードに本体裏のシリアル番号(S/N)を入力。

あとはフォームにtar.gz形式のファームウェアファイルを指定して送信するだけ。30分ほど待つと勝手にFONが再起動して、復旧できます。

DEVELOPERファームに復旧したので、再度再起動してSSH接続成功!やー、シリアル接続するハメにならなくて良かった。

以下も参考。

FON2202にDEVELOPERファームを入れてSSHアクセスできるようにする : blog.loadlimit – digital matter –


RAID構成のHDDのファームウェアを更新する

今となっては過去の話となりつつあるSeagateのファームウェア問題。

参考:SeagateのBarracuda 7200.11などにアクセス不能になる不具合

自宅のサーバがちょうどこの問題のど真ん中で、SeagateのBarracuda ES.2 1TBを4台使ってRAID 5を構成しているのでした。で、このHDDのファームウェアを更新しようというのが今回の話。

再起動のタイミングで条件が揃うとHDDが起動できなくなるバグなので、問題が発覚してからなるべく再起動しないようにビクビクしながら使ってたのですが、さすがにWindows Updateが溜まってきて限界に。

とりあえずバックアップ用のHDDを用意しました。家に転がってた1TBと500GBのHDDに分割して全部退避できました。

ちなみにRAIDはハードウェアRAIDで、カードは3ware Escalade 9500S-4LP。

手順は色々なところで解説されていると思うので、ざっくりと。

とりあえず公式
Seagate ナレッジ ベース

まず、3wareの管理画面から各ユニットのシリアルナンバーを調べてメモ。

で、それをシリアル番号確認ユーティリティに突っ込む。

見たところ、家の環境では4台中2台が問題のあるHDDだった模様。同じ店で同時に買ったんですけどね。

アップデート用のISOをダウンロードして、CD-Rに焼く。

チップセット統合のRAIDなら、そのままファームウェアアップデートできると読んだので、とりあえず更新する必要のないRAID以外のシステムドライブを物理的に外して、CDからブート。

アップデートツールからはRAID以下のHDDを認識せず…

まぁ、何となく予想はしていたので、RAIDからHDDを外して一台ずつオンボードのSATAに接続してアップデートする方針に。

HDDをRAIDカードから外す関係上、外した状態で一度でもRAIDカードに通電したらRAIDが崩壊すると思ったので(一台ずつなら許容範囲と言えなくもないけど、復旧必要になってしまうので)、RAIDカード自体を先にPCIスロットから外します。

で、HDDを一台マザーボード上のSATAポートに差して、CDアップデータ起動。

これでファームウェアのアップデート自体は成功したので、残りの対応が必要なもう一台もアップデート。

アップデート不要と言われた2台はアップデートせずにそのまま残しておきました。

で、RAIDカードのSATAポートとHDDの対応が変わらないようにケーブルを接続し直して、PCIスロットに戻して起動。

成功ー。何もなかったかのようにRAIDはそのまま起動しました。


実はFiddlerがすごすぎたので、機能まとめ紹介

今までFiddlerをただのセッションの中身を確認できるLocal Proxyとしてしか見ていなかったのですが
改めて良く調べると色々できることが多すぎると判明。感動したので便利な機能をまとめてみました。

先に簡単に説明しておくと、FiddlerはMicrosoftが無料で配布しているWeb Debugging Proxyです。

Windows環境にインストールして、ブラウザとサーバの間の通信を読んだり操作したりできます。

配布サイトはこちら。

Fiddler Web Debugger – A free web debugging tool

動作環境は「Windows 2000 / XP / 2003 / Vista with Microsoft .NET Framework v2.0 or later」

今回使ったバージョンは、2009年9月10日時点で最新の安定版、2.2.4.6。

とりあえず簡単に目次。

  • セッションのリクエスト一覧を確認する
  • やり取りしているヘッダ情報を見る
  • リクエスト・レスポンスの実際のデータの中身を確認する
  • セッション一覧表示をフィルタリングして、特定のContent-Typeだけ表示するようにする
  • リクエストを自分で作る
  • AutoResponderで特定のURLに対して、ローカルのファイルを割り当てる
  • Fiddler起動時にProxyを自動的に切り替える
  • Webページに対する一連の自動テストを実行する
  • サンドボックス
  • JScript.NETで拡張できる
  • C#やVB.NETで拡張できる
  • UIに好きな項目を追加できる
  • ブレークポイントの設定

マークアップエンジニアにおすすめしたいのは

  • セッション一覧表示をフィルタリングして、特定のContent-Typeだけ表示するようにする
  • AutoResponderで特定のURLに対して、ローカルのファイルを割り当てる

あたり。

プログラマには全部おすすめ。

詳細は「続き」からどうぞ。

この投稿の続きを読む »


NSISから使える、起動中のプロセスを削除するプラグイン

常駐アプリケーションを作ったはいいが、アンインストールしようとしたときにプロセスが起動していると、削除できなくて困る。

というわけで、プロセスを殺す目的のプラグインDLLを作成。コンパイル済みファイルはエントリの最後に。

taskkillコマンド使えという話ですが、Windows XP Home Editionにはtaskkillコマンドが含まれていないので。

今回もさっくりC#で。C#.NETで作ってしまうと、そのままではNSISで使えないのだけど、.NETで作ったDLLをNSISのプラグインとして使う方法は以下のエントリを参照。

NSISで、C#で書かれた自作のDLLを使う : blog.loadlimit – digital matter –

ソースは以下。C#でクラスライブラリとしてプロジェクトを作成。プロセス名を指定すると、マッチしたプロセスを全部終了してくれます。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace TaskKill
{
    public class TaskKill
    {
        [DllImport("Psapi.dll", SetLastError = true)]
        static extern bool EnumProcesses(
           [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U4)] [In][Out] UInt32[] processIds,
             UInt32 arraySizeBytes,
             [MarshalAs(UnmanagedType.U4)] out UInt32 bytesCopied
          );

        [DllImport("kernel32.dll")]
        static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
           uint dwProcessId);

        [Flags]
        public enum ProcessAccessFlags : uint
        {
            All = 0x001F0FFF,
            Terminate = 0x00000001,
            CreateThread = 0x00000002,
            VMOperation = 0x00000008,
            VMRead = 0x00000010,
            VMWrite = 0x00000020,
            DupHandle = 0x00000040,
            SetInformation = 0x00000200,
            QueryInformation = 0x00000400,
            Synchronize = 0x00100000
        }

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool CloseHandle(IntPtr hObject);

        [StructLayout(LayoutKind.Sequential)]
        public struct StringBuffer
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string text;
        }

        [DllImport("psapi.dll")]
        private static extern bool EnumProcessModules(IntPtr hProcess, out IntPtr lphModule, int cb, out int lpcbNeeded);
        [DllImport("psapi.dll")]
        private static extern int GetModuleBaseName(IntPtr hProcess, IntPtr hModule, out StringBuffer lpBaseName, int nSize);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool TerminateProcess(IntPtr hProcess, int uExitCode);

        public static void KillByName(string pname)
        {

            UInt32 arraySize = 1024;
            UInt32 arrayBytesSize = arraySize * sizeof(UInt32);
            UInt32[] processIds = new UInt32[arraySize];
            UInt32 bytesCopied;

            bool success = EnumProcesses(processIds, arrayBytesSize, out bytesCopied);

            if (!success)
            {
                return;
            }
            if (0 == bytesCopied)
            {
                return;
            }

            UInt32 numIdsCopied = bytesCopied >> 2;

            if (0 != (bytesCopied & 3))
            {
                UInt32 partialDwordBytes = bytesCopied & 3;

                return;
            }

            for (UInt32 index = 0; index < numIdsCopied; index++)
            {
                IntPtr hProcess = OpenProcess(
                    ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead | ProcessAccessFlags.Terminate,
                    false,processIds[index]);
                if (hProcess.ToInt32() != 0)
                {
                    IntPtr hMod = IntPtr.Zero;
                    int cbNeeded;
                    StringBuffer szProcessName;
                    szProcessName.text = "<unknown>";

                    if (EnumProcessModules(hProcess, out hMod, Marshal.SizeOf(hMod), out cbNeeded))
                    {
                        GetModuleBaseName(hProcess, hMod, out szProcessName, Marshal.SizeOf(szProcessName));
                    }

                    if (szProcessName.text == pname)
                    {
                        TerminateProcess(hProcess, -1);
                    }

                    CloseHandle(hProcess);
                }
            }

        }

    }
}

で、これをNSISの配布ファイルに含めておいて、

; アンインストーラ
Section "Uninstall"
  ; アンインストールで使用するプラグインの準備
  InitPluginsDir
  SetOutPath $PLUGINSDIR
  File "TaskKill.dll"

  ; hogehoge.exeが起動していたら、それを落とす
  CLR::Call /NOUNLOAD "TaskKill.dll" "TaskKill.TaskKill" "KillByName" 1 "hogehoge.exe"

  ; インストールしたファイル群削除
  Delete $INSTDIR\*.*

  CLR::Destroy
SectionEnd

という感じでnsiファイルを記述。

ファイルは下記リンクからダウンロードしてお使いください。

download TaskKill.dll


スクリーンキーボード

Vistaでソフトウェアキーボードというか、スクリーンキーボードを作ろうとしてハマったのでメモ。ただし、結局解決には至っていません。アプローチ変えてしまったので。

スクリーンキーボードを作るにあたって検索すると、imm32関連の関数を使ったサンプルが諸々出てくるのだけど、どうやらこの関数がWindows XPまでのもので、Vista以降はTSF(Text Services Framework)というものに置き換わっているらしい。

これに気づかず、

IntPtr hIMC = ImmGetContext(AHwnd);
IntPtr hKL = GetKeyboardLayout(0);
int dwSize = ImmGetConversionList(hKL, hIMC, AText, IntPtr.Zero, 0, GCL_CONVERSION);

とかやっていたのだけど、ImmGetConversionListの結果が必ず0になってしまう。

imm32 を使ったプログラムの互換性について

試してないけど、TSFのドキュメントは以下。

Text Services Framework Reference (Windows)

で、ここまでわかったところで、結局Linuxでやることになりました。


NSISで、C#で書かれた自作のDLLを使う

NSISでインストーラ&アンインストーラを作っていて、インストール時に一緒にインストールしたAdobe AIRアプリケーションを、アンインストール時に同時にアンインストールしたいという要件。

Adobe AIRアプリケーションのアンインストールは、手動ならWindowsのコントロールパネルからできるので、ここの情報をレジストリから引っ張り出して実行すればOK。この辺は良くある手段。

で、レジストリからアンインストールに必要なプログラムの実行パス情報を持ってこようとしたら、Adobe AIRでは、Uninstall以下のサブキーの名前が毎回変わるので、検索する必要があることが発覚。

NSISにはレジストリの特定のキーを読む機能はあっても、キーを検索する機能はないので、DLLで拡張を作成。さっくり適当にC#でレジストリを検索して文字列を返すDLLを作成してみた。

ちなみにアンインストール情報はHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall以下にあります。

ということで、必要な動作はUninstall以下のサブキーを全部開いてDisplayNameが目的の名前と一致するサブキーを探すこと。ソースは以下。

SearchUninstall.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace SearchUninstall
{
    public class SearchUninstall
    {
        public static string Find(string name)
        {
            string keyPath = "";

            // レジストリからの読み取り
            Microsoft.Win32.RegistryKey regkey =
                Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", false);
            // キーが存在しないときは null が返される
            if (regkey == null) return null;

            // 文字列を読み込む
            // 読み込む値が存在しないときは null が返される
            string stringValue = (string)regkey.GetValue("string");

            // sub以下のすべてのキー名を取得
            string[] keyNames = regkey.GetSubKeyNames();
            foreach (string k in keyNames)
            {
                string tmp_keyPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" + k;
                Microsoft.Win32.RegistryKey regkey2 =
                    Microsoft.Win32.Registry.LocalMachine.OpenSubKey(tmp_keyPath, false);
                try
                {
                    string displayName = (string)regkey2.GetValue("DisplayName");
                    if (displayName == name)
                    {
                        keyPath = tmp_keyPath;
                        break;
                    }
                }
                catch (Exception e)
                {
                    ;
                }
                finally
                {
                    regkey2.Close();
                }
            }

            //閉じる
            regkey.Close();

            return keyPath;
        }
    }
}

で、出来上がったDLLをNSISに読み込ませようとしても、どうにも動かない。

Dependency walkerで他のDLLと見比べてみると、C#で作られたDLLはエントリポイントが見えない。

そう言えばそんな話もあったような。

参考:WINAMP.COM | Forums – How can I use a C# DLL in NSIS

NSISからでは.NETのDLLが読めないらしい。ということで、見つけたのが以下。.NETのDLLを使えるようにするプラグイン。

Call .NET DLL methods plug-in – NSIS

CLR.zipをダウンロードしてきて、NSISをインストールしたフォルダのPluginsフォルダに入れておけばOK。

先に作ったSearchUninstall.dllはnsiファイルと同じ場所に入れておく。

で、nsiファイルは以下の感じ。Uninstall部分の必要部分を抜粋。

; アンインストーラ
Section "Uninstall"
  ; アンインストールで使用するプラグインの準備
  InitPluginsDir
  SetOutPath $PLUGINSDIR
  File "SearchUninstall.dll"

  ; AIRアプリケーションのアンインストーラを探す
  CLR::Call /NOUNLOAD "SearchUninstall.dll" "SearchUninstall.SearchUninstall" "Find" 1 "HogeHogeAir"
  pop $0
  CLR::Destroy

  ReadRegStr $4 HKLM $0 "UninstallString"

  ; AIRアプリケーションのアンインストーラをPassiveモード(自動処理)で実行する
  ExecWait "$4 /passive"

  ; 後片付け
  Delete "$PLUGINSDIR\SearchUninstall.dll"
SectionEnd

これで、アンインストール時にAdobe AIRアプリケーションのアンインストーラも勝手に起動して削除できる。

CLR超便利。プラグインを作るのが相当楽に。


FON2202のファームウェアのビルド

La Fonera2.0ことFON2202のファームウェアのビルドに成功したのでメモ。

環境はDebian lenny。主な手順はここ。

build fon-ng

でもこのままやってもビルドできませんでした。

まずは手順にある通り、必要なパッケージをインストール。

$ sudo aptitude install subversion g++ libdigest-crc-perl ncurses-dev zlib1g-dev gawk bison flex autoconf intltool-debian intltool

他のサイトで、以下も必要みたいな記事を読んだのでインストール。

$ sudo aptitude install gettext pkg-config libz-dev ccache libncurses-dev unzip

libdigest-crc-perlがaptだと古いという話なので、CPANから最新をインストール。

$ cpan
CPAN> install Digest
CPAN> install Digest::CRC
CPAN> install YAML

で、手順通りレポジトリからtrunkを落とすとビルドできないので、tags/Flipper-2.2.5.0をダウンロードします。

$ svn co http://svn.fonosfera.org/fon-ng/tags/Flipper-2.2.5.0
$ cd Flipper-2.2.5.0/
$ ./install.sh
$ cd openwrt/
$ make menuconfig

メニュー画面ではとりあえず何もせずにそのままExitで設定を保存。

いざmake。V=99は詳細表示オプション。なくてもいい。

$ make V=99

超時間かかる。Core2QudaのVista上のVirtualPCで2時間くらい。

で、完了。

$ ll bin/
合計 8388
-rw-r–r– 1 dev dev   65536 2009-08-13 09:24 loader.bin
-rwxr-xr-x 1 dev dev   11860 2009-08-13 09:24 meraki-loader.elf
-rwxr-xr-x 1 dev dev 3039219 2009-08-13 09:24 openwrt-fonera2-vmlinux.elf
-rw-r–r– 1 dev dev  786432 2009-08-13 09:24 openwrt-fonera2-vmlinux.image
-rw-r–r– 1 dev dev 4653060 2009-08-13 09:24 openwrt-fonera2.image
drwxr-xr-x 3 dev dev    4096 2009-08-13 08:32 packages

packagesディレクトリにはipk形式のパッケージファイル一式ができてます。
これが
http://www.fonera.be/rep/FON2202/index.php
これってことか。サイトにはpackagesディレクトリに含まれていないものもたくさんあるけど。
逆に言うと、ipkファイルを作る必要性はなさそう。

このままでは正しくファームウェアを書き換えられたかわからないので、ちょっと軽くいじっておきます。
Fonera->facebookをスペースでチェックを外す

ちょっとここで通常のファームウェアの構成を調べる。

$ wget http://download.fonosfera.org/LATEST/20090421_FON2202_2.2.5.0_Flipper_DEVELOPER.tar.gz
$ tar xvzf ./20090421_FON2202_2.2.5.0_Flipper_DEVELOPER.tar.gz
20090421_FON2202_2.2.5.0_Flipper_DEVELOPER.image
upgrade
fonera20_fon.image

できたファイルはディレクトリを含まず上記3つ。

$ ll
-rw-r–r– 1 dev dev 4653060 2009-04-22 01:05 20090421_FON2202_2.2.5.0_Flipper_DEVELOPER.image
-rw-r–r– 1 dev dev 4529210 2009-04-22 02:50 20090421_FON2202_2.2.5.0_Flipper_DEVELOPER.tar.gz
lrwxrwxrwx 1 dev dev      48 2009-08-13 19:25 fonera20_fon.image -> 20090421_FON2202_2.2.5.0_Flipper_DEVELOPER.image
-rwxr-xr-x 1 dev dev     305 2009-04-01 00:57 upgrade

fonera20_fon.imageはシンボリックリンクでimageファイルの実体へ。で、upgradeがシェルスクリプトになってて、これが実行される、と。

$ cat upgrade
#!/bin/ash

VERSION=$(cat /etc/fon_version)
FAILSAFE=$(cat /etc/failsafe)

if [ "$VERSION" = "2.2.1" -o "$VERSION" = "2.2.2" -o "$VERSION" = "2.2.3" -o "$VERSION" = "2.2.4" -o "$FAILSAFE" = 1 ]
then
mtd -r write fonera20_fon.image image > /dev/null 2>&1
#(sleep 4; reboot) &
return 0

else return 1; fi

なるほど、バージョンチェックして必要ならmtdコマンドで書き換え実行ということね。ということは、すでに2.2.5になってるこのFONでは上書きできないということか。

というわけで書き換える。

$ vi ./upgrade

シンプルに以下の感じに。

#!/bin/ash

mtd -r write fonera20_fon.image image > /dev/null 2>&1
return 0

で、リンク先を書き直し。tar.gz作成。

$ rm fonera20_fon.image
$ ln -s openwrt-fonera2.image fonera20_fon.image
$ tar zcvf openwrt-fonera2.tar.gz openwrt-fonera2.image fonera20_fon.image upgrade

で、できあがったopenwrt-fonera2.tar.gzを管理画面経由でFONにアップロード。

Firmware Update
Failed to identify upload.

Σ(゚Д゚)ガーン

なんだろ。ちなみに公開されているtar.gzを展開→再圧縮しただけでも反映に失敗したので、何かtarの作り方に秘密があるっぽい。
仕方ないのでimageファイルを転送して、FON上のSSHで反映することに。
以下、FONのSSH。

# cd /tmp/
# mtd -r write fonera20_fon.image image
Unlocking image …
Writing from fonera20_fon.image to image …  [w]
Rebooting …

で、どうやら書き込み完了。wktkしながらブラウザで確認…

緑の画面から書き変わってオレンジの画面に…あれ?SSHが効かない…?ん?Facebookのアイコンは残ったまま…?

Facebookは画面から消すのに何か別の作業がいるのかもしれないと思うことにして、SSHは…?プラグインのところにも出てこないし…

しかもブラウザからファーム書き戻そうとしてもバージョンが同じだから上書きできないし!!

\(^o^)/オワタ

シリアルケーブル手に入れるまで放置で…

もしくは管理画面からアップできるtar.gzの作り方、か。

※追記(2009/10/12)

lostmanさんに教えていただいた方法で復旧できました。
FON2202をFailSafeモードで復旧させる : blog.loadlimit – digital matter –