Using Both Channels on PCAN-USB Pro FD With Python

The free LIN software API (Application Programming Interface) for Windows® (only for usage with the PCAN-USB Pro CAN/LIN interface)
Post Reply
chill
Posts: 2
Joined: Thu 27. Feb 2020, 20:48

Using Both Channels on PCAN-USB Pro FD With Python

Post by chill » Thu 27. Feb 2020, 21:50

Hello,

I am using the PLIN-API with Python3.8 to create an app to talk to a LIN slave. The app has 2 different jobs to do and depending on the job, connect to either channel 1 or channel 2.

I have had the app working well using 1 channel at once, but I am now trying to get both channels working at the same time.

I have created a LinBus class that creates a connection. If I create 2 instances of this class, then try and configure something on the first one (such as starting a schedule), I get a 'TLIN_ERROR_ILLEGAL_CLIENT' error response. If I start the schedule as part of creating the connection, I can see messages arriving from both slaves/channels, so I know 2 chanels at once is possible.

Also, calling 'closeConnection' on the 1st created LinBus (penultimate line of code) doesn't seem to close the connection (the light on channel 1 on the PCAN box keeps flashing) whereas when called on the 2nd created connection (last line) the channel 2 light goes solid on.

My test code:

Code: Select all

import PLinApi
from ctypes import *
from threading import Thread


class LinMessage(object):

    def __init__(self):
        self.frameId = 0
        self.protectedId = 0
        self.payload = [0, 0, 0, 0, 0, 0, 0, 0]


class LinBus(object):

    def __init__(self, baudrate, channel, name):

        self.bus = PLinApi.PLinApi()
        if self.bus is False: raise Exception("PLIN API Not Loaded")

        self.hClient = PLinApi.HLINCLIENT(0)
        self.hHw = PLinApi.HLINHW(0)
        self.HwMode = PLinApi.TLIN_HARDWAREMODE_MASTER
        self.HwBaudrate = c_ushort(baudrate)

        result = self.bus.RegisterClient(name, None, self.hClient)
        if result is not PLinApi.TLIN_ERROR_OK: raise Exception("Error registering client")

        if channel == "PCAN_USBBUS1":
            self.hHw = PLinApi.HLINHW(1)
        elif channel == "PCAN_USBBUS2":
            self.hHw = PLinApi.HLINHW(2)
        result = self.bus.ConnectClient(self.hClient, self.hHw)
        if result is not PLinApi.TLIN_ERROR_OK: raise Exception("Error connecting client")

        result = self.bus.InitializeHardware(self.hClient, self.hHw, self.HwMode, self.HwBaudrate)
        if result is not PLinApi.TLIN_ERROR_OK: raise Exception("Error initialising hardware")

        result = self.bus.RegisterFrameId(self.hClient, self.hHw, 0x00, 0x3F)
        if result is not PLinApi.TLIN_ERROR_OK: raise Exception("Error registering frame id client")

        # configure schedule
        masterRequestScheduleSlot = PLinApi.TLINScheduleSlot()
        masterRequestScheduleSlot.Type = PLinApi.TLIN_SLOTTYPE_MASTER_REQUEST
        masterRequestScheduleSlot.Delay = 10

        slaveResponseScheduleSlot = PLinApi.TLINScheduleSlot()
        slaveResponseScheduleSlot.Type = PLinApi.TLIN_SLOTTYPE_SLAVE_RESPONSE
        slaveResponseScheduleSlot.Delay = 10

        diagSchedule = (PLinApi.TLINScheduleSlot * 2)()
        diagSchedule[0] = masterRequestScheduleSlot
        diagSchedule[1] = slaveResponseScheduleSlot

        masterRequestFrameEntry = PLinApi.TLINFrameEntry()
        masterRequestFrameEntry.FrameId = c_ubyte(0x3C)
        masterRequestFrameEntry.Length = c_ubyte(8)
        masterRequestFrameEntry.Direction = PLinApi.TLIN_DIRECTION_PUBLISHER
        masterRequestFrameEntry.ChecksumType = PLinApi.TLIN_CHECKSUMTYPE_CLASSIC
        masterRequestFrameEntry.Flags = PLinApi.FRAME_FLAG_RESPONSE_ENABLE
        for i in range(0, 8):
            masterRequestFrameEntry.InitialData[0] = c_ubyte(0)

        slaveResponseFrameEntry = PLinApi.TLINFrameEntry()
        slaveResponseFrameEntry.FrameId = c_ubyte(0x3D)
        slaveResponseFrameEntry.Length = c_ubyte(8)
        slaveResponseFrameEntry.Direction = PLinApi.TLIN_DIRECTION_SUBSCRIBER
        slaveResponseFrameEntry.ChecksumType = PLinApi.TLIN_CHECKSUMTYPE_CLASSIC

        result = self.bus.SetFrameEntry(self.hClient, self.hHw, masterRequestFrameEntry)
        result = self.bus.SetFrameEntry(self.hClient, self.hHw, slaveResponseFrameEntry)

        result = self.bus.SetSchedule(self.hClient, self.hHw, 1, diagSchedule, 2)

        self.receiveThread = Thread(group=None, target=self.receiveFunction, name="Receive Thread")

        self.receiveThreadActive = False

    def receiveFunction(self):

        recvMessage = PLinApi.TLINRcvMsg()

        while self.receiveThreadActive:

            result = self.bus.Read(self.hClient, recvMessage)
            if result == PLinApi.TLIN_ERROR_OK:

                if recvMessage.ErrorFlags == PLinApi.TLIN_MSGERROR_OK and recvMessage.Type == 0:
                    msg = LinMessage()
                    msg.frameId = recvMessage.FrameId & 0x3F
                    length = recvMessage.Length
                    try:
                        for i in range(0, length):
                            msg.payload[i] = recvMessage.Data[i]

                        self.on_message_received(msg)

                    except Exception as err:
                        print("LinBus recv message error: {}".format(err))
                        pass

    def on_message_received(self, msg):

        print("Message Received: {}".format(self.hHw))
        print("FrameID: {0}".format(msg.frameId))
        print(msg.payload)

    def startDiagnosticSchedule(self):

        result = self.bus.StartSchedule(self.hClient, self.hHw, 1)
        if result is not PLinApi.TLIN_ERROR_OK: raise Exception("Error registering client, diag: {}".format(result))

        if not self.receiveThreadActive:
            self.receiveThreadActive = True
            self.receiveThread.start()

    def suspendSchedule(self):

        result = self.bus.SuspendSchedule(self.hClient, self.hHw)
        if result is not PLinApi.TLIN_ERROR_OK: raise Exception("Error registering client, norm")

    def sendMasterRequest(self, frameID, payload):
        # print("sendMasterRequest payload: ", payload)
        dataLength = len(payload)
        data = (c_ubyte * 8)()

        for i in range(0, 8):
            data[i] = c_ubyte(0)

        for i in range(0, dataLength):
            data[i] = c_ubyte(payload[i])

        self.bus.UpdateByteArray(self.hClient, self.hHw, frameID, 0, 8, data)

    def closeConnection(self):

        self.receiveThreadActive = False

        while self.receiveThread.is_alive():
            pass

        self.bus.SuspendSchedule(self.hClient, self.hHw)

        self.bus.ResetHardwareConfig(self.hClient, self.hHw)
        self.bus.RemoveClient(self.hClient)
        # print("LinBusRaw Connection Closed")

    def wakeup(self):
        print("wakeup")
        self.bus.XmtWakeUp(self.hClient, self.hHw)


if __name__ == "__main__":

    from time import time
    connection1 = LinBus(19200, "PCAN_USBBUS1", "conn1")
    connection2 = LinBus(19200, "PCAN_USBBUS2", "conn2")

    print("Conn 1: {}".format(connection1.hHw, connection1.bus.))
    print("Conn 2: {}".format(connection2.hHw))

    connection1.startDiagnosticSchedule()
    connection2.startDiagnosticSchedule()

    startTime = time()
    sendTime = startTime
    currTime = startTime

    while (currTime - startTime) < 2:

        if (currTime - sendTime) > 1:
            connection1.sendMasterRequest(0x03, [0x02, 0x3E, 0x00])
            connection2.sendMasterRequest(0x04, [0x02, 0x3E, 0x00])
            sendTime = currTime

        currTime = time()

    connection1.closeConnection()
    connection2.closeConnection()
I'm thinking something I do when creating the 2nd client is stamping on the 1st one?
Any help/ideas would be greatly appreciated.

User avatar
M.Riedl
Software Development
Software Development
Posts: 26
Joined: Wed 22. Sep 2010, 13:28

Re: Using Both Channels on PCAN-USB Pro FD With Python

Post by M.Riedl » Fri 28. Feb 2020, 16:08

Hello,

Currently I cannot reproduce the problem you described.
But I found a possible issue in your code at '__main__':

Code: Select all

connection1.sendMasterRequest(0x03, [0x02, 0x3E, 0x00])
connection2.sendMasterRequest(0x04, [0x02, 0x3E, 0x00])
You have configured the LIN frames 0x3C (master request) and 0x3D (slave response).
But you try to update the LIN frame data of the IDs 0x03 and 0x04.
The function calls should be like this, if you like to send master request data there.

Code: Select all

connection1.sendMasterRequest(0x3C, [0x02, 0x3E, 0x00])
connection2.sendMasterRequest(0x3C, [0x02, 0x3E, 0x00])
Regards
M.Riedl

chill
Posts: 2
Joined: Thu 27. Feb 2020, 20:48

Re: Using Both Channels on PCAN-USB Pro FD With Python

Post by chill » Mon 2. Mar 2020, 16:09

Hi,

The problem I was having seems to have solved itself, probably through restarted my PC over the weekend, I will keep an eye on it.

The issue you picked up on was a mistake, I cut down the code I am using to use as an example and must have left that in there.

Post Reply