From c1bb142e18a30f83c4d518aae7303e58a6ac72d8 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 1 Jun 2019 13:00:02 -0600 Subject: [PATCH] Squashed commit of the following: apps/graphics/tmw4nx and apps/graphics/slcd: This seems the last of the show stopper bugs. All seems functional. apps/graphics/slcd: Correct some errors found in early texting. Now the Twm4Nx::CClock window comes up, but there are problems with the way that the segments are being displayed. apps/graphicx/twm4nx: CClock is complete and compiles correctly. Crashes with a hardware when the clock is selected from the Main Menu, however. --- graphics/slcd/cslcd.cxx | 17 +- graphics/slcd/slcd.hxx | 7 - graphics/twm4nx/Makefile | 4 + graphics/twm4nx/apps/Kconfig | 21 + graphics/twm4nx/apps/ccalibration.cxx | 30 +- graphics/twm4nx/apps/cclock.cxx | 658 ++++++++++++++++++ graphics/twm4nx/apps/cnxterm.cxx | 92 ++- graphics/twm4nx/src/cresize.cxx | 10 +- graphics/twm4nx/src/twm4nx_main.cxx | 11 + include/graphics/slcd.hxx | 9 + include/graphics/twm4nx/apps/cclock.hxx | 291 ++++++++ include/graphics/twm4nx/apps/clock_config.hxx | 135 ++++ include/graphics/twm4nx/apps/cnxterm.hxx | 18 +- include/graphics/twm4nx/cwindow.hxx | 13 + 14 files changed, 1225 insertions(+), 91 deletions(-) create mode 100644 graphics/twm4nx/apps/cclock.cxx create mode 100644 include/graphics/twm4nx/apps/cclock.hxx create mode 100644 include/graphics/twm4nx/apps/clock_config.hxx diff --git a/graphics/slcd/cslcd.cxx b/graphics/slcd/cslcd.cxx index 2b2f3eb9d..4960ff5ed 100644 --- a/graphics/slcd/cslcd.cxx +++ b/graphics/slcd/cslcd.cxx @@ -85,6 +85,10 @@ CSLcd::CSLcd(NXWidgets::INxWindow *wnd, nxgl_coord_t height) void CSLcd::scale(nxgl_coord_t height) { + // Save the new height + + m_height = height; + // Scale each segment scaleSegment(GTop_Runs, m_top, NTOP_TRAPEZOIDS + 1); @@ -92,8 +96,8 @@ void CSLcd::scale(nxgl_coord_t height) scaleSegment(GTopRight_Runs, m_topRight, NTOPRIGHT_TRAPEZOIDS + 1); scaleSegment(GMiddle_Runs, m_middle, NMIDDLE_TRAPEZOIDS + 1); scaleSegment(GBottomLeft_Runs, m_bottomLeft, NBOTTOMLEFT_TRAPEZOIDS + 1); - scaleSegment(GBottomRight_Runs, m_bottom, NBOTTOMRIGHT_TRAPEZOIDS + 1); - scaleSegment(GBottom_Runs, m_top, NBOTTOM_TRAPEZOIDS + 1); + scaleSegment(GBottomRight_Runs, m_bottomRight, NBOTTOMRIGHT_TRAPEZOIDS + 1); + scaleSegment(GBottom_Runs, m_bottom, NBOTTOM_TRAPEZOIDS + 1); } /** @@ -209,12 +213,12 @@ bool CSLcd::show(uint8_t code, FAR const struct nxgl_point_s &pos) if ((code & SEGMENT_6) != 0) { - showSegment(m_bottom, pos, NBOTTOMRIGHT_TRAPEZOIDS); + showSegment(m_bottomRight, pos, NBOTTOMRIGHT_TRAPEZOIDS); } if ((code & SEGMENT_7) != 0) { - showSegment(m_top, pos, NBOTTOM_TRAPEZOIDS); + showSegment(m_bottom, pos, NBOTTOM_TRAPEZOIDS); } return true; @@ -240,7 +244,8 @@ void CSLcd::scaleSegment(FAR const struct SLcdTrapezoidRun *run, trapezoid[0].top.x2 = m_height * run[0].rightx; trapezoid[0].top.y = b16toi(m_height * run[0].y); - for (int i = 1; i <= nRuns; i++) + int nTraps = nRuns - 1; + for (int i = 1; i < nRuns; i++) { // Get the bottom of the previous trapezoid @@ -248,7 +253,7 @@ void CSLcd::scaleSegment(FAR const struct SLcdTrapezoidRun *run, trapezoid[i - 1].bot.x2 = m_height * run[i].rightx; trapezoid[i - 1].bot.y = b16toi(m_height * run[i].y); - if (i < nRuns) + if (i < nTraps) { // Get the top of the current trapezoid diff --git a/graphics/slcd/slcd.hxx b/graphics/slcd/slcd.hxx index b8726452c..58215da2f 100644 --- a/graphics/slcd/slcd.hxx +++ b/graphics/slcd/slcd.hxx @@ -43,19 +43,12 @@ #include #include -#include "graphics/nxwidgets/nxconfig.hxx" #include "graphics/slcd.hxx" ///////////////////////////////////////////////////////////////////////////// // Pre-processor definitions ///////////////////////////////////////////////////////////////////////////// -// Default colors: Light grey-green background, greenish-black foreground. -// Similar to what you would see on a classic LCD. - -#define SLCD_BACKGROUND MKRGB(128, 140, 128) -#define SLCD_FOREGROUND MKRGB(0, 16, 0) - // Segment encoding: // // 11111111 diff --git a/graphics/twm4nx/Makefile b/graphics/twm4nx/Makefile index 6db8949ee..6e3c5aa60 100644 --- a/graphics/twm4nx/Makefile +++ b/graphics/twm4nx/Makefile @@ -68,6 +68,10 @@ ifeq ($(CONFIG_TWM4NX_CALIBRATION),y) CXXSRCS += ccalibration.cxx endif +ifeq ($(CONFIG_TWM4NX_CLOCK),y) +CXXSRCS += cclock.cxx +endif + ifeq ($(CONFIG_TWM4NX_NXTERM),y) CXXSRCS += cnxterm.cxx endif diff --git a/graphics/twm4nx/apps/Kconfig b/graphics/twm4nx/apps/Kconfig index 738a31758..3251e5a82 100644 --- a/graphics/twm4nx/apps/Kconfig +++ b/graphics/twm4nx/apps/Kconfig @@ -32,3 +32,24 @@ config TWM4NX_NXTERM ---help--- Enable support for the NxTerm window which provides a text window in which you can interact with NSH. + +if TWM4NX_NXTERM +endif # TWM4NX_NXTERM + +config TWM4NX_CLOCK + bool "Retro segment LCD clock" + default y + select GRAPHICS_SLCD + ---help--- + Enable support for the LCD clock window based on the retro segment + LCD driver of apps/graphics/slcd. + +if TWM4NX_CLOCK + +config TWM4NX_CLOCK_HEIGHT + int "LCD clock height" + default 64 + ---help--- + Fixed height of the LCD clock. The clock window is not re-sizeable. + +endif # TWM4NX_CLOCK diff --git a/graphics/twm4nx/apps/ccalibration.cxx b/graphics/twm4nx/apps/ccalibration.cxx index 4db22511e..f84857d43 100644 --- a/graphics/twm4nx/apps/ccalibration.cxx +++ b/graphics/twm4nx/apps/ccalibration.cxx @@ -195,7 +195,7 @@ bool CCalibration::initialize(void) m_nxWin = m_twm4nx->createRawWindow(control, wflags); if (m_nxWin == (FAR NXWidgets::CNxWindow *)0) { - gerr("ERROR: Failed open raw window\n"); + twmerr("ERROR: Failed open raw window\n"); delete control; return false; } @@ -242,7 +242,7 @@ bool CCalibration::initialize(void) if (!createWidgets()) { - gerr("ERROR: failed to create widgets\n"); + twmerr("ERROR: failed to create widgets\n"); return (FAR void *)0; } #endif @@ -268,7 +268,7 @@ bool CCalibration::run(void) if (m_calthread == CALTHREAD_RUNNING) { - gwarn("WARNING: The calibration thread is already running\n"); + twmwarn("WARNING: The calibration thread is already running\n"); return false; } @@ -292,11 +292,11 @@ bool CCalibration::run(void) int ret = pthread_create(&m_thread, &attr, calibration, (FAR void *)this); if (ret != 0) { - gerr("ERROR: pthread_create failed: %d\n", ret); + twmerr("ERROR: pthread_create failed: %d\n", ret); return false; } - ginfo("Calibration thread m_calthread=%d\n", (int)m_calthread); + twminfo("Calibration thread m_calthread=%d\n", (int)m_calthread); return true; } @@ -426,7 +426,7 @@ bool CCalibration::createWidgets(void) CONFIG_TWM4NX_DEFAULT_FONTCOLOR, CONFIG_TWM4NX_TRANSPARENT_COLOR); if (!m_font) { - gerr("ERROR failed to create font\n"); + twmerr("ERROR failed to create font\n"); return false; } @@ -435,7 +435,7 @@ bool CCalibration::createWidgets(void) struct nxgl_size_s windowSize; if (!m_nxWin->getSize(&windowSize)) { - gerr("ERROR: Failed to get window size\n"); + twmerr("ERROR: Failed to get window size\n"); delete m_font; m_font = (NXWidgets::CNxFont *)0; return false; @@ -474,7 +474,7 @@ bool CCalibration::createWidgets(void) if (!m_text) { - gerr("ERROR: Failed to create CLabel\n"); + twmerr("ERROR: Failed to create CLabel\n"); delete m_font; m_font = (NXWidgets::CNxFont *)0; return false; @@ -530,7 +530,7 @@ FAR void *CCalibration::calibration(FAR void *arg) This->m_calthread = CALTHREAD_RUNNING; This->m_calphase = CALPHASE_NOT_STARTED; - ginfo("Started: m_calthread=%d\n", (int)This->m_calthread); + twminfo("Started: m_calthread=%d\n", (int)This->m_calthread); // Make the calibration display visible and show the initial calibration // display @@ -574,7 +574,7 @@ FAR void *CCalibration::calibration(FAR void *arg) This->destroy(); - ginfo("Terminated: m_calthread=%d\n", (int)This->m_calthread); + twminfo("Terminated: m_calthread=%d\n", (int)This->m_calthread); return (FAR void *)0; } @@ -783,7 +783,7 @@ bool CCalibration::averageSamples(struct nxgl_point_s &average) void CCalibration::stateMachine(void) { - ginfo("Old m_calphase=%d\n", m_calphase); + twminfo("Old m_calphase=%d\n", m_calphase); #ifdef CONFIG_TWM4NX_CALIBRATION_AVERAGE // Are we collecting samples? @@ -1092,7 +1092,7 @@ void CCalibration::finishCalibration(void) sizeof(struct SCalibrationData)); if (ret != 0) { - gerr("ERROR: Failed to save calibration data\n"); + twmerr("ERROR: Failed to save calibration data\n"); } #endif // And provide the calibration data to CInput, enabling @@ -1116,7 +1116,7 @@ void CCalibration::finishCalibration(void) void CCalibration::stop(void) { - ginfo("Stopping calibration: m_calthread=%d\n", (int)m_calthread); + twminfo("Stopping calibration: m_calthread=%d\n", (int)m_calthread); // Was the calibration thread created? @@ -1135,7 +1135,7 @@ void CCalibration::stop(void) // Try to wake up the calibration thread so that it will see our // termination request - ginfo("Stopping calibration: m_calthread=%d\n", (int)m_calthread); + twminfo("Stopping calibration: m_calthread=%d\n", (int)m_calthread); (void)pthread_kill(m_thread, CONFIG_TWM4NX_CALIBRATION_SIGNO); // Wait for the calibration thread to exit @@ -1187,7 +1187,7 @@ bool CCalibration::createCalibrationData(struct SCalibrationData &data) struct nxgl_size_s windowSize; if (!m_nxWin->getSize(&windowSize)) { - gerr("ERROR: NXWidgets::INxWindow::getSize failed\n"); + twmerr("ERROR: NXWidgets::INxWindow::getSize failed\n"); return false; } diff --git a/graphics/twm4nx/apps/cclock.cxx b/graphics/twm4nx/apps/cclock.cxx new file mode 100644 index 000000000..312fc2b96 --- /dev/null +++ b/graphics/twm4nx/apps/cclock.cxx @@ -0,0 +1,658 @@ +///////////////////////////////////////////////////////////////////////////// +// apps/graphics/twm4nx/src/cnxterm.cxx +// Clock window +// +// Copyright (C) 2019 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// 3. Neither the name NuttX nor the names of its contributors may be +// used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// Included Files +///////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "nshlib/nshlib.h" + +#include "graphics/nxwidgets/cwidgetcontrol.hxx" + +#include "graphics/nxglyphs.hxx" +#include "graphics/twm4nx/twm4nx_config.hxx" +#include "graphics/twm4nx/ctwm4nx.hxx" +#include "graphics/twm4nx/cwindow.hxx" +#include "graphics/twm4nx/cwindowfactory.hxx" +#include "graphics/twm4nx/cmainmenu.hxx" + +#include "graphics/slcd.hxx" +#include "graphics/twm4nx/apps/clock_config.hxx" +#include "graphics/twm4nx/apps/cclock.hxx" + +///////////////////////////////////////////////////////////////////////////// +// Private Types +///////////////////////////////////////////////////////////////////////////// + +namespace Twm4Nx +{ +///////////////////////////////////////////////////////////////////////////// +// Private Types +///////////////////////////////////////////////////////////////////////////// + + /** + * This structure is used to pass start up parameters to the Clock task + * and to assure the the Clock is successfully started. + */ + + struct SClock + { + FAR CClock *that; /**< The CClock 'this' pointer */ + sem_t exclSem; /**< Sem that gives exclusive access to this structure */ + sem_t waitSem; /**< Sem that posted when the task is initialized */ + bool success; /**< True if successfully initialized */ + }; + +///////////////////////////////////////////////////////////////////////////// +// Private Data +///////////////////////////////////////////////////////////////////////////// + + /** + * This global data structure is used to pass start parameters to Clock + * task and to assure that the Clock is successfully started. + */ + + static struct SClock GClockVars; +} + +///////////////////////////////////////////////////////////////////////////// +// CClock Method Implementations +///////////////////////////////////////////////////////////////////////////// + +using namespace Twm4Nx; + +/** + * CClock constructor + * + * @param twm4nx. The Twm4Nx session instance + */ + +CClock::CClock(FAR CTwm4Nx *twm4nx) +{ + // Save/initialize the context data + + m_twm4nx = twm4nx; + m_window = (FAR CWindow *)0; + m_slcd = (FAR SLcd::CSLcd *)0; + + // The clock task is not running + + m_pid = (pid_t)-1; + + // This is un-neccessary but helpful in debugging to have a known value + + std::memset(m_digits, 0, CLOCK_NDIGITS * sizeof(struct SClockDigit)); +} + +/** + * CClock destructor + */ + +CClock::~CClock(void) +{ + // There would be a problem if we were stopped with the Clock task + // running... that should never happen but we'll check anyway: + + stop(); + + // Destroy the CSLcd instance + + if (m_window != (FAR CWindow *)0) + { + delete m_window; + } + + // Destroy the CSLcd instance + + if (m_slcd != (FAR SLcd::CSLcd *)0) + { + delete m_slcd; + } +} + +/** + * CClock initializers. Perform miscellaneous post-construction + * initialization that may fail (and hence is not appropriate to be + * done in the constructor) + * + * @return True if the Clock application was successfully initialized. + */ + +bool CClock::initialize(void) +{ + // Call CWindowFactory::createWindow() to create a window for the Clock + // application. Customizations: + // + // Flags: + // WFLAGS_NO_MENU_BUTTON No menu button in the toolbar + // WFLAGS_NO_RESIZE_BUTTON No resize button in the toolbar + // WFLAGS_HIDDEN Window is initially hidden + // + // Null Icon manager means to use the system, common Icon Manager + + NXWidgets::CNxString name("Clock"); + + uint8_t wflags = (WFLAGS_NO_MENU_BUTTON | WFLAGS_NO_RESIZE_BUTTON | + WFLAGS_HIDDEN); + + FAR CWindowFactory *factory = m_twm4nx->getWindowFactory(); + m_window = factory->createWindow(name, &CONFIG_TWM4NX_CLOCK_ICON, + (FAR CIconMgr *)0, wflags); + if (m_window == (FAR CWindow *)0) + { + twmerr("ERROR: Failed to create CWindow\n"); + return false; + } + + // Get the minimum tool bar + + // Configure events needed by the Clock applications + + struct SAppEvents events; + events.eventObj = (FAR void *)this; + events.redrawEvent = EVENT_CLOCK_REDRAW; + events.resizeEvent = EVENT_CLOCK_RESIZE; + events.mouseEvent = EVENT_CLOCK_XYINPUT; + events.kbdEvent = EVENT_CLOCK_KBDINPUT; + events.closeEvent = EVENT_CLOCK_CLOSE; + events.deleteEvent = EVENT_CLOCK_DELETE; + + bool success = m_window->configureEvents(events); + if (!success) + { + delete m_window; + m_window = (FAR CWindow *)0; + return false; + } + + // Create an instance of the segment LCD emulation + + m_slcd = new SLcd::CSLcd(m_window->getNxWindow(), + CONFIG_TWM4NX_CLOCK_HEIGHT); + if (m_slcd == (FAR SLcd::CSLcd *)0) + { + twmerr("ERROR: Failed to create SLcd::CSLcd instance\n"); + delete m_window; + m_window = (FAR CWindow *)0; + return false; + } + + // Set the correct size and position of the window based on the SLCD + // character height. + + nxgl_coord_t segmentWidth = m_slcd->getWidth(); + nxgl_coord_t gapWidth = segmentWidth / 2; + + struct nxgl_size_s windowSize; + windowSize.w = 4 * (segmentWidth + CONFIG_TWM4NX_CLOCK_HSPACING) + gapWidth; + windowSize.h = m_slcd->getHeight() + 2 * CONFIG_TWM4NX_CLOCK_HSPACING; + + // Check against the minimum toolbar width + + nxgl_coord_t minWidth = minimumToolbarWidth(m_twm4nx, name, wflags); + + nxgl_coord_t xOffset = CONFIG_TWM4NX_CLOCK_HSPACING; + if (windowSize.w < minWidth) + { + xOffset += (minWidth - windowSize.w) / 2; + windowSize.w = minWidth; + } + + // Resize and position the frame. The window is initially position in + // the upper left hand corner of the display. + + struct nxgl_size_s frameSize; + m_window->windowToFrameSize(&windowSize, &frameSize); + + struct nxgl_point_s framePos; + framePos.x = 0; + framePos.y = 0; + + if (!m_window->resizeFrame(&frameSize, &framePos)) + { + delete m_window; + m_window = (FAR CWindow *)0; + delete m_slcd; + m_slcd = (FAR SLcd::CSLcd *)0; + return false; + } + + // Initialize the SLCD digit horizontal positions + + m_digits[0].xOffset = xOffset; + m_digits[1].xOffset = m_digits[0].xOffset + segmentWidth + + CONFIG_TWM4NX_CLOCK_HSPACING; + m_digits[2].xOffset = m_digits[1].xOffset + segmentWidth + + gapWidth; + m_digits[3].xOffset = m_digits[2].xOffset + segmentWidth + + CONFIG_TWM4NX_CLOCK_HSPACING; + + // Display the initial time + + redraw(); + + // Now we can show the completed window + + return m_window->showWindow(); +} + +/** + * Start the application (perhaps in the minimized state). + * + * @return True if the application was successfully started. + */ + +bool CClock::run(void) +{ + // Some sanity checking + + if (m_pid >= 0) + { + twmerr("ERROR: All ready running?\n"); + return false; + } + + // Get exclusive access to the global data structure + + if (sem_wait(&GClockVars.exclSem) != 0) + { + // This might fail if a signal is received while we are waiting. Or, + // perhaps if the task is canceled. + + twmerr("ERROR: Failed to get semaphore\n"); + return false; + } + + // Initialize the rest of parameter passing area for temporary use to + // start the new Clock task + + sem_init(&GClockVars.waitSem, 0, 0); + sem_setprotocol(&GClockVars.waitSem, SEM_PRIO_NONE); + + GClockVars.that = this; + GClockVars.success = false; + + // Start the Clock task + + sched_lock(); + m_pid = task_create("Clock", CONFIG_TWM4NX_CLOCK_PRIO, + CONFIG_TWM4NX_CLOCK_STACKSIZE, clock, + (FAR char * const *)0); + + // Did we successfully start the Clock task? + + bool success = true; + if (m_pid < 0) + { + twmerr("ERROR: Failed to create the Clock task\n"); + success = false; + } + else + { + // Wait for up to two seconds for the task to initialize + + struct timespec abstime; + clock_gettime(CLOCK_REALTIME, &abstime); + abstime.tv_sec += 2; + + int ret = sem_timedwait(&GClockVars.waitSem, &abstime); + sched_unlock(); + + if (ret < 0 || !GClockVars.success) + { + // sem_timedwait failed OR the Clock task reported a + // failure. Stop the application + + twmerr("ERROR: Failed start the Clock task\n"); + stop(); + success = false; + } + } + + sem_destroy(&GClockVars.waitSem); + sem_post(&GClockVars.exclSem); + return success; +} + +/** + * This is the close window event handler. It will stop the Clock + * application thread. + */ + +void CClock::stop(void) +{ + // Delete the Clock task if it is still running (this could strand + // resources). + + if (m_pid >= 0) + { + pid_t pid = m_pid; + m_pid = (pid_t)-1; + + // Then delete the NSH task, possibly stranding resources + + std::task_delete(pid); + } +} + +/** + * This is the Clock task. + */ + +int CClock::clock(int argc, char *argv[]) +{ + // Get the 'this' pointer + + FAR CClock *This = GClockVars.that; + + // Inform the parent thread that we successfully initialized + + GClockVars.success = true; + sem_post(&GClockVars.waitSem); + + // Loop forever. When the window is deleted, this task will be brutally + // terminated via task_delete() + + for (; ; ) + { + // Update the clock + + This->update(); + + // Then sleep for a minute + + sleep(60); + } + + return EXIT_FAILURE; // Never get here +} + +/** + * Handle Twm4Nx events. This overrides a method from CTwm4NXEvent + * + * @param eventmsg. The received NxWidget WINDOW event message. + * @return True if the message was properly handled. false is + * return on any failure. + */ + +bool CClock::event(FAR struct SEventMsg *eventmsg) +{ + bool success = true; + + switch (eventmsg->eventID) + { + case EVENT_CLOCK_REDRAW: // Redraw event (doesn't happen) + redraw(); // Redraw the whole window + break; + + case EVENT_CLOCK_CLOSE: // Window close event + stop(); // Stop the Clock thread + break; + + default: + success = false; + break; + } + + return success; +} + +/** + * Update the Clock. + */ + +void CClock::update(void) +{ + // Get the current time. + + FAR struct std::timespec ts; + int ret = std::clock_gettime(CLOCK_REALTIME, &ts); + if (ret < 0) + { + twmerr("ERROR: clock_gettime() failed\n"); + return; + } + + // Break out the time + // + // tm_hour - The number of hours past midnight, in the range 0 to 23. + // tm_min - The number of minutes after the hour, in the range 0 to 59. + + struct std::tm tm; + if (std::gmtime_r(&ts.tv_sec, &tm) == (FAR struct std::tm *)0) + { + twmerr("ERROR: gmtime_r() failed\n"); + return; + } + + // Convert hours and minutes into SLCD segment codes + // + // Conversion of 24 hour clock (0-23) to twelve hour (1-12) + // 0 -> 12 6 -> 6 12 -> 12 18 -> 6 + // 1 -> 1 7 -> 7 13 -> 1 19 -> 7 + // 2 -> 2 8 -> 8 14 -> 2 20 -> 8 + // 3 -> 3 9 -> 9 15 -> 3 21 -> 9 + // 4 -> 4 10 -> 10 16 -> 4 22 -> 10 + // 5 -> 5 11 -> 11 17 -> 5 23 -> 11 + + unsigned int hour = tm.tm_hour; /* Range 0-23 */ + if (hour == 0) + { + hour = 12; + } + else if (hour > 12) /* Range 1-23 */ + { + hour -= 12; /* Range 1-11 */ + } + + uint8_t codes[CLOCK_NDIGITS]; + + char ascii = (hour > 9) ? '1' : ' '; + (void)m_slcd->convert(ascii, codes[0]); + + ascii = (hour % 10) + '0'; + (void)m_slcd->convert(ascii, codes[1]); + + ascii = (tm.tm_min / 10) + '0'; + (void)m_slcd->convert(ascii, codes[2]); + + ascii = (tm.tm_min % 10) + '0'; + (void)m_slcd->convert(ascii, codes[3]); + + struct nxgl_point_s pos; + pos.y = CONFIG_TWM4NX_CLOCK_VSPACING; + + // Then show each segment LCD + // There might be a more efficient way to to this than to erase the entire + // SLCD on each update. + + for (int i = 0; i < CLOCK_NDIGITS; i++) + { + if (m_digits[i].segments != codes[i]) + { + pos.x = m_digits[i].xOffset; + + m_slcd->erase(pos); + m_slcd->show(codes[i], pos); + m_digits[i].segments = codes[i]; + } + } +} + +/** + * Redraw the entire clock. + */ + +void CClock::redraw(void) +{ + // Get the size of the window + + struct nxgl_size_s windowSize; + (void)m_window->getWindowSize(&windowSize); + + // Create a bounding box + + struct nxgl_rect_s windowRect; + windowRect.pt1.x = 0; + windowRect.pt1.y = 0; + windowRect.pt2.x = windowSize.w - 1; + windowRect.pt2.y = windowSize.h - 1; + + // Fill the entire window with the clock background color + + FAR NXWidgets::INxWindow *nxWindow = m_window->getNxWindow(); + if (!nxWindow->fill(&windowRect, SLCD_BACKGROUND)) + { + twmerr("ERROR: Failed to fill window"); + return; + } + + // Reset the saved codes to force a complete update + + for (int i = 0; i < CLOCK_NDIGITS; i++) + { + m_digits[i].segments = 0; + } + + // Then update the Clock window + + update(); +} + +///////////////////////////////////////////////////////////////////////////// +// CClockFactory Method Implementations +///////////////////////////////////////////////////////////////////////////// + +/** + * CClockFactory Initializer. Performs parts of the instance + * construction that may fail. In this implementation, it will + * initialize the NSH library and register an menu item in the + * Main Menu. + */ + +bool CClockFactory::initialize(FAR CTwm4Nx *twm4nx) +{ + // Save the session instance + + m_twm4nx = twm4nx; + + // Initialize the parameter passing area. Other fields are initialized + // by CClock thread-specific logic. + + sem_init(&GClockVars.exclSem, 0, 1); + + // Register an entry with the Main menu. When selected, this will + // Case the start + + FAR CMainMenu *cmain = twm4nx->getMainMenu(); + return cmain->addApplication(this); +} + +/** + * Handle CClockFactory events. This overrides a method from + * CTwm4NXEvent + * + * @param eventmsg. The received NxWidget WINDOW event message. + * @return True if the message was properly handled. false is + * return on any failure. + */ + +bool CClockFactory::event(FAR struct SEventMsg *eventmsg) +{ + bool success = true; + + switch (eventmsg->eventID) + { + case EVENT_CLOCK_START: // Main menu selection + startFunction(); // Create a new Clock instance + break; + + default: + success = false; + break; + } + + return success; +} + +/** + * Create and start a new instance of CClock. + */ + +bool CClockFactory::startFunction(void) +{ + // Instantiate the Nxterm application, providing only the session session + // instance to the constructor + + FAR CClock *clock = new CClock(m_twm4nx); + if (clock == (FAR CClock *)0) + { + twmerr("ERROR: Failed to instantiate CClock\n"); + return false; + } + + // Initialize the Clock application + + if (!clock->initialize()) + { + twmerr("ERROR: Failed to initialize CClock instance\n"); + delete clock; + return false; + } + + // Start the Clock application instance + + if (!clock->run()) + { + twmerr("ERROR: Failed to start the Clock application\n"); + delete clock; + return false; + } + + return true; +} diff --git a/graphics/twm4nx/apps/cnxterm.cxx b/graphics/twm4nx/apps/cnxterm.cxx index 47b27f98d..216f546cc 100644 --- a/graphics/twm4nx/apps/cnxterm.cxx +++ b/graphics/twm4nx/apps/cnxterm.cxx @@ -91,9 +91,13 @@ namespace Twm4Nx { +///////////////////////////////////////////////////////////////////////////// +// Private Types +///////////////////////////////////////////////////////////////////////////// + /** - * This structure is used to pass start up parameters to the NxTerm task and to assure the - * the NxTerm is successfully started. + * This structure is used to pass start up parameters to the NxTerm task + * and to assure the the NxTerm is successfully started. */ struct SNxTerm @@ -113,11 +117,11 @@ namespace Twm4Nx ///////////////////////////////////////////////////////////////////////////// /** - * This global data structure is used to pass start parameters to NxTerm task and to - * assure that the NxTerm is successfully started. + * This global data structure is used to pass start parameters to NxTerm + * task and to assure that the NxTerm is successfully started. */ - static struct SNxTerm g_nxtermvars; + static struct SNxTerm GNxTermVars; } ///////////////////////////////////////////////////////////////////////////// @@ -139,7 +143,7 @@ CNxTerm::CNxTerm(FAR CTwm4Nx *twm4nx) m_twm4nx = twm4nx; m_nxtermWindow = (FAR CWindow *)0; - // The NxTerm is not runing + // The NxTerm is not running m_pid = (pid_t)-1; m_NxTerm = (NXTERM)0; @@ -155,16 +159,6 @@ CNxTerm::~CNxTerm(void) // running... that should never happen but we'll check anyway: stop(); - - // The following is not necessary. The system will automatically - // delete the CWindow instance when the terminate button is pressed. - // We simply have to terminate the application behind the window - -#if 0 - // Delete the application window - - delete m_nxtermWindow; -#endif } /** @@ -182,7 +176,7 @@ bool CNxTerm::initialize(void) // // Flags: WFLAGS_NO_MENU_BUTTON indicates that there is no menu associated // with the NxTerm application window - // Null Icon mager means to use the system, common Icon Manager + // Null Icon manager means to use the system, common Icon Manager NXWidgets::CNxString name("NuttShell"); @@ -237,7 +231,7 @@ bool CNxTerm::run(void) // Get exclusive access to the global data structure - if (sem_wait(&g_nxtermvars.exclSem) != 0) + if (sem_wait(&GNxTermVars.exclSem) != 0) { // This might fail if a signal is received while we are waiting. @@ -251,21 +245,21 @@ bool CNxTerm::run(void) // Get the window handle from the widget control - g_nxtermvars.hwnd = control->getWindowHandle(); + GNxTermVars.hwnd = control->getWindowHandle(); // Describe the NxTerm - g_nxtermvars.wndo.wcolor[0] = CONFIG_TWM4NX_NXTERM_WCOLOR; - g_nxtermvars.wndo.fcolor[0] = CONFIG_TWM4NX_NXTERM_FONTCOLOR; - g_nxtermvars.wndo.fontid = CONFIG_TWM4NX_NXTERM_FONTID; + GNxTermVars.wndo.wcolor[0] = CONFIG_TWM4NX_NXTERM_WCOLOR; + GNxTermVars.wndo.fcolor[0] = CONFIG_TWM4NX_NXTERM_FONTCOLOR; + GNxTermVars.wndo.fontid = CONFIG_TWM4NX_NXTERM_FONTID; // Remember the device minor number (before it is incremented) - m_minor = g_nxtermvars.minor; + m_minor = GNxTermVars.minor; // Get the size of the window - if (!m_nxtermWindow->getWindowSize(&g_nxtermvars.wndo.wsize)) + if (!m_nxtermWindow->getWindowSize(&GNxTermVars.wndo.wsize)) { twmerr("ERROR: getWindowSize() failed\n"); return false; @@ -273,9 +267,9 @@ bool CNxTerm::run(void) // Start the NxTerm task - g_nxtermvars.console = (FAR void *)this; - g_nxtermvars.success = false; - g_nxtermvars.nxterm = 0; + GNxTermVars.console = (FAR void *)this; + GNxTermVars.success = false; + GNxTermVars.nxterm = 0; sched_lock(); m_pid = task_create("NxTerm", CONFIG_TWM4NX_NXTERM_PRIO, @@ -298,20 +292,20 @@ bool CNxTerm::run(void) clock_gettime(CLOCK_REALTIME, &abstime); abstime.tv_sec += 2; - int ret = sem_timedwait(&g_nxtermvars.waitSem, &abstime); + int ret = sem_timedwait(&GNxTermVars.waitSem, &abstime); sched_unlock(); - if (ret == OK && g_nxtermvars.success) + if (ret == OK && GNxTermVars.success) { #ifdef CONFIG_NXTERM_NXKBDIN // Re-direct NX keyboard input to the new NxTerm driver - DEBUGASSERT(g_nxtermvars.nxterm != 0); - m_nxtermWindow->redirectNxTerm(g_nxtermvars.nxterm); + DEBUGASSERT(GNxTermVars.nxterm != 0); + m_nxtermWindow->redirectNxTerm(GNxTermVars.nxterm); #endif // Save the handle to use in the stop method - m_NxTerm = g_nxtermvars.nxterm; + m_NxTerm = GNxTermVars.nxterm; } else { @@ -324,13 +318,13 @@ bool CNxTerm::run(void) } } - sem_post(&g_nxtermvars.exclSem); + sem_post(&GNxTermVars.exclSem); return success; } /** - * This is the close windoe event handler. It will stop the NxTerm - * application trhead. + * This is the close window event handler. It will stop the NxTerm + * application thread. */ void CNxTerm::stop(void) @@ -387,10 +381,10 @@ int CNxTerm::nxterm(int argc, char *argv[]) struct boardioc_nxterm_create_s nxcreate; nxcreate.nxterm = (FAR void *)0; - nxcreate.hwnd = g_nxtermvars.hwnd; - nxcreate.wndo = g_nxtermvars.wndo; + nxcreate.hwnd = GNxTermVars.hwnd; + nxcreate.wndo = GNxTermVars.wndo; nxcreate.type = BOARDIOC_XTERM_FRAMED; - nxcreate.minor = g_nxtermvars.minor; + nxcreate.minor = GNxTermVars.minor; ret = boardctl(BOARDIOC_NXTERM, (uintptr_t)&nxcreate); if (ret < 0) @@ -399,17 +393,17 @@ int CNxTerm::nxterm(int argc, char *argv[]) goto errout; } - g_nxtermvars.nxterm = nxcreate.nxterm; - DEBUGASSERT(g_nxtermvars.nxterm != NULL); + GNxTermVars.nxterm = nxcreate.nxterm; + DEBUGASSERT(GNxTermVars.nxterm != NULL); // Construct the driver name using this minor number char devname[32]; - snprintf(devname, 32, "/dev/nxterm%d", g_nxtermvars.minor); + snprintf(devname, 32, "/dev/nxterm%d", GNxTermVars.minor); // Increment the minor number while it is protect by the semaphore - g_nxtermvars.minor++; + GNxTermVars.minor++; // Open the NxTerm driver @@ -460,8 +454,8 @@ int CNxTerm::nxterm(int argc, char *argv[]) // Inform the parent thread that we successfully initialized - g_nxtermvars.success = true; - sem_post(&g_nxtermvars.waitSem); + GNxTermVars.success = true; + sem_post(&GNxTermVars.waitSem); // Run the NSH console @@ -476,9 +470,9 @@ int CNxTerm::nxterm(int argc, char *argv[]) return EXIT_SUCCESS; errout: - g_nxtermvars.nxterm = 0; - g_nxtermvars.success = false; - sem_post(&g_nxtermvars.waitSem); + GNxTermVars.nxterm = 0; + GNxTermVars.success = false; + sem_post(&GNxTermVars.waitSem); return EXIT_FAILURE; } @@ -612,8 +606,8 @@ bool CNxTermFactory::nshlibInitialize(void) { // Initialize the global data structure - sem_init(&g_nxtermvars.exclSem, 0, 1); - sem_init(&g_nxtermvars.waitSem, 0, 0); + sem_init(&GNxTermVars.exclSem, 0, 1); + sem_init(&GNxTermVars.waitSem, 0, 0); // Initialize the NSH library diff --git a/graphics/twm4nx/src/cresize.cxx b/graphics/twm4nx/src/cresize.cxx index 903492759..2e5a75097 100644 --- a/graphics/twm4nx/src/cresize.cxx +++ b/graphics/twm4nx/src/cresize.cxx @@ -484,13 +484,13 @@ bool CResize::startResize(FAR struct SEventMsg *eventmsg) if (!m_resizeWindow->getFramePosition(&m_lastPos)) { - gerr("ERROR: Failed to get frame position"); + twmerr("ERROR: Failed to get frame position"); return false; } if (!m_resizeWindow->getFrameSize(&m_lastSize)) { - gerr("ERROR: Failed to get frame size"); + twmerr("ERROR: Failed to get frame size"); return false; } @@ -699,7 +699,7 @@ bool CResize::pauseResize(FAR struct SEventMsg *eventmsg) if (!updateSize(eventmsg)) { - gerr("ERROR: Failed to update the window size\n"); + twmerr("ERROR: Failed to update the window size\n"); } // Set the new frame position and size if the size has changed @@ -746,13 +746,13 @@ bool CResize::resumeResize(FAR struct SEventMsg *eventmsg) if (!m_resizeWindow->getFramePosition(&m_lastPos)) { - gerr("ERROR: Failed to get frame position"); + twmerr("ERROR: Failed to get frame position"); return false; } if (!m_resizeWindow->getFrameSize(&m_lastSize)) { - gerr("ERROR: Failed to get frame size"); + twmerr("ERROR: Failed to get frame size"); return false; } diff --git a/graphics/twm4nx/src/twm4nx_main.cxx b/graphics/twm4nx/src/twm4nx_main.cxx index 48860dd41..9e0ad80b4 100644 --- a/graphics/twm4nx/src/twm4nx_main.cxx +++ b/graphics/twm4nx/src/twm4nx_main.cxx @@ -56,6 +56,7 @@ #include "graphics/twm4nx/apps/ccalibration.hxx" #include "graphics/twm4nx/apps/cnxterm.hxx" +#include "graphics/twm4nx/apps/cclock.hxx" ///////////////////////////////////////////////////////////////////////////// // Public Function Prototypes @@ -187,6 +188,16 @@ int twm4nx_main(int argc, char *argv[]) } #endif +#ifdef CONFIG_TWM4NX_CLOCK + CClockFactory clockFactory; + success = clockFactory.initialize(twm4nx); + if (!success) + { + twmerr(" ERROR: Failed to initialize CClockFactory\n"); + return EXIT_FAILURE; + } +#endif + #ifdef CONFIG_TWM4NX_NXTERM CNxTermFactory nxtermFactory; success = nxtermFactory.initialize(twm4nx); diff --git a/include/graphics/slcd.hxx b/include/graphics/slcd.hxx index 8f1884274..103219ff1 100644 --- a/include/graphics/slcd.hxx +++ b/include/graphics/slcd.hxx @@ -40,8 +40,11 @@ // Included Files ///////////////////////////////////////////////////////////////////////////// +#include #include +#include "graphics/nxwidgets/nxconfig.hxx" + ///////////////////////////////////////////////////////////////////////////// // Pre-processor definitions ///////////////////////////////////////////////////////////////////////////// @@ -68,6 +71,12 @@ #define NBOTTOMRIGHT_TRAPEZOIDS 5 #define NBOTTOM_TRAPEZOIDS 2 +// Clock colors: Light grey-green background, greenish-black foreground. +// Similar to what you would see on a classic LCD. + +#define SLCD_BACKGROUND MKRGB(128, 140, 128) +#define SLCD_FOREGROUND MKRGB(0, 16, 0) + ///////////////////////////////////////////////////////////////////////////// // CSLcd Implementation Class ///////////////////////////////////////////////////////////////////////////// diff --git a/include/graphics/twm4nx/apps/cclock.hxx b/include/graphics/twm4nx/apps/cclock.hxx new file mode 100644 index 000000000..e7df2acc1 --- /dev/null +++ b/include/graphics/twm4nx/apps/cclock.hxx @@ -0,0 +1,291 @@ +///////////////////////////////////////////////////////////////////////////// +// apps/include/graphics/twm4nx/apps/cclock.hxx +// Retro LCD Clock +// +// Copyright (C) 2019 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// 3. Neither the name NuttX nor the names of its contributors may be +// used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CCLOCK_HXX +#define __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CCLOCK_HXX + +///////////////////////////////////////////////////////////////////////////// +// Included Files +///////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include + +#include "graphics/twm4nx/ctwm4nx.hxx" +#include "graphics/twm4nx/ctwm4nxevent.hxx" +#include "graphics/twm4nx/twm4nx_events.hxx" +#include "graphics/twm4nx/iapplication.hxx" + +///////////////////////////////////////////////////////////////////////////// +// Pre-processor Definitions +///////////////////////////////////////////////////////////////////////////// + +// CClock application events +// Window Events + +#define EVENT_CLOCK_REDRAW (EVENT_RECIPIENT_APP | 0x0000) /* Not necessary */ +#define EVENT_CLOCK_RESIZE EVENT_SYSTEM_NOP +#define EVENT_CLOCK_XYINPUT EVENT_SYSTEM_NOP +#define EVENT_CLOCK_KBDINPUT EVENT_SYSTEM_NOP +#define EVENT_CLOCK_DELETE EVENT_WINDOW_DELETE + +// Button Events + +#define EVENT_CLOCK_CLOSE (EVENT_RECIPIENT_APP | 0x0001) + +// Menu Events + +#define EVENT_CLOCK_START (EVENT_RECIPIENT_APP | 0x0002) + +// Number of digits in clock display + +#define CLOCK_NDIGITS 4 + +///////////////////////////////////////////////////////////////////////////// +// Implementation Classes +///////////////////////////////////////////////////////////////////////////// + +namespace SLcd +{ + class CSLcd; // Forward reference +} + +namespace Twm4Nx +{ + /** + * This structure describes the state of one clock digit + */ + + struct SClockDigit + { + nxgl_coord_t xOffset; /**< X offset from left side of the window */ + uint8_t segments; /**< LCD segment code of number */ + }; + + /** + * This class implements the Clock application. + */ + + class CClock : public CTwm4NxEvent + { + private: + FAR CTwm4Nx *m_twm4nx; /**< Reference to the Twm4Nx session instance */ + FAR CWindow *m_window; /**< Reference to the Clock application window */ + FAR SLcd::CSLcd *m_slcd; /**< Reference to the segment LCD helper */ + pid_t m_pid; /**< Task ID of the Clock thread */ + + // The current clock state, digit-by-digit: + + struct SClockDigit m_digits[CLOCK_NDIGITS]; + + /** + * This is the Clock task. + */ + + static int clock(int argc, char *argv[]); + + /** + * Handle Twm4Nx events. This overrides a method from CTwm4NXEvent + * + * @param eventmsg. The received NxWidget WINDOW event message. + * @return True if the message was properly handled. false is + * return on any failure. + */ + + bool event(FAR struct SEventMsg *eventmsg); + + /** + * Update the Clock. + */ + + void update(void); + + /** + * Redraw the entire clock. + */ + + void redraw(void); + + /** + * This is the close window event handler. It will stop the Clock + * application thread. + */ + + void stop(void); + + public: + + /** + * CClock constructor + * + * @param twm4nx. The Twm4Nx session instance + */ + + CClock(FAR CTwm4Nx *twm4nx); + + /** + * CClock destructor + */ + + ~CClock(void); + + /** + * CClock initializers. Perform miscellaneous post-construction + * initialization that may fail (and hence is not appropriate to be + * done in the constructor) + * + * @return True if the Clock application was successfully initialized. + */ + + bool initialize(void); + + /** + * Start the Clock. + * + * @return True if the Clock application was successfully started. + */ + + bool run(void); + }; + + class CClockFactory : public IApplication, + public IApplicationFactory, + public CTwm4NxEvent + { + private: + + FAR CTwm4Nx *m_twm4nx; /**< Twm4Nx session instance */ + + /** + * Handle CClockFactory events. This overrides a method from + * CTwm4NXEvent + * + * @param eventmsg. The received NxWidget WINDOW event message. + * @return True if the message was properly handled. false is + * return on any failure. + */ + + bool event(FAR struct SEventMsg *eventmsg); + + /** + * Create and start a new instance of an CClock. + */ + + bool startFunction(void); + + /** + * Return the Main Menu item string. This overrides the method from + * IApplication + * + * @param name The name of the application. + */ + + inline NXWidgets::CNxString getName(void) + { + return NXWidgets::CNxString("Clock"); + } + + /** + * There is no sub-menu for this Main Menu item. This overrides + * the method from IApplication. + * + * @return This implementation will always return a null value. + */ + + inline FAR CMenus *getSubMenu(void) + { + return (FAR CMenus *)0; + } + + /** + * There is no custom event handler. We use the common event handler. + * + * @return. null is always returned in this implementation. + */ + + inline FAR CTwm4NxEvent *getEventHandler(void) + { + return (FAR CTwm4NxEvent *)this; + } + + /** + * Return the Twm4Nx event that will be generated when the Main Menu + * item is selected. + * + * @return. This function always returns EVENT_SYSTEM_NOP. + */ + + inline uint16_t getEvent(void) + { + return EVENT_CLOCK_START; + } + + public: + + /** + * CClockFactory Constructor + * + * @param twm4nx. The Twm4Nx session instance + */ + + inline CClockFactory(void) + { + m_twm4nx = (FAR CTwm4Nx *)0; + } + + /** + * CClockFactory Destructor + */ + + inline ~CClockFactory(void) + { + // REVISIT: Would need to remove Main Menu item + } + + /** + * CClockFactory Initializer. Performs parts of the instance + * construction that may fail. In this implemenation, it will + * initialize the NSH library and register an menu item in the + * Main Menu. + */ + + bool initialize(FAR CTwm4Nx *twm4nx); + }; +} + +#endif // __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CCLOCK_HXX diff --git a/include/graphics/twm4nx/apps/clock_config.hxx b/include/graphics/twm4nx/apps/clock_config.hxx new file mode 100644 index 000000000..c7412137a --- /dev/null +++ b/include/graphics/twm4nx/apps/clock_config.hxx @@ -0,0 +1,135 @@ +///////////////////////////////////////////////////////////////////////////// +// apps/include/graphics/twm4nx/apps/clock_config.hxx +// Clock configuration settings +// +// Copyright (C) 2019 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// 3. Neither the name NuttX nor the names of its contributors may be +// used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CLOCK_CONFIG_HXX +#define __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CLOCK_CONFIG_HXX + +///////////////////////////////////////////////////////////////////////////// +// Included Files +///////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "graphics/nxglyphs.hxx" +#include "graphics/nxwidgets/crlepalettebitmap.hxx" +#include "graphics/twm4nx/twm4nx_config.hxx" + +#ifdef CONFIG_TWM4NX_CLOCK + +///////////////////////////////////////////////////////////////////////////// +// Pre-Processor Definitions +///////////////////////////////////////////////////////////////////////////// + +// General Configuration //////////////////////////////////////////////////// + +/** + * Required settings: + * + * CONFIG_HAVE_CXX : C++ support is required + * CONFIG_NX : NX must enabled + * CONFIG_GRAPHICS_SLCD : For segment LCD emulation + */ + +#ifndef CONFIG_HAVE_CXX +# error C++ support is required (CONFIG_HAVE_CXX) +#endif + +#ifndef CONFIG_NX +# error NX support is required (CONFIG_NX) +#endif + +#ifndef CONFIG_GRAPHICS_SLCD +# warning Segment LCD emulation is required (CONFIG_GRAPHICS_SLCD) +#endif + +// Clock Window ///////////////////////////////////////////////////////////// + +/** + * Clock Window Configuration + * + * CONFIG_TWM4NX_CLOCK_PRIO - Priority of the Clock task. Default: + * SCHED_PRIORITY_DEFAULT. NOTE: This priority should be less than + * CONFIG_NXSTART_SERVERPRIO or else there may be data overrun errors. + * Such errors would most likely appear as duplicated rows of data on the + * display. + * CONFIG_TWM4NX_CLOCK_STACKSIZE - The stack size to use when starting the + * Clock task. Default: 1024 bytes. + * CONFIG_TWM4NX_CLOCK_ICON - The glyph to use as the Clock icon + * CONFIG_TWM4NX_CLOCK_HEIGHT - The fixed height of the clock + */ + +// Tasking + +#ifndef CONFIG_TWM4NX_CLOCK_PRIO +# define CONFIG_TWM4NX_CLOCK_PRIO SCHED_PRIORITY_DEFAULT +#endif + +#if CONFIG_NXSTART_SERVERPRIO <= CONFIG_TWM4NX_CLOCK_PRIO +# warning "CONFIG_NXSTART_SERVERPRIO <= CONFIG_TWM4NX_CLOCK_PRIO" +# warning" -- This can result in data overrun errors" +#endif + +#ifndef CONFIG_TWM4NX_CLOCK_STACKSIZE +# define CONFIG_TWM4NX_CLOCK_STACKSIZE 1024 +#endif + +// Colors -- Controlled by the CSLcd configuration + +// The Clock window glyph + +#ifndef CONFIG_TWM4NX_CLOCK_ICON +# define CONFIG_TWM4NX_CLOCK_ICON NXWidgets::g_lcdClockBitmap +#endif + +// The fixed clock window height + +#ifndef CONFIG_TWM4NX_CLOCK_HEIGHT +# define CONFIG_TWM4NX_CLOCK_HEIGHT 64 +#endif + +// Spacing + +#ifndef CONFIG_TWM4NX_CLOCK_HSPACING +# define CONFIG_TWM4NX_CLOCK_HSPACING 2 +#endif + +#ifndef CONFIG_TWM4NX_CLOCK_VSPACING +# define CONFIG_TWM4NX_CLOCK_VSPACING 2 +#endif + +#endif // CONFIG_TWM4NX_CLOCK +#endif // __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CLOCK_CONFIG_HXX diff --git a/include/graphics/twm4nx/apps/cnxterm.hxx b/include/graphics/twm4nx/apps/cnxterm.hxx index 97b20fa3b..e7b9df1b0 100644 --- a/include/graphics/twm4nx/apps/cnxterm.hxx +++ b/include/graphics/twm4nx/apps/cnxterm.hxx @@ -86,11 +86,11 @@ namespace Twm4Nx class CNxTerm : public CTwm4NxEvent { private: - CTwm4Nx *m_twm4nx; /**< Reference to the Twm4Nx session instance */ - CWindow *m_nxtermWindow; /**< Reference to the NxTerm application window */ - NXTERM m_NxTerm; /**< NxTerm handle */ - pid_t m_pid; /**< Task ID of the NxTerm thread */ - int m_minor; /**< Terminal device minor number */ + FAR CTwm4Nx *m_twm4nx; /**< Reference to the Twm4Nx session instance */ + FAR CWindow *m_nxtermWindow; /**< Reference to the NxTerm application window */ + NXTERM m_NxTerm; /**< NxTerm handle */ + pid_t m_pid; /**< Task ID of the NxTerm thread */ + int m_minor; /**< Terminal device minor number */ /** * This is the NxTerm task. This function first redirects output to the @@ -107,7 +107,7 @@ namespace Twm4Nx * return on any failure. */ - bool event(FAR struct SEventMsg *eventmsg); + bool event(FAR struct SEventMsg *eventmsg); /** * Handle the NxTerm redraw event. @@ -123,7 +123,7 @@ namespace Twm4Nx /** * This is the close window event handler. It will stop the NxTerm - * application trhead. + * application thread. */ void stop(void); @@ -189,7 +189,7 @@ namespace Twm4Nx * return on any failure. */ - bool event(FAR struct SEventMsg *eventmsg); + bool event(FAR struct SEventMsg *eventmsg); /** * Create and start a new instance of an CNxTerm. @@ -224,7 +224,7 @@ namespace Twm4Nx /** * There is no custom event handler. We use the common event handler. * - * @return. null is always returned in this impementation. + * @return. null is always returned in this implementation. */ inline FAR CTwm4NxEvent *getEventHandler(void) diff --git a/include/graphics/twm4nx/cwindow.hxx b/include/graphics/twm4nx/cwindow.hxx index 59b595b8d..5aaa83c6b 100644 --- a/include/graphics/twm4nx/cwindow.hxx +++ b/include/graphics/twm4nx/cwindow.hxx @@ -56,6 +56,7 @@ #include #include +#include "graphics/nxwidgets/cnxtkwindow.hxx" #include "graphics/nxwidgets/cnxtoolbar.hxx" #include "graphics/nxwidgets/cwidgeteventhandler.hxx" #include "graphics/nxwidgets/cwidgeteventargs.hxx" @@ -508,6 +509,18 @@ namespace Twm4Nx return m_nxWin->getWidgetControl(); } + /** + * Get the raw window interface. This is sometimes needed for connecting + * the window to external NXWidgets applications. + * + * @return The raw window interface (NXWidgets::INxWindow) + */ + + inline NXWidgets::INxWindow *getNxWindow(void) + { + return static_cast(m_nxWin); + } + #ifdef CONFIG_NXTERM_NXKBDIN /** * By default, NX forwards keyboard input to the various widgets residing