Browse Source

firmware_update

master
Ivan Olenichev 6 months ago
parent
commit
9dfd5e6009
  1. 175
      Upstream/Src/hal_msp.c
  2. 129
      Upstream/Src/interrupts.c
  3. 143
      Upstream/Src/led.c
  4. 258
      Upstream/Src/main.c
  5. 333
      Upstream/Src/upstream_hid.c
  6. 608
      Upstream/Src/upstream_hid_botdetect.c
  7. 403
      Upstream/Src/upstream_msc.c
  8. 545
      Upstream/Src/upstream_spi.c
  9. 347
      Upstream/Src/upstream_statemachine.c
  10. 61
      Upstream/Src/usb_device.c
  11. 517
      Upstream/Src/usbd_config.c
  12. 288
      Upstream/Src/usbd_descriptors.c

175
Upstream/Src/hal_msp.c

@ -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****/

129
Upstream/Src/interrupts.c

@ -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****/

143
Upstream/Src/led.c

@ -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;
}
}
}
}

258
Upstream/Src/main.c

@ -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****/

333
Upstream/Src/upstream_hid.c

@ -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)

608
Upstream/Src/upstream_hid_botdetect.c

@ -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

403