我是土匪
发表于 2015-12-2 11:42
boolIRAConvertGsm7Bit(const u8 *iraData, u16 iraLen, u8 *gsmData, u16 *gsmLen, bool dropInconvertible)
{
bool result = TRUE;
u8 gsmValue = 0;
u16 i = 0;
*gsmLen = 0;
for (i = 0; i < iraLen; i++)
{
gsmValue = ira_to_gsm7[*iraData];
if (gsmValue != INVALID_CHAR)
{
*gsmData++ = gsmValue;
(*gsmLen)++;
}
else if ((gsmValue = ira_to_ext_gsm7[*iraData]) != INVALID_CHAR)
{
*gsmData++ = 0x1B;
*gsmData++ = gsmValue;
*gsmLen += 2;
}
else if (!dropInconvertible)
{
result = FALSE;
break;
}
else
{
/* Replace inconvertible char with a space */
*gsmData++ = REPLACEMENT_CHAR;
(*gsmLen)++;
}
iraData++;
}
return result;
}
s32 gsmInvertNumbers(const char* pSrc, char* pDst, s32 nSrcLength)
{
s32 nDstLength;
u8 ch;
s32 i;
nDstLength = nSrcLength;
for(i=0; i<nSrcLength;i+=2)
{
ch = *pSrc++;
*pDst++ = *pSrc++;
*pDst++ = ch;
}
if(nSrcLength & 1)
{
*(pDst-2) = 'F';
nDstLength++;
}
*pDst = '\0';
return nDstLength;
}
s32 gsmSerializeNumbers(const char* pSrc, char* pDst, s32 nSrcLength)
{
s32 nDstLength;
s32 i = 0;
u8 ch;
nDstLength = nSrcLength;
for(i=0; i<nSrcLength;i+=2)
{
ch = *pSrc++;
*pDst++ = *pSrc++;
*pDst++ = ch;
}
if(*(pDst-1) == 'F')
{
pDst--;
nDstLength--;
}
*pDst = '\0';
return nDstLength;
}
s32 gsmBytes2String(const u8 *pSrc, char*pDst, s32 nSrcLength)
{
const u8 tab[]="0123456789ABCDEF";
s32 i = 0;
for (i=0; i < nSrcLength; i++)
{
*pDst++ = tab[*pSrc >> 4];
*pDst++ = tab[*pSrc & 0x0f];
pSrc++;
}
*pDst = '\0';
return nSrcLength * 2;
}
s32 gsmString2Bytes(const char* pSrc, u8* pDst, s32 nSrcLength)
{
s32 i = 0;
for (i=0; i<nSrcLength; i+=2)
{
if(*pSrc>='0' && *pSrc<='9')
{
*pDst = (*pSrc - '0') << 4;
}
else
{
*pDst = (*pSrc - 'A' + 10) << 4;
}
pSrc++;
if(*pSrc>='0' && *pSrc<='9')
{
*pDst |= *pSrc - '0';
}
else
{
*pDst |= *pSrc - 'A' + 10;
}
pSrc++;
pDst++;
}
return nSrcLength / 2;
}
s32 gsmEncode8bit(const char* pSrc,u8 *pDst, s32 nSrcLength)
{
s32 i = 0;
for(i=0; i<nSrcLength; i++)
{
*pDst++ = *pSrc++;
}
return nSrcLength;
}
s32 gsmDecode7bit(const u8* pSrc, char *pDst, s32 nSrcLength)
{
s32 nSrc;
s32 nDst;
s32 nByte;
u8 nLeft;
nSrc = 0;
nDst = 0;
nByte = 0;
nLeft = 0;
while(nSrc<nSrcLength)
{
*pDst = ((*pSrc << nByte) | nLeft) & 0x7f;
nLeft = *pSrc >> (7-nByte);
pDst++;
nDst++;
nByte++;
if(nByte == 7)
{
*pDst = nLeft;
pDst++;
nDst++;
nByte = 0;
nLeft = 0;
}
pSrc++;
nSrc++;
}
*pDst = 0;
return nDst;
}
s32 gsmEncode7bit(const char* pSrc, u8* pDst, s32 nSrcLength)
{
s32 nSrc;
s32 nDst;
s32 nChar;
u8nLeft = 0;
u8cSrc;
nSrc = 0;
nDst = 0;
while(nSrc<nSrcLength)
{
nChar = nSrc & 7;
cSrc = *pSrc;
if(nChar == 0)
{
nLeft = cSrc;
}
else
{
*pDst++ = (cSrc << (8-nChar)) | nLeft;
nLeft = cSrc >> nChar;
nDst++;
}
pSrc++; nSrc++;
}
return nDst;
}
s32 gsmDecode8bit(const u8* pSrc, char * pDst, s32 nSrcLength)
{
s32 i = 0;
for(i=0; i<nSrcLength; i++)
{
*pDst++ = *pSrc++;
}
return nSrcLength;
}
u8 gsmDecodeSmsValidity(const u8 *data,SmsValidityFormatType validityFormat)
{
u8 pos = 0;
if (data == NULL )
{
return 0;
}
else
{
switch(validityFormat)
{
case SMS_VALIDITY_NONE:
break;
case SMS_VALIDITY_RELATIVE:
pos ++;
break;
case SMS_VALIDITY_ABSOLUTE:
pos += 7;
break;
case SMS_VALIDITY_ENHANCED:
break;
}
}
return pos*2;
}
u8 SmsDecodeDcs(const u8*data, SmsDcsType*dcs)
{
u8 pos = 0;
u8 i;
if (data == NULL || dcs == NULL)
{
return 0;
}
dcs->msgClass = SMS_MSG_CLASS_NONE;
dcs->msgWaiting = SMS_MSG_WAITING_NONE;
dcs->alphabet = SMS_ALPHABET_7_BIT_DEFAULT;
dcs->isCompressed= FALSE;
/* bits 7-6 */
i = ( data & 0xC0 ) >> 6;
switch( i )
{
case 0:
/* pattern 00xx xxxx */
dcs->isCompressed = data & 0x20;
if( data & 0x10 )
{
dcs->msgClass = (SmsMsgClassType) (data & 0x03);
}
else
{
/* no class information */
dcs->msgClass = SMS_MSG_CLASS_NONE;
}
dcs->alphabet = (SmsAlphabetType) (( data & 0x0C ) >> 2);
break;
case 3:
/* bits 5-4 */
if( (data & 0x30) == 0x30 )
{
/* pattern 1111 xxxx */
/* bit 3 is reserved */
/* bit 2 */
dcs->alphabet = (data & 0x04 ) ? SMS_ALPHABET_8_BIT:
SMS_ALPHABET_7_BIT_DEFAULT;
/* bits 1-0 */
dcs->msgClass = (SmsMsgClassType) (data & 0x03);
/* set remaining fields */
dcs->isCompressed= FALSE;
dcs->msgWaiting = SMS_MSG_WAITING_NONE_1111;
}
else
{
/* Message waiting groups
*/
dcs->isCompressed= FALSE;
dcs->msgClass = SMS_MSG_CLASS_NONE;
/* bits 5-4 */
if( (data & 0x30) == 0x00 )
{
dcs->msgWaiting= SMS_MSG_WAITING_DISCARD;
dcs->alphabet = SMS_ALPHABET_7_BIT_DEFAULT;
}
else if( (data & 0x30) == 0x10 )
{
dcs->msgWaiting= SMS_MSG_WAITING_STORE;
dcs->alphabet = SMS_ALPHABET_7_BIT_DEFAULT;
}
else
{
dcs->msgWaiting= SMS_MSG_WAITING_STORE;
dcs->alphabet = SMS_ALPHABET_UCS2;
}
/* bit 3 */
dcs->msgWaitingActive = ( data & 0x08 ) ? TRUE : FALSE;
/* bit 2 is reserved */
/* bits 1-0 */
dcs->msgWaitingKind = (SmsMsgWaitingKindType) (data & 0x03);
}
break;
default:
dcs->alphabet = SMS_ALPHABET_7_BIT_DEFAULT;
dcs->isCompressed= FALSE;
dcs->msgWaiting = SMS_MSG_WAITING_NONE;
dcs->msgClass = SMS_MSG_CLASS_NONE;
break;
}
if ( dcs->alphabet > SMS_ALPHABET_UCS2 )
{
dcs->alphabet = SMS_ALPHABET_7_BIT_DEFAULT;
}
dcs->rawDcsData = data;
pos ++;
return pos;
}
boolgsmEncodePdu( SM_PARAM* pSrc, char* pDst, u16 *dstLen)
{
#define MAX_GSM7BIT_SMS_LEN 160
s32nDstLength = 0;
u8buf = { 0 };
bool result = TRUE;
s32 nLength;
/* SMSC address field */
nLength = strlen(pSrc->SCA);
if( nLength )
{
buf = (s8)((nLength & 1) == 0 ? nLength : nLength + 1) / 2 + 1;
buf = 0x81;
nDstLength = gsmBytes2String(buf, pDst, 2);
nDstLength += gsmInvertNumbers(pSrc->SCA, &pDst, nLength);
}
else
{
pDst='0';
pDst='0';
}
nLength = strlen(pSrc->TPA);
buf = 0x11;
buf = 0;
if( '+' == pSrc->TPA )
{
memmove( pSrc->TPA, pSrc->TPA+1, nLength );
nLength -= 1;
buf = 0x91;
}
else
{
buf = 0x81;
}
buf = (s8)nLength;
nDstLength += gsmBytes2String(buf, &pDst, 4);
nDstLength += gsmInvertNumbers(pSrc->TPA, &pDst, nLength);
nLength = strlen(pSrc->TP_UD);
buf = pSrc->TP_PID;
buf = pSrc->TP_DCS;
/*
VP Value Validity period value
0-143 (VP + 1) x 5 minutes (i.e 5 minutes intervals up to 12 hours)
144-167 12 hours + ((VP-143) x 30 minutes)
168-196 (VP-166) x 1 day
197-255 (VP - 192) x 1 week
*/
buf = g_sms_vp; /* 4 days */
if(pSrc->TP_DCS == GSM_7BIT)
{
chartmpGsm;
s32 nSrcLength;
nSrcLength = strlen((char *)pSrc->TP_UD);
IRAConvertGsm7Bit((const u8 *)(pSrc->TP_UD), nSrcLength, (u8 *)tmpGsm, (u16 *)&nLength,TRUE);
buf = nLength;
nLength = gsmEncode7bit(tmpGsm, &buf, nLength+1) + 4;
}
else if (pSrc->TP_DCS == GSM_8BIT)
{
buf = gsmEncode8bit(pSrc->TP_UD, &buf, nLength);
nLength = buf + 4;
}
else if (pSrc->TP_DCS == GSM_UCS2)
{
*dstLen = 0;
return FALSE;
}
nDstLength += gsmBytes2String(buf, &pDst, nLength);
*dstLen = nDstLength;
return result;
}
bool gsmDecodePdu(const char* pSrc, SM_PARAM* pDst, u16 *dstLen)
{
SmsValidityFormatType validityFormat;
SmsDcsTypedcs;
bool result = TRUE;
u16 nDstLength;
u8tmp;
u8 buf;
u8 TP;
*dstLen = 0;
memset( pDst, 0, sizeof(SM_PARAM) );
gsmString2Bytes(pSrc, &tmp, 2);
if (tmp)
{
tmp = (tmp - 1) * 2;
pSrc += 4;
gsmSerializeNumbers(pSrc, pDst->SCA, tmp);
pSrc += tmp;
}
else
{
pSrc += 2;
}
gsmString2Bytes(pSrc, &TP, 2);
pSrc += 2;
validityFormat = (SmsValidityFormatType) (( TP & 0x18 ) >> 3); /* bits 3, 4 */
if( TP & 0x1 )
{
pSrc += 2;
}
/* the long sms.Discard it */
if (TP & 0x40)
{
return FALSE;
}
/* the status reprt.Discard it */
if (( TP & 0x3 ) == 0x2)
{
return FALSE;
}
gsmString2Bytes(pSrc, &tmp, 2);
if(tmp & 1)
{
tmp += 1;
}
pSrc += 2;
gsmString2Bytes(pSrc, &pDst->TPATP, 2);
pSrc += 2;
if( 0x91 == pDst->TPATP )
{
pDst->TPA = '+';
gsmSerializeNumbers(pSrc, pDst->TPA+1, tmp);
}
else if( 0xD0 == pDst->TPATP)
{
nDstLength = gsmString2Bytes(pSrc, buf, tmp & 7 ? (int)tmp * 7 / 4 + 2 : (int)tmp * 7 / 4);
nDstLength = tmp *4 /7;
gsmDecode7bit(buf, pDst->TPA, nDstLength);
}
else
{
gsmSerializeNumbers(pSrc, pDst->TPA, tmp);
}
pSrc += tmp;
gsmString2Bytes(pSrc, (unsigned char*)&pDst->TP_PID, 2);
pSrc += 2;
gsmString2Bytes(pSrc, (unsigned char*)&pDst->TP_DCS, 2);
SmsDecodeDcs( (unsigned char*)&pDst->TP_DCS, &dcs );
pSrc += 2;
if( TP & 0x1 )
{
pSrc += gsmDecodeSmsValidity( (u8 *)pSrc, validityFormat);
}
else
{
gsmSerializeNumbers(pSrc, pDst->TP_SCTS, 14);
pSrc += 14;
}
gsmString2Bytes(pSrc, &tmp, 2);
pSrc += 2;
if (dcs.alphabet == SMS_ALPHABET_7_BIT_DEFAULT)
{
char tmpGsm = { 0 };
u16 gsmLen = 0;
nDstLength = gsmString2Bytes(pSrc, buf, tmp & 7 ? (s32)tmp * 7 / 4 + 2 : (s32)tmp * 7 / 4);
gsmDecode7bit(buf, tmpGsm, nDstLength);
tmpGsm = '\0';
gsmLen = strlen(tmpGsm);
gsm7BitConvertIRA((const u8 *)tmpGsm, gsmLen, (u8 *)pDst->TP_UD, &nDstLength, TRUE);
pDst->TP_UD = '\0';
}
else if (dcs.alphabet == SMS_ALPHABET_8_BIT)
{
nDstLength = gsmString2Bytes(pSrc, buf, tmp * 2);
nDstLength = gsmDecode8bit(buf, pDst->TP_UD, nDstLength);
*dstLen = nDstLength;
}
else if(dcs.alphabet == SMS_ALPHABET_UCS2)
{
result = FALSE;
}
return result;
}
我是土匪
发表于 2015-12-10 17:13
本帖最后由 我是土匪 于 2015-12-10 17:14 编辑
TCPIP学习
TCPIP目前使用非常广泛,参照官方的《AN_SIM900_TCPIP_V1.01.pdf》实现。
本人在DTU项目中,采用TCPIP方式,可以稳定的实现数据的链接和传输。
下面介绍TCPIP流程。
我是土匪
发表于 2015-12-10 17:42
本帖最后由 我是土匪 于 2015-12-10 18:00 编辑
下面罗列出几种常用的URC的返回值(URC不局限于此)。代码上处理如下:void Deal_URCStrHandle(char*urcstr){ char *p = (char *) urcstr; s16urcType = -1; u8 i= 0;static char count_pdp = 0; char *UrcTable[ ] = { "CONNECT OK", "ALREADY CONNECT", "CONNECT FAIL", "CLOSED", "+PDP: DEACT", //PDP DEACT "+CIPRXGET:1", "OK", "+CPIN:NOT READY" };
while ('\r' == *p || '\n'== *p) { p++; }
for (i = 0; i < sizeof(UrcTable) /sizeof(UrcTable); i++) { if (strstr(p, UrcTable)) { urcType = i; break; } }
switch (urcType) { case 0:/* CONNECT OK */ { tcpConnConnect = TRUE; tcpRetryNum = 0; InitParams( );
//停止数据发送相关的动作 TimerStop(REMOTE_SEND_DATA_TIMER_ID); TimerStop(REMOTE_SEND_DATA_DELAY_TIMER_ID); TimerStop(RECV_REMOTE_DATA_TIMER_ID);
SendDataToSerial((char *)"CONNECT SERVER OK\r\n",strlen((constchar *)"CONNECT SERVER OK\r\n"));
} break; case 1:/* ALREADY CONNECT */ { ; } break; case 2: /* CONNECT FAIL */ { //关闭移动场景 } break; case 3: { SendDataToSerial((char*)"\r\nCONNECT SERVER FAIL\r\n",strlen((const char*)"\r\nCONNECT SERVER FAIL\r\n")); //modified by ds for connectstatus's URC
TimerStop(REMOTE_SEND_DATA_TIMER_ID); TimerStop(REMOTE_SEND_DATA_DELAY_TIMER_ID); TimerStop(RECV_REMOTE_DATA_TIMER_ID); //关闭移动场景
} break; case 4: /* +PDP: DEACT */ {
SendDataToSerial((char*)"\r\nCONNECT SERVER FAIL\r\n",strlen((const char*)"\r\nCONNECT SERVER FAIL\r\n")); //modified by ds for connectstatus's URC
tcpConnConnect= FALSE;
//重启模块 }
break; case 5: /* +CIPRXGET: 1 */ { char *pStr = NULL;
pStr = strstr(p, UrcTable);
TimerStart(RECV_REMOTE_DATA_TIMER_ID);//启动读数据
} break;
case7: //+CPIN: NOT READY { simCardStatusOk= FALSE;
//掉卡,重启模块
} break; default: break; }
}
我是土匪
发表于 2015-12-10 17:59
上电会检查是否注册商网络,成功后就会发起连接服务器操作,连接成功后靠心跳维持靠心跳维持长连接。
如果中途出现发送失败会重新发送,超过一定次数仍旧失败,需要断开连接,重连服务器,
通常网络变化,以及连接失败等会有URC上报。根据URC针对性的处理,重连即可。
windows100
发表于 2015-12-11 08:53
mark
cliffboy
发表于 2015-12-11 09:44
我是土匪 发表于 2015-8-24 18:00
6、如何主动控制重启?
复位引脚。听说SIM900该引脚不足够可靠。
AT命令:AT+CFUN=1,1 ...
串口倒灌引起的有电,弱弱问句软件方面是怎么处理的?
我是土匪
发表于 2015-12-11 10:55
cliffboy 发表于 2015-12-11 09:44
串口倒灌引起的有电,弱弱问句软件方面是怎么处理的?
这种情况指的是,单片机跑起来了,但是GPRS没有上电,但是电流通过MCU的串口串电给GPRS,导致一定概率的GPRS开机失败。
解决办法:
GPRS没上电的时候,单片机串口配置输出0电平,这样就不会串电。当GPRS供电后,再将串口引脚配置为串口模式。
cliffboy
发表于 2015-12-11 13:29
我是土匪 发表于 2015-12-11 10:55
这种情况指的是,单片机跑起来了,但是GPRS没有上电,但是电流通过MCU的串口串电给GPRS,导致一定概率的GPR ...
这个在单片机启动过程中无法保证,还是有一定风险,最好还是硬件上来处理
我是土匪
发表于 2015-12-11 13:48
本帖最后由 我是土匪 于 2015-12-11 14:13 编辑
cliffboy 发表于 2015-12-11 13:29
这个在单片机启动过程中无法保证,还是有一定风险,最好还是硬件上来处理 ...
逻辑上完全能处理,
保证模块上电前没有被串电即可。
当然硬件处理更好,否则软件代码可读性就会差一点。
sun1238898
发表于 2015-12-11 17:33
收藏一下,后续慢慢品味。。。
cliffboy
发表于 2015-12-11 17:34
我是土匪 发表于 2015-12-11 13:48
逻辑上完全能处理,
保证模块上电前没有被串电即可。
单板机启动过程中在逻辑上是无法来控制的,因为此过程串口是不受控的
我是土匪
发表于 2015-12-11 17:42
cliffboy 发表于 2015-12-11 17:34
单板机启动过程中在逻辑上是无法来控制的,因为此过程串口是不受控的
不是说设备上电的过程。
设备上电-》串口配置为GPIO输出0-》GPRS上电-》GPRS开机-》单片机串口引脚配置为串口模式
只要我开机之前模块是断电的就好。
这个教训血淋淋,十万RMB的代价。
cliffboy
发表于 2015-12-14 15:33
我是土匪 发表于 2015-12-11 17:42
不是说设备上电的过程。
设备上电-》串口配置为GPIO输出0-》GPRS上电-》GPRS开机-》单片机串口引脚配置为 ...
你这是设备起来稳定后正常的流程,当然没有问题,我是说设备在上电启动稳定前的这一个过程中,你这流程是根本无法实现的,只能通过硬件电路实现
我是土匪
发表于 2015-12-14 15:54
cliffboy 发表于 2015-12-14 15:33
你这是设备起来稳定后正常的流程,当然没有问题,我是说设备在上电启动稳定前的这一个过程中,你这流程是 ...
其实上电过程,不关心串电等状态的。
我这里描述的串电指的是,GPRS模块电源被MOS切断的状态下,测量GPRS的vbat,电压不是0而为1.8V左右(单片机串口初始化后引脚为高电平),基于这个状态,模块供电,再拉powerkey会出现千分之几概率的无法开机。
当然硬件解决是最理想的,软件只是后来弥补的办法。
zuoxuqi
发表于 2015-12-21 22:46
楼主能否分享一下第三章AT架构部分的完整工程代码,基础太差,有些地方实在搞不定
cliffboy
发表于 2015-12-25 17:29
我是土匪 发表于 2015-9-24 14:18
n 架构二:中断方式
个人喜欢用的方式。
这块能不详细讲一下架构,定时中断与接收中断时如何配合来工作的?
我是土匪
发表于 2015-12-30 14:43
zuoxuqi 发表于 2015-12-21 22:46
楼主能否分享一下第三章AT架构部分的完整工程代码,基础太差,有些地方实在搞不定 ...
思路交流可以,思想交流欢迎,整个完整代码,只能说抱歉了,望理解。
我是土匪
发表于 2015-12-30 14:44
cliffboy 发表于 2015-12-25 17:29
这块能不详细讲一下架构,定时中断与接收中断时如何配合来工作的?
接收中断,实际就是字符串中断,设置成超时中断是很不错的办法。
定时中断和超时中断是没有冲突的。
我是土匪
发表于 2016-1-7 14:48
因为项目需求,要画个最小系统板。
最近SIM900A停产了,所以计划做一块兼容的板子,SIM900A&SIM800A&SIM2000C.
今天评估了资料,马上动手,及时分享。
wrr360661326
发表于 2016-1-11 11:20
刚开始接触GPRS,买了模块使用串口测试了一下,TCPIP短信功能都用到了,后面用单片机去做。感觉好大的工作量。解析、发送好复杂的赶脚