⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pdu.cpp~

📁 您在开发gsm模块短信功能的时候是否遇到过这样的问题:智能发英文不能发中文?其实是英文默认的模式是ascii编码
💻 CPP~
字号:
/********************************************************************
	created:	2006/11/22
	created:	22:11:2006   10:04
	author:		Louis huang<hlouis@gmail.com>
	purpose:	GSM SMS PDU format manipulate class
	Copyright (C) 2006-2008 Louis hunag

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.
*********************************************************************/
#define STRICT
#include <crtdbg.h>
#include <tchar.h>
#include <windows.h>

#include <sstream>
#include <iomanip>
#include <bitset>
#include <vector>
#include <algorithm>
#include "PDU.h"

CPDU::CPDU(void)
{
	m_pduTpvp	= 0;	//default is 5 min.
	m_bTP_RP	= false;
	m_bTP_UDHI	= false;
	m_bTP_SRI	= false;
	m_bTP_MMS	= false;
	m_wayTP_MMI = ESMSWay_UNKNOW;
	m_eMethod	= EEncode_UNKNOW;
}

CPDU::~CPDU(void)
{
}


//////////////////////////////////////////////////////////////////////////
// Methods
int CPDU::Compose(CPDU::pdudata& pdu,
				  std::tstring msg, std::tstring phone,
				  std::tstring msc /* = _T("") */, EEncodeMethod eMethod /* = EEncodeUCS2 */) throw(...)
{
	std::tcout.imbue(std::locale("chs"));
	std::tcout << _T("Compose a message:\n");

	if (!msc.empty())
		SetMSCNumber(msc);
	else if (m_szMSC.empty())
		throw CPDUException (_T("No Message center number"), 1);

	if (phone.empty())
		throw CPDUException (_T("No target user number"), 1);

	std::stringstream ssPdu;
	// First the MSC part
	ssPdu << std::hex << std::setw(2) << std::setfill('0') << (int)(m_pduMSC.length() / 2);
	ssPdu << m_pduMSC;

	// Start build the phone part
	std::stringstream ssPhone;
	ssPhone << "1100";			// The static phone part header, see document for detail
	pdudata pduPhone;
	ssPhone << std::hex << std::setw(2) << std::setfill('0') << EncodePDUNumber(phone, pduPhone);	// Number length
	ssPhone << "91" << pduPhone;	// phone and 91 prefix

	ssPhone << "00";				// The Protocol identifier 00 for SMS.
	ssPhone << std::hex << std::setw(2) << std::setfill('0') << eMethod;
	ssPhone  << std::hex << std::setw(2) << std::setfill('0') << m_pduTpvp;				// The validity period


	// Start build the USERDATA part
	pdudata pduData;
	if (eMethod == EEncodeUCS2)
	{
		if (msg.length() > 70)
			throw CPDUException (_T("Message text number too large!"), 2);
		EncodeUCS2(pduData, msg);
	}

	ssPhone << pduData;
	pduData = ssPhone.str();
	int iLen = (int)pduData.length() / 2;

	std::cout << "The data len is:\t" << iLen << '\n';

	ssPdu << pduData;
	pdu = ssPdu.str();

	std::cout << "The final pdu is:\n" << pdu
			  << "\n------------------------------------------------\n"
			  << std::endl;
	
	return iLen;
}

int CPDU::EncodeUCS2(pdudata& pdu, std::tstring message)
{
	size_t iLen = message.length();
	std::stringstream ss;
	ss << std::hex << std::setw(2) << std::setfill('0') << iLen * 2;
	for (size_t i = 0; i < iLen; ++i)
		ss << std::hex << std::setw(4) << std::setfill('0') << message[i];

	pdu = ss.str();
	std::cout << "User data is:\t\t" << pdu << std::endl;
	return (int)iLen * 2;
}

std::tstring CPDU::Fetch(pdudata pdu) throw (...)
{
	std::tcout.imbue(std::locale("chs"));
	std::tcout << _T("Fetch data:\n");
//	std::cout << "Begin to fetch message from:\n" << pdu << '\n';
	int iPduLen = (int)pdu.length();
	int iOffset = 0;

	// First get the msc part
	int iLenSmsc = 0;
	std::stringstream ss(pdu.substr(iOffset, 2));
	ss >> std::hex >> iLenSmsc;
	iLenSmsc = iLenSmsc * 2;
	iOffset += 2;

	SetMSCNumber(DecodePDUNumber(pdu.substr(2, iLenSmsc)));
	std::tcout << _T("MSCS number is:\t\t") << m_szMSC << '\n';
	iOffset += iLenSmsc;

	// Parse the parameters
	ss.clear();
	ss.str(pdu.substr(iOffset, 2));
	long iPara = 0;
	ss >> std::hex >> iPara;
	ParseSMSPara(iPara);
	iOffset += 2;

	if (m_wayTP_MMI == ESMSWay_SUBMIT)
		iOffset += 2;		// jump over the message reference part if the type is submit message

	if (m_bTP_RP)		// There is replay number so parse it
	{
		ss.clear();
		ss.str(pdu.substr(iOffset, 2));
		int iLen = 0;
		ss >> std::hex >> iLen;
		iOffset += 2;

		iOffset += 2;		//Jump over the number format part (91)
		m_szCaller = DecodePDUNumber(pdu.substr(iOffset, iLen + 1));
		std::tcout << _T("The caller/Sender is:\t") << m_szCaller << '\n';
		iOffset += iLen + 1;
	}

	iOffset += 2;		// Jump over the Protocol identifier part.

	// Get the data encoding method
	int iMethod = 0;
	ss.clear();
	ss.str(pdu.substr(iOffset, 2));
	ss >> std::hex >> iMethod;
	m_eMethod = (EEncodeMethod)iMethod;
	iOffset += 2;

	if (m_wayTP_MMI == ESMSWay_DELIVER)
	{
		m_szTimeStamp = ParseTimeStamp(pdu.substr(iOffset, 14));
		iOffset += 14;
		std::tcout << _T("The time stamp is:\t") << m_szTimeStamp << '\n';
	}
	else if (m_wayTP_MMI == ESMSWay_SUBMIT)
		iOffset += 2;	// Jump over the TP-Validity-Period part

	// Decode the user data
	std::tstring szUserData;
	if (m_eMethod == EEncodeUCS2)
		DecodeUCS2(pdu.substr(iOffset), szUserData);
	else if (m_eMethod == EEncode_7bit)
		Decode7bit(pdu.substr(iOffset), szUserData);

	std::tcout << _T("The user data is:\n") << szUserData
			   << _T("\n------------------------------------------------\n")
			   << std::endl;
	return szUserData;
}

std::tstring CPDU::ParseTimeStamp(pdudata pdu)
{
	std::tstringstream ss;
	ss << _T("20");
	ss << pdu[1] << pdu[0];	//year
	ss << ' ' << pdu[3] << pdu[2]; //month
	ss << '/' << pdu[5] << pdu[4]; //day
	ss << ' ' << pdu[7] << pdu[6]; //Hour
	ss << ':' << pdu[9] << pdu[8]; //min
	ss << ':' << pdu[11] << pdu[10]; //sec

	int iGMT = 0;
	std::stringstream ss2(pdu.substr(12, 2));
	ss2 >> std::hex >> iGMT;
	ss << _T(" GMT+") << iGMT / 4;

	return ss.str();
}

void CPDU::ParseSMSPara(long iPara)
{
	std::bitset<8> bit (iPara);
	m_bTP_RP	= !bit[7];			// TODO: make sure this message meaning
	m_bTP_UDHI	= bit[6];
	m_bTP_SRI	= bit[5];
	m_bTP_MMS	= bit[2];

	if (!bit[1] && bit[0])
		m_wayTP_MMI = ESMSWay_SUBMIT;
	else if (!bit[1] && !bit[0])
		m_wayTP_MMI = ESMSWay_DELIVER;
	else
		m_wayTP_MMI = ESMSWay_UNKNOW;
}

int CPDU::DecodeUCS2(const pdudata pdu, std::tstring& message)
{
	int iLen = 0;
	std::stringstream ss(pdu.substr(0, 2));
	ss >> std::hex >> iLen;

	int iChar = 0;
	std::tstringstream tss;
	for (int i = 0; i < iLen / 2; ++i)
	{
		ss.clear();
		ss.str(pdu.substr(2 + i * 4, 4));
		ss >> std::hex >> iChar;
		tss << (TCHAR)iChar;
	}
	message = tss.str();

// 	std::cout << "The pdu length is: " << iLen << '\n';
// 
// 	std::tcout.imbue(std::locale("chs"));
// 	std::tcout << _T("The message is:") << message << std::endl;

	return iLen;
}

void CPDU::SetMSCNumber(std::tstring szNum)
{
	m_szMSC = szNum;
	EncodePDUNumber(szNum, m_pduMSC);
	m_pduMSC = "91" + m_pduMSC;
//	std::cout << "PDU MSC number is:\t" << m_pduMSC << std::endl;
}


std::tstring CPDU::DecodePDUNumber(pdudata pNumber)
{
	pdudata pduTemp = pNumber.substr(0, 2);
	int iStart = 0;
	if (pduTemp == "91")
		iStart = 2;

	std::tstringstream tss;
	for (int i = iStart; i < (int)pNumber.length(); i+=2)
	{
		tss << pNumber[i + 1];
		tss << pNumber[i];
	}

	std::tstring szNumber = tss.str();
	
	if (szNumber[szNumber.length() - 1] == 'f' || szNumber[szNumber.length() - 1] == 'F')
		szNumber.erase(szNumber.length() - 1);
	return szNumber;
}

int CPDU::EncodePDUNumber(std::tstring number, pdudata& pduNum)
{
	if (number[0] == '+')
		number = number.substr(1);

	if (number.substr(0, 2) != _T(COUNTRY_NUMBER))
		number = _T(COUNTRY_NUMBER) + number;

	int iLen = (int)number.length();

	if ( (iLen % 2) != 0)
		number += 'F';

	std::stringstream ss;
	int iGap = 1;
	for (size_t i = 0; i < number.length(); ++i)
	{
		int test = number[i + iGap];
		ss << ss.narrow(number[i + iGap]);		// Only convert number here, so no data lose possible
		iGap = (i % 2 == 0) ? -1 : 1;
	}

	pduNum = ss.str();
	return iLen;
}

void CPDU::SetValidityPeriod(long days, int hours, int mins)
{
	if (days > 30)
	{
		if (days > 441)
			days = 441;
		m_pduTpvp = (days / 7) + 192;
	}
	else if (days >= 1)
		m_pduTpvp = days + 166;
	else if (hours >= 12)
	{
		if (hours >= 24)
			hours = 23;
		m_pduTpvp = (hours - 12) * 2 + 143;
	}
	else
	{
		if (mins >= 60)
			mins = 59;

		m_pduTpvp = hours * 12 + mins / 5 - 1;
		if (m_pduTpvp < 0) m_pduTpvp = 0;
	}

	m_tpvp = CTimeSpan(days, hours, mins, 0);
}

int CPDU::Decode7bit(const pdudata pdu, std::tstring& message)
{
	long iLeft = 0;
	std::stringstream ss;
	std::tstringstream tss;
	int iCount = 0, iChar = 0;
	int i = 0;
	int iLen = (int)pdu.length() / 2 - 1;	// minus 1 for the data length part
	for (; i < iLen; ++i)
	{
		ss.str(pdu.substr(2 + i * 2, 2));	// plus 2 to jump over the data length part
		ss >> std::hex >> iChar;
		ss.clear();

		iCount++;
		if (iCount > 7) iCount = 1;

		std::bitset<8> bit(iChar);
		std::bitset<8> bitTemp = bit >> (8 - iCount);
		std::bitset<8> bitLeft(iLeft);
		bit <<= iCount;
		bit >>= 1;
		bit |= bitLeft;
		iLeft = bitTemp.to_ulong();

		char charTemp = (char)bit.to_ulong();
		tss << charTemp;

		if (iCount == 7)	// output the extra byte
			tss << (char)bitTemp.to_ulong();
	}

	message = tss.str();
//	std::tcout << message << std::endl;

	return i;
}

int CPDU::Encode7bit(pdudata& pdu, const std::tstring msg)
{
	int iLeft = 0;
	std::vector<long> vect;
	int iLen = (int)msg.length();
	int iCount = iLen % 8;

	for (int i = iLen - 1; i >= 0; --i)
	{
		std::bitset<8> bit(msg[i]);

		std::bitset<8> bitTemp = bit << (8 - iCount + 1);

		bit >>= (iCount - 1);
		std::bitset<8> bitLeft(iLeft);
		bit |= bitLeft;

		iLeft = bitTemp.to_ulong();
		if (iCount != 8)
			vect.push_back(bit.to_ulong());

		iCount--;
		if (iCount < 1) iCount = 8;
	}

	std::reverse(vect.begin(), vect.end());
	std::stringstream ss;
	ss << std::hex << std::setw(2) << std::setfill('0') << iLen;
	for (int i = 0; i < (int)vect.size(); ++i)
		ss << std::hex << vect[i];
	pdudata pdu = ss.str();
	std::cout << pdu << std::endl;

	return iLen;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -