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)
Related
What is the Kotlin 1.5 command to convert a 16 bit integer to a Byte of length 2? Secondary problem is that outputstream needs a string at the end so it can convert with toByteArray()
# Original Python Code
...
i = int((2**16-1)*ratio) # 16 bit int
i.to_bytes(2, byteorder='big')
output = (i).to_bytes(2, byteorder='big')
# Kotlin Code so far
var i = ((2.0.pow(16) - 1) * ratio).toInt() // Convert to 16 bit Integer
print("16 bit Int: " + i)
output = .....
....
...
val outputStream: OutputStream = socket.getOutputStream()
outputStream.write(output.toByteArray()) // write requires ByteArray for some reason
It is simple math, so it is probably the best to calculate manually and define as an extension function:
fun Int.to2ByteArray() : ByteArray = byteArrayOf(toByte(), shr(8).toByte())
Then you can use it:
output = i.to2ByteArray()
outputStream.write(output)
Note, this function writes the integer in little-endian. If you need big-endian the just reverse the order of items in the array. You can also add some min/max checks if you need them.
Also, if you only need 16-bit values then you can consider using Short or UShort instead of Int. It doesn't change much regarding the memory usage, but it could be a cleaner approach - we could name our extension just toByArray() and we would not need min/max checks.
I am really struggling here as a new programming with a process using the snap7 library connected to a siemens PLC using Python3 on a raspberry PI. Basically I am reading in data as a byte array then modifying it and sending it back to the PLC. I am able to read it in and convert it to a list and modify the data.
So my data is a list that looks like [0,0,0,0,0,0,1,0]. It will always be exactly 1 byte (8 bits). So I can modify these bits. However I am struggling with getting them back into a byte array. I need to convert from that list into a byte array response that should look like bytearray(b'\x02')
Couple examples of what I am expecting
Input [0,0,0,0,0,0,0,1]
Output bytearray(b'\x01')
Input [0,0,0,0,0,0,1,0]
Output bytearray(b'\x02')
Input[0,0,0,0,0,0,1,1]
Output bytearray(b'\x03')
It is a bit odd that it is a byte array for only 1 byte but that is how the library works for writing to the datablock in the PLC.
Please let me know if there is any additional data I can share
Kevin
First convert the list to a decimal, this can be done in one line using.
sum(val*(2**idx) for idx, val in enumerate(reversed(binary)))
but to make the code a little more readable
binary_list = [0,0,0,0,0,0,1,0]
number = 0
for b in binary_list:
number = (2 * number) + b
Then simply use bytearray and add the number as an input
output = bytearray([number])
Changing this into a function
def create_bytearray(binary_list):
number = 0
for b in binary_list:
number = (2 * number) + b
return bytearray([number])
Now you just have to call
output = create_bytearray([0,0,0,0,0,0,1,0])
print(output)
And you will get
bytearray(b'\x02')
I am attempting to write an app in Swift that uses this library for playing MOD music files: https://github.com/martincameron/micromod/tree/master/ibxm-ac
The library has a method called replay_get_audio that takes in, alongside the actual data to be processed (replay and mute), an int pointer to a buffer where audio data should be written to (mix_buf):
int replay_get_audio( struct replay *replay, int *mix_buf, int mute )
The problem is that no matter what I do, I can't seem to access the data that gets written to this buffer in Swift. It's showing up as an array of zeroes in the variable inspector when I convert the bufferPointer to the data to an array:
let dataSize = Int(calculate_mix_buf_len(44100)) // 14040 is the output for my mod file - this is the necessary memory allocation amount for mix_buf according to the library
let mixBufDataPointer = UnsafeMutablePointer<Int32>.allocate(capacity: dataSize)
let resultingNumSamplesWrittenToMixBuf = replay_get_audio(replay, mixBufDataPointer, 0) // The function outputs the number of samples written to mixBuf - it is returning 882 for my mod file, so I assume it is writing the data successfully
let mixBufBufferPointer = UnsafeMutableBufferPointer(start: mixBufDataPointer, count:dataSize)
let arrayDataForMixBuf = Array(mixBufBufferPointer) // An array of 14040 Int32s - all with the value of 0...as if the data is not being written
If I manually write a value to, say, mixBufDataPointer[1], I can see it shows up in the arrayDataForMixBuf, so I know the reading using mixBufBufferPointer and the associated array conversion are working correctly. The issue appears to be where the library writes into the mixBufDataPointer.
Am I missing something? I'm completely new to pointers in Swift so this is all new to me.
I'm having a hard time in realizing how to use the repeated field rule.
for example, this is my .proto:
message Test
{
repeated float value = 1;
}
now, I'm initialize a new Test object:
Test test = test_init_zero()
Finally, I want to assign some values. For example:
float values[] = { 1.0, 2.2, 5.5, 7.13 }
My question is how can I assign them?
is it like
test.value = values
//or
test.value[0] = values[0] //... etc.
and then, how do I read them back?
This depends on how you define the repeated field inside the proto file. According to nanopb docs, you either just specify the repeated field like you did, and then use a callback function to handle each item separately during encoding/decoding, or you use nanopb-specific settings so have a fixed length array:
Strings, bytes and repeated fields of any type map to callback functions by default.
If there is a special option (nanopb).max_size specified in the .proto file, string maps to null-terminated char array and bytes map to a structure containing a char array and a size field.
If (nanopb).fixed_length is set to true and (nanopb).max_size is also set, then bytes map to an inline byte array of fixed size.
If there is a special option (nanopb).max_count specified on a repeated field, it maps to an array of whatever type is being repeated. Another field will be created for the actual number of entries stored.
For example, byte arrays need to use max_size:
required bytes data = 1 [(nanopb).max_size = 40, (nanopb).fixed_length = true];
And this would create the following field, when compiled using nanopb:
// byte arrays get a special treatment in nanopb
pb_byte_t data[40];
Or, for a float, you would use max_count according to rule 4.:
repeated float data = 1 [(nanopb).max_count = 40];
And then you'll get:
size_t data_count;
float data[40];
If you simply define a repeated field like you did, then nanopb will create a callback function:
// repeated float value = 1;
pb_callback_t value;
Which means you will have to provide your own function which will handle each incoming item:
yourobject.value.arg = &custom_args;
yourobject.value.funcs.decode = custom_function_for_decoding;
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!