Created
December 4, 2021 15:34
-
-
Save FlorianHeigl/684eccc28272de3c484af550566d4889 to your computer and use it in GitHub Desktop.
zte modemswitch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# source in blogpost comment at | |
# https://technicalexperiments.wordpress.com/2015/10/30/zte-mf831-for-use-with-openwrt-serial-modem-instead-of-cdc_ether/comment-page-1/ | |
wLog(){ | |
case $debug in | |
0) | |
logger "${0##*/}: $1" | |
;; | |
esac | |
return 0 | |
} | |
now(){ | |
let now=`date +%s` | |
echo $now | |
} | |
cleanup(){ | |
wLog "Removing Lockfile." | |
progname=$0 | |
proclist=$(echo -en "$(pgrep -s0 -lf ash; pgrep -lf ash)" | sort | uniq -u | awk '{ print $1 }') | |
for i in $proclist; do | |
kill $i; | |
done | |
[ -e /tmp/modem-reset.tmp ] && rm /tmp/modem-reset.tmp | |
return 0 | |
} | |
findttyUSB(){ | |
if [ $# -eq 0 ]; then | |
r="" | |
for i in $(find -L /sys/bus/usb/devices/ -maxdepth 2 -name "ttyUSB*"); do | |
egrep -i "v19d2p0016(.*)in02" $i/../modalias >/dev/null | |
if [ $? -eq 0 ]; then | |
r=`echo -en "$r $(echo "/dev/${i##*/}")\r\n"` | |
fi | |
done | |
echo $r | |
return 0 | |
else | |
case $1 in | |
"is_true") | |
for i in $(find -L /sys/bus/usb/devices/ -maxdepth 2 -name "ttyUSB*"); do | |
egrep -i "v19d2p0016(.*)in02" $i/../modalias >/dev/null | |
if [ $? -eq 0 ]; then | |
echo 0 | |
return 0 | |
fi | |
done | |
;; | |
esac | |
fi | |
echo 1 | |
return 0 | |
} | |
setModeModem(){ | |
if [ $(testRoute device) -eq 0 ]; then | |
prepareModeModem | |
if [ $# -ge 1 ]; then | |
wLog "setModeModem will now try to switch $1 ..." | |
/usr/bin/curl -d "goformId=USB_MODE_SWITCH&usb_mode=FACTORY" http://$1/goform/goform_set_cmd_process >/dev/null | |
wLog "setModeModem will now wait for a tty device to come up." | |
until [ $(findttyUSB is_true) -eq 0 ]; do | |
sleep 5 | |
done | |
else | |
wLog "setModeModem has been invoked without a target ip address. Not switching anything." | |
return 1 | |
fi | |
fi | |
return 0 | |
} | |
setModeEthernet(){ | |
let timeOut=$(now)+45 | |
modemMode=$(determineMode) | |
until [ $modemMode = "0016" ]; do | |
case $modemMode in | |
"1405") | |
wLog "Already found ZTE Ethernet device. Not switching. Bye." | |
return 0 | |
;; | |
*) | |
if [ $timeOut -le $(now) ]; then | |
wLog "setModeEthernet: Softly resetting USB after timeout." | |
usbSoftResetMF831 | |
fi | |
sleep 5 | |
modemMode=$(determineMode) | |
;; | |
esac | |
done | |
if [ $modemMode = "0016" ]; then | |
for chatfile in mf831-reboot mf831-modeswitch; do | |
until [ $(waitForUsbDevice 0) -eq 0 ]; do | |
sleep 5 | |
done | |
if [ $(determineMode) = "1405" ]; then | |
wLog "Already found ZTE Ethernet device. Not switching. Bye." | |
return 0 | |
fi | |
wLog "A device just came up." | |
let count=0 | |
until [ $(findttyUSB is_true) -eq 0 ] || [ $count -eq 6 ]; do | |
sleep 5 | |
let count++ | |
done | |
wLog "Modem terminals are now present." | |
for m in $(findttyUSB); do | |
wLog "Modem terminal found at $m." | |
pppproc=`pgrep -lf "pppd(.*)$m" | awk '{ print $1 }'` | |
if [ ${#pppproc} -gt 1 ]; then | |
kill -9 $pppproc | |
fi | |
sleep 2 | |
/usr/sbin/pppd debug $(echo ${m} | egrep -oe "/dev/[[:alnum:]]*") \ | |
115200 modem crtscts asyncmap 0 lock noauth nodetach \ | |
connect "/usr/sbin/chat -v -t 30 -f /etc/scripts/${chatfile}.chat" | |
sleep 10 | |
done | |
done | |
fi | |
let count=0 | |
until [ $(testRoute device) -eq 0 ] || [ $count -eq 3 ]; do | |
sleep 1 | |
let count++ | |
done | |
return 0 | |
} | |
prepareModeModem(){ | |
lsmod | grep "^option" >/dev/null || /usr/sbin/modprobe option | |
grep "19d2\ 0016" /sys/bus/usb-serial/drivers/option1/new_id >/dev/null || echo "19d2 0016 ff" | tee /sys/bus/usb-serial/drivers/option1/new_id | |
return 0 | |
} | |
createLockFile(){ | |
if [ $# -gt 0 ]; then | |
let offset=$1 | |
else | |
let offset=0 | |
fi | |
let timestamp=$(now)+offset | |
wLog "Creating lockfile with offset value $offset." | |
echo $timestamp > /tmp/modem-reset.tmp | |
return 0 | |
} | |
determineMode() { | |
mode=`lsusb -d 19d2: | egrep -oe "19d2\:([[:digit:]]){4}"` | |
if [ ${#mode} -gt 0 ]; then | |
id=`echo $mode | cut -d ":" -f2` | |
else | |
id="error" | |
fi | |
echo $id | |
return 0 | |
} | |
testEthernet(){ | |
let count=0 | |
let success=1 | |
until [ $success -eq 0 ]; do | |
LANGUAGE=POSIX ifconfig -a | egrep -oe "usb[[:digit:]]" >/dev/null | |
let success=$? | |
[ $success -gt 0 ] && sleep 3 | |
if [ $count -eq 6 ] && [ $# -eq 1 ]; then | |
echo $success | |
return $success | |
fi | |
let count++ | |
done | |
[ $success -eq 0 ] && wLog "Virtual USB Ethernet interface has just been detected." | |
if [ $# -eq 1 ]; then | |
echo $success | |
fi | |
return $success | |
} | |
pingtest(){ | |
ping -c3 -W3 $1 >/dev/null | |
let result=$? | |
if [ $# -ge 2 ]; then | |
echo $result | |
fi | |
return $result | |
} | |
waitForEthernet(){ | |
wLog "Waiting for USB ethernet device to appear." | |
let runs=0 | |
let isup=1 | |
until [ $isup -eq 0 ]; do | |
let isup=$(testEthernet 0) | |
if [ $runs -eq 6 ]; then | |
break | |
else | |
sleep 5 | |
fi | |
let runs++ | |
done | |
if [ $# -eq 1 ]; then | |
echo $isup | |
fi | |
return $isup | |
} | |
handleModemErrorConditions(){ | |
wLog "Error condition handler invoked." | |
if [ $# -eq 1 ]; then | |
let count=$1 | |
else | |
let count=1 | |
fi | |
until [ $count -eq 101 ]; do | |
case $count in | |
1) | |
wLog "Error condition handler tries ifupdown." | |
ifupdown usb0 | |
waitForEthernet | |
;; | |
2) | |
wLog "Error condition handler tries modreload and reset." | |
unloadResetLoad | |
waitForEthernet | |
;; | |
3) | |
wLog "Error condition handler tries modeswitching." | |
if [ $(ifconfig usb0 2&>1 /dev/null; echo $?) -eq 0 ]; then | |
if [ $(pingtest $modemip 0) -eq 0 ]; then | |
resetModem | |
waitForEthernet | |
fi | |
fi | |
;; | |
4) | |
wLog "Error condition handler tries usb soft reset." | |
usbSoftResetMF831 | |
waitForEthernet | |
;; | |
5) | |
wLog "Error condition handler tries usb hard reset." | |
usbReset | |
usbPowerCycle | |
waitForUsbDevice | |
;; | |
100) | |
wLog "Error condition handler gives up and triggers a reboot." | |
if [ $(testRoute device 1) -gt 0 ] || [ $(testRoute default 1) -gt 0 ] || [ $(pingtest $modemip 0) -gt 0 ]; then | |
wLog "Now going bananas... reboot." | |
reboot -f | |
fi | |
;; | |
*) | |
sleep 1 | |
;; | |
esac | |
if [ $(testRoute device 1) -eq 0 ] && [ $(testRoute default 1) -eq 0 ]; then | |
if [ $(pingtest $modemip 0) -eq 0 ]; then | |
if [ $(pingtest $externalip 0) -eq 0 ]; then | |
wLog "Recovery seems to be successful. Device and routes are now up." | |
echo 0 | |
return 0 | |
else | |
wLog "Recovery seemed successful, but internet test failed." | |
fi | |
fi | |
fi | |
let count++ | |
done | |
echo 1 | |
return 1 | |
} | |
testRoute(){ | |
case $1 in | |
"device") | |
invert="-v" | |
text="device" | |
text2="Device" | |
;; | |
default) | |
invert="" | |
text="default" | |
text2="Default" | |
;; | |
esac | |
case $2 in | |
[0-10]) | |
let runs=$2 | |
;; | |
*) | |
let runs=1 | |
esac | |
let re=1 | |
let count=0 | |
wLog "Looking for existing default route." | |
until [ $re -eq 0 ]; do | |
ip r s dev usb0 | grep $invert "default" >/dev/null | |
let re=$? | |
if [ $re -eq 0 ]; then | |
wLog "$1 route ok." | |
break | |
else | |
wLog "$1 route does not exist on try #$count." | |
fi | |
if [ $count -eq 2 ]; then | |
break | |
fi | |
sleep 3 | |
let count++ | |
done | |
echo $re | |
return $re | |
} | |
testInternet(){ | |
let isup=1 | |
if [ $(testRoute default) -eq 0 ]; then | |
let count=1 | |
until [ $isup -eq 0 ]; do | |
wLog "Now pinging internet hosts - try #$count." | |
let isup=$(pingtest $externalip 0) | |
if [ $count -eq 2 ];then | |
break | |
fi | |
if [ $isup -eq 0 ]; then | |
wLog "Ping test succeeded on try #$count." | |
break | |
else | |
sleep 10 | |
fi | |
let count++ | |
done | |
fi | |
echo $isup | |
return $isup | |
} | |
usbSoftResetMF831(){ | |
wLog "Performing usb reset on device." | |
for i in $(find -L /sys/bus/usb/devices/usb1 -maxdepth 3 -name "modalias"); do | |
j=`egrep -ioe "v19d2p1405|v19d2p0016" $i >/dev/null && echo ${i%%/*modalias}authorized` | |
echo 0 | tee ${j} | |
prepareModeModem | |
echo 1 | tee ${j} | |
sleep 20 | |
done | |
return 0 | |
} | |
resetModem(){ | |
setModeModem $modemip | |
setModeEthernet | |
return 0 | |
} | |
usbReset(){ | |
usbreset 19d2:1405 | |
usbreset 1a40:0101 | |
# for xhci in /sys/bus/usb/drivers/?hci_hcd ; do | |
for xhci in /sys/bus/platform/drivers/?hci-platform ; do | |
if ! cd $xhci ; then | |
echo Weird error. Failed to change directory to $xhci | |
exit 1 | |
fi | |
echo Resetting devices from $xhci... | |
for i in ????:??:??.? ; do | |
echo -n "$i" > unbind | |
echo -n "$i" > bind | |
done | |
done | |
} | |
usbPowerCycle(){ | |
pin="" | |
router=grep machine /proc/cpuinfo | egrep -oe "TL(.+)([[:alpha:]]+)([[:digit:]]{3,4})([[:alpha:]]{0,2})" | |
case $router in | |
"TL-MR3420") | |
pin=6 | |
;; | |
"TL-WR1043ND") | |
# pin=22 | |
pin="" | |
;; | |
esac | |
if [ ${#pin} -gt 0 ]; then | |
echo 0 > /sys/class/gpio/gpio${pin}/value | |
sleep 10 | |
echo 1 > /sys/class/gpio/gpio${pin}/value | |
fi | |
return 0 | |
} | |
ifupdown(){ | |
wLog "Now trying to toggle virtual ethernet interface status. This will initiate a dhcp request, too." | |
if [ $(lsmod | egrep "rndis_host|cdc_ether" >/dev/null && echo 0 || echo 1) -eq 0 ]; then | |
netif=$(uci show network | grep $1 | egrep -oe "\.(.*)\.ifname=" | cut -d "." -f2) | |
ifdown $netif | |
udhcpcproc=`ps w | grep udhcpc | grep usb0 | awk '{ print $1 }'` | |
if [ ${#udhcpcproc} -gt 1 ]; then | |
kill -9 $udhcpcproc | |
fi | |
ifup $netif | |
else | |
unloadResetLoad | |
fi | |
return 0 | |
} | |
unloadResetLoad(){ | |
wLog "removing modules, usbresetting modem, reloading" | |
rmmod rndis_host | |
rmmod cdc_ether | |
usbSoftResetMF831 | |
sleep 1 | |
modprobe cdc_ether | |
modprobe rndis_host | |
return 0 | |
} | |
waitForUsbDevice(){ | |
wLog "Waiting for USB device to initialize" | |
let runs=0 | |
let devhere=$(lsusb -d 19d2: | grep "0016\|1225\|1404\|1405" >/dev/null && echo 0 || echo 1) | |
until [ $devhere -eq 0 ]; do | |
let devhere=$(lsusb -d 19d2: | grep "0016\|1225\|1404\|1405" >/dev/null && echo 0 || echo 1) | |
if [ $devhere -eq 1 ] && [ $runs -eq 4 ]; then | |
wLog "USB device did not come up within 60 seconds after reset." | |
break | |
else | |
[ $runs -gt 0 ] && sleep 15 || sleep 3 | |
fi | |
let runs++ | |
done | |
if [ $# -eq 1 ]; then | |
echo $devhere | |
fi | |
return $devhere | |
} | |
recoveryProcedure(){ | |
[ $# -eq 1 ] && let force=0 || let force=1 | |
case $(determineMode) in | |
"0016") | |
wLog "Modem in serial mode detected. Modeswitching to ethernet mode by sending an AT command sequence." | |
setModeEthernet | |
;; | |
"0076") | |
wLog "Modem in real download mode detected. Resetting USB Power." | |
usbPowerCycle | |
;; | |
"1405") | |
wLog "Modem in ethernet mode detected." | |
if [ $force -eq 0 ] ; then | |
wLog "recovery forced: soft reset of modem forced." | |
resetModem | |
return $? | |
fi | |
wLog "Recovery is trying to resolve error conditions." | |
handleModemErrorConditions | |
return $? | |
;; | |
"error") | |
wLog "Modem not present or other problems...preparing for reboot (120s)." | |
sleep 120 | |
if [ $(determineMode) = "error" ]; then | |
reboot -f | |
fi | |
;; | |
esac | |
return 0 | |
} | |
main(){ | |
[ $# -eq 1 ] && let force=0 || let force=1 | |
if [ ! -e /tmp/modem-reset.tmp ] || [ $force -eq 0 ]; then | |
createLockFile 0 | |
let count=0 | |
until [ $(testInternet) -eq 0 ]; do | |
case $count in | |
[0-2]) | |
wLog "Entering recovery procedure." | |
recoveryProcedure $force | |
;; | |
3) | |
wLog "The recovery procedure has timed out." | |
return 1 | |
;; | |
esac | |
let count++ | |
done | |
wLog "Internet test succeeded on turn: $count." | |
else | |
wLog "Modem reset script exiting due to existing lockfile" | |
exit 1 | |
fi | |
return 0 | |
} | |
modemip='192.168.0.1' | |
externalip='8.8.4.4' | |
let debug=1 | |
let force=1 | |
if [ -e /tmp/modem-reset.tmp ]; then | |
let ageOfLockFileInSec=$(now)-`date -r /tmp/modem-reset.tmp +"%s"` | |
if [ $ageOfLockFileInSec -gt 300 ]; then | |
wLog "Stale lockfile detected. Removing it." | |
cleanup 0 | |
fi | |
fi | |
if [ $# -ge 1 ]; then | |
sortedparams=`printf "%s\n" $@ | sort -t " " -k2 | tr "\n" " "` | |
for i in $sortedparams; do | |
case $i in | |
"--help") | |
echo -en "usage:\r\n" | |
echo -en "\t$0 --help \r\n\t\t show this help message\r\n" | |
echo -en "\t$0 --debug \r\n\t\t force debug log\r\n" | |
echo -en "\t$0 --force \r\n\t\t force modem reset\r\n" | |
echo -en "\t$0 modem \r\n\t\t manually set serial modem mode on device\r\n" | |
echo -en "\t$0 ethernet \r\n\t\t manually set ethernet mode \(tethering\) on device\r\n" | |
echo -en "\t$0 status \r\n\t\t show current device state\r\n" | |
;; | |
"--debug") | |
let debug=0 | |
wLog "debug mode forced." | |
;; | |
"--force") | |
let debug=0 | |
wLog "Forcing reset." | |
main force | |
;; | |
"modem") | |
wLog "manually setting modem Mode on IP $modemip." | |
setModeModem $modemip | |
;; | |
"ethernet") | |
wLog "manually resetting to ethernet mode." | |
setModeEthernet | |
;; | |
"usb") | |
usbReset | |
;; | |
"status") | |
mode=$(determineMode) | |
case $mode in | |
"0016") | |
message="Modem is in serial mode ($mode)." | |
;; | |
"0076") | |
message="Modem is in download mode ($mode)." | |
;; | |
"1405") | |
message="Modem is in ethernet mode ($mode)." | |
;; | |
"1404") | |
message="Modem is in adb+cdc mode ($mode)." | |
;; | |
*) | |
message="Modem is in an unknown mode ($mode)." | |
;; | |
esac | |
echo $message | |
wLog $message | |
;; | |
esac | |
done | |
else | |
let debug=0 | |
main | |
cleanup | |
fi | |
exit 0 | |
Corresponding chat-files: | |
mf831-modeswitch.chat (+ZSNT:will reset to carrier mode autoselection (2g/3g/4g); +ZBANDI: will reset to band autoselection mode. You could try to add +ZOPRT=5 to reset to “always on” mode, but that didn’t work for me.) | |
ABORT 'BUSY' | |
ABORT 'NO CARRIER' | |
TIMEOUT 30 | |
ECHO ON | |
'' AT&F | |
OK ATE1 | |
OK AT+ZSNT=0,0,0 | |
OK AT+ZBANDI=0 | |
OK AT+ZCDRUN=9 | |
OK AT+ZCDRUN=F | |
mf831-reboot.chat: | |
ABORT 'BUSY' | |
ABORT 'NO CARRIER' | |
TIMEOUT 30 | |
ECHO ON | |
'' AT&F | |
OK ATE1 | |
OK AT+CFUN=1,1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
no warranties for this step:
reach like this
http://192.168.0.1/goform/goform_process?goformId=MODE_SWITCH&switchCmd=FACTORY