Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Public domain sources for NDIS mode dialer for e173 modem

428 views
Skip to first unread message

Wojciech M. Zabolotny

unread,
Sep 21, 2011, 10:23:04 AM9/21/11
to
Archive-name: e173-dialer
Submitted-by: Wojciech M. Zabolotny wzab<at>ise.pw.edu.pl

This is my first, quick and dirty dialer for e173-u2 in NDIS mode.
The archive contains:
1. 10-huawei-e173.rules , which should be located in /etc/udev/rules.d
2. wwan0_off and wwan0_on , which should be placed in /usr/local/bin
3. wwan0_on_off, which should be placed in /etc/sudoers.d
4. e173.glade, which should be placed in the same directory in
which you'll execute e173.py
5. e173.py itself

To avoid running the Python script with GUI from the root account,
I have splited the functionalities between the e173.py script
and two shell scripts (wwan0_on and wwan0_off), which may be run
with sudo by all members of the "dialout" group (as defined
in wwan0_on_off).
I've noticed, that sometimes different interfaces od e173 are
asigned to ttyUSB* nodes in different order. This is solved
by use of the 10-huawei-e173.rules.
The dialer uses four different threads - one for GUI, one
for sending commands to e173, one for receiving responses,
and the last one for monitoring of the pcui port.
Handling of modem responses should be improved - the thread
should detect not only "OK", but also "ERROR" and
probably "COMMAND NOT SUPPORT". Feel free to improve it ;-).

All the sources are published as PUBLIC DOMAIN and
WITHOUT ANY WARRANTY.
Use it only on your own risk!
Developing this dialer, I've used information found in many
websites, eg.:
http://jdtech.pl/2011/09/aero2-zmiany-na-stronach-www.html#IDComment193304288
(in Polish)
http://www.draisberghof.de/usb_modeswitch/bb
The udev rules are based on the original rules provided in the driver
http://www.t-mobile.de/downloads/neu/linux_driver_4.19.00.00.zip

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.11).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh09935
# Made on 2011-09-21 16:18 CEST by <wzab@wzlaphp>.
# Source directory was `/home/wzab/biezace/aero2_starter/pub'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 497 -rw-r--r-- 10-huawei-e173.rules
# 2922 -rw-r--r-- e173.glade
# 6419 -rwxr--r-- e173.py
# 65 -rwxr-xr-x wwan0_off
# 82 -rwxr-xr-x wwan0_on
# 99 -r--r--r-- wwan0_on_off
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false

for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done

if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done

if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901

if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'

elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'

elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'

else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU `touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= 10-huawei-e173.rules ==============
if test -n "${keep_file}" && test -f '10-huawei-e173.rules'
then
${echo} "x - SKIPPING 10-huawei-e173.rules (file already exists)"
else
${echo} "x - extracting 10-huawei-e173.rules (text)"
sed 's/^X//' << 'SHAR_EOF' > '10-huawei-e173.rules' &&
SUBSYSTEMS=="usb", ATTRS{modalias}=="usb:v12D1p1436*", KERNEL=="ttyUSB*", ATTRS{bInterfaceNumber}=="00", ATTRS{bInterfaceProtocol}=="ff", SYMLINK="ttyUSB_utps_modem"
SUBSYSTEMS=="usb", ATTRS{modalias}=="usb:v12D1p1436*", KERNEL=="ttyUSB*", ATTRS{bInterfaceNumber}=="03", ATTRS{bInterfaceProtocol}=="ff", SYMLINK="ttyUSB_utps_diag"
SUBSYSTEMS=="usb", ATTRS{modalias}=="usb:v12D1p1436*", KERNEL=="ttyUSB*", ATTRS{bInterfaceNumber}=="04", ATTRS{bInterfaceProtocol}=="ff", SYMLINK="ttyUSB_utps_pcui"
SHAR_EOF
(set 20 11 09 21 15 52 26 '10-huawei-e173.rules'
eval "${shar_touch}") && \
chmod 0644 '10-huawei-e173.rules'
if test $? -ne 0
then ${echo} "restore of 10-huawei-e173.rules failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} '10-huawei-e173.rules': 'MD5 check failed'
) << \SHAR_EOF
c13ec668ef0519d1f20b22e2e3b4fa39 10-huawei-e173.rules
SHAR_EOF
else
test `LC_ALL=C wc -c < '10-huawei-e173.rules'` -ne 497 && \
${echo} "restoration warning: size of '10-huawei-e173.rules' is not 497"
fi
fi
# ============= e173.glade ==============
if test -n "${keep_file}" && test -f 'e173.glade'
then
${echo} "x - SKIPPING e173.glade (file already exists)"
else
${echo} "x - extracting e173.glade (text)"
sed 's/^X//' << 'SHAR_EOF' > 'e173.glade' &&
<?xml version="1.0" encoding="UTF-8"?>
<interface>
X <requires lib="gtk+" version="2.20"/>
X <object class="GtkWindow" id="mainwin">
X <property name="width_request">0</property>
X <property name="height_request">0</property>
X <property name="can_focus">False</property>
X <child>
X <object class="GtkVBox" id="box2">
X <property name="width_request">0</property>
X <property name="height_request">0</property>
X <property name="visible">True</property>
X <property name="can_focus">False</property>
X <child>
X <object class="GtkProgressBar" id="Strength">
X <property name="visible">True</property>
X <property name="can_focus">False</property>
X <property name="fraction">0.0</property>
X <property name="pulse_step">0.01</property>
X </object>
X <packing>
X <property name="expand">False</property>
X <property name="fill">True</property>
X <property name="position">0</property>
X </packing>
X </child>
X <child>
X <object class="GtkHButtonBox" id="buttonbox1">
X <property name="visible">True</property>
X <property name="can_focus">False</property>
X <property name="layout_style">start</property>
X <child>
X <object class="GtkButton" id="Connect">
X <property name="label" translatable="yes">Connect</property>
X <property name="visible">True</property>
X <property name="can_focus">True</property>
X <property name="receives_default">True</property>
X <property name="use_action_appearance">False</property>
X </object>
X <packing>
X <property name="expand">False</property>
X <property name="fill">True</property>
X <property name="position">0</property>
X </packing>
X </child>
X <child>
X <object class="GtkButton" id="Disconnect">
X <property name="label" translatable="yes">Disconnect</property>
X <property name="visible">True</property>
X <property name="can_focus">True</property>
X <property name="receives_default">True</property>
X <property name="use_action_appearance">False</property>
X </object>
X <packing>
X <property name="expand">False</property>
X <property name="fill">True</property>
X <property name="position">2</property>
X </packing>
X </child>
X </object>
X <packing>
X <property name="expand">False</property>
X <property name="fill">True</property>
X <property name="position">1</property>
X </packing>
X </child>
X </object>
X </child>
X </object>
</interface>
SHAR_EOF
(set 20 11 09 21 16 08 14 'e173.glade'
eval "${shar_touch}") && \
chmod 0644 'e173.glade'
if test $? -ne 0
then ${echo} "restore of e173.glade failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'e173.glade': 'MD5 check failed'
) << \SHAR_EOF
090364ba59ea48422242c2f7dd3b9cbd e173.glade
SHAR_EOF
else
test `LC_ALL=C wc -c < 'e173.glade'` -ne 2922 && \
${echo} "restoration warning: size of 'e173.glade' is not 2922"
fi
fi
# ============= e173.py ==============
if test -n "${keep_file}" && test -f 'e173.py'
then
${echo} "x - SKIPPING e173.py (file already exists)"
else
${echo} "x - extracting e173.py (text)"
sed 's/^X//' << 'SHAR_EOF' > 'e173.py' &&
#!/usr/bin/python
import os
import thread
import threading
import pygtk
pygtk.require("2.0")
import gtk
gtk.gdk.threads_init()
X
# This scripts allows you to control the NDIS connetion
# via e173-u2 modem.
# It also provides you with simple GUI showing the strength
# of the signal
X
#What is the maximum RSSI level reported by e173?
#I assume 30. Correct it, if you have more accurate information
rssi_max=30.0
class msg_fifo():
X def __init__(self):
X self.lock=threading.Condition()
X self.ready=threading.Condition()
X self.queue=[]
X def append(self,data):
X self.lock.acquire()
X self.queue.append(data)
X self.lock.notifyAll()
X self.lock.release()
X def pop(self,tmout):
X self.lock.acquire()
X if len(self.queue) == 0:
X self.lock.wait(tmout)
X if len(self.queue) == 0:
X self.lock.release()
X return None
X res=self.queue.pop(0)
X self.lock.release()
X return res
X def ack(self):
X self.lock.acquire()
X if len(self.queue)==0:
X self.ready.acquire()
X self.ready.notifyAll()
X self.ready.release()
X self.lock.release()
X def wait_ready(self):
X self.ready.acquire()
X self.ready.wait()
X self.ready.release()
X
responses = msg_fifo()
commands = msg_fifo()
X
class gui_class:
X def do_Connect(self):
X if not gui.required_connection:
X return
X commands.append("ATZ")
X commands.append("AT^NDISDUP=1,1,\"my_apn_name\"")
X commands.wait_ready()
X os.system("/usr/bin/sudo /usr/local/bin/wwan0_off")
X os.system("/usr/bin/sudo /usr/local/bin/wwan0_on")
X print "Connect"+"\n"
X return
X def cb_Connect(self,o):
X gui.required_connection = True
X self.do_Connect()
X return
X def cb_Disconnect(self,o):
X gui.required_connection = False
X self.do_Disconnect()
X return
X def do_Disconnect(self):
X commands.append("AT^NDISDUP=1,0")
X commands.wait_ready()
X os.system("/usr/bin/sudo /usr/local/bin/wwan0_off")
X print "Disconnect"+"\n"
X return
X def cb_Destroy(self,o):
X print "Destroy the window!\n"
X gui.exit_program=True
X gtk.main_quit()
X return
X def __init__(self):
X #Create GUI
X builder = gtk.Builder()
X builder.add_from_file("e173.glade")
X builder.connect_signals({})
X builder.get_object("Connect").connect("clicked",self.cb_Connect)
X builder.get_object("Disconnect").connect("clicked",self.cb_Disconnect)
X self.mainwin = builder.get_object("mainwin")
X self.mainwin.connect("destroy",self.cb_Destroy)
X self.strength = builder.get_object("Strength")
X self.mainwin.show()
X self.required_connection = False
X self.exit_program = False
X
resp_lock=thread.allocate_lock()
X
# I have noticed, that sometimes the me173-u2 modem resets
# spontaneously, and ttyUSB... ports disappear from the system
# Therefore the threads used to send command, receive responses
# and to monitor connection are run in a loop with exception
# handling
X
def sending(gui,out_fifo,in_fifo):
X modem="/dev/ttyUSB_utps_modem"
X while not gui.exit_program:
X try:
X out_file=open(modem,"w")
X except IOError:
X print "Can't open modem for writing\n"
X continue
X try:
X cmd=out_fifo.pop(None)
X out_file.write(cmd+"\r\n")
X out_file.flush()
X while not gui.exit_program:
X l = responses.pop(12)
X print l
X if l=="OK":
X out_fifo.ack()
X break
X except IOError:
X print "Modem write port has disappeared...\n"
X continue
X try:
X out_file.close()
X except IOError:
X pass
X
def receiving(gui,out_fifo):
X modem="/dev/ttyUSB_utps_modem"
X while not gui.exit_program:
X try:
X in_file=open(modem,"r")
X except IOError:
X print "No modem port\n"
X continue
X try:
X line=""
X while not gui.exit_program:
X c=in_file.read(1)
X if c=="\n" or c=="\r":
X out_fifo.append(line)
X line = ""
X else:
X line += c
X except IOError:
X print "Modem port disappeared\n"
X try:
X in_file.close()
X except IOError:
X pass
X
def monitoring(gui):
X monitor="/dev/ttyUSB_utps_pcui"
X while not gui.exit_program:
X try:
X in_file=open(monitor,"r")
X except IOError:
X #Service the opening error
X print "No PCUI port\n"
X continue
X try:
X line=""
X while not gui.exit_program:
X c=in_file.read(1)
X #print c+":"+hex(ord(c))
X if c=="\n" or c=="\r":
X print line
X #Now analyze the received line
X if line[0:6]=="^RSSI:":
X #Set the signal strength to the appropriate value
X print line+"\n"
X gtk.gdk.threads_enter()
X sig_level=int(line[6:])
X if sig_level==99:
X sig_level=0
X sig_level = sig_level/rssi_max
X if sig_level > 1:
X sig_level=1
X gui.strength.set_fraction(sig_level)
X gtk.gdk.threads_leave()
X elif line[0:7]=="^SRVST:":
X print line+"\n"
X #Set the connection status
X if line[7]=="1":
X gtk.gdk.threads_enter()
X gui.strength.set_text("Disconnected")
X gtk.gdk.threads_leave()
X #Disconnected, update the indicator and trigger reconnection
X gui.do_Connect()
X elif line[7]=="2":
X #Connected, update the indicator
X gtk.gdk.threads_enter()
X gui.strength.set_text("Connected")
X gtk.gdk.threads_leave()
X status=1
X line = ""
X else:
X line += c
X except IOError:
X print "PCUI port disappeared :-( \n"
X try:
X in_file.close()
X except IOError:
X continue
X continue
X
#Initialization of different threads...
print "gui\n"
gui = gui_class()
# Start the sending thread
print "sending\n"
snd_thread = thread.start_new_thread(sending,(gui,commands,responses))
# Start the receiving thread
print "receiving\n"
rcv_thread = thread.start_new_thread(receiving,(gui,responses,))
# Start the monitoring thread
print "monitoring\n"
mon_thread = thread.start_new_thread(monitoring,(gui,))
print "main loop\n"
gtk.gdk.threads_enter()
gtk.main()
gtk.gdk.threads_leave()
X
X
SHAR_EOF
(set 20 11 09 21 16 17 59 'e173.py'
eval "${shar_touch}") && \
chmod 0744 'e173.py'
if test $? -ne 0
then ${echo} "restore of e173.py failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'e173.py': 'MD5 check failed'
) << \SHAR_EOF
ae82c030176912bb4fb03626a30f2310 e173.py
SHAR_EOF
else
test `LC_ALL=C wc -c < 'e173.py'` -ne 6419 && \
${echo} "restoration warning: size of 'e173.py' is not 6419"
fi
fi
# ============= wwan0_off ==============
if test -n "${keep_file}" && test -f 'wwan0_off'
then
${echo} "x - SKIPPING wwan0_off (file already exists)"
else
${echo} "x - extracting wwan0_off (text)"
sed 's/^X//' << 'SHAR_EOF' > 'wwan0_off' &&
#!/bin/bash
/sbin/ifconfig wwan0 down
/usr/bin/killall dhclient
X
SHAR_EOF
(set 20 11 09 20 23 01 00 'wwan0_off'
eval "${shar_touch}") && \
chmod 0755 'wwan0_off'
if test $? -ne 0
then ${echo} "restore of wwan0_off failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wwan0_off': 'MD5 check failed'
) << \SHAR_EOF
056fb4e2e0ba608a6adf34d1b5b9a0b3 wwan0_off
SHAR_EOF
else
test `LC_ALL=C wc -c < 'wwan0_off'` -ne 65 && \
${echo} "restoration warning: size of 'wwan0_off' is not 65"
fi
fi
# ============= wwan0_on ==============
if test -n "${keep_file}" && test -f 'wwan0_on'
then
${echo} "x - SKIPPING wwan0_on (file already exists)"
else
${echo} "x - extracting wwan0_on (text)"
sed 's/^X//' << 'SHAR_EOF' > 'wwan0_on' &&
#!/bin/bash
/sbin/ifconfig wwan0 hw ether 00:01:02:03:04:05
/sbin/dhclient wwan0
X
SHAR_EOF
(set 20 11 09 20 23 02 00 'wwan0_on'
eval "${shar_touch}") && \
chmod 0755 'wwan0_on'
if test $? -ne 0
then ${echo} "restore of wwan0_on failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wwan0_on': 'MD5 check failed'
) << \SHAR_EOF
e8ea6cd60f5215eaa0d26eb21205003e wwan0_on
SHAR_EOF
else
test `LC_ALL=C wc -c < 'wwan0_on'` -ne 82 && \
${echo} "restoration warning: size of 'wwan0_on' is not 82"
fi
fi
# ============= wwan0_on_off ==============
if test -n "${keep_file}" && test -f 'wwan0_on_off'
then
${echo} "x - SKIPPING wwan0_on_off (file already exists)"
else
${echo} "x - extracting wwan0_on_off (text)"
sed 's/^X//' << 'SHAR_EOF' > 'wwan0_on_off' &&
%dialout ALL = NOPASSWD: /usr/local/bin/wwan0_on
%dialout ALL = NOPASSWD: /usr/local/bin/wwan0_off
SHAR_EOF
(set 20 11 09 20 23 10 00 'wwan0_on_off'
eval "${shar_touch}") && \
chmod 0444 'wwan0_on_off'
if test $? -ne 0
then ${echo} "restore of wwan0_on_off failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wwan0_on_off': 'MD5 check failed'
) << \SHAR_EOF
440b921dd51b85f660c7ed2748a2bdc5 wwan0_on_off
SHAR_EOF
else
test `LC_ALL=C wc -c < 'wwan0_on_off'` -ne 99 && \
${echo} "restoration warning: size of 'wwan0_on_off' is not 99"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0


wzab

unread,
Sep 21, 2011, 10:55:58 AM9/21/11
to
One important functionality, which is lacking in the e173.py is
locking of the modem port.
If someone knows how to do it reliably in a situation when our port is
accessible via symlink, please let me know.

wzab

unread,
Sep 21, 2011, 1:34:58 PM9/21/11
to
I've stated, that in some systems it is necessary to switch on
reporting on the ttyUSB_utps_pcui port.
To achieve that, one should send "AT^CURC=1" command to the
ttyUSB_utps_modem port.

Therefore the code:
[...]
def sending(gui,out_fifo,in_fifo):
modem="/dev/ttyUSB_utps_modem"
while not gui.exit_program:
try:
out_file=open(modem,"w")
except IOError:
print "Can't open modem for writing\n"
continue
try:
cmd=out_fifo.pop(None)
out_file.write(cmd+"\r\n")
out_file.flush()
[...]

Should be modified to:

[...]
def sending(gui,out_fifo,in_fifo):
modem="/dev/ttyUSB_utps_modem"
while not gui.exit_program:
try:
out_file=open(modem,"w")
out_file.write("AT^CURC=1\r\n")
out_file.flush()
except IOError:
print "Can't open modem for writing\n"
continue
try:
cmd=out_fifo.pop(None)
out_file.write(cmd+"\r\n")
out_file.flush()
[...]

wzab

unread,
Sep 21, 2011, 1:04:20 PM9/21/11
to

I don't know why, but in one of my systems the udev rules with SYMLINK
do not work, and I had to replace SYMLINK with NAME, as below:

SUBSYSTEMS=="usb", ATTRS{modalias}=="usb:v12D1p1436*",
KERNEL=="ttyUSB*", ATTRS{bInterfaceNumber}=="00",

ATTRS{bInterfaceProtocol}=="ff", NAME="ttyUSB_utps_modem"


SUBSYSTEMS=="usb", ATTRS{modalias}=="usb:v12D1p1436*",
KERNEL=="ttyUSB*", ATTRS{bInterfaceNumber}=="03",

ATTRS{bInterfaceProtocol}=="ff", NAME="ttyUSB_utps_diag"


SUBSYSTEMS=="usb", ATTRS{modalias}=="usb:v12D1p1436*",
KERNEL=="ttyUSB*", ATTRS{bInterfaceNumber}=="04",

ATTRS{bInterfaceProtocol}=="ff", NAME="ttyUSB_utps_pcui"

In another system (also Debian/testing) the version with "NAME" works,
but generates warnings, that
name provided by the kernel differs from the name in rule, and
suggests using SYMLINK...

0 new messages