diff --git a/Pcie40Applications/pcie40_ul_lib.cpp b/Pcie40Applications/pcie40_ul_lib.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..289d2f7bedf2c336f6be79d2e64c4e52b531147a
--- /dev/null
+++ b/Pcie40Applications/pcie40_ul_lib.cpp
@@ -0,0 +1,380 @@
+#include "pcie40_ul_lib.h"
+
+int crc_calc( int * crc, unsigned int * data ){ 
+  int byte1, byte2, byte3, byte4 ;
+  byte1 = (*data) & 0xFF;
+  byte2 = ( (*data) & 0xFF00 ) >> 8;
+  byte3 = ( (*data) & 0xFF0000 ) >> 16;
+  byte4 = ( (*data) & 0xFF000000 ) >> 24;
+  *crc = ((((*crc))<<8)&0xff00) ^ CRC16_XMODEM_TABLE[((((*crc))>>8)&0xff)^byte4] ;
+  *crc = ((((*crc))<<8)&0xff00) ^ CRC16_XMODEM_TABLE[((((*crc))>>8)&0xff)^byte3] ;
+  *crc = ((((*crc))<<8)&0xff00) ^ CRC16_XMODEM_TABLE[((((*crc))>>8)&0xff)^byte2] ;
+  *crc = ((((*crc))<<8)&0xff00) ^ CRC16_XMODEM_TABLE[((((*crc))>>8)&0xff)^byte1] ;
+}
+
+
+int crc_calc_event( unsigned int* data, int start_pos ){
+  int i = 0;
+  int cur_pos = start_pos;
+  int first_crc ;
+  int crc = 0xffff ;
+  int size = data[ cur_pos % DMASIZE ];
+
+  int good_flag = 0;
+
+  if( size > 0xffff || size <= 0 ){
+    printf("Invalid total event size %.8x\n", size);
+    return -1;
+  }
+
+  /* printf( "TRL %.8x %.8x %.8x\n",  */
+  /* 	  data[ ( cur_pos + size - 1 + DMASIZE ) % DMASIZE ],  */
+  /* 	  data[ ( cur_pos + 1 + size ) % DMASIZE ],  */
+  /* 	  data[ ( cur_pos + 2 + size ) % DMASIZE ] );  */
+
+  cur_pos = start_pos + 4;
+  unsigned int ctime = data[ cur_pos % DMASIZE ];
+
+  cur_pos = start_pos + 3;
+  unsigned int evenum = data[ cur_pos % DMASIZE ];
+  cur_pos = start_pos + 5;
+  unsigned int utime = data[ cur_pos % DMASIZE ];
+  cur_pos = start_pos + 2;
+  unsigned int exp_run = data[ cur_pos % DMASIZE ] ;
+
+  int offset = 8; // size of ROB header [words]
+
+  int link_num = 0;
+
+
+  crc_calc( &crc, &ctime );
+  crc_calc( &crc, &evenum );
+  crc_calc( &crc, &utime );
+  crc_calc( &crc, &exp_run );
+  first_crc = crc ;
+
+  
+#ifdef DEBUG
+  printf("Start\n");
+  for( i = start_pos ; i < start_pos + size ; i++){
+    printf("%.8x\n", data[ i % DMASIZE ] );
+  }
+  printf("End\n");
+#endif
+  int bad = 0;
+  
+  while( offset + 4 < size ){ // 4 = ROB trailer size
+    cur_pos = start_pos + offset;
+    int size_link = data[ cur_pos % DMASIZE ] & 0x000ffff ;
+    if ( 0 >= size_link || size_link > 10000000 ){
+      printf("[ERROR] Invalid size per link (%.8x words): link num %d\n", size_link, link_num);
+      return -1 ; // it could be that the memory was read
+    } 
+
+    //
+    // Calculation of CRC
+    //
+    crc = first_crc ;
+#ifdef DEBUG
+    printf("%.8x %.8x crc %.8x\n", data[ ( start_pos + offset ) % DMASIZE ], data[ ( start_pos + offset + 1 ) % DMASIZE ], crc );
+#endif
+    for ( cur_pos = start_pos + offset + 2 ; cur_pos < start_pos + offset + size_link -2; ++cur_pos ) {
+      crc_calc( &crc, &data[ cur_pos % DMASIZE ] );
+#ifdef DEBUG
+      printf("crc %.8x data %.8x\n", crc, data[ cur_pos % DMASIZE ] );
+#endif
+    }
+#ifdef DEBUG
+    printf("%.8x %.8x\n", data[ ( cur_pos ) % DMASIZE ], data[ ( cur_pos + 1 ) % DMASIZE ]);
+#endif
+    //    cur_pos = start_pos +  8 + size_link -2;
+    cur_pos = start_pos + offset + size_link -2;
+#ifdef DEBUG
+    printf("calcd %.4x data %.4x\n", crc, data[ cur_pos % DMASIZE ] & 0xffff );
+#endif
+
+    //
+    // Check of CRC
+    //
+    if( ( crc & 0xffff ) != ( data[ cur_pos % DMASIZE ] & 0xffff ) ){
+      printf("%.2d Bad  ! calcd %.4x data %.4x offset %.4x size %.4x szlnk %.4x trl %.8x\n", 
+	     link_num, crc, data[ cur_pos % DMASIZE ] & 0xffff, offset, size, size_link, data[ (cur_pos+1) % DMASIZE ] );
+      bad = 1;
+
+    }else{
+      good_flag = 1;
+       // printf("%.2d Good ! calcd %.4x data %.4x offset %.4x size %.4x szlnk %.4x trl %.8x\n",  
+       // 	      link_num, crc, data[ cur_pos % DMASIZE ] & 0xffff, offset, size, size_link, data[ (cur_pos+1) % DMASIZE ] ); 
+
+    }
+    link_num++;
+    offset += size_link;
+  }
+
+  if( bad ){
+  //  if( evenum > 50000 ){
+    //  if( 1 ){
+    for( i = 0 ; i < size ; i++){
+      printf("%.8x ", data[ ( start_pos  + i ) % DMASIZE ] );
+      if( i % 8 == 7 ) printf("\n");
+    }
+    printf("\n");
+    good_flag = -2;
+  }
+  return good_flag;
+     
+}
+
+  int decode_data_wUL( unsigned int * data , unsigned int * ce , int * crc , int * run , 
+		       int * bad , int *evn , int * retry , int * pctime , int * putime , 
+		       int * nmissed ) { 
+
+    int magic; 
+    int size, size_link;
+    int ix ;
+
+    int offset; 
+    unsigned int exp_run, evenum, ctime, utime; 
+    int start_pos = *ce;
+    int cnt = 0;
+    int cur_pos = *ce + 1;
+    int ret = 0;
+    
+    while( !( ( ( magic = data[ cur_pos % DMASIZE ] ) & 0xffff0000 ) != 0x7f7f0000 ) ){
+      usleep(1000);
+      cnt++;
+      //
+      // Scan to find x"7f7f...."
+      //
+      if( cnt > 10 ){
+	cnt = 0;
+	int j = 0 ; 
+	for ( j = 0 ; j < DMASIZE ; ++j ) { 
+	  if ( ( ( data[ ( cur_pos + j ) % DMASIZE ] & 0xffff0000 ) == 0x7f7f0000 ) ){
+	    evenum = data[ ( cur_pos + j + 2 ) % DMASIZE ];
+	    if( evenum > *evn ){
+	      *evn = evenum;
+	      cur_pos = ( cur_pos + j - 1 + DMASIZE ) % DMASIZE;
+	      size = data[ cur_pos ] ;
+	      *ce = ( cur_pos + size ) % DMASIZE;
+	      printf( "New Event number prev %d new %d pos %d size %d\n" , *evn ,  evenum, cur_pos, size );
+	      crc_calc_event( data, cur_pos );
+
+	    }else{
+	      printf( "Old Event number prev %d new %d pos %d\n" , *evn ,  evenum, ( cur_pos + j - 1 + DMASIZE ) % DMASIZE );
+	      break;
+	    }
+	  }else{
+	    continue;
+	  }
+	}
+      }
+    }
+
+    return size ;
+  }
+
+int readout(){
+//  int main (int argc ,char** argv) {
+    // Stop trigger
+    /* system( "ssh robbep@vme \"resetft -53\"" ) ; */
+    /* sleep( 2 ) ;  */
+
+    int res = ecs_open( 0 , 0 ) ;
+    if ( -1 == res ) printf("ERROR: Could not open device (BAR 0)\n") ;
+    else printf("SUCCESS: Device opened for DMA\n");
+    res = ecs_open( 0 , 2 ) ;
+    // ecs_write( 0 , 2 ,  0x000501A0 , 0x0 ) ;
+    ecs_write( 0 , 2 ,  0x000501A0 , 0x1 ) ;
+    pcie40_b2dmabufferreset( 0 ) ; 
+    // Start trigger
+    //  fp = popen( "ssh robbep@vme \"trigft -53 pulse 1000 -1\"" , "r" ) ;
+    // sleep( 2 ) ;
+    /* while( fgets( buf , sizeof(buf) , fp ) != NULL ) {  */
+    /*   // printf( "A= %d\n" , strncmp( exp , buf , 3 ) ) ; */
+    /*   //    printf( strncmp( &buf[0] , 'exp' , 1 ) ) ; */
+    /*   tmp = strdup( buf ) ; */
+    /*   if ( strncmp( exp , buf , 3 ) == 0 ) { */
+    /*     //printf( '%s\n' , buf )  ; */
+    /*     // printf( "ICI\n" ) ; */
+    /*     ptr = strtok( tmp , " " ) ; */
+    /*     ptr = strtok( NULL , " " ) ; */
+    /*     ptr = strtok( NULL , " " ) ; */
+    /*     ptr = strtok( NULL , " " ) ; */
+    /*     // while ( ptr != NULL ) { */
+    /*     run = atoi( ptr ) ;  */
+    /*     //	ptr = strtok( NULL , " " ) ;  */
+    /*   } */
+    /*     //} */
+    /* } */
+    /* pclose( fp ) ; */
+    //sleep( 2 ) ; 
+
+    int run  = 0 ; 
+    FILE* fp; 
+    char * ptr ;
+    char * tmp ;
+    char buf[1000] ;
+    char exp[] = "exp" ; 
+
+    unsigned int * data ; 
+    double time_spent ;
+    int retry ;
+    int bad ;
+    int evn ;
+    evn = 0  ;
+    bad = 0 ;
+    retry = 0 ;
+    int pctime, putime ; 
+    pctime = 0 ;
+    putime = 0 ;
+
+    int i ;
+    int size, size_256, currentEventIndex, crc, nErr, nEvt, nRetry, nMissed ;
+    currentEventIndex = 0 ;
+    nErr = 0 ;
+    nEvt = 0 ;
+    nRetry = 0 ;
+    nMissed = 0 ;
+    int read_dma = 1 ; 
+    clock_t begin = clock() ;
+    int size_zero_cnt = 0;
+
+    int start_flag = 1;
+
+    int magic; 
+    int size_link;
+
+    int offset; 
+    unsigned int next_exp_run, cur_exp_run = 0, evenum, ctime, utime, first_eve = 0; 
+    int start_pos = 0;
+    int cnt = 0;
+    int eve_cnt = 0, first_event_flag = 0, crc_err_eve_cnt = 0;
+    
+    
+    int cur_pos = 0;
+    int ret = 0;
+    unsigned int cur_eve = 0, next_eve = 0;
+    int mod_pos = 0;
+
+    //    if ( ( nEvt % 1000 == 1 ) && ( size != 0 ) ) printf( "Event number %d\n", nEvt ) ;
+
+    //
+    // Read the 1st data
+    //
+    if ( read_dma == 1 ) { 
+      // set busy
+      //res = ecs_write( 0 , 2 ,  0x000501A0 , 0x1 ) ;
+      //sleep(5);
+      res = pcie40_b2dmapointerread( 0 , &data ) ;
+      if ( start_flag == 1 ){
+	ecs_write( 0 , 2 ,  0x000501A0 , 0x0 ) ;
+	start_flag = 0;
+      }
+      //usleep( 5 ) ;
+      // release busy
+      //res = ecs_write( 0 , 2 ,  0x000501A0 , 0x0 ) ;
+      read_dma = 1 ;
+    } 
+
+    //
+    // Main loop
+    //
+    while( 1 ){
+      while( 1 ){
+	if( !( ( ( ( magic = data[ ( cur_pos + 1 ) % DMASIZE ] ) & 0xffff0000 ) != 0x7f7f0000 )
+	    || data[ ( cur_pos +  data[ cur_pos  % DMASIZE ] - 1 + DMASIZE ) % DMASIZE ] != 0x7fff0006 ) ){
+	  break;
+	}
+	//	printf("MAGIC %.8x\n", magic);
+
+	//	usleep(1000); // to avoid BUSY loop
+	
+	//
+	// Refresh DMA memory
+	//
+	res = pcie40_b2dmapointerread( 0 , &data ) ;
+	int wait_flag = 0;
+	//
+	// Scan to find x"7f7f...."
+	//
+	if( cnt > 100 ){
+	  cnt = 0;
+	  int j = 0 ; 
+	  for ( j = 0 ; j < DMASIZE ; ++j ) { 
+#ifdef DEBUG	    
+	    printf("%.8x %d\n", data[ ( cur_pos + j + 1 ) % DMASIZE ], cur_pos + j );
+#endif
+	    if ( ( ( data[ ( cur_pos + j + 1 ) % DMASIZE ] & 0xffff0000 ) == 0x7f7f0000 ) ){
+	      next_eve = data[ ( cur_pos + j + 3 ) % DMASIZE ];
+	      next_exp_run =  data[ ( cur_pos + j + 2 ) % DMASIZE ] ;
+
+	      //	      printf( "TRAILER %.8x %.8x %.8x\n",data[ ( cur_pos + j + data[ ( cur_pos + j + DMASIZE ) % DMASIZE ] - 1 + DMASIZE ) % DMASIZE ] );
+
+	      if( next_eve > cur_eve && next_exp_run >= cur_exp_run ){
+		/* if( data[ ( ( data[ ( cur_pos + j + DMASIZE ) % DMASIZE ] ) - 1 + DMASIZE ) % DMASIZE ] != 0x7fff0006 ){ */
+		/*   usleep(1000); */
+		/*   break; */
+		/* } */
+		cur_pos = ( cur_pos + j + DMASIZE ) % DMASIZE;
+		size = data[ cur_pos ];
+		//		printf( "Detect new Event number prev %.8x new %.8x pos %.8x size %.8x\n" , cur_eve , next_eve, cur_pos, size );
+		break;
+	      }else{
+		//		printf( "Detect Old Event number prev %.8x new %.8x pos %d\n" , cur_eve , next_eve, ( cur_pos + j + DMASIZE ) % DMASIZE );
+		break;
+	      }
+	    }else{
+	      continue;
+	    }
+	  }
+	}
+	cnt++;
+      }
+      size = data[ cur_pos ] ;
+ 
+      next_eve = data[ ( cur_pos + 3 ) % DMASIZE ];
+      next_exp_run = data[ ( cur_pos + 2 ) % DMASIZE ];
+
+      if( first_event_flag == 0 || cur_exp_run != next_exp_run ){
+	first_event_flag = 1;
+	first_eve = next_eve;
+	crc_err_eve_cnt = 0;
+	eve_cnt = 0;
+      }
+      eve_cnt++;
+      ret = crc_calc_event( data, cur_pos );
+      if( ret != 1 ){
+	crc_err_eve_cnt++;
+      }
+
+      if(ret != 1 || eve_cnt % 100 == 0 ){
+	printf( "Event number prev %.8x new %.8x pos %.8x size %.8x\n" , cur_eve , next_eve, cur_pos, size );
+      }
+      cur_eve = next_eve;
+      cur_exp_run = next_exp_run;
+      if(ret != 1 ||  eve_cnt % 10000 == 0 ){
+	printf("STATUS : tot eve %d read eve %d err_eve %d run %d\n", next_eve - first_eve, eve_cnt, crc_err_eve_cnt, cur_exp_run );
+      }
+      mod_pos = ( cur_pos + size ) % 8;
+      if( mod_pos != 0 ){
+	cur_pos = ( cur_pos + size + DMASIZE + ( 8 - mod_pos) ) % DMASIZE ;
+      }else{
+	cur_pos = ( cur_pos + size + DMASIZE ) % DMASIZE ;
+      }
+
+    }
+
+
+    clock_t end = clock();
+    time_spent += (double)(end - begin) / CLOCKS_PER_SEC;
+
+    ecs_close( 0 , 0 ) ;
+
+    printf( "Timing = %f s\n" , time_spent ) ;
+    printf( "Number of events = %d \n", nEvt ) ;  
+    printf( "Number of errors = %d \n", nErr ) ; 
+    printf( "Number of retries = %d \n", nRetry ) ;
+    printf( "Number of missed = %d \n", nMissed ) ;
+    return 0 ;
+  }
diff --git a/Pcie40Applications/pcie40_ul_lib.h b/Pcie40Applications/pcie40_ul_lib.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f580bf8171d5bd42ddad2c7f00657df1860395b
--- /dev/null
+++ b/Pcie40Applications/pcie40_ul_lib.h
@@ -0,0 +1,59 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include "altera_dma_regs.h"
+
+extern "C" int  ecs_open(int dev, int bar);
+extern "C" void ecs_close(int dev, int bar);
+extern "C" int pcie40_b2dmabufferreset(int fd);
+extern "C" int pcie40_b2dmapointerread(int fd , unsigned int ** pData );
+extern "C" int      ecs_write(int dev, int bar, unsigned add, int val);
+
+//#define DEBUG
+
+const int CRC16_XMODEM_TABLE[] = {
+  0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+  0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+  0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+  0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+  0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+  0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+  0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+  0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+  0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+  0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+  0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+  0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+  0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+  0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+  0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+  0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+  0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+  0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+  0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+  0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+  0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+  0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+  0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+  0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+  0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+  0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+  0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+  0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+  0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+  0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+  0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+  0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
+} ;
+
+
+
+int crc_calc( int * crc, unsigned int * data );
+
+int crc_calc_event( unsigned int* data, int start_pos );
+
+int decode_data_wUL( unsigned int * data , unsigned int * ce , int * crc , int * run , 
+		       int * bad , int *evn , int * retry , int * pctime , int * putime , 
+		     int * nmissed );
+int readout();