ublox-config: Merge all modem scripts in one
Features:
- Settings USB ECM mode and bridge mode
- SIM switch (auto or according to sim.conf)
- SW reset instead of HW reset
- Supports private APN through apn.conf file
- Now volatile config
- Dump running config
BugzID: 57321
BugZID: 57325
This commit is contained in:
parent
8cea86285c
commit
4f1be4fe1b
|
|
@ -1,76 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import serial
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
|
||||
|
||||
CONF_PATH = '/run/modem'
|
||||
ser = serial.Serial('/dev/ttyACM0', 115200, timeout=0.5)
|
||||
while True:
|
||||
try:
|
||||
ser.read()
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
os.makedirs(CONF_PATH, exist_ok=True)
|
||||
config_full_file = open(CONF_PATH + '/modem-at.config', 'w')
|
||||
config_file = open(CONF_PATH + '/modem.config', 'w')
|
||||
|
||||
|
||||
def usb_profile_parser(output):
|
||||
x = re.search('UUSBCONF:\s\d,"(.*)",', output)
|
||||
return x.group(1)
|
||||
|
||||
def mode_parser(output):
|
||||
x = re.search('UBMCONF:\s(\d)', output)
|
||||
mode = int(x.group(1))
|
||||
if mode == 1:
|
||||
return "Router"
|
||||
elif mode == 2:
|
||||
return "Bridge"
|
||||
else:
|
||||
return "unsupported"
|
||||
|
||||
def apn_parser(output):
|
||||
x = re.search('","(.*)",', output)
|
||||
return x.group(1)
|
||||
|
||||
def default_parser(output):
|
||||
x = re.search('(.*)\n.*\nOK',output)
|
||||
return x.group(1)
|
||||
|
||||
def read_config(cmd, label='', parser=default_parser):
|
||||
while True:
|
||||
try:
|
||||
ser.flushInput()
|
||||
ser.write(cmd)
|
||||
ser.write(b'\r')
|
||||
s = ser.read_until(b'OK')
|
||||
if(len(s.decode('utf-8')) < 4): # Avoid empty response just after reset
|
||||
continue
|
||||
break
|
||||
except Exception as e:
|
||||
print("Exception : " + str(e))
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
config_full_file.write(label + '\n')
|
||||
config_full_file.write(s.decode('utf-8').strip("OK"))
|
||||
|
||||
config_file.write((label + ':').ljust(20))
|
||||
config_file.write(parser(s.decode('utf-8')) + '\n')
|
||||
|
||||
read_config(b'AT+CGMI', 'VendorID')
|
||||
read_config(b'AT+CGMM', 'ModelID')
|
||||
read_config(b'AT+CGMR', 'Firmware')
|
||||
|
||||
config_full_file.write('-' * 80 + '\n' * 2)
|
||||
|
||||
read_config(b'AT+UCGDFLT?', 'Default APN', apn_parser)
|
||||
read_config(b'AT+UBMCONF?', 'Mode', mode_parser)
|
||||
read_config(b'AT+UUSBCONF?', 'USBprofile', usb_profile_parser)
|
||||
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
[Unit]
|
||||
Before=ModemManager.service
|
||||
After=sim-config.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/modem-config-dump
|
||||
|
||||
[Install]
|
||||
WantedBy=ModemManager.service
|
||||
|
||||
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
SUMMARY = "Dump of the modem config"
|
||||
DESCRIPTION = "Dump the config of the modem for debugging purposes"
|
||||
AUTHOR = "Alexandre Bard"
|
||||
|
||||
SECTION = "connectivity"
|
||||
LICENSE = "GPLv2+"
|
||||
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
|
||||
PR = "r2"
|
||||
|
||||
RDEPENDS_${PN}="python3-pyserial"
|
||||
|
||||
inherit systemd
|
||||
|
||||
SRC_URI = " \
|
||||
file://modem-config-dump.service \
|
||||
file://modem-config-dump.py \
|
||||
"
|
||||
|
||||
S = "${WORKDIR}"
|
||||
|
||||
INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
|
||||
|
||||
SYSTEMD_SERVICE_${PN} = "modem-config-dump.service"
|
||||
SYSTEMD_AUTO_ENABLE ?= "enable"
|
||||
|
||||
FILES_${PN}_append = " \
|
||||
/lib \
|
||||
/usr \
|
||||
"
|
||||
|
||||
do_install () {
|
||||
install -d ${D}${systemd_unitdir}/system/
|
||||
install -m 0644 modem-config-dump.service ${D}${systemd_unitdir}/system/
|
||||
|
||||
install -d ${D}/usr/bin
|
||||
install -m 0755 modem-config-dump.py ${D}/usr/bin/modem-config-dump
|
||||
}
|
||||
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import serial
|
||||
import os
|
||||
import time
|
||||
import configparser
|
||||
import sys
|
||||
|
||||
CONFIG = '/etc/sim.conf'
|
||||
SERIAL_DEV = '/dev/ttyACM0'
|
||||
GPIO_PATH = '/sys/class/gpio/'
|
||||
GPIO_SIM_SW = '44'
|
||||
GPIO_SIM_RST = '57'
|
||||
RST_FILE = '/tmp/modem-reset-required'
|
||||
|
||||
rst = False
|
||||
|
||||
def write_to_file(file, value):
|
||||
f = open(file, 'w')
|
||||
f.write(value)
|
||||
f.close()
|
||||
|
||||
def reset_modem():
|
||||
print("modem reset")
|
||||
write_to_file(GPIO_PATH + 'export', GPIO_SIM_RST)
|
||||
write_to_file(GPIO_PATH + 'gpio' + GPIO_SIM_RST + '/direction', 'out')
|
||||
write_to_file(GPIO_PATH + 'gpio' + GPIO_SIM_RST + '/value', '1')
|
||||
time.sleep(2)
|
||||
write_to_file(GPIO_PATH + 'gpio' + GPIO_SIM_RST + '/value', '0')
|
||||
# Wait until modem rebooted
|
||||
while os.path.exists('/dev/ttyACM0'):
|
||||
time.sleep(1)
|
||||
while not os.path.exists('/dev/ttyACM0'):
|
||||
time.sleep(1)
|
||||
print("reset done")
|
||||
|
||||
def is_rst_required():
|
||||
global rst
|
||||
if rst:
|
||||
return True
|
||||
elif os.path.exists(RST_FILE):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def switch_sim():
|
||||
global rst
|
||||
write_to_file(GPIO_PATH + 'export', GPIO_SIM_SW)
|
||||
write_to_file(GPIO_PATH + 'gpio' + GPIO_SIM_SW + '/direction', 'out')
|
||||
write_to_file(GPIO_PATH + 'gpio' + GPIO_SIM_SW + '/value', '0')
|
||||
rst = True
|
||||
|
||||
def sim_present(ser):
|
||||
cmd = b'AT+CCID?'
|
||||
while True:
|
||||
try:
|
||||
ser.flushInput()
|
||||
ser.write(cmd)
|
||||
ser.write(b'\r')
|
||||
s = ser.read_until(b'OK')
|
||||
if b'ERROR' in s:
|
||||
return False
|
||||
elif b'OK' in s:
|
||||
return True
|
||||
except Exception as e:
|
||||
print("Exception : " + str(e))
|
||||
time.sleep(1)
|
||||
|
||||
return s
|
||||
|
||||
|
||||
def check_sim_presence():
|
||||
while not os.path.exists(SERIAL_DEV):
|
||||
time.sleep(1)
|
||||
|
||||
ser = serial.Serial(SERIAL_DEV, 115200, timeout=0.5)
|
||||
while True:
|
||||
try:
|
||||
ser.read()
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if sim_present(ser):
|
||||
print("sim present")
|
||||
else:
|
||||
print("no sim, switching to esim")
|
||||
switch_sim()
|
||||
ser.close()
|
||||
|
||||
def read_config():
|
||||
config = configparser.ConfigParser()
|
||||
config.read(CONFIG)
|
||||
print(config.get('default', 'SIM'))
|
||||
sim = config.get('default', 'SIM')
|
||||
if sim == 'auto':
|
||||
check_sim_presence()
|
||||
elif sim == 'esim' or sim == 'ui-top':
|
||||
switch_sim()
|
||||
# ui-btm and main are default
|
||||
if is_rst_required():
|
||||
reset_modem()
|
||||
|
||||
|
||||
read_config();
|
||||
|
||||
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
[Unit]
|
||||
After=ublox-config.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/sim-config
|
||||
|
||||
[Install]
|
||||
WantedBy=ModemManager.service
|
||||
|
||||
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
SUMMARY = "Select the wanted sim card"
|
||||
DESCRIPTION = "Allows to select which sim card to use from a config file"
|
||||
AUTHOR = "Alexandre Bard"
|
||||
|
||||
SECTION = "connectivity"
|
||||
LICENSE = "GPLv2+"
|
||||
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
|
||||
PR = "r2"
|
||||
|
||||
RDEPENDS_${PN}="python3-pyserial"
|
||||
|
||||
inherit systemd
|
||||
|
||||
SRC_URI = " \
|
||||
file://sim-config.service \
|
||||
file://sim-config.py \
|
||||
file://sim.conf \
|
||||
"
|
||||
|
||||
S = "${WORKDIR}"
|
||||
|
||||
INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
|
||||
|
||||
SYSTEMD_SERVICE_${PN} = "sim-config.service"
|
||||
SYSTEMD_AUTO_ENABLE ?= "enable"
|
||||
|
||||
FILES_${PN}_append = " \
|
||||
/lib \
|
||||
/usr \
|
||||
/etc \
|
||||
"
|
||||
|
||||
do_install () {
|
||||
install -d ${D}${systemd_unitdir}/system/
|
||||
install -m 0644 sim-config.service ${D}${systemd_unitdir}/system/
|
||||
|
||||
install -d ${D}/usr/bin
|
||||
install -m 0755 sim-config.py ${D}/usr/bin/sim-config
|
||||
|
||||
install -d ${D}/etc
|
||||
install -m 0644 sim.conf ${D}/etc/
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import serial
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
|
||||
CONF_PATH = '/run/modem'
|
||||
|
||||
|
||||
def usb_profile_parser(output):
|
||||
x = re.search('UUSBCONF:\s\d,"(.*)",', output)
|
||||
return x.group(1)
|
||||
|
||||
def mode_parser(output):
|
||||
x = re.search('UBMCONF:\s(\d)', output)
|
||||
mode = int(x.group(1))
|
||||
if mode == 1:
|
||||
return "Router"
|
||||
elif mode == 2:
|
||||
return "Bridge"
|
||||
else:
|
||||
return "unsupported"
|
||||
|
||||
def apn_parser(output):
|
||||
x = re.search('","(.*)",', output)
|
||||
return x.group(1)
|
||||
|
||||
def default_parser(output):
|
||||
x = re.search('(.*)\n.*\nOK',output)
|
||||
return x.group(1)
|
||||
|
||||
def read_config(ser, config_file, full_config_file, cmd, label='', parser=default_parser):
|
||||
|
||||
while True:
|
||||
try:
|
||||
ser.flushInput()
|
||||
ser.write(cmd)
|
||||
ser.write(b'\r')
|
||||
s = ser.read_until(b'OK')
|
||||
if(len(s.decode('utf-8')) < 4): # Avoid empty response just after reset
|
||||
continue
|
||||
break
|
||||
except Exception as e:
|
||||
print("Exception : " + str(e))
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
full_conf = label + '\n' + s.decode('utf-8').strip("OK")
|
||||
conf = (label + ':').ljust(20) + parser(s.decode('utf-8')) + '\n'
|
||||
|
||||
full_config_file.write(full_conf)
|
||||
config_file.write(conf)
|
||||
|
||||
def dump_modem_config(ser):
|
||||
os.makedirs(CONF_PATH, exist_ok=True)
|
||||
full_config_file = open(CONF_PATH + '/modem-at.config', 'w')
|
||||
config_file = open(CONF_PATH + '/modem.config', 'w')
|
||||
|
||||
read_config(ser, config_file, full_config_file, b'AT+CGMI', 'VendorID')
|
||||
read_config(ser, config_file, full_config_file, b'AT+CGMM', 'ModelID')
|
||||
read_config(ser, config_file, full_config_file, b'AT+CGMR', 'Firmware')
|
||||
|
||||
full_config_file.write('-' * 80 + '\n' * 2)
|
||||
|
||||
read_config(ser, config_file, full_config_file, b'AT+UCGDFLT?', 'Default APN', apn_parser)
|
||||
read_config(ser, config_file, full_config_file, b'AT+UBMCONF?', 'Mode', mode_parser)
|
||||
read_config(ser, config_file, full_config_file, b'AT+UUSBCONF?', 'USBprofile', usb_profile_parser)
|
||||
|
|
@ -4,18 +4,25 @@ import serial
|
|||
import sys
|
||||
import time
|
||||
import os
|
||||
import configparser
|
||||
config_dump = __import__("modem-config-dump")
|
||||
|
||||
MAX_TRY = 5
|
||||
tries = 0
|
||||
SERIAL_DEV = '/dev/ttyACM0'
|
||||
WWAN_DEV = '/sys/class/net/wwan0'
|
||||
SIM_CONFIG = '/etc/sim.conf'
|
||||
APN_CONFIG = '/etc/apn.conf'
|
||||
GPIO_PATH = '/sys/class/gpio/'
|
||||
GPIO_SIM_SW = '44'
|
||||
APN_CONFIG = '/etc/apn.conf'
|
||||
|
||||
while not os.path.exists(SERIAL_DEV):
|
||||
time.sleep(1)
|
||||
def write_to_file(file, value):
|
||||
f = open(file, 'w')
|
||||
f.write(value)
|
||||
f.close()
|
||||
|
||||
ser = serial.Serial(SERIAL_DEV, 115200, timeout=0.5)
|
||||
|
||||
def execute_and_check(cmd):
|
||||
global tries
|
||||
def execute_and_check(ser, cmd):
|
||||
tries = 0
|
||||
MAX_TRY = 5
|
||||
ser.flushInput()
|
||||
ser.write(cmd)
|
||||
ser.write(b'\r')
|
||||
|
|
@ -26,25 +33,123 @@ def execute_and_check(cmd):
|
|||
tries += 1
|
||||
if tries < MAX_TRY:
|
||||
time.sleep(1)
|
||||
execute_and_check(cmd)
|
||||
execute_and_check(ser, cmd)
|
||||
else:
|
||||
sys.exit(-1)
|
||||
tries = 0
|
||||
|
||||
def switch_sim():
|
||||
write_to_file(GPIO_PATH + 'export', GPIO_SIM_SW)
|
||||
write_to_file(GPIO_PATH + 'gpio' + GPIO_SIM_SW + '/direction', 'out')
|
||||
write_to_file(GPIO_PATH + 'gpio' + GPIO_SIM_SW + '/value', '0')
|
||||
|
||||
print("Setting up bridge mode")
|
||||
execute_and_check(b'AT+UBMCONF=2')
|
||||
def sim_present(ser):
|
||||
cmd = b'AT+CCID?'
|
||||
while True:
|
||||
try:
|
||||
ser.flushInput()
|
||||
ser.write(cmd)
|
||||
ser.write(b'\r')
|
||||
s = ser.read_until(b'OK')
|
||||
if b'ERROR' in s:
|
||||
return False
|
||||
elif b'OK' in s:
|
||||
return True
|
||||
except Exception as e:
|
||||
print("Exception : " + str(e))
|
||||
time.sleep(1)
|
||||
|
||||
return s
|
||||
|
||||
def check_sim_presence(ser):
|
||||
if sim_present(ser):
|
||||
print("sim present")
|
||||
return False
|
||||
else:
|
||||
print("no sim, switching to esim")
|
||||
switch_sim()
|
||||
return True
|
||||
|
||||
print("Setting up USB mode to ECM")
|
||||
execute_and_check(b'AT+UUSBCONF=2,"ECM",0')
|
||||
def sim_config(ser):
|
||||
config = configparser.ConfigParser()
|
||||
config.read(SIM_CONFIG)
|
||||
sim = config.get('default', 'SIM')
|
||||
print(sim)
|
||||
if sim == 'auto':
|
||||
return check_sim_presence(ser)
|
||||
elif sim == 'esim' or sim == 'ui-top':
|
||||
switch_sim()
|
||||
return True
|
||||
# ui-btm and main are default
|
||||
return False
|
||||
|
||||
def apn_setup(ser):
|
||||
if not os.path.exists(APN_CONFIG):
|
||||
print('No APN configured')
|
||||
return
|
||||
|
||||
print("Resetting modem")
|
||||
# Let the reset be done by sim-config to avoid 2 resets
|
||||
# ser.write(b'AT+CFUN=16\r')
|
||||
f = open('/tmp/modem-reset-required', 'w')
|
||||
f.write('1')
|
||||
f.close()
|
||||
config = configparser.ConfigParser()
|
||||
config.read(APN_CONFIG)
|
||||
|
||||
ser.close()
|
||||
try:
|
||||
apn = config.get('default', 'apn')
|
||||
except:
|
||||
print('apn.conf malformed : no apn found\n')
|
||||
return
|
||||
try:
|
||||
user = '"' + config.get('default', 'user') + '"'
|
||||
try:
|
||||
password = '"' + config.get('default', 'password') + '"'
|
||||
except:
|
||||
print("No password for APN")
|
||||
password = 'NULL'
|
||||
except:
|
||||
print("No user for APN")
|
||||
user = 'NULL'
|
||||
password = 'NULL'
|
||||
|
||||
if not apn:
|
||||
return
|
||||
auth = '1' if user is not 'NULL' else '0'
|
||||
print("Switching to airplane mode")
|
||||
execute_and_check(ser, b'AT+CFUN=4\r')
|
||||
|
||||
print("Configuring default ctx")
|
||||
cmd = 'AT+UCGDFLT=0,"IP","' + str(apn) + '",0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,' + auth + ',' + str(user) + ',' + str(password) + ',""\r'
|
||||
execute_and_check(ser, bytes(cmd, 'utf8'))
|
||||
|
||||
print("Full functionality mode")
|
||||
execute_and_check(ser, b'AT+CFUN=1\r')
|
||||
|
||||
def main():
|
||||
rst = False
|
||||
# Wait on device
|
||||
while not os.path.exists(SERIAL_DEV):
|
||||
time.sleep(1)
|
||||
ser = serial.Serial(SERIAL_DEV, 115200, timeout=0.5)
|
||||
|
||||
if not os.path.exists(WWAN_DEV):
|
||||
print("Setting up bridge mode")
|
||||
execute_and_check(ser, b'AT+UBMCONF=2')
|
||||
|
||||
print("Setting up USB mode to ECM")
|
||||
execute_and_check(ser, b'AT+UUSBCONF=2,"ECM",0')
|
||||
rst = True
|
||||
rst = sim_config(ser) or rst
|
||||
if rst:
|
||||
print("Resetting modem")
|
||||
ser.write(b'AT+CFUN=16\r')
|
||||
|
||||
ser.close()
|
||||
while os.path.exists(SERIAL_DEV):
|
||||
time.sleep(1)
|
||||
while not os.path.exists(SERIAL_DEV):
|
||||
time.sleep(1)
|
||||
ser = serial.Serial(SERIAL_DEV, 115200, timeout=0.5)
|
||||
|
||||
apn_setup(ser)
|
||||
config_dump.dump_modem_config(ser)
|
||||
ser.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
[Unit]
|
||||
Before=sim-config.service
|
||||
Before=ModemManager.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/bash -c "ifconfig wwan0 && { echo 'already configured'; exit 0; };/usr/bin/ublox-config;"
|
||||
ExecStart=/usr/bin/ublox-config
|
||||
|
||||
[Install]
|
||||
WantedBy=ModemManager.service
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@ PR = "r2"
|
|||
|
||||
RDEPENDS_${PN}="python3-pyserial"
|
||||
|
||||
inherit systemd
|
||||
inherit systemd python3-dir
|
||||
|
||||
SRC_URI = " \
|
||||
file://ublox-config.service \
|
||||
file://ublox-config.py \
|
||||
file://modem-config-dump.py \
|
||||
file://sim.conf \
|
||||
"
|
||||
|
||||
S = "${WORKDIR}"
|
||||
|
|
@ -34,5 +36,13 @@ do_install () {
|
|||
|
||||
install -d ${D}/usr/bin
|
||||
install -m 0755 ublox-config.py ${D}/usr/bin/ublox-config
|
||||
|
||||
install -d ${D}${PYTHON_SITEPACKAGES_DIR}
|
||||
install -m 0755 modem-config-dump.py ${D}${PYTHON_SITEPACKAGES_DIR}/
|
||||
|
||||
install -d ${D}/etc
|
||||
install -m 0644 sim.conf ${D}/etc/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue