Marc-Oliver
Marc-Oliver

Reputation: 55

IOS Swift TI SensorTag2 data conversion

I write an app for iOS using the TI SensorTag2. Right now i'm stuck with the conversion of data i read over bluetooth to Float for the app.

Following Code is from the released source code of TI for an Objective C App.

-(NSString *) calcValue:(NSData *) value {

char vals[value.length];
[value getBytes:vals length:value.length];

Point3D gyroPoint;

gyroPoint.x = ((float)((int16_t)((vals[0] & 0xff) | (((int16_t)vals[1] << 8) & 0xff00)))/ (float) 32768) * 255 * 1;
gyroPoint.y = ((float)((int16_t)((vals[2] & 0xff) | (((int16_t)vals[3] << 8) & 0xff00)))/ (float) 32768) * 255 * 1;
gyroPoint.z = ((float)((int16_t)((vals[4] & 0xff) | (((int16_t)vals[5] << 8) & 0xff00)))/ (float) 32768) * 255 * 1;

self.gyro = gyroPoint;

Point3D accPoint;

accPoint.x = (((float)((int16_t)((vals[6] & 0xff) | (((int16_t)vals[7] << 8) & 0xff00)))/ (float) 32768) * 8) * 1;
accPoint.y = (((float)((int16_t)((vals[8] & 0xff) | (((int16_t)vals[9] << 8) & 0xff00))) / (float) 32768) * 8) * 1;
accPoint.z = (((float)((int16_t)((vals[10] & 0xff) | (((int16_t)vals[11] << 8) & 0xff00)))/ (float) 32768) * 8) * 1;

self.acc = accPoint;

Point3D magPoint;
magPoint.x = (((float)((int16_t)((vals[12] & 0xff) | (((int16_t)vals[13] << 8) & 0xff00))) / (float) 32768) * 4912);
magPoint.y = (((float)((int16_t)((vals[14] & 0xff) | (((int16_t)vals[15] << 8) & 0xff00))) / (float) 32768) * 4912);
magPoint.z = (((float)((int16_t)((vals[16] & 0xff) | (((int16_t)vals[17] << 8) & 0xff00))) / (float) 32768) * 4912);


self.mag = magPoint;


return [NSString stringWithFormat:@"ACC : X: %+6.1f, Y: %+6.1f, Z: %+6.1f\nMAG : X: %+6.1f, Y: %+6.1f, Z: %+6.1f\nGYR : X: %+6.1f, Y: %+6.1f, Z: %+6.1f",self.acc.x,self.acc.y,self.acc.z,self.mag.x,self.mag.y,self.mag.z,self.gyro.x,self.gyro.y,self.gyro.z];
}

When i try to convert this code to Swift, i get an error "Integer literal '65280' overflows when stored into Int16

let xF: Float = ((Float((Int16(bytes[6]) & 0xff) | ((Int16(bytes[7]) << 8) & 0xff00)) / Float(32768)) * 8) * 1

As i understand that, it combines the 2 Int8 variables into a single Int16 and it should work, i just don't find where i made the error. The part with "& 0xff00" is marked and when i understand it right this is here so only the first 8 bits contain 1's , the rest is 0's

I had it working with code from the android app for SensorTag2, but that code crashes the app from time to time, when i do also read data from gyroscope, so i wanted to use that iOS Code

let x = (Int16(bytes[7]) << 8) + Int16(bytes[6])
let xF = Float(x) / (32768.0 / 8.0)

Maybe somebody here can point me in the right direction to solve my problem

Upvotes: 0

Views: 168

Answers (2)

Marc-Oliver
Marc-Oliver

Reputation: 55

I couldn't use the UInt solution, because i get the data as raw bytes that are encoded as signed int with 16bit. In ObjectiveC they are read into a char-array, that i converted to Int8

But i found another solution and now i just read the bytes into a Int16 array, that way two following bytes will be treated as a single Int16, like the ObjectiveC code made them already.

var bytes: [Int16] = [Int16](count: data.length, repeatedValue: 0)
let dataLength = data.length
data.getBytes(&bytes, length: dataLength * sizeof(Int16))

That way i don't need the bitshifting and bit operations.

now i have an array of 9 Int16 values, instead of 16 Int8, that i had to convert to Int16. Also a test with the TI SensorTag App resulted in the same numbers

Upvotes: 0

OOPer
OOPer

Reputation: 47876

One bad thing in this line:

let xF: Float = ((Float((Int16(bytes[6]) & 0xff) | ((Int16(bytes[7]) << 8) & 0xff00)) / Float(32768)) * 8) * 1

is this: ((Int16(bytes[7]) << 8) & 0xff00).

You know Int16 can represent numbers -32768...32767, and the value of 0xff00 is 65280. As the error message is saying, it is too large for Int16.

(Remember Swift does no implicit conversions for numeric types.)

With making bytes as unsigned:

let bytes = UnsafePointer<UInt8>(data.bytes)

You have no need to use &.

But you need to pass a signed value to Float.init, so your code needs to be something like this:

let xF: Float = ((Float(Int16(bitPattern: UInt16(bytes[6]) | (UInt16(bytes[7]) << 8))) / Float(32768)) * 8) * 1

(Or else, negative values in bytes make your app crash.)

Upvotes: 1

Related Questions