def loadConfiguration(configPath=None): #load the base config baseConfig = path.dirname(__file__) + "/config.ini" config = Config() if path.exists(baseConfig): config.read(baseConfig) else: raise FileNotFoundError("No base config file") # check the config path if configPath is not None: if path.exists(configPath): config.read(configPath) else: raise FileNotFoundError("specified config not found") TpFactory.config = config
class LinTp(iTp): #__metaclass__ = iTp def __init__(self, configPath=None, **kwargs): # perform the instance config self.__config = None self.__loadConfiguration(configPath) self.__checkKwargs(**kwargs) self.__maxPduLength = 6 self.__NAD = int(self.__config["linTp"]["nodeAddress"], 16) self.__STMin = float(self.__config["linTp"]["STMin"]) # hardcoding the baudrate for the time being self.__connection = LinBus.LinBus(19200) # ... TODO: replace with something like the following #self.__connection = LinBusFactory.LinBusFactory(linBusType="Peak",baudrate=19200) # ... TODO: replace with defined values rather than variables self.__connection.on_message_received = self.callback_onReceive # self.__connection.on_message_received = self.callback_onReceive ... needs to be replaced as handled internall in the LIN bus impl self.__connection.startDiagnosticSchedule() #self.__connection.startSchedule() # ... replaced by this self.__recvBuffer = [] self.__transmitBuffer = None def send(self, payload, functionalReq=False): # TODO: functionalReq not used??? #self.__connection.send(payload) # .... implemented in the LIN bus impl, so the rest of function replaced by this payloadLength = len(payload) if payloadLength > LINTP_MAX_PAYLOAD_LENGTH: raise Exception("Payload too large for CAN Transport Protocol") if payloadLength <= self.__maxPduLength: state = LinTpState.SEND_SINGLE_FRAME else: # we might need a check for functional request as we may not be able to service functional requests for # multi frame requests state = LinTpState.SEND_FIRST_FRAME firstFrameData = payload[0:self.__maxPduLength-1] cfBlocks = self.create_blockList(payload[5:]) sequenceNumber = 1 txPdu = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] endOfMessage_flag = False ## this needs fixing to get the timing from the config timeoutTimer = ResettableTimer(1) stMinTimer = ResettableTimer(self.__STMin) self.clearBufferedMessages() timeoutTimer.start() while endOfMessage_flag is False: rxPdu = self.getNextBufferedMessage() if rxPdu is not None: raise Exception("Unexpected receive frame") if state == LinTpState.SEND_SINGLE_FRAME: txPdu[N_PCI_INDEX] += (LinTpMessageType.SINGLE_FRAME << 4) txPdu[SINGLE_FRAME_DL_INDEX] += payloadLength txPdu[SINGLE_FRAME_DATA_START_INDEX:] = fillArray(payload, self.__maxPduLength) self.transmit(txPdu) endOfMessage_flag = True elif state == LinTpState.SEND_FIRST_FRAME: payloadLength_highNibble = (payloadLength & 0xF00) >> 8 payloadLength_lowNibble = (payloadLength & 0x0FF) txPdu[N_PCI_INDEX] += (LinTpMessageType.FIRST_FRAME << 4) txPdu[FIRST_FRAME_DL_INDEX_HIGH] += payloadLength_highNibble txPdu[FIRST_FRAME_DL_INDEX_LOW] += payloadLength_lowNibble txPdu[FIRST_FRAME_DATA_START_INDEX:] = firstFrameData self.transmit(txPdu) state = LinTpState.SEND_CONSECUTIVE_FRAME stMinTimer.start() timeoutTimer.restart() elif state == LinTpState.SEND_CONSECUTIVE_FRAME: if( stMinTimer.isExpired() and (self.__transmitBuffer is None) ): txPdu[N_PCI_INDEX] += (LinTpMessageType.CONSECUTIVE_FRAME << 4) txPdu[CONSECUTIVE_FRAME_SEQUENCE_NUMBER_INDEX] += sequenceNumber txPdu[CONSECUTIVE_FRAME_SEQUENCE_DATA_START_INDEX:] = cfBlocks.pop(0) self.transmit(txPdu) sequenceNumber = (sequenceNumber + 1) % 16 stMinTimer.restart() timeoutTimer.restart() if len(cfBlocks) == 0: endOfMessage_flag = True txPdu = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] sleep(0.001) if timeoutTimer.isExpired(): raise Exception("Timeout") def recv(self, timeout_s): #return self.__connection.recv(... can pass timeout from here if required ...) # .... implemented in the LIN bus impl, so the rest of function replaced by this timeoutTimer = ResettableTimer(timeout_s) payload = [] payloadPtr = 0 payloadLength = None sequenceNumberExpected = 1 endOfMessage_flag = False state = LinTpState.IDLE timeoutTimer.start() while endOfMessage_flag is False: rxPdu = self.getNextBufferedMessage() if rxPdu is not None: N_PCI = (rxPdu[N_PCI_INDEX] & 0xF0) >> 4 if state == LinTpState.IDLE: if N_PCI == LinTpMessageType.SINGLE_FRAME: payloadLength = rxPdu[N_PCI_INDEX & 0x0F] payload = rxPdu[SINGLE_FRAME_DATA_START_INDEX: SINGLE_FRAME_DATA_START_INDEX + payloadLength] endOfMessage_flag = True elif N_PCI == LinTpMessageType.FIRST_FRAME: payload = rxPdu[FIRST_FRAME_DATA_START_INDEX:] payloadLength = ((rxPdu[FIRST_FRAME_DL_INDEX_HIGH] & 0x0F) << 8) + rxPdu[ FIRST_FRAME_DL_INDEX_LOW] payloadPtr = self.__maxPduLength - 1 state = LinTpState.RECEIVING_CONSECUTIVE_FRAME timeoutTimer.restart() elif state == LinTpState.RECEIVING_CONSECUTIVE_FRAME: if N_PCI == LinTpMessageType.CONSECUTIVE_FRAME: sequenceNumber = rxPdu[CONSECUTIVE_FRAME_SEQUENCE_NUMBER_INDEX] & 0x0F if sequenceNumber != sequenceNumberExpected: raise Exception("Consecutive frame sequence out of order") else: sequenceNumberExpected = (sequenceNumberExpected + 1) % 16 payload += rxPdu[CONSECUTIVE_FRAME_SEQUENCE_DATA_START_INDEX:] payloadPtr += (self.__maxPduLength) timeoutTimer.restart() else: raise Exception("Unexpected PDU received") if payloadLength is not None: if payloadPtr >= payloadLength: endOfMessage_flag = True if timeoutTimer.isExpired(): raise Exception("Timeout in waiting for message") return list(payload[:payloadLength]) ## # dummy function for the time being def closeConnection(self): #self.__connection.disconnect() # .... implemented in the LIN bus impl, so the rest of function replaced by this self.__connection.closeConnection() def callback_onReceive(self, msg): msgNad = msg.payload[0] msgFrameId = msg.frameId #print("Received message") if msgNad == self.__NAD: if msgFrameId == 0x3C: if msg.payload == self.__transmitBuffer: self.__transmitBuffer = None elif msgFrameId == 0x3D or 125: self.__recvBuffer.append(msg.payload[1:8]) ## # @brief clear out the receive list def clearBufferedMessages(self): self.__recvBuffer = [] self.__transmitBuffer = None ## # @brief retrieves the next message from the received message buffers # @return list, or None if nothing is on the receive list def getNextBufferedMessage(self): length = len(self.__recvBuffer) if(length != 0): return self.__recvBuffer.pop(0) else: return None ## # @brief creates the blocklist from the blocksize and payload def create_blockList(self, payload): blockList = [] currBlock = [] payloadLength = len(payload) counter = 0 for i in range(0, payloadLength): currBlock.append(payload[i]) counter += 1 if counter == self.__maxPduLength: blockList.append(currBlock) counter = 0 currBlock = [] if len(currBlock) is not 0: blockList.append(fillArray(currBlock, self.__maxPduLength)) return blockList # This function is effectively moved down to the LIN bus impl (i.e. only called from within send() which is moving down def transmit(self, payload): txPdu = [self.__NAD] + payload self.__connection.sendMasterRequest(txPdu) self.__transmitBuffer = txPdu """ def addSchedule(self): #self.__connection.addSchedule(index???) # .... implemented in the LIN bus impl, so the rest of function replaced by this def startSchedule(self): #self.__connection.startSchedule(index???) # .... implemented in the LIN bus impl, so the rest of function replaced by this def pauseSchedule(self): #self.__connection.pauseSchedule(index???) # .... implemented in the LIN bus impl, so the rest of function replaced by this def stopSchedule(self): #self.__connection.stopSchedule(index???) # .... implemented in the LIN bus impl, so the rest of function replaced by this """ def wakeup(self): #self.__connection.wakeBus(index???) # .... implemented in the LIN bus impl, so the rest of function replaced by this self.__connection.wakeup() ## # @brief used to load the local configuration options and override them with any passed in from a config file def __loadConfiguration(self, configPath, **kwargs): # load the base config baseConfig = path.dirname(__file__) + "\config.ini" self.__config = Config() if path.exists(baseConfig): self.__config.read(baseConfig) else: raise FileNotFoundError("No base config file") # check the config path if configPath is not None: if path.exists(configPath): self.__config.read(configPath) else: raise FileNotFoundError("specified config not found") ## # @brief goes through the kwargs and overrides any of the local configuration options def __checkKwargs(self, **kwargs): if 'nodeAddress' in kwargs: self.__config['linTp']['nodeAddress'] = str(hex(kwargs['nodeAddress'])) if 'STMin' in kwargs: self.__config['linTp']['STMin'] = str(kwargs['STMin'])
class CanTp(iTp): configParams = ['reqId', 'resId', 'addressingType'] ## # @brief constructor for the CanTp object def __init__(self, configPath=None, **kwargs): # perform the instance config self.__config = None self.__loadConfiguration(configPath) self.__checkKwargs(**kwargs) # load variables from the config self.__N_AE = int(self.__config['canTp']['N_AE'], 16) self.__N_TA = int(self.__config['canTp']['N_TA'], 16) self.__N_SA = int(self.__config['canTp']['N_SA'], 16) Mtype = self.__config['canTp']['Mtype'] if (Mtype == "DIAGNOSTICS"): self.__Mtype = CanTpMTypes.DIAGNOSTICS elif (Mtype == "REMOTE_DIAGNOSTICS"): self.__Mtype = CanTpMTypes.REMOTE_DIAGNOSTICS else: raise Exception("Do not understand the Mtype config") addressingType = self.__config['canTp']['addressingType'] if addressingType == "NORMAL": self.__addressingType = CanTpAddressingTypes.NORMAL elif addressingType == "NORMAL_FIXED": self.__addressingType = CanTpAddressingTypes.NORMAL_FIXED elif self.__addressingType == "EXTENDED": self.__addressingType = CanTpAddressingTypes.EXTENDED elif addressingType == "MIXED": self.__addressingType = CanTpAddressingTypes.MIXED else: raise Exception("Do not understand the addressing config") self.__reqId = int(self.__config['canTp']['reqId'], 16) self.__resId = int(self.__config['canTp']['resId'], 16) # sets up the relevant parameters in the instance if ((self.__addressingType == CanTpAddressingTypes.NORMAL) | (self.__addressingType == CanTpAddressingTypes.NORMAL_FIXED)): self.__maxPduLength = 7 self.__pduStartIndex = 0 elif ((self.__addressingType == CanTpAddressingTypes.EXTENDED) | (self.__addressingType == CanTpAddressingTypes.MIXED)): self.__maxPduLength = 6 self.__pduStartIndex = 1 # set up the CAN connection canConnectionFactory = CanConnectionFactory() self.__connection = canConnectionFactory( self.callback_onReceive, self.__resId, # <-filter configPath, **kwargs) self.__recvBuffer = [] self.__discardNegResp = bool(self.__config['canTp']['discardNegResp']) ## # @brief used to load the local configuration options and override them with any passed in from a config file def __loadConfiguration(self, configPath, **kwargs): #load the base config baseConfig = path.dirname(__file__) + "/config.ini" self.__config = Config() if path.exists(baseConfig): self.__config.read(baseConfig) else: raise FileNotFoundError("No base config file") # check the config path if configPath is not None: if path.exists(configPath): self.__config.read(configPath) else: raise FileNotFoundError("specified config not found") ## # @brief goes through the kwargs and overrides any of the local configuration options def __checkKwargs(self, **kwargs): if 'addressingType' in kwargs: self.__config['canTp']['addressingType'] = kwargs['addressingType'] if 'reqId' in kwargs: self.__config['canTp']['reqId'] = str(hex(kwargs['reqId'])) if 'resId' in kwargs: self.__config['canTp']['resId'] = str(hex(kwargs['resId'])) if 'N_SA' in kwargs: self.__config['canTp']['N_SA'] = str(kwargs['N_SA']) if 'N_TA' in kwargs: self.__config['canTp']['N_TA'] = str(kwargs['N_TA']) if 'N_AE' in kwargs: self.__config['canTp']['N_AE'] = str(kwargs['N_AE']) if 'Mtype' in kwargs: self.__config['canTp']['Mtype'] = str(kwargs['Mtype']) if 'discardNegResp' in kwargs: self.__config['canTp']['discardNegResp'] = str( kwargs['discardNegResp']) ## # @brief connection method # def createBusConnection(self): # # check config file and load # connectionType = self.__config['DEFAULT']['interface'] # # if connectionType == 'virtual': # connectionName = self.__config['virtual']['interfaceName'] # bus = can.interface.Bus(connectionName, # bustype='virtual') # elif connectionType == 'peak': # channel = self.__config['peak']['device'] # baudrate = self.__config['connection']['baudrate'] # bus = pcan.PcanBus(channel, # bitrate=baudrate) # elif connectionType == 'vector': # channel = self.__config['vector']['channel'] # app_name = self.__config['vector']['app_name'] # baudrate = int(self.__config['connection']['baudrate']) * 1000 # bus = vector.VectorBus(channel, # app_name=app_name, # data_bitrate=baudrate) # # return bus ## # @brief send method # @param [in] payload the payload to be sent def send(self, payload, functionalReq=False): payloadLength = len(payload) payloadPtr = 0 state = CanTpState.IDLE if payloadLength > CANTP_MAX_PAYLOAD_LENGTH: raise Exception("Payload too large for CAN Transport Protocol") if payloadLength < self.__maxPduLength: state = CanTpState.SEND_SINGLE_FRAME else: # we might need a check for functional request as we may not be able to service functional requests for # multi frame requests state = CanTpState.SEND_FIRST_FRAME txPdu = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] sequenceNumber = 1 endOfMessage_flag = False blockList = [] currBlock = [] ## this needs fixing to get the timing from the config timeoutTimer = ResettableTimer(1) stMinTimer = ResettableTimer() self.clearBufferedMessages() while endOfMessage_flag is False: rxPdu = self.getNextBufferedMessage() if rxPdu is not None: N_PCI = (rxPdu[0] & 0xF0) >> 4 if N_PCI == CanTpMessageType.FLOW_CONTROL: fs = rxPdu[0] & 0x0F if fs == CanTpFsTypes.WAIT: raise Exception("Wait not currently supported") elif fs == CanTpFsTypes.OVERFLOW: raise Exception("Overflow received from ECU") elif fs == CanTpFsTypes.CONTINUE_TO_SEND: if state == CanTpState.WAIT_FLOW_CONTROL: if fs == CanTpFsTypes.CONTINUE_TO_SEND: bs = rxPdu[FC_BS_INDEX] if (bs == 0): bs = 585 blockList = self.create_blockList( payload[payloadPtr:], bs) stMin = self.decode_stMin( rxPdu[FC_STMIN_INDEX]) currBlock = blockList.pop(0) state = CanTpState.SEND_CONSECUTIVE_FRAME stMinTimer.timeoutTime = stMin stMinTimer.start() timeoutTimer.stop() else: raise Exception( "Unexpected Flow Control Continue to Send request" ) else: raise Exception("Unexpected fs response from ECU") else: raise Exception("Unexpected response from device") if state == CanTpState.SEND_SINGLE_FRAME: txPdu[N_PCI_INDEX] += (CanTpMessageType.SINGLE_FRAME << 4) txPdu[SINGLE_FRAME_DL_INDEX] += payloadLength txPdu[SINGLE_FRAME_DATA_START_INDEX:] = fillArray( payload, self.__maxPduLength) self.transmit(txPdu, functionalReq) endOfMessage_flag = True elif state == CanTpState.SEND_FIRST_FRAME: payloadLength_highNibble = (payloadLength & 0xF00) >> 8 payloadLength_lowNibble = (payloadLength & 0x0FF) txPdu[N_PCI_INDEX] += (CanTpMessageType.FIRST_FRAME << 4) txPdu[FIRST_FRAME_DL_INDEX_HIGH] += payloadLength_highNibble txPdu[FIRST_FRAME_DL_INDEX_LOW] += payloadLength_lowNibble txPdu[FIRST_FRAME_DATA_START_INDEX:] = payload[0:self. __maxPduLength - 1] payloadPtr += self.__maxPduLength - 1 self.transmit(txPdu, functionalReq) timeoutTimer.start() state = CanTpState.WAIT_FLOW_CONTROL elif state == CanTpState.SEND_CONSECUTIVE_FRAME: if (stMinTimer.isExpired()): txPdu[N_PCI_INDEX] += ( CanTpMessageType.CONSECUTIVE_FRAME << 4) txPdu[ CONSECUTIVE_FRAME_SEQUENCE_NUMBER_INDEX] += sequenceNumber txPdu[ CONSECUTIVE_FRAME_SEQUENCE_DATA_START_INDEX:] = currBlock.pop( 0) payloadPtr += self.__maxPduLength self.transmit(txPdu, functionalReq) sequenceNumber = (sequenceNumber + 1) % 16 stMinTimer.restart() if (len(currBlock) == 0): if (len(blockList) == 0): endOfMessage_flag = True else: timeoutTimer.start() state = CanTpState.WAIT_FLOW_CONTROL #print("waiting for flow control") txPdu = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # timer / exit condition checks if (timeoutTimer.isExpired()): raise Exception("Timeout waiting for message") sleep(0.001) ## # @brief recv method # @param [in] timeout_ms The timeout to wait before exiting # @return a list def recv(self, timeout_s): timeoutTimer = ResettableTimer(timeout_s) payload = [] payloadPtr = 0 payloadLength = None sequenceNumberExpected = 1 txPdu = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] endOfMessage_flag = False state = CanTpState.IDLE timeoutTimer.start() while endOfMessage_flag is False: rxPdu = self.getNextBufferedMessage() if rxPdu is not None: N_PCI = (rxPdu[N_PCI_INDEX] & 0xF0) >> 4 if state == CanTpState.IDLE: if N_PCI == CanTpMessageType.SINGLE_FRAME: payloadLength = rxPdu[N_PCI_INDEX & 0x0F] payload = rxPdu[SINGLE_FRAME_DATA_START_INDEX: SINGLE_FRAME_DATA_START_INDEX + payloadLength] endOfMessage_flag = True elif N_PCI == CanTpMessageType.FIRST_FRAME: payload = rxPdu[FIRST_FRAME_DATA_START_INDEX:] payloadLength = ( (rxPdu[FIRST_FRAME_DL_INDEX_HIGH] & 0x0F) << 8) + rxPdu[FIRST_FRAME_DL_INDEX_LOW] payloadPtr = self.__maxPduLength - 1 state = CanTpState.SEND_FLOW_CONTROL elif state == CanTpState.RECEIVING_CONSECUTIVE_FRAME: if N_PCI == CanTpMessageType.CONSECUTIVE_FRAME: sequenceNumber = rxPdu[ CONSECUTIVE_FRAME_SEQUENCE_NUMBER_INDEX] & 0x0F if sequenceNumber != sequenceNumberExpected: raise Exception( "Consecutive frame sequence out of order") else: sequenceNumberExpected = (sequenceNumberExpected + 1) % 16 payload += rxPdu[ CONSECUTIVE_FRAME_SEQUENCE_DATA_START_INDEX:] payloadPtr += (self.__maxPduLength) timeoutTimer.restart() else: raise Exception("Unexpected PDU received") if state == CanTpState.SEND_FLOW_CONTROL: txPdu[N_PCI_INDEX] = 0x30 txPdu[FLOW_CONTROL_BS_INDEX] = 0 txPdu[FLOW_CONTROL_STMIN_INDEX] = 0x1E self.transmit(txPdu) state = CanTpState.RECEIVING_CONSECUTIVE_FRAME if payloadLength is not None: if payloadPtr >= payloadLength: endOfMessage_flag = True if timeoutTimer.isExpired(): raise Exception("Timeout in waiting for message") return list(payload[:payloadLength]) ## # dummy function for the time being def closeConnection(self): # deregister filters, listeners and notifiers etc # close can connection pass ## # @brief clear out the receive list def clearBufferedMessages(self): self.__recvBuffer = [] ## # @brief retrieves the next message from the received message buffers # @return list, or None if nothing is on the receive list def getNextBufferedMessage(self): length = len(self.__recvBuffer) if (length != 0): return self.__recvBuffer.pop(0) else: return None ## # @brief the listener callback used when a message is received def callback_onReceive(self, msg): if self.__addressingType == CanTpAddressingTypes.NORMAL: if msg.arbitration_id == self.__resId: self.__recvBuffer.append(msg.data[self.__pduStartIndex:]) elif self.__addressingType == CanTpAddressingTypes.NORMAL_FIXED: raise Exception( "I do not know how to receive this addressing type yet") elif self.__addressingType == CanTpAddressingTypes.MIXED: raise Exception( "I do not know how to receive this addressing type yet") else: raise Exception( "I do not know how to receive this addressing type") ## # @brief function to decode the StMin parameter @staticmethod def decode_stMin(val): if (val <= 0x7F): time = val / 1000 return time elif ((val >= 0xF1) & (val <= 0xF9)): time = (val & 0x0F) / 10000 return time else: raise Exception("Unknown STMin time") ## # @brief creates the blocklist from the blocksize and payload def create_blockList(self, payload, blockSize): blockList = [] currBlock = [] currPdu = [] payloadPtr = 0 blockPtr = 0 payloadLength = len(payload) pduLength = self.__maxPduLength blockLength = blockSize * pduLength working = True while (working): if (payloadPtr + pduLength) >= payloadLength: working = False currPdu = fillArray(payload[payloadPtr:], pduLength) currBlock.append(currPdu) blockList.append(currBlock) if working: currPdu = payload[payloadPtr:payloadPtr + pduLength] currBlock.append(currPdu) payloadPtr += pduLength blockPtr += pduLength if (blockPtr == blockLength): blockList.append(currBlock) currBlock = [] blockPtr = 0 return blockList ## # @brief transmits the data over can using can connection # def transmit(self, data, functionalReq=False): # # # check functional request # if functionalReq: # raise Exception("Functional requests are currently not supported") # else: # self.__connection.transmit(data, self.__reqId, self.__addressingType) def transmit(self, data, functionalReq=False): # check functional request if functionalReq: raise Exception("Functional requests are currently not supported") transmitData = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] if ((self.__addressingType == CanTpAddressingTypes.NORMAL) | (self.__addressingType == CanTpAddressingTypes.NORMAL_FIXED)): transmitData = data elif self.__addressingType == CanTpAddressingTypes.MIXED: transmitData[0] = self.__N_AE transmitData[1:] = data else: raise Exception("I do not know how to send this addressing type") self.__connection.transmit( transmitData, self.__reqId, )
class Uds(object): ## # @brief a constructor # @param [in] reqId The request ID used by the UDS connection, defaults to None if not used # @param [in] resId The response Id used by the UDS connection, defaults to None if not used def __init__(self, configPath=None, ihexFile=None, **kwargs): self.__config = None self.__transportProtocol = None self.__P2_CAN_Client = None self.__P2_CAN_Server = None self.__loadConfiguration(configPath) self.__checkKwargs(**kwargs) self.__transportProtocol = self.__config['uds']['transportProtocol'] self.__P2_CAN_Client = float(self.__config['uds']['P2_CAN_Client']) self.__P2_CAN_Server = float(self.__config['uds']['P2_CAN_Server']) tpFactory = TpFactory() self.tp = tpFactory(self.__transportProtocol, configPath=configPath, **kwargs) # used as a semaphore for the tester present self.__transmissionActive_flag = False self.sendLock = threading.Lock() # Process any ihex file that has been associated with the ecu at initialisation self.__ihexFile = ihexFileParser( ihexFile) if ihexFile is not None else None def __loadConfiguration(self, configPath=None): baseConfig = path.dirname(__file__) + "/config.ini" self.__config = Config() # check the config path if configPath is not None: if path.exists(configPath): self.__config.read(configPath) else: raise FileNotFoundError("specified config not found") else: if path.exists(baseConfig): self.__config.read(baseConfig) else: raise FileNotFoundError("No base config file") def __checkKwargs(self, **kwargs): if 'transportProtocol' in kwargs: self.__config['uds']['transportProtocol'] = kwargs[ 'transportProtocol'] if 'P2_CAN_Server' in kwargs: self.__config['uds']['P2_CAN_Server'] = str( kwargs['P2_CAN_Server']) if 'P2_CAN_Client' in kwargs: self.__config['uds']['P2_CAN_Client'] = str( kwargs['P2_CAN_Client']) @property def ihexFile(self): return self.__ihexFile @ihexFile.setter def ihexFile(self, value): if value is not None: self.__ihexFile = ihexFileParser(value) ## # @brief Currently only called from transferFile to transfer ihex files def transferIHexFile(self, transmitChunkSize=None, compressionMethod=None): if transmitChunkSize is not None: self.__ihexFile.transmitChunksize = transmitChunkSize if compressionMethod is None: compressionMethod = IsoDataFormatIdentifier.noCompressionMethod self.requestDownload([compressionMethod], self.__ihexFile.transmitAddress, self.__ihexFile.transmitLength) self.transferData(transferBlocks=self.__ihexFile) return self.transferExit() ## # @brief This will eventually support more than one file type, but for now is limited to ihex only def transferFile(self, fileName=None, transmitChunkSize=None, compressionMethod=None): if fileName is None and self.__ihexFile is None: raise FileNotFoundError("file to transfer has not been specified") # Currently only ihex is recognised and supported if fileName[-4:] == '.hex' or fileName[-5:] == '.ihex': self.__ihexFile = ihexFileParser(fileName) return self.transferIHexFile(transmitChunkSize, compressionMethod) else: raise FileNotFoundError( "file to transfer has not been recognised as a supported type ['.hex','.ihex']" ) ## # @brief def send(self, msg, responseRequired=True, functionalReq=False): # sets a current transmission in progress - tester present (if running) will not send if this flag is set to true self.__transmissionActive_flag = True #print(("__transmissionActive_flag set:",self.__transmissionActive_flag)) response = None # We're moving to threaded operation, so putting a lock around the send operation. self.sendLock.acquire() try: a = self.tp.send(msg, functionalReq) finally: self.sendLock.release() if functionalReq is True: responseRequired = False # Note: in automated mode (unlikely to be used any other way), there is no response from tester present, so threading is not an issue here. if responseRequired: while True: response = self.tp.recv(self.__P2_CAN_Client) if not ((response[0] == 0x7F) and (response[2] == 0x78)): break # If the diagnostic session control service is supported, record the sending time for possible use by the tester present functionality (again, if present) ... try: self.sessionSetLastSend() except: pass # ... if the service isn't present, just ignore # Lets go of the hold on transmissions - allows test present to resume operation (if it's running) self.__transmissionActive_flag = False #print(("__transmissionActive_flag cleared:",self.__transmissionActive_flag)) return response def disconnect(self): self.tp.closeConnection() ## # @brief def isTransmitting(self): #print(("requesting __transmissionActive_flag:",self.__transmissionActive_flag)) return self.__transmissionActive_flag