Using serial port with goserial packages

1,825 views
Skip to first unread message

alex martin

unread,
Nov 11, 2012, 5:26:27 PM11/11/12
to golan...@googlegroups.com
Hi
i'm trying to develop a little procedure to send a SMS via AT commands; i found goserial package to connect to serial and a test with loop back works.
When i try  to use a modem write function work but read function don't wait the response from modem ?
Are there someone that use this packages??
I don't know the syscall in windows so the following piece of code is for me "mysterious" ...

func (p *serialPort) Read(buf []byte) (int, error) {
if p == nil || p.f == nil {
return 0, fmt.Errorf("Invalid port on read %v %v", p, p.f)
}

p.rl.Lock()
defer p.rl.Unlock()

if err := resetEvent(p.ro.HEvent); err != nil {
return 0, err
}
var done uint32
err := syscall.ReadFile(p.fd, buf, &done, p.ro)
 //        fmt.Printf("\np.fd %+v,\nbuf %+v,\nbuf %s done %+v, p.ro %+v \n",p.fd,buf,buf,done,p.ro
if err != nil && err != syscall.ERROR_IO_PENDING {
return int(done), err
}
return getOverlappedResult(p.fd, p.ro)
}


How can i wait the response from modem ?
A curiosity.. Why some functions, like syscall.ReadFile, is not present in web documentation?

Alex

brainman

unread,
Nov 11, 2012, 6:10:56 PM11/11/12
to golan...@googlegroups.com
On Monday, 12 November 2012 09:26:27 UTC+11, alex martin wrote:

> ... read function don't wait the response from modem ?

It is not clear to me what your problem is. If you like help, just post small program for us to demonstrate your issue.

> ... Are there someone that use this packages??

I think, I looked at this package long time ago.

> ... I don't know the syscall in windows so the following piece of code is for me "mysterious" ...

I always look at the source code so see what it does. Also see, for example, http://msdn.microsoft.com/en-us/library/ff802693.aspx for "why", especially "Overlapped I/O" section.

> ... How can i wait the response from modem ?

I could be wrong, but I think (*goserial.serialPort).Read should work for you.

> ... Why some functions, like syscall.ReadFile, is not present in web documentation?

Are you referring to http://tip.golang.org/pkg/syscall/ ? If you are, it is running "godoc -http=:80" command on platform other them windows. And godoc command only shows packages for the platform it runs on. syscall package looks different on different platforms. You could use godoc command on you computer to see what you need. Alternatively, just look at the source files.

Alex

alex martin

unread,
Nov 11, 2012, 10:20:00 PM11/11/12
to golan...@googlegroups.com
Hi Alex
thank for links 


> ... read function don't wait the response from modem ?
When i send a command to modem by go-serial Write i want to read the response; when i do this my example not read all chars at first time so i do iterate until there aren't chars in buffer
ie
 
->ATE0
<-OK

this is the pieces of main

1        c := &serial.Config{Name: "COM26", Baud: 115200}
2       s, err := serial.OpenPort(c)
3        if err != nil {
4                log.Fatal(err)
5        }
6
7        n, err := s.Write([]byte("ATE0\r\n"))
8        if err != nil {
9                log.Fatal(err)
10        }

11        buf := make([]byte, 128)
12       n, err = s.Read(buf)
13        if err != nil {
14                log.Fatal(err)
15        }
16        fmt.Printf("\nbuffer %v\nbuffer %s", buf[:n],buf[:n])

the result of Read is 

buffer [13]
buffer

when i repeat two time  rows from 12 to 16 the result is 

buffer [13]
buffer
buffer [10 79 75 13 10]
buffer
OK

The function  func (p *serialPort) Read(buf []byte) (int, error)  read <CR> and  <NL>OK<CR><NL> in two step.

>I always look at the source code so see what it does. Also see, for example, http://msdn.microsoft.com/en-us/library/ff802693.aspx for "why", especially "Overlapped I/O" section.

Thank, i was looking for some information about overlapping because Read function call,after syscall.ReadFile, a func called "getOverlappedResult(p.fd, p.ro)"

>Are you referring to http://tip.golang.org/pkg/syscall/ ?
Yes, I don't know  "godoc -http=:80", great tips

Alex
 






brainman

unread,
Nov 11, 2012, 11:10:13 PM11/11/12
to golan...@googlegroups.com
On Monday, 12 November 2012 14:20:00 UTC+11, alex martin wrote:

> ... i want to read the response; when i do this my example not read all chars at first time so i do iterate until there aren't chars in buffer

I think you do not have clear plan of attack. You say you want to read "response", but, I think< you aren't clear what "response" means.

Considering you are talking to a modem, what I would do is say that all modem replies are "lines" = sequence of bytes with byte=13 at the end. Then I would write a function to read one line (read byte by byte and check if it is 13 and exit if it is). Then I would write a function that reads a sequence of lines until I get line of "OK", then that sequence is a "modem response" to your command. You could analyze these to determine modem state.

I could be wrong about value of line end (13), it might be 10 instead. Also, if you use 13, then you should ignore 10, and vice verse. As far as I remember modems could do one or the other or both. They could also "echo" commands you send, or they can accept them without "echo". It is all can be configure in the modem. So you should be aware.

Hope it helps.

Alex

Tarmigan Casebolt

unread,
Nov 11, 2012, 11:13:32 PM11/11/12
to alex martin, golan...@googlegroups.com
Protip: CC the author of the package when you have questions about it.

If I understand your description, I think that is working as intended.  (At some point I would like to add more tests and functionality to the package, but what you're interested in should work.)

Reading a fixed number of bytes from a serial port can take an indeterminate amount of time.  The indended behavior of goserial Read() is this:
If NO bytes can be read, then block until at least 1 byte is available.
If ANY bytes can be read, then read as many bytes as possible without blocking, and return those bytes.

With this low-level behavior you should be able to build the behavior you want.  If you know how many bytes you expect, you could wrap it in io.ReadFull or io.ReadAtLeast, but you should also think about how to timeout if those bytes don't come back.  You could construct a ReadFullOrTimeout function for yourself but that functionality is not in the goserial package.  But you might also want to make a ReadUntilNewlineOrTimeout function or something.  It's application specific, so you will need to write that wrapper yourself.

Thanks,
Tarmigan


alex martin

unread,
Nov 12, 2012, 12:20:38 AM11/12/12
to golan...@googlegroups.com
Alex I'm sorry for my awful english. 

>I think you do not have clear plan of attack

I expected that Read function read all buffer, not some char. Tarmigan on the following reply explain the reason 

>Considering you are talking to a modem, what I would do is say that all modem replies are "lines" = sequence of bytes with byte=13 at the end. Then > I would write a function to read one line (read byte by byte and check if it is 13 and exit if it is). Then I would write a function that reads a sequence of >lines until I get line of "OK", then that sequence is a "modem response" to your command. You could analyze these to determine modem state

I'm arrived at the same conclusion, i search "OK<CR><NL>" string with bytes.Index.. If position is <> -1 the string is not present so i continue to read. 

notnot

unread,
Jul 1, 2013, 7:52:15 PM7/1/13
to golan...@googlegroups.com, alex martin
Hello, hijacking an old thread, I stumbled upon it while researching an issue I'm having.
 
Reading a fixed number of bytes from a serial port can take an indeterminate amount of time.  The indended behavior of goserial Read() is this:
If NO bytes can be read, then block until at least 1 byte is available.
If ANY bytes can be read, then read as many bytes as possible without blocking, and return those bytes. 

This would be the behavior I would like to see, but on my system (Ubuntu) it doesn't work that way. Instead of blocking until data can be read from the tty file, serial Read() returns an error io.EOF almost all the time, if there isn't new data available. I'm new to serial port programming so I thought this behavior could be 'normal'. I worked my way around the issue by calling time.Sleep() after getting an io.EOF and trying again. I don't quite like this polling mechanism, and i would rather see that serial Read() would do the proper blocking. Is this a bug in your serial package on linux?

 

Dave Cheney

unread,
Jul 1, 2013, 7:57:26 PM7/1/13
to notnot, golang-nuts, alex martin
-1 for hijacking an old thread -- start a new one please.
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Jan Mercl

unread,
Jul 2, 2013, 1:43:21 AM7/2/13
to notnot, golang-nuts, alex martin
On Tue, Jul 2, 2013 at 1:52 AM, notnot <snes...@gmail.com> wrote:
> This would be the behavior I would like to see, but on my system (Ubuntu) it
> doesn't work that way. Instead of blocking until data can be read from the
> tty file, serial Read() returns an error io.EOF almost all the time, if
> there isn't new data available. I'm new to serial port programming so I
> thought this behavior could be 'normal'. I worked my way around the issue by
> calling time.Sleep() after getting an io.EOF and trying again. I don't quite
> like this polling mechanism, and i would rather see that serial Read() would
> do the proper blocking. Is this a bug in your serial package on linux?

Setting the port (its fd actually) to non-block mode should solve the
EOF on no data problem. See for example [1].

[1]: https://github.com/schleibinger/sio/blob/master/sio.go#L86

-j

Erwin

unread,
Jul 2, 2013, 5:47:41 AM7/2/13
to Jan Mercl, golang-nuts, alex martin
Jan, thanks for pointing me to that serial IO package. Its an interesting one because it doesn't use CGO. Linux only though, and the software I am writing might have to run on OS X as well. Perhaps its not that hard to implement a syscall only implementation for OS X, I'll see.

I guess I figured out why I was having the issues with github.com/tarm/goserial. This package is supposed to set /dev/tty* to blocking mode, but that wasn't working as expected, probably because the /dev/tty* file was already opened by another program (the Arduino serial monitor) in non-blocking mode. When I continued testing this morning, without the Arduino monitoring software running, I no longer get the io.EOF :)



 
 
Reply all
Reply to author
Forward
0 new messages