суббота, 31 июля 2010 г.

Отправлять длинные SMS из своей программы

Чудо, чудо! Если использовать конкатенацию SMS, то можно обойти жуткое ограничение в 70 символов на сообщение!

Но, конечно, пришлось разбивать сообщение на кусочки, к каждому из которых в начало прописывать по шесть байтов:

text =
"06" + // Length of User Data Header
"08" + // Concatenated short messages, 16-bit reference number
"04" + // Length of the header, excluding the first two fields
CSMS_reference_number + // уникальный номер длинного сообщения
chunks.Count.ToString("X2") + // число кусков сообщения
(i+1).ToString("X2") + // номер куска
text;

и в SMS-SUBMIT PDU устанавливать 6-й бит, так что он теперь стал не "11", а "51".

воскресенье, 25 июля 2010 г.

Отправлять SMS из своей программы

В общем-то, C# рулит...

1. Самой большой проблемой было добиться от сотового телефона на команду "AT" внятный ответ "OK".
Использовал System.IO.Ports.SerialPort:

System.IO.Ports.SerialPort serialPort = new SerialPort("COM5");
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
serialPort.BaudRate = 115200;
serialPort.Open();
serialPort.WriteLine("AT\r");

В обработчике serialPort_DataReceived получилось примерно следующее:

void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
this.SetText(serialPort.ReadExisting());
}

Соответственно, основные пляски с бубном - это позволить написать что-то в textBox1 из другой нитки:

delegate void SetTextCallback(string text);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text += "\r\nrcv: " + text;
}
}

2. Теперь о собственно передаче сообщений. Очень заманчиво было бы воспользоваться советами, приведенными тут. В самом деле,

AT+CSCS="UCS2"\r
AT+CSMP=1,167,0,8\r
AT+CMGS="+31638740161"\r
06450631062D06280627 + Convert.ToChar(26)

и всё, sms-ка ушла, что может быть проще? Но почему-то оказалось не судьба. На второй команде Siemens CX75 взбрыкнул, и пришлось пойти длинным путем.

Вот тут и тут написана куча полезного. Получилось такое:

AT+CMGF=0\r
AT+CMGS= + (sms.Length/2-1).ToString() + \r
sms + Convert.ToChar(26)

Здесь строка sms конструируется так:

string text = TextToSMS("АБРАКАДАБРА");
string sms =
"00" + // длина SMSC информации (пусть телефон ее додумает сам)
"11" + // first octet of the SMS-SUBMIT PDU
// (установлен бит 0 -> вид сообщения=SMS-SUBMIT)
// (установлен бит 3 -> есть поле TP-VP )
"00" + // TP-Message-Reference. "00" lets the phone set the message reference number itself.
PhoneNumberToSMS("79030123456") + // номер получателя
"00" + // PID - идентификатор номера протокола
"08" + // DCS схема кодирования данных (08 - UCS2=кириллица)
"AA" + // TP-VP - Validity Period, время жизни сообщения на сервере (AA - установлен в 4 дня)
(text.Length/2).ToString("X2") + // длина сообшения
text;


Две функции, PhoneNumberToSMS и TextToSMS, служат для кодирования номера телефона и текста сообщения соответственно:

private string PhoneNumberToSMS(string number)
{
number += "F";
string result =
"0B" + // длина номера (12 цифр, включая F)
"91"; // международный формат номера
int i = 0;
while (i < number.Length)
{
result += number[i + 1].ToString() + number[i].ToString();
i += 2;
}
return result;
}

private string TextToSMS(string text)
{
byte[] b = (new System.Text.UnicodeEncoding()).GetBytes(text);
string result = "";
int i = 0;
while (i < b.Length)
{
result += b[i + 1].ToString("X2") + b[i].ToString("X2");
i += 2;
}
return result;
}

четверг, 1 июля 2010 г.

Хозяйке на заметку...

KEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Winlogon
значение UserEnvDebugLevel типа REG_DWORD ставим 0x10002
Перезагружаем... и в журнале %systemroot%\debug\userenv.log имеем задокументированные последовательности применения политики и профилей...