Выполнение AT/USSD команд к /dev/ttyUSB* модему из консоли Linux
Утилиты и скрипты для коммуникации с /dev/ttyUSB* устройством из shell консоли (bash скриптов).
Теория
Отправить в /dev/ttyUSB* терминал AT команду не составляет проблем. Но результат вывода мы не увидим!
echo ATI > /dev/ttyUSB2
# или
echo ATI | sudo tee /dev/ttyUSB2
Мы можем читать поток stdout c /dev/ttyUSB2 (результат выполнения команд):
sudo cat /dev/ttyUSB2
В чем проблемы?
- Нужно получить только результат выполнения конкретной AT команды, а не весь поток вывода.
- Нужно использовать gsm7bit кодировку для кодирования параметров и получения ответа при выполнении USSD запросов:
echo AT+CUSD=1,AA182C3602,15 | sudo tee /dev/ttyUSB2
- Ну и хочется простоты в работе)
Выполнение AT/USSD команд
bash
Скрипт at.sh для отправки AT команды и получения ответа в переменную:
at.sh "AT+COPS=3,0\nAT+COPS?" /dev/ttyUSB2
#!/bin/bash
AT="$1"
TTY="$2"
SLEEP=0
RESULT=$(cat $TTY & echo -e "$AT" > $TTY; sleep $SLEEP; kill %cat)
echo $RESULT
Но вы получите ответ вида:
AT+COPS? +COPS: 0,0,"lifecell",2 OK ^BOOT:36507742,0,0,0,87 ^RSSI:3 ^RSSI:3 ^RSSI:3
minicom
Можно отправить AT команду и перенаправить весь вывод в файл:
sudo minicom -D /dev/ttyUSB2 -S ./at/carrier-name.txt -C output.txt
После этого нужно закрыть терминал и разобрать/декодировать весь вывод из файла output.txt. Не круто..
ussd.py
В сети нашел python скрипт для отправки USSD запросов (немного поправил):
ussd.py *121# /dev/ttyUSB2
122 SMS po Ukraine. 3G: 1024 MB Nomer do 01.05.18.
Скрипт ussd.py:
#!/usr/bin/python
#coding: utf8
import base64, io, tty, sys
import time
ussd = sys.argv[1]
modem = '/dev/ttyUSB5'
if len(sys.argv) > 2:
modem = sys.argv[2]
else:
modem = '/dev/ttyUSB2'
def write2p(a):
#sp.write(bytes(a + '\r\n', 'utf8'))
sp.write(a + '\r\n')
def gsm7bitencode(src):
"""
Encode ASCII text to 7-bit encoding
"""
result, count, last = [], 0, 0
for c in src:
this = ord(c) << (8 - count)
if count:
result.append('%02X' % ((last >> 8) | (this & 0xFF)))
count = (count + 1) % 8
last = this
result.append('%02x' % (last >> 8))
return ''.join(result)
def gsm7bitdecode(f):
f = ''.join(["{0:08b}".format(int(f[i:i+2], 16)) for i in range(0, len(f), 2)][::-1])
return ''.join([chr(int(f[::-1][i:i+7][::-1], 2)) for i in range(0, len(f), 7)])
###
sp = io.open(modem, 'w+b', 0)
tty.setraw(sp)
write2p('AT+CUSD=1,' + gsm7bitencode(ussd) + ',15')
###
start = time.time()
while (time.time() - start < 10):
l = sp.readline()
#print(l)
if l.startswith('+CUSD'):
ussd_response = l[10:l.rfind('"')]
response_decoded = gsm7bitdecode(ussd_response)
print(response_decoded)
break
# @note Реализация без таймаута
# @todo Нужен таймаут для прерывания ридера потока, если ничего
#for l in sp:
##print(l)
#if l.startswith('+CUSD'):
#ussd_response = l[10:l.rfind('"')]
##print(ussd_response)
#response_decoded = gsm7bitdecode(ussd_response)
#print(response_decoded)
#break
sp.close()
Кодировка GSM 7bit в USSD запросах
Кодирование в gsm7bit
При отправке USSD запросов нужно кодировать USSD-код в кодировку GSM 7bit (как я понял из-за того, что модем не поддерживает текстовый режим).
Следующие запросы вернут ERROR:
AT+CUSD=1,"*111#","15"
AT+CUSD=1,"*121#",15
Python функция gsm7bitencode для кодирования utf8 строки в gsm7bit:
def gsm7bitencode(src):
"""
Encode ASCII text to 7-bit encoding
"""
result, count, last = [], 0, 0
for c in src:
this = ord(c) << (8 - count)
if count:
result.append('%02X' % ((last >> 8) | (this & 0xFF)))
count = (count + 1) % 8
last = this
result.append('%02x' % (last >> 8))
return ''.join(result)
Примечание
Смотрите онлайн-сервис для работы с кодировками: http://smstools3.kekekasvi.com/topic.php?id=288
Пример USSD команд в кодировке 7bit gsm проверки баланса:
AT+CUSD=1,"AA582C3602",15 # *111#
AT+CUSD=1,"AA182C3602",15 # *121#
Кодированные ответы (ответ всегда приходит на устройство /dev/ttyUSB2):
+CUSD: 0,"C2303BEC9E83662E98ED2C77B340E2B7BB3E07C15C30D859EE762914",15
+CUSD: 0,"C2303BEC9E83662E98ED2C77B340E2B7BB3E07C15C30D859EE7629542A9502442CD3C3ECB40EA48AC9622317E8299687E9697A196477A7DB6177BACC02B9DFEDB21C4466E7C320B8FC6D2FCBD7699038CC0EBBE761103B6D2E8FCB6C3648158BC5460A05",15
Декодирование из gsm7bit
Python функция gsm7bitdecode для декодирования gsm7bit в utf8:
def gsm7bitdecode(f):
f = ''.join(["{0:08b}".format(int(f[i:i+2], 16)) for i in range(0, len(f), 2)][::-1])
return ''.join([chr(int(f[::-1][i:i+7][::-1], 2)) for i in range(0, len(f), 7)])
#modem, #tty, #at, #bash