I'm a bit new to C/C++. I'm working on my first real project, and it's the first time I've used multiple files. I'm currently stuck with it saying I have multiple definitions of a big long list of stuff (just about everything).
The way I have the code set up is each file has its own .c and .h file, declarations and constant definitions in the header files, then function definitions in the c file. The files form a long chain so that all files get included, and none are included more than once. In ascending order, each file includes the one before it.
- Bus_Timing.h (uses "extern" to reference a variable from file 3)
- Bus_Timing.c
- Communication_Format.h
- Communication_Format.c (uses functions & variables from file 1&2, naturally called/used because those files are upstream in the include chain)
- Cashless.h
- Cashless.c (uses functions & variables from files 1-4, they're included upstream)
- Main.c
In general, the first few errors say I defined a function in file 2 (or "defined" a variable, by assigning it a value), then when I try to use that function or variable in file 6, it sees it as a 2nd definition rather than a function call or me assigning a value to the variable.
If what I'm doing wrong hasn't been revealed yet, here's the files and error codes. I've left the "cashless" files out because they're 1000+ lines each. Note, i'm using arduino so there is a bit of c++ but I'm trying to stick to C because I want this to run on linux eventually. You can get to the error list by scrolling to the very bottom.
Thanks if anyone helps! It's an open source project (currently just me working on it) I made to provide super easy to use, 100% capable&configurable code to interact with vending machines in an abstract way (making it substantially easier for a tech startup to make some new device for a vending machine). The industry standard this code is a transcription of, has existed nearly half a century, and still there are no software libraries for it, so that's what this code is aimed to fix. There's more files, but they're irrelevant to the question.
Bus_Timing.h
Code:
#include <esp32-hal.h>
struct transmission { //Structure for status/timing flags related to the MDB transmission.
unsigned char isUnresponsive : 1; //Flag set when transmission completes and non-response time is reached before a response.
unsigned char isDone : 1; //Flag set when recieved transmission completes and inter-byte time-out is reached before the next byte, or know end of conversation (poll required before peripheral transmits again).
unsigned char isResetting : 1; //Flag set when a 'BUS RESET' is taking place.
unsigned char isActive : 1; //Flag set when VMC's TX line goes active, and unset the instant the line goes inactive (used to detect 'BUS RESET').
} transmission;
unsigned long microseconds;//microseconds = Used by the timing method with 'micros()' in order to measure how many microseconds have gone by since the method was last called, rather than how many have gone by since the system started up.
void chronoLogic(unsigned char command, unsigned char address); //Stopwatch that updates all timing flags. Update later to have separate timers for each device.
extern unsigned int result;
extern unsigned long micros();
Bus_Timing.c
Code:
#include "Bus_Timing.h"
void chronoLogic(unsigned char command, unsigned char address) { //Command 0 to reset. Command 1 to update timing variables. Think of it like a stopwatch, but it updates flags rather than reporting a time.
if (!command) {
microseconds = micros(); //Save time of this command's execution.
transmission.isDone = 0; //Reset the inter-byte timing flag.
transmission.isUnresponsive = 0; //Reset the non-response timing flag.
transmission.isResetting = 0; //Reset the 'BUS RESET' timing flag.
return;
}
result = micros() - microseconds;
if (result > 2144) transmission.isDone = 0x01;
if (result > 6144) transmission.isUnresponsive = 0x01;
if (result > 101144) transmission.isResetting = 0x01;
if (result > 201144) transmission.isResetting = 0x00;
return;
}
Code:
#include "Bus_Timing.cpp"
unsigned int counter, result, pointer;
unsigned char checksum, ack, ret, nak;
unsigned short txBypass; /*Fixes tx() using nineBit datatype's read-only as a write method.*/
/*counter = A tracker for loops to define an endpoint with.*/
/*result = A non-volatile temporary storage variable for results of operations to be stored. When calling a method and using the returned value from it, this makes checking the value more than once possible.*/
/*pointer = Points to the last byte in a data block to indicate when to stop transmitting or when the last recieved byte occurs within the block.*/
/*checksum = Calculated checksum for comparison with recieved checksum.*/
/*ack, ret, nak = Values of described command/value.*/
void serialEvent1(); //9 bit UART data recieved.
int rX(unsigned char address); //Recieves a byte, judges if it needs to recieve the rest of the data, and ends at appropriate time. Returns status codes.
void clearBlock(); //Clear all communications related variables.
int tX(unsigned int pointer, unsigned char address); //Send the data in the block, calculate and insert check byte into location of pointer, uness pointer is zero. ALways sets mode bit on last byte.
union nineBit { //Union allows writing mode and data bits simultaneously as a short, therefore not overwriting one another. Bit format: dddddddd_______m
struct { //Structure allows accessing 8 data bits and 1 mode bit separately, as well as setting the parent union's size.
unsigned char data : 8; //8 data bits dddddddd most significant byte when written to as a short..
unsigned char mode : 1; //1 mode bit _______m least significant byte when written to as a short.
} part; //Named for readability & organization of code.
unsigned short whole; //Allows writing the 'data' and 'mode' all at once, otherwise the second write would erase the first.
} block[35]; //Array of 9 bit data, 36 is the maximum amount of 'bytes' MDB allows per transmission.
unsigned char command; //Would be part of the 'block' union but must be a separate variable.
static struct peripheral {
unsigned char isActive : 1;
unsigned char address;
} peripheral;
Communication_Format.c
Code:
//static unsigned char
#include "Communication_Format.h"
#include <HardwareSerial.h>
int rX(unsigned char address) { //1=ACK, 2=NAK, 3=RET, 4=NO-RESPONSE, 5=Ignored, 6=OK!
clearBlock();
while (!Serial1.available()) { //Wait for first byte.
chronoLogic(1, address); //Update timing flags.
if (transmission.isUnresponsive) //Check if time is up.
return 4; //Return status that time is up if so.
}
block[counter].whole = Serial1.read(); //Get first byte.
command = block[0].part.data;
if (block[0].part.data == ack) //If Acknowledged...
return 1; //Return with one, meaning Acknowledge response recieved.
if (block[0].part.data == ret) //If VMC requests a retransmit...
return 3; //Return to API in order to reload the block w/ data.
if (block[0].part.data == nak) //If Negatively Acknowledged...
return 2;
if (!block[0].part.mode) {
if (!peripheral.isActive)
return 5; //Return if it's not an address byte and the device isn't active.
}
else if ((block[0].part.data & 0xf8) != peripheral.address)
return 5; //Return if it's not addressed to you.
while (counter != 36) { //While the counter does not exceed the maximum block size...
while (!Serial1.available()) { ////Wait for data to be recieved.
chronoLogic(1, address); //Update timing flags.
if (transmission.isDone) //Check for inter-byte timeout.
return 6; //Transmission ended.
}
chronoLogic(0, address);
checksum += block[counter].part.data; //Add last byte to checksum.
counter++;
block[counter].whole = Serial1.read(); //Recieve data byte.
}
}
void clearBlock() { //Clears data out of the block.
counter = 0;
while (counter != 36) {
block[counter].whole = (0x0000);
counter++;
}
counter = 0;
command = 0x0;
checksum = 0x00;
}
int tX(unsigned int pointer, unsigned char address) {
counter = 0;
checksum = 0x00;
while (pointer != counter) {
Serial1.write(block[counter].whole);
checksum += block[counter].part.data; //Add on to the checksum byte.
counter++;
Serial1.flush(); //Wait for information to finish sending, placed here so previous commands execute prior to any waiting time.
}
block[counter].whole = (block[counter].whole | checksum | 0x100);
Serial1.write(block[counter].whole);
chronoLogic(0, address); //Set non-response timer.
result = rX(address);
if ((result == 1) || (result == 2) || (result == 4))
clearBlock();
return result;
} //The pointer describes how many data bytes are sent. If just sending ACK or NAK, there are zero data bytes. Commands are considered data bytes.
Error
Code:
Arduino: 1.8.7 (Mac OS X), Board: "ESP32 Dev Module, Disabled, Default, 240MHz (WiFi/BT), QIO, 80MHz, 4MB (32Mb), 921600, None"
sketch/Cashless.cpp.o:(.bss.transmission+0x0): multiple definition of `transmission'
sketch/Bus_Timing.cpp.o:(.bss.transmission+0x0): first defined here
sketch/Cashless.cpp.o: In function `chronoLogic(unsigned char, unsigned char)':
Cashless.cpp:(.text._Z11chronoLogichh+0x0): multiple definition of `chronoLogic(unsigned char, unsigned char)'
sketch/Bus_Timing.cpp.o:Bus_Timing.cpp:(.text._Z11chronoLogichh+0x0): first defined here
sketch/Cashless.cpp.o:(.bss.microseconds+0x0): multiple definition of `microseconds'
sketch/Bus_Timing.cpp.o:(.bss.microseconds+0x0): first defined here
sketch/Communication_Format.cpp.o:(.bss.transmission+0x0): multiple definition of `transmission'
sketch/Bus_Timing.cpp.o:(.bss.transmission+0x0): first defined here
sketch/Communication_Format.cpp.o:(.bss.result+0x0): multiple definition of `result'
sketch/Cashless.cpp.o:(.bss.result+0x0): first defined here
sketch/Communication_Format.cpp.o: In function `chronoLogic(unsigned char, unsigned char)':
Communication_Format.cpp:(.text._Z11chronoLogichh+0x0): multiple definition of `chronoLogic(unsigned char, unsigned char)'
sketch/Bus_Timing.cpp.o:Bus_Timing.cpp:(.text._Z11chronoLogichh+0x0): first defined here
sketch/Communication_Format.cpp.o:(.bss.counter+0x0): multiple definition of `counter'
sketch/Cashless.cpp.o:(.bss.counter+0x0): first defined here
sketch/Communication_Format.cpp.o:(.bss.block+0x0): multiple definition of `block'
sketch/Cashless.cpp.o:(.bss.block+0x0): first defined here
sketch/Communication_Format.cpp.o:(.bss.command+0x0): multiple definition of `command'
sketch/Cashless.cpp.o:(.bss.command+0x0): first defined here
sketch/Communication_Format.cpp.o:(.bss.checksum+0x0): multiple definition of `checksum'
sketch/Cashless.cpp.o:(.bss.checksum+0x0): first defined here
sketch/Communication_Format.cpp.o: In function `clearBlock()':
Communication_Format.cpp:(.text._Z10clearBlockv+0x0): multiple definition of `clearBlock()'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z10clearBlockv+0x0): first defined here
sketch/Communication_Format.cpp.o:(.bss.ack+0x0): multiple definition of `ack'
sketch/Cashless.cpp.o:(.bss.ack+0x0): first defined here
sketch/Communication_Format.cpp.o:(.bss.ret+0x0): multiple definition of `ret'
sketch/Cashless.cpp.o:(.bss.ret+0x0): first defined here
sketch/Communication_Format.cpp.o:(.bss.nak+0x0): multiple definition of `nak'
sketch/Cashless.cpp.o:(.bss.nak+0x0): first defined here
sketch/Communication_Format.cpp.o: In function `rX(unsigned char)':
Communication_Format.cpp:(.text._Z2rXh+0x0): multiple definition of `rX(unsigned char)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z2rXh+0x0): first defined here
sketch/Communication_Format.cpp.o: In function `tX(unsigned int, unsigned char)':
Communication_Format.cpp:(.text._Z2tXjh+0x0): multiple definition of `tX(unsigned int, unsigned char)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z2tXjh+0x0): first defined here
sketch/Communication_Format.cpp.o:(.bss.txBypass+0x0): multiple definition of `txBypass'
sketch/Cashless.cpp.o:(.bss.txBypass+0x0): first defined here
sketch/Communication_Format.cpp.o:(.bss.pointer+0x0): multiple definition of `pointer'
sketch/Cashless.cpp.o:(.bss.pointer+0x0): first defined here
sketch/Communication_Format.cpp.o:(.bss.microseconds+0x0): multiple definition of `microseconds'
sketch/Bus_Timing.cpp.o:(.bss.microseconds+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.cashless2+0x0): multiple definition of `cashless2'
sketch/Cashless.cpp.o:(.bss.cashless2+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.cashless+0x0): multiple definition of `cashless'
sketch/Cashless.cpp.o:(.bss.cashless+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.transmission+0x0): multiple definition of `transmission'
sketch/Bus_Timing.cpp.o:(.bss.transmission+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.result+0x0): multiple definition of `result'
sketch/Cashless.cpp.o:(.bss.result+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `chronoLogic(unsigned char, unsigned char)':
MDB.ino.cpp:(.text._Z11chronoLogichh+0x0): multiple definition of `chronoLogic(unsigned char, unsigned char)'
sketch/Bus_Timing.cpp.o:Bus_Timing.cpp:(.text._Z11chronoLogichh+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.counter+0x0): multiple definition of `counter'
sketch/Cashless.cpp.o:(.bss.counter+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.block+0x0): multiple definition of `block'
sketch/Cashless.cpp.o:(.bss.block+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.command+0x0): multiple definition of `command'
sketch/Cashless.cpp.o:(.bss.command+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.checksum+0x0): multiple definition of `checksum'
sketch/Cashless.cpp.o:(.bss.checksum+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `clearBlock()':
MDB.ino.cpp:(.text._Z10clearBlockv+0x0): multiple definition of `clearBlock()'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z10clearBlockv+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.ack+0x0): multiple definition of `ack'
sketch/Cashless.cpp.o:(.bss.ack+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.ret+0x0): multiple definition of `ret'
sketch/Cashless.cpp.o:(.bss.ret+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.nak+0x0): multiple definition of `nak'
sketch/Cashless.cpp.o:(.bss.nak+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `rX(unsigned char)':
MDB.ino.cpp:(.text._Z2rXh+0x0): multiple definition of `rX(unsigned char)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z2rXh+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `tX(unsigned int, unsigned char)':
MDB.ino.cpp:(.text._Z2tXjh+0x0): multiple definition of `tX(unsigned int, unsigned char)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z2tXjh+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `cashlessSetup()':
MDB.ino.cpp:(.text._Z13cashlessSetupv+0x0): multiple definition of `cashlessSetup()'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z13cashlessSetupv+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.cashless1+0x0): multiple definition of `cashless1'
sketch/Cashless.cpp.o:(.bss.cashless1+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `resetPeripheral(int)':
MDB.ino.cpp:(.text._Z15resetPeripherali+0x0): multiple definition of `resetPeripheral(int)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z15resetPeripherali+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `beginSession(int, String)':
MDB.ino.cpp:(.text._Z12beginSessioni6String+0x0): multiple definition of `beginSession(int, String)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z12beginSessioni6String+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `startCashless(int)':
MDB.ino.cpp:(.text._Z13startCashlessi+0x0): multiple definition of `startCashless(int)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z13startCashlessi+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `sessionCancelRequest(int, String)':
MDB.ino.cpp:(.text._Z20sessionCancelRequesti6String+0x0): multiple definition of `sessionCancelRequest(int, String)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z20sessionCancelRequesti6String+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `vendApproved(int, String)':
MDB.ino.cpp:(.text._Z12vendApprovedi6String+0x0): multiple definition of `vendApproved(int, String)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z12vendApprovedi6String+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `vendDenied(int, String)':
MDB.ino.cpp:(.text._Z10vendDeniedi6String+0x0): multiple definition of `vendDenied(int, String)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z10vendDeniedi6String+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `displayRequest(String)':
MDB.ino.cpp:(.text._Z14displayRequest6String+0x0): multiple definition of `displayRequest(String)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z14displayRequest6String+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `displayCancel(String)':
MDB.ino.cpp:(.text._Z13displayCancel6String+0x0): multiple definition of `displayCancel(String)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z13displayCancel6String+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.pointer+0x0): multiple definition of `pointer'
sketch/Cashless.cpp.o:(.bss.pointer+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `rESET(int)':
MDB.ino.cpp:(.text._Z5rESETi+0x0): multiple definition of `rESET(int)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z5rESETi+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `pOLL(int)':
MDB.ino.cpp:(.text._Z4pOLLi+0x0): multiple definition of `pOLL(int)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z4pOLLi+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `sETUP(int)':
MDB.ino.cpp:(.text._Z5sETUPi+0x0): multiple definition of `sETUP(int)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z5sETUPi+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `vEND(int)':
MDB.ino.cpp:(.text._Z4vENDi+0x0): multiple definition of `vEND(int)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z4vENDi+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `rEADER(int)':
MDB.ino.cpp:(.text._Z6rEADERi+0x0): multiple definition of `rEADER(int)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z6rEADERi+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `rEVALUE(int)':
MDB.ino.cpp:(.text._Z7rEVALUEi+0x0): multiple definition of `rEVALUE(int)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z7rEVALUEi+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `eXPANSION(int)':
MDB.ino.cpp:(.text._Z9eXPANSIONi+0x0): multiple definition of `eXPANSION(int)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z9eXPANSIONi+0x0): first defined here
sketch/MDB.ino.cpp.o: In function `cashlessMain(int)':
MDB.ino.cpp:(.text._Z12cashlessMaini+0x0): multiple definition of `cashlessMain(int)'
sketch/Cashless.cpp.o:Cashless.cpp:(.text._Z12cashlessMaini+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.txBypass+0x0): multiple definition of `txBypass'
sketch/Cashless.cpp.o:(.bss.txBypass+0x0): first defined here
sketch/MDB.ino.cpp.o:(.bss.microseconds+0x0): multiple definition of `microseconds'
sketch/Bus_Timing.cpp.o:(.bss.microseconds+0x0): first defined here
/var/folders/yp/9ssqgmw5487096x4gxt_syn80000gp/T/arduino_cache_16607/core/core_6a7bd73d325d0e5f3ec363d0061f08d8.a(HardwareSerial.cpp.o):(.bss.Serial+0x0): multiple definition of `Serial'
sketch/MDB.ino.cpp.o:(.bss.Serial+0x0): first defined here
/var/folders/yp/9ssqgmw5487096x4gxt_syn80000gp/T/arduino_cache_16607/core/core_6a7bd73d325d0e5f3ec363d0061f08d8.a(main.cpp.o):(.literal._Z8loopTaskPv+0x4): undefined reference to `loop()'
/var/folders/yp/9ssqgmw5487096x4gxt_syn80000gp/T/arduino_cache_16607/core/core_6a7bd73d325d0e5f3ec363d0061f08d8.a(main.cpp.o): In function `loopTask(void*)':
/Users/Nathan/Documents/Arduino/hardware/espressif/esp32/cores/esp32/main.cpp:23: undefined reference to `loop()'
collect2: error: ld returned 1 exit status
exit status 1
Error compiling for board ESP32 Dev Module.
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.