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

Added support for FC43/14 #40

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,12 @@ type Client interface {
//ReadFIFOQueue reads the contents of a First-In-First-Out (FIFO) queue
// of register in a remote device and returns FIFO value register.
ReadFIFOQueue(address uint16) (results []byte, err error)

// MEI functions

// ReadDeviceIdentification reads all the Basic and Regular identification strings
// from the device. If firstExtendedID is >= 0x80, it will also read the Extended strings,
// starting from the specified one.
// It returns a map with the retrieved strings.
ReadDeviceIdentification(firstExtendedID byte) (results map[byte]string, err error)
}
126 changes: 126 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,132 @@ func (mb *client) ReadFIFOQueue(address uint16) (results []byte, err error) {
return
}

// Request:
// Function code : 1 byte (0x2B)
// MEI type : 1 byte (0x0E)
// Read Device ID Code : 1 byte
// Object ID : 1 byte
// Response:
// Function code : 1 byte (0x2B)
// MEI type : 1 byte (0x0E)
// Read Device ID Code : 1 byte
// Conformity level : 1 byte
// More follows : 1 byte
// Next object ID : 1 byte
// Number of objects : 1 byte
// List of objects : <Number of objects>
// Object ID : 1
// Object length : 1
// Object value : <Object length> bytes
func (mb *client) ReadDeviceIdentification(firstExtendedID byte) (results map[byte]string, err error) {
readDevIDCode := byte(0x01)
objectID := byte(0x00)
conformityLevel := byte(0x00)

objects := make(map[byte]string)
results = make(map[byte]string)

// Getting basic objects (mandatory)
for {
conformityLevel, objectID, objects, err =
mb.sendReadDeviceIdentification(readDevIDCode, objectID)
if err != nil {
return results, err
}

for k, v := range objects {
results[k] = v
}

if len(results) >= 3 {
break
} else {
if objectID == 0x00 {
err := fmt.Errorf("modbus: mandatory device identification objects are not available")
return results, err
}
}
}

// Getting regular and extended objects, if supported and requested by the user
for {
if (readDevIDCode == 0x01) && (conformityLevel&0x02) >= 0x02 {
readDevIDCode = 0x02
objectID = 0x00
} else if (readDevIDCode == 0x02) && (conformityLevel&0x03) == 0x03 && firstExtendedID >= 0x80 {
readDevIDCode = 0x03
objectID = firstExtendedID
} else {
break
}

for {
_, objectID, objects, err =
mb.sendReadDeviceIdentification(readDevIDCode, objectID)
if err != nil {
return results, err
}

for k, v := range objects {
results[k] = v
}

if objectID == 0x00 {
break
}
}
}

return
}

// sendReadDeviceIdentification sends a FC43/14 request and returns the reponse after some basic checks
func (mb *client) sendReadDeviceIdentification(readDeviceIDCode byte, objectID byte) (
conformityLevel byte, nextObjID byte, objects map[byte]string, err error) {

objects = make(map[byte]string)

reqData := make([]byte, 3)
reqData[0] = MEITypeReadDeviceIdentification
reqData[1] = readDeviceIDCode
reqData[2] = objectID

request := ProtocolDataUnit{
FunctionCode: FuncCodeMEI,
Data: reqData,
}

response, err := mb.send(&request)
if err != nil {
return
}

conformityLevel = response.Data[2]
if !((conformityLevel >= 0x01 && conformityLevel <= 0x03) ||
(conformityLevel >= 0x81 && conformityLevel <= 0x83)) {
err = fmt.Errorf("modbus: response conformitiy level '%v' is not valid", conformityLevel)
return
}

moreFollows := response.Data[3]
if moreFollows == 0xFF {
nextObjID = response.Data[4]
}

count := response.Data[5]
index := 6
for i := byte(0); i < count; i++ {
id := response.Data[index]
length := int(response.Data[index+1])
value := response.Data[index+2 : index+2+length]

objects[id] = string(value)
index += 2 + length
}

return
}

// Helpers

// send sends request and checks possible exception in the response.
Expand Down
4 changes: 4 additions & 0 deletions modbus.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ const (
FuncCodeReadWriteMultipleRegisters = 23
FuncCodeMaskWriteRegister = 22
FuncCodeReadFIFOQueue = 24

//MEI
FuncCodeMEI = 43
MEITypeReadDeviceIdentification = 14
)

const (
Expand Down