//---------------------------------------------------------------------------------------------- static void Ymodem_PrepareIntialPacket(uint8_t *data, const uint8_t* fileName, uint32_t *length) { uint16_t i, j; uint8_t file_ptr[10]; uint16_t tempCRC; // Make first three packet data[0] = SOH; data[1] = 0x00; data[2] = 0xff; // Filename packet has valid data for (i = 0; (fileName[i] != '\0') && (i <SPIFFS_OBJ_NAME_LEN);i++) { data[i + PACKET_HEADER] = fileName[i]; } data[i + PACKET_HEADER] = 0x00; Int2Str (file_ptr, *length); for (j =0, i = i + PACKET_HEADER + 1; file_ptr[j] != '\0' ; ) { data[i++] = file_ptr[j++]; } data[i++] = 0x20; for (j = i; j < PACKET_SIZE + PACKET_HEADER; j++) { data[j] = 0; } tempCRC = Cal_CRC16(&data[PACKET_HEADER], PACKET_SIZE); data[PACKET_SIZE + PACKET_HEADER] = tempCRC >> 8; data[PACKET_SIZE + PACKET_HEADER + 1] = tempCRC & 0xFF; }
/** * @brief Transmit a file using the ymodem protocol * @param buf: Address of the first byte * @retval The size of the file */ uint8_t Ymodem_Transmit (uint8_t *buf, const uint8_t* sendFileName, uint32_t sizeFile) { uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD]; uint8_t filename[FILE_NAME_LENGTH]; uint8_t *buf_ptr, tempCheckSum; uint16_t tempCRC; uint16_t blkNumber; uint8_t receivedC[2], CRC16_F = 0, i; uint32_t errors, ackReceived, size = 0, pktSize; errors = 0; ackReceived = 0; for (i = 0; i < (FILE_NAME_LENGTH - 1); i++) { filename[i] = sendFileName[i]; } CRC16_F = 1; /* Prepare first block */ Ymodem_PrepareIntialPacket(&packet_data[0], filename, &sizeFile); do { /* Send Packet */ Ymodem_SendPacket(packet_data, PACKET_SIZE + PACKET_HEADER); /* Send CRC or Check Sum based on CRC16_F */ if (CRC16_F) { tempCRC = Cal_CRC16(&packet_data[3], PACKET_SIZE); Send_Byte(tempCRC >> 8); Send_Byte(tempCRC & 0xFF); } else { tempCheckSum = CalChecksum (&packet_data[3], PACKET_SIZE); Send_Byte(tempCheckSum); } /* Wait for Ack and 'C' */ if (Receive_Byte(&receivedC[0], 10000) == 0) { if (receivedC[0] == ACK) { /* Packet transferred correctly */ ackReceived = 1; } } else { errors++; } } while (!ackReceived && (errors < 0x0A));
/******************************************************************************* * @函数名称 Ymodem_Transmit * @函数说明 通过ymodem协议传输一个文件 * @输入参数 buf :数据地址指针 sendFileName :文件名 sizeFile:文件长度 * @输出参数 无 * @返回参数 是否成功 0:成功 *******************************************************************************/ uint8_t Ymodem_Transmit (uint8_t *buf, const uint8_t* sendFileName, uint32_t sizeFile) { uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD]; uint8_t FileName[FILE_NAME_LENGTH]; uint8_t *buf_ptr, tempCheckSum ; uint16_t tempCRC, blkNumber; uint8_t receivedC[2], CRC16_F = 0, i; uint32_t errors, ackReceived, size = 0, pktSize; errors = 0; ackReceived = 0; for (i = 0; i < (FILE_NAME_LENGTH - 1); i++) { FileName[i] = sendFileName[i]; } CRC16_F = 1; //准备第一个数据包 Ymodem_PrepareIntialPacket(&packet_data[0], FileName, &sizeFile); do { //发送数据包 Ymodem_SendPacket(packet_data, PACKET_SIZE + PACKET_HEADER); //发送CRC校验 if (CRC16_F) { tempCRC = Cal_CRC16(&packet_data[3], PACKET_SIZE); Send_Byte(tempCRC >> 8); Send_Byte(tempCRC & 0xFF); } else { tempCheckSum = CalChecksum (&packet_data[3], PACKET_SIZE); Send_Byte(tempCheckSum); } //等待响应 if (Receive_Byte(&receivedC[0], 10000) == 0) { if (receivedC[0] == ACK) { //数据包正确传输 ackReceived = 1; } } else { errors++; } } while (!ackReceived && (errors < 0x0A));
//------------------------------------------------- static void Ymodem_PrepareLastPacket(uint8_t *data) { uint16_t i; uint16_t tempCRC; data[0] = SOH; data[1] = 0x00; data[2] = 0xff; for (i = PACKET_HEADER; i < (PACKET_SIZE + PACKET_HEADER); i++) { data[i] = 0x00; } tempCRC = Cal_CRC16(&data[PACKET_HEADER], PACKET_SIZE); data[PACKET_SIZE + PACKET_HEADER] = tempCRC >> 8; data[PACKET_SIZE + PACKET_HEADER + 1] = tempCRC & 0xFF; }
//------------------------------------------------------------------------------ static void Ymodem_PreparePacket(uint8_t *data, uint8_t pktNo, uint32_t sizeBlk) { uint16_t i, size; uint16_t tempCRC; data[0] = STX; data[1] = pktNo; data[2] = (~pktNo); size = sizeBlk < PACKET_1K_SIZE ? sizeBlk :PACKET_1K_SIZE; // Read block from file if (size > 0) SPIFFS_read(&fs, (spiffs_file)file_fd, data + PACKET_HEADER, size); if ( size <= PACKET_1K_SIZE) { for (i = size + PACKET_HEADER; i < PACKET_1K_SIZE + PACKET_HEADER; i++) { data[i] = 0x1A; // EOF (0x1A) or 0x00 } } tempCRC = Cal_CRC16(&data[PACKET_HEADER], PACKET_1K_SIZE); data[PACKET_1K_SIZE + PACKET_HEADER] = tempCRC >> 8; data[PACKET_1K_SIZE + PACKET_HEADER + 1] = tempCRC & 0xFF; }
/** * @brief Receive a packet from sender * @param data * @param length * 0: end of transmission * 2: abort by sender * >0: packet length * @param timeout * @retval HAL_OK: normally return * HAL_BUSY: abort by user */ 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(&UartHandle, &char1, 1, RX_TIMEOUT); if (status == HAL_OK) { switch (char1) { case SOH: packet_size = PACKET_SIZE; break; case STX: packet_size = PACKET_1K_SIZE; break; case EOT: break; case CA: if ((HAL_UART_Receive(&UartHandle, &char1, 1, timeout) == HAL_OK) && (char1 == CA)) { packet_size = 2; } else { status = HAL_ERROR; } break; case ABORT1: case ABORT2: status = HAL_BUSY; break; default: status = HAL_ERROR; break; } *p_data = char1; if (packet_size >= PACKET_SIZE ) { status = HAL_UART_Receive(&UartHandle, &p_data[PACKET_NUMBER_INDEX], packet_size + PACKET_OVERHEAD_SIZE, timeout); /* Simple packet sanity check */ if (status == HAL_OK ) { if (p_data[PACKET_NUMBER_INDEX] != ((p_data[PACKET_CNUMBER_INDEX]) ^ NEGATIVE_BYTE)) { packet_size = 0; status = HAL_ERROR; } else { /* 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 ) { packet_size = 0; status = HAL_ERROR; } } } else { packet_size = 0; } } } *p_length = packet_size; return status; }
/** * @brief Transmit a file using the ymodem protocol * @param p_buf: Address of the first byte * @param p_file_name: Name of the file sent * @param file_size: Size of the transmission * @retval COM_StatusTypeDef result of the communication */ COM_StatusTypeDef Ymodem_Transmit (uint8_t *p_buf, const uint8_t *p_file_name, uint32_t file_size) { uint32_t errors = 0, ack_recpt = 0, size = 0, pkt_size; uint8_t *p_buf_int; COM_StatusTypeDef result = COM_OK; uint32_t blk_number = 1; uint8_t a_rx_ctrl[2]; uint8_t i; #ifdef CRC16_F uint32_t temp_crc; #else /* CRC16_F */ uint8_t temp_chksum; #endif /* CRC16_F */ /* Prepare first block - header */ PrepareIntialPacket(aPacketData, p_file_name, file_size); while (( !ack_recpt ) && ( result == COM_OK )) { /* Send Packet */ HAL_UART_Transmit(&UartHandle, &aPacketData[PACKET_START_INDEX], PACKET_SIZE + PACKET_HEADER_SIZE, NAK_TIMEOUT); /* Send CRC or Check Sum based on CRC16_F */ #ifdef CRC16_F temp_crc = Cal_CRC16(&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE); Serial_PutByte(temp_crc >> 8); Serial_PutByte(temp_crc & 0xFF); #else /* CRC16_F */ temp_chksum = CalcChecksum (&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE); Serial_PutByte(temp_chksum); #endif /* CRC16_F */ /* Wait for Ack and 'C' */ if (HAL_UART_Receive(&UartHandle, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) { if (a_rx_ctrl[0] == ACK) { ack_recpt = 1; } else if (a_rx_ctrl[0] == CA) { if ((HAL_UART_Receive(&UartHandle, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) && (a_rx_ctrl[0] == CA)) { HAL_Delay( 2 ); __HAL_UART_FLUSH_DRREGISTER(&UartHandle); result = COM_ABORT; } } } else { errors++; } if (errors >= MAX_ERRORS) { result = COM_ERROR; } } p_buf_int = p_buf; size = file_size; /* Here 1024 bytes length is used to send the packets */ while ((size) && (result == COM_OK )) { /* Prepare next packet */ PreparePacket(p_buf_int, aPacketData, blk_number, size); ack_recpt = 0; a_rx_ctrl[0] = 0; errors = 0; /* Resend packet if NAK for few times else end of communication */ while (( !ack_recpt ) && ( result == COM_OK )) { /* Send next packet */ if (size >= PACKET_1K_SIZE) { pkt_size = PACKET_1K_SIZE; } else { pkt_size = PACKET_SIZE; } HAL_UART_Transmit(&UartHandle, &aPacketData[PACKET_START_INDEX], pkt_size + PACKET_HEADER_SIZE, NAK_TIMEOUT); /* Send CRC or Check Sum based on CRC16_F */ #ifdef CRC16_F temp_crc = Cal_CRC16(&aPacketData[PACKET_DATA_INDEX], pkt_size); Serial_PutByte(temp_crc >> 8); Serial_PutByte(temp_crc & 0xFF); #else /* CRC16_F */ temp_chksum = CalcChecksum (&aPacketData[PACKET_DATA_INDEX], pkt_size); Serial_PutByte(temp_chksum); #endif /* CRC16_F */ /* Wait for Ack */ if ((HAL_UART_Receive(&UartHandle, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) && (a_rx_ctrl[0] == ACK)) { ack_recpt = 1; if (size > pkt_size) { p_buf_int += pkt_size; size -= pkt_size; if (blk_number == (USER_FLASH_SIZE / PACKET_1K_SIZE)) { result = COM_LIMIT; /* boundary error */ } else { blk_number++; } } else { p_buf_int += pkt_size; size = 0; } } else { errors++; } /* Resend packet if NAK for a count of 10 else end of communication */ if (errors >= MAX_ERRORS) { result = COM_ERROR; } } } /* Sending End Of Transmission char */ ack_recpt = 0; a_rx_ctrl[0] = 0x00; errors = 0; while (( !ack_recpt ) && ( result == COM_OK )) { Serial_PutByte(EOT); /* Wait for Ack */ if (HAL_UART_Receive(&UartHandle, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) { if (a_rx_ctrl[0] == ACK) { ack_recpt = 1; } else if (a_rx_ctrl[0] == CA) { if ((HAL_UART_Receive(&UartHandle, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) && (a_rx_ctrl[0] == CA)) { HAL_Delay( 2 ); __HAL_UART_FLUSH_DRREGISTER(&UartHandle); result = COM_ABORT; } } } else { errors++; } if (errors >= MAX_ERRORS) { result = COM_ERROR; } } /* Empty packet sent - some terminal emulators need this to close session */ if ( result == COM_OK ) { /* Preparing an empty packet */ aPacketData[PACKET_START_INDEX] = SOH; aPacketData[PACKET_NUMBER_INDEX] = 0; aPacketData[PACKET_CNUMBER_INDEX] = 0xFF; for (i = PACKET_DATA_INDEX; i < (PACKET_SIZE + PACKET_DATA_INDEX); i++) { aPacketData [i] = 0x00; } /* Send Packet */ HAL_UART_Transmit(&UartHandle, &aPacketData[PACKET_START_INDEX], PACKET_SIZE + PACKET_HEADER_SIZE, NAK_TIMEOUT); /* Send CRC or Check Sum based on CRC16_F */ #ifdef CRC16_F temp_crc = Cal_CRC16(&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE); Serial_PutByte(temp_crc >> 8); Serial_PutByte(temp_crc & 0xFF); #else /* CRC16_F */ temp_chksum = CalcChecksum (&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE); Serial_PutByte(temp_chksum); #endif /* CRC16_F */ /* Wait for Ack and 'C' */ if (HAL_UART_Receive(&UartHandle, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) { if (a_rx_ctrl[0] == CA) { HAL_Delay( 2 ); __HAL_UART_FLUSH_DRREGISTER(&UartHandle); result = COM_ABORT; } } }
/** * @brief Receive a packet from sender * @param data * @param length * @param timeout * 0: end of transmission * -1: abort by sender * >0: packet length * @retval 0: normally return * -1: timeout or packet error * 1: abort by user */ static int32_t Receive_Packet (uint8_t *data, int32_t *length, uint32_t timeout) { uint16_t i, packet_size, computedcrc; uint8_t c; *length = 0; if (Receive_Byte(&c, timeout) != 0) { return -1; } switch (c) { case SOH: packet_size = PACKET_SIZE; break; case STX: packet_size = PACKET_1K_SIZE; break; case EOT: return 0; case CA: if ((Receive_Byte(&c, timeout) == 0) && (c == CA)) { *length = -1; return 0; } else { return -1; } case ABORT1: case ABORT2: return 1; default: return -1; } *data = c; for (i = 1; i < (packet_size + PACKET_OVERHEAD); i ++) { if (Receive_Byte(data + i, timeout) != 0) { return -1; } } if (data[PACKET_SEQNO_INDEX] != ((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff)) { return -1; } /* Compute the CRC */ computedcrc = Cal_CRC16(&data[PACKET_HEADER], (uint32_t)packet_size); /* Check that received CRC match the already computed CRC value data[packet_size+3]<<8) | data[packet_size+4] contains the received CRC computedcrc contains the computed CRC value */ if (computedcrc != (uint16_t)((data[packet_size+3]<<8) | data[packet_size+4])) { /* CRC error */ return -1; } *length = packet_size; return 0; }
/* 接收一包数据 参数分别为 数据缓存 一包长度 超时时间 */ int32_t Receive_Packet (uint8_t *data, int32_t *length, uint32_t timeout) { uint16_t i, packet_size; //一包数据长度 uint8_t c; //接收一个字符的临时保存变量 crcvalue = 0; *length = 0; if (Receive_Byte(&c, timeout) != 0) { return -1; //如果在规定时间 没有字符传过来 就直接退出该函数 } //如果接收到一个字符了 说明收到一个串口命令 判断是什么命令 switch (c) { case 0x01://设置包长度为128字节命令 /* start of 128-byte data packet */ packet_size=128; break; // case 0x02://设置包长度为1024字节命令 /* start of 1024-byte data packet */ // packet_size=1024; // break; case 0x04:// 传输结束命令 /* end of transmission */ __NOP(); return 0; // break; case 0x18://传输成功后的结束命令 /* two of these in succession aborts transfer */ if ((Receive_Byte(&c, timeout) == 0) && (c == 0x18)) //接收到一个字符 并且收到结束命令 { *length = -1;//长度 return 0; //正常退出 } else { return -1; // 异常退出 } case 0x41: /* 'A' == 0x41, abort by user */ case 0x61: /* 'a' == 0x61, abort by user */ return 1; default: return -1; } *data = c; //保存收到的字符c for (i=1; i<(packet_size + 5); i ++) /* 接收一包的数据 (包括数据包头的3 + 数据包尾2) */ { if (Receive_Byte(data + i, timeout) != 0) /* 数据保存在data数组中 */ { return -1; } } //包头校验 if (data[1] != ((data[2] ^ 0xff) & 0xff)) //data[1] 中的数据必须等于data[2] 中的数据取反 { return -1; } //CRC校验 crcvalue = (data[132] | (data[131]<<8)); if (Cal_CRC16(&data[3], 128) != crcvalue) /* 将data数组中,其中128个纯数据取出做CRC校验 */ { return -1; //如果校验失败,则终止接收 } *length = packet_size; return 0; }