单片机一直向上位机发送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_OBJECT public: 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<PackNumber;i++) { PackIndex++; qDebug()<<"PackIndex="<<PackIndex; 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()<<"PackCnt="<<PackCnt; 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 #define PACKET_HEADER_SIZE ((uint32_t)3) #define PACKET_DATA_INDEX ((uint32_t)4) #define PACKET_START_INDEX ((uint32_t)1) #define PACKET_NUMBER_INDEX ((uint32_t)2) #define PACKET_CNUMBER_INDEX ((uint32_t)3) #define PACKET_TRAILER_SIZE ((uint32_t)2) #define PACKET_OVERHEAD_SIZE (PACKET_HEADER_SIZE + PACKET_TRAILER_SIZE - 1) #define PACKET_SIZE ((uint32_t)128) #define PACKET_1K_SIZE ((uint32_t)1024) #define FILE_NAME_LENGTH ((uint32_t)64) #define FILE_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) /* two of these in succession aborts transfer */ #define CRC16 ((uint8_t)0x43) /* 'C' == 0x43, request 16-bit CRC */ #define NEGATIVE_BYTE ((uint8_t)0xFF)
#define ABORT1 ((uint8_t)0x41) /* 'A' == 0x41, abort by user */ #define ABORT2 ((uint8_t)0x61) /* 'a' == 0x61, abort by user */
#define NAK_TIMEOUT ((uint32_t)0x100000) #define DOWNLOAD_TIMEOUT ((uint32_t)1000) /* One second retry delay */ #define MAX_ERRORS ((uint32_t)5) Ymodem.c
HAL_StatusTypeDef Serial_PutByte( uint8_t param ) { return HAL_UART_Transmit(&huart1, ¶m, 1, TX_TIMEOUT);
}
static HAL_StatusTypeDef ReceivePacket(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; 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 void PrepareIntialPacket(uint8_t *p_data, const uint8_t *p_file_name, uint32_t length) { 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; } }
static void PreparePacket(uint8_t *p_source, uint8_t *p_packet, uint8_t pkt_nr, uint32_t size_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_t UpdateCRC16(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_t Cal_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_t CalcChecksum(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 of reception/programming */ COM_StatusTypeDef Ymodem_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("send ACK2\n"); Serial_PutByte(ACK); result = COM_ABORT; break; case 0: /* End of transmission */ if(EOTCN==1) { printf("EOTsend NAK\n"); Serial_PutByte(NAK); } else { printf("send ACK0\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 be sent */ /* Image size is greater than Flash size */ 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("erase ok\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("send ACK3\n"); Serial_PutByte(ACK); file_done = 1; session_done = 1; break; } } else /* Data packet */ { /* Write received data in Flash */ if (SocFlashWrite(flashdestination, & aPacketData[PACKET_DATA_INDEX], packet_length/4) == FLASHIF_OK) { flashdestination += packet_length; printf("send ACK4\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: /* Abort actually */ 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; }
|