Plugin-DLLs - LOTUS interfaces, supported features?

  • I see that I have to set up a timer:TTimer, and I guess I initialize it in the PluginStart procedure (add interval, enable it...etc).

    That's absolutely correct. And don't forget the "timer := TTimer.Create(AOwner) at the beginning. :-)


    And in PluginFinalize, you have to free it by FreeAndNil(timer) (you have to add SysUtils to the uses-block)

    I add a timer as a variable globally?

    That's correct, too.

    Should I inherit my "onTimer" event handler procedure from something

    No, that's quite easy: Just declare a procedure in the given format, in this case: procedure Blablabla(Sender: TObject). The parameter Sender tells you, which object did call this procedure, but in your case, this information is unneccessary.


    Then, while setting up timer, you add this handler procedure by setting timer.OnTimer := Blablabla.

  • I'm probably messing up something, because I still get errors for the parameterlist of the OnStart usage.


    My code looks like this (well, parts of it):



    However the compiler doesn't like this much, since I get these errors:


    Compile project, output: EV_fulke.dll: Exit code: 1, Errors: 2

    EV_fulke.lpr(82,20) Error: Wrong number of parameters specified for call to "sendData"

    EV_fulke.lpr(37,11) Error: Found declaration: sendData(TObject);

  • OK, I sorry, I did a mistake:


    OnTimer has to be a method of an object, so this could be the problem.


    So please try this declaration:


    - between the uses and the var section, you add this:

    Code
    1. type
    2. TMainClass: class
    3. public
    4. Timer: TTimer;
    5. procedure SendData(Sender: TObject);
    6. constructor Create(_aowner: TComponent);
    7. end;

    - In the var section, you don't declare "timer : TTimer;" but "MainObj: TMainClass;"

    - you add a "TMainClass." before the "sendData":

    Code
    1. procedure TMainClass.SendData(Sender: TObject);
    2. var
    3. ...
    4. begin
    5. ...
    6. end;

    - implement the constructor like this and add the timer initialization:

    Code
    1. constructor TMainClass.Create(_aowner: TComponent);
    2. begin
    3. Timer := TTimer.Create(AOwner);
    4. Timer.Interval := 50;
    5. Timer.Enabled := True;
    6. Timer.OnTimer := SendData;
    7. end;

    - instead of creating and removing the timer in the PluginStart and PluginFinalize, create and remove here the MainObj:


    Does this code compile?

  • Unfortunately not. :/

    After the var section I placed the constructor, THEN the TMainClass.SendData (which is followed by pluginstart, pluginfinalize and receivefloat).


    For that I receive 2 errors:



    At this point I don't even dare to guess what its problems are...



    BUT: after that I modified to the old, very not desired way, so it uses a counter to send data in every 25th frame, so I could test my setup. What happened is that the serial communication was faulty, sometimes it sent the correct values, sometimes it sent random or null values (my gauges were all over the place, my lights were flickering). Out of curiosity I disabled multithreading in the settings and...it would work. It didn't flicker, it sent constantly the correct values. Is it possible, that still, multithreading handles things like that so badly?


    Also I know I made a different topic for that, but map and vehicle lights are still flickering and glitching for me in night if multithreading is enabled.



    P.S: is it normal that I cannot attach any files when replying?

  • I actually got fed up with trying with delphi, so I started to port the whole plugin script into C (more exactly WinAPI C). Which sounds terrible, maybe it is, but I'm more familier with C, so... :D


    Since I could finally make a timer with it, it is finally working, though I needed a few days of fine-tuning the serial communication, because otherwise the arduino's buffer got corrupted and all my ligths were flickering like a christmas tree.




    However I found some interesting error in the lexikon articles, and please don't mind that I don't start a new thread for it in the feedback section. In the DLL article Janine quotes some type definitions for C/C++/C# language:


    I actually think some of these are not correct. First, variables. In delphi, Single is a 4 byte long real type (according to wiki.freepascal.org). Float is not even listed in the wiki. On the other hand, default LOTUS scripts use type "word", which is NOT in this typedef. Word is by the way a 2 byte unsigned integer. Therefore, "unsigned short" for single is absolutely wrong, since we want to represent real values, but we only use a 0...65535 range integer.


    Secondly, the functions. With function headers like this I could not make them work. I had to add "__declspec(dllexport)" to them, but what's more interesting is that ReceiveVar... functions don't even share the same header here, as in LOTUS script system. E.g. for floats it's like that:


    ReceiveVarFloat(varindex: word; value: single)


    and not like that:


    ReceiveVarFloat(Single VarIndex, Float *Value)


    Not only that single is not the same as word, but also why the dereference at value? We copy variables not their pointers.



    I ended up using something like this: