def ProcessMessage(self, msg): self.messageCount += 1 id = msg.hdr.GetMessageID() # if we write CSV to multiple files, we'd probably look up a hash table for this message id, # and open it and write a header if (id in self.outputFiles): outputFile = self.outputFiles[id] else: # create a new file outputFile = open( self.outputName + "/" + msg.MsgName().replace("/", "_") + ".csv", 'w') # store a pointer to it, so we can find it next time (instead of creating it again) self.outputFiles[id] = outputFile # add table header, one column for each message field tableHeader = msgcsv.csvHeader( msg, nameColumn=False, timeColumn=True) + '\n' outputFile.write(tableHeader) try: # \todo Detect time rolling. this only matters when we're processing a log file # with insufficient timestamp size, such that time rolls over from a large number # to a small one, during the log. thisTimestamp = msg.hdr.GetTime() if thisTimestamp < self._lastTimestamp: self._timestampOffset += 1 self._lastTimestamp = thisTimestamp timeSizeInBits = int( round( math.log( int( Messaging.findFieldInfo(msg.hdr.fields, "Time").maxVal), 2))) timestamp = ( self._timestampOffset << timeSizeInBits) + thisTimestamp if Messaging.findFieldInfo(msg.hdr.fields, "Time").units == "ms": timestamp = timestamp / 1000.0 text = str(timestamp) + ", " except AttributeError: text = "unknown, " text += msgcsv.toCsv(msg, nameColumn=False, timeColumn=False) text += '\n' outputFile.write(text) # This is not efficient, but if we don't flush during socket processing # and the user hits Ctrl-C, we'll drop a bunch of data and end up with empty files. # So flush each message as it comes in. if self.connectionType != 'file': outputFile.flush()
def HandleButtonPress(self): # when a button is used to start a log, the text of that button changes to "Stop". # starting any other log will stop the current one (changing it's text back to normal) button = self.sender() if "logtag" in button.options: if button == self.activeLogButton: self.CloseLogFile() button.setText(button.label) self.activeLogButton = None else: if self.activeLogButton != None: self.activeLogButton.setText(self.activeLogButton.label) self.CreateLogFile(button.options["logtag"][0]) button.setText("Stop") self.activeLogButton = button if "send" in button.options: for opts in button.options['send']: msgname = opts.split("[")[0] fields = opts.split("[")[1].replace("]","").split(",") msgClass = Messaging.MsgClassFromName[msgname] msg = msgClass() for field in fields: parts = field.split("=") name = parts[0] value = parts[1] Messaging.set(msg, Messaging.findFieldInfo(msgClass.fields, name), value) self.SendMsg(msg)
def HandleButtonPress(self): # when a button is used to start a log, the text of that button changes to "Stop". # starting any other log will stop the current one (changing it's text back to normal) button = self.sender() if "logtag" in button.options: if button == self.activeLogButton: self.CloseLogFile() button.setText(button.label) self.activeLogButton = None else: if self.activeLogButton != None: self.activeLogButton.setText(self.activeLogButton.label) self.CreateLogFile(button.options["logtag"][0]) button.setText("Stop") self.activeLogButton = button if "send" in button.options: for opts in button.options['send']: msgname = opts.split("[")[0] fields = opts.split("[")[1].replace("]", "").split(",") msgClass = Messaging.MsgClassFromName[msgname] msg = msgClass() for field in fields: parts = field.split("=") name = parts[0] value = parts[1] Messaging.set( msg, Messaging.findFieldInfo(msgClass.fields, name), value) self.SendMsg(msg)
def handle_query(self, msg): msgquery = msg.GetQuery() msgAndFieldName = msgquery.split(",")[0] msgname = msgAndFieldName.split(".")[0] fieldname = msgAndFieldName.split(".")[1] tagQuery = msgquery.split(",")[1] if tagQuery != "": tagQuery += " AND " start = msg.GetStartTime() end = msg.GetEndTime() averagingPeriod = msg.GetAveragingPeriod() if averagingPeriod != 0: dbquery = 'SELECT "' + fieldname + '" FROM "' + msgname + '"' else: dbquery = 'SELECT MEAN("' + fieldname + '") FROM "' + msgname + '"' dbquery += " WHERE " + tagQuery + "time > " + FormattedTime(start) if end != 0: dbquery += " AND time < " + FormattedTime(end) else: end = datetime.datetime.now() if averagingPeriod != 0: # limit averaging period such that we don't get too many data points if avg / (end - start) > MAX_POINTS: avg = MAX_POINTS * (end - start) dbquery += " GROUP BY *,time("+FormattedTime(avg)+")" dbquery += " LIMIT " + str(MAX_POINTS) # send query to database, get result result = self.db.query(dbquery) # output results resultMsg = Messaging.Messages.Network.History.Result() resultMsg.SetCookie(self.cookie) resultCount = f(result) resultMsg.SetResultCount(resultCount) resultMsg.SetQuery(msgquery) self.msgClient.send_message(resultMsg) dataInfo = Messaging.findFieldInfo(Messaging.Messages.Network.History.Data, "Data") maxDataPerMsg = dataInfo.count resultNumber = 0 for something in result: dataMsg = Messaging.Messages.Network.History.Data() dataMsg.SetCookie(self.cookie) dataMsg.SetResultNumber(resultNumber) dataRange = min(maxDataPerMsg, tilEndOfResults) for index in range(0, dataRange,2): dataMsg.SetData(time(something), index) dataMsg.SetData(value(something), index+1) # truncate message buffer to actual amount of data dataMsg.hdr.SetDataLength(dataInfo.offset + dataInfo.size * dataRange) self.msgClient.send_message(dataMsg) resultNumber += 1 # increment cookie so the next query's results are easy to tell apart from out query results # especially useful if two clients query at almost the same time! self.cookie += 1
def handle_query(self, msg): msgquery = msg.GetQuery() msgAndFieldName = msgquery.split(",")[0] msgname = msgAndFieldName.split(".")[0] fieldname = msgAndFieldName.split(".")[1] tagQuery = msgquery.split(",")[1] if tagQuery != "": tagQuery += " AND " start = msg.GetStartTime() end = msg.GetEndTime() averagingPeriod = msg.GetAveragingPeriod() if averagingPeriod != 0: dbquery = 'SELECT "' + fieldname + '" FROM "' + msgname + '"' else: dbquery = 'SELECT MEAN("' + fieldname + '") FROM "' + msgname + '"' dbquery += " WHERE " + tagQuery + "time > " + FormattedTime(start) if end != 0: dbquery += " AND time < " + FormattedTime(end) else: end = datetime.datetime.now() if averagingPeriod != 0: # limit averaging period such that we don't get too many data points if avg / (end - start) > MAX_POINTS: avg = MAX_POINTS * (end - start) dbquery += " GROUP BY *,time("+FormattedTime(avg)+")" dbquery += " LIMIT " + str(MAX_POINTS) # send query to database, get result result = self.db.query(dbquery) # output results resultMsg = Messaging.Messages.Network.History.Result() resultMsg.SetCookie(self.cookie) resultCount = f(result) resultMsg.SetResultCount(resultCount) resultMsg.SetQuery(msgquery) self.msgClient.send_message(resultMsg) dataInfo = Messaging.findFieldInfo(Messaging.Messages.Network.History.Data, "Data") maxDataPerMsg = dataInfo.count resultNumber = 0 for something in result: dataMsg = Messaging.Messages.Network.History.Data() dataMsg.SetCookie(self.cookie) dataMsg.SetResultNumber(resultNumber) dataRange = min(maxDataPerMsg, tilEndOfResults) for index in range(0, dataRange,2): dataMsg.SetData(time(something), index) dataMsg.SetData(value(something), index+1) # truncate message buffer to actual amount of data dataMsg.hdr.SetDataLength(dataInfo.offset + dataInfo.size * dataRange) self.msgClient.send_message(dataMsg) resultNumber += 1 # increment cookie so the next query's results are easy to tell apart from out query results # especially useful if two clients query at almost the same time! self.cookie += 1
def ProcessMessage(self, msg): self.messageCount += 1 id = msg.hdr.GetMessageID() # if we write CSV to multiple files, we'd probably look up a hash table for this message id, # and open it and write a header if(id in self.outputFiles): outputFile = self.outputFiles[id] else: # create a new file outputFile = open(self.outputName + "/" + msg.MsgName().replace("/","_") + ".csv", 'w') # store a pointer to it, so we can find it next time (instead of creating it again) self.outputFiles[id] = outputFile # add table header, one column for each message field tableHeader = msgcsv.csvHeader(msg, nameColumn=False, timeColumn=True) + '\n' outputFile.write(tableHeader) try: # \todo Detect time rolling. this only matters when we're processing a log file # with insufficient timestamp size, such that time rolls over from a large number # to a small one, during the log. thisTimestamp = msg.hdr.GetTime() if thisTimestamp < self._lastTimestamp: self._timestampOffset+=1 self._lastTimestamp = thisTimestamp timeSizeInBits = int(round(math.log(int(Messaging.findFieldInfo(msg.hdr.fields, "Time").maxVal), 2))) timestamp = (self._timestampOffset << timeSizeInBits) + thisTimestamp if Messaging.findFieldInfo(msg.hdr.fields, "Time").units == "ms": timestamp = timestamp / 1000.0 text = str(timestamp) + ", " except AttributeError: text = "unknown, " text += msgcsv.toCsv(msg, nameColumn=False, timeColumn=False) text += '\n' outputFile.write(text) # This is not efficient, but if we don't flush during socket processing # and the user hits Ctrl-C, we'll drop a bunch of data and end up with empty files. # So flush each message as it comes in. if self.connectionType !='file': outputFile.flush()
def store_message(self, msg): try: timeVal = msg.hdr.GetTime() timeInfo = Messaging.findFieldInfo(msg.hdr.fields, "Time") # if it's not big enough to be an absolute timestamp, give up on using it and just use current time if float(timeInfo.maxVal) <= 2**32: raise AttributeError if timeInfo.units == "ms": timeVal = timeVal / 1000.0 timeVal = datetime.datetime.fromtimestamp(timeVal, datetime.timezone.utc) except AttributeError: timeVal = datetime.datetime.now() dbJson = { "time": str(timeVal), "measurement": msg.MsgName(), 'fields': {}, 'tags': {} } for fieldInfo in msg.hdr.fields: if len(fieldInfo.bitfieldInfo) == 0: if fieldInfo.idbits == 0 and fieldInfo.name != "Time" and fieldInfo.name != "DataLength": dbJson['tags'][fieldInfo.name] = Messaging.get( msg.hdr, fieldInfo) else: for bitInfo in fieldInfo.bitfieldInfo: if bitInfo.idbits == 0 and bitInfo.name != "Time" and bitInfo.name != "DataLength": dbJson['tags'][bitInfo.name] = Messaging.get( msg.hdr, bitInfo) msgClass = type(msg) for fieldInfo in msgClass.fields: if fieldInfo.count == 1: if len(fieldInfo.bitfieldInfo) == 0: dbJson['fields'][ fieldInfo.name] = InfluxDBConnection.GetDBValue( msg, fieldInfo) else: for bitInfo in fieldInfo.bitfieldInfo: dbJson['fields'][ bitInfo.name] = InfluxDBConnection.GetDBValue( msg, bitInfo) # leave out arrays until we figure out how to handle them #else: # arrayList = [] # for i in range(0,fieldInfo.count): # arrayList.append(InfluxDBConnection.GetDBValue(msg, fieldInfo, i)) # dbJson['fields'][fieldInfo.name] = arrayList #print("Create a retention policy") #retention_policy = 'awesome_policy' #client.create_retention_policy(retention_policy, '3d', 3, default=True) self.db.write_points([dbJson]) #, retention_policy=retention_policy)
def __init__(self, hdr, portName): super(SerialConnection, self).__init__(None) self.hdr = hdr self.settings = QtCore.QSettings("MsgTools", "MessageServer/SerialPlugin") # button to open/close serial port self.openCloseButton = QtWidgets.QPushButton("button") self.openCloseButton.pressed.connect(self.openCloseSwitch) # button select new serial port self.selectPortButton = QtWidgets.QPushButton("Select Port") self.selectPortButton.pressed.connect(self.selectPort) self.statusLabel = QtWidgets.QLabel() self.subscriptions = {} self.subMask = 0 self.subValue = 0 self.isHardwareLink = True # if port not specified, default to last used port if not portName: portName = self.settings.value("portName", None) self.serialPort = QSerialPort(portName) self.serialPort.setBaudRate(QSerialPort.Baud115200) self.serialPort.setFlowControl(QSerialPort.NoFlowControl) self.serialPort.setParity(QSerialPort.NoParity) self.serialPort.setDataBits(QSerialPort.Data8) self.serialPort.setStopBits(QSerialPort.OneStop) self.rxBuffer = bytearray() self.gotHeader = 0 self.rxMsgCount = 0 self.serialPort.readyRead.connect(self.onReadyRead) self.name = "Serial " + self.serialPort.portName() self.hdrTranslator = HeaderTranslator(hdr, Messaging.hdr) self.serialStartSeqField = Messaging.findFieldInfo( hdr.fields, "StartSequence") if self.serialStartSeqField != None: self.startSequence = int(hdr.GetStartSequence.default) self.startSeqSize = int(hdr.GetStartSequence.size) try: self.hdrCrcRegion = int(hdr.GetHeaderChecksum.offset) except AttributeError: self.hdrCrcRegion = None self.tmpRxHdr = ctypes.create_string_buffer(0)
def addLine(self, msgClass, fieldName): fieldName, fieldIndex = MsgPlot.split_fieldname(fieldName) fieldInfo = Messaging.findFieldInfo(msgClass.fields, fieldName) if fieldInfo == None: raise MsgPlot.PlotError("Invalid field %s for message %s" % (fieldName, msgClass.MsgName())) if fieldInfo.units == "ASCII": raise MsgPlot.PlotError("Cannot plot %s.%s, it is a string" % (msgClass.MsgName(), fieldName)) # don't add if it's already there! for line in self.lines: if fieldInfo == line.fieldInfo and fieldIndex == line.fieldSubindex: name = fieldInfo.name if fieldInfo.count > 1: name = "%s[%d]" % (name, fieldIndex) raise MsgPlot.PlotError("Line %s already on plot" % name) if msgClass != self.msgClass: raise MsgPlot.NewPlotError( "Message %s != %s, cannot add to same plot" % (msgClass.__name__, self.msgClass.__name__)) if fieldInfo.units != self.units: raise MsgPlot.NewPlotError("Units %s != %s, not adding to plot" % (fieldInfo.units, self.units)) if fieldIndex != None: self._addLine(msgClass, fieldInfo, fieldIndex) elif fieldInfo.count == 1: self._addLine(msgClass, fieldInfo, 0) else: dups = [] for fieldIndex in range(0, fieldInfo.count): duplicate = False for line in self.lines: if fieldInfo == line.fieldInfo and fieldIndex == line.fieldSubindex: dups.append(fieldIndex) duplicate = True break if not duplicate: self._addLine(msgClass, fieldInfo, fieldIndex) if len(dups) > 0: if len(dups) == 1: s = ' ' + str(dups[0]) elif len(dups) == fieldInfo.count: s = 's %d-%d' % (0, fieldInfo.count) else: s = 's ' for d in dups: s += '%s,' % d raise MsgPlot.PlotError("Line%s already on plot" % s)
def store_message(self, msg): try: timeVal = msg.hdr.GetTime() timeInfo = Messaging.findFieldInfo(msg.hdr.fields, "Time") # if it's not big enough to be an absolute timestamp, give up on using it and just use current time if float(timeInfo.maxVal) <= 2**32: raise AttributeError if timeInfo.units == "ms": timeVal = timeVal / 1000.0 timeVal = datetime.datetime.fromtimestamp(timeVal, datetime.timezone.utc) except AttributeError: timeVal = datetime.datetime.now() dbJson = { "time": str(timeVal), "measurement": msg.MsgName(), 'fields': {}, 'tags': {} } for fieldInfo in msg.hdr.fields: if len(fieldInfo.bitfieldInfo) == 0: if fieldInfo.idbits == 0 and fieldInfo.name != "Time" and fieldInfo.name != "DataLength": dbJson['tags'][fieldInfo.name] = Messaging.get(msg.hdr, fieldInfo) else: for bitInfo in fieldInfo.bitfieldInfo: if bitInfo.idbits == 0 and bitInfo.name != "Time" and bitInfo.name != "DataLength": dbJson['tags'][bitInfo.name] = Messaging.get(msg.hdr, bitInfo) msgClass = type(msg) for fieldInfo in msgClass.fields: if fieldInfo.count == 1: if len(fieldInfo.bitfieldInfo) == 0: dbJson['fields'][fieldInfo.name] = InfluxDBConnection.GetDBValue(msg, fieldInfo) else: for bitInfo in fieldInfo.bitfieldInfo: dbJson['fields'][bitInfo.name] = InfluxDBConnection.GetDBValue(msg, bitInfo) # leave out arrays until we figure out how to handle them #else: # arrayList = [] # for i in range(0,fieldInfo.count): # arrayList.append(InfluxDBConnection.GetDBValue(msg, fieldInfo, i)) # dbJson['fields'][fieldInfo.name] = arrayList #print("Create a retention policy") #retention_policy = 'awesome_policy' #client.create_retention_policy(retention_policy, '3d', 3, default=True) self.db.write_points([dbJson]) #, retention_policy=retention_policy)
def addData(self, msg): # TODO what to do for things that can't be numerically expressed? just ascii strings, i guess? for line in self.lines: try: newDataPoint = Messaging.getFloat(msg, line.fieldInfo, line.fieldSubindex) except ValueError: print("ERROR! Plot of %s.%s cannot accept value %s" % (self.msgClass.MsgName(), line.fieldInfo.name, Messaging.get(msg, line.fieldInfo, line.fieldSubindex))) continue try: timestamp = msg.hdr.GetTime() if Messaging.findFieldInfo(msg.hdr.fields, "Time").units == "ms": timestamp = timestamp / 1000.0 newTime = float(elapsedSeconds(timestamp)) if newTime != 0: self.useHeaderTime = 1 if not self.useHeaderTime: newTime = elapsedSeconds(datetime.now().timestamp()) except AttributeError: # if header has no time, fallback to PC time. newTime = elapsedSeconds(datetime.now().timestamp()) # add data in the array until MAX_LENGTH is reached, then drop data off start of array # such that plot appears to scroll. The array size is limited to MAX_LENGTH. if len(line.dataArray) >= MsgPlot.MAX_LENGTH: line.dataArray[:-1] = line.dataArray[ 1:] # shift data in the array one sample left line.dataArray[-1] = newDataPoint line.timeArray[:-1] = line.timeArray[ 1:] # shift data in the array one sample left line.timeArray[-1] = newTime else: line.dataArray.append(newDataPoint) line.timeArray.append(newTime) if not self.pause: timeArray = line.timeArray dataArray = line.dataArray count = self.timeSlider.value() if len(line.dataArray) > count: timeArray = timeArray[-count:] dataArray = dataArray[-count:] line.curve.setData(timeArray, dataArray) line.curve.setPos(line.ptr1, 0)
def addLine(self, msgClass, fieldName): fieldName, fieldIndex = MsgPlot.split_fieldname(fieldName) fieldInfo = Messaging.findFieldInfo(msgClass.fields, fieldName) if fieldInfo == None: raise MsgPlot.PlotError("Invalid field %s for message %s" % (fieldName, msgClass.MsgName())) if fieldInfo.units == "ASCII": raise MsgPlot.PlotError("Cannot plot %s.%s, it is a string" % (msgClass.MsgName(), fieldName)) # don't add if it's already there! for line in self.lines: if fieldInfo == line.fieldInfo and fieldIndex == line.fieldSubindex: name = fieldInfo.name if fieldInfo.count > 1: name = "%s[%d]" % (name, fieldIndex) raise MsgPlot.PlotError("Line %s already on plot" % name) if msgClass != self.msgClass: raise MsgPlot.NewPlotError("Message %s != %s, cannot add to same plot" % (msgClass.__name__, self.msgClass.__name__)) if fieldInfo.units != self.units: raise MsgPlot.NewPlotError("Units %s != %s, not adding to plot" % (fieldInfo.units, self.units)) if fieldIndex != None: self._addLine(msgClass, fieldInfo, fieldIndex) elif fieldInfo.count == 1: self._addLine(msgClass, fieldInfo, 0) else: dups = [] for fieldIndex in range(0, fieldInfo.count): duplicate = False for line in self.lines: if fieldInfo == line.fieldInfo and fieldIndex == line.fieldSubindex: dups.append(fieldIndex) duplicate = True break if not duplicate: self._addLine(msgClass, fieldInfo, fieldIndex) if len(dups) > 0: if len(dups) == 1: s = ' '+str(dups[0]) elif len(dups) == fieldInfo.count: s = 's %d-%d' % (0, fieldInfo.count) else: s = 's ' for d in dups: s += '%s,' % d raise MsgPlot.PlotError("Line%s already on plot" % s)
def __init__(self, argv, parent=None): msgtools.lib.gui.Gui.__init__(self, "Message Plot 0.1", argv, [], parent) vbox = QVBoxLayout() centralWidget = QWidget() centralWidget.setLayout(vbox) self.setCentralWidget(centralWidget) self.msgPlots = {} self.RxMsg.connect(self.ProcessMessage) if len(sys.argv) < 1: sys.stderr.write( 'Usage: ' + sys.argv[0] + ' msg1=field1[,field2] [msg2=field1,field2,field3]\n') sys.exit(1) for arg in argv[1:]: argComponentList = arg.split("=") msgName = argComponentList[0] fieldNameList = argComponentList[1] self.msgClass = Messaging.MsgClassFromName[msgName] fieldNames = fieldNameList.split(",") firstField = 1 for fieldName in fieldNames: fieldInfo = Messaging.findFieldInfo(self.msgClass.fields, fieldName) if fieldInfo != None: if firstField: plot = MsgPlot(self.msgClass, fieldInfo, 0) vbox.addWidget(plot.plotWidget) firstField = 0 plotListForID = [] if self.msgClass.ID in self.msgPlots: plotListForID = self.msgPlots[self.msgClass.ID] else: self.msgPlots[self.msgClass.ID] = plotListForID plotListForID.append(plot) else: plot.addPlot(self.msgClass, fieldInfo, 0)
def __init__(self, msgClass, fieldName): super(QWidget, self).__init__() newFieldName, fieldIndex = MsgPlot.split_fieldname(fieldName) fieldInfo = Messaging.findFieldInfo(msgClass.fields, newFieldName) if fieldInfo == None: raise MsgPlot.PlotError("Invalid field %s for message %s" % (newFieldName, msgClass.MsgName())) layout = QVBoxLayout() self.setLayout(layout) self.msgClass = msgClass self.pause = 0 self.lineCount = 0 self.units = fieldInfo.units self.lines = [] yAxisLabel = fieldInfo.units xAxisLabel = "time (s)" self.plotWidget = pg.PlotWidget(labels={ 'left': yAxisLabel, 'bottom': xAxisLabel }) layout.addWidget(self.plotWidget) self.plotWidget.addLegend() self.addLine(msgClass, fieldName) # set up click handler to pause graph self.plotWidget.scene().sigMouseClicked.connect(self.mouseClicked) # add slider bar to control time scale self.timeSlider = QSlider(Qt.Horizontal) self.timeSlider.setMinimum(50) self.timeSlider.setMaximum(MsgPlot.MAX_LENGTH) self.timeSlider.setSingleStep(10) self.timeSlider.setPageStep(50) layout.addWidget(self.timeSlider) self.plotWidget.dragEnterEvent = self.dragEnterEvent self.plotWidget.dragMoveEvent = self.dragMoveEvent self.plotWidget.dropEvent = self.dropEvent self.plotWidget.setAcceptDrops(1)
def __init__(self, hdr, portName): super(SerialConnection, self).__init__("Serial", portName) self.hdr = hdr self.rxBuffer = bytearray() self.gotHeader = 0 self.hdrTranslator = HeaderTranslator(hdr, Messaging.hdr) self.serialStartSeqField = Messaging.findFieldInfo( hdr.fields, "StartSequence") if self.serialStartSeqField != None: self.startSequence = int(hdr.GetStartSequence.default) self.startSeqSize = int(hdr.GetStartSequence.size) try: self.hdrCrcRegion = int(hdr.GetHeaderChecksum.offset) except AttributeError: self.hdrCrcRegion = None self.tmpRxHdr = ctypes.create_string_buffer(0)
def addData(self, msg): # TODO what to do for things that can't be numerically expressed? just ascii strings, i guess? for line in self.lines: try: newDataPoint = Messaging.getFloat(msg, line.fieldInfo, line.fieldSubindex) except ValueError: print("ERROR! Plot of %s.%s cannot accept value %s" % ( self.msgClass.MsgName(), line.fieldInfo.name, Messaging.get(msg, line.fieldInfo, line.fieldSubindex))) continue try: timestamp = msg.hdr.GetTime() if Messaging.findFieldInfo(msg.hdr.fields, "Time").units == "ms": timestamp = timestamp / 1000.0 newTime = float(elapsedSeconds(timestamp)) if newTime != 0: self.useHeaderTime = 1 if not self.useHeaderTime: newTime = elapsedSeconds(datetime.now().timestamp()) except AttributeError: # if header has no time, fallback to PC time. newTime = elapsedSeconds(datetime.now().timestamp()) # add data in the array until MAX_LENGTH is reached, then drop data off start of array # such that plot appears to scroll. The array size is limited to MAX_LENGTH. if len(line.dataArray) >= MsgPlot.MAX_LENGTH: line.dataArray[:-1] = line.dataArray[1:] # shift data in the array one sample left line.dataArray[-1] = newDataPoint line.timeArray[:-1] = line.timeArray[1:] # shift data in the array one sample left line.timeArray[-1] = newTime else: line.dataArray.append(newDataPoint) line.timeArray.append(newTime) if not self.pause: self.refreshLine(line)
def __init__(self, msgClass, fieldName, runButton = None, clearButton = None, timeSlider = None, displayControls=True): super(QWidget,self).__init__() newFieldName, fieldIndex = MsgPlot.split_fieldname(fieldName) fieldInfo = Messaging.findFieldInfo(msgClass.fields, newFieldName) if fieldInfo == None: raise MsgPlot.PlotError("Invalid field %s for message %s" % (newFieldName, msgClass.MsgName())) layout = QVBoxLayout() self.setLayout(layout) self.msgClass = msgClass self.pause = 0 self.lineCount = 0 self.units = fieldInfo.units self.lines = [] yAxisLabel = fieldInfo.units xAxisLabel = "time (s)" self.plotWidget = pg.PlotWidget(labels={'left':yAxisLabel,'bottom':xAxisLabel}) layout.addWidget(self.plotWidget) self.plotWidget.addLegend() self.addLine(msgClass, fieldName) # set up click handler to pause graph self.plotWidget.scene().sigMouseClicked.connect(self.mouseClicked) hLayout = QHBoxLayout() layout.addLayout(hLayout) # add a Pause/Run button if runButton == None: self.runButton = QPushButton("Pause") else: self.runButton = runButton self.runButton.clicked.connect(self.pauseOrRun) if displayControls: hLayout.addWidget(self.runButton) # add a 'Clear' button if clearButton == None: self.clearButton = QPushButton("Clear") else: self.clearButton = clearButton self.clearButton.clicked.connect(self.clearData) if displayControls: hLayout.addWidget(self.clearButton) # add slider bar to control time scale if timeSlider == None: self.timeSlider = QSlider(Qt.Horizontal) self.timeSlider.setMinimum(50) self.timeSlider.setMaximum(MsgPlot.MAX_LENGTH) self.timeSlider.setSingleStep(10) self.timeSlider.setPageStep(50) else: self.timeSlider = timeSlider self.timeSlider.valueChanged.connect(self.timeScaleChanged) if displayControls: hLayout.addWidget(QLabel("Time Scale")) hLayout.addWidget(self.timeSlider) self.plotWidget.dragEnterEvent = self.dragEnterEvent self.plotWidget.dragMoveEvent = self.dragMoveEvent self.plotWidget.dropEvent = self.dropEvent self.plotWidget.setAcceptDrops(1)
def __init__(self, parent=None): parser = argparse.ArgumentParser(description=DESCRIPTION) parser.add_argument('msgs', nargs='*', help=''' One or more messages that you wish to send. This entire list is sent each time the message period is up. Network messages are ignored. By default we send all known messages.''') parser = msgtools.lib.gui.Gui.addBaseArguments(parser) args = parser.parse_args() msgtools.lib.gui.Gui.__init__(self, "Noise Maker 0.1", args, parent) self.timeInfo = Messaging.findFieldInfo(Messaging.hdr.fields, "Time") # event-based way of getting messages self.RxMsg.connect(self.ProcessMessage) self.currentTime = 0 self.msgTimer = QtCore.QTimer(self) self.msgTimer.setInterval(50) self.msgTimer.timeout.connect(self.msgTimeout) vbox = QtWidgets.QVBoxLayout() w = QtWidgets.QWidget(self) w.setLayout(vbox) self.setCentralWidget(w) self.timeSlider = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.timeSlider.setMinimum(1) self.timeSlider.setMaximum(5) vbox.addWidget(self.timeSlider) t = int(self.settings.value('time_slider', 10)) self.timeSlider.setValue(t) self.timeSlider.valueChanged.emit(t) self.startStop = QtWidgets.QPushButton(self) self.startStop.setText('Stop') self.startStop.clicked.connect(self.startStopFn) vbox.addWidget(self.startStop) # check if user specified which messages we should output msgs = args.msgs # find a few messages to send at specified rates period = 0.1 self.fieldNumber = 0 self.msgPeriod = {} self.msgTxTime = {} for msgName in Messaging.MsgClassFromName: if not msgName.startswith("Network"): if len(msgs) > 0 and msgName not in msgs: continue print("found message " + msgName) self.msgPeriod[msgName] = period period = period + 0.050 if period > 0.5: period = 0.1 self.msgTxTime[msgName] = 0 self.msgTimer.start()