//HalUARTWrite(MT_UART_DEFAULT_PORT, msgPtr, dataLen + SPI_0DATA_MSG_LEN);可以避免打印FE開頭的數據也可以在MT_TransportSend函數中將上述語句替換為自己的開機提示信息方便上位機判斷zigbee模塊是否重啟
HalUARTWrite(MT_UART_DEFAULT_PORT, "Reset/r/n", 7);
if(serial.bytesAvailable() >=5 )檢測緩沖區,如果有效可讀數據大于等于5的話再去讀取串口!!!還有就是表示發送開始的信息發送出去以后,延時一會兒,這樣QT那邊就能將整個開始信息完整讀取,方便新建文件,同樣,在發送結束信息之前也要延時!!!
在使用QFile新建文件的時候,文件名不能包含冒號等特殊字符,否則會不能新建文件。多利用linux的grep命令在開源項目查找代碼需要解決的問題: (1)如果協調器斷電重啟、終端重啟 (2)QT串口如何處理包頭信息已達到區分不同類型的節點數據 (3)美化上位機:添加設置選項,目前是寫死了波特率等選項!還有進度條,所用時間等都需要設置!串口讀取的核心代碼:
void MainWindow::serialRead(){ static unsigned int length = 0; if(serial.bytesAvailable() >=5 ) { //讀串口數據 QByteArray serial_data = serial.readAll(); length += serial_data.length(); char *str_tmp=serial_data.data(); //判斷圖片是否傳送完畢--接收到的是否是end if(strcmp("end/r/n",str_tmp) == 0) { dst.close(); qDebug()<<"end"; qDebug()<<length; return ; } //判斷是不是一張新的圖片 //如果是beigin開頭,新建文件 if(strcmp("begin/r/n",str_tmp) == 0) { QDateTime time = QDateTime::currentDateTime();//獲取系統現在的時間 //設置顯示格式,注意QFile的文件名不能有:(冒號)等特殊字符 QString str = time.toString("yyyy-MM-dd-hh-mm-ss"); str += ".jpg"; qDebug()<<str; dst.setFileName(str);//將時間作為文件名 //QDir::currentPath() bool isOK = dst.open(QIODevice::WriteOnly|QIODevice::Append); if(isOK == false) { qDebug()<<"dst.open err"; this->close(); } qDebug()<<length; return ; } //如果不是begin開頭,將數據插入原來打開文件的末尾 dst.write(serial_data); //將數據格式化 QString str_display; QString str = serial_data.toHex().data(); str = str.toUpper(); str_display.clear(); for(int i = 0;i < str.length();i+= 2) { QString st = str.mid(i,2); str_display += st; str_display += " "; } //顯示數據 ui->textEdit->insertPlainText(str_display); qDebug()<<length; }}協調器核心代碼
void SimonApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ){ uint8 id = 255; if ( MY_ENDPOINT01 == pkt->endPoint )//7號端點 { switch ( pkt->clusterId ) { case 0x0001://1號員工--負責處理終端節點按鍵3按下發送過來的數據 //Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength); LS164_BYTE(pkt->cmd.Data[0]); MYLED1 ^= 1;//LED翻轉 break; case 0x0002://2號員工--負責處理終端節點按鍵4按下發送過來的數據 //Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength); LS164_BYTE(pkt->cmd.Data[0]); MYLED2 ^= 1; break; } } if ( MY_ENDPOINT02 == pkt->endPoint )//6號端點/房間 { switch ( pkt->clusterId ) { case CLUSTER_PHOTO_NODE://1號員工 //Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength); //LS164_BYTE(pkt->cmd.Data[0]); //HalUARTWrite(MY_PORT_NUM,"Simon/r/n",7); if(TYPE_PHOTO == pkt->cmd.Data[0])//如果是圖像節點發送來的數據 { MYLED3 ^= 1;//LED3翻轉 id = pkt->cmd.Data[1];//獲取節點在同類節點中的序號 gPhotoID = id;//緩存序號 //HalUARTWrite(MY_PORT_NUM,pkt->cmd.Data,pkt->cmd.DataLength); //為了避免終端節點突然死機重新入網引起的數據中斷錯誤需要判斷新的網絡地址和之前保存的是否一致 //此時在協調器PothoNode_AddrArr[id].exist非零,但終端節點的網絡短地址可能發生改變 //如果不更新網絡地址,則協調器反饋的信息將不能達到終端節點,從而引發錯誤 if((0 == PothoNode_AddrArr[id].exist) || (PothoNode_AddrArr[id].shortAddr != *((uint16 *)&(pkt->cmd.Data[4])))) { //((uint8 * )&(PothoNode_AddrArr[id].shortAddr))[0] = pkt->cmd.Data[5];//pkt->cmd.Data[4]<<8+ pkt->cmd.Data[5]); //((uint8 * )&(PothoNode_AddrArr[id].shortAddr))[1] = pkt->cmd.Data[4]; /*每次數據到來都講數據包里攜帶的網絡短地址和端點緩存下來*/ PothoNode_AddrArr[id].shortAddr = *((uint16 *)&(pkt->cmd.Data[4]));//(pkt->cmd.Data[5]*256+ pkt->cmd.Data[4]); PothoNode_AddrArr[id].endPoint = pkt->cmd.Data[6]; //表示已經緩存過該節點--現處于調試階段--后期修改 //按理來說,這里的代碼應該只在節點第一次發送數據給協調器的時候調用 PothoNode_AddrArr[id].exist = 1; MYLED2 ^= 1;//協調器第一次收到某個節點發送的數據--翻轉LED2 } #if 0 //HalUARTWrite(MY_PORT_NUM,(uint8 *)PothoNode_AddrArr,PHOTO_ID_MAX*sizeof(AddrInfo_t)); //if((PothoNode_AddrArr[id].seqnb + 1) == (pkt->cmd.Data[2]<<8+ pkt->cmd.Data[3])) //if( (((uint8 * )&(PothoNode_AddrArr[id].seqnb))[0] +1) == pkt->cmd.Data[3] // && ((uint8 * )&(PothoNode_AddrArr[id].seqnb))[1] == pkt->cmd.Data[2] ) //if((PothoNode_AddrArr[id].seqnb + 1) == (pkt->cmd.Data[3]*256+ pkt->cmd.Data[2])) if((PothoNode_AddrArr[id].seqnb + 1) == (*((uint16 *)&(pkt->cmd.Data[2])))) { HalUARTWrite(MY_PORT_NUM,pkt->cmd.Data,pkt->cmd.DataLength); osal_set_event( SimonApp_TaskID, SimonApp_RESPONSE_PHOTO_EVT ); PothoNode_AddrArr[id].seqnb++; }#endif //每次有數據到來,都直接將數據發送給上位機 HalUARTWrite(MY_PORT_NUM,pkt->cmd.Data+8,pkt->cmd.DataLength-8); //每次有數據到來,都給節點反饋信息 osal_set_event( SimonApp_TaskID, SimonApp_RESPONSE_PHOTO_EVT ); //ResponsePhotoNode(); } break; } }}終端模塊核心代碼
/*added by Simon*//*當串口接收到上位機的數據以后,打包-->發送給協調器*/static void rxCB(uint8 port,uint8 event){ static uint8 tmp_len = 0; //osal_memset(gUartBuf,0,BUF_MAX); //在協議棧的回調函數里必須加上該條件判斷才能正常使用回調功能 //回調函數默認是利用DMA的輪詢方式工作 if ((event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT)) &&!tmp_len) { if(!tmp_len)//tmp_len必須是0 { osal_memset(gUartBuf,0,BUF_MAX);//清空緩沖區 tmp_len=HalUARTRead(MY_PORT_NUM,gUartBuf+7, BUF_MAX);//讀取串口內容,此時的長度tmp_len為有效數據長度 /*開頭的八個字節是節點的相關信息*/ gUartBuf[0] = TYPE_PHOTO;//節點類型 gUartBuf[1] = MY_ID;//同類節點中的節點序號 /*2530是低地址對應低字節*/ /*在網絡數據包里盡量吧低字節放在低地址(數據包的前面)*/ /*該數據包在已發送序列中的序號*/ mySeq++; //HalUARTWrite(MY_PORT_NUM,(uint8 *)&mySeq,2); gUartBuf[3] = (mySeq>>8); gUartBuf[2] = (mySeq%256); /*該節點的網絡短地址*/ myAddr = NLME_GetShortAddr(); gUartBuf[5] = (myAddr>>8); gUartBuf[4] = (myAddr%256); /*該節點用哪個端點給協調器發送數據*/ gUartBuf[6] = MY_ENDPOINT; //gUartBuf[7] = 0;//保留未使用-->填充為0 //HalUARTWrite(MY_PORT_NUM,gUartBuf,tmp_len+3); } if(tmp_len>2 )//該參數有待修改 {// HalUARTWrite(MY_PORT_NUM,(uint8*)&tmp_len,1); //HalUARTWrite(MY_PORT_NUM,gUartBuf,tmp_len+3); tmp_len += 7;//長度修正為實際數據包大小 /*填充目標地址*/ SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;//單播模式 SimonApp_DstAddr.addr.shortAddr = 0x0000;//目標是協調器 // Take the first endpoint, Can be changed to search through endpoints SimonApp_DstAddr.endPoint = MY_ENDPOINT02;//發送給協調器的6號端點 AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,//端點描述符用默認填充的就好 CLUSTER_PHOTO_NODE,//6號端點里面的CLUSTER_PHOTO_NODE員工 tmp_len,//實際長度 (byte *)&gUartBuf,//打包好的數據 &SimonApp_TransID,//協議棧自動維護的數據包序號 AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );//后兩個參數默認不修改 } tmp_len=0; //清空長度 }}圖片發送模塊Linux開發板核心模塊:
#include "uart.h" #define MAX_BUF 64#define HDR_LEN 1#define OPEN_PIC_ERR -2 #define MAX_SEC 2 const char begin_str[] = "begin/r/n";const char end_str[] = "end/r/n";char buf[MAX_BUF+HDR_LEN]={0};char rcv_buf[MAX_BUF]={0};fd_set inset,tempset; struct timeval tv; int waitACK(int src_fd,int read_cnt){ int res = 0; while(1) { memset(rcv_buf,0,MAX_BUF); /*為了程序的健壯性,需要在主循環不斷更新文件描述符集合以及等待時間*/ tempset = inset; tv.tv_sec = MAX_SEC; tv.tv_usec = 0; res = select(src_fd + 1,&tempset,NULL,NULL,&tv); /*3.3.1 規定時間內收到響應數據包繼續往下執行*/ /*3.3.2 超時沒有響應信息則重新發送當前緩沖區數據包*/ /*3.3.3 發生錯誤就退出程序給出提示信息*/ if(res == 0) {新聞熱點
疑難解答