Example #1
0
    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")
Example #2
0
    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
Example #3
0
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'])
Example #4
0
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,
        )
Example #5
0
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