def rpc_init(self): "Initializes the serial connection and the MSP430." port = self.Configuration['SerialPort'] self.logdebug("Initializing MSP430 at '%s'." % self.Configuration['SerialPort']) self.send(Message(self.name, port, "subscribe", {"name": self.name, "function": "serialsubscription"})) self.send(Message(self.name, port, "connect")) self.send(Message(self.name, port, "write", "\n")) self.send(Message(self.name, port, "write", "hello\n"))
def scanregistry(self, node=""): msg = Message(sender=self.name, recipientnode=node, recipient=self.systemregistry, func="listRegisteredComponents", arg=None) self.transmit(msg) msg = Message(sender=self.name, recipientnode=node, recipient=self.systemregistry, func="listRegisteredTemplates", arg=None) self.transmit(msg)
def composeMessage(self, name="", node="", sender=None): if not sender: sender = self.name msg = Message(sender=sender, recipientnode=node, recipient=name) msgdialog = TkMessageDialog(self.window, msg, onclosecallback=self.transmit)
def rpc(self): # Inconveniently decode JSON back to an object. # Actually this should be managed by cherrpy and jQuery, # alas that prove difficult. cl = cherrypy.request.headers['Content-Length'] rawbody = cherrypy.request.body.read(int(cl)) body = jsonpickle.decode(rawbody) recipient = body['recipient'] func = body['func'] arg = body['arg'] # Suppose this should be the same for all calls to /rpc cherrypy.response.headers['Content-Type'] = 'application/json' # Replace simple directory addresses if recipient in self.gateway.directory: recipient = self.gateway.directory[recipient] msg = Message(sender=self.gateway.name, recipient=recipient, func=func, arg=arg) self.gateway.transmit(msg, self) # Store defer and wait for request's response return self.defer(msg)
def rpc_blinkLight(self, light, count): if light <= 1: for blink in range(count): self.send(Message(self.name, self.Configuration['SerialPort'], "write", "toggle%i\n" % light)) return (True) else: return (False, "Not more than two lights available.")
def _pingNodes(self): disconnectednodes = [] for node in self.nodes: if self.nodes[node]['lastping'] + self.nodes[node][ 'interval'] <= time(): if self.nodes[node]['pingcount'] >= 3: self.loginfo( "Node '%s' hasn't reacted for three pings, disconnecting." % node) disconnectednodes.append(node) else: self.loginfo("Pinging '%s'." % node) self.nodes[node]['pingcount'] += 1 self.nodes[node]['lastping'] = time() ping = Message(sender=self.name, sendernode=identity.SystemUUID, recipientnode=node, recipient='DTNGate', func='ping', arg={}) self.nodes[node]['socket'].send(jsonpickle.encode(ping)) else: pass #self.logdebug("Not pinging '%s' - interval not yet reached." % node) for node in disconnectednodes: self._disconnectNode(node, announce=False)
def rpc_gpsinput(self, args): sen_type, sen = args if sen_type == 'GPGGA': self.latitude = self._decode(sen.latitude, sen.lat_direction) self.longitude = self._decode(sen.longitude, sen.lon_direction) elif sen_type == 'GPGLL': self.latitude = self._decode(sen.lat, sen.lat_direction) self.longitude = self._decode(sen.lon, sen.lon_direction) elif sen_type == 'GPRMC': self.latitude = self._decode(sen.lat, sen.lat_dir) self.longitude = self._decode(sen.lon, sen.lon_dir) self.track = float(sen.true_course) self.speed = float(sen.spd_over_grnd) elif sen_type == 'GPVTG': self.track = float(sen.true_track) self.speed = float(sen.spd_over_grnd_kts) else: return for subscriber, function in self.subscribers.items(): self.loginfo("Sending tracker data to subscriber %s" % subscriber) message = Message(sender=self.name, recipient=subscriber, func=function, arg={'latitude': self.latitude, 'longitude': self.longitude, 'track': self.track, 'speed': self.speed}) self.send(message, "outbox")
def rpc_test_remote_transmit(self): msg = Message(sender=self.name, recipient="cape.system.RegistryComponent.RegistryComponent_7", recipientnode='3508dac4-1b23-4134-81f9-29cd10e02181', func="listRegisteredComponents", arg=None) self.send(msg, "outbox")
def handleMessage(msg): if not msg.localRecipient: self.logcritical("Remote node message received for '%s'" % msg.recipientnode) if msg.recipientnode in self.gateways: gateway = self.gateways[msg.recipientnode] msg.sendernode = str(identity.SystemUUID) forward = Message( sender=self.name, recipient=self.gateways[msg.recipientnode], func="transmit", arg={'msg': msg}) self.send(forward, gateway) else: self.logwarning("Remote node '%s' not available." % msg.recipientnode) self.logdebug("Offending sender: '%s'" % msg.sender) else: if msg.recipient in self.directory: # Replace with real name msg.recipient = self.directory[msg.recipient] if msg.recipient in self.inboxes: self.send(msg, msg.recipient) else: self.logerror( 'MESSAGE WITH ERRONEOUS RECIPIENT RECIEVED: %s\n%s\n' % (msg, self.inboxes))
def rpc_setThrust(self, newthrust): """Calculates the new servo value for a given thrust. Arranges 4 bytes to contain the control command, servo address and new target. Transmits a Message containing these bytes to the Maestro Component and returns True. """ # Problems: # * We don't really know what name the Maestro has. # * Most of the stuff isn't really configureable right now, this has to wait for the configuration # system to be # fully grown to potential. # * This is a very Maestro centric component, and should be defined as such. # * It cannot really decide wether the maestro actually sent the command, # unless we integrate states and defers # (It has to talk back with the Maestro and await its response before it can reliably give the # requesting # party a response) target = int(self.center + (self.delta / 2) * newthrust) #print(("\n\n\n##### ENGINE TARGET: ", target)) # Construct the bytes to send to the maestro byte = chr(0x84) + chr(self.address) + chr((target * 4) & 0x7f) + chr(( (target * 4) >> 7) & 0x7F) #print(("##### ENGINE BYTES: ", byte, "\n\n\n")) self.send( Message(self.name, self.Configuration['Maestro'], "write", {"args": byte})) # TODO: Instead of this, we should enter a state here and await a response before returning our OK. return (True, "New thrust set.")
def scancomponent(self, name, node=""): self.logdebug("Scanning component '%s'." % name) msg = Message(sender=self.name, recipientnode=node, recipient=name, func="getComponentInfo", arg=None) self.transmit(msg)
def rpc_updateControls(self, latitude, longitude, track, speed): currentTime = time() if self.course is None: return False, "Course not set" elif self.speed is None: return False, "Speed not set" correction = self.course - track if correction > 180: correction -= 360 elif correction < -180: correction += 360 rudder = self.Configuration['rudderProportionalGain'] * correction if self.previousTime is not None: gain = self.Configuration['rudderDerivativeGain'] change = track - self.previousTrack interval = currentTime - self.previousTime rudder -= gain * change / interval if rudder < -1: rudder = -1 elif rudder > 1: rudder = 1 request = Message(sender=self.name, recipient=self.Configuration['rudder'], func="setRudder", arg={'newangle': float(rudder)}) self.send(request, "outbox") correction = self.speed - speed thrust = self.Configuration['thrustProportionalGain'] * correction if self.previousTime is not None: gain = self.Configuration['thrustDerivativeGain'] change = speed - self.previousSpeed interval = currentTime - self.previousTime thrust -= gain * change / interval if thrust < 0: thrust = 0 elif thrust > 1: thrust = 1 request = Message(sender=self.name, recipient=self.Configuration['engine'], func="setThrust", arg={'newthrust': float(thrust)}) self.send(request, "outbox") self.previousTrack = track self.previousSpeed = speed self.previousTime = currentTime return True
def callSimpleMethod(self, name, node, func): self.loginfo("Calling '%s'@'%s'." % (func, name)) msg = Message(sender=self.name, recipient=name, recipientnode=node, func=func, arg=None) self.transmit(msg)
def createcomponent(self, name, node=""): self.loginfo("Creating component from template '%s'." % name) msg = Message(sender=self.name, recipientnode=node, recipient=self.systemregistry, func="createComponent", arg={'templatename': name}) self.transmit(msg)
def main_prepare(self): self.latitude = 0.0 self.longitude = 0.0 self.track = 0.0 self.speed = 0.0 self.loginfo("Subscribing to NMEA data") request = Message(sender=self.name, recipient=self.Configuration['gps'], func="subscribe", arg={'function': 'gpsinput', 'name': self.name}) self.send(request, "outbox")
def rpc_test_local_discovery(self): context = zmq.Context() socket = context.socket(zmq.DEALER) socket.connect("tcp://%s:55555" % (DTNConnector.routeraddress)) msg = Message(sendernode="FOOBAR", func="discovery", arg={'ip': 'bazqux'}) package = jsonpickle.encode(msg) self.logdebug("Transmitting '%s' to local node discovery " % package) socket.send(package) return True
def callComplexMethodFinal(self, name, node, func, args): self.loginfo("Finally calling func '%s'@'%s' with args '%s'" % (func, name, args)) msg = Message(sender=self.name, recipientnode=node, recipient=name, func=func, arg=args) self.transmit(msg)
def main_prepare(self): self.loginfo("Controller subscribing to tracker") request = Message(sender=self.name, recipient=self.Configuration['tracker'], func="subscribe", arg={ 'name': self.name, 'function': 'updateControls' }) self.send(request, "outbox")
def main_prepare(self): self.loginfo("Subscribing to configured SerialPort") request = Message(sender=self.name, recipient=self.Configuration['SerialPort'], func="subscribe", arg={ 'function': 'nmeainput', 'name': self.name }) self.send(request, "outbox")
def _feedSubscribers(self): self.loginfo("Feeding subscribers.") for subscriber, method in self.subscribers.iteritems(): self.logdebug( "Transmitting resource to subscriber function '%s'@'%s'." % (subscriber, method)) msg = Message(sender=self.name, recipient=subscriber, func=method, arg={'resource': self.resource}) self.send(msg, "outbox")
def mainthread(self): for i, offset in enumerate(range(3, 8, 2)): msb = self.bus.read_byte_data(self.address, offset) lsb = self.bus.read_byte_data(self.address, offset + 1) value = (msb << 8) + lsb if value >= 32768: value -= 65536 self.values[i] = value for subscriber, func in self.subscribers.items(): self.send(Message(sender=self.name, recipient=subscriber, func=func, arg={'x': self.values[0], 'y': self.values[2], 'z': self.values[1]}), "outbox") sleep(0.1)
def mainthread(self): if self.Port and self.Port.isOpen() and self.listening: self.buf = self.buf + self.Port.read(self.Port.inWaiting()) if self.Configuration['readline']: if '\n' in self.buf: lines = self.buf.split( '\n') # Guaranteed to have at least 2 entries line = lines[-2] self.buf = lines[-1] self.logdebug(line) for recipient in self.subscribers: msg = Message(sender=self.name, recipient=recipient, func=self.subscribers[recipient], arg={'line': line}) self.send(msg, "outbox") else: for recipient in self.subscribers: msg = Message(sender=self.name, recipient=recipient, func=self.subscribers[recipient], arg=self.buf) self.send(msg, "outbox") self.buf = ""
def main_loop(self): """ Loops and pings the configured pong component every configured interval. """ if self.Configuration['target'] and (self.lastping + self.Configuration['interval'] < time()): self.logdebug("Pinging '%s'." % (self.Configuration['target'])) self.lastping = time() # Time to act: Send a ping message to our pong counterpart self.count += 1 pingmsg = Message(sender=self.name, recipient=self.Configuration['target'], recipientnode=self.Configuration['targetnode'], func="ping", arg=None) self.send(pingmsg, "outbox")
def _disconnectNode(self, node, announce=True): if node not in self.nodes: return (False, "Node not connected.") socket = self.nodes[node]['socket'] if announce: msg = Message(sendernode=str(identity.SystemUUID), sender=self.name, recipient='DTNGate', func='disconnect') socket.send(jsonpickle.encode(msg)) socket.close() del (self.nodes[node]) return True
def rpc_nmeainput(self, line): """ Called when a publisher sends a new nmea sentence to this sensor. The nmea data is parsed and further handling can happen. """ sen_time = time() # TODO: This is late due to message traversal etc. for sentence in self.streamer.get_objects(line): self.nmeaLog[sen_time] = { 'raw': line, 'type': sentence.sen_type, 'obj': sentence } for recipient, func in self.subscribers.items(): msg = Message(sender=self.name, recipient=recipient, func=func, arg={'args': (sentence.sen_type, sentence)}) self.send(msg, "outbox")
def rpc_setRudder(self, newangle): """Calculates the new servo value for a given angle. Arranges 4 bytes to contain the control command, servo address and new target. Transmits a Message containing these bytes to the Maestro Component and returns True. """ target = int(self.center + (self.delta / 2) * newangle) #print(("\n\n\n##### ENGINE TARGET: ", target)) # Construct the bytes to send to the maestro byte = chr(0x84) + chr(self.address) + chr((target * 4) & 0x7f) + chr(( (target * 4) >> 7) & 0x7F) #print(("##### ENGINE BYTES: ", byte, "\n\n\n")) self.send( Message(self.name, self.Configuration['Maestro'], "write", {"args": byte})) # TODO: Instead of this, we should enter a state here and await a response before returning our OK. return (True, "New angle set.")
def main_prepare(self): """ Method that is executed prior entering mainloop. Overwrite if necessary. """ self.logdebug("Requesting database access.") if "database" in self.directory: recipient = self.directory['database'] self.logdebug("Database found: '%s'" % recipient) msg = Message(sender=self.name, recipient=recipient, func="getCollection", arg={ 'name': "wiki", 'create': True }) self.send(msg, "outbox") self.loginfo("Database access requested.") else: self.logerror("No db access.")
def _discoverNode(self, ip): self.loginfo("Discovering node '%s'" % ip) socket = self.context.socket(zmq.DEALER) socket.setsockopt(zmq.IDENTITY, str(identity.SystemUUID)) socket.connect('tcp://%s:55555' % ip) # TODO: Is this smart, sending discovery data upon first message? # Maybe better in the reply... msg = Message(sendernode=str(identity.SystemUUID), sender=self.name, recipient='DTNGate', func="discover", arg={ 'ip': self.Configuration['routeraddress'], 'registry': str(self.systemregistry), 'dispatcher': str(self.systemdispatcher), }) self.logdebug("Discovery message: '%s'" % msg) socket.send(jsonpickle.encode(msg)) self.probednodes[ip] = socket self.logdebug("Discovery sent to '%s'" % ip)
def main(self): protocol_running = True self.loginfo("Client connected.") while protocol_running: while not self.anyReady(): self.pause() # Thumb twiddling. yield 1 response = None if self.dataReady("inbox"): msg = self.recv("inbox") if ("ALL" in self.msgfilter['recipients']) or (not self.msgfilter['recipients']) or msg.recipient in self.msgfilter['recipients']: self.send(msg.jsonencode().encode("utf-8"), "protocolout") yield 1 else: self.logwarning("Filtered: %s" % msg) if self.dataReady("protocolin"): response = None msg = None data = None self.logdebug("Running inbox.") data = self.recv("protocolin") if len(data) == 0: response = "\n" else: try: msg = jsonpickle.decode(data.decode("utf-8")) if isinstance(msg, Message): # TODO: Message validation! msg.sender = self.name self.send(msg, "outbox") self.logdebug("Accepted external message.") else: self.logdebug("Malformed message or non message. Type '%s': '%s'" % (type(msg), msg)) response = Message(sender=self.name, recipient="CLIENT", func="Error", arg="Malformed Message") except ValueError as error: self.logwarning("%s:MALFORMED INPUT: %s" % (self.name, data)) response = Message(sender=self.name, recipient="CLIENT", func="ValueError", arg=[error.args[0], data.decode("UTF-8", errors="ignore")]) # TODO: Watch this crappy exception. We need better input handling against bad boys. self.logdebug(response) # if msg and isinstance(msg, Message): # if msg.recipient == "JSONServer": # if msg.func == "SetFilter": # self.msgfilter = msg.arg # #response = msg.response(True) # print(("Filter has been changed to %s" % msg.arg)) # if msg.func == "AddRecipient": # self.msgfilter['recipients'].append(msg.arg) # #response = msg.response(True # print(("Recipient %s has been added to filter." % msg.arg)) if response: response = response.jsonencode() response = response.encode("utf-8") self.send(response, "protocolout") yield 1 if self.dataReady("control"): data = self.recv("control") if isinstance(data, Kamaelia.IPC.socketShutdown): self.loginfo("Protocol shutting down.") protocolRunning = False yield 1
def handleResponse(self, response): if response.error == "Not connected.": # TODO: WHAT THE HECK. Not like this. self.logwarning("Serialport not connected. Trying to connect.") self.send( Message(self.name, self.Configuration['SerialPort'], "connect"))
def _handleMessage(self, msg): """ Handle messages for this DTNGate component. """ sendernode = msg.sendernode if sendernode in self.nodes: # Any message from a node resets the ping interval self.nodes[sendernode]['lastping'] = time() self.logdebug("Analysing input: '%s'" % msg) if msg.func == "ping": if msg.type == "request": self.loginfo("Got a ping from '%s'." % sendernode) response = msg.response(time()) if sendernode in self.nodes: self.loginfo("Replying to ping request.") self.nodes[sendernode]['pingcount'] = 0 self.nodes[sendernode]['socket'].send( jsonpickle.encode(response)) else: self.logerror("Can't respond to ping request, no socket!") if msg.type == "response": self.loginfo("Got a pong from '%s'." % sendernode) if sendernode in self.nodes: self.nodes[sendernode]['pingcount'] = 0 if msg.func == "disconnect": if sendernode in self.nodes: self.loginfo( "Disconnect announcement received from '%s'@'%s'" % (sendernode, self.nodes[sendernode]['ip'])) self._disconnectNode(sendernode) else: self.logwarning( "Disconnect announcement from unconnected node received '%s', args: '%s'" % (sendernode, msg.arg)) if msg.func == "discover": node = msg.arg ip = node['ip'] if msg.type == 'request': self.loginfo("Probe request received from '%s' " % node['ip']) # We're being probed! Store request details. self.probes[ip] = { 'uuid': sendernode, 'registry': node['registry'], 'dispatcher': node['dispatcher'], 'lastping': time(), 'pingcount': 0, 'interval': 15 # TODO: Automate the interval with smart info (like movement speed) } if ip in self.probednodes: self.loginfo("Probe returned storing socket for '%s'" % (ip)) self.nodes[sendernode] = self.probes[ip] self.nodes[sendernode]['socket'] = self.probednodes[ip] reply = msg.response( {'ip': self.Configuration['routeraddress']}) self.nodes[sendernode]['socket'].send( jsonpickle.encode(reply)) route = Message( sender=self.name, recipient=self.systemdispatcher, func="addgateway", arg={ 'remotenode': sendernode, 'connector': self.name }, ) self.send(route, "outbox") del (self.probednodes[ip]) del (self.probes[ip]) else: self.loginfo( "Uninitiated probe by '%s' - discovering in reverse." % ip) self._discoverNode(ip) else: # Hm, a response! This is the last packet in our discovery chain. self.loginfo("'%s' has successfully connected to us." % ip) # if ip in self.probes: probe = self.probes[ip] self.nodes[probe['uuid']] = probe self.nodes[probe['uuid']]['socket'] = self.probednodes[ip] self.nodes[probe['uuid']]['lastping'] = time() self.nodes[probe['uuid']]['pingcount'] = 0 self.nodes[probe['uuid']]['interval'] = 15 route = Message( sender=self.name, recipient=self.systemdispatcher, func="addgateway", arg={ 'remotenode': probe['uuid'], 'connector': self.name }, ) self.send(route, "outbox") del (self.probednodes[ip]) del (self.probes[ip]) self.loginfo("Connected nodes after discovery action: '%s'" % self.nodes.keys())