From c9335332df86fbc895a8868a34abcc98817d53f0 Mon Sep 17 00:00:00 2001 From: Joshua Drake Date: Sat, 6 Dec 2025 14:22:21 -0600 Subject: Inital Commit --- .../usb/usb_peripheral/usb_peripheral.c | 646 +++++++ .../usb/usb_peripheral/usb_peripheral.h | 336 ++++ .../usb/usb_peripheral/usb_peripheral_avr_du.h | 1930 ++++++++++++++++++++ .../usb/usb_peripheral/usb_peripheral_endpoint.c | 510 ++++++ .../usb/usb_peripheral/usb_peripheral_endpoint.h | 171 ++ .../usb/usb_peripheral/usb_peripheral_read_write.c | 484 +++++ .../usb/usb_peripheral/usb_peripheral_read_write.h | 222 +++ 7 files changed, 4299 insertions(+) create mode 100644 mcc_generated_files/usb/usb_peripheral/usb_peripheral.c create mode 100644 mcc_generated_files/usb/usb_peripheral/usb_peripheral.h create mode 100644 mcc_generated_files/usb/usb_peripheral/usb_peripheral_avr_du.h create mode 100644 mcc_generated_files/usb/usb_peripheral/usb_peripheral_endpoint.c create mode 100644 mcc_generated_files/usb/usb_peripheral/usb_peripheral_endpoint.h create mode 100644 mcc_generated_files/usb/usb_peripheral/usb_peripheral_read_write.c create mode 100644 mcc_generated_files/usb/usb_peripheral/usb_peripheral_read_write.h (limited to 'mcc_generated_files/usb/usb_peripheral') diff --git a/mcc_generated_files/usb/usb_peripheral/usb_peripheral.c b/mcc_generated_files/usb/usb_peripheral/usb_peripheral.c new file mode 100644 index 0000000..bdaaf92 --- /dev/null +++ b/mcc_generated_files/usb/usb_peripheral/usb_peripheral.c @@ -0,0 +1,646 @@ +/** + * USBPERIPHERAL Peripheral Source File + * @file usb_peripheral.c + * @ingroup usb_peripheral + * @brief Interface for a usb_peripheral module that needs to be implemented by a device specific USB module driver. + * @version USB Device Stack HAL Driver Version 1.0.0 + */ + +/* +(c) 2021 Microchip Technology Inc. and its subsidiaries. + +Subject to your compliance with these terms, you may use Microchip software and any +derivatives exclusively with Microchip products. It is your responsibility to comply with third party +license terms applicable to your use of third party software (including open source software) that +may accompany Microchip software. + +THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER +EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY +IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS +FOR A PARTICULAR PURPOSE. + +IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, +INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND +WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP +HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO +THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL +CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT +OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS +SOFTWARE. +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +STATIC USB_CONTROL_TRANSFER_t controlTransfer __attribute__((aligned(2))) = { .transferDataPtr = controlTransfer.buffer }; + +bool USB_SetupIsReceived(void) +{ + return USB_SetupInterruptIs(); +} + +bool USB_EventSOFIsReceived(void) +{ + return USB_SOFInterruptIs(); +} + +void USB_EventSOFClear(void) +{ + USB_SOFInterruptClear(); +} + +bool USB_EventResetIsReceived(void) +{ + return USB_ResetInterruptIs(); +} + +void USB_EventResetClear(void) +{ + USB_ResetInterruptClear(); +} + +uint8_t USB_EventOverUnderflowIsReceived(void) +{ + uint8_t eventOverUnderflow = 0; + if (USB_OverflowInterruptIs() == true) + { + eventOverUnderflow |= (uint8_t)OVERFLOW_EVENT; + } + if (USB_UnderflowInterruptIs() == true) + { + eventOverUnderflow |= (uint8_t)UNDERFLOW_EVENT; + } + return eventOverUnderflow; +} + +uint8_t USB_ControlOverUnderflowIsReceived(void) +{ + uint8_t eventOverUnderflow = 0; + if (USB_EndpointOutOverUnderflowIsSet(0) == true) + { + eventOverUnderflow |= (uint8_t)OVERFLOW_EVENT; + USB_EndpointOutOverUnderflowAck(0); + } + if (USB_EndpointInOverUnderflowIsSet(0) == true) + { + eventOverUnderflow |= (uint8_t)UNDERFLOW_EVENT; + USB_EndpointInOverUnderflowAck(0); + } + return eventOverUnderflow; +} + +void USB_EventOverUnderflowClear(void) +{ + USB_OverflowInterruptClear(); + USB_UnderflowInterruptClear(); +} + +bool USB_EventSuspendIsReceived(void) +{ + return USB_SuspendInterruptIs(); +} + +void USB_EventSuspendClear(void) +{ + USB_SuspendInterruptClear(); +} + +bool USB_EventResumeIsReceived(void) +{ + return USB_ResumeInterruptIs(); +} + +void USB_EventResumeClear(void) +{ + USB_ResumeInterruptClear(); +} + +bool USB_EventStalledIsReceived(void) +{ + return USB_StalledInterruptIs(); +} + +void USB_EventStalledClear(void) +{ + USB_StalledInterruptClear(); +} + +void USB_BusAttach(void) +{ + USB_ConnectionAttach(); +} + +void USB_BusDetach(void) +{ + USB_ConnectionDetach(); +} + +bool USB_IsBusAttached(void) +{ + return USB_ConnectionIsAttach(); +} + +void USB_DeviceAddressConfigure(uint8_t deviceAddress) +{ + USB_DeviceAddressSet(deviceAddress); +} + +uint16_t USB_FrameNumberGet(void) +{ + return (USB_FrameNumGet()); +} + +RETURN_CODE_t USB_ControlEndpointsInit(void) +{ + RETURN_CODE_t status = UNINITIALIZED; + + USB_PIPE_t controlPipeOut = { .address = 0, .direction = USB_EP_DIR_OUT }; + USB_PIPE_t controlPipeIn = { .address = 0, .direction = USB_EP_DIR_IN }; + + status = USB_EndpointConfigure(controlPipeOut, USB_EP0_SIZE, CONTROL); + if (SUCCESS == status) + { + status = USB_EndpointConfigure(controlPipeIn, USB_EP0_SIZE, CONTROL); + } + + if (SUCCESS == status) + { + status = EndpointBufferSet(controlPipeOut, controlTransfer.buffer); + if (SUCCESS == status) + { + status = EndpointBufferSet(controlPipeIn, controlTransfer.buffer); + } + } + + if (SUCCESS == status) + { + status = USB_DataToggleClear(controlPipeOut); + if (SUCCESS == status) + { + status = USB_DataToggleSet(controlPipeIn); + } + } + + if (SUCCESS == status) + { + controlTransfer.status = USB_CONTROL_SETUP; + } + + return status; +} + +RETURN_CODE_t USB_ControlSetupReceived(void) +{ + RETURN_CODE_t status = UNINITIALIZED; + + USB_SetupInterruptClear(); + + if (USB_CONTROL_STALL_REQ == controlTransfer.status) + { + // Stall events are handled by the EventHandler. + status = SUCCESS; + } + else + { + // Acks Setup Received on the control endpoints. + USB_EndpointOutSetupReceivedAck(0u); + USB_EndpointInSetupCompleteAck(0u); + + // Clears bytes received and sent + USB_NumberBytesToSendReset(0u); + USB_NumberBytesSentReset(0u); + USB_NumberBytesToReceiveReset(0u); + USB_NumberBytesReceivedReset(0u); + + // Copies setup packet out of buffer to make it available for a data stage. + (void)memcpy((uint8_t *)(&controlTransfer.setupRequest), controlTransfer.buffer, sizeof(USB_SETUP_REQUEST_t)); + + // The processSetupCallback is in most cases the USB_SetupProcess function in usb_core.c. + if (controlTransfer.processSetupCallback != NULL) + { + RETURN_CODE_t setup_status = controlTransfer.processSetupCallback(&controlTransfer.setupRequest); + + if (UNSUPPORTED == setup_status) + { + // Setup Request unknown or rejected, stalls the next control transaction. + controlTransfer.status = USB_CONTROL_STALL_REQ; + USB_EndpointInStall(0u); + USB_EndpointOutStall(0u); + + status = SUCCESS; + } + else if (SUCCESS == setup_status) + { + if (0u == controlTransfer.transferDataSize) + { + // Request did not contain a data stage, sends ZLP directly. + status = USB_ControlTransferZLP(USB_EP_DIR_IN); + } + else + { + // Sends or Receives data in next stage of request. + controlTransfer.totalBytesTransferred = 0; + USB_PIPE_t controlPipe = { .address = 0u, .direction = USB_EP_DIR_IN }; + if ((controlTransfer.setupRequest.bmRequestType.dataPhaseTransferDirection) == USB_REQUEST_DIR_IN) + { + controlTransfer.status = USB_CONTROL_DATA_IN; + } + else + { + // Control OUT data transactions are controlled by the IN.DATAPTR so set specifically here. + status = EndpointBufferSet(controlPipe, controlTransfer.transferDataPtr); + + controlPipe.direction = USB_EP_DIR_OUT; + controlTransfer.status = USB_CONTROL_DATA_OUT; + } + + // Sets up the pipe variables. + USB_PipeDataTransferredSizeReset(controlPipe); + USB_PipeDataPtrSet(controlPipe, controlTransfer.transferDataPtr); + USB_PipeDataToTransferSizeSet(controlPipe, controlTransfer.transferDataSize); + + // Start data stage transaction. + status = USB_ControlTransactionComplete(controlPipe); + } + } + else + { + // Forward error from setup. + status = setup_status; + } + } + else + { + // processSetupCallback missing, return error. + status = CONTROL_SETUP_CALLBACK_ERROR; + } + } + + return status; +} + +RETURN_CODE_t USB_ControlTransactionComplete(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if (pipe.address != 0) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + // The data stage and the status stage must always have the data toggle bit set. + status = USB_DataToggleSet(pipe); + } + + if (SUCCESS == status) + { + switch (controlTransfer.status) + { + case USB_CONTROL_DATA_IN: + { + pipe.direction = USB_EP_DIR_IN; + + // Updates bytes sent and to be sent. + uint16_t bytesSent = USB_PipeDataTransferredSizeGet(pipe); + bytesSent += USB_NumberBytesSentGet(pipe.address); + USB_PipeDataTransferredSizeSet(pipe, bytesSent); + uint16_t transferDataSize = USB_PipeDataToTransferSizeGet(pipe); + + // Checks remaining data to send. + if (0U == (transferDataSize - bytesSent)) + { + controlTransfer.totalBytesTransferred += bytesSent; + if (controlTransfer.transferDataSize == controlTransfer.totalBytesTransferred) + { + + // Data stage is complete, sends an OUT ZLP for status stage. + status = USB_ControlTransferZLP(USB_REQUEST_DIR_OUT); + } + else + { + // Data stage is not complete, checks if we need a new buffer. + if ((controlTransfer.overUnderRunCallback != NULL) && (SUCCESS == controlTransfer.overUnderRunCallback())) + { + USB_PipeDataTransferredSizeReset(pipe); + USB_PipeDataToTransferSizeSet(pipe, controlTransfer.transferDataSize); + } + + // If no new buffer a normal in ZLP will get sent for the data stage. + status = USB_InTransactionRun(pipe); + } + } + else + { + // Starts next transaction in data stage. + status = USB_InTransactionRun(pipe); + } + + USB_EndpointInOverUnderflowAck(0); + + break; + } + case USB_CONTROL_DATA_OUT: + { + pipe.direction = USB_EP_DIR_OUT; + + // Updates bytes received and to be received. + uint16_t bytesReceived = USB_PipeDataTransferredSizeGet(pipe); + bytesReceived += USB_NumberBytesReceivedGet(pipe.address); + USB_PipeDataTransferredSizeSet(pipe, bytesReceived); + uint16_t transferDataSize = USB_PipeDataToTransferSizeGet(pipe); + + if (0U == (transferDataSize - bytesReceived)) + { + controlTransfer.totalBytesTransferred += bytesReceived; + if (controlTransfer.transferDataSize == controlTransfer.totalBytesTransferred) + { + + // Data stage is complete, sends an IN ZLP for status stage. + status = USB_ControlTransferZLP(USB_REQUEST_DIR_IN); + } + else + { + // Data stage is not complete, checks if we need a new buffer. + if ((controlTransfer.overUnderRunCallback != NULL) && (SUCCESS == controlTransfer.overUnderRunCallback())) + { + USB_PipeDataTransferredSizeReset(pipe); + USB_PipeDataToTransferSizeSet(pipe, controlTransfer.transferDataSize); + status = USB_InTransactionRun(pipe); + } + else + { + // If no new buffer the next transaction will be stalled. + controlTransfer.status = USB_CONTROL_STALL_REQ; + USB_EndpointInStall(0); + USB_EndpointOutStall(0); + + status = SUCCESS; + } + } + } + else + { + // Starts next transaction in data stage. + status = USB_OutTransactionRun(pipe); + } + + USB_EndpointOutOverUnderflowAck(0); + break; + } + case USB_CONTROL_ZLP: + { + // Valid end of setup request. + if (controlTransfer.endOfRequestCallback != NULL) + { + controlTransfer.endOfRequestCallback(); + } + + // Reinitializes control endpoint management. + status = USB_ControlTransferReset(); + break; + } + case USB_CONTROL_SETUP: + { + status = USB_ControlTransferReset(); + break; + } + default: + { + status = CONTROL_TRANSACTION_STATUS_ERROR; + break; + } + } + } + + return status; +} + +RETURN_CODE_t USB_ControlTransferZLP(uint8_t direction) +{ + RETURN_CODE_t status = UNINITIALIZED; + + USB_NumberBytesToSendReset(0); + USB_NumberBytesSentReset(0); + USB_NumberBytesToReceiveReset(0u); + USB_NumberBytesReceivedReset(0u); + + // Prepare to receive a new setup package in case the host decides to ignore the ZLP stage + USB_PipeDataPtrSet((USB_PIPE_t){ .address = 0, .direction = USB_REQUEST_DIR_OUT }, controlTransfer.buffer); + status = EndpointBufferSet((USB_PIPE_t){ .address = 0, .direction = USB_REQUEST_DIR_OUT }, controlTransfer.buffer); + + if (SUCCESS == status) + { + controlTransfer.status = USB_CONTROL_ZLP; + + // Starts the ZLP transaction + if (direction == USB_REQUEST_DIR_IN) + { + USB_EndpointInNAKClear(0); + USB_EndpointInOverUnderflowAck(0); + } + else + { + USB_EndpointOutNAKClear(0); + USB_EndpointOutOverUnderflowAck(0); + } + } + + return status; +} + +RETURN_CODE_t USB_ControlTransferReset(void) +{ + RETURN_CODE_t status = UNINITIALIZED; + USB_PIPE_t controlPipeOut = { .address = 0u, .direction = USB_EP_DIR_OUT }; + + // Aborts any ongoing transaction and resets the endpoint statuses + status = USB_TransactionAbort(controlPipeOut); + if (SUCCESS == status) + { + USB_PIPE_t controlPipeIn = { .address = 0u, .direction = USB_EP_DIR_IN }; + status = USB_TransactionAbort(controlPipeIn); + } + + if (SUCCESS == status) + { + USB_EndpointOutStatusClear(0u); + USB_EndpointInStatusClear(0u); + + // Prepare for receiving a new request packet + USB_PipeDataPtrSet(controlPipeOut, controlTransfer.buffer); + USB_PipeDataToTransferSizeSet(controlPipeOut, sizeof(USB_SETUP_REQUEST_t)); + USB_PipeDataTransferredSizeReset(controlPipeOut); + USB_PipeTransferEndCallbackRegister(controlPipeOut, NULL); + + // Clears the endpoint count registers + USB_NumberBytesToSendReset(0u); + USB_NumberBytesSentReset(0u); + USB_NumberBytesToReceiveReset(0u); + USB_NumberBytesReceivedReset(0u); + + // Resets the control transfer variables + controlTransfer.endOfRequestCallback = NULL; + controlTransfer.overUnderRunCallback = NULL; + controlTransfer.transferDataSize = 0u; + controlTransfer.status = USB_CONTROL_SETUP; + } + + return status; +} + +RETURN_CODE_t USB_ControlTransferDataSet(uint8_t *dataPtr, uint16_t dataSize) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if (dataPtr == NULL) + { + controlTransfer.transferDataPtr = controlTransfer.buffer; + if (0u != dataSize) + { + status = CONTROL_SIZE_ERROR; + } + else + { + status = SUCCESS; + } + } + else + { + controlTransfer.transferDataPtr = dataPtr; + status = SUCCESS; + } + controlTransfer.transferDataSize = dataSize; + + return status; +} + +RETURN_CODE_t USB_ControlTransferDataWriteBuffer(uint8_t *dataPtr, uint8_t dataSize) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if (USB_EP0_SIZE < dataSize) + { + status = CONTROL_SIZE_ERROR; + } + else + { + (void)memcpy(controlTransfer.buffer, dataPtr, dataSize); + controlTransfer.transferDataPtr = controlTransfer.buffer; + controlTransfer.transferDataSize = dataSize; + + status = SUCCESS; + } + return status; +} + +void USB_ControlEndOfRequestCallbackRegister(USB_SETUP_ENDOFREQUEST_CALLBACK_t callback) +{ + controlTransfer.endOfRequestCallback = callback; +} + +void USB_ControlProcessSetupCallbackRegister(USB_SETUP_PROCESS_CALLBACK_t callback) +{ + controlTransfer.processSetupCallback = callback; +} + +void USB_ControlOverUnderRunCallbackRegister(USB_SETUP_OVERUNDERRUN_CALLBACK_t callback) +{ + controlTransfer.overUnderRunCallback = callback; +} + +RETURN_CODE_t USB_ControlProcessOverUnderflow(uint8_t overunderflow) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if (USB_CONTROL_DATA_IN == controlTransfer.status) + { + if (OVERFLOW_EVENT == overunderflow) + { + // Host is done with the data stage and expects an OUT ZLP + status = USB_ControlTransferZLP(USB_REQUEST_DIR_OUT); + } + else + { + // Host is too eager, let this be handled by the transfer handler + status = SUCCESS; + } + } + else if (USB_CONTROL_DATA_OUT == controlTransfer.status) + { + if (UNDERFLOW_EVENT == overunderflow) + { + // Host is done with the data stage and expects an IN ZLP + status = USB_ControlTransferZLP(USB_REQUEST_DIR_IN); + } + else + { + // Host is too eager, let this be handled by the transfer handler + status = SUCCESS; + } + } + else + { + // Remaining control statuses ignores overflow and underflow events + status = SUCCESS; + } + + return status; +} + +RETURN_CODE_t USB_HandleEventStalled(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + USB_EndpointInStallAck(pipe.address); + USB_EndpointOutStallAck(pipe.address); + + USB_EndpointInStallClear(pipe.address); + USB_EndpointOutStallClear(pipe.address); + + if (0u == pipe.address) + { + // Reinitializes control endpoint management. + status = USB_ControlTransferReset(); + } + else + { + status = USB_TransactionAbort(pipe); + } + + return status; +} + +void USB_PeripheralInitialize(void) +{ + USB_Enable(); + USB_FrameNumEnable(); + USB_FifoEnable(); + USB_FifoReadPointerReset(); + USB_FifoWritePointerReset(); + USB_EndpointTableAddressSet(endpointTable.EP); + USB_MaxEndpointsSet(USB_EP_NUM - 1u); + USB_InterruptFlagsClear(); + // Reset endpoints table + for (uint8_t endpoint = 0; endpoint < (uint8_t)USB_EP_NUM; endpoint++) + { + endpointTable.EP[endpoint].OUT.CTRL = 0; + endpointTable.EP[endpoint].OUT.STATUS = 0; + endpointTable.EP[endpoint].IN.CTRL = 0; + endpointTable.EP[endpoint].IN.STATUS = 0; + } +} + +void USB_PeripheralDisable(void) +{ + USB_Disable(); + USB_DeviceAddressReset(); +} diff --git a/mcc_generated_files/usb/usb_peripheral/usb_peripheral.h b/mcc_generated_files/usb/usb_peripheral/usb_peripheral.h new file mode 100644 index 0000000..2957f60 --- /dev/null +++ b/mcc_generated_files/usb/usb_peripheral/usb_peripheral.h @@ -0,0 +1,336 @@ +/** + * USBPERIPHERAL Peripheral Header File + * @file usb_peripheral.h + * @defgroup usb_peripheral USB Peripheral Hardware Abstraction Layer (HAL) + * @brief Interface for a USB peripheral module that needs to be implemented by a device-specific USB module driver. + * @version USB Device Stack HAL Driver Version 1.0.0 + */ + +/* + (c) 2021 Microchip Technology Inc. and its subsidiaries. + + Subject to your compliance with these terms, you may use Microchip software and any + derivatives exclusively with Microchip products. It is your responsibility to comply with third party + license terms applicable to your use of third party software (including open source software) that + may accompany Microchip software. + + THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY + IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS + FOR A PARTICULAR PURPOSE. + + IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, + INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND + WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP + HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO + THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL + CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT + OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS + SOFTWARE. + */ + +#ifndef USB_PERIPHERAL_H +// cppcheck-suppress misra-c2012-2.5 +#define USB_PERIPHERAL_H + +#include +#include + +#include +#include +#include +#include + +/** + * @ingroup usb_peripheral + * @struct USB_CONTROL_TRANSFER_t + * @brief The data structure for internally handling control transfers, either IN or OUT. + */ +typedef struct USB_CONTROL_TRANSFER_struct +{ + uint8_t buffer[64]; /** +#else // avr-gcc + #include +#endif + +#include +#include + +/** + * @ingroup usb_peripheral_avr_du + * @def ALWAYS_INLINE + * @brief Alias that makes always inline function definitions more readable. + */ +#define ALWAYS_INLINE __attribute__((always_inline)) inline + +/** + * @ingroup usb_peripheral_avr_du + * @struct USB_ENDPOINT_TABLE_struct + * @brief Represents the endpoint configuration table based on the number of endpoints in use. + * The table data structure is defined by USB_EP_TABLE_struct in the device header file, + * modified to support configuration of size from USB_EP_NUM. + */ +typedef struct USB_ENDPOINT_TABLE_struct +{ + register8_t FIFO[USB_EP_NUM * 2u]; /**> USB_MAXEP_gp); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Sets the address of the endpoint table. + * This is a device-specific function. + * @param endpointTableAddress - Address of the endpoint table + * @return None. + */ +static ALWAYS_INLINE void USB_EndpointTableAddressSet(USB_EP_PAIR_t *endpointTableAddress) +{ + USB0.EPPTR = (uint16_t)endpointTableAddress; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Sets the address of the endpoint table to 0. + * This is a device-specific function. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_EndpointTableAddressReset(void) +{ + USB0.EPPTR = 0x0000; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Gets the address of the endpoint table. + * This is a device-specific function. + * @param None. + * @return The address of the endpoint table + */ +static ALWAYS_INLINE uint16_t USB_EndpointTableAddressGet(void) +{ + return (USB0.EPPTR); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Resets the read FIFO pointer. + * This is a device-specific function. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_FifoReadPointerReset(void) +{ + USB0.FIFORP |= (USB_FIFORP_gm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Gets the read FIFO pointer. + * This is a device-specific function. + * @param None. + * @return The FIFO read pointer + */ +static ALWAYS_INLINE int8_t USB_FifoReadPointerGet(void) +{ + return (int8_t)(USB0.FIFORP); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Resets the write FIFO pointer. + * This is a device-specific function. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_FifoWritePointerReset(void) +{ + USB0.FIFOWP |= (USB_FIFOWP_gm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Gets the write FIFO pointer. + * This is a device-specific function. + * @param None. + * @return The FIFO write pointer + */ +static ALWAYS_INLINE int8_t USB_FifoWritePointerGet(void) +{ + return (int8_t)(USB0.FIFOWP); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Sets the device address. + * @param usbAddress - The device address to set + * @return None. + */ +static ALWAYS_INLINE void USB_DeviceAddressSet(uint8_t usbAddress) +{ + USB0.ADDR = ((USB0.ADDR & ~USB_ADDR_gm) | (((usbAddress) << USB_ADDR_gp) & USB_ADDR_gm)); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Resets the device address. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_DeviceAddressReset(void) +{ + USB0.ADDR &= ~(USB_ADDR_gm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Gets the device address. + * @param None. + * @return The device address + */ +static ALWAYS_INLINE uint8_t USB_DeviceAddressGet(void) +{ + return ((USB0.ADDR & USB_ADDR_gm) >> USB_ADDR_gp); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Enables an upstream resume to be initated. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_UpstreamResumeEnable(void) +{ + USB0.CTRLB |= USB_URESUME_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if upstream resume is enabled, but not yet initiated. + * @param None. + * @retval 0 - Upstream resume initiated or not enabled + * @retval 1 - Upstream resume enabled + */ +static ALWAYS_INLINE bool USB_UpstreamResumeIsEnable(void) +{ + return ((USB0.CTRLB & USB_URESUME_bm) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Gets the USB bus state. + * @param None. + * @return The state of the USB bus + */ +static ALWAYS_INLINE uint8_t USB_BusStateGet(void) +{ + return (USB0.BUSSTATE); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if the USB bus has any specific status flags set. + * @param bus_state_bm - The bitmap of the specific status flags to check + * @retval 0 - No status flags set + * @retval 1 - The bus has one or more specified status flags set + */ +static ALWAYS_INLINE bool USB_BusStateIs(uint8_t bus_state_bm) +{ + return ((USB0.BUSSTATE & (bus_state_bm)) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Enables the USB Start-Of-Frame interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_SOFInterruptEnable(void) +{ + USB0.INTCTRLA |= USB_SOF_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Disables the USB Start-Of-Frame interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_SOFInterruptDisable(void) +{ + USB0.INTCTRLA &= ~(USB_SOF_bm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Clears the USB Start-Of-Frame Interrupt flag. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_SOFInterruptClear(void) +{ + USB0.INTFLAGSA = USB_SOF_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if the USB Start-Of-Frame interrupt has been triggered. + * @param None. + * @retval 0 - Interrupt not triggered + * @retval 1 - Interrupt triggered + */ +static ALWAYS_INLINE bool USB_SOFInterruptIs(void) +{ + return ((USB0.INTFLAGSA & USB_SOF_bm) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Enables the USB Suspend interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_SuspendInterruptEnable(void) +{ + USB0.INTCTRLA |= USB_SUSPEND_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Disables the USB Suspend interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_SuspendInterruptDisable(void) +{ + USB0.INTCTRLA &= ~(USB_SUSPEND_bm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Clears the USB Suspend Interrupt flag. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_SuspendInterruptClear(void) +{ + USB0.INTFLAGSA = USB_SUSPEND_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if the USB Suspend interrupt has been triggered. + * @param None. + * @retval 0 - Interrupt not triggered + * @retval 1 - Interrupt triggered + */ +static ALWAYS_INLINE bool USB_SuspendInterruptIs(void) +{ + return ((USB0.INTFLAGSA & USB_SUSPEND_bm) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Enables the USB Resume interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_ResumeInterruptEnable(void) +{ + USB0.INTCTRLA |= USB_RESUME_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Disables the USB Resume interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_ResumeInterruptDisable(void) +{ + USB0.INTCTRLA &= ~(USB_RESUME_bm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Clears the USB Resume Interrupt flag. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_ResumeInterruptClear(void) +{ + USB0.INTFLAGSA = USB_RESUME_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if the USB Resume interrupt has been triggered. + * @param None. + * @retval 0 - Interrupt not triggered + * @retval 1 - Interrupt triggered + */ +static ALWAYS_INLINE bool USB_ResumeInterruptIs(void) +{ + return ((USB0.INTFLAGSA & USB_RESUME_bm) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Enables the USB Reset interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_ResetInterruptEnable(void) +{ + USB0.INTCTRLA |= USB_RESET_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Disables the USB Reset interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_ResetInterruptDisable(void) +{ + USB0.INTCTRLA &= ~(USB_RESET_bm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Clears the USB Reset Interrupt flag. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_ResetInterruptClear(void) +{ + USB0.INTFLAGSA = USB_RESET_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if the USB Reset interrupt has been triggered. + * @param None. + * @retval 0 - Interrupt not triggered + * @retval 1 - Interrupt triggered + */ +static ALWAYS_INLINE bool USB_ResetInterruptIs(void) +{ + return ((USB0.INTFLAGSA & USB_RESET_bm) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Enables the USB Stalled interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_StalledInterruptEnable(void) +{ + USB0.INTCTRLA |= USB_STALLED_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Disables the USB Stalled interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_StalledInterruptDisable(void) +{ + USB0.INTCTRLA &= ~(USB_STALLED_bm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Clears the USB Stalled Interrupt flag. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_StalledInterruptClear(void) +{ + USB0.INTFLAGSA = USB_STALLED_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if the USB Stalled interrupt has been triggered. + * @param None. + * @retval 0 - Interrupt not triggered + * @retval 1 - Interrupt triggered + */ +static ALWAYS_INLINE bool USB_StalledInterruptIs(void) +{ + return ((USB0.INTFLAGSA & USB_STALLED_bm) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Enables the USB Underflow interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_UnderflowInterruptEnable(void) +{ + USB0.INTCTRLA |= USB_UNF_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Disables the USB Underflow interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_UnderflowInterruptDisable(void) +{ + USB0.INTCTRLA &= ~(USB_UNF_bm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Clears the USB Underflow Interrupt flag. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_UnderflowInterruptClear(void) +{ + USB0.INTFLAGSA = USB_UNF_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if an Underflow interrupt has been triggered. + * @param None. + * @retval 0 - Interrupt not triggered + * @retval 1 - Interrupt triggered + */ +static ALWAYS_INLINE bool USB_UnderflowInterruptIs(void) +{ + return ((USB0.INTFLAGSA & USB_UNF_bm) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Enables the USB Overflow interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_OverflowInterruptEnable(void) +{ + USB0.INTCTRLA |= USB_OVF_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Disables the USB Overflow interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_OverflowInterruptDisable(void) +{ + USB0.INTCTRLA &= ~(USB_OVF_bm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Clears the USB Overflow Interrupt flag. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_OverflowInterruptClear(void) +{ + USB0.INTFLAGSA = USB_OVF_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if an Overflow interrupt has been triggered. + * @param None. + * @retval 0 - Interrupt not triggered + * @retval 1 - Interrupt triggered + */ +static ALWAYS_INLINE bool USB_OverflowInterruptIs(void) +{ + return ((USB0.INTFLAGSA & USB_OVF_bm) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Enables the USB Transaction Complete interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_TransactionCompleteInterruptEnable(void) +{ + USB0.INTCTRLB |= USB_TRNCOMPL_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Disables the USB Transaction Complete interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_TransactionCompleteInterruptDisable(void) +{ + USB0.INTCTRLB &= ~(USB_TRNCOMPL_bm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Clears the USB Transaction Complete Interrupt flag. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_TransactionCompleteInterruptAck(void) +{ + USB0.INTFLAGSB = USB_TRNCOMPL_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if a Transaction Complete interrupt has been triggered. + * @param None. + * @retval 0 - Interrupt not triggered + * @retval 1 - Interrupt triggered + */ +static ALWAYS_INLINE bool USB_TransactionCompleteInterruptIs(void) +{ + return ((USB0.INTFLAGSB & USB_TRNCOMPL_bm) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if the USB Read-Modify-Write Interrupt is enabled. + * @param None. + * @retval 0 - Interrupt not enabled + * @retval 1 - Interrupt enabled + */ +static ALWAYS_INLINE bool USB_ReadModifyWriteInterruptIs(void) +{ + return ((USB0.INTFLAGSB & USB_RMWBUSY_bm) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Enables the USB Global NAK Done interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_GlobalNAKDoneInterruptEnable(void) +{ + USB0.INTCTRLB |= USB_GNDONE_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Disables the USB Global NAK Done interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_GlobalNAKDoneInterruptDisable(void) +{ + USB0.INTCTRLB &= ~(USB_GNDONE_bm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Clears the USB Global NAK Done Interrupt flag. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_GlobalNAKDoneInterruptAck(void) +{ + USB0.INTFLAGSB = USB_GNDONE_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if the USB Global NAK Done interrupt has been triggered. + * @param None. + * @retval 0 - Interrupt not triggered + * @retval 1 - Interrupt triggered + */ +static ALWAYS_INLINE bool USB_GlobalNAKDoneInterruptIs(void) +{ + return ((USB0.INTFLAGSB & USB_GNDONE_bm) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Enables the USB Setup interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_SetupInterruptEnable(void) +{ + USB0.INTCTRLB |= USB_SETUP_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Disables the USB Setup interrupt. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_SetupInterruptDisable(void) +{ + USB0.INTCTRLB &= ~(USB_SETUP_bm); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Clears the USB Setup Interrupt flag. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_SetupInterruptClear(void) +{ + USB0.INTFLAGSB = USB_SETUP_bm; +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Checks if a USB Setup interrupt has been triggered. + * @param None. + * @retval 0 - Interrupt not triggered + * @retval 1 - Interrupt triggered + */ +static ALWAYS_INLINE bool USB_SetupInterruptIs(void) +{ + return ((USB0.INTFLAGSB & USB_SETUP_bm) != 0u); +} + +/** + * @ingroup usb_peripheral_avr_du + * @brief Clears all the USB Interrupt flags. + * @param None. + * @return None. + */ +static ALWAYS_INLINE void USB_InterruptFlagsClear(void) +{ + USB0.INTFLAGSA = 0xff; + USB0.INTFLAGSB = 0xff; +} + +#endif /* USB_PERIPHERAL_AVR_DU_H */ diff --git a/mcc_generated_files/usb/usb_peripheral/usb_peripheral_endpoint.c b/mcc_generated_files/usb/usb_peripheral/usb_peripheral_endpoint.c new file mode 100644 index 0000000..5ee9a21 --- /dev/null +++ b/mcc_generated_files/usb/usb_peripheral/usb_peripheral_endpoint.c @@ -0,0 +1,510 @@ +/** + * USBPERIPHERALENDPOINT Peripheral Endpoint Source File + * @file usb_peripheral_endpoint.c + * @ingroup usb_peripheral_endpoint + * @brief API module for usb_peripheral covering endpoint related functions. + * @version USB Device Stack HAL Driver Version 1.0.0 + */ + +/* + (c) 2021 Microchip Technology Inc. and its subsidiaries. + + Subject to your compliance with these terms, you may use Microchip software and any + derivatives exclusively with Microchip products. It is your responsibility to comply with third party + license terms applicable to your use of third party software (including open source software) that + may accompany Microchip software. + + THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY + IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS + FOR A PARTICULAR PURPOSE. + + IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, + INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND + WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP + HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO + THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL + CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT + OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS + SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(USB_EP_NUM) && defined(USB_MAX_ENDPOINTS) + #if USB_EP_NUM > USB_MAX_ENDPOINTS + #error "USB_EP_NUM is too large, max is USB_MAX_ENDPOINTS" + #endif +#else + #error "USB_EP_NUM not configured" +#endif + +/** + * @ingroup usb_peripheral_endpoint + * @brief Algorithm to detect if a given number is a power of two. + * A number is a power of two if it has exactly one '1' in its binary representation. This is true if subtracting '1' from the number + * and doing an AND operation on the result with the number itself returns 0. + * @param number 8-bit unsigned integer + * @retval True - The given number is a power of two + * @retval False - The given number is not a power of two + */ +#define IsPowerOfTwo(number) ((0u != (number)) && (((number) & ((number)-1u)) == 0u)) + +/** + * @ingroup usb_peripheral_endpoint + * @brief SRAM tables for the FIFO and endpoint registers, as well as the FRAMENUM register. + * Represents the endpoint configuration table based on the number of endpoints in use. + * This line instantiates an object using the data structure type. + */ +USB_ENDPOINT_TABLE_t endpointTable __attribute__((aligned(2))); + +RETURN_CODE_t USB_EndpointConfigure(USB_PIPE_t pipe, uint16_t endpointSize, USB_ENDPOINT_t endpointType) +{ + RETURN_CODE_t status = UNINITIALIZED; + + uint8_t endpointConfiguration = 0; + if (SUCCESS != ConvertEndpointSizeToMask(endpointSize, endpointType, &endpointConfiguration)) + { + status = ENDPOINT_SIZE_ERROR; + } + else if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else if (INTERRUPT < endpointType) + { + status = ENDPOINT_TYPE_ERROR; + } + else + { + switch (endpointType) + { + case CONTROL: + endpointConfiguration |= USB_TYPE_CONTROL_gc; + break; + case ISOCHRONOUS: + endpointConfiguration |= USB_TYPE_ISO_gc; + break; + case BULK: + case INTERRUPT: + endpointConfiguration |= USB_TYPE_BULKINT_gc; + break; + default: + endpointConfiguration |= USB_TYPE_DISABLE_gc; + break; + } + + if (USB_EP_DIR_OUT == pipe.direction) + { + USB_EndpointOutNAKSet(pipe.address); + USB_EndpointOutStatusClear(pipe.address); + USB_NumberBytesReceivedReset(pipe.address); + USB_EndpointOutControlSet(pipe.address, endpointConfiguration); + + // Set up the static endpoint configurations + if ((uint8_t)0x01 == endpointStaticConfig[pipe.address].OutMultipktEnable) + { + USB_EndpointOutMultipktEnable(pipe.address); + + if ((uint8_t)0x01 == endpointStaticConfig[pipe.address].OutAzlpEnable) + { + USB_EndpointOutAzlpEnable(pipe.address); + } + + status = SUCCESS; + } + else if ((uint8_t)0x01 == endpointStaticConfig[pipe.address].OutAzlpEnable) + { + // AZLP only works together with multipacket + status = ENDPOINT_AZLP_ERROR; + } + else + { + status = SUCCESS; + } + + if ((uint8_t)0x01 != endpointStaticConfig[pipe.address].OutTrncInterruptEnable) + { + USB_EndpointOutTransactionCompleteInterruptDisable(pipe.address); + } + } + else + { + USB_EndpointInNAKSet(pipe.address); + USB_EndpointInStatusClear(pipe.address); + USB_NumberBytesToSendReset(pipe.address); + USB_EndpointInControlSet(pipe.address, endpointConfiguration); + + // Set up the static endpoint configurations + if ((uint8_t)0x01 == endpointStaticConfig[pipe.address].InMultipktEnable) + { + USB_EndpointInMultipktEnable(pipe.address); + + if ((uint8_t)0x01 == endpointStaticConfig[pipe.address].InAzlpEnable) + { + USB_EndpointInAlzpEnable(pipe.address); + } + + status = SUCCESS; + } + else if ((uint8_t)0x01 == endpointStaticConfig[pipe.address].InAzlpEnable) + { + // AZLP only works together with multipacket + status = ENDPOINT_AZLP_ERROR; + } + else + { + status = SUCCESS; + } + + if ((uint8_t)0x01 != endpointStaticConfig[pipe.address].InTrncInterruptEnable) + { + USB_EndpointInTransactionCompleteDisable(pipe.address); + } + } + } + + return status; +} + +RETURN_CODE_t USB_EndpointDisable(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + if (USB_EP_DIR_OUT == pipe.direction) + { + USB_EndPointOutDisable(pipe.address); + } + else + { + USB_EndPointInDisable(pipe.address); + } + + status = SUCCESS; + } + + return status; +} + +uint16_t USB_EndpointSizeGet(USB_PIPE_t pipe) +{ + uint8_t endpointType = 0; + uint8_t endpointSizeConfig = 0; + int16_t endpointSize = 0; + if (USB_EP_DIR_OUT == pipe.direction) + { + endpointType = USB_EndPointOutTypeConfigGet(pipe.address); + endpointSizeConfig = (USB_TYPE_ISO_gc == endpointType) ? USB_EndpointOutIsoSizeGet(pipe.address) : USB_EndpointOutDefaultSizeGet(pipe.address); + } + else + { + endpointType = USB_EndPointInTypeConfigGet(pipe.address); + endpointSizeConfig = (USB_TYPE_ISO_gc == endpointType) ? USB_EndpointInIsoSizeGet(pipe.address) : USB_EndpointInDefaultSizeGet(pipe.address); + } + if (USB_BUFSIZE_ISO_BUF1023_gc == endpointSizeConfig) + { + endpointSize = MAX_ENDPOINT_SIZE_ISO; + } + else + { + endpointSize = 8U << (uint16_t)endpointSizeConfig; + } + return endpointSize; +} + +USB_ENDPOINT_t USB_EndpointTypeGet(USB_PIPE_t pipe) +{ + USB_TYPE_t endpointConfigType; + if (USB_EP_DIR_OUT == pipe.direction) + { + endpointConfigType = USB_EndPointOutTypeConfigGet(pipe.address); + } + else // USB_EP_DIR_IN + { + endpointConfigType = USB_EndPointInTypeConfigGet(pipe.address); + } + + USB_ENDPOINT_t endpointType = DISABLED; + switch (endpointConfigType) + { + case USB_TYPE_CONTROL_gc: + endpointType = CONTROL; + break; + case USB_TYPE_BULKINT_gc: + // Peripheral does not distinguish between BULK and INTERRUPT, returning BULK + endpointType = BULK; + break; + case USB_TYPE_ISO_gc: + endpointType = ISOCHRONOUS; + break; + default: + // endpointType = DISABLED; + break; + } + + return endpointType; +} + +RETURN_CODE_t USB_EndpointStall(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + if (USB_EP_DIR_OUT == pipe.direction) + { + USB_EndpointOutStall(pipe.address); + } + else + { + USB_EndpointInStall(pipe.address); + } + + status = SUCCESS; + } + + return status; +} + +RETURN_CODE_t USB_EndpointStallClear(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + if (USB_EP_DIR_OUT == pipe.direction) + { + USB_EndpointOutStallClear(pipe.address); + } + else + { + USB_EndpointInStallClear(pipe.address); + } + + status = SUCCESS; + } + + return status; +} + +bool USB_EndpointIsStalled(USB_PIPE_t pipe) +{ + + bool isStalled = false; + + if ((uint8_t)USB_EP_NUM > pipe.address) + { + if (USB_EP_DIR_OUT == pipe.direction) + { + isStalled = USB_EndpointOutIsStalled(pipe.address); + } + else + { + isStalled = USB_EndpointInIsStalled(pipe.address); + } + } + + return isStalled; +} + +RETURN_CODE_t USB_EndpointStalledConditionAck(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + if (USB_EP_DIR_OUT == pipe.direction) + { + USB_EndpointOutStallAck(pipe.address); + } + else + { + USB_EndpointInStallAck(pipe.address); + } + + status = SUCCESS; + } + + return status; +} + +RETURN_CODE_t USB_DataToggleSet(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + if (USB_EP_DIR_OUT == pipe.direction) + { + USB_EndpointOutDataToggleSet(pipe.address); + } + else + { + USB_EndpointInDataToggleSet(pipe.address); + } + + status = SUCCESS; + } + + return status; +} + +RETURN_CODE_t USB_DataToggleClear(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + if (USB_EP_DIR_OUT == pipe.direction) + { + USB_EndpointOutDataToggleClear(pipe.address); + } + else + { + USB_EndpointInDataToggleClear(pipe.address); + } + + status = SUCCESS; + } + + return status; +} + +RETURN_CODE_t USB_DataToggle(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + if (USB_EP_DIR_OUT == pipe.direction) + { + (USB_EndpointOutDataToggleIsSet(pipe.address)) ? USB_DataToggleClear(pipe) : USB_DataToggleSet(pipe); + } + else + { + (USB_EndpointInDataToggleIsSet(pipe.address)) ? USB_DataToggleClear(pipe) : USB_DataToggleSet(pipe); + } + + status = SUCCESS; + } + + return status; +} + +RETURN_CODE_t ConvertEndpointSizeToMask(uint16_t endpointSize, USB_ENDPOINT_t endpointType, uint8_t *endpointMaskPtr) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if (ISOCHRONOUS == endpointType) + { + if (((uint16_t)MAX_ENDPOINT_SIZE_ISO < endpointSize) || ((endpointSize < (uint16_t)MAX_ENDPOINT_SIZE_ISO) && !(IsPowerOfTwo(endpointSize)))) + { + status = ENDPOINT_SIZE_ERROR; + } + } + else + { + if (((uint16_t)MAX_ENDPOINT_SIZE_DEFAULT < endpointSize) || !(IsPowerOfTwo(endpointSize))) + { + status = ENDPOINT_SIZE_ERROR; + } + } + + if (UNINITIALIZED == status) + { + if ((uint16_t)MAX_ENDPOINT_SIZE_ISO == endpointSize) + { + *endpointMaskPtr = USB_BUFSIZE_ISO_BUF1023_gc; + } + else + { + uint8_t mask = 0; + uint16_t baseSize = 8; + + while (baseSize < endpointSize) + { + + mask++; + baseSize <<= 1; + } + + *endpointMaskPtr = mask << USB_BUFSIZE_DEFAULT_gp; + } + + status = SUCCESS; + } + + return status; +} + +RETURN_CODE_t EndpointBufferSet(USB_PIPE_t pipe, uint8_t *bufAddress) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + if (USB_EP_DIR_OUT == pipe.direction) + { + // Errata: Out transactions must be word aligned when using multipacket + if ((1u == endpointStaticConfig[pipe.address].OutMultipktEnable) && (((uint16_t)bufAddress & 0x0001) != 0u)) + { + status = ENDPOINT_ALIGN_ERROR; + } + else + { + USB_EndpointOutBufferSet(pipe.address, bufAddress); + status = SUCCESS; + } + } + else + { + USB_EndpointInBufferSet(pipe.address, bufAddress); + status = SUCCESS; + } + } + + return status; +} diff --git a/mcc_generated_files/usb/usb_peripheral/usb_peripheral_endpoint.h b/mcc_generated_files/usb/usb_peripheral/usb_peripheral_endpoint.h new file mode 100644 index 0000000..fa77fca --- /dev/null +++ b/mcc_generated_files/usb/usb_peripheral/usb_peripheral_endpoint.h @@ -0,0 +1,171 @@ +/** + * USBPERIPHERALENDPOINT Peripheral Endpoint Header File + * @file usb_peripheral_endpoint.h + * @defgroup usb_peripheral_endpoint USB Peripheral Endpoint + * @ingroup usb_peripheral + * @brief API module for usb_peripheral_endpoint covering endpoint-related functions. + * @version USB Device Stack HAL Driver Version 1.0.0 + */ + +/* + (c) 2021 Microchip Technology Inc. and its subsidiaries. + + Subject to your compliance with these terms, you may use Microchip software and any + derivatives exclusively with Microchip products. It is your responsibility to comply with third party + license terms applicable to your use of third party software (including open source software) that + may accompany Microchip software. + + THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY + IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS + FOR A PARTICULAR PURPOSE. + + IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, + INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND + WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP + HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO + THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL + CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT + OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS + SOFTWARE. + */ + +#ifndef USB_PERIPHERAL_ENDPOINT_H +// cppcheck-suppress misra-c2012-2.5 +#define USB_PERIPHERAL_ENDPOINT_H + +#include +#include + +#include "usb_common_elements.h" +#include "usb_protocol_headers.h" + +/** + * @ingroup usb_peripheral_endpoint + * @brief Configures the endpoint with the desired settings using the Control and Status Register. + * Used to set up an endpoint before using it in an application. + * Sets up all the control register settings by looking up the usb_config.h file and clears the count registers. + * @param pipe - A combination of endpoint address and direction + * @param endpointSize - Number of bytes of data supported by the endpoint in one USB transaction + * @param endpointType - Type of USB endpoint as defined by usb_endpoint_type + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_EndpointConfigure(USB_PIPE_t pipe, uint16_t endpointSize, USB_ENDPOINT_t endpointType); + +/** + * @ingroup usb_peripheral_endpoint + * @brief Disables the endpoint by setting the endpoint type to 0x00. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_EndpointDisable(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_endpoint + * @brief Helper function to return the endpoint size. + * @param pipe - A combination of endpoint address and direction + * @return The size of the endpoint + */ +uint16_t USB_EndpointSizeGet(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_endpoint + * @brief Helper function to return the endpoint type. + * @param pipe - A combination of endpoint address and direction + * @return The endpoint type + */ +USB_ENDPOINT_t USB_EndpointTypeGet(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_endpoint + * @brief Helps stall an endpoint when a command received from the host is invalid or unrecognizable. + * Used if the host sends data that is not supported by the device. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_EndpointStall(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_endpoint + * @brief Helps clear the Stall condition after the device has recovered from an unsupported command from the host. + * Used to reset stall before the next USB transfer. + * Used when the host issues a clear HALT/Feature request to reset stall. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_EndpointStallClear(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_endpoint + * @brief Helper function to return the endpoint Stall condition. + * @param pipe - A combination of endpoint address and direction + * @return A boolean value representing the Stall condition. If the pipe address is out of bounds, the function will always return false + */ +bool USB_EndpointIsStalled(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_endpoint + * @brief Acknowledges the stall status condition by clearing the Stall Status bit. + * Used to clear the Stall Status bit after a stall has been detected. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_EndpointStalledConditionAck(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_endpoint + * @brief Sets the Data Toggle bit on an endpoint which is used to ensure correct data sequence. + * Only used if hardware data toggling is not available. + * After a successful transaction, toggle the Data Toggle bit. + * For SETUP transactions, ensure that the SETUP stage clears the Data Toggle bit, + * while the data stage and status stage set the Data Toggle bit. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_DataToggleSet(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_endpoint + * @brief Clears the Data Toggle bit on an endpoint which is used to ensure correct data sequence. + * Only used if hardware data toggling is not available. + * After a successful transaction, toggle the Data Toggle bit. + * For SETUP transactions, ensure that the SETUP stage clears the Data Toggle bit, + * while the data stage and status stage set the Data Toggle bit. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_DataToggleClear(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_endpoint + * @brief Toggles the Data Toggle bit on an endpoint which is used to ensure correct data sequence. + * Only used if hardware data toggling is not available. + * After a successful transaction, toggle the Data Toggle bit. + * For SETUP transactions, ensure that the SETUP stage clears the Data Toggle bit, + * while the data stage and status stage set the Data Toggle bit. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_DataToggle(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_endpoint + * @brief Converts an endpoint size in number of bytes into a register setting. + * Converts the endpoint size bit mask based on the EP_BUFSIZE setting of the endpoint control register. + * @param endpointSize - The size to convert + * @param endpointType - The endpoint type + * @param endpointMaskPtr - Pointer to the mask variable to write to + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t ConvertEndpointSizeToMask(uint16_t endpointSize, USB_ENDPOINT_t endpointType, uint8_t *endpointMaskPtr); + +/** + * @ingroup usb_peripheral_endpoint + * @brief Configures the endpoint data buffer to a location in RAM for the next transaction. + * @param pipe - A combination of endpoint address and direction + * @param bufAddress - The pointer to the data buffer the endpoint will use + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t EndpointBufferSet(USB_PIPE_t pipe, uint8_t *bufAddress); + +#endif /* USB_PERIPHERAL_ENDPOINT_H */ diff --git a/mcc_generated_files/usb/usb_peripheral/usb_peripheral_read_write.c b/mcc_generated_files/usb/usb_peripheral/usb_peripheral_read_write.c new file mode 100644 index 0000000..1d91d08 --- /dev/null +++ b/mcc_generated_files/usb/usb_peripheral/usb_peripheral_read_write.c @@ -0,0 +1,484 @@ +/** + * USBPERIPHERALREADWRITE Peripheral Read/Write Source File + * @file usb_peripheral_read_write.c + * @ingroup usb_peripheral_read_write + * @brief API module for usb_peripheral covering low level USB transaction functions. + * @version USB Device Stack HAL Driver Version 1.0.0 + */ + +/* + (c) 2021 Microchip Technology Inc. and its subsidiaries. + + Subject to your compliance with these terms, you may use Microchip software and any + derivatives exclusively with Microchip products. It is your responsibility to comply with third party + license terms applicable to your use of third party software (including open source software) that + may accompany Microchip software. + + THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY + IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS + FOR A PARTICULAR PURPOSE. + + IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, + INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND + WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP + HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO + THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL + CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT + OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS + SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/** + * @ingroup usb_peripheral_read_write + * @def Calculates from pipe address and direction to location in a transfer array. + * @param pipe - A combination of endpoint address and direction + * @return The pipe transaction index for this pipe in pipe_transfer[] + */ +#define PipeTransferIndexGet(pipe) (((pipe).address * 2) + (pipe).direction) + +STATIC USB_PIPE_TRANSFER_t pipeTransfer[USB_EP_NUM * 2]; + +RETURN_CODE_t USB_TransactionStart(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + if (USB_EP_DIR_OUT == pipe.direction) + { + USB_EndpointOutNAKClear(pipe.address); + } + else + { + USB_EndpointInNAKClear(pipe.address); + } + + status = SUCCESS; + } + + return status; +} + +RETURN_CODE_t USB_TransactionAbort(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + if (USB_EP_DIR_OUT == pipe.direction) + { + USB_EndpointOutNAKSet(pipe.address); + } + else + { + USB_EndpointInNAKSet(pipe.address); + } + + pipeTransfer[PipeTransferIndexGet(pipe)].status = USB_PIPE_TRANSFER_ABORTED; + status = SUCCESS; + } + + return status; +} + +RETURN_CODE_t USB_TransactionCompleteAck(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + if (USB_EP_DIR_OUT == pipe.direction) + { + USB_EndpointOutTransactionCompleteAck(pipe.address); + } + else + { + USB_EndpointInTransactionCompleteAck(pipe.address); + } + pipeTransfer[PipeTransferIndexGet(pipe)].status = USB_PIPE_TRANSFER_OK; + status = SUCCESS; + } + + return status; +} + +bool USB_TransactionIsCompleted(void) +{ + return USB_TransactionCompleteInterruptIs(); +} + +RETURN_CODE_t USB_TransactionCompletedPipeGet(USB_PIPE_t *pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + + if (USB_TransactionIsCompleted()) + { + // Finds FIFO entry by adding (subtracting) the signed read pointer to the size of the FIFO + // Reading the FIFO Read Pointer will handle the Transaction Complete Interrupt flag. + // The USB_FifoReadPointerGet is a device-specific function. + + uint8_t fifoEntry = endpointTable.FIFO[(USB_EP_NUM * 2u) + USB_FifoReadPointerGet()]; + + // The FIFO entry contains the endpoint address and direction of the endpoint to handle next. + USB_PIPE_t returnPipe = { .direction = (fifoEntry & USB_DIR_bm) >> USB_DIR_bp, .address = (fifoEntry & USB_EPNUM_gm) >> USB_EPNUM_gp }; + + if ((uint8_t)USB_EP_NUM <= returnPipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + pipe->address = returnPipe.address; + pipe->direction = returnPipe.direction; + status = SUCCESS; + } + } + else + { + // No transaction is completed. + status = PIPE_TRANSFER_ERROR; + } + + return status; +} + +RETURN_CODE_t USB_PipeReset(USB_PIPE_t pipe) +{ + RETURN_CODE_t status = UNINITIALIZED; + USB_PIPE_TRANSFER_t *pipeTransferPtr = &pipeTransfer[PipeTransferIndexGet(pipe)]; + + if ((uint8_t)USB_EP_NUM <= pipe.address) + { + status = ENDPOINT_ADDRESS_ERROR; + } + else + { + pipeTransferPtr->status = USB_PIPE_TRANSFER_OK; + pipeTransferPtr->transferDataPtr = NULL; + pipeTransferPtr->transferDataSize = 0; + pipeTransferPtr->bytesTransferred = 0; + pipeTransferPtr->transferEndCallback = NULL; + pipeTransferPtr->ZLPEnable = false; + + status = SUCCESS; + } + + return status; +} + +USB_TRANSFER_STATUS_t USB_PipeStatusGet(USB_PIPE_t pipe) +{ + + return pipeTransfer[PipeTransferIndexGet(pipe)].status; +} + +bool USB_PipeStatusIsBusy(USB_PIPE_t pipe) +{ + + return (pipeTransfer[PipeTransferIndexGet(pipe)].status == USB_PIPE_TRANSFER_BUSY); +} + +void USB_PipeDataPtrSet(USB_PIPE_t pipe, uint8_t *dataPtr) +{ + + pipeTransfer[PipeTransferIndexGet(pipe)].transferDataPtr = dataPtr; +} + +uint8_t *USB_PipeDataPtrGet(USB_PIPE_t pipe) +{ + + return pipeTransfer[PipeTransferIndexGet(pipe)].transferDataPtr; +} + +void USB_PipeDataToTransferSizeSet(USB_PIPE_t pipe, uint16_t dataSize) +{ + + pipeTransfer[PipeTransferIndexGet(pipe)].transferDataSize = dataSize; +} + +uint16_t USB_PipeDataToTransferSizeGet(USB_PIPE_t pipe) +{ + + return pipeTransfer[PipeTransferIndexGet(pipe)].transferDataSize; +} + +uint16_t USB_PipeDataTransferredSizeGet(USB_PIPE_t pipe) +{ + + return pipeTransfer[PipeTransferIndexGet(pipe)].bytesTransferred; +} + +void USB_PipeDataTransferredSizeSet(USB_PIPE_t pipe, uint16_t dataSize) +{ + + pipeTransfer[PipeTransferIndexGet(pipe)].bytesTransferred = dataSize; +} + +void USB_PipeDataTransferredSizeReset(USB_PIPE_t pipe) +{ + + pipeTransfer[PipeTransferIndexGet(pipe)].bytesTransferred = 0; +} + +void USB_PipeTransferZLP_Enable(USB_PIPE_t pipe) +{ + // Only enable manual ZLP if hardware AZLP is not enabled. + if (((USB_EP_DIR_IN == pipe.direction) && (0u == endpointStaticConfig[pipe.address].InAzlpEnable)) + || ((USB_EP_DIR_OUT == pipe.direction) && (0u == endpointStaticConfig[pipe.address].OutAzlpEnable))) + { + pipeTransfer[PipeTransferIndexGet(pipe)].ZLPEnable = true; + } +} + +void USB_PipeTransferEndCallbackRegister(USB_PIPE_t pipe, USB_TRANSFER_END_CALLBACK_t callback) +{ + pipeTransfer[PipeTransferIndexGet(pipe)].transferEndCallback = callback; +} + +void USB_PipeTransferEndCallback(USB_PIPE_t pipe) +{ + USB_PIPE_TRANSFER_t *pipeTransferPtr = &pipeTransfer[PipeTransferIndexGet(pipe)]; + + if (NULL != pipeTransferPtr->transferEndCallback) + { + pipeTransferPtr->transferEndCallback(pipe, pipeTransferPtr->status, pipeTransferPtr->bytesTransferred); + } +} + +RETURN_CODE_t USB_InTransactionRun(USB_PIPE_t pipe) +{ + USB_PIPE_TRANSFER_t *pipeTransferPtr = &pipeTransfer[PipeTransferIndexGet(pipe)]; + RETURN_CODE_t status = UNINITIALIZED; + uint16_t nextTransactionSize; + + if (USB_EP_DIR_IN != pipe.direction) + { + // Pipe is OUT, returns error code. + status = ENDPOINT_DIRECTION_ERROR; + } + else + { + // Makes sure the transfer status is busy. + pipeTransferPtr->status = USB_PIPE_TRANSFER_BUSY; + + // Calculates the size of next transaction. + nextTransactionSize = pipeTransferPtr->transferDataSize - pipeTransferPtr->bytesTransferred; + if (0U == nextTransactionSize) + { + // All data is sent, check if we need to send a manual ZLP as well. + if (true == pipeTransferPtr->ZLPEnable) + { + // Sends a zero-length package by setting bytes to send to 0. + USB_NumberBytesToSendSet(pipe.address, 0u); + USB_NumberBytesSentReset(pipe.address); + USB_EndpointInNAKClear(pipe.address); + + // Clears ZLPEnable to show it has been sent. + pipeTransferPtr->ZLPEnable = false; + } + else + { + // Everything has been sent, return transfer status to OK. + pipeTransferPtr->status = USB_PIPE_TRANSFER_OK; + } + + status = SUCCESS; + } + else + { + uint16_t endpointSize = USB_EndpointSizeGet(pipe); + if ((0u == endpointStaticConfig[pipe.address].InMultipktEnable) && (nextTransactionSize > endpointSize)) + { + // Only send endpoint size packet per transaction when MultiPacket is disabled. + nextTransactionSize = endpointSize; + } + else + { + // Check if a manual ZLP is needed after transaction, if transaction size is a multiple of endpoint size. + pipeTransferPtr->ZLPEnable = (pipeTransferPtr->ZLPEnable) && (0U == (nextTransactionSize % (uint16_t)endpointSize)); + } + + // Configure where to transfer from. + status = EndpointBufferSet(pipe, &pipeTransferPtr->transferDataPtr[pipeTransferPtr->bytesTransferred]); + + // Send transaction + if (SUCCESS == status) + { + USB_NumberBytesToSendSet(pipe.address, nextTransactionSize); + USB_NumberBytesSentReset(pipe.address); + USB_EndpointInNAKClear(pipe.address); + } + } + } + + return status; +} + +RETURN_CODE_t USB_OutTransactionRun(USB_PIPE_t pipe) +{ + USB_PIPE_TRANSFER_t *pipeTransferPtr = &pipeTransfer[PipeTransferIndexGet(pipe)]; + RETURN_CODE_t status = UNINITIALIZED; + + if (USB_EP_DIR_OUT != pipe.direction) + { + // Pipe is IN, return error code. + status = ENDPOINT_DIRECTION_ERROR; + } + else + { + // Make sure the transfer status is busy. + pipeTransferPtr->status = USB_PIPE_TRANSFER_BUSY; + + // Update the data pointer for the next transaction. + status = EndpointBufferSet(pipe, &pipeTransferPtr->transferDataPtr[pipeTransferPtr->bytesTransferred]); + + // Calculate the size of next transaction. + uint16_t endpointSize = USB_EndpointSizeGet(pipe); + uint16_t nextTransactionSize = pipeTransferPtr->transferDataSize - pipeTransferPtr->bytesTransferred; + if (0u == endpointStaticConfig[pipe.address].OutMultipktEnable) + { + if (nextTransactionSize < endpointSize) + { + // Temporarily enable MultiPacket to avoid receiving data that overflows endpoint buffer. + USB_EndpointOutMultipktEnable(pipe.address); + } + else + { + // Only expect one endpoint size packet per transaction when MultiPacket is disabled. + if (nextTransactionSize > endpointSize) + { + nextTransactionSize = endpointSize; + } + + // Disable MultiPacket in case it was enabled for previous transaction. + USB_EndpointOutMultipktDisable(pipe.address); + } + } + + if (0u == nextTransactionSize) + { + // Clear ZLPEnable to indicate that the transfer is completed and the ZLP transfer is initated. + pipeTransferPtr->ZLPEnable = false; + + // Everything has been sent, return transfer status to OK. + pipeTransferPtr->status = USB_PIPE_TRANSFER_OK; + } + else + { + // Check if a manual ZLP is needed after transaction, if transaction size is a multiple of endpoint size. + pipeTransferPtr->ZLPEnable = pipeTransferPtr->ZLPEnable && (0u == (nextTransactionSize % endpointSize)); + } + + // Start the transaction + USB_NumberBytesReceivedReset(pipe.address); + USB_NumberBytesToReceiveSet(pipe.address, nextTransactionSize); + USB_EndpointOutNAKClear(pipe.address); + } + + return status; +} + +RETURN_CODE_t USB_PipeTransactionComplete(USB_PIPE_t pipe) +{ + USB_PIPE_TRANSFER_t *pipeTransferPtr = &pipeTransfer[PipeTransferIndexGet(pipe)]; + RETURN_CODE_t status = UNINITIALIZED; + uint16_t transactionSize; + + if (USB_EP_DIR_IN == pipe.direction) + { + // Transaction complete on IN. + if (USB_EndpointInMultipktIsEnabled(pipe.address) == true) + { + // With multipacket enabled we know exactly what got transferred. + transactionSize = USB_NumberBytesSentGet(pipe.address); + } + else + { + // With multipacket disabled we know what we meant to transfer. + transactionSize = USB_NumberBytesToSendGet(pipe.address); + } + + // Check if we need to send more data, or ZLP. + pipeTransferPtr->bytesTransferred += transactionSize; + if ((pipeTransferPtr->bytesTransferred != pipeTransferPtr->transferDataSize) || (pipeTransferPtr->ZLPEnable)) + { + status = USB_InTransactionRun(pipe); + } + else + { + pipeTransferPtr->status = USB_PIPE_TRANSFER_OK; + status = SUCCESS; + } + } + else + { + // Transaction complete on OUT. + transactionSize = USB_NumberBytesReceivedGet(pipe.address); + + // Checks if we have transferred more than we wanted. + uint16_t expectedTransferRemainingSize = pipeTransferPtr->transferDataSize - pipeTransferPtr->bytesTransferred; + if (expectedTransferRemainingSize < transactionSize) + { + // We may have overflowed the receive location! + if (USB_NumberBytesToReceiveGet(pipe.address) == expectedTransferRemainingSize) + { + // Multipacket has limited what we received, even if transactionSize is larger. + transactionSize = expectedTransferRemainingSize; + } + else + { + pipeTransferPtr->status = USB_PIPE_TRANSFER_ERROR; + status = PIPE_TRANSFER_ERROR; + } + } + + if (PIPE_TRANSFER_ERROR != status) + { + // Updates bytes transfered and check if we need to run more transactions. + pipeTransferPtr->bytesTransferred += transactionSize; + + if (((pipeTransferPtr->bytesTransferred < pipeTransferPtr->transferDataSize) || pipeTransferPtr->ZLPEnable) && (0u == (transactionSize % USB_EndpointSizeGet(pipe)))) + { + status = USB_OutTransactionRun(pipe); + } + else + { + pipeTransferPtr->status = USB_PIPE_TRANSFER_OK; + status = SUCCESS; + } + } + } + + // Checks if transfer is completed and cleans up. + if (USB_PIPE_TRANSFER_BUSY != pipeTransferPtr->status) + { + USB_PipeTransferEndCallback(pipe); + } + + return status; +} diff --git a/mcc_generated_files/usb/usb_peripheral/usb_peripheral_read_write.h b/mcc_generated_files/usb/usb_peripheral/usb_peripheral_read_write.h new file mode 100644 index 0000000..9c477c0 --- /dev/null +++ b/mcc_generated_files/usb/usb_peripheral/usb_peripheral_read_write.h @@ -0,0 +1,222 @@ +/** + * USBPERIPHERALREADWRITE Peripheral Read/Write Header File + * @file usb_peripheral_read_write.h + * @defgroup usb_peripheral_read_write USB Peripheral Read/Write + * @ingroup usb_peripheral + * @brief API module for usb_peripheral covering low-level USB transaction functions. + * @version USB Device Stack HAL Driver Version 1.0.0 + */ +/* + (c) 2021 Microchip Technology Inc. and its subsidiaries. + + Subject to your compliance with these terms, you may use Microchip software and any + derivatives exclusively with Microchip products. It is your responsibility to comply with third party + license terms applicable to your use of third party software (including open source software) that + may accompany Microchip software. + + THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY + IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS + FOR A PARTICULAR PURPOSE. + + IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, + INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND + WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP + HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO + THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL + CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT + OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS + SOFTWARE. + */ + +#ifndef USB_PERIPHERAL_READ_WRITE_H +// cppcheck-suppress misra-c2012-2.5 +#define USB_PERIPHERAL_READ_WRITE_H + +#include +#include + +#include "usb_common_elements.h" +#include "usb_protocol_headers.h" + +/** + * @ingroup usb_peripheral_read_write + * @brief Starts sending or receiving data on an endpoint by clearing BUSNACK. + * Used as a final step while setting up a transaction on the bus. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_TransactionStart(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Aborts the next transaction on an endpoint by setting BUSNACK. + * Used to stop exchanging data on an endpoint. The device will start NAKing requests from the host after calling this API. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_TransactionAbort(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Acknowledges the Transaction Complete status condition by clearing the Transaction Complete status bit. + * Used to clear the Transaction Complete status bit after a transaction has successfully completed. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_TransactionCompleteAck(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Helper function to return the endpoint transaction complete condition. + * @param None. + * @retval 0 - Transaction not complete or pipe address is out of bounds + * @retval 1 - Transaction is complete + */ +bool USB_TransactionIsCompleted(void); + +/** + * @ingroup usb_peripheral_read_write + * @brief Returns the pipe address and direction for the latest completed transaction. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_TransactionCompletedPipeGet(USB_PIPE_t *pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Resets the pipe. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_PipeReset(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Gets the current status of pipe. + * @param pipe - A combination of endpoint address and direction + * @return USB_PIPE_TRANSFER_OK or an Error code according to USB_TRANSFER_STATUS_t + */ +USB_TRANSFER_STATUS_t USB_PipeStatusGet(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Checks if the pipe status is busy. + * @param pipe - A combination of endpoint address and direction + * @retval 0 - Pipe status not busy + * @retval 1 - Pipe status is busy + */ +bool USB_PipeStatusIsBusy(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Configures the pointer for the data transfer in a given pipe. + * @param pipe - A combination of endpoint address and direction + * @param *dataPtr - The pointer to the data location + * @return None. + */ +void USB_PipeDataPtrSet(USB_PIPE_t pipe, uint8_t *dataPtr); + +/** + * @ingroup usb_peripheral_read_write + * @brief Gets the current data pointer for a given pipe. + * @param pipe - A combination of endpoint address and direction + * @return The pointer to the data location + */ +uint8_t *USB_PipeDataPtrGet(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Sets the size of pipe data to transfer. + * @param pipe - A combination of endpoint address and direction + * @param dataSize - The size of pipe data to transfer + * @return None. + */ +void USB_PipeDataToTransferSizeSet(USB_PIPE_t pipe, uint16_t dataSize); + +/** + * @ingroup usb_peripheral_read_write + * @brief Gets the size of pipe data to transfer. + * @param pipe - A combination of endpoint address and direction + * @return The size of pipe data to transfer + */ +uint16_t USB_PipeDataToTransferSizeGet(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Gets the size of the transferred pipe data. + * @param pipe - A combination of endpoint address and direction + * @return The size of transferred pipe data + */ +uint16_t USB_PipeDataTransferredSizeGet(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Sets the size of the transferred pipe data. + * @param pipe - A combination of endpoint address and direction + * @param dataSize - The size of pipe data transferred + * @return None. + */ +void USB_PipeDataTransferredSizeSet(USB_PIPE_t pipe, uint16_t dataSize); + +/** + * @ingroup usb_peripheral_read_write + * @brief Resets the size of transferred pipe data. + * @param pipe - A combination of endpoint address and direction + * @return None. + */ +void USB_PipeDataTransferredSizeReset(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Enables a ZLP on a transfer. + * It is enabled by default if the AZLP static config is enabled for the pipe. + * @param pipe - A combination of endpoint address and direction + * @return None. + */ +void USB_PipeTransferZLP_Enable(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Sets the callback for transfer end. + * @param pipe - A combination of endpoint address and direction + * @param callback - A combination of pipe, status and transferred bytes + * @return None. + */ +void USB_PipeTransferEndCallbackRegister(USB_PIPE_t pipe, USB_TRANSFER_END_CALLBACK_t callback); + +/** + * @ingroup usb_peripheral_read_write + * @brief Calls the callback for transfer end. + * @param pipe - A combination of endpoint address and direction + * @return None. + */ +void USB_PipeTransferEndCallback(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Checks the correctness of IN transactions and runs them. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_InTransactionRun(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Checks the correctness OUT transactions and runs them. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_OutTransactionRun(USB_PIPE_t pipe); + +/** + * @ingroup usb_peripheral_read_write + * @brief Handles completed IN and OUT transactions. + * Processes the completed transaction and either completes the transfer or runs the next transaction. + * Will call the pipe transferEndCallback at the end of transfer, if configured. + * @param pipe - A combination of endpoint address and direction + * @return SUCCESS or an Error code according to RETURN_CODE_t + */ +RETURN_CODE_t USB_PipeTransactionComplete(USB_PIPE_t pipe); + +#endif /* USB_PERIPHERAL_READ_WRITE_H */ -- cgit v1.2.3