706 lines
22 KiB
Go
706 lines
22 KiB
Go
// wrap7 project wrap7.go
|
|
package wrap7
|
|
|
|
/*
|
|
#cgo CFLAGS: -O2 -march=native
|
|
#cgo LDFLAGS: -lm -lsnap7
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <snap7b.h>
|
|
|
|
|
|
#ifdef OS_WINDOWS
|
|
# define WIN32_LEAN_AND_MEAN
|
|
# include <windows.h>
|
|
#endif
|
|
|
|
#define MAXPDULENGTH 960
|
|
|
|
// https://support.industry.siemens.com...view/109747136 Seite 6813
|
|
// S7-300 240 Byte
|
|
// S7-400 480 Byte
|
|
// S7-1200 240 Byte
|
|
// S7-1500 960 Byte
|
|
|
|
int MultiRead(S7Object Client, byte (*buffer)[MAXPDULENGTH], TS7DataItem *psivar, int ItemsCount)
|
|
{
|
|
int i;
|
|
TS7DataItem Items[ItemsCount];
|
|
|
|
for( i = 0; i< ItemsCount; i++ ) {
|
|
//printf("Item Nr. %d\n",i);
|
|
Items[i].Area = psivar[i].Area;
|
|
Items[i].WordLen = psivar[i].WordLen;
|
|
Items[i].DBNumber = psivar[i].DBNumber;
|
|
Items[i].Start = psivar[i].Start;
|
|
Items[i].Amount = psivar[i].Amount;
|
|
Items[i].pdata = &buffer[i];
|
|
}
|
|
|
|
return Cli_ReadMultiVars(Client, &Items[0], ItemsCount);
|
|
}
|
|
|
|
int MultiWrite(S7Object Client, byte (*buffer)[MAXPDULENGTH], TS7DataItem *psivar, int ItemsCount)
|
|
{
|
|
int i;
|
|
TS7DataItem Items[ItemsCount];
|
|
|
|
for( i = 0; i< ItemsCount; i++ ) {
|
|
//printf("Item Nr. %d\n",i);
|
|
Items[i].Area = psivar[i].Area;
|
|
Items[i].WordLen = psivar[i].WordLen;
|
|
Items[i].DBNumber = psivar[i].DBNumber;
|
|
Items[i].Start = psivar[i].Start;
|
|
Items[i].Amount = psivar[i].Amount;
|
|
Items[i].pdata = &buffer[i];
|
|
}
|
|
|
|
return Cli_WriteMultiVars(Client, &Items[0], ItemsCount);
|
|
}
|
|
*/
|
|
import (
|
|
"C"
|
|
)
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"unsafe"
|
|
)
|
|
|
|
type ( // Type-Alias ist ansich nur Kosmetik
|
|
S7Object = C.S7Object
|
|
)
|
|
|
|
type ConditionType string
|
|
|
|
const (
|
|
CONDITION_RUNNING ConditionType = "running"
|
|
CONDITION_STOPPED ConditionType = "stopped"
|
|
CONDITION_UNKNOWN ConditionType = "unknown"
|
|
)
|
|
|
|
var ( // Damit im Go-Code nicht das C-Package importiert werden muß
|
|
S7AreaDB = (int)(C.S7AreaDB)
|
|
S7AreaMK = (int)(C.S7AreaMK)
|
|
S7AreaPE = (int)(C.S7AreaPE)
|
|
S7AreaPA = (int)(C.S7AreaPA)
|
|
S7AreaTM = (int)(C.S7AreaTM)
|
|
S7AreaCT = (int)(C.S7AreaCT)
|
|
|
|
S7WLBit = (int)(C.S7WLBit)
|
|
S7WLByte = (int)(C.S7WLByte)
|
|
S7WLWord = (int)(C.S7WLWord)
|
|
S7WLDWord = (int)(C.S7WLDWord)
|
|
S7WLReal = (int)(C.S7WLReal)
|
|
S7WLCounter = (int)(C.S7WLCounter)
|
|
S7WLTimer = (int)(C.S7WLTimer)
|
|
)
|
|
|
|
var EventCallBackLength = (int)(C.EventCallBackLength)
|
|
|
|
var (
|
|
SrvAreaPE = (int)(C.srvAreaPE)
|
|
SrvAreaPA = (int)(C.srvAreaPA)
|
|
SrvAreaMK = (int)(C.srvAreaMK)
|
|
SrvAreaCT = (int)(C.srvAreaCT)
|
|
SrvAreaTM = (int)(C.srvAreaTM)
|
|
SrvAreaDB = (int)(C.srvAreaDB)
|
|
)
|
|
|
|
const (
|
|
BlockTypeOB = 0x38
|
|
BlockTypeDB = 0x41
|
|
BlockTypeSDB = 0x42
|
|
BlockTypeFC = 0x43
|
|
BlockTypeSFC = 0x44
|
|
BlockTypeFB = 0x45
|
|
BlockTypeSFB = 0x46
|
|
)
|
|
|
|
// Diese Konstante gibt es doppelt. Sie muß auch im C-Code angepaßt werden!
|
|
const MAXPDULENGTH int = 960
|
|
|
|
const MULTIREADWRITE_BUFFERS = 10 // Wievele Buffers und Items MultiRead und MultiWrite anlegen soll.
|
|
|
|
//const DEVICE_IP = "192.168.0.10"
|
|
|
|
// https://support.industry.siemens.com...view/109747136 Seite 6813
|
|
// S7-300 240 Byte
|
|
// S7-400 480 Byte
|
|
// S7-1200 240 Byte
|
|
// S7-1500 960 Byte
|
|
|
|
type MultiReadWriteItem struct {
|
|
Area, WordLen, DBNumber, Start, Amount int
|
|
}
|
|
|
|
type TS7OrderCode struct {
|
|
Code string
|
|
V1, V2, V3 int
|
|
}
|
|
|
|
type TSCpuInfo struct {
|
|
ModuleTypeName, SerialNumber, ASName, Copyright, ModuleName string
|
|
}
|
|
|
|
type TS7CpInfo struct {
|
|
MaxPduLength, MaxConnections, MaxMpiRate, MaxBusRate int // MaxPduLengt zu MaxPduLength korrigiert
|
|
}
|
|
|
|
type TS7BlocksList struct {
|
|
OBCount, FBCount, FCCount, SFBCount, SFCCount, DBCount, SDBCount int
|
|
}
|
|
|
|
type TS7BlockInfo struct {
|
|
BlkType int // Block Type (OB, DB)
|
|
BlkNumber int // Block number
|
|
BlkLang int // Block Language
|
|
BlkFlags int // Block flags
|
|
MC7Size int // The real size in bytes
|
|
LoadSize int // Load memory size
|
|
LocalData int // Local data
|
|
SBBLength int // SBB Length
|
|
CheckSum int // Checksum
|
|
Version int // Block version
|
|
// Chars info
|
|
CodeDate string // Code date
|
|
IntfDate string // Interface date
|
|
Author string // Author
|
|
Family string // Family
|
|
Header string // Header
|
|
}
|
|
|
|
func GetOrderCode(client C.S7Object) (int, TS7OrderCode) {
|
|
var info C.TS7OrderCode
|
|
|
|
res := C.Cli_GetOrderCode(client, (*C.TS7OrderCode)(unsafe.Pointer(&info)))
|
|
|
|
return (int)(res), TS7OrderCode{
|
|
Code: C.GoString((*C.char)(unsafe.Pointer(&info.Code[0]))),
|
|
V1: (int)(info.V1),
|
|
V2: (int)(info.V2),
|
|
V3: (int)(info.V3)} /*, func() string {
|
|
return fmt.Sprintf("Order Code: %s\n, Version: %d.%d.%d\n", C.GoString((*C.char)(unsafe.Pointer(&info.Code[0]))), (int)(info.V1), (int)(info.V2), (int)(info.V3))
|
|
}()*/
|
|
}
|
|
|
|
func GetCpuInfo(client C.S7Object) (int, TSCpuInfo) {
|
|
var info C.TS7CpuInfo
|
|
|
|
res := C.Cli_GetCpuInfo(client, (*C.TS7CpuInfo)(unsafe.Pointer(&info)))
|
|
|
|
return (int)(res), TSCpuInfo{
|
|
ModuleTypeName: C.GoString((*C.char)(unsafe.Pointer(&info.ModuleTypeName[0]))),
|
|
SerialNumber: C.GoString((*C.char)(unsafe.Pointer(&info.SerialNumber[0]))),
|
|
ASName: C.GoString((*C.char)(unsafe.Pointer(&info.ASName[0]))),
|
|
Copyright: C.GoString((*C.char)(unsafe.Pointer(&info.Copyright[0]))),
|
|
ModuleName: C.GoString((*C.char)(unsafe.Pointer(&info.ModuleName[0])))}
|
|
}
|
|
|
|
func GetCpInfo(client C.S7Object) (int, TS7CpInfo) {
|
|
var info C.TS7CpInfo
|
|
|
|
res := C.Cli_GetCpInfo(client, (*C.TS7CpInfo)(unsafe.Pointer(&info)))
|
|
|
|
return (int)(res), TS7CpInfo{
|
|
MaxPduLength: (int)(info.MaxPduLengt),
|
|
MaxConnections: (int)(info.MaxConnections),
|
|
MaxMpiRate: (int)(info.MaxMpiRate),
|
|
MaxBusRate: (int)(info.MaxBusRate)}
|
|
}
|
|
|
|
func ListBlocks(client C.S7Object) (int, TS7BlocksList) {
|
|
var list C.TS7BlocksList
|
|
|
|
res := C.Cli_ListBlocks(client, (*C.TS7BlocksList)(unsafe.Pointer(&list)))
|
|
|
|
return (int)(res), TS7BlocksList{
|
|
OBCount: (int)(list.OBCount),
|
|
FBCount: (int)(list.FBCount),
|
|
FCCount: (int)(list.FCCount),
|
|
SFBCount: (int)(list.SFBCount),
|
|
SFCCount: (int)(list.SFCCount),
|
|
DBCount: (int)(list.DBCount),
|
|
SDBCount: (int)(list.SDBCount)}
|
|
}
|
|
|
|
func GetAgBlockInfo(client C.S7Object, blockType, blockNum int) (int, TS7BlockInfo) {
|
|
var info C.TS7BlockInfo
|
|
/*
|
|
blockType:
|
|
OB = 0x38
|
|
DB = 0x41
|
|
SDB = 0x42
|
|
FC = 0x43
|
|
SFC = 0x44
|
|
FB = 0x45
|
|
SFB =0x46
|
|
|
|
Wrap7BlockTypeOB = 0x38
|
|
Wrap7BlockTypeDB = 0x41
|
|
Wrap7BlockTypeSDB = 0x42
|
|
Wrap7BlockTypeFC = 0x43
|
|
Wrap7BlockTypeSFC = 0x44
|
|
Wrap7BlockTypeFB = 0x45
|
|
Wrap7BlockTypeSFB = 0x46
|
|
*/
|
|
|
|
res := C.Cli_GetAgBlockInfo(client, (C.int)(blockType), (C.int)(blockNum), (*C.TS7BlockInfo)(unsafe.Pointer(&info)))
|
|
|
|
return (int)(res), TS7BlockInfo{
|
|
BlkType: (int)(info.BlkType),
|
|
BlkNumber: (int)(info.BlkNumber),
|
|
BlkLang: (int)(info.BlkLang),
|
|
BlkFlags: (int)(info.BlkFlags),
|
|
MC7Size: (int)(info.MC7Size),
|
|
LoadSize: (int)(info.LoadSize),
|
|
LocalData: (int)(info.LocalData),
|
|
SBBLength: (int)(info.SBBLength),
|
|
CheckSum: (int)(info.CheckSum),
|
|
Version: (int)(info.Version),
|
|
CodeDate: C.GoString((*C.char)(unsafe.Pointer(&info.CodeDate[0]))),
|
|
IntfDate: C.GoString((*C.char)(unsafe.Pointer(&info.IntfDate[0]))),
|
|
Author: C.GoString((*C.char)(unsafe.Pointer(&info.Author[0]))),
|
|
Family: C.GoString((*C.char)(unsafe.Pointer(&info.Family[0]))),
|
|
Header: C.GoString((*C.char)(unsafe.Pointer(&info.Header[0])))}
|
|
}
|
|
|
|
/*
|
|
int GetAgBlockInfo(int BlockType, int BlockNum, PS7BlockInfo pUsrData);
|
|
int GetPgBlockInfo(void *pBlock, PS7BlockInfo pUsrData, int Size);
|
|
int ListBlocksOfType(int BlockType, TS7BlocksOfType *pUsrData, int *ItemsCount);
|
|
*/
|
|
|
|
func GetPlcStatus(client C.S7Object) (int, int8, ConditionType) {
|
|
var status C.int
|
|
res := C.Cli_GetPlcStatus(client, &status)
|
|
|
|
return (int)(res), (int8)(status), func(sc int8) ConditionType {
|
|
switch sc {
|
|
case C.S7CpuStatusRun:
|
|
return CONDITION_RUNNING
|
|
case C.S7CpuStatusStop:
|
|
return CONDITION_STOPPED
|
|
default: //C.S7CpuStatusUnknown
|
|
return CONDITION_UNKNOWN
|
|
|
|
}
|
|
}((int8)(status))
|
|
}
|
|
|
|
/*
|
|
Cli_GetPlcStatus(Client, &Status);
|
|
if (Check(res, "CPU Status"))
|
|
{
|
|
switch (Status)
|
|
{
|
|
case S7CpuStatusRun:
|
|
printf(" RUN\n");
|
|
break;
|
|
case S7CpuStatusStop:
|
|
printf(" STOP\n");
|
|
break;
|
|
default:
|
|
printf(" UNKNOWN\n");
|
|
break;
|
|
}
|
|
};
|
|
}
|
|
*/
|
|
|
|
// MultiRead liest ein Array von Werten aus der SPS
|
|
func MultiRead(client C.S7Object, items []MultiReadWriteItem) (int, [][]byte) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
fmt.Printf("%v", err)
|
|
}
|
|
}()
|
|
|
|
itemsCount := len(items)
|
|
if itemsCount > MULTIREADWRITE_BUFFERS {
|
|
panic("Error in \"func MultiRead(client C.S7Object, items []MultiReadWriteItem)\": Too many items\n\n") // FIXME: Standardfehlermeldung erzeugen
|
|
}
|
|
|
|
var mulitReadWriteBuffer [MULTIREADWRITE_BUFFERS][MAXPDULENGTH]byte
|
|
var cItems [MULTIREADWRITE_BUFFERS]C.TS7DataItem
|
|
for i, v := range items {
|
|
cItems[i].Area = (C.int)(v.Area)
|
|
cItems[i].WordLen = (C.int)(v.WordLen)
|
|
cItems[i].DBNumber = (C.int)(v.DBNumber)
|
|
cItems[i].Start = (C.int)(v.Start)
|
|
cItems[i].Amount = (C.int)(v.Amount)
|
|
}
|
|
|
|
res := C.MultiRead(client, (*[MAXPDULENGTH]C.uchar)(unsafe.Pointer(&mulitReadWriteBuffer)), (*C.TS7DataItem)(unsafe.Pointer(&cItems)), (C.int)(itemsCount))
|
|
|
|
/*DEBUG
|
|
// Baue eine Testinfo ein
|
|
mulitReadWriteBuffer[0][2] = 'G'
|
|
fmt.Println(mulitReadWriteBuffer)
|
|
*/
|
|
|
|
// Bereinige das von Snap7 gelieferte Ergebnis und begrenze die Ausgabe auf den tatsächlichen Inhalt
|
|
var datares [][]byte
|
|
datares = make([][]byte, itemsCount)
|
|
|
|
for i := 0; i < itemsCount; i++ {
|
|
datares[i] = make([]byte, items[i].Amount)
|
|
copy(datares[i], mulitReadWriteBuffer[i][0:items[i].Amount])
|
|
}
|
|
|
|
return (int)(res), datares
|
|
}
|
|
|
|
// MultiWrite schreibt ein Array von Werten in die SPS. Auf den ersten Blick ist ein Rücklesen der Werte in MultiWrite nun ein überflüssiger Overhead. Machen wir dies hier aber nicht, müßte in Fällen, wo mit dem veränderten Speicher weitergearbeitet werden soll, ein weiteres MultiRead folgen. Dies können wir hier einsparen, wenn wir den veränderten Speicher hier zurückgeben. Wir bleiben somit auch synchron zur MultiRead-Funktion
|
|
func MultiWrite(client C.S7Object, items []MultiReadWriteItem, buffers *[][]byte) (int, [][]byte) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
fmt.Printf("%v", err)
|
|
}
|
|
}()
|
|
|
|
itemsCount := len(items)
|
|
|
|
if itemsCount > MULTIREADWRITE_BUFFERS {
|
|
panic("Error in \"func MultiWrite(client C.S7Object, items []MultiReadWriteItem)\": Too many items\n\n") // FIXME: Standardfehlermeldung erzeugen
|
|
} else if buffersCount := len(*buffers); itemsCount != buffersCount {
|
|
panic("Error in \"func MultiWrite(client C.S7Object, items []MultiReadWriteItem)\": Number of items and number of buffers must be identical\n\n") // FIXME: Standardfehlermeldung erzeugen
|
|
}
|
|
|
|
var mulitReadWriteBuffer [MULTIREADWRITE_BUFFERS][MAXPDULENGTH]byte
|
|
var cItems [MULTIREADWRITE_BUFFERS]C.TS7DataItem
|
|
for i, v := range items {
|
|
if len((*buffers)[i]) < v.Amount {
|
|
panic(fmt.Sprintf("Error in \"func MultiWrite(client C.S7Object, items []MultiReadWriteItem) [Index %d]\": Amount must not be larger than buffer length!\n\n", i)) // FIXME: Standardfehlermeldung erzeugen
|
|
}
|
|
|
|
cItems[i].Area = (C.int)(v.Area)
|
|
cItems[i].WordLen = (C.int)(v.WordLen)
|
|
cItems[i].DBNumber = (C.int)(v.DBNumber)
|
|
cItems[i].Start = (C.int)(v.Start)
|
|
cItems[i].Amount = (C.int)(v.Amount)
|
|
copy(mulitReadWriteBuffer[i][0:items[i].Amount], (*buffers)[i][0:items[i].Amount])
|
|
}
|
|
|
|
res := C.MultiWrite(client, (*[MAXPDULENGTH]C.uchar)(unsafe.Pointer(&mulitReadWriteBuffer)), (*C.TS7DataItem)(unsafe.Pointer(&cItems)), (C.int)(itemsCount))
|
|
|
|
// Bereinige das von Snap7 gelieferte Ergebnis und begrenze die Ausgabe auf den tatsächlichen Inhalt
|
|
var datares [][]byte
|
|
datares = make([][]byte, itemsCount)
|
|
|
|
for i := 0; i < itemsCount; i++ {
|
|
datares[i] = make([]byte, items[i].Amount)
|
|
copy(datares[i], mulitReadWriteBuffer[i][0:items[i].Amount])
|
|
}
|
|
|
|
return (int)(res), datares
|
|
}
|
|
|
|
func ReadArea(client C.S7Object, Area, DBNumber, Start, Amount, WordLen int) (int, []byte) {
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
|
|
res := C.Cli_ReadArea(client, (C.int)(Area), (C.int)(DBNumber), (C.int)(Start), (C.int)(Amount), (C.int)(WordLen), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func WriteArea(client C.S7Object, Area, DBNumber, Start, Amount, WordLen int, gobuffer *[]byte) (int, []byte) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
fmt.Printf("%v", err)
|
|
}
|
|
}()
|
|
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
|
|
if len(*gobuffer) < Amount {
|
|
panic("Error in \"func WriteArea(client C.S7Object, Area, DBNumber, Start, Amount, WordLen int, gobuffer *[]byte)\": Amount must not be larger than buffer length!\n\n") // FIXME: Standardfehlermeldung erzeugen
|
|
}
|
|
|
|
cbuffer = *(*[MAXPDULENGTH]C.char)(C.CBytes(*gobuffer))
|
|
|
|
res := C.Cli_WriteArea(client, (C.int)(Area), (C.int)(DBNumber), (C.int)(Start), (C.int)(Amount), (C.int)(WordLen), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func DBRead(client C.S7Object, DBNumber, Start, Amount int) (int, []byte) {
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
res := C.Cli_DBRead(client, (C.int)(DBNumber), (C.int)(Start), (C.int)(Amount), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func DBWrite(client C.S7Object, DBNumber, Start, Amount int, gobuffer *[]byte) (int, []byte) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
fmt.Printf("%v", err)
|
|
}
|
|
}()
|
|
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
|
|
if len(*gobuffer) < Amount {
|
|
panic("Error in \"func DBWrite(client C.S7Object, DBNumber, Start, Amount int, gobuffer *[]byte)\": Amount must not be larger than buffer length!\n\n") // FIXME: Standardfehlermeldung erzeugen
|
|
}
|
|
|
|
cbuffer = *(*[MAXPDULENGTH]C.char)(C.CBytes(*gobuffer))
|
|
|
|
res := C.Cli_DBWrite(client, (C.int)(DBNumber), (C.int)(Start), (C.int)(Amount), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func MBRead(client C.S7Object, Start, Amount int) (int, []byte) {
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
res := C.Cli_MBRead(client, (C.int)(Start), (C.int)(Amount), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func MBWrite(client C.S7Object, Start, Amount int, gobuffer *[]byte) (int, []byte) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
fmt.Printf("%v", err)
|
|
}
|
|
}()
|
|
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
|
|
if len(*gobuffer) < Amount {
|
|
panic("Error in \"func MBWrite(client C.S7Object, Start, Amount int, gobuffer *[]byte)\": Amount must not be larger than buffer length!\n\n") // FIXME: Standardfehlermeldung erzeugen
|
|
}
|
|
|
|
cbuffer = *(*[MAXPDULENGTH]C.char)(C.CBytes(*gobuffer))
|
|
|
|
res := C.Cli_MBWrite(client, (C.int)(Start), (C.int)(Amount), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func EBRead(client C.S7Object, Start, Amount int) (int, []byte) {
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
res := C.Cli_EBRead(client, (C.int)(Start), (C.int)(Amount), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func EBWrite(client C.S7Object, Start, Amount int, gobuffer *[]byte) (int, []byte) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
fmt.Printf("%v", err)
|
|
}
|
|
}()
|
|
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
|
|
if len(*gobuffer) < Amount {
|
|
panic("Error in \"func EBWrite(client C.S7Object, Start, Amount int, gobuffer *[]byte)\": Amount must not be larger than buffer length!\n\n") // FIXME: Standardfehlermeldung erzeugen
|
|
}
|
|
|
|
cbuffer = *(*[MAXPDULENGTH]C.char)(C.CBytes(*gobuffer))
|
|
|
|
res := C.Cli_EBWrite(client, (C.int)(Start), (C.int)(Amount), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func ABRead(client C.S7Object, Start, Amount int) (int, []byte) {
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
res := C.Cli_ABRead(client, (C.int)(Start), (C.int)(Amount), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func ABWrite(client C.S7Object, Start, Amount int, gobuffer *[]byte) (int, []byte) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
fmt.Printf("%v", err)
|
|
}
|
|
}()
|
|
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
|
|
if len(*gobuffer) < Amount {
|
|
panic("Error in \"func ABWrite(client C.S7Object, Start, Amount int, gobuffer *[]byte)\": Amount must not be larger than buffer length!\n\n") // FIXME: Standardfehlermeldung erzeugen
|
|
}
|
|
|
|
cbuffer = *(*[MAXPDULENGTH]C.char)(C.CBytes(*gobuffer))
|
|
|
|
res := C.Cli_ABWrite(client, (C.int)(Start), (C.int)(Amount), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func TMRead(client C.S7Object, Start, Amount int) (int, []byte) {
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
res := C.Cli_TMRead(client, (C.int)(Start), (C.int)(Amount), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func TMWrite(client C.S7Object, Start, Amount int, gobuffer *[]byte) (int, []byte) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
fmt.Printf("%v", err)
|
|
}
|
|
}()
|
|
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
|
|
if len(*gobuffer) < Amount {
|
|
panic("Error in \"func TMWrite(client C.S7Object, Start, Amount int, gobuffer *[]byte)\": Amount must not be larger than buffer length!\n\n") // FIXME: Standardfehlermeldung erzeugen
|
|
}
|
|
|
|
cbuffer = *(*[MAXPDULENGTH]C.char)(C.CBytes(*gobuffer))
|
|
|
|
res := C.Cli_TMWrite(client, (C.int)(Start), (C.int)(Amount), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func CTRead(client C.S7Object, Start, Amount int) (int, []byte) {
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
res := C.Cli_CTRead(client, (C.int)(Start), (C.int)(Amount), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
func CTWrite(client C.S7Object, Start, Amount int, gobuffer *[]byte) (int, []byte) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
fmt.Printf("%v", err)
|
|
}
|
|
}()
|
|
|
|
var cbuffer [MAXPDULENGTH]C.char
|
|
|
|
if len(*gobuffer) < Amount {
|
|
panic("Error in \"func CTWrite(client C.S7Object, Start, Amount int, gobuffer *[]byte)\": Amount must not be larger than buffer length!\n\n") // FIXME: Standardfehlermeldung erzeugen
|
|
}
|
|
|
|
cbuffer = *(*[MAXPDULENGTH]C.char)(C.CBytes(*gobuffer))
|
|
|
|
res := C.Cli_CTWrite(client, (C.int)(Start), (C.int)(Amount), unsafe.Pointer(&cbuffer))
|
|
|
|
return (int)(res), C.GoBytes(unsafe.Pointer(&cbuffer), (C.int)(Amount))
|
|
}
|
|
|
|
// CliCreate creates a SPS-client
|
|
func CliCreate() S7Object {
|
|
return C.Cli_Create()
|
|
}
|
|
|
|
// CliConnect connects to SPS-client
|
|
func CliConnect(client S7Object, ip net.IP, rack uint8, slot uint8) {
|
|
C.Cli_ConnectTo(client, C.CString(ip.String()), (C.int)(rack), (C.int)(slot))
|
|
}
|
|
|
|
// FIXME: Remove me sometimes
|
|
// CreateAndConnect is a wrapper for CliDisconnect for compatibility purpose, has to be removed in a later version or wrap7
|
|
func CreateAndConnect(ip net.IP, rack uint8, slot uint8) S7Object {
|
|
log.Println("CreateAndConnect is a wrapper for CliCreateAndConnect for compatibility purpose, has to be removed in a later version or wrap7")
|
|
return CliCreateAndConnect(ip, rack, slot)
|
|
}
|
|
|
|
// CliCreateAndConnect creates a SPS-client and connect to SPS
|
|
func CliCreateAndConnect(ip net.IP, rack uint8, slot uint8) S7Object {
|
|
client := C.Cli_Create()
|
|
C.Cli_ConnectTo(client, C.CString(ip.String()), (C.int)(rack), (C.int)(slot))
|
|
|
|
return client
|
|
}
|
|
|
|
// CliConditionalCreateAndConnect creates a SPS-client after successfull ping and connects to SPS
|
|
func CliConditionalCreateAndConnect(ip net.IP, rack uint8, slot uint8) (S7Object, error) {
|
|
_, loss := pingMyDing(ip)
|
|
var client S7Object
|
|
|
|
if loss < PINGER_CRITICAL_LOSS_PERCENT {
|
|
client = C.Cli_Create()
|
|
C.Cli_ConnectTo(client, C.CString(ip.String()), (C.int)(rack), (C.int)(slot))
|
|
return client, nil
|
|
} else {
|
|
return client, fmt.Errorf("Unable to ping SPS [%s, %v% loss]", ip.String(), loss)
|
|
}
|
|
|
|
}
|
|
|
|
// CliDisconnect disconnects SPS-client from SPS
|
|
func CliDisconnect(client S7Object) {
|
|
C.Cli_Disconnect(client)
|
|
}
|
|
|
|
func CliDestroy(client *S7Object) {
|
|
C.Cli_Destroy(client)
|
|
}
|
|
|
|
func CliDisconnectAndDestroy(client S7Object) {
|
|
C.Cli_Disconnect(client)
|
|
C.Cli_Destroy(&client)
|
|
}
|
|
|
|
// FIXME: Remove me sometimes
|
|
// Disconnect is a wrapper for CliDisconnect for compatibility purpose, has to be removed in a later version or wrap7
|
|
func Disconnect(client S7Object) {
|
|
log.Println("Disconnect is a wrapper for CliDisconnect for compatibility purpose, has to be removed in a later version or wrap7")
|
|
CliDisconnect(client)
|
|
}
|
|
|
|
/*Server Functions*/
|
|
func SrvCreate() S7Object {
|
|
return C.Srv_Create()
|
|
}
|
|
|
|
func SrvStart(server *S7Object) int {
|
|
return (int)(C.Srv_Start(*server))
|
|
}
|
|
|
|
func SrvStop(server *S7Object) {
|
|
C.Srv_Stop(*server)
|
|
}
|
|
|
|
func SrvDestroy(server *S7Object) {
|
|
C.Srv_Destroy(server)
|
|
}
|
|
|
|
func SrvErrorText(errorCode int, spsServerText *rune, eventCallBackLength int) {
|
|
//C.Srv_ErrorText((C.int)(ErrorCode), (*C.char)(unsafe.Pointer(&spsServerText[0])), C.EventCallBackLength)
|
|
C.Srv_ErrorText((C.int)(errorCode), (*C.char)(unsafe.Pointer(spsServerText)), (C.int)(eventCallBackLength))
|
|
}
|
|
|
|
func SrvRegisterArea(server *S7Object, area int, index uint16, buffer []byte, length int) {
|
|
C.Srv_RegisterArea(*server,
|
|
(C.int)(area), // Area
|
|
(C.ushort)(index), // Nummer des Datenbausteins
|
|
//unsafe.Pointer(&(buffer[0])), // Buffer
|
|
//unsafe.Pointer(&((*buffer)[0])),
|
|
C.CBytes(buffer),
|
|
(C.int)(length)) // Die Länge ist durch die Variablendefinition bereits vorgegeben und kann hier gemessen werden.
|
|
|
|
}
|
|
|
|
func SrvUnregisterArea(server *S7Object, area int, index uint16) {
|
|
C.Srv_UnregisterArea(*server, (C.int)(area), (C.ushort)(index))
|
|
}
|
|
|
|
func RegisterEventCallBack(server *S7Object) {
|
|
C._RegisterEventCallBack(*server)
|
|
}
|
|
|
|
func SrvLockArea(server *S7Object, area int, index uint16) {
|
|
C.Srv_LockArea(*server,
|
|
(C.int)(area), // Area
|
|
(C.ushort)(index)) // Nummer des Datenbausteins
|
|
}
|
|
|
|
func SrvUnlockArea(server *S7Object, area int, index uint16) {
|
|
C.Srv_UnlockArea(*server,
|
|
(C.int)(area), // Area
|
|
(C.ushort)(index)) // Nummer des Datenbausteins
|
|
}
|