[OFFEN] Unions wie in C, C++?

  • 15 Antworten
  • Letztes Antwortdatum
D

DrMarko

Neues Mitglied
1
In C und C++ nutze ich sehr viel Unions um z.B. einen Byte-Zugriff auf die Einzelbytes einer Float-Zahl zu kriegen:
typedef union
{
float Number;
struct
{
unsigned char Byte0;
unsigned char Byte1;
unsigned char Byte2;
unsigned char Byte3;
} Bytes;
} union_float;

Gibt es sowas auch in Java um es in Android zu verwenden?

Marko
 
Hi,
ich weiß jetzt nicht so ganz, ob ich das richtig verstanden habe. Wenn es dir ums Umwandeln von Floats in Byte und umgekehrt geht, schau mal hier vorbei: Byte | Android Developers

Habe hier auch mal noch einen kleinen Codeschnipsel gefunden, ist das vielleicht das, was du suchst? Falls nicht sorry :)
Code:
byte[] data = new byte[36];
ByteBuffer buffer = ByteBuffer.wrap(data);          
float second = buffer.getFloat(); //This helps to 
float x = 0;
buffer.putFloat(x);
 
Ich habe gerade mal in die Klasse reingelesen. Das scheint das zu sein was ich suche :) Letztlich übertrage ich mir per Bluetooth 1024*4 Bytes, welche 1024 float-Zahlen darstellen. Die brauche ich wieder in einem Array um sie darstellen zu können.

In C sieht der Code so aus:
Code:
// Übertragen des Strings aus dem COM-Port-RX-Buffer in das lange Byte-Array der Union
for (i=0; i<COMstrLen; i++) SpectrumBuffer.Byte[SpectrumBufferBytes + i] = COMreadBuf;
//plotten der Float-Zahlen
PlotY(MainPanel, MainP_GRAPH, SpectrumBuffer.floatWord, NrOfSpectrumPoints, VAL_FLOAT, VAL_THIN_LINE, VAL_NO_POINT, VAL_SOLID, 1, VAL_YELLOW);

//Und sie hier habe ich die Unions und die Variable im Header definiert:
typedef union
{
   float            floatWord[   NrOfSpectrumPoints];                   // Array of spectrum points
   unsigned char        Byte[4* NrOfSpectrumPoints];
} union_SpectrumBuffer;

union_SpectrumBuffer SpectrumBuffer;
 
Kann mir das gerade zeitbedingt nicht genauer anschauen, aber an der Stelle noch ein kleiner Tipp: Wenn du Code posten möchtest kannst du im Editor ganz rechts oben in den ASCII/BBCode Editor wechseln und dort kannst du auch deinen Code richtig darstellen, dann ist das wesentlich einfacher zu lesen. :)

Hab das in deinem letzten Post mal beispielshalber gemacht.
 
Hallo Marco,

Äqulvalent zu einem C-Struct/Union kannst du dir eine Klasse anlegen - so handhabe ich das auch
(Auch hauptberuflicher C-ler)

Bsp :

Code:
public class myStruct
{
 public int val_1;
 public String val_2;

  public myStruct()
  {
   val1_ = 0;
   val2 = "";
  }
}

private myStruct ms = new myStruct();
ms.val1 = 1000;
ms.val2 = " Test";

Ich würde es auch vermeiden statische Array-Grössen zu setzen .
Arbeite besser mit new, resp z.b. ArrayList

Code:
ArrayList<myStruct> MeinArrayList = new ArrayList<myStruct>
ms = new myStruct();
.
.
MeinArrayList.add (ms);



Für den ByteZugriff innerhalb von Float / Double kannst du ganz normal Shiften
 
Zuletzt bearbeitet:
Die Konvertierung vom Bytes hin zum Foat klappt problemlos, ich hänge jetzt aber an einer Sache die eigentlich so simple sein sollte:
- Ich muss vom COM-Port den Buffer als String auslesen (sonst hängt er sich auf).
- So lange die (unsigned) Bytes kleiner als 127 bleiben ist die Welt in Ordnung:
Ich sende 5 Bytes und empfange 5 Byte
- Aber wehe ich bin über 127 (also das 1ste Bit ist gesetzt). Dann scheint er das nicht nur als negative Zahl zu interpretieren, sondern macht aus jedem solchen Byte gleich 3 Stück.

Mein Problem ist also, dass die String readMessage = (String) msg.obj; ein Eigenleben hat und abhängig vom Dateninhalte die Daten unterschiedlich behandelt. Hier habe ich ein Verständnisproblem und brauche Hilfe:

Code:
bluetoothIn = new Handler()
{
    int stringLength;

   public void handleMessage(android.os.Message msg)
    {
        if (msg.what == handlerState)                                               // does this message belong to our Bluetooth COM port?
        {
            String readMessage = (String) msg.obj;                                  // msg.arg1 = bytes from connect thread
            recDataString.append(readMessage);                              // keep appending to string until you got enough data
            oldStringLength = stringLength;
            stringLength = recDataString.length();                                  // get string length
            byte[] byteBuffer = readMessage.getBytes(Charset.forName("UTF-8"));

            int y = 0;                                                              // copy data from the RX buffer into an array
            for (int i = oldStringLength; i<stringLength; i++)
            {
                DisplayData[i] = byteBuffer[y];
                y++;
            }
 
Hallo Marko,

hat es einen Grund , warum du nicht rein Socket basierend arbeitest und somit das String Problem umgehst ?
Also bei deinem ByteStream bleibst , anstatt ihn in ein String zu konvertieren.
"Zusammenstückeln" kannst du ihn ja nach Bedarf.

Hier ist ein schönes Beispiel
Sending and Receiving Data with Sockets · codepath/android_guides Wiki · GitHub




P.S. eine Anmerkung in eigener Sache :

Wir würden uns schon über eine Rückmeldung der gegebenen Antworten von Dir freuen.
Auch wie du dein Problem letztendlich umgesetzt hast.
Es ist sicherlich nicht von Dir beabsichtigt , aber ein Danke oder ein paar eingehenden Worte wären
schon angebracht. - Hier sitzen ja auch reale Menschen hinter der Tastatur :)
 
Zuletzt bearbeitet:
Hallo Stefan,

Sorry für meine Kommunikation. Das Problem ist halt dass ich noch kein Stück weiter gekommen bin und daher leider noch nix zurückgeben kann. Ich hänge jetzt schon den dritten Tag an dieser eigentlich einfachen Baustelle fest und überlege sogar Android hinzuschmeißen und ein W10-Mobile aufzusetzen um nicht in Java programmieren zu müssen. Ich habe bislang keine Objektorientierte Erfahrung. Ich habe schon Programme mit vielen tausenden Zeilen Code für verschiedene Prozessoren und auch PC geschrieben und bin damit auch ziemlich fit (strukturiertes hardwarenahes C). Umso frustrierender ist es gerade dass ich so eine einfach Sache wie ein paar Bytes über den Bluetooth-COM-Port nicht rüberzukriegen weil die String-Funktion der Meinung ist meine Bytes interpretieren zu müsen.

Ich habe folgende Zeile versucht um das Objekt direkt in ein Byte-Array einzulesen:
Code:
byte[] readMessage = (byte[]) msg.obj;
Android Studio meckert nicht, aber das Programm hängt sich auf und wird "angehalten".
Daher verfolge ich die Strategie den String einzulesen und in ein byte-Array umzuwandeln. Wenn das aber bereis beim Einlesen schief geht habe ich natürlich keine Chance.

Ich arbeite normal direkt auf den Registern des Prozessors und auch viel mit FPGAs, wo ich Prozessoren implementiere und die Befehlssätze erweitere. Aber meine Hardwarenahe Denke scheint für Java genau das Problem zu sein, dabei ist mein Programm fertig wenn ich es schaffe den COM mit Bytes statt String auszulesen.

Nochmals vielen Dank dass ihr hier da seid und ich werde über meine Lessons Learned schreiben.

Viele Grüße!
Marko

Code:
import android.support.v7.app.ActionBarActivity;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Random;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.LineGraphSeries;
import static java.nio.ByteOrder.LITTLE_ENDIAN;
import static java.nio.ByteOrder. BIG_ENDIAN ;

/**
* Created by Marko on 25.04.2017.
*/

public class ScanScreen extends ActionBarActivity {

    Handler bluetoothIn;

    final int handlerState = 1;                      //used to identify handler message (assigned to Bluetooth COM port)
    private BluetoothAdapter btAdapter = null;
    private BluetoothSocket btSocket = null;
    private StringBuilder recDataString = new StringBuilder();
    private byte[] DisplayData = new byte[4096];    //collects the 1024*4 Bytes which contain 1024 float numbers
    private int oldStringLength = 0;
    private ConnectedThread mConnectedThread;

    int stateComMachine;                            // this state information allows us to interprete the received data
    final int COM_idle          = 0;                    // idle state (if a message is received then do nothing more than to display it in the console
    final int COM_whoAreYou     = 1;                    // wait for 34 bytes to be received and display the value in the console
    final int COM_NormSpec      = 2;                    // wait for 2056 Bytes to be received and 2047 Byte sto be received and calculate 4 Byte to an float number

    final byte CMD_whoAreYou        = (byte) 0x80;
    final byte CMD_readSerialNr     = (byte) 0x81;
    final byte CMD_NormSpec         = (byte) 0x8F;
    final byte CMD_DumNormSpec      = (byte) 0x90;



    // SPP UUID service - this should work for most devices
    private static final UUID BTMODULEUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    // String for MAC address
    private static String address;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        //view of the ScanScreen
        setContentView(R.layout.activity_scan_screen);

        final TextView TextBox  = (TextView) findViewById(R.id.TextBox);
        final GraphView graph   = (GraphView) findViewById(R.id.graph);
        Button ScanButton       = (Button) findViewById(R.id.ScanButton);
        Button whoAreYouButton  = (Button) findViewById(R.id.whoAreYouButton);
        graph.getViewport().setXAxisBoundsManual(true);
        graph.getViewport().setYAxisBoundsManual(true);
        graph.getViewport().setMinX(0);
        graph.getViewport().setMaxX(100);
        graph.getViewport().setMinY(-1);
        graph.getViewport().setMaxY(2);

        TextBox.append("\nHello User! \nBoschSavartEva-App v1.0");

        bluetoothIn = new Handler()
        {
            int stringLength;

            public void handleMessage(android.os.Message msg)
            {
                if (msg.what == handlerState)                                               // does this message belong to our Bluetooth COM port?
                {
                    String readMessage = (String) msg.obj;                                  // msg.arg1 = bytes from connect thread
                    recDataString.append(readMessage);                              // keep appending to string until you got enough data
                    oldStringLength = stringLength;
                    stringLength = recDataString.length();                                  // get string length
                    byte[] byteBuffer = readMessage.getBytes(Charset.forName("UTF-8"));

                    int y = 0;                                                              // copy data from the RX buffer into an array
                    for (int i = oldStringLength; i<stringLength; i++)
                    {
                        DisplayData[i] = byteBuffer[y];
                        y++;
                    }


stateComMachine = COM_idle;

                    switch (stateComMachine)
                    {
                        case COM_whoAreYou:
                        {
                            if (stringLength >= 34)
                            {
                                TextBox.append("\n" + recDataString.substring(0, stringLength));    // print the who are you answer in the console

                                recDataString.delete(0, recDataString.length());                    //clear all string data
                                stateComMachine = COM_idle;
                                oldStringLength = 0;
                            }
                        }
                        break;
                        case COM_NormSpec:
                        {
                            //TextBox.append("\n" + stringLength);
                            if (stringLength >= (4096))
                            {
                                //TextBox.append("\n" + recDataString.substring(0, stringLength));    // print the who are you answer in the console
                                char[] dataC        = new char[4096];
                                byte[] dataB        = new byte[4096];
                                float[] DataAsFloat = new float[1024];

/*
                                //Dummy fill with Float = 1.2
                                recDataString.delete(0, recDataString.length());           // dummy fill the array with the float value 1.2
                                for(int i = 0; i <1024; i++)
                                {
                                    recDataString.append((char)  154);
                                    recDataString.append((char)  153);
                                    recDataString.append((char)  153);
                                    recDataString.append((char)   63);
                                }
                                //Dummy fill end
*/

                                recDataString.getChars(0, 4096, dataC, 0);                          // string to character conversion
                                for(int i = 0; i <4096; i++) dataB[i] = (byte) (dataC[i]);          // character to byte conversion
                                ByteBuffer buffer = ByteBuffer.wrap(dataB);                         // 4*bytes to float conversion

                                //ByteBuffer buffer = ByteBuffer.wrap(DisplayData);                         // 4*bytes to float conversion

                                buffer.order(LITTLE_ENDIAN);
                                //buffer.order(BIG_ENDIAN);

                                //for(int i = 0; i <1024; i++)
                                for(int i = 0; i <2; i++)
                                {
                                    DataAsFloat[i] = buffer.getFloat(i*4);

                                    TextBox.append("\n" +i + "        " + DataAsFloat[i] + "  " + dataB[i*4+3] + dataB[i*4+2] + dataB[i*4+1] + dataB[i*4+0]);
                                }
                                for(int i = 1022; i <1024; i++)
                                {
                                    DataAsFloat[i] = buffer.getFloat(i*4);

                                    TextBox.append("\n" +i + " " + DataAsFloat[i] + "  " + dataB[i*4+3] + dataB[i*4+2] + dataB[i*4+1] + dataB[i*4+0]);
                                }



                                recDataString.delete(0, recDataString.length());                    //clear all string data
                                oldStringLength = 0;
                                stateComMachine = COM_idle;
                            }
                        }
                        break;
                        case COM_idle:
                        {
                            recDataString.delete(0, recDataString.length());                                       //clear all string data
                            oldStringLength = 0;
                        }
                        default:
                        {
                            recDataString.delete(0, recDataString.length());                                       //clear all string data
                            oldStringLength = 0;
                            stateComMachine = COM_idle;
                        }
                        break;


                    }
                }
            }
        };

        btAdapter = BluetoothAdapter.getDefaultAdapter();       // get Bluetooth adapter
        checkBTState();

        Button ExitButton = (Button) findViewById(R.id.ExitButton);
        ExitButton.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                DisconnectBT();     // disconnect Bluetooth
                finish();           // return to the previous screen
            }
        });


        ScanButton.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                requestNormSpec();
                TextBox.append("\nnormalized spectrum requested");
                LineGraphSeries<DataPoint> series = new LineGraphSeries<>(getData());
                graph.addSeries(series);
            }
        });

        whoAreYouButton.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                whoAreYou();
                TextBox.append("\nwhoAreYou requested");
            }
        });

    }

    private void whoAreYou()
    {
        stateComMachine = COM_whoAreYou;                    // set COM state for handler
//        recDataString.delete(0, recDataString.length());    //clear all string data
        mConnectedThread.writeByte(CMD_whoAreYou);          // send code to request to measure the spectrum and to send the data normalize
    }

    private void requestNormSpec()
    {
        stateComMachine = COM_NormSpec;                     // set the COM state Marker to wait for ans display the normalized spectrum
//        recDataString.delete(0, recDataString.length());    //clear all string data
        mConnectedThread.writeByte(CMD_NormSpec);           // send code to request to measure the spectrum and to send the data normalized
    }


    private DataPoint[] getData()
    {
        Random mRand = new Random();
        int count = 100;
        DataPoint[] values = new DataPoint[count];
        for (int i=0; i<count; i++)
        {
            double x = i;
            double f = mRand.nextDouble()*0.01+0.3;
            double y = Math.sin(i*f+2) + mRand.nextDouble()*0.3;
            DataPoint v = new DataPoint(x, y);
            values[i] = v;
        }
        return values;
    }


    private void DisconnectBT()
    {
        if (btSocket!=null) //If the btSocket is busy
        {
            try
            {
                btSocket.close(); //close connection
            }
            catch (IOException e)
            { msg("Error");}
        }
    }

    // fast way to call Toast
    private void msg(String s)
    {
        Toast.makeText(getApplicationContext(),s,Toast.LENGTH_LONG).show();
    }

    private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {

        return  device.createRfcommSocketToServiceRecord(BTMODULEUUID);
        //creates secure outgoing connecetion with BT device using UUID
    }

    @Override
    public void onResume() {
        super.onResume();

        //Get MAC address from DeviceListActivity via intent
        Intent intent = getIntent();

        //Get the MAC address from the DeviceListActivty via EXTRA
        address = intent.getStringExtra(DeviceList.EXTRA_ADDRESS);  //receive the address of the bluetooth device

        //create device and set the MAC address
        BluetoothDevice device = btAdapter.getRemoteDevice(address);

        try {
            btSocket = createBluetoothSocket(device);
        } catch (IOException e) {
            Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_LONG).show();
        }
        // Establish the Bluetooth socket connection.
        try
        {
            btSocket.connect();
        } catch (IOException e) {
            try
            {
                btSocket.close();
            } catch (IOException e2)
            {
                //insert code to deal with this
            }
        }
        mConnectedThread = new ConnectedThread(btSocket);
        mConnectedThread.start();

        //I send a character when resuming.beginning transmission to check device is connected
        //If it is not an exception will be thrown in the write method and finish() will be called
        mConnectedThread.write("x");
    }

    @Override
    public void onPause()
    {
        super.onPause();
        try
        {
            //Don't leave Bluetooth sockets open when leaving activity
            btSocket.close();
        } catch (IOException e2) {
            //insert code to deal with this
        }
    }

    //Checks that the Android device Bluetooth is available and prompts to be turned on if off
    private void checkBTState() {

        if(btAdapter==null) {
            Toast.makeText(getBaseContext(), "Device does not support bluetooth", Toast.LENGTH_LONG).show();
        } else {
            if (btAdapter.isEnabled()) {
            } else {
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, 1);
            }
        }
    }

    //create new class for connect thread
    private class ConnectedThread extends Thread {
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;

        //creation of the connect thread
        public ConnectedThread(BluetoothSocket socket) {
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            try {
                //Create I/O streams for connection
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) { }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }


        public void run() {
            byte[] buffer = new byte[8192];
            int bytes;

            // Keep looping to listen for received messages
            while (true) {
                try {
                    bytes = mmInStream.read(buffer);           //read bytes from input buffer
                    String readMessage = new String(buffer, 0, bytes);
                    // Send the obtained bytes to the UI Activity via handler
                    bluetoothIn.obtainMessage(handlerState, bytes, -1, readMessage).sendToTarget();
                } catch (IOException e) {
                    break;
                }
            }
        }
        //write method
        public void write(String input) {
            byte[] msgBuffer = input.getBytes();           //converts entered String into bytes
            try {
                mmOutStream.write(msgBuffer);                //write bytes over BT connection via outstream
            } catch (IOException e) {
                //if you cannot write, close the application
                Toast.makeText(getBaseContext(), "Connection Failure", Toast.LENGTH_LONG).show();
                finish();

            }
        }


        public void writeByte(byte data) {
            try {
                mmOutStream.write(data);                //write bytes over BT connection via outstream
            } catch (IOException e) {
                //if you cannot write, close the application
                Toast.makeText(getBaseContext(), "Connection Failure", Toast.LENGTH_LONG).show();
                finish();

            }
        }
    }
}
 
Hallo Marco,

wie Du ja weisst , bin ich selber C-ler und kann sehr sehr gut nachvollziehen , was du mit deinen Worten mir sagen möchtest.
Fakt ist : es ist ein graus , wenn man in Tiefe gehen mag - besonders , wenn du einen Dauerprocess benötigt .
Ich hoffe für dich inständig , dass du das unter Android nicht realisieren musst.

Ich persönlich arbeite sehr viel mit NDK ( also C Code Implementation) um einige Dinge zu umgehen.

Ich schau mir mal jetzt eben jetzt deinen Source an ........
P.S hast du mal meinen Link oben durchforstet ?
.
.

Nachtrag nochmal zum verständnis :

An der Stelle hast du den beschriebenen Fehler ? ( 127 +)

String readMessage = (String) msg.obj; // msg.arg1 = bytes from connect thread
recDataString.append(readMessage);
 
Zuletzt bearbeitet:
Hallo Stefan,

Ich denke ich habe jetzt einen guten Ansatz gefunden: Ich habe die Handlerübergabe von String auf byte[] umgestellt und jetzt stürzt er erstmal nicht mehr ab:

Code:
public void run() {
    byte[] RxBuffer = new byte[8192];
    int bytes;

    // Keep looping to listen for received messages
    while (true) {
        try {
            bytes = mmInStream.read(RxBuffer);         //read bytes from input buffer
            String readMessage = new String(RxBuffer, 0, bytes);
            // Send the obtained bytes to the UI Activity via handler
            //bluetoothIn.obtainMessage(handlerState, bytes, -1, readMessage).sendToTarget();

            bluetoothIn.obtainMessage(handlerState, bytes, -1, RxBuffer).sendToTarget();
        } catch (IOException e) {
            break;
        }
    }
}

oben beim Auslesen mache ich das auch mit Bytes und jetzt kommt man was Sinnvolles an:
Code:
//                    String readMessage = (String) msg.obj;                                  // msg.arg1 = bytes from connect thread
                    byte[] RxBuffer = (byte[]) msg.obj;

Ich denke damit komme ich jetzt ein Stück weiter.

Vielen Dank!
Marko

PS: Wie machst du das eigentlich dass du so schnell antwortest?
 
Ich habe die Handlerübergabe von String auf byte[] umgestellt und jetzt stürzt er erstmal nicht mehr ab

Genau darauf wollte hinaus :)
Wollte aber zuvor sicher gehen , dass ich richtig liege :)

Verwende Strings unter Java nur dafür , wozu sie gedacht sind - alles andere bitte mit ByteArray. :)
Die entsprechen eher "unserem" unsigned char ....

Wie machst du das eigentlich dass du so schnell antwortest?
Schreibtisch ist voll, sitze derzeit rund um die Uhr im Büro und wenn sich hier was tut , bimmelt Outlook :)
 
Yep, ist bei mir genauso. Jetzt ist das Büro leer und endlich ist Ruhe sich zu konzentrieren.

Übriegens zum Thema Mensch und was schreiben was andere gebrauchen könnten: Hier meine Homepage:
www.Rocznik.de/Marko
 
^^ da war ich schon vor tagen drauf , - Man möchte ja auch wissen mit wem man es zu tun hat :)

Meine "Bande" will nicht von mir ins Netz, die "positionieren" sich schon selbst ( 13 & 21 Jahre) :)

Dir einen schönen Feierabend
 
Das mit dem Geben und Nehmen ist so eine Sache die ich selber ziemlich hoch halte. Ich bin ziemlich aktiv im Flugzeugbau tätig und als ich mal einen Oltimer restauriert hatte habe ich viel Hilfe bekommen nachdem ich eine Seite über den Flieger aufgesetzt hatte. Damit bin ich dann gleichzeitig zum digitalen Zentrum geworden und jetzt gibt es jährliche SF27 Treffen :) . Derzeit konstruiere ich einen kleine Flieger selber und auch hier bewährt es sich sei Wissen der Gemeinde zur Verfügung zu stellen, die Hilfsbereitschaft ist dann eine ganz andere als wenn man ein digitaler Niemand ist. Auch auf Facebook bin ich da ziemlich aktiv. Die letzten Tage habe ich z.B. einen 3D-Drucker gebaut und das begeistert meine Kids. Jetzt helfe ich denen in der Gruppe die Probleme haben - von genau der Gruppe die auch mir geholfen hat.

Heute morgen z.B. habe ich das hier online gestellt, aber bitte nicht lachen:
www.Rocznik.de/temp/Vogelpfeife.mp4

Und gestern Abend als ich das Schränkchen fetig hatte das hier (die Beschriftung musste trotz Mitternach noch rein ins Video):
http://www.rocznik.de/temp/AnetA8_Marko.mp4

Jetzt aber zurück zu Java :)

Marko
 
Hallo, noch ein Nachtrag zu deinen Code.
Soweit ich sehe benutzt du ein Inputstream. Du solltest ihn schließen (close() ) nachdem du die Bytes eingelesen hast. Sonst kann der GC den Stream nicht aus dem Speicher räumen.

Die Vogelpfeife finde ich genial. ;) Ich glaube ich muss den 3D-Drucker auf der Arbeit mal misshandeln (ähnliches Model).
 
Hier nochmal in der Zusammenfassung die Lösung meines Problem:

Ich habe mir einen Datenstrom vom Bluetooth-COM-Port geholt. Dabei will ich float-Zahlen empfangen(4Byte). Die ersten 4 Byte aber sind eine Integer-Zahl, welche sagt wie viele Datensätze (hier 2x float) ich zu empfangen habe.

RxBuffer:
Code:
public void run()
        {
            final int   RxBufferSize = 10000;                    // we expect 8192 Bytes max, so 10,000 is a sufficient number
            byte[]      RxInBuffer = new byte[RxBufferSize];
            byte[]      RxOutBuffer = new byte[RxBufferSize];
            int         RxBytesReceived;

            while (true)                            // Keep looping to listen for received messages
            {
                try
                {
                    RxBytesReceived = mmInStream.read(RxInBuffer);                          //read bytes from input buffer

                    if (RxDataLength < RxBufferSize)                                                // make sure you do not exceed the array size!
                    {                                                                       // the RxHandler will check whether it got enough data;if there is enought data, then it will be processed and RxDataLegth will be set to '0'
                        for (int i = 0; i < RxBytesReceived; i++)                           // copy data from the RxInBuffer into the RxOutBuffer
                        {
                            RxOutBuffer[RxDataLength] = RxInBuffer[i];
                            RxDataLength++;
                        }
                        bluetoothIn.obtainMessage(handlerState, RxDataLength, -1, RxOutBuffer).sendToTarget();      // Send the obtained bytes to the UI Activity via handler
                    }
                }
                catch (IOException e)
                {
                    break;
                }
            }
        }
Zu bemerken ist, dass "RxDataLength" als globale Variable am Beginn meines Programms steht, da sie vom RxHandler aus zurückgesetzt werden muss.
Code:
private int                 RxDataLength = 0;

Die Auswertung der empfangenen Bytes geschieht in einem Handler. Ich habe eine Variable "stateComMachine" welche ich setze bevor ich einen Befehl an meine Elektronik schicke. Daher weiß ich jetzt wie die Antwort zu behandeln ist. Ich möchte im untigen Code die Aufmerksamkeit auf die Stelle ab der Zeile
"if (RxDataLength >= 4)"
richten. Das ist die Stelle an der die ersten 4 Bytes eingetroffen sind, welche die Integer-Zahl entsprechen wie viele weitere Bytes emfpangen werden müssen (2 Byte pro Datensatz für 2x float). Die Umwandlung der Bytes in eine Integer-Zahl geschieht durch:
Code:
ByteBuffer myIntBuffer = ByteBuffer.wrap(RxData);
myIntBuffer.order(LITTLE_ENDIAN);
NrOfSampleToReceive = myIntBuffer.getInt(0);

Mit dieser Information weiß man jetzt wie lange man warten muss bis alle Bytes eingetroffen sind
Code:
if (RxDataLength >= (8*NrOfSampleToReceive+4))

Jetzt können die Float-Zahlen welche ab Byte 4 im Bytestrom vorhanden sind in eine Floatzahl umgerechnet werden. Wichtig ist, dass die Reihenfolge mit dem des sendenden Format übereinstimmt (LITTLE_ENDIAN/BIG_ENDIAN):
Code:
ByteBuffer FloatBuffer = ByteBuffer.wrap(RxData);                         // 4*bytes to float conversion
FloatBuffer.order(LITTLE_ENDIAN);
float[] WaveLength = new float[NrOfSampleToReceive];
float[] Intensity  = new float[NrOfSampleToReceive];

Damit hat man die Daten aus dem Byte-Strom extrahiert und kann sie plotten. Hier der komplette Code welcher darstellt wie man Zahlen aus einem Datenstrom wiedergewinnt, was man sonst in C mit Unions machen würde:

Code:
 bluetoothIn = new Handler()
        {

            public void handleMessage(android.os.Message msg)
            {
                if (msg.what == handlerState)                                     // does this message belong to our Bluetooth COM port?
                {
                    byte[] RxData = (byte[]) msg.obj;                             // get Data from the receive Routine

                    switch (stateComMachine)
                    {
                        case COM_whoAreYou:
                        {
                            if (RxDataLength >= 34)
                            {
                                String WhoAreYouMessage = new String(RxData, 0, 35);
                                TextBox.append("\n" + WhoAreYouMessage);    // print the who are you answer in the console

                                RxDataLength = 0;
                                stateComMachine = COM_idle;
                            }
                        }
                        break;
                        case COM_NormSpec:
                        {
                            int NrOfSampleToReceive;
                            if (RxDataLength >= 4)      // we know now how many bytes we need to receive
                            {
                                ByteBuffer myIntBuffer = ByteBuffer.wrap(RxData);
                                myIntBuffer.order(LITTLE_ENDIAN);
                                NrOfSampleToReceive = myIntBuffer.getInt(0);
                            }
                            else break;

                            if (RxDataLength >= (8*NrOfSampleToReceive+4))         // we expect 2 float number (meaning 8 byte per Datapoint)
                            {
                                ByteBuffer FloatBuffer = ByteBuffer.wrap(RxData);                         // 4*bytes to float conversion
                                FloatBuffer.order(LITTLE_ENDIAN);

                                float[] WaveLength = new float[NrOfSampleToReceive];
                                float[] Intensity  = new float[NrOfSampleToReceive];

                                DataPoint[] PlotValues = new DataPoint[NrOfSampleToReceive];
                                for(int i = 0; i <NrOfSampleToReceive; i++)
                                {
                                    WaveLength[i] = FloatBuffer.getFloat(i * 8 + 4);    // first 4 Bytes are the wave length as float number
                                    Intensity[i]  =  FloatBuffer.getFloat(i * 8 + 8);    // the next 4 Bytes are the intensity

                                    Intensity[i] = Log(1);

                                    DataPoint v = new DataPoint( WaveLength[i], Intensity[i]);
                                    PlotValues[i] = v;
                                }

                                graph.getViewport().setMinX(400);
                                graph.getViewport().setMaxX(700);
                                graph.getViewport().setMinY(-1);
                                graph.getViewport().setMaxY(20);

                                LineGraphSeries<DataPoint> series = new LineGraphSeries<>(PlotValues);
                                graph.removeAllSeries();
                                graph.addSeries(series);

                                RxDataLength = 0;
                                stateComMachine = COM_idle;
                            }
                        }
                        break;
                        case COM_idle:
                        {
                            RxDataLength = 0;
                        }
                        default:
                        {
                            RxDataLength = 0;
                            stateComMachine = COM_idle;
                        }
                        break;
                    }
                }
            }
        };

Ich hoffe das hilft jemanden mit einem ähnlichen Problem.
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: lordzwieback
Zurück
Oben Unten