- Implement notification of Downstream USB device removal, and

corresponding Upstream disconnection
- Improve Upstream handling of TxOk signal from Downstream
- Misc tweaks
pull/7/head
Robert Fisk 9 years ago
parent f24714cd8c
commit 750c2f3a21

@ -49,5 +49,13 @@ typedef enum
InterfaceCommandMscTypeDef; InterfaceCommandMscTypeDef;
typedef enum
{
COMMAND_ERROR_GENERIC,
COMMAND_ERROR_DEVICE_DISCONNECTED,
}
InterfaceCommandErrorTypeDef;
#endif /* INC_DOWNSTREAM_INTERFACE_DEF_H_ */ #endif /* INC_DOWNSTREAM_INTERFACE_DEF_H_ */

@ -17,22 +17,12 @@
#define DOWNSTREAM_PACKET_LEN_MIN (DOWNSTREAM_PACKET_HEADER_LEN) #define DOWNSTREAM_PACKET_LEN_MIN (DOWNSTREAM_PACKET_HEADER_LEN)
#define DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID \ #define DOWNSTREAM_SPI_FREAKOUT \
do { \ do { \
LED_Fault_SetBlinkRate(LED_FAST_BLINK_RATE); \ LED_Fault_SetBlinkRate(LED_FAST_BLINK_RATE); \
Downstream_PacketProcessor_SetErrorState(); \ Downstream_PacketProcessor_SetErrorState(); \
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_ERROR; \ DownstreamInterfaceState = DOWNSTREAM_INTERFACE_ERROR; \
while (1); \ while (1); \
/*return;*/ \
} while (0);
#define DOWNSTREAM_SPI_FREAKOUT_RETURN_HAL_ERROR \
do { \
LED_Fault_SetBlinkRate(LED_FAST_BLINK_RATE); \
Downstream_PacketProcessor_SetErrorState(); \
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_ERROR; \
while (1); \
/*return HAL_ERROR;*/ \
} while (0); } while (0);

@ -25,14 +25,6 @@ typedef enum
#define DOWNSTREAM_STATEMACHINE_FREAKOUT \ #define DOWNSTREAM_STATEMACHINE_FREAKOUT \
do { \
LED_Fault_SetBlinkRate(LED_FAST_BLINK_RATE); \
DownstreamState = STATE_ERROR; \
return; \
} while (0);
#define DOWNSTREAM_STATEMACHINE_FREAKOUT_NORETURN \
do { \ do { \
LED_Fault_SetBlinkRate(LED_FAST_BLINK_RATE); \ LED_Fault_SetBlinkRate(LED_FAST_BLINK_RATE); \
DownstreamState = STATE_ERROR; \ DownstreamState = STATE_ERROR; \
@ -44,7 +36,7 @@ typedef enum
void Downstream_InitStateMachine(void); void Downstream_InitStateMachine(void);
void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id); void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id);
void Downstream_PacketProcessor(DownstreamPacketTypeDef* receivedPacket); void Downstream_PacketProcessor(DownstreamPacketTypeDef* receivedPacket);
void Downstream_PacketProcessor_ErrorReply(DownstreamPacketTypeDef* replyPacket); void Downstream_PacketProcessor_GenericErrorReply(DownstreamPacketTypeDef* replyPacket);
void Downstream_PacketProcessor_ClassReply(DownstreamPacketTypeDef* replyPacket); void Downstream_PacketProcessor_ClassReply(DownstreamPacketTypeDef* replyPacket);
void Downstream_PacketProcessor_SetErrorState(void); void Downstream_PacketProcessor_SetErrorState(void);
void Downstream_PacketProcessor_FreakOut(void); void Downstream_PacketProcessor_FreakOut(void);

@ -151,7 +151,7 @@ void Downstream_MSC_PacketProcessor_RdWrCompleteCallback(USBH_StatusTypeDef resu
{ {
if (result != USBH_OK) if (result != USBH_OK)
{ {
Downstream_GetFreePacket(Downstream_PacketProcessor_ErrorReply); Downstream_GetFreePacket(Downstream_PacketProcessor_GenericErrorReply);
return; return;
} }
Downstream_ReceivePacket(Downstream_PacketProcessor); Downstream_ReceivePacket(Downstream_PacketProcessor);

@ -26,7 +26,7 @@ SpiPacketReceivedCallbackTypeDef ReceivePacketCallback = NULL; //Indicates some
HAL_StatusTypeDef Downstream_CheckPreparePacketReception(void); HAL_StatusTypeDef Downstream_CheckPreparePacketReception(void);
void Downstream_PreparePacketReception(DownstreamPacketTypeDef* freePacket); void Downstream_PrepareReceivePacketSize(DownstreamPacketTypeDef* freePacket);
@ -62,7 +62,8 @@ HAL_StatusTypeDef Downstream_GetFreePacket(FreePacketCallbackTypeDef callback)
//Do we already have a queued callback? //Do we already have a queued callback?
if (PendingFreePacketCallback != NULL) if (PendingFreePacketCallback != NULL)
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_HAL_ERROR; DOWNSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
} }
//Check if there is a free buffer now //Check if there is a free buffer now
@ -98,7 +99,8 @@ void Downstream_ReleasePacket(DownstreamPacketTypeDef* packetToRelease)
if ((packetToRelease != &DownstreamPacket0) && if ((packetToRelease != &DownstreamPacket0) &&
(packetToRelease != &DownstreamPacket1)) (packetToRelease != &DownstreamPacket1))
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; DOWNSTREAM_SPI_FREAKOUT;
return;
} }
if (PendingFreePacketCallback != NULL) if (PendingFreePacketCallback != NULL)
@ -125,10 +127,14 @@ HAL_StatusTypeDef Downstream_ReceivePacket(SpiPacketReceivedCallbackTypeDef call
return HAL_ERROR; return HAL_ERROR;
} }
if (ReceivePacketCallback != NULL) if ((DownstreamInterfaceState == DOWNSTREAM_INTERFACE_RX_SIZE_WAIT) ||
(DownstreamInterfaceState == DOWNSTREAM_INTERFACE_RX_PACKET_WAIT) ||
(ReceivePacketCallback != NULL))
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_HAL_ERROR; DOWNSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
} }
ReceivePacketCallback = callback; ReceivePacketCallback = callback;
return Downstream_CheckPreparePacketReception(); return Downstream_CheckPreparePacketReception();
} }
@ -137,21 +143,32 @@ HAL_StatusTypeDef Downstream_ReceivePacket(SpiPacketReceivedCallbackTypeDef call
//Internal use only //Internal use only
HAL_StatusTypeDef Downstream_CheckPreparePacketReception(void) HAL_StatusTypeDef Downstream_CheckPreparePacketReception(void)
{ {
if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
{
return HAL_ERROR;
}
if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_IDLE) if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_IDLE)
{ {
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_RX_SIZE_WAIT; DownstreamInterfaceState = DOWNSTREAM_INTERFACE_RX_SIZE_WAIT;
return Downstream_GetFreePacket(Downstream_PreparePacketReception); return Downstream_GetFreePacket(Downstream_PrepareReceivePacketSize);
} }
return HAL_OK; return HAL_OK;
} }
//Internal use only //Internal use only
void Downstream_PreparePacketReception(DownstreamPacketTypeDef* freePacket) void Downstream_PrepareReceivePacketSize(DownstreamPacketTypeDef* freePacket)
{ {
if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
{
return;
}
if (DownstreamInterfaceState != DOWNSTREAM_INTERFACE_RX_SIZE_WAIT) if (DownstreamInterfaceState != DOWNSTREAM_INTERFACE_RX_SIZE_WAIT)
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; DOWNSTREAM_SPI_FREAKOUT;
return;
} }
CurrentWorkingPacket = freePacket; CurrentWorkingPacket = freePacket;
//CurrentWorkingPacket->Length = 0; //CurrentWorkingPacket->Length = 0;
@ -160,7 +177,8 @@ void Downstream_PreparePacketReception(DownstreamPacketTypeDef* freePacket)
(uint8_t*)&CurrentWorkingPacket->Length, (uint8_t*)&CurrentWorkingPacket->Length,
(2 + 1)) != HAL_OK) //"When the CRC feature is enabled the pData Length must be Size + 1" (2 + 1)) != HAL_OK) //"When the CRC feature is enabled the pData Length must be Size + 1"
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; DOWNSTREAM_SPI_FREAKOUT;
return;
} }
UPSTREAM_TX_REQUEST_ASSERT; UPSTREAM_TX_REQUEST_ASSERT;
@ -185,14 +203,16 @@ void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
if ((CurrentWorkingPacket->Length < DOWNSTREAM_PACKET_LEN_MIN) || if ((CurrentWorkingPacket->Length < DOWNSTREAM_PACKET_LEN_MIN) ||
(CurrentWorkingPacket->Length > DOWNSTREAM_PACKET_LEN)) (CurrentWorkingPacket->Length > DOWNSTREAM_PACKET_LEN))
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; DOWNSTREAM_SPI_FREAKOUT;
return;
} }
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_RX_PACKET_WAIT; DownstreamInterfaceState = DOWNSTREAM_INTERFACE_RX_PACKET_WAIT;
if ((HAL_SPI_Receive_DMA(&Hspi1, if ((HAL_SPI_Receive_DMA(&Hspi1,
&CurrentWorkingPacket->CommandClass, &CurrentWorkingPacket->CommandClass,
CurrentWorkingPacket->Length + 1)) != HAL_OK) //"When the CRC feature is enabled the pData Length must be Size + 1" CurrentWorkingPacket->Length + 1)) != HAL_OK) //"When the CRC feature is enabled the pData Length must be Size + 1"
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; DOWNSTREAM_SPI_FREAKOUT;
return;
} }
UPSTREAM_TX_REQUEST_ASSERT; UPSTREAM_TX_REQUEST_ASSERT;
return; return;
@ -203,7 +223,8 @@ void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_IDLE; DownstreamInterfaceState = DOWNSTREAM_INTERFACE_IDLE;
if (ReceivePacketCallback == NULL) if (ReceivePacketCallback == NULL)
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; DOWNSTREAM_SPI_FREAKOUT;
return;
} }
//Packet processor may want to receive another packet immediately, //Packet processor may want to receive another packet immediately,
//so clear ReceivePacketCallback before the call. //so clear ReceivePacketCallback before the call.
@ -214,7 +235,8 @@ void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
return; return;
} }
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; //case default:
DOWNSTREAM_SPI_FREAKOUT;
} }
@ -233,17 +255,20 @@ HAL_StatusTypeDef Downstream_TransmitPacket(DownstreamPacketTypeDef* packetToWri
if ((packetToWrite != &DownstreamPacket0) && if ((packetToWrite != &DownstreamPacket0) &&
(packetToWrite != &DownstreamPacket1)) (packetToWrite != &DownstreamPacket1))
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_HAL_ERROR; DOWNSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
} }
if ((packetToWrite->Busy != BUSY) || if ((packetToWrite->Busy != BUSY) ||
(packetToWrite->Length < DOWNSTREAM_PACKET_LEN_MIN) || (packetToWrite->Length < DOWNSTREAM_PACKET_LEN_MIN) ||
(packetToWrite->Length > DOWNSTREAM_PACKET_LEN)) (packetToWrite->Length > DOWNSTREAM_PACKET_LEN))
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_HAL_ERROR; DOWNSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
} }
if (NextTxPacket != NULL) if (NextTxPacket != NULL)
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_HAL_ERROR; DOWNSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
} }
switch (DownstreamInterfaceState) switch (DownstreamInterfaceState)
@ -261,13 +286,15 @@ HAL_StatusTypeDef Downstream_TransmitPacket(DownstreamPacketTypeDef* packetToWri
(uint8_t*)&CurrentWorkingPacket->Length, (uint8_t*)&CurrentWorkingPacket->Length,
2 + 1) != HAL_OK) //"When the CRC feature is enabled the pRxData Length must be Size + 1" 2 + 1) != HAL_OK) //"When the CRC feature is enabled the pRxData Length must be Size + 1"
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_HAL_ERROR; DOWNSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
} }
UPSTREAM_TX_REQUEST_ASSERT; UPSTREAM_TX_REQUEST_ASSERT;
break; break;
default: default:
DOWNSTREAM_SPI_FREAKOUT_RETURN_HAL_ERROR; DOWNSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
} }
return HAL_OK; return HAL_OK;
@ -289,14 +316,16 @@ void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
if (DownstreamInterfaceState != DOWNSTREAM_INTERFACE_TX_SIZE_WAIT) if (DownstreamInterfaceState != DOWNSTREAM_INTERFACE_TX_SIZE_WAIT)
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; DOWNSTREAM_SPI_FREAKOUT;
return;
} }
if (CurrentWorkingPacket->Length != 0) if (CurrentWorkingPacket->Length != 0)
{ {
//Currently we just freak out if Upstream sends us an unexpected command. //Currently we just freak out if Upstream sends us an unexpected command.
//Theoretically we could reset our downstream state machine and accept the new command... //Theoretically we could reset our downstream state machine and accept the new command...
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; DOWNSTREAM_SPI_FREAKOUT;
return;
} }
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_TX_PACKET_WAIT; DownstreamInterfaceState = DOWNSTREAM_INTERFACE_TX_PACKET_WAIT;
@ -304,7 +333,8 @@ void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
&CurrentWorkingPacket->CommandClass, &CurrentWorkingPacket->CommandClass,
CurrentWorkingPacket->Length)) != HAL_OK) CurrentWorkingPacket->Length)) != HAL_OK)
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; DOWNSTREAM_SPI_FREAKOUT;
return;
} }
UPSTREAM_TX_REQUEST_ASSERT; UPSTREAM_TX_REQUEST_ASSERT;
} }
@ -323,7 +353,8 @@ void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
if (DownstreamInterfaceState != DOWNSTREAM_INTERFACE_TX_PACKET_WAIT) if (DownstreamInterfaceState != DOWNSTREAM_INTERFACE_TX_PACKET_WAIT)
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; DOWNSTREAM_SPI_FREAKOUT;
return;
} }
Downstream_ReleasePacket(CurrentWorkingPacket); Downstream_ReleasePacket(CurrentWorkingPacket);
@ -339,7 +370,8 @@ void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
(uint8_t*)&CurrentWorkingPacket->Length, (uint8_t*)&CurrentWorkingPacket->Length,
2 + 1) != HAL_OK) //"When the CRC feature is enabled the pRxData Length must be Size + 1" 2 + 1) != HAL_OK) //"When the CRC feature is enabled the pRxData Length must be Size + 1"
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; DOWNSTREAM_SPI_FREAKOUT;
return;
} }
UPSTREAM_TX_REQUEST_ASSERT; UPSTREAM_TX_REQUEST_ASSERT;
return; return;
@ -357,6 +389,6 @@ void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
//Something bad happened! Possibly CRC error... //Something bad happened! Possibly CRC error...
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{ {
DOWNSTREAM_SPI_FREAKOUT_RETURN_VOID; DOWNSTREAM_SPI_FREAKOUT;
} }

@ -43,21 +43,38 @@ void Downstream_PacketProcessor(DownstreamPacketTypeDef* receivedPacket)
return; return;
} }
switch (receivedPacket->CommandClass) if (receivedPacket->CommandClass == COMMAND_CLASS_INTERFACE)
{ {
case COMMAND_CLASS_INTERFACE:
if (DownstreamState > STATE_DEVICE_READY) if (DownstreamState > STATE_DEVICE_READY)
{ {
DOWNSTREAM_STATEMACHINE_FREAKOUT; DOWNSTREAM_STATEMACHINE_FREAKOUT;
return;
} }
Downstream_PacketProcessor_Interface(receivedPacket); Downstream_PacketProcessor_Interface(receivedPacket);
break; return;
}
//If we get a class-specific message when our device is disconnected,
//we need to tell Upstream of the fact (and not freak out).
if (DownstreamState == STATE_DEVICE_NOT_READY)
{
receivedPacket->Length = DOWNSTREAM_PACKET_HEADER_LEN;
receivedPacket->CommandClass = COMMAND_CLASS_ERROR;
receivedPacket->Command = COMMAND_ERROR_DEVICE_DISCONNECTED;
Downstream_PacketProcessor_ClassReply(receivedPacket);
return;
}
//We should only receive class-specific messages when we are in the Active state.
if (DownstreamState != STATE_ACTIVE)
{
DOWNSTREAM_STATEMACHINE_FREAKOUT;
return;
}
switch (receivedPacket->CommandClass)
{
case COMMAND_CLASS_MASS_STORAGE: case COMMAND_CLASS_MASS_STORAGE:
if (DownstreamState != STATE_ACTIVE)
{
DOWNSTREAM_STATEMACHINE_FREAKOUT;
}
Downstream_MSC_PacketProcessor(receivedPacket); Downstream_MSC_PacketProcessor(receivedPacket);
break; break;
@ -89,11 +106,9 @@ void Downstream_PacketProcessor_Interface(DownstreamPacketTypeDef* receivedPacke
switch (receivedPacket->Command) switch (receivedPacket->Command)
{ {
case COMMAND_INTERFACE_ECHO: case COMMAND_INTERFACE_ECHO:
if (Downstream_TransmitPacket(receivedPacket) == HAL_OK) Downstream_TransmitPacket(receivedPacket);
{ Downstream_ReceivePacket(Downstream_PacketProcessor);
Downstream_ReceivePacket(Downstream_PacketProcessor); break;
}
return;
case COMMAND_INTERFACE_NOTIFY_DEVICE: case COMMAND_INTERFACE_NOTIFY_DEVICE:
if (DownstreamState == STATE_DEVICE_READY) if (DownstreamState == STATE_DEVICE_READY)
@ -109,7 +124,7 @@ void Downstream_PacketProcessor_Interface(DownstreamPacketTypeDef* receivedPacke
return; return;
} }
DOWNSTREAM_STATEMACHINE_FREAKOUT; DOWNSTREAM_STATEMACHINE_FREAKOUT;
return; break;
default: default:
@ -133,24 +148,21 @@ void Downstream_PacketProcessor_Interface_ReplyNotifyDevice(DownstreamPacketType
} }
void Downstream_PacketProcessor_ErrorReply(DownstreamPacketTypeDef* replyPacket) void Downstream_PacketProcessor_GenericErrorReply(DownstreamPacketTypeDef* replyPacket)
{ {
replyPacket->Length = DOWNSTREAM_PACKET_HEADER_LEN; replyPacket->Length = DOWNSTREAM_PACKET_HEADER_LEN;
replyPacket->CommandClass = COMMAND_CLASS_ERROR; replyPacket->CommandClass = COMMAND_CLASS_ERROR;
replyPacket->Command = COMMAND_ERROR_GENERIC;
if (Downstream_TransmitPacket(replyPacket) == HAL_OK) Downstream_TransmitPacket(replyPacket);
{ Downstream_ReceivePacket(Downstream_PacketProcessor);
Downstream_ReceivePacket(Downstream_PacketProcessor);
}
} }
void Downstream_PacketProcessor_ClassReply(DownstreamPacketTypeDef* replyPacket) void Downstream_PacketProcessor_ClassReply(DownstreamPacketTypeDef* replyPacket)
{ {
if (Downstream_TransmitPacket(replyPacket) == HAL_OK) Downstream_TransmitPacket(replyPacket);
{ Downstream_ReceivePacket(Downstream_PacketProcessor);
Downstream_ReceivePacket(Downstream_PacketProcessor);
}
} }
@ -173,14 +185,12 @@ void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id)
return; return;
} }
//Elevate our priority level so we aren't interrupted __set_BASEPRI(INT_PRIORITY_OTG_FS); //Elevate our priority level so we aren't interrupted
__set_BASEPRI(INT_PRIORITY_OTG_FS);
//Called from main() //Called from main()
if (id == HOST_USER_UNRECOVERED_ERROR) if (id == HOST_USER_UNRECOVERED_ERROR)
{ {
DOWNSTREAM_STATEMACHINE_FREAKOUT_NORETURN; DOWNSTREAM_STATEMACHINE_FREAKOUT;
__set_BASEPRI(0); __set_BASEPRI(0);
return; return;
} }
@ -212,7 +222,7 @@ void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id)
//If the new device has failed its 'approval' checks, we are sufficiently freaked out. //If the new device has failed its 'approval' checks, we are sufficiently freaked out.
if (newActiveClass == COMMAND_CLASS_INTERFACE) if (newActiveClass == COMMAND_CLASS_INTERFACE)
{ {
DOWNSTREAM_STATEMACHINE_FREAKOUT_NORETURN; DOWNSTREAM_STATEMACHINE_FREAKOUT;
__set_BASEPRI(0); __set_BASEPRI(0);
return; return;
} }
@ -222,7 +232,7 @@ void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id)
if ((ConfiguredDeviceClass != COMMAND_CLASS_INTERFACE) && if ((ConfiguredDeviceClass != COMMAND_CLASS_INTERFACE) &&
(ConfiguredDeviceClass != newActiveClass)) (ConfiguredDeviceClass != newActiveClass))
{ {
DOWNSTREAM_STATEMACHINE_FREAKOUT_NORETURN; DOWNSTREAM_STATEMACHINE_FREAKOUT;
__set_BASEPRI(0); __set_BASEPRI(0);
return; return;
} }
@ -242,7 +252,7 @@ void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id)
return; return;
} }
DOWNSTREAM_STATEMACHINE_FREAKOUT_NORETURN; DOWNSTREAM_STATEMACHINE_FREAKOUT;
__set_BASEPRI(0); __set_BASEPRI(0);
return; return;
} }

@ -51,4 +51,13 @@ typedef enum
InterfaceCommandMscTypeDef; InterfaceCommandMscTypeDef;
typedef enum
{
COMMAND_ERROR_GENERIC,
COMMAND_ERROR_DEVICE_DISCONNECTED,
}
InterfaceCommandErrorTypeDef;
#endif /* INC_UPSTREAM_INTERFACE_DEF_H_ */ #endif /* INC_UPSTREAM_INTERFACE_DEF_H_ */

@ -27,7 +27,6 @@
typedef enum typedef enum
{ {
UPSTREAM_INTERFACE_IDLE, UPSTREAM_INTERFACE_IDLE,

@ -33,6 +33,7 @@ typedef enum
void Upstream_InitStateMachine(void); void Upstream_InitStateMachine(void);
void Upstream_StateMachine_SetErrorState(void); void Upstream_StateMachine_SetErrorState(void);
HAL_StatusTypeDef Upstream_StateMachine_CheckClassOperationOk(void); HAL_StatusTypeDef Upstream_StateMachine_CheckClassOperationOk(void);
void Upstream_StateMachine_DeviceDisconnected(void);

@ -24,12 +24,16 @@ InterfaceStateTypeDef UpstreamInterfaceState = UPSTREAM_INTERFACE_IDLE;
FreePacketCallbackTypeDef PendingFreePacketCallback = NULL; //Indicates someone is waiting for a packet buffer to become available FreePacketCallbackTypeDef PendingFreePacketCallback = NULL; //Indicates someone is waiting for a packet buffer to become available
SpiPacketReceivedCallbackTypeDef ReceivePacketCallback = NULL; //Indicates someone is waiting for a received packet SpiPacketReceivedCallbackTypeDef ReceivePacketCallback = NULL; //Indicates someone is waiting for a received packet
uint8_t TxOkInterruptReceived = 0;
uint8_t SentCommandClass; uint8_t SentCommandClass;
uint8_t SentCommand; uint8_t SentCommand;
static HAL_StatusTypeDef Upstream_CheckBeginPacketReception(void); void Upstream_BeginTransmitPacketSize(void);
static void Upstream_BeginPacketReception(UpstreamPacketTypeDef* freePacket); void Upstream_BeginTransmitPacketBody(void);
HAL_StatusTypeDef Upstream_CheckBeginPacketReception(void);
void Upstream_BeginReceivePacketSize(UpstreamPacketTypeDef* freePacket);
void Upstream_BeginReceivePacketBody(void);
@ -191,6 +195,14 @@ HAL_StatusTypeDef Upstream_TransmitPacket(UpstreamPacketTypeDef* packetToWrite)
CurrentWorkingPacket = packetToWrite; CurrentWorkingPacket = packetToWrite;
SentCommandClass = CurrentWorkingPacket->CommandClass; SentCommandClass = CurrentWorkingPacket->CommandClass;
SentCommand = CurrentWorkingPacket->Command; SentCommand = CurrentWorkingPacket->Command;
//Downstream may have set TxOk pin before we wanted to transmit.
//In this case we can go ahead and transmit now.
if (TxOkInterruptReceived)
{
TxOkInterruptReceived = 0;
Upstream_BeginTransmitPacketSize();
}
break; break;
default: default:
@ -217,6 +229,11 @@ void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
if (UpstreamInterfaceState == UPSTREAM_INTERFACE_TX_SIZE) if (UpstreamInterfaceState == UPSTREAM_INTERFACE_TX_SIZE)
{ {
UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_PACKET_WAIT; UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_PACKET_WAIT;
if (TxOkInterruptReceived)
{
TxOkInterruptReceived = 0;
Upstream_BeginTransmitPacketBody();
}
return; return;
} }
@ -241,6 +258,11 @@ void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_SIZE_WAIT; UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_SIZE_WAIT;
CurrentWorkingPacket = NextTxPacket; CurrentWorkingPacket = NextTxPacket;
NextTxPacket = NULL; NextTxPacket = NULL;
if (TxOkInterruptReceived)
{
TxOkInterruptReceived = 0;
Upstream_BeginTransmitPacketSize();
}
return; return;
} }
@ -286,7 +308,7 @@ HAL_StatusTypeDef Upstream_CheckBeginPacketReception(void)
return HAL_ERROR; return HAL_ERROR;
} }
if (UpstreamInterfaceState > UPSTREAM_INTERFACE_RX_SIZE_WAIT) if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_RX_SIZE_WAIT)
{ {
UPSTREAM_SPI_FREAKOUT; UPSTREAM_SPI_FREAKOUT;
return HAL_ERROR; return HAL_ERROR;
@ -295,6 +317,11 @@ HAL_StatusTypeDef Upstream_CheckBeginPacketReception(void)
if (UpstreamInterfaceState == UPSTREAM_INTERFACE_IDLE) if (UpstreamInterfaceState == UPSTREAM_INTERFACE_IDLE)
{ {
UpstreamInterfaceState = UPSTREAM_INTERFACE_RX_SIZE_WAIT; UpstreamInterfaceState = UPSTREAM_INTERFACE_RX_SIZE_WAIT;
if (TxOkInterruptReceived)
{
TxOkInterruptReceived = 0;
Upstream_GetFreePacket(Upstream_BeginReceivePacketSize);
}
} }
return HAL_OK; return HAL_OK;
} }
@ -311,41 +338,24 @@ void Upstream_TxOkInterrupt(void)
switch (UpstreamInterfaceState) switch (UpstreamInterfaceState)
{ {
case UPSTREAM_INTERFACE_IDLE:
TxOkInterruptReceived = 1;
break;
case UPSTREAM_INTERFACE_TX_SIZE_WAIT: case UPSTREAM_INTERFACE_TX_SIZE_WAIT:
UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_SIZE; Upstream_BeginTransmitPacketSize();
SPI1_NSS_ASSERT;
if (HAL_SPI_Transmit_DMA(&Hspi1,
(uint8_t*)&CurrentWorkingPacket->Length,
2) != HAL_OK)
{
UPSTREAM_SPI_FREAKOUT;
}
break; break;
case UPSTREAM_INTERFACE_TX_PACKET_WAIT: case UPSTREAM_INTERFACE_TX_PACKET_WAIT:
UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_PACKET; Upstream_BeginTransmitPacketBody();
SPI1_NSS_ASSERT;
if ((HAL_SPI_Transmit_DMA(&Hspi1,
&CurrentWorkingPacket->CommandClass,
CurrentWorkingPacket->Length)) != HAL_OK)
{
UPSTREAM_SPI_FREAKOUT;
}
break; break;
case UPSTREAM_INTERFACE_RX_SIZE_WAIT: case UPSTREAM_INTERFACE_RX_SIZE_WAIT:
Upstream_GetFreePacket(Upstream_BeginPacketReception); Upstream_GetFreePacket(Upstream_BeginReceivePacketSize);
break; break;
case UPSTREAM_INTERFACE_RX_PACKET_WAIT: case UPSTREAM_INTERFACE_RX_PACKET_WAIT:
UpstreamInterfaceState = UPSTREAM_INTERFACE_RX_PACKET; Upstream_BeginReceivePacketBody();
SPI1_NSS_ASSERT;
if ((HAL_SPI_Receive_DMA(&Hspi1,
&CurrentWorkingPacket->CommandClass,
(CurrentWorkingPacket->Length + 1))) != HAL_OK) //"When the CRC feature is enabled the pData Length must be Size + 1"
{
UPSTREAM_SPI_FREAKOUT;
}
break; break;
default: default:
@ -354,9 +364,35 @@ void Upstream_TxOkInterrupt(void)
} }
void Upstream_BeginTransmitPacketSize(void)
{
UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_SIZE;
SPI1_NSS_ASSERT;
if (HAL_SPI_Transmit_DMA(&Hspi1,
(uint8_t*)&CurrentWorkingPacket->Length,
2) != HAL_OK)
{
UPSTREAM_SPI_FREAKOUT;
}
}
void Upstream_BeginTransmitPacketBody(void)
{
UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_PACKET;
SPI1_NSS_ASSERT;
if ((HAL_SPI_Transmit_DMA(&Hspi1,
&CurrentWorkingPacket->CommandClass,
CurrentWorkingPacket->Length)) != HAL_OK)
{
UPSTREAM_SPI_FREAKOUT;
}
}
//Internal use only. //Internal use only.
//Called when we want to receive downstream packet, and a packet buffer has become free. //Called when we want to receive downstream packet, and a packet buffer has become free.
void Upstream_BeginPacketReception(UpstreamPacketTypeDef* freePacket) void Upstream_BeginReceivePacketSize(UpstreamPacketTypeDef* freePacket)
{ {
if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_ERROR) if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_ERROR)
{ {
@ -381,6 +417,19 @@ void Upstream_BeginPacketReception(UpstreamPacketTypeDef* freePacket)
} }
void Upstream_BeginReceivePacketBody(void)
{
UpstreamInterfaceState = UPSTREAM_INTERFACE_RX_PACKET;
SPI1_NSS_ASSERT;
if ((HAL_SPI_Receive_DMA(&Hspi1,
&CurrentWorkingPacket->CommandClass,
(CurrentWorkingPacket->Length + 1))) != HAL_OK) //"When the CRC feature is enabled the pData Length must be Size + 1"
{
UPSTREAM_SPI_FREAKOUT;
}
}
//Called at the end of the SPI RX DMA transfer, //Called at the end of the SPI RX DMA transfer,
//at DMA2 interrupt priority. Assume *hspi points to our hspi1. //at DMA2 interrupt priority. Assume *hspi points to our hspi1.
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
@ -403,20 +452,34 @@ void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
return; return;
} }
UpstreamInterfaceState = UPSTREAM_INTERFACE_RX_PACKET_WAIT; UpstreamInterfaceState = UPSTREAM_INTERFACE_RX_PACKET_WAIT;
if (TxOkInterruptReceived)
{
TxOkInterruptReceived = 0;
Upstream_BeginReceivePacketBody();
}
return; return;
} }
if (UpstreamInterfaceState == UPSTREAM_INTERFACE_RX_PACKET) if (UpstreamInterfaceState == UPSTREAM_INTERFACE_RX_PACKET)
{ {
UpstreamInterfaceState = UPSTREAM_INTERFACE_IDLE;
if (ReceivePacketCallback == NULL) if (ReceivePacketCallback == NULL)
{ {
UPSTREAM_SPI_FREAKOUT; UPSTREAM_SPI_FREAKOUT;
return; return;
} }
UpstreamInterfaceState = UPSTREAM_INTERFACE_IDLE; if ((CurrentWorkingPacket->CommandClass == COMMAND_CLASS_ERROR) &&
if ((SentCommandClass != (CurrentWorkingPacket->CommandClass & COMMAND_CLASS_MASK)) || (CurrentWorkingPacket->Command == COMMAND_ERROR_DEVICE_DISCONNECTED))
(SentCommand != CurrentWorkingPacket->Command)) {
Upstream_ReleasePacket(CurrentWorkingPacket);
ReceivePacketCallback = NULL;
Upstream_StateMachine_DeviceDisconnected();
return;
}
if (((CurrentWorkingPacket->CommandClass & COMMAND_CLASS_MASK) != SentCommandClass) ||
(CurrentWorkingPacket->Command != SentCommand))
{ {
UPSTREAM_SPI_FREAKOUT; UPSTREAM_SPI_FREAKOUT;
Upstream_ReleasePacket(CurrentWorkingPacket); Upstream_ReleasePacket(CurrentWorkingPacket);

@ -14,12 +14,13 @@
#include "usbd_msc.h" #include "usbd_msc.h"
UpstreamStateTypeDef UpstreamState = STATE_TEST_INTERFACE; UpstreamStateTypeDef UpstreamState = STATE_TEST_INTERFACE;
InterfaceCommandClassTypeDef ActiveDeviceClass = COMMAND_CLASS_INTERFACE; InterfaceCommandClassTypeDef ConfiguredDeviceClass = COMMAND_CLASS_INTERFACE;
void Upstream_TestInterfaceReplyCallback(UpstreamPacketTypeDef* replyPacket); void Upstream_StateMachine_TestInterfaceReplyCallback(UpstreamPacketTypeDef* replyPacket);
void Upstream_NotifyDeviceReplyCallback(UpstreamPacketTypeDef* replyPacket); void Upstream_StateMachine_NotifyDevice(UpstreamPacketTypeDef* freePacket);
void Upstream_StateMachine_NotifyDeviceReplyCallback(UpstreamPacketTypeDef* replyPacket);
@ -42,9 +43,9 @@ void Upstream_InitStateMachine(void)
freePacket->Length = UPSTREAM_PACKET_HEADER_LEN + MSC_MEDIA_PACKET; freePacket->Length = UPSTREAM_PACKET_HEADER_LEN + MSC_MEDIA_PACKET;
freePacket->CommandClass = COMMAND_CLASS_INTERFACE; freePacket->CommandClass = COMMAND_CLASS_INTERFACE;
freePacket->Command = COMMAND_INTERFACE_ECHO; freePacket->Command = COMMAND_INTERFACE_ECHO;
testDataValue = 0xFF;
//Fill our test packet with some junk //Fill our test packet with some junk
testDataValue = 0xFF;
for (i = 0; i < MSC_MEDIA_PACKET; i++) for (i = 0; i < MSC_MEDIA_PACKET; i++)
{ {
freePacket->Data[i] = testDataValue; freePacket->Data[i] = testDataValue;
@ -53,7 +54,7 @@ void Upstream_InitStateMachine(void)
if (Upstream_TransmitPacket(freePacket) == HAL_OK) if (Upstream_TransmitPacket(freePacket) == HAL_OK)
{ {
Upstream_ReceivePacket(Upstream_TestInterfaceReplyCallback); Upstream_ReceivePacket(Upstream_StateMachine_TestInterfaceReplyCallback);
} }
} }
@ -62,8 +63,8 @@ void Upstream_InitStateMachine(void)
void Upstream_StateMachine_SetErrorState(void) void Upstream_StateMachine_SetErrorState(void)
{ {
UpstreamState = STATE_ERROR; UpstreamState = STATE_ERROR;
if ((ActiveDeviceClass > COMMAND_CLASS_INTERFACE) && if ((ConfiguredDeviceClass > COMMAND_CLASS_INTERFACE) &&
(ActiveDeviceClass < COMMAND_CLASS_ERROR)) (ConfiguredDeviceClass < COMMAND_CLASS_ERROR))
{ {
USBD_Stop(&hUsbDeviceFS); USBD_Stop(&hUsbDeviceFS);
} }
@ -87,7 +88,7 @@ HAL_StatusTypeDef Upstream_StateMachine_CheckClassOperationOk(void)
} }
void Upstream_TestInterfaceReplyCallback(UpstreamPacketTypeDef* replyPacket) void Upstream_StateMachine_TestInterfaceReplyCallback(UpstreamPacketTypeDef* replyPacket)
{ {
uint16_t i; uint16_t i;
uint8_t testDataValue; uint8_t testDataValue;
@ -121,21 +122,29 @@ void Upstream_TestInterfaceReplyCallback(UpstreamPacketTypeDef* replyPacket)
testDataValue += 39; testDataValue += 39;
} }
//SPI interface passed checks. Now we wait for a device to be attached to downstream. //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; UpstreamState = STATE_WAIT_DEVICE;
replyPacket->Length = UPSTREAM_PACKET_HEADER_LEN; freePacket->Length = UPSTREAM_PACKET_HEADER_LEN;
replyPacket->CommandClass = COMMAND_CLASS_INTERFACE; freePacket->CommandClass = COMMAND_CLASS_INTERFACE;
replyPacket->Command = COMMAND_INTERFACE_NOTIFY_DEVICE; freePacket->Command = COMMAND_INTERFACE_NOTIFY_DEVICE;
if (Upstream_TransmitPacket(replyPacket) == HAL_OK) if (Upstream_TransmitPacket(freePacket) == HAL_OK)
{ {
Upstream_ReceivePacket(Upstream_NotifyDeviceReplyCallback); Upstream_ReceivePacket(Upstream_StateMachine_NotifyDeviceReplyCallback);
} }
} }
void Upstream_NotifyDeviceReplyCallback(UpstreamPacketTypeDef* replyPacket) void Upstream_StateMachine_NotifyDeviceReplyCallback(UpstreamPacketTypeDef* replyPacket)
{ {
InterfaceCommandClassTypeDef newActiveClass = COMMAND_CLASS_INTERFACE;
USBD_ClassTypeDef* newClassPointer;
if (UpstreamState >= STATE_ERROR) if (UpstreamState >= STATE_ERROR)
{ {
return; return;
@ -157,20 +166,47 @@ void Upstream_NotifyDeviceReplyCallback(UpstreamPacketTypeDef* replyPacket)
switch (replyPacket->Data[0]) switch (replyPacket->Data[0])
{ {
case COMMAND_CLASS_MASS_STORAGE: case COMMAND_CLASS_MASS_STORAGE:
USBD_RegisterClass(&hUsbDeviceFS, &USBD_MSC); newActiveClass = COMMAND_CLASS_MASS_STORAGE;
newClassPointer = &USBD_MSC;
break; break;
default: //Add other supported classes here...
}
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; UPSTREAM_STATEMACHINE_FREAKOUT;
return; return;
} }
USBD_Start(&hUsbDeviceFS);
UpstreamState = STATE_DEVICE_ACTIVE; UpstreamState = STATE_DEVICE_ACTIVE;
ActiveDeviceClass = replyPacket->Data[0]; ConfiguredDeviceClass = newActiveClass;
USBD_RegisterClass(&hUsbDeviceFS, newClassPointer);
USBD_Start(&hUsbDeviceFS);
//The USB device stack will now receive commands from our host. //The USB device stack will now receive commands from our host.
//All we need to do is check for downstream device removal. //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);
}

Loading…
Cancel
Save