Repository: edgexfoundry/device-sdk-go (go)

Issue:
Add eNotation and Base64 formatting for float* types
Using the example simpledriver in the device-service-go, I am able to use all the NewXValue methods to submit the various types of data except floats.  When I use the two NewFloatXValue methods, the values are somehow being binary encoded to that what gets submitted is a random string (examp;e:  "value":"PqRObw==")

Pull request:
 Make float encoding according to PropertyValue 
The float value of reading was base64 encoding only.
This commit makes it configurable by PropertyValue.
fix #107

Add new fields when careating ValueDescriptor

Patch:
diff --git a/async.go b/async.go
index a497effd..ff094c8e 100644
--- a/async.go
+++ b/async.go
@@ -69,7 +69,7 @@ func processAsyncResults() {
 				}
 			}
 
-			reading := common.CommandValueToReading(cv)
+			reading := common.CommandValueToReading(cv, device.Name, dr.Properties.Value.FloatEncoding)
 			readings = append(readings, *reading)
 		}
 
diff --git a/internal/common/utils.go b/internal/common/utils.go
index 82ef8b3f..46441f0e 100644
--- a/internal/common/utils.go
+++ b/internal/common/utils.go
@@ -31,12 +31,12 @@ func BuildAddr(host string, port string) string {
 	return buffer.String()
 }
 
-func CommandValueToReading(cv *dsModels.CommandValue) *contract.Reading {
-	reading := &contract.Reading{Name: cv.DeviceResourceName}
+func CommandValueToReading(cv *dsModels.CommandValue, devName string, encoding string) *contract.Reading {
+	reading := &contract.Reading{Name: cv.DeviceResourceName, Device: devName}
 	if cv.Type == dsModels.Binary {
 		reading.BinaryValue = cv.BinValue
 	} else {
-		reading.Value = cv.ValueToString()
+		reading.Value = cv.ValueToString(encoding)
 	}
 
 	// if value has a non-zero Origin, use it
diff --git a/internal/handler/command.go b/internal/handler/command.go
index 7fc29ba8..4d09dd54 100644
--- a/internal/handler/command.go
+++ b/internal/handler/command.go
@@ -170,7 +170,7 @@ func execReadCmd(device *contract.Device, cmd string) (*dsModels.Event, common.A
 		// been implemened in gxds. TBD at the devices f2f whether this
 		// be killed completely.
 
-		reading := common.CommandValueToReading(cv)
+		reading := common.CommandValueToReading(cv, device.Name, dr.Properties.Value.FloatEncoding)
 		readings = append(readings, *reading)
 
 		common.LoggingClient.Debug(fmt.Sprintf("Handler - execReadCmd: device: %s DeviceResource: %v reading: %v", device.Name, cv.DeviceResourceName, reading))
diff --git a/internal/provision/profiles.go b/internal/provision/profiles.go
index 1257591b..f540231e 100644
--- a/internal/provision/profiles.go
+++ b/internal/provision/profiles.go
@@ -142,14 +142,16 @@ func createDescriptor(name string, dr contract.DeviceResource) (*contract.ValueD
 	common.LoggingClient.Debug(fmt.Sprintf("ps: createDescriptor: %s, value: %v, units: %v", name, value, units))
 
 	desc := &contract.ValueDescriptor{
-		Name:         name,
-		Min:          value.Minimum,
-		Max:          value.Maximum,
-		Type:         value.Type,
-		UomLabel:     units.DefaultValue,
-		DefaultValue: value.DefaultValue,
-		Formatting:   "%s",
-		Description:  dr.Description,
+		Name:          name,
+		Min:           value.Minimum,
+		Max:           value.Maximum,
+		Type:          value.Type,
+		UomLabel:      units.DefaultValue,
+		DefaultValue:  value.DefaultValue,
+		Formatting:    "%s",
+		Description:   dr.Description,
+		FloatEncoding: value.FloatEncoding,
+		MediaType:     value.MediaType,
 	}
 
 	ctx := context.WithValue(context.Background(), common.CorrelationHeader, uuid.New().String())
diff --git a/pkg/models/commandvalue.go b/pkg/models/commandvalue.go
index 122c6805..bddb28e7 100644
--- a/pkg/models/commandvalue.go
+++ b/pkg/models/commandvalue.go
@@ -1,7 +1,7 @@
 // -*- Mode: Go; indent-tabs-mode: t -*-
 //
 // Copyright (C) 2018 Canonical Ltd
-// Copyright (C) 2018 IOTech Ltd
+// Copyright (C) 2018-2019 IOTech Ltd
 //
 // SPDX-License-Identifier: Apache-2.0
 
@@ -17,6 +17,7 @@ import (
 	"strconv"
 	"strings"
 
+	contract "github.com/edgexfoundry/go-mod-core-contracts/models"
 	"github.com/ugorji/go/codec"
 )
 
@@ -70,6 +71,9 @@ const (
 	// Policy limits should be located in global config namespace
 	// Currently assigning 16MB (binary), 16 * 2^20 bytes
 	MaxBinaryBytes = 16777216
+	// DefaultFoloatEncoding indicates the representation of floating value of reading.
+	// It would be configurable in system level in the future
+	DefaultFloatEncoding = contract.Base64Encoding
 )
 
 // ParseValueType could get ValueType from type name in string format
@@ -253,7 +257,7 @@ func decodeValue(reader io.Reader, value interface{}) error {
 }
 
 //ValueToString returns the string format of the value
-func (cv *CommandValue) ValueToString() (str string) {
+func (cv *CommandValue) ValueToString(encoding ...string) (str string) {
 	if cv.Type == String {
 		str = cv.stringValue
 		return
@@ -326,15 +330,25 @@ func (cv *CommandValue) ValueToString() (str string) {
 		}
 		str = strconv.FormatInt(res, 10)
 	case Float32:
-		//var res float32
-		//binary.Read(reader, binary.BigEndian, &res)
-		//str = strconv.FormatFloat(float64(res), 'f', -1, 32)
-		str = base64.StdEncoding.EncodeToString(cv.NumericValue)
+		floatEncoding := getFloatEncoding(encoding)
+
+		if floatEncoding == contract.ENotation {
+			var res float32
+			binary.Read(reader, binary.BigEndian, &res)
+			str = fmt.Sprintf("%e", res)
+		} else if floatEncoding == contract.Base64Encoding {
+			str = base64.StdEncoding.EncodeToString(cv.NumericValue)
+		}
 	case Float64:
-		//var res float64
-		//binary.Read(reader, binary.BigEndian, &res)
-		//str = strconv.FormatFloat(res, 'f', -1, 64)
-		str = base64.StdEncoding.EncodeToString(cv.NumericValue)
+		floatEncoding := getFloatEncoding(encoding)
+
+		if floatEncoding == contract.ENotation {
+			var res float64
+			binary.Read(reader, binary.BigEndian, &res)
+			str = fmt.Sprintf("%e", res)
+		} else if floatEncoding == contract.Base64Encoding {
+			str = base64.StdEncoding.EncodeToString(cv.NumericValue)
+		}
 	case Binary:
 		// produce string representation of first 20 bytes of binary value
 		str = fmt.Sprintf(fmt.Sprintf("Binary: [%v...]", string(cv.BinValue[:20])))
@@ -343,6 +357,18 @@ func (cv *CommandValue) ValueToString() (str string) {
 	return
 }
 
+func getFloatEncoding(encoding []string) string {
+	if len(encoding) > 0 {
+		if encoding[0] == contract.Base64Encoding {
+			return contract.Base64Encoding
+		} else if encoding[0] == contract.ENotation {
+			return contract.ENotation
+		}
+	}
+
+	return DefaultFloatEncoding
+}
+
 // String returns a string representation of a CommandValue instance.
 func (cv *CommandValue) String() (str string) {
 


Test patch:
diff --git a/pkg/models/commandvalue_test.go b/pkg/models/commandvalue_test.go
index 6d6331ca..48cef0e4 100644
--- a/pkg/models/commandvalue_test.go
+++ b/pkg/models/commandvalue_test.go
@@ -14,6 +14,8 @@ import (
 	"math"
 	"testing"
 	"time"
+
+	contract "github.com/edgexfoundry/go-mod-core-contracts/models"
 )
 
 // Test NewBoolValue function.
@@ -490,7 +492,7 @@ func TestNewFloat32Value(t *testing.T) {
 	if v != value {
 		t.Errorf("NewFloat32Value: float32 value is incorrect")
 	}
-	if cv.ValueToString() != "AAAAAQ==" {
+	if cv.ValueToString(contract.Base64Encoding) != "AAAAAQ==" {
 		t.Errorf("NewFloat32Value #1: invalid reading Value: %s", cv.ValueToString())
 	}
 
@@ -512,7 +514,7 @@ func TestNewFloat32Value(t *testing.T) {
 	if v != value {
 		t.Errorf("NewFloat32Value: float32 value is incorrect")
 	}
-	if cv.ValueToString() != "f3///w==" {
+	if cv.ValueToString(contract.Base64Encoding) != "f3///w==" {
 		t.Errorf("NewFloat32Value #2: invalid reading Value: %s", cv.ValueToString())
 	}
 }
@@ -541,7 +543,7 @@ func TestNewFloat64Value(t *testing.T) {
 	if v != value {
 		t.Errorf("NewFloat64Value: float64 value is incorrect")
 	}
-	if cv.ValueToString() != "AAAAAAAAAAE=" {
+	if cv.ValueToString(contract.Base64Encoding) != "AAAAAAAAAAE=" {
 		t.Errorf("NewFloat64Value #1: invalid reading Value: %s", cv.ValueToString())
 	}
 
@@ -563,7 +565,7 @@ func TestNewFloat64Value(t *testing.T) {
 	if v != value {
 		t.Errorf("NewFloat64Value: float64 value is incorrect")
 	}
-	if cv.ValueToString() != "f+////////8=" {
+	if cv.ValueToString(contract.Base64Encoding) != "f+////////8=" {
 		t.Errorf("NewFloat64Value #2: invalid reading Value: %s", cv.ValueToString())
 	}
 }