版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_17017545/article/details/79301574
读取的原理:
1. 首先向设备发送一条命令,设备收到这条命令时会将配置数据返回。
2. 程序初始化代码中有个定时器,会定时检测从串口收到的数据,通过添加判断对不同种类的数据做不同的处理
3. 当发现串口收到的数据为我们需要的数据时(这里通过检测数据头部标记”@#^*”),将数据存储下来。
4. 继续通过不同的GT命令头,将整个数据分为多个GT数据段
5. 每个GT数据段通过逗号将每一位数据分配到指定的控件中并显示出来
具体代码流程如下:
// Read 菜单项消息处理函数
void CIntegrityMobileConfiguratorDlg::OnDeviceRead()
{
// TODO: 在此添加命令处理程序代码
m_pcfgProcess->CfgRead(CFG_TYPE_ALL);
}
afx_msg void OnDeviceRead(); //头文件中消息响应函数申明
//发送
void CfgProcess::CfgRead(DWORD cfgType)
{
nCurrentCfgType = cfgType; //设置配置类型
switch (cfgType)
{
case CFG_TYPE_ALL:
{
memset(strCmdPara,0,sizeof strCmdPara);
char *data_t = "AT+GTRTO=AIR11,2,,,,,,,,,,,,,000B$"; //GTRTO模式2:请求设备报告其整个配置
//case内部有定义,需要加大括号
sendData(data_t); //发送数据的函数,在此不再展开
break;
}
default:
break;
}
}
//与此同时在初始化函数中有个定时从串口接收数据的定时器
BOOL CIntegrityMobileConfiguratorDlg::OnInitDialog()
{
SetTimer(COM_RECV_PROC_TIMER,150,NULL);//串口接收数据定时器
}
//对定时器的事件的响应函数
void CIntegrityMobileConfiguratorDlg::OnTimer(UINT nIDEvent)
{
switch (nIDEvent)
{
case COM_RECV_PROC_TIMER:
{
ComRecvProc();
break;
}
default:
break;
}
}
//接收串口数据
void CIntegrityMobileConfiguratorDlg::ComRecvProc()
{
DrawConnInd(m_bConnInd); //画出连接指示
if(!m_bSerialConnected)
{
return;
}
char cData[SERIAL_RECV_BUF_LEN+1];
DWORD data_len; //读取的字节数
COMSTAT comstat = {0};
DWORD dwError
ClearCommError(m_hCom,&dwError,&comstat);
if(comstat.cbInQue > 0) //收到数据
{
Sleep(50);
ReadFile(m_hCom, cData, SERIAL_RECV_BUF_LEN, &data_len, NULL);
cData[data_len] = '\0'; // cData就是指向接收到的字符串的指针
if(strstr(cData,SERIAL_HANDSHAKE_RSP) != NULL) //如果握手连接成功,设置m_bConnInd为true,显示灯变绿色
{
m_bConnInd = TRUE;
SetTimer(COM_DISCONN_IND_TIMER,11000,NULL);
}
//进行配置处理
char *pStart, *pEnd;
#if 1
//如果接收的数据不是ACK或者RESP,就不进行配置处理
if((pStart=strstr(cData,CFG_UART_RECV_HEAD)) == NULL)
{
if((pStart=strstr(cData,"AT+CGMR\r\n\r\n+CGMR: ")) != NULL)//for query version
{
pStart+=strlen("AT+CGMR\r\n\r\n+CGMR: ");
// AddMessage(CString("Query Version\r\n\r\nVersion: ")+pStart);//在控件中显示接收到的数据
if((pEnd=strchr(pStart,'t')) != NULL)
{
int verno = strtol(pEnd+1,NULL,16);
//配置工具和设备兼容性检查
if(verno>COMPATIBLE_VERNO_MAX)
AfxMessageBox("Version not compatible!\r\nPlease use the new version ConfigTool!");
else if(verno<COMPATIBLE_VERNO_MIN)
AfxMessageBox("Version not compatible!\r\nPlease use the old version ConfigTool!");
else
AfxMessageBox("Version compatible!");
}
}
else if(strstr(cData,SERIAL_HANDSHAKE_RSP) == NULL && strstr(cData,SERIAL_HANDSHAKE_REQ) == NULL && strchr(cData,CFG_END_SYMBOL) == NULL
&& strstr(cData,"recv from telit -") == NULL)
{
// AddMessage(cData);//在控件中显示接收到的数据
}
return;
}
#endif
pStart += strlen(CFG_UART_RECV_HEAD); //头指针的位置通过"@#^*"来判断 注:串口工具读出来有这串字符,工具没有
if((pEnd=strchr(pStart,CFG_END_SYMBOL)) == NULL) //尾指针的位置通过"$"来判断
{
return;
}
*(pEnd+1) = 0;
data_len = pEnd-pStart+1;
//处理ACK或者RESP数据
::SendMessage(this->m_hWnd,WM_CFG_RECV,(WPARAM)pStart,(LPARAM)data_len);
}
}
//映射表中的宏与响应函数
ON_MESSAGE(WM_CFG_RECV,&CIntegrityMobileConfiguratorDlg::OnCfgRecvMsg)
//响应函数的定义
LONG CIntegrityMobileConfiguratorDlg::OnCfgRecvMsg(WPARAM wParam,LPARAM lParam)
{
//处理收到的数据
m_pcfgProcess->CfgRecvData((char*)wParam,(int)lParam);
return 0;
}
void CfgProcess::CfgRecvData(char *data, int len)
{
int tempLen = 0;
if(*data != CFG_CUSTOM_SYMBOL)
{
return;
}
if(*(data+len-1) != CFG_END_SYMBOL)
{
return;
}
else if(strncmp(data,CFG_RESP_TOKEN,tempLen=strlen(CFG_RESP_TOKEN))==0)
{
CfgRecvResp(data+tempLen,len-tempLen);
}
//处理完成,清除配置类型
nCurrentCfgType = CFG_TYPE_NONE;
}
//数据校验(头部尾部)
void CfgProcess::CfgRecvResp(char *data, int len)
{
int tempLen = 0, datalen;
char *pStart;
if((pStart=strchr(data,CFG_CUSTOM_COMMA)) == NULL)
return;
//数据头部校验
pStart++;
if(!CheckRecvHead(pStart,&tempLen))
return;
pStart += tempLen+1;
//数据尾部校验
if(!CheckRecvTail(pStart,&tempLen))
return;
datalen = data+len-pStart-tempLen-1;
if(datalen < 0)
datalen = 0;
//判断命令类型
if(strncmp(data,CFG_CMD_GTALL,strlen(CFG_CMD_GTALL))==0)
{
CfgGetAll(pStart,datalen);
}
else
{
//NULL
}
}
//重要步骤
// GTALL: BSI,SRI,CFG,NMD...... 从模块内读取数据,并覆盖当前输入框内的数据。
BOOL CfgProcess::CfgGetAll(char *data, int len)
{
int i=0, j=0, GtallCmdNum = sizeof GtallCmdTable / sizeof struct_cmd_map; // GtGtallCmdNum:总的命令个数 (这里等于9)
char *pStart, *pEnd = data;
for(i=0; i<GtallCmdNum; i=j+1)
{
pStart = pEnd + strlen(GtallCmdTable[i].cmdStr) + 1; //相当于 pEnd+4 此时pStart指向 (例BSI,4444,,,,,,,)BSI逗号之后,真正数据开始处
for(j=i, pEnd=NULL; (j<GtallCmdNum-1) && !(pEnd=strstr(pStart,GtallCmdTable[j+1].cmdStr)); j++); //strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。
if(pEnd==NULL || pEnd>=(data+len+1))
{
pEnd = data+len+1;
GtallCmdNum = i; //终止循环
}
//提取参数并更新显示
if(nCurrentCfgType & GtallCmdTable[i].cfgType)
{
(this->*GtallCmdTable[i].cmdFunc)(pStart,pEnd-pStart-1);
}
}
return TRUE;
}
//GtallCmdTable严格按GTALL的参数顺序排列
//这里的顺序代表当read all 时从串口读取的所有的resp的顺序
struct_cmd_map GtallCmdTable[]=
{
{CFG_TYPE_BSI, "BSI", &CfgProcess::CfgGetBsi},
{CFG_TYPE_SRI, "SRI", &CfgProcess::CfgGetSri},
{CFG_TYPE_CFG, "CFG", &CfgProcess::CfgGetCfg},
{CFG_TYPE_NMD, "NMD", &CfgProcess::CfgGetNmd},
{CFG_TYPE_FRI, "FRI", &CfgProcess::CfgGetFri},
{CFG_TYPE_WLT, "WLT", &CfgProcess::CfgGetWlt},
{CFG_TYPE_AGP, "AGP", &CfgProcess::CfgGetAgp},
{CFG_TYPE_WSL, "WSL", &CfgProcess::CfgGetWsl},
{CFG_TYPE_MDA, "DEV", &CfgProcess::CfgGetMda},
}
//GTBSI举例
BOOL CfgProcess::CfgGetBsi(char *data, int len)
// 函数中两个参数分别代表BSI相关数据字符串起始位置以及长度。
// 参数传递自上方函数(this->*GtallCmdTable[i].cmdFunc)(pStart,pEnd-pStart-1);
{
if(!(nCurrentCfgType & CFG_TYPE_BSI))
return FALSE;
if(SplitCmdPara(data,len) < 3)
return FALSE;
// CheckBsiPara(strCmdPara);
//更新显示
lpUpdateDisplay(strCmdPara,CFG_TYPE_BSI,dwUserData);
return TRUE;
}
//将命令解析开来,每一段都存储到对应数组中
int CfgProcess::SplitCmdPara(char *data, int len) //Split:分裂
{
int i, tempLen;
char *pStart, *pEnd;
memset(strCmdPara,0,sizeof strCmdPara);
if(len < 0)
return 0;
for(i=0, pStart=data; ; i++, pStart=pEnd+1)
{ //strchr是计算机的一个函数,原型为extern char *strchr(const char *s,char c),可以查找字符串s中首次出现字符c的位置。
pEnd = strchr(pStart,CFG_CUSTOM_COMMA); //#define CFG_CUSTOM_COMMA ',' 以逗号来分开命令
if(pEnd==NULL || pEnd>=(data+len))
{
break;
}
if((tempLen=pEnd-pStart) >= MAX_CMD_PARA_LEN)
{
tempLen = MAX_CMD_PARA_LEN-1;
}
memcpy(strCmdPara[i],pStart,tempLen);
//void *memcpy(void *dest, const void *src, size_t n);
//memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。
}
if((tempLen=data+len-pStart) >= MAX_CMD_PARA_LEN)
{
tempLen = MAX_CMD_PARA_LEN-1;
}
memcpy(strCmdPara[i],pStart,tempLen);
return i+1;
}
//GTMDA举例
BOOL CfgProcess::CfgGetMda(char *data, int len)
{
if(!(nCurrentCfgType & CFG_TYPE_MDA))
return FALSE;
if(M3_SplitCmdPara(data,len) < 2)
return FALSE;
// CheckMdaPara(strCmdPara);
//更新显示
lpUpdateDisplay(strCmdPara,CFG_TYPE_MDA,dwUserData);
return TRUE;
}
int CfgProcess::M3_SplitCmdPara(char *data, int len)
{
int i,tempLen;
char *pStart = NULL,*pMid = NULL,*pEnd = NULL;
memset(strCmdPara,0,sizeof strCmdPara);
if(len <= 0) //当数据为空时显示 DEV,,20170000……$, 需要判断为零就返回
return 0;
for(i=0,pStart=data; i<31 ; i+=2, pStart=pEnd+1)
{
pMid = strchr(pStart,CFG_CUSTOM_COLON); //#define CFG_CUSTOM_COLON ':'
if(pMid != NULL)
{
memcpy(strCmdPara[i],pStart+3,5); //将每组数据的后面五位存储到Address中 一组数据例如:22:12345
memcpy(strCmdPara[i+1],pStart,2); //将每组数据的前两位转换为Dui
pEnd = strchr(pMid,CFG_CUSTOM_COMMA);
}
else
{
strcpy(strCmdPara[i],"");
strcpy(strCmdPara[i+1],"10");
}
}
return i+1;
}
//更新函数
void CIntegrityMobileConfiguratorDlg::UpdateDisplay(char cmdPara[][MAX_CMD_PARA_LEN],DWORD cfgType)
{
isInnerChange = TRUE;
switch (cfgType)
{
case CFG_TYPE_BSI:
SetGtbsiPara(cmdPara); //将数组数据显示到对应控件中
page2.SetDlgItemText(IDC_EDIT_GTBSI,m_pcfgProcess->CfgMakeGtbsi_read(cmdPara)); //将新的数据重新显示到下方AT编辑框中
break;
case CFG_TYPE_SRI:
SetGtsriPara(cmdPara);
page2.SetDlgItemText(IDC_EDIT_GTSRI,m_pcfgProcess->CfgMakeGtsri_read(cmdPara));
break;
case CFG_TYPE_CFG:
SetGtcfgPara(cmdPara);
page2.SetDlgItemText(IDC_EDIT_GTCFG,m_pcfgProcess->CfgMakeGtcfg_read(cmdPara));
break;
case CFG_TYPE_WSL:
SetGtwslPara(cmdPara);
page2.SetDlgItemText(IDC_EDIT_GTWSL,m_pcfgProcess->CfgMakeGtwsl_read(cmdPara));
break;
case CFG_TYPE_WLT:
SetGtwltPara(cmdPara);
page2.SetDlgItemText(IDC_EDIT_GTWLT,m_pcfgProcess->CfgMakeGtwlt_read(cmdPara));
break;
case CFG_TYPE_FRI:
SetGtfriPara(cmdPara);
page2.SetDlgItemText(IDC_EDIT_GTFRI,m_pcfgProcess->CfgMakeGtfri_read(cmdPara));
break;
case CFG_TYPE_AGP:
SetGtagpPara(cmdPara);
page2.SetDlgItemText(IDC_EDIT_GTAGP,m_pcfgProcess->CfgMakeGtagp_read(cmdPara));
break;
case CFG_TYPE_NMD:
SetGtnmdPara(cmdPara);
page2.SetDlgItemText(IDC_EDIT_GTNMD,m_pcfgProcess->CfgMakeGtnmd_read(cmdPara));
break;
case CFG_TYPE_MDA:
SetGtmdaPara(cmdPara);
Mosaic(cmdPara); // 将Dui转换为对应的选项
page1.SetDlgItemText(IDC_EDIT_GTDEV,m_pcfgProcess->CfgMakeGtdev_read(cmdPara));
break;
default:
break;
}
isInnerChange = FALSE;
}
//将GTDEV中每一组mode与Address拼接在一起
void CIntegrityMobileConfiguratorDlg::Mosaic(char cmdPara[][MAX_CMD_PARA_LEN])
{
int i=0,j=1,k=41,X;
for(;i<31;i+=2,j+=2,k+=1)
{
CString Address(cmdPara[i]);
CString Dui(cmdPara[j]);
CString Add(cmdPara[k]);
X = atoi(cmdPara[j]);
switch(X)
{
case 0:
Dui = "10";
break;
case 1:
Dui = "11";
break;
case 2:
Dui = "12";
break;
case 3:
Dui = "13";
break;
case 4:
Dui = "14";
break;
case 5:
Dui = "20";
break;
case 6:
Dui = "21";
break;
case 7:
Dui = "22";
break;
case 8:
Dui = "30";
break;
case 9:
Dui = "31";
break;
case 10:
Dui = "32";
break;
}
if((strlen(Address))>0)
{
Add = Dui + Address;
strcpy(cmdPara[k], Add.GetBuffer(0));
}
else
{
Add = Address; //当Address为空时,不将Dui与Address拼接在一起显示,只将Address的空值显示到底部的边框内
strcpy(cmdPara[k], Add.GetBuffer(0));
}
}
}