diff --git a/FEE/smile_fee.h b/FEE/smile_fee.h
index 416901ca5775970f0f6017c91c69135b211e17ec..9d0ffc05f8d0b68b80dfe46d1715f1e7301299ca 100644
--- a/FEE/smile_fee.h
+++ b/FEE/smile_fee.h
@@ -132,9 +132,23 @@ struct fee_event_dection {
 } __attribute__((packed));
 
 
+__extension__
+struct fee_data_pkt {
+	struct fee_data_hdr hdr;
+	uint8_t *data;
+} __attribute__((packed));
 
+__extension__
+struct fee_pattern {
+	union {
+		uint16_t ccd:1;
+		uint16_t side:1;
+		uint16_t row:7;
+		uint16_t col:7;
+		uint16_t pat;
+	};
 
-
+} __attribute__((packed));
 
 
 
diff --git a/FEE/smile_fee_cmd.c b/FEE/smile_fee_cmd.c
index e710447f092ee94c6633e62475422bc743d480fb..92a4466f6c19d9bc1f7dbcf08ec4909999ebdb32 100644
--- a/FEE/smile_fee_cmd.c
+++ b/FEE/smile_fee_cmd.c
@@ -77,8 +77,8 @@ static int fee_read_cmd_register_internal(uint16_t trans_id, uint8_t *cmd,
 static int fee_write_cmd_register_internal(uint16_t trans_id, uint8_t *cmd,
 					    uint32_t addr)
 {
-	return smile_fee_gen_cmd(trans_id, cmd, RMAP_WRITE_ADDR_INC_VERIFY_REPLY,
-			    addr, 4);
+	return smile_fee_gen_cmd(trans_id, cmd, RMAP_WRITE_ADDR_INC_REPLY,
+				 addr, 4);
 }
 
 
diff --git a/FEE/smile_fee_demo.c b/FEE/smile_fee_demo.c
index 2041e0784cf01898bc834a843dabcd7d729ea857..a869a489ef4b7a680808296fa9b978988c3a6369 100644
--- a/FEE/smile_fee_demo.c
+++ b/FEE/smile_fee_demo.c
@@ -28,11 +28,11 @@
 
 #include <gresb.h>
 
+#include <smile_fee.h>
 #include <smile_fee_cfg.h>
 #include <smile_fee_ctrl.h>
 #include <smile_fee_rmap.h>
 
-
 #include <rmap.h>	/* for FEE simulation */
 
 /* whatever for now ... */
@@ -391,6 +391,70 @@ static int32_t rmap_tx(const void *hdr,  uint32_t hdr_size,
 }
 
 
+/**
+ * dirty hack for packet reception, more or less a copy of rmap_rx()
+ */
+
+static uint32_t pkt_rx(uint8_t *pkt)
+{
+	int recv_bytes;
+	static uint32_t pkt_size; /* keep last packet size */
+
+	/* XXX: gresb-to-host header is just 4 bytes, but we need 2 extra in
+	 * order to be able to distinguish between rmap and non-rmap packets
+	 *
+	 *
+	 * NOTE THAT THIS IS A DIRTY HACK FOR THE DEMONSTRATOR ONLY, DO NOT DO
+	 * THIS IN PRODUCTION CODE! EVER!
+	 */
+
+	uint8_t gresb_hdr[4+2];
+
+	uint8_t *recv_buffer;
+
+	if (!pkt) {	/* next packet size requested */
+
+		/* try to grab a header */
+		recv_bytes = recv(bridge_fd, gresb_hdr, 6, MSG_PEEK | MSG_DONTWAIT);
+
+		/* we won't bother, this is a stupid demo, not production code */
+		if (recv_bytes <= 0)
+			return 0;
+
+		/* header is 4 bytes, but we need 6 */
+		if (recv_bytes < (4 + 2))
+			return 0;
+
+		pkt_size = gresb_get_spw_data_size(gresb_hdr);
+
+		/* XXX the protocol id is (or should be) in byte 6 */
+		if (gresb_hdr[5] != FEE_DATA_PROTOCOL)
+			return 0;
+
+		/* tell caller about next packet */
+		return pkt_size;
+	}
+
+	/* we packet space, now start receiving
+	 * note the lack of basic sanity checks...
+	 */
+
+	/* buffer is payload + header */
+	recv_buffer = malloc(pkt_size + 4);
+
+	recv_bytes  = recv(bridge_fd, recv_buffer, pkt_size + 4, 0);
+
+
+	/* the caller supplied their own buffer */
+	memcpy(pkt, gresb_get_spw_data(recv_buffer), pkt_size);
+	free(recv_buffer);
+
+	return pkt_size;
+
+}
+
+
+
 /**
  * rx function for smile_fee_ctrl
  *
@@ -409,27 +473,37 @@ static uint32_t rmap_rx(uint8_t *pkt)
 	int recv_bytes;
 	static uint32_t pkt_size; /* keep last packet size */
 
-	uint8_t gresb_hdr[4];	/* gresb-to-host header is 4 bytes */
+	/* XXX: gresb-to-host header is just 4 bytes, but we need 2 extra in
+	 * order to be able to distinguish between rmap and non-rmap packets
+	 *
+	 *
+	 * NOTE THAT THIS IS A DIRTY HACK FOR THE DEMONSTRATOR ONLY, DO NOT DO
+	 * THIS IN PRODUCTION CODE! EVER!
+	 */
+
+	uint8_t gresb_hdr[4+2];
 
 	uint8_t *recv_buffer;
 
 	if (!pkt) {	/* next packet size requested */
 
 		/* try to grab a header */
-
-		//recv_bytes = recv(bridge_fd, gresb_hdr, 4, MSG_PEEK);
-		recv_bytes = recv(bridge_fd, gresb_hdr, 4, MSG_PEEK | MSG_DONTWAIT);
+		recv_bytes = recv(bridge_fd, gresb_hdr, 6, MSG_PEEK | MSG_DONTWAIT);
 
 		/* we won't bother, this is a stupid demo, not production code */
 		if (recv_bytes <= 0)
 			return 0;
 
-		/* header is 4 bytes... */
-		if (recv_bytes < 4)
+		/* header is 4 bytes, but we need 6 */
+		if (recv_bytes < (4 + 2))
 			return 0;
 
 		pkt_size = gresb_get_spw_data_size(gresb_hdr);
 
+		/* XXX the protocol id is (or should be) in byte 6 */
+		if (gresb_hdr[5] != RMAP_PROTOCOL_ID)
+			return 0;
+
 		/* tell caller about next packet */
 		return pkt_size;
 	}
@@ -530,33 +604,50 @@ static void sync_rmap(void)
 	printf("synced\n\n");
 }
 
-
-
 /**
- * SMILE FEE commanding demonstrator, this would run on the DPU
- * note: all values are random
+ *  procedure Test 1: read a basic FEE register
+ *
  */
 
-static void smile_fee_demo(void)
+static void smile_fee_test1(void)
 {
-	printf("sync vstart from FEE\n");
+	printf("Test1: read a basic FEE register\n");
+
+	printf("sync vstart/vend from FEE\n");
 	smile_fee_sync_vstart(FEE2DPU);
+	sync_rmap();
 
+	printf("vstart: %x, vend %x\n", smile_fee_get_vstart(), smile_fee_get_vend());
+
+	printf("Test1 complete\n\n");
+}
+
+
+/**
+ *  procedure Test 2: read, write & read a basic FEE register
+ *
+ */
+
+static void smile_fee_test2(void)
+{
+	printf("Test 2: read, write & read a basic FEE register\n");
 
 	printf("sync ccd2 e/f single pixel threshold from FEE\n");
 	smile_fee_sync_ccd2_e_pix_treshold(FEE2DPU);
 
 	sync_rmap();
 
-	printf("ccd2 e value now: %x\n", smile_fee_get_ccd2_e_pix_treshold());
-	printf("ccd2 f value now: %x\n", smile_fee_get_ccd2_f_pix_treshold());
-
-
+	printf("ccd2 e value currently: %x\n", smile_fee_get_ccd2_e_pix_treshold());
+	printf("ccd2 f value currently: %x\n", smile_fee_get_ccd2_f_pix_treshold());
 	printf("setting2 ccd e/f local values\n");
+
 	smile_fee_set_ccd2_e_pix_treshold(0x7b);
 	smile_fee_set_ccd2_f_pix_treshold(0x7c);
 
-	printf("syncing ccd2 e/f single pixel thresold to FEE\n");
+	printf("ccd2 e local value now: %x\n", smile_fee_get_ccd2_e_pix_treshold());
+	printf("ccd2 f local value now: %x\n", smile_fee_get_ccd2_f_pix_treshold());
+
+	printf("syncing ccd2 e/f single pixel threshold to FEE\n");
 	smile_fee_sync_ccd2_e_pix_treshold(DPU2FEE);
 
 	sync_rmap();
@@ -565,7 +656,7 @@ static void smile_fee_demo(void)
 	smile_fee_set_ccd2_e_pix_treshold(0x0);
 	smile_fee_set_ccd2_f_pix_treshold(0x0);
 
-	printf("syncing back ccd2 e/f single pixel thresold from FEE\n");
+	printf("syncing back ccd2 e/f single pixel threshold from FEE\n");
 	smile_fee_sync_ccd2_e_pix_treshold(FEE2DPU);
 
 	sync_rmap();
@@ -573,80 +664,127 @@ static void smile_fee_demo(void)
 	printf("ccd1 value now: %x\n", smile_fee_get_ccd2_e_pix_treshold());
 	printf("ccd2 value now: %x\n", smile_fee_get_ccd2_f_pix_treshold());
 
+	printf("Test2 complete\n\n");
+}
 
-	printf("standing by\n");
-	while(1) usleep(1000000); /* stop here for now */
 
+/**
+ *  procedure Test 3: Get 6x6 binned pattern images from "Frame Transfer Pattern
+ *  Mode."
+ *
+ */
 
-	printf("Configuring start of vertical row shared with charge injection\n");
-	smile_fee_set_vstart(35);
 
-	printf("Configuring duration of a parallel overlap period (TOI)\n");
-	smile_fee_set_parallel_toi_period(5);
+static void smile_fee_test3(void)
+{
+	printf("Test 3: 6x6 binned pattern from frame transfer pattern mode\n");
 
 
-	printf("Syncing configured values to FEE via RMAP\n");
-	smile_fee_sync_vstart(DPU2FEE);
-	smile_fee_sync_parallel_toi_period(DPU2FEE);
+	smile_fee_set_packet_size(0x30c);
+	smile_fee_set_int_period(0x0fa0);
 
-	printf("Waiting for sync to complete\n");
-	sync_rmap();
+	/* all above are reg4, this will suffice */
+	smile_fee_sync_packet_size(DPU2FEE);
 
-	printf("Verifying configured values in FEE\n");
+	smile_fee_set_correction_bypass(1);
+	smile_fee_set_digitise(1);
+	smile_fee_set_readout_nodes(3);
 
-	printf("Clearing local values\n");
-	smile_fee_set_vstart(0);
-	smile_fee_set_parallel_toi_period(0);
+	/* all above are reg5, this will suffice */
+	smile_fee_sync_correction_bypass(DPU2FEE);
 
-	printf("Syncing configured values from FEE to DPU via RMAP\n");
-	smile_fee_sync_vstart(FEE2DPU);
-	smile_fee_sync_parallel_toi_period(FEE2DPU);
+	smile_fee_set_ccd_mode_config(0x1);
+	smile_fee_set_ccd_mode2_config(0x2);
+
+	/* all above are reg32, this will suffice */
+	smile_fee_sync_ccd_mode_config(DPU2FEE);
+
+	sync_rmap(); /* make sure all parameters are set */
+
+	/* trigger packet transmission */
+	smile_fee_set_execute_op(0x1);
+	smile_fee_sync_execute_op(DPU2FEE);
 
-	printf("Waiting for sync to complete\n");
 	sync_rmap();
 
+	while (1)
+	{
+		static int ps = 1;	/* times to print everything... */
+		static int pp = 1;	/* times to print everything... */
+		int n, i;
+		struct fee_data_pkt *pkt;
+		struct fee_pattern  *pat;
 
-	printf("Checking values: vertical row shared with charge injection: ");
+		usleep(1000);
 
-	if (smile_fee_get_vstart() == 35)
-		printf("SUCCESS\n");
-	else
-		printf("FAILURE\n");
+		n  = pkt_rx(NULL);
 
+		if (n)
+			pkt = (struct fee_data_pkt *) malloc(n);
+		else
+			continue;
 
-	printf("Checking values: duration of a parallel overlap period (TOI): ");
+		n = pkt_rx((uint8_t *) pkt);
 
-	if (smile_fee_get_parallel_toi_period() == 5)
-		printf("SUCCESS\n");
-	else
-		printf("FAILURE\n");
+		if (n <= 0)
+			printf("Error in pkt_rx()\n");
 
 
-	printf("Setting execute op flag to expedite operational parameters\n");
-	smile_fee_set_execute_op(1);
+		pkt->hdr.data_len   = __be16_to_cpu(pkt->hdr.data_len);
+		pkt->hdr.frame_cntr = __be16_to_cpu(pkt->hdr.frame_cntr);
+		pkt->hdr.seq_cntr   = __be16_to_cpu(pkt->hdr.seq_cntr);
 
-	printf("Syncing execute op flag to FEE via RMAP\n");
-	smile_fee_sync_execute_op(DPU2FEE);
-	printf("Waiting for sync to complete\n");
-	sync_rmap();
+		if (ps) {
+			ps--;
 
+			printf("data type %d len %d frame %d seq %d\n",
+			       pkt->hdr.type.pkt_type,
+			       pkt->hdr.data_len,
+			       pkt->hdr.frame_cntr,
+			       pkt->hdr.seq_cntr);
+		}
 
-	printf("Waiting for FEE to complete operation\n");
+		pat = (struct fee_pattern *) &pkt->data;
+		n = pkt->hdr.data_len / sizeof(struct fee_pattern);
 
-	while (1) {
-		printf("Syncing execute op flag from FEE to DPU via RMAP\n");
-		smile_fee_sync_execute_op(FEE2DPU);
-		printf("Waiting for sync to complete\n");
-		sync_rmap();
+		if (pp) {
+			pp--;
+			printf("n %d\n", n);
+			for (i = 0; i < n; i++) {
+				pat[i].pat = __be16_to_cpu(pat[i].pat);
+				printf("%d %d %d %d\n", pat[i].ccd, pat[i].side, pat[i].row, pat[i].col);
 
-		if (!smile_fee_get_execute_op())
-			break;
+			}
+		}
+
+		/* setup abort ... */
+		if (pkt->hdr.seq_cntr == 2555)	/* gen stops about there? */
+			ps = -1;
 
-		printf("FEE hast not yet completed operation\n");
+		free(pkt);
+
+		/* abort ... */
+		if (ps < 0)
+			break;
 	}
 
+	printf("Test3 complete\n\n");
+}
+
+
+/**
+ * SMILE FEE commanding demonstrator, this would run on the DPU
+ */
+
+static void smile_fee_demo(void)
+{
+	smile_fee_test1();
+	smile_fee_test2();
+	smile_fee_test3();
 
-	printf("FEE operation completed\n");
+
+	printf("standing by\n");
+	while(1) usleep(1000000); /* stop here for now */
 }
 
 
diff --git a/FEE/smile_fee_rmap.c b/FEE/smile_fee_rmap.c
index 13b56399199c4a2ac05c545602d8e2cf071d4801..20cbabcd2f9e0ad2c6193639a68671b9deacf143 100644
--- a/FEE/smile_fee_rmap.c
+++ b/FEE/smile_fee_rmap.c
@@ -558,6 +558,7 @@ int smile_fee_package(uint8_t *blob,
 	case RMAP_WRITE_ADDR_INC_VERIFY:
 	case RMAP_WRITE_ADDR_SINGLE_VERIFY_REPLY:
 	case RMAP_WRITE_ADDR_INC_VERIFY_REPLY:
+	case RMAP_WRITE_ADDR_INC_REPLY:
 		has_data_crc = 1;
 		n += 1;
 		break;
@@ -596,8 +597,8 @@ int smile_fee_package(uint8_t *blob,
 		}
 #endif /* __BYTE_ORDER__ */
 
+	blob[cmd_size + 1 + data_size] = rmap_crc8(&blob[cmd_size + 1], data_size);
 
-		blob[cmd_size + 1 + data_size] = rmap_crc8(data, data_size);
 	} else {
 		/* if no data is present, data crc is 0x0 */
 		if (has_data_crc)