diff --git a/Conf.cpp b/Conf.cpp index ae966a8..f293550 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -119,8 +119,12 @@ m_hd44780PWM(false), m_hd44780PWMPin(), m_hd44780PWMBright(), m_hd44780PWMDim(), +m_hd44780DisplayClock(false), +m_hd44780UTC(false), m_nextionPort("/dev/ttyAMA0"), m_nextionBrightness(50U), +m_nextionDisplayClock(false), +m_nextionUTC(false), m_oledType(3), m_oledBrightness(0), m_oledInvert(0) @@ -402,6 +406,10 @@ bool CConf::read() m_hd44780PWMBright = (unsigned int)::atoi(value); else if (::strcmp(key, "PWMDim") == 0) m_hd44780PWMDim = (unsigned int)::atoi(value); + else if (::strcmp(key, "DisplayClock") == 0) + m_hd44780DisplayClock = ::atoi(value) == 1; + else if (::strcmp(key, "UTC") == 0) + m_hd44780UTC = ::atoi(value) == 1; else if (::strcmp(key, "Pins") == 0) { char* p = ::strtok(value, ",\r\n"); while (p != NULL) { @@ -415,6 +423,10 @@ bool CConf::read() m_nextionPort = value; else if (::strcmp(key, "Brightness") == 0) m_nextionBrightness = (unsigned int)::atoi(value); + else if (::strcmp(key, "DisplayClock") == 0) + m_nextionDisplayClock = ::atoi(value) == 1; + else if (::strcmp(key, "UTC") == 0) + m_nextionUTC = ::atoi(value) == 1; } else if (section == SECTION_OLED) { if (::strcmp(key, "Type") == 0) m_oledType = (unsigned char)::atoi(value); @@ -800,6 +812,16 @@ unsigned int CConf::getHD44780PWMDim() const return m_hd44780PWMDim; } +bool CConf::getHD44780DisplayClock() const +{ + return m_hd44780DisplayClock; +} + +bool CConf::getHD44780UTC() const +{ + return m_hd44780UTC; +} + std::string CConf::getNextionPort() const { return m_nextionPort; @@ -810,6 +832,16 @@ unsigned int CConf::getNextionBrightness() const return m_nextionBrightness; } +bool CConf::getNextionDisplayClock() const +{ + return m_nextionDisplayClock; +} + +bool CConf::getNextionUTC() const +{ + return m_nextionUTC; +} + unsigned char CConf::getOLEDType() const { return m_oledType; diff --git a/Conf.h b/Conf.h index 39b5d93..e90450d 100644 --- a/Conf.h +++ b/Conf.h @@ -130,10 +130,14 @@ public: unsigned int getHD44780PWMPin() const; unsigned int getHD44780PWMBright() const; unsigned int getHD44780PWMDim() const; + bool getHD44780DisplayClock() const; + bool getHD44780UTC() const; // The Nextion section std::string getNextionPort() const; unsigned int getNextionBrightness() const; + bool getNextionDisplayClock() const; + bool getNextionUTC() const; // The OLED section unsigned char getOLEDType() const; @@ -229,9 +233,13 @@ private: unsigned int m_hd44780PWMPin; unsigned int m_hd44780PWMBright; unsigned int m_hd44780PWMDim; + bool m_hd44780DisplayClock; + bool m_hd44780UTC; std::string m_nextionPort; unsigned int m_nextionBrightness; + bool m_nextionDisplayClock; + bool m_nextionUTC; unsigned char m_oledType; unsigned char m_oledBrightness; diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 5295c9e..e137bd8 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -413,7 +413,7 @@ void CDMRSlot::writeModem(unsigned char *data) unsigned char fid = m_rfLC->getFID(); if (fid == FID_ETSI || fid == FID_DMRA) { errors = m_fec.regenerateDMR(data + 2U); - // LogDebug("DMR Slot %u, audio sequence no. 0, errs: %u/141", m_slotNo, errors); + LogDebug("DMR Slot %u, audio sequence no. 0, errs: %u/141", m_slotNo, errors); m_rfErrs += errors; } @@ -450,7 +450,7 @@ void CDMRSlot::writeModem(unsigned char *data) unsigned char fid = m_rfLC->getFID(); if (fid == FID_ETSI || fid == FID_DMRA) { errors = m_fec.regenerateDMR(data + 2U); - // LogDebug("DMR Slot %u, audio sequence no. %u, errs: %u/141", m_slotNo, m_rfN, errors); + LogDebug("DMR Slot %u, audio sequence no. %u, errs: %u/141", m_slotNo, m_rfN, errors); m_rfErrs += errors; } @@ -533,7 +533,7 @@ void CDMRSlot::writeModem(unsigned char *data) unsigned char fid = m_rfLC->getFID(); if (fid == FID_ETSI || fid == FID_DMRA) { errors = m_fec.regenerateDMR(data + 2U); - // LogDebug("DMR Slot %u, audio sequence no. %u, errs: %u/141", m_slotNo, m_rfN, errors); + LogDebug("DMR Slot %u, audio sequence no. %u, errs: %u/141", m_slotNo, m_rfN, errors); m_rfErrs += errors; } @@ -966,12 +966,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) if (m_netState == RS_NET_AUDIO) { unsigned char fid = m_netLC->getFID(); - if (fid == FID_ETSI || fid == FID_DMRA) { - unsigned int errors = m_fec.regenerateDMR(data + 2U); - // LogDebug("DMR Slot %u, audio, errs: %u/141", m_slotNo, errors); - m_netErrs += errors; - } - + if (fid == FID_ETSI || fid == FID_DMRA) + m_netErrs += m_fec.regenerateDMR(data + 2U); m_netBits += 141U; data[0U] = TAG_DATA; @@ -1010,12 +1006,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) return; unsigned char fid = m_netLC->getFID(); - if (fid == FID_ETSI || fid == FID_DMRA) { - unsigned int errors = m_fec.regenerateDMR(data + 2U); - // LogDebug("DMR Slot %u, audio, errs: %u/141", m_slotNo, errors); - m_netErrs += errors; - } - + if (fid == FID_ETSI || fid == FID_DMRA) + m_netErrs += m_fec.regenerateDMR(data + 2U); m_netBits += 141U; // Regenerate the embedded LC diff --git a/DStarControl.cpp b/DStarControl.cpp index c28a9e5..9706cbb 100644 --- a/DStarControl.cpp +++ b/DStarControl.cpp @@ -246,7 +246,7 @@ bool CDStarControl::writeModem(unsigned char *data) if (m_rfN == 0U) CSync::addDStarSync(data + 1U); - // LogDebug("D-Star, audio sequence no. %u, errs: %u/48", m_rfN, errors); + LogDebug("D-Star, audio sequence no. %u, errs: %u/48", m_rfN, errors); if (m_net) writeNetworkDataRF(data, errors, false); @@ -355,7 +355,7 @@ bool CDStarControl::writeModem(unsigned char *data) m_rfErrs += errors; m_rfBits += 48U; - // LogDebug("D-Star, audio sequence no. %u, errs: %u/48", m_rfN, errors); + LogDebug("D-Star, audio sequence no. %u, errs: %u/48", m_rfN, errors); if (m_net) writeNetworkDataRF(data, errors, false); diff --git a/HD44780.cpp b/HD44780.cpp index 821d41d..37cbc60 100644 --- a/HD44780.cpp +++ b/HD44780.cpp @@ -31,7 +31,10 @@ const char* LISTENING = "Listening "; const char* DEADSPACE = " "; -CHD44780::CHD44780(unsigned int rows, unsigned int cols, const std::string& callsign, unsigned int dmrid, const std::vector& pins, bool pwm, unsigned int pwmPin, unsigned int pwmBright, unsigned int pwmDim, bool duplex) : +char m_buffer1[128U]; +char m_buffer2[128U]; + +CHD44780::CHD44780(unsigned int rows, unsigned int cols, const std::string& callsign, unsigned int dmrid, const std::vector& pins, bool pwm, unsigned int pwmPin, unsigned int pwmBright, unsigned int pwmDim, bool displayClock, bool utc, bool duplex) : CDisplay(), m_rows(rows), m_cols(cols), @@ -47,11 +50,15 @@ m_pwm(pwm), m_pwmPin(pwmPin), m_pwmBright(pwmBright), m_pwmDim(pwmDim), +m_displayClock(displayClock), +m_utc(utc), m_duplex(duplex), -//m_duplex(true), // uncomment to force duplex display for testing! +//m_duplex(true), // uncomment to force duplex display for testing! m_fd(-1), m_dmr(false), -m_timer(1000U, 0U, 250U) // 250ms +m_clockDisplayTimer(1000U, 0U, 75U), // Update the clock display every 75ms +m_scrollTimer1(1000U, 0U, 250U), // Scroll speed for slot 1 - every 250ms +m_scrollTimer2(1000U, 0U, 250U) // Scroll speed for slot 2 - every 250ms { assert(rows > 1U); assert(cols > 15U); @@ -288,6 +295,9 @@ void CHD44780::adafruitLCDColour(ADAFRUIT_COLOUR colour) void CHD44780::setIdleInt() { + m_scrollTimer1.stop(); // Stop the scroll timer on slot 1 + m_scrollTimer2.stop(); // Stop the scroll timer on slot 2 + m_clockDisplayTimer.start(); // Start the clock display in IDLE only ::lcdClear(m_fd); #ifdef ADAFRUIT_DISPLAY @@ -301,16 +311,21 @@ void CHD44780::setIdleInt() ::pwmWrite(m_pwmPin, (m_pwmDim / 100) * 1024); } + // Print callsign and ID at on top row for all screen sizes ::lcdPosition(m_fd, 0, 0); - ::lcdPrintf(m_fd, "%-6s / %u", m_callsign.c_str(), m_dmrid); + ::lcdPrintf(m_fd, "%-6s", m_callsign.c_str()); + ::lcdPosition(m_fd, m_cols - 7, 0); + ::lcdPrintf(m_fd, "%7u", m_dmrid); - ::lcdPosition(m_fd, 0, 1); + // Print MMDVM and Idle on bottom row for all screen sizes + ::lcdPosition(m_fd, 0, m_rows - 1); ::lcdPutchar(m_fd, 2); ::lcdPutchar(m_fd, 2); ::lcdPutchar(m_fd, 3); ::lcdPutchar(m_fd, 4); ::lcdPutchar(m_fd, 2); - ::lcdPuts(m_fd, " Idle"); + ::lcdPosition(m_fd, m_cols - 4, m_rows - 1); + ::lcdPuts(m_fd, "Idle"); // Gets overwritten by clock on 2 line screen m_dmr = false; } @@ -323,6 +338,9 @@ void CHD44780::setErrorInt(const char* text) adafruitLCDColour(AC_RED); #endif + m_clockDisplayTimer.stop(); // Stop the clock display + m_scrollTimer1.stop(); // Stop the scroll timer on slot 1 + m_scrollTimer2.stop(); // Stop the scroll timer on slot 2 ::lcdClear(m_fd); if (m_pwm) { @@ -351,6 +369,9 @@ void CHD44780::setLockoutInt() adafruitLCDColour(AC_RED); #endif + m_clockDisplayTimer.stop(); // Stop the clock display + m_scrollTimer1.stop(); // Stop the scroll timer on slot 1 + m_scrollTimer2.stop(); // Stop the scroll timer on slot 2 ::lcdClear(m_fd); if (m_pwm) { @@ -385,6 +406,7 @@ void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your, adafruitLCDColour(AC_RED); #endif + m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); if (m_pwm) { @@ -398,45 +420,43 @@ void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your, ::lcdPuts(m_fd, "D-Star"); if (m_rows == 2U && m_cols == 16U) { - char buffer[16U]; - ::sprintf(buffer, "%s %.8s/%.4s", type, my1, my2); + ::sprintf(m_buffer1, "%s %.8s/%.4s", type, my1, my2); ::lcdPosition(m_fd, 0, 1); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 4U && m_cols == 16U) { - char buffer[16U]; - ::sprintf(buffer, "%s %.8s/%.4s", type, my1, my2); + ::sprintf(m_buffer1, "%s %.8s/%.4s", type, my1, my2); ::lcdPosition(m_fd, 0, 1); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); if (strcmp(reflector, " ") == 0) - ::sprintf(buffer, "%.8s", your); + ::sprintf(m_buffer1, "%.8s", your); else - ::sprintf(buffer, "%.8s<%.8s", your, reflector); + ::sprintf(m_buffer1, "%.8s<%.8s", your, reflector); ::lcdPosition(m_fd, 0, 2); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 4U && m_cols == 20U) { - char buffer[20U]; - ::sprintf(buffer, "%s %.8s/%.4s >", type, my1, my2); + char m_buffer1[20U]; + ::sprintf(m_buffer1, "%s %.8s/%.4s >", type, my1, my2); ::lcdPosition(m_fd, 0, 1); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); if (strcmp(reflector, " ") == 0) - ::sprintf(buffer, "%.8s", your); + ::sprintf(m_buffer1, "%.8s", your); else - ::sprintf(buffer, "%.8s <- %.8s", your, reflector); + ::sprintf(m_buffer1, "%.8s <- %.8s", your, reflector); ::lcdPosition(m_fd, 0, 2); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 2 && m_cols == 40U) { - char buffer[40U]; + char m_buffer1[40U]; if (strcmp(reflector, " ") == 0) - ::sprintf(buffer, "%s %.8s/%.4s > %.8s", type, my1, my2, your); + ::sprintf(m_buffer1, "%s %.8s/%.4s > %.8s", type, my1, my2, your); else - ::sprintf(buffer, "%s %.8s/%.4s > %.8s via %.8s", type, my1, my2, your, reflector); + ::sprintf(m_buffer1, "%s %.8s/%.4s > %.8s via %.8s", type, my1, my2, your, reflector); ::lcdPosition(m_fd, 0, 1); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } m_dmr = false; @@ -448,6 +468,8 @@ void CHD44780::clearDStarInt() adafruitLCDColour(AC_PURPLE); #endif + m_clockDisplayTimer.stop(); // Stop the clock display + if (m_rows == 2U && m_cols == 16U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); @@ -471,10 +493,10 @@ void CHD44780::clearDStarInt() void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type) { - char buffer[128]; // force 128 char buffer - we're never getting that far but stops us overflowing it! assert(type != NULL); if (!m_dmr) { + m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); #ifdef ADAFRUIT_DISPLAY @@ -491,21 +513,24 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro if (m_duplex) { if (m_rows > 2U) { ::lcdPosition(m_fd, 0, (m_rows / 2) - 2); - ::sprintf(buffer, "%s%s", "DMR", DEADSPACE); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::sprintf(m_buffer1, "%s%s", "DMR", DEADSPACE); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } if (slotNo == 1U) { + m_scrollTimer2.stop(); ::lcdPosition(m_fd, 0, (m_rows / 2)); ::lcdPrintf(m_fd, "2 %.*s", m_cols - 2U, LISTENING); } else { + m_scrollTimer1.stop(); ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); ::lcdPrintf(m_fd, "1 %.*s", m_cols - 2U, LISTENING); } } else { + m_scrollTimer2.stop(); ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); - ::sprintf(buffer, "%s%s", "DMR", DEADSPACE); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::sprintf(m_buffer1, "%s%s", "DMR", DEADSPACE); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPosition(m_fd, 0, (m_rows / 2)); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); } @@ -519,49 +544,51 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro if (slotNo == 1U) { ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); ::lcdPuts(m_fd, "1 "); - ::sprintf(buffer, "%s > %s%s", src.c_str(), dst.c_str(), DEADSPACE); + ::sprintf(m_buffer1, "%s > %s%s ", src.c_str(), group ? "TG" : "", dst.c_str()); + ::lcdPrintf(m_fd, "%.*s", m_cols - 2U, m_buffer1); - // Thread this out? - ::lcdPrintf(m_fd, "%.*s", m_cols - 2U, buffer); - - if (m_cols > 16) { - ::lcdCharDef(m_fd, 6, group ? tgChar : privChar); - ::lcdCharDef(m_fd, 5, strcmp(type, "R") == 0 ? rfChar : ipChar); - ::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2) - 1); - ::lcdPuts(m_fd, " "); - ::lcdPutchar(m_fd, 6); - ::lcdPutchar(m_fd, 5); + // Start the scroll timer on slot 1 if text in m_buffer1 will not fit in the space available + if (strlen(m_buffer1) - 5 > m_cols - 5 ) { + m_scrollTimer1.start(); } + + ::lcdCharDef(m_fd, 6, group ? tgChar : privChar); + ::lcdCharDef(m_fd, 5, strcmp(type, "R") == 0 ? rfChar : ipChar); + ::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2) - 1); + ::lcdPuts(m_fd, " "); + ::lcdPutchar(m_fd, 6); + ::lcdPutchar(m_fd, 5); } else { ::lcdPosition(m_fd, 0, (m_rows / 2)); ::lcdPuts(m_fd, "2 "); - ::sprintf(buffer, "%s > %s%s", src.c_str(), dst.c_str(), DEADSPACE); + ::sprintf(m_buffer2, "%s > %s%s ", src.c_str(), group ? "TG" : "", dst.c_str()); + ::lcdPrintf(m_fd, "%.*s", m_cols - 2U, m_buffer2); - // Thread this out? - ::lcdPrintf(m_fd, "%.*s", m_cols - 2U, buffer); - - if (m_cols > 16) { - ::lcdCharDef(m_fd, 6, group ? tgChar : privChar); - ::lcdCharDef(m_fd, 5, strcmp(type, "R") == 0 ? rfChar : ipChar); - ::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2)); - ::lcdPuts(m_fd, " "); - ::lcdPutchar(m_fd, 6); - ::lcdPutchar(m_fd, 5); + // Start the scroll timer on slot 2 if text in m_buffer2 will not fit in the space available + if (strlen(m_buffer2) - 5 > m_cols - 5 ) { + m_scrollTimer2.start(); } + + ::lcdCharDef(m_fd, 6, group ? tgChar : privChar); + ::lcdCharDef(m_fd, 5, strcmp(type, "R") == 0 ? rfChar : ipChar); + ::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2)); + ::lcdPuts(m_fd, " "); + ::lcdPutchar(m_fd, 6); + ::lcdPutchar(m_fd, 5); } } else { ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); ::lcdPutchar(m_fd, 0); - ::sprintf(buffer, " %s%s", src.c_str(), DEADSPACE); - ::lcdPrintf(m_fd, "%.*s", m_cols - 4U, buffer); + ::sprintf(m_buffer2, " %s%s", src.c_str(), DEADSPACE); + ::lcdPrintf(m_fd, "%.*s", m_cols - 4U, m_buffer2); ::lcdCharDef(m_fd, 5, strcmp(type, "R") == 0 ? rfChar : ipChar); ::lcdPosition(m_fd, m_cols - 1U, (m_rows / 2) - 1); ::lcdPutchar(m_fd, 5); ::lcdPosition(m_fd, 0, (m_rows / 2)); ::lcdPutchar(m_fd, 1); - ::sprintf(buffer, " %s%s", dst.c_str(), DEADSPACE); - ::lcdPrintf(m_fd, "%.*s", m_cols - 4U, buffer); + ::sprintf(m_buffer2, " %s%s", dst.c_str(), DEADSPACE); + ::lcdPrintf(m_fd, "%.*s", m_cols - 4U, m_buffer2); ::lcdCharDef(m_fd, 6, group ? tgChar : privChar); ::lcdPosition(m_fd, m_cols - 1U, (m_rows / 2)); ::lcdPutchar(m_fd, 6); @@ -571,26 +598,29 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro void CHD44780::clearDMRInt(unsigned int slotNo) { - char buffer[128]; // force 128 char buffer - we're never getting that far but stops us overflowing it! - #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_PURPLE); #endif + m_clockDisplayTimer.stop(); // Stop the clock display + if (m_duplex) { if (slotNo == 1U) { + m_scrollTimer1.stop(); // Stop the scroll timer on slot 1 ::lcdPosition(m_fd, 0, 0); ::lcdPrintf(m_fd, "1 %.*s", m_cols - 2U, LISTENING); } else { + m_scrollTimer2.stop(); // Stop the scroll timer on slot 2 ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "2 %.*s", m_cols - 2U, LISTENING); } } else { - ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); - ::sprintf(buffer, "%s%s", "DMR", DEADSPACE); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); - ::lcdPosition(m_fd, 0, (m_rows / 2)); - ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); + m_scrollTimer2.stop(); // Stop the scroll timer on slot 2 + ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); + ::sprintf(m_buffer2, "%s%s", "DMR", DEADSPACE); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer2); + ::lcdPosition(m_fd, 0, (m_rows / 2)); + ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); } } @@ -605,6 +635,7 @@ void CHD44780::writeFusionInt(const char* source, const char* dest, const char* adafruitLCDColour(AC_RED); #endif + m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); if (m_pwm) { @@ -618,34 +649,34 @@ void CHD44780::writeFusionInt(const char* source, const char* dest, const char* ::lcdPuts(m_fd, "System Fusion"); if (m_rows == 2U && m_cols == 16U) { - char buffer[16U]; - ::sprintf(buffer, "%.10s >", source); + char m_buffer1[16U]; + ::sprintf(m_buffer1, "%.10s >", source); ::lcdPosition(m_fd, 0, 1); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 4U && m_cols == 16U) { - char buffer[16U]; - ::sprintf(buffer, "%.10s >", source); + char m_buffer1[16U]; + ::sprintf(m_buffer1, "%.10s >", source); ::lcdPosition(m_fd, 0, 1); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); - ::sprintf(buffer, "%.10s", dest); + ::sprintf(m_buffer1, "%.10s", dest); ::lcdPosition(m_fd, 0, 2); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 4U && m_cols == 20U) { - char buffer[20U]; - ::sprintf(buffer, "%.10s >", source); + char m_buffer1[20U]; + ::sprintf(m_buffer1, "%.10s >", source); ::lcdPosition(m_fd, 0, 1); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); - ::sprintf(buffer, "%.10s", dest); + ::sprintf(m_buffer1, "%.10s", dest); ::lcdPosition(m_fd, 0, 2); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 2 && m_cols == 40U) { - char buffer[40U]; - ::sprintf(buffer, "%.10s > %.10s", source, dest); + char m_buffer1[40U]; + ::sprintf(m_buffer1, "%.10s > %.10s", source, dest); ::lcdPosition(m_fd, 0, 1); - ::lcdPrintf(m_fd, "%.*s", m_cols, buffer); + ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } m_dmr = false; @@ -657,6 +688,8 @@ void CHD44780::clearFusionInt() adafruitLCDColour(AC_PURPLE); #endif + m_clockDisplayTimer.stop(); // Stop the clock display + if (m_rows == 2U && m_cols == 16U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); @@ -680,13 +713,59 @@ void CHD44780::clearFusionInt() void CHD44780::clockInt(unsigned int ms) { - m_timer.clock(ms); - if (m_timer.isRunning() && m_timer.hasExpired()) { - // Do work every 250ms here + m_clockDisplayTimer.clock(ms); + m_scrollTimer1.clock(ms); + m_scrollTimer2.clock(ms); - // Start the timer with m_timer.start(); - // and stop it with m_timer.stop(); - m_timer.start(); + // Idle clock display + if (m_displayClock && m_clockDisplayTimer.isRunning() && m_clockDisplayTimer.hasExpired()) { + time_t currentTime; + struct tm *Time; + time(¤tTime); + + if (m_utc) { + Time = gmtime(¤tTime); + } else { + Time = localtime(¤tTime); + } + + int Day = Time->tm_mday; + int Month = Time->tm_mon + 1; + int Year = Time->tm_year + 1900; + int Hour = Time->tm_hour; + int Min = Time->tm_min; + int Sec = Time->tm_sec; + + if (m_cols == 16U && m_rows == 2U) { + ::lcdPosition(m_fd, m_cols - 8, 1); + } else { + ::lcdPosition(m_fd, (m_cols - 8) / 2, m_rows == 2 ? 1 : 2); + } + ::lcdPrintf(m_fd, "%02d:%02d:%02d", Hour, Min, Sec); + + if (m_cols != 16U && m_rows != 2U) { + ::lcdPosition(m_fd, (m_cols - 8) / 2, m_rows == 2 ? 0 : 1); + ::lcdPrintf(m_fd, "%02d/%02d/%2d", Day, Month, Year%100); + } + m_clockDisplayTimer.start(); + } + + // Slot 1 scrolling + if (m_scrollTimer1.isRunning() && m_scrollTimer1.hasExpired()) { + strncat(m_buffer1, m_buffer1, 1); // Move the first character to the end of the buffer + memmove(m_buffer1, m_buffer1 + 1, strlen(m_buffer1)); // Strip the first character + ::lcdPosition(m_fd, 2, (m_rows / 2) - 1); // Position on the LCD + ::lcdPrintf(m_fd, "%.*s", m_cols - 5U, m_buffer1); // Print it out + m_scrollTimer1.start(); // Restart the scroll timer + } + + // Slot 2 scrolling + if (m_scrollTimer2.isRunning() && m_scrollTimer2.hasExpired()) { + strncat(m_buffer2, m_buffer2, 1); + memmove(m_buffer2, m_buffer2 + 1, strlen(m_buffer2)); + ::lcdPosition(m_fd, 2, (m_rows / 2)); + ::lcdPrintf(m_fd, "%.*s", m_cols - 5U, m_buffer2); + m_scrollTimer2.start(); } } diff --git a/HD44780.h b/HD44780.h index 332a14f..2a803de 100644 --- a/HD44780.h +++ b/HD44780.h @@ -53,7 +53,7 @@ enum ADAFRUIT_COLOUR { class CHD44780 : public CDisplay { public: - CHD44780(unsigned int rows, unsigned int cols, const std::string& callsign, unsigned int dmrid, const std::vector& pins, bool pwm, unsigned int pwmPin, unsigned int pwmBright, unsigned int pwmDim, bool duplex); + CHD44780(unsigned int rows, unsigned int cols, const std::string& callsign, unsigned int dmrid, const std::vector& pins, bool pwm, unsigned int pwmPin, unsigned int pwmBright, unsigned int pwmDim, bool displayClock, bool utc, bool duplex); virtual ~CHD44780(); virtual bool open(); @@ -91,10 +91,14 @@ private: unsigned int m_pwmPin; unsigned int m_pwmBright; unsigned int m_pwmDim; + bool m_displayClock; + bool m_utc; bool m_duplex; int m_fd; bool m_dmr; - CTimer m_timer; + CTimer m_clockDisplayTimer; + CTimer m_scrollTimer1; + CTimer m_scrollTimer2; #ifdef ADAFRUIT_DISPLAY void adafruitLCDSetup(); diff --git a/HD44780.layouts b/HD44780.layouts new file mode 100644 index 0000000..03560cf --- /dev/null +++ b/HD44780.layouts @@ -0,0 +1,58 @@ +IDLE SCREEN LAYOUTS +------------------- + +16 x 2 +------ + + With clock Without clock + ---------- ------------- + + 0 1 0 1 + 0123456789012345 0123456789012345 + +----------------+ +----------------+ +0|AAAAAA NNNNNNN| 0|AAAAAA NNNNNNN| +1|MMDVM HH:MM:SS| 1|MMDVM Idle| + +----------------+ +----------------+ + +40 x 2 +------ + + With clock Without clock + ---------- ------------- + + 0 1 2 3 0 1 2 3 + 0123456789012345678901234567890123456789 0123456789012345678901234567890123456789 + +----------------------------------------+ +----------------------------------------+ +0|AAAAAA DD/MM/YY NNNNNNN| 0|AAAAAA NNNNNNN| +1|MMDVM HH:MM:SS Idle| 1|MMDVM Idle| + +----------------------------------------+ +----------------------------------------+ + +16 x 4 +------ + + With clock Without clock + ---------- ------------- + + 0 1 0 1 + 0123456789012345 0123456789012345 + +----------------+ +----------------+ +0|AAAAAA NNNNNNN| 0|AAAAAA NNNNNNN| +1| DD/MM/YY | 1| | +2| HH:MM:SS | 2| | +3|MMDVM Idle| 3|MMDVM Idle| + +----------------+ +----------------+ + +20 x 4 +------ + + With clock Without clock + ---------- ------------- + + 0 1 0 1 + 01234567890123456479 01234567890123456789 + +--------------------+ +--------------------+ +0|AAAAAA NNNNNNN| 0|AAAAAA NNNNNNN| +1| DD/MM/YY | 1| | +2| HH:MM:SS | 2| | +3|MMDVM Idle| 3|MMDVM Idle| + +--------------------+ +--------------------+ diff --git a/MMDVM.ini b/MMDVM.ini index 5cb9235..a92d104 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -95,18 +95,21 @@ Pins=11,10,0,1,2,3 # For Adafruit i2c HD44780 # Pins=115,113,112,111,110,109 -# PWM brightness control -PWM=1 +# PWM backlight +PWM=0 PWMPin=21 PWMBright=100 PWMDim=16 +DisplayClock=1 +UTC=0 [Nextion] Port=/dev/ttyAMA0 Brightness=50 +DisplayClock=1 +UTC=0 [OLED] Type=3 Brightness=0 Invert=0 - diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 328079a..fec92a9 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -27,6 +27,7 @@ #include "NullDisplay.h" #include "YSFControl.h" #include "Nextion.h" +#include "Thread.h" #if defined(HD44780) #include "HD44780.h" @@ -255,6 +256,7 @@ int CMMDVMHost::run() LogInfo(" Time: %u mins", time); m_cwIdTimer.setTimeout(time * 60U); + m_cwIdTimer.start(); } CTimer dmrBeaconTimer(1000U, 4U); @@ -551,9 +553,12 @@ int CMMDVMHost::run() m_cwIdTimer.clock(ms); if (m_cwIdTimer.isRunning() && m_cwIdTimer.hasExpired()) { - if (m_mode == MODE_IDLE && !m_modem->hasTX()) + if (m_mode == MODE_IDLE && !m_modem->hasTX()){ + LogDebug("sending CW ID"); m_modem->sendCWId(m_callsign); - m_cwIdTimer.start(); + + m_cwIdTimer.start(); //reset only after sending ID, timer-overflow after 49 days doesnt matter + } } dmrBeaconTimer.clock(ms); @@ -568,13 +573,8 @@ int CMMDVMHost::run() m_dmrTXTimer.stop(); } - if (ms < 5U) { -#if defined(_WIN32) || defined(_WIN64) - ::Sleep(5UL); // 5ms -#else - ::usleep(5000); // 5ms -#endif - } + if (ms < 5U) + CThread::sleep(5U); } LogMessage("MMDVMHost-%s is exiting on receipt of SIGHUP1", VERSION); @@ -791,11 +791,16 @@ void CMMDVMHost::createDisplay() } else if (type == "Nextion") { std::string port = m_conf.getNextionPort(); unsigned int brightness = m_conf.getNextionBrightness(); + bool displayClock = m_conf.getNextionDisplayClock(); + bool utc = m_conf.getNextionUTC(); LogInfo(" Port: %s", port.c_str()); LogInfo(" Brightness: %u", brightness); + LogInfo(" Clock Display: %s", displayClock ? "yes" : "no"); + if (displayClock) + LogInfo(" Display UTC: %s", utc ? "yes" : "no"); - m_display = new CNextion(m_callsign, dmrid, port, brightness); + m_display = new CNextion(m_callsign, dmrid, port, brightness, displayClock, utc); #if defined(HD44780) } else if (type == "HD44780") { unsigned int rows = m_conf.getHD44780Rows(); @@ -805,20 +810,26 @@ void CMMDVMHost::createDisplay() unsigned int pwmPin = m_conf.getHD44780PWMPin(); unsigned int pwmBright = m_conf.getHD44780PWMBright(); unsigned int pwmDim = m_conf.getHD44780PWMDim(); + bool displayClock = m_conf.getHD44780DisplayClock(); + bool utc = m_conf.getHD44780UTC(); if (pins.size() == 6U) { LogInfo(" Rows: %u", rows); LogInfo(" Columns: %u", columns); LogInfo(" Pins: %u,%u,%u,%u,%u,%u", pins.at(0U), pins.at(1U), pins.at(2U), pins.at(3U), pins.at(4U), pins.at(5U)); + LogInfo(" PWM Backlight: %s", pwm ? "yes" : "no"); if (pwm) { - LogInfo("PWM Brightness Control Enabled"); LogInfo(" PWM Pin: %u", pwmPin); LogInfo(" PWM Bright: %u", pwmBright); LogInfo(" PWM Dim: %u", pwmDim); } - m_display = new CHD44780(rows, columns, m_callsign, dmrid, pins, pwm, pwmPin, pwmBright, pwmDim, m_duplex); + LogInfo(" Clock Display: %s", displayClock ? "yes" : "no"); + if (displayClock) + LogInfo(" Display UTC: %s", utc ? "yes" : "no"); + + m_display = new CHD44780(rows, columns, m_callsign, dmrid, pins, pwm, pwmPin, pwmBright, pwmDim, displayClock, utc, m_duplex); } #endif #if defined(OLED) diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 1803f8c..1fc5912 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -187,6 +187,7 @@ + @@ -236,6 +237,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index b271f59..cf774a7 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -164,6 +164,9 @@ Header Files + + Header Files + @@ -301,5 +304,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index 830ee36..d464064 100644 --- a/Makefile +++ b/Makefile @@ -2,15 +2,15 @@ CC = gcc CXX = g++ -CFLAGS = -g -O3 -Wall -std=c++0x -LIBS = +CFLAGS = -g -O3 -Wall -std=c++0x -pthread +LIBS = -lpthread LDFLAGS = -g OBJECTS = \ AMBEFEC.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRIPSC.o DMRLookup.o DMRLC.o \ DMRShortLC.o DMRSlot.o DMRSlotType.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o Golay24128.o Hamming.o Log.o MMDVMHost.o Modem.o \ - Nextion.o NullDisplay.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o + Nextion.o NullDisplay.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o \ + YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 5ef85b3..7e5a9a5 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -2,14 +2,14 @@ # Support for the Adafruit i2c 16 x 2 RGB LCD Pi Plate CC = gcc CXX = g++ -CFLAGS = -g -O3 -Wall -std=c++0x -DHD44780 -DADAFRUIT_DISPLAY -I/usr/local/include +CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -DADAFRUIT_DISPLAY -I/usr/local/include LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRIPSC.o DMRLookup.o DMRLC.o \ DMRShortLC.o DMRSlot.o DMRSlotType.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o Log.o MMDVMHost.o \ - Modem.o Nextion.o NullDisplay.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Timer.o UDPSocket.o Utils.o YSFControl.o \ + Modem.o Nextion.o NullDisplay.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o \ YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 7ac9e20..e44d606 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -2,14 +2,14 @@ CC = gcc CXX = g++ -CFLAGS = -g -O3 -Wall -std=c++0x -DHD44780 -I/usr/local/include +CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -I/usr/local/include LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRIPSC.o DMRLookup.o DMRLC.o \ DMRShortLC.o DMRSlot.o DMRSlotType.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o Log.o MMDVMHost.o \ - Modem.o Nextion.o NullDisplay.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Timer.o UDPSocket.o Utils.o YSFControl.o \ + Modem.o Nextion.o NullDisplay.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o \ YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index bd7df7f..7af4bed 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -2,14 +2,14 @@ CC = gcc CXX = g++ -CFLAGS = -g -O3 -Wall -std=c++0x -DOLED -I/usr/local/include -LIBS = -lArduiPi_OLED +CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DOLED -I/usr/local/include +LIBS = -lArduiPi_OLED -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRIPSC.o DMRLookup.o DMRLC.o \ DMRShortLC.o DMRSlot.o DMRSlotType.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o Golay24128.o Hamming.o OLED.o Log.o MMDVMHost.o \ - Modem.o Nextion.o NullDisplay.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Timer.o UDPSocket.o Utils.o YSFControl.o \ + Modem.o Nextion.o NullDisplay.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o \ YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Modem.cpp b/Modem.cpp index a03e5f3..c16bf43 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -20,6 +20,7 @@ #include "DMRDefines.h" #include "YSFDefines.h" #include "Defines.h" +#include "Thread.h" #include "Modem.h" #include "Utils.h" #include "Log.h" @@ -717,11 +718,7 @@ bool CModem::readVersion() return false; for (unsigned int count = 0U; count < MAX_RESPONSES; count++) { -#if defined(_WIN32) || defined(_WIN64) - ::Sleep(10UL); -#else - ::usleep(10000UL); -#endif + CThread::sleep(10U); RESP_TYPE_MMDVM resp = getResponse(); if (resp == RTM_OK && m_buffer[2U] == MMDVM_GET_VERSION) { LogInfo("MMDVM protocol version: %u, description: %.*s", m_buffer[3U], m_length - 4U, m_buffer + 4U); @@ -729,11 +726,7 @@ bool CModem::readVersion() } } -#if defined(_WIN32) || defined(_WIN64) - ::Sleep(1000UL); // 1s -#else - ::sleep(1UL); // 1s -#endif + CThread::sleep(1000U); } LogError("Unable to read the firmware version after six attempts"); @@ -802,13 +795,9 @@ bool CModem::setConfig() unsigned int count = 0U; RESP_TYPE_MMDVM resp; do { -#if defined(_WIN32) || defined(_WIN64) - ::Sleep(10UL); -#else - ::usleep(10000UL); -#endif - resp = getResponse(); + CThread::sleep(10U); + resp = getResponse(); if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { count++; if (count >= MAX_RESPONSES) { @@ -861,13 +850,9 @@ bool CModem::setFrequency() unsigned int count = 0U; RESP_TYPE_MMDVM resp; do { -#if defined(_WIN32) || defined(_WIN64) - ::Sleep(10UL); -#else - ::usleep(10000UL); -#endif - resp = getResponse(); + CThread::sleep(10U); + resp = getResponse(); if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { count++; if (count >= MAX_RESPONSES) { diff --git a/Nextion.cpp b/Nextion.cpp index a3e777c..4cc22f8 100644 --- a/Nextion.cpp +++ b/Nextion.cpp @@ -22,14 +22,18 @@ #include #include #include +#include -CNextion::CNextion(const std::string& callsign, unsigned int dmrid, const std::string& port, unsigned int brightness) : +CNextion::CNextion(const std::string& callsign, unsigned int dmrid, const std::string& port, unsigned int brightness, bool displayClock, bool utc) : CDisplay(), m_callsign(callsign), m_dmrid(dmrid), m_serial(port, SERIAL_9600), m_brightness(brightness), -m_mode(MODE_IDLE) +m_mode(MODE_IDLE), +m_displayClock(displayClock), +m_utc(utc), +m_clockDisplayTimer(1000U, 0U, 400U) { assert(brightness >= 0U && brightness <= 100U); } @@ -67,6 +71,8 @@ void CNextion::setIdleInt() sendCommand(command); sendCommand("t1.txt=\"MMDVM IDLE\""); + m_clockDisplayTimer.start(); + m_mode = MODE_IDLE; } @@ -82,6 +88,8 @@ void CNextion::setErrorInt(const char* text) sendCommand(command); sendCommand("t1.txt=\"ERROR\""); + m_clockDisplayTimer.stop(); + m_mode = MODE_ERROR; } @@ -91,6 +99,8 @@ void CNextion::setLockoutInt() sendCommand("t0.txt=\"LOCKOUT\""); + m_clockDisplayTimer.stop(); + m_mode = MODE_LOCKOUT; } @@ -117,6 +127,8 @@ void CNextion::writeDStarInt(const char* my1, const char* my2, const char* your, sendCommand(text); } + m_clockDisplayTimer.stop(); + m_mode = MODE_DSTAR; } @@ -158,6 +170,8 @@ void CNextion::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro sendCommand(text); } + m_clockDisplayTimer.stop(); + m_mode = MODE_DMR; } @@ -193,6 +207,8 @@ void CNextion::writeFusionInt(const char* source, const char* dest, const char* sendCommand(text); } + m_clockDisplayTimer.stop(); + m_mode = MODE_YSF; } @@ -203,6 +219,35 @@ void CNextion::clearFusionInt() sendCommand("t2.txt=\"\""); } +void CNextion::clockInt(unsigned int ms) +{ + // Update the clock display in IDLE mode every 400ms + m_clockDisplayTimer.clock(ms); + if (m_displayClock && m_mode == MODE_IDLE && m_clockDisplayTimer.isRunning() && m_clockDisplayTimer.hasExpired()) { + time_t currentTime; + struct tm *Time; + ::time(¤tTime); // Get the current time + + if (m_utc) + Time = ::gmtime(¤tTime); + else + Time = ::localtime(¤tTime); + + int Day = Time->tm_mday; + int Month = Time->tm_mon + 1; + int Year = Time->tm_year + 1900; + int Hour = Time->tm_hour; + int Min = Time->tm_min; + int Sec = Time->tm_sec; + + char text[50U]; + ::sprintf(text, "t2.txt=\"%02d:%02d:%02d %02d/%02d/%2d\"", Hour, Min, Sec, Day, Month, Year % 100); + sendCommand(text); + + m_clockDisplayTimer.start(); // restart the clock display timer + } +} + void CNextion::close() { m_serial.close(); diff --git a/Nextion.h b/Nextion.h index 86667e6..319b23d 100644 --- a/Nextion.h +++ b/Nextion.h @@ -22,13 +22,14 @@ #include "Display.h" #include "Defines.h" #include "SerialController.h" +#include "Timer.h" #include class CNextion : public CDisplay { public: - CNextion(const std::string& callsign, unsigned int dmrid, const std::string& port, unsigned int brightness); + CNextion(const std::string& callsign, unsigned int dmrid, const std::string& port, unsigned int brightness, bool displayClock, bool utc); virtual ~CNextion(); virtual bool open(); @@ -49,12 +50,17 @@ protected: virtual void writeFusionInt(const char* source, const char* dest, const char* type, const char* origin); virtual void clearFusionInt(); + virtual void clockInt(unsigned int ms); + private: std::string m_callsign; unsigned int m_dmrid; CSerialController m_serial; unsigned int m_brightness; unsigned char m_mode; + bool m_displayClock; + bool m_utc; + CTimer m_clockDisplayTimer; void sendCommand(const char* command); }; diff --git a/Nextion/MMDVM_2.4.HMI b/Nextion/MMDVM_2.4.HMI index 3b33f0c..d3014ac 100644 Binary files a/Nextion/MMDVM_2.4.HMI and b/Nextion/MMDVM_2.4.HMI differ diff --git a/Nextion/MMDVM_2.4.tft b/Nextion/MMDVM_2.4.tft index b2faa39..c650c1c 100644 Binary files a/Nextion/MMDVM_2.4.tft and b/Nextion/MMDVM_2.4.tft differ diff --git a/Nextion/MMDVM_3.2.HMI b/Nextion/MMDVM_3.2.HMI index 2436267..25b07ce 100644 Binary files a/Nextion/MMDVM_3.2.HMI and b/Nextion/MMDVM_3.2.HMI differ diff --git a/Nextion/MMDVM_3.2.tft b/Nextion/MMDVM_3.2.tft index fd2752d..84d8519 100644 Binary files a/Nextion/MMDVM_3.2.tft and b/Nextion/MMDVM_3.2.tft differ diff --git a/Nextion/MMDVM_3.5.HMI b/Nextion/MMDVM_3.5.HMI index b3eb571..0e06f31 100644 Binary files a/Nextion/MMDVM_3.5.HMI and b/Nextion/MMDVM_3.5.HMI differ diff --git a/Nextion/MMDVM_3.5.tft b/Nextion/MMDVM_3.5.tft index 0c4cc62..41d66cb 100644 Binary files a/Nextion/MMDVM_3.5.tft and b/Nextion/MMDVM_3.5.tft differ diff --git a/Thread.cpp b/Thread.cpp new file mode 100644 index 0000000..b334436 --- /dev/null +++ b/Thread.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Thread.h" + +#if defined(_WIN32) || defined(_WIN64) + +CThread::CThread() : +m_handle() +{ +} + +CThread::~CThread() +{ +} + +bool CThread::run() +{ + m_handle = ::CreateThread(NULL, 0, &helper, this, 0, NULL); + + return m_handle != NULL; +} + + +void CThread::wait() +{ + ::WaitForSingleObject(m_handle, INFINITE); + + ::CloseHandle(m_handle); +} + + +DWORD CThread::helper(LPVOID arg) +{ + CThread* p = (CThread*)arg; + + p->entry(); + + return 0UL; +} + +void CThread::sleep(unsigned int ms) +{ + ::Sleep(ms); +} + +#else + +#include + +CThread::CThread() : +m_thread() +{ +} + +CThread::~CThread() +{ +} + +bool CThread::run() +{ + return ::pthread_create(&m_thread, NULL, helper, this) == 0; +} + + +void CThread::wait() +{ + ::pthread_join(m_thread, NULL); +} + + +void* CThread::helper(void* arg) +{ + CThread* p = (CThread*)arg; + + p->entry(); + + return NULL; +} + +void CThread::sleep(unsigned int ms) +{ + ::usleep(ms * 1000); +} + +#endif diff --git a/Thread.h b/Thread.h new file mode 100644 index 0000000..352d938 --- /dev/null +++ b/Thread.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if !defined(THREAD_H) +#define THREAD_H + +#if defined(_WIN32) || defined(_WIN64) +#include +#else +#include +#endif + +class CThread +{ +public: + CThread(); + virtual ~CThread(); + + virtual bool run(); + + virtual void entry() = 0; + + virtual void wait(); + + static void sleep(unsigned int ms); + +private: +#if defined(_WIN32) || defined(_WIN64) + HANDLE m_handle; +#else + pthread_t m_thread; +#endif + +#if defined(_WIN32) || defined(_WIN64) + static DWORD __stdcall helper(LPVOID arg); +#else + static void* helper(void* arg); +#endif +}; + +#endif diff --git a/YSFControl.cpp b/YSFControl.cpp index ee180b7..4d5ee00 100644 --- a/YSFControl.cpp +++ b/YSFControl.cpp @@ -459,7 +459,7 @@ void CYSFControl::writeNetwork() } fich.setVoIP(true); - fich.setMR(YSF_MR_NOT_BUSY); + fich.setMR(YSF_MR_BUSY); fich.encode(data + 35U); }