goplctag icon indicating copy to clipboard operation
goplctag copied to clipboard

Bug: GetString and GetRawBytes do not populate buffer when rc is successful

Open MichaelPiran opened this issue 4 months ago • 2 comments

I have problem regarding the functions "GetString()" and "GetRawBytes()" declared in goplctag.go file, they do not fill the buffer.

The problem is related to the function "copyPCharBytes()", i have tried to bypass that method and declaring the variable "cbuffer" as "cbuffer := (*C.char)(unsafe.Pointer(&buffer[0]))" and it worked for me.

Here is my code:

func main() {

	// ... //

	tag_path := fmt.Sprintf("protocol=ab_eip&gateway=%s&path=1,0&cpu=nx1p2&name=%s", ip_ipdentifier, TAG)

	tag := goplctag.Create(tag_path, DATA_TIMEOUT)
	if tag < 0 {
		fmt.Printf("ERROR %s: Could not create tag!\n", goplctag.DecodeError(int32(tag)))
		os.Exit(0)
	}

	if rc := goplctag.Status(tag); rc != goplctag.StatusOk {
		fmt.Printf("ERROR %s: Error setting up tag internal state.\n", goplctag.DecodeError(rc))
		goplctag.Destroy(tag)
		os.Exit(0)
	}

	// read the tag from plc
	if rc := goplctag.Read(tag, DATA_TIMEOUT); rc != goplctag.StatusOk {
		fmt.Printf("ERROR: Unable to read the data! Got error code %d: %s\n", rc, goplctag.DecodeError(rc))
		goplctag.Destroy(tag)
		os.Exit(0)
	}

	tagSize := goplctag.GetSize(tag)
	fmt.Printf("Tag size: %d bytes\n", tagSize)

	var offset int32 = 0
	strNum := 1
	for offset < tagSize {
		strCap := goplctag.GetStringLength(tag, offset) + 1 // +1 per il terminatore zero

		str := make([]byte, int(strCap))

		rc := goplctag.GetString(tag, offset, str, strCap)
		if rc != goplctag.StatusOk {
			goplctag.Destroy(tag)
			fmt.Printf("unable to get string %d, got error %s!", strNum, goplctag.DecodeError(rc))
			return
		}

		fmt.Fprintf(os.Stderr, "string %d (%d chars) = '%s'", strNum, len(str), string(str))

		strNum++
		offset += goplctag.GetStringTotalLength(tag, offset)
	}

	goplctag.Destroy(tag)
}

Below you see my successful workaround:

func GetString(tagId int32, stringStartOffset int32, buffer []byte, bufferLength int32) int32 {
	ctagId, ctagIdAllocMap := (C.int32_t)(tagId), cgoAllocsUnknown
	cstringStartOffset, cstringStartOffsetAllocMap := (C.int)(stringStartOffset), cgoAllocsUnknown

	cbuffer := (*C.char)(unsafe.Pointer(&buffer[0]))

	cbufferLength, cbufferLengthAllocMap := (C.int)(bufferLength), cgoAllocsUnknown
	__ret := C.plc_tag_get_string(ctagId, cstringStartOffset, cbuffer, cbufferLength)
	runtime.KeepAlive(cbufferLengthAllocMap)
	// runtime.KeepAlive(cbufferAllocMap)
	runtime.KeepAlive(cstringStartOffsetAllocMap)
	runtime.KeepAlive(ctagIdAllocMap)
	__v := (int32)(__ret)
	return __v
}

Is there a bug on the goplctag.go file or am I using it wrong?

example.txt

MichaelPiran avatar Aug 27 '25 10:08 MichaelPiran

Hey Michael, is been a good while since I have used this library. My goal was to build some things with go but I sorta moved on from controls engineering to software engineering right when I was building it. The library is built with code generation tool https://github.com/xlab/c-for-go

Lemme ask on the google forum to see if any other users have ran into the same problem, I would have expected more bug reports by now, almost 3 years with zero gh issues. https://groups.google.com/g/libplctag/c/Y4fkZxPb4wU/m/GjJUFJNdAAAJ

Two things for now, please post your usage use code blocks like this:

var offset int32 = 0

Second in another code block post the code that you got working. Why do this, it allows for people to see the code on the issue, instead of downloading files.

Lastly what version of plctag core library are you using? If is not 2.5.x, then please test with 2.5.x and let me know. I will try to get my environment setup again to possibly regenerate and add more tests for strings, but it could be a while before I get to it.

TheFern2 avatar Aug 28 '25 23:08 TheFern2

I m using the 2.5.1

MichaelPiran avatar Sep 01 '25 06:09 MichaelPiran