def checkFrame(self): """ Check if the next frame is available. Return True if we were successful. 1. Populate header 2. Discard frame if UID does not match """ try: self.populateHeader() frame_size = self._header['len'] # print(frame_size) # print(len(self._buffer)) data = self._buffer[:frame_size - 2] crc = self._buffer[frame_size - 2:frame_size] crc_val = (byte2int(crc[0]) << 8) + byte2int(crc[1]) # print(crc) # print(self._buffer.hex()) # print(crc_val) # print(len(data)) if checkCRC(data, crc_val): return True else: _logger.debug("CRC invalid, discarding header!!") self.resetFrame() return False except (IndexError, KeyError, struct.error): return False
def checkFrame(self): ''' Check if the next frame is available. Return True if we were successful. ''' try: self.populateHeader() frame_size = self.__header['len'] data = self.__buffer[:frame_size - 2] crc = self.__buffer[frame_size - 2:frame_size] crc_val = (byte2int(crc[0]) << 8) + byte2int(crc[1]) return checkCRC(data, crc_val) except (IndexError, KeyError): return False
def checkFrame(self): ''' Check if the next frame is available. Return True if we were successful. ''' try: self.populateHeader() frame_size = self.__header['len'] data = self.__buffer[:frame_size - 2] crc = self.__buffer[frame_size - 2:frame_size] crc_val = (ord(crc[0]) << 8) + ord(crc[1]) return checkCRC(data, crc_val) except (IndexError, KeyError): return False
def checkFrame(self): start = self.__buffer.find(self.__start) if start == -1: return False self.__buffer = self.__buffer[start:] end = self.__buffer.rfind(self.__end) if end == -1: return False if end - start < 3: return False self.__header['len'] = end - start + 1 self.__header['uid'] = struct.unpack('>B', self.__buffer[start + 1]) self.__header['crc'] = struct.unpack('>H', self.__buffer[end - 2:end])[0] data = self.__buffer[start + 1:end - 2] return checkCRC(data, self.__header['crc'])
def checkFrame(self): """ Check if the next frame is available. Return True if we were successful. 1. Populate header 2. Discard frame if UID does not match """ try: self.populateHeader() frame_size = self._header['len'] data = self._buffer[:frame_size - 2] crc = self._buffer[frame_size - 2:frame_size] crc_val = (byte2int(crc[0]) << 8) + byte2int(crc[1]) return checkCRC(data, crc_val) except (IndexError, KeyError): return False
def checkFrame(self): ''' Check and decode the next frame :returns: True if we are successful, False otherwise ''' start = self.__buffer.find(self.__start) if start == -1: return False if start > 0 : # go ahead and skip old bad data self.__buffer = self.__buffer[start:] end = self.__buffer.find(self.__end) if (end != -1): self.__header['len'] = end self.__header['uid'] = struct.unpack('>B', self.__buffer[1:2]) self.__header['crc'] = struct.unpack('>H', self.__buffer[end - 2:end])[0] data = self.__buffer[start + 1:end - 2] return checkCRC(data, self.__header['crc']) return False
def checkFrame(self): """ Check if the next frame is available. Return True if we were successful. 1. Populate header 2. Discard frame if UID does not match """ try: self.populateHeader() frame_size = self._header['len'] data = self._buffer[:frame_size - 2] crc = self._buffer[frame_size - 2:frame_size] crc_val = (byte2int(crc[0]) << 8) + byte2int(crc[1]) if checkCRC(data, crc_val): return True else: _logger.debug("CRC invalid, discarding header!!") self.resetFrame() return False except (IndexError, KeyError, struct.error): return False
def testCyclicRedundancyCheck(self): ''' Test the cyclic redundancy check code ''' self.assertTrue(checkCRC(self.data, 0xe2db)) self.assertTrue(checkCRC(self.string, 0x889e))
def modbus_rtu_read(fd, decoder, size=1024, timeout=None): """An fd select.select/os.read loop understands Modbus/RTU protocol, and receives all the data available up to the end of the first recognized Modbus/RTU request/reply. A pymodbus.factory ClientDecoder or ServerDecoder must be supplied, in order to recognize the allowed RTU requests/replies and compute their sizes. """ incoming = b'' begun = misc.timer() logging.debug("Modbus/RTU %s Receive begins in %7.3f/%7.3fs", decoder.__class__.__name__, misc.timer() - begun, timeout if timeout is not None else misc.inf) complete = False rejected = 1 # known *not* to be a valid request <function code> ... <crc> # Wait up to 'timeout' for an initial request character, then 1/10th second. while (len(incoming) < size and not complete and select.select( [fd], [], [], 1.0 / 10 if incoming else timeout)[0]): # Not yet satisfied, and frame not yet complete, and still readable; get the next one. If # no input is availabe within 1.5 character times, we should quit; we cannot be anywhere # near that precise at the "user" level (probably not even at the device driver level; must # be implemented in the RS485-capable UART), so wait a long time (adequate for any UART # input available to trickle thru the kernel to the serial input buffer and be reported as # ready to receive). Since we don't know baudrate or kernel loading, we must use an # extraordinarily long timeout (1/10th) second. Unfortunately, this is roughly equivalent # to opening the serial port with VMIN=0 and VTIME=1 -- but, astonishingly, there is no way # to do that via PySerial! c = os.read(fd, 1) if not c: raise serial.SerialException( 'device reports readiness to read but returned no data (device disconnected or multiple access on port?)' ) incoming += c logging.debug( "Modbus/RTU %s Receive reading in %7.3f/%7.3fs; %d bytes", decoder.__class__.__name__, misc.timer() - begun, timeout if timeout is not None else misc.inf, len(incoming)) for i in range(rejected, max(rejected, len(incoming) - 2)): # in a buffer N long, the function code could be anywhere from index 1, to within 3 # characters from the end: <unit> <func_code> [<data> ...] <crc0> <crc1>. See if we can # reject any more input as definitely *not* a potentially valid request in formation. # If its a recognized function code, and we have the complete request data, and its CRC # is invalid, reject it and move along. However, if we cannot yet tell (because we # don't yet have a CRC), keep receiving. For actual ExceptionResponse, we'll just # timeout and return what we get (because we can't identify those reliably) pdu_class = decoder.lookupPduClass(ord(incoming[i])) if pdu_class is ExceptionResponse: # Returned for every unrecognized function... rejected = i logging.debug( "Modbus/RTU %s Receive rejects in %7.3f/%7.3fs; %d bytes: no frame at offset %d", decoder.__class__.__name__, misc.timer() - begun, timeout if timeout is not None else misc.inf, len(incoming), rejected) continue # Might be a function code! How big? Raises Exception if data not yet available. try: frame_size = pdu_class.calculateRtuFrameSize(incoming[i - 1:]) data = incoming[i - 1:i - 1 + frame_size - 2] crc = incoming[i - 1 + frame_size - 2:i - 1 + frame_size] crc_val = (ord(crc[0]) << 8) + ord(crc[1]) if checkCRC(data, crc_val): logging.debug( "Modbus/RTU %s Receive framing in %7.3f/%7.3fs; %d bytes: %s of %d bytes", decoder.__class__.__name__, misc.timer() - begun, timeout if timeout is not None else misc.inf, len(incoming), pdu_class.__name__, frame_size) complete = True break except Exception: # Not yet possible to tell; keep receiving break logging.debug("Modbus/RTU %s Receive success in %7.3f/%7.3fs; %d bytes", decoder.__class__.__name__, misc.timer() - begun, timeout if timeout is not None else misc.inf, len(incoming)) return incoming
def modbus_rtu_read( fd, decoder, size=1024, timeout=None ): """An fd select.select/os.read loop understands Modbus/RTU protocol, and receives all the data available up to the end of the first recognized Modbus/RTU request/reply. A pymodbus.factory ClientDecoder or ServerDecoder must be supplied, in order to recognize the allowed RTU requests/replies and compute their sizes. """ incoming = b'' begun = misc.timer() logging.debug( "Modbus/RTU %s Receive begins in %7.3f/%7.3fs", decoder.__class__.__name__, misc.timer() - begun, timeout if timeout is not None else misc.inf ) complete = False rejected = 1 # known *not* to be a valid request <function code> ... <crc> # Wait up to 'timeout' for an initial request character, then 1/10th second. while ( len( incoming ) < size and not complete and select.select( [fd], [], [], 1.0/10 if incoming else timeout )[0] ): # Not yet satisfied, and frame not yet complete, and still readable; get the next one. If # no input is availabe within 1.5 character times, we should quit; we cannot be anywhere # near that precise at the "user" level (probably not even at the device driver level; must # be implemented in the RS485-capable UART), so wait a long time (adequate for any UART # input available to trickle thru the kernel to the serial input buffer and be reported as # ready to receive). Since we don't know baudrate or kernel loading, we must use an # extraordinarily long timeout (1/10th) second. Unfortunately, this is roughly equivalent # to opening the serial port with VMIN=0 and VTIME=1 -- but, astonishingly, there is no way # to do that via PySerial! c = os.read( fd, 1 ) if not c: raise serial.SerialException('device reports readiness to read but returned no data (device disconnected or multiple access on port?)') incoming += c logging.debug( "Modbus/RTU %s Receive reading in %7.3f/%7.3fs; %d bytes", decoder.__class__.__name__, misc.timer() - begun, timeout if timeout is not None else misc.inf, len( incoming )) for i in range( rejected, max( rejected, len( incoming ) - 2 )): # in a buffer N long, the function code could be anywhere from index 1, to within 3 # characters from the end: <unit> <func_code> [<data> ...] <crc0> <crc1>. See if we can # reject any more input as definitely *not* a potentially valid request in formation. # If its a recognized function code, and we have the complete request data, and its CRC # is invalid, reject it and move along. However, if we cannot yet tell (because we # don't yet have a CRC), keep receiving. For actual ExceptionResponse, we'll just # timeout and return what we get (because we can't identify those reliably) pdu_class = decoder.lookupPduClass( ord( incoming[i] )) if pdu_class is ExceptionResponse: # Returned for every unrecognized function... rejected = i logging.debug( "Modbus/RTU %s Receive rejects in %7.3f/%7.3fs; %d bytes: no frame at offset %d", decoder.__class__.__name__, misc.timer() - begun, timeout if timeout is not None else misc.inf, len( incoming ), rejected ) continue # Might be a function code! How big? Raises Exception if data not yet available. try: frame_size = pdu_class.calculateRtuFrameSize( incoming[i-1:] ) data = incoming[i-1:i-1+frame_size-2] crc = incoming[i-1+frame_size-2:i-1+frame_size] crc_val = (ord(crc[0]) << 8) + ord(crc[1]) if checkCRC( data, crc_val ): logging.debug( "Modbus/RTU %s Receive framing in %7.3f/%7.3fs; %d bytes: %s of %d bytes", decoder.__class__.__name__, misc.timer() - begun, timeout if timeout is not None else misc.inf, len( incoming ), pdu_class.__name__, frame_size ) complete = True break except Exception: # Not yet possible to tell; keep receiving break logging.debug( "Modbus/RTU %s Receive success in %7.3f/%7.3fs; %d bytes", decoder.__class__.__name__, misc.timer() - begun, timeout if timeout is not None else misc.inf, len( incoming )) return incoming