diff --git a/ArduinoSerialPlotterProtocol.md b/ArduinoSerialPlotterProtocol.md new file mode 100644 index 00000000000..162c66d2f66 --- /dev/null +++ b/ArduinoSerialPlotterProtocol.md @@ -0,0 +1,170 @@ +# SerialPlotter protocol + +One message can consist of multiply parts. +One part can consist of one label, one label and a value or only a value. + +| | | +| --- | --- | +| End of message symbol | \n | +| Part separator symbols | ' '(space), '\t'(tab), ','(comma) | +| Label-value separator symbol | : | + +# Valid messages are + +## Labels and value messages: +| | | | | | | +|-------------------|----|-------------------|-----|-------------------|----| +| Label : Value | | | | | \n | +| Label 1 : Value 1 | \t | Label 2 : Value 2 | | | \n | +| Label 1 : Value 1 | \t | Label 2 : Value 2 | ... | Label n : Value n | \n | + +## Label only messages +| | | | | | | +|-----------|----|-----------|-----|----------|----| +| Label: | | | | | \n | +| Label 1 : | \t | Label 2 : | | | \n | +| Label 1 : | \t | Label 2 | ... | Label n: | \n | + +There is a special case, the CSV header style. + +| | | | | | | +|-------|----|---------|-----|---------|----| +|Label 1| \t | Label 2 | ... | Label n | \n | + +But in this format, labels consisting of only numbers are not recognised as labels. +It is safer to just use the normal label only message. + +## Value only messages Value +This is not recommended if you using a board with USB to UART converter. +Because when the label is sent, before you had the SerialPlotter opened, then the label/labels get/gets never set. + +| | | | | | | +|---------|----|---------|-----|---------|----| +| Value 1 | \t | Value 2 | | | \n | +| Value 1 | \t | Value 2 | ... | Value n | \n | + + +# Examples +## Single Trace without label + +This example plots on line on serial plotter without setting a label + +```ino +void setup() { + Serial.begin(9600); +} + +void loop() { + int sensorValue1 = analogRead(A0); + + Serial.println(sensorValue1); + + delay(100); +} +``` + +The output looks like this +``` +10\n +11\n +12\n +13\n +14\n +``` +## Single Trace with label + +This example sends the label once in the setup routine. Afterwards only the value is send. + +```ino +void setup() { + Serial.begin(9600); + Serial.println("Label 1:"); +} + +void loop() { + int sensorValue1 = analogRead(A0); + + Serial.println(sensorValue1); + + delay(100); +} +``` + +The output looks like this +``` +Label 1:\n +10\n +11\n +12\n +13\n +14\n +``` + +## Single Trace with label send every time + +This example sends the label every time together with the value. + +```ino +void setup() { + Serial.begin(9600); +} + +void loop() { + int sensorValue1 = analogRead(A0); + + Serial.print("Label 1:"); Serial.println(sensorValue1); + + delay(100); +} +``` + +The output looks like this +``` +Label 1:10\n +Label 1:11\n +Label 1:12\n +Label 1:13\n +Label 1:14\n +``` +## Two Traces with label send every time + +This example sends two values together with the labels. + +```ino +void setup() { + Serial.begin(9600); +} + +float avg = 0; + +void loop() { + int sensorValue1 = analogRead(A0); + + // send lable and value seperated by ':' + Serial.print("Value:"); Serial.print(sensorValue1); + + + avg = (avg * 4 + analogRead(A0)) / 5.0; + // send part devider '\t' + Serial.print("\t"); + // send the second lable and value + Serial.print("AVG5:"); Serial.println(avg); + + + delay(100); +} +``` + +The output looks like this +``` +Value:377 AVG5:431.01 +Value:338 AVG5:408.81 +Value:392 AVG5:395.85 +Value:583 AVG5:427.28 +Value:221 AVG5:383.42 +Value:195 AVG5:343.74 +Value:202 AVG5:314.19 +Value:209 AVG5:292.15 + +``` + diff --git a/ArduinoSerialPlotterProtocol.pdf b/ArduinoSerialPlotterProtocol.pdf new file mode 100644 index 00000000000..e2e0b7024f9 Binary files /dev/null and b/ArduinoSerialPlotterProtocol.pdf differ diff --git a/app/src/processing/app/SerialPlotter.java b/app/src/processing/app/SerialPlotter.java index 363753749fe..336cbd43e7e 100644 --- a/app/src/processing/app/SerialPlotter.java +++ b/app/src/processing/app/SerialPlotter.java @@ -46,6 +46,7 @@ public class SerialPlotter extends AbstractMonitor { private static class Graph { public CircularBuffer buffer; private Color color; + public String label; public Graph(int id) { buffer = new CircularBuffer(BUFFER_CAPACITY); @@ -185,12 +186,24 @@ public void paintComponent(Graphics g1) { g.setTransform(AffineTransform.getTranslateInstance(xOffset, 0)); float xstep = (float) (bounds.width - xOffset - xPadding) / (float) BUFFER_CAPACITY; - int legendLength = graphs.size() * 10 + (graphs.size() - 1) * 3; + // draw legend + int legendXOffset = 0; for(int i = 0; i < graphs.size(); ++i) { graphs.get(i).paint(g, xstep, minY, maxY, rangeY, bounds.height); - if(graphs.size() > 1) { - g.fillRect(bounds.width - (xOffset + legendLength + 10) + i * 13, 10, 10, 10); + if(graphs.size() > 1) { + //draw legend rectangle + g.fillRect(10 + legendXOffset, 10, 10, 10); + legendXOffset += 13; + //draw label + g.setColor(boundsColor); + String s = graphs.get(i).label; + if(s != null && s.length() > 0) { + Rectangle2D fBounds = fm.getStringBounds(s, g); + int sWidth = (int)fBounds.getWidth(); + g.drawString(s, 10 + legendXOffset, 10 + (int)fBounds.getHeight() /2); + legendXOffset += sWidth + 3; + } } } } @@ -282,17 +295,60 @@ public void message(final String s) { } int validParts = 0; + int validLabels = 0; for(int i = 0; i < parts.length; ++i) { - try { - double value = Double.valueOf(parts[i]); + Double value = null; + String label = null; + + // column formated name value pair + if(parts[i].contains(":")) { + // get label + String[] subString = parts[i].split("[:]+"); + + if(subString.length > 0) { + int labelLength = subString[0].length(); + + if(labelLength > 32) { + labelLength = 32; + } + label = subString[0].substring(0, labelLength); + } else { + label = ""; + } + + if(subString.length > 1) { + parts[i] = subString[1]; + } else { + parts[i] = ""; + } + } + + try { + value = Double.valueOf(parts[i]); + } catch (NumberFormatException e) { + // ignored + } + //CSV header + if(label == null && value == null) { + label = parts[i]; + } + + if(value != null) { if(validParts >= graphs.size()) { graphs.add(new Graph(validParts)); } graphs.get(validParts).buffer.add(value); validParts++; - } catch (NumberFormatException e) { - // ignore } + if(label != null) { + if(validLabels >= graphs.size()) { + graphs.add(new Graph(validLabels)); + } + graphs.get(validLabels).label = label; + validLabels++; + } + if(validParts > validLabels) validLabels = validParts; + else if(validLabels > validParts) validParts = validLabels; } }