问题的提出
由于golang的微线程(goroutines)的特征,实现同时交互进行的任务变得自然而容易。一直想实现一个能对手机进行自动发送AT的程序,而实现相应的自动化测试。现在用golang来偿试一下。
问题所依赖的库
使用golang来实现的对串口的操作的库从网上找到了一个,就不用重新发明轮子啦。https://github.com/huin/goserial
在Windows下使用的文件如下:
serial.go
/*
Goserial is a simple go package to allow you to read and write from
the serial port as a stream of bytes.
It aims to have the same API on all platforms, including windows. As
an added bonus, the windows package does not use cgo, so you can cross
compile for windows from another platform. Unfortunately goinstall
does not currently let you cross compile so you will have to do it
manually:
GOOS=windows make clean install
Currently there is very little in the way of configurability. You can
set the baud rate. Then you can Read(), Write(), or Close() the
connection. Read() will block until at least one byte is returned.
Write is the same. There is currently no exposed way to set the
timeouts, though patches are welcome.
Currently ports are opened with 8 data bits, 1 stop bit, no parity, no hardware
flow control, and no software flow control by default. This works fine for
many real devices and many faux serial devices including usb-to-serial
converters and bluetooth serial ports.
You may Read() and Write() simulantiously on the same connection (from
different goroutines).
Example usage:
package main
import (
"github.com/tarm/goserial"
"log"
)
func main() {
c := &serial.Config{Name: "COM5", Baud: 115200}
s, err := serial.OpenPort(c)
if err != nil {
log.Fatal(err)
}
n, err := s.Write([]byte("test"))
if err != nil {
log.Fatal(err)
}
buf := make([]byte, 128)
n, err = s.Read(buf)
if err != nil {
log.Fatal(err)
}
log.Print("%q", buf[:n])
}
*/
package goserial
import (
"errors"
"io"
)
var (
ErrConfigStopBits = errors.New("goserial config: bad number of stop bits")
ErrConfigByteSize = errors.New("goserial config: bad byte size")
ErrConfigParity = errors.New("goserial config: bad parity")
)
type ParityMode byte
const (
ParityNone = ParityMode(iota)
ParityEven
ParityOdd
)
type ByteSize byte
const (
Byte8 = ByteSize(iota)
Byte5
Byte6
Byte7
)
type StopBits byte
const (
StopBits1 = StopBits(iota)
StopBits2
)
// Config contains the information needed to open a serial port.
//
// Currently few options are implemented, but more may be added in the
// future (patches welcome), so it is recommended that you create a
// new config addressing the fields by name rather than by order.
//
// For example:
//
// c0 := &serial.Config{Name: "COM45", Baud: 115200}
// or
// c1 := new(serial.Config)
// c1.Name = "/dev/tty.usbserial"
// c1.Baud = 115200
//
type Config struct {
Name string
Baud int
Size ByteSize
Parity ParityMode
StopBits StopBits
// RTSFlowControl bool
// DTRFlowControl bool
// XONFlowControl bool
CRLFTranslate bool // Ignored on Windows.
// TimeoutStuff int
}
func (c *Config) check() error {
switch c.Size {
case Byte5, Byte6, Byte7, Byte8:
default:
return ErrConfigByteSize
}
switch c.StopBits {
case StopBits1, StopBits2:
default:
return ErrConfigParity
}
switch c.Parity {
case ParityNone, ParityEven, ParityOdd:
default:
return ErrConfigParity
}
return nil
}
// OpenPort opens a serial port with the specified configuration
func OpenPort(c *Config) (io.ReadWriteCloser, error) {
if err := c.check(); err != nil {
return nil, err
}
return openPort(c.Name, c)
}
// func Flush()
// func SendBreak()
// func RegisterBreakHandler(func())
Goserial is a simple go package to allow you to read and write from
the serial port as a stream of bytes.
It aims to have the same API on all platforms, including windows. As
an added bonus, the windows package does not use cgo, so you can cross
compile for windows from another platform. Unfortunately goinstall
does not currently let you cross compile so you will have to do it
manually:
GOOS=windows make clean install
Currently there is very little in the way of configurability. You can
set the baud rate. Then you can Read(), Write(), or Close() the
connection. Read() will block until at least one byte is returned.
Write is the same. There is currently no exposed way to set the
timeouts, though patches are welcome.
Currently ports are opened with 8 data bits, 1 stop bit, no parity, no hardware
flow control, and no software flow control by default. This works fine for
many real devices and many faux serial devices including usb-to-serial
converters and bluetooth serial ports.
You may Read() and Write() simulantiously on the same connection (from
different goroutines).
Example usage:
package main
import (
"github.com/tarm/goserial"
"log"
)
func main() {
c := &serial.Config{Name: "COM5", Baud: 115200}
s, err := serial.OpenPort(c)
if err != nil {
log.Fatal(err)
}
n, err := s.Write([]byte("test"))
if err != nil {
log.Fatal(err)
}
buf := make([]byte, 128)
n, err = s.Read(buf)
if err != nil {
log.Fatal(err)
}
log.Print("%q", buf[:n])
}
*/
package goserial
import (
"errors"
"io"
)
var (
ErrConfigStopBits = errors.New("goserial config: bad number of stop bits")
ErrConfigByteSize = errors.New("goserial config: bad byte size")
ErrConfigParity = errors.New("goserial config: bad parity")
)
type ParityMode byte
const (
ParityNone = ParityMode(iota)
ParityEven
ParityOdd
)
type ByteSize byte
const (
Byte8 = ByteSize(iota)
Byte5
Byte6
Byte7
)
type StopBits byte
const (
StopBits1 = StopBits(iota)
StopBits2
)
// Config contains the information needed to open a serial port.
//
// Currently few options are implemented, but more may be added in the
// future (patches welcome), so it is recommended that you create a
// new config addressing the fields by name rather than by order.
//
// For example:
//
// c0 := &serial.Config{Name: "COM45", Baud: 115200}
// or
// c1 := new(serial.Config)
// c1.Name = "/dev/tty.usbserial"
// c1.Baud = 115200
//
type Config struct {
Name string
Baud int
Size ByteSize
Parity ParityMode
StopBits StopBits
// RTSFlowControl bool
// DTRFlowControl bool
// XONFlowControl bool
CRLFTranslate bool // Ignored on Windows.
// TimeoutStuff int
}
func (c *Config) check() error {
switch c.Size {
case Byte5, Byte6, Byte7, Byte8:
default:
return ErrConfigByteSize
}
switch c.StopBits {
case StopBits1, StopBits2:
default:
return ErrConfigParity
}
switch c.Parity {
case ParityNone, ParityEven, ParityOdd:
default:
return ErrConfigParity
}
return nil
}
// OpenPort opens a serial port with the specified configuration
func OpenPort(c *Config) (io.ReadWriteCloser, error) {
if err := c.check(); err != nil {
return nil, err
}
return openPort(c.Name, c)
}
// func Flush()
// func SendBreak()
// func RegisterBreakHandler(func())
serial_windows.go
// +build windows
package goserial
import (
"fmt"
"io"
"os"
"sync"
"syscall"
"unsafe"
)
type serialPort struct {
f *os.File
fd syscall.Handle
rl sync.Mutex
wl sync.Mutex
ro *syscall.Overlapped
wo *syscall.Overlapped
}
type structDCB struct {
DCBlength, BaudRate uint32
flags [4]byte
wReserved, XonLim, XoffLim uint16
ByteSize, Parity, StopBits byte
XonChar, XoffChar, ErrorChar, EofChar, EvtChar byte
wReserved1 uint16
}
type structTimeouts struct {
ReadIntervalTimeout uint32
ReadTotalTimeoutMultiplier uint32
ReadTotalTimeoutConstant uint32
WriteTotalTimeoutMultiplier uint32
WriteTotalTimeoutConstant uint32
}
func openPort(name string, c *Config) (rwc io.ReadWriteCloser, err error) {
if len(name) > 0 && name[0]!= '\\' {
name = "\\\\.\\"+ name
}
h, err := syscall.CreateFile(syscall.StringToUTF16Ptr(name),
syscall.GENERIC_READ|syscall.GENERIC_WRITE,
0,
nil,
syscall.OPEN_EXISTING,
syscall.FILE_ATTRIBUTE_NORMAL|syscall.FILE_FLAG_OVERLAPPED,
0)
if err != nil {
return nil, err
}
f := os.NewFile(uintptr(h), name)
defer func() {
if err != nil {
f.Close()
}
}()
if err = setCommState(h, c); err != nil {
return
}
if err = setupComm(h, 64, 64); err != nil {
return
}
if err = setCommTimeouts(h); err != nil {
return
}
if err = setCommMask(h); err != nil {
return
}
ro, err := newOverlapped()
if err != nil {
return
}
wo, err := newOverlapped()
if err != nil {
return
}
port :=new(serialPort)
port.f = f
port.fd = h
port.ro = ro
port.wo = wo
return port, nil
}
func (p *serialPort) Close() error {
return p.f.Close()
}
func (p *serialPort) Write(buf []byte) (int, error) {
p.wl.Lock()
defer p.wl.Unlock()
if err := resetEvent(p.wo.HEvent); err != nil {
return 0, err
}
var n uint32
err := syscall.WriteFile(p.fd, buf,&n, p.wo)
if err != nil && err != syscall.ERROR_IO_PENDING {
return int(n), err
}
return getOverlappedResult(p.fd, p.wo)
}
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)
if err != nil && err != syscall.ERROR_IO_PENDING {
return int(done), err
}
return getOverlappedResult(p.fd, p.ro)
}
var (
nSetCommState,
nSetCommTimeouts,
nSetCommMask,
nSetupComm,
nGetOverlappedResult,
nCreateEvent,
nResetEvent uintptr
)
func init() {
k32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
panic("LoadLibrary " + err.Error())
}
defer syscall.FreeLibrary(k32)
nSetCommState = getProcAddr(k32, "SetCommState")
nSetCommTimeouts = getProcAddr(k32, "SetCommTimeouts")
nSetCommMask = getProcAddr(k32, "SetCommMask")
nSetupComm = getProcAddr(k32, "SetupComm")
nGetOverlappedResult = getProcAddr(k32, "GetOverlappedResult")
nCreateEvent = getProcAddr(k32, "CreateEventW")
nResetEvent = getProcAddr(k32, "ResetEvent")
}
func getProcAddr(lib syscall.Handle, name string) uintptr {
addr, err := syscall.GetProcAddress(lib, name)
if err != nil {
panic(name + " " + err.Error())
}
return addr
}
func setCommState(h syscall.Handle, c *Config) error {
var params structDCB
params.DCBlength = uint32(unsafe.Sizeof(params))
params.flags[0] = 0x01 // fBinary
params.flags[0] |= 0x10 // Assert DSR
params.BaudRate = uint32(c.Baud)
// Select byte size.
switch c.Size {
case Byte5:
params.ByteSize = 5
case Byte6:
params.ByteSize = 6
case Byte7:
params.ByteSize = 7
case Byte8:
params.ByteSize = 8
default:
panic(c.Size)
}
// Select parity mode.
switch c.Parity {
case ParityNone:
params.Parity = 0
case ParityEven:
params.Parity = 2
case ParityOdd:
params.Parity = 1
default:
panic(c.Parity)
}
// Selet stop bits.
switch c.StopBits {
case StopBits1:
params.StopBits = 0
case StopBits2:
params.StopBits = 2
default:
panic(c.StopBits)
}
r, _, err := syscall.Syscall(nSetCommState,2, uintptr(h), uintptr(unsafe.Pointer(¶ms)),0)
if r == 0 {
return err
}
return nil
}
func setCommTimeouts(h syscall.Handle) error {
var timeouts structTimeouts
const MAXDWORD = 1<<32- 1
timeouts.ReadIntervalTimeout = MAXDWORD
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD
timeouts.ReadTotalTimeoutConstant = MAXDWORD- 1
/* From http://msdn.microsoft.com/en-us/library/aa363190(v=VS.85).aspx
For blocking I/O see below:
Remarks:
If an application sets ReadIntervalTimeout and
ReadTotalTimeoutMultiplier to MAXDWORD and sets
ReadTotalTimeoutConstant to a value greater than zero and
less than MAXDWORD, one of the following occurs when the
ReadFile function is called:
If there are any bytes in the input buffer, ReadFile returns
immediately with the bytes in the buffer.
If there are no bytes in the input buffer, ReadFile waits
until a byte arrives and then returns immediately.
If no bytes arrive within the time specified by
ReadTotalTimeoutConstant, ReadFile times out.
*/
r, _, err := syscall.Syscall(nSetCommTimeouts,2, uintptr(h), uintptr(unsafe.Pointer(&timeouts)),0)
if r == 0 {
return err
}
return nil
}
func setupComm(h syscall.Handle, in, out int) error {
r, _, err := syscall.Syscall(nSetupComm,3, uintptr(h), uintptr(in), uintptr(out))
if r == 0 {
return err
}
return nil
}
func setCommMask(h syscall.Handle) error {
const EV_RXCHAR = 0x0001
r, _, err := syscall.Syscall(nSetCommMask,2, uintptr(h), EV_RXCHAR, 0)
if r == 0 {
return err
}
return nil
}
func resetEvent(h syscall.Handle) error {
r, _, err := syscall.Syscall(nResetEvent,1, uintptr(h), 0,0)
if r == 0 {
return err
}
return nil
}
func newOverlapped() (*syscall.Overlapped, error) {
var overlapped syscall.Overlapped
r, _, err := syscall.Syscall6(nCreateEvent,4, 0, 1, 0, 0,0, 0)
if r == 0 {
return nil, err
}
overlapped.HEvent = syscall.Handle(r)
return &overlapped, nil
}
func getOverlappedResult(h syscall.Handle, overlapped *syscall.Overlapped) (int, error) {
var n int
r, _, err := syscall.Syscall6(nGetOverlappedResult,4,
uintptr(h),
uintptr(unsafe.Pointer(overlapped)),
uintptr(unsafe.Pointer(&n)), 1, 0, 0)
if r == 0 {
return n, err
}
return n, nil
}
package goserial
import (
"fmt"
"io"
"os"
"sync"
"syscall"
"unsafe"
)
type serialPort struct {
f *os.File
fd syscall.Handle
rl sync.Mutex
wl sync.Mutex
ro *syscall.Overlapped
wo *syscall.Overlapped
}
type structDCB struct {
DCBlength, BaudRate uint32
flags [4]byte
wReserved, XonLim, XoffLim uint16
ByteSize, Parity, StopBits byte
XonChar, XoffChar, ErrorChar, EofChar, EvtChar byte
wReserved1 uint16
}
type structTimeouts struct {
ReadIntervalTimeout uint32
ReadTotalTimeoutMultiplier uint32
ReadTotalTimeoutConstant uint32
WriteTotalTimeoutMultiplier uint32
WriteTotalTimeoutConstant uint32
}
func openPort(name string, c *Config) (rwc io.ReadWriteCloser, err error) {
if len(name) > 0 && name[0]!= '\\' {
name = "\\\\.\\"+ name
}
h, err := syscall.CreateFile(syscall.StringToUTF16Ptr(name),
syscall.GENERIC_READ|syscall.GENERIC_WRITE,
0,
nil,
syscall.OPEN_EXISTING,
syscall.FILE_ATTRIBUTE_NORMAL|syscall.FILE_FLAG_OVERLAPPED,
0)
if err != nil {
return nil, err
}
f := os.NewFile(uintptr(h), name)
defer func() {
if err != nil {
f.Close()
}
}()
if err = setCommState(h, c); err != nil {
return
}
if err = setupComm(h, 64, 64); err != nil {
return
}
if err = setCommTimeouts(h); err != nil {
return
}
if err = setCommMask(h); err != nil {
return
}
ro, err := newOverlapped()
if err != nil {
return
}
wo, err := newOverlapped()
if err != nil {
return
}
port :=new(serialPort)
port.f = f
port.fd = h
port.ro = ro
port.wo = wo
return port, nil
}
func (p *serialPort) Close() error {
return p.f.Close()
}
func (p *serialPort) Write(buf []byte) (int, error) {
p.wl.Lock()
defer p.wl.Unlock()
if err := resetEvent(p.wo.HEvent); err != nil {
return 0, err
}
var n uint32
err := syscall.WriteFile(p.fd, buf,&n, p.wo)
if err != nil && err != syscall.ERROR_IO_PENDING {
return int(n), err
}
return getOverlappedResult(p.fd, p.wo)
}
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)
if err != nil && err != syscall.ERROR_IO_PENDING {
return int(done), err
}
return getOverlappedResult(p.fd, p.ro)
}
var (
nSetCommState,
nSetCommTimeouts,
nSetCommMask,
nSetupComm,
nGetOverlappedResult,
nCreateEvent,
nResetEvent uintptr
)
func init() {
k32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
panic("LoadLibrary " + err.Error())
}
defer syscall.FreeLibrary(k32)
nSetCommState = getProcAddr(k32, "SetCommState")
nSetCommTimeouts = getProcAddr(k32, "SetCommTimeouts")
nSetCommMask = getProcAddr(k32, "SetCommMask")
nSetupComm = getProcAddr(k32, "SetupComm")
nGetOverlappedResult = getProcAddr(k32, "GetOverlappedResult")
nCreateEvent = getProcAddr(k32, "CreateEventW")
nResetEvent = getProcAddr(k32, "ResetEvent")
}
func getProcAddr(lib syscall.Handle, name string) uintptr {
addr, err := syscall.GetProcAddress(lib, name)
if err != nil {
panic(name + " " + err.Error())
}
return addr
}
func setCommState(h syscall.Handle, c *Config) error {
var params structDCB
params.DCBlength = uint32(unsafe.Sizeof(params))
params.flags[0] = 0x01 // fBinary
params.flags[0] |= 0x10 // Assert DSR
params.BaudRate = uint32(c.Baud)
// Select byte size.
switch c.Size {
case Byte5:
params.ByteSize = 5
case Byte6:
params.ByteSize = 6
case Byte7:
params.ByteSize = 7
case Byte8:
params.ByteSize = 8
default:
panic(c.Size)
}
// Select parity mode.
switch c.Parity {
case ParityNone:
params.Parity = 0
case ParityEven:
params.Parity = 2
case ParityOdd:
params.Parity = 1
default:
panic(c.Parity)
}
// Selet stop bits.
switch c.StopBits {
case StopBits1:
params.StopBits = 0
case StopBits2:
params.StopBits = 2
default:
panic(c.StopBits)
}
r, _, err := syscall.Syscall(nSetCommState,2, uintptr(h), uintptr(unsafe.Pointer(¶ms)),0)
if r == 0 {
return err
}
return nil
}
func setCommTimeouts(h syscall.Handle) error {
var timeouts structTimeouts
const MAXDWORD = 1<<32- 1
timeouts.ReadIntervalTimeout = MAXDWORD
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD
timeouts.ReadTotalTimeoutConstant = MAXDWORD- 1
/* From http://msdn.microsoft.com/en-us/library/aa363190(v=VS.85).aspx
For blocking I/O see below:
Remarks:
If an application sets ReadIntervalTimeout and
ReadTotalTimeoutMultiplier to MAXDWORD and sets
ReadTotalTimeoutConstant to a value greater than zero and
less than MAXDWORD, one of the following occurs when the
ReadFile function is called:
If there are any bytes in the input buffer, ReadFile returns
immediately with the bytes in the buffer.
If there are no bytes in the input buffer, ReadFile waits
until a byte arrives and then returns immediately.
If no bytes arrive within the time specified by
ReadTotalTimeoutConstant, ReadFile times out.
*/
r, _, err := syscall.Syscall(nSetCommTimeouts,2, uintptr(h), uintptr(unsafe.Pointer(&timeouts)),0)
if r == 0 {
return err
}
return nil
}
func setupComm(h syscall.Handle, in, out int) error {
r, _, err := syscall.Syscall(nSetupComm,3, uintptr(h), uintptr(in), uintptr(out))
if r == 0 {
return err
}
return nil
}
func setCommMask(h syscall.Handle) error {
const EV_RXCHAR = 0x0001
r, _, err := syscall.Syscall(nSetCommMask,2, uintptr(h), EV_RXCHAR, 0)
if r == 0 {
return err
}
return nil
}
func resetEvent(h syscall.Handle) error {
r, _, err := syscall.Syscall(nResetEvent,1, uintptr(h), 0,0)
if r == 0 {
return err
}
return nil
}
func newOverlapped() (*syscall.Overlapped, error) {
var overlapped syscall.Overlapped
r, _, err := syscall.Syscall6(nCreateEvent,4, 0, 1, 0, 0,0, 0)
if r == 0 {
return nil, err
}
overlapped.HEvent = syscall.Handle(r)
return &overlapped, nil
}
func getOverlappedResult(h syscall.Handle, overlapped *syscall.Overlapped) (int, error) {
var n int
r, _, err := syscall.Syscall6(nGetOverlappedResult,4,
uintptr(h),
uintptr(unsafe.Pointer(overlapped)),
uintptr(unsafe.Pointer(&n)), 1, 0, 0)
if r == 0 {
return n, err
}
return n, nil
}
问题的解
为了能在脚本中使用,决定使之能对任意串口,执行单条AT命令。
atsender.go
package main
import (
"./goserial"
"log"
"io"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
comname :="COM51"
atcommand :="at\r\n"
baud :=115200
if len(os.Args) > 1 {
comname = os.Args[1]
}
if len(os.Args) > 2 {
atcommand = checkAtformat(os.Args[2])
baud = 115200
}
if len(os.Args) > 3 {
baud,_ = strconv.Atoi(os.Args[3])
}
fmt.Printf("Com: %s Baud: %d AT: %s ",comname,baud ,atcommand)
s,_ := openCom(comname ,baud)//"COM51",115200
_, err := s.Write([]byte(atcommand))
if err != nil {
log.Fatal(err)
}
receiveCom(s)
s.Close()
}
func openCom(name string,baud int)(io.ReadWriteCloser, error){
c :=&goserial.Config{Name: name, Baud: baud}
s, err := goserial.OpenPort(c)
if err != nil {
log.Fatal(err)
}
return s,nil
}
func checkAtformat(in string)(string){
if strings.Contains(in,"\r\n") {
return in
}else {
return in + "\r\n"
}
return ""
}
func receiveCom(s io.ReadWriteCloser){
buf := make([]byte,128)
for{
n, err := s.Read(buf)
if err != nil {
log.Fatal(err)
}
strResult := string(buf[:n])
fmt.Println(strResult)
if strings.Contains(strResult,"OK\r\n"){
break
}
}
}
import (
"./goserial"
"log"
"io"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
comname :="COM51"
atcommand :="at\r\n"
baud :=115200
if len(os.Args) > 1 {
comname = os.Args[1]
}
if len(os.Args) > 2 {
atcommand = checkAtformat(os.Args[2])
baud = 115200
}
if len(os.Args) > 3 {
baud,_ = strconv.Atoi(os.Args[3])
}
fmt.Printf("Com: %s Baud: %d AT: %s ",comname,baud ,atcommand)
s,_ := openCom(comname ,baud)//"COM51",115200
_, err := s.Write([]byte(atcommand))
if err != nil {
log.Fatal(err)
}
receiveCom(s)
s.Close()
}
func openCom(name string,baud int)(io.ReadWriteCloser, error){
c :=&goserial.Config{Name: name, Baud: baud}
s, err := goserial.OpenPort(c)
if err != nil {
log.Fatal(err)
}
return s,nil
}
func checkAtformat(in string)(string){
if strings.Contains(in,"\r\n") {
return in
}else {
return in + "\r\n"
}
return ""
}
func receiveCom(s io.ReadWriteCloser){
buf := make([]byte,128)
for{
n, err := s.Read(buf)
if err != nil {
log.Fatal(err)
}
strResult := string(buf[:n])
fmt.Println(strResult)
if strings.Contains(strResult,"OK\r\n"){
break
}
}
}
辅助工具
由于AT命令在执行时,有时会用时较长,须要有一个等待命令,也用golang实现一下吧。总之是练习而已。
sleep.go
// sleep.go
package main
import (
"fmt"
"os"
"strconv"
"time"
)
func main() {
if len(os.Args) > 1 {
count, _ := strconv.Atoi(os.Args[1])
// t0 := time.Now()
go promtString("*",count)
time.Sleep(time.Duration(count) * time.Second)
// t1 := time.Now()
// fmt.Printf("\nThe call took %v to run.\n", t1.Sub(t0))
fmt.Println()
} else {
fmt.Println("Sleep count Seconds.\nUsage: sleep [count]")
}
}
func promtString(str string, count int) {
for i := 0; i< count; i++ {
fmt.Print(str)
time.Sleep(time.Second)
}
}
package main
import (
"fmt"
"os"
"strconv"
"time"
)
func main() {
if len(os.Args) > 1 {
count, _ := strconv.Atoi(os.Args[1])
// t0 := time.Now()
go promtString("*",count)
time.Sleep(time.Duration(count) * time.Second)
// t1 := time.Now()
// fmt.Printf("\nThe call took %v to run.\n", t1.Sub(t0))
fmt.Println()
} else {
fmt.Println("Sleep count Seconds.\nUsage: sleep [count]")
}
}
func promtString(str string, count int) {
for i := 0; i< count; i++ {
fmt.Print(str)
time.Sleep(time.Second)
}
}
应用脚本
有了这两个命令行程序,就可以编写自动化脚本啦。
echo off
for %%i in (1,2,3,4)do call :Call_Case
:Call_Case
atsender COM51 atd10086;
sleep 10
atsender COM51 at+chup
sleep 5
goto :eof
for %%i in (1,2,3,4)do call :Call_Case
:Call_Case
atsender COM51 atd10086;
sleep 10
atsender COM51 at+chup
sleep 5
goto :eof
有疑问加站长微信联系(非本文作者)