- basic docs added

- doxygen styling added
- CDC -> ACM refactor
- type refactoring
- examples categorized
- flatUSB_config.h examples added
This commit is contained in:
Wiesner András 2024-11-16 21:53:01 +01:00
parent 685fa77bda
commit 2a69c57225
38 changed files with 6946 additions and 1821 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
docs/html/

View File

@ -10,8 +10,8 @@ endif()
set(FLATUSB_CLASSES_SRC "") set(FLATUSB_CLASSES_SRC "")
if ("CDC_ACM" IN_LIST FLATUSB_CLASSES) if ("CDC_ACM" IN_LIST FLATUSB_CLASSES)
list(APPEND FLATUSB_CLASSES_SRC list(APPEND FLATUSB_CLASSES_SRC
class/cdc.c class/acm.c
class/cdc.h class/acm.h
) )
endif() endif()
@ -73,3 +73,9 @@ if (FLATUSB_DESC_JSON AND FLATUSB_DESC_DIR)
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
) )
endif() endif()
add_custom_target(
flatUSB-docs
COMMAND doxygen
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)

2676
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

158
class/acm.c Normal file
View File

@ -0,0 +1,158 @@
/**
******************************************************************************
* @file cdc.c
* @copyright András Wiesner, 2024-\showdate "%Y"
* @brief CDC ACM implementation module for the flatUSB project.
******************************************************************************
*/
#include "acm.h"
#include <memory.h>
#include <string.h>
#include "../usb.h"
#include "../usb_device_types.h"
#include <blocking_io/blocking_fifo.h>
// -------------------------
static Usb_AcmState acms = {0}; ///< ACM module state
static uint8_t tx_buffer[USB_ACM_PCKT_BUFSIZE]; ///< Transmit buffer
static uint8_t fifo_mem[USB_ACM_FIFO_MEM_SIZE]; ///< Memory assigned to the TX BFifo
static BFifo fifo; ///< TX Blocking FIFO
// -------------------------
void usb_acm_read_callback(const uint8_t *data, uint32_t size);
void usb_acm_init(const Usb_Acm_EpAssignments *as) {
// clear the structure
memset(&acms, 0, sizeof(Usb_AcmState));
// set Control Line State to something invalid
acms.control_line_state.D = USB_ACM_INVALID_CONTROL_LINE_STATE;
// fill-in assigments
acms.ep_assignments = *as;
// initialize buffer
bfifo_create(&fifo, fifo_mem, USB_ACM_FIFO_MEM_SIZE);
// initialize an all-0 interrupt
acms.interrupt_data = 0;
acms.interrupt_pending = true;
// communication parameters have not been set
acms.commInit = false;
// from now on CDC module is considered initialized
acms.moduleInit = true;
}
static void usb_cdc_review_comm_init() {
// check if line coding was initialized
Usb_Acm_LineCodingStruct *lc = &acms.line_coding;
bool lcOk = (lc->dwDTERate != 0) && (lc->bDataBits != 0);
// check if control line state was initialized
bool clsOk = acms.control_line_state.D != USB_ACM_INVALID_CONTROL_LINE_STATE;
// combine the above criteria
acms.commInit = lcOk && clsOk;
}
int usb_acm_process_and_return(Usb_CallbackEvent *cbevt) {
int ret = -1;
switch (cbevt->type) {
case USB_CBEVT_UNKNOWN_REQ: {
// initialize reply
cbevt->reply_data = NULL;
cbevt->reply_size = 0;
cbevt->reply_valid = true;
switch (cbevt->setup_request->bRequest) {
case USB_ACM_SET_LINE_CODING: // set line coding
memcpy(&acms.line_coding, cbevt->data, sizeof(Usb_Acm_LineCodingStruct));
usb_cdc_review_comm_init(); // review the communcation initialization state
ret = 0;
break;
case USB_ACM_GET_LINE_CODING: // get line coding
cbevt->reply_data = (const uint8_t *)&acms.line_coding; // expert move: pass the pointer, no copying
cbevt->reply_size = sizeof(Usb_Acm_LineCodingStruct);
ret = 0;
break;
case USB_ACM_SEND_BREAK: // send break
// do nothing
ret = 0;
break;
case USB_ACM_SET_CONTROL_LINE_STATE: // set control line state
acms.control_line_state.D = cbevt->setup_request->wValue; // control line state is carried in wValue of the SETUP request
usb_cdc_review_comm_init(); // review the communcation initialization state
ret = 0;
break;
default:
cbevt->reply_valid = false; // this event is not processed by or not related to the CDC ACM module
break;
}
break;
}
case USB_CBEVT_OUT: {
if (cbevt->ep == acms.ep_assignments.data_ep) {
ret = 0;
usb_acm_read_callback(cbevt->data, cbevt->size);
}
break;
}
case USB_CBEVT_IN: {
if (cbevt->ep == acms.ep_assignments.control_ep) { // if notification feeding is requested
if (acms.interrupt_pending) {
usbcore_schedule_transmission(acms.ep_assignments.control_ep, (const uint8_t *)&(acms.interrupt_data), sizeof(uint16_t)); // send ZLP
acms.interrupt_pending = false;
}
ret = 0;
} else if (cbevt->ep == acms.ep_assignments.data_ep) { // if data are requested
ret = 0;
// read from the fifo
if (acms.commInit) {
uint32_t readSize = bfifo_read(&fifo, tx_buffer, USB_ACM_PCKT_BUFSIZE);
if (readSize > 0) {
uint32_t writeSize = usbcore_schedule_transmission(acms.ep_assignments.data_ep, tx_buffer, readSize); // write data acquired from the buffer
bfifo_pop(&fifo, writeSize, 0); // pop with no blocking
}
}
}
}
default:
break;
}
return ret;
}
void usb_acm_write(const uint8_t *data, uint32_t size) {
if (acms.moduleInit) {
bfifo_push_all(&fifo, data, size);
usbcore_wake_up_endpoint(acms.ep_assignments.data_ep, USB_IN);
}
}
/**
* @fn void usb_acm_read_callback(const uint8_t *data, uint32_t size)
* Callback function prototype for data reception. This function is
* expected to be overridden by the application.
*
* @param data ingress data
* @param size length of the data
*/
__attribute__((weak)) void usb_acm_read_callback(const uint8_t *data, uint32_t size) {
(void)data;
(void)size;
return;
}

129
class/acm.h Normal file
View File

@ -0,0 +1,129 @@
/**
******************************************************************************
* @file cdc.h
* @brief This is the USB Communication Device Class, Abstract Control Model
* implementation module for the flatUSB project. The following standard
* requestes are implemented: `SetLineCoding`, `GetLineCoding`,
* `SetControlLineState` and `SendBreak`. Data transmission is performed by
* calling `usb_acm_write()`. Ingress data is passed to the application through
* the `usb_acm_read_callback()` function. A weak prototype is provided which
* is expected to be overridden by the application. Supplying a BlockingFifo
* is mandatory!
*
* If necessary, `USB_CDC_FIFO_MEM_SIZE` and `USB_CDC_PCKT_BUFSIZE` can be freely
* overridden in the flatUSB configuration file.
*
* For more information about the USB CDC ACM class refer to the
* <a href="https://www.usb.org/document-library/class-definitions-communication-devices-12" target="_blank">
* USB CDC PSTN subclass</a>.
*
* @copyright András Wiesner, 2024-\showdate "%Y"
******************************************************************************
*/
#ifndef CORE_USB_CLASS_CDC
#define CORE_USB_CLASS_CDC
#include "../usb_callback_event.h"
/**
* CDC request codes
*/
typedef enum {
USB_ACM_SET_COMM_FEATURE = 0x2, ///< SetCommFeature
USB_ACM_GET_COMM_FEATURE = 0x3, ///< GetCommFeature
USB_ACM_CLEAR_COMM_FEATURE = 0x4, ///< ClearCommFeature
USB_ACM_SET_AUX_LINE_STATE = 0x10, ///< SetAuxLineState
USB_ACM_SET_HOOK_STATE = 0x11, ///< SetHookState
USB_ACM_PULSE_SETUP = 0x12, ///< PulseSetup
USB_ACM_SEND_PULSE = 0x13, ///< SendPulse
USB_ACM_SET_PULSE_TIME = 0x14, ///< SetPulseTime
USB_ACM_RING_AUX_JACK = 0x15, ///< RingAuxJack
USB_ACM_SET_LINE_CODING = 0x20, ///< SetLineCoding
USB_ACM_GET_LINE_CODING = 0x21, ///< GetLineCoding
USB_ACM_SET_CONTROL_LINE_STATE = 0x22, ///< SetControlLineState
USB_ACM_SEND_BREAK = 0x23, ///< SendBreak
USB_ACM_SET_RINGER_PARMS = 0x30, ///< SetRingerParms
USB_ACM_GET_RINGER_PARMS = 0x31, ///< GetRingerParms
USB_ACM_SET_OPERATION_PARMS = 0x32, ///< SetOperationParms
USB_ACM_GET_OPERATION_PARMS = 0x33, ///< GetOperationParms
USB_ACM_SET_LINE_PARMS = 0x34, ///< GetLineParms
} Usb_Acm_RequestCodes;
/**
* ACM line coding structure
*/
typedef struct {
uint32_t dwDTERate; ///< data terminal rate, bits per second
uint8_t bCharFormat; ///< character format
uint8_t bParityType; ///< parity type
uint8_t bDataBits; ///< data bits
} Usb_Acm_LineCodingStruct;
/**
* CDC control line state struct
*/
typedef struct {
uint16_t D; ///< settings word
} Usb_Acm_ControlLineStateStruct;
// ----------------
/**
* Endpoint assignments
*/
typedef struct {
uint8_t control_ep : 4; ///< Control endpoint
uint8_t data_ep : 4; ///< Data endpoint
} Usb_Acm_EpAssignments;
typedef struct {
Usb_Acm_EpAssignments ep_assignments; ///< Endpoint assignments
Usb_Acm_LineCodingStruct line_coding; ///< Line Coding
Usb_Acm_ControlLineStateStruct control_line_state; ///< Control Line State
uint16_t interrupt_data; ///< Data sent though the next transfer on the notification element
bool interrupt_pending; ///< Interrupt data is valid and should be send in the next cycle
bool moduleInit; ///< CDC module is initialized
bool commInit; ///< Communication protocol is initialized
} Usb_AcmState;
// ----------------
#define USB_ACM_INVALID_CONTROL_LINE_STATE (0xFFFF) ///< Invalid Control Line State
// ----------------
#ifndef USB_ACM_FIFO_MEM_SIZE
#define USB_ACM_FIFO_MEM_SIZE (3072) ///< CDC ACM FIFO memory size
#endif
#ifndef USB_ACM_PCKT_BUFSIZE
#define USB_ACM_PCKT_BUFSIZE (128) ///< Buffer size assigned to the data transfer endpoint
#endif
// ----------------
/**
* Initialize CDC ACM module.
*
* @param as pointer to filled endpoint assignments object
*/
void usb_acm_init(const Usb_Acm_EpAssignments *as);
/**
* Regular USB class process and return function.
*
* @param cbevt pointer to callback event emitted by the USB core
* @return request is unprocessed if < 0
*/
int usb_acm_process_and_return(Usb_CallbackEvent *cbevt);
/**
* Write to CDC ACM interface.
*
* @param data data to be sent through the interface
* @param size length of the data
*/
void usb_acm_write(const uint8_t *data, uint32_t size);
#endif /* CORE_USB_CLASS_CDC */

View File

@ -1,180 +0,0 @@
#include "cdc.h"
#include <memory.h>
#include "../usb_device_types.h"
#include "../usb.h"
#include <blocking_io/blocking_fifo.h>
#include <cmsis_gcc.h>
#include <string.h>
// state
static USB_CdcState cdcs = {0};
static uint8_t tx_buffer[USB_CDC_PCKT_BUFSIZE];
#define USB_CDC_FIFO_MEM_SIZE (3072) // FIXME: ez vagy a blocking FIFO bugos
static uint8_t fifo_mem[USB_CDC_FIFO_MEM_SIZE];
static BFifo fifo;
void usb_cdc_read_callback(const uint8_t *data, uint32_t size);
void usb_cdc_init(const USB_CdcAssignments *as) {
// clear the structure
memset(&cdcs, 0, sizeof(USB_CdcState));
// set Control Line State to something invalid
cdcs.control_line_state.D = USB_CDC_INVALID_CONTROL_LINE_STATE;
// fill-in default values
// USB_Cdc_LineCodingStruct *lc = &cdcs.line_coding;
// lc->dwDTERate = USB_CDC_DEFAULT_BITRATE;
// lc->bCharFormat = USB_CDC_DEFAULT_CHAR_FORMAT;
// lc->bParityType = USB_CDC_DEFAULT_PARITY_TYPE;
// lc->bDataBits = USB_CDC_DEFAULT_DATA_BITS;
// fill-in assigments
cdcs.ep_assignments = *as;
// initialize buffer
bfifo_create(&fifo, fifo_mem, USB_CDC_FIFO_MEM_SIZE);
// initialize an all-0 interrupt
cdcs.interrupt_data = 0;
cdcs.interrupt_pending = true;
// communication parameters have not been set
cdcs.commInit = false;
// from now on CDC module is considered initialized
cdcs.moduleInit = true;
}
// static uint8_t replyBuf[sizeof(USB_Cdc_LineCodingStruct)];
// static void usbcore_setup_cplt_cb(uint8_t in) {
// usbcore_wake_up_endpoint(cdcs.ep_assignments.data_ep, USB_IN);
// }
static void usb_cdc_review_comm_init() {
// check if line coding was initialized
USB_Cdc_LineCodingStruct *lc = &cdcs.line_coding;
bool lcOk = (lc->dwDTERate != 0) && (lc->bDataBits != 0);
// check if control line state was initialized
bool clsOk = cdcs.control_line_state.D != USB_CDC_INVALID_CONTROL_LINE_STATE;
// combine the above criteria
cdcs.commInit = lcOk && clsOk;
// // wake up endpoint if initialized
// if (cdcs.commInit) {
// usbcore_register_IN_callback(0, usbcore_setup_cplt_cb);
// }
}
int usb_cdc_process_and_return(USB_CallbackEvent *cbevt) {
int ret = -1;
switch (cbevt->type) {
case USB_CBEVT_UNKNOWN_REQ: {
// initialize reply
cbevt->reply_data = NULL;
cbevt->reply_size = 0;
cbevt->reply_valid = true;
switch (cbevt->setup_request->bRequest) {
case USB_CDC_SET_LINE_CODING: // set line coding
memcpy(&cdcs.line_coding, cbevt->data, sizeof(USB_Cdc_LineCodingStruct));
usb_cdc_review_comm_init(); // review the communcation initialization state
// MSG("%u\n", cdcs.line_coding.dwDTERate);
ret = 0;
break;
case USB_CDC_GET_LINE_CODING: // get line coding
cbevt->reply_data = (const uint8_t *)&cdcs.line_coding; // expert move: pass the pointer, no copying
cbevt->reply_size = sizeof(USB_Cdc_LineCodingStruct);
ret = 0;
break;
case USB_CDC_SEND_BREAK: // send break
// do nothing
ret = 0;
break;
case USB_CDC_SET_CONTROL_LINE_STATE: // set control line state
cdcs.control_line_state.D = cbevt->setup_request->wValue; // control line state is carried in wValue of the SETUP request
usb_cdc_review_comm_init(); // review the communcation initialization state
// MSG("%u\n", cdcs.control_line_state.D);
ret = 0;
break;
default:
cbevt->reply_valid = false; // this event is not processed by or not related to the CDC ACM module
break;
}
// send a ZLP reply
if (ret != -1) {
cbevt->reply_data = NULL;
cbevt->reply_size = 0;
cbevt->reply_valid = true;
}
break;
}
case USB_CBEVT_OUT: {
if (cbevt->ep == cdcs.ep_assignments.data_ep) {
// MSG("%c\n", cbevt->data[0]);
ret = 0;
usb_cdc_read_callback(cbevt->data, cbevt->size);
// usbcore_schedule_transmission(cdcs.ep_assignments.data_ep, cbevt->data, cbevt->size); // echo
}
break;
}
case USB_CBEVT_IN: {
if (cbevt->ep == cdcs.ep_assignments.control_ep) { // if notification feeding is requested
if (cdcs.interrupt_pending) {
usbcore_schedule_transmission(cdcs.ep_assignments.control_ep, (const uint8_t *)&(cdcs.interrupt_data), sizeof(uint16_t)); // send ZLP
cdcs.interrupt_pending = false;
}
ret = 0;
} else if (cbevt->ep == cdcs.ep_assignments.data_ep) { // if data are requested
// usbcore_schedule_transmission(cdcs.ep_assignments.data_ep, NULL, 0); // send ZLP
ret = 0;
// read from the fifo
if (cdcs.commInit) {
uint32_t readSize = bfifo_read(&fifo, tx_buffer, USB_CDC_PCKT_BUFSIZE);
if (readSize > 0) {
uint32_t writeSize = usbcore_schedule_transmission(cdcs.ep_assignments.data_ep, tx_buffer, readSize); // write data acquired from the buffer
bfifo_pop(&fifo, writeSize, 0); // pop with no blocking
}
}
}
}
default:
break;
}
return ret;
}
// void usb_event_callback(USB_CallbackEvent *cbevt) {
// usb_cdc_process_and_return(cbevt);
// }
void usb_cdc_write(const uint8_t *data, uint32_t size) {
if (cdcs.moduleInit) {
bfifo_push_all(&fifo, data, size);
usbcore_wake_up_endpoint(cdcs.ep_assignments.data_ep, USB_IN);
}
}
__attribute__((weak)) void usb_cdc_read_callback(const uint8_t *data, uint32_t size) {
(void)data;
(void)size;
return;
}

View File

@ -1,78 +0,0 @@
#ifndef CORE_USB_CLASS_CDC
#define CORE_USB_CLASS_CDC
#include "../usb_callback_event.h"
// CDC request codes
typedef enum {
USB_CDC_SET_COMM_FEATURE = 0x2,
USB_CDC_GET_COMM_FEATURE = 0x3,
USB_CDC_CLEAR_COMM_FEATURE = 0x4,
USB_CDC_SET_AUX_LINE_STATE = 0x10,
USB_CDC_SET_HOOK_STATE = 0x11,
USB_CDC_PULSE_SETUP = 0x12,
USB_CDC_SEND_PULSE = 0x13,
USB_CDC_SET_PULSE_TIME = 0x14,
USB_CDC_RING_AUX_JACK = 0x15,
USB_CDC_SET_LINE_CODING = 0x20,
USB_CDC_GET_LINE_CODING = 0x21,
USB_CDC_SET_CONTROL_LINE_STATE = 0x22,
USB_CDC_SEND_BREAK = 0x23,
USB_CDC_SET_RINGER_PARMS = 0x30,
USB_CDC_GET_RINGER_PARMS = 0x31,
USB_CDC_SET_OPERATION_PARMS = 0x32,
USB_CDC_GET_OPERATION_PARMS = 0x33,
USB_CDC_SET_LINE_PARMS = 0x34,
} USB_Cdc_RequestCodes;
// CDC line coding structure
typedef struct {
uint32_t dwDTERate; // data terminal rate, bits per second
uint8_t bCharFormat; // character format
uint8_t bParityType; // parity type
uint8_t bDataBits; // data bits
} USB_Cdc_LineCodingStruct;
// CDC control line state struct
typedef struct {
uint16_t D; // settings word
} USB_Cdc_ControlLineStateStruct;
// ----------------
// endpoint assignments
typedef struct {
uint8_t control_ep : 4; // control endpoint
uint8_t data_ep : 4; // data endpoint
} USB_CdcAssignments;
typedef struct {
USB_CdcAssignments ep_assignments; // endpoint assignments
USB_Cdc_LineCodingStruct line_coding; // line coding
USB_Cdc_ControlLineStateStruct control_line_state; // control line state
uint16_t interrupt_data; // data sent though the next transfer on the notification element
bool interrupt_pending; // interrupt data is valid and should be send in the next cycle
bool moduleInit; // CDC module is initialized
bool commInit; // communication is initialized
} USB_CdcState;
// ----------------
#define USB_CDC_INVALID_CONTROL_LINE_STATE (0xFFFF)
#define USB_CDC_DEFAULT_BITRATE (115200)
#define USB_CDC_DEFAULT_DATA_BITS (8)
#define USB_CDC_DEFAULT_PARITY_TYPE (0)
#define USB_CDC_DEFAULT_CHAR_FORMAT (0)
// ----------------
#define USB_CDC_PCKT_BUFSIZE (300)
// ----------------
void usb_cdc_init(const USB_CdcAssignments *as);
int usb_cdc_process_and_return(USB_CallbackEvent *cbevt);
void usb_cdc_write(const uint8_t *data, uint32_t size);
#endif /* CORE_USB_CLASS_CDC */

View File

@ -73,7 +73,7 @@ USB_EemEvent usb_eem_pop_event() {
return evt; return evt;
} }
int usb_eem_process_and_return(USB_CallbackEvent *cbevt) { int usb_eem_process_and_return(Usb_CallbackEvent *cbevt) {
switch (cbevt->type) { switch (cbevt->type) {
case USB_CBEVT_UNKNOWN_REQ: case USB_CBEVT_UNKNOWN_REQ:
break; break;

View File

@ -24,7 +24,6 @@ usb_target_dir = argv[2]
print("Input JSON: ", usb_config_file_name) print("Input JSON: ", usb_config_file_name)
print("Target directory: ", usb_target_dir) print("Target directory: ", usb_target_dir)
#usb_config_file_name = "/home/epagris/VCSDEV/usbt1/stws/USB-T1/Modules/flatUSB/desc/usb_config_cdc.json"
with open(usb_config_file_name, 'r') as usb_config_file: with open(usb_config_file_name, 'r') as usb_config_file:
usb_config_data = usb_config_file.read() usb_config_data = usb_config_file.read()
usb_config = json.loads(usb_config_data) usb_config = json.loads(usb_config_data)
@ -42,29 +41,5 @@ if "misc" in usb_config:
cfggen = ConfigGenerator(usb_config) cfggen = ConfigGenerator(usb_config)
cfggen.generate(usb_target_dir) cfggen.generate(usb_target_dir)
# devDesc = desc.DeviceDescriptor(usb_config)
# print(devDesc.print_assigment())
#
# strDesc = desc.StringDescriptor("Testdevice", "StrDevice")
# print(strDesc.print_assigment())
#intrec = sg.RecordFactory.create("num", "u32", 127)
#print(intrec.print_typedef("INT"))
# intrec = sg.RecordFactory.create([ "num", "u32", 127, ])
# print(intrec.print_typedef("INTINT"))
# #
# strrec = sg.RecordFactory.create("some_string", "str", "Some string")
# print(strrec.print_typedef("STR"))
#print(strrec.print_content())
#
# recs = [ intrec, strrec ]
#
# struct1 = sg.StructRecord("struct1", "struct struct 1", recs)
# struct2 = sg.StructRecord("struct2", "struct struct2", recs)
# print(struct2.print_typedef("struct2"))
#
# structrec = sg.StructRecord("object", "struct compound", [ struct1, struct2, *recs ])
# print(structrec.print_content())
# print complete message # print complete message
print("Descriptor generation complete!") print("Descriptor generation complete!")

21
docs/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,157 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeDarkModeToggle extends HTMLElement {
// SVG icons from https://fonts.google.com/icons
// Licensed under the Apache 2.0 license:
// https://www.apache.org/licenses/LICENSE-2.0.html
static lightModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FCBF00"><rect fill="none" height="24" width="24"/><circle cx="12" cy="12" opacity=".3" r="3"/><path d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"/></svg>`
static darkModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FE9700"><rect fill="none" height="24" width="24"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27 C17.45,17.19,14.93,19,12,19c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z" opacity=".3"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"/></svg>`
static title = "Toggle Light/Dark Mode"
static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode"
static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode"
static _staticConstructor = function() {
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.userPreference)
// Update the color scheme when the browsers preference changes
// without user interaction on the website.
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
})
// Update the color scheme when the tab is made visible again.
// It is possible that the appearance was changed in another tab
// while this tab was in the background.
document.addEventListener("visibilitychange", visibilityState => {
if (document.visibilityState === 'visible') {
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
}
});
}()
static init() {
$(function() {
$(document).ready(function() {
const toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle')
toggleButton.title = DoxygenAwesomeDarkModeToggle.title
toggleButton.updateIcon()
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
toggleButton.updateIcon()
})
document.addEventListener("visibilitychange", visibilityState => {
if (document.visibilityState === 'visible') {
toggleButton.updateIcon()
}
});
$(document).ready(function(){
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
})
$(window).resize(function(){
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
})
})
})
}
constructor() {
super();
this.onclick=this.toggleDarkMode
}
/**
* @returns `true` for dark-mode, `false` for light-mode system preference
*/
static get systemPreference() {
return window.matchMedia('(prefers-color-scheme: dark)').matches
}
/**
* @returns `true` for dark-mode, `false` for light-mode user preference
*/
static get userPreference() {
return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) ||
(DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey))
}
static set userPreference(userPreference) {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = userPreference
if(!userPreference) {
if(DoxygenAwesomeDarkModeToggle.systemPreference) {
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey, true)
} else {
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)
}
} else {
if(!DoxygenAwesomeDarkModeToggle.systemPreference) {
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey, true)
} else {
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)
}
}
DoxygenAwesomeDarkModeToggle.onUserPreferenceChanged()
}
static enableDarkMode(enable) {
if(enable) {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = true
document.documentElement.classList.add("dark-mode")
document.documentElement.classList.remove("light-mode")
} else {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = false
document.documentElement.classList.remove("dark-mode")
document.documentElement.classList.add("light-mode")
}
}
static onSystemPreferenceChanged() {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
}
static onUserPreferenceChanged() {
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
}
toggleDarkMode() {
DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference
this.updateIcon()
}
updateIcon() {
if(DoxygenAwesomeDarkModeToggle.darkModeEnabled) {
this.innerHTML = DoxygenAwesomeDarkModeToggle.darkModeIcon
} else {
this.innerHTML = DoxygenAwesomeDarkModeToggle.lightModeIcon
}
}
}
customElements.define("doxygen-awesome-dark-mode-toggle", DoxygenAwesomeDarkModeToggle);

View File

@ -0,0 +1,85 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2022 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeFragmentCopyButton extends HTMLElement {
constructor() {
super();
this.onclick=this.copyContent
}
static title = "Copy to clipboard"
static copyIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>`
static successIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>`
static successDuration = 980
static init() {
$(function() {
$(document).ready(function() {
if(navigator.clipboard) {
const fragments = document.getElementsByClassName("fragment")
for(const fragment of fragments) {
const fragmentWrapper = document.createElement("div")
fragmentWrapper.className = "doxygen-awesome-fragment-wrapper"
const fragmentCopyButton = document.createElement("doxygen-awesome-fragment-copy-button")
fragmentCopyButton.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon
fragmentCopyButton.title = DoxygenAwesomeFragmentCopyButton.title
fragment.parentNode.replaceChild(fragmentWrapper, fragment)
fragmentWrapper.appendChild(fragment)
fragmentWrapper.appendChild(fragmentCopyButton)
}
}
})
})
}
copyContent() {
const content = this.previousSibling.cloneNode(true)
// filter out line number from file listings
content.querySelectorAll(".lineno, .ttc").forEach((node) => {
node.remove()
})
let textContent = content.textContent
// remove trailing newlines that appear in file listings
let numberOfTrailingNewlines = 0
while(textContent.charAt(textContent.length - (numberOfTrailingNewlines + 1)) == '\n') {
numberOfTrailingNewlines++;
}
textContent = textContent.substring(0, textContent.length - numberOfTrailingNewlines)
navigator.clipboard.writeText(textContent);
this.classList.add("success")
this.innerHTML = DoxygenAwesomeFragmentCopyButton.successIcon
window.setTimeout(() => {
this.classList.remove("success")
this.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon
}, DoxygenAwesomeFragmentCopyButton.successDuration);
}
}
customElements.define("doxygen-awesome-fragment-copy-button", DoxygenAwesomeFragmentCopyButton)

View File

@ -0,0 +1,91 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2022 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeInteractiveToc {
static topOffset = 38
static hideMobileMenu = true
static headers = []
static init() {
window.addEventListener("load", () => {
let toc = document.querySelector(".contents > .toc")
if(toc) {
toc.classList.add("interactive")
if(!DoxygenAwesomeInteractiveToc.hideMobileMenu) {
toc.classList.add("open")
}
document.querySelector(".contents > .toc > h3")?.addEventListener("click", () => {
if(toc.classList.contains("open")) {
toc.classList.remove("open")
} else {
toc.classList.add("open")
}
})
document.querySelectorAll(".contents > .toc > ul a").forEach((node) => {
let id = node.getAttribute("href").substring(1)
DoxygenAwesomeInteractiveToc.headers.push({
node: node,
headerNode: document.getElementById(id)
})
document.getElementById("doc-content")?.addEventListener("scroll",this.throttle(DoxygenAwesomeInteractiveToc.update, 100))
})
DoxygenAwesomeInteractiveToc.update()
}
})
}
static update() {
let active = DoxygenAwesomeInteractiveToc.headers[0]?.node
DoxygenAwesomeInteractiveToc.headers.forEach((header) => {
let position = header.headerNode.getBoundingClientRect().top
header.node.classList.remove("active")
header.node.classList.remove("aboveActive")
if(position < DoxygenAwesomeInteractiveToc.topOffset) {
active = header.node
active?.classList.add("aboveActive")
}
})
active?.classList.add("active")
active?.classList.remove("aboveActive")
}
static throttle(func, delay) {
let lastCall = 0;
return function (...args) {
const now = new Date().getTime();
if (now - lastCall < delay) {
return;
}
lastCall = now;
return setTimeout(() => {func(...args)}, delay);
};
}
}

View File

@ -0,0 +1,40 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
@media screen and (min-width: 768px) {
#MSearchBox {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - var(--searchbar-height) - 1px);
}
#MSearchField {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 66px - var(--searchbar-height));
}
}

View File

@ -0,0 +1,116 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
html {
/* side nav width. MUST be = `TREEVIEW_WIDTH`.
* Make sure it is wide enough to contain the page title (logo + title + version)
*/
--side-nav-fixed-width: 335px;
--menu-display: none;
--top-height: 120px;
--toc-sticky-top: -25px;
--toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 25px);
}
#projectname {
white-space: nowrap;
}
@media screen and (min-width: 768px) {
html {
--searchbar-background: var(--page-background-color);
}
#side-nav {
min-width: var(--side-nav-fixed-width);
max-width: var(--side-nav-fixed-width);
top: var(--top-height);
overflow: visible;
}
#nav-tree, #side-nav {
height: calc(100vh - var(--top-height)) !important;
}
#nav-tree {
padding: 0;
}
#top {
display: block;
border-bottom: none;
height: var(--top-height);
margin-bottom: calc(0px - var(--top-height));
max-width: var(--side-nav-fixed-width);
overflow: hidden;
background: var(--side-nav-background);
}
#main-nav {
float: left;
padding-right: 0;
}
.ui-resizable-handle {
cursor: default;
width: 1px !important;
background: var(--separator-color);
box-shadow: 0 calc(-2 * var(--top-height)) 0 0 var(--separator-color);
}
#nav-path {
position: fixed;
right: 0;
left: var(--side-nav-fixed-width);
bottom: 0;
width: auto;
}
#doc-content {
height: calc(100vh - 31px) !important;
padding-bottom: calc(3 * var(--spacing-large));
padding-top: calc(var(--top-height) - 80px);
box-sizing: border-box;
margin-left: var(--side-nav-fixed-width) !important;
}
#MSearchBox {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)));
}
#MSearchField {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 65px);
}
#MSearchResultsWindow {
left: var(--spacing-medium) !important;
right: auto;
}
}

View File

@ -0,0 +1,90 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeTabs {
static init() {
window.addEventListener("load", () => {
document.querySelectorAll(".tabbed:not(:empty)").forEach((tabbed, tabbedIndex) => {
let tabLinkList = []
tabbed.querySelectorAll(":scope > ul > li").forEach((tab, tabIndex) => {
tab.id = "tab_" + tabbedIndex + "_" + tabIndex
let header = tab.querySelector(".tab-title")
let tabLink = document.createElement("button")
tabLink.classList.add("tab-button")
tabLink.appendChild(header)
header.title = header.textContent
tabLink.addEventListener("click", () => {
tabbed.querySelectorAll(":scope > ul > li").forEach((tab) => {
tab.classList.remove("selected")
})
tabLinkList.forEach((tabLink) => {
tabLink.classList.remove("active")
})
tab.classList.add("selected")
tabLink.classList.add("active")
})
tabLinkList.push(tabLink)
if(tabIndex == 0) {
tab.classList.add("selected")
tabLink.classList.add("active")
}
})
let tabsOverview = document.createElement("div")
tabsOverview.classList.add("tabs-overview")
let tabsOverviewContainer = document.createElement("div")
tabsOverviewContainer.classList.add("tabs-overview-container")
tabLinkList.forEach((tabLink) => {
tabsOverview.appendChild(tabLink)
})
tabsOverviewContainer.appendChild(tabsOverview)
tabbed.before(tabsOverviewContainer)
function resize() {
let maxTabHeight = 0
tabbed.querySelectorAll(":scope > ul > li").forEach((tab, tabIndex) => {
let visibility = tab.style.display
tab.style.display = "block"
maxTabHeight = Math.max(tab.offsetHeight, maxTabHeight)
tab.style.display = visibility
})
tabbed.style.height = `${maxTabHeight + 10}px`
}
resize()
new ResizeObserver(resize).observe(tabbed)
})
})
}
static resize(tabbed) {
}
}

2681
docs/doxygen-awesome.css Normal file

File diff suppressed because it is too large Load Diff

86
docs/header.html Normal file
View File

@ -0,0 +1,86 @@
<!-- HTML header for doxygen 1.9.8-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN FULL_SIDEBAR-->
<script type="text/javascript">var page_layout=1;</script>
<!--END FULL_SIDEBAR-->
<!--END DISABLE_INDEX-->
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
$treeview
$search
$mathjax
$darkmode
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
<script type="text/javascript" src="$relpath^doxygen-awesome-fragment-copy-button.js"></script>
<script type="text/javascript">
DoxygenAwesomeFragmentCopyButton.init()
</script>
<script type="text/javascript" src="$relpath^doxygen-awesome-interactive-toc.js"></script>
<script type="text/javascript">
DoxygenAwesomeInteractiveToc.init()
</script>
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
<script type="text/javascript">
DoxygenAwesomeDarkModeToggle.init()
</script>
</head>
<body>
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN FULL_SIDEBAR-->
<div id="side-nav" class="ui-resizable side-nav-resizable"><!-- do not remove this div, it is closed by doxygen! -->
<!--END FULL_SIDEBAR-->
<!--END DISABLE_INDEX-->
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr id="projectrow">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
<!--END PROJECT_LOGO-->
<!--BEGIN PROJECT_NAME-->
<td id="projectalign">
<div id="projectname">$projectname<!--BEGIN PROJECT_NUMBER--><span id="projectnumber">&#160;$projectnumber</span><!--END PROJECT_NUMBER-->
</div>
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME-->
<!--BEGIN PROJECT_BRIEF-->
<td>
<div id="projectbrief">$projectbrief</div>
</td>
<!--END PROJECT_BRIEF-->
<!--END !PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<!--BEGIN !FULL_SIDEBAR-->
<td>$searchbox</td>
<!--END !FULL_SIDEBAR-->
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
<!--BEGIN SEARCHENGINE-->
<!--BEGIN FULL_SIDEBAR-->
<tr><td colspan="2">$searchbox</td></tr>
<!--END FULL_SIDEBAR-->
<!--END SEARCHENGINE-->
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->

View File

@ -0,0 +1,3 @@
body {
--top-height: 160px
}

View File

@ -1,16 +0,0 @@
#ifndef CORE_USB_USB_CORE_TYPES
#define CORE_USB_USB_CORE_TYPES
// #include "usb_common_types.h"
// /* USB linespeed */
// typedef enum { USB_SPD_UNKNOWN = 0b00, USB_SPD_LOW = 0b01, USB_SPD_FULL = 0b11 } USB_Speed;
// /* USB core state */
// typedef struct
// {
// uint8_t linespeed; // USB linespeed
// } USB_CoreState;
#endif /* CORE_USB_USB_CORE_TYPES */

View File

@ -15,14 +15,16 @@
// ------------------------ // ------------------------
#define USB_RX_BUF_SIZE (512) #define USB_RX_BUF_SIZE (512) ///< Receive buffer size
static USBDRV_GlobalState gs; // global USB state static USBDRV_GlobalState gs; ///< Blobal USB state
static uint8_t rx_buf[USB_RX_BUF_SIZE] DWORD_ALIGN; // receive buffer static uint8_t rx_buf[USB_RX_BUF_SIZE] DWORD_ALIGN; ///< Receive buffer
static USBDRV_IN_cb cbs[USB_NUM_OF_ENDPOINTS]; // callbacks for IN completion static UsbDrv_IN_cb cbs[USB_NUM_OF_ENDPOINTS]; ///< Callbacks for IN completion
/** \cond false */
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b))
/** \endcond */
// ------------------------ // ------------------------
@ -46,13 +48,13 @@ __weak void usbdrv_ulpi_init() {
// ------------------------ // ------------------------
void usbdrv_register_IN_complete_cb(uint8_t ep, USBDRV_IN_cb cb) { void usbdrv_register_IN_complete_cb(uint8_t ep, UsbDrv_IN_cb cb) {
cbs[ep] = cb; cbs[ep] = cb;
} }
// ------------------------ // ------------------------
static USB_DrvIntf drvIntf; static UsbDrv_DrvIntf drvIntf;
void usbdrv_init_intf() { void usbdrv_init_intf() {
drvIntf.init = usbdrv_init; drvIntf.init = usbdrv_init;
@ -67,7 +69,7 @@ void usbdrv_init_intf() {
drvIntf.reg_IN_cb = usbdrv_register_IN_complete_cb; drvIntf.reg_IN_cb = usbdrv_register_IN_complete_cb;
} }
USB_DrvIntf *usbdrv_get_intf() { UsbDrv_DrvIntf *usbdrv_get_intf() {
return &drvIntf; return &drvIntf;
} }
@ -185,7 +187,7 @@ void usbdrv_init_global_state() {
memset(&gs, 0, sizeof(USBDRV_GlobalState)); memset(&gs, 0, sizeof(USBDRV_GlobalState));
// clear IN complete callbacks // clear IN complete callbacks
memset(&cbs, 0, sizeof(USBDRV_IN_cb) * USB_NUM_OF_ENDPOINTS); memset(&cbs, 0, sizeof(UsbDrv_IN_cb) * USB_NUM_OF_ENDPOINTS);
// initialize receive buffer // initialize receive buffer
gs.rx_buf = rx_buf; gs.rx_buf = rx_buf;
@ -734,12 +736,26 @@ void usbdrv_process_rx_fifo_top(USBDRV_EventData *evt_data) {
USBMSG("%s [%u] %u\n", FIFO_STATUS_STR[pckt_status - 1], ep_num, byte_count); USBMSG("%s [%u] %u\n", FIFO_STATUS_STR[pckt_status - 1], ep_num, byte_count);
} }
// always pass ALIGNED data! /**
* Function prototype for processing SETUP packets. This function is expected to be
* overridden by the application.
*
* @param data pointer to the SETUP packet
* @param size size of the packet
* @param stage stage of the SETUP transaction
*/
__weak void usbcore_process_setup_pckt(const uint8_t *data, uint16_t size, uint8_t stage) { __weak void usbcore_process_setup_pckt(const uint8_t *data, uint16_t size, uint8_t stage) {
// always pass ALIGNED data!
return; return;
} }
__weak void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) { /**
* Function prototype for processing non-SETUP packets. This function is expected to be
* overridden by the application.
*
* @param cbcpd pointer to callback compound
*/
__weak void usbcore_process_nonsetup_event(UsbDrv_CallbackCompound *cbcpd) {
return; return;
} }
@ -815,7 +831,7 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
// SET_BIT(USBG->GINTMSK, USB_OTG_GINTMSK_RXFLVLM); // unmask interrupt // SET_BIT(USBG->GINTMSK, USB_OTG_GINTMSK_RXFLVLM); // unmask interrupt
} else { // not EP0 } else { // not EP0
if (evt_data.rx.pckt_status == USB_PCKT_STATUS_OUT_DATA_RECV) { if (evt_data.rx.pckt_status == USB_PCKT_STATUS_OUT_DATA_RECV) {
USBDRV_CallbackCompound cbcpd; UsbDrv_CallbackCompound cbcpd;
cbcpd.ep = evt_data.rx.ep_num; cbcpd.ep = evt_data.rx.ep_num;
cbcpd.dir = USB_OUT; cbcpd.dir = USB_OUT;
cbcpd.code = USB_CBC_OUT; cbcpd.code = USB_CBC_OUT;
@ -852,7 +868,7 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
case USB_EVT_IN_DONE: { // some IN operations have finished case USB_EVT_IN_DONE: { // some IN operations have finished
// callback compound // callback compound
USBDRV_CallbackCompound cbcpd; UsbDrv_CallbackCompound cbcpd;
cbcpd.dir = USB_IN; cbcpd.dir = USB_IN;
cbcpd.data = NULL; cbcpd.data = NULL;
cbcpd.size = 0; cbcpd.size = 0;
@ -887,7 +903,7 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
// invoke callback if registered // invoke callback if registered
if (cbs[ep] != NULL) { if (cbs[ep] != NULL) {
USBDRV_IN_cb cb = cbs[ep]; // fetch function pointer UsbDrv_IN_cb cb = cbs[ep]; // fetch function pointer
cbs[ep] = NULL; // clear callback cbs[ep] = NULL; // clear callback
cb(ep); // invoke the callback cb(ep); // invoke the callback
} }

View File

@ -118,6 +118,11 @@ void usbdrv_init();
*/ */
void usbdrv_reset(); void usbdrv_reset();
/**
* Init driver's global state.
*/
void usbdrv_init_global_state();
/** /**
* Initialize driver interface. * Initialize driver interface.
*/ */
@ -125,33 +130,33 @@ void usbdrv_init_intf();
/** /**
* USB peripheral initialization. * USB peripheral initialization.
* *
* @param reset only perform an after-reset reinitialization * @param reset only perform an after-reset reinitialization
*/ */
void usbdrv_periph_init(bool reset); void usbdrv_periph_init(bool reset);
/** /**
* Flush specific TX FIFO. * Flush specific TX FIFO.
* *
* @param n index of the TX FIFO * @param n index of the TX FIFO
*/ */
void usbdrv_flush_tx_fifo(uint8_t n); void usbdrv_flush_tx_fifo(uint8_t n);
/** /**
* Flush specific RX FIFO. * Flush all RX FIFOs.
*/ */
void usbdrv_flush_rx_fifo(); void usbdrv_flush_rx_fifo();
/** /**
* Power down or up the USB peripheral. Also control built-in transciever. * Power down or up the USB peripheral. Also control built-in transciever.
* *
* @param en power on/off * @param en power on/off
*/ */
void usbdrv_power_and_connect(bool en); void usbdrv_power_and_connect(bool en);
/** /**
* Configure USB Endpoint. * Configure USB Endpoint.
* *
* @param ep index of the endpoint * @param ep index of the endpoint
* @param dir direction of the endpoint to be configured * @param dir direction of the endpoint to be configured
* @param cfg pointer to the configuration details * @param cfg pointer to the configuration details
@ -160,7 +165,7 @@ void usbdrv_configure_endpoint(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *c
/** /**
* Deconfigure a specific USB Endpoint. * Deconfigure a specific USB Endpoint.
* *
* @param ep index of the endpoint * @param ep index of the endpoint
* @param dir direction of the endpoint to be deconfigured * @param dir direction of the endpoint to be deconfigured
*/ */
@ -168,7 +173,7 @@ void usbdrv_deconfigure_endpoint(uint8_t ep, uint8_t dir);
/** /**
* Stall a particular USB Endpoint. * Stall a particular USB Endpoint.
* *
* @param ep index of the endpoint to be stalled * @param ep index of the endpoint to be stalled
* @param dir direction of the endpoint * @param dir direction of the endpoint
* @param stall enable/disable stalling * @param stall enable/disable stalling
@ -177,7 +182,7 @@ void usbdrv_stall_endpoint(uint8_t ep, uint8_t dir, bool stall);
/** /**
* Implement or rescind responding NAK globally in the chosen direction. * Implement or rescind responding NAK globally in the chosen direction.
* *
* @param dir communication direction * @param dir communication direction
* @param en enable/disable NAK responses * @param en enable/disable NAK responses
*/ */
@ -185,7 +190,7 @@ void usbdrv_set_global_NAK(uint8_t dir, bool en);
/** /**
* Fetch data corresponding to a single Endpoint. * Fetch data corresponding to a single Endpoint.
* *
* @param ep index of endpoint * @param ep index of endpoint
* @param len maximum length of data to be fetched * @param len maximum length of data to be fetched
*/ */
@ -195,7 +200,7 @@ void usbdrv_fetch_received_data(uint8_t ep, uint16_t len);
* Setup and prepare Endpoint to transfer data towards the host. * Setup and prepare Endpoint to transfer data towards the host.
* May be called multiple times in a single transmission, since * May be called multiple times in a single transmission, since
* large messages do not have to fit into a single buffer. * large messages do not have to fit into a single buffer.
* *
* @param ep index of the Endpoint * @param ep index of the Endpoint
* @param data pointer to the data * @param data pointer to the data
* @param len length of the data to be read * @param len length of the data to be read
@ -205,7 +210,7 @@ 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. * Prepare Endpoint to expect data reception from the host.
* *
* @param ep index of the Endpoint * @param ep index of the Endpoint
* @param size expected reception length * @param size expected reception length
* @return message length that the endpoint can support during next reception * @return message length that the endpoint can support during next reception
@ -217,28 +222,26 @@ uint32_t usbdrv_arm_OUT_endpoint(uint8_t ep, uint16_t size);
* Right after a transaction completes the USB core * Right after a transaction completes the USB core
* automatically prepares the endpoint for the next * automatically prepares the endpoint for the next
* reception if this feature is enabled. * reception if this feature is enabled.
* *
* @param ep index of the Endpoint * @param ep index of the Endpoint
*/ */
void usbdrv_autoarm_OUT_endpoint(uint8_t ep); void usbdrv_autoarm_OUT_endpoint(uint8_t ep);
/** /**
* Mask or unmask Endpoint interrupt generation. * Mask or unmask Endpoint interrupt generation.
* *
* @param ep index of the Endpoint * @param ep index of the Endpoint
* @param dir direction of the Endpoint * @param dir direction of the Endpoint
* @param en enable/disable interrupt * @param en enable/disable interrupt
*/ */
void usbdrv_enable_endpoint_interrupt(uint8_t ep, uint8_t dir, bool en); void usbdrv_enable_endpoint_interrupt(uint8_t ep, uint8_t dir, bool en);
/** /**
* Set the shared FIFO size for all receptions. * Set the shared FIFO size for all receptions.
* (Shared among all OUT endpoints.) * (Shared among all OUT endpoints.)
* Size of multiple of 4 are recommended. Values * Size of multiple of 4 are recommended. Values
* not obeying this will be rounded up. * not obeying this will be rounded up.
* *
* @param size FIFO size in BYTES * @param size FIFO size in BYTES
*/ */
void usbdrv_set_rx_fifo_size(uint16_t size); void usbdrv_set_rx_fifo_size(uint16_t size);
@ -246,7 +249,7 @@ void usbdrv_set_rx_fifo_size(uint16_t size);
/** /**
* Preload Endpoint config. Do not write configuration * Preload Endpoint config. Do not write configuration
* to the hardware right away, just buffer them in. * to the hardware right away, just buffer them in.
* *
* @param ep index of the Endpoint * @param ep index of the Endpoint
* @param dir direction of the Endpint * @param dir direction of the Endpint
* @param cfg pointer to Endpoint configuration * @param cfg pointer to Endpoint configuration
@ -259,7 +262,6 @@ void usbdrv_preload_endpoint_config(uint8_t ep, uint8_t dir, const USBDRV_EpConf
*/ */
void usbdrv_clear_endpoint_config(); void usbdrv_clear_endpoint_config();
/** /**
* Apply preloaded Endpoint configuration, write * Apply preloaded Endpoint configuration, write
* Endpoint config to the hardware. * Endpoint config to the hardware.
@ -269,7 +271,7 @@ void usbdrv_apply_endpoint_config();
/** /**
* Select a specific configuration from the descriptor * Select a specific configuration from the descriptor
* dump, preload Endpoint settings and finally apply them. * dump, preload Endpoint settings and finally apply them.
* *
* @param config_index configuration index * @param config_index configuration index
*/ */
void usbdrv_fetch_endpoint_configuration(uint8_t config_index); void usbdrv_fetch_endpoint_configuration(uint8_t config_index);
@ -286,24 +288,47 @@ void usbdrv_initial_ep0_setup();
/** /**
* Set USB device address. * Set USB device address.
* *
* @param addr device address * @param addr device address
*/ */
void usbdrv_set_address(uint8_t addr); void usbdrv_set_address(uint8_t addr);
/** /**
* Get driver interface. * Get driver interface.
* *
* @return pointer to the driver interface * @return pointer to the driver interface
*/ */
USB_DrvIntf * usbdrv_get_intf(); UsbDrv_DrvIntf *usbdrv_get_intf();
/** /**
* Register callback for IN transaction complete. * Register callback for IN transaction complete.
* *
* @param ep index of the Endpoint * @param ep index of the Endpoint
* @param cb pointer to the callback function * @param cb pointer to the callback function
*/ */
void usbdrv_register_IN_complete_cb(uint8_t ep, USBDRV_IN_cb cb); 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 */ #endif /* STM32_USB_DRV */

View File

@ -0,0 +1,46 @@
#ifndef SRC_FLATUSB_CONFIG
#define SRC_FLATUSB_CONFIG
#include <stm32f4xx_hal.h>
#define USB_VBUSSENSE (0)
static inline void usbdrv_gpio_init() {
__HAL_RCC_GPIOA_CLK_ENABLE(); // turn ON GPIOA clocks
GPIO_InitTypeDef gpio_init;
gpio_init.Mode = GPIO_MODE_AF_PP;
gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
gpio_init.Pull = GPIO_NOPULL;
gpio_init.Alternate = GPIO_AF10_OTG_FS;
gpio_init.Pin = GPIO_PIN_11 | GPIO_PIN_12;
HAL_GPIO_Init(GPIOA, &gpio_init); // USB D-, D+
#if USB_VBUSSENSE
// FIXME
#endif
}
#define USB_IRQ_N OTG_FS_IRQn
#define USB_IRQ_HANDLER OTG_FS_IRQHandler
#define USB_IRQ_PRIORITY (8)
#define USB_IRQ_SET_PRIORITY(irq, priority) HAL_NVIC_SetPriority((irq),(priority),0)
#define USB_IRQ_ENABLE(irq) HAL_NVIC_EnableIRQ((irq))
#define USB_IRQ_DISABLE(irq) HAL_NVIC_DisableIRQ((irq))
// define USBG
#define USBG (USB_OTG_FS)
#define USB_CLOCK_ENABLE() __HAL_RCC_USB_OTG_FS_CLK_ENABLE()
#define USB_INTERNAL (1)
#define USB_UPLI (0)
#include "embfmt/embformat.h"
#define SNPRINTF(str, n, fmt, ...) embfmt(str, n, fmt, __VA_ARGS__)
#ifdef USBDBGMSG
#define USBMSG(...) MSG(__VA_ARGS__)
#endif
#endif /* SRC_FLATUSB_CONFIG */

View File

@ -0,0 +1,58 @@
#ifndef SRC_FLATUSB_CONFIG
#define SRC_FLATUSB_CONFIG
#include <stm32f4xx_hal.h>
#define USB_VBUSSENSE (0)
static inline void usbdrv_gpio_init() {
// turn on GPIO clocks
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
// initialize pins
GPIO_InitTypeDef gpio_init;
gpio_init.Mode = GPIO_MODE_AF_PP;
gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
gpio_init.Pull = GPIO_NOPULL;
gpio_init.Alternate = GPIO_AF10_OTG_HS;
gpio_init.Pin = GPIO_PIN_3 | GPIO_PIN_5; // D0, CK
HAL_GPIO_Init(GPIOA, &gpio_init);
// D1, D2, D7, D3, D4, D5, D6
gpio_init.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
HAL_GPIO_Init(GPIOB, &gpio_init);
// STP, DIR, NXT
gpio_init.Pin = GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3;
HAL_GPIO_Init(GPIOC, &gpio_init);
#if USB_VBUSSENSE
// FIXME
#endif
}
#define USB_IRQ_N OTG_HS_IRQn
#define USB_IRQ_HANDLER OTG_HS_IRQHandler
#define USB_IRQ_PRIORITY (8)
#define USB_IRQ_SET_PRIORITY(irq, priority) HAL_NVIC_SetPriority((irq),(priority),0)
#define USB_IRQ_ENABLE(irq) HAL_NVIC_EnableIRQ((irq))
#define USB_IRQ_DISABLE(irq) HAL_NVIC_DisableIRQ((irq))
#define USBG (USB_OTG_HS)
#define USB_CLOCK_ENABLE() __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE()
#define USB_INTERNAL (0)
#define USB_UPLI (1)
#include "embfmt/embformat.h"
#define SNPRINTF(str, n, fmt, ...) embfmt(str, n, fmt, __VA_ARGS__)
#ifdef USBDBGMSG
#define USBMSG(...) MSG(__VA_ARGS__)
#endif
#endif /* SRC_FLATUSB_CONFIG */

View File

@ -0,0 +1,82 @@
#ifndef SRC_FLATUSB_CONFIG
#define SRC_FLATUSB_CONFIG
#include <stm32h7xx_hal.h>
#define USB_VBUSSENSE (0)
// H723
#if 1
static inline void usbdrv_gpio_init() {
__HAL_RCC_GPIOA_CLK_ENABLE();
#if USB_VBUSSENSE
// FIXME
#endif
}
// H743
#elif 1
static inline void usbdrv_gpio_init() {
__HAL_RCC_GPIOA_CLK_ENABLE(); // turn ON GPIOA clocks
GPIO_InitTypeDef gpio_init;
gpio_init.Mode = GPIO_MODE_AF_PP;
gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
gpio_init.Pull = GPIO_NOPULL;
gpio_init.Alternate = GPIO_AF10_OTG_FS;
gpio_init.Pin = GPIO_PIN_11 | GPIO_PIN_12;
HAL_GPIO_Init(GPIOA, &gpio_init); // USB D-, D+
#if USB_VBUSSENSE
// FIXME
#endif
}
#endif
// H723
#if 1
#define USB_IRQ_N OTG_HS_IRQn
#define USB_IRQ_HANDLER OTG_HS_IRQHandler
// H743
#elif 1
#define USB_IRQ_N OTG_FS_IRQn
#define USB_IRQ_HANDLER OTG_FS_IRQHandler
#endif
#define USB_IRQ_PRIORITY (8)
#define USB_IRQ_SET_PRIORITY(irq, priority) HAL_NVIC_SetPriority((irq),(priority),0)
#define USB_IRQ_ENABLE(irq) HAL_NVIC_EnableIRQ((irq))
#define USB_IRQ_DISABLE(irq) HAL_NVIC_DisableIRQ((irq))
// H723
#if 1
#define USBG (USB_OTG_HS)
// H743
#elif 1
#define USBG (USB_OTG_FS)
#endif
#define USB_STM32H7_ENABLE_USB_VOLTAGE_DETECTOR() HAL_PWREx_EnableUSBVoltageDetector(); WAIT_FOR_nBIT_DELAY(PWR->CR3, PWR_CR3_USB33RDY, 1)
// STM32H723
#if 1
#define USB_CLOCK_ENABLE() USB_STM32H7_ENABLE_USB_VOLTAGE_DETECTOR(); __HAL_RCC_USB1_OTG_HS_CLK_ENABLE()
// STM32H743
#elif 1
#define USB_CLOCK_ENABLE() USB_STM32H7_ENABLE_USB_VOLTAGE_DETECTOR(); __HAL_RCC_USB2_OTG_FS_CLK_ENABLE()
#endif
#define USB_INTERNAL (1)
#define USB_UPLI (0)
#include "embfmt/embformat.h"
#define SNPRINTF(str, n, fmt, ...) embfmt(str, n, fmt, __VA_ARGS__)
#ifdef USBDBGMSG
#define USBMSG(...) MSG(__VA_ARGS__)
#endif
#endif /* SRC_FLATUSB_CONFIG */

View File

@ -0,0 +1,38 @@
#ifndef SRC_FLATUSB_CONFIG
#define SRC_FLATUSB_CONFIG
#include <stm32h7xx_hal.h>
#define USB_VBUSSENSE (0)
static inline void usbdrv_gpio_init() {
// FIXME
#if USB_VBUSSENSE
// FIXME
#endif
}
#define USB_IRQ_N OTG_HS_IRQn
#define USB_IRQ_HANDLER OTG_HS_IRQHandler
#define USB_IRQ_PRIORITY (8)
#define USB_IRQ_SET_PRIORITY(irq, priority) HAL_NVIC_SetPriority((irq),(priority),0)
#define USB_IRQ_ENABLE(irq) HAL_NVIC_EnableIRQ((irq))
#define USB_IRQ_DISABLE(irq) HAL_NVIC_DisableIRQ((irq))
#define USBG (USB_OTG_HS)
#define USB_STM32H7_ENABLE_USB_VOLTAGE_DETECTOR() // FIXME
#define USB_CLOCK_ENABLE() // FIXME
#define USB_INTERNAL (0)
#define USB_UPLI (1)
#include "embfmt/embformat.h"
#define SNPRINTF(str, n, fmt, ...) embfmt(str, n, fmt, __VA_ARGS__)
#ifdef USBDBGMSG
#define USBMSG(...) MSG(__VA_ARGS__)
#endif
#endif /* SRC_FLATUSB_CONFIG */

89
usb.c
View File

@ -6,72 +6,52 @@
#include "usb_common.h" #include "usb_common.h"
#include "usb_driver_common.h" #include "usb_driver_common.h"
// #include "utils/gen_queue.h"
#include FLATUSB_DESCRIPTOR_HEADER #include FLATUSB_DESCRIPTOR_HEADER
// --------------- // ---------------
/** \cond false */
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b))
/** \endcond */
#define USBDRV_ARM_IN_ZLP(ep) drv->arm_IN((ep), NULL, 0) ///< Arm a ZLP IN message
// --------------- // ---------------
#define USBDRV_ARM_IN_ZLP(ep) drv->arm_IN((ep), NULL, 0) static uint8_t tx_assembly_buf[USB_RX_BUF_SIZE] DWORD_ALIGN; ///< Buffer for assembling packets
static Usb_SetupTransferState stups; ///< Setup transfer state.
#define USB_RX_BUF_SIZE (512) // FIXME static UsbDrv_DrvIntf *drv; ///< Mutable pointer to the driver interface
static uint8_t tx_assembly_buf[USB_RX_BUF_SIZE] DWORD_ALIGN; // buffer for assembling packets
// ---------------
// // state of changeing address
// typedef enum {
// USB_ADDRCHG_IDLE = 0, // idle state
// USB_ADDRCHG_NEW_ADDR_RECVD, // new address received
// } USB_AddressChangeState;
// ---------------- // ----------------
__attribute__((weak)) void usb_event_callback(USB_CallbackEvent *cbevt) { /**
* @fn void usb_event_callback(USB_CallbackEvent *cbevt)
* Prototype for the USB event callback.
*
* @param cbevt pointer to the event data
*/
__attribute__((weak)) void usb_event_callback(Usb_CallbackEvent *cbevt) {
return; return;
} }
// ---------------- // ----------------
// prepare descriptor for transmission, return with final transmission size /**
// static uint8_t usb_prepare_descriptor(const uint8_t *desc, uint8_t desc_size, uint8_t req_size) { * Callback function for bus issued Reset is done notification.
// uint8_t sz = (uint8_t)(MIN(req_size, desc_size)); // determine transmission size */
// memcpy(gs.tx_assembly_buf, desc, sz); // copy that portion to the assembly buffer
// USB_DescHdr *hdr = (USB_DescHdr *)gs.tx_assembly_buf; // obtain header
// hdr->bLength = MIN(sz, hdr->bLength); // write transmit size
// return sz;
// }
// #define USB_SETUP_STREAM_BUFFER (72)
typedef struct {
USB_SetupRequest setup_req; // setup request
uint8_t next_stage; // next expected stage
bool out_complete; // signals if transfer's OUT direction is complete, no later data reception is expected
} USB_SetupTransferState;
static USB_SetupTransferState stups;
static USB_DrvIntf *drv;
void usbcore_reset() {
// init state
memset(&stups, 0, sizeof(USB_SetupTransferState));
}
static void usbcore_rst_notify() { static void usbcore_rst_notify() {
usbcore_reset(); usbcore_reset();
} }
/**
* Callback for Enumeration Done notification.
*/
static void usbcore_enum_notify(uint8_t spd) { static void usbcore_enum_notify(uint8_t spd) {
(void)spd; (void)spd;
} }
void usbcore_init(USB_DrvIntf *drvIntf) { void usbcore_init(UsbDrv_DrvIntf *drvIntf) {
usbcore_reset(); // reset USB Core usbcore_reset(); // reset USB Core
drv = drvIntf; // store USB driver interface assignments drv = drvIntf; // store USB driver interface assignments
@ -79,6 +59,18 @@ void usbcore_init(USB_DrvIntf *drvIntf) {
drv->enum_notify = usbcore_enum_notify; // assign Enumeration Done callback drv->enum_notify = usbcore_enum_notify; // assign Enumeration Done callback
} }
void usbcore_reset() {
// init state
memset(&stups, 0, sizeof(Usb_SetupTransferState));
}
/**
* Process SETUP packets.
*
* @param data pointer to the SETUP packet
* @param size size of the packet
* @param stage stage of the SETUP transaction
*/
void usbcore_process_setup_pckt(const uint8_t *data, uint16_t size, uint8_t stage) { void usbcore_process_setup_pckt(const uint8_t *data, uint16_t size, uint8_t stage) {
// MSG("STUP: %u, %s\n", size, stage == UST_SETUP ? "SETUP" : "DATA"); // MSG("STUP: %u, %s\n", size, stage == UST_SETUP ? "SETUP" : "DATA");
@ -186,12 +178,12 @@ void usbcore_process_setup_pckt(const uint8_t *data, uint16_t size, uint8_t stag
} }
case UREQ_SetInterface: // SET INTERFACE case UREQ_SetInterface: // SET INTERFACE
{ {
// TODO: set configuration // TODO: set interface
USBDRV_ARM_IN_ZLP(0); USBDRV_ARM_IN_ZLP(0);
break; break;
} }
default: { // UNKNOWN REQUEST, pass processing to user application default: { // UNKNOWN REQUEST, pass processing to user application
USB_CallbackEvent cbevt = {0}; Usb_CallbackEvent cbevt = {0};
cbevt.type = USB_CBEVT_UNKNOWN_REQ; cbevt.type = USB_CBEVT_UNKNOWN_REQ;
cbevt.setup_request = &stups.setup_req; cbevt.setup_request = &stups.setup_req;
cbevt.data = (const uint8_t *)data; cbevt.data = (const uint8_t *)data;
@ -211,8 +203,13 @@ void usbcore_process_setup_pckt(const uint8_t *data, uint16_t size, uint8_t stag
stups.out_complete = false; stups.out_complete = false;
} }
void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) { /**
USB_CallbackEvent cbevt = {0}; // allocate and clear structure... * Process the non-SETUP packets.
*
* @param cbcpd pointer to callback compound
*/
void usbcore_process_nonsetup_event(UsbDrv_CallbackCompound *cbcpd) {
Usb_CallbackEvent cbevt = {0}; // allocate and clear structure...
cbevt.ep = cbcpd->ep; // later only fill nonzero fields cbevt.ep = cbcpd->ep; // later only fill nonzero fields
bool discard_event = false; // only discard if event does not fit any category above bool discard_event = false; // only discard if event does not fit any category above
@ -257,7 +254,7 @@ void usbcore_wake_up_endpoint(uint8_t ep, uint8_t dir) {
drv->en_ep_irq(ep, dir, true); drv->en_ep_irq(ep, dir, true);
} }
void usbcore_register_IN_callback(uint8_t ep, USBDRV_IN_cb cb) { void usbcore_register_IN_callback(uint8_t ep, UsbDrv_IN_cb cb) {
drv->reg_IN_cb(ep, cb); drv->reg_IN_cb(ep, cb);
} }

73
usb.h
View File

@ -3,12 +3,75 @@
#include <stdint.h> #include <stdint.h>
#include "usb_device_types.h"
#include "usb_driver_common.h" #include "usb_driver_common.h"
void usbcore_init(USB_DrvIntf *drvIntf); // initialize USB core // --------------
uint32_t usbcore_schedule_transmission(uint8_t ep, const uint8_t *data, uint16_t size); // write data to endpoint, return with number of bytes actually written
uint32_t usbcore_schedule_reception(uint8_t ep, uint16_t size); // expect data coming from the endpoint /**
void usbcore_wake_up_endpoint(uint8_t ep, uint8_t dir); // wake up endpoint * Setup transfer state.
void usbcore_register_IN_callback(uint8_t ep, USBDRV_IN_cb cb); // register IN complete callback */
typedef struct {
USB_SetupRequest setup_req; ///< Setup request
uint8_t next_stage; ///< Next expected stage
bool out_complete; ///< Signals if transfer's OUT direction is complete, no later data reception is expected
} Usb_SetupTransferState;
// --------------
/** \cond 0 */
#ifndef USB_RX_BUF_SIZE
#define USB_RX_BUF_SIZE (512) ///< Receive buffer size FIXME
#endif
/** \endcond */
// --------------
/**
* Initialize USB core.
*
* @param drvIntf pointer to a mutable driver interface object
*/
void usbcore_init(UsbDrv_DrvIntf *drvIntf);
/**
* Reset USB core.
*/
void usbcore_reset();
/**
* Write data to an IN Endpoint.
*
* @param ep index of the Endpoint
* @param data pointer to data to be written
* @param size data length
* @return number of bytes written
*/
uint32_t usbcore_schedule_transmission(uint8_t ep, const uint8_t *data, uint16_t size);
/**
* Expect ingress data on an Endpoint.
*
* @param ep index of the Endpoint
* @param size expected reception length
* @return message length that the endpoint can support during next reception
*/
uint32_t usbcore_schedule_reception(uint8_t ep, uint16_t size);
/**
* Wake up an Endpoint.
*
* @param ep index of the Endpoint
* @param dir direction of the Endpoint
*/
void usbcore_wake_up_endpoint(uint8_t ep, uint8_t dir);
/**
* Register a callback for IN transmission completion.
*
* @param ep index of the Endpoint
* @param cb callback function
*/
void usbcore_register_IN_callback(uint8_t ep, UsbDrv_IN_cb cb);
#endif /* CORE_USB_USB */ #endif /* CORE_USB_USB */

View File

@ -5,30 +5,39 @@
#include "usb_device_types.h" #include "usb_device_types.h"
/**
* Callback event type.
*/
typedef enum { typedef enum {
USB_CBEVT_OUT, // OUT event USB_CBEVT_OUT, ///< OUT event
USB_CBEVT_IN, // IN event USB_CBEVT_IN, ///< IN event
USB_CBEVT_UNKNOWN_REQ // unknown request on a control endpoint USB_CBEVT_UNKNOWN_REQ ///< unknown request on a control endpoint
} USB_CallbackEventType; } Usb_CallbackEventType;
/**
* Callback event subtype.
*/
typedef enum { typedef enum {
USB_CBEVST_IN_NONE = 0, // no subtype USB_CBEVST_IN_NONE = 0, ///< No subtype
USB_CBEVST_IN_REQ // IN request was received but could not be responded USB_CBEVST_IN_REQ ///< IN request was received but could not be responded
} USB_CallbackEventSubType; } Usb_CallbackEventSubType;
/**
* USB callback event.
*/
typedef struct { typedef struct {
uint8_t type : 4; // event type uint8_t type : 4; ///< Event type
uint8_t subtype : 4; // event subtype uint8_t subtype : 4; ///< Event subtype
uint8_t ep; // endpoint number uint8_t ep; ///< Endpoint number
uint8_t dir; // endpoint direction uint8_t dir; ///< Endpoint direction
uint8_t size; // size of accompaining data uint8_t size; ///< Size of accompaining data
const uint8_t * data; // event data const uint8_t *data; ///< Event data
const USB_SetupRequest * setup_request; // corresponding setup request (if exists) const USB_SetupRequest *setup_request; ///< Corresponding setup request (if exists)
bool reply_valid; // reply message is valid bool reply_valid; ///< Reply message is valid
const uint8_t * reply_data; // reply data const uint8_t *reply_data; ///< Reply data
uint8_t reply_size; // reply size uint8_t reply_size; ///< Reply size
bool arm_out_endpoint; // automatically arm OUT endpoint at the end of the current transmission bool arm_out_endpoint; ///< Automatically arm OUT endpoint at the end of the current transmission
} USB_CallbackEvent; } Usb_CallbackEvent;
#endif /* CORE_USB_USB_CALLBACK_EVENT */ #endif /* CORE_USB_USB_CALLBACK_EVENT */

View File

@ -4,18 +4,18 @@
#include "usb_common_types.h" #include "usb_common_types.h"
#include "usb_device_types.h" #include "usb_device_types.h"
#define USB_DELAY(t) for (uint64_t i = 0; i < (t) * 10000; i++) { asm("nop"); } #define USB_DELAY(t) for (uint64_t i = 0; i < (t) * 10000; i++) { asm("nop"); } ///< Create a delay that does not relay on the processor ticks.
#define READ_FIELD(r,f) (((r) & (f##_Msk)) >> (f##_Pos)) #define READ_FIELD(r,f) (((r) & (f##_Msk)) >> (f##_Pos)) ///< Read a named field of a register
#define WRITE_FIELD(r,f,v) ((r) = ((r) & ~(f##_Msk)) | (v << (f##_Pos))) #define WRITE_FIELD(r,f,v) ((r) = ((r) & ~(f##_Msk)) | (v << (f##_Pos))) ///< Write a name field of a register
#define WAIT_FOR_BIT(r,b) while ((r) & (b)) {} #define WAIT_FOR_BIT(r,b) while ((r) & (b)) {} ///< Wait for a bit to clear
#define WAIT_FOR_BIT_DELAY(r,b,d) while ((r) & (b)) { USB_DELAY((d)); } #define WAIT_FOR_BIT_DELAY(r,b,d) while ((r) & (b)) { USB_DELAY((d)); } ///< Wait for a bit to clear with injected delay
#define WAIT_FOR_nBIT(r,b) while (!((r) & (b))) {} #define WAIT_FOR_nBIT(r,b) while (!((r) & (b))) {} ///< Wait for a bit to set
#define WAIT_FOR_nBIT_DELAY(r,b,d) while (!((r) & (b))) { USB_DELAY((d)); } #define WAIT_FOR_nBIT_DELAY(r,b,d) while (!((r) & (b))) { USB_DELAY((d)); } ///< Wait for a bit to set with injected delay
#define DWORD_ALIGN __attribute__((aligned(4))) #define DWORD_ALIGN __attribute__((aligned(4))) ///< Declare a 32-bit aligned memory area
#define CEILDIV4(x) (((x) + 3) >> 2) #define CEILDIV4(x) (((x) + 3) >> 2) ///< Integer division by four after rounding up to the nearest multiple of 4
#define CEIL4(x) (((x) + 3) & (~0b11)) #define CEIL4(x) (((x) + 3) & (~0b11)) ///< Round up to the closest multiple of 4
#endif /* CORE_USB_USB_COMMON */ #endif /* CORE_USB_USB_COMMON */

View File

@ -4,6 +4,9 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
/**
* A byte-sized boolean.
*/
typedef uint8_t bool8_t; typedef uint8_t bool8_t;
#endif /* CORE_USB_USB_COMMON_TYPES */ #endif /* CORE_USB_USB_COMMON_TYPES */

View File

@ -9,109 +9,120 @@
/* ------ USB DESCRIPTORS ------- */ /* ------ USB DESCRIPTORS ------- */
// USB Descriptor type codes /**
* USB Descriptor type codes.
*/
typedef enum { typedef enum {
UD_Device = 1, UD_Device = 1, ///< Device Descriptor
UD_Configuration = 2, UD_Configuration = 2, ///< Configuration Descriptor
UD_String = 3, UD_String = 3, ///< String Descriptor
UD_Interface = 4, UD_Interface = 4, ///< Interface Descriptor
UD_Endpoint = 5, UD_Endpoint = 5, ///< Endpoint Descriptor
UD_DeviceQualifier = 6, UD_DeviceQualifier = 6, ///< DeviceQualifier Descriptor
UD_OtherSpeedConfiguration = 7 UD_OtherSpeedConfiguration = 7 ///< OtherSpeedConfiguration Descriptor
// NOT FULL! // NOT FULL!
} USB_DescType; } USB_DescType;
// USB descriptor header /**
* USB descriptor header
*/
#define USB_DESC_HEADER \ #define USB_DESC_HEADER \
uint8_t bLength; /* length in bytes */ \ uint8_t bLength; /* length in bytes */ \
uint8_t bDescriptorType; /* descriptor type */ uint8_t bDescriptorType; /* descriptor type */
#define USB_DESC_HEADER_SIZE (2) // USB descriptor header size #define USB_DESC_HEADER_SIZE (2) ///< USB descriptor header size
// USB Descriptor header
/**
* USB Descriptor header
*/
typedef struct { typedef struct {
USB_DESC_HEADER USB_DESC_HEADER
} USB_DescHdr; } USB_DescHdr;
// USB Device descriptor /**
* USB Device descriptor
*/
typedef struct { typedef struct {
USB_DESC_HEADER USB_DESC_HEADER
uint16_t bcdUSB; // USB specification release number (BCD) uint16_t bcdUSB; ///< USB specification release number (BCD)
uint8_t bDeviceClass; // Class code uint8_t bDeviceClass; ///< Class code
uint8_t bDeviceSubclass; // Subclass code uint8_t bDeviceSubclass; ///< Subclass code
uint8_t bDeviceProtocol; // Protocol code uint8_t bDeviceProtocol; ///< Protocol code
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0 uint8_t bMaxPacketSize0; ///< Maximum packet size for endpoint 0
uint16_t idVendor; // Vendor ID uint16_t idVendor; ///< Vendor ID
uint16_t idProduct; // Product ID uint16_t idProduct; ///< Product ID
uint16_t bcdDevice; // Device release number (BCD) uint16_t bcdDevice; ///< Device release number (BCD)
uint8_t iManufacturer; // Index of string descriptor for manufacturer uint8_t iManufacturer; ///< Index of string descriptor for manufacturer
uint8_t iProduct; // Index of string descriptor for the product uint8_t iProduct; ///< Index of string descriptor for the product
uint8_t iSerialNumber; // Index of string descriptor for the serial number uint8_t iSerialNumber; ///< Index of string descriptor for the serial number
uint8_t bNumConfiguration; // Number of possible configurations uint8_t bNumConfiguration; ///< Number of possible configurations
} USB_DeviceDesc; } USB_DeviceDesc;
// USB Device Qualifier descriptor /**
* USB Device Qualifier descriptor
*/
typedef struct { typedef struct {
USB_DESC_HEADER USB_DESC_HEADER
uint16_t bcdUSB; // USB specification release number (BCD) uint16_t bcdUSB; ///< USB specification release number (BCD)
uint8_t bDeviceClass; // Class code uint8_t bDeviceClass; ///< Class code
uint8_t bDeviceSubclass; // Subclass code uint8_t bDeviceSubclass; ///< Subclass code
uint8_t bDeviceProtocol; // Protocol code uint8_t bDeviceProtocol; ///< Protocol code
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0 uint8_t bMaxPacketSize0; ///< Maximum packet size for endpoint 0
uint8_t bNumConfiguration; // Number of possible configurations uint8_t bNumConfiguration; ///< Number of possible configurations
} __attribute__((packed)) USB_DeviceQualifierDesc; } __attribute__((packed)) USB_DeviceQualifierDesc;
#define USB_CONFIG_ATTR_SELF_POWERED (1 << 6) #define USB_CONFIG_ATTR_SELF_POWERED (1 << 6) ///< Device is self-powered
#define USB_CONFIG_ATTR_REMOTE_WKUP (1 << 5) #define USB_CONFIG_ATTR_REMOTE_WKUP (1 << 5) ///< Device is intended to wake up the host
#define USB_CONFIG_ATTR_USB1_1_FLAG (1 << 7) #define USB_CONFIG_ATTR_USB1_1_FLAG (1 << 7) ///< It's a USB 1.1 or newer device
// USB Configuration descriptor
/**
* USB Configuration descriptor
*/
typedef struct { typedef struct {
USB_DESC_HEADER USB_DESC_HEADER
uint16_t wTotalLength; // The number of bytes in the configuration descriptor and all of its subordinate descriptors uint16_t wTotalLength; ///< The number of bytes in the configuration descriptor and all of its subordinate descriptors
uint8_t bNumInterfaces; // Number of interfaces in the configuration uint8_t bNumInterfaces; ///< Number of interfaces in the configuration
uint8_t bConfigrationValue; // Identifier for Set Configuration and Get Configuration Requests uint8_t bConfigrationValue; ///< Identifier for Set Configuration and Get Configuration Requests
uint8_t iConfiguration; // Index of string descriptor for the configuration uint8_t iConfiguration; ///< Index of string descriptor for the configuration
uint8_t bmAttributes; // Self/bus power and remote wakeup settings uint8_t bmAttributes; ///< Self/bus power and remote wakeup settings
uint8_t bMaxPower; // Bus power required in units of 2 mA uint8_t bMaxPower; ///< Bus power required in units of 2 mA
} __attribute__((packed)) USB_ConfigurationDesc; } __attribute__((packed)) USB_ConfigurationDesc;
// USB Interface descriptor /**
* USB Interface descriptor
*/
typedef struct { typedef struct {
USB_DESC_HEADER USB_DESC_HEADER
uint8_t bInterfaceNumber; // Number identifying this interface uint8_t bInterfaceNumber; ///< Number identifying this interface
uint8_t bAlternateSetting; // A number that identifies a descriptor with alternate settings for this bInterfaceNumber uint8_t bAlternateSetting; ///< A number that identifies a descriptor with alternate settings for this bInterfaceNumber
uint8_t bNumEndpoints; // Number of endpoints supported not counting endpoint zero uint8_t bNumEndpoints; ///< Number of endpoints supported not counting endpoint zero
uint8_t bInterfaceClass; // Class code uint8_t bInterfaceClass; ///< Class code
uint8_t bInterfaceSubclass; // Subclass code uint8_t bInterfaceSubclass; ///< Subclass code
uint8_t bInterfaceProtocol; // Protocol code uint8_t bInterfaceProtocol; ///< Protocol code
uint8_t iInterface; // Index of string descriptor for the interface uint8_t iInterface; ///< Index of string descriptor for the interface
} __attribute__((packed)) USB_InterfaceDesc; } __attribute__((packed)) USB_InterfaceDesc;
// USB Transfer type /**
* USB Transfer type
*/
typedef enum { typedef enum {
UT_Control = 0b00, UT_Control = 0b00, ///< Control
UT_Isochronous = 0b01, UT_Isochronous = 0b01, ///< Isochronous
UT_Bulk = 0b10, UT_Bulk = 0b10, ///< Bulk
UT_Interrupt = 0b11 UT_Interrupt = 0b11 ///< Interrupt
} USB_TransferType; } USB_TransferType;
// USB Endpoint descriptor
/**
* USB Endpoint descriptor
*/
typedef struct { typedef struct {
USB_DESC_HEADER USB_DESC_HEADER
uint8_t bEndpointAddress; // Endpoint number and direction uint8_t bEndpointAddress; ///< Endpoint number and direction
uint8_t bmAttributes; // Transfer type and supplementary information uint8_t bmAttributes; ///< Transfer type and supplementary information
uint16_t wMaxPacketSize; // Maximum packet size supported uint16_t wMaxPacketSize; ///< Maximum packet size supported
uint8_t bInterval; // Service interval or NAK rate uint8_t bInterval; ///< Service interval or NAK rate
} __attribute__((packed)) USB_EndpointDesc; } __attribute__((packed)) USB_EndpointDesc;
/* struct { /* struct {
@ -119,21 +130,25 @@ typedef struct {
uint8_t dir; // direction uint8_t dir; // direction
} bEndpointAddress; // Endpoint number and direction*/ } bEndpointAddress; // Endpoint number and direction*/
// USB String descriptor
/**
* USB String descriptor
*/
typedef struct { typedef struct {
USB_DESC_HEADER USB_DESC_HEADER
} USB_StringDesc; } USB_StringDesc;
// USB endpoint direction /**
* USB endpoint direction
*/
typedef enum { typedef enum {
USB_OUT = 0, USB_OUT = 0, ///< OUT
USB_IN = 1 USB_IN = 1 ///< IN
} USB_EndpointDir; } USB_EndpointDir;
// USB PIDs /**
* USB PIDs
*/
typedef enum { typedef enum {
PID_EXT = 0, PID_EXT = 0,
PID_OUT = 1, PID_OUT = 1,
@ -153,16 +168,18 @@ typedef enum {
PID_MDATA = 15, PID_MDATA = 15,
} USB_PID; } USB_PID;
// USB Request types /**
* USB Request types
*/
typedef enum { typedef enum {
UR_Standard = 0, UR_Standard = 0,
UR_VendorSpec = 1, UR_VendorSpec = 1,
UR_ReqDefVendorSpec = 2 UR_ReqDefVendorSpec = 2
} USB_RequestType; } USB_RequestType;
// USB Recipients /**
* USB Recipients
*/
typedef enum { typedef enum {
UREC_Device = 0, UREC_Device = 0,
UREC_SpecificInterface = 1, UREC_SpecificInterface = 1,
@ -170,8 +187,9 @@ typedef enum {
UREC_OtherElement = 3 UREC_OtherElement = 3
} USB_Recipient; } USB_Recipient;
// USB Request types /**
* USB Request types
*/
typedef enum { typedef enum {
UREQ_GetStatus = 0x00, UREQ_GetStatus = 0x00,
UREQ_ClearFeature = 0x01, UREQ_ClearFeature = 0x01,
@ -188,23 +206,24 @@ typedef enum {
UREQ_SetIsochronousDelay = 0x31 UREQ_SetIsochronousDelay = 0x31
} USB_RequestCode; } USB_RequestCode;
// setup request structure /**
* Setup request structure
*/
typedef struct { typedef struct {
union { union {
uint8_t bmRequestType; uint8_t bmRequestType; ///< Request type
struct { struct {
uint8_t recipient : 5; uint8_t recipient : 5; ///< Recipient
uint8_t type : 2; uint8_t type : 2; ///< Type
uint8_t dir : 1; uint8_t dir : 1; ///< Direction
} fields; } fields;
} bmRequestType; // request type } bmRequestType; ///< Request type
uint8_t bRequest; // request uint8_t bRequest; ///< Request
uint16_t wValue; // ... uint16_t wValue; ///< Value
uint16_t wIndex; // ... uint16_t wIndex; ///< Index
uint16_t wLength; // number of bytes in the data stage uint16_t wLength; ///< Number of bytes in the data stage
} USB_SetupRequest; } USB_SetupRequest;
#endif /* CORE_USB_USB_DEVICE_TYPES */ #endif /* CORE_USB_USB_DEVICE_TYPES */

File diff suppressed because it is too large Load Diff

View File

@ -1,170 +0,0 @@
#ifndef CORE_USB_USB_DRIVER
#define CORE_USB_USB_DRIVER
// #include "utils/gen_queue.h"
#include "usb_common_types.h"
// #define USBDBGMSG
#define USB_NUM_OF_ENDPOINTS (4) // FIXME: this is module-dependend
// 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 <cmsis_os2.h>
#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;
// callback codes
typedef enum {
USB_CBC_OUT, // OUT done!
USB_CBC_IN_DONE, // IN done!
USB_CBC_IN_FIFOEMPTY, // could not serve IN request, since Tx FIFO was empty
} USBDRV_CallbackCode;
// callback compound
typedef struct {
uint8_t ep : 4; // endpoint number
uint8_t dir : 1; // direction
uint8_t code : 3; // event code
uint16_t size; // data size
const uint8_t *data; // data
} USBDRV_CallbackCompound;
typedef enum { UST_SETUP,
UST_DATA } USBDRV_ControlTfStage;
// ------------
void usbdrv_gpio_init(); // USB pin low level, early peripheral initialization
void usbdrv_init_global_state(); // initialize global state
void usbdrv_periph_init(); // initialize USB peripheral
void usbdrv_initial_ep0_setup(); // create an initial setup for EP0 in both directions
void usbdrv_power_and_connect(bool en); // connect to or disconnect from the bus
void usbdrv_init(); // initialize USB subsystem
void usbdrv_reset(); // reset USB subsystem
void usbdrv_preload_endpoint_config(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *cfg); // preload usb endpoint config
void usbdrv_clear_endpoint_config(); // clear endpoint config
void usbdrv_apply_endpoint_config(); // apply preloaded endpoint configuration
void usbdrv_build_fifo(); // build FIFO (compute addresses)
const char *usbdrv_get_fifo_addr_table(); // get FIFO address table
void usbdrv_fetch_endpoint_configuration(uint8_t config_index); // fetch endpoint configuration from descriptor dump
void usbdrv_configure_endpoint(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *cfg); // configure USB endpoint
void usbdrv_deconfigure_endpoint(uint8_t ep, uint8_t dir); // deconfigure USB endpoint
void usbdrv_stall_endpoint(uint8_t ep, uint8_t dir, bool stall); // stall endpoint
void usbdrv_set_global_NAK(uint8_t dir, bool en); // set global NAK
void usbdrv_flush_tx_fifo(uint8_t n); // flush specific or all Tx FIFOs
void usbdrv_flush_rx_fifo(); // flush the Rx FIFO
void usbdrv_set_rx_fifo_size(uint16_t size); // set Rx FIFO size
void usbdrv_fetch_received_data(uint8_t ep, uint16_t len); // fetch received data from RX FIFO to receive buffer
void usbdrv_process_rx_fifo_top(USBDRV_EventData *evt_data); // see what's on top of Rx FIFO
uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len); // write data to specific endpoint FIFO
#define USBDRV_ARM_IN_ZLP(ep) usbdrv_arm_IN_endpoint((ep), NULL, 0)
uint32_t usbdrv_arm_OUT_endpoint(uint8_t ep, uint8_t size); // arm OUT endpoint, returned with the actual armed size (capped by the max packet size on that endpoint)
void usbdrv_autoarm_OUT_endpoint(uint8_t ep); // automatically re-arm OUT endpoint at the and of the current OUT transfer
void usbdrv_enable_endpoint_interrupt(uint8_t ep, uint8_t dir, bool en); // enable/disable endpoint interrupt signaling
bool usbdrv_get_endpoint_interrupt_flag(uint8_t ep, uint8_t dir); // get endpoint interrupt flag
void usbdrv_set_address(uint8_t addr); // set device address
void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data); // process USB event
void usbdrv_push_event(uint32_t evt_code, USBDRV_EventData *evt_data); // push event onto the event queue
void usbdrv_periodic_processing(); // call this to process incoming events
#endif /* CORE_USB_USB_DRIVER */

View File

@ -9,49 +9,60 @@ typedef enum {
USB_SPD_LOW = 1, USB_SPD_LOW = 1,
USB_SPD_FULL = 2, USB_SPD_FULL = 2,
USB_SPD_HIGH = 3 USB_SPD_HIGH = 3
} USBDRV_LineSpeed; } UsbDrv_LineSpeed;
typedef void (*USBDRV_IN_cb)(uint8_t ep); typedef void (*UsbDrv_IN_cb)(uint8_t ep);
/**
* USB Driver interface.
*/
typedef struct { typedef struct {
// USB CORE -> USB DRIVER // USB CORE -> USB DRIVER
void (*init)(); // initialize USB driver void (*init)(); ///< Initialize USB driver
void (*reset)(); // reset USB driver void (*reset)(); ///< Reset USB driver
void (*stall)(uint8_t ep, uint8_t dir, bool stall); // stall the endpoint void (*stall)(uint8_t ep, uint8_t dir, bool stall); ///< Stall the endpoint
uint32_t (*arm_IN)(uint8_t ep, const uint8_t *data, uint16_t len); // arm IN endpoint uint32_t (*arm_IN)(uint8_t ep, const uint8_t *data, uint16_t len); ///< Arm IN endpoint
uint32_t (*arm_OUT)(uint8_t ep, uint16_t len); // arm OUT endpoint uint32_t (*arm_OUT)(uint8_t ep, uint16_t len); ///< Arm OUT endpoint
void (*set_address)(uint8_t addr); // set device address void (*set_address)(uint8_t addr); ///< Set device address
void (*set_config)(uint8_t ci); // make the chosen setting operational void (*set_config)(uint8_t ci); ///< Make the chosen setting operational
void (*autoarm)(uint8_t ep); // enable OUT autoarm void (*autoarm)(uint8_t ep); ///< Enable OUT autoarm
void (*en_ep_irq)(uint8_t ep, uint8_t dir, bool en); // enable endpoint interrupt void (*en_ep_irq)(uint8_t ep, uint8_t dir, bool en); ///< Enable endpoint interrupt
void (*reg_IN_cb)(uint8_t ep, USBDRV_IN_cb cb); // register a callback for IN transaction complete void (*reg_IN_cb)(uint8_t ep, UsbDrv_IN_cb cb); ///< Register a callback for IN transaction complete
// USB DRIVER -> USB CORE // USB DRIVER -> USB CORE
void (*rst_notify)(); // notify USB core of a bus issued reset void (*rst_notify)(); ///< Notify USB core of a bus issued reset
void (*enum_notify)(uint8_t spd); // notify the USB core that speed negotiation has concluded void (*enum_notify)(uint8_t spd); ///< Notify the USB core that speed negotiation has concluded
} USB_DrvIntf; } UsbDrv_DrvIntf;
#ifndef USBDBGMSG #ifndef USBDBGMSG
#define USBMSG(...) #define USBMSG(...)
#endif #endif
// callback codes /**
* Callback codes.
*/
typedef enum { typedef enum {
USB_CBC_OUT, // OUT done! USB_CBC_OUT, ///< OUT done!
USB_CBC_IN_DONE, // IN done! USB_CBC_IN_DONE, ///< IN done!
USB_CBC_IN_FIFOEMPTY, // could not serve IN request, since Tx FIFO was empty USB_CBC_IN_FIFOEMPTY, ///< Could not serve IN request, since Tx FIFO was empty
} USBDRV_CallbackCode; } UsbDrv_CallbackCode;
// callback compound /**
* Callback compound.
*/
typedef struct { typedef struct {
uint8_t ep : 4; // endpoint number uint8_t ep : 4; ///< Endpoint number
uint8_t dir : 1; // direction uint8_t dir : 1; ///< Direction
uint8_t code : 3; // event code uint8_t code : 3; ///< Event code
uint16_t size; // data size uint16_t size; ///< Data size
const uint8_t *data; // data const uint8_t *data; ///< Data
} USBDRV_CallbackCompound; } UsbDrv_CallbackCompound;
typedef enum { UST_SETUP, /**
UST_DATA } USBDRV_ControlTfStage; * Control transfer stages.
*/
typedef enum { UST_SETUP, ///< Setup stage
UST_DATA ///< Data stage
} UsbDrv_ControlTfStage;
#endif /* FLATUSB_USB_DRIVER_INTERFACE */ #endif /* FLATUSB_USB_DRIVER_INTERFACE */