parent
b271e038a3
commit
674cb621a7
@ -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_ */
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in new issue