LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How to properly call a C function with unsigned char

Hello,

 

I try to call this function in a CLFN:

DLLIMPORT int ReadDataFromConfig(
unsigned int devID,
unsigned int offset,
unsigned char *output,
unsigned int length
)

 

When creating the VIs from the Import Shared Library tool this function prototype in labview is:

int32_t ReadDataFromConfig(uint32_t devID, uint32_t offset, CStr output, uint32_t length);

 

The problem is that when I call the function, the returned values are not what I'm expecting.

 

The function should return a table of characters sized by the input parameter length.

Should I pass an U8 table sized by length instead of the CStr Output ?

 

Thanks

0 Kudos
Message 1 of 8
(4,013 Views)

Hi

The C-function is expecting a pointer to a memory area of size "length".

Setting up the LV interface it should be possible to get a string in that place.

 

Gabi

 

Do you have an example of your code ?

7.1 -- 2013
CLA
0 Kudos
Message 2 of 8
(3,994 Views)

Can you show your LabVIEW code? Do you have any documentation for this function?

 

You need to pass an initialized string of the appropriate length into the CLFN for the string (unsigned char *) output. Alternatively you can pass in an initialized array of U8 values passed as an array by Array Data Pointer; it will do exactly the same thing as far as the DLL function is concerned. To create an empty string, use Initialize Array to create an array of U8, then use Byte Array to String to convert to a string. You should pass the length of that string as the length parameter. This tells the DLL to write the output into that memory, and not to write more than length bytes.

0 Kudos
Message 3 of 8
(3,992 Views)

Hello All. 

I'm new at using tabview to call DLL functions, and I have this structure definition, but my DLL does not accept one or more of the parameters that I defined in my type def.

 

typedef struct { 

  unsigned int  arbitrationBitRate;

  unsigned int  sjwAbr;              // CAN bus timing for nominal / arbitration bit rate

  unsigned int  tseg1Abr;

  unsigned int  tseg2Abr;

  unsigned int  dataBitRate;

  unsigned int  sjwDbr;              // CAN bus timing for data bit rate

  unsigned int  tseg1Dbr;

  unsigned int  tseg2Dbr;

  unsigned char reserved;            // has to be zero

  unsigned char options;             // CANFD_CONFOPT_

  unsigned char reserved1[2];        // has to be zero

  unsigned int  reserved2;           // has to be zero 

} XLcanFdConf; 

 

I'm attaching the ctl defined as I understand. Can someone spot the problem with my definition?

Thank you. Amazing forum.

0 Kudos
Message 4 of 8
(3,118 Views)

I've been away from C for a long time, but here are the 2 things I think you need to do.

 

1. Figure out the "bitness" of the dll so you know how many bits there are in an unsigned int.  These days, I'd expect it might be either 32 or 64, depending on compiler options.  (Back in my time, it was 16 for an int, 8 for a short or a char, 32 for a long).

    Then you'll need to change the datatype representation in your typedef to match all the unsigned int fields.

 

2.  You don't want an array of u8's in your LabVIEW typedef.  A LabVIEW array datatype includes a prepended 4 byte length before the bytes used for the data itself.  The C array won't have the length bytes.

   I'd just make 2 consecutive u8 fields with names like reserved_1A and reserved_1B to match the C-style memory layout.  (I *think*, but am less than 100% sure, that a LabVIEW cluster with 2 u8 elements would also match the C-style memory layout.)

 

Beyond that, there's a chance you may also need to account for further compiler options that define how byte boundaries are enforced for structs.  (Sometimes struct fields can occupy more memory space than strictly necessary in order to start each field at a multiple of, say, 4 bytes.)  I've been away from C compilers far too long to speculate on the likelihood or how to investigate.  Just giving you an alert in case things still crash.

 

 

-Kevin P

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
0 Kudos
Message 5 of 8
(3,108 Views)

""A LabVIEW array datatype includes a prepended 4 byte length before the bytes used for the data itself.  The C array won't have the length bytes.""

 

This helped me a lot to solve the problem. thank you.

0 Kudos
Message 6 of 8
(3,081 Views)

@trncrboy wrote:

""A LabVIEW array datatype includes a prepended 4 byte length before the bytes used for the data itself.  The C array won't have the length bytes.""


That's only very partially true and not even the main problem here! Do you know any C? If you do the LabVIEW data structure you created will pass this datatype to the function:

 

typedef struct (
  int32_t numElm;
  uint8_t elm[];
} LVArrayRec, **LVArrayPtr, **LVArrHdl;

typedef struct { 
  uint8_t  arbitrationBitRate;
  uint8_t  sjwAbr;              // CAN bus timing for nominal / arbitration bit rate
  uint8_t  tseg1Abr;
  uint8_t  tseg2Abr;
  uint16_t  dataBitRate;
  uint8_t  sjwDbr;              // CAN bus timing for data bit rate
  uint8_t  tseg1Dbr;
  uint8_t  tseg2Dbr;
  uint8_t reserved;            // has to be zero
  uint8_t options;             // CANFD_CONFOPT_
  LVArrHdl reserved1[2];        // has to be zero
  uint8_t  reserved2;           // has to be zero 
} XLcanFdConf; 

 

Pretty much every element in there does not match the data element type in your declaration that you show!! uint8_t is NOT equal to int! It's equal to unsigned char!

And as you can see the LabVIEW array is a handle (a pointer to a pointer to a data structure containing the array data with a prepended 4 byte size integer.

As has been over and over mentioned in this forum in virtually umptien threads, fixed size C arrays embedded in a struct need to be represented in LabVIEW by a cluster with the according number of elements of the correct datatype in there.

And of course you need to make sure that the other elements are correct in size. (unsigned) int is equivalent to an (unsigned) int32 on every LabVIEW platform since the demise of the Windows 3.1 version of LabVIEW.

Rolf Kalbermatter
My Blog
0 Kudos
Message 7 of 8
(3,065 Views)

To the OP:  listen to @rolfk before listening to me (or practically anyone else).  I'd consider him the preeminent active expert around here about these kinds of things (among many others).

 

 

-Kevin P

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
0 Kudos
Message 8 of 8
(3,058 Views)