Need help with LIN Master

Hello,
I'm new to Arduino programming and LIN
Right now I'm working on a project that was done by engineer that is not available, so I'm trying to understand the program that he left and there is an issue I can't understand:
There is a usage of type that I can't find where is defined or declared. Just need a clue or direction to where to look.

There is an include "#include <LIN_master_HardwareSerial.h>" and interface?
LIN_Master_HardwareSerial LIN(Serial1, "LIN_HW");

And afterwards there are declarations of following type:
LIN_Master::frame_t LIN_Type;
LIN_Master::error_t LIN_Error;
and similar. Compiler doesn't recognise any of them, so my question is, what can I be missing?
Error message :
"\Arduino Code\Slave Mega\Box_Slave_V3_ino\Box_Slave_V3_ino.ino:328:3: error: 'LIN_Master' has not been declared
LIN_Master::frame_t LIN_Type;
^~~~~~~~~~"

Thank you
Zeev

Just type copy/paste that into a Google search and the github link will be shown, OR just goto the github site and use it's search.

do you have “LIN_master_HardwareSerial.h” and .cpp files in the IDE libraries folder?

Yes, I do , among other files.
I tried without these files and compiler tell me that LIN_master_HardwareSerial.h is not found.
I can't understand what "LIN_Master::frame_t" or "LIN_Master::error_t" refer to.
Is it some kind of declaration that supposed to be in .h file?
Best regards

I have this file in library folder, its probably not the issue.

Nobody will be able to help you without supplying the complete code. And, perhaps more importantly, we'll need the code for the LIN_master_HardwareSerial library. Where did you get it? Supply its link on GitHub.

Before posting any code, read this and learn to do it properly with code tags:
How to get the best out of this forum

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);
      }
  }

Haver you installed the library?

Have you tried using older versions of the library that were available at the time the sketch was written? Sometimes a library will have changes that break compatibility with earlier code.

The compile should be stopping with an error at the include statement if the library cannot be found. That does not mean that you have the correct library, but I’m only seeing one library in my quick google search.

Maybe if the OP posted the complete verbose error log it would be helpful.
Also post the location of the

#include <LIN_master_HardwareSerial.h>

I tried github but not found

It looks like this is the library:
https://github.com/gicking/LIN_master_portable_Arduino

Those are types defined in the scope of the LIN_MASTER class. It looks like your code was written for an old version of the library. Starting in v1.3 (Dec, 2024), the class's name was changed to LIN_Master_Base. You might try installing v1.2 of the library.

Hi,
I don't know where to find the older library that probably was working here.
I can just download the latest version.

Thank you.
I will try to do it. When I asked Co-pilot about this problem, it clearly told me not to use the "base" variant but to try the original Lin_master class. When I tried to include this class I saw there was a "Tasks" class that is missing. So I was not sure if I need to keep adding classes.

It's a part of this package

And how did that advice work out for you?

That's what I provided in Post #12. But you haven't yet told us which version (Rev) you have installed.

On the GitHub page, look at the right column where it says "Releases 10". Beneath that is "+9 releases", click on that. You will see a list of all the releases, under each of which is an "Assets" tab, where there are zip and tar.gz files containing that release.

They're also available in the Library Manager:

Hello, Sorry for a late response, I was away from this project. I managed to change and compile the project for Arduino Mega (slave)
Now I have a different problem compiling a project part for Arduino Uno, master file that talks to PLC.
It complains specifically about #include "ModbusIP.h" , specificing that certain functionality is not there
ModbusIP mb;

// Add MODBUS registers for data coming from PLC
  mb.addHreg (i_PLC_TriggerReg);

  // Add MODBUS registers for data outgoing to PLC
  mb.addIreg (i_HeartBeat_Reg);
  mb.addIreg (i_PLC_MasterStatusReg);
  mb.addIreg (i_PLC_SlaveStatusReg);
  mb.addIreg (i_PLC_RequestAcknReg);
  mb.addIreg (i_PLC_Data_SWIndice_Reg);
  mb.addIreg (i_PLC_Data_SWRev_Reg);
  mb.addIreg (i_PLC_Data_HWRev_Reg);
  mb.addIreg (i_PLC_Data_ProdDateYear_Reg);
  mb.addIreg (i_PLC_Data_ProdDateMonth_Reg);

And so on.
I get the following errors from the type:
error: 'class ModbusIP' has no member named 'addHreg'
mb.addHreg (i_PLC_TriggerReg);```

CoPilot suggest me that I'm using a wrong ModbusIP.h file for my project.
I searched a couple of versions, including suggest ESP8266 but couldn't find this functions in it (addIreg or addhreg)

Maybe you know what is wrong ?
Zeev