+++ /dev/null
-#!/usr/bin/env python
-
-from PyQt4.QtGui import *
-from PyQt4.QtCore import SIGNAL, SLOT, Qt, QTimer, QThread
-
-from time import sleep
-from threading import Thread
-from datetime import datetime
-
-import bluetooth
-import os
-import socket
-import sys
-import dbus
-
-from nmea import GPSData
-
-devices = [
- [ "00:0D:B5:38:9E:16", "BT-335" ],
- [ "00:0D:B5:38:AF:C7", "BT-821" ],
-]
-
-reconnect_delay = 10
-logprefix = "/home/user/gps/"
-
-# lets you get/set powered state of your bluetooth adapter
-# code from http://tomch.com/wp/?p=132
-def enable_bluetooth(enabled = None):
- bus = dbus.SystemBus();
- root = bus.get_object('org.bluez', '/')
- manager = dbus.Interface(root, 'org.bluez.Manager')
- defaultAdapter = manager.DefaultAdapter()
- obj = bus.get_object('org.bluez', defaultAdapter)
- adapter = dbus.Interface(obj, 'org.bluez.Adapter')
- props = adapter.GetProperties()
-
- if enabled is None:
- return adapter.GetProperties()['Powered']
- elif enabled:
- adapter.SetProperty('Powered', True)
- else:
- adapter.SetProperty('Powered', False)
-
-
-class GPSThread(QThread):
- def __init__(self, addr, name, parent = None):
- QThread.__init__(self, parent)
-
- self.addr = addr
- self.name = name
- self.exiting = False
- self.logfile = None
-
- self.total_length = 0
- self.total_connects = 0
- self.total_lines = 0
-
- def __del__(self):
- self.exiting = True
- self.wait()
-
- def stop(self):
- self.exiting = True
-
- def init(self):
- logname = os.path.join(logprefix, "%s.%s.nmea" % (datetime.today().strftime("%Y.%m.%d"), self.name))
-
- enable_bluetooth(True)
- self.logfile = open(logname, 'a')
-
- def cleanup(self):
- if self.logfile is not None:
- self.logfile.close()
- self.logfile = None
-
- def main_loop(self):
- error = None
- buffer = ""
- last_length = 0
- socket = None
-
- gpsdata = GPSData()
-
- try:
- # connect
- while not self.exiting and socket is None:
- self.emit(SIGNAL("status_updated(QString)"), "Connecting...")
- socket = bluetooth.BluetoothSocket()
- socket.connect((self.addr, 1))
- socket.settimeout(10)
- self.total_connects += 1
-
- self.emit(SIGNAL("status_updated(QString)"), "Connected")
-
- # read
- while not self.exiting and socket is not None:
- chunk = socket.recv(1024)
-
- if len(chunk) == 0:
- raise Exception("Zero read")
-
- buffer += chunk
- self.total_length += len(chunk)
- self.logfile.write(chunk)
-
- # parse lines
- lines = buffer.split('\n')
- buffer = lines.pop()
-
- for line in lines:
- gpsdata.parse_nmea_string(line)
-
- self.total_lines += len(lines)
-
- # update display info every 10k
- if self.total_length - last_length > 512:
- self.emit(SIGNAL("status_updated(QString)"), "Logged %d lines, %d bytes, %d connects" % (self.total_lines, self.total_length, self.total_connects))
- last_length = self.total_length
-
- self.emit(SIGNAL("data_updated(QString)"), gpsdata.dump())
-
- except IOError, e:
- error = "%s: %s" % ("Cannot connect" if socket is None else "Read error", str(e))
- except:
- error = "%s: %s" % ("Cannot connect" if socket is None else "Read error", sys.exc_info())
-
- if self.exiting or error is None: return
-
- # process error: wait some time and retry
- global reconnect_delay
- count = reconnect_delay
- while not self.exiting and count > 0:
- self.emit(SIGNAL("status_updated(QString)"), "%s, retry in %d" % (error, count))
- sleep(1)
- count -= 1
-
- socket = None
-
- def run(self):
- try:
- self.init()
-
- while not self.exiting:
- self.main_loop()
- except Exception, e:
- self.emit(SIGNAL("status_updated(QString)"), "FATAL: %s" % str(e))
-
- try:
- self.cleanup()
- except:
- self.emit(SIGNAL("status_updated(QString)"), "FATAL: cleanup failed")
-
- self.emit(SIGNAL("status_updated(QString)"), "stopped")
-
-class ContainerWidget(QWidget):
- def __init__(self, addr, name, parent=None):
- QWidget.__init__(self, parent)
-
- # data
- self.addr = addr
- self.name = name
- self.thread = None
- self.status = "stopped"
-
- # UI: header
- self.startbutton = QPushButton("Start")
- self.startbutton.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
- self.connect(self.startbutton, SIGNAL('clicked()'), self.start_thread)
-
- self.stopbutton = QPushButton("Stop")
- self.stopbutton.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
- self.stopbutton.setEnabled(False)
- self.connect(self.stopbutton, SIGNAL('clicked()'), self.stop_thread)
-
- self.statuswidget = QLabel()
- self.statuswidget.setWordWrap(True)
-
- self.monitorwidget = QLabel()
-
- header = QHBoxLayout()
- header.addWidget(self.startbutton)
- header.addWidget(self.stopbutton)
- header.addWidget(self.statuswidget)
-
- self.layout = QVBoxLayout()
- self.layout.addLayout(header)
- self.layout.addWidget(self.monitorwidget)
-
- self.setLayout(self.layout)
-
- # done
- self.update_status()
-
- def __del__(self):
- self.thread = None
-
- def start_thread(self):
- if self.thread is not None:
- return
-
- self.startbutton.setEnabled(False)
- self.stopbutton.setEnabled(True)
-
- self.thread = GPSThread(self.addr, self.name, self)
- self.connect(self.thread, SIGNAL("status_updated(QString)"), self.update_status)
- self.connect(self.thread, SIGNAL("data_updated(QString)"), self.update_monitor)
- self.connect(self.thread, SIGNAL("finished()"), self.gc_thread)
- self.thread.start()
-
- def stop_thread(self):
- if self.thread is None:
- return
-
- self.stopbutton.setEnabled(False)
- self.thread.stop()
-
- def gc_thread(self):
- self.thread = None # join
-
- self.startbutton.setEnabled(True)
- self.stopbutton.setEnabled(False)
- self.update_status()
-
- def update_status(self, status = None):
- if status is not None:
- self.status = status
- self.statuswidget.setText("%s: %s" % (self.name, self.status))
-
- def update_monitor(self, data = None):
- self.monitorwidget.setText(data)
-
-class MainWindow(QWidget):
- def __init__(self, parent=None):
- QWidget.__init__(self, parent)
- self.setWindowTitle("UberLogger")
-
- layout = QVBoxLayout()
-
- global devices
- for addr, name in devices:
- layout.addWidget(ContainerWidget(addr, name))
-
- self.setLayout(layout)
-
-def main():
- app = QApplication(sys.argv)
-
- window = MainWindow()
- window.show()
- sys.exit(app.exec_())
-
-if __name__ == "__main__":
- main()