From 94040fa5c74c8bde346c969d14443f022e79994e Mon Sep 17 00:00:00 2001 From: penfold42 Date: Fri, 3 Aug 2018 15:38:07 +1000 Subject: [PATCH 1/7] Optimise OLED display updates --- src/SSD1306.cpp | 47 +++++++++++++++++++++++++++++++++++------------ src/SSD1306.h | 17 ++++++++++------- src/ScreenLCD.cpp | 2 +- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/SSD1306.cpp b/src/SSD1306.cpp index 9e6728a..68ea99d 100644 --- a/src/SSD1306.cpp +++ b/src/SSD1306.cpp @@ -25,8 +25,6 @@ extern "C" #include "xga_font_data.h" } -unsigned char frame[SSD1306_128x64_BYTES]; - SSD1306::SSD1306(int BSCMaster, u8 address, unsigned width, unsigned height, int flip, LCD_MODEL type) : BSCMaster(BSCMaster) , address(address) @@ -36,8 +34,10 @@ SSD1306::SSD1306(int BSCMaster, u8 address, unsigned width, unsigned height, int , width(width) , height(height) { + sizeof_frame = width*height/8; + frame = (unsigned char *)malloc(sizeof_frame); + oldFrame = (unsigned char *)malloc(sizeof_frame); RPI_I2CInit(BSCMaster, 1); - InitHardware(); } @@ -117,10 +117,10 @@ void SSD1306::SendData(u8 data) void SSD1306::Home() { - MoveCursorByte(0, 0); + SetDataPointer(0, 0); } -void SSD1306::MoveCursorByte(u8 page, u8 col) +void SSD1306::SetDataPointer(u8 page, u8 col) { if (col > width-1) { col = width-1; } if (page > height/8-1) { page = height/8-1; } @@ -142,7 +142,8 @@ void SSD1306::RefreshScreen() } } -void SSD1306::RefreshRows(u32 start, u32 amountOfRows) +// assumes a text row is 16 bit high +void SSD1306::RefreshTextRows(u32 start, u32 amountOfRows) { unsigned int i; @@ -154,6 +155,10 @@ void SSD1306::RefreshRows(u32 start, u32 amountOfRows) } } +// Some very basic optimisation is implemented. +// it scans the page to work out the first (new_start) and last (new_end) changed bytes +// Only update that window on the OLED +// If someone is keen, a smarter algorithm could work out a series of ranges to update void SSD1306::RefreshPage(u32 page) { if (page >= height/8) @@ -170,16 +175,33 @@ void SSD1306::RefreshPage(u32 page) int start = page*width; int end = start + width; - MoveCursorByte(page, 0); + int new_start = -1; + int new_end = -1; for (i = start; i < end; i++) { - SendData(frame[i]); + if (oldFrame[i] ^ frame[i]) + { + if (new_start == -1) + new_start = i; + new_end = i; + } + } + + if (new_start >= 0) + { + SetDataPointer(page, new_start-start); + for (i = new_start; i <= new_end; i++) + { + SendData(frame[i]); + oldFrame[i] = frame[i]; + } } } void SSD1306::ClearScreen() { - memset(frame, 0, sizeof(frame)); + memset(frame, 0, sizeof_frame); + memset(oldFrame, 0xff, sizeof_frame); // to force update RefreshScreen(); } @@ -210,6 +232,7 @@ void SSD1306::SetVCOMDeselect(u8 value) void SSD1306::PlotText(int x, int y, char* str, bool inverse) { +// assumes 16 character width int i; i = 0; while (str[i] && x < 16) @@ -258,9 +281,9 @@ void SSD1306::PlotPixel(int x, int y, int c) { switch (c) { - case 1: frame[x+ (y/8)*SSD1306_LCDWIDTH] |= (1 << (y&7)); break; - case 0: frame[x+ (y/8)*SSD1306_LCDWIDTH] &= ~(1 << (y&7)); break; - case -1: frame[x+ (y/8)*SSD1306_LCDWIDTH] ^= (1 << (y&7)); break; + case 1: frame[x+ (y/8)*width] |= (1 << (y&7)); break; + case 0: frame[x+ (y/8)*width] &= ~(1 << (y&7)); break; + case -1: frame[x+ (y/8)*width] ^= (1 << (y&7)); break; } } diff --git a/src/SSD1306.h b/src/SSD1306.h index 6ab245f..92c5473 100644 --- a/src/SSD1306.h +++ b/src/SSD1306.h @@ -18,6 +18,8 @@ #ifndef SSD1306_H #define SSD1306_H + +#include #include "types.h" extern "C" { @@ -66,10 +68,7 @@ extern "C" //0000000 | 0 //________________________________________________________ -#define SSD1306_LCDWIDTH 128 -#define SSD1306_LCDHEIGHT 64 - -#define SSD1306_128x64_BYTES ((SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT) / 8) +#define SSD1306_128x64_BYTES ((128 * 64) / 8) class SSD1306 { @@ -91,7 +90,7 @@ public: void ClearScreen(); void RefreshScreen(); void RefreshPage(u32 page); - void RefreshRows(u32 start, u32 amountOfRows); + void RefreshTextRows(u32 start, u32 amountOfRows); void SetDisplayWindow(u8 x1, u8 y1, u8 x2, u8 y2); void PlotPixel(int x, int y, int c); void PlotImage(const unsigned char * source); @@ -101,9 +100,13 @@ protected: void SendData(u8 data); void Home(); - void MoveCursorByte(u8 row, u8 col); + void SetDataPointer(u8 row, u8 col); - unsigned char frame[SSD1306_128x64_BYTES]; +// unsigned char frame[SSD1306_128x64_BYTES]; +// unsigned char oldFrame[SSD1306_128x64_BYTES]; + unsigned char * frame; + unsigned char * oldFrame; + unsigned sizeof_frame; int BSCMaster; u8 address; diff --git a/src/ScreenLCD.cpp b/src/ScreenLCD.cpp index 591422c..36b4a2f 100644 --- a/src/ScreenLCD.cpp +++ b/src/ScreenLCD.cpp @@ -127,5 +127,5 @@ void ScreenLCD::SwapBuffers() void ScreenLCD::RefreshRows(u32 start, u32 amountOfRows) { if (ssd1306) - ssd1306->RefreshRows(start, amountOfRows); + ssd1306->RefreshTextRows(start, amountOfRows); } From c55c5169ddac99e2ffeb7c69efb7810cc485967a Mon Sep 17 00:00:00 2001 From: penfold42 Date: Fri, 3 Aug 2018 15:39:25 +1000 Subject: [PATCH 2/7] OLED dont highlight entire row --- src/FileBrowser.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/FileBrowser.cpp b/src/FileBrowser.cpp index 650e8b6..5656e0c 100644 --- a/src/FileBrowser.cpp +++ b/src/FileBrowser.cpp @@ -81,6 +81,10 @@ void FileBrowser::BrowsableListView::RefreshLine(u32 entryIndex, u32 x, u32 y, b FileBrowser::BrowsableList::Entry* entry = &list->entries[entryIndex]; if (screen->IsMonocrome()) { + // pre-clear line on OLED + memset(buffer1, ' ', columnsMax); + screen->PrintText(false, x, y, buffer1, BkColour, BkColour); + if (entry->filImage.fattrib & AM_DIR) { snprintf(buffer2, 256, "[%s]", entry->filImage.fname); @@ -106,9 +110,14 @@ void FileBrowser::BrowsableListView::RefreshLine(u32 entryIndex, u32 x, u32 y, b } int len = strlen(buffer2 + highlightScrollOffset); strncpy(buffer1, buffer2 + highlightScrollOffset, sizeof(buffer1)); - while (len < (int)columnsMax) - buffer1[len++] = ' '; - buffer1[columnsMax] = 0; + + if (!screen->IsMonocrome()) + { + // space pad the remainder of the line (but not on OLED==monochrome) + while (len < (int)columnsMax) + buffer1[len++] = ' '; + buffer1[columnsMax] = 0; + } if (selected) { @@ -140,7 +149,7 @@ void FileBrowser::BrowsableListView::RefreshLine(u32 entryIndex, u32 x, u32 y, b } } } - else + else // line is blank, write spaces { memset(buffer1, ' ', columnsMax); screen->PrintText(false, x, y, buffer1, BkColour, BkColour); From 98961a94215e1f0e63e11a14df8440abd215c0cc Mon Sep 17 00:00:00 2001 From: penfold42 Date: Fri, 3 Aug 2018 15:39:48 +1000 Subject: [PATCH 3/7] LCtrl+LAlt+Delete = reboot --- src/InputMappings.cpp | 8 ++++++++ src/Keyboard.h | 19 ++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/InputMappings.cpp b/src/InputMappings.cpp index a300ede..3f2a1e0 100644 --- a/src/InputMappings.cpp +++ b/src/InputMappings.cpp @@ -23,6 +23,7 @@ extern "C" { #include "rpi-aux.h" +extern void reboot_now(void); } // If disk swaps can be done via multiple cores then directDiskSwapRequest needs to be volatile. WARNING: volatile acesses can be very expensive. @@ -152,6 +153,9 @@ bool InputMappings::CheckKeyboardBrowseMode() keyboardFlags = 0; + if (keyboard->KeyHeld(KEY_DELETE) && keyboard->KeyLCtrlAlt() ) + reboot_now(); + if (keyboard->KeyHeld(KEY_ESC)) SetKeyboardFlag(ESC_FLAG); else if (keyboard->KeyHeld(KEY_ENTER)) @@ -245,6 +249,10 @@ void InputMappings::CheckKeyboardEmulationMode(unsigned numberOfImages, unsigned keyboardFlags = 0; if (keyboard->CheckChanged()) { + + if (keyboard->KeyHeld(KEY_DELETE) && keyboard->KeyLCtrlAlt() ) + reboot_now(); + if (keyboard->KeyHeld(KEY_ESC)) SetKeyboardFlag(ESC_FLAG); else if (keyboard->KeyHeld(KEY_PAGEUP)) diff --git a/src/Keyboard.h b/src/Keyboard.h index 774ef6c..2a62ddd 100644 --- a/src/Keyboard.h +++ b/src/Keyboard.h @@ -340,17 +340,14 @@ public: u64 mask = 1ULL << (rawKey & 0x3f); return (keyStatus[keyStatusIndex] & mask); } + inline bool KeyAnyHeld() - { - return (keyStatus[0] | keyStatus[1]); - } - inline bool KeyEitherAlt() - { - return (modifier & (KEY_MOD_LALT | KEY_MOD_RALT) ); - } - inline bool KeyNoModifiers() - { - return (!modifier ); - } + { return (keyStatus[0] | keyStatus[1]); } + + inline bool KeyEitherAlt() { return (modifier & (KEY_MOD_LALT | KEY_MOD_RALT) ); } + + inline bool KeyNoModifiers() { return (!modifier ); } + + inline bool KeyLCtrlAlt() { return (modifier == (KEY_MOD_LALT | KEY_MOD_LCTRL) ); } }; #endif From 550677cc930f2dbd3f7acdbd53866525b8cf7ba3 Mon Sep 17 00:00:00 2001 From: penfold42 Date: Fri, 3 Aug 2018 16:46:14 +1000 Subject: [PATCH 4/7] OLED Emulator - dont highlight entire row --- src/DiskCaddy.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/DiskCaddy.cpp b/src/DiskCaddy.cpp index e84677c..2f8f66e 100644 --- a/src/DiskCaddy.cpp +++ b/src/DiskCaddy.cpp @@ -318,7 +318,10 @@ void DiskCaddy::ShowSelectedImage(u32 index) const char* name = image->GetName(); if (name) { - snprintf(buffer, 256, "%d %s ", caddyIndex + 1, name); +// snprintf(buffer, 256, " "); + memset(buffer, 'Z', screenLCD->Width()/screenLCD->GetFontWidth()); + screenLCD->PrintText(false, x, y, buffer, BkColour, BkColour); + snprintf(buffer, 256, "%d %s", caddyIndex + 1, name); screenLCD->PrintText(false, x, y, buffer, RGBA(0xff, 0xff, 0xff, 0xff), caddyIndex == index ? RGBA(0xff, 0xff, 0xff, 0xff) : BkColour); y += LCDFONTHEIGHT; } From 52a74a6f5c7b78220f119312e305af8cdafbb1a4 Mon Sep 17 00:00:00 2001 From: penfold42 Date: Fri, 3 Aug 2018 22:37:39 +1000 Subject: [PATCH 5/7] Browse: Some directories werent show as directories. fixed --- src/FileBrowser.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FileBrowser.cpp b/src/FileBrowser.cpp index 5656e0c..5e47c8c 100644 --- a/src/FileBrowser.cpp +++ b/src/FileBrowser.cpp @@ -557,6 +557,7 @@ void FileBrowser::RefreshFolderEntries() f_closedir(&dir); strcpy(entry.filImage.fname, ".."); + entry.filImage.fattrib |= AM_DIR; entry.filIcon.fname[0] = 0; folder.entries.push_back(entry); From 48eaa18163b17d470c0f150e7976e101e8d64bb4 Mon Sep 17 00:00:00 2001 From: penfold42 Date: Fri, 3 Aug 2018 22:55:32 +1000 Subject: [PATCH 6/7] re-init display at emulation exit --- src/DiskCaddy.cpp | 3 +-- src/main.cpp | 10 +++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/DiskCaddy.cpp b/src/DiskCaddy.cpp index 2f8f66e..04e6d4a 100644 --- a/src/DiskCaddy.cpp +++ b/src/DiskCaddy.cpp @@ -318,8 +318,7 @@ void DiskCaddy::ShowSelectedImage(u32 index) const char* name = image->GetName(); if (name) { -// snprintf(buffer, 256, " "); - memset(buffer, 'Z', screenLCD->Width()/screenLCD->GetFontWidth()); + memset(buffer, ' ', screenLCD->Width()/screenLCD->GetFontWidth()); screenLCD->PrintText(false, x, y, buffer, BkColour, BkColour); snprintf(buffer, 256, "%d %s", caddyIndex + 1, name); screenLCD->PrintText(false, x, y, buffer, RGBA(0xff, 0xff, 0xff, 0xff), caddyIndex == index ? RGBA(0xff, 0xff, 0xff, 0xff) : BkColour); diff --git a/src/main.cpp b/src/main.cpp index 44bd790..b62c026 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -690,9 +690,13 @@ void emulator() { IEC_Bus::VIA = 0; + IEC_Bus::Reset(); +// workaround for occasional oled curruption + if (screenLCD) + screenLCD->ClearInit(0); + roms.ResetCurrentROMIndex(); fileBrowser->ClearScreen(); - IEC_Bus::Reset(); fileBrowserSelectedName = 0; fileBrowser->ClearSelections(); @@ -948,6 +952,10 @@ void emulator() if (diskCaddy.Empty()) IEC_Bus::WaitMicroSeconds(2 * 1000000); +// workaround for occasional oled curruption +// if (screenLCD) +// screenLCD->ClearInit(0); + fileBrowser->ClearSelections(); fileBrowser->RefeshDisplay(); // Just redisplay the current folder. From 457293c0917958a23b1c78a585e2bac67c3ffbf6 Mon Sep 17 00:00:00 2001 From: penfold42 Date: Fri, 3 Aug 2018 23:18:44 +1000 Subject: [PATCH 7/7] IEC graph: vertical black line at update position --- src/main.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index b62c026..2ae3bf5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -441,9 +441,9 @@ void UpdateScreen() u32 textColour = COLOUR_BLACK; u32 bgColour = COLOUR_WHITE; + RGBA atnColour = COLOUR_YELLOW; RGBA dataColour = COLOUR_GREEN; RGBA clockColour = COLOUR_CYAN; - RGBA atnColour = COLOUR_YELLOW; RGBA BkColour = FileBrowser::Colour(VIC2_COLOUR_INDEX_BLUE); int height = screen.ScaleY(60); @@ -487,6 +487,9 @@ void UpdateScreen() //refreshUartStatusDisplay = true; } + if (options.GraphIEC()) + screen.DrawLineV(graphX, top3, bottom, BkColour); + value = IEC_Bus::GetPI_Atn(); if (options.GraphIEC()) { @@ -497,7 +500,6 @@ void UpdateScreen() } else { - screen.DrawLineV(graphX, top3, bottom, BkColour); if (value) screen.PlotPixel(graphX, top3, atnColour); else screen.PlotPixel(graphX, bottom, atnColour); } @@ -520,7 +522,6 @@ void UpdateScreen() } else { - screen.DrawLineV(graphX, top2, bottom, BkColour); if (value) screen.PlotPixel(graphX, top2, dataColour); else screen.PlotPixel(graphX, bottom, dataColour); } @@ -543,7 +544,6 @@ void UpdateScreen() } else { - screen.DrawLineV(graphX, top, bottom, BkColour); if (value) screen.PlotPixel(graphX, top, clockColour); else screen.PlotPixel(graphX, bottom, clockColour); } @@ -557,6 +557,9 @@ void UpdateScreen() } if (graphX++ > screenWidthM1) graphX = 0; +// black vertical line ahead of graph + if (options.GraphIEC()) + screen.DrawLineV(graphX, top3, bottom, COLOUR_BLACK); u32 track = pi1541.drive.Track(); if (track != oldTrack)