From dac73fcd0966594cd3d2b8911d45d73401d874ac Mon Sep 17 00:00:00 2001 From: Ibrahim Abd Elkader Date: Mon, 17 Sep 2018 01:21:49 +0200 Subject: [PATCH] Add webcam/UVC firmware. (#374) --- src/Makefile | 124 +++- src/omv/fb_alloc.c | 2 +- src/webcam/Makefile | 18 + src/webcam/include/stm32fxxx_it.h | 74 +++ src/webcam/include/usbd_conf.h | 81 +++ src/webcam/include/usbd_core.h | 159 +++++ src/webcam/include/usbd_ctlreq.h | 106 ++++ src/webcam/include/usbd_def.h | 323 ++++++++++ src/webcam/include/usbd_desc.h | 34 ++ src/webcam/include/usbd_ioreq.h | 121 ++++ src/webcam/include/usbd_types.h | 65 ++ src/webcam/include/usbd_uvc.h | 372 ++++++++++++ src/webcam/include/usbd_uvc_if.h | 65 ++ src/webcam/include/uvc.h | 522 +++++++++++++++++ src/webcam/include/uvc_desc.h | 61 ++ src/webcam/include/uvc_desc_conf.h | 11 + src/webcam/include/uvc_desc_va.h | 13 + src/webcam/include/uvc_desc_vc.h | 261 +++++++++ src/webcam/include/uvc_desc_vs.h | 75 +++ src/webcam/include/uvc_desc_vs_if.h | 23 + src/webcam/src/main.c | 177 ++++++ src/webcam/src/stm32fxxx_it.c | 165 ++++++ src/webcam/src/string0.c | 219 +++++++ src/webcam/src/systick.c | 21 + src/webcam/src/usbd_conf.c | 522 +++++++++++++++++ src/webcam/src/usbd_core.c | 554 ++++++++++++++++++ src/webcam/src/usbd_ctlreq.c | 769 ++++++++++++++++++++++++ src/webcam/src/usbd_desc.c | 214 +++++++ src/webcam/src/usbd_ioreq.c | 236 ++++++++ src/webcam/src/usbd_uvc.c | 879 ++++++++++++++++++++++++++++ src/webcam/src/usbd_uvc_if.c | 398 +++++++++++++ src/webcam/stm32fxxx.ld.S | 172 ++++++ 32 files changed, 6804 insertions(+), 32 deletions(-) create mode 100755 src/webcam/Makefile create mode 100644 src/webcam/include/stm32fxxx_it.h create mode 100644 src/webcam/include/usbd_conf.h create mode 100644 src/webcam/include/usbd_core.h create mode 100644 src/webcam/include/usbd_ctlreq.h create mode 100644 src/webcam/include/usbd_def.h create mode 100644 src/webcam/include/usbd_desc.h create mode 100644 src/webcam/include/usbd_ioreq.h create mode 100644 src/webcam/include/usbd_types.h create mode 100644 src/webcam/include/usbd_uvc.h create mode 100644 src/webcam/include/usbd_uvc_if.h create mode 100644 src/webcam/include/uvc.h create mode 100644 src/webcam/include/uvc_desc.h create mode 100644 src/webcam/include/uvc_desc_conf.h create mode 100644 src/webcam/include/uvc_desc_va.h create mode 100644 src/webcam/include/uvc_desc_vc.h create mode 100644 src/webcam/include/uvc_desc_vs.h create mode 100644 src/webcam/include/uvc_desc_vs_if.h create mode 100644 src/webcam/src/main.c create mode 100644 src/webcam/src/stm32fxxx_it.c create mode 100644 src/webcam/src/string0.c create mode 100644 src/webcam/src/systick.c create mode 100644 src/webcam/src/usbd_conf.c create mode 100644 src/webcam/src/usbd_core.c create mode 100644 src/webcam/src/usbd_ctlreq.c create mode 100644 src/webcam/src/usbd_desc.c create mode 100644 src/webcam/src/usbd_ioreq.c create mode 100644 src/webcam/src/usbd_uvc.c create mode 100644 src/webcam/src/usbd_uvc_if.c create mode 100755 src/webcam/stm32fxxx.ld.S diff --git a/src/Makefile b/src/Makefile index 9aeb957d7..fdeafc853 100755 --- a/src/Makefile +++ b/src/Makefile @@ -27,6 +27,7 @@ CAT = $(Q)cat # Targets OPENMV = openmv BOOTLOADER = bootloader +WEBCAM = webcam FIRMWARE = firmware # Directories @@ -38,7 +39,8 @@ MICROPY_DIR=micropython OMV_DIR=omv LEPTON_DIR=lepton WINC1500_DIR=winc1500 -BOOT_DIR=bootloader +BOOTLDR_DIR=bootloader +WEBCAM_DIR=webcam # Additional qstr definitions for OpenMV OMV_QSTR_DEFS = $(TOP_DIR)/$(OMV_DIR)/py/qstrdefsomv.h @@ -80,38 +82,51 @@ CFLAGS += -D$(MCU) -D$(CFLAGS_MCU) -D$(ARM_MATH) -DARM_MATH_DSP -DARM_NN_TRUNCAT CFLAGS += -D__FPU_PRESENT=1 -D__VFP_FP__ -DUSE_USB_FS -DUSE_DEVICE_MODE -DUSE_USB_OTG_ID=0 -DHSE_VALUE=12000000\ -D$(TARGET) -DSTM32_HAL_H=$(HAL_INC) -DVECT_TAB_OFFSET=$(VECT_TAB_OFFSET) -DMAIN_APP_ADDR=$(MAIN_APP_ADDR) -CFLAGS += -I. -Iinclude -CFLAGS += -I$(TOP_DIR)/$(BOOT_DIR)/include/ -CFLAGS += -I$(TOP_DIR)/$(CMSIS_DIR)/include/ -CFLAGS += -I$(TOP_DIR)/$(CMSIS_DIR)/include/st -CFLAGS += -I$(TOP_DIR)/$(STHAL_DIR)/include/ -CFLAGS += -I$(TOP_DIR)/$(STHAL_DIR)/include/Legacy/ +ST_CFLAGS += -I. -Iinclude +ST_CFLAGS += -I$(TOP_DIR)/$(CMSIS_DIR)/include/ +ST_CFLAGS += -I$(TOP_DIR)/$(CMSIS_DIR)/include/st +ST_CFLAGS += -I$(TOP_DIR)/$(STHAL_DIR)/include/ +ST_CFLAGS += -I$(TOP_DIR)/$(STHAL_DIR)/include/Legacy/ -CFLAGS += -I$(BUILD)/$(MICROPY_DIR)/ -CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ -CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/py/ -CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/lib/mp-readline -CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/lib/oofatfs -CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/stm32/ -CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/stm32/usbdev/core/inc/ -CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/stm32/usbdev/class/inc/ -CFLAGS += -I$(MP_BOARD_CONFIG_DIR) +MP_CFLAGS += -I$(BUILD)/$(MICROPY_DIR)/ +MP_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ +MP_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/py/ +MP_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/lib/mp-readline +MP_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/lib/oofatfs +MP_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/stm32/ +MP_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/stm32/usbdev/core/inc/ +MP_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/stm32/usbdev/class/inc/ +MP_CFLAGS += -I$(MP_BOARD_CONFIG_DIR) -CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/ -CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/py/ -CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/nn/ -CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/img/ -CFLAGS += -I$(OMV_BOARD_CONFIG_DIR) -CFLAGS += -I$(TOP_DIR)/$(LEPTON_DIR)/include/ -CFLAGS += -I$(TOP_DIR)/$(WINC1500_DIR)/include/ +OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/ +OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/py/ +OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/nn/ +OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/img/ +OMV_CFLAGS += -I$(OMV_BOARD_CONFIG_DIR) +OMV_CFLAGS += -I$(TOP_DIR)/$(LEPTON_DIR)/include/ +OMV_CFLAGS += -I$(TOP_DIR)/$(WINC1500_DIR)/include/ + +WEBCAM_CFLAGS = $(CFLAGS) +WEBCAM_CFLAGS += -I$(OMV_BOARD_CONFIG_DIR) +WEBCAM_CFLAGS += -I$(TOP_DIR)/$(WEBCAM_DIR)/include/ + +BOOTLDR_CFLAGS = $(CFLAGS) +BOOTLDR_CFLAGS += -I$(OMV_BOARD_CONFIG_DIR) +BOOTLDR_CFLAGS += -I$(TOP_DIR)/$(BOOTLDR_DIR)/include/ + +CFLAGS += $(ST_CFLAGS) $(MP_CFLAGS) $(OMV_CFLAGS) # Linker Flags LDFLAGS = -mcpu=$(CPU) -mabi=aapcs-linux -mthumb -mfpu=$(FPU) -mfloat-abi=hard\ -nostdlib -Wl,--gc-sections -Wl,-T$(BUILD)/stm32fxxx.lds # Linker Flags -BOOT_LDFLAGS = -mcpu=$(CPU) -mabi=aapcs-linux -mthumb -mfpu=$(FPU) -mfloat-abi=hard\ - -nostdlib -Wl,--gc-sections -Wl,-T$(BUILD)/$(BOOT_DIR)/stm32fxxx.lds +BOOTLDR_LDFLAGS = -mcpu=$(CPU) -mabi=aapcs-linux -mthumb -mfpu=$(FPU) -mfloat-abi=hard\ + -nostdlib -Wl,--gc-sections -Wl,-T$(BUILD)/$(BOOTLDR_DIR)/stm32fxxx.lds + +# Linker Flags +WEBCAM_LDFLAGS = -mcpu=$(CPU) -mabi=aapcs-linux -mthumb -mfpu=$(FPU) -mfloat-abi=hard\ + -nostdlib -Wl,--gc-sections -Wl,-T$(BUILD)/$(WEBCAM_DIR)/stm32fxxx.lds #------------- Libraries ----------------# FIRM_OBJ += $(wildcard $(BUILD)/$(CMSIS_DIR)/src/dsp/CommonTables/*.o) @@ -389,14 +404,51 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/drivers/,\ ) # Bootloader object files -BOOT_OBJ += $(wildcard $(BUILD)/$(BOOT_DIR)/src/*.o) +BOOT_OBJ += $(wildcard $(BUILD)/$(BOOTLDR_DIR)/src/*.o) BOOT_OBJ += $(wildcard $(BUILD)/$(STHAL_DIR)/src/*.o) - BOOT_OBJ += $(addprefix $(BUILD)/$(CMSIS_DIR)/src/st/,\ $(STARTUP).o \ system_stm32fxxx.o \ ) +# Webcam object files +WEBCAM_OBJ += $(wildcard $(BUILD)/$(WEBCAM_DIR)/src/*.o) +WEBCAM_OBJ += $(wildcard $(BUILD)/$(STHAL_DIR)/src/*.o) +WEBCAM_OBJ += $(addprefix $(BUILD)/$(CMSIS_DIR)/src/st/,\ + $(STARTUP).o \ + system_stm32fxxx.o \ + ) + +WEBCAM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/, \ + fb_alloc.o \ + framebuffer.o \ + array.o \ + cambus.o \ + ov9650.o \ + ov2640.o \ + ov7725.o \ + mt9v034.o \ + lepton.o \ + sensor.o \ + stm32fxxx_hal_msp.o \ + soft_i2c.o \ + mutex.o \ + trace.o \ + ) + +WEBCAM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/img/,\ + lab_tab.o \ + xyz_tab.o \ + yuv_tab.o \ + rainbow_tab.o \ + rgb2rgb_tab.o \ + invariant_tab.o \ + jpeg.o \ + fmath.o \ + imlib.o \ + ) + +WEBCAM_OBJ += $(wildcard $(BUILD)/$(LEPTON_DIR)/src/*.o) ################################################### #Export Variables export Q @@ -422,7 +474,10 @@ $(BUILD): $(MKDIR) -p $@ BOOTLOADER_OBJS: FIRMWARE_OBJS - $(MAKE) -C $(BOOT_DIR) BUILD=$(BUILD)/$(BOOT_DIR) + $(MAKE) -C $(BOOTLDR_DIR) BUILD=$(BUILD)/$(BOOTLDR_DIR) CFLAGS="$(BOOTLDR_CFLAGS) -MMD" + +WEBCAM_OBJS: FIRMWARE_OBJS + $(MAKE) -C $(WEBCAM_DIR) BUILD=$(BUILD)/$(WEBCAM_DIR) CFLAGS="$(WEBCAM_CFLAGS) -MMD" FIRMWARE_OBJS: $(MAKE) -C $(CMSIS_DIR) BUILD=$(BUILD)/$(CMSIS_DIR) CFLAGS="$(CFLAGS) -fno-strict-aliasing -MMD" @@ -443,14 +498,21 @@ $(FIRMWARE): FIRMWARE_OBJS # once without padding, to generate the bootloader.dfu file, and once with padding # up to the main fw image (MAIN_APP_ADDR), to generate a contiguous firmware.bin image. $(BOOTLOADER): FIRMWARE_OBJS BOOTLOADER_OBJS - $(CPP) -P -E -I$(OMV_BOARD_CONFIG_DIR) $(BOOT_DIR)/stm32fxxx.ld.S > $(BUILD)/$(BOOT_DIR)/stm32fxxx.lds - $(CC) $(BOOT_LDFLAGS) $(BOOT_OBJ) -o $(FW_DIR)/$(BOOTLOADER).elf + $(CPP) -P -E -I$(OMV_BOARD_CONFIG_DIR) $(BOOTLDR_DIR)/stm32fxxx.ld.S > $(BUILD)/$(BOOTLDR_DIR)/stm32fxxx.lds + $(CC) $(BOOTLDR_LDFLAGS) $(BOOT_OBJ) -o $(FW_DIR)/$(BOOTLOADER).elf $(OBJCOPY) -Obinary $(FW_DIR)/$(BOOTLOADER).elf $(FW_DIR)/$(BOOTLOADER).bin $(PYTHON) $(MKDFU) -b 0x08000000:$(FW_DIR)/$(BOOTLOADER).bin $(FW_DIR)/$(BOOTLOADER).dfu $(OBJCOPY) -Obinary --pad-to=$(MAIN_APP_ADDR) --gap-fill=0xFF $(FW_DIR)/$(BOOTLOADER).elf $(FW_DIR)/$(BOOTLOADER).bin +# This target generates the webcam firmware. +$(WEBCAM): FIRMWARE_OBJS WEBCAM_OBJS + $(CPP) -P -E -I$(OMV_BOARD_CONFIG_DIR) $(WEBCAM_DIR)/stm32fxxx.ld.S > $(BUILD)/$(WEBCAM_DIR)/stm32fxxx.lds + $(CC) $(WEBCAM_LDFLAGS) $(WEBCAM_OBJ) -o $(FW_DIR)/$(WEBCAM).elf + $(OBJCOPY) -Obinary $(FW_DIR)/$(WEBCAM).elf $(FW_DIR)/$(WEBCAM).bin + $(PYTHON) $(MKDFU) -b $(MAIN_APP_ADDR):$(FW_DIR)/$(WEBCAM).bin $(FW_DIR)/$(WEBCAM).dfu + # This target generates a combined bootloader+main firmware image. -$(OPENMV): $(BOOTLOADER) $(FIRMWARE) | $(BUILD) +$(OPENMV): $(BOOTLOADER) $(WEBCAM) $(FIRMWARE) | $(BUILD) $(CAT) $(FW_DIR)/$(BOOTLOADER).bin $(FW_DIR)/$(FIRMWARE).bin > $(FW_DIR)/$(OPENMV).bin $(PYTHON) $(MKDFU) -b 0x08000000:$(FW_DIR)/$(BOOTLOADER).bin -b $(MAIN_APP_ADDR):$(FW_DIR)/$(FIRMWARE).bin $(FW_DIR)/$(OPENMV).dfu $(SIZE) $(FW_DIR)/$(BOOTLOADER).elf diff --git a/src/omv/fb_alloc.c b/src/omv/fb_alloc.c index 708d3049b..bf8560625 100644 --- a/src/omv/fb_alloc.c +++ b/src/omv/fb_alloc.c @@ -13,7 +13,7 @@ extern char _fballoc; static char *pointer = &_fballoc; -NORETURN void fb_alloc_fail() +__weak NORETURN void fb_alloc_fail() { nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError, "Out of fast Frame Buffer Stack Memory!" diff --git a/src/webcam/Makefile b/src/webcam/Makefile new file mode 100755 index 000000000..7f1e13956 --- /dev/null +++ b/src/webcam/Makefile @@ -0,0 +1,18 @@ +# Sources +SRCS = $(wildcard src/*.c) +OBJS = $(addprefix $(BUILD)/, $(SRCS:.c=.o)) +OBJ_DIRS = $(sort $(dir $(OBJS))) + +all: | $(OBJ_DIRS) $(OBJS) +$(OBJ_DIRS): + $(MKDIR) -p $@ + +$(BUILD)/%.o : %.c + $(ECHO) "CC $<" + $(CC) $(CFLAGS) -c -o $@ $< + +$(BUILD)/%.o : %.s + $(ECHO) "AS $<" + $(AS) $(AFLAGS) $< -o $@ + +-include $(OBJS:%.o=%.d) diff --git a/src/webcam/include/stm32fxxx_it.h b/src/webcam/include/stm32fxxx_it.h new file mode 100644 index 000000000..965542649 --- /dev/null +++ b/src/webcam/include/stm32fxxx_it.h @@ -0,0 +1,74 @@ +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Inc/stm32f4xx_it.h + * @author MCD Application Team + * @version V1.2.2 + * @date 25-May-2015 + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + *

© 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_IT_H +#define __STM32F4xx_IT_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void SVC_Handler(void); +void DebugMon_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); +#ifdef USE_USB_FS +void OTG_FS_IRQHandler(void); +#else +void OTG_HS_IRQHandler(void); +#endif +void USARTx_DMA_TX_IRQHandler(void); +void USARTx_IRQHandler(void); +void TIMx_IRQHandler(void); +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_IT_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/webcam/include/usbd_conf.h b/src/webcam/include/usbd_conf.h new file mode 100644 index 000000000..0b24c7696 --- /dev/null +++ b/src/webcam/include/usbd_conf.h @@ -0,0 +1,81 @@ +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Inc/usbd_conf.h + * @author MCD Application Team + * @version V1.2.2 + * @date 25-May-2015 + * @brief General low level driver configuration + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CONF_H +#define __USBD_CONF_H + +/* Includes ------------------------------------------------------------------*/ +#include STM32_HAL_H +#include +#include +#include + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Common Config */ +#define USBD_MAX_NUM_INTERFACES 1 +#define USBD_MAX_NUM_CONFIGURATION 1 +#define USBD_MAX_STR_DESC_SIZ 512 +#define USBD_SUPPORT_USER_STRING 0 +#define USBD_SELF_POWERED 1 +#define USBD_DEBUG_LEVEL 0 + +/* #define for FS and HS identification */ +#define DEVICE_FS 0 +#define DEVICE_HS 1 + +/* DEBUG macros */ +#if (USBD_DEBUG_LEVEL > 0) +#define USBD_UsrLog(...) printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBD_UsrLog(...) +#endif + +#if (USBD_DEBUG_LEVEL > 1) + +#define USBD_ErrLog(...) printf("ERROR: ") ;\ + printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBD_ErrLog(...) +#endif + +#if (USBD_DEBUG_LEVEL > 2) +#define USBD_DbgLog(...) printf("DEBUG : ") ;\ + printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBD_DbgLog(...) +#endif + +/* Exported functions ------------------------------------------------------- */ + +#endif /* __USBD_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/webcam/include/usbd_core.h b/src/webcam/include/usbd_core.h new file mode 100644 index 000000000..c78c7b363 --- /dev/null +++ b/src/webcam/include/usbd_core.h @@ -0,0 +1,159 @@ +/** + ****************************************************************************** + * @file usbd_core.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief Header file for usbd_core.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CORE_H +#define __USBD_CORE_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_conf.h" +#include "usbd_def.h" +#include "usbd_ioreq.h" +#include "usbd_ctlreq.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_CORE + * @brief This file is the Header file for usbd_core.c file + * @{ + */ + + +/** @defgroup USBD_CORE_Exported_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_CORE_Exported_TypesDefinitions + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup USBD_CORE_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_CORE_Exported_Variables + * @{ + */ +#define USBD_SOF USBD_LL_SOF +/** + * @} + */ + +/** @defgroup USBD_CORE_Exported_FunctionsPrototype + * @{ + */ +USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id); +USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, USBD_ClassTypeDef *pclass); + +USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx); +USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx); + +USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup); +USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata); +USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata); + +USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed); +USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev); + +USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum); +USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum); + +USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev); + +/* USBD Low Level Driver */ +USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_DeInit (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_Stop (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_OpenEP (USBD_HandleTypeDef *pdev, + uint8_t ep_addr, + uint8_t ep_type, + uint16_t ep_mps); + +USBD_StatusTypeDef USBD_LL_CloseEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +USBD_StatusTypeDef USBD_LL_FlushEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +USBD_StatusTypeDef USBD_LL_StallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +USBD_StatusTypeDef USBD_LL_ClearStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +uint8_t USBD_LL_IsStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +USBD_StatusTypeDef USBD_LL_SetUSBAddress (USBD_HandleTypeDef *pdev, uint8_t dev_addr); +USBD_StatusTypeDef USBD_LL_Transmit (USBD_HandleTypeDef *pdev, + uint8_t ep_addr, + uint8_t *pbuf, + uint16_t size); + +USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, + uint8_t ep_addr, + uint8_t *pbuf, + uint16_t size); + +uint32_t USBD_LL_GetRxDataSize (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +void USBD_LL_Delay (uint32_t Delay); + +/** + * @} + */ + +#endif /* __USBD_CORE_H */ + +/** + * @} + */ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + + diff --git a/src/webcam/include/usbd_ctlreq.h b/src/webcam/include/usbd_ctlreq.h new file mode 100644 index 000000000..cd57fa828 --- /dev/null +++ b/src/webcam/include/usbd_ctlreq.h @@ -0,0 +1,106 @@ +/** + ****************************************************************************** + * @file usbd_req.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief header file for the usbd_req.c file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USB_REQUEST_H_ +#define __USB_REQUEST_H_ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" + + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_REQ + * @brief header file for the usbd_ioreq.c file + * @{ + */ + +/** @defgroup USBD_REQ_Exported_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Exported_Types + * @{ + */ +/** + * @} + */ + + + +/** @defgroup USBD_REQ_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBD_REQ_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USBD_REQ_Exported_FunctionsPrototype + * @{ + */ + +USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); +USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); +USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); + + +void USBD_CtlError (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); + +void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata); + +void USBD_GetString (uint8_t *desc, uint8_t *unicode, uint16_t *len); +/** + * @} + */ + +#endif /* __USB_REQUEST_H_ */ + +/** + * @} + */ + +/** +* @} +*/ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/webcam/include/usbd_def.h b/src/webcam/include/usbd_def.h new file mode 100644 index 000000000..e29ad2b26 --- /dev/null +++ b/src/webcam/include/usbd_def.h @@ -0,0 +1,323 @@ +/** + ****************************************************************************** + * @file usbd_def.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief general defines for the usb device library + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USBD_DEF_H +#define __USBD_DEF_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_conf.h" + +/** @addtogroup STM32_USBD_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USB_DEF + * @brief general defines for the usb device library file + * @{ + */ + +/** @defgroup USB_DEF_Exported_Defines + * @{ + */ + +#ifndef NULL +#define NULL ((void *)0) +#endif + + +#define USB_LEN_DEV_QUALIFIER_DESC 0x0A +#define USB_LEN_DEV_DESC 0x12 +#define USB_LEN_CFG_DESC 0x09 +#define USB_LEN_IF_DESC 0x09 +#define USB_LEN_EP_DESC 0x07 +#define USB_LEN_OTG_DESC 0x03 +#define USB_LEN_LANGID_STR_DESC 0x04 +#define USB_LEN_OTHER_SPEED_DESC_SIZ 0x09 + +#define USBD_IDX_LANGID_STR 0x00 +#define USBD_IDX_MFC_STR 0x01 +#define USBD_IDX_PRODUCT_STR 0x02 +#define USBD_IDX_SERIAL_STR 0x03 +#define USBD_IDX_CONFIG_STR 0x04 +#define USBD_IDX_INTERFACE_STR 0x05 + +#define USB_REQ_TYPE_STANDARD 0x00 +#define USB_REQ_TYPE_CLASS 0x20 +#define USB_REQ_TYPE_VENDOR 0x40 +#define USB_REQ_TYPE_MASK 0x60 + +#define USB_REQ_RECIPIENT_DEVICE 0x00 +#define USB_REQ_RECIPIENT_INTERFACE 0x01 +#define USB_REQ_RECIPIENT_ENDPOINT 0x02 +#define USB_REQ_RECIPIENT_MASK 0x03 + +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_DESC_TYPE_DEVICE 1 +#define USB_DESC_TYPE_CONFIGURATION 2 +#define USB_DESC_TYPE_STRING 3 +#define USB_DESC_TYPE_INTERFACE 4 +#define USB_DESC_TYPE_ENDPOINT 5 +#define USB_DESC_TYPE_DEVICE_QUALIFIER 6 +#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7 + + +#define USB_CONFIG_REMOTE_WAKEUP 2 +#define USB_CONFIG_SELF_POWERED 1 + +#define USB_FEATURE_EP_HALT 0 +#define USB_FEATURE_REMOTE_WAKEUP 1 +#define USB_FEATURE_TEST_MODE 2 + + +#define USB_HS_MAX_PACKET_SIZE 512 +#define USB_FS_MAX_PACKET_SIZE 64 +#define USB_MAX_EP0_SIZE 64 + +/* Device Status */ +#define USBD_STATE_DEFAULT 1 +#define USBD_STATE_ADDRESSED 2 +#define USBD_STATE_CONFIGURED 3 +#define USBD_STATE_SUSPENDED 4 + + +/* EP0 State */ +#define USBD_EP0_IDLE 0 +#define USBD_EP0_SETUP 1 +#define USBD_EP0_DATA_IN 2 +#define USBD_EP0_DATA_OUT 3 +#define USBD_EP0_STATUS_IN 4 +#define USBD_EP0_STATUS_OUT 5 +#define USBD_EP0_STALL 6 + +#define USBD_EP_TYPE_CTRL 0 +#define USBD_EP_TYPE_ISOC 1 +#define USBD_EP_TYPE_BULK 2 +#define USBD_EP_TYPE_INTR 3 + + +/** + * @} + */ + + +/** @defgroup USBD_DEF_Exported_TypesDefinitions + * @{ + */ + +typedef struct usb_setup_req +{ + + uint8_t bmRequest; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +}USBD_SetupReqTypedef; + +struct _USBD_HandleTypeDef; + +typedef struct _Device_cb +{ + uint8_t (*Init) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx); + uint8_t (*DeInit) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx); + /* Control Endpoints*/ + uint8_t (*Setup) (struct _USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req); + uint8_t (*EP0_TxSent) (struct _USBD_HandleTypeDef *pdev ); + uint8_t (*EP0_RxReady) (struct _USBD_HandleTypeDef *pdev ); + /* Class Specific Endpoints*/ + uint8_t (*DataIn) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); + uint8_t (*DataOut) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); + uint8_t (*SOF) (struct _USBD_HandleTypeDef *pdev); + uint8_t (*IsoINIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); + uint8_t (*IsoOUTIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); + + uint8_t *(*GetHSConfigDescriptor)(uint16_t *length); + uint8_t *(*GetFSConfigDescriptor)(uint16_t *length); + uint8_t *(*GetOtherSpeedConfigDescriptor)(uint16_t *length); + uint8_t *(*GetDeviceQualifierDescriptor)(uint16_t *length); +#if (USBD_SUPPORT_USER_STRING == 1) + uint8_t *(*GetUsrStrDescriptor)(struct _USBD_HandleTypeDef *pdev ,uint8_t index, uint16_t *length); +#endif + +} USBD_ClassTypeDef; + +/* Following USB Device Speed */ +typedef enum +{ + USBD_SPEED_HIGH = 0, + USBD_SPEED_FULL = 1, + USBD_SPEED_LOW = 2, +}USBD_SpeedTypeDef; + +/* Following USB Device status */ +typedef enum { + USBD_OK = 0, + USBD_BUSY, + USBD_FAIL, +}USBD_StatusTypeDef; + +/* USB Device descriptors structure */ +typedef struct +{ + uint8_t *(*GetDeviceDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length); + uint8_t *(*GetLangIDStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length); + uint8_t *(*GetManufacturerStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length); + uint8_t *(*GetProductStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length); + uint8_t *(*GetSerialStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length); + uint8_t *(*GetConfigurationStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length); + uint8_t *(*GetInterfaceStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length); +} USBD_DescriptorsTypeDef; + +/* USB Device handle structure */ +typedef struct +{ + uint32_t status; + uint32_t total_length; + uint32_t rem_length; + uint32_t maxpacket; +} USBD_EndpointTypeDef; + +/* USB Device handle structure */ +typedef struct _USBD_HandleTypeDef +{ + uint8_t id; + uint32_t dev_config; + uint32_t dev_default_config; + uint32_t dev_config_status; + USBD_SpeedTypeDef dev_speed; + USBD_EndpointTypeDef ep_in[15]; + USBD_EndpointTypeDef ep_out[15]; + uint32_t ep0_state; + uint32_t ep0_data_len; + uint8_t dev_state; + uint8_t dev_old_state; + uint8_t dev_address; + uint8_t dev_connection_status; + uint8_t dev_test_mode; + uint32_t dev_remote_wakeup; + + USBD_SetupReqTypedef request; + USBD_DescriptorsTypeDef *pDesc; + USBD_ClassTypeDef *pClass; + void *pClassData; + void *pUserData; + void *pData; +} USBD_HandleTypeDef; + +/** + * @} + */ + + + +/** @defgroup USBD_DEF_Exported_Macros + * @{ + */ +#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \ + (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8)) + +#define LOBYTE(x) ((uint8_t)(x & 0x00FF)) +#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8)) +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + + +#if defined ( __GNUC__ ) + #ifndef __weak + #define __weak __attribute__((weak)) + #endif /* __weak */ + #ifndef __packed + #define __packed __attribute__((__packed__)) + #endif /* __packed */ +#endif /* __GNUC__ */ + + +/* In HS mode and when the DMA is used, all variables and data structures dealing + with the DMA during the transaction process should be 4-bytes aligned */ + +#if defined (__GNUC__) /* GNU Compiler */ + #define __ALIGN_END __attribute__ ((aligned (4))) + #define __ALIGN_BEGIN +#else + #define __ALIGN_END + #if defined (__CC_ARM) /* ARM Compiler */ + #define __ALIGN_BEGIN __align(4) + #elif defined (__ICCARM__) /* IAR Compiler */ + #define __ALIGN_BEGIN + #elif defined (__TASKING__) /* TASKING Compiler */ + #define __ALIGN_BEGIN __align(4) + #endif /* __CC_ARM */ +#endif /* __GNUC__ */ + + +/** + * @} + */ + +/** @defgroup USBD_DEF_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_DEF_Exported_FunctionsPrototype + * @{ + */ + +/** + * @} + */ + +#endif /* __USBD_DEF_H */ + +/** + * @} + */ + +/** +* @} +*/ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/webcam/include/usbd_desc.h b/src/webcam/include/usbd_desc.h new file mode 100644 index 000000000..32daeaefa --- /dev/null +++ b/src/webcam/include/usbd_desc.h @@ -0,0 +1,34 @@ +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Inc/usbd_desc.h + * @author MCD Application Team + * @version V1.2.2 + * @date 25-May-2015 + * @brief Header for usbd_desc.c module + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ +#ifndef __USBD_DESC_H +#define __USBD_DESC_H + +#include "usbd_def.h" + +extern USBD_DescriptorsTypeDef FS_Desc; + +#endif /* __USBD_DESC_H */ diff --git a/src/webcam/include/usbd_ioreq.h b/src/webcam/include/usbd_ioreq.h new file mode 100644 index 000000000..ab83bc086 --- /dev/null +++ b/src/webcam/include/usbd_ioreq.h @@ -0,0 +1,121 @@ +/** + ****************************************************************************** + * @file usbd_ioreq.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief header file for the usbd_ioreq.c file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USBD_IOREQ_H_ +#define __USBD_IOREQ_H_ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" +#include "usbd_core.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_IOREQ + * @brief header file for the usbd_ioreq.c file + * @{ + */ + +/** @defgroup USBD_IOREQ_Exported_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Exported_Types + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup USBD_IOREQ_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_IOREQ_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_IOREQ_Exported_FunctionsPrototype + * @{ + */ + +USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev, + uint8_t *buf, + uint16_t len); + +USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len); + +USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len); + +USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len); + +USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev); + +USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev); + +uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , + uint8_t epnum); + +/** + * @} + */ + +#endif /* __USBD_IOREQ_H_ */ + +/** + * @} + */ + +/** +* @} +*/ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/webcam/include/usbd_types.h b/src/webcam/include/usbd_types.h new file mode 100644 index 000000000..5ee57d741 --- /dev/null +++ b/src/webcam/include/usbd_types.h @@ -0,0 +1,65 @@ +#ifndef __USBD_TYPES_H +#define __USBD_TYPES_H + +#define USB_REQ_READ_MASK 0x80 + +/* USB_DT_CONFIG: Configuration descriptor information. */ +struct usb_config_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +} __attribute__ ((packed)); + +#define USB_DT_CONFIG_SIZE 9 + +/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */ +struct usb_interface_assoc_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + + uint8_t bFirstInterface; + uint8_t bInterfaceCount; + uint8_t bFunctionClass; + uint8_t bFunctionSubClass; + uint8_t bFunctionProtocol; + uint8_t iFunction; +} __attribute__ ((packed)); + +#define USB_DT_INTERFACE_ASSOC_SIZE 8 + +/* USB_DT_INTERFACE: Interface descriptor */ +struct usb_interface_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} __attribute__ ((packed)); + +#define USB_DT_INTERFACE_SIZE 9 + +/* USB_DT_ENDPOINT: Endpoint descriptor */ +struct usb_endpoint_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} __attribute__ ((packed)); + +#define USB_DT_ENDPOINT_SIZE 7 + +#endif \ No newline at end of file diff --git a/src/webcam/include/usbd_uvc.h b/src/webcam/include/usbd_uvc.h new file mode 100644 index 000000000..19931300f --- /dev/null +++ b/src/webcam/include/usbd_uvc.h @@ -0,0 +1,372 @@ +/** + ****************************************************************************** + * @file usbd_cdc.h + * @author MCD Application Team + * @version V2.4.1 + * @date 19-June-2015 + * @brief header file for the usbd_cdc.c file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_UVC_H +#define __USB_UVC_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_ioreq.h" +#include "uvc.h" + +/** @addtogroup STM32_USB_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup usbd_cdc + * @brief This file is the Header file for usbd_cdc.c + * @{ + */ + + +/** @defgroup usbd_cdc_Exported_Defines + * @{ + */ + +// USB Video device class specification version 1.10 +#ifdef UVC_1_1 +#define UVC_VERSION 0x0110 // UVC 1.1 +#else +#define UVC_VERSION 0x0100 // UVC 1.0 +#endif + +#define UVC_IN_EP 0x81 /* EP1 for data IN */ +#define UVC_CMD_EP 0x82 /* EP2 for UVC commands */ +#define VIDEO_PACKET_SIZE ((unsigned int)(960 + 2)) +#define VIDEO_MAX_SETUP_PACKET_SIZE ((unsigned int)(1024)) +#define CMD_PACKET_SIZE ((unsigned int)(8)) + +#define CAM_FPS 120 + +enum CUST_COMTROL_IDS { + CUST_CONTROL_COMMAND=0, + CUST_CONTROL_GET, + CUST_CONTROL_SET, + CUST_CONTROL_RUN, + CUST_CONTROL_DIRECT_WRITE, + CUST_CONTROL_DIRECT_READ, + CUST_CONTROL_END +}; + +enum _vs_fmt_indexes { + VS_FMT_INDEX_YUYV = 1, + VS_FMT_INDEX_GREY, + VS_FMT_INDEX_RGB565, +}; + +#define VS_NUM_FORMATS 3 + +enum _vs_fmt_size { + VS_FMT_SIZE_YUYV = 16, + VS_FMT_SIZE_GREY = 8, + VS_FMT_SIZE_RGB565 = 16, +}; + +#define VS_FMT_GUID_NONE \ + '0', '0', '0', '0', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define VS_FMT_GUID_GREY \ + 'Y', '8', ' ', ' ', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 + +#define VS_FMT_GUID_Y16 \ + 'Y', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 + +#define VS_FMT_GUID_YUYV \ + 'U', 'Y', 'V', 'Y', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 + +#define VS_FMT_GUID_NV12 \ + 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 + +#define VS_FMT_GUID_YU12 \ + 'I', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 + +#define VS_FMT_GUID_BGR3 \ + 0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 + +#define VS_FMT_GUID_RGB565 \ + 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 + +#define VS_FMT_INDEX(NAME) VS_FMT_INDEX_ ## NAME +#define VS_FMT_GUID(NAME) { VS_FMT_GUID_ ## NAME } +#define VS_FMT_SIZE(NAME) VS_FMT_SIZE_ ## NAME + +enum _vs_frame_indexes { + VS_FRAME_INDEX_1 = 1, + VS_FRAME_INDEX_2 = 2, + VS_FRAME_INDEX_3 = 3, + VS_FRAME_INDEX_4 = 4, +}; + +#define VS_FRAME_INDEX(NAME) VS_FRAME_INDEX_ ## NAME + +#define USB_UVC_VCIF_NUM 0 +#define USB_UVC_VSIF_NUM (char)1 + +#define VIDEO_TOTAL_IF_NUM 2 +#define WINDOWS_MAX_CONTROLS 31 + +typedef enum _vs_terminal_id { + VC_INPUT_TERMINAL_ID = 1, + VC_CONTROL_PU_ID, + VC_CONTROL_XU_LEP_AGC_ID, + VC_CONTROL_XU_LEP_OEM_ID, + VC_CONTROL_XU_LEP_RAD_ID, + VC_CONTROL_XU_LEP_SYS_ID, + VC_CONTROL_XU_LEP_VID_ID, + VC_CONTROL_XU_LEP_AGC_2_ID = VC_CONTROL_XU_LEP_AGC_ID + 0x10, + VC_CONTROL_XU_LEP_OEM_2_ID, + VC_CONTROL_XU_LEP_RAD_2_ID, + VC_CONTROL_XU_LEP_SYS_2_ID, + VC_CONTROL_XU_LEP_VID_2_ID, + VC_CONTROL_XU_LEP_CUST_ID = 0xfe, + VC_OUTPUT_TERMINAL_ID = 0xff +} VC_TERMINAL_ID; + +/** + * @} + */ + + +/** @defgroup USBD_CORE_Exported_TypesDefinitions + * @{ + */ + + +typedef struct _USBD_UVC_Itf +{ + int8_t (* Init) (void); + int8_t (* DeInit) (void); + int8_t (* Control) (uint8_t, uint8_t * , uint16_t, uint16_t, uint16_t); + int8_t (* VS_CtrlGet) (uint8_t, uint8_t * , uint16_t, uint16_t, uint16_t); + int8_t (* VS_CtrlSet) (uint8_t, uint8_t * , uint16_t, uint16_t, uint16_t); + int8_t (* ControlGet) (VC_TERMINAL_ID, uint8_t, uint8_t * , uint16_t, uint16_t, uint16_t); + int8_t (* ControlSet) (VC_TERMINAL_ID, uint8_t, uint8_t * , uint16_t, uint16_t, uint16_t); + int8_t (* Receive) (uint8_t *, uint32_t *); + +}USBD_UVC_ItfTypeDef; + + +typedef struct +{ + uint32_t data[VIDEO_MAX_SETUP_PACKET_SIZE/4]; /* Force 32bits alignment */ + uint8_t CmdOpCode; + uint16_t CmdLength; + uint16_t CmdIndex; + uint16_t CmdValue; + uint8_t *RxBuffer; + uint8_t *TxBuffer; + uint32_t RxLength; + uint32_t TxLength; + + __IO uint32_t TxState; + __IO uint32_t RxState; +} +USBD_UVC_HandleTypeDef; + +#if 0 +struct uvc_input_terminal_desc { + uint8_t bLength; + uint8_t bDescriptorType; /* : CS_INTERFACE */ + uint8_t bDescriptorSubtype; /* VC_INPUT_TERMINAL descriptor subtype */ + uint8_t bTerminalID; /* Constant uniquely identifying the Terminal within the video function. + This value is used in all requests to address this Terminal. */ + uint8_t[2] wTerminalType; /* ITT_MEDIA_TRANSPORT_INPUT */ + uint8_t bAssocTerminal; /* ID of the Output Terminal to which this Input Terminal is associated. */ + uint8_t iTerminal; /* */ + uint8_t bControlSize; /* Size of the bmControls field, in bytes: n=1 */ + uint8_t[1] bmControls; /* + A bit set to 1 indicates that the mentioned Control is supported for the video stream. + D0: Transport Control + D1: Absolute Track Number Control + D2: Media Information + D3: Time Code Information D4...(n*8-1): Reserved + */ + uint8_t bTransportModeSize; /* Size of the bmTransportModes field, in bytes: m=4 */ + uint8_t[4] bmTransportModes; /* + A bit set to 1 indicates that the mentioned Transport mode is supported. + D0: Play Forward + D1: Pause + D2: Rewind + D3: Fast Forward + D4: High Speed Rewind + D5: Stop + D6: Eject + D7: Play Next Frame + D8: Play Slowest Forward + D9: Play Slow Forward 4 + D10: Play Slow Forward 3 + D11: Play Slow Forward 2 + D12: Play Slow Forward 1 + D13: Play X1 + D14: Play Fast Forward 1 + D15: Play Fast Forward 2 + D16: Play Fast Forward 3 + D17: Play Fast Forward 4 + D18: Play Fastest Forward + D19: Play Previous Frame + D20: Play Slowest Reverse + D21: Play Slow Reverse 4 + D22: Play Slow Reverse 3 + D23: Play Slow Reverse 2 + D24: Play Slow Reverse 1 + D25: Play X1 Reverse + D26: Play Fast Reverse 1 + D27: Play Fast Reverse 2 + D28: Play Fast Reverse 3 + D29: Play Fast Reverse 4 + D30: Play Fastest Reverse + D31: Record StateStart + */ +}; +#endif + +/** + * @} + */ + +/** @defgroup USBD_CORE_Exported_Macros + * @{ + */ + +#define SIZEOF_M(type, member) sizeof(((type *)0)->member) + +#define UVC_DATA_HS_IN_PACKET_SIZE VIDEO_PACKET_SIZE +#define UVC_DATA_HS_OUT_PACKET_SIZE VIDEO_PACKET_SIZE + +#define UVC_DATA_FS_IN_PACKET_SIZE VIDEO_PACKET_SIZE +#define UVC_DATA_FS_OUT_PACKET_SIZE VIDEO_PACKET_SIZE + +#define UVC_LEN_IF_ASSOCIATION_DESC (char)8 + +#define UVC_VS_INTERFACE_INPUT_HEADER_DESC_SIZE(a,b) (char) (13+a*b) + +#define USB_INTERFACE_POWER_DESCRIPTOR_TYPE 8 +#define USB_OTG_DESCRIPTOR_TYPE 9 +#define USB_DEBUG_DESCRIPTOR_TYPE 10 +#define USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE 11 + +/* bmAttributes in Configuration Descriptor */ +#define USB_CONFIG_POWERED_MASK 0xC0 +#define USB_CONFIG_BUS_POWERED 0x80 + +/* bMaxPower in Configuration Descriptor */ +#define USB_CONFIG_POWER_MA(mA) ((mA)/2) +#define MAX_FRAME_SIZE(width, height, bits_per_pixel) ((unsigned long)((width*height*bits_per_pixel)>>3)) +#define MIN_BIT_RATE(width, height, bits_per_pixel) ((unsigned long)(width*height*bits_per_pixel*CAM_FPS)) +#define MAX_BIT_RATE(width, height, bits_per_pixel) ((unsigned long)(width*height*bits_per_pixel*CAM_FPS)) +#define INTERVAL ((unsigned long)(10000000/CAM_FPS)) + +/* bEndpointAddress in Endpoint Descriptor */ +#define USB_ENDPOINT_DIRECTION_MASK 0x80 +#define USB_ENDPOINT_OUT(addr) ((addr) | 0x00) +#define USB_ENDPOINT_IN(addr) ((addr) | 0x80) + +#define UVC_FORMAT_UNCOMPRESSED_DESCRIPTOR(FMT_NAME, NUM_FRAME_DESCS) { \ + .bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE, \ + .bDescriptorType = UVC_CS_INTERFACE, /* CS_INTERFACE */ \ + .bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED, /* VS_FORMAT_UNCOMPRESSED subtype */ \ + .bFormatIndex = VS_FMT_INDEX(FMT_NAME), /* First format descriptor */ \ + .bNumFrameDescriptors = NUM_FRAME_DESCS, /* One frame descriptor for this format follows. */ \ + .guidFormat = VS_FMT_GUID(FMT_NAME), /* */ \ + .bBitsPerPixel = VS_FMT_SIZE(FMT_NAME), /* Number of bits per pixel used to specify color in the decoded video frame - 16 for yuy2, 12 for nv12... */ \ + .bDefaultFrameIndex = 0x01, /* Default frame index is 1. */ \ + .bAspectRatioX = 0x00, /* Non-interlaced stream not required. */ \ + .bAspectRatioY = 0x00, /* Non-interlaced stream not required. */ \ + .bmInterlaceFlags = 0x00, /* Non-interlaced stream */ \ + .bCopyProtect = 0x00, /* No restrictions imposed on the duplication of this video stream. */ \ +} + +#define UVC_FRAME_FORMAT(FRAME_INDEX, FMT_NAME, WIDTH, HEIGHT) { \ + .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1), \ + .bDescriptorType = UVC_CS_INTERFACE, /* CS_INTERFACE */ \ + .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED, /* VS_FRAME_UNCOMPRESSED */ \ + .bFrameIndex = FRAME_INDEX, /* First (and only) frame descriptor */ \ + .bmCapabilities = 0x02, /* Still images using capture method 0 are supported at this frame setting.D1: Fixed frame-rate. */ \ + .wWidth = WIDTH, /* Width of frame is 128 pixels. */ \ + .wHeight = HEIGHT, /* Height of frame is 64 pixels. */ \ + .dwMinBitRate = MIN_BIT_RATE(WIDTH,HEIGHT,VS_FMT_SIZE(FMT_NAME)), /* Min bit rate in bits/s */ \ + .dwMaxBitRate = MAX_BIT_RATE(WIDTH,HEIGHT,VS_FMT_SIZE(FMT_NAME)), /* Max bit rate in bits/s */ \ + .dwMaxVideoFrameBufferSize = MAX_FRAME_SIZE(WIDTH,HEIGHT,VS_FMT_SIZE(FMT_NAME)), /* Maximum video or still frame size, in bytes. */ \ + .dwDefaultFrameInterval = INTERVAL, /* */ \ + .bFrameIntervalType = 0x01, /* Continuous frame interval */ \ + .dwFrameInterval = { INTERVAL }, /* 1,000,000 ns *100ns -> 10 FPS */ \ +} + +#define UVC_COLOR_MATCHING_DESCRIPTOR() { \ + .bLength = UVC_DT_COLOR_MATCHING_SIZE, \ + .bDescriptorType = UVC_CS_INTERFACE, /* CS_INTERFACE */ \ + .bDescriptorSubType = UVC_VS_COLORFORMAT, /* VS_COLORFORMAT */ \ + .bColorPrimaries = 0x01, /* 1: BT.709, sRGB (default) */ \ + .bTransferCharacteristics = 0x01, /* 1: BT.709 (default) */ \ + .bMatrixCoefficients = 0x04, /* 1: SMPTE 170M (BT.601) */ \ +} + +/** + * @} + */ + +/** @defgroup USBD_CORE_Exported_Variables + * @{ + */ + +extern USBD_ClassTypeDef USBD_UVC; +#define USBD_UVC_CLASS &USBD_UVC +/** + * @} + */ + +/** @defgroup USB_CORE_Exported_Functions + * @{ + */ +uint8_t USBD_UVC_RegisterInterface (USBD_HandleTypeDef *pdev, + USBD_UVC_ItfTypeDef *fops); + +uint8_t USBD_UVC_SetTxBuffer (USBD_HandleTypeDef *pdev, + uint8_t *pbuff, + uint16_t length); + +uint8_t USBD_UVC_SetRxBuffer (USBD_HandleTypeDef *pdev, + uint8_t *pbuff); + +uint8_t USBD_UVC_ReceivePacket (USBD_HandleTypeDef *pdev); + +uint8_t USBD_UVC_TransmitPacket (USBD_HandleTypeDef *pdev); +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USB_UVC_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/webcam/include/usbd_uvc_if.h b/src/webcam/include/usbd_uvc_if.h new file mode 100644 index 000000000..be61cf04f --- /dev/null +++ b/src/webcam/include/usbd_uvc_if.h @@ -0,0 +1,65 @@ +/** + ****************************************************************************** + * @file : usbd_cdc_if.h + * @brief : Header for usbd_cdc_if file. + ****************************************************************************** + * 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. + * + ****************************************************************************** +*/ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_UVC_IF_H +#define __USBD_UVC_IF_H + +#ifdef __cplusplus + extern "C" { +#endif +/* Includes ------------------------------------------------------------------*/ +#include "usbd_uvc.h" + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported cariables --------------------------------------------------------*/ +extern USBD_UVC_ItfTypeDef USBD_Interface_fops_FS; + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +/** @defgroup USBD_UVC_IF_Exported_FunctionsPrototype + * @{ + */ +uint8_t UVC_Transmit_FS(uint8_t* Buf, uint16_t Len); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USBD_UVC_IF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/webcam/include/uvc.h b/src/webcam/include/uvc.h new file mode 100644 index 000000000..54be1ce8c --- /dev/null +++ b/src/webcam/include/uvc.h @@ -0,0 +1,522 @@ +#ifndef __UVC_H +#define __UVC_H + +/*---------------------------------------------------------------------------- + * Definitions based on USB_Video_Class_1.1.pdf (www.usb.org) + *---------------------------------------------------------------------------*/ + +/* -------------------------------------------------------------------------- + * UVC constants + */ + +/* A.1 Video Interface Class Code */ +#define UVC_CC_VIDEO 0x0E + +/* A.2. Video Interface Subclass Codes */ +#define UVC_SC_UNDEFINED 0x00 +#define UVC_SC_VIDEOCONTROL 0x01 +#define UVC_SC_VIDEOSTREAMING 0x02 +#define UVC_SC_VIDEO_INTERFACE_COLLECTION 0x03 + +/* A.3. Video Interface Protocol Codes */ +#define UVC_PC_PROTOCOL_UNDEFINED 0x00 + +/* A.4 Video Class-Specific Descriptor Types */ +#define UVC_CS_UNDEFINED 0x20 +#define UVC_CS_DEVICE 0x21 +#define UVC_CS_CONFIGURATION 0x22 +#define UVC_CS_STRING 0x23 +#define UVC_CS_INTERFACE 0x24 +#define UVC_CS_ENDPOINT 0x25 + +/* A.5. Video Class-Specific VC Interface Descriptor Subtypes */ +#define UVC_VC_DESCRIPTOR_UNDEFINED 0x00 +#define UVC_VC_HEADER 0x01 +#define UVC_VC_INPUT_TERMINAL 0x02 +#define UVC_VC_OUTPUT_TERMINAL 0x03 +#define UVC_VC_SELECTOR_UNIT 0x04 +#define UVC_VC_PROCESSING_UNIT 0x05 +#define UVC_VC_EXTENSION_UNIT 0x06 + +/* A.6. Video Class-Specific VS Interface Descriptor Subtypes */ +#define UVC_VS_UNDEFINED 0x00 +#define UVC_VS_INPUT_HEADER 0x01 +#define UVC_VS_OUTPUT_HEADER 0x02 +#define UVC_VS_STILL_IMAGE_FRAME 0x03 +#define UVC_VS_FORMAT_UNCOMPRESSED 0x04 +#define UVC_VS_FRAME_UNCOMPRESSED 0x05 +#define UVC_VS_FORMAT_MJPEG 0x06 +#define UVC_VS_FRAME_MJPEG 0x07 +#define UVC_VS_FORMAT_MPEG2TS 0x0a +#define UVC_VS_FORMAT_DV 0x0c +#define UVC_VS_COLORFORMAT 0x0d +#define UVC_VS_FORMAT_FRAME_BASED 0x10 +#define UVC_VS_FRAME_FRAME_BASED 0x11 +#define UVC_VS_FORMAT_STREAM_BASED 0x12 + +/* A.7. Video Class-Specific Endpoint Descriptor Subtypes */ +#define UVC_EP_UNDEFINED 0x00 +#define UVC_EP_GENERAL 0x01 +#define UVC_EP_ENDPOINT 0x02 +#define UVC_EP_INTERRUPT 0x03 + +/* A.8. Video Class-Specific Request Codes */ +#define UVC_RC_UNDEFINED 0x00 +#define UVC_SET_CUR 0x01 +#define UVC_GET_CUR 0x81 +#define UVC_GET_MIN 0x82 +#define UVC_GET_MAX 0x83 +#define UVC_GET_RES 0x84 +#define UVC_GET_LEN 0x85 +#define UVC_GET_INFO 0x86 +#define UVC_GET_DEF 0x87 + +/* A.9.1. VideoControl Interface Control Selectors */ +#define UVC_VC_CONTROL_UNDEFINED 0x00 +#define UVC_VC_VIDEO_POWER_MODE_CONTROL 0x01 +#define UVC_VC_REQUEST_ERROR_CODE_CONTROL 0x02 + +/* A.9.2. Terminal Control Selectors */ +#define UVC_TE_CONTROL_UNDEFINED 0x00 + +/* A.9.3. Selector Unit Control Selectors */ +#define UVC_SU_CONTROL_UNDEFINED 0x00 +#define UVC_SU_INPUT_SELECT_CONTROL 0x01 + +/* A.9.4. Camera Terminal Control Selectors */ +#define UVC_CT_CONTROL_UNDEFINED 0x00 +#define UVC_CT_SCANNING_MODE_CONTROL 0x01 +#define UVC_CT_AE_MODE_CONTROL 0x02 +#define UVC_CT_AE_PRIORITY_CONTROL 0x03 +#define UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04 +#define UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05 +#define UVC_CT_FOCUS_ABSOLUTE_CONTROL 0x06 +#define UVC_CT_FOCUS_RELATIVE_CONTROL 0x07 +#define UVC_CT_FOCUS_AUTO_CONTROL 0x08 +#define UVC_CT_IRIS_ABSOLUTE_CONTROL 0x09 +#define UVC_CT_IRIS_RELATIVE_CONTROL 0x0a +#define UVC_CT_ZOOM_ABSOLUTE_CONTROL 0x0b +#define UVC_CT_ZOOM_RELATIVE_CONTROL 0x0c +#define UVC_CT_PANTILT_ABSOLUTE_CONTROL 0x0d +#define UVC_CT_PANTILT_RELATIVE_CONTROL 0x0e +#define UVC_CT_ROLL_ABSOLUTE_CONTROL 0x0f +#define UVC_CT_ROLL_RELATIVE_CONTROL 0x10 +#define UVC_CT_PRIVACY_CONTROL 0x11 + +/* A.9.5. Processing Unit Control Selectors */ +#define UVC_PU_CONTROL_UNDEFINED 0x00 +#define UVC_PU_BACKLIGHT_COMPENSATION_CONTROL 0x01 +#define UVC_PU_BRIGHTNESS_CONTROL 0x02 +#define UVC_PU_CONTRAST_CONTROL 0x03 +#define UVC_PU_GAIN_CONTROL 0x04 +#define UVC_PU_POWER_LINE_FREQUENCY_CONTROL 0x05 +#define UVC_PU_HUE_CONTROL 0x06 +#define UVC_PU_SATURATION_CONTROL 0x07 +#define UVC_PU_SHARPNESS_CONTROL 0x08 +#define UVC_PU_GAMMA_CONTROL 0x09 +#define UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a +#define UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b +#define UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c +#define UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d +#define UVC_PU_DIGITAL_MULTIPLIER_CONTROL 0x0e +#define UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f +#define UVC_PU_HUE_AUTO_CONTROL 0x10 +#define UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11 +#define UVC_PU_ANALOG_LOCK_STATUS_CONTROL 0x12 + +/* A.9.7. VideoStreaming Interface Control Selectors */ +#define UVC_VS_CONTROL_UNDEFINED 0x00 +#define UVC_VS_PROBE_CONTROL 0x01 +#define UVC_VS_COMMIT_CONTROL 0x02 +#define UVC_VS_STILL_PROBE_CONTROL 0x03 +#define UVC_VS_STILL_COMMIT_CONTROL 0x04 +#define UVC_VS_STILL_IMAGE_TRIGGER_CONTROL 0x05 +#define UVC_VS_STREAM_ERROR_CODE_CONTROL 0x06 +#define UVC_VS_GENERATE_KEY_FRAME_CONTROL 0x07 +#define UVC_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08 +#define UVC_VS_SYNC_DELAY_CONTROL 0x09 + +/* B.1. USB Terminal Types */ +#define UVC_TT_VENDOR_SPECIFIC 0x0100 +#define UVC_TT_STREAMING 0x0101 + +/* B.2. Input Terminal Types */ +#define UVC_ITT_VENDOR_SPECIFIC 0x0200 +#define UVC_ITT_CAMERA 0x0201 +#define UVC_ITT_MEDIA_TRANSPORT_INPUT 0x0202 + +/* B.3. Output Terminal Types */ +#define UVC_OTT_VENDOR_SPECIFIC 0x0300 +#define UVC_OTT_DISPLAY 0x0301 +#define UVC_OTT_MEDIA_TRANSPORT_OUTPUT 0x0302 + +/* B.4. External Terminal Types */ +#define UVC_EXTERNAL_VENDOR_SPECIFIC 0x0400 +#define UVC_COMPOSITE_CONNECTOR 0x0401 +#define UVC_SVIDEO_CONNECTOR 0x0402 +#define UVC_COMPONENT_CONNECTOR 0x0403 + +/* 2.4.2.2. Status Packet Type */ +#define UVC_STATUS_TYPE_CONTROL 1 +#define UVC_STATUS_TYPE_STREAMING 2 + +/* 2.4.3.3. Payload Header Information */ +#define UVC_STREAM_EOH (1 << 7) +#define UVC_STREAM_ERR (1 << 6) +#define UVC_STREAM_STI (1 << 5) +#define UVC_STREAM_RES (1 << 4) +#define UVC_STREAM_SCR (1 << 3) +#define UVC_STREAM_PTS (1 << 2) +#define UVC_STREAM_EOF (1 << 1) +#define UVC_STREAM_FID (1 << 0) + +/* 4.1.2. Control Capabilities */ +#define UVC_CONTROL_CAP_GET (1 << 0) +#define UVC_CONTROL_CAP_SET (1 << 1) +#define UVC_CONTROL_CAP_DISABLED (1 << 2) +#define UVC_CONTROL_CAP_AUTOUPDATE (1 << 3) +#define UVC_CONTROL_CAP_ASYNCHRONOUS (1 << 4) + +/* ------------------------------------------------------------------------ + * UVC structures + */ + +/* All UVC descriptors have these 3 fields at the beginning */ +struct uvc_descriptor_header { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; +} __attribute__((packed)); + +/* 3.7.2. Video Control Interface Header Descriptor */ +struct uvc_header_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint16_t bcdUVC; + uint16_t wTotalLength; + uint32_t dwClockFrequency; + uint8_t bInCollection; + uint8_t baInterfaceNr[]; +} __attribute__((__packed__)); + +#define UVC_DT_HEADER_SIZE(n) (12+(n)) + +#define UVC_HEADER_DESCRIPTOR(n) \ + uvc_header_descriptor_##n + +#define DECLARE_UVC_HEADER_DESCRIPTOR(n) \ +struct UVC_HEADER_DESCRIPTOR(n) { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint16_t bcdUVC; \ + uint16_t wTotalLength; \ + uint32_t dwClockFrequency; \ + uint8_t bInCollection; \ + uint8_t baInterfaceNr[n]; \ +} __attribute__ ((packed)) + +/* 3.7.2.1. Input Terminal Descriptor */ +struct uvc_input_terminal_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bTerminalID; + uint16_t wTerminalType; + uint8_t bAssocTerminal; + uint8_t iTerminal; +} __attribute__((__packed__)); + +#define UVC_DT_INPUT_TERMINAL_SIZE 8 + +/* 3.7.2.2. Output Terminal Descriptor */ +struct uvc_output_terminal_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bTerminalID; + uint16_t wTerminalType; + uint8_t bAssocTerminal; + uint8_t bSourceID; + uint8_t iTerminal; +} __attribute__((__packed__)); + +#define UVC_DT_OUTPUT_TERMINAL_SIZE 9 + +/* 3.7.2.3. Camera Terminal Descriptor */ +struct uvc_camera_terminal_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bTerminalID; + uint16_t wTerminalType; + uint8_t bAssocTerminal; + uint8_t iTerminal; + uint16_t wObjectiveFocalLengthMin; + uint16_t wObjectiveFocalLengthMax; + uint16_t wOcularFocalLength; + uint8_t bControlSize; + uint8_t bmControls[3]; +} __attribute__((__packed__)); + +#define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n)) + +/* 3.7.2.4. Selector Unit Descriptor */ +struct uvc_selector_unit_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bUnitID; + uint8_t bNrInPins; + uint8_t baSourceID[0]; + uint8_t iSelector; +} __attribute__((__packed__)); + +#define UVC_DT_SELECTOR_UNIT_SIZE(n) (6+(n)) + +#define UVC_SELECTOR_UNIT_DESCRIPTOR(n) \ + uvc_selector_unit_descriptor_##n + +#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n) \ +struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bUnitID; \ + uint8_t bNrInPins; \ + uint8_t baSourceID[n]; \ + uint8_t iSelector; \ +} __attribute__ ((packed)) + +/* 3.7.2.5. Processing Unit Descriptor */ +struct uvc_processing_unit_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bUnitID; + uint8_t bSourceID; + uint16_t wMaxMultiplier; + uint8_t bControlSize; + uint8_t bmControls[3]; + uint8_t iProcessing; +} __attribute__((__packed__)); + +#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n)) + +/* 3.7.2.6. Extension Unit Descriptor */ +struct uvc_extension_unit_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bUnitID; + uint8_t guidExtensionCode[16]; + uint8_t bNumControls; + uint8_t bNrInPins; + uint8_t baSourceID[0]; + uint8_t bControlSize; + uint8_t bmControls[0]; + uint8_t iExtension; +} __attribute__((__packed__)); + +#define UVC_DT_EXTENSION_UNIT_SIZE(p, n) (24+(p)+(n)) + +#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \ + uvc_extension_unit_descriptor_##p_##n + +#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \ +struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bUnitID; \ + uint8_t guidExtensionCode[16]; \ + uint8_t bNumControls; \ + uint8_t bNrInPins; \ + uint8_t baSourceID[p]; \ + uint8_t bControlSize; \ + uint8_t bmControls[n]; \ + uint8_t iExtension; \ +} __attribute__ ((packed)) + +/* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */ +struct uvc_control_endpoint_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint16_t wMaxTransferSize; +} __attribute__((__packed__)); + +#define UVC_DT_CONTROL_ENDPOINT_SIZE 5 + +/* 3.9.2.1. Input Header Descriptor */ +struct uvc_input_header_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bNumFormats; + uint16_t wTotalLength; + uint8_t bEndpointAddress; + uint8_t bmInfo; + uint8_t bTerminalLink; + uint8_t bStillCaptureMethod; + uint8_t bTriggerSupport; + uint8_t bTriggerUsage; + uint8_t bControlSize; + uint8_t bmaControls[]; +} __attribute__((__packed__)); + +#define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p)) + +#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \ + uvc_input_header_descriptor_##n_##p + +#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \ +struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bNumFormats; \ + uint16_t wTotalLength; \ + uint8_t bEndpointAddress; \ + uint8_t bmInfo; \ + uint8_t bTerminalLink; \ + uint8_t bStillCaptureMethod; \ + uint8_t bTriggerSupport; \ + uint8_t bTriggerUsage; \ + uint8_t bControlSize; \ + uint8_t bmaControls[p][n]; \ +} __attribute__ ((packed)) + +/* 3.9.2.2. Output Header Descriptor */ +struct uvc_output_header_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bNumFormats; + uint16_t wTotalLength; + uint8_t bEndpointAddress; + uint8_t bTerminalLink; + uint8_t bControlSize; + uint8_t bmaControls[]; +} __attribute__((__packed__)); + +#define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p)) + +#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \ + uvc_output_header_descriptor_##n_##p + +#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \ +struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bNumFormats; \ + uint16_t wTotalLength; \ + uint8_t bEndpointAddress; \ + uint8_t bTerminalLink; \ + uint8_t bControlSize; \ + uint8_t bmaControls[p][n]; \ +} __attribute__ ((packed)) + +/* 3.9.2.6. Color matching descriptor */ +struct uvc_color_matching_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bColorPrimaries; + uint8_t bTransferCharacteristics; + uint8_t bMatrixCoefficients; +} __attribute__((__packed__)); + +#define UVC_DT_COLOR_MATCHING_SIZE 6 + +/* 4.3.1.1. Video Probe and Commit Controls */ +struct uvc_streaming_control { + uint16_t bmHint; + uint8_t bFormatIndex; + uint8_t bFrameIndex; + uint32_t dwFrameInterval; + uint16_t wKeyFrameRate; + uint16_t wPFrameRate; + uint16_t wCompQuality; + uint16_t wCompWindowSize; + uint16_t wDelay; + uint32_t dwMaxVideoFrameSize; + uint32_t dwMaxPayloadTransferSize; + uint32_t dwClockFrequency; + uint8_t bmFramingInfo; + uint8_t bPreferedVersion; + uint8_t bMinVersion; + uint8_t bMaxVersion; +} __attribute__((__packed__)); + +/* Uncompressed Payload - 3.1.1. Uncompressed Video Format Descriptor */ +struct uvc_format_uncompressed { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFormatIndex; + uint8_t bNumFrameDescriptors; + uint8_t guidFormat[16]; + uint8_t bBitsPerPixel; + uint8_t bDefaultFrameIndex; + uint8_t bAspectRatioX; + uint8_t bAspectRatioY; + uint8_t bmInterlaceFlags; + uint8_t bCopyProtect; +} __attribute__((__packed__)); + +#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE 27 + +/* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */ +struct uvc_frame_uncompressed { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFrameIndex; + uint8_t bmCapabilities; + uint16_t wWidth; + uint16_t wHeight; + uint32_t dwMinBitRate; + uint32_t dwMaxBitRate; + uint32_t dwMaxVideoFrameBufferSize; + uint32_t dwDefaultFrameInterval; + uint8_t bFrameIntervalType; + uint32_t dwFrameInterval[]; +} __attribute__((__packed__)); + +#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n)) + +#define UVC_FRAME_UNCOMPRESSED(n) \ + uvc_frame_uncompressed_##n + +#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \ +struct UVC_FRAME_UNCOMPRESSED(n) { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bFrameIndex; \ + uint8_t bmCapabilities; \ + uint16_t wWidth; \ + uint16_t wHeight; \ + uint32_t dwMinBitRate; \ + uint32_t dwMaxBitRate; \ + uint32_t dwMaxVideoFrameBufferSize; \ + uint32_t dwDefaultFrameInterval; \ + uint8_t bFrameIntervalType; \ + uint32_t dwFrameInterval[n]; \ +} __attribute__ ((packed)) + +#define UVC_FRAMES_FORMAT_UNCOMPRESSED(n) \ + uvc_vs_frame_format_desc_##n + +#define DECLARE_UVC_FRAMES_FORMAT_UNCOMPRESSED(n) \ +struct UVC_FRAMES_FORMAT_UNCOMPRESSED(n) { \ + struct uvc_format_uncompressed uvc_vs_format; \ + struct UVC_FRAME_UNCOMPRESSED(1) uvc_vs_frame[n]; \ + struct uvc_color_matching_descriptor uvc_vs_color; \ +} __attribute__ ((packed)); + +#endif /* __UVC_H */ + diff --git a/src/webcam/include/uvc_desc.h b/src/webcam/include/uvc_desc.h new file mode 100644 index 000000000..1b330499e --- /dev/null +++ b/src/webcam/include/uvc_desc.h @@ -0,0 +1,61 @@ +/* + * uvc_desc.h + * + * Created on: Nov 23, 2017 + * Author: kurt + */ + +#ifndef ST_STM32_USB_DEVICE_LIBRARY_CLASS_VIDEO_INC_UVC_DESC_H_ +#define ST_STM32_USB_DEVICE_LIBRARY_CLASS_VIDEO_INC_UVC_DESC_H_ + +#include "usbd_desc.h" +#include "usbd_types.h" +#include "uvc.h" + +// consistent macro expansion of VS_NUM_FORMATS +#define _UVC_INPUT_HEADER_DESCRIPTOR(n, p) UVC_INPUT_HEADER_DESCRIPTOR(n, p) + +DECLARE_UVC_HEADER_DESCRIPTOR(1); +DECLARE_UVC_FRAME_UNCOMPRESSED(1); +DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(1, 4); +DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(1, 8); +DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, VS_NUM_FORMATS); +DECLARE_UVC_FRAMES_FORMAT_UNCOMPRESSED(3); +DECLARE_UVC_FRAMES_FORMAT_UNCOMPRESSED(4); + +struct uvc_vs_frames_formats_descriptor { + struct UVC_FRAMES_FORMAT_UNCOMPRESSED(3) uvc_vs_frames_format_1; + struct UVC_FRAMES_FORMAT_UNCOMPRESSED(4) uvc_vs_frames_format_2; + struct UVC_FRAMES_FORMAT_UNCOMPRESSED(3) uvc_vs_frames_format_3; +}; + +struct usbd_uvc_cfg { + struct usb_config_descriptor usb_configuration; + struct usb_interface_assoc_descriptor usb_uvc_association; + + struct usb_interface_descriptor uvc_vc_if_desc; + struct UVC_HEADER_DESCRIPTOR(1) ucv_vc_header; + struct uvc_camera_terminal_descriptor uvc_vc_input_terminal; + struct uvc_processing_unit_descriptor uvc_vc_processing_unit; + struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 4) uvc_vc_xu_lep_agc; + struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 4) uvc_vc_xu_lep_oem; + struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 8) uvc_vc_xu_lep_rad; + struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 4) uvc_vc_xu_lep_sys; + struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 4) uvc_vc_xu_lep_vid; + struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 4) uvc_vc_xu_lep_rad_2; + struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 4) uvc_vc_xu_lep_cust; + struct uvc_output_terminal_descriptor uvc_vc_output_terminal; + struct usb_endpoint_descriptor uvc_vc_ep; + struct uvc_control_endpoint_descriptor uvc_vc_cs_ep; + + struct usb_interface_descriptor uvc_vs_if_alt0_desc; + struct _UVC_INPUT_HEADER_DESCRIPTOR(1, VS_NUM_FORMATS) uvc_vs_input_header_desc; + struct uvc_vs_frames_formats_descriptor uvc_vs_frames_formats_desc; + + struct usb_interface_descriptor uvc_vs_if_alt1_desc; + struct usb_endpoint_descriptor uvc_vs_if_alt1_ep; +} __attribute__ ((packed)); + +extern struct usbd_uvc_cfg USBD_UVC_CfgFSDesc; + +#endif /* ST_STM32_USB_DEVICE_LIBRARY_CLASS_VIDEO_INC_UVC_DESC_H_ */ diff --git a/src/webcam/include/uvc_desc_conf.h b/src/webcam/include/uvc_desc_conf.h new file mode 100644 index 000000000..81236dce2 --- /dev/null +++ b/src/webcam/include/uvc_desc_conf.h @@ -0,0 +1,11 @@ +/* Configuration 1 */ +.usb_configuration = { + .bLength = USB_LEN_CFG_DESC, // 9 + .bDescriptorType = USB_DESC_TYPE_CONFIGURATION, // 2 + .wTotalLength = sizeof(struct usbd_uvc_cfg), + .bNumInterfaces = 0x02, // 2 + .bConfigurationValue = 0x01, // 1 ID of this configuration + .iConfiguration = 0x00, // 0 no description available + .bmAttributes = USB_CONFIG_BUS_POWERED , // 0x80 Bus Powered + .bMaxPower = USB_CONFIG_POWER_MA(100), // 100 mA +}, diff --git a/src/webcam/include/uvc_desc_va.h b/src/webcam/include/uvc_desc_va.h new file mode 100644 index 000000000..1988a6dfe --- /dev/null +++ b/src/webcam/include/uvc_desc_va.h @@ -0,0 +1,13 @@ +/*----------------- Video Association (Control + stream) ------------------*/ + +/* Interface Association Descriptor */ +.usb_uvc_association = { + .bLength = USB_DT_INTERFACE_ASSOC_SIZE, // 8 + .bDescriptorType = USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE, // 11 + .bFirstInterface = 0x00, // 0 + .bInterfaceCount = 0x02, // 2 + .bFunctionClass = UVC_CC_VIDEO, // 14 Video + .bFunctionSubClass = UVC_SC_VIDEO_INTERFACE_COLLECTION, // 3 Video Interface Collection + .bFunctionProtocol = UVC_PC_PROTOCOL_UNDEFINED, // 0 (protocol undefined) + .iFunction = 0x02, // 2 +}, diff --git a/src/webcam/include/uvc_desc_vc.h b/src/webcam/include/uvc_desc_vc.h new file mode 100644 index 000000000..3a949520a --- /dev/null +++ b/src/webcam/include/uvc_desc_vc.h @@ -0,0 +1,261 @@ +/*----------------- Video Association (Control + stream) ------------------*/ + +/* Interface Association Descriptor */ +.usb_uvc_association = { + .bLength = USB_DT_INTERFACE_ASSOC_SIZE, // 8 + .bDescriptorType = USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE, // 11 + .bFirstInterface = 0x00, // 0 + .bInterfaceCount = 0x02, // 2 + .bFunctionClass = UVC_CC_VIDEO, // 14 Video + .bFunctionSubClass = UVC_SC_VIDEO_INTERFACE_COLLECTION, // 3 Video Interface Collection + .bFunctionProtocol = UVC_PC_PROTOCOL_UNDEFINED, // 0 (protocol undefined) + .iFunction = 0x02, // 2 +}, + + +/*------------------ VideoControl Interface descriptor --------------------*/ + +/* Standard VC Interface Descriptor = interface 0 */ +.uvc_vc_if_desc = { + .bLength = USB_LEN_IF_DESC, // 9 + .bDescriptorType = USB_DESC_TYPE_INTERFACE, // 4 + .bInterfaceNumber = USB_UVC_VCIF_NUM, // 0 index of this interface (VC) + .bAlternateSetting = 0x00, // 0 index of this setting + .bNumEndpoints = 0x01, // 1 endpoint + .bInterfaceClass = UVC_CC_VIDEO, // 14 Video + .bInterfaceSubClass = UVC_SC_VIDEOCONTROL, // 1 Video Control + .bInterfaceProtocol = UVC_PC_PROTOCOL_UNDEFINED, // 0 (protocol undefined) + .iInterface = 0x00, +}, + +/* Class-specific VC Interface Descriptor */ +.ucv_vc_header = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, ucv_vc_header), + .bDescriptorType = UVC_CS_INTERFACE, // 36 (INTERFACE) + .bDescriptorSubType = UVC_VC_HEADER, // 1 (HEADER) + .bcdUVC = UVC_VERSION, // 1.10 or 1.00 + .wTotalLength = + SIZEOF_M(struct usbd_uvc_cfg, ucv_vc_header) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_input_terminal) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_processing_unit) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_agc) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_oem) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_rad) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_sys) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_vid) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_rad_2) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_cust) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_output_terminal), // header+units+terminals + .dwClockFrequency = 0x005B8D80, // 6.000000 MHz + .bInCollection = 0x01, // 1 one streaming interface + .baInterfaceNr = { 0x01 }, // 1 VS interface 1 belongs to this VC interface +}, + +/* Input Terminal Descriptor (Camera) */ +.uvc_vc_input_terminal = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_input_terminal), // Descriptor size + .bDescriptorType = UVC_CS_INTERFACE, // 36 (INTERFACE) + .bDescriptorSubType = UVC_VC_INPUT_TERMINAL, // 2 (INPUT_TERMINAL) + .bTerminalID = VC_INPUT_TERMINAL_ID, // 1 ID of this Terminal + .wTerminalType = UVC_ITT_CAMERA, // 0x0201 Camera Sensor + .bAssocTerminal = 0x00, // 0 no Terminal associated + .iTerminal = 0x00, // 0 no description available + .wObjectiveFocalLengthMin = 0x0000, // 0 + .wObjectiveFocalLengthMax = 0x0000, // 0 + .wOcularFocalLength = 0x0000, // 0 + .bControlSize = 0x03, // 2 + .bmControls = { 0x00, 0x00, 0x00 }, // 0x0000 no controls supported +}, + +/* Processing Unit Descriptor */ +.uvc_vc_processing_unit = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_processing_unit), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x05, // Processing Unit Descriptor type + .bUnitID = VC_CONTROL_PU_ID, // ID of this terminal + .bSourceID = 0x01, // Source ID : 1 : Connected to input terminal + .wMaxMultiplier = 0, // Digital multiplier + .bControlSize = 0x03, // Size of controls field for this terminal : 2 bytes + .bmControls = { 0x03, 0x00, 0x00 }, // Brightness and contrast + .iProcessing = 0x00, // String desc index : Not used +}, + +/* Extension Unit Descriptor */ +.uvc_vc_xu_lep_agc = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_agc), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_AGC_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 'a','g','c','-', + '0','0','0','0' + }, + .bNumControls = 0x14, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x04, // Size of controls field for this terminal : 1 byte + .bmControls = { 0xff, 0xff, 0x0f, 0x00 }, // Registers 0x00 to 0x48 + .iExtension = 0x00, // String desc index : Not used +}, + +/* Extension Unit Descriptor */ +.uvc_vc_xu_lep_oem = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_oem), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_OEM_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 'o','e','m','-', + '0','0','0','0' + }, + .bNumControls = 0x1e, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x04, // Size of controls field for this terminal : 1 byte + .bmControls = { 0xbf, 0xff, 0xff, 0x7f }, // Registers 0x00 to 0x48 + .iExtension = 0x00, // String desc index : Not used +}, + +/* Extension Unit Descriptor */ +.uvc_vc_xu_lep_rad = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_rad), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_RAD_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 'r','a','d','-', + '0','0','0','0' + }, + .bNumControls = 48, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x08, // Size of controls field for this terminal : 1 byte + .bmControls = { 0xFF, 0xFF, 0xFF, 0x81, 0xFC, 0xCF, 0xFF, 0x03 }, // Registers 0x00 to 0x48 + .iExtension = 0x00, // String desc index : Not used +}, + +/* Extension Unit Descriptor */ +.uvc_vc_xu_lep_rad_2 = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_rad_2), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_RAD_2_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 'r','a','d','2', + '0','0','0','0' + }, + .bNumControls = 27, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x04, // Size of controls field for this terminal : 1 byte + .bmControls = { 0xf9, 0x9f, 0xff, 0x07 }, // Registers 0x00 to 0x48 + .iExtension = 0x00, // String desc index : Not used +}, + +/* Extension Unit Descriptor */ +.uvc_vc_xu_lep_sys = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_sys), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_SYS_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 's','y','s','-', + '0','0','0','0' + }, + .bNumControls = 0x17, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x04, // Size of controls field for this terminal : 1 byte + .bmControls = { 0xFF, 0xFF, 0x7F, 0x00 }, // Registers 0x00 to 0x48 + .iExtension = 0x00, // String desc index : Not used +}, + +/* Extension Unit Descriptor */ +.uvc_vc_xu_lep_vid = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_vid), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_VID_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 'v','i','d','-', + '0','0','0','0' + }, + .bNumControls = 0x0e, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x04, // Size of controls field for this terminal : 1 byte + .bmControls = { 0xFF, 0x3F, 0x00, 0x00 }, // Registers 0x00 to 0x48 + .iExtension = 0x00, // String desc index : Not used +}, + +/* Extension Unit Descriptor */ +.uvc_vc_xu_lep_cust = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_cust), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_CUST_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 'c','u','s','t', + '0','0','0','0' + }, + .bNumControls = CUST_CONTROL_END, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x04, // Size of controls field for this terminal : 1 byte + .bmControls = { (1 << CUST_CONTROL_END) - 1, 0, 0, 0 }, // + .iExtension = 0x00, // String desc index : Not used +}, + +/* Output Terminal Descriptor */ +.uvc_vc_output_terminal = { + .bLength = UVC_DT_OUTPUT_TERMINAL_SIZE, // 9 + .bDescriptorType = UVC_CS_INTERFACE, // 36 (INTERFACE) + .bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL, // 3 (OUTPUT_TERMINAL) + .bTerminalID = VC_OUTPUT_TERMINAL_ID, // 2 ID of this Terminal + .wTerminalType = UVC_TT_STREAMING, // 0x0101 USB streaming terminal + .bAssocTerminal = 0x00, // 0 no Terminal assiciated + .bSourceID = 0x03, // 1 input pin connected to output pin unit 1 + .iTerminal = 0x00, // 0 no description available +}, + +/* Standard Interrupt Endpoint Descriptor */ +.uvc_vc_ep = { + .bLength = USB_DT_ENDPOINT_SIZE, // 7 + .bDescriptorType = USB_DESC_TYPE_ENDPOINT, // 5 (ENDPOINT) + .bEndpointAddress = UVC_CMD_EP, // 0x82 EP 2 IN + .bmAttributes = USBD_EP_TYPE_INTR, // interrupt + .wMaxPacketSize = CMD_PACKET_SIZE, // 8 bytes status + .bInterval = 0x20, // poll at least every 32ms +}, + +/* Class-specific Interrupt Endpoint Descriptor */ +.uvc_vc_cs_ep = { + .bLength = UVC_DT_CONTROL_ENDPOINT_SIZE, + .bDescriptorType = UVC_CS_ENDPOINT, + .bDescriptorSubType = USBD_EP_TYPE_INTR, + .wMaxTransferSize = CMD_PACKET_SIZE, +}, diff --git a/src/webcam/include/uvc_desc_vs.h b/src/webcam/include/uvc_desc_vs.h new file mode 100644 index 000000000..d06b0afca --- /dev/null +++ b/src/webcam/include/uvc_desc_vs.h @@ -0,0 +1,75 @@ +/*-------------- Video Streaming (VS) Interface Descriptor ----------------*/ + +/* Standard VS Interface Descriptor = interface 1 */ +// alternate setting 0 = Zero Bandwidth +.uvc_vs_if_alt0_desc = { + .bLength = USB_DT_INTERFACE_SIZE, // 9 + .bDescriptorType = USB_DESC_TYPE_INTERFACE, // 4 + .bInterfaceNumber = USB_UVC_VSIF_NUM, // 1 index of this interface + .bAlternateSetting = 0x00, // 0 index of this setting + .bNumEndpoints = 0x00, // 0 no EP used + .bInterfaceClass = UVC_CC_VIDEO, // 14 Video + .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING, // 2 Video Streaming + .bInterfaceProtocol = UVC_PC_PROTOCOL_UNDEFINED, // 0 (protocol undefined) + .iInterface = 0x00, // 0 no description available +}, + +/* Class-specific VS Header Descriptor (Input) */ +.uvc_vs_input_header_desc = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vs_input_header_desc), + .bDescriptorType = UVC_CS_INTERFACE, // 36 (INTERFACE) + .bDescriptorSubType = UVC_VS_INPUT_HEADER, // 1 (INPUT_HEADER) + .bNumFormats = VS_NUM_FORMATS, // 4 four format descriptors follow + .wTotalLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vs_input_header_desc) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vs_frames_formats_desc), + .bEndpointAddress = UVC_IN_EP, // 0x83 EP 3 IN + .bmInfo = 0x00, // 0 no dynamic format change supported + .bTerminalLink = VC_OUTPUT_TERMINAL_ID, // 2 supplies terminal ID 2 (Output terminal) + .bStillCaptureMethod = 0x01, // 1 Host captures from video stream + .bTriggerSupport = 0x00, // 0 HW trigger supported for still image capture + .bTriggerUsage = 0x00, // 0 HW trigger initiate a still image capture + .bControlSize = 0x01, // 1 one byte bmaControls field size + .bmaControls = { + { 0x00 }, // bmaControls(0) 0 no VS specific controls + { 0x00 }, // bmaControls(1) 0 no VS specific controls + { 0x00 }, // bmaControls(2) 0 no VS specific controls + { 0x00 }, // bmaControls(3) 0 no VS specific controls + { 0x00 }, // bmaControls(4) 0 no VS specific controls + }, +}, + +.uvc_vs_frames_formats_desc = { +.uvc_vs_frames_format_1 = + { + .uvc_vs_format = UVC_FORMAT_UNCOMPRESSED_DESCRIPTOR(YUYV, 1), + .uvc_vs_frame = { UVC_FRAME_FORMAT(VS_FRAME_INDEX_DEFAULT, YUYV, 80, 60) }, + .uvc_vs_color = UVC_COLOR_MATCHING_DESCRIPTOR(), + }, +.uvc_vs_frames_format_2 = + { + .uvc_vs_format = UVC_FORMAT_UNCOMPRESSED_DESCRIPTOR(Y16, 1), + .uvc_vs_frame = { UVC_FRAME_FORMAT(VS_FRAME_INDEX_DEFAULT, Y16, 80, 60), + UVC_FRAME_FORMAT(VS_FRAME_INDEX_TELEMETRIC, Y16, 80, 63) }, + .uvc_vs_color = UVC_COLOR_MATCHING_DESCRIPTOR(), + }, +.uvc_vs_frames_format_3 = + { + .uvc_vs_format = UVC_FORMAT_UNCOMPRESSED_DESCRIPTOR(GREY, 1), + .uvc_vs_frame = { UVC_FRAME_FORMAT(VS_FRAME_INDEX_DEFAULT, GREY, 80, 60) }, + .uvc_vs_color = UVC_COLOR_MATCHING_DESCRIPTOR(), + }, +.uvc_vs_frames_format_4 = + { + .uvc_vs_format = UVC_FORMAT_UNCOMPRESSED_DESCRIPTOR(RGB565, 1), + .uvc_vs_frame = { UVC_FRAME_FORMAT(VS_FRAME_INDEX_DEFAULT, RGB565, 80, 60) }, + .uvc_vs_color = UVC_COLOR_MATCHING_DESCRIPTOR(), + }, +.uvc_vs_frames_format_5 = + { + .uvc_vs_format = UVC_FORMAT_UNCOMPRESSED_DESCRIPTOR(BGR3, 1), + .uvc_vs_frame = { UVC_FRAME_FORMAT(VS_FRAME_INDEX_DEFAULT, BGR3, 80, 60) }, + .uvc_vs_color = UVC_COLOR_MATCHING_DESCRIPTOR(), + }, +}, diff --git a/src/webcam/include/uvc_desc_vs_if.h b/src/webcam/include/uvc_desc_vs_if.h new file mode 100644 index 000000000..74979ce44 --- /dev/null +++ b/src/webcam/include/uvc_desc_vs_if.h @@ -0,0 +1,23 @@ +/* Standard VS Interface Descriptor = interface 1 */ +// alternate setting 1 = operational setting +.uvc_vs_if_alt1_desc = { + .bLength = USB_DT_INTERFACE_SIZE, // 9 + .bDescriptorType = USB_DESC_TYPE_INTERFACE, // 4 + .bInterfaceNumber = USB_UVC_VSIF_NUM, // 1 index of this interface + .bAlternateSetting = 0x01, // 1 index of this setting + .bNumEndpoints = 0x01, // 1 one EP used + .bInterfaceClass = UVC_CC_VIDEO, // 14 Video + .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING, // 2 Video Streaming + .bInterfaceProtocol = UVC_PC_PROTOCOL_UNDEFINED, // 0 (protocol undefined) + .iInterface = 0x00, // 0 no description available +}, + +/* Standard VS Isochronous Video data Endpoint Descriptor */ +.uvc_vs_if_alt1_ep = { + .bLength = USB_DT_ENDPOINT_SIZE, // 7 + .bDescriptorType = USB_DESC_TYPE_ENDPOINT, // 5 (ENDPOINT) + .bEndpointAddress = UVC_IN_EP, // 0x83 EP 3 IN + .bmAttributes = USBD_EP_TYPE_ISOC, // 1 isochronous transfer type + .wMaxPacketSize = VIDEO_PACKET_SIZE, + .bInterval = 0x01, // 1 one frame interval +}, diff --git a/src/webcam/src/main.c b/src/webcam/src/main.c new file mode 100644 index 000000000..fed39122f --- /dev/null +++ b/src/webcam/src/main.c @@ -0,0 +1,177 @@ +#include STM32_HAL_H +#include "usbd_core.h" +#include "usbd_desc.h" +#include "usbd_uvc.h" +#include "usbd_uvc_if.h" +#include "sensor.h" +#include "framebuffer.h" +#include "omv_boardconfig.h" + +extern sensor_t sensor; +USBD_HandleTypeDef hUsbDeviceFS; +extern volatile uint8_t g_uvc_stream_status; +extern struct uvc_streaming_control videoCommitControl; + +void __attribute__((noreturn)) __fatal_error() +{ + while (1) { + } +} + +#ifdef STACK_PROTECTOR +uint32_t __stack_chk_guard=0xDEADBEEF; + +void __attribute__((noreturn)) __stack_chk_fail(void) +{ + __asm__ volatile ("BKPT"); + while (1) { + } +} +#endif + +void *xrealloc(void *mem, uint32_t size) +{ + // Will never be called. + __fatal_error(); + return NULL; +} + +NORETURN void fb_alloc_fail() +{ + __fatal_error(); +} + +int main() +{ + HAL_Init(); + + // Re-enable IRQs (disabled by bootloader) + __enable_irq(); + + + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.Pull = GPIO_PULLUP; + GPIO_InitStructure.Speed = GPIO_SPEED_LOW; + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + + GPIO_InitStructure.Pin = OMV_BOOTLDR_LED_PIN; + HAL_GPIO_Init(OMV_BOOTLDR_LED_PORT, &GPIO_InitStructure); + HAL_GPIO_WritePin(OMV_BOOTLDR_LED_PORT, OMV_BOOTLDR_LED_PIN, GPIO_PIN_SET); + + sensor_init0(); + fb_alloc_init0(); + + // Initialize the sensor + if (sensor_init() != 0) { + __fatal_error(); + } + + sensor_reset(); + + /* Init Device Library */ + USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS); + + /* Add Supported Class */ + USBD_RegisterClass(&hUsbDeviceFS, &USBD_UVC); + + /* Add Interface Class */ + USBD_UVC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS); + + USBD_Start(&hUsbDeviceFS); + + image_t image = {0}; + uint32_t frame_size = 0; + uint8_t frame_index = 0; + uint8_t format_index = 0; + uint32_t packet_size = VIDEO_PACKET_SIZE; + static uint8_t uvc_header[2] = { 2, 0 }; + static uint8_t packet[VIDEO_PACKET_SIZE]; + + while (1) { + uint32_t idx = 0; + while (g_uvc_stream_status == 2) { + uint32_t pidx = 0; + packet[pidx++] = uvc_header[0]; + packet[pidx++] = uvc_header[1]; + + if (image.bpp == 0) { + if (frame_index != videoCommitControl.bFrameIndex || + format_index != videoCommitControl.bFormatIndex) { + + switch (videoCommitControl.bFormatIndex) { + case VS_FMT_INDEX(YUYV): + sensor_set_pixformat(PIXFORMAT_YUV422); + break; + case VS_FMT_INDEX(GREY): + sensor_set_pixformat(PIXFORMAT_GRAYSCALE); + break; + case VS_FMT_INDEX(RGB565): + sensor_set_pixformat(PIXFORMAT_RGB565); + break; + default: + break; + } + + switch (videoCommitControl.bFrameIndex) { + case VS_FRAME_INDEX_1: + sensor_set_framesize(FRAMESIZE_QQQVGA); + break; + case VS_FRAME_INDEX_2: + sensor_set_framesize(FRAMESIZE_QQVGA); + break; + case VS_FRAME_INDEX_3: + sensor_set_framesize(FRAMESIZE_QVGA); + break; + case VS_FRAME_INDEX_4: + sensor_set_framesize(FRAMESIZE_VGA); + break; + default: + break; + } + + frame_index = videoCommitControl.bFrameIndex; + format_index = videoCommitControl.bFormatIndex; + } + + // capture new frame + sensor.snapshot(&sensor, &image); + frame_size = image.w * image.h * image.bpp; + } + + switch (videoCommitControl.bFormatIndex) { + case VS_FMT_INDEX(YUYV): { + for (; pidx + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Interrupt handlers. + * + */ + +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Src/stm32f4xx_it.c + * @author MCD Application Team + * @version V1.2.2 + * @date 25-May-2015 + * @brief Main Interrupt Service Routines. + * This file provides template for all exceptions handler and + * peripherals interrupt service routine. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +#include STM32_HAL_H +#include + +extern PCD_HandleTypeDef hpcd; +extern DCMI_HandleTypeDef DCMIHandle; +extern void DCMI_VsyncExtiCallback(); +extern TIM_HandleTypeDef TIM5_Handle; + +/** + * @brief This function handles NMI exception. + * @param None + * @retval None + */ +void NMI_Handler(void) +{ +} + +/** + * @brief This function handles Hard Fault exception. + * @param None + * @retval None + */ +void HardFault_Handler(void) +{ + /* Go to infinite loop when Hard Fault exception occurs */ + while (1) + { + } +} + +/** + * @brief This function handles Memory Manage exception. + * @param None + * @retval None + */ +void MemManage_Handler(void) +{ + /* Go to infinite loop when Memory Manage exception occurs */ + while (1) + { + } +} + +/** + * @brief This function handles Bus Fault exception. + * @param None + * @retval None + */ +void BusFault_Handler(void) +{ + /* Go to infinite loop when Bus Fault exception occurs */ + while (1) + { + } +} + +/** + * @brief This function handles Usage Fault exception. + * @param None + * @retval None + */ +void UsageFault_Handler(void) +{ + /* Go to infinite loop when Usage Fault exception occurs */ + while (1) + { + } +} + +/** + * @brief This function handles SVCall exception. + * @param None + * @retval None + */ +void SVC_Handler(void) +{ +} + +/** + * @brief This function handles Debug Monitor exception. + * @param None + * @retval None + */ +void DebugMon_Handler(void) +{ +} + +/** + * @brief This function handles PendSVC exception. + * @param None + * @retval None + */ +void PendSV_Handler(void) +{ +} + +/** + * @brief This function handles SysTick Handler. + * @param None + * @retval None + */ +void SysTick_Handler(void) +{ + HAL_IncTick(); +} + +/** + * @brief This function handles USB-On-The-Go FS global interrupt request. + * @param None + * @retval None + */ +#ifdef USE_USB_FS +void OTG_FS_IRQHandler(void) +#else +void OTG_HS_IRQHandler(void) +#endif +{ + HAL_PCD_IRQHandler(&hpcd); +} + +void DCMI_IRQHandler(void) { + HAL_DCMI_IRQHandler(&DCMIHandle); +} + +void DMA2_Stream1_IRQHandler(void) { + HAL_DMA_IRQHandler(DCMIHandle.DMA_Handle); +} diff --git a/src/webcam/src/string0.c b/src/webcam/src/string0.c new file mode 100644 index 000000000..c2f2abd0f --- /dev/null +++ b/src/webcam/src/string0.c @@ -0,0 +1,219 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#define likely(x) __builtin_expect((x), 1) + +void *memcpy(void *dst, const void *src, size_t n) { + if (likely(!(((uintptr_t)dst) & 3) && !(((uintptr_t)src) & 3))) { + // pointers aligned + uint32_t *d = dst; + const uint32_t *s = src; + + // copy words first + for (size_t i = (n >> 2); i; i--) { + *d++ = *s++; + } + + if (n & 2) { + // copy half-word + *(uint16_t*)d = *(const uint16_t*)s; + d = (uint32_t*)((uint16_t*)d + 1); + s = (const uint32_t*)((const uint16_t*)s + 1); + } + + if (n & 1) { + // copy byte + *((uint8_t*)d) = *((const uint8_t*)s); + } + } else { + // unaligned access, copy bytes + uint8_t *d = dst; + const uint8_t *s = src; + + for (; n; n--) { + *d++ = *s++; + } + } + + return dst; +} + +void *memmove(void *dest, const void *src, size_t n) { + if (src < dest && (uint8_t*)dest < (const uint8_t*)src + n) { + // need to copy backwards + uint8_t *d = (uint8_t*)dest + n - 1; + const uint8_t *s = (const uint8_t*)src + n - 1; + for (; n > 0; n--) { + *d-- = *s--; + } + return dest; + } else { + // can use normal memcpy + return memcpy(dest, src, n); + } +} + +void *memset(void *s, int c, size_t n) { + if (c == 0 && ((uintptr_t)s & 3) == 0) { + // aligned store of 0 + uint32_t *s32 = s; + for (size_t i = n >> 2; i > 0; i--) { + *s32++ = 0; + } + if (n & 2) { + *((uint16_t*)s32) = 0; + s32 = (uint32_t*)((uint16_t*)s32 + 1); + } + if (n & 1) { + *((uint8_t*)s32) = 0; + } + } else { + uint8_t *s2 = s; + for (; n > 0; n--) { + *s2++ = c; + } + } + return s; +} + +int memcmp(const void *s1, const void *s2, size_t n) { + const uint8_t *s1_8 = s1; + const uint8_t *s2_8 = s2; + while (n--) { + char c1 = *s1_8++; + char c2 = *s2_8++; + if (c1 < c2) return -1; + else if (c1 > c2) return 1; + } + return 0; +} + +void *memchr(const void *s, int c, size_t n) { + if (n != 0) { + const unsigned char *p = s; + + do { + if (*p++ == c) + return ((void *)(p - 1)); + } while (--n != 0); + } + return 0; +} + +size_t strlen(const char *str) { + int len = 0; + for (const char *s = str; *s; s++) { + len += 1; + } + return len; +} + +int strcmp(const char *s1, const char *s2) { + while (*s1 && *s2) { + char c1 = *s1++; // XXX UTF8 get char, next char + char c2 = *s2++; // XXX UTF8 get char, next char + if (c1 < c2) return -1; + else if (c1 > c2) return 1; + } + if (*s2) return -1; + else if (*s1) return 1; + else return 0; +} + +int strncmp(const char *s1, const char *s2, size_t n) { + while (*s1 && *s2 && n > 0) { + char c1 = *s1++; // XXX UTF8 get char, next char + char c2 = *s2++; // XXX UTF8 get char, next char + n--; + if (c1 < c2) return -1; + else if (c1 > c2) return 1; + } + if (n == 0) return 0; + else if (*s2) return -1; + else if (*s1) return 1; + else return 0; +} + +char *strcpy(char *dest, const char *src) { + char *d = dest; + while (*src) { + *d++ = *src++; + } + *d = '\0'; + return dest; +} + +// needed because gcc optimises strcpy + strcat to this +char *stpcpy(char *dest, const char *src) { + while (*src) { + *dest++ = *src++; + } + *dest = '\0'; + return dest; +} + +char *strcat(char *dest, const char *src) { + char *d = dest; + while (*d) { + d++; + } + while (*src) { + *d++ = *src++; + } + *d = '\0'; + return dest; +} + +// Public Domain implementation of strchr from: +// http://en.wikibooks.org/wiki/C_Programming/Strings#The_strchr_function +char *strchr(const char *s, int c) +{ + /* Scan s for the character. When this loop is finished, + s will either point to the end of the string or the + character we were looking for. */ + while (*s != '\0' && *s != (char)c) + s++; + return ((*s == c) ? (char *) s : 0); +} + + +// Public Domain implementation of strstr from: +// http://en.wikibooks.org/wiki/C_Programming/Strings#The_strstr_function +char *strstr(const char *haystack, const char *needle) +{ + size_t needlelen; + /* Check for the null needle case. */ + if (*needle == '\0') + return (char *) haystack; + needlelen = strlen(needle); + for (; (haystack = strchr(haystack, *needle)) != 0; haystack++) + if (strncmp(haystack, needle, needlelen) == 0) + return (char *) haystack; + return 0; +} diff --git a/src/webcam/src/systick.c b/src/webcam/src/systick.c new file mode 100644 index 000000000..f31efe437 --- /dev/null +++ b/src/webcam/src/systick.c @@ -0,0 +1,21 @@ +#include STM32_HAL_H +#include "stdint.h" +#include "stdbool.h" +#include "systick.h" + +void systick_sleep(volatile uint32_t ms) +{ + volatile uint32_t curr_ticks = HAL_GetTick(); + while ((HAL_GetTick() - curr_ticks) < ms) { + __WFI(); + } +} + +uint32_t systick_current_millis() +{ + return HAL_GetTick(); +} + +bool sys_tick_has_passed(uint32_t start_tick, uint32_t delay_ms) { + return HAL_GetTick() - start_tick >= delay_ms; +} diff --git a/src/webcam/src/usbd_conf.c b/src/webcam/src/usbd_conf.c new file mode 100644 index 000000000..f38559f94 --- /dev/null +++ b/src/webcam/src/usbd_conf.c @@ -0,0 +1,522 @@ +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Src/usbd_conf.c + * @author MCD Application Team + * @version V1.2.2 + * @date 25-May-2015 + * @brief This file implements the USB Device library callbacks and MSP + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include STM32_HAL_H +#include "stm32_hal_legacy.h" +#include "usbd_core.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +PCD_HandleTypeDef hpcd; + +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* + PCD BSP Routines +*******************************************************************************/ +/** + * @brief Initializes the PCD MSP. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + if(hpcd->Instance == USB_OTG_FS) + { + /* Configure USB FS GPIOs */ + __GPIOA_CLK_ENABLE(); + + 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_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* Configure VBUS Pin */ + // USB VBUS detect pin is always A9 + GPIO_InitStruct.Pin = GPIO_PIN_9; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + +#if 0 //defined(MICROPY_HW_USB_OTG_ID_PIN) + // Not used + // USB ID pin is always A10 + GPIO_InitStruct.Pin = GPIO_PIN_10; + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); +#endif + + #if defined(MCU_SERIES_H7) + // Keep USB clock running during sleep or else __WFI() will disable the USB + __HAL_RCC_USB2_OTG_FS_CLK_SLEEP_ENABLE(); + __HAL_RCC_USB2_OTG_FS_ULPI_CLK_SLEEP_DISABLE(); + #endif + + /* Enable USB FS Clocks */ + __USB_OTG_FS_CLK_ENABLE(); + + /* Set USBFS Interrupt priority */ + HAL_NVIC_SetPriority(OTG_FS_IRQn, 6, 0); + + /* Enable USBFS Interrupt */ + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + } +} +/** + * @brief DeInitializes the PCD MSP. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) +{ + if(hpcd->Instance == USB_OTG_FS) + { + /* Disable USB FS Clocks */ + __USB_OTG_FS_CLK_DISABLE(); + __SYSCFG_CLK_DISABLE(); + } + #if defined(USE_USB_HS) + else if(hpcd->Instance == USB_OTG_HS) + { + /* Disable USB FS Clocks */ + __USB_OTG_HS_CLK_DISABLE(); + __SYSCFG_CLK_DISABLE(); + } + #endif +} + + +/******************************************************************************* + LL Driver Callbacks (PCD -> USB Device Library) +*******************************************************************************/ + + +/** + * @brief Setup stage callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) +{ + USBD_LL_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_LL_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_LL_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_LL_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_LL_SetSpeed(hpcd->pData, speed); + + /* Reset Device */ + USBD_LL_Reset(hpcd->pData); +} + +/** + * @brief Suspend callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) +{ + USBD_LL_Suspend(hpcd->pData); +} + +/** + * @brief Resume callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) +{ + USBD_LL_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_LL_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_LL_IsoINIncomplete(hpcd->pData, epnum); +} + +/** + * @brief Connect callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) +{ + USBD_HandleTypeDef *pdev = hpcd->pData; + pdev->dev_connection_status = 1; + USBD_LL_DevConnected(hpcd->pData); +} + +/** + * @brief Disconnect callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) +{ + USBD_HandleTypeDef *pdev = hpcd->pData; + pdev->dev_connection_status = 0; + USBD_LL_DevDisconnected(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) +{ + /* Change Systick prioity */ + NVIC_SetPriority (SysTick_IRQn, 0); + +#ifdef USE_USB_FS + /*Set LL Driver parameters */ + hpcd.Instance = USB_OTG_FS; + hpcd.Init.dev_endpoints = 3; + hpcd.Init.use_dedicated_ep1 = 0; + hpcd.Init.ep0_mps = DEP0CTL_MPS_64; + hpcd.Init.dma_enable = 0; + hpcd.Init.low_power_enable = 0; + hpcd.Init.phy_itface = PCD_PHY_EMBEDDED; + hpcd.Init.Sof_enable = 1; + hpcd.Init.speed = PCD_SPEED_FULL; + hpcd.Init.vbus_sensing_enable = 1; + /* Link The driver to the stack */ + hpcd.pData = pdev; + pdev->pData = &hpcd; + /*Initialize LL Driver */ + HAL_PCD_Init(&hpcd); + + HAL_PCDEx_SetRxFiFo(&hpcd, 0x2E); + HAL_PCDEx_SetTxFiFo(&hpcd, 0, 0x20); + HAL_PCDEx_SetTxFiFo(&hpcd, 1, 0xF2); + + +#endif +#ifdef USE_USB_HS + /*Set LL Driver parameters */ + hpcd.Instance = USB_OTG_HS; + hpcd.Init.dev_endpoints = 6; + hpcd.Init.use_dedicated_ep1 = 0; + hpcd.Init.ep0_mps = 0x40; + + /* Be aware that enabling USB-DMA mode will result in data being sent only by + multiple of 4 packet sizes. This is due to the fact that USB-DMA does + not allow sending data from non word-aligned addresses. + For this specific application, it is advised to not enable this option + unless required. */ + hpcd.Init.dma_enable = 0; + + hpcd.Init.low_power_enable = 0; + hpcd.Init.phy_itface = PCD_PHY_ULPI; + hpcd.Init.Sof_enable = 0; + hpcd.Init.speed = PCD_SPEED_HIGH; + hpcd.Init.vbus_sensing_enable = 1; + /* Link The driver to the stack */ + hpcd.pData = pdev; + pdev->pData = &hpcd; + /*Initialize LL Driver */ + HAL_PCD_Init(&hpcd); + + HAL_PCDEx_SetRxFiFo(&hpcd, 0x200); + HAL_PCDEx_SetTxFiFo(&hpcd, 0, 0x80); + HAL_PCDEx_SetTxFiFo(&hpcd, 1, 0x174); + + +#endif + 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 an USB address to the device + * @param pdev: Device handle + * @param dev_addr: USB address + * @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 Delay routine for the USB Device Library + * @param Delay: Delay in ms + * @retval None + */ +void USBD_LL_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/webcam/src/usbd_core.c b/src/webcam/src/usbd_core.c new file mode 100644 index 000000000..66acf1ebd --- /dev/null +++ b/src/webcam/src/usbd_core.c @@ -0,0 +1,554 @@ +/** + ****************************************************************************** + * @file usbd_core.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides all the USBD core functions. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_core.h" + +/** @addtogroup STM32_USBD_DEVICE_LIBRARY +* @{ +*/ + + +/** @defgroup USBD_CORE +* @brief usbd core module +* @{ +*/ + +/** @defgroup USBD_CORE_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBD_CORE_Private_Defines +* @{ +*/ + +/** +* @} +*/ + + +/** @defgroup USBD_CORE_Private_Macros +* @{ +*/ +/** +* @} +*/ + + + + +/** @defgroup USBD_CORE_Private_FunctionPrototypes +* @{ +*/ + +/** +* @} +*/ + +/** @defgroup USBD_CORE_Private_Variables +* @{ +*/ + +/** +* @} +*/ + +/** @defgroup USBD_CORE_Private_Functions +* @{ +*/ + +/** +* @brief USBD_Init +* Initailizes the device stack and load the class driver +* @param pdev: device instance +* @param core_address: USB OTG core ID +* @param pdesc: Descriptor structure address +* @param id: Low level core index +* @retval None +*/ +USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id) +{ + /* Check whether the USB Host handle is valid */ + if(pdev == NULL) + { + USBD_ErrLog("Invalid Device handle"); + return USBD_FAIL; + } + + /* Unlink previous class*/ + if(pdev->pClass != NULL) + { + pdev->pClass = NULL; + } + + /* Assign USBD Descriptors */ + if(pdesc != NULL) + { + pdev->pDesc = pdesc; + } + + /* Set Device initial State */ + pdev->dev_state = USBD_STATE_DEFAULT; + pdev->id = id; + /* Initialize low level driver */ + USBD_LL_Init(pdev); + + return USBD_OK; +} + +/** +* @brief USBD_DeInit +* Re-Initialize th device library +* @param pdev: device instance +* @retval status: status +*/ +USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev) +{ + /* Set Default State */ + pdev->dev_state = USBD_STATE_DEFAULT; + + /* Free Class Resources */ + pdev->pClass->DeInit(pdev, pdev->dev_config); + + /* Stop the low level driver */ + USBD_LL_Stop(pdev); + + /* Initialize low level driver */ + USBD_LL_DeInit(pdev); + + return USBD_OK; +} + + +/** + * @brief USBD_RegisterClass + * Link class driver to Device Core. + * @param pDevice : Device Handle + * @param pclass: Class handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, USBD_ClassTypeDef *pclass) +{ + USBD_StatusTypeDef status = USBD_OK; + if(pclass != 0) + { + /* link the class tgo the USB Device handle */ + pdev->pClass = pclass; + status = USBD_OK; + } + else + { + USBD_ErrLog("Invalid Class handle"); + status = USBD_FAIL; + } + + return status; +} + +/** + * @brief USBD_Start + * Start the USB Device Core. + * @param pdev: Device Handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev) +{ + + /* Start the low level driver */ + USBD_LL_Start(pdev); + + return USBD_OK; +} + +/** + * @brief USBD_Stop + * Stop the USB Device Core. + * @param pdev: Device Handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev) +{ + /* Free Class Resources */ + pdev->pClass->DeInit(pdev, pdev->dev_config); + + /* Stop the low level driver */ + USBD_LL_Stop(pdev); + + return USBD_OK; +} + +/** +* @brief USBD_RunTestMode +* Launch test mode process +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev) +{ + return USBD_OK; +} + + +/** +* @brief USBD_SetClassConfig +* Configure device and start the interface +* @param pdev: device instance +* @param cfgidx: configuration index +* @retval status +*/ + +USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx) +{ + USBD_StatusTypeDef ret = USBD_FAIL; + + if(pdev->pClass != NULL) + { + /* Set configuration and Start the Class*/ + if(pdev->pClass->Init(pdev, cfgidx) == 0) + { + ret = USBD_OK; + } + } + return ret; +} + +/** +* @brief USBD_ClrClassConfig +* Clear current configuration +* @param pdev: device instance +* @param cfgidx: configuration index +* @retval status: USBD_StatusTypeDef +*/ +USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx) +{ + /* Clear configuration and Deinitialize the Class process*/ + pdev->pClass->DeInit(pdev, cfgidx); + return USBD_OK; +} + + +/** +* @brief USBD_SetupStage +* Handle the setup stage +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup) +{ + + USBD_ParseSetupRequest(&pdev->request, psetup); + + pdev->ep0_state = USBD_EP0_SETUP; + pdev->ep0_data_len = pdev->request.wLength; + + switch (pdev->request.bmRequest & 0x1F) + { + case USB_REQ_RECIPIENT_DEVICE: + USBD_StdDevReq (pdev, &pdev->request); + break; + + case USB_REQ_RECIPIENT_INTERFACE: + USBD_StdItfReq(pdev, &pdev->request); + break; + + case USB_REQ_RECIPIENT_ENDPOINT: + USBD_StdEPReq(pdev, &pdev->request); + break; + + default: + USBD_LL_StallEP(pdev , pdev->request.bmRequest & 0x80); + break; + } + return USBD_OK; +} + +/** +* @brief USBD_DataOutStage +* Handle data OUT stage +* @param pdev: device instance +* @param epnum: endpoint index +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata) +{ + USBD_EndpointTypeDef *pep; + + if(epnum == 0) + { + pep = &pdev->ep_out[0]; + + if ( pdev->ep0_state == USBD_EP0_DATA_OUT) + { + if(pep->rem_length > pep->maxpacket) + { + pep->rem_length -= pep->maxpacket; + + USBD_CtlContinueRx (pdev, + pdata, + MIN(pep->rem_length ,pep->maxpacket)); + } + else + { + if((pdev->pClass->EP0_RxReady != NULL)&& + (pdev->dev_state == USBD_STATE_CONFIGURED)) + { + pdev->pClass->EP0_RxReady(pdev); + } + USBD_CtlSendStatus(pdev); + } + } + } + else if((pdev->pClass->DataOut != NULL)&& + (pdev->dev_state == USBD_STATE_CONFIGURED)) + { + pdev->pClass->DataOut(pdev, epnum); + } + return USBD_OK; +} + +/** +* @brief USBD_DataInStage +* Handle data in stage +* @param pdev: device instance +* @param epnum: endpoint index +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev ,uint8_t epnum, uint8_t *pdata) +{ + USBD_EndpointTypeDef *pep; + + if(epnum == 0) + { + pep = &pdev->ep_in[0]; + + if ( pdev->ep0_state == USBD_EP0_DATA_IN) + { + if(pep->rem_length > pep->maxpacket) + { + pep->rem_length -= pep->maxpacket; + + USBD_CtlContinueSendData (pdev, + pdata, + pep->rem_length); + } + else + { /* last packet is MPS multiple, so send ZLP packet */ + if((pep->total_length % pep->maxpacket == 0) && + (pep->total_length >= pep->maxpacket) && + (pep->total_length < pdev->ep0_data_len )) + { + + USBD_CtlContinueSendData(pdev , NULL, 0); + pdev->ep0_data_len = 0; + } + else + { + if((pdev->pClass->EP0_TxSent != NULL)&& + (pdev->dev_state == USBD_STATE_CONFIGURED)) + { + pdev->pClass->EP0_TxSent(pdev); + } + USBD_CtlReceiveStatus(pdev); + } + } + } + if (pdev->dev_test_mode == 1) + { + USBD_RunTestMode(pdev); + pdev->dev_test_mode = 0; + } + } + else if((pdev->pClass->DataIn != NULL)&& + (pdev->dev_state == USBD_STATE_CONFIGURED)) + { + pdev->pClass->DataIn(pdev, epnum); + } + return USBD_OK; +} + +/** +* @brief USBD_LL_Reset +* Handle Reset event +* @param pdev: device instance +* @retval status +*/ + +USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev) +{ + /* Open EP0 OUT */ + USBD_LL_OpenEP(pdev, + 0x00, + USBD_EP_TYPE_CTRL, + USB_MAX_EP0_SIZE); + + pdev->ep_out[0].maxpacket = USB_MAX_EP0_SIZE; + + /* Open EP0 IN */ + USBD_LL_OpenEP(pdev, + 0x80, + USBD_EP_TYPE_CTRL, + USB_MAX_EP0_SIZE); + + pdev->ep_in[0].maxpacket = USB_MAX_EP0_SIZE; + /* Upon Reset call usr call back */ + pdev->dev_state = USBD_STATE_DEFAULT; + + if (pdev->pClassData) + pdev->pClass->DeInit(pdev, pdev->dev_config); + + + return USBD_OK; +} + + + + +/** +* @brief USBD_LL_Reset +* Handle Reset event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed) +{ + pdev->dev_speed = speed; + return USBD_OK; +} + +/** +* @brief USBD_Suspend +* Handle Suspend event +* @param pdev: device instance +* @retval status +*/ + +USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev) +{ + pdev->dev_old_state = pdev->dev_state; + pdev->dev_state = USBD_STATE_SUSPENDED; + return USBD_OK; +} + +/** +* @brief USBD_Resume +* Handle Resume event +* @param pdev: device instance +* @retval status +*/ + +USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev) +{ + pdev->dev_state = pdev->dev_old_state; + return USBD_OK; +} + +/** +* @brief USBD_SOF +* Handle SOF event +* @param pdev: device instance +* @retval status +*/ + +USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev) +{ + if(pdev->dev_state == USBD_STATE_CONFIGURED) + { + if(pdev->pClass->SOF != NULL) + { + pdev->pClass->SOF(pdev); + } + } + return USBD_OK; +} + +/** +* @brief USBD_IsoINIncomplete +* Handle iso in incomplete event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + return USBD_OK; +} + +/** +* @brief USBD_IsoOUTIncomplete +* Handle iso out incomplete event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + return USBD_OK; +} + +/** +* @brief USBD_DevConnected +* Handle device connection event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev) +{ + return USBD_OK; +} + +/** +* @brief USBD_DevDisconnected +* Handle device disconnection event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev) +{ + /* Free Class Resources */ + pdev->dev_state = USBD_STATE_DEFAULT; + pdev->pClass->DeInit(pdev, pdev->dev_config); + + return USBD_OK; +} +/** +* @} +*/ + + +/** +* @} +*/ + + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/webcam/src/usbd_ctlreq.c b/src/webcam/src/usbd_ctlreq.c new file mode 100644 index 000000000..d0bd68086 --- /dev/null +++ b/src/webcam/src/usbd_ctlreq.c @@ -0,0 +1,769 @@ +/** + ****************************************************************************** + * @file usbd_req.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides the standard USB requests following chapter 9. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_ctlreq.h" +#include "usbd_ioreq.h" + + +/** @addtogroup STM32_USBD_STATE_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup USBD_REQ + * @brief USB standard requests module + * @{ + */ + +/** @defgroup USBD_REQ_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Variables + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_FunctionPrototypes + * @{ + */ +static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_SetAddress(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_SetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_GetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_GetStatus(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_SetFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_ClrFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static uint8_t USBD_GetLen(uint8_t *buf); + +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Functions + * @{ + */ + + +/** +* @brief USBD_StdDevReq +* Handle standard usb device requests +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) +{ + USBD_StatusTypeDef ret = USBD_OK; + + switch (req->bRequest) + { + case USB_REQ_GET_DESCRIPTOR: + + USBD_GetDescriptor (pdev, req) ; + break; + + case USB_REQ_SET_ADDRESS: + USBD_SetAddress(pdev, req); + break; + + case USB_REQ_SET_CONFIGURATION: + USBD_SetConfig (pdev , req); + break; + + case USB_REQ_GET_CONFIGURATION: + USBD_GetConfig (pdev , req); + break; + + case USB_REQ_GET_STATUS: + USBD_GetStatus (pdev , req); + break; + + + case USB_REQ_SET_FEATURE: + USBD_SetFeature (pdev , req); + break; + + case USB_REQ_CLEAR_FEATURE: + USBD_ClrFeature (pdev , req); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + + return ret; +} + +/** +* @brief USBD_StdItfReq +* Handle standard usb interface requests +* @param pdev: USB OTG device instance +* @param req: usb request +* @retval status +*/ +USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) +{ + USBD_StatusTypeDef ret = USBD_OK; + + switch (pdev->dev_state) + { + case USBD_STATE_CONFIGURED: + + if (LOBYTE(req->wIndex) <= USBD_MAX_NUM_INTERFACES) + { + pdev->pClass->Setup (pdev, req); + + if((req->wLength == 0)&& (ret == USBD_OK)) + { + USBD_CtlSendStatus(pdev); + } + } + else + { + USBD_CtlError(pdev , req); + } + break; + + default: + USBD_CtlError(pdev , req); + break; + } + return USBD_OK; +} + +/** +* @brief USBD_StdEPReq +* Handle standard usb endpoint requests +* @param pdev: USB OTG device instance +* @param req: usb request +* @retval status +*/ +USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) +{ + + uint8_t ep_addr; + USBD_StatusTypeDef ret = USBD_OK; + USBD_EndpointTypeDef *pep; + ep_addr = LOBYTE(req->wIndex); + + switch (req->bRequest) + { + + case USB_REQ_SET_FEATURE : + + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + USBD_LL_StallEP(pdev , ep_addr); + } + break; + + case USBD_STATE_CONFIGURED: + if (req->wValue == USB_FEATURE_EP_HALT) + { + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + USBD_LL_StallEP(pdev , ep_addr); + + } + } + pdev->pClass->Setup (pdev, req); + USBD_CtlSendStatus(pdev); + + break; + + default: + USBD_CtlError(pdev , req); + break; + } + break; + + case USB_REQ_CLEAR_FEATURE : + + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + USBD_LL_StallEP(pdev , ep_addr); + } + break; + + case USBD_STATE_CONFIGURED: + if (req->wValue == USB_FEATURE_EP_HALT) + { + if ((ep_addr & 0x7F) != 0x00) + { + USBD_LL_ClearStallEP(pdev , ep_addr); + pdev->pClass->Setup (pdev, req); + } + USBD_CtlSendStatus(pdev); + } + break; + + default: + USBD_CtlError(pdev , req); + break; + } + break; + + case USB_REQ_GET_STATUS: + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if ((ep_addr & 0x7F) != 0x00) + { + USBD_LL_StallEP(pdev , ep_addr); + } + break; + + case USBD_STATE_CONFIGURED: + pep = ((ep_addr & 0x80) == 0x80) ? &pdev->ep_in[ep_addr & 0x7F]:\ + &pdev->ep_out[ep_addr & 0x7F]; + if(USBD_LL_IsStallEP(pdev, ep_addr)) + { + pep->status = 0x0001; + } + else + { + pep->status = 0x0000; + } + + USBD_CtlSendData (pdev, + (uint8_t *)&pep->status, + 2); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + break; + + default: + break; + } + return ret; +} +/** +* @brief USBD_GetDescriptor +* Handle Get Descriptor requests +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + uint16_t len; + uint8_t *pbuf; + + + switch (req->wValue >> 8) + { + case USB_DESC_TYPE_DEVICE: + pbuf = pdev->pDesc->GetDeviceDescriptor(pdev->dev_speed, &len); + break; + + case USB_DESC_TYPE_CONFIGURATION: + if(pdev->dev_speed == USBD_SPEED_HIGH ) + { + pbuf = (uint8_t *)pdev->pClass->GetHSConfigDescriptor(&len); + pbuf[1] = USB_DESC_TYPE_CONFIGURATION; + } + else + { + pbuf = (uint8_t *)pdev->pClass->GetFSConfigDescriptor(&len); + pbuf[1] = USB_DESC_TYPE_CONFIGURATION; + } + break; + + case USB_DESC_TYPE_STRING: + switch ((uint8_t)(req->wValue)) + { + case USBD_IDX_LANGID_STR: + pbuf = pdev->pDesc->GetLangIDStrDescriptor(pdev->dev_speed, &len); + break; + + case USBD_IDX_MFC_STR: + pbuf = pdev->pDesc->GetManufacturerStrDescriptor(pdev->dev_speed, &len); + break; + + case USBD_IDX_PRODUCT_STR: + pbuf = pdev->pDesc->GetProductStrDescriptor(pdev->dev_speed, &len); + break; + + case USBD_IDX_SERIAL_STR: + pbuf = pdev->pDesc->GetSerialStrDescriptor(pdev->dev_speed, &len); + break; + + case USBD_IDX_CONFIG_STR: + pbuf = pdev->pDesc->GetConfigurationStrDescriptor(pdev->dev_speed, &len); + break; + + case USBD_IDX_INTERFACE_STR: + pbuf = pdev->pDesc->GetInterfaceStrDescriptor(pdev->dev_speed, &len); + break; + + default: +#if (USBD_SUPPORT_USER_STRING == 1) + pbuf = pdev->pClass->GetUsrStrDescriptor(pdev, (req->wValue) , &len); + break; +#else + USBD_CtlError(pdev , req); + return; +#endif + } + break; + case USB_DESC_TYPE_DEVICE_QUALIFIER: + + if(pdev->dev_speed == USBD_SPEED_HIGH ) + { + pbuf = (uint8_t *)pdev->pClass->GetDeviceQualifierDescriptor(&len); + break; + } + else + { + USBD_CtlError(pdev , req); + return; + } + + case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION: + if(pdev->dev_speed == USBD_SPEED_HIGH ) + { + pbuf = (uint8_t *)pdev->pClass->GetOtherSpeedConfigDescriptor(&len); + pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION; + break; + } + else + { + USBD_CtlError(pdev , req); + return; + } + + default: + USBD_CtlError(pdev , req); + return; + } + + if((len != 0)&& (req->wLength != 0)) + { + + len = MIN(len , req->wLength); + + USBD_CtlSendData (pdev, + pbuf, + len); + } + +} + +/** +* @brief USBD_SetAddress +* Set device address +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetAddress(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + uint8_t dev_addr; + + if ((req->wIndex == 0) && (req->wLength == 0)) + { + dev_addr = (uint8_t)(req->wValue) & 0x7F; + + if (pdev->dev_state == USBD_STATE_CONFIGURED) + { + USBD_CtlError(pdev , req); + } + else + { + pdev->dev_address = dev_addr; + USBD_LL_SetUSBAddress(pdev, dev_addr); + USBD_CtlSendStatus(pdev); + + if (dev_addr != 0) + { + pdev->dev_state = USBD_STATE_ADDRESSED; + } + else + { + pdev->dev_state = USBD_STATE_DEFAULT; + } + } + } + else + { + USBD_CtlError(pdev , req); + } +} + +/** +* @brief USBD_SetConfig +* Handle Set device configuration request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + static uint8_t cfgidx; + + cfgidx = (uint8_t)(req->wValue); + + if (cfgidx > USBD_MAX_NUM_CONFIGURATION ) + { + USBD_CtlError(pdev , req); + } + else + { + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if (cfgidx) + { + pdev->dev_config = cfgidx; + pdev->dev_state = USBD_STATE_CONFIGURED; + if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL) + { + USBD_CtlError(pdev , req); + return; + } + USBD_CtlSendStatus(pdev); + } + else + { + USBD_CtlSendStatus(pdev); + } + break; + + case USBD_STATE_CONFIGURED: + if (cfgidx == 0) + { + pdev->dev_state = USBD_STATE_ADDRESSED; + pdev->dev_config = cfgidx; + USBD_ClrClassConfig(pdev , cfgidx); + USBD_CtlSendStatus(pdev); + + } + else if (cfgidx != pdev->dev_config) + { + /* Clear old configuration */ + USBD_ClrClassConfig(pdev , pdev->dev_config); + + /* set new configuration */ + pdev->dev_config = cfgidx; + if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL) + { + USBD_CtlError(pdev , req); + return; + } + USBD_CtlSendStatus(pdev); + } + else + { + USBD_CtlSendStatus(pdev); + } + break; + + default: + USBD_CtlError(pdev , req); + break; + } + } +} + +/** +* @brief USBD_GetConfig +* Handle Get device configuration request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + if (req->wLength != 1) + { + USBD_CtlError(pdev , req); + } + else + { + switch (pdev->dev_state ) + { + case USBD_STATE_ADDRESSED: + pdev->dev_default_config = 0; + USBD_CtlSendData (pdev, + (uint8_t *)&pdev->dev_default_config, + 1); + break; + + case USBD_STATE_CONFIGURED: + + USBD_CtlSendData (pdev, + (uint8_t *)&pdev->dev_config, + 1); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + } +} + +/** +* @brief USBD_GetStatus +* Handle Get Status request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetStatus(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + case USBD_STATE_CONFIGURED: + +#if ( USBD_SELF_POWERED == 1) + pdev->dev_config_status = USB_CONFIG_SELF_POWERED; +#else + pdev->dev_config_status = 0; +#endif + + if (pdev->dev_remote_wakeup) + { + pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP; + } + + USBD_CtlSendData (pdev, + (uint8_t *)& pdev->dev_config_status, + 2); + break; + + default : + USBD_CtlError(pdev , req); + break; + } +} + + +/** +* @brief USBD_SetFeature +* Handle Set device feature request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) + { + pdev->dev_remote_wakeup = 1; + pdev->pClass->Setup (pdev, req); + USBD_CtlSendStatus(pdev); + } + +} + + +/** +* @brief USBD_ClrFeature +* Handle clear device feature request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_ClrFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + case USBD_STATE_CONFIGURED: + if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) + { + pdev->dev_remote_wakeup = 0; + pdev->pClass->Setup (pdev, req); + USBD_CtlSendStatus(pdev); + } + break; + + default : + USBD_CtlError(pdev , req); + break; + } +} + +/** +* @brief USBD_ParseSetupRequest +* Copy buffer into setup structure +* @param pdev: device instance +* @param req: usb request +* @retval None +*/ + +void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata) +{ + req->bmRequest = *(uint8_t *) (pdata); + req->bRequest = *(uint8_t *) (pdata + 1); + req->wValue = SWAPBYTE (pdata + 2); + req->wIndex = SWAPBYTE (pdata + 4); + req->wLength = SWAPBYTE (pdata + 6); + +} + +/** +* @brief USBD_CtlError +* Handle USB low level Error +* @param pdev: device instance +* @param req: usb request +* @retval None +*/ + +void USBD_CtlError( USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + USBD_LL_StallEP(pdev , 0x80); + USBD_LL_StallEP(pdev , 0); +} + + +/** + * @brief USBD_GetString + * Convert Ascii string into unicode one + * @param desc : descriptor buffer + * @param unicode : Formatted string buffer (unicode) + * @param len : descriptor length + * @retval None + */ +void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len) +{ + uint8_t idx = 0; + + if (desc != NULL) + { + *len = USBD_GetLen(desc) * 2 + 2; + unicode[idx++] = *len; + unicode[idx++] = USB_DESC_TYPE_STRING; + + while (*desc != '\0') + { + unicode[idx++] = *desc++; + unicode[idx++] = 0x00; + } + } +} + +/** + * @brief USBD_GetLen + * return the string length + * @param buf : pointer to the ascii string buffer + * @retval string length + */ +static uint8_t USBD_GetLen(uint8_t *buf) +{ + uint8_t len = 0; + + while (*buf != '\0') + { + len++; + buf++; + } + + return len; +} +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/webcam/src/usbd_desc.c b/src/webcam/src/usbd_desc.c new file mode 100644 index 000000000..30d43f928 --- /dev/null +++ b/src/webcam/src/usbd_desc.c @@ -0,0 +1,214 @@ +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Src/usbd_desc.c + * @author MCD Application Team + * @version V1.2.2 + * @date 25-May-2015 + * @brief This file provides the USBD descriptors and string formating method. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_core.h" +#include "usbd_desc.h" +#include "usbd_conf.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +#define USBD_VID 0x1209 +#define USBD_PID 0xabd1 +#define USBD_LANGID_STRING 0x409 +#define USBD_MANUFACTURER_STRING "OpenMV" +#define USBD_PRODUCT_HS_STRING "OpenMV UVC in HS Mode" +#define USBD_SERIALNUMBER_HS_STRING "000000000010" +#define USBD_PRODUCT_FS_STRING "OpenMV UVC in FS Mode" +#define USBD_SERIALNUMBER_FS_STRING "000000000011" +#define USBD_CONFIGURATION_HS_STRING "UVC Config" +#define USBD_INTERFACE_HS_STRING "UVC Interface" +#define USBD_CONFIGURATION_FS_STRING "UVC Config" +#define USBD_INTERFACE_FS_STRING "UVC Interface" + + +/* Private macro -------------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +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 */ + +/* Private variables ---------------------------------------------------------*/ +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, +}; + +/* USB Standard Device Descriptor */ +#if defined ( __ICCARM__ ) /*!< IAR Compiler */ + #pragma data_alignment=4 +#endif +__ALIGN_BEGIN uint8_t USBD_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = { + 0x12, /* bLength */ + USB_DESC_TYPE_DEVICE, /* bDescriptorType */ + 0x00, /* bcdUSB */ + 0x02, + 0xef, /* bDeviceClass */ + 0x02, /* bDeviceSubClass */ + 0x01, /* bDeviceProtocol */ + USB_MAX_EP0_SIZE, /* bMaxPacketSize */ + LOBYTE(USBD_VID), /* idVendor */ + HIBYTE(USBD_VID), /* idVendor */ + LOBYTE(USBD_PID), /* idVendor */ + HIBYTE(USBD_PID), /* 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 */ + +/* USB Standard Device Descriptor */ +#if defined ( __ICCARM__ ) /*!< IAR Compiler */ + #pragma data_alignment=4 +#endif +__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; + +/** + * @brief Returns 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_DeviceDesc); + return (uint8_t*)USBD_DeviceDesc; +} + +/** + * @brief Returns 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 (uint8_t*)USBD_LangIDDesc; +} + +/** + * @brief Returns 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) +{ + if(speed == 0) { + USBD_GetString((uint8_t *)USBD_PRODUCT_HS_STRING, USBD_StrDesc, length); + } else { + USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** + * @brief Returns 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((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length); + return USBD_StrDesc; +} + +/** + * @brief Returns 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) +{ + if(speed == USBD_SPEED_HIGH) { + USBD_GetString((uint8_t *)USBD_SERIALNUMBER_HS_STRING, USBD_StrDesc, length); + } else { + USBD_GetString((uint8_t *)USBD_SERIALNUMBER_FS_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** + * @brief Returns 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) +{ + if(speed == USBD_SPEED_HIGH) { + USBD_GetString((uint8_t *)USBD_CONFIGURATION_HS_STRING, USBD_StrDesc, length); + } else { + USBD_GetString((uint8_t *)USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** + * @brief Returns 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) +{ + if(speed == 0) { + USBD_GetString((uint8_t *)USBD_INTERFACE_HS_STRING, USBD_StrDesc, length); + } else { + USBD_GetString((uint8_t *)USBD_INTERFACE_FS_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/webcam/src/usbd_ioreq.c b/src/webcam/src/usbd_ioreq.c new file mode 100644 index 000000000..41d4cbcc9 --- /dev/null +++ b/src/webcam/src/usbd_ioreq.c @@ -0,0 +1,236 @@ +/** + ****************************************************************************** + * @file usbd_ioreq.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides the IO requests APIs for control endpoints. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_ioreq.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup USBD_IOREQ + * @brief control I/O requests module + * @{ + */ + +/** @defgroup USBD_IOREQ_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_FunctionPrototypes + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Functions + * @{ + */ + +/** +* @brief USBD_CtlSendData +* send data on the ctl pipe +* @param pdev: device instance +* @param buff: pointer to data buffer +* @param len: length of data to be sent +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len) +{ + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_DATA_IN; + pdev->ep_in[0].total_length = len; + pdev->ep_in[0].rem_length = len; + /* Start the transfer */ + USBD_LL_Transmit (pdev, 0x00, pbuf, len); + + return USBD_OK; +} + +/** +* @brief USBD_CtlContinueSendData +* continue sending data on the ctl pipe +* @param pdev: device instance +* @param buff: pointer to data buffer +* @param len: length of data to be sent +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len) +{ + /* Start the next transfer */ + USBD_LL_Transmit (pdev, 0x00, pbuf, len); + + return USBD_OK; +} + +/** +* @brief USBD_CtlPrepareRx +* receive data on the ctl pipe +* @param pdev: USB OTG device instance +* @param buff: pointer to data buffer +* @param len: length of data to be received +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len) +{ + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_DATA_OUT; + pdev->ep_out[0].total_length = len; + pdev->ep_out[0].rem_length = len; + /* Start the transfer */ + USBD_LL_PrepareReceive (pdev, + 0, + pbuf, + len); + + return USBD_OK; +} + +/** +* @brief USBD_CtlContinueRx +* continue receive data on the ctl pipe +* @param pdev: USB OTG device instance +* @param buff: pointer to data buffer +* @param len: length of data to be received +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len) +{ + + USBD_LL_PrepareReceive (pdev, + 0, + pbuf, + len); + return USBD_OK; +} +/** +* @brief USBD_CtlSendStatus +* send zero lzngth packet on the ctl pipe +* @param pdev: USB OTG device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev) +{ + + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_STATUS_IN; + + /* Start the transfer */ + USBD_LL_Transmit (pdev, 0x00, NULL, 0); + + return USBD_OK; +} + +/** +* @brief USBD_CtlReceiveStatus +* receive zero lzngth packet on the ctl pipe +* @param pdev: USB OTG device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev) +{ + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_STATUS_OUT; + + /* Start the transfer */ + USBD_LL_PrepareReceive ( pdev, + 0, + NULL, + 0); + + return USBD_OK; +} + + +/** +* @brief USBD_GetRxCount +* returns the received data length +* @param pdev: USB OTG device instance +* epnum: endpoint index +* @retval Rx Data blength +*/ +uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , uint8_t ep_addr) +{ + return USBD_LL_GetRxDataSize(pdev, ep_addr); +} + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/webcam/src/usbd_uvc.c b/src/webcam/src/usbd_uvc.c new file mode 100644 index 000000000..2f634294f --- /dev/null +++ b/src/webcam/src/usbd_uvc.c @@ -0,0 +1,879 @@ +/** + ****************************************************************************** + * @file usbd_cdc.c + * @author MCD Application Team + * @version V2.4.1 + * @date 19-June-2015 + * @brief This file provides the high layer firmware functions to manage the + * following functionalities of the USB UVC Class: + * - Initialization and Configuration of high and low layer + * - Enumeration as UVC Device (and enumeration for each implemented memory interface) + * - OUT/IN data transfer + * - Command IN transfer (class requests management) + * - Error management + * + * @verbatim + * + * =================================================================== + * UVC Class Driver Description + * =================================================================== + * This driver manages the "Universal Serial Bus Class Definitions for Communications Devices + * Revision 1.2 November 16, 2007" and the sub-protocol specification of "Universal Serial Bus + * Communications Class Subclass Specification for PSTN Devices Revision 1.2 February 9, 2007" + * This driver implements the following aspects of the specification: + * - Device descriptor management + * - Configuration descriptor management + * - Enumeration as UVC device with 2 data endpoints (IN and OUT) and 1 command endpoint (IN) + * - Requests management (as described in section 6.2 in specification) + * - Abstract Control Model compliant + * - Union Functional collection (using 1 IN endpoint for control) + * - Data interface class + * + * These aspects may be enriched or modified for a specific user application. + * + * This driver doesn't implement the following aspects of the specification + * (but it is possible to manage these features with some modifications on this driver): + * - Any class-specific aspect relative to communication classes should be managed by user application. + * - All communication classes other than PSTN are not managed + * + * @endverbatim + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_uvc.h" +#include "usbd_desc.h" +#include "usbd_ctlreq.h" +#include "usbd_types.h" +#include "uvc_desc.h" + +static USBD_UVC_HandleTypeDef USBD_UVC_Handle; +volatile uint8_t g_uvc_stream_status = 0; + +static uint8_t USBD_UVC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx); +static uint8_t USBD_UVC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx); +static uint8_t USBD_UVC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); +static uint8_t USBD_UVC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum); +static uint8_t USBD_UVC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum); +static uint8_t USBD_UVC_SOF(USBD_HandleTypeDef *pdev); +static uint8_t USBD_UVC_EP0_RxReady(USBD_HandleTypeDef *pdev); +static uint8_t *USBD_UVC_GetFSCfgDesc(uint16_t *length); +uint8_t *USBD_UVC_GetDeviceQualifierDescriptor(uint16_t *length); + +/* USB Standard Device Descriptor */ +__ALIGN_BEGIN static uint8_t USBD_UVC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = { + USB_LEN_DEV_QUALIFIER_DESC, + USB_DESC_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x40, + 0x01, + 0x00, +}; + +/* UVC interface class callbacks structure */ +USBD_ClassTypeDef USBD_UVC = { + USBD_UVC_Init, + USBD_UVC_DeInit, + USBD_UVC_Setup, + NULL, /* EP0_TxSent, */ + USBD_UVC_EP0_RxReady, + USBD_UVC_DataIn, + USBD_UVC_DataOut, + USBD_UVC_SOF, + NULL, + NULL, + USBD_UVC_GetFSCfgDesc, + USBD_UVC_GetFSCfgDesc, + USBD_UVC_GetFSCfgDesc, + USBD_UVC_GetDeviceQualifierDescriptor, +}; + +/* USB UVC device Configuration Descriptor */ +__ALIGN_BEGIN struct usbd_uvc_cfg USBD_UVC_CfgFSDesc __ALIGN_END = { + /* Configuration 1 */ + .usb_configuration = { + .bLength = USB_LEN_CFG_DESC, // 9 + .bDescriptorType = USB_DESC_TYPE_CONFIGURATION, // 2 + .wTotalLength = sizeof(struct usbd_uvc_cfg), + .bNumInterfaces = 0x02, // 2 + .bConfigurationValue = 0x01, // 1 ID of this configuration + .iConfiguration = 0x00, // 0 no description available + .bmAttributes = USB_CONFIG_BUS_POWERED , // 0x80 Bus Powered + .bMaxPower = USB_CONFIG_POWER_MA(100), // 100 mA + }, + + /*----------------- Video Association (Control + stream) ------------------*/ + + /* Interface Association Descriptor */ + .usb_uvc_association = { + .bLength = USB_DT_INTERFACE_ASSOC_SIZE, // 8 + .bDescriptorType = USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE, // 11 + .bFirstInterface = 0x00, // 0 + .bInterfaceCount = 0x02, // 2 + .bFunctionClass = UVC_CC_VIDEO, // 14 Video + .bFunctionSubClass = UVC_SC_VIDEO_INTERFACE_COLLECTION, // 3 Video Interface Collection + .bFunctionProtocol = UVC_PC_PROTOCOL_UNDEFINED, // 0 (protocol undefined) + .iFunction = 0x02, // 2 + }, + + /*----------------- Video Association (Control + stream) ------------------*/ + + /* Interface Association Descriptor */ + .usb_uvc_association = { + .bLength = USB_DT_INTERFACE_ASSOC_SIZE, // 8 + .bDescriptorType = USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE, // 11 + .bFirstInterface = 0x00, // 0 + .bInterfaceCount = 0x02, // 2 + .bFunctionClass = UVC_CC_VIDEO, // 14 Video + .bFunctionSubClass = UVC_SC_VIDEO_INTERFACE_COLLECTION, // 3 Video Interface Collection + .bFunctionProtocol = UVC_PC_PROTOCOL_UNDEFINED, // 0 (protocol undefined) + .iFunction = 0x02, // 2 + }, + + + /*------------------ VideoControl Interface descriptor --------------------*/ + + /* Standard VC Interface Descriptor = interface 0 */ + .uvc_vc_if_desc = { + .bLength = USB_LEN_IF_DESC, // 9 + .bDescriptorType = USB_DESC_TYPE_INTERFACE, // 4 + .bInterfaceNumber = USB_UVC_VCIF_NUM, // 0 index of this interface (VC) + .bAlternateSetting = 0x00, // 0 index of this setting + .bNumEndpoints = 0x01, // 1 endpoint + .bInterfaceClass = UVC_CC_VIDEO, // 14 Video + .bInterfaceSubClass = UVC_SC_VIDEOCONTROL, // 1 Video Control + .bInterfaceProtocol = UVC_PC_PROTOCOL_UNDEFINED, // 0 (protocol undefined) + .iInterface = 0x00, + }, + + /* Class-specific VC Interface Descriptor */ + .ucv_vc_header = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, ucv_vc_header), + .bDescriptorType = UVC_CS_INTERFACE, // 36 (INTERFACE) + .bDescriptorSubType = UVC_VC_HEADER, // 1 (HEADER) + .bcdUVC = UVC_VERSION, // 1.10 or 1.00 + .wTotalLength = + SIZEOF_M(struct usbd_uvc_cfg, ucv_vc_header) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_input_terminal) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_processing_unit) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_agc) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_oem) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_rad) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_sys) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_vid) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_rad_2) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_cust) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_output_terminal), // header+units+terminals + .dwClockFrequency = 0x005B8D80, // 6.000000 MHz + .bInCollection = 0x01, // 1 one streaming interface + .baInterfaceNr = { 0x01 }, // 1 VS interface 1 belongs to this VC interface + }, + + /* Input Terminal Descriptor (Camera) */ + .uvc_vc_input_terminal = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_input_terminal), // Descriptor size + .bDescriptorType = UVC_CS_INTERFACE, // 36 (INTERFACE) + .bDescriptorSubType = UVC_VC_INPUT_TERMINAL, // 2 (INPUT_TERMINAL) + .bTerminalID = VC_INPUT_TERMINAL_ID, // 1 ID of this Terminal + .wTerminalType = UVC_ITT_CAMERA, // 0x0201 Camera Sensor + .bAssocTerminal = 0x00, // 0 no Terminal associated + .iTerminal = 0x00, // 0 no description available + .wObjectiveFocalLengthMin = 0x0000, // 0 + .wObjectiveFocalLengthMax = 0x0000, // 0 + .wOcularFocalLength = 0x0000, // 0 + .bControlSize = 0x03, // 2 + .bmControls = { 0x00, 0x00, 0x00 }, // 0x0000 no controls supported + }, + + /* Processing Unit Descriptor */ + .uvc_vc_processing_unit = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_processing_unit), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x05, // Processing Unit Descriptor type + .bUnitID = VC_CONTROL_PU_ID, // ID of this terminal + .bSourceID = 0x01, // Source ID : 1 : Connected to input terminal + .wMaxMultiplier = 0, // Digital multiplier + .bControlSize = 0x03, // Size of controls field for this terminal : 2 bytes + .bmControls = { 0x03, 0x00, 0x00 }, // Brightness and contrast + .iProcessing = 0x00, // String desc index : Not used + }, + + /* Extension Unit Descriptor */ + .uvc_vc_xu_lep_agc = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_agc), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_AGC_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 'a','g','c','-', + '0','0','0','0' + }, + .bNumControls = 0x14, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x04, // Size of controls field for this terminal : 1 byte + .bmControls = { 0xff, 0xff, 0x0f, 0x00 }, // Registers 0x00 to 0x48 + .iExtension = 0x00, // String desc index : Not used + }, + + /* Extension Unit Descriptor */ + .uvc_vc_xu_lep_oem = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_oem), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_OEM_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 'o','e','m','-', + '0','0','0','0' + }, + .bNumControls = 0x1e, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x04, // Size of controls field for this terminal : 1 byte + .bmControls = { 0xbf, 0xff, 0xff, 0x7f }, // Registers 0x00 to 0x48 + .iExtension = 0x00, // String desc index : Not used + }, + + /* Extension Unit Descriptor */ + .uvc_vc_xu_lep_rad = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_rad), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_RAD_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 'r','a','d','-', + '0','0','0','0' + }, + .bNumControls = 48, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x08, // Size of controls field for this terminal : 1 byte + .bmControls = { 0xFF, 0xFF, 0xFF, 0x81, 0xFC, 0xCF, 0xFF, 0x03 }, // Registers 0x00 to 0x48 + .iExtension = 0x00, // String desc index : Not used + }, + + /* Extension Unit Descriptor */ + .uvc_vc_xu_lep_rad_2 = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_rad_2), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_RAD_2_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 'r','a','d','2', + '0','0','0','0' + }, + .bNumControls = 27, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x04, // Size of controls field for this terminal : 1 byte + .bmControls = { 0xf9, 0x9f, 0xff, 0x07 }, // Registers 0x00 to 0x48 + .iExtension = 0x00, // String desc index : Not used + }, + + /* Extension Unit Descriptor */ + .uvc_vc_xu_lep_sys = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_sys), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_SYS_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 's','y','s','-', + '0','0','0','0' + }, + .bNumControls = 0x17, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x04, // Size of controls field for this terminal : 1 byte + .bmControls = { 0xFF, 0xFF, 0x7F, 0x00 }, // Registers 0x00 to 0x48 + .iExtension = 0x00, // String desc index : Not used + }, + + /* Extension Unit Descriptor */ + .uvc_vc_xu_lep_vid = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_vid), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_VID_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 'v','i','d','-', + '0','0','0','0' + }, + .bNumControls = 0x0e, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x04, // Size of controls field for this terminal : 1 byte + .bmControls = { 0xFF, 0x3F, 0x00, 0x00 }, // Registers 0x00 to 0x48 + .iExtension = 0x00, // String desc index : Not used + }, + + /* Extension Unit Descriptor */ + .uvc_vc_xu_lep_cust = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vc_xu_lep_cust), // Descriptor size + .bDescriptorType = 0x24, // Class specific interface desc type + .bDescriptorSubType = 0x06, // Extension Unit Descriptor type + .bUnitID = VC_CONTROL_XU_LEP_CUST_ID, // ID of this terminal + .guidExtensionCode = { // 16 byte GUID + 'p','t','1','-', + 'l','e','p','-', + 'c','u','s','t', + '0','0','0','0' + }, + .bNumControls = CUST_CONTROL_END, // Number of controls in this terminal + .bNrInPins = 0x01, // Number of input pins in this terminal + .baSourceID = { 0x02 }, // Source ID : 2 : Connected to Proc Unit + .bControlSize = 0x04, // Size of controls field for this terminal : 1 byte + .bmControls = { (1 << CUST_CONTROL_END) - 1, 0, 0, 0 }, // + .iExtension = 0x00, // String desc index : Not used + }, + + /* Output Terminal Descriptor */ + .uvc_vc_output_terminal = { + .bLength = UVC_DT_OUTPUT_TERMINAL_SIZE, // 9 + .bDescriptorType = UVC_CS_INTERFACE, // 36 (INTERFACE) + .bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL, // 3 (OUTPUT_TERMINAL) + .bTerminalID = VC_OUTPUT_TERMINAL_ID, // 2 ID of this Terminal + .wTerminalType = UVC_TT_STREAMING, // 0x0101 USB streaming terminal + .bAssocTerminal = 0x00, // 0 no Terminal assiciated + .bSourceID = 0x03, // 1 input pin connected to output pin unit 1 + .iTerminal = 0x00, // 0 no description available + }, + + /* Standard Interrupt Endpoint Descriptor */ + .uvc_vc_ep = { + .bLength = USB_DT_ENDPOINT_SIZE, // 7 + .bDescriptorType = USB_DESC_TYPE_ENDPOINT, // 5 (ENDPOINT) + .bEndpointAddress = UVC_CMD_EP, // 0x82 EP 2 IN + .bmAttributes = USBD_EP_TYPE_INTR, // interrupt + .wMaxPacketSize = CMD_PACKET_SIZE, // 8 bytes status + .bInterval = 0x20, // poll at least every 32ms + }, + + /* Class-specific Interrupt Endpoint Descriptor */ + .uvc_vc_cs_ep = { + .bLength = UVC_DT_CONTROL_ENDPOINT_SIZE, + .bDescriptorType = UVC_CS_ENDPOINT, + .bDescriptorSubType = USBD_EP_TYPE_INTR, + .wMaxTransferSize = CMD_PACKET_SIZE, + }, + + /*-------------- Video Streaming (VS) Interface Descriptor ----------------*/ + + /* Standard VS Interface Descriptor = interface 1 */ + // alternate setting 0 = Zero Bandwidth + .uvc_vs_if_alt0_desc = { + .bLength = USB_DT_INTERFACE_SIZE, // 9 + .bDescriptorType = USB_DESC_TYPE_INTERFACE, // 4 + .bInterfaceNumber = USB_UVC_VSIF_NUM, // 1 index of this interface + .bAlternateSetting = 0x00, // 0 index of this setting + .bNumEndpoints = 0x00, // 0 no EP used + .bInterfaceClass = UVC_CC_VIDEO, // 14 Video + .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING, // 2 Video Streaming + .bInterfaceProtocol = UVC_PC_PROTOCOL_UNDEFINED, // 0 (protocol undefined) + .iInterface = 0x00, // 0 no description available + }, + + /* Class-specific VS Header Descriptor (Input) */ + .uvc_vs_input_header_desc = { + .bLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vs_input_header_desc), + .bDescriptorType = UVC_CS_INTERFACE, // 36 (INTERFACE) + .bDescriptorSubType = UVC_VS_INPUT_HEADER, // 1 (INPUT_HEADER) + .bNumFormats = VS_NUM_FORMATS, // number of format descriptors + .wTotalLength = + SIZEOF_M(struct usbd_uvc_cfg, uvc_vs_input_header_desc) + + SIZEOF_M(struct usbd_uvc_cfg, uvc_vs_frames_formats_desc), + .bEndpointAddress = UVC_IN_EP, // 0x83 EP 3 IN + .bmInfo = 0x00, // 0 no dynamic format change supported + .bTerminalLink = VC_OUTPUT_TERMINAL_ID, // 2 supplies terminal ID 2 (Output terminal) + .bStillCaptureMethod = 0x01, // 1 Host captures from video stream + .bTriggerSupport = 0x00, // 0 HW trigger supported for still image capture + .bTriggerUsage = 0x00, // 0 HW trigger initiate a still image capture + .bControlSize = 0x01, // 1 one byte bmaControls field size + .bmaControls = { + { 0x00 }, // bmaControls(0) 0 no VS specific controls + { 0x00 }, // bmaControls(1) 0 no VS specific controls + { 0x00 }, // bmaControls(2) 0 no VS specific controls + }, + }, + + .uvc_vs_frames_formats_desc = { + .uvc_vs_frames_format_1 = + { + .uvc_vs_format = UVC_FORMAT_UNCOMPRESSED_DESCRIPTOR(YUYV, 3), + .uvc_vs_frame = { UVC_FRAME_FORMAT(VS_FRAME_INDEX_1, YUYV, 80, 60), + UVC_FRAME_FORMAT(VS_FRAME_INDEX_2, YUYV, 160, 120), + UVC_FRAME_FORMAT(VS_FRAME_INDEX_3, YUYV, 320, 240)}, + .uvc_vs_color = UVC_COLOR_MATCHING_DESCRIPTOR(), + }, + .uvc_vs_frames_format_2 = + { + .uvc_vs_format = UVC_FORMAT_UNCOMPRESSED_DESCRIPTOR(GREY, 4), + .uvc_vs_frame = { UVC_FRAME_FORMAT(VS_FRAME_INDEX_1, GREY, 80, 60), + UVC_FRAME_FORMAT(VS_FRAME_INDEX_2, GREY, 160, 120), + UVC_FRAME_FORMAT(VS_FRAME_INDEX_3, GREY, 320, 240), + UVC_FRAME_FORMAT(VS_FRAME_INDEX_4, GREY, 640, 480)}, + .uvc_vs_color = UVC_COLOR_MATCHING_DESCRIPTOR(), + }, + .uvc_vs_frames_format_3 = + { + .uvc_vs_format = UVC_FORMAT_UNCOMPRESSED_DESCRIPTOR(RGB565, 3), + .uvc_vs_frame = { UVC_FRAME_FORMAT(VS_FRAME_INDEX_1, RGB565, 80, 60), + UVC_FRAME_FORMAT(VS_FRAME_INDEX_2, RGB565, 160, 120), + UVC_FRAME_FORMAT(VS_FRAME_INDEX_3, RGB565, 320, 240)}, + .uvc_vs_color = UVC_COLOR_MATCHING_DESCRIPTOR(), + }, + }, + + /* Standard VS Interface Descriptor = interface 1 */ + // alternate setting 1 = operational setting + .uvc_vs_if_alt1_desc = { + .bLength = USB_DT_INTERFACE_SIZE, // 9 + .bDescriptorType = USB_DESC_TYPE_INTERFACE, // 4 + .bInterfaceNumber = USB_UVC_VSIF_NUM, // 1 index of this interface + .bAlternateSetting = 0x01, // 1 index of this setting + .bNumEndpoints = 0x01, // 1 one EP used + .bInterfaceClass = UVC_CC_VIDEO, // 14 Video + .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING, // 2 Video Streaming + .bInterfaceProtocol = UVC_PC_PROTOCOL_UNDEFINED, // 0 (protocol undefined) + .iInterface = 0x00, // 0 no description available + }, + + /* Standard VS Isochronous Video data Endpoint Descriptor */ + .uvc_vs_if_alt1_ep = { + .bLength = USB_DT_ENDPOINT_SIZE, // 7 + .bDescriptorType = USB_DESC_TYPE_ENDPOINT, // 5 (ENDPOINT) + .bEndpointAddress = UVC_IN_EP, // 0x83 EP 3 IN + .bmAttributes = USBD_EP_TYPE_ISOC, // 1 isochronous transfer type + .wMaxPacketSize = VIDEO_PACKET_SIZE, + .bInterval = 0x01, // 1 one frame interval + }, + +}; + +/** + * @brief USBD_UVC_Init + * Initialize the UVC interface + * @param pdev: device instance + * @param cfgidx: Configuration index + * @retval status + */ +static uint8_t USBD_UVC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) +{ + uint8_t ret = 0; + USBD_UVC_HandleTypeDef *hcdc; + + /* Open EP IN */ + USBD_LL_OpenEP(pdev, + UVC_IN_EP, + USBD_EP_TYPE_ISOC, + VIDEO_PACKET_SIZE); + + USBD_LL_OpenEP(pdev, + UVC_CMD_EP, + USBD_EP_TYPE_INTR, + CMD_PACKET_SIZE); + + + pdev->pClassData = &USBD_UVC_Handle; + hcdc = (USBD_UVC_HandleTypeDef*) pdev->pClassData; + + /* Init physical Interface components */ + ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->Init(); + + /* Init Xfer states */ + hcdc->TxState =0; + hcdc->RxState =0; + return ret; +} + +/** + * @brief USBD_UVC_Init + * DeInitialize the UVC layer + * @param pdev: device instance + * @param cfgidx: Configuration index + * @retval status + */ +static uint8_t USBD_UVC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) +{ + uint8_t ret = 0; + + /* Open EP IN */ + USBD_LL_CloseEP(pdev, UVC_IN_EP); + + USBD_LL_CloseEP(pdev, UVC_CMD_EP); + + /* DeInit physical Interface components */ + if(pdev->pClassData != NULL) { + ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->DeInit(); + //USBD_free(pdev->pClassData); //TODO + pdev->pClassData = NULL; + } + + return ret; +} + +/** + * @brief USBD_UVC_Setup + * Handle the UVC specific requests + * @param pdev: instance + * @param req: usb requests + * @retval status + */ +static uint8_t USBD_UVC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) +{ + uint8_t ret = USBD_OK; + static uint8_t ifalt = 0; + USBD_UVC_HandleTypeDef *hcdc = (USBD_UVC_HandleTypeDef*) pdev->pClassData; + + switch (req->bmRequest & USB_REQ_TYPE_MASK) { + case USB_REQ_TYPE_CLASS : + if (req->wLength) { + // TODO: what to do with recipient as endpoint? + uint8_t address = (req->wIndex >> 0) & 0xff; + VC_TERMINAL_ID entity_id = (VC_TERMINAL_ID)((req->wIndex >> 8) & 0xff); + if (req->bmRequest & USB_REQ_READ_MASK) { + USBD_LL_FlushEP (pdev,USB_ENDPOINT_OUT(0)); + if (address == USB_UVC_VSIF_NUM) { + ret = ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->VS_CtrlGet(req->bRequest, + (uint8_t *)hcdc->data, req->wLength, req->wIndex, req->wValue); + } else { + ret = ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->ControlGet(entity_id, req->bRequest, + (uint8_t *)hcdc->data, req->wLength, req->wIndex, req->wValue); + } + + if (ret == USBD_OK) { + USBD_CtlSendData (pdev, (uint8_t *)hcdc->data, req->wLength); + } else { + USBD_CtlError (pdev, req); + } + } else { + hcdc->CmdOpCode = req->bRequest; + hcdc->CmdLength = req->wLength; + hcdc->CmdIndex = req->wIndex; + hcdc->CmdValue = req->wValue; + USBD_CtlPrepareRx (pdev, (uint8_t *)hcdc->data, req->wLength); + } + } else { + ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->Control(req->bRequest, (uint8_t*)req, 0, 0, 0); + } + break; + + case USB_REQ_TYPE_STANDARD: + switch (req->bRequest) { + case USB_REQ_GET_DESCRIPTOR: + if( (req->wValue >> 8) == UVC_CS_DEVICE) { + USBD_CtlSendData (pdev, (uint8_t *)&USBD_UVC_CfgFSDesc.uvc_vc_if_desc, MIN(sizeof(USBD_UVC_CfgFSDesc), req->wLength)); + } else { + USBD_CtlSendData (pdev, (uint8_t *)hcdc->data, req->wLength); + } + break; + + case USB_REQ_GET_INTERFACE : + USBD_CtlSendData (pdev, &ifalt, 1); + break; + + case USB_REQ_SET_INTERFACE : + if ((uint8_t)(req->wValue) < VIDEO_TOTAL_IF_NUM) { + ifalt = (uint8_t)(req->wValue); + // TODO: refactor this to callback user code instead of doing this here + if (ifalt == 1) { + g_uvc_stream_status = 1; + } else { + g_uvc_stream_status = 0; + } + } else { + /* Call the error management function (command will be nacked */ + USBD_CtlError (pdev, req); + return USBD_FAIL; + } + break; + default: + return USBD_FAIL; + } + break; + + default: + return USBD_FAIL; + break; + } + return ret; +} + +/** + * @brief USBD_UVC_DataIn + * Data sent on non-control IN endpoint + * @param pdev: device instance + * @param epnum: endpoint number + * @retval status + */ +static uint8_t USBD_UVC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + USBD_UVC_HandleTypeDef *hcdc = (USBD_UVC_HandleTypeDef*) pdev->pClassData; + + if(pdev->pClassData != NULL) { + hcdc->TxState = 0; + return USBD_OK; + } else { + return USBD_FAIL; + } +} + +/** + * @brief USBD_UVC_DataOut + * Data received on non-control Out endpoint + * @param pdev: device instance + * @param epnum: endpoint number + * @retval status + */ +static uint8_t USBD_UVC_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + USBD_UVC_HandleTypeDef *hcdc = (USBD_UVC_HandleTypeDef*) pdev->pClassData; + + /* Get the received data length */ + hcdc->RxLength = USBD_LL_GetRxDataSize (pdev, epnum); + + /* USB data will be immediately processed, this allow next USB traffic being + NAKed till the end of the application Xfer */ + if(pdev->pClassData != NULL) { + ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->Receive(hcdc->RxBuffer, &hcdc->RxLength); + return USBD_OK; + } else { + return USBD_FAIL; + } +} + +static uint8_t USBD_UVC_SOF (USBD_HandleTypeDef *pdev) +{ + if (g_uvc_stream_status == 1) { + USBD_LL_FlushEP(pdev, USB_ENDPOINT_IN(1)); + USBD_LL_Transmit(pdev, USB_ENDPOINT_IN(1), (uint8_t*)0x0002, 2);//header + g_uvc_stream_status = 2; + } + return USBD_OK; +} + + +/** + * @brief USBD_UVC_DataOut + * Data received on non-control Out endpoint + * @param pdev: device instance + * @param epnum: endpoint number + * @retval status + */ +static uint8_t USBD_UVC_EP0_RxReady (USBD_HandleTypeDef *pdev) +{ + uint8_t ret = USBD_OK; + USBD_UVC_HandleTypeDef *hcdc = (USBD_UVC_HandleTypeDef*) pdev->pClassData; + + if((pdev->pUserData != NULL) && (hcdc->CmdOpCode != 0xFF)) + { + uint8_t address = (hcdc->CmdIndex >> 0) & 0xff; + uint8_t entity_id = (hcdc->CmdIndex >> 8) & 0xff; + + if (address == USB_UVC_VSIF_NUM) { + ret = ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->VS_CtrlSet(hcdc->CmdOpCode, + (uint8_t *)hcdc->data, hcdc->CmdLength, hcdc->CmdIndex, hcdc->CmdValue); + } else { + ret = ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->ControlSet(entity_id, hcdc->CmdOpCode, + (uint8_t *)hcdc->data, hcdc->CmdLength, hcdc->CmdIndex, hcdc->CmdValue); + } + + hcdc->CmdOpCode = 0xFF; + } + return ret; +} + +/** + * @brief USBD_UVC_GetFSCfgDesc + * Return configuration descriptor + * @param speed : current device speed + * @param length : pointer data length + * @retval pointer to descriptor buffer + */ +static uint8_t *USBD_UVC_GetFSCfgDesc (uint16_t *length) +{ + *length = sizeof(USBD_UVC_CfgFSDesc); + return (uint8_t*)&USBD_UVC_CfgFSDesc; +} + +/** +* @brief DeviceQualifierDescriptor +* return Device Qualifier descriptor +* @param length : pointer data length +* @retval pointer to descriptor buffer +*/ +uint8_t *USBD_UVC_GetDeviceQualifierDescriptor (uint16_t *length) +{ + *length = sizeof (USBD_UVC_DeviceQualifierDesc); + return USBD_UVC_DeviceQualifierDesc; +} + +/** +* @brief USBD_UVC_RegisterInterface + * @param pdev: device instance + * @param fops: CD Interface callback + * @retval status + */ +uint8_t USBD_UVC_RegisterInterface (USBD_HandleTypeDef *pdev, USBD_UVC_ItfTypeDef *fops) +{ + uint8_t ret = USBD_FAIL; + if(fops != NULL) { + pdev->pUserData= fops; + ret = USBD_OK; + } + return ret; +} + +/** + * @brief USBD_UVC_SetTxBuffer + * @param pdev: device instance + * @param pbuff: Tx Buffer + * @retval status + */ +uint8_t USBD_UVC_SetTxBuffer (USBD_HandleTypeDef *pdev, + uint8_t *pbuff, + uint16_t length) +{ + USBD_UVC_HandleTypeDef *hcdc = (USBD_UVC_HandleTypeDef*) pdev->pClassData; + + hcdc->TxBuffer = pbuff; + hcdc->TxLength = length; + + return USBD_OK; +} + + +/** + * @brief USBD_UVC_SetRxBuffer + * @param pdev: device instance + * @param pbuff: Rx Buffer + * @retval status + */ +uint8_t USBD_UVC_SetRxBuffer (USBD_HandleTypeDef *pdev, + uint8_t *pbuff) +{ + USBD_UVC_HandleTypeDef *hcdc = (USBD_UVC_HandleTypeDef*) pdev->pClassData; + + hcdc->RxBuffer = pbuff; + + return USBD_OK; +} + +/** + * @brief USBD_UVC_DataOut + * Data received on non-control Out endpoint + * @param pdev: device instance + * @param epnum: endpoint number + * @retval status + */ +uint8_t USBD_UVC_TransmitPacket(USBD_HandleTypeDef *pdev) +{ + USBD_UVC_HandleTypeDef *hcdc = (USBD_UVC_HandleTypeDef*) pdev->pClassData; + + if(pdev->pClassData != NULL) + { + if(hcdc->TxState == 0) + { + /* Tx Transfer in progress */ + hcdc->TxState = 1; + + /* Transmit next packet */ + USBD_LL_Transmit(pdev, + UVC_IN_EP, + hcdc->TxBuffer, + hcdc->TxLength); + + return USBD_OK; + } + else + { + return USBD_BUSY; + } + } + else + { + return USBD_FAIL; + } +} + + +/** + * @brief USBD_UVC_ReceivePacket + * prepare OUT Endpoint for reception + * @param pdev: device instance + * @retval status + */ +uint8_t USBD_UVC_ReceivePacket(USBD_HandleTypeDef *pdev) +{ + /* Suspend or Resume USB Out process */ + if(pdev->pClassData != NULL) + { + /* Prepare Out endpoint to receive next packet */ + // USBD_LL_PrepareReceive(pdev, + // UVC_OUT_EP, + // hcdc->RxBuffer, + // UVC_DATA_FS_OUT_PACKET_SIZE); + return USBD_OK; + } + else + { + return USBD_FAIL; + } +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/webcam/src/usbd_uvc_if.c b/src/webcam/src/usbd_uvc_if.c new file mode 100644 index 000000000..e1c8fb8a4 --- /dev/null +++ b/src/webcam/src/usbd_uvc_if.c @@ -0,0 +1,398 @@ +/** + ****************************************************************************** + * @file : usbd_cdc_if.c + * @brief : + ****************************************************************************** + * 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. + * + ****************************************************************************** +*/ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_uvc_if.h" +#include "uvc_desc.h" + +/* Define size for the receive and transmit buffer over UVC */ +/* It's up to user to redefine and/or remove those define */ +#define APP_RX_DATA_SIZE 1024 +#define APP_TX_DATA_SIZE 1024 + +/* Create buffer for reception and transmission */ +/* It's up to user to redefine and/or remove those define */ +/* Received Data over USB are stored in this buffer */ +uint8_t UserRxBufferFS[APP_RX_DATA_SIZE]; + +/* Send Data over USB UVC are stored in this buffer */ +uint8_t UserTxBufferFS[APP_TX_DATA_SIZE]; + +/* USB handle declaration */ +USBD_HandleTypeDef *hUsbDevice_0; + +extern USBD_HandleTypeDef hUsbDeviceFS; + +//data array for Video Probe and Commit +__ALIGN_BEGIN struct uvc_streaming_control videoCommitControl __ALIGN_END = +{ + .bmHint = 0x00, + .bFormatIndex = VS_FMT_INDEX(YUYV), + .bFrameIndex = 0x01, + .dwFrameInterval = 0, + .wKeyFrameRate = 0, + .wPFrameRate = 0, + .wCompQuality = 0, + .wCompWindowSize = 0, + .wDelay = 0, + .dwMaxVideoFrameSize = MAX_FRAME_SIZE(640, 480, 8), + .dwMaxPayloadTransferSize = VIDEO_PACKET_SIZE, + .dwClockFrequency = 0, + .bmFramingInfo = 0, + .bPreferedVersion = 0, + .bMinVersion = 0, + .bMaxVersion = 0, +}; + +__ALIGN_BEGIN struct uvc_streaming_control videoProbeControl __ALIGN_END = +{ + .bmHint = 0x00, + .bFormatIndex = VS_FMT_INDEX(YUYV), + .bFrameIndex = 0x01, + .dwFrameInterval = 0, + .wKeyFrameRate = 0, + .wPFrameRate = 0, + .wCompQuality = 0, + .wCompWindowSize = 0, + .wDelay = 0, + .dwMaxVideoFrameSize = MAX_FRAME_SIZE(640, 480, 8), + .dwMaxPayloadTransferSize = VIDEO_PACKET_SIZE, + .dwClockFrequency = 0, + .bmFramingInfo = 0, + .bPreferedVersion = 0, + .bMinVersion = 0, + .bMaxVersion = 0, +}; + +static int8_t UVC_Init_FS (void); +static int8_t UVC_DeInit_FS (void); +static int8_t UVC_Control (uint8_t cmd, uint8_t* pbuf, uint16_t length, uint16_t index, uint16_t value); +static int8_t UVC_VC_ControlGet (VC_TERMINAL_ID entity_id, + uint8_t cmd, uint8_t* pbuf, uint16_t length, uint16_t index, uint16_t value); +static int8_t UVC_VC_ControlSet (VC_TERMINAL_ID entity_id, + uint8_t cmd, uint8_t* pbuf, uint16_t length, uint16_t index, uint16_t value); +static int8_t UVC_VS_ControlGet(uint8_t cmd, uint8_t* pbuf, uint16_t length, uint16_t index, uint16_t value); +static int8_t UVC_VS_ControlSet(uint8_t cmd, uint8_t* pbuf, uint16_t length, uint16_t index, uint16_t value); +static int8_t UVC_Receive_FS (uint8_t* pbuf, uint32_t *Len); + +USBD_UVC_ItfTypeDef USBD_Interface_fops_FS = { + .Init = UVC_Init_FS, + .DeInit = UVC_DeInit_FS, + .Control = UVC_Control, + .VS_CtrlGet = UVC_VS_ControlGet, + .VS_CtrlSet = UVC_VS_ControlSet, + .ControlGet = UVC_VC_ControlGet, + .ControlSet = UVC_VC_ControlSet, + .Receive = UVC_Receive_FS, +}; + +/** + * @brief UVC_Init_FS + * Initializes the UVC media low layer over the FS USB IP + * @param None + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t UVC_Init_FS(void) +{ + hUsbDevice_0 = &hUsbDeviceFS; + /* Set Application Buffers */ + USBD_UVC_SetTxBuffer(hUsbDevice_0, UserTxBufferFS, 0); + USBD_UVC_SetRxBuffer(hUsbDevice_0, UserRxBufferFS); + return (USBD_OK); +} + +/** + * @brief UVC_DeInit_FS + * DeInitializes the UVC media low layer + * @param None + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t UVC_DeInit_FS(void) +{ + return (USBD_OK); +} + +static int8_t UVC_Control(uint8_t cmd, uint8_t* pbuf, uint16_t length, uint16_t idx, uint16_t value) +{ + return USBD_OK; +} + +/** + * @brief UVC_Control_FS + * Manage the UVC class requests + * @param cmd: Command code + * @param pbuf: Buffer containing command data (request parameters) + * @param length: Number of data to be sent (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t UVC_VC_ControlGet(VC_TERMINAL_ID entity_id, uint8_t cmd, uint8_t* pbuf, uint16_t length, uint16_t idx, uint16_t value) +{ + uint8_t cs_value = (value >> 8) & 0xFF; + (void) cs_value; //TODO + + switch (entity_id) { + case VC_CONTROL_XU_LEP_AGC_ID: + case VC_CONTROL_XU_LEP_OEM_ID: + case VC_CONTROL_XU_LEP_RAD_ID: + case VC_CONTROL_XU_LEP_RAD_2_ID: + case VC_CONTROL_XU_LEP_SYS_ID: + case VC_CONTROL_XU_LEP_VID_ID: + case VC_CONTROL_XU_LEP_CUST_ID: + memset(pbuf, 0, length); + switch (cmd) { + case UVC_GET_DEF: + case UVC_GET_MIN: + break; + case UVC_GET_CUR: + if (length > 1) { + //VC_LEP_GetAttribute(entity_id, (cs_value - 1) << 2, pbuf, length); + } + break; + case UVC_GET_MAX: + //VC_LEP_GetMaxValue(entity_id, (cs_value - 1) << 2, pbuf, length); + break; + case UVC_GET_RES: + pbuf[0] = 1; + break; + case UVC_GET_LEN: + //VC_LEP_GetAttributeLen(entity_id, (cs_value - 1) << 2, (uint16_t*)pbuf); + break; + case UVC_GET_INFO: + pbuf[0] = UVC_CONTROL_CAP_GET | UVC_CONTROL_CAP_SET; + break; + default: + return USBD_FAIL; + } + + break; + + case VC_CONTROL_PU_ID: + switch (cmd) { + case UVC_GET_MIN: + pbuf[0] = 0; + break; + case UVC_GET_DEF: + case UVC_GET_CUR: + pbuf[0] = 128; + break; + case UVC_GET_MAX: + pbuf[0] = 255; + break; + case UVC_GET_RES: + pbuf[0] = 1; + break; + case UVC_GET_LEN: + pbuf[0] = 2; + break; + case UVC_GET_INFO: + pbuf[0] = UVC_CONTROL_CAP_GET | UVC_CONTROL_CAP_DISABLED; + break; + default: + return USBD_FAIL; + } + + break; + + default: + return USBD_FAIL; + } + + return (USBD_OK); +} + +static int8_t UVC_VC_ControlSet(VC_TERMINAL_ID entity_id, uint8_t cmd, uint8_t* pbuf, uint16_t length, uint16_t idx, uint16_t value) +{ + uint8_t cs_value = (value >> 8) & 0xFF; + (void) cs_value; + + switch (cmd) { + case UVC_SET_CUR: + break; + default: + return USBD_FAIL; + } + + switch (entity_id) { + case VC_CONTROL_XU_LEP_AGC_ID: + case VC_CONTROL_XU_LEP_OEM_ID: + case VC_CONTROL_XU_LEP_RAD_ID: + case VC_CONTROL_XU_LEP_RAD_2_ID: + case VC_CONTROL_XU_LEP_SYS_ID: + case VC_CONTROL_XU_LEP_VID_ID: + case VC_CONTROL_XU_LEP_CUST_ID: + if (length == 1) { + //VC_LEP_RunCommand(entity_id, (cs_value - 1) << 2); + } else { + //VC_LEP_SetAttribute(entity_id, (cs_value - 1) << 2, pbuf, length); + } + break; + case VC_CONTROL_PU_ID: + break; + default: + return USBD_FAIL; + } + + return (USBD_OK); +} + + +/** + * @brief UVC_Control_FS + * Manage the UVC class requests + * @param cmd: Command code + * @param pbuf: Buffer containing command data (request parameters) + * @param length: Number of data to be sent (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t UVC_VS_ControlGet(uint8_t cmd, uint8_t* pbuf, uint16_t length, uint16_t idx, uint16_t value) +{ + uint8_t cs_value = (value >> 8) & 0xFF; + + switch (cmd) { + case UVC_GET_DEF: + case UVC_GET_CUR: + case UVC_GET_MIN: + case UVC_GET_MAX: + if(cs_value == UVC_VS_PROBE_CONTROL || cs_value == UVC_VS_STILL_PROBE_CONTROL) { + struct uvc_streaming_control *rtnBuf = (struct uvc_streaming_control*)pbuf; + memset(rtnBuf, 0, length); + rtnBuf->bFormatIndex = videoProbeControl.bFormatIndex; + rtnBuf->bFrameIndex = videoProbeControl.bFrameIndex; + rtnBuf->dwMaxPayloadTransferSize = VIDEO_PACKET_SIZE; + rtnBuf->dwFrameInterval = INTERVAL; + + if (cmd == UVC_GET_DEF || cmd == UVC_GET_MIN || cmd == UVC_GET_MAX || cmd == UVC_GET_CUR) { + struct uvc_vs_frames_formats_descriptor *frames_formats; + struct UVC_FRAME_UNCOMPRESSED(1) *frame; + frames_formats = &USBD_UVC_CfgFSDesc.uvc_vs_frames_formats_desc; + + switch (videoProbeControl.bFormatIndex) { + case VS_FMT_INDEX(YUYV): + frame = frames_formats->uvc_vs_frames_format_1.uvc_vs_frame; + break; + case VS_FMT_INDEX(GREY): + frame = frames_formats->uvc_vs_frames_format_2.uvc_vs_frame; + break; + case VS_FMT_INDEX(RGB565): + frame = frames_formats->uvc_vs_frames_format_3.uvc_vs_frame; + break; + default: + return USBD_FAIL; + } + rtnBuf->dwMaxVideoFrameSize = frame[videoProbeControl.bFrameIndex - 1].dwMaxVideoFrameBufferSize; + } else { + return USBD_FAIL; + } + } else if (cs_value == UVC_VS_COMMIT_CONTROL || cs_value == UVC_VS_STILL_COMMIT_CONTROL) { + // Commit Request + memcpy(pbuf, &videoCommitControl, MIN(sizeof(struct uvc_streaming_control), length)); + } else { + return USBD_FAIL; + } + break; + + default: + return USBD_FAIL; + } + + return (USBD_OK); +} + +static int8_t UVC_VS_ControlSet(uint8_t cmd, uint8_t* pbuf, uint16_t length, uint16_t idx, uint16_t value) +{ + uint8_t cs_value = (value >> 8) & 0xFF; + + switch (cmd) { + case UVC_SET_CUR: { + struct uvc_streaming_control *rtnBuf = (struct uvc_streaming_control*)pbuf; + if (rtnBuf->bFormatIndex > VS_NUM_FORMATS) { + return USBD_FAIL; + } + + if(cs_value == UVC_VS_PROBE_CONTROL || cs_value == UVC_VS_STILL_PROBE_CONTROL) { + memcpy(&videoProbeControl, pbuf, MIN(sizeof(struct uvc_streaming_control), length)); + } else if (cs_value == UVC_VS_COMMIT_CONTROL || cs_value == UVC_VS_STILL_COMMIT_CONTROL) { + memcpy(&videoCommitControl, pbuf, MIN(sizeof(struct uvc_streaming_control), length)); + } else { + return USBD_FAIL; + } + break; + } + default: + return USBD_FAIL; + } + + return (USBD_OK); +} + +/** + * @brief UVC_Receive_FS + * Data received over USB OUT endpoint are sent over UVC interface + * through this function. + * + * @note + * This function will block any OUT packet reception on USB endpoint + * untill exiting this function. If you exit this function before transfer + * is complete on UVC interface (ie. using DMA controller) it will result + * in receiving more data while previous ones are still not sent. + * + * @param Buf: Buffer of data to be received + * @param Len: Number of data received (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t UVC_Receive_FS (uint8_t* Buf, uint32_t *Len) +{ + return (USBD_OK); +} + +/** + * @brief UVC_Transmit_FS + * Data send over USB IN endpoint are sent over UVC interface + * through this function. + * @note + * + * + * @param Buf: Buffer of data to be send + * @param Len: Number of data to be send (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY + */ +uint8_t UVC_Transmit_FS(uint8_t* Buf, uint16_t Len) +{ + uint8_t result = USBD_OK; + HAL_NVIC_DisableIRQ(OTG_FS_IRQn); + USBD_UVC_SetTxBuffer(hUsbDevice_0, Buf, Len); + result = USBD_UVC_TransmitPacket(hUsbDevice_0); + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + return result; +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/webcam/stm32fxxx.ld.S b/src/webcam/stm32fxxx.ld.S new file mode 100755 index 000000000..b6c67c8d2 --- /dev/null +++ b/src/webcam/stm32fxxx.ld.S @@ -0,0 +1,172 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Linker script for STM32F4xx Devices. + * + */ + +/* Entry Point */ +ENTRY(Reset_Handler) + +#include "omv_boardconfig.h" + +/* Specify the memory areas */ +MEMORY +{ + CCM (xrw) : ORIGIN = OMV_CCM_ORIGIN, LENGTH = OMV_CCM_LENGTH + SRAM1 (xrw) : ORIGIN = OMV_SRAM1_ORIGIN, LENGTH = OMV_SRAM1_LENGTH + #if defined(OMV_SRAM2_ORIGIN) + SRAM2 (xrw) : ORIGIN = OMV_SRAM2_ORIGIN, LENGTH = OMV_SRAM2_LENGTH + #endif + #if defined(OMV_SRAM3_ORIGIN) + SRAM3 (xrw) : ORIGIN = OMV_SRAM3_ORIGIN, LENGTH = OMV_SRAM3_LENGTH + #endif + #if defined(OMV_SRAM4_ORIGIN) + SRAM4 (xrw) : ORIGIN = OMV_SRAM4_ORIGIN, LENGTH = OMV_SRAM4_LENGTH + #endif + #if defined(OMV_AXI_SRAM_ORIGIN) + AXI_SRAM (xrw) : ORIGIN = OMV_AXI_SRAM_ORIGIN, LENGTH = OMV_AXI_SRAM_LENGTH + #endif + FLASH_TEXT (rx) : ORIGIN = OMV_TEXT_ORIGIN, LENGTH = OMV_TEXT_LENGTH +} + +_estack = ORIGIN(OMV_MAIN_MEMORY) + LENGTH(OMV_MAIN_MEMORY); +_ram_end = ORIGIN(OMV_MAIN_MEMORY) + LENGTH(OMV_MAIN_MEMORY); + +#if defined(OMV_FFS_MEMORY) +_ffs_cache = ORIGIN(OMV_FFS_MEMORY); +#endif + +#if defined(OMV_JPEG_MEMORY) +_jpeg_buf = ORIGIN(OMV_JPEG_MEMORY); +#endif + +_heap_size = OMV_HEAP_SIZE; /* required amount of heap */ +_stack_size = OMV_STACK_SIZE; /* minimum amount of stack */ + +/* Define output sections */ +SECTIONS +{ + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + KEEP(*(.isr_vector))// ISR table + . = ALIGN(4); + *(.text) // .text sections (code) + . = ALIGN(4); + *(.text*) // .text* sections (code) + . = ALIGN(4); + *(.rodata) // .rodata sections (constants, strings, etc.) + . = ALIGN(4); + *(.rodata*) // .rodata* sections (constants, strings, etc.) + . = ALIGN(4); + _etext = .; // define a global symbols at end of code + } >FLASH_TEXT + + /* used by the startup to initialize data */ + _sidata = .; + + /* Main framebuffer memory */ + .fb_memory (NOLOAD) : + { + . = ALIGN(4); + _fb_base = .; + . = . + OMV_FB_SIZE + OMV_FB_ALLOC_SIZE; + + . = ALIGN(4); + _fballoc = .; + + } >OMV_FB_MEMORY + + /* Misc DMA buffers kept in uncachable region */ + /* NOTE: on H7 DMA buffers are kept in cached AXI RAM and cache maintenance is performed */ + .dma_memory (NOLOAD) : + { + . = ALIGN(4); + _line_buf = .; // Image line buffer. + . = . + OMV_LINE_BUF_SIZE; + + . = ALIGN(4); + _msc_buf = .; // USB MSC bot data (2K) + . = . + OMV_MSC_BUF_SIZE; + + . = ALIGN(4); + _vfs_buf = .; // VFS sturct + FATFS file buffer (around 624 bytes) + . = . + OMV_VFS_BUF_SIZE; + + #if !defined(OMV_FFS_MEMORY) + . = ALIGN(4); + _ffs_cache = .; // Flash filesystem cache + . = . + OMV_FFS_BUF_SIZE; + #endif + + #if !defined(OMV_JPEG_MEMORY) + . = ALIGN(4); + _jpeg_buf = .; // IDE JPEG buffer + . = . + OMV_JPEG_BUF_SIZE; + #endif + + . = ALIGN(4); + *(.dma_buffer) + + } >OMV_DMA_MEMORY + + /* Initialized data sections */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; // Create a global symbol at data start + _ram_start = .; + *(.data) // .data sections + + . = ALIGN(4); + *(.data*) // .data* sections + + . = ALIGN(4); + _edata = .; // define a global symbol at data end + } >OMV_MAIN_MEMORY + + /* Uninitialized data section */ + . = ALIGN(4); + .bss (NOLOAD) : + { + . = ALIGN(4); + _sbss = .; // Used by the startup to initialize the .bss secion + __bss_start__ = _sbss; + *(.bss) + + . = ALIGN(4); + *(.bss*) + + . = ALIGN(4); + *(COMMON) + + . = ALIGN(4); + _ebss = .; // define a global symbol at bss end + _bss_end = .; // Used by gccollect + __bss_end__ = .; + } >OMV_MAIN_MEMORY + + ._heap (NOLOAD) : + { + . = ALIGN(4); + _heap_start = .; + . = . + _heap_size; + + . = ALIGN(4); + _heap_end = .; + + } >OMV_MAIN_MEMORY + + /* Make sure there is enough ram for the stack */ + ._stack (NOLOAD) : + { + . = ALIGN(4); + . = . + _stack_size; + } >OMV_MAIN_MEMORY + + .ARM.attributes 0 : { *(.ARM.attributes) } +}