Over The Air Provision (OTAP) как функция модема TC65Т

 

 Это мое повествование об одном из свойств уникального GSM модема SIEMENS TC65

http://tc65-terminal.ru или http://www.cinterion.com/tc65t.html .

 Речь вовсе не о том, что этот модем поддерживает  JAVA  программирование, что при наличии в нем десяти дискретных входов-выходов и двух аналоговых входов делает его незаменимым при разработке систем удаленного контроля технологических процессов по GSM/GPRS. Речь о том, что делать, если потребовалось обновить уже работающую на модеме программу, а сам модем находиться в несколько удаленном месте.

 И так воспользуемся тем, что на английском звучит так:

Secure data transfer and easy software updates over the air (OTA)

 т. е. обеспечивает передачу данных и удобное обновление программы через эфир. Будем называть эту возможность OTAP функцией.

 Разбираемся дальше и в документации находим рисунок:

 

 

и еще определенные требования к СМС: An OTAP control SM must use a Submit PDU with Class1, PID $7d and 8 bit encoding.

 

Install operation:

 

First SM:

 

OTAP_IMPNG

PWD:secret

JADURL:http://www.greatcompany.com/coolapps/mega.jad

APPDIR:a:/work/appdir

HTTPUSER:user

HTTPPWD:anothersecret

 


 

Second SM:

 

OTAP_IMPNG
PWD:secret
BEARER:gprs
APNORNUM:access.to-thenet.net
NETUSER:nobody
NETPWD:nothing
DNS:192.168.1.2
START:install

 

Delete operation:

 

OTAP_IMPNG
PWD:secret
APPDIR:a:/work/appdir
START:delete

 

 Понятно, что мы должны на каком-то web-сервере выложить нашу обновленную программу в виде файлов *.jad  и *.jar. Для этого даже можно воспользоваться www.narod.ru. Далее послать СМС специального вида на модем, и модем самостоятельно через GPRS скачает и запустит новую программу. Смущают только некие требования к СМС в виде:  PDU with Class 1 и Pid $7d and 8 bit encoding. Почему-то приходит мысль, что обычный мобильный телефон для этой операции не подойдет и нужен еще один GSM модем, а формировать СМС придется с помощью специальной программы, которую сейчас разработаем. Так что же из себя представляет СМС в виде: PDU with Class 1 и Pid $7d and 8 bit encoding.  Пытаемся найти ответ на сайте SMS and PDU format . Там весьма подробно разобрано СМС в виде: PDU with Class 0 и Pid $00 and 7 bit encoding c  текстом hellohello. На модем-передатчик в этом случае необходимо подать следующие команды:

 

AT+CMGF=0 //Set PDU mode AT+CSMS=0 //Check if modem supports SMS commands AT+CMGS=23 //Send message, 23 octets (excluding the two initial zeros) >0011000B916407281553F80000AA0AE8329BFD4697D9EC37<ctrl-z>

 

Теперь рассмотрим, что же нужно нам.

 Команду: AT+CMGF=0 используем без изменений т. к. модем надо таки переключить в режим PDU.

 Команда: AT+CMGS= XX говорит о размере СМС в байтах, т. е. нам придется составить СМС, определить его размер, подать эту команду с цифрами обозначающими размер нашей СМС. Причем размер СМС не может превышать 140 байт (XX максимально может быть 139 т. к. считаем с 0), в противном случае полезный текст отправляется несколькими СМС не превышающими 140 байт.

 Ну, а далее на модем-передатчик через COM-порт передадим, составленное ранее СМС:

0011000B91 - используется без изменения,

6407281553F8 – номер телефона (46708251358) куда будет отправлено СМС,

00 - TP-PID в нашем случае должно быть 7d,

00 - TP-DCS, здесь Class 0 и 7 bit encoding. В нашем случае должно быть 15 т. е. Class 1 и

8 bit encoding,

AA – оператор связи будет пытаться доставить СМС адресату в течении 4-х дней,

0А – размер в байтах собственно полезного текста - нам тоже придется считать,

E8329BFD4697D9EC37 – это закодировано hellohello с использованием 7 битового кодирования, нам же надо 8 битовое кодирование и вовсе не hellohello, а что-то на подобие:

 

OTAP_IMPNG

PWD:

APNORNUM:internet.tele2.ru

JADURL:http://www.csu-tst.narod.ru/MyTC65.jar

APPDIR:a:\

BEARER:gprs

START:install

 

 И так: запускаем С++ Builder 6, создаем новый проект. На форму кидаем: во-первых два поля Edit для ввода номера телефона и идентификатора , два элемента ListBox где будут отображаться номера телефонов уже существующих в базе данных и две кнопки “Записать” и “Удалить”; далее располагаем поля Edit, предназначенные для ввода содержимого нашей СМС и кнопка “Make SMS” с помощью которой СМС сгенерируется и сохраниться в базе данных; верхнее поле Memo предназначено для отображения текста СМС; нижнее поле Memo предназначено для отображения AT-команд, которые будут поступать на модем передатчик через Com-порт; два ComboBox рядом с текстом Com port предназначены для выбора com порта, к которому подключен модем - передатчик и установки скорости обмена по выбранному Com – порту; текстовое поле Nb chars предназначено для отображения размера СМС в байтах, если размер СМС больше 140 байт, то формируются две СМС и размер их отображается в текстовых полях Nb chars1 и Nb chars2; кнопка Send sms формирует AT команды, необходимые для отправки СМС.

Вот что у меня получилось:

 

Теперь напишем функции для работы с Сом портом. В основном используются те же функции, что и для работы с файлами: CreateFile, WriteFile, ReadFile. Используя их напишем функции для инициализации Сом порта, записи информации в Сом порт и чтения информации из Сом порта

 

Инициализация Com порта.

DCB dcb;

HANDLE hComm;

 

//Установка настроек com-порта

bool __fastcall InstallComm(AnsiString sPort="COM1",AnsiString Baud="115200" ) //номер порта

{

  BOOL fSuccess;

 

  char szCommPattern[8];

    if (sPort=="")

    return false;

  sprintf(szCommPattern, "%s", sPort.c_str());

  hComm = CreateFile(szCommPattern,

      GENERIC_READ | GENERIC_WRITE,0,0,

      OPEN_EXISTING,0,0);

  if (hComm == INVALID_HANDLE_VALUE)

       return false;

 

//Получаем настройки порта

  fSuccess = GetCommState(hComm, &dcb);

  if (!fSuccess)

    return false;

  dcb.BaudRate = StrToInt(Baud);  //CBR_115200;

  dcb.ByteSize = 8;

  dcb.fParity = FALSE;

  dcb.Parity = NOPARITY;

  dcb.StopBits = TWOSTOPBITS;

  dcb.fOutxCtsFlow = FALSE;

  dcb.fOutxDsrFlow = FALSE;

  dcb.fDtrControl = DTR_CONTROL_DISABLE;

  dcb.fDsrSensitivity = FALSE;

  dcb.fRtsControl = RTS_CONTROL_DISABLE;

 

//Устанавливаем новые настройки

  fSuccess = SetCommState(hComm, &dcb);

  if (!fSuccess)

    return false;

 

//Устанавливаем размеры входного и выходного буфера данных

  SetupComm(hComm, 1024, 1024);

 

/* Установка таймаутов. 
        Служит, чтобы программа не висла
        в ожидании ответа от модема */

COMMTIMEOUTS TO;

  TO.ReadIntervalTimeout = 80;

  TO.ReadTotalTimeoutMultiplier = 1;

  TO.ReadTotalTimeoutConstant = 100;

  TO.WriteTotalTimeoutMultiplier = 200;

  TO.WriteTotalTimeoutConstant = 2000;

  SetCommTimeouts(hComm, &TO);

  return true;

}

 

 

 

Запись в com-порт.

void WriteBuffer(char *buf_out)

{

 unsigned long dwSize;

// char *buf_out="AT+CMGF=0\r";

 

GetCommState(hComm,&dcb);

dcb.fDtrControl=DTR_CONTROL_DISABLE;

SetCommState(hComm,&dcb);

GetCommState(hComm,&dcb);

dcb.fDtrControl=DTR_CONTROL_ENABLE;

SetCommState(hComm,&dcb);

 

    WriteFile(hComm, buf_out, strlen(buf_out), &dwSize, NULL);

    Sleep(1);

}

 

 

Для чтения из Сом порта просто будем вызывать функцию ReadFile

  BOOL ReadFile(

    HANDLE hFile,      // handle of file to read

    LPVOID lpBuffer,   // address of buffer that receives data 

    DWORD nNumberOfBytesToRead,           // number of bytes to read

    LPDWORD lpNumberOfBytesRead,          // address of number of bytes read

    LPOVERLAPPED lpOverlapped    // address of structure for data

   );

 

Еще две функции относящиеся к Сом порту.

Эта просто создает список скоростей обмена в Сом порту для  ComboBox2.

void TForm1::SpeedCOMPort(void)

{

  ComboBox2->Items->Add("115200");

  ComboBox2->Items->Add("57600");

  ComboBox2->Items->Add("38400");

  ComboBox2->Items->Add("19200");

  ComboBox2->Items->Add("9600");

  ComboBox2->Items->Add("4800");

  ComboBox2->Items->Add("2400");

  ComboBox2->Items->Add("1200");

  ComboBox2->ItemIndex = 0;

 

}

 

А эта функция определяет, существует ли вообще у компьютера доступные Сом порты и создает из них список для ComboBox1.

void TForm1::DetectCOMport(void)

 {

   HANDLE hComm_test;

   String comm_port;

    for(int i = 1; i < 255; i++)

    {

        comm_port = "COM" + IntToStr(i);

 

        hComm_test = CreateFile(comm_port.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);

        if(hComm_test != INVALID_HANDLE_VALUE)

        {

            ComboBox1->Items->Add("COM" + IntToStr(i));

            CloseHandle(hComm_test);

        }

 

     }

    if(ComboBox1->Items->Capacity>=1)

    {

     ComboBox1->ItemIndex = 0;

     SpeedCOMPort();

     }

     else

     {

      ComboBox1->Text="";

      ComboBox2->Text="";

     }

 

 }      

 

 Теперь надо написать функции преобразующие текст СМС в формат PDU с Классом 1, PID$7d и 8 битовым кодированием.

Преобразуем номер телефона:

AnsiString ConvertPhoneNumber(char* PhoneNumber)

 {

   char telefon[13];

   char telefonConvert[13];

 

   sprintf(telefon,"%s",PhoneNumber);

//Добавляем символ F в ASCII коде

   telefon[strlen(telefon)]='\x46';

   telefon[12]='\x00';

 

//Меняем четные и нечетные символы номера телефона местами

     for(int i=0;i<12;i=i+2)

      {

        telefonConvert[i]=telefon[i+1];

        telefonConvert[i+1]=telefon[i];

       }

     telefonConvert[12]='\x00';

  

 

    return AnsiString(telefonConvert);

 

 }

 

 

Функция преобразующая текст СМС в ASCII код.

AnsiString ConvertToMessageHex(AnsiString message)

  {

   AnsiString str="";

   int integer;

 

   char out[10];

   char* var=new char[strlen(message.c_str())+2];

   strcpy(var, message.c_str());

   for(int i=0; i<strlen(var); i++)

   {

   integer=(int)var[i];

   itoa(integer, out, 16);

 

   str=str+AnsiString(out);

   }

   delete []var;

    str=UpperCase(str);

   return str;

 

  }

 

 

Теперь создадим СМС используя PDU формат. Эту функцию используем если общий размер СМС меньше 140 байт.

AnsiString TForm1::CreateMessagePDU(void)

 {

  char* begin0011000B91="0011000B91";

  char telefon[12];

  char* afteTelefon="7d15AA";

  AnsiString strOnePDU;

 

 //шапка СМС ,  считываем выделенный номер телефона из ListBox1

 sprintf(telefon,"%s",ListBox1->Items->Strings[ListBox1->ItemIndex].c_str());

   strOnePDU=AnsiString(begin0011000B91)+ConvertPhoneNumber(telefon)+

      AnsiString(afteTelefon);

 

  //Сформируем полезный текст, подсчитаем его размер, все это представим  ASCII  символами, и добавим к уже созданной шапке

 

   AnsiString MessageText="";

   int b;

   char* OTAP_IMPNG="OTAP_IMPNG";

   char* PWD="PWD:";

   char* APNORNUM="APNORNUM:";

   char* NETUSER="NETUSER:";

   char* NETPWD="NETPWD:";

   char* DNS="DNS:";

   char* JADURL="JADURL:";

   char* APPDIR="APPDIR:";

   char* BEARER="BEARER:gprs";

   char* START="START:install";

   int lenStr;

 

  Memo2->Lines->Clear();

 

  char* var1=new char[strlen(OTAP_IMPNG)+2];

  strcpy(var1, OTAP_IMPNG);

   b=strlen(var1);

 

   var1[b]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var1))+"0A";

// 0A в ASCII коде LF перевод каретки на новую строку

   delete []var1;

  

   char* var2=new char[strlen((PWD+Edit4->Text).c_str())+2];

   strcpy(var2, (PWD+Edit4->Text).c_str());

   b=strlen(var2);

 

   var2[b]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var2))+"0A";

   delete []var2;

 

   if(!(Edit5->Text.IsEmpty()))

   {

 

   char* var3=new char[strlen((APNORNUM+Edit5->Text).c_str())+2];

   strcpy(var3, (APNORNUM+Edit5->Text).c_str());

   b=strlen(var3);

 

   var3[b+1]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var3))+"0A";

   delete []var3;

   }

 

 

   if(!(Edit6->Text.IsEmpty()))

   {

 

   char* var9=new char[strlen((NETUSER+Edit6->Text).c_str())+2];

   strcpy(var9, (NETUSER+Edit6->Text).c_str());

   b=strlen(var9);

 

   var9[b+1]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var9))+"0A";

   delete []var9;

   }

 

   if(!(Edit7->Text.IsEmpty()))

   {

 

   char* var10=new char[strlen((NETPWD+Edit7->Text).c_str())+2];

   strcpy(var10, (NETPWD+Edit7->Text).c_str());

   b=strlen(var10);

 

   var10[b+1]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var10))+"0A";

   delete []var10;

   }

 

 

   if(!(Edit2->Text.IsEmpty()))

   {

 

   char* var4=new char[strlen((JADURL+Edit2->Text).c_str())+2];

   strcpy(var4, (JADURL+Edit2->Text).c_str());

   b=strlen(var4);

 

   var4[b]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var4))+"0A";

   delete []var4;

   }

 

   if(!(Edit3->Text.IsEmpty()))

   {

 

   char* var5=new char[strlen((APPDIR+Edit3->Text).c_str())+2];

   strcpy(var5, (APPDIR+Edit3->Text).c_str());

   b=strlen(var5);

 

   var5[b]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var5))+"0A";

   delete []var5;

   }

   char* var6=new char[strlen(BEARER)+2];

   strcpy(var6, BEARER);

   b=strlen(var6);

 

   var6[b]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var6))+"0A";

   delete []var6;

 

 

   if(!(Edit8->Text.IsEmpty()))

   {

 

   char* var11=new char[strlen((DNS+Edit8->Text).c_str())+2];

   strcpy(var11, (DNS+Edit8->Text).c_str());

   b=strlen(var11);

 

   var11[b]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var11))+"0A";

   delete []var11;

   }

 

 

  

   char* var7=new char[strlen(START)+2];

   strcpy(var7, START);

   b=strlen(var7);

 

   var7[b]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var7))+"0A";

   delete []var7;

 

 //Подсчитаем размер получившейся СМС

  lenStr=strlen(MessageText.c_str())/2;

    if(lenStr<140)

    {

     Memo2->Lines->Add(OTAP_IMPNG);

     Memo2->Lines->Add(PWD+Edit4->Text);

       if(!(Edit5->Text.IsEmpty())) Memo2->Lines->Add(APNORNUM+Edit5->Text);

       if(!(Edit6->Text.IsEmpty())) Memo2->Lines->Add(NETUSER+Edit6->Text);

       if(!(Edit7->Text.IsEmpty())) Memo2->Lines->Add(NETPWD+Edit7->Text);

       if(!(Edit2->Text.IsEmpty())) Memo2->Lines->Add(JADURL+Edit2->Text);

       if(!(Edit3->Text.IsEmpty())) Memo2->Lines->Add(APPDIR+Edit3->Text);

     Memo2->Lines->Add(BEARER);

       if(!(Edit8->Text.IsEmpty())) Memo2->Lines->Add(DNS+Edit8->Text);

     Memo2->Lines->Add(START);

     }

 

  char lenHex[10];

 //Число обозначающее размер надо представить в шестнадцатеричном виде.

  itoa(lenStr, lenHex, 16);

  strOnePDU=strOnePDU+UpperCase(AnsiString(lenHex))+MessageText;

//Вот и получили СМС в PDU формате, можно отправлять в СОМ порт.

  return  strOnePDU;

 }

Если размер текста больше 140 байт, то сформируем две СМС:

 

bool TForm1::CreateMessagePDU_big(AnsiString& MessageFirst, AnsiString& MessageSecond)

 {

  char* begin0011000B91="0011000B91";

  char telefon[12];

  char* afteTelefon="7d15AA";

  AnsiString strOnePDU;

  bool first=false;

  bool second=false;

 

  //считывем выделенный номер телефона из ListBox1

   sprintf(telefon,"%s",ListBox1->Items->Strings[ListBox1->ItemIndex].c_str());

   strOnePDU=AnsiString(begin0011000B91)+ConvertPhoneNumber(telefon)+

      AnsiString(afteTelefon);

 

   //Возвращаем SMS сообщение одной строкой без пробелов

 

   AnsiString MessageText="";

   int b;

   char* OTAP_IMPNG="OTAP_IMPNG";

   char* PWD="PWD:";

   char* APNORNUM="APNORNUM:";

   char* NETUSER="NETUSER:";

   char* NETPWD="NETPWD:";

   char* DNS="DNS:";

   char* JADURL="JADURL:";

   char* APPDIR="APPDIR:";

   char* BEARER="BEARER:gprs";

   char* START="START:install";

   int lenStr;

 

  char* var1=new char[strlen(OTAP_IMPNG)+2];

  strcpy(var1, OTAP_IMPNG);

   b=strlen(var1);

 

   var1[b]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var1))+"0A";

   delete []var1;

 

   char* var2=new char[strlen((PWD+Edit4->Text).c_str())+2];

   strcpy(var2, (PWD+Edit4->Text).c_str());

   b=strlen(var2);

 

   var2[b]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var2))+"0A";

   delete []var2;

 

 

 

  if(!(Edit5->Text.IsEmpty()))

   {

   char* var3=new char[strlen((APNORNUM+Edit5->Text).c_str())+2];

   strcpy(var3, (APNORNUM+Edit5->Text).c_str());

   b=strlen(var3);

 

   var3[b+1]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var3))+"0A";

   delete []var3;

   }

 

  if(!(Edit6->Text.IsEmpty()))

    {

 

     char* var9=new char[strlen((NETUSER+Edit6->Text).c_str())+2];

     strcpy(var9, (NETUSER+Edit6->Text).c_str());

     b=strlen(var9);

 

     var9[b+1]='\x00';

     MessageText=MessageText+

     ConvertToMessageHex(AnsiString(var9))+"0A";

     delete []var9;

     }

 

 

   if(!(Edit7->Text.IsEmpty()))

     {

 

     char* var10=new char[strlen((NETPWD+Edit7->Text).c_str())+2];

     strcpy(var10, (NETPWD+Edit7->Text).c_str());

     b=strlen(var10);

 

     var10[b+1]='\x00';

     MessageText=MessageText+

     ConvertToMessageHex(AnsiString(var10))+"0A";

     delete []var10;

     }

 

     if(!(Edit2->Text.IsEmpty()))

      {

 

       char* var4=new char[strlen((JADURL+Edit2->Text).c_str())+2];

       strcpy(var4, (JADURL+Edit2->Text).c_str());

       b=strlen(var4);

 

       var4[b]='\x00';

       MessageText=MessageText+

       ConvertToMessageHex(AnsiString(var4))+"0A";

       delete []var4;

       }

 

    

     lenStr=strlen(MessageText.c_str())/2;

     char lenHex1[10];

     itoa(lenStr, lenHex1, 16);

     MessageFirst=strOnePDU+UpperCase(AnsiString(lenHex1))+MessageText;

   //Первая СМС сформирована, проверяем чтобы размер был менее 140 байт

 

     if(lenStr<140)

      {

 

     Memo2->Lines->Add(OTAP_IMPNG);

     Memo2->Lines->Add(PWD+Edit4->Text);

       if(!(Edit5->Text.IsEmpty())) Memo2->Lines->Add(APNORNUM+Edit5->Text);

       if(!(Edit6->Text.IsEmpty())) Memo2->Lines->Add(NETUSER+Edit6->Text);

       if(!(Edit7->Text.IsEmpty())) Memo2->Lines->Add(NETPWD+Edit7->Text);

       if(!(Edit2->Text.IsEmpty())) Memo2->Lines->Add(JADURL+Edit2->Text);

       first=true;

       }

//----------------------------------------------------------

    MessageText="";

 

    char* var11=new char[strlen(OTAP_IMPNG)+2];

    strcpy(var11, OTAP_IMPNG);

    b=strlen(var11);

 

   var11[b]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var11))+"0A";

   delete []var11;

  

 

   char* var12=new char[strlen((PWD+Edit4->Text).c_str())+2];

   strcpy(var12, (PWD+Edit4->Text).c_str());

   b=strlen(var12);

 

   var12[b]='\x00';

   MessageText=MessageText+

   ConvertToMessageHex(AnsiString(var12))+"0A";

   delete []var12;

 

    if(!(Edit3->Text.IsEmpty()))

        {

 

         char* var5=new char[strlen((APPDIR+Edit3->Text).c_str())+2];

         strcpy(var5, (APPDIR+Edit3->Text).c_str());

         b=strlen(var5);

 

         var5[b]='\x00';

         MessageText=MessageText+

         ConvertToMessageHex(AnsiString(var5))+"0A";

         delete []var5;

         }

 

 

 

   char* var6=new char[strlen(BEARER)+2];

      strcpy(var6, BEARER);

      b=strlen(var6);

 

      var6[b]='\x00';

      MessageText=MessageText+

      ConvertToMessageHex(AnsiString(var6))+"0A";

   delete []var6;

 

 

      if(!(Edit8->Text.IsEmpty()))

         {

 

         char* var11=new char[strlen((DNS+Edit8->Text).c_str())+2];

         strcpy(var11, (DNS+Edit8->Text).c_str());

          b=strlen(var11);

 

          var11[b]='\x00';

          MessageText=MessageText+

          ConvertToMessageHex(AnsiString(var11))+"0A";

          delete []var11;

          }

 

 

    char* var7=new char[strlen(START)+2];

    strcpy(var7, START);

    b=strlen(var7);

 

    var7[b]='\x00';

    MessageText=MessageText+

    ConvertToMessageHex(AnsiString(var7))+"0A";

    delete []var7;

 

     lenStr=strlen(MessageText.c_str())/2;

     char lenHex2[10];

     itoa(lenStr, lenHex2, 16);

     MessageSecond=strOnePDU+UpperCase(AnsiString(lenHex2))+MessageText;

   //Вторая СМС сформирована, проверяем чтобы размер ее был меньше 140 байт

    lenStr=strlen(MessageText.c_str())/2;

 

         if(lenStr<140)

           {

                 Memo2->Lines->Add(" ");

                 Memo2->Lines->Add(OTAP_IMPNG);

                 Memo2->Lines->Add(PWD+Edit4->Text);

 

                     if(!(Edit3->Text.IsEmpty())) Memo2->Lines->Add(APPDIR+Edit3->Text);

                 Memo2->Lines->Add(BEARER);

                     if(!(Edit8->Text.IsEmpty())) Memo2->Lines->Add(DNS+Edit8->Text);

                 Memo2->Lines->Add(START);

                 second=true;

                  }

     //Если размер и первой и второй СМС меньше 140 байт возвращаем TRUE, если нет FALSE, но по идее размера двух СМС должно хватить для передачи нужной нам информации.

      if (first && second)

      return true;

      else

      return false;

 

 }

 

 

 И вот здесь, для отправки СМС мы используем наши функции для работы с COM портом и функции создания СМС в формате PDU

 

void TForm1::SendSMSSmall(void)
{

if(FindIDSmsFile()==true)
{
int ibuf3;
char Data[2000];
int len;

char *buf1="AT+CMGF=0\r";
char *buf="AT+CMGS=";
AnsiString AT_pl_CMGS="";
len=strlen(CreateMessagePDU().c_str())/2-1;
AT_pl_CMGS=AT_pl_CMGS+AnsiString(buf)+CurrToStr(len)+"\r";

char* buf3=new char[strlen(CreateMessagePDU().c_str())+2];
strcpy(buf3,CreateMessagePDU().c_str());



Memo1->Lines->Clear();

unsigned long dwSize;
int a,b,c;

if(!InstallComm(ComboBox1->Text, ComboBox2->Text))
MessageBox(NULL, "Невозможно открыть последовательный порт", "Error", MB_OK);
else
{

WriteBuffer(buf1);
a=ReadFile( hComm, Data, 2000, &dwSize, NULL );
if(a>0)
{
Data[dwSize] = 0;
Memo1->Lines->Add(Data);
}//if(a>0)
CloseHandle(hComm);
} //else
//-----------------------------------------------------------------
Sleep(1000);
//--------------------------------------------------------------------
if(!InstallComm(ComboBox1->Text, ComboBox2->Text))
MessageBox(NULL, "Невозможно открыть последовательный порт", "Error", MB_OK);
else
{
WriteBuffer(AT_pl_CMGS.c_str());
b=ReadFile( hComm, Data, 2000, &dwSize, NULL );
if(b>0)
{
Data[dwSize] = 0;
Memo1->Lines->Add(Data);
}//if(b>0)
CloseHandle(hComm);
} //else
//-----------------------------------------------------------------------
Sleep(2000);
//------------------------------------------------------------------------
if(!InstallComm(ComboBox1->Text, ComboBox2->Text))
MessageBox(NULL, "Невозможно открыть последовательный порт", "Error", MB_OK);
else
{
ibuf3=strlen(buf3);
buf3[ibuf3]='\x1A';
// Символ ‘\x1A’ в ASCII символах SUB - конец файла или <ctrl-z>
WriteBuffer(buf3);
c=ReadFile( hComm, Data, 2000, &dwSize, NULL );
if (c>0)
{
Data[ibuf3] = 0;
Memo1->Lines->Add(Data);
}//if (c>0)
CloseHandle(hComm);
} //else


delete []buf3;
}//if(FindIDSmsFile()==true)

}

 

Тоже самое если информации много и необходимо посылать две СМС

void TForm1::SendSMSBig(void)
{

if(FindIDSmsFile()==true)
{
int ibuf3;
int ibuf4;
char Data[2000];
int len;
char *buf1="AT+CMGF=0\r";
char *buf="AT+CMGS=";
AnsiString AT_pl_CMGS="";

AnsiString One;
AnsiString Two;
bool yes;
yes=CreateMessagePDU_big(One, Two);
if(yes)
{
len=strlen(One.c_str())/2-1;
AT_pl_CMGS="";
AT_pl_CMGS=AT_pl_CMGS+AnsiString(buf)+CurrToStr(len)+"\r";
char* buf3=new char[strlen(One.c_str())+2];
strcpy(buf3,One.c_str());


Memo1->Lines->Clear();

unsigned long dwSize;
int a,b,c;
if(!InstallComm(ComboBox1->Text, ComboBox2->Text))
MessageBox(NULL, "Невозможно открыть последовательный порт", "Error", MB_OK);
else
{
WriteBuffer(buf1);
a=ReadFile( hComm, Data, 2000, &dwSize, NULL );
if(a>0)
{
Data[dwSize] = 0;
Memo1->Lines->Add(Data);
}//if(a>0)
CloseHandle(hComm);
}//else
//-----------------------------------------------------------------------------
Sleep(1000);
//----------------------------------------------------------------------------
if(!InstallComm(ComboBox1->Text, ComboBox2->Text))
MessageBox(NULL, "Невозможно открыть последовательный порт", "Error", MB_OK);
else
{
WriteBuffer(AT_pl_CMGS.c_str());
b=ReadFile( hComm, Data, 2000, &dwSize, NULL );
if(b>0)
{
Data[dwSize] = 0;
Memo1->Lines->Add(Data);
}//if(b>0)
CloseHandle(hComm);
} //else
//------------------------------------------------------------------------------
Sleep(2000);
//-----------------------------------------------------------------------------
if(!InstallComm(ComboBox1->Text, ComboBox2->Text))
MessageBox(NULL, "Невозможно открыть последовательный порт", "Error", MB_OK);
else
{
ibuf3=strlen(buf3);
buf3[ibuf3]='\x1A';
// Символ ‘\x1A’ в ASCII символах SUB - конец файла или <ctrl-z>
WriteBuffer(buf3);
c=ReadFile( hComm, Data, 2000, &dwSize, NULL );
if (c>0)
{
Data[ibuf3] = 0;
Memo1->Lines->Add(Data);
}//if (c>0)
CloseHandle(hComm);
} //else


delete []buf3;

//============================================================================
Sleep(10000);
//============================================================================
len=strlen(Two.c_str())/2-1;
AT_pl_CMGS="";
AT_pl_CMGS=AT_pl_CMGS+AnsiString(buf)+CurrToStr(len)+"\r";
char* buf4=new char[strlen(Two.c_str())+2];
strcpy(buf4,Two.c_str());

if(!InstallComm(ComboBox1->Text, ComboBox2->Text))
MessageBox(NULL, "Невозможно открыть последовательный порт", "Error", MB_OK);
else
{
WriteBuffer(buf1);
a=ReadFile( hComm, Data, 2000, &dwSize, NULL );
if(a>0)
{
Data[dwSize] = 0;
Memo1->Lines->Add(Data);
}//if(a>0)
CloseHandle(hComm);
} //else
//-----------------------------------------------------------------------------
Sleep(1000);
//-----------------------------------------------------------------------------

if(!InstallComm(ComboBox1->Text, ComboBox2->Text))
MessageBox(NULL, "Невозможно открыть последовательный порт", "Error", MB_OK);
else
{
WriteBuffer(AT_pl_CMGS.c_str());
b=ReadFile( hComm, Data, 2000, &dwSize, NULL );
if(b>0)
{
Data[dwSize] = 0;
Memo1->Lines->Add(Data);
}//if(b>0)
CloseHandle(hComm);
} //else
//-----------------------------------------------------------------------------
Sleep(2000);
//-----------------------------------------------------------------------------
if(!InstallComm(ComboBox1->Text, ComboBox2->Text))
MessageBox(NULL, "Невозможно открыть последовательный порт", "Error", MB_OK);
else
{
ibuf4=strlen(buf4);
buf4[ibuf4]='\x1A';
// Символ ‘\x1A’ в ASCII символах SUB - конец файла или <ctrl-z>
WriteBuffer(buf4);
c=ReadFile( hComm, Data, 2000, &dwSize, NULL );
if (c>0)
{
Data[ibuf4] = 0;
Memo1->Lines->Add(Data);
}//if(c>0)
CloseHandle(hComm);
}//else
delete []buf4;

}// if(yes)

}//if(FindIDSmsFile()==true)

}

 

Во время работы программы я буду использовать два вспомогательных файла. В одном будет список телефонов, а в другом параметры, передаваемые в СМС. Объединятся эта информация будет через идентификатор.   

 

//Функция обработки события: нажатия кнопки Записать (Button6)

void __fastcall TForm1::Button6Click(TObject *Sender)

{

  bool numOK=true;

  char telefon[13];

  char Id_str[10];

  int Id;

  int len;

  FILE *telef;

 

// Индентификатор  переводится из AnsiString  в char и копируется в переменную Id_str

  sprintf(Id_str,"%s",Edit9->Text.c_str());

 

//Проверяем чтобы состоял из одних только цифр

  int a=10;

  for(int i=0;i<a-1;i++)

  {

   

     if(Id_str[i]=='\x00')

     {

      Id=Edit9->Text.ToInt();

      break;

     }

 

     else if(!(('\x30'<=Id_str[i])&&(Id_str[i]<='\x39')))

      {

       MessageBox(NULL,"Идентификатор должен состоять из цифр!", "Error", MB_OK);

       numOK=false;

       break;

       }

      else if(('\x30'<=Id_str[i])&&(Id_str[i]<='\x39'))

        {

         continue;

 

        }

  }

 

//Если идентификатор состоит из цифр, то проверяем чтобы не было второго такого же.

  if  (numOK==true)

  {

    FILE *id_telef;

    int id_file;

    char telefon_file[13];

 

         if ((id_telef = fopen("telefon.dat", "rb"))!=NULL)

     {

       while (fscanf(id_telef, "%d %s",&id_file, telefon_file)!=EOF)

       {

         if (id_file==Id)

           {

             numOK=false;

             MessageBox(NULL,"Телефон с таким идентификатором уже существует!", "Error", MB_OK);

             break;

            }

 

        }

       fclose(id_telef);

     }

 

  }

 

 

//Теперь т. к. идентификатор проверен и соответствует нашим требованиям займемся номером телефона.

 if  (numOK==true)

 {

  sprintf(telefon,"%s",Edit1->Text.c_str());

 //В номере телефона используем только цифры, даже если первый символ в номере телефона “ +”.

  if (telefon[0]=='\x2B')

    {

    // MessageBox(NULL, "Нашел +", "Error", MB_OK);

     int n=13;

     for(int i=0;i<n-1;i++)

      {

        telefon[i]=telefon[i+1];

       }

      telefon[13]='\x00';

    }

 

  len=strlen(telefon);

//Проверяем чтобы номер телефона состоял из 11 цифр

 if (len!=11)

   {

       MessageBox(NULL,"Номер телефона должен состоять из 11 цифр!", "Error", MB_OK);

        numOK=false;

    }

   else

    {

      int n=12;

      for(int i=0;i<n-1;i++)

      {

         if(!(('\x30'<=telefon[i])&&(telefon[i]<='\x39')))

          {

           MessageBox(NULL,"В номере телефона должны быть только цифры!", "Error", MB_OK);

           numOK=false;

           break;

           }

      

       }

      

 

     // Если номер телефона тоже прошел проверку, то записываем идентификатор и номер телефона в файл.

     if (numOK==true)

       {

        ListBox1->Items->Add(telefon);

        ListBox2->Items->Add(CurrToStr(Id));

         Edit1->Text="";

         Edit9->Text="";

 

          if((telef = fopen("telefon.dat", "ab"))

             == NULL)

          {

            MessageBox(NULL, "Не могу записать в файл", "Error", MB_OK);

           }

           else

            {

              fprintf(telef,"%d %s\r", Id, telefon);

              fclose(telef);

 

            }

         } //if (numOK==true)

 

     } // else  if (len!=11)

  } //  (numOK==true)

}

//---------------------------------------------------------------------------      

 

 

//При запуске программы мы считываем идентификаторы и соответствующие им номера телефонов из файла и заполняем этими списками ListBox1 и ListBox2. Также определяем номера доступных Com  портов.

void __fastcall TForm1::FormCreate(TObject *Sender)

{

        Label13->Visible=False;

        Label14->Visible=False;

        Label15->Visible=False;

        Label16->Visible=False;

 

        Label10->Visible=False;

        Label11->Visible=False;

 

 

  FILE *telef;

  int Id;

  char telefon[12];

  if ((telef = fopen("telefon.dat", "rb"))!=NULL)

     {

       while (fscanf(telef, "%d %s",&Id, telefon)!=EOF)

       {

         ListBox1->Items->Add(telefon);

         ListBox2->Items->Add (CurrToStr(Id));

        }

       fclose(telef);

     }

 

       DetectCOMport();

  

 

}    

 

//Чтобы удалить номер телефона надо его выделить в списке ListBox1 и нажать кнопку “Удалить”. Одновременно удалятся данные СМС связанные с этим номером через идентификатор.

void __fastcall TForm1::Button7Click(TObject *Sender)

{

 

if(ListBox1->ItemIndex<0)

  {

   ShowMessage("Вы не выбрали номер для удаления");

   }

 else

 {

  

   DellFileSMS();

   DellFileTelefon();

  }

 

 

}

//--------------------------------------------------------------------------- 

 

void TForm1::DellFileTelefon(void)

 {

   FILE *telef;

   FILE *telef1;

   int Id;

   char telefon[12];

 

   if ((telef = fopen("telefon.dat", "rb"))!=NULL)

    {

        if ((telef1 = fopen("telefon.tmp", "wb"))!=NULL)

          {

 

            while (fscanf(telef, "%d %s",&Id, telefon)!=EOF)

             {

 

              if (Id!=ListBox2->Items->Strings[ListBox2->ItemIndex].ToInt())

                fprintf(telef1,"%d %s\r",Id, telefon);

               //ListBox1->Items->Add(telefon);

             }

            fclose(telef1);

     }

    fclose(telef);

 

  }

 

   ListBox1->DeleteSelected();

   ListBox2->DeleteSelected();

   DeleteFile("telefon.dat");

   MoveFile("telefon.tmp","telefon.dat");

 

 }

 

void TForm1::DellFileSMS(void)

{

    FILE *sms;

    FILE *sms_tmp;

    int Id_sms;

    char smsPWD[20];

    char smsAPNORNUM[20];

    char smsNETUSER[20];

    char smsNETPWD[20];

    char smsDNS[20];

    char smsJADURL[50];

    char smsAPPDIR[50];

 

   if ((sms = fopen("sms.dat", "rb"))!=NULL)

    {

        if ((sms_tmp = fopen("sms.tmp", "wb"))!=NULL)

          {

 

            while (fscanf(sms, "%d %s %s %s %s %s %s %s",&Id_sms, smsPWD,

            smsAPNORNUM, smsJADURL, smsAPPDIR, smsNETUSER, smsNETPWD, smsDNS)!=EOF)

             {

 

              if (Id_sms!=ListBox2->Items->Strings[ListBox2->ItemIndex].ToInt())

                fprintf(sms_tmp,"%d %s %s %s %s %s %s %s\r",Id_sms, smsPWD,

                 smsAPNORNUM, smsJADURL, smsAPPDIR, smsNETUSER, smsNETPWD, smsDNS);

               //ListBox1->Items->Add(telefon);

             }

            fclose(sms_tmp);

     }

    fclose(sms);

 

  }

 

     Edit4->Text="";

     Edit5->Text="";

     Edit2->Text="";

     Edit3->Text="";

     Edit6->Text="";

     Edit7->Text="";

     Edit8->Text="";

 

     Memo1->Lines->Clear();

     Memo2->Lines->Clear();

 //  ListBox1->DeleteSelected();

 //  ListBox2->DeleteSelected();

 

   DeleteFile("sms.dat");

   MoveFile("sms.tmp","sms.dat");

 

 

}

 

bool TForm1::FindIDSmsFile(void)

{

    FILE *sms;

    int Id_sms;

    char smsPWD[20];

    char smsAPNORNUM[20];

    char smsNETUSER[20];

    char smsNETPWD[20];

    char smsDNS[20];

    char smsJADURL[50];

    char smsAPPDIR[50];

 

    bool IdSMSFind=false;

 

   if ((sms = fopen("sms.dat", "rb"))!=NULL)

    {

 

       while (fscanf(sms, "%d %s %s %s %s %s %s %s",&Id_sms, smsPWD,

            smsAPNORNUM, smsJADURL, smsAPPDIR, smsNETUSER, smsNETPWD, smsDNS)!=EOF)

         {

 

               if (Id_sms==ListBox2->Items->Strings[ListBox2->ItemIndex].ToInt())

              {

               IdSMSFind=true;

               break;

               }

             }

 

    fclose(sms);

 

   }

 

  return  IdSMSFind;

}

 

 

 

//Чтобы создать СМС необходимо выбрать номер телефона, ввести данные в поля

void __fastcall TForm1::Button9Click(TObject *Sender)

{

   if(ListBox1->ItemIndex<0)

  {

   ShowMessage("Вы не выбрали номер телефона!");

   }

 else

 {

 

    FILE *sms;

    FILE *sms_tmp;

    int Id_sms;

 

    char smsJADURL[50];

    char smsAPPDIR[50];

    char smsPWD[20];

    char smsAPNORNUM[20];

    char smsNETUSER[20];

    char smsNETPWD[20];

    char smsDNS[20];

 

    if(Edit4->Text.IsEmpty()) sprintf(smsPWD,"%s","empty");

    else  sprintf(smsPWD,"%s",Edit4->Text.c_str());

 

    if(Edit5->Text.IsEmpty()) sprintf(smsAPNORNUM,"%s","empty");

    else sprintf(smsAPNORNUM,"%s",Edit5->Text.c_str());

 

    if (Edit2->Text.IsEmpty()) sprintf(smsJADURL,"%s","empty");

    else sprintf(smsJADURL,"%s",Edit2->Text.c_str());

 

    if (Edit3->Text.IsEmpty()) sprintf(smsAPPDIR,"%s","empty");

    else sprintf(smsAPPDIR,"%s",Edit3->Text.c_str());

 

    if (Edit6->Text.IsEmpty()) sprintf(smsNETUSER,"%s","empty");

    else sprintf(smsNETUSER,"%s",Edit6->Text.c_str());

 

    if (Edit7->Text.IsEmpty()) sprintf(smsNETPWD,"%s","empty");

    else sprintf(smsNETPWD,"%s",Edit7->Text.c_str());

 

   if (Edit8->Text.IsEmpty()) sprintf(smsDNS,"%s","empty");

    else sprintf(smsDNS,"%s",Edit8->Text.c_str());

 

    char smsJADURLfile[50];

    char smsAPPDIRfile[50];

    char smsPWDfile[20];

    char smsAPNORNUMfile[20];

    char smsNETUSERfile[20];

    char smsNETPWDfile[20];

    char smsDNSfile[20];

 

   // char* smsBEARER="BEARER:gprs";

   // char* smsSTART="START:install";

 

    if ((sms = fopen("sms.dat", "rb"))==NULL)

    {

 

            if(( sms_tmp = fopen("sms.dat", "wb"))!=NULL)

             {

             Id_sms=ListBox2->Items->Strings[ListBox2->ItemIndex].ToInt();

             fprintf(sms_tmp,"%d %s %s %s %s %s %s %s\r",Id_sms, smsPWD, smsAPNORNUM,

                  smsJADURL, smsAPPDIR, smsNETUSER, smsNETPWD, smsDNS);

              }

             fclose(sms_tmp);

     }

     else

     {

      //ShowMessage("Файл открыт!");

        bool flFindSms=false;

        sms_tmp = fopen("sms.tmp", "wb");

        while (fscanf(sms, "%d %s %s %s %s %s %s %s",&Id_sms, smsPWDfile, smsAPNORNUMfile,

         smsJADURLfile, smsAPPDIRfile, smsNETUSERfile, smsNETPWDfile, smsDNSfile)!=EOF)

             {

 

              if (Id_sms!=ListBox2->Items->Strings[ListBox2->ItemIndex].ToInt())

                fprintf(sms_tmp,"%d %s %s %s %s %s %s %s\r",Id_sms, smsPWDfile,

                smsAPNORNUMfile, smsJADURLfile, smsAPPDIRfile, smsNETUSERfile, smsNETPWDfile, smsDNSfile);

              else

                {

                fprintf(sms_tmp,"%d %s %s %s %s %s %s %s\r",ListBox2->Items->Strings[ListBox2->ItemIndex].ToInt(), smsPWD,

                smsAPNORNUM, smsJADURL, smsAPPDIR, smsNETUSER, smsNETPWD, smsDNS);

                flFindSms=true;

                }

 

              }

         if(flFindSms==false)

          {

          fprintf(sms_tmp,"%d %s %s %s %s %s %s %s\r",ListBox2->Items->Strings[ListBox2->ItemIndex].ToInt(), smsPWD,

                smsAPNORNUM, smsJADURL, smsAPPDIR, smsNETUSER, smsNETPWD, smsDNS);

                flFindSms=true;

 

          }

 

      fclose(sms_tmp);

      fclose(sms);

      DeleteFile("sms.dat");

      MoveFile("sms.tmp","sms.dat");

      }

      MakeSmsPDU();

  } //else

}

 

//---------------------------------------------------------------------------

 

void __fastcall TForm1::ListBox1Click(TObject *Sender)

{

 if(ListBox1->ItemIndex>=0)

  {

    ListBox2->ItemIndex=ListBox1->ItemIndex;

 

    ShowMessageText();

 

    MakeSmsPDU();

  

   }

}

//---------------------------------------------------------------------------

 

void __fastcall TForm1::ListBox2Click(TObject *Sender)

{

 if(ListBox2->ItemIndex>=0)

  {

    ListBox1->ItemIndex=ListBox2->ItemIndex;

 

     ShowMessageText();

 

      MakeSmsPDU();

 

   }

}

//---------------------------------------------------------------------------

 

 

Если внимательно посмотреть на текст передаваемой СМС, то увидим, что в поле JADURL указан путь к файлу *.jad. Но сама java программа это файл *.jar. Как же модем узнает откуда брать файл *.jar? Откроем файл *.jad в любом текстовом редакторе.

MIDlet-Jar-Size: 1058

MIDlet-Jar-URL: MyTC65.jar

MIDlet-Name: MyTC65 Midlet Suite

MIDlet-Vendor: Midlet Suite Vendor

MIDlet-Version: 1.0.0

MicroEdition-Configuration: CLDC-1.1

MicroEdition-Profile: IMP-2.0

 

Обратим внимание на строку MIDlet-Jar-URL: Именно здесь указывается полный путь к *.jar файлу. Если оба файла *.jad и *.jar будут лежать в корневом каталоге на сервере www.csu-tst.narod.ru, то эта строка должна выглядеть следующим образом:

MIDlet-Jar-URL: http://www.csu-tst.narod.ru/MyTC65.jar

Если требуется определить причину неудачи при использовании OTAP функции, то воспользуемся командой:  AT^SCFG=Trace/Syslog/OTAP,1  С помощью нее модем трассирует весь процесс с выводом информации в стандартный порт вывода, определяемый параметром "Userware/Stdout". Например команда AT^SCFG="Userware/Stdout","ASC0" назначает стандартным портом вывода модема нулевой COM порт, разъем его  находится на корпусе модема.

Команда AT^SJOTAP  позволяет установить пароль на использование OTAP. Очевидно, что при этом для успешного выполнения OTAP функции в СМС необходимо указать этот пароль. В программе это поле “Password”. Команда AT^SJOTAP дает возможность также установить ограничения и по другим признакам. 

  Архив рассмотренной программы с исходниками: Send_SMS_only.rar

Кому интересно: ссылка на сайт посвященный той же теме:

Введение

GSM модем Siemens TC65

GSM модем SL116 на базе модуля Enfora GSM0308

Пишите автору сайта ganatol2000@mail.ru

 

http://florent.clairambault.fr/smsotap-1-2  

Hosted by uCoz