Printf revisited?

Status
Not open for further replies.

mjs513

Senior Member+
Hi all. Printf does not seem to be working even if I do a Serial.printf or do a #define printf Serial.printf which I saw on another thread. All I am doing in a loop is Serial.printf("This is a test\n"); and nothing is printed.

Yes I know I can switch to sprintf or snprintf but would rather not if I don't have to since its embedded in this function:
Code:
/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#ifndef UAVCAN_HELPERS_OSTREAM_HPP_INCLUDED
#define UAVCAN_HELPERS_OSTREAM_HPP_INCLUDED

#include <uavcan/util/templates.hpp>
#include <cstdio>
#include <Arduino.h>
//#define printf Serial.printf 

namespace uavcan
{
/**
 * Compact replacement for ostream for use on embedded systems.
 * Can be used for printing UAVCAN messages to stdout.
 *
 * Relevant discussion: https://groups.google.com/forum/#!topic/px4users/6c1CLNutN90
 *
 * Usage:
 *      OStream::instance() << "Hello world!" << OStream::endl;
 */
class UAVCAN_EXPORT OStream : uavcan::Noncopyable
{
    OStream() { }

public:
    static OStream& instance()
    {
        static OStream s;
        return s;
    }

    static OStream& endl(OStream& stream)
    {
        printf("\n");
        return stream;
    }
};

inline OStream& operator<<(OStream& s, long long x)          { printf("%lld", x);  return s; }
inline OStream& operator<<(OStream& s, unsigned long long x) { printf("%llu", x); return s; }

inline OStream& operator<<(OStream& s, long x)           { printf("%ld", x); return s; }
inline OStream& operator<<(OStream& s, unsigned long x)  { printf("%lu", x); return s; }

inline OStream& operator<<(OStream& s, int x)            { printf("%d", x);  return s; }
inline OStream& operator<<(OStream& s, unsigned int x)   { printf("%u", x);  return s; }

inline OStream& operator<<(OStream& s, short x)          { return operator<<(s, static_cast<int>(x)); }
inline OStream& operator<<(OStream& s, unsigned short x) { return operator<<(s, static_cast<unsigned>(x)); }

inline OStream& operator<<(OStream& s, long double x) { printf("%Lg", x); return s; }
inline OStream& operator<<(OStream& s, double x)      { printf("%g", x);  return s; }
inline OStream& operator<<(OStream& s, float x)       { return operator<<(s, static_cast<double>(x)); }

inline OStream& operator<<(OStream& s, char x)        { printf("%c", x); return s; }
inline OStream& operator<<(OStream& s, const char* x) { printf("%s", x); return s; }

inline OStream& operator<<(OStream& s, OStream&(*manip)(OStream&)) { return manip(s); }

}

#endif // UAVCAN_HELPERS_OSTREAM_HPP_INCLUDED
Who knows this might be a handy function for a cout replacement. I also don't think the Streaming library handles all the types listed.

Thanks

Mike
 
Hi all. Printf does not seem to be working even if I do a Serial.printf or do a #define printf Serial.printf which I saw on another thread. All I am doing in a loop is Serial.printf("This is a test\n"); and nothing is printed.

Yes I know I can switch to sprintf or snprintf but would rather not if I don't have to since its embedded in this function:
Code:
/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#ifndef UAVCAN_HELPERS_OSTREAM_HPP_INCLUDED
#define UAVCAN_HELPERS_OSTREAM_HPP_INCLUDED

#include <uavcan/util/templates.hpp>
#include <cstdio>
#include <Arduino.h>
//#define printf Serial.printf 

namespace uavcan
{
/**
 * Compact replacement for ostream for use on embedded systems.
 * Can be used for printing UAVCAN messages to stdout.
 *
 * Relevant discussion: https://groups.google.com/forum/#!topic/px4users/6c1CLNutN90
 *
 * Usage:
 *      OStream::instance() << "Hello world!" << OStream::endl;
 */
class UAVCAN_EXPORT OStream : uavcan::Noncopyable
{
    OStream() { }

public:
    static OStream& instance()
    {
        static OStream s;
        return s;
    }

    static OStream& endl(OStream& stream)
    {
        printf("\n");
        return stream;
    }
};

inline OStream& operator<<(OStream& s, long long x)          { printf("%lld", x);  return s; }
inline OStream& operator<<(OStream& s, unsigned long long x) { printf("%llu", x); return s; }

inline OStream& operator<<(OStream& s, long x)           { printf("%ld", x); return s; }
inline OStream& operator<<(OStream& s, unsigned long x)  { printf("%lu", x); return s; }

inline OStream& operator<<(OStream& s, int x)            { printf("%d", x);  return s; }
inline OStream& operator<<(OStream& s, unsigned int x)   { printf("%u", x);  return s; }

inline OStream& operator<<(OStream& s, short x)          { return operator<<(s, static_cast<int>(x)); }
inline OStream& operator<<(OStream& s, unsigned short x) { return operator<<(s, static_cast<unsigned>(x)); }

inline OStream& operator<<(OStream& s, long double x) { printf("%Lg", x); return s; }
inline OStream& operator<<(OStream& s, double x)      { printf("%g", x);  return s; }
inline OStream& operator<<(OStream& s, float x)       { return operator<<(s, static_cast<double>(x)); }

inline OStream& operator<<(OStream& s, char x)        { printf("%c", x); return s; }
inline OStream& operator<<(OStream& s, const char* x) { printf("%s", x); return s; }

inline OStream& operator<<(OStream& s, OStream&(*manip)(OStream&)) { return manip(s); }

}

#endif // UAVCAN_HELPERS_OSTREAM_HPP_INCLUDED
Who knows this might be a handy function for a cout replacement. I also don't think the Streaming library handles all the types listed.

Thanks

Mike

Mike, unsigned long long, long long, and long double are not handled by the Streaming library. Having an easy way to direct printf to Serial.println() would be great! I often find myself developing C code methods on my PC that I want to use as part of Teensy projects and the lack of printf is a bit of nuisance.

Brian
 
Brian. When I get it working I will definitely posted the update code here for testing.

UPDATE: ok I ran this sketch:
Code:
#include <uavcan.h>

//#include <uavan/uavcan.h>
#include <uavcan/helpers/ostream.hpp>
using namespace uavcan;

double test = 98.9987485;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  
}

void loop() {
  // put your main code here, to run repeatedly:
  OStream::instance() << "Hello world!" << ", " << test << OStream::endl; 

}
with this function:
Code:
/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#ifndef UAVCAN_HELPERS_OSTREAM_HPP_INCLUDED
#define UAVCAN_HELPERS_OSTREAM_HPP_INCLUDED

#include <uavcan/util/templates.hpp>
#include <cstdio>
#include <Arduino.h>
#define printf Serial.printf 

namespace uavcan
{
/**
 * Compact replacement for ostream for use on embedded systems.
 * Can be used for printing UAVCAN messages to stdout.
 *
 * Relevant discussion: https://groups.google.com/forum/#!topic/px4users/6c1CLNutN90
 *
 * Usage:
 *      OStream::instance() << "Hello world!" << OStream::endl;
 */
class UAVCAN_EXPORT OStream : uavcan::Noncopyable
{
    OStream() { }

public:
    static OStream& instance()
    {
        static OStream s;
        return s;
    }

    static OStream& endl(OStream& stream)
    {
        printf("\n");
        return stream;
    }
};

inline OStream& operator<<(OStream& s, long long x)          { printf("%lld", x);  return s; }
inline OStream& operator<<(OStream& s, unsigned long long x) { printf("%llu", x); return s; }

inline OStream& operator<<(OStream& s, long x)           { printf("%ld", x); return s; }
inline OStream& operator<<(OStream& s, unsigned long x)  { printf("%lu", x); return s; }

inline OStream& operator<<(OStream& s, int x)            { printf("%d", x);  return s; }
inline OStream& operator<<(OStream& s, unsigned int x)   { printf("%u", x);  return s; }

inline OStream& operator<<(OStream& s, short x)          { return operator<<(s, static_cast<int>(x)); }
inline OStream& operator<<(OStream& s, unsigned short x) { return operator<<(s, static_cast<unsigned>(x)); }

inline OStream& operator<<(OStream& s, long double x) { printf("%Lg", x); return s; }
inline OStream& operator<<(OStream& s, double x)      { printf("%g", x);  return s; }
inline OStream& operator<<(OStream& s, float x)       { return operator<<(s, static_cast<double>(x)); }

inline OStream& operator<<(OStream& s, char x)        { printf("%c", x); return s; }
inline OStream& operator<<(OStream& s, const char* x) { printf("%s", x); return s; }

inline OStream& operator<<(OStream& s, OStream&(*manip)(OStream&)) { return manip(s); }

}

#endif // UAVCAN_HELPERS_OSTREAM_HPP_INCLUDED
and it worked fine.
Code:
Hello world!, 98.9987
Hello world!, 98.9987
Hello world!, 98.9987
Hello world!, 98.9987
Hello world!, 98.9987
So something else must be going on that I have to trace.
 
Last edited:
Ok. Looking and looking but no clue. Anyone have any idea what could possibly cause printf not to print to serial?

UPDATE: Figured it out. After looking at this post https://forum.pjrc.com/threads/2479...e-function-Teensy-3?highlight=_write()+printf and embedding it in the sketch it led to a conflict. Looking at my sketch I found an old piece of code extern "C"{
int _getpid(){ return -1;}
int _kill(int pid, int sig){ return -1; }
int _write(){return -1;}
}
that caused the conflict. Once I removed that didn't need the fix in the other post and it worked like a charm

Mike
 
Last edited:
I see it working? IIRC T_LC has the printf code truncated due to space - is this with a T_LC?

I tried it in the time sync sample [ where I ignored printf and called out to sprint ] Brian put out and it doesn't truncate to 32 bit: Serial.printf( "\t%llu", ttime_nanos*10000 );

I had used the macro printf >> Serial.printf before I thought but compiler yelled at me today so I just did find&replace in samples I got from web below.

I just haphazardly gathered some printf'y stuff here and it all seems to work T_3.1 and T_3.5:

Code:
void setup() {
  // put your setup code here, to run once:
  while (!Serial && millis() < 5000 );
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);


  Serial.printf( "1\n" );
  Serial.printf( "1:%d\n", 1 );
  uint64_t x = 1234567890LL;
  Serial.printf("%lld\n", x);
  Serial.printf("%lld\n", x + x);
  Serial.printf("%lld\n", x * x);

  uint64_t z = 50596132LL;
  Serial.printf( "llu>> \t%llu\n", z );
  Serial.printf( "\t%llu\n", z * 10000 + 333 );

  int ii;
  uint32_t mm = 1;
  for ( ii = 0; ii <= 32; ii++ ) {
    Serial.printf( "\tmmu>>  %u", mm );
    mm *=2;
    if ( !(ii%4) ) Serial.println();
  }

  uint64_t nn = 1;
  for ( ii = 0; ii <= 64; ii++ ) {
    Serial.printf( "\tnnLLu>> %llu", nn ); // requires ll
    nn *=2;
    if ( !(ii%4) ) Serial.println();
  }

  float testf = 98.9987485;
  for ( ii = 0; ii <= 12; ii++ ) {
    Serial.printf( "\ttest f>> %f", testf );
    testf *=10;
    if ( !(ii%3) ) Serial.println();
  }
  double test = 98.9987485;
  for ( ii = 0; ii <= 12; ii++ ) {
    Serial.printf( "\ttest d>> %f", test );
    test *=10;
    if ( !(ii%3) ) Serial.println();
  }

  uint64_t zb = 50596132L;
  Serial.printf( "zb>> \t%llu\n", zb );
  Serial.printf( "\t%llu\n", zb * 10000 + 333 );


  float y = 12345.67890f;
  Serial.printf("%lld\n", y);

  Serial.printf("Characters: %c %c \n", 'a', 65);
  Serial.printf("Decimals: %d %ld\n", 1977, 650000L);
  Serial.printf("Preceding with blanks: %10d \n", 1977);
  Serial.printf("Preceding with zeros: %010d \n", 1977);
  Serial.printf("Some different radices: %d %x %o %#x %#o \n", 100, 100, 100, 100, 100);
  Serial.printf("floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);
  Serial.printf("Width trick: >%*d< \n", 5, 10);
  Serial.printf("%s \n", "A string");

  Serial.printf("Strings:\n");
  const char* s = "Hello";
  Serial.printf("\t.%10s.\n\t.%-10s.\n\t.%*s.\n", s, s, 10, s);

  Serial.printf("Characters:\t%c %%\n", 65);

  Serial.printf("Integers\n");
  Serial.printf("Decimal:\t%i %d %.6i %i %.0i %+i %i\n", 1, 2, 3, 0, 0, 4, -4);
  Serial.printf("Hexadecimal:\t%x %x %X %#x\n", 5, 10, 10, 6);
  Serial.printf("Octal:\t%o %#o %#o\n", 10, 10, 4);

  Serial.printf("Floating point\n");
  Serial.printf("Rounding:\t%f %.0f %.32f\n", 1.5, 1.5, 1.3);
  Serial.printf("Padding:\t%05.2f %.2f %5.2f\n", 1.5, 1.5, 1.5);
  Serial.printf("Scientific:\t%E %e\n", 1.5, 1.5);
  Serial.printf("Hexadecimal:\t%a %A\n", 1.5, 1.5);


}

void loop() {
  // put your main code here, to run repeatedly:

}
 
I see that now - my browser didn't update right - I was watching Shark Week and playing with printf ... did my post and saw Pauls' post - and your update still didn't draw ... really wondered what the fix was :confused: ... then after refresh ...

Either way - I learned to trust printf to work where I had been avoiding it and code bloat on T_3.5/3.6 not so much a worry for the features it offers!

33KB for that post #7 pile of nothing on T_3.5:
Sketch uses 33060 bytes (6%) of program storage space. Maximum is 524288 bytes.
Global variables use 5320 bytes (2%) of dynamic memory, leaving 256816 bytes for local variables. Maximum is 262136 bytes.

And on T_3.2 - with 256KB Flash it is okay too ::
Sketch uses 32784 bytes (12%) of program storage space. Maximum is 262144 bytes.
Global variables use 4984 bytes (7%) of dynamic memory, leaving 60552 bytes for local variables. Maximum is 65536 bytes.
 
Last edited:
Done that myself Tim. Cross posts always got me.

Either way - I learned to trust printf to work where I had been avoiding it and code bloat on T_3.5/3.6 not so much a worry for the features it offers!
Didn't make much of a difference in the sketch size with the T3.5/T3.6 and printf does make it easier.
 
Those were both with printf code.

A simple print pair is a 12K sketch, making them printf jumps to 30K. ... that's why it is off by default in T_LC with 64K.
 
@defragster. I just did a compile on the T3.6 with the UAVcan code and the difference in using the Ostream function was only about 700bytes. I will have to give it a test as a separate function.
 
@defragster. I just did a compile on the T3.6 with the UAVcan code and the difference in using the Ostream function was only about 700bytes. I will have to give it a test as a separate function.

Let me know if there is a min set needed to try. I saw there was the #include of a library and wasn't sure if that was required to try it.

Code:
#include <uavcan.h>
#include <uavcan/helpers/ostream.hpp>

… and wasn't sure where the 2nd code block in that post #3 went and it has:
Code:
#include <uavcan/util/templates.hpp>
#include <cstdio>
 
I am going to try and make it stand alone so I can use it in any sketch and will let you know. Running into a few other problems now :) Probably will make that a separate post.
 
Notr sure if you saw my LTO Debug thread - printf works except with LTO
No I didn't see that one. Will have to see if I can find it. Anyway here is the standalone version with OStream.

Have fun...
 

Attachments

  • sketch_aug12a.zip
    1.3 KB · Views: 92
It is here: https://forum.pjrc.com/threads/53451-LTO-Compile-Error?p=185296#post185296

<edit> - that is pretty FAT!

Sketch uses 31652 bytes (3%) of program storage space. Maximum is 1048576 bytes.
Global variables use 5568 bytes (2%) of dynamic memory, leaving 256576 bytes for local variables.


Comment out the loop line:

Sketch uses 9204 bytes (0%) of program storage space. Maximum is 1048576 bytes.
Global variables use 4072 bytes (1%) of dynamic memory, leaving 258072 bytes for local variables.

ODDLY that compiles with printf code compiled with LTO - unlike my like sketch
 
ODDLY that compiles with printf code compiled with LTO - unlike my like sketch
Not sure if that's good or bad.

Wonder why the bloat when its in the loop? Something not clearing?
 
Bloat is from added printf code pulled in. Not from being 'in' loop - would be the same if moved one time to setup()
 
Interesting thing is that I added and deleted addition prints in loop and didn't change the size noticeably. Once you call it, not much additional is added for addition stream cases. Have to do a test.
 
Status
Not open for further replies.
Back
Top