# Path: pybar/utils/utils.py
# def get_float_time():
#     '''returns time as double precision floats - Time64 in pytables - mapping to and from python datetime's
# 
#     '''
#     t1 = time.time()
#     t2 = datetime.datetime.fromtimestamp(t1)
#     return time.mktime(t2.timetuple()) + 1e-6 * t2.microsecond
# 
# Path: pybar/daq/readout_utils.py
# def data_array_from_data_iterable(data_iterable):
#     '''Convert data iterable to raw data numpy array.
# 
#     Parameters
#     ----------
#     data_iterable : iterable
#         Iterable where each element is a tuple with following content: (raw data, timestamp_start, timestamp_stop, status).
# 
#     Returns
#     -------
#     data_array : numpy.array
#         concatenated data array
#     '''
#     try:
#         data_array = np.concatenate([item[0] for item in data_iterable])
#     except ValueError:  # length is 0
#         data_array = np.empty(0, dtype=np.uint32)
#     return data_array
# 
# def convert_data_iterable(data_iterable, filter_func=None, converter_func=None):  # TODO: add concatenate parameter
#     '''Convert raw data in data iterable.
# 
#     Parameters
#     ----------
#     data_iterable : iterable
#         Iterable where each element is a tuple with following content: (raw data, timestamp_start, timestamp_stop, status).
#     filter_func : function
#         Function that takes array and returns true or false for each item in array.
#     converter_func : function
#         Function that takes array and returns an array or tuple of arrays.
# 
#     Returns
#     -------
#     data_list : list
#         Data list of the form [(converted data, timestamp_start, timestamp_stop, status), (...), ...]
#     '''
#     data_list = []
#     for item in data_iterable:
#         data_list.append((convert_data_array(item[0], filter_func=filter_func, converter_func=converter_func), item[1], item[2], item[3]))
#     return data_list
# 
# def convert_data_array(array, filter_func=None, converter_func=None):  # TODO: add copy parameter, otherwise in-place
#     '''Filter and convert raw data numpy array (numpy.ndarray).
# 
#     Parameters
#     ----------
#     array : numpy.array
#         Raw data array.
#     filter_func : function
#         Function that takes array and returns true or false for each item in array.
#     converter_func : function
#         Function that takes array and returns an array or tuple of arrays.
# 
#     Returns
#     -------
#     data_array : numpy.array
#         Data numpy array of specified dimension (converter_func) and content (filter_func)
#     '''
# #     if filter_func != None:
# #         if not hasattr(filter_func, '__call__'):
# #             raise ValueError('Filter is not callable')
#     if filter_func:
#         array = array[filter_func(array)]
# #     if converter_func != None:
# #         if not hasattr(converter_func, '__call__'):
# #             raise ValueError('Converter is not callable')
#     if converter_func:
#         array = converter_func(array)
#     return array
# 
# def logical_and(f1, f2):  # function factory
#     '''Logical and from functions.
# 
#     Parameters
#     ----------
#     f1, f2 : function
#         Function that takes array and returns true or false for each item in array.
# 
#     Returns
#     -------
#     Function.
# 
#     Usage:
#     filter_func=logical_and(is_data_record, is_data_from_channel(4))  # new filter function
#     filter_func(array) # array that has Data Records from channel 4
#     '''
#     def f(value):
#         return np.logical_and(f1(value), f2(value))
#     f.__name__ = "(" + f1.__name__ + "_and_" + f2.__name__ + ")"
#     return f
# 
# def is_fe_word(value):
#     return np.equal(np.bitwise_and(value, 0xF0000000), 0)
# 
# def is_data_header(value):
#     return np.equal(np.bitwise_and(value, 0x00FF0000), 0b111010010000000000000000)


import logging
import sys
import numpy as np
from time import sleep, time
from itertools import izip
from threading import Thread, Event, Lock, Condition
from collections import deque, Iterable
from basil.HL import sitcp_fifo
from pybar.utils.utils import get_float_time
from pybar.daq.readout_utils import data_array_from_data_iterable, convert_data_iterable, convert_data_array, logical_and, is_fe_word, is_data_header

            List of data and meta data dicts.
        '''
        if self._is_running:
            raise RuntimeError('Readout thread running')
        if not self.fill_buffer:
            logging.warning('Data buffer is not activated')
        return [convert_data_iterable(data_iterable, filter_func=filter_func, converter_func=converter_func) for data_iterable in self._data_buffer]

    def get_raw_data_from_buffer(self, filter_func=None, converter_func=None):
        '''Reads local data buffer and returns raw data array.

        Returns
        -------
        data : np.array
            An array containing data words from the local data buffer.
        '''
        if self._is_running:
            raise RuntimeError('Readout thread running')
        if not self.fill_buffer:
            logging.warning('Data buffer is not activated')
        return [convert_data_array(data_array_from_data_iterable(data_iterable), filter_func=filter_func, converter_func=converter_func) for data_iterable in self._data_buffer]

    def read_raw_data_from_fifo(self, fifo, filter_func=None, converter_func=None):
        '''Reads FIFO data and returns raw data array.

        Returns
        -------
        data : np.array
            An array containing FIFO data words.
        '''

# Path: pybar/utils/utils.py
# def get_float_time():
#     '''returns time as double precision floats - Time64 in pytables - mapping to and from python datetime's
# 
#     '''
#     t1 = time.time()
#     t2 = datetime.datetime.fromtimestamp(t1)
#     return time.mktime(t2.timetuple()) + 1e-6 * t2.microsecond
# 
# Path: pybar/daq/readout_utils.py
# def data_array_from_data_iterable(data_iterable):
#     '''Convert data iterable to raw data numpy array.
# 
#     Parameters
#     ----------
#     data_iterable : iterable
#         Iterable where each element is a tuple with following content: (raw data, timestamp_start, timestamp_stop, status).
# 
#     Returns
#     -------
#     data_array : numpy.array
#         concatenated data array
#     '''
#     try:
#         data_array = np.concatenate([item[0] for item in data_iterable])
#     except ValueError:  # length is 0
#         data_array = np.empty(0, dtype=np.uint32)
#     return data_array
# 
# def convert_data_iterable(data_iterable, filter_func=None, converter_func=None):  # TODO: add concatenate parameter
#     '''Convert raw data in data iterable.
# 
#     Parameters
#     ----------
#     data_iterable : iterable
#         Iterable where each element is a tuple with following content: (raw data, timestamp_start, timestamp_stop, status).
#     filter_func : function
#         Function that takes array and returns true or false for each item in array.
#     converter_func : function
#         Function that takes array and returns an array or tuple of arrays.
# 
#     Returns
#     -------
#     data_list : list
#         Data list of the form [(converted data, timestamp_start, timestamp_stop, status), (...), ...]
#     '''
#     data_list = []
#     for item in data_iterable:
#         data_list.append((convert_data_array(item[0], filter_func=filter_func, converter_func=converter_func), item[1], item[2], item[3]))
#     return data_list
# 
# def convert_data_array(array, filter_func=None, converter_func=None):  # TODO: add copy parameter, otherwise in-place
#     '''Filter and convert raw data numpy array (numpy.ndarray).
# 
#     Parameters
#     ----------
#     array : numpy.array
#         Raw data array.
#     filter_func : function
#         Function that takes array and returns true or false for each item in array.
#     converter_func : function
#         Function that takes array and returns an array or tuple of arrays.
# 
#     Returns
#     -------
#     data_array : numpy.array
#         Data numpy array of specified dimension (converter_func) and content (filter_func)
#     '''
# #     if filter_func != None:
# #         if not hasattr(filter_func, '__call__'):
# #             raise ValueError('Filter is not callable')
#     if filter_func:
#         array = array[filter_func(array)]
# #     if converter_func != None:
# #         if not hasattr(converter_func, '__call__'):
# #             raise ValueError('Converter is not callable')
#     if converter_func:
#         array = converter_func(array)
#     return array
# 
# def logical_and(f1, f2):  # function factory
#     '''Logical and from functions.
# 
#     Parameters
#     ----------
#     f1, f2 : function
#         Function that takes array and returns true or false for each item in array.
# 
#     Returns
#     -------
#     Function.
# 
#     Usage:
#     filter_func=logical_and(is_data_record, is_data_from_channel(4))  # new filter function
#     filter_func(array) # array that has Data Records from channel 4
#     '''
#     def f(value):
#         return np.logical_and(f1(value), f2(value))
#     f.__name__ = "(" + f1.__name__ + "_and_" + f2.__name__ + ")"
#     return f
# 
# def is_fe_word(value):
#     return np.equal(np.bitwise_and(value, 0xF0000000), 0)
# 
# def is_data_header(value):
#     return np.equal(np.bitwise_and(value, 0x00FF0000), 0b111010010000000000000000)


# Path: pybar/daq/fifo_readout.py
import logging
import sys
import numpy as np
from time import sleep, time
from itertools import izip
from threading import Thread, Event, Lock, Condition
from collections import deque, Iterable
from basil.HL import sitcp_fifo
from pybar.utils.utils import get_float_time
from pybar.daq.readout_utils import data_array_from_data_iterable, convert_data_iterable, convert_data_array, logical_and, is_fe_word, is_data_header

            List of data and meta data dicts.
        '''
        if self._is_running:
            raise RuntimeError('Readout thread running')
        if not self.fill_buffer:
            logging.warning('Data buffer is not activated')
        return [convert_data_iterable(data_iterable, filter_func=filter_func, converter_func=converter_func) for data_iterable in self._data_buffer]

    def get_raw_data_from_buffer(self, filter_func=None, converter_func=None):
        '''Reads local data buffer and returns raw data array.

        Returns
        -------
        data : np.array
            An array containing data words from the local data buffer.
        '''
        if self._is_running:
            raise RuntimeError('Readout thread running')
        if not self.fill_buffer:
            logging.warning('Data buffer is not activated')
        return [convert_data_array(data_array_from_data_iterable(data_iterable), filter_func=filter_func, converter_func=converter_func) for data_iterable in self._data_buffer]

    def read_raw_data_from_fifo(self, fifo, filter_func=None, converter_func=None):
        '''Reads FIFO data and returns raw data array.

        Returns
        -------
        data : np.array
            An array containing FIFO data words.
        '''

        return convert_data_array(self.dut[fifo].get_data(), filter_func=filter_func, converter_func=converter_func)
