#!/bin/sh # Copyright (C) 2025 Fujr _Vendor="sierra" _Author="Fujr" _Maintainer="Fujr " source /usr/share/qmodem/generic.sh debug_subject="quectel_ctrl" function unlock_advance(){ [ -z "$sierra_pass" ] && sierra_pass="A710" at $at_port "AT!ENTERCND=\"$sierra_pass\"" > /dev/null } 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+EGMR=1,7,\"$imei\"" } function get_mode(){ cfg=$(at $at_port "AT!USBCOMP?") config_type=`echo -e "$cfg" | grep -o 'Config Type: [0-9]'` config_type=${config_type:14} interface_mask=`echo -e "$cfg" | grep -o 'Interface bitmask: [0-9a-fA-F]*'` interface_mask=${interface_mask:18} _mask_to_mode $interface_mask if [ "$mbim_port" = "1" ]; then mode="mbim" elif [ "$rmnet_port" = "1" ]; then mode="rmnet" fi 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 case $mode in "mbim") interface_mask=0x00001009 ;; "rmnet") interface_mask=0x00000109 ;; *) echo "Invalid mode" return 1 ;; esac at $at_port "AT!USBCOMP=1,4,$interface_mask" } function get_network_prefer(){ res=$(at $at_port "at!SELRAT?"| grep -o "!SELRAT: [0-9A-Fa-f]*") # (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 code=${res:9} local network_prefer_3g="0" local network_prefer_4g="0" local network_prefer_5g="0" case $code in "00") network_prefer_3g="1" network_prefer_4g="1" network_prefer_5g="1" ;; "01") network_prefer_3g="1" ;; "06") network_prefer_4g="1" ;; "20") network_prefer_5g="1" ;; "11") network_prefer_3g="1" network_prefer_4g="1" ;; "21") network_prefer_4g="1" network_prefer_5g="1" ;; "22") network_prefer_3g="1" network_prefer_5g="1" ;; *) network_prefer_3g="0" network_prefer_4g="0" network_prefer_5g="0" ;; esac 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="01" elif [ "$network_prefer_4g" = "true" ]; then code="06" elif [ "$network_prefer_5g" = "true" ]; then code="20" fi ;; "2") if [ "$network_prefer_3g" = "true" ] && [ "$network_prefer_4g" = "true" ]; then code="11" elif [ "$network_prefer_4g" = "true" ] && [ "$network_prefer_5g" = "true" ]; then code="21" elif [ "$network_prefer_3g" = "true" ] && [ "$network_prefer_5g" = "true" ]; then code="22" fi ;; "3") code="00" ;; *) code="00" ;; esac res=$(at $at_port "AT!SELRAT=$code") json_add_string "code" "$code" json_add_string "result" "$res" } function get_lockband(){ json_add_object "lockband" case $platform in "qualcomm") _get_lockband_nr ;; *) _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 "qualcomm") _set_lockband_nr ;; *) _set_lockband_nr ;; esac } function sim_info() { class="SIM Information" at_command="AT!UIMS?" slot=$(at $at_port $at_command | grep -o '!UIMS: [0-9]*' | grep -o '[0-9]*') sim_slot=$(($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) add_plain_info_entry "SIM Status" "$sim_status" "SIM Status" add_plain_info_entry "SIM Slot" "$sim_slot" "SIM Slot" } function base_info(){ #Name(名称) at_command="AT+CGMM" name=$(at $at_port $at_command | 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 _get_voltage } function network_info() { class="Network Information" at_command="AT!GSTATUS?" res=$(at $at_port $at_command |grep -i -v "!GSTATUS"| grep -v "OK") _parse_gstatus "$res" } function vendor_get_disabled_features(){ json_add_string "" "IMEI" json_add_string "" "NeighborCell" } 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_voltage(){ voltage=$(at $at_port "AT!PCVOLT?" | grep -o 'Power supply voltage: [0-9]* mV'|grep -o '[0-9]*' ) [ -n "$voltage" ] && { add_plain_info_entry "voltage" "$voltage mV" "Voltage" } } function _get_temperature(){ temperature=$(at $at_port "AT!PCTEMP?" | grep -o 'Temperature: [0-9]*\.[0-9]*'|grep -o '[0-9]*\.[0-9]*' ) [ -n "$temperature" ] && { add_plain_info_entry "temperature" "$temperature 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 _mask_to_mode() { mask=$1 # RmNet – 0x00000100 bin: 000100000000 # MBIM – 0x00001000 bin: 0001000000000000 hex_to_bin=$(echo "obase=2; ibase=16; $mask" | bc) #paddding to 16 bits hex_to_bin=$(printf "%016d" $hex_to_bin) adb_port=${hex_to_bin: -1} diag_port=${hex_to_bin: -2:1} modem_port=${hex_to_bin: -4:1} rmnet_port=${hex_to_bin: -9:1} mbim_port=${hex_to_bin: -13:1} } 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 } unlock_advance