There are other features that I want to discuss (I've already implemented them; it's just a matter of whether or not to remove them):
Attached you'll find the Print.h file, which has macro definitions at the beginning that can be commented out to disable individual features; as well as the Print.cpp file (for AVR, not SAM). These macros and all the #ifdef would be removed on the final code I put on the PR.
What do you think? Any opinions on which features should or shouldn't go here, or any other comment? I think this could improve the user experience considerably.
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.
For this reason, I always use printf if I can afford the memory.Is it possible to do number formatting such as zero or space padding ?Although the existing syntax is painful, its worst feature is the inability to print columns of aligned values.
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.
I use printf 99.9% of the time.
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.
From a beginner’s point of view, I think the most valuable addition to print and println would be a Java/JavaScript-style ability to string multiple substrings and variables together with +. e.g.:int SensorOne = analogRead(A0);int sensorTwo = analogRead(A1);Serial.println(“sensor 1: “ + sensorOne + “\tsensor 2: “ + sensorTwo);orint red = analogRead(A0)/4;int green = analogRead(A1)/4;int blue = analogRead(A2)/4;Serial.println(“<body bgcolor=\”#” + hex(red) + hex(green) + hex(blue) + “\”>);I’ve taught beginners in different programming languages, and of all the ones I’ve dealt with, that style is the one that comes most naturally to novices. Adding that without adding significantly to the memory footprint of the functions would be the biggest improvement. It’s the one thing about print/println that I get asked for most often.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.
From a beginner’s point of view, I think the most valuable addition to print and println would be a Java/JavaScript-style ability to string multiple substrings and variables together with +. e.g.:
Serial.println("sensor 1: " + sensorOne + "\tsensor 2: " + sensorTwo);
I have to point out that, as can be seen in avr-gcc documentation for *printf, the implementation is rather weak: it doesn't handle %f specifiers the way Arduino uses it (displays ? instead) and it lacks other printf features such as *, plus some minor things (e.g. printf("%hhX", -1) prints FFFF; it should print FF). So it's not like printf will be a full replacement for print, and C users may find it's not what they're used to. But it still works for simple things such as integer formatting.
I think having hex(num, [width]) and base(num, radix, [width]) would be the way to go.
Then again, that doesn't give much freedom specifying arbitrary formatters; another option is stringing formatters like hex(num).width(8).digits(5).withSign() (sadly C++ doesn't allow the optional argument syntax other languages such as Python do), or pushing them as dummy arguments that modify how Serial behaves (kinda like std::cout) but that option feels weird.
A (probably inefficient) idea for a format function:
format(num, "width", 3, "base", 16)
(returns num formatted as a String in base 16 padded to 3 digits)
#define DIGITS <<8 // minimum width (chars; not necessarily digits)
#define ZEROS 0x00 // pad with zeros (default)
#define SPACES 0x80 // pad with spaces
#define SIGN 0x40 // always +/- sign
#define HEX 16 // base 16, etc
Serial.print(n, HEX | ZEROS | 6 DIGITS);
This allows combining base (6 bits), '0' flag (1 bit), '+' flag (1 bit), and width (8 bits) into a single 16-bit int field. For floats/doubles, base is replaced by decimals (up to 63, might be a bit short).
(This doesn't solve the problem of print(n, attributes) being a bit weird combined with other print(string1, string2) calls which just print 2 things, though.)
string foo;
Serial.print(foo=....);
Serial.print((string)....);
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.
Some pros and cons of printf (functionality):
Pros:
- It's existed for decades, so it's well known and broadly documented.
- C programmers are used to it.
- It's already there; there's no need to reimplement it (unless there's a good reason for it such as efficiency).
- It provides plenty of formatting features in a compact manner.
- It teaches how to use printf (although Arduino is more about teaching programming than C specifically).
Cons:
- It doesn't allow printing non-POD objects such as Arduino Strings directly (a solution for this might be to add a variadic template wrapper that adds .c_str() before calling printf).
- Its syntax looks rather weird to new users.
- It requires a format string; you can't print a variable directly as Serial.print allows.
- It doesn't allow printing binary or arbitrary bases.
- avr-gcc's implementation of printf is limited (small too, nevertheless).
Conclusion: Serial.printf would be a good thing to have because of formatting, but Serial.print is more convenient from an ease of use point of view (specially if the variadic thing I proposed is implemented), therefore both methods should coexist.
I think the way to go is to implement Serial.printf (in an efficient way, if you want) AND improve Serial.print (I may be biased but I think my idea of including formatting flags into the `base` parameter may be good).
By the way, if creating custom file descriptors is as easy as you say, it may be a good idea to make a Print::operator FILE*() method so that you can just call fprintf(Serial, ...), fputs(str, Serial), etc.
What I think is that implementing it properly using callback functions and custom FILE objects would be important.
I think I'm going to drop that feature from this "project" and move it to a separate one; it deserves its own PR and is independent from the variadic template thing anyway (both can be implemented as separate PRs).
I'm also going to forget about adding formatting capabilities to the `base` parameter *for now* for a similar reason; it doesn't affect the rest of the idea and can be implemented separately. (Also it would require modifying WString.cpp as well.) But I still think it should be done, since there seems to be quite some interest in adding extra formatting capabilities to Serial.print.
Gabriel,
What you propose is very limited and requires modification for every individual usage case. IMO, it is not a good solution.
There are much better ways to get xxprintf() style formatted output within the C++ Arduino environment.
For example using the power of C++ and the Arduino Print class it is really
trivial to make a function that works like fprintf() but uses Print
class objects.
Here is the code for a simple function called Printf()
that works just like fprintf() but uses a Print class object instead of
a FILE pointer.
size_t Pprintf(Print &outdev, const char *format, ...)
{
char buf[128];
va_list ap;
va_start(ap, format);
vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
return(outdev.write(buf));
}
This
function would will work with any object that uses the Print class,
which includes pretty much any Serial, LCD, GLCD, LED matrix libraries,
etc..
Essentially, anything that currently supports print() will work with the Pprintf() function above.
and here is a working sketch that demonstrates how to use it with the Serial object.
void setup(void)
{
Serial.begin(115200);
Pprintf(Serial, "Pprintf...\n");
}
void loop(void)
{
Pprintf(Serial, "Seconds up: %04ld\n", millis()/1000);
delay(1000);
}
size_t Pprintf(Print &outdev, const char *format, ...)
{
char buf[128];
va_list ap;
va_start(ap, format);
vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
return(outdev.write(buf));
}
And here is a bit of rant on the topic of the Arduino Print class.
From
a larger perspective, IMO, the only reason not to have a printf()
method built into the bundled Print class provided by the Arduino IDE is
obstinance on the part of certain key Arduino developers. Yeah I know
that is a pretty harsh assessment, but that is my opinion.
At this point in time, the xxprintf() formatting routines have existed for 50 years.
They are very well documented and understood and examples on how the formatting string works are literally everywhere.
Many people have been asking for it on Arduino for many years.
This playground page has existing for around 6 years: https://playground.arduino.cc/main/printf
Also,
several 3rd party cores have already added a printf() method to their
Print class. Cores like Teensy/Teensy3, Chipkit, and ESP.
Even if
very green/newbie Arduino users find it complicated or too complex for
them, they don't have to use it and it won't eat up any code space in
their images.
But in reality with a small bit of coaching and a bit
of googling, I believe that even a newbie should be able to easily
figure out how to use it.
So at this point in time, I really
don't understand why there is still so much resistance to adding a
printf() method to the Print class.
--- bill
--
I seem to recall there was a language that had print formats in the form of an even more specific template than printf - something like nnnnn.nn. I forget what it was. A quick scan of Python, Pascal and several FORTRANS didn't find it but did confirm that there is nothing in common use that's better than printf. Just messier ones.
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.
To view this discussion on the web visit https://groups.google.com/a/arduino.cc/d/msgid/developers/CAH1-q0hNsssYOAM%3DZEej471hJOKtjAOL5DhTQdpSM7mHUkpCtA%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/a/arduino.cc/d/msgid/developers/067BEFA0688749578132D845346329E6%40JohnDoughPC.
On testing...
This isn't so much Arduino as it is all computers in general, I have a similar system on multiple platforms. I always did conditional assembly - /ddodebug under multiple languages
which you can use to remove all debug based code if you place the conditional within the macro
The problem always arises when you are dealing with clock cycle intensive work, or within an interrupt you needed to track - your stuff needs to be FAST if working with system calls
I used to have one I wrote for assembly under 8088: essentially it was a macro in the form of
macro Debug <msg1>
#ifdef dodebug
call debugprint
db Msg1,0
#endif
endm
---->>> Where debugprint was linked as a separate routine in your code, and /ddodebug was the assembler conditional directive
or
macro Debug <msg1>
#ifdef dodebug
Int 60 (any open interrupt you have, place your receiver routine on that interrupt)
db Msg1,0
#endif
endm
---->>> Where receiver was sitting on an interrupt to be interpreted as a separate routine in your code
So you could write Debug <'Location 1: %h@pc values: %h@ax %h@bx %h@cx %c13,10'> (in 8088 for example)
Your receiving routine saves the return address and pops of the message to the return location. With the interrupt one popping more information off the stack.
You should note that any debug that does anything major should first save all of the register values to be restored and switch to a new stack immediately to not corrupt the primary code stack in process.
Within that debug routine I had %c %h %o %d %s print for char, hex, octal, decimal, and string respectively, and looking up register values from the text. That worked well
If you get creative you can write another debug receptor that allows you to dump the output to memory, file, serial, or a monochrome monitor for example as the output at the end of the debug section.
I wrote a whole subsystem for DOS that dumps all of the file system calls (selectivity) and allows you to direct them to where you want using this method.
It does effect model size of course under those OS's, they have compact, small, medium, and large compiler models. With the code and data being restricted accordingly, just like C.
Maybe you could develop a similar system for Arduino. Serial by the way can be a problem if you have any sort of handshaking to outside devices - it will slow it quite a bit, same with disk output,
You might even setup a secondary Arduino and send the output to it and let it do the debug output work, maybe to a VGA monitor or something. You would want to setup a ring buffer on the primary so as to not lose anything, but I bet it could be done fairly easily.
Hope that gives you some ideas.
B
To view this discussion on the web visit https://groups.google.com/a/arduino.cc/d/msgid/developers/CALiMYrvC0yrY%2BpEdHLMC7YG69FN8kyzhQfeVE4Dk4Vn_Pip7Tw%40mail.gmail.com.