From 2d42ea1e4dfb86bd9a68bf46354f03a990f85fed Mon Sep 17 00:00:00 2001
From: marshmellow42 <marshmellow42@users.noreply.github.com>
Date: Tue, 21 Mar 2017 03:26:26 -0400
Subject: [PATCH] add bitswap option for lf em 4x05write (#236)

default read mode of this chip outputs in reverse order...  so offer the
option to program in reverse order
---
 client/cmdlfem4x.c | 34 ++++++++++++++++++++--------------
 client/util.c      |  9 +++++++++
 client/util.h      |  1 +
 3 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c
index d2ccfae8..6a076e33 100644
--- a/client/cmdlfem4x.c
+++ b/client/cmdlfem4x.c
@@ -763,9 +763,10 @@ int CmdEM4x05dump(const char *Cmd) {
 int usage_lf_em_write(void) {
 	PrintAndLog("Write EM4x05/EM4x69.  Tag must be on antenna. ");
 	PrintAndLog("");
-	PrintAndLog("Usage:  lf em 4x05writeword [h] <address> <data> <pwd>");
+	PrintAndLog("Usage:  lf em 4x05writeword [h] [s] <address> <data> <pwd>");
 	PrintAndLog("Options:");
 	PrintAndLog("       h         - this help");
+	PrintAndLog("       s         - swap data bit order before write");
 	PrintAndLog("       address   - memory address to write to. (0-15)");
 	PrintAndLog("       data      - data to write (hex)");	
 	PrintAndLog("       pwd       - password (hex) (optional)");
@@ -778,18 +779,23 @@ int usage_lf_em_write(void) {
 int CmdEM4x05WriteWord(const char *Cmd) {
 	uint8_t ctmp = param_getchar(Cmd, 0);
 	if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_write();
-	
+
 	bool usePwd = false;
-		
+
 	uint8_t addr = 16; // default to invalid address
 	uint32_t data = 0xFFFFFFFF; // default to blank data
 	uint32_t pwd = 0xFFFFFFFF; // default to blank password
-	
-	addr = param_get8ex(Cmd, 0, 16, 10);
-	data = param_get32ex(Cmd, 1, 0, 16);
-	pwd =  param_get32ex(Cmd, 2, 1, 16);
-	
-	
+	char swap = 0;
+
+	int p = 0;
+	swap = param_getchar(Cmd, 0);
+	if (swap == 's' || swap=='S') p++;
+	addr = param_get8ex(Cmd, p++, 16, 10);
+	data = param_get32ex(Cmd, p++, 0, 16);
+	pwd  = param_get32ex(Cmd, p++, 1, 16);
+
+	if (swap == 's' || swap=='S') data = SwapBits(data, 32);
+
 	if ( (addr > 15) ) {
 		PrintAndLog("Address must be between 0 and 15");
 		return 1;
@@ -798,15 +804,15 @@ int CmdEM4x05WriteWord(const char *Cmd) {
 		PrintAndLog("Writing address %d data %08X", addr, data);	
 	else {
 		usePwd = true;
-		PrintAndLog("Writing address %d data %08X using password %08X", addr, data, pwd);		
+		PrintAndLog("Writing address %d data %08X using password %08X", addr, data, pwd);
 	}
-	
+
 	uint16_t flag = (addr << 8 ) | usePwd;
-	
+
 	UsbCommand c = {CMD_EM4X_WRITE_WORD, {flag, data, pwd}};
 	clearCommandBuffer();
 	SendCommand(&c);
-	UsbCommand resp;	
+	UsbCommand resp;
 	if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)){
 		PrintAndLog("Error occurred, device did not respond during write operation.");
 		return -1;
@@ -814,7 +820,7 @@ int CmdEM4x05WriteWord(const char *Cmd) {
 	if ( !downloadSamplesEM() ) {
 		return -1;
 	}
-	//check response for 00001010 for write confirmation!	
+	//check response for 00001010 for write confirmation!
 	//attempt demod:
 	uint32_t dummy = 0;
 	int result = demodEM4x05resp(&dummy,false);
diff --git a/client/util.c b/client/util.c
index 81b2d844..7c70d55d 100644
--- a/client/util.c
+++ b/client/util.c
@@ -257,6 +257,15 @@ void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest) {
 	}
 }
 
+// Swap bit order on a uint32_t value.  Can be limited by nrbits just use say 8bits reversal
+// And clears the rest of the bits.
+uint32_t SwapBits(uint32_t value, int nrbits) {
+	uint32_t newvalue = 0;
+	for(int i = 0; i < nrbits; i++) {
+		newvalue ^= ((value >> i) & 1) << (nrbits - 1 - i);
+	}
+	return newvalue;
+}
 
 // aa,bb,cc,dd,ee,ff,gg,hh, ii,jj,kk,ll,mm,nn,oo,pp
 // to
diff --git a/client/util.h b/client/util.h
index 1739498e..27f9348e 100644
--- a/client/util.h
+++ b/client/util.h
@@ -47,6 +47,7 @@ extern uint64_t bytes_to_num(uint8_t* src, size_t len);
 extern void num_to_bytebits(uint64_t	n, size_t len, uint8_t *dest);
 extern void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
 extern char *printBits(size_t const size, void const * const ptr);
+extern uint32_t SwapBits(uint32_t value, int nrbits);
 extern uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
 extern void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest);
 
-- 
2.39.5