?? 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 + -