2

A few years back for one of my applications I moved my serial handling to a thread when a certain app had to respond very quickly to certain serial events.

It was in BDS2006, with an older version (some 3.x?) It was done by having code like this in the tthread.execute:

    while ...
          begin
          events:=[evRxChar];
          { Prepare a stop event for killing a waiting communication wait. }
           try
             comport1.WaitForEvent(events,stopevent.handle,500);
             if evRxChar in events then
               ComPort1RxChar(comport1,comport1.InputCount); // method of thread.
           on e: exception do {only logs} ;
           end;

Initialization was like

procedure TSerThread.initcomport(comportname:string='COM1');
begin
 comport1:=tcomport.create(nil);
 ComPort1.BaudRate:=br115200;
 ComPort1.DataBits:=dbEight;
 ComPort1.Port:=comportname;

 ComPort1.StopBits:=sbOneStopBit;
 ComPort1.Events:=[];
 ComPort1.Connected:=true;

 StopEvent := TEvent.Create(nil,{ManualReset}false,{InitialState}false,'StopEvent');
end;

The rxchar method reads using comport1.readstr()

I recently had to dig this up, and noticed it didn't work in my Delphi XE, which has tcomport4. Looking in the source I saw remarks that comport4 has changed the way it deals with its internal threads ("overlapped" property), but the default seems to be "true" has a comment "classic", and I

assumed that means compatible with older versions.

Note that the protocols are binary, and all string,char<-> ansistring,ansichar changes have been done like I did in the normal mainthread version

Now the real questions:

  1. does anybody have tcomport4 working in a thread ?
  2. Are there obvious mistakes in the above?
  3. or do I need to migrate to a different component?

I'm still debugging what is going on, but am in a hurry, which is while I post this in the hope of quickly getting pointers.

Update

I reinstalled an old turbo delphi copy, and verified it worked there with v3. I fixed a small bug though in the codepath that went a bit different from what I thought (not in the above code)

This allows me to describe the behaviour between dxe/comportv4 and bds2006/comportv3 better; the v4 code generates much more read events (hundreds/second). It seems that the read doesn't delete the read chars from the incoming queue or so.

Update 2

I did a quick test with the newest version, and did the necessary rearranging (kill string function use for an essentially binary protocol). I got stuck for a while because the application crashed on startup, but that is because I use gnugettext, and Comport packages a different (non unicode even?) version. But after that it works.

Unfortunately the changes are a bit to risky to propagate back to the production version (completely written protocol decoding), so I'll have to test with inbetween versions (between 4.0 and 4.11f). I'll do that in due time, any suggestion which version was the last readstr(ansistring) one?

Update 3

In the end I simply renamed the 4.11f units and use them in parallel to the old version, using the 4.11f for the threaded codebases and the old one to maintain existing code.

Long term I might simply take the waitforevent code and make an own version. The main problem with it is that it is afaik not possible to see if the wait terminated on timeout, stopevent or whatever. This means you need another timer if you want to e.g. send on regular intervals.

Marco van de Voort
  • 25,628
  • 5
  • 56
  • 89
  • What EXACT version of TComPort? (There are a lot of differences and a lot of different weird bugs in various 4.x releases.) – Warren P Dec 19 '11 at 18:42
  • 4.0 with a string "Fixed up for Delphi 2009 by W.Postma. Oct 2008 ". Afaik I got it in summer 2009 in an archive called "tcomport4beta" – Marco van de Voort Dec 19 '11 at 19:16
  • That version has some serious bugs. The event handling code you're using barely works at all in delphi 2009, and not at all in XE, with that release. I would move up to stable released version. Note that 4.0 and 4.11 have differences in their string types. From the code you posted, it doesn't look like you chose my default route of using AnsiString for for your serial code, so may I recommend you move to the latest 4.11 release. – Warren P Dec 19 '11 at 20:42
  • How knowledgeable are you about Unicode issues in Delphi pre-2009, and post-2009? :-) As you know, a Char was easily equal to a byte coming in from com ports, in Delphi 2006/2007 era. As of now, a Char in delphi is a Unicode entity, and while TComPort isn't dumb enough to read two bytes and call that a "unicode character", you still might encounter some strange things if you didn't port to Unicode Delphi properly. – Warren P Dec 19 '11 at 20:45
  • The buffers are ansistring, the comport devicename still being "string" doesn't matter. I'll debug and play with more tomorrow, my only desktop with comport here refused to open a port for the remote debugger, probably too botched up by an old antivirus install. I didn't like the direction of newer tcomports, converting essentially ascii data to unicodestring. I added the relevant defines for XE to the .inc myself. But anyway, for this specialty it doesn't matter, I'll test tomorrow with newer code. – Marco van de Voort Dec 19 '11 at 21:17
  • Oh, and my knowledge about string types in Delphi I summed up here: http://www.stack.nl/~marcov/delphistringtypes.txt :-) – Marco van de Voort Dec 19 '11 at 21:19
  • I suppose it doesn't matter, but what would you expect TComPort to do if you write a WideChar containing a unicode codepoint with value greater than 255, to a com port? – Warren P Dec 20 '11 at 21:07
  • I don't know a practical use for unicode comport use, but if I was forced to provide something, I'd add an encoding property, (utf8, UTF16LE and UTF16BE) and emit it like accordingly. I would set the default to UTF8, since the only practical use I can imagine is connecting to an Unix or linux embedded device with the (UTF8) terminal on serial. Personally I would think encoding it is better suited for a higher (terminal level) though – Marco van de Voort Dec 21 '11 at 07:49
  • I think that Serial ports make sense as a place to dump bytes, and ansichars only. The only devices I know of require an 8 bit binary approach, or an ASCII-subset approach. So I originally ported it that way in TComPort when I moved it up to Delphi 2009, but the latest open source TComPort is done with "Strings and Characters". – Warren P Dec 22 '11 at 00:10
  • The first (dump bytes) is what I meant too. If more (e.g. encoding) is needed it is better suited for a layer on top of comport, e.g. a terminal layer. – Marco van de Voort Dec 22 '11 at 08:56

1 Answers1

1

You need to upgrade to the latest stable 4.11 release here.

Warren P
  • 65,725
  • 40
  • 181
  • 316
  • Initially I was more looking for a vote if it was on the right track and that doing it in a thread was a serious possibility (and not lucky chance in the comport3 version). I'll test with the newer version – Marco van de Voort Dec 19 '11 at 21:19
  • I agree with you about the latest 4.x branch using UnicodeString in a way I didn't like for com ports. There is a version that is not quite the latests, that is still better than the beta you have. IE events actually work. – Warren P Dec 19 '11 at 23:03