wj008 / gos7

PLC 西门子
2 stars 2 forks source link

这个怎么用啊 有说明不 #1

Open whaosoft opened 1 year ago

wj008 commented 1 year ago

嗯,这个只是读取库,读取转换需要解析地址:


// catchData 抓取数据---
func (d *Device) catchData(client *gos7.Client) (err error) {
    if d.tagCache == nil || d.Start == 0 {
        return nil
    }
    dataMap := make(H)
    for key, group := range d.tagCache.Groups {
        //log.Println("抓取DB:", key, group.Start, group.Length)
        var reader *gos7.DataReader = nil
        if len(key) >= 2 {
            area := key[0:2]
            if area == "DB" {
                dbNo, _ := strconv.Atoi(key[2:])
                reader, err = client.AGReadDB(dbNo, group.Start, group.Length)
            } else if area == "QB" || area == "QW" || area == "QD" {
                reader, err = client.AGReadQ(group.Start, group.Length)
            } else if area == "IB" || area == "IW" || area == "ID" {
                reader, err = client.AGReadI(group.Start, group.Length)
            } else if area == "VB" || area == "VW" || area == "VD" {
                reader, err = client.AGReadV(group.Start, group.Length)
            } else if area == "MB" || area == "MW" || area == "MD" {
                reader, err = client.AGReadM(group.Start, group.Length)
            }
        } else {
            if key == "Q" {
                reader, err = client.AGReadQ(group.Start, group.Length)
            } else if key == "I" {
                reader, err = client.AGReadI(group.Start, group.Length)
            } else if key == "V" {
                reader, err = client.AGReadV(group.Start, group.Length)
            } else if key == "M" {
                reader, err = client.AGReadM(group.Start, group.Length)
            }
        }
        if err != nil {
            log.Println("抓取DB错误:", key, group.Start, group.End)
            for _, elem := range group.ElemMap {
                log.Println("集合DB错误:", elem.Addr)
            }
            return
        }
        if reader == nil {
            continue
        }
        //获取元素数据
        for _, elem := range group.ElemMap {
            offset := elem.Index1 - group.Start
            if offset < 0 {
                continue
            }
            value, readErr := reader.Read(elem.Typ, offset, elem.Index2)
            if readErr != nil {
                log.Println(readErr.Error())
                continue
            }
            dataMap[elem.Code] = value
        }
    }
    d.putData(dataMap)
    return
}

地址解析的大概代码

type S7Elem struct {
    Addr   string `json:"a"`
    Typ    string `json:"t"`
    Code   string
    Key1   string
    Key2   string
    Index1 int
    Index2 int
}

type TagGroup struct {
    Start   int
    End     int
    Length  int
    ElemMap []*S7Elem
}

type TagCache struct {
    Groups map[string]*TagGroup
    Tags   []string
    Sets   map[string]string
}

func NewTagCache() *TagCache {
    return &TagCache{
        Groups: make(map[string]*TagGroup),
        Tags:   make([]string, 0),
        Sets:   make(map[string]string),
    }
}

func ParseTag(code string, tag *S7Elem) (*S7Elem, error) {
    tag.Code = code
    addr := strings.ToUpper(tag.Addr)
    addr = strings.Replace(addr, " ", "", -1)
    typ := strings.ToLower(tag.Typ)
    typ = strings.Replace(typ, " ", "", -1)
    if addr == "" || typ == "" {
        return nil, errors.New("PLC:数据为空")
    }
    tag.Addr = addr
    tag.Typ = typ
    switch area := addr[0:2]; area {
    case "DB": //input byte
        dbArray := strings.Split(addr, ".")
        if len(dbArray) < 2 {
            return nil, errors.New("Db Area read variable should not be empty")
        }
        key1 := dbArray[0] //DB1
        key2 := dbArray[1] //000
        index2 := 0        //点位数
        if len(dbArray) == 3 {
            index2, _ = strconv.Atoi(dbArray[2]) //位数
        }
        index1 := 0
        match, _ := regexp.MatchString("^\\d+$", key2)
        if len(key2) > 3 {
            index1, _ = strconv.Atoi(key2[3:])
        } else if match {
            index1, _ = strconv.Atoi(key2)
        }
        tag.Key1 = key1
        tag.Key2 = key2
        tag.Index1 = index1
        tag.Index2 = index2
        return tag, nil
    case "VB", "VW", "VD", "MB", "MW", "MD", "IB", "IW", "ID", "QB", "QW", "QD":
        firstKey := string(addr[2:])
        dbArray := strings.Split(firstKey, ".")
        index2 := 0
        index1 := 0
        if len(dbArray) == 2 {
            index1, _ = strconv.Atoi(dbArray[0])
            index2, _ = strconv.Atoi(dbArray[1])
        } else {
            index1, _ = strconv.Atoi(firstKey)
        }
        key1 := area
        key2 := addr
        tag.Key1 = key1
        tag.Key2 = key2
        tag.Index1 = index1
        tag.Index2 = index2
        return tag, nil
    default:
        switch otherArea := addr[0:1]; otherArea {
        case "I", "M", "Q", "V":
            firstKey := string(addr[1:])
            dbArray := strings.Split(firstKey, ".")
            index2 := 0
            index1 := 0
            if len(dbArray) == 2 {
                index1, _ = strconv.Atoi(dbArray[0])
                index2, _ = strconv.Atoi(dbArray[1])
            } else {
                index1, _ = strconv.Atoi(firstKey)
            }
            key1 := otherArea
            key2 := addr
            tag.Key1 = key1
            tag.Key2 = key2
            tag.Index1 = index1
            tag.Index2 = index2
            return tag, nil
        default:
            return nil, errors.New("PLC:数据为空")
        }
    }
}

func (tc *TagCache) AddTag(code string, tag *S7Elem) {
    tag, _ = ParseTag(code, tag)
    if tag == nil {
        return
    }
    if _, ok := tc.Sets[tag.Addr]; ok {
        return
    }
    tc.Sets[tag.Addr] = code
    tc.Tags = append(tc.Tags, tag.Addr)
    key1 := tag.Key1
    if _, ok := tc.Groups[key1]; !ok {
        elemMap := make([]*S7Elem, 0)
        tc.Groups[key1] = &TagGroup{
            Start:   -1,
            End:     0,
            Length:  0,
            ElemMap: elemMap,
        }
    }
    typLen := 1
    switch tag.Typ {
    case "bool", "byte":
        typLen = 1
        break
    case "word", "int":
        typLen = 2
        break
    case "dword", "dint", "real":
        typLen = 4
        break
    }
    if tc.Groups[key1].Start < 0 || tag.Index1 < tc.Groups[key1].Start {
        tc.Groups[key1].Start = tag.Index1
    }
    thisEnd := tag.Index1 + typLen
    if thisEnd > tc.Groups[key1].End {
        tc.Groups[key1].End = thisEnd
    }
    tc.Groups[key1].Length = tc.Groups[key1].End - tc.Groups[key1].Start
    tc.Groups[key1].ElemMap = append(tc.Groups[key1].ElemMap, tag)
}

链接的大概代码:

// loop 循环工作---
func (d *Device) loop() error {
    defer func() { // 必须要先声明defer,否则不能捕获到panic异常
        log.Println(d.Id, "PLC:工作线程已经退出")
        if err := recover(); err != nil {
            log.Println(err) // 这里的err其实就是panic传入的内容
        }
    }()
    //开始链接
    client, err := gos7.NewClient(d.DeviceAddr, d.DeviceRack, d.DeviceSlot)
    if err != nil {
        log.Println(d.Id, "PLC:设备链接失败,终止任务....", "host:", d.DeviceAddr, "rack:", d.DeviceRack, "slot:", d.DeviceSlot, "error:", err.Error())
        return err
    }
    defer func() {
        client.Close()
        if d.IsRun {
            d.putOffline()
            d.IsRun = false
        }
        log.Println(d.Id, "PLC:设备断开....")
    }()
    //log.Println(d.Id, "PLC:链接设备成功....")
    for {
        log.Println("开始抓取数据:", d.DeviceNo)
        err = d.catchData(client)
        if err != nil {
            log.Println(err.Error())
            return err
        }
        //如果开机
        if d.PowerStatus {
            if d.Sleep < 1 {
                d.Sleep = 1
            }
            //log.Println("开机轮值(秒):", d.Sleep)
            time.Sleep(time.Duration(d.Sleep) * time.Second)
        } else {
            if d.DieSleep < 5 {
                d.DieSleep = 5
            }
            //log.Println("关机轮值(秒):", d.DieSleep)
            time.Sleep(time.Duration(d.DieSleep) * time.Second)
        }
    }
}
wj008 commented 1 year ago

最近有点忙,有什么疑问可以留言,等稍微有空我整理写一个 demo