Beispiel #1
0
def start_device():
    # Connect to BITalino
    device = BITalino(settings.bitalino.mac_address)

    # Set battery threshold
    device.battery(settings.bitalino.battery_led_threshold)

    # Read BITalino version
    logger.info(device.version())

    # Start Acquisition
    device.start(settings.sampling.base_sample_rate, [0, 1, 2, 3])

    return device
Beispiel #2
0
def launch_acquisition(msg):
    global isAcquiring
    isAcquiring = 1
    macAddress = msg['payload']['macAddress']

    # This example will collect data for 5 sec.
    running_time = 9

    batteryThreshold = 30
    acqChannels = [0, 1, 2, 3, 4, 5]
    samplingRate = 1000
    nSamples = 10
    digitalOutput = [1, 1]

    # Connect to BITalino
    device = BITalino(macAddress)

    # Set battery threshold
    device.battery(batteryThreshold)

    # Read BITalino version
    print(device.version())

    # ON/OFF
    device.trigger([1, 1])
    device.trigger([0, 0])

    # Start Acquisition
    device.start(samplingRate, acqChannels)

    start = time.time()
    end = time.time()
    while (end - start) < running_time and isAcquiring == 1:
        # Read samples
        data = device.read(nSamples)
        print(data)
        msg['payload']['val'] = data.tolist()
        end = time.time()

    # Stop acquisition
    device.stop()

    # Close connection
    device.close()
    isAcquiring = 0
    return ("success")
Beispiel #3
0
try:
    # Connect to BITalino
    device = BITalino(device)
except:
    print "Error: cannot connect to BITalino"
    exit()

# Read BITalino version
print(device.version())

# Set battery threshold
device.battery(batterythreshold)

# Start Acquisition
device.start(fsample, channels)

# Turn BITalino led on
digitalOutput = [1,1]
device.trigger(digitalOutput)

startfeedback = time.time();
countfeedback = 0;

print "STARTING STREAM"
while True:

    # measure the time that it takes
    start = time.time();

    # read the selected channels from the
Beispiel #4
0
running_time = 100

batteryThreshold = 30
acqChannels = [0]
samplingRate = 100
nSamples = 1
digitalOutput = [1, 1]

# Connect to BITalino
device = BITalino(macAddress)

# Set battery threshold
device.battery(batteryThreshold)

# Start Acquisition
device.start(samplingRate, acqChannels)

start = time.time()
end = time.time()
i = 0

while (end - start) < running_time:
    raw = device.read(nSamples).tolist()
    print(raw[0][5])

    xdata.append(i)
    ydata.append(raw[0][5])

    oldValue = raw[0][5]
    plt.plot(xdata, ydata)
    plt.draw()
Beispiel #5
0
class bitalino_device(object):
    def __init__(self, macAddress, batteryThreshold, samplingRate, nSamples):
        self.macAddress = macAddress
        self.batteryThreshold = batteryThreshold
        self.acqChannels = [0, 1, 2, 3, 4, 5]
        self.samplingRate = samplingRate
        self.nSamples = nSamples
        self.status = 0
        self.ledOn = [1, 0]
        self.ledOff = [0, 1]
        self.attSensors = "this"
        self.file = ""
        self.threshold = 5
        self.noise = [1, 1, 1, 1, 1, 1]
        self.prevData = [0, 0, 0, 0, 0, 0]

    def connect(self):
        try:
            self.connection = BITalino(self.macAddress)
            self.status = 1
        except:
            print('failed to connect')

    def state(self):
        return self.connection.state()

    def start(self):
        self.connection.start(self.samplingRate, self.acqChannels)

    def start_read(self):
        return self.connection.read(self.nSamples)

    def stop(self):
        self.connection.stop()

    def led_on(self):
        self.connection.trigger(self.ledOn)

    def led_off(self):
        self.connection.trigger(self.ledOff)

    def create_file(self, current_directory):
        print('in create file')
        new_file = bitFile(self.macAddress, self.acqChannels,
                           self.samplingRate, self.attSensors)
        self.file = new_file.createFile(current_directory)

    def update_sensors(self, sensorValues):
        self.attSensors = sensorValues

    def get_sensor_value(self):
        print(str(self.attSensors))

    def matToString(self, matrix):
        """
        :param matrix: The matrix to be turned into string
        Returns a string of a matrix row by row, without brackets or commas
        """
        r, c = matrix.shape
        string = ""
        for row in range(0, r):
            string = string + strftime("%Y-%m-%d %H:%M:%S", gmtime()) + "\t"
            for col in range(1, c):
                string = string + str(int(matrix[row, col])) + "\t"
            string += "\n"
        return string

    def openFile(self):
        open(self.file, "w")

    def checkNoiseArray(self, channels):
        for i in range(6):
            if (int(channels[i]) - int(self.prevData[i]) < self.threshold):
                self.noise[i] = 0
            else:
                self.noise[i] = 1
        self.prevData = channels
        #print(self.noise)

    def checkNoise(self, data):
        data = self.matToString(data)
        #print(data)
        channels_list = data.split('\n')

        for channels in channels_list:
            channel = channels.split('\t')
            if len(channel) > 1:
                self.checkNoiseArray(channel[5:11])

        #for channel in channels[2:]:
        #    print(channel)

    def write(self, string_sample):
        self.file.write(string_sample)

    def closeFile(self):
        self.file.close()
Beispiel #6
0
    def main(self):
        parser = argparse.ArgumentParser()

        parser.add_argument("--sampling_rate",
                            help="Sampling rate used for recording data",
                            type=int,
                            default=10)
        parser.add_argument("--offline",
                            help="run in offline mode",
                            action="store_true")
        parser.add_argument("--logging",
                            dest="logging",
                            help="Log the data",
                            action="store_true",
                            default=True)
        parser.add_argument("--no_logging",
                            dest='logging',
                            help="Log the data",
                            action="store_false")

        parser.add_argument("--osc_path",
                            help="the osc path prefix",
                            default="Bitalino")
        parser.add_argument("--dest_ip",
                            help="IP address of the destination",
                            default="127.0.0.1")
        parser.add_argument("--dest_port",
                            help="the port",
                            type=int,
                            default=8000)
        parser.add_argument("--mac_address", default="20:16:12:22:45:56")
        parser.add_argument("--battery_threshold", default=30)
        parser.add_argument("--analog_channels", default="0,1,2,3,4,5")
        parser.add_argument("--batch_size",
                            help="number of samples read in batch",
                            type=int,
                            default=10)
        parser.add_argument("--EDA_channel",
                            help="the analog channel inded of EXA",
                            type=int,
                            default=3)

        args = parser.parse_args()

        the_logger = log_writer(args.logging)
        the_logger.log_msg("Starting up.")

        # The channel list parsing is bit of a hack.. I'm sure there is some more pythonesque way of doing this
        anal_channels = args.analog_channels.split(',')
        channels = list(map(int, anal_channels))

        # small samping rate for testing..
        analogChannels = args.analog_channels
        samplingRate = args.sampling_rate
        nSamples = args.batch_size

        # Connect to BITalino
        device = BITalino(args.mac_address)

        # Set battery threshold
        batty = device.battery(args.battery_threshold)

        # If we are not in offline mode we start streaming to given UDP port.
        # He we just create a UDPClient for that.
        if not args.offline:
            client = udp_client.SimpleUDPClient(args.dest_ip, args.dest_port)

        # Start recording

        device.start(samplingRate, channels)

        while self.interrupter == False:

            # Start Acquisition
            rec_data = device.read(nSamples)

            current_time = datetime.datetime.now().timestamp()
            for sample in rec_data:
                # Delete digital channels (that contains just zeroes but that cannot be ignored)
                # maybe this delete/insert thing is inefficient, but hopefully not inefficient enough
                # to cause issues...
                sample = np.delete(sample, [0, 1, 2, 3, 4])
                sample = np.insert(sample, 0, current_time)
                the_logger.log_data(sample)
                current_time += (1.0 / samplingRate)

    #  Following code just for State of Darkness!! Does not generalize and will break if EDA is
    #  recorded from somewhere other than first channel.
            EDA_data = np.mean(rec_data, axis=0)[(4 + args.EDA_channel)]
            print("the EDA_data is:  ", EDA_data)
            osc_address = args.osc_path + "/EDA"
            msg = osc_message_builder.OscMessageBuilder(address=osc_address)
            msg.add_arg(EDA_data)
            msg = msg.build()
            if not args.offline:
                client.send(msg)

        # Stop acquisition
        device.stop()

        # Close connection
        device.close()

        return
class Opisense:
    def __init__(self):
        #TODO Implement a failure to connect condition.

        #sudo hciconfig hci0 reset
        failCounter = 0
        print(time.strftime("%d %b %Y %H:%M:%S", time.gmtime()))
        """MAC Address for test device."""
        self._macAddress = '98:D3:41:FD:4F:D9'

        while not (self.__connect_bitalino()):
            failCounter += 1
            if failCounter > 5:
                sys.exit('Unable to connect: Exiting.')
                break
            pass
        """Sampling rate of the device in Hz (samples per second)."""
        self._sampleRate = 1000
        """Channels to acquire data from."""
        self._acqChannels = [0, 1, 2, 3]
        """Initialize read status."""
        self._canRead = False

    def find_devices(self) -> list:
        """Search for nearby BITalino devices and return the MAC address of those found."""
        localBITalinoMACs = [
            device[0] for device in find() if 'BITalino' in device[1]
        ]
        return localBITalinoMACs

    def __connect_bitalino(self) -> bool:
        """Attempt to establish a connection w/ the BITalion hardware."""
        try:
            self._device = BITalino(macAddress='98:D3:41:FD:4F:D9')
            #self._device = BITalino(macAddress=self._macAddress)
            return True
        except:
            print('Error in establishing device connection. Trying again.')
            return False

    def start(self) -> None:
        """Start data collection by the device using the defined parameters."""
        self._canRead = True
        self._device.start(SamplingRate=self._sampleRate,
                           analogChannels=self._acqChannels)

    def stop(self) -> None:
        """Stops data collection by the device."""
        self._canRead = False
        self._device.stop()

    def __reset(self):
        """Initialize the instance variables for data recording."""
        pass

    def read_data(self) -> pd.DataFrame:
        """Reads data off of the device in 5.0s windows and casts it as a dataframe."""
        if self._canRead:
            rawData = self._device.read(5000)
            rawCol = [
                'channel_1_raw', 'channel_2_raw', 'channel_3_raw',
                'channel_4_raw'
            ]
            df = pd.DataFrame(columns=rawCol)
            df.channel_1_raw = rawData[:, 5]
            df.channel_2_raw = rawData[:, 6]
            df.channel_3_raw = rawData[:, 7]
            df.channel_4_raw = rawData[:, 8]
            #print(time.strftime("%H:%M:%S", time.localtime()))
            df['time'] = time.strftime("%H:%M:%S", time.localtime())
            #df.set_index('time',inplace=True)
            #print(df.head())
            return df
        else:
            print(f'Device must be started.')
Beispiel #8
0
try:
    # Connect to BITalino
    device = BITalino(device)
except:
    print("Error: cannot connect to BITalino")
    exit()

# Read BITalino version
print((device.version()))

# Set battery threshold
device.battery(batterythreshold)

# Start Acquisition
device.start(fsample, channels)

# Turn BITalino led on
digitalOutput = [1,1]
device.trigger(digitalOutput)

startfeedback = time.time()
countfeedback = 0

print("STARTING STREAM")
while True:

    # measure the time that it takes
    start = time.time();

    # read the selected channels from the bitalino
def _start():
    """Start the module
    This uses the global variables from setup and adds a set of global variables
    """
    global parser, args, config, r, response, patch, name
    global  monitor, debug, device, fsample, blocksize, channels, batterythreshold, nchans, startfeedback, countfeedback, ft_host, ft_port, ft_output, datatype, digitalOutput

    # this can be used to show parameters that have changed
    monitor = EEGsynth.monitor(name=name, debug=patch.getint("general", "debug"))

    # get the options from the configuration file
    debug = patch.getint("general", "debug")
    device = patch.getstring("bitalino", "device")
    fsample = patch.getfloat("bitalino", "fsample", default=1000)
    blocksize = patch.getint("bitalino", "blocksize", default=10)
    channels = patch.getint("bitalino", "channels", multiple=True)  # these should be one-offset
    batterythreshold = patch.getint("bitalino", "batterythreshold", default=30)

    # switch from one-offset to zero-offset
    nchans = len(channels)
    for i in range(nchans):
        channels[i] -= 1

    monitor.info("fsample = " + str(fsample))
    monitor.info("channels = " + str(channels))
    monitor.info("nchans = " + str(nchans))
    monitor.info("blocksize = " + str(blocksize))

    try:
        ft_host = patch.getstring("fieldtrip", "hostname")
        ft_port = patch.getint("fieldtrip", "port")
        monitor.success("Trying to connect to buffer on %s:%i ..." % (ft_host, ft_port))
        ft_output = FieldTrip.Client()
        ft_output.connect(ft_host, ft_port)
        monitor.success("Connected to output FieldTrip buffer")
    except:
        raise RuntimeError("cannot connect to output FieldTrip buffer")

    datatype = FieldTrip.DATATYPE_FLOAT32
    ft_output.putHeader(nchans, float(fsample), datatype)

    try:
        # Connect to BITalino
        device = BITalino(device)
        monitor.success((device.version()))
    except:
        raise RuntimeError("cannot connect to BITalino")

    # Set battery threshold
    device.battery(batterythreshold)

    # Start Acquisition
    device.start(fsample, channels)

    # Turn BITalino led on
    digitalOutput = [1, 1]
    device.trigger(digitalOutput)

    startfeedback = time.time()
    countfeedback = 0

    # there should not be any local variables in this function, they should all be global
    if len(locals()):
        print("LOCALS: " + ", ".join(locals().keys()))
Beispiel #10
0
class BluetoothDataReceiver():
    """ Creates a data receiver via Bitalino class object,
    a configuration and a data buffer. 

    Keyword arguments:
    receiver_configuration -- a BluetoothReceiverConfiguration object
    which contains the receiver settings from a JSON file. 
    data_buffer -- A Queue through which the received data is
    transmitted forward. 
    """
    def __init__(self, receiver_configuration, data_buffer):
        self.__data_buffer = data_buffer
        self.__receiver_configuration = receiver_configuration
        self.__communication_queue = None
        self.__receiver_thread = None
        self.__bitalino_device = BITalino(receiver_configuration.macAddress)
        self.t0 = None

    def Start(self):
        """ Starts an 'infinite loop' which will receive and transmit 
        data on a separate thread until the *Stop* method is called.
        """
        # Creates a Bitalino object using the given receiver configuration
        # and try to connect to the Bitalino device.
        self.__bitalino_device.start(
            self.__receiver_configuration.samplingRate,
            self.__receiver_configuration.acqChannels)

        if self.__receiver_thread is None:
            self.__communication_queue = queue.Queue()
            self.__receiver_thread = threading.Thread(
                target=self.__receiver_loop, args=[])
            self.__receiver_thread.start()

    def __receiver_loop(self):
        """ An 'infinite loop' which is stopped by *Stop* method. \n
        This method will get the data received through the Bitalino 
        device and send further via data buffer.
        """
        self.t0 = time.time()

        while True:
            if not self.__communication_queue.empty():
                cmd = self.__communication_queue.get()
                if isinstance(cmd, str) and cmd == 'quit':
                    break

            data = self.__bitalino_device.read(
                self.__receiver_configuration.nSamples)
            self.__data_buffer.put(
                (self.__receiver_configuration.macAddress[-5:].replace(
                    ':', ''), data[:, 5]))

    def Stop(self):
        """ Stops the 'infinite loop' thread created by *Start* call.
        """
        self.__communication_queue.put('quit')
        self.__receiver_thread.join()
        self.__bitalino_device.stop()
        self.__bitalino_device.close()
        self.__communication_queue = None
        self.__receiver_thread = None
Beispiel #11
0
def main():
    
    # OS Specific Initializations
    clearCmd = "cls||clear"

    if platform.system() == 'Windows':
        clearCmd = "cls"
        print("Using Windows default console size 80x24")
        columns = 80
        rows = 24
    else:
        clearCmd = "clear"
        rows, columns = os.popen('stty size', 'r').read().split()

    print("Connecting to BITalino...")

    # Set MAC Address with argument
    defaultMACAddress = "20:16:12:21:98:56"

    if len(sys.argv) == 2:
        macAddress = sys.argv[1]
        print("Using address: " + macAddress)
    elif len(sys.argv) > 1:
        print("Please input only 1 argument, which is the address of the BITalino device.")
        print("Running without argument will use default MAC Address = " + defaultMACAddress)
        print("Exiting...")
        exit()
    else:
        macAddress = defaultMACAddress
        print("Using default MAC address: " + macAddress)

    # Setting other attributes
    batteryThreshold = 30
    acqChannels = [0,1]
    samplingRate = 100
    nSamples = 20
    digitalOutput = [1,1]

    # Connect to BITalino
    device = BITalino(macAddress)
    
    # Set battery threshold
    device.battery(batteryThreshold)

    # Read BITalino version
    os.system(clearCmd)
    print("Device Version:" + device.version())

    # Start Acquisition
    device.start(samplingRate, acqChannels)

    # Take baseline measurement
    p1Base = []
    p2Base = []

    start = time.time()
    end = time.time()

    samplingTime = 15

    print("Sampling for baseline...")

    while (end - start) < samplingTime:
        # Sampling for baseline
        baseSample = device.read(nSamples)
        p1Base.append(numpy.mean(baseSample[:,5]))
        p2Base.append(numpy.mean(baseSample[:,6]))
        end = time.time()

    p1B = numpy.mean(p1Base)
    p2B = numpy.mean(p2Base)

    print("\n")
    p1P = "Player 1 Baseline: " + str(p1B)
    print(p1P)
    p2P = "Player 2 Baseline: " + str(p2B)
    print(p2P)


    print("\n\n\n\n\n\n")
    print("Are you ready for the game? Type 'No' to exit".center(int(columns)," "))
    response = sys.stdin.readline().rstrip()
    if response == "No":
        sys.exit()

    print("\n")
    print("Starting Game...".center(int(columns), " "))

    time.sleep(5)


    # Start Game

    os.system(clearCmd)

    gameRunning = True

    player1Progress = 28

    while gameRunning:
        # While not reaching runningTime, read samples
        rawData = device.read(nSamples)
        portA1 = rawData[:,5]
        #print "Port A1: ", portA1
        valueA1 = numpy.mean(portA1 - p1B)
        #print "Value A1: ", valueA1
        #print ""
        portA2 = rawData[:,6]
        #print "Port A2: ", portA2
        valueA2 = numpy.mean(portA2 - p2B)
        #print "Value A2: ", valueA2
        #print "\n"
        if (valueA2 - valueA1) > 10:
            player1Progress-=1
        elif (valueA2 - valueA1) > 20:
            plater1Progress-=2
        elif (valueA1 - valueA2) > 10:
            player1Progress+=1
        elif (valueA1 - valueA2) > 20:
            player1Progress+=2

        print("\n\n")
        print("Player 1 Reading:".center(int(columns)," "))
        print("\n")
        print(str(valueA1).center(int(columns)," "))
        print("\n\n\n")

        print("*****************************I*****************************".center(int(columns)," "))
        progress = "P1 *" + ' '*player1Progress + 'O' + ' '*(56-player1Progress) + '* P2'
        print(progress.center(int(columns)," "))
        print("*****************************I*****************************".center(int(columns)," "))
        print("\n\n\n")

        print("Player 2 Reading:".center(int(columns)," "))
        print("\n")
        print(str(valueA2).center(int(columns)," "))

        time.sleep(0.2)

        os.system(clearCmd)

        if player1Progress == 0:
            print("\n\n\n\n\n")
            print("Player 1 has won".center(int(columns)," "))
            gameRunning = False
        elif player1Progress == 56:
            print("\n\n\n\n\n")
            print("Player 2 has won".center(int(columns)," "))
            gameRunning = False

    # Turn BITalino LED on
    device.trigger(digitalOutput)

    # Stop acquisition
    device.stop()

    # Close connection
    device.close()
Beispiel #12
0
except IndexError:
    raise Exception('No BITalino found using address {}'.format(args.bitalino))

chans = [1, 2]  # ECG = 1, EDA = 2
fs = 100  # sampling rate
n_samples = 10  # how many samples to read from BITalino
session_id = int(args.session)

# Connect to BITalino
device = BITalino(device_address)

# Read BITalino version
print(device.version())

# Start Acquisition
device.start(fs, chans)

hr = HeartRate.HeartRate(fs, 32)
edr = SkinConductance.SkinConductance(fs, 20, 0.4, 20, 20)

osc_ip = args.osc_ip
osc_port = args.osc_port
print("connecting to osc server: {}:{}".format(osc_ip, osc_port))

client = OSCClient()
client.connect((osc_ip, osc_port))

ecg_ignore_beats = 5
ecg_last_rate = 0
ecg_rates = []
Beispiel #13
0
import pygame
import pygame.mixer
from pygame.locals import *
import sys

# ----------------------------------------
# デバイスの初期化

macAddress = "20:16:12:21:35:82" # MACアドレス
samplingRate = 1000 # サンプリングレート
acqChannels = [0] # 取得チャネル(A1)
nSamples = 100 # 取得サンプル数

device = BITalino(macAddress) # デバイスの取得
print(device.version())
device.start(samplingRate, acqChannels) # データ取得開始
# ----------------------------------------

# ----------------------------------------
# 信号の取得

def selected():
    BITS = 10 # 信号のビット幅
    VCC = 3.3 # 操作電圧
    GAIN = 1009 # センサーゲイン
    THRESHOLD = 0.3 # 閾値

    data = device.read(nSamples)
    emg = (((((data[:,5] / 2**BITS) - 1/2) * VCC) / GAIN) * 1000) # 単位変換(mV)
    emg = np.abs(emg) # 絶対値
    max_value = np.max(emg)
Beispiel #14
0
class Bitalino(Node):
    """BITalino driver.

    This node connects to a BITalino device and streams data at a provided rate.
    It is based on the original BITalino Python library, with some performance
    improvements and careful timestamping.

    Two output streams are provided. The default output is the data read from the
    analog and digital channels. The ``o_offsets`` output provides continuous offsets
    between the local time and the estimated device time. This enables drift correction
    to be performed during post-processing, although no significant drift has been
    observed during testing.

    Attributes:
        o (Port): BITalino data, provides DataFrame.
        o_offsets (Port): Time offsets, provide DataFrame.

    Args:
        port (string): The serial port.
            e.g. ``COM3`` on Windows;  ``/dev/tty.bitalino-DevB`` on MacOS;
            ``/dev/ttyUSB0`` on GNU/Linux.
        rate (int): The device rate in Hz.
            Possible values: ``1``, ``10``, ``100``, ``1000``. Default: ``1000``.
        channels (tupple): The analog channels to read from.
            Default: ``('A1', 'A2', 'A3', 'A4', 'A5', 'A6')``.

    Example:
        .. literalinclude:: /../examples/bitalino.yaml
           :language: yaml

    Notes:

    .. attention::

        Make sure to set your graph rate to an high-enough value, otherwise the device
        internal buffer may saturate, and data may be lost. A 30Hz graph rate is
        recommended for a 1000Hz device rate.

    """
    def __init__(self,
                 port,
                 rate=1000,
                 channels=("A1", "A2", "A3", "A4", "A5", "A6")):

        # Check port
        if not port.startswith("/dev/") and not port.startswith("COM"):
            raise ValueError(f"Invalid serial port: {port}")

        # Check rate
        if rate not in (1, 10, 100, 1000):
            raise ValueError(f"Invalid rate: {rate}")

        # Check channels
        unique_channels = set(channels)
        analog_channels = ["A1", "A2", "A3", "A4", "A5", "A6"]
        channels = []
        for channel_num, channel_name in enumerate(analog_channels):
            if channel_name in unique_channels:
                channels.append(channel_num)

        # Set column names
        # Sequence number and numeric channels are always present
        self.columns = ["SEQ", "I1", "I2", "O1", "O2"]
        # Add required analog channels
        for channel in channels:
            self.columns.append(analog_channels[channel])

        # Compute the sample size in bytes
        self.channel_count = len(channels)
        if self.channel_count <= 4:
            self.sample_size = int(
                np.ceil((12.0 + 10.0 * self.channel_count) / 8.0))
        else:
            self.sample_size = int(
                np.ceil((52.0 + 6.0 * (self.channel_count - 4)) / 8.0))

        # Connect to BITalino
        try:
            self.device = BITalino(port)
        except UnicodeDecodeError:
            # This can happen after an internal buffer overflow.
            # The solution seems to power off the device and repair.
            raise WorkerInterrupt("Unstable state. Could not connect.")
        except Exception as e:
            raise WorkerInterrupt(e)

        # Set battery threshold
        # The red led will light up at 5-10%
        self.device.battery(30)

        # Read BITalino version
        self.logger.info(self.device.version())

        # Read state and show battery level
        # http://forum.bitalino.com/viewtopic.php?t=448
        state = self.device.state()
        battery = round(
            1 + (state["battery"] - 511) * ((99 - 1) / (645 - 511)), 2)
        self.logger.info("Battery: %.2f%%", battery)

        # Start Acquisition
        self.device.start(rate, channels)

        # Initialize counters for timestamp indices and continuity checks
        self.last_sample_counter = 15
        self.time_device = np.datetime64(int(time.time() * 1e6), "us")
        self.time_local = self.time_device
        self.time_delta = np.timedelta64(int(1000 / rate), "ms")

        # Set meta
        self.meta = {"rate": rate}

    def update(self):
        # Send BITalino data
        data, timestamps = self._read_all()
        self.o.set(data, timestamps, self.columns, self.meta)
        # Send time offsets
        if len(timestamps) > 0:
            offset = (self.time_local - self.time_device).astype(int)
            self.o_offsets.set(
                [[self.time_device, offset]],
                [self.time_local],
                ["time_device", "time_offset"],
            )

    def _read_all(self):
        """Read all available data"""

        # Make sure the device is in aquisition mode
        if not self.device.started:
            raise Exception(ExceptionCode.DEVICE_NOT_IN_ACQUISITION)

        # We only support serial connections
        if not self.device.serial:
            raise Exception("Device must be opened in serial mode.")

        # Check buffer size and limits
        buffer_size = self.device.socket.in_waiting
        if buffer_size == 1020:
            # The device buffer can hold up to 1020 bytes
            self.logger.warn(
                "OS serial buffer saturated. Increase graph rate or decrease device rate."
            )

        # Compute the maximum number of samples we can get
        sample_count = int(buffer_size / self.sample_size)

        # Infer timestamps from sample count and rate
        # Will fail dramatically if too much packets are lost
        # Tests show that there is no significant drift during a 2-hour session
        start = self.time_device
        stop = start + self.time_delta * sample_count
        self.time_device = stop
        timestamps = np.arange(start, stop, self.time_delta)
        self.time_local = np.datetime64(int(time.time() * 1e6), "us")

        # Infer timestamps from local time and rate
        # /!\ Not monotonic
        # stop = np.datetime64(int(time.time() * 1e6), 'us')
        # start = stop - (sample_count * self.time_delta)
        # timestamps = np.arange(start, stop, self.time_delta)

        # Read raw samples from device
        raw = self.device.socket.read(sample_count * self.sample_size)

        # Initialize the output matrix
        data = np.full((sample_count, 5 + self.channel_count), np.nan)

        # Parse the raw data
        # http://bitalino.com/datasheets/REVOLUTION_MCU_Block_Datasheet.pdf
        for sample_number in range(sample_count):

            # Extract sample
            start = sample_number * self.sample_size
            stop = start + self.sample_size
            sample = list(
                struct.unpack(self.sample_size * "B ", raw[start:stop]))

            # Is the sample corrupted?
            crc = sample[-1] & 0x0F
            sample[-1] = sample[-1] & 0xF0
            x = 0
            for i in range(self.sample_size):
                for bit in range(7, -1, -1):
                    x = x << 1
                    if x & 0x10:
                        x = x ^ 0x03
                    x = x ^ ((sample[i] >> bit) & 0x01)
            if crc != x & 0x0F:
                self.logger.warn("Checksum failed.")
                continue

            # Parse sample
            data[sample_number, 0] = sample[-1] >> 4
            data[sample_number, 1] = sample[-2] >> 7 & 0x01
            data[sample_number, 2] = sample[-2] >> 6 & 0x01
            data[sample_number, 3] = sample[-2] >> 5 & 0x01
            data[sample_number, 4] = sample[-2] >> 4 & 0x01
            if self.channel_count > 0:
                data[sample_number,
                     5] = ((sample[-2] & 0x0F) << 6) | (sample[-3] >> 2)
            if self.channel_count > 1:
                data[sample_number,
                     6] = ((sample[-3] & 0x03) << 8) | sample[-4]
            if self.channel_count > 2:
                data[sample_number, 7] = (sample[-5] << 2) | (sample[-6] >> 6)
            if self.channel_count > 3:
                data[sample_number,
                     8] = ((sample[-6] & 0x3F) << 4) | (sample[-7] >> 4)
            if self.channel_count > 4:
                data[sample_number,
                     9] = ((sample[-7] & 0x0F) << 2) | (sample[-8] >> 6)
            if self.channel_count > 5:
                data[sample_number, 10] = sample[-8] & 0x3F

            # Did we miss any sample?
            # Check for discontinuity in the internal sample counter, encoded to 4 bits.
            sample_counter = data[sample_number, 0]
            if sample_counter == self.last_sample_counter + 1:
                pass
            elif sample_counter == 0 and self.last_sample_counter == 15:
                pass
            else:
                self.logger.warn("Missed sample.")
            self.last_sample_counter = sample_counter

        return data, timestamps

    def terminate(self):
        self.device.stop()
        self.device.close()
class BITalinoProcess(Process):
    """
    BITalino acquisition process.
    """
    def __init__(self,
                 outQueue,
                 goFlag,
                 acqFlag,
                 mac=None,
                 channels=[0],
                 step=100,
                 SamplingRate=1000,
                 timeout=5,
                 bitCls=None):
        # run parent __init__
        super(BITalinoProcess, self).__init__()

        # synchronization inputs
        self.queue = outQueue
        self.go = goFlag
        self.acq = acqFlag

        # BITalino settings
        self.mac = mac
        self.channels = channels
        self.step = step
        self.SamplingRate = int(SamplingRate)
        if bitCls is None:
            self.device = BITalino()
        else:
            self.device = bitCls()

        # trigger stuff
        c1, c2 = Pipe()
        self._outerPipe = c1
        self._innerPipe = c2
        self._trigout = 2 * self.step / float(self.SamplingRate)

        # timeout
        self.timeout = timeout

    @classmethod
    def instaStart(cls, *args, **kwargs):
        # do some class method magic here to instantiate and start the process

        outQueue = Queue()
        goFlag = Event()
        goFlag.set()
        acqFlag = Event()

        p = cls(outQueue, goFlag, acqFlag, *args, **kwargs)
        p.start()

        return p, outQueue, goFlag, acqFlag

    def _checkTrigger(self):
        # check if there is a trigger to act on

        if self._innerPipe.poll():
            data = self._innerPipe.recv()

            try:
                mask = data['Mask']
            except KeyError:
                # report failure
                self._innerPipe.send({'Ack': False})
            else:
                # trigger
                self.device.trigger(mask)

                # report success
                self._innerPipe.send({'Ack': True})

    def trigger(self, data=[0, 0, 0, 0]):
        # act on digital outputs

        if not self.acq.is_set():
            return False

        # send mask
        self._outerPipe.send({'Mask': data})

        # wait for ack

        if self._outerPipe.poll(self._trigout):
            out = self._outerPipe.recv()
            return out['Ack']
        else:
            return False

    def connect(self):
        # connect to BITalino

        if self.device.open(self.mac, self.SamplingRate):
            time.sleep(1.5)
            print "successful"
            return True
        else:
            print "failed"
            return False

    def setup(self):
        # setup bitalino

        print "connecting to %s: " % self.mac

        while self.go.is_set():
            if self.connect():
                return True
            time.sleep(1.5)

        return False

    def on_start(self):
        # run immediately after acquisition starts

        pass

    def exit(self):
        # exit process

        self.acq.clear()
        self.go.clear()

    def processData(self, data):
        # process received data

        # send data
        self.queue.put(data)

    def on_stop(self):
        # run immediately before acquisition stops

        pass

    def run(self):
        # main loop

        # connect to device, proceed if successful
        if self.setup():
            while self.go.is_set():
                # wait for acquisition flag
                print "Waiting"
                self.acq.wait(timeout=self.timeout)

                if self.acq.is_set():
                    # start acquisition
                    self.device.start(self.channels)
                    # time.sleep(1)
                    print "acquiring"

                    self.on_start()

                    while self.acq.is_set():
                        # read data
                        data = self.device.read(self.step)

                        # process data
                        self.processData(data)

                        # check trigger
                        self._checkTrigger()

                    # clean up
                    self.on_stop()
                    self.queue.put('')

                    # stop acquisition
                    self.device.stop()
                    # print "blocked"
                    print "acquisition stopped"

            # disconnect device
            self.device.close()
            print "disconnected"
		print "MAC address (%s) is not defined..." %macAddress
		print "connecting to BITalino(%s)..." 
	
# Set battery threshold
device.battery(batteryThreshold)
# Read BITalino version
print device.version()
print "connected to BITalino(%s)" %macAddress
print "creating Signal stream..."
info = StreamInfo('BiTalino','BiTalino',+len(acqChannels),samplingRate,'float32','myuid34234');
# next make an outlet
outlet = StreamOutlet(info)
print"created Signal stream : %s" %info.name()
print("starting acquisition...")
# Start Acquisition
device.start(samplingRate, acqChannels)
# Read samples
while 1:
	data=device.read(nSamples)
	print data
 	outlet.push_sample(data[0][defaultChannel+1:])

# Turn BITalino led on
device.trigger(digitalOutput)
# Stop acquisition
device.stop()
# Close connection
outlet.close()
info.close()
device.close()