1

I'm building a byte array to identify an M-Bus Master and i need to do it using the secondary address.

Details from Seller Software

To do it i need to build a byte[] with the identification of the address:

  1. Identification Number (4 bytes) – A number ranging from 00000000 to 99999999 to identify the meter.
  2. Manufacturer ID (2 bytes) – Three letters that identify the manufacturer.
  3. Version (1 byte) – Specifies the version of the device. The version is manufacturer specific.
  4. Device type (1 byte) – This field codes the device type (e.g. electricity meter, cold water meter)

If my math is not failing me this has a total of 8 bytes.

So here is my code to do it:

public static void main(String[] args) {
    // TODO code application logic here
    MBusSerialBuilder builder = MBusConnection.newSerialBuilder("COM4").setBaudrate(2400);
    try (MBusConnection mBusConnection = builder.build()) {
        // read/write
        int primaryAddress = 253;

        byte[] idNum = ByteBuffer.allocate(4).putInt(46152604).array();
        byte version = 0xFF & 88; //only need a byte not a 4 byte int
        byte deviceType = 0xFF & 13; //only need a byte not a 4 byte int
        short manuID = createManuID("ZRI");
        //builds the message without overflow now
        byte[] data = ByteBuffer.allocate(8).put(idNum).putShort(manuID).put(version).put(deviceType).array();

        mBusConnection.write(primaryAddress, data);
        VariableDataStructure vds = mBusConnection.read(primaryAddress);
        System.out.println(vds);
    } catch (IOException ex) {
        System.out.println(ex.getLocalizedMessage());
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }
}

Note previouslly i had

byte[] manId = ByteBuffer.allocate(2).putChar('Z').putChar('R').putChar('I').array();

And it was returning me java.nio.BufferOverflowException.

With the recent changes the error is now on data declaration.

Even if i alloc 50 bytes

byte[] data = ByteBuffer.allocate(50).put(idNum).put(manId).putInt(88).putInt(13).array();

Diferent error

java.lang.IndexOutOfBoundsException

Here is some info i extracted from a log file of the seller's program.

MBus Tx_raw-><11><68><b><b><68><53><fd><52><4><26><15><46><ff><ff><ff><ff><23><16>
MBus Rx_raw-><0><aa><1><e5><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0>
MBus Tx_raw-><5><10><7b><fd><78><16>
MBus Rx_raw-><0><aa><b7><68><b1><b1><68><8><0><72><4><26><15><46><49><6a><88><d><29><0><0><0><4><6d><34><a><27><2c><82><4><6c><21><21><82><a><6c><21><2c><4><6><0><0><0><0><84><4><6><0><0><0><0><84><a><6><0><0><0><0><4><13><4a><30><0><0>
MBus consecutive Frame [183]-><68><b1><b1><68><8><0><72><4><26><15><46><49><6a><88><d><29><0><0><0><4><6d><34><a><27><2c><82><4><6c><21><21><82><a><6c><21><2c><4><6><0><0><0><0><84><4><6><0><0><0><0><84><a><6><0><0><0><0><4><13><4a><30><0><0><2><59><8a><7><2><5d><bc><7><2><61><ce><ff><4><3b><bf><2><0><0><4><2d><4><0><0><0><4><26><b><8><0><0><84><10><6><2><0><0><0><84><14><6><0><0><0><0><84><1a><6><0><0><0><0><84><40><14><c1><6><0><0><84><44><14><0><0><0><0><84><4a><14><a9><0><0><0><84><80><40><14><10><0><0><0><84><84><40><14><0><0><0><0><84><8a><40><14><0><0><0><0><84><c0><40><14><e3><0><0><0><84><c4><40><14><0><0><0><0><84><ca><40><14><0><0><0><0><1b><16>

Readout insert->INSERT INTO LETTURE_CONTATORI_TEMP VALUES(NULL,'OK','1','1','510','07/12/2017 10:16:23','','','1512641783','0','07/12/2017 10:52','01/01/2017','01/12/2017','0','0','0','12362','1930','1980','-50','703','4','2059','2','0','0','1729','0','169','16','0','0','227','0','0','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','');
Tiago_nes
  • 843
  • 7
  • 30

2 Answers2

1

Ok, so with an offset of 65 (A) to every character you can create a mapping so-to-speak of the letters to convert them to smaller values which will fit in the 2 bytes (16 bits) whereby the values range from 0 to 25 (0=A, 1=B..., 25=Z). Since this range requires at most 5 bits, and you have a maximum of 3 characters to convert, you only need 15 bits and can squeeze these into the 2 bytes (16 bits) required for the manufacturer id. All you have to do is apply a bit shift of 5 (size of the values) * the index of the character in your manufacturer id string.

Here is the method

  public static short createManuID(String id)
  {
      int bitMashedManuID = 0;
      id = id.toUpperCase(); //force the chars to be within 65-90
      if(id.length() == 3)
      {
          short offset = 65; //A = 0, B = 1 ... Z = 25
          //number bits needed to fit 0-25 and so values won't overlap during the bit mashing
          short bitShift = 5; 
          for(int i = 0; i < id.length(); i++)
          {
              short valueOfChar = (short)id.charAt(i);
              valueOfChar -= offset; //apply the offset
              bitMashedManuID += valueOfChar << bitShift * i; //pack the bits
          }
      }
      return (short)bitMashedManuID;
  }

Example

Z = 90, apply the offset of 65 and we get 25 (11001)

So a manufacturer id of ZZZ should look like (11001|11001|11001) which equals 26425.

System.out.println(createManuID("ZZZ")); //outputs 26425

Your manufacturer id

Z = 90 - 65 = 25 = 11001
R = 82 - 65 = 17 = 10001
I = 73 - 65 = 8  = 01000

ZRI = |01000|10001|11001| = 8761

System.out.println(createManuID("ZRI")); //8761

Therefore when all is said and done you can create your byte array like this without overflow and satisfying the 8 byte array length requirement.

  public static void main(String[] args) 
  {
      byte[] idNum = ByteBuffer.allocate(4).putInt(46152604).array();
      byte version = 0xFF & 88; //only need a byte not a 4 byte int
      byte deviceType = 0xFF & 13; //only need a byte not a 4 byte int

      short manuID = createManuID("ZRI");
      //builds the message without overflow now
      byte[] data = ByteBuffer.allocate(8).put(idNum).putShort(manuID).put(version).put(deviceType).array(); 

  }

All that's left is determine the order of the letters are going to be packed in. Currently I pack them from right to left but depending on the device you are talking to it may require left to right which means you have the loop start at for(int i = id.length() - 1; i >= 0; i--)

RAZ_Muh_Taz
  • 4,059
  • 1
  • 13
  • 26
  • But the device still seems not to get a valid message. – Tiago_nes Dec 11 '17 at 09:40
  • can you wireshark the data you get back from the device? then take a look at how it packs the manufacturer ID in the message you get and show it? if you capture that message and ask a new question just comment here and i'll take a look at it for you – RAZ_Muh_Taz Dec 11 '17 at 16:32
  • it is from a serial port i'll update with the remaining code – Tiago_nes Dec 11 '17 at 17:05
  • ok show the full header message you get so i can see how the device is bit packing the manufacturer ID @Tiago_nes – RAZ_Muh_Taz Dec 11 '17 at 18:36
  • @ RAZ_Muh_Taz added some info from sellers program – Tiago_nes Dec 12 '17 at 09:36
  • so i took a look at that log output and compared it to the message we create and nothing even comes close to any part of the logs... i even reversed the bits to see if possibly that would show something but nothing. i don't know where the header is for the mbus in that capture.. @Tiago_nes – RAZ_Muh_Taz Dec 12 '17 at 16:50
  • here is a pdf of the MBUS protocol that should help you out http://www.m-bus.com/mbusdoc/md5.php – RAZ_Muh_Taz Dec 12 '17 at 16:57
-1

The BB isn't large enough.

You don't need all this. Allocate one ByteBuffer large enough for all the data, and then call all the puts you need. Or use a DataOutputStream.

user207421
  • 305,947
  • 44
  • 307
  • 483