Android Question Char to Byte Issue/help

chrisinky

Member
Licensed User
Longtime User
I'm sending data over astream and on the other end any number values past 9 are getting truncated, for example 11 comes across as 1. Here is my class:
Class:
Sub Class_Globals
    'List of char/int16 that make up the command
    Private data As List
End Sub

Public Sub Initialize(command As Char)
    data.Initialize 'Can't use Initialize2 here because then we won't be able to add new items
    data.Add(command)
End Sub

Public Sub AddNumberArgument(arg As Char)
    data.Add(arg)
End Sub

Public Sub AddStringArgument(arg As String)
    For i = 0 To arg.Length - 1
        data.Add(Asc(arg.CharAt(i)))
    Next
End Sub

Public Sub ToByteArray As Byte()
    data.InsertAt(0, data.Size) 'Add number of chars of command
    Dim byteArray(data.Size * 2) As Byte '1 char = 2 bytes
    For i = 0 To data.Size - 1
        'Split char into its two bytes
        byteArray(i * 2) = Bit.ShiftRight(Bit.And(data.Get(i), 0xFF00), 8)
        byteArray(i * 2 + 1) = Bit.And(data.Get(i), 0xFF)
    Next
    Return byteArray
End Sub


Here is how I'm using this to send data:

B4X:
Private Sub SendCursorUpdate(x As Int, y As Int) 'new code
    Dim c3 As Packet2
    c3.Initialize(3)
    c3.AddNumberArgument(x) 'example x=5
    c3.AddNumberArgument(y) 'example x=11 - but it comes across the other side as 1
    c3.AddNumberArgument(2)

    astream.Write(c3.ToByteArray)

End Sub
The byte stuff is over my head, can anyone assist with why this may not be working?
Thanks!
 

agraham

Expert
Licensed User
Longtime User
Firstly Bytes are not Chars. A Byte is an signed 8 bit value whereas Chars are usually (almost always in reality) unicode point 16 bit integer values.

Your types are all confused so I am not sure what you are actually trying to send. , AddNumberArgument takes a Char parameter but you are passing Int values of 5 and 11 to it in SendCursorUpdate. These will be cast to Chars equivalent to Char(5) and Char(11) which are control characters. The Unicode point value of the '5' character is 53.

To convert a Char to an integer unicode point value use Asc(SomeChar)
To convert an integer unicode point value to a Char use Char(SomeInt)
 
Upvote 0

chrisinky

Member
Licensed User
Longtime User
Firstly Bytes are not Chars. A Byte is an signed 8 bit value whereas Chars are usually (almost always in reality) unicode point 16 bit integer values.

Your types are all confused so I am not sure what you are actually trying to send. , AddNumberArgument takes a Char parameter but you are passing Int values of 5 and 11 to it in SendCursorUpdate. These will be cast to Chars equivalent to Char(5) and Char(11) which are control characters. The Unicode point value of the '5' character is 53.

To convert a Char to an integer unicode point value use Asc(SomeChar)
To convert an integer unicode point value to a Char use Char(SomeInt)
Thank you, so the other end is expecting unicode point 16 bit integer values. So - the add number argument I assume I shouldn't be taking those as Char? If I want to send a unicode point 16 bit integer value can I just use INT?
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
so the other end is expecting ...
You tell me, I don't know
If I want to send a unicode point 16 bit integer value can I just use INT?
Yes

EDIT: Actually probably not as an Int value is actually four bytes and the other end may only be expecting two byes so it all depends upon what it will accept.
 
Upvote 0

chrisinky

Member
Licensed User
Longtime User
You tell me, I don't know

Yes

EDIT: Actually probably not as an Int value is actually four bytes and the other end may only be expecting two byes so it all depends upon what it will accept.
Yes, sorry other end is expecting 2 bytes... so thats where I'm crossed up....
 
Upvote 0

chrisinky

Member
Licensed User
Longtime User
With some most excellent help from a discord member, he found that using Char in B4A it first converts the number to a string, the first character of that string is taken off and returned back. So thats why single numbers worked, and anything double digit did not. Hope this helps someone in the future.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
So thats why single numbers worked, and anything double digit did not. H
Unless I totally misunderstand that's not the reason I'm afraid. You cannot represent two characters in a single Char. It is nothing to do with the way B4X handles Chars which does not do anything that is not intuitive and is always equivalent to handling single characters without any intervening conversion.
 
Upvote 0

chrisinky

Member
Licensed User
Longtime User
When B4A converts to native Java it wraps CHAR in a function called Object to Char, B4A source for that below:
b4asource:
public static char ObjectToChar(Object o) {
  if (o instanceof Character)
    return ((Character)o).charValue();
  else
    return CharFromString(o.toString());
}

public static char CharFromString(String s) {
  if (s == null || s.length() == 0)
    return '\0';
  else
    return s.charAt(0);
}

As you can see, it converts whatever you send to a string, then returns the value at position 0.

So - when I was doing CHAR(11) - in the end the data sent to the system I'm integrating with only got "1".

The sample code, in Java, using the same CHAR(11) works fine. My understanding is that in Java a CHAR is a 2 byte # OR a single character.

Changing my code from using CHAR(x) to INT(x) before creating my byte array fixed my problem.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
As you can see, it converts whatever you send to a string, the returns the value at position 0.
Of course I know that, I've been poking around inside B4A and it's predecessor Basic4PPC for years now and my statement above in post #7 is correct. I don't think you understand what Char(11) actually does. Char(11) returns the UTF16 character of the code point value of 11 which is the control character VT or Ctl-K. The string for the value 11 is Char(49) & Char(49)'
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
I'm going to agree with @agraham here that this is not an issue with B4A, but with how you are using B4A. In your case you have a function
B4X:
Public Sub AddNumberArgument(arg As Char)
But you call it with
B4X:
AddNumberArgument(x)
where x is defined as an Int. At this point you are at the mercy of B4A's Int to Char conversion. The way you should have called it is
B4X:
AddNumberArgument(Chr(x))
and then the proper conversion would have happened.
When B4A converts to native Java it wraps CHAR in a function called Object to Char, B4A source for that below:
It only does this if you, like in your case above, let B4A convert one object type to another (in your case Int to Char) implicitly, instead of using the explicit conversion method of converting the Int to a Char via Chr(). Even then, you are technically converting the integer expression of a Unicode character to Char.

So - when I was doing CHAR(11) - in the end the data sent to the system I'm integrating with only got "1".
At what point where you actually doing a proper Chr(11) in your code?
Changing my code from using CHAR(x) to INT(x) before creating my byte array fixed my problem.
Where was this code change accomplished?
 
Upvote 0
Top