stm32f1/usb_cables.c

886 lines
22 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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 <http://www.gnu.org/licenses/>.
*
*/
/** USB cable definitions and utilities
* @file
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2019
*/
/* standard libraries */
#include <stdint.h> // standard integer types
#include <string.h> // string utilities
/* STM32 (including CM3) libraries */
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
#include <libopencm3/stm32/gpio.h> // 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;
}