text: /* Copyright 2019 The Chromium OS Authors. All rights reserved.
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   *
   * Test USB Protocol Layer module.
   */
  #include "common.h"
  #include "crc.h"
  #include "task.h"
  #include "tcpm.h"
  #include "test_util.h"
  #include "timer.h"
  #include "usb_emsg.h"
  #include "usb_pd_test_util.h"
  #include "usb_pd.h"
  #include "usb_pe_sm.h"
  #include "usb_prl_sm.h"
  #include "usb_sm_checks.h"
  #include "usb_tc_sm.h"
  #include "util.h"
  
  #define PORT0 0
  
  /*
   * These enum definitions are declared in usb_prl_sm and are private to that
   * file. If those definitions are re-ordered, then we need to update these
   * definitions (should be very rare).
   */
  enum usb_prl_tx_state {
  	PRL_TX_PHY_LAYER_RESET,
  	PRL_TX_WAIT_FOR_MESSAGE_REQUEST,
  	PRL_TX_LAYER_RESET_FOR_TRANSMIT,
  	PRL_TX_WAIT_FOR_PHY_RESPONSE,
  	PRL_TX_SRC_SOURCE_TX,
  	PRL_TX_SNK_START_AMS,
  	PRL_TX_SRC_PENDING,
  	PRL_TX_SNK_PENDING,
  	PRL_TX_DISCARD_MESSAGE,
  };
  
  enum usb_prl_hr_state {
  	PRL_HR_WAIT_FOR_REQUEST,
  	PRL_HR_RESET_LAYER,
  	PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE,
  	PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE,
  };
  
  enum usb_rch_state {
  	RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER,
  	RCH_PASS_UP_MESSAGE,
  	RCH_PROCESSING_EXTENDED_MESSAGE,
  	RCH_REQUESTING_CHUNK,
  	RCH_WAITING_CHUNK,
  	RCH_REPORT_ERROR,
  };
  
  enum usb_tch_state {
  	TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE,
  	TCH_WAIT_FOR_TRANSMISSION_COMPLETE,
  	TCH_CONSTRUCT_CHUNKED_MESSAGE,
  	TCH_SENDING_CHUNKED_MESSAGE,
  	TCH_WAIT_CHUNK_REQUEST,
  	TCH_MESSAGE_RECEIVED,
  	TCH_MESSAGE_SENT,
  	TCH_REPORT_ERROR,
  };
  
  /* Defined in implementation */
  enum usb_prl_tx_state prl_tx_get_state(const int port);
  enum usb_prl_hr_state prl_hr_get_state(const int port);
  enum usb_rch_state rch_get_state(const int port);
  enum usb_tch_state tch_get_state(const int port);
  
  #ifndef CONFIG_USB_PD_EXTENDED_MESSAGES
  enum usb_rch_state rch_get_state(const int port)
  {
  	return RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER;
  }
  #endif
  
  
  static uint32_t test_data[] = {
  	0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f,
  	0x10111213, 0x14151617, 0x1819a0b0, 0xc0d0e0f0,
  	0x20212223, 0x24252627, 0x28292a2b, 0x2c2d2e2f,
  	0x30313233, 0x34353637, 0x38393a3b, 0x3c3d3e3f,
  	0x40414243, 0x44454647, 0x48494a4b, 0x4c4d4e4f,
  	0x50515253, 0x54555657, 0x58595a5b, 0x5c5d5e5f,
  	0x60616263, 0x64656667, 0x68696a6b, 0x6c6d6e6f,
  	0x70717273, 0x74757677, 0x78797a7b, 0x7c7d7e7f,
  	0x80818283, 0x84858687, 0x88898a8b, 0x8c8d8e8f,
  	0x90919293, 0x94959697, 0x98999a9b, 0x9c9d9e9f,
  	0xa0a1a2a3, 0xa4a5a6a7, 0xa8a9aaab, 0xacadaeaf,
  	0xb0b1b2b3, 0xb4b5b6b7, 0xb8b9babb, 0xbcbdbebf,
  	0xc0c1c2c3, 0xc4c5c6c7, 0xc8c9cacb, 0xcccdcecf,
  	0xd0d1d2d3, 0xd4d5d6d7, 0xd8d9dadb, 0xdcdddedf,
  	0xe0e1e2e3, 0xe4e5e6e7, 0xe8e9eaeb, 0xecedeeef,
  	0xf0f1f2f3, 0xf4f5f6f7, 0xf8f9fafb, 0xfcfdfeff,
  	0x11223344
  };
  
  void pd_set_suspend(int port, int suspend)
  {
  }
  
  static struct pd_prl {
  	int rev;
  	int pd_enable;
  	enum pd_power_role power_role;
  	enum pd_data_role data_role;
  	int msg_tx_id;
  	int msg_rx_id;
  	enum tcpm_transmit_type sop;
  
  	int mock_pe_message_sent;
  	int mock_pe_error;
  	int mock_pe_hard_reset_sent;
  	int mock_pe_got_hard_reset;
  	int mock_pe_message_received;
  	int mock_got_soft_reset;
  	int mock_message_discard;
  } pd_port[CONFIG_USB_PD_PORT_MAX_COUNT];
  
  static void init_port(int port, int rev)
  {
  	pd_port[port].rev = rev;
  	pd_port[port].pd_enable = 0;
  	pd_port[port].power_role = PD_ROLE_SINK;
  	pd_port[port].data_role = PD_ROLE_UFP;
  	pd_port[port].msg_tx_id = 0;
  	pd_port[port].msg_rx_id = 0;
  
  	tcpm_init(port);
  	tcpm_set_polarity(port, 0);
  	tcpm_set_rx_enable(port, 0);
  }
  
  static inline uint32_t pending_pd_task_events(int port)
  {
  	return *task_get_event_bitmap(PD_PORT_TO_TASK_ID(port));
  }
  
  void inc_tx_id(int port)
  {
  	pd_port[port].msg_tx_id = (pd_port[port].msg_tx_id + 1) & 7;
  }
  
  void inc_rx_id(int port)
  {
  	pd_port[port].msg_rx_id = (pd_port[port].msg_rx_id + 1) % 7;
  }
  
  static int verify_goodcrc(int port, int role, int id)
  {
  	return pd_test_tx_msg_verify_sop(port) &&
  		pd_test_tx_msg_verify_short(port, PD_HEADER(PD_CTRL_GOOD_CRC,
  				role, role, id, 0, 0, 0)) &&
  		pd_test_tx_msg_verify_crc(port) &&
  		pd_test_tx_msg_verify_eop(port);
  }
  
  static void simulate_rx_msg(int port, uint16_t header, int cnt,
  							const uint32_t *data)
  {
  	int i;
  
  	pd_test_rx_set_preamble(port, 1);
  	pd_test_rx_msg_append_sop(port);
  	pd_test_rx_msg_append_short(port, header);
  
  	crc32_init();
  	crc32_hash16(header);
  
  	for (i = 0; i < cnt; ++i) {
  		pd_test_rx_msg_append_word(port, data[i]);
  		crc32_hash32(data[i]);
  	}
  
  	pd_test_rx_msg_append_word(port, crc32_result());
  
  	pd_test_rx_msg_append_eop(port);
  	pd_test_rx_msg_append_last_edge(port);
  
  	pd_simulate_rx(port);
  }
  
  static void simulate_goodcrc(int port, int role, int id)
  {
  	simulate_rx_msg(port, PD_HEADER(PD_CTRL_GOOD_CRC, role, role, id, 0,
  					pd_port[port].rev, 0), 0, NULL);
  }
  
  static void cycle_through_state_machine(int port, uint32_t num, uint32_t time)
  {
  	int i;
  
  	for (i = 0; i < num; i++) {
  		task_wake(PD_PORT_TO_TASK_ID(port));
  		task_wait_event(time);
  	}
  }
  
  static int simulate_request_chunk(int port, enum pd_data_msg_type msg_type,
  							int chunk_num, int len)
  {
  	uint16_t header = PD_HEADER(msg_type, pd_port[port].power_role,
  					pd_port[port].data_role,
  					pd_port[port].msg_rx_id,
  					1, pd_port[port].rev, 1);
  	uint32_t msg = PD_EXT_HEADER(chunk_num, 1, len);
  
  	simulate_rx_msg(port, header, 1, (const uint32_t *)&msg);
  	task_wait_event(30 * MSEC);
  
  	if (!verify_goodcrc(port, pd_port[port].data_role,
  						pd_port[port].msg_rx_id))
  		return 0;
  
  	return 1;
  }
  
  static int simulate_receive_ctrl_msg(int port, enum pd_ctrl_msg_type msg_type)
  {
  	uint16_t header = PD_HEADER(msg_type, pd_port[port].power_role,
  			pd_port[port].data_role, pd_port[port].msg_rx_id,
  			0, pd_port[port].rev, 0);
  
  	simulate_rx_msg(port, header, 0, NULL);
  	task_wait_event(30 * MSEC);
  
  	if (!verify_goodcrc(port, pd_port[port].data_role,
  						pd_port[port].msg_rx_id))
  		return 0;
  
  	return 1;
  }
  
  static int verify_data_reception(int port, uint16_t header, int len)
  {
  	int i;
  	int cnt = (len + 3) & ~3;
  
  	cycle_through_state_machine(port, 3, 10 * MSEC);
  
  	if (pd_port[port].mock_pe_error >= 0)
  		return 0;
  
  	if (!pd_port[port].mock_pe_message_received)
  		return 0;
  
  	if (rx_emsg[port].header != header)
  		return 0;
  
  	if (rx_emsg[port].len != cnt)
  		return 0;
  
  	for (i = 0; i < cnt; i++) {
  		if (i < len) {
  			if (rx_emsg[port].buf[i] !=
  					*((unsigned char *)test_data + i))
  				return 0;
  		} else {
  			if (rx_emsg[port].buf[i] != 0)
  				return 0;
  		}
  	}
  
  	return 1;
  }
  
  static int verify_chunk_data_reception(int port, uint16_t header, int len)
  {
  	int i;
  	uint8_t *td = (uint8_t *)test_data;
  
  	if (pd_port[port].mock_got_soft_reset) {
  		ccprintf("Got mock soft reset\n");
  		return 0;
  	}
  
  	if (!pd_port[port].mock_pe_message_received) {
  		ccprintf("No mock pe msg received\n");
  		return 0;
  	}
  
  	if (pd_port[port].mock_pe_error >= 0) {
  		ccprintf("Mock pe error (%d)\n", pd_port[port].mock_pe_error);
  		return 0;
  	}
  
  	if (rx_emsg[port].len != len) {
  		ccprintf("emsg len (%d) != 0\n", rx_emsg[port].len);
  		return 0;
  	}
  
  	for (i = 0; i < len; i++) {
  		if (rx_emsg[port].buf[i] != td[i]) {
  			ccprintf("emsg buf[%d] != td\n", i);
  			return 0;
  		}
  	}
  
  	return 1;
  }
  
  static int simulate_receive_data(int port, enum pd_data_msg_type msg_type,
  									int len)
  {
  	int i;
  	int nw = (len + 3) >> 2;
  	uint8_t td[28];
  	uint16_t header = PD_HEADER(msg_type, pd_port[port].power_role,
  		pd_port[port].data_role, pd_port[port].msg_rx_id,
  		nw, pd_port[port].rev, 0);
  
  	pd_port[port].mock_pe_error = -1;
  	pd_port[port].mock_pe_message_received = 0;
  	rx_emsg[port].header = 0;
  	rx_emsg[port].len = 0;
  	memset(rx_emsg[port].buf, 0, ARRAY_SIZE(rx_emsg[port].buf));
  
  	for (i = 0; i < 28; i++) {
  		if (i < len)
  			td[i] = *((uint8_t *)test_data + i);
  		else
  			td[i] = 0;
  	}
  
  	simulate_rx_msg(port, header, nw, (uint32_t *)td);
  	task_wait_event(30 * MSEC);
  
  	if (!verify_goodcrc(port, pd_port[port].data_role,
  						pd_port[port].msg_rx_id))
  		return 0;
  
  	inc_rx_id(port);
  
  	return verify_data_reception(port, header, len);
  }
  
  static int simulate_receive_extended_data(int port,
  					enum pd_data_msg_type msg_type, int len)
  {
  	int i;
  	int j;
  	int byte_len;
  	int nw;
  	int dsize;
  	uint8_t td[28];
  	int chunk_num = 0;
  	int data_offset = 0;
  	uint8_t *expected_data = (uint8_t *)test_data;
  	uint16_t header;
  
  	pd_port[port].mock_pe_error = -1;
  	pd_port[port].mock_pe_message_received = 0;
  	rx_emsg[port].header = 0;
  	rx_emsg[port].len = 0;
  	memset(rx_emsg[port].buf, 0, ARRAY_SIZE(rx_emsg[port].buf));
  
  	dsize = len;
  	for (j = 0; j < 10; j++) {
  		/* Let state machine settle before starting another round */
  		cycle_through_state_machine(port, 10, MSEC);
  
  		byte_len = len;
  		if (byte_len > PD_MAX_EXTENDED_MSG_CHUNK_LEN)
  			byte_len = PD_MAX_EXTENDED_MSG_CHUNK_LEN;
  
  		len -= PD_MAX_EXTENDED_MSG_CHUNK_LEN;
  
  		memset(td, 0, 28);
  		*(uint16_t *)td = PD_EXT_HEADER(chunk_num, 0, dsize);
  
  		for (i = 0; i < byte_len; i++)
  			td[i + 2] = *(expected_data + data_offset++);
  
  		nw = (byte_len + 2 + 3) >> 2;
  		header = PD_HEADER(msg_type, pd_port[port].power_role,
  			pd_port[port].data_role, pd_port[port].msg_rx_id,
  			nw, pd_port[port].rev, 1);
  
  		if (pd_port[port].mock_pe_error >= 0) {
  			ccprintf("Mock pe error (%d) iteration (%d)\n",
  				pd_port[port].mock_pe_error, j);
  			return 0;
  		}
  
  		if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES) &&
  				pd_port[port].mock_pe_message_received) {
  			ccprintf("Mock pe msg received iteration (%d)\n", j);
  			return 0;
  		}
  
  		if (rx_emsg[port].len != 0) {
  			ccprintf("emsg len (%d) != 0 iteration (%d)\n",
  				rx_emsg[port].len, j);
  			return 0;
  		}
  
  		simulate_rx_msg(port, header, nw, (uint32_t *)td);
  		cycle_through_state_machine(port, 1, MSEC);
  
  		if (!verify_goodcrc(port, pd_port[port].data_role,
  						pd_port[port].msg_rx_id)) {
  			ccprintf("Verify goodcrc bad iteration (%d)\n", j);
  			return 0;
  		}
  
  		cycle_through_state_machine(port, 1, MSEC);
  		inc_rx_id(port);
  
  		if (!IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) {
  			if (pd_port[port].mock_pe_message_received)
  				return 1;
  			return 0;
  		}
  
  		/*
  		 * If no more data, do expected to get a chunk request
  		 */
  		if (len <= 0)
  			break;
  
  		/*
  		 * We need to ensure that the TX event has been set, which may
  		 * require an extra cycle through the state machine
  		 */
  		if (!(PD_EVENT_TX & pending_pd_task_events(port)))
  			cycle_through_state_machine(port, 1, MSEC);
  
  		chunk_num++;
  
  		/* Test Request next chunk packet */
  		if (!pd_test_tx_msg_verify_sop(port)) {
  			ccprintf("Verify sop bad iteration (%d)\n", j);
  			return 0;
  		}
  
  		if (!pd_test_tx_msg_verify_short(port,
  				PD_HEADER(msg_type,
  				pd_port[port].power_role,
  				pd_port[port].data_role,
  				pd_port[port].msg_tx_id,
  				1, pd_port[port].rev, 1))) {
  			ccprintf("Verify msg short bad iteration (%d)\n", j);
  			return 0;
  		}
  
  		if (!pd_test_tx_msg_verify_word(port,
  				PD_EXT_HEADER(chunk_num, 1, 0))) {
  			ccprintf("Verify msg word bad iteration (%d)\n", j);
  			return 0;
  		}
  
  		if (!pd_test_tx_msg_verify_crc(port)) {
  			ccprintf("Verify msg crc bad iteration (%d)\n", j);
  			return 0;
  		}
  
  		if (!pd_test_tx_msg_verify_eop(port)) {
  			ccprintf("Verify msg eop bad iteration (%d)\n", j);
  			return 0;
  		}
  
  		cycle_through_state_machine(port, 1, MSEC);
  
  		/* Request next chunk packet was good. Send GoodCRC */
  		simulate_goodcrc(port, pd_port[port].power_role,
  					pd_port[port].msg_tx_id);
  
  		cycle_through_state_machine(port, 1, MSEC);
  
  		inc_tx_id(port);
  	}
  
  	cycle_through_state_machine(port, 1, MSEC);
  
  	return verify_chunk_data_reception(port, header, dsize);
  }
  
  static int verify_ctrl_msg_transmission(int port,
  						enum pd_ctrl_msg_type msg_type)
  {
  	if (!pd_test_tx_msg_verify_sop(port))
  		return 0;
  
  	if (!pd_test_tx_msg_verify_short(port,
  			PD_HEADER(msg_type, pd_port[port].power_role,
  			pd_port[port].data_role, pd_port[port].msg_tx_id, 0,
  			pd_port[port].rev, 0)))
  		return 0;
  
  	if (!pd_test_tx_msg_verify_crc(port))
  		return 0;
  
  	if (!pd_test_tx_msg_verify_eop(port))
  		return 0;
  
  	return 1;
  }
  
  static int simulate_send_ctrl_msg_request_from_pe(int port,
  	enum tcpm_transmit_type type, enum pd_ctrl_msg_type msg_type)
  {
  	pd_port[port].mock_got_soft_reset = 0;
  	pd_port[port].mock_pe_error = -1;
  	pd_port[port].mock_pe_message_sent = 0;
  	prl_send_ctrl_msg(port, type, msg_type);
  	cycle_through_state_machine(port, 1, MSEC);
  
  	return verify_ctrl_msg_transmission(port, msg_type);
  }
  
  static int verify_data_msg_transmission(int port,
  				enum pd_data_msg_type msg_type, int len)
  {
  	int i;
  	int num_words = (len + 3) >> 2;
  	int data_obj_in_bytes;
  	uint32_t td;
  
  	if (!pd_test_tx_msg_verify_sop(port))
  		return 0;
  
  	if (!pd_test_tx_msg_verify_short(port,
  			PD_HEADER(msg_type, pd_port[port].power_role,
  			pd_port[port].data_role, pd_port[port].msg_tx_id,
  			num_words, pd_port[port].rev, 0)))
  		return 0;
  
  	for (i = 0; i < num_words; i++) {
  		td = test_data[i];
  		data_obj_in_bytes = (i + 1) * 4;
  		if (data_obj_in_bytes > len) {
  			switch (data_obj_in_bytes - len) {
  			case 1:
  				td &= 0x00ffffff;
  				break;
  			case 2:
  				td &= 0x0000ffff;
  				break;
  			case 3:
  				td &= 0x000000ff;
  				break;
  			}
  		}
  
  		if (!pd_test_tx_msg_verify_word(port, td))
  			return 0;
  	}
  
  	if (!pd_test_tx_msg_verify_crc(port))
  		return 0;
  
  	if (!pd_test_tx_msg_verify_eop(port))
  		return 0;
  
  	return 1;
  }
  
  static int simulate_send_data_msg_request_from_pe(int port,
  	enum tcpm_transmit_type type, enum pd_ctrl_msg_type msg_type, int len)
  {
  	int i;
  	uint8_t *buf = tx_emsg[port].buf;
  	uint8_t *td = (uint8_t *)test_data;
  
  	pd_port[port].mock_got_soft_reset = 0;
  	pd_port[port].mock_pe_error = -1;
  	pd_port[port].mock_pe_message_sent = 0;
  
  	for (i = 0; i < len; i++)
  		buf[i] = td[i];
  
  	tx_emsg[port].len = len;
  
  	prl_send_data_msg(port, type, msg_type);
  	cycle_through_state_machine(port, 1, MSEC);
  
  	return verify_data_msg_transmission(port, msg_type, len);
  }
  
  static int verify_extended_data_msg_transmission(int port,
  			enum pd_data_msg_type msg_type, int len)
  {
  	int i;
  	int j;
  	int nw;
  	int byte_len;
  	int dsize;
  	uint32_t td;
  	uint8_t *expected_data = (uint8_t *)&test_data;
  	int data_offset = 0;
  	int chunk_number_to_send = 0;
  
  	dsize = len;
  
  	for (j = 0; j < 10; j++) {
  		byte_len = len;
  		if (byte_len > PD_MAX_EXTENDED_MSG_CHUNK_LEN)
  			byte_len = PD_MAX_EXTENDED_MSG_CHUNK_LEN;
  
  		nw = (byte_len + 2 + 3) >> 2;
  
  		if (!pd_test_tx_msg_verify_sop(port)) {
  			ccprintf("failed tx sop; iteration (%d)\n", j);
  			return 0;
  		}
  
  		if (!pd_test_tx_msg_verify_short(port,
  				PD_HEADER(msg_type, pd_port[port].power_role,
  				pd_port[port].data_role,
  				pd_port[port].msg_tx_id,
  				nw, pd_port[port].rev, 1))) {
  			ccprintf("failed tx short\n");
  			return 0;
  		}
  		td = PD_EXT_HEADER(chunk_number_to_send, 0, dsize);
  		td |= *(expected_data + data_offset++) << 16;
  		td |= *(expected_data + data_offset++) << 24;
  
  		if (byte_len == 1)
  			td &= 0x00ffffff;
  
  		if (!pd_test_tx_msg_verify_word(port, td)) {
  			ccprintf("failed tx word\n");
  			return 0;
  		}
  
  		byte_len -= 2;
  
  		if (byte_len > 0) {
  			nw = (byte_len + 3) >> 2;
  			for (i = 0; i < nw; i++) {
  				td = *(expected_data + data_offset++) << 0;
  				td |= *(expected_data +	data_offset++) << 8;
  				td |= *(expected_data +	data_offset++) << 16;
  				td |= *(expected_data +	data_offset++) << 24;
  
  				switch (byte_len) {
  				case 3:
  					td &= 0x00ffffff;
  					break;
  				case 2:
  					td &= 0x0000ffff;
  					break;
  				case 1:
  					td &= 0x000000ff;
  					break;
  				}
  
  				if (!pd_test_tx_msg_verify_word(port, td))
  					return 0;
  				byte_len -= 4;
  			}
  		}
  
  		if (!pd_test_tx_msg_verify_crc(port)) {
  			ccprintf("failed tx crc\n");
  			return 0;
  		}
  
  		if (!pd_test_tx_msg_verify_eop(port)) {
  			ccprintf("failed tx eop\n");
  			return 0;
  		}
  
  		cycle_through_state_machine(port, 1, MSEC);
  
  		/* Send GoodCRC */
  		simulate_goodcrc(port, pd_port[port].power_role,
  						pd_port[port].msg_tx_id);
  		cycle_through_state_machine(port, 1, MSEC);
  		inc_tx_id(port);
  
  		len -= PD_MAX_EXTENDED_MSG_CHUNK_LEN;
  		if (len <= 0)
  			break;
  
  		chunk_number_to_send++;
  		/* Let state machine settle */
  		cycle_through_state_machine(port, 10, MSEC);
  		if (!simulate_request_chunk(port, msg_type,
  				chunk_number_to_send, dsize)) {
  			ccprintf("failed request chunk\n");
  			return 0;
  		}
  
  		cycle_through_state_machine(port, 1, MSEC);
  		inc_rx_id(port);
  	}
  
  	return 1;
  }
  
  static int simulate_send_extended_data_msg(int port,
  		enum tcpm_transmit_type type, enum pd_ctrl_msg_type msg_type,
  		int len)
  {
  	int i;
  	uint8_t *buf = tx_emsg[port].buf;
  	uint8_t *td = (uint8_t *)test_data;
  
  	memset(buf, 0, ARRAY_SIZE(tx_emsg[port].buf));
  	tx_emsg[port].len = len;
  
  	/* don't overflow buffer */
  	if (len > ARRAY_SIZE(tx_emsg[port].buf))
  		len = ARRAY_SIZE(tx_emsg[port].buf);
  
  	for (i = 0; i < len; i++)
  		buf[i] = td[i];
  
  	prl_send_ext_data_msg(port, type, msg_type);
  	cycle_through_state_machine(port, 1, MSEC);
  
  	return verify_extended_data_msg_transmission(port, msg_type,
  							len);
  }
  
  uint8_t tc_get_pd_enabled(int port)
  {
  	return pd_port[port].pd_enable;
  }
  
  static void enable_prl(int port, int en)
  {
  	tcpm_set_rx_enable(port, en);
  
  	pd_port[port].pd_enable = en;
  	pd_port[port].msg_tx_id = 0;
  	pd_port[port].msg_rx_id = 0;
  
  	/* Init PRL */
  	cycle_through_state_machine(port, 10, MSEC);
  
  	prl_set_rev(port, TCPC_TX_SOP, pd_port[port].rev);
  }
  
  enum pd_power_role pd_get_power_role(int port)
  {
  	return pd_port[port].power_role;
  }
  
  enum pd_data_role pd_get_data_role(int port)
  {
  	return pd_port[port].data_role;
  }
  
  enum pd_cable_plug tc_get_cable_plug(int port)
  {
  	return PD_PLUG_FROM_DFP_UFP;
  }
  
  void pe_report_error(int port, enum pe_error e, enum tcpm_transmit_type type)
  {
  	pd_port[port].mock_pe_error = e;
  	pd_port[port].sop = type;
  }
  
  void pe_report_discard(int port)
  {
  	pd_port[port].mock_message_discard = 1;
  }
  
  void pe_got_hard_reset(int port)
  {
  	pd_port[port].mock_pe_got_hard_reset = 1;
  }
  
  void pe_message_received(int port)
  {
  	pd_port[port].mock_pe_message_received = 1;
  }
  
  void pe_message_sent(int port)
  {
  	pd_port[port].mock_pe_message_sent = 1;
  }
  
  void pe_hard_reset_sent(int port)
  {
  	pd_port[port].mock_pe_hard_reset_sent = 1;
  }
  
  void pe_got_soft_reset(int port)
  {
  	pd_port[port].mock_got_soft_reset = 1;
  }
  
  bool pe_in_local_ams(int port)
  {
  	/* We will probably want to change this in the future */
  	return false;
  }
  
  static int test_prl_reset(void)
  {
  	int port = PORT0;
  
  	enable_prl(port, 1);
  
  	prl_reset(port);
  
  	TEST_EQ(prl_tx_get_state(port),
  			PRL_TX_WAIT_FOR_MESSAGE_REQUEST, "%u");
  	TEST_EQ(rch_get_state(port),
  			RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER, "%u");
  	TEST_EQ(tch_get_state(port),
  			TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE, "%u");
  	TEST_EQ(prl_hr_get_state(port),
  			PRL_HR_WAIT_FOR_REQUEST, "%u");
  	enable_prl(port, 0);
  
  	return EC_SUCCESS;
  }
  
  static int test_send_ctrl_msg(void)
  {
  	int i;
  	int port = PORT0;
  
  	enable_prl(port, 1);
  
  	/*
  	 * TEST: Control message transmission and tx_id increment
  	 */
  	for (i = 0; i < 10; i++) {
  		task_wake(PD_PORT_TO_TASK_ID(port));
  		task_wait_event(40 * MSEC);
  
  		TEST_EQ(prl_tx_get_state(port),
  				PRL_TX_WAIT_FOR_MESSAGE_REQUEST, "%u");
  
  		TEST_NE(simulate_send_ctrl_msg_request_from_pe(port,
  				TCPC_TX_SOP, PD_CTRL_ACCEPT), 0, "%d");
  
  		cycle_through_state_machine(port, 1, MSEC);
  
  		simulate_goodcrc(port, pd_port[port].power_role,
  						pd_port[port].msg_tx_id);
  		inc_tx_id(port);
  
  		/* Let statemachine settle */
  		cycle_through_state_machine(port, 10, MSEC);
  
  		TEST_EQ(pd_port[port].mock_got_soft_reset, 0, "%d");
  		TEST_NE(pd_port[port].mock_pe_message_sent, 0, "%d");
  		TEST_LE(pd_port[port].mock_pe_error, 0, "%d");
  	}
  
  	enable_prl(port, 0);
  
  	return EC_SUCCESS;
  }
  
  static int test_send_data_msg(void)
  {
  	int i;
  	int port = PORT0;
  
  	enable_prl(port, 1);
  
  	/*
  	 * TEST: Sending data  message with 1 to 28 bytes
  	 */
  	for (i = 1; i <= 28; i++) {
  		cycle_through_state_machine(port, 1, MSEC);
  
  		TEST_EQ(prl_tx_get_state(port),
  				PRL_TX_WAIT_FOR_MESSAGE_REQUEST, "%u");
  
  		TEST_NE(simulate_send_data_msg_request_from_pe(port,
  				TCPC_TX_SOP, PD_DATA_SOURCE_CAP, i), 0, "%d");
  
  		cycle_through_state_machine(port, 1, MSEC);
  
  		simulate_goodcrc(port, pd_port[port].power_role,
  						pd_port[port].msg_tx_id);
  		inc_tx_id(port);
  
  		cycle_through_state_machine(port, 10, MSEC);
  
  		TEST_EQ(pd_port[port].mock_got_soft_reset, 0, "%d");
  		TEST_NE(pd_port[port].mock_pe_message_sent, 0, "%d");
  		TEST_LE(pd_port[port].mock_pe_error, 0, "%d");
  	}
  
  	enable_prl(port, 0);
  
  	return EC_SUCCESS;
  }
  
  static int test_send_data_msg_to_much_data(void)
  {
  	int port = PORT0;
  
  	enable_prl(port, 1);
  
  	/*
  	 * TEST: Send data message with more than 28-bytes, should fail
  	 */
  	task_wake(PD_PORT_TO_TASK_ID(port));
  	task_wait_event(40 * MSEC);
  
  	TEST_EQ(prl_tx_get_state(port),
  			PRL_TX_WAIT_FOR_MESSAGE_REQUEST, "%u");
  
  	/* Try to send 29-bytes */
  	TEST_EQ(simulate_send_data_msg_request_from_pe(port,
  			TCPC_TX_SOP, PD_DATA_SOURCE_CAP, 29), 0, "%d");
  
  	task_wake(PD_PORT_TO_TASK_ID(port));
  	task_wait_event(30 * MSEC);
  
  	cycle_through_state_machine(port, 10, MSEC);
  
  	TEST_EQ(pd_port[port].mock_got_soft_reset, 0, "%d");
  	TEST_EQ(pd_port[port].mock_pe_message_sent, 0, "%d");
  	TEST_EQ(pd_port[port].mock_pe_error, ERR_TCH_XMIT, "%d");
  
  	enable_prl(port, 0);
  
  	return EC_SUCCESS;
  }
  
  static int test_send_extended_data_msg(void)
  {
  	int i;
  	int port = PORT0;
  
  	if (!IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) {
  		ccprints("CONFIG_USB_PD_EXTENDED_MESSAGES disabled; skipping");
  		return EC_SUCCESS;
  	}
  
  	enable_prl(port, 1);
  
  	/*
  	 * TEST: Sending extended data message with 29 to 260 bytes
  	 */
  
  	pd_port[port].mock_got_soft_reset = 0;
  	pd_port[port].mock_pe_error = -1;
  
  	ccprintf("Iteration ");
  	for (i = 29; i <= PD_MAX_EXTENDED_MSG_LEN; i++) {
  		ccprintf(".%d", i);
  		pd_port[port].mock_pe_message_sent = 0;
  
  		cycle_through_state_machine(port, 10, MSEC);
  
  		TEST_EQ(prl_tx_get_state(port),
  				PRL_TX_WAIT_FOR_MESSAGE_REQUEST, "%d");
  
  		TEST_NE(simulate_send_extended_data_msg(
  				port, TCPC_TX_SOP, PD_EXT_MANUFACTURER_INFO, i),
  					0, "%d");
  
  		cycle_through_state_machine(port, 10, MSEC);
  
  		TEST_EQ(pd_port[port].mock_got_soft_reset, 0, "%d");
  		TEST_NE(pd_port[port].mock_pe_message_sent, 0, "%d");
  		TEST_LE(pd_port[port].mock_pe_error, 0, "%d");
  	}
  	enable_prl(port, 0);
  
  	return EC_SUCCESS;
  }
  
  static int test_receive_soft_reset_msg(void)
  {
  	int port = PORT0;
  
  	enable_prl(port, 1);
  
  	/*
  	 * TEST: Receiving Soft Reset
  	 */
  
  	task_wake(PD_PORT_TO_TASK_ID(port));
  	task_wait_event(40 * MSEC);
  
  	TEST_EQ(rch_get_state(port),
  			RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER, "%u");
  
  	pd_port[port].mock_got_soft_reset = 0;
  	pd_port[port].mock_pe_error = -1;
  	pd_port[port].mock_pe_message_received = 0;
  
  	TEST_NE(simulate_receive_ctrl_msg(port, PD_CTRL_SOFT_RESET), 0, "%d");
  
  	task_wake(PD_PORT_TO_TASK_ID(port));
  	task_wait_event(30 * MSEC);
  
  	cycle_through_state_machine(port, 10, MSEC);
  
  	TEST_EQ(pd_port[port].mock_got_soft_reset, 1, "%d");
  	TEST_LE(pd_port[port].mock_pe_error, 0, "%d");
  	/*
  	 * We don't want to get  pe_got_soft_reset and pe_message_received, just
  	 * pe_got_soft_reset.
  	 */
  	TEST_EQ(pd_port[port].mock_pe_message_received, 0, "%d");
  
  	enable_prl(port, 0);
  
  	return EC_SUCCESS;
  }
  
  static int test_receive_control_msg(void)
  {
  	int port = PORT0;
  	int expected_header = PD_HEADER(PD_CTRL_DR_SWAP,
  				pd_port[port].power_role,
  				pd_port[port].data_role,
  				pd_port[port].msg_rx_id,
  				0, pd_port[port].rev, 0);
  
  	enable_prl(port, 1);
  
  	/*
  	 * TEST: Receiving a control message
  	 */
  
  	task_wake(PD_PORT_TO_TASK_ID(port));
  	task_wait_event(40 * MSEC);
  
  	TEST_EQ(rch_get_state(port),
  			RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER, "%u");
  
  	pd_port[port].mock_got_soft_reset = 0;
  	pd_port[port].mock_pe_error = -1;
  	pd_port[port].mock_pe_message_received = 0;
  
  	TEST_NE(simulate_receive_ctrl_msg(port, PD_CTRL_DR_SWAP), 0, "%d");
  
  	task_wake(PD_PORT_TO_TASK_ID(port));
  	task_wait_event(30 * MSEC);
  
  	cycle_through_state_machine(port, 3, 10 * MSEC);
  
  	TEST_EQ(pd_port[port].mock_got_soft_reset, 0, "%d");
  	TEST_LE(pd_port[port].mock_pe_error, 0, "%d");
  	TEST_NE(pd_port[port].mock_pe_message_received, 0, "%d");
  	TEST_EQ(expected_header, rx_emsg[port].header, "%d");
  	TEST_EQ(rx_emsg[port].len, 0, "%d");
  
  	enable_prl(port, 0);
  
  	return EC_SUCCESS;
  }
  
  static int test_receive_data_msg(void)
  {
  	int port = PORT0;
  	int i;
  
  	enable_prl(port, 1);
  
  	/*
  	 * TEST: Receiving data message with 1 to 28 bytes
  	 */
  
  	for (i = 1; i <= 28; i++) {
  		task_wake(PD_PORT_TO_TASK_ID(port));
  		task_wait_event(40 * MSEC);
  
  		TEST_EQ(rch_get_state(port),
  				RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER, "%u");
  		TEST_NE(simulate_receive_data(port,
  				PD_DATA_BATTERY_STATUS, i), 0, "%d");
  	}
  
  	enable_prl(port, 0);
  
  	return EC_SUCCESS;
  }
  
  static int test_receive_extended_data_msg(void)
  {
  	int len;
  	int port = PORT0;
  
  	enable_prl(port, 1);
  
  	if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) {
  		/*
  		 * TEST: Receiving extended data message with 29 to 260 bytes
  		 */
  
  		task_wake(PD_PORT_TO_TASK_ID(port));
  		task_wait_event(40 * MSEC);
  
  		TEST_EQ(rch_get_state(port),
  				RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER, "%u");
  
  		for (len = 29; len <= PD_MAX_EXTENDED_MSG_LEN; len++) {
  			TEST_NE(simulate_receive_extended_data(port,
  					PD_DATA_BATTERY_STATUS, len), 0, "%d");
  		}
  	} else {
  		/*
  		 * TEST: Receiving unsupported extended data message and then
  		 * subsequently receiving a support non-extended data message.
  		 */
  		task_wake(PD_PORT_TO_TASK_ID(port));
  		task_wait_event(40 * MSEC);
  		TEST_NE(simulate_receive_extended_data(port,
  					PD_DATA_BATTERY_STATUS, 29), 0, "%d");
  
  		task_wake(PD_PORT_TO_TASK_ID(port));
  		task_wait_event(40 * MSEC);
  		TEST_NE(simulate_receive_data(port,
  				PD_DATA_BATTERY_STATUS, 28), 0, "%d");
  	}
  
  	enable_prl(port, 0);
  
  	return EC_SUCCESS;
  }
  
  static int test_send_soft_reset_msg(void)
  {
  	int port = PORT0;
  
  	enable_prl(port, 1);
  
  	/*
  	 * TEST: Send soft reset
  	 */
  
  	task_wake(PD_PORT_TO_TASK_ID(port));
  	task_wait_event(40 * MSEC);
  
  	TEST_EQ(prl_tx_get_state(port),
  				PRL_TX_WAIT_FOR_MESSAGE_REQUEST, "%u");
  
  	TEST_NE(simulate_send_ctrl_msg_request_from_pe(port,
  			TCPC_TX_SOP, PD_CTRL_SOFT_RESET), 0, "%d");
  
  	task_wake(PD_PORT_TO_TASK_ID(port));
  	task_wait_event(30 * MSEC);
  
  	simulate_goodcrc(port, pd_port[port].power_role,
  						pd_port[port].msg_tx_id);
  	inc_tx_id(port);
  
  	TEST_EQ(prl_tx_get_state(port),
  			PRL_TX_LAYER_RESET_FOR_TRANSMIT, "%u");
  
  	cycle_through_state_machine(port, 3, 10 * MSEC);
  
  	TEST_EQ(pd_port[port].mock_got_soft_reset, 0, "%d");
  	TEST_NE(pd_port[port].mock_pe_message_sent, 0, "%d");
  	TEST_LE(pd_port[port].mock_pe_error, 0, "%d");
  
  	enable_prl(port, 0);
  
  	return EC_SUCCESS;
  }
  
  static int test_pe_execute_hard_reset_msg(void)
  {
  	int port = PORT0;
  
  	enable_prl(port, 1);
  
  	pd_port[port].mock_pe_hard_reset_sent = 0;
  
  	/*
  	 * TEST: Policy Engine initiated hard reset
  	 */
  
  	task_wake(PD_PORT_TO_TASK_ID(port));
  	task_wait_event(40 * MSEC);
  
  	TEST_EQ(prl_hr_get_state(port), PRL_HR_WAIT_FOR_REQUEST, "%u");
  
  	/* Simulate receiving hard reset from policy engine */
  	prl_execute_hard_reset(port);
  
  	TEST_EQ(prl_hr_get_state(port), PRL_HR_RESET_LAYER, "%u");
  	TEST_EQ(prl_tx_get_state(port),
  			PRL_TX_WAIT_FOR_MESSAGE_REQUEST, "%u");
  
  	cycle_through_state_machine(port, 1, 10 * MSEC);
  
  	TEST_EQ(prl_hr_get_state(port),
  			PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE, "%u");
  
  	cycle_through_state_machine(port, 2, PD_T_PS_HARD_RESET);
  	TEST_NE(pd_port[port].mock_pe_hard_reset_sent, 0, "%d");
  
  	TEST_EQ(prl_hr_get_state(port),
  			PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE, "%u");
  
  	/* Simulate policy engine indicating that it is done hard reset */
  	prl_hard_reset_complete(port);
  
  	cycle_through_state_machine(port, 1, 10 * MSEC);
  
  	TEST_EQ(prl_hr_get_state(port), PRL_HR_WAIT_FOR_REQUEST, "%u");
  
  	enable_prl(port, 0);
  
  	return EC_SUCCESS;
  }
  
  static int test_phy_execute_hard_reset_msg(void)
  {
  	int port = PORT0;
  
  	enable_prl(port, 1);
  
  	/*
  	 * TEST: Port partner initiated hard reset
  	 */
  
  	pd_port[port].mock_pe_got_hard_reset = 0;
  
  	task_wake(PD_PORT_TO_TASK_ID(port));
  	task_wait_event(40 * MSEC);
  
  	TEST_EQ(prl_hr_get_state(port), PRL_HR_WAIT_FOR_REQUEST, "%u");
  
  	/* Simulate receiving hard reset from port partner */
  	pd_execute_hard_reset(port);
  
  	TEST_EQ(prl_hr_get_state(port), PRL_HR_RESET_LAYER, "%u");
  	TEST_EQ(prl_tx_get_state(port),
  			PRL_TX_WAIT_FOR_MESSAGE_REQUEST, "%u");
  
  	cycle_through_state_machine(port, 1, 10 * MSEC);
  
  	TEST_EQ(prl_hr_get_state(port),
  			PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE, "%u");
  
  	cycle_through_state_machine(port, 2, PD_T_PS_HARD_RESET);
  	TEST_NE(pd_port[port].mock_pe_got_hard_reset, 0, "%d");
  
  	TEST_EQ(prl_hr_get_state(port),
  			PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE, "%u");
  
  	/* Simulate policy engine indicating that it is done hard reset */
  	prl_hard_reset_complete(port);
  
  	cycle_through_state_machine(port, 1, 10 * MSEC);
  
  	TEST_EQ(prl_hr_get_state(port), PRL_HR_WAIT_FOR_REQUEST, "%u");
  
  	enable_prl(port, 0);
  
  	return EC_SUCCESS;
  }
  
  /* Reset the state machine between each test */
  void before_test(void)
  {
  	/* This test relies on explicitly cycling through events manually */
  	tc_pause_event_loop(PORT0);
  
  	pd_port[PORT0].mock_pe_message_sent = 0;
  	pd_port[PORT0].mock_pe_error = -1;
  	pd_port[PORT0].mock_message_discard = 0;
  	pd_port[PORT0].mock_pe_hard_reset_sent = 0;
  	pd_port[PORT0].mock_pe_got_hard_reset = 0;
  	pd_port[PORT0].mock_pe_message_received = 0;
  	pd_port[PORT0].mock_got_soft_reset = 0;
  	pd_port[PORT0].pd_enable = false;
  	cycle_through_state_machine(PORT0, 10, MSEC);
  	pd_port[PORT0].pd_enable = true;
  	cycle_through_state_machine(PORT0, 10, MSEC);
  }
  
  void run_test(int argc, char **argv)
  {
  	test_reset();
  
  	/* Test PD 2.0 Protocol */
  	init_port(PORT0, PD_REV20);
  	RUN_TEST(test_prl_reset);
  	RUN_TEST(test_send_ctrl_msg);
  	RUN_TEST(test_send_data_msg);
  	RUN_TEST(test_send_data_msg_to_much_data);
  	RUN_TEST(test_receive_control_msg);
  	RUN_TEST(test_receive_data_msg);
  	RUN_TEST(test_receive_soft_reset_msg);
  	RUN_TEST(test_send_soft_reset_msg);
  	RUN_TEST(test_pe_execute_hard_reset_msg);
  	RUN_TEST(test_phy_execute_hard_reset_msg);
  
  	/* TODO(shurst): More PD 2.0 Tests */
  
  	ccprints("Starting PD 3.0 tests");
  
  	/* Test PD 3.0 Protocol */
  	init_port(PORT0, PD_REV30);
  	RUN_TEST(test_prl_reset);
  	RUN_TEST(test_send_ctrl_msg);
  	RUN_TEST(test_send_data_msg);
  	RUN_TEST(test_send_data_msg_to_much_data);
  	RUN_TEST(test_send_extended_data_msg);
  	RUN_TEST(test_receive_control_msg);
  	RUN_TEST(test_receive_data_msg);
  	RUN_TEST(test_receive_extended_data_msg);
  	RUN_TEST(test_receive_soft_reset_msg);
  	RUN_TEST(test_send_soft_reset_msg);
  	RUN_TEST(test_pe_execute_hard_reset_msg);
  	RUN_TEST(test_phy_execute_hard_reset_msg);
  
  	/* TODO(shurst): More PD 3.0 Tests */
  
  	/* Do basic state machine validity checks last. */
  	RUN_TEST(test_prl_no_parent_cycles);
  	RUN_TEST(test_prl_all_states_named);
  
  	test_print_result();
  }
  