读取数据过程分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 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));            

            }
    }    
}

猜你喜欢

转载自blog.csdn.net/qq_17017545/article/details/79301574