Jump to content

Rolf Kalbermatter

Members
  • Posts

    3,776
  • Joined

  • Last visited

  • Days Won

    243

Posts posted by Rolf Kalbermatter

  1. 12 hours ago, bjustice said:

    Would love to know what you guys think.

    I always use Unflatten from String/Flatten to String. It even has a third Endianess selection to never byte swap. It may be not as fast as MoveBlock but has been fast enough so far for me.

    The only thing I don’t like about it is that it forces String on the flattened side but a Byte Array to String or String to Byte Array solves this.

    It would be trivial for the LabVIEW devs to allow Byte Array too, just a flag in the node properties that would need to change and should have been done so 20 years ago and set as default as a first step to allow the divorce of String==Byte Array assumption that still hampers proper adoption of non ASCII strings in LabVIEW.

    I even hacked a LabVIEW copy in the past to allow automatic adaption of the Unflatten from String Node to Byte Arrays but that was of course a completely undistributable hack. An according LabVIEW Idea Exchange suggestion from me was acknowledged by AQ himself but dismissed as highly unlikely to be implemented by LabVIEW R&D.

    https://forums.ni.com/t5/LabVIEW-Idea-Exchange/Allow-Unflatten-from-String-to-also-accept-an-Unsigned-Byte/idi-p/3968413

  2. On 7/29/2021 at 3:14 PM, Yair said:

    I'm attaching some of Rolf's VIs from years ago. They do include code for writing an image to the clipboard (see the example in clipbrd.llb and look at the control or panel buttons). This would probably require adapting if you're on 64 bit LV.

    Clipboard - RolfK.zip 629.71 kB · 13 downloads

    For anyone looking at this library, I did an update in LabVIEW 2009 to properly support both 32-bit and 64-bit LabVIEW without any potential trouble.

    https://forums.ni.com/t5/LabVIEW/LV-slows-down-extremely-when-having-large-contents-in-clipboard/m-p/4251413

  3. Quote

    So, when I hit write for one case, it will upload that specific code. Any tips?

    What is a panther programmer? How do you interface to it?

    Your problem description sounds mostly like a basic LabVIEW programmer problem.

    Have you done some online programming courses and tutorials? Do you know how to write a simple LabVIEW program?

  4. 9 hours ago, Lipko said:

    Thanks for the comment and also the info about the GDI thing. I have a small issue with dashed lines appearing solid or very dense when printing (yes, I use the printer method) also present in DiAdem, and I will research if it's also related to GDI.

    Edit: no, it's the printer that's causing the linestyle issue.

    It may be the printer or its printer driver.

  5. 4 hours ago, paul_cardinale said:

    Do you know of a way to invoke the font dialog?

    image.png.ce8bd5966043266ec896005f014f2551.png

    Actually, there is no direct way to call it that I would know of, but it should be possible to send the according menu command to LabVIEW. But what do you want to do then? This is not a vi, but an internal LabVIEW dialog. It does use a front panel resource like what VIs use but it is not a VI, the entire programmatic handling is a C code function.

  6. 2 hours ago, Neon_Light said:

    So I can give the adres of handle to testDataBlock.dataRecords, like this:

     

    and thats it ? 

     

    when I try the code above I get:

    a value of type "DataArrayHdl*" cannot be assigned to an antity of type "DataArrayHdl"

    in the line: 

    testDataBlock.DataRecords = &handle;

    Can anyone tell me what I might be doing wrong ?

    Please, follow a C programming course first and work through it until you get to the advanced topics including memory pointers! This is not LabVIEW but C programming.

    You are missing very fundamental pointer knowledge!

    testDataBlock.DataRecords = (DataArrayHdl)handle;

    Alternatively you can write the code directly like this.

        size_t len = offsetof(DataArrayRec, elms) + size * sizeof(DataRecord)
        if (!testDataBlock.dataRecords)
        {
            testDataBlock.dataRecords = (DataArrayHdl)DSNewHandle(len);
            if (!testDataBlock.dataRecords)
                err = mFullErr;
        }
        else
        {
            err = DSSetHandleSize((UHandle)testDataBlock.dataRecords, len);
        }

    And you need to do that every time again.

    testDataBlock is on the stack, this stack gets invalidated every time you leave your function. That is why we do a DSDisposeHandle() before leaving the function, to deallocate the previously allocated handle before the stack is invalidated and the handle lost forever.

  7. 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;
    }

     

    32 minutes ago, Neon_Light said:

    How do I change the code when I want to change the array from int int,  to int double? Can I use this piece of code you gave earlier:

     if (!handle)
        {
            handle = DSNewHandle(sizeof(DataArrayRec) * (size - 1));
            if (!handle)
                err = mFullErr;
        }
        else
        {
            err = DSSetHandleSize(handle, sizeof(DataArrayRec) * (size - 1));
        }

    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);
        }

     

    32 minutes ago, Neon_Light said:

    And change the adres where  to testDataBlock.dataRecords points ?

    the handle is it easy to explain whats done here is it that the Labview functions add some extra bytes to make every variable the same size e.g. when I have char and a int they ad 3 chars for the char to make the size the same as a int or is there more going on?

    Sorry mate, but this sounds gibberish and I have no idea what you mean.

  8. On 6/26/2023 at 11:19 AM, Lipko said:

    Hmm, that print to PDF method is pretty amazing, I wonder why it seems so unfinished (rotated texts become bitmaps, overlapping things may or may not become bitmaps, etc)

    So: maybe everybody already knew that, but picture controls are actually vector based. Lines are pretty, smoth vector lines, texts are texts that will be selectable in the pdf, etc. I'm shocked....

    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.

  9. 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!

  10. On 6/25/2023 at 9:46 PM, Neil Pate said:

    OK, this is what I remember.

    Hardware was something like this:

    • cRIO
    • Ethernet switch
    • Industrial modem (Teltonika something... you put a SIM in and connect the ethernet to the switch)

    Security I just had to kinda figure out. I think I got it working in the end, check out this thread: 

     

     

    The big question mark for me was how I was going to manage the cRIO remotely as my LTE connection could not guarantee a fixed IP address, so I had no simple way to connect to the cRIO after it had been deployed in the field. Finally we decided that we would actually need a PC anyway for something else, and the cRIO would be connected to that. The plan was to remote desktop into the PC and then connect to the cRIO that way, or get the dynamic IP address of the cRIO. Or maybe the idea was to the cRIO to broadcast somewhere its IP address. The project was put on ice and never deployed to the field, so I was not able to test these assumptions.

    People do get stuff like this to work, so I am sure somebody had a solution for these problems.

    Hope this helps!

     

    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.

    • Thanks 1
  11. 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.

     

  12. 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.

  13. On 4/24/2023 at 5:23 PM, dadreamer said:

    No, don't pass LabVIEW arrays straight to the cluster! They are different entity than those in C/C++. In order to match your struct definition, you have to turn each array into a separate cluster. Use Array To Cluster primitive for that. RMB click -> Cluster size on it allows you to specify the output cluster size. Then bundle all the clusters into one (plus three int parameters), then pass that resulting cluster to your CLFN. I assume, you know your .so's calling convention.

    Oh, I forgot to add, that Array To Cluster node doesn't accept more than 256 elements. So, if SV_STRING_SIZE is 512, you need to make a pairs of 256+256 elements (e.g., two "id" clusters, two "vendor" clusters etc.). There's another way with DSNewPtr+MoveBlock, but it's a bit more advanced.

    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.

    • Like 1
  14. 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.

  15. 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.

  16. On 5/19/2023 at 12:23 PM, MapleBay said:

    Hello!

    When I set "Defer panel update" to false for top layer VI, will subpanels in my top layer VI be affected?

     

    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.

  17. On 6/5/2023 at 11:18 PM, Lucky--Luka said:

    Hi everyone
    I need to make a VI that receives 4-byte hexadecimal values as ASCII strings from a CAN-USB interface. I am using an Arduino CAN schield with a firmware that I have not personally written and that I still haven't access to. I do have a problem with the format in which I receive the values. To get the exact value I should add 0 in the middle of the values when missing.
    I give an example to explain better.
    I get the string:
    2 8 D5 0 0 0 0 B 5 70 <CR><LF> (value: 46448)
    I'd like to interpret it as:
    2 8 D5 0 0 0 0 B 05 70 <CR><LF> (value: 722288)
    I'll give another example.
    I get the string:
    2 8 D5 0 0 0 0 B 4 5 <CR><LF> (value: 2885)
    I'd like to interpret it as:
    2 8 D5 0 0 0 0 B 04 05 <CR><LF> (value: 721925)
    The maximum value I can read in this case is 1000000 in any case.

    After I have added the zeros where needed in order to have always groups of two characters I can make something as in the attached VI to get the number that I am looking for.
    Does anyone have an idea what algorithm I can use? Thank you!

    ASCII-HEX.vi 6.73 kB · 2 downloads

    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

  18. 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.

  19. On 3/25/2021 at 2:45 PM, Fábio Nicolas Schmidt said:

    I am using the MCP2221 to read analog values from an ADC MCP3424, and noticed a bug when reading bytes from the analog data register.

    image.png.40e27cadb62c4a80c0552fccce08e0c8.png

     

    Do you have any workaround for this issue? I tried to download latest driver and DLL, but still no luck solving this.

    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).

    • Like 1
  20. 16 minutes ago, viSci said:

    Later this afternoon I plan on remoting into the server.  Could you suggest a specific MSC runtime to try?

    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.

  21. 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.

  22. 2 hours ago, ShaunR said:

    So I guess you have a Ham Radio licence? It's exactly what my Ham Radio buddy said.

    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.

×
×
  • Create New...

Important Information

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