Initial implementation of Downstream SPI interface and state machine.

pull/7/head
Robert Fisk 9 years ago
parent b271e038a3
commit 674cb621a7

@ -611,7 +611,7 @@ __weak void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t
*
@verbatim
===============================================================================
##### Peripheral Control functions #####
##### Host Control functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to control the HCD data
@ -1087,7 +1087,7 @@ static void HCD_RXQLVL_IRQHandler(HCD_HandleTypeDef *hhcd)
if ((pktcnt > 0) && (hhcd->hc[channelnum].xfer_buff != (void *)0))
{
USB_ReadPacket(hhcd->Instance, hhcd->hc[channelnum].xfer_buff, pktcnt);
USB_ReadPacket(hhcd->Instance, hhcd->hc[channelnum].xfer_buff, pktcnt); //Todo: buffer overflow here!
/*manage multiple Xfer */
hhcd->hc[channelnum].xfer_buff += pktcnt;

@ -0,0 +1,51 @@
/*
* downstream_interface_def.h
*
* Created on: 24/07/2015
* Author: Robert Fisk
*/
#ifndef INC_DOWNSTREAM_INTERFACE_DEF_H_
#define INC_DOWNSTREAM_INTERFACE_DEF_H_
//***************
// Attention!
// Keep this file synchronised with downstream_interface_def.h
// in the Upstream project.
//***************
#define COMMAND_CLASS_DATA_FLAG 0x80
#define COMMAND_CLASS_MASK ((uint8_t)(~COMMAND_CLASS_DATA_FLAG))
typedef enum
{
COMMAND_CLASS_INTERFACE,
COMMAND_CLASS_MASS_STORAGE,
}
InterfaceCommandClassTypeDef;
typedef enum
{
COMMAND_INTERFACE_ECHO, //Returns echo packet including all data
COMMAND_INTERFACE_NOTIFY_DEVICE //Returns COMMAND_CLASS_*** byte when downstream USB device is connected
}
InterfaceCommandInterfaceTypeDef;
typedef enum
{
COMMAND_MSC_TEST_UNIT_READY, //Returns HAL_StatusTypeDef result
COMMAND_MSC_GET_CAPACITY, //Returns uint32_t blk_nbr, uint32_t blk_size
COMMAND_MSC_BEGIN_READ, //Returns HAL_StatusTypeDef result, then data stream
COMMAND_MSC_BEGIN_WRITE, //Returns HAL_OK, HAL_ERROR if medium not present, HAL_BUSY if write-protected result, then waits for data stream
}
InterfaceCommandMscTypeDef;
#endif /* INC_DOWNSTREAM_INTERFACE_DEF_H_ */

@ -0,0 +1,92 @@
/*
* downstream_spi.h
*
* Created on: 24/07/2015
* Author: Robert Fisk
*/
#ifndef INC_DOWNSTREAM_SPI_H_
#define INC_DOWNSTREAM_SPI_H_
#include "usbh_config.h"
#define DOWNSTREAM_PACKET_HEADER_LEN (2) //Min length = CommandClass & Command bytes
#define DOWNSTREAM_PACKET_LEN (DOWNSTREAM_PACKET_HEADER_LEN + USBH_MAX_DATA_BUFFER)
#define DOWNSTREAM_PACKET_LEN_MIN (DOWNSTREAM_PACKET_HEADER_LEN)
#define SPI_INTERFACE_FREAKOUT_RETURN_VOID \
do { \
while (1); \
/*UpstreamInterfaceState = INTERFACE_STATE_ERROR;*/ \
/*return;*/ \
} while (0);
#define SPI_INTERFACE_FREAKOUT_RETURN_HAL_ERROR \
do { \
while (1); \
/*UpstreamInterfaceState = INTERFACE_STATE_ERROR;*/ \
/*return HAL_ERROR;*/ \
} while (0);
#define SPI_INTERFACE_FREAKOUT_NO_RETURN \
do { \
while (1); \
/*while (1);*/ \
} while (0);
typedef enum
{
DOWNSTREAM_INTERFACE_IDLE,
DOWNSTREAM_INTERFACE_RX_SIZE_WAIT,
DOWNSTREAM_INTERFACE_RX_PACKET_WAIT,
DOWNSTREAM_INTERFACE_TX_SIZE_WAIT,
DOWNSTREAM_INTERFACE_TX_PACKET_WAIT,
DOWNSTREAM_INTERFACE_ERROR
}
InterfaceStateTypeDef;
typedef enum
{
NOT_BUSY,
BUSY
}
PacketBusyTypeDef;
typedef struct
{
PacketBusyTypeDef Busy; //Everything after Busy should be word-aligned
uint16_t Length __ALIGN_END; //Packet length includes CommandClass, Command, and Data
uint8_t CommandClass;
uint8_t Command;
uint8_t Data[USBH_MAX_DATA_BUFFER]; //Should (must?) be word-aligned, for USB copy routine
uint8_t RxCrc;
}
DownstreamPacketTypeDef;
typedef void (*FreePacketCallbackTypeDef)(DownstreamPacketTypeDef* freePacket);
typedef void (*SpiPacketReceivedCallbackTypeDef)(DownstreamPacketTypeDef* receivedPacket);
void Downstream_InitSPI(void);
HAL_StatusTypeDef Downstream_GetFreePacket(FreePacketCallbackTypeDef callback);
DownstreamPacketTypeDef* Downstream_GetFreePacketImmediately(void);
void Downstream_ReleasePacket(DownstreamPacketTypeDef* packetToRelease);
HAL_StatusTypeDef Downstream_ReceivePacket(SpiPacketReceivedCallbackTypeDef callback);
HAL_StatusTypeDef Downstream_TransmitPacket(DownstreamPacketTypeDef* packetToWrite);
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi);
#endif /* INC_DOWNSTREAM_SPI_H_ */

@ -0,0 +1,30 @@
/*
* downstream_statemachine.h
*
* Created on: 2/08/2015
* Author: Robert Fisk
*/
#ifndef INC_DOWNSTREAM_STATEMACHINE_H_
#define INC_DOWNSTREAM_STATEMACHINE_H_
#include "usbh_def.h"
typedef enum
{
STATE_NOT_READY,
STATE_WAIT_DEVICE_READY_CALLBACK,
STATE_DEVICE_READY,
STATE_ERROR
} DownstreamStateTypeDef;
void Downstream_InitStateMachine(void);
void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id);
#endif /* INC_DOWNSTREAM_STATEMACHINE_H_ */

@ -1,45 +0,0 @@
/*
* upstream_interface_def.h
*
* Created on: 24/07/2015
* Author: Robert Fisk
*/
#ifndef INC_UPSTREAM_INTERFACE_DEF_H_
#define INC_UPSTREAM_INTERFACE_DEF_H_
//***************
// Attention!
// Keep this file synchronised with downstream_interface_def.h
// in the Upstream project.
//***************
#define COMMAND_CLASS_DATA_FLAG 0x80
#define COMMAND_CLASS_MASK ((uint8_t)(~COMMAND_CLASS_DATA_FLAG))
typedef enum
{
COMMAND_CLASS_INTERFACE = 0,
COMMAND_CLASS_MASS_STORAGE = 1,
COMMAND_CLASS_MAX = 2,
}
InterfaceCommandClassTypeDef;
typedef enum
{
COMMAND_MSC_TEST_UNIT_READY = 0, //Returns HAL_StatusTypeDef result
COMMAND_MSC_GET_CAPACITY = 2, //Returns uint32_t blk_nbr, uint32_t blk_size
COMMAND_MSC_BEGIN_READ = 3, //Returns HAL_StatusTypeDef result, then data stream
COMMAND_MSC_BEGIN_WRITE = 4, //Returns HAL_OK, HAL_ERROR if medium not present, HAL_BUSY if write-protected result, then waits for data stream
COMMAND_MSC_MAX = 5,
}
InterfaceCommandMscTypeDef;
#endif /* INC_UPSTREAM_INTERFACE_DEF_H_ */

@ -1,77 +0,0 @@
/*
* upstream_spi.h
*
* Created on: 24/07/2015
* Author: Robert Fisk
*/
#ifndef INC_UPSTREAM_SPI_H_
#define INC_UPSTREAM_SPI_H_
#include "usbh_config.h"
#define UPSTREAM_PACKET_HEADER_LEN (2) //Min length = CommandClass & Command bytes
#define UPSTREAM_PACKET_LEN (UPSTREAM_PACKET_HEADER_LEN + USBH_MAX_DATA_BUFFER)
#define UPSTREAM_PACKET_LEN_MIN (UPSTREAM_PACKET_HEADER_LEN)
#define SPI_INTERFACE_FREAKOUT_VOID \
do { \
while (1); \
/*UpstreamInterfaceState = INTERFACE_STATE_ERROR;*/ \
/*return;*/ \
} while (0);
#define SPI_INTERFACE_FREAKOUT_HAL_ERROR \
do { \
while (1); \
/*UpstreamInterfaceState = INTERFACE_STATE_ERROR;*/ \
/*return HAL_ERROR;*/ \
} while (0);
typedef enum
{
INTERFACE_STATE_RESET = 0,
// INTERFACE_STATE_WAITING_CLIENT = 1,
// INTERFACE_STATE_IDLE = 2,
// INTERFACE_STATE_TX_SIZE_WAIT = 3,
// INTERFACE_STATE_TX_SIZE = 4,
// INTERFACE_STATE_TX_PACKET_WAIT = 5,
// INTERFACE_STATE_TX_PACKET = 6,
// INTERFACE_STATE_RX_SIZE_WAIT = 7,
// INTERFACE_STATE_RX_SIZE = 8,
// INTERFACE_STATE_RX_PACKET_WAIT = 9,
// INTERFACE_STATE_RX_PACKET = 10,
INTERFACE_STATE_ERROR = 11
} InterfaceStateTypeDef;
typedef enum
{
NOT_BUSY = 0,
BUSY = 1
} PacketBusyTypeDef;
typedef struct
{
PacketBusyTypeDef Busy; //Everything after Busy should be word-aligned
uint16_t Length __ALIGN_END; //Packet length includes CommandClass, Command, and Data
uint8_t CommandClass;
uint8_t Command;
uint8_t Data[USBH_MAX_DATA_BUFFER]; //Should (must?) be word-aligned, for USB copy routine
uint8_t RxCrc;
}
UpstreamPacketTypeDef;
void Upstream_InitInterface(void);
#endif /* INC_UPSTREAM_SPI_H_ */

@ -240,7 +240,7 @@ USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun)
break;
case BOT_DATA_IN:
/* Send first packet */
/* Get first packet */
USBH_BulkReceiveData (phost,
MSC_Handle->hbot.pbuf,
MSC_Handle->InEpSize , //Todo: Possible buffer overflow here?
@ -270,7 +270,7 @@ USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun)
/* More Data To be Received */
if(MSC_Handle->hbot.cbw.field.DataTransferLength > 0)
{
/* Send next packet */
/* Get next packet */
USBH_BulkReceiveData (phost,
MSC_Handle->hbot.pbuf,
MSC_Handle->InEpSize , //Todo: Possible buffer overflow here?

@ -0,0 +1,344 @@
/*
* upstream_spi.c
*
* Created on: 24/07/2015
* Author: Robert Fisk
*/
#include <downstream_interface_def.h>
#include <downstream_spi.h>
#include "board_config.h"
SPI_HandleTypeDef Hspi1;
DownstreamPacketTypeDef DownstreamPacket0;
DownstreamPacketTypeDef DownstreamPacket1;
DownstreamPacketTypeDef* CurrentWorkingPacket;
InterfaceStateTypeDef DownstreamInterfaceState;
FreePacketCallbackTypeDef PendingFreePacketCallback; //Indicates someone is waiting for a packet buffer to become available
SpiPacketReceivedCallbackTypeDef ReceivePacketCallback; //Indicates someone is waiting for a received packet
void SPI1_Init(void);
HAL_StatusTypeDef Downstream_CheckPreparePacketReception(void);
void Downstream_PreparePacketReception(DownstreamPacketTypeDef* freePacket);
void Downstream_InitSPI(void)
{
SPI1_Init();
DownstreamPacket0.Busy = NOT_BUSY;
DownstreamPacket1.Busy = NOT_BUSY;
//NextTxPacket = NULL;
PendingFreePacketCallback = NULL;
ReceivePacketCallback = NULL;
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_IDLE;
}
void SPI1_Init(void)
{
Hspi1.Instance = SPI1;
Hspi1.Init.Mode = SPI_MODE_SLAVE;
Hspi1.Init.Direction = SPI_DIRECTION_2LINES;
Hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
Hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
Hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
Hspi1.Init.NSS = SPI_NSS_HARD_INPUT;
Hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
Hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
Hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
Hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_ENABLE;
Hspi1.Init.CRCPolynomial = SPI_CRC_DEFAULTPOLYNOMIAL;
HAL_SPI_Init(&Hspi1);
}
//Used by...
HAL_StatusTypeDef Downstream_GetFreePacket(FreePacketCallbackTypeDef callback)
{
//Sanity checks
if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
{
SPI_INTERFACE_FREAKOUT_RETURN_HAL_ERROR;
}
//Do we already have a queued callback?
if (PendingFreePacketCallback != NULL)
{
SPI_INTERFACE_FREAKOUT_RETURN_HAL_ERROR;
}
//Check if there is a free buffer now
if (DownstreamPacket0.Busy == NOT_BUSY)
{
DownstreamPacket0.Busy = BUSY;
callback(&DownstreamPacket0);
return HAL_OK;
}
if (DownstreamPacket1.Busy == NOT_BUSY)
{
DownstreamPacket1.Busy = BUSY;
callback(&DownstreamPacket1);
return HAL_OK;
}
//Otherwise save requested address for when a buffer becomes free in the future
PendingFreePacketCallback = callback;
return HAL_OK;
}
//DownstreamPacketTypeDef* Downstream_GetFreePacketImmediately(void)
//{
// //Sanity checks
// if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
// {
// SPI_INTERFACE_FREAKOUT_RETURN_HAL_ERROR;
// }
//
// //We are expecting a free buffer now
// if (DownstreamPacket0.Busy == NOT_BUSY)
// {
// DownstreamPacket0.Busy = BUSY;
// return &DownstreamPacket0;
// }
// if (DownstreamPacket1.Busy == NOT_BUSY)
// {
// DownstreamPacket1.Busy = BUSY;
// return &DownstreamPacket1;
// }
//
// //Should not happen:
// SPI_INTERFACE_FREAKOUT_NO_RETURN;
//}
//Used by...
void Downstream_ReleasePacket(DownstreamPacketTypeDef* packetToRelease)
{
FreePacketCallbackTypeDef tempCallback;
if ((packetToRelease != &DownstreamPacket0) &&
(packetToRelease != &DownstreamPacket1))
{
SPI_INTERFACE_FREAKOUT_RETURN_HAL_ERROR;
}
if (PendingFreePacketCallback != NULL)
{
tempCallback = PendingFreePacketCallback; //In extreme situations, running this callback can trigger another request for a free packet,
PendingFreePacketCallback = NULL; //thereby causing GetFreePacket to freak out. So we need to clear the callback indicator first.
tempCallback(packetToRelease);
}
else
{
packetToRelease->Busy = NOT_BUSY;
}
}
//Used by Downstream state machine (and USB classes?).
//Ok to call when idle or transmitting.
//Not OK to call when receiving or waiting for downstream reply.
HAL_StatusTypeDef Downstream_ReceivePacket(SpiPacketReceivedCallbackTypeDef callback)
{
if (ReceivePacketCallback != NULL)
{
SPI_INTERFACE_FREAKOUT_RETURN_HAL_ERROR;
}
ReceivePacketCallback = callback;
return Downstream_CheckPreparePacketReception();
}
//Internal use only
HAL_StatusTypeDef Downstream_CheckPreparePacketReception(void)
{
if (DownstreamInterfaceState > DOWNSTREAM_INTERFACE_TX_PACKET_WAIT)
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_IDLE)
{
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_RX_SIZE_WAIT;
return Downstream_GetFreePacket(Downstream_PreparePacketReception);
}
return HAL_OK;
}
//Internal use only
void Downstream_PreparePacketReception(DownstreamPacketTypeDef* freePacket)
{
if (DownstreamInterfaceState != DOWNSTREAM_INTERFACE_RX_SIZE_WAIT)
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
CurrentWorkingPacket = freePacket;
//CurrentWorkingPacket->Length = 0;
//if (HAL_SPI_TransmitReceive_DMA(... ????
if (HAL_SPI_Receive_DMA(&Hspi1,
(uint8_t*)&CurrentWorkingPacket->Length,
(2 + 1)) != HAL_OK) //"When the CRC feature is enabled the pData Length must be Size + 1"
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
UPSTREAM_TX_REQUEST_ASSERT;
}
//Called at the end of the SPI RX DMA transfer,
//at DMA2 interrupt priority. Assume *hspi points to our hspi1.
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
SpiPacketReceivedCallbackTypeDef tempPacketCallback;
UPSTREAM_TX_REQUEST_DEASSERT;
if ((DownstreamInterfaceState != DOWNSTREAM_INTERFACE_RX_SIZE_WAIT) &&
(DownstreamInterfaceState != DOWNSTREAM_INTERFACE_RX_PACKET_WAIT))
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_RX_SIZE_WAIT)
{
if ((CurrentWorkingPacket->Length < DOWNSTREAM_PACKET_LEN_MIN) ||
(CurrentWorkingPacket->Length > DOWNSTREAM_PACKET_LEN))
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_RX_PACKET_WAIT;
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"
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
UPSTREAM_TX_REQUEST_ASSERT;
return;
}
if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_RX_PACKET_WAIT)
{
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_IDLE;
if (ReceivePacketCallback == NULL)
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
//Packet processor may want to receive another packet immediately,
//so clear ReceivePacketCallback before the call.
//It is the callback's responsibility to release the packet buffer we are passing to it!
tempPacketCallback = ReceivePacketCallback;
ReceivePacketCallback = NULL;
tempPacketCallback(CurrentWorkingPacket);
}
}
//Used by Downstream state machine (and USB classes?).
//Call when idle only.
HAL_StatusTypeDef Downstream_TransmitPacket(DownstreamPacketTypeDef* packetToWrite)
{
//Sanity checks
if ((packetToWrite != &DownstreamPacket0) &&
(packetToWrite != &DownstreamPacket1))
{
SPI_INTERFACE_FREAKOUT_RETURN_HAL_ERROR;
}
if ((packetToWrite->Busy != BUSY) ||
(packetToWrite->Length < DOWNSTREAM_PACKET_LEN_MIN) ||
(packetToWrite->Length > DOWNSTREAM_PACKET_LEN))
{
SPI_INTERFACE_FREAKOUT_RETURN_HAL_ERROR;
}
if (DownstreamInterfaceState != DOWNSTREAM_INTERFACE_IDLE)
{
SPI_INTERFACE_FREAKOUT_RETURN_HAL_ERROR;
}
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_TX_SIZE_WAIT;
CurrentWorkingPacket = packetToWrite;
if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
(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"
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
UPSTREAM_TX_REQUEST_ASSERT;
return HAL_OK;
}
//Called at the end of the SPI TxRx DMA transfer,
//at DMA2 interrupt priority. Assume *hspi points to our hspi1.
//We use TxRx while sending our reply packet to check if Upstream was trying
//to send us a packet at the same time.
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
UPSTREAM_TX_REQUEST_DEASSERT;
if (DownstreamInterfaceState != DOWNSTREAM_INTERFACE_TX_SIZE_WAIT)
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
if (CurrentWorkingPacket->Length != 0)
{
//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...
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_TX_PACKET_WAIT;
if ((HAL_SPI_Transmit_DMA(&Hspi1,
&CurrentWorkingPacket->CommandClass,
CurrentWorkingPacket->Length)) != HAL_OK)
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
UPSTREAM_TX_REQUEST_ASSERT;
}
//Called at the end of the SPI TX DMA transfer,
//at DMA2 interrupt priority. Assume *hspi points to our hspi1.
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
UPSTREAM_TX_REQUEST_DEASSERT;
if (DownstreamInterfaceState != DOWNSTREAM_INTERFACE_TX_PACKET_WAIT)
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_IDLE;
Downstream_ReleasePacket(CurrentWorkingPacket);
if (ReceivePacketCallback != NULL)
{
Downstream_CheckPreparePacketReception();
}
}
//Something bad happened! Possibly CRC error...
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}

@ -0,0 +1,160 @@
/*
* 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 "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_PacketProcessor_EmptyReply(DownstreamPacketTypeDef* replyPacket);
void Downstream_InitStateMachine(void)
{
DownstreamState = STATE_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_NOT_READY)
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
Downstream_PacketProcessor_Interface(receivedPacket);
break;
case COMMAND_CLASS_MASS_STORAGE:
if (DownstreamState != STATE_DEVICE_READY)
{
Downstream_PacketProcessor_EmptyReply(receivedPacket);
}
//Mass storage packet processor...
break;
//Add other classes here...
default:
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
}
void Downstream_PacketProcessor_Interface(DownstreamPacketTypeDef* receivedPacket)
{
switch (receivedPacket->Command)
{
case COMMAND_INTERFACE_ECHO:
Downstream_TransmitPacket(receivedPacket);
Downstream_ReceivePacket(Downstream_PacketProcessor);
break;
case COMMAND_INTERFACE_NOTIFY_DEVICE:
if (ConfiguredDeviceClass != COMMAND_CLASS_INTERFACE)
{
Downstream_PacketProcessor_Interface_ReplyNotifyDevice(receivedPacket);
}
else
{
Downstream_ReleasePacket(receivedPacket);
DownstreamState = STATE_WAIT_DEVICE_READY_CALLBACK;
}
break;
default:
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
}
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_DEVICE_READY;
Downstream_ReceivePacket(Downstream_PacketProcessor);
}
//An empty reply implies and error processing class-specific requests.
void Downstream_PacketProcessor_EmptyReply(DownstreamPacketTypeDef* replyPacket)
{
replyPacket->Length = DOWNSTREAM_PACKET_HEADER_LEN;
Downstream_TransmitPacket(replyPacket);
Downstream_ReceivePacket(Downstream_PacketProcessor);
}
void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id)
{
InterfaceCommandClassTypeDef newActiveClass;
if (id == HOST_USER_DISCONNECTION)
{
DownstreamState = STATE_NOT_READY;
return;
}
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;
break;
//Add other classes here...
default:
newActiveClass = COMMAND_CLASS_INTERFACE;
}
if ((ConfiguredDeviceClass != COMMAND_CLASS_INTERFACE) &&
(ConfiguredDeviceClass != newActiveClass)) //To change device class, we must reboot.
{
SPI_INTERFACE_FREAKOUT_RETURN_VOID;
}
ConfiguredDeviceClass = newActiveClass;
if (DownstreamState == STATE_WAIT_DEVICE_READY_CALLBACK)
{
Downstream_GetFreePacket(Downstream_PacketProcessor_Interface_ReplyNotifyDevice);
}
return;
}
}

@ -31,10 +31,10 @@
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <downstream_spi.h>
#include "stm32f4xx_hal.h"
#include "usb_host.h"
#include "board_config.h"
#include "upstream_spi.h"
@ -58,7 +58,7 @@ int main(void)
GPIO_Init();
USB_Host_Init();
Upstream_InitInterface();
Downstream_InitSPI();
while (1)
{

@ -1,49 +0,0 @@
/*
* upstream_spi.c
*
* Created on: 24/07/2015
* Author: Robert Fisk
*/
#include "upstream_spi.h"
#include "upstream_interface_def.h"
SPI_HandleTypeDef Hspi1;
InterfaceStateTypeDef UpstreamInterfaceState;
void SPI1_Init(void);
void Upstream_InitInterface(void)
{
UpstreamInterfaceState = INTERFACE_STATE_RESET;
SPI1_Init();
}
void SPI1_Init(void)
{
Hspi1.Instance = SPI1;
Hspi1.Init.Mode = SPI_MODE_SLAVE;
Hspi1.Init.Direction = SPI_DIRECTION_2LINES;
Hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
Hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
Hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
Hspi1.Init.NSS = SPI_NSS_HARD_INPUT;
Hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
Hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
Hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
Hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_ENABLE;
Hspi1.Init.CRCPolynomial = SPI_CRC_DEFAULTPOLYNOMIAL;
HAL_SPI_Init(&Hspi1);
}

@ -36,17 +36,10 @@
#include "usb_host.h"
#include "usbh_core.h"
#include "usbh_msc.h"
#include "downstream_statemachine.h"
/* USB Host Core handle declaration */
USBH_HandleTypeDef hUsbHostFS;
ApplicationTypeDef App_state = APPLICATION_IDLE;
/*
* user callback declaration
*/
static void USBH_UserProcess (USBH_HandleTypeDef *phost, uint8_t id);
@ -54,7 +47,7 @@ static void USBH_UserProcess (USBH_HandleTypeDef *phost, uint8_t id);
void USB_Host_Init(void)
{
/* Init Host Library,Add Supported Class and Start the library*/
USBH_Init(&hUsbHostFS, USBH_UserProcess, HOST_FS);
USBH_Init(&hUsbHostFS, Downstream_HostUserCallback, HOST_FS);
USBH_RegisterClass(&hUsbHostFS, USBH_MSC_CLASS);
@ -70,39 +63,7 @@ void USB_Host_Process()
USBH_Process(&hUsbHostFS);
}
/*
* user callback definition
*/
static void USBH_UserProcess (USBH_HandleTypeDef *phost, uint8_t id)
{
switch(id)
{
case HOST_USER_SELECT_CONFIGURATION:
//usbh_core.c only stored the first configuration returned by the device,
//so we don't really have a choice of configurations at this point!
break;
case HOST_USER_DISCONNECTION:
App_state = APPLICATION_DISCONNECT;
break;
case HOST_USER_CLASS_ACTIVE:
App_state = APPLICATION_READY;
break;
case HOST_USER_CONNECTION:
App_state = APPLICATION_START;
break;
default:
break;
}
}
/**
* @}
*/
/**
* @}

Loading…
Cancel
Save