Package for dealing with AT devices / data streams.
PR's welcome.
stringer from https://github.com/golang/tools/blob/master/cmd/stringer/stringer.go is used.
These dependencies are added to tools.go and included in go.mod - to install correct versions you can use go mod vendor, and then use go run ./vendor/golang.org/x/tools/cmd/stringer.
Invoking go generate requires stringer on the path, however.
AT is a struct for wrapping AT devices to provide a nice, simple API to send AT commands.
ctx:=context.Background()
varrawDevice io.ReadWriter=openATDevice()
// create AT - note that specifying the DeviceProfile is optionalatDevice:=at.NewAT(rawDevice, at.WithProfile(at.DefaultProfile{}))
// we want to set a timeout for the AT command we're about to send.commandCtx, cancelFn:=context.WithTimeout(ctx, time.Second*10)
defercancelFn()
// Send the command "AT". Implementation of Send adds EOL automatically.response, err:=atDevice.Send(commandCtx, "AT")
iferr!=nil {
// there was an error sending the command.// Could be io error, context timeout, or some AT errorswitcherr {
caseat.ErrUnexpectedPrompt:
// handlecasecontext.DeadlineExceeded:
// handledefault:
panic(err)
}
}
// Print the responseprintln(response)
// NOTE: because we sent the "AT" command, response here *should* be an empty string.// This is because command echoes, "OK" and error strings are stripped from the response.// Error strings are instead put in the err return value.// OK is inferred from the lack of errors.// And Echoes are removed so as to not get mixed up with "real" command outputs// so, again, response is empty for AT commands that don't output anything (other than potential command echo and OK)ScanWriter wraps an AT device to infer the device state.
ScanWriter can tell you if the received "token" is an AT command echo, or and AT error, or an interactive prompt.
ctx:=context.Background()
varrawDevice io.ReadWriter=openATDevice()
// create a scanwriter over an io.ReadWriter// after this point you should no longer use the rawDevice anywhere elsescanwriter:=at.NewScanWriter(rawDevice, at.DefaultProfile{})
// initial state should be "ready"state:=scanwriter.State()
ifstate!=at.ATReady {
panic("unexpected state")
}
// write a command to the AT deviceerr:=scanwriter.Write([]byte("AT\r\n"))
iferr!=nil {
panic("error writing to scanwriter")
}
// scan in a loopforscanwriter.Scan(ctx) {
state:=scanwriter.State()
switchstate {
// We expect the first output after sending out command to be an Echocaseat.ATEcho:
continuecaseat.ATData:
// we got data - this is unexpected for the AT command// AT normally only returns an echo (ATEcho) and an OK (ATReady)// get the datadata:=scanwriter.Bytes()
println(data)
continuecaseat.ATError:
// ATError means the command failed and returned an error// we can get the errorerr=scanwriter.Err()
// as well as any data returned before the error occurreddata:=scanwriter.Bytes()
fmt.Printf("error in AT command: %v\nData: %s\n", err, data)
breakcaseat.ATNotice:
// notice is very unexpected here - normally only sent on the Notification port on my device.// An ATNotice is a notification pushed from the network, ie. ^BOOT, RING, etc.// ATNotice and ATData classification might get be mixed up.// we can inspect the data receiveddata:=scanwriter.Byte()
println(data)
continuecaseat.ATReady:
// we got an "OK" - command finished successfullyprintln("Command completed successfully!")
break
}
}
err=scanwriter.Err()
iferr!=nil {
panic("error scanning")
}