/* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /** USB cable definitions and utilities * @file * @author King Kévin * @date 2019 */ /* standard libraries */ #include // standard integer types #include // string utilities /* STM32 (including CM3) libraries */ #include // Cortex M3 utilities #include // general purpose input output library /* own libraries */ #include "global.h" // board definitions #include "print.h" // printing utilities #include "usb_cables.h" // own definitions /* USB connectors */ /** USB type A connector (host side) */ static const struct usb_pin_t usb_host_a_pins[] = { { .name = "shield", .port = GPIOD, .pin = GPIO0, }, { .name = "VBUS", .port = GPIOC, .pin = GPIO12, }, { .name = "D-", .port = GPIOA, .pin = GPIO15, }, { .name = "D+", .port = GPIOG, .pin = GPIO6, }, { .name = "GND", .port = GPIOG, .pin = GPIO2, }, { .name = "SSRX−", .port = GPIOC, .pin = GPIO11, }, { .name = "SSRX+", .port = GPIOC, .pin = GPIO10, }, { .name = "GND_DRAIN", .port = GPIOG, .pin = GPIO8, }, { .name = "SSTX-", .port = GPIOG, .pin = GPIO4, }, { .name = "SSTX+", .port = GPIOD, .pin = GPIO14, }, }; /** USB-C connector ("host" side) */ static const struct usb_pin_t usb_host_c_pins[] = { { .name = "shield", .port = GPIOG, .pin = GPIO13, }, { .name = "GND-A1", .port = GPIOD, .pin = GPIO15, }, { .name = "SSTX+1", .port = GPIOG, .pin = GPIO3, }, { .name = "SSTX-1", .port = GPIOG, .pin = GPIO5, }, { .name = "VBUS-A4", .port = GPIOG, .pin = GPIO7, }, { .name = "CC1", .port = GPIOC, .pin = GPIO6, }, { .name = "D+1", .port = GPIOC, .pin = GPIO8, }, { .name = "D-1", .port = GPIOA, .pin = GPIO8, }, { .name = "SBU1", .port = GPIOA, .pin = GPIO10, }, { .name = "VBUS-A9", .port = GPIOG, .pin = GPIO11, }, { .name = "SSRX-2", .port = GPIOA, .pin = GPIO9, }, { .name = "SSRX+2", .port = GPIOC, .pin = GPIO9, }, { .name = "GND-A12", .port = GPIOC, .pin = GPIO7, }, { .name = "GND-B12", .port = GPIOG, .pin = GPIO12, }, { .name = "SSRX+1", .port = GPIOG, .pin = GPIO14, }, { .name = "SSRX-1", .port = GPIOG, .pin = GPIO10, }, { .name = "VBUS-B9", .port = GPIOG, .pin = GPIO9, }, { .name = "SBU2", .port = GPIOG, .pin = GPIO15, }, { .name = "D-2", .port = GPIOD, .pin = GPIO6, }, { .name = "D+2", .port = GPIOD, .pin = GPIO7, }, { .name = "CC2", .port = GPIOD, .pin = GPIO1, }, { .name = "VBUS-B4", .port = GPIOD, .pin = GPIO5, }, { .name = "SSTX-2", .port = GPIOD, .pin = GPIO4, }, { .name = "SSTX+2", .port = GPIOD, .pin = GPIO2, }, { .name = "GND-B1", .port = GPIOD, .pin = GPIO3, }, }; /** USB type A connector (device) * @note type A should be a host side connector, but it is sometimes used on the device side, or to provide additional power on Y cables */ static const struct usb_pin_t usb_device_a_pins[] = { { .name = "shield", .port = GPIOB, .pin = GPIO3, }, { .name = "VBUS", .port = GPIOE, .pin = GPIO3, }, { .name = "D-", .port = GPIOE, .pin = GPIO1, }, { .name = "D+", .port = GPIOB, .pin = GPIO9, }, { .name = "GND", .port = GPIOB, .pin = GPIO5, }, { .name = "SSRX−", .port = GPIOE, .pin = GPIO2, }, { .name = "SSRX+", .port = GPIOC, .pin = GPIO13, }, { .name = "GND_DRAIN", .port = GPIOE, .pin = GPIO0, }, { .name = "SSTX-", .port = GPIOB, .pin = GPIO8, }, { .name = "SSTX+", .port = GPIOB, .pin = GPIO4, }, }; /** USB type B connector (device side) */ static const struct usb_pin_t usb_device_b_pins[] = { { .name = "shield", .port = GPIOF, .pin = GPIO1, }, { .name = "VBUS", .port = GPIOC, .pin = GPIO3, }, { .name = "D-", .port = GPIOA, .pin = GPIO0, }, { .name = "D+", .port = GPIOA, .pin = GPIO4, }, { .name = "GND", .port = GPIOC, .pin = GPIO0, }, { .name = "SSTX−", .port = GPIOA, .pin = GPIO2, }, { .name = "SSTX+", .port = GPIOA, .pin = GPIO1, }, { .name = "GND_DRAIN", .port = GPIOF, .pin = GPIO6, }, { .name = "SSRX-", .port = GPIOC, .pin = GPIO2, }, { .name = "SSRX+", .port = GPIOC, .pin = GPIO1, }, }; /** USB mini-B connector (device side) * @note this connector does not support USB 3.x */ static const struct usb_pin_t usb_device_minib_pins[] = { { .name = "shield", .port = GPIOC, .pin = GPIO14, }, { .name = "VBUS", .port = GPIOE, .pin = GPIO4, }, { .name = "D-", .port = GPIOE, .pin = GPIO5, }, { .name = "D+", .port = GPIOE, .pin = GPIO5, }, { .name = "ID", .port = GPIOF, .pin = GPIO0, }, { .name = "GND", .port = GPIOC, .pin = GPIO15, }, }; /** USB micro-B connector (device side) */ static const struct usb_pin_t usb_device_microb_pins[] = { { .name = "shield", .port = GPIOD, .pin = GPIO12, }, { .name = "VBUS", .port = GPIOD, .pin = GPIO11, }, { .name = "D-", .port = GPIOD, .pin = GPIO10, }, { .name = "D+", .port = GPIOD, .pin = GPIO9, }, { .name = "ID", .port = GPIOD, .pin = GPIO8, }, { .name = "GND", .port = GPIOB, .pin = GPIO15, }, { .name = "SSTX−", .port = GPIOB, .pin = GPIO14, }, { .name = "SSTX+", .port = GPIOB, .pin = GPIO13, }, { .name = "GND_DRAIN", .port = GPIOB, .pin = GPIO11, }, { .name = "SSRX-", .port = GPIOB, .pin = GPIO10, }, { .name = "SSRX+", .port = GPIOB, .pin = GPIO12, }, }; /** USB-C connector ("device" side) */ static const struct usb_pin_t usb_device_c_pins[] = { { .name = "shield", .port = GPIOE, .pin = GPIO11, }, { .name = "GND-A1", .port = GPIOF, .pin = GPIO13, }, { .name = "SSTX+1", .port = GPIOF, .pin = GPIO12, }, { .name = "SSTX-1", .port = GPIOF, .pin = GPIO11, }, { .name = "VBUS-A4", .port = GPIOB, .pin = GPIO2, }, { .name = "CC1", .port = GPIOB, .pin = GPIO1, }, { .name = "D+1", .port = GPIOB, .pin = GPIO0, }, { .name = "D-1", .port = GPIOC, .pin = GPIO5, }, { .name = "SBU1", .port = GPIOC, .pin = GPIO4, }, { .name = "VBUS-A9", .port = GPIOA, .pin = GPIO7, }, { .name = "SSRX-2", .port = GPIOA, .pin = GPIO6, }, { .name = "SSRX+2", .port = GPIOA, .pin = GPIO5, }, { .name = "GND-A12", .port = GPIOA, .pin = GPIO3, }, { .name = "GND-B12", .port = GPIOE, .pin = GPIO10, }, { .name = "SSRX+1", .port = GPIOE, .pin = GPIO12, }, { .name = "SSRX-1", .port = GPIOE, .pin = GPIO9, }, { .name = "VBUS-B9", .port = GPIOE, .pin = GPIO8, }, { .name = "SBU2", .port = GPIOE, .pin = GPIO13, }, { .name = "D-2", .port = GPIOG, .pin = GPIO1, }, { .name = "D+2", .port = GPIOE, .pin = GPIO7, }, { .name = "CC2", .port = GPIOE, .pin = GPIO14, }, { .name = "VBUS-B4", .port = GPIOG, .pin = GPIO0, }, { .name = "SSTX-2", .port = GPIOF, .pin = GPIO15, }, { .name = "SSTX+2", .port = GPIOE, .pin = GPIO15, }, { .name = "GND-B1", .port = GPIOF, .pin = GPIO14, }, }; /** Apple lightning connector (device side) * @note this is not strictly a USB connector */ static const struct usb_pin_t lighnting_device_pins[] = { { .name = "GND", .port = GPIOF, .pin = GPIO10, }, { .name = "L0p", .port = GPIOF, .pin = GPIO9, }, { .name = "L0n", .port = GPIOF, .pin = GPIO8, }, { .name = "ID0", .port = GPIOF, .pin = GPIO7, }, { .name = "PWR", .port = GPIOF, .pin = GPIO5, }, { .name = "L1n", .port = GPIOF, .pin = GPIO2, }, { .name = "L1p", .port = GPIOF, .pin = GPIO3, }, { .name = "ID1", .port = GPIOF, .pin = GPIO4, }, }; /** list of all connectors */ static const struct usb_connector_t usb_host_a_connector = { .name = "A", .host = true, .pins_nb = LENGTH(usb_host_a_pins), .pins = usb_host_a_pins, }; static const struct usb_connector_t usb_host_c_connector = { .name = "C", .host = true, .pins_nb = LENGTH(usb_host_c_pins), .pins = usb_host_c_pins, }; static const struct usb_connector_t usb_device_a_connector = { .name = "A", .host = false, .pins_nb = LENGTH(usb_device_a_pins), .pins = usb_device_a_pins, }; static const struct usb_connector_t usb_device_b_connector = { .name = "B", .host = false, .pins_nb = LENGTH(usb_device_b_pins), .pins = usb_device_b_pins, }; static const struct usb_connector_t usb_device_minib_connector = { .name = "mini-B", .host = false, .pins_nb = LENGTH(usb_device_minib_pins), .pins = usb_device_minib_pins, }; static const struct usb_connector_t usb_device_microb_connector = { .name = "micro-B", .host = false, .pins_nb = LENGTH(usb_device_microb_pins), .pins = usb_device_microb_pins, }; static const struct usb_connector_t usb_device_c_connector = { .name = "C", .host = false, .pins_nb = LENGTH(usb_device_c_pins), .pins = usb_device_c_pins, }; static const struct usb_connector_t lightning_device_connector = { .name = "lightning", .host = false, .pins_nb = LENGTH(lighnting_device_pins), .pins = lighnting_device_pins, }; const struct usb_connector_t usb_connectors[] = { usb_host_a_connector, usb_host_c_connector, usb_device_a_connector, usb_device_b_connector, usb_device_minib_connector, usb_device_microb_connector, usb_device_c_connector, lightning_device_connector, }; /** USB cable definitions */ static const struct usb_connector_t usb_a_a_power_unshielded_connectors[] = { usb_host_a_connector, usb_device_a_connector, }; static const struct usb_pin_t usb_a_a_power_unshielded_pins[][2] = { {usb_host_a_pins[1], usb_device_a_pins[1]}, {usb_host_a_pins[4], usb_device_a_pins[4]}, }; static const struct usb_connector_t usb_a_a_usb2_unshielded_connectors[] = { usb_host_a_connector, usb_device_a_connector, }; static const struct usb_pin_t usb_a_a_usb2_unshielded_pins[][2] = { {usb_host_a_pins[1], usb_device_a_pins[1]}, {usb_host_a_pins[2], usb_device_a_pins[2]}, {usb_host_a_pins[3], usb_device_a_pins[3]}, {usb_host_a_pins[4], usb_device_a_pins[4]}, }; const struct usb_cable_t usb_cables[] = { { .name = "A-A power only", .connectors_nb = LENGTH(usb_a_a_power_unshielded_connectors), .connectors = usb_a_a_power_unshielded_connectors, .pin_pairs_nb = LENGTH(usb_a_a_power_unshielded_pins), .pin_pairs = usb_a_a_power_unshielded_pins, }, { .name = "A-A USB2.0 shielded", .connectors_nb = LENGTH(usb_a_a_usb2_unshielded_connectors), .connectors = usb_a_a_usb2_unshielded_connectors, .pin_pairs_nb = LENGTH(usb_a_a_usb2_unshielded_pins), .pin_pairs = usb_a_a_usb2_unshielded_pins, }, }; void usb_cables_pins_float(const struct usb_connector_t* connector) { // input argument check if (NULL == connector) { return; } for (uint8_t pin = 0; pin < connector->pins_nb; pin++) { // go through every pin gpio_set_mode(connector->pins[pin].port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, connector->pins[pin].pin); // put pin to floating } } void usb_cables_connectors_float(const struct usb_connector_t* connectors, uint8_t connectors_nb) { if (NULL == connectors || 0 == connectors_nb) { return; } for (uint8_t connector = 0; connector < connectors_nb; connector++) { // go through every connector usb_cables_pins_float(&connectors[connector]); } } void usb_cables_check_intra(const struct usb_connector_t* connector) { // input argument check if (NULL == connector) { return; } usb_cables_pins_float(connector); // ensure we start in a safe state for (uint8_t pin_from = 0; pin_from < connector->pins_nb; pin_from++) { // test from every pin gpio_set_mode(connector->pins[pin_from].port, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, connector->pins[pin_from].pin); // we will drive the from pin for (uint8_t pin_to = 0; pin_to < connector->pins_nb; pin_to++) { // test to every pin (except itself) if (pin_to == pin_from) { continue; } gpio_set_mode(connector->pins[pin_to].port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, connector->pins[pin_to].pin); // we will read every to pin gpio_set(connector->pins[pin_to].port, connector->pins[pin_to].pin); // pull up gpio_clear(connector->pins[pin_from].port, connector->pins[pin_from].pin); // drive low if (gpio_get(connector->pins[pin_to].port, connector->pins[pin_to].pin) == gpio_get(connector->pins[pin_from].port, connector->pins[pin_from].pin)) { // if they are at the same level it means the from pin was able to drive low the pulled up to pin, thus they are connected printf("%s (%s) %s connected to %s (on low)\n", connector->name, connector->host ? "host" : "device", connector->pins[pin_from].name, connector->pins[pin_to].name); } gpio_clear(connector->pins[pin_to].port, connector->pins[pin_to].pin); // pull up gpio_set(connector->pins[pin_from].port, connector->pins[pin_from].pin); // drive low if (gpio_get(connector->pins[pin_to].port, connector->pins[pin_to].pin) == gpio_get(connector->pins[pin_from].port, connector->pins[pin_from].pin)) { // if they are at the same level it means the from pin was able to drive high the pulled down to pin, thus they are connected printf("%s (%s) %s connected to %s (on high)\n", connector->name, connector->host ? "host" : "device", connector->pins[pin_from].name, connector->pins[pin_to].name); } gpio_set_mode(connector->pins[pin_to].port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, connector->pins[pin_to].pin); // put pin back to safe floating state } gpio_set_mode(connector->pins[pin_from].port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, connector->pins[pin_from].pin); // put pin back to safe floating state } usb_cables_pins_float(connector); // go back to safe state } void usb_cables_check_inter(const struct usb_connector_t* connectors, uint8_t connectors_nb) { if (NULL == connectors || 0 == connectors_nb) { return; } usb_cables_connectors_float(connectors, connectors_nb); // ensure we start in a safe state for (uint8_t connector_from = 0; connector_from < connectors_nb; connector_from++) { // test from every connector for (uint8_t pin_from = 0; pin_from < connectors[connector_from].pins_nb; pin_from++) { // test from every pin gpio_set_mode(connectors[connector_from].pins[pin_from].port, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, connectors[connector_from].pins[pin_from].pin); // we will drive the from pin for (uint8_t connector_to = 0; connector_to < connectors_nb; connector_to++) { // test to every connector (except itself) if (connector_to == connector_from) { // don't test the connector itself since we already did this test continue; } for (uint8_t pin_to = 0; pin_to < connectors[connector_to].pins_nb; pin_to++) { // test to every pin (except itself) gpio_set_mode(connectors[connector_to].pins[pin_to].port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, connectors[connector_to].pins[pin_to].pin); // we will read every to pin gpio_set(connectors[connector_to].pins[pin_to].port, connectors[connector_to].pins[pin_to].pin); // pull up gpio_clear(connectors[connector_from].pins[pin_from].port, connectors[connector_from].pins[pin_from].pin); // drive low if (gpio_get(connectors[connector_to].pins[pin_to].port, connectors[connector_to].pins[pin_to].pin) == gpio_get(connectors[connector_from].pins[pin_from].port, connectors[connector_from].pins[pin_from].pin)) { // if they are at the same level it means the from pin was able to drive low the pulled up to pin, thus they are connected printf("%s (%s) %s connected to %s (%s) %s (on low)\n", connectors[connector_from].name, connectors[connector_from].host ? "host" : "device", connectors[connector_from].pins[pin_from].name, connectors[connector_to].name, connectors[connector_to].host ? "host" : "device", connectors[connector_to].pins[pin_to].name); } gpio_clear(connectors[connector_to].pins[pin_to].port, connectors[connector_to].pins[pin_to].pin); // pull down gpio_set(connectors[connector_from].pins[pin_from].port, connectors[connector_from].pins[pin_from].pin); // drive high if (gpio_get(connectors[connector_to].pins[pin_to].port, connectors[connector_to].pins[pin_to].pin) == gpio_get(connectors[connector_from].pins[pin_from].port, connectors[connector_from].pins[pin_from].pin)) { // if they are at the same level it means the from pin was able to drive high the pulled down to pin, thus they are connected printf("%s %s connected to %s %s (on high)\n", connectors[connector_from].name, connectors[connector_from].pins[pin_from].name, connectors[connector_to].name, connectors[connector_to].pins[pin_to].name); } gpio_set_mode(connectors[connector_to].pins[pin_to].port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, connectors[connector_to].pins[pin_to].pin); // put pin back to safe floating state } } gpio_set_mode(connectors[connector_from].pins[pin_from].port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, connectors[connector_from].pins[pin_from].pin); // put pin back to safe floating state } } usb_cables_connectors_float(connectors, connectors_nb); // go back to safe state } bool usb_cables_check_cable(const struct usb_cable_t* usb_cable, uint8_t* defined, uint8_t* undefined, uint8_t* disconnected, uint8_t* error) { *defined = 0; *undefined = 0; *disconnected = 0; *error = 0; if (NULL == usb_cable) { return false; } usb_cables_connectors_float(usb_cable->connectors, usb_cable->connectors_nb); // ensure we start in a safe state for (uint8_t connector_from = 0; connector_from < usb_cable->connectors_nb; connector_from++) { // test from every connector for (uint8_t pin_from = 0; pin_from < usb_cable->connectors[connector_from].pins_nb; pin_from++) { // test from every pin uint32_t from_port = usb_cable->connectors[connector_from].pins[pin_from].port; uint32_t from_pin = usb_cable->connectors[connector_from].pins[pin_from].pin; for (uint8_t connector_to = 0; connector_to < usb_cable->connectors_nb; connector_to++) { // test to every connector for (uint8_t pin_to = 0; pin_to < usb_cable->connectors[connector_to].pins_nb; pin_to++) { // test to every pin (except itself) uint32_t to_port = usb_cable->connectors[connector_to].pins[pin_to].port; uint32_t to_pin = usb_cable->connectors[connector_to].pins[pin_to].pin; if (from_port == to_port && from_pin == to_pin) { continue; } gpio_set_mode(to_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, to_pin); // we will read from this pin gpio_set(to_port, to_pin); // pull up gpio_clear(from_port, from_pin); // drive low gpio_set_mode(from_port, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, from_pin); // we will drive this pin bool from_to_low = (gpio_get(to_port, to_pin) == gpio_get(to_port, to_pin)); // if they are at the same level it means the from pin was able to drive low the pulled up to pin, thus they are connected gpio_set_mode(to_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, to_pin); // we will read from this pin gpio_clear(to_port, to_pin); // pull up gpio_set(from_port, from_pin); // drive low gpio_set_mode(from_port, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, from_pin); // we will drive this pin bool from_to_high = (gpio_get(to_port, to_pin) == gpio_get(to_port, to_pin)); // if they are at the same level it means the from pin was able to drive high the pulled low to pin, thus they are connected gpio_set_mode(from_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, from_pin); // we will read from this pin gpio_set(from_port, from_pin); // pull up gpio_clear(to_port, to_pin); // drive low gpio_set_mode(to_port, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, to_pin); // we will drive this pin bool to_from_low = (gpio_get(to_port, to_pin) == gpio_get(to_port, to_pin)); // if they are at the same level it means the to pin was able to drive low the pulled up from pin, thus they are connected gpio_set_mode(from_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, from_pin); // we will read from this pin gpio_clear(from_port, from_pin); // pull up gpio_set(to_port, to_pin); // drive low gpio_set_mode(to_port, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, to_pin); // we will drive this pin bool to_from_high = (gpio_get(to_port, to_pin) == gpio_get(to_port, to_pin)); // if they are at the same level it means the to pin was able to drive high the pulled low from pin, thus they are connected gpio_set_mode(from_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, from_pin); // put pin back to safe floating state gpio_set_mode(to_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, to_pin); // put pin back to safe floating state // calculate the connection rate (the booleans are only in case the want to debug) uint8_t connections = 0; if (from_to_low) connections++; if (from_to_high) connections++; if (to_from_low) connections++; if (to_from_high) connections++; // figure out if this connection pair is defined bool pair_defined = false; for (uint8_t pair = 0; pair < usb_cable->pin_pairs_nb; pair++) { if (usb_cable->pin_pairs[pair][0].port == from_port && usb_cable->pin_pairs[pair][0].pin == from_pin && usb_cable->pin_pairs[pair][1].port == to_port && usb_cable->pin_pairs[pair][1].pin == to_pin) { pair_defined = true; } if (usb_cable->pin_pairs[pair][1].port == from_port && usb_cable->pin_pairs[pair][1].pin == from_pin && usb_cable->pin_pairs[pair][0].port == to_port && usb_cable->pin_pairs[pair][0].pin == to_pin) { pair_defined = true; } } if (4 == connections) { // the connection is fine if (pair_defined) { (*defined)++; } else { (*undefined)++; } } else if (0 == connections) { // there is no connection if (pair_defined) { (*disconnected)++; } } else { // there is an error in the connection (*error)++; } } } } } usb_cables_connectors_float(usb_cable->connectors, usb_cable->connectors_nb); // ensure we return to a safe state return true; }