package mdbs import ( "eps/models/statusMgr" "eps/tcp/tc" "eps/tcp/tcpserver" "fmt" "github.com/astaxie/beego" "net" "strings" "time" "wb/lg" "wb/modbus" "wb/st" "wb/ut" ) type MConn struct { tc.TConn ModeInfo modbus.ModelInfo } type model interface { GetStatus(mConn *MConn) (string, map[string]interface{}) SendCmd(mConn *MConn, cmd string) } func NewMConn(conn net.Conn) *MConn { o := MConn{} o.Conn = conn o.IsConnect = true o.Typo = "MDBS" o.ReadBuf = make([]byte, 4096) return &o } func (this *MConn) Init(termId string) bool { this.TConn.Init(termId) for startId, modelInfo := range modbus.ModelInfoMap { if strings.HasPrefix(termId, startId) { this.LogInfo("MConn.Init modelInfo as: ", modelInfo.Name) this.ModeInfo = modelInfo this.StatusMgr = statusMgr.GetMgrBySid(this.TermId) this.StatusMap = this.StatusMgr.GetDefaultStatusMap(this.TermId) return true } } this.LogError("MConn.Init modelInfo error: no model match id:", termId) return false } func (this *MConn) Read() ([]byte, error) { READ: i, err := this.Conn.Read(this.ReadBuf) if err != nil { this.LogError("MDBS Read error:", err.Error()) this.IsConnect = false return []byte{}, err } else { this.LogRecv(this.ReadBuf[:i]) if i < 5 { goto READ } this.LogDebug("[P]R: ", this.ParseRecv(this.ReadBuf[:i])) } return this.ReadBuf[:i], nil } func (this *MConn) ParseRecv(bs []byte) string { if len(bs) < 5 { this.LogError("parse ERROR:", ut.BytesToHexStr(bs)) return "" } funcCode := bs[modbus.FuncCode] retLen := int8(bs[modbus.RetLen]) body := bs[modbus.RetBobyStart : len(bs)-2] return fmt.Sprint("FUNC=>", ut.ByteToHex(funcCode), " LEN=>", retLen, " BODY=>", ut.BytesToHexStr(body)) } const ( StartCmd = "start" StopCmd = "stop" ) func (this *MConn) SendCmd(key string) { if cmd, ok := this.ModeInfo.CmdMap[key]; ok { this.WriteReq(cmd.Bytes) } else { this.LogError("MConn.SendCmd error no such cmd:", key) } } func (this *MConn) WriteReq(req []byte) ([]byte, error) { req = modbus.AppendCrc(req) _, err := this.Write(req) if err != nil { this.LogError("WriteReq send error:", err.Error()) this.IsConnect = false // panic("network broken") return []byte{}, err } buf, err := this.Read() if err != nil { return []byte{}, err } return buf, nil } func (this *MConn) GetStatus() (string, map[string]interface{}) { if this.ModeInfo.Querys == nil { this.LogError("MConn.SendCmd error: model not init.") return st.Failed, nil } for _, query := range this.ModeInfo.Querys { this.GetRegisters(query, this.StatusMap, query.RegStart, query.RegLen, query.Address) } return st.Success, ut.Maps.Copy(this.StatusMap) } // 只适合连续的寄存器,并且结果位数相同 func (mConn *MConn) GetRegisters(query modbus.Query, mapValue map[string]interface{}, regStart, regLen, address int) { mConn.LogDebug("GetRegisters regStart:", regStart, " regLen:", regLen) req := modbus.BuildReadRequest(address, query.Code, regStart, regLen) //fmt.Println(ut.BytesToHexStr(req)) _, err := mConn.Write(req) if err != nil { mConn.LogError("GetRegisters send error:", err.Error()) mConn.IsConnect = false return } resp, err := mConn.Read() if err != nil { return } if len(resp) < 5 { return } modbus.DoRecvMdbsUart(mConn.ModeInfo, mapValue, resp, mConn.Logger) } const idLen = 6 func ReadTermId(conn net.Conn) string { buf := make([]byte, 1024) mLen, err := conn.Read(buf) if err != nil { println("Error register:", err.Error()) return "" } if mLen >= idLen { mLen = idLen } dst := make([]byte, idLen*2) for i := 0; i < idLen*2; i++ { dst[i] = '0' } d := (idLen - mLen) * 2 for _, v := range buf[:mLen] { dst[d] = ut.Hextable[v>>4] dst[d+1] = ut.Hextable[v&0x0f] d = d + 2 } return string(dst) } func EchoFunc(conn net.Conn) { lg.Info("MDBS CONNECT FROM: ", conn.RemoteAddr()) defer conn.Close() id := ReadTermId(conn) if id == "" { return } mConn := NewMConn(conn) if !mConn.Init(id) { return } tc.AddMConn(mConn) for mConn.IsConnect { time.Sleep(queryUartDelay * time.Second) mConn.LogInfo("queryUartDelay") status, vMap := mConn.GetStatus() if status == st.Success { mConn.StatusMgr.AddStatus(vMap) } } } func ServerRun() { port := beego.AppConfig.String("shport") server.Run(port, EchoFunc) } var queryUartDelay time.Duration func init() { samp := beego.AppConfig.DefaultInt("samplingPeriods", 10) queryUartDelay = time.Duration(samp) lg.Info("mbds samplingPeriods:", queryUartDelay) }