implement forwarding of PTS/PPS from emulator to host PC + test case
diff --git a/firmware/src_simtrace/card_emu.c b/firmware/src_simtrace/card_emu.c
index 97b3d94..ec9fdb8 100644
--- a/firmware/src_simtrace/card_emu.c
+++ b/firmware/src_simtrace/card_emu.c
@@ -165,6 +165,45 @@
 	 * be transmitted now */
 }
 
+/* convert a non-contiguous PTS request/responsei into a contiguous
+ * buffer, returning the number of bytes used in the buffer */
+static int serialize_pts(uint8_t *out,  const uint8_t *in)
+{
+	int i = 0;
+
+	out[i++] = in[_PTSS];
+	out[i++] = in[_PTS0];
+	if (in[_PTS0] & (1 << 4))
+		out[i++] = in[_PTS1];
+	if (in[_PTS0] & (1 << 5))
+		out[i++] = in[_PTS2];
+	if (in[_PTS0] & (1 << 6))
+		out[i++] = in[_PTS3];
+	out[i++] = in[_PCK];
+
+	return i;
+}
+
+static void flush_pts(struct card_handle *ch)
+{
+	struct req_ctx *rctx;
+	struct cardemu_usb_msg_pts_info *ptsi;
+
+	rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
+	if (!rctx)
+		return;
+
+	ptsi = (struct cardemu_usb_msg_pts_info *) rctx->data;
+	ptsi->hdr.msg_type = CEMU_USB_MSGT_DO_PTS;
+	ptsi->hdr.data_len = serialize_pts(ptsi->req, ch->pts.req);
+	serialize_pts(ptsi->resp, ch->pts.resp);
+
+	req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
+
+	/* FIXME: call into USB code to see if this buffer can
+	 * be transmitted now */
+}
+
 static void update_fidi(struct card_handle *ch)
 {
 	int rc;
@@ -310,6 +349,7 @@
 	case PTS_S_WAIT_REQ_PCK:
 		ch->pts.req[_PCK] = byte;
 		/* FIXME: check PCK */
+		/* FIXME: check if proposal matches capabilities in ATR */
 		memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp));
 		break;
 	default:
@@ -320,6 +360,12 @@
 	/* calculate the next state and set it */
 	set_pts_state(ch, next_pts_state(ch));
 
+	if (ch->pts.state == PTS_S_WAIT_RESP_PTSS) {
+		flush_pts(ch);
+		/* activate UART TX to transmit PTS response */
+		card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
+	}
+
 	return ISO_S_IN_PTS;
 }
 
diff --git a/firmware/test/card_emu_tests.c b/firmware/test/card_emu_tests.c
index 235f511..e071dfa 100644
--- a/firmware/test/card_emu_tests.c
+++ b/firmware/test/card_emu_tests.c
@@ -180,6 +180,25 @@
 	req_ctx_set_state(rctx, RCTX_S_FREE);
 }
 
+static void get_and_verify_rctx_pps(const uint8_t *data, unsigned int len)
+{
+	struct req_ctx *rctx;
+	struct cardemu_usb_msg_pts_info *ptsi;
+
+	rctx = req_ctx_find_get(0, RCTX_S_USB_TX_PENDING, RCTX_S_USB_TX_BUSY);
+	assert(rctx);
+	dump_rctx(rctx);
+
+	ptsi = (struct cardemu_usb_msg_pts_info *) rctx->data;
+	/* FIXME: verify */
+	assert(ptsi->hdr.msg_type == CEMU_USB_MSGT_DO_PTS);
+	assert(!memcmp(ptsi->req, data, len));
+	assert(!memcmp(ptsi->resp, data, len));
+
+	/* free the req_ctx, indicating it has fully arrived on the host */
+	req_ctx_set_state(rctx, RCTX_S_FREE);
+}
+
 /* emulate a TPDU header being sent by the reader/phone */
 static void rdr_send_tpdu_hdr(struct card_handle *ch, const uint8_t *tpdu_hdr)
 {
@@ -304,6 +323,27 @@
 	card_emu_io_statechg(ch, CARD_IO_CLK, 1);
 }
 
+const uint8_t pps[] = {
+	/* PPSS identifies the PPS request or response and is set to
+	 * 'FF'. */
+	0xFF,		// PPSS
+	/* In PPS0, each bit 5, 6 or 7 set to 1 indicates the presence
+	 * of an optional byte PPS 1 , PPS 2 , PPS 3 ,
+	 * respectively. Bits 4 to 1 encode a type T to propose a
+	 * transmission protocol. Bit 8 is reserved for future
+	 * use and shall be set to 0. */
+	0b00010000,	// PPS0: PPS1 present
+	0x00,		// PPS1 proposed Fi/Di value
+	0xFF ^ 0b00010000// PCK
+};
+
+static void
+test_ppss(struct card_handle *ch)
+{
+	reader_send_bytes(ch, pps, sizeof(pps));
+	get_and_verify_rctx_pps(pps, sizeof(pps));
+	card_tx_verify_chars(ch, pps, sizeof(pps));
+}
 
 /* READ RECORD (offset 0, 10 bytes) */
 const uint8_t tpdu_hdr_read_rec[] = { 0xA0, 0xB2, 0x00, 0x00, 0x0A };
@@ -327,6 +367,8 @@
 	io_start_card(ch);
 	card_tx_verify_chars(ch, NULL, 0);
 
+	test_ppss(ch);
+
 	for (i = 0; i < 2; i++) {
 		test_tpdu_reader2card(ch, tpdu_hdr_write_rec, tpdu_body_write_rec, sizeof(tpdu_body_write_rec));