Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: supply string type #262

Merged
merged 9 commits into from
Aug 3, 2021
19 changes: 19 additions & 0 deletions cmd/res/devices/modbus.test.devices.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,22 @@
UnitID = '1'
Timeout = "5"
IdleTimeout = "5"

# Pre-define Devices
[[DeviceList]]
Name = 'Modbus-TCP-Read-String'
ProfileName = 'Test-Device-Modbus-String-Profile'
Description = 'use for auto read a string value'
labels = [ 'modbus TCP' ]
[DeviceList.Protocols]
[DeviceList.Protocols.modbus-tcp]
Address = '0.0.0.0'
Port = '1502'
UnitID = '1'
Timeout = '5'
IdleTimeout = '5'
[[DeviceList.AutoEvents]]
Interval = '20s'
OnChange = false
SourceName = 'ReadString'

41 changes: 41 additions & 0 deletions cmd/res/profiles/modbus.test.device.string.profile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: "Test-Device-Modbus-String-Profile"
manufacturer: "no manufacturer"
model: "string value type"
labels:
- "no lable"
description: "this profile is testing string value type with read and write"

deviceResources:
-
name: "StringA"
description: "no description"
attributes:
{ primaryTable: "INPUT_REGISTERS", startingAddress: 1, stringRegisterSize: 1}
properties:
valueType: "String"
readWrite: "R"

-
name: "StringB"
description: "no description"
attributes:
{ primaryTable: "HOLDING_REGISTERS", startingAddress: 15, stringRegisterSize: 5}
properties:
valueType: "String"
readWrite: "RW"



deviceCommands:
-
name: "ReadString"
readWrite: "R"
isHidden: false
resourceOperations:
- { deviceResource: "StringA"}
-
name: "WriteString"
readWrite: "RW"
isHidden: false
resourceOperations:
- { deviceResource: "StringB" }
5 changes: 4 additions & 1 deletion internal/driver/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ const (
// RAW_TYPE define binary data type which read from Modbus device
RAW_TYPE = "rawType"

// STRING_REGISTER_SIZE E.g. "abcd" need 4 bytes as is 2 registers(2 words), so STRING_REGISTER_SIZE=2
STRING_REGISTER_SIZE = "stringRegisterSize"
SERVICE_STOP_WAIT_TIME = 1
)

Expand All @@ -58,5 +60,6 @@ var ValueTypeBitCountMap = map[string]uint16{
common.ValueTypeFloat32: 32,
common.ValueTypeFloat64: 64,

common.ValueTypeBool: 1,
common.ValueTypeBool: 1,
common.ValueTypeString: 16,
}
48 changes: 38 additions & 10 deletions internal/driver/deviceclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,17 @@ func createCommandInfo(req *models.CommandRequest) (*CommandInfo, error) {
return nil, err
}
}
length := calculateAddressLength(primaryTable, rawType)
var length uint16
if req.Type == common.ValueTypeString {
length, err = castStartingAddress(req.Attributes[STRING_REGISTER_SIZE])
if err != nil {
return nil, err
} else if (length > 123) || (length < 1) {
return nil, errors.NewCommonEdgeX(errors.KindLimitExceeded, fmt.Sprintf("register size should be within the range of 1~123, get %v.", length), nil)
}
} else {
length = calculateAddressLength(primaryTable, rawType)
}

var isByteSwap = false
if _, ok := req.Attributes[IS_BYTE_SWAP]; ok {
Expand Down Expand Up @@ -157,6 +167,8 @@ func TransformDataBytesToResult(req *models.CommandRequest, dataBytes []byte, co
if (dataBytes[0] & 1) > 0 {
res = true
}
case common.ValueTypeString:
res = string(bytes.Trim(dataBytes, string(rune(0))))
default:
return nil, fmt.Errorf("return result fail, none supported value type: %v", commandInfo.ValueType)
}
Expand All @@ -175,15 +187,18 @@ func TransformDataBytesToResult(req *models.CommandRequest, dataBytes []byte, co
func TransformCommandValueToDataBytes(commandInfo *CommandInfo, value *models.CommandValue) ([]byte, error) {
var err error
var byteCount = calculateByteCount(commandInfo)
var dataBytes []byte
buf := new(bytes.Buffer)
err = binary.Write(buf, binary.BigEndian, value.Value)
if err != nil {
return nil, fmt.Errorf("failed to transform %v to []byte", value.Value)
}
if commandInfo.ValueType != common.ValueTypeString {
err = binary.Write(buf, binary.BigEndian, value.Value)
if err != nil {
return nil, fmt.Errorf("failed to transform %v to []byte", value.Value)
}

numericValue := buf.Bytes()
var maxSize = uint16(len(numericValue))
var dataBytes = numericValue[maxSize-byteCount : maxSize]
numericValue := buf.Bytes()
var maxSize = uint16(len(numericValue))
dataBytes = numericValue[maxSize-byteCount : maxSize]
}

_, ok := ValueTypeBitCountMap[commandInfo.ValueType]
if !ok {
Expand All @@ -195,7 +210,7 @@ func TransformCommandValueToDataBytes(commandInfo *CommandInfo, value *models.Co
dataBytes = swap32BitDataBytes(dataBytes, commandInfo.IsByteSwap, commandInfo.IsWordSwap)
}

// Cast value according to the rawType, this feature only converts float value to integer 32bit value
// Cast value according to the rawType, this feature converts float value to integer 32bit value
if commandInfo.ValueType == common.ValueTypeFloat32 {
val, edgexErr := value.Float32Value()
if edgexErr != nil {
Expand Down Expand Up @@ -228,8 +243,21 @@ func TransformCommandValueToDataBytes(commandInfo *CommandInfo, value *models.Co
return dataBytes, err
}
}
} else if commandInfo.ValueType == common.ValueTypeString {
// Cast value of string type
oriStr := value.ValueToString()
tempBytes := []byte(oriStr)
bytesL := len(tempBytes)
oriByteL := int(commandInfo.Length * 2)
if bytesL < oriByteL {
less := make([]byte, oriByteL-bytesL)
dataBytes = append(tempBytes, less...)
} else if bytesL > oriByteL {
dataBytes = tempBytes[:oriByteL]
} else {
dataBytes = []byte(oriStr)
}
}

driver.Logger.Debugf("Transfer CommandValue to dataBytes for write command, %v, %v", commandInfo.ValueType, dataBytes)
return dataBytes, err
}
Expand Down