Hi gfvalvo,
The project was done a couple of years ago by someone who is unreachable right now, so I afraid that original library went through changes or I can't find original data
I'm copy pasting the code excluding many cases, just to show the idea:
/*********************
Program for the slave I2C/Master LIN module (Arduino Mega)
LIN communication Idents:
Diagnostic Request: 3C
Diagnostic Response: 3D
**********************/
// include files
#include <LIN_master_HardwareSerial.h>
#include <Wire.h>
//
//*** *** *** Define PINS ****************************************************
#define EnableLIN 53
#define MCU2_OK_LED 24
#define MCU2_BUSY_LED 25
//
//
//*** *** *** Enable debugging ***********************************************
const bool EnableConsole = true; // Serial debugging toggle
// *** Specify LIN commands used in the calibration process ******************
// Generic parameters
// LIN frame components
uint8_t MasterID = 0x3C; // Master node ID
uint8_t SlaveID = 0x3D; // Slave node ID
uint8_t NAD = 0x7F; // Node Address (fixed LIN standard)
uint8_t PCI = 0x06; // Protocol Control Information (fixed LIN standard)
uint8_t SID = 0xB4; // Service Identifier (fixed LIN standard)
uint8_t RSID = 0xF4; // Response Service Identifier (fixed LIN standard)
uint8_t K_Code = 0xDE; // Key code to enter in service mode
//uint8_t ActionType = 0x00; // Type of action depending on required task
//uint8_t Data_0 = 0x00; // EEPROM data
//uint8_t Data_1 = 0x00; // EEPROM data
//uint8_t Data_2 = 0x00; // EEPROM data
//*** *** *** Software and Hardware revision (0x50/0x53)
// Byte 5 (Data 0) - SW Indice (0x0)
// Byte 6 (Data 1) - SW Revision (0x0)
// Byte 7 (Data 2) - HW Revision (0x0)
// Registers holding the response values
uint8_t Read_SW_Indice = 0x00;
uint8_t Read_SW_Revision = 0x00;
uint8_t Read_HW_Revision = 0x00;
//uint8_t WriteRevision[8] = {NAD, PCI, SID, K_Code, 0x50, 0xData0, 0xData1, 0xData2};
//uint8_t Expected_Response[8] = {NAD, PCI, RSID, K_Code, 0x50, 0xData0, 0xData1, 0xData2};
uint8_t Read_SHRevision[8] = {NAD, PCI, SID, K_Code, 0x53, 0xFF, 0xFF, 0xFF};
uint8_t Read_SHRevision_Response[8] = {NAD, PCI, RSID, K_Code, 0x53, Read_SW_Indice, Read_SW_Revision, Read_HW_Revision};
// Registers holding the response values
uint8_t Read_ProdFlag_0 = 0x00;
uint8_t Read_ProdFlag_1 = 0x00;
uint8_t Read_ProdFlag_2 = 0x00;
//
uint8_t Write_ProdFlag_0F[8] = {NAD, PCI, SID, K_Code, 0x1A, ProdFlag_B5, ProdFlag_B6, ProdFlag_0F};
uint8_t Write_ProdFlag_1F[8] = {NAD, PCI, SID, K_Code, 0x1A, ProdFlag_B5, ProdFlag_B6, ProdFlag_1F};
uint8_t Write_ProdFlag_3F[8] = {NAD, PCI, SID, K_Code, 0x1A, ProdFlag_B5, ProdFlag_B6, ProdFlag_3F};
uint8_t Write_ProdFlag_7F[8] = {NAD, PCI, SID, K_Code, 0x1A, ProdFlag_B5, ProdFlag_B6, ProdFlag_7F};
uint8_t Write_ProdFlag_EF[8] = {NAD, PCI, SID, K_Code, 0x1A, ProdFlag_B5, ProdFlag_B6, ProdFlag_EF};
//uint8_t Expected_Response[8] = {NAD, PCI, SID, K_Code, 0x1A, 0xData0, 0xData1, 0xData2};
uint8_t Read_ProdFlag[8] = {NAD, PCI, SID, K_Code, 0x1B, 0xFF, 0xFF, 0xFF};
uint8_t Read_ProdFlag_Response[8] = {NAD, PCI, RSID, K_Code, 0x1B, Read_ProdFlag_0, Read_ProdFlag_1, Read_ProdFlag_2};
//
//
//
//
//
//
// *** Define Software Settings **********************************************
// pause between LIN frames
#define LIN_PAUSE 100
#define LIN_BANDWIDTH 9600
#define SERIAL_BANDWIDTH 115200
// skip serial output (for time measurements)
//#define SKIP_CONSOLE
// *** I2C Communication flags
#define SLAVE_ADDRESS 0x10 // I2C address of the slave
int i_I2C_triggerReceived = 0; // RECEIVED - TRIGGER
uint8_t B_I2C_bytesReceived[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // RECEIVED - DATA
//
int i_I2C_SlaveStatus = 0; // OUTGOING - STATUS OF SLAVE SEQUENCE
uint8_t B_I2C_bytesSent[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // OUTGOING - DATA
//
// *** Define LIN constants **************************************************
const uint16_t i_LIN_Pause = 100; // Pause between LIN frames
const uint8_t i_LIN_frameSize = 8; // Size of LIN message
//
// *** Sequence Variables ****************************************************
bool b_LIN_RequestExecuted = false; // Prevent repeatable execution (each task is executed only one unless it fails)
bool b_LIN_RequestError = false; // Flag up LIN error - request failed to be delivered
bool b_LIN_ReplyError = false; // Flag up LIN error - no response
bool b_LIN_CommandFailed = false; // Flag up LIN error - incorrect response
bool b_FirstTravelSaveRequired = false; // Flag marking updated first travel run and eeprom save required
uint8_t LIN_FrameId; // LIN frame identifier
uint8_t LIN_NumData; // LIN numerical data for incoming message
uint16_t ui_LIN_FrameCount = 0; // Frame count
uint32_t ui_LastLINFrame = 0; // Time stamp of the most recent LIN frame
uint8_t LIN_TX[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t LIN_RX[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint16_t i_lastTaskTracer = 9999; // Keep track of changing tasks for LIN state machine reset
/*********************
Class constructor
LIN_Master_HardwareSerial(HardwareSerial &Interface, const char NameLIN[]);
**********************/
LIN_Master_HardwareSerial LIN(Serial1, "LIN_HW"); // parameter: HW-interface, name
// *** SETUP ****** SETUP ****** SETUP ****** SETUP ****** SETUP ****** SETUP ***
void setup()
{
// indicate background operation
//pinMode(PIN_TOGGLE, OUTPUT);
// indicate LIN status via pin
//pinMode(PIN_ERROR, OUTPUT);
// Enable LIN (drive LIN ENABLE pin HIGH)
pinMode(EnableLIN, OUTPUT); // Declare EnableLIN pin as output
digitalWrite(EnableLIN, true); // Enable LIN pin
// open LIN interface
LIN.begin(LIN_BANDWIDTH);
// *** I2C COMMUNICATION
Wire.begin(SLAVE_ADDRESS); // open I2C interface
Wire.onReceive(I2C_receiveEvent); // Set up the receive event handler
Wire.onRequest(I2C_requestEvent); // Set up the request event handler
// for user interaction via console
Serial.begin(SERIAL_BANDWIDTH);
//while(!Serial);
//*** *** *** Setup hardware pins
pinMode(MCU2_OK_LED, OUTPUT); // Declare OK_LED pin as output
pinMode(MCU2_BUSY_LED, OUTPUT); // Declare BUSY_LED pin as output
digitalWrite(MCU2_OK_LED, true); // Update the MCU1_OK LED
digitalWrite(MCU2_BUSY_LED, false); // Update the BUSY LED
Serial.println("HARDWARE SETUP COMPLETE...");
Serial.println("STATUS LED SHOULD BE ON NOW...");
} // setup()
// *** LOOP ****** LOOP ****** LOOP ****** LOOP ****** LOOP ****** LOOP ***
void loop()
{
// Static variables
LIN_Master::LIN_frame_t LIN_Type;
LIN_Master::error_t LIN_Error;
//*** *** *** Await I2C data/request
I2C_receiveEvent(); // Receive data from master
// Print incoming data to console if console enabled
switch (i_I2C_triggerReceived){
case 1: // 0x53 Read software and hardware revision
digitalWrite(MCU2_BUSY_LED, true); // Update the BUSY LED
if(!b_LIN_RequestExecuted && !b_LIN_RequestError && !b_LIN_ReplyError){i_I2C_SlaveStatus = 1010;I2C_requestEvent();}
updateCommand(Read_SHRevision, LIN_TX); // Update command that needs to be send to the motor
// Check if this request was already executed
// (Prevent the request looped execution)
if (!b_LIN_RequestExecuted) {
//if (EnableConsole) {Serial.print("\t");Serial.print(" Master_Requested_Task: Read software and hardware revision"); Serial.println(" *");} // Provide feedback if console enabled
// Check if LIN frame has finished
LIN.handler(); // Run LIN in background handler
runLIN_Scheduler();
//resetLIN_atTaskChange();
if (LIN.getState() == LIN_Master::STATE_DONE){
// Get frame data
// LIN version_t : 1 (version 1.x), 2 (version 2.x)
// LIN frame_t : 1 (MASTER_REQUEST), 2 (SLAVE_RESPONSE)
// LIN state_t : 0 (STATE_OFF), 1 (STATE_IDLE), 2 (STATE_BREAK), 3 (STATE_BODY), 4 (STATE_DONE)
// LIN error_t : 0x00 (NO_ERROR), 0x01 (ERROR_STATE), 0x02 (ERROR_ECHO), 0x04 (ERROR_TIMEOUT), 0x08 (ERROR_CHK), 0x80 (ERROR_MISC)
LIN.getFrame(LIN_Type, LIN_FrameId, LIN_NumData, LIN_RX); // Get LIN frame data
// Inspect LIN MASTER COMMAND for ERRORS
if (LIN_Type == LIN_Master::MASTER_REQUEST){
if (LIN.getError() == LIN_Master::NO_ERROR){b_LIN_RequestError = false;}else{b_LIN_RequestError = true;}
}
//
// IF no request errors then proceed to reply
if(!b_LIN_RequestError){
if (LIN_Type == LIN_Master::SLAVE_RESPONSE){
if(LIN.getError() == LIN_Master::NO_ERROR) {
// Read the response to confirm that command
// has executed correctly
if (LIN_RX[4] == Read_SHRevision_Response[4]){b_LIN_CommandFailed = false;}
else{
b_LIN_CommandFailed = true;
B_I2C_bytesSent[0] = 0x00;
B_I2C_bytesSent[1] = 0x00;
B_I2C_bytesSent[2] = 0x00;
}
if (!b_LIN_CommandFailed) {
// Assign speciffic data to output feedback array
resetI2C_Feedback(); // Reset feedback to master
B_I2C_bytesSent[0] = LIN_RX[5];
B_I2C_bytesSent[1] = LIN_RX[6];
B_I2C_bytesSent[2] = LIN_RX[7];
b_LIN_RequestExecuted = true;
b_LIN_ReplyError = false;
}
}
else{
B_I2C_bytesSent[0] = 0x00;
B_I2C_bytesSent[1] = 0x00;
B_I2C_bytesSent[2] = 0x00;
b_LIN_RequestExecuted = false;
b_LIN_ReplyError = true;
}
}
}
LIN.resetStateMachine();
LIN.resetError();
//
}
}
// Share results feedback with slave
if(b_LIN_RequestError){i_I2C_SlaveStatus = 1016;I2C_requestEvent();delay(1);} // Request failed
if(b_LIN_ReplyError){i_I2C_SlaveStatus = 1017;I2C_requestEvent();delay(1);} // Response failed
if(b_LIN_CommandFailed){i_I2C_SlaveStatus = 1018;I2C_requestEvent();delay(1);} // Incorrect response
if(b_LIN_RequestExecuted){i_I2C_SlaveStatus = 1019;I2C_requestEvent();delay(1);} // Command successful
break;
default: // No task
digitalWrite(MCU2_BUSY_LED, false); // Update the BUSY LED
i_I2C_SlaveStatus = 100; // IDLE
b_LIN_RequestExecuted = false; // Reset flag preventing LIN command re-execution
b_LIN_RequestError = false; // Reset LIN error flag
b_LIN_ReplyError = false; // Reset LIN error flag
b_LIN_CommandFailed = false; // Reset LIN error flag
//
//if (EnableConsole) {Serial.print("\t");Serial.print(" IDLE"); Serial.println(" *");}
//
LIN.resetStateMachine();
LIN.resetError();
delay(1);
break;
}
}
//*** *** *** Copy command array before sending it to the actuator
void updateCommand(uint8_t* src, uint8_t* dst) {
memcpy(dst, src, sizeof(src[0])*8);
}
//*** *** *** Reset data in I2C feedback and response
void resetI2C_Feedback() {
i_I2C_SlaveStatus = 100;
for (uint8_t i=0; (i < 8); i++)
{B_I2C_bytesSent[i] = 0x00; }
}
// Function to handle when the slave receives data from the master
void I2C_receiveEvent() {
if (Wire.available()) {
i_I2C_triggerReceived = (Wire.read() << 8) | Wire.read(); // Receive integer (2 bytes)
B_I2C_bytesReceived[0] = Wire.read(); // Receive byte 1
B_I2C_bytesReceived[1] = Wire.read(); // Receive byte 2
B_I2C_bytesReceived[2] = Wire.read(); // Receive byte 3
B_I2C_bytesReceived[3] = Wire.read(); // Receive byte 4
B_I2C_bytesReceived[4] = Wire.read(); // Receive byte 5
B_I2C_bytesReceived[5] = Wire.read(); // Receive byte 6
B_I2C_bytesReceived[6] = Wire.read(); // Receive byte 7
B_I2C_bytesReceived[7] = Wire.read(); // Receive byte 8
}
}
// Function to handle when the slave sends data to the master
void I2C_requestEvent() {
Wire.write((byte*)&i_I2C_SlaveStatus, sizeof(i_I2C_SlaveStatus)); // Send the feedback from slave - LIN module
Wire.write(B_I2C_bytesSent, sizeof(B_I2C_bytesSent)); // Send the 8-byte array back
//Serial.println(i_I2C_SlaveStatus);
}
// Activate LIN interface
void runLIN_Scheduler () {
if (millis() - ui_LastLINFrame > i_LIN_Pause)
{
ui_LastLINFrame = millis();
if (ui_LIN_FrameCount == 0)
{ui_LIN_FrameCount++; LIN.sendMasterRequest(LIN_Master::LIN_V1, MasterID, i_LIN_frameSize, LIN_TX);} // Run LIN master request - send command to motor
else
{ui_LIN_FrameCount = 0; LIN.receiveSlaveResponse(LIN_Master::LIN_V1, SlaveID, i_LIN_frameSize);} // Run LIN slave request - listen to data incoming from motor
}
}
// Reset LIN state machine if task changes
void resetLIN_atTaskChange(){
if (i_I2C_triggerReceived != i_lastTaskTracer) {
b_LIN_RequestExecuted = false; // Reset flag preventing LIN command re-execution
b_LIN_RequestError = false; // Reset LIN error flag
b_LIN_ReplyError = false; // Reset LIN error flag
LIN.resetStateMachine();
LIN.resetError();
i_lastTaskTracer = i_I2C_triggerReceived; // Update last task register
delay(1);
}
}