class NexusSDKCollector():
    
    def run(self,nexusSerial,port):
        self.despikes=[0,0,0]
    
        self.portBase=port
        # set up senders and data queues
        self.outQueues = []
        self.dataSenders=[]
        self.senderParent=SenderParent(self.portBase,self)
        for c in range(0,10):
            self.dataSenders.append (ChildDataSender(c,self))
            self.outQueues.append(deque())
        for ds in self.dataSenders:
            ds.start()
        self.senderParent.start()
    
    
        NEXUSDATAFUNC = CFUNCTYPE(None,c_int, c_int, POINTER(c_float))
        self.dll=cdll.LoadLibrary('GenericDeviceInterfaceDLL2.dll')
        self.dll.InitGenericDevice.restype=c_int
        self.dll.StartGenericDevice.restype=c_int
        self.callbackFunction=NEXUSDATAFUNC(self.nexusDataFunction)
        retVal=self.dll.InitGenericDevice(self.callbackFunction,1,c_longlong(nexusSerial))    
        if retVal==-6:
            self.dll.ShowAuthenticationWindow()
                    
        print retVal
        sampleRate=c_int(256)
        retVal=self.dll.StartGenericDevice(byref(sampleRate))
        print retVal
        
        while True:
            time.sleep(10)
    
    def nexusDataFunction(self,nsamples,nchannels,pData):                
        if nchannels>=10:
            data=[0,0,0,0,0,0,0,0,0,0]
            for c in range(10):
                data[c]=pData[c]            
            self.despikeGSR(data)
            for (c,ds) in enumerate(self.dataSenders):
                if ds.isConnected():
                    self.outQueues[c].append("%f"%data[c])
            # trigger the data senders all at once
            for ds in self.dataSenders:
                if ds.isConnected():
                    ds.dataReady()
        #print "[%2.2d,%2.2d] "%(nsamples,nchannels),
         
        #for c in range(nchannels):
            #print "%2.2f"%pData[c],
            #print ",",
        #print ""
        
    
    def despikeGSR(self,data):
        self.despikes.append(data[5])
        if len(self.despikes)>3:
            self.despikes=self.despikes[1:]
        minVal=min(self.despikes)
        maxVal=max(self.despikes)
        curVal=data[5]
        for c in self.despikes:
            if c!=minVal and c!=maxVal:
                data[5]=c
        
        
                    
    def getData(self,port):
        portnum=port
        if len(self.outQueues[portnum])>0:
            return self.outQueues[portnum].popleft()
        else:
            return None
            
    def getMultiStream(self,queryString):
        print "connect multistream %s"%queryString
        try:
            if int(queryString)<len(self.outQueues) and int(queryString)>=0:
                return self.dataSenders[int(queryString)]
        except ValueError,v:
            None
        print "bad query string for nexus collector"
        return None
class NexusDirectCollector():
    
    def run(self,nexusComPort,port):
        self.portBase=port
        self.comport=nexusComPort
        while True:
            try:
                self.port = serial.Serial(self.comport,115200,timeout=10)

                # set up senders and data queues
                self.outQueues = []
                self.dataSenders=[]
                self.senderParent=SenderParent(self.portBase,self)
                for c in range(0,10):
                    self.dataSenders.append (ChildDataSender(c,self))
                    self.outQueues.append(deque())
                for ds in self.dataSenders:
                    ds.start()
                self.senderParent.start()
           
                #    start reading data from nexus
                self.writePort("AA AA 00 05 56 50")
                  
                  
                #port setup
                self.writePort("AA AA 02 22 00 00 80 00 D4 32")
                self.writePort("AA AA 02 22 80 00 53 00 81 32")
                self.writePort("AA AA 02 22 00 10 80 00 D4 22")
                self.writePort("AA AA 02 22 01 10 80 00 D3 22 	")
                self.writePort("AA AA 02 22 00 00 80 00 D4 32 ")
                self.writePort("AA AA 02 22 80 00 53 00 81 32 ")
                self.writePort("AA AA 02 22 00 10 80 00 D4 22 ")
                self.writePort("AA AA 02 22 01 10 80 00 D3 22 	")

                #go
                self.writePort("AA AA 03 02 0E 00 00 00 00 00 45 53")

                #stay alive
                self.writePort("AA AA 00 27 56 2E",False)

                singlePacket=[]
                foundPacket=0
                
                self.despikes=[0,0,0]



                stayalivelast=time.clock()        
                while True:
                    #    stay alive
                    if (time.clock()-stayalivelast)>0.5:
                        self.writePort("AA AA 00 27 56 2E",False)
                        stayalivelast=time.clock()                
                        #    print "Stay alive"
                        
                    data=self.port.read(64)
                    packetBuffer=map(ord,data)
                    for c in packetBuffer:
                        if c==0xaa:
                            foundPacket+=1
                        else:
                            if foundPacket>=2:
                                # dump packet
        #                        for val in singlePacket:
        #                            print "%02x"%val,
        #                        print ""
                                self.sendPacketValues(singlePacket)
                                singlePacket=[]
                            foundPacket=0
                        singlePacket.append(c)
            except serial.SerialException,e:
                print "Couldn't connect Nexus on ",nexusComPort
                time.sleep(5)
class VilistusSerialCollector():
    
    def run(self,sensorPort,portBase):
        self.comport=None
        self.portBase = portBase
        self.outQueues = []
        self.dataSenders=[]
        self.portCount=6
        self.senderParent=SenderParent(portBase,self)
        for c in range(0,self.portCount):
            self.dataSenders.append (ChildDataSender(c,self))
            self.outQueues.append(deque([],1000))
        for ds in self.dataSenders:
            ds.start()
        self.senderParent.start()
        
        self.connected=False
        self.comport=None
        
        dataBuffers=[]
        spareData=""
        
        while(True):
            try:
                # connect to vilistus if it isn't
                if not self.connected:                
                    time.sleep(0.25)
                    self.comport=serial.Serial(sensorPort,57600,timeout=5)
                    dataLines=self.comport.readlines(64)
                    if len(dataLines)==0 or len(dataLines[-1])<20:                    
                        print "Can't connect to q sensor %s"%sensorPort
                        self.connected=False
                        self.comport.close()
                        self.comport=None
                    else:
                        self.connected=True
                        print "connected to q sensor %s"%sensorPort
                        self.comport.timeout=1.0
                else:
                    dataLine=self.comport.readline(64)
                    dataLine=dataLine.strip('\r')
                    dataLineSplit=dataLine.split(',')
                    if len(dataLineSplit)>=7:
                        #print "Good data Line",dataLine
                        for c in range(0,self.portCount):
                            try:
                                value=float(dataLineSplit[c+1])                                
                                if self.dataSenders[c].isConnected():
                                    self.outQueues[c].append("%f"%value)
                            except ValueError:
                                print "Bad value:",dataLineSplit[c+1]
                        # trigger the data senders
                        for ds in self.dataSenders:
                            ds.dataReady()
                    else:
                        print "Bad data line",dataLine
                        self.comport.close()
                        self.comport=None
                        self.connected=False
            except serial.SerialException,e:
                print "Serial connection failed",e
                self.comport=None
                self.connected=False
class EmotivDirectCollector():

    # userNum is the index of the headset to use
    def run(self,emotivHost,emotivPort,portBase,userNum):        
        self.senderLock=Lock()
        self.portBase = portBase
        self.channelCount=15
        self.outQueues = {}
        self.dataSenders={}
        self.newSenders={}
        self.headset=Headset(emotivHost,emotivPort,userNum)
        self.senderParent=SenderParent(portBase,self)
        self.senderParent.start()

        lastTime=time.clock()
        while(True):
            # arbitrary polling interval - 128hz
            curTime=time.clock()
            sleepTime=0.0078125-( curTime-lastTime)
            if sleepTime>0:
                time.sleep(0.0078125-( curTime-lastTime))
            
            lastTime=curTime

            self.headset.handleEvents()
# debug code to display all channel values            
#            values=[]
#            for c in range(0,15):
#                values.append(self.getHeadsetChannel(c))
#            print values
            # read the raw data from the headset
            self.headset.readRawData()
            # get the data from the channels we are listening to from the headset
            # and put the data into the out queues
            self.senderLock.acquire()
            for (channel,ds) in self.dataSenders.iteritems():
                if ds.isConnected():
                    if channel<100:
                        # emotion detection etc.
                        value=self.getHeadsetChannel(channel)
                        self.outQueues[channel].append(value)
                    elif channel<200:
                        # raw EEG/accelerometer etc. channels 100-125
                        if self.headset.hasState:
                            values=self.headset.getRawChannel(channel-100)
                            for c in values:
                                self.outQueues[channel].append("%f"%c)
                    elif channel<300:
                        # signal quality / connection quality
                        raise "need to implement signal quality channels"
            # trigger data senders for each out queue - trigger all at once so data comes nicely in sync
            for ds in self.dataSenders.itervalues():
                if ds.isConnected():
                    ds.dataReady()
            self.senderLock.release()

    # called by datasenders to get the data to be sent
    def getData(self,port):
        if self.outQueues.has_key(port) and len(self.outQueues[port])>0:
            return self.outQueues[port].popleft()
        else:
            return None
            
    def getMultiStream(self,queryString):
#        print "connect multistream %s"%queryString
        retVal=None
        self.senderLock.acquire()
        try:
            channelNum=int(queryString)
            if channelNum<self.channelCount and channelNum>=0:
                if not self.dataSenders.has_key( channelNum):
                    self.dataSenders[channelNum]=ChildDataSender(channelNum,self)
                    self.outQueues[channelNum]=deque([],1000)
                    self.dataSenders[channelNum].start()
                retVal= self.dataSenders[channelNum]
            elif channelNum>=100 and channelNum<125:
                # raw EEG / accelerometer data
                if not self.dataSenders.has_key( channelNum):
                    self.dataSenders[channelNum]=ChildDataSender(channelNum,self)
                    self.outQueues[channelNum]=deque([],1000)
                    self.dataSenders[channelNum].start()
                retVal= self.dataSenders[channelNum]
            elif channelNum>=200 and channelNum<216:
                # sensor signal quality
                raise "Implement sensor signal quality channels"
                retVal=None
        except ValueError,v:
            retVal=None # drop out
        if retVal==None:
            print "bad query string for Emotiv collector:",queryString
        self.senderLock.release()
        return retVal