diff --git a/linux-software/lib/atca-v2-daq-lib.c b/linux-software/lib/atca-v2-daq-lib.c
new file mode 100644
index 0000000000000000000000000000000000000000..63118e26f68f869a250f954808d3875ee7af9f27
--- /dev/null
+++ b/linux-software/lib/atca-v2-daq-lib.c
@@ -0,0 +1,182 @@
+/**
+ * ATCA MIMO v2 Lib functions 
+ * Project Name:
+ * Design Name:
+ * working  with kernel 4.xx
+ *
+ *
+ * Copyright 2014 - 2019 IPFN-Instituto Superior Tecnico, Portugal
+ * Creation Date  2019-07-26
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they
+ * will be approved by the European Commission - subsequent
+ * versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the
+ * Licence.
+ * You may obtain a copy of the Licence at:
+ *
+ * http://ec.europa.eu/idabc/eupl
+ *
+ * Unless required by applicable law or agreed to in
+ * writing, software distributed under the Licence is
+ * distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the Licence for the specific language governing
+ * permissions and limitations under the Licence.
+ *
+ */
+// For CPU_ZERO
+#define _GNU_SOURCE
+/*---------------------------------------------------------------------------*/
+/*                        Standard header includes                           */
+/*---------------------------------------------------------------------------*/
+
+#include <errno.h>
+#include <sched.h>
+#include <stdio.h>
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+/*---------------------------------------------------------------------------*/
+/*                        Project header includes                            */
+/*---------------------------------------------------------------------------*/
+#include "atca-v2-daq.h"
+#include "atca-v2-daq-ioctl.h"
+
+int bind_to_cpu(int core_id) {
+  // cpu_set_t: This data set is a bitset where each bit represents a CPU.
+  cpu_set_t cpuset;
+  const pthread_t pid = pthread_self();
+
+  // CPU_ZERO: This macro initializes the CPU set set to be the empty set.
+  CPU_ZERO(&cpuset);
+  // CPU_SET: This macro adds cpu to the CPU set set.
+  CPU_SET(core_id, &cpuset);
+
+  // pthread_setaffinity_np: The pthread_setaffinity_np() function sets the CPU
+  // affinity mask of the thread thread to the CPU set pointed to by cpuset. If
+  // the call is successful, and the thread is not currently running on one of
+  // the CPUs in cpuset, then it is migrated to one of those CPUs.
+  const int set_result =
+      pthread_setaffinity_np(pid, sizeof(cpu_set_t), &cpuset);
+  if (set_result != 0) {
+    // errno = en;
+    perror("pthread_setaffinity_np");
+    return set_result;
+    /*print_error_then_terminate(set_result, "pthread_setaffinity_np");*/
+  }
+  // Check what is the actual affinity mask that was assigned to the thread.
+  // pthread_getaffinity_np: The pthread_getaffinity_np() function returns the
+  // CPU affinity mask of the thread thread in the buffer pointed to by cpuset.
+  const int get_affinity =
+      pthread_getaffinity_np(pid, sizeof(cpu_set_t), &cpuset);
+  if (get_affinity != 0) {
+
+    perror("pthread_getaffinity_np");
+    return get_affinity;
+    /*print_error_then_terminate(get_affinity, "pthread_getaffinity_np");*/
+  }
+  if (CPU_ISSET(core_id, &cpuset))
+    printf("pid %ld, running on core %d\n", pid, core_id);
+  return 0;
+}
+int atca_mimo_v2_get_status(int fd, unsigned int * pstatus) {
+  int rc;
+  rc = ioctl(fd, ATCA_PCIE_IOCG_STATUS, pstatus);
+  return rc;
+}
+int atca_mimo_v2_soft_trigger(int fd) {
+  int rc;
+  rc = ioctl(fd, ATCA_PCIE_IOCT_SOFT_TRIG);
+  return rc;
+}
+int atca_mimo_v2_stop_acq(int fd) {
+  int max_buf_count;
+  max_buf_count = ioctl(fd, ATCA_PCIE_IOCT_ACQ_DISABLE);
+  /*int rc = */
+  ioctl(fd, ATCA_PCIE_IOCT_DMA_DISABLE);
+  return max_buf_count;
+}
+int atca_mimo_v2_acq_enable(int fd) {
+  int rc;
+  rc = ioctl(fd, ATCA_PCIE_IOCT_ACQ_ENABLE);
+  rc = ioctl(fd, ATCA_PCIE_IOCT_DMA_ENABLE);
+
+  return rc;
+}
+int atca_mimo_v2_init_device_16bit(int fd, unsigned int chop_period){
+  int rc;
+  int tmp=0;
+
+  atca_mimo_v2_stop_acq(fd);
+  rc = ioctl(fd, ATCA_PCIE_IOCT_DATA32_DISABLE);
+  if(chop_period){
+        rc = ioctl(fd, ATCA_PCIE_IOCT_CHOP_ENABLE);
+        tmp = ((0xFFFF & chop_period)<<16) | ((0xFFFF &chop_period/2));	
+        rc = ioctl(fd, ATCA_PCIE_IOCS_CHOP_PERIOD, &tmp);
+  }
+  else {
+        rc = ioctl(fd, ATCA_PCIE_IOCT_CHOP_DISABLE);
+  }
+    rc = ioctl(fd, ATCA_PCIE_IOCT_DMA_RESET);
+    rc = ioctl(fd, ATCA_PCIE_IOCT_INT_ENABLE);
+
+  rc = ioctl(fd, ATCA_PCIE_IOCG_DMA_SIZE, &tmp);
+ return tmp;
+}
+
+
+
+/*unsigned long int time_interval_us(tstart, tend) struct timespec *tstart,
+ * *tend;*/
+unsigned long int time_interval_us(struct timeval *tstart,
+                                   struct timeval *tend) {
+  unsigned long int duration = 1000000UL * (tend->tv_sec - tstart->tv_sec) +
+                               (unsigned long)tend->tv_usec -
+                               (unsigned long)tstart->tv_usec;
+  return duration;
+}
+
+void get_rt_pckt_adc_data(int32_t *pAdcData, DMACH1_PCKT *pPdma) {
+  int j;
+  for (j = 0; j < ADC_CHANNELS; j++)
+    *pAdcData++ = pPdma->adc_decim_data.channel[j].adc_data;
+}
+
+void get_pckt_adc_data(int32_t *pAdcData, DMA_PCKT *pPdma) {
+  /*Normal samples*/
+  int i, j;
+  for (i = 0; i < PCK_N_SAMPLES; i++) {
+    for (j = 0; j < ADC_CHANNELS; j++)
+      *pAdcData++ = pPdma->samp[i].channel[j].adc_data;
+  }
+}
+unsigned int get_pckt_head_magic(DMA_PCKT *pPdma) {
+  unsigned int uval = 0;
+  int i;
+  for (i = 0; i < 4; i++) {
+    uval |= pPdma->samp[0].channel[i].data_byte << (i * 8);
+  }
+  return uval;
+}
+unsigned int get_pckt_foot_magic(DMA_PCKT *pPdma) {
+  unsigned int uval = 0;
+  int i;
+  for (i = 0; i < 4; i++) {
+    uval |= (pPdma->samp[PCK_N_SAMPLES - 1].channel[i].data_byte) << (i * 8);
+  }
+  return uval;
+}
+uint64_t get_sample_cnt(SAMPLE *pSamp) {
+  uint64_t uval = 0;
+  int i;
+  for (i = 0; i < 8; i++) {
+    uval |= (pSamp->channel[8 + i].data_byte) << (i * 8);
+  }
+  return uval;
+}