From 674cb621a718277795729ee78affb1b9bcde63f6 Mon Sep 17 00:00:00 2001 From: Robert Fisk Date: Sat, 8 Aug 2015 12:13:44 +1200 Subject: [PATCH] Initial implementation of Downstream SPI interface and state machine. --- .../Src/stm32f4xx_hal_hcd.c | 4 +- Downstream/Inc/downstream_interface_def.h | 51 +++ Downstream/Inc/downstream_spi.h | 92 +++++ Downstream/Inc/downstream_statemachine.h | 30 ++ Downstream/Inc/upstream_interface_def.h | 45 --- Downstream/Inc/upstream_spi.h | 77 ---- .../Class/MSC/Src/usbh_msc_bot.c | 4 +- Downstream/Src/downstream_spi.c | 344 ++++++++++++++++++ Downstream/Src/downstream_statemachine.c | 160 ++++++++ Downstream/Src/main.c | 4 +- Downstream/Src/upstream_spi.c | 49 --- Downstream/Src/usb_host.c | 43 +-- 12 files changed, 685 insertions(+), 218 deletions(-) create mode 100644 Downstream/Inc/downstream_interface_def.h create mode 100644 Downstream/Inc/downstream_spi.h create mode 100644 Downstream/Inc/downstream_statemachine.h delete mode 100644 Downstream/Inc/upstream_interface_def.h delete mode 100644 Downstream/Inc/upstream_spi.h create mode 100644 Downstream/Src/downstream_spi.c create mode 100644 Downstream/Src/downstream_statemachine.c delete mode 100644 Downstream/Src/upstream_spi.c diff --git a/Downstream/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_hcd.c b/Downstream/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_hcd.c index 8185987..22ed0db 100644 --- a/Downstream/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_hcd.c +++ b/Downstream/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_hcd.c @@ -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; diff --git a/Downstream/Inc/downstream_interface_def.h b/Downstream/Inc/downstream_interface_def.h new file mode 100644 index 0000000..d0f2947 --- /dev/null +++ b/Downstream/Inc/downstream_interface_def.h @@ -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_ */ diff --git a/Downstream/Inc/downstream_spi.h b/Downstream/Inc/downstream_spi.h new file mode 100644 index 0000000..843185f --- /dev/null +++ b/Downstream/Inc/downstream_spi.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_ */ diff --git a/Downstream/Inc/downstream_statemachine.h b/Downstream/Inc/downstream_statemachine.h new file mode 100644 index 0000000..8fce582 --- /dev/null +++ b/Downstream/Inc/downstream_statemachine.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_ */ diff --git a/Downstream/Inc/upstream_interface_def.h b/Downstream/Inc/upstream_interface_def.h deleted file mode 100644 index fd5e6b6..0000000 --- a/Downstream/Inc/upstream_interface_def.h +++ /dev/null @@ -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_ */ diff --git a/Downstream/Inc/upstream_spi.h b/Downstream/Inc/upstream_spi.h deleted file mode 100644 index d63c2ea..0000000 --- a/Downstream/Inc/upstream_spi.h +++ /dev/null @@ -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_ */ diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c index ffa84cf..2aef67f 100644 --- a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c +++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c @@ -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? diff --git a/Downstream/Src/downstream_spi.c b/Downstream/Src/downstream_spi.c new file mode 100644 index 0000000..561ccb8 --- /dev/null +++ b/Downstream/Src/downstream_spi.c @@ -0,0 +1,344 @@ +/* + * upstream_spi.c + * + * Created on: 24/07/2015 + * Author: Robert Fisk + */ + + +#include +#include +#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; +} + diff --git a/Downstream/Src/downstream_statemachine.c b/Downstream/Src/downstream_statemachine.c new file mode 100644 index 0000000..5f4924b --- /dev/null +++ b/Downstream/Src/downstream_statemachine.c @@ -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; + } +} + diff --git a/Downstream/Src/main.c b/Downstream/Src/main.c index f74873d..3b5873e 100644 --- a/Downstream/Src/main.c +++ b/Downstream/Src/main.c @@ -31,10 +31,10 @@ ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ +#include #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) { diff --git a/Downstream/Src/upstream_spi.c b/Downstream/Src/upstream_spi.c deleted file mode 100644 index cb26532..0000000 --- a/Downstream/Src/upstream_spi.c +++ /dev/null @@ -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); -} - - diff --git a/Downstream/Src/usb_host.c b/Downstream/Src/usb_host.c index e5c90ad..e3ef322 100644 --- a/Downstream/Src/usb_host.c +++ b/Downstream/Src/usb_host.c @@ -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; - } -} - -/** - * @} - */ /** * @}