单片机一直向上位机发送C,上位机收到后,发送文件,却只能发送一帧数据到单片机。上位机是我复制过来的,也改了许多。万望路过的大佬,可以帮帮忙看看代码哪里有错误?
QT上位机: Ymodem.h #include <QTimer>#include <QEventLoop> #include <QtSerialPort/QSerialPort>#include <QtSerialPort/QSerialPortInfo> #include <QLayout>#include <QProgressBar>#include <QLineEdit>#include <QPushButton>#include <QFileDialog> #include <QMessageBox> class terminal;class FtpHandle: public QWidget{ Q_OBJECTpublic: explicit FtpHandle(QWidget *parent); void SetPort(QSerialPort *P); //初始化串口端口 qint16 GetCrc(QByteArray Data); int ackwait(int to);private: QSerialPort *Port; QString FilePath; QString *recString; QByteArray TxData; QByteArray RxData; qint32 PackNumber; //发送文件的包数 qint32 PackCnt; //已发送的包数 qint32 PackIndex; //包序号 qint32 PackSize; //1包字节数 qint32 SendLen; //发送一帧数据的实际长度 //QTimer *tm_timeout; qint8 Step; quint8 AckFlag; //子窗口 QVBoxLayout *ftpLayout; QHBoxLayout *fileLayout; QProgressBar *pb_ftpProgress; QLineEdit *led_filePath; QPushButton *btn_fileOpen; QPushButton *btn_fileSend; signals: sgn_ftpEnd(); sgn_recvACK();private slots: void slt_rec_Handle(); //接收处理 void slt_send_Handle(); //发送处理 void slt_fileOpen();protected: virtual void closeEvent(QCloseEvent *event);}; #endif // FTPHANDLE_H Ymodem.c void FtpHandle::slt_rec_Handle() //接收处理函数{ QByteArray temp=Port->readAll(); RxData.append(temp); if(RxData.size()<0) return; switch(Step){ case 0: //等待收方的请求 { if(RxData.at(0) != 'C') break; qDebug()<<"get ack"; AckFlag='C'; sgn_recvACK(); //传输开始 Step=1; break; } case 1: //等待响应 { if(RxData.size()==1) { if(RxData.at(0)=='C') //只有C { qDebug()<<"only C"; AckFlag='C'; sgn_recvACK(); Step=3; } else if(RxData.at(0)==ACK) //只有ACK { qDebug()<<"only ACK"; } } else { if(RxData.at(0)==ACK&&RxData.at(1)=='C') //同时ACK C { qDebug()<<"get ack and C"; AckFlag='C'; sgn_recvACK(); Step=3; } } break; } case 2: //第二次等待对方的请求 { if(RxData.at(0) != 'C') break; AckFlag='C'; sgn_recvACK(); Step=3; break; } case 3: //发送文件数据包 { if(RxData.at(0) != ACK) break; pb_ftpProgress->setValue(PackCnt*100/PackNumber); //正式传输文件进度 TxData.remove(0, SendLen); //回复正确删除已发的长度 if(PackCnt >= PackNumber){ //发送完成 Step=4; } sgn_recvACK(); break; } case 4: //等待ACK C响应 { if(RxData.size()==1) { if(RxData.at(0)=='C') //只有C { qDebug()<<"only C"; sgn_recvACK(); Step=6; //slt_send_Handle(3); //直接发送空包 } else if(RxData.at(0)==ACK) //只有ACK { qDebug()<<"only ACK"; } else if(RxData.at(0)==NAK) { sgn_recvACK(); } } else { if(RxData.at(0)==ACK&&RxData.at(1)=='C') //同时ACK C { qDebug()<<"get ack and C"; sgn_recvACK(); Step=6; } } break; } case 5: //第三次等待C字符 { if(RxData.at(0) != 'C') break; qDebug()<<"get C"; Step=6; break; } case 6: // { if(RxData.at(0) != ACK) break; qDebug()<<"get the null pkg ack,ftp end"; sgn_recvACK(); break; } }} void FtpHandle::slt_send_Handle(){ quint16 ValidLen = 0; QByteArray Pack, Data; quint8 cnt = 0; //YModem 包号从1开始 quint16 Crc; int ackval=0; if(FilePath.isEmpty()) { QMessageBox *msgBox=new QMessageBox(this); //串口未打开,创建一个消息提醒框 msgBox->setWindowTitle(tr("Notice")); msgBox->setText(tr("请打开文件!")); msgBox->setStandardButtons(QMessageBox::Ok); msgBox->setDefaultButton(QMessageBox::Ok); int ret = msgBox->exec(); if(ret == QMessageBox::Ok) return; //串口未打开,禁止发送 else return; } Step=0; PackCnt=0; PackIndex=0; /***********************************************************************/ RxData.clear(); qDebug()<<"start"; ackval=ackwait(2000); if(ackval<=0) {RxData.clear();return;} else{ if(RxData.at(0)!='C') {RxData.clear();return;} }/***********************************************************************/ qDebug()<<"send file info"; PackIndex=0; //设置包序号 Pack[0] = SOH; Pack[1] = PackIndex; //包号 Pack[2] = ~PackIndex; //包号取反 Pack+=FilePath.section('/',-1).toLocal8Bit(); //添加文件名 Pack+='\0'; Pack+=QString::number(TxData.size()); int len=Pack.length()-3; //出去头部和序列号的长度 if(len<128) { QByteArray zero(128 - len, 0x00); //不足部分填充0x00 qDebug()<<"creat zero section"; Pack+=zero; } Crc = GetCrc(Pack.mid(3)); //CRC Pack += (quint8)(Crc >> 8); //先发高位 Pack += (quint8)(Crc & 0xff); //后发低位 qDebug()<<"write data to port"; Port->write(Pack, 128 + 5); //发送数据 qDebug()<<"write end"; qDebug()<<"send file info end"; Pack.clear(); //清buf Data.clear(); //清buf RxData.clear(); ackval=ackwait(2000); //超时2s if(ackval<=0) { RxData.clear(); return; } else { if(RxData.size()==1) { if(RxData.at(0)!='C') { RxData.clear(); return; } } if(RxData.size()>1) { if(RxData.at(0)!=ACK||RxData.at(1)!='C') { qDebug()<<"5"; RxData.clear(); return; } } }/***********************************************************************/ for(int i=0;i< ackNumber;i++) { PackIndex++; qDebug()<<" ackIndex="<< ackIndex; Pack[0] = STX; //目前只用1024byte类型 Pack[1] = PackIndex; //包号 Pack[2] = ~PackIndex; //包号取反 ValidLen = TxData.size(); //有效数据长度 if(ValidLen >= PackSize){ //大于包长 Data = TxData.left(PackSize); //从TxData的左侧取出PackSize长 SendLen = PackSize; //已发长度 }else{ QByteArray zero(PackSize - ValidLen, 0x1A); //不足部分填充0x1A Data = TxData.left(ValidLen); //不足一包 Data += zero; //填充其它数据 SendLen = ValidLen; //已发长度 } Crc = GetCrc(Data); //CRC Pack += Data; //填入数据 Pack += (quint8)(Crc >> 8); //先发高位 Pack += (quint8)(Crc & 0xff); //后发低位 Port->write(Pack, PackSize + 5); //发送数据 Pack.clear(); //清buf Data.clear(); //清buf PackCnt++; qDebug()<<" ackCnt="<< ackCnt; RxData.clear(); ackval=ackwait(20000); //超时1s if(ackval<=0) { RxData.clear(); return; } else { if(RxData.at(0)!=ACK) { RxData.clear(); return; } } }/***********************************************************************/ while(1) { qDebug()<<"send EOT"; Pack.clear(); //清除buf Pack += EOT; //发送结束符 Port->write(Pack, 1); //写 Pack.clear(); RxData.clear(); ackval=ackwait(3000); //超时1s if(ackval<=0) { RxData.clear(); return; } else { if(RxData.size()==1) { if(RxData.at(0)=='C') { RxData.clear(); break; } else if(RxData.at(0)!=NAK) { RxData.clear(); return; } } else if(RxData.size()>1) { if(RxData.at(0)==ACK&&RxData.at(1)=='C') { RxData.clear(); break; } } } } /***********************************************************************/ qDebug()<<"send null pkg to end"; cnt = 0; Pack[0] = SOH; //目前只用128byte类型 Pack[1] = cnt; //包号 Pack[2] = ~cnt; //包号取反 QByteArray zero(128, 0x00); //填充0x00 Crc = GetCrc(zero); //CRC Pack += zero; //填入数据 Pack += (quint8)(Crc >> 8); //先发高位 Pack += (quint8)(Crc & 0xff); //后发低位 Port->write(Pack, 128 + 5); //发送数据 Pack.clear(); //清buf Data.clear(); //清buf RxData.clear(); ackval=ackwait(1000); //超时1s if(ackval<=0) {RxData.clear();return;} else{ if(RxData.at(0)!=ACK) {RxData.clear();return;} }/***********************************************************************/ this->close();} int FtpHandle::ackwait(int to){ QEventLoop loop; QTimer timeout_t; timeout_t.setSingleShot(true); connect(&timeout_t,SIGNAL(timeout()),&loop,SLOT(quit())); connect(this,SIGNAL(sgn_recvACK()),&loop,SLOT(quit())); timeout_t.start(to); loop.exec(); if(timeout_t.isActive()) { qDebug()<<"ack ok"; return 1; } else { qDebug()<<"timeout"; return -1; }} Stm32F777单片机下: Ymodem.h #definePACKET_HEADER_SIZE ((uint32_t)3) #definePACKET_DATA_INDEX ((uint32_t)4) #definePACKET_START_INDEX ((uint32_t)1) #definePACKET_NUMBER_INDEX ((uint32_t)2) #definePACKET_CNUMBER_INDEX ((uint32_t)3) #definePACKET_TRAILER_SIZE ((uint32_t)2) #definePACKET_OVERHEAD_SIZE (PACKET_HEADER_SIZE + PACKET_TRAILER_SIZE - 1) #definePACKET_SIZE ((uint32_t)128) #definePACKET_1K_SIZE ((uint32_t)1024) #defineFILE_NAME_LENGTH ((uint32_t)64) #defineFILE_SIZE_LENGTH ((uint32_t)16) #define SOH ((uint8_t)0x01) /* start of 128-byte data packet */ #define STX ((uint8_t)0x02) /* start of 1024-byte data packet */ #define EOT ((uint8_t)0x04) /* end of transmission */ #define ACK ((uint8_t)0x06) /* acknowledge */ #define NAK ((uint8_t)0x15) /* negative acknowledge */ #define CA ((uint32_t)0x18) /* twoof these in succession aborts transfer */ #define CRC16 ((uint8_t)0x43) /* 'C' == 0x43, request 16-bit CRC */ #defineNEGATIVE_BYTE ((uint8_t)0xFF) #define ABORT1 ((uint8_t)0x41) /* 'A' == 0x41, abort by user */ #define ABORT2 ((uint8_t)0x61) /* 'a' == 0x61, abort by user */ #defineNAK_TIMEOUT ((uint32_t)0x100000) #define DOWNLOAD_TIMEOUT ((uint32_t)1000) /* One second retrydelay */ #defineMAX_ERRORS ((uint32_t)5) Ymodem.c HAL_StatusTypeDefSerial_PutByte( uint8_t param ) { return HAL_UART_Transmit(&huart1,¶m, 1, TX_TIMEOUT); } static HAL_StatusTypeDefReceivePacket(uint8_t *p_data, uint32_t *p_length, uint32_t timeout) { uint32_t crc; uint32_t packet_size = 0; HAL_StatusTypeDef status; uint8_t char1; *p_length = 0; status = HAL_UART_Receive(&huart1, &char1, 1, timeout); if (status == HAL_OK)//串口判忙 { // printf("ReceivePacket中char1 = :%c\r\n",char1); switch (char1) { case SOH://0x01 printf("SOH\r\n"); packet_size = PACKET_SIZE; //128byte break; case STX://0x02 printf("STX \r\n"); packet_size = PACKET_1K_SIZE;//1024byte break; case EOT://0x04 //结束发送标志位 printf("EOT\r\n"); if(EOTCN==0) { EOTCN=1; } else if(EOTCN==1) { EOTCN=2; } break; case CA: //两个连续终止传输 printf("CA\r\n"); if ((HAL_UART_Receive(&huart1,&char1, 1, timeout) == HAL_OK) && (char1 == CA)) { packet_size = 2; } else { status = HAL_ERROR; } break; case ABORT1: //'A' printf("ABORT1\r\n"); case ABORT2: //'a' printf("ABORT2\r\n"); status = HAL_BUSY; break; default: status = HAL_ERROR; break; } *p_data = char1; /************************************************* 当数据长度大于等于128byte时,判忙 若忙,判断p_data的长度,若长度不等,进行CRC检验 若不忙,将包的大小置0 **************************************************/ if (packet_size >= PACKET_SIZE ) { printf("packet_size >=PACKET_SIZE\r\n"); status = HAL_UART_Receive(&huart1,&p_data[PACKET_NUMBER_INDEX], packet_size + PACKET_OVERHEAD_SIZE, timeout); /* Simple packet sanity check */ if (status == HAL_OK ) { printf("reeive%02x\n",p_data[PACKET_NUMBER_INDEX]); if (p_data[PACKET_NUMBER_INDEX] !=((p_data[PACKET_CNUMBER_INDEX]) ^ NEGATIVE_BYTE)) { packet_size = 0; status = HAL_ERROR; } else { printf("check crc\r\n"); /* Check packet CRC */ crc = p_data[ packet_size + PACKET_DATA_INDEX] << 8; crc += p_data[ packet_size + PACKET_DATA_INDEX+ 1 ]; if (Cal_CRC16(&p_data[PACKET_DATA_INDEX],packet_size) != crc ) { printf("Error\r\n"); packet_size = 0; status = HAL_ERROR; } } } else { printf("size = 0\r\n"); packet_size = 0; } } } *p_length = packet_size; return status; } /** * @brief Prepare the first block //准备起始帧 * @param p_data: output buffer //输出缓冲区 * @param p_file_name: name of the file to be sent //要发送的文件名 * @param length: length of the file to be sent in bytes//要发送的文件长度 * @retval None */ static voidPrepareIntialPacket(uint8_t *p_data, const uint8_t *p_file_name, uint32_tlength) { uint32_t i, j = 0; uint8_t astring[10]; /* first 3 bytes are constant */ p_data[PACKET_START_INDEX] = SOH; //起始帧的首位0x01 p_data[PACKET_NUMBER_INDEX] = 0x00; //起始帧的第二位,即帧序号,依次向下 p_data[PACKET_CNUMBER_INDEX] = 0xff; //起始帧的第三位,帧序号取反 /* Filename written */ for (i = 0; (p_file_name != '\0')&& (i < FILE_NAME_LENGTH); i++) { p_data[i + PACKET_DATA_INDEX] =p_file_name;//从第四位开始是文件名字 } p_data[i + PACKET_DATA_INDEX] = 0x00; //在文件末名尾加0x00,表示文件名的结束 /* file size written */ Int2Str (astring, length); //转换成字符 i = i + PACKET_DATA_INDEX + 1; while (astring[j] != '\0') //加上0表示结束 { p_data[i++] = astring[j++]; } /* padding with zeros */ /* 用0填充 */ for (j = i; j < PACKET_SIZE +PACKET_DATA_INDEX; j++)//除去文件名与文件大小占用的空间,其余的都用0填充 { p_data[j] = 0; } } /** * @brief Prepare the data packet //准备的数据包,即数据帧 * @param p_source: pointer to the data to be sent //指向要发送的数据 * @param p_packet: pointer to the output buffer //指向要输出的缓冲区 * @param pkt_nr: number of the packet //包的数量 * @param size_blk: length of the block to be sent in bytes * @retval None */ static voidPreparePacket(uint8_t *p_source, uint8_t *p_packet, uint8_t pkt_nr, uint32_tsize_blk) { uint8_t *p_record; uint32_t i, size, packet_size; /* Make first three packet */ packet_size = size_blk >= PACKET_1K_SIZE ?PACKET_1K_SIZE : PACKET_SIZE; size = size_blk < packet_size ? size_blk :packet_size; if (packet_size == PACKET_1K_SIZE) //判断数据包是否为1024字节 { p_packet[PACKET_START_INDEX] = STX; //数据帧的起始0x02 } else //否则,为起始帧的起始位 { p_packet[PACKET_START_INDEX] = SOH; } p_packet[PACKET_NUMBER_INDEX] = pkt_nr; p_packet[PACKET_CNUMBER_INDEX] = (~pkt_nr); p_record = p_source; /* Filename packet has valid data */ for (i = PACKET_DATA_INDEX; i < size +PACKET_DATA_INDEX;i++) { p_packet = *p_record++; } if ( size <= packet_size) { for (i = size + PACKET_DATA_INDEX; i <packet_size + PACKET_DATA_INDEX; i++) { p_packet = 0x1A; /* EOF (0x1A) or 0x00*/ } } } /** * @brief Update CRC16 for input byte * @param crc_in input value * @param input byte * @retval None */ uint16_tUpdateCRC16(uint16_t crc_in, uint8_t byte) { uint32_t crc = crc_in; uint32_t in = byte | 0x100; do { crc <<= 1; in <<= 1; if(in & 0x100) ++crc; if(crc & 0x10000) crc ^= 0x1021; } while(!(in & 0x10000)); return crc & 0xffffu; } /** * @brief Cal CRC16 for YModem Packet * @param data * @param length * @retval None */ uint16_tCal_CRC16(const uint8_t* p_data, uint32_t size) { uint32_t crc = 0; const uint8_t* dataEnd = p_data+size; while(p_data < dataEnd) crc = UpdateCRC16(crc, *p_data++); crc = UpdateCRC16(crc, 0); crc = UpdateCRC16(crc, 0); return crc&0xffffu; } /** * @brief Calculate Check sum for YModem Packet * @param p_data Pointer to input data * @param size length of input data * @retval uint8_t checksum value */ uint8_tCalcChecksum(const uint8_t *p_data, uint32_t size) { uint32_t sum = 0; const uint8_t *p_data_end = p_data + size; while (p_data < p_data_end ) { sum += *p_data++; } return (sum & 0xffu); } /* Public functions---------------------------------------------------------*/ /** * @brief Receive a file using the ymodem protocol with CRC16. * @param p_size The size of the file. * @retval COM_StatusTypeDef result ofreception/programming */ COM_StatusTypeDefYmodem_Receive ( uint32_t *p_size ) { uint32_t i, packet_length, session_done = 0,file_done, errors = 0, session_begin = 0; uint32_t flashdestination, filesize; uint8_t *file_ptr; uint8_t file_size[FILE_SIZE_LENGTH], tmp,packets_received; COM_StatusTypeDef result = COM_OK; /* Initialize flashdestination variable */ flashdestination = APPLICATION_ADDRESS; while ((session_done == 0) && (result== COM_OK)) { packets_received = 0; file_done = 0; while ((file_done == 0) &&(result == COM_OK)) { switch (ReceivePacket(aPacketData,&packet_length, DOWNLOAD_TIMEOUT)) { case HAL_OK: printf("HAL_OK\r\n"); errors = 0; switch (packet_length) { case 2: /* Abort by sender */ printf("sendACK2\n"); Serial_PutByte(ACK); result =COM_ABORT; break; case 0: /* End of transmission */ if(EOTCN==1) { printf("EOTsendNAK\n"); Serial_PutByte(NAK); } else { printf("sendACK0\n"); Serial_PutByte(ACK); file_done =1; } break; default: /* Normal packet */ //printf("num%d\n",aPacketData[PACKET_NUMBER_INDEX]); // printf("packets_received%d\n",packets_received); if(aPacketData[PACKET_NUMBER_INDEX] != packets_received) { printf("NAK\n"); Serial_PutByte(NAK); } else { if(packets_received == 0) { /* File name packet */ if(aPacketData[PACKET_DATA_INDEX] != 0) { /* File name extraction */ i= 0; file_ptr= aPacketData + PACKET_DATA_INDEX; while( (*file_ptr != 0) && (i < FILE_NAME_LENGTH)) { aFileName[i++]= *file_ptr++; } /* File size extraction */ aFileName[i++]= '\0'; i = 0; file_ptr++; while( (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH)) { file_size[i++]= *file_ptr++; } file_size[i++]= '\0'; Str2Int(file_size,&filesize); /* Test the size of the image to besent */ /* Image size is greater than Flashsize */ if(*p_size > (USER_FLASH_SIZE + 1)) { /* End session */ tmp= CA; HAL_UART_Transmit(&huart1,&tmp, 1, NAK_TIMEOUT); HAL_UART_Transmit(&huart1,&tmp, 1, NAK_TIMEOUT); result= COM_LIMIT; } /* erase user application area */ if(SocFlashErase(APPLICATION_ADDRESS)==FLASHIF_OK) { printf("eraseok\n"); } *p_size= filesize; //printf("send ACK+C\n"); Serial_PutByte(ACK); Serial_PutByte(CRC16); } /* File header packet is empty, end session */ else { EOTCN=0; printf("sendACK3\n"); Serial_PutByte(ACK); file_done= 1; session_done= 1; break; } } else /*Data packet */ { // ramsource = (uint32_t)& aPacketData[PACKET_DATA_INDEX1]; //amsource = aPacketData[PACKET_DATA_INDEX1]; /* Write received data in Flash */ if(SocFlashWrite(flashdestination, & aPacketData[PACKET_DATA_INDEX],packet_length/4) == FLASHIF_OK) { flashdestination+= packet_length; printf("sendACK4\n"); Serial_PutByte(ACK); } else/* An error occurred while writing to Flash memory */ { /* End session */ Serial_PutByte(CA); Serial_PutByte(CA); result= COM_DATA; } } packets_received++; session_begin= 1; } break; } break; case HAL_BUSY: /* Abortactually */ Serial_PutByte(CA); Serial_PutByte(CA); result = COM_ABORT; break; default: if (session_begin > 0) { errors ++; } if (errors >MAX_ERRORS) { /*Abort communication */ Serial_PutByte(CA); Serial_PutByte(CA); } else { Serial_PutByte(CRC16);/* Ask for a packet */ } break; } } } return result; }
|