Communicate via LIN Advanced

Motivation

LIN is commonly used as an inexpensive and decently reliable way for peripherals to communicate and can in some cases
be required to communicate with a device under test. The miniHIL is also capable of simulating LIN masters and slaves
and communicating over a CAN bus. For more information on how to set this up, read the
LIN bus adapter guide.

In this tutorial we will set up a LIN master, slave and scheduler to send messages from the slave to the master
without using the CAN bus, then output the data that the master receives.

Pre-requisites

On the miniHIL, the pins PD0(RX) and PD1(TX) are used by the LIN adapter. In our case, since we aren’t using
the bus, we simply connect the two pins together.

To prepare the SW create a new project as described in the "Creating a new project" How-To.

Finally, to be able to see some output, make sure you can log as described in here. Note that in this case you only need the USB connection. Log messages will be generated by the LIN tester below.

Instantiate the LIN in software

In this project, we will create three actors: The LIN master, LIN slave and a LIN tester that is used to select the
master’s schedule, start the master and slave and log data.

As a container we will use the Application contained in MiniHILApplication.room. So open the file in your newly
created project and go to the Structure Section of the Application actor.
There, create instances of the LIN actors as shown below.

RoomModel MiniHilProject {
	//...
	import etrice.api.interrupt.PInterrupt
	import etrice.api.timer.PTimer
	import etrice.api.logger.PLogger 1

	import busadapters.api.lin.PLinPayload
	import busadapters.api.lin.PLinCtrl
	import busadapters.api.lin.PLinCtrlScheduler 2
	import busadapters.platform.lin.ALinMasterController
	import busadapters.platform.lin.ALinSlaveController 3

	ActorClass Application {
		Structure {
			//	  ...
			ActorRef slaveDevice: ALinSlaveDeviceController
			ActorRef masterDevice: ALinDeviceMasterController
			ActorRef linTester: ALinTester 4
		}
	}
1 Imports for logging, timing and interrupts.
2 Imports the required ports.
3 Import the abstractions for master and slave.
4 Instantiate the actors.

We will need to implement ALinSlaveDeviceController and ALinDeviceMasterController and currently these instantiations
will show errors.

In the following sections, we will implement and define the different actors behavior. Since the LIN hardware is abstracted by
further actors, we will only have to define frame tables and a schedule for the master in order for the nodes
to communicate. The only state needed to define our master and slave’s behavior is an initialization state.
If you are interested in details set the cursor on ALinMasterController and press F3.

Implementing the LIN master

For the master to communicate with its slaves, it will need a frame table, indicating which IDs it stores and whether
it wants to send or receive the corresponding data, and a scheduler table showing when the data should be transfered.

In our example, we will use the following code. We can see that a frame table is defined, as well as multiple schedules.
This example will only execute LIN_SchedulerTableEntries_DefaultTable, however for future projects it can be useful to
know how to define further schedules to, for example, share the diagnostic frames with ID 60 and 61.
Scheduler tables are defined by first creating a list of scheduler entries and then storing them in a LIN_SchedulerTable type
along with the number of entries.

We can also see that a ALinMasterController actor is defined inside of the master. This acts as our abstraction of the LIN hardware.

ActorClass ALinDeviceMasterController {
    Interface {
        Port payload: PLinPayload
        Port ctrl: PLinCtrl
        Port ctrlScheduler[5]: PLinCtrlScheduler 1
    }
    Structure {
        usercode3 '''
            #include "busadapters/platform/lin/LinImpl.h"2

				/* LIN Node Frame Table
				{ id, length, store/send, data}*/
				static const LIN_FrameTableEntry LIN_FrameTable_Controller[5] = {3
				    {1, 3, own, {0xAA,0x55,23,0,0,0,0,0,0}},	// own = store data
				    {2, 8, ofInterest, {0,0,0,0,0,0,0,0,0}},	// ofInterest = send data
				    {3, 8, ofInterest, {0,0xFF,0,0,0,0,0,0,0}},
				    {60, 8, own, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}},
				    {61, 8, ofInterest, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}}
				};
				/* LIN Node Scheduler Table(s) */
				/* LIN_SchedulerEntry
				 * @param type: unconditional or sporadic, see wikipedia for info on frame types
				 * @param fid: number to identify frame
				 * @param delay: how often to transmit/request frame
				 * @param typeSpecificData: void pointer for unconditional/sporadic data
				 */
				// table 1
				static const LIN_SchedulerEntry LIN_SchedulerTableEntries_DefaultTable[] = {4
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 1, .delay = 100.0, .typeSpecificData = NULL},
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 2, .delay = 100.0, .typeSpecificData = NULL},
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 3, .delay = 100.0, .typeSpecificData = NULL}
				};
				static const LIN_SchedulerTable LIN_SchedulerTable_DefaultTable = {5
				    3,	// table length
				    LIN_SchedulerTableEntries_DefaultTable
				};
				// table 2
				static const LIN_SchedulerEntry LIN_SchedulerTableEntries_ControllerFrameOnly[] = {
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 1, .delay = 100.0, .typeSpecificData = NULL}
				};
				static const LIN_SchedulerTable LIN_SchedulerTable_ControllerFrameOnly = {
				    1,
				    LIN_SchedulerTableEntries_ControllerFrameOnly
				};
				// table 3
				static const LIN_SchedulerEntry LIN_SchedulerTableEntries_MasterReqTable[] = {
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 60, .delay = 20.0, .typeSpecificData = NULL}
				};
				static const LIN_SchedulerTable LIN_SchedulerTable_MasterReqTable = {
				    1,
				    LIN_SchedulerTableEntries_MasterReqTable
				};
				// table 4
				static const LIN_SchedulerEntry LIN_SchedulerTableEntries_SlaveRespTable[] = {
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 61, .delay = 20.0, .typeSpecificData = NULL}
				};
				static const LIN_SchedulerTable LIN_SchedulerTable_SlaveRespTable = {
				    1,
				    LIN_SchedulerTableEntries_SlaveRespTable
				};
				// table 5
				static const LIN_SchedulerEntry LIN_SchedulerTableEntries_DiagMasterSlaveTable[] = {
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 60, .delay = 20.0, .typeSpecificData = NULL},
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 61, .delay = 20.0, .typeSpecificData = NULL}
				};
				static const LIN_SchedulerTable LIN_SchedulerTable_DiagMasterSlaveTable = {
				    2,
				    LIN_SchedulerTableEntries_DiagMasterSlaveTable
				};

				static const LIN_SchedulerTable * LIN_SchedulerTableList_Controller[] = {6
				    &LIN_SchedulerTableNull,
				    &LIN_SchedulerTable_DefaultTable,
				    &LIN_SchedulerTable_ControllerFrameOnly,
				    &LIN_SchedulerTable_MasterReqTable,
				    &LIN_SchedulerTable_SlaveRespTable,
				    &LIN_SchedulerTable_DiagMasterSlaveTable
				};
			'''
        conjugated Port rxInterrupt: PInterrupt
        ActorRef controller: ALinMasterController 7
        Binding rxInterrupt and controller.rxDataIsr
        Binding controller.payload and payload
        Binding controller.ctrl and ctrl
        Binding controller.ctrlScheduler and ctrlScheduler
    }
    Behavior {
        StateMachine {
            State Operational
            Transition init: initial -> Operational { 8
                action '''
					// initialize LIN master
                    LIN_InitData initData = {
                        .baudRateBps = 19200
                    };
                    LIN_init(&initData);
                    LIN_configureSchedulerTableList(LIN_SchedulerTableList_Controller, 0);
                    LIN_registerDataRxPort(rxInterrupt.export(), LIN_FrameTable_Controller, 5);
                '''
            }
        }
    }
}
1 Add the required ports
2 Import definitions for frames, schedules and initialization functions.
3 Frames to be sent/received.
4 Scheduler table entries.
5 Scheduler table.
6 List of schedules to pass to master abstraction.
7 Instantiation of master abstraction and required port connections.
8 Initialization behavior.

Implementing the LIN slave

Similar to the master, we will have to define the slave’s frame table and initialize the slave. For this, we use the following code:

ActorClass ALinSlaveDeviceController {
    Interface {
        Port payload: PLinPayload
        Port ctrl: PLinCtrl 1
    }
    Structure {
        usercode3 '''
            #include "busadapters/platform/lin/LinImpl.h" 2

            /* LIN Node Frame Table
            { id, length, store/send, data}*/
            static const LIN_FrameTableEntry LIN_FrameTable_Device2[4] = { 3
                {3, 8, own, {1,2,3,4,5,6,7,8,0}},	// own = store data
                {1, 3, ofInterest, {0,0,0,0,0,0,0,0,0}},	// ofInterest = send data
                {60, 8, ofInterest, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}},
                {61, 8, own, {0x01,0x02,0x03,0xFF,0xFF,0xFF,0xFF,0xFF}}
            };
        '''
        conjugated Port rxInterrupt: PInterrupt
        ActorRef controller: ALinSlaveController 4
        Binding rxInterrupt and controller.rxDataIsr
        Binding controller.payload and payload
        Binding controller.ctrl and ctrl
        SAP timer: PTimer
    }
    Behavior {
        StateMachine {
            State Operational
            Transition init: initial -> Operational { 5
				// initialize LIN slave
                action '''
                    LIN_InitData initData = {
                        .baudRateBps = 19200
                    };
                    LIN_init(&initData);
                    LIN_registerDataRxPort(rxInterrupt.export(), LIN_FrameTable_Device2, 4);
                '''
            }
        }
    }
}
1 Add the required ports
2 Import definitions for frames, schedules and initialization functions.
3 Frames to be sent/received.
4 Instantiation of slave abstraction and required port connections.
5 Initialization behavior.

Implementing the LIN tester

We now add the code for the LIN tester. This involves connecting the tester to both master and slave, starting the
master and slave while also selecting the master’s schedule, and updating the slave’s data. This is all controlled
using the ports. The master’s schedulerCtrl is used to select the schedule to use, the masterCtrl and slaveCtrl
ports start the nodes and the payload ports can be used to update and read data.

In our example, we will update the slave’s data in frame 3 with an incrementing counter and then run
the master’s default schedule once per second. When a frame entry in the table is updated, the data
is automatically sent through the payload port. We will also add a state that reacts to this change
and logs the data.

Enumeration ELinScheduleTableSimpleDevice of uint8 {
    Null = 0,
    DefaultTable = 1,
    ControllerFrameOnly = 2,
    MasterReqTable = 3,
    SlaveRespTable = 4,
    DiagMasterSlaveTable = 5
}

ActorClass ALinTester {
    Interface {
        conjugated Port masterPayload: PLinPayload 1
        conjugated Port masterCtrl: PLinCtrl
        conjugated Port slaveCtrl: PLinCtrl
        conjugated Port schedulerCtrl: PLinCtrlScheduler
        conjugated Port slavePayload: PLinPayload
    }
    Structure {
        usercode3 '''
            #include "ELinScheduleTableSimpleDevice.h"
        '''
        external Port masterPayload 2
        external Port masterCtrl
        external Port slaveCtrl
        external Port schedulerCtrl
        external Port slavePayload
        SAP timer: PTimer
        SAP timerUpate: PTimer
        SAP logger: PLogger
        Attribute counter: uint8 = "0"
    }
    Behavior {
		StateMachine {
			State configuring
			State setupScheduler
			Transition init0: initial -> configuring {
				action '''
					timer.startTimeout(1000);
				'''
			}
			Transition tr0: configuring -> setupScheduler {
				triggers {
					<timeout: timer>
				}
				// configure master and slave and start communication
				action '''3
					masterCtrl.start();
					slaveCtrl.start();
					schedulerCtrl.break();
					schedulerCtrl.notifyRolloverScheduleDone(false);
					DLinScheduleState defaultSchedule = {ELinScheduleTableSimpleDevice_DefaultTable, 1};
					schedulerCtrl.schedule(&defaultSchedule);	// select master schedule
					timer.startTimeout(1000);
				'''
			}
			State scheduleDone
			Transition tr1: setupScheduler -> scheduleDone {
				triggers {
					<scheduleDone: schedulerCtrl>
				}
				action '''timer.startTimeout(1000);'''
			}
			Transition tr2: scheduleDone -> scheduleDone {
				triggers {
					<scheduleDone: schedulerCtrl>
				}
				action '''timer.startTimeout(1000);'''
			}
			Transition tr3: scheduleDone -> scheduleDone {
				// periodically set slave data
				triggers {
					<timeout: timer>
				}
				action '''4
					DLinPayload slaveData;
					slaveData.fid = 0x03;
					slaveData.data[0] = counter;
					slaveData.data[1] = counter;
					slaveData.data[2] = counter;
					slaveData.data[3] = counter;
					slaveData.data[4] = counter;
					slaveData.data[5] = counter;
					slaveData.data[6] = counter;
					slaveData.data[7] = counter;
					counter++;
					slavePayload.setData(&slaveData);	// set slave data
					schedulerCtrl.runOnce();	// run schedule once'''
			}
			Transition log: scheduleDone -> scheduleDone {
				// master automatically sends data over payload, we capture this and process it
				triggers {
					<data: masterPayload>
				}
				action '''5
					logger.logF("(Master) fid: %x, data: %x, %x, %x, %x, %x, %x, %x", transitionData->fid, transitionData->data[0], transitionData->data[1], transitionData->data[2], transitionData->data[3], transitionData->data[4], transitionData->data[5], transitionData->data[6]);
					logger.log("------------------------");
				'''
			}
        }
    }
}
1 Ports for communicating with master and slave.
2 Instantiate ports, timer, logger and counter.
3 Select schedule and start master and slave.
4 update slave data and run schedule once.
5 Log updated data.

Connect the tester to the nodes

Finally before being able to run the code, we need to update our MiniHilProject.room application to connect the test
to the nodes.

RoomModel MiniHilProject {
	ActorClass Application {
		Structure {
			//	  ...
			ActorRef slaveDevice: ALinSlaveDeviceController
			ActorRef masterDevice: ALinDeviceMasterController
			ActorRef linTester: ALinTester
			Binding linTester.masterCtrl and masterDevice.ctrl
			Binding linTester.masterPayload and masterDevice.payload
			Binding linTester.schedulerCtrl and masterDevice.ctrlScheduler
			Binding linTester.slaveCtrl and slaveDevice.ctrl
			Binding linTester.slavePayload and slaveDevice.payload 1
		}
	}
1 Bindings between tester and nodes.

Running the example

Once you have flashed and started the target you should see output like this in your terminal.

LIN example output
(Master) fid: 3, data: 0, 0, 0, 0, 0, 0, 0
------------------------
(Master) fid: 3, data: 1, 1, 1, 1, 1, 1, 1
------------------------
(Master) fid: 3, data: 2, 2, 2, 2, 2, 2, 2
------------------------
(Master) fid: 3, data: 3, 3, 3, 3, 3, 3, 3
------------------------

Summary

  • Instantiate LIN master and slave

  • Create schedules and frame tables

  • Set and read master and slave’s data

See Also

Complete example file

RoomModel MiniHilProject {
	import etrice.api.timer.PTimer
	import etrice.api.logger.PLogger
	import etrice.api.interrupt.PInterrupt

	// LIN imports
	import busadapters.api.lin.PLinPayload
	import busadapters.api.lin.PLinCtrl
	import busadapters.api.lin.PLinCtrlScheduler
	import busadapters.platform.lin.ALinMasterController
	import busadapters.platform.lin.ALinSlaveController

	/**
	 * The "root" of every miniHIL test project is the Application actor which should be defined in the MiniHilProject.room file (This file, the ActorClass below).
	 * This actor commonly contains the (one and only) test actor (of the system), the simulation elements and any other actors which are used in conjunction with the test cases.
	 * Usually this actor also contains all or most of the Actors which provide the hardware abstraction (e.g. UART, DigitalIN/OUT, AnalogIn/OUT, etc.).
	 */
	ActorClass Application {
		Structure {
			// LIN main and test actors
			ActorRef slaveDevice: ALinSlaveDeviceController
			ActorRef masterDevice: ALinDeviceMasterController
			ActorRef linTester: ALinTester
			Binding linTester.masterCtrl and masterDevice.ctrl
			Binding linTester.masterPayload and masterDevice.payload
			Binding linTester.schedulerCtrl and masterDevice.ctrlScheduler
			Binding linTester.slaveCtrl and slaveDevice.ctrl
			Binding linTester.slavePayload and slaveDevice.payload
		}
	}

	Enumeration ELinScheduleTableSimpleDevice of uint8 {
		Null = 0,
		DefaultTable = 1,
		ControllerFrameOnly = 2,
		MasterReqTable = 3,
		SlaveRespTable = 4,
		DiagMasterSlaveTable = 5
	}

	ActorClass ALinTester {
		Interface {
			conjugated Port masterPayload: PLinPayload
			conjugated Port masterCtrl: PLinCtrl
			conjugated Port slaveCtrl: PLinCtrl
			conjugated Port schedulerCtrl: PLinCtrlScheduler
			conjugated Port slavePayload: PLinPayload
		}
		Structure {
			usercode3 '''
				#include "ELinScheduleTableSimpleDevice.h"
			'''
			external Port masterPayload
			external Port masterCtrl
			external Port slaveCtrl
			external Port schedulerCtrl
			external Port slavePayload
			SAP timer: PTimer
			SAP timerUpate: PTimer
			SAP logger: PLogger
			Attribute counter: uint8 = "0"
		}
		Behavior {
			StateMachine {
				State configuring
				State setupScheduler
				Transition init0: initial -> configuring {
					action '''
						timer.startTimeout(1000);
					'''
				}
				Transition tr0: configuring -> setupScheduler {
					triggers {
						<timeout: timer>
					}
					// configure master and slave and start communication
					action '''
						masterCtrl.start();
						slaveCtrl.start();
						schedulerCtrl.break();
						schedulerCtrl.notifyRolloverScheduleDone(false);
						DLinScheduleState defaultSchedule = {ELinScheduleTableSimpleDevice_DefaultTable, 1};
						schedulerCtrl.schedule(&defaultSchedule);	// select master schedule
						timer.startTimeout(1000);
					'''
				}
				State scheduleDone
				Transition tr1: setupScheduler -> scheduleDone {
					triggers {
						<scheduleDone: schedulerCtrl>
					}
					action '''timer.startTimeout(1000);'''
				}
				Transition tr2: scheduleDone -> scheduleDone {
					triggers {
						<scheduleDone: schedulerCtrl>
					}
					action '''timer.startTimeout(1000);'''
				}
				Transition tr3: scheduleDone -> scheduleDone {
					// periodically set slave data
					triggers {
						<timeout: timer>
					}
					action '''
						DLinPayload slaveData;
						slaveData.fid = 0x03;
						slaveData.data[0] = counter;
						slaveData.data[1] = counter;
						slaveData.data[2] = counter;
						slaveData.data[3] = counter;
						slaveData.data[4] = counter;
						slaveData.data[5] = counter;
						slaveData.data[6] = counter;
						slaveData.data[7] = counter;
						counter++;
						slavePayload.setData(&slaveData);	// set slave data
						schedulerCtrl.runOnce();	// run schedule once'''
				}
				Transition log: scheduleDone -> scheduleDone {
					// master automatically sends data over payload, we capture this and process it
					triggers {
						<data: masterPayload>
					}
					action '''
						logger.logF("(Master) fid: %x, data: %x, %x, %x, %x, %x, %x, %x", transitionData->fid, transitionData->data[0], transitionData->data[1], transitionData->data[2], transitionData->data[3], transitionData->data[4], transitionData->data[5], transitionData->data[6]);
						logger.log("------------------------");
					'''
				}
			}
		}
	}

	ActorClass ALinSlaveDeviceController {
		Interface {
			Port payload: PLinPayload
			Port ctrl: PLinCtrl
		}
		Structure {
			usercode3 '''
				#include "busadapters/platform/lin/LinImpl.h"

				/* LIN Node Frame Table
				{ id, length, store/send, data}*/
				static const LIN_FrameTableEntry LIN_FrameTable_Device2[4] = {
				    {3, 8, own, {1,2,3,4,5,6,7,8,0}},	// own = store data
				    {1, 3, ofInterest, {0,0,0,0,0,0,0,0,0}},	// ofInterest = send data
				    {60, 8, ofInterest, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}},
				    {61, 8, own, {0x01,0x02,0x03,0xFF,0xFF,0xFF,0xFF,0xFF}}
				};
			'''
			conjugated Port rxInterrupt: PInterrupt
			ActorRef controller: ALinSlaveController
			Binding rxInterrupt and controller.rxDataIsr
			Binding controller.payload and payload
			Binding controller.ctrl and ctrl
			SAP timer: PTimer
		}
		Behavior {
			StateMachine {
				State Operational
				Transition init: initial -> Operational {
					// initialize LIN slave
					action '''
						LIN_InitData initData = {
						    .baudRateBps = 19200
						};
						LIN_init(&initData);
						LIN_registerDataRxPort(rxInterrupt.export(), LIN_FrameTable_Device2, 4);
					'''
				}
			}
		}
	}

	ActorClass ALinDeviceMasterController {
		Interface {
			Port payload: PLinPayload
			Port ctrl: PLinCtrl
			Port ctrlScheduler[5]: PLinCtrlScheduler
		}
		Structure {
			usercode3 '''
				#include "busadapters/platform/lin/LinImpl.h"

				/* LIN Node Frame Table
				{ id, length, store/send, data}*/
				static const LIN_FrameTableEntry LIN_FrameTable_Controller[5] = {
				    {1, 3, own, {0xAA,0x55,23,0,0,0,0,0,0}},	// own = store data
				    {2, 8, ofInterest, {0,0,0,0,0,0,0,0,0}},	// ofInterest = send data
				    {3, 8, ofInterest, {0,0xFF,0,0,0,0,0,0,0}},
				    {60, 8, own, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}},
				    {61, 8, ofInterest, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}}
				};
				/* LIN Node Scheduler Table(s) */
				/* LIN_SchedulerEntry
				 * @param type: unconditional or sporadic, see wikipedia for info on frame types
				 * @param fid: number to identify frame
				 * @param delay: how often to transmit/request frame
				 * @param typeSpecificData: void pointer for unconditional/sporadic data
				 */
				// table 1
				static const LIN_SchedulerEntry LIN_SchedulerTableEntries_DefaultTable[] = {
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 1, .delay = 100.0, .typeSpecificData = NULL},
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 2, .delay = 100.0, .typeSpecificData = NULL},
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 3, .delay = 100.0, .typeSpecificData = NULL}
				};
				static const LIN_SchedulerTable LIN_SchedulerTable_DefaultTable = {
				    3,	// table length
				    LIN_SchedulerTableEntries_DefaultTable
				};
				// table 2
				static const LIN_SchedulerEntry LIN_SchedulerTableEntries_ControllerFrameOnly[] = {
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 1, .delay = 100.0, .typeSpecificData = NULL}
				};
				static const LIN_SchedulerTable LIN_SchedulerTable_ControllerFrameOnly = {
				    1,
				    LIN_SchedulerTableEntries_ControllerFrameOnly
				};
				// table 3
				static const LIN_SchedulerEntry LIN_SchedulerTableEntries_MasterReqTable[] = {
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 60, .delay = 20.0, .typeSpecificData = NULL}
				};
				static const LIN_SchedulerTable LIN_SchedulerTable_MasterReqTable = {
				    1,
				    LIN_SchedulerTableEntries_MasterReqTable
				};
				// table 4
				static const LIN_SchedulerEntry LIN_SchedulerTableEntries_SlaveRespTable[] = {
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 61, .delay = 20.0, .typeSpecificData = NULL}
				};
				static const LIN_SchedulerTable LIN_SchedulerTable_SlaveRespTable = {
				    1,
				    LIN_SchedulerTableEntries_SlaveRespTable
				};
				// table 5
				static const LIN_SchedulerEntry LIN_SchedulerTableEntries_DiagMasterSlaveTable[] = {
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 60, .delay = 20.0, .typeSpecificData = NULL},
				    {.type = LIN_ScheduleEntryType_UNCONDITIONAL, .fid = 61, .delay = 20.0, .typeSpecificData = NULL}
				};
				static const LIN_SchedulerTable LIN_SchedulerTable_DiagMasterSlaveTable = {
				    2,
				    LIN_SchedulerTableEntries_DiagMasterSlaveTable
				};

				static const LIN_SchedulerTable * LIN_SchedulerTableList_Controller[] = {
				    &LIN_SchedulerTableNull,
				    &LIN_SchedulerTable_DefaultTable,
				    &LIN_SchedulerTable_ControllerFrameOnly,
				    &LIN_SchedulerTable_MasterReqTable,
				    &LIN_SchedulerTable_SlaveRespTable,
				    &LIN_SchedulerTable_DiagMasterSlaveTable
				};
			'''
			conjugated Port rxInterrupt: PInterrupt
			ActorRef controller: ALinMasterController
			Binding rxInterrupt and controller.rxDataIsr
			Binding controller.payload and payload
			Binding controller.ctrl and ctrl
			Binding controller.ctrlScheduler and ctrlScheduler
		}
		Behavior {
			StateMachine {
				State Operational
				Transition init: initial -> Operational {
					// initialize LIN master
					action '''
						LIN_InitData initData = {
						    .baudRateBps = 19200
						};
						LIN_init(&initData);
						LIN_configureSchedulerTableList(LIN_SchedulerTableList_Controller, 0);
						LIN_registerDataRxPort(rxInterrupt.export(), LIN_FrameTable_Controller, 5);
					'''
				}
			}
		}
	}
}