When I add "extern" declarations of variables in the header file of the code which is using those variables (which are declared & defined in another file) that works fine. Except in 1 particular case: if the file which is using the "extern" variable is the main .ino file (the one with "setup" and "loop") then I get a compiler error: *"variable_name does not name a type; did you mean ...".
AFAIK it is best practice to put extern references always in a header file and not in de code file. Why is this not working for the main header file?
Am I doing something wrong?
please post the code
The sketch is called "Smartfloat" and contains the software to monitor the fuel level in a fuel tank.
In file "Smartfloat.h":
#pragma once
/*--------------------------------+
* All of this has global scope *
*---------------------------------*/
#define SYS_JOBLIST_SIZE 16 // size of array to hold job list and job requests
/*------------------+
* Debugging *
*-------------------*/
#define DEBUG_MAIN true // debug Smartfloat.ino
/******************************************************************************
* SmartFloat / ESP32 pins *
*******************************************************************************/
#define buzzPin GPIO_NUM_17 // buzzer (output)
#define btcLedPin GPIO_NUM_18 // Blue bluetooth connection LED (output)
#define errLedPin GPIO_NUM_19 // Red error LED (output)
#define fuelLedPin GPIO_NUM_21 // Green fuel status LED (output)
#define pwrLedPin GPIO_NUM_23 // Green power LED (output)
#define stripSensorDacPin GPIO_NUM_25 // DAC CH1 50 mV - 2.5 V (output)
#define stripSensorAdcPin GPIO_NUM_33 // ADC to verify correct DAC output (input)
// WARNING: SmartFloat PCB 3.1 rev0 needs wire bridges between GPIO 25 (PIN 9) and GPIO 33 (PIN 8), GPIO 25 and C of D6
// This error has been fixed in PCB rev 1.
#define FLS_FloatSensorPin GPIO_NUM_34 // ADC Float Sensor 0.5 - 2 V (analog input)
#define PWR_vBattPin GPIO_NUM_35 // vBatt = 0 - 3 V (analog input)
#define FLS_StripHeaterPin GPIO_NUM_36 // Fuelstrip heater signal (digital input)
#define FLS_FloatSwitchPin GPIO_NUM_39 // Strip Sensor Heater (digital input)
/******************
* I/O values *
*******************/
#define ON 1 // I/O value
#define OFF 0 // I/O value
#define SECONDS_IN_HOUR 3600 // seconds in 1 hour
/*---------------------+
* Version Information *
*---------------------*/
const char * versionString = "0.0.1"; // development software version
// Notification
/*---------------------+
* External references *
*---------------------*/
extern buzzer_t buzzer; // Buzzer.ino**
extern char BT_ownMacAddress[];
extern bt_spp_status_t bt_spp_status;
... etc...
The variables are used in file Smartfloat.ino like this:
void loop() {
/*---------------------------+
* Execute once every 100 ms *
*---------------------------*/
if (xSemaphoreTake(smartFloatTimerSemaphore, 0) == pdTRUE) // fuelTimer fires every 100 ms
{
if(buzzer.active) BUZZ_PlayTune(); // play buzzer tune
if(!engineRunning)
{Monitor PWR, else monitor PWR every second}
if(++smartFloatTimer == 10)
{ handle fuel monitoring actions and clear smartFloatTimer }
BT_SuperviseIncomingStream(); // check if BT incoming character stream is flowing
BT_SuperviseOutgoingStream(); // check if BT outgoing character stream is flowing
VBATT_MonitorVbatt(); // monitor battery voltage
FLS_MonitorFuelLevel(); // monitor float sensor value
//FLS_MonitorZFESheater(); // monitor fuel strip heater
//FLS_ShowFuelLevel(); // output fuel level
LED_LEDmonitor(); // handle LED blinking
}
etc...
Buzzer.h contains the declaration of the struct "buzzer_t"
typedef struct
{
bool active; // true when buzzer is engaged
uint8_t pinValue; // ON or OFF
buzzStatus_t status; // SOUND, SILENCE, WAIT4NEXT
unsigned int tune; // the tune to play
uint8_t bitIndex; // index in tune bit pattern
uint8_t waitCounter; // counter for pause between tunes
uint8_t playList[BUZZ_TUNE_PLAYLIST_SIZE]; // queue for more tunes to be played
uint8_t playListIndex; // index for playlist
} buzzer_t;
an finally the code file "buzzer.ino" contains the definition of the variable:
buzzer_t buzzer; // buzzer object
buzzTunes_t buzzTunes; // different bitpatterns representing tunes
Post the complete code, not snippets that we have to piece together ourselves.
which variable? where is it defined, declared and used?
The complete error message:
`In file included from D:\Gilbert\Documents\Arduino\ESP32\Code\SmartFloat_3_1_1\SmartFloat_3_1_1.ino:26:
D:\Gilbert\Documents\Arduino\ESP32\Code\SmartFloat_3_1_1\SmartFloat.h:59:8: error: 'buzzer_t' does not name a type; did you mean 'timer_t'?
extern buzzer_t buzzer; // Buzzer.ino
^~~~~~~~
timer_t
D:\Gilbert\Documents\Arduino\ESP32\Code\SmartFloat_3_1_1\SmartFloat.h:61:8: error: 'bt_spp_status_t' does not name a type; did you mean 'TaskStatus_t'?
extern bt_spp_status_t bt_spp_status;
^~~~~~~~~~~~~~~
TaskStatus_t
exit status 1
Compilation error: 'buzzer_t' does not name a type; did you mean 'timer_t'?`
I don't think that you want to walk through 8700 lines of code for this.
When I move the extern declarations from Smartfloat.h to Smartfloat.ino, the problem goes away.
All other files have the extern declarations in the header file and the compiler seems to be happy with that.
The obvious question is, where did you define the buzzer_t and bt_spp_status_t types?
Did you include the header files in which they are defined in the SmartFloats.h file before the extern declarations?
buzzer_t: struct declared in buzzer.ino and defined and used in buzzer.ino like this:
in buzzer.h:
typedef struct
{
bool active; // true when buzzer is engaged
uint8_t pinValue; // ON or OFF
buzzStatus_t status; // SOUND, SILENCE, WAIT4NEXT
unsigned int tune; // the tune to play
uint8_t bitIndex; // index in tune bit pattern
uint8_t waitCounter; // counter for pause between tunes
uint8_t playList[BUZZ_TUNE_PLAYLIST_SIZE]; // queue for more tunes to be played
uint8_t playListIndex; // index for playlist
} buzzer_t;
in buzzer.ino:
buzzer_t buzzer; // buzzer object
bt_spp_status_t: enum declared in BTspp.h and defined and used in BTspp.ino like this:
in BTspp.h:
typedef enum
{
BT_SPP_IDLE, // ready to accept incoming messages
BT_SPP_RECEIVING, // incoming stream in progress
BT_SPP_SENDING, // outgoing stream in progress, change to IDLE when done
BT_SPP_READY2PROCESS, // incoming stream complete, ready for parsing
BT_SPP_PROCESSING, // incoming stream parsing in progress
BT_SPP_FAIL, // something bad happened, re-init after delay
BT_SPP_CLOSED // SPP connection closed
} bt_spp_status_t;
in BTspp.ino:
bt_spp_status_t bt_spp_status; // status of BT serial communication link
Interesting detail: extern char BT_ownMacAddress[]; is also part of the group of extern references, but doesn't cause a problem. The difference is that BT_ownMacAddress[] is declared and defined in the BTspp.ino file. No declaration in the BTspp.h file.
I'll give it a try and merge the offending declarations into declaration + definition in their .ino file to see if the problem goes away. Surely not in agreement with recommended practice, but what the heck... Moving the extern declarations to the .ino file is also not "clean" code.
oesn't Smartfloat.h need to include the . h where the buzzer_t struct is defined?
Tried that. This works. Thanks. I thought that "include" always goes in the ino file and that's how it works for all other files. Maybe this doesn't cause problems for the compiler because most other files have been included previously at some point ?
PS: moving the offending declarations from the.h file to the corresponding .ino file didn't work.
Sketch uses 1110901 bytes (84%) of program storage space. Maximum is 1310720 bytes.
Global variables use 42968 bytes (13%) of dynamic memory, leaving 284712 bytes for local variables. Maximum is 327680 bytes.
See My Post #5 in this Thread for a basic guide to breaking large projects into separate .h / .cpp files.
Thanks for the clarification. I tried to stick to gfvalvo's recommended way of working, but with ino files iso cpp. Turns out that the IDE follows a different thinking...
However, when I comment out all "extern" references in my sketch the compiler complains about missing variabe declarations like this:
D:\Gilbert\Documents\Arduino\ESP32\Code\SmartFloat_3_1_1\Buzzer.ino: In function 'void BUZZ_SetTune(buzzTune_t)':
D:\Gilbert\Documents\Arduino\ESP32\Code\SmartFloat_3_1_1\Buzzer.ino:80:7: error: 'generalErrorCounters' was not declared in this scope
Did you see the last line at the link I posted??

The rest of the code should be in .cpp files.
Yes, I saw that.
I'm not used to program in "pure" c++. For me that means opening another can of worms ;-). I'll try that with a future (smaller) project.
True. But apart from the issue which started this thread, everything is fine. There's no value for me in changing to cpp in this project.
Thanks for the advice.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.