ВСЕ ЗАПИСИ
Статьи,заметки
Получение СМС сообщений на компьютере и расшифровка PDU
В интернете полно примеров и документации, по вопросу как раскодировать СМС из PDU в читаемый текст, здесь я постараюсь популярно объяснить, как это реализовано в моей программе. Ссылки на исходники для Delphi XE 5 есть в конце статьи, также имеется рабочий код для Delphi 7. Архив с кучей инфы по AT командам и спецификациями PDU можно загрузить по ссылке . Там много полезного, главное правильно переварить эти сведения и не запутаться ещё больше, лично мне в процессе написания кода больше помог поиск по различным форумам и блогам.
У себя на сайте выложил несколько полезных программ для конвертирования PDU: encode_pdu, PDUDecoder, и PDU Spy, а вот мои собственные утилиты для перекодировки:
PDU Decoder - извлекает из строки PDU номер СЦ, номер телефона отправителя, время отправки и текст сообщения
PDU2TEXT Decoder- конвертирует строку символов из 7bit default alphabet или UCS2 в текст.
Архивы также содержат исходники с комментариями.
Вот пример принятого СМС сообщения, в виде шестнадцатеричной последовательности (PDU), данные которые выдает в COM порт USB модем:
07919730071111F1040B919781274894F7000861502012116121100414043E0441044204300432043A0430
Чтобы раскодировать его нужно правильно интерпретировать значения полей, которые для наглядности подкрашены различными цветами.
07 обозначает длину номера сервисного центра СМС , здесь номер это 9730071111F1 07- десятичное значение, применяем такой алгоритм: отнимаем единицу, получаем 6, шесть пар символов, это и будет номер.
Либо так: семь умножить на два = 14, минус 2, получим 12, считываем 12 одиночных символов, получаем номер СЦ.
91 следующее поле формат номера, 91 обозначает - международный, в большинстве случаев, можно сказать всегда, значение равно 91.
9730071111F1 В этом поле находится номер СЦ. Чтобы его получить, следует разбить это поле на пары по 2 символа и в каждой паре поменять символы местами: 79 03 70 11 11 1F
Если номер содержит нечётное количество цифр, в конце всегда будет символ F, удаляем его. Впереди дописываем плюс, и вот он, номер СЦ СМС: +79037011111.
Следует иметь ввиду, что номер СЦ может и вовсе отсутствовать, я нашёл у себя в телефоне такое СМС: 00000C9144977389050000004160910213250023D9775D0EBABEE56C728B5AC6D341D0A413E4AEB7C56539283D07D56C39580D - здесь первые 2 поля (4 символа) имеют нулевые значения.
04 Поле TP-MTI & Co, играет важную роль, его значение зависит от различных условий, например, включен ли на передающей стороне запрос отчета о доставке, является ли это сообщение multipart, то есть одной из частей длинного сообщения более 140 символов, разбитого на несколько частей, и др.На практике следует учитывать, что от значения этого поля зависит, есть ли в теле СМС заголовок перед пользовательскими данными, или он отсутствует, это нужно знать, чтобы определить, где в PDU находится непосредственно сам текст сообщения. В моей программе задействован следующий алгоритм: если значение поля равно 00, 04, или 24, значит заголовок отсутствует, если же значения равны 40, 44, или 64, то определяем длину заголовка, откусываем его от пользовательских данных и получаем текст сообщения.
Про заголовки будет рассказано ниже.
0B Шестнадцатеричное значение, переводим в десятичное, получаем 11. Это количество цифр в номере отправителя, если номер - цифровой, в данном примере номер содержится в этом поле 9781274894F7
Но так как, согласно правилам стандарта PDU, если количество символов номера - нечетное, то в конец добавляется символ F, значит, чтобы получить правильное значение, считываем 11+1, то есть 12 символов.
Номер также может иметь и алфавитно-цифровой формат, напр., Beeline или Tele2, тогда считываем именно указанное количесто символов в поле номера отправителя (в этом случае единицу не добавляем, даже если число нечетное). После конвертирования из 7- битной кодировки считанного значения получим имя отправителя. Вот пример сообщения от отправителя InternetSMS
07919730071111F10014D04937BD2C7797E9D3E61400086140618064750014042D0442043E002004110418041B04100419041D
В желтом поле - значение 14 в HEX (десятичное значение 20), значит 20 символов в красном поле содержат имя/номер отправителя, можно ввести его в прогу
PDU2TEXT Decoder и увидеть результат.
91 это поле обозначает тип номера, 91 - международный формат, 81 - нестандартный цифровой номер (как напр., в СМС-ках приходящих с коротких номеров), D0 - алфавитно-цифровое имя отправителя.
9781274894F7 поле, где содержится номер, с которого отправлено СМС. В данном случае, это номер в международном формате, считываем его значение, определив сколько в нем цифр, из данных прописанных в этом поле - 0B, и обрабатываем по такому же алгоритму, как и номер СЦ: разбиваем поле на пары, и меняем местами символы в каждой паре, если последний символ будет F, - удаляем его. Добавляем плюс к номеру. Для данного примера наш номер это: +79187284497
Для нестандартных номеров (тип 81) алгоритм точно такой же: вычисляем длину, меняем местами символы в парах, удаляем F, если он есть, только плюс впереди не ставим. Ниже пример сообщения от номера 679
07919740430900F340038176F90008516091206173004A0500034E020204410430043904420435002000540065006C00650032002C002004400430043704340435043B002000AB041104350437043E043F04300441043D043E04410442044C00BB
желтое поле - количество цифр (3), красное - тип номера (81), синее - сам номер (679)
Случай, когда тип номера D0 (алфавитно-цифровой) был уже разобран ранее.
00 для входящих СМС это поле всегда имеет нулевое значение, поэтому рассматривать его не буду.
08 тип кодировки СМС. Возможные значения: 08, 18 - кодировка UCS2(юникод); 00, 10 - GSM 7-bit default alphabet (латиница и спецсимволы).
61502012116121 время отправки (время, когда сообщение поступило в СЦ). Это поле всегда состоит из семи пар цифр. Алгоритм расшифровки: разбиваем на пары, в каждой паре меняем цифры местами,получим вот это:
16 05 02 21 11 16 12 , что означает: дата: 2016 г. 5-й месяц(май) 2-е число, время: 21 час 11 мин. 16 сек. часовой пояс: 12(UTC+3)
10 двухсимвольное поле, значение в шестнадцатеричном формате. Указывает длину USER DATA (пользовательские данные), в которых содержится текст сообщения. Подробно описывать это поле не буду, желающие могут почитать спецификации (ссылка есть в начале статьи). Для упрощения алгоритма в программе я считываю просто все оставшиеся после этого поля символы до конца строки, чтобы получить текст СМС, но заранее следует убедиться, что перед текстом отстутствует заголовок с дополнительными данными, иначе вместо текста получится нечитаемая мешанина из непонятных знаков
Так как значение этого поля 04 равно 04, значит в данном примере заголовка нет и можно оставшиеся символы воспринимать как текст, иначе пришлось бы сначала вычислить, где заканчивается заголовок, и отделить его от текста.
0414043E0441044204300432043A0430 это текст СМС. которое используется в примере. Так как это поле 08 означает, что сообщение использует кодировку UCS2, будем использовать соответствующую функцию
Вот пример кода для юникодных версий Delphi:
показатьА это функция, работающая в Delphi 7:
показатьВ результате получили текст СМС: Доставка
Теперь покажу алгоритм, как в поле USER DATA убрать дополнительный заголовок и найти текст сообщения.
07919730071111F1440B919781532319F200086150803152732130050003F902020424043E0440043C043004420435042D0442043E04120442043E04400430044F0427043004410442044C
Здесь видим, что поле 44 TP-MTI & Co имеет значение 44, что однозначно говорит о наличии заголовка в USER DATA. Поле 30 - длина пользовательских данных, пропускаем эти два символа, следующее поле, 05, которое я отметил розовым цветом, имеет значение 05. Оно указывает длину заголовка. Смотрим какую кодировку имеет СМС (это важно!), в этом примере у нас - 08, - кодировка юникод. Длина заголовка 05, и если кодировка СМС в юникоде, то пропускаем следующие пять пар символов, вот эти, 0003F90202, оставшиеся символы до конца строки, это и есть текст СМС
0424043E0440043C043004420435042D0442043E04120442043E04400430044F0427043004410442044C вот этот текст:ФорматеЭтоВтораяЧасть
Следующий пример
07919730071111F1440B919750814364F30000615061819575215E050003FD0202F2A03B3A4C07A5E920F6FBBD9E83D8E97519247CBFE9A069794C7FCB41E7371D440EB7C3E73219347FB7CBE8F79D9506B5C3EEF0B94C06D1DF2079794E7FCBCB20EB9B5D6F9741E872985C9603
Опять же видим, что в пользовательских данных имеется заголовок, поле 44 TP-MTI & Co имеет значение 44. Пропускаем два символа 5E, длина заголовка 05 равна 05. Смотрим, что кодировка сообщения здесь 7bit default alphabet, так как 00 , - это поле содержит нулевые значения. И в этом случае, (ВНИМАНИЕ!), если длина заголовка равна 05, а кодировка 7bit, то пропускаем следующие 6 (шесть!) пар символов (5+1), вот эти 0003FD0202F2. Оставшаяся часть строки A03B3A4C07A5E920F6FBBD9E83D8E97519247CBFE9A069794C7FCB41E7371D440EB7C3E73219347FB7CBE8F79D9506B5C3EEF0B94C06D1DF2079794E7FCBCB20EB9B5D6F9741E872985C9603 - это текст СМС: what it looks like Boot Sector got damaged somehow,i managed to restore Volume header
Расшифровка 7-битной кодировки, - это целая песня, просто приведу здесь код модуля, с функцией Decode7bit(), которую я написал
показатьНа вход функции передаём строку символов в кодировке 7bit, на выходе получаем текст СМС в читаемом виде. Функция корректно обрабатывает текст, по возможности даже удаляет терминальный ноль в конце строки, к примеру в других PDU конвертерах имя отправителя, допустим, Beeline, отображается как Beeline@, или Beelinex, (не фильтруется символ конца строки), в моей функции же предусмотрена обработка таких ситуаций.
Программа испытывалась в работе с модемом ZTE-MF180, в теории она совместима и с другими моделями. Даю ссылки на исходники для тех, кто захочет, добавить в прогу дополнительный фукционал, например, возможность выполнять на компьютере какие-либо действия по командам через СМС. Если будут вопросы и предложения, пишем в комментарии.
скачать рабочий исходник для RAD Studio
скачать рабочий исходник для Delphi 7
Добавлено: май 2016
©Veterock