title: ESP32 build in Arduino IDE: undefined reference to `CLASS::function' error
body: <p>I tried to write an Library for the Sensirion SFM3000 Flow Sensor in the Arduino IDE for an ESP32. As long as it was one sketch, everything worked. But as I tried to seperate it into an .h and .cpp file and implemented it as a class, I get some weird error when I try to compile the sketch.</p>
  <pre><code>sketch\SFM3019_HSKA.cpp.o:(.literal._ZN12SFM3019_HSKA17i2c_read_flow_CRCEv+0x4): undefined reference to `SFM3019_HSKA::crc8(unsigned char, unsigned char)'
  sketch\SFM3019_HSKA.cpp.o: In function `SFM3019_HSKA::i2c_read_flow_CRC()':
  sketch/SFM3019_HSKA.cpp:124: undefined reference to `SFM3019_HSKA::crc8(unsigned char, unsigned char)'
  sketch/SFM3019_HSKA.cpp:128: undefined reference to `SFM3019_HSKA::crc8(unsigned char, unsigned char)'
  collect2.exe: error: ld returned 1 exit status
  exit status 1
  Fehler beim Kompilieren für das Board ESP32 Dev Module.
  </code></pre>
  <p>As I understand the error message, it occurs when the i2c_read_flow_CRC() meethod is calling the crc8() method in the last thrid of SFM3019_HSKA.cpp file. By now I don´t see an error in the syntax. But I have also no other idea on how to continue debugging...</p>
  <p>This is the main code im trying to use the library in:</p>
  <pre><code>#include &quot;SFM3019_HSKA.h&quot;
  #include &lt;Wire.h&gt;
  
  
  SFM3019_HSKA::SensVal_s SensVal = {0, 0, 0};
  
  SFM3019_HSKA SFM3019(0x2E); //Generate Object SFM3019 of class SFM3019_HSKA
   
  void setup() {
    // put your setup code here, to run once:
    Serial.begin (115200);
    delay(100);  
    Wire.begin (21, 22);   // for ESP32: SDA= GPIO_21 /SCL= GPIO_22
  
    SFM3019.i2c_device_check();  //checks if I2C device is available
    SFM3019.i2c_write(0x3608); //write 2Byte to start continuous measurement
    delay(100);
  }
  
  void loop() {
    // put your main code here, to run repeatedly:
  
    
    SensVal.flow = SFM3019.i2c_read_flow_CRC();  //read only Flow Bytes
    Serial.println(SensVal.flow, 10);
    delay(100);
    SensVal = SFM3019.i2c_read_all();  //read all Sensor Bytes
    Serial.print(&quot;Flow: &quot;);
    if (SensVal.flow &gt;= 0) Serial.print(&quot; &quot;); //just for beauty reasons
    Serial.print(SensVal.flow,10);
    Serial.print(&quot;  Temp: &quot;);
    Serial.print(SensVal.temp,3);
    Serial.print(&quot;  Statusword: &quot;);
    Serial.print(SensVal.statusword, HEX);
    delay(400);
    Serial.println();
  }
  </code></pre>
  <p>and those are the library files:
  SFM3019_HSKA.h</p>
  <pre><code>#ifndef SFM3019_HSKA_H  // include guard
  #define SFM3019_HSKA_H  
  
  #include &quot;Arduino.h&quot;
  
  
  
      class SFM3019_HSKA {
        
      public: //can be accessed public
  
          SFM3019_HSKA(uint8_t i2cAddress); //Constructor
      
          //may be nicer in private if it works anyway
          typedef struct {float flow; float temp; int16_t statusword;} SensVal_s; //Struct for complete Sensor Readout
          SensVal_s SensVal = {0, 0, 0};  //initialize with 0
  
          int8_t i2c_device_check(); //function for Initialisation
          int8_t i2c_write(const uint16_t SendData); //function to write 16Bit Data to sensor
          SensVal_s i2c_read_all();  //function to read Flow, Temperature and Statusword
          float i2c_read_flow(); //function to only read Flow
          float i2c_read_flow_CRC(); //function to only read Flow with CRC check
  
  
  
      private:  //can only be accessed by functions oh same object
          
          uint8_t SFM3019addr = 46; //SFM3019 I2C Adress: 46 / 0x2E
          uint8_t crc8(const uint8_t data, uint8_t crc);  //fuction for CRC confirmation
      };
  
  #endif
  </code></pre>
  <p>and the C++ file leading to the error:
  SFM3019_HSKA.cpp:</p>
  <pre><code>#include &quot;SFM3019_HSKA.h&quot; //when placed in same folder
  //#include &lt;SFM3019_HSKA.h&gt; //when placed in standard library folder
  #include &lt;Wire.h&gt;
  
  //  some values needed for calculation of physical flow and temperature values
  #define SFM3019Offset 24576
  #define SFM3019ScaleFactorFlow 170.0 //needs to be a float, otherwise it will not calculate in float
  #define SFM3019ScaleFactorTemp 200.0 //needs to be a float, otherwise it will not calculate in float
  
  
  SFM3019_HSKA::SFM3019_HSKA(uint8_t i2cAddress)  //constructor
  {
    //: mI2cAddress(i2cAddress)
    SFM3019addr = i2cAddress;
  }
  
  
  /*  checks if a Device at the desired address is responding with an ACK */
  int8_t SFM3019_HSKA::i2c_device_check(){
    Wire.beginTransmission(SFM3019addr);    // Begin I2C transmission Address (i)
    if (Wire.endTransmission() == 0)  // Receive 0 = success (ACK response) 
      {
        Serial.print (&quot;Found Seosor at address&quot;);
        Serial.print (SFM3019addr, DEC);
        Serial.print (&quot; (0x&quot;);
        Serial.print (SFM3019addr, HEX);     // 7 bit address
        Serial.println (&quot;)&quot;);
        return 0;                        //0=device sent ACK
        
      }else{
        
        Serial.print (&quot;Did not receive Acknowledge from I2C address &quot;);
        Serial.print (SFM3019addr, DEC);
        Serial.print (&quot; (0x&quot;);
        Serial.print (SFM3019addr, HEX);     // 7 bit address
        Serial.println (&quot;)&quot;);
        return 1;                        //no ACK received
      }
  }
  
  
  
  /*  writes a 16bit &quot;SendData&quot; to I2C Bus Device &quot;address&quot; */
  int8_t SFM3019_HSKA::i2c_write(const uint16_t SendData) {
      Wire.beginTransmission(SFM3019addr);
      //fill I2C outbuffer
      Wire.write((SendData&gt;&gt;8)&amp; 0xFF); //isolate HighByte
      Wire.write(SendData &amp; 0xFF); //isolate LowByte
      //send I2C outbuffer
      Wire.endTransmission();
  
      return 0;
  }
  
  
  
  /*  reads all 9 measurement bytes for flow, temp and status */
  SFM3019_HSKA::SensVal_s SFM3019_HSKA::i2c_read_all(){
      SensVal_s SensVal = {0};  //create empty struct
      Wire.requestFrom(SFM3019addr, 9, true); // Request 9byte (3x16bit + CRC) from the sensor
     //while(Wire.available()&lt;3){};  //wait for all the data to be received //ATTENTION may be critical loop forever, however not using this may lead to an error, as the Buffer may be processed faster, then the input is read on I2C
      
      //get Flow Bytes
      int16_t flow = Wire.read()&lt;&lt;8;  //get Highbyte and shift 8bit to 8MSB
      flow = flow | Wire.read();      //get Lowbyte 8LSB
      byte CRCflow = Wire.read();         //get CRC Check Byte (you could do a data validy check with that)    
      //Serial.println(flow, HEX);    //raw values for debugging
      SensVal.flow = (flow + SFM3019Offset) / SFM3019ScaleFactorFlow; //calculate the flow in slm as Datasheet mentions        
  
      //get Temperature Bytes
      int16_t temp = Wire.read()&lt;&lt;8;  //get Highbyte and shift 8bit to 8MSB
      temp = temp | Wire.read();      //get Lowbyte 8LSB
      byte CRCtemp = Wire.read();         //get CRC Check Byte (you could do a data validy check with that)    
      //Serial.println(temp, HEX);    //raw values for debugging
      SensVal.temp = temp / SFM3019ScaleFactorTemp; //calculate the flow in slm as Datasheet mentions        
  
      //get StatusWord Bytes
      int16_t stat = Wire.read()&lt;&lt;8;  //get Highbyte and shift 8bit to 8MSB
      stat = stat | Wire.read();      //get Lowbyte 8LSB
      byte CRCstat = Wire.read();         //get CRC Check Byte (you could do a data validy check with that)    
      //Serial.println(stat, HEX);    //raw values for debugging
      SensVal.statusword = temp / SFM3019ScaleFactorTemp; //calculate the flow in slm as Datasheet mentions        
  
      //return all data
      return SensVal;
      
  }
  
  
  
  /*  reads only first 3 bytes for flow and does NO CRC!*/
  float SFM3019_HSKA::i2c_read_flow(){
      Wire.requestFrom(SFM3019addr, 3, true); // Request 9byte (2x16bit + CRC) from the sensor
      //while(Wire.available()&lt;3){};  //wait for all the data to be received //ATTENTION may be critical loop forever, however not using this may lead to an error, as the Buffer may be processed faster, then the input is read on I2C
      int16_t flow = Wire.read()&lt;&lt;8;  //get Highbyte and shift 8bit to 8MSB
      flow = flow | Wire.read();      //get Lowbyte 8LSB
      byte CRC = Wire.read();         //get CRC Check Byte (you could do a data validy check with that)    
      //Serial.println(flow, HEX);    //raw values for debugging
      return (flow + SFM3019Offset) / SFM3019ScaleFactorFlow; //calculate the flow in slm as Datasheet mentions  
  }
  
  /*  reads only first 3 bytes for flow and DOES CRC*/
  float SFM3019_HSKA::i2c_read_flow_CRC(){
      Wire.requestFrom(SFM3019addr, 3, true); // Request 9byte (2x16bit + CRC) from the sensor
      //while(Wire.available()&lt;3){};  //wait for all the data to be received //ATTENTION may be critical loop forever, however not using this may lead to an error, as the Buffer may be processed faster, then the input is read on I2C
      uint8_t Highbyte = Wire.read();    //get Highbyte 8MSB
      uint8_t Lowbyte =  Wire.read();      //get Lowbyte 8LSB
      uint8_t CRC = Wire.read();         //get CRC Check Byte
  
      //Confirm CRC
      uint8_t mycrc = 0xFF; // initialize crc variable
      mycrc = crc8(Highbyte, mycrc); // let first byte through CRC calculation
      mycrc = crc8(Lowbyte, mycrc); // and the second byte too
      if (mycrc != CRC) { // check if the calculated and the received CRC byte matches
        //Serial.println(&quot;Error: wrong CRC&quot;);
        return -10000;  //extreme low value, so user knows somethig is wrong
      } else {
        //Serial.println(&quot;Success: identical CRC&quot;);
        int16_t flow = (Highbyte&lt;&lt;8) | Lowbyte; //stack the to bytes together as signed int16
        return (flow + SFM3019Offset) / SFM3019ScaleFactorFlow; //calculate the flow in slm as Datasheet mentions  
      }
  }
  
  /*  calculate a CRC Byte, (Cyclic Redundancy Check) */
  uint8_t crc8(const uint8_t data, uint8_t crc)
  {
       crc ^= data;                     //crc XOR data
       for ( uint8_t i = 8; i; --i ) {
         crc = ( crc &amp; 0x80 )           
         ? (crc &lt;&lt; 1) ^ 0x31
         : (crc &lt;&lt; 1);
      }
    return crc;
  }
  </code></pre>
  <p>I would be really thankfull for any idea on how to continue...</p>