def HandleRequest(self, ReceivedData): """ Convert a Modbus server request message into a Modbus server reply message. ReceivedData - Binary string with raw request message. Returns - Binary string with completed raw reply message. If a server error occurs, an empty string will be returned instead. This method handles Modbus protocol functions 1, 2, 3, 4, 5, 6, 15, and 16. """ # Decode message. 'RequestData' may mean either number of coils or sent data, depending # upon the function code being received. For functions 15 and 16, it is a tuple containing # data and quantity. try: TransID, UnitID, FunctionCode, Start, Qty, RequestData, ExceptionCode = \ self._MBServerMsg.MBRequest(ReceivedData) except: # Something is wrong with the message, and we can't decode it. TransID = 0 UnitID = 0 FunctionCode = 0 Start = 0 Qty = 0 RequestData = 0 ExceptionCode = 0 try: # Read coils. RequestData = quantity. if FunctionCode == 1: MsgData = MBDataTable.MemMap.GetCoils(Start, Qty) ReplyData = self._MBServerMsg.MBResponse(TransID, UnitID, FunctionCode, Start, MsgData) # Read discrete inputs. RequestData = quantity. elif FunctionCode == 2: MsgData = MBDataTable.MemMap.GetDiscreteInputs(Start, Qty) ReplyData = self._MBServerMsg.MBResponse(TransID, UnitID, FunctionCode, Start, MsgData) # Read holding registers. RequestData = quantity. elif FunctionCode == 3: # Get the expanded address. if self._ExpAddressing: try: dtstart = self._DTOffsets[UnitID] + Start except: raise ExpDTError, self._ExpDTError else: dtstart = Start MsgData = MBDataTable.MemMap.GetHoldingRegisters(dtstart, Qty) ReplyData = self._MBServerMsg.MBResponse(TransID, UnitID, FunctionCode, Start, MsgData) # Read input registers. RequestData = quantity. elif FunctionCode == 4: MsgData = MBDataTable.MemMap.GetInputRegisters(Start, Qty) ReplyData = self._MBServerMsg.MBResponse(TransID, UnitID, FunctionCode, Start, MsgData) # Write single coil. RequestData contains data. elif FunctionCode == 5: MBDataTable.MemMap.SetCoils(Start, 1, RequestData) ReplyData = self._MBServerMsg.MBResponse(TransID, UnitID, FunctionCode, Start, RequestData) # Write single holding register. RequestData contains data. elif FunctionCode == 6: # Get the expanded register maps. if self._ExpAddressing: try: dtstart = self._DTOffsets[UnitID] + Start except: raise ExpDTError, self._ExpDTError else: dtstart = Start MBDataTable.MemMap.SetHoldingRegisters(dtstart, 1, RequestData) ReplyData = self._MBServerMsg.MBResponse(TransID, UnitID, FunctionCode, Start, RequestData) # Write multiple coils. RequestData is a tuple. elif FunctionCode == 15: MBDataTable.MemMap.SetCoils(Start, Qty, RequestData) ReplyData = self._MBServerMsg.MBResponse(TransID, UnitID, FunctionCode, \ Start, ModbusDataLib.Int2BinStr(Qty)) # Write multiple holding registers. RequestData is a tuple. elif FunctionCode == 16: # Get the expanded register maps. if self._ExpAddressing: try: dtstart = self._DTOffsets[UnitID] + Start except: raise ExpDTError, self._ExpDTError else: dtstart = Start MBDataTable.MemMap.SetHoldingRegisters(dtstart, Qty, RequestData) ReplyData = self._MBServerMsg.MBResponse(TransID, UnitID, FunctionCode, \ Start, ModbusDataLib.Int2BinStr(Qty)) # Modbus exception. elif FunctionCode > 127: ReplyData = self._MBServerMsg.MBErrorResponse(TransID, UnitID, FunctionCode, ExceptionCode) # Something is wrong here and we don't understand the message. else: ReplyData = self._MBServerMsg.MBErrorResponse(TransID, UnitID, FunctionCode + 128, 1) # Extended addressing errors. except ExpDTError: # Modbus exception 2. The extended UID is not known. ReplyData = self._MBServerMsg.MBErrorResponse(TransID, UnitID, FunctionCode + 128, 2) except: # Modbus exception 4. An error has occured in reading or writing a memory location. ReplyData = self._MBServerMsg.MBErrorResponse(TransID, UnitID, FunctionCode + 128, 4) # Return the result. return ReplyData
def handle_read(self): try: ReceivedData = self.recv(8192) except: ReceivedData = None if ReceivedData: # Decode message. 'RequestData' may mean either number of coils or sent data, depending # upon the function code being received. For functions 15 and 16, it is a tuple containing # data and quantity. try: TransID, UnitID, FunctionCode, Start, Qty, RequestData, ExceptionCode = \ MBServerMSg.MBRequest(ReceivedData) # We can't decode this message at all, so just drop the request and stop here. # Can't decode the message, because the length is invalid. except ModbusTCPLib.MessageLengthError: print('Server %d - Invalid message length. %s' % (CmdOpts.GetFieldPort(), time.ctime())) TransID, UnitID, FunctionCode, Start, Qty, RequestData, ExceptionCode = self._GetDefaultData( ) except: TransID, UnitID, FunctionCode, Start, Qty, RequestData, ExceptionCode = self._GetDefaultData( ) # Log the incoming messages for reporting purposes. StatusReporter.Report.AddFieldRequest(ModbusStatusReportMsg.ModbusServerFieldRequest(TransID, \ UnitID, FunctionCode, Start, Qty, RequestData)) ReplyData = '' MsgData = [0] # Decode messages. If we get an error in reading/writing memory or in constructing messages, # we will consider this to be a Modbus exception. try: if FunctionCode == 1: # Read coils. MsgData = MemMap.GetCoils(Start, Qty) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, Start, MsgData) elif FunctionCode == 2: # Read discrete inputs. MsgData = MemMap.GetDiscreteInputs(Start, Qty) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, Start, MsgData) elif FunctionCode == 3: # Read holding registers. MsgData = MemMap.GetHoldingRegisters(Start, Qty) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, Start, MsgData) elif FunctionCode == 4: # Read input registers. MsgData = MemMap.GetInputRegisters(Start, Qty) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, Start, MsgData) elif FunctionCode == 5: # Write single coil. RequestData contains data. MemMap.SetCoils(Start, 1, RequestData) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, Start, RequestData) elif FunctionCode == 6: # Write single holding register. RequestData contains data. MemMap.SetHoldingRegisters(Start, 1, RequestData) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, Start, RequestData) elif FunctionCode == 15: # Write multiple coils. MemMap.SetCoils(Start, Qty, RequestData) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, \ Start, ModbusDataLib.Int2BinStr(Qty)) elif FunctionCode == 16: # Write multiple holding registers. MemMap.SetHoldingRegisters(Start, Qty, RequestData) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, \ Start, ModbusDataLib.Int2BinStr(Qty)) elif FunctionCode > 127: # Modbus exception. ReplyData = MBServerMSg.MBErrorResponse( TransID, UnitID, FunctionCode, ExceptionCode) else: print('Server %d - Unsupported function call' % CmdOpts.GetFieldPort()) ReplyData = MBServerMSg.MBErrorResponse( TransID, UnitID, FunctionCode + 128, 1) except: # Modbus exception 4. An error has occured in reading or writing a memory location. ReplyData = MBServerMSg.MBErrorResponse( TransID, UnitID, FunctionCode + 128, 4) # Send the reply. try: self.send(ReplyData) except: # If we have an error here, there's not much we can do about it. print('Server %d - Could not reply to request.' % CmdOpts.GetFieldPort()) # Log the response messages for reporting purposes. StatusReporter.Report.AddFieldResponse(ModbusStatusReportMsg.ModbusServerFieldResponse(TransID, \ FunctionCode, MsgData, RequestData, Qty, ExceptionCode)) else: self.close()