Issues bit shifting UInt8 after converting to from Objective C to Swift - ios

I am streaming video to a UIImage in my app using NSURLConnection. Part of my code, that works in Objective C I am having trouble converting to Swift:
func connection(connection: NSURLConnection, didReceiveData data: NSData) {
//...other code
UInt32 sizeOfJPEG_1; //same type as was in Objective C
var payloadsize = [UInt8](count: 4, repeatedValue: 0x00) //was uint8_t in Objective C
data.getBytes(&payloadsize[1], range: NSMakeRange(12, 3))
payloadsize[0] = 0
sizeOfJPEG_1 = (payloadsize[1] << 16) + (payloadsize[2] << 8) + payloadsize[3]//here is the problem
//UInt32(sizeOfJPEG_1 = (payloadsize[1] << 16) + (payloadsize[2] << 8) + payloadsize[3]) //the way I am currently dealing with converting my shifting and additions to the correct sizeOfJPEG_1 UInt32 argument type
//..more code
}
I am having two issues here:
I am not sure of the best way to convert the payloadsize UInt8 bitshifting and additions to the argument UInt32
More importantly, possibly, to figure out first, is the runtime error I get shifting a UInt8 << 16, in objective C the type was uint8_t, I do not know if that was a legal operation in Objective C with a tyupe of uint8_t and just is not in Swift with a type of UInt8
I am getting an overflow error because I am left shifting a UInt8 << 16 as well as UInt8 << 8:
fatal error: shift amount is larger than type size in bits
I think I understand Objective C will quietly shift a uint8_t << 16 without crashing but I do not know how to calculate this, what is the result of uint8_t << 16, wouldn't it be 0? (uint8_t is defined as unsigned char)

Unlike (Objective-)C, Swift does not promote smaller integer types
to int or unsigned int, so you have to do that explicitly (before
shifting the data):
let sizeOfJPEG_1 = UInt32(payloadsize[1]) << 16 + UInt32(payloadsize[2]) << 8 + UInt32(payloadsize[3])

Related

How to map an UnsafePointer to another type?

I'm trying to convert an UnsafePointer<UInt16> to an UnsafePointer<Float> and so far I ended with this solution:
let bufferSize = 1024
let buffer: UnsafePointer<UInt16> = ....
let tmp = UnsafeBufferPointer(start: buffer, count: bufferSize).map(Float.init)
let converted: UnsafePointer<Float> = UnsafePointer(tmp)
It works but I have the feeling it's not an efficient way since I'm creating an intermediate Array... Is there a better way to do that ?
You can use withMemoryRebound to convert a pointer from one type to another:
buffer.withMemoryRebound(to: Float.self, capacity: 1024) { converted -> Void in
// use `converted` here
}
But be careful that MemoryLayout<Float>.size is 4 (i.e. 32 bits) and MemoryLayout<UInt16> is obviously 2 (i.e.. 16 bits), so the bufferSize of your Float will be half of that of your UInt16 buffer.

Getting wrong output while executing sizeof(char)

My question is sizeof(char) is 1 byte but while executing below code why I am getting wrong output. Kindly help me. Thank you
typedef struct {
int x;
int y;
char a;
}Point2D;
main() {
Point2D *myPoint=malloc(sizeof(Point2D));
NSLog(#"sizeof(Point2D): %zu", sizeof(Point2D));
}
Output: sizeof(Point2D) : 12 //But it should return 9 [int + int + char / 4 + 4 + 1]
Note: While running char individually , I am getting correct output
Example:
typedef struct {
char a;
char b;
}Point2D;
main() {
Point2D *myPoint=malloc(sizeof(Point2D));
NSLog(#"sizeof(Point2D): %zu", sizeof(char));
}
output: sizeof(char) : 2
You are not getting "wrong" output, when an (Objective-)C compiler lays out a struct it is allowed to use internal padding so that the fields start at the best memory alignment for their type.
If you need the size of a struct to be exactly the sum of its field sizes you can use __attribute__((__packed__)). E.g:
typedef struct
{
int x;
int y;
char a;
} __attribute__((__packed__)) Point2D;
has a size of 9. However access to the fields may be slower due to the CPU having to deal with values not having optimal storage alignment.

Zero fill right shift in swift

(byte) ((val & 0xff00) >>> 8);
This is the Java code. I want to convert this code to Swift. But there is no >>> operator in swift. How can I use Zero fill right shift in Swift?
If you use the truncatingBitPattern initializer of integer types
to extract a byte then you don't have to mask the value and it does not matter if the shift operator fills with zeros or ones (which depends on whether the source
type is unsigned or signed).
Choose Int8 or UInt8 depending
on whether the byte should be interpreted as a signed or
unsigned number.
let value = 0xABCD
let signedByte = Int8(truncatingBitPattern: value >> 8)
print(signedByte) // -85
let unsignedByte = UInt8(truncatingBitPattern: value >> 8)
print(unsignedByte) // 171
Operator >> in Swift is zero-fill (for unsigned integers):
The bit-shifting behavior for unsigned integers is as follows:
Existing bits are moved to the left or right by the requested number of places.
Any bits that are moved beyond the bounds of the integer’s storage are discarded.
Zeros are inserted in the spaces left behind after the original bits are moved to the left or right.
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-ID29
You don't need zero fill shift int this case because a byte is only 8-bits.
The code you have is the same as
(byte) (((val & 0xFF00) >> 8) & 0xFF)
or
(byte) ((val & 0xFF00) >> 8)
or
(byte) (val >> 8)
Zero-fill right shift operator doesn't exist in swift/objc, unfortunately. As an alternative / workaround:
// java
// let's say we want to zero-fill right shift 4 bits
int num = -333;
num >>>= 4; // num: 268435435
// objc
NSInteger num = -333;
num >>= 1;
if (num < 0) num ^= NSIntegerMin;
num >>= 3; // num: 268435435
// swift (assume we are dealing with 32 bit integer)
var num: Int32 = -333
num >>= 1
if num < 0 {
num ^= Int32.min
}
num >>= 3 // num: 268435435
Essentially get rid of the sign bit when negative.

Sending int data to BLE device

I have 4 distinct int values that I need to send to a BLE device (connection established OK).
I'll call the int values A,B,C,D for clarity. A and B range between 0-100, C has a range of 0-2000 and D has a range of 0-10000. All values are determined by user input.
I need to send these four values to the BLE device in quick succession, and package each of them differently: A and B (8 bits), C (16 bits) and D (32 bits). I'm unsure as to how to package the values correctly.
Below are three methods I've tried with varying degrees of success.
Convert int to data and send, e.g. for A (8 bit) int:
const unsigned char CHR = (float)A;
float size = sizeof(CHR);
NSData * aData = [NSData dataWithBytes:&CHR length:size];
[p writeValue:aData forCharacteristic:aCHAR type:CBCharacteristicWriteWithResponse];
Convert to string first, e.g. for (16 bit) C:
NSString * cString = [NSString stringWithFormat:#"%i",C];
NSData * cData = [cString dataUsingEncoding:NSUTF16StringEncoding];
[p writeValue:cData forCharacteristic:cCHAR type:CBCharacteristicWriteWithResponse];
Use uint, e.g. for (32 bit) D int:
uint32_t val = D;
float size = sizeof(val);
NSData * dData = [NSData dataWithBytes:(void*)&val length:size];
[p writeValue:valData forCharacteristic:dCHAR type:CBCharacteristicWriteWithResponse];
What am I doing wrong in the above, and how best to convert and send an int value to the device, allowing for the 3 formats required?
You need to know a little more information about the format your device expects:
Are the values signed or unsigned
Is the system little-endian or big-endian
Assuming that you want to use the little-endian format that iOS uses, you can just use dataWithBytes -
unsigned char a = 100
NSData *aData = [NSData dataWithBytes:&a length:sizeof(i)];
UInt16 c = 1000
NSData *cData = [NSData dataWithBytes:&c length:sizeof(c)];
Unit32 d = 10000
NSData *dData = [NSData dataWithBytes:&d length:sizeof(d)];
And then just write the NSData using writeValue:forCharacteristic:type:
If the device wants big-endian data then you will need to manipulate the bytes into the proper order. For this reason it is often easier just to send numeric values as ASCII strings and convert them back to numeric values on the receiving end, but this will depend on whether you have control over the format the device is expecting.

How to convert NSData to multiple type Ints

I obtain magnetometer trim register as get NSData() that looks as follows:
<00001a1a 4f56f202 00000000 1dfd421b>
I need to convert it to Int8, UInt8, Int16, UInt16 depending on which byte I access.
Sources from docs:
s8 dig_x1;/**< trim x1 data */
s8 dig_y1;/**< trim y1 data */
s8 dig_x2;/**< trim x2 data */
s8 dig_y2;/**< trim y2 data */
u16 dig_z1;/**< trim z1 data */
s16 dig_z2;/**< trim z2 data */
s16 dig_z3;/**< trim z3 data */
s16 dig_z4;/**< trim z4 data */
u8 dig_xy1;/**< trim xy1 data */
s8 dig_xy2;/**< trim xy2 data */
u16 dig_xyz1;/**< trim xyz1 data *
The main problem is how to access a selected byte in NSData to convert it manually either to Int8 or UIint16 etc?
Generally, how to approach such problem? Should look for a way to manually iterate over NSData and convert each value manualy as well?
You can convert data.bytes + offset to a pointer of the
appropriate type and then dereference the pointer:
let dig_x1 = UnsafePointer<Int8>(data.bytes).memory
let dig_y1 = UnsafePointer<Int8>(data.bytes + 1).memory
// ...
let dig_z1 = UnsafePointer<UInt16>(data.bytes + 4).memory
let dig_z2 = UnsafePointer<Int16>(data.bytes + 6).memory
// ...
(Note: Here it is assumed that all values in that binary blob are
property aligned for their type.)
The data is in little-endian byte order, which is also what all
current iOS platforms use. To be on the safe side, convert
the data to host byte order explicitly:
let dig_z1 = UInt16(littleEndian: UnsafePointer(data.bytes + 4).memory)
let dig_z2 = Int16(littleEndian: UnsafePointer(data.bytes + 6).memory)
// ...
An alternative is to define a C structure in the bridging header file
struct MagnetometerData {
int8_t dig_x1;
int8_t dig_y1;
int8_t dig_x2;
int8_t dig_y2;
uint16_t dig_z1;
int16_t dig_z2;
int16_t dig_z3;
int16_t dig_z4;
uint8_t dig_xy1;
int8_t dig_xy2;
uint16_t dig_xyz1;
} ;
and extract the data in one step:
var mdata = MagnetometerData()
data.getBytes(&mdata, length: sizeofValue(mdata))
This works (if there is no padding between the struct members)
because Swift preserves the layout of structures imported from C.
A possible Swift 3 implementation of the first approach is
let dig_x1 = ((data as NSData).bytes).load(as: Int8.self)
let dig_y1 = ((data as NSData).bytes + 1).load(as: Int8.self)
// ...
let dig_z1 = ((data as NSData).bytes + 4).load(as: UInt16.self)
let dig_z2 = ((data as NSData).bytes + 6).load(as: Int16.self)
// ...
Again it is assumed that all values are property aligned for their
type.

Resources