Compilation problem under Arduino 1.8.1
-
Hello,
I tried to compile following code (MyMaster 2.0.0 or same result with 2.1.1) with following error code. For info, it was perfectly working with MySensors 1.5 and Arduino 1.6.5 r5) :
Linking everything together...
"C:_myProgFiles\arduino-1.8.1\hardware\tools\avr/bin/avr-gcc" -w -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega328p -o "C:\Users\xxxxx\AppData\Local\Temp\arduino_build_741820/GenericDevices.ino.elf" "C:\Users\xxxxx\AppData\Local\Temp\arduino_build_741820\sketch\GenericDevices.ino.cpp.o" "C:\Users\xxxxx\AppData\Local\Temp\arduino_build_741820\libraries\SPI\SPI.cpp.o" "C:\Users\xxxxx\AppData\Local\Temp\arduino_build_741820\libraries\Bounce2\Bounce2.cpp.o" "C:\Users\xxxxx\AppData\Local\Temp\arduino_build_741820\libraries\DallasTemperature\DallasTemperature.cpp.o" "C:\Users\xxxxx\AppData\Local\Temp\arduino_build_741820\libraries\MAX31850_OneWire\OneWire.cpp.o" "C:\Users\xxxxx\AppData\Local\Temp\arduino_build_741820/core\core.a" "-LC:\Users\xxxxx\AppData\Local\Temp\arduino_build_741820" -lm
main.cpp.o (symbol from plugin): In functionatexit': (.text+0x0): multiple definition of
main'
C:\Users\xxxxx\AppData\Local\Temp\arduino_build_741820\sketch\GenericDevices.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2.exe: error: ld returned 1 exit statusCan anyone help me please ?
Thx- GenericDevices.ino
#define MY_RADIO_NRF24 #define MY_RF24_PA_LEVEL RF24_PA_HIGH #include <MySensors.h> #include "Devices.h" DECLARE_ID(RELAY); DECLARE_ID(BUTTON); DECLARE_ID(DALLAST); void before() { DECLARE_RELAY(RELAY // id / name (must be unique) , 3 // pin , bOff // off at start , true // reverse output (some relay are active when 0v is present on pin and inactive at 5V) , true); // persistent // button to change the sate of previous declared relay DECLARE_BUTTON(BUTTON // id / name , 4 // pin , RELAY // linked device , true); // reverse state when button pushed DECLARE_DALLAST(DALLAST // id / name , 5 // pin , 30000); // retrieve temperature every ... } void setup() { } void presentation() { sendSketchInfo("Generic Device", "2.11a"); // Send the sketch version information to the gateway and Controller for(int i=1; i<=NBOFDEVICES; i++) { if (DEVICEMAP[i] != NULL) { DEVICEMAP[i]->presentation(); } } } void loop() { // parse all devices in order to know if change occurs for(int i=1; i<=NBOFDEVICES; i++) { if (DEVICEMAP[i] != NULL) { DEVICEMAP[i]->checkChange(); } } } void receive(const MyMessage &msg) { if (DEVICEMAP[msg.sensor] != NULL) { DEVICEMAP[msg.sensor]->setVal(msg); // call corresponding sensor to take into account data coming from Controller } }
- Device.h
#pragma once #include <Bounce2.h> #include <DallasTemperature.h> #include <OneWire.h> #include "ElapsedTime.h" uint8_t g_nbOfDevice = 0; #define NBOFDEVICES g_nbOfDevice #define DECLARE_ID(id) static const uint8_t id = ++g_nbOfDevice; #define DECLARE_RELAY(id,pin,initialVal,reverseOutput,persistent) \ static CDOutput o##id(id,pin,#id,initialVal,reverseOutput,0,persistent) #define DECLARE_BUTTON(id,pin,linkedId,reverseLinkedId) \ static CDInput o##id(id,pin,#id,linkedId,reverseLinkedId) #define DECLARE_DALLAST(id,pin,period) \ static CDallasT o##id(id,pin,#id,period); #define NOTEWORTHY (reinterpret_cast<CDevice*>(0xDEADBEEF)) CDevice* g_deviceMap[11] = {NOTEWORTHY}; // static map with maximum number of device declared by node is the number minus 1 void initDeviceMap() { if (g_deviceMap[0] == NOTEWORTHY) { memset(g_deviceMap, 0/*NULL*/, sizeof(g_deviceMap)); } }; #define DEVICEMAP g_deviceMap //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CDevice { public: CDevice(uint8_t id, const char* sName, uint8_t pin, uint8_t val=0) : m_id(id) , m_sName(sName) , m_pin(pin) , m_val(val) { #ifdef DEBUG Serial.print("CDevice() name="); Serial.print(sName); Serial.print(" id="); Serial.println(m_id); #endif initDeviceMap(); // run only once, after all IDs has been declared with DECLARE_XXXX macro g_deviceMap[m_id] = this; } virtual void presentation() {} // generic behavior virtual uint8_t getVal() { return m_val; } // generic behavior virtual void setVal(const MyMessage &msg) { m_val = msg.getInt(); } // generic behavior virtual void checkChange() {}; // used in some devices protected: void save() { saveState(m_id, m_val); } void load() { m_val = loadState(m_id); } // last known state from previous run uint8_t m_id; // device id const char* m_sName; // device name uint8_t m_pin; // device associated pin uint8_t m_val; // device generic value }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ const uint8_t bOn = 1; const uint8_t bOff = 0; class CDOutput : public CDevice { public: CDOutput(uint8_t id, uint8_t pin, const char* sName, bool bActiveAtStart, bool bReverseOutput, uint8_t linkedId=0, bool bPersistent=false, int sensorTypName=S_LIGHT) : CDevice(id, sName, pin, bActiveAtStart ? bOn : bOff) , m_linkedId(linkedId == 0 ? id : linkedId) , m_bReverseOutput(bReverseOutput) , m_bPersistent(bPersistent) , m_sensorTypName(sensorTypName) { pinMode(m_pin, OUTPUT); if (m_bPersistent) { load(); } // read and set previous state dWrite(); } virtual void presentation() { if (m_linkedId == m_id) // if not linked to other device, declare to GW { present(m_id, m_sensorTypName, m_sName); } } void setVal(const MyMessage &msg) { if (m_linkedId == m_id) // if linked to this device { m_val = msg.getInt(); dWrite(); if (m_bPersistent) { save(); } #ifdef DEBUG Serial.print("CDOutput::setVal id="); Serial.print(m_id); Serial.print(", new val="); Serial.println(m_val); #endif } else // linked to other device so get value from it { checkChange(); } } void dWrite() { digitalWrite(m_pin, m_bReverseOutput ? (m_val ? bOff : bOn) : (m_val ? bOn : bOff) ); } virtual void checkChange() { if (m_linkedId != m_id) // if linked to other device { m_val = g_deviceMap[m_linkedId]->getVal(); // get value dWrite(); if (m_bPersistent) { save(); } } } protected: uint8_t m_linkedId; bool m_bReverseOutput; bool m_bPersistent; int m_sensorTypName; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // used to know the state of digital input (button, state of anything on digital input) // TODO: a button should be associated to more than 1 device: a list of id should be managed // TODO: should be used to manage analog input too ? class CDInput : public CDevice, public MyMessage, public Bounce, public CElapsedTime { public: CDInput(uint8_t id, uint8_t pin, const char* sName, uint8_t linkedId=0, bool bReverse=false, uint32_t delay=0) : CDevice(id, sName, pin) , MyMessage((linkedId == 0) ? id : linkedId, V_LIGHT) , Bounce() , CElapsedTime(delay) // used to send periodically state of this input. 0 = only when change , m_linkedId((linkedId == 0) ? id : linkedId) , m_bReverse(bReverse) { pinMode(m_pin, INPUT); digitalWrite(m_pin, HIGH); // internal pull-up attach(m_pin); // Bounce class interval(5); // Bounce class }; virtual void presentation() { if (m_linkedId == m_id) // if not dedicated to linked id, declare this to GW { present(m_id, S_BINARY, m_sName); } } // should be called periodically in order to check pin state virtual void checkChange() { bool bSend = false; update(); // Bounce class int iVal = read(); // Bounce class if (!m_bEnabled) // status should not be sent periodically { bSend = (iVal != m_val) && ((m_linkedId != m_id) && (iVal == 0)); } else if (isElapsed()) // status should be sent periodically { // in this case, always (not olny when change) send state to GW bSend = true; start(); } if (bSend) { send(set(g_deviceMap[m_linkedId]->getVal() ? !m_bReverse : m_bReverse), true); } m_val = iVal; // memorize old value } protected: uint8_t m_linkedId; // Id with which device (button for instance) is associated bool m_bReverse; // used for button to invert state of attached relay for instance }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #define MAX_ATTACHED_DS18B20 16 // (D)allas (T)emperature (S)tate automaton const uint8_t DTS_BEGIN=1; const uint8_t DTS_REQUEST=2; const uint8_t DTS_RETRIEVE=3; class CDallasT : public CDevice, public MyMessage, public CElapsedTime { public: // period : minimum allowed time between two request of temperature CDallasT(uint8_t id, uint8_t pin, const char* sName, uint32_t period) : CDevice(id, sName, pin) , MyMessage(id, V_TEMP) , CElapsedTime(ELAPSED_NOW) // at startup, time is elapsed , m_oneWire(pin) , m_dallasT(&m_oneWire) , m_state(DTS_BEGIN) // 1st time, request should be done , m_requestPeriod(period) { // try m_dallasT.setOneWire(&m_oneWire); m_dallasT.begin(); m_dallasT.setWaitForConversion(false); // requestTemperatures() will not block current thread } // shoud be called periodically in order to check if temperature has to be measured virtual void checkChange() { // TODO: ? check if this state works in constructor. If yes, DTS_BEGIN should be removed if (m_state == DTS_BEGIN) // run only once (init) { m_nbOfSensors = m_dallasT.getDeviceCount(); // Fetch the number of attached temperature sensors for (int i=0; (i<m_nbOfSensors) && (i<MAX_ATTACHED_DS18B20); i++) { present(m_id+i, S_TEMP, "DallasT"); } m_conversionTime = m_dallasT.millisToWaitForConversion(m_dallasT.getResolution()); m_state = DTS_REQUEST; } if (isElapsed()) { if (m_state == DTS_REQUEST) { m_dallasT.requestTemperatures(); // request temperature from Dallas sensor m_state = DTS_RETRIEVE; // next time, retrieve temperature will be done start(m_conversionTime); // 'wait' for end of temperature sampling } else if (m_state == DTS_RETRIEVE) { // Read temperatures and send them to controller for (int i=0; (i<m_nbOfSensors) && (i<MAX_ATTACHED_DS18B20); i++) { // fetch and round temperature to one decimal float tp = getConfig().isMetric // float tp = getControllerConfig().isMetric ? m_dallasT.getTempCByIndex(i) : m_dallasT.getTempFByIndex(i); tp = static_cast<float>(static_cast<int>(tp * 10.)) / 10.; if ((tp != m_fTempPrev[i]) && (tp != -127.00) && (tp != 85.00)) { send(setSensor(m_id+i).set(tp, 1)); m_fTempPrev[i] = tp; // Save new temperature for next compare } } m_state = DTS_REQUEST; // next time, request temperature will be asked start(m_requestPeriod); // once temperature is retrieved, wait for next request to retrieve again } } } protected: OneWire m_oneWire; DallasTemperature m_dallasT; float m_fTempPrev[MAX_ATTACHED_DS18B20]; uint8_t m_state; // internal state to toggle between 1st init, request and retrieve temperature uint32_t m_requestPeriod; uint32_t m_conversionTime; int m_nbOfSensors; };
- ElapsedTime.h
#pragma once const uint32_t ELAPSED_NOW=1; // used to check if set time is elapsed class CElapsedTime { public: CElapsedTime(uint32_t delay=0) // by default, this component is disabled (delay=0) because of using it in generic derivated object { m_delay = delay; start(); } ~CElapsedTime() {}; // start to count requested 'wait' time. If delay is 0, isElapsed() always returns 'false' (component disabled) void start(uint32_t delay=0) { m_tStart = millis(); if (delay != 0) { m_delay = delay; } m_bEnabled = (m_delay != 0); } void disable() { m_bEnabled = false; } // check if requested time is elapsed since previous call of 'start' method bool isElapsed() { // overflow (every 49.71 days) is natively managed by unsigned var return m_bEnabled && ((millis() - m_tStart) > m_delay); } protected: uint32_t m_tStart; uint32_t m_delay; bool m_bEnabled; };
-
What the f...... hell ! I have found the problem :-). It comes from the 'static' keyword while declaring the Device derivated object in Devices.h !
I'm happy but I don't know why this new compiler forbids this...See you for next adventures