-
Notifications
You must be signed in to change notification settings - Fork 14
/
setup.sh
executable file
·309 lines (275 loc) · 9.81 KB
/
setup.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
#!/usr/bin/env bash
pushd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null
RPI_SETUP_DIR="$( pwd )"
I2S_MODE=
XMOS_DEVICE=
INSTALL_ATTEMPT_NUM_MAX=10
# Valid values for XMOS device
VALID_XMOS_DEVICES="xvf3100 xvf3500 xvf3510-int xvf3510-ua xvf3600-slave xvf3600-master xvf3610-int xvf3610-ua xvf3615-int xvf3615-ua xvf3800-intdev xvf3800-inthost"
PACKAGES_TO_INSTALL="python3-matplotlib python3-numpy libatlas-base-dev audacity libreadline-dev libncurses-dev"
PACKAGES_TO_INSTALL_ONLY_FOR_UA="libusb-1.0-0-dev libevdev-dev libudev-dev"
usage() {
local VALID_XMOS_DEVICES_DISPLAY_STRING=
local NUMBER_OF_VALID_DEVICES=$(echo $VALID_XMOS_DEVICES | wc -w)
local i=1
local SEP=
# Build a string of valid device options
for d in $VALID_XMOS_DEVICES; do
if [[ $i -eq $NUMBER_OF_VALID_DEVICES ]]; then
SEP=" or "
fi
VALID_XMOS_DEVICES_DISPLAY_STRING=$VALID_XMOS_DEVICES_DISPLAY_STRING$SEP$d
SEP=", "
(( ++i ))
done
cat <<EOT
This script sets up the Raspberry Pi to use different XMOS devices
usage: setup.sh <DEVICE-TYPE>
The DEVICE-TYPE is the XMOS device to setup: $VALID_XMOS_DEVICES_DISPLAY_STRING
EOT
}
# validate XMOS_DEVICE value
validate_device() {
local DEV=$1
shift
for d in $*; do
if [[ "$DEV" = "$d" ]]; then
return 0
fi
done
return 1
}
if [[ $# -eq 1 ]]; then
XMOS_DEVICE=$1
if ! validate_device $XMOS_DEVICE $VALID_XMOS_DEVICES; then
echo "error: $XMOS_DEVICE is not a valid device type."
echo
usage
exit 1
fi
else
usage
exit 1
fi
# Configure device-specific settings
case $XMOS_DEVICE in
xvf3510-ua|xvf3610-ua|xvf3615-ua)
USB_MODE=y
I2S_MODE=slave
ASOUNDRC_TEMPLATE=$RPI_SETUP_DIR/resources/asoundrc_vf_xvf3510_ua
;;
xvf3510-int|xvf3610-int|xvf3615-int)
I2S_MODE=master
IO_EXP_AND_DAC_SETUP=y
ASOUNDRC_TEMPLATE=$RPI_SETUP_DIR/resources/asoundrc_vf_xvf3510_int
;;
xvf3500)
I2S_MODE=slave
ASOUNDRC_TEMPLATE=$RPI_SETUP_DIR/resources/asoundrc_vf_stereo
;;
xvf3[01]00)
I2S_MODE=slave
ASOUNDRC_TEMPLATE=$RPI_SETUP_DIR/resources/asoundrc_vf
;;
xvf3600-slave)
I2S_MODE=master
IO_EXP_AND_DAC_SETUP=y
ASOUNDRC_TEMPLATE=$RPI_SETUP_DIR/resources/asoundrc_vf
;;
xvf3600-master)
I2S_MODE=slave
IO_EXP_AND_DAC_SETUP=y
ASOUNDRC_TEMPLATE=$RPI_SETUP_DIR/resources/asoundrc_vf
;;
# Note DAC is not setup for XVF3800 - the setup script takes an arg which will conditionally do this
xvf3800-intdev)
I2S_MODE=master
IO_EXP_AND_DAC_SETUP=y
ASOUNDRC_TEMPLATE=$RPI_SETUP_DIR/resources/asoundrc_vf
;;
xvf3800-inthost)
I2S_MODE=slave
IO_EXP_AND_DAC_SETUP=y
ASOUNDRC_TEMPLATE=$RPI_SETUP_DIR/resources/asoundrc_vf
;;
*)
echo Error: unknown XMOS device type $XMOS_DEVICE.
exit 1
;;
esac
# Disable the built-in audio output so there is only one audio
# device in the system
sudo sed -i -e 's/^dtparam=audio=on/#dtparam=audio=on/' /boot/config.txt
# Enable the i2s device tree
sudo sed -i -e 's/#dtparam=i2s=on/dtparam=i2s=on/' /boot/config.txt
# Enable the I2C device tree
sudo raspi-config nonint do_i2c 1
sudo raspi-config nonint do_i2c 0
# Set the I2C baudrate to 100k
sudo sed -i -e '/^dtparam=i2c_arm_baudrate/d' /boot/config.txt
sudo sed -i -e 's/dtparam=i2c_arm=on$/dtparam=i2c_arm=on\ndtparam=i2c_arm_baudrate=100000/' /boot/config.txt
# Enable the SPI support
sudo raspi-config nonint do_spi 1
sudo raspi-config nonint do_spi 0
# Install the kernel header package to allow building the I2S module.
# We only need to do this once, and we must not do it again if we have called
# 'apt-get update' as it may install a later kernel and headers which have not
# been tested and verified.
KERNEL_HEADERS_PACKAGE=raspberrypi-kernel-headers
if ! dpkg -s $KERNEL_HEADERS_PACKAGE &> /dev/null; then
echo "Installing Raspberry Pi kernel headers"
sudo apt-get install -y $KERNEL_HEADERS_PACKAGE
fi
echo "Installing necessary packages for dev kit"
packages=$PACKAGES_TO_INSTALL
# Add packages for UA mode
if [[ -n "$USB_MODE" ]]; then
packages="$packages $PACKAGES_TO_INSTALL_ONLY_FOR_UA"
fi
for package in $packages; do
installed=0
attempt_num=0
while [ $installed -eq 0 ]; do
attempt_num=$((attempt_num+1))
sudo apt-get install -y $package && installed=1
if [[ $attempt_num -gt $INSTALL_ATTEMPT_NUM_MAX ]]; then
echo "Error: installation of package $package failed after $attempt_num attempts"
echo "Please retry installation procedure."
exit 1
fi
done
done
# Build I2S kernel module
PI_MODEL=$(cat /proc/device-tree/model | awk '{print $3}')
if [[ $PI_MODEL -eq 4 ]]; then
I2S_MODULE_CFLAGS="-DRPI_4B"
fi
if [[ -n "$I2S_MODE" ]]; then
case $I2S_MODE in
master)
if [[ -z "$I2S_MODULE_CFLAGS" ]]; then
I2S_MODULE_CFLAGS=-DI2S_MASTER
else
I2S_MODULE_CFLAGS="$I2S_MODULE_CFLAGS -DI2S_MASTER"
fi
;;
slave)
# no flags needed for I2S slave compilation
;;
*)
echo Error: I2S mode not known for XMOS device $XMOS_DEVICE.
exit 1
;;
esac
I2S_BUILD_DIR=$RPI_SETUP_DIR/loader/i2s_$I2S_MODE
pushd $I2S_BUILD_DIR > /dev/null
if [[ -n "$I2S_MODULE_CFLAGS" ]]; then
CMD="make CFLAGS_MODULE='$I2S_MODULE_CFLAGS'"
else
CMD=make
fi
echo $CMD
eval $CMD
if [[ $? -ne 0 ]]; then
echo "Error: I2S kernel module build failed"
exit 1
fi
fi
popd > /dev/null
# Copy the udev rules files if device is UA
if [[ -n "$USB_MODE" ]]; then
echo "Add UDEV rules for XMOS devices"
sudo cp $RPI_SETUP_DIR/resources/99-xmos.rules /etc/udev/rules.d/
fi
# Move existing files to back up
if [[ -e ~/.asoundrc ]]; then
chmod a+w ~/.asoundrc
cp ~/.asoundrc ~/.asoundrc.bak
fi
if [[ -e /usr/share/alsa/pulse-alsa.conf ]]; then
sudo mv /usr/share/alsa/pulse-alsa.conf /usr/share/alsa/pulse-alsa.conf.bak
fi
# Check XMOS device for asoundrc selection.
if [[ -z "$ASOUNDRC_TEMPLATE" ]]; then
echo Error: sound card config not known for XMOS device $XMOS_DEVICE.
exit 1
fi
# Apply changes
sudo /etc/init.d/alsa-utils restart
if [[ -n "$I2S_MODE" ]]; then
# Create the script to run after each reboot and make the soundcard available
i2s_driver_script=$RPI_SETUP_DIR/resources/load_i2s_${I2S_MODE}_driver.sh
rm -f $i2s_driver_script
# Sometimes with Buster on RPi3 the SYNC bit in the I2S_CS_A_REG register is not set before the drivers are loaded
# According to section 8.8 of https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf
# this bit is set after 2 PCM clocks have occurred.
# To avoid this issue we add a 1-second delay before the drivers are loaded
echo "sleep 1" >> $i2s_driver_script
I2S_NAME=i2s_$I2S_MODE
I2S_MODULE=$RPI_SETUP_DIR/loader/$I2S_NAME/${I2S_NAME}_loader.ko
echo "sudo insmod $I2S_MODULE" >> $i2s_driver_script
echo "# Run Alsa at startup so that alsamixer configures" >> $i2s_driver_script
echo "arecord -d 1 > /dev/null 2>&1" >> $i2s_driver_script
echo "aplay dummy > /dev/null 2>&1" >> $i2s_driver_script
if [[ "$I2S_MODE" = "master" ]]; then
echo "# Preconfigure i2s clocks to 48kHz" >> $i2s_driver_script
# wait a bit as it doesn't work otherwise, this is probably caused
# by the same process that is deleting .asoundrc
echo "sleep 15" >> $i2s_driver_script
echo "arecord -Dhw:sndrpisimplecar,0 -c2 -fS32_LE -r48000 -s1 /dev/null" >> $i2s_driver_script
echo "sudo $RPI_SETUP_DIR/resources/clk_dac_setup/setup_bclk" >> $i2s_driver_script
fi
fi
if [[ -n "$IO_EXP_AND_DAC_SETUP" ]]; then
pushd $RPI_SETUP_DIR/resources/clk_dac_setup/ > /dev/null
make
popd > /dev/null
dac_and_clks_script=$RPI_SETUP_DIR/resources/init_dac_and_clks.sh
rm -f $dac_and_clks_script
# Configure the clocks only if RaspberryPi is configured as I2S master
if [[ "$I2S_MODE" = "master" ]]; then
echo "sudo $RPI_SETUP_DIR/resources/clk_dac_setup/setup_mclk" >> $dac_and_clks_script
echo "sudo $RPI_SETUP_DIR/resources/clk_dac_setup/setup_bclk" >> $dac_and_clks_script
fi
# Note that only the substring xvfXXXX from $XMOS_DEVICE is used in the lines below
echo "python $RPI_SETUP_DIR/resources/clk_dac_setup/setup_io_exp_and_dac.py $(echo $XMOS_DEVICE | cut -c1-7)" >> $dac_and_clks_script
echo "python $RPI_SETUP_DIR/resources/clk_dac_setup/reset_xvf.py $(echo $XMOS_DEVICE | cut -c1-7)" >> $dac_and_clks_script
fi
if [[ -n "$IO_EXP_AND_DAC_SETUP" ]]; then
audacity_script=$RPI_SETUP_DIR/resources/run_audacity.sh
rm -f $audacity_script
echo "#!/usr/bin/env bash" >> $audacity_script
echo "/usr/bin/audacity &" >> $audacity_script
echo "sleep 5" >> $audacity_script
if [[ "$I2S_MODE" = "master" ]]; then
echo "sudo $RPI_SETUP_DIR/resources/clk_dac_setup/setup_bclk >> /dev/null" >> $audacity_script
fi
sudo chmod +x $audacity_script
sudo mv $audacity_script /usr/local/bin/audacity
fi
# Regenerate crontab file with new commands
crontab_file=$RPI_SETUP_DIR/resources/crontab
if [ -n "$USB_MODE" ]; then
crontab_file="${crontab_file}_usb"
elif [ -n "$I2S_MODE" ]; then
crontab_file="${crontab_file}_i2s_${I2S_MODE}"
fi
rm -f $crontab_file
# Setup the crontab to restart I2S at reboot
if [ -n "$I2S_MODE" ] || [ -n "$IO_EXP_AND_DAC_SETUP" ]; then
if [[ -n "$I2S_MODE" ]]; then
echo "@reboot sh $i2s_driver_script" >> $crontab_file
fi
if [[ -n "$IO_EXP_AND_DAC_SETUP" ]]; then
echo "@reboot sh $dac_and_clks_script" >> $crontab_file
fi
popd > /dev/null
fi
# Setup the crontab to copy the .asoundrc file at reboot
# Delay the action to allow the host to boot up
# This is needed to address the known issue in Raspian Buster:
# https://forums.raspberrypi.com/viewtopic.php?t=295008
echo "@reboot sleep 20 && cp $ASOUNDRC_TEMPLATE ~/.asoundrc" >> $crontab_file
# Update crontab
crontab $crontab_file
echo "To enable all interfaces, this Raspberry Pi must be rebooted."