print "%d" "${ber}"
return ${EXIT_OK}
}
+
+# USDD stuff
+
+function modem_ussd_send_command() {
+ local device="${1}"
+ assert isset device
+
+ local command="${2}"
+ assert isset command
+ shift 2
+
+ local cleartext="false"
+ local timeout="20"
+
+ while [ $# -gt 0 ]; do
+ case "${1}" in
+ --cleartext)
+ cleartext="true"
+ ;;
+ --timeout=*)
+ timeout="$(cli_get_val "${1}")"
+ ;;
+ *)
+ warning "Unrecognized argument: ${1}"
+ ;;
+ esac
+ shift
+ done
+
+ local encoded_command="${command}"
+ if ! enabled cleartext; then
+ encoded_command="$(modem_ussd_encode "${command}")"
+ fi
+
+ log INFO "Sending USSD command '${command}' on ${device}"
+
+ local at_command="AT+CUSD=1,\"${encoded_command}\",${encoding}"
+
+ # Send the AT command and parse the output.
+ modem_chat --answer="nothing" --timeout="${timeout}" \
+ "${device}" "${at_command}" | __modem_ussd_parse_output
+
+ local ret=${PIPESTATUS[1]}
+ return ${ret}
+}
+
+function __modem_ussd_parse_output() {
+ local line
+ while read -r line; do
+ # Find the expected answer.
+ [ "${line:0:7}" = "+CUSD: " ] || continue
+
+ # Strip +CUSD:
+ line="${line:7}"
+
+ local response_type
+ local response
+ local response_encoding
+
+ line="${line//,/ }"
+
+ local section=0 arg
+ while read -r arg; do
+ case "${section}" in
+ 0)
+ response_type="${arg}"
+ ;;
+ 1)
+ response="${arg}"
+ ;;
+ 2)
+ response_encoding="${arg}"
+ ;;
+ *)
+ break
+ ;;
+ esac
+ section=$(( ${section} + 1 ))
+ done <<< "$(args ${line})"
+
+ log DEBUG "USSD response type: ${response_type}"
+ log DEBUG "USSD response encoding: ${response_encoding}"
+ log DEBUG "USSD encoded response: ${response}"
+
+ # If we got anything else than a response (type 0),
+ # we don't know how to handle that.
+ if [ "${response_type}" -ne "0" ]; then
+ return ${EXIT_ERROR}
+ fi
+
+ # Decode the string if needed.
+ case "${response_encoding}" in
+ 15)
+ response="$(modem_ussd_decode "${response}")"
+ ;;
+ esac
+ log DEBUG "USSD response: ${response}"
+
+ print "${response}"
+ return ${EXIT_OK}
+ done
+
+ return ${EXIT_ERROR}
+}
+
+function modem_ussd_encode() {
+ local string="${1}"
+ assert isset string
+
+ local output buffer char
+ while read -r char; do
+ char="$(char2bin "${char}")"
+ char="$(string_reverse "${char:1:7}")"
+
+ buffer="${buffer}${char}"
+ done <<< "$(string_split "${string}")"
+
+ local pos=0 len=8
+ while [ ${pos} -lt ${#buffer} ]; do
+ char="$(string_reverse "${buffer:${pos}:${len}}")"
+ pos=$(( ${pos} + ${len} ))
+
+ char="$(bin2hex "${char}")"
+ output="${output}${char}"
+ done
+
+ # Make everything uppercase.
+ output="${output^^}"
+
+ print "${output}"
+}
+
+function modem_ussd_decode() {
+ local string="${1}"
+ assert isset string
+
+ local buffer1 buffer2
+ local output char
+
+ local pos=0 len=2
+ while [ ${pos} -lt ${#string} ]; do
+ char="${string:${pos}:${len}}"
+ pos=$(( ${pos} + ${len} ))
+
+ char="$(hex2bin "${char}")"
+ char="$(string_reverse "${char}")"
+ buffer1="${buffer1}${char}"
+ done
+
+ # Reset pointers.
+ pos=0
+ len=7
+
+ while [ ${pos} -lt ${#buffer1} ]; do
+ char="${buffer1:${pos}:${len}}"
+ pos=$(( ${pos} + ${len} ))
+
+ buffer2="${buffer2}0${char}"
+ done
+ buffer2="${buffer2:1}"
+
+ # Reset pointers again.
+ pos=0
+ len=8
+
+ while [ ${pos} -lt ${#buffer2} ]; do
+ char="${buffer2:${pos}:${len}}"
+ pos=$(( ${pos} + ${len} ))
+
+ char="$(string_reverse "${char}")"
+ char="$(bin2char "${char}")"
+ output="${output}${char}"
+ done
+
+ print "${output}"
+ return ${EXIT_OK}
+}
printf "%d\n" "${hex}"
}
+function chr() {
+ local char="${1}"
+
+ [ ${char} -lt 256 ] || return ${EXIT_ERROR}
+
+ printf "\\$(( ${char} / 64 * 100 + ${char} % 64 / 8 * 10 + ${char} % 8 ))\n"
+}
+
+function ord() {
+ LC_CTYPE="C" printf "%d\n" "'${1}"
+}
+
+function hex() {
+ printf "%X\n" "${1}"
+}
+
function network_is_running() {
# Check, if the network service is running.
service_is_active network
return ${EXIT_FALSE}
}
+
+function string_split() {
+ local string="$@"
+
+ local pos=0
+ while [ ${pos} -lt ${#string} ]; do
+ print "${string:${pos}:1}"
+ pos=$(( ${pos} + 1 ))
+ done
+
+ return ${EXIT_OK}
+}
+
+function string_reverse() {
+ local string="$@"
+
+ local output
+ local pos=0
+ while [ ${pos} -lt ${#string} ]; do
+ output="${string:${pos}:1}${output}"
+ pos=$(( ${pos} + 1 ))
+ done
+
+ print "${output}"
+ return ${EXIT_OK}
+}
+
+function dec2bin() {
+ local number="${1}"
+
+ local output
+
+ local i div
+ for i in 7 6 5 4 3 2 1; do
+ div=$(( 2 ** ${i} ))
+
+ if [ $(( ${number} / ${div} )) -eq 1 ]; then
+ output="${output}1"
+ else
+ output="${output}0"
+ fi
+ number="$(( ${number} % ${div} ))"
+ done
+
+ if [ $(( ${number} % 2 )) -eq 1 ]; then
+ output="${output}1"
+ else
+ output="${output}0"
+ fi
+
+ print "${output}"
+}
+
+function bin2dec() {
+ local string="${1}"
+ local number=0
+
+ local pos=0 char
+ while [ ${pos} -lt ${#string} ]; do
+ char="${string:${pos}:1}"
+ pos=$(( ${pos} + 1 ))
+
+ number=$(( ${number} << 1 ))
+
+ case "${char}" in
+ 0) ;;
+ 1)
+ number=$(( ${number} + 1 ))
+ ;;
+ *)
+ assert false "Invalid character: ${char}"
+ ;;
+ esac
+ done
+
+ print "${number}"
+ return ${EXIT_OK}
+}
+
+function char2bin() {
+ local dec="$(ord "${1}")"
+
+ dec2bin "${dec}"
+}
+
+function bin2char() {
+ local dec="$(bin2dec "$@")"
+
+ chr "${dec}"
+}
+
+function bin2hex() {
+ local dec="$(bin2dec "$@")"
+
+ dec2hex "${dec}"
+}
+
+function hex2bin() {
+ local dec="$(hex2dec "$@")"
+
+ dec2bin "${dec}"
+}
+
+function hex2dec() {
+ local hex="${1}"
+
+ # Prepend 0x if necessary.
+ [ "${hex:0:2}" = "0x" ] || hex="0x${hex}"
+
+ printf "%d\n" "${hex}"
+}
+
+function dec2hex() {
+ printf "%02x\n" "${1}"
+}
unlock)
cli_device_serial_unlock ${device} $@
;;
+ ussd)
+ cli_device_send_ussd_command "${device}" $@
+ ;;
*)
cli_show_man network-device
;;
exit $?
}
+function cli_device_send_ussd_command() {
+ local device="${1}"
+ assert isset device
+ shift
+
+ local command
+ local timeout
+
+ while [ $# -gt 0 ]; do
+ case "${1}" in
+ --timeout=*)
+ timeout="$(cli_get_val "${1}")"
+ ;;
+ *)
+ if isset command; then
+ warning "Unrecognized argument: ${1}"
+ else
+ command="${1}"
+ fi
+ ;;
+ esac
+ shift
+ done
+
+ assert device_is_serial "${device}"
+
+ local args
+ if isset timeout; then
+ args="${args} --timeout=${timeout}"
+ fi
+
+ modem_ussd_send_command "${device}" "${command}" ${args}
+ exit $?
+}
+
function cli_hostname() {
if cli_help_requested $@; then
cli_show_man network