]> git.ipfire.org Git - people/stevee/network.git/blame - src/functions/functions.modem
network fix parameter passing when using ""
[people/stevee/network.git] / src / functions / functions.modem
CommitLineData
6c74a64c
MT
1#!/bin/bash
2###############################################################################
3# #
4# IPFire.org - A linux based firewall #
5# Copyright (C) 2012 IPFire Network Development Team #
6# #
7# This program is free software: you can redistribute it and/or modify #
8# it under the terms of the GNU General Public License as published by #
9# the Free Software Foundation, either version 3 of the License, or #
10# (at your option) any later version. #
11# #
12# This program is distributed in the hope that it will be useful, #
13# but WITHOUT ANY WARRANTY; without even the implied warranty of #
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15# GNU General Public License for more details. #
16# #
17# You should have received a copy of the GNU General Public License #
18# along with this program. If not, see <http://www.gnu.org/licenses/>. #
19# #
20###############################################################################
21
22# Exit codes from the chat(8) command:
23CHAT_OK=0
24CHAT_INVALID=1
25CHAT_ERROR=2
26CHAT_TIMEOUT=3
27
1c6a4e30 28modem_chat() {
6c74a64c
MT
29 local answer="OK"
30 local device
31 local timeout=2
32 local quiet="false"
33
34 while [ $# -gt 0 ]; do
35 case "${1}" in
36 --timeout=*)
2212045f 37 timeout=$(cli_get_val "${1}")
6c74a64c
MT
38 ;;
39 --answer=*)
2212045f 40 answer=$(cli_get_val "${1}")
6c74a64c
MT
41 ;;
42 --quiet)
43 quiet="true"
44 ;;
45 *)
46 device=${1}
47 shift; break
48 ;;
49 esac
50 shift
51 done
52
53 assert serial_exists ${device}
6c74a64c
MT
54 assert isset answer
55 assert isset timeout
56
57 local command=$@
58
59 log DEBUG "Sending command to ${device}: ${command}"
60
61 (
62 # This cannot be run with -x.
63 set +x 2>/dev/null
64
65 chat -V -s -t ${timeout} "" "${command}" "${answer}" \
66 < ${device} > ${device} || exit $?
67 print # Print line feed.
68 ) 2>&1 | __modem_chat_process_output "${answer}" ${quiet}
69
70 local ret=${PIPESTATUS[0]}
71
72 # Return the exit code of the chat command.
73 case "${ret}" in
74 ${CHAT_OK})
75 return ${EXIT_OK}
76 ;;
77
78 # When the timeout condition hit, the expected string has not
79 # been received in the given amount of time.
80 ${CHAT_TIMEOUT}|${CHAT_ERROR})
81 return ${EXIT_ERROR}
82 ;;
83
84 ${CHAT_INVALID})
85 return ${EXIT_CONF_ERROR}
86 ;;
87 esac
88
89 log WARNING "Received unknown exit code from chat(8): ${ret}"
90 return ${EXIT_ERROR}
91}
92
1c6a4e30 93__modem_chat_process_output() {
6c74a64c
MT
94 local answer=${1}
95 local quiet=${2}
96
97 if enabled quiet; then
98 # Just throw everything away.
99 cat >/dev/null
100 return ${EXIT_OK}
101 fi
102
103 local counter=0
104
105 local line
daa5599a 106 while read -r line; do
6c74a64c
MT
107 # Also skip empty lines.
108 [ -n "${line}" ] || continue
109
110 # Ignore all volatile messages.
111 [ "${line:0:1}" = "^" ] && continue
112
daa5599a 113 log DEBUG "Output[${counter}]: ${line}"
6c74a64c
MT
114 counter=$(( ${counter} + 1 ))
115
116 # Skip the first line, because that's out command.
117 [ ${counter} -eq 1 ] && continue
118
119 # Filter out the expected answer.
120 [ "${line}" = "${answer}" ] && continue
121
122 # Print the rest.
123 print "${line}"
124 done
125}
126
1c6a4e30 127modem_initialize() {
95416c1e
MT
128 local device="${1}"
129 assert isset device
3255c894
MT
130 shift
131
132 # Sleep for $sleep seconds, to give
133 # the modem a moment to initialize itself.
134 local sleep=1
135
136 while [ $# -gt 0 ]; do
137 case "${1}" in
138 --sleep=*)
139 sleep="$(cli_get_val "${1}")"
140 ;;
141 *)
142 warning "Unrecognized argument: ${1}"
143 ;;
144 esac
145 shift
146 done
147 assert isinteger sleep
95416c1e
MT
148
149 log INFO "Initializing modem ${device}"
150
151 # Reset the modem.
152 modem_chat "${device}" "${AT_INITIALIZE}"
3255c894
MT
153
154 # Wait...
155 if [ ${sleep} -gt 0 ]; then
156 sleep ${sleep}
157 fi
95416c1e
MT
158}
159
6c74a64c
MT
160# Exit codes of the sim_status function.
161EXIT_SIM_READY=0
162EXIT_SIM_PIN=1
163EXIT_SIM_PUK=2
164EXIT_SIM_UNKNOWN=3
165
1c6a4e30 166modem_sim_status() {
6c74a64c
MT
167 local device=${1}
168 assert isset device
169
170 local output
171 output=$(modem_chat ${device} "AT+CPIN?")
172 assert_check_retval $?
173
174 # Strip leading +CPIN: from the output.
175 output=${output#*: }
176
177 case "${output}" in
178 "READY")
179 log DEBUG "${device}'s SIM is unlocked or doesn't need a PIN."
180 return ${EXIT_SIM_READY}
181 ;;
182 "SIM PIN")
183 log DEBUG "${device}'s SIM is waiting for a PIN."
184 return ${EXIT_SIM_PIN}
185 ;;
186 "SIM PUK")
187 log DEBUG "${device}'s SIM is PUK locked."
188 return ${EXIT_SIM_PUK}
189 ;;
190 esac
191
192 log WARNING "${device}: Invalid output of the AT+CPIN? command."
193 return ${EXIT_SIM_UNKNOWN}
194}
195
1c6a4e30 196modem_sim_unlocked() {
6c74a64c
MT
197 local device=${1}
198 assert isset device
199
200 modem_sim_status "${device}"
201 local ret=$?
202
203 [ ${ret} -eq ${EXIT_SIM_READY} ] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
204}
205
1c6a4e30 206modem_sim_locked() {
2212045f 207 modem_sim_unlocked "$@" && return ${EXIT_FALSE} || return ${EXIT_TRUE}
6c74a64c
MT
208}
209
1c6a4e30 210modem_sim_unlock() {
6c74a64c
MT
211 local device=${1}
212 assert isset device
213
214 local pin=${2}
215 assert isset pin
216
217 local command="AT+CPIN=${pin}"
218
219 local new_pin=${3}
220 if isset new_pin; then
221 command="${command},${new_pin}"
222 fi
223
224 modem_chat --timeout=2 --quiet "${device}" "${command}"
225
226 local ret=$?
227 case "${ret}" in
228 ${EXIT_OK})
229 log INFO "Successfully unlocked SIM card on ${device}."
230 ;;
231 *)
232 log ERROR "Could not unlock SIM card on ${device}."
233 ret=${EXIT_ERROR}
234 ;;
235 esac
236
237 return ${ret}
238}
239
1c6a4e30 240modem_sim_auto_unlock() {
95416c1e
MT
241 local device="${1}"
242 assert isset device
243
244 local pin="${2}"
245 assert isset pin
246
247 # Get the current state the SIM card is in.
248 modem_sim_status "${device}" &>/dev/null
249 local sim_status_code=$?
250
251 case "${sim_status_code}" in
252 ${EXIT_SIM_READY})
253 # Everything's fine. The SIM card is
254 # already unlocked.
255 return ${EXIT_OK}
256 ;;
257 ${EXIT_SIM_PIN})
258 # Try to unlock the device.
259 if modem_sim_unlock ${device} ${pin}; then
260 return ${EXIT_OK}
261 else
262 return ${EXIT_ERROR}
263 fi
264 ;;
265 ${EXIT_SIM_PUK})
266 log ERROR "SIM card is PUK locked. Please unlock manually."
267 return ${EXIT_ERROR}
268 ;;
269 esac
270
271 return ${EXIT_ERROR}
272}
273
6c74a64c
MT
274# Returns the vendor of the modem.
275# For example: "huawei"
1c6a4e30 276modem_get_manufacturer() {
6c74a64c
MT
277 local device=${1}
278 assert isset device
279
280 local output
281 output=$(modem_chat ${device} "AT+GMI")
282 assert_check_retval $?
283
284 [ "${output:0:1}" = "+" ] && output=${output#*: }
285 output=${output//\"/}
286
287 print "${output}"
288}
289
1c6a4e30 290modem_get_model() {
6c74a64c
MT
291 local device=${1}
292 assert isset device
293
294 local output
295 output=$(modem_chat ${device} "AT+GMM")
296 assert_check_retval $?
297
298 [ "${output:0:1}" = "+" ] && output=${output#*: }
299 output=${output//\"/}
300
301 print "${output}"
302}
303
1c6a4e30 304modem_get_software_version() {
6c74a64c
MT
305 local device=${1}
306 assert isset device
307
308 local output
309 output=$(modem_chat ${device} "AT+GMR")
310 assert_check_retval $?
311
312 [ "${output:0:1}" = "+" ] && output=${output#*: }
313 output=${output//\"/}
314
315 print "${output}"
316}
317
1c6a4e30 318modem_get_sim_imsi() {
6c74a64c
MT
319 local device=${1}
320 assert isset device
321
6c74a64c
MT
322 modem_chat ${device} "AT+CIMI"
323}
324
1c6a4e30 325modem_get_device_imei() {
6c74a64c
MT
326 local device=${1}
327 assert isset device
328
329 local output
330 output=$(modem_chat --timeout=1 ${device} "AT+CGSN") || assert_check_retval $?
331 local ret=$?
332
333 if [ ${ret} -eq ${EXIT_OK} ]; then
334 print "${output}"
335 fi
336
337 return ${ret}
338}
339
1c6a4e30 340modem_is_mobile() {
6c74a64c
MT
341 local device=${1}
342 assert isset device
343
344 # Check if the device can return it's IMEI.
345 # If not, it's probably a serial 56k modem or something
346 # in that category.
347
348 modem_get_device_imei ${device} &>/dev/null
349}
350
36aeb387
MT
351modem_mobile_network_status() {
352 local device="${1}"
353 assert isset device
354
355 local ident="${2}"
356 isset ident || ident=1
357
358 cli_headline "${ident}" "Network status"
359
360 modem_sim_status ${device} &>/dev/null
361 local sim_status_code=$?
362
363 local sim_status="unknown"
364 case "${sim_status_code}" in
365 ${EXIT_SIM_READY})
366 sim_status="SIM ready"
367 ;;
368 ${EXIT_SIM_PIN})
369 sim_status="PIN locked"
370 ;;
371 ${EXIT_SIM_PUK})
372 sim_status="PUK locked"
373 ;;
374 esac
375 cli_print_fmt1 "${ident}" "SIM status" "${sim_status}"
376
377 if [ ${sim_status_code} -eq ${EXIT_SIM_READY} ]; then
378 cli_print_fmt1 "${ident}" "Network Registration" \
379 "$(modem_get_network_registration ${device})"
380 cli_print_fmt1 "${ident}" "Operator" \
381 "$(modem_get_network_operator ${device})"
382 cli_print_fmt1 "${ident}" "Mode" \
383 "$(modem_get_network_mode ${device})"
384 cli_print_fmt1 "${ident}" "IMSI" \
385 "$(modem_get_sim_imsi ${device})"
386 cli_print_fmt1 "${ident}" "Signal quality" \
387 "$(modem_get_signal_quality ${device}) dBm"
388
389 local ber=$(modem_get_bit_error_rate ${device})
390 isset ber || ber="unknown"
391 cli_print_fmt1 "${ident}" "Bit Error Rate" "${ber}"
392 fi
393
394 return ${EXIT_OK}
395}
396
6c74a64c
MT
397# Exit codes of the network registration function.
398EXIT_REG_REGISTERED_TO_HOME_NETWORK=0
399EXIT_REG_NOT_REGISTERED_NOT_SEARCHING=1
400EXIT_REG_NOT_REGISTERED_SEARCHING=2
401EXIT_REG_REGISTRATION_DENIED=3
402EXIT_REG_REGISTERED_ROAMING=4
403EXIT_REG_UNKNOWN=5
404
1c6a4e30 405modem_get_network_registration() {
6c74a64c
MT
406 local device=${1}
407 assert isset device
408
6c74a64c
MT
409 local output
410 output=$(modem_chat ${device} "AT+CREG?")
411 assert_check_retval $?
412
413 # Cut out unneeded parts of the message.
414 output=${output#*: }
415
416 case "${output}" in
417 [0-2],[0-5])
418 local status=${output%,*}
419
420 # The status variable must be zero.
421 [ ${status} -ne 0 ] && break
422
423 local stat=${output#*,}
424 case "${stat}" in
425 0)
d3096443 426 print "Registered"
6c74a64c
MT
427 return ${EXIT_REG_NOT_REGISTERED_NOT_SEARCHING}
428 ;;
429 1)
d3096443 430 print "Registered to home network"
6c74a64c
MT
431 return ${EXIT_REG_REGISTERED_TO_HOME_NETWORK}
432 ;;
433 2)
d3096443 434 print "Registered, Searching"
6c74a64c
MT
435 return ${EXIT_REG_NOT_REGISTERED_SEARCHING}
436 ;;
437 3)
d3096443 438 print "Registration denied"
6c74a64c
MT
439 return ${EXIT_REG_REGISTRATION_DENIED}
440 ;;
441 5)
d3096443 442 print "Registered, Roaming"
6c74a64c
MT
443 return ${EXIT_REG_REGISTERED_ROAMING}
444 ;;
445 *)
d3096443 446 print "Unknown"
6c74a64c
MT
447 return ${EXIT_REG_UNKNOWN}
448 ;;
449 esac
450 ;;
451 esac
452
453 # Apparently the output of the CREG? command was not in
454 # the right format. The modem will be tried to be set to the
455 # right mode.
456
457 modem_set_network_registration ${device} 0
458 modem_get_network_registration ${device}
459}
460
1c6a4e30 461modem_set_network_registration() {
6c74a64c
MT
462 local device=${1}
463 assert isset device
464
6c74a64c
MT
465 local mode=${2}
466 assert isset mode
467
468 modem_chat ${device} "AT+CREG=${mode}"
469}
470
1c6a4e30 471modem_scan_networks() {
6c74a64c
MT
472 local device=${1}
473 assert isset device
474
6c74a64c
MT
475 local output
476 output=$(modem_chat --timeout=60 ${device} "AT+COPS=?")
477 assert_check_retval $?
478
479 output=${output#*: }
480
481 # XXX the output is not very nice to parse.
482}
483
1c6a4e30 484__modem_get_network_operator() {
6c74a64c
MT
485 local device=${1}
486 assert isset device
487
6c74a64c
MT
488 local argument=${2}
489 assert isset argument
490
491 local output
492 output=$(modem_chat ${device} "AT+COPS?")
493 assert_check_retval $?
494
495 output=${output#*: }
c5feadb0
MT
496 output=${output//,/ }
497
498 local arg mode format operator act
499 local i=0
500 while read -r arg; do
501 case "${i}" in
502 0)
503 mode="${arg}"
504 ;;
505 1)
506 format="${arg}"
507 ;;
508 2)
509 operator="$(strip ${arg})"
510 ;;
511 3)
512 act="${arg}"
513 ;;
514 *)
515 break
516 ;;
517 esac
518 i="$(( ${i} + 1 ))"
519 done <<< "$(args ${output})"
6c74a64c
MT
520
521 print "${!argument}"
522 return ${EXIT_OK}
523}
524
1c6a4e30 525modem_get_network_operator() {
6c74a64c
MT
526 local device=${1}
527 assert isset device
528
529 __modem_get_network_operator ${device} operator
530}
531
532# Exit codes of the network operator mode function.
533EXIT_OPMODE_GSM=0
534EXIT_OPMODE_COMPACTGSM=1
aa6a4e88
MT
535EXIT_OPMODE_UMTS=2
536EXIT_OPMODE_GSM_WITH_EGPRS=3
6c74a64c
MT
537EXIT_OPMODE_UMTS_WITH_HSDPA=4
538EXIT_OPMODE_UMTS_WITH_HSUPA=5
539EXIT_OPMODE_UMTS_WITH_HSDPA_AND_HSUPA=6
aa6a4e88
MT
540EXIT_OPMODE_LTE=7
541EXIT_OPMODE_UNKNOWN=8
6c74a64c 542
1c6a4e30 543modem_get_network_mode() {
6c74a64c
MT
544 local device=${1}
545 assert isset device
546
547 local output
548 output=$(__modem_get_network_operator ${device} act)
549 assert_check_retval $?
550
551 case "${output}" in
552 0)
553 print "GSM"
554 return ${EXIT_OPMODE_GSM}
555 ;;
556 1)
557 print "Compact GSM"
558 return ${EXIT_OPMODE_COMPACTGSM}
559 ;;
560 2)
561 print "UMTS"
562 return ${EXIT_OPMODE_UMTS}
563 ;;
564 3)
aa6a4e88
MT
565 print "EDGE (GSM+EGPRS)"
566 return ${EXIT_OPMODE_GSM_WITH_EGPRS}
6c74a64c
MT
567 ;;
568 4)
aa6a4e88
MT
569 print "UMTS +HSDPA"
570 return ${EXIT_OPMODE_UMTS_WITH_HSDPA}
6c74a64c
MT
571 ;;
572 5)
aa6a4e88
MT
573 print "UMTS +HSUPA"
574 return ${EXIT_OPMODE_UMTS_WITH_HSUPA}
575 ;;
576 6)
577 print "UMTS +HSDPA +HSUPA"
6c74a64c
MT
578 return ${EXIT_OPMODE_UMTS_WITH_HSDPA_AND_HSUPA}
579 ;;
aa6a4e88
MT
580 7)
581 print "LTE"
582 return ${EXIT_OPMODE_LTE}
583 ;;
6c74a64c
MT
584 *)
585 print "Unknown"
586 return ${EXIT_OPMODE_UNKNOWN}
587 ;;
588 esac
589}
590
1c6a4e30 591__modem_get_signal_quality() {
6c74a64c
MT
592 local device=${1}
593 assert isset device
594
6c74a64c
MT
595 local argument=${2}
596 assert isset argument
597
598 local output
599 output=$(modem_chat ${device} "AT+CSQ")
600 assert_check_retval $?
601
602 output=${output#*: }
603
604 case "${output}" in
605 *,*)
fbf647ae 606 local asu=${output%,*}
6c74a64c
MT
607 local ber=${output#*,}
608
609 print "${!argument}"
610 return ${EXIT_OK}
611 ;;
612 *)
613 log ERROR "Unknown format for AT+CSQ: ${device}: ${output}"
614 ;;
615 esac
616
617 return ${EXIT_ERROR}
618}
619
fbf647ae
MT
620__modem_rssi_to_dbm() {
621 local rssi="${1}"
622
623 # 99 indicates unknown signal strength
624 [ ${rssi} -eq 99 ] && return ${EXIT_UNKNOWN}
625
626 print "$(( ${rssi} * 2 - 113 ))"
627 return ${EXIT_OK}
628}
629
630__modem_rscp_to_dbm() {
631 local rscp="${1}"
632
633 # 255 indicates unknown signal strength
634 [ ${rscp} -eq 255 ] && return ${EXIT_UNKNOWN}
635
636 print "$(( ${rscp} - 116 ))"
637 return ${EXIT_OK}
638}
639
640__modem_rsrp_to_dbm() {
641 local rsrp="${1}"
642
643 case "${rsrp}" in
644 0)
645 print "< -140"
646 ;;
647 97)
648 print "> -44"
649 ;;
650 *)
651 # This is only an approximation since RSRP references
652 # to a range of +/-1dbm
653 print "$(( ${rsrp} - 141 ))"
654 ;;
655 esac
656
657 return ${EXIT_OK}
658}
659
1c6a4e30 660modem_get_signal_quality() {
6c74a64c
MT
661 local device=${1}
662 assert isset device
663
fbf647ae
MT
664 # Arbritrary Strength Unit
665 local asu
666 asu=$(__modem_get_signal_quality ${device} asu)
6c74a64c
MT
667 assert_check_retval $?
668
fbf647ae 669 isset asu || return ${EXIT_ERROR}
6c74a64c 670
fbf647ae 671 local network_mode="$(modem_get_network_mode ${device} &>/dev/null; echo $?)"
6c74a64c 672
fbf647ae
MT
673 local ret
674 case "${network_mode}" in
675 # GSM
676 ${EXIT_OPMODE_GSM}|${EXIT_OPMODE_COMPACTGSM}|${GSM_WITH_EGPRS})
677 __modem_rssi_to_dbm "${asu}"
678 ret=${?}
679 ;;
6c74a64c 680
fbf647ae
MT
681 # UMTS
682 ${EXIT_OPMODE_UMTS}|${EXIT_OPMODE_UMTS_WITH_HSDPA}|${EXIT_OPMODE_UMTS_WITH_HSUPA}|${EXIT_OPMODE_UMTS_WITH_HSDPA_AND_HSUPA})
683 __modem_rscp_to_dbm "${asu}"
684 ret=${?}
685 ;;
686
687 # LTE
688 ${EXIT_OPMODE_LTE})
689 __modem_rsrp_to_dbm "${asu}"
690 ret=${?}
691 ;;
692
693 # unknown
694 *)
695 ret=${EXIT_ERROR}
696 ;;
697 esac
698
699 return ${ret}
6c74a64c
MT
700}
701
1c6a4e30 702modem_get_bit_error_rate() {
6c74a64c
MT
703 local device=${1}
704 assert isset device
705
706 local ber
707 ber=$(__modem_get_signal_quality ${device} ber)
708 assert_check_retval $?
709
710 isset ber || return ${EXIT_ERROR}
711
712 # 99 indicates that the bit error rate could not be detected or
713 # is unknown for some other reason.
714 [ ${ber} -eq 99 ] && return ${EXIT_UNKNOWN}
715
716 print "%d" "${ber}"
717 return ${EXIT_OK}
718}
5cf0edf9
MT
719
720# USDD stuff
721
1c6a4e30 722modem_ussd_send_command() {
5cf0edf9
MT
723 local device="${1}"
724 assert isset device
725
726 local command="${2}"
727 assert isset command
728 shift 2
729
730 local cleartext="false"
731 local timeout="20"
732
733 while [ $# -gt 0 ]; do
734 case "${1}" in
735 --cleartext)
736 cleartext="true"
737 ;;
738 --timeout=*)
739 timeout="$(cli_get_val "${1}")"
740 ;;
741 *)
742 warning "Unrecognized argument: ${1}"
743 ;;
744 esac
745 shift
746 done
747
748 local encoded_command="${command}"
749 if ! enabled cleartext; then
750 encoded_command="$(modem_ussd_encode "${command}")"
751 fi
752
753 log INFO "Sending USSD command '${command}' on ${device}"
754
755 local at_command="AT+CUSD=1,\"${encoded_command}\",${encoding}"
756
757 # Send the AT command and parse the output.
758 modem_chat --answer="nothing" --timeout="${timeout}" \
759 "${device}" "${at_command}" | __modem_ussd_parse_output
760
761 local ret=${PIPESTATUS[1]}
762 return ${ret}
763}
764
1c6a4e30 765__modem_ussd_parse_output() {
5cf0edf9
MT
766 local line
767 while read -r line; do
768 # Find the expected answer.
769 [ "${line:0:7}" = "+CUSD: " ] || continue
770
771 # Strip +CUSD:
772 line="${line:7}"
773
774 local response_type
775 local response
776 local response_encoding
777
778 line="${line//,/ }"
779
780 local section=0 arg
781 while read -r arg; do
782 case "${section}" in
783 0)
784 response_type="${arg}"
785 ;;
786 1)
787 response="${arg}"
788 ;;
789 2)
790 response_encoding="${arg}"
791 ;;
792 *)
793 break
794 ;;
795 esac
796 section=$(( ${section} + 1 ))
797 done <<< "$(args ${line})"
798
799 log DEBUG "USSD response type: ${response_type}"
800 log DEBUG "USSD response encoding: ${response_encoding}"
801 log DEBUG "USSD encoded response: ${response}"
802
803 # If we got anything else than a response (type 0),
804 # we don't know how to handle that.
805 if [ "${response_type}" -ne "0" ]; then
806 return ${EXIT_ERROR}
807 fi
808
809 # Decode the string if needed.
810 case "${response_encoding}" in
811 15)
812 response="$(modem_ussd_decode "${response}")"
813 ;;
814 esac
815 log DEBUG "USSD response: ${response}"
816
817 print "${response}"
818 return ${EXIT_OK}
819 done
820
821 return ${EXIT_ERROR}
822}
823
1c6a4e30 824modem_ussd_encode() {
5cf0edf9
MT
825 local string="${1}"
826 assert isset string
827
828 local output buffer char
829 while read -r char; do
830 char="$(char2bin "${char}")"
831 char="$(string_reverse "${char:1:7}")"
832
833 buffer="${buffer}${char}"
834 done <<< "$(string_split "${string}")"
835
836 local pos=0 len=8
837 while [ ${pos} -lt ${#buffer} ]; do
838 char="$(string_reverse "${buffer:${pos}:${len}}")"
839 pos=$(( ${pos} + ${len} ))
840
841 char="$(bin2hex "${char}")"
842 output="${output}${char}"
843 done
844
845 # Make everything uppercase.
846 output="${output^^}"
847
848 print "${output}"
849}
850
1c6a4e30 851modem_ussd_decode() {
5cf0edf9
MT
852 local string="${1}"
853 assert isset string
854
855 local buffer1 buffer2
856 local output char
857
858 local pos=0 len=2
859 while [ ${pos} -lt ${#string} ]; do
860 char="${string:${pos}:${len}}"
861 pos=$(( ${pos} + ${len} ))
862
863 char="$(hex2bin "${char}")"
864 char="$(string_reverse "${char}")"
865 buffer1="${buffer1}${char}"
866 done
867
868 # Reset pointers.
869 pos=0
870 len=7
871
872 while [ ${pos} -lt ${#buffer1} ]; do
873 char="${buffer1:${pos}:${len}}"
874 pos=$(( ${pos} + ${len} ))
875
876 buffer2="${buffer2}0${char}"
877 done
878 buffer2="${buffer2:1}"
879
880 # Reset pointers again.
881 pos=0
882 len=8
883
884 while [ ${pos} -lt ${#buffer2} ]; do
885 char="${buffer2:${pos}:${len}}"
886 pos=$(( ${pos} + ${len} ))
887
888 char="$(string_reverse "${char}")"
889 char="$(bin2char "${char}")"
890 output="${output}${char}"
891 done
892
893 print "${output}"
894 return ${EXIT_OK}
895}