Ejemplo n.º 1
0
    def __init__(self, server):
        self.server = server
        self.values = {'gps': {}, 'wind': {}, 'rudder': {}}

        def make_source(name, dirname, speed=True):
            timestamp = server.TimeStamp(name)
            self.values[name][dirname] = server.Register(
                SensorValue(name + '.' + dirname, timestamp, directional=True))
            if speed:
                self.values[name]['speed'] = server.Register(
                    SensorValue(name + '.speed', timestamp))
            self.values[name]['source'] = server.Register(
                StringValue(name + '.source', 'none'))
            self.values[name]['lastupdate'] = 0

        make_source('gps', 'track')
        make_source('wind', 'direction')
        make_source('rudder', 'angle')

        self.devices = []
        self.devices_lastmsg = {}
        self.probedevice = None
        self.primarydevices = {'gps': None, 'wind': None, 'rudder': None}
        self.gpsdpoller = GpsdPoller(self)

        self.process = NmeaBridgeProcess()
        self.process.start()
        self.poller = select.poll()
        self.process_fd = self.process.pipe.fileno()
        self.poller.register(self.process_fd, select.POLLIN)
        self.gps_fd = self.gpsdpoller.process.pipe.fileno()
        self.poller.register(self.gps_fd, select.POLLIN)
        self.device_fd = {}

        self.nmea_times = {}
        self.last_imu_time = time.time()
        self.last_rudder_time = time.time()
        self.starttime = time.time()
Ejemplo n.º 2
0
class Nmea(object):
    def __init__(self, server):
        self.server = server
        self.values = {'gps': {}, 'wind': {}}

        def make_source(name, dirname):
            timestamp = server.TimeStamp(name)
            self.values[name][dirname] = server.Register(
                SensorValue(name + '.' + dirname, timestamp, directional=True))
            self.values[name]['speed'] = server.Register(
                SensorValue(name + '.speed', timestamp))
            self.values[name]['source'] = server.Register(
                StringValue(name + '.source', 'none'))
            self.values[name]['lastupdate'] = 0

        make_source('gps', 'track')
        make_source('wind', 'direction')

        self.devices = []
        self.devices_lastmsg = {}
        self.probedevice = None
        self.primarydevices = {'gps': None, 'wind': None}
        self.gpsdpoller = GpsdPoller(self)

        self.process = NmeaBridgeProcess()
        self.process.start()
        self.poller = select.poll()
        self.process_fd = self.process.pipe.fileno()
        self.poller.register(self.process_fd, select.POLLIN)
        self.gps_fd = self.gpsdpoller.process.pipe.fileno()
        self.poller.register(self.gps_fd, select.POLLIN)
        self.device_fd = {}

        self.nmea_times = {}
        self.last_imu_time = time.time()
        self.last_rudder_time = time.time()
        self.starttime = time.time()

    def __del__(self):
        print 'terminate nmea process'
        self.process.terminate()

    def read_process_pipe(self):
        msgs = self.process.pipe.recv()
        if msgs == 'sockets':
            self.process.sockets = True
        elif msgs == 'nosockets':
            self.process.sockets = False
        else:
            self.handle_messages(msgs, 'tcp')

    def read_serial_device(self, device, serial_msgs):
        t = time.time()
        line = device.readline()
        if not line:
            return
        if self.process.sockets:
            nmea_name = line[:6]
            # do not output nmea data over tcp faster than 5hz
            # for each message time
            if not nmea_name in self.nmea_times or t - self.nmea_times[
                    nmea_name] > .2:
                self.process.pipe.send(line, False)
                self.nmea_times[nmea_name] = t

        self.devices_lastmsg[device] = t
        parsers = []
        if not self.primarydevices['wind'] or self.primarydevices[
                'wind'] == device:
            parsers.append(parse_nmea_wind)
        if self.values['gps']['source'] != 'gpsd' and \
           (not self.primarydevices['gps'] or self.primarydevices['gps'] == device):
            parsers.append(parse_nmea_gps)

        for parser in parsers:
            result = parser(line)
            if result:
                name, msg = result
                if not self.primarydevices[name]:
                    print 'found primary serial device for', name
                    self.primarydevices[name] = device
                serial_msgs[name] = msg
                break

    def remove_serial_device(self, device):
        index = self.devices.index(device)
        print 'lost serial nmea%d' % index
        self.devices[index] = False
        self.poller.unregister(device.device.fileno())
        del self.devices_lastmsg[device]
        for name in self.primarydevices:
            if device == self.primarydevices[name]:
                self.primarydevices[name] = None
        device.close()

    def poll(self):
        t0 = time.time()
        self.probe_serial()

        t1 = time.time()
        # handle tcp nmea messages
        serial_msgs = {}
        while True:
            events = self.poller.poll(0)
            if not events:
                break
            while events:
                event = events.pop()
                fd, flag = event
                if fd == self.process_fd:
                    if flag != select.POLLIN:
                        print 'nmea got flag for process pipe:', flag
                    else:
                        self.read_process_pipe()
                elif fd == self.gps_fd:
                    if flag != select.POLLIN:
                        print 'nmea got flag for gpsdpoller pipe:', flag
                    else:
                        self.gpsdpoller.read()
                elif flag == select.POLLIN:
                    #if flag & (select.POLLHUP | select.POLLERR | select.POLLNVAL):
                    self.read_serial_device(self.device_fd[fd], serial_msgs)
                else:
                    self.remove_serial_device(self.device_fd[fd])

        t2 = time.time()
        self.handle_messages(serial_msgs, 'serial')
        t3 = time.time()

        for device in self.devices:
            # timeout serial devices
            if not device:
                continue
            dt = time.time() - self.devices_lastmsg[device]
            if dt > 1:
                print 'serial device dt', dt, device
            if dt > 15:
                print 'serial device timed out', dt, device
                self.remove_serial_device(device)
        t4 = time.time()

        # timeout sources
        for name in self.values:
            value = self.values[name]
            if value['source'].value == 'none':
                continue
            if t4 - value['lastupdate'] > 8:
                print 'nmea timeout for', name, 'source', value[
                    'source'].value, time.time(), t4 - value['lastupdate']
                value['source'].set('none')

        # send nmea messages to sockets
        dt = time.time() - self.last_imu_time
        if self.process.sockets and (dt > .5 or dt < 0) and \
           'imu.pitch' in self.server.values:
            self.send_nmea('APXDR,A,%.3f,D,PTCH' %
                           self.server.values['imu.pitch'].value)
            self.send_nmea('APXDR,A,%.3f,D,ROLL' %
                           self.server.values['imu.roll'].value)
            self.send_nmea('APHDM,%.3f,M' %
                           self.server.values['imu.heading_lowpass'].value)
            self.last_imu_time = time.time()

        dt = time.time() - self.last_rudder_time
        if self.process.sockets and (dt > .2 or dt < 0) and \
           'servo.rudder' in self.server.values:
            value = self.server.values['servo.rudder'].value
            if value:
                self.send_nmea('APRSA,%.3f,A,,' % value)
            self.last_rudder_time = time.time()

        t5 = time.time()
        if t5 - t0 > .1:
            print 'nmea poll times', t1 - t0, t2 - t1, t3 - t2, t4 - t3, t5 - t4

    def probe_serial(self):
        # probe new nmea data devices
        if not self.probedevice:
            try:
                self.probeindex = self.devices.index(False)
            except:
                self.probeindex = len(self.devices)
            self.probedevicepath = serialprobe.probe(
                'nmea%d' % self.probeindex, [38400, 4800])
            if self.probedevicepath:
                try:
                    self.probedevice = NMEASerialDevice(self.probedevicepath)
                    self.probetime = time.time()
                except serial.serialutil.SerialException:
                    print 'failed to open', self.probedevicepath, 'for nmea data'
                    pass
        elif time.time() - self.probetime > 5:
            print 'nmea serial probe timeout', self.probedevicepath
            self.probedevice = None  # timeout
        else:
            # see if the probe device gets a valid nmea message
            if self.probedevice:
                if self.probedevice.readline():
                    print 'new nmea device', self.probedevicepath
                    serialprobe.success('nmea%d' % self.probeindex,
                                        self.probedevicepath)
                    if self.probeindex < len(self.devices):
                        self.devices[self.probeindex] = self.probedevice
                    else:
                        self.devices.append(self.probedevice)
                    fd = self.probedevice.device.fileno()
                    self.device_fd[fd] = self.probedevice
                    self.poller.register(fd, select.POLLIN)
                    self.devices_lastmsg[self.probedevice] = time.time()
                    self.probedevice = None

    def send_nmea(self, msg):
        line = '$' + msg + ('*%02X' % nmea_cksum(msg))
        self.process.pipe.send(line, False)

    def handle_messages(self, msgs, source):
        for name in msgs:
            if not name in self.values:
                print 'unknown data parsed!', name
                break
            value = self.values[name]

            if source_priority[
                    value['source'].value] < source_priority[source]:
                continue

            msg = msgs[name]
            timestamp = msg['timestamp'] if 'timestamp' in msg else time.time(
            ) - self.starttime
            self.server.TimeStamp(name, timestamp)

            for vname in msg:
                if vname != 'timestamp':
                    value[vname].set(msg[vname])
            if value['source'].value != source:
                print 'nmea source for', name, 'source', source, time.time()
            value['source'].update(source)
            value['lastupdate'] = time.time()