Uses a 20x4 text LCD to display the time and date.
#ifdef USE_SYSFS_PORT
#else
#endif
#include <boost/property_tree/info_parser.hpp>
#include <iostream>
#include <sstream>
#include <thread>
#include <iomanip>
#include <algorithm>
#include <chrono>
#include <assert.h>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/program_options.hpp>
void WriteLarge(
const std::shared_ptr<duds::hardware::display::TextDisplay> &disp,
const std::string &str,
unsigned int c,
unsigned int r
);
enum DigitPartCodes {
Clear,
UpLeft,
BarLeft,
BarUp,
BarCorn,
Dot,
DownLeft = UpLeft,
BarDown = BarUp,
};
char DigitPart(int ud, int x, int y, char d);
constexpr std::uint32_t DigSeg(
std::uint32_t x,
std::uint32_t y,
std::uint32_t c
) {
return (c << (x * 3)) << (y * 9);
}
const std::uint32_t DigitFont[2][10] = {
{
DigSeg(0, 0, UpLeft) | DigSeg(1, 0, BarUp) | DigSeg(2, 0, BarLeft) |
DigSeg(0, 1, BarLeft) | DigSeg(1, 1, Clear) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, BarUp) | DigSeg(1, 2, BarUp) | DigSeg(2, 2, BarCorn),
DigSeg(0, 0, Clear) | DigSeg(1, 0, BarLeft) | DigSeg(2, 0, Clear) |
DigSeg(0, 1, Clear) | DigSeg(1, 1, BarLeft) | DigSeg(2, 1, Clear) |
DigSeg(0, 2, Clear) | DigSeg(1, 2, BarCorn) | DigSeg(2, 2, Clear),
DigSeg(0, 0, BarUp) | DigSeg(1, 0, BarUp) | DigSeg(2, 0, BarLeft) |
DigSeg(0, 1, UpLeft) | DigSeg(1, 1, BarUp) | DigSeg(2, 1, BarCorn) |
DigSeg(0, 2, BarUp) | DigSeg(1, 2, BarUp) | DigSeg(2, 2, BarCorn),
DigSeg(0, 0, BarUp) | DigSeg(1, 0, BarUp) | DigSeg(2, 0, BarLeft) |
DigSeg(0, 1, BarUp) | DigSeg(1, 1, BarUp) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, BarUp) | DigSeg(1, 2, BarUp) | DigSeg(2, 2, BarCorn),
DigSeg(0, 0, BarLeft) | DigSeg(1, 0, Clear) | DigSeg(2, 0, BarLeft) |
DigSeg(0, 1, BarUp) | DigSeg(1, 1, BarUp) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, Clear) | DigSeg(1, 2, Clear) | DigSeg(2, 2, BarCorn),
DigSeg(0, 0, UpLeft) | DigSeg(1, 0, BarUp) | DigSeg(2, 0, BarCorn) |
DigSeg(0, 1, BarUp) | DigSeg(1, 1, BarUp) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, BarUp) | DigSeg(1, 2, BarUp) | DigSeg(2, 2, BarCorn),
DigSeg(0, 0, UpLeft) | DigSeg(1, 0, BarUp) | DigSeg(2, 0, BarCorn) |
DigSeg(0, 1, UpLeft) | DigSeg(1, 1, BarUp) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, BarUp) | DigSeg(1, 2, BarUp) | DigSeg(2, 2, BarCorn),
DigSeg(0, 0, BarUp) | DigSeg(1, 0, BarUp) | DigSeg(2, 0, BarLeft) |
DigSeg(0, 1, Clear) | DigSeg(1, 1, Clear) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, Clear) | DigSeg(1, 2, Clear) | DigSeg(2, 2, BarCorn),
DigSeg(0, 0, UpLeft) | DigSeg(1, 0, BarUp) | DigSeg(2, 0, BarLeft) |
DigSeg(0, 1, UpLeft) | DigSeg(1, 1, BarUp) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, BarUp) | DigSeg(1, 2, BarUp) | DigSeg(2, 2, BarCorn),
DigSeg(0, 0, UpLeft) | DigSeg(1, 0, BarUp) | DigSeg(2, 0, BarLeft) |
DigSeg(0, 1, BarUp) | DigSeg(1, 1, BarUp) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, BarUp) | DigSeg(1, 2, BarUp) | DigSeg(2, 2, BarCorn)
},
{
DigSeg(0, 0, BarDown) | DigSeg(1, 0, BarDown) | DigSeg(2, 0, BarCorn) |
DigSeg(0, 1, BarLeft) | DigSeg(1, 1, Clear) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, DownLeft)| DigSeg(1, 2, BarDown) | DigSeg(2, 2, BarLeft),
DigSeg(0, 0, Clear) | DigSeg(1, 0, BarCorn) | DigSeg(2, 0, Clear) |
DigSeg(0, 1, Clear) | DigSeg(1, 1, BarLeft) | DigSeg(2, 1, Clear) |
DigSeg(0, 2, Clear) | DigSeg(1, 2, BarLeft) | DigSeg(2, 2, Clear),
DigSeg(0, 0, BarDown) | DigSeg(1, 0, BarDown) | DigSeg(2, 0, BarCorn) |
DigSeg(0, 1, BarDown) | DigSeg(1, 1, BarDown) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, DownLeft)| DigSeg(1, 2, BarDown) | DigSeg(2, 2, BarCorn),
DigSeg(0, 0, BarDown) | DigSeg(1, 0, BarDown) | DigSeg(2, 0, BarCorn) |
DigSeg(0, 1, BarDown) | DigSeg(1, 1, BarDown) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, BarDown) | DigSeg(1, 2, BarDown) | DigSeg(2, 2, BarLeft),
DigSeg(0, 0, BarCorn) | DigSeg(1, 0, Clear) | DigSeg(2, 0, BarCorn) |
DigSeg(0, 1, DownLeft)| DigSeg(1, 1, BarDown) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, Clear) | DigSeg(1, 2, Clear) | DigSeg(2, 2, BarLeft),
DigSeg(0, 0, BarDown) | DigSeg(1, 0, BarDown) | DigSeg(2, 0, BarCorn) |
DigSeg(0, 1, DownLeft)| DigSeg(1, 1, BarDown) | DigSeg(2, 1, BarCorn) |
DigSeg(0, 2, BarDown) | DigSeg(1, 2, BarDown) | DigSeg(2, 2, BarLeft),
DigSeg(0, 0, BarDown) | DigSeg(1, 0, BarDown) | DigSeg(2, 0, BarCorn) |
DigSeg(0, 1, DownLeft)| DigSeg(1, 1, BarDown) | DigSeg(2, 1, BarCorn) |
DigSeg(0, 2, DownLeft)| DigSeg(1, 2, BarDown) | DigSeg(2, 2, BarLeft),
DigSeg(0, 0, BarDown) | DigSeg(1, 0, BarDown) | DigSeg(2, 0, BarCorn) |
DigSeg(0, 1, Clear) | DigSeg(1, 1, Clear) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, Clear) | DigSeg(1, 2, Clear) | DigSeg(2, 2, BarLeft),
DigSeg(0, 0, BarDown) | DigSeg(1, 0, BarDown) | DigSeg(2, 0, BarCorn) |
DigSeg(0, 1, DownLeft)| DigSeg(1, 1, BarDown) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, DownLeft)| DigSeg(1, 2, BarDown) | DigSeg(2, 2, BarLeft),
DigSeg(0, 0, BarDown) | DigSeg(1, 0, BarDown) | DigSeg(2, 0, BarCorn) |
DigSeg(0, 1, DownLeft)| DigSeg(1, 1, BarDown) | DigSeg(2, 1, BarLeft) |
DigSeg(0, 2, BarDown) | DigSeg(1, 2, BarDown) | DigSeg(2, 2, BarLeft)
},
};
char DigitPart(int ud, int x, int y, char d) {
return (DigitFont[ud][d - '0'] >> (y * 9 + x * 3)) & 7;
};
enum GlyphSet {
None,
Upward,
Downward
};
static int glyphSet = 2;
static const char *glyphNames[2][5] = {
{
"UpNumPartUpLeft",
"UpNumPartBarLeft",
"UpNumPartBarUp",
"UpNumPartBarCorn",
"UpNumPartDot"
},
{
"DownNumPartDownLeft",
"DownNumPartBarLeft",
"DownNumPartBarDown",
"DownNumPartBarCorn",
"DownNumPartDot"
}
};
void WriteLarge(
const std::shared_ptr<duds::hardware::devices::displays::HD44780> &disp,
const std::string &str,
unsigned int c,
unsigned int r
) {
if (r > 1) {
)
);
}
if ((glyphSet + 1) != r) {
glyphSet = r + 1;
for (int i = 0; i < 5; ++i) {
disp->setGlyph(imgArc.
get(glyphNames[r][i]), i + 1);
}
}
int width = 0;
for (char c : str) {
if (((c >= '0') && (c <= '9')) || (c == ' ')) {
width += 3;
} else if ((c == ':') || (c == '~') || (c == '.')) {
++width;
} else {
}
}
if ((c + width) > disp->columns()) {
)
);
}
for (int y = 0; y < 3; ++y) {
std::string line;
for (char c : str) {
if (c == ':') {
if ((!r && (y < 2)) || (r && ( y > 0))) {
line.push_back(Dot);
} else {
line.push_back(' ');
}
} else if (c == '~') {
line.push_back(' ');
} else if (c == '.') {
line.push_back(BarCorn);
} else if (c == ' ') {
line += " ";
}else {
for (int x = 0; x < 3; ++x) {
char dp = DigitPart(r, x, y, c);
if (!dp) {
dp = ' ';
}
line.push_back(dp);
}
}
}
}
}
bool quit = false;
void runtest(const std::shared_ptr<displays::HD44780> &tmd)
try {
std::chrono::high_resolution_clock::time_point start;
float dispTime = 32768.0f;
boost::gregorian::date_facet *dateform =
new boost::gregorian::date_facet("%a %b %e, %Y");
tds.imbue(std::locale(tds.getloc(), dateform));
do {
start = std::chrono::high_resolution_clock::now();
lcd->sampleTime(ts);
int uS = (ts.value.time_since_epoch().count() / 1000) % 1000000;
int advT = uS + 64000 + (int)dispTime;
if (advT > 1000000) {
++tt;
}
std::tm ltime;
localtime_r(&tt, <ime);
if (ltime.tm_min & 1) {
} else {
}
boost::gregorian::date date = boost::gregorian::date_from_tm(ltime);
std::ostringstream oss;
char sep;
if (ltime.tm_sec & 1) {
sep = '~';
} else {
sep = ':';
}
oss << std::setfill(' ') << std::setw(2) << ltime.tm_hour << sep <<
std::setfill('0') << std::setw(2) << ltime.tm_min << sep <<
std::setw(2) << ltime.tm_sec;
if (ltime.tm_min & 1) {
WriteLarge(tmd, tds, oss.str(), 0, 0);
} else {
WriteLarge(tmd, tds, oss.str(), 0, 1);
}
tds.flush();
auto timeTaken = std::chrono::high_resolution_clock::now() - start;
dispTime = dispTime * 0.8f + 0.2f *
(float)(std::chrono::duration_cast<std::chrono::microseconds>(
timeTaken
).count());
std::chrono::microseconds delay(1000000 - uS - 64000 - (int)dispTime);
if (delay.count() > 16384) {
std::this_thread::sleep_for(delay);
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(16));
}
} while (!quit);
std::cout << "Last moving average of time taken to display: " <<
dispTime << "uS" << std::endl;
} catch (...) {
std::cerr << "Program failed in runtest(): " <<
boost::current_exception_diagnostic_information() << std::endl;
}
int main(int argc, char *argv[])
try {
std::string confpath;
{
boost::program_options::options_description optdesc(
"Options for clockLCD"
);
optdesc.add_options()
(
"help,h",
"Show this help message"
)
(
"conf,c",
boost::program_options::value<std::string>(&confpath)->
default_value("samples/pins.conf"),
"Pin configuration file; REQUIRED"
)
;
boost::program_options::variables_map vm;
boost::program_options::store(
boost::program_options::parse_command_line(argc, argv, optdesc),
vm
);
boost::program_options::notify(vm);
if (vm.count("help")) {
std::cout << "Show the time and date on the attached text LCD\n" <<
argv[0] << " [options]\n" << optdesc << std::endl;
return 0;
}
}
{
std::string imgpath(argv[0]);
int found = 0;
while (!imgpath.empty() && (found < 3)) {
imgpath.pop_back();
if (imgpath.back() == '/') {
++found;
}
}
imgArc.
load(imgpath +
"images/numberparts.bppia");
}
boost::property_tree::ptree tree;
boost::property_tree::read_info(confpath, tree);
boost::property_tree::ptree &pinconf = tree.get_child("pins");
#ifdef USE_SYSFS_PORT
std::shared_ptr<duds::hardware::interface::linux::SysFsPort> port =
#else
std::shared_ptr<duds::hardware::interface::linux::GpioDevPort> port =
#endif
std::shared_ptr<displays::HD44780> tmd =
std::make_shared<displays::HD44780>(
);
tmd->initialize();
std::thread doit(&runtest, std::ref(tmd));
std::cin.get();
quit = true;
doit.join();
} catch (...) {
std::cerr << "Test failed in main():\n" <<
boost::current_exception_diagnostic_information() << std::endl;
return 1;
}