mirror of
https://github.com/hathach/tinyusb.git
synced 2025-03-25 01:43:47 +00:00
wrap up initial PD support for G4
This commit is contained in:
parent
c28503060c
commit
6941a5af81
@ -62,7 +62,8 @@ int main(void)
|
||||
while (1) {
|
||||
led_blinking_task();
|
||||
|
||||
// tuc_task();
|
||||
// tinyusb typec task
|
||||
tuc_task();
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,6 +74,93 @@ void app_main(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TypeC PD callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool tuc_pd_data_received_cb(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end) {
|
||||
switch (header->msg_type) {
|
||||
case PD_DATA_SOURCE_CAP: {
|
||||
printf("PD Source Capabilities\r\n");
|
||||
// Examine source capability and select a suitable PDO (starting from 1 with safe5v)
|
||||
uint8_t obj_pos = 1;
|
||||
|
||||
for(size_t i=0; i<header->n_data_obj; i++) {
|
||||
TU_VERIFY(dobj < p_end);
|
||||
uint32_t const pdo = tu_le32toh(tu_unaligned_read32(dobj));
|
||||
|
||||
switch ((pdo >> 30) & 0x03ul) {
|
||||
case PD_PDO_TYPE_FIXED: {
|
||||
pd_pdo_fixed_t const* fixed = (pd_pdo_fixed_t const*) &pdo;
|
||||
printf("[Fixed] %u mV %u mA\r\n", fixed->voltage_50mv*50, fixed->current_max_10ma*10);
|
||||
break;
|
||||
}
|
||||
|
||||
case PD_PDO_TYPE_BATTERY:
|
||||
break;
|
||||
|
||||
case PD_PDO_TYPE_VARIABLE:
|
||||
break;
|
||||
|
||||
case PD_PDO_TYPE_APDO:
|
||||
break;
|
||||
}
|
||||
|
||||
dobj += 4;
|
||||
}
|
||||
|
||||
//------------- Response with selected PDO -------------//
|
||||
// Be careful and make sure your board can withstand the selected PDO voltage other than safe5v e.g 12v or 20v
|
||||
|
||||
// Send request with selected PDO position as response to Source Cap
|
||||
pd_rdo_fixed_variable_t rdo = {
|
||||
.current_extremum_10ma = 50, // max 500mA
|
||||
.current_operate_10ma = 30, // 300mA
|
||||
.reserved = 0,
|
||||
.epr_mode_capable = 0,
|
||||
.unchunked_ext_msg_support = 0,
|
||||
.no_usb_suspend = 0,
|
||||
.usb_comm_capable = 1,
|
||||
.capability_mismatch = 0,
|
||||
.give_back_flag = 0, // exteremum is max
|
||||
.object_position = obj_pos,
|
||||
};
|
||||
|
||||
tuc_msg_request(rhport, &rdo);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tuc_pd_control_received_cb(uint8_t rhport, pd_header_t const* header) {
|
||||
switch (header->msg_type) {
|
||||
case PD_CTRL_ACCEPT:
|
||||
printf("PD Request Accepted\r\n");
|
||||
// preparing for power transition
|
||||
break;
|
||||
|
||||
case PD_CTRL_REJECT:
|
||||
printf("PD Request Rejected\r\n");
|
||||
// try to negotiate further power
|
||||
break;
|
||||
|
||||
case PD_CTRL_PS_READY:
|
||||
printf("PD Power Ready\r\n");
|
||||
// Source is ready to supply power
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// BLINKING TASK
|
||||
//--------------------------------------------------------------------+
|
||||
|
@ -48,8 +48,7 @@ enum {
|
||||
TCD_EVENT_TX_COMPLETE,
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint8_t rhport;
|
||||
uint8_t event_id;
|
||||
|
||||
@ -58,10 +57,10 @@ typedef struct {
|
||||
uint8_t cc_state[2];
|
||||
} cc_changed;
|
||||
|
||||
struct {
|
||||
uint16_t xferred_bytes;
|
||||
uint8_t result;
|
||||
} rx_complete;
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t result : 2;
|
||||
uint16_t xferred_bytes : 14;
|
||||
} xfer_complete;
|
||||
};
|
||||
|
||||
} tcd_event_t;;
|
||||
@ -114,7 +113,7 @@ void tcd_event_rx_complete(uint8_t rhport, uint16_t xferred_bytes, uint8_t resul
|
||||
tcd_event_t event = {
|
||||
.rhport = rhport,
|
||||
.event_id = TCD_EVENT_RX_COMPLETE,
|
||||
.rx_complete = {
|
||||
.xfer_complete = {
|
||||
.xferred_bytes = xferred_bytes,
|
||||
.result = result
|
||||
}
|
||||
@ -128,7 +127,7 @@ void tcd_event_tx_complete(uint8_t rhport, uint16_t xferred_bytes, uint8_t resul
|
||||
tcd_event_t event = {
|
||||
.rhport = rhport,
|
||||
.event_id = TCD_EVENT_TX_COMPLETE,
|
||||
.rx_complete = {
|
||||
.xfer_complete = {
|
||||
.xferred_bytes = xferred_bytes,
|
||||
.result = result
|
||||
}
|
||||
|
180
src/typec/utcd.c
180
src/typec/utcd.c
@ -52,8 +52,12 @@ static bool _utcd_inited = false;
|
||||
static bool _port_inited[TUP_TYPEC_RHPORTS_NUM];
|
||||
|
||||
// Max possible PD size is 262 bytes
|
||||
static uint8_t _rx_buf[262] TU_ATTR_ALIGNED(4);
|
||||
static uint8_t _tx_buf[100] TU_ATTR_ALIGNED(4);
|
||||
static uint8_t _rx_buf[64] TU_ATTR_ALIGNED(4);
|
||||
static uint8_t _tx_buf[64] TU_ATTR_ALIGNED(4);
|
||||
|
||||
bool utcd_msg_send(uint8_t rhport, pd_header_t const* header, void const* data);
|
||||
bool parse_msg_data(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end);
|
||||
bool parse_msg_control(uint8_t rhport, pd_header_t const* header);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
@ -79,6 +83,7 @@ bool tuc_init(uint8_t rhport, uint32_t port_type) {
|
||||
}
|
||||
|
||||
TU_LOG_UTCD("UTCD init on port %u\r\n", rhport);
|
||||
TU_LOG_INT(UTCD_DEBUG, sizeof(tcd_event_t));
|
||||
|
||||
TU_ASSERT(tcd_init(rhport, port_type));
|
||||
tcd_int_enable(rhport);
|
||||
@ -87,6 +92,65 @@ bool tuc_init(uint8_t rhport, uint32_t port_type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void tuc_task_ext(uint32_t timeout_ms, bool in_isr) {
|
||||
(void) in_isr; // not implemented yet
|
||||
|
||||
// Skip if stack is not initialized
|
||||
if (!_utcd_inited) return;
|
||||
|
||||
// Loop until there is no more events in the queue
|
||||
while (1) {
|
||||
tcd_event_t event;
|
||||
if (!osal_queue_receive(_utcd_q, &event, timeout_ms)) return;
|
||||
|
||||
switch (event.event_id) {
|
||||
case TCD_EVENT_CC_CHANGED:
|
||||
break;
|
||||
|
||||
case TCD_EVENT_RX_COMPLETE:
|
||||
// TODO process message here in ISR, move to thread later
|
||||
if (event.xfer_complete.result == XFER_RESULT_SUCCESS) {
|
||||
pd_header_t const* header = (pd_header_t const*) _rx_buf;
|
||||
|
||||
if (header->n_data_obj == 0) {
|
||||
parse_msg_control(event.rhport, header);
|
||||
|
||||
}else {
|
||||
uint8_t const* p_end = _rx_buf + event.xfer_complete.xferred_bytes;
|
||||
uint8_t const * dobj = _rx_buf + sizeof(pd_header_t);
|
||||
|
||||
parse_msg_data(event.rhport, header, dobj, p_end);
|
||||
}
|
||||
}
|
||||
|
||||
// prepare for next message
|
||||
tcd_msg_receive(event.rhport, _rx_buf, sizeof(_rx_buf));
|
||||
break;
|
||||
|
||||
case TCD_EVENT_TX_COMPLETE:
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool parse_msg_data(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end) {
|
||||
if (tuc_pd_data_received_cb) {
|
||||
tuc_pd_data_received_cb(rhport, header, dobj, p_end);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_msg_control(uint8_t rhport, pd_header_t const* header) {
|
||||
if (tuc_pd_control_received_cb) {
|
||||
tuc_pd_control_received_cb(rhport, header);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
@ -104,94 +168,18 @@ bool utcd_msg_send(uint8_t rhport, pd_header_t const* header, void const* data)
|
||||
return tcd_msg_send(rhport, _tx_buf, sizeof(pd_header_t) + n_data_obj * 4);
|
||||
}
|
||||
|
||||
bool parse_message(uint8_t rhport, uint8_t const* buf, uint16_t len) {
|
||||
(void) rhport;
|
||||
uint8_t const* p_end = buf + len;
|
||||
pd_header_t const* header = (pd_header_t const*) buf;
|
||||
uint8_t const * ptr = buf + sizeof(pd_header_t);
|
||||
bool tuc_msg_request(uint8_t rhport, void const* rdo) {
|
||||
pd_header_t const header = {
|
||||
.msg_type = PD_DATA_REQUEST,
|
||||
.data_role = PD_DATA_ROLE_UFP,
|
||||
.specs_rev = PD_REV_30,
|
||||
.power_role = PD_POWER_ROLE_SINK,
|
||||
.msg_id = 0,
|
||||
.n_data_obj = 1,
|
||||
.extended = 0,
|
||||
};
|
||||
|
||||
if (header->n_data_obj == 0) {
|
||||
// control message
|
||||
switch (header->msg_type) {
|
||||
case PD_CTRL_GOOD_CRC:
|
||||
break;
|
||||
|
||||
case PD_CTRL_ACCEPT:
|
||||
break;
|
||||
|
||||
case PD_CTRL_REJECT:
|
||||
break;
|
||||
|
||||
case PD_CTRL_PS_READY:
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
} else {
|
||||
// data message
|
||||
switch (header->msg_type) {
|
||||
case PD_DATA_SOURCE_CAP: {
|
||||
// Examine source capability and select a suitable PDO (starting from 1 with safe5v)
|
||||
uint8_t obj_pos = 1;
|
||||
|
||||
for(size_t i=0; i<header->n_data_obj; i++) {
|
||||
TU_VERIFY(ptr < p_end);
|
||||
uint32_t const pdo = tu_le32toh(tu_unaligned_read32(ptr));
|
||||
|
||||
switch ((pdo >> 30) & 0x03ul) {
|
||||
case PD_PDO_TYPE_FIXED: {
|
||||
pd_pdo_fixed_t const* fixed = (pd_pdo_fixed_t const*) &pdo;
|
||||
TU_LOG3("[Fixed] %u mV %u mA\r\n", fixed->voltage_50mv*50, fixed->current_max_10ma*10);
|
||||
break;
|
||||
}
|
||||
|
||||
case PD_PDO_TYPE_BATTERY:
|
||||
break;
|
||||
|
||||
case PD_PDO_TYPE_VARIABLE:
|
||||
break;
|
||||
|
||||
case PD_PDO_TYPE_APDO:
|
||||
break;
|
||||
}
|
||||
|
||||
ptr += 4;
|
||||
}
|
||||
|
||||
// Send request with selected PDO position as response to Source Cap
|
||||
pd_rdo_fixed_variable_t rdo = {
|
||||
.current_extremum_10ma = 50, // max 500mA
|
||||
.current_operate_10ma = 30, // 300mA
|
||||
.reserved = 0,
|
||||
.epr_mode_capable = 0,
|
||||
.unchunked_ext_msg_support = 0,
|
||||
.no_usb_suspend = 0,
|
||||
.usb_comm_capable = 1,
|
||||
.capability_mismatch = 0,
|
||||
.give_back_flag = 0, // exteremum is max
|
||||
.object_position = obj_pos,
|
||||
};
|
||||
|
||||
pd_header_t const req_header = {
|
||||
.msg_type = PD_DATA_REQUEST,
|
||||
.data_role = PD_DATA_ROLE_UFP,
|
||||
.specs_rev = PD_REV_20,
|
||||
.power_role = PD_POWER_ROLE_SINK,
|
||||
.msg_id = 0,
|
||||
.n_data_obj = 1,
|
||||
.extended = 0,
|
||||
};
|
||||
|
||||
utcd_msg_send(rhport, &req_header, &rdo);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return utcd_msg_send(rhport, &header, rdo);
|
||||
}
|
||||
|
||||
void tcd_event_handler(tcd_event_t const * event, bool in_isr) {
|
||||
@ -199,25 +187,17 @@ void tcd_event_handler(tcd_event_t const * event, bool in_isr) {
|
||||
switch(event->event_id) {
|
||||
case TCD_EVENT_CC_CHANGED:
|
||||
if (event->cc_changed.cc_state[0] || event->cc_changed.cc_state[1]) {
|
||||
// Attach
|
||||
// Attach, start receiving
|
||||
tcd_msg_receive(event->rhport, _rx_buf, sizeof(_rx_buf));
|
||||
}else {
|
||||
// Detach
|
||||
}
|
||||
break;
|
||||
|
||||
case TCD_EVENT_RX_COMPLETE:
|
||||
// TODO process message here in ISR, move to thread later
|
||||
if (event->rx_complete.result == XFER_RESULT_SUCCESS) {
|
||||
parse_message(event->rhport, _rx_buf, event->rx_complete.xferred_bytes);
|
||||
}
|
||||
|
||||
// start new rx
|
||||
tcd_msg_receive(event->rhport, _rx_buf, sizeof(_rx_buf));
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
osal_queue_send(_utcd_q, event, in_isr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
@ -52,6 +52,17 @@ bool tuc_init(uint8_t rhport, uint32_t port_type);
|
||||
// Check if typec port is initialized
|
||||
bool tuc_inited(uint8_t rhport);
|
||||
|
||||
// Task function should be called in main/rtos loop, extended version of tud_task()
|
||||
// - timeout_ms: millisecond to wait, zero = no wait, 0xFFFFFFFF = wait forever
|
||||
// - in_isr: if function is called in ISR
|
||||
void tuc_task_ext(uint32_t timeout_ms, bool in_isr);
|
||||
|
||||
// Task function should be called in main/rtos loop
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void tuc_task (void) {
|
||||
tuc_task_ext(UINT32_MAX, false);
|
||||
}
|
||||
|
||||
#ifndef _TUSB_TCD_H_
|
||||
extern void tcd_int_handler(uint8_t rhport);
|
||||
#endif
|
||||
@ -59,10 +70,19 @@ extern void tcd_int_handler(uint8_t rhport);
|
||||
// Interrupt handler, name alias to TCD
|
||||
#define tuc_int_handler tcd_int_handler
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
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);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool tuc_msg_request(uint8_t rhport, void const* rdo);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user