diff --git a/Downstream/.cproject b/Downstream/.cproject
index ae7ab7c..e7f3c64 100644
--- a/Downstream/.cproject
+++ b/Downstream/.cproject
@@ -15,7 +15,7 @@
-
+
@@ -24,7 +24,7 @@
-
+
@@ -91,7 +91,7 @@
-
+
diff --git a/Downstream/.settings/language.settings.xml b/Downstream/.settings/language.settings.xml
index 1974b05..7febaad 100644
--- a/Downstream/.settings/language.settings.xml
+++ b/Downstream/.settings/language.settings.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/Downstream/Inc/downstream_interface_def.h b/Downstream/Inc/downstream_interface_def.h
index d0f2947..5121572 100644
--- a/Downstream/Inc/downstream_interface_def.h
+++ b/Downstream/Inc/downstream_interface_def.h
@@ -25,6 +25,8 @@ typedef enum
{
COMMAND_CLASS_INTERFACE,
COMMAND_CLASS_MASS_STORAGE,
+ //...
+ COMMAND_CLASS_ERROR
}
InterfaceCommandClassTypeDef;
diff --git a/Downstream/Inc/downstream_msc.h b/Downstream/Inc/downstream_msc.h
new file mode 100644
index 0000000..8b1e5b4
--- /dev/null
+++ b/Downstream/Inc/downstream_msc.h
@@ -0,0 +1,20 @@
+/*
+ * downstream_msc.h
+ *
+ * Created on: 8/08/2015
+ * Author: Robert Fisk
+ */
+
+#ifndef INC_DOWNSTREAM_MSC_H_
+#define INC_DOWNSTREAM_MSC_H_
+
+
+#include "downstream_spi.h"
+
+
+HAL_StatusTypeDef Downstream_MSC_ApproveConnectedDevice(void);
+void Downstream_MSC_PacketProcessor(DownstreamPacketTypeDef* receivedPacket);
+
+
+
+#endif /* INC_DOWNSTREAM_MSC_H_ */
diff --git a/Downstream/Inc/downstream_statemachine.h b/Downstream/Inc/downstream_statemachine.h
index 8fce582..dc61ce4 100644
--- a/Downstream/Inc/downstream_statemachine.h
+++ b/Downstream/Inc/downstream_statemachine.h
@@ -10,13 +10,15 @@
#include "usbh_def.h"
+#include "downstream_spi.h"
typedef enum
{
- STATE_NOT_READY,
- STATE_WAIT_DEVICE_READY_CALLBACK,
- STATE_DEVICE_READY,
+ STATE_DEVICE_NOT_READY,
+ STATE_DEVICE_READY, //HOST_USER_CLASS_ACTIVE callback arrives first
+ STATE_WAIT_DEVICE_READY, //COMMAND_INTERFACE_NOTIFY_DEVICE message arrives first
+ STATE_ACTIVE,
STATE_ERROR
} DownstreamStateTypeDef;
@@ -24,7 +26,8 @@ typedef enum
void Downstream_InitStateMachine(void);
void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id);
-
+void Downstream_PacketProcessor_ErrorReply(DownstreamPacketTypeDef* replyPacket);
+void Downstream_PacketProcessor_ClassReply(DownstreamPacketTypeDef* replyPacket);
#endif /* INC_DOWNSTREAM_STATEMACHINE_H_ */
diff --git a/Downstream/Src/downstream_msc.c b/Downstream/Src/downstream_msc.c
new file mode 100644
index 0000000..a721cbe
--- /dev/null
+++ b/Downstream/Src/downstream_msc.c
@@ -0,0 +1,132 @@
+/*
+ * downstream_msc.c
+ *
+ * Created on: 8/08/2015
+ * Author: Robert Fisk
+ */
+
+
+#include "downstream_msc.h"
+#include "downstream_interface_def.h"
+#include "downstream_statemachine.h"
+#include "usbh_msc.h"
+
+
+extern USBH_HandleTypeDef hUsbHostFS; //Hard-link ourselves to usb_host.c
+
+
+void Downstream_MSC_PacketProcessor_TestUnitReady(DownstreamPacketTypeDef* receivedPacket);
+void Downstream_MSC_PacketProcessor_GetCapacity(DownstreamPacketTypeDef* receivedPacket);
+void Downstream_MSC_PacketProcessor_BeginRead(DownstreamPacketTypeDef* receivedPacket);
+
+
+
+//High-level checks on the connected device. We don't want some weirdly
+//configured device to bomb our USB stack, accidentally or otherwise.
+HAL_StatusTypeDef Downstream_MSC_ApproveConnectedDevice(void)
+{
+ MSC_HandleTypeDef* MSC_Handle = (MSC_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
+
+ if ((MSC_Handle->unit[0].capacity.block_nbr == 0) ||
+ (MSC_Handle->unit[0].capacity.block_nbr == UINT32_MAX))
+ {
+ return HAL_ERROR;
+ }
+
+ if (MSC_Handle->unit[0].capacity.block_size != 512)
+ {
+ return HAL_ERROR;
+ }
+
+ return HAL_OK;
+}
+
+
+void Downstream_MSC_PacketProcessor(DownstreamPacketTypeDef* receivedPacket)
+{
+ switch (receivedPacket->Command)
+ {
+ case COMMAND_MSC_TEST_UNIT_READY:
+ Downstream_MSC_PacketProcessor_TestUnitReady(receivedPacket);
+ break;
+
+ case COMMAND_MSC_GET_CAPACITY:
+ Downstream_MSC_PacketProcessor_GetCapacity(receivedPacket);
+ break;
+
+ case COMMAND_MSC_BEGIN_READ:
+ Downstream_MSC_PacketProcessor_BeginRead(receivedPacket);
+ break;
+
+ default:
+ Downstream_PacketProcessor_ErrorReply(receivedPacket);
+ }
+
+}
+
+
+void Downstream_MSC_PacketProcessor_TestUnitReady(DownstreamPacketTypeDef* receivedPacket)
+{
+ if (USBH_MSC_UnitIsReady(&hUsbHostFS, 0))
+ {
+ receivedPacket->Data[0] = HAL_OK;
+ }
+ else
+ {
+ receivedPacket->Data[0] = HAL_ERROR;
+ }
+ receivedPacket->Length = DOWNSTREAM_PACKET_HEADER_LEN + 1;
+ Downstream_PacketProcessor_ClassReply(receivedPacket);
+}
+
+
+void Downstream_MSC_PacketProcessor_GetCapacity(DownstreamPacketTypeDef* receivedPacket)
+{
+ MSC_HandleTypeDef* MSC_Handle = (MSC_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
+
+ receivedPacket->Length = DOWNSTREAM_PACKET_HEADER_LEN + 8;
+ *(uint32_t*)&(receivedPacket->Data[0]) = MSC_Handle->unit[0].capacity.block_nbr;
+ *(uint32_t*)&(receivedPacket->Data[4]) = (uint32_t)MSC_Handle->unit[0].capacity.block_size;
+ Downstream_PacketProcessor_ClassReply(receivedPacket);
+}
+
+
+
+void Downstream_MSC_PacketProcessor_BeginRead(DownstreamPacketTypeDef* receivedPacket)
+{
+ uint64_t address;
+ uint32_t count;
+ MSC_HandleTypeDef* MSC_Handle = (MSC_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
+
+ if (receivedPacket->Length != (DOWNSTREAM_PACKET_HEADER_LEN + (4 * 3)))
+ {
+ Downstream_PacketProcessor_ErrorReply(receivedPacket);
+ return;
+ }
+
+ address = *(uint64_t*)&(receivedPacket->Data[0]);
+ count = *(uint32_t*)&(receivedPacket->Data[8]);
+ if ((address >= (uint64_t)MSC_Handle->unit[0].capacity.block_nbr) ||
+ ((address + count - 1) >= (uint64_t)MSC_Handle->unit[0].capacity.block_nbr))
+ {
+ Downstream_PacketProcessor_ErrorReply(receivedPacket);
+ return;
+ }
+
+ if (USBH_MSC_UnitIsReady(&hUsbHostFS, 0))
+ {
+ receivedPacket->Data[0] = HAL_OK;
+ }
+ else
+ {
+ receivedPacket->Data[0] = HAL_ERROR;
+ }
+ receivedPacket->Length = DOWNSTREAM_PACKET_HEADER_LEN + 1;
+ Downstream_TransmitPacket(receivedPacket);
+
+ USBH_MSC_Read(&hUsbHostFS,
+ 0,
+ (uint32_t)address,
+ count);
+}
+
diff --git a/Downstream/Src/downstream_statemachine.c b/Downstream/Src/downstream_statemachine.c
index 5f4924b..3a9f97a 100644
--- a/Downstream/Src/downstream_statemachine.c
+++ b/Downstream/Src/downstream_statemachine.c
@@ -9,6 +9,7 @@
#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"
@@ -21,13 +22,12 @@ InterfaceCommandClassTypeDef ConfiguredDeviceClass;
void Downstream_PacketProcessor(DownstreamPacketTypeDef* receivedPacket);
void Downstream_PacketProcessor_Interface(DownstreamPacketTypeDef* receivedPacket);
void Downstream_PacketProcessor_Interface_ReplyNotifyDevice(DownstreamPacketTypeDef* replyPacket);
-void Downstream_PacketProcessor_EmptyReply(DownstreamPacketTypeDef* replyPacket);
void Downstream_InitStateMachine(void)
{
- DownstreamState = STATE_NOT_READY;
+ DownstreamState = STATE_DEVICE_NOT_READY;
ConfiguredDeviceClass = COMMAND_CLASS_INTERFACE;
Downstream_InitSPI();
@@ -41,7 +41,7 @@ void Downstream_PacketProcessor(DownstreamPacketTypeDef* receivedPacket)
switch (receivedPacket->CommandClass)
{
case COMMAND_CLASS_INTERFACE:
- if (DownstreamState != STATE_NOT_READY)
+ if (DownstreamState > STATE_DEVICE_READY)
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
@@ -49,17 +49,18 @@ void Downstream_PacketProcessor(DownstreamPacketTypeDef* receivedPacket)
break;
case COMMAND_CLASS_MASS_STORAGE:
- if (DownstreamState != STATE_DEVICE_READY)
+ if (DownstreamState != STATE_ACTIVE)
{
- Downstream_PacketProcessor_EmptyReply(receivedPacket);
+ Downstream_PacketProcessor_ErrorReply(receivedPacket);
+ return;
}
- //Mass storage packet processor...
+ Downstream_MSC_PacketProcessor(receivedPacket);
break;
//Add other classes here...
default:
- SPI_INTERFACE_FREAKOUT_RETURN_VOID;
+ Downstream_PacketProcessor_ErrorReply(receivedPacket);
}
}
@@ -72,22 +73,27 @@ void Downstream_PacketProcessor_Interface(DownstreamPacketTypeDef* receivedPacke
case COMMAND_INTERFACE_ECHO:
Downstream_TransmitPacket(receivedPacket);
Downstream_ReceivePacket(Downstream_PacketProcessor);
- break;
+ return;
case COMMAND_INTERFACE_NOTIFY_DEVICE:
- if (ConfiguredDeviceClass != COMMAND_CLASS_INTERFACE)
+ if (DownstreamState == STATE_DEVICE_READY)
{
Downstream_PacketProcessor_Interface_ReplyNotifyDevice(receivedPacket);
+ return;
}
- else
+
+ if (DownstreamState == STATE_DEVICE_NOT_READY)
{
+ DownstreamState = STATE_WAIT_DEVICE_READY;
Downstream_ReleasePacket(receivedPacket);
- DownstreamState = STATE_WAIT_DEVICE_READY_CALLBACK;
+ return;
}
- break;
+ Downstream_PacketProcessor_ErrorReply(receivedPacket);
+ return;
+
default:
- SPI_INTERFACE_FREAKOUT_RETURN_VOID;
+ Downstream_PacketProcessor_ErrorReply(receivedPacket);
}
}
@@ -100,60 +106,85 @@ void Downstream_PacketProcessor_Interface_ReplyNotifyDevice(DownstreamPacketType
replyPacket->Data[0] = ConfiguredDeviceClass;
Downstream_TransmitPacket(replyPacket);
- DownstreamState = STATE_DEVICE_READY;
+ DownstreamState = STATE_ACTIVE;
Downstream_ReceivePacket(Downstream_PacketProcessor);
}
-//An empty reply implies and error processing class-specific requests.
-void Downstream_PacketProcessor_EmptyReply(DownstreamPacketTypeDef* replyPacket)
+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;
+ InterfaceCommandClassTypeDef newActiveClass = COMMAND_CLASS_INTERFACE;
+ //Called from USB interrupt
if (id == HOST_USER_DISCONNECTION)
{
- DownstreamState = STATE_NOT_READY;
+ DownstreamState = STATE_DEVICE_NOT_READY;
return;
}
-
+ //Called from main(). Beware pre-emption!
if (id == HOST_USER_CLASS_ACTIVE)
{
- if (DownstreamState > STATE_WAIT_DEVICE_READY_CALLBACK)
- {
- SPI_INTERFACE_FREAKOUT_RETURN_VOID;
- }
-
switch (phost->pActiveClass->ClassCode)
{
case USB_MSC_CLASS:
- newActiveClass = COMMAND_CLASS_MASS_STORAGE;
+ if (Downstream_MSC_ApproveConnectedDevice() == HAL_OK)
+ {
+ newActiveClass = COMMAND_CLASS_MASS_STORAGE;
+ }
break;
//Add other classes here...
-
- default:
- newActiveClass = COMMAND_CLASS_INTERFACE;
}
+ //To change device class, we must reboot.
if ((ConfiguredDeviceClass != COMMAND_CLASS_INTERFACE) &&
- (ConfiguredDeviceClass != newActiveClass)) //To change device class, we must reboot.
+ (ConfiguredDeviceClass != newActiveClass))
{
- SPI_INTERFACE_FREAKOUT_RETURN_VOID;
+ SPI_INTERFACE_FREAKOUT_NO_RETURN;
+ DownstreamState = STATE_ERROR;
+ return;
}
+
+ if (newActiveClass == COMMAND_CLASS_INTERFACE)
+ {
+ return;
+ }
+
ConfiguredDeviceClass = newActiveClass;
- if (DownstreamState == STATE_WAIT_DEVICE_READY_CALLBACK)
+ 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;
}
}
diff --git a/Upstream/.cproject b/Upstream/.cproject
index 6331ec4..d430332 100755
--- a/Upstream/.cproject
+++ b/Upstream/.cproject
@@ -153,7 +153,7 @@
-
+
@@ -239,7 +239,21 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Upstream/.settings/language.settings.xml b/Upstream/.settings/language.settings.xml
index e0f7243..c8d28e9 100755
--- a/Upstream/.settings/language.settings.xml
+++ b/Upstream/.settings/language.settings.xml
@@ -16,7 +16,7 @@
-
+
diff --git a/Upstream/Inc/upstream_interface_def.h b/Upstream/Inc/upstream_interface_def.h
index ae7eb24..24e12de 100644
--- a/Upstream/Inc/upstream_interface_def.h
+++ b/Upstream/Inc/upstream_interface_def.h
@@ -26,7 +26,9 @@
typedef enum
{
COMMAND_CLASS_INTERFACE,
- COMMAND_CLASS_MASS_STORAGE
+ COMMAND_CLASS_MASS_STORAGE,
+ //...
+ COMMAND_CLASS_ERROR
}
InterfaceCommandClassTypeDef;