Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2010-10

Using 5dpo for serial comm...

22 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Bo Berglund

I'm sorry to bother you again but I can't grip the serial posrt handling at all....
I have installed 5dpo serial component in Lazarus on Ubuntu 10 (a virtual machine in VMWare, which uses the host COM1 serial port) and tried the following test:

- Created a form with an Open/Close button, an edit box and a listbox.
- Added a 5dpo serial component to the form and set it to 9600 baud.
- Also set it to use ttyS0 (which I assume translates to the first serial port in Linux)
- Implemented a button click event to open/close the port
- Implemented a button click event to send the editbox text out
- Implemented an RxData event to put incoming text into the listbox
- Connected the serial port used by the Ubuntu VM to the other port on the PC using a null terminal cable.
- In Windows I started Hyperterminal on the second port

My test program was started in Ubuntu and I clicked the Open button, then entered text in the editbox and clicked the send button. Nothing appeared in Hyperterminal...

Tried typing into hyperterminal, but nothing appeared in the program listbox either.

If I now close the port with my button and then try to open it again there is an exception that forces the program to end.

In fact if I use the open/close button repeatedly without sending anything then all seems to work. But if I open-send text-close then the next time I try the open button again the exception occurs.

What have I done wrong?

Here is the body of the code:

  TfrmMain = class(TForm)
    btnClose: TBitBtn;
    btnOpen: TButton;
    btnSendData: TButton;
    edSendData: TEdit;
    lbxData: TListBox;
    serSdpo: TSdpoSerial;
    shpLED: TShape;
    procedure btnOpenClick(Sender: TObject);
    procedure btnSendDataClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction:
TCloseAction);
    procedure serSdpoRxData(Sender: TObject);
  private
    FComBuffer: string;
  public
    { public declarations }
  end;
var
  frmMain: TfrmMain;
implementation

{ TfrmMain }

procedure TfrmMain.serSdpoRxData(Sender: TObject);
var
  Data: string;
begin
  Data := serSdpo.ReadData();
  if Length(Data) > 0 then
    FComBuffer := FComBuffer + Data;
  lbxData.Items.Add(Data);
end;
procedure TfrmMain.btnOpenClick(Sender: TObject);
begin
  {Open/close port}
  if serSdpo.Active then
  begin
    serSdpo.Close;
    shpLED.Brush.Color := clRed;
    btnSendData.Enabled := false;
  end
  else
  begin
    FComBuffer := '';
    serSdpo.Open;
    shpLED.Brush.Color:= clLime;
    btnSendData.Enabled := true;
  end;
end;
procedure TfrmMain.btnSendDataClick(Sender: TObject);
var
  SendText: string;
  Res: integer;
begin
  SendText := edSendData.Text;
  if (SendText  '') and serSdpo.Active then
    Res := serSdpo.WriteData(SendText);
end;
procedure TfrmMain.FormClose(Sender: TObject; var CloseAction:
TCloseAction);
begin
  if serSdpo.Active then
    serSdpo.Close;
end;
Bo Berglund Developer in Sweden

Reply by email

Mark Morgan Lloyd
to Bo Berglund
Bo Berglund wrote 26 lines
I'm sorry to bother you again but I can't grip the serial posrt handling at all.... I have installed 5dpo serial component in Lazarus on Ubuntu 10 (a virtual machine in VMWare, which uses the host COM1 serial port) and tried the following test: - Created a form with an Open/Close button, an edit box and a listbox. - Added a 5dpo serial component to the form and set it to 9600 baud. - Also set it to use ttyS0 (which I assume translates to the first serial port in Linux) - Implemented a button click event to open/close the port - Implemented a button click event to send the editbox text out - Implemented an RxData event to put incoming text into the listbox - Connected the serial port used by the Ubuntu VM to the other port on the PC using a null terminal cable. - In Windows I started Hyperterminal on the second port My test program was started in Ubuntu and I clicked the Open button, then entered text in the editbox and clicked the send button. Nothing appeared in Hyperterminal... Tried typing into hyperterminal, but nothing appeared in the program listbox either. If I now close the port with my button and then try to open it again there is an exception that forces the program to end.

Check port ownership, the groups the current user is in, and look at dmesg output.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Bo Berglund
to Mark Morgan Lloyd
Mark Morgan Lloyd wrote 6 lines
> If I now close the port with my button and then try to open it again > there is an exception that forces the program to end. Check port ownership, the groups the current user is in, and look at dmesg output.

Hmm, what do you mean by that? Could you be more specific? The current user is myself, there is no other account created on the system and I am an admin.
And what is "dmesg output"?

Bo Berglund Developer in Sweden

Reply by email

Lukasz Sokol
to Bo Berglund
Bo Berglund wrote 16 lines
On Thu, 07 Oct 2010 02:14:47 +0000, Mark Morgan Lloyd wrote: >> If I now close the port with my button and then try to open it again >> there is an exception that forces the program to end. > > Check port ownership, the groups the current user is in, and look at > dmesg output. > Hmm, what do you mean by that? Could you be more specific? The current user is myself, there is no other account created on the system and I am an admin. And what is "dmesg output"?

In virtual console, type 'ls -l /dev/ttyS*' will list all ttyS with permissions.

like this :

crw-rw---- 1 root dialout 4, 64 2010-04-12 09:17 /dev/ttyS0 crw-rw---- 1 root dialout 4, 65 2010-04-12 09:17 /dev/ttyS1 crw-rw---- 1 root dialout 4, 66 2010-04-12 09:17 /dev/ttyS2 crw-rw---- 1 root dialout 4, 67 2010-04-12 09:17 /dev/ttyS3

(this is from actual Ubuntu machine, under 8.10).

This shows you that root owns all these ports, and dialout group is allowed to use it too, no others (man chmod).

So to get your port working, you need to change your user group (add the username to group dialout in /etc/group file), then log out and log in again.

Or you can, for quick look, start your app under gksudo;

Dmesg output appears on console if you type 'dmesg' or you can view it as saved to /var/log/dmesg (it lists a whole lot of kernel startup messages).

HTH,
Lukasz

Reply by email

Mark Morgan Lloyd
to Bo Berglund: On Thu, 07 Oct 2010 02:14:47 +0000, Mark Morgan Lloyd Hmm, what do you mean by that?…
Bo Berglund wrote 13 lines
On Thu, 07 Oct 2010 02:14:47 +0000, Mark Morgan Lloyd wrote: >> If I now close the port with my button and then try to open it again >> there is an exception that forces the program to end. > Check port ownership, the groups the current user is in, and look at > dmesg output. > Hmm, what do you mean by that? Could you be more specific? The current user is myself, there is no other account created on the system and I am an admin. And what is "dmesg output"?

I am not going into details because you're using Ubuntu hence Gnome while I'm using Debian with KDE. Ubuntu is a derivative of Debian but there are differences, and if I tried to give you detailed advice it could backfire.

The device /dev/ttyS0 has an associated user and group, e.g.

$ ls -l /dev/ttyS0
crw-rw---- 1 root dialout 4, 64 2010-10-04 09:08 /dev/ttyS0

That shows that in order to do anything useful with the port the program needs to either be run as root (considered bad practice), or the current user needs to be in the 'dialout' group.

As for the other question,

$ dmesg |tail

followed I suggest by looking at the manpages for dmesg and less. Once you've done that continue with e.g.

$ dmesg |less
Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Mark Morgan Lloyd
to Lukasz Sokol: In virtual console, type 'ls -l /dev/ttyS*' will list all ttyS with permissions. like…
Lukasz Sokol wrote 5 lines
This shows you that root owns all these ports, and dialout group is allowed to use it too, no others (man chmod). So to get your port working, you need to change your user group (add the username to group dialout in /etc/group file), then log out and log in again.

I'd suggest not doing that manually, since there might be an /etc/gshadow file that needs to be kept in step. Gnome will have a user management program which should be used in preference, not being a Gnome user I can't provide more detail.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Lukasz Sokol
to Mark Morgan Lloyd
Mark Morgan Lloyd wrote 10 lines
Lukasz Sokol wrote: > This shows you that root owns all these ports, and dialout group > is allowed to use it too, no others (man chmod). > > So to get your port working, you need to change your user group (add the username > to group dialout in /etc/group file), then log out and log in again. I'd suggest not doing that manually, since there might be an /etc/gshadow file that needs to be kept in step. Gnome will have a user management program which should be used in preference, not being a Gnome user I can't provide more detail.

Yeah, can be found under System -> Administration menu in the default Gnome. Don't remember the name now thou.

L.

Reply by email

Mark Morgan Lloyd
to Michael Schnell
Michael Schnell wrote
Did you check with minterm or similar that the serial port is in fact working for you ?

Good point. I usually use gtkterm since it doesn't make assumptions about modems etc. which is more use for talking to instrumentation.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Koenraad Lelong
to Michael Schnell: Did you check with minterm or similar that the serial port is in fact working for you ?…
Michael Schnell wrote 10 lines
Did you check with minterm or similar that the serial port is in fact working for you ? -Michael -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Hi,

When I'm having problems with serial-comms, I use minicom/hyperterminal. I disable all handshaking. I have plugged in a test-connector in the port : with a 9pin connector shortcircuit pins 2 and 3. Then if I send anything to the port, I should get it back on the screen. If that works, I go further.
My 2 cents.

Regards,

Koenraad Lelong.

Reply by email

Bo Berglund
to Lukasz Sokol: In virtual console, type 'ls -l /dev/ttyS*' will list all ttyS with permissions. like…
Lukasz Sokol wrote 39 lines
On 07/10/2010 06:01, Bo Berglund wrote: > On Thu, 07 Oct 2010 02:14:47 +0000, Mark Morgan Lloyd > wrote: > >>> If I now close the port with my button and then try to open it again >>> there is an exception that forces the program to end. >> >> Check port ownership, the groups the current user is in, and look at >> dmesg output. >> > > Hmm, what do you mean by that? Could you be more specific? > The current user is myself, there is no other account created on the > system and I am an admin. > And what is "dmesg output"? > > In virtual console, type 'ls -l /dev/ttyS*' will list all ttyS with permissions. like this : crw-rw---- 1 root dialout 4, 64 2010-04-12 09:17 /dev/ttyS0 crw-rw---- 1 root dialout 4, 65 2010-04-12 09:17 /dev/ttyS1 crw-rw---- 1 root dialout 4, 66 2010-04-12 09:17 /dev/ttyS2 crw-rw---- 1 root dialout 4, 67 2010-04-12 09:17 /dev/ttyS3 (this is from actual Ubuntu machine, under 8.10). This shows you that root owns all these ports, and dialout group is allowed to use it too, no others (man chmod). So to get your port working, you need to change your user group (add the username to group dialout in /etc/group file), then log out and log in again. Or you can, for quick look, start your app under gksudo; Dmesg output appears on console if you type 'dmesg' or you can view it as saved to /var/log/dmesg (it lists a whole lot of kernel startup messages).

Looks the same on mine:
crw-rw---- 1 root dialout 4, 64 2010-10-07 11:40 /dev/ttyS0 crw-rw---- 1 root dialout 4, 65 2010-10-06 11:00 /dev/ttyS1 crw-rw---- 1 root dialout 4, 66 2010-10-06 11:00 /dev/ttyS2 crw-rw---- 1 root dialout 4, 67 2010-10-06 11:00 /dev/ttyS3

So I opened /etc/group in gedit and looked for dialout, my login was already listed:
dialout:x:20:bosse

Using dmesg resulted in a lot of text, too much to show here. In fact, what am I looking for in the dmesg output???

Bo Berglund Developer in Sweden

Reply by email

Bo Berglund
to Lukasz Sokol: Yeah, can be found under System -> Administration menu in the default Gnome. Don't…
Lukasz Sokol wrote 5 lines
On 07/10/2010 10:07, Mark Morgan Lloyd wrote: > I'd suggest not doing that manually, since there might be an /etc/gshadow file that needs to be kept in step. Gnome will have a user management program which should be used in preference, not being a Gnome user I can't provide more detail. > Yeah, can be found under System -> Administration menu in the default Gnome. Don't remember the name now thou.

"Users and Groups" is the name...
I am listed as a dialout user.

Bo Berglund Developer in Sweden

Reply by email

Bo Berglund
to Koenraad Lelong: When I'm having problems with serial-comms, I use minicom/hyperterminal. I disable all…
Koenraad Lelong wrote 6 lines
When I'm having problems with serial-comms, I use minicom/hyperterminal. I disable all handshaking. I have plugged in a test-connector in the port : with a 9pin connector shortcircuit pins 2 and 3. Then if I send anything to the port, I should get it back on the screen. If that works, I go further. My 2 cents.

Good idea, I did not think about that kind of self-test into a single application! I just made myself a loopback connector-cable and tested.

Michael Schnell wrote 5 lines
> Did you check with minterm or similar that the serial port is in fact > working for you ? Good point. I usually use gtkterm since it doesn't make assumptions about modems etc. which is more use for talking to instrumentation.

I installed gtkterm and used that for initial testing with the loopback connector. I found that while I had been using ttyS0 all along, the working port is ttyS1!

After that I got my test application working too, both using the loopback connector and with a connection to Hyperterminal on my Windows host.

So far just functional tests, but next I will start up a serious comm unit and start checking out the capabilities of the comm component.

Thanks for the tips and suggestions!

A question concerning gtkterm:
I cannot find any command to open/close the port. How is that done? Do I have to shut down the program to release the port?

Bo Berglund Developer in Sweden

Reply by email

Mark Morgan Lloyd
to Bo Berglund
Bo Berglund wrote 16 lines
I installed gtkterm and used that for initial testing with the loopback connector. I found that while I had been using ttyS0 all along, the working port is ttyS1! After that I got my test application working too, both using the loopback connector and with a connection to Hyperterminal on my Windows host. So far just functional tests, but next I will start up a serious comm unit and start checking out the capabilities of the comm component. Thanks for the tips and suggestions! A question concerning gtkterm: I cannot find any command to open/close the port. How is that done? Do I have to shut down the program to release the port?

[Checks] You don't, the designated port is open as long as the program is running. However you need to distinguish between "open", "in use" and "locked": there is a convention that when a program wants to claim usage of a port it writes a file containing its PID:

# ls -l /var/lock
total 12
-rw-r--r-- 1 root root 11 Aug 16 17:02 LCK..ttyS11 -rw-r--r-- 1 root root 11 Oct 2 14:38 LCK..ttyS6 drwxr-xr-x 2 root root 4096 Mar 16 2010 subsys

There are times when having multiple programs looking at a port can be extremely useful, for example gettys tend to work like that. However managing these PID files reliably can be a lot of effort.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Bo Berglund
to Mark Morgan Lloyd
Mark Morgan Lloyd wrote 21 lines
Bo Berglund wrote: > A question concerning gtkterm: > I cannot find any command to open/close the port. How is that done? > Do I have to shut down the program to release the port? [Checks] You don't, the designated port is open as long as the program is running. However you need to distinguish between "open", "in use" and "locked": there is a convention that when a program wants to claim usage of a port it writes a file containing its PID: # ls -l /var/lock total 12 -rw-r--r-- 1 root root 11 Aug 16 17:02 LCK..ttyS11 -rw-r--r-- 1 root root 11 Oct 2 14:38 LCK..ttyS6 drwxr-xr-x 2 root root 4096 Mar 16 2010 subsys There are times when having multiple programs looking at a port can be extremely useful, for example gettys tend to work like that. However managing these PID files reliably can be a lot of effort.

I am used to the Windows world where you can manage the com port data prior to actually opening it. Then you use it for a while, close it and continu other stuff. Later again you can open and use the port. If one tries to open a port that is either non-existing or already in use by another program, then there will be an exception. But in my Linux case where I only have a single com port there was nothing warning me that the port I opened was not really there... Hence my problems, I believed that the port was ttyS0 and not receiving an exception on open enhanced this belief. But in actual fact only ttyS1 is backed by real hardware, the others are just plain files by the looks of it. Strange....

In the case of gtkterm, does it actually open and use the com port as soon as it starts? How can it know in advance *which* port the user wants it to use?

It makes more sense to me to first specify port number, data speeds and such and only then open the port, send the data or whatever, and finally close the port. Then maybe go to another port and repeat the above...

If hardware access is managed by "lock" files in /var/lock, then what will happen if the application fails to remove the lock file afterwards? Do we get a forever unaccessible com port???

Bo Berglund

Reply by email

Mark Morgan Lloyd
to Bo Berglund
Bo Berglund wrote 11 lines
I am used to the Windows world where you can manage the com port data prior to actually opening it. Then you use it for a while, close it and continu other stuff. Later again you can open and use the port. If one tries to open a port that is either non-existing or already in use by another program, then there will be an exception. But in my Linux case where I only have a single com port there was nothing warning me that the port I opened was not really there... Hence my problems, I believed that the port was ttyS0 and not receiving an exception on open enhanced this belief. But in actual fact only ttyS1 is backed by real hardware, the others are just plain files by the looks of it. Strange....

No, they're not files.

In the case of gtkterm, does it actually open and use the com port as soon as it starts? How can it know in advance *which* port the user wants it to use?

Configuration file.

It makes more sense to me to first specify port number, data speeds and such and only then open the port, send the data or whatever, and finally close the port. Then maybe go to another port and repeat the above...

There's two ways to look at that:

i) Unix doesn't work like that. You need to get a handle for the device before you can set the Baud rate etc.

ii) Windows doesn't work like that either :-)

Put another way, what you're saying is that you're used to setting up an object (term used loosely) representing a port before actually doing something with the port. That's not an OS issue, it's down to the class library etc.

If hardware access is managed by "lock" files in /var/lock, then what will happen if the application fails to remove the lock file afterwards? Do we get a forever unaccessible com port???

I said it was hard work to get right, didn't I?

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Bo Berglund
to Mark Morgan Lloyd
Mark Morgan Lloyd wrote
I said it was hard work to get right, didn't I? -- Mark Morgan Lloyd

Yeah....
But by asking here I have actually saved a lot of time. Since I am such a novice in Linux programming I would probably have straggled around for days and weeks trying to find the answers people like you supply quickly. :)
It is very good to have a resource like this without flames on the less knowing too! Kudos to this list and its participants!

And just an hour ago FEDEX delivered the ARM based embedded system with a touch panel, which is my final target, so now I have a new step to climb up the ladder.
Fun though, and it keeps the grey cells from vanishing.

Like Arnold said: "I'll be back...."

Bo Berglund

Reply by email

Bo Berglund
to Bo Berglund: I'm sorry to bother you again but I can't grip the serial posrt handling at all.... I…

On Wed, 06 Oct 2010 23:11:57 +0200, Bo Berglund
wrote:

After I got 5dpo operational on Ubuntu I went back to my old Delphi code, which I intend to port over to Lazarus, to remind me what it is doing.

I have to perform some surgery on it to allow for a different comm component when used from lazarus at the very least. Then I found that when sending data to the instrumentation there is one case when a memory upload is being done that involves a large amount of data, up to 1 Mb on occasion.
For this reason I have code that splits the data into chunks of 512 bytes and sends those to the comm component only after checking the state of the transmit buffer.
Like this:

{code}
      repeat
        {send data from Cmd in chunks of 512 bytes}
        sBuf := Copy(Cmd, 1, 512);
        Delete(Cmd,1,512);
        FComm.WriteString(sBuf);
        while FComm.TxWaiting > 16 do
        begin
          Application.ProcessMessages;
          Sleep(1);
        end;
        {Here was code for the progress bar update}
      until Cmd = '';
{code}

One purpose of this is to not overload the transmit buffer and another is to be able to track the progress of transfer by incrementing a progress bar for each 512 bytes sent.

But with TSdpoSerial I can't find any such property as TxWaiting or similar to check.
Is it not needed or possible? Maybe the component can handle any size string I send to it without choking?

But what about the user feedback? I would really want to be able to show the actual data flow to the user in a progress bar since the whole operation takes considerable time.
So how can I know how many bytes have actually left the transmit buffer (or how many that still remain to be sent).

Bo Berglund Developer in Sweden

Reply by email

Paulo Costa
to Bo Berglund
Show quoted text 10 lines
But with TSdpoSerial I can't find any such property as TxWaiting or similar to check. Is it not needed or possible? Maybe the component can handle any size string I send to it without choking? But what about the user feedback? I would really want to be able to show the actual data flow to the user in a progress bar since the whole operation takes considerable time. So how can I know how many bytes have actually left the transmit buffer (or how many that still remain to be sent).

TSdpoSerial exposes a property SynSer: TBlockSerial where there are more methods like:

     function SendingData: integer; virtual;
     {:Returns the number of bytes waiting to be sent in the output buffer.
      0 is returned when the output buffer is empty.}

Probably it is what you need.

Paulo Costa

Reply by email

Bo Berglund
to Paulo Costa
Paulo Costa wrote 20 lines
> But with TSdpoSerial I can't find any such property as TxWaiting or > similar to check. > Is it not needed or possible? Maybe the component can handle any size > string I send to it without choking? > > But what about the user feedback? I would really want to be able to > show the actual data flow to the user in a progress bar since the > whole operation takes considerable time. > So how can I know how many bytes have actually left the transmit > buffer (or how many that still remain to be sent). TSdpoSerial exposes a property SynSer: TBlockSerial where there are more methods like: function SendingData: integer; virtual; {:Returns the number of bytes waiting to be sent in the output buffer. 0 is returned when the output buffer is empty.} Probably it is what you need. Paulo Costa

Thanks, this is exactly what I need!
So if there are more detailed items needed I could look at the SynSer documentation, right?

Bo Berglund Developer in Sweden

Reply by email

Paulo Costa
to Bo Berglund
Bo Berglund wrote
Thanks, this is exactly what I need! So if there are more detailed items needed I could look at the SynSer documentation, right?

Yes. (or its source code and comments...)

Paulo Costa

Reply by email