ルギア君の戯言

雑多な記事。

Linux 版の ePSXe で遊ぶ

いや、別に普通に Windows で遊ぶか Wine を使ってくれればいいと思うんだ。だってこっちのほうが (一部のグラボ以外は) 確実に遅いし、なんのメリットもない。ちなみにとある N から始まるメーカーのチップを搭載したグラボ×公式ドライバでは

$ glxgears

のフレームレートが (フレームリミットがかからないため) 5 桁 (ウィンドウの大きさデフォルト) 行くという鬼仕様だけどそれでも Windows でやったほうが (多分) 速い。


この記事は僕の単なるメモに過ぎず、今は入手できないファイルを使っていることをご理解の上見て欲しい。ただし、このために音がでない、とかそういうことは無い。


さて Linux でも動かせる PSX エミュとしては ePSXe と PCSX がある。が、バイナリであるのは ePSXe だけ。これは以下の理由による。

  • このマシンは 64 bit 動作中
  • PCSX のソースは 64 bit ではコンパイル不可


もちろん、ePSXe のバイナリも 32bit。
ePSXe を動かすためには、とりあえず、

# rpm -q gtk+1.i686 SDL.i686
gtk+1-1.2.10-53m.mo8.i686
SDL-1.2.14-6m.mo8.i686

をインストールしておく。

映像のプラグインはとりあえず

  • SDL のものは segmentation fault となっちゃって使い物にならず。
  • ソフトレンダリングはやはりお察しの通りだろう。

となると MesaGL か XGL になるが、この 2 つはあまり変わらなかった。上の某 N 社チップだと XGL のほうが速いと思う。

音声のプラグインは

  • ALSA 対応のものがなく、SDLOSS になる
  • やっぱり SDL だとトラブルが多いので (古い SDL のライブラリを入れるのが癪なので)

最近のだと /dev/dsp がないとかいうトンデモになっているから

# modprobe snd-pcm-oss

して作ってやる。


ここで使ったのはかの有名な (?) Eternal SPU。ただ、C++ で組まれているらしく、libstdc++-libc6.2-2.so.3 を要求してくるので、

# yum install libstdc++3.2.i686

で昔のをインストールし、適当にシンボリックリンク貼るかコピーすればおk。


あとは適当にやれば動く (コラ

Matrox カードでデュアルスクリーン環境を構築する

以下のようなパッチを xorg-x11-drv-mga に当てた。

diff -ur xf86-video-mga-1.4.13.orig/src/mga.h xf86-video-mga-1.4.13/src/mga.h
--- xf86-video-mga-1.4.13.orig/src/mga.h        2012-02-08 02:36:22.062533733 -0500
+++ xf86-video-mga-1.4.13/src/mga.h     2012-02-07 21:50:14.572730442 -0500
@@ -337,6 +337,13 @@
     int                        mastervideoRam;
     int                        slavevideoRam;
     Bool               directRenderingEnabled;
+
+    void  *            mappedIOBase;
+    int                        mappedIOUsage;
+
+    void  *            mappedILOADBase;
+    int                        mappedILOADUsage;
+
     ScrnInfoPtr        pScrn_1;
     ScrnInfoPtr        pScrn_2;
 } MGAEntRec, *MGAEntPtr;
diff -ur xf86-video-mga-1.4.13.orig/src/mga_driver.c xf86-video-mga-1.4.13/src/mga_driver.c
--- xf86-video-mga-1.4.13.orig/src/mga_driver.c 2012-02-08 02:36:22.091533731 -0500
+++ xf86-video-mga-1.4.13/src/mga_driver.c      2012-02-07 21:51:58.448335431 -0500
@@ -1374,6 +1374,9 @@
 
     xf86SetDDCproperties(pScrn, MonInfo);
 
+ /* MGARestore(pScrn);  */
+ /* MGAUnmapMem(pScrn); */
+
     return MonInfo;
 }
 
@@ -2674,30 +2677,51 @@
 #ifdef XSERVER_LIBPCIACCESS
     struct pci_device *const dev = pMga->PciInfo;
     struct pci_mem_region *region;
-    void **memory[2];
-    int i, err;
+    int err;
 #endif
 
 
     if (!pMga->FBDev) {
 #ifdef XSERVER_LIBPCIACCESS
-        memory[pMga->io_bar] = &pMga->IOBase;
-        memory[pMga->framebuffer_bar] = &pMga->FbBase;
 
-        for (i = 0; i < 2; i++) {
-            region = &dev->regions[i];
-            err = pci_device_map_range(dev,
-                                       region->base_addr, region->size,
-                                       PCI_DEV_MAP_FLAG_WRITABLE,
-                                       memory[i]);
+           pciaddr_t fbaddr = pMga->FbAddress;
+           pciaddr_t fbsize = pMga->FbMapSize;
+       err = pci_device_map_range(dev,
+                                  fbaddr, fbsize,
+                                  PCI_DEV_MAP_FLAG_WRITABLE,
+                                  (void **)&pMga->FbBase);
 
-            if (err) {
+       if (err) {
                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-                           "Unable to map BAR %i.  %s (%d)\n",
-                           i, strerror(err), err);
+                           "Unable to map Framebuffer %08llX %llx.  %s (%d)\n", (long long)fbaddr, (long long)fbsize,
+                           strerror(err), err);
                 return FALSE;
-            }
-        }
+       }
+       else
+                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+                           "MAPPED Framebuffer %08llX %llx to %p.\n", (long long)fbaddr, (long long)fbsize, pMga->FbBase);
+
+
+
+       if(pMga->entityPrivate->mappedIOUsage == 0)
+       {
+               region = &dev->regions[pMga->io_bar];
+               err = pci_device_map_range(dev,
+                                          region->base_addr, region->size,
+                                          PCI_DEV_MAP_FLAG_WRITABLE,
+                                          &pMga->entityPrivate->mappedIOBase);
+
+               if (err) {
+                       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                                  "Unable to map IO Region %i.  %s (%d)\n",
+                                  pMga->io_bar, strerror(err), err);
+                       return FALSE;
+               }
+       }
+       
+       pMga->entityPrivate->mappedIOUsage ++;
+       pMga->IOBase = pMga->entityPrivate->mappedIOBase;
+
 #else
        /*
         * For Alpha, we need to map SPARSE memory, since we need
@@ -2748,16 +2772,23 @@
     if (pMga->iload_bar != -1) {
 #ifdef XSERVER_LIBPCIACCESS
         region = &dev->regions[pMga->iload_bar];
-        err = pci_device_map_range(dev,
+
+       if(pMga->entityPrivate->mappedILOADUsage == 0)
+       {
+               err = pci_device_map_range(dev,
                                    region->base_addr, region->size,
                                    PCI_DEV_MAP_FLAG_WRITABLE,
-                                   (void *) &pMga->ILOADBase);
-       if (err) {
-           xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-                      "Unable to map BAR 2 (ILOAD region).  %s (%d)\n",
-                      strerror(err), err);
-           return FALSE;
+                                   (void *) &pMga->entityPrivate->mappedILOADBase);
+               if (err) {
+                       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                                  "Unable to map BAR 2 (ILOAD region).  %s (%d)\n",
+                                  strerror(err), err);
+                       return FALSE;
+               }
        }
+
+       pMga->ILOADBase = pMga->entityPrivate->mappedILOADBase;
+       pMga->entityPrivate->mappedILOADUsage ++;
 #else
        pMga->ILOADBase = xf86MapPciMem(pScrn->scrnIndex,
                                        VIDMEM_MMIO | VIDMEM_MMIO_32BIT |
@@ -2787,10 +2818,17 @@
     
     if (!pMga->FBDev) {
 #ifdef XSERVER_LIBPCIACCESS
-        pci_device_unmap_range(dev, pMga->IOBase, 
-                              dev->regions[pMga->io_bar].size);
+           pMga->entityPrivate->mappedIOUsage --;
+           if(pMga->entityPrivate->mappedIOUsage == 0)
+           {
+                   pci_device_unmap_range(dev, pMga->IOBase, 
+                                          dev->regions[pMga->io_bar].size);
+                   pMga->entityPrivate->mappedIOBase = NULL;
+           }
+
+           xf86DrvMsg(pScrn->scrnIndex, X_INFO, "UNMAPPING framebuffer 0x%08llX, %p.\n", (long long)pMga->FbBase, pMga->FbMapSize);
         pci_device_unmap_range(dev, pMga->FbBase, 
-                              dev->regions[pMga->framebuffer_bar].size);
+                              pMga->FbMapSize);
 #else
        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->IOBase, 0x4000);
        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->FbBase, pMga->FbMapSize);
@@ -2803,8 +2841,14 @@
 
     if ((pMga->iload_bar != -1) && (pMga->ILOADBase != NULL)) {
 #ifdef XSERVER_LIBPCIACCESS
-        pci_device_unmap_range(dev, pMga->ILOADBase,
+           pMga->entityPrivate->mappedILOADUsage --;
+           if(pMga->entityPrivate->mappedILOADUsage == 0)
+           {
+                   pci_device_unmap_range(dev, pMga->ILOADBase,
                               dev->regions[pMga->iload_bar].size);
+                   pMga->entityPrivate->mappedILOADBase = NULL;
+           }
+
 #else
        pMga->ILOADBase = xf86MapPciMem(pScrn->scrnIndex,
                                        VIDMEM_MMIO | VIDMEM_MMIO_32BIT |
@@ -2787,10 +2818,17 @@
     
     if (!pMga->FBDev) {
 #ifdef XSERVER_LIBPCIACCESS
-        pci_device_unmap_range(dev, pMga->IOBase, 
-                              dev->regions[pMga->io_bar].size);
+           pMga->entityPrivate->mappedIOUsage --;
+           if(pMga->entityPrivate->mappedIOUsage == 0)
+           {
+                   pci_device_unmap_range(dev, pMga->IOBase, 
+                                          dev->regions[pMga->io_bar].size);
+                   pMga->entityPrivate->mappedIOBase = NULL;
+           }
+
+           xf86DrvMsg(pScrn->scrnIndex, X_INFO, "UNMAPPING framebuffer 0x%08llX, %p.\n", (long long)pMga->FbBase, pMga->FbMapSize);
         pci_device_unmap_range(dev, pMga->FbBase, 
-                              dev->regions[pMga->framebuffer_bar].size);
+                              pMga->FbMapSize);
 #else
        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->IOBase, 0x4000);
        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->FbBase, pMga->FbMapSize);
@@ -2803,8 +2841,14 @@
 
     if ((pMga->iload_bar != -1) && (pMga->ILOADBase != NULL)) {
 #ifdef XSERVER_LIBPCIACCESS
-        pci_device_unmap_range(dev, pMga->ILOADBase,
+           pMga->entityPrivate->mappedILOADUsage --;
+           if(pMga->entityPrivate->mappedILOADUsage == 0)
+           {
+                   pci_device_unmap_range(dev, pMga->ILOADBase,
                               dev->regions[pMga->iload_bar].size);
+                   pMga->entityPrivate->mappedILOADBase = NULL;
+           }
+
 #else
        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->ILOADBase, 0x800000);
 #endif

ちなみにタイムゾーンが -0500 (EST) になっていることに対するツッコミはなしで。

/etc/X11/xorg.conf
Section "Monitor"
 Identifier  "Monitor0"
 VendorName  "CPQ"
 ModelName   "P110"
 Option      "DPMS" "On"
 HorizSync   30-107
 VertRefresh 60,75,85
EndSection

Section "Monitor"
 Identifier  "Monitor1"
 VendorName  "SAMSUNG"
 Option      "DPMS" "On"
 ModelName   "SyncMaster 740BX"
 VertRefresh 60
EndSection

Section "Screen"
 Identifier   "Screen0"
 Device       "Videocard0"
 Monitor      "Monitor0"
 DefaultDepth 24
 SubSection "Display"
  Viewport  0 0
  Depth     24
  Modes     "1600x1200" "1280x1024" "1024x768" "800x600" "640x480"
 EndSubSection
EndSection

Section "Screen"
 Identifier   "Screen1"
 Device       "Videocard1"
 Monitor      "Monitor1"
 DefaultDepth 24
 SubSection  "Display"
  Viewport   0 0
  Depth      24
  Modes      "1280x1024" "1024x768" "800x600" "640x480"
 EndSubSection
EndSection

Section "Device"
 Identifier "Videocard0"
 Driver     "mga"
 Screen     0
 BusID      "PCI:1:0:0"
EndSection

Section "Device"
 Identifier "Videocard1"
 Driver     "mga"
 Screen     1
 BusID      "PCI:1:0:0"
EndSection

Section "ServerLayout"
 Option     "Xinerama" "on"
 Screen 0   "Screen0" 0 0
 Screen 1   "Screen1" Rightof "Screen0"
 Identifier "DualHead"
EndSection

これで動いている (正確に言えば P110 は 1280x1024 モードになっている *1 ) けど、このパッチは

  • Launchpad の記事で対象になっている Ubuntu でも Merge されていない (少なくとも Natty (11.04) では変更されている様子はなかった)
  • 一応 Bugfix であるが
    • このパッチだけではデュアルディスプレイにできない (RandR に対応していない)
    • よって xorg.conf を書かない限り認識しない
    • 高解像度デュアルディスプレイは不可 (前述)
    • RandR を無効にするので一部のソフトが動かなくなる (わりと深刻)
    • ほとんどのアプリ (gtk?) を起動する際に「Xサーバーの RandR が無効です!」と警告がでる。

ので、Momonga への Merge も保留にしておく。

*1:ドライバの制限でデュアルディスプレイ時は (?) 高解像度が利用できないと書かれている記事を見つけたけど見失った

メモ - その1

今回は初期位置。まずは村クエストから。不安定乱入についてはできるだけ乱入させるようにしている。なお、必ずしもそのモンスターとは限らない…と思う。クルペッコクエにかかってこいは効果がない模様。あとからやってるから1回だけしかできないクエは入ってない。

右の値はムービーイベントの場所 (違うもののみ)。

☆2

孤島に向かう我が主のために
アオアシラ 5 3
アオアシラを生け捕れ!
アオアシラ 3
ドスジャギィを捕まえろ!
ドスジャギィ 6
砂原のならず者の長
ドスジャギィ 5

☆3

トリックスターを捕まえろ
クルペッコ 7
ドスジャギィ 6
ロアルドロス捕獲作戦!
ロアルドロス 9
彩鳥・クルペッコの狩猟!
クルペッコ 4 8
ドスジャギィ 4 8
土砂竜・ボルボロス!
ボルボロス 3
リノプロスの暴走!
ドスジャギィ 4
水没林愚連隊
ドスフロギィ 2 10
ロアルドロスを狩猟せよ!
ロアルドロス 4

☆4

女王・リオレイアの狩猟
リオレイア 8 3→2?
竜の卵の納品
リオレイア 8
土砂竜と群れ長の狩猟
ボルボロス 3
ドスジャギィ 5
陸の女王、捕獲作戦!
リオレイア 2
灯魚竜・チャナガブル!
チャナガブル 4 6
雪のちウルクスス
ウルクスス 2
群れを統べるドスバギィ!
ドスバギィ 7 3
暗闇にうごめく猛毒!
ギギネブラ 5 4
青き集団、バギィ討伐!
ドスバギィ 7
極寒の地の採掘依頼
ギギネブラ 5

☆5

ラギアクルスを仕留めろ!
ラギアクルス 11 10
砂上のテーブルマナー
ハプルボッカ 9 10
大海の王、捕獲大作戦!
ラギアクルス 6
渾身のドボルベルク
ドボルベルク 7 2
赤甲獣ラングロトラ現る!
ラングロトラ 5
ウラガンキンを捕獲せよ!
ウラガンキン 5
最も危険な運び依頼
ウラガンキン 5
最終決戦・ナバルデウス!
ナバルデウス BC (初回時) *1 *2
ナバルデウス 3 (続行時) *3
空の王者リオレウス!
リオレウス 3 8
氷牙竜・ベリオロス!
ベリオロス 6 2
砂原の角竜を狩れ!
ディアブロス 8 9
空の王者を狩猟せよ!
リオレウス 8
脅威! 火山の鉄槌!
ウラガンキン 5 6
火の海に棲む竜!
アグナコトル 7

ちなみにかかってこいは魚+酒 (煮込む) にある。


リタイアした回数が 50 回超えた。

*1:モガ村を救え! とは無関係。この名前のクエを初めてやる場合 BC スタート。

*2:必ずムービーあり

*3:前回「古龍は傷付き逃げていった」で終わっている場合

メモ

ほぼ自分用メモ。瀕死で寝るところ。ちなみに全部確認したわけではなく、以前の情報や薄い記憶をそのままのところもある。原種と亜種による違いは一部であるかも。間違っている可能性大のため鵜呑みにしない (アテにしない) こと。また、間違っていても文句を言わないこと。情報なら歓迎。

孤島 砂原 水没林 凍土 火山 渓流
ドスジャギィ 6 5 - - - 8?
ドスバギィ - - - 7 - -
ドスフロギィ - - 10 - 6? -
クルペッコ 8 7 10 - - 8?
ロアルドロス 12 - 8 - - 8
チャナガブル ? - 8 - - -
ラギアクルス 12 - 8? - - -
ハプルボッカ - 11 - - - -
アグナコトル - - - 7? 10 -
ガノトトス 11 - ? - - -
リオレイア 8 7 10 - - 8
リオレウス 8 - - - 6 8
ギギネブラ - - - 5 - -
ベリオロス - ? - 6 - -
ナルガクルガ ? - 10*1 - - 9
ディアブロス ? 11 - - - -
ジンオウガ ? - - 9 ? 9
ボルボロス - 3 - 9 - -
ウラガンキン - - - - 6 -
ドボルベルク 7 ? 10 - - ?
ブラキディオス ? - - 9 6 -
イビルジョー 6? ? 10 9 5 -
アオアシラ ? - - - - ?
ウルクスス - - - 6 - -
ラングロトラ ? ? - - ? -

同じく食事処。食料がガウシカ・ポポ・アプトノスなどの場合は場所を問わず食えるのも多い。ただし、お互いの行動範囲の関係上かなり限定される。例えば孤島ではアプトノスは 1/2/3 のいずれかにしかいないため、リオレイアが 1 へ行かないことを考慮すると 2 か 3 でしか捕食できない。多分 3rd 以降は飯を食わずに頑張っているのが多数いる模様。

孤島 砂原 水没林 凍土 火山 渓流
ドスジャギィ 6 5 - - - ? 死肉
ドスバギィ - - - 7 - - 死肉
ドスフロギィ - - ? - ? - ?
クルペッコ 10 7 4 - - ?
ロアルドロス 2 - なし - - 6 水浴び箇所
チャナガブル ? - ? - - - エピオス?
ラギアクルス 10 - 6 - - - エピオス/?
ハプルボッカ - 10 - - - - リノプロス
アグナコトル - - - 1 5 - リノプロス/ガウシカ/ポポ
ガノトトス ? - ? - - - ?
リオレイア 不定 4 2 - - 2 アプトノス/ガーグァ
リオレウス 不定 - - - 不定 2? アプトノス/ガーグァ
ギギネブラ - - - なし - -
ベリオロス - ? - 不定 - - ポポ/リノプロス?
ナルガクルガ ? - 7 - - ? ケルビ
ディアブロス ? 9 - - - - サボテンの花
ジンオウガ ? - - ? ? ? アプトノス/ガーグァ
ボルボロス - ? - ? - - アプトノス (だったような)
ウラガンキン - - - - 4 - 岩石
ドボルベルク - ? 10 - - ? 木(の実)
ブラキディオス ? - - ? ? - ポポ
イビルジョー 不定 不定 不定 不定 不定 - 死肉
アオアシラ 3 - - - - 5 はちみつ
ウルクスス - - - ? - - ?
ラングロトラ ? 10 - - ? - ?

まだまだ未知の部分は多いね。

孤島のガノトトスが 11 で寝るのが一番ショックだった (2死の状態&シビレ罠なかったため捕獲できず失敗した)

*1:3rd は 5

Wii に Twitter のボットをやらせる - その3

【初めて見に来た人へ】その 1 に Wii で Linux を動かすことについて注意が記載されています。そのように利用される場合は必ずお読みください。

ルギア君「ちょっと話が変わって、少しおかしいところを直そうと思う。」
キリルン「ふむふむ。」

時計が合わない…?

ルギア君「手元の環境では支離滅裂な時間、たとえば日本時間を UTC とした時の日本時間になっているとかではなく、本当にめちゃくちゃな時間になっていることがある。」
キリルン「??」
ルギア君「Wii 本体の設定で正しく直しても変わらない *1 ので、Linux 側で対処することにする。」
キリルン「ふむふむ。」
ルギア君「お決まりの NTP さんに活躍してもらうことにする。まずは競合するものの削除。こっちのほうが軽そうだけどこっちを使わないのは、最初に openssl をアップデートしちゃってて libcrypto.so.0.9.8 がなくなっているから。pacman が yum ほど高性能ではない一面が窺える。逆に最初にアップデートしていないなら openntpd 使ってもいいかもね。ちなみに openntpd はレポジトリにはないよ。作った人の個人 AUR *2 で作ったのかも。openssl をアップデートしていてどうしても openntpd を、という人は ここ から、ソースをビルドしてね。」
キリルン「…」

#  pacman -Rcc openntpd

ルギア君「ntp をアップデートする。」
キリルン「アップデート?」
ルギア君「元から競合している状態で入っているんだね。」

#  mv /etc/ntp.conf /etc/ntp.conf.bak
#  pacman -Sy ntp

ルギア君「そしたら、まずは強制同期してしまおう。サーバーを全く知らないかもしれないので 1 つあげておくけど、お好きなサーバーをどうぞ。」

#  ntpdate 0.pool.ntp.org

ルギア君「次に起動する。強制同期するときは必ず、起動する前にしてね。」

#  /etc/rc.d/ntpd start

ルギア君「最初から起動するときは、/etc/rc.confDAEMONS のところに ntpd を追加する。」

DAEMONS=(syslog-ng net-profiles netfs ntpd crond sshd alsa hal bluetooth)

ルギア君「起動の確認は」

#  ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*rin.zone-expres 133.243.238.243  2 u  233  512  377   14.091    1.356  23.968
+sylph.white-voi 10.33.1.19       3 u  472  256  376   15.842    1.470   1.988

ルギア君「で相手先サーバー名が返ってくればおk。ちなみに、リモートの数が多いとそれだけメモリを食うのでご注意を。」

top - 10:00:42 up  2:01,  1 user,  load average: 1.15, 1.07, 1.01
Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.3%sy,  0.0%ni, 96.7%id,  0.0%wa,  2.3%hi,  0.7%si,  0.0%st
Mem:     76204k total,    73040k used,     3164k free,     3300k buffers
Swap:    65528k total,        0k used,    65528k free,    45096k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
  953 root      40   0  6128 1572 1240 S  0.0  2.1   0:00.04 ntpd

ルギア君「とりあえず、こんなもんかな。それじゃまたあとで。」

*1:後記: hwclock -s する必要がある…??

*2:Arch Linux のユーザーレポジトリ

Wii に Twitter のボットをやらせる - その2

その1 にある注意事項をお読みください。

Wii Linux の準備

ルギア君「Wii 用の Linuxディストリビューションとしては Debian GNU/Linux (Whiite) と Arch Linux (Archii) がある。Arch Linux のほうが導入がやさし…そう…だから、そっちを入れることにするよ。」
キリルン「自分でビルドしてもいいの?」
ルギア君「ああ、不可能ではないが、相当面倒臭いぞ。」
キリルン「そうですね。」
ルギア君「話を戻すぞ。Archii の場合、基本的には」

https://wiki.archlinux.org/index.php/Wii_Tutorial

ルギア君「に書いてあることをそっくりそのままやればいいだけだ。」
キリルン「ふむふむ。」
ルギア君「まず、SDカードの下ごしらえからだ。この作業は USB メモリや USB ハードディスクに Linux を入れる場合には不要だ。逆に USB メモリや USB ハードディスクにインストールしたければカーネルを書き換えなくちゃいけないんだ。バイナリ編集が苦手なら、SD カードにインストールするしかないね。ほかにも NFS を使ったりするという選択肢もあるけど、これは他にもマシンを立ち上げておくことになるから今回の目的である Wii を使ったエコボットを作るという目的に対しては本末転倒になっちゃうね。」
キリルン「なるほど。」
ルギア君「まず、SDカードのパーティションを分ける。SDカードのパーティションを分けたものは Wii や Windows 機でフォーマットしないでね。(多分だけど) パーティションの設定が消えちゃうと思う。」
キリルン「なんで?」
ルギア君「SDカードはもともと FAT16 (SDHC は FAT32、SDXC は exFAT) 1 パーティションで使わなければいけない、って決まっているからね。ちなみに SDHC は使えるかもしれないけど、SDXC はほとんどダメだろうね (これも試したわけじゃないんだけどさ)。」
キリルン「はぁ。」
ルギア君「それじゃあ、始めよう。Linux マシンを使ってこうやってパーティションを分ける。CUI が苦手な人は gparted というソフトを使ってもできる。」

# fdisk -l /dev/sdf

Disk /dev/sdf: 4098 MB, 4098883584 bytes
128 heads, 63 sectors/track, 992 cylinders, total 8005632 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sdf1   *         190     7999487     3999649    c  W95 FAT32 (LBA)

ルギア君「SD カードがどのデバイスファイルかは十分に注意してね。ここでは、/dev/sdf が SD カードだとするよ。」
キリルン「ふむふむ。」
ルギア君「まずは、中に入っているデータをどこかにバックアップしておいて。」
キリルン「そうね。」

# mount /dev/sdf1 /mnt -t vfat
# cp -rv /mnt /tmp                   # /tmp/mnt へバックアップ
# umount /mnt

ルギア君「それじゃ、作業を始めよう。まずは、パーティションテーブルの作成。」

# fdisk /dev/sdf
Command (m for help): o
Building a new DOS disklabel. Changes will remain in memory only,
until you decide to write them. After that, of course, the previous
content won't be recoverable.

ルギア君「次に、1つ目のパーティションを作る。これはあとで FAT でフォーマットする。ここでは容量が 256MB としておく。 のところは、Enter を押すだけね。」

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-990, default 1): <RETURN>
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-990, default 990): +256M

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): 6
Changed system type of partition 1 to 6 (FAT16)

ルギア君「もし FAT32 にしたければ、Hex code のところで L と叩いて FAT32 のコードを確認してね。」
キリルン「exFAT は?」
ルギア君「exFAT は今のところ Linux では対応していないから exFAT のフォーマットはできないよ。」
キリルン「なるほど。」
ルギア君「次に、2つ目のパーティションを作る。これをあとで ext2 で作る。ここでは容量 1.6GB としてある。」

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 2
First cylinder (136-990, default 136): <RETURN>
Using default value 136
Last cylinder or +size or +sizeM or +sizeK (126-990, default 990): +1600M

ルギア君「できたら、その設定を書き込む。」

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

Syncing disks.

ルギア君「そしたら、フォーマットする。」

# mkfs.vfat /dev/sdf1 -n boot
# mkfs.ext2 /dev/sdf2 -L Archii

ルギア君「そしたら、最初に bootmii をインストールしたときに入っていた SD カードの bootmii 以下のディレクトリをコピーする。」

# mkdir -p /mnt/sdf1
# mount /dev/sdf1 /mnt/sdf1
# cp -rv /tmp/mnt/bootmii /mnt/sdf1

ルギア君「次に、Linux カーネルを取ってくる。自分のテレビの仕様を間違えないように。日本の場合は、NTSC/60Hz で、コンポジット接続の場合はインターレース 480i で、コンポーネント接続・D端子接続の場合は、プログレッシブ 480p を選ぶ。」

# cd /mnt/sdf1
# wget 'http://downloads.sourceforge.net/gc-linux/mikep5-zImage-2.6.32.mini.480i(NTSC).elf'    # NTSC インターレース
# wget 'http://downloads.sourceforge.net/gc-linux/mikep5-zImage-2.6.32.mini.480p(NTSC).elf'    # NTSC プログレッシブ

ルギア君「ダウンロードしたファイルは短い名前にリネームしておこう。」

# mv mikep5-zImage-2.6.32.mini.480i\(NTSC\).elf mikep5-480i.elf
# mv mikep5-zImage-2.6.32.mini.480p\(NTSC\).elf mikep5-480p.elf

ルギア君「その他のカーネルはここから。」

http://www.gc-linux.org/wiki/MINI:KernelPreviewFive

ルギア君「ちなみに ここ に Arch Linux のプロジェクトの方で少しカスタマイズされたカーネルがおいてあるけど、これは NTSC の 480i 専用みたい。」
キリルン「ふむふむ。」
ルギア君「同じところから archii.tar.xz をダウンロードしてくる。そして、ext2 の領域に展開する。このとき、」

# mkdir -p /mnt/sdf2
# mount /dev/sdf2 /mnt/sdf2 -t ext2
# cd /mnt/sdf2
# tar Jxvf /path/to/where/you/download/archii.tar.xz --exclude=./swapfile

ルギア君「のように、あとで簡単に作れる swapfile は除いてください*1。SD カードの読み書きが遅くなければいいんだけどね。ちなみに、tar の J オプションがダメって言われたときは、」

# xz -dc /path/to/where/you/download/archii.tar.xz | tar xvf - --exclude=./swapfile

ルギア君「てやれば OK だよ。」
キリルン「なるほど。」
ルギア君「そしたら swap をつくろう。まあ、必須ではないが、メモリが足りなくなるのは目に見えているので、な。」

# dd if=/dev/zero of=swapfile bs=4M count=16
# mkswap -L archii.swap swapfile
# chmod 600 swapfile

ルギア君「サイズは bs × count な。この場合は 64M。最適値は本体のメモリと同じ量で、72M …かな。できたら、次は設定の変更だ。」
キリルン「おー、大変ですね。」
ルギア君「うむ。」

# vim etc/fstab                 # 頭に / はないよ! あと、エディタはお好きなものをどうぞ。
#
# /etc/fstab: static file system information
#
# <file system>        <dir>         <type>    <options>          <dump> <pass>
none                   /dev/pts      devpts    defaults            0      0
none                   /dev/shm      tmpfs     defaults            0      0

/dev/mmcblk0p2         /           auto    rw,defaults,noatime     0      1
/dev/mmcblk0p1         /boot       auto    rw,defaults,noatime     0      0
/swapfile              swap        swap    defaults                0      0    # この行を追加

/dev/cdrom             /media/cd   auto    ro,user,noauto,unhide   0      0
/dev/dvd               /media/dvd  auto    ro,user,noauto,unhide   0      0
/dev/fd0               /media/fl   auto    user,noauto             0      0

ルギア君「もうひとつ。まずは基本的な設定から。」

# vim etc/rc.conf
#
# /etc/rc.conf - Main Configuration for Arch Linux
#

# -----------------------------------------------------------------------
# LOCALIZATION
# -----------------------------------------------------------------------
#
# LOCALE: available languages can be listed with the 'locale -a' command
# HARDWARECLOCK: set to "UTC" or "localtime"
# USEDIRECTISA: use direct I/O requests instead of /dev/rtc for hwclock
# TIMEZONE: timezones are found in /usr/share/zoneinfo
# KEYMAP: keymaps are found in /usr/share/kbd/keymaps
# CONSOLEFONT: found in /usr/share/kbd/consolefonts (only needed for non-US)
# CONSOLEMAP: found in /usr/share/kbd/consoletrans
# USECOLOR: use ANSI color sequences in startup messages
#
LOCALE="en_US.utf8"            # 端末は日本語が表示できないので英語のままにしておきます
HARDWARECLOCK="localtime"      # Wii は日本時間で設定していると思うので、localtime に変えます
USEDIRECTISA="no"
TIMEZONE="Asia/Tokyo"          # 日本時間。Asia/Tokyo または Japan。他は上に書いてある場所を参照
KEYMAP="jp106"                 # 直接挿して使うキーボードの配列。英語の場合は us。他は上に書いてある場所を参照
CONSOLEFONT=
CONSOLEMAP=
USECOLOR="yes"

ルギア君「更に下の方を見ていく。ここは変更する必要はなし。」

# -----------------------------------------------------------------------
# HARDWARE
# -----------------------------------------------------------------------
#
# MOD_AUTOLOAD: Allow autoloading of modules at boot and when needed
# MOD_BLACKLIST: Prevent udev from loading these modules
# MODULES: Modules to load at boot-up. Prefix with a ! to blacklist.
#
# NOTE: Use of 'MOD_BLACKLIST' is deprecated. Please use ! in the MODULES array.
#
MOD_AUTOLOAD="yes"
#MOD_BLACKLIST=() #deprecated
MODULES=()

# Scan for LVM volume groups at startup, required if you use LVM
USELVM="no"

ルギア君「更に下を見ると、ネットの設定がある。比較的新しい Arch Linux では netcfg というものを使うことになっていて、有線、無線にかかわらず、これを使う。ちなみに無線の場合は古い設定では (多分だが) WPA が使えない。とりあえず、ここでは無線を使う場合を考えることにする。さっきも言ったように、古い設定では無線が使えないので、」

# -----------------------------------------------------------------------
# NETWORKING
# -----------------------------------------------------------------------
#
# HOSTNAME: Hostname of machine. Should also be put in /etc/hosts
#
HOSTNAME="Wii"

# Use 'ifconfig -a' or 'ls /sys/class/net/' to see all available interfaces.
#
# Interfaces to start at boot-up (in this order)
# Declare each interface then list in INTERFACES
#   - prefix an entry in INTERFACES with a ! to disable it
#   - no hyphens in your interface names - Bash doesn't like it
#
# DHCP:     Set your interface to "dhcp" (eth0="dhcp")
# Wireless: See network profiles below
#
#eth0="dhcp"           # コメントアウト
INTERFACES=(!wlan0)    # !wlan0 に変える

# Routes to start at boot-up (in this order)
# Declare each route then list in ROUTES
#   - prefix an entry in ROUTES with a ! to disable it
#
gateway="default gw 192.168.0.1"
ROUTES=(!gateway)

# Enable these network profiles at boot-up.  These are only useful
# if you happen to need multiple network configurations (ie, laptop users)
#   - set to 'menu' to present a menu during boot-up (dialog package required)
#   - prefix an entry with a ! to disable it
#
# Network profiles are found in /etc/network.d
#
# This now requires the netcfg package
#
NETWORKS=(ArpaCastle) # コメントアウトを外し、好きな名前に変える

ルギア君「あ、そうそう、IOS 版のカーネル*2 だと Wii 内蔵の無線は使えないから気をつけてね。最後、デーモンの設定をする。」

# -----------------------------------------------------------------------
# DAEMONS
# -----------------------------------------------------------------------
#
# Daemons to start at boot-up (in this order)
#   - prefix a daemon with a ! to disable it
#   - prefix a daemon with a @ to start it up in the background
#
DAEMONS=(syslog-ng net-profiles netfs crond sshd alsa hal bluetooth)
# network の代わりに net-profiles に変える。

ルギア君「そしたら、ネットの詳しい設定をする。etc/network.d に入って、examples の中から使いたいものを選んで、先程 rc.conf で設定した名前でコピーします。」

# cd etc/network.d
# ls examples
complete.example         ethernet.example  ppp.example         wep.example
ethernet-static.example  loopback.example  wep-static.example  wpa.example
# cp examples/wpa.example ArpaCastle
# vim ArpaCastle
CONNECTION="wireless"
INTERFACE=wlan0
SCAN="yes"
SECURITY="wpa"
ESSID="mynetwork"    # ESSID
KEY="SomePasskey"    # WPA key
IP="dhcp"
TIMEOUT=20

ルギア君「ちなみに SturmHome というのがもとから入っていて、おそらくパッケージした人の環境。多分何かのミス。」
キリルンは笑った。
ルギア君「あと、これも作った人のミス (だと思う) で、root のパスワードがどこにも書かれてないのでここで変更する。ちなみに期限切れにする方法はダメだった。ので、/etc/shadow からコピーするなどして凌いでくれ。」

# vim etc/shadow
root:[暗号化されたパスワード]:14437::::::
# (以下略)

ルギア君「ちなみに archie のパスワードは root でログインしたあとで変更してね。」
キリルン「ああ。」
ルギア君「設定はこれで終わりで、起動する。」
キリルン「おお。」

# cd
# umount /mnt/sdf1
# umount /mnt/sdf2
# eject /dev/sdf

起動

ルギア君「電源を入れたらリモコンで Homebrew Channel を選んで起動する。起動したら、リモコンのホームボタンかGCコントローラの START ボタンを押してメニューを表示し、Bootmii を起動する。」
キリルン「ふむふむ。」
ルギア君「ゲームキューブコントローラの矢印キーとAボタンで SD カードのアイコンを選択し、SD カードに入れた mikep5-480i.elf か mikep5-480p.elf を起動すれば Linux が立ち上がってくるはずだ。ちなみに、ゲームキューブのコントローラがない場合は、Wii の電源ボタンとリセットボタンを使うんだよ。」

ボットを作るためのソフトウェアの下ごしらえ

ルギア君「ボットを作るためには、いくつかの方法があるんだけど、ここでは twbot2.rb というフレームワークを使ったボットを作ることにしよう。」

フレームワーク/ライブラリ名 言語
twbot2.rb Ruby
Twitter (Rubygem) Ruby
python-twitter Python
twitteroauth PHP
Net::Twitter Perl
liboauth C/C++
Twitter4J Java

ルギア君「これらの言語では当然こんなフレームワークを使わずに…というかここにあるのもいくつかは認証のサポートだけだけど、自分で API を叩いて bot を作ることも出来るよ。gcc/g++ の環境はあるから liboauth を使う場合もあとで説明しておこう。」


ルギア君「まず、ruby は入っていないので、インストールするん…だけど、しばらく前から Arch Linuxレポジトリの依存関係が不十分となっていて、ruby-1.9.3p0 に必要な libyaml がないので、ここ からまず libyaml をダウンロードしてビルドする。多分、これはそのうち直るから、直っていたら、pacman -Sy ruby でインストールしてね。」

#  wget http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz
#  tar zxvf yaml-0.1.4.tar.gz
#  cd yaml-0.1.4
#  ./configure --prefix=/usr
#  make
#  make install
#  ldconfig

ルギア君「他必要なものをインストールないしは更新する。pacman を更新して良いか聞かれるが、その必要はない。というか面倒くさい。」

#  pacman -Sy openssl

ルギア君「次に ruby をインストールする。ruby-1.9.3-20110919.tar.xz 直(ルギア君の自前ビルド)*3 をダウンロードして展開し、」

#  tar Jxvf ruby-1.9.3-20110919.tar.xz
#  cd ruby-1.9.3-20110919
#  make install

ルギア君「をやればいいんだけど、そのままやると 2GB の SD カードではたぶん容量が足らなくなるので USB メモリを用意するか 200M 以上開けてからやってほしい。ちなみに 3, 4 時間あればビルドもできるよ。」
キリルン「…。」
ルギア君「あ、そうそう、ビルドオプションは」

# ./configure --prefix=/usr

ルギア君「な。あ、あと、このファイルは多分そのうち消す。そして oauth の gem をインストールする。」

#  gem install oauth

ルギア君「そしたら、twbot2.rb を取ってくる。」

# wget http://maraigue.hhiro.net/twbot/twbot2-0.20.zip
# unzip twbot2-0.20.zip
# cd twbot2
# ruby simplebot.rb init
============================================================
Here I help you register your bot account to the setting file.
Please prepare a browser to retrieve OAuth tokens.

Input the screen name of your bot account.
============================================================
User name >lugia_kun
============================================================
To retrieve OAuth token of user "lugia_kun":
(1) Log in Twitter with a browser for user "lugia_kun".
(2) Access the URL below with same browser:
    https://api.twitter.com/oauth/authorize?oauth_token=[トークン]
(3) Check the application name is "twbot2.rb" and
    click "Allow" link in the browser.
(4) Input the shown number (PIN number).
    To cancel, input nothing and press enter key.
============================================================
PIN number >

ルギア君「あとは、twbot2 の説明を読んで楽しい bot を創り上げてね! じゃあ、またな。」

*1:1.6G だと swapfile を入れちゃうと容量が足りない気がした。Arch Linux の wiki では 2GB の SD カードを使っているようであり、他にも幾つか外部サイトとの整合性があっていないところがある。wiki にもは、そこの内容が out-of-date とかかれているが、まさにそのようである。

*2:Homebrew Channel から直接起動するタイプ

*3:SHA256SUM: d59f040771b3880f7fd94680e688bb7c57c49c2a488fd2f110f6a0f24823876f, 22MB

7年6月31日 (海)

みんな「みーっつ! みんな笑顔で明るいあるぱ城!」
ドンちゃん「よし、今日も仕事始め〜! …といいたいところだが、依頼はきてないし、閏日だからお休み!」
みんな「わーっ!」
フロル君「閏日って何?」
ガブちゃん「閏日っていうのはな、普通の年にはない、余計な日のことだよ。」
フロル君「なんでそんなのが必要なの?」
ガブちゃん「あまり詳しくは知らないが、そうしないと段々季節とずれてきちゃうんだってさ。」
ルギア君「正確には日付と太陽の位置の対応…だよ。」
フロル君「段々ずれてくるってことはさ、閏日は定期的にあるの?」
ガブちゃん「ああ、大体4年に1回はな。」
フロル君「なんか得した気分!」
ルギア君「(世界暦だと閏日が休みだからなぁ。)」
ガブちゃん「?」
フロル君「?」
ルギア君「閏日が休みなのはこのあるぱ城で使っている暦、つまり世界歴だけで、人間世界では特に祝ったりもしない、普通の日さ。」
フロル君「なんか損している気分…。」
ルギア君「まあ、例えば 7 年 1 月 1 日の時点で 7 年 9 月 1 日までにやってきてね! って課題を出すのと閏日が入らない 8 年 1 月 1 日に 8 年 9 月 1 日までにやってきてね! って課題を出すのとでは 1 日差があるのには人間世界の暦でも世界暦でも代わりはない。」
フロル君「なるほど。」
アルル君「それだったら、1 年を 365.25 日にすればいいと思うのになぁ。」
ルギア君「実際には 365.2425 日 *1 だから、100 年置きに閏日があるはずの年に閏日がない年が来て、400 年置きにさっきの効果でなくなっているはずの閏日が復活する。つまり、400 年の間に閏日は 97 日ある。実際に 365.2422 日にしないのは、昼間に年が変わるっていうのは変だろ?」
フロル君「え、なんで?」
ルギア君「日付だって夜中にしか変わらないじゃないか。昼に変わっていたらややこしくて仕方ないよね。」
ガブちゃん「夜に活動する『こともある』おれたちの身にもなっておくれよ。」
ルギア君「…いつも同じタイミングで変わっていれば問題ないでしょ? 寧ろ君が昼に活動する時には夜に日付が変わって、夜に活動するときには昼に日付が変わるっていうのは 1 日の長さが今以上にバラバラになる *2 し、なにより不条理すぎないか?」
ガブちゃん「ぐぬぅ。」
ルギア君「だから、長さを議論するとき以外は日にちに小数を使わない。わかった?」
アルル君「なるほど。よくわかる。」
フロル君「あれ、君は時の番人じゃなかったの?」
アルル君「時の番人と言っている割にはその言いぐさはなんだ? 俺は人間が決めたことなど全く知らないからな。」
フロル君「…ごめんなさい。」
アルル君「(かわいい仔だなぁ。)」
ラプちゃん・キルリア達「……(アルル君は雌だったのか…?)」

*1:本当のことを言えばこれでもずれる

*2:もともと日の出と日没を中心に計算しているため 1 日の長さにはばらつきがある。