A bit ago I was working on a class that I could use to make managing text on displays a bit easier, and one of the obvious functions would be a print()
function/method that would display nearly any data type. It would need to convert it to a char[]
and store it in a buffer.
I know this can be done with either templates or method overloading, but I figured there's probably a library that could handle just the overloading functionality, and I found the Print class that's already included as part of the Arduino core libraries, and it seems almost perfect for this.
I'm currently running into two problems with it though:
- float/double values passed to
print()
get split up. If I executeprint((float)12.34)
, then it will get broken up into 4 different prints, the 12, . (decimal), 3 and 4 will all get broken up and handled separately. - Negative integers/longs/floats/doubles will get converted into their absolute (positive) values. I suspect this is maybe related to this thread, but I'm not sure how to fix it when extending the Print class.
All of the code, as well as the example sketch and its serial output are below.
Settings.h
#pragma once
#ifndef __MYPRINT_SETTINGS__
#define __MYPRINT_SETTINGS__
const size_t MAX_CHAR_LENGTH = 60; // Char length of strings in UI
#endif
MyPrint.h
#pragma once
#ifndef MY_PRINT_H
#define MY_PRINT_H
#include <Arduino.h>
#include <Print.h>
#include <ArduinoSTL.h>
#include "Settings.h"
#include <stdint.h>
#include <stddef.h>
class MyPrint : public Print {
public:
MyPrint();
~MyPrint(){};
size_t write(const uint8_t *buffer, size_t size);
// This method is required since its extended from the parent Print class,
// I'm not entirely sure what its needed. It only returns sizeof(val);
size_t write(uint8_t val);
private:
// Current char/string being displayed (or to be displayed)
char _printerVal[ MAX_CHAR_LENGTH ];
};
#endif
MyPrint.cpp
#pragma once
#include "MyPrint.h"
MyPrint::MyPrint() : Print () {}
size_t MyPrint::write(const uint8_t *buffer, size_t size) {
int diff = 0;
if ( strcmp( buffer, _printerVal ) != 0 ){
strcpy( _printerVal, buffer );
}
size_t n = 0;
while (size--) {
size_t ret = write(pgm_read_byte(buffer++));
if (ret == 0) {
// Write of last byte didn't complete, abort additional processing
break;
}
n += ret;
}
// Print the entire buffer
// NOTE: This will be replaced with the display logic, but for now, it just outputs it to the console.
std::cout << _printerVal << std::endl;
return n;
}
size_t MyPrint::write(uint8_t val){
// Not entirely sure what this is for..
return sizeof(val);
}
Test_MyPrint.ino
#include "MyPrint.h"
MyPrint * MP;
void setup() {
Serial.begin(9600);
delay(2000);
MP = new MyPrint();
std::cout << "1)\t";
MP->print("Y");
std::cout << "2)\t";
MP->print("Test with char");
std::cout << "3)\t";
MP->print(String("Test with the forbidden String"));
std::cout << "4)\t";
MP->print((int) 12);
std::cout << "5)\t";
MP->print((int) -12);
std::cout << "6)\t";
MP->print((uint8_t) 63);
std::cout << "7)\t";
MP->print((uint16_t) 63);
std::cout << "8)\t";
MP->print((unsigned short) 34);
std::cout << "9)\t";
MP->print((int) -56);
std::cout << "10)\t";
MP->print((int) 56);
std::cout << "11)\t";
MP->print((unsigned int) 32);
std::cout << "12)\t";
MP->print((long) -78);
std::cout << "13)\t";
MP->print((long) millis());
std::cout << "14)\t";
MP->print((unsigned long) 78);
std::cout << "15)\t";
MP->print((float) 12.34);
std::cout << "16)\t";
MP->print((float) -56.78);
}
void loop(){}
Serial output
Note: I'm running this on a Nano Every, but this will be used on other Arduinos too, such as the Uno and Mega. But this is the serial output on the Nano Every
1) Y
2) Test with char
3) Test with the forbidden String
4) 12
5) 12 // Expected: -12
6) 63
7) 63
8) 34
9) 56 // Expected: -56
10) 56
11) 32
12) 78 // Expected: -78
13) 2066
14) 78
15) 12 // Expected: 12.34
.
3
4
16) 56 // Expected: -56.78
.
7
8
The odd test result #'s are 5, 9, 12 15 and 16 above.
And another question.. If you look at line 55 in Print.h, you'll see the method:
virtual size_t write(uint8_t) = 0;
And it looks like pretty much all methods in that class eventually conclude by calling this write method. But all this does is take in a uint8_t
parameter and return the result of sizeof(uint8_t val)
, and I can't figure out what the point of that is supposed to be.
Any input is appreciated. Thanks in advance.
-J