Esempio n. 1
0
    def __init__( self ) :

        self._socket = Socket()     
        self._system_spec = _get_endianness_string()
        self._fmt = _Format()
        self._data_fmt = _DataFormat()     
Esempio n. 2
0
    def __init__(self):

        self._socket = Socket()
        self._system_spec = _get_endianness_string()
        self._fmt = _Format()
        self._data_fmt = _DataFormat()
Esempio n. 3
0
class Netstation :     
    """ Provides Python interface for a connection with the Netstation via a TCP/IP socket. """

    def __init__( self ) :

        self._socket = Socket()     
        self._system_spec = _get_endianness_string()
        self._fmt = _Format()
        self._data_fmt = _DataFormat()     

    def connect( self, str_address, port_no ):
        """ connect to the Netstaton machine """

        self._socket.connect( str_address, port_no )

        # return None     

    def disconnect( self ):
        """ close the connection """

        self._socket.disconnect()     

        # return None         

    ## -----------------------------------------------------------
        
    def GetServerResponse( self, b_raise = True ):
        """ read the response from the socket and convert it to a True / False resulting value """

        code = self._socket.read(1)


        if code == 'Z':

            return True

        elif code == 'F' : # an 'F' <error code> sequence     

            error_info_length = self._fmt.format_length( code )     
            error_info = self._socket.read( error_info_length )

            if b_raise :

                err_msg = "server returned an error : " + repr( self._fmt.unpack(code, error_info) )     
                raise Eggog( err_msg )     
                
            else :     
                return False     
        
        elif code == 'I' : # a version byte should follow     

            version_length = self._fmt.format_length( code )     
            version_info = self._socket.read( version_length )
            version = self._fmt.unpack( code, version_info )     

            ## # debug
            ## print version

            self._egi_protocol_version = version     
            self._egi_protocol_version = version[0]     

            return self._egi_protocol_version # just a bit more informative than 'None'     
            
        else : # something completely unexpected     

            if b_raise :
                
                raise Eggog(  "unexpected character code returned from server: '%s'" % (code, )  )     

            else :

                return False     
            
    
    ## -----------------------------------------------------------
    
    def BeginSession( self ) :     
        """ say 'hi!' to the server """     

        ## self._connection.write( 'Q%s' % ( systemSpec, )  )     
        ## assert self.GetServerResponse() == True # " the quick-&-dirty way " // to-do: create an own exception     

        message = self._fmt.pack( 'Q', self._system_spec )
        self._socket.write( message )     

        # debug
        print "BS: ", message     

        return self.GetServerResponse()     
        

    def EndSession( self ):
        """ say 'bye' to the server """

        self._socket.write( 'X' )     
        # self._connection.write( 'X' ).flush()     

        return self.GetServerResponse()     
        
    
    ## -----------------------------------------------------------

    def StartRecording( self ):
        """ start recording to the selected ( externally ) file """

        self._socket.write( 'B' )     
        
        return self.GetServerResponse()     


    def StopRecording( self ):
        """ stop recording to the selected file;     
            the recording can be resumed with the BeginRecording() command     
            if the session is not closed yet .     
        """     

        self._socket.write( 'E' )     
        
        return self.GetServerResponse()     

    ## -----------------------------------------------------------

    def SendAttentionCommand( self ):
        """ Sends and 'Attention' command """ # also pauses the recording ?

        self._socket.write( 'A' )
        
        return self.GetServerResponse()     


    def SendLocalTime( self, ms_time = None ):
        """ Send the local time (in ms) to Netstation; usually this happens after an 'Attention' command """     

        if ms_time is None :     
            ms_time = ms_localtime()

        message = self._fmt.pack( 'T', ms_time )     

	# # debug     
	# print message, struct.unpack('=L', message[1:])     

        self._socket.write( message )     

        return self.GetServerResponse()     
        
    ## -----------------------------------------------------------

    def sync( self, timestamp = None ) :
        """ a shortcut for sending the 'attention' command and the time info """

        if ( self.SendAttentionCommand() ) and ( self.SendLocalTime( timestamp ) ) :

            return True

        else :

            raise Eggog( "sync command failed!" )
        
    
    ## -----------------------------------------------------------

    # send_event, send_simple_event

    ## def pack( self, key, timestamp = None, label = None, description = None, table = None, pad = False ) :     
    def send_event( self, key, timestamp = None, label = None, description = None, table = None, pad = False ) :     
        """
            Send an event ; note that before sending any events a sync() has to be called
            to make the sent events effective .     

            Arguments:
            -- 'id' -- a four-character identifier of the event ;
            -- 'timestamp' -- the local time when event has happened, in milliseconds ;
                              note that the "clock" used to produce the timestamp should be the same
                              as for the sync() method, and, ideally,
                              should be obtained via a call to the same function ;
                              if 'timestamp' is None, a time.time() wrapper is used .
            -- 'label' -- a string with any additional information, up to 256 characters .     
            -- 'description' -- more additional information can go here ( same limit applies ) .
            -- 'table' -- a standart Python dictionary, where keys are 4-byte identifiers,
                          not more than 256 in total ;
                          there are no special conditions on the values,
                          but the size of every value entry in bytes should not exceed 2 ^ 16 .     
                          
            Note A: due to peculiarity of the implementation, our particular version of NetStation
                    was not able to record more than 2^15 events per session .
                    
            Note B: it is *strongly* recommended to send as less data as possible .
            
        """     

        '''
        
        #
        # bufix : as it seems that NetStation
        #
        #        (a) does not clean the internal buffer for the "event" data
        #          and
        #        (b) ignores the "total packet length" from the "event" message header
        #            when reading the "label" / "description" / "key/data" information ,     
        #
        #        we have to append a fake "tail" to our message if the case if it is incomplete --
        #        -- otherwise either garbage or the information from the previous datagram
        #        would be erroneously recognized as belonging to ours .     
        #

        # 
        # the following would make the _DataFormat.pack() method     
        # to create (empty) description and label fields as well, if necessary     
        #
        
        if ( table is None ) or ( len( table.keys() ) <= 0 ) :     

            zero_entry = { '\x00' * 4 : 0 }     
            
        '''     

        message = self._data_fmt.pack( key, timestamp, label, description, table, pad )     
        self._socket.write( message )     

        '''     
        # # debug     
        # print message     
        with open('message.dump', 'ab') as l :     
             l.write("'")
             l.write(message)
             l.write("'")
             l.write('\n\n---\n\n')

        '''     

        return self.GetServerResponse()     


    ## -----------------------------------------------------------

    # legacy code     
    def SendSimpleEvent(self, markercode, timestamp = None ):
        """ send a 'simple' marker event -- i.e. an event marker without any additional information;     
        
            nb. the marker code must be a string of exactly four characters
        """     

        ## assert len(markercode) == 4, "the length of the event marker code must be *exactly* four characters"

        #
        # read the time     
        #

        if timestamp:

            current_time = timestamp

        else: 

            # one day is 1000 * 60 * 60 * 24 milliseconds
            one_day = 1000 * 60 * 60 * 24
            current_time = math.floor( time.time() * 1000 ) % one_day     


        default_duration = 1 # also in milliseconds     


        sizeof_int32 = 4     

        event_min_size = 3 * sizeof_int32     
        data_string = 'D%s%s%s%s' % ( struct.pack('h', event_min_size), # using 'default', or "native", endianness     
                                      struct.pack('l', current_time),
                                      struct.pack('l', default_duration),
                                      struct.pack('4s', markercode),
                                      )

        self._socket.write( data_string )     

        return self.GetServerResponse()     
Esempio n. 4
0
class Netstation:
    """ Provides Python interface for a connection with the Netstation via a TCP/IP socket. """
    def __init__(self):

        self._socket = Socket()
        self._system_spec = _get_endianness_string()
        self._fmt = _Format()
        self._data_fmt = _DataFormat()

    def connect(self, str_address, port_no):
        """ connect to the Netstaton machine """

        return self._socket.connect(str_address, port_no)

        # return None

    def disconnect(self):
        """ close the connection """

        self._socket.disconnect()

        # return None

    ## -----------------------------------------------------------

    def GetServerResponse(self, b_raise=True):
        """ read the response from the socket and convert it to a True / False resulting value """

        code = self._socket.read(1)

        if code == 'Z':

            return True

        elif code == 'F':  # an 'F' <error code> sequence

            error_info_length = self._fmt.format_length(code)
            error_info = self._socket.read(error_info_length)

            if b_raise:

                err_msg = "server returned an error : " + repr(
                    self._fmt.unpack(code, error_info))
                raise Eggog(err_msg)

            else:
                return False

        elif code == 'I':  # a version byte should follow

            version_length = self._fmt.format_length(code)
            version_info = self._socket.read(version_length)
            version = self._fmt.unpack(code, version_info)

            ## # debug
            ## print version

            self._egi_protocol_version = version
            self._egi_protocol_version = version[0]

            return self._egi_protocol_version  # just a bit more informative than 'None'

        else:  # something completely unexpected

            if b_raise:

                raise Eggog(
                    "unexpected character code returned from server: '%s'" %
                    (code, ))

            else:

                return False

    ## -----------------------------------------------------------

    def BeginSession(self):
        """ say 'hi!' to the server """

        ## self._connection.write( 'Q%s' % ( systemSpec, )  )
        ## assert self.GetServerResponse() == True # " the quick-&-dirty way " // to-do: create an own exception

        message = self._fmt.pack('Q', self._system_spec)
        self._socket.write(message)

        # debug
        print "BS: ", message

        return self.GetServerResponse()

    def EndSession(self):
        """ say 'bye' to the server """

        self._socket.write('X')
        # self._connection.write( 'X' ).flush()

        return self.GetServerResponse()

    ## -----------------------------------------------------------

    def StartRecording(self):
        """ start recording to the selected ( externally ) file """

        self._socket.write('B')

        return self.GetServerResponse()

    def StopRecording(self):
        """ stop recording to the selected file;
            the recording can be resumed with the BeginRecording() command
            if the session is not closed yet .
        """

        self._socket.write('E')

        return self.GetServerResponse()

    ## -----------------------------------------------------------

    def SendAttentionCommand(self):
        """ Sends and 'Attention' command """  # also pauses the recording ?

        self._socket.write('A')

        return self.GetServerResponse()

    def SendLocalTime(self, ms_time=None):
        """ Send the local time (in ms) to Netstation; usually this happens after an 'Attention' command """

        if ms_time is None:
            ms_time = ms_localtime()

        message = self._fmt.pack('T', ms_time)

        ## # debug
        ## print message, struct.unpack('=L', message[1:])

        self._socket.write(message)

        return self.GetServerResponse()

    ## -----------------------------------------------------------

    def sync(self, timestamp=None):
        """ a shortcut for sending the 'attention' command and the time info """

        if (self.SendAttentionCommand()) and (self.SendLocalTime(timestamp)):

            return True

        else:

            raise Eggog("sync command failed!")

    ## -----------------------------------------------------------

    # send_event, send_simple_event

    ## def pack( self, key, timestamp = None, label = None, description = None, table = None, pad = False ) :
    def send_event(self,
                   key,
                   timestamp=None,
                   label=None,
                   description=None,
                   table=None,
                   pad=False):
        """
            Send an event ; note that before sending any events a sync() has to be called
            to make the sent events effective .

            Arguments:
            -- 'id' -- a four-character identifier of the event ;
            -- 'timestamp' -- the local time when event has happened, in milliseconds ;
                              note that the "clock" used to produce the timestamp should be the same
                              as for the sync() method, and, ideally,
                              should be obtained via a call to the same function ;
                              if 'timestamp' is None, a time.time() wrapper is used .
            -- 'label' -- a string with any additional information, up to 256 characters .
            -- 'description' -- more additional information can go here ( same limit applies ) .
            -- 'table' -- a standart Python dictionary, where keys are 4-byte identifiers,
                          not more than 256 in total ;
                          there are no special conditions on the values,
                          but the size of every value entry in bytes should not exceed 2 ^ 16 .

            Note A: due to peculiarity of the implementation, our particular version of NetStation
                    was not able to record more than 2^15 events per session .

            Note B: it is *strongly* recommended to send as less data as possible .

        """
        '''

        #
        # bugfix : as it seems that NetStation
        #
        #        (a) does not clean the internal buffer for the "event" data
        #          and
        #        (b) ignores the "total packet length" from the "event" message header
        #            when reading the "label" / "description" / "key/data" information ,
        #
        #        we have to append a fake "tail" to our message if the case if it is incomplete --
        #        -- otherwise either garbage or the information from the previous datagram
        #        would be erroneously recognized as belonging to ours .
        #

        #
        # the following would make the _DataFormat.pack() method
        # to create (empty) description and label fields as well, if necessary
        #

        if ( table is None ) or ( len( table.keys() ) <= 0 ) :

            zero_entry = { '\x00' * 4 : 0 }

        '''

        message = self._data_fmt.pack(key, timestamp, label, description,
                                      table, pad)
        self._socket.write(message)
        '''
        # # debug
        # print message
        with open('message.dump', 'ab') as l :
             l.write("'")
             l.write(message)
             l.write("'")
             l.write('\n\n---\n\n')

        '''

        return self.GetServerResponse()

    def send_timestamped_event(self,
                               key,
                               label=None,
                               description=None,
                               table=None,
                               pad=False):
        """
            Send an event timestamped to the time it is sent;
            note that before sending any events a sync() has to be called
            to make the sent events effective .

            Arguments:
            -- 'id' -- a four-character identifier of the event ;
            -- 'timestamp' -- the local time when event has happened, in milliseconds ;
                              note that the "clock" used to produce the timestamp should be the same
                              as for the sync() method, and, ideally,
                              should be obtained via a call to the same function ;
                              if 'timestamp' is None, a time.time() wrapper is used .
            -- 'label' -- a string with any additional information, up to 256 characters .
            -- 'description' -- more additional information can go here ( same limit applies ) .
            -- 'table' -- a standart Python dictionary, where keys are 4-byte identifiers,
                          not more than 256 in total ;
                          there are no special conditions on the values,
                          but the size of every value entry in bytes should not exceed 2 ^ 16 .

            Note A: due to peculiarity of the implementation, our particular version of NetStation
                    was not able to record more than 2^15 events per session .

            Note B: it is *strongly* recommended to send as less data as possible .

        """
        '''

        #
        # bugfix : as it seems that NetStation
        #
        #        (a) does not clean the internal buffer for the "event" data
        #          and
        #        (b) ignores the "total packet length" from the "event" message header
        #            when reading the "label" / "description" / "key/data" information ,
        #
        #        we have to append a fake "tail" to our message if the case if it is incomplete --
        #        -- otherwise either garbage or the information from the previous datagram
        #        would be erroneously recognized as belonging to ours .
        #

        #
        # the following would make the _DataFormat.pack() method
        # to create (empty) description and label fields as well, if necessary
        #

        if ( table is None ) or ( len( table.keys() ) <= 0 ) :

            zero_entry = { '\x00' * 4 : 0 }

        '''
        timestamp = ms_localtime()
        message = self._data_fmt.pack(key, timestamp, label, description,
                                      table, pad)
        self._socket.write(message)
        '''
        # # debug
        # print message
        with open('message.dump', 'ab') as l :
             l.write("'")
             l.write(message)
             l.write("'")
             l.write('\n\n---\n\n')

        '''

        return self.GetServerResponse()

        ## -----------------------------------------------------------

    # legacy code
    def SendSimpleEvent(self, markercode, timestamp=None):
        """ send a 'simple' marker event -- i.e. an event marker without any additional information;

            nb. the marker code must be a string of exactly four characters
        """

        ## assert len(markercode) == 4, "the length of the event marker code must be *exactly* four characters"

        #
        # read the time
        #

        if timestamp:

            current_time = timestamp

        else:

            # one day is 1000 * 60 * 60 * 24 milliseconds
            one_day = 1000 * 60 * 60 * 24
            current_time = math.floor(time.time() * 1000) % one_day

        default_duration = 1  # also in milliseconds

        sizeof_int32 = 4

        event_min_size = 3 * sizeof_int32
        data_string = 'D%s%s%s%s' % (
            struct.pack(
                'h',
                event_min_size),  # using 'default', or "native", endianness
            struct.pack('l', current_time),
            struct.pack('l', default_duration),
            struct.pack('4s', markercode),
        )

        self._socket.write(data_string)

        return self.GetServerResponse()

    def SendSimpleTimestampedEvent(self, markercode):
        """ send a 'simple' marker event -- i.e. an event marker without any additional information;

            nb. the marker code must be a string of exactly four characters
        """

        ## assert len(markercode) == 4, "the length of the event marker code must be *exactly* four characters"

        #
        # read the time
        #

        current_time = ms_localtime()

        default_duration = 1  # also in milliseconds

        sizeof_int32 = 4

        event_min_size = 3 * sizeof_int32
        data_string = 'D%s%s%s%s' % (
            struct.pack(
                'h',
                event_min_size),  # using 'default', or "native", endianness
            struct.pack('l', current_time),
            struct.pack('l', default_duration),
            struct.pack('4s', markercode),
        )

        self._socket.write(data_string)

        return self.GetServerResponse()