886 lines
22 KiB
C
886 lines
22 KiB
C
/* 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;
|
||
}
|