Search code examples
androidkotlinbinarybyteascii

KOTLIN - How to represent message length as 2 binary bytes


I am facing a problem while building an integration between ECR (electronic cash register) and an android POS. I'm working on the android POS and i want to calculate the message size and add it in "2 bytes, binary".

I have this block of code to calculate and generate the complete message

fun  generateMessage(message: String): String {
    
            return buildString {
                append(Constants.DIRECTION)
                append(AppData.getProtocolVariant())
                append(AppData.getProtocolVersion())
                append(message)
    
                val buffer = ByteBuffer.allocate(2)
                buffer.putShort(message.length.toShort())
                insert(0, buffer.array().decodeToString())
            }
        }

But this code only works for really small messages, because in the logs i can see that for larger messages this code adds 3 digits and communication fails. The complete message is in the form of <MSG SIZE(2 bytes, binary)><DIRECTION INDICATOR(3 bytes, ascii)><PROTOCOL VARIANT(2 bytes, ascii)><PROTOCOL VERSION(2 bytes, ascii)><Actual messsage (MSG SIZE-7)>

When I send a simple message "E/000" (hex dump 45 2f 30 30 30) the code works and the ECR accepts it and in the logs i see "��POS0110E/000" when i have a bigger message i see something like this "���POS0110R/S852484/RDLF****16/T93/M0/C00/DMastercard:00:0000***1234:200:200:0:0:0:1:803:2:133030119089:193439:497853:20230926115814:0"

which has 3 digits for the message size and it fails.

So how can i create this message and follow the protocol <MSG SIZE(2 bytes, binary)>?

override fun sendMessage(message: String) { 
      val finalMessage = Utils.generateMessage(message) 
      server.sendMessage(finalMessage.encodeToByteArray()) }

`

changed the code to

 fun sendMessage(bytes: ByteArray) { 
   coroutineScope.launch(Dispatchers.IO) { 
    val outputStream = socket?.getOutputStream() 
    outputStream?.write(bytes) 
    outputStream?.flush() 
  } 
}` 

and still is not accepted

example from the guide enter image description here


Solution

  • You need to write bytes to the OutputStream, not a String. You should change your generateMessage() method to return a ByteArray instead of a String, like this:

    fun generateMessage(message: String): ByteArray {
        val x = buildString {
            append(Constants.DIRECTION)
            append(AppData.getProtocolVariant())
            append(AppData.getProtocolVersion())
            append(message)
        }
        // Create byte array containing 2-byte message length (binary) followed
        //  by the actual message
        val buffer = ByteBuffer.allocate(2 + x.length)
        buffer.putShort(x.length.toShort())
        buffer.put(x.getBytes())
        return buffer
    }
    

    Also, please note that the message length (according to the example from the guide you pasted) is the length of the entire message (including the header: direction, protocol version, etc.). In your code you only used the length of the actual message (not including the header data).