Łukasz Posted November 1, 2021 Report Share Posted November 1, 2021 Hello, I'm trying to move the example of library use from C to LabVIEW. The function is C looks like that: static volatile UA_Boolean running = true; static void stopHandler(int sig) { running = false; } int main(void) { ... UA_StatusCode retval = UA_Server_run(server, &running); ... the code goes to the Server_run function and stops here as long as the variable running is true. In C stopHandler will change that and the program can finish. How we can transfer this functionality to LabVIEW? What should be connected as a second parameter to the CLF node function? Quote Link to comment
dadreamer Posted November 1, 2021 Report Share Posted November 1, 2021 If you export running global variable from your DLL, then you could get its memory address with GetProcAddress and pass it to your UA_Server_run function as the second argument. That should work, if I got your tactic right. 1 Quote Link to comment
Rolf Kalbermatter Posted November 1, 2021 Report Share Posted November 1, 2021 (edited) 3 hours ago, Łukasz said: Hello, I'm trying to move the example of library use from C to LabVIEW. The function is C looks like that: static volatile UA_Boolean running = true; static void stopHandler(int sig) { running = false; } int main(void) { ... UA_StatusCode retval = UA_Server_run(server, &running); ... the code goes to the Server_run function and stops here as long as the variable running is true. In C stopHandler will change that and the program can finish. How we can transfer this functionality to LabVIEW? What should be connected as a second parameter to the CLF node function? It's pretty unclear what you really try to do. You mention CLNF and all that and have a DLL but you talk like you would like to implement everything in LabVIEW. My suspicion is that you still want to call UA_server_run(), but from LabVIEW and the bad news in that case is that you can't do what you try to do. LabVIEW is dataflow driven. While it allows to call C functions, it doesn't and can't implement the full C semantics. Once it passes control to the UA_server_run() function in the Call Library Node, this code executes on its own until it decides to return. But since LabVIEW is dataflow driven and doesn't know pointers like in C, you do not have access to the memory location the running boolean is stored at that you pass to the function. If you branch the wire, LabVIEW will very "helpfully" create a seperate copy of that variable, not just pass a pointer around, since passing pointers around would completely go against the entire dataflow paradigm. You will have to create a wrapper DLL that implements and exports the stopHandler() function as well as a function that calls UA_server_run(), passing it the DLL global "running". Edited November 1, 2021 by Rolf Kalbermatter 1 Quote Link to comment
ShaunR Posted November 1, 2021 Report Share Posted November 1, 2021 (edited) 29 minutes ago, Rolf Kalbermatter said: It's pretty unclear what you really try to do. You mention CLNF and all that and have a DLL but you talk like you would like to implement everything in LabVIEW. My suspicion is that you still want to call UA_server_run(), but from LabVIEW and the bad news in that case is that you can't do what you try to do. LabVIEW is dataflow driven. While it allows to call C functions, it doesn't and can't implement the full C semantics. Once it passes control to the UA_server_run() function in the Call Library Node, this code executes on its own until it decides to return. But since LabVIEW is dataflow driven and doesn't know pointers like in C, you do not have access to the memory location the running boolean is stored at that you pass to the function. If you branch the wire, LabVIEW will very "helpfully" create a seperate copy of that variable, not just pass a pointer around, since passing pointers around would completely go against the entire dataflow paradigm. You will have to create a wrapper DLL that implements and exports the stopHandler() function as well as a function that calls UA_server_run(), passing it the DLL global "running". I think the UA_Server_run function may just write the boolean state to the running parameter (an out parm). Difficult to say with the info given but Pointer To Value for "running" might be all that's needed. The static volatile "running" variable is a red-herring in that it is an application variable that would be in LabVIEW as would the stopHandler. If the server is stopped and started by toggling the boolean, then there is a serious problem with either the DLL that exports UA_Server_run or the OP's understanding of how it works. I wouldn't be surprised if there is a UA_Server_stop which we haven't been shown. Edited November 1, 2021 by ShaunR 1 Quote Link to comment
Łukasz Posted November 1, 2021 Author Report Share Posted November 1, 2021 Thanks for the answers, the dll which wraps those functions is the easiest way to get it working. However, I was simply curious if there is any other possibility. - to clarify a running variable - it's a flag that specifies if the server should continue its process. If you pass false to UA_Server_run, then it will not start. Strange, but works. I haven't found UA_Server_stop function yet. Quote Link to comment
dadreamer Posted November 1, 2021 Report Share Posted November 1, 2021 53 minutes ago, Łukasz said: However, I was simply curious if there is any other possibility. Well, if you implement everything in LabVIEW, you could create such a global with DSNewPtr, which would give you a pointer, that you could easily pass to UA_Server_run. Then when the server is running, you may stop it by writing a zero to that pointer using MoveBlock. In such a way you won't need an additional wrapper DLL. Of course, your global should be one before you call UA_Server_run. Also don't forget to dispose that pointer when finished with it. Quote Link to comment
Rolf Kalbermatter Posted November 1, 2021 Report Share Posted November 1, 2021 2 hours ago, dadreamer said: Well, if you implement everything in LabVIEW, you could create such a global with DSNewPtr, which would give you a pointer, that you could easily pass to UA_Server_run. Then when the server is running, you may stop it by writing a zero to that pointer using MoveBlock. In such a way you won't need an additional wrapper DLL. Of course, your global should be one before you call UA_Server_run. Also don't forget to dispose that pointer when finished with it. A good remark. I didn't immediately think of this. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.