// See serial_packet.h for documentation on this function. status_t serial_packet_read(const peripheral_descriptor_t * self, uint8_t ** packet, uint32_t * packetLength, packet_type_t packetType) { if (!packet || !packetLength) { debug_printf("Error: invalid packet\r\n"); return kStatus_InvalidArgument; } *packetLength = 0; status_t status; g_serialContext.isBackToBackWrite = false; // Send ACK if needed. status = send_deferred_ack(); if (status != kStatus_Success) { return status; } framing_data_packet_t framingPacket; bool isPacketOk; do { // Clear the packet data area so unsent parameters default to zero. memset(g_serialContext.data, 0, sizeof(g_serialContext.data)); // Receive the framing data packet. isPacketOk = true; status_t status = read_data_packet(&framingPacket, g_serialContext.data, packetType); if (status != kStatus_Success) { // No packet available. *packetLength = 0; return status; } // Verify crc. uint16_t calculated_crc = calculate_framing_crc16(&framingPacket, g_serialContext.data); if (framingPacket.crc16 != calculated_crc) { debug_printf("Error: invalid crc 0x%x, expected 0x%x\r\n", framingPacket.crc16, calculated_crc); isPacketOk = false; } // Send Nak if necessary. if (!isPacketOk) { serial_packet_send_sync(kFramingPacketType_Nak); } } while (!isPacketOk); // Indicate an ACK must be sent. g_serialContext.isAckNeeded = true; // Set caller's data buffer and length *packet = g_serialContext.data; *packetLength = framingPacket.length; return kStatus_Success; }
// See serial_packet.h for documentation on this function. status_t serial_packet_write(const peripheral_descriptor_t *self, const uint8_t *packet, uint32_t byteCount, packet_type_t packetType) { if (!packet || (byteCount > kOutgoingPacketBufferSize)) { debug_printf("Error: invalid packet or packet size %d\r\n", byteCount); return kStatus_InvalidArgument; } // Send ACK if needed. status_t status = send_deferred_ack(); if (status != kStatus_Success) { return status; } // Back-to-back writes require delay for receiver to enter peripheral read routine. if (g_serialContext.isBackToBackWrite) { g_serialContext.isBackToBackWrite = false; #if defined(BOOTLOADER_HOST) host_delay(100); #endif } // Initialize the framing data packet. serial_framing_packet_t *framingPacket = &g_serialContext.framingPacket; framingPacket->dataPacket.header.startByte = kFramingPacketStartByte; framingPacket->dataPacket.header.packetType = kFramingPacketType_Command; if (packetType != kPacketType_Command) { framingPacket->dataPacket.header.packetType = kFramingPacketType_Data; } framingPacket->dataPacket.length = (uint16_t)byteCount; // Copy the caller's data buffer into the framing packet. if (byteCount) { memcpy(framingPacket->data, packet, byteCount); } // Calculate and set the framing packet crc. framingPacket->dataPacket.crc16 = calculate_framing_crc16(&framingPacket->dataPacket, (uint8_t *)framingPacket->data); #if defined(TEST_NAK) ++framingPacket->dataPacket.crc16; #endif // TEST_NAK // Send the framing data packet. status = write_data((uint8_t *)framingPacket, sizeof(framing_data_packet_t) + byteCount); if (status != kStatus_Success) { return status; } return wait_for_ack_packet(); }
//! @brief Handle a command transaction. static status_t handle_command_internal(uint8_t *packet, uint32_t packetLength) { serial_framing_packet_t framingPacket; status_t status = kStatus_Success; uint8_t *rxBuf = (uint8_t *)g_targetRxBuffer; uint8_t rxSize = 0; framing_sync_packet_t sync; // Convert to framing packet framingPacket.dataPacket.header.startByte = kFramingPacketStartByte; framingPacket.dataPacket.header.packetType = kFramingPacketType_Command; // Only read, write memory, receive SB file and flash read resource will have data command type // Will add later framingPacket.dataPacket.length = packetLength; // Copy the caller's data buffer into the framing packet. if (packetLength) { memcpy(framingPacket.data, packet, packetLength); } framingPacket.dataPacket.crc16 = calculate_framing_crc16(&framingPacket.dataPacket, (uint8_t *)framingPacket.data); // send framing packet to target peripheral if (peripheral_write((uint8_t *)&framingPacket, sizeof(framing_data_packet_t) + framingPacket.dataPacket.length) != kStatus_Success) { status = kStatus_Fail; } else // recering ACK from target peripheral { uint8_t count = 32; do { if (peripheral_read((uint8_t *)&sync.header.startByte, 1) != kStatus_Success) { status = kStatus_Fail; break; } else { if (sync.header.startByte == kFramingPacketStartByte) { if (peripheral_read((uint8_t *)&sync.header.packetType, 1) != kStatus_Success) { status = kStatus_Fail; } else if (sync.header.packetType != kFramingPacketType_Ack) { status = kStatus_Fail; } else { // receiving framing paket header if (peripheral_read(rxBuf, sizeof(framing_data_packet_t)) != kStatus_Success) { status = kStatus_Fail; } else { rxSize = ((framing_data_packet_t *)rxBuf)->length; if (peripheral_read(rxBuf + sizeof(framing_data_packet_t), rxSize) != kStatus_Success) { status = kStatus_Fail; sync.header.packetType = kFramingPacketType_Nak; } else { sync.header.packetType = kFramingPacketType_Ack; } // send Ack/Nak back to peripheral peripheral_write((uint8_t *)&sync, sizeof(framing_sync_packet_t)); } } break; } } } while (count-- != 0); // really good?? } if (status == kStatus_Success) { status = usb_hid_packet_write(&g_peripherals[0], rxBuf + sizeof(framing_data_packet_t), rxSize, kPacketType_Command); } return status; }
static status_t handle_data_write(bool *hasMoreData) { serial_framing_packet_t framingPacket; if (g_commandData.dataPhase.count == 0) { // No data phase. *hasMoreData = false; finalize_data_phase(kStatus_Success); return kStatus_Success; } *hasMoreData = true; uint32_t remaining = g_commandData.dataPhase.count; uint32_t dataAddress = g_commandData.dataPhase.address; uint8_t *packet; uint32_t packetLength = 0; status_t status; framing_sync_packet_t sync; // read data packet status = usb_hid_packet_read(&g_peripherals[0], &packet, &packetLength, kPacketType_Data); if (status != kStatus_Success) { // Abort data phase due to error. debug_printf("consumer abort data phase due to status 0x%x\r\n", status); // g_packetInterface->abortDataPhase(0); finalize_data_phase(status); *hasMoreData = false; return kStatus_Success; } if (packetLength == 0) { // Sender requested data phase abort. debug_printf("Data phase aborted by sender\r\n"); // finalize_data_phase(kStatus_AbortDataPhase); finalize_data_phase(kStatus_Success); *hasMoreData = false; return kStatus_Success; } packetLength = MIN(packetLength, remaining); // Convert to framing packet framingPacket.dataPacket.header.startByte = kFramingPacketStartByte; framingPacket.dataPacket.header.packetType = kFramingPacketType_Data; framingPacket.dataPacket.length = packetLength; // Copy the caller's data buffer into the framing packet. if (packetLength) { memcpy(framingPacket.data, packet, packetLength); } framingPacket.dataPacket.crc16 = calculate_framing_crc16(&framingPacket.dataPacket, (uint8_t *)framingPacket.data); // send framing packet to target peripheral if (peripheral_write((uint8_t *)&framingPacket, sizeof(framing_data_packet_t) + framingPacket.dataPacket.length) != kStatus_Success) { status = kStatus_Fail; } // recering ACK from target peripheral else { uint8_t count = 32; do { if (peripheral_read((uint8_t *)&sync.header, 2) != kStatus_Success) { status = kStatus_Fail; } else { if ((sync.header.startByte != kFramingPacketStartByte) && (sync.header.packetType != kFramingPacketType_Ack)) { status = kStatus_Fail; } break; } } while ((sync.header.startByte != kFramingPacketStartByte) && (count-- != 0)); // } dataAddress += packetLength; remaining -= packetLength; if (remaining == 0) { finalize_data_phase(status); *hasMoreData = false; } else if (status != kStatus_Success) { debug_printf("writePacket aborted due to status 0x%x\r\n", status); finalize_data_phase(status); *hasMoreData = false; } else { g_commandData.dataPhase.count = remaining; g_commandData.dataPhase.address = dataAddress; } return kStatus_Success; }