コンピュータやソフトウェアのあれこれ@道民(&元道民)
Android
ndk-buildで他のCPUもサポートする
3月 25th
トマト味の野菜ジュースが苦手なんですけど、うっかり手元にあったりして、
そういうのは、トマト味のリゾットに流し込んじゃいます、
こんばんは、ネコです。
そういえば、Android NDKもr7bがリリースされたりしてて、
噂ではIntel CPUをサポートしたなんて聞いてたんですけど、
いつものように、”AndroidManifest.xml”がある階層で、
$ ndk-build
って入力しても、”libs/armeabi”にしかsoファイルができなくて、
ん〜って思ってたのですが、ちゃんとリリースノート見なきゃダメですね。
$ ndk-build APP_ABI=all
って打つと、いくつかのフォルダとsoファイルが出力されました。
ちなみに、これはRevision 7のリリースノートに載ってます。
めでたし、めでたし。
ライフゲーム作ってます
3月 21st
そろそろ、宣伝しますね。
って言っても、古い話になるのですが・・・。
このライフゲーム(Google Play)の作者こと、techno_nekoです。
えっと、どうですかね、これ。
インストールしてる方の感想を聞いてみたいです。
まだ、ライブ壁紙しか作ったことのないですが、
今後ともよろしくお願いします。
おしまい。
settingsActivityのメモ
2月 5th
settingsActivityを使ってみたので、
設定を伴わないライブ壁紙からの差分ということでメモ。
いつものライブ壁紙のコードを改良していきます。
まずは、ファイルの先頭に。
import android.content.SharedPreferences;
次に、設定の保存先を定義。
public class LifeGameWallpaper extends WallpaperService {
// 他のアプリとかぶらないようなのを使用する
public static final String SHARED_PREFS_NAME = "your.domain.preferencesName";
// 以下は、今まで通り
次に、ライブ壁紙エンジンのクラスに、
設定値の変更イベントを受け取るためのインターフェイスを追加。
class LifeGameWallpaperEngine extends Engine
implements SharedPreferences.OnSharedPreferenceChangeListener {
// 今回は、この値を変更できるようにする
private final long _drawInterval = 1000 / 8; // 描画間隔
// ここは今まで通り
// 以下を追加
private SharedPreferences _prefs;
コンストラクタの中で、初回設定値読み出し。
_prefs = LifeGameWallpaper.this.getSharedPreferences( SHARED_PREFS_NAME, 0 ); _prefs.registerOnSharedPreferenceChangeListener( this ); onSharedPreferenceChanged( _prefs, null )
onSharedPreferenceChangedという関数を追加
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
if ( sharedPreferences.getBoolean("speed", false) ) {
_drawInterval = 1000 / 16; // Hi-Speed mode
}
else {
_drawInterval = 1000 / 8;
}
}
“speed”はどっから出て来たかというと、
設定画面のXML(“lifegame_settings.xml”)として、以下を用意する。
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="speed"
android:title="Hi-Speed mode"
android:summary="on: 16fps, off: 8fps"/>
</PreferenceScreen>
設定値は、”android:key=”に指定したキーを通じて取得できる。
ちなみに、今回は”AndroidManifest.xml”に以下の記述を追加している。
場所は、”application”タグ囲まれた、”service”タグの直後に同じインデントで追加。
<activity
android:label="@string/lifegame_settings"
android:name=".LifeGameWallpaperSettings"
android:theme="@android:style/Theme.Light.WallpaperSettings"
android:exported="true">
</activity>
“strings.xml”に、
<string name="lifegame_settings">(設定画面のタイトル)</string>
の追加もお忘れなく。
あとは肝心の設定用Activityのソースですが、
公式サイトの”src”フォルダの中を漁ると出てきます。
おしまい。
NDKを使ってみた
1月 22nd
もちろん、NDKを使ってライフゲームをもっと早くするというお話です。
まず、最初にやったのはNDKのセットアップ、
「Android ndk」とかで検索すれば、その手順が出てきます。
自分の場合はホームディレクトリに”Develop”フォルダを作って、
そこにまとめてインストールしています。
~/Develop ├── android-ndk-r6b ├── android-sdk-linux_x86 ├── eclipse └── workspace
この”android-ndk-r6b”が、現在使用してるNDKです。
なので、”.bashrc”には、以下の記述を追加しています。
export PATH=${PATH}:~/Develop/android-sdk-linux_x86/tools
export PATH=${PATH}:~/Develop/android-ndk-r6b
あとは、
$ ndk-build -v
とかでパスが通ったことを確認できれば準備完了です。
次に、EclipseにCDTをインストール(*1)するということ。
これは、「Eclipse CDT」で検索してください。
これによって、EclipseでCソースやヘッダーファイルの編集が可能になります。
あと、”Android.mk”(NDKにおけるMakefile)も色分けされます。
1. Cで実装する処理の選定
まず、どこを高速化するかですよね。
ライフゲームの場合は選択肢がないので、
誕生と消失を行う関数をCソースに移植します。
2. ByteBufferによる書き直し
さっそくCで書き直す前に、ByteBufferで実装し直します。
というのも、Javaの配列をそのまま渡してしまうと、
引数として受け取ったあとにCで使える配列に変換する必要出てしまいます。
このオーバーヘッド(*2)をなくすためにByteBufferに置き換えます。
3. Cで書き直す
Cで書き直すにもファイルをどこに置くかですよね。
“AndroidManifest.xml”がある階層に、”jni”フォルダを用意します。
その中に、Cソースとヘッダーファイル、そして”Android.mk”を置きます。
jni ├── Android.mk ├── lifegamelib.c └── lifegamelib.h
ちなみに、ByteBufferを引数で渡すと、こんな感じで先頭アドレスを確保出来ます。
void Java_your_domain_LifeGameWallpaper_LifeGame_ndkExecLifeGame(
JNIEnv* env, jobject thiz, jobject buf, jint w, jint h)
{
// ByteBufferを配列の先頭アドレスとして確保
unsigned char *p = (*env)->GetDirectBufferAddress( env, buf );
// 処理を書く
}
それと、自分が作成した”Android.mk”はこんな感じです。
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := lifegamelib.c LOCAL_MODULE := lifegamelib include $(BUILD_SHARED_LIBRARY)
4. ビルドする
端末(コンソール?)を使って、”AndroidManifest.xml”がある階層で、
$ ndk-build
これだけデス。(*3)
これで、”libs”フォルダが作られて、その中にさらにフォルダが作られて、
上記の例だと、”liblifegamelib.so”が生成されます。
こんな感じで、先頭に”lib”が付いて、拡張子に”.so”がくっ付きます。
5. ライブラリを使用する
このライブラリを使うクラスでは、以下のように宣言します。
package your.domain.LifeGameWallpaper;
import java.nio.ByteBuffer;
public class LifeGame {
private final byte
STATE_DEAD = 0,
STATE_STAY = 1,
STATE_BORN = 2;
private int _width;
private int _height;
private byte[] _buf;
private ByteBuffer _directBuffer;
// ライブラリを読み込むための記述
static {
System.loadLibrary( "lifegamelib" );
}
// ライブラリ内の関数を参照するための記述
private native void ndkExecLifeGame(ByteBuffer buf, int w, int h);
// 既存のメソッド定義等
}
あとは、ndkExecLifeGameを適所で呼び出すだけです。
まとめ
まずは、自分がハマったポイントから。
- 生成されるライブラリは”liblifegamelib.so”だけど、
loadLibraryの引数は”lifegamelib”と書く。 - Cソースにおける関数名は、
“Java_package_class_method”のように定義しないとJava側で呼び出せない。
という訳で、まずloadLibraryでハマって、関数名の記述ミスでハマりました。
あと、どの程度早くなったのかというと、
ライフゲームの処理が10msくらい掛かっていたのが、3msくらいになりました。
Javaのコードをコピペして、コンパイルが通る程度に手を入れた訳ですが、
十分に効果がありました。
ただ、まだまだ無駄なメモリコピーがあって、
あと、入力と出力の計2つByteBufferを渡さなきゃいけないところを、
1つのByteBufferの前半と後半を使って処理してたりと、
人様に見せられない恥ずかしい実装なので、コードはちょっと晒せないデス。
それと、NDKの導入は考えてなかったので、
“liblifegamelib.so”という恥ずかしいファイル名になってしまって、
これも本来なら晒したくなかったデス。
あと、メモとして、
Android側のコードに変更がないと、ライブラリの変更が反映されないらしいです。
今後の予定は以下の通り。
- ライブ壁紙の設定を実装する
- 描画周りが5msくらい掛かっているので最適化する
- 計測方法を検証する(*4)
(*1) CDTのインストールをしなくてもNDKを使った開発はできます。
(*2) どの程度オーバーヘッドが発生するのかは未検証デス、ゴメンなさい。
(*3) ビルドオプションは、自分で検索してください。
(*4) デバッグのためにケーブルを接続した状態だと遅いらしい(?)
おしまい。
ByteBufferのお話
1月 16th
こないだライフゲームのライブ壁紙を作ってみたんだけど、
最近はNDKを使って、省バッテリー化に取り組みたいなーって思ってて、
そのためにはByteBufferを使う必要がありまして。
という訳で、いきなりNDKのお話をする前にByteBufferの勉強をします。
ByteBufferは、java.nio.Bufferを継承したものなので、
まずはjava.nio.Bufferを確認しなきゃいけなくて、
なんでこんなことを書いているかというと、
お察しの通り、これを確認しないで使ってハマった訳です。
で、注意しなきゃいけない点は以下の通り
- put()するとposition()が変わる
- position()が変わると次のput()先が変わる
うまく説明できないので、C言語で説明します。
unsigned char buf[3] = { 0, 0, 0 };
unsigned char *p = buf;
// put()による書き換えのイメージ
(*p++) = 1; // buf[0] => 1
(*p++) = 2; // buf[1] => 2
(*p++) = 3; // buf[2] => 3
という訳で、バッファの先頭から書き換えたい場合はrewind()を呼び出して、
position()を巻き戻しましょう。
おしまい。
ライブ壁紙でライフゲーム
1月 9th
前回はぶっきらぼうにライフゲームのコードだけ載せたので、
今回はライブ壁紙のコードも晒します。
ポイントは以下の通り
- LifeGameWallpaperEngineのコンストラクタで_lifeGameを初期化
- onSurfaceChangedで描画設定を初期化
- drawMainでイロイロしてる
あと、端末の向きが変わるとonSurfaceChangedが呼ばれるので、
ライフゲームの計算結果は引き継いだまま続行されるのがミソです。
ちなみに、このソースコードはgoogleの公式サイトからパクってます。
サンプルコード一覧のここ。
で、サンプルコードにあったタッチイベントを利用して、
そのタッチした場所に生命を誕生させるなんていうのは、
touchProcessに実装しています。
package your.domain.LifeGameWallpaper;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
//import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
public class LifeGameWallpaper extends WallpaperService {
private final Handler _handler = new Handler();
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public Engine onCreateEngine() {
// Log.d( "lifegame", "onCreateEngine" );
return new LifeGameWallpaperEngine();
}
class LifeGameWallpaperEngine extends Engine {
private final long DRAW_INTERVAL = 1000 / 8; // 描画間隔
private int _screenW, _screenH;
private int _nx, _ny;
private int _x0, _y0;
private int _size;
private Point _offset = new Point( 0, 0 );
private Paint _paintBorn, _paintStay;
private LifeGame _lifeGame;
private byte[] _dst;
private float _touchX, _touchY;
private final Runnable _drawLifeGame = new Runnable() {
public void run() {
drawMain();
}
};
private boolean _visible;
public LifeGameWallpaperEngine() {
// ライフゲームの計算量に直結するので、動作を見ながらもっさりしないように決める
_lifeGame = new LifeGame( 80, 80 );
_dst = new byte[ _lifeGame.getWidth() * _lifeGame.getHeight() ];
{
// 初期パターンのコピー
final byte[][][] patterns = {
{ // ドングリ
{ 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 0 },
{ 1, 1, 0, 0, 1, 1, 1 }
},
{ // ダイハード
{ 0, 0, 0, 0, 0, 0, 1, 0 },
{ 1, 1, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 1, 1, 1 }
}
};
byte[][] pattern = patterns[0];
int offsetX = (_lifeGame.getWidth() - pattern[0].length) / 2;
int offsetY = (_lifeGame.getHeight() - pattern.length) / 2;
_lifeGame.setPattern( pattern, offsetX, offsetY );
}
_lifeGame.exec( _dst );
_paintBorn = new Paint();
_paintBorn.setColor( Color.RED );
_paintStay = new Paint();
_paintStay.setColor( Color.YELLOW );
// 無効な座標で初期化
_touchX = _touchY = -1f;
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate( surfaceHolder );
setTouchEventsEnabled( true );
}
@Override
public void onDestroy() {
super.onDestroy();
_handler.removeCallbacks( _drawLifeGame );
}
@Override
public void onVisibilityChanged(boolean visible) {
_visible = visible;
if ( _visible ) {
drawMain();
}
else {
_handler.removeCallbacks( _drawLifeGame );
}
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged( holder, format, width, height );
_screenW = width;
_screenH = height;
final int SIZE_MIN = 8;
{
// 端数切り上げしないと、
// 描画可能な要素数の計算がライフゲームの幅、もしくは高さを越えてしまう
int w = (int)Math.ceil( (float)_screenW / _lifeGame.getWidth() );
int h = (int)Math.ceil( (float)_screenH / _lifeGame.getHeight() );
// 長い方を正方形の高さとして採用する
_size = ( w < h ) ? h : w;
// 高さのクリップ
if ( _size < SIZE_MIN ) {
_size = SIZE_MIN;
}
}
// ライフゲーム空間のどの範囲を描画するか確定する
_nx = _screenW / _size;
_ny = _screenH / _size;
_x0 = (_lifeGame.getWidth() - _nx) / 2;
_y0 = (_lifeGame.getHeight() - _ny) / 2;
// 描画対象の中心に描画するための描画開始座標を計算
_offset = new Point(
(_screenW - (_nx * _size)) / 2,
(_screenH - (_ny * _size)) / 2
);
/*
Log.d( "onSurfaceChanged", "_screenW = " + _screenW );
Log.d( "onSurfaceChanged", "_screenH = " + _screenH );
Log.d( "onSurfaceChanged", "_size = " + _size );
Log.d( "onSurfaceChanged", "_nx = " + _nx );
Log.d( "onSurfaceChanged", "_ny = " + _ny );
Log.d( "onSurfaceChanged", "_x0 = " + _x0 );
Log.d( "onSurfaceChanged", "_y0 = " + _y0 );
Log.d( "onSurfaceChanged", "_offset.x = " + _offset.x );
Log.d( "onSurfaceChanged", "_offset.y = " + _offset.y );
*/
drawMain();
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated( holder );
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed( holder );
_visible = false;
_handler.removeCallbacks( _drawLifeGame );
}
@Override
public void onOffsetsChanged(
float xOffset, float yOffset,
float xOffsetStep, float yOffsetStep,
int xPixelOffset, int yPixelOffset) {
}
@Override
public void onTouchEvent(MotionEvent event) {
if ( event.getAction() == MotionEvent.ACTION_DOWN ) {
_touchX = event.getX();
_touchY = event.getY();
// Log.d( "touch", "X = " + _touchX + ", Y = " + _touchY );
}
super.onTouchEvent( event );
}
private void drawMain() {
final SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
long begin = 0, endDraw = 0, endLifeGame = 0;
try {
touchProcess();
c = holder.lockCanvas();
if (c != null) {
begin = System.currentTimeMillis();
_lifeGame.exec( _dst );
endLifeGame = System.currentTimeMillis();
drawRectangles( c );
endDraw = System.currentTimeMillis();
}
} finally {
if ( c != null ) {
holder.unlockCanvasAndPost( c );
}
}
// Log.d( "lifegame", "becnch = " + (endLifeGame - begin) );
// Log.d( "draw", "becnch = " + (endDraw - begin) );
// Reschedule the next redraw
_handler.removeCallbacks( _drawLifeGame );
if ( _visible ) {
long delay = DRAW_INTERVAL - (endDraw - begin);
if ( delay < 0 ) {
delay = 0; // clip
}
_handler.postDelayed( _drawLifeGame, delay );
}
}
private void drawRectangles(Canvas c) {
c.drawColor( Color.BLACK ); // Clear
for (int iy=0; iy<_ny; iy++) {
final float n = _size;
float offsetY = (float)( _offset.y + (iy * _size) );
float offsetX = (float)( _offset.x );
int lineOffset = _lifeGame.getWidth() * (_y0 + iy);
for (int ix=0; ix<_nx; ix++) {
int status = _dst[ lineOffset + _x0 + ix ];
if ( status != 0 ) {
final Paint paint = ( status == 1 ) ? _paintStay : _paintBorn;
c.drawRect(
offsetX, offsetY,
(offsetX + n - 1), (offsetY + n - 1),
paint
);
}
offsetX += n;
}
}
}
private void touchProcess() {
if ( _touchX < 0f || _touchY < 0f ) {
return;
}
final byte[][] pattern = {
{ 1, 1, 1 },
{ 1, 1, 1 },
{ 1, 1, 1 }
};
float x = (_touchX - (float)_offset.x) / (float)_size;
float y = (_touchY - (float)_offset.y) / (float)_size;
int offsetX = _x0 + (int)x - (pattern[0].length / 2);
int offsetY = _y0 + (int)y - (pattern.length / 2);
_lifeGame.setPattern( pattern, offsetX, offsetY );
// タッチした座標の破棄
_touchX = _touchY = -1f;
}
}
}
こんな時間なので、まだ呑んでないよ。
おしまい。
Android始めました
1月 9th
と言っても、何かアプリをリリースした訳じゃないですが、
宿題を出されたので、ライブ壁紙を一生懸命作ってみました。
ライブ壁紙でライフゲーム
最初は「日経ソフトウェア」の記事を写経してたんですが、
まぁ、それでうまくいったんですが、例外が起きてちょっとアレでして。
そこで、googleの公式サイトにもサンプルソースが上がってたので、
今度は、そっちからコードをパクって仕上げました。
まずは、ライフゲームのクラス
package your.domain.LifeGameWallpaper;
public class LifeGame {
private final byte
STATE_DEAD = 0,
STATE_STAY = 1,
STATE_BORN = 2;
private int _width;
private int _height;
private byte[] _buf;
public LifeGame(int w, int h) {
_width = w;
_height = h;
_buf = new byte[ _width * _height ];
for (int i=0; i<_buf.length; i++) {
_buf[i] = STATE_DEAD;
}
}
public int getWidth() {
return _width;
}
public int getHeight() {
return _height;
}
public void setPattern(byte[][] pattern, int offsetX, int offsetY) {
int x0 = offsetX;
int y0 = offsetY;
int x1 = offsetX + pattern[0].length;
int y1 = offsetY + pattern.length;
// 上下左右の端の行と列は計算対象外なので、
// データを書き込まないようにクリップ(LifeGameの仕様)
if ( x0 <= 0 ) { x0 = 1; }
if ( y0 <= 0 ) { y0 = 1; }
if ( _width <= x1 ) { x1 = _width - 1; }
if ( _height <= y1 ) { y1 = _height - 1; }
// 上下左右の端の行と列にかぶらない部分を初期化
for (int iy=y0; iy<y1; iy++) {
for (int ix=x0; ix<x1; ix++) {
int idx = (iy * _width) + ix;
if ( pattern[(iy - offsetY)][(ix - offsetX)] != 0 ) {
_buf[idx] = STATE_STAY;
}
}
}
}
public void exec(byte[] dst) {
// dstに結果を格納
execLifeGame( dst );
// 次の準備
for (int i=0; i<_buf.length; i++) {
_buf[i] = dst[i];
}
}
private int getAroundOf(int index) {
int ret = 0;
index -= _width; // 1つ前のラインから走査するためのデクリメント
for (int i=0; i<3; i++) {
if ( _buf[index - 1] != STATE_DEAD ) { ret++; }
if ( _buf[index ] != STATE_DEAD ) { ret++; }
if ( _buf[index + 1] != STATE_DEAD ) { ret++; }
index += _width;
}
return ret;
}
private void execLifeGame(byte[] dst) {
int iy = 1;
int lineOffset = _width * iy;
for (; iy<(_height-1); iy++) {
for (int ix=1; ix<(_width-1); ix++) {
int idx = lineOffset + ix;
byte state = _buf[idx];
int cnt = getAroundOf( idx );
if ( state == STATE_DEAD ) {
state = ( cnt == 3 ) ? STATE_BORN : STATE_DEAD;
}
else {
state = ( (cnt-1) <= 1 || 4 <= (cnt-1) ) ? STATE_DEAD : STATE_STAY;
}
dst[idx] = state;
}
lineOffset += _width;
}
}
}
そもそも、ライフゲームって何かというと、
自分の中心に3×3の計9マスを対象として、
その中心が死滅状態で周囲に3匹の生存していれば誕生、
もしくは中心に1匹と周辺に2〜3匹入れば生命を維持、
中心の他に生命が1匹以下、もしくは4匹以上居れば
過疎、もしくは過密により死滅するというプログラムです。
興味のあるヒトは、「ライフゲーム」検索してください。
例えば、こんな感じ。
で、最初は120×120くらいで計算してたのですが、
Androidシミュレータ上だと100ms以上時間が掛かってて、
描画処理も描画する長方形の数依存で気持ち悪いことになってて、
結果的に80×80を採用することにしました。
あと、初回execが時間掛かるので、
Engineのコンストラクタであらかじめ一回呼ぶようにしました。
一応、実測なんですが、実機にAcerのA500を使って計測したところ、
Androidシミュレータより画面(*1)が広くなって不安だったのですが、
結果的にはライフゲームが10ms以下で、描画処理は3〜5msくらい。
8fpsなら安定して動いてるようです。
あと、描画に必要な座標計算をonSurfaceChangedで行っていたので、
端末の向きが変わっても問題なく動作してました。
そんなこんなで、未だにソースコードを晒すときは
お酒を呑まないと恥ずかしくてやってられないネコでした。
おしまい。
(*1) シミュレータは320×240, A500は1280×800
Galaxy S2+HID+Debian = Perfect Handheld Computer(後編)
9月 11th
Galaxy S2が面白くて仕方がないよシリーズの後編記事です。
前編は、IS01での挫折の顛末〜Bluetooth Keyboard + MEDIAS N-04C、そしてGalaxy S2(SC-02C)への道程についてでした。後編では、主にSC-02Cのお話が出来ればと思います。
ふつうにHIDとして使う
そんなわけで勢いで機種変更してしまったGalaxy S2、まずはHIDデバイスの使い勝手が気になります。
うん。大変快適でした。キーボードもマウスも認識するっていいよね。Androidをスマホ用OSとして認識している人にとっては、マウスポインタが表示されるという事それ自体が新鮮かもしれません。どちらかと言うと組み込み系の汎用OSという出自で捉えると納得しやすいかと思います。
リモートデスクトップクライアントにしてみる
標準状態のAndroidでも、キーボードとマウスが使えるなら、リモートデスクトップは大いに実用になるはず、と踏んでいました。
早速試してみたところ、
- まあ普通に使える
- 画面解像度が合わないのが辛い。RDPは自由な解像度を許してくれないのだろうか、あるいはクライアントアプリの問題だろうか。
- キーボードもマウスも無い状態で使うRDPよりは100倍快適と思われる
という感触でした。概ね、思惑通りです。
そんなことより、とりあえずroot
で、買って半日もしないうちに、root権限を取るための作業を始めました。そもそも、rootedであることを前提として端末を買っているので、ごく自然な流れです。
※ここから先の話は、見よう見まねでやるとGalaxy S2がゴミになる(文鎮化する)可能性が非常に高い作業ですので、わかる人には参考になるであろう程度に大雑把に書きます。読んでも判らない人には、お勧めしません。このページだけ見てやろうとしても無理です。それでもやろうということであれば、その心意気はとても良いと思いますが、壊れたことを人のせいにするような人は絶対に手を出さないようにしましょう。ジコセキニンってやつです。
作業自体は先達諸兄の足跡をなぞっただけですので、詳説はしません。要するにカスタムROMを書き込むことになります。Galaxy S2は、ht-03aのような状況で、カスタムROMはCPU電圧を調整したりディスプレイ輝度を調整したり、もろもろ手が入ったカスタムROMが何種類もある状況のようです。某巨大掲示板群の当該スレッドを読めば概ね把握できるのではないかと思います。というか僕はそこしか読んでいません。また、ROMイメージの転送方法については、ぐーぐる先生にお伺いを立てれば回答が得られる程度の難度ですので、各自で把握頂ければと思います。
それでどのイメージを転送するかという話になりますが、標準状態のGalaxy S2をちょっと触ってみて、パフォーマンス等々には全く不満を感じなかったので、あくまで標準ベースでrootだけ取れる、というイメージを書き込みました。最近は書き込みのことを「煮る」と言ったりするんでしょうか、それは一部だけでしょうか。その辺はついていけていません…。
カスタムROM制作にトライしている諸兄には篤く御礼申し上げます。
※ところで、カスタムROMを取得して導入するのって、著作権的には違法になるんでしょうか。海外ではカスタムROMを書き込みできるように開放する、といった動きもあるようで、黙認なのかなあと思っているんですが(純正ROMの製造コスト自体は端末の料金に含まれているわけだし)、もし法に触れる(あるいは誰かの迷惑になる)ようであれば、本意ではないので、このエントリは削除します。
そんなわけで無事にrootを取得できました。
なんてお手軽なんでしょう、感動的です。ハックしてる感は、全くありません。ていうかハックしてません。
Debianイメージの作成
続いて、Debian の準備を行います。基本的なアイデアはここに説明されている通りです。ざっと見てもらえればわかると思いますが、要するに
- debootstrapでarm用バイナリを指定してextのイメージファイルを作る
- 作ったイメージファイルをloopback mountして、そこにchrootする
という、それだけの話です。その筋の方なら難しくも何ともないと思います。逆に、先のページの内容を理解出来ないようだと、苦労すると思います。とはいえ、やってみないといつまで経っても出来るようにはならないので、リスクを承知でトライするのは面白いと思います。root取るのさえ失敗しなければ、この作業は失敗したところでdebianが立ち上がらないだけで、Android環境までは壊さない・・・いや/system/ を書き換えて壊そうと思えば壊せるか・・・まあたぶん、よほどじゃなきゃ壊さないと思います。知らん。
で、おいらはdebianを普段使っていないので、ESXiにさくっとdebian環境作って作業しましたよ。CDブートでいいんじゃね?とか、なんか別にCentOS上でも何とかなるんじゃね?って気もしたんですが、debianのインストールって、いま、酷く簡単だし、仮想化のおかげで物理マシンも用意しなくていいし。ラクな方に流れました。
debian.img の作り方はもう手引きの通りです。留意する点としては、
- おそらくSDカード上にイメージを配置しようと考えていると思います。ファイルシステムを確認してください。
- fat32であれば、1ファイルのサイズ上限は4GBまでです。
- 謎の数字で言うと 4194304000 ぐらいの感じです。
あとは特に何もなかった気がします。
ちなみに、armバイナリがあるディストリビューションでいまもアクティブに保守されてるのって、どれぐらい選択肢あるんだろうと思ってwikipediaを見てみたところ、うーん。Debianのほかには、GentooとSlackwareだけですか。さすがにクロスビルドする気合いはありません。
そう・・・玄箱にVineを入れていてね・・・アップデートできなくなって悲しい気持ちになってたんですよ。玄箱うぉううぉうさんのアレです。その玄箱も、半年ほど前、ものすごく忙しいさなかに華麗に逝きました。臭いからして、電源系のコンデンサとかそんな感じで。でも丸6年以上動いたのかな。彼はえらかった。
Debianイメージを端末に持ち込んでchrootする
このステップさえ乗り越えてしまえば勝ったも同然ですね。とりあえず作ったdebian.imgをscpなりで作業端末経由でSDカードに書いてあげて、端末に置いてあげて、までは誰でも出来ると思います。問題は、先の手引きで”bootdebian”として紹介されているシェルスクリプトですね。
答えは載せませんが、要点だけ
- chrootコマンド自体は、Androidマーケットからbusyboxを導入することでわき出てきます。
- 僕はStephen(Stericson)さん作のBusyBoxというのを導入しています
- このアプリはBusyBoxのInstallerということらしく、起動すると導入するBusyBoxのバージョンを選べるのですが、最初導入を選択した1.18.xのバージョンでは、chrootが導入されませんでした。
- v1.17.1 を導入するとchrootのsymlinkが出来ていました
- chrootが無くてすんげーハマった。知らんがな
- まさかyaffs2そのままでやろうって人はいないよね。/dev/block/mtdblock3 とかそのまま使おうって人はいないよね。自分の端末のmountの結果見てから考えるよね。
- そういえばext4にびびった
- Galaxy S2は内蔵ストレージと外付けストレージ(micro SD)がある
- 内蔵ストレージ: /mnt/sdcard
- micro SD: /mnt/sdcard/external_sd
- /system に書きたければ、
mount -o remount,rw -t ext4 /dev/block/mmcblk0p9 /system
大体これぐらいの情報でいけるんじゃないかと思います。行けない人はやめといた方が(略)。いやだってさあ、ここを無理に進めたとしても、X11環境をイチから作ることになるんすよ。.Xresourcesとかxinitとか@im=とか、解ってないと相当辛いと思うんですよね。。。(やったことあっても苦労する)
ちなみに僕のbootdebianは、
export img=/mnt/sdcard/external_sd/debian.img
export home_img=/mnt/sdcard/external_sd/root_home.img
:
losetup /dev/block/loop5 $img
losetup /dev/block/loop6 $home_img
:
mount -t ext2 -o noatime,nodiratime /dev/block/loop5 $mnt
mount -t ext2 -o noatime,nodiratime /dev/block/loop6 $mnt/root
ということになっております。4Gじゃ足りなかったの。
debootstrap –second-stage する
いやもうここまで来ちゃえばね。
眺めてるだけ。特に問題なく終了してくれました。
つまり、
まるっとdebianな訳です!やったね!
環境構築
正直ここから先なんてどうでもいいっていうか、もうAndroid関係ないしおまけみたいなもんです。
- とりあえず # apt-get install gnome とかやってみました(←
- sslcert の導入でコケました。$TEMPDIRが定義されていないのが問題だったので、適当に.bashrcこさえました。
mtabが無いおかげでdfコマンドが使えません。ln -s /proc/mounts /etc/mtab という大味な回避策を取ってみました。いいのかこんなんで。
- Xのビデオドライバなんてあるわけないのでvncサーバを使う。
- tightvncserverしか選択肢がないので、それで。
何か残ってた謎のメモ文字列。
# export USER=root # touch /root/.Xresources # vncserver -geometry 800x480 -depth 24 :1 (なんかパスワード訊かれるから適当に) # export DISPLAY=:1 # vncserver -kill :1 (tightvncの止め方)
gnomeは、使えなくはないんだけど重たいので、WindowManagerはXfce4に落ち着きました。あとはまあ、フォント関係(unifont ttf-kochi-gothic ttf-kochi-mincho ttf-vlgothic)導入したり、日本語入力環境整えたり、ですね。
- http://wiki.debian.org/JapaneseEnvironment
- http://www.softel.co.jp/blogs/tech/archives/2589
- http://www.h7.dion.ne.jp/~maruyosi/pasocom/debian_trial_52.html
意外と難しいのが、AndoroidアプリのVNCクライアントですね。試した中では「アンドロイドのVNC」というアプリが一番良かったです。難しさとしては、
- 2ストロークキーが入力されない
- 画面サイズが上手く指定できず全画面表示に出来ない
- マウスでアプリケーションのウインドウを掴む操作(移動、リサイズなど)が出来ない
- localhostへの通信なのに再描画が入ったりストレスを感じる
という類のモノがあると感じました。その中で一番バランスが良かったのが、アンドロイドのVNCという、直訳ロックなソフトでした。このアプリで不満なのは、Shift+Spaceが認識されないことだけです。(僕は10年前のkinput2の時代からimのスイッチをShift+Spaceでやっている。Windows/Mac環境下ではCtrl+SpaceでIMのスイッチをしている)これは、Shift+↑がなぜか認識されるので、とりあえずそっちに振り分けて妥協することにしました。いいの、非常用だし。Alt+Escとかそんな非人道的なキーよりはいいと思う。あれは指がつると思うんだ。
現状のパフォーマンス
結局どんなもんか、見てもらうのが早いでしょうか。
ごめん、ちょっと作業環境が良くなくて、あまりきれいなビデオ撮れなかったんですが、大体どの程度の感覚なのかはつかめるかと思います。
まず、sylpheed を立ち上げています。キータッチが遅いのは、手前に漫画を積んで、その上にビデオカメラを置いているから。1分前後のあたりで受信箱を開いてから少し待ちがありますが、これは3GでIMAPアクセスをしているからです。通信は全てdocomo 3Gです。
1:30あたりから、firefox (iceweasel)を立ち上げています。これは普通に新聞社サイトを閲覧しています。3G待ちの時間が多い感じですね。
最後に、3:20あたりから、OpenOffice.orgを立ち上げている感じです。
正直、sylpheed とfirefox ぐらいなら全然イケちゃうなあ、という感想です。いや、そりゃ、画面の狭さは如何ともし難いものがありますが、体感的にはPentium2-400MHzよりは早いんじゃないだろうか、と思っています。
まとめ
どうですかね。普通のキーボードとマウスがあって。画面こそ狭くて小さいけれども、これぐらいの処理能力があるコンピュータが、常に携帯できるとしたら。結構魅力的じゃないかと思うんです。正直、F-07Cよりこっちの方がいいんじゃないかと思うんです。だって、Windowsモード時にbluetooth使えないって、あんまりだよF-07C。買う気満々だったのに。
キーボードとマウスが重たいじゃん一緒じゃん、という向きもあるかと思うんですが、考えてください。スマホはいずれにせよ常に持ち歩いてますよね。なので、重量増分は0グラム。僕の場合、AC-USB(iPhone用)と、USBケーブルも常に持ち歩いているので、充電分まで含めて重量増分ナシです。で、キーボードがRBK-2000BT3で、重量は電池含まず180g。電池は単4が2本なので、おおよそ20g、それにケースで20gを見てざっくり220gぐらいでしょうか。マウスがiBuffaloのBSMLB06NWHで、重量が18g。電池2本入れて40gぐらいでしょうか。キーボードとマウスの総計で260gを持ち歩くということになります。
いかにVAIO typePが軽いとはいえ、600gはあるんです。それに、ACアダプタが100gちょいでしたか。そのほかケースだケーブルだ、と考えると、なんだかんだで800gぐらいにはなるんじゃないでしょうか。そう考えると、500gぐらいは違うわけですよ。いつも500mlペット一本無駄に持ち歩く感じな訳です。重いって。普通のPC(レツノとかMBAとか)は本体だけで1kgを軽く越えちゃいますからねえ。ACアダプタまで入れたら1.3kgでもまあ軽いんじゃないでしょうか。1kg違うわけです。
もちろん、かなり制約は厳しいです。非力だし画面は狭いし字は小さいし。でも、最低限出来ないと困ることは提供してくれている、そこに価値があると思うんです。繰り返しになりますが、計算機を使うと解ってるなら、最初っからThinkPadなりTypePなり持参すれば済む話なんですよ。まず使わないけど、最悪の場合のために・・・という理由でPCを持ち歩く事情がある人には、理解してもらえるんじゃないかと思っています。
ところで、僕の中ではGalaxy S2いじりはまだ終わっていなくて、以下のネタがあります。
- USBホストケーブルを使って
- SDカードからデジカメ画像を取り込んでflickrに上げてみる
- セルフパワーのHDDをつなげてみる
- 無理だと思うけど手当たり次第USBデバイスをつないでみる
- HDMI出力ケーブルを使って
- OpenOffice.org の Impress、またはAdobe PDFの最大化表示を使ってプレゼンに挑戦
- qemu動いたりしないかなー
- ビデオとかどうでもいいからエミュレートだけ走ってくれればなあ
- XPをRDPサーバにできれば、描画はAndroidアプリのRDPクライアントを使えばいいよね
- まあ実用になるかというと、アレだけど。
特にqemuの件は先に検証してから日記を書きたかったわけですが、いかんせん最近忙しくなってしまい、まとまった時間を取るのが1ヶ月後ぐらいになりそうなため、pendingのまま日記を上げてしまおうと思います。どなたか時間ある方いらっしゃったら、試してみませんか。すごい面白いと思うんですけど、ダメっすかね。Galaxy S2でエロゲの一本でも動かせば、それなりにインパクトのある感じになると思います。
そんなわけで、Galaxy S2、すごくいいです。Android端末、特にdocomoのAndroid端末を使っている人は、spモードメールアプリの遅さにイラッ☆と来てるに違いないと思いますが、Galaxy S2で使うと超快適です。ブラウザもtwiccaもアホみたいに早いです。iPhone3GとiPhone3GSぐらいの違いがあると思います。きっと、来年あたりは、デュアルコアCPUが主流になるんだろうなあと予感せずにはいられない一台でした。あと、スマホに関して言えば、現時点では国産はダメかもしれない。いままでいいなと思った端末は全部洋物な気がしてきました。MEDIAS(N-04C)は、いつになったら2.3に更新してもらえるんだろう。
それではみなさん、よいモバイル・ライフを。
Galaxy S2+HID+Debian = Perfect Handheld Computer(前編)
9月 11th
Galaxy S2買っちゃったー&そっこーでオモチャにしちゃった。
今回は、なんで唐突にGalaxy S2を買っちゃったのか、そこに至る経緯と、Android はそのままに、Debianのユーザランドを動かす話について書くよ。意外と長くなっちゃったので、前編はGalaxy S2(SC-02C)購入に至るまでのアレコレ、後編はSC-02Cを触ってのアレコレ、という構成になっています。
プロローグ
そもそも僕はハンドヘルドコンピュータが大好きなのです。今にして思えば、PC-9801NS/Tを背負って中学校に通ったあたりから僕のモバイルコンピューティングが始まりました。電子手帳やらpremini(初代)やらSigmarion3やらLibretto50やら、大好きなのです。Willcom D4も当然買いました。IS01も当然に乞食しました。
僕がモバイルに求めるのは、
- 何も考えずに常に持ち歩けること。
- いつ何時必要になるかわからない。
- 必要になると最初からわかっているなら、ThinkPadを持っていけばよい話でしかない
- フルコンピュータとして、一通りの事が出来ること。
- ssh接続して一通りのサーバ保守作業
- SDカード読みこんで画像をflickrに上げたりメール添付したりぐらいは出来ること
- 打ち合わせメモをストレスなく取れること
- メールを見られること。添付で付いてきた.xlsぐらいは読めること。
- I/Oは今ならUSB必須。有線LAN、外部モニタ出力は欲しい。RS-232Cあればなお可だがUSBで逃げてもよし。
- フルキーボード必須。
- マウスポインタはトラックポイント(または準ずるもの)が望ましい
- 最低電池駆動1時間
です。
これらの条件を満たすため、現在はVAIO typePを携帯しています。
この子には基本的に何も不満が無いのですが、最近これですら「重たい」と感じるようになってきました。「いつ必要になるか判らないから常時携帯していたい」ので、常に持ち歩いている訳ですが、言い換えると「9割方使わない」わけで、やっぱり使わないとなると、無駄な重量だと感じてしまうのです。歳のせいにしておきたいと思います。
そんな折、IS01でDebianが使える、という記事を見かけました。VNCをXサーバとして使うことで、X11環境も構築できるようです。
IS01でX11 環境の夢を見た
「ほうほうこれは興味深い、では僕も早速・・・」ということで、購入後一度もファームアップしていない自慢のIS01を掘り出してきてですね
MobileHackerzさん謹製「IS01 rooter」を
いやーなんてお手軽なんでしょう。もう、ハックなんて恥ずかしくて呼べないレベルまでお手軽になっちゃってます。ただの設定、ですね。だってもう、本スレのログ読む必要すら無いレベルですよ。
ありがたや。指示通りに操作するだけで何の問題もなくroot取れました。あ、01.00.07 でも問題なく特権取れてます。留意点は、せいぜい、super userは別途導入してあげないといけない、ってぐらいでしょうか。とにかく簡単すぎて、もうあまり記憶がありません。
さて、まあとにかくrootは取れたので、次はdebianのイメージを作って。。。って、このキーボード、パイプ(|)入力できないのかよ!!!!
あー、ごめん、無理。一時的にはソフトキーで逃げれるけど、、、
僕の目的は前述の通り、linuxのシェルぐらい操作出来ないと困るわけで、パイプがソフトキーとか、ちょっと考えたくないです。 ps -ax | grep hoge って入力するのに、ソフトキーボードは、ねえ。大体、外でターミナル開かないといけないってのは、割と平時な状況ではないわけでして、あんまりのんびりもしてられないわけで。
じゃあ、IS01にキーボードだけ外付けすればいいじゃん、と考えるわけです。Bluetoothキーボードをですね・・・って調べてみたら、IS01はHIDをサポートしてないんですね。そうですかそうですか。確かに、標準のキーボードとトラックボール、いいですもんね。外付けキーボードなんていらないですよね。
そんな理由でIS01にDebianを載せるのはやめちゃいました。IS01には、このまま主に車載マルチメディア端末として活躍していただこうと思います。彼がいないと、渋滞したときにNHKニュースすら見られなくて困るのです。
なぜかBluetoothキーボードを買ってMEDIAS N-04Cで活用してみる
ところで、Bluetoothの外付けキーボードを調べていくと、HID非対応、SPPプロファイル対応、という端末でも(無理やり)キーボードを使える製品というのがいくつかあるのですね。その中でも、リュウドのRBK-2000BT3あたりは、僕が使っているMEDIAS N-04Cも(非公式)対応しており、そこそこ安価なようです。打ち合わせメモぐらい取れるようになるといいなーと思い、ぽちったのが先々週?の話です。
到着したら、張り切って使うわけじゃないですか。
そんなわけで打ち合わせメモをMEDIAS N-04Cで取ってみた感想は・・・
- とりあえず使える
- 使えないわけじゃない
- Androidスマホ単体で使う事を考えたら遥かに快適だ
- キータイプに微妙についてこない事がある
- やっぱ打ち合わせメモだけ取れても仕方ないかなあ・・・
というものでした。まあ、概ね予想通りというところですね。入力を実現するためにBlueKeyboard だっけな、そういったアプリを使うのですが、キーボードの切り替えを毎回意識しなければならないのが手間なのと、タイプについてこない事があるのとがストレスかなあ、と感じました。
ここでやめておけば良かった。「ちなみに、HIDをサポートしているスマホって何があるんだろう」と、docomoの公式をつらつらと見てしまったのが悪かった。圧倒的なスペックで話題のGalaxy S2のBluetooth欄には「HID」としっかり書いてあった。そして、Galaxy S2は、既に先達により、rootedだった。この状況で、僕が物欲を抑えることが出来るだろうか。
結論から言うと、3回目のヨドバシカメラで、屈した。だって、デュアルコアだし。
書いてて思ったんですが、わりとココまで全てどーでもいい内容ですね。前後編に分けた方が、見る人にとって優しい気がしてきました。そんなわけで、全六部作は無理ですが、全二部作にしようかと思います。
つまり、後編に続きます。
イオン980円SIMとWiMAXとドコモ純正SIMと心強さと
8月 24th
なんか4つになってるけど、まあいいか。イオン980円プラン北海道展開記念エントリです。
そんなわけで先週東京に行ってきてですね、念願のb-mobile 100kbps 980円/月のSIMを大購入してきた僕様なんですが、なんとその翌々日に北海道での展開が発表されるとかね、もうね。わざわざ品川シーサイドまで電車を乗り継いで行ったのに・・・。そんなわけで時代の最先端の最後尾を突っ走る僕様が、札幌での使用感を簡単に報告しますよ。
契約について
品川シーサイドのジャスコではこんな雰囲気で展開していました。
まあ、こういうことになりますよね。そこにあるプラカードをレジに持っていって下さいな、と言えば契約できます。ぼくは免許証とクレジットカードで行きました。契約自体は30分かからなかったと思います。
でまあ、SIMはSIMでしかないので
見ても何の変哲もありませんね。強いて言えば、このSIMをぽきっとやるのは初体験でした。微妙に緊張しましたが、きっと初めてだからでしょう。
ぼくはこのSIMを、現在のところiPhone 3G(JB, unlock済み)で使っています。重要なのは「で、それ、使い物になるの?」ですよね。そんなわけで、勢いで契約したWiMAX、docomoの標準データ定額wifiルータ、docomoのふつうのスマホと並べて比較してみたいと思います。
iPhone 3GS + WiMAX WM3500R @ 札幌市北区(札幌駅近郊・ビル内)
未だに赤にするべきだったか迷いがあります。白、思いのほか文字や表示が見づらいんですね、これ。
このルータについては、特に何も感想が無いです。SSIDやキーが初期状態で適切にランダムなものが設定されていて、それが本体にシールで貼ってあるので、そのまんま使っちゃうぐらい何も設定しないで使ってます。レビューおわり。
で、今日の話題は反応速度や速度感の問題なので、動画をごらんくださいませ。
AFがあらぬところにいっているのは平にご容赦を。見ての通り、大変快適です。1分あたりのところでLockerz開けなくて待っちゃってますが、これはその後再試行することで上手く行ったので、どこかで誰かがくじけていた感じですね。結論としては、エリアさえあれば、とても良いです。でも北海道を移動する人には使えないと思います。とりあえず、新千歳空港~大谷地駅のバスは、使えませんでした。新千歳空港のバス乗り場は大丈夫で、自宅も大丈夫なんです。恵庭なんかでも時々電波捕まえるんですが、市街地の間は全くダメですね。
何でもいいんだけど、HD(1080p)で見れるのね、この動画。NEX-5で撮ったのをそのまんまyoutubeに置いただけなんだけど、ものっそい無駄なことは確かですね。
iPhone 3G + b-mobile 100Kbps @ 札幌市北区(札幌駅近郊・ビル内)
先にも書きましたが、国内でソフトバンクが発売したiPhoneは、そのままではもちろん使えません。SIMロック解除については本題から外れるので省略と言う事で
まあ、動画を見てください。話はそれからだ。
今度はAFばっちり。つか、480pあたりで見るとすげー高画質なのね。いい時代だなあ。
で、どうでしょう。iPhone3G、思ったより使い物になってると思いませんか?僕は「ピクト立ってるのにパケットが通らなくてイライラするソフトバンク回線」より遥かに使えると感じました。何ていうんですかね、端末ののんびり感とパケット通信の牧歌的な感じが、どちらに責任があるのか判らない、極上の待ち時間を醸し出しています。こうやって使うなら、980円SIM、すごくいいと思います。
しかし、ピクト立ってないのは、A-GPSの云々とかの話なのかなあ。foursquareはくじけちゃう感じでした。
MEDIAS N-04C + docomo普通の契約 @ 札幌市北区(札幌駅近郊・ビル内)
申し訳ないくらいどこにでもある初代MEDIASです。
何の面白みも無いですが、一応比較対照的な。
メモリ容量的な理由でスピード計測アプリ入れてないんですよね、この子。なもんで、お約束のブロードバンドスピードテスト(www.bspeedtest.jp)で計測してみました。
あと、そうだ、このビデオを撮ったとき、twitpicさんがくじけておられたのでした。僕のtwiccaにはtwitpicプラグインしか入れてなかったもので、しょうがないのでtwitter純正のアプリからyfrogにアップロードしています。iPhoneはEchofonでLockerzに上げていますので、その辺条件がイーブンでは無いです。まあ使用感はこんなもんだよね、ということでひとつご容赦を。
PC(TP X301/Windows7) + WiMAX WM3500R @ 札幌市北区(札幌駅近郊・ビル内)
これはスピード計測の画像一枚で。
んーまあこんなもんすかね、ストレスは特に無いです。ちょうど10年前ぐらいに、ヤフーBBさんあたりが大量に配っていた8MbpsのADSLぐらいの感覚で使えるかなあ、というところです。新宿ヨドバシカメラ横の喫茶店では10Mbpsが出ましたが、あれは条件が良すぎるのだろうなあ。何にせよ、不満のない速度です。数回試すと上り3Mbpsぐらいまで行くこともあるので、多少振れ幅はありそうです。
PC(TP X301/Windows7) + docomo BF-01B/docomoデータ定額契約 @ 札幌市北区(札幌駅近郊・ビル内)
素直にドコモショップに行って「パソコンでインターネットしたいんです!Xiとか何それわかんない怖い!3Gがいい!」って言ったら出てくるであろう契約ですね。
うん、まあ、こんなもんすよね。この契約の価値は、全道どこでもとりあえず最低限の通信環境を確保できることにあると思います。例えそれが池田町でも、陸別町でも、きっと大丈夫です。逆に言うと、大都市部にしか居ない人には無用なのかも。
PC(TP X301/Windows7) + docomo BF-01B/b-mobile イオン100Kbps @ 札幌市北区(札幌駅近郊・ビル内)
さて、じゃあ、BF-01BにイオンSIMを刺したらどうなるか。
うん。
えーっとね、体感的には、15年昔に戻ったと思えば大体外さないです。V.42bisの56kモデムとか、PHSでPIAFSとか、そうそんな感じ。ある意味で青春を感じるインターネットがここにありますよ。そのエモさをぜひ動画でお届けしたいと思います。
たまらないじゃないですか「ちろっ、ちろっ」と流れてくるjpeg画像。ほら、tripodやgeocitiesに掲載されている無○正画像をワクテカしながらモニタの前で2分間正座していたあの頃を思い出しませんか?思い出しませんか。すみません、その頃僕ハイティーンだったんです。察してください。久米田も言ってたじゃないですか、現代はいきなりすぎて詫び寂びが無いって。いきなりモロとかグロとか心の準備出来ないからイクナイですよ。そういう意味ではとても安心できる在野のインターネットがここにあるんじゃないかと思います。
ビデオ後半ではシェルでの操作も行っています。ls や ps を目で追えるこの安心感は凄いですね。目lessが可能です。vimはねえ。。。出来ない事はないけど、って感じですね。緊急対応でコンフィグ書き変えてプロセス立ち上げ直させるぐらいなら全然いいですが、これでコーディングはしたくないなあ、というところです。PHSみたいなもんです、ホントに。
あとは、fomaデータ定額だと規制掛かって繋がらないircは一撃ですんなり繋がりました(IRCnet/6667)。SSH(22)もOKでした。ちゃんと使ってないんですが、まあSSHさえ通ればあとはSOCKSなりポート転送なりでどうにでもなるので、それ以上調べる気もありません。
まとめ
僕としては、docomo純正のデータ定額プラン(月5,000円ぐらい)をどうするか本気で悩んでいます。iPhone3Gがテザリング出来るので、IP取るだけならそれでいいんですよねえ(b-mobileのSIMは用途を限定したりしていないので(普通にVAIO TypePに刺すのだってOKなはず)、PCにテザリングさせても何も問題ないはず)。60-70Kbpsと、800Kbps-2Mbpsの間に月4,000円の価値があるかというと、微妙なところです。外出先でメール取ったりweb参照するぐらいなら、100Kbpsでも使えるんだよなあ。
WiMAXについては、UQ Flat で契約したので、最低利用期間30日間は使います。31日目に解約するつもりです。その後は、電波がある状態で高速な回線が欲しくなったときに、UQ 1Day で運用するつもりです。じゃあなんで最初UQ Flatで契約したかって、こっちで契約すると端末が1万円引きだったんですよね。1ヶ月分の基本料4,480円? を失うとしても、実質5,000円ぐらいは値引きになるじゃないですか。それに、契約したら少なくとも2,3日は使うんだから、そう考えると定価で端末買う事も無いか、と考えた次第だったのでした。
レポートは以上です。おおよその速度感を把握する一助になれば幸いです。いやあ、しかし最近はこの辺が断然面白いですね。




























