Signal Generator
Dependencies: IniManager RA8875 Watchdog mbed-rtos mbed
Fork of speaker_demo_Analog by
Revision 1:dd07e1deec6c, committed 2017-01-13
- Comitter:
- WiredHome
- Date:
- Fri Jan 13 12:33:37 2017 +0000
- Parent:
- 0:1c8118ee4106
- Child:
- 2:8f71b71fce1b
- Commit message:
- Added settings screen, started revising the scope layout
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IniManager.lib Fri Jan 13 12:33:37 2017 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/WiredHome/code/IniManager/#392d1ec637eb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RA8875.lib Fri Jan 13 12:33:37 2017 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/WiredHome/code/RA8875/#33ca352755a2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SignalGenDisplay.cpp Fri Jan 13 12:33:37 2017 +0000 @@ -0,0 +1,1011 @@ + +#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"); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SignalGenDisplay.h Fri Jan 13 12:33:37 2017 +0000 @@ -0,0 +1,218 @@ + +#ifndef SIGNALGENDISPLAY_H +#define SIGNALGENDISPLAY_H + +#include "mbed.h" +#include "RA8875.h" +#include "SignalGenerator.h" + +#define SG_MIN_V 0.0 // Constraint, to match to the hardware +#define SG_MAX_V 3.3 // +#define SG_AOUT_FS 3.3 // Analog output full scale + +class SignalGenDisplay { +public: + /// Constructor for the Signal Generator User Interface. + /// + /// @param[in] lcd is a pointer to the Graphics Display + /// @param[in] signal is a handle to the signal generator + /// @param[in] ProgrName is a pointer to a constant string + /// @param[in] Manuf is a pointer to a constant string + /// @param[in] Ver is a pointer to a constant string + /// @param[in] Build is a pointer to a constant string + /// + SignalGenDisplay(RA8875 * lcd, SignalGenerator * signal, + const char * ProgName, const char * Manuf, const char * Ver, + const char * Build); + + /// Destructor + //// + ~SignalGenDisplay(); + + /// Initialization to present the initial display + /// + /// As part of the display initialization, it also shows + /// program information. + /// + void Init(void); + + /// Set the frequency information + /// + /// This automatically sets the period as 1/frequency + /// + /// @param[in] frequency desired + /// @returns true if the value was accepted + /// + bool SetFrequency(float frequency); + + /// Get the current frequency setting + /// + /// @returns current frequency + /// + float GetFrequency(void) { return frequency; } + + /// Set the period instead of the frequency + /// + /// This automatically sets the frequency as 1/period + /// + /// @param[in] period desired + /// @returns true if the value was accepted + /// + bool SetPeriod(float period); + + /// Get the current period + /// + /// @returns current period + /// + float GetPeriod(void) { return 1/frequency; } + + /// Set the Duty Cycle + /// + /// This adjusts the duty cycle of the waveform + /// + /// @param[in] dutyCycle is a value ranging from 0 to 100. + /// @returns true if the value was accepted + /// + bool SetDutyCycle(float dutyCycle); + + /// Get the current duty cycle + /// + /// @returns the duty cycle + /// + float GetDutyCycle(void) { return dutycycle; } + + /// Set the peak-to-peak voltage of the of the waveform + /// + /// In the range of 0 to 3.3v + /// + /// @param[in] voltage is the peak to peak voltage + /// @returns true if the value was accepted + /// + bool SetVoltagePeakToPeak(float voltage); + + /// Get the Peak to Peak voltage + /// + /// @returns peak to peak voltage + /// + float GetVoltagePeakToPeak(void) { return voltage; } + + /// Set the offset in the range of +/- 1.65v + /// + /// A zero volt offset is biased to VCC/2 (3.3/2) + /// + /// @param[in] voltage is the offset voltage. + /// @returns true if the value was accepted + /// + bool SetVoltageOffset(float voltage); + + /// Get the offset voltage + /// + /// @returns offset voltage + /// + float GetVoltageOffset(void) { return offset; } + + /// Signal Generator Modes + /// + /// This defines the modes. However, SG_KEYPAD is not an mode, + /// it is a proprietary mechanism used for displaying the keypad, and + /// is not intended to be used by the application. + /// + typedef enum { + SG_SINE, ///< Sine wave + SG_SQUARE, ///< Square wave + SG_TRIANGLE, ///< Triangle wave + SG_SAWTOOTH, ///< Sawtooth + SG_USER, ///< User defined waveform + SG_KEYPAD, ///< This is an internal value, not for applications + } SG_Mode; + + /// Select a Waveform Mode + /// + /// The selection will update the display to reflect the current state + /// + /// @param[in] mode sets the signal generator mode. + /// @returns true if the value was accepted + /// + bool SelectWaveformMode(SG_Mode mode); + + /// Operating mode changes + /// + /// Changes in the operating mode are reported by a bitmask value, where + /// zero or more bits are set. + /// + typedef enum { + SG_NONE = 0, ///< No change in operating mode + SG_MODE = 1, ///< Signal mode changed; Sine, Square, Triangle, Sawtooth, User + SG_FREQ = 2, ///< Change in the frequency + SG_PERI = 4, ///< Change in the period (effectively same as frequency) + SG_DUTY = 8, ///< Change in the duty cycle + SG_VOLT = 16, ///< Change in the peak to peak amplitude + SG_OFFS = 32, ///< Change in the offset voltage + } SG_Changes; + + /// Poll the Signal Generator UI for changes in operation. + /// + /// Call this periodically, in order to determine if there is a user-activated + /// change in the operating mode of the signal generator. + /// + /// @param[in] c is the optional character, emulating the onscreen keypad + /// - '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 + /// @returns a bitmask of which non-zero indicates changes in mode. + /// + SG_Changes Poll(char c = 0); + + /// Show the menu of commands on the console interface + /// + void ShowMenu(void); + +private: + RA8875 * lcd; + SignalGenerator * signal; + const char * ProgName; + const char * Manuf; + const char * Ver; + const char * Build; + typedef enum { + VS_MainScreen, + VS_Settings, + } VisualScreen; + VisualScreen vis; + SG_Mode mode; ///< signal mode + float frequency; ///< selected frequency + float dutycycle; ///< selected duty cycle + float voltage; ///< selected voltage + float offset; ///< selected offset + SG_Changes EntryMd; ///< indicates if in data entry mode + char textBuffer[10]; ///< a place to enter text + int textLen; ///< num chars in textBuffer + Timer timer; + + void DrawNavGadget(void); + void ShowProductInfo(void); + void ShowBrightnessSetting(void); + char GetTouchEvent(void); + void ClearScope(void); + void UpdateScope(void); + void updateDutyCycle(void); + void updateFrequency(void); + void updatePeriod(void); + void updateVoltage(void); + void updateOffset(void); + void updateTextWindow(void); + void resetDataEntry(void); + void DrawKeypadEnabled(bool enable = false); + void DrawButton(rect_t r, bool pressed, SG_Mode mode, bool enable = false, int label=0); + void DrawWaveform(rect_t r, SG_Mode mode, color_t color, float dutycycleOverride = 0.0); + float rangelimit(float value, float minV, float maxV); +}; + + +#endif // SIGNALGENDISPLAY_H \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SignalGenerator.lib Fri Jan 13 12:33:37 2017 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/Yann/code/SignalGenerator/#b634f7945085
--- a/Speaker.h Mon Jan 21 03:37:11 2013 +0000 +++ b/Speaker.h Fri Jan 13 12:33:37 2017 +0000 @@ -1,3 +1,6 @@ + +#if 0 + class Speaker { public: @@ -50,3 +53,4 @@ } }; +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Watchdog.lib Fri Jan 13 12:33:37 2017 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/WiredHome/code/Watchdog/#e0f547e22dd5
--- a/main.cpp Mon Jan 21 03:37:11 2013 +0000 +++ b/main.cpp Fri Jan 13 12:33:37 2017 +0000 @@ -1,22 +1,168 @@ + #include "mbed.h" -// Audio output demo for speaker -// Speaker Class demo - plays a note on the analog output pin -// 32 data points on one sine wave cycle are precomputed, -// scaled, stored in an array and -// continuously output to the Digital to Analog convertor +#include "SignalGenDisplay.h" +#include "RA8875.h" +#include "Watchdog.h" // ver 2 +#include "IniManager.h" // v19 + +const char * PROG_MANF = "Smartware Computing"; +const char * PROG_NAME = "Signal Generator"; +const char * PROG_VERS = "0.01"; +const char * BUILD_DATE = __DATE__ " " __TIME__; + +RA8875 lcd(p5,p6,p7,p12, NC, "tft"); // SPI:{MOSI,MISO,SCK,/ChipSelect,/reset}, name +INI ini; +SignalGenerator g_signal(p18); + +SignalGenDisplay ui(&lcd, &g_signal, PROG_NAME, PROG_MANF, PROG_VERS, BUILD_DATE); + +RawSerial pc(USBTX, USBRX); +LocalFileSystem local("local"); +Watchdog wd; + +/* CPU Available indicator + */ +DigitalOut g_availableLed(LED1); //<! Led used to indicate the program is alive +void AvailableLedIndicator(); //<! Ticker callback +Ticker g_available; + +/* SignalGenerator usage + */ +void SynchronousUserInput(); //<! Ticker callback +Ticker g_synchronousUserInput; + + -// add Speaker class and PlayNote -// PlayNote args are frequency in hz (<=5000), duration in secs , and volume(0.0..1.0) -#include "Speaker.h" - -int main() +// Calibrate the resistive touch screen, and store the data on the +// local file system. +// +void CalibrateTS(void) { -// setup instance of new Speaker class, mySpeaker -// the pin must be the AnalogOut pin - p18 - Speaker mySpeaker(p18); - // loops forever playing two notes on speaker using analog samples - while(1) { - mySpeaker.PlayNote(969.0, 0.5, 1.0); - mySpeaker.PlayNote(800.0, 0.5, 1.0); + FILE * fh; + tpMatrix_t matrix; + RetCode_t r; + Timer testperiod; + + r = lcd.TouchPanelCalibrate("Calibrate the touch panel", &matrix); + if (r == noerror) { + fh = fopen("/local/tpcal.cfg", "wb"); + if (fh) { + fwrite(&matrix, sizeof(tpMatrix_t), 1, fh); + fclose(fh); + printf(" tp cal written.\r\n"); + lcd.cls(); + } else { + printf(" couldn't open tpcal file.\r\n"); + } + } 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 InitTS(void) +{ + FILE * fh; + tpMatrix_t matrix; + + fh = fopen("/local/tpcal.cfg", "rb"); + if (fh) { + fread(&matrix, sizeof(tpMatrix_t), 1, fh); + fclose(fh); + lcd.TouchPanelSetMatrix(&matrix); + printf(" tp cal loaded.\r\n"); + } else { + CalibrateTS(); } } + + + +/* Program Entry Point + */ +int main() { + pc.baud(460800); + pc.printf("\r\n%s %s\r\n", PROG_NAME, BUILD_DATE); + + if (wd.WatchdogCausedReset()) { + pc.printf("**** Watchdog Event caused reset ****\r\n"); + } + // Set very long timeout because the <PrintScreen> function is incredibly slow with local filesystem... +// wd.Configure(120.0); // This is forever for real-time embedded, but for a casual network appliance... + ini.SetFile("/local/SigGen.ini", 2); + + // Bring the LCD online + lcd.frequency(2000000); + lcd.init(480,272,16, true, true, true); + lcd.TouchPanelInit(); + int bl = ini.ReadLongInt("Settings", "Backlight", 80); + lcd.Backlight_u8(bl); + InitTS(); + + // Bring the signal generator online + ui.Init(); + + //volatile SignalGenerator::SignalGeneratorType _choice; //<! User selects the desired signal type + //volatile int frequency; //<! Signal frequency + + wait(1); // Needed after startup + + // Launch available indicator + g_availableLed = 1; + g_available.attach(&AvailableLedIndicator, 2.0); // Never detached + + ui.ShowMenu(); + // Start infinite loop + while(true) + { +// wd.Service(); + if (pc.readable()) { + int c = pc.getc(); + ui.Poll(c); + } else { + ui.Poll(); + } +#if 0 + // Acquire settings + //_choice = DisplaySignalGeneratorTestMenuAndGetChoice(); + printf("\r\nEnter signal frequency (< 1MHz/# of samples): "); + scanf("%d", &frequency); + + // Prepare the signal + g_signal.SetSignalFrequency(_choice, frequency); + + // Launch execution + if (g_signal.BeginRunAsync() == -1) { + // Synchronous mode + g_synchronousUserInput.attach(&SynchronousUserInput, 0.005); // 5ms + g_signal.Run(); // Never stopped + printf("\r\nSignal Generator terminated\r\n"); + g_synchronousUserInput.detach(); + } else { + // Asynchronous mode + printf("\r\n\r\nPress 'q' to terminate\r\n"); + while (getchar() != 'q'); + g_signal.EndRunAsync(); + } +#endif + } // End of 'while' statement +} // End of main program + +/** Callbak used by CPU availabe ticker to indicate the program is alive + */ +void AvailableLedIndicator() { + g_availableLed != g_availableLed; +} // End of function AvailableLedIndicator + +/** Callbak used when SignalLibrary is used in synchronous mode (Run() method) + */ +void SynchronousUserInput() { + if (pc.readable()) { + g_signal.Stop(); + getchar(); + } +} // End of function SynchronousUserInput +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rtos.lib Fri Jan 13 12:33:37 2017 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed-rtos/#bdd541595fc5
--- a/mbed.bld Mon Jan 21 03:37:11 2013 +0000 +++ b/mbed.bld Fri Jan 13 12:33:37 2017 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/mbed_official/code/mbed/builds/0480438fc29c \ No newline at end of file +http://mbed.org/users/mbed_official/code/mbed/builds/9bcdf88f62b0 \ No newline at end of file