I'm attempting to break out a previously working sketch I created into a class and sketch, and I'm having some trouble. I'm extending the functionality of a keyboard class designed for the board I'm working on, but the compiler keeps complaining about multiple definitions of functions.
here is my sketch, my .h, and my .cpp:
sketch
#include <DigiKeyboard.h>
#include "MacroKeyboard.h"
//constants
#define LED 1
#define SWITCH 0
//configuration
#define PAUSE_ON_ENTER true
const char command[] PROGMEM = "test string";
MacroKeyboard kb(command, SWITCH);
void setup() {
//tie switch to high
pinMode(SWITCH, OUTPUT);
digitalWrite(SWITCH, HIGH);
// set pins to correct uh whatever
pinMode(LED, OUTPUT);
pinMode(SWITCH, INPUT);
}
void loop() {
DigiKeyboard.update();
kb.update();
}
.h:
#ifndef MacroKeyboard_h
#define MacroKeyboard_h
#include "Arduino.h"
#define ON LOW
#define OFF HIGH
#define SCANCODE_DIFF 8
class MacroKeyboard {
const char* command;
int pin;
bool isPressed = false;
public:
MacroKeyboard(const char*, int);
void parseLetter(int);
void update();
};
#endif
.cpp:
#include <DigiKeyboard.h>
#include "MacroKeyboard.h"
MacroKeyboard::MacroKeyboard(const char* macro_position, int pin_number){
command = macro_position;
pin = pin_number;
}
void MacroKeyboard::parseLetter(int letter){
unsigned int scancode = pgm_read_byte_near(ascii_to_scan_code_table + letter - SCANCODE_DIFF);
unsigned int keycode = scancode & ((1 << 7) - 1); // masking off shift bit
unsigned int mods = 0;
unsigned int shift = (scancode & (1 << 7)) >> 7;
mods |= (shift == 1) ? MOD_SHIFT_LEFT : 0;
DigiKeyboard.sendKeyStroke(keycode, mods);
}
void MacroKeyboard::update(){
if(digitalRead(pin) == ON && !isPressed){
isPressed = true;
for (int i = 0; i < strlen(command); i++){
char letter = pgm_read_byte_near(command + i);
parseLetter(letter);
}
}
if (digitalRead(pin) == OFF && isPressed){
isPressed = false; // debounce
}
}
the errors I'm getting are this:
MacroKeyboard\MacroKeyboard.cpp.o: In function `usbFunctionSetup':
C:\Program Files (x86)\Digistump_Arduino\hardware\digistump\avr\libraries\DigisparkKeyboard/DigiKeyboard.h:216: multiple definition of `usbFunctionSetup'
MacroKeyboardTest.cpp.o:C:\Program Files (x86)\Digistump_Arduino\hardware\digistump\avr\libraries\DigisparkKeyboard/DigiKeyboard.h:216: first defined here
MacroKeyboard\MacroKeyboard.cpp.o: In function `MacroKeyboard::MacroKeyboard(char const*, int)':
C:\Program Files (x86)\Digistump_Arduino\hardware\digistump\avr\libraries\DigisparkKeyboard/DigiKeyboard.h:170: multiple definition of `DigiKeyboard'
MacroKeyboardTest.cpp.o:C:\Program Files (x86)\Digistump_Arduino\hardware\digistump\avr\libraries\DigisparkKeyboard/DigiKeyboard.h:199: first defined here
MacroKeyboard\MacroKeyboard.cpp.o:(.progmem.data.usbDescriptorHidReport+0x0): multiple definition of `usbDescriptorHidReport'
MacroKeyboardTest.cpp.o:(.progmem.data.usbDescriptorHidReport+0x0): first defined here
collect2: error: ld returned 1 exit status
Error compiling.
what am I doing wrong?
The library you use is written in a strange way. In the file DigiKeyboard.h there are such definitions as (comments mine):
// Declares a global variable.
// If you include this file in more than one cpp file it will cause linker error.
DigiKeyboardDevice DigiKeyboard = DigiKeyboardDevice();
// Defines a non-inline function
// Again, multiple definitions error if the file is included in several source files.
uchar usbFunctionSetup(uchar data[8]) {
// code
}
So you have to use it by including this .h file into only one of .cpp files.
Related
This question already has answers here:
multiple definition in header file
(4 answers)
multiple definition error c++
(2 answers)
Closed 6 days ago.
I'm using VS Code with Platformio Plugin for an Arduino that is communicating with an Raspberry.
I receive the error "multiple definition of... (see below).
I canĀ“t see that I'm importing my own file multiple times and I can't get the link to the function requestEvent().
my main:
#include <Arduino.h>
#include <Wire.h>
#include <comm.cpp>
#define SLAVE_ADDRESS 0x08
volatile boolean receiveFlag = false;
char temp[32];
//String command;
const char* message_event = "init";
RaspiArduStatus comm_status{false};
void requestEvent() {
Wire.write(message_event);
}
void receiveEvent(int howMany) {
for (int i = 0; i < howMany; i++) {
temp[i] = Wire.read();
temp[i + 1] = '\0'; //add null after ea. char
}
for (int i = 0; i < howMany; ++i)
temp[i] = temp[i + 1];
receiveFlag = true;
}
void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
// initialize i2c as slave
Wire.begin(SLAVE_ADDRESS);
// define callbacks for i2c communication
Wire.onReceive(receiveEvent);
Serial.begin(9600);
}
void loop() {
Serial.println("Registering event");
message_event = "event";
Wire.onRequest(requestEvent); // register event
Serial.println("Receiving");
if (receiveFlag == true) {
Serial.println(temp);
receiveFlag = false;
if (strcmp (temp, "test")==0)
{
Serial.println("Erkannt");
message_event = "Erkannt";
Wire.onRequest(requestEvent);
}
}
delay(2000);
}
my included file:
class RaspiArduStatus {
bool status_;
public:
explicit RaspiArduStatus(bool s) : status_{s} {}
void set_low();
void set_high();
bool get_status() const;
};
void RaspiArduStatus::set_high()
{
status_ = true;
}
void RaspiArduStatus::set_low()
{
status_ = false;
}
and theres the error:
Building in release mode
Compiling .pio/build/nanoatmega328/src/comm.cpp.o
Compiling .pio/build/nanoatmega328/src/main.cpp.o
Linking .pio/build/nanoatmega328/firmware.elf
.pio/build/nanoatmega328/src/main.cpp.o (symbol from plugin): In function `requestEvent()':
(.text+0x0): multiple definition of `RaspiArduStatus::set_high()'
.pio/build/nanoatmega328/src/comm.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio/build/nanoatmega328/src/main.cpp.o (symbol from plugin): In function `requestEvent()':
(.text+0x0): multiple definition of `RaspiArduStatus::set_low()'
.pio/build/nanoatmega328/src/comm.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
*** [.pio/build/nanoatmega328/firmware.elf] Error 1
I already copied the content of my included file to my main.cpp and removed the include. Didn't change anything.
I am working with GNU AVR GCC version 5.4.0 and Atmelstudio 7.0.2397 and I have the following problem.
Problem Description
In the following Image, ye can see that up to line 13, the program has stored the address of function usart_send into the transmitter variable which is member of SimpleClass object sc.
The prototype of the transmitter function is void (*transmitter)(uint8_t * txbuff, uint8_t len); and usart_send function prototype definition is void usart_send(uint8_t *, uint8_t);.
Now when I step into the foo function, notice that when inside the member function of the class's object, the address of transmitter is now 0.
Similarly inside the function flush, its value is still 0. So I cannot call the desired function. And this is what disassembly is showing and so is my MCU.
Cause of this problem
So I have the following code for SimpleClass.h
#pragma once
typedef unsigned char uint8_t;
#ifndef rxBufferLen
#define rxBufferLen 30
#endif
#ifndef txBufferLen
#define txBufferLen 30
#endif
class SimpleClass{
uint8_t rxbuffer[rxBufferLen]; ///< receiver buffer
uint8_t txBuffer[txBufferLen]; ///< transmitter buffer
uint8_t rxbuff_index, ///< rxbuffer index. Indicates where to put new data
txbuff_index; ///< txBuffer index. Indicates where to put new data
public:
void (*transmitter)(uint8_t * txbuff, uint8_t len);
void pushtx(uint8_t byte);
void pushrx(uint8_t byte);
void flush();
void foo();
};
Notice that have the length of txBuffer and rxBuffer defined using define. And in incfile1.h I have the following code.
#pragma once
#define rxBufferLen 50
#define txBufferLen 50
#include <avr/io.h>
#include "simpleClass.h"
#define TIMER0_CLOCK_PRESCALAR (3)
#define TIMER0_CLOCK_COUNT (0xff - 50)
void usart_init();
void timer0_init();
void serial_send_ln(const char *);
void usart_send(uint8_t *, uint8_t);
void usart_send_ln(uint32_t num);
In here I have redefined rxBufferLen and txBufferLen. This definition of define causes the above problem. If I remove these two lines, this code is working fine.
Question
So you can see that by defining the buffer length for a buffer which is inside a class, causes its member function to loose the value the class's function pointer (which is a member variable). And I want to know why?
Code
Here are many un used functions and this is because I was isolating bug(if it is a bug!) from my project.
main.cpp
#include "IncFile1.h"
SimpleClass sc;
int main(void)
{
usart_init();
timer0_init();
sc.transmitter = &usart_send;
sc.foo();
while (1)
{
}
}
IncFile.h
#pragma once
#define rxBufferLen 50
#define txBufferLen 50
#include <avr/io.h>
#include "simpleClass.h"
#define TIMER0_CLOCK_PRESCALAR (3)
#define TIMER0_CLOCK_COUNT (0xff - 50)
void usart_init();
void timer0_init();
void serial_send_ln(const char *);
void usart_send(uint8_t *, uint8_t);
void usart_send_ln(uint32_t num);
SimpleClass.h
#pragma once
typedef unsigned char uint8_t;
#ifndef rxBufferLen
#define rxBufferLen 30
#endif
#ifndef txBufferLen
#define txBufferLen 30
#endif
class SimpleClass{
uint8_t rxbuffer[rxBufferLen]; ///< receiver buffer
uint8_t txBuffer[txBufferLen]; ///< transmitter buffer
uint8_t rxbuff_index, ///< rxbuffer index. Indicates where to put new data
txbuff_index; ///< txBuffer index. Indicates where to put new data
public:
void (*transmitter)(uint8_t * txbuff, uint8_t len);
void pushtx(uint8_t byte);
void pushrx(uint8_t byte);
void flush();
void foo();
};
SimpleClass.cpp
#include "simpleClass.h"
void SimpleClass::flush(){
transmitter(txBuffer, txbuff_index);
}
void SimpleClass::pushtx(uint8_t byte){
txBuffer[txbuff_index++] = byte;
}
void SimpleClass::pushrx(uint8_t byte){
rxbuffer[rxbuff_index++] = byte;
}
void SimpleClass::foo(){
uint8_t dv = 0;
dv ++ ;
pushtx(0x01);
pushtx(0x02);
pushtx(0x03);
pushtx(0x04);
pushtx(0x05);
flush();
}
CPPFile1.cpp
#include "IncFile1.h"
void usart_init(){
unsigned int ubrr = 51;
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, stop bit */
UCSR0C = (3<<UCSZ00);
}
void timer0_init(){
TCCR0B = TIMER0_CLOCK_PRESCALAR;
TIMSK0 = 1; // enable timer overflow interrupt
TCNT0 = TIMER0_CLOCK_COUNT;
}
void serial_send(const char * c){
for(uint8_t i=0 ; c[i] != '\0';i++){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = c[i];
}
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = 0x0a;
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = 0x0d;
}
void usart_send(uint8_t *buff, uint8_t len){
for(uint8_t i = 0; i < len; i++){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = buff[i];
}
}
void usart_send_ln(uint32_t num){
for(uint8_t i =0;i < 4; i++){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = num >> (8*(3-i));
}
}
Edits
You are violating the One Definition Rule - linking C++ program where the same class is defined twice and these definitions are not identical is undefined behaviour. The compiler/linker is not required to check or report these errors.
You are doing just that:
CPPFile1.cpp includes IncFile1.h which creates SimpleClass definition with buffers[50],
SimpleClass.cpp includes SimpleClass.h with buffers[30].
Its been a while since ive coded in c++/c and im a little confused as to what im doing wrong
I have three files, 2 .h and one .cpp.
The files are as follow
Base Menu
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
#define SSD1306_LCDHEIGHT 64
Adafruit_SSD1306 display(OLED_RESET);
class BaseMenu {
public:
// for moving the menu up and down
void moveDownMenu();
void moveUpMenu();
void selectMenu();
// for changing the text and the positions
void incrementText();
void decrementText();
protected:
//
char menuTitlePos1[20];
char menuTitlePos2[20];
char menuTitlePos3[20];
bool is_menuPos1_selected = true;
bool is_menuPos2_selected = false;
bool is_menuPos3_selected = false;
private:
virtual void AbstractClass() = 0;
};
MainMenu.h
#include "BaseMenu.h"
#include <string.h>
#define ARRAYSIZE 4
class MainMenu : BaseMenu {
private:
// Constructor
MainMenu() {};
public:
static void init();
};
MainMenu.cpp
#include "MainMenu.h"
void MainMenu::init() {
// clearing display
display.clearDisplay();
display.display();
display.setTextSize(1);
display.setTextColor(WHITE);
for (int i = 0; i < ARRAYSIZE; i++) {
if (i == 1) {
display.setTextSize(1);
display.setTextColor(BLACK, WHITE);
//display.println(MainMenuTitles[i]);
}
else {
display.setTextSize(1);
display.setTextColor(WHITE);
//display.println(MainMenuTitles[i]);
}
}
display.display();
}
When ever i go to build the code i get the following error.
MainMenu.cpp.o (symbol from plugin)*: In function display
(.text+0x0)*: multiple definition of display
TestingLibrary.cpp.o (symbol from plugin)*: (.text+0x0): first defined here
collect2.exe*: error: ld returned 1 exit status
Can someone please shed some light as to what i'm doing wrong?
I am trying to split up my arduino code base from a single 'ino' file into a proper-ish c++ program by creating classes which have both .h & .cpp files. I am running into a few errors that I just haven't been able to solve. I hope I am missing something simple.
When compiling in visual studio running the "Arduino IDE for Visual Studio" plugin, I get the following errors:
7:8: error: 'class MPU6050' has no member named 'timer
30:5: error: prototype for 'int MPU6050::MPU6050_read(int, uint8_t*, int)' does not match any in class 'MPU6050
What am I missing here?
.h
#ifndef MPU6050_H
#define MPU6050_H
class MPU6050
{
private: // Vars
uint32_t timer; // Hold the value of the timer used for the complementary filter
int error;
public: // Methods
MPU6050();
~MPU6050();
void read_acc_gyr();
float const * const getXa();
float const * const getYa();
float const * const getXvel();
float const * const getYvel();
float const * const getZvel();
float const * const getZang();
double const * const getDt();
private:
void test_gyr_acc();
void MPU6050_init();
void printGyroValues();
void calibrateGyro();
int MPU6050_write(int start, const uint8_t *pData, int size);
int MPU6050_read(int start, uint8_t *buffer, int size);
int MPU6050_write_reg(int reg, uint8_t data);
};
#endif
.cpp
#include "MPU6050.h"
#include "Arduino.h"
#include "MPU6050Definitions.h"
MPU6050::MPU6050()
{
timer = 0; // Always start the timer at 0
error = 1;
Serial.println("Testing Gyro");
test_gyr_acc();
}
MPU6050::~MPU6050()
{
}
int MPU6050::MPU6050_read(int start, uint8_t *buffer, int size)
{
int i, n, error;
Wire.beginTransmission(MPU6050_I2C_ADDRESS);
n = Wire.write(start);
if (n != 1)
return (-10);
n = Wire.endTransmission(false); // hold the I2C-bus
if (n != 0)
return (n);
// Third parameter is true: relase I2C-bus after data is read.
Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true);
i = 0;
while (Wire.available() && i<size)
{
buffer[i++] = Wire.read();
}
if (i != size)
return (-11);
return (0); // return : no error
}
void MPU6050::test_gyr_acc()
{
uint8_t c = 0;
error = MPU6050_read(MPU6050_WHO_AM_I, &c, 1);
if (error != 0) {
while (true) {
digitalWrite(13, HIGH);
delay(300);
digitalWrite(13, LOW);
delay(300);
}
}
}
MPUT6050Definitions.h includes all of my constants and looks like the following: (many more #defines which I don't think are relevant to include)
#pragma once
//All the values to setup the MPU6050 gyro/accelermeter
#define MPU6050_AUX_VDDIO 0x01 // R/W
#define MPU6050_SMPLRT_DIV 0x19 // R/W
#define MPU6050_CONFIG 0x1A // R/W
#define MPU6050_GYRO_CONFIG 0x1B // R/W
It looks like I made a simple mistake.
A few more errors down the list was an unknown declaration of type uint_32 which propagated itself causing the errors I was seeing before. I included the Arduino.h header which resolved the uint_32 problem causing the rest of the code to compile as expected.
Moral of the story is don't try to fix your errors from the top down.
moc_mm.o: In function `Counter::metaObject() const':
moc_mm.cpp:(.text+0x0): multiple definition of `Counter::metaObject() const'
moc_joystick.o:moc_joystick.cpp:(.text+0x0): first defined here
moc_mm.o:(.rodata+0x0): multiple definition of `Counter::staticMetaObject'
Which part of the code am I supposed to present here, w.r.t this error?
What is meaning of this error?
I have done make clean, but that doesn't help. The function name metaObject seems to be internal to Qt.
EDIT 1:
Adding the header file:
#include <stdio.h>
#include <QObject>
#ifndef __JOYSTICK_H__
#define __JOYSTICK_H__
#define JOYSTICK_DEVNAME "/dev/input/js0"
#define JS_EVENT_BUTTON 0x01 /* button pressed/released */
#define JS_EVENT_AXIS 0x02 /* joystick moved */
#define JS_EVENT_INIT 0x80 /* initial state of device */
struct js_event {
unsigned int time; /* event timestamp in milliseconds */
short value; /* value */
unsigned char type; /* event type */
unsigned char number; /* axis/button number */
};
struct wwvi_js_event {
int button[11];
int stick_x;
int stick_y;
};
class Counter : public QObject
{
Q_OBJECT
private:
int m_value;
public:
Counter() { m_value = 0; }
int value() const { return m_value; }
//public slots:
int open_joystick();
int read_joystick_event(struct js_event *jse);
//void set_joystick_y_axis(int axis);
//void set_joystick_x_axis(int axis);
void close_joystick();
int get_joystick_status(struct wwvi_js_event *wjse);
//signals:
//void valueChanged(int newValue);
};
#endif
Output:
anisha#linux-dopx:~/Desktop/anishaJoystick> qmake -project
anisha#linux-dopx:~/Desktop/anishaJoystick> qmake
anisha#linux-dopx:~/Desktop/anishaJoystick> make
g++ -m64 -Wl,-O1 -Wl,-rpath,/home/anisha/qtsdk-2010.05/qt/lib -o anishaJoystick joy.o mm.o moc_joystick.o moc_mm.o -L/home/anisha/qtsdk-2010.05/qt/lib -lQtGui -L/home/anisha/qtsdk-2010.05/qt/lib -L/usr/X11R6/lib64 -lQtCore -lpthread
moc_mm.o: In function `Counter::metaObject() const':
moc_mm.cpp:(.text+0x0): multiple definition of `Counter::metaObject() const'
moc_joystick.o:moc_joystick.cpp:(.text+0x0): first defined here
moc_mm.o:(.rodata+0x0): multiple definition of `Counter::staticMetaObject'
moc_joystick.o:(.rodata+0x0): first defined here
moc_mm.o: In function `Counter::qt_metacast(char const*)':
moc_mm.cpp:(.text+0x20): multiple definition of `Counter::qt_metacast(char const*)'
moc_joystick.o:moc_joystick.cpp:(.text+0x30): first defined here
moc_mm.o: In function `Counter::valueChanged(int)':
moc_mm.cpp:(.text+0x70): multiple definition of `Counter::valueChanged(int)'
mm.o:mm.cpp:(.text+0x10): first defined here
moc_mm.o: In function `Counter::qt_metacall(QMetaObject::Call, int, void**)':
moc_mm.cpp:(.text+0xb0): multiple definition of `Counter::qt_metacall(QMetaObject::Call, int, void**)'
moc_joystick.o:moc_joystick.cpp:(.text+0x20): first defined here
collect2: ld returned 1 exit status
make: *** [anishaJoystick] Error 1
Source file:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "joystick.h"
static int joystick_fd = -1;
int Counter::open_joystick()
{
joystick_fd = open(JOYSTICK_DEVNAME, O_RDONLY | O_NONBLOCK); // read write for force feedback?
if (joystick_fd < 0)
return joystick_fd;
// maybe ioctls to interrogate features here?
return joystick_fd;
}
int Counter::read_joystick_event(struct js_event *jse)
{
int bytes;
bytes = read(joystick_fd, jse, sizeof(*jse));
if (bytes == -1)
return 0;
if (bytes == sizeof(*jse))
return 1;
printf("Unexpected bytes from joystick:%d\n", bytes);
return -1;
}
void Counter:: close_joystick()
{
close(joystick_fd);
}
int Counter::get_joystick_status(struct wwvi_js_event *wjse)
{
int rc;
struct js_event jse;
if (joystick_fd < 0)
return -1;
// memset(wjse, 0, sizeof(*wjse));
while ((rc = read_joystick_event(&jse) == 1)) {
jse.type &= ~JS_EVENT_INIT; /* ignore synthetic events */
if (jse.type == JS_EVENT_AXIS) {
switch (jse.number) {
case 0: wjse->stick_x = jse.value;
break;
case 1: wjse->stick_y = jse.value;
break;
default:
break;
}
} else if (jse.type == JS_EVENT_BUTTON) {
if (jse.number < 10) {
switch (jse.value) {
case 0:
case 1: wjse->button[jse.number] = jse.value;
break;
default:
break;
}
}
}
}
// printf("%d\n", wjse->stick1_y);
return 0;
}
//#if 0
/* a little test program */
int main(int argc, char *argv[])
{
int fd, rc;
int done = 0;
struct js_event jse;
Counter c;
fd = c.open_joystick();
if (fd < 0) {
printf("open failed.\n");
exit(1);
}
while (!done) {
rc = c.read_joystick_event(&jse);
usleep(1000);
if (rc == 1) {
printf("Event: time %8u, value %8hd, type: %3u, axis/button: %u\n", jse.time, jse.value, jse.type, jse.number);
}
}
}
//#endif
You probably have multiple moc_* files, perhaps old ones after some renames, in your directory, and running qmake -project has included the old ones in your build. It finds multiple moc_* declarations for the same names (moc_mm.cpp and moc_joystick.cpp) and conflicts.
Remove all moc_* files by hand and re-create the .pro file with -project.
This error also happens when you accidentally use the Q_OBJECT macro twice for the same class.
For example, I just had this during a messed up transition from a source code layout with declaration and implementation in the .cpp file (as described here) to the typical layout of splitting these into .h and .cpp. Mapped to your example code, my code was as follows:
joystick.h: Exactly as in the question, including this key section with the macro call:
class Counter : public QObject {
Q_OBJECT
// ... method declarations here ...
};
joystick.cpp, including the accidental second macro call from leftovers of the original implementation that was completely here:
class Counter : public QObject {
// The erroneous SECOND call of the macro.
Q_OBJECT
// ... method definitions here ...
};
// The obligatory include when using the Q_OBJECT macro in a .cpp file.
#include "joystick.moc"