card_emu: Fix state transitions for both Rx and Tx data phase

We now use the P3 value to determine how many characters to
receive (in case of Reader->Card payload phase).
diff --git a/firmware/src_simtrace/card_emu.c b/firmware/src_simtrace/card_emu.c
index f1f7605..093e9a1 100644
--- a/firmware/src_simtrace/card_emu.c
+++ b/firmware/src_simtrace/card_emu.c
@@ -371,17 +371,34 @@
  * TPDU handling
  **********************************************************************/
 
+
+/* compute number of data bytes according to Chapter 10.3.2 of 7816-3 */
+static unsigned int t0_num_data_bytes(uint8_t p3, int reader_to_card)
+{
+	if (reader_to_card) {
+		return p3;
+	} else {
+		if (p3 == 0)
+			return 256;
+		else
+			return p3;
+	}
+}
+
 /* add a just-received TPDU byte (from reader) to USB buffer */
-static void add_tpdu_byte(struct card_handle *ch, uint8_t byte)
+static enum iso7816_3_card_state add_tpdu_byte(struct card_handle *ch, uint8_t byte)
 {
 	struct req_ctx *rctx;
 	struct cardemu_usb_msg_rx_data *rd;
+	unsigned int num_data_bytes = t0_num_data_bytes(ch->tpdu.hdr[_P3], 0);
 
 	/* ensure we have a buffer */
 	if (!ch->uart_rx_ctx) {
-		rctx = ch->uart_rx_ctx = req_ctx_find_get(1, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
-		if (!ch->uart_rx_ctx)
+		rctx = ch->uart_rx_ctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
+		if (!ch->uart_rx_ctx) {
+			TRACE_DEBUG("Received UART byte but unable to allocate Rx Buf\n");
 			return;
+		}
 		rd = (struct cardemu_usb_msg_rx_data *) ch->uart_rx_ctx->data;
 		cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
 		rctx->tot_len = sizeof(*rd);
@@ -395,8 +412,14 @@
 	rctx->tot_len++;
 
 	/* check if the buffer is full. If so, send it */
-	if (rctx->tot_len >= rctx->size)
+	if (rctx->tot_len >= sizeof(*rd) + num_data_bytes) {
+		rd->flags |= CEMU_DATA_F_FINAL;
 		flush_rx_buffer(ch);
+		return ISO_S_WAIT_TPDU;
+	} else if (rctx->tot_len >= rctx->size)
+		flush_rx_buffer(ch);
+
+	return ISO_S_IN_TPDU;
 }
 
 static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
@@ -459,7 +482,7 @@
 	}
 
 	/* ensure we have a new buffer */
-	ch->uart_rx_ctx = req_ctx_find_get(1, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
+	ch->uart_rx_ctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
 	if (!ch->uart_rx_ctx)
 		return;
 	rctx = ch->uart_rx_ctx;
@@ -484,31 +507,34 @@
 	switch (ch->tpdu.state) {
 	case TPDU_S_WAIT_CLA:
 		ch->tpdu.hdr[_CLA] = byte;
+		set_tpdu_state(ch, next_tpdu_state(ch));
 		break;
 	case TPDU_S_WAIT_INS:
 		ch->tpdu.hdr[_INS] = byte;
+		set_tpdu_state(ch, next_tpdu_state(ch));
 		break;
 	case TPDU_S_WAIT_P1:
 		ch->tpdu.hdr[_P1] = byte;
+		set_tpdu_state(ch, next_tpdu_state(ch));
 		break;
 	case TPDU_S_WAIT_P2:
 		ch->tpdu.hdr[_P2] = byte;
+		set_tpdu_state(ch, next_tpdu_state(ch));
 		break;
 	case TPDU_S_WAIT_P3:
 		ch->tpdu.hdr[_P3] = byte;
+		set_tpdu_state(ch, next_tpdu_state(ch));
 		/* FIXME: start timer to transmit further 0x60 */
 		/* send the TPDU header as part of a procedure byte
 		 * request to the USB host */
 		send_tpdu_header(ch);
 		break;
 	case TPDU_S_WAIT_RX:
-		add_tpdu_byte(ch, byte);
-		break;
+		return add_tpdu_byte(ch, byte);
 	default:
 		TRACE_DEBUG("process_byte_tpdu() in invalid state %u\n",
 			    ch->tpdu.state);
 	}
-	set_tpdu_state(ch, next_tpdu_state(ch));
 
 	/* ensure we stay in TPDU ISO state */
 	return ISO_S_IN_TPDU;
@@ -523,7 +549,7 @@
 	/* ensure we are aware of any data that might be pending for
 	 * transmit */
 	if (!ch->uart_tx_ctx) {
-		ch->uart_tx_ctx = req_ctx_find_get(1, RCTX_S_UART_TX_PENDING,
+		ch->uart_tx_ctx = req_ctx_find_get(0, RCTX_S_UART_TX_PENDING,
 						   RCTX_S_UART_TX_BUSY);
 		if (!ch->uart_tx_ctx)
 			return 0;
@@ -536,7 +562,7 @@
 	td = (struct cardemu_usb_msg_tx_data *) rctx->data;
 
 #if 0
-	/* this must happen _after_ the byte has been transmittd */
+	/* FIXME: this must happen _after_ the byte has been transmittd */
 	switch (ch->tpdu.state) {
 	case TPDU_S_WAIT_PB:
 		if (td->flags & CEMU_DATA_F_PB_AND_TX)
@@ -592,6 +618,8 @@
 	case ISO_S_WAIT_CLK:
 	case ISO_S_WAIT_RST:
 	case ISO_S_WAIT_ATR:
+		TRACE_DEBUG("Received UART char in 7816 state %u\n",
+				ch->state);
 		/* we shouldn't receive any data from the reader yet! */
 		break;
 	case ISO_S_WAIT_TPDU:
@@ -640,6 +668,8 @@
 	if (rc)
 		ch->stats.tx_bytes++;
 
+	/* if we return 0 here, the UART needs to disable transmit-ready
+	 * interrupts */
 	return rc;
 }