def __init__(self, host, port, timeout, stnaddr=1): """ host (string) = IP address of server. port (integer) = Port for server. timeout (float) = Time out in seconds. stnaddr (integer) = The desired SBus station address. """ self._host = host self._port = port self._timeout = timeout self._stnaddr = stnaddr self._msgsequence = 1 # Define the boolean values for 0 and 1. self._bitoff = ModbusDataStrLib.boollist2bin( [False, False, False, False, False, False, False, False]) self._biton = ModbusDataStrLib.boollist2bin( [True, False, False, False, False, False, False, False]) # Initialise the client connection. try: self._msg = SBusSimpleClient.SBusSimpleClient( self._host, self._port, self._timeout) except: self._msg = None print((_ErrorMsgs['connnecterror'])) # Raise the exception again so the next layer can deal with it. raise
def _handle(self): ReceivedData = self.rfile.read() if ReceivedData: # Decode message. try: (TelegramAttr, MsgSequence, StnAddr, CmdCode, DataAddr, DataCount, MsgData, MsgResult) = SBServerMsg.SBRequest(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 SBusMsg.MessageLengthError: print('Server %d - Invalid message length. %s' % (CmdOpts.GetPort(), time.ctime())) MsgResult = False MsgSequence = 0 # Message had a CRC error. except SBusMsg.CRCError: print('Server %d - Bad CRC. %s' % (CmdOpts.GetPort(), time.ctime())) MsgResult = False MsgSequence = 0 # All other errors. except: print('Server %d - Request could not be decoded. %s' % (CmdOpts.GetPort(), time.ctime())) MsgResult = False MsgSequence = 0 ReplyData = '' # Handle the command, but only if know the parameters are valid. if (MsgResult): # Decode messages. If we get an error in reading/writing memory or # in constructing messages, we will consider this to be an SBus error. try: # Read Flags. if CmdCode == 2: MemData = MemMap.GetFlags(DataAddr, DataCount) MsgData = ModbusDataStrLib.boollist2bin(MemData) ReplyData = SBServerMsg.SBResponse( MsgSequence, CmdCode, 0, MsgData) # Read Inputs elif CmdCode == 3: MemData = MemMap.GetInputs(DataAddr, DataCount) MsgData = ModbusDataStrLib.boollist2bin(MemData) ReplyData = SBServerMsg.SBResponse( MsgSequence, CmdCode, 0, MsgData) # Read Outputs elif CmdCode == 5: MemData = MemMap.GetOutputs(DataAddr, DataCount) MsgData = ModbusDataStrLib.boollist2bin(MemData) ReplyData = SBServerMsg.SBResponse( MsgSequence, CmdCode, 0, MsgData) # Read Registers elif CmdCode == 6: MemData = MemMap.GetRegisters(DataAddr, DataCount) MsgData = SBusMsg.signedint32list2bin(MemData) ReplyData = SBServerMsg.SBResponse( MsgSequence, CmdCode, 0, MsgData) # Write flags elif CmdCode == 11: MemData = ModbusDataStrLib.bin2boollist(MsgData) MemMap.SetFlags(DataAddr, DataCount, MemData) ReplyData = SBServerMsg.SBResponse( MsgSequence, CmdCode, 0, '') # Write outputs elif CmdCode == 13: MemData = ModbusDataStrLib.bin2boollist(MsgData) MemMap.SetOutputs(DataAddr, DataCount, MemData) ReplyData = SBServerMsg.SBResponse( MsgSequence, CmdCode, 0, '') # Write Registers elif CmdCode == 14: MemData = SBusMsg.signedbin2int32list(MsgData) MemMap.SetRegisters(DataAddr, DataCount, MemData) ReplyData = SBServerMsg.SBResponse( MsgSequence, CmdCode, 0, '') # We don't understand this command code. else: print('Server %d - Unsupported command code' % CmdOpts.GetPort()) ReplyData = SBServerMsg.SBErrorResponse(MsgSequence) # We don't understand this message. except: ReplyData = SBServerMsg.SBErrorResponse(MsgSequence) # The message was bad, so we return a NAK response. else: ReplyData = SBServerMsg.SBErrorResponse(MsgSequence) # Send the reply. try: self.wfile.write(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. %s' % (CmdOpts.GetPort(), time.ctime()))
def Request(self, cmdcode, dataaddr, data=None): """Read data from an address. Parameters: cmdcode (integer) = SBus command code. dataaddr (integer) = SBus address. data (integer) = Data to be written (optional). Returns: (tuple) = If OK, returns True plus the received data. If error, returns False plus an error message. """ # Increment the transaction id. self._IncMsgSeq() # Only request one at a time. datacount = 1 sendata = None # Only the following command codes are supported. if (cmdcode not in [2, 3, 5, 6, 11, 13, 14]): return False, _ErrorMsgs['badcmdcode'] # Check if the SBus address is legal. This does not guaranty though # that it will be supported in the field device. if (dataaddr < 0) or (dataaddr > 65535): return False, _ErrorMsgs['invalidaddress'] # If we are writing data, make sure it is valid. if cmdcode in [11, 13, 14]: try: dataint = int(data) except: return False, _ErrorMsgs['dataerr'] # For writing data, convert the data to a binary string, # and check if it is within range for that function. if (cmdcode in (11, 13)): if (dataint == 0): sendata = self._bitoff elif (dataint == 1): sendata = self._biton else: return False, _ErrorMsgs['dataerr'] elif (cmdcode == 14): if ((dataint >= -2147483648) and (dataint <= 2147483647)): sendata = SBusMsg.signedint32list2bin([data]) else: return False, _ErrorMsgs['dataerr'] # Send the request. try: self._msg.SendRequest(self._msgsequence, self._stnaddr, cmdcode, datacount, dataaddr, sendata) # Something was wrong with the parameters we gave it to send. # This should have been caught earlier. except SBusMsg.ParamError: return False, _ErrorMsgs['invalidparam'] # Some other error occured while sending. except: return False, _ErrorMsgs['connnecterror'] # Receive the response. try: telegramattr, recv_msgsequence, recv_msgdata = self._msg.ReceiveResponse( ) # The message length did not match any valid message type. except SBusMsg.MessageLengthError: return False, _ErrorMsgs['responselength'] # The message CRC was bad. except SBusMsg.CRCError: return False, _ErrorMsgs['crcerr'] # Some other error occured while receiving. except: return False, _ErrorMsgs['connnecterror'] # Look at the telegrapm attribute to see what sort of response # it was, and compare that to the command code. # If it was a 1, we expect some data from a read operation. if (telegramattr == 1): # Decode the data by command code. if (cmdcode in (2, 3, 5)): rdata = int(ModbusDataStrLib.bin2boollist(recv_msgdata)[0]) elif (cmdcode == 6): rdata = SBusMsg.signedbin2int32list(recv_msgdata)[0] # This was an ack from a write operation, or it was a NAK. elif (telegramattr == 2): acknak = ModbusDataStrLib.signedbin2intlist(recv_msgdata)[0] # This is an ACK from a write operation if (acknak == 0) and (cmdcode in (11, 13, 14)): return True, '' else: return False, _ErrorMsgs['deviceerror'] # We have an invalid telegram. else: return False, _ErrorMsgs['badmessage'] return True, rdata
def handle_read(self): try: ReceivedData = self.recv(8192) except: ReceivedData = None if ReceivedData: if ShutDownCommand and (ReceivedData == ShutDownCommand): print('Shutdown command received by server %d. %s' % (CmdOpts.GetPort(), time.ctime())) self.close() raise asyncore.ExitNow # 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, RequestData, ExceptionCode = \ MBServerMSg.MBRequest(ReceivedData) except: FunctionCode = 0 TransID = 0 UnitID = 0 Start = 0 ReplyData = '' # 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. RequestData = quantity. MsgData = MemMap.GetCoils(Start, RequestData) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, Start, MsgData) elif FunctionCode == 2: # Read discrete inputs. RequestData = quantity. MsgData = MemMap.GetDiscreteInputs(Start, RequestData) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, Start, MsgData) elif FunctionCode == 3: # Read holding registers. RequestData = quantity. MsgData = MemMap.GetHoldingRegisters(Start, RequestData) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, Start, MsgData) elif FunctionCode == 4: # Read input registers. RequestData = quantity. MsgData = MemMap.GetInputRegisters(Start, RequestData) 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. RequestData is a tuple. MemMap.SetCoils(Start, RequestData[0], RequestData[1]) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, \ Start, ModbusDataStrLib.Int2BinStr(RequestData[0])) elif FunctionCode == 16: # Write multiple holding registers. RequestData is a tuple. MemMap.SetHoldingRegisters(Start, RequestData[0], RequestData[1]) ReplyData = MBServerMSg.MBResponse(TransID, UnitID, FunctionCode, \ Start, ModbusDataStrLib.Int2BinStr(RequestData[0])) elif FunctionCode > 127: # Modbus exception. ReplyData = MBServerMSg.MBErrorResponse( TransID, UnitID, FunctionCode, ExceptionCode) else: print('Server %d - Unsupported function call' % CmdOpts.GetPort()) 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.GetPort()) else: self.close()
def handle(self): ReceivedData = self.rfile.read() if ReceivedData: # Decode message. try: (TelegramAttr, MsgSequence, StnAddr, CmdCode, DataAddr, DataCount, MsgData, MsgResult) = SBServerMsg.SBRequest(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 SBusMsg.MessageLengthError: print('Server %d - Invalid message length. %s' % (CmdOpts.GetPort(), time.ctime())) MsgResult = False MsgSequence = 0 # Message had a CRC error. except SBusMsg.CRCError: print('Server %d - Bad CRC. %s' % (CmdOpts.GetPort(), time.ctime())) MsgResult = False MsgSequence = 0 # All other errors. except: print('Server %d - Request could not be decoded. %s' % (CmdOpts.GetPort(), time.ctime())) MsgResult = False MsgSequence = 0 ReplyData = '' # Handle the command, but only if know the parameters are valid. if (MsgResult): # Decode messages. If we get an error in reading/writing memory or # in constructing messages, we will consider this to be an SBus error. try: # Read Flags. if CmdCode == 2: MemData = MemMap.GetFlags(DataAddr, DataCount) MsgData = ModbusDataStrLib.boollist2bin(MemData) ReplyData = SBServerMsg.SBResponse(MsgSequence, CmdCode, 0, MsgData) # Read Inputs elif CmdCode == 3: MemData = MemMap.GetInputs(DataAddr, DataCount) MsgData = ModbusDataStrLib.boollist2bin(MemData) ReplyData = SBServerMsg.SBResponse(MsgSequence, CmdCode, 0, MsgData) # Read Outputs elif CmdCode == 5: MemData = MemMap.GetOutputs(DataAddr, DataCount) MsgData = ModbusDataStrLib.boollist2bin(MemData) ReplyData = SBServerMsg.SBResponse(MsgSequence, CmdCode, 0, MsgData) # Read Registers elif CmdCode == 6: MemData = MemMap.GetRegisters(DataAddr, DataCount) MsgData = SBusMsg.signedint32list2bin(MemData) ReplyData = SBServerMsg.SBResponse(MsgSequence, CmdCode, 0, MsgData) # Write flags elif CmdCode == 11: MemData = ModbusDataStrLib.bin2boollist(MsgData) MemMap.SetFlags(DataAddr, DataCount, MemData) ReplyData = SBServerMsg.SBResponse(MsgSequence, CmdCode, 0, '') # Write outputs elif CmdCode == 13: MemData = ModbusDataStrLib.bin2boollist(MsgData) MemMap.SetOutputs(DataAddr, DataCount, MemData) ReplyData = SBServerMsg.SBResponse(MsgSequence, CmdCode, 0, '') # Write Registers elif CmdCode == 14: MemData = SBusMsg.signedbin2int32list(MsgData) MemMap.SetRegisters(DataAddr, DataCount, MemData) ReplyData = SBServerMsg.SBResponse(MsgSequence, CmdCode, 0, '') # We don't understand this command code. else: print('Server %d - Unsupported command code' % CmdOpts.GetPort()) ReplyData = SBServerMsg.SBErrorResponse(MsgSequence) # We don't understand this message. except: ReplyData = SBServerMsg.SBErrorResponse(MsgSequence) # The message was bad, so we return a NAK response. else: ReplyData = SBServerMsg.SBErrorResponse(MsgSequence) # Send the reply. try: self.wfile.write(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. %s' % (CmdOpts.GetPort(), time.ctime()))
SendAddr = int(CharAddr) # Preset the transaction ID. SendTransID = 0 CharacterOutput = CmdOpts.GetCharacter() # If this is a write function, convert the data to binary packed string format. BinData = '\x00\x00' try: if (SendFunction == 5): sendval = int(SendData) if sendval in (0, 1): BinData = ModbusDataStrLib.coilvalue(int(SendData)) else: print('Invalid data for Modbus Function %d.' % SendFunction) sys.exit(4) elif (SendFunction == 15): BinData = ModbusDataStrLib.bininversor(SendData) elif SendFunction in (6, 16, 66): BinData = ModbusDataStrLib.hex2bin(SendData) elif SendFunction == 65: BinData = '\x00\x00' else: BinData = '\x00\x00' except: print('Invalid data for modbus function %d.' % SendFunction) sys.exit(4)