Jump to content

Rolf Kalbermatter

Members
  • Posts

    3,909
  • Joined

  • Last visited

  • Days Won

    270

Everything posted by Rolf Kalbermatter

  1. Unless you use a truely speced high speed flash pen drive you are likely to keep seeing poor performance. Especially those cheapo give away flash drives (I'm looking at you NI ) have abominable performance, especially for writing. I've found that almost all flash drives that are handed out for marketing purposes seem to be of that super el cheapo quality, and similarly most noname flash drives that you can find in the super market stores. Cost maybe half of a high quality brand drive but perform much less than half that good.
  2. You might be right there. I guess I was assuming that there must be a difference between an initialized object and one that hasn't been initialize yet since there is this Get LV Class Default Value.vi. But I guess any class has as soon as it gets placed on a diagram a cluster and the To More Specific Class simply compares that the underlaying object has a matching method AND cluster definition and in that case copies the class data into the existing cluster. Makes sense from a by val architectural point of view. As such there is indeed no Not an Object but only a Default Data state, which is the equivalent of the Class data cluster having all default data elements.
  3. I didn't mean to indicate that an object reference is a by-ref implementation. But I have a hunch that an object wire on the LabVIEW diagram is similar to other refnums. The use of a refnum doesn't have to mean that the object is by-ref. It's only a matter of how LabVIEW implements the rules to access the underlaying object that defines by-ref or by-value implementation. As such implementation of a "Not an Object" primitive would be not that difficult. But maybe they didn't do that so far as they might want to solve a few more issues with Not a Number/Path/Refnum to allow some distinction between the canonical invalid underlying object type for Refnums and Objects and the once allocated but later destroyed object type.
  4. It sure is known when the function returns. So you would need to determine its length after the function returned the array of strings. There is a C runtime function strlen() which does exactly that, and a LabVIEW Manager Function StrLen() which does the same. So calling StrLen() with the CLN just like you did with MoveBlock() on the string pointer will return you the number of characters in the string and then you can do an Initialize Array with that length and then a MoveBlock() to copy the string from the string pointer into the LabVIEW byte array and then convert it with Bytes to String into a String. There is another LabVIEW Manager function LStrPrintf() which combines those two into one convinient function call. The definition is: MgErr LStrPrintf(LStrHandle handle, CStr format, .....); You would configure the first parameter of the CLN as LabVIEW String handle passed by value, the second as C String pointer, and the third as Pointer sized integer. To the first you wire an empty LabVIEW string constant, to the second a string constant containing "%s" (without quotes) and the third is your C string pointer from your array. The output of the first parameter then contains the properly sized string. The return value of the function is an int32 and if not equal to zero indicates a LabVIEW error code.
  5. This is one topic, but there are more and I've seen some weird errors too especially with the conditional disable structure in the General Error Handler.
  6. That is only half the truth. For an unitialized object reference you are right but for an object reference that has been created and then destroyed the actual refnum value is not null but still not valid anymore! There should be something akin to "Not a Number/Path/Refnum" for object wires. In fact I was at first assuming that LabVIEW objects are inherently also refnums but that seems not really the case. And extending "Not a Number/Path/Refnum" to "Not a Number/Path/Refnum/Object" would seem logical but the resulting long name sounds like a bad idea.
  7. Conditional disable while allowing a VI to run despite unrunable code in disabled frames can have some strange effects. For one, LabVIEW normally tries to load the VIs anyhow which can result in dialogs during loading for missing subVIs and such. Also there have been strange and hard to reproduce problems with the error list showing errors that only go away after removing and recreating the code in conditional disable frames.
  8. You create VIs that contain those refnums but you load and call them dynamically through Open VI Reference and (Asynchronous) Call by Reference (CBR)! Usually I create the VI that does the work and a wrapper VI that does the Open VI Reference and (A)CBR and Close Reference. You can make the wrapper as smart as you like adding the logic to decide if it should attempt to load the VI or just bail out without doing anything (or creating a warning or something) in there. Also I usually do some smart caching for the refnum using an uninitialized shift register to prevent opening and closing the refnum over and over again. Last but not least although not very nice from a design point of view I tried in the past to combine multiple operations in one wrapper/dynamic subVI combination since maintaining lots of these in parallel is quite a work load. Another better approach I have considered but which failed in the past with older LabVIEW versions because of some LVOOP limitations is to use the dynamic dispatch feature of LVOOP. You would then create two (or more) classes for the different platforms and a dummy base class and load the appropriate child class dynamically (with Get LV Class Default Value.vi) at start and then call it through the interface provided by the base class. This is IMHO the most clean design for such things. It basically uses the Factory Pattern here. While I'm not yet converted to LVOOP for everything, I find the Factory Pattern a very elegant design method to solve problems where you have dynamic components that you need to access depending on some condition that has to be determined at runtime. Doing it through VI server with (A)CBR is certainly an option but LVOOP dynamic dispatch makes it that more elegant.
  9. There is nothing new there as far as iterating the array of strings goes. Instead of a double array you basically have a string. This is a C string in the DLL and you need to MoveBlock() into a LabVIEW handle that you have allocated before with a long enough size. Using Initialize Array with a type of U8 and passing it as C array pointer into the dst parameter of MoveBlock() will do, and after the MoveBlock() call you can convert it to a string with Bytes To String.
  10. Well, maybe we are not talking about the same. I had a hell of a time (admittedly in earlier versions than 2014) when developing a plugin interface using CBR. Every time I updated the connector pane of the plugin VI in any way (just fixing a typo in an enum is enough) I had to go into every location where I had loaded the plugin through Open VI Reference and relink the strict VI refnum with the new connector pane or the CBR would return an error because the actual connector pane was not matching the expected one. Making the Strict VI Reference a strict typedef didn't seem to help. Since some time I use LVOOP with the factory pattern to implement plugins so have not tried the CBR approach anymore. Some posts on other fora made me believe that it is still a problem even in recent LabVIEW versions. Plugin devolopment is generally a pain in just about any programming environment I have tried. You either have problems at edit time to make sure the interface stays fully consistent or at runtime when trying to load the plugins and often both. The next problem is to make sure the plugins are where your software expects them to be, independent of running in debug mode in your IDE or in the final application. Nothing that specifically more difficult in LabVIEW.
  11. But beware. Even if you create a strict typedef of this "Strict VI refnum" control, it will not update its instances if you chance the connector pane of the VI and also change the strict typedef to link to this new connector pane. You have to go into every place where you used this control even if you used the strict typedef, and update it to use the new connector pane. Quite painfull if you try to built a plugin interface. And it's not really unintuitive. It was the only way to open a VI Reference for use with the Call By Reference node, before the static VI refnum was introduced.
  12. I was wondering about that when I wrote the VI, but I just didn't feel like creating a real DLL and trying it out in the debugger. Figured you could solve that problem yourself if it turned out to be necessary. To append something to a reply post you have to click the "More Options" button to the right of the "Post" buttion. This will give you the choice to switch into the full editor which allows to attach files (and insert images that you have uploaded as attachement). Had to search myself for that. It seems these forum board softwares like to hide that option under strange buttons names. Also if you chose to edit your previous post you get into an editor with a somewhat more meaningfull button besides the "Save Changes" button called "Use Full Editor" which goes into the same editor as the other option in reply mode.
  13. Something like this should probably work. But beware it's not tested in any way. Test Array Pointers.vi
  14. And where in this is your: void myfunction(double ***arrayptrs, int *size) If this would be your allocateArrays() then what you would do is make sure to export free_arrayptrs() too and call that from LabVIEW at the end. Also *arrayptrs_out = (double**)malloc(*arraycnt_out*sizeof(double*)); should probably be instead: *arrayptrs_out = (double**)malloc(*size * sizeof(double*)); Then in LabVIEW you configure the parameter as pointer sized integer passed by reference, then in a loop do what ned has suggested before. But your proposed interface is pretty weak. While you return the number of array pointers in the returned data in *size, the caller has absolutely no way to know how many elements of data each array contains. This would be just by convention (caller and callee both have to know magically) and that is always a very bad API design. And you forgot to deallocate the array of array pointers in your free_arrayptrs()!!!!
  15. The TLB file is now embedded in the LabVIEW executable. Everything else works the same.
  16. It could be that the function allocates the array of arrays itself and returns it and for that the pointer of pointer needs to be passed by reference. But there is absolutely no way to tell from the C prototype. The C syntax alone is notoriously inadequate to describe such details. The only way to know is to read the function documentation, consult any possible C sample that comes with the library and usually do lots of trial and error anyways since even the documentation and samples are usually to poorly made than that they would explain everything. Basically the solution to free() the array in the calling program is not safe because of the possible mismatch of the C runtime library between what the DLL uses and what the caller uses. The library exposing functions that return allocated memory MUST always export a function to deallocate that memory properly.
  17. No DSDisposePtr() is not safe! Your DLL should export a function that uses internally free() to dispose those resources. One of the reason for this is that the DLL will most likely link to a different C runtime library than what LabVIEW would use, so that malloc() in the DLL works on a different managed heap than free() in LabVIEW. Also DSDisposePtr() does a little more than just calling free() and that would conflict with a memory pointer only allocated with malloc() even if the free() used by LabVIEW would operate on the same heap than the malloc() used in your DLL.
  18. Well as has been many times stated by me and many others about interfacing external code there is a fundamental and very important difference about having a string that is fixed size or variable size. Fixed size looks like this: type name[n]; and when used in a struct is fully inlined. This means that the struct is extended directly with n elements of type. This however: type *name; will only place a pointer in the structure and will require the program(mer) to manage the actual memory himself. Now a LabVIEW string is again a different beast that is not directly compatible with either C declaration, so adding a LabVIEW String to the cluster is really the totally wrong thing here. If it was a pointer you would have to add an integer in there (32 bit if you intend to run it in LabVIEW 32 bit, and 64 bit if you intend to run it in LabVIEW 64 bit). Since it is inlined you have to place a cluster in there with 256 U8 elements. Not nice but that is how this is to be solved.
  19. The OpenG LabVIEW Data Toolkit's origine date from LabVIEW 5 or so times when waveforms, timestamps etc. were not yet present. Some of that was added later by whoever found to need that particular datatype support, but usually not in a structured manner either but just in the particular functions that happened to be used by that person and sometimes only to the limited extend that was required by him or her. I don't think there is any other reason to the lack of full support for the datatypes that you noticed, other than that they didn't exist back then or that the original developer decided that they were unneeded or to cumbersome to implement for the moment. You usually have to cut a line somewhere when developing such a large and involved library as this. If you start with the intention to support everything and all and handle every corner case you won't get ever to a state where you have a working library at all.
  20. Didn't I say to configure the parameter as: Adapt to Type, Array Data Pointer???? Also it would be more correct to write your function prototoype like this: int32_t LV_DLL_EXPORT func(table *pointer); That is not causing your crashes (the previous point about configuring the parameter however sure is), but it simply makes things more clear that way. Also what top secret nuclear project are you working at, that you still refuse to attach even your actual test VIs, which surely won't reveal your super duper algorithme that you will only eventually implement in the code after your principal interfacing to your test VI is working?
  21. 2) You configure the Call Library Node parameter as Adapt to type: Pass C Array Pointer. 4) Just because you assign the pointer value of memory location to a pointer parameter does nothing about making sure the contents of the memory area is copied into that parameter. table datatable[16]; (here is C allocating the memory for the array with struct of integers if i am right) int32_t func (struct *pointer) { pointer = datatable; } This only assigns the memory address of datatable to the pointer. However the calling function never sees that pointer nor any data in the pointer. You simply destroy the data area that LabVIEW has allocated and on return of the function LabVIEW can't help but trip over the trap you laid out for it. You would have to do something like int32_t func (struct **pointer) { *pointer = datatable; } but that only works for C as caller (and not like this since the datatypes are not the same). LabVIEW can't deal directly with pointers. More appropriate would be: int32_t func (struct *pointer) { *pointer = *datatable; } But that works in standard C not for all compilers and even in modern C++ it would cause a compilation error since the datatypes are incompatible. The best thing to do would be: int32_t func (struct *pointer) { memcpy(pointer, datatable, sizeof(datatable); } And making sure that you allocated a big enough variable in LabVIEW to be passed to the pointer parameter. If the dataarea from LabVIEW is even one single byte smaller than the length of datatable, very bad things will happen for sure.
  22. The biggest problem is about trying to tackle this without having a fundamental understanding of C and memory handling in general. 1) yes 2) 16 times 7 times 2 bytes, plus some LabVIEW dataspace for management of the array but you do not want to pass the LabVIEW array to the C function but the C pointer to the array. Only specially written C code can directly handle native LabVIEW arrays and strings. 3) Code Interface node is an old legacy technology to incorporate external code in LabVIEW. It is only present in some of the LabVIEW platforms nowadays and completely missing on any 64 bit versions of LabVIEW and also all realtime targets. LabVIEW ceased to ship with any tools that were necessary to create CINs many versions ago. 4) You can return data from a function through its parameters and are not limited to the function return value. Also it is good courtesy to mention that you have crossposted this in the NI forums already. The LabVIEW community is not that big that nobody would notice, but it helps others to see if they should spend any time to provide an answer that was already given elsewhere to the same person.
  23. From what I could see on the website they are mostly into high end hardware for space/defense/airplane industries and there USB doesn't really fit into very well in terms of reliability and harsh environment resistance. Haven't seen any prices but it would not surprise me if their price is in the same range or higher than NI.
  24. Except that when you follow the link from Dave's post you get to a page which looks like the card he is talking about and in red letter New Product! afterwards. After about 8 years it would seem a little strange to still claim it's a new product. CPCI isn't as quick paced as general computer technology but that slow!!!!???
  25. AVI is really only a container format and mostly meant by Microsoft to be used for real world video. What format the data is actually written in depends highly on the available codecs on your machine. Most likely it won't support U8 and/or greyscale without installing a very specific codec that supports such a format. And if you created such a formatted AVI you won't be able to replay it on machines that have not the same codec installed. The Windows AVI interface correctly changes the format to an available codec format that, at what it believes at its own discretion is the closest match to the incoming format. If you check the format of the resulting AVI file with some AVI file format checker you will see that it is already RGB when written on disc and the reading will simply read in what is on disc and has no way to magically know that it should convert it back to U8 greyscale.
×
×
  • Create New...

Important Information

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