Merge remote-tracking branch 'remotes/tinyusb/master' into rx_fb

This commit is contained in:
HiFiPhile
2024-05-08 23:18:29 +02:00
268 changed files with 10497 additions and 3953 deletions

View File

@@ -39,12 +39,11 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
typedef struct
{
typedef struct {
uint8_t itf_num;
uint8_t ep_in;
uint8_t ep_out; // optional Out endpoint
uint8_t itf_protocol; // Boot mouse or keyboard
uint8_t ep_out; // optional Out endpoint
uint8_t itf_protocol; // Boot mouse or keyboard
uint16_t report_desc_len;
CFG_TUSB_MEM_ALIGN uint8_t protocol_mode; // Boot (0) or Report protocol (1)
@@ -56,7 +55,7 @@ typedef struct
// TODO save hid descriptor since host can specifically request this after enumeration
// Note: HID descriptor may be not available from application after enumeration
tusb_hid_descriptor_hid_t const * hid_descriptor;
tusb_hid_descriptor_hid_t const *hid_descriptor;
} hidd_interface_t;
CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID];
@@ -64,12 +63,12 @@ CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID];
/*------------- Helpers -------------*/
static inline uint8_t get_index_by_itfnum(uint8_t itf_num)
{
for (uint8_t i=0; i < CFG_TUD_HID; i++ )
{
if ( itf_num == _hidd_itf[i].itf_num ) return i;
}
for (uint8_t i = 0; i < CFG_TUD_HID; i++) {
if (itf_num == _hidd_itf[i].itf_num)
return i;
}
return 0xFF;
return 0xFF;
}
//--------------------------------------------------------------------+
@@ -82,37 +81,29 @@ bool tud_hid_n_ready(uint8_t instance)
return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in);
}
bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len)
bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, uint16_t len)
{
uint8_t const rhport = 0;
hidd_interface_t * p_hid = &_hidd_itf[instance];
hidd_interface_t *p_hid = &_hidd_itf[instance];
// claim endpoint
TU_VERIFY( usbd_edpt_claim(rhport, p_hid->ep_in) );
TU_VERIFY(usbd_edpt_claim(rhport, p_hid->ep_in));
// prepare data
if (report_id)
{
if (report_id) {
p_hid->epin_buf[0] = report_id;
TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf+1, CFG_TUD_HID_EP_BUFSIZE-1, report, len));
TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf + 1, CFG_TUD_HID_EP_BUFSIZE - 1, report, len));
len++;
}else
{
} else {
TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf, CFG_TUD_HID_EP_BUFSIZE, report, len));
}
return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len);
}
uint8_t tud_hid_n_interface_protocol(uint8_t instance)
{
return _hidd_itf[instance].itf_protocol;
}
uint8_t tud_hid_n_interface_protocol(uint8_t instance) { return _hidd_itf[instance].itf_protocol; }
uint8_t tud_hid_n_get_protocol(uint8_t instance)
{
return _hidd_itf[instance].protocol_mode;
}
uint8_t tud_hid_n_get_protocol(uint8_t instance) { return _hidd_itf[instance].protocol_mode; }
bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6])
{
@@ -121,27 +112,23 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi
report.modifier = modifier;
report.reserved = 0;
if ( keycode )
{
if (keycode) {
memcpy(report.keycode, keycode, sizeof(report.keycode));
}else
{
} else {
tu_memclr(report.keycode, 6);
}
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
}
bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id,
uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal)
bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal)
{
hid_mouse_report_t report =
{
hid_mouse_report_t report = {
.buttons = buttons,
.x = x,
.y = y,
.wheel = vertical,
.pan = horizontal
.x = x,
.y = y,
.wheel = vertical,
.pan = horizontal
};
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
@@ -149,29 +136,27 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id,
bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal)
{
hid_abs_mouse_report_t report =
{
hid_abs_mouse_report_t report = {
.buttons = buttons,
.x = x,
.y = y,
.wheel = vertical,
.pan = horizontal
.x = x,
.y = y,
.wheel = vertical,
.pan = horizontal
};
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
}
bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id,
int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) {
hid_gamepad_report_t report =
{
.x = x,
.y = y,
.z = z,
.rz = rz,
.rx = rx,
.ry = ry,
.hat = hat,
.buttons = buttons,
bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons)
{
hid_gamepad_report_t report = {
.x = x,
.y = y,
.z = z,
.rz = rz,
.rx = rx,
.ry = ry,
.hat = hat,
.buttons = buttons,
};
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
@@ -180,67 +165,64 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id,
//--------------------------------------------------------------------+
// USBD-CLASS API
//--------------------------------------------------------------------+
void hidd_init(void) {
void hidd_init(void)
{
hidd_reset(0);
}
bool hidd_deinit(void) {
bool hidd_deinit(void)
{
return true;
}
void hidd_reset(uint8_t rhport)
{
(void) rhport;
(void)rhport;
tu_memclr(_hidd_itf, sizeof(_hidd_itf));
}
uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len)
{
uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
{
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0);
// len = interface + hid + n*endpoints
uint16_t const drv_len =
(uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) +
desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
uint16_t const drv_len = (uint16_t)(sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
TU_ASSERT(max_len >= drv_len, 0);
// Find available interface
hidd_interface_t * p_hid = NULL;
hidd_interface_t *p_hid = NULL;
uint8_t hid_id;
for(hid_id=0; hid_id<CFG_TUD_HID; hid_id++)
{
if ( _hidd_itf[hid_id].ep_in == 0 )
{
for (hid_id = 0; hid_id < CFG_TUD_HID; hid_id++) {
if (_hidd_itf[hid_id].ep_in == 0) {
p_hid = &_hidd_itf[hid_id];
break;
}
}
TU_ASSERT(p_hid, 0);
uint8_t const *p_desc = (uint8_t const *) desc_itf;
uint8_t const *p_desc = (uint8_t const *)desc_itf;
//------------- HID descriptor -------------//
p_desc = tu_desc_next(p_desc);
TU_ASSERT(HID_DESC_TYPE_HID == tu_desc_type(p_desc), 0);
p_hid->hid_descriptor = (tusb_hid_descriptor_hid_t const *) p_desc;
p_hid->hid_descriptor = (tusb_hid_descriptor_hid_t const *)p_desc;
//------------- Endpoint Descriptor -------------//
p_desc = tu_desc_next(p_desc);
TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0);
if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->itf_protocol = desc_itf->bInterfaceProtocol;
if (desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT)
p_hid->itf_protocol = desc_itf->bInterfaceProtocol;
p_hid->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode
p_hid->itf_num = desc_itf->bInterfaceNumber;
p_hid->itf_num = desc_itf->bInterfaceNumber;
// Use offsetof to avoid pointer to the odd/misaligned address
p_hid->report_desc_len = tu_unaligned_read16((uint8_t const*) p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength));
p_hid->report_desc_len = tu_unaligned_read16((uint8_t const *)p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength));
// Prepare for output endpoint
if (p_hid->ep_out)
{
if ( !usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)) )
{
if (p_hid->ep_out) {
if (!usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))) {
TU_LOG_FAILED();
TU_BREAKPOINT();
}
@@ -252,144 +234,120 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint1
// Invoked when a control transfer occurred on an interface of this class
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
// return false to stall control endpoint (e.g unsupported request)
bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
uint8_t const hid_itf = get_index_by_itfnum((uint8_t) request->wIndex);
uint8_t const hid_itf = get_index_by_itfnum((uint8_t)request->wIndex);
TU_VERIFY(hid_itf < CFG_TUD_HID);
hidd_interface_t* p_hid = &_hidd_itf[hid_itf];
hidd_interface_t *p_hid = &_hidd_itf[hid_itf];
if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD)
{
if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) {
//------------- STD Request -------------//
if ( stage == CONTROL_STAGE_SETUP )
{
uint8_t const desc_type = tu_u16_high(request->wValue);
//uint8_t const desc_index = tu_u16_low (request->wValue);
if (stage == CONTROL_STAGE_SETUP) {
uint8_t const desc_type = tu_u16_high(request->wValue);
// uint8_t const desc_index = tu_u16_low (request->wValue);
if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID)
{
if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID) {
TU_VERIFY(p_hid->hid_descriptor);
TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) p_hid->hid_descriptor, p_hid->hid_descriptor->bLength));
}
else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT)
{
uint8_t const * desc_report = tud_hid_descriptor_report_cb(hid_itf);
tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_report, p_hid->report_desc_len);
}
else
{
TU_VERIFY(tud_control_xfer(rhport, request, (void *)(uintptr_t)p_hid->hid_descriptor, p_hid->hid_descriptor->bLength));
} else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT) {
uint8_t const *desc_report = tud_hid_descriptor_report_cb(hid_itf);
tud_control_xfer(rhport, request, (void *)(uintptr_t)desc_report, p_hid->report_desc_len);
} else {
return false; // stall unsupported request
}
}
}
else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
{
} else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) {
//------------- Class Specific Request -------------//
switch( request->bRequest )
{
case HID_REQ_CONTROL_GET_REPORT:
if ( stage == CONTROL_STAGE_SETUP )
{
uint8_t const report_type = tu_u16_high(request->wValue);
uint8_t const report_id = tu_u16_low(request->wValue);
switch (request->bRequest) {
case HID_REQ_CONTROL_GET_REPORT:
if (stage == CONTROL_STAGE_SETUP) {
uint8_t const report_type = tu_u16_high(request->wValue);
uint8_t const report_id = tu_u16_low(request->wValue);
uint8_t* report_buf = p_hid->ctrl_buf;
uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
uint8_t *report_buf = p_hid->ctrl_buf;
uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
uint16_t xferlen = 0;
uint16_t xferlen = 0;
// If host request a specific Report ID, add ID to as 1 byte of response
if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) )
{
*report_buf++ = report_id;
req_len--;
// If host request a specific Report ID, add ID to as 1 byte of response
if ((report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1)) {
*report_buf++ = report_id;
req_len--;
xferlen++;
}
xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len);
TU_ASSERT( xferlen > 0 );
tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen);
xferlen++;
}
xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, req_len);
TU_ASSERT(xferlen > 0);
tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen);
}
break;
case HID_REQ_CONTROL_SET_REPORT:
if ( stage == CONTROL_STAGE_SETUP )
{
TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf));
tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength);
case HID_REQ_CONTROL_SET_REPORT:
if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf));
tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength);
} else if (stage == CONTROL_STAGE_ACK) {
uint8_t const report_type = tu_u16_high(request->wValue);
uint8_t const report_id = tu_u16_low(request->wValue);
uint8_t const *report_buf = p_hid->ctrl_buf;
uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
// If host request a specific Report ID, extract report ID in buffer before invoking callback
if ((report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0])) {
report_buf++;
report_len--;
}
else if ( stage == CONTROL_STAGE_ACK )
{
uint8_t const report_type = tu_u16_high(request->wValue);
uint8_t const report_id = tu_u16_low(request->wValue);
uint8_t const* report_buf = p_hid->ctrl_buf;
uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
// If host request a specific Report ID, extract report ID in buffer before invoking callback
if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) )
{
report_buf++;
report_len--;
}
tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len);
}
tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, report_len);
}
break;
case HID_REQ_CONTROL_SET_IDLE:
if ( stage == CONTROL_STAGE_SETUP )
{
p_hid->idle_rate = tu_u16_high(request->wValue);
if ( tud_hid_set_idle_cb )
{
// stall request if callback return false
TU_VERIFY( tud_hid_set_idle_cb( hid_itf, p_hid->idle_rate) );
}
tud_control_status(rhport, request);
case HID_REQ_CONTROL_SET_IDLE:
if (stage == CONTROL_STAGE_SETUP) {
p_hid->idle_rate = tu_u16_high(request->wValue);
if (tud_hid_set_idle_cb) {
// stall request if callback return false
TU_VERIFY(tud_hid_set_idle_cb(hid_itf, p_hid->idle_rate));
}
tud_control_status(rhport, request);
}
break;
case HID_REQ_CONTROL_GET_IDLE:
if ( stage == CONTROL_STAGE_SETUP )
{
// TODO idle rate of report
tud_control_xfer(rhport, request, &p_hid->idle_rate, 1);
}
case HID_REQ_CONTROL_GET_IDLE:
if (stage == CONTROL_STAGE_SETUP) {
// TODO idle rate of report
tud_control_xfer(rhport, request, &p_hid->idle_rate, 1);
}
break;
case HID_REQ_CONTROL_GET_PROTOCOL:
if ( stage == CONTROL_STAGE_SETUP )
{
tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1);
}
case HID_REQ_CONTROL_GET_PROTOCOL:
if (stage == CONTROL_STAGE_SETUP) {
tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1);
}
break;
case HID_REQ_CONTROL_SET_PROTOCOL:
if ( stage == CONTROL_STAGE_SETUP )
{
tud_control_status(rhport, request);
}
else if ( stage == CONTROL_STAGE_ACK )
{
p_hid->protocol_mode = (uint8_t) request->wValue;
if (tud_hid_set_protocol_cb)
{
tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode);
}
case HID_REQ_CONTROL_SET_PROTOCOL:
if (stage == CONTROL_STAGE_SETUP) {
tud_control_status(rhport, request);
} else if (stage == CONTROL_STAGE_ACK) {
p_hid->protocol_mode = (uint8_t)request->wValue;
if (tud_hid_set_protocol_cb) {
tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode);
}
}
break;
default: return false; // stall unsupported request
default:
return false; // stall unsupported request
}
}else
{
} else {
return false; // stall unsupported request
}
@@ -398,31 +356,43 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
(void) result;
(void)result;
uint8_t instance = 0;
hidd_interface_t * p_hid = _hidd_itf;
hidd_interface_t *p_hid = _hidd_itf;
// Identify which interface to use
for (instance = 0; instance < CFG_TUD_HID; instance++)
{
for (instance = 0; instance < CFG_TUD_HID; instance++) {
p_hid = &_hidd_itf[instance];
if ( (ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in) ) break;
if ((ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in))
break;
}
TU_ASSERT(instance < CFG_TUD_HID);
// Check if there was a problem
if (XFER_RESULT_SUCCESS != result) { // Inform application about the issue
if (tud_hid_report_fail_cb) {
tud_hid_report_fail_cb(instance, ep_addr, (uint16_t)xferred_bytes);
}
// Allow a new transfer to be received if issue happened on an OUT endpoint
if (ep_addr == p_hid->ep_out) {
// Prepare the OUT endpoint to be able to receive a new transfer
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
}
return true;
}
// Sent report successfully
if (ep_addr == p_hid->ep_in)
{
if (tud_hid_report_complete_cb)
{
tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes);
if (ep_addr == p_hid->ep_in) {
if (tud_hid_report_complete_cb) {
tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t)xferred_bytes);
}
}
// Received report
else if (ep_addr == p_hid->ep_out)
{
tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, (uint16_t) xferred_bytes);
// Received report successfully
else if (ep_addr == p_hid->ep_out) {
tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t)xferred_bytes);
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
}

View File

@@ -128,6 +128,8 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate);
// Note: For composite reports, report[0] is report ID
TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len);
// Invoked when a transfer wasn't successful
TU_ATTR_WEAK void tud_hid_report_fail_cb(uint8_t instance, uint8_t ep_addr, uint16_t len);
//--------------------------------------------------------------------+
// Inline Functions
@@ -471,6 +473,7 @@ uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf
bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
#ifdef __cplusplus
}
#endif

View File

@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2021, Ha Thach (tinyusb.org)
* Copyright (c) 2024, Hardy Griech
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,22 +25,58 @@
* This file is part of the TinyUSB stack.
*/
#ifndef _TUSB_NCM_H_
#define _TUSB_NCM_H_
#include "common/tusb_common.h"
#ifdef __cplusplus
extern "C" {
// NTB buffers size for reception side, must be >> MTU to avoid TCP retransmission (driver issue ?)
// Linux use 2048 as minimal size
#ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE
#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200
#endif
// Table 4.3 Data Class Interface Protocol Codes
typedef enum
{
NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK = 0x01
} ncm_data_interface_protocol_code_t;
// NTB buffers size for reception side, must be > MTU
// Linux use 2048 as minimal size
#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE
#define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200
#endif
// Number of NTB buffers for reception side
// Depending on the configuration, this parameter could be increased with the cost of additional RAM requirements
// On Full-Speed (RP2040) :
// 1 - good performance
// 2 - up to 30% more performance with iperf with small packets
// >2 - no performance gain
// On High-Speed (STM32F7) :
// No performance gain
#ifndef CFG_TUD_NCM_OUT_NTB_N
#define CFG_TUD_NCM_OUT_NTB_N 1
#endif
// Number of NTB buffers for transmission side
// Depending on the configuration, this parameter could be increased with the cost of additional RAM requirements
// On Full-Speed (RP2040) :
// 1 - good performance but SystemView shows lost events (on load test)
// 2 - up to 50% more performance with iperf with small packets, "tud_network_can_xmit: request blocked"
// happens from time to time with SystemView
// 3 - "tud_network_can_xmit: request blocked" never happens
// >3 - no performance gain
// On High-Speed (STM32F7) :
// No performance gain
#ifndef CFG_TUD_NCM_IN_NTB_N
#define CFG_TUD_NCM_IN_NTB_N 1
#endif
// How many datagrams it is allowed to put into an NTB for transmission side
#ifndef CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB
#define CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB 8
#endif
// This tells the host how many datagrams it is allowed to put into an NTB
#ifndef CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB
#define CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB 6
#endif
// Table 6.2 Class-Specific Request Codes for Network Control Model subclass
typedef enum
@@ -62,8 +99,65 @@ typedef enum
NCM_SET_CRC_MODE = 0x8A,
} ncm_request_code_t;
#ifdef __cplusplus
}
#endif
#define NTH16_SIGNATURE 0x484D434E
#define NDP16_SIGNATURE_NCM0 0x304D434E
#define NDP16_SIGNATURE_NCM1 0x314D434E
typedef struct TU_ATTR_PACKED {
uint16_t wLength;
uint16_t bmNtbFormatsSupported;
uint32_t dwNtbInMaxSize;
uint16_t wNdbInDivisor;
uint16_t wNdbInPayloadRemainder;
uint16_t wNdbInAlignment;
uint16_t wReserved;
uint32_t dwNtbOutMaxSize;
uint16_t wNdbOutDivisor;
uint16_t wNdbOutPayloadRemainder;
uint16_t wNdbOutAlignment;
uint16_t wNtbOutMaxDatagrams;
} ntb_parameters_t;
typedef struct TU_ATTR_PACKED {
uint32_t dwSignature;
uint16_t wHeaderLength;
uint16_t wSequence;
uint16_t wBlockLength;
uint16_t wNdpIndex;
} nth16_t;
typedef struct TU_ATTR_PACKED {
uint16_t wDatagramIndex;
uint16_t wDatagramLength;
} ndp16_datagram_t;
typedef struct TU_ATTR_PACKED {
uint32_t dwSignature;
uint16_t wLength;
uint16_t wNextNdpIndex;
//ndp16_datagram_t datagram[];
} ndp16_t;
typedef union TU_ATTR_PACKED {
struct {
nth16_t nth;
ndp16_t ndp;
ndp16_datagram_t ndp_datagram[CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB + 1];
};
uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE];
} xmit_ntb_t;
typedef union TU_ATTR_PACKED {
struct {
nth16_t nth;
// only the header is at a guaranteed position
};
uint8_t data[CFG_TUD_NCM_OUT_NTB_MAX_SIZE];
} recv_ntb_t;
struct ncm_notify_t {
tusb_control_request_t header;
uint32_t downlink, uplink;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -28,14 +28,13 @@
#ifndef _TUSB_NET_DEVICE_H_
#define _TUSB_NET_DEVICE_H_
#include <stdint.h>
#include "class/cdc/cdc.h"
#if CFG_TUD_ECM_RNDIS && CFG_TUD_NCM
#error "Cannot enable both ECM_RNDIS and NCM network drivers"
#endif
#include "ncm.h"
/* declared here, NOT in usb_descriptors.c, so that the driver can intelligently ZLP as needed */
#define CFG_TUD_NET_ENDPOINT_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
@@ -44,21 +43,13 @@
#define CFG_TUD_NET_MTU 1514
#endif
#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE
#define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200
#endif
#ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE
#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200
#endif
// Table 4.3 Data Class Interface Protocol Codes
typedef enum
{
NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK = 0x01
} ncm_data_interface_protocol_code_t;
#ifndef CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB
#define CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB 8
#endif
#ifndef CFG_TUD_NCM_ALIGNMENT
#define CFG_TUD_NCM_ALIGNMENT 4
#endif
#ifdef __cplusplus
extern "C" {
@@ -96,11 +87,6 @@ void tud_network_init_cb(void);
// TODO removed later since it is not part of tinyusb stack
extern uint8_t tud_network_mac_address[6];
//------------- NCM -------------//
// callback to client providing optional indication of internal state of network driver
void tud_network_link_state_cb(bool state);
//--------------------------------------------------------------------+
// INTERNAL USBD-CLASS DRIVER API
//--------------------------------------------------------------------+

View File

@@ -183,6 +183,23 @@ typedef enum {
} usmtmc_request_type_enum;
typedef enum {
// The last and first valid bNotify1 for use by the USBTMC class specification.
USBTMC_bNOTIFY1_USBTMC_FIRST = 0x00,
USBTMC_bNOTIFY1_USBTMC_LAST = 0x3F,
// The last and first valid bNotify1 for use by vendors.
USBTMC_bNOTIFY1_VENDOR_SPECIFIC_FIRST = 0x40,
USBTMC_bNOTIFY1_VENDOR_SPECIFIC_LAST = 0x7F,
// The last and first valid bNotify1 for use by USBTMC subclass specifications.
USBTMC_bNOTIFY1_SUBCLASS_FIRST = 0x80,
USBTMC_bNOTIFY1_SUBCLASS_LAST = 0xFF,
// From the USB488 Subclass Specification, Section 3.4.
USB488_bNOTIFY1_SRQ = 0x81,
} usbtmc_int_in_payload_format;
typedef enum {
USBTMC_STATUS_SUCCESS = 0x01,
USBTMC_STATUS_PENDING = 0x02,
@@ -303,6 +320,14 @@ typedef struct TU_ATTR_PACKED
TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_rsp_488_t) == 3u, "struct wrong length");
typedef struct TU_ATTR_PACKED
{
uint8_t bNotify1; // Must be USB488_bNOTIFY1_SRQ
uint8_t StatusByte;
} usbtmc_srq_interrupt_488_t;
TU_VERIFY_STATIC(sizeof(usbtmc_srq_interrupt_488_t) == 2u, "struct wrong length");
typedef struct TU_ATTR_PACKED
{
struct TU_ATTR_PACKED

View File

@@ -86,6 +86,11 @@ tu_static char logMsg[150];
// imposes a minimum buffer size of 32 bytes.
#define USBTMCD_BUFFER_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
// Interrupt endpoint buffer size, default to 2 bytes as USB488 specification.
#ifndef CFG_TUD_USBTMC_INT_EP_SIZE
#define CFG_TUD_USBTMC_INT_EP_SIZE 2
#endif
/*
* The state machine does not allow simultaneous reading and writing. This is
* consistent with USBTMC.
@@ -124,13 +129,15 @@ typedef struct
uint8_t ep_bulk_in;
uint8_t ep_bulk_out;
uint8_t ep_int_in;
uint32_t ep_bulk_in_wMaxPacketSize;
uint32_t ep_bulk_out_wMaxPacketSize;
// IN buffer is only used for first packet, not the remainder
// in order to deal with prepending header
CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_in_buf[USBTMCD_BUFFER_SIZE];
uint32_t ep_bulk_in_wMaxPacketSize;
// OUT buffer receives one packet at a time
CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_BUFFER_SIZE];
uint32_t ep_bulk_out_wMaxPacketSize;
// Buffer int msg to ensure alignment and placement correctness
CFG_TUSB_MEM_ALIGN uint8_t ep_int_in_buf[CFG_TUD_USBTMC_INT_EP_SIZE];
uint32_t transfer_size_remaining; // also used for requested length for bulk IN.
uint32_t transfer_size_sent; // To keep track of data bytes that have been queued in FIFO (not header bytes)
@@ -240,6 +247,19 @@ bool tud_usbtmc_transmit_dev_msg_data(
return true;
}
bool tud_usbtmc_transmit_notification_data(const void * data, size_t len)
{
#ifndef NDEBUG
TU_ASSERT(len > 0);
TU_ASSERT(usbtmc_state.ep_int_in != 0);
#endif
TU_VERIFY(usbd_edpt_busy(usbtmc_state.rhport, usbtmc_state.ep_int_in));
TU_VERIFY(tu_memcpy_s(usbtmc_state.ep_int_in_buf, sizeof(usbtmc_state.ep_int_in_buf), data, len) == 0);
TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, usbtmc_state.ep_int_in_buf, (uint16_t)len));
return true;
}
void usbtmcd_init_cb(void)
{
usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb();
@@ -547,9 +567,10 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
case STATE_TX_INITIATED:
if(usbtmc_state.transfer_size_remaining >= sizeof(usbtmc_state.ep_bulk_in_buf))
{
// FIXME! This removes const below!
// Copy buffer to ensure alignment correctness
memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf));
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in,
(void*)(uintptr_t) usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf)));
usbtmc_state.ep_bulk_in_buf, sizeof(usbtmc_state.ep_bulk_in_buf)));
usbtmc_state.devInBuffer += sizeof(usbtmc_state.ep_bulk_in_buf);
usbtmc_state.transfer_size_remaining -= sizeof(usbtmc_state.ep_bulk_in_buf);
usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.ep_bulk_in_buf);
@@ -585,7 +606,9 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
}
}
else if (ep_addr == usbtmc_state.ep_int_in) {
// Good?
if (tud_usbtmc_notification_complete_cb) {
TU_VERIFY(tud_usbtmc_notification_complete_cb());
}
return true;
}
return false;

View File

@@ -73,6 +73,10 @@ bool tud_usbtmc_check_abort_bulk_in_cb(usbtmc_check_abort_bulk_rsp_t *rsp);
bool tud_usbtmc_check_abort_bulk_out_cb(usbtmc_check_abort_bulk_rsp_t *rsp);
bool tud_usbtmc_check_clear_cb(usbtmc_get_clear_status_rsp_t *rsp);
// The interrupt-IN endpoint buffer was transmitted to the host. Use
// tud_usbtmc_transmit_notification_data to send another notification.
TU_ATTR_WEAK bool tud_usbtmc_notification_complete_cb(void);
// Indicator pulse should be 0.5 to 1.0 seconds long
TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult);
@@ -82,17 +86,23 @@ TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg);
//TU_ATTR_WEAK bool tud_usbtmc_app_go_to_local_cb();
#endif
/*******************************************
* Called from app
*
* We keep a reference to the buffer, so it MUST not change until the app is
* notified that the transfer is complete.
******************************************/
// Called from app
//
// We keep a reference to the buffer, so it MUST not change until the app is
// notified that the transfer is complete.
bool tud_usbtmc_transmit_dev_msg_data(
const void * data, size_t len,
bool endOfMessage, bool usingTermChar);
// Buffers a notification to be sent to the host. The data starts
// with the bNotify1 field, see the USBTMC Specification, Table 13.
//
// If the previous notification data has not yet been sent, this
// returns false.
//
// Requires an interrupt endpoint in the interface.
bool tud_usbtmc_transmit_notification_data(const void * data, size_t len);
bool tud_usbtmc_start_bus_read(void);
@@ -105,9 +115,4 @@ void usbtmcd_reset_cb(uint8_t rhport);
bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
/************************************************************
* USBTMC Descriptor Templates
*************************************************************/
#endif /* CLASS_USBTMC_USBTMC_DEVICE_H_ */