I am using libnodave 0.8.4.4 library to connect to a S7 PLC and what I would like to know if how can I detect if a bit (e.g. DB100.DBX8.0) in PLC DB changes its value. What I did is to read this bit within a while loop but I would like to create an event on value changed on this bit and launch a task when it happens.
There is no default event available with libnodave or any other libraries like S7.net.
Either you need to use OPCor write your own function which will read the set of bits set on time and notify to the main program.
Related
I am trying out this MCU / SoC emulator, Renode.
I loaded their existing model template under platforms/cpus/stm32l072.repl, which just includes the repl file for stm32l071 and adds one little thing.
When I then load & run a program binary built with STM32CubeIDE and ST's LL library, and the code hits the initial function of SystemClock_Config(), where the Flash:ACR register is being probed in a loop, to observe an expected change in value, it gets stuck there, as the Renode Monitor window is outputting:
[WARNING] sysbus: Read from an unimplemented register Flash:ACR (0x40022000), returning a value from SVD: 0x0
This seems to be expected, not all existing templates model nearly everything out of the box. I also found that the stm32L071 model is missing some of the USARTs and NVIC channels. I saw how, probably, the latter might be added, but there seems to be not a single among the default models defining that Flash:ACR register that I could use as example.
How would one add such a missing register for this particular MCU model?
Note1: For this test, I'm using a STM32 firmware binary which works as intended on actual hardware, e.g. a devboard for this MCU.
Note2:
The stated advantage of Renode over QEMU, which does apparently not emulate peripherals, is also allowing to stick together a more complex system, out of mocked external e.g. I2C and other devices (apparently C# modules, not yet looked into it).
They say "use the same binary as on the real system".
Which is my reason for trying this out - sounds like a lot of potential for implementing systems where the hardware is not yet fully available, and also automatted testing.
So the obvious thing, commenting out a lot of parts in init code, to only test some hardware-independent code while sidestepping such issues, would defeat the purpose here.
If you want to just provide the ACR register for the flash to pass your init, use a tag.
You can either provide it via REPL (recommended, like here https://github.com/renode/renode/blob/master/platforms/cpus/stm32l071.repl#L175) or via RESC.
Assuming that your software would like to read value 0xDEADBEEF. In the repl you'd use:
sysbus:
init:
Tag <0x40022000, 0x40022003> "ACR" 0xDEADBEEF
In the resc or in the Monitor it would be just:
sysbus Tag <0x40022000, 0x40022003> "ACR" 0xDEADBEEF
If you want more complex logic, you can use a Python peripheral, as described in the docs (https://renode.readthedocs.io/en/latest/basic/using-python.html#python-peripherals-in-a-platform-description):
flash: Python.PythonPeripheral # sysbus 0x40022000
size: 0x1000
initable: false
filename: "script_with_complex_python_logic.py"
```
If you really need advanced implementation, then you need to create a complete C# model.
As you correctly mentioned, we do not want you to modify your binary. But we're ok with mocking some parts we're not interested in for a particular use case if the software passes with these mocks.
Disclaimer: I'm one of the Renode developers.
I want to write to the holding registers an actuator of mine has, but I've only recently started using pymodbus and I'm a little uncertain about some of its commands. As far as I've understand the primary write command looks like this:
write_register(address, value, **kwargs)
But I'm uncertain about how I "define" which kind of register I write too. Unlike other modbus libraries I've used, in pymodbus I can't define which kind of register I write too. As far as I understand of modbus there's coils, input registers and holding registers. I've read that you can't write to input registers, but how can I be certain I write to holding registers? If I write 1 in address in the write_register will that always be a holding register with that address?
Thank you in advance.
You need to know a little bit more about your actuator. Do you have a datasheet about it? If yes, you need to find a map registers where all the addresses are given for registers where the actuator's information are stored. Here an example where you can find this kind of registers map : SIMEAS Pxxx Com-Modbus Datasheet.
Be careful, sometimes you need to add or subtrace 1 to your register address because the guys who implement this did in this way. Read your datasheet carefully.
So if you need to write something in a particular register, you need the correct address of the register, the value you want to write in the correct format, and the client of the library ModbusClient.
You should have something like this :
client = ModbusClient(host='YOUR_IP_ADRESS', port=xxx)
client.connect()
client.write_register(REGISTER_ADRESS, PAYLOAD, UNIT)
Hope this will help a little. You can also go further by reading the Pymodbus documentation.
I need to increment an integer value each time the PLC program is updated to track changes.
There are system events like online_change and before_download, but I have no idea how to implement their functions.
Also I need to save value between updates. I think the tracking variable should be created as RETAIN but not sure.
The variable declaration type should be VAR RETAIN PERSISTENT in your case. Variables declared under RETAIN only will lose their values (intentionally) with a program change.
I believe the builtin Codesys library SysLibProjectInfo.lib has what you are looking for with the function SysGetProjectID. If you store SysGetProjectID as a RETAIN PERSISTENT and then compare against it, you can track changes (or, this unique value may be exactly what you wanted in the first place, without manually creating an ID).
Note: Depending on how you declare your variables, changing the I/O configuration can have unexpected changes even on VAR RETAIN PERSISTENT variables (as all dynamically allocated addresses are shifted and may not point where they used to).
If I understand you you only want to know like what version is running on the PLC and you want to track changes that you make? You can do it two ways:
Since it's a constant each time you make a change external to the PLC you roll the rev of a variable that is declared like SoftwareVersion :WORD := 100; and keep it in a Revision global list that you can add your notes to and change the version before downloading to PLC.
You can also use the PLC summary area that has fields to enter the values and then you can read them through CoDeSys without software upload.
And of course the suggestion above can work.
I am trying set a control value in my VI (which is already running).
I use the following commands:
e=actxserver('LabVIEW.Application');
vipath='C:\DATA\Labview\test.vi';
vi=invoke(e,'GetVIReference',vipath);
% my control parameter is z which is DBL (double precision)
vi.SetControlValue('z',10)
Everything seems to work fine ! I can see the 'z' value change to 10 in VI but actually VI is not reading that value and VI application is not responding to this value
The VI is a third party application, which is developed by someone else. Unfortunately, I don't have privilege in this forum to post a picture of it (I need 10 points)
I am trying to control variable "z" from Matlab. The "z"is an input to a .dll file. Note that I can do it by front panel control in VI, but can't using Matlab as described earlier.
Without seeing the code, it's impossible to tell, but here are a couple of guesses:
Are you reading the control using a value change event? This event is only triggered either by a change in the UI or by calling the Value(Signaling) property for the control. I'm not sure if you can access this property from the ActiveX interface, but you can try by getting a reference to the control (although I have no idea how that's done from the ActiveX interface either. Maybe the VI has a method?). If you can't, the best would probably be to change the VI to poll the control. You could also have another loop which will fire the event whenever the control changes, but if you do that, I would suggest you have a separate control just for passing that value.
Another possibility - the value is read from the control's terminal before you modified it and your code uses the value on the wire, not the value from the control.
If that doesn't help, post the code.
Got it ! The control variable 'z' was within a event structure, and it was set to value change of 'z'. So, I just removed it for the time being and it works well.
However, I am not sure how to work with an event structure to control it using Matlab active x
Consider testing the project you've just implemented. If it's using the system's clock in anyway, testing it would be an issue. The first solution that comes to mind is simulation; manually manipulate system's clock to fool all the components of your software to believe the time is ticking the way you want it to. How do you implement such a solution?
My solution is:
Using a virtual environment (e.g. VMWare Player) and installing a Linux (I leave the distribution to you) and manipulating virtual system's clock to create the illusion of time passing. The only problem is, clock is ticking as your code is running. Me, myself, am looking for a solution that time will actually stop and it won't change unless I tell it to.
Constraints:
You can't confine the list of components used in project, as they might be anything. For instance I used MySQL date/time functions and I want to fool them without amending MySQL's code in anyway (it's too costy since you might end up compiling every single component of your project).
Write a small program that changes the system clock when you want it, and how much you want it. For example, each second, change the clock an extra 59 seconds.
The small program should
Either keep track of what it did, so it can undo it
Use the Network Time Protocol to get the clock back to its old value (reference before, remember difference, ask afterwards, apply difference).
From your additional explanation in the comments (maybe you cold add them to your question?), my thoughts are:
You may already have solved 1 & 2, but they relate to the problem, if not the question.
1) This is a web application, so you only need to concern yourself with your server's clock. Don't trust any clock that is controlled by the client.
2) You only seem to need elapsed time as opposed to absolute time. Therefore why not keep track of the time at which the server request starts and ends, then add the elapsed server time back on to the remaining 'time-bank' (or whatever the constraint is)?
3) As far as testing goes, you don't need to concern yourself with any actual 'clock' at all. As Gilbert Le Blanc suggests, write a wrapper around your system calls that you can then use to return dummy test data. So if you had a method getTime() which returned the current system time, you could wrap it in another method or overload it with a parameter that returns an arbitrary offset.
Encapsulate your system calls in their own methods, and you can replace the system calls with simulation calls for testing.
Edited to show an example.
I write Java games. Here's a simple Java Font class that puts the font for the game in one place, in case I decide to change the font later.
package xxx.xxx.minesweeper.view;
import java.awt.Font;
public class MinesweeperFont {
protected static final String FONT_NAME = "Comic Sans MS";
public static Font getBoldFont(int pointSize) {
return new Font(FONT_NAME, Font.BOLD, pointSize);
}
}
Again, using Java, here's a simple method of encapsulating a System call.
public static void printConsole(String text) {
System.out.println(text);
}
Replace every instance of System.out.println in your code with printConsole, and your system call exists in only one place.
By overriding or modifying the encapsulated methods, you can test them.
Another solution would be to debug and manipulate values returned by time functions to set them to anything you want