Problems with char array + library issues

OK, that title might not even be 100% correct, but I’m trying to make a library for the DS1307 RTC that upon calling something like TimeStamp.DateAndTime(); a beautiful string would be returned for my storage purposes. Right now, my code prints the data straight onto an SD card, but ultimately I want the string returned from the function and then I will use that in turn to store to the SD card, something like status.print(TimeStamp.DateAndTime()); (status being the File from the SD Card). Here is my current code that I am trying to convert:

void print_date_and_time(boolean code_b) {
  DateTime now = RTC.now();
  
  if (code_b) {
    the_status = SD.open("Status/Status.txt", FILE_WRITE);
    the_status.print(now.year(), DEC);
    the_status.print('/');
    
    if (!(now.month() / 10)) {
      the_status.print('0');
    }
    
    the_status.print(now.month(), DEC);
    the_status.print('/');
    
    if (!(now.day() / 10)) {
      the_status.print('0');
    }
    
    the_status.print(now.day(), DEC);
    the_status.print(' ');
    
    if (!(now.hour() / 10)) {
      the_status.print('0');
    }
    
    the_status.print(now.hour(), DEC);
    the_status.print(':');
    
    if (!(now.minute() / 10)) {
      the_status.print('0');
    }
    
    the_status.print(now.minute(), DEC);
    the_status.print(':');
    
    if (!(now.second() / 10)) {
      the_status.print('0');
    }
    
    the_status.print(now.second(), DEC);
    the_status.print(F(" - "));
  } else {
    errors = SD.open("Errors/Errors.txt", FILE_WRITE);
    errors.print(now.year(), DEC);
    errors.print('/');
    
    if ((now.month() / 10) == 0) {
      errors.print('0');
    }
    
    errors.print(now.month(), DEC);
    errors.print('/');
    
    if ((now.day() / 10) == 0) {
      errors.print('0');
    }
    
    errors.print(now.day(), DEC);
    errors.print(' ');
    
    if ((now.hour() / 10) == 0) {
      errors.print('0');
    }
    
    errors.print(now.hour(), DEC);
    errors.print(':');
    
    if ((now.minute() / 10) == 0) {
      errors.print('0');
    }
    
    errors.print(now.minute(), DEC);
    errors.print(':');
    
    if ((now.second() / 10) == 0) {
      errors.print('0');
    }
    
    errors.print(now.second(), DEC);
    errors.print(F(" - "));
  }   
}

As you can tell, it prints out an aesthetically appealing "2013/08/08 10:16:45 - " and then I can put whatever I want after that. My problem is that returning a char* from a function seemed a bit complicated, so I was wondering if there was an easier way to do that (that’s the library part of the problem), the other problem was filling up a char array in an efficient way granted all this boring logic (many many calls to the same char array to fill it up properly). I was trying to avoid Strings as everyone hates them, and I was looking up methods using strcpy/strcat/sprintf but the problem is that now.year() returns an integer and I can only fill up these char arrays with chars.

DISCLAIMER
The above code is probably 10x less efficient than it could be, but I’m a newbie to some things and so I did it the easiest way logically (and it works) to start things out. Feel free to point out methods where I can improve. Also, I have no idea why I did (!(now.day()) / 10) instead of (now.day() < 10), things can definitely be improved.

cypherrage: My problem is that returning a char* from a function seemed a bit complicated, so I was wondering if there was an easier way to do that (that's the library part of the problem)

I don't know where the library comes into it, but as far as returning a char array from a function, you don't. You declare the char array before calling the function, and send the function the array to populate:

char buffer[10];
populateMyArray(buffer);
Serial.println(buffer);

...

void populateMyArray(char *buf)
{
  strcpy(buf, "Hello!");
}

the other problem was filling up a char array in an efficient way granted all this boring logic (many many calls to the same char array to fill it up properly).

sprintf()

Maybe I just don't understand how sprintf works, but repeated calls to sprintf for the same buffer would just overwrite everything else in it (that was from primitive tests, I could have been calling it wrong or something)

cypherrage: Maybe I just don't understand how sprintf works, but repeated calls to sprintf for the same buffer would just overwrite everything else in it.

You don't need repeat calls to sprintf(). A single call will do with multiple variables:

char buffer[20];
int hour = 5;
int mins = 20;
int secs = 59;
sprintf(buffer, "Time: %02d:%02d:%02d", hour, mins, secs);
Serial.println(buffer); // prints Time: 05:20:59

Typically you would never return a char * from a function. Instead you pass the char * to the function as a parameter and the function operates on that char *. Something that might look like:

void formatTime(char *buffer, int maxlen) {
  snprintf(buffer, "%02d:%02d:%02d", rtc.getHours(), rtc.getMinutes(), rtc.getSeconds());
}

char buf[20];
formatTime(buf, 20);
Serial.println(buf);

Here is list of available parameters for sprintf: http://www.cplusplus.com/reference/cstdio/printf/

Also I'm not sure why people say it's wrong to return a char pointer, I always do this and never had any problems.

http://ideone.com/sfVFdd

Wow, that was insane, the simplicity, ugh, it hurts, it’s so good. New code seems to work well. Although I am curious, why didn’t snprintf work but sprintf did?

#include <Wire.h>
#include "RTClib.h"

RTC_DS1307 RTC;

void setup () {
    Serial.begin(9600);
    Wire.begin();
    RTC.begin();
}

void loop () {
  char temp_date_and_time[22];
  date_and_time(temp_date_and_time);
  Serial.println(temp_date_and_time);
  delay(3000);
}

void date_and_time(char *buffer) {
  DateTime now = RTC.now();
  sprintf(buffer, "%02d/%02d/%d %02d:%02d:%02d - ", now.month(), now.day(), now.year(), now.hour(), now.minute(), now.second());
}

cypherrage:
Although I am curious, why didn’t snprintf work but sprintf did?

Couldn’t tell you without seeing what you did and what “didn’t work” means.

Edit: Didn’t notice majenko’s usage in his code.

Missing parameter in majenko's code...

What argument did he leave out?

Alright well here is the library problem…(followed the Morse library tutorial the the point, or so I thought)

TimeStamp.h

#ifndef TimeStamp.h
#define TimeStamp.h

#include "Arduino.h"
#include <Wire.h>
#include <RTClib.h>

class TimeStamp
{
  public:
    TimeStamp();
    char* date_and_time();    
  private:
    RTC_DS1307 RTC;
    char temp_date_and_time[]; 
};

#endif

TimeStamp.cpp

#include "Arduino.h"
#include "TimeStamp.h"
#include <RTClib.h>
#include <Wire.h>

TimeStamp::TimeStamp()
{
  RTC_DS1307 RTC;
  char temp_date_and_time[22];
  Wire.begin();
  RTC.begin();
}

char* TimeStamp::date_and_time()
{
  DateTime now = RTC.now();
  sprintf(temp_date_and_time, "%02d/%02d/%d %02d:%02d:%02d - ", now.month(), now.day(), now.year(), now.hour(), now.minute(), now.second());
  return temp_date_and_time;
}

TimeStamp.ino

#include <TimeStamp.h>

TimeStamp test;

void setup () {
  Serial.begin(9600);
}

void loop () {
  Serial.println(test.date_and_time());
  delay(3000);
}

Error:
In file included from TimeStamp.ino:1:
\Arduino\libraries\TimeStamp/TimeStamp.h:14: error: expected identifier before ‘.’ token
\Arduino\libraries\TimeStamp/TimeStamp.h:14: error: expected unqualified-id before ‘.’ token
TimeStamp:3: error: expected unqualified-id before ‘.’ token
TimeStamp.ino: In function ‘void loop()’:
TimeStamp:10: error: ‘test’ was not declared in this scope

TimeStamp.h

#ifndef TimeStamp.h
#define TimeStamp.h

#include "Arduino.h"
#include <Wire.h>
#include <RTClib.h>

class TimeStamp
{
  public:
    TimeStamp();
    char* date_and_time();    
  private:
    RTC_DS1307 RTC;
};

#endif

TimeStamp.cpp

#include "Arduino.h"
#include "TimeStamp.h"
#include <RTClib.h>
#include <Wire.h>

TimeStamp::TimeStamp()
{
  RTC_DS1307 RTC;
  Wire.begin();
  RTC.begin();
}

char* TimeStamp::date_and_time()
{
  static char temp_date_and_time[23]; // 22 is too small, never forget to give room for the null terminator char
  DateTime now = RTC.now();
  sprintf(temp_date_and_time, "%02d/%02d/%d %02d:%02d:%02d - ", now.month(), now.day(), now.year(), now.hour(), now.minute(), now.second());
  return temp_date_and_time;
}

TimeStamp.ino

#include <TimeStamp.h>

TimeStamp test;

void setup () {
  Serial.begin(9600);
}

void loop () {
  Serial.println(test.date_and_time());
  delay(3000);
}

(Untested)

Same error, I'm not so sure the problem was with that char array. The problem is with some "." but I don't see any missing or out of the ordinary.

So I'm not sure why this would make a difference, but keeping TimeStamp.h the same, I made my TimeStamp class now Time_Stamp, and those errors were taken care of, but now there is a new error:

'RTC_DS1307' does not name a type

Which wasn't there before. I'm not even sure why changing TimeStamp to Time_Stamp fixed that problem, but whatever.

It seems to be a pathing error, but the libraries are all in the same folder on my C: drive so I'm not sure why it is having problems finding the RTC library...