firmware_update

master
Ivan Olenichev 3 years ago
parent e5929ea3d8
commit 9dfd5e6009

@ -0,0 +1,175 @@
/**
******************************************************************************
* File Name : stm32f4xx_hal_msp.c
* Date : 03/02/2015 20:27:00
* Description : This file provides code for the MSP Initialization
* and de-Initialization codes.
******************************************************************************
*
* COPYRIGHT(c) 2015 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*
* Modifications by Robert Fisk
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#include "interrupts.h"
#include "board_config.h"
DMA_HandleTypeDef spiTxDmaHandle;
DMA_HandleTypeDef spiRxDmaHandle;
/**
* Initializes the Global MSP.
*/
void HAL_MspInit(void)
{
// HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
//
// /* System interrupt init*/
///* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, INT_PRIORITY_SYSTICK, 0);
}
uint32_t HAL_GetHSECrystalFreqMHz(void)
{
if ((BOARD_REV_ID_PORT->IDR & BOARD_REV_PIN_MASK) < BOARD_REV_1_0_BETA_3)
{
return BOARD_REV_1_0_BETA_FREQ;
}
else
{
return BOARD_REV_1_0_BETA_3_FREQ;
}
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hspi->Instance==SPI1)
{
/* Peripheral clock enable */
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA4 ------> GPIO manual slave select
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PA7 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
SPI1_NSS_DEASSERT;
GPIO_InitStruct.Pin = SPI1_NSS_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(SPI1_NSS_PORT, &GPIO_InitStruct);
//Configure downstream request pin and interrupt
GPIO_InitStruct.Pin = DOWNSTREAM_TX_OK_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT | GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(DOWNSTREAM_TX_OK_PORT, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI3_IRQn, INT_PRIORITY_EXT3I, 0);
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
//Prepare Tx DMA stream
hspi->hdmatx = &spiTxDmaHandle;
spiTxDmaHandle.Instance = DMA2_Stream3;
spiTxDmaHandle.Parent = hspi;
spiTxDmaHandle.Init.Channel = DMA_CHANNEL_3;
spiTxDmaHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;
spiTxDmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;
spiTxDmaHandle.Init.MemInc = DMA_MINC_ENABLE;
spiTxDmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
spiTxDmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
spiTxDmaHandle.Init.Mode = DMA_NORMAL;
spiTxDmaHandle.Init.Priority = DMA_PRIORITY_MEDIUM;
spiTxDmaHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&spiTxDmaHandle);
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, INT_PRIORITY_SPI_DMA, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
//Prepare Rx DMA stream
hspi->hdmarx = &spiRxDmaHandle;
spiRxDmaHandle.Instance = DMA2_Stream2;
spiRxDmaHandle.Parent = hspi;
spiRxDmaHandle.Init.Channel = DMA_CHANNEL_3;
spiRxDmaHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;
spiRxDmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;
spiRxDmaHandle.Init.MemInc = DMA_MINC_ENABLE;
spiRxDmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
spiRxDmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
spiRxDmaHandle.Init.Mode = DMA_NORMAL;
spiRxDmaHandle.Init.Priority = DMA_PRIORITY_MEDIUM;
spiRxDmaHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&spiRxDmaHandle);
HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, INT_PRIORITY_SPI_DMA, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
}
}
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{
if(hspi->Instance==SPI1)
{
/* Peripheral clock disable */
__HAL_RCC_SPI1_CLK_DISABLE();
__HAL_RCC_DMA2_CLK_DISABLE();
/**SPI1 GPIO Configuration
PA4 ------> SPI1_NSS
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PA7 ------> SPI1_MOSI
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
HAL_DMA_DeInit(&spiTxDmaHandle);
HAL_DMA_DeInit(&spiRxDmaHandle);
HAL_NVIC_DisableIRQ(DMA2_Stream3_IRQn);
HAL_NVIC_DisableIRQ(DMA2_Stream2_IRQn);
}
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -0,0 +1,129 @@
/**
******************************************************************************
* @file stm32f4xx_it.c
* @date 03/02/2015 20:27:00
* @brief Interrupt Service Routines.
******************************************************************************
*
* COPYRIGHT(c) 2015 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*
* Modifications by Robert Fisk
*/
/* Includes ------------------------------------------------------------------*/
#include "interrupts.h"
#include "upstream_spi.h"
#include "stm32f4xx_hal.h"
#include "board_config.h"
#include "build_config.h"
#include "led.h"
#include "upstream_hid_botdetect.h"
#include "upstream_statemachine.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/* External variables --------------------------------------------------------*/
extern PCD_HandleTypeDef hpcd_USB_OTG_FS;
extern DMA_HandleTypeDef spiTxDmaHandle;
extern DMA_HandleTypeDef spiRxDmaHandle;
uint8_t BusFaultAllowed = 0;
/******************************************************************************/
/* Cortex-M4 Processor Interruption and Exception Handlers */
/******************************************************************************/
void SysTick_Handler(void)
{
HAL_IncTick();
LED_Tick();
Upstream_StateMachine_PollDeviceConnected();
#if (defined (CONFIG_KEYBOARD_ENABLED) && defined (CONFIG_KEYBOARD_BOT_DETECT_ENABLED)) || \
(defined (CONFIG_MOUSE_ENABLED) && defined (CONFIG_MOUSE_BOT_DETECT_ENABLED))
Upstream_HID_BotDetect_Systick();
#endif
}
/////////////////////////
//All interrupts in this section must be at the same priority.
//They interact with each other, and calls are not thread-safe
//when different interrupt priorities are used.
/////////////////////////
void OTG_FS_IRQHandler(void)
{
HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS);
}
void DMA2_Stream2_IRQHandler(void)
{
HAL_DMA_IRQHandler(&spiRxDmaHandle);
}
void DMA2_Stream3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&spiTxDmaHandle);
}
void EXTI3_IRQHandler(void)
{
__HAL_GPIO_EXTI_CLEAR_IT(DOWNSTREAM_TX_OK_PIN);
Upstream_TxOkInterrupt();
}
/////////////////////////
/////////////////////////
//This weird stuff is required when disabling flash writes.
//The deliberate flash lockout will cause a bus fault that we need to process.
void EnableOneBusFault(void)
{
//It should not be enabled already!
if (BusFaultAllowed)
{
while (1);
}
SCB->SHCSR = SCB_SHCSR_BUSFAULTENA_Msk;
BusFaultAllowed = 1;
}
void BusFault_Handler(void)
{
if (BusFaultAllowed)
{
BusFaultAllowed = 0;
return;
}
while (1);
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -0,0 +1,143 @@
/*
* led.c
*
* Created on: 19/08/2015
* Author: Robert Fisk
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "led.h"
#include "board_config.h"
#include "build_config.h"
uint32_t FaultLedCounter;
uint32_t ReadWriteFlashEndTime;
LedStatusTypeDef FaultLedState;
uint16_t FaultLedOnMs;
uint16_t FaultLedOffMs;
uint8_t FaultLedBlinkCount;
uint8_t FaultLedBlinkCountState;
uint8_t FaultLedOutputState;
void LED_Init(void)
{
FAULT_LED_ON;
ReadWriteFlashEndTime = 0;
FaultLedState = LED_STATUS_STARTUP;
}
void LED_SetState(LedStatusTypeDef newState)
{
switch (newState)
{
case LED_STATUS_OFF:
FaultLedCounter = UINT32_MAX;
FaultLedBlinkCountState = 0;
FaultLedOutputState = 0;
FAULT_LED_OFF;
break;
case LED_STATUS_FLASH_UNSUPPORTED:
FaultLedOnMs = LED_UNSUPPORTED_BLINK_MS;
FaultLedOffMs = LED_UNSUPPORTED_BLINK_MS;
FaultLedBlinkCount = 1;
break;
case LED_STATUS_FLASH_BOTDETECT:
FaultLedOnMs = LED_BOTDETECT_ON_MS;
FaultLedOffMs = LED_BOTDETECT_OFF_MS;
FaultLedBlinkCount = 2;
break;
case LED_STATUS_FLASH_READWRITE:
#ifdef CONFIG_WRITE_FLASH_TIME_MS
if (FaultLedState == LED_STATUS_OFF)
{
FaultLedOnMs = LED_READWRITE_ON_MS;
FaultLedOffMs = LED_READWRITE_OFF_MS;
FaultLedBlinkCount = 1;
ReadWriteFlashEndTime = HAL_GetTick() + CONFIG_WRITE_FLASH_TIME_MS;
}
else
#endif
{
newState = FaultLedState; //Don't override other active states
}
break;
default:
FaultLedOnMs = LED_ERROR_BLINK_MS; //Everything else is LED_STATUS_ERROR
FaultLedOffMs = LED_ERROR_BLINK_MS;
FaultLedBlinkCount = 1;
}
FaultLedState = newState;
}
void LED_Tick(void)
{
if (FaultLedState == LED_STATUS_OFF) return;
if (FaultLedState == LED_STATUS_STARTUP)
{
if (HAL_GetTick() >= STARTUP_FLASH_DELAY_MS)
{
LED_SetState(LED_STATUS_OFF);
}
return;
}
#ifdef CONFIG_WRITE_FLASH_TIME_MS
if (FaultLedState == LED_STATUS_FLASH_READWRITE)
{
if ((int32_t)(HAL_GetTick() - ReadWriteFlashEndTime) > 0)
{
LED_SetState(LED_STATUS_OFF);
return;
}
}
#endif
if (FaultLedOutputState)
{
if (FaultLedCounter++ >= FaultLedOnMs) //Check to turn LED off
{
FaultLedBlinkCountState++;
FaultLedCounter = 0;
FaultLedOutputState = 0;
FAULT_LED_OFF;
}
}
else
{
if (FaultLedBlinkCountState >= FaultLedBlinkCount) //Checks to turn LED on...
{
if (FaultLedCounter++ >= FaultLedOffMs) //Last flash may have longer off-time
{
FaultLedBlinkCountState = 0;
FaultLedCounter = 0;
FaultLedOutputState = 1;
FAULT_LED_ON;
}
}
else
{
if (FaultLedCounter++ >= FaultLedOnMs) //Flash sequence uses on-time as intermediate off-time
{
FaultLedCounter = 0;
FaultLedOutputState = 1;
FAULT_LED_ON;
}
}
}
}

@ -0,0 +1,258 @@
/**
******************************************************************************
* File Name : main.c
* Date : 03/02/2015 20:27:01
* Description : Main program body
******************************************************************************
*
* COPYRIGHT(c) 2015 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*
* Modifications by Robert Fisk
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#include "usb_device.h"
#include "board_config.h"
#include "led.h"
#include "upstream_statemachine.h"
#include "upstream_spi.h"
#include "interrupts.h"
/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static void GPIO_Init(void);
static void DisableFlashWrites(void);
static void CheckFirmwareMatchesHardware(void);
int main(void)
{
//First things first!
DisableFlashWrites();
CheckFirmwareMatchesHardware();
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
GPIO_Init();
LED_Init();
Upstream_InitStateMachine();
HAL_Delay(200); //Delay executing WFI to avoid destroying JTAG access
while (1)
{
__WFI(); //sleep time!
}
}
void DisableFlashWrites(void)
{
//Disable flash writes until the next reset
//This will cause a bus fault interrupt, so allow one now.
EnableOneBusFault();
FLASH->KEYR = 999;
//Confirm that flash cannot be unlocked
//This unlock attempt will also cause two bus faults.
if ((FLASH->CR & FLASH_CR_LOCK) == 0) while(1);
EnableOneBusFault();
FLASH->KEYR = FLASH_KEY1;
EnableOneBusFault();
FLASH->KEYR = FLASH_KEY2;
if ((FLASH->CR & FLASH_CR_LOCK) == 0) while(1);
}
void CheckFirmwareMatchesHardware(void)
{
//Check we are running on the expected hardware:
//STM32F401RC on USG v1.0 beta
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOB_CLK_ENABLE();
if ((*(uint32_t*)DBGMCU_BASE & DBGMCU_IDCODE_DEV_ID) == DBGMCU_IDCODE_DEV_ID_401xB_xC)
{
//Read in board revision and ID on port C
GPIO_InitStruct.Pin = BOARD_REV_PIN_MASK | BOARD_ID_PIN_MASK;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = 0;
HAL_GPIO_Init(BOARD_REV_ID_PORT, &GPIO_InitStruct);
//Correct board revision?
if ((BOARD_REV_ID_PORT->IDR & BOARD_REV_PIN_MASK) <= BOARD_REV_1_0_BETA_3)
{
//Correct board ID: upstream?
if ((BOARD_REV_ID_PORT->IDR & BOARD_ID_PIN_MASK))
{
return;
}
}
}
//This is not the hardware we expected, so turn on our fault LED(s) and die in a heap.
GPIO_InitStruct.Pin = FAULT_LED_PIN | H405_FAULT_LED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(FAULT_LED_PORT, &GPIO_InitStruct);
FAULT_LED_ON;
H405_FAULT_LED_ON;
while (1);
}
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = (HAL_GetHSECrystalFreqMHz() / 2); //PLL input frequency = 2MHz
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) while (1);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_PCLK1 |
RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) while(1);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
//__HAL_RCC_GPIOH_CLK_ENABLE(); //HS oscillator on port H
//Bulk initialise all ports as inputs with pullups active,
//excluding JTAG pins which must remain as AF0!
GPIO_InitStruct.Pin = (GPIO_PIN_All & ~(PA_JTMS | PA_JTCK | PA_JTDI));
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = 0;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = (GPIO_PIN_All & ~(PB_JTDO | PB_NJTRST));
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_All;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
//Fault LED is output
GPIO_InitStruct.Pin = FAULT_LED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(FAULT_LED_PORT, &GPIO_InitStruct);
FAULT_LED_OFF;
// //SPI_INT_ACTIVE indicator
// GPIO_InitStruct.Pin = INT_ACTIVE_PIN;
// //GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
// //GPIO_InitStruct.Pull = GPIO_NOPULL;
// HAL_GPIO_Init(INT_ACTIVE_PORT, &GPIO_InitStruct);
// INT_ACTIVE_OFF;
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -0,0 +1,333 @@
/*
* upstream_hid.c
*
* Created on: Jan 16, 2016
* Author: Robert Fisk
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "upstream_hid.h"
#include "upstream_hid_botdetect.h"
#include "upstream_interface_def.h"
#include "build_config.h"
#if defined (CONFIG_KEYBOARD_ENABLED) || defined (CONFIG_MOUSE_ENABLED)
UpstreamPacketTypeDef* UpstreamHidPacket = NULL;
UpstreamHidGetReportCallback GetReportCallback = NULL;
#ifdef CONFIG_KEYBOARD_ENABLED
KeyboardOutStateTypeDef KeyboardOutDataState = KEYBOARD_OUT_STATE_IDLE;
uint8_t KeyboardOutData[HID_KEYBOARD_OUTPUT_DATA_LEN];
#endif
uint8_t GetReportLoopIsRunning = 0;
static void Upstream_HID_ReceiveInterruptReport(void);
static void Upstream_HID_ReceiveInterruptReportCallback(UpstreamPacketTypeDef* receivedPacket);
static void Upstream_HID_SendControlReport(void);
static void Upstream_HID_SendControlReportCallback(UpstreamPacketTypeDef* receivedPacket);
void Upstream_HID_DeInit(void)
{
if (UpstreamHidPacket != NULL)
{
Upstream_ReleasePacket(UpstreamHidPacket);
UpstreamHidPacket = NULL;
}
GetReportCallback = NULL;
GetReportLoopIsRunning = 0;
#ifdef CONFIG_KEYBOARD_ENABLED
KeyboardOutDataState = KEYBOARD_OUT_STATE_IDLE;
#endif
}
//Called by usbd_hid to request our next interrupt report
void Upstream_HID_GetInterruptReport(UpstreamHidGetReportCallback callback)
{
GetReportCallback = callback;
if (UpstreamHidPacket != NULL)
{
Upstream_ReleasePacket(UpstreamHidPacket);
UpstreamHidPacket = NULL;
}
//Wakeup interrupts are apparently broken.
//So we check for resume when the host sends us something here.
Upstream_StateMachine_CheckResume();
//Start our internal loop?
if (!GetReportLoopIsRunning)
{
GetReportLoopIsRunning = 1;
Upstream_HID_ReceiveInterruptReport();
}
}
//Our internal report request loop
static void Upstream_HID_ReceiveInterruptReport(void)
{
UpstreamPacketTypeDef* freePacket;
InterfaceCommandClassTypeDef activeClass;
activeClass = Upstream_StateMachine_CheckActiveClass();
if ((activeClass != COMMAND_CLASS_HID_MOUSE) &&
(activeClass != COMMAND_CLASS_HID_KEYBOARD)) //add classes here
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
freePacket = Upstream_GetFreePacketImmediately();
if (freePacket == NULL)
{
return;
}
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16;
freePacket->CommandClass = activeClass;
freePacket->Command = COMMAND_HID_GET_REPORT;
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
{
Upstream_ReceivePacket(Upstream_HID_ReceiveInterruptReportCallback);
}
else
{
Upstream_ReleasePacket(freePacket);
}
}
static void Upstream_HID_ReceiveInterruptReportCallback(UpstreamPacketTypeDef* receivedPacket)
{
UpstreamHidGetReportCallback tempReportCallback;
InterfaceCommandClassTypeDef activeClass;
uint32_t i;
uint8_t dataLength;
activeClass = Upstream_StateMachine_CheckActiveClass();
if ((activeClass != COMMAND_CLASS_HID_MOUSE) &&
(activeClass != COMMAND_CLASS_HID_KEYBOARD)) //add classes here
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
if (receivedPacket == NULL) //Error receiving packet
{
return; //Just give up...
}
if (receivedPacket->Length16 == UPSTREAM_PACKET_HEADER_LEN_16)
{
//Zero-length reply indicates no data from downstream device
Upstream_ReleasePacket(receivedPacket);
}
else
{
#ifdef CONFIG_MOUSE_ENABLED
if (activeClass == COMMAND_CLASS_HID_MOUSE)
{
if (receivedPacket->Length16 != (UPSTREAM_PACKET_HEADER_LEN_16 + ((HID_MOUSE_INPUT_DATA_LEN + 1) / 2)))
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
dataLength = HID_MOUSE_INPUT_DATA_LEN;
if ((receivedPacket->Data[0] & ~((1 << HID_MOUSE_MAX_BUTTONS) - 1)) != 0) //Check number of buttons received
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
//Mouse wakeup is triggered by button clicks only
if (receivedPacket->Data[0] != 0)
{
if (Upstream_StateMachine_GetSuspendState())
{
Upstream_StateMachine_Wakeup(); //Send wakeup signal to host
}
}
#ifdef CONFIG_MOUSE_BOT_DETECT_ENABLED
Upstream_HID_BotDetectMouse(receivedPacket->Data);
#endif
}
else
#endif
#ifdef CONFIG_KEYBOARD_ENABLED
if (activeClass == COMMAND_CLASS_HID_KEYBOARD)
{
if (receivedPacket->Length16 != (UPSTREAM_PACKET_HEADER_LEN_16 + ((HID_KEYBOARD_INPUT_DATA_LEN + 1) / 2)))
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
dataLength = HID_KEYBOARD_INPUT_DATA_LEN;
if (receivedPacket->Data[1] != 0)
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
for (i = 2; i < HID_KEYBOARD_INPUT_DATA_LEN; i++)
{
if (receivedPacket->Data[i] > HID_KEYBOARD_MAX_KEY)
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
}
if (Upstream_StateMachine_GetSuspendState())
{
Upstream_StateMachine_Wakeup(); //Send wakeup signal to host
}
#ifdef CONFIG_KEYBOARD_BOT_DETECT_ENABLED
Upstream_HID_BotDetectKeyboard(receivedPacket->Data);
#endif
}
//Other HID classes go here...
else
#endif
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
if ((GetReportCallback == NULL) ||
(UpstreamHidPacket != NULL) ||
(Upstream_StateMachine_GetSuspendState()))
{
Upstream_ReleasePacket(receivedPacket);
}
else
{
//Send resulting data to host
UpstreamHidPacket = receivedPacket; //Save packet so we can free it when upstream USB transaction is done
tempReportCallback = GetReportCallback;
GetReportCallback = NULL;
tempReportCallback(receivedPacket->Data, dataLength);
}
}
if (GetReportLoopIsRunning)
{
#ifdef CONFIG_KEYBOARD_ENABLED
//Check if we need to send OUT data to the keyboard before requesting next Interrupt IN data
if (KeyboardOutDataState == KEYBOARD_OUT_STATE_DATA_READY)
{
Upstream_HID_SendControlReport();
}
else
#endif
{
Upstream_HID_ReceiveInterruptReport(); //Otherwise poll downstream again
}
}
}
#ifdef CONFIG_KEYBOARD_ENABLED
void Upstream_HID_RequestSendControlReport(UpstreamPacketTypeDef* packetToSend, uint8_t dataLength)
{
InterfaceCommandClassTypeDef activeClass;
uint32_t i;
activeClass = Upstream_StateMachine_CheckActiveClass();
if ((packetToSend == NULL) ||
(activeClass != COMMAND_CLASS_HID_KEYBOARD) ||
(dataLength != HID_KEYBOARD_OUTPUT_DATA_LEN))
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
//Save data until after the next interrupt data is received from Downstream
KeyboardOutDataState = KEYBOARD_OUT_STATE_DATA_READY;
for (i = 0; i < HID_KEYBOARD_OUTPUT_DATA_LEN; i++)
{
KeyboardOutData[i] = packetToSend->Data[i];
}
}
static void Upstream_HID_SendControlReport(void)
{
UpstreamPacketTypeDef* freePacket;
uint32_t i;
KeyboardOutDataState = KEYBOARD_OUT_STATE_BUSY;
freePacket = Upstream_GetFreePacketImmediately();
if (freePacket == NULL) return;
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16 + ((HID_KEYBOARD_OUTPUT_DATA_LEN + 1) / 2);
freePacket->CommandClass = COMMAND_CLASS_HID_KEYBOARD;
freePacket->Command = COMMAND_HID_SET_REPORT;
for (i = 0; i < HID_KEYBOARD_OUTPUT_DATA_LEN; i++)
{
freePacket->Data[i] = KeyboardOutData[i];
}
freePacket->Data[0] &= ((1 << HID_KEYBOARD_MAX_LED) - 1);
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
{
Upstream_ReceivePacket(Upstream_HID_SendControlReportCallback);
}
else
{
Upstream_ReleasePacket(freePacket);
}
}
static void Upstream_HID_SendControlReportCallback(UpstreamPacketTypeDef* receivedPacket)
{
InterfaceCommandClassTypeDef activeClass;
activeClass = Upstream_StateMachine_CheckActiveClass();
if (activeClass != COMMAND_CLASS_HID_KEYBOARD) //add classes here
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
if (receivedPacket == NULL)
{
return; //Just give up...
}
Upstream_ReleasePacket(receivedPacket);
KeyboardOutDataState = KEYBOARD_OUT_STATE_IDLE;
Upstream_HID_ReceiveInterruptReport();
}
#endif
#endif //#if defined (CONFIG_KEYBOARD_ENABLED) || defined (CONFIG_MOUSE_ENABLED)

@ -0,0 +1,608 @@
/*
* upstream_hid_botdetect.c
*
* Created on: Aug 17, 2017
* Author: Robert Fisk
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "upstream_hid_botdetect.h"
#include "upstream_hid.h"
#include "build_config.h"
#include "usbd_hid.h"
#include "math.h"
//Variables common between keyboard and mouse bot detection:
volatile LockoutStateTypeDef LockoutState = LOCKOUT_STATE_INACTIVE;
uint32_t TemporaryLockoutTimeMs;
uint8_t TemporaryLockoutCount = 0;
//Variables specific to keyboard bot detection:
#if defined (CONFIG_KEYBOARD_ENABLED) && defined (CONFIG_KEYBOARD_BOT_DETECT_ENABLED)
uint32_t LastKeyDownTime = 0;
KeyTimerLogTypeDef KeyTimerLog[KEYBOARD_BOTDETECT_MAX_ACTIVE_KEYS] = {0};
uint8_t OldKeyboardInData[HID_KEYBOARD_INPUT_DATA_LEN] = {0};
uint8_t KeyDelayFastBinDrainDivideCount = 0;
uint8_t KeyDelaySlowBinDrainDivideCount = 0;
uint8_t KeyDowntimeFastBinDrainDivideCount = 0;
uint8_t KeyDowntimeSlowBinDrainDivideCount = 0;
uint8_t KeyDelayFastBinArray[KEYBOARD_BOTDETECT_FAST_BIN_COUNT] = {0};
uint8_t KeyDelaySlowBinArray[KEYBOARD_BOTDETECT_SLOW_BIN_COUNT] = {0};
uint8_t KeyDowntimeFastBinArray[KEYBOARD_BOTDETECT_FAST_BIN_COUNT] = {0};
uint8_t KeyDowntimeSlowBinArray[KEYBOARD_BOTDETECT_SLOW_BIN_COUNT] = {0};
//Debug:
// uint8_t KeyDelayFastBinArrayPeak;
// uint8_t KeyDelaySlowBinArrayPeak;
// uint8_t KeyDowntimeFastBinArrayPeak;
// uint8_t KeyDowntimeSlowBinArrayPeak;
static uint32_t Upstream_HID_BotDetectKeyboard_RolloverCheck(uint8_t* keyboardInData);
static void Upstream_HID_BotDetectKeyboard_DoLockout(void);
static void Upstream_HID_BotDetectKeyboard_KeyDown(uint8_t keyCode);
static void Upstream_HID_BotDetectKeyboard_KeyUp(uint8_t keyCode);
#endif
//Variables specific to mouse bot detection:
#if defined (CONFIG_MOUSE_ENABLED) && defined (CONFIG_MOUSE_BOT_DETECT_ENABLED)
uint32_t LastMouseMoveTime = 0;
//Jump detection stuff
uint32_t FirstMouseMoveTime = 0;
uint8_t JumpMouseIsMoving = 0;
//Constant acceleration detection stuff
uint16_t MouseVelocityHistory[MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE] = {0};
int32_t PreviousSmoothedAcceleration = 0;
int32_t ConstantAccelerationCounter = 0;
//Jiggle detection stuff
uint8_t MouseStopIntervalBinDrainDivideCount = 0;
uint8_t MouseStopIntervalBinArray[MOUSE_BOTDETECT_JIGGLE_BIN_COUNT] = {0};
//Debug:
// int8_t ConstantAccelerationCounterMax = 0;
// int8_t ConstantAccelerationCounterMin = 0;
// uint8_t MouseStopIntervalBinArrayPeak = 0;
static void Upstream_HID_BotDetectMouse_DoLockout(void);
#endif
//Code specific to keyboard bot detection:
#if defined (CONFIG_KEYBOARD_ENABLED) && defined (CONFIG_KEYBOARD_BOT_DETECT_ENABLED)
//Checks if received keyboard data is from a real human.
//This is not entirely bulletproof as an attacking device may randomize its keypresses.
void Upstream_HID_BotDetectKeyboard(uint8_t* keyboardInData)
{
uint32_t i;
uint32_t j;
uint8_t tempModifier;
if (Upstream_HID_BotDetectKeyboard_RolloverCheck(keyboardInData)) return;
//Process modifier keys in first byte
tempModifier = keyboardInData[0];
for (i = 0; i < 8; i++)
{
if ((tempModifier & 1) && !(OldKeyboardInData[0] & 1))
{
Upstream_HID_BotDetectKeyboard_KeyDown(KEY_MODIFIER_BASE + i);
}
if (!(tempModifier & 1) && (OldKeyboardInData[0] & 1))
{
Upstream_HID_BotDetectKeyboard_KeyUp(KEY_MODIFIER_BASE + i);
}
tempModifier >>= 1;
OldKeyboardInData[0] >>= 1;
}
//Process key array: search for keydowns
for (i = 2; i < HID_KEYBOARD_INPUT_DATA_LEN; i++)
{
if (keyboardInData[i] >= KEY_A)
{
for (j = 2; j < HID_KEYBOARD_INPUT_DATA_LEN; j++)
{
if (keyboardInData[i] == OldKeyboardInData[j]) break;
}
if (j >= HID_KEYBOARD_INPUT_DATA_LEN)
{
Upstream_HID_BotDetectKeyboard_KeyDown(keyboardInData[i]);
}
}
}
//Process key array: search for keyups
for (i = 2; i < HID_KEYBOARD_INPUT_DATA_LEN; i++)
{
if (OldKeyboardInData[i] >= KEY_A)
{
for (j = 2; j < HID_KEYBOARD_INPUT_DATA_LEN; j++)
{
if (OldKeyboardInData[i] == keyboardInData[j]) break;
}
if (j >= HID_KEYBOARD_INPUT_DATA_LEN)
{
Upstream_HID_BotDetectKeyboard_KeyUp(OldKeyboardInData[i]);
}
}
}
//Check for evidence of bot typing
for (i = 0; i < KEYBOARD_BOTDETECT_FAST_BIN_COUNT; i++)
{
if ((KeyDelayFastBinArray[i] > KEYBOARD_BOTDETECT_LOCKOUT_BIN_THRESHOLD) ||
(KeyDowntimeFastBinArray[i] > KEYBOARD_BOTDETECT_LOCKOUT_BIN_THRESHOLD))
{
Upstream_HID_BotDetectKeyboard_DoLockout();
break;
}
//Debug:
// if (KeyDelayFastBinArray[i] > KeyDelayFastBinArrayPeak) KeyDelayFastBinArrayPeak = KeyDelayFastBinArray[i];
// if (KeyDowntimeFastBinArray[i] > KeyDowntimeFastBinArrayPeak) KeyDowntimeFastBinArrayPeak = KeyDowntimeFastBinArray[i];
}
for (i = 0; i < KEYBOARD_BOTDETECT_SLOW_BIN_COUNT; i++)
{
if ((KeyDelaySlowBinArray[i] > KEYBOARD_BOTDETECT_LOCKOUT_BIN_THRESHOLD) ||
(KeyDowntimeSlowBinArray[i] > KEYBOARD_BOTDETECT_LOCKOUT_BIN_THRESHOLD))
{
Upstream_HID_BotDetectKeyboard_DoLockout();
break;
}
//Debug:
// if (KeyDelaySlowBinArray[i] > KeyDelaySlowBinArrayPeak) KeyDelaySlowBinArrayPeak = KeyDelaySlowBinArray[i];
// if (KeyDowntimeSlowBinArray[i] > KeyDowntimeSlowBinArrayPeak) KeyDowntimeSlowBinArrayPeak = KeyDowntimeSlowBinArray[i];
}
//Copy new data to old array
for (i = 0; i < HID_KEYBOARD_INPUT_DATA_LEN; i++)
{
OldKeyboardInData[i] = keyboardInData[i];
}
//Host receives no data if we are locked
if ((LockoutState == LOCKOUT_STATE_TEMPORARY_ACTIVE) ||
(LockoutState == LOCKOUT_STATE_PERMANENT_ACTIVE))
{
for (i = 0; i < HID_KEYBOARD_INPUT_DATA_LEN; i++)
{
keyboardInData[i] = 0;
}
}
}
static void Upstream_HID_BotDetectKeyboard_DoLockout(void)
{
uint32_t i;
if (LockoutState == LOCKOUT_STATE_PERMANENT_ACTIVE) return;
//Are we already in warning state? -> activate permanent lockout
if ((LockoutState == LOCKOUT_STATE_TEMPORARY_ACTIVE) ||
(LockoutState == LOCKOUT_STATE_TEMPORARY_FLASHING))
{
LockoutState = LOCKOUT_STATE_PERMANENT_ACTIVE;
return;
}
//Three (temporary) strikes -> you're out!
if (++TemporaryLockoutCount >= 3)
{
LockoutState = LOCKOUT_STATE_PERMANENT_ACTIVE;
LED_SetState(LED_STATUS_FLASH_BOTDETECT);
return;
}
//Otherwise, reset counters and give warning
for (i = 0; i < KEYBOARD_BOTDETECT_FAST_BIN_COUNT; i++)
{
KeyDelayFastBinArray[i] = 0;
KeyDowntimeFastBinArray[i] = 0;
}
for (i = 0; i < KEYBOARD_BOTDETECT_SLOW_BIN_COUNT; i++)
{
KeyDelaySlowBinArray[i] = 0;
KeyDowntimeSlowBinArray[i] = 0;
}
TemporaryLockoutTimeMs = 0;
LockoutState = LOCKOUT_STATE_TEMPORARY_ACTIVE;
LED_SetState(LED_STATUS_FLASH_BOTDETECT);
}
//Keyboard reports a rollover code when there are too many keys to scan/report.
static uint32_t Upstream_HID_BotDetectKeyboard_RolloverCheck(uint8_t* keyboardInData)
{
uint32_t i;
for (i = 2; i < HID_KEYBOARD_INPUT_DATA_LEN; i++)
{
if (keyboardInData[i] == KEY_ROLLOVER) break;
}
if (i >= HID_KEYBOARD_INPUT_DATA_LEN) return 0;
//As I am unclear on the exact usage and interpretation of the rollover code,
//we are going to play it safe by copying the old keyboard data over the new array.
//This ensures the host interprets a rollover event exactly the way we do!
//Host receives no data if we are locked
if ((LockoutState == LOCKOUT_STATE_TEMPORARY_ACTIVE) ||
(LockoutState == LOCKOUT_STATE_PERMANENT_ACTIVE))
{
for (i = 0; i < HID_KEYBOARD_INPUT_DATA_LEN; i++)
{
keyboardInData[i] = 0;
}
}
else
{
for (i = 0; i < HID_KEYBOARD_INPUT_DATA_LEN; i++)
{
keyboardInData[i] = OldKeyboardInData[i];
}
}
return 1;
}
static void Upstream_HID_BotDetectKeyboard_KeyDown(uint8_t keyCode)
{
uint32_t i;
uint32_t keyDelay;
uint32_t now = HAL_GetTick();
keyDelay = now - LastKeyDownTime;
if (keyDelay < (KEYBOARD_BOTDETECT_FAST_BIN_WIDTH_MS * KEYBOARD_BOTDETECT_FAST_BIN_COUNT))
{
KeyDelayFastBinArray[(keyDelay / KEYBOARD_BOTDETECT_FAST_BIN_WIDTH_MS)]++; //Add key to fast bin
//Drain fast bins at specified rate
KeyDelayFastBinDrainDivideCount++;
if (KeyDelayFastBinDrainDivideCount >= KEYBOARD_BOTDETECT_FAST_BIN_DRAIN_DIVIDER)
{
KeyDelayFastBinDrainDivideCount = 0;
for (i = 0; i < KEYBOARD_BOTDETECT_FAST_BIN_COUNT; i++)
{
if (KeyDelayFastBinArray[i] > 0) KeyDelayFastBinArray[i]--;
}
}
}
else
{
keyDelay = keyDelay % (KEYBOARD_BOTDETECT_SLOW_BIN_WIDTH_MS * KEYBOARD_BOTDETECT_SLOW_BIN_COUNT); //Wrap slow key time into the slow array
KeyDelaySlowBinArray[(keyDelay / KEYBOARD_BOTDETECT_SLOW_BIN_WIDTH_MS)]++; //Add key to slow bin
//Drain slow bins at specified rate
KeyDelaySlowBinDrainDivideCount++;
if (KeyDelaySlowBinDrainDivideCount >= KEYBOARD_BOTDETECT_SLOW_BIN_DRAIN_DIVIDER)
{
KeyDelaySlowBinDrainDivideCount = 0;
for (i = 0; i < KEYBOARD_BOTDETECT_SLOW_BIN_COUNT; i++)
{
if (KeyDelaySlowBinArray[i] > 0) KeyDelaySlowBinArray[i]--;
}
}
}
LastKeyDownTime = now;
for (i = 0; i < KEYBOARD_BOTDETECT_MAX_ACTIVE_KEYS; i++)
{
if (KeyTimerLog[i].KeyCode == 0) break;
}
if (i >= KEYBOARD_BOTDETECT_MAX_ACTIVE_KEYS) while (1); //Totally should not happen
KeyTimerLog[i].KeyCode = keyCode;
KeyTimerLog[i].KeyDownStart = now;
}
static void Upstream_HID_BotDetectKeyboard_KeyUp(uint8_t keyCode)
{
uint32_t i;
uint32_t keyDowntime;
for (i = 0; i < KEYBOARD_BOTDETECT_MAX_ACTIVE_KEYS; i++)
{
if (KeyTimerLog[i].KeyCode == keyCode) break;
}
if (i >= KEYBOARD_BOTDETECT_MAX_ACTIVE_KEYS) while (1); //Totally should not happen
KeyTimerLog[i].KeyCode = 0; //Clear out the key entry
keyDowntime = HAL_GetTick() - KeyTimerLog[i].KeyDownStart;
if (keyDowntime < (KEYBOARD_BOTDETECT_FAST_BIN_WIDTH_MS * KEYBOARD_BOTDETECT_FAST_BIN_COUNT))
{
KeyDowntimeFastBinArray[(keyDowntime / KEYBOARD_BOTDETECT_FAST_BIN_WIDTH_MS)]++; //Add key to fast bin
//Drain fast bins at specified rate
KeyDowntimeFastBinDrainDivideCount++;
if (KeyDowntimeFastBinDrainDivideCount >= KEYBOARD_BOTDETECT_FAST_BIN_DRAIN_DIVIDER)
{
KeyDowntimeFastBinDrainDivideCount = 0;
for (i = 0; i < KEYBOARD_BOTDETECT_FAST_BIN_COUNT; i++)
{
if (KeyDowntimeFastBinArray[i] > 0) KeyDowntimeFastBinArray[i]--;
}
}
}
else
{
keyDowntime = keyDowntime % (KEYBOARD_BOTDETECT_SLOW_BIN_WIDTH_MS * KEYBOARD_BOTDETECT_SLOW_BIN_COUNT); //Wrap slow key time into the slow array
KeyDowntimeSlowBinArray[(keyDowntime / KEYBOARD_BOTDETECT_SLOW_BIN_WIDTH_MS)]++; //Add key to slow bin
//Drain slow bins at specified rate
KeyDowntimeSlowBinDrainDivideCount++;
if (KeyDowntimeSlowBinDrainDivideCount >= KEYBOARD_BOTDETECT_SLOW_BIN_DRAIN_DIVIDER)
{
KeyDowntimeSlowBinDrainDivideCount = 0;
for (i = 0; i < KEYBOARD_BOTDETECT_SLOW_BIN_COUNT; i++)
{
if (KeyDowntimeSlowBinArray[i] > 0) KeyDowntimeSlowBinArray[i]--;
}
}
}
}
#endif //if defined (CONFIG_KEYBOARD_ENABLED) && defined (CONFIG_KEYBOARD_BOT_DETECT_ENABLED)
//Called by Systick_Handler every 1ms, at high interrupt priority.
void Upstream_HID_BotDetect_Systick(void)
{
#if (defined (CONFIG_KEYBOARD_ENABLED) && defined (CONFIG_KEYBOARD_BOT_DETECT_ENABLED)) || \
(defined (CONFIG_MOUSE_ENABLED) && defined (CONFIG_MOUSE_BOT_DETECT_ENABLED))
//Check if temporary lockout has expired
if (LockoutState == LOCKOUT_STATE_TEMPORARY_ACTIVE)
{
if (TemporaryLockoutTimeMs++ > BOTDETECT_TEMPORARY_LOCKOUT_TIME_MS)
{
LockoutState = LOCKOUT_STATE_TEMPORARY_FLASHING;
}
}
else if (LockoutState == LOCKOUT_STATE_TEMPORARY_FLASHING)
{
if (TemporaryLockoutTimeMs++ > BOTDETECT_TEMPORARY_LOCKOUT_FLASH_TIME_MS)
{
LED_SetState(LED_STATUS_OFF);
LockoutState = LOCKOUT_STATE_INACTIVE;
}
}
#endif
}
//Code specific to mouse bot detection:
#if defined (CONFIG_MOUSE_ENABLED) && defined (CONFIG_MOUSE_BOT_DETECT_ENABLED)
void Upstream_HID_BotDetectMouse(uint8_t* mouseInData)
{
uint32_t i;
uint32_t now = HAL_GetTick();
uint32_t moveDelay;
uint32_t velocity;
int8_t mouseX;
int8_t mouseY;
//Constant acceleration detection stuff
uint32_t newSmoothedVelocity;
uint32_t oldSmoothedVelocity;
int32_t newSmoothedAcceleration;
int32_t smoothedAccelerationMatchError;
mouseX = mouseInData[1];
mouseY = mouseInData[2];
velocity = (sqrtf(((int32_t)mouseX * mouseX) +
((int32_t)mouseY * mouseY))) * MOUSE_BOTDETECT_VELOCITY_MULTIPLIER; //Multiply floating-point sqrt result to avoid integer rounding errors
moveDelay = now - LastMouseMoveTime;
//Reset constant acceleration detection state after a few seconds of inactivity
if (moveDelay > MOUSE_BOTDETECT_VELOCITY_RESET_TIMEOUT_MS)
{
//Is this the start of a new movement?
if (velocity != 0)
{
for (i = 0; i < MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE; i++)
{
MouseVelocityHistory[i] = 0;
}
ConstantAccelerationCounter = 0;
}
}
//Jiggle detection: did the mouse stop moving?
if (moveDelay > ((MOUSE_BOTDETECT_JIGGLE_STOP_PERIODS * HID_FS_BINTERVAL) - (HID_FS_BINTERVAL / 2)))
{
//Is this the start of a new movement?
if (velocity != 0)
{
//Jiggle detection: add stopped time to jiggle bins
moveDelay = moveDelay % (MOUSE_BOTDETECT_JIGGLE_BIN_WIDTH_MS * MOUSE_BOTDETECT_JIGGLE_BIN_COUNT); //Wrap stopped time into the array
MouseStopIntervalBinArray[(moveDelay / MOUSE_BOTDETECT_JIGGLE_BIN_WIDTH_MS)]++;
if (MouseStopIntervalBinArray[(moveDelay / MOUSE_BOTDETECT_JIGGLE_BIN_WIDTH_MS)] > MOUSE_BOTDETECT_LOCKOUT_JIGGLE_BIN_THRESHOLD)
{
Upstream_HID_BotDetectMouse_DoLockout();
}
//Debug:
// if (MouseStopIntervalBinArray[(moveDelay / MOUSE_BOTDETECT_JIGGLE_BIN_WIDTH_MS)] > MouseStopIntervalBinArrayPeak)
// {
// MouseStopIntervalBinArrayPeak = MouseStopIntervalBinArray[(moveDelay / MOUSE_BOTDETECT_JIGGLE_BIN_WIDTH_MS)];
// }
//Drain jiggle bins at specified rate
MouseStopIntervalBinDrainDivideCount++;
if (MouseStopIntervalBinDrainDivideCount >= MOUSE_BOTDETECT_JIGGLE_BIN_DIVIDER)
{
MouseStopIntervalBinDrainDivideCount = 0;
for (i = 0; i < MOUSE_BOTDETECT_JIGGLE_BIN_COUNT; i++)
{
if (MouseStopIntervalBinArray[i] > 0) MouseStopIntervalBinArray[i]--;
}
}
}
}
//Jump detection: did the mouse stop moving briefly?
if (moveDelay > ((MOUSE_BOTDETECT_JUMP_PERIODS * HID_FS_BINTERVAL) - (HID_FS_BINTERVAL / 2)))
{
FirstMouseMoveTime = 0;
if (JumpMouseIsMoving) //Was a significant movement in progress?
{
JumpMouseIsMoving = 0;
if ((LastMouseMoveTime - FirstMouseMoveTime) < ((MOUSE_BOTDETECT_JUMP_PERIODS * HID_FS_BINTERVAL) - (HID_FS_BINTERVAL / 2)))
{
Upstream_HID_BotDetectMouse_DoLockout();
}
}
}
if (velocity != 0)
{
//Jump detection
LastMouseMoveTime = now;
if (FirstMouseMoveTime == 0)
{
FirstMouseMoveTime = now;
}
if (velocity > (MOUSE_BOTDETECT_JUMP_VELOCITY_THRESHOLD * MOUSE_BOTDETECT_VELOCITY_MULTIPLIER))
{
JumpMouseIsMoving = 1;
}
//Constant acceleration detection
for (i = (MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE - 1); i > 0; i--) //Shuffle down history data
{
MouseVelocityHistory[i] = MouseVelocityHistory[i - 1];
}
MouseVelocityHistory[0] = velocity; //Store latest data at head
if (MouseVelocityHistory[(MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE - 1)] > 0)
{
velocity = 0; //Calculate new and old average velocities
for (i = 0; i < (MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE / 2); i++)
{
velocity += MouseVelocityHistory[i];
}
newSmoothedVelocity = (velocity * 8) / (MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE / 2); //Multiply velocity up to avoid rounding errors on divide
velocity = 0;
for (i = (MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE / 2); i < MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE; i++)
{
velocity += MouseVelocityHistory[i];
}
oldSmoothedVelocity = (velocity * 8) / (MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE / 2); //Multiply velocity up to avoid rounding errors on divide
newSmoothedAcceleration = newSmoothedVelocity - oldSmoothedVelocity;
smoothedAccelerationMatchError = (oldSmoothedVelocity * MOUSE_BOTDETECT_VELOCITY_MATCH_ERROR) / MOUSE_BOTDETECT_VELOCITY_MATCH_BASE;
if (((PreviousSmoothedAcceleration + smoothedAccelerationMatchError) >= newSmoothedAcceleration) &&
((PreviousSmoothedAcceleration - smoothedAccelerationMatchError) <= newSmoothedAcceleration))
{
ConstantAccelerationCounter++;
if (ConstantAccelerationCounter > MOUSE_BOTDETECT_CONSTANT_ACCEL_LOCKOUT)
{
Upstream_HID_BotDetectMouse_DoLockout();
}
else if (ConstantAccelerationCounter >= MOUSE_BOTDETECT_CONSTANT_ACCEL_STOP) //Stop mouse movement if it looks suspiciously constant
{
mouseInData[1] = 0;
mouseInData[2] = 0;
}
}
else
{
if (ConstantAccelerationCounter > -MOUSE_BOTDETECT_CONSTANT_ACCEL_CREDIT) ConstantAccelerationCounter--;
}
PreviousSmoothedAcceleration = newSmoothedAcceleration;
//Debug:
// if (ConstantAccelerationCounter > ConstantAccelerationCounterMax) ConstantAccelerationCounterMax = ConstantAccelerationCounter;
// if (ConstantAccelerationCounter < ConstantAccelerationCounterMin) ConstantAccelerationCounterMin = ConstantAccelerationCounter;
}
}
else
{
mouseInData[1] = 0; //If we don't want to process this event, makes sure no movement data gets through
mouseInData[2] = 0;
}
//Host receives no data if we are locked
if ((LockoutState == LOCKOUT_STATE_TEMPORARY_ACTIVE) ||
(LockoutState == LOCKOUT_STATE_PERMANENT_ACTIVE))
{
for (i = 0; i < HID_MOUSE_INPUT_DATA_LEN; i++)
{
mouseInData[i] = 0;
}
}
}
static void Upstream_HID_BotDetectMouse_DoLockout(void)
{
uint32_t i;
if (LockoutState == LOCKOUT_STATE_PERMANENT_ACTIVE) return;
//Are we already in warning state? -> activate permanent lockout
if ((LockoutState == LOCKOUT_STATE_TEMPORARY_ACTIVE) ||
(LockoutState == LOCKOUT_STATE_TEMPORARY_FLASHING))
{
LockoutState = LOCKOUT_STATE_PERMANENT_ACTIVE;
return;
}
//Three (temporary) strikes -> you're out!
if (++TemporaryLockoutCount >= 3)
{
LockoutState = LOCKOUT_STATE_PERMANENT_ACTIVE;
LED_SetState(LED_STATUS_FLASH_BOTDETECT);
return;
}
//Otherwise, reset counters and give warning
for (i = 0; i < MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE; i++)
{
MouseVelocityHistory[i] = 0;
}
ConstantAccelerationCounter = 0;
for (i = 0; i < MOUSE_BOTDETECT_JIGGLE_BIN_COUNT; i++)
{
MouseStopIntervalBinArray[i] = 0;
}
TemporaryLockoutTimeMs = 0;
LockoutState = LOCKOUT_STATE_TEMPORARY_ACTIVE;
LED_SetState(LED_STATUS_FLASH_BOTDETECT);
}
#endif

@ -0,0 +1,403 @@
/*
* upstream_msc.c
*
* Created on: 4/07/2015
* Author: Robert Fisk
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "upstream_interface_def.h"
#include "upstream_msc.h"
#include "upstream_spi.h"
#include "upstream_statemachine.h"
#include "stm32f4xx_hal.h"
#include "build_config.h"
#ifdef CONFIG_MASS_STORAGE_ENABLED
//Stuff we need to save for our callbacks to use:
UpstreamMSCCallbackTypeDef TestReadyCallback;
UpstreamMSCCallbackTypeDef BeginReadCallback;
UpstreamMSCCallbackTypeDef BeginWriteCallback;
UpstreamMSCCallbackTypeDef DisconnectCallback;
UpstreamMSCCallbackUintPacketTypeDef GetCapacityCallback;
UpstreamMSCCallbackPacketTypeDef GetStreamDataCallback;
uint64_t BlockStart;
uint32_t BlockCount;
uint32_t ByteCount;
UpstreamPacketTypeDef* ReadStreamPacket;
uint8_t ReadStreamBusy;
static void Upstream_MSC_TestReadyFreePacketCallback(UpstreamPacketTypeDef* freePacket);
static void Upstream_MSC_TestReadyReplyCallback(UpstreamPacketTypeDef* replyPacket);
static void Upstream_MSC_GetCapacityFreePacketCallback(UpstreamPacketTypeDef* freePacket);
static void Upstream_MSC_GetCapacityReplyCallback(UpstreamPacketTypeDef* replyPacket);
static void Upstream_MSC_GetStreamDataPacketCallback(UpstreamPacketTypeDef* replyPacket);
static void Upstream_MSC_BeginReadFreePacketCallback(UpstreamPacketTypeDef* freePacket);
static void Upstream_MSC_BeginWriteFreePacketCallback(UpstreamPacketTypeDef* freePacket);
static void Upstream_MSC_RequestDisconnectFreePacketCallback(UpstreamPacketTypeDef* freePacket);
static void Upstream_MSC_RequestDisconnectReplyCallback(UpstreamPacketTypeDef* replyPacket);
HAL_StatusTypeDef Upstream_MSC_TestReady(UpstreamMSCCallbackTypeDef callback)
{
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
{
//UPSTREAM_STATEMACHINE_FREAKOUT;
return HAL_ERROR;
}
TestReadyCallback = callback;
return Upstream_GetFreePacket(Upstream_MSC_TestReadyFreePacketCallback);
}
static void Upstream_MSC_TestReadyFreePacketCallback(UpstreamPacketTypeDef* freePacket)
{
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16;
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
freePacket->Command = COMMAND_MSC_TEST_UNIT_READY;
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
{
//Upstream_PacketManager will free the packet when the transfer is done
if (Upstream_ReceivePacket(Upstream_MSC_TestReadyReplyCallback) != HAL_OK)
{
TestReadyCallback(HAL_ERROR);
}
return;
}
//else:
Upstream_ReleasePacket(freePacket);
TestReadyCallback(HAL_ERROR);
}
static void Upstream_MSC_TestReadyReplyCallback(UpstreamPacketTypeDef* replyPacket)
{
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
{
return;
}
if (replyPacket == NULL)
{
TestReadyCallback(HAL_ERROR);
return;
}
if ((replyPacket->Length16 != (UPSTREAM_PACKET_HEADER_LEN_16 + 1)) ||
(replyPacket->Data[0] != HAL_OK))
{
Upstream_ReleasePacket(replyPacket);
TestReadyCallback(HAL_ERROR);
return;
}
Upstream_ReleasePacket(replyPacket);
TestReadyCallback(HAL_OK);
}
HAL_StatusTypeDef Upstream_MSC_GetCapacity(UpstreamMSCCallbackUintPacketTypeDef callback)
{
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
{
return HAL_ERROR;
}
GetCapacityCallback = callback;
return Upstream_GetFreePacket(Upstream_MSC_GetCapacityFreePacketCallback);
}
static void Upstream_MSC_GetCapacityFreePacketCallback(UpstreamPacketTypeDef* freePacket)
{
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16;
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
freePacket->Command = COMMAND_MSC_GET_CAPACITY;
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
{
if (Upstream_ReceivePacket(Upstream_MSC_GetCapacityReplyCallback) != HAL_OK)
{
GetCapacityCallback(NULL, 0, 0);
}
return;
}
//else:
Upstream_ReleasePacket(freePacket);
GetCapacityCallback(NULL, 0, 0);
}
static void Upstream_MSC_GetCapacityReplyCallback(UpstreamPacketTypeDef* replyPacket)
{
uint32_t block_count;
uint32_t block_size;
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
{
return;
}
if (replyPacket == NULL)
{
GetCapacityCallback(NULL, 0, 0);
return;
}
if (replyPacket->Length16 != (UPSTREAM_PACKET_HEADER_LEN_16 + (8 / 2)))
{
Upstream_ReleasePacket(replyPacket);
GetCapacityCallback(NULL, 0, 0);
return;
}
block_count = *(uint32_t*)&(replyPacket->Data[0]);
block_size = *(uint32_t*)&(replyPacket->Data[4]);
if ((block_count < MSC_MINIMUM_BLOCK_COUNT) ||
(block_size != MSC_SUPPORTED_BLOCK_SIZE))
{
Upstream_ReleasePacket(replyPacket);
GetCapacityCallback(NULL, 0, 0);
return;
}
GetCapacityCallback(replyPacket, block_count, block_size); //usb_msc_scsi will use this packet, so don't release now
}
HAL_StatusTypeDef Upstream_MSC_BeginRead(UpstreamMSCCallbackTypeDef callback,
uint64_t readBlockStart,
uint32_t readBlockCount,
uint32_t readByteCount)
{
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
{
return HAL_ERROR;
}
BlockStart = readBlockStart;
BlockCount = readBlockCount;
ByteCount = readByteCount;
ReadStreamPacket = NULL; //Prepare for GetStreamDataPacket's use
ReadStreamBusy = 0;
BeginReadCallback = callback;
return Upstream_GetFreePacket(Upstream_MSC_BeginReadFreePacketCallback);
}
static void Upstream_MSC_BeginReadFreePacketCallback(UpstreamPacketTypeDef* freePacket)
{
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16 + ((4 * 3) / 2);
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
freePacket->Command = COMMAND_MSC_READ;
*(uint64_t*)&(freePacket->Data[0]) = BlockStart;
*(uint32_t*)&(freePacket->Data[8]) = BlockCount;
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
{
BeginReadCallback(HAL_OK);
return;
}
//else:
Upstream_ReleasePacket(freePacket);
BeginReadCallback(HAL_ERROR);
}
HAL_StatusTypeDef Upstream_MSC_GetStreamDataPacket(UpstreamMSCCallbackPacketTypeDef callback)
{
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
{
return HAL_ERROR;
}
GetStreamDataCallback = callback;
if (ReadStreamBusy != 0)
{
return HAL_OK;
}
ReadStreamBusy = 1;
if (ReadStreamPacket && GetStreamDataCallback) //Do we have a stored packet and an address to send it?
{
Upstream_MSC_GetStreamDataPacketCallback(ReadStreamPacket); //Send it now!
ReadStreamPacket = NULL;
return HAL_OK; //Our callback will call us again, so we don't need to get a packet in this case.
}
return Upstream_ReceivePacket(Upstream_MSC_GetStreamDataPacketCallback);
}
static void Upstream_MSC_GetStreamDataPacketCallback(UpstreamPacketTypeDef* replyPacket)
{
uint32_t dataLength8;
ReadStreamBusy = 0;
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
{
return;
}
if (GetStreamDataCallback == NULL)
{
ReadStreamPacket = replyPacket; //We used up our callback already, so save this one for later.
return;
}
if (replyPacket == NULL)
{
GetStreamDataCallback(NULL, 0);
return;
}
dataLength8 = (replyPacket->Length16 - UPSTREAM_PACKET_HEADER_LEN_16) * 2;
if (((replyPacket->CommandClass & COMMAND_CLASS_DATA_FLAG) == 0) || //Any 'command' reply (as opposed to 'data' reply) is an automatic fail here
(dataLength8 != MSC_MINIMUM_DATA_UNIT) || //Should only receive integer units of MSC block size
(dataLength8 > ByteCount)) //No more data than expected transfer length
{
GetStreamDataCallback(NULL, 0);
return;
}
ByteCount -= dataLength8;
GetStreamDataCallback(replyPacket, dataLength8); //usb_msc_scsi will use this packet, so don't release now
if (ByteCount > 0)
{
Upstream_MSC_GetStreamDataPacket(NULL); //Try to get the next packet now, before USB asks for it
}
}
#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
HAL_StatusTypeDef Upstream_MSC_BeginWrite(UpstreamMSCCallbackTypeDef callback,
uint64_t writeBlockStart,
uint32_t writeBlockCount)
{
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
{
return HAL_ERROR;
}
LED_SetState(LED_STATUS_FLASH_READWRITE);
BlockStart = writeBlockStart;
BlockCount = writeBlockCount;
BeginWriteCallback = callback;
return Upstream_GetFreePacket(Upstream_MSC_BeginWriteFreePacketCallback);
}
static void Upstream_MSC_BeginWriteFreePacketCallback(UpstreamPacketTypeDef* freePacket)
{
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16 + ((4 * 3) / 2);
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
freePacket->Command = COMMAND_MSC_WRITE;
*(uint64_t*)&(freePacket->Data[0]) = BlockStart;
*(uint32_t*)&(freePacket->Data[8]) = BlockCount;
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
{
BeginWriteCallback(HAL_OK);
return;
}
//else:
Upstream_ReleasePacket(freePacket);
BeginWriteCallback(HAL_ERROR);
}
HAL_StatusTypeDef Upstream_MSC_PutStreamDataPacket(UpstreamPacketTypeDef* packetToSend,
uint32_t dataLength8)
{
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
{
return HAL_ERROR;
}
if ((dataLength8 % 2) != 0)
{
return HAL_ERROR;
}
packetToSend->Length16 = (dataLength8 / 2) + UPSTREAM_PACKET_HEADER_LEN_16;
packetToSend->CommandClass = COMMAND_CLASS_MASS_STORAGE | COMMAND_CLASS_DATA_FLAG;
packetToSend->Command = COMMAND_MSC_WRITE;
return Upstream_TransmitPacket(packetToSend);
}
#endif //#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
HAL_StatusTypeDef Upstream_MSC_RequestDisconnect(UpstreamMSCCallbackTypeDef callback)
{
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE) return HAL_ERROR;
DisconnectCallback = callback;
return Upstream_GetFreePacket(Upstream_MSC_RequestDisconnectFreePacketCallback);
}
static void Upstream_MSC_RequestDisconnectFreePacketCallback(UpstreamPacketTypeDef* freePacket)
{
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16;
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
freePacket->Command = COMMAND_MSC_DISCONNECT;
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
{
//Upstream_PacketManager will free the packet when the transfer is done
if (Upstream_ReceivePacket(Upstream_MSC_RequestDisconnectReplyCallback) != HAL_OK)
{
DisconnectCallback(HAL_ERROR);
}
return;
}
//else:
Upstream_ReleasePacket(freePacket);
DisconnectCallback(HAL_ERROR);
}
static void Upstream_MSC_RequestDisconnectReplyCallback(UpstreamPacketTypeDef* replyPacket)
{
//Acknowledge the SCSI Stop command to host now.
//We will disconnect from host when Downstream replies with COMMAND_ERROR_DEVICE_DISCONNECTED.
Upstream_ReleasePacket(replyPacket);
DisconnectCallback(HAL_OK);
}
#endif //#ifdef CONFIG_MASS_STORAGE_ENABLED

@ -0,0 +1,545 @@
/*
* upstream_spi.c
*
* Created on: 21/06/2015
* Author: Robert Fisk
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "upstream_interface_def.h"
#include "upstream_spi.h"
#include "stm32f4xx_hal.h"
#include "board_config.h"
#include "interrupts.h"
SPI_HandleTypeDef Hspi1;
UpstreamPacketTypeDef UpstreamPacket0;
UpstreamPacketTypeDef UpstreamPacket1;
UpstreamPacketTypeDef* CurrentWorkingPacket;
UpstreamPacketTypeDef* NextTxPacket = NULL; //Indicates we have a pending TX packet
InterfaceStateTypeDef UpstreamInterfaceState = UPSTREAM_INTERFACE_IDLE;
FreePacketCallbackTypeDef PendingFreePacketCallback = NULL; //Indicates someone is waiting for a packet buffer to become available
SpiPacketReceivedCallbackTypeDef ReceivePacketCallback = NULL; //Indicates someone is waiting for a received packet
uint32_t TemporaryIncomingPacketLength; //We don't actually care about what Downstream sends us when we are transmitting. We just need somewhere to put it so that our own packet length is not overwritten.
uint8_t TxOkInterruptReceived = 0;
uint8_t SentCommandClass;
uint8_t SentCommand;
void Upstream_BeginTransmitPacketSize(void);
void Upstream_BeginTransmitPacketBody(void);
HAL_StatusTypeDef Upstream_CheckBeginPacketReception(void);
void Upstream_BeginReceivePacketSize(UpstreamPacketTypeDef* freePacket);
void Upstream_BeginReceivePacketBody(void);
void Upstream_InitSPI(void)
{
UpstreamPacket0.Busy = NOT_BUSY;
UpstreamPacket1.Busy = NOT_BUSY;
Hspi1.Instance = SPI1;
Hspi1.State = HAL_SPI_STATE_RESET;
Hspi1.Init.Mode = SPI_MODE_MASTER;
Hspi1.Init.Direction = SPI_DIRECTION_2LINES;
Hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
Hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
Hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
Hspi1.Init.NSS = SPI_NSS_SOFT;
Hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; //42MHz APB2 / 4 = 10.5Mbaud
Hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
Hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
Hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_ENABLED;
Hspi1.Init.CRCPolynomial = SPI_CRC_DEFAULTPOLYNOMIAL;
HAL_SPI_Init(&Hspi1);
if (DOWNSTREAM_TX_OK_ACTIVE)
{
TxOkInterruptReceived = 1;
}
}
//Used by USB interface classes, and by our internal RX code.
HAL_StatusTypeDef Upstream_GetFreePacket(FreePacketCallbackTypeDef callback)
{
if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_ERROR)
{
return HAL_ERROR;
}
//Do we already have a queued callback?
if (PendingFreePacketCallback != NULL)
{
UPSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
}
//Check if there is a free buffer now
if (UpstreamPacket0.Busy == NOT_BUSY)
{
UpstreamPacket0.Busy = BUSY;
callback(&UpstreamPacket0);
return HAL_OK;
}
if (UpstreamPacket1.Busy == NOT_BUSY)
{
UpstreamPacket1.Busy = BUSY;
callback(&UpstreamPacket1);
return HAL_OK;
}
//Otherwise save requested address for when a buffer becomes free in the future
PendingFreePacketCallback = callback;
return HAL_OK;
}
UpstreamPacketTypeDef* Upstream_GetFreePacketImmediately(void)
{
if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_ERROR)
{
return NULL;
}
//We are expecting a free buffer now
if (UpstreamPacket0.Busy == NOT_BUSY)
{
UpstreamPacket0.Busy = BUSY;
return &UpstreamPacket0;
}
if (UpstreamPacket1.Busy == NOT_BUSY)
{
UpstreamPacket1.Busy = BUSY;
return &UpstreamPacket1;
}
//Should not happen:
UPSTREAM_SPI_FREAKOUT;
return NULL;
}
//Used by USB interface classes, and by our internal RX code.
void Upstream_ReleasePacket(UpstreamPacketTypeDef* packetToRelease)
{
FreePacketCallbackTypeDef tempCallback;
if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_ERROR)
{
return;
}
if ((packetToRelease != &UpstreamPacket0) &&
(packetToRelease != &UpstreamPacket1))
{
UPSTREAM_SPI_FREAKOUT;
return;
}
if (packetToRelease->Busy != BUSY)
{
UPSTREAM_SPI_FREAKOUT;
return;
}
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 USB interface classes only.
//OK to call when still transmitting another packet.
//Not OK to call when receiving or waiting for downstream reply,
//as we can't let the size/packet sequence get out of sync.
HAL_StatusTypeDef Upstream_TransmitPacket(UpstreamPacketTypeDef* packetToWrite)
{
if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_ERROR)
{
return HAL_ERROR;
}
//Sanity checks
if ((packetToWrite != &UpstreamPacket0) &&
(packetToWrite != &UpstreamPacket1))
{
UPSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
}
if ((packetToWrite->Busy != BUSY) ||
(packetToWrite->Length16 < UPSTREAM_PACKET_LEN_MIN_16) ||
(packetToWrite->Length16 > UPSTREAM_PACKET_LEN_16))
{
UPSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
}
if (NextTxPacket != NULL)
{
UPSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
}
switch (UpstreamInterfaceState)
{
case UPSTREAM_INTERFACE_TX_SIZE_WAIT:
case UPSTREAM_INTERFACE_TX_SIZE:
case UPSTREAM_INTERFACE_TX_PACKET_WAIT:
case UPSTREAM_INTERFACE_TX_PACKET:
NextTxPacket = packetToWrite;
break;
case UPSTREAM_INTERFACE_IDLE:
UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_SIZE_WAIT;
CurrentWorkingPacket = packetToWrite;
SentCommandClass = CurrentWorkingPacket->CommandClass;
SentCommand = CurrentWorkingPacket->Command;
//Downstream may have set TxOk pin before we wanted to transmit.
//In this case we can go ahead and transmit now.
if (TxOkInterruptReceived)
{
TxOkInterruptReceived = 0;
Upstream_BeginTransmitPacketSize();
}
break;
default:
UPSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
}
return HAL_OK;
}
//Called at the end of the SPI TxRx transfer,
//at SPI1 interrupt priority. Assume *hspi points to our hspi1.
//We TxRx our outgoing packet because the SPI hardware freaks out if we only Tx it :-/
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
UNUSED(hspi);
SpiPacketReceivedCallbackTypeDef tempPacketCallback;
UpstreamPacketTypeDef* tempPacketToFree;
SPI1_NSS_DEASSERT;
if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_ERROR)
{
return;
}
//Finished transmitting packet size
if (UpstreamInterfaceState == UPSTREAM_INTERFACE_TX_SIZE)
{
UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_PACKET_WAIT;
if (TxOkInterruptReceived)
{
TxOkInterruptReceived = 0;
Upstream_BeginTransmitPacketBody();
}
return;
}
//Finished transmitting packet body
if (UpstreamInterfaceState == UPSTREAM_INTERFACE_TX_PACKET)
{
if ((PendingFreePacketCallback != NULL) && (NextTxPacket == NULL))
{
UPSTREAM_SPI_FREAKOUT;
return;
}
tempPacketToFree = CurrentWorkingPacket;
if (NextTxPacket != NULL)
{
//NextTxPacket has already passed the checks in Upstream_TransmitPacket.
//So we just need to pass it to HAL_SPI_Transmit_DMA.
UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_SIZE_WAIT;
CurrentWorkingPacket = NextTxPacket;
NextTxPacket = NULL;
SentCommandClass = CurrentWorkingPacket->CommandClass;
SentCommand = CurrentWorkingPacket->Command;
if (TxOkInterruptReceived)
{
TxOkInterruptReceived = 0;
Upstream_BeginTransmitPacketSize();
}
}
else
{
//No packet queued for transmission:
UpstreamInterfaceState = UPSTREAM_INTERFACE_IDLE;
if (ReceivePacketCallback != NULL)
{
Upstream_CheckBeginPacketReception();
}
}
//Release old packet after moving Next to Current
Upstream_ReleasePacket(tempPacketToFree);
return;
}
if (UpstreamInterfaceState == UPSTREAM_INTERFACE_RX_SIZE)
{
if ((CurrentWorkingPacket->Length16 < UPSTREAM_PACKET_LEN_MIN_16) ||
(CurrentWorkingPacket->Length16 > UPSTREAM_PACKET_LEN_16))
{
UPSTREAM_SPI_FREAKOUT;
return;
}
UpstreamInterfaceState = UPSTREAM_INTERFACE_RX_PACKET_WAIT;
if (TxOkInterruptReceived)
{
TxOkInterruptReceived = 0;
Upstream_BeginReceivePacketBody();
}
return;
}
if (UpstreamInterfaceState == UPSTREAM_INTERFACE_RX_PACKET)
{
UpstreamInterfaceState = UPSTREAM_INTERFACE_IDLE;
if (ReceivePacketCallback == NULL)
{
UPSTREAM_SPI_FREAKOUT;
return;
}
if ((CurrentWorkingPacket->CommandClass == COMMAND_CLASS_ERROR) &&
(CurrentWorkingPacket->Command == COMMAND_ERROR_DEVICE_DISCONNECTED))
{
Upstream_ReleasePacket(CurrentWorkingPacket);
ReceivePacketCallback = NULL;
Upstream_StateMachine_DeviceDisconnected();
return;
}
if (((CurrentWorkingPacket->CommandClass & COMMAND_CLASS_MASK) != (SentCommandClass & COMMAND_CLASS_MASK)) ||
(CurrentWorkingPacket->Command != SentCommand))
{
UPSTREAM_SPI_FREAKOUT;
Upstream_ReleasePacket(CurrentWorkingPacket);
CurrentWorkingPacket = NULL; //Call back with a NULL packet to indicate error
}
//USB interface 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);
return;
}
//case default:
UPSTREAM_SPI_FREAKOUT;
}
//Used by USB interface classes.
//Ok to call when idle or transmitting.
//Not OK to call when receiving or waiting for downstream reply.
HAL_StatusTypeDef Upstream_ReceivePacket(SpiPacketReceivedCallbackTypeDef callback)
{
if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_ERROR)
{
return HAL_ERROR;
}
if (ReceivePacketCallback != NULL)
{
UPSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
}
ReceivePacketCallback = callback;
return Upstream_CheckBeginPacketReception();
}
//Internal use only.
HAL_StatusTypeDef Upstream_CheckBeginPacketReception(void)
{
if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_ERROR)
{
return HAL_ERROR;
}
if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_RX_SIZE_WAIT)
{
UPSTREAM_SPI_FREAKOUT;
return HAL_ERROR;
}
if (UpstreamInterfaceState == UPSTREAM_INTERFACE_IDLE)
{
UpstreamInterfaceState = UPSTREAM_INTERFACE_RX_SIZE_WAIT;
if (TxOkInterruptReceived)
{
TxOkInterruptReceived = 0;
Upstream_GetFreePacket(Upstream_BeginReceivePacketSize);
}
}
return HAL_OK;
}
//This is called by EXTI3 falling edge interrupt,
//indicating that downstream is ready for the next transaction.
void Upstream_TxOkInterrupt(void)
{
if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_ERROR)
{
return;
}
switch (UpstreamInterfaceState)
{
case UPSTREAM_INTERFACE_IDLE:
TxOkInterruptReceived = 1;
break;
case UPSTREAM_INTERFACE_TX_SIZE_WAIT:
Upstream_BeginTransmitPacketSize();
break;
case UPSTREAM_INTERFACE_TX_PACKET_WAIT:
Upstream_BeginTransmitPacketBody();
break;
case UPSTREAM_INTERFACE_RX_SIZE_WAIT:
Upstream_GetFreePacket(Upstream_BeginReceivePacketSize);
break;
case UPSTREAM_INTERFACE_RX_PACKET_WAIT:
Upstream_BeginReceivePacketBody();
break;
default:
UPSTREAM_SPI_FREAKOUT;
}
}
void Upstream_BeginTransmitPacketSize(void)
{
UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_SIZE;
SPI1_NSS_ASSERT;
if (HAL_SPI_TransmitReceive(&Hspi1,
(uint8_t*)&CurrentWorkingPacket->Length16,
(uint8_t*)&TemporaryIncomingPacketLength,
2, //We only need to write one word, but the peripheral library freaks out...
SPI_TIMEOUT_VALUE) != HAL_OK)
{
UPSTREAM_SPI_FREAKOUT;
}
HAL_SPI_TxRxCpltCallback(&Hspi1);
}
void Upstream_BeginTransmitPacketBody(void)
{
UpstreamInterfaceState = UPSTREAM_INTERFACE_TX_PACKET;
SPI1_NSS_ASSERT;
if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
&CurrentWorkingPacket->CommandClass,
&CurrentWorkingPacket->CommandClass,
((CurrentWorkingPacket->Length16 < 2) ? 2 : CurrentWorkingPacket->Length16)) != HAL_OK)
{
UPSTREAM_SPI_FREAKOUT;
}
}
//Internal use only.
//Called when we want to receive downstream packet, and a packet buffer has become free.
void Upstream_BeginReceivePacketSize(UpstreamPacketTypeDef* freePacket)
{
if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_ERROR)
{
return;
}
if (UpstreamInterfaceState != UPSTREAM_INTERFACE_RX_SIZE_WAIT)
{
UPSTREAM_SPI_FREAKOUT;
return;
}
UpstreamInterfaceState = UPSTREAM_INTERFACE_RX_SIZE;
CurrentWorkingPacket = freePacket;
CurrentWorkingPacket->Length16 = 0; //Our RX buffer is used by HAL_SPI_TransmitReceive_DMA as dummy TX data, we set Length to 0 so downstream will know this is a dummy packet.
SPI1_NSS_ASSERT;
if (HAL_SPI_TransmitReceive(&Hspi1,
(uint8_t*)&CurrentWorkingPacket->Length16,
(uint8_t*)&CurrentWorkingPacket->Length16,
2, //We only need to write one word, but the peripheral library freaks out...
SPI_TIMEOUT_VALUE) != HAL_OK)
{
UPSTREAM_SPI_FREAKOUT;
}
HAL_SPI_TxRxCpltCallback(&Hspi1);
}
void Upstream_BeginReceivePacketBody(void)
{
UpstreamInterfaceState = UPSTREAM_INTERFACE_RX_PACKET;
SPI1_NSS_ASSERT;
if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
&CurrentWorkingPacket->CommandClass,
&CurrentWorkingPacket->CommandClass,
((CurrentWorkingPacket->Length16 < 2) ? 2 : CurrentWorkingPacket->Length16)) != HAL_OK)
{
UPSTREAM_SPI_FREAKOUT;
}
}
//Something bad happened! Possibly CRC error...
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
UNUSED(hspi);
SpiPacketReceivedCallbackTypeDef tempPacketCallback;
if (UpstreamInterfaceState >= UPSTREAM_INTERFACE_ERROR)
{
return;
}
UPSTREAM_SPI_FREAKOUT;
if (ReceivePacketCallback != NULL)
{
tempPacketCallback = ReceivePacketCallback;
ReceivePacketCallback = NULL;
tempPacketCallback(NULL); //Call back with a NULL packet to indicate error
}
}

@ -0,0 +1,347 @@
/*
* upstream_statemachine.c
*
* Created on: 20/08/2015
* Author: Robert Fisk
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "upstream_statemachine.h"
#include "upstream_spi.h"
#include "upstream_hid.h"
#include "usb_device.h"
#include "usbd_core.h"
#include "usbd_msc.h"
#include "usbd_hid.h"
#include "build_config.h"
#define POLL_DEVICE_CONNECTED_TIMEOUT_MS 1000
UpstreamStateTypeDef UpstreamState = STATE_TEST_INTERFACE;
InterfaceCommandClassTypeDef ConfiguredDeviceClass = COMMAND_CLASS_INTERFACE;
uint32_t PollDeviceConnectedTimer;
void Upstream_StateMachine_TestInterfaceReplyCallback(UpstreamPacketTypeDef* replyPacket);
void Upstream_StateMachine_NotifyDevice(UpstreamPacketTypeDef* freePacket);
void Upstream_StateMachine_NotifyDeviceReplyCallback(UpstreamPacketTypeDef* replyPacket);
void Upstream_StateMachine_PollDeviceConnectedReplyCallback(UpstreamPacketTypeDef* replyPacket);
void Upstream_InitStateMachine(void)
{
UpstreamPacketTypeDef* freePacket;
uint16_t i;
uint8_t testDataValue;
Upstream_InitSPI();
//Prepare SPI test packet
freePacket = Upstream_GetFreePacketImmediately();
if (freePacket == NULL)
{
UpstreamState = STATE_ERROR;
return;
}
freePacket->Length16 = UPSTREAM_PACKET_LEN_16;
freePacket->CommandClass = COMMAND_CLASS_INTERFACE;
freePacket->Command = COMMAND_INTERFACE_ECHO;
//Fill our test packet with some junk
testDataValue = 0xFF;
for (i = 0; i < MSC_MEDIA_PACKET; i++)
{
freePacket->Data[i] = testDataValue;
testDataValue += 39;
}
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
{
Upstream_ReceivePacket(Upstream_StateMachine_TestInterfaceReplyCallback);
}
}
//Used by upstream_spi freakout macro, indicates we should stop everything.
void Upstream_StateMachine_SetErrorState(void)
{
UpstreamState = STATE_ERROR;
if ((ConfiguredDeviceClass > COMMAND_CLASS_INTERFACE) &&
(ConfiguredDeviceClass < COMMAND_CLASS_ERROR))
{
USBD_DeInit(&hUsbDeviceFS);
}
}
InterfaceCommandClassTypeDef Upstream_StateMachine_CheckActiveClass(void)
{
if (UpstreamState == STATE_ERROR)
{
return COMMAND_CLASS_ERROR;
}
if ((UpstreamState == STATE_DEVICE_ACTIVE) ||
(UpstreamState == STATE_SUSPENDED))
{
return ConfiguredDeviceClass;
}
//else:
UPSTREAM_STATEMACHINE_FREAKOUT;
return COMMAND_CLASS_INTERFACE;
}
uint32_t Upstream_StateMachine_GetSuspendState(void)
{
if (UpstreamState == STATE_SUSPENDED)
{
return 1;
}
return 0;
}
void Upstream_StateMachine_TestInterfaceReplyCallback(UpstreamPacketTypeDef* replyPacket)
{
uint16_t i;
uint8_t testDataValue;
if (UpstreamState >= STATE_ERROR)
{
return;
}
if ((UpstreamState != STATE_TEST_INTERFACE) ||
(replyPacket == NULL))
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
if (replyPacket->Length16 != UPSTREAM_PACKET_LEN_16)
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
testDataValue = 0xFF;
for (i = 0; i < MSC_MEDIA_PACKET; i++)
{
if (replyPacket->Data[i] != testDataValue)
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
testDataValue += 39;
}
//SPI interface passed checks. Now we wait for a device to be attached to downstream.
Upstream_StateMachine_NotifyDevice(replyPacket);
}
void Upstream_StateMachine_NotifyDevice(UpstreamPacketTypeDef* freePacket)
{
UpstreamState = STATE_WAIT_DEVICE;
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16;
freePacket->CommandClass = COMMAND_CLASS_INTERFACE;
freePacket->Command = COMMAND_INTERFACE_NOTIFY_DEVICE;
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
{
Upstream_ReceivePacket(Upstream_StateMachine_NotifyDeviceReplyCallback);
}
}
void Upstream_StateMachine_NotifyDeviceReplyCallback(UpstreamPacketTypeDef* replyPacket)
{
InterfaceCommandClassTypeDef newActiveClass = COMMAND_CLASS_INTERFACE;
USBD_ClassTypeDef* newClassPointer;
if (UpstreamState >= STATE_ERROR)
{
return;
}
if ((UpstreamState != STATE_WAIT_DEVICE) ||
(replyPacket == NULL))
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
if (replyPacket->Length16 != (UPSTREAM_PACKET_HEADER_LEN_16 + 1))
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
switch (replyPacket->Data[0])
{
#ifdef CONFIG_MASS_STORAGE_ENABLED
case COMMAND_CLASS_MASS_STORAGE:
newActiveClass = COMMAND_CLASS_MASS_STORAGE;
newClassPointer = &USBD_MSC;
break;
#endif
#ifdef CONFIG_MOUSE_ENABLED
case COMMAND_CLASS_HID_MOUSE:
newActiveClass = COMMAND_CLASS_HID_MOUSE;
newClassPointer = &USBD_HID;
USBD_HID_PreinitMouse();
break;
#endif
#ifdef CONFIG_KEYBOARD_ENABLED
case COMMAND_CLASS_HID_KEYBOARD:
newActiveClass = COMMAND_CLASS_HID_KEYBOARD;
newClassPointer = &USBD_HID;
USBD_HID_PreinitKeyboard();
break;
#endif
//Add other supported classes here...
}
Upstream_ReleasePacket(replyPacket);
if (newActiveClass == COMMAND_CLASS_INTERFACE)
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
//Downstream should never change the active device class without rebooting!
if ((ConfiguredDeviceClass != COMMAND_CLASS_INTERFACE) &&
(ConfiguredDeviceClass != newActiveClass))
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
UpstreamState = STATE_DEVICE_ACTIVE;
ConfiguredDeviceClass = newActiveClass;
USB_Device_Init();
USBD_RegisterClass(&hUsbDeviceFS, newClassPointer);
USBD_Start(&hUsbDeviceFS);
//The USB device stack will now receive commands from our host.
//All we need to do is monitor for downstream device disconnection.
}
void Upstream_StateMachine_DeviceDisconnected(void)
{
if ((ConfiguredDeviceClass == COMMAND_CLASS_INTERFACE) ||
(ConfiguredDeviceClass >= COMMAND_CLASS_ERROR))
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
USBD_DeInit(&hUsbDeviceFS);
Upstream_GetFreePacket(Upstream_StateMachine_NotifyDevice);
}
//Suspend event activated by our host
void Upstream_StateMachine_Suspend(void)
{
if (UpstreamState >= STATE_SUSPENDED) //Ignore when already suspended, or in error state
{
return;
}
if (UpstreamState != STATE_DEVICE_ACTIVE)
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
PollDeviceConnectedTimer = 0;
UpstreamState = STATE_SUSPENDED;
}
//Resume event activated by our host
void Upstream_StateMachine_CheckResume(void)
{
if (UpstreamState == STATE_SUSPENDED)
{
UpstreamState = STATE_DEVICE_ACTIVE;
}
}
//Activated by downstream report, causing us to wake up the host
void Upstream_StateMachine_Wakeup(void)
{
USBD_ClassTypeDef* activeClass;
if (UpstreamState != STATE_SUSPENDED)
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
//This is how I'd wakeup the host, IF IT ACTUALLY WORKED!
//USBD_LL_WakeupHost(&hUsbDeviceFS);
//This is really ugly! But wakeup seems to be broken on the STM32, so we do it the hard way.
activeClass = USBD_DeInit(&hUsbDeviceFS);
USB_Device_Init();
USBD_RegisterClass(&hUsbDeviceFS, activeClass);
USBD_Start(&hUsbDeviceFS);
}
//Called by Systick_Handler every 1ms, at high interrupt priority.
void Upstream_StateMachine_PollDeviceConnected(void)
{
UpstreamPacketTypeDef* freePacket;
if ((UpstreamState != STATE_SUSPENDED) ||
(ConfiguredDeviceClass != COMMAND_CLASS_MASS_STORAGE))
{
return;
}
if (++PollDeviceConnectedTimer >= POLL_DEVICE_CONNECTED_TIMEOUT_MS)
{
PollDeviceConnectedTimer = 0;
freePacket = Upstream_GetFreePacketImmediately();
if (freePacket == NULL)
{
UpstreamState = STATE_ERROR;
return;
}
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16;
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
freePacket->Command = COMMAND_MSC_POLL_DISCONNECT;
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
{
Upstream_ReceivePacket(Upstream_StateMachine_PollDeviceConnectedReplyCallback);
}
}
}
void Upstream_StateMachine_PollDeviceConnectedReplyCallback(UpstreamPacketTypeDef* replyPacket)
{
if ((UpstreamState != STATE_SUSPENDED) ||
(replyPacket == NULL))
{
UPSTREAM_STATEMACHINE_FREAKOUT;
return;
}
//Downstream device is still connected, so nothing to do here
Upstream_ReleasePacket(replyPacket);
}

@ -0,0 +1,61 @@
/**
******************************************************************************
* @file : USB_DEVICE
* @date : 03/02/2015 20:26:59
* @version : v1.0_Cube
* @brief : This file implements the USB Device
******************************************************************************
*
* COPYRIGHT(c) 2015 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*
* Modifications by Robert Fisk
*/
#include "usbd_descriptors.h"
#include "usb_device.h"
#include "usbd_core.h"
#include "usbd_msc.h"
/* USB Device Core handle declaration */
USBD_HandleTypeDef hUsbDeviceFS;
void USB_Device_Init(void)
{
USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS);
// USBD_RegisterClass(&hUsbDeviceFS, &USBD_MSC);
// USBD_Start(&hUsbDeviceFS);
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -0,0 +1,517 @@
/**
******************************************************************************
* @file : usbd_conf.c
* @date : 03/02/2015 20:26:59
* @version : v1.0_Cube
* @brief : This file implements the board support package for the USB device library
******************************************************************************
*
* COPYRIGHT(c) 2015 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*
* Modifications by Robert Fisk
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"
#include "usbd_def.h"
#include "usbd_core.h"
#include "interrupts.h"
PCD_HandleTypeDef hpcd_USB_OTG_FS;
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/*******************************************************************************
LL Driver Callbacks (PCD -> USB Device Library)
*******************************************************************************/
/* MSP Init */
void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hpcd->Instance==USB_OTG_FS)
{
/* USER CODE BEGIN USB_OTG_FS_MspInit 0 */
/* USER CODE END USB_OTG_FS_MspInit 0 */
/* Peripheral clock enable */
__USB_OTG_FS_CLK_ENABLE();
/**USB_OTG_FS GPIO Configuration
PA11 ------> USB_OTG_FS_DM
PA12 ------> USB_OTG_FS_DP
*/
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_SetPriority(OTG_FS_IRQn, INT_PRIORITY_USB, 0);
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
/* USER CODE BEGIN USB_OTG_FS_MspInit 1 */
/* USER CODE END USB_OTG_FS_MspInit 1 */
}
}
void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd)
{
if(hpcd->Instance==USB_OTG_FS)
{
/* USER CODE BEGIN USB_OTG_FS_MspDeInit 0 */
/* USER CODE END USB_OTG_FS_MspDeInit 0 */
/* Peripheral clock disable */
__USB_OTG_FS_CLK_DISABLE();
/**USB_OTG_FS GPIO Configuration
PA11 ------> USB_OTG_FS_DM
PA12 ------> USB_OTG_FS_DP
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
/* Peripheral interrupt Deinit*/
HAL_NVIC_DisableIRQ(OTG_FS_IRQn);
/* USER CODE BEGIN USB_OTG_FS_MspDeInit 1 */
/* USER CODE END USB_OTG_FS_MspDeInit 1 */
}
}
/**
* @brief Setup stage callback
* @param hpcd: PCD handle
* @retval None
*/
void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
{
USBD_SetupStage(hpcd->pData, (uint8_t *)hpcd->Setup);
}
/**
* @brief Data Out stage callback.
* @param hpcd: PCD handle
* @param epnum: Endpoint Number
* @retval None
*/
void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
{
USBD_DataOutStage(hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
}
/**
* @brief Data In stage callback..
* @param hpcd: PCD handle
* @param epnum: Endpoint Number
* @retval None
*/
void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
{
USBD_DataInStage(hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff);
}
/**
* @brief SOF callback.
* @param hpcd: PCD handle
* @retval None
*/
void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
{
USBD_SOF(hpcd->pData);
}
/**
* @brief Reset callback.
* @param hpcd: PCD handle
* @retval None
*/
void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
{
USBD_SpeedTypeDef speed = USBD_SPEED_FULL;
/*Set USB Current Speed*/
switch (hpcd->Init.speed)
{
case PCD_SPEED_HIGH:
speed = USBD_SPEED_HIGH;
break;
// case PCD_SPEED_FULL:
// speed = USBD_SPEED_FULL;
// break;
//
// default:
// speed = USBD_SPEED_FULL;
// break;
}
USBD_SetSpeed(hpcd->pData, speed);
/*Reset Device*/
USBD_Reset(hpcd->pData);
}
/**
* @brief Suspend callback.
* When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
* @param hpcd: PCD handle
* @retval None
*/
void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
{
/* Inform USB library that core enters in suspend Mode */
USBD_Suspend(hpcd->pData);
__HAL_PCD_GATE_PHYCLOCK(hpcd);
/*Enter in STOP mode */
/* USER CODE BEGIN 2 */
if (hpcd->Init.low_power_enable)
{
/* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register */
//SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
}
/* USER CODE END 2 */
}
/**
* @brief Resume callback.
When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
* @param hpcd: PCD handle
* @retval None
*/
void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)
{
/* USER CODE BEGIN 3 */
if (hpcd->Init.low_power_enable)
{
/* Reset SLEEPDEEP bit of Cortex System Control Register */
//SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
}
/* USER CODE END 3 */
__HAL_PCD_UNGATE_PHYCLOCK(hpcd);
USBD_Resume(hpcd->pData);
}
/**
* @brief ISOC Out Incomplete callback.
* @param hpcd: PCD handle
* @param epnum: Endpoint Number
* @retval None
*/
void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
{
USBD_IsoOUTIncomplete(hpcd->pData, epnum);
}
/**
* @brief ISOC In Incomplete callback.
* @param hpcd: PCD handle
* @param epnum: Endpoint Number
* @retval None
*/
void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
{
USBD_IsoINIncomplete(hpcd->pData, epnum);
}
/**
* @brief Connect callback.
* @param hpcd: PCD handle
* @retval None
*/
void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd)
{
USBD_DevConnected(hpcd->pData);
}
/**
* @brief Disconnect callback.
* @param hpcd: PCD handle
* @retval None
*/
void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
{
USBD_DevDisconnected(hpcd->pData);
}
void HAL_PCD_BufferFreedCallBack(PCD_HandleTypeDef *hpcd)
{
USBD_BufferFreed(hpcd->pData);
}
/*******************************************************************************
LL Driver Interface (USB Device Library --> PCD)
*******************************************************************************/
/**
* @brief Initializes the Low Level portion of the Device driver.
* @param pdev: Device handle
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev)
{
/* Init USB_IP */
if (pdev->id == DEVICE_FS) {
/* Link The driver to the stack */
hpcd_USB_OTG_FS.pData = pdev;
pdev->pData = &hpcd_USB_OTG_FS;
hpcd_USB_OTG_FS.Instance = USB_OTG_FS;
hpcd_USB_OTG_FS.Init.dev_endpoints = 7;
hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL;
hpcd_USB_OTG_FS.Init.dma_enable = DISABLE;
hpcd_USB_OTG_FS.Init.ep0_mps = DEP0CTL_MPS_64;
hpcd_USB_OTG_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
hpcd_USB_OTG_FS.Init.Sof_enable = ENABLE;
hpcd_USB_OTG_FS.Init.low_power_enable = DISABLE;
hpcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE;
hpcd_USB_OTG_FS.Init.use_dedicated_ep1 = DISABLE;
hpcd_USB_OTG_FS.Init.use_external_vbus = DISABLE;
HAL_PCD_Init(&hpcd_USB_OTG_FS);
HAL_PCD_SetRxFiFo(&hpcd_USB_OTG_FS, 0x80);
HAL_PCD_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 0x40);
HAL_PCD_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 0x80);
}
return USBD_OK;
}
/**
* @brief De-Initializes the Low Level portion of the Device driver.
* @param pdev: Device handle
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_DeInit (USBD_HandleTypeDef *pdev)
{
HAL_PCD_DeInit(pdev->pData);
return USBD_OK;
}
/**
* @brief Starts the Low Level portion of the Device driver.
* @param pdev: Device handle
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev)
{
HAL_PCD_Start(pdev->pData);
return USBD_OK;
}
/**
* @brief Stops the Low Level portion of the Device driver.
* @param pdev: Device handle
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_Stop (USBD_HandleTypeDef *pdev)
{
HAL_PCD_Stop(pdev->pData);
return USBD_OK;
}
/**
* @brief Opens an endpoint of the Low Level Driver.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @param ep_type: Endpoint Type
* @param ep_mps: Endpoint Max Packet Size
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_OpenEP (USBD_HandleTypeDef *pdev,
uint8_t ep_addr,
uint8_t ep_type,
uint16_t ep_mps)
{
HAL_PCD_EP_Open(pdev->pData,
ep_addr,
ep_mps,
ep_type);
return USBD_OK;
}
/**
* @brief Closes an endpoint of the Low Level Driver.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_CloseEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
HAL_PCD_EP_Close(pdev->pData, ep_addr);
return USBD_OK;
}
/**
* @brief Flushes an endpoint of the Low Level Driver.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_FlushEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
HAL_PCD_EP_Flush(pdev->pData, ep_addr);
return USBD_OK;
}
/**
* @brief Sets a Stall condition on an endpoint of the Low Level Driver.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_StallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
HAL_PCD_EP_SetStall(pdev->pData, ep_addr);
return USBD_OK;
}
/**
* @brief Clears a Stall condition on an endpoint of the Low Level Driver.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_ClearStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
HAL_PCD_EP_ClrStall(pdev->pData, ep_addr);
return USBD_OK;
}
/**
* @brief Returns Stall condition.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval Stall (1: Yes, 0: No)
*/
uint8_t USBD_LL_IsStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
PCD_HandleTypeDef *hpcd = pdev->pData;
if((ep_addr & 0x80) == 0x80)
{
return hpcd->IN_ep[ep_addr & 0x7F].is_stall;
}
else
{
return hpcd->OUT_ep[ep_addr & 0x7F].is_stall;
}
}
/**
* @brief Assigns a USB address to the device.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_SetUSBAddress (USBD_HandleTypeDef *pdev, uint8_t dev_addr)
{
HAL_PCD_SetAddress(pdev->pData, dev_addr);
return USBD_OK;
}
/**
* @brief Transmits data over an endpoint.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @param pbuf: Pointer to data to be sent
* @param size: Data size
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_Transmit (USBD_HandleTypeDef *pdev,
uint8_t ep_addr,
uint8_t *pbuf,
uint16_t size)
{
HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size);
return USBD_OK;
}
/**
* @brief Prepares an endpoint for reception.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @param pbuf: Pointer to data to be received
* @param size: Data size
* @retval USBD Status
*/
USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev,
uint8_t ep_addr,
uint8_t *pbuf,
uint16_t size)
{
HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size);
return USBD_OK;
}
/**
* @brief Returns the last transfered packet size.
* @param pdev: Device handle
* @param ep_addr: Endpoint Number
* @retval Recived Data Size
*/
uint32_t USBD_LL_GetRxDataSize (USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
return HAL_PCD_EP_GetRxCount(pdev->pData, ep_addr);
}
/**
* @brief Delays routine for the USB Device Library.
* @param Delay: Delay in ms
* @retval None
*/
void USBD_LL_Delay (uint32_t Delay)
{
HAL_Delay(Delay);
}
void USBD_LL_WakeupHost(USBD_HandleTypeDef *pdev)
{
if (pdev->dev_remote_wakeup == 1)
{
HAL_PCD_ActivateRemoteWakeup(pdev->pData);
HAL_Delay(10);
HAL_PCD_DeActivateRemoteWakeup(pdev->pData);
}
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -0,0 +1,288 @@
/**
******************************************************************************
* @file : usbd_desc.c
* @date : 03/02/2015 20:26:59
* @version : v1.0_Cube
* @brief : This file implements the USB Device descriptors
******************************************************************************
*
* COPYRIGHT(c) 2015 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*
* Modifications by Robert Fisk
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_config.h"
#include "usbd_descriptors.h"
#include "usbd_core.h"
#include "usbd_msc.h"
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_DESC
* @brief USBD descriptors module
* @{
*/
/** @defgroup USBD_DESC_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DESC_Private_Defines
* @{
*/
#define USBD_VID 0xF000 //TODO: get a real VID :) We also need a separate PID for each supported device class.
#define USBD_LANGID_STRING 1033
#define USBD_MANUFACTURER_STRING "The USG is Good, not Bad"
#define USBD_PRODUCT_STRING_FS "USG v1.0"
#define USBD_SERIALNUMBER_STRING_FS "00000000001A"
#define USBD_CONFIGURATION_STRING_FS "USG multipurpose configuration"
#define USBD_INTERFACE_STRING_FS "USG multipurpose interface"
/**
* @}
*/
/** @defgroup USBD_DESC_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DESC_Private_Variables
* @{
*/
uint8_t * USBD_FS_DeviceDescriptor( USBD_SpeedTypeDef speed , uint16_t *length);
uint8_t * USBD_FS_LangIDStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length);
uint8_t * USBD_FS_ManufacturerStrDescriptor ( USBD_SpeedTypeDef speed , uint16_t *length);
uint8_t * USBD_FS_ProductStrDescriptor ( USBD_SpeedTypeDef speed , uint16_t *length);
uint8_t * USBD_FS_SerialStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length);
uint8_t * USBD_FS_ConfigStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length);
uint8_t * USBD_FS_InterfaceStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length);
#ifdef USB_SUPPORT_USER_STRING_DESC
uint8_t * USBD_FS_USRStringDesc (USBD_SpeedTypeDef speed, uint8_t idx , uint16_t *length);
#endif /* USB_SUPPORT_USER_STRING_DESC */
USBD_DescriptorsTypeDef FS_Desc =
{
USBD_FS_DeviceDescriptor,
USBD_FS_LangIDStrDescriptor,
USBD_FS_ManufacturerStrDescriptor,
USBD_FS_ProductStrDescriptor,
USBD_FS_SerialStrDescriptor,
USBD_FS_ConfigStrDescriptor,
USBD_FS_InterfaceStrDescriptor,
};
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
/* USB Standard Device Descriptor */
__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
{
0x12, /*bLength */
USB_DESC_TYPE_DEVICE, /*bDescriptorType*/
0x00, /*bcdUSB */
0x02,
0x00, /*bDeviceClass*/
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
USB_MAX_EP0_SIZE, /*bMaxPacketSize*/
LOBYTE(USBD_VID), /*idVendor*/
HIBYTE(USBD_VID), /*idVendor*/
0x00, //LOBYTE(USBD_PID_FS), /*idVendor*/
0x00, //HIBYTE(USBD_PID_FS), /*idVendor*/
0x00, /*bcdDevice rel. 2.00*/
0x02,
USBD_IDX_MFC_STR, /*Index of manufacturer string*/
USBD_IDX_PRODUCT_STR, /*Index of product string*/
USBD_IDX_SERIAL_STR, /*Index of serial number string*/
USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/
} ; /* USB_DeviceDescriptor */
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
/* USB Standard Device Descriptor */
__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END =
{
USB_LEN_LANGID_STR_DESC,
USB_DESC_TYPE_STRING,
LOBYTE(USBD_LANGID_STRING),
HIBYTE(USBD_LANGID_STRING),
};
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
/* USB Mass storage Standard Inquiry Data */
const int8_t STORAGE_Inquirydata_FS[] = { //36
/* LUN 0 */
0x00,
0x80,
0x02,
0x02,
(STANDARD_INQUIRY_DATA_LEN - 5),
0x00,
0x00,
0x00,
'T', 'h', 'e', ' ', 'U', 'S', 'G', ' ', /* Manufacturer : 8 bytes */
'i', 's', ' ', 'G', 'o', 'o', 'd', ',', /* Product : 16 Bytes */
' ', 'n', 'o', 't', ' ', 'b', 'a', 'd',
'v', '1', '.' ,'0', /* Version : 4 Bytes */
};
/**
* @}
*/
/** @defgroup USBD_DESC_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DESC_Private_Functions
* @{
*/
/**
* @brief USBD_FS_DeviceDescriptor
* return the device descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_FS_DeviceDescriptor( USBD_SpeedTypeDef speed , uint16_t *length)
{
*length = sizeof(USBD_FS_DeviceDesc);
return USBD_FS_DeviceDesc;
}
/**
* @brief USBD_FS_LangIDStrDescriptor
* return the LangID string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_FS_LangIDStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length)
{
*length = sizeof(USBD_LangIDDesc);
return USBD_LangIDDesc;
}
/**
* @brief USBD_FS_ProductStrDescriptor
* return the product string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_FS_ProductStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length)
{
USBD_GetString (USBD_PRODUCT_STRING_FS, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief USBD_FS_ManufacturerStrDescriptor
* return the manufacturer string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_FS_ManufacturerStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length)
{
USBD_GetString (USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief USBD_FS_SerialStrDescriptor
* return the serial number string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_FS_SerialStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length)
{
USBD_GetString (USBD_SERIALNUMBER_STRING_FS, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief USBD_FS_ConfigStrDescriptor
* return the configuration string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_FS_ConfigStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length)
{
USBD_GetString (USBD_CONFIGURATION_STRING_FS, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief USBD_HS_InterfaceStrDescriptor
* return the interface string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_FS_InterfaceStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length)
{
USBD_GetString (USBD_INTERFACE_STRING_FS, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
Loading…
Cancel
Save