#ifndef STM32_USB_DRV #define STM32_USB_DRV #include "common_defs.h" #include "../../usb_common_types.h" #include "../../usb_driver_common.h" // number of supported endpoints #define USB_NUM_OF_ENDPOINTS (6) // set it to the maximum that this type of module can support // non isochronous transfers #define USB_MAX_FS_PCKT_SIZE_NON_ISOCHRONOUS (64) #define USB_MAX_HS_PCKT_SIZE_NON_ISOCHRONOUS (512) // isochronous transfers #define USB_MAX_FS_PCKT_SIZE_ISOCHRONOUS (1023) #define USB_MIN_EP_FIFO_SIZE (64) // Unfortunately this cannot be enabled, since the USB controller // generates such enormous amounts of interrupts, so that no other // task can run along the USB processing. #define USB_EVENT_PROCESSING_IN_OS_THREAD (0) #if USB_EVENT_PROCESSING_IN_OS_THREAD #include #endif // endpoint configuration structure typedef struct { uint16_t max_packet_size; // maximum packet size bool8_t responding_NAK; // indicates if endpoint responds with NAK uint8_t type; // endpoint type uint8_t service_interval; // service interval // calculated values uint8_t is_configured; // the endpoint is in use uint16_t fifo_address; // address in the FIFO uint16_t fifo_size; // FIFO size bool8_t zlp_next; // indicates, that ZLP should be transmitted at the end of the current transfer (for IN endpoints) bool8_t autoarm; // automatically arm endpoint (for OUT endpoints) } USBDRV_EpConfig; typedef enum { USB_FSM_INITIAL_WAIT_SPEEDNEG = 0, // initial state, right after reset, wait for speed negotiation, must be ZERO! USB_FSM_SETUP_OPERATE, // ready to perform setup operations } USBDRV_FsmState; typedef enum { USB_EVT_USB_RESET, // bus reset received USB_EVT_SPEEDNEG_DONE, // linespeed negotiation (ST calls "enumeration") done USB_EVT_RECEPTION_DONE, // received packet is waiting to be fetched from the Rx FIFO USB_EVT_OUT_DONE, // something has happened on an OUT endpoint USB_EVT_IN_DONE, // previously armed IN endpoint has finished packet transmission } USBDRV_EventCode; // endpoint event typedef enum { USB_EPEVT_IDLE = 0x00, // endpoint is IDLE USB_EPEVT_ARMED, // endpoint is armed for transmission USB_EPEVT_STALLED, // endpoint is stalled USB_EPEVT_NAK // endpoint responds NAK regardless of FIFO level } USBDRV_EndpointEvent; // USB device state typedef struct { USBDRV_EpConfig ep_OUT[USB_NUM_OF_ENDPOINTS]; // OUT endpoint configs USBDRV_EpConfig ep_IN[USB_NUM_OF_ENDPOINTS]; // IN endpoint configs uint16_t rx_fifo_size; // Rx FIFO size in bytes uint16_t state; // FSM state uint8_t *rx_buf; // pointer to the receive buffer (this way declaration can be separated) uint16_t rx_buf_level; // fill level of the rx buffer uint8_t address; // device address #if USB_EVENT_PROCESSING_IN_OS_THREAD osMessageQueueId_t event_queue; // event queue osThreadId_t th; // event processing thread #endif } USBDRV_GlobalState; // USB received packet status typedef enum { USB_PCKT_STATUS_GLOBAL_OUT_NAK = 0b0001, USB_PCKT_STATUS_OUT_DATA_RECV = 0b0010, USB_PCKT_STATUS_OUT_TRANSFER_CPLT = 0b0011, USB_PCKT_STATUS_SETUP_CPLT = 0b0100, USB_PCKT_STATUS_SETUP_DATA_RECV = 0b0110, } USBDRV_PcktStatus; #define USB_FLUSH_TX_FIFO_ALL (0b10000) // event data typedef union { struct { uint8_t pckt_status; // read packet status uint8_t data_pid; // data PID uint8_t byte_count; // byte count uint8_t ep_num; // read endpoint number } rx; // receive event data } USBDRV_EventData; // event compound for queueing typedef struct { uint32_t code; // event code USBDRV_EventData data; // accompaining event data } USBDRV_EventCompound; // ------------ /** * Fully initialize USB driver. */ void usbdrv_init(); /** * Reset USB driver. */ void usbdrv_reset(); /** * Init driver's global state. */ void usbdrv_init_global_state(); /** * Initialize driver interface. */ void usbdrv_init_intf(); /** * USB peripheral initialization. * * @param reset only perform an after-reset reinitialization */ void usbdrv_periph_init(bool reset); /** * Flush specific TX FIFO. * * @param n index of the TX FIFO */ void usbdrv_flush_tx_fifo(uint8_t n); /** * Flush all RX FIFOs. */ void usbdrv_flush_rx_fifo(); /** * Power down or up the USB peripheral. Also control built-in transciever. * * @param en power on/off */ void usbdrv_power_and_connect(bool en); /** * Configure USB Endpoint. * * @param ep index of the endpoint * @param dir direction of the endpoint to be configured * @param cfg pointer to the configuration details */ void usbdrv_configure_endpoint(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *cfg); /** * Deconfigure a specific USB Endpoint. * * @param ep index of the endpoint * @param dir direction of the endpoint to be deconfigured */ void usbdrv_deconfigure_endpoint(uint8_t ep, uint8_t dir); /** * Stall a particular USB Endpoint. * * @param ep index of the endpoint to be stalled * @param dir direction of the endpoint * @param stall enable/disable stalling */ void usbdrv_stall_endpoint(uint8_t ep, uint8_t dir, bool stall); /** * Implement or rescind responding NAK globally in the chosen direction. * * @param dir communication direction * @param en enable/disable NAK responses */ void usbdrv_set_global_NAK(uint8_t dir, bool en); /** * Fetch data corresponding to a single Endpoint. * * @param ep index of endpoint * @param len maximum length of data to be fetched */ void usbdrv_fetch_received_data(uint8_t ep, uint16_t len); /** * Setup and prepare Endpoint to transfer data towards the host. * May be called multiple times in a single transmission, since * large messages do not have to fit into a single buffer. * * @param ep index of the Endpoint * @param data pointer to the data * @param len length of the data to be read * @return number of bytes read from the data buffer */ uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len); /** * Prepare Endpoint to expect data reception from the host. * * @param ep index of the Endpoint * @param size expected reception length * @return message length that the endpoint can support during next reception */ uint32_t usbdrv_arm_OUT_endpoint(uint8_t ep, uint16_t size); /** * Enable or disable OUT Endpoint auto arming. * Right after a transaction completes the USB core * automatically prepares the endpoint for the next * reception if this feature is enabled. * * @param ep index of the Endpoint */ void usbdrv_autoarm_OUT_endpoint(uint8_t ep); /** * Mask or unmask Endpoint interrupt generation. * * @param ep index of the Endpoint * @param dir direction of the Endpoint * @param en enable/disable interrupt */ void usbdrv_enable_endpoint_interrupt(uint8_t ep, uint8_t dir, bool en); /** * Set the shared FIFO size for all receptions. * (Shared among all OUT endpoints.) * Size of multiple of 4 are recommended. Values * not obeying this will be rounded up. * * @param size FIFO size in BYTES */ void usbdrv_set_rx_fifo_size(uint16_t size); /** * Preload Endpoint config. Do not write configuration * to the hardware right away, just buffer them in. * * @param ep index of the Endpoint * @param dir direction of the Endpint * @param cfg pointer to Endpoint configuration */ void usbdrv_preload_endpoint_config(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *cfg); /** * Clear ALL Endpoints' preload configurations. * Does NOT clear configuration in the hardware! */ void usbdrv_clear_endpoint_config(); /** * Apply preloaded Endpoint configuration, write * Endpoint config to the hardware. */ void usbdrv_apply_endpoint_config(); /** * Select a specific configuration from the descriptor * dump, preload Endpoint settings and finally apply them. * * @param config_index configuration index */ void usbdrv_fetch_endpoint_configuration(uint8_t config_index); /** * Construct FIFO considering configured Endpoints. */ void usbdrv_build_fifo(); /** * Apply an initial EP0 setup. */ void usbdrv_initial_ep0_setup(); /** * Set USB device address. * * @param addr device address */ void usbdrv_set_address(uint8_t addr); /** * Get driver interface. * * @return pointer to the driver interface */ UsbDrv_DrvIntf *usbdrv_get_intf(); /** * Register callback for IN transaction complete. * * @param ep index of the Endpoint * @param cb pointer to the callback function */ void usbdrv_register_IN_complete_cb(uint8_t ep, UsbDrv_IN_cb cb); /** * Get Endpoint interrupt flag. * * @param ep index of the Endpoint * @param dir direction of the Endpoint * @return flag was set */ bool usbdrv_get_endpoint_interrupt_flag(uint8_t ep, uint8_t dir); /** * Process data on the RX FIFO top. * * @param evt_data pointer to event data target area */ void usbdrv_process_rx_fifo_top(USBDRV_EventData *evt_data); /** * Get the address table. * * @return immutable pointer to the address table */ const char *usbdrv_get_fifo_addr_table(); #endif /* STM32_USB_DRV */