IoT
無聊閒閒沒事情做又開始玩開發板,這次目標是 Raspberry Pi Zero W :這是一片 ARMv6、512MB RAM、802.11 b/g/n WiFi 的開發板,在上面安裝 ArchLinux 。
Install OS
在網路上找到很多安裝的方式,目前我參考了 這個 script 改寫成我自己的版本:
- 下載 ArchLinux 最新的 Raspberry Image 與驗證 MD5
- 重新格式化 SD 卡: vfat 與 ext4
以下是 sh script:
#! /bin/sh -exu
DEV=$1
IMG_NAME=ArchLinuxARM-rpi-latest.tar.gz
ARCH_LINUX_IMG=http://os.archlinuxarm.org/os/${IMG_NAME}
LOCAL_IMG=/tmp/${IMG_NAME}
function umountboot {
umount boot || true
umount root || true
}
function download_image_and_verify {
if [ ! -f "${LOCAL_IMG}" ]; then
# download the image
wget ${ARCH_LINUX_IMG} -O ${LOCAL_IMG}
fi
wget ${ARCH_LINUX_IMG}.md5 -qO - | sed "s%${IMG_NAME}%${LOCAL_IMG}%g" | md5sum -c
if [ $? != 0 ]; then
exit -1
fi
}
cd $(mktemp -d)
download_image_and_verify
parted -s ${DEV} mklabel msdos
parted -s ${DEV} mkpart primary fat32 1 128
parted -s ${DEV} mkpart primary ext4 128 -- -1
mkfs.vfat ${DEV}1
mkfs.ext4 -F ${DEV}2
# auto-umount
trap umountboot EXIT
mkdir -p boot && mount ${DEV}1 boot
mkdir -p root && mount ${DEV}2 root
bsdtar -xpf ${LOCAL_IMG} -C root
sync
mv root/boot/* boot
Scenario 1 - hostname
第一個客製化系統就是修改你 RPI 上的 hostname :這可以用獨特的關鍵字來判斷正在使用哪一個開發版。 在安裝完 OS 之後先不要執行 umount 的情況之下,可以執行以下指令 (HOSTNAME 需要自行設定) 就可以修改成自己的名稱st:
#! /bin/sh
echo ${HOSTNAME} > root/etc/hostname
Scenario 2 - USB Gadget
可以透過載入各種不同的 USB Gadget module 之後,就可以將 USB 裝置視為是另一種方面的裝置了。
Serial Port over USB
透過安裝 g_serial 之後可以將 USB 視為是 serial port 的裝置:
#! /bin/sh
# load dwc2 when boot
sed -i "s/rootwait/rootwait modules-load=dwc2,g_serial/g" /boot/cmdline.txt"
echo "dtoverlay=dwc2" >> /boot/config.txt
# enable getty systemd service
systemctl enable getty@ttyGS0.service
另一種寫法則是透過 systemd 的設定檔負責載入 kernel module 跟啟用 ttyGS0:
#! /bin/sh
## Setup by each gadget case ##
cat >> root/usr/lib/systemd/system/usb_serial.service << EOF
# USB serial port gadget
[Unit]
Description=USB Serial Port Gadget
After=systemd-modules-load.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/modprobe g_serial
ExecStart=/bin/systemctl start serial-getty@ttyGS0.service
ExecStop=/bin/systemctl stop serial-getty@ttyGS0.service
ExecStop=/sbin/modprobe -r g_serial
[Install]
WantedBy=getty.target
EOF
# enable getty systemd service
systemctl enable usb_serial.service
Mass Storage over USB
透過安裝 g_mass_storage 之後可以將 RPi 視為是一個可讀寫的 USB 裝置,但是在我的測試環境中第二次使用就會出現 dmesg 的錯誤訊息:
[601761.743841] sd 6:0:0:0: [sdb] Synchronizing SCSI cache
[601761.743921] sd 6:0:0:0: [sdb] Synchronize Cache(10) failed: Result: hostbyte=DID_NO_CONNECT driverbyte=DRIVER_OK
不過依然可以用以下 shell script 安裝:
#! /bin/sh
# load dwc2 when boot
sed -i "s/rootwait/rootwait modules-load=dwc2,g_mass_storage/g" /boot/cmdline.txt"
echo "dtoverlay=dwc2" >> /boot/config.txt
# touch a file as storage
dd if=/dev/zero of=/root/usbstorage.img bs=1MB count=100
echo "options g_mass_storage file=/root/usbstorage.img" >> /etc/modprobe.d/mass_storage_gadget.conf
經過操作之後可以進入到 RPi 執行指令 file /root/usbstorage.img
之後可以看到是一個 ext4 的檔案系統格式:
/root/usbstorage.img: Linux rev 1.0 ext4 filesystem data
Multiple Gadget
接下來透過 libcomposite 這個套件可以使用各種 USB Gadget 模組,並透過 sysfs 做各種設定:
#! /bin/sh -e
# /usr/sbin/usbgadget
# ref: https://www.kernel.org/doc/Documentation/usb/gadget_configfs.txt
USB_GADGET_PATH=/sys/kernel/config/usb_gadget
USB_GADGET_NAME=g
# load libcomposite and USB gadget modules
modprobe -r g_ether
modprobe libcomposite
# make new USB gadget in configs
mkdir -p ${USB_GADGET_PATH}/${USB_GADGET_NAME}/configs/c.1
cd ${USB_GADGET_PATH}/${USB_GADGET_NAME}
# General USB property #
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x0100 > bcdDevice # v1.0.0
echo 0x0200 > bcdUSB # USB2
mkdir -p strings/0x409
echo "deadbeef00112233" > strings/0x409/serialnumber
echo "RPi0w" > strings/0x409/manufacturer
echo "RPi0w USB Gadget" > strings/0x409/product
mkdir -p configs/c.1/strings/0x409
echo "Config 1: ECM network" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower
# create function #
mkdir -p functions/acm.usb0 # serial
mkdir -p functions/ecm.usb0 # ECM ethernet
# enable function #
ln -s functions/acm.usb0 configs/c.1/ ## Serial Adapter ##
ln -s functions/ecm.usb0 configs/c.1/ ## ECM Ethernet Adapter ##
udevadm settle -t 20 || :
ls /sys/class/udc/ > UDC
透過產生 /usr/sbin/usbgadget
檔案並產生相對的 systemd 設定檔,就可以在 RPi 上面同時產生 serial
跟 CDC ECM 網路裝置。