[menu]
[必要なもの]
[ここでの前提]
USB HDD は、ブートパーティーションとルートパーティーションの2つのパーティーションを作成して使う場合の記述をする。もっとパーティーションを作成したい場合は好みで変える
[手順]
主に以下を参考にする。
(a) https://denor.jp/raspberry-pi-4%E3%81%A7usb%E6%8E%A5%E7%B6%9Ahdd%E3%81%8B%E3%82%8964%E3%83%93%E3%83%83%E3%83%88ubuntu-20-04-1%E3%82%92%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%A6%E3%81%BF%E3%81%BE%E3%81%97%E3%81%9F
(b) https://www.raspberrypi.org/forums/viewtopic.php?t=278791
を行う。ブートローダーの更新では、
/lib/firmware/raspberrypi/bootloader/critical/pieeprom-2020-09-03.binをファイル指定して書き込めばブートローダーのオプションも書き換える必要のないものが設定される。(critical のものも stable のものも同じ)
  https://qiita.com/mt08/items/9799bb7ae760011832dc#%E3%81%9D%E3%81%AE%E4%BB%96 ここの情報を見るかぎり、critical のものが最も安定してるものだと思われる。beta, stable, critical のディレクトリの中身を見れば察しが付く。
  以上で rasberry pi os の役目は終了。
$ sudo apt update $ sudo apt upgrade
$ sudo parted -l
$ sudo fdisk -l /dev/mmcblk0
$ sudo parted /dev/sda # parted の対話モードに入る mklabel gpt mkpart primary fat32 2048s 526335s mkpart primary ext4 526336s -1s p q
$ sudo fdisk -l /dev/sda # /dev/sda1 と /dev/sda2 が作成されてるのを確認 $ sudo mkfs.vfat -F 32 -n system-boot /dev/sda1 # boot パーティーションを fat32 でフォーマット。ボリュームラベルは system-boot。ワーニングは無視する $ sudo mkfs.ext4 -L writable /dev/sda2 # root パーティーションを ext4 でフォーマット。ボリュームラベルは writable
$ sudo fatlabel /dev/sda1 # system-boot かどうか。細かいメッセージは気にしない $ sudo e2label /dev/sda2 # writable かどうか
$ cd $ mkdir sd_org sd_new # マウント用のディレクトリを作る
$ sudo mount /dev/mmcblk0p1 sd_org # sd_org にコピー元をマウント $ sudo mount /dev/sda1 sd_new # sd_new にコピー先をマウント $ sudo rsync -aHAXxSvP --numeric-ids sd_org/ sd_new/ # コピーを実行する $ sudo umount sd_org # アンマウントしておく $ sudo umount sd_new
$ sudo mount /dev/mmcblk0p2 sd_org $ sudo mount /dev/sda2 sd_new $ sudo rsync -aHAXxSvP --numeric-ids sd_org/ sd_new/ $ sudo umount sd_org $ sudo umount sd_new
$ sudo su - # めんどくさいのでスーパーユーザーになる # mount /dev/sda1 /media # boot パーティーションを適当なところにマウントする # cd /media # zcat vmlinuz > vmlinux # カーネルの展開 # nano config.txt # vi なり nano なり、エディタで config.txt を開く # condig.txt の [pi4] エントリを以下のように書き換えてセーブする [pi4] #kernel=uboot_rpi_4.bin max_framebuffers=2 dtoverlay=vc4-fkms-v3d boot_delay kernel=vmlinux initramfs initrd.img followkernel
# pwd # /media にいるかどうか確認 # cat > auto_decompress_kernel # スクリプト作成。以下をコピペして ^d を押す。 #!/bin/bash -e #Set Variables BTPATH=/boot/firmware CKPATH=$BTPATH/vmlinuz DKPATH=$BTPATH/vmlinux #Check if compression needs to be done. if [ -e $BTPATH/check.md5 ]; then if md5sum --status --ignore-missing -c $BTPATH/check.md5; then echo -e "\e[32mFiles have not changed, Decompression not needed\e[0m" exit 0 else echo -e "\e[31mHash failed, kernel will be compressed\e[0m" fi fi #Backup the old decompressed kernel mv $DKPATH $DKPATH.bak if [ ! $? == 0 ]; then echo -e "\e[31mDECOMPRESSED KERNEL BACKUP FAILED!\e[0m" exit 1 else echo -e "\e[32mDecompressed kernel backup was successful\e[0m" fi #Decompress the new kernel echo "Decompressing kernel: "$CKPATH".............." zcat $CKPATH > $DKPATH if [ ! $? == 0 ]; then echo -e "\e[31mKERNEL FAILED TO DECOMPRESS!\e[0m" exit 1 else echo -e "\e[32mKernel Decompressed Succesfully\e[0m" fi #Hash the new kernel for checking md5sum $CKPATH $DKPATH > $BTPATH/check.md5 if [ ! $? == 0 ]; then echo -e "\e[31mMD5 GENERATION FAILED!\e[0m" else echo -e "\e[32mMD5 generated Succesfully\e[0m" fi #Exit exit 0
# cd
# umount /media
# mount /dev/sda2 /media # 今度は root パーティーションをいじる
# cd /media/etc/apt/apt.conf.d/
# cat > zz_decompress_rpi_kernel  # スクリプト作成。以下をコピペして ^d を押す。
DPkg::Post-Invoke {"/bin/bash /boot/firmware/auto_decompress_kernel"; };
# logout $ sync $ sudo shutdown now # このあと microSD を抜いて USB HDD で起動する
[注意]
行程を思い出しながらメモしているので抜けがあるかも
[手順]
主に以下を参考にする。
(a) https://www.willusher.io/general/2020/11/15/hw-accel-encoding-rpi4
(b) https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu
$ sudo apt build-dep ffmpeg
エラーになるときは、sources.list を編集してコメントアウトされてる部分を有効にする
$ sudo vi /etc/apt/sources.list :%s/# deb-src/deb-src/ :wq
編集したあと、apt update してから再度インストールする
$ sudo apt update $ sudo apt build-dep ffmpeg
$ git clone --depth 1 --branch release/4.3 https://github.com/FFmpeg/FFmpeg.git
$ ./configure --prefix=$HOME/ffmpeg --pkg-config-flags="--static" --bindir=$HOME/bin --extra-cflags="-I$HOME/ffmpeg/include" --extra-ldflags="-L$HOME/ffmpeg/lib" --extra-libs="-lpthread -lm" --disable-debug --enable-gpl --enable-nonfree --arch=aarch64 --enable-libaom --enable-libass --enable-libfdk-aac --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libwebp --enable-libdrm
実行時に hogehoge ライブラリでエラーが出た場合、(b) のサイトを参考にインストールを行う(以下は例)2つくらいやった気がする。
$ sudo apt-get install hogehoge-dev
$ make install
$ ffmpeg -codecs | grep h264 $ ffmpeg -i test.ts -c:v h264_v4l2m2m -b:v 8000k test.mp4
問題は一つあって、出力 1080p で yadif のフィルターをかけると画像がおかしくなる。720p なら大丈夫。バグかな?
# ソースが地上波 1920x1080 のとき、 $ ffmpeg -i test.ts -c:v h264_v4l2m2m -b:v 8000k -vf yadif test.mp4 # 画像がおかしくなる $ ffmpeg -i test.ts -c:v h264_v4l2m2m -b:v 3000k -vf yadif,scale=-2:720 test.mp4 # 大丈夫
 
 
 
 
Revision 1.1
 

 
 
revision 1.1/1.0 共通接続図

RTC board のピンフレームを右手に置いて、ピンフレームの上端が raspberry pi のピンヘッダの 1, 2番に来るように挿す
RTC board Rev1.1 を USB で接続して制御するための python スクリプトを以下のサイトで公開している。windows10、python 3.9.2 で動作確認をしている。また、ラズパイで動くサービスもあわせて公開している。Ubuntu Server 20.04.2 LTS 64bit で動作確認をしている。
https://github.com/nekokomaru/hidctrl
rtc は入手性の良さ、実装部品の少なさ、インターフェイスの使いやすさ、linux のドライバサポートを考慮し、nxp の PCF2129 を使う。秋月電子 (https://akizukidenshi.com/) の I-09097。
インターフェイスは I2C を選ぶ。ただし、後述の理由から raspberry pi の i2c6 バスを使用する。
raspberry pi の起動には、GPIO 3 を使う。run ヘッダを使用する方法もあるが、アーマーケースを使っていると利用できないのでピンヘッダに出ている GPIO から選んだ。
ここで問題が一つあり、raspberry pi の代表的 I2C インターフェイス(4B の場合は i2c1)は GPIO3 を使用するので、重複してしまって良くない。なので、他の GPIO を使う i2c6 インターフェイスを利用する。
pcf2129 のデータシートを参考に、raspberry pi と pcf2129 を接続する。i2c モードとして接続すること。
 
ここでは、330Ω抵抗を200Ωに、6.8uF コンデンサを 10uF にしている。電池をつないでいないときは VBAT は GND 接続とあるが、そうするとドライバーがうるさいので、ここでは VDD に接続している。raspberry pi の GPIO 22 を pcf2129 の SDA に、GPIO 23 を SCL に接続する。i2c バスは 4.7kΩでプルアップしている。pcf2129 の INT# は GPIO 3 に接続する。GPIO 3 は内部プルアップされているので繋げるだけでいい。
raspberrypi os の /boot/overlays/README を参考にする。(残念ながら ubuntu には用意されてない)
まず i2c6 を有効にするために、以下の記述が必要となる。
dtoverlay=i2c6,pins_22_23,baudrate=400000
さらに、i2c-rtc を追記すれば pcf2129 がデバイスツリーに追加され、ドライバが自動的にロードされるはずである。
dtoverlay=i2c-rtc,pcf2129,wakeup-source,addr=0x51
しかしこれはうまく行かない。/boot/firmware/overlays/i2c-rtc.dtbo には i2c_arm (4B の場合は i2c1) 以下に pcf2129 を始めとする rtc が接続しているデバイスツリーが記述されているためである。
これを解決するため、i2c-rtc.dtbo をバイナリエディタで開き、i2c_arm の文字列を i2c6 で置換する。これを i2c6-rtc.dtbo としてセーブする。(本来は、i2c-rtc.dtbo を dts に変換して記述を修正し、再度 dtb に再構成するべき)
以上を踏まえ、/boot/firmware/overlays/i2c6-rtc.dtbo を作成した上で、/boot/firmware/usercfg.txt に以下を追記する。
dtoverlay=i2c6,pins_22_23,baudrate=400000 dtoverlay=i2c6-rtc,pcf2129,wakeup-source,addr=0x51
再起動すると i2c6 にデバイスが接続されて、ドライバがロードされている様子が確認できる。
$ sudo apt install i2c-tools # i2c ツールのインストール $ sudo i2cdetect -y 6 # 接続状況の確認 $ ls /dev/rtc* # rtc デバイスが表示される
i2cdetect を実行すると、マトリックスの 0x51 の部分が UU と表示されているのがわかる。UU はドライバーが適用されている状態。i2c デバイスとして認識してはいるがドライバーが適用されてないときは、51 というように slave address が表示される。UU として表示されているのであれば、rtc が利用できる。
$ sudo hwclock -w # システムクロック時間をハードウエアクロック(rtc)に書き込む $ sudo hwclock -r # rtc 時間を読み出して表示する
しかし、alarm 機能は使えない。
$ sudo rtcwake --date +5min -m off # 5分後に起動を指定して電源off する… でもエラーが返る $ cat /proc/driver/rtc # rtc の日時は表示される。しかしそれだけである $ ls /sys/class/rtc/rtc0/ # wakeなんちゃら〜というデバイスは存在しない
ubuntu のソースで、pcf2129 のドライバー(drivers/rtc/rtc-pcf2127.c)を眺めてみると、alarm レジスタへのアクセス記述が一切無いのがわかる。raspberrypi os 5.4 のドライバーでも同様で、現在のバージョンのドライバーでは pcf2129 を使った wakeup は出来ないことがわかる。
将来的なドライバのアップデートを期待する。
$ git clone http://github.com/raspberrypi/linux/ -b rpi-5.11.y # ~/rasp5.11 以下にクローンした
$ cp ../rasp5.11/linux/drivers/rtc/rtc-pcf2127.c .
Makefile
----------------
CFILES = rtc-pcf2127.c
obj-m += rtc-pcf2127-11.o
rtc-pcf2127-11-objs := $(CFILES:.c=.o)
ccflags-y += -std=gnu99 -Wall -Wno-declaration-after-statement
all:
        make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
----------------
$ cp ../rasp5.11/linux/include/uapi/linux/rtc.h . # この rtc.h の中の以下の2行を rtc-pcf2127.c に追記する
# > 印は追記の印 # < 印は削除の印 26a27,29 > #define RTC_VL_BACKUP_LOW _BITUL(1) /* Backup voltage is low */ > #define RTC_VL_BACKUP_SWITCH _BITUL(4) /* Backup switchover happened */ >
612c615,616 < ret = devm_rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg); --- > //!!ret = devm_rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg); > ret = rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg); 686c690,691 < return devm_rtc_register_device(pcf2127->rtc); --- > //!!return devm_rtc_register_device(pcf2127->rtc); > return rtc_register_device(pcf2127->rtc);
803,805c808,810
<       { "pcf2127", 1 },
<       { "pcf2129", 0 },
<       { "pca2129", 0 },
---
>       { "pcf2127_11", 1 },
>       { "pcf2129_11", 0 },
>       { "pca2129_11", 0 },
812c817
<               .name   = "rtc-pcf2127-i2c",
---
>               .name   = "rtc-pcf2127-i2c-11",
870,872c875,877
<       { "pcf2127", 1 },
<       { "pcf2129", 0 },
<       { "pca2129", 0 },
---
>       { "pcf2127_11", 1 },
>       { "pcf2129_11", 0 },
>       { "pca2129_11", 0 },
879c884
<               .name   = "rtc-pcf2127-spi",
---
>               .name   = "rtc-pcf2127-spi-11",
92a96,98
> static int alarm_en = 0;
> module_param(alarm_en, int, S_IRUGO);
>
599c605,606
<       if (alarm_irq > 0 || device_property_read_bool(dev, "wakeup-source")) {
---
>       //!!if (alarm_irq > 0 || device_property_read_bool(dev, "wakeup-source")) {
>       if (alarm_irq > 0 || device_property_read_bool(dev, "wakeup-source") || (alarm_en != 0)) {
$ diff ../rasp5.11/linux/drivers/rtc/rtc-pcf2127.c rtc-pcf2127.c   # オリジナルからの差分出力
26a27,29
> #define RTC_VL_BACKUP_LOW       _BITUL(1) /* Backup voltage is low */
> #define RTC_VL_BACKUP_SWITCH    _BITUL(4) /* Backup switchover happened */
> 
92a96,98
> static int alarm_en = 0;
> module_param(alarm_en, int, S_IRUGO);
> 
599c605,606
< 	if (alarm_irq > 0 || device_property_read_bool(dev, "wakeup-source")) {
---
> 	//!!if (alarm_irq > 0 || device_property_read_bool(dev, "wakeup-source")) {
> 	if (alarm_irq > 0 || device_property_read_bool(dev, "wakeup-source") || (alarm_en != 0)) {
612c619,620
< 		ret = devm_rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg);
---
> 		//!!ret = devm_rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg);
> 		ret = rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg);
686c694,695
< 	return devm_rtc_register_device(pcf2127->rtc);
---
> 	//!!return devm_rtc_register_device(pcf2127->rtc);
> 	return rtc_register_device(pcf2127->rtc);
803,805c812,814
< 	{ "pcf2127", 1 },
< 	{ "pcf2129", 0 },
< 	{ "pca2129", 0 },
---
> 	{ "pcf2127_11", 1 },
> 	{ "pcf2129_11", 0 },
> 	{ "pca2129_11", 0 },
812c821
< 		.name	= "rtc-pcf2127-i2c",
---
> 		.name	= "rtc-pcf2127-i2c-11",
870,872c879,881
< 	{ "pcf2127", 1 },
< 	{ "pcf2129", 0 },
< 	{ "pca2129", 0 },
---
> 	{ "pcf2127_11", 1 },
> 	{ "pcf2129_11", 0 },
> 	{ "pca2129_11", 0 },
879c888
< 		.name	= "rtc-pcf2127-spi",
---
> 		.name	= "rtc-pcf2127-spi-11",
$ make # rtc-pcf2127-11.ko が作成される
$ sudo insmod rtc-pcf2127-11.ko alarm_en=1 # パラメータを与えて、ドライバをインストール $ sudo bash -c 'echo pcf2129_11 0x51 > /sys/bus/i2c/devices/i2c-6/new_device' # i2c-6 上、slave address 0x51 のデバイスに識別子 pcf2129_11 でドライバーを適用させる $ sudo i2cdetect -y 6 # ドライバが適用されているのがわかる
$ sudo hwclock -w # システム時間を rtc に書き込む $ sudo hwclock -r # rtc 時間を読み出して表示する $ cat /proc/driver/rtc # alarm 時間や alarm_IRQ(アラームするか否か)などが表示される。 $ ls /sys/class/rtc/rtc0/ # wakeup2 や wakealarm のデバイスが存在するのがわかる
$ sudo sh -c "echo 0 > /sys/class/rtc/rtc0/wakealarm" # アラームクリア $ sudo sh -c "echo `date '+%s' -d '+ 2 minutes'` > /sys/class/rtc/rtc0/wakealarm" # 2分後にパワーオンするように alarm 時刻セット $ cat /sys/class/rtc/rtc0/wakealarm # 確認 値が書き込まれている $ cat /proc/driver/rtc # 確認 alarm 時刻がセットされている $ sudo shutdown now # 即時シャットダウン
# ドライバを適用した後… $ sudo sh -c "echo 0 > /sys/class/rtc/rtc0/wakealarm" # アラームクリア # もしくは、ドライバを適用前に… $ sudo i2cset -y 6 0x51 0x01 0x00 b # 直接レジスタをいじってアラーム有効、検出フラグを落とす。が、0x01 の部分は 0x00 でないとダメかもしれない。詳しくは上記参照。
$ sudo rtcwake --date +2min -m off # 2分後に alarm をセットしてシャットダウンする。
$ cp ../rasp5.11/linux/drivers/rtc/class.c . $ cp ../rasp5.11/linux/drivers/rtc/dev.c . $ cp ../rasp5.11/linux/drivers/rtc/interface.c . $ cp ../rasp5.11/linux/drivers/rtc/nvmem.c . $ cp ../rasp5.11/linux/drivers/rtc/proc.c . $ cp ../rasp5.11/linux/drivers/rtc/rtc-core.h . $ cp ../rasp5.11/linux/drivers/rtc/rtc-pcf2127.c . $ cp ../rasp5.11/linux/drivers/rtc/sysfs.c .
custom.h
---------
#define RTC_VL_BACKUP_SWITCH    _BITUL(4) /* Backup switchover happened */
#define RTC_VL_BACKUP_LOW       _BITUL(1) /* Backup voltage is low */
int devm_rtc_nvmem_register(struct rtc_device *rtc,
                            struct nvmem_config *nvmem_config);
int __devm_rtc_register_device(struct module *owner, struct rtc_device *rtc);
#define devm_rtc_register_device(device) \
        __devm_rtc_register_device(THIS_MODULE, device)
---------
rtc-pcf2127.c
> #include "custom.h"
Makefile
---------
CFILES = nvmem.c class.c interface.c dev.c proc.c sysfs.c rtc-pcf2127.c
obj-m += rtc-pcf2127-11p.o
rtc-pcf2127-11p-objs := $(CFILES:.c=.o)
ccflags-y += -std=gnu99 -Wall -Wno-declaration-after-statement
all:
        make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
---------
以上2通りの方法を試したが、どちらのドライバも正常には動作しなかった。
[注意] 原因を追求しておらず、検証不足だが、/proc/driver/rtc にアクセスすると alarm が正しく動作しなくなる場合があるような気がする。
693a694,724
> 	//!! read interrupt flag and clear
> 	unsigned int ctrl2 = 0;
> 	ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2);
> 	if(ret) {
> 		dev_err(dev, "failed to read CTRL2\n");
> 		return ret;
> 	}
> 	if((ctrl2 & PCF2127_BIT_CTRL2_AF) != 0 ) {
> 		printk("AF is HI\n");
> 		// clear alarm interrupt and enable
> 	        ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
>         	        PCF2127_BIT_CTRL2_AF |
>                         PCF2127_BIT_CTRL2_AIE, 0);
>         	if(ret) {
>                 	dev_err(dev, "failed to update AF/AIE\n");
> 	                return ret;
>         	}
> 		printk("Clear AF/AIE\n");
> 	}
> 	if((ctrl2 & PCF2127_BIT_CTRL2_WDTF) != 0 ) {
>                 printk("WDTF is HI\n");
> 		// clear watch dog interrupt
>                 ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
>                         PCF2127_BIT_CTRL2_WDTF, 0);
>                 if(ret) {
>                         dev_err(dev, "failed to update WDTF\n");
>                         return ret;
>                 }
>                 printk("Clear WDTF\n");
> 	}
> 
> // i2c bus no > static int bus_no = -1; > module_param(bus_no, int, S_IRUGO); > > // driver name > static char *i2c_name = NULL; > module_param(i2c_name, charp, S_IRUGO); > > // i2c slave address > static int slvaddr = -1; > module_param(slvaddr, int, S_IRUGO); > > // client for unregister > static struct i2c_client *i2c_clie = NULL;
916a972,989
> 	//!!}
> 	//!!  regist i2c device
>  	} else if((i2c_name != NULL) && (slvaddr > 0) && (bus_no > 0)) {
> 
>  	        // make i2c board info
>  		struct i2c_board_info i2c_info;
>  		memset(&i2c_info, 0, sizeof(struct i2c_board_info));
>  		strscpy(i2c_info.type, i2c_name, sizeof(i2c_info.type));
>  		i2c_info.addr = slvaddr;
> 
>  	        struct i2c_adapter *i2c_adap = NULL;
>  	        i2c_adap = i2c_get_adapter(bus_no);
>  	        if(i2c_adap == NULL) return ret;
> 
>  	        i2c_clie = i2c_new_device(i2c_adap, &i2c_info);
>  	        if(i2c_clie == NULL) return ret;
> 
>  	        i2c_put_adapter(i2c_adap);
931a1005,1009
> 
> 	//!! unregist
> 	if(i2c_clie) {
> 		i2c_unregister_device(i2c_clie);
> 	}
$ make $ sudo cp rtc-pcf2127-11.ko /lib/modules/`uname -r`/kernel/drivers/rtc/ $ sudo depmod -a # module.dep を自動で再構成
/etc/modprobe.d/myrtc.conf ------ alias my_pcf2129 rtc-pcf2127-11 options my_pcf2129 alarm_en=1 i2c_name="pcf2129_11" bus_no=6 slvaddr=0x51 ------
> my_pcf2129
$ sudo reboot # 再起動 $ sudo i2cdetect -y 6 # 再起動後に実行すると、ドライバが適用されているのがわかる
369c390,392 < unsigned int buf[5], ctrl2; --- > //!!unsigned int buf[5], ctrl2; > unsigned char buf[5]; > unsigned int ctrl2;
781,785c863,881
< 	static const struct regmap_config config = {
< 		.reg_bits = 8,
< 		.val_bits = 8,
< 		.max_register = 0x1d,
< 	};
---
>         //static const struct regmap_config config = {
>         //        .reg_bits = 8,
>         //        .val_bits = 8,
>         //        .max_register = 0x1d,
>         //};
> 	//!! apply to register size
> 	// val_bytes = val_bits/8, and regmap_bulk access is based on val_bytes.
> 	// so, regmap_bulk_* functions need a buffer of unsigned char.
> 	static struct regmap_config config;
> 	memset(&config, 0, sizeof(struct regmap_config));
>  	config.reg_bits = 8;
> 	config.val_bits = 8;
> 	if(id->driver_data == 0) {
> 		printk("detect pcf2129\n");
> 		config.max_register = 0x1b;
> 	} else {
> 		printk("detect pcf2127\n");
> 		config.max_register = 0x1d;
> 	}
ここで宣言される config が __regmap_init() の中で評価され、val_bits 値が regmap 構造体の format.val_bytes という値に反映される。val_bytes = val_bits / 8 の切り上げ値となる。
そして、val_bytes 値が regmap_bulk_read() および regmap_bulk_write() でのデータ入出力の大きさの単位になる。rtc-pcf2127 ドライバの中では1バイト単位となる。
691,693c773,775
< 	{ .compatible = "nxp,pcf2127" },
< 	{ .compatible = "nxp,pcf2129" },
< 	{ .compatible = "nxp,pca2129" },
---
> 	{ .compatible = "nxp,pcf2127_11" },
> 	{ .compatible = "nxp,pcf2129_11" },
> 	{ .compatible = "nxp,pca2129_11" },
$ make $ sudo cp rtc-pcf2127-11.ko /lib/modules/`uname -r`/kernel/drivers/rtc/ $ sudo depmod -a # module.dep を自動で再構成
#my_pcf2129
i2c-rtc-overlay.dts
--------
// Definitions for several I2C based Real Time Clocks
/dts-v1/;
/plugin/;
/ {
	compatible = "brcm,bcm2835";
	fragment@0 {
		target = <&i2cbus>;
		__dormant__ {
			#address-cells = <1>;
			#size-cells = <0>;
			pcf2127_11: pcf2127_11@51 {
				compatible = "nxp,pcf2127_11";
				reg = <0x51>;
			};
		};
	};
	fragment@1 {
		target = <&i2cbus>;
		__dormant__ {
			#address-cells = <1>;
			#size-cells = <0>;
			pcf2129_11: pcf2129_11@51 {
				compatible = "nxp,pcf2129_11";
				reg = <0x51>;
			};
		};
	};
	fragment@2 {
		target = <&i2cbus>;
		__dormant__ {
			#address-cells = <1>;
			#size-cells = <0>;
			pca2129_11: pca2129_11@51 {
				compatible = "nxp,pca2129_11";
				reg = <0x51>;
			};
		};
	};
	frag100: fragment@100 {
		target = <&i2c6>;
		i2cbus: __overlay__ {
			status = "okay";
		};
	};
	__overrides__ {
		pcf2127_11 = <0>,"+0";
		pcf2129_11 = <0>,"+1";
		pca2129_11 = <0>,"+2";
		i2c0 = <&frag100>, "target:0=",<&i2c0>;
		i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>;
		wakeup-source = <&pcf2127_11>,"wakeup-source?",
				<&pcf2129_11>,"wakeup-source?",
				<&pca2129_11>,"wakeup-source?";
	};
};
--------
$ dtc -@ -I dts -O dtb -o i2c6-rtc-pcf2127.dtbo i2c-rtc-overlay.dts # 入力形式は dts、出力形式は dtb、他の dtb から参照できるようにシンボルをつける(これは特に必要ないけど)
$ sudo cp i2c6-rtc-pcf2127.dtbo /boot/firmware/overlays/ # raspberry pi os だと、コピー先は /boot/overlays/ かな?
dtoverlay=i2c6,pins_22_23,baudrate=400000 dtoverlay=i2c6-rtc-pcf2127,pcf2129_11,wakeup-source
$ sudo reboot $ sudo i2cdetect -y 6 $ cat /proc/driver/rtc
i2c-rtc-overlay.dts
----------
// Definitions for several I2C based Real Time Clocks
/dts-v1/;
/plugin/;
/ {
	compatible = "brcm,bcm2835";
	fragment@0 {
		target = <&i2cbus>;
		__dormant__ {
			#address-cells = <1>;
			#size-cells = <0>;
			pcf2127_11: pcf2127_11@51 {
				compatible = "nxp,pcf2127_11";
				reg = <0x51>;
			};
		};
	};
	fragment@1 {
		target = <&i2cbus>;
		__dormant__ {
			#address-cells = <1>;
			#size-cells = <0>;
			pcf2129_11: pcf2129_11@51 {
				compatible = "nxp,pcf2129_11";
				reg = <0x51>;
			};
		};
	};
	fragment@2 {
		target = <&i2cbus>;
		__dormant__ {
			#address-cells = <1>;
			#size-cells = <0>;
			pca2129_11: pca2129_11@51 {
				compatible = "nxp,pca2129_11";
				reg = <0x51>;
			};
		};
	};
	frag100: fragment@100 {
		target = <&i2c_arm>;
		i2cbus: __overlay__ {
			status = "okay";
		};
	};
	__overrides__ {
		pcf2127_11 = <0>,"+0";
		pcf2129_11 = <0>,"+1";
		pca2129_11 = <0>,"+2";
		i2c0 = <&frag100>, "target:0=",<&i2c0>;
		i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>;
		i2c1 = <&frag100>, "target:0=",<&i2c1>;
		i2c3 = <&frag100>, "target:0=",<&i2c3>;
		i2c4 = <&frag100>, "target:0=",<&i2c4>;
		i2c5 = <&frag100>, "target:0=",<&i2c5>;
		i2c6 = <&frag100>, "target:0=",<&i2c6>;
		wakeup-source = <&pcf2127_11>,"wakeup-source?",
				<&pcf2129_11>,"wakeup-source?",
				<&pca2129_11>,"wakeup-source?";
	};
};
----------
$ dtc -@ -I dts -O dtb -o i2c-rtc-pcf2127.dtbo i2c-rtc-overlay.dts # 入力形式は dts、出力形式は dtb、他の dtb から参照できるようにシンボルをつける(これは特に必要ないけど) $ sudo cp i2c-rtc-pcf2127.dtbo /boot/firmware/overlays/ # raspberry pi os だと、コピー先は /boot/overlays/ かな?
dtoverlay=i2c6,pins_22_23,baudrate=400000 dtoverlay=i2c-rtc-pcf2127,pcf2129_11,i2c6,wakeup-source
$ sudo reboot $ sudo i2cdetect -y 6 $ cat /proc/driver/rtc
> //!! MSF interrupt type > #define PCF2127_BIT_WD_CTL_TITP BIT(5) > //!! MSF interupt flag > #define PCF2127_BIT_CTRL2_MSF BIT(7)
> // Enable flag for initializeing registers > static int initreg_en = 0; > module_param(initreg_en, int, S_IRUGO); > > // Enable flag for clear interrupt > static int clrint_en = 0; > module_param(clrint_en, int, S_IRUGO);
> //!! clearing interrupt func.
> static int pcf2127_clear_int(struct device *dev, struct regmap *map)
> {
> 	int ret = 0;
> 	unsigned int data = 0;
> 
>         ret = regmap_read(map, PCF2127_REG_CTRL2, &data);
>         if(ret) {
>                 dev_err(dev, "failed to read CTRL2\n");
>                 return ret;
>         }
>         if((data & PCF2127_BIT_CTRL2_AF) != 0 ) {
>                 printk("pcf2127:AF is HI\n");
>                 // clear alarm interrupt and enable
> 		data &= ~(PCF2127_BIT_CTRL2_AF | PCF2127_BIT_CTRL2_AIE);
>                 printk("pcf2127:Clear AF/AIE\n");
>         }
>         if((data & PCF2127_BIT_CTRL2_WDTF) != 0 ) {
>                 printk("pcf2127:WDTF is HI\n");
>                 // clear watch dog interrupt
> 		data &= ~PCF2127_BIT_CTRL2_WDTF;
>                 printk("pcf2127:Clear WDTF\n");
>         }
>         if((data & PCF2127_BIT_CTRL2_TSF2) != 0 ) {
>                 printk("pcf2127:TSF2 is HI\n");
>                 // clear timestamp interrupt 2
> 		data &= ~PCF2127_BIT_CTRL2_TSF2;
>                 printk("pcf2127:Clear TSF2\n");
>         }
>         if((data & PCF2127_BIT_CTRL2_MSF) != 0 ) {
>                 printk("pcf2127:MSF is HI\n");
>                 // clear min/sec interrupt
>                 data &= ~PCF2127_BIT_CTRL2_MSF;
>                 printk("pcf2127:Clear MSF\n");
>         }
> 	ret = regmap_write(map, PCF2127_REG_CTRL2, data);
>         if(ret) {
>                 dev_err(dev, "failed to write CTRL2\n");
>                 return ret;
>         }
> 
> 	data = 0;
>         ret = regmap_read(map, PCF2127_REG_CTRL1, &data);
>         if(ret) {
>                 dev_err(dev, "failed to read CTRL1\n");
>                 return ret;
>         }
>         if((data & PCF2127_BIT_CTRL1_TSF1) != 0 ) {
>                 printk("pcf2127:TSF1 is HI\n");
>                 // clear timestamp imterrupt 1
>                 data &= ~PCF2127_BIT_CTRL1_TSF1;
>                 printk("pcf2127:Clear TSF1\n");
>         }
>         ret = regmap_write(map, PCF2127_REG_CTRL1, data);
>         if(ret) {
>                 dev_err(dev, "failed to write CTRL1\n");
>                 return ret;
>         }
> 
> 	return ret;
> }
> //!! initialze registers
> static int pcf2127_init_regs(struct device *dev, struct regmap *map)
> {
> 	int ret = 0;
> 	unsigned int data = 0;
> 
> 	// reset EXT_TEST
> 	// rtc is running
> 	// 24 hour mode
> 	// disable minute and second interrupt
>         ret = regmap_read(map, PCF2127_REG_CTRL1, &data);
>         if (ret) {
>                 dev_err(dev, "failed to read CTRL1\n");
>                 return ret;
>         }
> 
> 	data &= 0b01011000;
> 
>         ret = regmap_write(map, PCF2127_REG_CTRL1, data);
>         if (ret) {
>                 dev_err(dev, "failed to write CTRL1\n");
>                 return ret;
>         }
> 
> 	// poqwer management is standard mode, enable low detection
> 	data = 0;
>         ret = regmap_read(map, PCF2127_REG_CTRL3, &data);
>         if (ret) {
>                 dev_err(dev, "failed to read CTRL3\n");
>                 return ret;
>         }
> 
> 	data &= 0b00011111;
> 
> 	ret = regmap_write(map, PCF2127_REG_CTRL3, data);
>         if (ret) {
>                 dev_err(dev, "failed to write CTRL3\n");
>                 return ret;
>         }
> 
> 	// CLKOUT is 32768Hz
> 	// temp. mesurement period = 4min.
> 	data = 0;
>         ret = regmap_read(map, 0x0F, &data);
>         if (ret) {
>                 dev_err(dev, "failed to read CLKOUT_ctl\n");
>                 return ret;
>         }
> 
>         data &= 0b00111000;
> 
>         ret = regmap_write(map, 0x0F, data);
>         if (ret) {
>                 dev_err(dev, "failed to write CLKOUT_ctl\n");
>                 return ret;
>         }
> 
> 	// aging is default = 0b1000
>         data = 0;
>         ret = regmap_read(map, 0x19, &data);
>         if (ret) {
>                 dev_err(dev, "failed to read AGING_offset\n");
>                 return ret;
>         }
> 
>         data &= 0xf0;
> 	data |= 0x08;
> 
>         ret = regmap_write(map, 0x19, data);
>         if (ret) {
>                 dev_err(dev, "failed to write AGING_offset\n");
>                 return ret;
>         }
> 	return ret;
> }
> 
> 	//!! read interrupt flag and clear
> 	if((clrint_en != 0) || device_property_read_bool(dev, "clear-ints")) {
> 		ret = pcf2127_clear_int(dev, pcf2127->regmap);
>         	if(ret) {
>                 	return ret;
> 	        }
> 	}
> 
> 	//!! initialize registers
> 	if((initreg_en != 0) || device_property_read_bool(dev, "init-regs")) {
> 	        ret = pcf2127_init_regs(dev, pcf2127->regmap);
>         	if(ret) {
>                 	return ret;
> 	        }
> 	}
        ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_WD_CTL,
                                 PCF2127_BIT_WD_CTL_CD1 |
        //!! unused              PCF2127_BIT_WD_CTL_CD0 |
                                 PCF2127_BIT_WD_CTL_TITP | //!! TI_TP added
                                 PCF2127_BIT_WD_CTL_TF1 |
                                 PCF2127_BIT_WD_CTL_TF0,
                                 PCF2127_BIT_WD_CTL_CD1 |
        //!! unused              PCF2127_BIT_WD_CTL_CD0 |
                                 PCF2127_BIT_WD_CTL_TF1);
        //!! watchdog int=enable, MSF int=disable, watchdog timer=1Hz
        ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL3,
                                 PCF2127_BIT_CTRL3_BTSE |
                                 PCF2127_BIT_CTRL3_BIE |
                                 PCF2127_BIT_CTRL3_BF | //!! added
                                 PCF2127_BIT_CTRL3_BLIE, 0);
$ make $ sudo cp rtc-pcf2127-11.ko /lib/modules/`uname -r`/kernel/drivers/rtc/ $ sudo depmod -a # module.dep を自動で再構成
i2c-rtc-overlay.dts
----------
// Definitions for several I2C based Real Time Clocks
/dts-v1/;
/plugin/;
/ {
	compatible = "brcm,bcm2835";
	fragment@0 {
		target = <&i2cbus>;
		__dormant__ {
			#address-cells = <1>;
			#size-cells = <0>;
			pcf2127_11: pcf2127_11@51 {
				compatible = "nxp,pcf2127_11";
				reg = <0x51>;
			};
		};
	};
	fragment@1 {
		target = <&i2cbus>;
		__dormant__ {
			#address-cells = <1>;
			#size-cells = <0>;
			pcf2129_11: pcf2129_11@51 {
				compatible = "nxp,pcf2129_11";
				reg = <0x51>;
			};
		};
	};
	fragment@2 {
		target = <&i2cbus>;
		__dormant__ {
			#address-cells = <1>;
			#size-cells = <0>;
			pca2129_11: pca2129_11@51 {
				compatible = "nxp,pca2129_11";
				reg = <0x51>;
			};
		};
	};
	frag100: fragment@100 {
		target = <&i2c_arm>;
		i2cbus: __overlay__ {
			status = "okay";
		};
	};
	__overrides__ {
		pcf2127_11 = <0>,"+0";
		pcf2129_11 = <0>,"+1";
		pca2129_11 = <0>,"+2";
		i2c0 = <&frag100>, "target:0=",<&i2c0>;
		i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>;
		i2c1 = <&frag100>, "target:0=",<&i2c1>;
		i2c3 = <&frag100>, "target:0=",<&i2c3>;
		i2c4 = <&frag100>, "target:0=",<&i2c4>;
		i2c5 = <&frag100>, "target:0=",<&i2c5>;
		i2c6 = <&frag100>, "target:0=",<&i2c6>;
		wakeup-source = <&pcf2127_11>,"wakeup-source?",
				<&pcf2129_11>,"wakeup-source?",
				<&pca2129_11>,"wakeup-source?";
		init-regs = <&pcf2127_11>,"init-regs?",
                            <&pcf2129_11>,"init-regs?",
                            <&pca2129_11>,"init-regs?";
                clear-ints = <&pcf2127_11>,"clear-ints?",
                             <&pcf2129_11>,"clear-ints?",
                             <&pca2129_11>,"clear-ints?";
	};
};
----------
$ dtc -@ -I dts -O dtb -o i2c-rtc-pcf2127.dtbo i2c-rtc-overlay.dts # 入力形式は dts、出力形式は dtb、他の dtb から参照できるようにシンボルをつける(これは特に必要ないけど) $ sudo cp i2c-rtc-pcf2127.dtbo /boot/firmware/overlays/ # raspberry pi os だと、コピー先は /boot/overlays/ かな
dtoverlay=i2c6,pins_22_23,baudrate=400000 dtoverlay=i2c-rtc-pcf2127,pcf2129_11,i2c6,wakeup-source,init-regs,clear-ints
> // waked up by alarm flag
> static int waked_alarm = 0;
> //!! find out if  PI is waked up by alarm
> static int pcf2127_get_alarmwaked(struct device *dev, struct regmap *map)
> {
> 	int ret = 0;
> 	unsigned int data = 0;
> 
>         ret = regmap_read(map, PCF2127_REG_CTRL2, &data);
>         if(ret) {
>                 dev_err(dev, "failed to read CTRL2\n");
>                 return ret;
>         }
>         if((data & (PCF2127_BIT_CTRL2_AF | PCF2127_BIT_CTRL2_AIE))
> 		== (PCF2127_BIT_CTRL2_AF | PCF2127_BIT_CTRL2_AIE)) {
> 		waked_alarm = 1;	// waked up by alarm
>         } else {
> 		waked_alarm = 0;
> 	}
> 
> 	return 0;
> }
> 	//!! get waked_alarm flag
> 	ret = pcf2127_get_alarmwaked(dev, pcf2127->regmap);
> 	if(ret) {
>                 dev_err(dev, "%s: failed to get waked_alarm flag\n",
>                         __func__);
>                 return ret;
> 	}
> //!! make /sys/class/rtc/rtc?/alarmwaked interface
> static ssize_t alarmwaked_show(struct device *dev,
>         struct device_attribute *attr, char *buf)
> {
>         return sprintf(buf, "%d\n", waked_alarm);
> }
> static DEVICE_ATTR_RO(alarmwaked);
include/device.h や sysfs.h に DEVICE_ATTR* のマクロに関する定義がされており、一部引用すると以下のようになる。
これらの記述から、このマクロに対して例えば alarmwaked を引数に与えたときの動作がわかる
ここで作成された dev_attr_alarmwaked 変数を、rtc_add_group() や device_create_file() に渡すと、目的のファイルシステムが作成される。
device.h
----------
#define DEVICE_ATTR_RO(_name) \
	struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
#define DEVICE_ATTR_RW(_name) \ 
	struct device_attribute dev_attr_##_name = __ATTR_RW(_name) 
#define DEVICE_ATTR(_name, _mode, _show, _store) \ 
	struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) 
----------
sysfs.h
----------
#define __ATTR_RO(_name) {						\
	.attr	= { .name = __stringify(_name), .mode = 0444 },		\
	.show	= _name##_show,						\
}
#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)
----------
static struct attribute *pcf2127_attrs[] = {
        &dev_attr_timestamp0.attr,
        &dev_attr_alarmwaked.attr,      //!! added
        NULL
};
$ make $ sudo cp rtc-pcf2127-11.ko /lib/modules/`uname -r`/kernel/drivers/rtc/ $ sudo depmod -a # module.dep を自動で再構成
$ cat /sys/class/rtc/rtc0/alarmwaked 0 # アラーム以外で起動した $ cat /sys/class/rtc/rtc0/alarmwaked 1 # アラームで起動した
[補足]
linux は、システムクロックが正確でありかつ rtc が接続された状態のとき、現在時刻とアラーム時刻を 11分ごとに rtc に書き込みに行くという動作をする。この動作の副作用として、ユーザー及び rtc のドライバモジュールが想定していないタイミングで 割り込みフラグがリセットされる。結果として、ユーザーは現在の OS が rtc のアラーム機能によって起動したのか、それ以外の理由で起動したかの区別ができなくなる。これを解消するための実装である。
> //!! make /sys/class/rtc/rtc?/batterylow interface
> static ssize_t batterylow_show(struct device *dev,
>         struct device_attribute *attr, char *buf)
> {
>         struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
> 	int ret = 0;
> 	unsigned int data = 0;
> 
>         ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL3, &data);
>         if (ret) {
>                 dev_err(dev, "failed to read CTRL3\n");
>                 return ret;
>         }
> 
> 	if((data & PCF2127_BIT_CTRL3_BLF) != 0 ) {
> 		data = 1;
> 	} else {
> 		data = 0;
> 	}
> 
>         return sprintf(buf, "%u\n", data);
> }
> static DEVICE_ATTR_RO(batterylow);
static struct attribute *pcf2127_attrs[] = {
        &dev_attr_timestamp0.attr,
        &dev_attr_alarmwaked.attr,      //!! added
        &dev_attr_batterylow.attr,      //!! added
        NULL
};
$ make $ sudo cp rtc-pcf2127-11.ko /lib/modules/`uname -r`/kernel/drivers/rtc/ $ sudo depmod -a # module.dep を自動で再構成
$ cat /sys/class/rtc/rtc0/batterylow 1 # バッテリーの電圧が 2.5V 以下 $ cat /sys/class/rtc/rtc0/batterylow 0 # バッテリーの電圧が 2.5V 以上
データシート 8.5.1節及び 9.3節。電源(VDD)が失われ、バッテリー動作(VBAT)に切り替わったときには、インターフェイス(I2C や SPI)は無効になり、通信できなくなる。デバイスへの入力は無視され、デバイスからの出力はハイインピーダンスになる。
I2C 及び SPI 通信中にバッテリー動作への切り替えが起きると、通信は切断される。I2C 通信の場合、バッテリー動作から電源動作に復帰したあとに、START〜STOP の通信サイクルをやり直す必要がある。
# よくわからないが、もしかすると電源復帰後の最初の START〜STOP 通信は破棄されるのかもしれない?
データシート 8.5.2節及び 8.6節。バッテリー電圧が 2.5V 以下になると、レジスタ 0x02 の BLF が 1 になって電圧の低下を知らせる。バッテリーを交換しないと BLF はクリアされない。
電源が失われてバッテリーで動作している時、バッテリー電圧が 1.2V以下になると rtc クロックは正常に動作できなくなり、レジスタ 0x03 の OSF が 1 になって rtc 時刻の異常を知らせる。
# この時、hwclock -r などで rtc 時刻を読もうとすると、エラーが返る。電源を回復した後に hwclock -w などで rtc に時刻を書き込むと、その際に OSF もクリアされる
データシート 8.14節。レジスタ 0x00 の STOP ビットを使うと、rtc の時刻カウンターを正確なタイミングでスタートさせることができる。
という手順を踏むとよい。STOP = 0 を書き込んだ時点から時刻のカウントが始まる。誤差を最大 15.625[ms] に抑えることができる。
今回の実装では比較的通信速度の遅い I2C を使っていることもあり、正確さを追求するためには通信時間を考慮した上で、セットする時刻値や I2C 通信をはじめるタイミングも考慮する必要があるだろう。目的からして高精度を追求してないので上記の実装は見送る。
通信速度が速く、バスにステータスをセットアップする必要もない SPI 通信を使うのであれば、とりあえずやってみてもいいかもしれない気はする。
$ sudo timedatectl set-ntp false # また動作させたかったら true を指定する
以上。
https://github.com/nekokomaru/epgrtc-tools
ソースを眺めていて、node.js の EventEmitter を使ってイベントを扱っており、エンコード終了イベントが定義されていることがわかった。
EncodeEvent.ts ----- 11: private emitter: events.EventEmitter = new events.EventEmitter(); 150: export const FINISH_ENCODE_EVENT = 'finishEncodeEvent';
以下、emitter.on() でイベント名とイベント時のコールバックを設定している。emitter.emit() でイベントを発火させている
EncodeEvent.ts
-----
94:
    public setFinishEncode(callback: (info: FinishEncodeInfo) => void): void {
        this.emitter.on(EncodeEvent.FINISH_ENCODE_EVENT, async (info: FinishEncodeInfo) => {
            try {
                await callback(info);
            } catch (err) {
                this.log.system.error(err);
            }
        });
    }
37:
    public emitFinishEncode(info: FinishEncodeInfo): void {
        this.emitter.emit(EncodeEvent.FINISH_ENCODE_EVENT, info);
    }
上記でわかるように、EncodeEvent.FINISH_ENCODE_EVENT が発火されると、await callback(info)が実行される。
async await は非同期処理。await は、async 宣言されたものの値が確定するまで待つ。
コールバック関数は、EncodeFinishModel.ts の中で設定している
EncodeFinishModel.ts ----- 32: this.encodeEvent.setFinishEncode(this.finishEncode.bind(this));
Function.bind(this) と記述すると、記述した箇所において this で参照できるスコープが、 Function 内でも this で参照できる。
[参考] [ https://www.1ft-seabass.jp/memo/2013/10/03/node_js_bind/ ]
イベントが発火されたときにコールされる関数は以下
EncodeFinishModel.ts
-----
53:
    /**
     * エンコード終了処理
     * @param info: FinishEncodeInfo
     */
    private async finishEncode(info: FinishEncodeInfo): Promise {
        try {
            if (info.fullOutputPath === null || info.filePath === null) {
                // update file size
                await this.ipc.recorded.updateVideoFileSize(info.videoFileId);
            } else {
                // add encode file
                await this.ipc.recorded.addVideoFile({
                    recordedId: info.recordedId,
                    parentDirectoryName: info.parentDirName,
                    filePath: info.filePath,
                    type: 'encoded',
                    name: info.mode,
                });
            }
        } catch (err) {
            this.log.encode.error('finish encode error');
            this.log.encode.error(err);
        }
        if (info.removeOriginal === true) {
            // delete source video file
            await this.ipc.recorded.deleteVideoFile(info.videoFileId, true);
        }
        this.socket.notifyClient();
    }
 
最後の notifyClient() は、SocketIOManagerModel.ts の関数コール(46行目)
socket ならば、多分、ブラウザの表示の更新とかだろう。そうであれば飛ばしても良い処理だろう。この処理の前にシャットダウンスクリプトを仕込めばいいと判断した
EncodeFinishModel.ts
-----
         await exec(EXE_FILE);
EncodeFinishModel.ts ----- import * as child_process from 'child_process'; import * as util from 'util'; const EXE_FILE: string = '/usr/local/bin/shutdown_srv'; const exec: any = util.promisify(child_process.exec);
$ node_modules/.bin/eslint --fix [エラーが出たファイルのパス]
[child_process について参考]
[ https://qiita.com/ryohji/items/93f5050b9af6fc15693c ] [ https://nodejs.keicode.com/nodejs/exec-child.php ] [ https://typescript.hotexamples.com/examples/child_process/ChildProcess/once/typescript-childprocess-once-method-examples.html ] [ https://github.com/nodejs/node-v0.x-archive/blob/master/lib/child_process.js ]
[TypeScript について参考]
[ http://js.studio-kingdom.com/typescript/handbook/module_resolution ] 
→javascript みたいに、require('child_process') みたいな記述は駄目っぽい。import で書かないといけないっぽい。
[eslint について参考]
[ https://qiita.com/mysticatea/items/f523dab04a25f617c87d ]
/etc/initramfs-tools/hooks/del_pcf2127_11
-----
#!/bin/sh
PREREQ="del_pcf2127_11"
prereqs()
{
	echo "$PREREQ"
}
case $1 in
prereqs)
	prereqs
	exit 0
        ;;
esac
. /usr/share/initramfs-tools/hook-functions
# Begin real processing below this line
#echo "MODULESDIR=${MODULESDIR}"
#echo "DESTDIR=${DESTDIR}"
#echo "rtcdir=${DESTDIR}/lib/modules/${version}/kernel/drivers/rtc/"
if [ -f "${DESTDIR}/lib/modules/${version}/kernel/drivers/rtc/rtc-pcf2127-11.ko" ]; then
	rm "${DESTDIR}/lib/modules/${version}/kernel/drivers/rtc/rtc-pcf2127-11.ko"
	echo "delete from initramfs - ${DESTDIR}/lib/modules/${version}/kernel/drivers/rtc/rtc-pcf2127-11.ko"
fi
exit 0
-----
$ sudo chmod +x /etc/initramfs-tools/hooks/del_pcf2127_11
$ sudo update-initramfs -u # initramfs 更新 $ lsinitramfs -l /boot/initrd.img-`uname -r` |grep pcf2127-11 # なにも表示されない
$ sudo apt install rpi-eeprom # インストールする $ sudo vcgencmd bootloader_version # ファームウェアのバージョンが見れる $ sudo vcgencmd bootloader_config # ファームウェアの設定が見れる
[参考] [ https://packages.ubuntu.com/search?keywords=rpi-eeprom ]
/etc/systemd/system/test.service ----- [Unit] Description=Test cancel shutdown Before=shutdown.target alsa-store.service DefaultDependencies=no ConditionFileIsExecutable=/usr/local/bin/test.sh [Service] Type=oneshot ExecStart=/usr/local/bin/test.sh RemainAfterExit=yes [Install] WantedBy=shutdown.target ----- /usr/local/bin/test.sh ----- #!/bin/bash echo 'cancel shutdown' >> /etc/systemd/system/test.service.log shutdown -c exit 0 -----
$ sudo systemctl daemon-reload $ sudo systemctl start test.service $ sudo systemctl enable test.service $ sudo shutdown now
[参考] [ https://unix.stackexchange.com/questions/39226/how-to-run-a-script-with-systemd-right-before-shutdown ] [ https://qiita.com/rdonster/items/33e98dea90ce34730e70 ] [ https://qiita.com/cmwig65/items/3386a061aeb3d2f81b81 ] [ https://kernhack.hatenablog.com/entry/2014/12/08/000708 ]
[pi4] #kernel=uboot_rpi_4.bin max_framebuffers=2 dtoverlay=vc4-fkms-v3d boot_delay=3 kernel=vmlinux initramfs initrd.img followkernel
他には、以下のようなことを試したが、あまり改善した感じはなかったので、上記の変更が効いたのだと考える