+
+//====================================================================
+// Forward Link send function
+// Requires: forwarLink_data filled with valid bits (1 bit per byte)
+// fwd_bit_count set with number of bits to be sent
+//====================================================================
+void SendForward(uint8_t fwd_bit_count) {
+
+// iceman, 21.3us increments for the USclock verification.
+// 55FC * 8us == 440us / 21.3 === 20.65 steps. could be too short. Go for 56FC instead
+// 32FC * 8us == 256us / 21.3 == 12.018 steps. ok
+// 16FC * 8us == 128us / 21.3 == 6.009 steps. ok
+
+#ifndef EM_START_GAP
+#define EM_START_GAP 56*8
+#endif
+#ifndef EM_ONE_GAP
+#define EM_ONE_GAP 32*8
+#endif
+#ifndef EM_ZERO_GAP
+# define EM_ZERO_GAP 16*8
+#endif
+
+ fwd_write_ptr = forwardLink_data;
+ fwd_bit_sz = fwd_bit_count;
+
+ // Set up FPGA, 125kHz
+ LFSetupFPGAForADC(95, true);
+
+ // force 1st mod pulse (start gap must be longer for 4305)
+ fwd_bit_sz--; //prepare next bit modulation
+ fwd_write_ptr++;
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ WaitUS(EM_START_GAP);
+
+ TurnReadLFOn(EM_ZERO_GAP);
+
+ // now start writting with bitbanging the antenna.
+ while(fwd_bit_sz-- > 0) { //prepare next bit modulation
+ if(((*fwd_write_ptr++) & 1) == 1)
+ WaitUS(EM_ONE_GAP);
+ else {
+ //These timings work for 4469/4269/4305
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ WaitUS(EM_ZERO_GAP);
+ TurnReadLFOn(EM_ZERO_GAP);
+ }
+ }
+}
+
+void EM4xLogin(uint32_t pwd) {
+ uint8_t len;
+ forward_ptr = forwardLink_data;
+ len = Prepare_Cmd( FWD_CMD_LOGIN );
+ len += Prepare_Data( pwd & 0xFFFF, pwd >> 16 );
+ SendForward(len);
+ WaitMS(20);
+}
+
+void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) {
+
+ LED_A_ON();
+
+ uint8_t len;
+
+ //clear buffer now so it does not interfere with timing later
+ BigBuf_Clear_ext(false);
+
+ if (usepwd) EM4xLogin(pwd);
+
+ forward_ptr = forwardLink_data;
+ len = Prepare_Cmd( FWD_CMD_READ );
+ len += Prepare_Addr( addr );
+
+ SendForward(len);
+
+ DoAcquisition_config(TRUE);
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ cmd_send(CMD_ACK,0,0,0,0,0);
+ LED_A_OFF();
+}
+
+void EM4xWriteWord(uint32_t flag, uint32_t data, uint32_t pwd) {
+
+ LED_A_ON();
+
+ bool usePwd = (flag & 0xF);
+ uint8_t addr = (flag >> 8) & 0xFF;
+ uint8_t len;
+
+ //clear buffer now so it does not interfere with timing later
+ BigBuf_Clear_ext(false);
+
+ if (usePwd) EM4xLogin(pwd);
+
+ forward_ptr = forwardLink_data;
+ len = Prepare_Cmd( FWD_CMD_WRITE );
+ len += Prepare_Addr( addr );
+ len += Prepare_Data( data & 0xFFFF, data >> 16 );
+
+ SendForward(len);
+
+ //Wait 20ms for write to complete
+ WaitMS(20);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ cmd_send(CMD_ACK,0,0,0,0,0);
+ LED_A_OFF();
+}
+
+/*
+Reading a COTAG.
+
+COTAG needs the reader to send a startsequence and the card has an extreme slow datarate.
+because of this, we can "sample" the data signal but we interpreate it to Manchester direct.
+
+READER START SEQUENCE:
+burst 800 us, gap 2.2 msecs
+burst 3.6 msecs gap 2.2 msecs
+burst 800 us gap 2.2 msecs
+pulse 3.6 msecs
+
+This triggers a COTAG tag to response
+*/
+void Cotag(uint32_t arg0) {
+#ifndef OFF
+# define OFF { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(2035); }
+#endif
+#ifndef ON
+# define ON(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); WaitUS((x)); }
+#endif
+ uint8_t rawsignal = arg0 & 0xF;
+
+ LED_A_ON();
+
+ // Switching to LF image on FPGA. This might empty BigBuff
+ FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
+
+ //clear buffer now so it does not interfere with timing later
+ BigBuf_Clear_ext(false);
+
+ // Set up FPGA, 132kHz to power up the tag
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 89);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
+
+ // Connect the A/D to the peak-detected low-frequency path.
+ SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
+
+ // Now set up the SSC to get the ADC samples that are now streaming at us.
+ FpgaSetupSsc();
+
+ // start clock - 1.5ticks is 1us
+ StartTicks();
+
+ //send COTAG start pulse
+ ON(740) OFF
+ ON(3330) OFF
+ ON(740) OFF
+ ON(1000)
+
+ switch(rawsignal) {
+ case 0: doCotagAcquisition(50000); break;
+ case 1: doCotagAcquisitionManchester(); break;
+ case 2: DoAcquisition_config(TRUE); break;
+ }
+
+ // Turn the field off
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
+ cmd_send(CMD_ACK,0,0,0,0,0);
+ LED_A_OFF();
+}
+
+/*
+* EM4305 support
+*/