I have an iOS application that talks to a RedBearLab Arduino device. My code that I use to send an int via bluetooth from Arduino to iOS is as follows:
void sendMyInt(int myInt) {
char b[4];
String str;
str=String(myInt);
str.toCharArray(b,4);
for (int i; i < 3; i++) {
char toPrint = b[i];
ble_write(toPrint);
}
}
Here is my code on the receiving end:
-(void) bleDidReceiveData:(unsigned char *)data length:(int)length
{
NSData *d = [NSData dataWithBytes:data length:length];
NSLog([NSString stringWithFormat:#"%#",d]);
NSString *s = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding];
const char* clearChar = "!";
if ([self.label.text isEqualToString:#"Label"]) {
self.label.text = #"";
}
else if ([s isEqualToString:[NSString stringWithUTF8String:clearChar]]) {
self.label.text = #"";
}
else {
NSString *store = self.label.text;
NSString *full = [NSString stringWithFormat:#"%#%#",store,s];
self.label.text = full;
}
}
The final else statement fires somewhat as expected, and a value of 233! is printed out to the label over and over again, getting longer each time eventually forming things like 233!233!233! etc. As you can see, I am using a character (!) sent over a function to clear the label, but it never clears. The integer is the ASCII code for the exclamation point:
void clearLabel() {
int clearString = 33;
char excalamtion = clearString;
ble_write(excalamtion);
}
Why would this not clear the label? I assume it has something to do with the clashing formats, but I'm not really too good at that even after reading some documentation. For the else if statement I also tried this
if ([s isEqualToString:#"!"])
but that didn't work out either... Any help would be appreciated.
EDIT:
I forgot to put in my loop code so you can see function calls. Here it is:
void loop()
{
if ( ble_connected() ) {
int a = 223;
sendMyInt(a);
delay(1000);
clearLabel();
delay(1000);
}
ble_do_events();
}
EDIT 2:
Based on a suggestion by #Duncan C , I have isolated the problem to the fact that the data is being sent as one packet to the iPhone. Upon printing out my generated string when the data is received, the string 233! is received all at once rather than individual chars of 2 3 3, and one second later the signal to clear, !. The data takes two seconds to appear on my phone, indicating that both delays are being used. I need a way to separate the 2 3 3 packet from the ! packet.
First off, this line:
NSLog([NSString stringWithFormat:#"%#",d]);
Is sort of pointless. The stringWithFormat serves no real purpose, since NSLog takes a format string anyway.
Use this instead:
NSLog(#"%#", d);
You should probably also log the contents of "s" once you convert your NSData to an NSString. That will help you figure out what's going on.
What is likely going on is that your string is coming in as "233!", all together, 4 bytes at a time (assuming that your integer is == 233).
Your string is unlikely to ever contain just "!". Instead, it will likely contain "233!" (4 characters.) I say likely because it depends on how the data is packetized into BLE. Something that short should be sent all in 1 BLE packet, so you should get the entire string together.
You could use the NSString method rangeOfString: to search for your "!" string, and if it contains an "!", clear your label, but that won't really do any good either. If you're sending "233!", then the iOS code will see the exclamation point in the string it receives and simply clear the label.
Or does your arduino project first send "233", then after some other event, send the "!". You didn't make that clear.
Another problem: What does the Arduino String class do if the integer is less than 1000, or less than 100, and doesn't require 3 or 4 characters to convert to a char array? What is stored in the unused bytes? You're always sending 4 characters, which is probably wrong.
Adding in another ble_do_events(); after calling the sendMyInt(); function causes the data to be transmit in two separate packets.
here is what I have done, but it appears disorderly. Thanks in advance.
1.use CGPDFStringCopyTextString to get the text from the pdf
2.encode the NSString to char*
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
const char *char_content = [self.currentData cStringUsingEncoding:enc];
Below is how I get the currentData:
void arrayCallback(CGPDFScannerRef inScanner, void *userInfo)
{
BIDViewController *pp = (__bridge BIDViewController*)userInfo;
CGPDFArrayRef array;
bool success = CGPDFScannerPopArray(inScanner, &array);
for(size_t n = 0; n < CGPDFArrayGetCount(array); n += 1)
{
if(n >= CGPDFArrayGetCount(array))
continue;
CGPDFStringRef string;
success = CGPDFArrayGetString(array, n, &string);
if(success)
{
NSString *data = (__bridge NSString *)CGPDFStringCopyTextString(string);
[pp.currentData appendFormat:#"%#", data];
}
}
}
- (IBAction)press:(id)sender {
table = CGPDFOperatorTableCreate();
CGPDFOperatorTableSetCallback(table, "TJ", arrayCallback);
CGPDFOperatorTableSetCallback(table, "Tj", stringCallback);
self.currentData = [NSMutableString string];
CGPDFContentStreamRef contentStream = CGPDFContentStreamCreateWithPage(pagerf);
CGPDFScannerRef scanner = CGPDFScannerCreate(contentStream, table, (__bridge void *)(self));
bool ret = CGPDFScannerScan(scanner);
}
According to the Mac Developer Library
CGPDFStringCopyTextString returns a CFString object that represents a PDF string as a text string. The PDF string is given as a CGPDFString which is a series of bytes—unsigned integer values in the range 0 to 255; thus, this method already decodes the bytes according to some character encoding.
It is given none explicitly, so it assumes one encoding type, most likely the PDFDocEncoding or the UTF-16BE Unicode character encoding scheme which are the two encodings that may be used to represent text strings in a PDF document outside the document’s content streams, cf. section 7.9.2.2 Text String Type and Table D.1, Annex D in the PDF specification.
Now you have not told us from where you received your CGPDFString. I assume, though, that you received it from inside one of the document’s content streams. Text strings there, on the other hand, can be encoded with any imaginable encoding. The encoding used is given by the embedded data of the font the string is to be displayed with.
For more information on this you may want to read CGPDFScannerPopString returning strange result and have a look at PDFKitten.
I'm using NSXMLParser for parsing XML to my app and having a problem with the encoding type. For example, here is one of the feeds coming in. It looks similar to this"
\U2026Some random text from the xml feed\U2026
I am currently using the encoding type:
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
Which encoding type am I suppose to use for converting \U2026 into a ellipse (...) ??
The answer here is you're screwed. They are using a non-standard encoding for XML, but what if they really want the literal \U2026? Let's say you add a decoder to handle all \UXXXX and \uXXXX encodings. What happens when another feed want the data to be the literal \U2026?
You're first choice and best bet is to get this feed fixed. If they need to encode data, they need to use proper HTML entities or numeric references.
As a fallback, I would isolate the decoder away from the XML parser. Don't create a non-conforming XML parser just because your getting non-conforming data. Have a post processor that would only be run on the offending feed.
If you must have a decoder, then there is more bad news. There is no built in decoder, you will need to find a category online or write one up yourself.
After some poking around, I think Using Objective C/Cocoa to unescape unicode characters, ie \u1234 may work for you.
Alright, heres a snippet of code that should work for any unicode code-point:
NSString *stringByUnescapingUnicodeSymbols(NSString *input)
{
NSMutableString *output = [NSMutableString stringWithCapacity:[input length]];
// get the UTF8 string for this string...
const char *UTF8Str = [input UTF8String];
while (*UTF8Str) {
if (*UTF8Str == '\\' && tolower(*(UTF8Str + 1)) == 'u')
{
// skip the next 2 chars '\' and 'u'
UTF8Str += 2;
// make sure we only read 4 chars
char tmp[5] = { UTF8Str[0], UTF8Str[1], UTF8Str[2], UTF8Str[3], 0 };
long unicode = strtol(tmp, NULL, 16); // remember that Unicode is base 16
[output appendFormat:#"%C", unicode];
// move on with the string (making sure we dont miss the end of the string
for (int i = 0; i < 4; i++) {
if (*UTF8Str == 0)
break;
UTF8Str++;
}
}
else
{
if (*UTF8Str == 0)
break;
[output appendFormat:#"%c", *UTF8Str];
}
UTF8Str++;
}
return output;
}
You should simple replace literal '\U2026' on a quotation, then encode it with NSUTF8StringEncoding encodind to NSData
I sending a byte array over a REST service. It is being received as String. Here is an extract of it. with start and end tags.
[0,0,0,0,32,122,26,65,0,0,0,0,96,123,26,65,0,0,0,0,192,123,20,65,0,0,0,0,0,125,20,65,71,73,70,56,57,97,244,1,244,1,247,0,0,51,85,51,51,85,102,51,85,153,51,85,204,51,85,255,51,128,0,51,128,51,51,128,102,51,128,153,51,128,204,51,128,255,51,170,0,51,170,51,51,170,102,51,170,153,51,170,204,51,170,255,51,213,0,51,213,51,51,213,102,51,213,153,51,213,204,51,213,255,51,255,0,51,255,51,51,255,102,51,255,153,51,255,204,51]
Now before anyone suggests sending it as a base64 encoded String, that would require Blackberry to actually have a working Base64 decoder. But alas, it fails for files over 64k and Ive tried alsorts.
Anyway this is what ive tried:
str = str.replace('[', ' ');
str = str.replace(']', ' ');
String[] tokens = split(str,",");
byte[] decoded = new byte[tokens.length];
for(int i = 0; i < tokens.length; i++)
{
decoded[i] = (byte)Integer.parseInt(tokens[i]);
}
But it fails. Where split is like the JAVA implementation found here.
Logically it should work? but its not. This is for JavaME / Blackberry. No Java Answers please (unless they work on javaME).
Two problems one minor and one that is a pain.
Minor:whitespaces (as mentioned by Nikita)
Major:casting to bytes ... since java only has unsigned byte, 128 and higher will become negative numbers when casting from int to byte.
str = str.replace('[',' ');
str = str.replace(']', ' ');
String[] tokens = split(str,",");//String[] tokens = str.split(",");
byte[] decoded = new byte[tokens.length];
for (int i = 0; i < tokens.length; i++) {
decoded[i] = (byte) (Integer.parseInt(tokens[i].trim()) & 0xFF);
}
for(byte b:decoded) {
int tmp = ((int)b) & 0xff;
System.out.print("byte:"+tmp);
}
(btw:implementing base64 encoder/decoder isn't especially hard - might be "overkill" for your project though)
Replace brackets with empty strings, not with spaces:
str = str.replace('[', '');
str = str.replace(']', '');
In your case you have following array:
[" 0", "0", "0", ..., "204", "51 "]
First element " 0" cannot be parsed to Integer.
I recommend to use Base64 encoded string to send byte array.
There's a post with link to Base64 library for J2ME.
This way allows you convert byte array to a string and later you can convert this string to byte array.
I am using the BluetoothSerialPortInfo class to get Bluetooth devices paired with my blackberry. When I tried to print the value of device address for each device, I don't see or get actual Bluetooth address. I am using the following code.
String btAddress = mPortInfo[count].getDeviceAddress().toString();
I actually get [#4d4cd14c from the above code. But the actual Bluetooth address of my device is : 00:21:3c:2d:1F:5c.
If I use javax.bluetooth, I get the actual Bluetooth address. But I want to use BluetoothSerialPortInfo to establish the serial connection to the device. So I want to correctly identify my device based on the Bluetooth address without using the friendly name of the device.
How do I convert the raw address which get from getDeviceAddress() method to the actual Bluetooth address???
Thanks,
getDeviceAddress() returns a byte array so you'll need to convert each byte into it's hex representation. If you're on 5.0 you can use ByteArrayUtilities.byteArrayToHex() but if you're on a lower OS version you'll need to write your own conversion code. Something like this should work (found on another SO post):
public static String toHexString(byte bytes[]) {
if (bytes == null) {
return null;
}
StringBuffer sb = new StringBuffer();
for (int iter = 0; iter < bytes.length; iter++) {
byte high = (byte) ( (bytes[iter] & 0xf0) >> 4);
byte low = (byte) (bytes[iter] & 0x0f);
sb.append(nibble2char(high));
sb.append(nibble2char(low));
}
return sb.toString();
}
private static char nibble2char(byte b) {
byte nibble = (byte) (b & 0x0f);
if (nibble < 10) {
return (char) ('0' + nibble);
}
return (char) ('a' + nibble - 10);
}
byte[] deviceaddress = info.getDeviceAddress();
String _url = ByteArrayUtilities.byteArrayToHex(deviceaddress)
Work for me.
Enjoy.