Android string processing from TCP stream - android

I have a very basic TCP socket connection to a remote device that I can poll for status.
Aside from the socket programming, which I have mostly figured out through asynctask, I'm trying to come up with a way to parse out the returning string.
I query the device with something like "VOL?"
The device responds with the Volume of 12 different audio outputs with this:
"VOL:33,0,21,12,0,43,0,0,0,0,20,0"
The ":" character always and only comes back after the echo of the initial command, so I can use whatever comes before the colon to flag what sort of answer is coming in. (VOL, BAS, MUT, TRE, BAL, etc)
In the case of VOL, I simply want to chunk out everything that comes between the commas, so I can chop up and place into an array the volumes of all zones.
The only thing I can think of is to grab the length of the string, then run a for loop through it searching for commas one by one, but it seems ridiculously messy:
int oldPos = 0; //used in the upcoming 'if clause' to mark where the last comma was found
int y = 0; //used to old the resulting value's array position
String strIncoming; = //the incoming TCP string
for(int x = 0; x <= strIncoming.length(); x++){
if(",".equals(strIncoming[x]){
volzoneVal[y] = strIncoming.subString(oldPos,x);
oldPos = x;
y++;
}
}
there has GOT to be a better way, (and I'm not even sure this is going to work, I'm typing it here for the first time as I brainstorm this problem, so it's not been run or compiled)
Is there a better way to scan through a string looking for hits?

strIncoming.split(":")[0] will give you what was before first colon
strIncoming.split(":")[1].split(",") will give you array of individual strings

First, split the string on the colon, and then split[0] is your type. Then take split[1] and split it on the comma, and you'll have all your 12 different outputs ready to go (just convert them to integers).

Use Java's string split function and split on the comma as the delimiter. You will then have an array of your parameters. If you append some kind of "end string" character to each response, you will know the start and end based on the colon for the start and your end character for the end.

Related

Kotlin chunked and map

I am quite new to all things Android and Kotlin. I am currently working with an Android app from Punch Through:
(Blog: https://punchthrough.com/android-ble-guide/)
(GitHub: https://github.com/PunchThrough/ble-starter-android)
The app connects with a BLE peripheral and allows the user to enter text to send to the peripheral via UART.
I am struggling interpreting what the following code means / does:
with(hexField.text.toString()) {
if (isNotBlank() && isNotEmpty()) {
val bytes = hexToBytes()
ConnectionManager.writeCharacteristic(device, characteristic, bytes)
}
}
Where hexField.text.toString() is the text entered in the EditText field by the user,
and
where hexToBytes() is defined as:
private fun String.hexToBytes() =
this.chunked(2).map { it.toUpperCase(Locale.US).toInt(16).toByte() }.toByteArray()
I have tried this a few times, always entering “111” and have am using Timber() to output the result of bytes. This result varies every time, for example:
[B#2acf801
[B#476814a
[B#e9a70e5
[B#10172a0
So, I assume that only the first three characters are relevant, and somehow there is no end of line / string information.
So perhaps I am only interested in: [B#.......
B# = 0x 5B 42 40
Hex: 5B4240
Dec: 5980736
Bin: 10110110100001001000000
So then I try (and fail) to interpret / breakdown what this code might be doing.
The first thing I struggle with is understanding the order of operation.
Here's my guess....
Given EditText entry, in this case I entered "111"
First:
this.chunked(2)
would produce something like:
"11 and "01"
Second, for each of the two items ("11 and "01"):
it.toUpperCase(Locale.US).toInt(16).toByte()
would produce byte values:
17 and 1
Third:
.map .toByteArray()
Would produce something like:
[1,7,1]
or
[0x01, 0x07, 0x1]
or
[0x0x31, 0x37, 0x31]
So, as you can see, I am getting lost in this!
Can anyone help me deconstruct this code?
Thanks in advance
Garrett
I have tried this a few times, always entering “111” and have am using Timber() to output the result of bytes. This result varies every time
The output when you try to print a ByteArray (or any array on the JVM) doesn't show the contents of the array, but its type and address in memory. This is why you don't get the same result every time.
In order to print an array's contents, use theArray.contentToString() (instead of plain interpolation or .toString()).
Regarding the interpretation of the code, you almost got it right, but there are a few mistakes here and there.
this.chunked(2) on the string "111" would return a list of 2 strings: ["11", "1"] - there is no padding here, just the plain strings with max size of 2.
Then, map takes each of those elements individually and applies the transformation it.toUpperCase(Locale.US).toInt(16).toByte(). This one makes the string uppercase (doesn't change anything for the 1s), and then converts the string into an integer by interpreting it in base 16, and then truncates this integer to a single byte. This part you got right, it transforms "11" into 17 and "1" into 1, but the map {...} operation transforms the list ["11", "1"] into [17, 1], it doesn't take the digits of 17 individually.
Now toByteArray() just converts the List ([17, 1]) into a byte array of the same values, so it's still [17, 1].

Android - ASCII and HEX Value

If this is a duplicate, first of all, I'm sorry I've been looking all around and I haven't found how to solve my problem (or my head is too messed up).
I think that is better if I throw my problem rather than explain it.
I have an integer value wich is int234. I convert this value to its hex string representation EA. Note that this is "EA", it is a string.
Then I use Integer.parseInt to convert it to 0xEA (which is an hex value, not hex string) and finally I need the ASCII (or character) representation of this value.
The problem is that when I decode it using Integer.toHexString I get C3AA instead of EA
This is the best explanation I've found. But still I don't know how to solve it..
I hope you can help me out! Thanks in advance!
EDIT
I'd like to transmit the int 234 in a UDP datagram that's why I use the conversions. (This UDP channel mainly sends ASCII ("234") but I want an exception to that and once in a while transmit it in ony 1byte) That's why I do all this conversions (maybe it is easier than this, but I think I'm too close the problem that I can't see it with clarity)
I can confortly do it in C but I need to do it in Java. And my head is going crazy.
So 234 toHexString becomes `hex="EA";
// HEX -> ASCII code
for(int i=0; i<hex.length()-1; i+=2 ){
String output = hex.substring(i, (i + 2));
int decimal = Integer.parseInt(output, 16);
result.append((char)decimal);
}
return result.toString();
As result I get a strange character (the one that #fadden said). Now a question: this value is 2bytes long?
I transmit this odd character and when I use str = Integer.toHexString(prevResult); I get C3AA.
Maybe I'm messing thing up, but what I want is just to transmit 0xEA(byte) and get the int 234 in the other side.
For Example, Let's say I'd like to transmit the word "COMMAND" and append the value 234. Normally I would send "COMMAND234" but now I need the command value to be only one byte long. So the hex representation of what I'd be transmitting would be:
0x67 0x79 0x77 0x77 0x65 0x78 0x68 0xEA
C O M M A N D 234

Arduino --> Android bluetooth communication (receive text with App Inventor)

I'm creating an Arduino based drone that can be controlled through an Android application.
In order to improve the user experience, I'd like to show the accelerometer/compass sensor's values on the application, so I need to send them from Arduino to Android, via Bluetooth. The values are simple integer number between 0 and 180.
The best solution I thought is to concatenate all the values (separated with a comma) in one string, and send it to the app, that will separate the single values (the string will be sent only when the app require it, in this case when a 'z' byte is received by Arduino).
if (Serial.available() > 0) {
if (Serial.read()=='z'){
Serial.println(String((int)sensor1) + ',' + String((int)sensor2) + ',' + String((int)sensor3));
}
}
Here are the App Inventor blocks:
It seems that the values are being received quite well, but there is a critical issue: somethimes the string is not received well, and that cause a lot of errors. Sometimes the received string is (for example) 10,10,10, but somethimes it is 10,10,1010 or just 10,10 ecc...
I also tried to send the values one by one, but the result was nearly the same.
I even tried to set 'numberOfBytes' to -1, using a delimiter byte, but this also was not succesful unfortunately.
I getting quite mad, so I hope there is another way to send thoose integers to Android, or to fix the system I'm already using.
I used Serial.print to send each result and then used Serial.write('>'); as the end marker.
In appinventor designer window set the Delimiter byte for Bluetooth client to 62 (the ASCII value for the > character ).
In the blocks window, use Bluetooth cliant1.Receive text and set number of bytes to -1
App invented will then read until a delimiter is found.
However it will cause the app to hang if it doesn't find one.
the problem is that you are not signaling the end of the string
I used his example on a project and was something like this:
while(Serial.available()>0){
Serial.println(String((int)Sensor1) + ',' + String((int)Sensor2)+ ',');
}
If you compare the two codes the difference will be a " , " the most at the end of the print and it solved the problem for you sitad

Best way to compare IP addresses quickly

I'm parsing two CSV files which contains IP addresses.
The first is a source CSV, and the second is a "Blacklist".
Because of the size of the source file, I'm trying to optimize the speed at which I find IP addresses that match the blacklist.
EDIT: The blacklist consists of IP Address "Blocks". This means that each record in the blacklist has two IP addresses: A Start Block (ex. 216.254.128.0) and an End Block. (Ex. 216.254.223.255)
This means that direct lookups etc, will NOT work.
I'm wondering what's the best way to approach this. The brute strength method would be:
String[] parts = sourceIP.split("\\."); // String array, each element is text between dots
int hi = 255;
int lo = 0;
int mid = (hi - lo) / 2 ;
if (Integer.valueOf(parts[0]) > mid) {
mid = lo;
}
I could then repeat this for each part to decide whether or not the IP address is in the black list.
This seems pretty aggressive and with 4k+ records, this could take a very, very long time.
It could take 10+ iterations to decide each part and that would then have to be repeated to check the "High" part of the IP blocks in the blacklist. That's 80+ iterations per record.
I'm hoping to get some input here to see the best method for comparing IP addresses.
What are your thoughts?
Would it be possible to use a quick bitwise mask to compare values rapidly by serializing INetAddress?
FILE STRUCTURE CLARIFICATION:
Source IP File:
Contains a list of records from a database. (Aprox 4k). Each record contains names, addresses, emails, and IP Address.
Blacklist:
Contains 4.2k records. Each record is an IP Address "Block". This consists of two IP Addresses. 1. Start and 2. End.
If the record in the Source list has an IP address that's found in the blacklist, I need to save that record and add it to a new file.
I assume you're talking IPV4 addresses of the form xxx.xxx.xxx.xxx.
You can easily convert an IP address into an integer. Each segment (i.e. xxx) is 8 bits (i.e. one byte). So four of them together makes a 32-bit integer. So, given an IP address like "192.168.100.12", you can split it into its four parts, parse each one to a byte and create an integer. Say, for example, that you created a byte array of the segments:
ipBytes[0] = 192;
ipBytes[1] = 168;
ipBytes[2] = 100;
ipBytes[3] = 12;
You can turn that into an integer:
int ipAddress = ipBytes[0];
ipAddress = (ipAddress << 8) | ipBytes[1];
ipAddress = (ipAddress << 8) | ipBytes[2];
ipAddress = (ipAddress << 8) | ipBytes[3];
There are more efficient ways to do that, but you get the idea. Your language's runtime library might already have something that'll parse an IP address and give you the bytes to make it an integer.
You have a set of IP address ranges that you want to check your source addresses against. Load each of the ranges into a structure like this:
class IPRange
{
public int startIp;
public int stopIp;
}
And store those in an array or list. Then sort the list by starting IP address.
For each source IP address, convert it to an integer and do a binary search of the list, searching the starting IP address. The source address itself might not be (probably won't be) found, but when the binary search terminates the mid value will hold the index of the range whose starting IP address is less than or equal to the source address. You then just have to check the source address against that item's ending IP address to see if it's in the range.
Binary search is O(log n). If you're searching a list of 4,300 ranges, it's going to take at most 13 probes to find an address in the array. That should be plenty fast enough, even when doing 4,000 different searches. You're only talking on the order of 50,000 total probes of the range array.
A couple of notes:
First, as I said above, I assume you're talking about IPV4 addresses. If you're talking about IPV6 addresses, the same concepts still apply but you'll need a 64 bit integer. I don't know enough about IPv6 to say how you'd convert the address to 64 bit integer. Probably you should depend on you runtime library to get the address bytes.
Second: I assume that ranges don't overlap. That is, you won't have something like:
start range end range
192.168.1.1 192.168.2.255
192.168.2.1 192.168.3.255
If you have that, then an IP address could fall within either of those ranges. You could potentially construct overlapping ranges that would allow addresses to fall through the cracks. If you have overlapping ranges, the problem becomes a little bit more complicated.
Put both files in a String. Use split(",") to split the ip's in the first string. Loop through the obtained ips array. For every ip search for it in the second String like blacklist.indexOf("," + ip + ",") But first add a "," at start and end of blacklist string.
Brute force it.
Load everything into ram, no reason not to.
Split the ips into a 2d array.
{0:123,123,123,123}
Blacklist into a 3d array.
Now you can start searching for integers.
When you have a match compare the next section.
If source value higher then compare to the END block same section.
When you have a match push to a new array and write it to a file at the end.
If this takes more time to run then it took me to type this then close the porn you have open because your ram is full and its using your page file.
You could use a data structure called Bloom Filter. Which is rather efficient performance and storage wise. As for an example, there's a question here, Most Efficient way of implementing a BlackList that has an answer that recommends this.
As far as I know, also Google Chrome uses this technique, as also explained rather nicely at Matthials Vallentine's blog post A Garden Variety of Bloom Filters.
Yet more explanation succinctly can be had found at Adobe leaked credentials checker. Some excerpts
The original leak is about 9.3GB uncompressed, of which 3.3GB is email
addresses [...] This means the data can fit into 512MB (i.e. 232 bits)
of memory and allows us to perform lookups in constant time [...] An
optimal bloom filter which is allowed to occupy 840MB would have
practically no false positives at all.
It seems like the most direction solution would be to use an interval tree to store the blacklist. Then check if the IP intersects with any of the intervals.
You also might want to consider using a Trie/hashtable to get fast lookups where the interval is the same. IE: 216.254.128.0 to 216.254.223.255 can be merged to 216.254.(128.0, 223.255), where the () is the interval. Thus you'd end up with two hash-table lookups (one for 216 and one for 254) then a search in an interval tree, which is likely to only contain a small number of elements.
You can also merge overlapping intervals into a single interval, which can probably be done as you build the interval tree. Which ends up being more like a binary search tree in that case.

ANDROID How to reduce String allocations

I've managed to get my allocations down to next to nothing using DDMS (great tool), this has drastically reduced my GCs to about 1 or 2 every 3 minutes. Still, I'm not happy because those usually cause a noticeable delay in the game (on some phones) when you interact with it.
Using DDMS, I know what the allocations are, they are Strings being converted from integers used to display game information to the HUD.
I'm basically doing this:
int playerScore = 20929;
String playerScoreText = Integer.toString(playerScore);
canvas.drawText(playerScoreText, xPos, yPos);
This happens once each frame update and the HUD system is modular so I plug things in when I need and this can cause 4 or 5 hud elements to allocate Strings and AbstractStringBuilders in DDMS.
Any way to reduce these further or eliminate all the String allocations and just reuse a String object?
Thanks,
Albert Pucciani
Reading your question reminded me of one of Robert Greens articles that I read quite some time ago. It discusses your problem almost identically. http://www.rbgrn.net/content/290-light-racer-20-days-32-33-getting-great-game-performance . Skip down to day 33 and start reading.
Remember the last int score and its string representation. On a new frame check if the score is the same. If the same, then no need to create a new string - just use the old one.
Here's what I've done in the past. This will eliminate string allocations.
I create a char[] of a size that will be at least as large as the maximum number of characters you will need to display on the screen. This means that you should select a maximum high score that is achievable in the game. The way you have it now let's you display a score as high as 2^31-1 which is insanely huge, it's not practical with respect to the game. Keep in mind, this is your game, so it's ok to limit the max score to something more reasonable in the context of the game. Pick a number that will virtually be impossible to achieve. Setting this limit will then set you up to be able to not have to muck around with converting large integers to String objects.
Here's what's required:
First, you need to be able to separate the digits in an integer and convert them to char without creating String objects. Let's say you want to convert the integer of 324 into three separate characters '3','2','4' to be placed in the text char[]. One way you can do this is by taking the value 324 and do a mod 10 to get the lowest digit. So 324%10 = 4. Then divide the value by ten and do another mod 10 to get the next digit. So (324/10)%10 = 2, and (324/100)%10 = 3.
int score = 324;
int firstPlaceInt = score%10; // firstPlace will equal 4
int tensPlaceInt = (score/10)%10; // tensPlace will equal 2
int hundresPlaceInt = (score/100)%10; // hundredsPlace will equal 3
You will have to do the above in a loop, but this expresses the idea of what you're trying to do here.
Next, with these digits you can then convert them to chars by referencing a character map. One way to do this is you can create this character map by making a char[] of size 10 and placing values 0 - 9 in indexes 0 - 9.
char[] charMap = {'0','1','2','3','4','5','6','7','8','9',};
So doing this:
int score = 324;
char firstPlace = charMap[score%10];
char tenslace = charMap[(score/10)%10];
char hundredsPlace = charMap[(score/100)%10];
Will create the chars you need for the 3 digits in score.
Now, after all that, I would limit the highest score to say 99,999 (or whatever makes sense in your game). This means the largest "string" I would need to display is "Score: xx,xxx". This would require a char[] (call it text for this example) of size 13. Initialize the first 7 characters with "Score: ", these will never need to change.
char[] text = new char[13];
text[0] = 'S';
text[1] = 'c';
text[2] = 'o';
text[3] = 'r';
text[4] = 'e';
text[5] = ':';
text[6] = ' ';
The next 6 will vary based on the score. Note, that you may not necessarily fill in all 6 of those remaining characters, therefore you need to create an int (call it scoreCount for this example) which will tell you how many characters in the text char[] are actually relevant to the current score in the game. Let's say I need to display "Score: 324", this only takes 10 chars out of the 13. Write the 3 chars for the score of 324 into char[7] to char[9], and set scoreCount to 10 to indicate the number of valid characters in the char[].
int scoreCount = 7;
text[9] = charMap[score%10]; // This is firstPlace
text[8] = charMap[(score/10)%10]; // This is tensPlace
text[7] = charMap[(score/100)%10]; // This is hundredsPlace
scoreCount = 10;
You will probably have to do the above in a loop, but this should express the general idea of what you're trying to do here.
After that, you can just use drawText (char[] text, int index, int count, float x, float y, Paint paint). index will be 0, and count will be scoreCount which indicates how many characters in text should be drawn. In the example above, it doens't matter what's in text[10] to text[12], it's considered invalid. You can continue to update text[] using the character map, and this should not create any objects.
I hope this helps. The code above isn't very robust, but I wrote it out as more of an expression of the ideas I'm trying to convey. You will have to create your own loops and manage the data properly within your code, but this sums up the mechanics of what needs to happen to avoid the use of Strings/StringBuilder/StringBuffer/etc.

Categories

Resources