Signal Generator
Dependencies: IniManager RA8875 Watchdog mbed-rtos mbed
Fork of speaker_demo_Analog by
SignalGenDisplay.cpp
- Committer:
- WiredHome
- Date:
- 2017-01-16
- Revision:
- 4:10281ddb673d
- Parent:
- 3:d22f3e52d06a
- Child:
- 5:49dd0c647a40
File content as of revision 4:10281ddb673d:
// // Signal Generator Control System // // #include "SignalGenDisplay.h" #include "rtos.h" #include "IniManager.h" #include "BPG_Arial08x08.h" // ##### Main Page ############################################################# // // +---------------------------------------------------------------------------+ // | +--- Scope Area ---------------------------+ Progam Name and version | // | | | Manufacturer name | // | | +---- Wave Outline - - | | // | | | | [Start/Stop ] [ ] | // | | | | [Text Entry Box] [ Back ] | // | | | +-- Keypad Area ---------+ | // | | | | | | // | | | | | | | // | | | | | | | // | | ---+ | | | | // | | | | | | // | +------------------------------------------+ | | | // | | | | // | [duty cycle] [frequency] [amplitude] | | | // | | | | // | [ ... ] [period ] [offset ] | | | // | | | | // | [ ] [ ] [ ] [ ] [ ] | | | // | [Sine ] [Square] [Triangle] [Sawtooth] [User] +------------------------+ | // +---------------------------------------------------------------------------+ // Object Colors #define UI_BackColor RGB(8,8,8) #define UI_ScopeBackColor RGB(0,0,0) #define UI_ScopeFrameColor RGB(255,255,255) #define WaveOutlineColor RGB(16,16,32) #define UI_DutyColor Magenta #define UI_FreqColor BrightRed #define UI_VP2PColor Yellow #define UI_VOffsetColor Green #define UI_BUTTON_FACE_UP White #define UI_BUTTON_FACE_DN RGB(255,92,92) #define UI_BUTTON_SHADOW RGB(128,0,0) #define UI_BUTTON_FACE_DISABLED RGB(24,24,24) #define UI_BUTTON_SHADOW_DISABLED RGB(32,0,0) #define UI_ProductNameColor UI_BUTTON_FACE_DN #define SC_LEFT_MARGIN 10 // Scope left margin #define SC_TOP_MARGIN 10 #define SC_RIGHT_MARGIN 30 #define SC_BOT_MARGIN 20 #define BTN_W 54 // Button width #define BTN_H 32 // Button height #define BTN_S 5 // Button white-space #define BTN_MODE_X 2 // Mode Buttons left edge #define BTN_MODE_Y 233 // Mode Buttons top edge #define BTN_KEYP_X 300 // Keypad left edge #define BTN_KEYP_Y 53 // Keypad top edge // Rectangular Zones const rect_t UI_START_STOP = {BTN_KEYP_X,BTN_KEYP_Y, BTN_KEYP_X + 2 * BTN_W + BTN_S,BTN_KEYP_Y+BTN_H}; const char * UI_StartLabels[3] = { "Start", "Stop", "Pulse" }; const char StartStopKeys[] = { 'G', 'O', 'P' }; const rect_t UI_DATA_ENTRY = {BTN_KEYP_X,BTN_KEYP_Y, BTN_KEYP_X + 2 * BTN_W + BTN_S,BTN_KEYP_Y+BTN_H}; const rect_t UI_SCOPE_RECT = {4,5, 290,160}; const rect_t UI_WAVE_RECT = {4+SC_LEFT_MARGIN,5+SC_TOP_MARGIN, 290-SC_RIGHT_MARGIN,160-SC_BOT_MARGIN}; const rect_t Parameters[] = { {4,170, 60,190}, // 'd'uty cycle {90,170, 186,190}, // 'f'requency {90,200, 186,220}, // 'p'eriod {230,170, 290,190}, // 'v'oltage {230,200, 290,220} // 'o'ffset }; const int ParameterCount = sizeof(Parameters)/sizeof(Parameters[0]); const char ParameterKeys[] = { 'd', 'f', 'p', 'v', 'o' }; const rect_t UI_PROD_RECT = { 298,3, 479,51 }; const rect_t NavToSettings = { 4,200, 60,220 }; // Mode Buttons const rect_t ModeButtons[] = { { BTN_MODE_X+0*(BTN_W+BTN_S),BTN_MODE_Y, BTN_MODE_X+0*(BTN_W+BTN_S)+BTN_W,BTN_MODE_Y+BTN_H }, { BTN_MODE_X+1*(BTN_W+BTN_S),BTN_MODE_Y, BTN_MODE_X+1*(BTN_W+BTN_S)+BTN_W,BTN_MODE_Y+BTN_H }, { BTN_MODE_X+2*(BTN_W+BTN_S),BTN_MODE_Y, BTN_MODE_X+2*(BTN_W+BTN_S)+BTN_W,BTN_MODE_Y+BTN_H }, { BTN_MODE_X+3*(BTN_W+BTN_S),BTN_MODE_Y, BTN_MODE_X+3*(BTN_W+BTN_S)+BTN_W,BTN_MODE_Y+BTN_H }, { BTN_MODE_X+4*(BTN_W+BTN_S),BTN_MODE_Y, BTN_MODE_X+4*(BTN_W+BTN_S)+BTN_W,BTN_MODE_Y+BTN_H }, }; const int ModeCount = sizeof(ModeButtons)/sizeof(ModeButtons[0]); SG_Mode UI_ModeList[] = { SG_SINE, SG_SQUARE, SG_TRIANGLE, SG_SAWTOOTH, SG_USER, }; const char ModeKeys[] = { 'S','Q','T','W','U' }; const char *ModeNames[] = { "Sine", "Square", "Triangle", "Sawtooth", "User", }; const rect_t UI_Keypad[] = { {BTN_KEYP_X+2*(BTN_W+BTN_S),BTN_KEYP_Y+0*(BTN_H+BTN_S), BTN_KEYP_X+2*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+0*(BTN_H+BTN_S)+BTN_H }, // backspace {BTN_KEYP_X+0*(BTN_W+BTN_S),BTN_KEYP_Y+1*(BTN_H+BTN_S), BTN_KEYP_X+0*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+1*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+1*(BTN_W+BTN_S),BTN_KEYP_Y+1*(BTN_H+BTN_S), BTN_KEYP_X+1*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+1*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+2*(BTN_W+BTN_S),BTN_KEYP_Y+1*(BTN_H+BTN_S), BTN_KEYP_X+2*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+1*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+0*(BTN_W+BTN_S),BTN_KEYP_Y+2*(BTN_H+BTN_S), BTN_KEYP_X+0*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+2*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+1*(BTN_W+BTN_S),BTN_KEYP_Y+2*(BTN_H+BTN_S), BTN_KEYP_X+1*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+2*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+2*(BTN_W+BTN_S),BTN_KEYP_Y+2*(BTN_H+BTN_S), BTN_KEYP_X+2*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+2*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+0*(BTN_W+BTN_S),BTN_KEYP_Y+3*(BTN_H+BTN_S), BTN_KEYP_X+0*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+3*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+1*(BTN_W+BTN_S),BTN_KEYP_Y+3*(BTN_H+BTN_S), BTN_KEYP_X+1*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+3*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+2*(BTN_W+BTN_S),BTN_KEYP_Y+3*(BTN_H+BTN_S), BTN_KEYP_X+2*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+3*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+0*(BTN_W+BTN_S),BTN_KEYP_Y+4*(BTN_H+BTN_S), BTN_KEYP_X+0*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+4*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+1*(BTN_W+BTN_S),BTN_KEYP_Y+4*(BTN_H+BTN_S), BTN_KEYP_X+1*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+4*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+2*(BTN_W+BTN_S),BTN_KEYP_Y+4*(BTN_H+BTN_S), BTN_KEYP_X+2*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+4*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+0*(BTN_W+BTN_S),BTN_KEYP_Y+5*(BTN_H+BTN_S), BTN_KEYP_X+0*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+5*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+1*(BTN_W+BTN_S),BTN_KEYP_Y+5*(BTN_H+BTN_S), BTN_KEYP_X+1*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+5*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+2*(BTN_W+BTN_S),BTN_KEYP_Y+5*(BTN_H+BTN_S), BTN_KEYP_X+2*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+5*(BTN_H+BTN_S)+BTN_H }, }; const int KeypadCount = sizeof(UI_Keypad)/sizeof(UI_Keypad[0]); const char UI_KeyLabels[] = { '\x1B', '7', '8', '9', '4', '5', '6', '1', '2', '3', '0', '.', '-', '\x19', '\x18', '\xB6', }; const char KeyPadKeys[] = { '\x08', '7', '8', '9', '4', '5', '6', '1', '2', '3', '0', '.', '-', '<', '>', '\n' }; // ##### Settings ############################################################# // // +---------------------------------------------------------------------------+ // | Progam Name and version | // | Manufacturer name | // | Build Date | // | Signal Generator Mode | // | \ | / | // | ( * ) Continuous = O = | // | / | \ | // | ( ) One-Shot +--------+ | // | | | | // | | | | // | | | | // | | | | // | | | | // | |--------| | // | | | | // | [ ... ] | | | // | | | | // | | | | // | +--------+ | // +---------------------------------------------------------------------------+ const point_t suncenter = { 450,85 }; const rect_t sunray[] = { { 450-2, 85-25, 450+2, 85+25 }, { 450-25,85-2, 450+25,85+2 } }; const rect_t sungraph = { 450-18,120+0, 450+18,265+0 }; const rect_t inrgraph = { 450-16,120+2, 450+16,265-2 }; const rect_t SignalMode = { 20,50, 20+140,70 }; const char * SignalModeLabel = "Signal Mode"; const rect_t radio_Cycles[] = { { 40, 80, 40+120,100 }, { 40,110, 40+120,130 } }; const int radio_CyclesCount = sizeof(radio_Cycles)/sizeof(radio_Cycles[0]); const char * radio_CyclesLabels[] = { "Continuous", "One-Shot" }; #define UI_CyclesColor Green #define UI_CyclesBackColor RGB(0,0,0) // rect_t radio_Cycles[], radio_CyclesCount, char * radio_CyclesLabels[] #define PI 3.1415 // Handy value template <typename T> int sgn(T val) { return (T(0) < val) - (val < T(0)); } // ############################################################################# SignalGenDisplay::SignalGenDisplay(RA8875 * _lcd, SignalGenDAC * _signal, const char * _Path, const char * _ProgName, const char * _Manuf, const char * _Ver, const char * _Build) : lcd(_lcd), signal(_signal), Path(_Path), ProgName(_ProgName), Manuf(_Manuf), Ver(_Ver), Build(_Build) { char buf[50]; snprintf(buf, sizeof(buf), "%s/SigGen.ini", Path); ini.SetFile(buf, 2); needsInit = true; } SignalGenDisplay::~SignalGenDisplay() { } char SignalGenDisplay::GetTouchEvent(void) { TouchCode_t touch; touch = lcd->TouchPanelReadable(); // any touch to report? if (touch == no_touch) { timerForceTSCal.stop(); timerForceTSCal.reset(); } else { uint8_t id = lcd->TouchID(0); // 'id' tracks the individual touches TouchCode_t ev = lcd->TouchCode(0); // 'ev'ent indicates no_touch, touch, held, release, ... point_t point = lcd->TouchCoordinates(0); // and of course the (x,y) coordinates if (ev == touch) { timerRepeat.start(); timerRepeat.reset(); timerForceTSCal.start(); timerForceTSCal.reset(); } else if (ev == held && timerForceTSCal.read() > 10.0) { printf("Forcing T.S. Cal\r\n"); timerForceTSCal.stop(); timerForceTSCal.reset(); lcd->cls(); CalibrateTS(); Refresh(); } if ((ev == release) || (ev == held && timerRepeat.read_ms() > 250)) { timerRepeat.reset(); switch (vis) { case VS_MainScreen: // Start/Stop/Pulse if (textLen == 0 && ev == release) { if (lcd->Intersect(UI_START_STOP, point)) { printf("Start/Stop/Pulse %d - %d : %c\r\n", pulseMode, signal->isRunning(), StartStopKeys[pulseMode ? 2 : signal->isRunning()]); return StartStopKeys[pulseMode ? 2 : signal->isRunning()]; } } // Mode Keys touch if (ev == release) { for (int i=0; i<ModeCount; i++) { if (lcd->Intersect(ModeButtons[i], point)) { return ModeKeys[i]; } } } // Parameters if (ev == release) { for (int i=0; i<ParameterCount; i++) { if (lcd->Intersect(Parameters[i], point)) { return ParameterKeys[i]; } } } // Keypad if (1 || ev == release) { for (int i=0; i<KeypadCount; i++) { if (lcd->Intersect(UI_Keypad[i], point)) { return KeyPadKeys[i]; } } } if (ev == release) { if (lcd->Intersect(NavToSettings, point)) { vis = VS_Settings; Refresh(); while (lcd->TouchPanelReadable()) ; Thread::wait(100); } } break; case VS_Settings: Thread::wait(20); if (lcd->Intersect(sungraph, point)) { float bl = (float)(sungraph.p2.y - point.y)/(sungraph.p2.y - sungraph.p1.y); lcd->Backlight(rangelimit(bl, 0.1, 1.0)); SaveSettings(OM_BACKL); ShowBrightnessSetting(); } if (ev == release) { if (lcd->Intersect(NavToSettings, point)) { // Switch to main screen vis = VS_MainScreen; Refresh(); while (lcd->TouchPanelReadable()) ; Thread::wait(100); ShowMenu(); } } if (ev == release) { for (int i=0; i<radio_CyclesCount; i++) { if (lcd->Intersect(radio_Cycles[i], point)) { pulseMode = i; signal->Stop(); ShowCyclesControl(); } } } break; } } } return 0; } void SignalGenDisplay::Refresh() { if (needsInit) { char buf[100]; needsInit = false; vis = VS_MainScreen; // always start on main screen lcd->TouchPanelInit(); InitializeTS(); // Default the backlight ini.ReadString("Settings", "Backlight", buf, sizeof(buf), "60"); lcd->Backlight_u8(atoi(buf)); ini.ReadString("Signal", "Waveform", buf, sizeof(buf), ModeNames[0]); for (int i=0; i<ModeCount; i++) { if (strcmp(ModeNames[i], buf) == 0) { mode = (SG_Mode)i; printf("Read ini mode is %d\r\n", mode); break; } } ini.ReadString("Signal", "Duty Cycle", buf, sizeof(buf), "50"); dutycycle = atof(buf); ini.ReadString("Signal", "Frequency", buf, sizeof(buf), "1000"); frequency = atof(buf); ini.ReadString("Signal", "Voltage", buf, sizeof(buf), "3.0"); voltage = atof(buf); ini.ReadString("Signal", "Offset", buf, sizeof(buf), "1.5"); offset = atof(buf); ini.ReadString("Signal", "Pulse Mode", buf, sizeof(buf), radio_CyclesLabels[0]); for (int i=0; i<radio_CyclesCount; i++) { if (strcmp(radio_CyclesLabels[i], buf) == 0) { pulseMode = i; break; } } ShowMenu(); } switch (vis) { case VS_MainScreen: lcd->background(UI_BackColor); lcd->cls(1); lcd->SelectDrawingLayer(0); // Clear Screen lcd->SetLayerMode(RA8875::ShowLayer0); // Product Info lcd->foreground(UI_ProductNameColor); ShowProductInfo(); ClearScope(); resetDataEntry(); DrawNavGadget(); DrawModeButtons(); break; case VS_Settings: lcd->background(UI_BackColor); lcd->cls(2); lcd->SelectDrawingLayer(1); lcd->SetLayerMode(RA8875::ShowLayer1); lcd->foreground(UI_ProductNameColor); ShowProductInfo(true); ShowCyclesControl(); ShowBrightnessSetting(); DrawNavGadget(); break; } } // rect_t radio_Cycles[], radio_CyclesCount, char * radio_CyclesLabels[] void SignalGenDisplay::ShowCyclesControl(void) { lcd->fillrect(SignalMode, UI_CyclesBackColor); lcd->foreground(UI_CyclesColor); lcd->background(UI_CyclesBackColor); lcd->SetTextCursor(SignalMode.p1.x+1, SignalMode.p1.y+1); lcd->printf("%s", SignalModeLabel); for (int x=0; x<radio_CyclesCount; x++) { lcd->fillrect(radio_Cycles[x], UI_CyclesBackColor); lcd->foreground(UI_CyclesColor); lcd->background(UI_CyclesBackColor); lcd->SetTextCursor(radio_Cycles[x].p1.x+1,radio_Cycles[x].p1.y+1); lcd->printf("%c %s", (pulseMode == x) ? '\x07' : '\x09', radio_CyclesLabels[x]); } } void SignalGenDisplay::DrawModeButtons(void) { for (int i=0; i<ModeCount; i++) { DrawButton(ModeButtons[i], (UI_ModeList[i] == mode) ? true : false, UI_ModeList[i], true); } UpdateScope(); } void SignalGenDisplay::DrawNavGadget(void) { lcd->fillrect(NavToSettings, Black); lcd->SetTextCursor(NavToSettings.p1.x+1, NavToSettings.p1.y+1); lcd->foreground(White); lcd->background(Black); lcd->puts(" ..."); } void SignalGenDisplay::ShowProductInfo(bool builddate) { rect_t r = UI_PROD_RECT; lcd->window(r); lcd->SetTextCursor(r.p1.x, r.p1.y); lcd->printf("%s v%s", ProgName, Ver); lcd->SetTextCursor(r.p1.x, r.p1.y+16); lcd->printf("by %s", Manuf); if (builddate) { lcd->SetTextCursor(r.p1.x, r.p1.y+32); lcd->printf("%s", Build); } lcd->window(); } void SignalGenDisplay::ShowBrightnessSetting(void) { int i; // Sunbeam lcd->fillrect(sunray[0], White); lcd->fillrect(sunray[1], White); for (i=-2; i<=+2; i++) { lcd->line( (sunray[0].p1.x + sunray[1].p1.x)/2 - 5 + i, (sunray[0].p1.y + sunray[1].p1.y)/2 - 5 - i, (sunray[0].p2.x + sunray[1].p2.x)/2 + 5 + i, (sunray[0].p2.y + sunray[1].p2.y)/2 + 5 - i, White); lcd->line( (sunray[0].p2.x + sunray[1].p1.x)/2 - 5 + i, (sunray[0].p2.y + sunray[1].p1.y)/2 + 5 + i, (sunray[0].p1.x + sunray[1].p2.x)/2 + 5 + i, (sunray[0].p1.y + sunray[1].p2.y)/2 - 5 + i, White); } lcd->fillcircle(suncenter, 18, UI_BackColor); lcd->fillcircle(suncenter, 12, White); lcd->rect(sungraph, Blue); float bl = lcd->GetBacklight(); lcd->fillrect(inrgraph, UI_BackColor); lcd->fillrect(inrgraph.p1.x,inrgraph.p2.y, inrgraph.p2.x, inrgraph.p2.y - bl * (inrgraph.p2.y - inrgraph.p1.y), White); } void SignalGenDisplay::ShowMenu(void) { if (Manuf) { printf("\r\n%s v%s by %s build %s\r\n\r\n", ProgName, Ver, Manuf, Build); } printf(" Select: Signal:\r\n"); printf(" S: Sine Wave d: Duty Cycle\r\n"); printf(" Q: Square Wave f: Frequency\r\n"); printf(" T: Triangle Wave p: Period\r\n"); printf(" W: Sawtooth Wave v: Voltage\r\n"); printf(" U: User Wave o: Offset\r\n"); printf(" \r\n"); printf(" 0-9 . - : Numeric entry\r\n"); printf(" < > : Modify selected signal\r\n"); printf(" <bs>: Backspace entry\r\n"); printf(" ?: This help <cr>: Save number\r\n"); printf(" #: Dump RA8875 <esc>: Exit number entry\r\n"); //printf(" 4: Reverse sawtoothSignal\r\n"); printf(" Settings:\r\n"); printf(" Mode: %d - %s\r\n", mode, ModeNames[mode]); printf(" Freq: %f\r\n", frequency); printf(" Duty: %f\r\n", dutycycle); printf(" Volt: %f\r\n", voltage); printf(" Offs: %f\r\n", offset); printf(" Puls: %d - %s\r\n", pulseMode, radio_CyclesLabels[pulseMode]); } SignalGenDisplay::OM_Changes SignalGenDisplay::Poll(char c) { OM_Changes ret = OM_NONE; if (needsInit) Refresh(); // If Poll was the first API call, we need to init SaveSettings(); if (!c) { c = GetTouchEvent(); } if (c) { printf("%02X: EntryMd: %d, textLen: %d [%s] VIS: %d\r\n", c, EntryMd, textLen, textBuffer, vis); } /// 01234567890-. #?SQTW dfpvo < > <bs> <enter> <esc> switch (c) { case '#': printf("DumpRegisters for RA8875 unsupported\r\n"); //lcd->DumpRegisters(); break; case '?': ShowMenu(); break; case 'G': // Go is 'Start' signal->Start(false); ShowStartStop(true); break; case 'O': // Off signal->Stop(); ShowStartStop(true); break; case 'P': // 'P'ulse signal->Start(true); ShowStartStop(true); break; case 'S': if (mode != SG_SINE) SaveSettings(OM_MODE); SetWaveformMode(SG_SINE); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); //ret = SG_SINE; break; case 'Q': if (mode != SG_SQUARE) SaveSettings(OM_MODE); SetWaveformMode(SG_SQUARE); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); //ret = SG_SQUARE; break; case 'T': if (mode != SG_TRIANGLE) SaveSettings(OM_MODE); SetWaveformMode(SG_TRIANGLE); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); //ret = SG_TRIANGLE; break; case 'W': if (mode != SG_SAWTOOTH) SaveSettings(OM_MODE); SetWaveformMode(SG_SAWTOOTH); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); //ret = SG_SAWTOOTH; break; case 'U': if (mode != SG_USER) SaveSettings(OM_MODE); SetWaveformMode(SG_USER); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); //ret = SG_USER; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': case '-': if (EntryMd) { if (textLen<8) { textBuffer[textLen++] = c; textBuffer[textLen] = '\0'; updateTextWindow(); } } break; case '\x08': if (EntryMd) { if (textLen) { textLen--; textBuffer[textLen] = '\0'; updateTextWindow(); } if (textLen == 0) clearTextWindow(); } break; case '\x1B': textBuffer[0] = '\0'; textLen = 0; resetDataEntry(); break; case '\r': case '\n': if (EntryMd) { if (strlen(textBuffer)) { switch (EntryMd) { case OM_DUTY: SetDutyCycle(atof(textBuffer)); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_DUTY); break; case OM_FREQ: SetFrequency(atof(textBuffer)); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_FREQ); break; case OM_PERI: SetPeriod(atof(textBuffer)); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_FREQ); break; case OM_VOLT: SetVoltagePeakToPeak(atof(textBuffer)); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_VOLT); break; case OM_OFFS: SetVoltageOffset(atof(textBuffer)); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_OFFS); break; default: break; } } resetDataEntry(OM_NONE, true); } break; case '>': switch (EntryMd) { case OM_DUTY: SetDutyCycle(dutycycle + 1.0); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_DUTY); break; case OM_FREQ: SetFrequency(frequency + 1.0); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_FREQ); break; case OM_PERI: SetPeriod(1/frequency + 0.000001); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_FREQ); break; case OM_VOLT: SetVoltagePeakToPeak(voltage + 0.1); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_VOLT); break; case OM_OFFS: SetVoltageOffset(offset + 0.1); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_OFFS); break; default: break; } break; case '<': switch (EntryMd) { case OM_DUTY: SetDutyCycle(dutycycle - 1.0); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_DUTY); break; case OM_FREQ: SetFrequency(frequency - 1.0); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_FREQ); break; case OM_PERI: SetPeriod(1/frequency - 0.000001); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_FREQ); break; case OM_VOLT: SetVoltagePeakToPeak(voltage - 0.1); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_VOLT); break; case OM_OFFS: SetVoltageOffset(offset - 0.1); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); SaveSettings(OM_OFFS); break; default: break; } break; case 'd': if (EntryMd != OM_DUTY) { SaveSettings(EntryMd); resetDataEntry(OM_DUTY, true); updateDutyCycle(); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); } else { resetDataEntry(OM_NONE, true); } break; case 'f': if (EntryMd != OM_FREQ) { SaveSettings(EntryMd); resetDataEntry(OM_FREQ, true); updateFrequency(); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); } else { resetDataEntry(OM_NONE, true); } break; case 'p': if (EntryMd != OM_PERI) { SaveSettings(EntryMd); resetDataEntry(OM_PERI, true); updatePeriod(); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); } else { resetDataEntry(OM_NONE, true); } break; case 'v': if (EntryMd != OM_VOLT) { SaveSettings(EntryMd); resetDataEntry(OM_VOLT, true); updateVoltage(); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); } else { resetDataEntry(OM_NONE, true); } break; case 'o': if (EntryMd != OM_OFFS) { SaveSettings(EntryMd); resetDataEntry(OM_OFFS, true); updateOffset(); signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); } else { resetDataEntry(OM_NONE, true); } break; default: break; } return ret; } bool SignalGenDisplay::SetWaveformMode(SG_Mode _mode, bool force) { if (/* _mode >= SG_SINE && */ _mode <= SG_USER) { mode = _mode; printf("mode is %d\r\n", mode); DrawModeButtons(); return true; } else { return false; } } bool SignalGenDisplay::SetDutyCycle(float _dutyCycle) { if (_dutyCycle >= 5 && _dutyCycle <= 95) { dutycycle = _dutyCycle; updateDutyCycle(); UpdateScope(); return true; } else { return false; } } bool SignalGenDisplay::SetFrequency(float _frequency) { if (_frequency >= 1.0 && _frequency <= 1.0E6) { frequency = _frequency; updateFrequency(); updatePeriod(); UpdateScope(); return true; } else { return false; } } bool SignalGenDisplay::SetPeriod(float _period) { if (_period >= 1.0E-6 && _period <= 1.0) { frequency = 1/_period; updatePeriod(); updateFrequency(); UpdateScope(); return true; } else { return false; } } bool SignalGenDisplay::SetVoltagePeakToPeak(float _voltage) { if (_voltage >= 0.0 && _voltage <= 3.3) { voltage = _voltage; updateVoltage(); UpdateScope(); return true; } else { return false; } } bool SignalGenDisplay::SetVoltageOffset(float _voltage) { if (_voltage > -SG_MAX_V && _voltage < SG_MAX_V) { if (abs(_voltage) < 0.008) // if binary precision slips it, fix it _voltage = 0.0; offset = _voltage; updateOffset(); UpdateScope(); return true; } else { return false; } } // ######################## Private Methods past here ####################### void SignalGenDisplay::UpdateScope(void) { ClearScope(); rect_t r = UI_WAVE_RECT; float vPeakPos, vPeakNeg; dim_t waveHeight = (UI_WAVE_RECT.p2.y - UI_WAVE_RECT.p1.y); vPeakPos = rangelimit(offset + voltage/2, SG_MIN_V, SG_MAX_V); vPeakNeg = rangelimit(offset - voltage/2, SG_MIN_V, SG_MAX_V); loc_t markerPos_y = UI_WAVE_RECT.p2.y - vPeakPos/(SG_MAX_V-SG_MIN_V) * waveHeight; loc_t markerNeg_y = UI_WAVE_RECT.p2.y - vPeakNeg/(SG_MAX_V-SG_MIN_V) * waveHeight; loc_t df = rangelimit(offset, SG_MIN_V, SG_MAX_V) / SG_MAX_V * (r.p2.y - r.p1.y); loc_t y; lcd->SelectUserFont(BPG_Arial08x08); lcd->background(UI_ScopeBackColor); // Draw the Waveform rectangle lcd->rect(UI_WAVE_RECT, WaveOutlineColor); // Draw the Peak to Peak markers lcd->line(UI_WAVE_RECT.p1.x-3,markerPos_y, UI_WAVE_RECT.p2.x+3*SC_RIGHT_MARGIN/4,markerPos_y, UI_VP2PColor); lcd->line(UI_WAVE_RECT.p1.x-3,markerNeg_y, UI_WAVE_RECT.p2.x+3*SC_RIGHT_MARGIN/4,markerNeg_y, UI_VP2PColor); lcd->line(r.p2.x+3*SC_RIGHT_MARGIN/4-3,markerPos_y, r.p2.x+3*SC_RIGHT_MARGIN/4-3,markerNeg_y, UI_VP2PColor); // vert lcd->filltriangle( // top arrowhead r.p2.x+3*SC_RIGHT_MARGIN/4-3, markerPos_y, r.p2.x+3*SC_RIGHT_MARGIN/4-3+2,markerPos_y+3, r.p2.x+3*SC_RIGHT_MARGIN/4-3-2,markerPos_y+3, UI_VP2PColor); lcd->filltriangle( // bottom arrowhead r.p2.x+3*SC_RIGHT_MARGIN/4-3, markerNeg_y, r.p2.x+3*SC_RIGHT_MARGIN/4-3+2,markerNeg_y-3, r.p2.x+3*SC_RIGHT_MARGIN/4-3-2,markerNeg_y-3, UI_VP2PColor); lcd->SetTextCursor(r.p2.x+3*SC_RIGHT_MARGIN/4-3 - 10, markerPos_y - 9); lcd->printf("%3.2f", vPeakPos); lcd->SetTextCursor(r.p2.x+3*SC_RIGHT_MARGIN/4-3 - 10, markerNeg_y + 3); lcd->printf("%3.2f", vPeakNeg); // Draw the offset voltage markers y = r.p2.y - df; dim_t w = (r.p2.x + SC_RIGHT_MARGIN/3 - r.p1.x) / 35; for (int i=0; i<=35+1; i++) { // dashed line if ((i & 1) == 0) { lcd->line(r.p1.x + i * w,y, r.p1.x + (i+1) * w, y, UI_VOffsetColor); } } switch (sgn(offset)) { default: case 0: break; case -1: case 1: lcd->line(r.p2.x+SC_RIGHT_MARGIN/3-3,r.p2.y, r.p2.x+SC_RIGHT_MARGIN/3-3,y, UI_VOffsetColor); // vert lcd->filltriangle( r.p2.x+SC_RIGHT_MARGIN/3-3,y, r.p2.x+SC_RIGHT_MARGIN/3-3+2,y+sgn(offset)*3, r.p2.x+SC_RIGHT_MARGIN/3-3-2,y+sgn(offset)*3, UI_VOffsetColor); lcd->line(r.p2.x,r.p2.y, r.p2.x+SC_RIGHT_MARGIN/3,r.p2.y, UI_VOffsetColor); // horz break; } lcd->SetTextCursor(r.p2.x+SC_RIGHT_MARGIN/3-3 - 8, y - 10); lcd->printf("%3.2f", offset); // Draw the Frequency marker w = r.p2.x - r.p1.x; dim_t dc = dutycycle/100.0 * 1*w/2; lcd->line(r.p1.x,r.p1.y-3, r.p1.x,r.p2.y+3*SC_BOT_MARGIN/4, UI_FreqColor); lcd->line(r.p1.x+1*w/2,r.p1.y-3, r.p1.x+1*w/2,r.p2.y+3*SC_BOT_MARGIN/4, UI_FreqColor); lcd->line(r.p1.x,r.p2.y+3*SC_BOT_MARGIN/4-3, r.p1.x+1*w/2,r.p2.y+3*SC_BOT_MARGIN/4-3, UI_FreqColor); lcd->filltriangle( r.p1.x+0,r.p2.y+3*SC_BOT_MARGIN/4-3, r.p1.x+3,r.p2.y+3*SC_BOT_MARGIN/4-3-2, r.p1.x+3,r.p2.y+3*SC_BOT_MARGIN/4-3+2, UI_FreqColor); lcd->filltriangle( r.p1.x+1*w/2-0,r.p2.y+3*SC_BOT_MARGIN/4-3, r.p1.x+1*w/2-3,r.p2.y+3*SC_BOT_MARGIN/4-3-2, r.p1.x+1*w/2-3,r.p2.y+3*SC_BOT_MARGIN/4-3+2, UI_FreqColor); // Draw the Duty Cycle markers lcd->line(r.p1.x,r.p1.y-3, r.p1.x,r.p2.y+2*SC_BOT_MARGIN/4, UI_DutyColor); lcd->line(r.p1.x + dc,r.p1.y-3, r.p1.x + dc,r.p2.y+2*SC_BOT_MARGIN/4, UI_DutyColor); point_t p; p.x = r.p1.x; p.y = r.p2.y+2*SC_BOT_MARGIN/4-3; lcd->line(p.x,p.y, p.x+dc,p.y, UI_DutyColor); lcd->filltriangle( p.x,p.y, p.x+3,p.y-2, p.x+3,p.y+2, UI_DutyColor); p.x = r.p1.x + dc; lcd->filltriangle( p.x,p.y, p.x-3,p.y-2, p.x-3,p.y+2, UI_DutyColor); lcd->SetTextCursor(p.x + 3, p.y-4); float period = dutycycle/100*1/frequency; if (period < 0.001) lcd->printf("%8.3f uS", period * 1000000); else lcd->printf("%8.3f mS", period * 1000); lcd->SelectUserFont(); // restore DrawWaveform(r, mode, White); } // ++ +----+ + + // . . | | / \ / | // . + | | | / + / + | // . | | \ / / | // ++ +----+ + + + // void SignalGenDisplay::DrawWaveform(rect_t r, SG_Mode mode, color_t color, bool drawPure) { loc_t x,y; loc_t y0 = (r.p1.y + r.p2.y)/2; dim_t w = r.p2.x - r.p1.x; dim_t h = r.p2.y - r.p1.y; dim_t privDutyCycleX; dim_t a = (r.p2.y - r.p1.y)/2; float privVoltage = voltage; float privOffset = offset; float privDutyCycle = dutycycle; float vRange = SG_MAX_V - SG_MIN_V; float v; if (drawPure) { privVoltage = vRange; privOffset = vRange/2; privDutyCycle = 50; } privDutyCycleX = privDutyCycle/100.0 * 1*w/2; switch (mode) { case SG_SINE: for (int cycle=0; cycle<2; cycle++) { for (x=0; x<=privDutyCycleX; x++) { v = privOffset + privVoltage/2 * sin(x * 1 * PI / privDutyCycleX); v = rangelimit(v, SG_MIN_V, SG_MAX_V); y = r.p2.y - 2 * a * v / vRange; lcd->pixel(r.p1.x + cycle * w/2 + x, y, color); } for (x=0; x<=(w/2-privDutyCycleX); x++) { v = privOffset - privVoltage/2 * sin(x * 1 * PI / (w/2-privDutyCycleX)); v = rangelimit(v, SG_MIN_V, SG_MAX_V); y = r.p2.y - 2 * a * v / vRange; lcd->pixel(r.p1.x + cycle * w/2 + privDutyCycleX + x, y, color); } } break; case SG_SQUARE: for (int cycle=0; cycle<2; cycle++) { loc_t mid = r.p2.y - rangelimit(privOffset, SG_MIN_V, SG_MAX_V) / vRange * h; loc_t upp = r.p2.y - rangelimit(privOffset + privVoltage/2, SG_MIN_V, SG_MAX_V) / vRange * h; loc_t low = r.p2.y - rangelimit(privOffset - privVoltage/2, SG_MIN_V, SG_MAX_V) / vRange * h; lcd->line(r.p1.x+cycle*w/2+0*w/8, mid, r.p1.x+cycle*w/2+0*w/8, upp, color); // rise lcd->line(r.p1.x+cycle*w/2+0*w/8, upp, r.p1.x+cycle*w/2+privDutyCycleX, upp, color); // horz lcd->line(r.p1.x+cycle*w/2+privDutyCycleX, upp, r.p1.x+cycle*w/2+privDutyCycleX, low, color); // fall lcd->line(r.p1.x+cycle*w/2+privDutyCycleX, low, r.p1.x+cycle*w/2+4*w/8, low, color); // horz lcd->line(r.p1.x+cycle*w/2+4*w/8, low, r.p1.x+cycle*w/2+4*w/8, mid, color); // rise } break; case SG_TRIANGLE: for (int cycle=0; cycle<2; cycle++) { for (x=0; x<=privDutyCycleX; x++) { v = privVoltage * (float)x/privDutyCycleX; if (x < privDutyCycleX/2) v += privOffset; else v = privVoltage - (v - privOffset); y = r.p2.y - rangelimit(v, SG_MIN_V, SG_MAX_V) / vRange * h; lcd->pixel(r.p1.x + cycle * w/2 + x, y, color); } dim_t phaseWidth = (w/2 - privDutyCycleX); for (x=0; x<phaseWidth; x++) { v = privVoltage * (float)x/phaseWidth; if (x < phaseWidth/2) v = privOffset - v; else v = v + privOffset - privVoltage; y = r.p2.y - rangelimit(v, SG_MIN_V, SG_MAX_V) / vRange * h; lcd->pixel(r.p1.x + cycle * w/2 + privDutyCycleX + x, y, color); } } break; case SG_SAWTOOTH: for (int cycle=0; cycle<2; cycle++) { for (x=0; x<=privDutyCycleX; x++) { v = privVoltage/2 * (float)x/privDutyCycleX - privVoltage/2 + privOffset; y = r.p2.y - rangelimit(v, SG_MIN_V, SG_MAX_V) / vRange * h; lcd->pixel(r.p1.x + cycle * w/2 + x, y, color); } dim_t phaseWidth = (w/2 - privDutyCycleX); for (x=0; x<phaseWidth; x++) { v = privVoltage/2 * (float)x/phaseWidth + privOffset; y = r.p2.y - rangelimit(v, SG_MIN_V, SG_MAX_V) / vRange * h; lcd->pixel(r.p1.x + cycle * w/2 + privDutyCycleX + x, y, color); } loc_t y2 = r.p2.y - rangelimit(-privVoltage/2 + privOffset, SG_MIN_V, SG_MAX_V) / vRange * h; lcd->line(r.p1.x + cycle*w/2 + w/2 - 1, y, r.p1.x + cycle*w/2 + w/2, y2); } break; case SG_USER: lcd->line(r.p1.x, y0-1, r.p1.x+w, y0-1, color); lcd->line(r.p1.x, y0-0, r.p1.x+w, y0-0, color); lcd->line(r.p1.x, y0+1, r.p1.x+w, y0+1, color); lcd->rect(r.p1.x+5*w/8, y0-a/4, r.p1.x+7*w/8, y0+a/4, color); break; } } void SignalGenDisplay::ClearScope(void) { // Scope area rect_t r = UI_SCOPE_RECT; lcd->fillrect(r, UI_ScopeBackColor); lcd->rect(r, UI_ScopeFrameColor); } void SignalGenDisplay::updateDutyCycle(void) { rect_t r = Parameters[0]; // UI_DUTY_CYCLE_RECT; color_t fcolor, bcolor; if (EntryMd != OM_DUTY) { fcolor = UI_DutyColor; bcolor = UI_ScopeBackColor; } else { fcolor = UI_ScopeBackColor; bcolor = UI_DutyColor; } lcd->fillrect(r, bcolor); lcd->foreground(fcolor); lcd->background(bcolor); lcd->SetTextCursor(r.p1.x+1, r.p1.y+1); lcd->printf("%3.0f %%", dutycycle); } void SignalGenDisplay::updateFrequency(void) { rect_t r = Parameters[1]; // UI_FREQ_RECT; color_t fcolor, bcolor; if (EntryMd != OM_FREQ) { fcolor = UI_FreqColor; bcolor = UI_ScopeBackColor; } else { fcolor = UI_ScopeBackColor; bcolor = UI_FreqColor; } lcd->fillrect(r, bcolor); lcd->foreground(fcolor); lcd->background(bcolor); lcd->SetTextCursor(r.p1.x+1, r.p1.y+1); if (frequency >= 1000000.0) lcd->printf("%8.3f MHz", frequency/1000000); else if (frequency >= 1000.0) lcd->printf("%8.3f kHz", frequency/1000); else lcd->printf("%8.3f Hz ", frequency); } void SignalGenDisplay::updatePeriod(void) { float period = 1/frequency; rect_t r = Parameters[2]; // UI_PERIOD_RECT; color_t fcolor, bcolor; if (EntryMd != OM_PERI) { fcolor = UI_FreqColor; bcolor = UI_ScopeBackColor; } else { fcolor = UI_ScopeBackColor; bcolor = UI_FreqColor; } lcd->fillrect(r, bcolor); lcd->foreground(fcolor); lcd->background(bcolor); lcd->SetTextCursor(r.p1.x+1, r.p1.y+1); if (period < 0.001) lcd->printf("%8.3f uS", period * 1000000); else lcd->printf("%8.3f mS", period * 1000); } void SignalGenDisplay::updateVoltage(void) { rect_t r = Parameters[3]; // UI_VP2P_RECT; color_t fcolor, bcolor; if (EntryMd != OM_VOLT) { fcolor = UI_VP2PColor; bcolor = UI_ScopeBackColor; } else { fcolor = UI_ScopeBackColor; bcolor = UI_VP2PColor; } lcd->fillrect(r, bcolor); lcd->foreground(fcolor); lcd->background(bcolor); lcd->SetTextCursor(r.p1.x+1, r.p1.y+1); lcd->printf("%5.1f v", voltage); } void SignalGenDisplay::updateOffset(void) { rect_t r = Parameters[4]; // UI_VOFFSET_RECT; color_t fcolor, bcolor; if (EntryMd != OM_OFFS) { fcolor = UI_VOffsetColor; bcolor = UI_ScopeBackColor; } else { fcolor = UI_ScopeBackColor; bcolor = UI_VOffsetColor; } lcd->fillrect(r, bcolor); lcd->foreground(fcolor); lcd->background(bcolor); lcd->SetTextCursor(r.p1.x+1, r.p1.y+1); lcd->printf("%+4.2f v", offset); } void SignalGenDisplay::DrawKeypadEnabled(bool enable) { for (int i=0; i<KeypadCount; i++) { DrawButton(UI_Keypad[i], false, SG_KEYPAD, enable, i); } } void SignalGenDisplay::DrawButton(rect_t r, bool pressed, SG_Mode mode, bool enable, int label) { rect_t wave; color_t buttonface = UI_BUTTON_FACE_DISABLED; color_t buttonshadow = UI_BUTTON_SHADOW_DISABLED; //lcd->fillrect(r, UI_ScopeBackColor); if (pressed) { if (enable) { buttonface = UI_BUTTON_FACE_DN; buttonshadow = UI_BUTTON_SHADOW; } lcd->fillrect(r, buttonface); lcd->line(r.p1.x+0,r.p1.y+0, r.p2.x+0,r.p1.y+0, buttonshadow); // top border lcd->line(r.p1.x+1,r.p1.y+1, r.p2.x+0,r.p1.y+1, buttonshadow); // top border lcd->line(r.p1.x+2,r.p1.y+2, r.p2.x+0,r.p1.y+2, buttonshadow); // top border lcd->line(r.p1.x+0,r.p1.y+0, r.p1.x+0,r.p2.y+0, buttonshadow); // left border lcd->line(r.p1.x+1,r.p1.y+1, r.p1.x+1,r.p2.y+0, buttonshadow); // left border lcd->line(r.p1.x+2,r.p1.y+2, r.p1.x+2,r.p2.y+0, buttonshadow); // left border wave.p1.x = r.p1.x+5 + 2; wave.p1.y = r.p1.y + 5 + 2; wave.p2.x = r.p2.x-5 + 2; wave.p2.y = r.p2.y - 5 + 2; } else { if (enable) { buttonface = UI_BUTTON_FACE_UP; buttonshadow = UI_BUTTON_SHADOW; } lcd->fillrect(r, buttonface); lcd->line(r.p1.x+0,r.p2.y-0, r.p2.x-0,r.p2.y-0, buttonshadow); // bottom border lcd->line(r.p1.x+0,r.p2.y-1, r.p2.x-1,r.p2.y-1, buttonshadow); // bottom border lcd->line(r.p1.x+0,r.p2.y-2, r.p2.x-2,r.p2.y-2, buttonshadow); // bottom border lcd->line(r.p2.x-0,r.p1.y+0, r.p2.x-0,r.p2.y-0, buttonshadow); // right border lcd->line(r.p2.x-1,r.p1.y+0, r.p2.x-1,r.p2.y-1, buttonshadow); // right border lcd->line(r.p2.x-2,r.p1.y+0, r.p2.x-2,r.p2.y-2, buttonshadow); // right border wave.p1.x = r.p1.x+5 + 0; wave.p1.y = r.p1.y + 5 + 0; wave.p2.x = r.p2.x-5 + 0; wave.p2.y = r.p2.y - 5 + 0; } switch (mode) { case SG_SINE: case SG_SQUARE: case SG_TRIANGLE: case SG_SAWTOOTH: case SG_USER: DrawWaveform(wave, mode, Black, true); break; case SG_KEYPAD: lcd->foreground(Black); lcd->background(buttonface); lcd->SetTextCursor((r.p1.x+r.p2.x)/2 - 4,r.p1.y + BTN_H/2 - 8); // 8x16 char lcd->putc(UI_KeyLabels[label]); break; case SG_START: lcd->foreground(Black); lcd->background(buttonface); lcd->SetTextCursor((r.p1.x+r.p2.x)/2 - 4 * strlen(UI_StartLabels[label]),r.p1.y + BTN_H/2 - 8); lcd->puts(UI_StartLabels[label]); break; } } void SignalGenDisplay::ShowStartStop(bool showIt) { if (textLen == 0) { lcd->fillrect(UI_START_STOP, UI_BackColor); if (showIt) { DrawButton(UI_START_STOP, signal->isRunning(), SG_START, true, pulseMode ? 2 : signal->isRunning()); } } } void SignalGenDisplay::updateTextWindow(void) { ShowStartStop(false); lcd->window(UI_DATA_ENTRY); lcd->fillrect(UI_DATA_ENTRY, White); lcd->foreground(Black); lcd->background(White); lcd->SetTextCursor(UI_DATA_ENTRY.p1.x+1,UI_DATA_ENTRY.p1.y+1); lcd->printf("%13s", textBuffer); lcd->window(); } void SignalGenDisplay::clearTextWindow(void) { lcd->fillrect(UI_DATA_ENTRY, UI_BackColor); textBuffer[0] = '\0'; textLen = 0; ShowStartStop(true); } float SignalGenDisplay::rangelimit(float value, float min, float max) { if (value < min) return min; else if (value > max) return max; else return value; } void SignalGenDisplay::SaveSettings(OM_Changes reportMode) { char buf[20]; if (reportMode != OM_NONE) { Changes |= reportMode; printf("SaveSettings - reset timer [%02X]\r\n", Changes); timerSave.reset(); timerSave.start(); } else if (timerSave.read() > SAVE_AFTER_IDLE_S) { timerSave.stop(); timerSave.reset(); printf("SaveSettings - timeout [%02X]\r\n", Changes); if (Changes & OM_MODE) { Changes &= ~ OM_MODE; ini.WriteString("Signal", "Waveform", ModeNames[mode]); } if (Changes & OM_FREQ) { Changes &= ~ OM_FREQ; snprintf(buf, sizeof(buf),"%5.3f", frequency); printf(" Signal:Frequency=%s\r\n", buf); ini.WriteString("Signal", "Frequency", buf); } if (Changes & OM_PERI) { Changes &= ~ OM_PERI; snprintf(buf, sizeof(buf),"%5.3f", frequency); printf(" Signal:Frequency=%s\r\n", buf); ini.WriteString("Signal", "Frequency", buf); } if (Changes & OM_DUTY) { Changes &= ~ OM_DUTY; snprintf(buf, sizeof(buf),"%1.0f", dutycycle); printf(" Signal:Duty Cycle=%s\r\n", buf); ini.WriteString("Signal", "Duty Cycle", buf); } if (Changes & OM_VOLT) { Changes &= ~ OM_VOLT; snprintf(buf, sizeof(buf),"%3.2f", voltage); printf(" Signal:Voltage=%s\r\n", buf); ini.WriteString("Signal", "Voltage", buf); } if (Changes & OM_OFFS) { Changes &= ~ OM_OFFS; snprintf(buf, sizeof(buf),"%3.2f", offset); printf(" Signal:Offset=%s\r\n", buf); ini.WriteString("Signal", "Offset", buf); } if (Changes & OM_BACKL) { Changes &= ~OM_BACKL; snprintf(buf, sizeof(buf), "%d", lcd->GetBacklight_u8()); ini.WriteString("Settings", "Backlight", buf); } } } void SignalGenDisplay::resetDataEntry(OM_Changes nextMode, bool save) { OM_Changes last = EntryMd; printf("-> resetDataEntry(next: %d) curr:%d, save:%d\r\n", nextMode, last, save); EntryMd = nextMode; if (last != OM_NONE) signal->PrepareWaveform(mode, frequency, dutycycle, voltage, offset); switch (last) { case OM_NONE: updateDutyCycle(); updateFrequency(); updatePeriod(); updateVoltage(); updateOffset(); break; case OM_DUTY: updateDutyCycle(); if (save) { SaveSettings(OM_DUTY); } break; case OM_FREQ: updateFrequency(); if (save) { SaveSettings(OM_FREQ); } break; case OM_PERI: updatePeriod(); if (save) { SaveSettings(OM_FREQ); } break; case OM_VOLT: updateVoltage(); if (save) { SaveSettings(OM_VOLT); } break; case OM_OFFS: updateOffset(); if (save) { SaveSettings(OM_OFFS); } break; default: break; } DrawKeypadEnabled(EntryMd != OM_NONE); if (EntryMd == OM_NONE) { clearTextWindow(); } printf("<- end resetDataEntry()\r\n"); } // Calibrate the resistive touch screen, and store the data on the // local file system. // void SignalGenDisplay::CalibrateTS(void) { FILE * fh; tpMatrix_t matrix; RetCode_t r; Timer testperiod; char buf[100]; r = lcd->TouchPanelCalibrate("Calibrate the touch panel", &matrix); if (r == noerror) { snprintf(buf, sizeof(buf), "%s/tpcal.cfg", Path); fh = fopen(buf, "wb"); if (fh) { fwrite(&matrix, sizeof(tpMatrix_t), 1, fh); fclose(fh); printf(" %s cal written.\r\n", buf); lcd->cls(); } else { printf(" couldn't open %s file.\r\n", buf); } } else { printf("error return: %d\r\n", r); } lcd->cls(); } // Try to load a previous resistive touch screen calibration from storage. If it // doesn't exist, activate the touch screen calibration process. // void SignalGenDisplay::InitializeTS(void) { FILE * fh; tpMatrix_t matrix; char buf[100]; snprintf(buf, sizeof(buf), "%s/tpcal.cfg", Path); fh = fopen(buf, "rb"); if (fh) { fread(&matrix, sizeof(tpMatrix_t), 1, fh); fclose(fh); lcd->TouchPanelSetMatrix(&matrix); printf(" tp cal loaded.\r\n"); } else { CalibrateTS(); } }