Jump to content

Rolf Kalbermatter

Members
  • Posts

    3,871
  • Joined

  • Last visited

  • Days Won

    262

Everything posted by Rolf Kalbermatter

  1. I added my comments in the comments behind //// static MgErr PostDataMessage(LVUserEventRef rwer, int32_t adapterNr, DataRecord *dataPtr, int32_t numElements) { // when you create the variable "testDataBlock" everything in the block is made 0 with the use of {0} // dataRecords points to a memory location which has got an unknow size. At this time the pointer is a Null pointer maybe ? //// => wrong!! It is a NULL pointer so it is not an unknown size but an invalid pointer pointing nowhere! DataBlock testDataBlock = {0}; // Here you use the function "NumericArrayResize" to resize the memorylocation dataRecords points to //// yes, it is a LabVIEW handle and needs to be accordingly setup, but since it is never really passed to the LabVIEW diagram //// it would not strictly be necessary to allocate it as LabVIEW handle but it needs to have the exact memory layout so it is //// easiest to do that in this way, anything else is going to confuse you simply more!!!! MgErr err = NumericArrayResize(uL, 1, (UHandle*)&testDataBlock.dataRecords, 2 * numElements); if (!err) { testDataBlock.adapterNr = adapterNr; // Here you use MoveBlock to Move the data from the source location where dataPtr points, to the // correct location of testDataBlock. You use the (*(..)) because if you would have used // *testDataBlock.dataRecords->elms you did point at the beginning of testDataBlock and not to the begining of elms //// wrong!! It is simply for correct C operator precedence evaluation, -> has higher precedence and would be evaluated //// before the * (pointer dereference) operator and would give you a compiler error since testDataBlock.dataRecords //// has no elms member, but *testDataBlock.dataRecords has, and I prefer to use more brackets to make it simply more //// clear, so (*(testDataBlock.dataRecords)) but the inner brackets are not strictly needed as operator precedence //// rules work fine here (. structure access has higher precedence than * pointer dereference, just as we want it here) MoveBlock(dataPtr, (*(testDataBlock.dataRecords))->elms, numElements * sizof(DataRecord)); (*(testDataBlock.dataRecords))->dimSize = numElements; err = PostLVUserEvent(rwer, &testDataBlock); // (this was your comment): PostLVUserEvent does a deep copy so we need to deallocate this handle to avoid a memory leak //// right! the testDataBlock memory area is going away at exit of this function and the handle stored in too, so we need //// to deallocate it otherwise it is lost DSDisposeHandle(testDataBlock.dataRecords); } return err; } No no! Doing it yourself instead of letting LabVIEW do it is only making things only really worse. And you definitely and absolutely are doing the calculation wrong although it will be simply a to big allocation so at least you won't blow up your harddisk. 🙂 Something like this would be more accurate: size_t len = offsetof(DataArrayRec, elms) + size * sizeof(DataRecord) if (!handle) { handle = DSNewHandle(len); if (!handle) err = mFullErr; } else { err = DSSetHandleSize(handle, len); } Sorry mate, but this sounds gibberish and I have no idea what you mean.
  2. There are many ways you can print and it is not entirely clear to me which one you use. If you use the method to have LabVIEW send a front panel to the (default) printer, what really happens is rather involved. LabVIEW has no idea if the printer is a real printer, using EPS, LPD/LPR, JetDirect or whatever else underlaying printer driver protocol. All it knows is that the printer driver supports a GDI interface (The Windows Graphic Device Interface specification that is also used to draw items on the screen) and it pretty much treats it exactly the same aside from some extra setup steps such as page size and orientation. What finally ends up on the printer is very specific on the quality of the printer driver and its ability to render each of the zig hundred GDI commands properly in a resulting output. It seems that the PDF printer driver you are using, does some shortcuts by not rendering everything itself but for instance letting rotated text be rendered by the Windows GDI subsystem itself and then reading the resulting bitmap and adding that into the PDF stream. A very valid procedure although of course not the highest quality result. Other PDF printer drivers may be a bit more developed and translate this properly into direct PDF commands, but they may cost something.
  3. Unfortunately, the LabVIEW internal manager function that would return the list of enumerated fonts is not exported from the LabVIEW runtime. That would have been a lot easier and platform independent.
  4. Well, with that much information we can only tell you: Good luck! What interface? What part do you want to make read only? What platform? What LabVIEW version? Can you show in a simple VI what you try to do and what you have done so far? Up to now, you basically only said that you need help and nothing else. You need to be a lot more specific in what is your problem!
  5. 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.
  6. 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.
  7. 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.
  8. 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.
  9. 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.
  10. 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.
  11. 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.
  12. 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
  13. 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.
  14. 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).
  15. 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.
  16. 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.
  17. 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.
  18. I'm an "Urgestein". For me PSK still mean Phase Shift Keying.
  19. 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.
  20. 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. 😎
  21. 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.
  22. 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.
  23. 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.
  24. 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.
  25. 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).
×
×
  • Create New...

Important Information

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