Jump to content

Rolf Kalbermatter

Members
  • Posts

    3,917
  • Joined

  • Last visited

  • Days Won

    271

Everything posted by Rolf Kalbermatter

  1. Some Dynamic DNS or similar could help with the problem of a dynamic IP adres device in the field. It would require a fairly simple modification in the cRIO setup, but if you use an NI Linux RT type this should be pretty trivial. Of course you will need to have access to a Dynamic DNS service somehow, they are usually not for free. No-IP for instance provides a free version but requires you to manually confirm it every 30 days and does not support SSL certificates on that level. For 1.99 per month you do get SSL and a 1 host name resolution without monthly confirmation. Other services have similar offers. The free tier has usually several limitations that are inconvenient but not a huge problem for private deployments. But they pretty much won't work for a commercial deployment.
  2. No, no, no! #include "extcode.h" #include "lv_prolog.h" typedef struct { int32_t status; int32_t value; } DataRecord; typedef struct { int32_t dimSize; DataRecord elms[1]; } DataArrayRec, *DataArrayPtr, **DataArrayHdl; typedef struct { int32_t adapterNr; DataArrayHdl dataRecords; } DataBlock; #include "lv_epilog.h" static MgErr PostDataMessage(LVUserEventRef rwer, int32_t adapterNr, DataRecord *dataPtr, int32_t numElements) { DataBlock testDataBlock = {0}; MgErr err = NumericArrayResize(uL, 1, (UHandle*)&testDataBlock.dataRecords, 2 * numElements); if (!err) { testDataBlock.adapterNr = adapterNr; MoveBlock(dataPtr, (*(testDataBlock.dataRecords))->elms, numElements * sizof(DataRecord)); (*(testDataBlock.dataRecords))->dimSize = numElements; err = PostLVUserEvent(rwer, &testDataBlock); // PostLVUserEvent does a deep copy so we need to deallocate this handle to avoid a memory leak DSDisposeHandle(testDataBlock.dataRecords); } return err; } And yes, my order of the elements in DataBlock seems the other way around than yours, I did it according to the optical order in your image, as that was all I had to go by.
  3. The first step in trying to create a DLL that uses LabVIEW data types natively, is to configure a Call Library Node to have a parameter which is configured Adapt to Type. Then connect the datatype you want to use to this parameter, right click on the Call Library Node and select "Create .c file". The resulting C file has an exact C type declaration for the parameter. Copy paste and start programming your code you want in your own C file. #include "extcode.h" #include "lv_prolog.h" typedef struct { int32_t status; int32_t value; } DataRecord; typedef struct { int32_t dimSize; DataRecord elms[1]; } DataArrayRec, *DataArrayPtr, **DataArrayHdl; typedef struct { int32_t adapterNr; DataArrayHdl dataRecords; } DataBlock; #include "lv_epilog.h" This is what your type will probably look like. Obviously the int32_t is just a guess, can't see that from an image.
  4. Actually DSNewPtr is not really needed. You can very well provide the necessary memory space by a simple Initialize Array node, datatype U8, size 8 * 512 + 3 * 4 and pass that as C array pointer to the shared library. Then do some indexing into the resulting array after the function executed and some Unflattening for the 3 integers and all should be well.
  5. Your problem likely is that SVLibInit() opens a handle to your file(s) and you never release them. Windows (Linux too) will clean up unclosed handles/fileids when a process exits but not before that. So you should also have a function SVLibUninit() or similar that will then release all the resources, and of course call it from LabVIEW when you are done with your software. Once that happens, you can access those files from other processes too, without needing to close LabVIEW.
  6. It misses context. void means NOTHING, and void * means a pointer to whatever the C programmer may have decided. Problem is that if the caller and callee don't agree what that anything means, really BAD things will happen. But without some more information all I can say is that it is a pointer and that would be in the LabVIEW Call Library Node a pointer sized integer. If that could work in this context is at least questionably. There obviously would need to be some other function that can return such a "handle"to you. The functions as you show them only consume this handle and can't create it in a meaningful way.
  7. Not sure, but it should be very trivial to test. Just put a list control in one of the sub panels, add several few thousend items to it and loop through it to update the cell background. Observe if your list control updates quickly.
  8. Posted on the dark side too and answered there quite extensively. https://forums.ni.com/t5/LabVIEW/Double-word-hex-string-to-number-format-problem/m-p/4309006
  9. It depends what was the reason of the loss. If the connection got lost because the remote side disconnected, then yes you absolutely SHOULD close your side of the connection too. Otherwise that refnum will reserve resources, for one for itself, as well as the underlying socket which also needs to be explicitly closed. So when in doubt ALWAYS close LabVIEW refnums explicitly through the proper close node even if the underlying resource has been somehow invalidated. The only time you do not need to do that is if the refnum got autoclosed because the top level VI in whose hierarchy the refnum was created got idle.
  10. This library has a bug. The underlying Read VI should use byte arrays as input and output data and the Call Library Node should be configured accordingly for this parameter to be Array, 8 bit unsigned Integer, Pass as C array pointer. With the current C String configuration in the Call Library Node, LabVIEW will scan the string after the Call Library Node has finished, and terminate it after the first 0 byte (since that is how in C strings are terminated).
  11. No, Microsoft Visual C 6.0 still used the standard Windows C Runtime MSVCRT.DLL which should be available in every Windows version since 3.0. Or maybe it is not anymore in Windows Server 2019?? Try to see if you can find MSVCRT.DLL in SysWow64.
  12. Well so long ago. I would have to look into the code to see if it could actually even cause this error from not being able to locate the Python kernel. I kind of doubt it. What might be more likely the problem is the lack of the correct MSC C Runtime library. Although a quick check seems to indicate that it was compiled with MSVC 6.0 which did not have this cumbersome C compiler version specific runtime support library issues. Not having a Windows Server 2019 installation available it is also a bit of a trouble to try to debug this.
  13. No, I didn't go through the whole procedure to obtain a license. But I did in a long ago past, during my education in electronics, experiment with building the hardware for a radio transceiver to do that. And also another one to receive the satellite radio signal from weather satellites (all at that time in analogue hardware, when 137MHz was considered still really HF and its signal propagation in a circuit sometimes more magic than anything else, not one of those easy SDR dongles 😁) At some point I decided that HF was simply too hard to really work with and concentrated on mostly digital electronics and some audio electronics for PA.
  14. I'm an "Urgestein". For me PSK still mean Phase Shift Keying.
  15. So you say you downloaded a driver but program the entire communication in plain calls anyhow. Why that? First thing would be that commands need to be terminated. Try to add a \n or maybe \r\n to the *IDN? command too. Also, while the case of the commands usually shouldn't matter for SCPI command, you do not need to write the syntax from the programming manual literally. The convention is, that the uppercase letters are required (short form), while the lowercase letters are optional (long form). Some instruments allow partial optional characters and other only understand either the exact short form or the full long form command parts in a single command. One potential problem is that the native TCP nodes only have 4 messages modes for TCP Read. And neither is usually perfect for normal instruments. You would want to use the termination character mode, but there is only the option to use CR AND LF. Many instruments send either one of them but not necessarily all of them. Standard mode kind of still works but the Read will timeout as it can't read the actually asked amount of characters. This will slow down your communication a lot. Better is usually to go and use VISA instead for these cases.
  16. If you happen to own a substantial amount of NI shares, that is certainly possible. 😁 Otherwise you have to consult with your pension provider first. 😎
  17. Why do you think your path hierarchy in the RTE needs to be different than on your development system? You should be able to arrange that in a way that there is (almost) no difference! If you make sure to not enable the LabVIEW 8.0 hierarchy layout in your application build settings, the relative paths inside the executable remain automatically the same. Of course you will need to add all those classes explicitly to the build now, as LabVIEW can't track them as dependency now anymore, since you have no static reference to them.
  18. This absolutely will pull every class in that case structure into your VI hierarchy. And if any of them is not executable (for instance because it calls a DLL whose dependencies is not satisfied) your VI here (and the whole class it is a member of) will have a broken executable status. The idea with using the Get Default Value for a class is exactly to avoid that. If you resolve the class at runtime with the Get Default Value function it does not matter if any of the classes that you may eventually call is present or not on disk, or broken or whatever, when trying to load your "Generic" PS2 OO class. It will load and as long as you do not try to instantiate one of the not present or broken classes at runtime, nothing bad will happen. Only when you indicate to this function to load SNDCSDLM, will it cause a runtime error to the fact that something is wrong with that class when it was trying to load it. If you however only indicate to load and use AG6038A (just to name something) and that class has no problems, you can execute everything and it does not matter that the SNDCSDLM class is not executable for some reason. But with your current implementation it does matter. The Class constant makes the whole class a static dependency of your VI (and of your entire Power Supply 2.0 class) and if any of the class members of SNDCSDLM is broken your entire Power Supply 2.0 class is also broken, even if you never even intend to run the SNDCSDLM class in it.
  19. Supposedly it is not using user input to add to the internal knowledge pool beyond a single session. Of course it's tempting to do that anyhow. It uses a lot of energy to run and somehow some bean counters want to see some form of ROI here, so "free" learning input would seem interesting. But without a very rigorous vetting of such input, the whole knowledge pool could easily be tainted with lots and lots of untruthiness. Not that even the selection of the actual training corpus for each new training round is guaranteed or even likely to be not biased in some ways either.
  20. Your time scale definitely seems skewed in terms of the grand scheme of the universe and all that. 😁 Or did you mean to write Atoms instead of Eons? 😎 I consider ChatGPT and friends still mainly a fairly advanced parrot.
  21. Shaun already pointed you at the culprit. There is one potential pitfall however. CVIRTE.dll is the same for LabWindows/CVI as is LVRT.dll for LabVIEW. It is the Runtime Engine that contains the entire business and support logic for executing LabWindows/CVI compiled DLLs and executables. And it has similar versions as LabVIEW too. So depending on in which CVI version the DLL was created, you may need to make sure you install the correct CVI Runtime version on that PC. Similar to LabVIEW, CVI also started to use an upwards compatible Runtime library somewhere around 2015 or 2016 I think. But if your DLL was compiled in an earlier version of LabWindows/CVI, things are listening a lot more narrow. CVIRTE is used by several tools in the NI software stall (Not everything is developed in LabVIEW and not even everything in LabWindows/CVI, some tools are directly developed and compiled in MSVC). But some of the plugins in NI Max such as the instrument control wizard and similar are developed in LabWindows/CVI. So if you install a typical NI Development machine, that runtime library is absolutely sure to be present, but on a minimal LabVIEW runtime only installed machine, it is not automatically there. And none of the typical LabVIEW Additional Installer containers includes it. The real problem is likely the developer of your SNDCSDLM.dll. S/he would know that they used LabWindows/CVI to compile that DLL and they should have provided a proper installer for this component that also takes care of installing the right version of the CVI Runtime to the target machine. Simply adding such components as a dependency in your LabVIEW project makes you automatically responsible to care about this yourself! And yes it is cumbersome, but there is no easy solution to this, other than the fact that the original developer of a component SHOULD provide a proper installer (and any user of such a component SHOULD include that installer as part of their own application installer rather than just copy the DLL alone into their project).
  22. That's simple. OPC is a completely different protocol layer. You need an OPC capable server (which last time I checked was an additional licensed component) in your PLC to do that. Part of the OPC UA protocol is to enumerate all the available resources on a system. That includes data items and their data type. And the NI OPC library has an extensive part that converts between the OPC wire data and the actual LabVIEW data in a seemingly transparent way. Snap7 (and all the other S7 Toolkits out there) communicate through the Siemens S7 protocol, which is based on ISO on TCP as basis protocol, and while the ISO protocol is an officially documented protocol, it is only the container frame in which Siemens then packs its own S7 protocol elements. And those S7 protocol features were never officially documented by Siemens, but the original protocol that only addresses fixed DB, EB, AB, MK elements was reverse engineered by projects like libnodave and then Snap7. No such reverse engineering has happened for the extended protocol elements present in the 1200 and 1500 series that support accessing "compressed" elements.
  23. Handles are only used for arrays (and a LabVIEW string is also an array of ASCII bytes). Now, when you start to do arrays of structures, things get really fun, but yes it is an array so it is a handle too.
  24. While it's not a problem for this specific datatype, you should do something extra for any struct definition, which I forgot in my example above! #include "extcode.h" // This is logical to get the definitions for the LabVIEW manager functions #include "hosttype.h" // Helpful if you also intend to include OS system API headers ...... // Anything else you may need to include #include "lv_prolog.h" // This is important to get correct alignment definition for any structured datatype // that is meant to interface directly to LabVIEW native diagram clusters typedef struct // This datatypes elements are now properly aligned to LabVIEW rules { int32_t firstInt; int32_t secondInt; int32_t thirdInt; LStrHandle lvString; } MyStruct, *MyStructPtr; #include "lv_epilog.h" // Reset the alignment to what it was before the "lv_prolog.h" include .......................... As mentioned for this particular cluster no special alignment rules apply for 32-bit as all 4 elements are 32-bit entities. In LabVIEW 64-bit the LStrHandle (which is a pointer really) is aligned to 64-bit, so there are 4 extra bytes added between thirdInt and lvString, but LabVIEW also uses the default alignment of 8 byte (64-bit) so the alignment is again the same independent if you use those lv_prolog.h and lv_epilog.h includes or not. But in LabVIEW 32-bit full byte packing is used (for traditional reason), while most compilers there also use 64-bit alignment rules. Therefore if the natural alignment of elements does cause extra filler bytes, it will not match with what LabVIEW 32-bit for Windows expects for its clusters.
  25. You clearly have not much C programming experience. Which of course is a very bad starting point to try to write C code that should then interoperate with LabVIEW. First this: // +++++ I try to add this, Gues this will not work .. see extcode.h LStrHandle textString[TEXT_STRING_SIZE]; }structSample; You are basically defining a fixed size array of TEXT_STRING_SIZE LabVIEW string handles, not a LabVIEW string handle of TEXT_STRING_SIZE length. LabVIEW string handles are never fixed size but instead dynamically allocated memory blocks with an extra pointer reference to it. And that dynamic allocation (and deallocation) ABSOLUTELY and SURELY must be done by using the LabVIEW memory manager functions. Anything else is nothing more than a crash site. What you have built there as datatype would look like an array of structs and each of these structs would contain three integers followed by 256 LabVIEW string handles, which is not only pretty weird but absolutely NOT compatible with any possible LabVIEW structure. And after allocating all these things you eventually only send the actual string handle to the event and leak everything else and the handle itself too! typedef struct { int32_t firstInt; int32_t secondInt; int32_t thirdInt; LStrHandle lvString; } MyStruct, *MyStructPtr; MgErr CreateStringHandle(LStrHandle *lvStringHandle, char* stringData) { MgErr err; size_t len = strlen(stringData); if (*lvStringHandle) { err = DSSetHandleSize(*lvStringHandle, sizeof(int32_t) + len); } else { *lvStringHandle = DSNewHandle(sizeof(int32_t) + len); if (!*lvStringHandle) err = mFullErr; } if (!err) { MoveBlock(stringData, LStrBuf(**lvStringHandle), len); LStrLen(**lvStringHandle) = (int32_t)len; } return err; } MgErr SendStringInSructToLV(LVUserEventRef *userEvent) { MyStruct structure = {1, 2, 3, NULL); MgErr err = CreateStringHandle(&structure.lvString, "Some C String!"); if (!err) { err = PostLVUserEvent(*userEvent, &structure); DSDisposeHandle(structure.lvString); } return err; }
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.