/* * upstream_statemachine.c * * Created on: 20/08/2015 * Author: Robert Fisk * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "upstream_statemachine.h" #include "upstream_spi.h" #include "upstream_interface_def.h" #include "usb_device.h" #include "usbd_core.h" #include "usbd_msc.h" UpstreamStateTypeDef UpstreamState = STATE_TEST_INTERFACE; InterfaceCommandClassTypeDef ConfiguredDeviceClass = COMMAND_CLASS_INTERFACE; void Upstream_StateMachine_TestInterfaceReplyCallback(UpstreamPacketTypeDef* replyPacket); void Upstream_StateMachine_NotifyDevice(UpstreamPacketTypeDef* freePacket); void Upstream_StateMachine_NotifyDeviceReplyCallback(UpstreamPacketTypeDef* replyPacket); void Upstream_InitStateMachine(void) { UpstreamPacketTypeDef* freePacket; uint16_t i; uint8_t testDataValue; Upstream_InitSPI(); //Prepare SPI test packet freePacket = Upstream_GetFreePacketImmediately(); if (freePacket == NULL) { UpstreamState = STATE_ERROR; return; } freePacket->Length16 = UPSTREAM_PACKET_LEN_16; freePacket->CommandClass = COMMAND_CLASS_INTERFACE; freePacket->Command = COMMAND_INTERFACE_ECHO; //Fill our test packet with some junk testDataValue = 0xFF; for (i = 0; i < MSC_MEDIA_PACKET; i++) { freePacket->Data[i] = testDataValue; testDataValue += 39; } if (Upstream_TransmitPacket(freePacket) == HAL_OK) { Upstream_ReceivePacket(Upstream_StateMachine_TestInterfaceReplyCallback); } } //Used by upstream_spi freakout macro, indicates we should stop everything. void Upstream_StateMachine_SetErrorState(void) { UpstreamState = STATE_ERROR; if ((ConfiguredDeviceClass > COMMAND_CLASS_INTERFACE) && (ConfiguredDeviceClass < COMMAND_CLASS_ERROR)) { USBD_Stop(&hUsbDeviceFS); } } HAL_StatusTypeDef Upstream_StateMachine_CheckClassOperationOk(void) { if (UpstreamState == STATE_ERROR) { return HAL_ERROR; } if (UpstreamState != STATE_DEVICE_ACTIVE) { UPSTREAM_STATEMACHINE_FREAKOUT; return HAL_ERROR; } return HAL_OK; } void Upstream_StateMachine_TestInterfaceReplyCallback(UpstreamPacketTypeDef* replyPacket) { uint16_t i; uint8_t testDataValue; if (UpstreamState >= STATE_ERROR) { return; } if ((UpstreamState != STATE_TEST_INTERFACE) || (replyPacket == NULL)) { UPSTREAM_STATEMACHINE_FREAKOUT; return; } if (replyPacket->Length16 != UPSTREAM_PACKET_LEN_16) { UPSTREAM_STATEMACHINE_FREAKOUT; return; } testDataValue = 0xFF; for (i = 0; i < MSC_MEDIA_PACKET; i++) { if (replyPacket->Data[i] != testDataValue) { UPSTREAM_STATEMACHINE_FREAKOUT; return; } testDataValue += 39; } //SPI interface passed checks. Now we wait for a device to be attached to downstream. Upstream_StateMachine_NotifyDevice(replyPacket); } void Upstream_StateMachine_NotifyDevice(UpstreamPacketTypeDef* freePacket) { UpstreamState = STATE_WAIT_DEVICE; freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16; freePacket->CommandClass = COMMAND_CLASS_INTERFACE; freePacket->Command = COMMAND_INTERFACE_NOTIFY_DEVICE; if (Upstream_TransmitPacket(freePacket) == HAL_OK) { Upstream_ReceivePacket(Upstream_StateMachine_NotifyDeviceReplyCallback); } } void Upstream_StateMachine_NotifyDeviceReplyCallback(UpstreamPacketTypeDef* replyPacket) { InterfaceCommandClassTypeDef newActiveClass = COMMAND_CLASS_INTERFACE; USBD_ClassTypeDef* newClassPointer; if (UpstreamState >= STATE_ERROR) { return; } if ((UpstreamState != STATE_WAIT_DEVICE) || (replyPacket == NULL)) { UPSTREAM_STATEMACHINE_FREAKOUT; return; } if (replyPacket->Length16 != (UPSTREAM_PACKET_HEADER_LEN_16 + 1)) { UPSTREAM_STATEMACHINE_FREAKOUT; return; } switch (replyPacket->Data[0]) { case COMMAND_CLASS_MASS_STORAGE: newActiveClass = COMMAND_CLASS_MASS_STORAGE; newClassPointer = &USBD_MSC; break; //Add other supported classes here... } Upstream_ReleasePacket(replyPacket); if (newActiveClass == COMMAND_CLASS_INTERFACE) { UPSTREAM_STATEMACHINE_FREAKOUT; return; } //Downstream should never change the active device class without rebooting! if ((ConfiguredDeviceClass != COMMAND_CLASS_INTERFACE) && (ConfiguredDeviceClass != newActiveClass)) { UPSTREAM_STATEMACHINE_FREAKOUT; return; } UpstreamState = STATE_DEVICE_ACTIVE; ConfiguredDeviceClass = newActiveClass; USBD_RegisterClass(&hUsbDeviceFS, newClassPointer); USBD_Start(&hUsbDeviceFS); //The USB device stack will now receive commands from our host. //All we need to do is monitor for downstream device disconnection. } void Upstream_StateMachine_DeviceDisconnected(void) { if ((ConfiguredDeviceClass == COMMAND_CLASS_INTERFACE) || (ConfiguredDeviceClass >= COMMAND_CLASS_ERROR)) { UPSTREAM_STATEMACHINE_FREAKOUT; return; } USBD_Stop(&hUsbDeviceFS); Upstream_GetFreePacket(Upstream_StateMachine_NotifyDevice); }