swift - corebluetooth writing 2 bytes - arrays

I getting a text input and writing it to a ble device. I don't have an issue for 1 Byte of data but I could not covert the text input value to 2 bytes and send it.
How can I convert a value like 3400 to 2 bytes of UInt8 array and what should I for values below 255?
For 1 byte I use:
let myInt = Int(textField.text)
let value: [UInt8] = [UInt8(myInt)]
self.bluetoothManager.writeValue(data: Data(bytes: value), forCharacteristic: myChar!, type: .withResponse)
I tried to convert like this but I can't send String with .writeValue:
https://stackoverflow.com/a/36967037/4704055
let d1 = 21
let b1 = String(d1, radix: 2)
print(b1) // "10101"

You probably want to convert the string to a 16-bit integer, then
convert the integer to data (compare round trip Swift number types to/from Data), and finally write the data to the device:
guard var value = Int16(textField.text) else {
// ... invalid number ...
}
// value = value.bigEndian (if big-endian is expected by the device)
let data = Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
self.bluetoothManager.writeValue(data: data, ...)

Related

How Can I convert byte array to String in Swift

I have a json as below. I need to convert the image to a byte array and post it as a String.
I can convert the image to byte array but how can I convert it to String?
I am getting an error while converting byte array to String.
Error:
"not a valid UTF-8 sequence"
JSON:
"photo1": "[255,216,255,224,0,16,74,70,73, ..... ,]"
Image Data to Byte Array:
func getArrayOfBytesFromImage(imageData:NSData) -> Array<UInt8> {
// the number of elements:
let count = imageData.length / MemoryLayout<Int8>.size
// create array of appropriate length:
var bytes = [UInt8](repeating: 0, count: count)
// copy bytes into array
imageData.getBytes(&bytes, length:count * MemoryLayout<Int8>.size)
var byteArray:Array = Array<UInt8>()
for i in 0 ..< count {
byteArray.append(bytes[i])
}
return byteArray
}
Using getArrayOfBytesFromImage Function:
if let string = String(bytes: getArrayOfBytesFromImage(imageData: imageData), encoding: .utf8) {
print(string)
} else {
print("not a valid UTF-8 sequence")
}
Those are not UTF-8 bytes, so don't say encoding: .utf8. Those bytes do not form a string, so you should not use String.init(bytes:encoding:). You should get the value of those bytes, and get their description one way or another (e.g. by string interpolation).
You don't even need a byte array here. Just go straight to strings, since that's what you're after.
let imageData = Data([1, 2, 3, 4, 5]) // for example
let string = "[\(imageData.map { "\($0)" }.joined(separator: ","))]"
print(string) // prints [1,2,3,4,5]

How do I transform a two-dimensional array into the ByteBuffer type required by FTLite?

In python, I got a applies to 113 * 113 array model, and it has been put into tflite, AnZhuoDuan I have got the 2 d array of 113 * 113, I want to know what I need to do to get the 2 d array to tflite model, I looked at the others write tflite run function of the model, using the bytebuffer data type, want to ask how to operate?
My two-dimensional array is a double, positive and negative
I will first write how I transformed my bitmaps to bytebuffer and then I will show a workaround to your inputs
Function to transform bitmaps to bytebuffer:
private fun convertBitmapToByteBuffer(bitmap: Bitmap): ByteBuffer {
// Pre-process the input: convert a Bitmap instance to a ByteBuffer instance
// containing the pixel values of all pixels in the input image.
// We use ByteBuffer because it is faster than a Kotlin native float
multidimensional array.
val byteBuffer = ByteBuffer.allocateDirect(modelInputSize)
byteBuffer.order(ByteOrder.nativeOrder())
val pixels = IntArray(inputImageWidth * inputImageHeight)
bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
for (pixelValue in pixels) {
val r = (pixelValue shr 16 and 0xFF)
val g = (pixelValue shr 8 and 0xFF)
val b = (pixelValue and 0xFF)
// Normalize pixel value to [0..1].
val normalizedPixelValue = (r + g + b) / 255.0F
byteBuffer.putFloat(normalizedPixelValue)
}
return byteBuffer
}
where modelInputSize is:
modelInputSize = FLOAT_TYPE_SIZE * inputImageWidth *
inputImageHeight * PIXEL_SIZE
//modelInputSize indicates how many bytes of memory we should allocate to store the input for our TensorFlow Lite model.
//FLOAT_TYPE_SIZE indicates how many bytes our input data type will require. We use float32, so it is 4 bytes.
//PIXEL_SIZE indicates how many color channels there are in each pixel. Our input image is a colored image, so we have 3 color channel.
//inputImageWidth and inputImageHeight are the width and height usually 224x224 that most pretrained models use.
So from above code if we want to transform the array to bytebuffer we have to use something like below:
private fun convertArrayToByteBuffer(twoDArray: FloatArray?): ByteBuffer {
// We use ByteBuffer because it is faster than a Kotlin native float
multidimensional array.
// FLOAT_TYPE_SIZE * WIDTH * HEIGHT
val byteBuffer = ByteBuffer.allocateDirect(4 * 113 * 113)
byteBuffer.order(ByteOrder.nativeOrder())
if (twoDArray != null) {
// Use [0] if this is 2D array or without [0] if it is one dimension array
for (input in twoDArray[0]) {
byteBuffer.putFloat(input)
}
}
return byteBuffer
}
You should also check if your array is double or float and transform accordingly to apply to above code for FLOAT_TYPE_SIZE (in my example value for float is 4).
Check project file with 2Darray of length 40
and project file with colored bitmap of 224*224 dimensions.
Good luck!

Typecast String to ByteArray in kotlin

I have variable in String format in kotlin:
var a ="[B#53c1c428"
I want to change it's datatype from String to ByteArray i.e typecast it to ByteArray, somewhat like:
var b: ByteArray = a
I also tried:
var b = a as ByteArray, but this throws an Exception
If I do:
var b = a.toByteArray(), I get output like:
[B#3aea9e4
But I want [B#53c1c428 as ByteArray.
Any suggestions?
Just to clarify:
[B#53c1c428 is the hexadecimal hash code of that object with a B[# prefix. The string "[B#53c1c428" itself does not contain the data needed to reconstruct the ByteArray.
Consider this:
val str = "Test"
val byteArray = str.toByteArray()
println(Integer.toHexString(byteArray.hashCode())) // 1f32e575
println(byteArray) // [B# + hash code as hexadecimal representation
val str2 = "This is a really long text and no 8 digit hex number in this world could encode it."
val byteArray2 = str2.toByteArray()
println(Integer.toHexString(byteArray2.hashCode())) // 279f2327
println(byteArray2) // [B# + hash code as hexadecimal representation
toByteArray() already gives you a ByteArray. If you want to print the single digits as integers do it like this:
val str = "Test"
println(str.toByteArray().joinToString(" "){ "$it" })
Output:
84 101 115 116
This output would be enough to fully restore the ByteArray, because it contains all necessary information.

Float Array to Byte Array and Vise Versa

My ultimate goal is to be able to send an array of floats over a UDP socket, but for now I'm just trying to get a few things working in python3.
The code below works just fine:
import struct
fake_data = struct.pack('f', 5.38976)
print(fake_data)
data1 = struct.unpack('f', fake_data)
print(data1)
Output:
b'\xeax\xac#'
(5.3897600173950195,)
But when I try this I get:
electrode_data = [1.22, -2.33, 3.44]
for i in range(3):
data = struct.pack('!d', electrode_data[i]) # float -> bytes
print(data[i])
x = struct.unpack('!d', data[i]) # bytes -> float
print(x[i])
Output:
63
Traceback (most recent call last):
File "cbutton.py", line 18, in <module>
x = struct.unpack('!d', data[i]) # bytes -> float
TypeError: a bytes-like object is required, not 'int'
How can I turn a float array to byte array and vise versa. The reason I'm tryin to accomplish this is because the first code allows me to send float data from a client to server (one by one) using a UDP socket. My ultimate goal is to do this with an array so I can plot the values using matplotlib.
You're only packing a single float here. But then you're trying to pass the first byte of the resulting buffer (which was implicitly converted to int) to unpack. You need to give it the entire buffer. Also, to do this in a more general way, you want to first encode the number of items in your array as an integer.
import struct
electrode_data = [1.22, -2.33, 3.44]
# First encode the number of data items, then the actual items
data = struct.pack("!I" + "d" * len(electrode_data), len(electrode_data), *electrode_data)
print(data)
# Pull the number of encoded items (Note a tuple is returned!)
elen = struct.unpack_from("!I", data)[0]
# Now pull the array of items
e2 = struct.unpack_from("!" + "d" * elen, data, 4)
print(e2)
(The *electrode_data means to flatten the list: it's the same as electrode_data[0], electrode_data[1]...)
If you really only want to do one at a time:
for elem in electrode_data:
data = struct.pack("!d", elem)
print(data)
# Again note that unpack *always* returns a tuple (even if only one member)
d2 = struct.unpack("!d", data)[0]
print(d2)

In Swift, how do I read an existing binary file into an array?

As part of my projects, I have a binary data file consisting of a large series of 32 bit integers that one of my classes reads in on initialization. In my C++ library, I read it in with the following initializer:
Evaluator::Evaluator() {
m_HandNumbers.resize(32487834);
ifstream inputReader;
inputReader.open("/path/to/file/7CHands.dat", ios::binary);
int inputValue;
for (int x = 0; x < 32487834; ++x) {
inputReader.read((char *) &inputValue, sizeof (inputValue));
m_HandNumbers[x] = inputValue;
}
inputReader.close();
};
and in porting to Swift, I decided to read the entire file into one buffer (it's only about 130 MB) and then copy the bytes out of the buffer.
So, I've done the following:
public init() {
var inputStream = NSInputStream(fileAtPath: "/path/to/file/7CHands.dat")!
var inputBuffer = [UInt8](count: 32478734 * 4, repeatedValue: 0)
inputStream.open()
inputStream.read(&inputBuffer, maxLength: inputBuffer.count)
inputStream.close()
}
and it works fine in that when I debug it, I can see inputBuffer contains the same array of bytes that my hex editor says it should. Now, I'd like to get that data out of there effectively. I know it's stored in.. whatever format you call it where the least significant bytes are first (i.e. the number 0x00011D4A is represented as '4A1D 0100' in the file). I'm tempted to just iterate through it manually and calculate the byte values by hand, but I'm wondering if there's a quick way I can pass an array of [Int32] and have it read those bytes in. I tried using NSData, such as with:
let data = NSData(bytes: handNumbers, length: handNumbers.count * sizeof(Int32))
data.getBytes(&inputBuffer, length: inputBuffer.count)
but that didn't seem to load the values (all the values were still zero). Can anyone please help me convert this byte array into some Int32 values? Better yet would be to convert them to Int (i.e. 64 bit integer) just to keep my variable sizes the same across the project.
Not sure about your endian-ness, but I use the following function. The difference from your code is using NSRanges of the actual required type, rather than lengths of bytes. This routine reads one value at a time (it's for ESRI files whose contents vary field by field), but should be easily adaptable.
func getBigIntFromData(data: NSData, offset: Int) -> Int {
var rng = NSRange(location: offset, length: 4)
var i = [UInt32](count: 1, repeatedValue:0)
data.getBytes(&i, range: rng)
return Int(i[0].bigEndian)// return Int(i[0]) for littleEndian
}
Grimxn provided the backbone of the solution to my problem, which showed me how to read sections of the buffer into an array; he then showed me a way to read the entire buffer in all at once. Rather than convert all of the items of the array needlessly to Int, I simply read the array into the buffer as UInt32 and did the casting to Int in the function that accesses that array.
For now, since I don't have my utility class defined yet, I integrated Grimxn's code directly into my initializer. The class initializer now looks like this:
public class Evaluator {
let HandNumberArraySize = 32487834
var handNumbers: [Int32]
public init() {
let data = NSData(contentsOfFile: "/path/to/file/7CHands.dat")!
var dataRange = NSRange(location: 0, length: HandNumberArraySize * 4)
handNumbers = [Int32](count: HandNumberArraySize, repeatedValue: 0)
data.getBytes(&handNumbers, range: dataRange)
println("Evaluator loaded successfully")
}
...
}
... and the function that references them is now:
public func cardVectorToHandNumber(#cards: [Int], numberToUse: Int) -> Int {
var output: Int
output = Int(handNumbers[53 + cards[0] + 1])
for i in 1 ..< numberToUse {
output = Int(handNumbers[output + cards[i] + 1])
}
return Int(handNumbers[output])
}
Thanks to Grimxn and thanks once again to StackOverflow for helping me in a very real way!

Resources