#include "string.h"
#include "lfdemod.h"
#include "lfsampling.h"
-#include "usb_cdc.h"
-
+#include "usb_cdc.h" //test
/**
* Function to do a modulation and then get samples.
}
}
+
+
void WriteTIbyte(uint8_t b)
{
int i = 0;
}
}
+
+
+
// arguments: 64bit data split into 32bit idhi:idlo and optional 16bit crc
// if crc provided, it will be written with the data verbatim (even if bogus)
// if not provided a valid crc will be computed from the data and written.
void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc)
{
+
+
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
if(crc == 0) {
crc = update_crc16(crc, (idlo)&0xff);
for(;;) {
//wait until SSC_CLK goes HIGH
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) {
- if(BUTTON_PRESS() || usb_poll()) {
+ if(BUTTON_PRESS() || (usb_poll_validate_length() )) {
DbpString("Stopped");
return;
}
int ledcontrol = 1;
int n=0, i=0;
uint8_t clk = (arg1 >> 8) & 0xFF;
- uint8_t encoding = arg1 & 1;
+ uint8_t encoding = arg1 & 0xFF;
uint8_t separator = arg2 & 1;
uint8_t invert = (arg2 >> 8) & 1;
void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol)
{
uint8_t *dest = BigBuf_get_addr();
- const size_t sizeOfBigBuff = BigBuf_max_traceLen();
- size_t size = 0;
+ //const size_t sizeOfBigBuff = BigBuf_max_traceLen();
+ size_t size;
uint32_t hi2=0, hi=0, lo=0;
int idx=0;
// Configure to go in 125Khz listen mode
DoAcquisition_default(-1,true);
// FSK demodulator
- size = sizeOfBigBuff; //variable size will change after demod so re initialize it before use
+ //size = sizeOfBigBuff; //variable size will change after demod so re initialize it before use
+ size = 50*128*2; //big enough to catch 2 sequences of largest format
idx = HIDdemodFSK(dest, &size, &hi2, &hi, &lo);
- if (idx>0 && lo>0){
- // final loop, go over previously decoded manchester data and decode into usable tag ID
- // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0
- if (hi2 != 0){ //extra large HID tags
+ if (idx>0 && lo>0 && (size==96 || size==192)){
+ // go over previously decoded manchester data and decode into usable tag ID
+ if (hi2 != 0){ //extra large HID tags 88/192 bits
Dbprintf("TAG ID: %x%08x%08x (%d)",
(unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF);
- }else { //standard HID tags <38 bits
+ }else { //standard HID tags 44/96 bits
//Dbprintf("TAG ID: %x%08x (%d)",(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); //old print cmd
uint8_t bitlen = 0;
uint32_t fc = 0;
return;
}
// reset
- hi2 = hi = lo = 0;
}
+ hi2 = hi = lo = idx = 0;
+ WDT_HIT();
+ }
+ DbpString("Stopped");
+ if (ledcontrol) LED_A_OFF();
+}
+
+// loop to get raw HID waveform then FSK demodulate the TAG ID from it
+void CmdAWIDdemodFSK(int findone, int *high, int *low, int ledcontrol)
+{
+ uint8_t *dest = BigBuf_get_addr();
+ //const size_t sizeOfBigBuff = BigBuf_max_traceLen();
+ size_t size;
+ int idx=0;
+ // Configure to go in 125Khz listen mode
+ LFSetupFPGAForADC(95, true);
+
+ while(!BUTTON_PRESS()) {
+
+ WDT_HIT();
+ if (ledcontrol) LED_A_ON();
+
+ DoAcquisition_default(-1,true);
+ // FSK demodulator
+ //size = sizeOfBigBuff; //variable size will change after demod so re initialize it before use
+ size = 50*128*2; //big enough to catch 2 sequences of largest format
+ idx = AWIDdemodFSK(dest, &size);
+
+ if (idx>0 && size==96){
+ // Index map
+ // 0 10 20 30 40 50 60
+ // | | | | | | |
+ // 01234567 890 1 234 5 678 9 012 3 456 7 890 1 234 5 678 9 012 3 456 7 890 1 234 5 678 9 012 3 - to 96
+ // -----------------------------------------------------------------------------
+ // 00000001 000 1 110 1 101 1 011 1 101 1 010 0 000 1 000 1 010 0 001 0 110 1 100 0 000 1 000 1
+ // premable bbb o bbb o bbw o fff o fff o ffc o ccc o ccc o ccc o ccc o ccc o wxx o xxx o xxx o - to 96
+ // |---26 bit---| |-----117----||-------------142-------------|
+ // b = format bit len, o = odd parity of last 3 bits
+ // f = facility code, c = card number
+ // w = wiegand parity
+ // (26 bit format shown)
+
+ //get raw ID before removing parities
+ uint32_t rawLo = bytebits_to_byte(dest+idx+64,32);
+ uint32_t rawHi = bytebits_to_byte(dest+idx+32,32);
+ uint32_t rawHi2 = bytebits_to_byte(dest+idx,32);
+
+ size = removeParity(dest, idx+8, 4, 1, 88);
+ // ok valid card found!
+
+ // Index map
+ // 0 10 20 30 40 50 60
+ // | | | | | | |
+ // 01234567 8 90123456 7890123456789012 3 456789012345678901234567890123456
+ // -----------------------------------------------------------------------------
+ // 00011010 1 01110101 0000000010001110 1 000000000000000000000000000000000
+ // bbbbbbbb w ffffffff cccccccccccccccc w xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ // |26 bit| |-117--| |-----142------|
+ // b = format bit len, o = odd parity of last 3 bits
+ // f = facility code, c = card number
+ // w = wiegand parity
+ // (26 bit format shown)
+
+ uint32_t fc = 0;
+ uint32_t cardnum = 0;
+ uint32_t code1 = 0;
+ uint32_t code2 = 0;
+ uint8_t fmtLen = bytebits_to_byte(dest,8);
+ if (fmtLen==26){
+ fc = bytebits_to_byte(dest+9, 8);
+ cardnum = bytebits_to_byte(dest+17, 16);
+ code1 = bytebits_to_byte(dest+8,fmtLen);
+ Dbprintf("AWID Found - BitLength: %d, FC: %d, Card: %d - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, rawHi2, rawHi, rawLo);
+ } else {
+ cardnum = bytebits_to_byte(dest+8+(fmtLen-17), 16);
+ if (fmtLen>32){
+ code1 = bytebits_to_byte(dest+8,fmtLen-32);
+ code2 = bytebits_to_byte(dest+8+(fmtLen-32),32);
+ Dbprintf("AWID Found - BitLength: %d -unknown BitLength- (%d) - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo);
+ } else{
+ code1 = bytebits_to_byte(dest+8,fmtLen);
+ Dbprintf("AWID Found - BitLength: %d -unknown BitLength- (%d) - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo);
+ }
+ }
+ if (findone){
+ if (ledcontrol) LED_A_OFF();
+ return;
+ }
+ // reset
+ }
+ idx = 0;
WDT_HIT();
}
DbpString("Stopped");
DoAcquisition_default(-1,true);
size = BigBuf_max_traceLen();
- //Dbprintf("DEBUG: Buffer got");
//askdemod and manchester decode
- errCnt = askmandemod(dest, &size, &clk, &invert, maxErr);
- //Dbprintf("DEBUG: ASK Got");
+ if (size > 16385) size = 16385; //big enough to catch 2 sequences of largest format
+ errCnt = askdemod(dest, &size, &clk, &invert, maxErr, 0, 1);
WDT_HIT();
- if (errCnt>=0){
- errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo);
- //Dbprintf("DEBUG: EM GOT");
- if (errCnt){
- if (size>64){
- Dbprintf("EM XL TAG ID: %06x%08x%08x - (%05d_%03d_%08d)",
- hi,
- (uint32_t)(lo>>32),
- (uint32_t)lo,
- (uint32_t)(lo&0xFFFF),
- (uint32_t)((lo>>16LL) & 0xFF),
- (uint32_t)(lo & 0xFFFFFF));
- } else {
- Dbprintf("EM TAG ID: %02x%08x - (%05d_%03d_%08d)",
- (uint32_t)(lo>>32),
- (uint32_t)lo,
- (uint32_t)(lo&0xFFFF),
- (uint32_t)((lo>>16LL) & 0xFF),
- (uint32_t)(lo & 0xFFFFFF));
- }
+ if (errCnt<0) continue;
+
+ errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo);
+ if (errCnt){
+ if (size>64){
+ Dbprintf("EM XL TAG ID: %06x%08x%08x - (%05d_%03d_%08d)",
+ hi,
+ (uint32_t)(lo>>32),
+ (uint32_t)lo,
+ (uint32_t)(lo&0xFFFF),
+ (uint32_t)((lo>>16LL) & 0xFF),
+ (uint32_t)(lo & 0xFFFFFF));
+ } else {
+ Dbprintf("EM TAG ID: %02x%08x - (%05d_%03d_%08d)",
+ (uint32_t)(lo>>32),
+ (uint32_t)lo,
+ (uint32_t)(lo&0xFFFF),
+ (uint32_t)((lo>>16LL) & 0xFF),
+ (uint32_t)(lo & 0xFFFFFF));
}
+
if (findone){
if (ledcontrol) LED_A_OFF();
*high=lo>>32;
*low=lo & 0xFFFFFFFF;
return;
}
- } else{
- //Dbprintf("DEBUG: No Tag");
}
WDT_HIT();
- hi = 0;
- lo = 0;
- clk=0;
- invert=0;
- errCnt=0;
- size=0;
+ hi = lo = size = idx = 0;
+ clk = invert = errCnt = 0;
}
DbpString("Stopped");
if (ledcontrol) LED_A_OFF();
//fskdemod and get start index
WDT_HIT();
idx = IOdemodFSK(dest, BigBuf_max_traceLen());
- if (idx>0){
- //valid tag found
-
- //Index map
- //0 10 20 30 40 50 60
- //| | | | | | |
- //01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23
- //-----------------------------------------------------------------------------
- //00000000 0 11110000 1 facility 1 version* 1 code*one 1 code*two 1 ???????? 11
- //
- //XSF(version)facility:codeone+codetwo
- //Handle the data
- if(findone){ //only print binary if we are doing one
- Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx], dest[idx+1], dest[idx+2],dest[idx+3],dest[idx+4],dest[idx+5],dest[idx+6],dest[idx+7],dest[idx+8]);
- Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+9], dest[idx+10],dest[idx+11],dest[idx+12],dest[idx+13],dest[idx+14],dest[idx+15],dest[idx+16],dest[idx+17]);
- Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+18],dest[idx+19],dest[idx+20],dest[idx+21],dest[idx+22],dest[idx+23],dest[idx+24],dest[idx+25],dest[idx+26]);
- Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+27],dest[idx+28],dest[idx+29],dest[idx+30],dest[idx+31],dest[idx+32],dest[idx+33],dest[idx+34],dest[idx+35]);
- Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+36],dest[idx+37],dest[idx+38],dest[idx+39],dest[idx+40],dest[idx+41],dest[idx+42],dest[idx+43],dest[idx+44]);
- Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+45],dest[idx+46],dest[idx+47],dest[idx+48],dest[idx+49],dest[idx+50],dest[idx+51],dest[idx+52],dest[idx+53]);
- Dbprintf("%d%d%d%d%d%d%d%d %d%d",dest[idx+54],dest[idx+55],dest[idx+56],dest[idx+57],dest[idx+58],dest[idx+59],dest[idx+60],dest[idx+61],dest[idx+62],dest[idx+63]);
- }
- code = bytebits_to_byte(dest+idx,32);
- code2 = bytebits_to_byte(dest+idx+32,32);
- version = bytebits_to_byte(dest+idx+27,8); //14,4
- facilitycode = bytebits_to_byte(dest+idx+18,8) ;
- number = (bytebits_to_byte(dest+idx+36,8)<<8)|(bytebits_to_byte(dest+idx+45,8)); //36,9
-
- Dbprintf("XSF(%02d)%02x:%05d (%08x%08x)",version,facilitycode,number,code,code2);
- // if we're only looking for one tag
- if (findone){
- if (ledcontrol) LED_A_OFF();
- //LED_A_OFF();
- *high=code;
- *low=code2;
- return;
- }
- code=code2=0;
- version=facilitycode=0;
- number=0;
- idx=0;
+ if (idx<0) continue;
+ //valid tag found
+
+ //Index map
+ //0 10 20 30 40 50 60
+ //| | | | | | |
+ //01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23
+ //-----------------------------------------------------------------------------
+ //00000000 0 11110000 1 facility 1 version* 1 code*one 1 code*two 1 ???????? 11
+ //
+ //XSF(version)facility:codeone+codetwo
+ //Handle the data
+ if(findone){ //only print binary if we are doing one
+ Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx], dest[idx+1], dest[idx+2],dest[idx+3],dest[idx+4],dest[idx+5],dest[idx+6],dest[idx+7],dest[idx+8]);
+ Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+9], dest[idx+10],dest[idx+11],dest[idx+12],dest[idx+13],dest[idx+14],dest[idx+15],dest[idx+16],dest[idx+17]);
+ Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+18],dest[idx+19],dest[idx+20],dest[idx+21],dest[idx+22],dest[idx+23],dest[idx+24],dest[idx+25],dest[idx+26]);
+ Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+27],dest[idx+28],dest[idx+29],dest[idx+30],dest[idx+31],dest[idx+32],dest[idx+33],dest[idx+34],dest[idx+35]);
+ Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+36],dest[idx+37],dest[idx+38],dest[idx+39],dest[idx+40],dest[idx+41],dest[idx+42],dest[idx+43],dest[idx+44]);
+ Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+45],dest[idx+46],dest[idx+47],dest[idx+48],dest[idx+49],dest[idx+50],dest[idx+51],dest[idx+52],dest[idx+53]);
+ Dbprintf("%d%d%d%d%d%d%d%d %d%d",dest[idx+54],dest[idx+55],dest[idx+56],dest[idx+57],dest[idx+58],dest[idx+59],dest[idx+60],dest[idx+61],dest[idx+62],dest[idx+63]);
+ }
+ code = bytebits_to_byte(dest+idx,32);
+ code2 = bytebits_to_byte(dest+idx+32,32);
+ version = bytebits_to_byte(dest+idx+27,8); //14,4
+ facilitycode = bytebits_to_byte(dest+idx+18,8);
+ number = (bytebits_to_byte(dest+idx+36,8)<<8)|(bytebits_to_byte(dest+idx+45,8)); //36,9
+
+ Dbprintf("XSF(%02d)%02x:%05d (%08x%08x)",version,facilitycode,number,code,code2);
+ // if we're only looking for one tag
+ if (findone){
+ if (ledcontrol) LED_A_OFF();
+ //LED_A_OFF();
+ *high=code;
+ *low=code2;
+ return;
}
+ code=code2=0;
+ version=facilitycode=0;
+ number=0;
+ idx=0;
+
WDT_HIT();
}
DbpString("Stopped");
* To compensate antenna falling times shorten the write times
* and enlarge the gap ones.
*/
-#define START_GAP 50*8 // 10 - 50fc 250
-#define WRITE_GAP 20*8 // - 30fc 160
-#define WRITE_0 24*8 // 16 - 63fc 54fc 144
-#define WRITE_1 54*8 // 48 - 63fc 54fc 432 for T55x7; 448 for E5550 //400
+#define START_GAP 31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc)
+#define WRITE_GAP 20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc)
+#define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc)
+#define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550
#define T55xx_SAMPLES_SIZE 12000 // 32 x 32 x 10 (32 bit times numofblock (7), times clock skip..)
if(num_blocks == 4) break;
}
memcpy(outBlocks, Blocks, 16*num_blocks);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+
return num_blocks;
}
Dbprintf("Memory content:");
Dbprintf("-----------------------------------------");
for(i=0; i<max_blocks; i++) {
- if(Blocks[i][ALLOC]==1)
+ if(Blocks[i][ALLOC]==1){
Dbprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
Blocks[i][0], Blocks[i][1], Blocks[i][2], Blocks[i][3], Blocks[i][4], Blocks[i][5], Blocks[i][6], Blocks[i][7],
Blocks[i][8], Blocks[i][9], Blocks[i][10], Blocks[i][11], Blocks[i][12], Blocks[i][13], Blocks[i][14], Blocks[i][15]);
- else
+ }else
Dbprintf("<missing block %d>", i);
}
Dbprintf("-----------------------------------------");
+
return ;
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
LED_D_OFF();
}
+
+
+#define T0_PCF 8 //period for the pcf7931 in us
+
+/* Write on a byte of a PCF7931 tag
+ * @param address : address of the block to write
+ @param byte : address of the byte to write
+ @param data : data to write
+ */
+void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data)
+{
+
+ uint32_t tab[1024]={0}; // data times frame
+ uint32_t u = 0;
+ uint8_t parity = 0;
+ bool comp = 0;
+
+
+ //BUILD OF THE DATA FRAME
+
+ //alimentation of the tag (time for initializing)
+ AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab);
+
+ //PMC
+ Dbprintf("Initialization delay : %d us", init_delay);
+ AddPatternPCF7931(8192/2*T0_PCF + 319*T0_PCF+70, 3*T0_PCF, 29*T0_PCF, tab);
+
+ Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p);
+
+ //password indication bit
+ AddBitPCF7931(1, tab, l, p);
+
+
+ //password (on 56 bits)
+ Dbprintf("Password (LSB first on each byte) : %02x %02x %02x %02x %02x %02x %02x", pass1,pass2,pass3,pass4,pass5,pass6,pass7);
+ AddBytePCF7931(pass1, tab, l, p);
+ AddBytePCF7931(pass2, tab, l, p);
+ AddBytePCF7931(pass3, tab, l, p);
+ AddBytePCF7931(pass4, tab, l, p);
+ AddBytePCF7931(pass5, tab, l, p);
+ AddBytePCF7931(pass6, tab, l, p);
+ AddBytePCF7931(pass7, tab, l, p);
+
+
+ //programming mode (0 or 1)
+ AddBitPCF7931(0, tab, l, p);
+
+ //block adress on 6 bits
+ Dbprintf("Block address : %02x", address);
+ for (u=0; u<6; u++)
+ {
+ if (address&(1<<u)) { // bit 1
+ parity++;
+ AddBitPCF7931(1, tab, l, p);
+ } else{ // bit 0
+ AddBitPCF7931(0, tab, l, p);
+ }
+ }
+
+ //byte address on 4 bits
+ Dbprintf("Byte address : %02x", byte);
+ for (u=0; u<4; u++)
+ {
+ if (byte&(1<<u)) { // bit 1
+ parity++;
+ AddBitPCF7931(1, tab, l, p);
+ } else{ // bit 0
+ AddBitPCF7931(0, tab, l, p);
+ }
+ }
+
+ //data on 8 bits
+ Dbprintf("Data : %02x", data);
+ for (u=0; u<8; u++)
+ {
+ if (data&(1<<u)) { // bit 1
+ parity++;
+ AddBitPCF7931(1, tab, l, p);
+ } else{ //bit 0
+ AddBitPCF7931(0, tab, l, p);
+ }
+ }
+
+
+ //parity bit
+ if((parity%2)==0){
+ AddBitPCF7931(0, tab, l, p); //even parity
+ }else{
+ AddBitPCF7931(1, tab, l, p);//odd parity
+ }
+
+ //time access memory
+ AddPatternPCF7931(5120+2680, 0, 0, tab);
+
+ //conversion of the scale time
+ for(u=0;u<500;u++){
+ tab[u]=(tab[u] * 3)/2;
+ }
+
+
+ //compennsation of the counter reload
+ while (!comp){
+ comp = 1;
+ for(u=0;tab[u]!=0;u++){
+ if(tab[u] > 0xFFFF){
+ tab[u] -= 0xFFFF;
+ comp = 0;
+ }
+ }
+ }
+
+ SendCmdPCF7931(tab);
+}
+
+
+
+/* Send a trame to a PCF7931 tags
+ * @param tab : array of the data frame
+ */
+
+void SendCmdPCF7931(uint32_t * tab){
+ uint16_t u=0;
+ uint16_t tempo=0;
+
+ Dbprintf("SENDING DATA FRAME...");
+
+ FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
+
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU );
+
+ LED_A_ON();
+
+ // steal this pin from the SSP and use it to control the modulation
+ AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
+ AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
+
+ //initialization of the timer
+ AT91C_BASE_PMC->PMC_PCER |= (0x1 << 12) | (0x1 << 13) | (0x1 << 14);
+ AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
+ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
+ AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; //clock at 48/32 MHz
+ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
+ AT91C_BASE_TCB->TCB_BCR = 1;
+
+
+ tempo = AT91C_BASE_TC0->TC_CV;
+ for(u=0;tab[u]!= 0;u+=3){
+
+
+ // modulate antenna
+ HIGH(GPIO_SSC_DOUT);
+ while(tempo != tab[u]){
+ tempo = AT91C_BASE_TC0->TC_CV;
+ }
+
+ // stop modulating antenna
+ LOW(GPIO_SSC_DOUT);
+ while(tempo != tab[u+1]){
+ tempo = AT91C_BASE_TC0->TC_CV;
+ }
+
+
+ // modulate antenna
+ HIGH(GPIO_SSC_DOUT);
+ while(tempo != tab[u+2]){
+ tempo = AT91C_BASE_TC0->TC_CV;
+ }
+
+
+ }
+
+ LED_A_OFF();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ SpinDelay(200);
+
+
+ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
+ DbpString("FINISH !");
+ DbpString("(Could be usefull to send the same trame many times)");
+ LED(0xFFFF, 1000);
+}
+
+
+/* Add a byte for building the data frame of PCF7931 tags
+ * @param b : byte to add
+ * @param tab : array of the data frame
+ * @param l : offset on low pulse width
+ * @param p : offset on low pulse positioning
+ */
+
+bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p){
+
+ uint32_t u;
+ for (u=0; u<8; u++)
+ {
+ if (byte&(1<<u)) { //bit à 1
+ if(AddBitPCF7931(1, tab, l, p)==1)return 1;
+ } else { //bit à 0
+ if(AddBitPCF7931(0, tab, l, p)==1)return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Add a bits for building the data frame of PCF7931 tags
+ * @param b : bit to add
+ * @param tab : array of the data frame
+ * @param l : offset on low pulse width
+ * @param p : offset on low pulse positioning
+ */
+bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p){
+ uint8_t u = 0;
+
+ for(u=0;tab[u]!=0;u+=3){} //we put the cursor at the last value of the array
+
+
+ if(b==1){ //add a bit 1
+ if(u==0) tab[u] = 34*T0_PCF+p;
+ else tab[u] = 34*T0_PCF+tab[u-1]+p;
+
+ tab[u+1] = 6*T0_PCF+tab[u]+l;
+ tab[u+2] = 88*T0_PCF+tab[u+1]-l-p;
+ return 0;
+ }else{ //add a bit 0
+
+ if(u==0) tab[u] = 98*T0_PCF+p;
+ else tab[u] = 98*T0_PCF+tab[u-1]+p;
+
+ tab[u+1] = 6*T0_PCF+tab[u]+l;
+ tab[u+2] = 24*T0_PCF+tab[u+1]-l-p;
+ return 0;
+ }
+
+
+ return 1;
+}
+
+/* Add a custom pattern in the data frame
+ * @param a : delay of the first high pulse
+ * @param b : delay of the low pulse
+ * @param c : delay of the last high pulse
+ * @param tab : array of the data frame
+ */
+bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab){
+ uint32_t u = 0;
+ for(u=0;tab[u]!=0;u+=3){} //we put the cursor at the last value of the array
+
+ if(u==0) tab[u] = a;
+ else tab[u] = a + tab[u-1];
+
+ tab[u+1] = b+tab[u];
+ tab[u+2] = c+tab[u+1];
+
+ return 0;
+}
\ No newline at end of file