Open FFBoard
Open source force feedback firmware
usbc.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2023 Ha Thach (thach@tinyusb.org)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 * This file is part of the TinyUSB stack.
25 */
26
27#include "tusb_option.h"
28
29#if CFG_TUC_ENABLED
30
31#include "tcd.h"
32#include "usbc.h"
33
34//--------------------------------------------------------------------+
35//
36//--------------------------------------------------------------------+
37
38// Debug level of USBD
39#define USBC_DEBUG 2
40#define TU_LOG_USBC(...) TU_LOG(USBC_DEBUG, __VA_ARGS__)
41
42// Event queue
43// usbc_int_set() is used as mutex in OS NONE config
44void usbc_int_set(bool enabled);
45OSAL_QUEUE_DEF(usbc_int_set, _usbc_qdef, CFG_TUC_TASK_QUEUE_SZ, tcd_event_t);
47
48// if stack is initialized
49static bool _usbc_inited = false;
50
51// if port is initialized
52static bool _port_inited[TUP_TYPEC_RHPORTS_NUM];
53
54// Max possible PD size is 262 bytes
55static uint8_t _rx_buf[64] TU_ATTR_ALIGNED(4);
56static uint8_t _tx_buf[64] TU_ATTR_ALIGNED(4);
57
58bool usbc_msg_send(uint8_t rhport, pd_header_t const* header, void const* data);
59bool parse_msg_data(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end);
60bool parse_msg_control(uint8_t rhport, pd_header_t const* header);
61
62//--------------------------------------------------------------------+
63//
64//--------------------------------------------------------------------+
65bool tuc_inited(uint8_t rhport) {
66 return _usbc_inited && _port_inited[rhport];
67}
68
69bool tuc_init(uint8_t rhport, uint32_t port_type) {
70 // Initialize stack
71 if (!_usbc_inited) {
72 tu_memclr(_port_inited, sizeof(_port_inited));
73
74 _usbc_q = osal_queue_create(&_usbc_qdef);
75 TU_ASSERT(_usbc_q != NULL);
76
77 _usbc_inited = true;
78 }
79
80 // skip if port already initialized
81 if ( _port_inited[rhport] ) {
82 return true;
83 }
84
85 TU_LOG_USBC("USBC init on port %u\r\n", rhport);
86 TU_LOG_INT(USBC_DEBUG, sizeof(tcd_event_t));
87
88 TU_ASSERT(tcd_init(rhport, port_type));
89 tcd_int_enable(rhport);
90
91 _port_inited[rhport] = true;
92 return true;
93}
94
95void tuc_task_ext(uint32_t timeout_ms, bool in_isr) {
96 (void) in_isr; // not implemented yet
97
98 // Skip if stack is not initialized
99 if (!_usbc_inited) return;
100
101 // Loop until there is no more events in the queue
102 while (1) {
103 tcd_event_t event;
104 if (!osal_queue_receive(_usbc_q, &event, timeout_ms)) return;
105
106 switch (event.event_id) {
108 break;
109
111 // TODO process message here in ISR, move to thread later
112 if (event.xfer_complete.result == XFER_RESULT_SUCCESS) {
113 pd_header_t const* header = (pd_header_t const*) _rx_buf;
114
115 if (header->n_data_obj == 0) {
117
118 }else {
119 uint8_t const* p_end = _rx_buf + event.xfer_complete.xferred_bytes;
120 uint8_t const * dobj = _rx_buf + sizeof(pd_header_t);
121
122 parse_msg_data(event.rhport, header, dobj, p_end);
123 }
124 }
125
126 // prepare for next message
127 tcd_msg_receive(event.rhport, _rx_buf, sizeof(_rx_buf));
128 break;
129
131 break;
132
133 default: break;
134 }
135 }
136}
137
138bool parse_msg_data(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end) {
140 tuc_pd_data_received_cb(rhport, header, dobj, p_end);
141 }
142
143 return true;
144}
145
146bool parse_msg_control(uint8_t rhport, pd_header_t const* header) {
149 }
150
151 return true;
152}
153
154//--------------------------------------------------------------------+
155//
156//--------------------------------------------------------------------+
157
158bool usbc_msg_send(uint8_t rhport, pd_header_t const* header, void const* data) {
159 // copy header
160 memcpy(_tx_buf, header, sizeof(pd_header_t));
161
162 // copy data objcet if available
163 uint16_t const n_data_obj = header->n_data_obj;
164 if (n_data_obj > 0) {
165 memcpy(_tx_buf + sizeof(pd_header_t), data, n_data_obj * 4);
166 }
167
168 return tcd_msg_send(rhport, _tx_buf, sizeof(pd_header_t) + n_data_obj * 4);
169}
170
171bool tuc_msg_request(uint8_t rhport, void const* rdo) {
172 pd_header_t const header = {
173 .msg_type = PD_DATA_REQUEST,
174 .data_role = PD_DATA_ROLE_UFP,
175 .specs_rev = PD_REV_30,
176 .power_role = PD_POWER_ROLE_SINK,
177 .msg_id = 0,
178 .n_data_obj = 1,
179 .extended = 0,
180 };
181
182 return usbc_msg_send(rhport, &header, rdo);
183}
184
185void tcd_event_handler(tcd_event_t const * event, bool in_isr) {
186 (void) in_isr;
187 switch(event->event_id) {
189 if (event->cc_changed.cc_state[0] || event->cc_changed.cc_state[1]) {
190 // Attach, start receiving
191 tcd_msg_receive(event->rhport, _rx_buf, sizeof(_rx_buf));
192 }else {
193 // Detach
194 }
195 break;
196
197 default: break;
198 }
199
201}
202
203//--------------------------------------------------------------------+
204//
205//--------------------------------------------------------------------+
206void usbc_int_set(bool enabled) {
207 // Disable all controllers since they shared the same event queue
208 for (uint8_t p = 0; p < TUP_TYPEC_RHPORTS_NUM; p++) {
209 if ( _port_inited[p] ) {
210 if (enabled) {
212 }else {
214 }
215 }
216 }
217}
218
219#endif
uint8_t header
static struct @612 data
static bool in_isr
static TU_ATTR_ALWAYS_INLINE osal_queue_t osal_queue_create(osal_queue_def_t *qdef)
QueueHandle_t osal_queue_t
Definition: osal_freertos.h:55
static TU_ATTR_ALWAYS_INLINE bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr)
static TU_ATTR_ALWAYS_INLINE bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec)
@ PD_DATA_REQUEST
Definition: pd_types.h:83
@ PD_POWER_ROLE_SINK
Definition: pd_types.h:111
@ PD_REV_30
Definition: pd_types.h:102
@ PD_DATA_ROLE_UFP
Definition: pd_types.h:106
struct TU_ATTR_PACKED pd_header_t
static void * memcpy(void *dst, const void *src, size_t n)
Definition: ringbuffer.c:8
AUDIO Channel Cluster Descriptor (4.1)
Definition: audio.h:647
struct TU_ATTR_PACKED::@670::TU_ATTR_PACKED xfer_complete
struct TU_ATTR_PACKED::@670::@672 cc_changed
uint8_t rhport
Definition: tcd.h:52
uint8_t event_id
Definition: tcd.h:53
@ TCD_EVENT_CC_CHANGED
Definition: tcd.h:46
@ TCD_EVENT_TX_COMPLETE
Definition: tcd.h:48
@ TCD_EVENT_RX_COMPLETE
Definition: tcd.h:47
@ XFER_RESULT_SUCCESS
Definition: tusb_types.h:237
void tcd_int_disable(uint8_t rhport)
Definition: typec_stm32.c:208
static uint8_t const * _rx_buf
Definition: typec_stm32.c:65
bool tcd_init(uint8_t rhport, uint32_t port_type)
Definition: typec_stm32.c:167
bool tcd_msg_receive(uint8_t rhport, uint8_t *buffer, uint16_t total_bytes)
Definition: typec_stm32.c:213
void tcd_int_enable(uint8_t rhport)
Definition: typec_stm32.c:202
bool tcd_msg_send(uint8_t rhport, uint8_t const *buffer, uint16_t total_bytes)
Definition: typec_stm32.c:219
bool tuc_msg_request(uint8_t rhport, void const *rdo)
Definition: usbc.c:171
static uint8_t _rx_buf[64] TU_ATTR_ALIGNED(4)
Definition: dcd.h:55
bool tuc_init(uint8_t rhport, uint32_t port_type)
Definition: usbc.c:69
tu_static osal_queue_t _usbc_q
Definition: usbc.c:46
bool usbc_msg_send(uint8_t rhport, pd_header_t const *header, void const *data)
Definition: usbc.c:158
bool tuc_inited(uint8_t rhport)
Definition: usbc.c:65
static bool _usbc_inited
Definition: usbc.c:49
static bool _port_inited[TUP_TYPEC_RHPORTS_NUM]
Definition: usbc.c:52
OSAL_QUEUE_DEF(usbc_int_set, _usbc_qdef, CFG_TUC_TASK_QUEUE_SZ, tcd_event_t)
void tcd_event_handler(tcd_event_t const *event, bool in_isr)
Definition: usbc.c:185
void usbc_int_set(bool enabled)
Definition: usbc.c:206
bool parse_msg_data(uint8_t rhport, pd_header_t const *header, uint8_t const *dobj, uint8_t const *p_end)
Definition: usbc.c:138
void tuc_task_ext(uint32_t timeout_ms, bool in_isr)
Definition: usbc.c:95
bool parse_msg_control(uint8_t rhport, pd_header_t const *header)
Definition: usbc.c:146
TU_ATTR_WEAK bool tuc_pd_data_received_cb(uint8_t rhport, pd_header_t const *header, uint8_t const *dobj, uint8_t const *p_end)
TU_ATTR_WEAK bool tuc_pd_control_received_cb(uint8_t rhport, pd_header_t const *header)