Merge pull request #60 from penfold42/i2cdelta
Oled display optimisations and small things
This commit is contained in:
commit
2819392170
8 changed files with 95 additions and 41 deletions
|
@ -318,7 +318,9 @@ void DiskCaddy::ShowSelectedImage(u32 index)
|
||||||
const char* name = image->GetName();
|
const char* name = image->GetName();
|
||||||
if (name)
|
if (name)
|
||||||
{
|
{
|
||||||
snprintf(buffer, 256, "%d %s ", caddyIndex + 1, name);
|
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);
|
screenLCD->PrintText(false, x, y, buffer, RGBA(0xff, 0xff, 0xff, 0xff), caddyIndex == index ? RGBA(0xff, 0xff, 0xff, 0xff) : BkColour);
|
||||||
y += LCDFONTHEIGHT;
|
y += LCDFONTHEIGHT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,10 @@ void FileBrowser::BrowsableListView::RefreshLine(u32 entryIndex, u32 x, u32 y, b
|
||||||
FileBrowser::BrowsableList::Entry* entry = &list->entries[entryIndex];
|
FileBrowser::BrowsableList::Entry* entry = &list->entries[entryIndex];
|
||||||
if (screen->IsMonocrome())
|
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)
|
if (entry->filImage.fattrib & AM_DIR)
|
||||||
{
|
{
|
||||||
snprintf(buffer2, 256, "[%s]", entry->filImage.fname);
|
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);
|
int len = strlen(buffer2 + highlightScrollOffset);
|
||||||
strncpy(buffer1, buffer2 + highlightScrollOffset, sizeof(buffer1));
|
strncpy(buffer1, buffer2 + highlightScrollOffset, sizeof(buffer1));
|
||||||
|
|
||||||
|
if (!screen->IsMonocrome())
|
||||||
|
{
|
||||||
|
// space pad the remainder of the line (but not on OLED==monochrome)
|
||||||
while (len < (int)columnsMax)
|
while (len < (int)columnsMax)
|
||||||
buffer1[len++] = ' ';
|
buffer1[len++] = ' ';
|
||||||
buffer1[columnsMax] = 0;
|
buffer1[columnsMax] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (selected)
|
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);
|
memset(buffer1, ' ', columnsMax);
|
||||||
screen->PrintText(false, x, y, buffer1, BkColour, BkColour);
|
screen->PrintText(false, x, y, buffer1, BkColour, BkColour);
|
||||||
|
@ -548,6 +557,7 @@ void FileBrowser::RefreshFolderEntries()
|
||||||
f_closedir(&dir);
|
f_closedir(&dir);
|
||||||
|
|
||||||
strcpy(entry.filImage.fname, "..");
|
strcpy(entry.filImage.fname, "..");
|
||||||
|
entry.filImage.fattrib |= AM_DIR;
|
||||||
entry.filIcon.fname[0] = 0;
|
entry.filIcon.fname[0] = 0;
|
||||||
folder.entries.push_back(entry);
|
folder.entries.push_back(entry);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
#include "rpi-aux.h"
|
#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.
|
// 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;
|
keyboardFlags = 0;
|
||||||
|
|
||||||
|
if (keyboard->KeyHeld(KEY_DELETE) && keyboard->KeyLCtrlAlt() )
|
||||||
|
reboot_now();
|
||||||
|
|
||||||
if (keyboard->KeyHeld(KEY_ESC))
|
if (keyboard->KeyHeld(KEY_ESC))
|
||||||
SetKeyboardFlag(ESC_FLAG);
|
SetKeyboardFlag(ESC_FLAG);
|
||||||
else if (keyboard->KeyHeld(KEY_ENTER))
|
else if (keyboard->KeyHeld(KEY_ENTER))
|
||||||
|
@ -245,6 +249,10 @@ void InputMappings::CheckKeyboardEmulationMode(unsigned numberOfImages, unsigned
|
||||||
keyboardFlags = 0;
|
keyboardFlags = 0;
|
||||||
if (keyboard->CheckChanged())
|
if (keyboard->CheckChanged())
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (keyboard->KeyHeld(KEY_DELETE) && keyboard->KeyLCtrlAlt() )
|
||||||
|
reboot_now();
|
||||||
|
|
||||||
if (keyboard->KeyHeld(KEY_ESC))
|
if (keyboard->KeyHeld(KEY_ESC))
|
||||||
SetKeyboardFlag(ESC_FLAG);
|
SetKeyboardFlag(ESC_FLAG);
|
||||||
else if (keyboard->KeyHeld(KEY_PAGEUP))
|
else if (keyboard->KeyHeld(KEY_PAGEUP))
|
||||||
|
|
|
@ -340,17 +340,14 @@ public:
|
||||||
u64 mask = 1ULL << (rawKey & 0x3f);
|
u64 mask = 1ULL << (rawKey & 0x3f);
|
||||||
return (keyStatus[keyStatusIndex] & mask);
|
return (keyStatus[keyStatusIndex] & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool KeyAnyHeld()
|
inline bool KeyAnyHeld()
|
||||||
{
|
{ return (keyStatus[0] | keyStatus[1]); }
|
||||||
return (keyStatus[0] | keyStatus[1]);
|
|
||||||
}
|
inline bool KeyEitherAlt() { return (modifier & (KEY_MOD_LALT | KEY_MOD_RALT) ); }
|
||||||
inline bool KeyEitherAlt()
|
|
||||||
{
|
inline bool KeyNoModifiers() { return (!modifier ); }
|
||||||
return (modifier & (KEY_MOD_LALT | KEY_MOD_RALT) );
|
|
||||||
}
|
inline bool KeyLCtrlAlt() { return (modifier == (KEY_MOD_LALT | KEY_MOD_LCTRL) ); }
|
||||||
inline bool KeyNoModifiers()
|
|
||||||
{
|
|
||||||
return (!modifier );
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,8 +25,6 @@ extern "C"
|
||||||
#include "xga_font_data.h"
|
#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)
|
SSD1306::SSD1306(int BSCMaster, u8 address, unsigned width, unsigned height, int flip, LCD_MODEL type)
|
||||||
: BSCMaster(BSCMaster)
|
: BSCMaster(BSCMaster)
|
||||||
, address(address)
|
, address(address)
|
||||||
|
@ -36,8 +34,10 @@ SSD1306::SSD1306(int BSCMaster, u8 address, unsigned width, unsigned height, int
|
||||||
, width(width)
|
, width(width)
|
||||||
, height(height)
|
, height(height)
|
||||||
{
|
{
|
||||||
|
sizeof_frame = width*height/8;
|
||||||
|
frame = (unsigned char *)malloc(sizeof_frame);
|
||||||
|
oldFrame = (unsigned char *)malloc(sizeof_frame);
|
||||||
RPI_I2CInit(BSCMaster, 1);
|
RPI_I2CInit(BSCMaster, 1);
|
||||||
|
|
||||||
InitHardware();
|
InitHardware();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,10 +117,10 @@ void SSD1306::SendData(u8 data)
|
||||||
|
|
||||||
void SSD1306::Home()
|
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 (col > width-1) { col = width-1; }
|
||||||
if (page > height/8-1) { page = height/8-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;
|
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)
|
void SSD1306::RefreshPage(u32 page)
|
||||||
{
|
{
|
||||||
if (page >= height/8)
|
if (page >= height/8)
|
||||||
|
@ -170,16 +175,33 @@ void SSD1306::RefreshPage(u32 page)
|
||||||
int start = page*width;
|
int start = page*width;
|
||||||
int end = start + width;
|
int end = start + width;
|
||||||
|
|
||||||
MoveCursorByte(page, 0);
|
int new_start = -1;
|
||||||
|
int new_end = -1;
|
||||||
for (i = start; i < end; i++)
|
for (i = start; i < end; 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]);
|
SendData(frame[i]);
|
||||||
|
oldFrame[i] = frame[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSD1306::ClearScreen()
|
void SSD1306::ClearScreen()
|
||||||
{
|
{
|
||||||
memset(frame, 0, sizeof(frame));
|
memset(frame, 0, sizeof_frame);
|
||||||
|
memset(oldFrame, 0xff, sizeof_frame); // to force update
|
||||||
RefreshScreen();
|
RefreshScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,6 +232,7 @@ void SSD1306::SetVCOMDeselect(u8 value)
|
||||||
|
|
||||||
void SSD1306::PlotText(int x, int y, char* str, bool inverse)
|
void SSD1306::PlotText(int x, int y, char* str, bool inverse)
|
||||||
{
|
{
|
||||||
|
// assumes 16 character width
|
||||||
int i;
|
int i;
|
||||||
i = 0;
|
i = 0;
|
||||||
while (str[i] && x < 16)
|
while (str[i] && x < 16)
|
||||||
|
@ -258,9 +281,9 @@ void SSD1306::PlotPixel(int x, int y, int c)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
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)*SSD1306_LCDWIDTH] &= ~(1 << (y&7)); break;
|
case 0: frame[x+ (y/8)*width] &= ~(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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
#ifndef SSD1306_H
|
#ifndef SSD1306_H
|
||||||
#define SSD1306_H
|
#define SSD1306_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
|
@ -66,10 +68,7 @@ extern "C"
|
||||||
//0000000 | 0
|
//0000000 | 0
|
||||||
//________________________________________________________
|
//________________________________________________________
|
||||||
|
|
||||||
#define SSD1306_LCDWIDTH 128
|
#define SSD1306_128x64_BYTES ((128 * 64) / 8)
|
||||||
#define SSD1306_LCDHEIGHT 64
|
|
||||||
|
|
||||||
#define SSD1306_128x64_BYTES ((SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT) / 8)
|
|
||||||
|
|
||||||
class SSD1306
|
class SSD1306
|
||||||
{
|
{
|
||||||
|
@ -91,7 +90,7 @@ public:
|
||||||
void ClearScreen();
|
void ClearScreen();
|
||||||
void RefreshScreen();
|
void RefreshScreen();
|
||||||
void RefreshPage(u32 page);
|
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 SetDisplayWindow(u8 x1, u8 y1, u8 x2, u8 y2);
|
||||||
void PlotPixel(int x, int y, int c);
|
void PlotPixel(int x, int y, int c);
|
||||||
void PlotImage(const unsigned char * source);
|
void PlotImage(const unsigned char * source);
|
||||||
|
@ -101,9 +100,13 @@ protected:
|
||||||
void SendData(u8 data);
|
void SendData(u8 data);
|
||||||
|
|
||||||
void Home();
|
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;
|
int BSCMaster;
|
||||||
u8 address;
|
u8 address;
|
||||||
|
|
|
@ -127,5 +127,5 @@ void ScreenLCD::SwapBuffers()
|
||||||
void ScreenLCD::RefreshRows(u32 start, u32 amountOfRows)
|
void ScreenLCD::RefreshRows(u32 start, u32 amountOfRows)
|
||||||
{
|
{
|
||||||
if (ssd1306)
|
if (ssd1306)
|
||||||
ssd1306->RefreshRows(start, amountOfRows);
|
ssd1306->RefreshTextRows(start, amountOfRows);
|
||||||
}
|
}
|
||||||
|
|
21
src/main.cpp
21
src/main.cpp
|
@ -441,9 +441,9 @@ void UpdateScreen()
|
||||||
u32 textColour = COLOUR_BLACK;
|
u32 textColour = COLOUR_BLACK;
|
||||||
u32 bgColour = COLOUR_WHITE;
|
u32 bgColour = COLOUR_WHITE;
|
||||||
|
|
||||||
|
RGBA atnColour = COLOUR_YELLOW;
|
||||||
RGBA dataColour = COLOUR_GREEN;
|
RGBA dataColour = COLOUR_GREEN;
|
||||||
RGBA clockColour = COLOUR_CYAN;
|
RGBA clockColour = COLOUR_CYAN;
|
||||||
RGBA atnColour = COLOUR_YELLOW;
|
|
||||||
RGBA BkColour = FileBrowser::Colour(VIC2_COLOUR_INDEX_BLUE);
|
RGBA BkColour = FileBrowser::Colour(VIC2_COLOUR_INDEX_BLUE);
|
||||||
|
|
||||||
int height = screen.ScaleY(60);
|
int height = screen.ScaleY(60);
|
||||||
|
@ -487,6 +487,9 @@ void UpdateScreen()
|
||||||
//refreshUartStatusDisplay = true;
|
//refreshUartStatusDisplay = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.GraphIEC())
|
||||||
|
screen.DrawLineV(graphX, top3, bottom, BkColour);
|
||||||
|
|
||||||
value = IEC_Bus::GetPI_Atn();
|
value = IEC_Bus::GetPI_Atn();
|
||||||
if (options.GraphIEC())
|
if (options.GraphIEC())
|
||||||
{
|
{
|
||||||
|
@ -497,7 +500,6 @@ void UpdateScreen()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
screen.DrawLineV(graphX, top3, bottom, BkColour);
|
|
||||||
if (value) screen.PlotPixel(graphX, top3, atnColour);
|
if (value) screen.PlotPixel(graphX, top3, atnColour);
|
||||||
else screen.PlotPixel(graphX, bottom, atnColour);
|
else screen.PlotPixel(graphX, bottom, atnColour);
|
||||||
}
|
}
|
||||||
|
@ -520,7 +522,6 @@ void UpdateScreen()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
screen.DrawLineV(graphX, top2, bottom, BkColour);
|
|
||||||
if (value) screen.PlotPixel(graphX, top2, dataColour);
|
if (value) screen.PlotPixel(graphX, top2, dataColour);
|
||||||
else screen.PlotPixel(graphX, bottom, dataColour);
|
else screen.PlotPixel(graphX, bottom, dataColour);
|
||||||
}
|
}
|
||||||
|
@ -543,7 +544,6 @@ void UpdateScreen()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
screen.DrawLineV(graphX, top, bottom, BkColour);
|
|
||||||
if (value) screen.PlotPixel(graphX, top, clockColour);
|
if (value) screen.PlotPixel(graphX, top, clockColour);
|
||||||
else screen.PlotPixel(graphX, bottom, clockColour);
|
else screen.PlotPixel(graphX, bottom, clockColour);
|
||||||
}
|
}
|
||||||
|
@ -557,6 +557,9 @@ void UpdateScreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (graphX++ > screenWidthM1) graphX = 0;
|
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();
|
u32 track = pi1541.drive.Track();
|
||||||
if (track != oldTrack)
|
if (track != oldTrack)
|
||||||
|
@ -690,9 +693,13 @@ void emulator()
|
||||||
{
|
{
|
||||||
IEC_Bus::VIA = 0;
|
IEC_Bus::VIA = 0;
|
||||||
|
|
||||||
|
IEC_Bus::Reset();
|
||||||
|
// workaround for occasional oled curruption
|
||||||
|
if (screenLCD)
|
||||||
|
screenLCD->ClearInit(0);
|
||||||
|
|
||||||
roms.ResetCurrentROMIndex();
|
roms.ResetCurrentROMIndex();
|
||||||
fileBrowser->ClearScreen();
|
fileBrowser->ClearScreen();
|
||||||
IEC_Bus::Reset();
|
|
||||||
|
|
||||||
fileBrowserSelectedName = 0;
|
fileBrowserSelectedName = 0;
|
||||||
fileBrowser->ClearSelections();
|
fileBrowser->ClearSelections();
|
||||||
|
@ -948,6 +955,10 @@ void emulator()
|
||||||
if (diskCaddy.Empty())
|
if (diskCaddy.Empty())
|
||||||
IEC_Bus::WaitMicroSeconds(2 * 1000000);
|
IEC_Bus::WaitMicroSeconds(2 * 1000000);
|
||||||
|
|
||||||
|
// workaround for occasional oled curruption
|
||||||
|
// if (screenLCD)
|
||||||
|
// screenLCD->ClearInit(0);
|
||||||
|
|
||||||
fileBrowser->ClearSelections();
|
fileBrowser->ClearSelections();
|
||||||
fileBrowser->RefeshDisplay(); // Just redisplay the current folder.
|
fileBrowser->RefeshDisplay(); // Just redisplay the current folder.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue