レベル変換の仕組み(オームの法則からMOS-FETを使ったレベル変換回路まで)
レベル変換
レベル変換とは、電圧の異なる信号線をつなぐ際に電圧を変換することです。
例えば Raspberry Pi という小さな Linux ボードコンピュータの電源電圧は 3.3V です。 そのため GPIO の入出力電圧も 3.3V となっており、電子工作でよくある 5V 駆動の装置を直接つなぐことができません。 著者は最近、秋月電子通商で売っている中で最安のキャラクタ液晶表示器 SC1602 を Raspberry Pi から制御しようと思ってレベル変換回路を作りました。
また、いわゆる「L チカ」といって LED を点滅させるだけの回路でも、LED によっては 3.5V 程度の電圧がないと十分に光らない品種があり (赤色 LED に比べ、青色 LED は高い電圧を求める傾向があります)、3.3V の出力では十分でないケースがあります。
レベル変換は低電圧側の回路から高電圧側の回路を制御するだけでなく、逆に高電圧側から低電圧側の回路を制御するのに用いる場合もあります。
ハードウェアエンジニアにとっては良く知られた回路ですが、ソフトウェア専門の人がちょっと電子工作しようとするとハマることが多いと思います。 この記事では、オームの法則を復習しつつ、レベル変換回路の基礎を見てみます。
続きを読むosdev-jp という自作 OS のコミュニティを作りました
これは 自作 OS Advent Calendar 2016 の初日の記事です。
自作 OS Advent Calendar といいつつ、初日は技術的なことは書かずにコミュニティの紹介をします。期待してくださった方にはすみません(^^;)
自作 OS コミュニティの昔と今
私が自作 OS というものを知ったのは 2003 年ごろのことです。 そのころ、ウェブには活発な自作 OS コミュニティがいくつかありました。 私は主に OSASK コミュニティで活動していましたが、周りには dev-j、OS-Wiki などの OS 系の情報サイトや Mona OS、MEG-OS もありました。
時は流れて 2016 年。 私はしばらく自作 OS から離れていましたが、あるきっかけでまた自作 OS 関連の活動を再開させようと思いました。
久しぶりの OS 熱に侵されながら、おぼろげな過去の記憶をもとに dev-j や OS-Wiki などを再訪してみました。 しかし、そこは荒れた荒野のような状態でした。 dev-j にいたっては、トップページさえ 403 エラーでアクセスできない状態になっています。
osdev-jp の紹介
そこで私は、自作 OS に再びかかわろうと思うきっかけを与えてくれた 2 人の若者 ―― @liva_jy さんと @hikalium さん ―― とともに osdev-jp というコミュニティを作ることにしました。
発足したのは 2016 年 3 月です。 発足当初、このコミュニティは(OS-Wiki のように)OS 関連の情報を集めるサイトの名前でした。 今は情報収集はあまり捗っていませんが、「自作 OS もくもく会」というオフ会を定期的に開催し、自作 OS 好きの人同士のつながりを作り出しています。
osdev-jp の主要なリソースは以下の通りです。
- GitHub : https://github.com/osdev-jp/
- リポジトリにはいくつかのサンプルコードがあり、GitHub Wiki にはメンバーが書いた記事が集約されています。
- osdev-jp Core Wiki : http://osdev-jp.readthedocs.io/ja/latest/
- コアメンバー(記事執筆時点で liva_jy, hikalium, uchan_nos の 3 人)が書いた、比較的体系立った記事が掲載されています。
- Vagrant や Visual Studio Code の記事は、自作 OS 以外の分野でも十分参考になる記事です。
- Slack : https://osdev-jp.slack.com/
- 自作 OS に興味のある方が参加しているチャットです。自作 OS もくもく会参加者を中心に 30 人ほど参加してくださっています。
- uchan_nos にメールアドレスを教えていただければ招待メッセージを送ります。
「自作 OS もくもく会」は今のところ 2 カ月に 1 回のペースで開催しています。 開催予告は GitHub Wiki の イベントカレンダー に載せていくつもりです。
nfcpy で複数の System Code を持つ NFC タグを扱う方法
Linux (Ubuntu 16.04) で nfcpy を使ってみました。落とし穴が多い気がしたので、ここにまとめます。 特に、複数の system code を持つような NFC タグの扱いが複雑ですので、詳しく説明します。
概要
Linux で NFC タグを読み書きするには nfcpy という Python ライブラリを使うのが割とよく用いられる方法のようです。 この記事では、nfcpy で NFC タグに記録されたブロックを取得する方法を説明します。
nfcpy に関する記事はいくつもあるのですが、どれも複数の System Code を持つ NFC カードの扱い方は書いてないようでした。 また、対応する nfcpy のバージョンが古かったりするので、この記事を書こうと思いました。
この記事で対象とする nfcpy のバージョンは 0.11.1 です。 また、動作検証は Sony 製の NFC リーダー・ライター PaSoRi RC-S380 を使って行いました。
nfcpy のインストール
公式ドキュメントは http://nfcpy.readthedocs.io/en/stable-0.11/ にあります。 (ただし、このドキュメントは少し古いです。現在 nfcpy は GitHub に移行したのですが、ドキュメントは lauchpad 時代のままです。)
nfcpy は PyPI に登録されているので、pip でインストールできます。 (nfcpy は現時点でまだ Python 3 系に対応してないので、pip3 は使わないでください。)
$ sudo pip install -U nfcpy
pip でインストールするとサンプルコードが手に入らないので、別途 GitHub からダウンロードします。
$ git clone git@github.com:nfcpy/nfcpy.git
$ cd nfcpy
$ git checkout stable/0.11
ここまでできたら、サンプルコードを実行して PaSoRi でタグを読み取ることができるはずです。
$ sudo examples/tagtool.py
[nfc.clf] searching for reader on path usb
[nfc.clf] using SONY RC-S380/P NFC Port-100 v1.11 at usb:002:013
** waiting for a tag **
Type3Tag 'FeliCa Standard (RC-S915)' ID=xxxxxxxxxxxxxxxx PMM=yyyyyyyyyyyyyyyy SYS=8108
NFC タグをタッチすると検出され、製造ID(IDm)、製造パラメータ(PMm)、システムコードが表示されます。(最終行)
おまけ:sudo を使わないで作業する方法
環境によって、USB 接続の NFC リーダーに一般ユーザが接続することができない場合があります。 毎回 sudo を使えば問題ないのですが、それは嫌だという方には公式ドキュメントで説明されている通り、回避策があります。
まず、一般ユーザで NFC リーダーが扱えないことを確認します。
$ examples/tagtool.py --device usb
[nfc.clf] searching for reader on path usb
[nfc.clf] no reader available on path usb
[main] no contactless reader found on usb
[main] no contactless reader available
この時点でちゃんとリーダーを検出できていれば、何もする必要はありません。 検出できないことが確認できたら、lsusb コマンドでデバイス ID を調べます。
$ lsusb
...
Bus 002 Device 013: ID 054c:06c3 Sony Corp.
...
それっぽいデバイスを見つけたら 054c:06c3
のところの番号を使って tagtool.py を実行しなおします。
$ examples/tagtool.py --device usb:054c:06c3
[nfc.clf] searching for reader on path usb:054c:06c3
[main] access denied for device with path usb:054c:06c3
[main] first match for path usb:054c:06c3 is usb:002:013
[main] usb:002:013 is owned by root but you are xxxxx
[main] members of the root group may use usb:002:013
[main] you may want to add a udev rule to access this device
[main] sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'
[main] no contactless reader available
「指定した ID のデバイスは root の所有なのでアクセスできないよ」てなことが書いてあります。 下から 2 行目に解決策が提示されていますので、そのコマンドを実行します。
$ sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'
マシンを再起動すれば、一般ユーザで使えるようになっているはずです。
NFC タグの中身を見てみる
nfcpy をインストールしたことですし、NFC タグの中身を表示するプログラムを作りましょう。 以下、NFC といいつつ FeliCa Standard を対象としたプログラムになっています。 他の規格のカードではうまく動かない可能性があります。
dump_simple.py は NFC タグ(の先頭 System)が持つサービスをすべて列挙するプログラムです。
import nfc
def check_services(tag, start, n):
services = [nfc.tag.tt3.ServiceCode(i >> 6, i & 0x3f)
for i in xrange(start, start+n)]
versions = tag.request_service(services)
for i in xrange(n):
if versions[i] == 0xffff: continue
print services[i], versions[i]
def on_connect(tag):
print tag
n = 32
for i in xrange(0, 0x10000, n):
check_services(tag, i, n)
def main():
with nfc.ContactlessFrontend('usb') as clf:
clf.connect(rdwr={'on-connect': on_connect})
if __name__ == '__main__':
main()
取りあえず実行してみます。サービスの全列挙には実行には時間がかかりますのでしばらく待ちましょう。
$ python dump_simple.py
Type3Tag 'FeliCa Standard (RC-S915)' ID=xxxxxxxxxxxxxxxx PMM=yyyyyyyyyyyyyyyy SYS=8108
Service Code 0000h (Service 0 Type 000000b) 4097
Service Code 0100h (Service 4 Type 000000b) 4097
...
プログラムを説明します。
nfc.ContactlessFrontend('usb')
で USB 接続の NFC リーダーを開きます。
clf.connect
で NFC リーダーを起動し、NFC タグのタッチ検出を開始します。
connect
の引数で、NFC タグがタッチされたときに呼び出すコールバック関数 on_connect
を指定します。
ドキュメントにはコールバック関数を設定しない(clf.connect(rdwr={})
)場合、NFC タグをタッチするまでブロックするような記述がありますが、実験したところブロックしませんでした。
きちんと on-connect
コールバックを設定する必要があるようです。
NFC タグがタッチされると on_connect
にはそのタグを表すオブジェクト tag
が渡ってきます。
以降、tag
を使って NFC タグと通信し、様々なデータを読み取っていきます。
dump_simple.py プログラムは、タッチした NFC タグが持つすべてのサービスを列挙します。
tag.request_service
にサービスコード(ServiceCode
)を渡すと、タグがそのサービスを持つかどうかを調べられます。
タグが指定したサービスを持つなら 0xffff 以外の値が返ってきます。
サービスコードは 16 ビットの値で、上位 10 ビットがサービス番号、下位 6 ビットが属性値です。
16 ビット値ですから、0 から 0x10000 までを調べればすべてのサービスを網羅できます。
for i in xrange(0, 0x10000, n)
はそういう意味です。
nfc.tag.tt3.ServiceCode(i >> 6, i & 0x3f)
は、16 ビットの整数 i
から ServiceCode
オブジェクトを生成するやり方です。
i >> 6
で上位 10 ビットを取り出します。i & 0x3f
で下位 6 ビットを取り出します。
tag.request_service
は複数のサービスを一度に指定することができます。
実際に check_services
関数では n
個の ServiceCode
のリストを作り、request_service
関数に渡しています。
1 つずつ調べるよりまとめて調べる方が速いので、32 個ずつ調べることにしたのです。
複数の System を扱う
dump_simple.py では System を切り替える処理を入れていなかったため、暗黙的に NFC タグの先頭の System を扱うことになります。 複数の System を持つタグの場合、明示的に扱う System を指定する処理が必要です。
今度は、すべての System を網羅的に調べるように改造した dump_all_systems.py を示します。
import nfc
def check_services(tag, start, n):
services = [nfc.tag.tt3.ServiceCode(i >> 6, i & 0x3f)
for i in xrange(start, start+n)]
versions = tag.request_service(services)
for i in xrange(n):
if versions[i] == 0xffff: continue
print services[i], versions[i]
def check_system(tag, system_code):
idm, pmm = tag.polling(system_code=system_code)
tag.idm, tag.pmm, tag.sys = idm, pmm, system_code
print tag
n = 32
for i in xrange(0, 0x10000, n):
check_services(tag, i, n)
def on_connect(tag):
system_codes = tag.request_system_code()
for s in system_codes:
check_system(tag, s)
def main():
with nfc.ContactlessFrontend('usb') as clf:
clf.connect(rdwr={'on-connect': on_connect})
if __name__ == '__main__':
main()
実行するとこんな感じになります。複数の SYS=
を調べているのが分かりますね。
$ python dump_all_systems.py
Type3Tag 'FeliCa Standard (RC-S915)' ID=xxxxxxxxxxxxxxxx PMM=yyyyyyyyyyyyyyyy SYS=8108
Service Code 0000h (Service 0 Type 000000b) 4097
Service Code 0100h (Service 4 Type 000000b) 4097
...
Type3Tag 'FeliCa Standard (RC-S915)' ID=xxxxxxxxxxxxxxxx PMM=yyyyyyyyyyyyyyyy SYS=FE00
Service Code 1748h (Service 93 Random RW with key) 4097
Service Code 174Bh (Service 93 Random RO w/o key) 5963
...
プログラムの変更のポイントはこんな感じです。
tag.request_system_code
関数で NFC タグが持っている System の一覧を得る- 今まで
on_connect
でやっていた処理をcheck_system
関数に移して、polling
処理を加えた
polling
の処理がミソとなる部分ですので、少し詳しく説明します。
ポーリングは、NFC リーダーが NFC タグを探す処理のことです。 ポーリング時に System Code を指定することで衝突防止を実現しています。 指定したコードと同じコードを持つ NFC タグだけがポーリングに反応することで、複数の NFC タグが探索範囲に存在しても衝突しないようになっています。
さて、tag.polling
関数に System Code を渡すと、そのコードを持つ NFC タグの IDm, PMm を取得できます。
取得した IDm と PMm、それからポーリングに使った System Code を tag.idm
, tag.pmm
, tag.sys
に設定することで、以降のデータ通信をその System に対して行えるようになります。
データブロックの読み込み
NFC タグがもつすべての System とすべてのサービスが分かったので、次はいよいよ任意のサービスが持つデータブロックを読み込んでみます。
dump_block.py
import nfc
from binascii import hexlify
def on_connect(tag):
idm, pmm = tag.polling(system_code=0xfe00)
tag.idm, tag.pmm, tag.sys = idm, pmm, 0xfe00
sc = nfc.tag.tt3.ServiceCode(93, 0x0b) # 174B
bc = nfc.tag.tt3.BlockCode(1, service=0)
data = tag.read_without_encryption([sc], [bc])
print 'str:', data
print 'hex:', hexlify(data)
def main():
with nfc.ContactlessFrontend('usb') as clf:
clf.connect(rdwr={'on-connect': on_connect})
if __name__ == '__main__':
main()
このプログラムはシステム 0xfe00 内のサービス 0x174B が持つブロック 1 のデータを読み込みます。 システムコードとサービスコードは、先ほどの探索で得た値を使っています。
このあたりは read_without_encryption のドキュメント に載っているサンプルを参考にしています。
ドキュメントにもありますが、BlockCode
の生成時に渡す service=0
はサービスコードそのものではなく、read_without_encryption
の引数 service_list
内でのインデックスです。
read_without_encryption([sc1, sc2, ..., scN], [...])
などと N 個のサービスを指定したとき、BlockCode
の service
は 0 から N-1 までの値を取れます。
1 つのサービスは 16 バイトの大きさのブロックを複数個持ち、サービスの中で 0 から連番が付いています。
| Service X |
| ---------|
| | Block 0 |
| ---------|
| | Block 1 |
| ---------|
| | ... |
サービスコードの下位 6 ビットは属性値で、次のようになっています。 この中で、パスワードなしで読み書きできるのは "w/o key" (without key = キーなし)となっているサービスだけです。 例えば 2 つのサービス "1748h" と "174Bh" のうち、読み取れるのは "174Bh" の方だけです。
ビット | 意味 |
---|---|
001000 | Random RW with key |
001001 | Random RW w/o key |
001010 | Random RO with key |
001011 | Random RO w/o key |
001100 | Cyclic RW with key |
001101 | Cyclic RW w/o key |
001110 | Cyclic RO with key |
001111 | Cyclic RO w/o key |
010000 | Purse Direct with key |
010001 | Purse Direct w/o key |
010010 | Purse Cashback with key |
010011 | Purse Cashback w/o key |
010100 | Purse Decrement with key |
010101 | Purse Decrement w/o key |
010110 | Purse Read Only with key |
010111 | Purse Read Only w/o key |
Python で Markdown 文書を HTML へ変換する
python-markdown2, py-gfm, pygments というライブラリを使って Markdown 文書を HTML へ変換するメモです。
GitHub Flavored Markdown (GFM) の特徴である Fenced Code Block にも対応しています。
インストール
$ pip3 install --user python-markdown2 py-gfm pygments pygments-style-github
スクリプト
md2html.py
#!/usr/bin/python3 import sys from textwrap import dedent from markdown2 import markdown CHARSET = 'utf-8' def main(): if len(sys.argv) < 2: print('Usage: md2html path/to/file', file=sys.stderr) sys.exit(1) with open(sys.argv[1], encoding=CHARSET) as f: source = f.read() body = markdown(source, extras=['fenced-code-blocks']) html = dedent('''\ <html> <head> <meta charset="{charset}"> <link rel="stylesheet" type="text/css" href="github_pygments.css"> </head> <body>{body}</body> </html> ''').format(charset=CHARSET, body=body) print(html) if __name__ == '__main__': main()
CSS の準備
$ ~/.local/bin/pygmentize -S github -f html > github_pygments.css
変換
$ ./md2html.py hoge.md > hoge.html
おまけ:ブラウザから確認
手軽にブラウザから確認するには Python で HTTP サーバを立てると便利です。 この程度の静的 HTML なら直接ブラウザで開いてもいいのですが、HTTP サーバを立てればリモート開発している時も便利です。
$ python3 -m http.server 8000
8000 番ポートで起動します。
deb パッケージングメモ - alien 編
Ubuntu で deb パッケージを作ろうとして調べ、実験したメモです。
なぜ自作ツールの deb パッケージを作るのか
開発したソフトウェアを Chef や Ansible などでデプロイするのに、apt-get install できると便利です。 deb にすることで、プログラム本体だけでなく、正しく動かすために必要なもろもろを deb 製作側の責任で作り込むことができます。 依存関係を考慮してくれたり、アップデートやアンインストールが容易なことも魅力です。
自作のプログラムに加え、Oracle Java のように tar.gz または rpm でしか提供されていないものを deb 化したいという需要もあります。
deb 化の方法の選択肢
プログラムを deb 化するに当たって、幾つかのやり方があります。
- alien コマンドを使う
- 正攻法でビルドする
alien
alien は tar.gz や rpm 形式のアーカイブを deb に変換するコマンドです。
tar.gz も rpm も deb も、基本的にはインストールするファイルをまとめて圧縮したものです。 したがって、ビルド済みのプログラムを含むアーカイブなら、簡単に変換できます。 Oracle Java の deb 化にはこの方法が合っていると思われます。
正攻法
dh_make や pdebuild を使い、ソースコードから deb パッケージを生成する方法です。
正攻法を正しく行うには事前の学習がそれなりに必要ですが、ビルド済みアーカイブがなくても良い点や、コンテナを用いたクリーンビルドができる点が優れています。 また、alien ではメタデータを細かく調整できなかったりしますが、正攻法ではその心配はありません。
正攻法はこの記事では扱いません。後日、別記事で書くかもしれません。書かないかもしれません。
alien を使って tar.gz から deb を作る
Oracle Java 8 JDK を例に、ビルド済みバイナリの tar.gz アーカイブを deb に変換する方法を紹介します。
まずはそのまま変換してみる
変換元のアーカイブが jdk-8u73-linux-x64.tar.gz であるとします。まずファイル名を希望するパッケージ名に変えます。
$ mv jdk-8u73-linux-x64.tar.gz oraclejdk8-jdk.tar.gz
Ubuntu のリポジトリにある OpenJDK 7 のパッケージ名は openjdk-7-jdk なので、それに合わせて oraclejdk-8-jdk というように 8 の前にハイフンを入れたくなります。しかし、alien の制約で、数字の前にハイフンがあるとその数字以降が無視されてしまいます。恐らく、バージョン番号だから無視すべきと判断しているのでしょう。したがって、8 の前にはハイフンを入れない名前にしました。
いよいよ deb に変換します。
$ sudo alien -v --version=1.8.0.73 --bump=0 oraclejdk8-jdk.tar.gz
alien コマンドは root ユーザを要求します。sudo または fakeroot とともに実行してください。
出来上がったパッケージのバージョンを指定するのに --version オプションを使います。また、パッケージのリビジョン(debian バージョン)を指定するのに --bump オプションを使います。
--bump は変換元のリビジョンに加算する数値を指定するオプションで、デフォルトでは 1 です。tar.gz にはもともとリビジョン(およびバージョンも)がありませんから、リビジョンとして 1 が指定されているとみなされます。したがって、--bump を指定せずに実行すると oraclejdk8-jdk_1.8.0.73-2_amd64.deb
というファイルが生成されます。
最初のパッケージなのにリビジョンが 2 になるのは気持ち悪いですね。ということで、例では --bump=0 として、リビジョンを増加させないように指示しています。oraclejdk8-jdk パッケージを一度でも外部に出した後、同じバージョンでビルドしなおすときは --bump を増やしましょう。リビジョンを上げておけば、APT の仕組みでアップグレードされるようになります。
alien コマンドがどのような処理をしているかを見たいので -v オプションを付けましたが、これは付けなくても動作は変わりません。
最後に出来上がったパッケージの中身を確認してみます。
$ dpkg -c oraclejdk8-jdk_1.8.0.73-1_amd64.deb | less
パッケージをインストールすると、ここで表示されたパスにファイルが配置されます。すべてのファイルが /jdk-1.8.0_73/
以下に配置されることが分かりました。このパスは通常使われるインストール先ではありません。後ほど、ルートディレクトリを調整する方法を紹介します。
インストールスクリプトを含ませてみる
rpm や deb はインストール前後に実行するスクリプトを含むことができます。スクリプトを使うと例えば、配置したバイナリを update-alternatives に登録したりできます。
これをやるには、一旦アーカイブを展開し、スクリプトを含めた DEBIAN ディレクトリとともに圧縮しなおします。(アーカイブのファイル名は元に戻した前提で話を進めます。)
$ tar xzf jdk-8u73-linux-x64.tar.gz
$ mkdir DEBIAN
$ vim DEBIAN/postinst
$ chmod +x DEBIAN/postinst
postinst はインストールの後処理で呼ばれるスクリプトです。ファイルがすべて配置し終わった後に呼び出されます。 postinst の中身はなんでもいいですが、例えばこんな感じにしてみましょうか。
#!/bin/sh
for f in $(ls /jdk-1.8.0_73/bin/*); do
update-alternatives --install /usr/bin/$f $f /jdk-1.8.0_73/bin/$f 1
done
このスクリプトはインストールされたすべてのコマンドを update-alternatives に登録します。update-alternatives は、/usr/bin/java などをシンボリックリンクにし、実際に指すコマンドを手軽に切り替えられる仕組みです。
$ tar czf oraclejdk8-jdk.tar.gz jdk-1.8.0_73/ DEBIAN/
$ sudo alien -v --version=1.8.0.73 --bump=1 oraclejdk8-jdk.tar.gz
oraclejdk8-jdk_1.8.0.73-2_amd64.deb をインストールしてみると、最後の方で update-alternatives が実行されるのを確認できます。
インストール先を調整してみる
これまでのやり方では、インストール先が /jdk-1.8.0_73
となってあまり綺麗ではありません。標準的には /usr
や /opt
にインストールすることになっていますから、それに従うように調整してみます。
これには、tar で展開するときにオプションを使って調整してしまうのが楽です。
$ mkdir -p opt/oraclejdk8-jdk
$ tar xzf jdk-8u73-linux-x64.tar.gz -C opt/oraclejdk8-jdk --strip-component 1
tar コマンドは -C オプションで展開先を指定できます。さらに --stript-component 1 で先頭から 1 つのパスを削りつつ展開するよう指示しています。これらを組み合わせると opt/oraclejdk8-jdk/bin/java
などに展開できます。
インストール先を変えたので、postinst も変更しておきましょう。ls /jdk-1.8.0_73/bin/*
を ls /opt/oraclejdk8-jdk/bin/*
に変えれば OK です。
あとはアーカイブを作り alien を実行するだけです。
$ tar czf oraclejdk8-jdk.tar.gz opt/ DEBIAN/
$ sudo alien -v --version=1.8.0.73 --bump=2 oraclejdk8-jdk.tar.gz
$ dpkg -c oraclejdk8-jdk_1.8.0.73-3_amd64.deb | less
どうでしょうか。/opt/oraclejdk8-jdk
以下にインストール先を変更できたことが分かるはずです。