/* * downstream_statemachine.c * * Created on: 2/08/2015 * Author: Robert Fisk */ #include "downstream_statemachine.h" #include "downstream_interface_def.h" #include "downstream_spi.h" #include "downstream_msc.h" #include "usbh_core.h" #include "usbh_msc.h" DownstreamStateTypeDef DownstreamState; InterfaceCommandClassTypeDef ConfiguredDeviceClass; void Downstream_PacketProcessor(DownstreamPacketTypeDef* receivedPacket); void Downstream_PacketProcessor_Interface(DownstreamPacketTypeDef* receivedPacket); void Downstream_PacketProcessor_Interface_ReplyNotifyDevice(DownstreamPacketTypeDef* replyPacket); void Downstream_InitStateMachine(void) { DownstreamState = STATE_DEVICE_NOT_READY; ConfiguredDeviceClass = COMMAND_CLASS_INTERFACE; Downstream_InitSPI(); //Prepare to receive our first packet from Upstream! Downstream_ReceivePacket(Downstream_PacketProcessor); } void Downstream_PacketProcessor(DownstreamPacketTypeDef* receivedPacket) { switch (receivedPacket->CommandClass) { case COMMAND_CLASS_INTERFACE: if (DownstreamState > STATE_DEVICE_READY) { SPI_INTERFACE_FREAKOUT_RETURN_VOID; } Downstream_PacketProcessor_Interface(receivedPacket); break; case COMMAND_CLASS_MASS_STORAGE: if (DownstreamState != STATE_ACTIVE) { Downstream_PacketProcessor_ErrorReply(receivedPacket); return; } Downstream_MSC_PacketProcessor(receivedPacket); break; //Add other classes here... default: Downstream_PacketProcessor_ErrorReply(receivedPacket); } } void Downstream_PacketProcessor_Interface(DownstreamPacketTypeDef* receivedPacket) { switch (receivedPacket->Command) { case COMMAND_INTERFACE_ECHO: Downstream_TransmitPacket(receivedPacket); Downstream_ReceivePacket(Downstream_PacketProcessor); return; case COMMAND_INTERFACE_NOTIFY_DEVICE: if (DownstreamState == STATE_DEVICE_READY) { Downstream_PacketProcessor_Interface_ReplyNotifyDevice(receivedPacket); return; } if (DownstreamState == STATE_DEVICE_NOT_READY) { DownstreamState = STATE_WAIT_DEVICE_READY; Downstream_ReleasePacket(receivedPacket); return; } Downstream_PacketProcessor_ErrorReply(receivedPacket); return; default: Downstream_PacketProcessor_ErrorReply(receivedPacket); } } void Downstream_PacketProcessor_Interface_ReplyNotifyDevice(DownstreamPacketTypeDef* replyPacket) { replyPacket->Length = DOWNSTREAM_PACKET_HEADER_LEN + 1; replyPacket->CommandClass = COMMAND_CLASS_INTERFACE; replyPacket->Command = COMMAND_INTERFACE_NOTIFY_DEVICE; replyPacket->Data[0] = ConfiguredDeviceClass; Downstream_TransmitPacket(replyPacket); DownstreamState = STATE_ACTIVE; Downstream_ReceivePacket(Downstream_PacketProcessor); } void Downstream_PacketProcessor_ErrorReply(DownstreamPacketTypeDef* replyPacket) { replyPacket->Length = DOWNSTREAM_PACKET_HEADER_LEN; replyPacket->CommandClass = COMMAND_CLASS_ERROR; Downstream_TransmitPacket(replyPacket); Downstream_ReceivePacket(Downstream_PacketProcessor); } void Downstream_PacketProcessor_ClassReply(DownstreamPacketTypeDef* replyPacket) { Downstream_TransmitPacket(replyPacket); Downstream_ReceivePacket(Downstream_PacketProcessor); } //This callback receives various event ids from the host stack, either //at INT_PRIORITY_OTG_FS or from main(). We should therefore be prepared //for pre-emption by USB or SPI/DMA interrupts. void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id) { InterfaceCommandClassTypeDef newActiveClass = COMMAND_CLASS_INTERFACE; //Called from USB interrupt if (id == HOST_USER_DISCONNECTION) { DownstreamState = STATE_DEVICE_NOT_READY; return; } //Called from main(). Beware pre-emption! if (id == HOST_USER_CLASS_ACTIVE) { switch (phost->pActiveClass->ClassCode) { case USB_MSC_CLASS: if (Downstream_MSC_ApproveConnectedDevice() == HAL_OK) { newActiveClass = COMMAND_CLASS_MASS_STORAGE; } break; //Add other classes here... } //To change device class, we must reboot. if ((ConfiguredDeviceClass != COMMAND_CLASS_INTERFACE) && (ConfiguredDeviceClass != newActiveClass)) { SPI_INTERFACE_FREAKOUT_NO_RETURN; DownstreamState = STATE_ERROR; return; } if (newActiveClass == COMMAND_CLASS_INTERFACE) { return; } ConfiguredDeviceClass = newActiveClass; if (DownstreamState == STATE_WAIT_DEVICE_READY) { Downstream_GetFreePacket(Downstream_PacketProcessor_Interface_ReplyNotifyDevice); return; } if (DownstreamState == STATE_DEVICE_NOT_READY) { DownstreamState = STATE_DEVICE_READY; return; } SPI_INTERFACE_FREAKOUT_NO_RETURN; DownstreamState = STATE_ERROR; return; } }