views:

2545

answers:

5

Hi, fairly new iPhone developer here. Building an app to send RS232 commands to a device expecting them over a TCP/IP socket connection. I've got the comms part down, and can send ASCII commands fine. It's the hex code commands I'm having trouble with.

So lets say I have the following hex data to send (in this format):

\x1C\x02d\x00\x00\x00\xFF\x7F

How do I convert this into an NSData object, which my send method expects?

Obviously this does not work for this hex data (but does for standard ascii commands):

NSString *commandascii;
NSData *commandToSend;
commandascii = @"\x1C\x02d\x00\x00\x00\xFF\x7F";
commandToSend = [commandascii dataUsingEncoding:NSStringEncoding];

For a start, some of the \x hex codes are escape characters, and I get an "input conversion stopped..." warning when compiling in XCode. And NSStringEncoding obviously isn't right for this hex string either.

So the first problem is how to store this hex string I guess, then how to convert to NSData.

Any ideas?

A: 

Hex data is just bytes in memory, you think of it as a string because that's how you see it but they could represent anything. Try: (typed in the browser, may contain errors)

NSMutableData *hexData = [[NSMutableData alloc] init];

[hexData appendBytes: 0x1C];
[hexData appendBytes: 0x02D];

etc...

Bruce Johnson
This looks more like what I'm after, thanks Bruce. Doesn't quite work though, after fixing up the syntax (should be appendbytes: length:) I get a "warning: passing argument 1 of 'appendBytes:length:' makes pointer from integer without a cast"Any ideas?
Max Clarke
`appendBytes:length:` expects a *pointer* to the bytes as well as the number of bytes you're appending.
dreamlax
A: 

Here's an example decoder implemented on a category on NSString.

#import <stdio.h>
#import <stdlib.h>
#import <string.h>

unsigned char strToChar (char a, char b)
{
    char encoder[3] = {'\0','\0','\0'};
    encoder[0] = a;
    encoder[1] = b;
    return (char) strtol(encoder,NULL,16);
}

@interface NSString (NSStringExtensions)
- (NSData *) decodeFromHexidecimal;
@end

@implementation NSString (NSStringExtensions)

- (NSData *) decodeFromHexidecimal;
{
    const char * bytes = [self cStringUsingEncoding: NSUTF8StringEncoding];
    NSUInteger length = strlen(bytes);
    unsigned char * r = (unsigned char *) malloc(length / 2 + 1);
    unsigned char * index = r;

    while ((*bytes) && (*(bytes +1))) {
        *index = strToChar(*bytes, *(bytes +1));
        index++;
        bytes+=2;
    }
    *index = '\0';

    NSData * result = [NSData dataWithBytes: r length: length / 2];
    free(r);

    return result;
}

@end
xyzzycoder
Thanks xyzzy, though this doesn't compile - it has issues with safeMalloc, strToChar and safeStrLen. Do I need to include/import something for these functions to work?
Max Clarke
Ah, right. You can replace these calls w/ malloc and strlen. I'll update the response.
xyzzycoder
Should compile now.
xyzzycoder
+1  A: 
dreamlax
Woah, that's ugly. Sorry if I have blinded anyone with that source code. It kinda looked ugly as I was writing it but decided to finish it anyway.
dreamlax
Also, completely untested.
dreamlax
A: 

If I want to hard-code the bytes, I do something like this:

enum { numCommandBytes = 8 };
static const unsigned char commandBytes[numCommandBytes] = { 0x1c, 0x02, 'd', 0x0, 0x0, 0x0, 0xff, 0x7f };

If you're obtaining these backslash-escaped bytes at run time, try the strunvis function.

Obviously this does not work for this hex data (but does for standard ascii commands):

NSString *commandascii;
NSData *commandToSend;
commandascii = @"\x1C\x02d\x00\x00\x00\xFF\x7F";
commandToSend = [commandascii dataUsingEncoding:NSStringEncoding];

For a start, some of the \x hex codes are escape characters, and I get an "input conversion stopped..." warning when compiling in XCode. And NSStringEncoding obviously isn't right for this hex string either.

First, it's Xcode, with a lowercase c.

Second, NSStringEncoding is a type, not an encoding identifier. That code shouldn't compile at all.

More to the point, backslash-escaping is not an encoding; in fact, it's largely independent of encoding. The backslash and 'x' are characters, not bytes, which means that they must be encoded to (and decoded from) bytes, which is the job of an encoding.

Peter Hosey
+1  A: 

Code for hex in NSStrings like "00 05 22 1C EA 01 00 FF". 'command' is the hex NSString.

command = [command stringByReplacingOccurrencesOfString:@" " withString:@""];
NSMutableData *commandToSend= [[NSMutableData alloc] init];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
int i;
for (i=0; i < 8; i++) {
    byte_chars[0] = [command characterAtIndex:i*2];
    byte_chars[1] = [command characterAtIndex:i*2+1];
    whole_byte = strtol(byte_chars, NULL, 16);
    [commandToSend appendBytes:&whole_byte length:1]; 
}
NSLog(@"%@", commandToSend);
Max Clarke