/* * downstream_interface_msc.c * * Created on: 4/07/2015 * Author: Robert Fisk */ #include "stm32f4xx_hal.h" #include "downstream_interface_msc.h" #include "downstream_interface_def.h" #include "downstream_spi.h" //Stuff we need to save for our callbacks to use: DownstreamInterfaceMSCCallbackTypeDef TestReadyCallback; DownstreamInterfaceMSCCallbackUintPacketTypeDef GetCapacityCallback; DownstreamInterfaceMSCCallbackPacketTypeDef GetStreamDataCallback; uint64_t BlockStart; uint32_t BlockCount; uint32_t ByteCount; DownstreamPacketTypeDef* ReadStreamPacket; uint8_t ReadStreamBusy; static void DownstreamInterface_TestReadyReplyCallback(DownstreamPacketTypeDef* replyPacket); static void DownstreamInterface_GetCapacityReplyCallback(DownstreamPacketTypeDef* replyPacket); static void DownstreamInterface_GetStreamDataPacketCallback(DownstreamPacketTypeDef* replyPacket); static void DownstreamInterface_BeginWriteReplyCallback(DownstreamPacketTypeDef* replyPacket); HAL_StatusTypeDef DownstreamInterface_TestReady(DownstreamInterfaceMSCCallbackTypeDef callback) { DownstreamPacketTypeDef* freePacket; HAL_StatusTypeDef tempResult; TestReadyCallback = callback; freePacket = Downstream_GetFreePacketImmediately(); freePacket->Length = DOWNSTREAM_PACKET_HEADER_LEN; freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE; freePacket->Command = COMMAND_MSC_TEST_UNIT_READY; tempResult = Downstream_SendPacket(freePacket); if (tempResult != HAL_OK) { return tempResult; } return Downstream_GetPacket(DownstreamInterface_TestReadyReplyCallback); } void DownstreamInterface_TestReadyReplyCallback(DownstreamPacketTypeDef* replyPacket) { if ((replyPacket->Length != (DOWNSTREAM_PACKET_HEADER_LEN + 1)) || (replyPacket->CommandClass & COMMAND_CLASS_DATA_FLAG) || (replyPacket->Data[0] != HAL_OK)) { Downstream_ReleasePacket(replyPacket); TestReadyCallback(HAL_ERROR); return; } Downstream_ReleasePacket(replyPacket); TestReadyCallback(HAL_OK); } HAL_StatusTypeDef DownstreamInterface_GetCapacity(DownstreamInterfaceMSCCallbackUintPacketTypeDef callback) { DownstreamPacketTypeDef* freePacket; HAL_StatusTypeDef tempResult; GetCapacityCallback = callback; freePacket = Downstream_GetFreePacketImmediately(); freePacket->Length = DOWNSTREAM_PACKET_HEADER_LEN; freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE; freePacket->Command = COMMAND_MSC_GET_CAPACITY; tempResult = Downstream_SendPacket(freePacket); if (tempResult != HAL_OK) { return tempResult; } return Downstream_GetPacket(DownstreamInterface_GetCapacityReplyCallback); } void DownstreamInterface_GetCapacityReplyCallback(DownstreamPacketTypeDef* replyPacket) { uint32_t uint[2]; if ((replyPacket->Length != (DOWNSTREAM_PACKET_HEADER_LEN + 8) || (replyPacket->CommandClass & COMMAND_CLASS_DATA_FLAG))) { GetCapacityCallback(HAL_ERROR, NULL, NULL); return; } uint[0] = *(uint32_t*)&(replyPacket->Data[0]); uint[1] = *(uint32_t*)&(replyPacket->Data[4]); GetCapacityCallback(HAL_OK, uint, replyPacket); //usb_msc_scsi will use this packet, so don't release now } HAL_StatusTypeDef DownstreamInterface_BeginRead(DownstreamInterfaceMSCCallbackTypeDef callback, uint64_t readBlockStart, uint32_t readBlockCount, uint32_t readByteCount) { DownstreamPacketTypeDef* freePacket; HAL_StatusTypeDef tempResult; ReadStreamPacket = NULL; //Prepare for GetStreamDataPacket's use ReadStreamBusy = 0; TestReadyCallback = callback; BlockStart = readBlockStart; BlockCount = readBlockCount; ByteCount = readByteCount; freePacket = Downstream_GetFreePacketImmediately(); freePacket->Length = DOWNSTREAM_PACKET_HEADER_LEN + (4 * 3); freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE; freePacket->Command = COMMAND_MSC_BEGIN_READ; *(uint64_t*)&(freePacket->Data[0]) = BlockStart; *(uint32_t*)&(freePacket->Data[8]) = BlockCount; tempResult = Downstream_SendPacket(freePacket); if (tempResult != HAL_OK) { TestReadyCallback(tempResult); } return Downstream_GetPacket(DownstreamInterface_TestReadyReplyCallback); //Re-use TestReadyReplyCallback because it does exactly what we want! } HAL_StatusTypeDef DownstreamInterface_GetStreamDataPacket(DownstreamInterfaceMSCCallbackPacketTypeDef callback) { GetStreamDataCallback = callback; if (ReadStreamBusy != 0) { return HAL_OK; } ReadStreamBusy = 1; if (ReadStreamPacket && GetStreamDataCallback) //Do we have a stored packet and an address to send it? { DownstreamInterface_GetStreamDataPacketCallback(ReadStreamPacket); //Send it now! ReadStreamPacket = NULL; return HAL_OK; //Our callback will call us again, so we don't need to get a packet in this case. } return Downstream_GetPacket(DownstreamInterface_GetStreamDataPacketCallback); } void DownstreamInterface_GetStreamDataPacketCallback(DownstreamPacketTypeDef* replyPacket) { uint16_t dataLength; ReadStreamBusy = 0; if (GetStreamDataCallback == NULL) { ReadStreamPacket = replyPacket; //We used up our callback already, so save this one for later. return; } if (((replyPacket->CommandClass & COMMAND_CLASS_DATA_FLAG) == 0) || //Any 'command' reply (as opposed to 'data' reply) is an automatic fail here (replyPacket->Length <= DOWNSTREAM_PACKET_HEADER_LEN) || //Should be at least one data byte in the reply. (replyPacket->Length > ByteCount)) { GetStreamDataCallback(HAL_ERROR, NULL); return; } dataLength = replyPacket->Length - DOWNSTREAM_PACKET_HEADER_LEN; ByteCount -= dataLength; GetStreamDataCallback(HAL_OK, replyPacket, dataLength); //usb_msc_scsi will use this packet, so don't release now if (ByteCount > 0) { DownstreamInterface_GetStreamDataPacket(NULL); //Try to get the next packet now, before USB asks for it } } HAL_StatusTypeDef DownstreamInterface_BeginWrite(DownstreamInterfaceMSCCallbackTypeDef callback, uint64_t readBlockStart, uint32_t readBlockCount) { DownstreamPacketTypeDef* freePacket; HAL_StatusTypeDef tempResult; TestReadyCallback = callback; BlockStart = readBlockStart; BlockCount = readBlockCount; freePacket = Downstream_GetFreePacketImmediately(); freePacket->Length = DOWNSTREAM_PACKET_HEADER_LEN + (4 * 3); freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE; freePacket->Command = COMMAND_MSC_BEGIN_WRITE; *(uint64_t*)&(freePacket->Data[0]) = BlockStart; *(uint32_t*)&(freePacket->Data[8]) = BlockCount; tempResult = Downstream_SendPacket(freePacket); if (tempResult != HAL_OK) { TestReadyCallback(tempResult); } return Downstream_GetPacket(DownstreamInterface_BeginWriteReplyCallback); } void DownstreamInterface_BeginWriteReplyCallback(DownstreamPacketTypeDef* replyPacket) { if ((replyPacket->Length != (DOWNSTREAM_PACKET_HEADER_LEN + 1)) || (replyPacket->CommandClass & COMMAND_CLASS_DATA_FLAG) || ((replyPacket->Data[0] != HAL_OK) && (replyPacket->Data[0] != HAL_BUSY))) { Downstream_ReleasePacket(replyPacket); TestReadyCallback(HAL_ERROR); return; } Downstream_ReleasePacket(replyPacket); TestReadyCallback(replyPacket->Data[0]); } HAL_StatusTypeDef DownstreamInterface_PutStreamDataPacket(DownstreamPacketTypeDef* packetToSend, uint32_t dataLength) { packetToSend->Length = dataLength + DOWNSTREAM_PACKET_HEADER_LEN; packetToSend->CommandClass = COMMAND_CLASS_MASS_STORAGE | COMMAND_CLASS_DATA_FLAG; packetToSend->Command = COMMAND_MSC_BEGIN_WRITE; return Downstream_SendPacket(packetToSend); }