📄 gr47.c
字号:
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
// 用户信息编码方式
#define GSM_7BIT 0
#define GSM_8BIT 4
#define GSM_UCS2 8
// 短消息参数结构,编码 / 解码共用
UCHAR xdata PhoneNum[32]; // 目标号码或回复号码 (TP-DA 或 TP-RA)
UCHAR xdata TP_DCS; // 用户信息编码方式 (TP-DCS)
bit message_ture = 0; //回执确认
/******************************************************************************/
/******************************************************************************/
// Bit7 编码
// pSrc: 源字符串指针
// pDst: 目标编码串指针
// nSrcLength: 源字符串长度
// 返回 : 目标编码串长度
UCHAR EncodeBit7(UCHAR xdata *pSrc,UCHAR xdata *pDst, UCHAR nSrcLength)
{
UCHAR nSrc; // 源字符串的计数值
UCHAR nDst; // 目标编码串的计数值
UCHAR nChar; // 当前正在处理的组内字符字节的序号,范围是 0-7
UCHAR nLeft; // 上一字节残余的数据
// 计数值初始化
nSrc = 0;
nDst = 0;
// 将源串每 8 个字节分为一组,压缩成 7 个字节
// 循环该处理过程,直至源串被处理完
// 如果分组不到 8 字节,也能正确处理
while(nSrc<nSrcLength)
{
nChar = nSrc & 7; // 取源字符串的计数值的最低 3 位
if(nChar == 0) // 处理源串的每个字节
{
nLeft = *pSrc; // 组内第一个字节,只是保存起来,待处理下一个字节时使用
}
else
{
*pDst = (*pSrc << (8-nChar)) | nLeft; // 组内其它字节,将其右边部分与残余数据相加,得到一个目标编码字节
nLeft = *pSrc >> nChar; // 将该字节剩下的左边部分,作为残余数据保存起来
pDst++; // 修改目标串的指针和计数值
nDst++;
}
pSrc++; // 修改源串的指针和计数值
nSrc++;
}
*pDst = nLeft;
return (nSrcLength - nSrcLength/8); // 返回目标编码串长度
}
/******************************************************************************/
// 7-bit 解码
// pSrc: 源编码串指针
// pDst: 目标字符串指针
// nSrcLength: 源编码串长度
// 返回 : 目标字符串长度
UCHAR DecodeBit7(UCHAR xdata *pSrc,UCHAR xdata *pDst, UCHAR nSrcLength)
{
UCHAR nDst; // 目标编码串的计数值
UCHAR nByte; // 当前正在处理的组内字符字节的序号,范围是 0-7
UCHAR nLeft; // 上一字节残余的数据
// 计数值初始化
nDst = 0; // 组内字节序号和残余数据初始化
nByte = 0;
nLeft = 0;
// 将源数据每 7 个字节分为一组,解压缩成 8 个字节
// 循环该处理过程,直至源数据被处理完
// 如果分组不到 7 字节,也能正确处理
while(nDst<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++; // 修改源串的指针和计数值
}
*pDst = 0;
return (nSrcLength); // 返回目标串长度
}
/******************************************************************************/
// BetyChange 编码
// pSrc: 源字符串指针
// pDst: 目标编码串指针
// nSrcLength: 源字符串长度
// 返回 : 目标编码串长度
UINT EncodeBetyChange(UCHAR xdata *pSrc,UCHAR xdata *pDst, UCHAR nSrcLength)
{
UCHAR i;
UINT xdata len;
UCHAR code tab[]={"0123456789ABCDEF"}; // 0x0-0xf 的字符查找表
for(i=0; i<nSrcLength; i++)
{
*pDst++ = tab[*pSrc >> 4]; // 输出高 4 位
*pDst++ = tab[*pSrc & 0x0f];// 输出低 4 位
pSrc++;
}
len = ((UINT)nSrcLength) * 2;
return (len); // 返回目标编码串长度
}
/******************************************************************************/
// BetyChange 解码
// pSrc: 源编码串指针
// pDst: 目标字符串指针
// nSrcLength: 源编码串长度
// 返回 : 目标字符串长度
UCHAR DecodeBetyChange(UCHAR xdata *pSrc,UCHAR xdata *pDst, UCHAR nSrcLength)
{
UCHAR i;
for(i=0; i<nSrcLength; i++)
{
if(*pSrc>='0' && *pSrc<='9') // 输出高 4 位
{
*pDst = (*pSrc - '0') << 4;
}
else
{
*pDst = (*pSrc - 'A' + 10) << 4;
}
pSrc++;
if(*pSrc>='0' && *pSrc<='9') // 输出低 4 位
{
*pDst |= *pSrc - '0';
}
else
{
*pDst |= *pSrc - 'A' + 10;
}
pSrc++;
pDst++;
}
return (nSrcLength); // 返回目标字符串长度
}
/******************************************************************************/
// 正常顺序的字符串转换为两两颠倒的字符串,若长度为奇数,补 'F' 凑成偶数
// 如: "8613851872468" --> "683158812764F8"
// pSrc: 源字符串指针
// pDst: 目标字符串指针
// nSrcLength: 源字符串长度
// 返回 : 目标字符串长度
UCHAR InvertNumbers(UCHAR xdata *pSrc,UCHAR xdata *pDst,UCHAR nSrcLength)
{
UCHAR nDstLength; // 目标字符串长度
UCHAR ch,i;
nDstLength = nSrcLength;
for(i=0; i<nSrcLength;i+=2) // 两两颠倒
{
ch = *pSrc++; // 保存先出现的字符
*pDst++ = *pSrc++; // 复制后出现的字符
*pDst++ = ch; // 复制先出现的字符
}
if(nSrcLength & 1) // 源串长度是奇数吗?
{
*(pDst-2) = 'F'; // 补 'F'
nDstLength++; // 目标串长度加 1
}
return(nDstLength); // 返回目标字符串长度
}
/******************************************************************************/
// 两两颠倒的字符串转换为正常顺序的字符串
// 如: "683158812764F8" --> "8613851872468"
// pSrc: 源字符串指针
// pDst: 目标字符串指针
// nSrcLength: 源字符串长度
// 返回 : 目标字符串长度
UCHAR Invert_Return(UCHAR xdata *pSrc,UCHAR xdata *pDst,UCHAR nSrcLength)
{
UCHAR nDstLength; // 目标字符串长度
UCHAR ch,i;
nDstLength = nSrcLength;
for(i=0; i<nSrcLength;i+=2) // 两两颠倒
{
ch = *pSrc++; // 保存先出现的字符
*pDst++ = *pSrc++; // 复制后出现的字符
*pDst++ = ch; // 复制先出现的字符
}
if(*(pDst-1) == 'F')
{
pDst--;
nDstLength--; // 目标字符串长度减 1
}
return(nDstLength); // 返回目标字符串长度
}
/******************************************************************************/
// 以下是 PDU 全串的编解码模块。为简化编程,有些字段用了固定值。
// PDU 编码,用于编制、发送短消息
// pSrc: 源 PDU 参数指针
// pDst: 目标 PDU 串指针
// 返回 : 目标 PDU 串长度
UINT gsmEncodePdu(UCHAR xdata *pSrc,UCHAR xdata *pDst)
{
UINT xdata nDstLength; // 目标 PDU 串长度
UCHAR xdata code_char[160]; //编码字符缓冲区
UCHAR xdata buf[5]; // 内部用的缓冲区
UCHAR xdata m;
buf[0] = 0x00; //默认中心号码
nDstLength = EncodeBetyChange(buf, pDst, 1); // 转换 1 个字节到目标 PDU 串
if(message_ture == 1)
buf[0] = 0x31; //需要回执
else
buf[0] = 0x11; // 是发送短信 (TP-MTI=01) , TP-VP 用相对格式 (TP-VPF=10)
buf[1] = 0x00; // TP-MR=0
m = strlen(PhoneNum);
buf[2] = m; // 目标地址数字个数 (TP-DA 地址字符串真实长度 )
if((PhoneNum[0] == '8')&&(PhoneNum[1] == '6'))
buf[3] = 0x91; //用国际格式号码
else
buf[3] = 0x81; //用国内格式号码
nDstLength += EncodeBetyChange(buf, pDst + nDstLength, 4); // 转换 4 个字节到目标 PDU 串
nDstLength += InvertNumbers(PhoneNum, pDst + nDstLength, m); // 转换 TP-DA 到目标 PDU 串
// TPDU 段协议标识、编码方式、用户信息等
buf[0] = 0; // 协议标识 (TP-PID)
buf[1] = TP_DCS; // 用户信息编码方式 (TP-DCS)
buf[2] = 255; // 有效期 (TP-VP)=0 为 5 分钟 ; =255为最长。
buf[3] = strlen(pSrc); //信息长度
if(data_gsm == 1)
buf[3] = data_len;
if(buf[1] == GSM_7BIT)
{
buf[4] = EncodeBit7(pSrc, code_char, buf[3]);
}
else if(buf[1] == GSM_8BIT)
{
buf[4] = buf[3];
memcpy(code_char, pSrc, buf[3]);
}
nDstLength += EncodeBetyChange(buf, pDst + nDstLength, 4); // 转换 4 个字节到目标 PDU 串
nDstLength += EncodeBetyChange(code_char, pDst + nDstLength, buf[4]); // 转换信息内容到目标 PDU 串
*(pDst + nDstLength) = 0x1a; // 以 Ctrl-Z 结束
nDstLength++;
return (nDstLength); // 返回目标字符串长度
}
/******************************************************************************/
// PDU 解码,用于接收、阅读短消息
// pSrc: 源 PDU 串指针
// pDst: 目标 PDU 参数指针
// 返回 : 用户信息串长度
UCHAR gsmDecodePdu(UCHAR xdata *pSrc,UCHAR xdata *pDst)
{
UCHAR nDstLength; // 目标 PDU 串长度
UCHAR xdata code_char[165]; //解码字符缓冲区
UCHAR code receive_ture[] = {"ok"}; //解码字符缓冲区
UCHAR xdata i,m;
m=(*(pSrc+1))&0xf; // 取SMSC 号码串长度
pSrc += m*2 + 2; // 指针后移
DecodeBetyChange(pSrc,&m,1); // 基本参数
pSrc += 2; // 指针后移
if((m & 0x02) == 0x02) //短信接受确认信息
{
pSrc += 2;
DecodeBetyChange(pSrc, &m, 1); // 取长度
pSrc += 4; // 指针后移,忽略了回复地址(TP-RA)格式
nDstLength = Invert_Return(pSrc,pDst,(m+1)&0xfe); // 取 TP-RA 号码
pSrc += (m+1)&0xfe; // 指针后移
*(pDst+nDstLength) = ',';
nDstLength++;
pSrc += 14;
nDstLength += Invert_Return(pSrc,pDst+nDstLength,12); // 服务时间戳字符串
*(pDst+nDstLength) = ',';
nDstLength++;
memcpy(pDst+nDstLength, receive_ture, 2);
nDstLength += 2;
return (nDstLength);
}
//08 91683108505905F0 06 1D 0D 91683158703261F6 505021908480 23 505021908411 23 00 FF //回执PDU
//08 91683108200505F0 24 0D 91683158714209F8 00 00 400152803535 00 04 D4F29C0E //接受PDU
DecodeBetyChange(pSrc,code_char,1);
m = code_char[0]; //回复地址信息长度 (TP-UDL)
pSrc += 4; // 指针后移
nDstLength = Invert_Return(pSrc,pDst,(m+1)&0xfe); // 取 TP-RA 号码
pSrc += (m+1)&0xfe;
*(pDst+nDstLength) = ',';
nDstLength++;
pSrc += 2;
TP_DCS = *(pSrc+1) & 0x0f; //编码方式
pSrc += 2;
nDstLength += Invert_Return(pSrc,pDst+nDstLength,12); // 服务时间戳字符串
pSrc += 14;
*(pDst+nDstLength) = ',';
nDstLength++;
DecodeBetyChange(pSrc,code_char,1);
m = code_char[0]; // 用户信息长度 (TP-UDL)
pSrc += 2;
DecodeBetyChange(pSrc,code_char,m); // 格式转换
if(TP_DCS == GSM_7BIT)
{
nDstLength += DecodeBit7(code_char,pDst+nDstLength,m); // 7-bit 解码
}
else if(TP_DCS == GSM_8BIT)
{
memcpy(pDst+nDstLength, code_char, m); // 8-bit 解码
nDstLength += m;
}
else if(TP_DCS == GSM_UCS2)
{
for(i = 0; i < m; )
{
*(pDst+nDstLength) = *(code_char + i + 1); // 16-bit 解码
nDstLength ++;
i += 2;
}
}
*(pDst+nDstLength) = '\n';
nDstLength++;
*(pDst+nDstLength) = '\0';
nDstLength++;
return (nDstLength);
}
/******************************************************************************/
// 发送短消息
// pSrc: 源 PDU 参数指针
bit SendMessage(UCHAR xdata *pSrc)
{
UINT xdata PduLength; // PDU 串长度
UCHAR xdata SmsLength; // SMS 串长度
UINT xdata r_len; // 串口收到的数据长度
UCHAR m,i,j;
UCHAR code cmd0[9]={"AT+CMGS="}; // 命令串
UCHAR xdata cmd[9]; // 命令串
UCHAR xdata pdu[500]; // PDU 串
UCHAR xdata ans[64]; // 应答串
while(gsm_busy)
os_wait(K_TMO,1,0);
gsm_busy = 1;
PduLength = gsmEncodePdu(pSrc, pdu); // 根据 PDU 参数,编码 PDU 串
SmsLength = (PduLength - 2)/2; // 取 PDU 串中的 SMS 信息长度
for(i=0;i<8;i++)
cmd[i]=cmd0[i];
get_string_clear1( ); //清空缓冲区
put_string1(cmd, 8);
i = SmsLength/100;
if(i != 0)
put_char1(i +0x30); //发送指令
SmsLength = SmsLength%100;
m = SmsLength/10;
if((m != 0)||(i != 0))
put_char1(m +0x30); //发送PDU长度
put_char1((SmsLength%10)+0x30);
put_char1(0x0d);
put_char1(0x0a);
for(i = 2; i>0; i--)
{
r_len = get_string1(ans); // 读应答数据
if(r_len != 0)
{
break;
}
}
if(r_len == 0)
{
gsm_busy = 0;
return(FALSE);
}
if(ans[r_len-2] != '>')
{
gsm_busy = 0;
return(FALSE);
}
put_string1(pdu,PduLength); //发送PDU
for(j=0; j<4; j++)
{
for(i=0; i<25; i++)
{
memset(ans,0x00,64);
r_len = get_string1(ans); // 读应答数据
if(r_len > 0)
{
break;
}
}
ans[r_len] = '\0';
if((r_len > 3) && (strstr(ans,"OK") != NULL)) //查找OK
{
gsm_busy = 0;
day_inc = 0;
return(TRUE);
}
}
gsm_busy = 0;
return(FALSE);
}
/******************************************************************************/
// 删除短消息
// index: 短消息序号,从 1 开始
void DeleteMessage(UCHAR index)
{
UCHAR m,i;
UCHAR code cmd0[9]={"AT+CMGD="}; // 命令串
UCHAR xdata cmd[9]; // 命令串
for(i=0;i<8;i++)
cmd[i]=cmd0[i];
get_string_clear1( ); //清空缓冲区
put_string1(cmd, 8);
m = index/10;
if(m != 0)
put_char1(m +0x30);
put_char1((index%10)+0x30);
put_char1(0x0d);
put_char1(0x0a);
get_string_clear1( ); //清空缓冲区
}
/******************************************************************************/
// 读取短消息
// 用CMGL
//一次读出一条短消息
// pDrc 返回字符串指针
// index 短信序号
//返回:字符串长度
UCHAR ReadMessage(UCHAR xdata *pDrc)
{
UCHAR m,i,index;
UINT xdata r_len; // 串口收到的数据长度
UCHAR code cmd0[16]={"AT+CMGL=4\r\n"}; // 命令串
UCHAR xdata cmd[16]; // 命令串
UCHAR xdata buf[500]; // 接受缓冲
UCHAR xdata *ptr;
while(gsm_busy)
os_wait(K_TMO,1,0);
ptr = buf;
gsm_busy = 1;
for(i=0;i<12;i++)
cmd[i]=cmd0[i];
get_string_clear1( ); //清空缓冲区
put_string1(cmd, 11);
for(i = 8; i>0; i--)
{
r_len = get_string1(buf); // 读应答数据
if(r_len > 30)
break;
}
if(r_len < 30)
{
gsm_busy = 0;
return(0);
}
buf[r_len] = '\0';
if((ptr = strstr(buf, "CMGL:")) != NULL)
{
ptr = strchr(buf,','); // 跳过"+CMGL:"
index = ((*(ptr-2))&0x0f)*10 + ((*(ptr-1))&0x0f); // 读取序号
ptr = strstr(ptr, "\r\n"); // 找下一行
ptr += 2; // 跳过"\r\n"
m = gsmDecodePdu(ptr, pDrc); // PDU串解码
DeleteMessage(index);
gsm_busy = 0;
return(m);
}
gsm_busy = 0;
return (0);
}
/******************************************************************************/
void read_storage(UCHAR n)
{
UCHAR code cmd0[]={"AT+CPMS= ME , SM , SM \r\n"}; // 命令串
UCHAR code cmd1[]={"AT+CPMS= SM , SM , SM \r\n"}; // 命令串
UCHAR xdata cmd[25]; // 命令串
UCHAR i;
while(gsm_busy)
os_wait(K_TMO,1,0);
gsm_busy = 1;
if(n == 1)
{
for(i=0;i<24;i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -