aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKing Kévin <kingkevin@cuvoodoo.info>2020-03-01 23:22:49 +0100
committerKing Kévin <kingkevin@cuvoodoo.info>2020-03-01 23:22:49 +0100
commit9d7e4940e9dd8cfb53adeda65f969f6262601fde (patch)
tree084b4036408f1e7213a490ee9907d5e48b47f7bd
parent0c5f5e8c2dde9c644d4a5dc30f0d189f63d44470 (diff)
application: add eMrker read outusb_cable_tester
-rw-r--r--application.c200
1 files changed, 188 insertions, 12 deletions
diff --git a/application.c b/application.c
index 7291e15..360146b 100644
--- a/application.c
+++ b/application.c
@@ -50,6 +50,9 @@
#include "oled_text.h" // OLED utilities to display text
#include "usb_fusb302.h" // USB-C controller utilities
+/* external library */
+#include "usb_pd.h" // USB Power Delivery definitions
+
/** watchdog period in ms */
#define WATCHDOG_PERIOD 10000
@@ -1235,6 +1238,94 @@ static void command_connections(void* argument)
}
}
+/** print discovery identity response (e.g. eMarker information)
+ * param[in] packet FUSB302 packet containing VDM information
+ */
+static void print_emarker(uint8_t* packet)
+{
+ const uint16_t header = (packet[2] << 8) + packet[1];
+ if (0 == PD_HEADER_CNT(header)) { // it's a control packet, not a data packet
+ return;
+ }
+ if (PD_DATA_VENDOR_DEF != PD_HEADER_TYPE(header)) { // not a VDM message
+ return;
+ }
+
+ // get objects
+ uint32_t objects[7]; // maximum message length
+ for (uint8_t i = 0; i < PD_HEADER_CNT(header); i++) {
+ objects[i] = (packet[i * 4 + 3 + 3] << 24) + (packet[i * 4 + 3 + 2] << 16) + (packet[i * 4 + 3 + 1] << 8) + (packet[i * 4 + 3 + 0] << 0);
+ }
+
+ puts("cable eMarker attributes:\n");
+ // decode some messages
+ const uint32_t vdm_header = objects[0];
+ if (vdm_header & VDO_SVDM_TYPE && VDO_CMDT(CMDT_RSP_ACK) == (vdm_header & VDO_CMDT_MASK) && CMD_DISCOVER_IDENT == (vdm_header & 0x1f)) { // we have a discover identity response
+ if (PD_HEADER_CNT(header) > 1) { // ID Header VDO (6.4.4.3.1.1)
+ //printf("- host %s enumerate\n", (objects[1] & (1 << 31)) ? "can" : "can't");
+ //printf("- device %s be enumerated\n", (objects[1] & (1 << 30)) ? "can" : "can't");
+ if (PD_HEADER_PROLE(header)) { // this is a plug
+ switch (PD_IDH_PTYPE(objects[1])) {
+ case 3:
+ puts("- cable: passive\n");
+ break;
+ case 4:
+ puts("- cable: active\n");
+ break;
+ default:
+ break;
+ }
+ }
+ printf("- VID: %04x\n", PD_IDH_VID(objects[1]));
+ }
+ if (PD_HEADER_CNT(header) > 2) { // Cert Stat VDO (6.4.4.3.1.2)
+ //printf("- cert stat: %08x\n", objects[2]);
+ }
+ if (PD_HEADER_CNT(header) > 3) { // Product VDO (6.4.4.3.1.3)
+ //printf("- product ID: %04x, bcdDevice: %04x\n", objects[3] >> 16, objects[3] & 0xffff);
+ }
+ if (PD_HEADER_CNT(header) > 3 && PD_HEADER_PROLE(header) && 3 == PD_IDH_PTYPE(objects[1])) { // Passive Cable VDO (6.4.4.3.1.4)
+ union cable_vdo cable;
+ memset(&cable, 0, sizeof(cable));
+ cable.raw_value = objects[4];
+ printf("- HW version: %u\n", cable.p_rev30.hw_version);
+ printf("- FW version: %u\n", cable.p_rev30.fw_version);
+ printf("- cable length: ~%um\n", ((cable.raw_value >> 13) & 0x7));
+ printf("- VCONN: %srequired\n", ((cable.raw_value >> 11) & 0x3) ? "" : "not ");
+ printf("- maximum VBUS voltage: %uV\n", ((cable.raw_value >> 9) & 0x3) * 10 + 20);
+ puts("- maximum VBUS current: ");
+ switch (((cable.raw_value >> 5) & 0x3)) {
+ case 1:
+ putc('3');
+ break;
+ case 2:
+ putc('5');
+ break;
+ default:
+ putc('?');
+ break;
+ }
+ puts("A\n");
+ puts("- SuperSpeed: USB ");
+ switch (cable.p_rev30.ss) {
+ case 0:
+ puts("2.0");
+ break;
+ case 1:
+ puts("3.2 Gen 1");
+ break;
+ case 2:
+ puts("3.2 Gen 2");
+ break;
+ default:
+ puts("???");
+ break;
+ }
+ putc('\n');
+ }
+ }
+}
+
/** test USB-C plug
* @param[in] argument no argument required
*/
@@ -1324,12 +1415,14 @@ static void command_cplug(void* argument)
printf("- CC2 %sconnected to GND (", cc2 ? "" : "not ");
print_connection(&cc2_connection);
puts(")\n");
- if (cc1_connection.tx_drive_pull && cc1_connection.rx_pull_float && cc2_connection.tx_drive_pull && cc2_connection.rx_pull_float) {
- puts("> powered cable to be connected to a sink on the other end (B, mini-B, or micro-B plug)\n");
- } else if ((cc1_connection.tx_drive_pull && cc1_connection.rx_pull_float) || (cc2_connection.tx_drive_pull && cc2_connection.rx_pull_float)) {
- puts("> powered cable, or to be connected to a sink on the other end (B, mini-B, or micro-B plug)\n");
- } else {
- puts("> unpowered cable\n");
+ if (gnd_all || vbus_all || gnd_any || vbus_any) {
+ if (cc1_connection.tx_drive_pull && cc1_connection.rx_pull_float && cc2_connection.tx_drive_pull && cc2_connection.rx_pull_float) {
+ puts("> powered cable to be connected to a sink on the other end (B, mini-B, or micro-B plug)\n");
+ } else if ((cc1_connection.tx_drive_pull && cc1_connection.rx_pull_float) || (cc2_connection.tx_drive_pull && cc2_connection.rx_pull_float)) {
+ puts("> powered cable, or to be connected to a sink on the other end (B, mini-B, or micro-B plug)\n");
+ } else {
+ puts("> unpowered cable\n");
+ }
}
// check if it should be connected to a source
cc1 = usb_cables_test_pins(&usb_pins[connector->pins[5]], &usb_pins[connector->pins[4]], &cc1_connection); // A5 CC1 - A4 VBUS
@@ -1340,10 +1433,12 @@ static void command_cplug(void* argument)
printf("- CC2 %sconnected to VBUS (", cc2 ? "" : "not ");
print_connection(&cc2_connection);
puts(")\n");
- if (cc1 || cc2) {
- puts("> to be connected to a source on the other end (A plug)\n");
- } else {
- puts("> not to be connected to a source on the other end (A plug)\n");
+ if (gnd_all || vbus_all || gnd_any || vbus_any) {
+ if (cc1 || cc2) {
+ puts("> to be connected to a source on the other end (A plug)\n");
+ } else {
+ puts("> not to be connected to a source on the other end (A plug)\n");
+ }
}
// find out if a resistor is present using USB-C controller
if (present_fusb302 && USB_CONNECTOR_C_DEVICE == connectors[connector_id]) { // HW v1 (modified for a v2 prototype) has only a FUSB302 on the C device port
@@ -1361,6 +1456,7 @@ static void command_cplug(void* argument)
gpio_set_mode(pin.port, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, pin.pin);
}
// figure out resistors on CC lines
+ uint8_t cc_pd = 0; // line used for PD communication
for (uint8_t cc = 1; cc < 3; cc++) {
const char* r_values[] = {"short to ground", "Ra", "Rd", "Rp", "open"};
int16_t r = usb_fusb302_r(cc);
@@ -1372,13 +1468,93 @@ static void command_cplug(void* argument)
}
putc('\n');
if (1 == r) {
- printf("> powered cable (CC%u is VCONN)\n", (1 == cc) ? 2 : 1);
+ printf("> powered cable (CC%u is CC, CC%u is VCONN)\n", (1 == cc) ? 2 : 1, cc);
+ cc_pd = ((1 == cc) ? 2 : 1); // remember this is the CC line to communicate with eMarker
} else if (2 == r) {
puts("> to be connected to a sink on the other end (B, mini-B, or micro-B plug)\n");
} else if (3 == r) {
puts("> to be connected to a source on the other end (A plug)\n");
}
}
+ if (cc_pd) { // read cable eMarker
+ uint8_t stage = 0;
+ int16_t rc = usb_fusb302_pd(cc_pd); // configure CC channel for PD communication (also flushes data)
+ if (rc < 0) {
+ stage = 1;
+ goto pd_end;
+ }
+ rc = usb_fusb302_discover_identity_request(); // send discover identity request
+ if (rc < 0) {
+ stage = 2;
+ goto pd_end;
+ }
+ sleep_ms(2); // wait tReceive = 1.1 ms for goodCRC response (PD3.0 section 6.6.1)
+ bool expected_message = false;
+ uint8_t packet[35];
+ while (!expected_message) { // wait got goodCRC
+ // I don't know why, after the first this action is called, the TX packet is also in the RX FIFO
+ rc = usb_fusb302_packet_read(packet);
+ if (0 == rc) { // RX FIFO is empty
+ stage = 3;
+ goto pd_end;
+ } else if (rc < 0) {
+ stage = 4;
+ goto pd_end;
+ }
+ if (6 != ((packet[0] >> 5) & 0x7)) { // not a SOP' response
+ continue;
+ }
+ uint16_t header = *(uint16_t*)(&packet[1]);
+ if (0 != PD_HEADER_CNT(header)) { // not a control message
+ continue;
+ }
+ if (PD_CTRL_GOOD_CRC != PD_HEADER_TYPE(header)) { // not a goodCRC message
+ continue;
+ }
+ expected_message = true;
+ }
+ if (!usb_fusb302_packet_checksum(packet)) { // verify CRC
+ stage = 5;
+ goto pd_end;
+ }
+ sleep_ms(15); // wait tReceiverResponse = 15 ms for request response (PD3.0 section 6.6.2)
+ expected_message = false;
+ while (!expected_message) { // wait got identity response
+ // I don't know why, after the first this action is called, the TX packet is also in the RX FIFO
+ rc = usb_fusb302_packet_read(packet);
+ if (0 == rc) { // RX FIFO is empty
+ stage = 6;
+ goto pd_end;
+ } else if (rc < 0) {
+ stage = 7;
+ goto pd_end;
+ }
+ if (6 != ((packet[0] >> 5) & 0x7)) { // not a SOP' response
+ continue;
+ }
+ uint16_t header = *(uint16_t*)(&packet[1]);
+ if (0 == PD_HEADER_CNT(header)) { // not a data message
+ continue;
+ }
+ if (PD_DATA_VENDOR_DEF != PD_HEADER_TYPE(header)) { // not a VDM message
+ continue;
+ }
+ expected_message = true;
+ }
+ if (!usb_fusb302_packet_checksum(packet)) { // verify CRC
+ stage = 8;
+ goto pd_end;
+ }
+pd_end:
+ if (0 == stage) {
+ print_emarker(packet);
+ sleep_ms(2); // wait a bit for the goodCRC to be received by the eMarker
+ } else {
+ //puts("could not read eMarker\n");
+ printf("could not read eMarker (stage=%u, error=%d)\n", stage, rc);
+ }
+ usb_fusb302_disconnect(); // remove all CC connections
+ }
// put ground back to floating
usb_cables_pins_float(); // not the most efficient way, but time is not critical
}
@@ -1390,7 +1566,7 @@ static void command_cplug(void* argument)
if (NULL == c1 || NULL == c2) {
return;
}
- puts("cable interconnection\n");
+ puts("cable interconnection (C host to C device)\n");
struct usb_connection_t connection;
bool connected;
connected = usb_cables_test_pins(&usb_pins[c1->pins[5]], &usb_pins[c2->pins[5]], &connection); // A5 CC1 - A5 CC1