problem compiling "large" project

I’m building something that right now amounts to 1600 lines of C, compiles to about 40K of code in a Mega2560.

I’m using arduino 1.5.4 on a Linux system. I’m an experienced developer with many years of C embedded systems
work behind me.

I’d hit the “Java stack overflow” problem once, re-wrote some stuff, and magically the error went away. My
research had indicated that stack overflows were due to bugs in the IDE pre-processor.

I hit the “Java stack overflow” problem again, and decided that my code was too complex, at one huge .ino file
of 1600 lines. So I decided to move some subroutines into .c and .h files to reduce the complexity for the
pre-processor.

Now I’m getting errors that just don’t make sense.

I tried to move all my #includes and global variable declarations into one .h file, and then include this in all the
little .c files. That “didn’t seem to work”, in that I was getting errors implying that the nested includes weren’t
happening.

So I moved just the needed #includes into ONE of the .c files, and tried to compile using the Arduino IDE.

It’s still puking as if it’s ignoring the #includes.

Here’s the .c file:

#include <Time.h>
#include <SPI.h>
#include <SD.h>

#include <HardwareSerial.h>

#define SDDEBUG 1
#define SDCARD 1

extern time_t tNow;
extern int Fvalue[];
extern char Dbuf[150];  //general purpose buffer for strings
extern char Dbuf2[50];  // all the rest for building messages with sprintf
extern char Dbuf3[300];
extern char Dbuf4[20];
extern char Dbuf5[300];

#define DL(x) Serial.print(x)
#define DLn(x) Serial.println(x)
#define DV(m, v) do{Serial.print(m);Serial.print(v);Serial.print(" ");}while(0)
#define DVn(m, v) do{Serial.print(m);Serial.println(v);}while(0)


void SDdatalog (unsigned char zone) {
    if(zone > 0) return;
    tNow = timelocal(now());
    // build line of date, time, and temperature:
    strcpy_P(Dbuf3,PSTR("%02d/%02d/%4d %02d:%02d:%02d\t%d\t%d"));
    sprintf(Dbuf,Dbuf3, month(tNow),day(tNow),year(tNow),hour(tNow),minute(tNow),second(tNow), Fvalue[zone], zone);

    // open the file.
    File dataFile = SD.open("datalog.txt", FILE_WRITE);

    // if the file is available, write to it:
    if (dataFile) {
        dataFile.println(Dbuf);
        dataFile.close();
#if SDDEBUG
        // print to the serial port too:
        Serial.println(Dbuf);
#endif
    }
#if SDDEBUG
    // if the file isn't open, pop up an error:
    else {
        Serial.println("error opening datalog.txt");
    }
#endif
}

And here are the errors:

In file included from /home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cors/arduino/Printable.h:23,
                 from /home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cors/arduino/Print.h:27,
                 from /home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cors/arduino/Stream.h:26,
                 from /home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cors/arduino/HardwareSerial.h:28,
                 from sdcard.c:5:
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/new.h:10: eror: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘new’
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/new.h:11: eror: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘new’
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/new.h:12: eror: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘delete’
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/new.h:13: eror: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘delete’
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/new.h:17: eror: expected identifier or ‘(’ before string constant
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/new.h:18: eror: expected identifier or ‘(’ before string constant
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/new.h:19: eror: expected identifier or ‘(’ before string constant
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/new.h:21: eror: expected identifier or ‘(’ before string constant
In file included from /home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cors/arduino/Print.h:27,
                 from /home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cors/arduino/Stream.h:26,
                 from /home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cors/arduino/HardwareSerial.h:28,
                 from sdcard.c:5:
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/Printable.h25: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘Print’
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/Printable.h33: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘Printable’
In file included from /home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cors/arduino/Stream.h:26,
                 from /home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cors/arduino/HardwareSerial.h:28,
                 from sdcard.c:5:
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/Print.h:34:error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘Print’
In file included from /home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cors/arduino/HardwareSerial.h:28,
                 from sdcard.c:5:
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/Stream.h:38 error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘Stream’
In file included from sdcard.c:5:
/home/dud/embedded/arduino-1.5.4/hardware/arduino/avr/cores/arduino/HardwareSeral.h:40: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘HardwaeSerial’
sdcard.c:10: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘tNw’
sdcard.c: In function ‘SDdatalog’:
sdcard.c:25: error: ‘tNow’ undeclared (first use in this function)
sdcard.c:25: error: (Each undeclared identifier is reported only once
sdcard.c:25: error: for each function it appears in.)
sdcard.c:31: error: ‘File’ undeclared (first use in this function)
sdcard.c:31: error: expected ‘;’ before ‘dataFile’
sdcard.c:34: error: ‘dataFile’ undeclared (first use in this function)
sdcard.c:39: error: ‘Serial’ undeclared (first use in this function)

Questions:

Can one do nested includes in Arduino IDE?

Why is the preprocessor ignoring the “#include <Time.h>” (tNow undeclared error) ???

Is there a DOCUMENTED way of building Arduino programs from the (Linux) command line? I see lots of broken links
and old pages about this, but nothing that seems current.

Thanks in advance for your time.

Bill Dudley

I think your separate source files should be .cpp - not .c

Pete

wfdudley:
Here's the .c file:

As @el_supremo mentioned, you will be better served feeding separate source files to the C++ compiler.

#include <Arduino.h>
#include <Time.h>
#include <SPI.h>
#include <SD.h>

#include <HardwareSerial.h>

#define SDDEBUG 1
#define SDCARD 1

extern time_t tNow;
extern int Fvalue;
extern char Dbuf[150]; //general purpose buffer for strings

Thanks for that. Adding the #include <Arduino.h> fixed a lot of errors, but I’m still getting errors
that suggest that the pre-processor isn’t including things I specify. I’ve changed the names of
the .c files to .cpp, as I guess that affects how the pre-processor works.

Here are more errors that tell me that things aren’t being #included, and I don’t understand why.

Here’s the “master” include file I am using:

thermostat.h:

#ifndef THERMOSTAT_H

#include <Arduino.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <Time.h>
#include <Ethernet.h> 
#include <EthernetUdp.h>
#include <Dns.h>
#include <SPI.h>
#include <SD.h>
            
#include <HardwareSerial.h> 
#include <EEPROM.h>
#include <OneWire.h>
#include <Timezone.h>

#if IS_MAIN
    #define EXTERN
    #define INIT(x) =x
#else
    #define EXTERN extern
    #define INIT(x)
#endif

EXTERN time_t tNow INIT(0);
EXTERN char Dbuf[150];  //general purpose buffer for strings
EXTERN char Dbuf2[50];  // all the rest for building messages with sprintf
EXTERN char Dbuf3[300];
EXTERN char Dbuf4[20];
EXTERN char Dbuf5[300];

#define THERMOSTAT_H 1
#endif

Here’s the use in “webclient.cpp”:

#include "thermostat.h"

// read a newline terminated line from the web template
PGM_P read_template_line (char *dbuf, PGM_P s) {
char c;
    *dbuf = '\0';
    while (c = pgm_read_byte(s)) {
        if(c == '\0') {
            *dbuf++ = '\0';
            return NULL;
        }      // leave pointing to '\0'
        else if(c == '\n') {
            *dbuf++ = c;
            *dbuf++ = '\0';
            s++;         // point to next line or '\0'
            break;
        }
        else {
            *dbuf++ = c;
            s++;
        }
    }
    return(s);
}

void show_template (EthernetClient eClient, unsigned char zone) {
PGM_P ptmpl;
char *p, *d;
    time_t tNow = timelocal(now());
    ptmpl = webtmpl;
    do {
        ptmpl = read_template_line (Dbuf, ptmpl);
        for(p = Dbuf, d = Dbuf3; *p ; ) {
            if(*p == '?') {
                *d = '\0';
                if(!strncmp_P(p, PSTR("?SAVE"), 5)) {
                    strcpy_P(d, state_saved[zone] ? PSTR("&nbsp;") : PSTR("<A HREF=/save>save</A>"));
                    d = Dbuf3 + strlen(Dbuf3);
                    p += 5;
                }
                else {
                    *d++ = *p++;
                }
            }
            else if(*p == '_') {
                *d = '\0';
                if(!strncmp_P(p, PSTR("_EOF"), 4)) {
                    ptmpl = NULL;
                    return;
                }
                else if(!strncmp_P(p, PSTR("_DATE"), 5)) {
                    strcpy_P(Dbuf2,PSTR("%02d:%02d:%02d"));
                    sprintf(d, Dbuf2 ,hour(tNow),minute(tNow),second(tNow));
                    d += 8;
                    *d = '\0';
                    p += 5;
                }
                else if(!strncmp_P(p, PSTR("_CTMP"), 5)) {
                    sprintf(d, "%2d", Fvalue[zone]);
                    d += 2;
                    *d = '\0';
                    p += 5;
                }
                else if(!strncmp_P(p, PSTR("_HYST"), 5)) {
                    sprintf(d, "%2d", configuration[zone].Hysteresis);
                    d += 2;
                    *d = '\0';
                    p += 5;
                }
                else if(!strncmp_P(p, PSTR("_STMP"), 5)) {
                    sprintf(d, "%2d", configuration[zone].tempSetting);
                    d += 2;
                    *d = '\0';
                    p += 5;
                }
                else if(!strncmp_P(p, PSTR("_SPACTV"), 7)) {
                    sp = p[7] - '0' ;
                    if(configuration[zone].setpoint[sp].active) {
                        strcpy_P(d, PSTR("On <A HREF=/spof"));
                        strcat(d, '0' + sp);
                        strcat(d, '0' + zone);
                        strcat_P(d, PSTR(">(-&gt; Off)</A>")) ;
                    }
                    else {
                        strcpy_P(d, PSTR("Off <A HREF=/spon
                        strcat(d, '0' + sp);
                        strcat(d, '0' + zone);
                        strcat_P(d, PSTR(">(-&gt; On)</A>")) ;
                    }
                    p += 8;
                }
                else if(!strncmp_P(p, PSTR("_SPTIME"), 7)) {
                    sp = p[7] - '0' ;
                    sprintf(d, "%2d:%02d", configuration[zone].setpoint[sp].hour, configuration[zone].setpoint[sp].minute);
                    d += 5;
                    *d = '\0';
                    p += 8;
                }
                else if(!strncmp_P(p, PSTR("_SPTEMP"), 7)) {
                    sp = p[7] - '0' ;
                    sprintf(d, "%2d", configuration[zone].setpoint[sp].temp);
                    d += 2;
                    *d = '\0';
                    p += 8;
                }
                else {
                    *d++ = *p++;
                }
            }
            else if(*p == '%') {
                if(*++p == 'd') {
                    sprintf(d, "%d", zone);
                    d++;
                    *d = '\0';
                    p++;
                }
                else {
                    *d++ = *p++;
                }
            }
            else if(*p == '\n') {
                *d++ = *p++;
                *p = '\0';
                *d = '\0';
                break;
            }
            else {
                *d++ = *p++;
            }
        }
#if DEBUG_TMPL
        Serial.print(Dbuf);
        Serial.println("^^^___dbuf");
        Serial.print(Dbuf3);
        Serial.println("^^^___dbuf3");
#endif
        eClient.print(Dbuf3);
    } while(Dbuf[0] && ptmpl);
}

// default or root level request, show status
void show_web_page (EthernetClient eClient) {
byte tm1, tp1;
unsigned char zone;
    // if (strstr_P(Dbuf2, PSTR("GET / ")) != 0)
    // standard http response header
    strcpy_P(Dbuf, PSTR("<html><head><title>Thermostat</title></head><body><table>"));
    eClient.print(Dbuf);
    for(zone = 0; zone < MAXZONES ; zone++) {
        show_template(eClient, zone);
    }
    strcpy_P(Dbuf, PSTR("</table></body></html>"));
    eClient.println(Dbuf);
}

finally, here are the error messages:

webclient.cpp:193:1: error: unterminated argument list invoking macro "PSTR"
In file included from webclient.cpp:1:
thermonew.h:42: error: ‘time_t’ does not name a type
webclient.cpp:26: error: variable or field ‘show_template’ declared void
webclient.cpp:26: error: ‘EthernetClient’ was not declared in this scope
webclient.cpp:26: error: expected primary-expression before ‘unsigned’

This was all working code before I cut it into pieces to avoid the “java stack overflow” problem,
so why is it complaining about “unterminated arg list . . . PSTR” ?

Why is time_t not recognized? I’m including <Time.h> in my thermostat.h file?

Similarly, why is ‘EthernetClient’ was not declared in this scope, when thermostat.h includes <Ethernet.h> ?

Thanks for your time,
Bill Dudley

A few things are missing from the end of this line…

strcpy_P(d, PSTR("Off <A HREF=/spon

All of these have to also be in your sketch…

#include <Time.h>
#include <Ethernet.h> 
#include <EthernetUdp.h>
#include <Dns.h>
#include <SPI.h>
#include <SD.h>
            
#include <EEPROM.h>
#include <OneWire.h>
#include <Timezone.h>

The first problem was apparently a cut and paste problem when I was creating webclient.cpp.
Thanks for spotting it, I just wished the error messages gave more of a hint besides listing
the last line in the file. But I suppose that's a wish for the gcc people, huh?

The last reply, about including all the header files in my .ino file, is the missing bit.
This isn't "just like" using a c compiler from the command line, is it? I have to explicitly
include them in the file so that the IDE "knows what to pull in".

Anyway, no I'm off finding all the other problems I created when I cut this into pieces.

Thanks to all..

Bill Dudley