summaryrefslogtreecommitdiff
path: root/h3consumption
blob: ce6a03c90ed8c94f93c51b657b59314a821a70ab (plain)
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
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
#!/bin/bash
#
# h3consumption
#
# This tool patches fex/script.bin, adds commands to /etc/rc.local and
# adjusts /etc/defaults/cpufrequtils to control board consumption. Works
# only with H3 devices running legacy kernel.
#
#############################################################################
#
# Background information:
#
# By controlling a few settings energy consumption of H3 boards can be
# influenced:
#
# - disabling GPU/HDMI on headless devices: 210 mW less idle consumption
#   (memory bandwidth also increases so performance will slightly improve)
# 
# - negotiate only Fast Ethernet on GbE devices: 370 mW less idle consumption
#
# - switch off Ethernet on Fast Ethernet devices: 200 mW less idle consumption
# 
# - limit max cpufreq: does not affect idle consumption but peak/full load
#   (using 912 mhz on NanoPi M1/NEO or Orange Pi One/Lite will prevent VDD_CPU
#   switching to the higher voltage and therfore greatly reduce consumption
#   with only a slight decrease in maximum performance)
# 
# - limit count of active cpu cores: low impact on idle consumption, high on
#   peak/full load consumption
# 
# - lower DRAM clockspeed to 408 MHz: 150 mW less idle consumption
# 
# - disabling all USB ports (it's only 'all or nothing'): 125 mW less idle
#
# Please be aware that WiFi might add significantly to consumption. Since there
# are too many possible configurations (USB WiFi dongles also considered and
# possibilities to tweak power management settings with individual WiFi chips)
# h3consumption does not adjust WiFi settings -- only the -p switch lists
# configured WiFi devices.
# 
# In case you don't need WiFi on the H3 boards with onboard WiFi adjust
# /etc/modules and comment the WiFi module out (8189es, 8189fs or bcmdhd).
# Please keep also in mind that you can control networking consumption also 
# on a 'on demand' basis. In case you use a H3 board as data logger and need
# WiFi only for a short time every 24 hours, disabling WiFi and only enabling
# it for data transfers will save you between 300 and 1000 mW with 8189FTV as 
# used on Orange Pi Lite, PC Plus or Plus 2E for example:
#
# ifconfig wlan0 down && rmmod -f 8189fs / modprobe 8189fs && sleep 0.5 && ifconfig wlan0 up
#
# Same with the Gigabit Ethernet equipped H3 boards: switching there to Fast
# Ethernet when no high speed transfers are needed saves a whopping 370 mW
# (and the same will happen on the switch's side if a more modern Gbit switch
# is in use):
#
# ethtool -s eth0 speed 100 duplex full / ethtool -s eth0 speed 1000 duplex full
#
# More information (and discussion in case questions arise!) in Armbian forum:
# https://forum.armbian.com/index.php/topic/1614-running-h3-boards-with-minimal-consumption/
# https://forum.armbian.com/index.php/topic/1748-sbc-consumptionperformance-comparisons/
# https://forum.armbian.com/index.php/topic/1823-opi-pc-wireless-not-powering-off/
#
#############################################################################
#
# CHANGES:
#
# v0.1: Initial release
#
#############################################################################
#
# TODO:
# 
# - Write documentation as nicely as it's done for h3disp
# - Allow higher DRAM clock in fex file than set from /etc/rc.local
# - Add revert mode, relinking original fex/bin and restore all original
#   settings
#
#############################################################################

Main() {
	export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
	
	# ensure script is running as root
	if [ "$(id -u)" != "0" ]; then
	        echo "This script must be executed as root. Exiting" >&2
	        exit 1
	fi

	# check installation
	CheckInstallation

	if [ $# -eq 0 ]; then
		DisplayUsage ; exit 0
	else
		FexSettings="$(mktemp /tmp/${0##*/}.XXXXXX)"
		RCLocalContents="$(mktemp /tmp/${0##*/}.XXXXXX)"
		ReadSettings
		ParseOptions "$@"
		ChangeSettings
		FinalizeSettings
	fi
	
	echo -e "Settings changed. Please reboot for changes to take effect\nand verify settings after the reboot using \"${0##*/} -p\""
	
	# Let's see whether we have to collect debug output
	case ${Debug} in
		TRUE)
			which curl >/dev/null 2>&1 || apt-get -f -qq -y install curl
			echo -e "\nDebug output has been collected at the following URL: \c"
			(cat "${DebugOutput}"; echo -e "\n\n\nfex contents:\n" ; cat "${MyTmpFile}") \
				| curl -F 'sprunge=<-' http://sprunge.us
			;;
	esac
} # Main

CheckInstallation() {
	# check if tool can rely on Armbian environment
	if [ ! -f /etc/armbian.txt ]; then
		echo -e "Error. This tool requires an Armbian installation. Exiting." >&2
		exit 1
	fi
	
	# check platform and kernel
	case $(uname -r) in
		3.4.*)
			HARDWARE=$(awk '/Hardware/ {print $3}' </proc/cpuinfo)
			if [ "X${HARDWARE}" != "Xsun8i" ]; then
				echo "This tool works only on H3 devices. Exiting." >&2
				exit 1
			fi
			;;
		*)
			echo "This tool requires legacy kernel on H3 devices. Exiting." >&2
			exit 1
			;;
	esac
	
	# ensure ethtool is installed
	which ethtool >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		echo -e "\nPlease be patient, external requirements are to be installed.\n"
		apt-get -f -qq -y install ethtool >/dev/null 2>&1
	fi
} # CheckInstallation

ParseOptions() {
	while getopts 'hHvVpPe:E:m:M:c:C:d:D:u:U:g:G:w:W:' c ; do
	case ${c} in
		H)
			export FullUsage=TRUE
			DisplayUsage
			exit 0
			;;
		h)
			DisplayUsage
			exit 0
			;;
		v|V)
			# Increase verbosity. Will try to upload debug output from script
			# to ease reporting of bugs or strange behaviour. Use only when 
			# asked for.
			export Debug=TRUE
			DebugOutput="$(mktemp /tmp/${0##*/}.XXXXXX)"
			trap "rm \"${DebugOutput}\" ; exit 0" 0 1 2 3 15
			set -x
			exec 2>"${DebugOutput}"
			;;
		e|E)
			# Ethernet: either none, fast or gbit
			Ethernet=$(echo -n ${OPTARG} | tr '[:upper:]' '[:lower:]')
			;;
		g|G)
			# GPU/HDMI: either on or off
			GPUHDMI=$(echo -n ${OPTARG} | tr '[:upper:]' '[:lower:]')
			;;
		m|M)
			# maximum allowed cpu clockspeed
			MaxClockspeed=$(echo -n ${OPTARG} | tr -d -c '[:digit:]')
			;;
		c|C)
			# count of cpu cores: 1 - 4
			CPUCores=$(echo -n ${OPTARG} | tr -d -c '[:digit:]')
			;;
		d)
			# dram clockspeed: 408 - 624 mhz
			DRAMLowerLimit=408
			DramClockspeed=$(echo -n ${OPTARG} | tr -d -c '[:digit:]')
			;;
		D)
			# dram clockspeed: 132 - 624 mhz
			DRAMLowerLimit=132
			DramClockspeed=$(echo -n ${OPTARG} | tr -d -c '[:digit:]')
			;;
		u|U)
			# All USB ports on or off
			USBUsed=$(echo -n ${OPTARG} | tr '[:upper:]' '[:lower:]')
			;;
		p|P)
			# print active settings
			PrintActiveSettings
			exit 0
			;;
		w|W)
			# Wi-Fi powermanagement
			WiFi=$(echo -n ${OPTARG} | tr '[:upper:]' '[:lower:]')
			;;
	esac
	done
} # ParseOptions

ChangeSettings() {
	# Ethernet
	case ${Ethernet} in
		"")
			: ;;
		fast)
			echo 'ethtool -s eth0 speed 100 duplex full' >>"${RCLocalContents}"
			;;
		on)
			BOARD=$(awk -F"=" '/^BOARD=/ {print $2}' </etc/armbian-release)
			if [ "X${BOARD}" = "X" ]; then
				echo "Armbian installation too old, please apt-get upgrade before. Exiting." >&2
				exit 1
			else
				OrigSettings=$(bin2fex /boot/bin/${BOARD}.bin 2>/dev/null | awk -F" " '/^gmac_used/ {print $3}')
				sed -i -e "s/^gmac_used\ =\ 0/gmac_used = ${OrigSettings}/g" "${FexSettings}"
			fi
			;;
		off)
			sed -i -e 's/^gmac_used\ =\ \(.*\)/gmac_used = 0/g' "${FexSettings}"
			;;
		*)
			echo "Parameter error: -e requires either on, fast or off. Exiting" >&2
			exit 1
			;;
	esac

	# Wi-Fi powermanagement
	case ${WiFi} in
		"")
			: ;;
		on)
			rm -f /etc/NetworkManager/dispatcher.d/99enable-power-management \
				/etc/NetworkManager/dispatcher.d/99disable-power-management \
				/etc/NetworkManager/conf.d/zz-override-wifi-powersave-off.conf

			;;
		off)
			rm -f /etc/NetworkManager/dispatcher.d/99enable-power-management \
				/etc/NetworkManager/dispatcher.d/99disable-power-management \
				/etc/NetworkManager/conf.d/zz-override-wifi-powersave-off.conf

			echo "Note: This action applies only to NetworkManager based connections"

			case "$(lsb_release -sc)" in
			jessie)
				mkdir -p /etc/NetworkManager/dispatcher.d/
				cat <<-'EOF' > /etc/NetworkManager/dispatcher.d/99disable-power-management
				#!/bin/sh
				case "$2" in
					up) /sbin/iwconfig $1 power off || true ;;
					down) /sbin/iwconfig $1 power on || true ;;
				esac
				EOF
				chmod 755 /etc/NetworkManager/dispatcher.d/99disable-power-management
				;;
			xenial)
				mkdir -p /etc/NetworkManager/conf.d/
				cat <<-EOF > /etc/NetworkManager/conf.d/zz-override-wifi-powersave-off.conf
				[connection]
				wifi.powersave = 2
				EOF
				;;
			*)
				echo "This action is supported only in Jessie and Xenial based releases. Exiting" >&2
				exit 1
				;;
			esac
			;;
		*)
			echo "Parameter error: -w requires either on or off. Exiting" >&2
			exit 1
			;;
	esac

	# Maximum cpu clock in mhz
	case ${MaxClockspeed} in
		"")
			: ;;
		*)	
			HardwareUpperLimit=$(awk -F" " '/^max_freq = / {print $3 / 1000000}' <"${FexSettings}")
			HardwareLowerLimit=$(awk -F" " '/^min_freq = / {print $3 / 1000000}' <"${FexSettings}")
			if [ ${MaxClockspeed} -lt ${HardwareLowerLimit} ]; then
				# adjust to lowest allowed clockspeed
				sed -i "s/MAX_SPEED=\(.*\)/MAX_SPEED=${HardwareLowerLimit}000/" /etc/default/cpufrequtils
			elif [ ${MaxClockspeed} -gt ${HardwareUpperLimit} ]; then
				# adjust to highest allowed clockspeed
				sed -i "s/MAX_SPEED=\(.*\)/MAX_SPEED=${HardwareUpperLimit}000/" /etc/default/cpufrequtils
			else
				# check cpufreq since not every value is possible
				for i in $(awk -F" " '{print $1}' </sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state | sed 's/000$//') ; do
					if [ $i -ge ${MaxClockspeed} ]; then
						sed -i "s/MAX_SPEED=\(.*\)/MAX_SPEED=${i}000/" /etc/default/cpufrequtils
						break
					fi
				done
			fi
			
		;;
	esac
	
	# dram clockspeed in mhz
	case ${DramClockspeed} in
		"")
			: ;;
		*)
			BOARD=$(awk -F"=" '/^BOARD=/ {print $2}' </etc/armbian-release)
			case ${BOARD} in
				nanopineo|nanopiair)
					HardwareUpperLimit=432
					;;
				*)
					HardwareUpperLimit=624
					;;
			esac
			if [ ${DramClockspeed} -lt ${DRAMLowerLimit} ]; then
				# adjust to lowest allowed clockspeed
				DramClockspeed=${DRAMLowerLimit}
			elif [ ${DramClockspeed} -gt ${HardwareUpperLimit} ]; then
				# adjust to highest allowed clockspeed
				DramClockspeed=${HardwareUpperLimit}
			else
				# round dramfreq since not every value is possible: between 132 and 384 mhz
				# 12 mhz steps are possible, above 24 mhz steps
				if [ ${DramClockspeed} -le 384 ]; then
					RoundedValue=$(( ${DramClockspeed} / 12 ))
					DramClockspeed=$(( ${RoundedValue} * 12 ))
				else
					RoundedValue=$(( ${DramClockspeed} / 24 ))
					DramClockspeed=$(( ${RoundedValue} * 24 ))
				fi
			fi
			echo "echo ${DramClockspeed}000 >/sys/devices/platform/sunxi-ddrfreq/devfreq/sunxi-ddrfreq/userspace/set_freq" \
				>>"${RCLocalContents}"
			sed -i "s/dram_clk\ =\ \(.*\)/dram_clk = ${DramClockspeed}/" "${FexSettings}"
		;;
	esac
	
	# Active CPU cores
	case ${CPUCores} in
		""|4)
			# enable corekeeper
			sed -i -e 's/^corekeeper_enabled\ =\ 0/corekeeper_enabled = 1/g' "${FexSettings}"
			echo "# All CPU cores active" >>"${RCLocalContents}"
			;;
		3)
			# disable corekeeper and 1 core in /etc/rc.local
			sed -i -e 's/^corekeeper_enabled\ =\ 1/corekeeper_enabled = 0/g' "${FexSettings}"
			echo "echo 0 >/sys/devices/system/cpu/cpu\3/online" >>"${RCLocalContents}"
			;;
		2)
			# disable corekeeper and 2 cores in /etc/rc.local
			sed -i -e 's/^corekeeper_enabled\ =\ 1/corekeeper_enabled = 0/g' "${FexSettings}"
			echo "for i in 3 2; do echo 0 >/sys/devices/system/cpu/cpu\${i}/online; done" >>"${RCLocalContents}"
			;;
		1)
			# disable corekeeper and 3 cores in /etc/rc.local
			sed -i -e 's/^corekeeper_enabled\ =\ 1/corekeeper_enabled = 0/g' "${FexSettings}"
			echo "for i in 3 2 1; do echo 0 >/sys/devices/system/cpu/cpu\${i}/online; done" >>"${RCLocalContents}"
			;;
		*)
			echo "Parameter error: -c requires 1, 2, 3 or 4. Exiting" >&2
			exit 1
			;;
	esac

	# GPU/HDMI
	case ${GPUHDMI} in
		"")
			: ;;
		on)
			sed -i -e 's/^hdmi_used\ =\ 0/hdmi_used = 1/' \
				-e 's/^mali_used\ =\ 0/mali_used = 1/' \
				-e 's/^disp_init_enable\ =\ 0/disp_init_enable = 1/' "${FexSettings}"
			;;
		off)
			sed -i -e 's/^hdmi_used\ =\ 1/hdmi_used = 0/' \
				-e 's/^mali_used\ =\ 1/mali_used = 0/' \
				-e 's/^disp_init_enable\ =\ 1/disp_init_enable = 0/' "${FexSettings}"
			;;
		*)
			echo "Parameter error: -g requires either on or off. Exiting" >&2
			exit 1
			;;
	esac

	# USB
	case ${USBUsed} in
		"")
			: ;;
		on)
			sed -i -e 's/^usb_used\ =\ 0/usb_used = 1/g' "${FexSettings}"
			;;
		off)
			sed -i -e 's/^usb_used\ =\ 1/usb_used = 0/g' "${FexSettings}"
			;;
		*)
			echo "Parameter error: -u requires either on or off. Exiting" >&2
			exit 1
			;;
		esac
} # ChangeSettings

PrintActiveSettings() {
	# function that prints the active consumption relevant settings
	# cpu settings
	echo -e "Active settings:\n"
	HardwareLimit=$(awk -F" " '/^max_freq = / {print $3 / 1000000}' <"${FexSettings}")
	SoftwareLimit=$(awk -F"=" '/^MAX_SPEED/ {print $2 / 1000}' </etc/default/cpufrequtils)
	CountOfActiveCores=$(grep -c '^processor' /proc/cpuinfo)
	echo -e "cpu       ${SoftwareLimit} mhz allowed, ${HardwareLimit} mhz possible, ${CountOfActiveCores} cores active\n"
	# dram settings
	echo -e "dram      $(sed 's/000$//' </sys/devices/platform/sunxi-ddrfreq/devfreq/sunxi-ddrfreq/cur_freq) mhz\n"
	# display active or headless mode
	echo -e "hdmi/gpu  $(awk -F" " '/^hdmi_used/ {print $3}' <"${FexSettings}" | head -n 1 | sed -e 's/1/active/' -e 's/0/off/')\n"
	# USB ports active or disabled
	echo -e "usb ports $(awk -F" " '/^usb_used/ {print $3}' <"${FexSettings}" | head -n 1 | sed -e 's/1/active/' -e 's/0/off/')\n"
	# network
	ethtool eth0 >/dev/null 2>&1 && echo -e "eth0      $(ethtool eth0 | grep -E "Speed|Link d|Duplex" | tr "\n" " " | awk '{print $2"/"$4", Link: "$7}')\n"
	ListOfWiFis=$(iwconfig 2>&1 | grep -Ev "lo|tunl0|eth0" | grep -v "^ " | awk -F" " '{print $1}')
	for i in ${ListOfWiFis} ; do
		iwconfig $i
	done
} # PrintActiveSettings

DisplayUsage() {
	# check if stdout is a terminal...
	if test -t 1; then
		# see if it supports colors...
		ncolors=$(tput colors)
		if test -n "$ncolors" && test $ncolors -ge 8; then
			BOLD="$(tput bold)"
			NC='\033[0m' # No Color
			LGREEN='\033[1;32m'
		fi
	fi
	echo -e "Usage: ${BOLD}${0##*/} [-h/-H] [-p] [-g on|off] [-m max_cpufreq] [-c 1|2|3|4]\n       [-d dram_freq] [-D dram_freq] [-u on|off] [-e on|off|fast] ${NC}\n"
	echo -e "############################################################################"
	if [ ${FullUsage} ]; then
		echo -e "\nDetailed Description:"
		grep "^#" "$0" | grep -v "^#\!/bin/bash" | sed 's/^#//'
	fi
	echo -e "\n This tool allows to adjust a few consumption relevant settings of your\n H3 device. Use the following switches\n"
	echo -e " ${BOLD}-h|-H${NC}           displays help or verbose help text"
	echo -e " ${BOLD}-p${NC}              print currently active settings"
	echo -e " ${BOLD}-g on|off${NC}       disables GPU/HDMI for headless use"
	echo -e " ${BOLD}-m max_cpufreq${NC}  adjusts maximum allowed cpu clockspeed (mhz)"
	echo -e " ${BOLD}-c 1|2|3|4${NC}      activate only this count of CPU cores"
	echo -e " ${BOLD}-d dram_freq${NC}    adjusts dram clockspeed (408 - 624 mhz)"
	echo -e " ${BOLD}-D dram_freq${NC}    like -d but as low as 132 mhz possible (experimental!)"
	echo -e " ${BOLD}-u on|off${NC}       enables/disabled all USB ports"
	echo -e " ${BOLD}-e on|off|fast${NC}  enables/disables Ethernet, the fast switch\n                 forces 100 mbits/sec negotiation on gigabit devices"
	echo -e " ${BOLD}-w on|off${NC}       enables/disables Wi-Fi powermanagement when interface\n                 supports this and is controlled by network-manager\n"
	echo -e "############################################################################\n"
} # DisplayUsage

ReadSettings() {
	# This function parses script.bin and install needed tools if necessary

	# check whether we've the necessary tools available
	Fex2Bin="$(which fex2bin)"
	if [ "X${Fex2Bin}" = "X" ]; then
	        apt-get -f -qq -y install sunxi-tools >/dev/null 2>&1 || InstallSunxiTools >/dev/null 2>&1
	fi
	which fex2bin >/dev/null 2>&1 || (echo -e "Aborted\nfex2bin/bin2fex not found and unable to install. Exiting" >&2 ; exit 1)
	
	# convert script.bin to temporary fex file	
	bin2fex /boot/script.bin "${FexSettings}" >/dev/null 2>&1
} # ReadSettings

FinalizeSettings() {
	# convert modified fex file back to script.bin, modify /etc/rc.local

	# create copy and backup to be able to recover from failed conversion
	cd /boot
	if [ -L script.bin ]; then
		Original="$(readlink -f script.bin)" && (rm script.bin ; cp -p "${Original}" script.bin)
	fi
	cp -p script.bin script.bin.bak
	
	fex2bin "${FexSettings}" /boot/script.bin 2>/dev/null
	if [ $? -ne 0 ]; then
	        mv /boot/script.bin.bak /boot/script.bin
	        echo -e "Aborted\nWriting script.bin went wrong. Nothing changed." >&2
	        logger "Writing script.bin went wrong. Nothing changed"
	        exit 1
	fi
	
	if [ -s "${RCLocalContents}" ];then
		# Adjust /etc/rc.local contents if necessary, first create clean file without h3consumption
		# additions
		grep -Ev "exit\s*0|h3consumption|sun8i-corekeeper" /etc/rc.local | sed '/^\s*$/d' >"${FexSettings}"
		echo -e "\n### do NOT edit the following lines, always use h3consumption instead ###" >>"${FexSettings}"
		cat "${RCLocalContents}" | while read ; do
			echo -e "${REPLY} # h3consumption" >>"${FexSettings}"
		done
		echo -e "\nexit 0" >>"${FexSettings}"
		cat "${FexSettings}" >/etc/rc.local
		rm "${RCLocalContents}"
	fi
	rm "${FexSettings}" 
} # FinalizeSettings

InstallSunxiTools() {
	sleep 1
	apt-get -f -qq -y install libusb-1.0-0-dev || (echo -e "Aborted\nNot possible to install a sunxi-tools requirement" ; exit 1)
	cd /tmp
	git clone https://github.com/linux-sunxi/sunxi-tools
	cd sunxi-tools
	make
	make install
} # InstallSunxiTools

Main "$@"