0

I'm trying to build an application that reads information sent on a bluetooth service using rfcomm. The device is an hardness tester (HT-6510A), unfortunalty specs about the device data format can't be found I'm faced with a strange problem, I've to understand how to read these information.

01-11 17:47:28.940 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:29.581 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:30.211 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:30.872 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:31.513 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:32.143 11862-13447/joinstore.it.testhardness V/result: ��T
01-11 17:47:32.794 11862-13447/joinstore.it.testhardness V/result: ��T

This is the data I receive from the device, I don't think there's something wrong with the implementation tha simply uses this thread after stabilizing a rfcomm connection.

    //After connection, handle data transfer
    private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;

        public ConnectedThread(BluetoothSocket socket) {
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            // Get the input and output streams, using temp objects because
            // member streams are final
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
            }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run() {
//            readAndPublishRaw();
            readAndPublishString();
            Log.v("result", "Reading data ended.");
            setStatusText(-1);
        }

        void readAndPublishRaw(){
            byte[] buffer = new byte[1024];  // buffer store for the stream
            int bytes; // bytes returned from read()
            Log.v("result", "Start reading...");
            // Keep listening to the InputStream until an exception occurs
            while (true) {
                try {
                    // Read from the InputStream
                    bytes = mmInStream.read(buffer);
                    // Send the obtained bytes to the UI activity
                    Log.v("result", bytes + "");
                } catch (IOException e) {
                    break;
                }
            }
        }

        void readAndPublishString(){
            //String method, not useful in this case?
            try {
                BufferedReader r = new BufferedReader(new InputStreamReader(mmInStream));
                StringBuilder total = new StringBuilder();
                String line;
                Log.v("result", "Start reading...");
                while ((line = r.readLine()) != null) {
                    total.append(line);
                    Log.v("result", line);
                }
                Log.v("result", total.toString());
                //TODO publish read string to the view
            } catch (Exception e) {
                //
                try {
                    mmSocket.close();
                }catch (Exception ex){}
                Log.v(TAG, "exception reading data from service");
            }
        }

        /* Call this from the main activity to send data to the remote device */
        public void write(byte[] bytes) {
            try {
                mmOutStream.write(bytes);
            } catch (IOException e) {
            }
        }

        /* Call this from the main activity to shutdown the connection */
        public void cancel() {
            try {
                mmSocket.close();
                setStatusText(-1);
            } catch (IOException e) {
            }
        }
    }

Can you guys give me any information about how to correctly parse this raw data? I think I should have a stream of float values, but instead I've just this random stuff.

Pievis
  • 1,954
  • 1
  • 22
  • 42
  • 1
    "Unfortunalty specs about the device data format can't be found" - And you expect us to help you without even disclosing what the device is?! – JimmyB Jan 11 '16 at 17:14
  • 1
    "I think I should have a stream of float values" - That may well be the case. However, you know that via bluetooth you only get a stream of *bytes*. You'll have to look at those *bytes* to figure out how the values are encoded. Simply "casting" the bytes to a string does not help in any way. At least give us some sample messages in the *raw* format, i.e. bytes; include the *length* of each message too! – JimmyB Jan 11 '16 at 17:16
  • I've updated the question with the device name. For now I get the bytes one after another using the function readAndPublishRaw, do you know a better method to fetch this information? – Pievis Jan 11 '16 at 17:31
  • Might also consider moving the question to http://reverseengineering.stackexchange.com/ – JimmyB Jan 11 '16 at 17:44
  • "I get the bytes one after another" - Note that `InputStream.read(byte[] buffer)` puts the data received into the given buffer. `InputStream.read()` returns one byte after another. But reading one *message* at a time into the `byte[]` is what you want here anyway. – JimmyB Jan 11 '16 at 18:03

1 Answers1

2

Suggestion on how to get some usable log output first:

    void readAndPublishRaw(){
        byte[] buffer = new byte[1024];  // buffer store for the stream
        int bytes; // bytes returned from read()
        Log.v("result", "Start reading...");
        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer);
                // Send the obtained bytes to the UI activity

              final StringBuilder sb = new StringBuilder();
              sb.append("Received ").append(bytes).append(" bytes: ");
              for ( int i = 0; i < bytes; i++ ) {
                sb.append( Integer.toHexString(((int)buffer[i]) & 0xff) ).append(", ");
              }

              Log.v("result", sb.toString());
            } catch (IOException e) {
                break;
            }
        }
    }

The next step should be to calibrate the data, i.e. make note of which input/display value yields what raw data. From there, you may or may not be able to infer the actual encoding.

Your device may or may not include other information besides the actual measurement in the data, e.g. to indicate a low battery. That would have to be factored out to get raw measurement values.

If one data value comprises more than one byte the byte-order (little- or big-endian) needs to be determined.

Often floating point data of small devices is represented in a fixed point representation. Sometimes, esp. if negative numbers are needed too, with an offset added, so that

realValue = rawValue * a + c

If you find out a and c you're good. Hence, once you can relate only two different realValues and corresponding rawValues from the calibration done above, you have enough data to solve the equation for a and c.

Devices with a little more "punch", embedded linux devices for instance, may also use regular IEEE floating point data. - Not that small embedded devices cannot use IEEE, but floating point is often more than is required and comes at the price of higher complexity (memory & CPU) for the floating point emulation code.

JimmyB
  • 12,101
  • 2
  • 28
  • 44