BlankTar

about | blog | works | photo

私とASUSのX205TAとの戦いの始まりは去年の2月に遡ります。gentoo入れようとしては失敗し、Arch Linux入れてはドライバが足りず…。
そしてついに、その戦いに決着が付きました。

Remix OSなるOSがあります。
元Googleの開発者が作ったOSとかで、Androidベース…というか、デスクトップ版Androidみたいな代物です。
結構面白いので実機に入れてみようと思ってX205TAに入れたのですが、これがかなり良い。

簡単にですが、手順を記録しておきます。
なお、ここで行なっている手順は非常に荒っぽいです
正直言ってマトモな手順ではありません。自己責任でどうぞ。

RemixOSを起動するためのUSBメモリを用意する

Remix OSのダウンロードページから64bit向けのzipファイルをダウンロードしてきます。
展開するとISOとexeが入っているはずです。

付属してきたexeでISOファイルをUSBメモリに入れます。
USBメモリは8GB以上32GB以下のものにしてください。普通に使う分には32GB以下って制限は無いのですが、この記事の方法でインストールする場合は必ず守った方が良いと思います。

例によってX205TAのUEFIではこのままでは起動出来ないので、一度マウントしてブートローダを差し替えます。
/EFI/boot//EFI/RemixOS/の二つのディレクトリにあるbootia32.efix100ta用のもので置き換えます。

これで準備完了。

BIOS(UEFI)の準備

もしもまだBIOS設定に入るための準備をしていないのなら、windowsの高速起動を無効にする必要があります。
Shiftを押しながら再起動ボタンをクリックして、トラブルシューティング->詳細オプション->UEFIファームウェアの順に選択していきます。

BIOS画面に入ったら、AdvancedタブのUSB ConfigurationでUSB Controller SelectをEHCIにします。
それと、SecurityタブのSecure Boot ControlをDisabledにしてください。

USBブートする

作ったUSBメモリをX205TAに挿して、BIOS画面のSave & ExitタブのBoot OverrideってやつからUSBメモリを選んでUSBブートします。
GRUBの画面に入ったらGuest modeってやつで起動。Resident modeでも良いのですが、やたらと遅くなったりするのでお勧めしません。
ちょっと時間が掛かるかもしれないけれど、辛抱して起動を待つ。

最初の設定に入るので、そのへんは適当に。
ただし、Wi-Fiはスキップしないで設定してください。ターミナルアプリを入れるために必要です。

インストール

いよいよインストール作業です。
本来ならばGRUB画面でブートオプションを書き換えて起動するインストーラを使うのですが、試した限りではうまく行きませんでした。
普通のインストーラの使い方を詳細に書かれている記事がありましたので、参考までにどうぞ。

で、入らないからどうするかというと、ddコマンドを使ってUSBメモリの中身を丸ごと内蔵ストレージにコピーします。
無茶苦茶な方法ですが、良い感じに出来ました。

Termuxというアプリが入っているので、左下のスタートボタン的なところから探して起動します。
起動したら以下のような感じで。

$ su -
# dd if=/dev/block/sda of=/dev/block/mmcblk0 bs=8192 count=1048576

これでインストール(というかコピー)することが出来ます。
死ぬほど時間がかかりますが、辛抱強く見守ってあげてください。

なお、bsとかcountオプションについては8GBのUSBメモリを使用した場合を想定しています。
bsとcountを掛けた値がUSBメモリのサイズになるように設定してください。

ddコマンドが無事終われば、ひとまず起動出来る状態になっているはずです。
途中でフリーズしてしまった感じがしても、強制終了させて起動してみると案外行けたりするかも? 私の場合はそんな感じでした。

パーティションの拡張

私が今回インストールに使用したUSBメモリは8GBのものです。
8GBのUSBメモリを32GBのeMMCにddしたので、当然かなりのスペースが無駄になっています。
勿体無いので、パーティションを広げておきます。

失敗するとデータが消えてしまうので、/dev/block/mmcblk0p3の中身のバックアップをしておくことを強くお勧めします。

バックアップが終わったら、自動でマウントされているものをアンマウントしてください。

準備が出来たらさきほどと同じくTermuxを起動して、以下のようにして拡張を行ないます。

$ su -
# fdisk /dev/block/mmcblk0
Command ('m' for help): p
Disk /dev/block/mmcblk0: 31.2 GB, 31272730624 bytes
4 heads, 16 sectors/track, 954368 cylinders
Units = cylinders of 64 * 512 = 32768 bytes

			 Device Boot      Start         End      Blocks  Id System
/dev/block/mmcblk0p1              33       34304     1096704   c Win95 FAT32 (LBA)
Partition 1 does not end on cylinder boundary
/dev/block/mmcblk0p2   *       34305      198144     5242880   b Win95 FAT32
Partition 2 does not end on cylinder boundary
/dev/block/mmcblk0p3          198145      247296     1572864  83 Linux
Partition 3 does not end on cylinder boundary


Command ('m' for help): d
Partition (1 - 4): 3


Command ('m' for help): n
  e  extended
  p  primary partition(1-4)
p

Partition (1 - 4): 3

First cylinder (1 - 954368, default 1): 198145

Last cylinder or +size or +sizeM or +sizeK (198145 - 954368, default 954368):
Using default value 954368


Command ('m' for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table
fdisk: WARNING rereading partition table failed, kernel still uses old table: Device or resource busy

パーティション3のstartの位置をpコマンドで確認して、nコマンドで同じ場所に新しいパーティションを作っています。
間違えるとデータを読み出せなくなるので要注意。

リソースが使用中だとか文句を言われたので、素直に再起動してもう一度USBメモリから起動します。
やっぱりTermuxを開いて、以下のように。

$ su -
# e2fsck -f /dev/block/mmcblk0p3
# resize2fs /dev/block/mmcblk0p3

これでパーティションの拡張は完了です。

内蔵ストレージからの起動

シャットダウンしてUSBメモリを抜いて、もう一度起動します。
すると内蔵ストレージから起動する、はず。きっと。
初回起動は時間が掛かったりしますが、何度かやってるとそこそこ早くなる気がします。体感ですが。

ハードウェアの対応状況

Wi-Fiとディスプレイの輝度、バッテーの状態取得、Webカメラは問題なく動作します。
タッチパッドもほぼ完全に動作しますが、二本指でのタップが無いっぽいです。右下をクリックすれば問題無し。

キーボードのファンクションは確認出来た範囲で機内モード、ディスプレイ輝度、音量調整などが使えます。
機内モードはOS側の機内モードとは別らしく、解除がちょっと面倒臭いので注意。キーボードで解除してからOS側のWi-Fiをオンオフしないといけない。
あと、fn + F8で何故か音楽プレイヤーが立ち上がります。

キーボードから音量調整が行なえると書きましたが、肝心の音は出ないようです。
内蔵スピーカー、イヤホン、HDMIの全てがダメでした。無念。

HDMIの映像出力は出来ますが、解像度を調整する術がありません。
そもそもディスプレイの解像度を調整出来ないので、Androidの宿命のようです。
ドライバ的には対応しているようなので、RemixOSの今後に期待?

スリープ状態に入ることは出来ますが、映像は復帰出来ても高確率でキーボードもタッチパッドも反応しなくなります。
たまにキーボードは使えるようになりますが、タッチパッドは今のところ復帰出来たことがありません。
タイムアウトによる自動スリープに注意。設定変えといた方が良いかも。

Bluetoothは使えません。そもそも認識していないようです。

色々動いてない感じがしますが、この子にしては上出来です。随分動いてます。やったね。

pythonでシングルトンを書くと結構スマートに書けるっぽいことを知ったのでメモ。
まあ、私は滅多にシングルトン使わないんですけれど。

シングルトンっていうのは以下のようなやつです。

class NormalSingleton:
	_instance = None

	def __init__(self):
		print('init')

	@classmethod
	def get_instance(cls):
		if cls._instance is None:
			cls._instance = cls()

		return cls._instance


if __name__ == '__main__':
	a = NormalSingleton.get_instance()  # initが表示される
	b = NormalSingleton.get_instance()  # 何も表示されない
	print(a is b)   # True

	c = NormalSingleton()  # init
	b = NormalSingleton()  # init
	print(a is b)  # False

こいつはよくある普通の実装。
get_instanceメソッドを使ってインスタンスを取得しているうちは良いのですが、普通にインスタンス化出来てしまうのでシングルトンになりません。
他の言語だとコンストラクタをプライベートにするとかで対処するわけですが、pythonではそうも行かず。

で、どうするかっていうと、__new__ってメソッドを定義することにします。
__new__っていうのはクラスのインスタンスを作るときに呼ばれる特殊なメソッドで、__init__の前に呼ばれるようになっています。
こいつを使うとめっちゃ良い感じになる。

class SimpleSingleton:
	_instance = None

	def __init__(self):
		print('init')

	def __new__(cls):
		if cls._instance is None:
			cls._instance = super().__new__(cls)

		return cls._instance


if __name__ == '__main__':
	a = SimpleSingleton()  # initが表示される
	b = SimpleSingleton()  # こっちもinitが表示される
	print(a is b)   # True

使い方がとてもシンプルになりました。シングルトンかそうでないかを利用者が気にする必要性が無くなってハッピー。

__init__が二回呼ばれるようになることだけ注意です。
初期化は__new__の中でやっても良いかもね?

ちなみにどちらの実装もスレッドセーフではないので、スレッドセーフにしたい場合はLockを導入しましょう。
導入すると以下のような感じ。

import threading


class ThreadingSingleton:
	_instance = None
	_lock = threading.Lock()

	def __init__(self):
		print('init')

	def __new__(cls):
		with cls._lock:
			if cls._instance is None:
				cls._instance = super().__new__(cls)

		return cls._instance

使い方は全く変わらないので省略。
めっちゃ単純で良い感じですね。

Elixirの変数は変更不能らしいです。変化出来ない数、変数。ふしぎ。
安全性が高くて良いのですが、Webのアクセスカウンター的なものを作りたいときとか、メモ化とかやりたいときに困ります。
というときに登場するのがAgentってやつらしいです。

とりあえず使ってみる

defmodule Counter do
  def counter do
	Agent.update(:counter, fn x -> x + 1 end)
	Agent.get(:counter, fn x -> x end)
  end

  def start_agent do
	Agent.start_link fn -> 0 end, name: :counter
  end
end

Counter.start_agent
IO.inspect Counter.counter
IO.inspect Counter.counter
IO.inspect Counter.counter

こんな感じで使います。

Counter.start_agent関数でAgentとやらを開始しています。スレッドみたいなもので、変数を保持しておいてくれるらしい。
第一引数は初期値を返す関数で、第二引数は識別子を渡しています。
識別子さえ変えておけば複数のAgentを立ち上げても大丈夫。

Counter.counter関数を実行すると、Agent.update関数を使って値を更新して、Agent.get関数で値を取得しています。
単純にカウントするだけだけどちょっと面倒臭い…。

メモ化のために使ってみる

メモ化といえばフィボナッチ数ということで、フィボナッチ数の実装をやってみました。

defmodule Memorize do
  def fib 0 do
	0
  end

  def fib 1 do
	1
  end

  def fib x do
	case Agent.get(:fib_memo, &Map.get(&1, x)) do
	  nil ->
		v = fib(x - 1) + fib(x - 2)
		Agent.update(:fib_memo, &Map.put(&1, x, v))
		v

	  v -> v
	end
  end

  def start_agent do
	Agent.start_link &Map.new/0, name: :fib_memo
  end
end


Memorize.start_agent
IO.inspect Memorize.fib 1024

Agentにmapを持っておいてもらって、fib関数が呼ばれる度に検索しにいっています。
見付かったらその値をそのまま返し、無ければ計算して保存する感じ。

メモ化しておけば1024とかで計算させてもすごいスピードが出ます。
事実上は1024回ループが回ってるだけだからね。

なんだか面倒臭い感じがするのですが、向いてないってことなのかなぁ…。

参考: Go VS Elixir (1)フィボナッチ数列 - 技術備忘記

[ << ] [ 2 ] [ 4 ] [ 6 ] [ >> ]