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')
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]);
}
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
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.
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.