Datenprotokoll für Graphview

Hallo Leute,
ich hab da mal ein kleines Problem. Ich möchte Messdaten, welches über Bluetooth an mein Tablet gesendet werden mit Graphview darstellen.
Die Messdaten werden als einzelne Bytes übertragen, müssen aber auf der Clientseite in float gewandelt werden.
Wenn ich den buffer auslese, werden die Daten mir auch angezeigt. Ich möchte dieses Datenpaket nun in einzelne 4 Byte = 1 floatpaket aufteilen, damit ich dies in Graphview anzeigen kann.
Wie macht man dies in java?
Wär echt super wenn mir da einer helfen könnte.

1 Byte im Buffer → ist das ein Messwert?

4 Byte im Buffer → oder ist das ein Messwert?

und falls ja, wenn also 4 Bytes EIN Messwert sind: wie ist der vom erzeugenden Gerät kodiert?

Wäre kein Problem dir zu helfen, aber das müsste man schon wissen.

ein Messwert entspricht 4 Bytes. Im Messsystem werden die Daten als floats verarbeitet. Erst bevor sie über Bluetooth versendet werden, werden sie in 4 Bytes aufgeteilt.
Der C-Code dafür sieht folgend aus:

		{
			// Accel Navigation
			unsigned char buf[4];
			float accelx = data.a.x;

			for(i = 0; i < 4 ; i++){
				buf** = *((unsigned char*)&accelx + i);
				szBuffer[index++] = buf**;
			}

			float accely = data.a.y;
			for(i = 0; i < 4 ; i++){
				buf** = *((unsigned char*)&accely + i);
				szBuffer[index++] = buf**;
			}

			float accelz = data.a.z;
			for(i = 0; i < 4 ; i++){
				buf** = *((unsigned char*)&accelz + i);
				szBuffer[index++] = buf**;
			}
		}```

Dies muss ich jetzt wieder in java zusammenbringen.

*** Edit ***

Ich habs jetzt erstmal so versucht:
Wenn eine Bluetoothverbindung besteht, soll folgender code abgearbeitet werden

case Bluetooth.MESSAGE_READ:

			byte[] readbuffer = (byte[])msg.obj;
			
			float[] floats = new float[14];
			for(int init = 0; init < floats.length; init++){
				floats[init] = 0f;
			}
			byte[] data_bin = new byte[readbuffer.length - Len_Header];
			//copy data to array
			System.arraycopy(readbuffer, Len_Header, data_bin, 0, data_bin.length);
			
			try(ByteArrayInputStream stream = new ByteArrayInputStream(data_bin)){
				try(InputStreamReader reader = new InputStreamReader(stream)){
					
					
					floats[0] = reader.read();
					floats[1] = reader.read();
					floats[2] = reader.read();
					floats[3] = reader.read();
					floats[4] = reader.read();
					floats[5] = reader.read();
					floats[6] = reader.read();
					floats[7] = reader.read();
					floats[8] = reader.read();
					floats[9] = reader.read();
					floats[10] = reader.read();
					floats[11] = reader.read();
					floats[11] = reader.read();
					floats[12] = reader.read();
					
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

// float startBytes;
// //byte[] bytes = { }
// startBytes = ByteBuffer.wrap(readbuffer).order(ByteOrder.LITTLE_ENDIAN).getFloat();
// String test = Float.toString(startBytes);
// Log.d(“fjf”, test);
// tvData.setText(test);

			break;

Was ist msg.obj? Ist garantiert, dass die Payload ein Byte-Array ist? Wie schaut’s mit LSB/MSB aus? Ist das garantiert, dass das bei deiner C-Anwendung genauso läuft wie in deiner App?

ich benutze einen handleMessage und übernehme die Daten von einem anderen Thread. In C habe ich little endian benutzt und die Werte werden nun richtig angezeigt.
Was jetzt aber hinbekommen möchte ist, dass die einzelnen Messwerte einezelnen Variablen zugeordnet werden sollen.
Das Protokoll begint mit 2 Startbytes, 2 Längenbyte, 1 Initialisierungsbyte, 4 speed_x Bytes, 4 speed_y Bytes, . . . , 2 CRC16 Bytes.
Ich will nun nur die speed_x, … in Textviews anzeigen und nicht den Rahmen. Bisher laufen alle Werte einfach durch die Textviews durch.

Was ist denn jetzt die eigentliche Frage? Sorry, ich versteh’ dich noch nicht.

  • Du möchtest 4 Bytes in ein Double/Int umwandeln, hast aber Probleme?
  • Du möchtest wissen, wie du ein Linewrap in einer Textview erzwingen kannst?
  • Du möchtest?

Das mit der “Byte in Float Konvertierung” habe ich schon hinbekommen. Was mir noch fehlt ist die Zuweisung der übertragenen Werte zu den dafür zuständigen Variablen.
Wie ich im letzten Beitrag zu erklären versuchte, bekomme ich immer nacheinander 2 Startbytes, 2 Längenbytes, 1 Initilalisierungsbyte und ab dann die eigentlichen Messwerte welche ich darstellen möchte.
Dieses sind der Reihenfolge nach: 4 Byte für speed_x, 4 Byte für speed_y und 4_Byte für speed_z und das gleiche nochmal für Beschleunigung, Position, … . Dabei sind die 4 Bytes in floatwerte konvertiert. Das ist aber schon fertig.
Und genau diese Werte will ich je einer Variablen zuorden, sodass ich diese dann in Textviews und im Graphview dartellen kann.
Z.B.:
float speed_x = float[0]; //der Rahmen müsste zunächst abgeschnitten sein (startbytes, init, länge)
float speed_y = float[1];

Bisher werden die Werte einfach nur durch die angelegten Textview durchgeschoben, also nicht jedem Textview gehört ein floatwert. Da sitzt zur Zeit mein Problem.
Die Textviews für die Geschwindikeiten, Beschleunigungen, … sollten sich in den Textviews nur verändern, wenn eine Änderung im Messsystem entsteht und diese übertragen wird.
Ich hoffe das ich mein Problem nun ein wenig genauer geschildert hab.

öhm - nicht wirklich.

// ...
floats[0] = reader.read();

Du deklariest die Floats schön sauber. Liest aber aus dem Stream ein Integer. Selbst mit einem Cast floats[0] = (float)reader.read(); wird nicht das passieren was Du erwartest.

Für solche Dinge ist es (auch wenn viele gleich meckern werden) durchaus hilfreich mal sich mit C/C++ etc. auseinander zu setzen. Nur um zu sehen wie das im Hintergrgund funktioniert. Dadurch lässt sich das dann auch leichter in Java umsetzen. Das gesamte Gedöns mit den Streams ist an der Stelle nur ein riesiger Overhead der (je nach Anwendung) merklich Rechenleistung zieht.

        int value = 0;
        for(int i = 0; i < 4; i++)
            value = (value << 8) + (source[offset + (3 - i)] & 0xff);
        return Float.intBitsToFloat(value);
    }
float speed_x = restoreFloatFromArray(readbuffer, 5);
float speed_y = restoreFloatFromArray(readbuffer, 9);
// ...

Danke mogel für die Antwort. Der obere Programmcode ist nicht mehr aktuell. Ich habe es wie folgt gemacht und die Werte stimmen. Leider habe ich immer noch das Problem, dass die Messwerte nicht fest den Variablen --> Textviews zugewiesen sind.

byte[] readbuffers = (byte[])msg.obj;ByteArrayInputStream byteArrayInput = new ByteArrayInputStream(readbuffers);
DataInputStream dataInput = new DataInputStream(byteArrayInput);

float[] floats = new float[(readbuffers.length -Len_Header) / 4]; //Len_Header = 5 (Byte)
float speed_x = 0f;
float speed_y = 0f;
float speed_z = 0f;
...
for(int init = 0; init <floats.length; init++){
     try {
	floats[init] = dataInput.readFloat();
       speed_x = floats[0];
       speed_y = floats[1];
       speed_z = floats[2];
...
	} catch (IOException e) {
	      e.printStackTrace();
	}
}

tvSpeed_x.setText(Float.toString(speed_x));
tvSpeed_y.setText(Float.toString(speed_y));
tvSpeed_z.setText(Float.toString(speed_z));
...

Ich hab gerade deinen Code ausprobiert. Die Werte sind die gleichen, aber auch hier sind die Messwerte nicht fest den Variablen zugewiesen.
Aber vielen Dank für die Mühe.

Zwei Sachen:

  1. Die Zuweisung zu den Variable speed_x,y,z macht innerhalb der for-Schleife, in der du ja überhaupt erst die Werte liest, keinen Sinn. Es werden unnötigerweise mehrfach Werte (zum Teil noch garnicht gültig) zugewiesen.
  2. Wozu überhaupt die extra Variablen? Nach Durchlauf durch die for-Schleife hast Du alle floats schön in dein Array eingelesen. Da hast Du quasi Deine Variablen
    tvSpeed_x.setText(floats[0]); usw. sollte es dann auch tun

Leider habe ich so immer noch das gleiche Problem, dass die Werte einfach durch die einzelnen Textviews durchgereicht werden.
Ich habe den Vorschlag von mogel jetzt übernommen. Läuft mindestens genauso gut.
Ich habe im Protokoll ja zwei Startbytes (0xF1 & 0xF1) gegeben. Wie sollte ich dies am besten implementieren damit der Stream immer damit startet?

So sieht mein Code jetzt aus:

			
				float acc_x = restoreFloatFromArray(readbuffers, 5);
				float acc_y = restoreFloatFromArray(readbuffers, 9);
				float acc_z = restoreFloatFromArray(readbuffers, 13);
				float speed_x = restoreFloatFromArray(readbuffers, 17);
				float speed_y = restoreFloatFromArray(readbuffers, 21);
				float speed_z = restoreFloatFromArray(readbuffers, 25);
				float pos_x = restoreFloatFromArray(readbuffers, 29);
				float pos_y = restoreFloatFromArray(readbuffers, 33);
				float pos_z = restoreFloatFromArray(readbuffers, 37);
				float quat_w = restoreFloatFromArray(readbuffers, 41);
				float quat_x = restoreFloatFromArray(readbuffers, 45);
				float quat_y = restoreFloatFromArray(readbuffers, 49);
				float quat_z = restoreFloatFromArray(readbuffers, 53);
				float time = restoreFloatFromArray(readbuffers, 57);
				
				tvT1.setText(Float.toString(acc_x));
				tvT2.setText(Float.toString(acc_y));
				tvT3.setText(Float.toString(acc_z));
				tvT4.setText(Float.toString(speed_x));
				tvT5.setText(Float.toString(speed_y));
				tvT6.setText(Float.toString(speed_z));
				tvT7.setText(Float.toString(pos_x));
				tvT8.setText(Float.toString(pos_y));
				tvT9.setText(Float.toString(pos_z));
				tvT10.setText(Float.toString(quat_w));
				tvT11.setText(Float.toString(quat_x));
				tvT12.setText(Float.toString(quat_y));
				tvT13.setText(Float.toString(quat_z));
				tvT14.setText(Float.toString(time));```

tvSpeed_x.setText(restoreFloatFromArray(readbuffer, 5)); // nicht wirklich nach CCD

*** Edit ***

Wenn Du die Daten Seriell rüber schiebst, brauchst Du exakt den Anfang Deiner Daten. Das dumme an Seriell ist, das es immer sendet - egal ob jemand zuhört. Kann also sein das du mitten drinn anfängst zu Lesen.

Leider klappt das so nicht, da im Textview die Daten als char’s angezeigt werden sollen.

Kann ich nicht mittels eines eventlisteners den readbuffer nach seinen startbytes (habe zwei, beide 0xF1) untersuchen und immer wenn er die findet soll er mir das floatarray füllen?