Jump to content

Rolf Kalbermatter

Members
  • Posts

    3,837
  • Joined

  • Last visited

  • Days Won

    259

Everything posted by Rolf Kalbermatter

  1. Well let me tell you about the lvZIP library on OpenG. That is magnitudes simpler than the FFMPEG library in terms of number of exported APIs as well as functionality. And creating that was more like a one or two year parttime project than a weekend project . And I knew some substantial C programming when I started with that, although I sure learned a few tricks during development of that library too. So even with an optimistic outlook I would consider the FFMPEG library to be a substantial full time project that likely takes up several months to do right. As to your specific problem: those AVStream and other parameters are so called opaque data types. Basically that means that the external declaration is simply a named datatype with no public data content. As such LabVIEW can not do anything with this datatype and the import wizard has to leave the not fully declared datatype undefined. Even if you go into the header file and add something to the structure to make it parsable you are really misguiding the import wizard as to what it should do. The only kind of fix that might sort of work would be to define the AVStream and others to be of type void instead of an unfinished struct. Then AVStream* will get void* which is actually what you want to have here. The idea about opaque types is that they are in the external API only treated as a pointer to an undefined struct. Much like what Windows uses HANDLEs for. They are basically a pointer to a data structure that the actual API knows how to interpret, but the caller never should be concerned about in any way. By making it an opaque type the programmer can make sure that any caller will never be able to concern itself with the contents of that structure. Internally in the library source code there is another header which declares the datatype completely so it can be used inside the library properly. The advantage of using AVStream* and friends as seen here instead of declaring every of these types as void* instead, is that you as caller can then not accidentally pass a pointer that describes a different resource than an FFMPEG stream to this function. Well that applies for C(++) only of course. In LabVIEW you don't have that automatic syntax check based on the C header declaration. Personally I would probably redefine all those opaque types to void and then let the import wizard correctly create the library calls. Here they should then end up as a pointer sized integer. You end up with the problem that you loose every type safety as a pointer sized integer that points to an AVStream is not distinguishable from another pointer sized integer that points to some other resource. But solving that issue is even more involved and definitely will go way beyond any type of weekend project.
  2. Under Windows there is a special root loop in LabVIEW that registers a LabVIEW Window Class on startup. That supposedly fails when it is already registered and in old days LabVIEW simply passed control to that other instance and then terminated. The allowMultipleInstances ini key is a fairly new addition (well around LabVIEW 7 or so) that seems to make LabVIEW not terminate on RegisterClass() returning an error but instead simply continues. Under Linux there is no such mechanisme and it is even more unusual for an application to not allow being started more than once. They would have to add some internal IPC mechanisme to check for that on startup and I'm sure that never really has come up so far and even a Product Suggestion has a very low chance to ever make it into LabVIEW. allowMultipleInstances most likely is nowhere present in any non-Windows version of LabVIEW. However, at least in Linux (and I suppose on OSX too) you can easily do this by creating a startup shell script for your LabVIEW application and check in there with shell commands for the existence of another instance of the same app. Look here for a fairly simple possibility to do that.
  3. As SDietrich mentioned, the pressing of a button can be intercepted by pop-up windows of any other application in the system. A slightly more involved possibility which still would work from vbscript would be to enable the ActiveX interface of the LabVIEW application and then control the application explicitly by invoking ActiveX methods of the LabVIEW server. This post is part of a thread that discusses the possibility to control a LabVIEW VI from vbscript and the post contains even a small sample.
  4. First, the distinction between AZ and DS memory space has long ago been removed. The functions remained for backwards compatibility but really allocate exactly the same handle. Second you shouldn't try to do this if you don't have a very deep understanding of C memory pointers. I can give you a principle idea, but can't do all the work for you. You will likely have to tweak this code and it may even contain syntax errors as I'm writing it just from memory without any compiler check. So watch out and reconsider if you really want to go this path. /* Call Library source file */ #include "extcode.h" /* lv_prolog.h and lv_epilog.h set up the correct alignment for LabVIEW data. */ #include "lv_prolog.h" /* Typedefs */ typedef struct { int32_t Numeric; LStrHandle String; } TD2; typedef struct { int32_t dimSize; TD2 Cluster[1]; } TD1; typedef TD1 **TD1Hdl; #include "lv_epilog.h" MgErr funcName(TD1Hdl *data); MgErr funcName(TD1Hdl *data) { MgErr err; int32 i, strLen, arrLen = ...; if (*data) { if ((**data)->dimSize > arrLen) { // Deallocate all contents in Clusters that get removed when resizing the array down for (i = arrLen; i < (**data)->dimSize, i++) { LStrHandle *str = &((**data)->Cluster[i].String); if (*str) { DSDisposeHandle(*str); *str = NULL; } } } err = DSSetHandleSize(*data, sizeof(int32) + arrLen * sizeof(TD1)); } else { *data = DSNewHClr(sizeof(int32) + arrLen * sizeof(TD1)); if (!*data) err = mFullErr; } if (!err) { TD2 rec = (**data)->Cluster; for (i = 0; i < arrLen; i++, rec++) { rec->Numeric = i; strLen = strlen(sourceString); err = NumericArrayResize(uB, 1, (UHandle*)&rec->String, strLen); if (err) return err; MoveBlock(sourceString, LStrBuf(*(rc->String)), strLen); LStrLen(*(rec->String)) = strLen; } (**data)->dimSize = arrLen; } return err; } This should give you a start. Please note that I did try to make some provisions to properly deallocate internal resources if the array resize would result in a shortening of the incoming array. However the error handling is not perfect at all. Currently if the code errors out because of anything then the array could actually stay in an inconsistent state, resulting in memory leaks, since LabVIEW wouldn't know about the already newly allocated array records. However in this example this is not really a big problem as the only errors that could happen are memory manager errors and once such an error has occurred you'll have to restart LabVIEW anyways. But if you add your own code in there to actually retrieve the data from somewhere you might run into more norrmal errors and just bailing out like this in the array fill in loop could have really bad consequences in terms of memory leaks.
  5. A shared library seems like a bad idea to start as self contained background application (deamon). Instead you should simply create a headless executable and add it to your boot sequence. How you can add an executable to the boot sequence depends a bit on your specific Linux distribution and version but you usually add a script that calls your executable somewhere in /etc/rc.d/, /etc/rc.d/init.d, or /etc/init.d, depending on your Linux version. This script is a shell script that takes certain parameters like start and stop and translates that into calls to your executable. Theoretically you could even program your LabVIEW program to simply take those command line parameters and execute accordingly and then just add a symlink to your executable to the right sysinit location. Your LabVIEW deamon really is a headless system as it will normally run directly in the system without any GUI. In order to allow user configuration you would either have to allow some IPC communication between your UI component and your deamon, such as a little TCP/IP server in your deamon program. You don't even have to write that server yourself but could enable the VI server in the LabVIEW application and simply call in the deamon some VIs that update its internal state through the Call By Reference method of VI server.
  6. Just a tiny bit more involved really! I just received my result back of my own CLA certification and passed, although barely. The comments on the sheet about what all still would need to be implemented simply sounds ridiculous to be finished in anything near to 4 hours. So prepare with the sample exam, and make sure you get your basic framework for that done in the shortest possible time. I would say if you can get your basic framework with skeleton VIs for all the sub units like GUI, Error handler etc. within less than an hour then you are more or less ready to take the exam. After that hour you can start to stamp all the requirement tags in the different VIs and start to fill in the raw diagram structures according to the requirements. One advice: rather than trying to implement real code, describe what needs to be done in text inside the various structures as much as possible. That will save you some time. And yes, if you are able to power create your basic framework without much thought, you can recreate that for the real certification almost blind, with some minor variations.
  7. If "End Process" doesn't work, your application is defininitly doing something VERY low level. Do you call some drivers that use kernel device driver somewhere? Except DAQmx of course, which definitely does have such drivers, but hasn't behaved like this on me so far. Other 3rd party vendor drivers however have done such things to me in the past. Unless your application is stuck in kernel space, "End Process" really ought to be able to kill the process cleanly.
  8. You can't dismiss the device itself. Some device may have an internal timout to free up resources which means they will actively and willfully drop any connection that has not seen any data transmission for a certain amount of time. While your desktop computer has a sea of memory and CPU power to process many parallel TCP/IP streams at the same time, your embedded device is typically much more resource constrained. They may not even be able to serve more than one endpoint at the same time, so any host trying to connect to them and leaving a connection hanging could block the device for anyone else entirely. That may be a security feature, by locking out other network access while you do some sort of transaction on the device that needs to be uninterrupted by anyone else, but if the device would allow infinite time for a connection to stay open, any misbehaving application could block the device totally for anyone else. So check your documentation! Most likely there is some info as to how long a data connection can stay open inactive before the device will close it from its own side, which is in fact the most common reason for error 66. Another possible reason for this error could be that the device detects some errors while serving the connection, either misformed data packets or some network protocol error due to for instance your bad network card or noisy connection and simply drops a connection on any such error. It is the safest thing to do in network communication: If there is any error during processing of the network connection, close it immediately and let the client reconnect. Your client software should be able to cope with that by using the information returned in the error cluster. Generally a robust network client would treat error 56 as an indication to retry the last operation one or more times (but not indefinitely) and if the error 56 persists or any other error occures, close the connection and attempt to reopen it.
  9. The ref num goes around the loop but the error cluster goes through the loop and then to the two Close Refnum nodes. At least that is how it looks in the picture. Maybe the real wiring is behind the loop but that would be a major style fault. Unfortunately the VI Snippet resource seems to get lost between posting to LAVA and downloading it to my computer, so can't really check it.
  10. Shouldn't really happen, since the error cluster is wired through (at least it looks like it is, didn't check in the actual code).
  11. Well, the code you claim causes problems in LabVIEW is commented out in the VBA code. So are you sure it does anything else in VBA than in LabVIEW if you enable the code?
  12. Other controls?? I'm pretty sure the Picture Control is still about the only one which allows that! Also note that its background is light blue, indicating that it is considered an Advanced (scripting) Feature. Also graphs do have a Cursor property, since about LabVIEW 4 or so but that is for something very different!
  13. That is not a correct analysis and the solution is only one way to solve the problem. The real problem is not a relative path but simply the fact that your DLL depends on another DLL. No path is stored in your DLL to the other DLL, just its name. Windows when asked to load a DLL will scan the entire import list of that DLL and load any dependency of that DLL too. For that it looks in following locations: 1) It looks if the current process has already loaded a DLL with the same name, if so it is simply linked to the imports of the DLL currently loaded 2) It then looks in the same directory as the executable file of the current process 3) Next it will look in the <System> directory 4) Then in the 16 bit <system> directory 5) Then it will look in the <Windows> directory 6) Next is the current directory (that is the directory where the latest operation was done from inside the current process, that can be the double click to start the application or any file dialog box that is dismissed with anything but Cancel is selected, or an explicit call to the SetCurrentDirectory() API) 7) Last but not least it will look in any directory listed in the PATH environment variable In Windows XP and earlier point 6) is by default placed between 1) and 2) placing your secondary DLLs into the LabVIEW.exe directory is the safest location, but gets quickly a mess if you have more than one or two such DLLs. It is also a hassle to remember to include those DLLs into your application executable build and make sure they get into the root directory of your application. The proper solution is to have an installer for your DLL that takes care about installing all dependencies correctly too, and that installer should be created by the supplier of your DLL.
  14. And it should definitely do make you feel uneasy! Doing that is a guaranteed recipe for disaster somewhere down the road. Even using the undocumented LvVariantGetDataPtr() function and friends is only slightly better for anything that you intend to have used by other people. Since it is undocumented, NI is free to change its prototype, semantics, or discontinue it altogether whenever they decide so. Yes they would have to review several other internal projects to adapt to the new interface which is a hassle and therefore they will think three times about doing that, but it is possible and manageable as they have all the control over every piece that makes legitimate use of this function. Once the function is publicly documented, it is carved in stone for eternity and no changes in any way are really possible anymore. You may understand the implications of using such a function in your code, but if you ever distribute your library to other people they will most likely have no clue at all about the entire C code interface in general and the use of an undocumented LabVIEW API in special and with a new LabVIEW version everything may fall to pieces for them. The proper way to handle this would be to get someone from NI give you a (semi)-official document that does document these functions. If you can manage to get that, then you can be somewhat confident that the LabVIEW team feels fairly safe about this API to be a standard for many versions of LabVIEW to come. It still can break for many reasons in the future, such as modifications to the LabVIEW source code to support new hardware architectures or such, but at least you have some assurance that someone in the knowing believes this is a permanent API.
  15. The sources for all OpenG libraries are on sourceforge. There is a project for the "OpenG Toolkit" and a separate project for "LabPython", since LabPython predates the OpenG Toolkit by a few months. The first search result in Google points to the LabPython home page hosted on sourceforge and has links to the the sourceforge project page where you can go to the code section and see that it contains both the LabVIEW and C code. It's still in CVS but there is an option to download the entire repository as GNU tarball, so no need to install a CVS client if you don't want to. As to the reason why it may crash, when you add ROOT to your python project, there are many possibilities. LabPython was developed with Python 2.3. It seems to work fairly well for most people with Python versions < 3.0, but there seem to be problems with certain Python libraries that contain binary components (C(++) DLLs compiled as Python modules). The reason is probably some version conflicts in runtime libraries between LabVIEW, the LabPython DLL and those binary Python modules. Hacking your own ROOT script interface based on LabPython might be a possibility but unless you are really deep into C programming I wouldn't recommend it.
  16. 1) is officially not only not supported by Apple but according to them fully illegal and actively frustrated. 2) you need to buy a Mac license 3) and further are in principle correct but because of 1) difficult and illegal to do
  17. Actually most modern text code IDEs have nowadays auto-intend with configurable code style rules so there certainly exists a "make code look nice" function there, although it is usually a menu and not a button.
  18. To add to your original question: No the Twain API is not trivial to call from an environment like LabVIEW. It is based on a very old Windows 3.0 paradigma that communicates through the applications windows event queue with the client and this windows event queue is pretty well hidden from the normal LabVIEW level where you normally operate inside VIs. For a big part this is because each LabVIEW platform has a fundamentally different window manager interface that had to be handled in LabVIEW in a consistent manner for all platforms. So this sits deep in the guts of LabVIEW and is only with some low level Windows API magic accessible in a way that allows to handle the Twain messages properly. I developed in the past such an interface for some internal projects and it worked, but is still quite a stretch from something that could be released to the greater public without risking disappointment by many developers who would go about using it. It worked for me because I knew how to call it (and what not to try to do) and because I could go into the C code and debug the issues if any surfaced. But it was a very painful debugging experience since if you try to single step into those parts of window event handling you are generally creating all kinds of hard deadlocks and race conditions on both the standard Windows event handling level as the more specialized LabVIEW windows manager layer.
  19. Well, it is quite possible that the first section of the structure needs to be filled in with specific values that tell the function what to return in the union and for what resource (device, subunit, or whatever). So having even one value off might simply cause the function to error out. Have you checked the function return value itself to not indicate some error condition?
  20. Well the sval is not a pointer but a fixed size string or byte array and as such must be inlined in the structure. Your bdrbag_byte_cluster.ctl is as such the most accurate control to use. However it only matches the Visual Basic definition not the original C definition as in there it is really 1500 bytes long, not just 127. As long as you are sure that the underlying function is not trying to write past byte 127 there won't be a problem though. All the other typedefs are not suited to resemble the C structure declaration in any way. And candidus, alignment is not an issue for this particular structure. The alignment rule specifies that each structure element is aligned on the smaller value of either the integral element size or the alignment value. Here all numerics are 32 bit sized and align therefore automatically on their natural position and the string has an integral size of 1 byte and has therefore no alignment requirement.
  21. Theoretically there could be some use, making the conditional compile structure unnecessary, but!! It would violate a very standard paradigm that LabVIEW has kept intact since its inception as multiplattform development system: A flattened datatype is on all systems the same format! Either that or the Flatten function would have to treat the special pointer typed datatype everywhere as 64 bit entity (and we would have to hope that the 128 bit pointers are far enough into the future that this wouldn't be obsoleted at some time or require a new large pointer type for the whole purpose of maintaining the flatten format consistent. Personally I find this anyhow rather academical, since if you start to deal with API calls with such parameters the time is ready to write an intermediate shared library which translates between this type of structure and a more LabVIEW friendly parameter list. In there the compiler will typically take care of any target specific bitness issues automatically (with some care when writing the C code to not introduce bitness troubles) and the LabVIEW diagram stays clean and proper for all platforms.
  22. While the minimum version for OpenG submission is still currently 2009, I think it is ok to place code for discussion in a newer version, if it is not just the latest and greatest. 2011 would seem like a very workable version for almost anyone here.
  23. The sourceforge repository for OpenG uses SVN which does not have pull and push requests like GIT. So the administrator of the OpenG Toolkit project, which I believe is still Jim Kring, would have to add your sourceforge ID to the project before you can actually commit anything to it. Anyone with commit rights can change anything about the OpenG Toolkit so it is not a right that everybody out there should have. In general it is anyhow preferable to have some discussion beforehand about proposed changes before committing anything to the repository.
  24. It's not really that difficult to stream data over a TCP/IP connection and in fact it is a bit more trivial in LabVIEW than in C(++)(#) but even there it is doable. You need to take care about byte order, which is big endian if you use the native LabVIEW flattening functions and also padding but in general LabVIEW is packing data as much as possible, except for booleans which are sent as byte. So you (or your collegue) will likely want to use some sort of C# library that allows to send data in big endian form over a stream. Most likely you will need to have some specific code on the C# side to flatten and unflatten the structures into and from the stream. Writing a general purpose library that can flatten and unflatten any form of structure into stream is most likely to much of a hassle, also because C# doesn't really know something like a cluster but uses classes for everything. So there is not a strict order in memory like for a structure in C. You could of course use create a library that uses reflection in C# to stream arbitrary structure classes on a wire but you have to be very careful that the order of elements in the class definition would stay consistent with what you use on the LabVIEW side in the cluster.
  25. I think the best approach is to actually post your proposed fix here for discussion. There will usually be some discussion about it and if it is considered useful and also doesn't break existing applications significantly, it is quite likely that it gets included in the next release, whenever that might be. But significant improvements to the code as it is in the sourceforge repository certainly warrant the effort to go through the hassles of releasing a new package. Unfortunately the current procedure about who does a new release is a bit unclear. I lack the detailed knowledge about the actual release procedures and also the time to commit to doing this on a regular base. Jonathan Green did a great job in releasing new packages when there was something to release but his focus has been shifting to other areas lately, which is unfortunate but of course his full right. But getting the discussion started about a proposed fix is for sure the first step anyways.
×
×
  • Create New...

Important Information

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