/* * Copyright (C) 2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX & Tony Corbett G0WFV * * 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 "HD44780.h" #include "Log.h" #include #include #include #include #include #include #include const char* LISTENING = "Listening "; const char* DEADSPACE = " "; char m_buffer1[128U]; char m_buffer2[128U]; char m_buffer3[128U]; char m_buffer4[128U]; const unsigned int DSTAR_RSSI_COUNT = 3U; // 3 * 420ms = 1260ms const unsigned int DMR_RSSI_COUNT = 4U; // 4 * 360ms = 1440ms const unsigned int YSF_RSSI_COUNT = 13U; // 13 * 100ms = 1300ms const unsigned int P25_RSSI_COUNT = 7U; // 7 * 180ms = 1260ms const unsigned int NXDN_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms const unsigned int M17_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms CHD44780::CHD44780(unsigned int rows, unsigned int cols, const std::string& callsign, unsigned int dmrid, const std::vector& pins, unsigned int i2cAddress, bool pwm, unsigned int pwmPin, unsigned int pwmBright, unsigned int pwmDim, bool displayClock, bool utc, bool duplex) : CDisplay(), m_rows(rows), m_cols(cols), m_callsign(callsign), m_dmrid(dmrid), m_rb(pins.at(0U)), m_strb(pins.at(1U)), m_d0(pins.at(2U)), m_d1(pins.at(3U)), m_d2(pins.at(4U)), m_d3(pins.at(5U)), m_i2cAddress(i2cAddress), 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_fd(-1), m_dmr(false), m_clockDisplayTimer(1000U, 0U, 250U), // Update the clock display every 250ms m_rssiCount1(0U), m_rssiCount2(0U) { assert(rows > 1U); assert(cols > 15U); } // Text-based custom character for "from" unsigned char fmChar[8] = { 0b11100, 0b10000, 0b11000, 0b10000, 0b00101, 0b00111, 0b00101, 0b00101 }; // Text-based custom character for "to" unsigned char toChar[8] = { 0b11100, 0b01000, 0b01000, 0b01000, 0b00010, 0b00101, 0b00101, 0b00010 }; // Icon-based custom character for RF traffic unsigned char rfChar[8] = { 0b11111, 0b10101, 0b01110, 0b00100, 0b00100, 0b00100, 0b00100, 0b00000 }; // Icon-based custom character for network traffic unsigned char ipChar[8] = { 0b00000, 0b01110, 0b10001, 0b00100, 0b01010, 0b00000, 0b00100, 0b00000 }; // Icon-based custom character for call to talkgroup unsigned char tgChar[8] = { 0b01110, 0b10001, 0b10001, 0b10001, 0b01010, 0b01100, 0b10000, 0b00000 }; // Icon-based custom character for private call unsigned char privChar[8] = { 0b00100, 0b00000, 0b11111, 0b01110, 0b01110, 0b01010, 0b01010, 0b00000 }; CHD44780::~CHD44780() { } bool CHD44780::open() { ::wiringPiSetup(); if (m_pwm) { if (m_pwmPin != 1U) { ::softPwmCreate(m_pwmPin, 0, 100); ::softPwmWrite(m_pwmPin, m_pwmDim); } else { ::pinMode(m_pwmPin, PWM_OUTPUT); ::pwmWrite(m_pwmPin, (m_pwmDim / 100) * 1024); } } #ifdef ADAFRUIT_DISPLAY adafruitLCDSetup(); #endif #ifdef PCF8574_DISPLAY pcf8574LCDSetup(); #endif m_fd = ::lcdInit(m_rows, m_cols, 4, m_rb, m_strb, m_d0, m_d1, m_d2, m_d3, 0, 0, 0, 0); if (m_fd == -1) { LogError("Unable to open the HD44780"); return false; } ::lcdDisplay(m_fd, 1); ::lcdCursor(m_fd, 0); ::lcdCursorBlink(m_fd, 0); ::lcdCharDef(m_fd, 0, fmChar); ::lcdCharDef(m_fd, 1, toChar); ::lcdCharDef(m_fd, 2, rfChar); ::lcdCharDef(m_fd, 3, ipChar); ::lcdCharDef(m_fd, 4, privChar); ::lcdCharDef(m_fd, 5, tgChar); return true; } #ifdef ADAFRUIT_DISPLAY void CHD44780::adafruitLCDSetup() { // The other control pins are initialised with lcdInit() ::mcp23017Setup(AF_BASE, m_i2cAddress); // Backlight LEDs ::pinMode(AF_RED, OUTPUT); ::pinMode(AF_GREEN, OUTPUT); ::pinMode(AF_BLUE, OUTPUT); // Control signals ::pinMode(AF_RW, OUTPUT); ::digitalWrite(AF_RW, LOW); m_rb = AF_RS; m_strb = AF_E; m_d0 = AF_D0; m_d1 = AF_D1; m_d2 = AF_D2; m_d3 = AF_D3; } void CHD44780::adafruitLCDColour(ADAFRUIT_COLOUR colour) { switch (colour) { case AC_OFF: ::digitalWrite(AF_RED, AF_OFF); ::digitalWrite(AF_GREEN, AF_OFF); ::digitalWrite(AF_BLUE, AF_OFF); break; case AC_WHITE: ::digitalWrite(AF_RED, AF_ON); ::digitalWrite(AF_GREEN, AF_ON); ::digitalWrite(AF_BLUE, AF_ON); break; case AC_RED: ::digitalWrite(AF_RED, AF_ON); ::digitalWrite(AF_GREEN, AF_OFF); ::digitalWrite(AF_BLUE, AF_OFF); break; case AC_GREEN: ::digitalWrite(AF_RED, AF_OFF); ::digitalWrite(AF_GREEN, AF_ON); ::digitalWrite(AF_BLUE, AF_OFF); break; case AC_BLUE: ::digitalWrite(AF_RED, AF_OFF); ::digitalWrite(AF_GREEN, AF_OFF); ::digitalWrite(AF_BLUE, AF_ON); break; case AC_PURPLE: ::digitalWrite(AF_RED, AF_ON); ::digitalWrite(AF_GREEN, AF_OFF); ::digitalWrite(AF_BLUE, AF_ON); break; case AC_YELLOW: ::digitalWrite(AF_RED, AF_ON); ::digitalWrite(AF_GREEN, AF_ON); ::digitalWrite(AF_BLUE, AF_OFF); break; case AC_ICE: ::digitalWrite(AF_RED, AF_OFF); ::digitalWrite(AF_GREEN, AF_ON); ::digitalWrite(AF_BLUE, AF_ON); break; default: break; } } #endif #ifdef PCF8574_DISPLAY void CHD44780::pcf8574LCDSetup() { // Initalize PFC8574 ::pcf8574Setup(AF_BASE, m_i2cAddress); // Turn on backlight ::pinMode(AF_BL, OUTPUT); ::digitalWrite(AF_BL, 1); // Set LCD to write mode. ::pinMode(AF_RW, OUTPUT); ::digitalWrite(AF_RW, 0); m_rb = AF_RS; m_strb = AF_E; m_d0 = AF_D0; m_d1 = AF_D1; m_d2 = AF_D2; m_d3 = AF_D3; } #endif void CHD44780::setIdleInt() { m_clockDisplayTimer.start(); // Start the clock display in IDLE only ::lcdClear(m_fd); #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_WHITE); #endif if (m_pwm) { if (m_pwmPin != 1U) ::softPwmWrite(m_pwmPin, m_pwmDim); else ::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", m_callsign.c_str()); ::lcdPosition(m_fd, m_cols - 7, 0); ::lcdPrintf(m_fd, "%7u", m_dmrid); // Print MMDVM and Idle on bottom row for all screen sizes ::lcdPosition(m_fd, 0, m_rows - 1); ::lcdPuts(m_fd, "MMDVM"); ::lcdPosition(m_fd, m_cols - 4, m_rows - 1); ::lcdPuts(m_fd, "Idle"); // Gets overwritten by clock on 2 line screen m_dmr = false; } void CHD44780::setErrorInt(const char* text) { assert(text != NULL); #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_RED); #endif m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); if (m_pwm) { if (m_pwmPin != 1U) ::softPwmWrite(m_pwmPin, m_pwmBright); else ::pwmWrite(m_pwmPin, (m_pwmBright / 100) * 1024); } ::lcdPosition(m_fd, 0, 0); ::lcdPuts(m_fd, "MMDVM"); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%s ERROR", text); m_dmr = false; } void CHD44780::setLockoutInt() { #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_RED); #endif m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); if (m_pwm) { if (m_pwmPin != 1U) ::softPwmWrite(m_pwmPin, m_pwmBright); else ::pwmWrite(m_pwmPin, (m_pwmBright / 100) * 1024); } ::lcdPosition(m_fd, 0, 0); ::lcdPuts(m_fd, "MMDVM"); ::lcdPosition(m_fd, 0, 1); ::lcdPuts(m_fd, "Lockout"); m_dmr = false; } void CHD44780::setQuitInt() { #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_RED); #endif m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); if (m_pwm) { if (m_pwmPin != 1U) ::softPwmWrite(m_pwmPin, m_pwmBright); else ::pwmWrite(m_pwmPin, (m_pwmBright / 100) * 1024); } ::lcdPosition(m_fd, 0, 0); ::lcdPuts(m_fd, "MMDVM"); ::lcdPosition(m_fd, 0, 1); ::lcdPuts(m_fd, "STOPPED"); m_dmr = false; } void CHD44780::setFMInt() { m_clockDisplayTimer.stop(); ::lcdClear(m_fd); #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_WHITE); #endif if (m_pwm) { if (m_pwmPin != 1U) ::softPwmWrite(m_pwmPin, m_pwmDim); else ::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", m_callsign.c_str()); ::lcdPosition(m_fd, m_cols - 7, 0); ::lcdPrintf(m_fd, "%7u", m_dmrid); // Print MMDVM and Idle on bottom row for all screen sizes ::lcdPosition(m_fd, 0, m_rows - 1); ::lcdPuts(m_fd, "MMDVM"); ::lcdPosition(m_fd, m_cols - 4, m_rows - 1); ::lcdPuts(m_fd, "FM"); // Gets overwritten by clock on 2 line screen m_dmr = false; } void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) { assert(my1 != NULL); assert(my2 != NULL); assert(your != NULL); assert(type != NULL); assert(reflector != NULL); #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_RED); #endif m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); if (m_pwm) { if (m_pwmPin != 1U) ::softPwmWrite(m_pwmPin, m_pwmBright); else ::pwmWrite(m_pwmPin, (m_pwmBright / 100) * 1024); } if (m_rows > 2U) { ::lcdPosition(m_fd, 0, (m_rows / 2) - 2); ::sprintf(m_buffer1, "%s%s", "D-Star", DEADSPACE); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); ::lcdPutchar(m_fd, 0); ::lcdPrintf(m_fd, " %.8s/%.4s", my1, my2); ::lcdPosition(m_fd, m_cols - 1, (m_rows / 2) - 1); if (strcmp(type, "R") == 0) ::lcdPutchar(m_fd, 2); else ::lcdPutchar(m_fd, 3); ::sprintf(m_buffer1, "%.8s", your); char *p = m_buffer1; for (; *p; ++p) { if (*p == ' ') *p = '_'; } if (strcmp(reflector, " ") != 0) { if (m_rows == 2 && m_cols == 40) { ::sprintf(m_buffer3, " via %.8s", reflector); strcat(m_buffer1, m_buffer3); } else if (m_rows > 2) { ::sprintf(m_buffer3, "via %.8s", reflector); ::lcdPosition(m_fd, 0, (m_rows / 2) + 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer3); } } ::lcdPosition(m_fd, 0, (m_rows / 2)); ::lcdPutchar(m_fd, 1); ::lcdPrintf(m_fd, " %.*s", m_cols, m_buffer1); m_dmr = false; m_rssiCount1 = 0U; } void CHD44780::writeDStarRSSIInt(unsigned char rssi) { if (m_rssiCount1 == 0U && m_rows > 2) { ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "-%3udBm", rssi); } m_rssiCount1++; if (m_rssiCount1 >= DSTAR_RSSI_COUNT) m_rssiCount1 = 0U; } void CHD44780::clearDStarInt() { #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_PURPLE); #endif m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); ::sprintf(m_buffer2, "%s%s", "D-Star", DEADSPACE); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer2); ::lcdPosition(m_fd, 0, (m_rows / 2)); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); } void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type) { assert(type != NULL); if (!m_dmr) { m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_GREEN); #endif if (m_pwm) { if (m_pwmPin != 1U) ::softPwmWrite(m_pwmPin, m_pwmBright); else ::pwmWrite(m_pwmPin, (m_pwmBright / 100) * 1024); } if (m_duplex) { if (m_rows > 2U) { ::lcdPosition(m_fd, 0, (m_rows / 2) - 2); ::sprintf(m_buffer1, "%s%s", "DMR", DEADSPACE); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } if (slotNo == 1U) { //m_dmrScrollTimer2.stop(); ::lcdPosition(m_fd, 0, (m_rows / 2)); ::lcdPrintf(m_fd, "2 %.*s", m_cols - 2U, LISTENING); } else { //m_dmrScrollTimer1.stop(); ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); ::lcdPrintf(m_fd, "1 %.*s", m_cols - 2U, LISTENING); } } else { //m_dmrScrollTimer2.stop(); if (m_rows > 2U) { ::lcdPosition(m_fd, 0, (m_rows / 2) - 2); ::sprintf(m_buffer1, "%s", DEADSPACE); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); ::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); } } #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_RED); #endif if (m_duplex) { if (m_rows > 2U) { ::lcdPosition(m_fd, 0, (m_rows / 2) - 2); ::sprintf(m_buffer1, "%s%s", "DMR", DEADSPACE); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } if (slotNo == 1U) { ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); ::lcdPuts(m_fd, "1 "); if (m_cols > 16 ) ::sprintf(m_buffer1, "%s > %s%s%s", src.c_str(), group ? "TG" : "", dst.c_str(), DEADSPACE); else ::sprintf(m_buffer1, "%s>%s%s", src.c_str(), dst.c_str(), DEADSPACE); ::lcdPrintf(m_fd, "%.*s", m_cols - 2U, m_buffer1); ::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2) - 1); ::lcdPuts(m_fd, " "); if (group) ::lcdPutchar(m_fd, 5); else ::lcdPutchar(m_fd, 4); if (strcmp(type, "R") == 0) ::lcdPutchar(m_fd, 2); else ::lcdPutchar(m_fd, 3); } else { ::lcdPosition(m_fd, 0, (m_rows / 2)); ::lcdPuts(m_fd, "2 "); if (m_cols > 16) ::sprintf(m_buffer2, "%s > %s%s%s", src.c_str(), group ? "TG" : "", dst.c_str(), DEADSPACE); else ::sprintf(m_buffer2, "%s>%s%s", src.c_str(), dst.c_str(), DEADSPACE); ::lcdPrintf(m_fd, "%.*s", m_cols - 2U, m_buffer2); ::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2)); ::lcdPuts(m_fd, " "); if (group) ::lcdPutchar(m_fd, 5); else ::lcdPutchar(m_fd, 4); if (strcmp(type, "R") == 0) ::lcdPutchar(m_fd, 2); else ::lcdPutchar(m_fd, 3); } } else { if (m_rows > 2U) { ::lcdPosition(m_fd, 0, (m_rows / 2) - 2); ::sprintf(m_buffer1, "%s%s", "DMR", DEADSPACE); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); ::lcdPutchar(m_fd, 0); ::sprintf(m_buffer2, " %s%s", src.c_str(), DEADSPACE); ::lcdPrintf(m_fd, "%.*s", m_cols - 4U, m_buffer2); ::lcdPosition(m_fd, m_cols - 1U, (m_rows / 2) - 1); if (strcmp(type, "R") == 0) ::lcdPutchar(m_fd, 2); else ::lcdPutchar(m_fd, 3); ::lcdPosition(m_fd, 0, (m_rows / 2)); ::lcdPutchar(m_fd, 1); ::sprintf(m_buffer2, " %s%s%s", group ? "TG" : "", dst.c_str(), DEADSPACE); ::lcdPrintf(m_fd, "%.*s", m_cols - 4U, m_buffer2); ::lcdPosition(m_fd, m_cols - 1U, (m_rows / 2)); if (group) ::lcdPutchar(m_fd, 5); else ::lcdPutchar(m_fd, 4); } m_dmr = true; m_rssiCount1 = 0U; m_rssiCount2 = 0U; } void CHD44780::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi) { if (m_rows > 2) { if (slotNo == 1U) { if (m_rssiCount1 == 0U) { ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "-%3udBm", rssi); } m_rssiCount1++; if (m_rssiCount1 >= DMR_RSSI_COUNT) m_rssiCount1 = 0U; } else { if (m_rssiCount2 == 0U) { ::lcdPosition(m_fd, (m_cols / 2), 3); ::lcdPrintf(m_fd, "-%3udBm", rssi); } m_rssiCount2++; if (m_rssiCount2 >= DMR_RSSI_COUNT) m_rssiCount2 = 0U; } } } void CHD44780::clearDMRInt(unsigned int slotNo) { #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_PURPLE); #endif m_clockDisplayTimer.stop(); // Stop the clock display if (m_duplex) { if (slotNo == 1U) { ::lcdPosition(m_fd, 0, (m_rows / 2) - 1); ::lcdPrintf(m_fd, "1 %.*s", m_cols - 2U, LISTENING); if (m_rows > 2) { // clear slot 1 RSSI ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "%.*s", m_cols / 2, DEADSPACE); } } else { ::lcdPosition(m_fd, 0, (m_rows / 2)); ::lcdPrintf(m_fd, "2 %.*s", m_cols - 2U, LISTENING); if (m_rows > 2) { // cleat slot 2 RSSI ::lcdPosition(m_fd, m_cols / 2, 3); ::lcdPrintf(m_fd, "%.*s", m_cols / 2, DEADSPACE); } } } else { if (m_rows > 2U) { ::lcdPosition(m_fd, 0, (m_rows / 2) - 2); ::sprintf(m_buffer1, "%s", DEADSPACE); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } ::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); } } void CHD44780::writeFusionInt(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin) { assert(source != NULL); assert(dest != NULL); assert(type != NULL); assert(origin != NULL); #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_RED); #endif m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); if (m_pwm) { if (m_pwmPin != 1U) ::softPwmWrite(m_pwmPin, m_pwmBright); else ::pwmWrite(m_pwmPin, (m_pwmBright / 100) * 1024); } ::lcdPosition(m_fd, 0, 0); ::lcdPuts(m_fd, "System Fusion"); if (m_rows == 2U && m_cols == 16U) { ::sprintf(m_buffer1, "%.10s >", source); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 4U && m_cols == 16U) { ::sprintf(m_buffer1, "%.10s >", source); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::sprintf(m_buffer1, "DG-ID %u", dgid); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 4U && m_cols == 20U) { ::sprintf(m_buffer1, "%.10s >", source); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::sprintf(m_buffer1, "DG-ID %u", dgid); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 2 && m_cols == 40U) { ::sprintf(m_buffer1, "%.10s > DG-ID %u", source, dgid); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } m_dmr = false; m_rssiCount1 = 0U; } void CHD44780::writeFusionRSSIInt(unsigned char rssi) { if (m_rssiCount1 == 0U && m_rows > 2) { ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "-%3udBm", rssi); } m_rssiCount1++; if (m_rssiCount1 >= YSF_RSSI_COUNT) m_rssiCount1 = 0U; } void CHD44780::clearFusionInt() { #ifdef ADAFRUIT_DISPLAY 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); } else if (m_rows == 4U && m_cols == 16U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); } else if (m_rows == 4U && m_cols == 20U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); } else if (m_rows == 2 && m_cols == 40U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); } } void CHD44780::writeP25Int(const char* source, bool group, unsigned int dest, const char* type) { assert(source != NULL); assert(type != NULL); #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_RED); #endif m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); if (m_pwm) { if (m_pwmPin != 1U) ::softPwmWrite(m_pwmPin, m_pwmBright); else ::pwmWrite(m_pwmPin, (m_pwmBright / 100) * 1024); } ::lcdPosition(m_fd, 0, 0); ::lcdPuts(m_fd, "P25"); if (m_rows == 2U && m_cols == 16U) { ::sprintf(m_buffer1, "%.10s >", source); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 4U && m_cols == 16U) { ::sprintf(m_buffer1, "%.10s >", source); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::sprintf(m_buffer1, "%s%u", group ? "TG" : "", dest); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 4U && m_cols == 20U) { ::sprintf(m_buffer1, "%.10s >", source); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::sprintf(m_buffer1, "%s%u", group ? "TG" : "", dest); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 2 && m_cols == 40U) { ::sprintf(m_buffer1, "%.10s > %s%u", source, group ? "TG" : "", dest); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } m_dmr = false; m_rssiCount1 = 0U; } void CHD44780::writeP25RSSIInt(unsigned char rssi) { if (m_rssiCount1 == 0U && m_rows > 2) { ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "-%3udBm", rssi); } m_rssiCount1++; if (m_rssiCount1 >= P25_RSSI_COUNT) m_rssiCount1 = 0U; } void CHD44780::clearP25Int() { #ifdef ADAFRUIT_DISPLAY 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); } else if (m_rows == 4U && m_cols == 16U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); } else if (m_rows == 4U && m_cols == 20U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); } else if (m_rows == 2 && m_cols == 40U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); } } void CHD44780::writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type) { assert(source != NULL); assert(type != NULL); #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_RED); #endif m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); if (m_pwm) { if (m_pwmPin != 1U) ::softPwmWrite(m_pwmPin, m_pwmBright); else ::pwmWrite(m_pwmPin, (m_pwmBright / 100) * 1024); } ::lcdPosition(m_fd, 0, 0); ::lcdPuts(m_fd, "NXDN"); if (m_rows == 2U && m_cols == 16U) { ::sprintf(m_buffer1, "%.10s >", source); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 4U && m_cols == 16U) { ::sprintf(m_buffer1, "%.10s >", source); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::sprintf(m_buffer1, "%s%u", group ? "TG" : "", dest); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 4U && m_cols == 20U) { ::sprintf(m_buffer1, "%.10s >", source); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::sprintf(m_buffer1, "%s%u", group ? "TG" : "", dest); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 2 && m_cols == 40U) { ::sprintf(m_buffer1, "%.10s > %s%u", source, group ? "TG" : "", dest); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } m_dmr = false; m_rssiCount1 = 0U; } void CHD44780::writeNXDNRSSIInt(unsigned char rssi) { if (m_rssiCount1 == 0U && m_rows > 2) { ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "-%3udBm", rssi); } m_rssiCount1++; if (m_rssiCount1 >= NXDN_RSSI_COUNT) m_rssiCount1 = 0U; } void CHD44780::clearNXDNInt() { #ifdef ADAFRUIT_DISPLAY 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); } else if (m_rows == 4U && m_cols == 16U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); } else if (m_rows == 4U && m_cols == 20U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); } else if (m_rows == 2 && m_cols == 40U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); } } void CHD44780::writeM17Int(const char* source, const char* dest, const char* type) { assert(source != NULL); assert(dest != NULL); assert(type != NULL); #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_RED); #endif m_clockDisplayTimer.stop(); // Stop the clock display ::lcdClear(m_fd); if (m_pwm) { if (m_pwmPin != 1U) ::softPwmWrite(m_pwmPin, m_pwmBright); else ::pwmWrite(m_pwmPin, (m_pwmBright / 100) * 1024); } ::lcdPosition(m_fd, 0, 0); ::lcdPuts(m_fd, "M17"); ::sprintf(m_buffer1, "%.9s", source); ::sprintf(m_buffer2, "%.9s", dest); if (m_rows == 2U && m_cols == 16U) { ::lcdPosition(m_fd, 5, 0); ::lcdPrintf(m_fd, "%.*s", m_cols - 5, m_buffer1); ::lcdPosition(m_fd, 5, 1); ::lcdPrintf(m_fd, "%.*s", m_cols - 5, m_buffer2); } else if (m_rows == 4U && m_cols == 16U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer2); } else if (m_rows == 4U && m_cols == 20U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } else if (m_rows == 2 && m_cols == 40U) { ::sprintf(m_buffer1, "%.9s > %.9s", source, dest); ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); } m_dmr = false; m_rssiCount1 = 0U; } void CHD44780::writeM17RSSIInt(unsigned char rssi) { if (m_rssiCount1 == 0U && m_rows > 2) { ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "-%3udBm", rssi); } m_rssiCount1++; if (m_rssiCount1 >= M17_RSSI_COUNT) m_rssiCount1 = 0U; } void CHD44780::clearM17Int() { #ifdef ADAFRUIT_DISPLAY adafruitLCDColour(AC_PURPLE); #endif m_clockDisplayTimer.stop(); // Stop the clock display if (m_rows == 2U && m_cols == 16U) { ::lcdPosition(m_fd, 5, 0); ::lcdPrintf(m_fd, "%.*s", m_cols - 5, LISTENING); ::lcdPosition(m_fd, 5, 1); ::lcdPrintf(m_fd, "%.*s", m_cols - 5, " "); } else if (m_rows == 4U && m_cols == 16U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); } else if (m_rows == 4U && m_cols == 20U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); ::lcdPosition(m_fd, 0, 2); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); ::lcdPosition(m_fd, 0, 3); ::lcdPrintf(m_fd, "%.*s", m_cols, " "); } else if (m_rows == 2 && m_cols == 40U) { ::lcdPosition(m_fd, 0, 1); ::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING); } } void CHD44780::writePOCSAGInt(uint32_t ric, const std::string& message) { ::lcdPosition(m_fd, m_cols - 5, m_rows - 1); ::lcdPuts(m_fd, "POCSG"); // Shortened "POCSAG TX" to 5 characters because it wraps around onto the next line (or on 16x2 displays the 1st line). } void CHD44780::clearPOCSAGInt() { ::lcdPosition(m_fd, m_cols - 5, m_rows - 1); ::lcdPuts(m_fd, " Idle"); // Reverted back to 5 character implementation. } void CHD44780::writeCWInt() { ::lcdPosition(m_fd, m_cols - 5, m_rows - 1); ::lcdPuts(m_fd, "CW TX"); } void CHD44780::clearCWInt() { ::lcdPosition(m_fd, m_cols - 5, m_rows - 1); ::lcdPuts(m_fd, " Idle"); } void CHD44780::clockInt(unsigned int ms) { m_clockDisplayTimer.clock(ms); // 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); setlocale(LC_TIME,""); ::strftime(m_buffer1, 128, "%X", Time); // Time ::strftime(m_buffer2, 128, "%x", Time); // Date if (m_cols == 16U && m_rows == 2U) { ::lcdPosition(m_fd, m_cols - 10, 1); ::lcdPrintf(m_fd, "%s%.*s", strlen(m_buffer1) > 8 ? "" : " ", 10, m_buffer1); } else { ::lcdPosition(m_fd, (m_cols - (strlen(m_buffer1) == 8 ? 8 : 10)) / 2, m_rows == 2 ? 1 : 2); ::lcdPrintf(m_fd, "%.*s", strlen(m_buffer1) == 8 ? 8 : 10, m_buffer1); ::lcdPosition(m_fd, (m_cols - strlen(m_buffer2)) / 2, m_rows == 2 ? 0 : 1); ::lcdPrintf(m_fd, "%s", m_buffer2); } m_clockDisplayTimer.start(); } } void CHD44780::close() { }