/* * Copyright (C) 2016,2017,2018 by Tony Corbett G0WFV * Copyright (C) 2018,2020 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. */ /* * Some LCD displays include additional LEDs for status. * If they exist, the LDCproc server will use the output command. * If the LEDs do not exist, the command is ignored. * to control these LEDs Below are the values for the Crystalfontz CFA-635. * N4IRS * LED 1 (DMR) * Green 1 0000 0001 * Red 16 0001 0000 * Yellow 17 0001 0001 * LED 2 (P25) * Green 2 0000 0010 * Red 32 0010 0000 * Yellow 34 0010 0010 * LED 3 (Fusion) * Green 4 0000 0100 * Red 64 0100 0000 * Yellow 68 1000 0100 * LED 4 (D-Star) * Green 8 0000 1000 * Red 128 1000 0000 * Yellow 136 1000 1000 * LED 5 (NXDN) * Green 16 0001 0000 * Red 255 1111 1111 * Yellow 255 1111 1111 */ #include "LCDproc.h" #include "Log.h" #include #include #include #include #include #include #if !defined(_WIN32) && !defined(_WIN64) #include #include #include #include #include #include #include #include #include #else #include #endif #define BUFFER_MAX_LEN 128 int m_socketfd; char m_buffer[BUFFER_MAX_LEN]; fd_set m_readfds, m_writefds; struct timeval m_timeout; int m_recvsize; unsigned int m_rows(0); unsigned int m_cols(0); bool m_screensDefined(false); bool m_connected(false); char m_displayBuffer1[BUFFER_MAX_LEN]; char m_displayBuffer2[BUFFER_MAX_LEN]; 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 CLCDproc::CLCDproc(std::string address, unsigned int port, unsigned short localPort, const std::string& callsign, unsigned int dmrid, bool displayClock, bool utc, bool duplex, bool dimOnIdle) : CDisplay(), m_address(address), m_port(port), m_localPort(localPort), m_callsign(callsign), m_dmrid(dmrid), m_displayClock(displayClock), m_utc(utc), m_duplex(duplex), //m_duplex(true), // uncomment to force duplex display for testing! m_dimOnIdle(dimOnIdle), m_dmr(false), m_clockDisplayTimer(1000U, 0U, 250U), // Update the clock display every 250ms m_rssiCount1(0U), m_rssiCount2(0U) { } CLCDproc::~CLCDproc() { } bool CLCDproc::open() { int err; unsigned int addrlen; std::string port, localPort; struct sockaddr_storage serverAddress, clientAddress; struct addrinfo hints, *res; port = std::to_string(m_port); localPort = std::to_string(m_localPort); memset(&hints, 0, sizeof(hints)); /* Lookup the hostname address */ hints.ai_flags = AI_NUMERICSERV; hints.ai_socktype = SOCK_STREAM; err = getaddrinfo(m_address.c_str(), port.c_str(), &hints, &res); if (err) { LogError("LCDproc, cannot lookup server"); return false; } memcpy(&serverAddress, res->ai_addr, addrlen = res->ai_addrlen); freeaddrinfo(res); /* Lookup the client address (random port - need to specify manual port from ini file) */ hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE; hints.ai_family = serverAddress.ss_family; err = getaddrinfo(NULL, localPort.c_str(), &hints, &res); if (err) { LogError("LCDproc, cannot lookup client"); return false; } memcpy(&clientAddress, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); /* Create TCP socket */ m_socketfd = socket(clientAddress.ss_family, SOCK_STREAM, 0); if (m_socketfd == -1) { LogError("LCDproc, failed to create socket"); return false; } /* Bind the address to the socket */ if (bind(m_socketfd, (struct sockaddr *)&clientAddress, addrlen) == -1) { LogError("LCDproc, error whilst binding address"); return false; } /* Connect to server */ if (connect(m_socketfd, (struct sockaddr *)&serverAddress, addrlen) == -1) { LogError("LCDproc, cannot connect to server"); return false; } socketPrintf(m_socketfd, "hello"); // Login to the LCD server socketPrintf(m_socketfd, "output 0"); // Clear all LEDs return true; } void CLCDproc::setIdleInt() { m_clockDisplayTimer.start(); // Start the clock display in IDLE only if (m_screensDefined) { socketPrintf(m_socketfd, "screen_set DStar -priority hidden"); socketPrintf(m_socketfd, "screen_set DMR -priority hidden"); socketPrintf(m_socketfd, "screen_set YSF -priority hidden"); socketPrintf(m_socketfd, "screen_set P25 -priority hidden"); socketPrintf(m_socketfd, "screen_set NXDN -priority hidden"); socketPrintf(m_socketfd, "screen_set M17 -priority hidden"); socketPrintf(m_socketfd, "widget_set Status Status %u %u Idle", m_cols - 3, m_rows); socketPrintf(m_socketfd, "output 0"); // Clear all LEDs } m_dmr = false; } void CLCDproc::setErrorInt(const char* text) { assert(text != NULL); m_clockDisplayTimer.stop(); // Stop the clock display if (m_screensDefined) { socketPrintf(m_socketfd, "screen_set DStar -priority hidden"); socketPrintf(m_socketfd, "screen_set DMR -priority hidden"); socketPrintf(m_socketfd, "screen_set YSF -priority hidden"); socketPrintf(m_socketfd, "screen_set P25 -priority hidden"); socketPrintf(m_socketfd, "screen_set NXDN -priority hidden"); socketPrintf(m_socketfd, "screen_set M17 -priority hidden"); socketPrintf(m_socketfd, "widget_set Status Status %u %u Error", m_cols - 4, m_rows); socketPrintf(m_socketfd, "output 0"); // Clear all LEDs } m_dmr = false; } void CLCDproc::setLockoutInt() { m_clockDisplayTimer.stop(); // Stop the clock display if (m_screensDefined) { socketPrintf(m_socketfd, "screen_set DStar -priority hidden"); socketPrintf(m_socketfd, "screen_set DMR -priority hidden"); socketPrintf(m_socketfd, "screen_set YSF -priority hidden"); socketPrintf(m_socketfd, "screen_set P25 -priority hidden"); socketPrintf(m_socketfd, "screen_set NXDN -priority hidden"); socketPrintf(m_socketfd, "screen_set M17 -priority hidden"); socketPrintf(m_socketfd, "widget_set Status Status %u %u Lockout", m_cols - 6, m_rows); socketPrintf(m_socketfd, "output 0"); // Clear all LEDs } m_dmr = false; } // LED 4 Green 8 Red 128 Yellow 136 void CLCDproc::setQuitInt() { m_clockDisplayTimer.stop(); // Stop the clock display if (m_screensDefined) { socketPrintf(m_socketfd, "screen_set DStar -priority hidden"); socketPrintf(m_socketfd, "screen_set DMR -priority hidden"); socketPrintf(m_socketfd, "screen_set YSF -priority hidden"); socketPrintf(m_socketfd, "screen_set P25 -priority hidden"); socketPrintf(m_socketfd, "screen_set NXDN -priority hidden"); socketPrintf(m_socketfd, "screen_set M17 -priority hidden"); socketPrintf(m_socketfd, "widget_set Status Status %u %u Stopped", m_cols - 6, m_rows); socketPrintf(m_socketfd, "output 0"); // Clear all LEDs } m_dmr = false; } void CLCDproc::setFMInt() { m_clockDisplayTimer.stop(); // Stop the clock display if (m_screensDefined) { socketPrintf(m_socketfd, "screen_set DStar -priority hidden"); socketPrintf(m_socketfd, "screen_set DMR -priority hidden"); socketPrintf(m_socketfd, "screen_set YSF -priority hidden"); socketPrintf(m_socketfd, "screen_set P25 -priority hidden"); socketPrintf(m_socketfd, "screen_set NXDN -priority hidden"); socketPrintf(m_socketfd, "screen_set M17 -priority hidden"); socketPrintf(m_socketfd, "widget_set Status Status %u %u FM", m_cols - 6, m_rows); socketPrintf(m_socketfd, "output 0"); // Clear all LEDs } m_dmr = false; } void CLCDproc::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); m_clockDisplayTimer.stop(); // Stop the clock display socketPrintf(m_socketfd, "screen_set DStar -priority foreground"); socketPrintf(m_socketfd, "widget_set DStar Mode 1 1 \"D-Star\""); ::sprintf(m_displayBuffer1, "%.8s", your); char *p = m_displayBuffer1; for (; *p; ++p) { if (*p == ' ') *p = '_'; } if (strcmp(reflector, " ") != 0) sprintf(m_displayBuffer2, " via %.8s", reflector); else memset(m_displayBuffer2, 0, BUFFER_MAX_LEN); if (m_rows == 2U) { socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 %u 2 h 3 \"%.8s/%.4s to %s%s\"", m_cols - 1, my1, my2, m_displayBuffer1, m_displayBuffer2); } else { socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 %u 2 h 3 \"%.8s/%.4s\"", m_cols - 1, my1, my2); socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 %u 3 h 3 \"%s%s\"", m_cols - 1, m_displayBuffer1, m_displayBuffer2); socketPrintf(m_socketfd, "output 128"); // Set LED4 color red } m_dmr = false; m_rssiCount1 = 0U; } void CLCDproc::writeDStarRSSIInt(unsigned char rssi) { if (m_rssiCount1 == 0U) { socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi); } m_rssiCount1++; if (m_rssiCount1 >= DSTAR_RSSI_COUNT) m_rssiCount1 = 0U; } void CLCDproc::clearDStarInt() { m_clockDisplayTimer.stop(); // Stop the clock display socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "output 8"); // Set LED4 color green } // LED 1 Green 1 Red 16 Yellow 17 void CLCDproc::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 socketPrintf(m_socketfd, "screen_set DMR -priority foreground"); if (m_duplex) { if (m_rows > 2U) socketPrintf(m_socketfd, "widget_set DMR Mode 1 1 DMR"); if (slotNo == 1U) socketPrintf(m_socketfd, "widget_set DMR Slot2 3 %u %u %u h 3 \"Listening\"", m_rows / 2 + 1, m_cols - 1, m_rows / 2 + 1); else socketPrintf(m_socketfd, "widget_set DMR Slot1 3 %u %u %u h 3 \"Listening\"", m_rows / 2, m_cols - 1, m_rows / 2); } else { socketPrintf(m_socketfd, "widget_set DMR Slot1_ 1 %u \"\"", m_rows / 2); socketPrintf(m_socketfd, "widget_set DMR Slot2_ 1 %u \"\"", m_rows / 2 + 1); socketPrintf(m_socketfd, "widget_set DMR Slot1 1 %u %u %u h 3 \"Listening\"", m_rows / 2, m_cols - 1, m_rows / 2); socketPrintf(m_socketfd, "widget_set DMR Slot2 1 %u %u %u h 3 \"\"", m_rows / 2 + 1, m_cols - 1, m_rows / 2 + 1); } } if (m_duplex) { if (m_rows > 2U) socketPrintf(m_socketfd, "widget_set DMR Mode 1 1 DMR"); if (slotNo == 1U) socketPrintf(m_socketfd, "widget_set DMR Slot1 3 %u %u %u h 3 \"%s > %s%s\"", m_rows / 2, m_cols - 1, m_rows / 2, src.c_str(), group ? "TG" : "", dst.c_str()); else socketPrintf(m_socketfd, "widget_set DMR Slot2 3 %u %u %u h 3 \"%s > %s%s\"", m_rows / 2 + 1, m_cols - 1, m_rows / 2 + 1, src.c_str(), group ? "TG" : "", dst.c_str()); } else { socketPrintf(m_socketfd, "widget_set DMR Mode 1 1 DMR"); if (m_rows == 2U) { socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 %u 2 h 3 \"%s > %s%s\"", m_cols - 1, src.c_str(), group ? "TG" : "", dst.c_str()); } else { socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 %u 2 h 3 \"%s >\"", m_cols - 1, src.c_str()); socketPrintf(m_socketfd, "widget_set DMR Slot2 1 3 %u 3 h 3 \"%s%s\"", m_cols - 1, group ? "TG" : "", dst.c_str()); } } socketPrintf(m_socketfd, "output 16"); // Set LED1 color red m_dmr = true; m_rssiCount1 = 0U; m_rssiCount2 = 0U; } void CLCDproc::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi) { if (m_rows > 2) { if (slotNo == 1U) { if (m_rssiCount1 == 0U) socketPrintf(m_socketfd, "widget_set DMR Slot1RSSI %u %u -%3udBm", 1, 4, rssi); m_rssiCount1++; if (m_rssiCount1 >= DMR_RSSI_COUNT) m_rssiCount1 = 0U; } else { if (m_rssiCount2 == 0U) socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u -%3udBm", (m_cols / 2) + 1, 4, rssi); m_rssiCount2++; if (m_rssiCount2 >= DMR_RSSI_COUNT) m_rssiCount2 = 0U; } } } void CLCDproc::clearDMRInt(unsigned int slotNo) { m_clockDisplayTimer.stop(); // Stop the clock display if (m_duplex) { if (slotNo == 1U) { socketPrintf(m_socketfd, "widget_set DMR Slot1 3 %u %u %u h 3 \"Listening\"", m_rows / 2, m_cols - 1, m_rows / 2); socketPrintf(m_socketfd, "widget_set DMR Slot1RSSI %u %u %*.s", 1, 4, m_cols / 2, " "); } else { socketPrintf(m_socketfd, "widget_set DMR Slot2 3 %u %u %u h 3 \"Listening\"", m_rows / 2 + 1, m_cols - 1, m_rows / 2 + 1); socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " "); } } else { socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set DMR Slot2 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " "); } socketPrintf(m_socketfd, "output 1"); // Set LED1 color green } // LED 3 Green 4 Red 64 Yellow 68 void CLCDproc::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); m_clockDisplayTimer.stop(); // Stop the clock display socketPrintf(m_socketfd, "screen_set YSF -priority foreground"); socketPrintf(m_socketfd, "widget_set YSF Mode 1 1 \"System Fusion\""); if (m_rows == 2U) { socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"%.10s > DG-ID %u\"", source, dgid); } else { socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"%.10s >\"", source); socketPrintf(m_socketfd, "widget_set YSF Line3 1 3 15 3 h 3 \"DG-ID %u\"", dgid); socketPrintf(m_socketfd, "output 64"); // Set LED3 color red } m_dmr = false; m_rssiCount1 = 0U; } void CLCDproc::writeFusionRSSIInt(unsigned char rssi) { if (m_rssiCount1 == 0U) socketPrintf(m_socketfd, "widget_set YSF Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi); m_rssiCount1++; if (m_rssiCount1 >= YSF_RSSI_COUNT) m_rssiCount1 = 0U; } void CLCDproc::clearFusionInt() { m_clockDisplayTimer.stop(); // Stop the clock display socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set YSF Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set YSF Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "output 4"); // Set LED3 color green } // LED 2 Green 2 Red 32 Yellow 34 void CLCDproc::writeP25Int(const char* source, bool group, unsigned int dest, const char* type) { assert(source != NULL); assert(type != NULL); m_clockDisplayTimer.stop(); // Stop the clock display socketPrintf(m_socketfd, "screen_set P25 -priority foreground"); socketPrintf(m_socketfd, "widget_set P25 Mode 1 1 P25"); if (m_rows == 2U) { socketPrintf(m_socketfd, "widget_set P25 Line2 1 2 15 2 h 3 \"%.10s > %s%u\"", source, group ? "TG" : "", dest); } else { socketPrintf(m_socketfd, "widget_set P25 Line2 1 2 15 2 h 3 \"%.10s >\"", source); socketPrintf(m_socketfd, "widget_set P25 Line3 1 3 15 3 h 3 \"%s%u\"", group ? "TG" : "", dest); socketPrintf(m_socketfd, "output 32"); // Set LED2 color red } m_dmr = false; m_rssiCount1 = 0U; } void CLCDproc::writeP25RSSIInt(unsigned char rssi) { if (m_rssiCount1 == 0U) { socketPrintf(m_socketfd, "widget_set P25 Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi); } m_rssiCount1++; if (m_rssiCount1 >= P25_RSSI_COUNT) m_rssiCount1 = 0U; } void CLCDproc::clearP25Int() { m_clockDisplayTimer.stop(); // Stop the clock display socketPrintf(m_socketfd, "widget_set P25 Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set P25 Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set P25 Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "output 2"); // Set LED2 color green } // LED 5 Green 16 Red 255 Yellow 255 void CLCDproc::writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type) { assert(source != NULL); assert(type != NULL); m_clockDisplayTimer.stop(); // Stop the clock display socketPrintf(m_socketfd, "screen_set NXDN -priority foreground"); socketPrintf(m_socketfd, "widget_set NXDN Mode 1 1 NXDN"); if (m_rows == 2U) { socketPrintf(m_socketfd, "widget_set NXDN Line2 1 2 15 2 h 3 \"%.10s > %s%u\"", source, group ? "TG" : "", dest); } else { socketPrintf(m_socketfd, "widget_set NXDN Line2 1 2 15 2 h 3 \"%.10s >\"", source); socketPrintf(m_socketfd, "widget_set NXDN Line3 1 3 15 3 h 3 \"%s%u\"", group ? "TG" : "", dest); socketPrintf(m_socketfd, "output 255"); // Set LED5 color red } m_dmr = false; m_rssiCount1 = 0U; } void CLCDproc::writeNXDNRSSIInt(unsigned char rssi) { if (m_rssiCount1 == 0U) { socketPrintf(m_socketfd, "widget_set NXDN Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi); } m_rssiCount1++; if (m_rssiCount1 >= NXDN_RSSI_COUNT) m_rssiCount1 = 0U; } void CLCDproc::clearNXDNInt() { m_clockDisplayTimer.stop(); // Stop the clock display socketPrintf(m_socketfd, "widget_set NXDN Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set NXDN Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set NXDN Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "output 16"); // Set LED5 color green } void CLCDproc::writeM17Int(const char* source, const char* dest, const char* type) { assert(source != NULL); assert(dest != NULL); assert(type != NULL); m_clockDisplayTimer.stop(); // Stop the clock display socketPrintf(m_socketfd, "screen_set M17 -priority foreground"); socketPrintf(m_socketfd, "widget_set M17 Mode 1 1 M17"); if (m_rows == 2U) { socketPrintf(m_socketfd, "widget_set M17 Line2 1 2 15 2 h 3 \"%.9s > %.9s\"", source, dest); } else { socketPrintf(m_socketfd, "widget_set M17 Line2 1 2 15 2 h 3 \"%.9s >\"", source); socketPrintf(m_socketfd, "widget_set M17 Line3 1 3 15 3 h 3 \"%.9ss\"", dest); socketPrintf(m_socketfd, "output 255"); // Set LED5 color red } m_dmr = false; m_rssiCount1 = 0U; } void CLCDproc::writeM17RSSIInt(unsigned char rssi) { if (m_rssiCount1 == 0U) { socketPrintf(m_socketfd, "widget_set M17 Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi); } m_rssiCount1++; if (m_rssiCount1 >= M17_RSSI_COUNT) m_rssiCount1 = 0U; } void CLCDproc::clearM17Int() { m_clockDisplayTimer.stop(); // Stop the clock display socketPrintf(m_socketfd, "widget_set M17 Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set M17 Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set M17 Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "output 16"); // Set LED5 color green } void CLCDproc::writePOCSAGInt(uint32_t ric, const std::string& message) { } void CLCDproc::clearPOCSAGInt() { } void CLCDproc::writeCWInt() { } void CLCDproc::clearCWInt() { } void CLCDproc::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_displayBuffer1, 128, "%X", Time); // Time strftime(m_displayBuffer2, 128, "%x", Time); // Date if (m_cols < 26U && m_rows == 2U) { socketPrintf(m_socketfd, "widget_set Status Time %u 2 \"%s%s\"", m_cols - 9, strlen(m_displayBuffer1) > 8 ? "" : " ", m_displayBuffer1); } else { socketPrintf(m_socketfd, "widget_set Status Time %u %u \"%s\"", (m_cols - (strlen(m_displayBuffer1) == 8 ? 6 : 8)) / 2, m_rows / 2, m_displayBuffer1); socketPrintf(m_socketfd, "widget_set Status Date %u %u \"%s\"", (m_cols - (strlen(m_displayBuffer1) == 8 ? 6 : 8)) / 2, m_rows / 2 + 1, m_displayBuffer2); } m_clockDisplayTimer.start(); } // We must set all this information on each select we do FD_ZERO(&m_readfds); // empty readfds // Then we put all the descriptors we want to wait for in a mask = m_readfds FD_SET(m_socketfd, &m_readfds); // Timeout, we will stop waiting for information m_timeout.tv_sec = 0; m_timeout.tv_usec = 0; /* The first parameter is the biggest descriptor + 1. The first one was 0, so * every other descriptor will be bigger * * readfds = &m_readfds * writefds = we are not waiting for writefds * exceptfds = we are not waiting for exception fds */ if (select(m_socketfd + 1, &m_readfds, NULL, NULL, &m_timeout) == -1) LogError("LCDproc, error on select"); // If something was received from the server... if (FD_ISSET(m_socketfd, &m_readfds)) { m_recvsize = recv(m_socketfd, m_buffer, BUFFER_MAX_LEN, 0); if (m_recvsize == -1) LogError("LCDproc, cannot receive information"); m_buffer[m_recvsize] = '\0'; char *argv[256]; size_t len = strlen(m_buffer); // Now split the string into tokens... int argc = 0; int newtoken = 1; for (size_t i = 0U; i < len; i++) { switch (m_buffer[i]) { case ' ': newtoken = 1; m_buffer[i] = 0; break; default: /* regular chars, keep tokenizing */ if (newtoken) argv[argc++] = m_buffer + i; newtoken = 0; break; case '\0': case '\n': m_buffer[i] = 0; if (argc > 0) { if (0 == strcmp(argv[0], "listen")) { LogDebug("LCDproc, the %s screen is displayed", argv[1]); } else if (0 == strcmp(argv[0], "ignore")) { LogDebug("LCDproc, the %s screen is hidden", argv[1]); } else if (0 == strcmp(argv[0], "key")) { LogDebug("LCDproc, Key %s", argv[1]); } else if (0 == strcmp(argv[0], "menu")) { } else if (0 == strcmp(argv[0], "connect")) { // connect LCDproc 0.5.7 protocol 0.3 lcd wid 16 hgt 2 cellwid 5 cellhgt 8 int a; for (a = 1; a < argc; a++) { if (0 == strcmp(argv[a], "wid")) m_cols = atoi(argv[++a]); else if (0 == strcmp(argv[a], "hgt")) m_rows = atoi(argv[++a]); else if (0 == strcmp(argv[a], "cellwid")) { //lcd_cellwid = atoi(argv[++a]); } else if (0 == strcmp(argv[a], "cellhgt")) { //lcd_cellhgt = atoi(argv[++a]); } } m_connected = true; socketPrintf(m_socketfd, "client_set -name MMDVMHost"); } else if (0 == strcmp(argv[0], "bye")) { //close the socket- todo } else if (0 == strcmp(argv[0], "success")) { //LogDebug("LCDproc, command successful"); } else if (0 == strcmp(argv[0], "huh?")) { sprintf(m_displayBuffer1, "LCDproc, command failed:"); sprintf(m_displayBuffer2, " "); int j; for (j = 1; j < argc; j++) { strcat(m_displayBuffer1, m_displayBuffer2); strcat(m_displayBuffer1, argv[j]); } LogDebug("%s", m_displayBuffer1); } } /* Restart tokenizing */ argc = 0; newtoken = 1; break; } /* switch( m_buffer[i] ) */ } } if (!m_screensDefined && m_connected) defineScreens(); } void CLCDproc::close() { } int CLCDproc::socketPrintf(int fd, const char *format, ...) { char buf[BUFFER_MAX_LEN]; va_list ap; va_start(ap, format); int size = vsnprintf(buf, BUFFER_MAX_LEN, format, ap); va_end(ap); if (size < 0) { LogError("LCDproc, socketPrintf: vsnprintf failed"); return -1; } if (size > BUFFER_MAX_LEN) LogWarning("LCDproc, socketPrintf: vsnprintf truncated message"); FD_ZERO(&m_writefds); // empty writefds FD_SET(m_socketfd, &m_writefds); m_timeout.tv_sec = 0; m_timeout.tv_usec = 0; if (select(m_socketfd + 1, NULL, &m_writefds, NULL, &m_timeout) == -1) LogError("LCDproc, error on select"); if (FD_ISSET(m_socketfd, &m_writefds)) { if (send(m_socketfd, buf, int(strlen(buf) + 1U), 0) == -1) { LogError("LCDproc, cannot send data"); return -1; } } return 0; } void CLCDproc::defineScreens() { // The Status Screen socketPrintf(m_socketfd, "screen_add Status"); socketPrintf(m_socketfd, "screen_set Status -name Status -heartbeat on -priority info -backlight %s", m_dimOnIdle ? "off" : "on"); socketPrintf(m_socketfd, "widget_add Status Callsign string"); socketPrintf(m_socketfd, "widget_add Status DMRNumber string"); socketPrintf(m_socketfd, "widget_add Status Title string"); socketPrintf(m_socketfd, "widget_add Status Status string"); socketPrintf(m_socketfd, "widget_add Status Time string"); socketPrintf(m_socketfd, "widget_add Status Date string"); socketPrintf(m_socketfd, "widget_set Status Callsign 1 1 %s", m_callsign.c_str()); socketPrintf(m_socketfd, "widget_set Status DMRNumber %u 1 %u", m_cols - 7, m_dmrid); socketPrintf(m_socketfd, "widget_set Status Title 1 %u MMDVM", m_rows); socketPrintf(m_socketfd, "widget_set Status Status %u %u Idle", m_cols - 3, m_rows); // The DStar Screen socketPrintf(m_socketfd, "screen_add DStar"); socketPrintf(m_socketfd, "screen_set DStar -name DStar -heartbeat on -priority hidden -backlight on"); socketPrintf(m_socketfd, "widget_add DStar Mode string"); socketPrintf(m_socketfd, "widget_add DStar Line2 scroller"); socketPrintf(m_socketfd, "widget_add DStar Line3 scroller"); socketPrintf(m_socketfd, "widget_add DStar Line4 scroller"); /* Do we need to pre-populate the values?? socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\""); */ // The DMR Screen socketPrintf(m_socketfd, "screen_add DMR"); socketPrintf(m_socketfd, "screen_set DMR -name DMR -heartbeat on -priority hidden -backlight on"); socketPrintf(m_socketfd, "widget_add DMR Mode string"); socketPrintf(m_socketfd, "widget_add DMR Slot1_ string"); socketPrintf(m_socketfd, "widget_add DMR Slot2_ string"); socketPrintf(m_socketfd, "widget_add DMR Slot1 scroller"); socketPrintf(m_socketfd, "widget_add DMR Slot2 scroller"); socketPrintf(m_socketfd, "widget_add DMR Slot1RSSI string"); socketPrintf(m_socketfd, "widget_add DMR Slot2RSSI string"); /* Do we need to pre-populate the values?? socketPrintf(m_socketfd, "widget_set DMR Slot1_ 1 %u 1", m_rows / 2); socketPrintf(m_socketfd, "widget_set DMR Slot2_ 1 %u 2", m_rows / 2 + 1); socketPrintf(m_socketfd, "widget_set DMR Slot1 3 1 15 1 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set DMR Slot2 3 2 15 2 h 3 \"Listening\""); */ // The YSF Screen socketPrintf(m_socketfd, "screen_add YSF"); socketPrintf(m_socketfd, "screen_set YSF -name YSF -heartbeat on -priority hidden -backlight on"); socketPrintf(m_socketfd, "widget_add YSF Mode string"); socketPrintf(m_socketfd, "widget_add YSF Line2 scroller"); socketPrintf(m_socketfd, "widget_add YSF Line3 scroller"); socketPrintf(m_socketfd, "widget_add YSF Line4 scroller"); /* Do we need to pre-populate the values?? socketPrintf(m_socketfd, "widget_set YSF Line2 2 1 15 1 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set YSF Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set YSF Line4 4 2 15 2 h 3 \" \""); */ // The P25 Screen socketPrintf(m_socketfd, "screen_add P25"); socketPrintf(m_socketfd, "screen_set P25 -name P25 -heartbeat on -priority hidden -backlight on"); socketPrintf(m_socketfd, "widget_add P25 Mode string"); socketPrintf(m_socketfd, "widget_add P25 Line2 scroller"); socketPrintf(m_socketfd, "widget_add P25 Line3 scroller"); socketPrintf(m_socketfd, "widget_add P25 Line4 scroller"); /* Do we need to pre-populate the values?? socketPrintf(m_socketfd, "widget_set P25 Line3 2 1 15 1 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set P25 Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set P25 Line4 4 2 15 2 h 3 \" \""); */ // The NXDN Screen socketPrintf(m_socketfd, "screen_add NXDN"); socketPrintf(m_socketfd, "screen_set NXDN -name NXDN -heartbeat on -priority hidden -backlight on"); socketPrintf(m_socketfd, "widget_add NXDN Mode string"); socketPrintf(m_socketfd, "widget_add NXDN Line2 scroller"); socketPrintf(m_socketfd, "widget_add NXDN Line3 scroller"); socketPrintf(m_socketfd, "widget_add NXDN Line4 scroller"); /* Do we need to pre-populate the values?? socketPrintf(m_socketfd, "widget_set NXDN Line3 2 1 15 1 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set NXDN Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set NXDN Line4 4 2 15 2 h 3 \" \""); */ // The M17 Screen socketPrintf(m_socketfd, "screen_add M17"); socketPrintf(m_socketfd, "screen_set M17 -name M17 -heartbeat on -priority hidden -backlight on"); socketPrintf(m_socketfd, "widget_add M17 Mode string"); socketPrintf(m_socketfd, "widget_add M17 Line2 scroller"); socketPrintf(m_socketfd, "widget_add M17 Line3 scroller"); socketPrintf(m_socketfd, "widget_add M17 Line4 scroller"); /* Do we need to pre-populate the values?? socketPrintf(m_socketfd, "widget_set M17 Line3 2 1 15 1 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set M17 Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set M17 Line4 4 2 15 2 h 3 \" \""); */ m_screensDefined = true; }