0

First question. If I include a header of a class to the header file of a second class, do I have to include the header of the first class to the .cpp file of the second class?

At the .cpp file of the second class I include its header which includes the .h file of the first class. So isn't it correct or do I have to include the first's class header to the .cpp file of the second class also?

Second problem. I have two classes. The first has static variables and functions, so I can call it without making objects. At the first class I have a static object of the second class. Now at the second class I want to pass the returns of some functions of the first class as operands to functions of the first class. I get no errors at the second's class, but I get an error at the declaration of the static object I mention before at the first class. Why is this happening?

The code:

Header files:

 /*
  * NTPlib.h
  *
  *  Created on: 13 Feb 2013
  *  Author    : Platonas
  */

#ifndef NTP_H_
#define NTP_H_

#include "Arduino.h"
#include "SPI.h"
#include "IPAddress.h"
#include "EthernetUdp.h"
#include "Ethernet.h"
#include "DayNumber.h"

class NTP {
    private:

    public:
        static EthernetUDP Udp;
        static DayNumber DN;

        static const int Gmt = 2;
        static const unsigned int localPort = 8888;
        static const int NTP_PACKET_SIZE = 48;

        static byte packetBuffer[NTP_PACKET_SIZE ];

        static unsigned long secsSince1900;
        static unsigned long UnixTime;
        static int utchour;
        static int lcthour;
        static int min;
        static int sec;
        static int year;
        static int month;
        static int date;
        static int dayOfWeek;
        static bool timeSet;

        NTP();
        static NTP getTime();
        static bool testNtpServer();
        static void startEthernetAndUdp();
        static unsigned long sendNTPpacket(IPAddress& address);
        static int getYear();
        static int getMonth();
        static int getDate();
        static int getDayOfWeek();
        static int getUTChour();
        static int getLCThour();
        static int getMin();
        static int getSec();
        static void serialPrinting();

        virtual ~NTP();
};

#endif /* NTPLIB_H_ */

and

    /*
      DayNumber.h - Library for calculation of day's number on 1 and 4 years loop.
      Created by Pavlidis Kyriakos, December 20, 2012.
      Released into the public domain.
    */

    #ifndef DayNumber_H_
    #define DayNumber_H_

    #include "NTP.h"

    class DayNumber {

        private:
            int _day1YearLoop[];
            int _day4YearLoop[];

        public:

            int Days1YearLoop;
            int Days4YearLoop;

        DayNumber();
        void dayNumberCalc();
        virtual ~DayNumber();

        bool checkLeapYear(int setYear);
    };

#endif

.cpp files:

/*
  NTP.cpp - Library for NTP server.
  Created by Pavlidis Kyriakos, Feb 13, 2013.
  Released into the public domain.
*/

#include "NTP.h"
#include "DayNumber.h"

unsigned long NTP::UnixTime = 0;
unsigned long NTP::secsSince1900 = 0;
int NTP::utchour = 99;
int NTP::lcthour = 99;
int NTP::min = 99;
int NTP::sec = 99;
int NTP::year = 99;
int NTP::month = 99;
int NTP::date = 99;
int NTP::dayOfWeek = 99;
byte NTP::packetBuffer[NTP_PACKET_SIZE ];
bool NTP::timeSet = false;
DayNumber NTP::DN = DayNumber();
EthernetUDP NTP::Udp = EthernetUDP();

NTP::NTP() {
    // TODO Auto-generated constructor stub
}

NTP NTP::getTime() {

    if (testNtpServer()) {
        timeSet = true;

        // We've received a packet, read the data from it
        Udp.read((unsigned char*)packetBuffer,NTP_PACKET_SIZE);  // Read the packet into the buffer

        // The timestamp starts at byte 40 of the received packet and is four bytes,
        // or two words, long. First, extract the two words:
        unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
        unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);

        // Combine the four bytes (two words) into a long integer.
        // This is NTP time (seconds since Jan 1 1900):
        secsSince1900 = highWord << 16 | lowWord;

        // Now convert NTP time into everyday time:
        // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
        const unsigned long seventyYears = 2208988800UL;

        // Subtract seventy years:
        UnixTime = secsSince1900 - seventyYears;

        sec = UnixTime % 60;

        //Calc min
        min = (UnixTime/60)%60;

        //Calc hour
        utchour = (UnixTime/3600)%24;
        lcthour = utchour + Gmt;

        //Day of the week
        dayOfWeek = (((UnixTime/86400UL) + 3) % 7) + 1; //Setting first day Sunday = 1

        //Calculating years
        unsigned long UnixTimeToDays = UnixTime/86400UL;
        //Serial.println(UnixTimeToDays);
        unsigned long calcDaysInYears = 0;
        int calcYear = 1970;
        while((calcDaysInYears += (DN.checkLeapYear(calcYear)? 366:365)) <= UnixTimeToDays) {
            calcYear++;
        }
        year = calcYear;

        //Calculating days in this year
        calcDaysInYears -= (DN.checkLeapYear(calcYear)? 366:365);
        int daysPassedInYear = UnixTimeToDays - calcDaysInYears;

        //Set DayNumber one year loop
        DN.Days1YearLoop = daysPassedInYear + 1;

        //calculating date and month
        static const uint8_t monthDays[] = {31,28,31,30,31,30,31,31,30,31,30,31};
        int calcMonth;
        int monthLength;

        for (calcMonth = 0; calcMonth<12; calcMonth++) {
            if (DN.checkLeapYear(year)) {
                monthLength = (calcMonth == 1) ? 29: 28;
            }
            else {
                monthLength = monthDays[calcMonth];
            }
            if ( daysPassedInYear > monthLength) {
                daysPassedInYear -= monthLength;
            }
            else {
                break;
            }
        }
        month = ++calcMonth;
        date = ++daysPassedInYear;

        serialPrinting();

        return NTP();
    }
    else {
        //Error me tous ntp diavazoume wra apo DS1307
        Serial.println("pame gia RTC");
        return NTP();
    }
}

unsigned long NTP::sendNTPpacket(IPAddress& address) {
  // Set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);

  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // Eight bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // All NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket();
}

void NTP::startEthernetAndUdp() {
    //Declaration of the mac address of ethernet shield
    byte mac[] = {0x00,0xAA,0xBB,0xCC,0xDE,0x02};
    if (Ethernet.begin(mac) == 0) {
        Serial.println("Failed to configure Ethernet using DHCP");
        // No point in carrying on, so do nothing forevermore:
        //for(;;)
        //    ;
        //Prepei na diorthwthei na kanei bypass to DHCP kai na paei sto RTC an den exei internet
    }
    Udp.begin(localPort);
}

bool NTP::testNtpServer() {
    //(193,93,167,241 ); //GR time server on athens ntp.asda.gr
    //(129,215,160,240 ); //UK extntp0.inf.ed.ac.uk School of Informatics, University of Edinburgh, Scotland, UK
    //(138,195,130,71 ); //FR ntp.via.ecp.fr VIA, Ecole Centrale Paris, France
    //(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov NTP server
    //(193,93,167,239); //GR time server on athens ChronosAsdaGr
    //(132, 163, 4, 102); // time-b.timefreq.bldrdoc.gov NTP server
    //(132, 163, 4, 103); // time-c.timefreq.bldrdoc.gov NTP server

    byte serverslist[4][4] = {
            193,93,167,241,
            129,215,160,240,
            138,195,130,71,
            132,163,4,101
    };
    IPAddress ntpServers(serverslist[0]);
    sendNTPpacket(ntpServers);
    int x = 0;
    delay(1000);

    //Checking different NTP server if someone is down
    while(!Udp.parsePacket() && x <= 3) {

        //Have to check parsePacket return.
        x++;
        IPAddress ntpServers(serverslist[x]);
        sendNTPpacket(ntpServers);
        delay(1000);
    }

    switch (x) {
        case 0:
            Serial.println("1st NTPServer working");
            return true;
            break;
        case 1:
            Serial.println("2st NTPServer working");
            return true;
            break;
        case 2:
            Serial.println("3st NTPServer working");
            return true;
            break;
        case 3:
            Serial.println("4st NTPServer working");
            return true;
            break;
        default:
            Serial.println("All NTP Servers are Down");
            return false;
    }
}

int NTP::getYear() {
    do {
        getTime();
    } while(timeSet == false);
    return year;
}

int NTP::getMonth() {
    do {
        getTime();
    }while(timeSet == false);
    return month;
}

int NTP::getDate() {
    do {
        getTime();
    } while(timeSet == false);
    return date;
}
int NTP::getDayOfWeek() {
    do {
        getTime();
    } while(timeSet == false);
    return dayOfWeek;
}
int NTP::getUTChour() {
    do {
        getTime();
    } while(timeSet == false);
    return utchour;
}
int NTP::getLCThour() {
    do {
        getTime();
    } while(timeSet == false);
    return lcthour;
}
int NTP::getMin() {
    do {
        getTime();
    } while(timeSet == false);
    return min;
}
int NTP::getSec() {
    do {
        getTime();
    } while(timeSet == false);

    return sec;
}

void NTP::serialPrinting() {

    //Serial.PRINTS
    //print seconds since 1900
    Serial.print("Seconds since Jan 1 1900 = " );
    Serial.println(secsSince1900);

    // print Unix time:
    Serial.print("Unix time = ");
    Serial.println(UnixTime);

    //print year
    Serial.print("the year is :");
    Serial.println(year);

    //print month
    Serial.print("Month is : ");
    Serial.print(month);

    //print date
    Serial.print(" Date is: ");
    Serial.println(date);

    //print dayOfWeek
    Serial.print("the day is : ");
    Serial.println(dayOfWeek);

    //printnumber of days that passed in this year (this day counts DayNumber object)
    Serial.print("This day is the number:");
    Serial.println(DN.Days1YearLoop);

    //print Local Time Hour
    Serial.print("The LTC time is ");
    Serial.println(lcthour);

    // Print the hour, minute and second:
    Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
    Serial.print(utchour); // Print the hour (86400 equals secs per day)
    Serial.print(':');

    if ( min < 10 ) {
        // In the first 10 minutes of each hour, we'll want a leading '0'.
        Serial.print('0');
    }
    Serial.print(min); // Print the minute (3600 equals secs per minute)
    Serial.print(':');

    if ( sec < 10 ) {
        // In the first 10 seconds of each minute, we'll want a leading '0'.
        Serial.print('0');
    }
    Serial.println(sec); // Print the seconds
}
NTP::~NTP() {
    // TODO Auto-generated destructor stub
}

and

/*
  DayNumber.cpp - Library for Calculation of Day's Number on 1 and 4 years loop.
  Created by Pavlidis Kyriakos, December 20, 2012.
  Released into the public domain.
*/

#include "DayNumber.h"


DayNumber::DayNumber() {

}

void DayNumber::dayNumberCalc() {

    int setYear = NTP::getYear();
    int setMonth = NTP::getMonth();
    int setDay = NTP::getDate();

    //Days that passed from the begging of the year for the 1st Day each Month
    int _day1YearLoop[] = {0,31,59,90,120,151,181,212,243,273,304,334};
    //i = _day1YearLoop;

    //Days that passed from the beginning of the second Year since the for the 1st Day of the running Year in 4 years loop.
    int _day4YearLoop[] = {366,731,1096};

    if (checkLeapYear(setYear)) {
        if (setMonth>2) { //Diorthwsi gia ton mina flebari
            Days1YearLoop = *(_day1YearLoop+(setMonth-1)) + setDay + 1;
            Days4YearLoop = Days1YearLoop;
        }
        else {
            Days1YearLoop = *(_day1YearLoop+(setMonth-1)) + setDay;
            Days4YearLoop = Days1YearLoop;
        }
    }
    else {
        Days1YearLoop = *(_day1YearLoop + (setMonth-1)) + setDay;
        switch (setYear%4) {
            case 1:
                Days4YearLoop = *(_day4YearLoop) + Days1YearLoop;
                break;
            case 2:
                 Days4YearLoop = *(_day4YearLoop+1) + Days1YearLoop;
                 break;
            case 3:
                Days4YearLoop = *(_day4YearLoop+2) + Days1YearLoop;
                break;
            Default:;
                break;
        }
    }
}


DayNumber::~DayNumber() {
}


bool DayNumber::checkLeapYear(int setYear) {
    if (setYear%4 == 0) {
        return true;
    }
    else {
        return false;
    }
}

The error is at the first header of NTP.h that says

Description Resource Path Location Type 'DayNumber' does not name a type NTP.h /NTP/lib line 24 C/C++ Problem

It does not understand the declaration of the object.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kyrpav
  • 756
  • 1
  • 13
  • 43
  • 2
    You should try to provide an [sscce](http://sscce.org/). Currently, you have a lot of unneccesary code. – default Feb 19 '13 at 14:57
  • [This Q&A](http://stackoverflow.com/questions/14909997/why-arent-my-include-guards-preventing-recursive-inclusion-and-multiple-symbol) will answer the question about mutual inclusion of header files (`DayNumber.h` and `NTP.h`) – Andy Prowl Feb 19 '13 at 14:57
  • If NTP is entirely static, you are MUCH better served with a namespace and free functions. – 111111 Feb 19 '13 at 15:00

1 Answers1

0

It is always good practice to include ALL files that the current file depends on. Let's say you change your "DayNumber.h" such that it no longer needs "NTP.h", now your code won't compile.

Assuming your files are local, and your machine isn't extremely low on memory, it will only make a marginal difference. There was a question on a similar subject recently, and I measured the difference between including some header or or not, compiling 30 or so files (actually, the SAME file). And the margin of error between a "good" and "bad" run on my machine was quite a bit larger than the difference between including headers and not including it.

As for your second question, it is actually caused by including "NTP.h" which isn't needed in "DayNumber.h" - so you should just "not include that". But if you have a real situation where you have one class that needs to know of another class, you need to use a forward declaration, e.g. class NTP; - now, you can use NTP * or NTP & to pass/store pointers/references to the NTP class. You can still not use what is inside the NTP class until the NTP class has been fully defined.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • well DayNumber.cpp has a function named dayNumberCalc that runs 3 functions of the NTP class, so if i do not include NTP.h i can not ask for NTP::getYear(); function.it gives error.Am i missing something something? – kyrpav Feb 19 '13 at 15:17
  • No, it's in "DayNumber.h" you shouldn't include "NTP.h". You will need to include "NTP.h" into "DayNumber.cpp". – Mats Petersson Feb 19 '13 at 15:36
  • hmmmmm.and in order to understand it better.if i general to call a function of a class inside a function of another and i do not need an object of that class i have to include the header file of the first class only in the .cpp file. I tried that and it is ok now but i thought that if i want to include a class i do that in the header file so the .cpp file reads all the headers included in its own header. From this solution i understand that i can inlude things to the .cpp only. Is that programmaticaly correct or is this a convinient solution for my problems.NO offence i want to learn, – kyrpav Feb 19 '13 at 15:48
  • I just do not know if you this solution is something like you are saying to me: "your code is wrong so place some stitches in order to work" or this is the correct way – kyrpav Feb 19 '13 at 15:50
  • You should only include header files that you actually NEED - if you don't use a class in the header file, then you don't need to include it. If you only use the NAME of a class [that is, there is no need for the compiler to understand the content of the class], you can do that with a "forward declaration" (e.g. `class NTP;`) to tell the compiler "I'm going to tell you what's inside the class at some later stage, but right now, you just need to know it exists"... And having circular dependencies between classes is not that unusual - the solution is typically to forward declare one class. – Mats Petersson Feb 19 '13 at 15:55
  • thank you very much i understood and i will check forward declaration to learn more. – kyrpav Feb 19 '13 at 15:58