/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) * * 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. * */ #include #include #include #include "bsp/board_api.h" #include "tusb.h" //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF PROTOTYPES //--------------------------------------------------------------------+ // Voltage and current for selecting PDO // DANGEROUS: Please make sure your board can withstand the voltage and current // defined here. Otherwise, you may damage your board, smoke can come out #define VOLTAGE_MAX_MV 5000 // maximum voltage in mV #define CURRENT_MAX_MA 500 // maximum current in mA #define CURRENT_OPERATING_MA 300 // operating current in mA /* Blink pattern * - 250 ms : Type-C disconnected * - 1000 ms : Type-C connected */ enum { BLINK_DISCONNECTED = 250, BLINK_CONNECTED = 1000 }; static uint32_t blink_interval_ms = BLINK_CONNECTED; void typec_connect_task(void); void led_blinking_task(void); int main(void) { board_init(); board_led_write(true); tuc_init(0, TUSB_TYPEC_PORT_DISCONNECTED); while (1) { typec_connect_task(); led_blinking_task(); // tinyusb typec task tuc_task(); } } #ifdef ESP_PLATFORM void app_main(void) { main(); } #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 selected_pos = 1; bool voltage_available = false; for(size_t i=0; in_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; uint32_t const voltage_mv = fixed->voltage_50mv*50; uint32_t const current_ma = fixed->current_max_10ma*10; printf("[Fixed] PDO%"PRIu8" %"PRIu32" mV %"PRIu32" mA\r\n", i+1, voltage_mv, current_ma); if (voltage_mv <= VOLTAGE_MAX_MV) { voltage_available = true; if (current_ma >= CURRENT_MAX_MA) { // Found a suitable PDO selected_pos = i+1; } } 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 if (!voltage_available) { printf("No PDO within %"PRIu32" mV, skip request\r\n", (uint32_t) VOLTAGE_MAX_MV); break; } printf("Selected PDO %u\r\n", selected_pos); // Send request with selected PDO position as response to Source Cap pd_rdo_fixed_variable_t rdo = { .current_extremum_10ma = CURRENT_MAX_MA / 10, .current_operate_10ma = CURRENT_OPERATING_MA / 10, .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 = selected_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) { (void) rhport; 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; } //--------------------------------------------------------------------+ // TypeC CONNECT TASK //--------------------------------------------------------------------+ void typec_connect_task(void) { static uint32_t btn_prev = 0; static bool connected = false; uint32_t const btn = board_button_read(); if ((btn_prev == 0u) && (btn != 0u)) { bool const connect = !connected; if (connect && tuc_connect(0)) { connected = true; blink_interval_ms = BLINK_CONNECTED; printf("Type-C connect\r\n"); } else if (!connect && tuc_disconnect(0)) { connected = false; blink_interval_ms = BLINK_DISCONNECTED; printf("Type-C disconnect\r\n"); } } btn_prev = btn; } //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ void led_blinking_task(void) { static uint32_t start_ms = 0; static bool led_state = false; // Blink every interval ms if ( tusb_time_millis_api() - start_ms < blink_interval_ms) return; // not enough time start_ms += blink_interval_ms; board_led_write(led_state); led_state = 1 - led_state; // toggle }