Clean up and refactor; new hw support

(Originally, https://android-review.googlesource.com/#/c/341550/)

This change addresses portability, a pn80t platform abstraction, and
nq-nci support.

Refactor/clean up:
- Adds darwin-sysdeps.c to help avoid reverting again.
- Clean up Android.bp
- T=1: moved T=1 to using bit_specs to keep some
  of the readability of bitfields without incurring
  weird toolchain side effects.
- T=1 will still rely on compilers keeping uchars
  aligned and check it with a div-by-zero build
  assertion.
- ESE platform specific methods are now wrapped.
- Adjusted error message constant usage.
- Enclosing {} for every if statement.
- Moved to relative headers for inclusion into other code
  bases.
- Added a comment to log.h to make debugging easier globally
  in libese code.

PN80T:
- Common code now shared across different
  wire configurations.
- Add support for kernel based driver (called nq-nci)
  which interacts with the nq-nci behavior for power
  management.
- Added cooldown/end of session code to pn80t/common.c
- Migrated the ese_nxp_sample code to NQ_NCI and added the empty
  session to test the cooldown code submission.

Bug: 34193473,35105409
Change-Id: I8fc320c8c236282ed103ef3ee3cb8c0dc99d8bcb
Test: unittests pass, tested ese-relay on hardware forwarding globalplatform pro
diff --git a/libese-teq1/Android.bp b/libese-teq1/Android.bp
index 86b9a41..76454f4 100644
--- a/libese-teq1/Android.bp
+++ b/libese-teq1/Android.bp
@@ -23,24 +23,24 @@
     local_include_dirs: ["include"],
 
     // Ensure that only explicitly exported symbols are visible.
-    cflags: ["-fvisibility=internal"],
+    cflags: ["-fvisibility=internal", "-std=c99"],
     debug: {
-      cflags: ["-DLOG_NDEBUG=0"],
+        cflags: ["-DLOG_NDEBUG=0"],
     },
-    shared_libs: ["liblog", "libese"],
+    shared_libs: ["liblog", "libese", "libese-sysdeps"],
     export_include_dirs: ["include"],
 }
 
 cc_library {
-  name: "libese-teq1-private",
-  host_supported: true,
+    name: "libese-teq1-private",
+    host_supported: true,
 
-  srcs: ["teq1.c"],
-  local_include_dirs: ["include"],
+    srcs: ["teq1.c"],
+    local_include_dirs: ["include"],
 
-  // Ensure that only explicitly exported symbols are visible.
-  shared_libs: ["liblog", "libese"],
-  export_include_dirs: ["include", "."],
+    // Ensure that only explicitly exported symbols are visible.
+    shared_libs: ["liblog", "libese", "libese-sysdeps"],
+    export_include_dirs: ["include", "."],
 }
 
 subdirs = ["tests"]
diff --git a/libese-teq1/include/ese/teq1.h b/libese-teq1/include/ese/teq1.h
index 61831a5..8a3fa2e 100644
--- a/libese-teq1/include/ese/teq1.h
+++ b/libese-teq1/include/ese/teq1.h
@@ -21,20 +21,22 @@
 extern "C" {
 #endif
 
-#include <ese/ese.h>
+#include "../../../libese/include/ese/ese.h"
+#include "../../../libese/include/ese/bit_spec.h"
 
-/* Reserved codes for T=1 devices. */
-#define TEQ1_ERROR_HARD_FAIL 0
-#define TEQ1_ERROR_ABORT 1
-#define TEQ1_ERROR_DEVICE_RESET 2
-
+/* Reserved codes for T=1 devices in EseOperation­>errors. */
+enum Teq1Error {
+ kTeq1ErrorHardFail = 0,
+ kTeq1ErrorAbort,
+ kTeq1ErrorDeviceReset,
+ kTeq1ErrorMax,
+};
 
 enum pcb_type {
   kPcbTypeInfo0 = 0x0,
   kPcbTypeInfo1 = 0x1,
   kPcbTypeReceiveReady = 0x2,
   kPcbTypeSupervisory = 0x3,
-  kPcbTypeMax,
 };
 
 enum super_type {
@@ -44,54 +46,52 @@
   kSuperTypeWTX = 0x3,
 };
 
-struct PCB {
-  union {
-    /* Info bits */
-    struct {
-      uint8_t reserved:5;  /* Should be 0. */
-      uint8_t more_data:1;
-      uint8_t send_seq:1;
-      uint8_t bit8:1;  /* Must be 0 for I-blocks. */
-    } I;  /* Information Block */
-    /* receive bits */
-    struct {
-      uint8_t parity_err:1;  /* char parity or redundancy code err */
-      uint8_t other_err:1;  /*  any other errors */
-      uint8_t unused_1:2;
-      uint8_t next_seq:1;  /* If the same seq as last frame, then err even if other bits are 0. */
-      uint8_t unused_0:1;
-      uint8_t pcb_type:2;  /* Always (1, 0)=2 for R */
-    } R;  /* Receive ready block */
-    struct {
-      uint8_t type:2;
-      uint8_t unused_0:3;
-      uint8_t response:1;
-      uint8_t pcb_type:2;
-    } S;  /* Supervisory block */
-    struct {
-      uint8_t data:6;
-      uint8_t type:2; /* I = 0|1, R = 2, S = 3 */
-    };  /* Bit7-8 access for block type access. */
-    /* Bitwise access */
-    struct {
-     uint8_t bit0:1;  /* lsb */
-     uint8_t bit1:1;
-     uint8_t bit2:1;
-     uint8_t bit3:1;
-     uint8_t bit4:1;
-     uint8_t bit5:1;
-     uint8_t bit6:1;
-     uint8_t bit7:1; /* msb */
-    } bits;
-    uint8_t val;
-  };
+struct PcbSpec {
+  struct bit_spec type;
+  struct bit_spec data;
+  struct {
+    struct bit_spec more_data;
+    struct bit_spec send_seq;
+  } I;
+  struct {
+    struct bit_spec parity_err;
+    struct bit_spec other_err;
+    struct bit_spec next_seq;
+  } R;
+  struct {
+    struct bit_spec type;
+    struct bit_spec response;
+  } S;
+};
+
+const static struct PcbSpec PCB = {
+  .type = { .value = 3, .shift = 6, },
+  .data = { .value = 63, .shift = 0, },
+  .I = {
+    .more_data = { .value = 1, .shift = 5, },
+    .send_seq = { .value = 1, .shift = 6, },
+  },
+  .R = {
+    /* char parity or redundancy code err */
+    .parity_err = { .value = 1, .shift = 0, },
+    /* any other errors */
+    .other_err = { .value = 1, .shift = 1, },
+    /* If the same seq as last frame, then err even if other bits are 0. */
+    .next_seq = { .value = 1, .shift = 4, },
+  },
+  .S = {
+    .type = { .value = 3, .shift = 0, },
+    .response = { .value = 1, .shift = 5, },
+  },
 };
 
 struct Teq1Header {
   uint8_t NAD;
-  struct PCB PCB;
+  uint8_t PCB;
   uint8_t LEN;
-} __attribute__((packed));
+};
+#define TEQ1HEADER_SIZE 3
+#define TEQ1FRAME_SIZE INF_LEN + 1 + TEQ1HEADER_SIZE
 
 #define INF_LEN 254
 #define IFSC 254
@@ -103,10 +103,10 @@
       union {
         uint8_t INF[INF_LEN + 1]; /* Up to 254 with trailing LRC byte. */
       };
-      /* uint8_t LRC;  If CRC was supported, it would be uint16_t. */
+      /* If CRC was supported, it would be uint16_t. */
     };
   };
-} __attribute__((packed));
+};
 
 
 /*
@@ -122,6 +122,7 @@
     uint8_t seq_bits;
   } seq;
 };
+
 /* Set "last sent" to 1 so we start at 0. */
 #define TEQ1_INIT_CARD_STATE(CARD) \
   (CARD)->seq.card = 1; \
@@ -146,7 +147,11 @@
   teq1_protocol_preprocess_op_t *preprocess;
 };
 
+/* PCB bits */
+#define kTeq1PcbType (3 << 6)
+
 /* I-block bits */
+#define kTeq1InfoType        (0 << 6)
 #define kTeq1InfoMoreBit     (1 << 5)
 #define kTeq1InfoSeqBit      (1 << 6)
 
@@ -176,9 +181,10 @@
 #define TEQ1_S_ABORT(R) (kTeq1SuperType | ((R) << 5) | kTeq1SuperAbortBit)
 #define TEQ1_S_IFS(R) (kTeq1SuperType | ((R) << 5) | kTeq1SuperIfsBit)
 
-size_t teq1_transceive(struct EseInterface *ese,
-                       const uint8_t *const tx_buf, size_t tx_len,
-                       uint8_t *rx_buf, size_t rx_max);
+uint32_t teq1_transceive(struct EseInterface *ese,
+                         const struct Teq1ProtocolOptions *opts,
+                         const uint8_t *const tx_buf, uint32_t tx_len,
+                         uint8_t *rx_buf, uint32_t rx_max);
 
 uint8_t teq1_compute_LRC(const struct Teq1Frame *frame);
 
diff --git a/libese-teq1/teq1.c b/libese-teq1/teq1.c
index 9d0b2a5..40d2b1d 100644
--- a/libese-teq1/teq1.c
+++ b/libese-teq1/teq1.c
@@ -14,13 +14,9 @@
  * limitations under the License.
  */
 
-#include <string.h>
-
-#include <ese/ese.h>
-#include <ese/teq1.h>
-
-#define LOG_TAG "ESE_T=1"
-#include <ese/log.h>
+#include "include/ese/teq1.h"
+#include "../libese/include/ese/ese.h"
+#include "../libese/include/ese/log.h"
 
 #include "teq1_private.h"
 
@@ -94,10 +90,15 @@
   }
 }
 
-int teq1_transmit(struct EseInterface *ese, struct Teq1Frame *frame) {
-  /* Set during ese_open() by teq1_init. */
-  const struct Teq1ProtocolOptions *opts = ese->ops->opts;
+void teq1_dump_buf(const char *prefix, const uint8_t *buf, uint32_t len) {
+  uint32_t recvd = 0;
+  for (recvd = 0; recvd < len; ++recvd)
+    ALOGV("%s[%u]: %.2X", prefix, recvd, buf[recvd]);
+}
 
+int teq1_transmit(struct EseInterface *ese,
+                  const struct Teq1ProtocolOptions *opts,
+                  struct Teq1Frame *frame) {
   /* Set correct node address. */
   frame->header.NAD = opts->node_address;
 
@@ -106,40 +107,48 @@
 
   /*
    * If the card does something weird, like expect an CRC/LRC based on a
-   * different
-   * header value, the preprocessing can handle it.
+   * different header value, the preprocessing can handle it.
    */
-  if (opts->preprocess)
+  if (opts->preprocess) {
     opts->preprocess(opts, frame, 1);
+  }
 
   /*
    * Begins transmission and ignore errors.
    * Failed transmissions will result eventually in a resync then reset.
    */
-  teq1_trace_transmit(frame->header.PCB.val, frame->header.LEN);
+  teq1_trace_transmit(frame->header.PCB, frame->header.LEN);
+  teq1_dump_transmit(frame->val, sizeof(frame->header) + frame->header.LEN + 1);
   ese->ops->hw_transmit(ese, frame->val,
                         sizeof(frame->header) + frame->header.LEN + 1, 1);
-  /* Even though in practice any WTX BWT extension starts when the above
-   * transmit ends.
-   * it is easier to implement it in the polling timeout of receive.
+  /*
+   * Even though in practice any WTX BWT extension starts when the above
+   * transmit ends, it is easier to implement it in the polling timeout of
+   * receive.
    */
   return 0;
 }
 
-int teq1_receive(struct EseInterface *ese, float timeout,
+int teq1_receive(struct EseInterface *ese,
+                 const struct Teq1ProtocolOptions *opts, float timeout,
                  struct Teq1Frame *frame) {
-  const struct Teq1ProtocolOptions *opts = ese->ops->opts;
   /* Poll the bus until we see the start of frame indicator, the interface NAD.
    */
-  if (ese->ops->poll(ese, opts->host_address, timeout, 0) < 0) {
+  int bytes_consumed = ese->ops->poll(ese, opts->host_address, timeout, 0);
+  if (bytes_consumed < 0 || bytes_consumed > 1) {
     /* Timed out or comm error. */
+    ALOGV("%s: comm error: %d", __func__, bytes_consumed);
     return -1;
   }
-  /* We polled for the NAD above. */
-  frame->header.NAD = opts->host_address;
+  /* We polled for the NAD above -- if it was consumed, set it here. */
+  if (bytes_consumed) {
+    frame->header.NAD = opts->host_address;
+  }
   /* Get the remainder of the header, but keep the line &open. */
-  ese->ops->hw_receive(ese, (uint8_t *)(&frame->header.PCB),
-                       sizeof(frame->header) - 1, 0);
+  ese->ops->hw_receive(ese, (uint8_t *)(&frame->header.NAD + bytes_consumed),
+                       sizeof(frame->header) - bytes_consumed, 0);
+  teq1_dump_receive((uint8_t *)(&frame->header.NAD + bytes_consumed),
+                    sizeof(frame->header) - bytes_consumed);
   if (frame->header.LEN == 255) {
     ALOGV("received invalid LEN of 255");
     /* Close the receive window and return failure. */
@@ -152,15 +161,17 @@
    */
   ese->ops->hw_receive(ese, (uint8_t *)(&(frame->INF[0])),
                        frame->header.LEN + 1, 1);
-  teq1_trace_receive(frame->header.PCB.val, frame->header.LEN);
+  teq1_dump_receive((uint8_t *)(&(frame->INF[0])), frame->header.LEN + 1);
+  teq1_trace_receive(frame->header.PCB, frame->header.LEN);
 
   /*
    * If the card does something weird, like expect an CRC/LRC based on a
    * different
    * header value, the preprocessing should fix up here prior to the LRC check.
    */
-  if (opts->preprocess)
+  if (opts->preprocess) {
     opts->preprocess(opts, frame, 0);
+  }
 
   /* LRC and other protocol goodness checks are not done here. */
   return frame->header.LEN; /* Return data bytes read. */
@@ -168,15 +179,17 @@
 
 uint8_t teq1_fill_info_block(struct Teq1State *state, struct Teq1Frame *frame) {
   uint32_t inf_len = INF_LEN;
-  if (state->ifs < inf_len)
+  if (state->ifs < inf_len) {
     inf_len = state->ifs;
-  switch (frame->header.PCB.type) {
+  }
+  switch (bs_get(PCB.type, frame->header.PCB)) {
   case kPcbTypeInfo0:
   case kPcbTypeInfo1: {
     uint32_t len = state->app_data.tx_len;
-    if (len > inf_len)
+    if (len > inf_len) {
       len = inf_len;
-    memcpy(frame->INF, state->app_data.tx_buf, len);
+    }
+    ese_memcpy(frame->INF, state->app_data.tx_buf, len);
     frame->header.LEN = (len & 0xff);
     ALOGV("Copying %x bytes of app data for transmission", frame->header.LEN);
     /* Incrementing here means the caller MUST handle retransmit with prepared
@@ -184,9 +197,10 @@
     state->app_data.tx_len -= len;
     state->app_data.tx_buf += len;
     /* Perform chained transmission if needed. */
-    frame->header.PCB.I.more_data = 0;
-    if (state->app_data.tx_len > 0)
-      frame->header.PCB.I.more_data = 1;
+    bs_assign(&frame->header.PCB, PCB.I.more_data, 0);
+    if (state->app_data.tx_len > 0) {
+      frame->header.PCB |= bs_mask(PCB.I.more_data, 1);
+    }
     return len;
   }
   case kPcbTypeSupervisory:
@@ -198,14 +212,15 @@
 }
 
 void teq1_get_app_data(struct Teq1State *state, struct Teq1Frame *frame) {
-  switch (frame->header.PCB.type) {
+  switch (bs_get(PCB.type, frame->header.PCB)) {
   case kPcbTypeInfo0:
   case kPcbTypeInfo1: {
     uint8_t len = frame->header.LEN;
     /* TODO(wad): Some data will be left on the table. Should this error out? */
-    if (len > state->app_data.rx_len)
+    if (len > state->app_data.rx_len) {
       len = state->app_data.rx_len;
-    memcpy(state->app_data.rx_buf, frame->INF, len);
+    }
+    ese_memcpy(state->app_data.rx_buf, frame->INF, len);
     /* The original caller must retain the starting pointer to determine
      * actual available data.
      */
@@ -227,8 +242,9 @@
                                struct Teq1Frame *rx_frame) {
   uint8_t lrc = 0;
   int chained = 0;
-  if (rx_frame->header.PCB.val == 255)
+  if (rx_frame->header.PCB == 255) {
     return R(0, 1, 0); /* Other error */
+  }
 
   lrc = teq1_compute_LRC(rx_frame);
   if (rx_frame->INF[rx_frame->header.LEN] != lrc) {
@@ -238,46 +254,42 @@
   }
 
   /* Check if we were chained and increment the last sent sequence. */
-  switch (tx_frame->header.PCB.type) {
+  switch (bs_get(PCB.type, tx_frame->header.PCB)) {
   case kPcbTypeInfo0:
   case kPcbTypeInfo1:
-    chained = tx_frame->header.PCB.I.more_data;
-    state->card_state->seq.interface = tx_frame->header.PCB.I.send_seq;
+    chained = bs_get(PCB.I.more_data, tx_frame->header.PCB);
+    state->card_state->seq.interface =
+        bs_get(PCB.I.send_seq, tx_frame->header.PCB);
   }
 
   /* Check if we've gone down an easy to catch error hole. The rest will turn up
    * on the
    * txrx switch.
    */
-  switch (rx_frame->header.PCB.type) {
+  switch (bs_get(PCB.type, rx_frame->header.PCB)) {
   case kPcbTypeSupervisory:
-    if (rx_frame->header.PCB.val != S(RESYNC, RESPONSE) &&
-        rx_frame->header.LEN != 1)
+    if (rx_frame->header.PCB != S(RESYNC, RESPONSE) &&
+        rx_frame->header.LEN != 1) {
       return R(0, 1, 0);
+    }
     break;
   case kPcbTypeReceiveReady:
-    if (rx_frame->header.LEN != 0)
+    if (rx_frame->header.LEN != 0) {
       return R(0, 1, 0);
-#if 0
-/* Handled explicitly. */
-    /* R() blocks are always an error if we're not chaining. */
-    if (!chained)
-      return R(0, 1, 0);
-    /* If we are chaining, the R must be the next seq. */
-    if (rx_frame->header.PCB.R.next_seq == state->card_state->seq.interface)
-      return R(0, 1, 0);
-#endif
+    }
     break;
   case kPcbTypeInfo0:
   case kPcbTypeInfo1:
     /* I-blocks must always alternate for each endpoint. */
-    if (rx_frame->header.PCB.I.send_seq == state->card_state->seq.card) {
-      ALOGV("Got seq %d expected %d", rx_frame->header.PCB.I.send_seq,
+    if ((bs_get(PCB.I.send_seq, rx_frame->header.PCB)) ==
+        state->card_state->seq.card) {
+      ALOGV("Got seq %d expected %d",
+            bs_get(PCB.I.send_seq, rx_frame->header.PCB),
             state->card_state->seq.card);
       return R(0, 1, 0);
     }
     /* Update the card's last I-block seq. */
-    state->card_state->seq.card = rx_frame->header.PCB.I.send_seq;
+    state->card_state->seq.card = bs_get(PCB.I.send_seq, rx_frame->header.PCB);
   default:
     break;
   };
@@ -291,25 +303,25 @@
   /* 0 = TX, 1 = RX */
   /* msb = tx pcb, lsb = rx pcb */
   /* BUG_ON(!rx_frame && !tx_frame && !next_tx); */
-  uint16_t txrx = TEQ1_RULE(tx_frame->header.PCB.val, rx_frame->header.PCB.val);
-  struct PCB R_err;
+  uint16_t txrx = TEQ1_RULE(tx_frame->header.PCB, rx_frame->header.PCB);
+  uint8_t R_err;
 
   while (1) {
     /* Timeout errors come like invalid frames: 255. */
-    if ((R_err.val = teq1_frame_error_check(state, tx_frame, rx_frame)) != 0) {
+    if ((R_err = teq1_frame_error_check(state, tx_frame, rx_frame)) != 0) {
       ALOGV("incoming frame failed the error check");
       state->last_error_message = "Invalid frame received";
       /* Mark the frame as bad for our rule evaluation. */
-      txrx = TEQ1_RULE(tx_frame->header.PCB.val, 255);
+      txrx = TEQ1_RULE(tx_frame->header.PCB, 255);
       state->errors++;
       /* Rule 6.4 */
-      if (state->errors >= 6) { /* XXX: Review error count lifetime. */
+      if (state->errors >= 6) {
         return kRuleResultResetDevice;
       }
       /* Rule 7.4.2 */
       if (state->errors >= 3) {
         /* Rule 7.4.1: state should start with error count = 2 */
-        next_tx->header.PCB.val = S(RESYNC, REQUEST);
+        next_tx->header.PCB = S(RESYNC, REQUEST);
         /* Resync result in a fresh session, so we should just continue here. */
         return kRuleResultContinue;
       }
@@ -327,25 +339,22 @@
       teq1_get_app_data(state, rx_frame);
       return kRuleResultComplete;
 
-      /* Read app data & return. */
-      teq1_get_app_data(state, rx_frame);
-      return kRuleResultComplete;
-
     /* Card begins chained response. */
     case TEQ1_RULE(I(0, 0), I(0, 1)):
     case TEQ1_RULE(I(1, 0), I(1, 1)):
       /* Prep R(N(S)) */
       teq1_get_app_data(state, rx_frame);
-      next_tx->header.PCB.val = TEQ1_R(!rx_frame->header.PCB.I.send_seq, 0, 0);
+      next_tx->header.PCB =
+          TEQ1_R(!bs_get(PCB.I.send_seq, rx_frame->header.PCB), 0, 0);
       next_tx->header.LEN = 0;
       return kRuleResultContinue;
 
     /*** Rule 2.2, Rule 5: Chained transmission ***/
     case TEQ1_RULE(I(0, 1), R(1, 0, 0)):
     case TEQ1_RULE(I(1, 1), R(0, 0, 0)):
-      /* Send next block */
-      next_tx->header.PCB.val = I(0, 0);
-      next_tx->header.PCB.I.send_seq = rx_frame->header.PCB.R.next_seq;
+      /* Send next block -- error-checking assures the R seq is our next seq. */
+      next_tx->header.PCB =
+          TEQ1_I(bs_get(PCB.R.next_seq, rx_frame->header.PCB), 0);
       teq1_fill_info_block(state, next_tx); /* Sets M-bit and LEN. */
       return kRuleResultContinue;
 
@@ -358,7 +367,7 @@
       case TEQ1_RULE(I(1, 1), S(WTX, REQUEST)):
       */
       /* Send S(WTX, RESPONSE) with same INF */
-      next_tx->header.PCB.val = S(WTX, RESPONSE);
+      next_tx->header.PCB = S(WTX, RESPONSE);
       next_tx->header.LEN = 1;
       next_tx->INF[0] = rx_frame->INF[0];
       state->wait_mult = rx_frame->INF[0];
@@ -377,7 +386,7 @@
     /* Don't support a IFS_REQUEST if we sent an error R-block. */
     case TEQ1_RULE(R(0, 0, 0), S(IFS, REQUEST)):
     case TEQ1_RULE(R(1, 0, 0), S(IFS, REQUEST)):
-      next_tx->header.PCB.val = S(IFS, RESPONSE);
+      next_tx->header.PCB = S(IFS, RESPONSE);
       next_tx->header.LEN = 1;
       next_tx->INF[0] = rx_frame->INF[0];
       state->ifs = rx_frame->INF[0];
@@ -393,7 +402,9 @@
     case TEQ1_RULE(R(1, 0, 0), I(1, 1)):
       /* Chaining continued; consume partial data and send R(N(S)) */
       teq1_get_app_data(state, rx_frame);
-      next_tx->header.PCB.val = TEQ1_R(!rx_frame->header.PCB.I.send_seq, 0, 0);
+      /* The card seq bit will be tracked/validated earlier. */
+      next_tx->header.PCB =
+          TEQ1_R(!bs_get(PCB.I.send_seq, rx_frame->header.PCB), 0, 0);
       return kRuleResultContinue;
 
     /* Rule 6: Interface can send a RESYNC */
@@ -414,10 +425,11 @@
     case TEQ1_RULE(I(1, 0), 255):
     case TEQ1_RULE(I(0, 1), 255):
     case TEQ1_RULE(I(1, 1), 255):
-      next_tx->header.PCB.val = R_err.val;
-      next_tx->header.PCB.R.next_seq = tx_frame->header.PCB.I.send_seq;
+      next_tx->header.PCB = R_err;
+      bs_assign(&next_tx->header.PCB, PCB.R.next_seq,
+                bs_get(PCB.I.send_seq, tx_frame->header.PCB));
       ALOGV("Rule 7.1,7.5,7.6: bad rx - sending error R: %x = %s",
-            next_tx->header.PCB.val, teq1_pcb_to_name(next_tx->header.PCB.val));
+            next_tx->header.PCB, teq1_pcb_to_name(next_tx->header.PCB));
       return kRuleResultSingleShot; /* So we still can retransmit the original.
                                        */
 
@@ -430,10 +442,10 @@
     case TEQ1_RULE(I(1, 0), R(0, 0, 1)):
     case TEQ1_RULE(I(1, 0), R(0, 1, 0)):
     case TEQ1_RULE(I(1, 0), R(0, 1, 1)):
-      next_tx->header.PCB.val = R(0, 0, 0);
-      next_tx->header.PCB.R.next_seq = tx_frame->header.PCB.I.send_seq;
+      next_tx->header.PCB =
+          TEQ1_R(bs_get(PCB.I.send_seq, tx_frame->header.PCB), 0, 0);
       ALOGV("Rule 7.1,7.5,7.6: weird rx - sending error R: %x = %s",
-            next_tx->header.PCB.val, teq1_pcb_to_name(next_tx->header.PCB.val));
+            next_tx->header.PCB, teq1_pcb_to_name(next_tx->header.PCB));
       return kRuleResultSingleShot;
 
     /* Rule 7.2: Retransmit the _same_ R-block. */
@@ -499,7 +511,7 @@
     case TEQ1_RULE(R(1, 0, 1), S(ABORT, REQUEST)):
     case TEQ1_RULE(R(1, 1, 0), S(ABORT, REQUEST)):
     case TEQ1_RULE(R(1, 1, 1), S(ABORT, REQUEST)):
-      next_tx->header.PCB.val = S(ABORT, REQUEST);
+      next_tx->header.PCB = S(ABORT, REQUEST);
       return kRuleResultContinue; /* Takes over prior flow. */
     case TEQ1_RULE(S(ABORT, RESPONSE), 255):
       return kRuleResultRetransmit;
@@ -515,9 +527,9 @@
      * For supported flows: If an operation was paused to
      * send it, the caller may then switch to that state and resume.
      */
-    if (rx_frame->header.PCB.val != 255) {
+    if (rx_frame->header.PCB != 255) {
       ALOGV("Unexpected frame. Marking error and re-evaluating.");
-      rx_frame->header.PCB.val = 255;
+      rx_frame->header.PCB = 255;
       continue;
     }
 
@@ -531,68 +543,75 @@
  *   if testing becomes onerous given the loop below.
  */
 
-API size_t teq1_transceive(struct EseInterface *ese,
-                           const uint8_t *const tx_buf, size_t tx_len,
-                           uint8_t *rx_buf, size_t rx_len) {
+API uint32_t teq1_transceive(struct EseInterface *ese,
+                             const struct Teq1ProtocolOptions *opts,
+                             const uint8_t *const tx_buf, uint32_t tx_len,
+                             uint8_t *rx_buf, uint32_t rx_len) {
   struct Teq1Frame tx_frame[2];
   struct Teq1Frame rx_frame;
   struct Teq1Frame *tx = &tx_frame[0];
-  int was_reset = 0;
   int active = 0;
-  int done = 0;
+  bool was_reset = false;
+  bool done = false;
   enum RuleResult result = kRuleResultComplete;
-  const struct Teq1ProtocolOptions *opts = ese->ops->opts;
   struct Teq1CardState *card_state = (struct Teq1CardState *)(&ese->pad[0]);
   struct Teq1State init_state =
       TEQ1_INIT_STATE(tx_buf, tx_len, rx_buf, rx_len, card_state);
   struct Teq1State state =
       TEQ1_INIT_STATE(tx_buf, tx_len, rx_buf, rx_len, card_state);
 
+  _static_assert(TEQ1HEADER_SIZE == sizeof(struct Teq1Header),
+                 "Ensure compiler alignment/padding matches wire protocol.");
+  _static_assert(TEQ1FRAME_SIZE == sizeof(struct Teq1Frame),
+                 "Ensure compiler alignment/padding matches wire protocol.");
+
   /* First I-block is always I(0, M). After that, modulo 2. */
-  tx->header.PCB.val = TEQ1_I(!card_state->seq.interface, 0);
+  tx->header.PCB = TEQ1_I(!card_state->seq.interface, 0);
   teq1_fill_info_block(&state, tx);
 
   teq1_trace_header();
   while (!done) {
     /* Populates the node address and LRC prior to attempting to transmit. */
-    teq1_transmit(ese, tx);
+    teq1_transmit(ese, opts, tx);
 
     /* If tx was pointed to the inactive frame for a single shot, restore it
      * now. */
     tx = &tx_frame[active];
 
     /* Clear the RX frame. */
-    memset(&rx_frame, 0xff, sizeof(rx_frame));
+    ese_memset(&rx_frame, 0xff, sizeof(rx_frame));
 
     /* -1 indicates a timeout or failure from hardware. */
-    if (teq1_receive(ese, opts->bwt * (float)state.wait_mult, &rx_frame) < 0) {
+    if (teq1_receive(ese, opts, opts->bwt * (float)state.wait_mult, &rx_frame) <
+        0) {
       /* TODO(wad): If the ese_error(ese) == 1, should this go ahead and fail?
        */
       /* Failures are considered invalid blocks in the rule engine below. */
-      rx_frame.header.PCB.val = 255;
+      rx_frame.header.PCB = 255;
     }
     /* Always reset |wait_mult| once we have calculated the timeout. */
     state.wait_mult = 1;
 
     /* Clear the inactive frame header for use as |next_tx|. */
-    memset(&tx_frame[!active].header, 0, sizeof(tx_frame[!active].header));
+    ese_memset(&tx_frame[!active].header, 0, sizeof(tx_frame[!active].header));
 
     result = teq1_rules(&state, tx, &rx_frame, &tx_frame[!active]);
     ALOGV("[ %s ]", teq1_rule_result_to_name(result));
     switch (result) {
     case kRuleResultComplete:
-      done = 1;
+      done = true;
       break;
     case kRuleResultRetransmit:
       /* TODO(wad) Find a clean way to move into teq1_rules(). */
-      if (state.retransmits++ < 3)
+      if (state.retransmits++ < 3) {
         continue;
-      if (tx->header.PCB.val == S(RESYNC, REQUEST)) {
-        ese_set_error(ese, TEQ1_ERROR_HARD_FAIL);
+      }
+      if (tx->header.PCB == S(RESYNC, REQUEST)) {
+        ese_set_error(ese, kTeq1ErrorHardFail);
         return 0;
       }
       /* Fall through */
-      tx_frame[!active].header.PCB.val = S(RESYNC, REQUEST);
+      tx_frame[!active].header.PCB = S(RESYNC, REQUEST);
     case kRuleResultContinue:
       active = !active;
       tx = &tx_frame[active];
@@ -600,10 +619,10 @@
       state.errors = 0;
       continue;
     case kRuleResultHardFail:
-      ese_set_error(ese, TEQ1_ERROR_HARD_FAIL);
+      ese_set_error(ese, kTeq1ErrorHardFail);
       return 0;
     case kRuleResultAbort:
-      ese_set_error(ese, TEQ1_ERROR_ABORT);
+      ese_set_error(ese, kTeq1ErrorAbort);
       return 0;
     case kRuleResultSingleShot:
       /*
@@ -615,19 +634,19 @@
       continue;
     case kRuleResultResetDevice:
       if (was_reset || !ese->ops->hw_reset || ese->ops->hw_reset(ese) == -1) {
-        ese_set_error(ese, TEQ1_ERROR_DEVICE_RESET);
+        ese_set_error(ese, kTeq1ErrorDeviceReset);
         return 0; /* Don't keep resetting -- hard fail. */
       }
-      was_reset = 1;
+      was_reset = true;
     /* Fall through to session reset. */
     case kRuleResultResetSession:
       /* Roll back state and reset. */
       state = init_state;
       TEQ1_INIT_CARD_STATE(state.card_state);
       /* Reset the active frame. */
-      memset(tx, 0, sizeof(*tx));
+      ese_memset(tx, 0, sizeof(*tx));
       /* Load initial I-block. */
-      tx->header.PCB.val = I(0, 0);
+      tx->header.PCB = I(0, 0);
       teq1_fill_info_block(&state, tx);
       continue;
     }
diff --git a/libese-teq1/teq1_private.h b/libese-teq1/teq1_private.h
index 3151753..6bd3d3c 100644
--- a/libese-teq1/teq1_private.h
+++ b/libese-teq1/teq1_private.h
@@ -25,6 +25,11 @@
 #define API __attribute__ ((visibility("default")))
 #endif  /* API */
 
+/* Mimic C11 _Static_assert behavior for a C99 world. */
+#ifndef _static_assert
+#define _static_assert(what, why) { while (!(1 / (!!(what)))); }
+#endif
+
 /*
  * Enable T=1 format to reduce to case integers.
  * Ensure there are tests to map TEQ1_X() to the shorthand below.
@@ -66,9 +71,9 @@
   struct Teq1CardState *card_state;
   struct {
     uint8_t *tx_buf;
-    size_t tx_len;
+    uint32_t tx_len;
     uint8_t *rx_buf;
-    size_t rx_len;
+    uint32_t rx_len;
   } app_data;
 };
 
@@ -102,8 +107,13 @@
 
 const char *teq1_rule_result_to_name(enum RuleResult result);
 const char *teq1_pcb_to_name(uint8_t pcb);
-int teq1_transmit(struct EseInterface *ese, struct Teq1Frame *frame);
-int teq1_receive(struct EseInterface *ese, float timeout, struct Teq1Frame *frame);
+int teq1_transmit(struct EseInterface *ese,
+                  const struct Teq1ProtocolOptions *opts,
+                  struct Teq1Frame *frame);
+int teq1_receive(struct EseInterface *ese,
+                 const struct Teq1ProtocolOptions *opts,
+                 float timeout,
+                 struct Teq1Frame *frame);
 uint8_t teq1_fill_info_block(struct Teq1State *state, struct Teq1Frame *frame);
 void teq1_get_app_data(struct Teq1State *state, struct Teq1Frame *frame);
 uint8_t teq1_frame_error_check(struct Teq1State *state,
@@ -114,6 +124,8 @@
                            struct Teq1Frame *rx_frame,
                            struct Teq1Frame *next_tx);
 
+#define teq1_dump_transmit(_B, _L) teq1_dump_buf("TX", (_B), (_L))
+#define teq1_dump_receive(_B, _L) teq1_dump_buf("RX", (_B), (_L))
 
 #ifdef __cplusplus
 }  /* extern "C" */
diff --git a/libese-teq1/tests/Android.bp b/libese-teq1/tests/Android.bp
index 9cb2fb4..a54a0af 100644
--- a/libese-teq1/tests/Android.bp
+++ b/libese-teq1/tests/Android.bp
@@ -14,28 +14,13 @@
 // limitations under the License.
 //
 
-cc_defaults {
-    name: "libese_teq1_tests_default",
-    multilib: {
-        lib32: {
-            suffix: "32",
-        },
-        lib64: {
-            suffix: "64",
-        },
-    },
-}
-
-test_libraries = [
-    "libese",
-    "libese-teq1-private",
-    "liblog",
-]
-
 cc_test {
     name: "ese_teq1_unittests",
-    defaults: ["libese_teq1_tests_default"],
     srcs: ["teq1_unittests.cpp"],
     host_supported: true,
-    shared_libs: test_libraries,
+    shared_libs: [
+        "libese",
+        "libese-teq1-private",
+        "liblog",
+    ],
 }
diff --git a/libese-teq1/tests/teq1_unittests.cpp b/libese-teq1/tests/teq1_unittests.cpp
index 77118fa..aef5e0a 100644
--- a/libese-teq1/tests/teq1_unittests.cpp
+++ b/libese-teq1/tests/teq1_unittests.cpp
@@ -36,7 +36,6 @@
 // - Unittests of each function
 // - teq1_rules matches Annex A of ISO 7816-3
 
-
 // Tests teq1_frame_error_check to avoid testing every combo that
 // ends in 255 in the rule engine.
 class Teq1FrameErrorCheck : public virtual Test {
@@ -60,16 +59,16 @@
   /* The PCBs above are all valid for a sent unchained I block with advancing
    * sequence #s.
    */
-  tx_frame_.header.PCB.val = TEQ1_I(0, 0);
+  tx_frame_.header.PCB = TEQ1_I(0, 0);
   state_.card_state = &card_state_;
   state_.card_state->seq.card = 1;
   while (*pcb != 255) {
-    rx_frame_.header.PCB.val = *pcb;
+    rx_frame_.header.PCB = *pcb;
     rx_frame_.header.LEN = 2;
     rx_frame_.INF[0] = 'A';
     rx_frame_.INF[1] = 'B';
     rx_frame_.INF[2] = teq1_compute_LRC(&rx_frame_);
-    EXPECT_EQ(0, teq1_frame_error_check(&state_, &tx_frame_, &rx_frame_)) << teq1_pcb_to_name(rx_frame_.header.PCB.val);
+    EXPECT_EQ(0, teq1_frame_error_check(&state_, &tx_frame_, &rx_frame_)) << teq1_pcb_to_name(rx_frame_.header.PCB);
     rx_frame_.INF[2] = teq1_compute_LRC(&rx_frame_) - 1;
     // Reset so we check the LRC error instead of a wrong seq.
     state_.card_state->seq.card = !state_.card_state->seq.card;
@@ -94,8 +93,9 @@
     tx_data_(INF_LEN, 'A'),
     rx_data_(INF_LEN, 'B'),
     card_state_({ .seq = { .card = 1, .interface = 1, }, }),
-    state_(TEQ1_INIT_STATE(tx_data_.data(), tx_data_.size(),
-                           rx_data_.data(), rx_data_.size(), &card_state_)) {
+    state_(TEQ1_INIT_STATE(tx_data_.data(), static_cast<uint32_t>(tx_data_.size()),
+                           rx_data_.data(), static_cast<uint32_t>(rx_data_.size()),
+                           &card_state_)) {
     memset(&tx_frame_, 0, sizeof(struct Teq1Frame));
     memset(&tx_next_, 0, sizeof(struct Teq1Frame));
     memset(&rx_frame_, 0, sizeof(struct Teq1Frame));
@@ -122,12 +122,12 @@
 class Teq1CompleteTest : public Teq1ErrorFreeTest {
  public:
   virtual void SetUp() {
-    tx_frame_.header.PCB.val = TEQ1_I(0, 0);
+    tx_frame_.header.PCB = TEQ1_I(0, 0);
     teq1_fill_info_block(&state_, &tx_frame_);
     // Check that the tx_data was fully consumed.
     EXPECT_EQ(0UL, state_.app_data.tx_len);
 
-    rx_frame_.header.PCB.val = TEQ1_I(0, 0);
+    rx_frame_.header.PCB = TEQ1_I(0, 0);
     rx_frame_.header.LEN = INF_LEN;
     ASSERT_EQ(static_cast<unsigned long>(INF_LEN), tx_data_.size());  // Catch fixture changes.
     // Supply TX data and make sure it overwrites RX data on consumption.
@@ -137,15 +137,15 @@
 
   virtual void RunRules() {
     teq1_trace_header();
-    teq1_trace_transmit(tx_frame_.header.PCB.val, tx_frame_.header.LEN);
-    teq1_trace_receive(rx_frame_.header.PCB.val, rx_frame_.header.LEN);
+    teq1_trace_transmit(tx_frame_.header.PCB, tx_frame_.header.LEN);
+    teq1_trace_receive(rx_frame_.header.PCB, rx_frame_.header.LEN);
 
     enum RuleResult result = teq1_rules(&state_,  &tx_frame_, &rx_frame_, &tx_next_);
     EXPECT_EQ(0, state_.errors);
     EXPECT_EQ(NULL,  state_.last_error_message)
       << "Last error: " << state_.last_error_message;
-    EXPECT_EQ(0, tx_next_.header.PCB.val)
-      << "Actual next TX: " << teq1_pcb_to_name(tx_next_.header.PCB.val);
+    EXPECT_EQ(0, tx_next_.header.PCB)
+      << "Actual next TX: " << teq1_pcb_to_name(tx_next_.header.PCB);
     EXPECT_EQ(kRuleResultComplete, result)
      << "Actual result name: " << teq1_rule_result_to_name(result);
   }
@@ -171,8 +171,8 @@
 };
 
 TEST_F(Teq1CompleteTest, I10_I10_data) {
-  tx_frame_.header.PCB.val = TEQ1_I(1, 0);
-  rx_frame_.header.PCB.val = TEQ1_I(0, 0);
+  tx_frame_.header.PCB = TEQ1_I(1, 0);
+  rx_frame_.header.PCB = TEQ1_I(0, 0);
   rx_frame_.INF[INF_LEN] = teq1_compute_LRC(&rx_frame_);
   RunRules();
   // Ensure that the rx_frame data was copied out to rx_data.
@@ -184,28 +184,28 @@
 // Note, IFS is not tested as it is not supported on current hardware.
 
 TEST_F(Teq1ErrorFreeTest, I00_WTX0_WTX1_data) {
-  tx_frame_.header.PCB.val = TEQ1_I(0, 0);
+  tx_frame_.header.PCB = TEQ1_I(0, 0);
   teq1_fill_info_block(&state_, &tx_frame_);
   // Check that the tx_data was fully consumed.
   EXPECT_EQ(0UL, state_.app_data.tx_len);
 
-  rx_frame_.header.PCB.val = TEQ1_S_WTX(0);
+  rx_frame_.header.PCB = TEQ1_S_WTX(0);
   rx_frame_.header.LEN = 1;
   rx_frame_.INF[0] = 2; /* Wait x 2 */
   rx_frame_.INF[1] = teq1_compute_LRC(&rx_frame_);
 
   teq1_trace_header();
-  teq1_trace_transmit(tx_frame_.header.PCB.val, tx_frame_.header.LEN);
-  teq1_trace_receive(rx_frame_.header.PCB.val, rx_frame_.header.LEN);
+  teq1_trace_transmit(tx_frame_.header.PCB, tx_frame_.header.LEN);
+  teq1_trace_receive(rx_frame_.header.PCB, rx_frame_.header.LEN);
 
   enum RuleResult result = teq1_rules(&state_,  &tx_frame_, &rx_frame_, &tx_next_);
-  teq1_trace_transmit(tx_next_.header.PCB.val, tx_next_.header.LEN);
+  teq1_trace_transmit(tx_next_.header.PCB, tx_next_.header.LEN);
 
   EXPECT_EQ(0, state_.errors);
   EXPECT_EQ(NULL,  state_.last_error_message)
     << "Last error: " << state_.last_error_message;
-  EXPECT_EQ(TEQ1_S_WTX(1), tx_next_.header.PCB.val)
-    << "Actual next TX: " << teq1_pcb_to_name(tx_next_.header.PCB.val);
+  EXPECT_EQ(TEQ1_S_WTX(1), tx_next_.header.PCB)
+    << "Actual next TX: " << teq1_pcb_to_name(tx_next_.header.PCB);
   EXPECT_EQ(state_.wait_mult, 2);
   EXPECT_EQ(state_.wait_mult, rx_frame_.INF[0]);
   // Ensure the next call will use the original TX frame.
@@ -221,9 +221,9 @@
     state_.app_data.tx_buf = tx_data_.data();
     teq1_fill_info_block(&state_, &tx_frame_);
     // Ensure More bit was set.
-    EXPECT_EQ(1, tx_frame_.header.PCB.I.more_data);
+    EXPECT_EQ(1, bs_get(PCB.I.more_data, tx_frame_.header.PCB));
     // Check that the tx_data was fully consumed.
-    EXPECT_EQ(static_cast<size_t>(oversized_data_len_ - INF_LEN),
+    EXPECT_EQ(static_cast<uint32_t>(oversized_data_len_ - INF_LEN),
               state_.app_data.tx_len);
     // No one is checking the TX LRC since there is no card present.
 
@@ -231,11 +231,11 @@
     rx_frame_.INF[0] = teq1_compute_LRC(&rx_frame_);
 
     teq1_trace_header();
-    teq1_trace_transmit(tx_frame_.header.PCB.val, tx_frame_.header.LEN);
-    teq1_trace_receive(rx_frame_.header.PCB.val, rx_frame_.header.LEN);
+    teq1_trace_transmit(tx_frame_.header.PCB, tx_frame_.header.LEN);
+    teq1_trace_receive(rx_frame_.header.PCB, rx_frame_.header.LEN);
 
     enum RuleResult result = teq1_rules(&state_,  &tx_frame_, &rx_frame_, &tx_next_);
-    teq1_trace_transmit(tx_next_.header.PCB.val, tx_next_.header.LEN);
+    teq1_trace_transmit(tx_next_.header.PCB, tx_next_.header.LEN);
     EXPECT_EQ(0, state_.errors);
     EXPECT_EQ(NULL,  state_.last_error_message)
       << "Last error: " << state_.last_error_message;
@@ -243,7 +243,7 @@
       << "Actual result name: " << teq1_rule_result_to_name(result);
     // Check that the tx_buf was drained already for the next frame.
     // ...
-    EXPECT_EQ(static_cast<size_t>(oversized_data_len_ - (2 * INF_LEN)),
+    EXPECT_EQ(static_cast<uint32_t>(oversized_data_len_ - (2 * INF_LEN)),
               state_.app_data.tx_len);
     // Belt and suspenders: make sure no RX buf was used.
     EXPECT_EQ(rx_data_.size(), state_.app_data.rx_len);
@@ -253,29 +253,29 @@
 
 TEST_F(Teq1ErrorFreeChainingTest, I01_R1_I11_chaining) {
   oversized_data_len_ = INF_LEN * 3;
-  tx_frame_.header.PCB.val = TEQ1_I(0, 0);
-  rx_frame_.header.PCB.val = TEQ1_R(1, 0, 0);
+  tx_frame_.header.PCB = TEQ1_I(0, 0);
+  rx_frame_.header.PCB = TEQ1_R(1, 0, 0);
   RunRules();
-  EXPECT_EQ(TEQ1_I(1, 1), tx_next_.header.PCB.val)
-    << "Actual next TX: " << teq1_pcb_to_name(tx_next_.header.PCB.val);
+  EXPECT_EQ(TEQ1_I(1, 1), tx_next_.header.PCB)
+    << "Actual next TX: " << teq1_pcb_to_name(tx_next_.header.PCB);
 };
 
 TEST_F(Teq1ErrorFreeChainingTest, I11_R0_I01_chaining) {
   oversized_data_len_ = INF_LEN * 3;
-  tx_frame_.header.PCB.val = TEQ1_I(1, 0);
-  rx_frame_.header.PCB.val = TEQ1_R(0, 0, 0);
+  tx_frame_.header.PCB = TEQ1_I(1, 0);
+  rx_frame_.header.PCB = TEQ1_R(0, 0, 0);
   RunRules();
-  EXPECT_EQ(TEQ1_I(0, 1), tx_next_.header.PCB.val)
-    << "Actual next TX: " << teq1_pcb_to_name(tx_next_.header.PCB.val);
+  EXPECT_EQ(TEQ1_I(0, 1), tx_next_.header.PCB)
+    << "Actual next TX: " << teq1_pcb_to_name(tx_next_.header.PCB);
 };
 
 TEST_F(Teq1ErrorFreeChainingTest, I11_R0_I00_chaining) {
   oversized_data_len_ = INF_LEN * 2;  // Exactly 2 frames worth.
-  tx_frame_.header.PCB.val = TEQ1_I(1, 0);
-  rx_frame_.header.PCB.val = TEQ1_R(0, 0, 0);
+  tx_frame_.header.PCB = TEQ1_I(1, 0);
+  rx_frame_.header.PCB = TEQ1_R(0, 0, 0);
   RunRules();
-  EXPECT_EQ(TEQ1_I(0, 0), tx_next_.header.PCB.val)
-    << "Actual next TX: " << teq1_pcb_to_name(tx_next_.header.PCB.val);
+  EXPECT_EQ(TEQ1_I(0, 0), tx_next_.header.PCB)
+    << "Actual next TX: " << teq1_pcb_to_name(tx_next_.header.PCB);
 };
 
 //
@@ -290,19 +290,19 @@
     state_.app_data.rx_len = 0;
     state_.app_data.tx_len = 0;
 
-    tx_frame_.header.PCB.val = TEQ1_I(0, 0);
+    tx_frame_.header.PCB = TEQ1_I(0, 0);
     teq1_fill_info_block(&state_, &tx_frame_);
     // No one is checking the TX LRC since there is no card present.
 
     // Assume the card may not even set the error bit.
     rx_frame_.header.LEN = 0;
-    rx_frame_.header.PCB.val = TEQ1_R(0, 0, 0);
+    rx_frame_.header.PCB = TEQ1_R(0, 0, 0);
     rx_frame_.INF[0] = teq1_compute_LRC(&rx_frame_);
   }
   virtual void TearDown() {
     teq1_trace_header();
-    teq1_trace_transmit(tx_frame_.header.PCB.val, tx_frame_.header.LEN);
-    teq1_trace_receive(rx_frame_.header.PCB.val, rx_frame_.header.LEN);
+    teq1_trace_transmit(tx_frame_.header.PCB, tx_frame_.header.LEN);
+    teq1_trace_receive(rx_frame_.header.PCB, rx_frame_.header.LEN);
 
     enum RuleResult result = teq1_rules(&state_,  &tx_frame_, &rx_frame_, &tx_next_);
     // Not counted as an error as it was on the card-side.
@@ -315,22 +315,22 @@
 };
 
 TEST_F(Teq1Retransmit, I00_R000_I00) {
-  rx_frame_.header.PCB.val = TEQ1_R(0, 0, 0);
+  rx_frame_.header.PCB = TEQ1_R(0, 0, 0);
   rx_frame_.INF[0] = teq1_compute_LRC(&rx_frame_);
 };
 
 TEST_F(Teq1Retransmit, I00_R001_I00) {
-  rx_frame_.header.PCB.val = TEQ1_R(0, 0, 1);
+  rx_frame_.header.PCB = TEQ1_R(0, 0, 1);
   rx_frame_.INF[0] = teq1_compute_LRC(&rx_frame_);
 };
 
 TEST_F(Teq1Retransmit, I00_R010_I00) {
-  rx_frame_.header.PCB.val = TEQ1_R(0, 1, 0);
+  rx_frame_.header.PCB = TEQ1_R(0, 1, 0);
   rx_frame_.INF[0] = teq1_compute_LRC(&rx_frame_);
 };
 
 TEST_F(Teq1Retransmit, I00_R011_I00) {
-  rx_frame_.header.PCB.val = TEQ1_R(0, 1, 1);
+  rx_frame_.header.PCB = TEQ1_R(0, 1, 1);
   rx_frame_.INF[0] = teq1_compute_LRC(&rx_frame_);
 }
 
@@ -339,25 +339,25 @@
   state_.app_data.rx_len = 0;
   state_.app_data.tx_len = 0;
 
-  tx_frame_.header.PCB.val = TEQ1_I(0, 0);
+  tx_frame_.header.PCB = TEQ1_I(0, 0);
   teq1_fill_info_block(&state_, &tx_frame_);
   // No one is checking the TX LRC since there is no card present.
 
-  rx_frame_.header.PCB.val = TEQ1_I(0, 0);
+  rx_frame_.header.PCB = TEQ1_I(0, 0);
   rx_frame_.header.LEN = 0;
   rx_frame_.INF[0] = teq1_compute_LRC(&rx_frame_) - 1;
 
   teq1_trace_header();
-  teq1_trace_transmit(tx_frame_.header.PCB.val, tx_frame_.header.LEN);
-  teq1_trace_receive(rx_frame_.header.PCB.val, rx_frame_.header.LEN);
+  teq1_trace_transmit(tx_frame_.header.PCB, tx_frame_.header.LEN);
+  teq1_trace_receive(rx_frame_.header.PCB, rx_frame_.header.LEN);
 
   enum RuleResult result = teq1_rules(&state_,  &tx_frame_, &rx_frame_, &tx_next_);
   EXPECT_EQ(1, state_.errors);
   const char *kNull = NULL;
   EXPECT_NE(kNull, state_.last_error_message);
   EXPECT_STREQ("Invalid frame received", state_.last_error_message);
-  EXPECT_EQ(TEQ1_R(0, 0, 1), tx_next_.header.PCB.val)
-    << "Actual next TX: " << teq1_pcb_to_name(tx_next_.header.PCB.val);
+  EXPECT_EQ(TEQ1_R(0, 0, 1), tx_next_.header.PCB)
+    << "Actual next TX: " << teq1_pcb_to_name(tx_next_.header.PCB);
   EXPECT_EQ(kRuleResultSingleShot, result)
    << "Actual result name: " << teq1_rule_result_to_name(result);
 };