From 1af23d6068bff408c4763a4fa162e0db4c5da994 Mon Sep 17 00:00:00 2001 From: coolsnowwolf Date: Thu, 15 May 2025 17:58:21 +0800 Subject: [PATCH] luci-app-qmodem: add Huawei TD Tech MT5700M-CN support --- luci/luci-app-qmodem/Makefile | 2 +- .../root/usr/share/qmodem/modem_dial.sh | 8 + .../root/usr/share/qmodem/modem_support.json | 15 + .../root/usr/share/qmodem/vendor/huawei.sh | 452 ++++++++++++++++++ 4 files changed, 476 insertions(+), 1 deletion(-) create mode 100755 luci/luci-app-qmodem/root/usr/share/qmodem/vendor/huawei.sh diff --git a/luci/luci-app-qmodem/Makefile b/luci/luci-app-qmodem/Makefile index d4e81e1..173a9e2 100644 --- a/luci/luci-app-qmodem/Makefile +++ b/luci/luci-app-qmodem/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-qmodem LUCI_TITLE:=LuCI support for QWRT Modem LUCI_PKGARCH:=all -PKG_VERSION:=2.7.0 +PKG_VERSION:=2.7.1 PKG_LICENSE:=GPLv3 PKG_LINCESE_FILES:=LICENSE PKG_MAINTAINER:=Tom diff --git a/luci/luci-app-qmodem/root/usr/share/qmodem/modem_dial.sh b/luci/luci-app-qmodem/root/usr/share/qmodem/modem_dial.sh index 79ba61d..d2061f1 100755 --- a/luci/luci-app-qmodem/root/usr/share/qmodem/modem_dial.sh +++ b/luci/luci-app-qmodem/root/usr/share/qmodem/modem_dial.sh @@ -786,6 +786,14 @@ at_dial() ;; esac ;; + "huawei") + case $platform in + "hisilicon") + at_command="AT^SETAUTODIAL=1,1" + cgdcont_command="AT+CGDCONT=1,\"$pdp_type\"" + ;; + esac + ;; "simcom") case $platform in "qualcomm") diff --git a/luci/luci-app-qmodem/root/usr/share/qmodem/modem_support.json b/luci/luci-app-qmodem/root/usr/share/qmodem/modem_support.json index 4c5290c..00a8c1f 100644 --- a/luci/luci-app-qmodem/root/usr/share/qmodem/modem_support.json +++ b/luci/luci-app-qmodem/root/usr/share/qmodem/modem_support.json @@ -69,6 +69,21 @@ "rndis" ] }, + "mt5700m-cn": { + "manufacturer_id": "3466", + "manufacturer": "huawei", + "platform": "hisilicon", + "data_interface": "usb", + "define_connect": "1", + "wcdma_band": "1/8", + "lte_band": "1/3/5/8/34/38/39/40/41", + "nsa_band": "41/78/79", + "sa_band": "1/28/41/78/79", + "modes": [ + "ecm", + "ncm" + ] + }, "rg200u-cn": { "manufacturer_id": "2c7c", "manufacturer": "quectel", diff --git a/luci/luci-app-qmodem/root/usr/share/qmodem/vendor/huawei.sh b/luci/luci-app-qmodem/root/usr/share/qmodem/vendor/huawei.sh new file mode 100755 index 0000000..70b2c1e --- /dev/null +++ b/luci/luci-app-qmodem/root/usr/share/qmodem/vendor/huawei.sh @@ -0,0 +1,452 @@ +#!/bin/sh +# Copyright (C) 2025 coolsnowwolf +_Vendor="huawei" +_Author="Lean" +_Maintainer="Lean " +source /usr/share/qmodem/generic.sh +debug_subject="quectel_ctrl" + +function get_imei(){ + imei=$(at $at_port "AT+CGSN" | grep -o '[0-9]\{15\}') + json_add_string imei $imei +} + +function set_imei(){ + imei=$1 + at $at_port "AT+CGSN=\"$imei\"" +} + +function get_mode(){ + cfg=$(at $at_port "AT^SETMODE?") + local mode_num=`echo -e "$cfg" | sed -n '2p' | sed 's/\r//g'` + + if [ -z "$mode_num" ]; then + echo "unknown" + return + fi + + case "$mode_num" in + "0"|"2") mode="ecm" ;; + "1"|"3"|"4"|"5") mode="ncm" ;; + "6") mode="rndis" ;; + "7") mode="mbim" ;; + "8") mode="ppp" ;; + *) mode="$mode_num" ;; + esac + + available_modes=$(uci -q get qmodem.$config_section.modes) + json_add_object "mode" + for available_mode in $available_modes; do + if [ "$mode" = "$available_mode" ]; then + json_add_string "$available_mode" "1" + else + json_add_string "$available_mode" "0" + fi + done + json_close_object +} + +function set_mode(){ + local mode=$1 + local mode_num + case $mode in + "ecm") + mode_num="0" + ;; + "ncm") + mode_num="4" + ;; + *) + mode_num="0" + ;; + esac + at $at_port "AT^SETMODE=${mode_num}" +} + +function get_network_prefer(){ + res=$(at $at_port "AT^SYSCFGEX?"| grep "\^SYSCFGEX:" | sed 's/\^SYSCFGEX://g') + # (RAT index): + # • 00 – Automatic + # • 01 – UMTS 3G only + # • 04 – LTE only + # • 05 – 5G only + # • 0E – UMTS and LTE only + # • 0F – LTE and NR5G only + # • 10 – WCDMA and NR5G only + local network_type_num=$(echo "$res" | awk -F'"' '{print $2}') + + #获取网络类型 + local network_prefer_3g="0" + local network_prefer_4g="0" + local network_prefer_5g="0" + + #匹配不同的网络类型 + local auto=$(echo "${network_type_num}" | grep "00") + + if [ -n "$auto" ]; then + network_prefer_2g="1" + network_prefer_3g="1" + network_prefer_4g="1" + network_prefer_5g="1" + else + local wcdma=$(echo "${network_type_num}" | grep "02") + local lte=$(echo "${network_type_num}" | grep "03") + local nr=$(echo "${network_type_num}" | grep "08") + + 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 + json_add_object network_prefer + json_add_string 3G $network_prefer_3g + json_add_string 4G $network_prefer_4g + json_add_string 5G $network_prefer_5g + json_close_array +} + +function set_network_prefer(){ + local network_prefer_3g=$(echo $1 |jq -r 'contains(["3G"])') + local network_prefer_4g=$(echo $1 |jq -r 'contains(["4G"])') + local network_prefer_5g=$(echo $1 |jq -r 'contains(["5G"])') + count=$(echo $1 | jq -r 'length') + case "$count" in + "1") + if [ "$network_prefer_3g" = "true" ]; then + code="02" + elif [ "$network_prefer_4g" = "true" ]; then + code="03" + elif [ "$network_prefer_5g" = "true" ]; then + code="08" + fi + ;; + "2") + if [ "$network_prefer_3g" = "true" ] && [ "$network_prefer_4g" = "true" ]; then + code="02" + elif [ "$network_prefer_4g" = "true" ] && [ "$network_prefer_5g" = "true" ]; then + code="03" + elif [ "$network_prefer_3g" = "true" ] && [ "$network_prefer_5g" = "true" ]; then + code="08" + fi + ;; + "3") + code="080302" + ;; + *) + code="00" + ;; + esac + + at_command='AT^SYSCFGEX="'${code}'",40000000,1,2,40000000,,' + res=$(at $at_port "${at_command}") + json_add_string "code" "$code" + json_add_string "result" "$res" +} + +function get_lockband(){ + json_add_object "lockband" + case $platform in + *) + _get_lockband_nr + ;; + esac + json_close_object +} + +function set_lockband(){ + config=$1 + band_class=$(echo $config | jq -r '.band_class') + lock_band=$(echo $config | jq -r '.lock_band') + case $platform in + *) + _set_lockband_nr + ;; + esac +} + +function sim_info() +{ + class="SIM Information" + + sim_slot="1" + + #SIM Status(SIM状态) + at_command="AT+CPIN?" + sim_status=$(at $at_port $at_command | grep "+CPIN:") + sim_status=${sim_status:7:-1} + #lowercase + sim_status=$(echo $sim_status | tr A-Z a-z) + + #SIM Number(SIM卡号码,手机号) + at_command="AT+CNUM" + sim_number=$(at $at_port $at_command | grep "+CNUM: " | awk -F'"' '{print $2}') + [ -z "$sim_number" ] && { + sim_number=$(at $at_port $at_command | grep "+CNUM: " | awk -F'"' '{print $4}') + } + + #IMSI(国际移动用户识别码) + at_command="AT+CIMI" + imsi=$(at $at_port $at_command | sed -n '2p' | sed 's/\r//g') + + #IMEI(国际移动设备识别码) + at_command="AT+CGSN" + imei=$(at $at_port $at_command | sed -n '2p' | sed 's/\r//g') + + add_plain_info_entry "SIM Status" "$sim_status" "SIM Status" + add_plain_info_entry "SIM Slot" "$sim_slot" "SIM Slot" + add_plain_info_entry "SIM Number" "$sim_number" "SIM Number" + add_plain_info_entry "IMEI" "$imei" "International Mobile Equipment Identity" + add_plain_info_entry "IMSI" "$imsi" "International Mobile Subscriber Identity" +} + +function base_info(){ + #Name(名称) + at_command="AT+CGMM" + name=$(at $at_port $at_command | grep -v "OK" | sed -n '2p' | sed 's/\r//g') + #Manufacturer(制造商) + at_command="AT+CGMI" + manufacturer=$(at $at_port $at_command | sed -n '2p' | sed 's/\r//g') + #Revision(固件版本) + at_command="ATI" + revision=$(at $at_port $at_command | grep "Revision:" | sed 's/Revision: //g' | sed 's/\r//g') + # at_command="AT+CGMR" + # revision=$(at $at_port $at_command | sed -n '2p' | sed 's/\r//g') + class="Base Information" + add_plain_info_entry "manufacturer" "$manufacturer" "Manufacturer" + add_plain_info_entry "revision" "$revision" "Revision" + add_plain_info_entry "at_port" "$at_port" "AT Port" + get_connect_status + _get_temperature +} + +function network_info() { + class="Network Information" + at_command="AT^SYSINFOEX" + res=$(at $at_port $at_command | grep "\^SYSINFOEX:" | awk -F'"' '{print $4}') + _parse_gstatus "$res" +} + +function _get_lockband_nr(){ + local bandcfg=$(at $at_port "AT!BAND?") + local bandtemplate=$(at $at_port "AT!BAND=?") + local start_flag=0 + IFS=$'\n' + for line in $bandtemplate; do + if [ "$start_flag" = 0 ];then + if [ "${line:0:10}" == "Available:" ];then + start_flag=1 + fi + continue + else + + if [ "${line:0:2}" == "OK" ];then + break + fi + fi + type_line=$(echo $line | grep '[0-9]* - .*:') + if [ -n "$type_line" ]; then + type=$(echo $line | grep -o '[0-9]* - .*:') + type=${type:4:-1} + json_add_object $type + json_add_array "available_band" + json_close_array + json_add_array "lock_band" + json_close_array + json_close_object + elif [ -n "$line" ]; then + band_name=${line##*-} + band_name=$(echo $band_name | xargs) + [ -z "$band_name" ] && continue + case $type in + "GW") + band_hex=${line%%-*} + band_bin=$(echo "obase=2; ibase=16; $band_hex" | bc) + band_id=$(echo $band_bin | wc -c) + band_id=$(($band_id - 1)) + ;; + *) + band_id=$(echo $band_name |grep -o '^[BbNn][0-9]*' | grep -o '[0-9]*') + ;; + esac + json_select $type + json_select "available_band" + add_avalible_band_entry $band_id ${type}_${band_name} + json_close_array + json_close_object + fi + + done + for line in $bandcfg; do + cfg_line=$(echo $line | grep '[0-9]* - ') + if [ -n "$cfg_line" ]; then + type=$(echo $cfg_line | cut -d' ' -f3) + type=${type:0:-1} + low_band=${cfg_line:11:16} + high_band=${cfg_line:28:16} + json_select $type + json_select "lock_band" + _mask_to_band _add_lock_band $low_band $high_band + json_select ".." + json_select ".." + fi + done + + unset IFS +} + +function _set_lockband_nr(){ + case $band_class in + "GW") + band_class=0 + ;; + "LTE") + band_class=1 + ;; + "NRNSA") + band_class=3 + ;; + "NRSA") + band_class=4 + ;; + esac + bandlist=$(_band_list_to_mask $lock_band) + [ "$band_class" -eq 0 ] && bandlist=${bandlist:0:16} + cmd="AT!BAND=0F,1,\"Custom\",$band_class,${bandlist}" + res=$(at $at_port "$cmd" | xargs) + if [ "$res" == "OK" ]; then + set_lockband="AT!BAND=0F" + else + set_lockband="AT!BAND=00" + fi + r=$(at $at_port "$set_lockband") + json_add_string "result" "$res" + json_add_string "cmd" "$cmd" +} + +function _get_temperature(){ + response=$(at $at_port "AT^CHIPTEMP?" | grep "\^CHIPTEMP" | awk -F',' '{print $6}' | sed 's/\r//g' ) + + local temperature + [ -n "$response" ] && { + response=$(awk "BEGIN{ printf \"%.2f\", $response / 10 }" | sed 's/\.*0*$//') + add_plain_info_entry "temperature" "$response $(printf "\xc2\xb0")C" "Temperature" + } +} + +function _add_avalible_band(){ + add_avalible_band_entry $1 $1 +} + +function _add_lock_band(){ + json_add_string "" $1 +} + +function _mask_to_band() +{ + func=$1 + low_band=$2 + high_band=$3 + low_band=$(echo "obase=2; ibase=16; $low_band" | bc) + low_band=$(printf "%064s" $low_band) + for i in $(seq 1 64); do + if [ "${low_band: -$i:1}" = "1" ]; then + band=$i + $func $band + fi + done + [ -z "$high_band" ] && return + high_band=$(echo "obase=2; ibase=16; $high_band" | bc) + high_band=$(printf "%064s" $high_band) + for i in $(seq 1 64); do + if [ "${high_band: -$i:1}" = "1" ]; then + band=$((64+i)) + $func $band + fi + done + +} + +function _band_list_to_mask() +{ + local band_list=$1 + local low=0 + local high=0 + #以逗号分隔 + IFS="," + for band in $band_list;do + if [ "$band" -le 64 ]; then + #使用bc计算2的band次方 + res=$(echo "2^($band-1)" | bc) + low=$(echo "$low+$res" | bc) + + else + tmp_band=$((band-64)) + res=$(echo "2^($tmp_band-1)" | bc) + high=$(echo "$high+$res" | bc) + fi + done + #十六进制输出,padding到16位 + low=$(printf "%016x" $low) + high=$(printf "%016x" $high) + echo "$low,$high" +} + +function _parse_gstatus(){ +data=$1 +IFS=$'\t\r\n' +for line in $data;do + line=${line//[$'\t\r\n']} + key=${line%%:*} + value=${line##*:} + key=${key} + #trim space at value + value=$(echo $value | xargs) + if [ -z "$value" ] || [ "$value" = "---" ]; then + continue + fi + + + case $key in + OK) + continue + ;; + *SINR*) + add_bar_info_entry "SINR" "$value" "$key" -23 40 dB + ;; + *RSRP*) + case $key in + *NR5G*) + add_bar_info_entry "NR5G RSRP" "$value" "$key" -187 -29 dBm + ;; + *) + add_bar_info_entry "RSRP" "$value" "$key" -140 -44 dBm + ;; + esac + ;; + *RSRQ*) + case $key in + *NR5G*) + add_bar_info_entry "NR5G RSRQ" "$value" "$key" -43 20 dBm + ;; + *) + add_bar_info_entry "RSRQ" "$value" "$key" -20 20 dBm + ;; + esac + ;; + *RSSI*) + add_bar_info_entry "RSSI" "$value" "$key" -140 -44 dBm + ;; + *) + add_plain_info_entry $key $value $key + ;; + esac + +done +unset IFS +} +