diff --git a/flight/Bootloaders/Revolution/Makefile b/flight/Bootloaders/Revolution/Makefile index f6bde1c54..b058a4c2c 100644 --- a/flight/Bootloaders/Revolution/Makefile +++ b/flight/Bootloaders/Revolution/Makefile @@ -80,6 +80,7 @@ OPUAVSYNTHDIR = $(OUTDIR)/../uavobject-synthetics/flight ## BOOTLOADER: SRC += main.c SRC += pios_board.c +SRC += pios_usb_board_data.c SRC += bl_fsm.c ## PIOS Hardware (STM32F4xx) @@ -91,7 +92,9 @@ SRC += $(FLIGHTLIB)/fifo_buffer.c # PIOS Hardware (Common) #SRC += $(PIOSCOMMON)/pios_com.c SRC += $(PIOSCOMMON)/pios_board_info.c +SRC += $(PIOSCOMMON)/pios_com_msg.c SRC += $(PIOSCOMMON)/printf-stdarg.c +SRC += $(PIOSCOMMON)/pios_usb_desc_hid_only.c # List C source files here which must be compiled in ARM-Mode (no -mthumb). # use file-extension c for "c-only"-files @@ -224,7 +227,7 @@ CFLAGS += -fpromote-loop-indices endif CFLAGS += -Wall -CFLAGS += -Werror +#CFLAGS += -Werror CFLAGS += -Wa,-adhlns=$(addprefix $(OUTDIR)/, $(notdir $(addsuffix .lst, $(basename $<)))) # Compiler flags to generate dependency files: CFLAGS += -MD -MP -MF $(OUTDIR)/dep/$(@F).d diff --git a/flight/Bootloaders/Revolution/inc/pios_config.h b/flight/Bootloaders/Revolution/inc/pios_config.h index d6f591f7c..469ea9035 100644 --- a/flight/Bootloaders/Revolution/inc/pios_config.h +++ b/flight/Bootloaders/Revolution/inc/pios_config.h @@ -34,6 +34,9 @@ #define PIOS_INCLUDE_SPI #define PIOS_INCLUDE_SYS #define PIOS_INCLUDE_IAP +#define PIOS_INCLUDE_USB +#define PIOS_INCLUDE_USB_HID +#define PIOS_INCLUDE_COM_MSG //#define PIOS_INCLUDE_BL_HELPER //#define PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT diff --git a/flight/Bootloaders/Revolution/inc/pios_usb_board_data.h b/flight/Bootloaders/Revolution/inc/pios_usb_board_data.h new file mode 100644 index 000000000..2c03dc2d0 --- /dev/null +++ b/flight/Bootloaders/Revolution/inc/pios_usb_board_data.h @@ -0,0 +1,51 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_BOARD Board specific USB definitions + * @brief Board specific USB definitions + * @{ + * + * @file pios_usb_board_data.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Board specific USB definitions + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_USB_BOARD_DATA_H +#define PIOS_USB_BOARD_DATA_H + +#define PIOS_USB_BOARD_HID_DATA_LENGTH 64 + +#define PIOS_USB_BOARD_EP_NUM 2 + +#include "pios_usb_defs.h" /* struct usb_* */ + +#define PIOS_USB_BOARD_PRODUCT_ID USB_PRODUCT_ID_REVOLUTION +#define PIOS_USB_BOARD_DEVICE_VER USB_OP_DEVICE_VER(USB_OP_BOARD_ID_REVOLUTION, USB_OP_BOARD_MODE_BL) + +/* + * The bootloader uses a simplified report structure + * BL: ... + * FW: ... + * This define changes the behaviour in pios_usb_hid.c + */ +#define PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + +#endif /* PIOS_USB_BOARD_DATA_H */ diff --git a/flight/Bootloaders/Revolution/pios_board.c b/flight/Bootloaders/Revolution/pios_board.c index 40950e006..a89f83103 100644 --- a/flight/Bootloaders/Revolution/pios_board.c +++ b/flight/Bootloaders/Revolution/pios_board.c @@ -23,11 +23,13 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include "bl_fsm.h" /* lfsm_* */ - #include "board_hw_defs.c" +#include +#include + +uint32_t pios_com_telem_usb_id; + static bool board_init_complete = false; void PIOS_Board_Init() { if (board_init_complete) { @@ -39,5 +41,30 @@ void PIOS_Board_Init() { PIOS_LED_Init(&pios_led_cfg); + +#if 0 && defined(PIOS_INCLUDE_USB) + /* Initialize board specific USB data */ + PIOS_USB_BOARD_DATA_Init(); + + /* Activate the HID-only USB configuration */ + PIOS_USB_DESC_HID_ONLY_Init(); + + uint32_t pios_usb_id; + PIOS_USB_Init(&pios_usb_id, &pios_usb_main_cfg); + +#if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_COM_MSG) + uint32_t pios_usb_hid_id; + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { + PIOS_Assert(0); + } + if (PIOS_COM_MSG_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id)) { + PIOS_Assert(0); + } +#endif /* PIOS_INCLUDE_USB_HID && PIOS_INCLUDE_COM_MSG */ + + PIOS_USBHOOK_Activate(); + +#endif /* PIOS_INCLUDE_USB */ + board_init_complete = true; } diff --git a/flight/Bootloaders/Revolution/pios_usb_board_data.c b/flight/Bootloaders/Revolution/pios_usb_board_data.c new file mode 100644 index 000000000..823496c29 --- /dev/null +++ b/flight/Bootloaders/Revolution/pios_usb_board_data.c @@ -0,0 +1,120 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_BOARD Board specific USB definitions + * @brief Board specific USB definitions + * @{ + * + * @file pios_usb_board_data.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Board specific USB definitions + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "pios_usb_board_data.h" /* struct usb_*, USB_* */ +#include "pios_sys.h" /* PIOS_SYS_SerialNumberGet */ +#include "pios_usbhook.h" /* PIOS_USBHOOK_* */ + +static const uint8_t usb_product_id[22] = { + sizeof(usb_product_id), + USB_DESC_TYPE_STRING, + 'R', 0, + 'e', 0, + 'v', 0, + 'o', 0, + 'l', 0, + 'u', 0, + 't', 0, + 'i', 0, + 'o', 0, + 'n', 0, +}; + +static uint8_t usb_serial_number[52] = { + sizeof(usb_serial_number), + USB_DESC_TYPE_STRING, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0 +}; + +static const struct usb_string_langid usb_lang_id = { + .bLength = sizeof(usb_lang_id), + .bDescriptorType = USB_DESC_TYPE_STRING, + .bLangID = htousbs(USB_LANGID_ENGLISH_UK), +}; + +static const uint8_t usb_vendor_id[28] = { + sizeof(usb_vendor_id), + USB_DESC_TYPE_STRING, + 'o', 0, + 'p', 0, + 'e', 0, + 'n', 0, + 'p', 0, + 'i', 0, + 'l', 0, + 'o', 0, + 't', 0, + '.', 0, + 'o', 0, + 'r', 0, + 'g', 0 +}; + +int32_t PIOS_USB_BOARD_DATA_Init(void) +{ + /* Load device serial number into serial number string */ + uint8_t sn[25]; + PIOS_SYS_SerialNumberGet((char *)sn); + for (uint8_t i = 0; sn[i] != '\0' && (2 * i) < usb_serial_number[0]; i++) { + usb_serial_number[2 + 2 * i] = sn[i]; + } + + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_PRODUCT, (uint8_t *)&usb_product_id, sizeof(usb_product_id)); + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_SERIAL, (uint8_t *)&usb_serial_number, sizeof(usb_serial_number)); + + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_LANG, (uint8_t *)&usb_lang_id, sizeof(usb_lang_id)); + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_VENDOR, (uint8_t *)&usb_vendor_id, sizeof(usb_vendor_id)); + + return 0; +} diff --git a/flight/CopterControl/Makefile b/flight/CopterControl/Makefile index 2e26acc4e..71e487997 100644 --- a/flight/CopterControl/Makefile +++ b/flight/CopterControl/Makefile @@ -53,7 +53,7 @@ USE_GPS ?= YES USE_I2C ?= YES # Set to YES when using Code Sourcery toolchain -CODE_SOURCERY ?= YES +CODE_SOURCERY ?= NO # Remove command is different for Code Sourcery on Windows ifeq ($(CODE_SOURCERY), YES) diff --git a/flight/Modules/Altitude/revolution/altitude.c b/flight/Modules/Altitude/revolution/altitude.c index 319ddaa6c..f757c2b3a 100644 --- a/flight/Modules/Altitude/revolution/altitude.c +++ b/flight/Modules/Altitude/revolution/altitude.c @@ -102,7 +102,6 @@ MODULE_INITCALL(AltitudeInitialize, AltitudeStart) static void altitudeTask(void *parameters) { BaroAltitudeData data; - portTickType lastSysTime; #if defined(PIOS_INCLUDE_HCSR04) SonarAltitudeData sonardata; @@ -115,7 +114,6 @@ static void altitudeTask(void *parameters) // TODO: Check the pressure sensor and set a warning if it fails test // Main task loop - lastSysTime = xTaskGetTickCount(); while (1) { #if defined(PIOS_INCLUDE_HCSR04) diff --git a/flight/Modules/Attitude/attitude.c b/flight/Modules/Attitude/attitude.c index 3664bebf0..e8ef24a72 100644 --- a/flight/Modules/Attitude/attitude.c +++ b/flight/Modules/Attitude/attitude.c @@ -170,7 +170,6 @@ int32_t gyro_test; static void AttitudeTask(void *parameters) { uint8_t init = 0; - portTickType lastSysTime; AlarmsClear(SYSTEMALARMS_ALARM_ATTITUDE); // Set critical error and wait until the accel is producing data @@ -205,8 +204,6 @@ static void AttitudeTask(void *parameters) // Force settings update to make sure rotation loaded settingsUpdatedCb(AttitudeSettingsHandle()); - lastSysTime = xTaskGetTickCount(); - // Main task loop while (1) { diff --git a/flight/PiOS/Boards/STM32F4xx_Revolution.h b/flight/PiOS/Boards/STM32F4xx_Revolution.h index f8cacf260..098fead57 100644 --- a/flight/PiOS/Boards/STM32F4xx_Revolution.h +++ b/flight/PiOS/Boards/STM32F4xx_Revolution.h @@ -229,6 +229,12 @@ extern uint32_t pios_com_telem_usb_id; // None. //------------------------- +//------------------------- +// USB +//------------------------- +#define PIOS_USB_MAX_DEVS 1 +#define PIOS_USB_ENABLED 1 /* Should remove all references to this */ +#define PIOS_USB_HID_MAX_DEVS 1 #endif /* STM3210E_INS_H_ */ /** diff --git a/flight/PiOS/Common/pios_usb_desc_hid_cdc.c b/flight/PiOS/Common/pios_usb_desc_hid_cdc.c index cd4e8a1da..a7ff85dc7 100644 --- a/flight/PiOS/Common/pios_usb_desc_hid_cdc.c +++ b/flight/PiOS/Common/pios_usb_desc_hid_cdc.c @@ -32,6 +32,7 @@ #include "pios_usb_defs.h" /* struct usb_*, USB_* */ #include "pios_usb_board_data.h" /* PIOS_USB_BOARD_* */ #include "pios_usbhook.h" /* PIOS_USBHOOK_Register* */ +#include "pios_usb_hid.h" /* PIOS_USB_HID_Register* */ static const struct usb_device_desc device_desc = { .bLength = sizeof(struct usb_device_desc), @@ -249,8 +250,8 @@ int32_t PIOS_USB_DESC_HID_CDC_Init(void) PIOS_USBHOOK_RegisterDevice((uint8_t *)&device_desc, sizeof(device_desc)); - PIOS_USBHOOK_RegisterHidInterface((uint8_t *)&(config_hid_cdc.hid_if), sizeof(config_hid_cdc.hid_if)); - PIOS_USBHOOK_RegisterHidReport((uint8_t *)hid_report_desc, sizeof(hid_report_desc)); + PIOS_USB_HID_RegisterHidInterface((uint8_t *)&(config_hid_cdc.hid_if), sizeof(config_hid_cdc.hid_if)); + PIOS_USB_HID_RegisterHidReport((uint8_t *)hid_report_desc, sizeof(hid_report_desc)); return 0; } diff --git a/flight/PiOS/Common/pios_usb_desc_hid_only.c b/flight/PiOS/Common/pios_usb_desc_hid_only.c index 168efe841..c0f38f5f4 100644 --- a/flight/PiOS/Common/pios_usb_desc_hid_only.c +++ b/flight/PiOS/Common/pios_usb_desc_hid_only.c @@ -32,6 +32,7 @@ #include "pios_usb_defs.h" /* struct usb_*, USB_* */ #include "pios_usb_board_data.h" /* PIOS_USB_BOARD_* */ #include "pios_usbhook.h" /* PIOS_USBHOOK_Register* */ +#include "pios_usb_hid.h" /* PIOS_USB_HID_Register* */ static const struct usb_device_desc device_desc = { .bLength = sizeof(struct usb_device_desc), @@ -75,7 +76,7 @@ static const uint8_t hid_report_desc[36] = { HID_MAIN_ITEM_1 (HID_TAG_MAIN_INPUT), 0x03, /* Variable, Constant (read-only) */ - /* Host -> Host emulated serial channel */ + /* Host -> Device emulated serial channel */ HID_GLOBAL_ITEM_1 (HID_TAG_GLOBAL_REPORT_ID), 0x02, /* OpenPilot emulated Serial Channel (Host -> Device) */ HID_LOCAL_ITEM_1 (HID_TAG_LOCAL_USAGE), @@ -157,8 +158,8 @@ int32_t PIOS_USB_DESC_HID_ONLY_Init(void) PIOS_USBHOOK_RegisterDevice((uint8_t *)&device_desc, sizeof(device_desc)); - PIOS_USBHOOK_RegisterHidInterface((uint8_t *)&(config_hid_only.hid_if), sizeof(config_hid_only.hid_if)); - PIOS_USBHOOK_RegisterHidReport((uint8_t *)hid_report_desc, sizeof(hid_report_desc)); + PIOS_USB_HID_RegisterHidInterface((uint8_t *)&(config_hid_only.hid_if), sizeof(config_hid_only.hid_if)); + PIOS_USB_HID_RegisterHidReport((uint8_t *)hid_report_desc, sizeof(hid_report_desc)); return 0; } diff --git a/flight/PiOS/STM32F10x/pios_spi.c b/flight/PiOS/STM32F10x/pios_spi.c index 0ae8cefc2..a279df40e 100644 --- a/flight/PiOS/STM32F10x/pios_spi.c +++ b/flight/PiOS/STM32F10x/pios_spi.c @@ -335,6 +335,7 @@ int32_t PIOS_SPI_RC_PinSet(uint32_t spi_id, uint32_t slave_id, uint8_t pin_value * \param[in] spi SPI number (0 or 1) * \param[in] b the byte which should be transfered */ +static uint8_t dummy; int32_t PIOS_SPI_TransferByte(uint32_t spi_id, uint8_t b) { struct pios_spi_dev * spi_dev = (struct pios_spi_dev *)spi_id; @@ -342,7 +343,6 @@ int32_t PIOS_SPI_TransferByte(uint32_t spi_id, uint8_t b) bool valid = PIOS_SPI_validate(spi_dev); PIOS_Assert(valid) - uint8_t dummy; uint8_t rx_byte; /* diff --git a/flight/PiOS/STM32F10x/pios_usb.c b/flight/PiOS/STM32F10x/pios_usb.c index dfe616dca..c7b2855da 100644 --- a/flight/PiOS/STM32F10x/pios_usb.c +++ b/flight/PiOS/STM32F10x/pios_usb.c @@ -148,7 +148,7 @@ out_fail: * \return < 0 on errors * \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions */ -int32_t PIOS_USB_ChangeConnectionState(uint32_t Connected) +int32_t PIOS_USB_ChangeConnectionState(bool Connected) { // In all cases: re-initialise USB HID driver if (Connected) { diff --git a/flight/PiOS/STM32F10x/pios_usb_cdc.c b/flight/PiOS/STM32F10x/pios_usb_cdc.c index 4bb1303d9..7a9bc0b23 100644 --- a/flight/PiOS/STM32F10x/pios_usb_cdc.c +++ b/flight/PiOS/STM32F10x/pios_usb_cdc.c @@ -38,6 +38,9 @@ #include "pios_usb_cdc_priv.h" #include "pios_usb_board_data.h" /* PIOS_BOARD_*_DATA_LENGTH */ +/* STM32 USB Library Definitions */ +#include "usb_lib.h" + static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callback tx_out_cb, uint32_t context); static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id, pios_com_callback rx_in_cb, uint32_t context); static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id, uint16_t tx_bytes_avail); @@ -312,6 +315,7 @@ static void PIOS_USB_CDC_DATA_EP_OUT_Callback(void) #endif /* PIOS_INCLUDE_FREERTOS */ } +static uint16_t control_line_state; RESULT PIOS_USB_CDC_SetControlLineState(void) { struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; @@ -319,8 +323,6 @@ RESULT PIOS_USB_CDC_SetControlLineState(void) bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); PIOS_Assert(valid); - static uint16_t control_line_state; - uint8_t wValue0 = pInformation->USBwValue0; uint8_t wValue1 = pInformation->USBwValue1; diff --git a/flight/PiOS/STM32F10x/pios_usb_hid.c b/flight/PiOS/STM32F10x/pios_usb_hid.c index e70c93046..72a08b7a7 100644 --- a/flight/PiOS/STM32F10x/pios_usb_hid.c +++ b/flight/PiOS/STM32F10x/pios_usb_hid.c @@ -38,6 +38,9 @@ #include "pios_usb_hid_priv.h" #include "pios_usb_board_data.h" /* PIOS_BOARD_*_DATA_LENGTH */ +/* STM32 USB Library Definitions */ +#include "usb_lib.h" + static void PIOS_USB_HID_RegisterTxCallback(uint32_t usbhid_id, pios_com_callback tx_out_cb, uint32_t context); static void PIOS_USB_HID_RegisterRxCallback(uint32_t usbhid_id, pios_com_callback rx_in_cb, uint32_t context); static void PIOS_USB_HID_TxStart(uint32_t usbhid_id, uint16_t tx_bytes_avail); diff --git a/flight/PiOS/STM32F10x/pios_usbhook.c b/flight/PiOS/STM32F10x/pios_usbhook.c index 7800faed1..530f4cbef 100644 --- a/flight/PiOS/STM32F10x/pios_usbhook.c +++ b/flight/PiOS/STM32F10x/pios_usbhook.c @@ -36,6 +36,9 @@ #include "pios_usb_cdc_priv.h" /* PIOS_USB_CDC_* */ #include "pios_usb_board_data.h" /* PIOS_USB_BOARD_* */ +/* STM32 USB Library Definitions */ +#include "usb_lib.h" + static ONE_DESCRIPTOR Device_Descriptor; void PIOS_USBHOOK_RegisterDevice(const uint8_t * desc, uint16_t desc_size) @@ -64,7 +67,7 @@ void PIOS_USBHOOK_RegisterString(enum usb_string_desc string_id, const uint8_t * static ONE_DESCRIPTOR Hid_Interface_Descriptor; -void PIOS_USBHOOK_RegisterHidInterface(const uint8_t * desc, uint16_t desc_size) +void PIOS_USB_HID_RegisterHidInterface(const uint8_t * desc, uint16_t desc_size) { Hid_Interface_Descriptor.Descriptor = desc; Hid_Interface_Descriptor.Descriptor_Size = desc_size; @@ -72,7 +75,7 @@ void PIOS_USBHOOK_RegisterHidInterface(const uint8_t * desc, uint16_t desc_size) static ONE_DESCRIPTOR Hid_Report_Descriptor; -void PIOS_USBHOOK_RegisterHidReport(const uint8_t * desc, uint16_t desc_size) +void PIOS_USB_HID_RegisterHidReport(const uint8_t * desc, uint16_t desc_size) { Hid_Report_Descriptor.Descriptor = desc; Hid_Report_Descriptor.Descriptor_Size = desc_size; @@ -290,6 +293,8 @@ static void PIOS_USBHOOK_Status_Out(void) * Output : None. * Return : USB_UNSUPPORT or USB_SUCCESS. *******************************************************************************/ +extern const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length); + static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo) { const uint8_t *(*CopyRoutine) (uint16_t); @@ -318,7 +323,7 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo) switch (pInformation->USBwIndex0) { case 0: /* HID Interface */ switch (RequestNo) { - case GET_PROTOCOL: + case USB_HID_REQ_GET_PROTOCOL: CopyRoutine = PIOS_USBHOOK_GetProtocolValue; break; } @@ -327,7 +332,7 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo) #if defined(PIOS_INCLUDE_USB_CDC) case 1: /* CDC Call Control Interface */ switch (RequestNo) { - case GET_LINE_CODING: + case USB_CDC_REQ_GET_LINE_CODING: CopyRoutine = PIOS_USB_CDC_GetLineCoding; break; } @@ -363,6 +368,9 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo) * Output : None. * Return : USB_UNSUPPORT or USB_SUCCESS. *******************************************************************************/ +extern RESULT PIOS_USB_CDC_SetControlLineState(void); +extern RESULT PIOS_USB_CDC_SetLineCoding(void); + static RESULT PIOS_USBHOOK_NoData_Setup(uint8_t RequestNo) { switch (Type_Recipient) { @@ -370,7 +378,7 @@ static RESULT PIOS_USBHOOK_NoData_Setup(uint8_t RequestNo) switch (pInformation->USBwIndex0) { case 0: /* HID */ switch (RequestNo) { - case SET_PROTOCOL: + case USB_HID_REQ_SET_PROTOCOL: return PIOS_USBHOOK_SetProtocol(); break; } @@ -380,10 +388,10 @@ static RESULT PIOS_USBHOOK_NoData_Setup(uint8_t RequestNo) #if defined(PIOS_INCLUDE_USB_CDC) case 1: /* CDC Call Control Interface */ switch (RequestNo) { - case SET_LINE_CODING: + case USB_CDC_REQ_SET_LINE_CODING: return PIOS_USB_CDC_SetLineCoding(); break; - case SET_CONTROL_LINE_STATE: + case USB_CDC_REQ_SET_CONTROL_LINE_STATE: return PIOS_USB_CDC_SetControlLineState(); break; } diff --git a/flight/PiOS/STM32F4xx/pios_sys.c b/flight/PiOS/STM32F4xx/pios_sys.c index bfbdc3c3c..8ee9a79ce 100644 --- a/flight/PiOS/STM32F4xx/pios_sys.c +++ b/flight/PiOS/STM32F4xx/pios_sys.c @@ -94,7 +94,7 @@ void PIOS_SYS_Init(void) //RCC_AHB2Periph_CRYP | No crypto //RCC_AHB2Periph_HASH | No hash generator //RCC_AHB2Periph_RNG | No random numbers @todo might be good to have later if entropy is desired - RCC_AHB2Periph_OTG_FS | + //RCC_AHB2Periph_OTG_FS | 0, ENABLE); RCC_AHB3PeriphClockCmd( //RCC_AHB3Periph_FSMC | No external static memory diff --git a/flight/PiOS/STM32F4xx/pios_usb.c b/flight/PiOS/STM32F4xx/pios_usb.c new file mode 100644 index 000000000..726aba379 --- /dev/null +++ b/flight/PiOS/STM32F4xx/pios_usb.c @@ -0,0 +1,290 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB USB Setup Functions + * @brief PIOS USB device implementation + * @{ + * + * @file pios_usb.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief USB device functions (STM32 dependent code) + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Project Includes */ +#include "pios.h" +#include "usb_core.h" +#include "pios_usb_board_data.h" +#include "pios_usb.h" +#include "pios_usb_priv.h" + +#if defined(PIOS_INCLUDE_USB) + +/* Rx/Tx status */ +static uint8_t transfer_possible = 0; + +enum pios_usb_dev_magic { + PIOS_USB_DEV_MAGIC = 0x17365904, +}; + +struct pios_usb_dev { + enum pios_usb_dev_magic magic; + const struct pios_usb_cfg * cfg; +}; + +/** + * @brief Validate the usb device structure + * @returns true if valid device or false otherwise + */ +static bool PIOS_USB_validate(struct pios_usb_dev * usb_dev) +{ + return (usb_dev && (usb_dev->magic == PIOS_USB_DEV_MAGIC)); +} + +#if defined(PIOS_INCLUDE_FREERTOS) +static struct pios_usb_dev * PIOS_USB_alloc(void) +{ + struct pios_usb_dev * usb_dev; + + usb_dev = (struct pios_usb_dev *)pvPortMalloc(sizeof(*usb_dev)); + if (!usb_dev) return(NULL); + + usb_dev->magic = PIOS_USB_DEV_MAGIC; + return(usb_dev); +} +#else +static struct pios_usb_dev pios_usb_devs[PIOS_USB_MAX_DEVS]; +static uint8_t pios_usb_num_devs; +static struct pios_usb_dev * PIOS_USB_alloc(void) +{ + struct pios_usb_dev * usb_dev; + + if (pios_usb_num_devs >= PIOS_USB_MAX_DEVS) { + return (NULL); + } + + usb_dev = &pios_usb_devs[pios_usb_num_devs++]; + usb_dev->magic = PIOS_USB_DEV_MAGIC; + + return (usb_dev); +} +#endif + + +/** + * Bind configuration to USB BSP layer + * \return < 0 if initialisation failed + */ +static uint32_t pios_usb_id; +int32_t PIOS_USB_Init(uint32_t * usb_id, const struct pios_usb_cfg * cfg) +{ + PIOS_Assert(usb_id); + PIOS_Assert(cfg); + + struct pios_usb_dev * usb_dev; + + usb_dev = (struct pios_usb_dev *) PIOS_USB_alloc(); + if (!usb_dev) goto out_fail; + + /* Bind the configuration to the device instance */ + usb_dev->cfg = cfg; + + /* + * This is a horrible hack to make this available to + * the interrupt callbacks. This should go away ASAP. + */ + pios_usb_id = (uint32_t) usb_dev; + + *usb_id = (uint32_t) usb_dev; + + return 0; /* No error */ + +out_fail: + return(-1); +} + +/** + * This function is called by the USB driver on cable connection/disconnection + * \param[in] connected connection status (1 if connected) + * \return < 0 on errors + * \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions + */ +int32_t PIOS_USB_ChangeConnectionState(bool connected) +{ + // In all cases: re-initialise USB HID driver + if (connected) { + transfer_possible = 1; + + //TODO: Check SetEPRxValid(ENDP1); + +#if defined(USB_LED_ON) + USB_LED_ON; // turn the USB led on +#endif + } else { + // Cable disconnected: disable transfers + transfer_possible = 0; + +#if defined(USB_LED_OFF) + USB_LED_OFF; // turn the USB led off +#endif + } + + return 0; +} + +/** + * This function returns the connection status of the USB interface + * \return 1: interface available + * \return 0: interface not available + */ +uint32_t usb_found; +bool PIOS_USB_CheckAvailable(uint8_t id) +{ + struct pios_usb_dev * usb_dev = (struct pios_usb_dev *) pios_usb_id; + + if(!PIOS_USB_validate(usb_dev)) + return false; + + usb_found = (usb_dev->cfg->vsense.gpio->IDR & usb_dev->cfg->vsense.init.GPIO_Pin); + return usb_found; + return usb_found != 0 && transfer_possible ? 1 : 0; +} + +/* + * + * Provide STM32 USB OTG BSP layer API + * + */ + +#include "usb_bsp.h" + +void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev) +{ + struct pios_usb_dev * usb_dev = (struct pios_usb_dev *) pios_usb_id; + + bool valid = PIOS_USB_validate(usb_dev); + PIOS_Assert(valid); + +#define FORCE_DISABLE_USB_IRQ 1 +#if FORCE_DISABLE_USB_IRQ + /* Make sure we disable the USB interrupt since it may be left on by bootloader */ + NVIC_InitTypeDef NVIC_InitStructure; + NVIC_InitStructure = usb_dev->cfg->irq.init; + NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; + NVIC_Init(&NVIC_InitStructure); +#endif + + /* Configure USB D-/D+ (DM/DP) pins */ + GPIO_InitTypeDef GPIO_InitStructure; + +#define FORCE_USB_DP_DM_LOW 1 +#if FORCE_USB_DP_DM_LOW + /* Force D-/D+ low for 50ms to trigger a disconnect */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, 0); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, 0); + + GPIO_ResetBits(GPIOA, GPIO_Pin_12); + GPIO_ResetBits(GPIOA, GPIO_Pin_11); + + PIOS_DELAY_WaitmS(50); +#endif + + /* Set up D-/D+ as USB function again */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_OTG1_FS); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_OTG1_FS); + + /* Configure VBUS sense pin */ + GPIO_Init(usb_dev->cfg->vsense.gpio, &usb_dev->cfg->vsense.init); + + /* Enable USB OTG Clock */ + RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS, ENABLE); +} + +void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE *pdev) +{ + struct pios_usb_dev * usb_dev = (struct pios_usb_dev *) pios_usb_id; + + bool valid = PIOS_USB_validate(usb_dev); + PIOS_Assert(valid); + + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); + + NVIC_Init(&usb_dev->cfg->irq.init); +} + +#ifdef USE_HOST_MODE +void USB_OTG_BSP_DriveVBUS(USB_OTG_CORE_HANDLE *pdev, uint8_t state) +{ + +} + +void USB_OTG_BSP_ConfigVBUS(USB_OTG_CORE_HANDLE *pdev) +{ + +} +#endif /* USE_HOST_MODE */ + +void USB_OTG_BSP_TimeInit ( void ) +{ + +} + +void USB_OTG_BSP_uDelay (const uint32_t usec) +{ + uint32_t count = 0; + const uint32_t utime = (120 * usec / 7); + do { + if (++count > utime) { + return ; + } + } + while (1); +} + +void USB_OTG_BSP_mDelay (const uint32_t msec) +{ + USB_OTG_BSP_uDelay(msec * 1000); +} + +void USB_OTG_BSP_TimerIRQ (void) +{ + +} + +#endif /* PIOS_INCLUDE_USB */ + +/** + * @} + * @} + */ diff --git a/flight/PiOS/STM32F4xx/pios_usb_cdc.c b/flight/PiOS/STM32F4xx/pios_usb_cdc.c new file mode 100644 index 000000000..cb468b6d1 --- /dev/null +++ b/flight/PiOS/STM32F4xx/pios_usb_cdc.c @@ -0,0 +1,400 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_COM USB COM Functions + * @brief PIOS USB COM implementation for CDC interfaces + * @notes This implements a CDC Serial Port + * @{ + * + * @file pios_usb_com_cdc.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief USB COM functions (STM32 dependent code) + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Project Includes */ +#include "pios.h" + +#if defined(PIOS_INCLUDE_USB_CDC) + +#include "pios_usb.h" +#include "pios_usb_cdc_priv.h" +#include "pios_usb_board_data.h" /* PIOS_BOARD_*_DATA_LENGTH */ + +static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callback tx_out_cb, uint32_t context); +static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id, pios_com_callback rx_in_cb, uint32_t context); +static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id, uint16_t tx_bytes_avail); +static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id, uint16_t rx_bytes_avail); + +const struct pios_com_driver pios_usb_cdc_com_driver = { + .tx_start = PIOS_USB_CDC_TxStart, + .rx_start = PIOS_USB_CDC_RxStart, + .bind_tx_cb = PIOS_USB_CDC_RegisterTxCallback, + .bind_rx_cb = PIOS_USB_CDC_RegisterRxCallback, +}; + +enum pios_usb_cdc_dev_magic { + PIOS_USB_CDC_DEV_MAGIC = 0xAABBCCDD, +}; + +struct pios_usb_cdc_dev { + enum pios_usb_cdc_dev_magic magic; + const struct pios_usb_cdc_cfg * cfg; + + uint32_t lower_id; + + pios_com_callback rx_in_cb; + uint32_t rx_in_context; + pios_com_callback tx_out_cb; + uint32_t tx_out_context; + + uint8_t rx_packet_buffer[PIOS_USB_BOARD_CDC_DATA_LENGTH]; + uint8_t tx_packet_buffer[PIOS_USB_BOARD_CDC_DATA_LENGTH]; + + uint32_t rx_dropped; + uint32_t rx_oversize; +}; + +static bool PIOS_USB_CDC_validate(struct pios_usb_cdc_dev * usb_cdc_dev) +{ + return (usb_cdc_dev && (usb_cdc_dev->magic == PIOS_USB_CDC_DEV_MAGIC)); +} + +#if defined(PIOS_INCLUDE_FREERTOS) +static struct pios_usb_cdc_dev * PIOS_USB_CDC_alloc(void) +{ + struct pios_usb_cdc_dev * usb_cdc_dev; + + usb_cdc_dev = (struct pios_usb_cdc_dev *)pvPortMalloc(sizeof(*usb_cdc_dev)); + if (!usb_cdc_dev) return(NULL); + + usb_cdc_dev->magic = PIOS_USB_CDC_DEV_MAGIC; + return(usb_cdc_dev); +} +#else +static struct pios_usb_cdc_dev pios_usb_cdc_devs[PIOS_USB_CDC_MAX_DEVS]; +static uint8_t pios_usb_cdc_num_devs; +static struct pios_usb_cdc_dev * PIOS_USB_CDC_alloc(void) +{ + struct pios_usb_cdc_dev * usb_cdc_dev; + + if (pios_usb_cdc_num_devs >= PIOS_USB_CDC_MAX_DEVS) { + return (NULL); + } + + usb_cdc_dev = &pios_usb_cdc_devs[pios_usb_cdc_num_devs++]; + usb_cdc_dev->magic = PIOS_USB_CDC_DEV_MAGIC; + + return (usb_cdc_dev); +} +#endif + +static void PIOS_USB_CDC_DATA_EP_IN_Callback(void); +static void PIOS_USB_CDC_DATA_EP_OUT_Callback(void); +static void PIOS_USB_CDC_CTRL_EP_IN_Callback(void); + +static uint32_t pios_usb_cdc_id; + +/* Need a better way to pull these in */ +extern void (*pEpInt_IN[7])(void); +extern void (*pEpInt_OUT[7])(void); + +int32_t PIOS_USB_CDC_Init(uint32_t * usbcdc_id, const struct pios_usb_cdc_cfg * cfg, uint32_t lower_id) +{ + PIOS_Assert(usbcdc_id); + PIOS_Assert(cfg); + + struct pios_usb_cdc_dev * usb_cdc_dev; + + usb_cdc_dev = (struct pios_usb_cdc_dev *) PIOS_USB_CDC_alloc(); + if (!usb_cdc_dev) goto out_fail; + + /* Bind the configuration to the device instance */ + usb_cdc_dev->cfg = cfg; + usb_cdc_dev->lower_id = lower_id; + + pios_usb_cdc_id = (uint32_t) usb_cdc_dev; + + /* Bind lower level callbacks into the USB infrastructure */ + pEpInt_OUT[cfg->ctrl_tx_ep - 1] = PIOS_USB_CDC_CTRL_EP_IN_Callback; + pEpInt_IN[cfg->data_tx_ep - 1] = PIOS_USB_CDC_DATA_EP_IN_Callback; + pEpInt_OUT[cfg->data_rx_ep - 1] = PIOS_USB_CDC_DATA_EP_OUT_Callback; + + *usbcdc_id = (uint32_t) usb_cdc_dev; + + return 0; + +out_fail: + return -1; +} + + + +static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id, pios_com_callback rx_in_cb, uint32_t context) +{ + struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_cdc_dev->rx_in_context = context; + usb_cdc_dev->rx_in_cb = rx_in_cb; +} + +static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callback tx_out_cb, uint32_t context) +{ + struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_cdc_dev->tx_out_context = context; + usb_cdc_dev->tx_out_cb = tx_out_cb; +} + +static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id, uint16_t rx_bytes_avail) { + struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + PIOS_Assert(valid); + + if (!PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id)) { + return; + } + + // If endpoint was stalled and there is now space make it valid + PIOS_IRQ_Disable(); + if ((GetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep) != EP_RX_VALID) && + (rx_bytes_avail >= sizeof(usb_cdc_dev->rx_packet_buffer))) { + SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_VALID); + } + PIOS_IRQ_Enable(); +} + +static void PIOS_USB_CDC_SendData(struct pios_usb_cdc_dev * usb_cdc_dev) +{ + uint16_t bytes_to_tx; + + if (!usb_cdc_dev->tx_out_cb) { + return; + } + + bool need_yield = false; + bytes_to_tx = (usb_cdc_dev->tx_out_cb)(usb_cdc_dev->tx_out_context, + usb_cdc_dev->tx_packet_buffer, + sizeof(usb_cdc_dev->tx_packet_buffer), + NULL, + &need_yield); + if (bytes_to_tx == 0) { + return; + } + + UserToPMABufferCopy(usb_cdc_dev->tx_packet_buffer, + GetEPTxAddr(usb_cdc_dev->cfg->data_tx_ep), + bytes_to_tx); + SetEPTxCount(usb_cdc_dev->cfg->data_tx_ep, bytes_to_tx); + SetEPTxValid(usb_cdc_dev->cfg->data_tx_ep); + +#if defined(PIOS_INCLUDE_FREERTOS) + if (need_yield) { + vPortYieldFromISR(); + } +#endif /* PIOS_INCLUDE_FREERTOS */ +} + +static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id, uint16_t tx_bytes_avail) +{ + struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + PIOS_Assert(valid); + + if (!PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id)) { + return; + } + + if (GetEPTxStatus(usb_cdc_dev->cfg->data_tx_ep) == EP_TX_VALID) { + /* Endpoint is already transmitting */ + return; + } + + PIOS_USB_CDC_SendData(usb_cdc_dev); +} + +static void PIOS_USB_CDC_DATA_EP_IN_Callback(void) +{ + struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + PIOS_Assert(valid); + + PIOS_USB_CDC_SendData(usb_cdc_dev); +} + +static void PIOS_USB_CDC_DATA_EP_OUT_Callback(void) +{ + struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + PIOS_Assert(valid); + + uint32_t DataLength; + + /* Get the number of received data on the selected Endpoint */ + DataLength = GetEPRxCount(usb_cdc_dev->cfg->data_rx_ep); + if (DataLength > sizeof(usb_cdc_dev->rx_packet_buffer)) { + usb_cdc_dev->rx_oversize++; + DataLength = sizeof(usb_cdc_dev->rx_packet_buffer); + } + + /* Use the memory interface function to read from the selected endpoint */ + PMAToUserBufferCopy((uint8_t *) usb_cdc_dev->rx_packet_buffer, + GetEPRxAddr(usb_cdc_dev->cfg->data_rx_ep), + DataLength); + + if (!usb_cdc_dev->rx_in_cb) { + /* No Rx call back registered, disable the receiver */ + SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_NAK); + return; + } + + uint16_t headroom; + bool need_yield = false; + uint16_t rc; + rc = (usb_cdc_dev->rx_in_cb)(usb_cdc_dev->rx_in_context, + usb_cdc_dev->rx_packet_buffer, + DataLength, + &headroom, + &need_yield); + + if (rc < DataLength) { + /* Lost bytes on rx */ + usb_cdc_dev->rx_dropped += (DataLength - rc); + } + + if (headroom >= sizeof(usb_cdc_dev->rx_packet_buffer)) { + /* We have room for a maximum length message */ + SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_VALID); + } else { + /* Not enough room left for a message, apply backpressure */ + SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_NAK); + } + +#if defined(PIOS_INCLUDE_FREERTOS) + if (need_yield) { + vPortYieldFromISR(); + } +#endif /* PIOS_INCLUDE_FREERTOS */ +} + +RESULT PIOS_USB_CDC_SetControlLineState(void) +{ + struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + PIOS_Assert(valid); + + static uint16_t control_line_state; + + uint8_t wValue0 = pInformation->USBwValue0; + uint8_t wValue1 = pInformation->USBwValue1; + + control_line_state = wValue1 << 8 | wValue0; + + return USB_SUCCESS; +} + +static struct usb_cdc_line_coding line_coding = { + .dwDTERate = htousbl(57600), + .bCharFormat = USB_CDC_LINE_CODING_STOP_1, + .bParityType = USB_CDC_LINE_CODING_PARITY_NONE, + .bDataBits = 8, +}; + +RESULT PIOS_USB_CDC_SetLineCoding(void) +{ + struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + PIOS_Assert(valid); + + return USB_SUCCESS; +} + +const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length) +{ + struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + PIOS_Assert(valid); + + if (Length == 0) { + pInformation->Ctrl_Info.Usb_wLength = sizeof(line_coding); + return NULL; + } else { + return ((uint8_t *) &line_coding); + } +} + +struct usb_cdc_serial_state_report uart_state = { + .bmRequestType = 0xA1, + .bNotification = USB_CDC_NOTIFICATION_SERIAL_STATE, + .wValue = 0, + .wIndex = htousbs(1), + .wLength = htousbs(2), + .bmUartState = htousbs(0), +}; + +static void PIOS_USB_CDC_CTRL_EP_IN_Callback(void) +{ + struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + PIOS_Assert(valid); + + /* Give back UART State Bitmap */ + /* UART State Bitmap + * 15-7: reserved + * 6: bOverRun overrun error + * 5: bParity parity error + * 4: bFraming framing error + * 3: bRingSignal RI + * 2: bBreak break reception + * 1: bTxCarrier DSR + * 0: bRxCarrier DCD + */ + uart_state.bmUartState = htousbs(0x0003); + + UserToPMABufferCopy((uint8_t *) &uart_state, + GetEPTxAddr(usb_cdc_dev->cfg->data_tx_ep), + sizeof(uart_state)); + SetEPTxCount(usb_cdc_dev->cfg->data_tx_ep, PIOS_USB_BOARD_CDC_MGMT_LENGTH); + SetEPTxValid(usb_cdc_dev->cfg->data_tx_ep); +} + +#endif /* PIOS_INCLUDE_USB_CDC */ diff --git a/flight/PiOS/STM32F4xx/pios_usb_hid.c b/flight/PiOS/STM32F4xx/pios_usb_hid.c new file mode 100644 index 000000000..730e0f285 --- /dev/null +++ b/flight/PiOS/STM32F4xx/pios_usb_hid.c @@ -0,0 +1,497 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_HID USB COM Functions + * @brief PIOS USB COM implementation for HID interfaces + * @notes This implements serial emulation over HID reports + * @{ + * + * @file pios_usb_hid.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief USB COM functions (STM32 dependent code) + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Project Includes */ +#include "pios.h" + +#if defined(PIOS_INCLUDE_USB_HID) + +#include "pios_usb.h" +#include "pios_usb_hid_priv.h" +#include "pios_usb_board_data.h" /* PIOS_BOARD_*_DATA_LENGTH */ +#include "pios_usbhook.h" /* PIOS_USBHOOK_* */ + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) + +static void PIOS_USB_HID_RegisterTxCallback(uint32_t usbhid_id, pios_com_callback tx_out_cb, uint32_t context); +static void PIOS_USB_HID_RegisterRxCallback(uint32_t usbhid_id, pios_com_callback rx_in_cb, uint32_t context); +static void PIOS_USB_HID_TxStart(uint32_t usbhid_id, uint16_t tx_bytes_avail); +static void PIOS_USB_HID_RxStart(uint32_t usbhid_id, uint16_t rx_bytes_avail); + +const struct pios_com_driver pios_usb_hid_com_driver = { + .tx_start = PIOS_USB_HID_TxStart, + .rx_start = PIOS_USB_HID_RxStart, + .bind_tx_cb = PIOS_USB_HID_RegisterTxCallback, + .bind_rx_cb = PIOS_USB_HID_RegisterRxCallback, +}; + +enum pios_usb_hid_dev_magic { + PIOS_USB_HID_DEV_MAGIC = 0xAA00BB00, +}; + +struct pios_usb_hid_dev { + enum pios_usb_hid_dev_magic magic; + const struct pios_usb_hid_cfg * cfg; + + uint32_t lower_id; + + pios_com_callback rx_in_cb; + uint32_t rx_in_context; + pios_com_callback tx_out_cb; + uint32_t tx_out_context; + + uint8_t rx_packet_buffer[PIOS_USB_BOARD_HID_DATA_LENGTH]; + uint8_t tx_packet_buffer[PIOS_USB_BOARD_HID_DATA_LENGTH]; + + uint32_t rx_dropped; + uint32_t rx_oversize; +}; + +static bool PIOS_USB_HID_validate(struct pios_usb_hid_dev * usb_hid_dev) +{ + return (usb_hid_dev && (usb_hid_dev->magic == PIOS_USB_HID_DEV_MAGIC)); +} + +#if defined(PIOS_INCLUDE_FREERTOS) +static struct pios_usb_hid_dev * PIOS_USB_HID_alloc(void) +{ + struct pios_usb_hid_dev * usb_hid_dev; + + usb_hid_dev = (struct pios_usb_hid_dev *)pvPortMalloc(sizeof(*usb_hid_dev)); + if (!usb_hid_dev) return(NULL); + + usb_hid_dev->magic = PIOS_USB_HID_DEV_MAGIC; + return(usb_hid_dev); +} +#else +static struct pios_usb_hid_dev pios_usb_hid_devs[PIOS_USB_HID_MAX_DEVS]; +static uint8_t pios_usb_hid_num_devs; +static struct pios_usb_hid_dev * PIOS_USB_HID_alloc(void) +{ + struct pios_usb_hid_dev * usb_hid_dev; + + if (pios_usb_hid_num_devs >= PIOS_USB_HID_MAX_DEVS) { + return (NULL); + } + + usb_hid_dev = &pios_usb_hid_devs[pios_usb_hid_num_devs++]; + usb_hid_dev->magic = PIOS_USB_HID_DEV_MAGIC; + + return (usb_hid_dev); +} +#endif + +static void PIOS_USB_HID_IF_Init(uint32_t usb_hid_id); +static void PIOS_USB_HID_IF_DeInit(uint32_t usb_hid_id); +static bool PIOS_USB_HID_IF_Setup(uint32_t usb_hid_id, struct usb_setup_request *req); +static void PIOS_USB_HID_IF_CtrlDataOut(uint32_t usb_hid_id, struct usb_setup_request *req); + +static struct pios_usb_ifops usb_hid_ifops = { + .init = PIOS_USB_HID_IF_Init, + .deinit = PIOS_USB_HID_IF_DeInit, + .setup = PIOS_USB_HID_IF_Setup, + .ctrl_data_out = PIOS_USB_HID_IF_CtrlDataOut, +}; + +static bool PIOS_USB_HID_EP_IN_Callback(uint32_t usb_hid_id, uint8_t epnum, uint16_t len); +static bool PIOS_USB_HID_EP_OUT_Callback(uint32_t usb_hid_id, uint8_t epnum, uint16_t len); + +int32_t PIOS_USB_HID_Init(uint32_t * usbhid_id, const struct pios_usb_hid_cfg * cfg, uint32_t lower_id) +{ + PIOS_Assert(usbhid_id); + PIOS_Assert(cfg); + + struct pios_usb_hid_dev * usb_hid_dev; + + usb_hid_dev = (struct pios_usb_hid_dev *) PIOS_USB_HID_alloc(); + if (!usb_hid_dev) goto out_fail; + + /* Bind the configuration to the device instance */ + usb_hid_dev->cfg = cfg; + usb_hid_dev->lower_id = lower_id; + + /* Register class specific interface callbacks with the USBHOOK layer */ + PIOS_USBHOOK_RegisterIfOps(cfg->data_if, &usb_hid_ifops, (uint32_t) usb_hid_dev); + + *usbhid_id = (uint32_t) usb_hid_dev; + + return 0; + +out_fail: + return -1; +} + + +static struct pios_usbhook_descriptor hid_if_desc; + +void PIOS_USB_HID_RegisterHidInterface(const uint8_t * desc, uint16_t length) +{ + hid_if_desc.descriptor = desc; + hid_if_desc.length = length; +} + +static struct pios_usbhook_descriptor hid_report_desc; + +void PIOS_USB_HID_RegisterHidReport(const uint8_t * desc, uint16_t length) +{ + hid_report_desc.descriptor = desc; + hid_report_desc.length = length; +} + +static bool PIOS_USB_HID_SendReport(struct pios_usb_hid_dev * usb_hid_dev) +{ + uint16_t bytes_to_tx; + + if (!usb_hid_dev->tx_out_cb) { + return false; + } + + bool need_yield = false; +#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + bytes_to_tx = (usb_hid_dev->tx_out_cb)(usb_hid_dev->tx_out_context, + &usb_hid_dev->tx_packet_buffer[1], + sizeof(usb_hid_dev->tx_packet_buffer)-1, + NULL, + &need_yield); +#else + bytes_to_tx = (usb_hid_dev->tx_out_cb)(usb_hid_dev->tx_out_context, + &usb_hid_dev->tx_packet_buffer[2], + sizeof(usb_hid_dev->tx_packet_buffer)-2, + NULL, + &need_yield); +#endif + if (bytes_to_tx == 0) { + return false; + } + + /* Always set type as report ID */ + usb_hid_dev->tx_packet_buffer[0] = 1; + +#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + PIOS_USBHOOK_EndpointTx(usb_hid_dev->cfg->data_tx_ep, + usb_hid_dev->tx_packet_buffer, + bytes_to_tx + 1); +#else + usb_hid_dev->tx_packet_buffer[1] = bytes_to_tx; + PIOS_USBHOOK_EndpointTx(usb_hid_dev->cfg->data_tx_ep, + usb_hid_dev->tx_packet_buffer, + bytes_to_tx + 2); +#endif + +#if defined(PIOS_INCLUDE_FREERTOS) + if (need_yield) { + vPortYieldFromISR(); + } +#endif /* PIOS_INCLUDE_FREERTOS */ + + return true; +} + +static void PIOS_USB_HID_RxStart(uint32_t usbhid_id, uint16_t rx_bytes_avail) { + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usbhid_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + PIOS_Assert(valid); + + if (!PIOS_USB_CheckAvailable(usb_hid_dev->lower_id)) { + return; + } + + // If endpoint was stalled and there is now space make it valid +#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 1; +#else + uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 2; +#endif + + PIOS_IRQ_Disable(); + if (rx_bytes_avail >= max_payload_length) { + /* + * FIXME should make sure we do not already have a buffer queued + */ + PIOS_USBHOOK_EndpointRx(usb_hid_dev->cfg->data_rx_ep, + usb_hid_dev->rx_packet_buffer, + sizeof(usb_hid_dev->rx_packet_buffer)); + } + PIOS_IRQ_Enable(); +} + +static void PIOS_USB_HID_TxStart(uint32_t usbhid_id, uint16_t tx_bytes_avail) +{ + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usbhid_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + PIOS_Assert(valid); + + if (!PIOS_USB_CheckAvailable(usb_hid_dev->lower_id)) { + return; + } + +#if 0 + if (GetEPTxStatus(usb_hid_dev->cfg->data_tx_ep) == EP_TX_VALID) { + /* Endpoint is already transmitting */ + return; + } +#else + /* + * FIXME start transmitter + */ +#endif + + PIOS_USB_HID_SendReport(usb_hid_dev); +} + +static void PIOS_USB_HID_RegisterRxCallback(uint32_t usbhid_id, pios_com_callback rx_in_cb, uint32_t context) +{ + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usbhid_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_hid_dev->rx_in_context = context; + usb_hid_dev->rx_in_cb = rx_in_cb; +} + +static void PIOS_USB_HID_RegisterTxCallback(uint32_t usbhid_id, pios_com_callback tx_out_cb, uint32_t context) +{ + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usbhid_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_hid_dev->tx_out_context = context; + usb_hid_dev->tx_out_cb = tx_out_cb; +} + +static void PIOS_USB_HID_IF_Init(uint32_t usb_hid_id) +{ + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usb_hid_id; + + if (!PIOS_USB_HID_validate(usb_hid_dev)) { + return; + } + + /* Register endpoint specific callbacks with the USBHOOK layer */ + PIOS_USBHOOK_RegisterEpInCallback(usb_hid_dev->cfg->data_tx_ep, + sizeof(usb_hid_dev->rx_packet_buffer), + PIOS_USB_HID_EP_IN_Callback, + (uint32_t) usb_hid_dev); + PIOS_USBHOOK_RegisterEpOutCallback(usb_hid_dev->cfg->data_rx_ep, + sizeof(usb_hid_dev->rx_packet_buffer), + PIOS_USB_HID_EP_OUT_Callback, + (uint32_t) usb_hid_dev); +} + +static void PIOS_USB_HID_IF_DeInit(uint32_t usb_hid_id) +{ + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usb_hid_id; + + if (!PIOS_USB_HID_validate(usb_hid_dev)) { + return; + } + + /* DeRegister endpoint specific callbacks with the USBHOOK layer */ + PIOS_USBHOOK_DeRegisterEpInCallback(usb_hid_dev->cfg->data_tx_ep); + PIOS_USBHOOK_DeRegisterEpOutCallback(usb_hid_dev->cfg->data_rx_ep); +} + +static uint8_t hid_protocol; +static uint8_t hid_altset; + +static bool PIOS_USB_HID_IF_Setup(uint32_t usb_hid_id, struct usb_setup_request *req) +{ + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usb_hid_id; + + if (!PIOS_USB_HID_validate(usb_hid_dev)) { + return false; + } + + /* Make sure this is a request for an interface we know about */ + uint8_t ifnum = req->wIndex & 0xFF; + if (ifnum != usb_hid_dev->cfg->data_if) { + return (false); + } + + switch (req->bmRequestType & (USB_REQ_TYPE_MASK | USB_REQ_RECIPIENT_MASK)) { + case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_INTERFACE): + switch (req->bRequest) { + case USB_REQ_GET_DESCRIPTOR: + switch (req->wValue >> 8) { + case USB_DESC_TYPE_REPORT: + PIOS_USBHOOK_CtrlTx(hid_report_desc.descriptor, + MIN(hid_report_desc.length, req->wLength)); + break; + case USB_DESC_TYPE_HID: + PIOS_USBHOOK_CtrlTx(hid_if_desc.descriptor, + MIN(hid_if_desc.length, req->wLength)); + break; + default: + /* Unhandled descriptor request */ + return false; + break; + } + break; + case USB_REQ_GET_INTERFACE: + PIOS_USBHOOK_CtrlTx(&hid_altset, 1); + break; + case USB_REQ_SET_INTERFACE: + hid_altset = (uint8_t)(req->wValue); + break; + default: + /* Unhandled standard request */ + return false; + break; + } + break; + case (USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE): + switch (req->bRequest) { + case USB_HID_REQ_SET_PROTOCOL: + hid_protocol = (uint8_t)(req->wValue); + break; + case USB_HID_REQ_GET_PROTOCOL: + PIOS_USBHOOK_CtrlTx(&hid_protocol, 1); + break; + case USB_HID_REQ_GET_REPORT: + { + /* Give back a dummy input report */ + uint8_t dummy_report[2] = { + [0] = req->wValue >> 8, /* Report ID */ + [1] = 0x00, + }; + PIOS_USBHOOK_CtrlTx(dummy_report, sizeof(dummy_report)); + } + break; + default: + /* Unhandled class request */ + return false; + break; + } + break; + default: + /* Unhandled request */ + return false; + } + + return true; +} + +static void PIOS_USB_HID_IF_CtrlDataOut(uint32_t usb_hid_id, struct usb_setup_request *req) +{ + /* HID devices don't have any OUT data stages on the control endpoint */ + PIOS_Assert(0); +} + +/** + * @brief Callback used to indicate a transmission from device INto host completed + * Checks if any data remains, pads it into HID packet and sends. + */ +static bool PIOS_USB_HID_EP_IN_Callback(uint32_t usb_hid_id, uint8_t epnum, uint16_t len) +{ + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usb_hid_id; + + if (!PIOS_USB_HID_validate(usb_hid_dev)) { + return false; + } + + if (!PIOS_USB_CheckAvailable(usb_hid_dev->lower_id)) { + return false; + } + + return (PIOS_USB_HID_SendReport(usb_hid_dev)); +} + +/** + * EP1 OUT Callback Routine + */ +static bool PIOS_USB_HID_EP_OUT_Callback(uint32_t usb_hid_id, uint8_t epnum, uint16_t len) +{ + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usb_hid_id; + + if (!PIOS_USB_HID_validate(usb_hid_dev)) { + return false; + } + + if (len > sizeof(usb_hid_dev->rx_packet_buffer)) { + len = sizeof(usb_hid_dev->rx_packet_buffer); + } + + if (!usb_hid_dev->rx_in_cb) { + /* No Rx call back registered, disable the receiver */ + return false; + } + + /* The first byte is report ID (not checked), the second byte is the valid data length */ + uint16_t headroom; + bool need_yield = false; +#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + (usb_hid_dev->rx_in_cb)(usb_hid_dev->rx_in_context, + &usb_hid_dev->rx_packet_buffer[1], + len-1, + &headroom, + &need_yield); +#else + (usb_hid_dev->rx_in_cb)(usb_hid_dev->rx_in_context, + &usb_hid_dev->rx_packet_buffer[2], + usb_hid_dev->rx_packet_buffer[1], + &headroom, + &need_yield); +#endif + +#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 1; +#else + uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 2; +#endif + + if (headroom >= max_payload_length) { + /* We have room for a maximum length message */ + return true; + } else { + /* Not enough room left for a message, apply backpressure */ + return false; + } + +#if defined(PIOS_INCLUDE_FREERTOS) + if (need_yield) { + vPortYieldFromISR(); + } +#endif /* PIOS_INCLUDE_FREERTOS */ +} + +#endif /* PIOS_INCLUDE_USB_HID */ diff --git a/flight/PiOS/STM32F4xx/pios_usbhook.c b/flight/PiOS/STM32F4xx/pios_usbhook.c new file mode 100644 index 000000000..d413b1edc --- /dev/null +++ b/flight/PiOS/STM32F4xx/pios_usbhook.c @@ -0,0 +1,897 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USBHOOK USB glue code + * @brief Glue between PiOS and STM32 libs + * @{ + * + * @file pios_usbhook.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Glue between PiOS and STM32 libs + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "pios.h" +#include "pios_usb.h" /* PIOS_USB_* */ +#include "pios_usbhook.h" +#include "pios_usb_defs.h" /* struct usb_* */ +#include "pios_usb_cdc_priv.h" /* PIOS_USB_CDC_* */ +#include "pios_usb_board_data.h" /* PIOS_USB_BOARD_* */ + + +/* STM32 USB Library Definitions */ +#include "usb_core.h" /* USBD_Class_cb_TypeDef */ +#include "usbd_core.h" /* USBD_Init USBD_OK*/ +#include "usbd_ioreq.h" /* USBD_CtlPrepareRx, USBD_CtlSendData */ +#include "usbd_req.h" /* USBD_CtlError */ +#include "usb_dcd_int.h" /* USBD_OTG_ISR_Handler */ + +/* + * External API + */ +static struct pios_usbhook_descriptor Device_Descriptor; + +void PIOS_USBHOOK_RegisterDevice(const uint8_t * desc, uint16_t length) +{ + Device_Descriptor.descriptor = desc; + Device_Descriptor.length = length; +} + +static struct pios_usbhook_descriptor String_Descriptor[4]; + +void PIOS_USBHOOK_RegisterString(enum usb_string_desc string_id, const uint8_t * desc, uint16_t desc_size) +{ + if (string_id < NELEMENTS(String_Descriptor)) { + String_Descriptor[string_id].descriptor = desc; + String_Descriptor[string_id].length = desc_size; + } +} + +static struct pios_usbhook_descriptor Config_Descriptor; + +void PIOS_USBHOOK_RegisterConfig(uint8_t config_id, const uint8_t * desc, uint16_t desc_size) +{ + Config_Descriptor.descriptor = desc; + Config_Descriptor.length = desc_size; +} + +static USB_OTG_CORE_HANDLE pios_usb_otg_core_handle; +static USBD_Class_cb_TypeDef class_callbacks; +static USBD_DEVICE device_callbacks; +static USBD_Usr_cb_TypeDef user_callbacks; + +void PIOS_USBHOOK_Activate(void) +{ + USBD_Init(&pios_usb_otg_core_handle, + USB_OTG_FS_CORE_ID, + &device_callbacks, + &class_callbacks, + &user_callbacks); +} + +void OTG_FS_IRQHandler(void) +{ + if(!USBD_OTG_ISR_Handler(&pios_usb_otg_core_handle)) { + /* spurious interrupt, disable IRQ */ + + } +} + +struct usb_if_entry { + struct pios_usb_ifops *ifops; + uint32_t context; +}; +static struct usb_if_entry usb_if_table[3]; +void PIOS_USBHOOK_RegisterIfOps(uint8_t ifnum, struct pios_usb_ifops * ifops, uint32_t context) +{ + PIOS_Assert(ifnum < NELEMENTS(usb_if_table)); + PIOS_Assert(ifops); + + usb_if_table[ifnum].ifops = ifops; + usb_if_table[ifnum].context = context; +} + +struct usb_ep_entry { + pios_usbhook_epcb cb; + uint32_t context; + uint16_t max_len; +}; +static struct usb_ep_entry usb_epin_table[6]; +void PIOS_USBHOOK_RegisterEpInCallback(uint8_t epnum, uint16_t max_len, pios_usbhook_epcb cb, uint32_t context) +{ + PIOS_Assert(epnum < NELEMENTS(usb_epin_table)); + PIOS_Assert(cb); + + usb_epin_table[epnum].cb = cb; + usb_epin_table[epnum].context = context; + usb_epin_table[epnum].max_len = max_len; + + DCD_EP_Open(&pios_usb_otg_core_handle, + epnum | 0x80, + max_len, + USB_OTG_EP_INT); + /* + * FIXME do not hardcode endpoint type + */ +} + +extern void PIOS_USBHOOK_DeRegisterEpInCallback(uint8_t epnum) +{ + PIOS_Assert(epnum < NELEMENTS(usb_epin_table)); + + usb_epin_table[epnum].cb = NULL; + + DCD_EP_Close(&pios_usb_otg_core_handle, epnum | 0x80); +} + +static struct usb_ep_entry usb_epout_table[6]; +void PIOS_USBHOOK_RegisterEpOutCallback(uint8_t epnum, uint16_t max_len, pios_usbhook_epcb cb, uint32_t context) +{ + PIOS_Assert(epnum < NELEMENTS(usb_epout_table)); + PIOS_Assert(cb); + + usb_epout_table[epnum].cb = cb; + usb_epout_table[epnum].context = context; + usb_epout_table[epnum].max_len = max_len; + + DCD_EP_Open(&pios_usb_otg_core_handle, + epnum, + max_len, + USB_OTG_EP_INT); + /* + * FIXME do not hardcode endpoint type + */ +} + +extern void PIOS_USBHOOK_DeRegisterEpOutCallback(uint8_t epnum) +{ + PIOS_Assert(epnum < NELEMENTS(usb_epout_table)); + + usb_epout_table[epnum].cb = NULL; + + DCD_EP_Close(&pios_usb_otg_core_handle, epnum); +} + +void PIOS_USBHOOK_CtrlTx(const uint8_t *buf, uint16_t len) +{ + USBD_CtlSendData(&pios_usb_otg_core_handle, buf, len); +} + +void PIOS_USBHOOK_CtrlRx(uint8_t *buf, uint16_t len) +{ + USBD_CtlPrepareRx(&pios_usb_otg_core_handle, buf, len); +} + +void PIOS_USBHOOK_EndpointTx(uint8_t epnum, const uint8_t *buf, uint16_t len) +{ + if (pios_usb_otg_core_handle.dev.device_status == USB_OTG_CONFIGURED) { + DCD_EP_Tx(&pios_usb_otg_core_handle, epnum, buf, len); + } +} + +void PIOS_USBHOOK_EndpointRx(uint8_t epnum, uint8_t *buf, uint16_t len) +{ + DCD_EP_PrepareRx(&pios_usb_otg_core_handle, epnum, buf, len); +} + +/* + * Device level hooks into STM USB library + */ + +static const uint8_t * PIOS_USBHOOK_DEV_GetDeviceDescriptor(uint8_t speed, uint16_t *length) +{ + *length = Device_Descriptor.length; + return Device_Descriptor.descriptor; +} + +static const uint8_t * PIOS_USBHOOK_DEV_GetLangIDStrDescriptor(uint8_t speed, uint16_t *length) +{ + *length = String_Descriptor[USB_STRING_DESC_LANG].length; + return String_Descriptor[USB_STRING_DESC_LANG].descriptor; +} + +static const uint8_t * PIOS_USBHOOK_DEV_GetManufacturerStrDescriptor(uint8_t speed, uint16_t *length) +{ + *length = String_Descriptor[USB_STRING_DESC_VENDOR].length; + return String_Descriptor[USB_STRING_DESC_VENDOR].descriptor; +} + +static const uint8_t * PIOS_USBHOOK_DEV_GetProductStrDescriptor(uint8_t speed, uint16_t *length) +{ + *length = String_Descriptor[USB_STRING_DESC_PRODUCT].length; + return String_Descriptor[USB_STRING_DESC_PRODUCT].descriptor; +} + +static const uint8_t * PIOS_USBHOOK_DEV_GetSerialStrDescriptor(uint8_t speed, uint16_t *length) +{ + *length = String_Descriptor[USB_STRING_DESC_SERIAL].length; + return String_Descriptor[USB_STRING_DESC_SERIAL].descriptor; +} + +static const uint8_t * PIOS_USBHOOK_DEV_GetConfigurationStrDescriptor(uint8_t speed, uint16_t *length) +{ + return NULL; +} + +static const uint8_t * PIOS_USBHOOK_DEV_GetInterfaceStrDescriptor(uint8_t speed, uint16_t *length) +{ + return NULL; +} + +static USBD_DEVICE device_callbacks = { + .GetDeviceDescriptor = PIOS_USBHOOK_DEV_GetDeviceDescriptor, + .GetLangIDStrDescriptor = PIOS_USBHOOK_DEV_GetLangIDStrDescriptor, + .GetManufacturerStrDescriptor = PIOS_USBHOOK_DEV_GetManufacturerStrDescriptor, + .GetProductStrDescriptor = PIOS_USBHOOK_DEV_GetProductStrDescriptor, + .GetSerialStrDescriptor = PIOS_USBHOOK_DEV_GetSerialStrDescriptor, + .GetConfigurationStrDescriptor = PIOS_USBHOOK_DEV_GetConfigurationStrDescriptor, + .GetInterfaceStrDescriptor = PIOS_USBHOOK_DEV_GetInterfaceStrDescriptor, +}; + +static void PIOS_USBHOOK_USR_Init(void) +{ + PIOS_USB_ChangeConnectionState(false); + +#if 1 + /* Force a physical disconnect/reconnect */ + DCD_DevDisconnect(&pios_usb_otg_core_handle); + DCD_DevConnect(&pios_usb_otg_core_handle); +#endif +} + +static void PIOS_USBHOOK_USR_DeviceReset(uint8_t speed) +{ + PIOS_USB_ChangeConnectionState(false); +} + +static void PIOS_USBHOOK_USR_DeviceConfigured(void) +{ + PIOS_USB_ChangeConnectionState(true); +} + +static void PIOS_USBHOOK_USR_DeviceSuspended(void) +{ + /* Unhandled */ +} + +static void PIOS_USBHOOK_USR_DeviceResumed(void) +{ + /* Unhandled */ +} + +static void PIOS_USBHOOK_USR_DeviceConnected(void) +{ + /* NOP */ +} + +static void PIOS_USBHOOK_USR_DeviceDisconnected(void) +{ + PIOS_USB_ChangeConnectionState(false); +} + +static USBD_Usr_cb_TypeDef user_callbacks = { + .Init = PIOS_USBHOOK_USR_Init, + .DeviceReset = PIOS_USBHOOK_USR_DeviceReset, + .DeviceConfigured = PIOS_USBHOOK_USR_DeviceConfigured, + .DeviceSuspended = PIOS_USBHOOK_USR_DeviceSuspended, + .DeviceResumed = PIOS_USBHOOK_USR_DeviceResumed, + .DeviceConnected = PIOS_USBHOOK_USR_DeviceConnected, + .DeviceDisconnected = PIOS_USBHOOK_USR_DeviceDisconnected, +}; + +static uint8_t PIOS_USBHOOK_CLASS_Init(void *pdev, uint8_t cfgidx) +{ + /* Call all of the registered init callbacks */ + for (uint8_t i = 0; i < NELEMENTS(usb_if_table); i++) { + struct usb_if_entry * usb_if = &(usb_if_table[i]); + if (usb_if->ifops && usb_if->ifops->init) { + usb_if->ifops->init(usb_if->context); + } + } + return USBD_OK; +} + +static uint8_t PIOS_USBHOOK_CLASS_DeInit(void *pdev, uint8_t cfgidx) +{ + /* Call all of the registered deinit callbacks */ + for (uint8_t i = 0; i < NELEMENTS(usb_if_table); i++) { + struct usb_if_entry * usb_if = &(usb_if_table[i]); + if (usb_if->ifops && usb_if->ifops->deinit) { + usb_if->ifops->deinit(usb_if->context); + } + } + return USBD_OK; +} + +static struct usb_setup_request usb_ep0_active_req; +static uint8_t PIOS_USBHOOK_CLASS_Setup(void *pdev, USB_SETUP_REQ *req) +{ + switch (req->bmRequest & (USB_REQ_TYPE_MASK | USB_REQ_RECIPIENT_MASK)) { + case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_INTERFACE): + case (USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE): + { + uint8_t ifnum = LOBYTE(req->wIndex); + if ((ifnum < NELEMENTS(usb_if_table)) && + (usb_if_table[ifnum].ifops && usb_if_table[ifnum].ifops->setup)) { + usb_if_table[ifnum].ifops->setup(usb_if_table[ifnum].context, + (struct usb_setup_request *)req); + if (req->bmRequest & 0x80 && req->wLength > 0) { + /* Request is a host-to-device data setup packet, keep track of the request details for the EP0_RxRead call */ + usb_ep0_active_req.bmRequestType = req->bmRequest; + usb_ep0_active_req.bRequest = req->bRequest; + usb_ep0_active_req.wValue = req->wValue; + usb_ep0_active_req.wIndex = req->wIndex; + usb_ep0_active_req.wLength = req->wLength; + } + } else { + /* No Setup handler or Setup handler failed */ + USBD_CtlError (&pios_usb_otg_core_handle, req); + } + break; + } + default: + /* Unhandled Setup */ + USBD_CtlError (&pios_usb_otg_core_handle, req); + break; + } + + return USBD_OK; +} + +static uint8_t PIOS_USBHOOK_CLASS_EP0_TxSent(void *pdev) +{ + return USBD_OK; +} + +static uint8_t PIOS_USBHOOK_CLASS_EP0_RxReady(void *pdev) +{ + uint8_t ifnum = LOBYTE(usb_ep0_active_req.wIndex); + + if ((ifnum < NELEMENTS(usb_if_table)) && + (usb_if_table[ifnum].ifops && usb_if_table[ifnum].ifops->ctrl_data_out)) { + usb_if_table[ifnum].ifops->ctrl_data_out(usb_if_table[ifnum].context, + &usb_ep0_active_req); + } + + return USBD_OK; +} + +static uint8_t PIOS_USBHOOK_CLASS_DataIn(void *pdev, uint8_t epnum) +{ + /* Make sure the previous transfer has completed before starting a new one */ + DCD_EP_Flush(pdev, epnum); /* NOT SURE IF THIS IS REQUIRED */ + + /* Remove the direction bit so we can use this as an index */ + epnum = epnum & 0xF; + + if ((epnum < NELEMENTS(usb_epin_table)) && usb_epin_table[epnum].cb) { + struct usb_ep_entry *ep = &(usb_epin_table[epnum]); + ep->cb(ep->context, epnum, ep->max_len); + } + + return USBD_OK; +} + +static uint8_t PIOS_USBHOOK_CLASS_DataOut(void *pdev, uint8_t epnum) +{ + /* Remove the direction bit so we can use this as an index */ + epnum = epnum & 0xF; + + if ((epnum < NELEMENTS(usb_epout_table)) && usb_epout_table[epnum].cb) { + struct usb_ep_entry *ep = &(usb_epout_table[epnum]); + ep->cb(ep->context, epnum, ep->max_len); + } + + return USBD_OK; +} + +static uint8_t PIOS_USBHOOK_CLASS_SOF(void *pdev) +{ + return USBD_OK; +} + +static uint8_t PIOS_USBHOOK_CLASS_IsoINIncomplete(void *pdev) +{ + return USBD_OK; +} + +static uint8_t PIOS_USBHOOK_CLASS_IsoOUTIncomplete(void *pdev) +{ + return USBD_OK; +} + +static const uint8_t * PIOS_USBHOOK_CLASS_GetConfigDescriptor(uint8_t speed, uint16_t *length) +{ + *length = Config_Descriptor.length; + return Config_Descriptor.descriptor; +} + +#ifdef USB_OTG_HS_CORE +static const uint8_t * PIOS_USBHOOK_CLASS_GetOtherConfigDescriptor(uint8_t speed, uint16_t *length) +{ + return PIOS_USBHOOK_CLASS_GetConfigDescriptor(speed, length); +} +#endif /* USB_OTG_HS_CORE */ + +#ifdef USB_SUPPORT_USER_STRING_DESC +static const uint8_t * PIOS_USBHOOK_CLASS_GetUsrStrDescriptor(uint8_t speed, uint8_t index, uint16_t *length) +{ + return NULL; +} +#endif /* USB_SUPPORT_USER_STRING_DESC */ + +static USBD_Class_cb_TypeDef class_callbacks = { + .Init = PIOS_USBHOOK_CLASS_Init, + .DeInit = PIOS_USBHOOK_CLASS_DeInit, + .Setup = PIOS_USBHOOK_CLASS_Setup, + .EP0_TxSent = PIOS_USBHOOK_CLASS_EP0_TxSent, + .EP0_RxReady = PIOS_USBHOOK_CLASS_EP0_RxReady, + .DataIn = PIOS_USBHOOK_CLASS_DataIn, + .DataOut = PIOS_USBHOOK_CLASS_DataOut, + .SOF = PIOS_USBHOOK_CLASS_SOF, + .IsoINIncomplete = PIOS_USBHOOK_CLASS_IsoINIncomplete, + .IsoOUTIncomplete = PIOS_USBHOOK_CLASS_IsoOUTIncomplete, + .GetConfigDescriptor = PIOS_USBHOOK_CLASS_GetConfigDescriptor, +#ifdef USB_OTG_HS_CORE + .GetOtherConfigDescriptor = PIOS_USBHOOK_CLASS_GetOtherConfigDescriptor, +#endif /* USB_OTG_HS_CORE */ +#ifdef USB_SUPPORT_USER_STRING_DESC + .GetUsrStrDescriptor = PIOS_USBHOOK_CLASS_GetUsrStrDescriptor, +#endif /* USB_SUPPORT_USER_STRING_DESC */ +}; + +#if 0 +#include "stm32f10x.h" /* __IO */ +__IO uint8_t EXTI_Enable; + +uint32_t ProtocolValue; + +DEVICE Device_Table = { + PIOS_USB_BOARD_EP_NUM, + 1 +}; + +static void PIOS_USBHOOK_Init(void); +static void PIOS_USBHOOK_Reset(void); +static void PIOS_USBHOOK_Status_In(void); +static void PIOS_USBHOOK_Status_Out(void); +static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo); +static RESULT PIOS_USBHOOK_NoData_Setup(uint8_t RequestNo); +static RESULT PIOS_USBHOOK_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting); +static const uint8_t *PIOS_USBHOOK_GetDeviceDescriptor(uint16_t Length); +static const uint8_t *PIOS_USBHOOK_GetConfigDescriptor(uint16_t Length); +static const uint8_t *PIOS_USBHOOK_GetStringDescriptor(uint16_t Length); + +DEVICE_PROP Device_Property = { + .Init = PIOS_USBHOOK_Init, + .Reset = PIOS_USBHOOK_Reset, + .Process_Status_IN = PIOS_USBHOOK_Status_In, + .Process_Status_OUT = PIOS_USBHOOK_Status_Out, + .Class_Data_Setup = PIOS_USBHOOK_Data_Setup, + .Class_NoData_Setup = PIOS_USBHOOK_NoData_Setup, + .Class_Get_Interface_Setting = PIOS_USBHOOK_Get_Interface_Setting, + .GetDeviceDescriptor = PIOS_USBHOOK_GetDeviceDescriptor, + .GetConfigDescriptor = PIOS_USBHOOK_GetConfigDescriptor, + .GetStringDescriptor = PIOS_USBHOOK_GetStringDescriptor, + .RxEP_buffer = 0, + .MaxPacketSize = 0x40, +}; + +static void PIOS_USBHOOK_SetConfiguration(void); +static void PIOS_USBHOOK_SetDeviceAddress(void); + +USER_STANDARD_REQUESTS User_Standard_Requests = { + .User_GetConfiguration = NOP_Process, + .User_SetConfiguration = PIOS_USBHOOK_SetConfiguration, + .User_GetInterface = NOP_Process, + .User_SetInterface = NOP_Process, + .User_GetStatus = NOP_Process, + .User_ClearFeature = NOP_Process, + .User_SetEndPointFeature = NOP_Process, + .User_SetDeviceFeature = NOP_Process, + .User_SetDeviceAddress = PIOS_USBHOOK_SetDeviceAddress +}; + +static RESULT PIOS_USBHOOK_SetProtocol(void); +static const uint8_t *PIOS_USBHOOK_GetProtocolValue(uint16_t Length); +static const uint8_t *PIOS_USBHOOK_GetReportDescriptor(uint16_t Length); +static const uint8_t *PIOS_USBHOOK_GetHIDDescriptor(uint16_t Length); + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_Init. +* Description : Custom HID init routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void PIOS_USBHOOK_Init(void) +{ + pInformation->Current_Configuration = 0; + + /* Connect the device */ + PowerOn(); + + /* Perform basic device initialization operations */ + USB_SIL_Init(); + + bDeviceState = UNCONNECTED; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_Reset. +* Description : Custom HID reset routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void PIOS_USBHOOK_Reset(void) +{ + /* Set DEVICE as not configured */ + pInformation->Current_Configuration = 0; + pInformation->Current_Interface = 0; /*the default Interface */ + + /* Current Feature initialization */ + pInformation->Current_Feature = 0; + +#ifdef STM32F10X_CL + /* EP0 is already configured in DFU_Init() by USB_SIL_Init() function */ + + /* Init EP1 IN as Interrupt endpoint */ + OTG_DEV_EP_Init(EP1_IN, OTG_DEV_EP_TYPE_INT, 2); + + /* Init EP1 OUT as Interrupt endpoint */ + OTG_DEV_EP_Init(EP1_OUT, OTG_DEV_EP_TYPE_INT, 2); +#else + SetBTABLE(BTABLE_ADDRESS); + + /* Initialize Endpoint 0 (Control) */ + SetEPType(ENDP0, EP_CONTROL); + SetEPTxAddr(ENDP0, ENDP0_TXADDR); + SetEPTxStatus(ENDP0, EP_TX_STALL); + Clear_Status_Out(ENDP0); + + SetEPRxAddr(ENDP0, ENDP0_RXADDR); + SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); + SetEPRxValid(ENDP0); + +#if defined(PIOS_INCLUDE_USB_HID) + /* Initialize Endpoint 1 (HID) */ + SetEPType(ENDP1, EP_INTERRUPT); + SetEPTxAddr(ENDP1, ENDP1_TXADDR); + SetEPTxCount(ENDP1, PIOS_USB_BOARD_HID_DATA_LENGTH); + SetEPTxStatus(ENDP1, EP_TX_NAK); + + SetEPRxAddr(ENDP1, ENDP1_RXADDR); + SetEPRxCount(ENDP1, PIOS_USB_BOARD_HID_DATA_LENGTH); + SetEPRxStatus(ENDP1, EP_RX_VALID); +#endif /* PIOS_INCLUDE_USB_HID */ + +#if defined(PIOS_INCLUDE_USB_CDC) + /* Initialize Endpoint 2 (CDC Call Control) */ + SetEPType(ENDP2, EP_INTERRUPT); + SetEPTxAddr(ENDP2, ENDP2_TXADDR); + SetEPTxStatus(ENDP2, EP_TX_NAK); + + SetEPRxAddr(ENDP2, ENDP2_RXADDR); + SetEPRxCount(ENDP2, PIOS_USB_BOARD_CDC_MGMT_LENGTH); + SetEPRxStatus(ENDP2, EP_RX_DIS); + + /* Initialize Endpoint 3 (CDC Data) */ + SetEPType(ENDP3, EP_BULK); + SetEPTxAddr(ENDP3, ENDP3_TXADDR); + SetEPTxStatus(ENDP3, EP_TX_NAK); + + SetEPRxAddr(ENDP3, ENDP3_RXADDR); + SetEPRxCount(ENDP3, PIOS_USB_BOARD_CDC_DATA_LENGTH); + SetEPRxStatus(ENDP3, EP_RX_VALID); + +#endif /* PIOS_INCLUDE_USB_CDC */ + + /* Set this device to response on default address */ + SetDeviceAddress(0); +#endif /* STM32F10X_CL */ + + bDeviceState = ATTACHED; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_SetConfiguration. +* Description : Update the device state to configured +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void PIOS_USBHOOK_SetConfiguration(void) +{ + if (pInformation->Current_Configuration != 0) { + /* Device configured */ + bDeviceState = CONFIGURED; + } + + /* Enable transfers */ + PIOS_USB_ChangeConnectionState(pInformation->Current_Configuration != 0); +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_SetConfiguration. +* Description : Update the device state to addressed. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void PIOS_USBHOOK_SetDeviceAddress(void) +{ + bDeviceState = ADDRESSED; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_Status_In. +* Description : status IN routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void PIOS_USBHOOK_Status_In(void) +{ +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_Status_Out +* Description : status OUT routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void PIOS_USBHOOK_Status_Out(void) +{ +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_Data_Setup +* Description : Handle the data class specific requests. +* Input : Request Nb. +* Output : None. +* Return : USB_UNSUPPORT or USB_SUCCESS. +*******************************************************************************/ +static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo) +{ + const uint8_t *(*CopyRoutine) (uint16_t); + + CopyRoutine = NULL; + + switch (Type_Recipient) { + case (STANDARD_REQUEST | INTERFACE_RECIPIENT): + switch (pInformation->USBwIndex0) { + case 0: /* HID Interface */ + switch (RequestNo) { + case GET_DESCRIPTOR: + switch (pInformation->USBwValue1) { + case USB_DESC_TYPE_REPORT: + CopyRoutine = PIOS_USBHOOK_GetReportDescriptor; + break; + case USB_DESC_TYPE_HID: + CopyRoutine = PIOS_USBHOOK_GetHIDDescriptor; + break; + } + } + } + break; + + case (CLASS_REQUEST | INTERFACE_RECIPIENT): + switch (pInformation->USBwIndex0) { + case 0: /* HID Interface */ + switch (RequestNo) { + case GET_PROTOCOL: + CopyRoutine = PIOS_USBHOOK_GetProtocolValue; + break; + } + + break; +#if defined(PIOS_INCLUDE_USB_CDC) + case 1: /* CDC Call Control Interface */ + switch (RequestNo) { + case GET_LINE_CODING: + CopyRoutine = PIOS_USB_CDC_GetLineCoding; + break; + } + + break; + + case 2: /* CDC Data Interface */ + switch (RequestNo) { + case 0: + break; + } + + break; +#endif /* PIOS_INCLUDE_USB_CDC */ + } + break; + } + + if (CopyRoutine == NULL) { + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyDataIn = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine) (0); + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_NoData_Setup +* Description : handle the no data class specific requests +* Input : Request Nb. +* Output : None. +* Return : USB_UNSUPPORT or USB_SUCCESS. +*******************************************************************************/ +static RESULT PIOS_USBHOOK_NoData_Setup(uint8_t RequestNo) +{ + switch (Type_Recipient) { + case (CLASS_REQUEST | INTERFACE_RECIPIENT): + switch (pInformation->USBwIndex0) { + case 0: /* HID */ + switch (RequestNo) { + case SET_PROTOCOL: + return PIOS_USBHOOK_SetProtocol(); + break; + } + + break; + +#if defined(PIOS_INCLUDE_USB_CDC) + case 1: /* CDC Call Control Interface */ + switch (RequestNo) { + case SET_LINE_CODING: + return PIOS_USB_CDC_SetLineCoding(); + break; + case SET_CONTROL_LINE_STATE: + return PIOS_USB_CDC_SetControlLineState(); + break; + } + + break; +#endif /* PIOS_INCLUDE_USB_CDC */ + } + + break; + } + + return USB_UNSUPPORT; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_GetDeviceDescriptor. +* Description : Gets the device descriptor. +* Input : Length +* Output : None. +* Return : The address of the device descriptor. +*******************************************************************************/ +static const uint8_t *PIOS_USBHOOK_GetDeviceDescriptor(uint16_t Length) +{ + return Standard_GetDescriptorData(Length, &Device_Descriptor); +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_GetConfigDescriptor. +* Description : Gets the configuration descriptor. +* Input : Length +* Output : None. +* Return : The address of the configuration descriptor. +*******************************************************************************/ +static const uint8_t *PIOS_USBHOOK_GetConfigDescriptor(uint16_t Length) +{ + return Standard_GetDescriptorData(Length, &Config_Descriptor); +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_GetStringDescriptor +* Description : Gets the string descriptors according to the needed index +* Input : Length +* Output : None. +* Return : The address of the string descriptors. +*******************************************************************************/ +static const uint8_t *PIOS_USBHOOK_GetStringDescriptor(uint16_t Length) +{ + uint8_t wValue0 = pInformation->USBwValue0; + if (wValue0 > 4) { + return NULL; + } else { + return Standard_GetDescriptorData(Length, &String_Descriptor[wValue0]); + } +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_GetReportDescriptor. +* Description : Gets the HID report descriptor. +* Input : Length +* Output : None. +* Return : The address of the configuration descriptor. +*******************************************************************************/ +static const uint8_t *PIOS_USBHOOK_GetReportDescriptor(uint16_t Length) +{ + return Standard_GetDescriptorData(Length, &Hid_Report_Descriptor); +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_GetHIDDescriptor. +* Description : Gets the HID descriptor. +* Input : Length +* Output : None. +* Return : The address of the configuration descriptor. +*******************************************************************************/ +static const uint8_t *PIOS_USBHOOK_GetHIDDescriptor(uint16_t Length) +{ + return Standard_GetDescriptorData(Length, &Hid_Interface_Descriptor); +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_Get_Interface_Setting. +* Description : tests the interface and the alternate setting according to the +* supported one. +* Input : - Interface : interface number. +* - AlternateSetting : Alternate Setting number. +* Output : None. +* Return : USB_SUCCESS or USB_UNSUPPORT. +*******************************************************************************/ +static RESULT PIOS_USBHOOK_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting) +{ + if (AlternateSetting > 0) { + return USB_UNSUPPORT; + } else if (Interface > 0) { + return USB_UNSUPPORT; + } + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_SetProtocol +* Description : Set Protocol request routine. +* Input : None. +* Output : None. +* Return : USB SUCCESS. +*******************************************************************************/ +static RESULT PIOS_USBHOOK_SetProtocol(void) +{ + uint8_t wValue0 = pInformation->USBwValue0; + ProtocolValue = wValue0; + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_GetProtocolValue +* Description : get the protocol value +* Input : Length. +* Output : None. +* Return : address of the protcol value. +*******************************************************************************/ +static const uint8_t *PIOS_USBHOOK_GetProtocolValue(uint16_t Length) +{ + if (Length == 0) { + pInformation->Ctrl_Info.Usb_wLength = 1; + return NULL; + } else { + return (uint8_t *) (&ProtocolValue); + } +} + +/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ +#endif diff --git a/flight/PiOS/inc/pios_usb.h b/flight/PiOS/inc/pios_usb.h index 1c6347a0d..76b8f01b4 100644 --- a/flight/PiOS/inc/pios_usb.h +++ b/flight/PiOS/inc/pios_usb.h @@ -30,9 +30,11 @@ #ifndef PIOS_USB_H #define PIOS_USB_H +#include + /* Global functions */ extern int32_t PIOS_USB_Reenumerate(); -extern int32_t PIOS_USB_ChangeConnectionState(uint32_t Connected); +extern int32_t PIOS_USB_ChangeConnectionState(bool connected); extern bool PIOS_USB_CheckAvailable(uint8_t id); #endif /* PIOS_USB_H */ diff --git a/flight/PiOS/inc/pios_usb_cdc_priv.h b/flight/PiOS/inc/pios_usb_cdc_priv.h index 74d6e347d..b87bd50cc 100644 --- a/flight/PiOS/inc/pios_usb_cdc_priv.h +++ b/flight/PiOS/inc/pios_usb_cdc_priv.h @@ -31,8 +31,6 @@ #ifndef PIOS_USB_CDC_PRIV_H #define PIOS_USB_CDC_PRIV_H -#include "usb_core.h" /* RESULT */ - struct pios_usb_cdc_cfg { uint8_t ctrl_if; uint8_t ctrl_tx_ep; @@ -46,10 +44,6 @@ extern const struct pios_com_driver pios_usb_cdc_com_driver; extern int32_t PIOS_USB_CDC_Init(uint32_t * usbcdc_id, const struct pios_usb_cdc_cfg * cfg, uint32_t lower_id); -extern const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length); -extern RESULT PIOS_USB_CDC_SetControlLineState(void); -extern RESULT PIOS_USB_CDC_SetLineCoding(void); - #endif /* PIOS_USB_CDC_PRIV_H */ /** diff --git a/flight/PiOS/inc/pios_usb_defs.h b/flight/PiOS/inc/pios_usb_defs.h index 2e63a8fa4..f0352333f 100644 --- a/flight/PiOS/inc/pios_usb_defs.h +++ b/flight/PiOS/inc/pios_usb_defs.h @@ -219,6 +219,57 @@ struct usb_endpoint_desc { uint8_t bInterval; } __attribute__((packed)); +struct usb_setup_request { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} __attribute__((packed)); + +#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 + +enum usb_standard_requests { + USB_REQ_GET_STATUS = 0x00, + USB_REQ_CLEAR_FEATURE = 0x01, + /* what is 0x02? */ + USB_REQ_SET_FEATURE = 0x03, + /* what is 0x04? */ + USB_REQ_SET_ADDRESS = 0x05, + USB_REQ_GET_DESCRIPTOR = 0x06, + USB_REQ_SET_DESCRIPTOR = 0x07, + USB_REQ_GET_CONFIGURATION = 0x08, + USB_REQ_SET_CONFIGURATION = 0x09, + USB_REQ_GET_INTERFACE = 0x0A, + USB_REQ_SET_INTERFACE = 0x0B, + USB_REQ_SYNCH_FRAME = 0x0C, +}; + +enum usb_hid_requests { + USB_HID_REQ_GET_REPORT = 0x01, + USB_HID_REQ_GET_IDLE = 0x02, + USB_HID_REQ_GET_PROTOCOL = 0x03, + /* 0x04-0x08 Reserved */ + USB_HID_REQ_SET_REPORT = 0x09, + USB_HID_REQ_SET_IDLE = 0x0A, + USB_HID_REQ_SET_PROTOCOL = 0x0B, +}; + +enum usb_cdc_requests { + USB_CDC_REQ_SET_LINE_CODING = 0x20, + USB_CDC_REQ_GET_LINE_CODING = 0x21, + + USB_CDC_REQ_SET_CONTROL_LINE_STATE = 0x23, +}; + struct usb_cdc_header_func_desc { uint8_t bLength; uint8_t bDescriptorType; @@ -301,6 +352,10 @@ enum usb_product_ids { USB_PRODUCT_ID_OPENPILOT_MAIN = 0x415A, USB_PRODUCT_ID_COPTERCONTROL = 0x415B, USB_PRODUCT_ID_PIPXTREME = 0x415C, + USB_PRODUCT_ID_CC3D = 0x415D, + USB_PRODUCT_ID_REVOLUTION = 0x415E, + USB_PRODUCT_ID_OSD = 0x4194, + USB_PRODUCT_ID_SPARE = 0x4195, } __attribute__((packed)); enum usb_op_board_ids { @@ -308,6 +363,7 @@ enum usb_op_board_ids { /* Board ID 2 may be unused or AHRS */ USB_OP_BOARD_ID_PIPXTREME = 3, USB_OP_BOARD_ID_COPTERCONTROL = 4, + USB_OP_BOARD_ID_REVOLUTION = 5, } __attribute__((packed)); enum usb_op_board_modes { diff --git a/flight/PiOS/inc/pios_usb_hid.h b/flight/PiOS/inc/pios_usb_hid.h index 7a7409631..3fc5f81b1 100644 --- a/flight/PiOS/inc/pios_usb_hid.h +++ b/flight/PiOS/inc/pios_usb_hid.h @@ -31,10 +31,13 @@ #define PIOS_USB_HID_H /* Global functions */ -extern int32_t PIOS_USB_HID_Reenumerate(); +extern int32_t PIOS_USB_HID_Reenumerate(void); extern int32_t PIOS_USB_HID_ChangeConnectionState(uint32_t Connected); extern bool PIOS_USB_HID_CheckAvailable(uint8_t id); +extern void PIOS_USB_HID_RegisterHidInterface(const uint8_t * desc, uint16_t length); +extern void PIOS_USB_HID_RegisterHidReport(const uint8_t * desc, uint16_t length); + #endif /* PIOS_USB_HID_H */ /** diff --git a/flight/PiOS/inc/pios_usb_hid_priv.h b/flight/PiOS/inc/pios_usb_hid_priv.h index ac638cd54..fba585c18 100644 --- a/flight/PiOS/inc/pios_usb_hid_priv.h +++ b/flight/PiOS/inc/pios_usb_hid_priv.h @@ -31,8 +31,6 @@ #ifndef PIOS_USB_HID_PRIV_H #define PIOS_USB_HID_PRIV_H -#include "usb_core.h" /* RESULT */ - struct pios_usb_hid_cfg { uint8_t data_if; uint8_t data_rx_ep; diff --git a/flight/PiOS/inc/pios_usb_hid_pwr.h b/flight/PiOS/inc/pios_usb_hid_pwr.h index c44f4164c..614344437 100644 --- a/flight/PiOS/inc/pios_usb_hid_pwr.h +++ b/flight/PiOS/inc/pios_usb_hid_pwr.h @@ -17,6 +17,8 @@ #ifndef __USB_PWR_H #define __USB_PWR_H +#include "usb_core.h" + /* Includes ------------------------------------------------------------------*/ /* Exported types ------------------------------------------------------------*/ typedef enum _RESUME_STATE { diff --git a/flight/PiOS/inc/pios_usbhook.h b/flight/PiOS/inc/pios_usbhook.h index f005a6fa1..39999919c 100644 --- a/flight/PiOS/inc/pios_usbhook.h +++ b/flight/PiOS/inc/pios_usbhook.h @@ -31,21 +31,14 @@ #ifndef PIOS_USBHOOK_H #define PIOS_USBHOOK_H -typedef enum _HID_REQUESTS { - GET_REPORT = 1, - GET_IDLE, - GET_PROTOCOL, +#include +#include +#include "pios_usb_defs.h" /* usb_setup_request */ - SET_REPORT = 9, - SET_IDLE, - SET_PROTOCOL -} HID_REQUESTS; - -typedef enum CDC_REQUESTS { - SET_LINE_CODING = 0x20, - GET_LINE_CODING = 0x21, - SET_CONTROL_LINE_STATE = 0x23, -} CDC_REQUESTS; +struct pios_usbhook_descriptor { + const uint8_t * descriptor; + uint16_t length; +}; enum usb_string_desc { USB_STRING_DESC_LANG = 0, @@ -57,8 +50,28 @@ enum usb_string_desc { extern void PIOS_USBHOOK_RegisterDevice(const uint8_t * desc, uint16_t desc_size); extern void PIOS_USBHOOK_RegisterConfig(uint8_t config_id, const uint8_t * desc, uint16_t desc_size); extern void PIOS_USBHOOK_RegisterString(enum usb_string_desc string_id, const uint8_t * desc, uint16_t desc_size); -extern void PIOS_USBHOOK_RegisterHidInterface(const uint8_t * desc, uint16_t desc_size); -extern void PIOS_USBHOOK_RegisterHidReport(const uint8_t * desc, uint16_t desc_size); + +struct pios_usb_ifops { + void (*init)(uint32_t context); + void (*deinit)(uint32_t context); + bool (*setup)(uint32_t context, struct usb_setup_request * req); + void (*ctrl_data_out)(uint32_t context, struct usb_setup_request * req); +}; + +extern void PIOS_USBHOOK_RegisterIfOps(uint8_t ifnum, struct pios_usb_ifops * ifops, uint32_t context); + +typedef bool (*pios_usbhook_epcb)(uint32_t context, uint8_t epnum, uint16_t len); + +extern void PIOS_USBHOOK_RegisterEpInCallback(uint8_t epnum, uint16_t max_len, pios_usbhook_epcb cb, uint32_t context); +extern void PIOS_USBHOOK_RegisterEpOutCallback(uint8_t epnum, uint16_t max_len, pios_usbhook_epcb cb, uint32_t context); +extern void PIOS_USBHOOK_DeRegisterEpInCallback(uint8_t epnum); +extern void PIOS_USBHOOK_DeRegisterEpOutCallback(uint8_t epnum); + +extern void PIOS_USBHOOK_CtrlTx(const uint8_t *buf, uint16_t len); +extern void PIOS_USBHOOK_CtrlRx(uint8_t *buf, uint16_t len); +extern void PIOS_USBHOOK_EndpointTx(uint8_t epnum, const uint8_t *buf, uint16_t len); +extern void PIOS_USBHOOK_EndpointRx(uint8_t epnum, uint8_t *buf, uint16_t len); +extern void PIOS_USBHOOK_Activate(void); #endif /* PIOS_USBHOOK_H */ diff --git a/flight/PiOS/pios.h b/flight/PiOS/pios.h index d955b3a0c..87149033f 100644 --- a/flight/PiOS/pios.h +++ b/flight/PiOS/pios.h @@ -149,8 +149,6 @@ #endif #if defined(PIOS_INCLUDE_USB) -/* USB Libs */ -#include #include #endif diff --git a/flight/Project/OpenOCD/stm32f4xx.stlink.cfg b/flight/Project/OpenOCD/stm32f4xx.stlink.cfg index 3d55f6da5..04f8958e2 100644 --- a/flight/Project/OpenOCD/stm32f4xx.stlink.cfg +++ b/flight/Project/OpenOCD/stm32f4xx.stlink.cfg @@ -30,5 +30,5 @@ target create $_TARGETNAME stm32_stlink -chain-position $_TARGETNAME -rtos auto $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32f2x 0x08000000 0 0 0 $_TARGETNAME +#set _FLASHNAME $_CHIPNAME.flash +#flash bank $_FLASHNAME stm32f2x 0x08000000 0 0 0 $_TARGETNAME diff --git a/flight/Revolution/Makefile b/flight/Revolution/Makefile index 48de773fb..407ca2a79 100644 --- a/flight/Revolution/Makefile +++ b/flight/Revolution/Makefile @@ -117,6 +117,7 @@ SRC += ${foreach MOD, ${MODULES}, ${wildcard ${OPMODULEDIR}/${MOD}/*.c}} SRC += ${OPMODULEDIR}/System/systemmod.c SRC += $(OPSYSTEM)/revolution.c SRC += $(OPSYSTEM)/pios_board.c +SRC += $(OPSYSTEM)/pios_usb_board_data.c SRC += $(OPSYSTEM)/alarms.c SRC += $(OPUAVTALK)/uavtalk.c SRC += $(OPUAVOBJ)/uavobjectmanager.c @@ -148,6 +149,8 @@ SRC += $(PIOSCOMMON)/pios_rcvr.c SRC += $(PIOSCOMMON)/pios_flash_jedec.c SRC += $(PIOSCOMMON)/pios_flashfs_objlist.c SRC += $(PIOSCOMMON)/printf-stdarg.c +SRC += $(PIOSCOMMON)/pios_usb_desc_hid_cdc.c +SRC += $(PIOSCOMMON)/pios_usb_desc_hid_only.c include ./UAVObjects.inc SRC += $(UAVOBJSRC) @@ -312,7 +315,7 @@ ifeq ($(CODE_SOURCERY), YES) CFLAGS += -fpromote-loop-indices endif -#CFLAGS += -Wall +CFLAGS += -Wall #CFLAGS += -Werror CFLAGS += -Wa,-adhlns=$(addprefix $(OUTDIR)/, $(notdir $(addsuffix .lst, $(basename $<)))) # Compiler flags to generate dependency files: diff --git a/flight/Revolution/System/inc/pios_config.h b/flight/Revolution/System/inc/pios_config.h index 135d879b9..54c05773b 100644 --- a/flight/Revolution/System/inc/pios_config.h +++ b/flight/Revolution/System/inc/pios_config.h @@ -49,7 +49,8 @@ #define PIOS_INCLUDE_SPI #define PIOS_INCLUDE_SYS #define PIOS_INCLUDE_USART -//#define PIOS_INCLUDE_USB_HID +#define PIOS_INCLUDE_USB +#define PIOS_INCLUDE_USB_HID //#define PIOS_INCLUDE_GPIO #define PIOS_INCLUDE_EXTI #define PIOS_INCLUDE_RTC diff --git a/flight/Revolution/System/inc/pios_usb_board_data.h b/flight/Revolution/System/inc/pios_usb_board_data.h new file mode 100644 index 000000000..dbd111134 --- /dev/null +++ b/flight/Revolution/System/inc/pios_usb_board_data.h @@ -0,0 +1,45 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_BOARD Board specific USB definitions + * @brief Board specific USB definitions + * @{ + * + * @file pios_usb_board_data.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Board specific USB definitions + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_USB_BOARD_DATA_H +#define PIOS_USB_BOARD_DATA_H + +#define PIOS_USB_BOARD_CDC_DATA_LENGTH 64 +#define PIOS_USB_BOARD_CDC_MGMT_LENGTH 32 +#define PIOS_USB_BOARD_HID_DATA_LENGTH 64 + +#define PIOS_USB_BOARD_EP_NUM 4 + +#include "pios_usb_defs.h" /* USB_* macros */ + +#define PIOS_USB_BOARD_PRODUCT_ID USB_PRODUCT_ID_REVOLUTION +#define PIOS_USB_BOARD_DEVICE_VER USB_OP_DEVICE_VER(USB_OP_BOARD_ID_REVOLUTION, USB_OP_BOARD_MODE_FW) + +#endif /* PIOS_USB_BOARD_DATA_H */ diff --git a/flight/Revolution/System/pios_board.c b/flight/Revolution/System/pios_board.c index 19c0608a2..b3a0e9f0c 100644 --- a/flight/Revolution/System/pios_board.c +++ b/flight/Revolution/System/pios_board.c @@ -251,6 +251,12 @@ uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; #define PIOS_COM_GPS_RX_BUF_LEN 32 +#define PIOS_COM_TELEM_USB_RX_BUF_LEN 65 +#define PIOS_COM_TELEM_USB_TX_BUF_LEN 65 + +#define PIOS_COM_BRIDGE_RX_BUF_LEN 65 +#define PIOS_COM_BRIDGE_TX_BUF_LEN 12 + uint32_t pios_com_aux_id; uint32_t pios_com_gps_id; uint32_t pios_com_telem_usb_id; @@ -321,7 +327,137 @@ void PIOS_Board_Init(void) { /* IAP System Setup */ //PIOS_IAP_Init(); - + +#if defined(PIOS_INCLUDE_USB) + /* Initialize board specific USB data */ + PIOS_USB_BOARD_DATA_Init(); + + /* Flags to determine if various USB interfaces are advertised */ + bool usb_hid_present = false; + bool usb_cdc_present = false; + + uint8_t hwsettings_usb_devicetype; + HwSettingsUSB_DeviceTypeGet(&hwsettings_usb_devicetype); + + switch (hwsettings_usb_devicetype) { + case HWSETTINGS_USB_DEVICETYPE_HIDONLY: + if (PIOS_USB_DESC_HID_ONLY_Init()) { + PIOS_Assert(0); + } + usb_hid_present = true; + break; + case HWSETTINGS_USB_DEVICETYPE_HIDVCP: + if (PIOS_USB_DESC_HID_CDC_Init()) { + PIOS_Assert(0); + } + usb_hid_present = true; + usb_cdc_present = true; + break; + case HWSETTINGS_USB_DEVICETYPE_VCPONLY: + break; + default: + PIOS_Assert(0); + } + + uint32_t pios_usb_id; + PIOS_USB_Init(&pios_usb_id, &pios_usb_main_cfg); + +#if defined(PIOS_INCLUDE_USB_CDC) + + uint8_t hwsettings_usb_vcpport; + /* Configure the USB VCP port */ + HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); + + if (!usb_cdc_present) { + /* Force VCP port function to disabled if we haven't advertised VCP in our USB descriptor */ + hwsettings_usb_vcpport = HWSETTINGS_USB_VCPPORT_DISABLED; + } + + switch (hwsettings_usb_vcpport) { + case HWSETTINGS_USB_VCPPORT_DISABLED: + break; + case HWSETTINGS_USB_VCPPORT_USBTELEMETRY: +#if defined(PIOS_INCLUDE_COM) + { + uint32_t pios_usb_cdc_id; + if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { + PIOS_Assert(0); + } + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); + uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); + PIOS_Assert(rx_buffer); + PIOS_Assert(tx_buffer); + if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, + rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, + tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_COM */ + break; + case HWSETTINGS_USB_VCPPORT_COMBRIDGE: +#if defined(PIOS_INCLUDE_COM) + { + uint32_t pios_usb_cdc_id; + if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { + PIOS_Assert(0); + } + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_BRIDGE_RX_BUF_LEN); + uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_BRIDGE_TX_BUF_LEN); + PIOS_Assert(rx_buffer); + PIOS_Assert(tx_buffer); + if (PIOS_COM_Init(&pios_com_vcp_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, + rx_buffer, PIOS_COM_BRIDGE_RX_BUF_LEN, + tx_buffer, PIOS_COM_BRIDGE_TX_BUF_LEN)) { + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_COM */ + break; + } +#endif /* PIOS_INCLUDE_USB_CDC */ + +#if defined(PIOS_INCLUDE_USB_HID) + /* Configure the usb HID port */ + uint8_t hwsettings_usb_hidport; + HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); + + if (!usb_hid_present) { + /* Force HID port function to disabled if we haven't advertised HID in our USB descriptor */ + hwsettings_usb_hidport = HWSETTINGS_USB_HIDPORT_DISABLED; + } + + switch (hwsettings_usb_hidport) { + case HWSETTINGS_USB_HIDPORT_DISABLED: + break; + case HWSETTINGS_USB_HIDPORT_USBTELEMETRY: +#if defined(PIOS_INCLUDE_COM) + { + uint32_t pios_usb_hid_id; + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { + PIOS_Assert(0); + } + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); + uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); + PIOS_Assert(rx_buffer); + PIOS_Assert(tx_buffer); + if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id, + rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, + tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_COM */ + break; + } + +#endif /* PIOS_INCLUDE_USB_HID */ + + if (usb_hid_present || usb_cdc_present) { + PIOS_USBHOOK_Activate(); + } +#endif /* PIOS_INCLUDE_USB */ + #if defined(PIOS_INCLUDE_COM) #if defined(PIOS_INCLUDE_GPS) diff --git a/flight/Revolution/System/pios_usb_board_data.c b/flight/Revolution/System/pios_usb_board_data.c new file mode 100644 index 000000000..823496c29 --- /dev/null +++ b/flight/Revolution/System/pios_usb_board_data.c @@ -0,0 +1,120 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_BOARD Board specific USB definitions + * @brief Board specific USB definitions + * @{ + * + * @file pios_usb_board_data.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Board specific USB definitions + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "pios_usb_board_data.h" /* struct usb_*, USB_* */ +#include "pios_sys.h" /* PIOS_SYS_SerialNumberGet */ +#include "pios_usbhook.h" /* PIOS_USBHOOK_* */ + +static const uint8_t usb_product_id[22] = { + sizeof(usb_product_id), + USB_DESC_TYPE_STRING, + 'R', 0, + 'e', 0, + 'v', 0, + 'o', 0, + 'l', 0, + 'u', 0, + 't', 0, + 'i', 0, + 'o', 0, + 'n', 0, +}; + +static uint8_t usb_serial_number[52] = { + sizeof(usb_serial_number), + USB_DESC_TYPE_STRING, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0 +}; + +static const struct usb_string_langid usb_lang_id = { + .bLength = sizeof(usb_lang_id), + .bDescriptorType = USB_DESC_TYPE_STRING, + .bLangID = htousbs(USB_LANGID_ENGLISH_UK), +}; + +static const uint8_t usb_vendor_id[28] = { + sizeof(usb_vendor_id), + USB_DESC_TYPE_STRING, + 'o', 0, + 'p', 0, + 'e', 0, + 'n', 0, + 'p', 0, + 'i', 0, + 'l', 0, + 'o', 0, + 't', 0, + '.', 0, + 'o', 0, + 'r', 0, + 'g', 0 +}; + +int32_t PIOS_USB_BOARD_DATA_Init(void) +{ + /* Load device serial number into serial number string */ + uint8_t sn[25]; + PIOS_SYS_SerialNumberGet((char *)sn); + for (uint8_t i = 0; sn[i] != '\0' && (2 * i) < usb_serial_number[0]; i++) { + usb_serial_number[2 + 2 * i] = sn[i]; + } + + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_PRODUCT, (uint8_t *)&usb_product_id, sizeof(usb_product_id)); + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_SERIAL, (uint8_t *)&usb_serial_number, sizeof(usb_serial_number)); + + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_LANG, (uint8_t *)&usb_lang_id, sizeof(usb_lang_id)); + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_VENDOR, (uint8_t *)&usb_vendor_id, sizeof(usb_vendor_id)); + + return 0; +} diff --git a/flight/board_hw_defs/revolution/board_hw_defs.c b/flight/board_hw_defs/revolution/board_hw_defs.c index 8f3ef6bd1..afeb6e6f4 100644 --- a/flight/board_hw_defs/revolution/board_hw_defs.c +++ b/flight/board_hw_defs/revolution/board_hw_defs.c @@ -1416,5 +1416,61 @@ static const struct pios_ppm_cfg pios_ppm_cfg = { #endif +#if defined(PIOS_INCLUDE_USB) +#include "pios_usb_priv.h" +static const struct pios_usb_cfg pios_usb_main_cfg = { + .irq = { + .init = { + .NVIC_IRQChannel = OTG_FS_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 3, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .vsense = { + .gpio = GPIOD, + .init = { + .GPIO_Pin = GPIO_Pin_11, + .GPIO_Speed = GPIO_Speed_25MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + }, + } +}; +#include "pios_usb_board_data_priv.h" +#include "pios_usb_desc_hid_cdc_priv.h" +#include "pios_usb_desc_hid_only_priv.h" +#include "pios_usbhook.h" + +#endif /* PIOS_INCLUDE_USB */ + +#if defined(PIOS_INCLUDE_COM_MSG) + +#include + +#endif /* PIOS_INCLUDE_COM_MSG */ + +#if defined(PIOS_INCLUDE_USB_HID) +#include + +const struct pios_usb_hid_cfg pios_usb_hid_cfg = { + .data_if = 0, + .data_rx_ep = 1, + .data_tx_ep = 1, +}; +#endif /* PIOS_INCLUDE_USB_HID */ + +#if defined(PIOS_INCLUDE_USB_CDC) +#include + +const struct pios_usb_cdc_cfg pios_usb_cdc_cfg = { + .ctrl_if = 1, + .ctrl_tx_ep = 2, + + .data_if = 2, + .data_rx_ep = 3, + .data_tx_ep = 3, +}; +#endif /* PIOS_INCLUDE_USB_CDC */