At 指令文档
SMS_PDU-mode文档
短消息Text编码原码(下载至PJ Naughter的主页)
pdu编码示例:
//message中的位的设置可以参考文档中的说明
//红色的字表示可能与mfcsms中不同的地方
CString CSMSMessage::CreatePDUMessage() const{CByteArray message;//message.SetSize(0, 280);
//First thing to do is work on the Service Center Numberif (!AddEncodedSMSCNumber(message, m_sServiceCenterNumber, m_ServiceCenterNumberAddressType))return _T("");
//Form the SMS-SUBMIT octetBYTE bySMSSubmit = 0x1; //By default set this PDU to an SMS-SUBMITif (m_bUseValidityPeriod){if (m_bUseRelativeValidityPeriod)bySMSSubmit |= 0x10;elsebySMSSubmit |= 0x18;}if (m_bRequireStatusReport)bySMSSubmit |= 0x20;message.Add(bySMSSubmit);
//Next is the TP-Message-Reference. We let the phone set the message reference itselfmessage.Add(0x0);
//Next is the Phone numberASSERT(m_sPhoneNumber.GetLength()); //Must specify a number to deliver the message toif (!AddEncodedPhoneNumber(message, m_sPhoneNumber, m_PhoneNumberAddressType))return _T("");
//Next is the Protocol Identifiermessage.Add(0x0);
//Next is the Data encoding scheme (this code always use PDU encoding)message.Add(0x8);
//Next is the validity periodif (m_bUseValidityPeriod){if (m_bUseRelativeValidityPeriod){//Relative Validity period is pseudo logarithmitly encoded into 1 octetBYTE byValidityPeriod = 0;if (m_RelativeValidityPeriod <= CTimeSpan(0, 12, 0, 0))byValidityPeriod = (BYTE) ((m_RelativeValidityPeriod.GetTotalSeconds() / 300) - 1);else if (m_RelativeValidityPeriod <= CTimeSpan(1, 0, 0, 0))byValidityPeriod = (BYTE) (((m_RelativeValidityPeriod.GetTotalSeconds() - 43200) / 1800) + 143);else if (m_RelativeValidityPeriod <= CTimeSpan(30, 0, 0, 0))byValidityPeriod = (BYTE) ((m_RelativeValidityPeriod.GetTotalSeconds() / 86400) + 166);else byValidityPeriod = (BYTE) ((m_RelativeValidityPeriod.GetTotalSeconds() / 604800) + 192);
message.Add(byValidityPeriod);}else{//Absolute Validity period is encoded into 7 octetsmessage.Add(SwappedNibble(m_AbsoluteValidityPeriod.wYear % 100));message.Add(SwappedNibble(m_AbsoluteValidityPeriod.wMonth));message.Add(SwappedNibble(m_AbsoluteValidityPeriod.wDay));message.Add(SwappedNibble(m_AbsoluteValidityPeriod.wHour));message.Add(SwappedNibble(m_AbsoluteValidityPeriod.wMinute));message.Add(SwappedNibble(m_AbsoluteValidityPeriod.wSecond));
long nLocalTimeZone = labs(m_TimeZone);BYTE byTimeZone = SwappedNibble(nLocalTimeZone / 15);if (m_TimeZone < 0)byTimeZone |= 0x80;message.Add(byTimeZone);}}
//Next is the length of the user dataint nMessageLength = m_sMessage.GetLength();int nActualLen=0;for(int j=0;j<nMessageLength;j++){BYTE data=(BYTE)m_sMessage.GetAt(j);int nNibble = (int)data;if(nNibble>=0&&nNibble<=127)nActualLen=nActualLen+2;elsenActualLen=nActualLen+1;
} if (nMessageLength > 255){TRACE(_T("CSMSMessage::CreatePDUMessage, Cannot encode %s as it is longer than the maximum size of 255/n"), m_sMessage);return _T("");}if (nMessageLength == 0){TRACE(_T("CSMSMessage::CreatePDUMessage, Failing as no message has been specified to be sent/n"));return _T("");}//Initially we just add a place holder as it will be updated later on once we have added the actual dataint nDataLengthIndex = message.GetSize();message.Add((BYTE) nActualLen);
//Finally before we return from the function, convert from the BYTE array representation to the string versionWCHAR wcBuffer[256];char cBuffer[256];memset(cBuffer,0,256);memset(wcBuffer,0,256*2);MultiByteToWideChar(CP_ACP, 0, m_sMessage, nMessageLength, wcBuffer, 256);memcpy((void*)cBuffer,(void*)wcBuffer,256);char tmp;for(int k =0; k<nMessageLength; k++){tmp = cBuffer[2*k];cBuffer[2*k] = cBuffer[2*k+1];cBuffer[2*k+1]=tmp;}
for(k=0;k<nActualLen;k++)message.Add(cBuffer[k]);int nArraySize = message.GetSize();CString sMsg;int nBufferSize = (nArraySize*2) + 1;TCHAR* pszData = sMsg.GetBuffer(nBufferSize);int nPDUOutputIndex = 0;for (int i=0; i<nArraySize; i++){BYTE byData = message.GetAt(i);int nNibble1 = (byData & 0xF0) >> 4;if (nNibble1 > 9)pszData[nPDUOutputIndex] = (TCHAR) (nNibble1 - 10 + _T('A'));elsepszData[nPDUOutputIndex] = (TCHAR) (nNibble1 + _T('0'));++nPDUOutputIndex;int nNibble2 = byData & 0xF;if (nNibble2 > 9)pszData[nPDUOutputIndex] = (TCHAR) (nNibble2 - 10 + _T('A'));elsepszData[nPDUOutputIndex] = (TCHAR) (nNibble2 + _T('0'));++nPDUOutputIndex;}sMsg.ReleaseBuffer(nPDUOutputIndex);
return sMsg;}
使用at指令发送端消息示例:
//Check to see if there is a modem on the specified serial portchar* pszATMsg = "AT/r";//测试连接是否成功Write(pszATMsg, strlen(pszATMsg));if (!WaitForSerialResponse("OK", dwTimeout, 32)){CString sError;sError.LoadString(IDS_SMSSERIALPORT_FAIL_RECEIVE_RESPONSE_FROM_MODEM);AfxThrowSMSException(sError, E_SMS_NO_MODEM_RESPONSE);}
char* pszSelectMessageMsg = "AT+CSMS=0/r"; //Select Message serviceWrite(pszSelectMessageMsg, strlen(pszSelectMessageMsg));if (!WaitForSerialResponse("OK", dwTimeout, 32)){CString sError;sError.LoadString(IDS_SMSSERIALPORT_MODEM_DOES_NOT_SUPPORT_SMS);AfxThrowSMSException(sError, E_SMS_NO_SMS_SUPPORT);}
char* pszMessageFormat = "AT+CMGF=0/r"; //Set the transfer mode to PDUWrite(pszMessageFormat, strlen(pszMessageFormat));if (!WaitForSerialResponse("OK", dwTimeout, 32)){CString sError;sError.LoadString(IDS_SMSSERIALPORT_FAIL_SET_PDU_MODE);AfxThrowSMSException(sError, E_SMS_SET_PDU_MODE);}
CString sSendCommand;sSendCommand.Format(_T("AT+CMGS=%d/r"), nMsgSize); //Prepare to send the PDULPSTR pszAsciiSendCommand = T2A((LPTSTR) (LPCTSTR) sSendCommand);Write(pszAsciiSendCommand, strlen(pszAsciiSendCommand));if (!WaitForSerialResponse(">", dwTimeout, 32)){CString sError;sError.LoadString(IDS_SMSSERIALPORT_FAIL_SEND_SMS_MESSAGE_TO_MODEM);AfxThrowSMSException(sError, E_SMS_SEND_MESSAGE_TO_MODEM);}
//And finally write out the PDU as a stringLPSTR pszAsciiPDU = T2A((LPTSTR) (LPCTSTR) sData);int nAsciiPDULength = strlen(pszAsciiPDU);Write(pszAsciiPDU, nAsciiPDULength);//pszAsciiPDU是短消息的PDU编码Write("/x1A", 1);if (!WaitForSerialResponse("OK", dwTimeout, 32 + nAsciiPDULength)){CString sError;sError.LoadString(IDS_SMSSERIALPORT_FAIL_SEND_SMS_MESSAGE);AfxThrowSMSException(sError, E_SMS_SEND_MESSAGE);}
我的主页
