def __init__( self ) : self._socket = Socket() self._system_spec = _get_endianness_string() self._fmt = _Format() self._data_fmt = _DataFormat()
def __init__(self): self._socket = Socket() self._system_spec = _get_endianness_string() self._fmt = _Format() self._data_fmt = _DataFormat()
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()
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()