1

So, as the title says, I'm in a struggle with translating a few functions for calling DLL, which I have documentation about in C, but I need to use it in Delphi.

After few initial tries, and after solving some compiler errors after translation, with the help of you guys (topic here), some of them still doesn't work. Mostly it's the problem with variables as parameters...

First the subject: I bought an USB logic analyzer and oscilloscope, made by some Czech company, which comes with rather basic and limited software, but has a DLL and (poor) documentation on how to implement it in our own applications in order to communicate with the analyzer.

Now, this documentation (found here) has several functions, written in C (code paragraph 1 below). I've translated them all to Delphi (code paragraph 2 below), but only got around half of them working.

I'd need some help to determine where the issue stands:

  • Is it in my translation of the functions to Delphi, or is it somewhere else?
  • Can it even be done via Delphi, or not?
  • Is the documentation too poor to be able to implement it in Delphi, or is it enough?

Note: All of the functions and all data communication work correctly using original software! Therefore, I believe it's safe to assume that everything that isn't working is the issue in either DLL or my Delphi code, not of the device itself...


int SetAnalogChannels(int CH1Gain, int CH2Gain, bool CH1Couple, bool
CH2Couple, bool CH1Multiplier, bool CH2Multiplier)

CHXGain: Possible values are 10, 20, 50, 100, 200, 500 mV/div. Send just the integer to set this value

Here, I have trouble sending the int CH1Gain and int CH2Gain. Device always returns 0 to the function, which means that Gain parameters are invalid. Don't have a clue of why...

function SetAnalogChannels(CH1Gain, CH2Gain: integer; CH1Couple, CH2Couple,
                           CH1Multiplier, CH2Multiplier: boolean): integer;
                           stdcall; external 'E_l80.dll';

long RetrieveDSOData(unsigned char whatchannels, double *DSOCH1,
double *DSOCH2, unsigned short *LADATA, unsigned char Nth_Sample)

DSOCHX: A pointer to an array of voltage points from the DSO channels.
LADATA: A pointer to an array of LA data.

Here, I have no idea what that types should be, if they really are pointers to the array (although there's no [] marks. But from logical view of the device, it should be an array. With max 32 values...).
Edit: I just figured out my mistake and shallow reading of the docs. The return of the function gives the exact size of the arrays!

function RetrieveDSOData(whatchannels: uchar; var DSOCH1, DSOCH2: TLAArray;
                         var LADATA: array of ushort; Nth_Sample: uchar):
                         longint; stdcall; external 'E_l80.dll';

float SetUPPS1(float Voltage)

Here, it's strange. It seems like I set it correctly, however the function return is always 0, although it should be some other value. I used "extended" for the float type... I can see I set it correctly since another function gives me the current status, which changes with this setting...

function SetUPPS1(Voltage: extended): extended; stdcall; external 'E_l80.dll';

long SetupAWG(double *AnalogVoltage, short *DigitalData, long
BufferSize, double DCOffsetVoltage, double SampleFrequency, long Use4xGain, double
OutputImpedance, long Repeat,long Triggered, long OverrideOtherClocks)

AnalogVoltage: A pointer to an array of voltages;
DigitalData: A pointer to an array of digital data;

Here, same issue as above with arrays. However, based on the usage, I believe this arrays are the one to be sent, not received via parameter, therefore the "var" here might be wrong?

function SetupAWG(var AnalogVoltage: double; var DigitalData: short; BufferSize: longint; 
                      DCOffsetVoltage, SampleFrequency: double; Use4xGain: longint; 
                      OutputImpedance: double; Repeat_, Triggered: longint; 
                     OverrideOtherClocks: longint): longint; stdcall; external 'E_l80.dll';

Now, as you might see, I changed the types to Delphi equivalent, at least as far as I know I did it the right way.

If anyone knows answer to any of these things, or sees any mistake, I'd be glad to see that in comments/answers.

If I defined this bad, please point me to the right directions and give me a hint instead of comments about me being wrong. They kind of don't help... :/

Thanks a lot.

8
  • Sorry. You were too fast! I had to finish it, since I got left out of the battery power before... Commented May 16, 2015 at 2:36
  • Huh. Bdw, @Remy, and Ken - Thank you. I'm all too unfamiliar with this formatting.... Commented May 16, 2015 at 2:39
  • 1
    This seems like a very broad "translate this code for me" request. SO is designed around being a "question and answer" site, not "many questionS for you to answer". Typically, you'd request translation of a single function, with the information you have and your efforts to translate it, and we'll try to help. You've written a whole long laundry list of questions, and asked us to basically translate it for you. You seem to be quite lucky that Remy has made an effort to help (he must be bored); you may not fare so well in the future. :-) Commented May 16, 2015 at 2:47
  • @KenWhite, thank you for your comment. I did try to make it as "short" as possible, and I hoped to give the impression, that I did translate it, but since partially works partially not, didn't know how to go on. +, each function had different parameters that were unsafe for me to deal, so I wrote different ones ( but not all of them). I definitely did NOT intend to ask something like "please translate this for me", at all. On a side note, I did start with just partial question in another topic. It's not about translating, and you can be sure I'm very thankful for your (and Remy's) efforts. Commented May 16, 2015 at 3:03
  • I'm aware you started in the other topic; I answered your question there. I have doubts about "as short as possible*; see my previous comment about 1 question/1 answer. You can always link a second question back to the first (and a third back to the first, and a fourth back to the first) in order to avoid repeating information, and still stay within the 1Q/1A guidelines. The reason for the guideline is that Remy could translate one function in his answer, and I could translate a different one in mine- which one would you mark as accepted with the green check if they're both correct? Commented May 16, 2015 at 3:14

1 Answer 1

2

It would be more useful to see the DLL's actual .h file instead of documentation, as documentation tends to not mention what the calling conventions actually are (and this case is no exception). You are declaring your Delphi functions as stdcall, which may or may not be correct. cdecl is another commonly used calling convention in DLLs, especially since it is C's default calling convention. So, if the functions are not declared with ANY explicit calling convention in the .h file, assume cdecl instead of stdcall. For this discussion, I will assume cdecl unless shown otherwise.

int SetAnalogChannels(int CH1Gain, int CH2Gain, bool CH1Couple, bool CH2Couple, bool CH1Multiplier, bool CH2Multiplier)

function SetAnalogChannels(CH1Gain, CH2Gain: Integer; CH1Couple, CH2Couple, CH1Multiplier, CH2Multiplier: Boolean): Integer; cdecl; external 'E_l80.dll';

long RetrieveDSOData(unsigned char whatchannels, double *DSOCH1, double *DSOCH2, unsigned short *LADATA, unsigned char Nth_Sample)

As the documentation says, these are pointers to arrays. I would translate them as-is, don't try to convert them to any fancy Delphi syntax:

function RetrieveDSOData(whatchannels: Byte; DSOCH1, DSOCH2: PDouble; LADATA: PWord; Nth_Sample: Byte): longint; cdecl; external 'E_l80.dll';

float SetUPPS1(float Voltage)

You converted this to Extended, which is wrong. Delphi's Single is equivalent to C's float:

function SetUPPS1(Voltage: Single): Single; cdecl; external 'E_l80.dll';

long SetupAWG(double *AnalogVoltage, short *DigitalData, long BufferSize, double DCOffsetVoltage, double SampleFrequency, long Use4xGain, double OutputImpedance, long Repeat,long Triggered, long OverrideOtherClocks)

Same as above for the arrays:

function SetupAWG(AnalogVoltage: PDouble; DigitalData: PShort; BufferSize: Longint; DCOffsetVoltage, SampleFrequency: Double; Use4xGain: Longint; OutputImpedance: Double; Repeat, Triggered, OverrideOtherClocks: Longint): longint; external 'E_l80.dll';
Sign up to request clarification or add additional context in comments.

11 Comments

So, 1st one: Still returns 0, even with cdecl instead of stdcall. 3rd one: solved. The Single instead of Extended works as it should. Thanks! 2nd one: is this correct to be without var for both pointers..? Anyway, either with var or not, with stdcall or cdecl, the app always hangs when I try to call it. Same goes for No4.
On your side note: var SerialNumber is a pointer; it just can't be NULL (nil in Delphi). SerialNumber has to be a variable that a return value can be assigned to; a pointer can be NULL, in which case the function knows you didn't pass a value. If the function returns information in the parameter, var is appropriate. If the parameter is optional, you should use a pointer type so you can pass nil. (My side note: Remy was nice enough to answer many questions on what is desinged to be a one question/one answer site, and you then ask another separate question in comments? Rather rude...
Yes, it is correct to use pointers without var in RetrieveDSOData() and SetupAWG(), in fact that is why pointers are being used in the first place. var does not make sense in those functions as they are array parameters. In the case of GetSerialNumber(), it is OK to replace the pointer with var since it is a single value being passed.
@KenWhite: actually a var parameter can be set to nil, you just have to use a type-cast to force the compiler to accept it. Sometimes people incorrectly declare a pointer parameter as var and then find out later that they need to pass a nil value to it. Type-casting a nil to a var parameter does produce correct machine code. Passing nil to a variable parameter
@KenWhite: I agree that the declaration should be fixed in that situation, but that is not always possible, depending on how the function is being used. Thus a workaround is possible, at least.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.