Отправка SMS-сообщений в формате PDU, теория с примерами на C#, часть 1

В интернете достаточно много информации по отправке SMS сообщений в PDU формате, однако, попробовав отправить сообщение таким способом, я был очень огорчен: информация из интернета либо скупа на объяснения, либо не точна. Результатом долгих плясок с бубном и явилась эта статья, дабы объяснить все подробно тем, кто захочет пойти по моим стопам.

Предыстория (можно пропустить)

Поводом заморочек по отсылке SMS стало небольшое ЧП на моей основной работе: из-за скачка напряжения в серверной отключились кондиционеры, в результате чего полторы тонны работающего оборудования подняло температуру в помещении до 45-50 градусов и зависло… Вот и родилась мысль: оповещать себя любимого о неприятностях в конторе путем автоматической отсылки SMS-сообщений. Т.е. скрипты периодически проверяют параметры систем и в случае если что-то не так – отправляют мне соответствующее сообщение через GSM-модем. Тогда же я стал искать программу, которая умеет отсылать SMS из командной строки, но то, что я нашел, мне не понравилось. В результате было решено написать свое приложение для отправки SMS. Инструментом написания стал C#. Результат вы можете увидеть и скачать здесь

Форматы СМС-сообщений

SMS-сообщения можно отправлять в двух форматах – текстовом и PDU. Текстовый формат чрезвычайно прост и везде достаточно подробно описан. Но из-за своей простоты он содержит несколько ограничений. Например, из текстового режима нельзя отправить сообщение русскими буквами. Кроме того, в текстовом режиме нельзя рулить параметрами сообщения, такими, например, как его тип. К тому же, некоторые телефоны/модемы вообще не поддерживают текстовый режим.

Для обхода ограничений текстового режима, а так же там, где он вообще не поддерживается, используется режим PDU. Это достаточно сложный и запутанный режим, но зато пользователю доступен весь потенциал SMS-сообщений. Вот его мы и рассмотрим.

В режиме PDU с помощью одного SMS-сообщения можно отправить максимум 140 байт информации. Для отправки используются две основные кодировки: 7-битная и UCS2. 7-битная используется только для отправки ASCII символов, т.е. символов с кодом от 32 (20h) до 127 (7Fh). Это означает, что русских букв там нет, зато, при отправке, 7-битная кодировка упаковывается в 8-битный вид, что позволяет запихнуть в отведенные нам 140 байт целых 160 ASCII-символов.

В кодировке UCS2(по сути тот же Unicode) каждый символ кодируется двумя байтами, поэтому становится возможна отправка сообщений на языках отличных от английского, но длина сообщения сокращается до 70 символов (140/2=70).

Форматы и принципы кодировок будут описаны ниже, сейчас же рассмотрим PDU-режим подробнее.

Что есть PDU?

PDU-режим придумали извращенцы-мозгофилы. Придумали они его для того, чтобы поиметь мозги тех, кто будет с ним работать. Таково было мое первое ощущение, когда я начал этим заниматься. Потом, когда картина прояснилась, ощущение ослабло, но до конца не исчезло J.

Итак, PDU это Packet Data Unit, то бишь, если вольно переводить – единица (блок, модуль) пакетных данных. По сути, это просто текстовая строка, состоящая из шестнадцатеричных байтов, которая содержит в себе все параметры сообщения. Эта строка и передается модему/телефону.

Судя по тем описаниям, которые я читал, все сотовые телефоны и GSM-модемы поддерживают прием/отправку сообщений в этой форме.

Сообщение в PDU-режиме представляет собой такую хитрую формулу:

SMS = SCA+TPDU,

Где:

  • SMS — это целиком сформированное сообщение,
  • SCA – это Service Center Address — номер телефона SMS-центра, через который отправляется SMS
  • TPDU – это Transport Protocol Data Unit – единица данных транспортного протокола. По сути TPDU и есть наша цель. Именно этот блок содержит номер получателя, текст сообщения и несколько служебных полей. Именно его мы и будем ковырять.

Данную формулу можно сократить до SMS = TPDU, т.е. не указывать SMS-центр. Это работает в большинстве случаев, ибо номер SMS-центра обычно уже указан в SIM-карте и не меняется, но об этом чуть позже.

Итак, все, что нам нужно – правильно закодировать сообщение в формат PDU. Слово «правильно» в предыдущем предложении – это ключевое слово, ибо на все неправильное модем ругнется типа «ERROR: 304» и все. Курите бамбук, пляшите с бубном и гадайте на картах – в чем именно ошибка он вам не скажет. Посему подробно разберем формат для отправки сообщения.

1. Полный “Привет!!!”

Итак, для начала будем отправлять сообщение «Привет!!!» на номер +79123456789. Во-первых, получать сообщения на родном языке приятнее, а во-вторых их проще кодировать с точки зрения программирования. В этом случае, как я уже писал, каждый символ сообщения кодируется двумя байтами (здравствуй, Unicode!). Так же, для начала, отправлять сообщение будем в полном виде, т.е. с указанием СМС-центра. Как обойтись без этого будет сказано позже.

Итак, SMS = SCA + TPDU. Начнем с SCA.

1.1. Формируем номер SMS-центра (он же SCA)

Формат номера SMS-центра прост и состоит из трех блоков:
1 байт 1 байт От 0 до 6 байт
Длина всего блока SCA Тип номера SMS-центра Номер SMS-центра

Длина блока SCA – это (длина типа + длина номера)

Тип номера – это формат номера телефона SMS-центра. В большинстве случаев (читай «почти всегда») это международный формат, например «+79123456789». Международному формату соответствует шестнадцатеричный байт 91h. То есть, у нас тип номера всегда будет равен «91».

Номер SMS-центра — тут извращенцы-мозгофилы решили, что просто так указать номер SMS-центра будет не прикольно, и придумали такую затею: из номера убирается все, кроме цифр, затем, если количество символов в номере нечетное, номер дополняется в конце буквой «F» и становится четным. Затем, каждая пара цифр в номере переставляется местами.

Поясню на примере: Пусть номер SMS-центра будет «+79107899999» (русский провайдер МТС). Приведем его в соответствие извращенскому формату: убираем плюс перед номером, считаем количество символов – получилось 11. Нечетное число, значит, дописываем в конец букву «F». Получается «79107899999F». Затем переставляем местами цифры в каждой паре. Получится «9701879999F9». Вот он, искомый номер SMS-центра.

Затем объединяем все до кучи: тут все достаточно просто: берем тип номера SMS-центра, добавляем к нему сам номер, и в начало вставляем количество получившихся БАЙТ в шестнадцатеричном виде. Т.е. для нашего случая с номером +79107899999 получим такую петрушку: «07919701879999F9». Что есть: «07» (длина) + «91» (тип, 1 байт) + «9701879999F9» (номер, 6 байт). Длина равна «07» потому что 1 байт типа + 6 байт номера. Обязательно «07», а не «7» — все байты переводятся в текстовый вид целиком, с лидирующим нулем, если он есть.

ВАЖНО! Я специально выделил жирным фразу «количество получившихся байт», ибо это очень важно! Извращенцы-мозгофилы конкретно все запутали, поскольку в номере получателя сообщения указывается не количество байт, а количество цифр в номере: бред и путаница. Так что тут нужно быть очень внимательным.

1.2 Формула TPDU

Теперь пришла очередь рассмотреть вторую часть PDU-формата. Для нее тоже есть формула:

TPDU = «PDU-Type» + «TP-MR» + «TP-DA» + «TP-PID» + «TP-DCS» + «TP-VP» +

+ «TP-UDL» + «TP-UD»

Выглядит страшно, но ничего, сейчас разберемся:

· PDU-Type – Тип сообщения. Поле флагов, о нем речь пойдет дальше. В некоторых источниках упоминается как SMS-SUBMIT-PDU

· TP-MR – TP-Message-Reference – назначение этого поля для меня осталось загадкой, надеюсь что когда-нибудь все прояснится. Поэтому ставим TP-MR = «00»

· TP-DA – TP-Destination-Address – Номер телефона получателя сообщения

· TP-PID – TP-Protocol ID – Идентификатор протокола. Особого интереса не представляет. Тоже всегда равен «00»

· TP-DCS – TP-Data-Coding-Scheme – Схема кодирования данных. Указывает, в каком формате представлено сообщение.

· TP-VP — TP-Validity-Period — время действия сообщения (если сообщение не будет получено абонентом в течение этого времени, SMS-центр его удалит)

· TP-UDL — TP-User-Data-Length – длина сообщения.

· TP-UD — TP-User-Data – непосредственно текст SMS-сообщения, закодированный согласно полю TP-DCS

В принципе, сложного ничего нет. Пойдем по порядку:

PDU-Type – Поле флагов. Один байт, состоящий из 8 бит (удивительно, правда?), которые осуществляют некоторую настройку сообщения. Посмотрим на табличку:
Бит 7 6 5 4 3 2 1 0
Название TP-RP TP-UDHI TP-SRR TP-VPF TP-VPF TP-RD TP-MTI TP-MTI

Расшифруем поля:

Бит Значение
TP-RP

Reply path

TP-UDHI

User data header indicator

TP-SRR

Status report request. Если бит равен 1 – запрашивается отчет о состоянии

TP-VPF

Validity Period Format – формат поля TP-VP (время действия сообщения). Эти 2 бита описывают, как будет выглядеть поле TP-VP в формуле TPDU:

Бит 4 Бит 3 Формат поля
0 0

Поле TP-VP отсутствует

1 0

Поле TP-VP присутствует и описывает относительный формат (1 байт)

0 1

Поле TP-VP присутствует и описывает расширенный формат (7 байт)

1 1

Поле TP-VP присутствует и описывает абсолютный формат (7 байт)

TP-RD

Reject duplicates

TP-MTI

Тип сообщения. Когда бит 1 равен «0», а бит 0 равен «1» это исходящее сообщение

Смысла некоторых полей я не узнал, поэтому и не будем обращать на них внимание. Для нас самым главным является тип сообщения, т.е. 2 бита TP-MTI, они должны быть 01, что указывает, что это исходящее сообщение.

Кроме того имеют некоторое значение биты TP-VPF (4-й и 3-й). Они указывают время жизни сообщения и влияют на размер поля TP-VP в формуле TPDU. Если оба бита равны «0», то поле TP-VP вообще из формулы исключается. Толкового описания этого поля я не искал, поэтому оставим биты по нулям и избавимся от этого поля вообще. Пусть SMS живет столько времени, сколько ей позволит жить SMS-центр.

В общем и целом, для нормальной отправки сообщения достаточно в байте PDU-Type установить в «1» только нулевой бит, таким образом, получим байт «01». Его и подставим в формулу.

Возвращаемся к формуле TPDU:

TP-MRполе загадочное, пусть остается нулевым, т.е. «00».

TP-DAНомер телефона получателя сообщения. Тут примерно такая же шиза, что и с номером SMS-центра:
1 байт 1 байт От 0 до 6 байт
Длина номера получателя Тип номера получателя Номер получателя

Тип номера остается таким же, как и для SMS-центра: международный формат записывается как «91».

Номер получателя кодируется так же, как и номер SMS-центра: убираем все, кроме цифр, дописываем в конец «F», если количество цифр в номере нечетное, а затем переставляем местами цифры в каждой паре. Пример такой же: нам нужно отправить SMS на номер +79123456789. Убираем плюс, цифр получилось 11 – дописываем в конец «F» и переставляем местами цифры, получаем «9721436587F9». Шиза косит наши ряды?

ВНИМАНИЕ! А теперь очередной финт, о котором по-русски нигде не написано. Точнее написано, но не правильно: Поле «длина номера получателя» считается не как количество байт, а как количество цифр в номере без учета добавленного символа «F»!

Применительно к нашему примеру все поле TP-DA будет выглядеть как «0B919721436587F9», т.е. «0B» (длина, 11 цифр) + «91» (тип) + «9721436587F9» (номер, длина 6 байт, но 11 цифр!!!)

Длина «0B» в шестнадцатеричной системе это 11 в десятичной, т.е. ту букву «F», которую мы добавили для четности мы не учитываем. Тип номера в длине тоже не учитывается. Чувствуете, что курили те парни, которые это придумали?

TP-PIDтоже непонятное поле, оставляем его как «00»

TP-DCS – TP-Data-Coding-Scheme – Схема кодирования данных. Она описывает, как будет закодировано отсылаемое сообщение. Тут достаточно знать только несколько значений:

00h: кодировка 7-бит (160 знаков, но не кириллическая, только латинские символы)

08h: кодировка UCS2 (тот же Unicode), 70 знаков, 2 байта на символ

Если первым полубайтом указать не «0», а «1» – то сообщение получится типа Flash – т.е. не осядет в мобильнике получателя, а сразу же выведется ему на экран. Это может быть полезной возможностью:

10h: Flash-сообщение, кодировка 7-бит

18h: Flash-сообщение, кодировка UCS2

По поводу кодировок речь пойдет дальше.

TP-VP — TP-Validity-Period — время действия сообщения. Я не искал описания, в каком виде это время задается, тем более что оно зависит от битов 4 и 3 поля PDU-Type. Поскольку формат нам не известен – то в поле PDU-Type укажем биты 4 и 3 равными «0», что означает, что поля TP-VP не будет указано вообще.

TP-UDLДлина сообщения. Указывается в байтах. Для сообщений на русском языке используется кодировка UCS2 (тот же Unicode), т.е. каждая буква кодируется двумя байтами. Соответственно сообщение из 9 букв «Привет!!!» будет иметь длину 18 байт, т.е. «12» в шестнадцатеричной системе счисления. (Для сообщений в 7-битной кодировке указывается количество символов в сообщении, т.е. для фразы «Hello!!!» длина будет равна «08» не смотря на то, что перекодированная в 8-битное представление эта фраза занимает не 8 а 7 байт, но о кодировках поговорим ниже.)

TP-UD — TP-User-Data – непосредственно текст SMS-сообщения, закодированный согласно полю TP-DCS, т.е. либо используется кодировка 7-бит, либо UCS2. Для примера, сообщение «Привет!!!» в кодировке UCS2 будет выглядеть так: «041F04400438043204350442002100210021».

К кодировкам вернемся позже, пока что резюмируем полученные знания:

Исходя из формулы

TPDU = « PDU-Type » + «TP-MR» + «TP-DA» + «TP-PID» + «TP-DCS» + «TP-VP» +

+ «TP-UDL» + «TP-UD»

Получаем подстановкой наш текст сообщения:

TPDU = «01» + «00» + «0B919721436587F9» + «00» + «08» + «12» + «041F04400438043204350442002100210021»

Памятуя о том, что SMS = SCA + TPDU, добавим в начало адрес SMS-центра и получим полноформатное PDU-сообщение «Привет!!!» на номер +79123456789 через SMS-центр +79107899999:

«07919701879999F901000B919721436587F9000812041F04400438043204350442002100210021»

Вот именно такую последовательность цифр и нужно отправить телефону/модему, чтобы он отправил сообщение. Но об отправке поговорим позже. Сейчас рассмотрим краткий формат отправки.

Краткий «Привет!!!»

Краткость, как известно, сестра таланта. Посему возьмем это на вооружение и освоим более краткий формат отправки SMS. А именно: из формулы SMS = SCA + TPDU исключается SCA. То есть мы не будем указывать телефону/модему номер SMS-центра, так как в 99,9% случаев он уже настроен в SIM-карте. А раз он настроен, значит, нечего его писать – телефон/модем сам догадается, что SMS-центр нужно взять из настроек SIM-карты. Но для того, чтобы он догадался, надо ему подсказать, а именно вместо SCA подставить «00».

Остальные параметры не меняются и подставляются точно так же. Следовательно, наш полный «Привет!!!» в кратком формате будет иметь вид:

«0001000B919721436587F9000812041F04400438043204350442002100210021»

Начинается с «00» а затем сразу идет поле « PDU-Type » и т.д.

Гораздо удобнее, не нужно производить лишней работы. Единственное «НО»: судя по тому, что я читал, не все телефоны/модемы понимают «00» вместо SCA. Для таких устройств нули нужно опускать и начинать сообщение сразу с поля « PDU-Type ». Лично мне таких устройств не попадалось, но помнить об этом стоит.

О кодировках

UCS2 (Unicode)

Начнем с кодировки UCS2, поскольку именно она позволяет нам отправлять сообщения на русском языке. Тут все очень просто: тот же Unicode. Каждый символ имеет двухбайтовое представление. Т.е. для английских символов однобайтовой кодировки в начало добавляется байт 00H. Для русских (те, что начинаются с C0H в Windows-кодировке) можно создать такое правило: из байта вычитается C0h и прибавляется 410h (кроме букв «ё» и «Ё», которые в Unicode имеют коды 0451h и 0401h соответственно).

Т.е. получается такая таблица кодировок:
Windows UCS2 Windows UCS2 Windows UCS2
А C0 04 10 К CA 04 1A Х D5 04 25
Б C1 04 11 Л CB 04 1B Ц D6 04 26
В C2 04 12 М CC 04 1C Ч D7 04 27
Г C3 04 13 Н CD 04 1D Ш D8 04 28
Д C4 04 14 О CE 04 1E Щ D9 04 29
Е C5 04 15 П CF 04 1F Ъ DA 04 2A
Ё A8 04 01 Р D0 04 20 Ы DB 04 2B
Ж C6 04 16 С D1 04 21 Ь DC 04 2C
З C7 04 17 Т D2 04 22 Э DD 04 2D
И C8 04 18 У D3 04 23 Ю DE 04 2E
Й C9 04 19 Ф D4 04 24 Я DF 04 2F

Здесь приведены только большие буквы. Остальные символы юникода можно посмотреть в программе «Таблица символов», которая есть в Windows и находится в меню «Пуск» — «Программы» — «Стандартные» — «Служебные» — «Таблица символов»

Таким образом, написание русских сообщений в кодировке UCS2 не представляет никакой сложности – бери букву, перекодируй ее в двухбайтовое представление и отправляй…

Однако в UCS2 можно отправить только 70 символов в одном SMS-сообщении. Если необходимо отправить больше – тут уж придется пожертвовать русским языком и отправлять латинскими символами. Они обычно кодируются одним байтом, от 0 до 7Eh. Точнее, даже не байтом, а 7 битами байта. Вот тут и кроется очередная бредовая хитрость: поскольку для того, чтобы закодировать символ нужно всего 7 бит, а в байте их 8, применяется специальный алгоритм, который упаковывает 7-битные символы в 8-битовое представление. За счет того, что используются свободные биты, длина сообщения в этой кодировке составляет максимум 160 символов, которые в упакованном формате занимают максимум 140 байт.

7-битная, упакованная

Теперь поговорим об алгоритме упаковки 7-битной строки в 8-битное представление. Он достаточно прост, хотя может потребовать времени, чтобы вникнуть. Объяснять буду на примере кодирования строки «Hello!!!»

Поскольку для кодирования символа ASCII используется 7 бит (биты от 0 до 6), значит, старший, 7-й бит всегда равен 0. Вот он-то и используется для упаковки. Т.е. последовательность такая:

1. Получаем первый байт: берется семь бит первого символа (биты 7-0); из семи бит второго символа самый младший (0-й) бит переносится в старший разряд первого байта, получается так: (0-й бит второго символа)(7 бит первого символа)

2. Далее получаем второй байт: от второго символа у нас теперь осталось 6 бит, дополняем их до целого байта, а именно берем из третьего символа уже два младших бита (1-й и 0-й) и переносим их в старшие разряды второго байта. Получается так: (1-й и 0-й биты третьего символа)(6 бит второго символа)

3. Получаем третий байт: от третьего символа забрали 2 бита, осталось 5. Значит, чтобы получить полный третий байт, надо из четвертого символа забрать 3 младших бита …

4. И так далее, по аналогии.

Картинка ниже иллюстрирует данный процесс (нажмите на нее, чтобы увеличить):

7-bit-encoding

Вот как выглядит последовательность байт фразы «Hello!!!» в 7-битной кодировке:

48 65 6C 6C 6F 21 21 21

А вот эта же фраза, но уже перекодированная в 8-битную:

C8 32 9B FD 0E 85 42

Как видно, получилось на целый байт меньше! Грубо говоря, кодирование каждых 8 символов дает выигрыш в один байт. Вот так и получается, что в 140 байт влезает 160 символов. Надеюсь, понятно объяснил…

Внимание! Еще раз обращаю внимание на то, что при отправке сообщений в 7-битной кодировке в поле TP-UDL (Длина сообщения) указывается количество символов в сообщении, а не количество байт, получившихся после упаковки! То есть для «Hello!!!» TP-UDL будет равно «08», хотя байтов у нас получилось семь! Это тоже остается на совести извращенцев-разработчиков формата…

Отправка

После того, как сообщение закодировано, его еще нужно правильно отправить, здесь тоже не все чисто (шизики постарались :)).

Я не буду вдаваться в подробности подключения модема и настройки COM-портов, будем считать, что модем подключен и готов принимать команды. Будем сразу отправлять сообщение, без записи его в память.

1. Переводим модем в PDU-режим. Для этого отсылаем ему команду «AT+CMGF=0». Если получаем в ответ «OK» — значит все в порядке, режим поддерживается и включен.

2. Затем, даем команду «AT+CMGS=<длина сообщения>». Эта команда требует пояснения: <длина сообщения> в данном случае подразумевает не длину всего сообщения, а длину блока TPDU! То есть длину без учета номера SMS-центра! Длина считается в байтах.

Возвращаясь к первому примеру (полноформатное PDU-сообщение «Привет!!!» на номер +79123456789 через SMS-центр +79107899999), где сообщение выглядело как:

07919701879999F901000B919721436587F9000812041F04400438043204350442002100210021

Для его отправки мы должны дать команду «AT+CMGS=31», т.е. начало «07919701879999F9» в длину не входит, ибо это номер SMS-центра.

Если номер SMS-центра не указывается, и вместо него подставляется «00», то этот байт тоже не учитывается. Т.е. для нашего короткого «привета»:

0001000B919721436587F9000812041F04400438043204350442002100210021

Длина все равно будет 31. Да, кстати: в данном случае, в команде телефону/модему, длина сообщения указывается десятичной цифрой.

3. После команды «AT+CMGS=<длина сообщения>», если все нормально, телефон/модем ответит приглашающей кавычкой «>». Теперь передаем ему непосредственно все сформированное нами сообщение. Вместе с номером SMS-центра, или «00» вместо него. То есть все, что мы кодировали, все, чем пробредились. Заканчиваться данный крик души должен спецсимволом «Ctrl+Z», имеющим ASCII-код 26.

4. Если все нормально, если нигде не накосячили и Бог GSM-связи нам благоволит – модем ответит «+CMGS: <номер>», а получателю придет долгожданная SMS-ка. Можно пить Боржом. «<номер>» — это какой-то внутренний номер, на него обращать внимание не стоит.

Если же мы где-то ошиблись – тогда модем ответит «ERROR: 304». Тогда бубен в зубы и вперед – перелопачивать все сначала…

Теоретическое “Итого”

Вот и вся теоретическая премудрость. На первый взгляд сложно, но вполне реализуемо. Теперь перейдем к обещанным примерам на C#.

Комментарии приветствуются, спрашивайте или поправляйте!

Продолжение:

Отправка SMS-сообщений в формате PDU, теория с примерами на C#, часть 2

Отправка длинных SMS-сообщений в формате PDU

Поделиться с друзьями:
  • Добавить ВКонтакте заметку об этой странице
  • Одноклассники
  • Facebook
  • В закладки Google
  • Мой Мир
  • Twitter
  • LiveJournal
  • Яндекс.Закладки
  • LinkedIn
  • Reddit
  • StumbleUpon
  • БобрДобр
  • Memori.ru
  • МоёМесто.ru

Комментарии

  1. Статья хорошая! Хоть с форматом ознакомился. Только почему то я думал, что в PDU задаётся также и номер отправителя.. эх…

    1. А зачем? SMS-центр итак знает, от кого идет посылка.
      Кроме того, даже если б это и было возможно, то эту возможность быстренько бы прикрыли, дабы нельзя было подделать номер отправителя SMS

  2. Небольшое замечание… Цитирую: «Да, кстати: в данном случае, в команде телефону/модему, длина сообщения указывается десятичной цифрой» — если я правильно понял, то десятичной цифрой мы пишем количество октетов сообщения, т.е. в сообщении «0001000B919721436587F9000812041F04400438043204350442002100210021» 62 символа, значит модему мы указываем 31… Так?

  3. скан SIMoCo > на siemens C72 модем S45
    передачаSMS 1234567890AaBbCcDdEeFfGg
    AT+CMGS=38
    07919761989901F031000B819861198377F600F4A818313233343536373839304161426243634464456546664767
    41 54 2B 43 4D 47 53 3D 33
    38 0D 30 37 39 31 39 37 36 31 39 38 39 39 30 31
    46 30 33 31 30 30 30 42 38 31 39 38 36 31 31 39
    38 33 37 37 46 36 30 30 46 34 41 38 31 38 33 31
    33 32 33 33 33 34 33 35 33 36 33 37 33 38 33 39
    33 30 34 31 36 31 34 32 36 32 34 33 36 33 34 34
    36 34 34 35 36 35 34 36 36 36 34 37 36 37 1A 0D
    ответ

    >
    +CMGS: 223

    OK
    0D 0A 3E 20 0D 0A 2B
    43 4D 47 53 3A 20 32 32 33 0D 0A 0D 0A 4F 4B 0D
    0A

    1. На четвертом месяце радистка Кэт…
      Хочется какой-то связи — связи нет…
      Медленно плывут по небу юнкерса…
      Шифр не тот. И жизнь не та…

      1. Помогите пожалуйста,не отправляются смски,я немного разобрался и понял что у меня нету номера smsc ,я вроде бы нашёл ,но после того как нажимаю обновить у меня вылетает ошибка ,помогите

  4. Строка не вся поместилась. А так проверил,работает.И шифр тот,и жизнь то та. Вот как принимать и декодировать команды в смске,то другой вопрос.

      1. Перевести телефон в режим работы с внешним устроством.Иначе при приёме смс телефон не пыплёвывает в порт.Внешнее устройство-PIC контроллер.Отработать режим ошибок при неудачной отправке.Распаовка,анализ № отправителя,команды.А дальше по своему усмотрению.

        1. Честно говоря, не совсем понимаю. Что значит «Перевести телефон в режим работы с внешним устроством» ? У вашего PICa USART есть? Если да — то в чем проблема? Соединяете USART микроконтроллера с соответствующими линиями телефона — и шлите ему АТ-команды на здоровье… С помощью АТ-команд можно и прочитать СМС, и удалить, и все что угодно!

  5. По АТ командам всё верно. Усарт есть,с ним предстоит разобраться.«Перевести телефон в режим работы с внешним устроством»-это образно.Заметил,что сименс с72 в связке с прогой SIMoCo,при получении смс,сразу скидывает смс в прогу.А работая самостоятельно,портом не дрыгает.Т.е. придётся непрерывно следить за смсками в телефоне.А так напр. раз в 10с опрашивать наличие соединения.И по получении смс телефон сам скинет в усарт пика.

    1. Ну, тут, мне кажется, уже какие-то особенности телефона, по этому поводу ничем не смогу помочь. Моя задача была отправить СМС, а не мониторить их получение. Перехватите весь обмен SIMoCo с телефоном, глядишь, удастся выявить инициализирующую последовательность…

  6. Верно
    Это я и выложил как пример в символах,примерно то,что описывалось выше в постах и в хексе,что передаётся в усарт. На это нужно обратить внимание.н.п.0хA и 0хD. Но это для тех кто использует мк.

  7. спасибо за статью, но в тексте есть опечатка

    Вот как выглядит последовательность байт фразы «Hello!!!» в 7-битной кодировке:
    48 65 6C 6C 6F 21 21 21
    А вот эта же фраза, но уже перекодированная в 8-битную:
    E8 32 9B FD 0E 85 42

    первый декодированный байт будет C8 а не E8
    P.S заметил когда сравнивал результат работы своего алгоритма с вашим(не сошелся первый символ) сперва подумал что а алгоритм неправильный, но потом в калькуляторе посмотрел и убедился в обратном

    ICQ: 866-233

  8. не хватает разбора буквенного обозначения номера. К примеру если с сайта мегафона слать СМС то на телефоне будет от megafon а в пакете данных 07919762020001F90414D0F7FBDDD52E9FC3E6B71B0008119010412371616E0037003800350031003600320037000A002F0020041B044304470448043804350020043804330440044B00200434043B044F002004420435043B04350444043E043D0430003A0020002A0035003000350023003200340032002300200028003800200440002F0441044304420029

    сможете дополнить свою статью ?

    1. вот весь пакет
      07919762020001F90414D0F7FBDDD52E9FC3E6B71B0008119010412371616E
      0037003800350031003600320037000A002F0020041B044304470448043804
      350020043804330440044B00200434043B044F002004420435043B04350444
      043E043D0430003A0020002A00350030003500230032003400320023002000
      28003800200440002F0441044304420029

    2. Декодирование текстового номера:
      К примеру:
      0E D0 C2303BEC1E971B
      0Е — длина (7 символов в номере)
      D0 — тип номера (алфавитно-цифровой)
      C2303BEC1E971B — текст, упакованный 7-битный
      42616C616E63650D — текст декодированный
      итого получаем: Balance

  9. здравствуйте !народ подскажите как открыть смс на пк.вобщем с карты памяти скинул их на пк.теперь чем можно открыть какой програмой или же в каком они формате?спасиба…

  10. В исходниках ошибка!
    Попробуйте отправить 67-69 символов.
    Вначале singleSMS = true;
    но потом текст режется а 2 части и отправляется 2 смс но без флагов составного!

      1. Если не затруднит, не могли бы Вы реализовать возможность получение отчета о доставке? Купил исходный код SMSSender, очень интересно изучать, но вот реально не хватает функции доставочных отчетов. Не против и заплатить за скачивание отдельной версии с такими отчетами.

        1. Вам повезло, я сейчас как раз занимаюсь этим вопросом. Однако предупреждаю сразу — отчеты о доставке умеют получать не все модемы, проверено лично… У меня фирменный модем МТС их получает, а вот универсальный модем от Связного с симкой TELE2 — не принимает их вообще.
          В общем, как реализую — выложу и напишу.

    1. А вот по срокам ничего конкретного сказать пока не могу — много основной работы и мало информации по отчетам о доставке. Но, думаю, в ближайшую неделю — две

    2. besieger, кстати, обдумывая процесс получения отчета о доставке возник вопрос: а как вы, примерно, это видите?
      Должна ли программа ждать отчета? Или по мере прихода отчетов выводить сообщения? Или еще как?
      И в каком это будет режиме? Консольном или оконном?

  11. Мне кажется лучше в оконном. Ждать, думаю, может быть опасно — а вдруг вообще не придет. Но с каким-то таймаутом проверять, а нет ли подтверждения? Если есть, то складывать, допустим, в какой-нидь словарик, где ключ — тел. номер, на который отправили, а значения — вся инфа из подтверждения, текст, время, статус и пр. Или можно на получение подтверждения генерить событие, в аргументах которого опять же будет тел. номер, с которого пришло подтверждение и вся доп. инфа. А там уже автор обработчика события пусть сам думает, в словарик ему это кидать или куда.

    1. В отчете о доставке нет никакого текста. Там есть номер СМС центра, номер на который отправлялось, время доставки и код доставки.
      Про словарики только не совсем понятно. Что за словарик?

      1. Ну в данном случае не об английском речь, а о названии в неймспейсах .нет фреймворка. А он тут причем, что после отправки СМС вызываешь какой-нибудь метод типа GetNotifications, который тебе может возвращать словарь подтверждений с ключом по номеру телефона. Если номера в словаре нет, значит все, не пришло подтверждение. Это один из вариантов. Можно на получение каждого подтверждение вызывать событие.

    1. Или вот допустим у билайна команда *102# для узнавания баланса. Как ее отправить и куда, чтобы получить баланс, допустим, ответной смской?

      1. А это совсем другая история. Специальных АТ-команд для проверки баланса нет. Это делается USSD-запросом, а с ним я еще не разбирался.

  12. Подумал, что допустим можно сделать еще так: запрашивать у модема все хранящиеся в симке/на телефоне СМСки, прорабатывать их список, вылавливать подтверждения и складывать в словарь по номеру телефона или ref-номеру, или что-то подобное. Т.е. без всяких событий, просто — пользователь вызовет этот метод, когда ему надо, и получит список имеющихся на текущий момент подтверждений

  13. Может быть вы пока выложите промежуточные результаты получения отчетов о доставке, я тоже бы с ними поэкспериментировал?

    1. На всякий случай напишу о своих результатах. Сразу скажу, что я отправляю одиночное сообщение, что в текстовом случае, что в PDU.

      Для текстового сообшения запрос отчета о доставке задается командой:
      AT+CSMP=37 (00100101, 0 и 1 биты — признак отправляемого сообщения =»01″, 2 бит — отвергать дубликаты =»1″, 3 и 4 — период валидности =»00″, 5 — самый важный, запрос отчета о доставке =»1″, 6 и 7 биты — UDH и Reply path=»00″).

      Это работает, приходит смска с отчетом доставки, которую потом можно прочитать с помощью AT+CMGL.

      Недостатки и недоработки:
      1) Смска-отчет всегда ложится в симку, а не в телефон, даже если задать AT+CPMS=»ME» (видимо, эта команда задает чисто источник чтения).
      2) Не удается подхватывать приходящие смски на лету, попеременно задавал команды AT+CNMI=2,1,0,0,0 и AT+CNMI=2,1,0,2,0, имея обработчик на SerialPort.DataReceived. Если бы можно было, то можно получать отчет о доставке и сразу его удалять, освобождая память, а так получается, что если отчетов придет много, они все не поместятся в симку.

      С отчетом о доставке PDU-сообщения вообще не заладилось 🙁
      Формируя SMS_SUBMIT_PDU, получаю так же 37 (00100101, 0 и 1 биты =»01″ — отправляемое сообщение, 2 бит =»1″ — больше сообщений нет, 3 и 4 биты =»00″, 5 бит =»1″ — опять самый важный, запрос отчета доставки, 6 бит =»0″, UDH отсутствует, сообщение одиночное, 7 бит также «0»). Подскажите, пожалуйста, что не так с битами SMS_SUBMIT_PDU? И есть ли способ победить недостатки 1 и 2?

      1. Поправка, сути дела не меняющая, но тем не менее: 2-й бит не «больше сообщений нет», это же не чтение СМС, а «отвергать дубликаты». Но он все равно установлен в 1.

      2. Значицца так.
        1) +CPMS действительно задает только источник для чтения, у меня тоже отчеты всегда ложатся на симку. Видимо по другому никак. В любом случае, я не знаю, как это победить.
        2) Как я ни бился с +CNMI у меня ничего не вышло. Я ни разу не получил незапрашиваемый ответ от модема. Причем пробовал несколько модемов — нигде не работает. Не пробовал только непосредственно с телефоном. Видимо, это не стандарт, никто его придерживаться не обязан. Так что на +CNMI я забил и тупо регулярно запрашиваю непрочитанные сообщения.

        С отчетом о доставке в PDU все очень просто: у меня SMS_SUBMIT_PDU либо равно 21 (HEX), либо 61 (HEX). Т.е. 00100001 либо 01100001. И все отлично работает. Остальные поля я не заполняю.

        1. CellRoute GSM от telecom fm зараза такая никак не хочет воспринимать бит TP-SRR. То есть, 01 нормально, 41 (мульти смс) — тоже, но 21 и 61 ни как — ERROR в ответ. В чем может быть трабл? Просто не поддерживается? С другим модемом не могу протестить — на работе только их используем.

  14. Большое спасибо за ответы! Вечером попробую ваш SMS-SUBMIT-PDU. По поводу периодического прочтения СМС — была такая идея, в отдельном потоке получать СМС и сразу удалять, чтобы место на симке не забилось. Но тут возникает вопрос: есть ли у модема некий пул AT-команд или все они поступают как придется. Если получится так, что я одновременно пошлю команды и на отправку СМС, и на чтение, то не будет ли коллизии и не свалится ли модем вообще? А если включать блокировку при отправке и читать СМС только после окончания всей серии отправок, то можно нарваться на ситуацию, когда все отчеты о доставке не влезут на симку, допустим отправил 21 смс, а емкость симки 20 сообщений, и к моменту, когда будешь читать сообщения, уже все отчеты придут. Или «невлезшая» СМСка автоматически доставится после того, как я удалю первую прочитанную смску с отчетом?

    1. SMS-SUBMIT-PDU сработал, даже мой, что-то я там с HEX’ами напутал сначала! Спасибо! Если не затруднит, не могли бы вы прояснить вопросы с зачиткой СМС, параллельной отправке, и что будет если придет СМС, а симка забита?..

  15. люди что делать? как остановить? мне на телефон приходят смс от номера 34-33 и за это снимают 3 рубля каждый день!!

  16. «из номера убирается все, кроме цифр»
    Разбирался с модемом от МТС (ZTE MF112), там из номера СМС-центра плюс не убирается, так и засовывается в строку PDU. Иначе не работает.
    То есть вместо:
    «07919711029099F30100…»
    нужно писать:
    «07917+19210099393100…»
    Можно, конечно, вообще его не указывать (как в статье, с 00 в начале или без), и даже СМС-ка приходит, но как-то странно: на телефоне выдает ошибку (хотя и читает).

    Спасибо за статью!

  17. Доброго времени суток.
    Написал приложение на Си шарпе по отправке смс с модема. В течение некоторого времени сообщения отправляются, но после модем по какой-то неведомой мне причине виснет и не хочет более отвечать на АТ команды. Перепробовал множество приемов чтобы вылечить этот недуг, но результата никакого. Чтобы модем заработал вновь надо физически отключить его от компа и вставить обратно. Сейчас алгоритм таков: в течение минуты приемник модема включен для приема смс, потом выключается, ждет 10 секунд, включается и снова ждет новые смс, как только находит новое, обработывает и отправляет ответ адресату. Так продолжается до тех пор, пока не будут обработаны все принятые смс. Через каждые 3 отправленные сообщения, цикл приостанавливает свое действие, выключает приемник/передатчик, ждет 10 секунд и продолжает свое действие. Так вот, подскажите из-за чего возможны такие тормоза модема? как с этим бороться?

    1. Не используй USB-удлинитель для подключения модема, особенно удлинитель без фильтров. Попробуй отключить параметр «Разрешить отключение устройства для экономии энергии» на вкладке «Управление электропитанием» свойств COM-портов и Модема в Диспетчере устройств.

  18. Попробую разгадать загадку «извращенцев-мозгофилов»:

    К моменту создания этого алгоритма, скорей всего в производстве использовались 16 битные контроллеры. Сам формат похож на двоично-десятичный. Переставлять числа местами необходимо для того, чтобы перевести человечески понятную запись в машинный код.
    Для примера:
    номер 79107899999F в пямяти 16ти битного контроллера будет выглядеть следующим образом 9701879999F9. А если его прдварительно перевернуть, получим следующее:
    9701879999F9 -> 79107899999F
    Перевый байт всегда младший разряд, потом старший. Код «F» в двоично-десятичной системе не существует. По этому по нему можно определить конец номера

  19. Искренне надеюсь, что ветка жива 🙂
    В общем такое дело — прогу написал, работает, в основном отправляются сообщения корректно (длинные, на русском языке, в PDU формате), на на некоторые телефоны приходят либо крокозябры, либо пустые сообщения. Кто-нибудь с подобным сталкивался? 🙁

  20. StarXXX, наверное тебя заколебали с смсками) спасибо еще раз, как ченить забудешь опять сюда идешь.

  21. Ваш краткий формат смс у меня не отправился. Но зато отправился похожий с некоторыми доработками. А именно: тип PDU — 11 а не 01 как у вас. Не знаю почему, но у меня работает. И по моему у вас пропущен байт времени хранения сообщения. После номера телефона и 0008 должен следовать байт C1. Т.е. перед длинной сообщения.

  22. Доступно про 8 упаковку:
    48 65 6C 6C 6F
    0100 1000 — 48 — H
    0110 0101 — 65 — e
    0110 1100 — 6C — l
    0110 1100 — 6C — l
    0110 1111 — 6F — o
    #убираем 7 бит
    100 1000 -H
    110 0101 -e
    110 1100 -l
    110 1100 -l
    110 1111 -o
    #записываем в обратном порядке
    110 1111 -o
    110 1100 -l
    110 1100 -l
    110 0101 -e
    100 1000 -H
    #Дописываем нули до первой кратности (если кратно 8 оставляем без изменений)
    0 0000 -null
    110 1111 -o
    110 1100 -l
    110 1100 -l
    110 0101 -e
    100 1000 -H
    #Запишем поток битов в строку разделяя по 8 бит
    00000110 11111101 10011011 00110010 11001000
    #Запишем столбец переставив значения байтов в обратном порядке
    1100 1000 — С8
    0011 0010 — 32
    1001 1011 — 9B
    1111 1101 — FD
    0000 0110 — 06
    Так проще для понимания

  23. Здравствуйте. Спасибо за замечательные статьи, часть ваших идей реализована в проекте библиотеки

    https://github.com/JFF-Bohdan/sim-module

    Это библиотека на Python 3, позволяющая работать с SIM900 (и совместимыми модулями) под Win/Linux (ARM Linux).

  24. Огромное, нечеловеческой спасибо. Асмодеев, придумавших это — на кол!!!!

  25. Здравствуйте. Спасибо за замечательные статьи, огромное, нечеловеческой спасибо.
    Но у меня есть такая задача:
    Имеется нескоько тысяч SMS сообщений с SIEMENS S55, все в формате блабла.sim, телефона давно уже нет. Как все это перевести в человеческие текстовые файлы?

  26. Спасибо за статью! PDU — ещё цветочки, вот когда ещё и Nokia FBUS — вот это взрыв мозга. Про третью версию FBUS’а — вообще молчу…

  27. огромное спасибо автору.
    написано человеческим языком.
    я бы пожелал ,чтобы автор писал статьи также доступно и доходчиво и по другим тематикам электроники.

  28. StarXXX, спасибо за статью! Очень полезная информация.

    Если кто в теме, то подскажите как решить этот вопрос:
    Приходит подтверждение о получение смс и как привязать это подтверждение к уже отправленной смс?
    (Как понять, что определенная смс`ка доставлена?)

  29. Автор молодец! Разжёвано до мелочей. Сколько в инете инфы, но только тут всё подробно и доходчиво написано. Особенно про принцип 7-битной упаковки (кто бы мог додуматься? в SMS-протоколе сплошное торжество маразма над здравым смыслом). За пару вечеров написал скрипт СМС-шлюза на РНР, и О чудо! — всё прекрасно заработало.

    1. А мне вы не могли бы написать, что бы можно было отправлять смс? Онлайн сервисы с ограничением по кол. знаков уже измотали

  30. Спасибо за интересную статью. Собираюсь заняться обратным, т.е. перекодировкой из PDU в нормальный текст, т.к. резервная копия программы MyPhoneExplorer (MPB) SMS сохраняет, похоже, именно в нём…

  31. Отправляю смс в pdu, и если длина исходного текста более 55 символов (без учёта заголовка в 6-7 байт) то модем не отправляет. Хотя в стандарте заявлено 70 символов. Кто-нибудь сталкивался?

  32. Хорошая статья. Вот как выглядит код на Qt для формирования отправляемых данных:

    QByteArray tel = «79123456789»;
    QString msg = QStringLiteral(«Привет!!!»);

    QByteArray ret;
    ret.append( QByteArray::fromHex(«000100») );
    ret.append( static_cast(tel.count()) );
    ret.append( QByteArray::fromHex(«91») );

    if (tel.count()%2 == 1) tel.append(‘F’);
    for (int i=0; imakeEncoder(QTextCodec::IgnoreHeader);
    QByteArray encodedString = encoder->fromUnicode(msg);
    delete encoder;

    ret.append( static_cast(encodedString.count()) );
    ret.append( encodedString );

    qDebug() << ret.toHex();

    1. Все поплыло, часть текста удалилось, попробую снова.
      [code]
      QByteArray tel = «79123456789»;
      QString msg = QStringLiteral(«Привет!!!»);

      QByteArray ret;
      ret.append( QByteArray::fromHex(«000100») );
      ret.append( static_cast(tel.count()) );
      ret.append( QByteArray::fromHex(«91») );

      if (tel.count()%2 == 1) tel.append(‘F’);
      for (int i=0; imakeEncoder(QTextCodec::IgnoreHeader);
      QByteArray encodedString = encoder->fromUnicode(msg);
      delete encoder;

      ret.append( static_cast(encodedString.count()) );
      ret.append( encodedString );
      qDebug() << ret.toHex();
      [/code]

  33. TP-UDL — TP-User-Data-Length в спецификации указано, что нужно указать кол-во байтов, а не ваша фантазия по поводу кол-во символов.

  34. TP-MR — номер части сообщения, если текст не уместился в отведенное количество символов. По значению этого поля принимающая сторона понимает куда и в каком порядке «прилепить» сообщение.

  35. Спасибо!

    У меня заработало только после того, как убрал TP-VP из формулы.

    А так все отлично!

    P.S. >> TP-UDL — TP-User-Data-Length в спецификации указано, что нужно указать кол-во байтов, а не ваша фантазия по поводу кол-во символов.
    — указывал как у автора — количество символов!

    1. Спасибо! С момента публикации прошло 10 лет, я уже давно сменил интересы и приоритеты, но то, что статья еще кому-то помогает греет душу!

  36. StarXXX, Большое тебе человеческое СПАСИБО!!!
    Starline отказывался принимать СМС команды отправленные в текстовом режиме (автозапуск и т.д.). Много адекватных и понятных статей перечитал, но ни одна не рабочая схема.

    Найти хоть что-то рабочее PDU режиму смог только у тебя.

    P.S. С меня пиво!

Добавить комментарий для BestMann Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *