Your new topic does not fit any of the above??? Check first. Then post here. Thanks.

Moderator: igrr

User avatar
By SwiCago
#60569 Hi Guys,

Trying to create my first library for Arduino/ESP8266
My library seems die at the linker stage

Can one of you guys tell me what I am doing wrong? Would really like to make this a library others with Mitsubishi heatpumps can benefit from.
I know it is most likely something stupid easy...thanks in advance for the help guys

TEST CODE for compile:
Code: Select all#include <ESP8266WiFi.h>
#include <HeatPump.h>

void setup() {
  // put your setup code here, to run once:
 HeatPump hp;
 hp.connect(&Serial);
 hp.update();
}

void loop() {
  // put your main code here, to run repeatedly:

}



HeatPump.h
Code: Select all#include <stdint.h>
#include <WString.h>
#include <HardwareSerial.h>
#if defined(ARDUINO) && ARDUINO >= 100
      #include "Arduino.h"
#else
      #include "WProgram.h"
#endif

typedef uint8_t byte;


class HeatPump
{
  private:
   static const byte CONNECT[];
   static const byte HEADER[];
   static const byte PAD[];   
   static const byte POWER[];     
   static const String POWER_MAP[];
   static const byte TEMP[];     
   static const String TEMP_MAP[];
   static const byte ROOM_TEMP[];   
   static const String ROOM_TEMP_MAP[];
   static const byte MODE[];     
   static const String MODE_MAP[];
   static const byte VANE[];     
   static const String VANE_MAP[];
   static const byte DIR[];       
   static const String DIR_MAP[];
   static const byte FAN[];     
   static const String FAN_MAP[];
   static const byte CONTROL_PACKET_VALUES[];     
   static const String CONTROL_PACKET_VALUES_MAP[];
   static const int CONTROL_PACKET_POSITIONS[];       
   static const String CONTROL_PACKET_POSITIONS_MAP[];
                           
   static String currentSettings[];
   static String wantedSettings[];

   static void createPacket(byte *packet, String settings[]);
   static int findPositionByByte(const byte values[], int len, byte value);
   static int findPositionByString(const String values[], int len, String value);
   static byte checkSum(byte bytes[], int len);
     static HardwareSerial * _HardSerial;

  public:
    HeatPump();
    void connect(HardwareSerial *serial);
    void update();
};


HeatPump.cpp
Code: Select all#include "HeatPump.h"

// Initialize Class Variables //////////////////////////////////////////////////
const byte CONNECT[] = {0xfc,0x5a,0x01,0x30,0x02,0xca,0x01,0xa8};
const byte HEADER[]  = {0xfc,0x41,0x01,0x30,0x10,0x01,0x9f,0x00};
const byte PAD[]     = {0x00,0x00,0x00,0x00,0x00};
const byte POWER[]       = {0x00, 0x01};
const String POWER_MAP[] = {"OFF","ON"};
const byte TEMP[]       = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
const String TEMP_MAP[] = {"31","30","29","28","27","26","25","24","23","22","21","20","19","18","17","16"};
const byte ROOM_TEMP[]       = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
                                0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f};
const String ROOM_TEMP_MAP[] = {"10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25",
                                "26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41"};
const byte MODE[]       = {0x01,   0x02,  0x03, 0x07, 0x08};
const String MODE_MAP[] = {"HEAT","DRY","COOL","FAN","AUTO"};
const byte VANE[]       = {0x00,  0x01,0x02,0x03,0x04,0x05,0x07};
const String VANE_MAP[] = {"AUTO", "1", "2", "3", "4", "5","SWING"};
const byte DIR[]        = {0x01,0x02,0x03,0x04,0x05,0x08,0x0c};
const String DIR_MAP[] = {"<<", "<", "|", ">",">>","<>","SWING"};
const byte FAN[]       = {0x00,  0x01,   0x02,0x03,0x05,0x06};
const String FAN_MAP[] = {"AUTO","QUIET","1", "2", "3", "4"};

const byte CONTROL_PACKET_VALUES[]       = {0x01,   0x02,  0x04,  0x08, 0x10,  0x80};
const String CONTROL_PACKET_VALUES_MAP[] = {"POWER","MODE","TEMP","FAN","VANE","DIR"};
const int CONTROL_PACKET_POSITIONS[]        = {3,      4,     5,     6,    7,     10};
const String CONTROL_PACKET_POSITIONS_MAP[] = {"POWER","MODE","TEMP","FAN","VANE","DIR"};
                           
String currentSettings[] = {POWER_MAP[0], MODE_MAP[0], TEMP_MAP[0], FAN_MAP[0], VANE_MAP[0], DIR_MAP[0]};
String wantedSettings[]  = {POWER_MAP[0], MODE_MAP[0], TEMP_MAP[0], FAN_MAP[0], VANE_MAP[0], DIR_MAP[0]};

HardwareSerial * _HardSerial;

// Constructors ////////////////////////////////////////////////////////////////

HeatPump::HeatPump(){}

// Public Methods //////////////////////////////////////////////////////////////

void HeatPump::connect(HardwareSerial *serial){
     _HardSerial = serial;
   _HardSerial->begin(2400,SERIAL_8E1);
   delay(2000);
   for(int i=0; i<8; i++)
           { _HardSerial->write((uint8_t)CONNECT[i]); } 
     delay(1100);
   for(int i=0; i<8; i++)
           { _HardSerial->write((uint8_t)CONNECT[i]); }
     delay(2000);
}                   

void HeatPump::update()
{
  byte packet[22] = {};
  createPacket(packet, wantedSettings);
  for(int i=0; i < 22; i++)
    { _HardSerial->write((uint8_t)packet[i]); }
}

int HeatPump::findPositionByByte(const byte values[], int len, byte value)
{
  for(int i=0; i < len; i++)
  {
    if(values[i] == value)
      { return i; }
  }
  return -1;
}
int HeatPump::findPositionByString(const String values[], int len, String value)
{
  for(int i=0; i < len; i++)
  {
    if(values[i] == value)
      { return i; }
  }
  return -1;
}

byte HeatPump::checkSum(byte bytes[], int len)
{
  byte sum = 0;
  for(int i=0; i < len; i++)
    { sum+=bytes[i]; }
  return (0xfc - sum) & 0xff;
}

void HeatPump::createPacket(byte *packet, String settings[])
{
  byte data[21] = {};
  for(int i=0; i < 8; i++)
    { data[i] = HEADER[i]; }
  data[8]  = POWER[findPositionByString(POWER_MAP,2,settings[0])];
  data[9]  = MODE[findPositionByString(MODE_MAP,5,settings[1])];
  data[10] = TEMP[findPositionByString(TEMP_MAP,16,settings[2])];
  data[11] = FAN[findPositionByString(FAN_MAP,6,settings[3])];
  data[12] = VANE[findPositionByString(VANE_MAP,7,settings[4])];
  data[13] = 0x00;
  data[14] = 0x00;
  data[15] = DIR[findPositionByString(DIR_MAP,7,settings[5])];
  for(int i=0; i < 5; i++)
    { data[i+16] = PAD[i]; }
 byte chkSum = checkSum(data, 21);
 for(int i=0; i < 21; i++)
    { packet[i] = data[i]; }
 packet[21] = chkSum;
}


Compiler output
Code: Select allC:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\mitsuTestLib.cpp.o C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\ESP8266WiFi\ESP8266WiFi.cpp.o C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\ESP8266WiFi\ESP8266WiFiAP.cpp.o C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\ESP8266WiFi\ESP8266WiFiGeneric.cpp.o C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\ESP8266WiFi\ESP8266WiFiMulti.cpp.o C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\ESP8266WiFi\ESP8266WiFiScan.cpp.o C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\ESP8266WiFi\ESP8266WiFiSTA.cpp.o C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\ESP8266WiFi\WiFiClient.cpp.o C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\ESP8266WiFi\WiFiClientSecure.cpp.o C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\ESP8266WiFi\WiFiServer.cpp.o C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\ESP8266WiFi\WiFiUdp.cpp.o C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp/arduino.ar -lm -lgcc -lhal -lphy -lpp -lnet80211 -lwpa -lcrypto -lmain -lwps -laxtls -lsmartconfig -lmesh -lwpa2 -llwip_gcc -lstdc++ -Wl,--end-group -LC:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump7connectEP14HardwareSerial+0x0): undefined reference to `HeatPump::_HardSerial'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump7connectEP14HardwareSerial+0x8): undefined reference to `HeatPump::CONNECT'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o: In function `HeatPump::findPositionByString(String const*, int, String)':
C:\Users\user_2\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\2.3.0-rc2\libraries\HeatPump/HeatPump.cpp:77: undefined reference to `HeatPump::HEADER'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0x4): undefined reference to `HeatPump::POWER_MAP'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0x8): undefined reference to `HeatPump::POWER'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0xc): undefined reference to `HeatPump::MODE_MAP'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0x10): undefined reference to `HeatPump::MODE'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0x14): undefined reference to `HeatPump::TEMP_MAP'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0x18): undefined reference to `HeatPump::TEMP'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0x1c): undefined reference to `HeatPump::FAN_MAP'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0x20): undefined reference to `HeatPump::FAN'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0x24): undefined reference to `HeatPump::VANE_MAP'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0x28): undefined reference to `HeatPump::VANE'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0x2c): undefined reference to `HeatPump::DIR_MAP'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0x30): undefined reference to `HeatPump::DIR'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o:(.text._ZN8HeatPump12createPacketEPhP6String+0x34): undefined reference to `HeatPump::PAD'
C:\Users\user_2\AppData\Local\Temp\build9159321788098351056.tmp\HeatPump\HeatPump.cpp.o: In function `HeatPump::createPacket(unsigned char*, String*)':
C:\Users\user_2\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\2.3.0-rc2\libraries\HeatPump/HeatPump.cpp:96: undefined reference to `HeatPump::wantedSettings'
collect2.exe: error: ld returned 1 exit status
Error compiling.
Last edited by SwiCago on Mon Jan 09, 2017 2:19 pm, edited 1 time in total.
User avatar
By SwiCago
#60616
martinayotte wrote:One thing I see is that you have _HardSerial defined as both static class member and global variables.


Thanks for the tip...I just commented all the code out and step by step re-enable/fixed errors until it was all working.

HeatPump.h
Code: Select all#include <stdint.h>
#include <WString.h>
#include <HardwareSerial.h>
#if defined(ARDUINO) && ARDUINO >= 100
      #include "Arduino.h"
#else
      #include "WProgram.h"
#endif

typedef uint8_t byte;


class HeatPump
{
  private:
   static const byte CONNECT[];
   static const byte HEADER[];
   static const byte PAD[];   
   static const byte POWER[];     
   static const String POWER_MAP[];
   static const byte TEMP[];     
   static const String TEMP_MAP[];
   static const byte ROOM_TEMP[];   
   static const String ROOM_TEMP_MAP[];
   static const byte MODE[];     
   static const String MODE_MAP[];
   static const byte VANE[];     
   static const String VANE_MAP[];
   static const byte DIR[];       
   static const String DIR_MAP[];
   static const byte FAN[];     
   static const String FAN_MAP[];
   static const byte CONTROL_PACKET_VALUES[];     
   static const String CONTROL_PACKET_VALUES_MAP[];
   static const int CONTROL_PACKET_POSITIONS[];       
   static const String CONTROL_PACKET_POSITIONS_MAP[];
                           
   static String currentSettings[];
   static String wantedSettings[];

   static void createPacket(byte *packet, String settings[]);
   static int findPositionByByte(const byte values[], int len, byte value);
   static int findPositionByString(const String values[], int len, String value);
   static byte checkSum(byte bytes[], int len);
     static HardwareSerial * _HardSerial;

  public:
    HeatPump();
    void connect(HardwareSerial *serial);
    void update();
    void setSettings(String settings[]);
    void getSettings(String *settings);
};


HeatPump.cpp
Code: Select all#include "HeatPump.h"

// Initialize Class Variables //////////////////////////////////////////////////

const byte HeatPump::CONNECT[] = {0xfc,0x5a,0x01,0x30,0x02,0xca,0x01,0xa8};
const byte HeatPump::HEADER[]  = {0xfc,0x41,0x01,0x30,0x10,0x01,0x9f,0x00};
const byte HeatPump::PAD[]     = {0x00,0x00,0x00,0x00,0x00};
const byte HeatPump::POWER[]       = {0x00, 0x01};
const String HeatPump::POWER_MAP[] = {"OFF","ON"};
const byte HeatPump::TEMP[]       = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
const String HeatPump::TEMP_MAP[] = {"31","30","29","28","27","26","25","24","23","22","21","20","19","18","17","16"};
const byte HeatPump::ROOM_TEMP[]       = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
                                0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f};
const String HeatPump::ROOM_TEMP_MAP[] = {"10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25",
                                "26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41"};
const byte HeatPump::MODE[]       = {0x01,   0x02,  0x03, 0x07, 0x08};
const String HeatPump::MODE_MAP[] = {"HEAT","DRY","COOL","FAN","AUTO"};
const byte HeatPump::VANE[]       = {0x00,  0x01,0x02,0x03,0x04,0x05,0x07};
const String HeatPump::VANE_MAP[] = {"AUTO", "1", "2", "3", "4", "5","SWING"};
const byte HeatPump::DIR[]        = {0x01,0x02,0x03,0x04,0x05,0x08,0x0c};
const String HeatPump::DIR_MAP[] = {"<<", "<", "|", ">",">>","<>","SWING"};
const byte HeatPump::FAN[]       = {0x00,  0x01,   0x02,0x03,0x05,0x06};
const String HeatPump::FAN_MAP[] = {"AUTO","QUIET","1", "2", "3", "4"};

const byte HeatPump::CONTROL_PACKET_VALUES[]       = {0x01,   0x02,  0x04,  0x08, 0x10,  0x80};
const String HeatPump::CONTROL_PACKET_VALUES_MAP[] = {"POWER","MODE","TEMP","FAN","VANE","DIR"};
const int HeatPump::CONTROL_PACKET_POSITIONS[]        = {3,      4,     5,     6,    7,     10};
const String HeatPump::CONTROL_PACKET_POSITIONS_MAP[] = {"POWER","MODE","TEMP","FAN","VANE","DIR"};
                           
String HeatPump::currentSettings[] = {POWER_MAP[0], MODE_MAP[0], TEMP_MAP[0], FAN_MAP[0], VANE_MAP[0], DIR_MAP[0]};
String HeatPump::wantedSettings[]  = {POWER_MAP[0], MODE_MAP[0], TEMP_MAP[0], FAN_MAP[0], VANE_MAP[0], DIR_MAP[0]};


HardwareSerial * HeatPump::_HardSerial;

// Constructors ////////////////////////////////////////////////////////////////

HeatPump::HeatPump(){}

// Public Methods //////////////////////////////////////////////////////////////

void HeatPump::connect(HardwareSerial *serial)
{
     _HardSerial = serial;
   _HardSerial->begin(2400,SERIAL_8E1);
   delay(2000);
   for(int i=0; i<8; i++)
           { _HardSerial->write((uint8_t)CONNECT[i]); } 
     delay(1100);
   for(int i=0; i<8; i++)
           { _HardSerial->write((uint8_t)CONNECT[i]); }
     delay(2000);
}                   

void HeatPump::update()
{
  byte packet[22] = {};
  createPacket(packet, HeatPump::wantedSettings);
  for(int i=0; i < 22; i++)
    { _HardSerial->write((uint8_t)packet[i]); }
  delay(1000);
}

void HeatPump::setSettings(String settings[])
{
  for(int i=0; i < 6; i++)
    { HeatPump::wantedSettings[i] = settings[i]; }
}

void HeatPump::getSettings(String *settings)
{
  settings = HeatPump::currentSettings;
}


int HeatPump::findPositionByByte(const byte values[], int len, byte value)
{
  for(int i=0; i < len; i++)
  {
    if(values[i] == value)
      { return i; }
  }
  return -1;
}
int HeatPump::findPositionByString(const String values[], int len, String value)
{
  for(int i=0; i < len; i++)
  {
    if(values[i] == value)
      { return i; }
  }
  return -1;
}

byte HeatPump::checkSum(byte bytes[], int len)
{
  byte sum = 0;
  for(int i=0; i < len; i++)
    { sum+=bytes[i]; }
  return (0xfc - sum) & 0xff;
}

void HeatPump::createPacket(byte *packet, String settings[])
{
  byte data[21] = {};
  for(int i=0; i < 8; i++)
    { data[i] = HEADER[i]; }
  data[8]  = HeatPump::POWER[findPositionByString(HeatPump::POWER_MAP,2,settings[0])];
  data[9]  = HeatPump::MODE[findPositionByString(HeatPump::MODE_MAP,5,settings[1])];
  data[10] = HeatPump::TEMP[findPositionByString(HeatPump::TEMP_MAP,16,settings[2])];
  data[11] = HeatPump::FAN[findPositionByString(HeatPump::FAN_MAP,6,settings[3])];
  data[12] = HeatPump::VANE[findPositionByString(HeatPump::VANE_MAP,7,settings[4])];
  data[13] = 0x00;
  data[14] = 0x00;
  data[15] = HeatPump::DIR[findPositionByString(HeatPump::DIR_MAP,7,settings[5])];
  for(int i=0; i < 5; i++)
    { data[i+16] = PAD[i]; }
 byte chkSum = checkSum(data, 21);
 for(int i=0; i < 21; i++)
    { packet[i] = data[i]; }
 packet[21] = chkSum;
}


Sample usage:
Code: Select all#include <HeatPump.h>

void setup() {
 HeatPump hp;
 hp.connect(&Serial);
 String settings[6]={"ON","FAN","26","4","3","|"};
 hp.setSettings(settings);
 hp.update();
}

void loop() {
 

}