robinson / gos7

Implementation of Siemens S7 protocol in golang
BSD 3-Clause "New" or "Revised" License
315 stars 124 forks source link

AGreadMulti with start value > 0 results in "CPU : Address out of range" #5

Closed Barpfotenbaer closed 3 years ago

Barpfotenbaer commented 5 years ago

(First: Great, ingenious tool, thank you very much!!!!)

I had some problem with AGreadMulti if start value isn't zero!

E.g. DB301[20] exists client.AGReadDB(301, 0, 20, buffer1) is working well client.AGReadDB(301, 2, 18, buffer2) is working well client.AGReadDB(301, 10, 10, buffer3) is working well

Also AGReadMuli is working well with

        buffer4 := make([]byte, 20)
        …
        gos7.S7DataItem{
            Area:     0x84,
            WordLen:  0x02,
            DBNumber: 301,
            Start:    0,
            Amount:   20,
            Data:     buffer4,
            Error:    error4,
        },

However

        buffer5 := make([]byte, 19)
        …
        gos7.S7DataItem{
            Area:     0x84,
            WordLen:  0x02,
            DBNumber: 301,
            Start:    1,
            Amount:   19,
            Data:     buffer5,
            Error:    error5,
        },

results in Error "CPU : Address out of range"

Is that a bug or a feature?

robinson commented 5 years ago

The error message said that is Address out of range, probably your address not in this range on this memory (start 1 amount 19).

Barpfotenbaer commented 5 years ago

The error message said that is Address out of range, probably your address not in this range on this memory (start 1 amount 19).

A few days ago, my first Example does work with start 0 and amount 20 and does not work with start 1 and amount 19, relative to DB 301. Address was definitely not out of range. However I solved my problem, using the Snap7-C-Code with CGO: Following example is working:

package main

// #cgo CFLAGS: -O2 -march=native
// #cgo LDFLAGS: -lsnap7
// #include <stdio.h>
// #include <stdlib.h>
// #include <ctype.h>
// #include "snap7.h"
/*
#ifdef OS_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif

byte myDBbuffer[210];

byte *MultiRead(S7Object Client, int myDBNumber, int myStart, int myAmount)
{
     int res;

     TS7DataItem Items[1];

     Items[0].Area     =S7AreaDB;
     Items[0].WordLen  =S7WLByte;
     Items[0].DBNumber =myDBNumber;
     Items[0].Start    =myStart;
     Items[0].Amount   =myAmount;
     Items[0].pdata    =&myDBbuffer;

     res=Cli_ReadMultiVars(Client, &Items[0], 1);
     if (res==0)
     {
        return myDBbuffer;
     };
}
*/
import (
    "C"
)

import (
    "fmt"
    "unsafe"
)

var (
    Client C.S7Object
)

func main() {
    MyClient := C.Cli_Create()
    C.Cli_ConnectTo(MyClient, C.CString("192.168.60.121"), 0, 2)

    fmt.Println(C.GoBytes(unsafe.Pointer(C.MultiRead(MyClient, 412, 0, 210)), 210))
    fmt.Println(C.GoBytes(unsafe.Pointer(C.MultiRead(MyClient, 412, 1, 210)), 210))
}

It successfully leads to the following result:

[0 3 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 134 0 0 4 136 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 28 0 0 0 20 0 0 0 30 0 0 0 10 0 0 0 2 0 0 14 16 0 0 0 20 0 0 0 100 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 18 0 0 8 152 0 0]
[3 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 134 0 0 4 136 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 28 0 0 0 20 0 0 0 30 0 0 0 10 0 0 0 2 0 0 14 16 0 0 0 20 0 0 0 100 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 18 0 0 8 152 0 0 0]

The same Code, written with go and gos7 …

package main

import (
    "errors"
    "fmt"
    "time"

    "github.com/robinson/gos7"
)

const (
    tcpDevice = "192.168.60.121"
    rack      = 0
    slot      = 2
)

func multiRead(client gos7.Client, myDBNumber int, myStart int, myAmount int) (error, []byte) {
    myDBbuffer := make([]byte, 210)
    var myError string
    mYtem := []gos7.S7DataItem{
        gos7.S7DataItem{
            Area:     0x84,
            WordLen:  0x02,
            DBNumber: myDBNumber,
            Start:    myStart,
            Amount:   myAmount,
            Data:     myDBbuffer,
            Error:    myError,
        },
    }
    client.AGReadMulti(mYtem, 1)
    return errors.New(myError), myDBbuffer
}

func main() {
    // TCPClient
    handler := gos7.NewTCPClientHandler(tcpDevice, rack, slot)
    handler.Timeout = 20 * time.Second
    handler.IdleTimeout = 20 * time.Second

    handler.Connect()
    defer handler.Close()
    client := gos7.NewClient(handler)

    fmt.Println(multiRead(client, 412, 0, 210))
    fmt.Println(multiRead(client, 412, 1, 210))
}

… incorrectly results in:

[0 3 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 134 0 0 4 136 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 2 28 0 0 0 20 0 0 0 30 0 0 0 10 0 0 0 2 0 0 14 16 0 0 0 20 0 0 0 100 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 18 0 0 8 152 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]