October 26, 2005 Re: Access to serial ports in Windows | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | 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. |
October 27, 2005 Re: Access to serial ports in Windows | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tiago Gasiba | 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 |
October 27, 2005 Re: Access to serial ports in Windows | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | 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
|
October 27, 2005 Re: Access to serial ports in Windows | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | 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 |
October 27, 2005 Re: Access to serial ports in Windows | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | 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. |
October 27, 2005 Re: Access to serial ports in Windows | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath Attachments: | 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 |
October 27, 2005 Re: Access to serial ports in Windows | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | 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. |
October 27, 2005 Re: Access to serial ports in Windows | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tiago Gasiba Attachments: | 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. |
October 27, 2005 Re: Access to serial ports in Windows | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tiago Gasiba | 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
|
October 27, 2005 Re: Access to serial ports in Windows | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tiago Gasiba | 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. |
Copyright © 1999-2021 by the D Language Foundation