+// Function to abstract an Arbitrary length byte array to store bit pattern.
+// bit_array - Array to hold data/bit pattern
+// start_offset - bit location to start storing new bits.
+// data - upto 32 bits of data to store
+// num_bits - how many bits (low x bits of data) Max 32 bits at a time
+// max_len - how many bytes can the bit_array hold (ensure no buffer overflow)
+// returns "Next" bit offset / bits stored (for next store)
+//int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len)
+int T55xx_SetBits (uint8_t *BitStream, uint8_t start_offset, uint32_t data , uint8_t num_bits, uint8_t max_len)
+{
+ int8_t offset;
+ int8_t NextOffset = start_offset;
+
+ // Check if data will fit.
+ if ((start_offset + num_bits) <= (max_len*8)) {
+ // Loop through the data and store
+ for (offset = (num_bits-1); offset >= 0; offset--) {
+
+ if ((data >> offset) & 1) BitStream[BitStream_Byte(NextOffset)] |= (1 << BitStream_Bit(NextOffset)); // Set the bit to 1
+ else BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset))); // Set the bit to 0
+
+ NextOffset++;
+ }
+ }
+ else {
+ // Note: This should never happen unless some code changes cause it.
+ // So short message for coders when testing.
+ Dbprintf ("T55 too many bits");
+ }
+ return NextOffset;
+}
+
+// Send one downlink command to the card
+void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) {
+
+ /*
+ arg bits
+ xxxxxxx1 0x01 PwdMode
+ xxxxxx1x 0x02 Page
+ xxxxx1xx 0x04 testMode
+ xxx11xxx 0x18 downlink mode
+ xx1xxxxx 0x20 !reg_readmode
+ x1xxxxxx 0x40 called for a read, so no data packet
+ 1xxxxxxx 0x80 reset
+
+ */
+ bool PwdMode = ((arg & 0x01) == 0x01);
+ bool Page = (arg & 0x02);
+ bool testMode = ((arg & 0x04) == 0x04);
+ uint8_t downlink_mode = (arg >> 3) & 0x03;
+ bool reg_readmode = ((arg & 0x20) == 0x20);
+ bool read_cmd = ((arg & 0x40) == 0x40);
+ bool reset = (arg & 0x80);
+
+ uint8_t i = 0;
+ uint8_t BitStream[10]; // Max Downlink Command size ~74 bits, so 10 bytes (80 bits)
+ uint8_t BitStreamLen;
+ T55xx_Timing *Timing;
+ uint8_t SendBits;
+
+ // Assigning Downlink Timeing for write
+ switch (downlink_mode)
+ {
+ case T55xx_DLMode_Fixed : Timing = &T55xx_Timing_FixedBit; break;
+ case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break;
+ case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0; break;
+ case T55xx_DLMode_1of4 : Timing = &T55xx_Timing_1of4; break;
+ default:
+ Timing = &T55xx_Timing_FixedBit;
+ }
+
+ // Build Bit Stream to send.
+ memset (BitStream,0x00,sizeof(BitStream));
+
+ BitStreamLen = 0; // Ensure 0 bit index to start.
+
+ // Add Leading 0 and 1 of 4 reference bit
+ if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4))
+ BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream));
+
+ // Add extra reference 0 for 1 of 4
+ if (downlink_mode == T55xx_DLMode_1of4)
+ BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream));
+
+ // Add Opcode
+ if (reset) {
+ // Reset : r*) 00
+ BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream));
+ }
+ else
+ {
+ if (testMode) Dbprintf("TestMODE");
+ BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream));
+ BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream));
+
+ if (PwdMode) {
+ // Leading 0 and 1 of 4 00 fixed bits if passsword used
+ if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) {
+ BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream));
+ }
+ BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream));
+ }
+
+ // Add Lock bit 0
+ if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream));