www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Access to serial ports in Windows

reply Don Clugston <dac nospam.com.au> writes:
Has anyone accessed serial (COM) ports using D (under Windows)?
Does Mango support them?

If there is currently nothing in D, does anyone know of a candidate that 
could be ported to D?
It ought to be possible to create something that would work on both 
Windows and Linux PCs, since the hardware is the same.
Oct 24 2005
next sibling parent reply =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= <jmjmak invalid_utu.fi> writes:
Don Clugston wrote:
 Has anyone accessed serial (COM) ports using D (under Windows)?
 Does Mango support them?
Windows and Linux behave a bit differently here. On Win9x/DOS you can access hardware ports directly. On WinNT+ and Linux you have to use system calls. I think D is able to call these system API functions directly, you just need correct header files.
 If there is currently nothing in D, does anyone know of a candidate that 
 could be ported to D?
 It ought to be possible to create something that would work on both 
 Windows and Linux PCs, since the hardware is the same.
I'm not really sure this interoperability will be of much motivation - nowadays serial ports are pretty ancient technology.
Oct 24 2005
parent reply Don Clugston <dac nospam.com.au> writes:
Jari-Matti Mäkelä wrote:
 Don Clugston wrote:
 
 Has anyone accessed serial (COM) ports using D (under Windows)?
 Does Mango support them?
Windows and Linux behave a bit differently here. On Win9x/DOS you can access hardware ports directly. On WinNT+ and Linux you have to use system calls. I think D is able to call these system API functions directly, you just need correct header files.
Yes, it is, but serial ports aren't quite that simple. There are subtle handshaking and concurrency issues, it's extremely easy to get it wrong. It's actually quite similar to a slow internet connection. You have to consider the possibility that the connection is lost in mid-transmission; you cannot freeze the machine while you wait for the next bytes to arrive; etc. The Windows API gives you very little help with this; I'm not sure what the situation is for Linux.
 If there is currently nothing in D, does anyone know of a candidate 
 that could be ported to D?
 It ought to be possible to create something that would work on both 
 Windows and Linux PCs, since the hardware is the same.
I'm not really sure this interoperability will be of much motivation - nowadays serial ports are pretty ancient technology.
It's ancient, but very common for engineering tools, where a cheap, simple interface is required. COM ports probably won't die for another decade. An ancient library would be adequate. If I could switch my code between Windows + Linux machines, it would be a real bonus for me.
Oct 24 2005
parent reply Sean Kelly <sean f4.ca> writes:
In article <djikpt$q52$1 digitaldaemon.com>, Don Clugston says...
Jari-Matti Mäkelä wrote:
 
 I'm not really sure this interoperability will be of much motivation - 
 nowadays serial ports are pretty ancient technology.
It's ancient, but very common for engineering tools, where a cheap, simple interface is required. COM ports probably won't die for another decade. An ancient library would be adequate.
So long as you're using an old PC at any rate. If I remember correctly, the latest mainboard format does away with serial ports. Sean
Oct 24 2005
parent antonio <antonio abrevia.net> writes:
Sean Kelly wrote:
 In article <djikpt$q52$1 digitaldaemon.com>, Don Clugston says...
 Jari-Matti Mäkelä wrote:
 I'm not really sure this interoperability will be of much motivation - 
 nowadays serial ports are pretty ancient technology.
It's ancient, but very common for engineering tools, where a cheap, simple interface is required. COM ports probably won't die for another decade. An ancient library would be adequate.
So long as you're using an old PC at any rate. If I remember correctly, the latest mainboard format does away with serial ports. Sean
Sorry, Sean: COM ports are very common on industrial environments actually and in the future. I agree that Office/playing machines can forget this technology... but there is other worlds in this world... and industrial environments and instrumentation is one of this worlds... Antonio
Oct 28 2005
prev sibling next sibling parent Florian Sonnenberger <nairolf online.de> writes:
Don Clugston schrieb:
 Has anyone accessed serial (COM) ports using D (under Windows)?
 Does Mango support them?
 
 If there is currently nothing in D, does anyone know of a candidate that 
 could be ported to D?
 It ought to be possible to create something that would work on both 
 Windows and Linux PCs, since the hardware is the same.
http://sourceforge.net/projects/dframework/ There is a file called "serialstream.d". I don't know if this is what you want, I haven't looked at it yet. But I think, it's Windows-only. Florian
Oct 24 2005
prev sibling next sibling parent reply "Kris" <fu bar.com> writes:
Mango does not currently support serial or parallel port I/O. Part of the 
reasoning behind this is that user-level code does not have access to the 
hardware: on Win32 you need a kernel-mode device driver to jump across the 
ring barrier. I don't know what the scoop is on Linux, but I imagine it's 
somewhat similar (the hardware ports are not likely to be exposed at the 
user-mode level).

In the past I've used 'UserPort' on Win32 to gain access to the hardware 
(via Java, actually). It's easy to apply, but would really need 
interrupt-callback support added for serious usage (currently you have to 
poll incoming data: a big no-no, IMO).

If it were deemed generally useful to treat the 'legacy' ports as a 
non-sharable entity, and a (interrupt supporting) driver were made available 
for both Win32 and Linux, I'd be happy to see wrappers for that within Mango 
:-)

In the meantime, if you're on Win32 and can put up with polling (or don't 
need to read data; just send it), then UserPort will be your friend. Let us 
know how you get on?

- Kris


"Don Clugston" <dac nospam.com.au> wrote in message 
news:djif1s$lfr$1 digitaldaemon.com...
 Has anyone accessed serial (COM) ports using D (under Windows)?
 Does Mango support them?

 If there is currently nothing in D, does anyone know of a candidate that 
 could be ported to D?
 It ought to be possible to create something that would work on both 
 Windows and Linux PCs, since the hardware is the same. 
Oct 24 2005
parent "Kris" <fu bar.com> writes:
Well I'll be. Win32 does expose access to the com ports, and supports 
asynchronous reading of them also: 
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/monitoring_communications_events.asp

WaitCommEvent
If the overlapped operation cannot be completed immediately, the function 
returns FALSE and the GetLastError function returns ERROR_IO_PENDING, 
indicating that the operation is executing in the background. When this 
happens, the system sets the hEvent member of the OVERLAPPED structure to 
the not-signaled state before WaitCommEvent returns, and then it sets it to 
the signaled state when one of the specified events or an error occurs. The 
calling process can use one of the wait functions to determine the event 
object's state and then use the GetOverlappedResult function to determine 
the results of the WaitCommEvent operation.


My apologies for the earlier misguidance.

- Kris



"Kris" <fu bar.com> wrote in message news:djj7e7$196e$1 digitaldaemon.com...
 Mango does not currently support serial or parallel port I/O. Part of the 
 reasoning behind this is that user-level code does not have access to the 
 hardware: on Win32 you need a kernel-mode device driver to jump across the 
 ring barrier. I don't know what the scoop is on Linux, but I imagine it's 
 somewhat similar (the hardware ports are not likely to be exposed at the 
 user-mode level).

 In the past I've used 'UserPort' on Win32 to gain access to the hardware 
 (via Java, actually). It's easy to apply, but would really need 
 interrupt-callback support added for serious usage (currently you have to 
 poll incoming data: a big no-no, IMO).

 If it were deemed generally useful to treat the 'legacy' ports as a 
 non-sharable entity, and a (interrupt supporting) driver were made 
 available for both Win32 and Linux, I'd be happy to see wrappers for that 
 within Mango :-)

 In the meantime, if you're on Win32 and can put up with polling (or don't 
 need to read data; just send it), then UserPort will be your friend. Let 
 us know how you get on?

 - Kris


 "Don Clugston" <dac nospam.com.au> wrote in message 
 news:djif1s$lfr$1 digitaldaemon.com...
 Has anyone accessed serial (COM) ports using D (under Windows)?
 Does Mango support them?

 If there is currently nothing in D, does anyone know of a candidate that 
 could be ported to D?
 It ought to be possible to create something that would work on both 
 Windows and Linux PCs, since the hardware is the same.
Oct 24 2005
prev sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Mon, 24 Oct 2005 13:03:16 +0200, Don Clugston <dac nospam.com.au> wrote:
 Has anyone accessed serial (COM) ports using D (under Windows)?
Yes.
 Does Mango support them?
 If there is currently nothing in D, does anyone know of a candidate that  
 could be ported to D?
 It ought to be possible to create something that would work on both  
 Windows and Linux PCs, since the hardware is the same.
The attached source is a COM stream for windows only. I have also written COM code on linux and freebsd and could probably add support for these two to the attached source, let me know if you're interested. Regan
Oct 24 2005
next sibling parent reply Tiago Gasiba <tiago.gasiba gmail.com> writes:
Hi Regan,


Regan Heath schrieb:

 I have also written COM code on linux and freebsd and could probably add
 support for these two to the attached source, let me know if you're
 interested.
I'm following this thread and, although I'm not imidiatly interested in COM support for Linux, maybe in the future it will come in handy... Could you post the code for Linux also? Thanks! Tiago -- Tiago Gasiba (MSc.) - http://www.gasiba.de Everything should be made as simple as possible, but not simpler.
Oct 26 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 26 Oct 2005 09:30:19 +0200, Tiago Gasiba <tiago.gasiba gmail.com>  
wrote:
 I have also written COM code on linux and freebsd and could probably add
 support for these two to the attached source, let me know if you're
 interested.
I'm following this thread and, although I'm not imidiatly interested in COM support for Linux, maybe in the future it will come in handy... Could you post the code for Linux also? Thanks!
All right, here goes! I have modified the previously posted com.d file, it now contains an 'else' block which should hopefully work for linux, freebsd, and even macosx (maybe, not sure if I ever got it working there). I haven't got any of those machines to compile upon and chances are I have missed some symbol or import that is required. I wasn't really sure what to do with "#if defined(M_ELF)" so I just put it in a version block. Same with "#if defined(_POSIX_SOURCE) || defined(_XOPEN_SOURCE)" (note: this is a pain to translate into D version blocks, when are we going to get version statements that allow || ?!?) I added a 'canRead' function to both implementations, the linux (etc) one may need some error checking added for the 'select' call. The basic idea with read/write in this class is that it will block until it completes, but the underlying device is placed in a non-blocking mode. What this means is that the 'read' and 'ReadFile' functions return immediately whether they read or not, thus the 'while' loop to keep trying till you get something. This source is intended for public domain. Regan
Oct 26 2005
parent reply Tiago Gasiba <tiago.gasiba gmail.com> writes:
Regan Heath schrieb:

 
 I haven't got any of those machines to compile upon and chances are I have
 missed some symbol or import that is required.
I also think so... :) Lets see, compiling with "dmd -c com.d" I get: ----- com.d(295): alias com.XCSETA conflicts with com.XCSETA at com.d(285) com.d(296): alias com.XCSETAW conflicts with com.XCSETAW at com.d(286) com.d(297): alias com.XCSETAF conflicts with com.XCSETAF at com.d(287) com.d(298): alias com.XCSETAF conflicts with com.XCSETAF at com.d(287) /opt/dmd/src/phobos/std/stream.d(2593): TArrayStream!(ubyte[]) is used as a type /opt/dmd/src/phobos/std/stream.d(2593): class std.stream.MemoryStream base type must be class or interface, not void /opt/dmd/src/phobos/std/stream.d(2613): function std.stream.MemoryStream.writeBlock function writeBlock does not override any /opt/dmd/src/phobos/std/stream.d(2670): TArrayStream!(MmFile) is used as a type /opt/dmd/src/phobos/std/stream.d(2670): class std.stream.MmFileStream base type must be class or interface, not void /opt/dmd/src/phobos/std/stream.d(2679): function std.stream.MmFileStream.flush function flush does not override any /opt/dmd/src/phobos/std/stream.d(2686): function std.stream.MmFileStream.close function close does not override any com.d(295): identifier 'TCSANOW' is not defined com.d(295): TCSANOW is used as a type com.d(296): identifier 'TCSADRAIN' is not defined com.d(296): TCSADRAIN is used as a type com.d(297): identifier 'TCSAFLUSH' is not defined com.d(297): TCSAFLUSH is used as a type com.d(298): identifier 'TCSADFLUSH' is not defined com.d(298): TCSADFLUSH is used as a type ----- And compiling with "dmd -c -version=M_ELF com.d" I get: ----- com.d(318): undefined identifier B110 com.d(318): undefined identifier B300 com.d(318): undefined identifier B600 com.d(318): undefined identifier B1200 com.d(319): undefined identifier B2400 com.d(319): undefined identifier B4800 com.d(319): undefined identifier B9600 com.d(319): undefined identifier B19200 com.d(320): undefined identifier B38400 com.d(320): undefined identifier B57600 com.d(320): undefined identifier B115200 ----- I rewrite part of your code like: (approx line 318) private static int BaudRates[BaudRate.B115200+1] = [ BaudRate.B110, BaudRate.B300, BaudRate.B600, BaudRate.B1200, BaudRate.B2400, BaudRate.B4800, BaudRate.B9600, BaudRate.B19200, BaudRate.B38400,BaudRate.B57600,BaudRate.B115200 ]; Compiling with "dmd -c -version=M_ELF com.d" I then get: ----- com.d(327): undefined identifier strerror com.d(327): function expected before (), not strerror of type int com.d(327): incompatible types for ((msg ~ " {") ~ (strerror(getErrno()))): 'char[]' and 'int' com.d(327): Can only concatenate arrays, not (char[] ~ int) com.d(327): incompatible types for ((msg ~ " {" ~ strerror(getErrno())) ~ ("}")): 'int' and 'char[1]' com.d(327): Can only concatenate arrays, not (int ~ char[1]) com.d(327): constructor object.Exception.this (char[]) does not match argument types (int) com.d(327): cannot implicitly convert expression (msg ~ " {" ~ strerror(getErrno()) ~ "}") of type int to char[] com.d(338): voids have no value com.d(338): cannot implicitly convert expression (this.open(port,cast(BaudRate)2050)) of type void to int com.d(341): undefined identifier tcgetattr com.d(341): function expected before (), not tcgetattr of type int com.d(350): cannot implicitly convert expression (CS8 | CREAD | CLOCAL | BaudRates[baud]) of type int to tcflag_t com.d(357): undefined identifier tcsetattr com.d(357): function expected before (), not tcsetattr of type int com.d(365): function com.ComStream.close () does not match argument types (int) com.d(365): Error: expected 0 arguments, not 1 com.d(378): cannot implicitly convert expression (FD_ISSET(this.file,&readfd)) of type int to bit com.d(387): function std.stream.Stream.read (ubyte[]) does not match argument types (int,void*,uint) com.d(387): Error: expected 1 arguments, not 3 com.d(387): cannot implicitly convert expression (this.file) of type int to wchar[] com.d(387): cast(wchar[])(this.file) is not an lvalue com.d(387): voids have no value com.d(387): cannot implicitly convert expression (cast(Stream)(this).read(cast(wchar[])(this.file),result,len)) of type void to int com.d(406): function std.stream.Stream.write (ubyte[]) does not match argument types (int,void*,uint) com.d(406): Error: expected 1 arguments, not 3 com.d(406): cannot implicitly convert expression (this.file) of type int to wchar[] com.d(406): voids have no value com.d(406): cannot implicitly convert expression (cast(Stream)(this).write(cast(wchar[])(this.file),result,len)) of type void to int ----- Oops... something is very wrong here :( Tried to quickly fix the code but no success... Also did not find "tcgetattr" defined in D anywhere. Best, Tiago -- Tiago Gasiba (MSc.) - http://www.gasiba.de Everything should be made as simple as possible, but not simpler.
Oct 26 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 26 Oct 2005 13:22:52 +0200, Tiago Gasiba <tiago.gasiba gmail.com>  
wrote:
 Regan Heath schrieb:

 I haven't got any of those machines to compile upon and chances are I  
 have
 missed some symbol or import that is required.
I also think so... :) Lets see, compiling with "dmd -c com.d" I get: ----- com.d(295): alias com.XCSETA conflicts with com.XCSETA at com.d(285) com.d(296): alias com.XCSETAW conflicts with com.XCSETAW at com.d(286) com.d(297): alias com.XCSETAF conflicts with com.XCSETAF at com.d(287) com.d(298): alias com.XCSETAF conflicts with com.XCSETAF at com.d(287)
Oops. alias lines are backwards, try: alias XCSETA TCSANOW; alias XCSETAW TCSADRAIN; alias XCSETAF TCSAFLUSH; alias XCSETAF TCSADFLUSH;
 /opt/dmd/src/phobos/std/stream.d(2593): TArrayStream!(ubyte[]) is used  
 as a type
 /opt/dmd/src/phobos/std/stream.d(2593): class std.stream.MemoryStream  
 base type must be class or interface, not void
 /opt/dmd/src/phobos/std/stream.d(2613): function  
 std.stream.MemoryStream.writeBlock function writeBlock does not override  
 any
 /opt/dmd/src/phobos/std/stream.d(2670): TArrayStream!(MmFile) is used as  
 a type
 /opt/dmd/src/phobos/std/stream.d(2670): class std.stream.MmFileStream  
 base type must be class or interface, not void
 /opt/dmd/src/phobos/std/stream.d(2679): function  
 std.stream.MmFileStream.flush function flush does not override any
 /opt/dmd/src/phobos/std/stream.d(2686): function  
 std.stream.MmFileStream.close function close does not override any
Not sure what that's on about.
 com.d(295): identifier 'TCSANOW' is not defined
 com.d(295): TCSANOW is used as a type
 com.d(296): identifier 'TCSADRAIN' is not defined
 com.d(296): TCSADRAIN is used as a type
 com.d(297): identifier 'TCSAFLUSH' is not defined
 com.d(297): TCSAFLUSH is used as a type
 com.d(298): identifier 'TCSADFLUSH' is not defined
 com.d(298): TCSADFLUSH is used as a type
should be fixed by alias lines.
 -----

 And compiling with "dmd -c -version=M_ELF com.d" I get:
 -----
 com.d(318): undefined identifier B110
 com.d(318): undefined identifier B300
 com.d(318): undefined identifier B600
 com.d(318): undefined identifier B1200
 com.d(319): undefined identifier B2400
 com.d(319): undefined identifier B4800
 com.d(319): undefined identifier B9600
 com.d(319): undefined identifier B19200
 com.d(320): undefined identifier B38400
 com.d(320): undefined identifier B57600
 com.d(320): undefined identifier B115200
 -----

 I rewrite part of your code like:

 (approx   line 318)
  private static int BaudRates[BaudRate.B115200+1] = [
     BaudRate.B110,  BaudRate.B300,  BaudRate.B600,  BaudRate.B1200,
     BaudRate.B2400, BaudRate.B4800, BaudRate.B9600, BaudRate.B19200,
     BaudRate.B38400,BaudRate.B57600,BaudRate.B115200
   ];
This is wrong. This array translates BaudRate values into the OS values for baud rate, i.e. B110 etc. They should be defined in a header somewhere... (I'll repost when I have fixed it)
 Compiling with "dmd -c -version=M_ELF com.d" I then get:
 -----
 com.d(327): undefined identifier strerror
Add "char* strerror(int);" to extern C block. <snip>
 Oops... something is very wrong here :(
 Tried to quickly fix the code but no success...
I'll fix these and repost.
 Also did not find "tcgetattr" defined in D anywhere.
Yep. Need to add that def too. Regan
Oct 26 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
Ok, here is my latest version.

I can compile it on a ubuntu linux vmware virtual machine but it wont run,  
it errors on the "tcsetattr" call. How about you?

Regan
Oct 27 2005
next sibling parent reply Tiago Gasiba <tiago.gasiba gmail.com> writes:
Regan Heath schrieb:

 Ok, here is my latest version.
 
 I can compile it on a ubuntu linux vmware virtual machine but it wont run,
 it errors on the "tcsetattr" call. How about you?
 
 Regan
Same here. The B57600,B115200 that you can not find are declared in termbits.h under /usr/include/asm. I give you a small <snip> of the file: <snip> #define B57600 0010001 #define B115200 0010002 #define B230400 0010003 #define B460800 0010004 #define B500000 0010005 #define B576000 0010006 #define B921600 0010007 #define B1000000 0010010 #define B1152000 0010011 #define B1500000 0010012 #define B2000000 0010013 #define B2500000 0010014 #define B3000000 0010015 #define B3500000 0010016 #define B4000000 0010017 <snip> Furthermore, I think that there is something wrong with your IOCTL. Lets see - I have downloaded and compiled the following program: http://gpsbots.com/tutorials/tut_linux_serial.php Compiled with g++ and ran the program with "strace", i.e. "strace tut_linux_serial". The program runs perfectly and I get the following (relevant) system calls: <snip> ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0 ioctl(3, TCFLSH, 0) = 0 ioctl(3, SNDCTL_TMR_START or TCSETS, {B38400 -opost -isig -icanon -echo ...}) = 0 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0 <snip> With your D module, I have written the following program: <snip - test.d> import com; int main(){ ComStream COM = new ComStream; COM.open("/dev/ttyS0",B9600); return 0; } <snip - test.d> And I get the following (relevant) system calls: ioctl(3, 0x7801, 0x40191fa4) = -1 EINVAL (Invalid argument) ioctl(3, 0x7801, 0x40191fa4) = -1 EINVAL (Invalid argument) Conclusion: I think that you are calling the IOCTL wrongly. I have further investigated which number TCGETS should be. It appears in /usr/include/asm/ioctls.h and its value is 0x5401. I have replaced the IOCTL call with: int tcgetattr(int fd, termios *termios_p) { return ioctl(fd, 0x5401, termios_p); } and it works! now, the system call trace looks like: ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0 BUT, the next error is: Error: ArrayBoundsError com(396) ie the line if (cfsetispeed(&attr,cast(speed_t)BaudRates[baud]) != 0) throw new ComException("Failed to set output speed"); For now, that's all... Best regards, Tiago -- Tiago Gasiba (MSc.) - http://www.gasiba.de Everything should be made as simple as possible, but not simpler.
Oct 27 2005
next sibling parent reply Tiago Gasiba <tiago.gasiba gmail.com> writes:
Tiago Gasiba schrieb:


 BUT, the next error is:
 Error: ArrayBoundsError com(396)
 ie the line
 if (cfsetispeed(&attr,cast(speed_t)BaudRates[baud]) != 0) throw new
ComException("Failed to set output speed");
I should have known... in test.d I have written COM.open("/dev/ttyS0",B9600); instead of COM.open("/dev/ttyS0",BaudRate.B9600); This is a serious source of bugs and I think that you should remove completely the BaudRate.B9600. Just declare the consts and use them/pass them as parameters! If necessary, use different definitions for Windows/Linux. After correcting this small bug, the next one pops out here: open("/dev/ttyS0", O_RDWR|O_NONBLOCK) = 3 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 opost isig icanon echo ...}) = 0 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 opost isig icanon echo ...}) = 0 ioctl(3, 0x7802, 0x40191fa4) = -1 EINVAL (Invalid argument) All the IOCTL's have to be reviewed: The better solution is to rewrite the ioctls's consts. You can find a first attempt in attachment. Best, Tiago -- Tiago Gasiba (MSc.) - http://www.gasiba.de Everything should be made as simple as possible, but not simpler.
Oct 27 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 27 Oct 2005 18:02:40 +0200, Tiago Gasiba <tiago.gasiba gmail.com>  
wrote:
 BUT, the next error is:
 Error: ArrayBoundsError com(396)
 ie the line
 if (cfsetispeed(&attr,cast(speed_t)BaudRates[baud]) != 0) throw new  
 ComException("Failed to set output speed");
I should have known... in test.d I have written COM.open("/dev/ttyS0",B9600); instead of COM.open("/dev/ttyS0",BaudRate.B9600); This is a serious source of bugs and I think that you should remove completely the BaudRate.B9600. Just declare the consts and use them/pass them as parameters! If necessary, use different definitions for Windows/Linux.
No. In order to make it a cross-platform we have to use the same definitions, that is why BaudRate was created. There should be a way to make it error when you fail to pass a BaudRate enum value. Regan
Oct 27 2005
parent reply Tiago Gasiba <tiago.gasiba gmail.com> writes:
 
 No. In order to make it a cross-platform we have to use the same
 definitions, that is why BaudRate was created. There should be a way to
 make it error when you fail to pass a BaudRate enum value.
Not really - You can use a construct similar to this: <snip> import std.c.stdlib; version(linux){ const int A = 0; } version(windows){ const int A = 1; } int main( ){ printf("%d\n",A); return 0; } <snip> If you compile it under Linux you see a "0", in Windows you see a "1" ;) The, in your routines you can just simply pass the argument transparently without the need of a translating array! Best, Tiago -- Tiago Gasiba (M.Sc.) - http://www.gasiba.de Everything should be made as simple as possible, but not simpler.
Oct 28 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
On Fri, 28 Oct 2005 10:53:42 +0200, Tiago Gasiba <tiago.gasiba gmail.com>  
wrote:
 No. In order to make it a cross-platform we have to use the same
 definitions, that is why BaudRate was created. There should be a way to
 make it error when you fail to pass a BaudRate enum value.
Not really - You can use a construct similar to this: <snip> import std.c.stdlib; version(linux){ const int A = 0; } version(windows){ const int A = 1; } int main( ){ printf("%d\n",A); return 0; } <snip> If you compile it under Linux you see a "0", in Windows you see a "1" ;) The, in your routines you can just simply pass the argument transparently without the need of a translating array!
You still have to choose either: - use the windows names - use the linux names - use new names Either way you're going to get someone (as you yourself did) typing the wrong thing. It would be better if you could catch the error at compile time. I was hoping something like this would work: typedef uint baud_t; version(Windows) { enum BaudRate : baud_t { B110 = 110, B300 = 300 } } version(linux) { enum BaudRate : baud_t { B110 = 0x3, B300 = 0x7 } } void foo(BaudRate b) {} void main() { uint a = 5; int b = 5; foo(5); //no error! foo(a); //error foo(b); //error foo(BaudRate.B110); //no error } But it seems that an integer literal is implicitly converted to a baud_t and is thus acceptable as a BaudRate. So, then I tried: version(Windows) { enum BaudRate : uint { B110 = 110, B300 = 300 } } version(linux) { enum BaudRate : uint { B110 = 0x3, B300 = 0x7 } } typedef BaudRate baud_t; void foo(baud_t b) {} and got the same results. Does anyone know how to do this? (restrict the input of a function to one of a bunch of defined values i.e. an Enum or similar) Regan
Oct 28 2005
prev sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 27 Oct 2005 15:04:22 +0200, Tiago Gasiba <tiago.gasiba gmail.com>  
wrote:
 Ok, here is my latest version.

 I can compile it on a ubuntu linux vmware virtual machine but it wont  
 run,
 it errors on the "tcsetattr" call. How about you?

 Regan
Same here. The B57600,B115200 that you can not find are declared in termbits.h under /usr/include/asm. I give you a small <snip> of the file:
<snip> I found them in the headers on my ubuntu system, but, they're not defined in the Digital Mars (DMC) headers. As DMD links with the DMC libraries (it does on Windows) I thought we could only use stuff that was present there. Am I wrong? is it linking with the ubuntu (or other) libraries?
 Furthermore, I think that there is something wrong with your IOCTL. Lets  
 see - I have downloaded and compiled the following program:  
 http://gpsbots.com/tutorials/tut_linux_serial.php
 Compiled with g++ and ran the program with "strace", i.e. "strace  
 tut_linux_serial".
 The program runs perfectly and I get the following (relevant) system  
 calls:

 <snip>
 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon  
 -echo ...}) = 0
 ioctl(3, TCFLSH, 0)                     = 0
 ioctl(3, SNDCTL_TMR_START or TCSETS, {B38400 -opost -isig -icanon -echo  
 ...}) = 0
 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon  
 -echo ...}) = 0
 <snip>

 With your D module, I have written the following program:

 <snip - test.d>
 import com;

 int main(){
   ComStream COM = new ComStream;

   COM.open("/dev/ttyS0",B9600);

   return 0;
 }
 <snip - test.d>

 And I get the following (relevant) system calls:
 ioctl(3, 0x7801, 0x40191fa4)            = -1 EINVAL (Invalid argument)
 ioctl(3, 0x7801, 0x40191fa4)            = -1 EINVAL (Invalid argument)


 Conclusion:
 I think that you are calling the IOCTL wrongly. I have further  
 investigated which number TCGETS should be.
 It appears in /usr/include/asm/ioctls.h and its value is 0x5401.
 I have replaced the IOCTL call with:

 int tcgetattr(int fd, termios *termios_p) { return ioctl(fd, 0x5401,  
 termios_p); }
 and it works! now, the system call trace looks like:

 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon  
 -echo ...}) = 0
 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon  
 -echo ...}) = 0
Did you compile with -version=M_ELF? tcgetattr works for me, it was tcsetattr that was failing. The TCGets value I am using is from the DMC headers (not the ubuntu ones). How do you use strace. I have tried using it on my D executable and all it doesn't seem to show anything of my own code, i.e. I cannot see the ioctl calls. I see some open calls (I assume this is the code DMD adds to the start of every executable).
 BUT, the next error is:
 Error: ArrayBoundsError com(396)
 ie the line
 if (cfsetispeed(&attr,cast(speed_t)BaudRates[baud]) != 0) throw new  
 ComException("Failed to set output speed");
This was due to you using the wrong baud value. Regan.
Oct 27 2005
parent reply Tiago Gasiba <tiago.gasiba gmail.com> writes:
 
 Did you compile with -version=M_ELF?
 tcgetattr works for me, it was tcsetattr that was failing.
 The TCGets value I am using is from the DMC headers (not the ubuntu ones).
No. I just compiled it without any -version stuff... What does M_ELF stand for should it be compiled like this on Linux?
 How do you use strace. I have tried using it on my D executable and all it
 doesn't seem to show anything of my own code, i.e. I cannot see the ioctl
 calls. I see some open calls (I assume this is the code DMD adds to the
 start of every executable).
 
I dont know what is your problem there! strace outputs many lines of information and you have to search for the IOCTLs. For example, the lines I get while executing (as root) the D code for testing com.d are the following: execve("./test_com", ["./test_com"], [/* 75 vars */]) = 0 uname({sys="Linux", node="licoslp0", ...}) = 0 brk(0) = 0x806a000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/root/GNUstep/Library/Libraries/tls/i686/sse2/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/root/GNUstep/Library/Libraries/tls/i686/sse2", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/root/GNUstep/Library/Libraries/tls/i686/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/root/GNUstep/Library/Libraries/tls/i686", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/root/GNUstep/Library/Libraries/tls/sse2/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/root/GNUstep/Library/Libraries/tls/sse2", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/root/GNUstep/Library/Libraries/tls/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/root/GNUstep/Library/Libraries/tls", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/root/GNUstep/Library/Libraries/i686/sse2/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/root/GNUstep/Library/Libraries/i686/sse2", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/root/GNUstep/Library/Libraries/i686/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/root/GNUstep/Library/Libraries/i686", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/root/GNUstep/Library/Libraries/sse2/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/root/GNUstep/Library/Libraries/sse2", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/root/GNUstep/Library/Libraries/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/root/GNUstep/Library/Libraries", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/Local/Library/Libraries/tls/i686/sse2/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/Local/Library/Libraries/tls/i686/sse2", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/Local/Library/Libraries/tls/i686/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/Local/Library/Libraries/tls/i686", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/Local/Library/Libraries/tls/sse2/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/Local/Library/Libraries/tls/sse2", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/Local/Library/Libraries/tls/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/Local/Library/Libraries/tls", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/Local/Library/Libraries/i686/sse2/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/Local/Library/Libraries/i686/sse2", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/Local/Library/Libraries/i686/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/Local/Library/Libraries/i686", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/Local/Library/Libraries/sse2/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/Local/Library/Libraries/sse2", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/Local/Library/Libraries/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/Local/Library/Libraries", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/System/Library/Libraries/tls/i686/sse2/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/System/Library/Libraries/tls/i686/sse2", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/System/Library/Libraries/tls/i686/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/System/Library/Libraries/tls/i686", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/System/Library/Libraries/tls/sse2/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/System/Library/Libraries/tls/sse2", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/System/Library/Libraries/tls/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/System/Library/Libraries/tls", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/System/Library/Libraries/i686/sse2/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/System/Library/Libraries/i686/sse2", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/System/Library/Libraries/i686/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/System/Library/Libraries/i686", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/System/Library/Libraries/sse2/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/System/Library/Libraries/sse2", 0xbff2950c) = -1 ENOENT (No such file or directory) open("/usr/GNUstep/System/Library/Libraries/libpthread.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/usr/GNUstep/System/Library/Libraries", {st_mode=S_IFDIR|0755, st_size=328, ...}) = 0 open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=131025, ...}) = 0 old_mmap(NULL, 131025, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40017000 close(3) = 0 open("/lib/tls/libpthread.so.0", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0pH\0\000"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=93266, ...}) = 0 old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40037000 old_mmap(NULL, 70104, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x40038000 madvise(0x40038000, 70104, MADV_SEQUENTIAL|0x1) = 0 old_mmap(0x40046000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xd000) = 0x40046000 old_mmap(0x40048000, 4568, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x40048000 close(3) = 0 open("/usr/GNUstep/System/Library/Libraries/libm.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) open("/lib/tls/libm.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\2203\0"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=191109, ...}) = 0 old_mmap(NULL, 151712, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x4004a000 madvise(0x4004a000, 151712, MADV_SEQUENTIAL|0x1) = 0 old_mmap(0x4006e000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x23000) = 0x4006e000 close(3) = 0 open("/usr/GNUstep/System/Library/Libraries/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) open("/lib/tls/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0`O\1\000"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1417063, ...}) = 0 old_mmap(NULL, 1174492, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x40070000 madvise(0x40070000, 1174492, MADV_SEQUENTIAL|0x1) = 0 old_mmap(0x40189000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x119000) = 0x40189000 old_mmap(0x4018d000, 7132, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4018d000 close(3) = 0 old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4018f000 mprotect(0x40189000, 4096, PROT_READ) = 0 set_thread_area({entry_number:-1 -> 6, base_addr:0x4018f6c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 munmap(0x40017000, 131025) = 0 set_tid_address(0x4018f708) = 6267 rt_sigaction(SIGRTMIN, {0x4003c3c0, [], SA_SIGINFO}, NULL, 8) = 0 rt_sigaction(SIGRT_1, {0x4003c440, [], SA_RESTART|SA_SIGINFO}, NULL, 8) = 0 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 getrlimit(RLIMIT_STACK, {rlim_cur=RLIM_INFINITY, rlim_max=RLIM_INFINITY}) = 0 _sysctl({{CTL_KERN, KERN_VERSION, 0, 20d91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 2, 0xbff29c30, 30, (nil), 0}) = 0 brk(0) = 0x806a000 brk(0x808b000) = 0x808b000 mmap2(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40190000 rt_sigaction(SIGUSR1, {0x8057c50, ~[RTMIN RT_1], 0}, NULL, 8) = 0 rt_sigaction(SIGUSR2, {0x8057cf0, ~[RTMIN RT_1], 0}, NULL, 8) = 0 open("/dev/ttyS0", O_RDWR|O_NONBLOCK) = 3 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 opost isig icanon echo ...}) = 0 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 opost isig icanon echo ...}) = 0 ioctl(3, 0x7802, 0x40191fa4) = -1 EINVAL (Invalid argument) fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40017000 write(1, "Error: Failed to set attributes "..., 51Error: Failed to set attributes {Invalid argument} ) = 51 munmap(0x40017000, 4096) = 0 exit_group(1) Notice the IOCTLs in the last lines... ;) In this case, the last IOCTL, namely ioctl(3, 0x7802, 0x40191fa4) is not recognized by the OS! (it results Invalid argument) Best, Tiago PS: I'm using a SuSE 10.0 with kernel 2.6.13-8-default, but this does not make any difference for the strace! -- Tiago Gasiba (M.Sc.) - http://www.gasiba.de Everything should be made as simple as possible, but not simpler.
Oct 28 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
On Fri, 28 Oct 2005 10:47:50 +0200, Tiago Gasiba <tiago.gasiba gmail.com>  
wrote:
 Did you compile with -version=M_ELF?
 tcgetattr works for me, it was tcsetattr that was failing.
 The TCGets value I am using is from the DMC headers (not the ubuntu  
 ones).
No. I just compiled it without any -version stuff... What does M_ELF stand for should it be compiled like this on Linux?
No idea. All I know is that on ubuntu the tcgetattr in the M_ELF block works whereas the other does not.
 How do you use strace. I have tried using it on my D executable and all  
 it
 doesn't seem to show anything of my own code, i.e. I cannot see the  
 ioctl
 calls. I see some open calls (I assume this is the code DMD adds to the
 start of every executable).
I dont know what is your problem there! strace outputs many lines of information and you have to search for the IOCTLs.
I realise this. I didn't get these lines:
 open("/dev/ttyS0", O_RDWR|O_NONBLOCK)   = 3
 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 opost isig icanon echo  
 ...}) = 0
 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 opost isig icanon echo  
 ...}) = 0
 ioctl(3, 0x7802, 0x40191fa4)            = -1 EINVAL (Invalid argument)
I was looking for them, especially the open containing "/dev/ttyS0". I didn't get anywhere near as many lines as you did, mine was much shorter. Can anyone tell me whether DMD on linux links with it's own C library (as it does on windows) or whether it links with the system libraries. If it's linking with the system libraries then I'll use the system headers to define the com stuff (as opposed to using the DMC ones). Regan
Oct 28 2005
prev sibling parent "Regan Heath" <regan netwin.co.nz> writes:
New version. This one works for me on ubuntu linux. However, the timeout  
on read isn't as instant as I'd like, each call to read takes approx 1 sec  
to timeout.

Regan
Oct 28 2005
prev sibling parent reply Don Clugston <dac nospam.com.au> writes:
Thanks Regan.

Unfortunately, the timeouts don't work in that code. Not for me, anyway. 
(In fact, I've never been able to get COM timeouts to work in Windows, 
except when I open the port in OVERLAPPED mode). For my application, 
timeouts are extremely important (a timeout occurs about once every five 
minutes). For every application I've used, a 0.5 second timeout has 
worked well. I modified your code to get this to work, but it's too 
hacky and specific to post here at the moment.

Thanks again, you've saved me quite a bit of time.
-Don



Regan Heath wrote:
 On Mon, 24 Oct 2005 13:03:16 +0200, Don Clugston <dac nospam.com.au> wrote:
 
 Has anyone accessed serial (COM) ports using D (under Windows)?
Yes.
 Does Mango support them?
 If there is currently nothing in D, does anyone know of a candidate 
 that  could be ported to D?
 It ought to be possible to create something that would work on both  
 Windows and Linux PCs, since the hardware is the same.
The attached source is a COM stream for windows only. I have also written COM code on linux and freebsd and could probably add support for these two to the attached source, let me know if you're interested. Regan
Oct 26 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 27 Oct 2005 08:30:24 +0200, Don Clugston <dac nospam.com.au> wrote:
 Thanks Regan.

 Unfortunately, the timeouts don't work in that code. Not for me, anyway.  
 (In fact, I've never been able to get COM timeouts to work in Windows,  
 except when I open the port in OVERLAPPED mode). For my application,  
 timeouts are extremely important (a timeout occurs about once every five  
 minutes). For every application I've used, a 0.5 second timeout has  
 worked well. I modified your code to get this to work, but it's too  
 hacky and specific to post here at the moment.
So... you want it to timeout after 0.5 seconds on a read? What sort of timeout occurs once every 5 mins? ReadFile should return immediately .. and you could use msleep to create a timeout (though it may not be 100% acurate). Is that what you did? Opening using OVERLAPPED then using WaitCommEvent should allow you to do a "wait for data then read" sort of thing.
 Thanks again, you've saved me quite a bit of time.
Glad I could help. Regan
 Regan Heath wrote:
 On Mon, 24 Oct 2005 13:03:16 +0200, Don Clugston <dac nospam.com.au>  
 wrote:

 Has anyone accessed serial (COM) ports using D (under Windows)?
Yes.
 Does Mango support them?
 If there is currently nothing in D, does anyone know of a candidate  
 that  could be ported to D?
 It ought to be possible to create something that would work on both   
 Windows and Linux PCs, since the hardware is the same.
The attached source is a COM stream for windows only. I have also written COM code on linux and freebsd and could probably add support for these two to the attached source, let me know if you're interested. Regan
Oct 27 2005
parent Don Clugston <dac nospam.com.au> writes:
Regan Heath wrote:
 On Thu, 27 Oct 2005 08:30:24 +0200, Don Clugston <dac nospam.com.au> wrote:
 
 Thanks Regan.

 Unfortunately, the timeouts don't work in that code. Not for me, 
 anyway.  (In fact, I've never been able to get COM timeouts to work in 
 Windows,  except when I open the port in OVERLAPPED mode). For my 
 application,  timeouts are extremely important (a timeout occurs about 
 once every five  minutes). For every application I've used, a 0.5 
 second timeout has  worked well. I modified your code to get this to 
 work, but it's too  hacky and specific to post here at the moment.
So... you want it to timeout after 0.5 seconds on a read? What sort of timeout occurs once every 5 mins?
The item of measurement equipment I'm currently working on has occasional glitches where it ignores commands. Such glitches occur about ten times per hour on this machine. It can happen when the PLC inside the equipment is momentarily overworked, and dumps its command buffer because it can't keep up. (Poor design, but it seems to be relatively common behaviour amongst engineering tools). The other case is when the power to the machine has been cut temporarily so that the PLC has reset, again clearing the command buffer, or ignoring commands for the few milliseconds it takes to restart. It's an important issue when your program needs to run 24/7.
 ReadFile should return immediately .. and you could use msleep to create 
 a  timeout (though it may not be 100% acurate). Is that what you did?
In this case, yes, and it's been enough to get it going. The length of the timeout period is generally not very critical, it's just important that the system not hang.
 Opening using OVERLAPPED then using WaitCommEvent should allow you to do 
 a  "wait for data then read" sort of thing.
This is what I plan to do in the longer term. I've done it in C++, but in D there are delegates and better multithreading support, so it can potentially be much better. It really isn't much different to a web client, you cannot guarantee that you'll get a response to all packets you send, this is why I thought it has commonality with Mango.
Oct 27 2005