123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- package netAtSDK
- import (
- "errors"
- "fmt"
- "github.com/gogf/gf/encoding/gbinary"
- "github.com/gogf/gf/net/gtcp"
- "github.com/gogf/gf/os/glog"
- "github.com/gogf/gf/text/gstr"
- "time"
- )
- const timeOut = 5 * time.Second
- type ATClient struct {
- conn *gtcp.Conn
- password string
- }
- func NetATClient(conn *gtcp.Conn, password string) *ATClient {
- return &ATClient{
- conn: conn,
- password: password,
- }
- }
- // Save 保存配置
- func (a *ATClient) Save() error {
- _, err := a.send("AT&W")
- return err
- }
- // Restart 模块重启
- // AT+CFUN=1,1
- func (a *ATClient) Restart() error {
- _, err := a.send("CFUN=1,1")
- return err
- }
- // GetIMEI 查询串号
- // AT+GSN
- func (a *ATClient) GetIMEI() (imei string, err error) {
- buf, err := a.send("GSN")
- if err != nil {
- return
- }
- imei = buf[0]
- return
- }
- // GetICCID 查询ICCID
- // AT+ICCID
- func (a *ATClient) GetICCID() (iccid string, err error) {
- buf, err := a.send("ICCID")
- if err != nil {
- return
- }
- iccid = buf[0]
- iccid = gstr.Replace(iccid, "+ICCID:", "")
- return
- }
- // GetGPS 查询基站信息
- // AT+GPS:查询基站信息, +GPS: Lac:0x581b,CellId:0x0b8aa201
- func (a *ATClient) GetGPS() (gps string, err error) {
- buf, err := a.send("GPS")
- if err != nil {
- return
- }
- gps = buf[0]
- gps = gstr.Replace(gps, "+GPS: ", "")
- return
- }
- // SetDTUMode 设备工作模式
- // AT+DTUMODE:配置工作模式
- /*
- 第一个参数 0 不启用该通道; 1 TCP/UDP 透传; 2 MQTT 透传; 3 塔石 DTU 云连接; 4 塔石 IOT 云连接; 5 HTTP 传输模式; 6 阿里云直连
- B 取值范围 1~4,代表 4 个不同的 SOCKET 通道,省略时仅配置通道 1 默认值:+DTUMODE:1,0,0,0 默认第一路为 TCP/UDP 透传,其他几路为默认关闭
- */
- func (a *ATClient) SetDTUMode(mode int, channel int) error {
- _, err := a.send(fmt.Sprintf("DTUMODE=%d,%d", mode, channel))
- if err != nil {
- return err
- }
- return nil
- }
- // GetDTUMode 查询工作模式
- // 返回1,0,0,0格式
- func (a *ATClient) GetDTUMode() (mode string, err error) {
- buf, err := a.send("DTUMODE?")
- if err != nil {
- return
- }
- mode = buf[0]
- mode = gstr.Replace(mode, "+DTUMODE= ", "")
- return
- }
- // SetServerAddr 设置连接服务器地址
- /*
- 格式:AT+DSCADDR=A,"B","C",D
- A 取值范围 1-4,代表 4 个不同的 SOCKET
- 通道
- B 为 TCP 或者 UDP
- C 为服务器地址,可填域名或 IP,长度最大 255
- D 为端口号,范围 1~65535
- */
- func (a *ATClient) SetServerAddr(channel int, cType string, Ip string, port int) error {
- _, err := a.send(fmt.Sprintf("DSCADDR=%d, \"%s\", \"%s\", %d", channel, cType, Ip, port))
- if err != nil {
- return err
- }
- return nil
- }
- // GetServerAddr 查询连接服务器 地址
- // +DSCADDR:1,"tcp","cloud.tastek.cn",10067
- // +DSCADDR:2,"tcp","cloud.tastek.cn",10067
- func (a *ATClient) GetServerAddr() (ret []string, err error) {
- buf, err := a.send("DSCADDR?")
- if err != nil {
- return
- }
- for _, v := range buf {
- newV := gstr.Replace(v, "+DSCADDR:", "")
- ret = append(ret, newV)
- }
- return
- }
- // SetUARTParam AT+UARTCFG:串口参数设置
- /*
- 格式:AT+UARTCFG=A,B,C,D
- A 串口波特率,支持的波特率为 115200、57600、38400、19200、14400、9600、4800、 2400、1200
- B 数据位,取值范围 0~1 0 7 位数据位 1 8 位数据位
- C 校验位,取值范围 0~2 0 无校验 NONE 1 奇校验 ODD 2 偶校验 EVEN
- D 停止位,取值范围 0~1 0 1 位停止位 1 2 位停止位
- 默认值:+UARTCFG:9600,1,0,0(9600,8,N,1)
- */
- func (a *ATClient) SetUARTParam(rate, dFlag, cFlag, sFlag int) error {
- _, err := a.send(fmt.Sprintf("UARTCFG=%d,%d,%d,%d", rate, dFlag, cFlag, sFlag))
- return err
- }
- // GetUARTParam 获取串口配置
- // 返回: 115200,1,0,0
- func (a *ATClient) GetUARTParam() (ret string, err error) {
- buf, err := a.send("UARTCFG?")
- if err != nil {
- return
- }
- ret = gstr.Replace(buf[0], "+UARTCFG: ", "")
- return
- }
- // SetDTUID AT+DTUID:注册包设置
- /*
- 格式:AT+DTUID=A,B,C,"D"(,E)
- A 注册包模式,取值范围 0-3 0 不启用注册包 1 仅连接时上传 2 和数据一起上传,在数据前 3 包括 1,2
- B 注册包内容,取值范围 0-2 0 自定义注册包 1 IMEI(15 位模块对应的唯一识别码) 2 ICCID(20 位 SIM 卡对应编码)
- C 数据输入格式,取值范围 0-1 0 ASCII 格式 1 HEX 格式
- D 数据内容,最大长度为 512Byte
- E 可选参数,取值范围 1-4,分别代表 4 个 socket 通道,省略时仅配置通道 1 默认值:+DTUID: 0,0,0,"tas001"
- */
- func (a *ATClient) SetDTUID(mode, idType, format int, content string, channel ...int) error {
- cmd := fmt.Sprintf("DTUID=%d,%d,%d,\"%s\"", mode, idType, format, content)
- if len(channel) > 0 {
- cmd = cmd + fmt.Sprintf(",%d", channel[0])
- }
- _, err := a.send(cmd)
- return err
- }
- // GetDTUID 查询注册包配置
- /*
- 返回:1,0,0,"dtuid1",1
- 1,0,0,"dtuid1",1
- */
- func (a *ATClient) GetDTUID() (ret []string, err error) {
- buf, err := a.send("DTUID?")
- if err != nil {
- return
- }
- for _, v := range buf {
- newV := gstr.Replace(v, "+DTUID: ", "")
- ret = append(ret, newV)
- }
- return
- }
- // SetKeepAlive AT+KEEPALIVE:心跳包设置
- /*
- 格式:AT+KEEPALIVE=A,B,"C"(,D)
- A 心跳时间间隔,取值范围 0-3600 0 不启用 1-3600 固定时间间隔,单位秒
- B 数据输入格式 0 ASCII 模式 1 HEX 模式
- C 数据内容,最大长度 256 ,固件 3.4.0 之后版本支持特殊含义字段,例如$(IMEI)、 $(ICCID)、$(TIME)、$(CSQ)等
- D 可选参数,范围 1-4,分别代表 4 个 socket 通道,省略时仅配置通道 1 默认值:+KEEPALIVE: 0,0,"ping"
- */
- func (a *ATClient) SetKeepAlive(dur, format int, content string, channel ...int) error {
- cmd := fmt.Sprintf("KEEPALIVE=%d,%d,\"%s\"", dur, format, content)
- if len(channel) > 0 {
- cmd = cmd + fmt.Sprintf(",%d", channel[0])
- }
- _, err := a.send(cmd)
- return err
- }
- // GetKeepAlive 查询心跳包配置
- // +KEEPALIVE: 120,0,"keepalive",1
- func (a *ATClient) GetKeepAlive() (ret []string, err error) {
- buf, err := a.send("KEEPALIVE?")
- if err != nil {
- return
- }
- for _, v := range buf {
- newV := gstr.Replace(v, "+KEEPALIVE: ", "")
- ret = append(ret, newV)
- }
- return
- }
- // GetAll 查询所有参数
- // AT+DTUALL:查询所有参数
- /*
- +DTUMODE:1,0,0,0 +TCPMODBUS:0,0,0,0 +UARTCFG:9600,1,0,0 +WORKMODE:0 +REVNUM:"10086",4,0 +CSTT:"","","" +RELINKTIME:3 +DSCTIME:300 +ACKTIME: 0 +PORTTIME: 0 +DTUFILTER:0 ------------SOCKET_1------------ +DSCADDR:1,"tcp","122.231.164.87",10158
- +KEEPALIVE:0,0,"ping",1 +DTUID:0,0,0,"tas001",1 +DTUCLOUD:2,"866262040274796","42ee4b0449154f959be44fc242337599",1 ------------SOCKET_2------------ +DSCADDR:2,"tcp","cloud.tastek.cn",10067 +KEEPALIVE:0,0,"ping",2 +DTUID:0,0,0,"tas002",2 +DTUCLOUD:0,"cloudID","cloudPWD",2 ------------SOCKET_3------------ +DSCADDR:3,"tcp","cloud.tastek.cn",10067 +KEEPALIVE:0,0,"ping",3 +DTUID:0,0,0,"tas003",3 +DTUCLOUD:0,"20060059","123456",3 ------------SOCKET_4------------ +DSCADDR:4,"tcp","cloud.tastek.cn",10067 +KEEPALIVE:0,0,"ping",4 +DTUID:0,0,0,"tas003",4 +DTUCLOUD:0,"20060059","123456",4
- */
- func (a *ATClient) GetAll() (result []string, err error) {
- result, err = a.send("DTUALL?")
- if err != nil {
- return
- }
- return
- }
- // SetPOLL AT+POLL:轮询使能
- /*
- 格式:AT+POLL=A,B,C
- A 自定义轮询使能,取值范围 0-1 0 关闭自定义轮询功能 1 开启自定义轮询功能
- B 轮询时间间隔,取值范围 1-3600,表示每条启用指令间的时间间隔,单位秒
- C 轮询数据输入格式,取值范围 0-1 0 ASCII 格式,设置为 0 表示之后输入的轮询指令均为以 ASCII 形式轮询, 即输入什么字串就轮询什么字串 1 HEX 格式,设置为 1 表示之后输入的轮询指令需要满足 HEX 格式,轮 询时会自动转成 16 进制对应的 ASCII 字串 默认值:+POLL:0,10,1
- */
- func (a *ATClient) SetPOLL(sw, dur, format int) error {
- _, err := a.send(fmt.Sprintf("POLL=%d,%d,%d", sw, dur, format))
- return err
- }
- // GetPOLL 查询轮询使能
- // +POLL: 0,10,1
- func (a *ATClient) GetPOLL() (result string, err error) {
- buf, err := a.send("POLL?")
- result = gstr.Replace(buf[0], "+POLL: ", "")
- return
- }
- // SetPOLLStr 设置轮询字符串
- // AT+POLLSTR:轮询字串设置
- /*
- 格式:AT+POLLSTR=A,B,C,"D"
- A 轮询字串号,取值范围 1-10
- B 字串轮询使能,取值范围 0-1 0 禁用该条轮询 1 启用该条轮询
- C 字串 CRC 使能,取值范围 0-1 0 无操作 1 对所输入字串进行 Modbus CRC 校验并在轮询时添加在字串末尾
- D 轮询字串数据,如果在 AT+POLL 指令中设置了 HEX 标志位为 1,那么必须以 16 进制输入,
- 轮询时自动转换成 BIN 格式(例:所输入字串为"313233414243", 实际轮询的字串为"123ABC")
- 具体字符对应关系可以对照以下网址 http://ascii.911cha.com/
- 默认值:+POLLSTR:1,0,0,"313233
- */
- func (a *ATClient) SetPOLLStr(index, sw, crc int, str string) error {
- _, err := a.send(fmt.Sprintf("POLLSTR=%d,%d,%d,%s", index, sw, crc, str))
- return err
- }
- // GetGPSInfo AT+GPSINFO:查询经纬度(精度 100m),
- // 查询经纬度信息,仅注册上基站后生效,属于原始 GPS 坐标
- // +GPSINFO: 030.1842195,120.2400433
- func (a *ATClient) GetGPSInfo() (gps string, err error) {
- buf, err := a.send("GPSINFO")
- if err != nil {
- return
- }
- gps = gstr.Replace(buf[0], "+GPSINFO: ", "")
- return
- }
- func (a *ATClient) send(cmd string) (ret []string, err error) {
- glog.Debugf("发送AT+%s", cmd)
- buf := a.prepareCommand(cmd)
- if _, err = a.conn.Write(buf); err != nil {
- return
- }
- timer := time.NewTimer(5 * time.Second)
- for {
- select {
- case <-timer.C:
- err = errors.New("读取AT响应超时")
- return
- default:
- buf, err = a.conn.RecvLine()
- if err != nil {
- return
- }
- str := string(buf)
- glog.Debugf("收到:%s, %2X", str, buf)
- if gstr.Contains(str, "OK") {
- return
- }
- ret = append(ret, str)
- }
- }
- }
- func (a *ATClient) prepareCommand(cmd string) []byte {
- cmdStr := fmt.Sprintf("@DTU:%s:%s", a.password, cmd)
- return gbinary.EncodeString(cmdStr)
- }
|