Getting Data From C Buffer Pointer in Swift - c

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.

Related

Converting From a list of bits to a byte array

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')

Basic initialization of a function using arrays

Currently setting up a function to declare the cases for a 4-part seven-segment display (a digital alarm clock basically) but keep getting errors when trying to confirm that it is properly set (Specifically from the core opening line)
Have tried looking around, but nothing is specific enough to the arrays I need.
Just a note on the code. I have not properly set up a code block before, so I am unsure as to how to highlight syntaxes. If it is properly set up, just ignore this message
Originally had it set as int SegmentWrite(int...[]) but would not produce results.
Other tests I have tried is including a size [10][7] before the opening braces, to declare count and size, changing type from byte to int, char, and float (although only byte produced any sort of result, not being what I wanted)
void SegmentWrite (int SegmentDigits[]){
byte SegmentDigits = zero[7] {1,1,1,1,1,1,0};//0
one[7] = {0,1,1,0,0,0,0};//1
two[7] = {1,1,0,1,1,0,1};//2
three[7] = {1,1,1,1,0,0,1};//3
four[7] = {0,1,1,0,0,1,1};//4
five[7] = {1,0,1,1,0,1,1};//5
six[7] = {1,0,1,1,1,1,1};//6
seven[7] = {1,1,1,0,0,0,0};//7
eight[7] = {1,1,1,1,1,1,1};//8
nine[7] = {1,1,1,1,0,1,1}; //9
This particular snippet of code isn't supposed to do anything - not on it's own, at least. When verifying, to confirm proper formatting, I only got the error report "declaration of 'byte SegmentDigits' shadows a parameter' with the first line highlighted.
-Just a note, found another error, specifically with the opening line - "declaration of 'SegmentWrite' as array of void" or "'SegmentWrite' declared as function returning an array"
You need to use a different name for the parameter array and the local array in the function.
Also, the function should take another parameter, the digit that you're trying to display.
You should then declare a 2-dimensional array, and you can use the digit as an index into it.
void SegmentWrite (int SegmentDigits[7], int digit){
int allSegmentDigits[][7] = {
{1,1,1,1,1,1,0},//0
{0,1,1,0,0,0,0},//1
{1,1,0,1,1,0,1},//2
{1,1,1,1,0,0,1},//3
{0,1,1,0,0,1,1},//4
{1,0,1,1,0,1,1},//5
{1,0,1,1,1,1,1},//6
{1,1,1,0,0,0,0},//7
{1,1,1,1,1,1,1},//8
{1,1,1,1,0,1,1}} //9
memcpy(SegmentDigits, allSegmentDigits[digit], sizeof allSegmentDigits[0]);
}

How to read data from file as String or Bytes from in swift 5 using readData function

i am trying to read content of the file using readData function .I am able to read data from the file currently it is displaying size of content read from file but i want actual content of the file .
Code using for reading file
var fileHandle = FileHandle(forReadingAtPath: FullFileName as String)
var data = fileHandle?.readData(ofLength: 10)
var availabledata = fileHandle!.availableData
print("data")
print(data)
print("availabledata")
print(availabledata)
Output
data
Optional(10 bytes)
availabledata
11 bytes
Q1. How can i print actual content read from the file ?
please suggest method related to the readData function only .
How can i print actual content read from the file ? please suggest method related to the readData function only .
The question isn't really tied to readData – this function returns Data?, an optional value. When you print this you will get Option(x bytes) where the x bytes is the .description of the value.
If you wish to print the byte values you need to write something to produce your desired format. For example:
print(data?.map { $0 })
will print the data as an array of UInt8. If you wish to format each byte differently, say as hex, change the closure to produce the format you wish – each byte gets passed to the closure as a UInt8 value.
This is far from the only way to do it, you just need to wrote what you need as Data itself doesn't provide a description that meets your needs.
HTH

swift 4 - get the memory size of array

I need to find out the size of an array (Swift 4 AnyObject) I just downloaded. Every mobile device has some free memory (size varies per user) and I need a way to examine the size of my download. I have searched and can't find a reasonable answer. Hope you can help!
This seems to be impossible currently. But if you just need a rough estimate, you can use class_getInstanceSize:
func size<T: AnyObject>(_ array: [T]) -> Int {
return class_getInstanceSize(T.self) * array.count
}
For this example array
class Test {
var a: Bool = false
var b: Int = 0
var c: String = ""
}
let array = [Test(), Test(), Test()]
you will get a size of 168. See this post for more information.
Of course, this approach will not work well with fields of variable length, for example with strings or arrays. The only possibility I see to get an accurate value is to write a function for each possible class to calculate the exact number of bytes need. For a string, for example, you can calculate the number of bytes with
"test".data(using: .utf8)!.count
But even with this approach you will not get the real size of the memory Swift uses internally to store the array.
So the question is: Why do you need to know the size of the array? And what is the reason that you do not know the size of downloaded data? If those data are received from outside, they must already be encoded in a byte representation, so counting should be quite easy.

Issue with managed array in C++/CLI

I'm a c++ programmer and I'm having some issue with managed array. I'll explain what i mean. I'm using Visual Studio to code a Windows Form to handle a device.
I need to plot datas from a MCU connected to my PC thru a serial port. To save the values incoming from serial port, I'm using an array like that:
array<double, 1>^ datas = gcnew array<double, 1>(ndatas);
array<Byte, 1>^ byteDatas = gcnew array<Byte, 1>(2*ndatas);
where ndatas is the number of values of my series and byteDatas is the array where I will save the bytes that compose every value. Every value is made by 2 bytes.
After that, I will fill this array like this:
for(int i = 0; <=ndatas; ) {
if(bytes = serialPort1->BytesToRead>=2) {
datas[i] = getData(serialPort1, byteDatas, i);
}
i++;
}
The funcion getData is this one:
double getData(serialPort^ sp, array<Byte,1> data, int i) {
union Level {
char L[2];
signed short level;
} lvl;
sp->Read(data, i, 2);
for(int j = 0; j<=2; j++) {
lvl.L[j]= data[i+j];
}
return safe_cast<double>(lvl.level/100.00);
}
This function is on another .cpp file, so I had to use the variable SerialPort.
Everything goes like charm. If I try to use a MessageBox to display my datas, I can see how my array is correctly filled with the right values.
My next step to do, is to plot this data on a pictureBox using drawLine. But I really can't cause half of the values of the array datas are set to 0. For istance, if my series has 100 values, I can draw only the first values with the right amplitude. The other are represented, of course, as a horizontal line of zeroes.
To find this out, I have used a for cycle like that.
for(int i = 0; i<=datas->Length; i++) {
MessageBox::Show(Convert::ToString(datas[i]+" " + Convert::ToString(i+1));
}
just to be sure from when I will find the problem.
The strange part of this one is that, if I put the same MessageBox line of code under
datas[i] = getData(serialPort1, byteDatas, i);
I can display all of values without zeroes.
I'm stuck, and I don't know how to get rid of this problem. I hope I can find a little help to overcome this annoying issue.
I wish everything is crystal clear and I would like to thank everyone will give me a feedback.
Cheers,
Emiliano
When you do call getData, you're getting a valid value.
But BytesToRead goes down as you read data. At some point it drops below 2, and the rest of the for loop does nothing.
You might need to save where you are in the array when you run out of data, and when more serial data arrives, continue filling in the array from where you left off.
Plus, of course, right now you appear to be putting every data value into element 0 of the array, because you never increment i.
Also, you're reading each data point at index i, which means that you overwrite the second byte from the previous sample.
There's no need for safe_cast, the result of the division is already a double. And even if you needed a conversion, safe_cast isn't appropriate, since none of these data types are polymorphic.
Furthermore, your use of the union causes undefined behavior.
Finally, you're in C++. So why are you using what is probably the worst designed serial port API Microsoft ever made? This is C++. Calling Win32 APIs is easy, just #include <windows.h> and go, no p/invoke needed.

Resources