How to Convert Float to NSData Bytes - ios

Using the following code, I am attempting to convert three float values into a single NSData object, which I can then transmit over a serial port.
float kP = [[self.kPTextField stringValue] floatValue];
float kI = [[self.kITextField stringValue] floatValue];
float kD = [[self.kDTextField stringValue] floatValue];
float combined[] = {kP, kI, kD};
NSData *dataPackage = [NSData dataWithBytes:&combined length:sizeof(combined)];
[self.serialPort sendData:dataPackage];
The problem is that it doesn't seem to work very well. Whenever I use the "sizeof()" C function, it tells me that the "dataPackage" is only 8 bytes, even though 3 float values should total 12 bytes. I am receiving the data with an Arduino. It sees the bytes coming in, but they aren't legible at all. I don't think it's a problem on the Arduino side of things (but who knows?).
Any help would be appreciated! I'm not a CS major, just a bio major, and I've never learned this stuff in a formal way so I am sorry if my question is ridiculous. I've spent several hours searching the net about this problem and haven't found anything that helped.
EDIT: It turns out this code was completely correct. I made a simple mistake on the arduino side of things by using a struct instead of a union to take the bytes and convert them back into floats.
For others who may be in a similar predicament, a successful way to convert floats from bytes coming out of the serial port is the following:
(at top of implementation file)
union {
float pidVals[3];
byte bytes[12];
} pidUnion;
(inside loop)
if (Serial.available() > 11) {
for (int i = 0; i < 12; i++) {
pidUnion.bytes[i] = Serial.read();
}
}
//Now, you can get access to all three floats of data using pidUnion.pidVals[0], pidUnion.pidVals[1], etc.
This probably isn't the best or most reliable way to transmit data. There is no error-correcting mechanism or packet structure. But it does work in a pinch. I imagine you would probably want to find a way to create a packet of data along with a hash byte to make sure all of the data is correct on the other side, this code doesn't have any of that though.

There are multiple problems with your code.
First, you don't want to use stringValue on a text field. You want the text property, which is a string.
So the first line should read like this:
float kP = [self.kPTextField.text floatValue];
Second, in C, an array of things is a pointer. The data type of
float combined[]
and
float *combined
is identical. Both are "pointer to float".
So this code:
NSData *dataPackage = [NSData dataWithBytes:&combined
length: sizeof(combined)];
Should not have an ampersand in front of combined. It should read:
NSData *dataPackage = [NSData dataWithBytes:combined
length: sizeof(combined)];
Third, what matters is sizeof(combined), not sizeof(dataPackage).
The expression sizeof(dataPackage) will tell you the size of the variable dataPackage, which is a pointer to an NSData object. You must be running on a 64 bit device, where pointers are 8 bytes.
To test the length of the data in your NSData object, you want to ask it with the length property:
NSLog(#"sizeof(combined) = %d", sizeof(combined)";
NSData *dataPackage = [NSData dataWithBytes:&combined
length: sizeof(combined)];
NSLog(#"dataPackage.length = %d", dataPackage.length";
Both log statements should display values of 12.

Related

In iOS, how can I get the address of self as a string?

If it matters I need this particularly when self is a UIView subclass. By way of example to clarify my question, the following stmt:
NSLog(#"self: %#", self);
gives the following output:
<RCLDataView: 0x10971a0b0; frame = (0 0; 0 0); transform = [0, 0, 0, 0, 0, 0]; alpha = 0; opaque = NO; layer = (null)>
I want just that address (0x10971a0b0) without the rest of the text. I suppose I can (somehow) capture that full string and (somehow) extract the address with NSString methods. But that seems really ugly. There is probably a way to get the address directly, since NSLog can get it.
NSString *addressString = [NSString stringWithFormat:#"%p", yourString];
unsigned long long address = 0;
NSScanner *scanner = [NSScanner scannerWithString:addressString];
[scanner scanHexLongLong:&address];
NSLog(#"%llx", address); //Prints the address
The first line gets the pointer address and puts it into an NSString.
The next line instantiates an unsigned long long to hold the hex value of the pointer. The pointer address representation is 64 bits I think so we need a 64 bit value to hold it. I know an int is not large enough but a long long works. Alternatively you could use a uint64_t depending on your architecture. The next two lines are to extract the hex value and store it in our long long. The NSScanner method is the only way I know to get a hex value from an NSString so I just used that. The last line of course is to print the value to make sure it's correct. You can check if it's correct by also printing the addressString.

Inconsistent values with NSNumber to double multiplication

I'm currently parsing NSString values to NSNumbers and then adding them into a NSMutableArray called operands in an object called "data" like so:
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * myNumber = [f numberFromString:*operandString];
[data.operands addObject:myNumber];
I then retrieve those numbers, perform some math on them, then update the array:
double x = [[data.operands objectAtIndex: i]doubleValue];
double y = [[data.operands objectAtIndex: i + 1]doubleValue];
double answer = x * y;
[data.operands replaceObjectAtIndex:(i) withObject:[NSNumber numberWithDouble:answer]];
When I get the answer, everything looks fine eg: ( 3.33 * 5 = 16.65)
BUT, when I look in the debugger I'm seeing some crazy values for x and answer, such as:
x = 3.3300000000000001
answer = 16.649999999999999
Why is this happening? Am I loosing some precision with parsing these back and fourth? Is it how I've used the NSNumberFormatter to parse the string?
The reason I'm in trouble with this is because I'm trying to ensure there's no double overflow errors so I'm using this simple test to check the integrity:
if (answer / y != x){
//THROW OVERFLOW ERROR
}
With the above crazy numbers this is always inconsistent. When I NSLog the answer it comes out fine:
NSLog (#"%g", [[data.operands objectAtIndex:i]doubleValue]]);
Same for
NSLog (#"%f", [[data.operands objectAtIndex:i]doubleValue]]);
You are not losing any precision that you need to worry about. Those are the correct values. There are only about 2^60 different double numbers, that finite set has to try to approximately cover the infinite 'number of numbers' in the range that doubles cover.
In other words, there are no exact answers in computer land and your
if (answer / y != x){
//THROW OVERFLOW ERROR
}
Will not work. Or it may work much of the time, but fail if you push it. Instead you need to acknowledge the limited precision (which is pretty high precision) of doubles:
//Don't waste time worrying like this...
if (fabs(answer / y - x) > 1e-12*fabs(answer)){
//Not correct or useful thing to check don't use this - i did not check
}
// let the math package handle it:
if (isnan(answer)){
// we gots problems
}
if (!isnormal(answer)){
// we gots some other problems
}
Also don't forget that 10^300 is a very large number, doubles work pretty well. To use 32 bit floats you need to pay much more attention to order of execution, etc.
NSLog is likely outputting with fewer decimals of precision, and rounds to the nearest thing, so the answers look better.

break a 32bit integer, and use the second half 16bit to form an int

I am making an app that downloads a 32bit integer from server, and use the first 16bit and second 16bit for different purposes...
I am responsible for the second 16bit, which should be used to form an int, I know I should use bitwise operation to do this, but unable to achieve, below is the code that I am using, please give me more information.
//CID is a 32bit integer, in nslog it shows as 68913219 - its different for every user
Byte lowByte = (CID>>16)&0xFF; //the 3rd byte
Byte highByte = (CID>>24)&0xFF; //the 4th byte
uint16_t value = lowByte & highByte; //combine, but the result is 0.
uint16_t value = lowByte & highByte; //combine, but the result is 0.
This is not how you combine two bytes into a single uint16_t: you are ANDing them in place, while you need to shift the high byte, and OR it with the low byte:
uint16_t value = lowByte | (((uint16_t)highByte) << 8);
However, this is suboptimal in terms of readability: if you start with a 32-bit integer, and you need to cut out the upper 16 bits, you could simply shift by 16, and mask with 0xFFFF - i.e. the same way that you cut out the third byte, but with a 16-bit mask.
You shouldn't need to do this byte-by-byte. Try this:
//CID is a 32bit integer, in nslog it shows as 68913219 - its different for every user
uint16_t value = (CID>>16)&0xffff;
You can also use NSData.
If you have this integer:
int i = 1;
You can use :
NSData *data = [NSData dataWithBytes: &i length: sizeof(i)];
and then, to get the second 16bit do:
int16_t recover;
[data getBytes: &recover range: NSMakeRange(2, 2)]
Then you have your 16 bits on "recover".
Maybe this way is not so efficient like bit operation, but it is clearer.
:D

Changing the number of significant digits for a string format with %g

I'm building an app that allows the user to perform some calculations except the calculations result in numbers with lots of decimal digits. It's fine for me to see that kind of precision but I want to let the users be able to choose how many significant digits they want shown. I'm creating a result string using a double and using the %g format shown here:
NSString *resultString = [[NSString alloc] initWithFormat:#"%.14g", result];
I have created a stepper that the users can interact with and storing the number they have chosen in another double. My question is, how can insert that double where the 14 is to change the number of significant digits? Or is this even possible? Please comment if you need clarification.
Any field width or precision in a format can be replaced by an * to indicate a dynamic value which is supplied by an int argument.
For example:
double d = 1.0/7;
for(int i = 4; i < 12; i++)
NSLog(#"%.*g", i, d);
Outputs:
0.1429
0.14286
0.142857
0.1428571
0.14285714
0.142857143
0.1428571429
0.14285714286

How do I count the occurrences of a byte in NSData on an iphone?

I'm new to iOS and Objective C and I'm having trouble figuring out how to use NSData correctly.
I want to count the number of new lines in my data.
// filedata is pulled from a URL asyn
NSInteger knt = 0;
NSInteger len = filedata.length;
const char *pointer = [filedata bytes];
for (NSInteger spot = 0; spot < len; spot++) {
if (pointer[spot] == 10) { // 10 is new line
knt++;
}
}
The count is off, is there a better way to do this?
Try checking for carriage returns as well (ascii 13 http://www.asciitable.com/).
Make sure the newlines are TRULY newlines (ascii 10). You can try this by opening up your data in a hex editor. Hex editors generally will show you text in a right pane, bytes in a middle pain, and addresses of the bytes in a left pane.
If this doesn't resolve your question, please consider posting sample data.

Resources