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…
Reference in new issue