![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Signal Generator
Dependencies: IniManager RA8875 Watchdog mbed-rtos mbed
Fork of speaker_demo_Analog by
SignalGenDisplay.cpp
- Committer:
- WiredHome
- Date:
- 2017-01-13
- Revision:
- 1:dd07e1deec6c
- Child:
- 2:8f71b71fce1b
File content as of revision 1:dd07e1deec6c:
#include "SignalGenDisplay.h" #include "rtos.h" #include "IniManager.h" extern INI ini; // ##### Main Page ############################################################# // // +---------------------------------------------------------------------------+ // | +------------------------------------------+ Progam Name and version | // | | | Manufacturer name | // | | | | // | | | [ Text Entry Box ] | // | | Scope Area | +------------------------+ | // | | | | | | // | | | | | | // | | | | | | // | | | | | | // | | | | | | // | | | | Keypad Area | | // | +------------------------------------------+ | | | // | | | | // | [duty cycle] [frequency] [amplitude] | | | // | | | | // | [ ... ] [period ] [offset ] | | | // | | | | // | [ ] [ ] [ ] [ ] [ ] | | | // | [Sine ] [Square] [Triangle] [Sawtooth] [User] +------------------------+ | // +---------------------------------------------------------------------------+ #define UI_BackColor RGB(8,8,8) const rect_t UI_DATA_ENTRY = {300,45, 475,65}; const rect_t UI_SCOPE_RECT = {4,5, 290,160}; #define UI_ScopeBackColor RGB(0,0,0) #define UI_ScopeFrameColor RGB(255,255,255) #define SC_LEFT_MARGIN 10 #define SC_TOP_MARGIN 20 #define SC_RIGHT_MARGIN 30 #define SC_BOT_MARGIN 30 #define WaveOutlineColor RGB(16,16,32) 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' }; #define UI_DutyColor Magenta #define UI_FreqColor BrightRed #define UI_VP2PColor DarkBrown #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) const rect_t UI_PROD_RECT = {298,3, 479,40}; #define UI_ProductNameColor UI_BUTTON_FACE_DN // RGB(192,192,192) #define PI 3.1415 #define BTN_W 54 #define BTN_H 35 #define BTN_S 5 // space #define BTN_MODE_X 2 #define BTN_MODE_Y 230 #define BTN_KEYP_X 300 #define BTN_KEYP_Y 70 const rect_t NavToSettings = { 4,200, 60,220 }; const rect_t UI_Buttons[] = { { 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 ButtonCount = sizeof(UI_Buttons)/sizeof(UI_Buttons[0]); SignalGenDisplay::SG_Mode UI_ModeList[] = { SignalGenDisplay::SG_SINE, SignalGenDisplay::SG_SQUARE, SignalGenDisplay::SG_TRIANGLE, SignalGenDisplay::SG_SAWTOOTH, SignalGenDisplay::SG_USER, }; const char ModeKeys[] = { 'S','Q','T','W','U' }; const rect_t UI_Keypad[] = { {BTN_KEYP_X+0*(BTN_W+BTN_S),BTN_KEYP_Y+0*(BTN_H+BTN_S), BTN_KEYP_X+0*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+0*(BTN_H+BTN_S)+BTN_H }, {BTN_KEYP_X+1*(BTN_W+BTN_S),BTN_KEYP_Y+0*(BTN_H+BTN_S), BTN_KEYP_X+1*(BTN_W+BTN_S)+BTN_W,BTN_KEYP_Y+0*(BTN_H+BTN_S)+BTN_H }, {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 }, {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 }, }; const int KeypadCount = sizeof(UI_Keypad)/sizeof(UI_Keypad[0]); const char UI_KeyLabels[] = { '7', '8', '9', '4', '5', '6', '1', '2', '3', '0', '.', '-', '\x1F', '\x1E', '\xB6', }; const char KeyPadKeys[] = { '7', '8', '9', '4', '5', '6', '1', '2', '3', '0', '.', '-', '<', '>', '\n' }; // ##### Settings ############################################################# // // +---------------------------------------------------------------------------+ // | Progam Name and version | // | Manufacturer name | // | | // | | // | | // | | // | +--------+ | // | | | | // | | | | // | | | | // | | | | // | | | | // | | | | // | |--------| | // | | | | // | [ ... ] | | | // | | | | // | | | | // | +--------+ | // +---------------------------------------------------------------------------+ const point_t suncenter = { 450,65 }; const rect_t sunray[] = { { 450-2,65-25, 450+2,65+25 }, { 450-25,65-2, 450+25,65+2 } }; const rect_t sungraph = { 450-20,100+0, 450+20,265+0 }; const rect_t inrgraph = { 450-18,100+2, 450+18,265-2 }; template <typename T> int sgn(T val) { return (T(0) < val) - (val < T(0)); } char SignalGenDisplay::GetTouchEvent(void) { TouchCode_t touch; touch = lcd->TouchPanelReadable(); // any touch to report? if (touch) { 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) { timer.start(); timer.reset(); } if ((ev == release) || (ev == held && timer.read_ms() > 250)) { timer.reset(); switch (vis) { case VS_MainScreen: printf("touch [vis: %d] (%d,%d)\r\n", vis, point.x, point.y); // Mode Keys touch for (int i=0; i<ButtonCount; i++) { if (lcd->Intersect(UI_Buttons[i], point)) { return ModeKeys[i]; } } // Parameters for (int i=0; i<ParameterCount; i++) { if (lcd->Intersect(Parameters[i], point)) { return ParameterKeys[i]; } } // Keypad for (int i=0; i<KeypadCount; i++) { if (lcd->Intersect(UI_Keypad[i], point)) { return KeyPadKeys[i]; } } if (lcd->Intersect(NavToSettings, point)) { printf("Nav\r\n"); vis = VS_Settings; Init(); while (lcd->TouchPanelReadable()) ; Thread::wait(100); } break; case VS_Settings: Thread::wait(20); printf("touch [VIS: %d\r\n", vis); 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)); ShowBrightnessSetting(); } if (lcd->Intersect(NavToSettings, point)) { // Save settings char buf[20]; snprintf(buf, sizeof(buf), "%d", lcd->GetBacklight_u8()); ini.WriteString("Settings", "Backlight", buf); // Switch to main screen vis = VS_MainScreen; Init(); while (lcd->TouchPanelReadable()) ; Thread::wait(100); ShowMenu(); } break; } } } return 0; } SignalGenDisplay::SignalGenDisplay(RA8875 * _lcd, SignalGenerator * _signal, const char * _ProgName, const char * _Manuf, const char * _Ver, const char * _Build) : lcd(_lcd), signal(_signal), ProgName(_ProgName), Manuf(_Manuf), Ver(_Ver), Build(_Build) { vis = VS_MainScreen; } SignalGenDisplay::~SignalGenDisplay() { } void SignalGenDisplay::Init() { 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(); // Some defaults for testing SetDutyCycle(30); SetFrequency(1230.0); SetVoltagePeakToPeak(3.0); SetVoltageOffset(1.50); resetDataEntry(); SelectWaveformMode(SignalGenDisplay::SG_SINE); DrawKeypadEnabled(false); DrawNavGadget(); break; case VS_Settings: lcd->background(UI_BackColor); lcd->cls(2); lcd->SelectDrawingLayer(1); lcd->SetLayerMode(RA8875::ShowLayer1); lcd->foreground(UI_ProductNameColor); ShowProductInfo(); ShowBrightnessSetting(); DrawNavGadget(); break; } } 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(void) { 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); lcd->window(); } void SignalGenDisplay::ShowBrightnessSetting(void) { // Sunbeam lcd->fillrect(sunray[0], White); lcd->fillrect(sunray[1], White); lcd->fillcircle(suncenter, 18, UI_BackColor); lcd->fillcircle(suncenter, 15, 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); } SignalGenDisplay::SG_Changes SignalGenDisplay::Poll(char c) { SG_Changes ret = SG_NONE; if (!c) { c = GetTouchEvent(); } if (c) { printf("%02X: EntryMd: %d, textLen: %d [%s] VIS: %d\r\n", c, EntryMd, textLen, textBuffer, vis); } /// - 'd' duty cycle entry /// - 'f' frequency entry /// - 'p' period entry /// - 'v' voltage entry /// - 'o' offset voltage entry /// - '0'-'9','.' numeric entry /// - <enter> complete numeric entry /// - <esc> abandon numeric entry /// - <nul> do nothing, just poll switch (c) { case '?': ShowMenu(); break; case 'S': SelectWaveformMode(SG_SINE); signal->SetSignalFrequency(SignalGenerator::SinusSignal, frequency); //ret = SG_SINE; break; case 'Q': SelectWaveformMode(SG_SQUARE); signal->SetSignalFrequency(SignalGenerator::SquareSignal, frequency); //ret = SG_SQUARE; break; case 'T': SelectWaveformMode(SG_TRIANGLE); signal->SetSignalFrequency(SignalGenerator::TriangleSignal, frequency); //ret = SG_TRIANGLE; break; case 'W': SelectWaveformMode(SG_SAWTOOTH); signal->SetSignalFrequency(SignalGenerator::SawtoothSignal, frequency); //ret = SG_SAWTOOTH; break; case 'U': SelectWaveformMode(SG_USER); //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(); } } break; case '\x1B': textBuffer[0] = '\0'; textLen = 0; EntryMd = SG_NONE; resetDataEntry(); break; case '\r': case '\n': if (EntryMd) { if (strlen(textBuffer)) { switch (EntryMd) { case SG_DUTY: SetDutyCycle(atof(textBuffer)); break; case SG_FREQ: SetFrequency(atof(textBuffer)); break; case SG_PERI: SetPeriod(atof(textBuffer)); break; case SG_VOLT: SetVoltagePeakToPeak(atof(textBuffer)); break; case SG_OFFS: SetVoltageOffset(atof(textBuffer)); break; default: break; } } EntryMd = SG_NONE; resetDataEntry(); } break; case '>': switch (EntryMd) { case SG_DUTY: SetDutyCycle(dutycycle + 1.0); break; case SG_FREQ: SetFrequency(frequency + 1.0); break; case SG_PERI: SetPeriod(1/frequency + 0.001); break; case SG_VOLT: SetVoltagePeakToPeak(voltage + 0.1); break; case SG_OFFS: SetVoltageOffset(offset + 0.01); break; default: break; } break; case '<': switch (EntryMd) { case SG_DUTY: SetDutyCycle(dutycycle - 1.0); break; case SG_FREQ: SetFrequency(frequency - 1.0); break; case SG_PERI: SetPeriod(1/frequency - 0.001); break; case SG_VOLT: SetVoltagePeakToPeak(voltage - 0.1); break; case SG_OFFS: SetVoltageOffset(offset - 0.01); break; default: break; } break; case 'd': if (EntryMd != SG_DUTY) { resetDataEntry(); EntryMd = SG_DUTY; DrawKeypadEnabled(true); updateDutyCycle(); } else { EntryMd = SG_NONE; resetDataEntry(); } break; case 'f': if (EntryMd != SG_FREQ) { resetDataEntry(); EntryMd = SG_FREQ; DrawKeypadEnabled(true); updateFrequency(); } else { EntryMd = SG_NONE; resetDataEntry(); } break; case 'p': if (EntryMd != SG_PERI) { resetDataEntry(); EntryMd = SG_PERI; DrawKeypadEnabled(true); updatePeriod(); } else { EntryMd = SG_NONE; resetDataEntry(); } break; case 'v': if (EntryMd != SG_VOLT) { resetDataEntry(); EntryMd = SG_VOLT; DrawKeypadEnabled(true); updateVoltage(); } else { EntryMd = SG_NONE; resetDataEntry(); } break; case 'o': if (EntryMd != SG_OFFS) { resetDataEntry(); EntryMd = SG_OFFS; DrawKeypadEnabled(true); updateOffset(); } else { EntryMd = SG_NONE; resetDataEntry(); } break; default: break; } return ret; } bool SignalGenDisplay::SelectWaveformMode(SG_Mode _mode) { if (/* _mode >= SG_SINE && */ _mode <= SG_USER) { mode= _mode; for (int i=0; i<ButtonCount; i++) { DrawButton(UI_Buttons[i], (UI_ModeList[i] == mode) ? true : false, UI_ModeList[i], true); } UpdateScope(); 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) { printf("-> SetFrequency(%f)\r\n", _frequency); if (_frequency >= 1.0 && _frequency <= 1.0E6) { frequency = _frequency; updateFrequency(); updatePeriod(); UpdateScope(); printf(" end SetFrequency\r\n"); return true; } else { printf(" end SetFrequency - out of range\r\n"); 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 >= -1.65 && _voltage <= 1.65) { 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) { printf("-> UpdateScope()\r\n"); ClearScope(); rect_t r; r.p1.x = UI_SCOPE_RECT.p1.x + SC_LEFT_MARGIN; r.p1.y = UI_SCOPE_RECT.p1.y + SC_TOP_MARGIN; r.p2.x = UI_SCOPE_RECT.p2.x - SC_RIGHT_MARGIN; r.p2.y = UI_SCOPE_RECT.p2.y - SC_BOT_MARGIN; lcd->rect(r, WaveOutlineColor); // Draw the Peak to Peak markers lcd->line(r.p1.x,r.p1.y, r.p2.x+3*SC_RIGHT_MARGIN/4,r.p1.y, UI_VP2PColor); lcd->line(r.p1.x,r.p2.y, r.p2.x+3*SC_RIGHT_MARGIN/4,r.p2.y, UI_VP2PColor); lcd->line(r.p2.x+3*SC_RIGHT_MARGIN/4-3,r.p1.y, r.p2.x+3*SC_RIGHT_MARGIN/4-3,r.p2.y, UI_VP2PColor); lcd->filltriangle( r.p2.x+3*SC_RIGHT_MARGIN/4-3,r.p1.y, r.p2.x+3*SC_RIGHT_MARGIN/4-3+2,r.p1.y+3, r.p2.x+3*SC_RIGHT_MARGIN/4-3-2,r.p1.y+3, UI_VP2PColor); lcd->filltriangle( r.p2.x+3*SC_RIGHT_MARGIN/4-3,r.p2.y, r.p2.x+3*SC_RIGHT_MARGIN/4-3+2,r.p2.y-3, r.p2.x+3*SC_RIGHT_MARGIN/4-3-2,r.p2.y-3, UI_VP2PColor); // Draw the offset voltage markers loc_t y = (r.p1.y + r.p2.y)/2; dim_t w = (r.p2.x + SC_RIGHT_MARGIN/3 - r.p1.x) / 35; dim_t h = (r.p2.y - r.p1.y); for (int i=0; i<=35+1; i++) { 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,y+sgn(offset)*(h/2+7), r.p2.x+SC_RIGHT_MARGIN/3-3,y, UI_VOffsetColor); 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); if (abs(offset) > voltage/2) lcd->line(r.p1.x,y+sgn(offset)*(h/2+7), r.p2.x+SC_RIGHT_MARGIN/3,y+sgn(offset)*(h/2+7), UI_VOffsetColor); else lcd->line(r.p1.x,y+(offset/voltage)*h, r.p2.x+SC_RIGHT_MARGIN/3,y+(offset/voltage)*h, UI_VOffsetColor); break; } // 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, r.p1.x,r.p2.y+3*SC_BOT_MARGIN/4, UI_FreqColor); lcd->line(r.p1.x+1*w/2,r.p1.y, 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, r.p1.x,r.p2.y+2*SC_BOT_MARGIN/4, UI_DutyColor); lcd->line(r.p1.x + dc,r.p1.y, 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); DrawWaveform(r, mode, White); printf(" end UpdateScope()\r\n"); } // ++ +----+ + + // . . | | / \ /| // . . | | | / \ / / | // . | | \ / / | // ++ +----+ + + + // void SignalGenDisplay::DrawWaveform(rect_t r, SG_Mode mode, color_t color, float dutycycleOverride) { 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 dc = ((dutycycleOverride >= 5.0) ? dutycycleOverride : dutycycle)/100.0 * 1*w/2; dim_t a = (r.p2.y - r.p1.y)/2; float v; switch (mode) { case SG_SINE: for (int cycle=0; cycle<2; cycle++) { for (x=0; x<=dc; x++) { v = offset + voltage/2 * sin(x * 1 * PI / dc); v = rangelimit(v, SG_MIN_V, SG_MAX_V); y = r.p2.y - 2 * a * v / SG_AOUT_FS; lcd->pixel(r.p1.x + cycle * w/2 + x, y, color); } for (x=0; x<=(w/2-dc); x++) { v = offset - voltage/2 * sin(x * 1 * PI / (w/2-dc)); v = rangelimit(v, SG_MIN_V, SG_MAX_V); y = r.p2.y - 2 * a * v / SG_AOUT_FS; lcd->pixel(r.p1.x + cycle * w/2 + dc + x, y, color); } } break; case SG_SQUARE: for (int cycle=0; cycle<2; cycle++) { lcd->line(r.p1.x+cycle*w/2+0*w/8, y0, r.p1.x+cycle*w/2+0*w/8, y0-a, color); // rise lcd->line(r.p1.x+cycle*w/2+0*w/8, y0-a, r.p1.x+cycle*w/2+dc, y0-a, color); // horz lcd->line(r.p1.x+cycle*w/2+dc, y0-a, r.p1.x+cycle*w/2+dc, y0+a, color); // fall lcd->line(r.p1.x+cycle*w/2+dc, y0+a, r.p1.x+cycle*w/2+4*w/8, y0+a, color); // horz lcd->line(r.p1.x+cycle*w/2+4*w/8, y0+a, r.p1.x+cycle*w/2+4*w/8, y0, color); // rise } break; case SG_TRIANGLE: for (int cycle=0; cycle<2; cycle++) { lcd->line(r.p1.x+cycle*w/2+0*w/8, y0+0, r.p1.x+cycle*w/2+dc/2, y0-a, color); // rise 2 lcd->line(r.p1.x+cycle*w/2+dc/2, y0-a, r.p1.x+cycle*w/2+dc/1, y0, color); // fall 1 lcd->line(r.p1.x+cycle*w/2+dc/1, y0, r.p1.x+cycle*w/2+(w/2+dc)/2, y0+a, color); // fall 2 lcd->line(r.p1.x+cycle*w/2+(w/2+dc)/2, y0+a, r.p1.x+cycle*w/2+4*w/8, y0, color); // rise 1 } break; case SG_SAWTOOTH: for (int cycle=0; cycle<2; cycle++) { lcd->line(r.p1.x+cycle*w/2+0*w/8+0, y0+a, r.p1.x+cycle*w/2+dc, y0, color); lcd->line(r.p1.x+cycle*w/2+dc, y0, r.p1.x+cycle*w/2+4*w/8-1, y0-a, color); lcd->line(r.p1.x+cycle*w/2+4*w/8-1, y0-a, r.p1.x+cycle*w/2+4*w/8, y0+a, color); } 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 != SG_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 != SG_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); printf("EntryMode: %d, bg: %08X, fg: %08X\r\n", EntryMd, bcolor, fcolor); 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 != SG_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 != SG_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 != SG_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, 50.0); 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; } } void SignalGenDisplay::updateTextWindow(void) { 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("%21s", textBuffer); lcd->window(); } 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::ShowMenu(void) { if (Manuf) { printf("\r\n%s v%s by %s build %s\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(" <cr>: Save number\r\n"); printf(" <esc>: Exit number entry\r\n"); //printf(" 4: Reverse sawtoothSignal\r\n"); } void SignalGenDisplay::resetDataEntry(void) { SG_Changes last = EntryMd; printf("-> resetDataEntry()\r\n"); EntryMd = SG_NONE; switch (last) { case SG_NONE: updateDutyCycle(); updateFrequency(); updatePeriod(); updateVoltage(); updateOffset(); lcd->fillrect(UI_DATA_ENTRY, UI_BackColor); textBuffer[0] = '\0'; textLen = 0; break; case SG_DUTY: updateDutyCycle(); break; case SG_FREQ: updateFrequency(); break; case SG_PERI: updatePeriod(); break; case SG_VOLT: updateVoltage(); break; case SG_OFFS: updateOffset(); break; default: break; } DrawKeypadEnabled(false); printf(" end resetDataEntry()\r\n"); }