update to version 2.0

This commit is contained in:
fujr 2024-07-23 15:19:17 +08:00
parent 5f39470aba
commit 71c8a39a6e
91 changed files with 7217 additions and 11513 deletions

View File

@ -0,0 +1,22 @@
# Copyright (C) 2024 Tom <fjrcn@outlook.com>
# This is free software, licensed under the GNU General Public License v3.
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-5gmodem-hc
LUCI_TITLE:=hc-g50 sim switch
LUCI_PKGARCH:=all
PKG_VERSION:=2.0
PKG_LICENSE:=GPLv3
PKG_LINCESE_FILES:=LICENSE
PKF_MAINTAINER:=fujr
LUCI_DEPENDS:=+luci-app-5gmodem
define Package/luci-app-5gmodem-hc/conffiles
/etc/config/modem_sim
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,82 @@
module("luci.controller.modem_hc", package.seeall)
local http = require "luci.http"
local fs = require "nixio.fs"
local json = require("luci.jsonc")
function index()
--sim卡配置
entry({"admin", "network", "modem", "modem_sim"}, cbi("modem_hc/modem_sim"), luci.i18n.translate("SIM Config"), 23).leaf = true
entry({"admin", "network", "modem", "set_sim"}, call("setSIM"), nil).leaf = true
entry({"admin", "network", "modem", "get_sim"}, call("getSIM"), nil).leaf = true
end
function getSimSlot(sim_path)
local sim_slot = fs.readfile(sim_path)
local current_slot = string.match(sim_slot, "%d")
if current_slot == "0" then
return "SIM2"
else
return "SIM1"
end
end
function shell(command)
local odpall = io.popen(command)
local odp = odpall:read("*a")
odpall:close()
return odp
end
function getNextBootSlot()
local fw_print_cmd = "fw_printenv -n sim2"
local nextboot_slot = shell(fw_print_cmd)
if nextboot_slot == "" then
return "SIM1"
else
return "SIM2"
end
end
function writeJsonResponse(current_slot, nextboot_slot)
local result_json = {}
result_json["current_slot"] = current_slot
result_json["nextboot_slot"] = nextboot_slot
luci.http.prepare_content("application/json")
luci.http.write_json(result_json)
end
function getSIM()
local sim_path = "/sys/class/gpio/sim/value"
local current_slot = getSimSlot(sim_path)
local nextboot_slot = getNextBootSlot()
writeJsonResponse(current_slot, nextboot_slot)
end
function setSIM()
local sim_gpio = "/sys/class/gpio/sim/value"
local modem_gpio = "/sys/class/gpio/4g/value"
local sim_slot = http.formvalue("slot")
local pre_detect = getSimSlot(sim_gpio)
local reset_module = 1
if pre_detect == sim_slot then
reset_module = 0
end
if sim_slot == "SIM1" then
sysfs_cmd = "echo 1 >"..sim_gpio
fw_setenv_cmd = "fw_setenv sim2"
elseif sim_slot == "SIM2" then
sysfs_cmd = "echo 0 >"..sim_gpio
fw_setenv_cmd = "fw_setenv sim2 1"
end
shell(sysfs_cmd)
shell(fw_setenv_cmd)
if reset_module == 1 then
shell("echo 0 >"..modem_gpio)
os.execute("sleep 1")
shell("echo 1 >"..modem_gpio)
end
local current_slot = getSimSlot(sim_gpio)
local nextboot_slot = getNextBootSlot()
writeJsonResponse(current_slot, nextboot_slot)
end

View File

@ -0,0 +1,29 @@
m = Map("modem_sim", translate("SIM Settings"))
s = m:section(TypedSection, "global", translate("SIM Settings"))
s.anonymous = true
s.addremove = false
sim_auto_switch = s:option(Flag, "sim_auto_switch", translate("SIM Auto Switch"))
sim_auto_switch.default = "0"
detect_interval = s:option(Value, "detect_interval", translate("Network Detect Interval"))
detect_interval.default = 15
judge_time = s:option(Value, "judge_time", translate("Network Down Judge Times"))
judge_time.default = 5
ping_dest = s:option(DynamicList, "ping_dest", translate("Ping Destination"))
o = s:option(Value, "wwan_ifname", translate("WWAN Interface"))
o.description = translate("Please enter the WWAN interface name")
o.template = "cbi/network_netlist"
-- o.widget = "optional"
o.nocreate = true
o.default = "cpewan0"
m:section(SimpleSection).template = "modem_hc/modem_sim"
return m

View File

@ -0,0 +1,64 @@
<script>
function set_sim_view(slot){
let sim_current_slot = slot["current_slot"];
let sim_nextboot_slot = slot["nextboot_slot"];
sim_current_view = document.getElementById("sim_slot_current");
sim_nextboot_view = document.getElementById("sim_slot_nextboot");
sim_current_view.innerHTML = sim_current_slot;
sim_nextboot_view.innerHTML = sim_nextboot_slot;
}
function set_sim(){
select = document.getElementById("sim_slot_select");
slot = select.value;
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "modem", "set_sim")%>', {"slot": slot },
function (x, data) {
set_sim_view(data);
}
);
}
window.onload=function(){
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "modem", "get_sim")%>', null,
function (x, data) {
set_sim_view(data);
}
);
}
</script>
<!-- 设置SIM卡槽 -->
<div class="cbi-section" >
<table class="table cbi-section-table">
<tbody id="sim_slot_setting">
<tr class="tr cbi-section-table-titles anonymous">
<th>
<%:SIM Slot%>|<%:Now%>
</th>
<th>
<%:SIM Slot%>|<%:Next Boot%>
</th>
<th>
<%:SIM Slot%>|<%:Setting%>
</th>
</tr>
<tr class="tr">
<td class="td" style="width: auto;">
<span id="sim_slot_current"></span>
</td>
<td class="td cbi-value-field">
<span id="sim_slot_nextboot"></span>
</td>
<td class="td cbi-value-field">
<select name="sim_slot_select" id="sim_slot_select" class="cbi-input-select">
<option value="SIM1"><%:SIM1 (Close to power)%></option>
<option value="SIM2"><%:SIM2 (Away from power)%></option>
</select>
</td>
</tr>
</tbody>
</table>
<input type="button" class="cbi-button-apply" onclick="set_sim()" value="<%:Set SIM%>">
</div>

View File

@ -0,0 +1,21 @@
#view/modem_sim.htm
msgid "SIM Slot"
msgstr "SIM卡卡槽"
msgid "Now"
msgstr "当前"
msgid "Next Boot"
msgstr "下次启动"
msgid "Setting'
msgstr "设置"
msgid "SIM1 (Close to power)"
msgstr "SIM1 (靠近电源)"
msgid "SIM2 (Away from power)"
msgstr "SIM2 (远离电源)"
msgid "Set SIM"
msgstr "设置SIM卡"

View File

@ -0,0 +1,21 @@
#view/modem_sim.htm
msgid "SIM Slot"
msgstr "SIM卡卡槽"
msgid "Now"
msgstr "当前"
msgid "Next Boot"
msgstr "下次启动"
msgid "Setting'
msgstr "设置"
msgid "SIM1 (Close to power)"
msgstr "SIM1 (靠近电源)"
msgid "SIM2 (Away from power)"
msgstr "SIM2 (远离电源)"
msgid "Set SIM"
msgstr "设置SIM卡"

View File

@ -0,0 +1,4 @@
config global
option sim_auto_switch '1'
option detect_interval '15'
option judge_time '5'

View File

@ -0,0 +1,35 @@
#!/bin/sh /etc/rc.common
USE_PROCD=1
START=99
STOP=10
PROG="/usr/share/modem/modem_sim.sh"
start_service() {
local sim_auto_switch=$(uci -q get modem_sim.@global[0].sim_auto_switch)
logger -t modem_sim start_service $sim_auto_switch
if [ "$sim_auto_switch" == 1 ];then
start_instace
else
stop_service
fi
}
start_instace(){
procd_open_instance "$PROG"
procd_set_param command /usr/share/modem/modem_sim.sh
procd_close_instance
logger -t modem_sim running
}
reload_service() {
stop
start
}
stop_service() {
logger -t modem_sim stop_service
service_stop "$PROG"
}
service_triggers() {
procd_add_reload_trigger 'modem_sim'
}

View File

@ -0,0 +1,183 @@
#!/bin/sh
sim_gpio="/sys/class/gpio/sim/value"
modem_gpio="/sys/class/gpio/4g/value"
ping_dest=$(uci -q get modem_sim.@global[0].ping_dest)
wwan_ifname=$(uci -q get modem_sim.@global[0].wwan_ifname)
[ -n $wwan_ifname ] && modem_config=$wwan_ifname
is_empty=$(uci -q get modem.$modem_config)
[ -z $is_empty ] && unset modem_config
[ -z "$modem_config" ] && get_first_avalible_config
netdev=$(ifstatus $wwan_ifname | jq -r .device)
judge_time=$(uci -q get modem_sim.@global[0].judge_time)
detect_interval=$(uci -q get modem_sim.@global[0].detect_interval)
[ -z $detect_interval ] && detect_interval=10
[ -z $judge_time ] && judge_time=5
set_modem_config()
{
cfg=$1
[ -n "$modem_config" ] && return
config_get state $1 state
[ -n "$state" ] && [ "$state" != "disabled" ] && modem_config=$cfg
}
get_first_avalible_config()
{
. /lib/functions.sh
config_load modem
config_foreach set_modem_config modem-device
}
sendat()
{
tty=$1
cmd=$2
sms_tool -d $tty at $cmd 2>&1
}
reboot_modem() {
echo 0 > $modem_gpio
sleep 1
echo 1 > $modem_gpio
}
switch_sim() {
if [ -f $sim_gpio ]; then
sim_status=$(cat $sim_gpio)
if [ $sim_status -eq 0 ]; then
echo 1 > $sim_gpio
else
echo 0 > $sim_gpio
fi
reboot_modem
logger -t modem_sim "switch sim from $sim_status to $(cat $sim_gpio)"
fi
}
ping_monitor() {
#ping_dest为空则不进行ping检测 ,如果有多个,用空格隔开
has_success=0
for dest in $ping_dest; do
ping -c 1 -W 1 $dest -I $netdev > /dev/null
if [ $? -eq 0 ]; then
return 1
fi
done
return 0
}
at_dial_monitor() {
ttydev=$1
define_connect=$2
#检查拨号状况,有v4或v6地址则返回1
at_cmd="AT+CGPADDR=1"
[ "$define_connect" == "3" ] && at_cmd="AT+CGPADDR=3"
expect="+CGPADDR:"
result=$(sendat $ttydev $at_cmd | grep "$expect")
if [ -n "$result" ];then
ipv6=$(echo $result | grep -oE "\b([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}\b")
ipv4=$(echo $result | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b")
disallow_ipv4="0.0.0.0"
#remove the disallow ip
if [ "$ipv4" == "$disallow_ipv4" ];then
ipv4=""
fi
if [ -n "$ipv4" ] || [ -n "$ipv6" ];then
return 1
fi
fi
return 0
}
at_sim_monitor() {
ttydev=$1
#检查sim卡状态有sim卡则返回1
expect="+CPIN: READY"
result=$(sendat $ttydev "AT+CPIN?" | grep -o "$expect")
if [ -n "$result" ]; then
return 1
fi
return 0
}
precheck()
{
modem_config=$1
config=$(uci -q show modem.$modem_config)
[ -z "$config" ] && return 1
ttydev=$(uci -q get modem.$modem_config.at_port)
enable_dial=$(uci -q get modem.$modem_config.enable_dial)
global_en=$(uci -q get modem.global.enable_dial)
[ "$global_en" == "0" ] && return 1
[ -z "$enable_dial" ] || [ "$enable_dial" == "0" ] && return 1
[ -z "$ttydev" ] && return 1
[ ! -e "$ttydev" ] && return 1
return 0
}
fail_times=0
main_monitor() {
while true; do
#检测前置条件1.tty存在 2.配置信息存在 3.拨号功能已开启
precheck $modem_config
if [ $? -eq 1 ]; then
sleep $detect_interval
continue
fi
#检查ping状态超过judge_time则切卡
if [ -n "$ping_dest" ]; then
ping_monitor
ping_result=$?
fi
[ -z $ttydev ] && ttydev=$(uci -q get modem.$modem_config.at_port)
[ -z $define_connect ] && define_connect=$(uci -q get modem.$modem_config.define_connect)
if [ -n $define_connect ] && [ -n $ttydev ];then
at_dial_monitor $ttydev $define_connect
dial_result=$?
fi
if [ -n $ttydev ];then
at_sim_monitor $ttydev;
sim_result=$?
fi
if [ -n "$ping_dest" ];then
#策略ping成功则重置fail_times否则fail_times累加
[ -z "$dial_result" ] && dial_result=1
[ -z "$sim_result" ] && sim_result=1
fail_total=$((3 - $ping_result - $dial_result - $sim_result))
if [ $ping_result -eq 1 ]; then
fail_times=0
else
fail_times=$(($fail_times + $fail_total))
fi
#如果失败次数超过judge_time * 3则切卡 切卡后等待3分钟
else
#策略 无ping则检测拨号和sim卡状态拨号成功则重置fail_times否则fail_times累加
[ -z "$dial_result" ] && dial_result=1
[ -z "$sim_result" ] && sim_result=1
fail_total=$((2 - $dial_result - $sim_result))
if [ $dial_result -eq 1 ]; then
fail_times=0
else
fail_times=$(($fail_times + $fail_total))
fi
fi
logger -t modem_sim "ping_result:$ping_result dial_result:$dial_result sim_result:$sim_result fail_times:$fail_times fail_total:$fail_total fail_times:$fail_times"
if [ $fail_times -ge $(($judge_time * 2)) ]; then
switch_sim
fail_times=0
sleep 240
fi
sleep $detect_interval
done
}
sleep 180
main_monitor

View File

@ -0,0 +1,22 @@
# Copyright (C) 2024 Tom <fjrcn@outlook.com>
# This is free software, licensed under the GNU General Public License v3.
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-5modem-mwan-single-module
LUCI_TITLE:=Luci modem mwan support
LUCI_PKGARCH:=all
PKG_VERSION:=2.0
PKG_LICENSE:=GPLv3
PKG_LINCESE_FILES:=LICENSE
PKF_MAINTAINER:=fujr
LUCI_DEPENDS:=+luci-app-5gmodem +luci-app-mwan3
define Package/luci-app-5gmodem-mwan/conffiles
/etc/config/modem_mwan
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,9 @@
module("luci.controller.modem_mwan", package.seeall)
function index()
if not nixio.fs.access("/etc/config/modem_mwan") then
return
end
--mwan配置
entry({"admin", "network", "modem", "mwan_config"}, cbi("modem/mwan_config"), luci.i18n.translate("Mwan Config"), 21).leaf = true
end

View File

@ -0,0 +1,12 @@
#model/modem_mwan.lua
msgid "same source ip address will always use the same wan interface"
msgstr "相同的源IP地址将在一定时间内始终使用相同的WAN接口"
msgid "Check and modify the mwan configuration"
msgstr "检查和修改mwan配置"
msgid "sticky mode"
msgstr "粘性模式"
msgid "sticky timeout"
msgstr "粘性超时"

View File

@ -0,0 +1,12 @@
#model/modem_mwan.lua
msgid "same source ip address will always use the same wan interface"
msgstr "相同的源IP地址将在一定时间内始终使用相同的WAN接口"
msgid "Check and modify the mwan configuration"
msgstr "检查和修改mwan配置"
msgid "sticky mode"
msgstr "粘性模式"
msgid "sticky timeout"
msgstr "粘性超时"

View File

@ -1,6 +1,6 @@
config ipv4 'ipv4'
option wan_ifname 'wan'
option wwan_ifname 'wwan_5g_0'
option wwan_ifname '2_1'
list track_ip 'test.ustc.edu.cn'
list track_ip 'cip.cc'
list track_ip '208.67.222.222'

View File

@ -51,3 +51,8 @@ stop_service() {
service_triggers() {
procd_add_reload_trigger 'modem_mwan'
}
reload_service() {
stop
start
}

View File

@ -0,0 +1,22 @@
# Copyright (C) 2024 Tom <fjrcn@outlook.com>
# This is free software, licensed under the GNU General Public License v3.
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-5gmodem-mwan
LUCI_TITLE:=Luci modem mwan support
LUCI_PKGARCH:=all
PKG_VERSION:=2.0
PKG_LICENSE:=GPLv3
PKG_LINCESE_FILES:=LICENSE
PKF_MAINTAINER:=fujr
LUCI_DEPENDS:=+luci-app-5gmodem +luci-app-mwan3
define Package/luci-app-5gmodem-mwan/conffiles
/etc/config/modem_mwan
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,9 @@
module("luci.controller.modem_mwan", package.seeall)
function index()
if not nixio.fs.access("/etc/config/modem_mwan") then
return
end
--mwan配置
entry({"admin", "network", "modem", "mwan_config"}, cbi("modem/mwan_config"), luci.i18n.translate("Mwan Config"), 21).leaf = true
end

View File

@ -0,0 +1,48 @@
local d = require "luci.dispatcher"
local uci = luci.model.uci.cursor()
local sys = require "luci.sys"
local script_path="/usr/share/modem/"
m = Map("modem_mwan")
m.title = translate("Mwan Config")
m.description = translate("Check and modify the mwan configuration")
s = m:section(NamedSection, "global", "global", translate("gloal Config"))
s.anonymous = true
s.addremove = false
enable_mwan = s:option(Flag, "enable_mwan", translate("Enable MWAN"))
sticky = s:option(Flag,"sticky_mode",translate("sticky mode"))
sticky.default = 0
sticky.description = translate("same source ip address will always use the same wan interface")
sticky_timeout = s:option(Value,"sticky_timeout",translate("sticky timeout"))
sticky_timeout.default = 300
sticky_timeout.datatype = "uinteger"
sticky_timeout:depends("sticky_mode",1)
s = m:section(TypedSection, "ipv4", translate("IPV4 Config"))
s.anonymous = true
s.addremove = true
s.template = "cbi/tblsection"
member_interface = s:option(DynamicList, "member_interface", translate("Interface"))
member_interface.rmempty = true
member_interface.datatype = "network"
member_interface.template = "cbi/network_netlist"
member_interface.widget = "select"
o = s:option(DynamicList, 'member_track_ip', translate('Track IP'))
o.datatype = 'host'
member_priority = s:option(Value, "member_priority", translate("Priority"))
member_priority.rmempty = true
member_priority.datatype = "uinteger"
member_priority.default = 1
-- member_priority:depends("member_interface", "")
member_weight = s:option(Value, "member_weight", translate("Weight"))
member_weight.rmempty = true
member_weight.datatype = "uinteger"
member_weight.default = 1
-- member_weight:depends("member_interface", "")
return m

View File

@ -0,0 +1,24 @@
#model/modem_mwan.lua
msgid "same source ip address will always use the same wan interface"
msgstr "相同的源IP地址将在一定时间内始终使用相同的WAN接口"
msgid "Check and modify the mwan configuration"
msgstr "检查和修改mwan配置"
msgid "sticky mode"
msgstr "粘性模式"
msgid "sticky timeout"
msgstr "粘性超时"
msgid "member_track_ip"
msgstr "成员跟踪IP"
msgid "member_interface"
msgstr "成员接口"
msgid "member_priority"
msgstr "成员优先级"
msgid "member_weight"
msgstr "成员权重"

View File

@ -0,0 +1,24 @@
#model/modem_mwan.lua
msgid "same source ip address will always use the same wan interface"
msgstr "相同的源IP地址将在一定时间内始终使用相同的WAN接口"
msgid "Check and modify the mwan configuration"
msgstr "检查和修改mwan配置"
msgid "sticky mode"
msgstr "粘性模式"
msgid "sticky timeout"
msgstr "粘性超时"
msgid "member_track_ip"
msgstr "成员跟踪IP"
msgid "Interface"
msgstr "成员接口"
msgid "Priority"
msgstr "成员优先级"
msgid "Weight"
msgstr "成员权重"

View File

@ -0,0 +1,29 @@
config ipv4
list member_track_ip 'test.ustc.edu.cn'
list member_track_ip 'cip.cc'
list member_track_ip '208.67.222.222'
list member_track_ip '208.67.220.220'
list member_interface 'wan'
option member_priority '1'
option member_weight '1'
config ipv4
list member_track_ip 'test.ustc.edu.cn'
list member_track_ip 'cip.cc'
list member_track_ip '208.67.222.222'
list member_track_ip '208.67.220.220'
list member_interface '2_1_2'
option member_priority '2'
option member_weight '1'
config ipv4
list member_track_ip 'test.ustc.edu.cn'
list member_track_ip 'cip.cc'
list member_track_ip '208.67.222.222'
list member_track_ip '208.67.220.220'
list member_interface '2_1_4'
option member_priority '2'
option member_weight '1'
config global 'global'
option enable_mwan '1'

View File

@ -0,0 +1,35 @@
#!/bin/sh /etc/rc.common
USE_PROCD=1
START=30
start_mwan3()
{
proto=$1
logger -t modem_mwan "before set $proto start"
/usr/share/modem/modem_mwan.sh $proto start
logger -t modem_mwan "set $proto start"
}
start_service() {
logger -t modem_mwan "start modem_mwan"
config_load modem_mwan
config_get enable global enable_mwan 0
if [ "$enable" = "0" ]; then
stop_service
fi
start_mwan3 ipv4
}
stop_service() {
/usr/share/modem/modem_mwan.sh ipv4 stop
}
service_triggers() {
procd_add_reload_trigger 'modem_mwan'
}
reload_service() {
stop
start
}

View File

@ -0,0 +1,158 @@
#! /bin/sh
. /lib/functions.sh
append_if(){
interface=$1
track_ip=$2
uci batch <<EOF
set mwan3.$interface=interface
set mwan3.$interface.enabled=1
set mwan3.$interface.family="$family"
set mwan3.$interface.track_method=ping
set mwan3.$interface.reliability='1'
set mwan3.$interface.count='1'
set mwan3.$interface.size='56'
set mwan3.$interface.max_ttl='60'
set mwan3.$interface.timeout='4'
set mwan3.$interface.interval='10'
set mwan3.$interface.failure_interval='5'
set mwan3.$interface.recovery_interval='5'
set mwan3.$interface.down='5'
set mwan3.$interface.up='5'
set mwan3.$interface.add_by=modem
delete mwan3.$interface.track_ip
EOF
if [ -n "$track_ip" ]; then
for ip in $track_ip; do
uci add_list mwan3.$interface.track_ip=$ip
done
fi
}
add_mwan3_member()
{
interface=$1
metric=$2
weight=$3
member_name=$4
uci batch <<EOF
set mwan3.$member_name=member
set mwan3.$member_name.interface=$interface
set mwan3.$member_name.metric=$metric
set mwan3.$member_name.weight=$weight
set mwan3.$member_name.add_by=modem
EOF
}
remove_member()
{
config_load mwan3
config_foreach remove_member_cb member
}
remove_member_cb()
{
local add_by
config_get add_by $1 add_by
if [ "$add_by" = "modem" ]; then
uci delete mwan3.$1
fi
}
append_mwan3_policy_member()
{
uci add_list mwan3.$1.use_member=$2
}
init_mwan3_policy()
{
policy_name=$1
uci batch <<EOF
set mwan3.$policy_name=policy
set mwan3.$policy_name.last_resort='default'
set mwan3.$policy_name.add_by=modem
delete mwan3.$policy_name.use_member
EOF
}
flush_config(){
config_load mwan3
config_foreach remove_cb interface
config_foreach remove_cb member
config_foreach remove_cb policy
config_foreach remove_cb rule
}
remove_cb(){
local add_by
config_get add_by $1 add_by
if [ "$add_by" = "modem" ]; then
uci delete mwan3.$1
fi
}
gen_rule()
{
use_policy=$1
rule_name=${family}_rule
uci batch <<EOF
set mwan3.$rule_name=rule
set mwan3.$rule_name.family="$family"
set mwan3.$rule_name.sticky=$sticky_mode
set mwan3.$rule_name.proto='all'
set mwan3.$rule_name.use_policy=$use_policy
set mwan3.$rule_name.add_by=modem
EOF
if [ -n "$sticky_timeout" ]; then
uci set mwan3.$rule_name.timeout=$sticky_timeout
fi
}
handle_config()
{
config_get interface $1 member_interface
config_get priority $1 member_priority
config_get weight $1 member_weight
config_get track_ip $1 member_track_ip
echo $1
append_if $interface "$track_ip"
add_mwan3_member $interface $priority $weight $1
append_mwan3_policy_member $family $1
}
/etc/init.d/mwan3 stop
flush_config
uci commit mwan3
config_load modem_mwan
family=$1
case $2 in
"start")
config_get sticky_mode global sticky_mode 0
config_get sticky_timeout global sticky_timeout
echo $sticky_mode $sticky_timeout
init_mwan3_policy $family
config_foreach handle_config $family
gen_rule $family
;;
"stop")
rule_name=${family}_rule
uci delete mwan3.$rule_name
;;
esac
uci commit mwan3
/etc/init.d/mwan3 start

View File

@ -0,0 +1,17 @@
# Copyright (C) 2024 Tom <fjrcn@outlook.com>
# This is free software, licensed under the GNU General Public License v3.
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-5gmodem-sms
LUCI_TITLE:=Luci modem sms support
LUCI_PKGARCH:=all
PKG_VERSION:=2.0
PKG_LICENSE:=GPLv3
PKG_LINCESE_FILES:=LICENSE
PKF_MAINTAINER:=fujr
LUCI_DEPENDS:=+luci-app-5gmodem
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,51 @@
module("luci.controller.modem_sms", package.seeall)
local http = require "luci.http"
local fs = require "nixio.fs"
local json = require("luci.jsonc")
local modem_ctrl = "/usr/share/modem/modem_ctrl.sh "
function shell(command)
local odpall = io.popen(command)
local odp = odpall:read("*a")
odpall:close()
return odp
end
function index()
--sim卡配置
entry({"admin", "network", "modem", "modem_sms"},template("modem_sms/modem_sms"), luci.i18n.translate("SMS"), 11).leaf = true
entry({"admin", "network", "modem", "send_sms"}, call("sendSMS"), nil).leaf = true
entry({"admin", "network", "modem", "get_sms"}, call("getSMS"), nil).leaf = true
entry({"admin", "network", "modem", "delete_sms"}, call("delSMS"), nil).leaf = true
end
function getSMS()
local cfg_id = http.formvalue("cfg")
response = shell(modem_ctrl .. "get_sms " .. cfg_id)
http.prepare_content("application/json")
http.write(response)
end
function sendSMS()
local cfg_id = http.formvalue("cfg")
local pdu = http.formvalue("pdu")
if pdu then
response = shell(modem_ctrl .. "send_raw_pdu " .. cfg_id .. " \"" .. pdu .. "\"")
else
local phone_number = http.formvalue("phone_number")
local message_content = http.formvalue("message_content")
json_cmd = string.format('{\\"phone_number\\":\\"%s\\",\\"message_content\\":\\"%s\\"}', phone_number, message_content)
response = shell(modem_ctrl .. "send_sms " .. cfg_id .." \"".. json_cmd .. "\"")
end
http.prepare_content("application/json")
http.write(response)
end
function delSMS()
local cfg_id = http.formvalue("cfg")
local index = http.formvalue("index")
response = shell(modem_ctrl .. "delete_sms " .. cfg_id .. " \"" ..index.."\"")
http.prepare_content("application/json")
http.write(response)
end

View File

@ -0,0 +1,908 @@
<%+header%>
<script>
var pduParser = {};
pduParser.parse = function(pdu) {
//Cursor points to the last octet we've read.
var cursor = 0;
var buffer = new Buffer(pdu.slice(0,4), 'hex');
var smscSize = buffer[0];
var smscType = buffer[1].toString(16);
cursor = (smscSize*2+2);
var smscNum = pduParser.deSwapNibbles(pdu.slice(4, cursor));
var buffer = new Buffer(pdu.slice(cursor,cursor+6), 'hex');
cursor += 6;
var smsDeliver = buffer[0];
var smsDeliverBits = ("00000000"+parseInt(smsDeliver).toString(2)).slice(-8);
var udhi = smsDeliverBits.slice(1,2) === "1";
var senderSize = buffer[1];
if(senderSize % 2 === 1)
senderSize++;
var senderType = parseInt(buffer[2]).toString(16)
var encodedSender = pdu.slice(cursor, cursor + senderSize);
var senderNum;
if (senderType === '91') {
senderNum = pduParser.deSwapNibbles(encodedSender);
} else if (senderType === 'd0') {
senderNum = this.decode7Bit(encodedSender).replace(/\0/g, '');
} else {
console.error('unsupported sender type.');
}
cursor += senderSize;
var protocolIdentifier = pdu.slice(cursor, cursor+2);
cursor += 2;
var dataCodingScheme = pdu.slice(cursor, cursor+2);
cursor = cursor+2;
var encoding = pduParser.detectEncoding(dataCodingScheme);
var timestamp = pduParser.deSwapNibbles(pdu.slice(cursor, cursor+14));
var time = new Date;
time.setUTCFullYear('20'+timestamp.slice(0,2));
time.setUTCMonth(timestamp.slice(2,4)-1);
time.setUTCDate(timestamp.slice(4,6));
time.setUTCHours(timestamp.slice(6,8));
time.setUTCMinutes(timestamp.slice(8,10));
time.setUTCSeconds(timestamp.slice(10,12));
var firstTimezoneOctet = parseInt(timestamp.slice(12,13));
var binary = ("0000"+firstTimezoneOctet.toString(2)).slice(-4);
var factor = binary.slice(0,1) === '1' ? 1 : -1;
var binary = '0'+binary.slice(1, 4);
var firstTimezoneOctet = parseInt(binary, 2).toString(10);
var timezoneDiff = parseInt(firstTimezoneOctet + timestamp.slice(13, 14));
var time = new Date(time.getTime() + (timezoneDiff * 15 * 1000 * 60 * factor));
cursor += 14;
var dataLength = parseInt(pdu.slice(cursor, cursor+2), 16).toString(10);
cursor += 2;
if(udhi) { //User-Data-Header-Indicator: means there's some User-Data-Header.
var udhLength = pdu.slice(cursor, cursor+2);
var iei = pdu.slice(cursor+2, cursor+4);
if(iei == "00") { //Concatenated sms.
var headerLength = pdu.slice(cursor+4, cursor+6);
var referenceNumber = pdu.slice(cursor+6, cursor+8);
var parts = pdu.slice(cursor+8, cursor+10);
var currentPart = pdu.slice(cursor+10, cursor+12);
}
if(iei == "08") { //Concatenaded sms with a two-bytes reference number
var headerLength = pdu.slice(cursor+4, cursor+6);
var referenceNumber = pdu.slice(cursor+6, cursor+10);
var parts = pdu.slice(cursor+10, cursor+12);
var currentPart = pdu.slice(cursor+12, cursor+14);
}
if(encoding === '16bit')
if(iei == '00')
cursor += (udhLength-2)*4;
else if(iei == '08')
cursor += ((udhLength-2)*4)+2;
else
cursor += (udhLength-2)*2;
}
if(encoding === '16bit')
var text = pduParser.decode16Bit(pdu.slice(cursor), dataLength);
else if(encoding === '7bit')
var text = pduParser.decode7Bit(pdu.slice(cursor), dataLength);
else if(encoding === '8bit')
var text = ''; //TODO
var data = {
'smsc' : smscNum,
'smsc_type' : smscType,
'sender' : senderNum,
'sender_type' : senderType,
'encoding' : encoding,
'time' : time,
'text' : text
};
if(udhi) {
data['udh'] = {
'length' : udhLength,
'iei' : iei,
};
if(iei == '00' || iei == '08') {
data['udh']['reference_number'] = referenceNumber;
data['udh']['parts'] = parseInt(parts);
data['udh']['current_part'] = parseInt(currentPart);
}
}
return data;
}
pduParser.detectEncoding = function(dataCodingScheme) {
var binary = ('00000000'+(parseInt(dataCodingScheme, 16).toString(2))).slice(-8);
if(binary == '00000000')
return '7bit';
if(binary.slice(0, 2) === '00') {
var compressed = binary.slice(2, 1) === '1';
var bitsHaveMeaning = binary.slice(3, 1) === '1';
if(binary.slice(4,6) === '00')
return '7bit';
if(binary.slice(4,6) === '01')
return '8bit';
if(binary.slice(4,6) === '10')
return '16bit';
}
}
pduParser.decode16Bit = function(data, length) {
//We are getting ucs2 characters.
var ucs2 = '';
for(var i = 0;i<=data.length;i=i+4) {
ucs2 += String.fromCharCode("0x"+data[i]+data[i+1]+data[i+2]+data[i+3]);
}
return ucs2;
}
pduParser.deSwapNibbles = function(nibbles) {
var out = '';
for(var i = 0; i< nibbles.length; i=i+2) {
if(nibbles[i] === 'F') //Dont consider trailing F.
out += parseInt(nibbles[i+1], 16).toString(10);
else
out += parseInt(nibbles[i+1], 16).toString(10)+parseInt(nibbles[i], 16).toString(10);
}
return out;
}
pduParser.decode7Bit = function(code, count) {
//We are getting 'septeps'. We should decode them.
var binary = '';
for(var i = 0; i<code.length;i++)
binary += ('0000'+parseInt(code.slice(i,i+1), 16).toString(2)).slice(-4);
var bin = Array();
var cursor = 0;
var fromPrevious = '';
var i = 0;
while(binary[i]) {
var remaining = 7 - fromPrevious.length;
var toNext = 8 - remaining;
bin[i] = binary.slice(cursor+toNext, cursor+toNext+remaining) + fromPrevious;
var fromPrevious = binary.slice(cursor, cursor+toNext);
if(toNext === 8)
fromPrevious = '';
else
cursor += 8;
i++;
}
var ascii = '';
for(i in bin)
ascii += String.fromCharCode(parseInt(bin[i], 2));
return ascii;
}
pduParser.encode7Bit = function(ascii) {
//We should create septeps now.
var octets = new Array();
for(var i = 0; i<ascii.length; i++)
octets.push(('0000000'+(ascii.charCodeAt(i).toString(2))).slice(-7));
for(var i in octets) {
var i = parseInt(i);
var freeSpace = 8 - octets[i].length;
if(octets[i+1] && freeSpace !== 8) {
octets[i] = octets[i+1].slice(7-freeSpace) + octets[i];
octets[i+1] = octets[i+1].slice(0, 7-freeSpace);
}
}
var hex = '';
for(i in octets)
if(octets[i].length > 0)
hex += ('00'+(parseInt(octets[i], 2).toString(16))).slice(-2);
return hex;
}
//TODO: TP-Validity-Period (Delivery)
pduParser.generate = function(message) {
var pdu = '00';
var parts = 1;
if(message.encoding === '16bit' && message.text.length > 70)
parts = message.text.length / 66;
else if(message.encoding === '7bit' && message.text.length > 160)
parts = message.text.length / 153;
parts = Math.ceil(parts);
TPMTI = 1;
TPRD = 4;
TPVPF = 8;
TPSRR = 32;
TPUDHI = 64;
TPRP = 128;
var submit = TPMTI;
if(parts > 1) //UDHI
submit = submit | TPUDHI;
submit = submit | TPSRR;
pdu += submit.toString(16);
pdu += '00'; //TODO: Reference Number;
var receiverSize = ('00'+(parseInt(message.receiver.length, 10).toString(16))).slice(-2);
var receiver = pduParser.swapNibbles(message.receiver);
var receiverType = 81; //TODO: NOT-Hardcoded PDU generation. Please note that Hamrah1 doesnt work if we set it to 91 (International).
pdu += receiverSize.toString(16) + receiverType + receiver;
pdu += '00'; //TODO TP-PID
if(message.encoding === '16bit')
pdu += '08';
else if(message.encoding === '7bit')
pdu += '00';
var pdus = new Array();
var csms = randomHexa(2); // CSMS allows to give a reference to a concatenated message
for(var i=0; i< parts; i++) {
pdus[i] = pdu;
if(message.encoding === '16bit') {
/* If there are more than one messages to be sent, we are going to have to put some UDH. Then, we would have space only
* for 66 UCS2 characters instead of 70 */
if(parts === 1)
var length = 70;
else
var length = 66;
} else if(message.encoding === '7bit') {
/* If there are more than one messages to be sent, we are going to have to put some UDH. Then, we would have space only
* for 153 ASCII characters instead of 160 */
if(parts === 1)
var length = 160;
else
var length = 153;
}
var text = message.text.slice(i*length, (i*length)+length);
if(message.encoding === '16bit') {
user_data = pduParser.encode16Bit(text);
var size = (user_data.length / 2);
if(parts > 1)
size += 6; //6 is the number of data headers we append.
} else if(message.encoding === '7bit') {
user_data = pduParser.encode7Bit(text);
var size = user_data.length / 2;
}
pdus[i] += ('00'+parseInt(size).toString(16)).slice(-2);
if(parts > 1) {
pdus[i] += '05';
pdus[i] += '00';
pdus[i] += '03';
pdus[i] += csms;
pdus[i] += ('00'+parts.toString(16)).slice(-2);
pdus[i] += ('00'+(i+1).toString(16)).slice(-2);
}
pdus[i] += user_data;
}
return pdus;
}
pduParser.encode16Bit = function(text) {
var out = '';
for(var i = 0; i<text.length;i++) {
out += ('0000'+(parseInt(text.charCodeAt(i), 10).toString(16))).slice(-4);
}
return out;
}
pduParser.swapNibbles = function(nibbles) {
var out = '';
for(var i = 0; i< nibbles.length; i=i+2) {
if(typeof(nibbles[i+1]) === 'undefined') // Add a trailing F.
out += 'F'+parseInt(nibbles[i], 16).toString(10);
else
out += parseInt(nibbles[i+1], 16).toString(10)+parseInt(nibbles[i], 16).toString(10);
}
return out;
}
pduParser.parseStatusReport = function(pdu) {
//Cursor points to the last octet we've read.
var cursor = 0;
var smscSize = parseInt(pdu.slice(0, 2), 16);
cursor += 2;
var smscType = parseInt(pdu.slice(cursor, cursor+2), 16);
cursor += 2;
var smscNum = pduParser.deSwapNibbles(pdu.slice(cursor, (smscSize*2)+2));
cursor = (smscSize*2+2);
var header = parseInt(pdu.slice(cursor,cursor+2));
cursor += 2;
var reference = parseInt(pdu.slice(cursor,cursor+2), 16);
cursor += 2;
var senderSize = parseInt(pdu.slice(cursor,cursor+2), 16);
if(senderSize % 2 === 1)
senderSize++;
cursor += 2;
var senderType = parseInt(pdu.slice(cursor,cursor+2));
cursor += 2;
var sender = pduParser.deSwapNibbles(pdu.slice(cursor, cursor+senderSize));
var status = pdu.slice(-2);
return {
smsc:smscNum,
reference:reference,
sender:sender,
status:status
}
}
function randomHexa(size)
{
var text = "";
var possible = "0123456789ABCDEF";
for( var i=0; i < size; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
class LuciTable{
constructor(){
this.rows = [];
this.tbody;
this.fieldset;
this.init_table();
}
init_table(){
//create a luci fieldset (class cbi-section)
var fieldset = document.createElement('fieldset');
fieldset.className="cbi-section";
//set fieldset Header name
var legend = document.createElement('legend');
var title_span = document.createElement('span');
title_span.className="panel-title"
//init table
var table = document.createElement('table');
var tbody = document.createElement('tbody');
table.className="table"
//save
this.fieldset = fieldset;
this.tbody = tbody
this.title_span = title_span
this.legend = legend
fieldset.appendChild(legend);
fieldset.appendChild(title_span);
table.appendChild(tbody)
fieldset.appendChild(table)
}
new_tr(data,index){
var type = data.type;
var col = data.col;
var left = data.left;
var right = data.right;
//clear the row
this.rows[index].left.innerHTML = "";
this.rows[index].right.innerHTML = "";
//set the row
this.rows[index].left.appendChild(left);
this.rows[index].right.appendChild(right);
if (right == null || right == "") {
this.rows[index].row.style.display = "none";
}
else{
this.rows[index].row.style.display = "";
}
}
set title(value){
this.legend.innerHTML = value;
this.title_span.innerHTML = value;
}
set object_data(value){
var row_length = this.rows.length;
var value_length = Object.keys(value).length;
if (row_length < value_length) {
for ( let i = row_length; i < value_length; i++) {
let row = document.createElement('tr');
row.className = "tr"
let cell_left = document.createElement('td');
cell_left.classList.add("td")
cell_left.setAttribute("width","33%")
let cell_right = document.createElement('td');
cell_right.classList.add("td")
row.appendChild(cell_left);
row.appendChild(cell_right);
this.tbody.appendChild(row);
var row_dict = {
"row":row,
"left":cell_left,
"right":cell_right,
}
this.rows.push(row_dict);
}
}
else if(row_length > value_length){
for (let i = value_length; i < row_length; i++) {
this.tbody.removeChild(this.rows[i].row);
}
this.rows = this.rows.slice(0,value_length);
}
var index = 0;
for (var key in value) {
this.rows[index].left.innerHTML = key;
this.rows[index].right.innerHTML = value[key];
index++;
}
}
set array_data(value){
var row_length = this.rows.length;
var value_length = value.length;
if (row_length < value_length) {
for ( let i = row_length; i < value_length; i++) {
let row = document.createElement('tr');
row.className = "tr"
let cell_left = document.createElement('td');
cell_left.classList.add("td")
cell_left.setAttribute("width","33%")
let cell_right = document.createElement('td');
cell_right.classList.add("td")
row.appendChild(cell_left);
row.appendChild(cell_right);
this.tbody.appendChild(row);
var row_dict = {
"row":row,
"left":cell_left,
"right":cell_right,
}
this.rows.push(row_dict);
}
}
else if(row_length > value_length){
for (let i = value_length; i < row_length; i++) {
this.tbody.removeChild(this.rows[i].row);
}
this.rows = this.rows.slice(0,value_length);
}
for (let i = 0; i < value.length; i++) {
this.new_tr(value[i],i);
}
}
set data(value){
if (value == null) {
return;
}
if (Array.isArray(value)) {
this.array_data = value;
}
else{
this.object_data = value;
}
}
}
class ModemSMS {
constructor() {
this.data = null;
this.cfg_id = null;
this.modem_cfg_list = [];
this.sms_recvbox_table = new LuciTable();
this.sms_send_table = new LuciTable();
this.sms_send_table.title = "<%:Send SMS%>";
this.cbi_map = document.querySelector('.cbi-map');
this.cbi_map.appendChild(this.sms_recvbox_table.fieldset);
this.cbi_map.appendChild(this.sms_send_table.fieldset);
this.modem_selector = document.getElementById('modem_selector');
this.create_modem_cfg_selector();
this.update_modem_cfg_list();
this.init_send_table_view();
this.init_msg_box();
}
init_msg_box()
{
var warn_msg_box = document.createElement('div');
warn_msg_box.className = "cbi-section";
var warn_msg = document.createElement('div');
warn_msg.className = "alert";
warn_msg_box.appendChild(warn_msg);
this.cbi_map.appendChild(warn_msg_box);
this.warn_msg_box = warn_msg_box;
//hide
this.warn_msg_box.style.display = "none";
}
warn_msg(msg,timeout){
this.warn_msg_box.style.display = "";
this.warn_msg_box.classList.add("alert-warning");
this.warn_msg_box.firstChild.innerHTML = msg;
setTimeout(()=>{
this.warn_msg_box.style.display = "none";
this.warn_msg_box.classList.remove("alert-warning");
},timeout);
}
log_msg(msg,timeout){
this.warn_msg_box.style.display = "";
this.warn_msg_box.classList.add("alert-info");
this.warn_msg_box.firstChild.innerHTML = msg;
setTimeout(()=>{
this.warn_msg_box.style.display = "none";
this.warn_msg_box.classList.remove("alert-info");
},timeout);
}
create_modem_cfg_selector(){
var selector = document.createElement('select');
selector.addEventListener('change', (event) => {
this.update();
this.cfg_id = event.target.value;
console.log(this.cfg_id);
});
this.modem_selector.appendChild(selector);
this.selector = selector;
this.poll_info();
}
send(){
//if content contain non-ascii char, use raw pdu
var content = this.message_content.value;
var is_ascii = /^[\x00-\x7F]*$/.test(content);
if (is_ascii) {
this.send_gsm();
}
else{
this.send_raw_pdu();
}
}
send_gsm(){
var phone_number = this.phone_number.value;
var message_content = this.message_content.value;
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "modem", "send_sms")%>',{
"cfg": this.cfg_id,
"phone_number": phone_number,
"message_content": message_content,
},(x,data)=>{
this.update();
data.result.status == 1 ? this.log_msg("<%:Send SMS Success%>",3000) : this.warn_msg("<%:Send SMS Failed%>",3000);
});
}
send_raw_pdu(){
var pdu = pduParser.generate(
{
text: this.message_content.value,
encoding: "16bit",
receiver: this.phone_number.value,
}
)
//if pdu is array,send first pdu
if (Array.isArray(pdu)) {
pdu = pdu[0];
}
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "modem", "send_sms")%>',{
"cfg": this.cfg_id,
"pdu": pdu,
},(x,data)=>{
this.update();
data.result.status == 1 ? this.log_msg("<%:Send SMS Success%>",3000) : this.warn_msg("<%:Send SMS Failed%>",3000);
});
}
lock(){
var delete_btns = document.querySelectorAll('input[value="<%:Delete%>"]');
for (let btn of delete_btns) {
console.log(btn);
btn.disabled = true;
}
}
release(){
var delete_btns = document.querySelectorAll('input[value="<%:Delete%>"]');
for (let btn of delete_btns) {
btn.disabled = false;
}
}
init_send_table_view(){
let phone_number,message_content,send_button,send_raw_pdu_button;
phone_number = document.createElement('input');
phone_number.type = "text";
message_content = document.createElement('textarea');
message_content.rows = 5;
message_content.cols = 50;
send_button = document.createElement('input');
send_button.type = "button";
send_button.value = "<%:Send%>";
send_button.addEventListener('click',()=>{
this.send();
});
this.phone_number = phone_number;
this.message_content = message_content;
this.sms_send_table.data = [
{
"col": 2,
"left": document.createTextNode("<%:Phone Number%>"),
"right": phone_number,
},
{
"col": 2,
"left": document.createTextNode("<%:Message Content%>"),
"right": message_content,
},
{
"col": 2,
"left": document.createTextNode("<%:Send%>"),
"right": send_button,
}
];
}
poll_info(){
if (this.cfg_id == null){
return;
}
XHR.poll(10,'<%=luci.dispatcher.build_url("admin", "network", "modem", "get_sms")%>',{
"cfg": this.cfg_id,
}, (x,data) => {
this.combine_messages(data);
});
}
update(){
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "modem", "get_sms")%>',{
"cfg": this.cfg_id,
}, (x,data) => {
this.combine_messages(data);
});
}
update_modem_cfg_list(){
XHR.poll(5,'<%=luci.dispatcher.build_url("admin", "network", "modem", "get_modem_cfg")%>',{},(x,data)=>{
var new_cfg_list = [];
var cfgs = data.cfgs;
for (let i = 0; i < cfgs.length; i++) {
var cfg = cfgs[i];
var name = cfg.name;
var value = cfg.cfg;
new_cfg_list.push({"value":value,"name":name});
}
if (new_cfg_list != this.modem_cfg_list) {
this.cfg_options = new_cfg_list;
}
});
}
combine_messages(data){
var messages,reference_table,msgs;
messages = []
reference_table = {}
msgs = data.msg;
for ( let msg of msgs){
let part,total,index,reference,sender,timestamp,content;
if (msg.reference){
reference = msg.reference;
if (reference in reference_table){
reference_table[reference].push(msg);
}
else{
reference_table[reference] = [msg];
}
}
else{
msg.index = [msg.index]
messages.push(msg);
}
}
//combile the messages in reference_table
for (let key in reference_table){
let reference_msgs = reference_table[key];
let total = reference_msgs[0].total;
let part = [];
let content = "";
let sender = reference_msgs[0].sender;
let timestamp = reference_msgs[0].timestamp;
let index = [];
reference_msgs.sort((a,b)=>{
return a.part - b.part;
});
for (let reference_msg of reference_msgs){
content += reference_msg.content;
part.push(reference_msg.part);
index.push(reference_msg.index);
}
messages.push({
"sender":sender,
"timestamp":timestamp,
"content":content,
"part":part,
"total":total,
"index":index,
});
}
messages.sort((a,b)=>{
//filter timestamp space and / :
let at,bt
at = a.timestamp;
bt = b.timestamp;
at = at.replace(/ /g,"");
bt = bt.replace(/ /g,"");
at = at.replace(/\//g,"");
bt = bt.replace(/\//g,"");
at = at.replace(/:/g,"");
bt = bt.replace(/:/g,"");
return bt - at;
});
this.view = messages;
}
set cfg_options(value){
var longger = this.modem_cfg_list.length > value.length ? this.modem_cfg_list : value;
if (longger.length == 0) {
return;
}
for (let i = 0; i < longger.length; i++) {
var option = this.selector.options[i];
if (i < value.length) {
if (i >= this.selector.options.length) {
option = document.createElement('option');
this.selector.appendChild(option);
}
option.value = value[i].value;
option.innerHTML = value[i].name;
}
else{
this.selector.removeChild(option);
}
}
this.cfg_id = this.selector.value;
this.modem_cfg_list = value;
this.update();
}
set view(data){
this.data = data;
if (data == null) {
return;
}
var enties = []
var msgs = data;
for (let msg of msgs){
let sender,timestamp,content,part,total,index;
sender = msg.sender;
timestamp = msg.timestamp;
content = msg.content;
part = msg.part;
total = msg.total;
index = msg.index;
let sender_strong,timestamp_strong,content_strong,part_strong,total_strong,delete_btn;
let left,right;
left = document.createElement('div');
right = document.createElement('div');
delete_btn = document.createElement('input');
delete_btn.type = "button";
delete_btn.value = "<%:Delete%>";
delete_btn.addEventListener('click',()=>{
this.lock();
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "modem", "delete_sms")%>',{
"cfg": this.cfg_id,
"index": index.sort((a,b)=>{return b-a}).join(" "),
},(x,data)=>{
this.update();
this.release
});
});
sender_strong = document.createElement('strong');
sender_strong.innerHTML = `<%:Sender%>: ${sender}`;
timestamp_strong = document.createElement('strong');
timestamp_strong.innerHTML = `<%:Timestamp%>: ${timestamp}`;
content_strong = document.createElement('strong');
content_strong.innerHTML = `<%:Content%>: ${content}`;
left.appendChild(sender_strong);
left.appendChild(document.createElement('br'));
left.appendChild(timestamp_strong);
left.appendChild(document.createElement('br'));
left.appendChild(delete_btn);
right.appendChild(content_strong);
if (part != null) {
part_strong = document.createElement('strong');
part_strong.innerHTML = `(${part}/${total})`;
right.appendChild(document.createElement('br'));
right.appendChild(part_strong);
}
enties.push({
"col" : 2,
"left" : left,
"right" : right
});
}
this.sms_recvbox_table.data = enties;
this.sms_recvbox_table.title = "SMS";
}
}
window.onload = function(){
const getSMS = new ModemSMS();
}
</script>
<div>
<div class="cbi-map">
<fieldset class="cbi-section">
<table class="table">
<tbody>
<tr class="tr">
<td class="td" width="33%"><%:Modem Name%></td>
<td class="td" id="modem_selector">
</td>
</tr>
</tbody>
</table>
</fieldset>
</div>
</div>
<%+footer%>

View File

@ -0,0 +1,27 @@
#modem_sms.htm
msgid "Sender"
msgstr "发信人"
msgid "Timestamp"
msgstr "时间戳"
msgid "Content"
msgstr "内容"
msgid "Send SMS"
msgstr "发送短信"
msgid "Send"
msgstr "发送"
msgid "Delete"
msgstr "删除"
msgid "SMS"
msgstr "短信"
msgid "Message Content"
msgstr "短信内容"
msgid "Phone Number"
msgstr "电话号码"

View File

@ -0,0 +1,33 @@
#modem_sms.htm
msgid "Sender"
msgstr "发信人"
msgid "Timestamp"
msgstr "时间戳"
msgid "Content"
msgstr "内容"
msgid "Send SMS"
msgstr "发送短信"
msgid "Send"
msgstr "发送"
msgid "Delete"
msgstr "删除"
msgid "SMS"
msgstr "短信"
msgid "Message Content"
msgstr "短信内容"
msgid "Phone Number"
msgstr "电话号码"
msgid "Send SMS Failed"
msgstr "发送短信失败"
msgid "Send SMS Success"
msgstr "发送短信成功"

View File

@ -0,0 +1,22 @@
# Copyright (C) 2024 Tom <fjrcn@outlook.com>
# This is free software, licensed under the GNU General Public License v3.
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-5gmodem-ttl
LUCI_TITLE:=Luci modem ttl support
LUCI_PKGARCH:=all
PKG_VERSION:=2.0
PKG_LICENSE:=GPLv3
PKG_LINCESE_FILES:=LICENSE
PKF_MAINTAINER:=fujr
LUCI_DEPENDS:=+luci-app-5gmodem
define Package/luci-app-5gmodem-ttl/conffiles
/etc/config/modem_ttl
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,8 @@
-- Copyright 2024 Siriling <siriling@qq.com>
module("luci.controller.modem_ttl", package.seeall)
function index()
if not nixio.fs.access("/etc/config/modem_ttl") then
return
end
entry({"admin", "network", "modem", "modem_ttl"}, cbi("modem/modem_ttl"), luci.i18n.translate("TTL Config"), 22).leaf = true
end

View File

@ -0,0 +1,18 @@
m = Map("modem_ttl", translate("TTL Config"))
s = m:section(NamedSection, "global", "global", translate("Global Config"))
enable = s:option(Flag, "enable", translate("Enable"))
enable.default = "0"
ttl = s:option(Value, "ttl", translate("TTL"))
ttl.default = 64
ttl.datatype = "uinteger"
o = s:option(Value, "ifname", translate("Interface"))
o.rmempty = ture
o.template = "cbi/network_netlist"
o.widget = "optional"
o.nocreate = true
o.unspecified = true
return m

View File

@ -0,0 +1 @@
config global 'global'

View File

@ -0,0 +1,65 @@
#!/bin/sh /etc/rc.common
START=95
STOP=13
USE_PROCD=1
. /usr/share/libubox/jshn.sh
. /lib/functions.sh
start_service()
{
config_load 'modem_ttl'
config_get enable 'global' 'enable' '0'
if [ "$enable" == 0 ]; then
return
fi
set_if_ttl
}
set_if_ttl()
{
config_get ifname 'global' 'ifname'
config_get ttl 'global' 'ttl'
iface=$(ifstatus $ifname)
json_load "$iface"
json_get_var device device
IPT="iptables"
IPT6="ip6tables"
logger -t modem_ttl "Setting TTL for $device to $ttl"
comment="modem_ttl"
$IPT -t mangle -A PREROUTING -i $device -j TTL --ttl-set $ttl -m comment --comment $comment
$IPT -t mangle -A POSTROUTING -o $device -j TTL --ttl-set $ttl -m comment --comment $comment
$IPT6 -t mangle -A PREROUTING -i $device -j HL --hl-set $ttl -m comment --comment $comment
$IPT6 -t mangle -A POSTROUTING -o $device -j HL --hl-set $ttl -m comment --comment $comment
}
stop_service(){
IPT_PREROUTING=$(iptables -t mangle -L PREROUTING -n --line-numbers | grep modem_ttl | awk '{print $1}')
IPT_POSTROUTING=$(iptables -t mangle -L POSTROUTING -n --line-numbers | grep modem_ttl | awk '{print $1}')
IPT6_PREROUTING=$(ip6tables -t mangle -L PREROUTING -n --line-numbers | grep modem_ttl | awk '{print $1}')
IPT6_POSTROUTING=$(ip6tables -t mangle -L POSTROUTING -n --line-numbers | grep modem_ttl | awk '{print $1}')
if [ -n "$IPT_PREROUTING" ]; then
iptables -t mangle -D PREROUTING $IPT_PREROUTING
fi
if [ -n "$IPT_POSTROUTING" ]; then
iptables -t mangle -D POSTROUTING $IPT_POSTROUTING
fi
if [ -n "$IPT6_PREROUTING" ]; then
ip6tables -t mangle -D PREROUTING $IPT6_PREROUTING
fi
if [ -n "$IPT6_POSTROUTING" ]; then
ip6tables -t mangle -D POSTROUTING $IPT6_POSTROUTING
fi
}
service_triggers()
{
procd_add_reload_trigger "modem_ttl"
procd_add_reload_trigger "network"
#netdev
}
reload_service()
{
stop
start
}

View File

@ -1,4 +1,5 @@
# Copyright (C) 2023 Siriling <siriling@qq.com>
# Copyright (C) 2024 Tom <fjrcn@outlook.com>
# This is free software, licensed under the GNU General Public License v3.
include $(TOPDIR)/rules.mk
@ -6,10 +7,10 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-5gmodem
LUCI_TITLE:=LuCI support for Modem
LUCI_PKGARCH:=all
PKG_VERSION:=1.4.4
PKG_VERSION:=2.0
PKG_LICENSE:=GPLv3
PKG_LINCESE_FILES:=LICENSE
PKF_MAINTAINER:=Siriling <siriling@qq.com>
PKF_MAINTAINER:=Tom <fjrcn@outlook.com>
LUCI_DEPENDS:=+luci-compat +kmod-usb-net +kmod-usb-net-cdc-ether +kmod-usb-acm \
+kmod-usb-net-rndis \
+kmod-usb-net-sierrawireless +kmod-usb-ohci\
@ -29,7 +30,8 @@ LUCI_DEPENDS:=+luci-compat +kmod-usb-net +kmod-usb-net-cdc-ether +kmod-usb-acm \
+quectel-CM-5G \
+sms-tool \
+jq +grep +bc\
+coreutils +coreutils-stat
define Package/luci-app-5gmodem/conffiles
/etc/config/modem

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,92 @@
'use strict';
'require baseclass';
'require rpc';
var callModemInfo = rpc.declare({
object: 'modem_ctrl',
method: 'info'
});
function progressbar(value, max, min, unit) {
var value = parseInt(value) || 0,
max = parseInt(max) || 100,
min = parseInt(min) || 0,
unit = unit || '',
pc = Math.floor((100 / (max - min)) * (value - min));
return E('div', {
'class': 'cbi-progressbar',
'title': '%s / %s%s (%d%%)'.format(value, max, unit,pc)
}, E('div', { 'style': 'width:%.2f%%'.format(pc) }));
}
return baseclass.extend({
title: _('Modem Info'),
load: function() {
return Promise.all([
L.resolveDefault(callModemInfo(), {}),
]);
},
render: function(data) {
var table = E('table', { 'class': 'table' });
try {
var infos = data[0].info
var fields = [];
for (let modem_info of infos) {
var info = modem_info.modem_info;
for (var entry of info) {
var full_name = entry.full_name;
if (entry.value == null) {
continue
}
if ((entry.class == 'Base Information') ||(entry.class == '"SIM Information"') || (entry.class == 'Cell Information' && entry.type == 'progress_bar')) {
fields.push(_(full_name));
fields.push(entry);
}
}
if (fields.length == 0) {
table.appendChild(E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'width': '100%' }, [ _('No modem information available') ])
]));
return table;
}
}
for (var i = 0; i < fields.length; i += 2) {
let entry, type, value;
entry = fields[i + 1];
type = entry.type;
if (type == 'progress_bar') {
value = E('td', { 'class': 'td left' }, [
(entry.value != null) ? progressbar(entry.value, entry.max_value, entry.min_value, entry.unit) : '?'
])
} else {
value = E('td', { 'class': 'td left' }, [ (fields[i + 1] != null) ? entry.value : '?' ])
}
table.appendChild(E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'width': '33%' }, [ fields[i] ]),
value
]));
}
return table;
}
catch (e) {
table.appendChild(E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'width': '100%' }, [ _('No modem information available') ])
]));
return table;
}
}
});

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ s:tab("advanced", translate("Advanced Settings"))
--------general--------
-- 是否启用
enable = s:taboption("general", Flag, "enable", translate("Enable"))
enable = s:taboption("general", Flag, "enable_dial", translate("enable_dial"))
enable.default = "0"
enable.rmempty = false
@ -22,82 +22,23 @@ enable.rmempty = false
remarks = s:taboption("general", Value, "remarks", translate("Remarks"))
remarks.rmempty = true
-- 移动网络
-- network = s:taboption("general", Value, "network", translate("Mobile Network"))
network = s:taboption("general", ListValue, "network", translate("Mobile Network"))
-- network.default = ""
network.rmempty = false
-- AT串口
at_port = s:taboption("general",Value, "at_port", translate("AT Port"))
at_port.placeholder = translate("Not null")
at_port.rmempty = false
-- 获取移动网络,并显示设备名
function getMobileNetwork()
local modem_number=uci:get('modem','global','modem_number')
if modem_number == "0" then
network:value("",translate("Mobile network not found"))
end
return
-- for i=0,modem_number-1 do
-- --获取模块名
-- local modem_name = uci:get('modem','modem'..i,'name')
-- if modem_name == nil then
-- modem_name = "unknown"
-- end
-- --设置网络
-- modem_network = uci:get('modem','modem'..i,'network')
-- if modem_network ~= nil then
-- network:value(modem_network,modem_network.." ("..translate(modem_name:upper())..")")
-- end
-- end
uci:foreach("modem", "modem-device", function (modem_device)
--获取模块名
local modem_name=modem_device["name"]
--获取网络
local modem_network=modem_device["network"]
--设置网络值
network:value(modem_network,modem_network.." ("..translate(modem_name:upper())..")")
end)
end
getMobileNetwork()
-- 拨号模式
-- mode = s:taboption("general", ListValue, "mode", translate("Mode"))
-- mode.rmempty = false
-- mode.description = translate("Only display the modes available for the adaptation modem")
-- local modes = {"qmi","gobinet","ecm","mbim","rndis","ncm"}
-- for i in ipairs(modes) do
-- mode:value(modes[i],string.upper(modes[i]))
-- end
-- 添加获取拨号模式信息
-- m:append(Template("modem/mode_info"))
--------advanced--------
-- 拨号工具
dial_tool = s:taboption("advanced", ListValue, "dial_tool", translate("Dial Tool"))
dial_tool.description = translate("After switching the dialing tool, it may be necessary to restart the module or restart the router to recognize the module.")
dial_tool.rmempty = true
dial_tool:value("", translate("Auto Choose"))
dial_tool:value("quectel-CM", translate("quectel-CM"))
dial_tool:value("mmcli", translate("mmcli"))
ra_master = s:taboption("advanced", Flag, "ra_master", translate("RA Master"))
ra_master.description = translate("After checking, This interface will enable IPV6 RA Master.Only one interface can be set to RA Master.")
ra_master.default = "0"
-- 网络类型
pdp_type= s:taboption("advanced", ListValue, "pdp_type", translate("PDP Type"))
pdp_type.default = "ipv4v6"
pdp_type.rmempty = false
pdp_type:value("ipv4", translate("IPv4"))
pdp_type:value("ip", translate("IPv4"))
pdp_type:value("ipv6", translate("IPv6"))
pdp_type:value("ipv4v6", translate("IPv4/IPv6"))
-- 网络桥接
network_bridge = s:taboption("advanced", Flag, "network_bridge", translate("Network Bridge"))
network_bridge.description = translate("After checking, enable network interface bridge.")
network_bridge.default = "0"
network_bridge.rmempty = false
-- 接入点
apn = s:taboption("advanced", Value, "apn", translate("APN"))
@ -131,13 +72,54 @@ password:depends("auth", "both")
password:depends("auth", "pap")
password:depends("auth", "chap")
pincode = s:taboption("advanced", Value, "pincode", translate("PIN Code"))
pincode.description = translate("If the PIN code is not set, leave it blank.")
--卡2
apn = s:taboption("advanced", Value, "apn2", translate("APN").." 2")
apn.description = translate("If solt 2 config is not set,will use slot 1 config.")
apn.default = ""
apn.rmempty = true
apn:value("", translate("Auto Choose"))
apn:value("cmnet", translate("China Mobile"))
apn:value("3gnet", translate("China Unicom"))
apn:value("ctnet", translate("China Telecom"))
apn:value("cbnet", translate("China Broadcast"))
apn:value("5gscuiot", translate("Skytone"))
auth = s:taboption("advanced", ListValue, "auth2", translate("Authentication Type").. " 2")
auth.default = "none"
auth.rmempty = false
auth:value("none", translate("NONE"))
auth:value("both", translate("PAP/CHAP (both)"))
auth:value("pap", "PAP")
auth:value("chap", "CHAP")
username = s:taboption("advanced", Value, "username2", translate("PAP/CHAP Username").. " 2")
username.rmempty = true
username:depends("auth2", "both")
username:depends("auth2", "pap")
username:depends("auth2", "chap")
password = s:taboption("advanced", Value, "password2", translate("PAP/CHAP Password").. " 2")
password.rmempty = true
password.password = true
password:depends("auth2", "both")
password:depends("auth2", "pap")
password:depends("auth2", "chap")
pincode = s:taboption("advanced", Value, "pincode2", translate("PIN Code").. " 2")
pincode.description = translate("If the PIN code is not set, leave it blank.")
metric = s:taboption("advanced", Value, "metric", translate("Metric"))
metric.description = translate("The metric value is used to determine the priority of the route. The smaller the value, the higher the priority. Cannot duplicate.")
metric.default = "10"
-- 配置ID
id = s:taboption("advanced", ListValue, "id", translate("Config ID"))
id.rmempty = false
id:value(arg[1])
-- uci:set('modem',arg[1],'id',arg[1])
-- 隐藏配置ID
m:append(Template("modem/hide_dial_config_id"))
return m

View File

@ -11,63 +11,53 @@ s = m:section(NamedSection, "global", "global", translate("Global Config"))
s.anonymous = true
s.addremove = false
-- 模组扫描
o = s:option(Button, "modem_scan", translate("Modem Scan"))
o.template = "modem/modem_scan"
-- 启用手动配置
o = s:option(Flag, "manual_configuration", translate("Manual Configuration"))
o.rmempty = false
o.description = translate("Enable the manual configuration of modem information").." " translate("(After enable, the automatic scanning and configuration function for modem information will be disabled)")
o = s:option(Flag, "enable_dial", translate("Enable Dial"))
o.rmempty = false
o.description = translate("Enable dial configurations")
-- 添加模块状态
m:append(Template("modem/modem_status"))
o = s:option(Button, "reload_dial", translate("Reload Dial Configurations"))
o.inputstyle = "apply"
o.description = translate("Manually Reload dial configurations When the dial configuration fails to take effect")
o.write = function()
sys.call("/etc/init.d/modem_network reload")
luci.http.redirect(d.build_url("admin", "network", "modem", "dial_overview"))
end
s = m:section(TypedSection, "modem-device", translate("Config List"))
s.anonymous = true
s.addremove = ture
s.template = "modem/tblsection"
s.template = "cbi/tblsection"
s.extedit = d.build_url("admin", "network", "modem", "dial_config", "%s")
-- function s.create(uci, t)
-- local uuid = string.gsub(luci.sys.exec("echo -n $(cat /proc/sys/kernel/random/uuid)"), "-", "")
-- t = uuid
-- TypedSection.create(uci, t)
-- luci.http.redirect(uci.extedit:format(t))
-- end
-- function s.remove(uci, t)
-- uci.map.proceed = true
-- uci.map:del(t)
-- luci.http.redirect(d.build_url("admin", "network", "modem","dial_overview"))
-- end
o = s:option(Flag, "enable_dial", translate("enable_dial"))
o.width = "5%"
o.rmempty = false
-- o = s:option(DummyValue, "status", translate("Status"))
-- o.template = "modem/status"
-- o.value = translate("Collecting data...")
o = s:option(DummyValue, "name", translate("Modem Name"))
o.cfgvalue = function(t, n)
local name = (Value.cfgvalue(t, n) or "")
return name:upper()
end
o = s:option(DummyValue, "remarks", translate("Remarks"))
o = s:option(DummyValue, "network", translate("Mobile Network"))
o = s:option(DummyValue, "state", translate("Modem Status"))
o.cfgvalue = function(t, n)
-- 检测移动网络是否存在
local network = (Value.cfgvalue(t, n) or "")
local odpall = io.popen("ls /sys/class/net/ | grep -w "..network.." | wc -l")
local odp = odpall:read("*a"):gsub("\n","")
odpall:close()
if odp ~= "0" then
return network
else
return translate("The network device was not found")
end
local name = translate(Value.cfgvalue(t, n) or "")
return name:upper()
end
o = s:option(DummyValue, "dial_tool", translate("Dial Tool"))
o.cfgvalue = function(t, n)
local dial_tool = (Value.cfgvalue(t, n) or "")
if dial_tool == "" then
dial_tool = translate("Auto Choose")
end
return translate(dial_tool)
end
o = s:option(DummyValue, "pdp_type", translate("PDP Type"))
@ -81,9 +71,6 @@ o.cfgvalue = function(t, n)
return pdp_type
end
o = s:option(Flag, "network_bridge", translate("Network Bridge"))
o.width = "5%"
o.rmempty = false
o = s:option(DummyValue, "apn", translate("APN"))
o.cfgvalue = function(t, n)
@ -94,9 +81,17 @@ o.cfgvalue = function(t, n)
return apn
end
remove_btn = s:option(Button, "_remove", translate("Remove"))
remove_btn.inputstyle = "remove"
function remove_btn.write(self, section)
local shell
shell="/usr/share/modem/modem_scan.sh remove "..section
luci.sys.call(shell)
--refresh the page
luci.http.redirect(d.build_url("admin", "network", "modem", "dial_overview"))
end
-- 添加模块拨号日志
m:append(Template("modem/modem_dial_log"))
m:append(Template("modem/dial_overview"))
-- m:append(Template("modem/list_status"))
return m

View File

@ -1,162 +0,0 @@
local dispatcher = require "luci.dispatcher"
local uci = require "luci.model.uci".cursor()
local sys = require "luci.sys"
local json = require("luci.jsonc")
local script_path="/usr/share/modem/"
--[[
@Description Shell脚本
@Params
command sh命令
]]
function shell(command)
local odpall = io.popen(command)
local odp = odpall:read("*a")
odpall:close()
return odp
end
--[[
@Description
@Params
data_interface
]]
function getSupportModems(data_interface)
local command="cat "..script_path.."modem_support.json"
local result=json.parse(shell(command))
return result["modem_support"][data_interface]
end
--[[
@Description
]]
function getManufacturers()
local manufacturers={}
-- 获取支持的模组
local support_modem=getSupportModems("usb")
-- USB
for modem in pairs(support_modem) do
local manufacturer=support_modem[modem]["manufacturer"]
if manufacturers[manufacturer] then
-- 直接插入
table.insert(manufacturers[manufacturer],modem)
else
-- 不存在先创建一个空表
local tmp={}
table.insert(tmp,modem)
manufacturers[manufacturer]=tmp
end
end
-- 获取支持的模组
local support_modem=getSupportModems("pcie")
-- PCIE
for modem in pairs(support_modem) do
local manufacturer=support_modem[modem]["manufacturer"]
if manufacturers[manufacturer] then
-- 直接插入
table.insert(manufacturers[manufacturer],modem)
else
-- 不存在先创建一个空表
local tmp={}
table.insert(tmp,modem)
manufacturers[manufacturer]=tmp
end
end
return manufacturers
end
m = Map("modem", translate("Modem Config"))
m.redirect = dispatcher.build_url("admin", "network", "modem","plugin_config")
s = m:section(NamedSection, arg[1], "modem-device", "")
s.addremove = false
s.dynamic = false
-- 手动配置
manual = s:option(Flag, "manual", translate("Manual"))
manual.default = "1"
manual.rmempty = false
-- uci:set('modem','modem-device','manual',1)
-- 隐藏手动配置
m:append(Template("modem/hide_manual_config_modem"))
-- 移动网络
mobile_network = s:option(ListValue, "network", translate("Mobile Network"))
mobile_network.rmempty = true
-- 获取移动网络
function getMobileNetwork()
--获取所有的网络接口
local networks = sys.exec("ls -l /sys/class/net/ 2>/dev/null |awk '{print $9}' 2>/dev/null")
--遍历所有网络接口
for network in string.gmatch(networks, "%S+") do
-- 只处理最上级的网络设备
-- local count=$(echo "${network_path}" | grep -o "/net" | wc -l)
-- [ "$count" -ge "2" ] && return
-- 获取网络设备路径
local command="readlink -f /sys/class/net/"..network
local network_path=shell(command)
-- 判断路径是否带有usb排除其他eth网络设备
local flag="0"
if network_path:find("eth") and not network_path:find("usb") then
flag="1"
end
if flag=="0" then
if network:find("usb") or network:find("wwan") or network:find("eth") then
--设置USB移动网络
mobile_network:value(network)
elseif network:find("mhi_hwip") or network:find("rmnet_mhi") then
--设置PCIE移动网络
mobile_network:value(network)
end
end
end
end
getMobileNetwork()
-- 模组名称
name = s:option(ListValue, "name", translate("Modem Name"))
name.placeholder = translate("Not null")
name.rmempty = false
-- 按照制造商给模组分类
local manufacturers=getManufacturers()
for key in pairs(manufacturers) do
local modems=manufacturers[key]
-- 排序
table.sort(modems)
for i in pairs(modems) do
-- 首字母大写
local first_str=string.sub(key, 1, 1)
local manufacturer = string.upper(first_str)..string.sub(key, 2)
-- 设置值
name:value(modems[i],manufacturer.." "..modems[i]:upper())
end
end
-- AT串口
at_port = s:option(Value, "at_port", translate("AT Port"))
at_port.placeholder = translate("Not null")
at_port.rmempty = false
enable_dial = s:option(Flag, "enable_dial", translate("enable_dial"))
enable_dial.default = 1
enable_dial.rmempty = false
return m

View File

@ -1,78 +0,0 @@
local d = require "luci.dispatcher"
local uci = luci.model.uci.cursor()
local sys = require "luci.sys"
local script_path="/usr/share/modem/"
m = Map("modem")
m.title = translate("Plugin Config")
m.description = translate("Check and modify the plugin configuration")
font_red = [[<b style=color:red>]]
font_off = [[</b>]]
bold_on = [[<strong>]]
bold_off = [[</strong>]]
--全局配置
s = m:section(TypedSection, "global", translate("Global Config"))
s.anonymous = true
s.addremove = false
-- 模组扫描
o = s:option(Button, "modem_scan", translate("Modem Scan"))
o.template = "modem/modem_scan"
-- 启用手动配置
o = s:option(Flag, "manual_configuration", font_red..bold_on..translate("Manual Configuration")..bold_off..font_off)
o.rmempty = false
o.description = translate("Enable the manual configuration of modem information").." "..font_red..bold_on.. translate("(After enable, the automatic scanning and configuration function for modem information will be disabled)")..bold_off..font_off
-- 配置模组信息
s = m:section(TypedSection, "modem-device", translate("Modem Config"))
s.anonymous = true
s.addremove = true
-- s.sortable = true
s.template = "modem/tblsection"
s.extedit = d.build_url("admin", "network", "modem", "modem_config", "%s")
function s.create(uci, t)
-- 获取模组序号
-- local modem_no=tonumber(uci.map:get("@global[0]","modem_number")) -- 将字符串转换为数字类型
local modem_no=0
local uci_tmp=luci.model.uci.cursor()
uci_tmp:foreach("modem", "modem-device", function (modem_device)
modem_no=modem_no+1
end)
t="modem"..modem_no
TypedSection.create(uci, t)
-- 设置手动配置
-- uci.map:set(t,"manual","1")
luci.http.redirect(uci.extedit:format(t))
end
function s.remove(uci, t)
uci.map.proceed = true
uci.map:del(t)
luci.http.redirect(d.build_url("admin", "network", "modem","plugin_config"))
end
-- 移动网络
o = s:option(DummyValue, "network", translate("Network"))
-- 模组名称
o = s:option(DummyValue, "name", translate("Modem Name"))
o.cfgvalue = function(t, n)
local name = (Value.cfgvalue(t, n) or "")
return name:upper()
end
-- AT串口
o = s:option(DummyValue, "at_port", translate("AT Port"))
o = s:option(Flag,'enable_dial',translate('Enable Dial'))
-- o = s:option(Value, "at_port", translate("AT Port"))
-- o.placeholder = translate("Not null")
-- o.rmempty = false
-- o.optional = false
return m

View File

@ -1,30 +0,0 @@
-- Copyright 2024 Siriling <siriling@qq.com>
local dispatcher = require "luci.dispatcher"
local fs = require "nixio.fs"
local http = require "luci.http"
local uci = require "luci.model.uci".cursor()
m = Map("custom_at_commands")
m.title = translate("Custom quick commands")
m.description = translate("Customize your quick commands")
m.redirect = dispatcher.build_url("admin", "network", "modem","modem_debug")
-- 自定义命令 --
s = m:section(TypedSection, "custom-commands", translate("Custom Commands"))
s.anonymous = true
s.addremove = true
s.sortable = true
s.template = "modem/tblsection_command"
description = s:option(Value, "description", translate("Description"))
description.placeholder = translate("Not null")
description.rmempty = true
description.optional = false
command = s:option(Value, "command", translate("Command"))
command.placeholder = translate("Not null")
command.rmempty = true
command.optional = false
return m

View File

@ -1,290 +0,0 @@
<%+header%>
<style type="text/css">
/* 消息样式 */
#info_message {
text-align: left;
font-size: 1.8em;
}
#info_message img {
vertical-align: middle;
}
#info_message a {
color: rgb(61, 143, 173);
font-size: 50%;
}
#modem_status_view > div {
display: inline-block;
margin: 1rem;
padding: 1rem;
width: 15rem;
float: left;
line-height: 125%;
}
</style>
<script type="text/javascript">
window.onload=function()
{
//获取快捷AT命令选择框元素
var command_select = document.getElementById('command_select');
//更换快捷AT命令时触发
command_select.addEventListener("change", function() {
//自动填写到命令输入框
copy_to_input();
});
//获取快捷AT命令选择框元素
command_select = document.getElementById('command_select');
//点击快捷AT命令时触发解决选择第一条命令的问题
command_select.addEventListener("click", function() {
//选择框不为空,且选中的为第一个
if (command_select.options.length != 0 && command_select.selectedIndex == 0) {
//自动填写到命令输入框
copy_to_input();
}
});
}
//自动填写到命令输入框
function copy_to_input()
{
var node = document.getElementById('response');
node.style.visibility = 'hidden';
var command_select = document.getElementById("command_select").value;
document.getElementById("at_command").value = command_select;
document.getElementById("response").innerHTML = "";
}
//第一次打开界面
first_start=1;
// 获取快捷命令
function get_quick_commands()
{
//获取快捷选项
var quick_option = "custom";
//获取选中的模组
var at_port = document.getElementById("modem_select").value;
//获取AT命令
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "modem", "get_quick_commands")%>', {"option":quick_option,"port":at_port},
function(x, data)
{
//获取模组选择框元素
var command_select = document.getElementById('command_select');
//获取快捷命令
var quick_commands=data["quick_commands"];
//遍历每一条信息
for (var info of quick_commands)
{
//遍历每一条信息里的键
for (var key in info)
{
var option = document.createElement('option');
option.text = key;
option.value = info[key];
command_select.appendChild(option);
}
}
}
);
}
// 定时触发更新AT串口
XHR.poll(5,'<%=luci.dispatcher.build_url("admin", "network", "modem", "get_at_port")%>', null,
function(x, data)
{
var at_ports=data["at_ports"];
//获取模块选择框元素
var modem_select = document.getElementById('modem_select');
// 记录所选
var selected=modem_select.value;
// 删除原来的选项
modem_select.options.length=0;
//遍历每一个AT串口
for (var port of at_ports)
{
//更新keyAT串口value模块名称
for (var key in port)
{
var option = document.createElement('option');
option.value = key;
var language=navigator.language;
if (port[key].includes("unknown"))
{
option.text = port[key].replace("unknown", key);
}
else
{
option.text = port[key];
}
modem_select.appendChild(option);
}
}
// 恢复原来的选择
for (let i = 0; i < modem_select.options.length; i++)
{
if(modem_select.options[i].value == selected)
{
modem_select.selectedIndex=i;
break;
}
}
// 界面显示控制
if (Object.keys(at_ports).length==0)
{
// 更新提示信息
document.getElementById("info_message").innerHTML='<strong><%:No modems found%></strong> <a href="https://blog.siriling.com:1212/2023/03/18/openwrt-5g-modem/#zi-dong-sao-miao-shi-bie-gong-neng" target="_blank"><%:(Check the reason)%></a>';
// 显示提示信息
document.getElementById("cbi-info").style.display="block";
// 隐藏AT命令界面
document.getElementById("at_command_view").style.display="none";
}
else
{
//获取快捷命令
if (first_start)
{
get_quick_commands();
first_start=0
}
// 显示AT命令界面
document.getElementById("at_command_view").style.display="block";
// 隐藏提示信息
document.getElementById("cbi-info").style.display="none";
}
}
);
function post_command(at_port,at_command)
{
XHR.post('<%=luci.dispatcher.build_url("admin", "network", "modem", "send_at_command")%>', {"port":at_port,"command":at_command},
function(x, data)
{
responseElement=document.getElementById("response");
if ("response" in data) {
//显示当前时间
// responseElement.value+=data["time"];
//显示返回值
responseElement.innerHTML+=data["response"];
}
}
);
return false;
}
document.addEventListener('DOMContentLoaded', function (ev) {
var button = document.getElementById("sendcmd");
button.addEventListener("click", function () {
//获取AT串口
var at_port = document.getElementById("modem_select").value;
if ( at_port.length == 0 )
{
document.getElementById("response").innerHTML = "";
alert("<%:Please choose a Modem%>");
return false;
}
//获取AT命令
var at_command = document.getElementById("at_command").value;
if ( at_command.length == 0 )
{
document.getElementById("response").innerHTML = "";
alert("<%:Please enter a AT Command%>");
return false;
}
//发送AT命令
post_command(at_port,at_command);
at_command = "";
var node = document.getElementById('response');
if (node.style.visibility=='visible') {
node.style.visibility = 'hidden';
}
else
node.style.visibility = 'visible'
return true;
});
}, true);
</script>
<h2 name="content"><%:AT Commands%></h2>
<div class="cbi-map-descr"><%:Debug Your Module%></div>
<fieldset class="cbi-section" id="cbi-info" style="display: block;">
<div class="cbi-section fade-in">
<h3><%:Message%></h3>
<table class="table" id="message">
<tr class="tr">
<td colspan="2" class="td left">
<div id="info_message">
<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>"/>
<%:Loading modem%>...
</div>
</td>
</tr>
</table>
</div>
</fieldset>
<div id="at_command_view" style="display: none;">
<h4><br/></h4>
<div class="table" width="100%">
<div class="tr">
<div class="td left" style="width:25%;"><%:Modem Select%></div>
<div class="td left" style="width:50%;">
<select name="modem_select" id="modem_select"></select>
</div>
<!-- <div class="td left" style="width:50%;"></div> -->
</div>
<div class="tr">
<div class="td left" style="width:25%;"><%:Quick Commands%></div>
<div class="td left" style="width:50%;">
<select name="command_select" id="command_select"></select>
</div>
<!-- <div class="td left" style="width:50%;"></div> -->
</div>
<div class="tr">
<div class="td left" style="width:25%;"><%:Enter Command%></div>
<div class="td left" style="width:50%;">
<input type="text" id="at_command" required size="20" >
</div>
<!-- <div class="td left" style="width:50%;"></div> -->
</div>
</div>
<div class="table" width="100%">
<div class="td left" style="width:25%;"><%:Response%>:
<pre id="response" style="visibility: hidden; width:100%;"></pre>
</div>
<div class="tr cbi-rowstyle-2">
<div class="td right"><input type="button" style="margin-right: 26%"; id="sendcmd" class="btn cbi-button cbi-button-neutral" value="<%:Send Command%>" /></div>
</div>
</div>
<div class="cbi-page-actions">
<input class="btn cbi-button cbi-button-link" type="button" value="<%:Return to modem debug%>" onclick="location.href='/cgi-bin/luci/admin/network/modem/modem_debug'">
</div>
</div>
<%+footer%>

View File

@ -0,0 +1,351 @@
<script type="text/javascript">//<![CDATA[
class LuciField {
constructor(classList,title){
this.classList=classList;
this.newLuciField();
this.title=title;
}
newLuciField(){
var field=document.createElement("fieldset");
for (var class_name of this.classList)
{
field.classList.add(class_name);
}
var h3title = document.createElement("h3")
field.appendChild(h3title);
this.h3title=h3title;
this.field=field;
}
set title(t){
this.h3title.innerHTML=t;
if (t != "")
{
this.h3title.style.display="";
}
else
{
this.h3title.style.display="none";
}
}
}
class LuciBtn {
constructor(classList,value,callback){
var btn=document.createElement("input");
var base_classList = ["cbi-button","btn"];
this.classList=base_classList.concat(classList);
for (var class_name of this.classList)
{
btn.classList.add(class_name);
}
btn.setAttribute('type','button');
btn.setAttribute('value',value);
btn.addEventListener('click',callback);
this.btn=btn;
}
}
class ModemState
{
constructor(){
this.modem_state_div = document.createElement('div');
this.modem_state_div.classList.add("modem_status_box");
this.connect_state = -1;
}
update(modem_datas){
var entrys = [];
this.connect_state = -1;
for (var entry of modem_datas)
{
//handle special entry
if (entry.key=="connect_status")
{
var state = '';
var css = '';
switch (entry.value)
{
case 'Yes':
entry.value = '<%:Connected%>';
this.connect_state = 1;
break;
case 'No':
entry.value = '<%:Disconnected%>';
this.connect_state = 0;
break;
default:
entry.value = '<%:unknown%>';
this.connect_state = -1;
break;
}
}
entrys.push(entry);
}
this.render(entrys);
}
render(entrys){
this.modem_state_div.innerHTML = "";
switch (this.connect_state)
{
case 1:
this.modem_state_div.classList.add("alert-message","success");
break;
case 0:
this.modem_state_div.classList.add("alert-message","danger");
break;
default:
this.modem_state_div.classList.add("alert-message","warning");
break;
}
for (var entry of entrys)
{
var key,value,full_name;
key=entry.key;
value=entry.value;
full_name=entry.full_name;
if (key == "connect_status" || key == "name" )
{
var div = document.createElement('div');
var strong = document.createElement('strong');
strong.innerHTML = value.toUpperCase();
div.appendChild(strong);
}
else
{
var div = document.createElement('div');
var strong = document.createElement('strong');
var span = document.createElement('span');
strong.innerHTML = full_name + ": ";
span.innerHTML = value;
div.appendChild(strong);
div.appendChild(span);
}
this.modem_state_div.appendChild(div);
}
}
}
class ModemLog {
constructor(section_name){
this.modem_log_div = document.createElement('div');
this.modem_log_div.style.display = "none";
this.modem_logmsg_textarea = document.createElement('textarea');
this.modem_logmsg_textarea.setAttribute('readonly','readonly');
this.modem_logmsg_textarea.setAttribute('rows','20');
this.modem_logmsg_textarea.setAttribute('maxlength','160');
var download_btn = new LuciBtn(["cbi-button-link"],"<%:Download%>",() => {
this.download();
}).btn;
var clear_btn = new LuciBtn(["cbi-button-reset"],"<%:Clear%>",() => {
this.clear();
}).btn;
var btns_div = document.createElement('div');
btns_div.appendChild(download_btn);
btns_div.appendChild(clear_btn);
this.btns_div = btns_div;
this.modem_log_div.appendChild(this.modem_logmsg_textarea);
this.modem_log_div.appendChild(this.btns_div);
this.section_name = section_name;
this.scroll_top = -1;
}
download(){
var file_name = this.section_name+"_dial_log.txt";
var file_content = this.log_msg;
var blob = new Blob([file_content], {type: "text/plain;charset=utf-8"});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = file_name;
a.click();
}
clear(){
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "modem", "modem_ctrl")%>', {"action":"clear_dial_log","cfg":this.section_name},
function(x, data)
{
var state = data.result.state;
if (state == "1")
{
this.log_msg = "";
this.render();
}
}
);
}
update(log_msg){
this.scroll_top = this.modem_logmsg_textarea.scrollTop;
this.log_msg = log_msg;
this.render();
this.modem_logmsg_textarea.scrollTop = this.scroll_top;
}
render(){
this.modem_logmsg_textarea.innerHTML=this.log_msg;
}
}
class ModemDialOverview {
constructor(){
this.modem_state_field=new LuciField(["cbi-section","cbi-section-modem-state"],"<%:Modem Status%>").field;
this.modem_log_tab_data_field = document.createElement('div');
this.modem_log_tab_menu_field = document.createElement('ul');
this.modem_log_tab_menu_field.classList.add("tabs")
this.modem_log_field=new LuciField(["cbi-section","cbi-section-modem-log"],"<%:Modem Log%>").field;
this.modems_state = [];
this.modems_logs = {};
this.modems_logs_menu = {};
this.activated_section = "";
this.modem_log_field.appendChild(this.modem_log_tab_menu_field);
this.modem_log_field.appendChild(this.modem_log_tab_data_field);
this.maincontent = document.getElementById("maincontent");
this.maincontent.appendChild(this.modem_state_field);
this.maincontent.appendChild(this.modem_log_field);
this.poll();
}
activate()
{
for (var section_name in this.modems_logs)
{
if (section_name == this.activated_section)
{
this.modems_logs[section_name].modem_log_div.style.display = "";
this.modems_logs_menu[section_name].classList.add("active");
}
else
{
this.modems_logs[section_name].modem_log_div.style.display = "none";
this.modems_logs_menu[section_name].classList.remove("active");
}
}
}
poll()
{
XHR.poll(5,'<%=luci.dispatcher.build_url("admin", "network", "modem", "modems_dial_overview")%>',{},
(x,data)=>{
this.update_modems_state(data.modems);
this.update_modems_log(data.logs);
});
}
update_modems_state(modems){
for (var i in modems)
{
var modem_info = modems[i];
if (this.modems_state[i]==null)
{
this.modems_state[i]=new ModemState();
this.modem_state_field.appendChild(this.modems_state[i].modem_state_div);
}
this.modems_state[i].update(modem_info);
}
if (this.modems_state.length> modems.length)
{
for (var i = modems.length; i < this.modems_state.length; i++)
{
this.modem_state_field.removeChild(this.modems_state[i].modem_state_div);
delete this.modems_state[i];
}
}
}
update_modems_log(logs){
var menus = [];
for (var log of logs)
{
var section_name,modem_name,log_msg;
section_name = log.section_name;
modem_name = log.name;
log_msg = log.log_msg;
menus.push(section_name);
if ( this.modems_logs[section_name]==null )
{
this.modems_logs[section_name]=new ModemLog(section_name);
let a = document.createElement('a');
let li = document.createElement('li');
let s = section_name;
li.appendChild(a);
a.href = "#";
a.innerHTML = modem_name.toUpperCase();
a.addEventListener('click',() => {
this.activate_tab = s;
});
this.modems_logs_menu[section_name]=li;
this.modem_log_tab_menu_field.appendChild(li);
this.modem_log_tab_data_field.appendChild(this.modems_logs[section_name].modem_log_div);
}
this.modems_logs[section_name].update(log_msg);
}
this.update_modems_log_menu();
//remove the log that not exist
for (var section_name in this.modems_logs)
{
if (menus.indexOf(section_name)==-1)
{
this.modem_log_tab_menu_field.removeChild(this.modems_logs_menu[section_name]);
this.modem_log_tab_data_field.removeChild(this.modems_logs[section_name].modem_log_div);
delete this.modems_logs[section_name];
delete this.modems_logs_menu[section_name];
}
}
}
update_modems_log_menu(){
if (this.activated_section == "")
{
this.activate_tab = Object.keys(this.modems_logs)[0];
}
}
set activate_tab(section_name){
this.activated_section = section_name;
this.activate();
}
}
window.onload = function(){
var modem_dial_overview = new ModemDialOverview();
}
</script>
<style type="text/css">
/* AT命令响应 */
textarea {
background:#373737;
border:none;
color:#FFF;
width: 100%;
border-top-width: 2px;
padding-top: 12px;
}
/* 加载中样式 */
#modem_status_view img {
vertical-align: middle;
}
.modem_status_box {
display: inline-block;
margin: 1rem;
padding: 1rem;
width: 16rem;
float: left;
line-height: 125%;
}
</style>

View File

@ -1,20 +0,0 @@
<script type="text/javascript">//<![CDATA[
window.onload=function()
{
// 获取高级设置标签元素
var str="advanced"
var advanced_element = document.querySelector('div[data-tab="'+str+'"]');
// 适配老版lucilede
if (advanced_element==null) {
advanced_element = document.querySelectorAll('div[id*="'+str+'"]')[0];
}
//隐藏拨号配置ID元素
var dial_config_id_element = advanced_element.lastElementChild;
dial_config_id_element.style.display="none";
}
//]]>
</script>

View File

@ -1,19 +0,0 @@
<script type="text/javascript">//<![CDATA[
window.onload=function()
{
// 获取高级设置标签元素
var str="manual"
var manual_element = document.querySelector('div[data-tab="'+str+'"]');
// 适配老版lucilede
if (manual_element==null) {
manual_element = document.querySelectorAll('div[id*="'+str+'"]')[0];
}
//隐藏拨号配置ID元素
manual_element.style.display="none";
}
//]]>
</script>

View File

@ -1,19 +0,0 @@
<script type="text/javascript">
//<![CDATA[
var _status = document.getElementsByClassName('_status');
for(var i = 0; i < _status.length; i++) {
var id = _status[i].parentElement.parentElement.parentElement.id;
id = id.substr(id.lastIndexOf("-") + 1);
XHR.poll(1,'<%=url([[admin]], [[network]], [[modem]], [[status]])%>', {
index: i,
id: id
},
function(x, result) {
_status[result.index].setAttribute("style","font-weight:bold;");
_status[result.index].setAttribute("color",result.status ? "green":"red");
_status[result.index].innerHTML = (result.status ? '✓' : 'X');
}
);
}
//]]>
</script>

View File

@ -1,51 +0,0 @@
<script type="text/javascript">
window.onload=function()
{
var url=window.location.pathname
var lastSlashIndex = url.lastIndexOf("/");
var uuid = url.substring(lastSlashIndex + 1);
// 查询network元素
var network = document.getElementById("widget.cbid.modem."+uuid+".network");
if (network===null)
{
// 查询所有以.network结尾的元素
var elements = document.querySelectorAll('[id$=".network"]');
network=elements[0];
}
//页面加载完成时触发
getMode(network,uuid);
// 更换移动网络时触发
network.addEventListener('change', function() {
// 获取对应的拨号模式,并设置到页面选项中
getMode(network,uuid);
});
};
// 获取对应的拨号模式,并设置到页面选项中
function getMode(network,uuid)
{
// 获取当前选中的值
var selected=network.options[network.selectedIndex].value;
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "modem", "mode_info")%>', {"network":selected},
function(x, json)
{
modeSelect = document.getElementById("widget.cbid.modem."+uuid+".mode");
if (modeSelect===null)
{
// 查询所有以.network结尾的元素
var elements = document.querySelectorAll('[id$=".mode"]');
modeSelect=elements[0];
}
// 删除原来的选项
modeSelect.options.length=0;
for (var key in json) {
modeSelect.add(new Option(json[key].toUpperCase(),json[key]));
}
}
);
}
</script>

File diff suppressed because it is too large Load Diff

View File

@ -1,509 +0,0 @@
<%+header%>
<script type="text/javascript" src="<%=resource%>/xhr.js"></script>
<div class="cbi-map" id="cbi-modem-debug">
<h2 id="content" name="content">
<%:Modem Debug%>
</h2>
<div class="cbi-map-descr">
<%:Debug Your Module%>
</div>
<head>
<style type="text/css">
/* table {
width: 100%;
border-spacing: 10px;
border: 0px;
} */
tr td:first-child {
width: 33%;
}
/* AT命令响应 */
/* #response_label {
font-size: 15px;
} */
/* 隐藏tab菜单 */
.cbi-tabmenu {
display: none;
}
/* 隐藏tab内容 */
#tab_context {
display: none;
}
/* 隐藏AT命令标题 */
#at_command_title {
display: none;
}
/* AT命令响应 */
textarea {
background: #373737;
border: none;
color: #FFF;
width: 100%;
}
#popup {
width: 560px;
height: 190px;
padding: 20px;
background-color: gainsboro;
border-style: solid;
position: fixed;
top: 40%;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
text-align: center;
display: none;
}
#lockcell_feature {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
</style>
</head>
<fieldset class="cbi-section" id="cbi-info" style="display: block;">
<div class="cbi-section fade-in">
<h3>
<%:Message%>
</h3>
<table class="table" id="message">
<tr class="tr">
<td colspan="2" class="td left">
<div align="left" id="info_message" style="font-size:1.875em">
<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>"
style="vertical-align:middle" />
<%:Loading modem%>...
</div>
</td>
</tr>
</table>
</div>
</fieldset>
<fieldset class="cbi-section" id="cbi-modem" style="display: none;">
<div class="cbi-section fade-in">
<!-- <legend><%:Modem Select%></legend> -->
<h3>
<%:Modem Select%>
</h3>
<div class="cbi-section-node">
<div class="cbi-value cbi-value-last">
<label class="cbi-value-title">
<%:Modem Name%>
</label>
<div class="cbi-value-field">
<div class="cbi-checkbox">
<select name="modem_select" id="modem_select" class="cbi-input-select"></select>
</div>
<div class="cbi-value-description">
<%:Select a modem for debugging%>
</div>
</div>
</div>
</div>
</div>
</fieldset>
<ul class="cbi-tabmenu" id="tab_menu">
<li class="cbi-tab" data-tab="mode_tab"><a href="#">
<%:Mode%>
</a></li>
<li class="cbi-tab-disabled" data-tab="network_prefer_tab"><a href="#">
<%:Network Preferences%>
</a></li>
<li class="cbi-tab-disabled" data-tab="lockband_tab"><a href="#">
<%:LockBand Settings%>
</a></li>
<li class="cbi-tab-disabled" data-tab="lockcell_tab"><a href="#">
<%:Lock Cell/Arfcn Settings%>
</a></li>
<li class="cbi-tab-disabled" data-tab="self_test_tab"><a href="#">
<%:Self Test%>
</a></li>
<li class="cbi-tab-disabled" data-tab="at_command_tab"><a href="#">
<%:AT Command%>
</a></li>
<li class="cbi-tab-disabled" data-tab="set_imei_tab"><a href="#">
<%:Set IMEI%>
</a></li>
</ul>
<div class="cbi-section-node cbi-section-node-tabbed" id="tab_context">
<!-- <div class="cbi-section cbi-tblsection" data-tab-active="true"> -->
<div class="cbi-section" data-tab="mode_tab" data-tab-title="<%:Mode%>" data-tab-active="true"
style="display: block;">
<!-- <legend><%:Mode%></legend> -->
<!-- <h3><%:Mode%></h3> -->
<table class="table cbi-section-table">
<tbody>
<tr class="tr cbi-section-table-titles anonymous">
<th class="th cbi-section-table-cell">
<%:Current%>
</th>
<th class="th cbi-section-table-cell">
<%:Config%>
</th>
<th class="th cbi-section-table-cell cbi-section-actions"></th>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-1">
<td class="td cbi-value-field" data-title="<%:Current%>" id="current_mode"></td>
<td class="td cbi-value-field" data-title="<%:Config%>" id="mode_option">
<!-- <div>
<span class="cbi-radio">
<input type="radio" name="mode_option" id="mode_option_qmi" value="qmi" checked="true">
<span>QMI</span>
</span>&nbsp;
<span class="cbi-radio">
<input type="radio" name="mode_option" id="mode_option_ecm" value="ecm">
<span>ECM</span>
</span>&nbsp;
<span class="cbi-radio">
<input type="radio" name="mode_option" id="mode_option_mbim" value="mbim">
<span>MBIM</span>
</span>&nbsp;
<span class="cbi-radio">
<input type="radio" name="mode_option" id="mode_option_rndis" value="rndis">
<span>RNDIS</span>
</span>&nbsp;
<span class="cbi-radio">
<input type="radio" name="mode_option" id="mode_option_ncm" value="ncm">
<span>NCM</span>
</span>
</div> -->
</td>
<td class="td">
<div>
<input type="button" class="cbi-button-apply" id="mode_button" onclick="set_mode()"
alt="<%:Apply%>" value="<%:Apply%>">
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- <div class="cbi-section cbi-tblsection"> -->
<div class="cbi-section" data-tab="network_prefer_tab" data-tab-title="<%:Network Preferences%>"
data-tab-active="false" style="display: none;">
<!-- <legend><%:Network Preferences%></legend> -->
<!-- <h3><%:Network Preferences%></h3> -->
<table class="table cbi-section-table">
<tbody>
<tr class="tr cbi-section-table-titles anonymous">
<th class="th cbi-section-table-cell">
<%:Config%>
</th>
<th class="th cbi-section-table-cell cbi-section-actions">
<%:Apply%>
</th>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-1">
<td class="td cbi-value-field" data-title="<%:Config%>" id="prefer_custom_config">
<div>
<span class="cbi-checkbox">
<input id="prefer_config_3g" type="checkbox" class="cbi-input-checkbox"
value="3g">
<span>
<%:3G%>
</span>
</span> &nbsp;
<span class="cbi-checkbox">
<input id="prefer_config_4g" type="checkbox" class="cbi-input-checkbox"
value="4g">
<span>
<%:4G%>
</span>
</span> &nbsp;
<span class="cbi-checkbox">
<input id="prefer_config_5g" type="checkbox" class="cbi-input-checkbox"
value="5g">
<span>
<%:5G%>
</span>
</span>
</div>
</td>
<td class="td">
<input type="button" class="cbi-button-apply" id="network_prefer_button"
onclick="set_network_prefer()" value="<%:Apply%>">
</td>
</tr>
</tbody>
</table>
</div>
<div class="cbi-section" data-tab="lockband_tab" data-tab-title="<%:LockBand Settings%>"
data-tab-active="false" style="display: none;">
<!-- <legend><%:Network Preferences%></legend> -->
<!-- <h3><%:Network Preferences%></h3> -->
<table class="table cbi-section-table">
<tbody>
<tr class="tr cbi-section-table-titles anonymous">
<th class="th cbi-section-table-cell">
<%:Config%>
</th>
</tr>
<tr class="tr cbi-section-table-row">
<td class="td cbi-value-field" data-title="<%:Config%>" id="lockband_custom_config">
</td>
</tr>
</tbody>
</table>
<input type="button" class="cbi-button-apply" onclick="all_choose_lockband_custom_config()"value="<%:Select All Band%>">
<input type="button" class="cbi-button-apply" onclick="set_lockband()" value="<%:Apply%>">
</div>
<div class="cbi-section" data-tab="lockcell_tab" data-tab-title="<%:Lock Cell/Arfcn Settings%>"
data-tab-active="false" style="display: none;">
<h3 id="Lock Cell/Arfcn_title">
<%:Current Settings%>
</h3>
<table class="table" id="CurrentStatus">
<tbody id="current_cell_status">
</tbody>
</table>
<h3 id="Lock Cell/Arfcn_title">
<%:Available Neighbor%>
</h3>
<table class="table" id="AvailableNeighbor">
<tbody id="neighbor_cell_info">
</tbody>
</table>
<!-- <legend><%:AT Command%></legend> -->
<h3 id="Lock Cell/Arfcn_title">
<%:Lock Cell/Arfcn Settings%>
</h3>
<table class="table" id="lockcell_info">
<tbody>
<tr class="tr">
<td class="td left">
<%:Select Rat%>
</td>
<td class="td left">
<select name="rat_select" id="rat_select" class="cbi-input-select"
onchange="lockcell_rat_onchange()">
<option value="0">4G</option>
<option value="1">5G</option>
</select>
</td>
</tr>
<tr class="tr">
<td class="td left">
<%:Enter Arfcn%>
</td>
<td class="td left">
<div>
<input type="text" id="arfcn_input" class="cbi-input-text"></input>
</div>
</td>
</tr>
<tr class="tr">
<td class="td left">
<%:Enter PCI%>
</td>
<td class="td left">
<div>
<input type="text" id="pci_input" class="cbi-input-text"></input>
</div>
</td>
</tr>
<tr class="tr" id="scs_input_tr" style="display:none;">
<td class="td left">
<%:Enter SCS%>
</td>
<td class="td left">
<select name="rat_select" id="scs_select" class="cbi-input-select">
<option value="0">15KHZ</option>
<option value="1">30KHZ</option>
<option value="2">60KHZ</option>
</select>
</td>
</tr>
<tr class="tr" id="nr_input_tr" style="display:none;">
<td class="td left">
<%:Enter NRBAND%>
</td>
<td class="td left">
<div>
<input type="text" id="nrband_input" class="cbi-input-text"></input>
</div>
</td>
</tr>
<tr class="tr">
<td class="td left">
<%:Submit%>
</td>
<td class="td left">
<div id="lockcell_feature">
</div>
</td>
</tr>
<span></span>
</tbody>
</table>
</div>
<!-- <div class="cbi-section fade-in"> -->
<div class="cbi-section" data-tab="self_test_tab" data-tab-title="<%:Self Test%>" data-tab-active="false"
style="display: none;">
<!-- <legend><%:Self Test%></legend> -->
<!-- <h3><%:Self Test%></h3> -->
<table class="table cbi-section-table">
<tbody>
<tr class="tr cbi-section-table-titles anonymous">
<th class="th cbi-section-table-cell">
<%:Item%>
</th>
<th class="th cbi-section-table-cell">
<%:Current%>
</th>
<th class="th cbi-section-table-cell">
<%:Status%>
</th>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-1">
<td class="td cbi-value-field" data-title="<%:Item%>" id="voltage_label">
<%:Voltage%>
</td>
<td class="td cbi-value-field" data-title="<%:Current%>" id="current_voltage"></td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="voltage_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-2">
<td class="td cbi-value-field" data-title="<%:Item%>" id="temperature_label">
<%:Temperature%>
</td>
<td class="td cbi-value-field" data-title="<%:Current%>" id="current_temperature"></td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="temperature_status">-</td>
</tr>
</tbody>
</table>
</div>
<!-- <div class="cbi-section fade-in"> -->
<div class="cbi-section" data-tab="at_command_tab" data-tab-title="<%:AT Command%>" data-tab-active="false"
style="display: none;">
<!-- <legend><%:AT Command%></legend> -->
<h3 id="at_command_title">
<%:AT Command%>
</h3>
<table class="table" id="at_command_info">
<tbody>
<!-- <tr class="tr">
<td class="td left"><%:Modem Select%></td>
<td class="td left"><select name="modem_select" id="modem_select" class="cbi-input-select"></select></td>
</tr> -->
<tr class="tr">
<td class="td left">
<%:Quick Option%>
</td>
<td class="td left" id="quick_option_td">
<div>
<span class="cbi-radio">
<input type="radio" name="quick_option" value="auto" checked="true">
<span>
<%:Auto%>
</span>
</span>&nbsp;
<span class="cbi-radio">
<input type="radio" name="quick_option" value="custom">
<span>
<%:Custom%>
</span>
</span>
</div>
</td>
</tr>
<tr class="tr">
<td class="td left">
<%:Quick Commands%>
</td>
<td class="td left"><select name="command_select" id="command_select"
class="cbi-input-select"></select></td>
</tr>
<tr class="tr">
<td class="td left">
<%:Enter Command%>
</td>
<td class="td left">
<div>
<input type="text" id="at_command" class="cbi-input-text"></input>
</div>
<div>
<input class="cbi-button cbi-button-apply" type="button" value="<%:Send%>"
onclick="send_at_command()" alt="<%:Send%>" title="<%:Send%>">
<input class="cbi-button cbi-button-reset" type="button" value="<%:Clean%>"
onclick="clean_at_command()" alt="<%:Clean%>" title="<%:Clean%>">
</div>
</td>
</tr>
<tr class="tr">
<td colspan="2" class="td left">
<div id="response_label">
<%:Response%>
</div><br />
<div><textarea readonly="readonly" id="response" rows="20" maxlength="160"></textarea>
</div>
<div class="cbi-page-actions">
<input class="btn cbi-button cbi-button-link" type="button"
value="<%:Return to old page%>"
onclick="location.href='/cgi-bin/luci/admin/network/modem/at_command_old'"
alt="<%:Return to old page%>" title="<%:Return to old page%>">
<input class="btn cbi-button cbi-button-link" type="button"
value="<%:Custom quick commands%>"
onclick="location.href='/cgi-bin/luci/admin/network/modem/quick_commands_config'"
alt="<%:Custom quick commands%>" title="<%:Custom quick commands%>">
<input class="cbi-button cbi-button-reset" type="button" value="<%:Clean%>"
onclick="clean_response()" alt="<%:Clean%>" title="<%:Clean%>">
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="cbi-section" data-tab="set_imei_tab" data-tab-title="<%:Set IMEI%>" data-tab-active="false"
style="display: none;">
<table class="table cbi-section-table">
<tbody id="imei_setting">
<tr class="tr cbi-section-table-titles anonymous">
<th>
<%:IMEI%>
</th>
<th>
<%:Set IMEI%>
</th>
</tr>
<tr class="tr">
<td class="td" style="width: auto;">
<%:IMEI%>
</td>
<td class="td cbi-value-field">
<input type="text" id="imei1_input" class="cbi-input-text"></input>
</td>
</tr>
</tbody>
</table>
<input type="button" class="cbi-button-apply" onclick="set_imei()" value="<%:Apply%>">
</div>
</div>
</div>
<%+footer%>

View File

@ -1,283 +0,0 @@
<script type="text/javascript">//<![CDATA[
function set_tab_event()
{
var tab_menu = document.getElementById("tab_menu");
//获取子元素
var childElements = tab_menu.children;
//获取需要禁用的元素
for (var i = 0; i < childElements.length; i++)
{
childElements[i].addEventListener('click', function(event) {
tab_event(this);
});
}
}
//获取需要禁用的元素
function get_enable_element(parent_element)
{
var enable_element;
//获取子元素
var childElements = parent_element.children;
//获取已启用的元素
for (var i = 0; i < childElements.length; i++)
{
// 检查当前子元素的class属性是否为cbi-tab
if (childElements[i].classList.contains('cbi-tab'))
{
enable_element=childElements[i];
break;
}
}
return enable_element;
}
// 设置标签显示
function set_tab_view(disenable_element,enable_element)
{
//获取tab内容父元素
var tab_context = document.getElementById('dial_log_view');
//禁用tab
disenable_element.classList.remove('cbi-tab');
disenable_element.classList.add('cbi-tab-disabled');
//禁用tab内容
var data_tab_disenable = disenable_element.getAttribute('data-tab');
var tab_context_disenable_element = tab_context.querySelector('div[data-tab="'+data_tab_disenable+'"]');
tab_context_disenable_element.setAttribute('data-tab-active','false');
tab_context_disenable_element.style.display="none";
//启用tab
enable_element.classList.remove('cbi-tab-disabled');
enable_element.classList.add('cbi-tab');
//启用tab内容
var data_tab_enable = enable_element.getAttribute('data-tab');
var tab_context_enable_element = tab_context.querySelector('div[data-tab="'+data_tab_enable+'"]');
tab_context_enable_element.setAttribute('data-tab-active','true');
tab_context_enable_element.style.display="block";
}
// 标签事件处理(更新选中的标签及标签内容)
function tab_event(tab_element)
{
//获取需要禁用的tab元素
var tab_menu = document.getElementById("tab_menu");
var disenable_element=get_enable_element(tab_menu);
if (tab_element != disenable_element) {
set_tab_view(disenable_element,tab_element);
}
}
// 设置滚动条
function set_scroll_top(log_ids)
{
for(var log_id in log_ids)
{
var log_element=document.getElementById(log_id);
if (log_ids[log_id]==-1)
{
log_element.scrollTop = log_element.scrollHeight;
}
else
{
log_element.scrollTop = log_ids[log_id];
}
}
}
// 下载日志
function download_dial_log()
{
// 获取启用的标签名
var enable_element=get_enable_element(tab_menu);
var enable_tab=enable_element.getAttribute("data-tab");
var enable_tab_name=enable_tab.replace("_tab","");
// 获取拨号日志
var log_element=document.getElementById(enable_tab_name+"_log");
var log=log_element.value
// 创建下载链接
var file = new Blob([log], {type: 'text/plain'});
var fileURL = URL.createObjectURL(file);
// 创建超链接并触发点击
var download_link = document.createElement("a");
download_link.href = fileURL;
download_link.download = enable_tab_name+"_dial_log.txt";
download_link.click();
}
// 清理拨号日志
function clean_dial_log()
{
// 获取启用的标签名
var enable_element=get_enable_element(tab_menu);
var enable_tab=enable_element.getAttribute("data-tab");
var enable_tab_name=enable_tab.replace("_tab","");
// 清空页面拨号日志
var log_element=document.getElementById(enable_tab_name+"_log");
log_element.value="";
// 获取拨号日志路径
var path="/tmp/run/modem/"+enable_tab_name+"_dial.cache";
// 清空文件拨号日志
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "modem", "clean_dial_log")%>', {"path":path},
function(x, data)
{
// console.log(data);
}
);
}
XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "network", "modem", "get_dial_log_info")%>', null,
function(x, data)
{
var dial_log_info=data["dial_log_info"];
var modem_name_info=data["modem_name_info"];
var translation=data["translation"];
var tab_menu=document.getElementById("tab_menu");
var dial_log_div=document.getElementById('dial_log_view');
if (Object.keys(dial_log_info).length!=0)
{
// 新添加标签或覆盖标签
var tab_view = "";
var dial_log_view = "";
var log_ids={};
var enable_tab_name_cache=""; // 缓存已启用标签名
for (var dial_log of dial_log_info)
{
//遍历拨号日志的信息
for ( var key in dial_log)
{
var class_name="cbi-tab-disabled";
var active="false";
var display="none";
var log_style="";
if (tab_menu.hasChildNodes())
{
// 获取启用的标签元素
var enable_element=get_enable_element(tab_menu);
// 设置启用的标签为上一次的启用标签
enable_tab=enable_element.getAttribute("data-tab");
enable_tab_name_cache=enable_tab.replace("_tab","");
if (enable_tab_name_cache==key)
{
class_name="cbi-tab";
active="true";
display="block";
}
var log_element=document.getElementById(key+'_log');
if (log_element!=null)
{
// 设置样式
log_style=log_element.getAttribute("style");
// 判断日志是否更新
var log=log_element.value;
if (dial_log[key]!=log)
{
// 更新的移动滚动条到最下面
log_ids[key+'_log']=-1;
}
else
{
// 记录滚到条位置
log_ids[key+'_log']=log_element.scrollTop;
}
}
}
// 设置拨号日志标签
var modem_name=translation[modem_name_info[key]].toUpperCase();
tab_view+='<li class="'+class_name+'" data-tab="'+key+'_tab"><a>'+modem_name+' ('+key.replace("modem","")+')</a></li>';
// 设置拨号日志
dial_log_view += '<div class="cbi-section" data-tab="'+key+'_tab" data-tab-title="'+key+'" data-tab-active="'+active+'" style="display: '+display+';">';
dial_log_view += '<div><textarea readonly="readonly" id="'+key+'_log" rows="20" maxlength="160" style="'+log_style+'">'+dial_log[key]+'</textarea></div>';
dial_log_view += '</div>'
}
}
// 添加到页面中
tab_menu.innerHTML=tab_view;
dial_log_div.innerHTML=dial_log_view;
// 设置默认启用的标签(上次启用标签已删除)
var enable_element=document.getElementById(enable_tab_name_cache+"_log");
if (enable_element==null)
{
//设置启用的为第一个标签
enable_element=tab_menu.firstChild;
enable_element.classList.remove('cbi-tab-disabled');
enable_element.classList.add('cbi-tab');
enable_element=dial_log_div.firstChild;
enable_element.setAttribute('data-tab-active','true');
enable_element.style.display="block";
}
//设置滚动条
set_scroll_top(log_ids);
// 设置标签事件
set_tab_event();
// 显示拨号日志(标签、日志内容、滚动条、标签事件加载完成才显示)
document.getElementById("modem_dial_log_field").style.display="block";
}
else
{
var log_view="<strong><%:No dial log%></strong>";
dial_log_div.innerHTML=log_view;
// 隐藏拨号日志
document.getElementById("modem_dial_log_field").style.display="none";
}
}
);
//]]>
</script>
<style type="text/css">
/* AT命令响应 */
textarea {
background:#373737;
border:none;
color:#FFF;
width: 100%;
border-top-width: 2px;
padding-top: 12px;
}
</style>
<fieldset id="modem_dial_log_field" class="cbi-section" style="display: none;">
<div class="cbi-section fade-in">
<!-- <legend><%:Dial Log%></legend> -->
<h3 id="dial_log_title"><%:Dial Log%></h3>
</div>
<!-- <div id="response_label"><%:Response%></div><br/> -->
<table class="table" id="at_command_info">
<tbody>
<tr class="tr">
<td colspan="2" class="td left">
<ul class="cbi-tabmenu" id="tab_menu"></ul>
<div id="dial_log_view">
<!-- <div class="cbi-section" data-tab="modem0_tab" data-tab-title="<%:Modem0%>" data-tab-active="true" style="display: block;">
<div><textarea readonly="readonly" id="response" rows="20" maxlength="160"></textarea></div>
</div> -->
</div>
<div class="cbi-page-actions">
<input class="btn cbi-button cbi-button-link" type="button" value="<%:Download Log%>" onclick="download_dial_log()" alt="<%:Download Log%>" title="<%:Download Log%>">
<input class="cbi-button cbi-button-reset" type="button" value="<%:Clean%>" onclick="clean_dial_log()" alt="<%:Clean%>" title="<%:Clean%>">
</div>
</td>
</tr>
</tbody>
</table>
</fieldset>

File diff suppressed because it is too large Load Diff

View File

@ -1,160 +0,0 @@
<script type="text/javascript">//<![CDATA[
XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "network", "modem", "get_modems")%>', null,
function(x, data)
{
var modems=data["modems"];
var translation=data["translation"];
var modems_div=document.getElementById('modem_status_view');
if (Object.keys(modems).length!=0)
{
var modem_view = "";
//遍历每一个模组
for (var modem of modems)
{
//遍历模组里面的信息
for ( var key in modem)
{
var modem=modem[key];
var language=navigator.language;
// 检查模组名
var name=modem["name"];
if (name==null)
{
continue;
}
else if (name=="unknown")
{
language=="en" ? name=name.toUpperCase() : name=translation[name];
}
else
{
name=name.toUpperCase();
}
// 检查拨号模式
var mode=modem["mode"]
if (mode==null)
{
continue;
}
else if (mode=="unknown")
{
language=="en" ? mode=mode.toUpperCase() : mode=translation[mode];
}
else
{
mode=mode.toUpperCase();
}
// 获取连接状态
var connect_status=modem["connect_status"];
if (modem["connect_status"]!=null)
{
if (language=="en") {
// 首字母大写
connect_status=connect_status.charAt(0).toUpperCase() + modem["connect_status"].slice(1);
}
else if (language=="zh-CN"||language=="zh") {
connect_status=translation[connect_status];
}
}
// 设置显示样式
var state = '';
var css = '';
switch (modem["connect_status"])
{
case 'connect':
state = '<%:Connect%>';
css = 'success';
break;
case 'disconnect':
state = '<%:Disconnect%>';
css = 'danger';
break;
default:
state = '<%:unknown%>';
css = 'warning';
break;
}
// 设置显示内容
modem_view += String.format(
'<div class="alert-message %s">',
css
);
modem_view += String.format(
'<div><strong>No: </strong>%s</div>',
modem[".name"].slice(-1)
);
modem_view += String.format(
'<div><strong><%:Modem Name%>: </strong>%s</div>',
name
);
modem_view += String.format(
'<div><strong><%:Data Interface%>: </strong>%s</div>',
modem.data_interface.toUpperCase()
);
modem_view += String.format(
'<div><strong><%:Mode%>: </strong>%s</div>',
mode
);
modem_view += String.format(
'<div><strong><%:Mobile Network%>: </strong>%s</div>',
modem.network
);
modem_view += String.format(
'<div><strong><%:Connect Status%>: </strong>%s</div>',
connect_status
);
modem_view += '</div>';
}
}
// 有参数不存在,则不显示模块状态
if (modem_view != "")
{
modems_div.innerHTML=modem_view;
// 显示模块状态(状态加载完成才显示)
document.getElementById("modem_status_field").style.display="block";
}
}
else
{
var modem_view="<strong><%:No modems found%></strong>";
modems_div.innerHTML=modem_view;
// 隐藏模块状态
document.getElementById("modem_status_field").style.display="none";
}
}
);
//]]>
</script>
<style type="text/css">
/* 加载中样式 */
#modem_status_view img {
vertical-align: middle;
}
#modem_status_view > div {
display: inline-block;
margin: 1rem;
padding: 1rem;
width: 15rem;
float: left;
line-height: 125%;
}
</style>
<!-- 默认隐藏模块状态 -->
<fieldset id="modem_status_field" class="cbi-section" style="display: none;">
<!-- <legend><%:Modem Status%></legend> -->
<h3><%:Modem Status%></h3>
<div id="modem_status_view">
<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>"/>
<%:Loading modem status%>...
</div>
</fieldset>

View File

@ -1,276 +0,0 @@
<%+header%>
<script type="text/javascript" src="<%=resource%>/xhr.js"></script>
<script type="text/javascript">//<![CDATA[
// 设置状态页面
function set_status_view(status,status_element,translation)
{
if (status=="Loaded") {
status_element.style.color = "green";
}
else if (status=="Not loaded") {
status_element.style.color = "red";
}
status_element.innerHTML=translation[status];
}
// 设置状态
function set_status(info,translation)
{
//遍历信息里面的内核模块
for (var model in info)
{
//获取状态元素
var status_element=document.getElementById(model.toLowerCase().replace(".ko","_status"));
// 设置状态页面
set_status_view(info[model],status_element,translation);
}
}
// 设置版本
function set_version(info,translation)
{
//遍历信息里面的插件版本
for (var plugin in info)
{
//获取版本元素
var version_element=document.getElementById(plugin+"_version");
if (info[plugin]=="Unknown") {
version_element.innerHTML=translation[info[plugin]];
version_element.style.color = "goldenrod";
}
else if (info[plugin]=="Not installed") {
version_element.innerHTML=translation[info[plugin]];
version_element.style.color = "red";
}
else
{
version_element.innerHTML="v"+info[plugin];
version_element.style.color = "green";
}
}
}
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "modem", "get_plugin_info")%>', {},
function(x, data)
{
// 获取翻译
var translation=data["translation"];
// 获取插件信息
var plugin_info=data["plugin_info"];
set_version(plugin_info,translation);
// 获取拨号工具信息
var dial_tool_info=data["dial_tool_info"];
set_version(dial_tool_info,translation);
// 设置通用驱动信息的状态
var general_driver_info=data["general_driver_info"];
set_status(general_driver_info,translation);
// 设置模组USB驱动信息的状态
var usb_driver_info=data["usb_driver_info"];
set_status(usb_driver_info,translation);
// 设置模组PCIE驱动信息的状态
var pcie_driver_info=data["pcie_driver_info"];
set_status(pcie_driver_info,translation);
}
);
//]]>
</script>
<div class="cbi-map" id="cbi-modem-debug">
<h2 id="content" name="content"><%:Plugin Info%></h2>
<div class="cbi-map-descr"><%:Check the version information of the plugin%></div>
<head>
<style type="text/css">
div .version {
margin-top: 5px;
}
</style>
</head>
<fieldset class="cbi-section" id="cbi-modem" style="display: block;">
<div class="cbi-section fade-in">
<!-- <legend><%:Plugin Info%></legend> -->
<h3><%:Plugin Info%></h3>
<div class="cbi-section-node">
<div class="cbi-value cbi-value-last">
<label class="cbi-value-title"><%:Plugin Version%></label>
<div class="cbi-value-field">
<div class="version">
<strong id="luci-app-modem_version"></strong>
</div>
<!-- <div class="cbi-value-description">
<%:Select a modem for debugging%>
</div> -->
</div>
</div>
</div>
</div>
</fieldset>
<fieldset class="cbi-section" id="cbi-modem" style="display: block;">
<div class="cbi-section fade-in">
<!-- <legend><%:Dial Tool Info%></legend> -->
<h3><%:Dial Tool Info%></h3>
<div class="cbi-section-node">
<div class="cbi-value">
<label class="cbi-value-title"><%:quectel-CM Version%></label>
<div class="cbi-value-field">
<div class="version">
<strong id="quectel-CM-5G_version"></strong>
</div>
<!-- <div class="cbi-value-description">
<%:Select a modem for debugging%>
</div> -->
</div>
</div>
<div class="cbi-value cbi-value-last">
<label class="cbi-value-title"><%:modemmanager Version%></label>
<div class="cbi-value-field">
<div class="version">
<strong id="modemmanager_version"></strong>
</div>
<!-- <div class="cbi-value-description">
<%:Select a modem for debugging%>
</div> -->
</div>
</div>
</div>
</div>
</fieldset>
<fieldset class="cbi-section" id="cbi-modem" style="display: block;">
<div class="cbi-section fade-in">
<!-- <legend><%:Modem PCIE Driver Info%></legend> -->
<h3><%:Modem General Driver Info%></h3>
<table class="table cbi-section-table">
<tbody>
<tr class="tr cbi-section-table-titles anonymous">
<th class="th cbi-section-table-cell"><%:Driver Type%></th>
<th class="th cbi-section-table-cell"><%:Kernel Model%></th>
<th class="th cbi-section-table-cell"><%:Status%></th>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-1">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="usb_network"><%:USB Network%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="usb_net_kernel_model_name">usbnet.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="usbnet_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-2">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="serial_port"><%:Serial Port%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="serial_port_kernel_model_name">option.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="option_status">-</td>
</tr>
<!-- <tr class="tr cbi-section-table-row cbi-rowstyle-2">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="serial_port"><%:Serial Port%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="serial_port_kernel_model_name">qcserial.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="qcserial_status">-</td>
</tr> -->
</tbody>
</table>
</div>
</fieldset>
<fieldset class="cbi-section" id="cbi-modem" style="display: block;">
<div class="cbi-section fade-in">
<!-- <legend><%:Modem USB Driver Info%></legend> -->
<h3><%:Modem USB Driver Info%></h3>
<table class="table cbi-section-table">
<tbody>
<tr class="tr cbi-section-table-titles anonymous">
<th class="th cbi-section-table-cell"><%:Driver Type%></th>
<th class="th cbi-section-table-cell"><%:Kernel Model%></th>
<th class="th cbi-section-table-cell"><%:Status%></th>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-1">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="qmi"><%:QMI%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="qmi_kernel_model_name">qmi_wwan.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="qmi_wwan_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-2">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="gobinet"><%:GobiNet%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="gobinet_kernel_model_name">GobiNet.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="gobinet_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-1">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="ecm"><%:ECM%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="ecm_kernel_model_name">cdc_ether.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="cdc_ether_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-2">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="mbim"><%:MBIM%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="mbim_kernel_model_name">cdc_mbim.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="cdc_mbim_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-1">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="rndis"><%:RNDIS%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="rndis_kernel_model_name">rndis_host.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="rndis_host_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-2">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="ecm"><%:NCM%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="ncm_kernel_model_name">cdc_ncm.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="cdc_ncm_status">-</td>
</tr>
</tbody>
</table>
</div>
</fieldset>
<fieldset class="cbi-section" id="cbi-modem" style="display: block;">
<div class="cbi-section fade-in">
<!-- <legend><%:Modem PCIE Driver Info%></legend> -->
<h3><%:Modem PCIE Driver Info%></h3>
<table class="table cbi-section-table">
<tbody>
<tr class="tr cbi-section-table-titles anonymous">
<th class="th cbi-section-table-cell"><%:Driver Type%></th>
<th class="th cbi-section-table-cell"><%:Kernel Model%></th>
<th class="th cbi-section-table-cell"><%:Status%></th>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-1">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="mhi_net"><%:General%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="mhi_net_kernel_model_name">mhi_net.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="mhi_net_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-2">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="qrtr_mhi"><%:General%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="qrtr_kernel_model_name">qrtr_mhi.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="qrtr_mhi_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-1">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="mhi_pci_generic"><%:General%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="mhi_pci_kernel_model_name">mhi_pci_generic.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="mhi_pci_generic_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-2">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="mhi_wwan_mbim"><%:General%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="mhi_mbim_kernel_model_name">mhi_wwan_mbim.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="mhi_wwan_mbim_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-1">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="mhi_wwan_ctrl"><%:General%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="mhi_wwan_kernel_model_name">mhi_wwan_ctrl.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="mhi_wwan_ctrl_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-2">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="private_q"><%:Private%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="pcie_mhi_kernel_model_name">pcie_mhi.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="pcie_mhi_status">-</td>
</tr>
<tr class="tr cbi-section-table-row cbi-rowstyle-2">
<td class="td cbi-value-field" data-title="<%:Driver Type%>" id="private_mtk"><%:Private%></td>
<td class="td cbi-value-field" data-title="<%:Kernel Model%>" id="mtk_pcie_wwan_m80_kernel_model_name">mtk_pcie_wwan_m80.ko</td>
<td class="td cbi-value-field" data-title="<%:Status%>" id="mtk_pcie_wwan_m80_status">-</td>
</tr>
</tbody>
</table>
</div>
</fieldset>
</div>
<%+footer%>

View File

@ -1,3 +0,0 @@
<%+cbi/valueheader%>
<font class="_status" hint="<%=self:cfgvalue(section)%>">--</font>
<%+cbi/valuefooter%>

View File

@ -1,203 +0,0 @@
<%-
local rowcnt = 0
function rowstyle()
rowcnt = rowcnt + 1
if rowcnt % 2 == 0 then
return " cbi-rowstyle-1"
else
return " cbi-rowstyle-2"
end
end
function width(o)
if o.width then
if type(o.width) == 'number' then
return ' style="width:%dpx"' % o.width
end
return ' style="width:%s"' % o.width
end
return ''
end
local has_titles = false
local has_descriptions = false
local anonclass = (not self.anonymous or self.sectiontitle) and "named" or "anonymous"
local titlename = ifattr(not self.anonymous or self.sectiontitle, "data-title", translate("Name"))
local i, k
for i, k in pairs(self.children) do
if not k.typename then
k.typename = k.template and k.template:gsub("^.+/", "") or ""
end
if not has_titles and k.title and #k.title > 0 then
has_titles = true
end
if not has_descriptions and k.description and #k.description > 0 then
has_descriptions = true
end
end
function render_titles()
if not has_titles then
return
end
%><tr class="tr cbi-section-table-titles <%=anonclass%>"<%=titlename%>><%
local i, k
for i, k in ipairs(self.children) do
if not k.optional then
%><th class="th cbi-section-table-cell"<%=
width(k) .. attr('data-widget', k.typename) %>><%
if k.titleref then
%><a title="<%=self.titledesc or translate('Go to relevant configuration page')%>" class="cbi-title-ref" href="<%=k.titleref%>"><%
end
write(k.title)
if k.titleref then
%></a><%
end
%></th><%
end
end
if self.sortable or self.extedit or self.addremove then
%><th class="th cbi-section-table-cell cbi-section-actions"></th><%
end
%></tr><%
rowcnt = rowcnt + 1
end
function render_descriptions()
if not has_descriptions then
return
end
%><tr class="tr cbi-section-table-descr <%=anonclass%>"><%
local i, k
for i, k in ipairs(self.children) do
if not k.optional then
%><th class="th cbi-section-table-cell"<%=
width(k) .. attr("data-widget", k.typename) %>><%
write(k.description)
%></th><%
end
end
if self.sortable or self.extedit or self.addremove then
%><th class="th cbi-section-table-cell cbi-section-actions"></th><%
end
%></tr><%
rowcnt = rowcnt + 1
end
-%>
<!-- tblsection -->
<div class="cbi-section cbi-tblsection" id="cbi-<%=self.config%>-<%=self.sectiontype%>">
<% if self.title and #self.title > 0 then -%>
<h3><%=self.title%></h3>
<%- end %>
<%- if self.sortable then -%>
<input type="hidden" id="cbi.sts.<%=self.config%>.<%=self.sectiontype%>" name="cbi.sts.<%=self.config%>.<%=self.sectiontype%>" value="" />
<%- end -%>
<div class="cbi-section-descr"><%=self.description%></div>
<table class="table cbi-section-table">
<%-
render_titles()
render_descriptions()
local isempty, section, i, k = true, nil, nil
for i, k in ipairs(self:cfgsections()) do
isempty = false
section = k
local sectionname = striptags((type(self.sectiontitle) == "function") and self:sectiontitle(section) or k)
local sectiontitle = ifattr(sectionname and (not self.anonymous or self.sectiontitle), "data-title", sectionname, true)
local colorclass = (self.extedit or self.rowcolors) and rowstyle() or ""
local scope = {
valueheader = "cbi/cell_valueheader",
valuefooter = "cbi/cell_valuefooter"
}
-%>
<tr class="tr cbi-section-table-row<%=colorclass%>" id="cbi-<%=self.config%>-<%=section%>"<%=sectiontitle%>>
<%-
local node
for k, node in ipairs(self.children) do
if not node.optional then
node:render(section, scope or {})
end
end
-%>
<%- if self.sortable or self.extedit or self.addremove then -%>
<td class="td cbi-section-table-cell nowrap cbi-section-actions">
<div>
<%- if self.sortable then -%>
<input class="btn cbi-button cbi-button-up" type="button" value="<%:Up%>" onclick="return cbi_row_swap(this, true, 'cbi.sts.<%=self.config%>.<%=self.sectiontype%>')" title="<%:Move up%>" />
<input class="btn cbi-button cbi-button-down" type="button" value="<%:Down%>" onclick="return cbi_row_swap(this, false, 'cbi.sts.<%=self.config%>.<%=self.sectiontype%>')" title="<%:Move down%>" />
<% end; if self.extedit then -%>
<input class="btn cbi-button cbi-button-edit" type="button" value="<%:Edit%>"
<%- if type(self.extedit) == "string" then
%> onclick="location.href='<%=self.extedit:format(section)%>'"
<%- elseif type(self.extedit) == "function" then
%> onclick="location.href='<%=self:extedit(section)%>'"
<%- end
%> alt="<%:Edit%>" title="<%:Edit%>" />
<% end; if self.addremove then %>
<input class="btn cbi-button cbi-button-remove" type="submit" value="<%:Delete%>" onclick="this.form.cbi_state='del-section'; return true" name="cbi.rts.<%=self.config%>.<%=k%>" alt="<%:Delete%>" title="<%:Delete%>" />
<%- end -%>
</div>
</td>
<%- end -%>
</tr>
<%- end -%>
<%- if isempty then -%>
<tr class="tr cbi-section-table-row placeholder">
<td class="td"><em><%:This section contains no values yet%></em></td>
</tr>
<%- end -%>
</table>
<% if self.error then %>
<div class="cbi-section-error">
<ul><% for _, c in pairs(self.error) do for _, e in ipairs(c) do -%>
<li><%=pcdata(e):gsub("\n","<br />")%></li>
<%- end end %></ul>
</div>
<% end %>
<%- if self.addremove then -%>
<% if self.template_addremove then include(self.template_addremove) else -%>
<div class="cbi-section-create cbi-tblsection-create">
<% if self.anonymous then %>
<input class="btn cbi-button cbi-button-add" type="submit" value="<%:Add%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" title="<%:Add%>" />
<% else %>
<% if self.invalid_cts then -%>
<div class="cbi-section-error"><%:Invalid%></div>
<%- end %>
<div>
<input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" data-type="uciname" data-optional="true" onkeyup="cbi_validate_named_section_add(this)"/>
</div>
<input class="btn cbi-button cbi-button-add" type="submit" onclick="this.form.cbi_state='add-section'; return true" value="<%:Add%>" title="<%:Add%>" disabled="" />
<% end %>
</div>
<%- end %>
<%- end -%>
</div>
<!-- /tblsection -->

View File

@ -1,208 +0,0 @@
<%-
local rowcnt = 0
function rowstyle()
rowcnt = rowcnt + 1
if rowcnt % 2 == 0 then
return " cbi-rowstyle-1"
else
return " cbi-rowstyle-2"
end
end
function width(o)
if o.width then
if type(o.width) == 'number' then
return ' style="width:%dpx"' % o.width
end
return ' style="width:%s"' % o.width
end
return ''
end
local has_titles = false
local has_descriptions = false
local anonclass = (not self.anonymous or self.sectiontitle) and "named" or "anonymous"
local titlename = ifattr(not self.anonymous or self.sectiontitle, "data-title", translate("Name"))
local i, k
for i, k in pairs(self.children) do
if not k.typename then
k.typename = k.template and k.template:gsub("^.+/", "") or ""
end
if not has_titles and k.title and #k.title > 0 then
has_titles = true
end
if not has_descriptions and k.description and #k.description > 0 then
has_descriptions = true
end
end
function render_titles()
if not has_titles then
return
end
%><tr class="tr cbi-section-table-titles <%=anonclass%>"<%=titlename%>>
<th class="th cbi-section-table-cell"><%:Serial Number%></th>
<%
local i, k
for i, k in ipairs(self.children) do
if not k.optional then
%><th class="th cbi-section-table-cell"<%=
width(k) .. attr('data-widget', k.typename) %>><%
if k.titleref then
%><a title="<%=self.titledesc or translate('Go to relevant configuration page')%>" class="cbi-title-ref" href="<%=k.titleref%>"><%
end
write(k.title)
if k.titleref then
%></a><%
end
%></th><%
end
end
if self.sortable or self.extedit or self.addremove then
%><th class="th cbi-section-table-cell cbi-section-actions"></th><%
end
%></tr><%
rowcnt = rowcnt + 1
end
function render_descriptions()
if not has_descriptions then
return
end
%><tr class="tr cbi-section-table-descr <%=anonclass%>"><%
local i, k
for i, k in ipairs(self.children) do
if not k.optional then
%><th class="th cbi-section-table-cell"<%=
width(k) .. attr("data-widget", k.typename) %>><%
write(k.description)
%></th><%
end
end
if self.sortable or self.extedit or self.addremove then
%><th class="th cbi-section-table-cell cbi-section-actions"></th><%
end
%></tr><%
rowcnt = rowcnt + 1
end
-%>
<!-- tblsection -->
<div class="cbi-section cbi-tblsection" id="cbi-<%=self.config%>-<%=self.sectiontype%>">
<% if self.title and #self.title > 0 then -%>
<h3><%=self.title%></h3>
<%- end %>
<%- if self.sortable then -%>
<input type="hidden" id="cbi.sts.<%=self.config%>.<%=self.sectiontype%>" name="cbi.sts.<%=self.config%>.<%=self.sectiontype%>" value="" />
<%- end -%>
<div class="cbi-section-descr"><%=self.description%></div>
<table class="table cbi-section-table">
<%-
render_titles()
render_descriptions()
local num = 1
local isempty, section, i, k = true, nil, nil
for i, k in ipairs(self:cfgsections()) do
isempty = false
section = k
local sectionname = striptags((type(self.sectiontitle) == "function") and self:sectiontitle(section) or k)
local sectiontitle = ifattr(sectionname and (not self.anonymous or self.sectiontitle), "data-title", sectionname, true)
local colorclass = (self.extedit or self.rowcolors) and rowstyle() or ""
local scope = {
valueheader = "cbi/cell_valueheader",
valuefooter = "cbi/cell_valuefooter"
}
-%>
<tr class="tr cbi-section-table-row<%=colorclass%>" id="cbi-<%=self.config%>-<%=section%>"<%=sectiontitle%>>
<td class="td cbi-value-field" data-title="<%:Serial Number%>">
<p><%=num%></p>
<% num = num + 1 -%>
</td>
<%-
local node
for k, node in ipairs(self.children) do
if not node.optional then
node:render(section, scope or {})
end
end
-%>
<%- if self.sortable or self.extedit or self.addremove then -%>
<td class="td cbi-section-table-cell nowrap cbi-section-actions">
<div>
<%- if self.sortable then -%>
<input class="btn cbi-button cbi-button-up" type="button" value="<%:Up%>" onclick="return cbi_row_swap(this, true, 'cbi.sts.<%=self.config%>.<%=self.sectiontype%>')" title="<%:Move up%>" />
<input class="btn cbi-button cbi-button-down" type="button" value="<%:Down%>" onclick="return cbi_row_swap(this, false, 'cbi.sts.<%=self.config%>.<%=self.sectiontype%>')" title="<%:Move down%>" />
<% end; if self.extedit then -%>
<input class="btn cbi-button cbi-button-edit" type="button" value="<%:Edit%>"
<%- if type(self.extedit) == "string" then
%> onclick="location.href='<%=self.extedit:format(section)%>'"
<%- elseif type(self.extedit) == "function" then
%> onclick="location.href='<%=self:extedit(section)%>'"
<%- end
%> alt="<%:Edit%>" title="<%:Edit%>" />
<% end; if self.addremove then %>
<input class="btn cbi-button cbi-button-remove" type="submit" value="<%:Delete%>" onclick="this.form.cbi_state='del-section'; return true" name="cbi.rts.<%=self.config%>.<%=k%>" alt="<%:Delete%>" title="<%:Delete%>" />
<%- end -%>
</div>
</td>
<%- end -%>
</tr>
<%- end -%>
<%- if isempty then -%>
<tr class="tr cbi-section-table-row placeholder">
<td class="td"><em><%:This section contains no values yet%></em></td>
</tr>
<%- end -%>
</table>
<% if self.error then %>
<div class="cbi-section-error">
<ul><% for _, c in pairs(self.error) do for _, e in ipairs(c) do -%>
<li><%=pcdata(e):gsub("\n","<br />")%></li>
<%- end end %></ul>
</div>
<% end %>
<%- if self.addremove then -%>
<% if self.template_addremove then include(self.template_addremove) else -%>
<div class="cbi-section-create cbi-tblsection-create">
<% if self.anonymous then %>
<input class="btn cbi-button cbi-button-add" type="submit" value="<%:Add%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" title="<%:Add%>" />
<% else %>
<% if self.invalid_cts then -%>
<div class="cbi-section-error"><%:Invalid%></div>
<%- end %>
<div>
<input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" data-type="uciname" data-optional="true" onkeyup="cbi_validate_named_section_add(this)"/>
</div>
<input class="btn cbi-button cbi-button-add" type="submit" onclick="this.form.cbi_state='add-section'; return true" value="<%:Add%>" title="<%:Add%>" disabled="" />
<% end %>
</div>
<%- end %>
<%- end -%>
</div>
<!-- /tblsection -->

View File

@ -0,0 +1,263 @@
msgid "Modem Information"
msgstr "Информация о модеме"
msgid "Dial Overview"
msgstr "Обзор набора"
msgid "Modem Debug"
msgstr "Отладка модема"
msgid "Mwan Config"
msgstr "Настройка Mwan"
msgid "TTL Config"
msgstr "Настройка TTL"
msgid "Plugin Config"
msgstr "Настройка плагина"
msgid "Modem Name"
msgstr "Название модема"
msgid "Base Information"
msgstr "Основная информация"
msgid "Производитель"
msgstr "Производитель"
msgid "Ревизия"
msgstr "Ревизия"
msgid "AT Port"
msgstr "AT Порт"
msgid "Temperature"
msgstr "Температура"
msgid "Voltage"
msgstr "Напряжение"
msgid "Connect Status"
msgstr "Статус подключения"
msgid "Yes"
msgstr "Да"
msgid "SIM Information"
msgstr "Информация о SIM"
msgid "SIM Status"
msgstr "Статус SIM"
msgid "ready"
msgstr "готово"
msgid "Internet Service Provider"
msgstr "Интернет-провайдер"
msgid "SIM Slot"
msgstr "Слот SIM"
msgid "International Mobile Equipment Identity"
msgstr "Международный идентификатор мобильного оборудования"
msgid "Международный идентификатор абонента мобильной связи"
msgstr "Международный идентификатор абонента мобильной связи"
msgid "Integrate Circuit Card Identity"
msgstr "Идентификатор интегральной схемы карты"
msgid "Network Information"
msgstr "Информация о сети"
msgid "Network Type"
msgstr "Тип сети"
msgid "TDD NR5G"
msgstr "TDD NR5G"
msgid "Channel Quality Indicator for Uplink"
msgstr "Индикатор качества канала для передачи"
msgid "Channel Quality Indicator for Downlink"
msgstr "Индикатор качества канала для приема"
msgid "Access Maximum Bit Rate for Uplink"
msgstr "Максимальная скорость передачи данных для передачи"
msgid "Access Maximum Bit Rate for Downlink"
msgstr "Максимальная скорость передачи данных для приема"
msgid "Transmit Rate"
msgstr "Скорость передачи"
msgid "Receive Rate"
msgstr "Скорость приема"
msgid "Cell Information"
msgstr "Информация о ячейке"
msgid "Режим сети"
msgstr "Режим сети"
msgid "Мобильный код страны"
msgstr "Мобильный код страны"
msgid "Мобильный код сети"
msgstr "Мобильный код сети"
msgid "Duplex Mode"
msgstr "Режим дуплекса"
msgid "TDD"
msgstr "TDD"
msgid "ID ячейки"
msgstr "ID ячейки"
msgid "Physical Cell ID"
msgstr "Физический ID ячейки"
msgid "Tracking area code of cell servedby neighbor Enb"
msgstr "Код зоны отслеживания ячейки, обслуживаемой соседним Enb"
msgid "Absolute Radio-Frequency Channel Number"
msgstr "Абсолютный номер радиочастотного канала"
msgid "Диапазон"
msgstr "Диапазон"
msgid "DL Bandwidth"
msgstr "Ширина полосы пропускания DL"
msgid "Reference Signal Received Power"
msgstr "Мощность принятого опорного сигнала"
msgid "Reference Signal Received Quality"
msgstr "Качество принятого опорного сигнала"
msgid "Signal to Interference plus Noise Ratio Bandwidth"
msgstr "Отношение сигнал/шум плюс полоса пропускания помех"
msgid "Serving Cell Receive Level"
msgstr "Уровень приема обслуживающей ячейки"
msgid "Check and add modem dialing configurations"
msgstr "Проверьте и добавьте конфигурации набора модема"
msgid "Global Config"
msgstr "Глобальная конфигурация"
msgid "Enable Dial"
msgstr "Включить набор"
msgid "Enable dial configurations"
msgstr "Включить конфигурации набора"
msgid "Reload Dial Configurations"
msgstr "Перезагрузить конфигурации набора"
msgid "Manually Reload dial configurations When the dial configuration fails to take effect"
msgstr "Вручную перезагрузите конфигурации набора, когда конфигурация набора не вступает в силу"
msgid "Config List"
msgstr "Список конфигураций"
msgid "enable_dial"
msgstr "включить_набор"
msgid "Remarks"
msgstr "Замечания"
msgid "Mobile Network"
msgstr "Мобильная сеть"
msgid "Dial Tool"
msgstr "Инструмент набора"
msgid "Тип PDP"
msgstr "Тип PDP"
msgid "Network Bridge"
msgstr "Сетевой мост"
msgid "Auto Choose"
msgstr "Автовыбор"
msgid "Modem Name"
msgstr "Название модема"
msgid "Dial Mode"
msgstr "Режим набора"
msgid "Rat Prefer"
msgstr "Предпочтительный Rat"
msgid "Set IMEI"
msgstr "Установить IMEI"
msgid "Neighbor Cell"
msgstr "Соседняя ячейка"
msgid "Lock Band"
msgstr "Заблокировать диапазон"
msgid "Dial Mode"
msgstr "Режим набора"
msgid "Current Mode"
msgstr "Текущий режим"
msgid "Plugin Config"
msgstr "Настройка плагина"
msgid "Check and modify the plugin configuration"
msgstr "Проверьте и измените конфигурацию плагина"
msgid "Global Config"
msgstr "Глобальная конфигурация"
msgid "Modem Scan"
msgstr "Сканирование модема"
msgid "The automatic configuration modem is triggered only at modem startup, otherwise, manual scanning is necessary"
msgstr "Автоматическая конфигурация модема запускается только при запуске модема, в противном случае необходимо ручное сканирование"
msgid "Manual Configuration"
msgstr "Ручная конфигурация"
msgid "Enable the manual configuration of modem information (After enable, the automatic scanning and configuration function for modem information will be disabled)"
msgstr "Включите ручную конфигурацию информации о модеме (после включения функция автоматического сканирования и конфигурации информации о модеме будет отключена)"
msgid "Modem Config"
msgstr "Конфигурация модема"
msgid "Удалить"
msgstr "Удалить"
msgid "Сеть"
msgstr "Сеть"
msgid "Modem Name"
msgstr "Название модема"
msgid "AT Port"
msgstr "AT Порт"

View File

@ -680,14 +680,6 @@ msgstr "输入SCS"
msgid "Enter NRBAND"
msgstr "输入NR频段"
msgid "SIM Slot|Now"
msgstr "SIM卡卡槽|当前"
msgid "SIM Slot|Next Boot"
msgstr "SIM卡卡槽|下次启动"
msgid "SIM Slot|Setting'
msgstr "SIM卡卡槽|设置"
msgid "SIM1 (Close to power)"
msgstr "SIM1 (靠近电源)"
@ -742,3 +734,123 @@ msgstr "启用多WAN"
msgid "Mwan Config"
msgstr "多WAN设置"
msgid "Network Down Judge Times"
msgstr "网络下线判断次数"
msgid "Network Detect Interval"
msgstr "网络检测间隔"
msgid "SIM Auto Switch"
msgstr "SIM卡自动切换"
msgid "Ping Destination"
msgstr "Ping目标"
msgid "SIM Settings"
msgstr "SIM卡设置"
msgid "SIM Config"
msgstr "SIM卡配置"
msgid "TTL Config"
msgstr "TTL配置"
msgid "enable_dial"
msgstr "启用拨号"
#modem_info.htm
msgid "Reference Signal Received Power"
msgstr "参考信号接收功率(RSRP)"
msgid "Reference Signal Received Quality"
msgstr "参考信号接收质量(RSRQ)"
msgid "Absolute Radio-Frequency Channel Number"
msgstr "绝对射频信道号(ARFCN)"
msgid "Tracking area code of cell servedby neighbor Enb"
msgstr "邻区Enb服务的跟踪区编码(TAC)"
msgid "Received Signal Level"
msgstr "接收信号级别(RxLev)"
msgid "Signal to Interference plus Noise Ratio Bandwidth"
msgstr "信噪比带宽(SINR)"
msgid "International Mobile Equipment Identity"
msgstr "国际移动设备识别码(IMEI)"
msgid "Integrate Circuit Card Identity"
msgstr "集成电路卡识别码(ICCID)"
#dial_overview.htm
msgid "Manually Reload dial configurations When the dial configuration fails to take effect"
msgstr "当拨号配置无法生效时,手动重新加载拨号配置"
msgid "Reload Dial Configurations"
msgstr "重新加载拨号配置"
#modem_debug.htm
msgid "Dial Mode"
msgstr "拨号模式"
msgid "Current Mode"
msgstr "当前模式"
msgid "Rat Prefer"
msgstr "制式偏好"
msgid "Setting"
msgstr "设置"
msgid "Neighbor Cell"
msgstr "邻区"
msgid "Lock Cell Setting"
msgstr "锁定小区设置"
msgid "Lock Band"
msgstr "锁定频段"
msgid "Select All"
msgstr "全选"
msgid "Disconnected"
msgstr "未连接"
msgid "Serving Cell Receive Level"
msgstr "服务小区接收信号级别(Srxlev)"
msgid "Internet Service Provider"
msgstr "互联网服务提供商(ISP)"
msgid "SIM Error,Error code:"
msgstr "SIM卡错误,错误码:"
msgid "Warning!"
msgstr "警告!"
msgid "PIN Code"
msgstr "PIN码"
msgid "If the PIN code is not set, leave it blank."
msgstr "如果未设置PIN码请留空。"
msgid "RA Master"
msgstr "IPV6中继 主"
msgid "After checking, This interface will enable IPV6 RA Master.Only one interface can be set to RA Master."
msgstr "勾选后此接口将启用IPV6中继主。只能设置一个接口为RA主。"
msgid "The metric value is used to determine the priority of the route. The smaller the value, the higher the priority. Cannot duplicate."
msgstr "度量值用于确定路由的优先级。值越小,优先级越高。不能重复。"
msgid "Modem Log"
msgstr "模组日志"
msgid "enabled"
msgstr "已启用"
msgid "disabled"
msgstr "已禁用"

View File

@ -646,6 +646,7 @@ msgstr "通用"
msgid "Private"
msgstr "私有"
msgid "Switch SIM"
msgstr "切换SIM卡"
@ -679,14 +680,6 @@ msgstr "输入SCS"
msgid "Enter NRBAND"
msgstr "输入NR频段"
msgid "SIM Slot|Now"
msgstr "SIM卡卡槽|当前"
msgid "SIM Slot|Next Boot"
msgstr "SIM卡卡槽|下次启动"
msgid "SIM Slot|Setting'
msgstr "SIM卡卡槽|设置"
msgid "SIM1 (Close to power)"
msgstr "SIM1 (靠近电源)"
@ -742,14 +735,125 @@ msgstr "启用多WAN"
msgid "Mwan Config"
msgstr "多WAN设置"
msgid "sticky mode"
msgstr "粘滞模式"
msgid "Network Down Judge Times"
msgstr "网络下线判断次数"
msgid "same source ip address will always use the same wan interface"
msgstr "相同源IP会使用同一个WAN出口"
msgid "Network Detect Interval"
msgstr "网络检测间隔"
msgid "sticky timeout"
msgstr "粘滞超时"
msgid "SIM Auto Switch"
msgstr "SIM卡自动切换"
msgid "Check and modify the mwan configuration"
msgstr "检查并修改mwan配置"
msgid "Ping Destination"
msgstr "Ping目标"
msgid "SIM Settings"
msgstr "SIM卡设置"
msgid "SIM Config"
msgstr "SIM卡配置"
msgid "TTL Config"
msgstr "TTL配置"
msgid "enable_dial"
msgstr "启用拨号"
#modem_info.htm
msgid "Reference Signal Received Power"
msgstr "参考信号接收功率(RSRP)"
msgid "Reference Signal Received Quality"
msgstr "参考信号接收质量(RSRQ)"
msgid "Absolute Radio-Frequency Channel Number"
msgstr "绝对射频信道号(ARFCN)"
msgid "Tracking area code of cell servedby neighbor Enb"
msgstr "邻区Enb服务的跟踪区编码(TAC)"
msgid "Received Signal Level"
msgstr "接收信号级别(RxLev)"
msgid "Signal to Interference plus Noise Ratio Bandwidth"
msgstr "信噪比带宽(SINR)"
msgid "International Mobile Equipment Identity"
msgstr "国际移动设备识别码(IMEI)"
msgid "Integrate Circuit Card Identity"
msgstr "集成电路卡识别码(ICCID)"
#dial_overview.htm
msgid "Manually Reload dial configurations When the dial configuration fails to take effect"
msgstr "当拨号配置无法生效时,手动重新加载拨号配置"
msgid "Reload Dial Configurations"
msgstr "重新加载拨号配置"
#modem_debug.htm
msgid "Dial Mode"
msgstr "拨号模式"
msgid "Current Mode"
msgstr "当前模式"
msgid "Rat Prefer"
msgstr "制式偏好"
msgid "Setting"
msgstr "设置"
msgid "Neighbor Cell"
msgstr "邻区"
msgid "Lock Cell Setting"
msgstr "锁定小区设置"
msgid "Lock Band"
msgstr "锁定频段"
msgid "Select All"
msgstr "全选"
msgid "Disconnected"
msgstr "未连接"
msgid "Serving Cell Receive Level"
msgstr "服务小区接收信号级别(Srxlev)"
msgid "Internet Service Provider"
msgstr "互联网服务提供商(ISP)"
msgid "SIM Error,Error code:"
msgstr "SIM卡错误,错误码:"
msgid "Warning!"
msgstr "警告!"
msgid "PIN Code"
msgstr "PIN码"
msgid "If solt 2 config is not set,will use slot 1 config."
msgstr "如果未设置卡槽2配置将使用卡槽1配置。"
msgid "If the PIN code is not set, leave it blank."
msgstr "如果未设置PIN码请留空。"
msgid "RA Master"
msgstr "IPV6中继 主"
msgid "After checking, This interface will enable IPV6 RA Master.Only one interface can be set to RA Master."
msgstr "勾选后此接口将启用IPV6中继主。只能设置一个接口为RA主。"
msgid "The metric value is used to determine the priority of the route. The smaller the value, the higher the priority. Cannot duplicate."
msgstr "度量值用于确定路由的优先级。值越小,优先级越高。不能重复。"
msgid "Modem Log"
msgstr "模组日志"
msgid "enabled"
msgstr "已启用"
msgid "disabled"
msgstr "已禁用"

6
luci-app-modem/quickinstall.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
host=$1
scp -oHostkeyalgorithms=+ssh-rsa -r luasrc/* root@$host:/usr/lib/lua/luci/
scp -oHostkeyalgorithms=+ssh-rsa -r root/usr/* root@$host:/usr/
scp -oHostkeyalgorithms=+ssh-rsa -r root/etc/init.d/* root@$host:/etc/init.d/
ssh -oHostkeyalgorithms=+ssh-rsa root@$host rm -rf /tmp/luci-indexcache

View File

@ -1,332 +0,0 @@
config custom-commands
option description '****************通用****************'
option command 'ATI'
config custom-commands
option description '模组信息 > ATI'
option command 'ATI'
config custom-commands
option description '查询SIM卡状态 > AT+CPIN?'
option command 'AT+CPIN?'
config custom-commands
option description '查询网络信号质量4G > AT+CSQ'
option command 'AT+CSQ'
config custom-commands
option description '查询网络信号质量5G > AT+CESQ'
option command 'AT+CESQ'
config custom-commands
option description '查询网络信息 > AT+COPS?'
option command 'AT+COPS?'
config custom-commands
option description '查询PDP信息 > AT+CGDCONT?'
option command 'AT+CGDCONT?'
config custom-commands
option description '查询PDP地址 > AT+CGPADDR'
option command 'AT+CGPADDR'
config custom-commands
option description '查询模组IMEI > AT+CGSN'
option command 'AT+CGSN'
config custom-commands
option description '查询模组IMEI > AT+GSN'
option command 'AT+GSN'
config custom-commands
option description '查看当前电压'
option command 'AT+CBC'
config custom-commands
option description '最小功能模式 > AT+CFUN=0'
option command 'AT+CFUN=0'
config custom-commands
option description '全功能模式 > AT+CFUN=1'
option command 'AT+CFUN=1'
config custom-commands
option description '重启模组 > AT+CFUN=1,1'
option command 'AT+CFUN=1,1'
config custom-commands
option description '****************移远****************'
option command 'ATI'
config custom-commands
option description 'SIM卡状态上报 > AT+QSIMSTAT?'
option command 'AT+QSIMSTAT?'
config custom-commands
option description '设置当前使用的为卡1 > AT+QUIMSLOT=1'
option command 'AT+QUIMSLOT=1'
config custom-commands
option description '设置当前使用的为卡2 > AT+QUIMSLOT=2'
option command 'AT+QUIMSLOT=2'
config custom-commands
option description '查询网络信息 > AT+QNWINFO'
option command 'AT+QNWINFO'
config custom-commands
option description '查询SIM卡签约速率 > AT+QNWCFG="nr5g_ambr"'
option command 'AT+QNWCFG="nr5g_ambr"'
config custom-commands
option description '查询载波聚合参数 > AT+QCAINFO'
option command 'AT+QCAINFO'
config custom-commands
option description '查询当前拨号模式 > AT+QCFG="usbnet"'
option command 'AT+QCFG="usbnet"'
config custom-commands
option description 'QMI/GobiNet拨号 > AT+QCFG="usbnet",0'
option command 'AT+QCFG="usbnet",0'
config custom-commands
option description 'ECM拨号 > AT+QCFG="usbnet",1'
option command 'AT+QCFG="usbnet",1'
config custom-commands
option description 'MBIM拨号 > AT+QCFG="usbnet",2'
option command 'AT+QCFG="usbnet",2'
config custom-commands
option description 'RNDIS拨号 > AT+QCFG="usbnet",3'
option command 'AT+QCFG="usbnet",3'
config custom-commands
option description 'NCM拨号 > AT+QCFG="usbnet",5'
option command 'AT+QCFG="usbnet",5'
config custom-commands
option description '锁4G > AT+QNWPREFCFG="mode_pref",LTE'
option command 'AT+QNWPREFCFG="mode_pref",LTE'
config custom-commands
option description '锁5G > AT+QNWPREFCFG="mode_pref",NR5G'
option command 'AT+QNWPREFCFG="mode_pref",NR5G'
config custom-commands
option description '锁5G NSA > AT+QNWPREFCFG="mode_pref",NR5G-NSA'
option command 'AT+QNWPREFCFG="mode_pref",NR5G-NSA'
config custom-commands
option description '锁5G SA > AT+QNWPREFCFG="mode_pref",NR5G-SA'
option command 'AT+QNWPREFCFG="mode_pref",NR5G-SA'
config custom-commands
option description '恢复自动搜索网络 > AT+QNWPREFCFG="mode_pref",AUTO'
option command 'AT+QNWPREFCFG="mode_pref",AUTO'
config custom-commands
option description '查询模组IMEI > AT+EGMR=0,7'
option command 'AT+EGMR=0,7'
config custom-commands
option description '更改模组IMEI > AT+EGMR=1,7,"IMEI"'
option command 'AT+EGMR=1,7,"在此设置IMEI"'
config custom-commands
option description '获取模组温度 > AT+QTEMP'
option command 'AT+QTEMP'
config custom-commands
option description '切换为USB通信端口 > AT+QCFG="data_interface",0,0'
option command 'AT+QCFG="data_interface",0,0'
config custom-commands
option description '切换为PCIE通信端口 > AT+QCFG="data_interface",1,0'
option command 'AT+QCFG="data_interface",1,0'
config custom-commands
option description '查看当前USB速率 > AT+QCFG="usbspeed"'
option command 'AT+QCFG="usbspeed"'
config custom-commands
option description '切换为USB2.0 > AT+QCFG="usbspeed","20"'
option command 'AT+QCFG="usbspeed","20"'
config custom-commands
option description '切换为USB3.1 Gen15Gbps > AT+QCFG="usbspeed","311"'
option command 'AT+QCFG="usbspeed","311"'
config custom-commands
option description '切换为USB3.1 Gen110Gbps > AT+QCFG="usbspeed","312"'
option command 'AT+QCFG="usbspeed","312"'
config custom-commands
option description '重置模组 > AT+QCFG="ResetFactory"'
option command 'AT+QCFG="ResetFactory"'
config custom-commands
option description '****************广和通****************'
option command 'ATI'
config custom-commands
option description '设置当前使用的为卡1 > AT+GTDUALSIM=0'
option command 'AT+GTDUALSIM=0'
config custom-commands
option description '设置当前使用的为卡2 > AT+GTDUALSIM=1'
option command 'AT+GTDUALSIM=1'
config custom-commands
option description 'ECM手动拨号 > AT+GTRNDIS=1,1'
option command 'AT+GTRNDIS=1,1'
config custom-commands
option description 'ECM拨号断开 > AT+GTRNDIS=0,1'
option command 'AT+GTRNDIS=0,1'
config custom-commands
option description '查询当前端口模式 > AT+GTUSBMODE?'
option command 'AT+GTUSBMODE?'
config custom-commands
option description 'QMI/GobiNet拨号 > AT+GTUSBMODE=32'
option command 'AT+GTUSBMODE=32'
config custom-commands
option description 'ECM拨号 > AT+GTUSBMODE=18'
option command 'AT+GTUSBMODE=18'
config custom-commands
option description 'MBIM拨号 > AT+GTUSBMODE=30'
option command 'AT+GTUSBMODE=30'
config custom-commands
option description 'RNDIS拨号 > AT+GTUSBMODE=24'
option command 'AT+GTUSBMODE=24'
config custom-commands
option description 'NCM拨号 > AT+GTUSBMODE=18'
option command 'AT+GTUSBMODE=18'
config custom-commands
option description '锁4G > AT+GTACT=2'
option command 'AT+GTACT=2'
config custom-commands
option description '锁5G > AT+GTACT=14'
option command 'AT+GTACT=14'
config custom-commands
option description '恢复自动搜索网络 > AT+GTACT=20'
option command 'AT+GTACT=20'
config custom-commands
option description '查询当前连接的网络类型 > AT+PSRAT?'
option command 'AT+PSRAT?'
config custom-commands
option description '查询模组IMEI > AT+GTSN=0,7'
option command 'AT+GTSN=0,7'
config custom-commands
option description '更改模组IMEI > AT+GTSN=1,7,"IMEI"'
option command 'AT+GTSN=1,7,"在此设置IMEI"'
config custom-commands
option description '报告一次当前BBIC的温度 > AT+MTSM=1,6'
option command 'AT+MTSM=1,6'
config custom-commands
option description '报告一次当前射频的温度 > AT+MTSM=1,7'
option command 'AT+MTSM=1,7'
config custom-commands
option description '获取当前温度 > AT+GTLADC'
option command 'AT+GTLADC'
config custom-commands
option description '重启模组 > AT+CFUN=15'
option command 'AT+CFUN=15'
config custom-commands
option description '****************美格****************'
option command 'ATI'
config custom-commands
option description 'SIM卡状态上报 > AT^SIMSLOTURC=1'
option command 'AT^SIMSLOTURC=1'
config custom-commands
option description '获取SIM卡卡槽状态 > AT^SIMSLOT?'
option command 'AT^SIMSLOT?'
config custom-commands
option description '设置当前使用的为卡1 > AT^SIMSLOT=1'
option command 'AT^SIMSLOT=1'
config custom-commands
option description '设置当前使用的为卡2 > AT^SIMSLOT=2'
option command 'AT^SIMSLOT=2'
config custom-commands
option description '查询网络信息 > AT^SYSINFOEX'
option command 'AT^SYSINFOEX'
config custom-commands
option description '查询载波聚合小区信息 > AT^CELLINFO=3'
option command 'AT^CELLINFO=3'
config custom-commands
option description '查询当前拨号模式 > AT+SER?'
option command 'AT+SER?'
config custom-commands
option description 'QMI/GobiNet拨号 > AT+SER=1,1'
option command 'AT+SER=1,1'
config custom-commands
option description 'ECM拨号 > AT+SER=2,1'
option command 'AT+SER=2,1'
config custom-commands
option description 'MBIM拨号 > AT+SER=3,1'
option command 'AT+SER=3,1'
config custom-commands
option description 'RNDIS拨号 > AT+SER=3,1'
option command 'AT+SER=3,1'
config custom-commands
option description 'NCM拨号 > AT+SER=2,1'
option command 'AT+SER=2,1'
config custom-commands
option description '锁4G > AT^SYSCFGEX="03",all,0,2,all,all,all,all,1'
option command 'AT^SYSCFGEX="03",all,0,2,all,all,all,all,1'
config custom-commands
option description '锁5G > AT^SYSCFGEX="04",all,0,2,all,all,all,all,1'
option command 'AT^SYSCFGEX="04",all,0,2,all,all,all,all,1'
config custom-commands
option description '恢复自动搜索网络 > AT^SYSCFGEX="00",all,0,2,all,all,all,all,1'
option command 'AT^SYSCFGEX="00",all,0,2,all,all,all,all,1'
config custom-commands
option description '查询模组IMEI > AT+LCTSN=0,7'
option command 'AT+LCTSN=0,7'
config custom-commands
option description '更改模组IMEI > AT+LCTSN=1,7,"IMEI"'
option command 'AT+LCTSN=1,7,"在此设置IMEI"'
config custom-commands
option description '获取模组温度 > AT+TEMP'
option command 'AT+TEMP'
config custom-commands
option description '重启模组 > AT+RESET'
option command 'AT+RESET'

View File

@ -1,276 +1,4 @@
config global 'global'
option enable_dial '1'
option modem_number '0'
option manual_configuration '0'
option ethernet "cpewan0"
config custom-commands
option description '****************通用****************'
option command 'ATI'
config custom-commands
option description '模组信息 > ATI'
option command 'ATI'
config custom-commands
option description '查询SIM卡状态 > AT+CPIN?'
option command 'AT+CPIN?'
config custom-commands
option description '查询网络信号质量4G > AT+CSQ'
option command 'AT+CSQ'
config custom-commands
option description '查询网络信号质量5G > AT+CESQ'
option command 'AT+CESQ'
config custom-commands
option description '查询网络信息 > AT+COPS?'
option command 'AT+COPS?'
config custom-commands
option description '查询PDP信息 > AT+CGDCONT?'
option command 'AT+CGDCONT?'
config custom-commands
option description '查询PDP地址 > AT+CGPADDR'
option command 'AT+CGPADDR'
config custom-commands
option description '最小功能模式 > AT+CFUN=0'
option command 'AT+CFUN=0'
config custom-commands
option description '全功能模式 > AT+CFUN=1'
option command 'AT+CFUN=1'
config custom-commands
option description '重启模组 > AT+CFUN=1,1'
option command 'AT+CFUN=1,1'
config custom-commands
option description '****************移远****************'
option command 'ATI'
config custom-commands
option description 'SIM卡状态上报 > AT+QSIMSTAT?'
option command 'AT+QSIMSTAT?'
config custom-commands
option description '设置当前使用的为卡1 > AT+QUIMSLOT=1'
option command 'AT+QUIMSLOT=1'
config custom-commands
option description '设置当前使用的为卡2 > AT+QUIMSLOT=2'
option command 'AT+QUIMSLOT=2'
config custom-commands
option description '查询网络信息 > AT+QNWINFO'
option command 'AT+QNWINFO'
config custom-commands
option description '查询SIM卡签约速率 > AT+QNWCFG="nr5g_ambr"'
option command 'AT+QNWCFG="nr5g_ambr"'
config custom-commands
option description '查询载波聚合参数 > AT+QCAINFO'
option command 'AT+QCAINFO'
config custom-commands
option description '查询当前拨号模式 > AT+QCFG="usbnet"'
option command 'AT+QCFG="usbnet"'
config custom-commands
option description 'QMI/GobiNet拨号 > AT+QCFG="usbnet",0'
option command 'AT+QCFG="usbnet",0'
config custom-commands
option description 'ECM拨号 > AT+QCFG="usbnet",1'
option command 'AT+QCFG="usbnet",1'
config custom-commands
option description 'MBIM拨号 > AT+QCFG="usbnet",2'
option command 'AT+QCFG="usbnet",2'
config custom-commands
option description 'RNDIS拨号 > AT+QCFG="usbnet",3'
option command 'AT+QCFG="usbnet",3'
config custom-commands
option description 'NCM拨号 > AT+QCFG="usbnet",5'
option command 'AT+QCFG="usbnet",5'
config custom-commands
option description '锁4G > AT+QNWPREFCFG="mode_pref",LTE'
option command 'AT+QNWPREFCFG="mode_pref",LTE'
config custom-commands
option description '锁5G > AT+QNWPREFCFG="mode_pref",NR5G'
option command 'AT+QNWPREFCFG="mode_pref",NR5G'
config custom-commands
option description '锁5G NSA > AT+QNWPREFCFG="mode_pref",NR5G-NSA'
option command 'AT+QNWPREFCFG="mode_pref",NR5G-NSA'
config custom-commands
option description '锁5G SA > AT+QNWPREFCFG="mode_pref",NR5G-SA'
option command 'AT+QNWPREFCFG="mode_pref",NR5G-SA'
config custom-commands
option description '恢复自动搜索网络 > AT+QNWPREFCFG="mode_pref",AUTO'
option command 'AT+QNWPREFCFG="mode_pref",AUTO'
config custom-commands
option description '查询模组IMEI > AT+CGSN'
option command 'AT+CGSN'
config custom-commands
option description '查询模组IMEI > AT+GSN'
option command 'AT+GSN'
config custom-commands
option description '更改模组IMEI > AT+EGMR=1,7,"IMEI"'
option command 'AT+EGMR=1,7,"在此设置IMEI"'
config custom-commands
option description '获取模组温度 > AT+QTEMP'
option command 'AT+QTEMP'
config custom-commands
option description '切换为USB通信端口 > AT+QCFG="data_interface",0,0'
option command 'AT+QCFG="data_interface",0,0'
config custom-commands
option description '切换为PCIE通信端口 > AT+QCFG="data_interface",1,0'
option command 'AT+QCFG="data_interface",1,0'
config custom-commands
option description '查看当前USB速率 > AT+QCFG="usbspeed"'
option command 'AT+QCFG="usbspeed"'
config custom-commands
option description '切换为USB2.0 > AT+QCFG="usbspeed","20"'
option command 'AT+QCFG="usbspeed","20"'
config custom-commands
option description '切换为USB3.1 Gen15Gbps > AT+QCFG="usbspeed","311"'
option command 'AT+QCFG="usbspeed","311"'
config custom-commands
option description '切换为USB3.1 Gen110Gbps > AT+QCFG="usbspeed","312"'
option command 'AT+QCFG="usbspeed","312"'
config custom-commands
option description '重置模组 > AT+QCFG="ResetFactory"'
option command 'AT+QCFG="ResetFactory"'
config custom-commands
option description '****************广和通****************'
option command 'ATI'
config custom-commands
option description '设置当前使用的为卡1 > AT+GTDUALSIM=0'
option command 'AT+GTDUALSIM=0'
config custom-commands
option description '设置当前使用的为卡2 > AT+GTDUALSIM=1'
option command 'AT+GTDUALSIM=1'
config custom-commands
option description 'ECM手动拨号 > AT+GTRNDIS=1,1'
option command 'AT+GTRNDIS=1,1'
config custom-commands
option description 'ECM拨号断开 > AT+GTRNDIS=0,1'
option command 'AT+GTRNDIS=0,1'
config custom-commands
option description '查询当前端口模式 > AT+GTUSBMODE?'
option command 'AT+GTUSBMODE?'
config custom-commands
option description 'QMI/GobiNet拨号 > AT+GTUSBMODE=32'
option command 'AT+GTUSBMODE=32'
config custom-commands
option description 'ECM拨号 > AT+GTUSBMODE=18'
option command 'AT+GTUSBMODE=18'
config custom-commands
option description 'MBIM拨号 > AT+GTUSBMODE=30'
option command 'AT+GTUSBMODE=30'
config custom-commands
option description 'RNDIS拨号 > AT+GTUSBMODE=24'
option command 'AT+GTUSBMODE=24'
config custom-commands
option description 'NCM拨号 > AT+GTUSBMODE=18'
option command 'AT+GTUSBMODE=18'
config custom-commands
option description '锁4G > AT+GTACT=2'
option command 'AT+GTACT=2'
config custom-commands
option description '锁5G > AT+GTACT=14'
option command 'AT+GTACT=14'
config custom-commands
option description '恢复自动搜索网络 > AT+GTACT=20'
option command 'AT+GTACT=20'
config custom-commands
option description '查询当前连接的网络类型 > AT+PSRAT?'
option command 'AT+PSRAT?'
config custom-commands
option description '查询模组IMEI > AT+CGSN?'
option command 'AT+CGSN?'
config custom-commands
option description '查询模组IMEI > AT+GSN?'
option command 'AT+GSN?'
config custom-commands
option description '更改模组IMEI > AT+GTSN=1,7,"IMEI"'
option command 'AT+GTSN=1,7,"在此设置IMEI"'
config custom-commands
option description '报告一次当前BBIC的温度 > AT+MTSM=1,6'
option command 'AT+MTSM=1,6'
config custom-commands
option description '报告一次当前射频的温度 > AT+MTSM=1,7'
option command 'AT+MTSM=1,7'
config custom-commands
option description '重置模组 > AT+CFUN=15'
option command 'AT+CFUN=15'
config dial-config 'defa0'
option network_bridge '0'
option enable '1'
option network 'wwan0'
option pdp_type 'ipv4v6'
option auth 'none'
option id 'defa0'
config dial-config 'defa1'
option network_bridge '0'
option enable '1'
option network 'usb0'
option pdp_type 'ipv4v6'
option auth 'none'
option id 'defa1'
config dial-config 'defa2'
option network_bridge '0'
option enable '1'
option network 'eth2'
option pdp_type 'ipv4v6'
option auth 'none'
option id 'defa2'

40
luci-app-modem/root/etc/hotplug.d/net/20-modem-net Normal file → Executable file
View File

@ -1,29 +1,25 @@
#!/bin/sh
# Copyright (C) 2023 Siriling <siriling@qq.com>
#导入组件工具
source "/usr/share/modem/modem_util.sh"
# Copyright (C) 2024 Tom <fjrcn@outlook.com>
manual=$(uci get -q modem.global.manual_configuration)
[ "${manual}" -eq 1 ] && exit
logger -t modem_hotplug "net slot: ${DEVPATH} action: ${ACTION}"
#网络设备名称不存在,退出
[ -z "${INTERFACE}" ] && exit
#网络设备路径不存在,退出
[ -z "${DEVPATH}" ] && exit
#始终确保存在运行目录
mkdir -m 0755 -p "${MODEM_RUNDIR}"
slot_path=$(readlink -f "/sys/${DEVPATH}/device")
[ -z "${slot_path}" ] && exit
slot_dir=$(dirname "${slot_path}")
slot=$(basename "${slot_dir}")
#设备路径不存在,退出
#初始化模组配置
# [[ "${INTERFACE}" = *"ip6tnl0"* ]] && {
# sh "${SCRIPT_DIR}/modem_init.sh"
# }
if [[ "${INTERFACE}" = *"usb"* ]] || [[ "${INTERFACE}" = *"wwan"* ]] || [[ "${INTERFACE}" = *"eth"* ]]; then
#配置网络设备
m_set_network_device "${ACTION}" "${INTERFACE}" "/sys${DEVPATH}" "usb"
elif [[ "${INTERFACE}" = *"mhi_hwip"* ]] || [[ "${INTERFACE}" = *"rmnet_mhi"* ]]; then
#配置网络设备
m_set_network_device "${ACTION}" "${INTERFACE}" "/sys${DEVPATH}" "pcie"
else
exit
fi
[ -d "/sys/bus/usb/devices/${slot}" ] && slot_type="usb"
[ -d "/sys/bus/pci/devices/${slot}" ] && slot_type="pcie"
[ -z "${slot_type}" ] && exit
logger -t modem_hotplug "net slot: ${slot} action: ${ACTION} slot_type: ${slot_type}"
case "${ACTION}" in
add)
/usr/share/modem/modem_scan.sh add "${slot}" "${slot_type}"
;;
esac

30
luci-app-modem/root/etc/hotplug.d/usb/20-modem-usb Normal file → Executable file
View File

@ -1,19 +1,19 @@
#!/bin/sh
# Copyright (C) 2023 Siriling <siriling@qq.com>
#导入组件工具
source "/usr/share/modem/modem_util.sh"
#只在添加和移除的时候执行
# [ "$ACTION" != "add" ] && [ "$ACTION" != "remove" ] && exit
#设备号不存在退出去掉多余的tty设备
# Copyright (C) 2024 Tom <fjrcn@outlook.com>
manual=$(uci get -q modem.global.manual_configuration)
[ "${manual}" -eq 1 ] && exit
logger -t modem_hotplug "usb_event slot: ${DEVPATH} action: ${ACTION}"
[ -z "${DEVNUM}" ] && exit
#测试
# test_usb_hotplug
#始终确保存在运行目录
mkdir -m 0755 -p "${MODEM_RUNDIR}"
#设置USB设备
m_check_usb_device "${ACTION}" "${DEVNUM}" "${PRODUCT}" "/sys${DEVPATH}"
slot=$(basename "${DEVPATH}")
logger -t modem_hotplug "usb_event run slot: ${slot} action: ${ACTION}"
case "${ACTION}" in
bind|\
add)
/usr/share/modem/modem_scan.sh add "${slot}" usb
;;
remove)
/usr/share/modem/modem_scan.sh disable "${slot}" usb
;;
esac

View File

@ -0,0 +1,45 @@
#!/bin/sh /etc/rc.common
START=80
STOP=30
USE_PROCD=1
. /lib/functions.sh
start_service() {
config_load modem
config_foreach mk_rundir modem-device
config_get manual_configuration global manual_configuration
[ "$manual_configuration" -eq 1 ] && return
logger -t modem_init "modem init"
config_foreach try_modem modem-slot
}
mk_rundir()
{
modem_cfg="$1"
mkdir -p "/var/run/modem/${modem_cfg}_dir"
}
try_modem()
{
config_get slot "$1" slot
config_get type "$1" type
case "$type" in
usb)
path="/sys/bus/usb/devices/${slot}"
;;
pcie)
path="/sys/bus/pci/devices/${slot}"
;;
esac
if [ -d "$path" ]; then
logger -t modem_init "try modem $1"
procd_open_instance "try_$1"
procd_set_param command "ash" "/usr/share/modem/modem_scan.sh" "add" "$slot" "$type"
procd_close_instance
else
/usr/share/modem/modem_scan.sh disable "$slot"
fi
}

View File

@ -8,9 +8,6 @@ SCRIPT_DIR="/usr/share/modem"
#运行目录
MODEM_RUNDIR="/var/run/modem"
MODEM_RUN_CONFIG="${MODEM_RUNDIR}/config.cache"
#导入组件工具
source "${SCRIPT_DIR}/modem_scan.sh"
service_triggers()
{
@ -20,44 +17,46 @@ service_triggers()
start_service() {
mkdir -p $MODEM_RUNDIR
local enable_dial=$(uci -q get modem.@global[0].enable_dial)
if [ "$enable_dial" = "0" ]; then
stop_service
else
#加载模组配置
config_load modem
config_foreach dial_modem modem-device
fi
config_get enabled global enable_dial
[ "$enabled" = "0" ] && config_foreach hang_modem modem-device && stop
config_foreach run_modem modem-device
}
reload_service()
{
stop_service
start_service
stop
start
}
stop_service()
{
#清理运行目录
rm -rf $MODEM_RUNDIR
config_load modem
config_foreach hang_modem modem-device
}
dial_modem()
run_modem()
{
config_get enable_dial $1 enable_dial
if [ "$enable_dial" == "1" ];then
procd_open_instance "modem_$1"
procd_set_param command "/usr/share/modem/modem_dial.sh" "$1" "dial"
procd_set_param respawn
procd_close_instance
else
config_get enabled $1 enable_dial
if [ "$enabled" = "0" ] ;then
hang_modem $1
return
fi
procd_open_instance "modem_$1"
procd_set_param command "/usr/share/modem/modem_dial.sh" "$1" dial
procd_set_param respawn
procd_close_instance
logger -t modem_network "dial modem $1"
}
hang_modem()
{
/usr/share/modem/modem_dial.sh $1 hang
service_stop "modem_$1"
"/usr/share/modem/modem_dial.sh" "$1" hang
logger -t modem_network "hang modem $1"
}

View File

@ -1,21 +0,0 @@
#!/bin/sh /etc/rc.common
START=95
STOP=13
USE_PROCD=1
#运行目录
MODEM_RUNDIR="/var/run/modem"
MODEM_RUN_CONFIG="${MODEM_RUNDIR}/config.cache"
start_service() {
mkdir -p $MODEM_RUNDIR
local dontscan=$(uci -q get modem.@global[0].manual_configuration)
logger -t modem_scan "manual_configuration: $dontscan"
if [ "$dontscan" == "0" ]; then
procd_open_instance "modem_scan_service"
procd_set_param command /usr/share/modem/usb_modem_scan.sh
procd_close_instance
fi
}

View File

@ -0,0 +1,69 @@
#!/bin/sh
. /lib/functions.sh
. /lib/functions/uci-defaults.sh
. /lib/functions/system.sh
modem_settings()
{
local board="$1"
case $board in
HC,HC-G80)
#mini pci slot
uci set modem.u1_1_4="modem-slot"
uci set modem.u1_1_4.slot="1-1.4"
uci set modem.u1_1_4.type="usb"
uci set modem.u1_1_4.net_led="wwan"
#m.2 slot (usb2.0)
uci set modem.u1_1_1="modem-slot"
uci set modem.u1_1_1.slot="1-1.1"
uci set modem.u1_1_1.type="usb"
uci set modem.u1_1_1.net_led="wwan"
uci set modem.u1_1_1.ethernet="cpewan0"
#m.2 slot (usb3.0)
uci set modem.u2_1="modem-slot"
uci set modem.u2_1.slot="2-1"
uci set modem.u2_1.type="usb"
uci set modem.u2_1.net_led="wwan"
uci set modem.u2_1.ethernet="cpewan0"
uci commit modem
;;
huasifei,ws3006)
#m2 usb3.0
#(slot 2)
uci set modem.u2_1_2="modem-slot"
uci set modem.u2_1_2.slot="2-1.2"
uci set modem.u2_1_2.type="usb"
uci set modem.u2_1_2.net_led="wwan2"
uci set modem.u2_1_2.sim_led="green:sim2"
#(slot 1)
uci set modem.u2_1_4="modem-slot"
uci set modem.u2_1_4.slot="2-1.4"
uci set modem.u2_1_4.type="usb"
uci set modem.u2_1_4.net_led="wwan1"
uci set modem.u2_1_4.sim_led="green:sim1"
#mini pci slot
#(slot 2)
uci set modem.u1_1_2="modem-slot"
uci set modem.u1_1_2.slot="1-1.2"
uci set modem.u1_1_2.type="usb"
uci set modem.u1_1_2.net_led="wwan2"
uci set modem.u1_1_2.sim_led="green:sim2"
#(slot 1)
uci set modem.u1_1_3="modem-slot"
uci set modem.u1_1_3.slot="1-1.3"
uci set modem.u1_1_3.type="usb"
uci set modem.u1_1_3.net_led="wwan1"
uci set modem.u1_1_3.sim_led="green:sim1"
uci commit modem
;;
esac
}
board=$(board_name)
modem_settings $board
exit 0

View File

@ -0,0 +1,79 @@
#!/bin/sh
. /lib/functions.sh
info()
{
state=$(uci get modem.$1.state)
if [ "$state" = "disabled" ]; then
return
fi
info=$(/usr/share/modem/modem_ctrl.sh info $1)
json_array=$(echo $json_array | jq ". += [ $info ]")
}
sim_info()
{
state=$(uci get modem.$1.state)
if [ "$state" = "disabled" ]; then
return
fi
/usr/share/modem/modem_ctrl.sh sim_info $1
}
base_info()
{
state=$(uci get modem.$1.state)
if [ "$state" = "disabled" ]; then
return
fi
/usr/share/modem/modem_ctrl.sh base_info $1
}
network_info()
{
state=$(uci get modem.$1.state)
if [ "$state" = "disabled" ]; then
return
fi
/usr/share/modem/modem_ctrl.sh network_info $1
}
cell_info()
{
state=$(uci get modem.$1.state)
if [ "$state" = "disabled" ]; then
return
fi
/usr/share/modem/modem_ctrl.sh cell_info $1
}
case "$1" in
list)
echo '{ "info": { }, "base_info": { }, "failme": {} }'
;;
call)
case "$2" in
"info")
json_array="[]"
config_load modem
config_foreach info modem-device
echo "{\"info\":$json_array}"
;;
"base_info")
config_load modem
config_foreach base_info modem-device
;;
"sim_info")
config_load modem
config_foreach sim_info modem-device
;;
"network_info")
config_load modem
config_foreach network_info modem-device
;;
"cell_info")
config_load modem
config_foreach cell_info modem-device
;;
esac
;;
esac

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,288 @@
#!/bin/sh
SCRIPT_DIR="/usr/share/modem"
source /usr/share/libubox/jshn.sh
source "${SCRIPT_DIR}/modem_util.sh"
add_plain_info_entry()
{
key=$1
value=$2
key_full_name=$3
class_overwrite=$4
if [ -n "$class_overwrite" ]; then
class="$class_overwrite"
fi
json_add_object ""
json_add_string key "$key"
json_add_string value "$value"
json_add_string "full_name" "$key_full_name"
json_add_string "type" "plain_text"
if [ -n "$class" ]; then
json_add_string "class" "$class"
fi
json_close_object
}
add_warning_message_entry()
{
key=$1
value=$2
key_full_name=$3
class_overwrite=$4
if [ -n "$class_overwrite" ]; then
class="$class_overwrite"
fi
json_add_object ""
json_add_string key "$key"
json_add_string value "$value"
json_add_string "full_name" "$key_full_name"
json_add_string "type" "warnning_message"
if [ -n "$class" ]; then
json_add_string "class" "$class"
fi
json_close_object
}
add_bar_info_entry()
{
key=$1
value=$2
key_full_name=$3
min_value=$4
max_value=$5
unit=$6
class_overwrite=$7
if [ -n "$class_overwrite" ]; then
class="$class_overwrite"
fi
json_add_object ""
json_add_string key "$key"
json_add_string value "$value"
json_add_string min_value "$min_value"
json_add_string max_value "$max_value"
json_add_string "full_name" "$key_full_name"
json_add_string "unit" "$unit"
json_add_string "type" "progress_bar"
if [ -n "$class" ]; then
json_add_string "class" "$class"
fi
json_close_object
}
add_avalible_band_entry()
{
band_id=$1
band_name=$2
json_add_object ""
json_add_string band_id "$band_id"
json_add_string band_name "$band_name"
json_add_string "type" "avalible_band"
json_close_object
}
get_dns()
{
[ -z "$define_connect" ] && {
define_connect="1"
}
local public_dns1_ipv4="223.5.5.5"
local public_dns2_ipv4="119.29.29.29"
local public_dns1_ipv6="2400:3200::1" #下一代互联网北京研究中心240C::6666阿里2400:3200::1腾讯2402:4e00::
local public_dns2_ipv6="2402:4e00::"
#获取DNS地址
at_command="AT+GTDNS=${define_connect}"
local response=$(at ${at_port} ${at_command} | grep "+GTDNS: ")
local ipv4_dns1=$(echo "${response}" | awk -F'"' '{print $2}' | awk -F',' '{print $1}')
[ -z "$ipv4_dns1" ] && {
ipv4_dns1="${public_dns1_ipv4}"
}
local ipv4_dns2=$(echo "${response}" | awk -F'"' '{print $4}' | awk -F',' '{print $1}')
[ -z "$ipv4_dns2" ] && {
ipv4_dns2="${public_dns2_ipv4}"
}
local ipv6_dns1=$(echo "${response}" | awk -F'"' '{print $2}' | awk -F',' '{print $2}')
[ -z "$ipv6_dns1" ] && {
ipv6_dns1="${public_dns1_ipv6}"
}
local ipv6_dns2=$(echo "${response}" | awk -F'"' '{print $4}' | awk -F',' '{print $2}')
[ -z "$ipv6_dns2" ] && {
ipv6_dns2="${public_dns2_ipv6}"
}
json_add_object "dns"
json_add_string "ipv4_dns1" "$ipv4_dns1"
json_add_string "ipv4_dns2" "$ipv4_dns2"
json_add_string "ipv6_dns1" "$ipv6_dns1"
json_add_string "ipv6_dns2" "$ipv6_dns2"
json_close_object
}
get_sim_status()
{
local sim_status
case $1 in
"")
sim_status="miss"
sim_state_code=0
;;
*"ERROR"*)
sim_status="miss"
sim_state_code=0
;;
*"READY"*)
sim_status="ready"
sim_state_code=1
;;
*"SIM PIN"*)
sim_status="MT is waiting SIM PIN to be given"
sim_state_code=2
;;
*"SIM PUK"*)
sim_status="MT is waiting SIM PUK to be given"
sim_state_code=3
;;
*"PH-FSIM PIN"*)
sim_status="MT is waiting phone-to-SIM card password to be given"
sim_state_code=4
;;
*"PH-FSIM PIN"*)
sim_status="MT is waiting phone-to-very first SIM card password to be given"
sim_state_code=5
;;
*"PH-FSIM PUK"*)
sim_status="MT is waiting phone-to-very first SIM card unblocking password to be given"
sim_state_code=6
;;
*"SIM PIN2"*)
sim_status="MT is waiting SIM PIN2 to be given"
sim_state_code=7
;;
*"SIM PUK2"*)
sim_status="MT is waiting SIM PUK2 to be given"
sim_state_code=8
;;
*"PH-NET PIN"*)
sim_status="MT is waiting network personalization password to be given"
sim_state_code=9
;;
*"PH-NET PUK"*)
sim_status="MT is waiting network personalization unblocking password to be given"
sim_state_code=10
;;
*"PH-NETSUB PIN"*)
sim_status="MT is waiting network subset personalization password to be given"
sim_state_code=11
;;
*"PH-NETSUB PUK"*)
sim_status="MT is waiting network subset personalization unblocking password to be given"
sim_state_code=12
;;
*"PH-SP PIN"*)
sim_status="MT is waiting service provider personalization password to be given"
sim_state_code=13
;;
*"PH-SP PUK"*)
sim_status="MT is waiting service provider personalization unblocking password to be given"
sim_state_code=14
;;
*"PH-CORP PIN"*)
sim_status="MT is waiting corporate personalization password to be given"
sim_state_code=16
;;
*"PH-CORP PUK"*)
sim_status="MT is waiting corporate personalization unblocking password to be given"
sim_state_code=17
;;
*)
sim_status="unknown"
sim_state_code=99
;;
esac
echo "$sim_status"
}
#获取信号强度指示
# $1:信号强度指示数字
get_rssi()
{
local rssi
case $1 in
"99") rssi="unknown" ;;
* ) rssi=$((2 * $1 - 113)) ;;
esac
echo "$rssi"
}
#获取网络类型
# $1:网络类型数字
get_rat()
{
local rat
case $1 in
"0"|"1"|"3"|"8") rat="GSM" ;;
"2"|"4"|"5"|"6"|"9"|"10") rat="WCDMA" ;;
"7") rat="LTE" ;;
"11"|"12") rat="NR" ;;
esac
echo "${rat}"
}
#获取连接状态
#return raw data
get_connect_status()
{
at_cmd="AT+CGPADDR=1"
[ "$define_connect" == "3" ] && at_cmd="AT+CGPADDR=3"
expect="+CGPADDR:"
result=$(at $at_port $at_cmd | grep $expect)
if [ -n "$result" ];then
ipv6=$(echo $result | grep -oE "\b([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}\b")
ipv4=$(echo $result | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b")
disallow_ipv4="0.0.0.0"
#remove the disallow ip
if [ "$ipv4" == "$disallow_ipv4" ];then
ipv4=""
fi
fi
if [ -n "$ipv4" ] || [ -n "$ipv6" ];then
connect_status="Yes"
else
connect_status="No"
fi
add_plain_info_entry "connect_status" "$connect_status" "Connect Status"
}
#获取移远模组信息
# $1:AT串口
# $2:平台
# $3:连接定义
get_info()
{
#基本信息
base_info
#SIM卡信息
sim_info
if [ "$sim_status" != "ready" ]; then
add_warning_message_entry "sim_status" "$sim_status" "SIM Error,Error code:" "warning"
return
fi
#网络信息
network_info
if [ "$connect_status" != "Yes" ]; then
return
fi
#小区信息
cell_info
return
}

View File

@ -1,835 +0,0 @@
#!/bin/sh
# Copyright (C) 2023 Siriling <siriling@qq.com>
#脚本目录
SCRIPT_DIR="/usr/share/modem"
#预设
meig_presets()
{
#关闭自动上报系统模式变化
at_command='AT^MODE=0'
sh "${SCRIPT_DIR}/modem_at.sh" "$at_port" "$at_command"
#关闭自动上报DS流量
at_command='AT^DSFLOWRPT=0,0,1'
sh "${SCRIPT_DIR}/modem_at.sh" "$at_port" "$at_command"
}
#获取DNS
# $1:AT串口
# $2:连接定义
meig_get_dns()
{
local at_port="$1"
local define_connect="$2"
[ -z "$define_connect" ] && {
define_connect="1"
}
local public_dns1_ipv4="223.5.5.5"
local public_dns2_ipv4="119.29.29.29"
local public_dns1_ipv6="2400:3200::1" #下一代互联网北京研究中心240C::6666阿里2400:3200::1腾讯2402:4e00::
local public_dns2_ipv6="2402:4e00::"
#获取DNS地址
at_command="AT+CGCONTRDP=${define_connect}"
local response=$(at ${at_port} ${at_command} | grep "+CGCONTRDP: " | grep -E '[0-9]+.[0-9]+.[0-9]+.[0-9]+' | sed -n '1p')
local ipv4_dns1=$(echo "${response}" | awk -F',' '{print $7}' | awk -F' ' '{print $1}')
[ -z "$ipv4_dns1" ] && {
ipv4_dns1="${public_dns1_ipv4}"
}
local ipv4_dns2=$(echo "${response}" | awk -F',' '{print $8}' | awk -F' ' '{print $1}')
[ -z "$ipv4_dns2" ] && {
ipv4_dns2="${public_dns2_ipv4}"
}
local ipv6_dns1=$(echo "${response}" | awk -F',' '{print $7}' | awk -F' ' '{print $2}')
[ -z "$ipv6_dns1" ] && {
ipv6_dns1="${public_dns1_ipv6}"
}
local ipv6_dns2=$(echo "${response}" | awk -F',' '{print $8}' | awk -F' ' '{print $2}' | sed 's/\r//g')
[ -z "$ipv6_dns2" ] && {
ipv6_dns2="${public_dns2_ipv6}"
}
dns="{
\"dns\":{
\"ipv4_dns1\":\"$ipv4_dns1\",
\"ipv4_dns2\":\"$ipv4_dns2\",
\"ipv6_dns1\":\"$ipv6_dns1\",
\"ipv6_dns2\":\"$ipv6_dns2\"
}
}"
echo "$dns"
}
#获取拨号模式
# $1:AT串口
# $2:平台
meig_get_mode()
{
local at_port="$1"
local platform="$2"
at_command="AT+SER?"
local mode_num=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | grep "+SER:" | sed 's/+SER: //g' | sed 's/\r//g')
if [ -z "$mode_num" ]; then
echo "unknown"
return
fi
#获取芯片平台
if [ -z "$platform" ]; then
local modem_number=$(uci -q get modem.@global[0].modem_number)
for i in $(seq 0 $((modem_number-1))); do
local at_port_tmp=$(uci -q get modem.modem$i.at_port)
if [ "$at_port" = "$at_port_tmp" ]; then
platform=$(uci -q get modem.modem$i.platform)
break
fi
done
fi
local mode
case "$platform" in
"qualcomm")
case "$mode_num" in
"1") mode="qmi" ;; #-
# "1") mode="gobinet" ;;
"2") mode="ecm" ;;
"7") mode="mbim" ;;
"3") mode="rndis" ;;
"2") mode="ncm" ;;
*) mode="$mode_num" ;;
esac
;;
*)
mode="$mode_num"
;;
esac
echo "${mode}"
}
#设置拨号模式
# $1:AT串口
# $2:拨号模式配置
meig_set_mode()
{
local at_port="$1"
local mode_config="$2"
#获取芯片平台
local platform
local modem_number=$(uci -q get modem.@global[0].modem_number)
for i in $(seq 0 $((modem_number-1))); do
local at_port_tmp=$(uci -q get modem.modem$i.at_port)
if [ "$at_port" = "$at_port_tmp" ]; then
platform=$(uci -q get modem.modem$i.platform)
break
fi
done
#获取拨号模式配置
local mode_num
case "$platform" in
"qualcomm")
case "$mode_config" in
"qmi") mode_num="1" ;;
# "gobinet") mode_num="1" ;;
"ecm") mode_num="2" ;;
"mbim") mode_num="7" ;;
"rndis") mode_num="3" ;;
"ncm") mode_num="2" ;;
*) mode_num="1" ;;
esac
;;
*)
mode_num="1"
;;
esac
#设置模组
at_command="AT+SER=${mode_num},1"
sh ${SCRIPT_DIR}/modem_at.sh ${at_port} "${at_command}"
}
#获取网络偏好
# $1:AT串口
meig_get_network_prefer()
{
local at_port="$1"
at_command="AT^SYSCFGEX?"
local response=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | grep "\^SYSCFGEX:" | awk -F'"' '{print $2}')
local network_prefer_3g="0";
local network_prefer_4g="0";
local network_prefer_5g="0";
#匹配不同的网络类型
local auto=$(echo "${response}" | grep "00")
if [ -n "$auto" ]; then
network_prefer_3g="1"
network_prefer_4g="1"
network_prefer_5g="1"
else
local wcdma=$(echo "${response}" | grep "02")
local lte=$(echo "${response}" | grep "03")
local nr=$(echo "${response}" | grep "04")
if [ -n "$wcdma" ]; then
network_prefer_3g="1"
fi
if [ -n "$lte" ]; then
network_prefer_4g="1"
fi
if [ -n "$nr" ]; then
network_prefer_5g="1"
fi
fi
local network_prefer="{
\"network_prefer\":{
\"3G\":$network_prefer_3g,
\"4G\":$network_prefer_4g,
\"5G\":$network_prefer_5g
}
}"
echo "$network_prefer"
}
#设置网络偏好
# $1:AT串口
# $2:网络偏好配置
meig_set_network_prefer()
{
local at_port="$1"
local network_prefer="$2"
#获取网络偏好配置
local network_prefer_config
#获取选中的数量
local count=$(echo "$network_prefer" | grep -o "1" | wc -l)
#获取每个偏好的值
local network_prefer_3g=$(echo "$network_prefer" | jq -r '.["3G"]')
local network_prefer_4g=$(echo "$network_prefer" | jq -r '.["4G"]')
local network_prefer_5g=$(echo "$network_prefer" | jq -r '.["5G"]')
case "$count" in
"1")
if [ "$network_prefer_3g" = "1" ]; then
network_prefer_config="02"
elif [ "$network_prefer_4g" = "1" ]; then
network_prefer_config="03"
elif [ "$network_prefer_5g" = "1" ]; then
network_prefer_config="04"
fi
;;
"2")
if [ "$network_prefer_3g" = "1" ] && [ "$network_prefer_4g" = "1" ]; then
network_prefer_config="0302"
elif [ "$network_prefer_3g" = "1" ] && [ "$network_prefer_5g" = "1" ]; then
network_prefer_config="0402"
elif [ "$network_prefer_4g" = "1" ] && [ "$network_prefer_5g" = "1" ]; then
network_prefer_config="0403"
fi
;;
"3") network_prefer_config="00" ;;
*) network_prefer_config="00" ;;
esac
#设置模组
at_command='AT^SYSCFGEX="'${network_prefer_config}'",all,0,2,all,all,all,all,1'
sh ${SCRIPT_DIR}/modem_at.sh "${at_port}" "${at_command}"
}
#获取电压
# $1:AT串口
meig_get_voltage()
{
local at_port="$1"
# #Voltage电压
# at_command="AT+ADCREAD=0"
# local voltage=$(sh ${SCRIPT_DIR}/modem_at.sh $at_port $at_command | grep "+ADCREAD:" | awk -F' ' '{print $2}' | sed 's/\r//g')
# voltage=$(awk "BEGIN{ printf \"%.2f\", $voltage / 1000000 }" | sed 's/\.*0*$//')
# echo "${voltage}"
}
#获取温度
# $1:AT串口
meig_get_temperature()
{
local at_port="$1"
#Temperature温度
at_command="AT+TEMP"
response=$(sh ${SCRIPT_DIR}/modem_at.sh $at_port $at_command | grep 'TEMP: "cpu0-0-usr"' | awk -F'"' '{print $4}')
local temperature
if [ -n "$response" ]; then
temperature="${response}$(printf "\xc2\xb0")C"
fi
echo "${temperature}"
}
#获取连接状态
# $1:AT串口
# $2:连接定义
meig_get_connect_status()
{
local at_port="$1"
local define_connect="$2"
#默认值为1
[ -z "$define_connect" ] && {
define_connect="1"
}
at_command="AT+CGPADDR=${define_connect}"
local ipv4=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | grep "+CGPADDR: " | awk -F',' '{print $2}')
local not_ip="0.0.0.0"
#设置连接状态
local connect_status
if [ -z "$ipv4" ] || [[ "$ipv4" = *"$not_ip"* ]]; then
connect_status="disconnect"
else
connect_status="connect"
fi
echo "${connect_status}"
}
#基本信息
meig_base_info()
{
debug "meig base info"
#Name名称
at_command="AT+CGMM"
name=$(sh ${SCRIPT_DIR}/modem_at.sh $at_port $at_command | grep "+CGMM: " | awk -F': ' '{print $2}' | sed 's/\r//g')
#Manufacturer制造商
at_command="AT+CGMI"
manufacturer=$(sh ${SCRIPT_DIR}/modem_at.sh $at_port $at_command | grep "+CGMI: " | awk -F': ' '{print $2}' | sed 's/\r//g')
#Revision固件版本
at_command="AT+CGMR"
revision=$(sh ${SCRIPT_DIR}/modem_at.sh $at_port $at_command | grep "+CGMR: " | awk -F': ' '{print $2}' | sed 's/\r//g')
#Mode拨号模式
mode=$(meig_get_mode ${at_port} ${platform} | tr 'a-z' 'A-Z')
#Temperature温度
temperature=$(meig_get_temperature ${at_port})
}
#获取SIM卡状态
# $1:SIM卡状态标志
meig_get_sim_status()
{
local sim_status
case $1 in
"") sim_status="miss" ;;
*"ERROR"*) sim_status="miss" ;;
*"READY"*) sim_status="ready" ;;
*"SIM PIN"*) sim_status="MT is waiting SIM PIN to be given" ;;
*"SIM PUK"*) sim_status="MT is waiting SIM PUK to be given" ;;
*"PH-FSIM PIN"*) sim_status="MT is waiting phone-to-SIM card password to be given" ;;
*"PH-FSIM PIN"*) sim_status="MT is waiting phone-to-very first SIM card password to be given" ;;
*"PH-FSIM PUK"*) sim_status="MT is waiting phone-to-very first SIM card unblocking password to be given" ;;
*"SIM PIN2"*) sim_status="MT is waiting SIM PIN2 to be given" ;;
*"SIM PUK2"*) sim_status="MT is waiting SIM PUK2 to be given" ;;
*"PH-NET PIN"*) sim_status="MT is waiting network personalization password to be given" ;;
*"PH-NET PUK"*) sim_status="MT is waiting network personalization unblocking password to be given" ;;
*"PH-NETSUB PIN"*) sim_status="MT is waiting network subset personalization password to be given" ;;
*"PH-NETSUB PUK"*) sim_status="MT is waiting network subset personalization unblocking password to be given" ;;
*"PH-SP PIN"*) sim_status="MT is waiting service provider personalization password to be given" ;;
*"PH-SP PUK"*) sim_status="MT is waiting service provider personalization unblocking password to be given" ;;
*"PH-CORP PIN"*) sim_status="MT is waiting corporate personalization password to be given" ;;
*"PH-CORP PUK"*) sim_status="MT is waiting corporate personalization unblocking password to be given" ;;
*) sim_status="unknown" ;;
esac
echo "${sim_status}"
}
#SIM卡信息
meig_sim_info()
{
debug "meig sim info"
#SIM SlotSIM卡卡槽
at_command="AT^SIMSLOT?"
response=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | grep "\^SIMSLOT:" | awk -F': ' '{print $2}' | awk -F',' '{print $2}')
if [ "$response" != "0" ]; then
sim_slot="1"
else
sim_slot="2"
fi
#IMEI国际移动设备识别码
at_command="AT+CGSN"
imei=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | sed -n '2p' | sed 's/\r//g')
#SIM StatusSIM状态
at_command="AT+CPIN?"
sim_status_flag=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | grep "+CPIN: ")
sim_status=$(meig_get_sim_status "$sim_status_flag")
if [ "$sim_status" != "ready" ]; then
return
fi
#ISP互联网服务提供商
at_command="AT+COPS?"
isp=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | grep "+COPS" | awk -F'"' '{print $2}')
# if [ "$isp" = "CHN-CMCC" ] || [ "$isp" = "CMCC" ]|| [ "$isp" = "46000" ]; then
# isp="中国移动"
# elif [ "$isp" = "CHN-UNICOM" ] || [ "$isp" = "UNICOM" ] || [ "$isp" = "46001" ]; then
# isp="中国联通"
# elif [ "$isp" = "CHN-CT" ] || [ "$isp" = "CT" ] || [ "$isp" = "46011" ]; then
# isp="中国电信"
# fi
#SIM NumberSIM卡号码手机号
at_command="AT+CNUM"
sim_number=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | grep "+CNUM: " | awk -F'"' '{print $2}')
[ -z "$sim_number" ] && {
sim_number=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | grep "+CNUM: " | awk -F'"' '{print $4}')
}
#IMSI国际移动用户识别码
at_command="AT+CIMI"
imsi=$(sh ${SCRIPT_DIR}/modem_at.sh $at_port $at_command | sed -n '2p' | sed 's/\r//g')
#ICCID集成电路卡识别码
at_command="AT+ICCID"
iccid=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | grep -o "+ICCID:[ ]*[-0-9]\+" | grep -o "[-0-9]\{1,4\}")
}
#获取网络类型
# $1:网络类型数字
meig_get_rat()
{
local rat
case $1 in
"0"|"1"|"3"|"8") rat="GSM" ;;
"2"|"4"|"5"|"6"|"9"|"10") rat="WCDMA" ;;
"7") rat="LTE" ;;
"11"|"12") rat="NR" ;;
esac
echo "${rat}"
}
#获取信号强度指示4G
# $1:信号强度指示数字
meig_get_rssi()
{
local rssi
case $1 in
"99") rssi="unknown" ;;
* ) rssi=$((2 * $1 - 113)) ;;
esac
echo "$rssi"
}
#获取4G签约速率
# $1:AT响应
# $2:上行或下行标志
meig_get_lte_ambr()
{
local response="$1"
local flag="$2"
local ambr
case $flag in
"ul")
#使用awk拆分字符串
ambr=$(echo "$response" | awk -F',' '{
#使用split()函数将字符串拆分为数组
n = split($0, arr, ",")
#循环遍历每个值
for (i = 1; i <= n-2; i=i+2)
{
if (arr[i] != "0") {
tmp = arr[i]
}
else {
break
}
}
print tmp
}')
;;
"dl")
#使用awk拆分字符串
ambr=$(echo "$response" | awk -F',' '{
#使用split()函数将字符串拆分为数组
n = split($0, arr, ",")
#循环遍历每个值
for (i = 2; i <= n-2; i=i+2)
{
if (arr[i] != "0") {
tmp = arr[i]
}
else {
break
}
}
print tmp
}')
;;
* )
#使用awk拆分字符串
ambr=$(echo "$response" | awk -F',' '{
#使用split()函数将字符串拆分为数组
n = split($0, arr, ",")
#循环遍历每个值
for (i = 2; i <= n-2; i=i+2)
{
if (arr[i] != "0") {
tmp = arr[i]
}
else {
break
}
}
print tmp
}')
;;
esac
echo "$ambr"
}
#网络信息
meig_network_info()
{
debug "meig network info"
#Connect Status连接状态
connect_status=$(meig_get_connect_status ${at_port} ${define_connect})
if [ "$connect_status" != "connect" ]; then
return
fi
#Network Type网络类型
at_command="AT^SYSINFOEX"
network_type=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | grep "\^SYSINFOEX:" | awk -F'"' '{print $4}')
[ -z "$network_type" ] && {
at_command='AT+COPS?'
local rat_num=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | grep "+COPS:" | awk -F',' '{print $4}' | sed 's/\r//g')
network_type=$(meig_get_rat ${rat_num})
}
#设置网络类型为5G时信号强度指示用RSRP代替
# at_command="AT+GTCSQNREN=1"
# sh ${SCRIPT_DIR}/modem_at.sh $at_port $at_command
#CSQ信号强度
at_command="AT+CSQ"
response=$(sh ${SCRIPT_DIR}/modem_at.sh $at_port $at_command | grep "+CSQ:" | sed 's/+CSQ: //g' | sed 's/\r//g')
#RSSI4G信号强度指示
# rssi_num=$(echo $response | awk -F',' '{print $1}')
# rssi=$(meig_get_rssi $rssi_num)
#BER4G信道误码率
# ber=$(echo $response | awk -F',' '{print $2}')
# #PER信号强度
# if [ -n "$csq" ]; then
# per=$(($csq * 100/31))"%"
# fi
#最大比特率,信道质量指示
at_command="AT^DSAMBR=${define_connect}"
response=$(sh ${SCRIPT_DIR}/modem_at.sh $at_port $at_command | grep "\^DSAMBR:" | awk -F': ' '{print $2}')
at_command='AT+COPS?'
local rat_num=$(sh ${SCRIPT_DIR}/modem_at.sh ${at_port} ${at_command} | grep "+COPS:" | awk -F',' '{print $4}' | sed 's/\r//g')
local network_type_tmp=$(meig_get_rat ${rat_num})
case $network_type_tmp in
"LTE")
ambr_ul_tmp=$(meig_get_lte_ambr ${response} "ul")
ambr_dl_tmp=$(meig_get_lte_ambr ${response} "dl")
;;
"NR")
ambr_ul_tmp=$(echo "$response" | awk -F',' '{print $9}')
ambr_dl_tmp=$(echo "$response" | awk -F',' '{print $10}' | sed 's/\r//g')
;;
*)
ambr_ul_tmp=$(meig_get_lte_ambr ${response} "ul")
ambr_dl_tmp=$(meig_get_lte_ambr ${response} "dl")
;;
esac
#AMBR UL上行签约速率单位Mbps
ambr_ul=$(awk "BEGIN{ printf \"%.2f\", $ambr_ul_tmp / 1024 }" | sed 's/\.*0*$//')
#AMBR DL下行签约速率单位Mbps
ambr_dl=$(awk "BEGIN{ printf \"%.2f\", $ambr_dl_tmp / 1024 }" | sed 's/\.*0*$//')
# #速率统计
# at_command='AT^DSFLOWQRY'
# response=$(sh ${SCRIPT_DIR}/modem_at.sh $at_port $at_command | grep "\^DSFLOWRPT:" | sed 's/\^DSFLOWRPT: //g' | sed 's/\r//g')
# #当前上传速率单位Byte/s
# tx_rate=$(echo $response | awk -F',' '{print $1}')
# #当前下载速率单位Byte/s
# rx_rate=$(echo $response | awk -F',' '{print $2}')
}
#获取频段
# $1:网络类型
# $2:频段数字
meig_get_band()
{
local band
case $1 in
"WCDMA") band="$2" ;;
"LTE") band="$2" ;;
"NR") band="$2" ;;
esac
echo "$band"
}
#获取带宽
# $1:网络类型
# $2:带宽数字
meig_get_bandwidth()
{
local network_type="$1"
local bandwidth_num="$2"
local bandwidth
case $network_type in
"LTE") bandwidth=$(( $bandwidth_num / 5 )) ;;
"NR") bandwidth="$bandwidth_num" ;;
esac
echo "$bandwidth"
}
#获取参考信号接收功率
# $1:网络类型
# $2:参考信号接收功率数字
meig_get_rsrp()
{
local rsrp
case $1 in
"LTE") rsrp=$(($2-141)) ;;
"NR") rsrp=$(($2-157)) ;;
esac
echo "$rsrp"
}
#获取参考信号接收质量
# $1:网络类型
# $2:参考信号接收质量数字
meig_get_rsrq()
{
local rsrq
case $1 in
"LTE") rsrq=$(awk "BEGIN{ printf \"%.2f\", $2 * 0.5 - 20 }" | sed 's/\.*0*$//') ;;
"NR") rsrq=$(awk -v num="$2" "BEGIN{ printf \"%.2f\", (num+1) * 0.5 - 44 }" | sed 's/\.*0*$//') ;;
esac
echo "$rsrq"
}
#获取信噪比
# $1:信噪比数字
meig_get_sinr()
{
local sinr=$(awk "BEGIN{ printf \"%.2f\", $1 / 10 }" | sed 's/\.*0*$//')
echo "$sinr"
}
#小区信息
meig_cell_info()
{
debug "Meig cell info"
at_command="AT^CELLINFO=${define_connect}"
response=$(sh ${SCRIPT_DIR}/modem_at.sh $at_port $at_command | grep "\^CELLINFO:" | sed 's/\^CELLINFO://')
local rat=$(echo "$response" | awk -F',' '{print $1}')
case $rat in
"5G")
network_mode="NR5G-SA Mode"
nr_duplex_mode=$(echo "$response" | awk -F',' '{print $2}')
nr_mcc=$(echo "$response" | awk -F',' '{print $3}')
nr_mnc=$(echo "$response" | awk -F',' '{print $4}')
nr_cell_id=$(echo "$response" | awk -F',' '{print $5}')
nr_physical_cell_id=$(echo "$response" | awk -F',' '{print $6}')
nr_tac=$(echo "$response" | awk -F',' '{print $7}')
nr_band_num=$(echo "$response" | awk -F',' '{print $8}')
nr_band=$(meig_get_band "NR" ${nr_band_num})
nr_dl_bandwidth_num=$(echo "$response" | awk -F',' '{print $9}')
nr_dl_bandwidth=$(meig_get_bandwidth "NR" ${nr_dl_bandwidth_num})
nr_scs=$(echo "$response" | awk -F',' '{print $10}')
nr_fr_type=$(echo "$response" | awk -F',' '{print $11}')
nr_dl_channel=$(echo "$response" | awk -F',' '{print $12}')
nr_ul_channel=$(echo "$response" | awk -F',' '{print $13}')
nr_rssi=$(echo "$response" | awk -F',' '{print $14}')
nr_rsrp=$(echo "$response" | awk -F',' '{print $15}')
nr_rsrq=$(echo "$response" | awk -F',' '{print $16}')
nr_sinr_num=$(echo "$response" | awk -F',' '{print $17}')
nr_sinr=$(meig_get_sinr ${nr_sinr_num})
nr_vonr=$(echo "$response" | awk -F',' '{print $18}' | sed 's/\r//g')
;;
"LTE-NR")
network_mode="EN-DC Mode"
#LTE
endc_lte_duplex_mode=$(echo "$response" | awk -F',' '{print $2}')
endc_lte_mcc=$(echo "$response" | awk -F',' '{print $3}')
endc_lte_mnc=$(echo "$response" | awk -F',' '{print $4}')
endc_lte_global_cell_id=$(echo "$response" | awk -F',' '{print $5}')
endc_lte_physical_cell_id=$(echo "$response" | awk -F',' '{print $6}')
# endc_lte_eNBID=$(echo "$response" | awk -F',' '{print $7}')
endc_lte_cell_id=$(echo "$response" | awk -F',' '{print $8}')
endc_lte_tac=$(echo "$response" | awk -F',' '{print $9}')
endc_lte_band_num=$(echo "$response" | awk -F',' '{print $10}')
endc_lte_band=$(meig_get_band "LTE" ${endc_lte_band_num})
ul_bandwidth_num=$(echo "$response" | awk -F',' '{print $11}')
endc_lte_ul_bandwidth=$(meig_get_bandwidth "LTE" ${ul_bandwidth_num})
endc_lte_dl_bandwidth="$endc_lte_ul_bandwidth"
endc_lte_dl_channel=$(echo "$response" | awk -F',' '{print $12}')
endc_lte_ul_channel=$(echo "$response" | awk -F',' '{print $13}')
endc_lte_rssi=$(echo "$response" | awk -F',' '{print $14}')
endc_lte_rsrp=$(echo "$response" | awk -F',' '{print $15}')
endc_lte_rsrq=$(echo "$response" | awk -F',' '{print $16}')
endc_lte_sinr_num=$(echo "$response" | awk -F',' '{print $17}')
endc_lte_sinr=$(meig_get_sinr ${endc_lte_sinr_num})
endc_lte_rssnr=$(echo "$response" | awk -F',' '{print $18}')
# endc_lte_ue_category=$(echo "$response" | awk -F',' '{print $19}')
# endc_lte_pathloss=$(echo "$response" | awk -F',' '{print $20}')
# endc_lte_cqi=$(echo "$response" | awk -F',' '{print $21}')
endc_lte_tx_power=$(echo "$response" | awk -F',' '{print $22}')
# endc_lte_tm=$(echo "$response" | awk -F',' '{print $23}')
# endc_lte_qci=$(echo "$response" | awk -F',' '{print $24}')
# endc_lte_volte=$(echo "$response" | awk -F',' '{print $25}')
# endc_lte_ims_sms=$(echo "$response" | awk -F',' '{print $26}')
# endc_lte_sib2_plmn_r15_info_present=$(echo "$response" | awk -F',' '{print $27}')
# endc_lte_sib2_upr_layer_ind=$(echo "$response" | awk -F',' '{print $28}')
# endc_lte_restrict_dcnr=$(echo "$response" | awk -F',' '{print $29}')
#NR5G-NSA
endc_nr_mcc=$(echo "$response" | awk -F',' '{print $3}')
endc_nr_mnc=$(echo "$response" | awk -F',' '{print $4}')
endc_nr_global_cell_id=$(echo "$response" | awk -F',' '{print $5}')
endc_nr_physical_cell_id=$(echo "$response" | awk -F',' '{print $6}')
endc_nr_cell_id=$(echo "$response" | awk -F',' '{print $8}')
endc_nr_tac=$(echo "$response" | awk -F',' '{print $9}')
endc_nr_rsrp=$(echo "$response" | awk -F',' '{print $30}')
endc_nr_rsrq=$(echo "$response" | awk -F',' '{print $31}')
endc_nr_sinr_num=$(echo "$response" | awk -F',' '{print $32}')
endc_nr_sinr=$(meig_get_sinr ${endc_nr_sinr_num})
endc_nr_band_num=$(echo "$response" | awk -F',' '{print $33}')
endc_nr_band=$(meig_get_band "NR" ${endc_nr_band_num})
endc_nr_freq=$(echo "$response" | awk -F',' '{print $34}')
nr_dl_bandwidth_num=$(echo "$response" | awk -F',' '{print $35}')
endc_nr_dl_bandwidth=$(meig_get_bandwidth "NR" ${nr_dl_bandwidth_num})
# endc_nr_pci=$(echo "$response" | awk -F',' '{print $36}')
endc_nr_scs=$(echo "$response" | awk -F',' '{print $37}' | sed 's/\r//g')
;;
"LTE"|"eMTC"|"NB-IoT")
network_mode="LTE Mode"
lte_duplex_mode=$(echo "$response" | awk -F',' '{print $2}')
lte_mcc=$(echo "$response" | awk -F',' '{print $3}')
lte_mnc=$(echo "$response" | awk -F',' '{print $4}')
lte_global_cell_id=$(echo "$response" | awk -F',' '{print $5}')
lte_physical_cell_id=$(echo "$response" | awk -F',' '{print $6}')
lte_eNBID=$(echo "$response" | awk -F',' '{print $7}')
lte_cell_id=$(echo "$response" | awk -F',' '{print $8}')
let_tac=$(echo "$response" | awk -F',' '{print $9}')
# lte_earfcn=$(echo "$response" | awk -F',' '{print $7}')
lte_band_num=$(echo "$response" | awk -F',' '{print $10}')
lte_band=$(meig_get_band "LTE" ${lte_band_num})
ul_bandwidth_num=$(echo "$response" | awk -F',' '{print $11}')
lte_ul_bandwidth=$(meig_get_bandwidth "LTE" ${ul_bandwidth_num})
lte_dl_bandwidth="$lte_ul_bandwidth"
lte_dl_channel=$(echo "$response" | awk -F',' '{print $12}')
lte_ul_channel=$(echo "$response" | awk -F',' '{print $13}')
lte_rssi=$(echo "$response" | awk -F',' '{print $14}')
lte_rsrp=$(echo "$response" | awk -F',' '{print $15}')
lte_rsrq=$(echo "$response" | awk -F',' '{print $16}')
lte_sinr_num=$(echo "$response" | awk -F',' '{print $17}')
lte_sinr=$(meig_get_sinr ${lte_sinr_num})
lte_rssnr=$(echo "$response" | awk -F',' '{print $18}')
# lte_ue_category=$(echo "$response" | awk -F',' '{print $19}')
# lte_pathloss=$(echo "$response" | awk -F',' '{print $20}')
# lte_cqi=$(echo "$response" | awk -F',' '{print $21}')
lte_tx_power=$(echo "$response" | awk -F',' '{print $22}')
# lte_tm=$(echo "$response" | awk -F',' '{print $23}')
# lte_qci=$(echo "$response" | awk -F',' '{print $24}')
# lte_volte=$(echo "$response" | awk -F',' '{print $25}')
# lte_ims_sms=$(echo "$response" | awk -F',' '{print $26}')
# lte_sib2_plmn_r15_info_present=$(echo "$response" | awk -F',' '{print $27}')
# lte_sib2_upr_layer_ind=$(echo "$response" | awk -F',' '{print $28}')
# lte_restrict_dcnr=$(echo "$response" | awk -F',' '{print $29}' | sed 's/\r//g')
;;
"WCDMA"|"UMTS")
network_mode="WCDMA Mode"
wcdma_mcc=$(echo "$response" | awk -F',' '{print $2}')
wcdma_mnc=$(echo "$response" | awk -F',' '{print $3}')
wcdma_global_cell_id=$(echo "$response" | awk -F',' '{print $4}')
wcdma_psc=$(echo "$response" | awk -F',' '{print $5}')
wcdma_NodeB=$(echo "$response" | awk -F',' '{print $6}')
wcdma_cell_id=$(echo "$response" | awk -F',' '{print $7}')
wcdma_lac=$(echo "$response" | awk -F',' '{print $8}')
wcdma_band_num=$(echo "$response" | awk -F',' '{print $9}')
wcdma_band=$(meig_get_band "WCDMA" ${wcdma_band_num})
wcdma_dl_channel=$(echo "$response" | awk -F',' '{print $10}')
wcdma_ul_channel=$(echo "$response" | awk -F',' '{print $11}')
wcdma_rssi=$(echo "$response" | awk -F',' '{print $12}')
wcdma_ecio=$(echo "$response" | awk -F',' '{print $13}')
# wcdma_sir=$(echo "$response" | awk -F',' '{print $14}')
wcdma_rscp=$(echo "$response" | awk -F',' '{print $15}' | sed 's/\r//g')
;;
"GSM")
network_mode="GSM Mode"
gsm_mcc=$(echo "$response" | awk -F',' '{print $3}')
gsm_mnc=$(echo "$response" | awk -F',' '{print $4}')
;;
esac
}
#获取美格模组信息
# $1:AT串口
# $2:平台
# $3:连接定义
get_meig_info()
{
debug "get meig info"
#设置AT串口
at_port="$1"
platform="$2"
define_connect="$3"
#基本信息
meig_base_info
#SIM卡信息
meig_sim_info
if [ "$sim_status" != "ready" ]; then
return
fi
#网络信息
meig_network_info
if [ "$connect_status" != "connect" ]; then
return
fi
#小区信息
meig_cell_info
}

View File

@ -1,11 +0,0 @@
#!/bin/sh
# Copyright (C) 2023 Siriling <siriling@qq.com>
#脚本目录
SCRIPT_DIR="/usr/share/modem"
source "${SCRIPT_DIR}/modem_debug.sh"
#发送at命令
# $1 AT串口
# $2 AT命令
at "$1" "$2"

View File

@ -0,0 +1,171 @@
#!/bin/sh
source /usr/share/libubox/jshn.sh
method=$1
config_section=$2
at_port=$(uci get modem.$config_section.at_port)
vendor=$(uci get modem.$config_section.manufacturer)
platform=$(uci get modem.$config_section.platform)
define_connect=$(uci get modem.$config_section.define_connect)
[ -z "$define_connect" ] && {
define_connect="1"
}
case $vendor in
"quectel")
. /usr/share/modem/quectel.sh
;;
"fibocom")
. /usr/share/modem/fibocom.sh
;;
*)
. /usr/share/modem/generic.sh
;;
esac
try_cache() {
cache_timeout=$1
cache_file=$2
function_name=$3
current_time=$(date +%s)
file_time=$(stat -t $cache_file | awk '{print $14}')
if [ ! -f $cache_file ] || [ $(($current_time - $file_time)) -gt $cache_timeout ]; then
touch $cache_file
json_add_array modem_info
$function_name
json_close_array
json_dump > $cache_file
return 1
else
cat $cache_file
exit 0
fi
}
get_sms(){
cache_timeout=$1
cache_file=$2
current_time=$(date +%s)
file_time=$(stat -t $cache_file | awk '{print $14}')
if [ ! -f $cache_file ] || [ $(($current_time - $file_time)) -gt $cache_timeout ]; then
touch $cache_file
sms_tool -d $at_port -j recv > $cache_file
cat $cache_file
else
cat $cache_file
fi
}
#会初始化一个json对象 命令执行结果会保存在json对象中
json_init
json_add_object result
json_close_object
case $method in
"clear_dial_log")
json_select result
log_file="/var/run/modem/${config_section}_dir/dial_log"
[ -f $log_file ] && echo "" > $log_file && json_add_string status "1" || json_add_string status "0"
json_close_object
;;
"get_dns")
get_dns
;;
"get_imei")
get_imei
;;
"set_imei")
set_imei $3
;;
"get_mode")
get_mode
;;
"set_mode")
set_mode $3
;;
"get_network_prefer")
get_network_prefer
;;
"set_network_prefer")
set_network_prefer $3
;;
"get_lockband")
get_lockband
;;
"set_lockband")
set_lockband $3
;;
"get_neighborcell")
get_neighborcell
;;
"set_neighborcell")
set_neighborcell $3
;;
"base_info")
cache_file="/tmp/cache_$1_$2"
try_cache 10 $cache_file base_info
;;
"sim_info")
cache_file="/tmp/cache_$1_$2"
try_cache 10 $cache_file sim_info
;;
"cell_info")
cache_file="/tmp/cache_$1_$2"
try_cache 10 $cache_file cell_info
;;
"network_info")
cache_file="/tmp/cache_$1_$2"
try_cache 10 $cache_file network_info
;;
"info")
cache_file="/tmp/cache_$1_$2"
try_cache 10 $cache_file get_info
;;
"get_sms")
get_sms 10 /tmp/cache_sms_$2
exit
;;
"send_sms")
cmd_json=$3
phone_number=$(echo $cmd_json | jq -r '.phone_number')
message_content=$(echo $cmd_json | jq -r '.message_content')
sms_tool -d $at_port send "$phone_number" "$message_content" > /dev/null
json_select result
if [ "$?" == 0 ]; then
json_add_string status "1"
json_add_string cmd "sms_tool -d $at_port send \"$phone_number\" \"$message_content\""
json_add_string "cmd_json" "$cmd_json"
else
json_add_string status "0"
fi
json_close_object
;;
"send_raw_pdu")
cmd=$3
res=$(sms_tool -d $at_port send_raw_pdu "$cmd" )
json_select result
if [ "$?" == 0 ]; then
json_add_string status "1"
json_add_string cmd "sms_tool -d $at_port send_raw_pdu \"$cmd\""
json_add_string "res" "$res"
else
json_add_string status "0"
fi
;;
"delete_sms")
json_select result
index=$3
for i in $index; do
sms_tool -d $at_port delete $i > /dev/null
touch /tmp/cache_sms_$2
if [ "$?" == 0 ]; then
json_add_string status "1"
json_add_string "index$i" "sms_tool -d $at_port delete $i"
else
json_add_string status "0"
fi
done
json_close_object
rm -rf /tmp/cache_sms_$2
;;
esac
json_dump

View File

@ -1,77 +0,0 @@
#!/bin/sh
# Copyright (C) 2023 Siriling <siriling@qq.com>
#脚本目录
SCRIPT_DIR="/usr/share/modem"
source "${SCRIPT_DIR}/quectel.sh"
source "${SCRIPT_DIR}/fibocom.sh"
source "${SCRIPT_DIR}/meig.sh"
# source "${SCRIPT_DIR}/simcom.sh"
#调试开关
# 0关闭
# 1打开
# 2输出到文件
switch=0
out_file="/tmp/modem.log" #输出文件
#日志信息
debug()
{
time=$(date "+%Y-%m-%d %H:%M:%S") #获取系统时间
if [ $switch = 1 ]; then
echo $time $1 #打印输出
elif [ $switch = 2 ]; then
echo $time $1 >> $outfile #输出到文件
fi
}
#发送at命令
# $1 AT串口
# $2 AT命令
at()
{
local at_port="$1"
local new_str="${2/[$]/$}"
local at_command="${new_str/\"/\"}"
#echo
# echo -e "${at_command}"" > "${at_port}" 2>&1
#sms_tool
sms_tool -d "${at_port}" at "${at_command}" 2>&1
}
#测试时打开
# debug $1
# at $1 $2
#获取快捷命令
# $1:快捷选项
# $2:制造商
get_quick_commands()
{
local quick_option="$1"
local manufacturer="$2"
local quick_commands
case "$quick_option" in
"auto") quick_commands=$(cat ${SCRIPT_DIR}/${manufacturer}_at_commands.json) ;;
"custom") quick_commands=$(cat /etc/modem/custom_at_commands.json) ;;
*) quick_commands=$(cat ${SCRIPT_DIR}/${manufacturer}_at_commands.json) ;;
esac
echo "$quick_commands"
}
#拨号日志
# $1:log mesg
# $2:日志路径
dial_log()
{
local logmsg="$1"
local path="$2"
#打印日志
local update_time=$(date +"%Y-%m-%d %H:%M:%S")
echo "[${update_time}] ${logmsg} " >> "${path}"
}

View File

@ -2,10 +2,47 @@
source /lib/functions.sh
#运行目录
MODEM_RUNDIR="/var/run/modem"
#脚本目录
SCRIPT_DIR="/usr/share/modem"
#导入组件工具
source "${SCRIPT_DIR}/modem_debug.sh"
modem_config=$1
mkdir -p "${MODEM_RUNDIR}/${modem_config}_dir"
log_file="${MODEM_RUNDIR}/${modem_config}_dir/dial_log"
debug_subject="modem_dial"
source "${SCRIPT_DIR}/generic.sh"
touch $log_file
set_led()
{
local type=$1
local modem_config=$2
local value=$3
case $data_interface in
usb)
config_get sim_led u$modem_config sim_led
config_get net_led u$modem_config net_led
;;
pcie)
config_get sim_led p$modem_config sim_led
config_get net_led p$modem_config net_led
;;
*)
#usb
config_get sim_led u$modem_config sim_led
config_get net_led u$modem_config net_led
;;
esac
case $type in
sim)
echo $value > /sys/class/leds/$sim_led/brightness
;;
net)
uci set system.led_${net_led}.dev=$value
uci commit system
/etc/init.d/led restart
;;
esac
}
get_driver()
{
for i in $(find $modem_path -name driver);do
@ -44,29 +81,125 @@ get_driver()
done
echo $mode
}
config_load modem
modem_config=$1
log_path="${MODEM_RUNDIR}/${modem_config}_dial.cache"
config_get apn $modem_config apn
config_get modem_path $modem_config path
config_get modem_dial $modem_config enable_dial
config_get dial_tool $modem_config dial_tool
config_get pdp_type $modem_config pdp_type
config_get network_bridge $modem_config network_bridge
config_get apn $modem_config apn
config_get username $modem_config username
config_get password $modem_config password
config_get auth $modem_config auth
config_get at_port $modem_config at_port
config_get manufacturer $modem_config manufacturer
config_get platform $modem_config platform
config_get define_connect $modem_config define_connect
modem_netcard=$(ls $(find $modem_path -name net |tail -1) | awk -F'/' '{print $NF}')
interface_name=wwan_5g_$(echo $modem_config | grep -oE "[0-9]+")
interface6_name=wwan6_5g_$(echo $modem_config | grep -oE "[0-9]+")
ethernet_5g=$(uci -q get modem.global.ethernet)
driver=$(get_driver)
dial_log "modem_path=$modem_path,driver=$driver,interface=$interface_name,at_port=$at_port" "$log_path"
unlock_sim()
{
pin=$1
sim_lock_file="/var/run/modem/${modem_config}_dir/pincode"
lock ${sim_lock_file}.lock
if [ -f $sim_lock_file ] && [ "$pin" == "$(cat $sim_lock_file)"];then
m_debug "pin code is already try"
else
res=$(at "$at_port" "AT+CPIN=\"$pin\"")
case "$?" in
0)
m_debug "unlock sim card with pin code $pin success"
;;
*)
echo $pin > $sim_lock_file
m_debug "info" "unlock sim card with pin code $pin failed,block try until nextboot"
;;
esac
fi
lock -u ${sim_lock_file}.lock
}
update_config()
{
config_load modem
config_get state $modem_config state
config_get enable_dial $modem_config enable_dial
config_get modem_path $modem_config path
config_get dial_tool $modem_config dial_tool
config_get pdp_type $modem_config pdp_type
config_get network_bridge $modem_config network_bridge
config_get metric $modem_config metric
config_get at_port $modem_config at_port
config_get manufacturer $modem_config manufacturer
config_get platform $modem_config platform
config_get define_connect $modem_config define_connect
config_get ra_master $modem_config ra_master
config_get global_dial global enable_dial
config_get ethernet_5g u$modem_config ethernet
driver=$(get_driver)
update_sim_slot
case $sim_slot in
1)
config_get apn $modem_config apn
config_get username $modem_config username
config_get password $modem_config password
config_get auth $modem_config auth
config_get pincode $modem_config pincode
;;
2)
config_get apn $modem_config apn2
config_get username $modem_config username2
config_get password $modem_config password2
config_get auth $modem_config auth2
config_get pincode $modem_config pincode2
[ -z "$apn" ] && config_get apn $modem_config apn
[ -z "$username" ] && config_get username $modem_config username
[ -z "$password" ] && config_get password $modem_config password
[ -z "$auth" ] && config_get auth $modem_config auth
[ -z "$pin" ] && config_get pincode $modem_config pincode
;;
*)
config_get apn $modem_config apn
config_get username $modem_config username
config_get password $modem_config password
config_get auth $modem_config auth
config_get pincode $modem_config pincode
;;
esac
modem_net=$(find $modem_path -name net |tail -1)
modem_netcard=$(ls $modem_net)
interface_name=$modem_config
interface6_name=${modem_config}v6
}
check_dial_prepare()
{
cpin=$(at "$at_port" "AT+CPIN?")
get_sim_status "$cpin"
case $sim_state_code in
"0")
m_debug "info sim card is miss"
;;
"1")
m_debug "info sim card is ready"
sim_fullfill=1
;;
"2")
m_debug "pin code required"
[ -n "$pincode" ] && unlock_sim $pincode
;;
*)
m_debug "info sim card state is $sim_state_code"
;;
esac
if [ "$sim_fullfill" = "1" ];then
set_led "sim" $modem_config 255
else
set_led "sim" $modem_config 0
fi
if [ -n "$modem_netcard" ] && [ -d "/sys/class/net/$modem_netcard" ];then
netdev_fullfill=1
else
netdev_fullfill=0
fi
if [ "$enable_dial" = "1" ] && [ "$sim_fullfill" = "1" ] && [ "$state" != "disabled" ] ;then
config_fullfill=1
fi
if [ "$config_fullfill" = "1" ] && [ "$sim_fullfill" = "1" ] && [ "$netdev_fullfill" = "1" ] ;then
return 1
else
return 0
fi
}
check_ip()
{
@ -126,10 +259,9 @@ check_ip()
if [ -n "$ipv4" ] && [ -n "$ipv6" ];then
connection_status=3
fi
dial_log "current ip [$ipv6],[$ipv4],connection_status=$connection_status" "$log_path"
else
connection_status="-1"
dial_log "at port response unexpected $ipaddr" "$log_path"
m_debug "at port response unexpected $ipaddr"
fi
}
@ -142,7 +274,7 @@ set_if()
uci set network.${interface_name}.proto='dhcp'
uci set network.${interface_name}.defaultroute='1'
uci set network.${interface_name}.peerdns='0'
uci set network.${interface_name}.metric='10'
uci set network.${interface_name}.metric="${metric}"
uci add_list network.${interface_name}.dns='114.114.114.114'
uci add_list network.${interface_name}.dns='119.29.29.29'
local num=$(uci show firewall | grep "name='wan'" | wc -l)
@ -150,7 +282,6 @@ set_if()
if [ "$wwan_num" = "0" ]; then
uci add_list firewall.@zone[$num].network="${interface_name}"
fi
#set ipv6
#if pdptype contain 6
if [ -n "$(echo $pdp_type | grep "6")" ];then
@ -159,44 +290,53 @@ set_if()
uci set network.lan.ip6class="${interface6_name}"
uci set network.${interface6_name}='interface'
uci set network.${interface6_name}.proto='dhcpv6'
uci set network.${interface6_name}.extendprefix='1'
uci set network.${interface6_name}.ifname="@${interface_name}"
uci set network.${interface6_name}.device="@${interface_name}"
uci set network.${interface6_name}.metric='10'
uci set network.${interface6_name}.metric="${metric}"
if [ "$ra_master" = "1" ];then
uci set dhcp.${interface6_name}='dhcp'
uci set dhcp.${interface6_name}.interface="${interface6_name}"
uci set dhcp.${interface6_name}.ra='relay'
uci set dhcp.${interface6_name}.ndp='relay'
uci set dhcp.${interface6_name}.master='1'
uci set dhcp.${interface6_name}.ignore='1'
uci set dhcp.lan.ra='relay'
uci set dhcp.lan.ndp='relay'
uci set dhcp.lan.dhcpv6='relay'
uci commit dhcp
fi
local wwan6_num=$(uci -q get firewall.@zone[$num].network | grep -w "${interface6_name}" | wc -l)
if [ "$wwan6_num" = "0" ]; then
uci add_list firewall.@zone[$num].network="${interface6_name}"
fi
fi
uci commit network
uci commit firewall
ifup ${interface_name}
dial_log "create interface $interface_name" "$log_path"
m_debug "create interface $interface_name"
fi
set_modem_netcard=$modem_netcard
if [ -z "$set_modem_netcard" ];then
dial_log "no netcard found" "$log_path"
m_debug "no netcard found"
fi
ethernet_check=$(handle_5gethernet)
if [ -n "$ethernet_check" ];then
if [ -n "$ethernet_check" ] && [ -n "/sys/class/net/$ethernet_5g" ] && [ -n "$ethernet_5g" ];then
set_modem_netcard=$ethernet_5g
fi
#set led
set_led "net" $modem_config $set_modem_netcard
origin_netcard=$(uci -q get network.$interface_name.ifname)
origin_device=$(uci -q get network.$interface_name.device)
if [ "$origin_netcard" == "$set_modem_netcard" ] && [ "$origin_device" == "$set_modem_netcard" ];then
dial_log "interface $interface_name already set to $set_modem_netcard" "$log_path"
m_debug "interface $interface_name already set to $set_modem_netcard"
else
uci set network.${interface_name}.ifname="${set_modem_netcard}"
uci set network.${interface_name}.device="${set_modem_netcard}"
uci commit network
ifup ${interface_name}
dial_log "set interface $interface_name to $modem_netcard" "$log_path"
m_debug "set interface $interface_name to $set_modem_netcard"
fi
}
@ -204,14 +344,26 @@ flush_if()
{
uci delete network.${interface_name}
uci delete network.${interface6_name}
uci delete dhcp.${interface6_name}
uci commit network
dial_log "delete interface $interface_name" "$log_path"
uci commit dhcp
set_led "net" $modem_config
set_led "sim" $modem_config 0
m_debug "delete interface $interface_name"
}
dial(){
update_config
m_debug "modem_path=$modem_path,driver=$driver,interface=$interface_name,at_port=$at_port,using_sim_slot:$sim_slot"
while [ "$dial_prepare" != 1 ] ; do
sleep 5
update_config
check_dial_prepare
dial_prepare=$?
done
set_if
dial_log "dialing $modem_path driver $driver" "$log_path"
m_debug "dialing $modem_path driver $driver"
case $driver in
"qmi")
qmi_dial
@ -234,7 +386,14 @@ dial(){
esac
}
hang()
wwan_hang()
{
#kill quectel-CM
killall quectel-CM
}
ecm_hang()
{
if [ "$manufacturer" = "quectel" ]; then
at_command="AT+QNETDEVCTL=1,2,1"
@ -252,6 +411,29 @@ hang()
fi
tmp=$(at "${at_port}" "${at_command}")
}
hang()
{
m_debug "hang up $modem_path driver $driver"
case $driver in
"ncm")
ecm_hang
;;
"ecm")
ecm_hang
;;
"rndis")
ecm_hang
;;
"qmi")
wwan_hang
;;
"mbim")
wwan_hang
;;
esac
flush_if
}
@ -269,7 +451,7 @@ qmi_dial()
cmd_line="quectel-CM"
case $pdp_type in
"ipv4") cmd_line="$cmd_line -4" ;;
"ip") cmd_line="$cmd_line -4" ;;
"ipv6") cmd_line="$cmd_line -6" ;;
"ipv4v6") cmd_line="$cmd_line -4 -6" ;;
*) cmd_line="$cmd_line -4 -6" ;;
@ -293,8 +475,8 @@ qmi_dial()
if [ -n "$modem_netcard" ]; then
cmd_line="$cmd_line -i $modem_netcard"
fi
dial_log "dialing $cmd_line" "$log_path"
cmd_line="$cmd_line -f $log_path"
cmd_line="$cmd_line -f $log_file"
$cmd_line
@ -306,7 +488,7 @@ at_dial()
apn="auto"
fi
if [ -z "$pdp_type" ];then
pdp_type="IPV4V6"
pdp_type="IP"
fi
local at_command='AT+COPS=0,0'
tmp=$(at "${at_port}" "${at_command}")
@ -359,15 +541,14 @@ at_dial()
;;
esac
dial_log "dialing vendor:$manufacturer;platform:$platform; $cgdcont_command" "$log_path"
dial_log "dialing vendor:$manufacturer;platform:$platform; $at_command" "$log_path"
m_debug "dialing vendor:$manufacturer;platform:$platform; $cgdcont_command ; $at_command"
at "${at_port}" "${cgdcont_command}"
at "$at_port" "$at_command"
}
ip_change_fm350()
{
dial_log "ip_change_fm350" "$log_path"
m_debug "ip_change_fm350"
at_command="AT+CGPADDR=3"
local ipv4_config=$(at ${at_port} ${at_command} | cut -d, -f2 | grep -oE '[0-9]+.[0-9]+.[0-9]+.[0-9]+')
local public_dns1_ipv4="223.5.5.5"
@ -407,49 +588,93 @@ ip_change_fm350()
uci commit network
ifdown ${interface_name}
ifup ${interface_name}
dial_log "set interface $interface_name to $ipv4_config" "$log_path"
m_debug "set interface $interface_name to $ipv4_config"
}
handle_5gethernet()
{
case $manufacturer in
"quectel")
case $platform in
"qualcomm")
quectel_qualcomm_ethernet
;;
"unisoc")
quectel_unisoc_ethernet
;;
esac
;;
esac
}
quectel_unisoc_ethernet()
{
case "$driver" in
"ncm"|\
"ecm"|\
"rndis")
case "$manufacturer" in
"quectel")
case "$platform" in
"unisoc")
check_ethernet_cmd="AT+QCFG=\"ethernet\""
time=0
while [ $time -lt 5 ]; do
result=$(sh ${SCRIPT_DIR}/modem_at.sh $at_port $check_ethernet_cmd | grep "+QCFG:")
if [ -n "$result" ]; then
if [ -n "$(echo $result | grep "ethernet\",1")" ]; then
echo "1"
dial_log "5G Ethernet mode is enabled" "$log_path"
break
fi
fi
sleep 5
time=$((time+1))
done
;;
esac
;;
esac
check_ethernet_cmd="AT+QCFG=\"ethernet\""
time=0
while [ $time -lt 5 ]; do
result=$(at $at_port $check_ethernet_cmd | grep "+QCFG:")
if [ -n "$result" ]; then
if [ -n "$(echo $result | grep "ethernet\",1")" ]; then
echo "1"
m_debug "5G Ethernet mode is enabled"
break
fi
fi
sleep 5
time=$((time+1))
done
;;
esac
}
quectel_qualcomm_ethernet()
{
case "$driver" in
"mbim")
eth_driver_at="AT+QETH=\"eth_driver\""
data_interface_at="AT+QCFG=\"data_interface\""
ehter_driver_expect="\"r8125\",1"
data_interface_expect="\"data_interface\",1"
time=0
while [ $time -lt 5 ]; do
eth_driver_result=$(at $at_port $eth_driver_at | grep "+QETH:")
time=$(($time+1))
sleep 1
if [ -n "$eth_driver_result" ];then
break
fi
done
time=0
while [ $time -lt 5 ]; do
data_interface_result=$(at $at_port $data_interface_at | grep "+QCFG:")
time=$(($time+1))
sleep 1
if [ -n "$data_interface_result" ];then
break
fi
done
eth_driver_pass=$(echo $eth_driver_result | grep "$ehter_driver_expect")
data_interface_pass=$(echo $data_interface_result | grep "$data_interface_expect")
if [ -n "$eth_driver_pass" ] && [ -n "$data_interface_pass" ];then
echo "1"
m_debug "5G Ethernet mode is enabled"
fi
;;
esac
}
handle_ip_change()
{
export ipv4
export ipv6
export connection_status
dial_log "ip changed from $ipv6_cache,$ipv4_cache to $ipv6,$ipv4" "$log_path"
m_debug "ip changed from $ipv6_cache,$ipv4_cache to $ipv6,$ipv4"
case $manufacturer in
"fibocom")
case $platform in
@ -463,10 +688,10 @@ handle_ip_change()
check_logfile_line()
{
local line=$(wc -l $log_path | awk '{print $1}')
local line=$(wc -l $log_file | awk '{print $1}')
if [ $line -gt 300 ];then
echo "" > $log_path
dial_log "log file line is over 300,clear it" "$log_path"
echo "" > $log_file
m_debug "log file line is over 300,clear it"
fi
}
@ -487,7 +712,7 @@ at_dial_monitor()
at_dial
unexpected_response_count=0
fi
sleep 5
sleep 10
else
#检测ipv4是否变化
sleep 15
@ -499,12 +724,19 @@ at_dial_monitor()
fi
check_logfile_line
done
}
case $2 in
case "$2" in
"hang")
debug_subject="modem_hang"
update_config
hang;;
"dial")
dial;;
case "$state" in
"disabled")
debug_subject="modem_hang"
hang;;
*)
dial;;
esac
esac

View File

@ -1,407 +0,0 @@
#!/bin/sh
# Copyright (C) 2023 Siriling <siriling@qq.com>
#脚本目录
SCRIPT_DIR="/usr/share/modem"
source "${SCRIPT_DIR}/modem_debug.sh"
#初值化数据结构
init_modem_info()
{
#基本信息
name='unknown' #名称
manufacturer='unknown' #制造商
revision='-' #固件版本
at_port='-' #AT串口
mode='unknown' #拨号模式
temperature="NaN $(printf "\xc2\xb0")C" #温度
update_time='-' #更新时间
#SIM卡信息
sim_status="unknown" #SIM卡状态
sim_slot="-" #SIM卡卡槽
isp="-" #运营商(互联网服务提供商)
sim_number='-' #SIM卡号码手机号
imei='-' #IMEI
imsi='-' #IMSI
iccid='-' #ICCID
#网络信息
connect_status="disconnect" #SIM卡状态
network_type="-" #蜂窝网络类型
cqi_ul="-" #上行信道质量指示
cqi_dl="-" #下行信道质量指示
ambr_ul="-" #上行签约速率
ambr_dl="-" #下行签约速率
tx_rate="-" #上传速率
rx_rate="-" #下载速率
#小区信息
network_mode="-" #网络模式
#NR5G-SA模式
nr_mcc=''
nr_mnc=''
nr_duplex_mode=''
nr_cell_id=''
nr_physical_cell_id=''
nr_tac=''
nr_arfcn=''
nr_band=''
nr_dl_bandwidth=''
nr_rsrp=''
nr_rsrq=''
nr_sinr=''
nr_rxlev=''
nr_scs=''
nr_srxlev=''
#EN-DC模式LTE
endc_lte_mcc=''
endc_lte_mnc=''
endc_lte_duplex_mode=''
endc_lte_cell_id=''
endc_lte_physical_cell_id=''
endc_lte_earfcn=''
endc_lte_freq_band_ind=''
endc_lte_ul_bandwidth=''
endc_lte_dl_bandwidth=''
endc_lte_tac=''
endc_lte_rsrp=''
endc_lte_rsrq=''
endc_lte_rssi=''
endc_lte_sinr=''
endc_lte_rxlev=''
endc_lte_cql=''
endc_lte_tx_power=''
endc_lte_srxlev=''
#EN-DC模式NR5G-NSA
endc_nr_mcc=''
endc_nr_mnc=''
endc_nr_physical_cell_id=''
endc_nr_arfcn=''
endc_nr_band=''
endc_nr_dl_bandwidth=''
endc_nr_rsrp=''
endc_nr_rsrq=''
endc_nr_sinr=''
endc_nr_scs=''
#LTE模式
lte_mcc=''
lte_mnc=''
lte_duplex_mode=''
lte_cell_id=''
lte_physical_cell_id=''
lte_earfcn=''
lte_freq_band_ind=''
lte_ul_bandwidth=''
lte_dl_bandwidth=''
lte_tac=''
lte_rsrp=''
lte_rsrq=''
lte_rssi=''
lte_sinr=''
lte_rxlev=''
lte_cql=''
lte_tx_power=''
lte_srxlev=''
#WCDMA模式
wcdma_mcc=''
wcdma_mnc=''
wcdma_lac=''
wcdma_cell_id=''
wcdma_uarfcn=''
wcdma_psc=''
wcdma_rac=''
wcdma_rscp=''
wcdma_ecio=''
wcdma_phych=''
wcdma_sf=''
wcdma_slot=''
wcdma_speech_code=''
wcdma_com_mod=''
}
#设置基本信息
set_base_info()
{
base_info="\"base_info\":{
\"manufacturer\":\"$manufacturer\",
\"revision\":\"$revision\",
\"at_port\":\"$at_port\",
\"mode\":\"$mode\",
\"temperature\":\"$temperature\",
\"update_time\":\"$update_time\"
},"
}
#设置SIM卡信息
set_sim_info()
{
if [ "$sim_status" = "ready" ]; then
sim_info="\"sim_info\":[
{\"SIM Status\":\"$sim_status\", \"full_name\":\"SIM Status\"},
{\"ISP\":\"$isp\", \"full_name\":\"Internet Service Provider\"},
{\"SIM Slot\":\"$sim_slot\", \"full_name\":\"SIM Slot\"},
{\"SIM Number\":\"$sim_number\", \"full_name\":\"SIM Number\"},
{\"IMEI\":\"$imei\", \"full_name\":\"International Mobile Equipment Identity\"},
{\"IMSI\":\"$imsi\", \"full_name\":\"International Mobile Subscriber Identity\"},
{\"ICCID\":\"$iccid\", \"full_name\":\"Integrate Circuit Card Identity\"}
],"
elif [ "$sim_status" = "miss" ]; then
sim_info="\"sim_info\":[
{\"SIM Status\":\"$sim_status\", \"full_name\":\"SIM Status\"},
{\"IMEI\":\"$imei\", \"full_name\":\"International Mobile Equipment Identity\"}
],"
elif [ "$sim_status" = "unknown" ]; then
sim_info="\"sim_info\":[
{\"SIM Status\":\"$sim_status\", \"full_name\":\"SIM Status\"}
],"
else
sim_info="\"sim_info\":[
{\"SIM Status\":\"$sim_status\", \"full_name\":\"SIM Status\"},
{\"SIM Slot\":\"$sim_slot\", \"full_name\":\"SIM Slot\"},
{\"IMEI\":\"$imei\", \"full_name\":\"International Mobile Equipment Identity\"},
{\"IMSI\":\"$imsi\", \"full_name\":\"International Mobile Subscriber Identity\"},
{\"ICCID\":\"$iccid\", \"full_name\":\"Integrate Circuit Card Identity\"}
],"
fi
}
#设置网络信息
set_network_info()
{
network_info="\"network_info\":[
{\"Network Type\":\"$network_type\", \"full_name\":\"Network Type\"},
{\"CQI UL\":\"$cqi_ul\", \"full_name\":\"Channel Quality Indicator for Uplink\"},
{\"CQI DL\":\"$cqi_dl\", \"full_name\":\"Channel Quality Indicator for Downlink\"},
{\"AMBR UL\":\"$ambr_ul\", \"full_name\":\"Access Maximum Bit Rate for Uplink\"},
{\"AMBR DL\":\"$ambr_dl\", \"full_name\":\"Access Maximum Bit Rate for Downlink\"},
{\"Tx Rate\":\"$tx_rate\", \"full_name\":\"Transmit Rate\"},
{\"Rx Rate\":\"$rx_rate\", \"full_name\":\"Receive Rate\"}
],"
}
#设置信号信息
set_cell_info()
{
if [ "$network_mode" = "NR5G-SA Mode" ]; then
cell_info="\"cell_info\":{
\"NR5G-SA Mode\":[
{\"MCC\":\"$nr_mcc\", \"full_name\":\"Mobile Country Code\"},
{\"MNC\":\"$nr_mnc\", \"full_name\":\"Mobile Network Code\"},
{\"Duplex Mode\":\"$nr_duplex_mode\", \"full_name\":\"Duplex Mode\"},
{\"Cell ID\":\"$nr_cell_id\", \"full_name\":\"Cell ID\"},
{\"Physical Cell ID\":\"$nr_physical_cell_id\", \"full_name\":\"Physical Cell ID\"},
{\"TAC\":\"$nr_tac\", \"full_name\":\"Tracking area code of cell servedby neighbor Enb\"},
{\"ARFCN\":\"$nr_arfcn\", \"full_name\":\"Absolute Radio-Frequency Channel Number\"},
{\"Band\":\"$nr_band\", \"full_name\":\"Band\"},
{\"DL Bandwidth\":\"$nr_dl_bandwidth\", \"full_name\":\"DL Bandwidth\"},
{\"RSRP\":\"$nr_rsrp\", \"full_name\":\"Reference Signal Received Power\"},
{\"RSRQ\":\"$nr_rsrq\", \"full_name\":\"Reference Signal Received Quality\"},
{\"SINR\":\"$nr_sinr\", \"full_name\":\"Signal to Interference plus Noise Ratio Bandwidth\"},
{\"RxLev\":\"$nr_rxlev\", \"full_name\":\"Received Signal Level\"},
{\"SCS\":\"$nr_scs\", \"full_name\":\"SCS\"},
{\"Srxlev\":\"$nr_srxlev\", \"full_name\":\"Serving Cell Receive Level\"}
]
}"
elif [ "$network_mode" = "EN-DC Mode" ]; then
cell_info="\"cell_info\":{
\"EN-DC Mode\":[
{\"LTE\":[
{\"MCC\":\"$endc_lte_mcc\", \"full_name\":\"Mobile Country Code\"},
{\"MNC\":\"$endc_lte_mnc\", \"full_name\":\"Mobile Network Code\"},
{\"Duplex Mode\":\"$endc_lte_duplex_mode\", \"full_name\":\"Duplex Mode\"},
{\"Cell ID\":\"$endc_lte_cell_id\", \"full_name\":\"Cell ID\"},
{\"Physical Cell ID\":\"$endc_lte_physical_cell_id\", \"full_name\":\"Physical Cell ID\"},
{\"EARFCN\":\"$endc_lte_earfcn\", \"full_name\":\"E-UTRA Absolute Radio Frequency Channel Number\"},
{\"Freq band indicator\":\"$endc_lte_freq_band_ind\", \"full_name\":\"Freq band indicator\"},
{\"Band\":\"$endc_lte_band\", \"full_name\":\"Band\"},
{\"UL Bandwidth\":\"$endc_lte_ul_bandwidth\", \"full_name\":\"UL Bandwidth\"},
{\"DL Bandwidth\":\"$endc_lte_dl_bandwidth\", \"full_name\":\"DL Bandwidth\"},
{\"TAC\":\"$endc_lte_tac\", \"full_name\":\"Tracking area code of cell servedby neighbor Enb\"},
{\"RSRP\":\"$endc_lte_rsrp\", \"full_name\":\"Reference Signal Received Power\"},
{\"RSRQ\":\"$endc_lte_rsrq\", \"full_name\":\"Reference Signal Received Quality\"},
{\"RSSI\":\"$endc_lte_rssi\", \"full_name\":\"Received Signal Strength Indicator\"},
{\"SINR\":\"$endc_lte_sinr\", \"full_name\":\"Signal to Interference plus Noise Ratio Bandwidth\"},
{\"RxLev\":\"$endc_lte_rxlev\", \"full_name\":\"Received Signal Level\"},
{\"RSSNR\":\"$endc_lte_rssnr\", \"full_name\":\"Radio Signal Strength Noise Ratio\"},
{\"CQI\":\"$endc_lte_cql\", \"full_name\":\"Channel Quality Indicator\"},
{\"TX Power\":\"$endc_lte_tx_power\", \"full_name\":\"TX Power\"},
{\"Srxlev\":\"$endc_lte_srxlev\", \"full_name\":\"Serving Cell Receive Level\"}
]
},
{\"NR5G-NSA\":[
{\"MCC\":\"$endc_nr_mcc\", \"full_name\":\"Mobile Country Code\"},
{\"MNC\":\"$endc_nr_mnc\", \"full_name\":\"Mobile Network Code\"},
{\"Physical Cell ID\":\"$endc_nr_physical_cell_id\", \"full_name\":\"Physical Cell ID\"},
{\"ARFCN\":\"$endc_nr_arfcn\", \"full_name\":\"Absolute Radio-Frequency Channel Number\"},
{\"Band\":\"$endc_nr_band\", \"full_name\":\"Band\"},
{\"DL Bandwidth\":\"$endc_nr_dl_bandwidth\", \"full_name\":\"DL Bandwidth\"},
{\"RSRP\":\"$endc_nr_rsrp\", \"full_name\":\"Reference Signal Received Power\"},
{\"RSRQ\":\"$endc_nr_rsrq\", \"full_name\":\"Reference Signal Received Quality\"},
{\"SINR\":\"$endc_nr_sinr\", \"full_name\":\"Signal to Interference plus Noise Ratio Bandwidth\"},
{\"SCS\":\"$endc_nr_scs\", \"full_name\":\"SCS\"}
]
}
]
}"
elif [ "$network_mode" = "LTE Mode" ]; then
cell_info="\"cell_info\":{
\"LTE Mode\":[
{\"MCC\":\"$lte_mcc\", \"full_name\":\"Mobile Country Code\"},
{\"MNC\":\"$lte_mnc\", \"full_name\":\"Mobile Network Code\"},
{\"Duplex Mode\":\"$lte_duplex_mode\", \"full_name\":\"Duplex Mode\"},
{\"Cell ID\":\"$lte_cell_id\", \"full_name\":\"Cell ID\"},
{\"Physical Cell ID\":\"$lte_physical_cell_id\", \"full_name\":\"Physical Cell ID\"},
{\"EARFCN\":\"$lte_earfcn\", \"full_name\":\"E-UTRA Absolute Radio Frequency Channel Number\"},
{\"Freq band indicator\":\"$lte_freq_band_ind\", \"full_name\":\"Freq band indicator\"},
{\"Band\":\"$lte_band\", \"full_name\":\"Band\"},
{\"UL Bandwidth\":\"$lte_ul_bandwidth\", \"full_name\":\"UL Bandwidth\"},
{\"DL Bandwidth\":\"$lte_dl_bandwidth\", \"full_name\":\"DL Bandwidth\"},
{\"TAC\":\"$lte_tac\", \"full_name\":\"Tracking area code of cell servedby neighbor Enb\"},
{\"RSRP\":\"$lte_rsrp\", \"full_name\":\"Reference Signal Received Power\"},
{\"RSRQ\":\"$lte_rsrq\", \"full_name\":\"Reference Signal Received Quality\"},
{\"RSSI\":\"$lte_rssi\", \"full_name\":\"Received Signal Strength Indicator\"},
{\"SINR\":\"$lte_sinr\", \"full_name\":\"Signal to Interference plus Noise Ratio Bandwidth\"},
{\"RxLev\":\"$lte_rxlev\", \"full_name\":\"RxLev\"},
{\"RSSNR\":\"$lte_rssnr\", \"full_name\":\"Radio Signal Strength Noise Ratio\"},
{\"CQI\":\"$lte_cql\", \"full_name\":\"Channel Quality Indicator\"},
{\"TX Power\":\"$lte_tx_power\", \"full_name\":\"TX Power\"},
{\"Srxlev\":\"$lte_srxlev\", \"full_name\":\"Serving Cell Receive Level\"}
]
}"
elif [ "$network_mode" = "WCDMA Mode" ]; then
cell_info="\"cell_info\":{
\"WCDMA Mode\":[
{\"MCC\":\"$wcdma_mcc\", \"full_name\":\"Mobile Country Code\"},
{\"MNC\":\"$wcdma_mnc\", \"full_name\":\"Mobile Network Code\"},
{\"LAC\":\"$wcdma_lac\", \"full_name\":\"Location Area Code\"},
{\"Cell ID\":\"$wcdma_cell_id\", \"full_name\":\"Cell ID\"},
{\"UARFCN\":\"$wcdma_uarfcn\", \"full_name\":\"UTRA Absolute Radio Frequency Channel Number\"},
{\"PSC\":\"$wcdma_psc\", \"full_name\":\"Primary Scrambling Code\"},
{\"RAC\":\"$wcdma_rac\", \"full_name\":\"Routing Area Code\"},
{\"Band\":\"$wcdma_band\", \"full_name\":\"Band\"},
{\"RSCP\":\"$wcdma_rscp\", \"full_name\":\"Received Signal Code Power\"},
{\"Ec/Io\":\"$wcdma_ecio\", \"full_name\":\"Ec/Io\"},
{\"Ec/No\":\"$wcdma_ecno\", \"full_name\":\"Ec/No\"},
{\"Physical Channel\":\"$wcdma_phych\", \"full_name\":\"Physical Channel\"},
{\"Spreading Factor\":\"$wcdma_sf\", \"full_name\":\"Spreading Factor\"},
{\"Slot\":\"$wcdma_slot\", \"full_name\":\"Slot\"},
{\"Speech Code\":\"$wcdma_speech_code\", \"full_name\":\"Speech Code\"},
{\"Compression Mode\":\"$wcdma_com_mod\", \"full_name\":\"Compression Mode\"},
{\"RxLev\":\"$wcdma_rxlev\", \"full_name\":\"RxLev\"}
]
}"
fi
}
#以Json格式保存模组信息
info_to_json()
{
base_info="\"base_info\":{},"
sim_info="\"sim_info\":{},"
network_info="\"network_info\":{},"
cell_info="\"cell_info\":{}"
#设置基本信息
set_base_info
#判断是否适配
if [ "$manufacturer" != "unknown" ]; then
#设置SIM卡信息
set_sim_info
fi
#判断插卡和连接状态
if [ "$sim_status" = "ready" ] && [ "$connect_status" = "connect" ]; then
#设置网络信息
set_network_info
#设置小区信息
set_cell_info
fi
#拼接所有信息(不要漏掉最后一个}
modem_info="{$base_info$modem_info$sim_info$network_info$cell_info}"
}
# echo $ECIO #参考信号接收质量 RSRQ ecio
# echo $ECIO1 #参考信号接收质量 RSRQ ecio1
# echo $RSCP #参考信号接收功率 RSRP rscp0
# echo $RSCP1 #参考信号接收功率 RSRP rscp1
# echo $SINR #信噪比 SINR rv["sinr"]
# #基站信息
# echo $COPS_MCC #MCC
# echo $$COPS_MNC #MNC
# echo $LAC #eNB ID
# echo '' #LAC_NUM
# echo $RNC #TAC
# echo '' #RNC_NUM
# echo $CID
# echo '' #CID_NUM
# echo $LBAND
# echo $channel
# echo $PCI
# echo $MODTYPE
# echo $QTEMP
#获取模组信息
get_modem_info()
{
update_time=$(date +"%Y-%m-%d %H:%M:%S")
debug "检查模组的AT串口"
#获取模块AT串口
if [ -z "$at_port" ]; then
debug "模组没有AT串口"
return
fi
#检查模块状态(是否处于重启,重置,串口异常状态)
local at_command="ATI"
local response=$(sh ${SCRIPT_DIR}/modem_at.sh $at_port $at_command)
if [[ "$response" = *"failed"* ]] || [[ "$response" = *"$at_port"* ]]; then
debug "模组AT串口未就绪"
return
fi
debug "根据模组的制造商获取信息"
#更多信息获取
case $manufacturer in
"quectel") get_quectel_info "${at_port}" "${platform}" "${define_connect}" ;;
"fibocom") get_fibocom_info "${at_port}" "${platform}" "${define_connect}" ;;
"meig") get_meig_info "${at_port}" "${platform}" "${define_connect}" ;;
"simcom") get_simcom_info "${at_port}" "${platform}" "${define_connect}" ;;
*) debug "未适配该模组" ;;
esac
#获取更新时间
update_time=$(date +"%Y-%m-%d %H:%M:%S")
}
#获取模组数据信息
# $1:AT串口
# $2:制造商
# $3:平台
# $4:连接定义
modem_info()
{
#初值化模组信息
debug "初值化模组信息"
init_modem_info
debug "初值化模组信息完成"
#获取模组信息
at_port="$1"
manufacturer="$2"
platform="$3"
define_connect="$4"
debug "获取模组信息"
get_modem_info
#整合模块信息
info_to_json
echo $modem_info
}
modem_info "$1" "$2" "$3" "$4"

View File

@ -1,23 +0,0 @@
#!/bin/sh
# Copyright (C) 2023 Siriling <siriling@qq.com>
#脚本目录
SCRIPT_DIR="/usr/share/modem"
source "${SCRIPT_DIR}/modem_util.sh"
#模组配置初始化
modem_init()
{
m_log "info" "Clearing all modem configurations"
#清空模组配置
local modem_count=$(uci -q get modem.@global[0].modem_number)
for i in $(seq 0 $((modem_count-1))); do
#删除该模组的配置
uci -q del modem.modem${i}
done
uci set modem.@global[0].modem_number=0
uci commit modem
m_log "info" "All module configurations cleared"
}
modem_init

View File

@ -1,301 +0,0 @@
#!/bin/sh
# Copyright (C) 2023 Siriling <siriling@qq.com>
#脚本目录
SCRIPT_DIR="/usr/share/modem"
#运行目录
MODEM_RUNDIR="/var/run/modem"
#导入组件工具
source "${SCRIPT_DIR}/modem_debug.sh"
#重设网络接口
# $1:AT串口
# $4:连接定义
# $5:模组序号
reset_network_interface()
{
local at_port="$1"
local define_connect="$2"
local modem_no="$3"
local interface_name="wwan_5g_${modem_no}"
local interface_name_ipv6="wwan6_5g_${modem_no}"
#获取IPv4地址
at_command="AT+CGPADDR=${define_connect}"
local ipv4=$(at ${at_port} ${at_command} | grep "+CGPADDR: " | awk -F',' '{print $2}' | sed 's/"//g')
#输出日志
# echo "[$(date +"%Y-%m-%d %H:%M:%S")] Get Modem new IPv4 address : ${ipv4}" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
#获取DNS地址
dns=$(fibocom_get_dns ${at_port} ${define_connect})
local ipv4_dns1=$(echo "${dns}" | jq -r '.dns.ipv4_dns1')
local ipv4_dns2=$(echo "${dns}" | jq -r '.dns.ipv4_dns2')
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] Get Modem IPv4 DNS1: ${ipv4_dns1}" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
echo "[$(date +"%Y-%m-%d %H:%M:%S")] Get Modem IPv4 DNS2: ${ipv4_dns2}" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
#比较的网络接口中的IPv4地址
local ipv4_config=$(uci -q get network.${interface_name}.ipaddr)
if [ "$ipv4_config" == "$ipv4" ]; then
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] IPv4 address is the same as in the network interface, skip" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
else
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] Reset network interface ${interface_name}" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
#设置静态地址
uci set network.${interface_name}.proto='static'
uci set network.${interface_name}.ipaddr="${ipv4}"
uci set network.${interface_name}.netmask='255.255.255.0'
uci set network.${interface_name}.gateway="${ipv4%.*}.1"
uci set network.${interface_name}.peerdns='0'
uci -q del network.${interface_name}.dns
uci add_list network.${interface_name}.dns="${ipv4_dns1}"
uci add_list network.${interface_name}.dns="${ipv4_dns2}"
uci commit network
service network reload
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] Reset network interface successful" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
fi
}
#GobiNet拨号
# $1:AT串口
# $2:制造商
# $3:连接定义
gobinet_dial()
{
local at_port="$1"
local manufacturer="$2"
local define_connect="$3"
#激活
local at_command="AT+CGACT=1,${define_connect}"
#打印日志
dial_log "${at_command}" "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
at "${at_port}" "${at_command}"
#拨号
local at_command
if [ "$manufacturer" = "quectel" ]; then
at_command='ATI'
elif [ "$manufacturer" = "fibocom" ]; then
at_command='AT$QCRMCALL=1,3'
elif [ "$manufacturer" = "meig" ]; then
at_command="ATI"
else
at_command='ATI'
fi
#打印日志
dial_log "${at_command}" "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
at "${at_port}" "${at_command}"
}
#ECM拨号
# $1:AT串口
# $2:制造商
# $3:连接定义
ecm_dial()
{
local at_port="$1"
local manufacturer="$2"
local define_connect="$3"
#激活
# local at_command="AT+CGACT=1,${define_connect}"
# #打印日志
# dial_log "${at_command}" "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
# at "${at_port}" "${at_command}"
#拨号
at_command
if [ "$manufacturer" = "quectel" ]; then
at_command="AT+QNETDEVCTL=${define_connect},3,1"
elif [ "$manufacturer" = "fibocom" ]; then
at_command="AT+GTRNDIS=1,${define_connect}"
elif [ "$manufacturer" = "meig" ]; then
at_command="AT$QCRMCALL=1,1,${define_connect},2,1"
else
at_command='ATI'
fi
#打印日志
dial_log "${at_command}" "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
at "${at_port}" "${at_command}"
sleep 2s
}
#RNDIS拨号
# $1:AT串口
# $2:制造商
# $3:平台
# $4:连接定义
# $5:模组序号
rndis_dial()
{
local at_port="$1"
local manufacturer="$2"
local platform="$3"
local define_connect="$4"
local modem_no="$5"
#手动设置IP广和通FM350-GL
if [ "$manufacturer" = "fibocom" ] && [ "$platform" = "mediatek" ]; then
at_command="AT+CGACT=1,${define_connect}"
#打印日志
dial_log "${at_command}" "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
#激活并拨号
at "${at_port}" "${at_command}"
sleep 3s
else
#拨号
ecm_dial "${at_port}" "${manufacturer}" "${define_connect}"
fi
}
#Modem Manager拨号
# $1:接口名称
# $2:连接定义
modemmanager_dial()
{
local interface_name="$1"
local define_connect="$2"
# #激活
# local at_command="AT+CGACT=1,${define_connect}"
# #打印日志
# dial_log "${at_command}" "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
# at "${at_port}" "${at_command}"
#启动网络接口
ifup "${interface_name}";
}
#检查模组网络连接
# $1:配置ID
# $2:模组序号
# $3:拨号模式
modem_network_task()
{
local config_id="$1"
local modem_no="$2"
local mode="$3"
#获取AT串口制造商平台连接定义接口名称
local at_port=$(uci -q get modem.modem${modem_no}.at_port)
local manufacturer=$(uci -q get modem.modem${modem_no}.manufacturer)
local platform=$(uci -q get modem.modem${modem_no}.platform)
local define_connect=$(uci -q get modem.modem${modem_no}.define_connect)
local interface_name="wwan_5g_${modem_no}"
local interface_name_ipv6="wwan6_5g_${modem_no}"
#重载配置解决AT命令发不出去的问题
# service modem reload
#IPv4地址缓存
local ipv4_cache
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] Start network task" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
while true; do
#全局
local enable_dial=$(uci -q get modem.@global[0].enable_dial)
if [ "$enable_dial" != "1" ]; then
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] The dialing configuration has been disabled, this network task quit" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
break
fi
#单个模组
enable=$(uci -q get modem.${config_id}.enable)
if [ "$enable" != "1" ]; then
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] The modem has disabled dialing, this network task quit" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
break
fi
#网络连接检查
local at_command="AT+CGPADDR=${define_connect}"
local ipv4=$(at ${at_port} ${at_command} | grep "+CGPADDR: " | awk -F',' '{print $2}' | sed 's/"//g')
if [ -z "$ipv4" ]; then
[ "$mode" = "modemmanager" ] && {
#拨号工具为modemmanager时不需要重新设置连接定义
continue
}
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] Unable to get IPv4 address" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
echo "[$(date +"%Y-%m-%d %H:%M:%S")] Redefine connect to ${define_connect}" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
service modem reload
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] Modem dial" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
#拨号针对获取IPv4返回为空的模组
case "$mode" in
"gobinet") gobinet_dial "${at_port}" "${manufacturer}" "${define_connect}" ;;
"ecm") ecm_dial "${at_port}" "${manufacturer}" "${define_connect}" ;;
"rndis") rndis_dial "${at_port}" "${manufacturer}" "${platform}" "${define_connect}" "${modem_no}" ;;
"modemmanager") modemmanager_dial "${interface_name}" "${define_connect}" ;;
*) ecm_dial "${at_port}" "${manufacturer}" "${define_connect}" ;;
esac
elif [[ "$ipv4" = *"0.0.0.0"* ]]; then
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] Modem${modem_no} current IPv4 address : ${ipv4}" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] Modem dial" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
#拨号
case "$mode" in
"gobinet") gobinet_dial "${at_port}" "${manufacturer}" "${define_connect}" ;;
"ecm") ecm_dial "${at_port}" "${manufacturer}" "${define_connect}" ;;
"rndis") rndis_dial "${at_port}" "${manufacturer}" "${platform}" "${define_connect}" "${modem_no}" ;;
"modemmanager") modemmanager_dial "${interface_name}" "${define_connect}" ;;
*) ecm_dial "${at_port}" "${manufacturer}" "${define_connect}" ;;
esac
elif [ "$ipv4" != "$ipv4_cache" ]; then
#第一次缓存IP为空时不输出日志
[ -n "$ipv4_cache" ] && {
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] Modem${modem_no} IPv4 address has changed" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
}
#输出日志
echo "[$(date +"%Y-%m-%d %H:%M:%S")] Modem${modem_no} current IPv4 address : ${ipv4}" >> "${MODEM_RUNDIR}/modem${modem_no}_dial.cache"
#缓存当前IP
ipv4_cache="${ipv4}"
#重新设置网络接口广和通FM350-GL
if [ "$manufacturer" = "fibocom" ] && [ "$platform" = "mediatek" ]; then
reset_network_interface "${at_port}" "${define_connect}" "${modem_no}"
sleep 3s
fi
[ "$mode" != "modemmanager" ] && {
#重新启动网络接口
ifup "${interface_name}"
ifup "${interface_name_ipv6}"
}
fi
sleep 5s
done
}
modem_network_task "$1" "$2" "$3"

View File

@ -1,82 +1,286 @@
#!/bin/sh
# Copyright (C) 2023 Siriling <siriling@qq.com>
#/bin/sh
#脚本目录
SCRIPT_DIR="/usr/share/modem"
source "${SCRIPT_DIR}/modem_util.sh"
action=$1
config=$2
slot_type=$3
modem_support=$(cat /usr/share/modem/modem_support.json)
#获取设备物理地址
# $1:网络设备或串口
get_device_physical_path()
source /usr/share/modem/modem_util.sh
scan()
{
local device_name="$(basename "$1")"
local device_path="$(find /sys/class/ -name $device_name)"
local device_physical_path="$(readlink -f $device_path/device/)"
echo "$device_physical_path"
}
#设置模组配置
# $1:网络设备
# $2:网络设备系统路径
set_modem_config()
{
local network="$(basename $sys_network)"
local network_path="$(readlink -f $sys_network)"
#只处理最上级的网络设备
local count=$(echo "${network_path}" | grep -o "/net" | wc -l)
[ "$count" -ge "2" ] && return
#判断路径是否带有usb排除其他eth网络设备
if [[ "$network" = *"eth"* ]] && [[ "$network_path" != *"usb"* ]]; then
return
fi
#获取物理路径
local device_physical_path=$(m_get_device_physical_path ${network_path})
#设置物理设备
m_set_physical_device "scan" "${network}" "${device_physical_path}"
#启用拨号
enable_dial "${network}"
}
#设置系统网络设备
# $1:系统网络设备列表
set_sys_network_config()
{
local sys_networks="$1"
for sys_network in $sys_networks; do
local network="$(basename $sys_network)"
set_modem_config "${network}" "${sys_network}"
scan_usb
scan_pcie
#remove duplicate
usb_slots=$(echo $usb_slots | uniq )
pcie_slots=$(echo $pcie_slots | uniq )
for slot in $usb_slots; do
slot_type="usb"
add $slot
done
for slot in $pcie_slots; do
slot_type="pcie"
add $slot
done
}
#设置模组信息
modem_scan()
scan_usb()
{
#模组配置初始化
sh "${SCRIPT_DIR}/modem_init.sh"
#发起模组添加事件
#USB
local sys_network
sys_network="$(find /sys/class/net -name usb*)" #ECM RNDIS NCM
set_sys_network_config "$sys_network"
sys_network="$(find /sys/class/net -name wwan*)" #QMI MBIM
set_sys_network_config "$sys_network"
sys_network="$(find /sys/class/net -name eth*)" #RNDIS
set_sys_network_config "$sys_network"
#PCIE
sys_network="$(find /sys/class/net -name mhi_hwip*)" #通用mhi驱动
set_sys_network_config "$sys_network"
sys_network="$(find /sys/class/net -name rmnet_mhi*)" #制造商mhi驱动
set_sys_network_config "$sys_network"
echo "modem scan complete"
usb_net_device_prefixs="usb eth wwan"
usb_slots=""
for usb_net_device_prefix in $usb_net_device_prefixs; do
usb_netdev=$(ls /sys/class/net | grep -E "${usb_net_device_prefix}")
for netdev in $usb_netdev; do
netdev_path=$(readlink -f "/sys/class/net/$netdev/device/")
[ -z "$netdev_path" ] && continue
[ -z "$(echo $netdev_path | grep usb)" ] && continue
usb_slot=$(basename $(dirname $netdev_path))
echo "netdev_path: $netdev_path usb slot: $usb_slot"
[ -z "$usb_slots" ] && usb_slots="$usb_slot" || usb_slots="$usb_slots $usb_slot"
done
done
}
#测试时打开
# modem_scan
scan_pcie()
{
#not implemented
echo "scan_pcie"
}
scan_usb_slot_interfaces()
{
local slot=$1
local slot_path="/sys/bus/usb/devices/$slot"
net_devices=""
tty_devices=""
[ ! -d "$slot_path" ] && return
local slot_interfaces=$(ls $slot_path | grep -E "$slot:[0-9]\.[0-9]+")
for interface in $slot_interfaces; do
unset device
unset ttyUSB_device
unset ttyACM_device
interface_driver_path="$slot_path/$interface/driver"
[ ! -d "$interface_driver_path" ] && continue
interface_driver=$(basename $(readlink $interface_driver_path))
[ -z "$interface_driver" ] && continue
case $interface_driver in
option|\
usbserial)
ttyUSB_device=$(ls "$slot_path/$interface/" | grep ttyUSB)
ttyACM_device=$(ls "$slot_path/$interface/" | grep ttyACM)
[ -z "$ttyUSB_device" ] && [ -z "$ttyACM_device" ] && continue
[ -n "$ttyUSB_device" ] && device="$ttyUSB_device"
[ -n "$ttyACM_device" ] && device="$ttyACM_device"
[ -z "$tty_devices" ] && tty_devices="$device" || tty_devices="$tty_devices $device"
;;
qmi_wwan*|\
cdc_mbim|\
cdc_ncm|\
cdc_ether|\
rndis_host)
net_path="$slot_path/$interface/net"
[ ! -d "$net_path" ] && continue
device=$(ls $net_path)
[ -z "$net_devices" ] && net_devices="$device" || net_devices="$net_devices $device"
;;
esac
done
echo "net_devices: $net_devices tty_devices: $tty_devices"
at_ports="$tty_devices"
validate_at_port
}
validate_at_port()
{
valid_at_ports=""
for at_port in $at_ports; do
dev_path="/dev/$at_port"
[ ! -e "$dev_path" ] && continue
res=$(at $dev_path "AT")
[ -z "$res" ] && continue
[ "$res" == *"No"* ] && [ "$res" == *"failed"* ] && continue #for sms_tools No response from modem
valid_at_port="$at_port"
[ -z "$valid_at_ports" ] && valid_at_ports="$valid_at_port" || valid_at_ports="$valid_at_ports $valid_at_port"
done
}
match_config()
{
local name=$(echo $1 | sed 's/\r//g' | tr 'A-Z' 'a-z')
[[ "$name" = *"nl678"* ]] && name="nl678"
[[ "$name" = *"em120k"* ]] && name="em120k"
#FM350-GL-00 5G Module
[[ "$name" = *"fm350-gl"* ]] && name="fm350-gl"
#RM500U-CNV
[[ "$name" = *"rm500u-cn"* ]] && name="rm500u-cn"
[[ "$name" = *"rm500u-ea"* ]] && name="rm500u-ea"
#rg200u-cn
[[ "$name" = *"rg200u-cn"* ]] && name="rg200u-cn"
modem_config=$(echo $modem_support | jq '.modem_support."'$slot_type'"."'$name'"')
[ "$modem_config" == "null" ] && return
modem_name=$name
manufacturer=$(echo $modem_config | jq -r ".manufacturer")
platform=$(echo $modem_config | jq -r ".platform")
define_connect=$(echo $modem_config | jq -r ".define_connect")
modes=$(echo $modem_config | jq -r ".modes[]")
}
get_modem_model()
{
local at_port=$1
cgmm=$(at $at_port "AT+CGMM")
cgmm_1=$(at $at_port "AT+CGMM?")
name_1=$(echo -e "$cgmm" |grep "+CGMM: " | awk -F': ' '{print $2}')
name_2=$(echo -e "$cgmm_1" |grep "+CGMM: " | awk -F'"' '{print $2} '| cut -d ' ' -f 1)
name_3=$(echo -e "$cgmm" | sed -n '2p')
modem_name=""
[ -n "$name_1" ] && match_config "$name_1"
[ -n "$name_2" ] && [ -z "$modem_name" ] && match_config "$name_2"
[ -n "$name_3" ] && [ -z "$modem_name" ] && match_config "$name_3"
[ -z "$modem_name" ] && return 1
return 0
}
add()
{
local slot=$1
lock -n /tmp/lock/modem_add_$slot
[ $? -eq 1 ] && return
#slot_type is usb or pcie
#section name is replace slot .:- with _
section_name=$(echo $slot | sed 's/[\.:-]/_/g')
is_exist=$(uci get modem.$section_name)
case $slot_type in
"usb")
scan_usb_slot_interfaces $slot
;;
"pcie")
#not implemented
;;
esac
for at_port in $valid_at_ports; do
get_modem_model "/dev/$at_port"
[ $? -eq 0 ] && break
done
[ -z "$modem_name" ] && lock -u /tmp/lock/modem_add_$slot && return
m_debug "add modem $modem_name slot $slot slot_type $slot_type"
if [ -n "$is_exist" ]; then
#network at_port state name 不变,则不需要重启网络
orig_network=$(uci get modem.$section_name.network)
orig_at_port=$(uci get modem.$section_name.at_port)
orig_state=$(uci get modem.$section_name.state)
orig_name=$(uci get modem.$section_name.name)
uci del modem.$section_name.modes
uci del modem.$section_name.valid_at_ports
uci del modem.$section_name.tty_devices
uci del modem.$section_name.net_devices
uci del modem.$section_name.ports
uci set modem.$section_name.state="enabled"
else
#aqcuire lock
lock /tmp/lock/modem_add
modem_count=$(uci get modem.@global[0].modem_count)
[ -z "$modem_count" ] && modem_count=0
modem_count=$(($modem_count+1))
uci set modem.@global[0].modem_count=$modem_count
uci set modem.$section_name=modem-device
uci commit modem
lock -u /tmp/lock/modem_add
#release lock
metric=$(($modem_count+10))
uci batch << EOF
set modem.$section_name.path="/sys/bus/usb/devices/$slot/"
set modem.$section_name.data_interface="$slot_type"
set modem.$section_name.enable_dial="1"
set modem.$section_name.pdp_type="ip"
set modem.$section_name.state="enabled"
set modem.$section_name.metric=$metric
EOF
fi
uci batch <<EOF
set modem.$section_name.name=$modem_name
set modem.$section_name.network=$net_devices
set modem.$section_name.manufacturer=$manufacturer
set modem.$section_name.platform=$platform
set modem.$section_name.define_connect=$define_connect
EOF
for mode in $modes; do
uci add_list modem.$section_name.modes=$mode
done
for at_port in $valid_at_ports; do
uci add_list modem.$section_name.valid_at_ports="/dev/$at_port"
uci set modem.$section_name.at_port="/dev/$at_port"
done
for at_port in $tty_devices; do
uci add_list modem.$section_name.ports="/dev/$at_port"
done
uci commit modem
mkdir -p /var/run/modem/${section_name}_dir
lock -u /tmp/lock/modem_add_$slot
#判断是否重启网络
[ -n "$is_exist" ] && [ "$orig_network" == "$net_devices" ] && [ "$orig_at_port" == "/dev/$at_port" ] && [ "$orig_state" == "enabled" ] && [ "$orig_name" == "$modem_name" ] && return
/etc/init.d/modem_network restart
}
remove()
{
section_name=$1
m_debug "remove $section_name"
is_exist=$(uci get modem.$section_name)
[ -z "$is_exist" ] && return
lock /tmp/lock/modem_remove
modem_count=$(uci get modem.@global[0].modem_count)
[ -z "$modem_count" ] && modem_count=0
modem_count=$(($modem_count-1))
uci set modem.@global[0].modem_count=$modem_count
uci commit modem
uci batch <<EOF
del modem.${section_name}
del network.${section_name}
del network.${section_name}v6
del dhcp.${section_name}
commit network
commit dhcp
commit modem
EOF
lock -u /tmp/lock/modem_remove
}
disable()
{
local slot=$1
section_name=$(echo $slot | sed 's/[\.:-]/_/g')
uci set modem.$section_name.state="disabled"
uci commit modem
}
case $action in
"add")
debug_subject="modem_scan_add"
add $config
;;
"remove")
debug_subject="modem_scan_remove"
remove $config
;;
"disable")
debug_subject="modem_scan_disable"
disable $config
;;
"scan")
debug_subject="modem_scan_scan"
[ -n "$config" ] && delay=$config && sleep $delay
lock -n /tmp/lock/modem_scan
[ $? -eq 1 ] && exit 0
scan
lock -u /tmp/lock/modem_scan
;;
esac

View File

@ -1,6 +1,22 @@
{
"modem_support":{
"usb":{
"em05":{
"manufacturer_id":"2c7c",
"manufacturer":"quectel",
"platform":"lte",
"data_interface":"usb",
"define_connect":"1",
"modes":["qmi","ecm","mbim","rndis","ncm"]
},
"em120k":{
"manufacturer_id":"2c7c",
"manufacturer":"quectel",
"platform":"lte12",
"data_interface":"usb",
"define_connect":"1",
"modes":["qmi","ecm","mbim","rndis","ncm"]
},
"rg200u-cn":{
"manufacturer_id":"2c7c",
"manufacturer":"quectel",
@ -17,6 +33,14 @@
"define_connect":"1",
"modes":["ecm","mbim","rndis","ncm"]
},
"rm500u-ea":{
"manufacturer_id":"2c7c",
"manufacturer":"quectel",
"platform":"unisoc",
"data_interface":"usb",
"define_connect":"1",
"modes":["ecm","mbim","rndis","ncm"]
},
"rm500q-cn":{
"manufacturer_id":"2c7c",
"manufacturer":"quectel",
@ -121,6 +145,14 @@
"define_connect":"1",
"modes":["qmi","gobinet","ecm","mbim","rndis","ncm"]
},
"nl678":{
"manufacturer_id":"2cb7",
"manufacturer":"fibocom",
"platform":"lte",
"data_interface":"usb",
"define_connect":"1",
"modes":["qmi","ecm","rndis","ncm"]
},
"srm815":{
"manufacturer_id":"2dee",
"manufacturer":"meig",

View File

@ -1,25 +0,0 @@
#!/bin/sh
# Copyright (C) 2023 Siriling <siriling@qq.com>
#脚本目录
SCRIPT_DIR="/usr/share/modem"
source "${SCRIPT_DIR}/modem_debug.sh"
source "${SCRIPT_DIR}/modem_scan.sh"
#模组扫描任务
modem_scan_task()
{
sleep 8s #刚开机需要等待移动网络出来
while true; do
enable_dial=$(uci -q get modem.@global[0].enable_dial)
if [ "$enable_dial" = "1" ]; then
#扫描模块
debug "开启模块扫描任务"
modem_scan
debug "结束模块扫描任务"
fi
sleep 10s
done
}
modem_scan_task

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,303 +0,0 @@
#!/bin/sh
# Copyright (C) 2023 Siriling <siriling@qq.com>
#脚本目录
SCRIPT_DIR="/usr/share/modem"
#查询信息强度
All_CSQ()
{
debug "All_CSQ"
#信号
OX=$( sh modem_at.sh $at_port "AT+CSQ" |grep "+CSQ:")
OX=$(echo $OX | tr 'a-z' 'A-Z')
CSQ=$(echo "$OX" | grep -o "+CSQ: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}")
if [ $CSQ = "99" ]; then
CSQ=""
fi
if [ -n "$CSQ" ]; then
CSQ_PER=$(($CSQ * 100/31))"%"
CSQ_RSSI=$((2 * CSQ - 113))" dBm"
else
CSQ="-"
CSQ_PER="-"
CSQ_RSSI="-"
fi
}
# SIMCOM获取基站信息
SIMCOM_Cellinfo()
{
#baseinfo.gcom
OX=$( sh modem_at.sh 2 "ATI")
OX=$( sh modem_at.sh 2 "AT+CGEQNEG=1")
#cellinfo0.gcom
OX1=$( sh modem_at.sh 2 "AT+COPS=3,0;+COPS?")
OX2=$( sh modem_at.sh 2 "AT+COPS=3,2;+COPS?")
OX=$OX1" "$OX2
#cellinfo.gcom
OY1=$( sh modem_at.sh 2 "AT+CREG=2;+CREG?;+CREG=0")
OY2=$( sh modem_at.sh 2 "AT+CEREG=2;+CEREG?;+CEREG=0")
OY3=$( sh modem_at.sh 2 "AT+C5GREG=2;+C5GREG?;+C5GREG=0")
OY=$OY1" "$OY2" "$OY3
OXx=$OX
OX=$(echo $OX | tr 'a-z' 'A-Z')
OY=$(echo $OY | tr 'a-z' 'A-Z')
OX=$OX" "$OY
#debug "$OX"
#debug "$OY"
COPS="-"
COPS_MCC="-"
COPS_MNC="-"
COPSX=$(echo $OXx | grep -o "+COPS: [01],0,.\+," | cut -d, -f3 | grep -o "[^\"]\+")
if [ "x$COPSX" != "x" ]; then
COPS=$COPSX
fi
COPSX=$(echo $OX | grep -o "+COPS: [01],2,.\+," | cut -d, -f3 | grep -o "[^\"]\+")
if [ "x$COPSX" != "x" ]; then
COPS_MCC=${COPSX:0:3}
COPS_MNC=${COPSX:3:3}
if [ "$COPS" = "-" ]; then
COPS=$(awk -F[\;] '/'$COPS'/ {print $2}' $ROOTER/signal/mccmnc.data)
[ "x$COPS" = "x" ] && COPS="-"
fi
fi
if [ "$COPS" = "-" ]; then
COPS=$(echo "$O" | awk -F[\"] '/^\+COPS: 0,0/ {print $2}')
if [ "x$COPS" = "x" ]; then
COPS="-"
COPS_MCC="-"
COPS_MNC="-"
fi
fi
COPS_MNC=" "$COPS_MNC
OX=$(echo "${OX//[ \"]/}")
CID=""
CID5=""
RAT=""
REGV=$(echo "$OX" | grep -o "+C5GREG:2,[0-9],[A-F0-9]\{2,6\},[A-F0-9]\{5,10\},[0-9]\{1,2\}")
if [ -n "$REGV" ]; then
LAC5=$(echo "$REGV" | cut -d, -f3)
LAC5=$LAC5" ($(printf "%d" 0x$LAC5))"
CID5=$(echo "$REGV" | cut -d, -f4)
CID5L=$(printf "%010X" 0x$CID5)
RNC5=${CID5L:1:6}
RNC5=$RNC5" ($(printf "%d" 0x$RNC5))"
CID5=${CID5L:7:3}
CID5="Short $(printf "%X" 0x$CID5) ($(printf "%d" 0x$CID5)), Long $(printf "%X" 0x$CID5L) ($(printf "%d" 0x$CID5L))"
RAT=$(echo "$REGV" | cut -d, -f5)
fi
REGV=$(echo "$OX" | grep -o "+CEREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{5,8\}")
REGFMT="3GPP"
if [ -z "$REGV" ]; then
REGV=$(echo "$OX" | grep -o "+CEREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{1,3\},[A-F0-9]\{5,8\}")
REGFMT="SW"
fi
if [ -n "$REGV" ]; then
LAC=$(echo "$REGV" | cut -d, -f3)
LAC=$(printf "%04X" 0x$LAC)" ($(printf "%d" 0x$LAC))"
if [ $REGFMT = "3GPP" ]; then
CID=$(echo "$REGV" | cut -d, -f4)
else
CID=$(echo "$REGV" | cut -d, -f5)
fi
CIDL=$(printf "%08X" 0x$CID)
RNC=${CIDL:1:5}
RNC=$RNC" ($(printf "%d" 0x$RNC))"
CID=${CIDL:6:2}
CID="Short $(printf "%X" 0x$CID) ($(printf "%d" 0x$CID)), Long $(printf "%X" 0x$CIDL) ($(printf "%d" 0x$CIDL))"
else
REGV=$(echo "$OX" | grep -o "+CREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{2,8\}")
if [ -n "$REGV" ]; then
LAC=$(echo "$REGV" | cut -d, -f3)
CID=$(echo "$REGV" | cut -d, -f4)
if [ ${#CID} -gt 4 ]; then
LAC=$(printf "%04X" 0x$LAC)" ($(printf "%d" 0x$LAC))"
CIDL=$(printf "%08X" 0x$CID)
RNC=${CIDL:1:3}
CID=${CIDL:4:4}
CID="Short $(printf "%X" 0x$CID) ($(printf "%d" 0x$CID)), Long $(printf "%X" 0x$CIDL) ($(printf "%d" 0x$CIDL))"
else
LAC=""
fi
else
LAC=""
fi
fi
REGSTAT=$(echo "$REGV" | cut -d, -f2)
if [ "$REGSTAT" == "5" -a "$COPS" != "-" ]; then
COPS_MNC=$COPS_MNC" (Roaming)"
fi
if [ -n "$CID" -a -n "$CID5" ] && [ "$RAT" == "13" -o "$RAT" == "10" ]; then
LAC="4G $LAC, 5G $LAC5"
CID="4G $CID<br />5G $CID5"
RNC="4G $RNC, 5G $RNC5"
elif [ -n "$CID5" ]; then
LAC=$LAC5
CID=$CID5
RNC=$RNC5
fi
if [ -z "$LAC" ]; then
LAC="-"
CID="-"
RNC="-"
fi
}
SIMCOM_SIMINFO()
{
debug "Quectel_SIMINFO"
# 获取IMEI
IMEI=$( sh modem_at.sh $at_port "AT+CGSN" | sed -n '2p' )
# 获取IMSI
IMSI=$( sh modem_at.sh $at_port "AT+CIMI" | sed -n '2p' )
# 获取ICCID
ICCID=$( sh modem_at.sh $at_port "AT+ICCID" | grep -o "+ICCID:[ ]*[-0-9]\+" | grep -o "[-0-9]\{1,4\}" )
# 获取电话号码
phone=$( sh modem_at.sh $at_port "AT+CNUM" | grep "+CNUM:" )
}
#simcom查找基站AT
get_simcom_data()
{
debug "get simcom data"
#设置AT串口
at_port=$1
All_CSQ
SIMCOM_SIMINFO
SIMCOM_Cellinfo
#温度
OX=$( sh modem_at.sh $at_port "AT+CPMUTEMP")
TEMP=$(echo "$OX" | grep -o "+CPMUTEMP:[ ]*[-0-9]\+" | grep -o "[-0-9]\{1,4\}")
if [ -n "$TEMP" ]; then
TEMP=$(echo $TEMP)$(printf "\xc2\xb0")"C"
fi
#基站信息
OX=$( sh modem_at.sh $at_port "AT+CPSI?")
rec=$(echo "$OX" | grep "+CPSI:")
w=$(echo $rec |grep "NO SERVICE"| wc -l)
if [ $w -ge 1 ];then
debug "NO SERVICE"
return
fi
w=$(echo $rec |grep "NR5G_"| wc -l)
if [ $w -ge 1 ];then
w=$(echo $rec |grep "32768"| wc -l)
if [ $w -ge 1 ];then
debug "-32768"
return
fi
debug "$rec"
rec1=${rec##*+CPSI:}
#echo "$rec1"
MODE="${rec1%%,*}" # MODE="NR5G"
rect1=${rec1#*,}
rect1s="${rect1%%,*}" #Online
rect2=${rect1#*,}
rect2s="${rect2%%,*}" #460-11
rect3=${rect2#*,}
rect3s="${rect3%%,*}" #0xCFA102
rect4=${rect3#*,}
rect4s="${rect4%%,*}" #55744245764
rect5=${rect4#*,}
rect5s="${rect5%%,*}" #196
rect6=${rect5#*,}
rect6s="${rect6%%,*}" #NR5G_BAND78
rect7=${rect6#*,}
rect7s="${rect7%%,*}" #627264
rect8=${rect7#*,}
rect8s="${rect8%%,*}" #-940
rect9=${rect8#*,}
rect9s="${rect9%%,*}" #-110
# "${rec1##*,}" #最后一位
rect10=${rect9#*,}
rect10s="${rect10%%,*}" #最后一位
PCI=$rect5s
LBAND="n"$(echo $rect6s | cut -d, -f0 | grep -o "BAND[0-9]\{1,3\}" | grep -o "[0-9]\+")
CHANNEL=$rect7s
RSCP=$(($(echo $rect8s | cut -d, -f0) / 10))
ECIO=$(($(echo $rect9s | cut -d, -f0) / 10))
if [ "$CSQ_PER" = "-" ]; then
CSQ_PER=$((100 - (($RSCP + 31) * 100/-125)))"%"
fi
SINR=$(($(echo $rect10s | cut -d, -f0) / 10))" dB"
fi
w=$(echo $rec |grep "LTE"|grep "EUTRAN"| wc -l)
if [ $w -ge 1 ];then
rec1=${rec#*EUTRAN-}
lte_band=${rec1%%,*} #EUTRAN-BAND
rec1=${rec1#*,}
rec1=${rec1#*,}
rec1=${rec1#*,}
rec1=${rec1#*,}
#rec1=${rec1#*,}
rec1=${rec1#*,}
lte_rssi=${rec1%%,*} #LTE_RSSI
lte_rssi=`expr $lte_rssi / 10` #LTE_RSSI
debug "LTE_BAND=$lte_band LTE_RSSI=$lte_rssi"
if [ $rssi == 0 ];then
rssi=$lte_rssi
fi
fi
w=$(echo $rec |grep "WCDMA"| wc -l)
if [ $w -ge 1 ];then
w=$(echo $rec |grep "UNKNOWN"|wc -l)
if [ $w -ge 1 ];then
debug "UNKNOWN BAND"
return
fi
fi
#CNMP
OX=$( sh modem_at.sh $at_port "AT+CNMP?")
CNMP=$(echo "$OX" | grep -o "+CNMP:[ ]*[0-9]\{1,3\}" | grep -o "[0-9]\{1,3\}")
if [ -n "$CNMP" ]; then
case $CNMP in
"2"|"55" )
NETMODE="1" ;;
"13" )
NETMODE="3" ;;
"14" )
NETMODE="5" ;;
"38" )
NETMODE="7" ;;
"71" )
NETMODE="9" ;;
"109" )
NETMODE="8" ;;
* )
NETMODE="0" ;;
esac
fi
# CMGRMI 信息
OX=$( sh modem_at.sh $at_port "AT+CMGRMI=4")
CAINFO=$(echo "$OX" | grep -o "$REGXz" | tr ' ' ':')
if [ -n "$CAINFO" ]; then
for CASV in $(echo "$CAINFO"); do
LBAND=$LBAND"<br />B"$(echo "$CASV" | cut -d, -f4)
BW=$(echo "$CASV" | cut -d, -f5)
decode_bw
LBAND=$LBAND" (CA, Bandwidth $BW MHz)"
CHANNEL="$CHANNEL, "$(echo "$CASV" | cut -d, -f2)
PCI="$PCI, "$(echo "$CASV" | cut -d, -f7)
done
fi
}

View File

@ -1,5 +0,0 @@
#!/bin/sh
sleep 15
logger -t usb_modem_scan "Start to scan USB modem"
source /usr/share/modem/modem_scan.sh
modem_scan

View File

@ -7,5 +7,13 @@
"write": {
"uci": [ "modem" ]
}
},
"luci-mod-status-index": {
"description": "Grant access to main status display",
"read": {
"ubus": {
"modem_ctrl": [ "info","base_info" ]
}
}
}
}