You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2021/04/10 11:43:23 UTC
[plc4x] branch develop updated: plc4go: fixed several bugs
concerning type conversions
This is an automated email from the ASF dual-hosted git repository.
sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/develop by this push:
new b4b2a63 plc4go: fixed several bugs concerning type conversions
b4b2a63 is described below
commit b4b2a63e2993a7a29554db49b0e77ed756783db1
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Sat Apr 10 13:43:10 2021 +0200
plc4go: fixed several bugs concerning type conversions
+ ManualTestRunner.go uses *testing.T now to better report failures
+ Implemented first draft of date/time
+ Fixed int and bit strings
+ Fixed PlcValueAdapter.go falsely having a plcValue child (was meant to be a "implements")
---
.../main/drivers/tests/manual_ads_driver_test.go | 2 +-
plc4go/internal/plc4go/ads/Reader.go | 2 +-
plc4go/internal/plc4go/spi/MessageCodec.go | 3 +
.../plc4go/spi/testutils/ManualTestRunner.go | 192 +++++++++++----------
plc4go/internal/plc4go/spi/values/DATE.go | 10 +-
plc4go/internal/plc4go/spi/values/DATE_AND_TIME.go | 10 +-
plc4go/internal/plc4go/spi/values/INT.go | 8 +-
plc4go/internal/plc4go/spi/values/LTIME.go | 9 +
plc4go/internal/plc4go/spi/values/PlcBitString.go | 8 +-
.../internal/plc4go/spi/values/PlcValueAdapter.go | 18 +-
plc4go/internal/plc4go/spi/values/TIME.go | 9 +
plc4go/internal/plc4go/spi/values/TIME_OF_DAY.go | 4 +
plc4go/pkg/plc4go/values/plc_value.go | 4 +-
13 files changed, 166 insertions(+), 113 deletions(-)
diff --git a/plc4go/cmd/main/drivers/tests/manual_ads_driver_test.go b/plc4go/cmd/main/drivers/tests/manual_ads_driver_test.go
index 24a4698..92b2634 100644
--- a/plc4go/cmd/main/drivers/tests/manual_ads_driver_test.go
+++ b/plc4go/cmd/main/drivers/tests/manual_ads_driver_test.go
@@ -85,7 +85,7 @@ func TestManualAds(t *testing.T) {
driverManager := plc4go.NewPlcDriverManager()
driverManager.RegisterDriver(ads.NewDriver())
driverManager.RegisterTransport(tcp.NewTransport())
- test := testutils.NewManualTestSuite(connectionString, driverManager)
+ test := testutils.NewManualTestSuite(connectionString, driverManager, t)
test.AddTestCase("main.hurz_BOOL:BOOL", true)
test.AddTestCase("main.hurz_BYTE:BYTE", []bool{false, false, true, false, true, false, true, false})
test.AddTestCase("main.hurz_WORD:WORD", []bool{true, false, true, false, false, true, false, true, true, false, true, true, true, false, false, false})
diff --git a/plc4go/internal/plc4go/ads/Reader.go b/plc4go/internal/plc4go/ads/Reader.go
index b1858f8..8a985d0 100644
--- a/plc4go/internal/plc4go/ads/Reader.go
+++ b/plc4go/internal/plc4go/ads/Reader.go
@@ -407,7 +407,7 @@ func (m *Reader) ToPlc4xReadResponse(amsTcpPaket readWriteModel.AmsTCPPacket, re
plcValues := map[string]values.PlcValue{}
// Get the field from the request
for _, fieldName := range readRequest.GetFieldNames() {
- log.Trace().Msg("get a field from request")
+ log.Debug().Msgf("get a field from request with name %s", fieldName)
field, err := castToAdsFieldFromPlcField(readRequest.GetField(fieldName))
if err != nil {
return nil, errors.Wrap(err, "error casting to ads-field")
diff --git a/plc4go/internal/plc4go/spi/MessageCodec.go b/plc4go/internal/plc4go/spi/MessageCodec.go
index 39e841a..bcb86c5 100644
--- a/plc4go/internal/plc4go/spi/MessageCodec.go
+++ b/plc4go/internal/plc4go/spi/MessageCodec.go
@@ -173,6 +173,7 @@ func (m *DefaultCodec) TimeoutExpectations(now time.Time) {
// Remove this expectation from the list.
m.Expectations = append(m.Expectations[:index], m.Expectations[index+1:]...)
// Call the error handler.
+ // TODO: decouple from worker thread
err := expectation.GetHandleError()(plcerrors.NewTimeoutError(now.Sub(expectation.GetExpiration())))
if err != nil {
log.Error().Err(err).Msg("Got an error handling error on expectation")
@@ -188,9 +189,11 @@ func (m *DefaultCodec) HandleMessages(message interface{}) bool {
// If it does, let it handle the message.
if accepts := expectation.GetAcceptsMessage()(message); accepts {
log.Debug().Stringer("expectation", expectation).Msg("accepts message")
+ // TODO: decouple from worker thread
err := expectation.GetHandleMessage()(message)
if err != nil {
// Pass the error to the error handler.
+ // TODO: decouple from worker thread
err := expectation.GetHandleError()(err)
if err != nil {
log.Error().Err(err).Msg("Got an error handling error on expectation")
diff --git a/plc4go/internal/plc4go/spi/testutils/ManualTestRunner.go b/plc4go/internal/plc4go/spi/testutils/ManualTestRunner.go
index 6a0ad52..5c0b522 100644
--- a/plc4go/internal/plc4go/spi/testutils/ManualTestRunner.go
+++ b/plc4go/internal/plc4go/spi/testutils/ManualTestRunner.go
@@ -21,11 +21,14 @@ package testutils
import (
"fmt"
+ "github.com/apache/plc4x/plc4go/internal/plc4go/spi/values"
"github.com/apache/plc4x/plc4go/pkg/plc4go"
"github.com/apache/plc4x/plc4go/pkg/plc4go/model"
"github.com/rs/zerolog/log"
"math/rand"
+ "reflect"
"strings"
+ "testing"
"time"
)
@@ -39,12 +42,14 @@ type ManualTestSuite struct {
ConnectionString string
DriverManager plc4go.PlcDriverManager
TestCases []ManualTestCase
+ t *testing.T
}
-func NewManualTestSuite(connectionString string, driverManager plc4go.PlcDriverManager) *ManualTestSuite {
+func NewManualTestSuite(connectionString string, driverManager plc4go.PlcDriverManager, t *testing.T) *ManualTestSuite {
return &ManualTestSuite{
ConnectionString: connectionString,
DriverManager: driverManager,
+ t: t,
}
}
@@ -62,111 +67,118 @@ func (m *ManualTestSuite) Run() {
// Run all entries separately:
for _, testCase := range m.TestCases {
fieldName := testCase.Address
+ m.t.Run(fieldName, func(t *testing.T) {
+ m.runSingleTest(t, connection, fieldName, testCase)
+ })
+ }
+ m.t.Run("combinedTest", func(t *testing.T) {
+ m.runBurstTest(t, connection)
+ })
+}
- {
- // Prepare the read-request
- readRequestBuilder := connection.Connection.ReadRequestBuilder()
- readRequestBuilder.AddQuery(fieldName, testCase.Address)
- readRequest, err := readRequestBuilder.Build()
- if err != nil {
- panic(err)
- }
-
- // Execute the read request
- readResponseResult := <-readRequest.Execute()
- if readResponseResult.Err != nil {
- panic(err)
- }
- readResponse := readResponseResult.Response
-
- // Check the result
- assertEquals(1, len(readResponse.GetFieldNames()), fieldName)
- assertEquals(fieldName, readResponse.GetFieldNames()[0], fieldName)
- assertEquals(model.PlcResponseCode_OK, readResponse.GetResponseCode(fieldName), fieldName)
- assertNotNil(readResponse.GetValue(fieldName), fieldName)
- // TODO: is list is not the right call here. There is also a bug which breaks the field on the get list call which should be fixed
- if readResponse.GetValue(fieldName).IsList() && false {
- plcList := readResponse.GetValue(fieldName).GetList()
- expectedValues := testCase.ExpectedReadValue.([]interface{})
- for j := 0; j < len(expectedValues); j++ {
- assertEquals(expectedValues[j], plcList[j].GetString(), fmt.Sprintf("%s[%d]", fieldName, j))
- }
- } else {
- assertEquals(fmt.Sprint(testCase.ExpectedReadValue), readResponse.GetValue(fieldName).GetString(), fieldName)
- }
+func (m *ManualTestSuite) runSingleTest(t *testing.T, connection plc4go.PlcConnectionConnectResult, fieldName string, testCase ManualTestCase) {
+ // Prepare the read-request
+ readRequestBuilder := connection.Connection.ReadRequestBuilder()
+ readRequestBuilder.AddQuery(fieldName, testCase.Address)
+ readRequest, err := readRequestBuilder.Build()
+ if err != nil {
+ panic(err)
+ }
- log.Info().Msg("Success")
+ // Execute the read request
+ readResponseResult := <-readRequest.Execute()
+ if readResponseResult.Err != nil {
+ panic(err)
+ }
+ readResponse := readResponseResult.Response
+
+ // Check the result
+ assertEquals(t, 1, len(readResponse.GetFieldNames()), fieldName)
+ assertEquals(t, fieldName, readResponse.GetFieldNames()[0], fieldName)
+ assertEquals(t, model.PlcResponseCode_OK, readResponse.GetResponseCode(fieldName), fieldName)
+ assertNotNil(t, readResponse.GetValue(fieldName), fieldName)
+ expectation := reflect.ValueOf(testCase.ExpectedReadValue)
+ if readResponse.GetValue(fieldName).IsList() && (expectation.Kind() == reflect.Slice || expectation.Kind() == reflect.Array) {
+ plcList := readResponse.GetValue(fieldName).GetList()
+ for j := 0; j < expectation.Len(); j++ {
+ assertEquals(t, expectation.Index(j).Interface(), plcList[j], fmt.Sprintf("%s[%d]", fieldName, j))
}
+ } else {
+ assertEquals(t, fmt.Sprint(testCase.ExpectedReadValue), readResponse.GetValue(fieldName).GetString(), fieldName)
+ }
+}
- {
- // Read all items in one big request.
- // Shuffle the list of test cases and run the test 10 times.
- log.Info().Msg("Reading all items together in random order")
- for i := 0; i < 100; i++ {
- log.Info().Msgf(" - run number %d of %d", i, 100)
- shuffledTestcases := append(make([]ManualTestCase, 0), m.TestCases...)
- rand.Seed(time.Now().UnixNano())
- rand.Shuffle(len(shuffledTestcases), func(i, j int) {
- shuffledTestcases[i], shuffledTestcases[j] = shuffledTestcases[j], shuffledTestcases[i]
- })
-
- sb := strings.Builder{}
- for _, testCase := range shuffledTestcases {
- sb.WriteString(testCase.Address)
- sb.WriteString(", ")
- }
- log.Info().Msgf(" using order: %s", sb.String())
+func (m *ManualTestSuite) runBurstTest(t *testing.T, connection plc4go.PlcConnectionConnectResult) {
+ // Read all items in one big request.
+ // Shuffle the list of test cases and run the test 10 times.
+ log.Info().Msg("Reading all items together in random order")
+ for i := 0; i < 100; i++ {
+ log.Info().Msgf(" - run number %d of %d", i, 100)
+ shuffledTestcases := append(make([]ManualTestCase, 0), m.TestCases...)
+ rand.Seed(time.Now().UnixNano())
+ rand.Shuffle(len(shuffledTestcases), func(i, j int) {
+ shuffledTestcases[i], shuffledTestcases[j] = shuffledTestcases[j], shuffledTestcases[i]
+ })
+
+ sb := strings.Builder{}
+ for _, testCase := range shuffledTestcases {
+ sb.WriteString(testCase.Address)
+ sb.WriteString(", ")
+ }
+ log.Info().Msgf(" using order: %s", sb.String())
- builder := connection.Connection.ReadRequestBuilder()
- for _, testCase := range shuffledTestcases {
- fieldName := testCase.Address
- builder.AddQuery(fieldName, testCase.Address)
- }
- readRequest, err := builder.Build()
- if err != nil {
- panic(err)
- }
+ builder := connection.Connection.ReadRequestBuilder()
+ for _, testCase := range shuffledTestcases {
+ fieldName := testCase.Address
+ builder.AddQuery(fieldName, testCase.Address)
+ }
+ readRequest, err := builder.Build()
+ if err != nil {
+ t.Errorf("Error building request %v", err)
+ return
+ }
- // Execute the read request
- readResponseResult := <-readRequest.Execute()
- if readResponseResult.Err != nil {
- panic(err)
- }
- readResponse := readResponseResult.Response
-
- // Check the result
- assertEquals(len(shuffledTestcases), len(readResponse.GetFieldNames()))
- for _, testCase := range shuffledTestcases {
- fieldName := testCase.Address
- assertEquals(model.PlcResponseCode_OK, readResponse.GetResponseCode(fieldName))
- assertNotNil(readResponse.GetValue(fieldName))
- // TODO: is list is not the right call here. There is also a bug which breaks the field on the get list call which should be fixed
- if readResponse.GetValue(fieldName).IsList() && false {
- plcList := readResponse.GetValue(fieldName).GetList()
- expectedValues := testCase.ExpectedReadValue.([]interface{})
- for j := 0; j < len(expectedValues); j++ {
- assertEquals(expectedValues[j], plcList[j].GetString(), fmt.Sprintf("%s[%d]", fieldName, j))
- }
- } else {
- assertEquals(fmt.Sprint(testCase.ExpectedReadValue), readResponse.GetValue(fieldName).GetString(), fieldName)
- }
+ // Execute the read request
+ readResponseResult := <-readRequest.Execute()
+ if readResponseResult.Err != nil {
+ t.Errorf("Error getting response %v", err)
+ return
+ }
+ readResponse := readResponseResult.Response
+
+ // Check the result
+ assertEquals(t, len(shuffledTestcases), len(readResponse.GetFieldNames()))
+ for _, testCase := range shuffledTestcases {
+ fieldName := testCase.Address
+ assertEquals(t, model.PlcResponseCode_OK, readResponse.GetResponseCode(fieldName))
+ assertNotNil(t, readResponse.GetValue(fieldName))
+ expectation := reflect.ValueOf(testCase.ExpectedReadValue)
+ if readResponse.GetValue(fieldName).IsList() && (expectation.Kind() == reflect.Slice || expectation.Kind() == reflect.Array) {
+ plcList := readResponse.GetValue(fieldName).GetList()
+ for j := 0; j < expectation.Len(); j++ {
+ assertEquals(t, expectation.Index(j).Interface(), plcList[j], fmt.Sprintf("%s[%d]", fieldName, j))
}
+ } else {
+ assertEquals(t, fmt.Sprint(testCase.ExpectedReadValue), readResponse.GetValue(fieldName).GetString(), fieldName)
}
- log.Info().Msg("Success")
}
}
}
-func assertEquals(expected interface{}, actual interface{}, message ...string) {
+func assertEquals(t *testing.T, expected interface{}, actual interface{}, message ...string) {
+ switch actual.(type) {
+ case values.PlcBOOL:
+ actual = actual.(values.PlcBOOL).GetBool()
+ case values.PlcWORD:
+ actual = actual.(values.PlcWORD).GetInt8()
+ }
if expected != actual {
- log.Error().Msgf("actual %v doesn't match expected %v\nmessage: %s", actual, expected, message)
- panic("Assertion failed")
+ t.Errorf("actual %v doesn't match expected %v\nmessage: %s", actual, expected, message)
}
}
-func assertNotNil(actual interface{}, message ...string) {
+func assertNotNil(t *testing.T, actual interface{}, message ...string) {
if actual == nil {
- log.Error().Msgf("actual %v is nil\nmessage: %v", actual, message)
- panic("Assertion failed")
+ t.Errorf("actual %v is nil\nmessage: %v", actual, message)
}
}
diff --git a/plc4go/internal/plc4go/spi/values/DATE.go b/plc4go/internal/plc4go/spi/values/DATE.go
index 7dc2da2..fdc19a4 100644
--- a/plc4go/internal/plc4go/spi/values/DATE.go
+++ b/plc4go/internal/plc4go/spi/values/DATE.go
@@ -48,11 +48,15 @@ func NewPlcDATE(value interface{}) PlcDATE {
}
}
-func (m PlcDATE) IsTime() bool {
+func (m PlcDATE) IsDate() bool {
return true
}
-func (m PlcDATE) GetTime() time.Time {
- return m.value
+func (m PlcDATE) GetDate() time.Time {
+ return time.Date(m.value.Year(), m.value.Month(), m.value.Day(), 0, 0, 0, 0, time.UTC)
+}
+
+func (m PlcDATE) GetString() string {
+ return m.GetDate().Format("2006-01-02")
}
func (m PlcDATE) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
diff --git a/plc4go/internal/plc4go/spi/values/DATE_AND_TIME.go b/plc4go/internal/plc4go/spi/values/DATE_AND_TIME.go
index fc7cb0c..2c39601 100644
--- a/plc4go/internal/plc4go/spi/values/DATE_AND_TIME.go
+++ b/plc4go/internal/plc4go/spi/values/DATE_AND_TIME.go
@@ -20,6 +20,7 @@ package values
import (
"encoding/xml"
+ "fmt"
"time"
)
@@ -34,12 +35,15 @@ func NewPlcDATE_AND_TIME(value time.Time) PlcDATE_AND_TIME {
}
}
-func (m PlcDATE_AND_TIME) IsTime() bool {
+func (m PlcDATE_AND_TIME) IsDateTime() bool {
return true
}
+func (m PlcDATE_AND_TIME) GetDateTime() time.Time {
+ return time.Time{}.Add(m.GetDuration())
+}
-func (m PlcDATE_AND_TIME) GetTime() time.Time {
- return m.value
+func (m PlcDATE_AND_TIME) GetString() string {
+ return fmt.Sprintf("%v", m.GetDateTime())
}
func (m PlcDATE_AND_TIME) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
diff --git a/plc4go/internal/plc4go/spi/values/INT.go b/plc4go/internal/plc4go/spi/values/INT.go
index af1c73f..cbfea8a 100644
--- a/plc4go/internal/plc4go/spi/values/INT.go
+++ b/plc4go/internal/plc4go/spi/values/INT.go
@@ -102,21 +102,21 @@ func (m PlcINT) GetInt16() int16 {
}
func (m PlcINT) GetInt32() int32 {
- return int32(m.GetInt8())
+ return int32(m.GetInt16())
}
func (m PlcINT) GetInt64() int64 {
- return int64(m.GetInt8())
+ return int64(m.GetInt16())
}
func (m PlcINT) GetFloat32() float32 {
//TODO: Check if this is ok
- return float32(m.GetInt8())
+ return float32(m.GetInt16())
}
func (m PlcINT) GetFloat64() float64 {
//TODO: Check if this is ok
- return float64(m.GetInt8())
+ return float64(m.GetInt16())
}
func (m PlcINT) GetString() string {
diff --git a/plc4go/internal/plc4go/spi/values/LTIME.go b/plc4go/internal/plc4go/spi/values/LTIME.go
index 738fd18..23f02d9 100644
--- a/plc4go/internal/plc4go/spi/values/LTIME.go
+++ b/plc4go/internal/plc4go/spi/values/LTIME.go
@@ -20,6 +20,7 @@ package values
import (
"encoding/xml"
+ "fmt"
"time"
)
@@ -42,6 +43,14 @@ func (m PlcLTIME) GetDuration() time.Duration {
return time.Duration(m.value)
}
+func (m PlcLTIME) IsString() bool {
+ return true
+}
+
+func (m PlcLTIME) GetString() string {
+ return fmt.Sprintf("PT%0.fS", m.GetDuration().Seconds())
+}
+
func (m PlcLTIME) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if err := e.EncodeElement(m.value, xml.StartElement{Name: xml.Name{Local: "PlcLTIME"}}); err != nil {
return err
diff --git a/plc4go/internal/plc4go/spi/values/PlcBitString.go b/plc4go/internal/plc4go/spi/values/PlcBitString.go
index ecb5503..a18a602 100644
--- a/plc4go/internal/plc4go/spi/values/PlcBitString.go
+++ b/plc4go/internal/plc4go/spi/values/PlcBitString.go
@@ -34,22 +34,22 @@ func NewPlcBitString(value interface{}) PlcBitString {
case uint8:
bools = make([]api.PlcValue, 8)
for i := 0; i < 8; i++ {
- bools[0] = NewPlcBOOL(((value.(uint8) >> uint8((8-1)-i)) & 0x01) == 0x01)
+ bools[i] = NewPlcBOOL(((value.(uint8) >> uint8((8-1)-i)) & 0x01) == 0x01)
}
case uint16:
bools = make([]api.PlcValue, 16)
for i := 0; i < 16; i++ {
- bools[0] = NewPlcBOOL(((value.(uint16) >> uint8((16-1)-i)) & 0x01) == 0x01)
+ bools[i] = NewPlcBOOL(((value.(uint16) >> uint8((16-1)-i)) & 0x01) == 0x01)
}
case uint32:
bools = make([]api.PlcValue, 32)
for i := 0; i < 32; i++ {
- bools[0] = NewPlcBOOL(((value.(uint32) >> uint8((32-1)-i)) & 0x01) == 0x01)
+ bools[i] = NewPlcBOOL(((value.(uint32) >> uint8((32-1)-i)) & 0x01) == 0x01)
}
case uint64:
bools = make([]api.PlcValue, 64)
for i := 0; i < 64; i++ {
- bools[0] = NewPlcBOOL(((value.(uint64) >> uint8((64-1)-i)) & 0x01) == 0x01)
+ bools[i] = NewPlcBOOL(((value.(uint64) >> uint8((64-1)-i)) & 0x01) == 0x01)
}
}
diff --git a/plc4go/internal/plc4go/spi/values/PlcValueAdapter.go b/plc4go/internal/plc4go/spi/values/PlcValueAdapter.go
index 89da493..a19916b 100644
--- a/plc4go/internal/plc4go/spi/values/PlcValueAdapter.go
+++ b/plc4go/internal/plc4go/spi/values/PlcValueAdapter.go
@@ -25,7 +25,6 @@ import (
// Dummy structure
type PlcValueAdapter struct {
- api.PlcValue
}
// Simple Types
@@ -158,13 +157,10 @@ func (m PlcValueAdapter) GetLength() uint32 {
return 1
}
func (m PlcValueAdapter) GetIndex(i uint32) api.PlcValue {
- if i == 0 {
- return m
- }
return nil
}
func (m PlcValueAdapter) GetList() []api.PlcValue {
- return []api.PlcValue{m}
+ return []api.PlcValue{}
}
// Struct Methods
@@ -183,3 +179,15 @@ func (m PlcValueAdapter) GetValue(key string) api.PlcValue {
func (m PlcValueAdapter) GetStruct() map[string]api.PlcValue {
return nil
}
+func (m PlcValueAdapter) IsDate() bool {
+ return false
+}
+func (m PlcValueAdapter) GetDate() time.Time {
+ return time.Time{}
+}
+func (m PlcValueAdapter) IsDateTime() bool {
+ return false
+}
+func (m PlcValueAdapter) GetDateTime() time.Time {
+ return time.Time{}
+}
diff --git a/plc4go/internal/plc4go/spi/values/TIME.go b/plc4go/internal/plc4go/spi/values/TIME.go
index 38c54c6..a472e54 100644
--- a/plc4go/internal/plc4go/spi/values/TIME.go
+++ b/plc4go/internal/plc4go/spi/values/TIME.go
@@ -20,6 +20,7 @@ package values
import (
"encoding/xml"
+ "fmt"
"time"
)
@@ -42,6 +43,14 @@ func (m PlcTIME) GetDuration() time.Duration {
return time.Duration(m.value)
}
+func (m PlcTIME) IsString() bool {
+ return true
+}
+
+func (m PlcTIME) GetString() string {
+ return fmt.Sprintf("PT%0.fS", m.GetDuration().Seconds())
+}
+
func (m PlcTIME) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if err := e.EncodeElement(m.value, xml.StartElement{Name: xml.Name{Local: "PlcTIME"}}); err != nil {
return err
diff --git a/plc4go/internal/plc4go/spi/values/TIME_OF_DAY.go b/plc4go/internal/plc4go/spi/values/TIME_OF_DAY.go
index 6d7b0d6..f6ba42b 100644
--- a/plc4go/internal/plc4go/spi/values/TIME_OF_DAY.go
+++ b/plc4go/internal/plc4go/spi/values/TIME_OF_DAY.go
@@ -58,6 +58,10 @@ func (m PlcTIME_OF_DAY) GetTime() time.Time {
return m.value
}
+func (m PlcTIME_OF_DAY) GetString() string {
+ return m.value.Format("15:04:05.000")
+}
+
func (m PlcTIME_OF_DAY) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if err := e.EncodeElement(m.value, xml.StartElement{Name: xml.Name{Local: "PlcTIME_OF_DAY"}}); err != nil {
return err
diff --git a/plc4go/pkg/plc4go/values/plc_value.go b/plc4go/pkg/plc4go/values/plc_value.go
index d741909..bdbb10e 100644
--- a/plc4go/pkg/plc4go/values/plc_value.go
+++ b/plc4go/pkg/plc4go/values/plc_value.go
@@ -66,9 +66,9 @@ type PlcValue interface {
IsTime() bool
GetTime() time.Time
IsDate() bool
- GetDate()
+ GetDate() time.Time
IsDateTime() bool
- GetDateTime()
+ GetDateTime() time.Time
// Raw Access
GetRaw() []byte