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()
Any help/ideas would be greatly appreciated.