Как стать автором
Обновить

Получение Cell Broadcast сообщений

Cell Broadcast (CB) — широковещательная передача сообщений в сотовой сети. CB используется для массовой рассылки SMS-сообщений в сетях стандартов GSM, CDMA, WCDM.

Сообщения могут состоять как из одной, так и из нескольких страниц. Максимальное количество страниц для одного сообщения – 15.

Для работы с CBM (CB messages) в Symbian реализована специальная библиотека etel.lib. Она non-public, а это означает, что для нее нет описание в официальной документации. Тем не менее, некую информацию к этой библиотеке можно почерпнуть в хидере — «etelmm.h», или интернете.

Первое, что необходимо сделать, подключиться к сервису телефона, который содержит информацию о сообщениях, звонках, системных фильтрах.

RTelServer iServer;
iServer.Connect();
iServer.LoadPhoneModule("phonetsy.tsy");
TInt enumphone;
iServer.EnumeratePhones(enumphone));
RTelServer::TPhoneInfo iPhoneInfo;
iServer.GetPhoneInfo(0, iPhoneInfo));


Для получения доступа к этой информации есть класс RMobilePhone:

RMobilePhone iPhone;
iPhone.Open(iServer, iPhoneInfo.iName);


Нам нужны лишь CB сообщения, соответственно создаем объект класса RMobileBroadcastMessaging. Еще необходимо создать буфер, в который мы будем сохранять полученное сообщение (если пролистать стандарт CBM, то наткнемся на информацию, что максимальная длинна тела сообщения — 88 байт). Так же необходимо создать объект TRequestStatus, который позволит следить за ходом выполнения запроса. Объект RMobileBroadcastMessaging содержит дополнительные атрибуты сообщения, в нашем случае они не используется.

TRequestStatus iReqStatus;
TBuf8<88> iGsmMsgdata;
RMobileBroadcastMessaging iBroadcastMsg;
iBroadcastMsg.Open(iPhone);
RMobileBroadcastMessaging::TMobileBroadcastAttributesV1 iAttrInfo;
TPckg<RMobileBroadcastMessaging::TMobileBroadcastAttributesV1> iDes(iAttrInfo);


Все настроено. Оставляем в системе запрос на получение сообщения. Теперь, когда телефон получит новое CB сообщение, оно будет помещено в буфер iGsmMsgdata, а объект iReqStatus будет содержать результат выполнения запроса.

iBroadcastMsg.ReceiveMessage(iReqStatus, iGsmMsgdata, iDes);
User::WaitForRequest(iReqStatus);
if(iReqStatus.Int() == KErrNone)
// Обрабатываем полученное сообщение.
else
// В процесе получения сообщения возникла ошибка. Необходимо ее обработать.
}


User::WaitForRequest блокирует поток выполнения. Как вариант, сервис получения CB сообщений можно поместить в отдельный поток.

В конце, необходимо закрыть все используемые подключения:

iBroadcastMsg.Close();
iPhone.Close();
iServer.UnloadPhoneModule( KGsmModuleName );
iServer.Close();


Следующий этап – декодирование полученного сообщения.

CB сообщение имеет следующий формат:

Байты 00-01: ID сообщения;
Байты 02-03: канал, с которого сообщение получено;
Байт 04: схема кодирования сообщения;
Байт 05: параметры полученной страницы (четыре младших бита – общее количество страниц, из которых состоит сообщение; четыре старших бита – номер полученной страницы);
Байты 06-88: тело сообщения.

Схема кодировки, указывает способ декодирования сообщения. Самые распространённые: GSM 7bit (задается «0х01») и UCS-2 (задается «0х58» или «0х59»). Описание остальных схем кодирования можно найти в стандарте CB.

Кодировка GSM 7bit означает, что символ кодируется не 8, а 7 битами.
UCS-2 – под символ выделяется два байта.

Первых шесть байт сообщение содержать служебную информацию. (pData – дескриптор строки с сообщением).

int msgID;
memcpy(&msgID, pData, 2);
msgID = msgID & 0xFFFF;
endian_swap(msgID);
unsigned short channel;
memcpy(&channel, pData + 2, 2);
channel = channel & 0xFFFF;
endian_swap(channel);
int dcScheme;
memcpy(&dcScheme, pData + 4, 1);
dcScheme = dcScheme & 0xFF;
char pageParam;
memcpy(&pageParam, pData + 5, 1);
pageParam = pageParam & 0xFF;
int pageId = pageParam >> 4; //get hi byte
int pagesTotal = pageParam & 0xF; //get lo byte


Дальше необходимо декодировать тело сообщения. Как говорилось ранее, способ декодирования указывается в dcScheme.

Теперь о том, как декодировать.

В случае с GSM 7bit работает с С строками:

char cbuf;
int char_cnt = 0;
unsigned int bb = 0;
unsigned char ur = 0;
unsigned char curr = 0;
unsigned char prev = 0;
int readPos = 0;
while (readPos < (fileLen - 1))
{
memcpy(&cbuf, pFile + readPos, 1);
readPos++;
unsigned char aa = (1 << (7 - bb % 7)) - 1;
ur = cbuf & aa;
ur = (ur << (bb)) | prev;
curr = cbuf & (0xff ^ aa);
curr = curr >> (7 - bb);
prev = curr;
if (ur == 0xd)
{
break;
}
msgData[char_cnt] = ur;
bb = ++bb % 7;
char_cnt++;
if (bb == 0)
{
msgData[char_cnt++] = prev;
prev = 0;
}
}
msgData[char_cnt] = '\0';
// определяем количество символов в строке, после декодирования
while(msgData[len] != NULL)
{
len++;
}
// переводим строку С в строку Symbian
HBufC* nameHeap = HBufC::NewL(len+1);
TPtr namePtr(nameHeap->Des());
for(int i=0; i<len; i++)
{
namePtr.Append((TChar)msgData[i]);
}


Для UCS-2, программа будет выглядеть следующим образом:

HBufC* nameHeap = HBufC::NewL(len+1);
TPtr namePtr(nameHeap->Des());
TUint16 * pUCSText = (TUint16 *)(aText.Ptr() + KHeaderLen);
//меняем LittleEndian на BigEndian
for (int i = 0; i < len; ++i)
{
pUCSText[i] = (pUCSText[i] >> 8) + ((pUCSText[i] & 0xFF) << 8);
}
namePtr.Append( pUCSText, len );
// определяем конец строки
TChar paddingSymbol = 0x0D0D; //class0
TInt iEnd = namePtr.Locate(paddingSymbol);
if(KErrNotFound == iEnd) // пробуем второй вариант окончания строки для class1
{
paddingSymbol = 0x000D;
iEnd = namePtr.Locate(paddingSymbol);
}
if(KErrNotFound != iEnd)
{
namePtr.SetLength(iEnd);
}


Если все сделано правильно, в namePtr будет указывать на тело нашего сообщения. Так как, сообщение может состоять из нескольких частей, то при сборке сообщения необходимо учитывать параметры страницы.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.