秋月で、なんとなく買ってしまった、nanopi。
あまらしとくのも難なので、作業場の音楽環境を、いろいろやらかすネタとして。
使ってみることに、しましたとさ。
#導入前の環境
作業場には、パソコンとモニタ、デジタル入力のアンプと、あとAirmac Expressがあります。
Airmac Express経由で、サーバに入れてあるiTunesを流しています。
モニタはTV的なのを流用しているため、自動電源OFFが無く、パソコンとの電源連動がアレ。
アンプは中華製のやつで、入力切り替えがめんどくさく。
また、隣のまったり系のお部屋まで、デジタル分岐した光回線が伸びてます。
Airplay使わない時にAirmac Expressの電源落としたりしてるのですが、まあめんどくさく!。
Airplayのキックも、スマホのリモコンツール経由だったりしてね。
このへん、どうにかしていきたいな、と。
#ざっくり設計
適当に秋月を眺め、以下の方針でいくことに決定。
###オーディオ切り替え
・SPDIFベース、nanopiはSPDIF出力ありそうだしね
・同軸はめんどくさげなので、光入出力
・スイッチは125あたりで
・隣の部屋送りのため、2系統独立出力、切り替えで
・予備ふくめて、光2系統つけとくべ
###電源回り
・商用電源のスイッチは、SSRで
・通常のリレー、入れるのに電流使うからね
・同じ筐体に一次側入れるのやなので、分離構造で
・途中配線はUSBだのEtherだのは避け、RJ11(モジュラー)で
###UI
・一応ほら、音モノだし、LED+スイッチで
・ノイズ的なアレ?
###I/F
・どうみてもIO足りないので、まあI2Cで増やしますかね
・リモコン使えるようにしたいかな
・配線はパッチケーブルベースでいいべ、めんどいし
###おまけ要素
・どうせだしPC用のUSB DACも入れちゃうべ
#詳細設計、電気編
・LEDは3mmをいくつか
・LEDの電流制限抵抗は、510Ω(緑黄赤)、270Ω(白青)
・パスコンは10uF
・SPDIF入力側の電源用Lは、47uH
・基板は秋月C基板で
・・・で、秋月発注、ざっくりしすぎてて、スイッチを買い忘れる失態ぶりでした。
#naniPiにAirplay喋らせる、基本動作編
まあ、ざっくりと。
###OS
・ArmbianのUbuntuベース、5.35を使用
・最近のだと、SPDIF回りが、いろいろめんどいみたいです
・というか挫折しました
###SPDIF回り
・SPDIF認識のさせざまは、以下URLでなんとかなりました
https://forum.armbian.com/topic/1891-spdif-output-on-nanopi-m1/
・SPDIFが正常に認識されると、以下な感じになりますです
root@nanopineo:~# cat /proc/asound/cards
0 [audiocodec ]: audiocodec - audiocodec
audiocodec
1 [sndhdmi ]: sndhdmi - sndhdmi
sndhdmi
2 [sndspdif ]: sndspdif - sndspdif
sndspdif
###shairport
・perlが絡んでるので、改造とからくそーだし、あえての無印を使いました
・systemdに以下登録して、動かしてます
[Unit]
Description = shairport
[Service]
ExecStart=/data/shairport/shairport.pl -a AirSelect --ao_devicename "default:CARD=sndspdif" --play_prog="/bin/touch /ramdisk/airplay_enable" --stop_prog="/bin/rm /ramdisk/airplay_enable"
Restart=always
Type=simple
[Install]
WantedBy=multi-user.target
・ポイントは以下な感じ
・SPDIF出力は、「--ao_devicename "default:CARD=sndspdif"」でいける
・自動制御用に、airplay動いてるかをハンドリングしたかったんだけど
ファイルの有無で判定することに
キックは、オプションでいける親切設計でした
「--play_prog="/bin/touch /ramdisk/airplay_enable"」
「--stop_prog="/bin/rm /ramdisk/airplay_enable"」
まあ、そゆことです
・これでサービスを有効化しておくと、同じネットワーク上のiTunesに、以下のステキ表示が!
・あ、出ない時は、iTunesのホームシェアリング回りをぐぐってみて下さいな、確かアカウント登録とかいるはず
・shairportはまあ、Sync機能が無いので、それぞれの出力音が混ざる環境だと、エコー的になりますが、離れていれば大丈夫、ぶっちゃけKodiあたりと一緒です動作は
###SPDIF出力回り(電気要素)
・nanoPiは、1列ピンヘッダ側、I2Sの隣が、SPDIF出力です
・3.3VTTL出力っぽい、そのまま光なTOSLINK出力に突っ込めば、光デジタルとして使えますー
#SPDIF切り替え回り
###切り替えデバイス
・切り替えは、74ロジックの3ステートバッファで、まあ「SN74HC125N」を使う感じ
・選定ミスった!、126のほうがいいかもね
・理由は、125はOEが反転動作なので、電源投入時には出力がぶつかっちゃう
・A入力にSPDIF入力を繋ぎ、OEをGPIOで制御、Y出力を4つぶつけて、「4入力1出力」にしました
・それを2回路で、4入力2出力ね
・パスコンは10uFを入れときましたとさ
###入出力
・SPDIF TTL入力2系統
・SPDIF 光入力2系統
・SPDIF 光出力2系統
な、感じで
###基板
・さくっと、作りました、右側ね
・TOSLINKは東芝のが終売状態
・秋月の「ちっこいほう」のは、固定用の足が2.54mmピッチなので、かなり取り回しがラクですよん
#I2cエキスパンダー回り
###デバイス
・秋月に在庫がある、MicrochipのMCP23017を、2コ使用
・アドレスが3bitで選べるので、適当に設定
・データシート確認せずに基板を造るという、恐ろしい行為を行った為、無駄にプルアップ入れてしまった、、、あっはっは
・基板はこんなかんじー
###製作留意点(電気要素)
・パスコンは10uF
・nanoPiは、I2cプルアップが入ってないので、この基板で(1k)
・ロジック入力側は、1kのバッファ抵抗を
・ロジック出力側は、1kのプルアップ/ダウンを
・LED駆動は、電流制限として、270Ωと510Ω入れてます
・このIC、中身はマイコンらしく、起動に多少時間がかかります、数秒
・リセットピンは1kプルアップしてあげないと、動作不安定です
###nanoPi側からの認識
・ま、さくっと
root@nanopineo:~# i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- 22 23 -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
root@nanopineo:~#
・どうして「22」と「23」なのか、よーわかってない適当さw
・まあ、てきとーに、アドレスピンをいじってます
#リモコン回り
###リモコンの選定
・まあ、Apple Remoteでいいかと
・中古を大人買いしたあと、自宅からも発掘されるというダメっぷりですが
###lirc設定
・まず、WiringNPをセットアップ
git clone https://github.com/friendlyarm/WiringNP
cd WiringNP/
chmod 755 build
./build
・このままだと動かないので、WiringNPの以下を変更
$HOME/WiringNP/wiringPi/boardtype_friendlyelec.c
//allwinner h3
// kernel 3.x
の、該当部分以外をコメントアウト、該当部分を「-1(-1)」にする
参考:「/sys/class/sunxi_info/sys_info」の 「sunxi_board_id」
このへんは、以下URLを参考にしました。
http://nopnop2002.webcrow.jp/NanoPi-M1/NanoPi-M1-2.html
これでリブートすると、sunxiのcirが生きてくるので、lircが使えるようになります。
OrangePi用ですが、以下URLで!
https://forum.armbian.com/topic/1953-configuring-orange-pi-pc-to-receive-irinfrared/
###Apple Remote回り
・Apple Remote、デバイスIDとかも送ってるみたいで、なかなかうまく学習してくれません
・以下URLから、設定貰ってきました
http://lirc.sourceforge.net/remotes/apple/A1156
###リモコンによる、コマンドキック
・irexecを使います
・/etc/lirc/lircrc というファイルに、定義を書けばOKみたい
begin
prog = irexec
button = KEY_PLAY
repeat = 2
config = /data/airplay_control/control.pl playpause
flags = quit
end
begin
prog = irexec
button = KEY_KPPLUS
repeat = 2
config = /data/airplay_control/control.pl volup
flags = quit
end
begin
prog = irexec
button = KEY_FASTFORWARD
repeat = 2
config = /data/airplay_control/control.pl next
flags = quit
end
begin
prog = irexec
button = KEY_REWIND
repeat = 2
config = /data/airplay_control/control.pl prev
flags = quit
end
begin
prog = irexec
button = KEY_KPMINUS
repeat = 2
config = /data/airplay_control/control.pl voldown
flags = quit
end
begin
prog = irexec
button = KEY_MENU
repeat = 2
config = /data/airplay_control/control.pl shuffle
flags = quit
end
・で、systemdに登録、キック、テスト動作は単純に「irexec」を実行でOK
[Unit]
Description = irexec
[Service]
ExecStart=/usr/bin/irexec
Restart=always
Type=simple
[Install]
WantedBy=multi-user.target
#aiplayによるiTunesのコントロール
・iTunesは、「DACP」という手順で、コントロールできます
https://ja.wikipedia.org/wiki/Digital_Audio_Control_Protocol
・まあざっくり、httpで特定のポートにアクセス、リクエスト投げるだけ
・が、認証キーを一緒に送らないと、だめみたいです
・認証キーは、shairportに送られてるので、それ取り出します
・shairport.pl内の、「conn_handle_request」の中のやりとりで、サーバ応答があるので
・そこにトラップを仕掛けます、こんなかんじ
sub conn_handle_request {
my ($fh, $conn) = @_;
my $req = $conn->{req};;
my $clen = $req->header('content-length') // 0;
if ($clen > 0 && !length($req->content)) {
$conn->{req_need} = $clen;
return; # need more!
}
my $resp = HTTP::Response->new(200);
$resp->request($req);
$resp->protocol($req->protocol);
#get Active-remote
my $remoteid = $req->header('Active-Remote');
if ($remoteid ne ""){
open (OUTPUTREMOTE,">/ramdisk/airplay_activeremote");
print OUTPUTREMOTE $remoteid;
close (OUTPUTREMOTE);
}
$resp->header('CSeq', $req->header('CSeq'));
$resp->header('Audio-Jack-Status', 'connected; type=analog');
・取り出したキーを使って、コントローラを適当に書いてみます
#!/usr/bin/perl
use Socket;
$activeremotefile = "/ramdisk/airplay_activeremote";
open (FILE,$activeremotefile);
($activeremotekey) = (<FILE>);
close (FILE);
$command = $ARGV[0];
$socket_port = 3689;
$hostname = "192.168.0.221";
$url = "/ctrl-int/1/" . $command;
$addr = inet_aton("$hostname");
socket(S, PF_INET, SOCK_STREAM, 0);
my $socket_name = pack_sockaddr_in($socket_port, $addr);
connect(S, $socket_name);
binmode(S);
select(S);
$|=1;
select(stdout);
print S "GET ".$url." HTTP/1.0\r\nHost: $hostname\r\n";
print S "Active-Remote: $activeremotekey\r\n\r\n";
while (<S>) {
print $_;
}
close (S);
・IPはiTunes動いてるPCのに書き換えてね、と
・コマンドは、以下資料が参考になるかと
https://nto.github.io/AirPlay.html
・但し!、この資料古いらしく、使えないコマンドとか、ちらほらあります
・そこでiTunesを適当にハック、いまんとここんな感じみたい(iTunes12系列)
コマンド | 内容 |
---|---|
beginff | begin fast forward |
beginrew | begin rewind |
mutetoggle | toggle mute status |
nextitem | play next item in playlist |
previtem | play previous item in playlist |
pause | pause playback |
playpause | toggle between play and pause |
play | start playback |
stop | stop playback |
playresume | play after fast forward or rewind |
volumedown | turn audio volume down |
volumeup | turn audio volume up |
prevgroup | 前のグループへ |
nextgroup | 次のグループへ |
restartitem | 再生中のアイテムを、頭から |
increment | 謎 |
playspec | 謎 |
cue | 謎だけどまあ、cue的な要素? |
repeatadv | リピート設定のトグル |
beginrew | restartitemと同一動作? |
nextcontainer | 次コンテナ |
prevchapter | 前チャプタ |
shuffletoggle | シャッフルのトグル |
prevcontainer | 前コンテナ |
discrete-pause | 謎 |
nextchapter | 次チャプタ |
controlpromptentry | 謎 |
・ちなみに、使えるコマンドは206が、無いコマンドは400が、dacp以外でパラメータとか渡さないとダメ系コマンドは501が帰ってくるみたいです
・先のリモコンと合わせて、無事リモコン操作ができるよーになりました、とさ
#箱の作成
・ま、アクリルで適当に
・一家に一台、レーザー加工機、べんりよー、30分作業だし!
#自動制御
・ま、やるきなく、スクリプトからコマンド呼び出しで、ごまかしてます
・自動切り替えとかべんりべんり
#!/usr/bin/perl
use Time::HiRes;
$tempdir = "/ramdisk";
&i2cinit;
while(){
&polling;
}
exit;
sub polling {
#detect
my $statusrawdata = &i2cget("0x22","0x12");
$statusrawdata = substr($statusrawdata,2,2);
$statusrawdata = unpack("B8", pack("H2", $statusrawdata ));
my $detectbutton = &buttondetect($statusrawdata);
my $detectpower = &powerdetect($statusrawdata);
my $detectairplay = &loadstatus("airplay_enable");
#load autostatus
my $autostatustime = &loadstatus("select_autostatustime","time");
#load status
my $statuspower1 = &loadstatus("power1_status","data");
my $statuspower2 = &loadstatus("power2_status","data");
my $statusaudio1 = &loadstatus("audio1_status","data");
my $statusaudio2 = &loadstatus("audio2_status","data");
#set default
if ($statuspower1 eq "0"){$statuspower1 = "off";}
if ($statuspower2 eq "0"){$statuspower2 = "off";}
if ($statusaudio1 eq "0"){$statusaudio1 = "disable";}
if ($statusaudio2 eq "0"){$statusaudio2 = "disable";}
#heartbeat
my $statusheartbeat = &loadstatus("airswitch_heartbeat","data");
my $statusheartbeattime = &loadstatus("airswitch_heartbeat","time");
if ($statusheartbeat eq "0"){
$statusheartbeattime = 100;
}
if ($statusheartbeattime > 10){
if ($statusheartbeat eq "on"){
$statusheartbeat = "off";
}
else {
$statusheartbeat = "on";
}
&updatestatusdata("airswitch_heartbeat",$statusheartbeat);
}
#autostatusupdate detect
my $autostatusupdateflag = 0;
if (($autostatustime > 7200)||($autostatustime == 0)){
if ($detectbutton eq "off"){
$autostatusupdateflag = 1;
}
}
#autostatusupdate exec
if ($autostatusupdateflag == 1){
&updatestatus("select_autostatustime","0");
$statusaudio1 = "disable";
$statusaudio2 = "disable";
$statuspower1 = "off";
$statuspower2 = "off";
if ($detectpower eq "on"){
$statusaudio1 = "spdif2";
$statusaudio2 = "spdif2";
$statuspower1 = "on";
$statuspower2 = "on";
}
if ($detectairplay eq "1"){
$statusaudio1 = "airplay";
$statusaudio2 = "airplay";
$statuspower2 = "on";
}
}
#manualstatusupdate exec
else {
if ($detectbutton eq "power1"){
if ($statuspower1 eq "on") { $statuspower1 = "off"; }
elsif ($statuspower1 eq "off") { $statuspower1 = "on"; }
}
if ($detectbutton eq "power2"){
if ($statuspower2 eq "on") { $statuspower2 = "off"; }
elsif ($statuspower2 eq "off") { $statuspower2 = "on"; }
}
if ($detectbutton eq "audio1"){
if ($statusaudio1 eq "disable") { $statusaudio1 = "airplay"; }
elsif ($statusaudio1 eq "airplay") { $statusaudio1 = "pc"; }
elsif ($statusaudio1 eq "pc") { $statusaudio1 = "spdif1"; }
elsif ($statusaudio1 eq "spdif1") { $statusaudio1 = "spdif2"; }
elsif ($statusaudio1 eq "spdif2") { $statusaudio1 = "disable"; }
}
if ($detectbutton eq "audio2"){
if ($statusaudio2 eq "disable") { $statusaudio2 = "airplay"; }
elsif ($statusaudio2 eq "airplay") { $statusaudio2 = "pc"; }
elsif ($statusaudio2 eq "pc") { $statusaudio2 = "spdif1"; }
elsif ($statusaudio2 eq "spdif1") { $statusaudio2 = "spdif2"; }
elsif ($statusaudio2 eq "spdif2") { $statusaudio2 = "disable"; }
}
if ($detectbutton ne "off"){
&updatestatus("select_autostatustime","2");
}
}
#update status
&updatestatusdata("power1_status",$statuspower1);
&updatestatusdata("power2_status",$statuspower2);
&updatestatusdata("audio1_status",$statusaudio1);
&updatestatusdata("audio2_status",$statusaudio2);
#update led status
# bit0 : O : POWER AUTO 1 (use power1 on/off)
# bit1 : O : POWER ON 1 (use detect airplay)
# bit2 : O : POWER AUTO 2 (use poser2 on/off)
# bit3 : O : POWER ON 2 (use detect pc)
# bit4 : O : POWER DETECT AIRPLAY (use automode)
# bit5 : O : POWER DETECT PC (heartbeat)
# bit6 : O : UNUSED
# bit7 : O : UNUSED
# bit8 : O : AUDIO TOSLINK1 1
# bit9 : O : AUDIO AIRPLAY 1
# bitA : O : AUDIO PCUSB 1
# bitB : O : AUDIO TOSLINK2 1
# bitC : O : AUDIO TOSLINK1 2
# bitD : O : AUDIO TOSLINK2 2
# bitE : O : AUDIO AIRPLAY 2
# bitF : O : AUDIO PCUSB 2
my (@ledarray);
for (0..15){
$ledarray[$_] = "0";
}
if ($statuspower1 eq "on") {$ledarray[0] = "1";}
if ($detectairplay eq "1") {$ledarray[1] = "1";}
if ($statuspower2 eq "on") {$ledarray[2] = "1";}
if ($detectpower eq "on") {$ledarray[3] = "1";}
if ($autostatusupdateflag eq "1"){$ledarray[4] = "1";}
if ($statusheartbeat eq "on") {$ledarray[5] = "1";}
if ($statusaudio1 eq "spdif1") {$ledarray[8] = "1";}
if ($statusaudio1 eq "airplay") {$ledarray[9] = "1";}
if ($statusaudio1 eq "pc") {$ledarray[10] = "1";}
if ($statusaudio1 eq "spdif2") {$ledarray[11] = "1";}
if ($statusaudio2 eq "spdif1") {$ledarray[12] = "1";}
if ($statusaudio2 eq "spdif2") {$ledarray[13] = "1";}
if ($statusaudio2 eq "airplay") {$ledarray[14] = "1";}
if ($statusaudio2 eq "pc") {$ledarray[15] = "1";}
my $setstatus = unpack("H2", pack("B8","$ledarray[0]$ledarray[1]$ledarray[2]$ledarray[3]$ledarray[4]$ledarray[5]$ledarray[6]$ledarray[7]"));
$setstatus = uc($setstatus);
&i2cset("0x23","0x14","0x".$setstatus);
$setstatus = unpack("H2", pack("B8","$ledarray[8]$ledarray[9]$ledarray[10]$ledarray[11]$ledarray[12]$ledarray[13]$ledarray[14]$ledarray[15]"));
$setstatus = uc($setstatus);
&i2cset("0x23","0x15","0x".$setstatus);
#update audioselector status
my $setstatusaudio1 = "1111";
my $setstatusaudio2 = "1111";
if ($statusaudio1 eq "airplay") {$setstatusaudio1 = "1101";}
if ($statusaudio1 eq "pc") {$setstatusaudio1 = "1110";}
if ($statusaudio1 eq "spdif1") {$setstatusaudio1 = "0111";}
if ($statusaudio1 eq "spdif2") {$setstatusaudio1 = "1011";}
if ($statusaudio2 eq "airplay") {$setstatusaudio2 = "1101";}
if ($statusaudio2 eq "pc") {$setstatusaudio2 = "1110";}
if ($statusaudio2 eq "spdif1") {$setstatusaudio2 = "0111";}
if ($statusaudio2 eq "spdif2") {$setstatusaudio2 = "1011";}
if ($statusaudio1 eq "disable") {
if ($detectairplay eq "0") {
$setstatusaudio1 = "1101";
}
}
if ($statusaudio2 eq "disable") {
if ($detectairplay eq "0") {
$setstatusaudio2 = "1101";
}
}
$setstatus = unpack("H2", pack("B8","$setstatusaudio1$setstatusaudio2"));
$setstatus = uc($setstatus);
&i2cset("0x22","0x15","0x".$setstatus);
#update power status
$setstatus = "0x00";
if (($statuspower1 eq "on")&&($statuspower2 eq "on")){
$setstatus = "0xC0";
}
elsif ($statuspower1 eq "on"){
$setstatus = "0x80";
}
elsif ($statuspower2 eq "on"){
$setstatus = "0x40";
}
&i2cset("0x22","0x14",$setstatus);
}
sub buttondetect {
my $rawdata = $_[0];
$rawdata = substr($rawdata,4,4);
my $filename = $tempdir . "/button_used";
if (-e $filename){
if ($rawdata eq "0000"){
unlink ($filename);
}
return ("off");
}
if ($rawdata ne "0000"){
open (STATUSFILE,">$filename");
print STATUSFILE ".";
close (FILE);
}
if ($rawdata eq "0001"){ return ("power2");}
if ($rawdata eq "0010"){ return ("power1");}
if ($rawdata eq "0100"){ return ("audio2");}
if ($rawdata eq "1000"){ return ("audio1");}
return ("off");
}
sub powerdetect {
my $rawdata = $_[0];
$rawdata = substr($rawdata,2,1);
if ($rawdata eq "1"){
&updatestatus("power_detect",1);
return ("on");
}
return ("off");
}
sub loadstatus {
my $filename = $tempdir . "/" . $_[0];
if (-e $filename){
if ($_[1] eq "data"){
open (STATUSFILE,$filename);
my ($filedata) = (<STATUSFILE>);
close (FILE);
return ($filedata);
}
if ($_[1] eq "time") {
my $modtime = (stat($filename))[9];
$modtime = abs ($modtime - time);
return ($modtime);
}
return (1);
}
return (0);
}
sub updatestatus {
my $filename = $tempdir . "/" . $_[0];
if ($_[1] eq "1"){
if (!-e $filename){
open (STATUSFILE,">$filename");
print STATUSFILE ".";
close (STATUSFILE);
}
return;
}
if ($_[1] eq "2"){
open (STATUSFILE,">$filename");
print STATUSFILE ".";
close (STATUSFILE);
return;
}
if ($_[1] eq "0"){
if (-e $filename){
unlink ($filename);
}
return;
}
}
sub updatestatusdata {
my $filename = $tempdir . "/" . $_[0];
my $prevstatus = &loadstatus($_[0],"data");
if ($_[1] ne $prevstatus){
open (STATUSFILE,">$filename");
print STATUSFILE $_[1];
close (STATUSFILE);
}
}
sub i2cinit {
&i2cset("0x22","0x00","0x2F");
&i2cset("0x22","0x0c","0x00");
&i2cset("0x22","0x01","0x00");
&i2cset("0x22","0x0d","0x00");
&i2cset("0x23","0x00","0x00");
&i2cset("0x23","0x01","0x00");
&i2cset("0x23","0x0c","0x00");
&i2cset("0x23","0x0d","0x00");
&i2cset("0x23","0x14","0xFF");
&i2cset("0x23","0x15","0xFF");
&i2cset("0x22","0x14","0x00");
&i2cset("0x22","0x15","0xFF");
# sleep (3);
&i2cset("0x23","0x14","0x00");
&i2cset("0x23","0x15","0x00");
}
sub i2cset {
my $i2caddress = $_[0];
my $memaddress = $_[1];
my $memsetdata = $_[2];
my $systemcommand = "/usr/sbin/i2cset -y 0 " . $i2caddress . " " . $memaddress . " " .$memsetdata;
system ($systemcommand);
Time::HiRes::sleep(0.2);
}
sub i2cget {
my $i2caddress = $_[0];
my $memaddress = $_[1];
my $systemcommand = "/usr/sbin/i2cget -y 0 " . $i2caddress . " " . $memaddress;
my $result = `$systemcommand`;
Time::HiRes::sleep(0.2);
return ($result);
}
・で、systemdに登録して、完了