Page 1 of 1

LIN Master - Schedule Table Processing and Read

Posted: Tue 17. Mar 2020, 06:59
by Volker.Schilling
Hello,

I'm trying to develop a LIN Master that is implemented using the PLinApi with Python 3. I want the Master to
run a schedule table on the hardware (this part is working fine) and read the BUS from the same hardware.
What I see is as soon as I read from a parallel thread the timings from the schedule table will not process proper.

- So, is it possible using the API to run an schedule table and do reads (logging of the bus) on the same hardware?
- How can this be realized? I tried multible threads.

Thanks,
Volker Schilling

Re: LIN Master - Schedule Table Processing and Read

Posted: Tue 17. Mar 2020, 11:54
by M.Heidemann
Hello,

Can you please send us the necessary code (your sheduler implementation) , so we can assess the issue further?

Best Regards

Marvin

Re: LIN Master - Schedule Table Processing and Read

Posted: Wed 18. Mar 2020, 05:40
by Volker.Schilling
Hello Marvin,

this is the code:

Code: Select all

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
from ctypes import *

import PLinApi


class LinFuzzer(object):
    """
    """

    FRAME_FILTER_MASK = c_uint64(0xFFFFFFFFFFFFFFFF)

    GLOBAL_FRAME_TABLE = {        
        0x00: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x01: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x02: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x03: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x04: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x05: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x06: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x07: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x08: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x09: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x0A: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x0B: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x0C: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x0D: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x0E: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x0F: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},

        0x10: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x11: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x12: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x13: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x14: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x15: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x16: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x17: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x18: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x19: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x1A: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x1B: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x1C: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x1D: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x1E: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},
        0x1F: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},

        # 0x20: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x20: {"dir": PLinApi.TLIN_DIRECTION_PUBLISHER, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 2},

        0x21: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x22: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x23: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x24: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x25: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x26: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x27: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x28: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x29: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},

        # 0x2A: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x2A: {"dir": PLinApi.TLIN_DIRECTION_SUBSCRIBER, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},

        # 0x2B: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x2B: {"dir": PLinApi.TLIN_DIRECTION_PUBLISHER, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},

        0x2C: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x2D: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x2E: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},
        0x2F: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},

        # 0x30: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x30: {"dir": PLinApi.TLIN_DIRECTION_PUBLISHER, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},

        # 0x31: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x31: {"dir": PLinApi.TLIN_DIRECTION_PUBLISHER, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 4},

        # 0x32: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x32: {"dir": PLinApi.TLIN_DIRECTION_PUBLISHER, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 1},

        # 0x33: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x33: {"dir": PLinApi.TLIN_DIRECTION_SUBSCRIBER, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 1},

        0x34: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x35: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x36: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},

        # 0x37: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x37: {"dir": PLinApi.TLIN_DIRECTION_PUBLISHER, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},

        0x38: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x39: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x3A: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x3B: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},

        # 0x3C: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x3C: {"dir": PLinApi.TLIN_DIRECTION_PUBLISHER, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},

        # 0x3D: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x3D: {"dir": PLinApi.TLIN_DIRECTION_SUBSCRIBER, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},

        0x3E: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
        0x3F: {"dir": PLinApi.TLIN_DIRECTION_DISABLED, "cst": PLinApi.TLIN_CHECKSUMTYPE_CLASSIC, "len": 8},
    }

    SCHEDULE_TABLE = [
        {"id": [0x37], "delay": 20, "type": PLinApi.TLIN_SLOTTYPE_UNCONDITIONAL},
        {"id": [0x33], "delay": 10, "type": PLinApi.TLIN_SLOTTYPE_UNCONDITIONAL},
        {"id": [0x32], "delay": 10, "type": PLinApi.TLIN_SLOTTYPE_UNCONDITIONAL},
        {"id": [0x2A], "delay": 20, "type": PLinApi.TLIN_SLOTTYPE_UNCONDITIONAL},
        {"id": [0x2B], "delay": 20, "type": PLinApi.TLIN_SLOTTYPE_UNCONDITIONAL},
        {"id": [0x30], "delay": 15, "type": PLinApi.TLIN_SLOTTYPE_UNCONDITIONAL},
        {"id": [0x31], "delay": 15, "type": PLinApi.TLIN_SLOTTYPE_UNCONDITIONAL},
        {"id": [0x20], "delay": 10, "type": PLinApi.TLIN_SLOTTYPE_UNCONDITIONAL},
        {"id": [0x2A], "delay": 20, "type": PLinApi.TLIN_SLOTTYPE_UNCONDITIONAL},
        {"id": [0x2B], "delay": 20, "type": PLinApi.TLIN_SLOTTYPE_UNCONDITIONAL},
    ]

    def __init__(self):
        """
        """
        self.m_objPLinApi = PLinApi.PLinApi()
        self.m_hClient = PLinApi.HLINCLIENT(0)
        self.m_hHw = PLinApi.HLINHW(0)
        self.m_HwMode = PLinApi.TLIN_HARDWAREMODE_MASTER
        self.m_HwBaudrate = c_ushort(9600)
        self.m_lMask = self.FRAME_FILTER_MASK

        if not self.m_objPLinApi.isLoaded():
            raise Exception("PLin-API could not be loaded ! Exiting...")

    def connect(self, name, device_number, channel_number):
        """
        :param name:
        :param device_number:
        :param channel_number:
        :return:
        """
        if self.m_objPLinApi.RegisterClient(name, None, self.m_hClient) != PLinApi.TLIN_ERROR_OK:
            raise Exception("Connect Failed")

        self.m_objPLinApi.ResetClient(self.m_hClient)

        self.m_hHw = PLinApi.HLINHW(device_number)

        if self.m_objPLinApi.ConnectClient(self.m_hClient, self.m_hHw) != PLinApi.TLIN_ERROR_OK:
            raise Exception("Connect Failed")

        mode = c_int(0)
        baudrate = c_int(0)

        if self.m_objPLinApi.GetHardwareParam(
                self.m_hHw, PLinApi.TLIN_HARDWAREPARAM_MODE, mode, 0) != PLinApi.TLIN_ERROR_OK:
            raise Exception("Connect Failed")
        if self.m_objPLinApi.GetHardwareParam(
                self.m_hHw, PLinApi.TLIN_HARDWAREPARAM_BAUDRATE, baudrate, 0) != PLinApi.TLIN_ERROR_OK:
            raise Exception("Connect Failed")

        self.m_objPLinApi.ResetHardware(self.m_hClient, self.m_hHw)

        if mode.value == PLinApi.TLIN_HARDWAREMODE_NONE.value or baudrate.value != self.m_HwBaudrate.value:
            if self.m_objPLinApi.InitializeHardware(
                    self.m_hClient, self.m_hHw, self.m_HwMode, self.m_HwBaudrate) != PLinApi.TLIN_ERROR_OK:
                raise Exception("Connect Failed")
            if self.m_objPLinApi.SetClientFilter(
                    self.m_hClient, self.m_hHw, self.m_lMask) != PLinApi.TLIN_ERROR_OK:
                raise Exception("Connect Failed")

    def disconnect(self):
        """
        :return:
        """

        if self.m_objPLinApi.DisconnectClient(self.m_hClient, self.m_hHw) == PLinApi.TLIN_ERROR_OK:
            self.m_hHw = PLinApi.HLINHW(0)
            self.m_objPLinApi.RemoveClient(self.m_hClient)

    def set_frame_entry(self, frameId, direction, cst, length):
        """
        :param frameId:
        :param direction:
        :param cst:
        :param length:
        :return:
        """
        frame_entry = PLinApi.TLINFrameEntry()
        frame_entry.FrameId = c_ubyte(frameId)
        frame_entry.ChecksumType = cst
        frame_entry.Direction = direction
        frame_entry.Length = c_ubyte(length)
        frame_entry.Flags = PLinApi.FRAME_FLAG_RESPONSE_ENABLE

        if self.m_objPLinApi.SetFrameEntry(self.m_hClient, self.m_hHw, frame_entry) == PLinApi.TLIN_ERROR_OK:
            mask = c_uint64(1 << frameId)
            self.m_lMask = c_uint64(self.m_lMask.value | mask.value)
            if self.m_objPLinApi.SetClientFilter(self.m_hClient, self.m_hHw, self.m_lMask) != PLinApi.TLIN_ERROR_OK:
                raise Exception("Connect Failed")

    def set_global_frame_table(self):
        """
        :return:
        """
        for frame_id in self.GLOBAL_FRAME_TABLE:
            entry = self.GLOBAL_FRAME_TABLE[frame_id]
            self.set_frame_entry(
                frameId=frame_id, direction=entry['dir'], cst=entry['cst'], length=entry['len'])

    def get_global_frame_table(self):
        """
        :return:
        """

        table = {}

        self.m_lMask = c_uint64(0x0)
        mask = c_uint64(0x0)

        for index in range(64):
            frame_entry = PLinApi.TLINFrameEntry()
            frame_entry.FrameId = c_ubyte(index)
            frame_entry.ChecksumType = PLinApi.TLIN_CHECKSUMTYPE_AUTO
            frame_entry.Direction = PLinApi.TLIN_DIRECTION_SUBSCRIBER_AUTOLENGTH

            if (index >= 0x00) and (index <= 0x1F):
                frame_entry.Length = c_ubyte(2)
            elif (index >= 0x20) and (index <= 0x2F):
                frame_entry.Length = c_ubyte(4)
            elif (index >= 0x30) and (index <= 0x3F):
                frame_entry.Length = c_ubyte(8)

            if self.m_objPLinApi.GetFrameEntry(self.m_hHw, frame_entry) == PLinApi.TLIN_ERROR_OK:

                table[frame_entry.FrameId] = {
                    "dir": frame_entry.Direction,
                    "cst": frame_entry.ChecksumType,
                    "len": frame_entry.Length
                }

                if frame_entry.Direction != PLinApi.TLIN_DIRECTION_DISABLED.value:
                    mask = c_uint64((1 << index) & self.FRAME_FILTER_MASK.value)
                    self.m_lMask = c_uint64(self.m_lMask.value | mask.value)

            if (self.m_hClient.value != 0) and (self.m_hHw.value != 0):
                self.m_objPLinApi.SetClientFilter(self.m_hClient, self.m_hHw, self.m_lMask)

        return table

    def set_schedule_table(self, tyble_id):
        """
        :param tyble_id:
        :return:
        """
        schedule_slot_array = (PLinApi.TLINScheduleSlot * len(self.SCHEDULE_TABLE))
        schedule_table = schedule_slot_array()

        for index, entry in enumerate(self.SCHEDULE_TABLE):
            schedule_entry = PLinApi.TLINScheduleSlot()

            for pos, frameId in enumerate(entry["id"]):
                schedule_entry.FrameId[pos] = c_ubyte(frameId)
            schedule_entry.Type = entry["type"]
            schedule_entry.Delay = c_ushort(entry["delay"])
            schedule_entry.CountResolve = c_ubyte(0)

            schedule_table[index] = schedule_entry

        self.m_objPLinApi.SetSchedule(self.m_hClient, self.m_hHw, tyble_id, schedule_table, len(self.SCHEDULE_TABLE))

    def get_schedule_table(self, tyble_id):
        """
        :param tyble_id:
        :return:
        """
        schedule_slot_array = (PLinApi.TLINScheduleSlot * 256)
        schedule_table = schedule_slot_array()

        count = c_int(0)
        self.m_objPLinApi.GetSchedule(self.m_hHw, tyble_id, schedule_table, c_int(256), count)

        for index in range(count.value):
            schedule_entry = schedule_table[index]
            print(
                schedule_entry.Type,
                schedule_entry.Delay,
                schedule_entry.FrameId[0],
                schedule_entry.CountResolve,
                schedule_entry.Handle
            )

    def delete_schedule_table(self, table_id):
        """
        :param table_id:
        :return:
        """
        self.m_objPLinApi.DeleteSchedule(self.m_hClient, self.m_hHw, table_id)

    def start_schedule_table(self, table_id):
        """
        :param table_id:
        :return:
        """
        self.m_objPLinApi.StartSchedule(self.m_hClient, self.m_hHw, table_id)

    def resume_schedule_table(self):
        """
        :return:
        """
        self.m_objPLinApi.ResumeSchedule(self.m_hClient, self.m_hHw)

    def suspend_schedule_table(self):
        """
        :return:
        """
        self.m_objPLinApi.SuspendSchedule(self.m_hClient, self.m_hHw)

    def update_schedule_data(self, frame_id, data=[]):
        """
        :param frame_id:
        :param data:
        :return:
        """

        raw_data = (c_ubyte * len(data))()
        for index, byte in enumerate(data):
            raw_data[index] = c_ubyte(byte)

        self.m_objPLinApi.UpdateByteArray(self.m_hClient, self.m_hHw, c_ubyte(frame_id), 0, c_ubyte(len(data)), raw_data)

    def write_frame(self, frame_id, data=[]):
        """
        :param frame_id:
        :param data:
        :return:
        """

        frame_entry = PLinApi.TLINFrameEntry()
        frame_entry.FrameId = c_ubyte(frame_id)
        self.m_objPLinApi.GetFrameEntry(self.m_hHw, frame_entry)

        msg = PLinApi.TLINMsg()
        msg.Direction = PLinApi.TLINDirection(frame_entry.Direction)
        msg.ChecksumType = PLinApi.TLINChecksumType(frame_entry.ChecksumType)
        msg.Length = c_ubyte(frame_entry.Length)

        for index in range(frame_entry.Length):
            msg.Data[index] = c_ubyte(data[index])

        private_id = c_ubyte(frame_id)
        self.m_objPLinApi.GetPID(private_id)
        msg.FrameId = c_ubyte(private_id.value)
        self.m_objPLinApi.CalculateChecksum(msg)
        self.m_objPLinApi.Write(self.m_hClient, self.m_hHw, msg)

    def read(self):
        """
        :return:
        """
        msg_buffer = {}

        while True:
            msg = PLinApi.TLINRcvMsg()
            if self.m_objPLinApi.Read(self.m_hClient, msg) == PLinApi.TLIN_ERROR_OK:
                delta = ((msg.TimeStamp - msg_buffer.setdefault(msg.FrameId, msg.TimeStamp)) / 1000.0)
                msg_buffer[msg.FrameId] = msg.TimeStamp

                if msg.Length == 1:
                    print("{} ({:>14}) : 0x{:02X} {} - {:02X} [{}]".format(
                        msg.TimeStamp, delta, msg.FrameId, msg.Length,
                        msg.Data[0], msg.ErrorFlags)
                    )
                elif msg.Length == 2:
                    print("{} ({:>14}) : 0x{:02X} {} - {:02X} {:02X} [{}]".format(
                        msg.TimeStamp, delta, msg.FrameId, msg.Length,
                        msg.Data[0],
                        msg.Data[1], msg.ErrorFlags)
                    )
                elif msg.Length == 3:
                    print("{} ({:>14}) : 0x{:02X} {} - {:02X} {:02X} {:02X} [{}]".format(
                        msg.TimeStamp, delta, msg.FrameId, msg.Length,
                        msg.Data[0],
                        msg.Data[1],
                        msg.Data[2], msg.ErrorFlags)
                    )
                elif msg.Length == 4:
                    print("{} ({:>14}) : 0x{:02X} {} - {:02X} {:02X} {:02X} {:02X} [{}]".format(
                        msg.TimeStamp, delta, msg.FrameId, msg.Length,
                        msg.Data[0],
                        msg.Data[1],
                        msg.Data[2],
                        msg.Data[3], msg.ErrorFlags)
                    )
                elif msg.Length == 5:
                    print("{} ({:>14}) : 0x{:02X} {} - {:02X} {:02X} {:02X} {:02X} {:02X} [{}]".format(
                        msg.TimeStamp, delta, msg.FrameId, msg.Length,
                        msg.Data[0],
                        msg.Data[1],
                        msg.Data[2],
                        msg.Data[3],
                        msg.Data[4], msg.ErrorFlags)
                    )
                elif msg.Length == 6:
                    print("{} ({:>14}) : 0x{:02X} {} - {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} [{}]".format(
                        msg.TimeStamp, delta, msg.FrameId, msg.Length,
                        msg.Data[0],
                        msg.Data[1],
                        msg.Data[2],
                        msg.Data[3],
                        msg.Data[4],
                        msg.Data[5], msg.ErrorFlags)
                    )
                elif msg.Length == 7:
                    print("{} ({:>14}) : 0x{:02X} {} - {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} [{}]".format(
                        msg.TimeStamp, delta, msg.FrameId, msg.Length,
                        msg.Data[0],
                        msg.Data[1],
                        msg.Data[2],
                        msg.Data[3],
                        msg.Data[4],
                        msg.Data[5],
                        msg.Data[6], msg.ErrorFlags)
                    )
                elif msg.Length == 8:
                    print("{} ({:>14}) : 0x{:02X} {} - {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} [{}]".format(
                        msg.TimeStamp, delta, msg.FrameId, msg.Length,
                        msg.Data[0],
                        msg.Data[1],
                        msg.Data[2],
                        msg.Data[3],
                        msg.Data[4],
                        msg.Data[5],
                        msg.Data[6],
                        msg.Data[7], msg.ErrorFlags)
                    )

            time.sleep(0.000001)


if __name__ == '__main__':

    import threading

    fuzzer = LinFuzzer()
    fuzzer.connect("Fuzzer", 1, 1)
    fuzzer.set_global_frame_table()

    fuzzer.delete_schedule_table(0)
    fuzzer.set_schedule_table(0)
    fuzzer.get_schedule_table(0)

    fuzzer.update_schedule_data(0x32, [0x00])
    fuzzer.update_schedule_data(0x2B, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
    fuzzer.update_schedule_data(0x30, [0x00, 0x00, 0x00, 0x00])
    fuzzer.update_schedule_data(0x31, [0x00, 0x00, 0x00, 0x00])
    fuzzer.update_schedule_data(0x20, [0x00, 0x00])
    fuzzer.update_schedule_data(0x37, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])

[b]    readThread = threading.Thread(target=fuzzer.read, args=(,))
    readThread.start()[/b]

    fuzzer.start_schedule_table(0)
    time.sleep(5)
    fuzzer.suspend_schedule_table()
    
[b]    readThread.join()[/b]
    
    fuzzer.delete_schedule_table(0)

    fuzzer.disconnect()
    
If I add the readThread part, then the timings (Interval ov the Frames) are not correct.
Whats wrong with this approach?

Thanks,
Volker

Re: LIN Master - Schedule Table Processing and Read

Posted: Wed 18. Mar 2020, 13:51
by M.Heidemann
Hello Volker,

To quote:
If I add the readThread part, then the timings (Interval ov the Frames) are not correct.
Do you mean the delays between the messages of the shedule table?

As an additional info:

Once the shedule-table is started, it runs independently on the hardware.


Best Regards

Marvin