Added support for ssd1306 128x64

Options.txt needs the line;-
LCDName = ssd1306_128x64
and depending upon how you want the keyboard's pgup and pgdown keys to work;-
keyboardBrowseLCDScreen = 1

Splits lines connect
SDA to GPIO 2 pin 3
SCL to GPIO 3 pin 5

Non-split lines
SDA to GPIO 0 pin 27
SCL to GPIO 1 pin 28
This commit is contained in:
Stephen White 2018-06-03 18:11:58 +10:00
parent fdac3079dd
commit e292de1179
19 changed files with 1337 additions and 230 deletions

View file

@ -1,8 +1,8 @@
OBJS = armc-start.o armc-cstartup.o armc-cstubs.o armc-cppstubs.o \ OBJS = armc-start.o armc-cstartup.o armc-cstubs.o armc-cppstubs.o \
exception.o main.o rpi-aux.o rpi-mailbox-interface.o rpi-mailbox.o \ exception.o main.o rpi-aux.o rpi-i2c.o rpi-mailbox-interface.o rpi-mailbox.o \
rpi-gpio.o rpi-interrupts.o cache.o ff.o interrupt.o Keyboard.o \ rpi-gpio.o rpi-interrupts.o cache.o ff.o interrupt.o Keyboard.o \
Pi1541.o DiskImage.o iec_bus.o iec_commands.o m6502.o m6522.o \ Pi1541.o DiskImage.o iec_bus.o iec_commands.o m6502.o m6522.o \
Drive.o gcr.o prot.o lz.o emmc.o diskio.o options.o Screen.o \ Drive.o gcr.o prot.o lz.o emmc.o diskio.o options.o Screen.o SSD1306.o ScreenLCD.o \
Timer.o FileBrowser.o DiskCaddy.o ROMs.o InputMappings.o xga_font_data.o Timer.o FileBrowser.o DiskCaddy.o ROMs.o InputMappings.o xga_font_data.o
SRCDIR = src SRCDIR = src

View file

@ -34,6 +34,8 @@ static u32 red = RGBA(0xff, 0, 0, 0xff);
bool DiskCaddy::Insert(const FILINFO* fileInfo, bool readOnly) bool DiskCaddy::Insert(const FILINFO* fileInfo, bool readOnly)
{ {
int x;
int y;
bool success; bool success;
FIL fp; FIL fp;
FRESULT res = f_open(&fp, fileInfo->fname, FA_READ); FRESULT res = f_open(&fp, fileInfo->fname, FA_READ);
@ -41,13 +43,28 @@ bool DiskCaddy::Insert(const FILINFO* fileInfo, bool readOnly)
{ {
if (screen) if (screen)
{ {
int x = screen->ScaleX(screenPosXCaddySelections); x = screen->ScaleX(screenPosXCaddySelections);
int y = screen->ScaleY(screenPosYCaddySelections); y = screen->ScaleY(screenPosYCaddySelections);
snprintf(buffer, 256, "Loading %s\r\n", fileInfo->fname); snprintf(buffer, 256, "Loading %s\r\n", fileInfo->fname);
screen->PrintText(false, x, y, buffer, RGBA(0xff, 0xff, 0xff, 0xff), red); screen->PrintText(false, x, y, buffer, RGBA(0xff, 0xff, 0xff, 0xff), red);
} }
if (screenLCD)
{
RGBA BkColour = RGBA(0, 0, 0, 0xFF);
screenLCD->Clear(BkColour);
x = 0;
y = 0;
snprintf(buffer, 256, "Loading");
screenLCD->PrintText(false, x, y, buffer, RGBA(0xff, 0xff, 0xff, 0xff), BkColour);
y += 16;
snprintf(buffer, 256, "%s ", fileInfo->fname);
screenLCD->PrintText(false, x, y, buffer, RGBA(0xff, 0xff, 0xff, 0xff), red);
screenLCD->SwapBuffers();
}
u32 bytesRead; u32 bytesRead;
SetACTLed(true); SetACTLed(true);
f_read(&fp, DiskImage::readBuffer, READBUFFER_SIZE, &bytesRead); f_read(&fp, DiskImage::readBuffer, READBUFFER_SIZE, &bytesRead);
@ -145,13 +162,15 @@ bool DiskCaddy::InsertNBZ(const FILINFO* fileInfo, unsigned char* diskImageData,
} }
void DiskCaddy::Display() void DiskCaddy::Display()
{
if (screen)
{ {
unsigned numberOfImages = GetNumberOfImages(); unsigned numberOfImages = GetNumberOfImages();
unsigned caddyIndex; unsigned caddyIndex;
int x = screen->ScaleX(screenPosXCaddySelections); int x;
int y = screen->ScaleY(screenPosYCaddySelections); int y;
if (screen)
{
x = screen->ScaleX(screenPosXCaddySelections);
y = screen->ScaleY(screenPosYCaddySelections);
snprintf(buffer, 256, "Emulating\r\n"); snprintf(buffer, 256, "Emulating\r\n");
screen->PrintText(false, x, y, buffer, RGBA(0xff, 0xff, 0xff, 0xff), red); screen->PrintText(false, x, y, buffer, RGBA(0xff, 0xff, 0xff, 0xff), red);
@ -168,18 +187,72 @@ void DiskCaddy::Display()
y += 16; y += 16;
} }
} }
ShowSelectedImage(0);
} }
if (screenLCD)
{
RGBA BkColour = RGBA(0, 0, 0, 0xFF);
screenLCD->Clear(BkColour);
}
ShowSelectedImage(0);
} }
void DiskCaddy::ShowSelectedImage(u32 index) void DiskCaddy::ShowSelectedImage(u32 index)
{ {
u32 x = screen->ScaleX(screenPosXCaddySelections) - 16; u32 x;
u32 y = screen->ScaleY(screenPosYCaddySelections) + 16 + 16 * index; u32 y;
if (screen)
{
x = screen->ScaleX(screenPosXCaddySelections) - 16;
y = screen->ScaleY(screenPosYCaddySelections) + 16 + 16 * index;
snprintf(buffer, 256, "*"); snprintf(buffer, 256, "*");
screen->PrintText(false, x, y, buffer, white, red); screen->PrintText(false, x, y, buffer, white, red);
} }
if (screenLCD)
{
unsigned numberOfImages = GetNumberOfImages();
unsigned caddyIndex;
if (screenLCD)
{
RGBA BkColour = RGBA(0, 0, 0, 0xFF);
//screenLCD->Clear(BkColour);
x = 0;
y = 0;
snprintf(buffer, 256, "Emulating %d/%d ", index + 1, numberOfImages);
screenLCD->PrintText(false, x, y, buffer, RGBA(0xff, 0xff, 0xff, 0xff), RGBA(0xff, 0xff, 0xff, 0xff));
y += 16;
if (numberOfImages > 3 && index > 2)
{
if (numberOfImages - index < 3)
caddyIndex = numberOfImages - 3;
else
caddyIndex = index;
}
else
{
caddyIndex = 0;
}
for (; caddyIndex < numberOfImages; ++caddyIndex)
{
DiskImage* image = GetImage(caddyIndex);
const char* name = image->GetName();
if (name)
{
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 += 16;
}
if (y >= screenLCD->Height())
break;
}
screenLCD->SwapBuffers();
}
}
}
bool DiskCaddy::Update() bool DiskCaddy::Update()
{ {
@ -198,6 +271,11 @@ bool DiskCaddy::Update()
ShowSelectedImage(oldCaddyIndex); ShowSelectedImage(oldCaddyIndex);
} }
if (screenLCD)
{
}
return true; return true;
} }
return false; return false;

View file

@ -29,10 +29,11 @@ public:
DiskCaddy() DiskCaddy()
: selectedIndex(0) : selectedIndex(0)
, screen(0) , screen(0)
, screenLCD(0)
{ {
} }
void SetScreen(Screen* screen) { this->screen = screen; } void SetScreen(Screen* screen, ScreenBase* screenLCD) { this->screen = screen; this->screenLCD = screenLCD; }
void Empty() void Empty()
{ {
@ -106,6 +107,7 @@ private:
u32 oldCaddyIndex; u32 oldCaddyIndex;
Screen* screen; Screen* screen;
ScreenBase* screenLCD;
}; };
#endif #endif

View file

@ -21,7 +21,6 @@
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <algorithm> #include <algorithm>
#include "Screen.h"
#include "debug.h" #include "debug.h"
#include "Keyboard.h" #include "Keyboard.h"
#include "options.h" #include "options.h"
@ -33,8 +32,6 @@ extern "C"
#include "rpi-gpio.h" #include "rpi-gpio.h"
} }
extern Screen screen;
#define PNG_WIDTH 320 #define PNG_WIDTH 320
#define PNG_HEIGHT 200 #define PNG_HEIGHT 200
@ -75,6 +72,205 @@ static const u32 palette[] =
RGBA(0x9F, 0x9F, 0x9F, 0xFF) RGBA(0x9F, 0x9F, 0x9F, 0xFF)
}; };
void FileBrowser::BrowsableListView::Refresh()
{
char buffer1[128] = { 0 };
char buffer2[128] = { 0 };
u32 index;
u32 entryIndex;
u32 x = positionX;
u32 y = positionY;
u32 colour;
RGBA BkColour = RGBA(0, 0, 0, 0xFF); //palette[VIC2_COLOUR_INDEX_BLUE];
// Ensure the current selection is visible
if (list->currentIndex - offset >= rows)
{
//DEBUG_LOG("CI= %d O = %d R = %d\r\n", list->currentIndex, offset, rows);
offset = list->currentIndex - rows + 1;
if ((int)offset < 0) offset = 0;
}
for (index = 0; index < rows; ++index)
{
entryIndex = offset + index;
if (entryIndex < list->entries.size())
{
FileBrowser::BrowsableList::Entry* entry = &list->entries[entryIndex];
if (screen->IsMonocrome())
{
if (entry->filImage.fattrib & AM_DIR)
{
snprintf(buffer2, columns + 1, "[%s]", entry->filImage.fname);
}
else
{
if (entry->caddyIndex != -1)
snprintf(buffer2, columns + 1, "%d>%s", entry->caddyIndex, entry->filImage.fname);
else
snprintf(buffer2, columns + 1, "%s", entry->filImage.fname);
}
}
else
{
snprintf(buffer2, columns + 1, "%s", entry->filImage.fname);
}
memset(buffer1, ' ', columns);
buffer1[127] = 0;
strncpy(buffer1, buffer2, strlen(buffer2));
if (/*showSelected && */list->currentIndex == entryIndex)
{
if (entry->filImage.fattrib & AM_DIR)
{
screen->PrintText(false, x, y, buffer1, palette[VIC2_COLOUR_INDEX_LBLUE], RGBA(0xff, 0xff, 0xff, 0xff));
}
else
{
colour = RGBA(0xff, 0, 0, 0xff);
if (entry->filImage.fattrib & AM_RDO)
colour = palette[VIC2_COLOUR_INDEX_RED];
screen->PrintText(false, x, y, buffer1, colour, RGBA(0xff, 0xff, 0xff, 0xff));
}
}
else
{
if (entry->filImage.fattrib & AM_DIR)
{
screen->PrintText(false, x, y, buffer1, palette[VIC2_COLOUR_INDEX_LBLUE], BkColour);
}
else
{
colour = palette[VIC2_COLOUR_INDEX_LGREY];
if (entry->filImage.fattrib & AM_RDO)
colour = palette[VIC2_COLOUR_INDEX_PINK];
screen->PrintText(false, x, y, buffer1, colour, BkColour);
}
}
}
else
{
memset(buffer1, ' ', 80);
screen->PrintText(false, x, y, buffer1, BkColour, BkColour);
}
y += 16;
}
screen->SwapBuffers();
}
bool FileBrowser::BrowsableListView::CheckBrowseNavigation(bool pageOnly)
{
InputMappings* inputMappings = InputMappings::Instance();
bool dirty = false;
u32 numberOfEntriesMinus1 = list->entries.size() - 1;
if (inputMappings->BrowseDown())
{
if (list->currentIndex < numberOfEntriesMinus1)
{
if (!pageOnly)
{
list->currentIndex++;
list->current = &list->entries[list->currentIndex];
}
if (list->currentIndex >= (offset + rows) && (list->currentIndex < list->entries.size()))
offset++;
dirty = true;
}
}
if (inputMappings->BrowseUp())
{
if (list->currentIndex > 0)
{
if (!pageOnly)
{
list->currentIndex--;
list->current = &list->entries[list->currentIndex];
}
if ((offset > 0) && (list->currentIndex < offset))
offset--;
dirty = true;
}
}
if ((lcdPgUpDown && inputMappings->BrowsePageDownLCD()) || (!lcdPgUpDown && inputMappings->BrowsePageDown()))
{
u32 rowsMinus1 = rows - 1;
if (list->currentIndex == offset + rowsMinus1)
{
// Need to move the screen window down so that the currentIndex is now at the top of the screen
offset = list->currentIndex;
// Current index now becomes the bottom one
if (offset + rowsMinus1 > numberOfEntriesMinus1)
list->currentIndex = numberOfEntriesMinus1; // Not enough entries to move another page just move to the last entry
else // Move the window down a page
list->currentIndex = offset + rowsMinus1;
}
else
{
// Need to move to list->offset + rowsMinus1
if (offset + rowsMinus1 > numberOfEntriesMinus1)
list->currentIndex = numberOfEntriesMinus1; // Run out of entries before we hit the bottom. Just move to the bottom.
else
list->currentIndex = offset + rowsMinus1; // Move the bottom of the screen
}
list->current = &list->entries[list->currentIndex];
dirty = true;
}
if ((lcdPgUpDown && inputMappings->BrowsePageUpLCD()) || (!lcdPgUpDown && inputMappings->BrowsePageUp()))
{
if (list->currentIndex == offset)
{
// If the cursor is already at the top of the window then page up
int offsetInWindow = (int)list->currentIndex - (int)rows;
if (offsetInWindow < 0) offset = 0;
else offset = (u32)offsetInWindow;
list->currentIndex = offset;
}
else
{
list->currentIndex = offset; // Move the cursor to the top of the window
}
list->current = &list->entries[list->currentIndex];
dirty = true;
}
return dirty;
}
void FileBrowser::BrowsableList::ClearSelections()
{
u32 entryIndex;
for (entryIndex = 0; entryIndex < entries.size(); ++entryIndex)
{
entries[entryIndex].caddyIndex = -1;
}
}
void FileBrowser::BrowsableList::RefreshViews()
{
u32 index;
for (index = 0; index < views.size(); ++index)
{
views[index].Refresh();
}
}
bool FileBrowser::BrowsableList::CheckBrowseNavigation()
{
bool dirty = false;
u32 index;
for (index = 0; index < views.size(); ++index)
{
dirty |= views[index].CheckBrowseNavigation(index != 0);
}
return dirty;
}
FileBrowser::BrowsableList::Entry* FileBrowser::BrowsableList::FindEntry(const char* name) FileBrowser::BrowsableList::Entry* FileBrowser::BrowsableList::FindEntry(const char* name)
{ {
int index; int index;
@ -89,18 +285,38 @@ FileBrowser::BrowsableList::Entry* FileBrowser::BrowsableList::FindEntry(const c
return 0; return 0;
} }
FileBrowser::FileBrowser(DiskCaddy* diskCaddy, ROMs* roms, unsigned deviceID, bool displayPNGIcons) FileBrowser::FileBrowser(DiskCaddy* diskCaddy, ROMs* roms, unsigned deviceID, bool displayPNGIcons, ScreenBase* screenMain, ScreenBase* screenLCD)
: state(State_Folders) : state(State_Folders)
, maxOnScreen(38)
, diskCaddy(diskCaddy) , diskCaddy(diskCaddy)
, selectionsMade(false) , selectionsMade(false)
, roms(roms) , roms(roms)
, deviceID(deviceID) , deviceID(deviceID)
, displayPNGIcons(displayPNGIcons) , displayPNGIcons(displayPNGIcons)
, screenMain(screenMain)
, screenLCD(screenLCD)
{ {
maxOnScreen = (int)(38.0f * screen.GetScaleY()); u32 columns = screenMain->ScaleX(80);
if (maxOnScreen < 1) u32 rows = (int)(38.0f * screenMain->GetScaleY());
maxOnScreen = 1; u32 positionX = 0;
u32 positionY = 17;
if (rows < 1)
rows = 1;
folder.AddView(screenMain, columns, rows, positionX, positionY, false);
positionX = screenMain->ScaleX(1024 - 320);
caddySelections.AddView(screenMain, columns, rows, positionX, positionY, false);
columns = 128 / 8;
rows = 4;
positionX = 0;
positionY = 0;
if (screenLCD)
folder.AddView(screenLCD, columns, rows, positionX, positionY, true);
} }
u32 FileBrowser::Colour(int index) u32 FileBrowser::Colour(int index)
@ -204,6 +420,7 @@ void FileBrowser::DisplayRoot()
FolderChanged(); FolderChanged();
} }
/*
void FileBrowser::RefeshDisplayForBrowsableList(FileBrowser::BrowsableList* browsableList, int xOffset, bool showSelected) void FileBrowser::RefeshDisplayForBrowsableList(FileBrowser::BrowsableList* browsableList, int xOffset, bool showSelected)
{ {
char buffer1[128] = { 0 }; char buffer1[128] = { 0 };
@ -219,7 +436,7 @@ void FileBrowser::RefeshDisplayForBrowsableList(FileBrowser::BrowsableList* brow
if (terminal) if (terminal)
printf("\E[2J\E[f"); printf("\E[2J\E[f");
u32 maxCharacters = screen.ScaleX(80); u32 maxCharacters = screenMain->ScaleX(80);
for (index = 0; index < maxOnScreen; ++index) for (index = 0; index < maxOnScreen; ++index)
{ {
@ -238,7 +455,7 @@ void FileBrowser::RefeshDisplayForBrowsableList(FileBrowser::BrowsableList* brow
{ {
if (terminal) if (terminal)
printf("\E[34;47m%s\E[0m\r\n", buffer1); printf("\E[34;47m%s\E[0m\r\n", buffer1);
screen.PrintText(false, x, y, buffer1, palette[VIC2_COLOUR_INDEX_LBLUE], RGBA(0xff, 0xff, 0xff, 0xff)); screenMain->PrintText(false, x, y, buffer1, palette[VIC2_COLOUR_INDEX_LBLUE], RGBA(0xff, 0xff, 0xff, 0xff));
} }
else else
{ {
@ -246,7 +463,7 @@ void FileBrowser::RefeshDisplayForBrowsableList(FileBrowser::BrowsableList* brow
if (entry->filImage.fattrib & AM_RDO) if (entry->filImage.fattrib & AM_RDO)
colour = palette[VIC2_COLOUR_INDEX_RED]; colour = palette[VIC2_COLOUR_INDEX_RED];
screen.PrintText(false, x, y, buffer1, colour, RGBA(0xff, 0xff, 0xff, 0xff)); screenMain->PrintText(false, x, y, buffer1, colour, RGBA(0xff, 0xff, 0xff, 0xff));
if (terminal) if (terminal)
printf("\E[31;47m%s\E[0m\r\n", buffer1); printf("\E[31;47m%s\E[0m\r\n", buffer1);
} }
@ -255,7 +472,7 @@ void FileBrowser::RefeshDisplayForBrowsableList(FileBrowser::BrowsableList* brow
{ {
if (entry->filImage.fattrib & AM_DIR) if (entry->filImage.fattrib & AM_DIR)
{ {
screen.PrintText(false, x, y, buffer1, palette[VIC2_COLOUR_INDEX_LBLUE], BkColour); screenMain->PrintText(false, x, y, buffer1, palette[VIC2_COLOUR_INDEX_LBLUE], BkColour);
if (terminal) if (terminal)
printf("\E[34m%s\E[0m\r\n", buffer1); printf("\E[34m%s\E[0m\r\n", buffer1);
} }
@ -264,7 +481,7 @@ void FileBrowser::RefeshDisplayForBrowsableList(FileBrowser::BrowsableList* brow
colour = palette[VIC2_COLOUR_INDEX_LGREY]; colour = palette[VIC2_COLOUR_INDEX_LGREY];
if (entry->filImage.fattrib & AM_RDO) if (entry->filImage.fattrib & AM_RDO)
colour = palette[VIC2_COLOUR_INDEX_PINK]; colour = palette[VIC2_COLOUR_INDEX_PINK];
screen.PrintText(false, x, y, buffer1, colour, BkColour); screenMain->PrintText(false, x, y, buffer1, colour, BkColour);
if (terminal) if (terminal)
printf("\E[0;m%s\E[0m\r\n", buffer1); printf("\E[0;m%s\E[0m\r\n", buffer1);
} }
@ -273,13 +490,14 @@ void FileBrowser::RefeshDisplayForBrowsableList(FileBrowser::BrowsableList* brow
else else
{ {
memset(buffer1, ' ', 80); memset(buffer1, ' ', 80);
screen.PrintText(false, x, y, buffer1, BkColour, BkColour); screenMain->PrintText(false, x, y, buffer1, BkColour, BkColour);
if (terminal) if (terminal)
printf("%s\r\n", buffer1); printf("%s\r\n", buffer1);
} }
y += 16; y += 16;
} }
} }
*/
void FileBrowser::RefeshDisplay() void FileBrowser::RefeshDisplay()
{ {
@ -289,13 +507,16 @@ void FileBrowser::RefeshDisplay()
u32 textColour = Colour(VIC2_COLOUR_INDEX_LGREEN); u32 textColour = Colour(VIC2_COLOUR_INDEX_LGREEN);
u32 bgColour = Colour(VIC2_COLOUR_INDEX_GREY); u32 bgColour = Colour(VIC2_COLOUR_INDEX_GREY);
screen.ClearArea(0, 0, (int)screen.Width(), 17, bgColour); screenMain->ClearArea(0, 0, (int)screenMain->Width(), 17, bgColour);
screen.PrintText(false, 0, 0, buffer, textColour, bgColour); screenMain->PrintText(false, 0, 0, buffer, textColour, bgColour);
} }
u32 offsetX = screen.ScaleX(1024 - 320); //u32 offsetX = screenMain->ScaleX(1024 - 320);
RefeshDisplayForBrowsableList(&folder, 0); //RefeshDisplayForBrowsableList(&folder, 0);
RefeshDisplayForBrowsableList(&caddySelections, offsetX, false); //RefeshDisplayForBrowsableList(&caddySelections, offsetX, false);
folder.RefreshViews();
caddySelections.RefreshViews();
DisplayPNG(); DisplayPNG();
DisplayStatusBar(); DisplayStatusBar();
@ -349,7 +570,7 @@ void FileBrowser::DisplayPNG(FILINFO& filIcon, int x, int y)
if (image && (w == PNG_WIDTH && h == PNG_HEIGHT)) if (image && (w == PNG_WIDTH && h == PNG_HEIGHT))
{ {
//DEBUG_LOG("Opened PNG %s w = %d h = %d cif = %d\r\n", fileName, w, h, channels_in_file); //DEBUG_LOG("Opened PNG %s w = %d h = %d cif = %d\r\n", fileName, w, h, channels_in_file);
screen.PlotImage((u32*)image, x, y, w, h); screenMain->PlotImage((u32*)image, x, y, w, h);
} }
else else
{ {
@ -368,8 +589,8 @@ void FileBrowser::DisplayPNG()
if (displayPNGIcons && folder.current) if (displayPNGIcons && folder.current)
{ {
FileBrowser::BrowsableList::Entry* current = folder.current; FileBrowser::BrowsableList::Entry* current = folder.current;
u32 x = screen.ScaleX(1024 - 320); u32 x = screenMain->ScaleX(1024 - 320);
u32 y = screen.ScaleY(666) - 240; u32 y = screenMain->ScaleY(666) - 240;
DisplayPNG(current->filIcon, x, y); DisplayPNG(current->filIcon, x, y);
} }
} }
@ -409,11 +630,6 @@ void FileBrowser::UpdateInput()
} }
} }
FileBrowser::Folder* FileBrowser::GetCurrentFolder()
{
return &folder;
}
bool FileBrowser::FillCaddyWithSelections() bool FileBrowser::FillCaddyWithSelections()
{ {
if (caddySelections.entries.size()) if (caddySelections.entries.size())
@ -450,6 +666,7 @@ bool FileBrowser::AddToCaddy(FileBrowser::BrowsableList::Entry* current)
} }
if (canAdd) if (canAdd)
{ {
current->caddyIndex = caddySelections.entries.size();
caddySelections.entries.push_back(*current); caddySelections.entries.push_back(*current);
added = true; added = true;
} }
@ -464,7 +681,7 @@ void FileBrowser::UpdateInputFolders()
if (folder.entries.size() > 0) if (folder.entries.size() > 0)
{ {
u32 numberOfEntriesMinus1 = folder.entries.size() - 1; //u32 numberOfEntriesMinus1 = folder.entries.size() - 1;
bool dirty = false; bool dirty = false;
if (inputMappings->BrowseSelect()) if (inputMappings->BrowseSelect())
@ -531,7 +748,7 @@ void FileBrowser::UpdateInputFolders()
} }
else if (inputMappings->Exit()) else if (inputMappings->Exit())
{ {
caddySelections.Clear(); ClearSelections();
dirty = true; dirty = true;
} }
else if (inputMappings->BrowseInsert()) else if (inputMappings->BrowseInsert())
@ -560,71 +777,7 @@ void FileBrowser::UpdateInputFolders()
} }
} }
if (inputMappings->BrowseDown()) dirty = folder.CheckBrowseNavigation();
{
if (folder.currentIndex < numberOfEntriesMinus1)
{
folder.currentIndex++;
folder.current = &folder.entries[folder.currentIndex];
if (folder.currentIndex >= (folder.offset + maxOnScreen) && (folder.currentIndex < folder.entries.size()))
folder.offset++;
dirty = true;
}
}
if (inputMappings->BrowseUp())
{
if (folder.currentIndex > 0)
{
folder.currentIndex--;
folder.current = &folder.entries[folder.currentIndex];
if ((folder.offset > 0) && (folder.currentIndex < folder.offset))
folder.offset--;
dirty = true;
}
}
if (inputMappings->BrowsePageDown())
{
u32 maxOnScreenMinus1 = maxOnScreen - 1;
if (folder.currentIndex == folder.offset + maxOnScreenMinus1)
{
// Need to move the screen window down so that the currentIndex is now at the top of the screen
folder.offset = folder.currentIndex;
// Current index now becomes the bottom one
if (folder.offset + maxOnScreenMinus1 > numberOfEntriesMinus1)
folder.currentIndex = numberOfEntriesMinus1; // Not enough entries to move another page just move to the last entry
else // Move the window down a page
folder.currentIndex = folder.offset + maxOnScreenMinus1;
}
else
{
// Need to move to folder.offset + maxOnScreenMinus1
if (folder.offset + maxOnScreenMinus1 > numberOfEntriesMinus1)
folder.currentIndex = numberOfEntriesMinus1; // Run out of entries before we hit the bottom. Just move to the bottom.
else
folder.currentIndex = folder.offset + maxOnScreenMinus1; // Move the bottom of the screen
}
folder.current = &folder.entries[folder.currentIndex];
dirty = true;
}
if (inputMappings->BrowsePageUp())
{
if (folder.currentIndex == folder.offset)
{
// If the cursor is already at the top of the window then page up
int offset = (int)folder.currentIndex - (int)maxOnScreen;
if (offset < 0) folder.offset = 0;
else folder.offset = (u32)offset;
folder.currentIndex = folder.offset;
}
else
{
folder.currentIndex = folder.offset; // Move the cursor to the top of the window
}
folder.current = &folder.entries[folder.currentIndex];
dirty = true;
}
} }
if (dirty) RefeshDisplay(); if (dirty) RefeshDisplay();
@ -641,9 +794,6 @@ bool FileBrowser::SelectLST(const char* filenameLST)
bool validImage = false; bool validImage = false;
//DEBUG_LOG("Selected %s\r\n", filenameLST); //DEBUG_LOG("Selected %s\r\n", filenameLST);
if (DiskImage::IsLSTExtention(filenameLST)) if (DiskImage::IsLSTExtention(filenameLST))
{
FileBrowser::Folder* currentFolder = GetCurrentFolder();
if (currentFolder)
{ {
DiskImage::DiskType diskType; DiskImage::DiskType diskType;
FIL fp; FIL fp;
@ -667,7 +817,7 @@ bool FileBrowser::SelectLST(const char* filenameLST)
diskType = DiskImage::GetDiskImageTypeViaExtention(token); diskType = DiskImage::GetDiskImageTypeViaExtention(token);
if (diskType == DiskImage::D64 || diskType == DiskImage::G64 || diskType == DiskImage::NIB || diskType == DiskImage::NBZ) if (diskType == DiskImage::D64 || diskType == DiskImage::G64 || diskType == DiskImage::NIB || diskType == DiskImage::NBZ)
{ {
FileBrowser::BrowsableList::Entry* entry = currentFolder->FindEntry(token); FileBrowser::BrowsableList::Entry* entry = folder.FindEntry(token);
if (entry && !(entry->filImage.fattrib & AM_DIR)) if (entry && !(entry->filImage.fattrib & AM_DIR))
{ {
bool readOnly = (entry->filImage.fattrib & AM_RDO) != 0; bool readOnly = (entry->filImage.fattrib & AM_RDO) != 0;
@ -683,7 +833,6 @@ bool FileBrowser::SelectLST(const char* filenameLST)
} }
} }
} }
}
return validImage; return validImage;
} }
@ -717,17 +866,25 @@ void FileBrowser::UpdateInputDiskCaddy()
void FileBrowser::DisplayStatusBar() void FileBrowser::DisplayStatusBar()
{ {
u32 x = 0; u32 x = 0;
u32 y = screen.ScaleY(STATUS_BAR_POSITION_Y); u32 y = screenMain->ScaleY(STATUS_BAR_POSITION_Y);
char bufferOut[128]; char bufferOut[128];
snprintf(bufferOut, 256, "LED 0 Motor 0 Track 00.0 ATN 0 DAT 0 CLK 0"); snprintf(bufferOut, 256, "LED 0 Motor 0 Track 00.0 ATN 0 DAT 0 CLK 0");
screen.PrintText(false, x, y, bufferOut, RGBA(0, 0, 0, 0xff), RGBA(0xff, 0xff, 0xff, 0xff)); screenMain->PrintText(false, x, y, bufferOut, RGBA(0, 0, 0, 0xff), RGBA(0xff, 0xff, 0xff, 0xff));
} }
void FileBrowser::ClearScreen() void FileBrowser::ClearScreen()
{ {
u32 bgColour = palette[VIC2_COLOUR_INDEX_BLUE]; u32 bgColour = palette[VIC2_COLOUR_INDEX_BLUE];
screen.Clear(bgColour); screenMain->Clear(bgColour);
}
void FileBrowser::ClearSelections()
{
selectionsMade = false;
caddySelections.Clear();
folder.ClearSelections();
} }
void FileBrowser::ShowDeviceAndROM() void FileBrowser::ShowDeviceAndROM()
@ -735,10 +892,10 @@ void FileBrowser::ShowDeviceAndROM()
char buffer[256]; char buffer[256];
u32 textColour = RGBA(0, 0, 0, 0xff); u32 textColour = RGBA(0, 0, 0, 0xff);
u32 bgColour = RGBA(0xff, 0xff, 0xff, 0xff); u32 bgColour = RGBA(0xff, 0xff, 0xff, 0xff);
u32 y = screen.ScaleY(STATUS_BAR_POSITION_Y); u32 y = screenMain->ScaleY(STATUS_BAR_POSITION_Y);
snprintf(buffer, 256, "Device %d %s \r\n", deviceID, roms->ROMNames[roms->currentROMIndex]); snprintf(buffer, 256, "Device %d %s \r\n", deviceID, roms->ROMNames[roms->currentROMIndex]);
screen.PrintText(false, 43 * 8, y, buffer, textColour, bgColour); screenMain->PrintText(false, 43 * 8, y, buffer, textColour, bgColour);
} }
void FileBrowser::DisplayDiskInfo(DiskImage* diskImage, const char* filenameForIcon) void FileBrowser::DisplayDiskInfo(DiskImage* diskImage, const char* filenameForIcon)
@ -754,7 +911,7 @@ void FileBrowser::DisplayDiskInfo(DiskImage* diskImage, const char* filenameForI
char name[17] = { 0 }; char name[17] = { 0 };
unsigned char buffer[260] = { 0 }; unsigned char buffer[260] = { 0 };
int charIndex; int charIndex;
u32 fontHeight = screen.GetCBMFontHeight(); u32 fontHeight = screenMain->GetFontHeight();
u32 x = 0; u32 x = 0;
u32 y = 0; u32 y = 0;
char bufferOut[128] = { 0 }; char bufferOut[128] = { 0 };
@ -763,7 +920,7 @@ void FileBrowser::DisplayDiskInfo(DiskImage* diskImage, const char* filenameForI
u32 usedColour = palette[VIC2_COLOUR_INDEX_RED]; u32 usedColour = palette[VIC2_COLOUR_INDEX_RED];
u32 freeColour = palette[VIC2_COLOUR_INDEX_LGREEN]; u32 freeColour = palette[VIC2_COLOUR_INDEX_LGREEN];
u32 BAMOffsetX = screen.ScaleX(400); u32 BAMOffsetX = screenMain->ScaleX(400);
ClearScreen(); ClearScreen();
@ -798,12 +955,12 @@ void FileBrowser::DisplayDiskInfo(DiskImage* diskImage, const char* filenameForI
if (!used) if (!used)
{ {
snprintf(bufferOut, 128, "%c", screen2petscii(87)); snprintf(bufferOut, 128, "%c", screen2petscii(87));
screen.PrintText(true, x, y, bufferOut, usedColour, bgColour); screenMain->PrintText(true, x, y, bufferOut, usedColour, bgColour);
} }
else else
{ {
snprintf(bufferOut, 128, "%c", screen2petscii(81)); snprintf(bufferOut, 128, "%c", screen2petscii(81));
screen.PrintText(true, x, y, bufferOut, freeColour, bgColour); screenMain->PrintText(true, x, y, bufferOut, freeColour, bgColour);
} }
x += 8; x += 8;
bits <<= 1; bits <<= 1;
@ -816,7 +973,7 @@ void FileBrowser::DisplayDiskInfo(DiskImage* diskImage, const char* filenameForI
for (int bit = 0; bit < DiskImage::SectorsPerTrack[bamTrack]; bit++) for (int bit = 0; bit < DiskImage::SectorsPerTrack[bamTrack]; bit++)
{ {
snprintf(bufferOut, 128, "%c", screen2petscii(87)); snprintf(bufferOut, 128, "%c", screen2petscii(87));
screen.PrintText(true, x, y, bufferOut, usedColour, bgColour); screenMain->PrintText(true, x, y, bufferOut, usedColour, bgColour);
x += 8; x += 8;
} }
y += fontHeight; y += fontHeight;
@ -824,10 +981,10 @@ void FileBrowser::DisplayDiskInfo(DiskImage* diskImage, const char* filenameForI
x = 0; x = 0;
y = 0; y = 0;
snprintf(bufferOut, 128, "0"); snprintf(bufferOut, 128, "0");
screen.PrintText(true, x, y, bufferOut, textColour, bgColour); screenMain->PrintText(true, x, y, bufferOut, textColour, bgColour);
x = 16; x = 16;
snprintf(bufferOut, 128, "\"%s\" %c%c%c%c%c%c", name, buffer[162], buffer[163], buffer[164], buffer[165], buffer[166], buffer[167]); snprintf(bufferOut, 128, "\"%s\" %c%c%c%c%c%c", name, buffer[162], buffer[163], buffer[164], buffer[165], buffer[166], buffer[167]);
screen.PrintText(true, x, y, bufferOut, bgColour, textColour); screenMain->PrintText(true, x, y, bufferOut, bgColour, textColour);
x = 0; x = 0;
y += fontHeight; y += fontHeight;
@ -876,10 +1033,10 @@ void FileBrowser::DisplayDiskInfo(DiskImage* diskImage, const char* filenameForI
//DEBUG_LOG("%d name = %s %x\r\n", blocks, name, fileType); //DEBUG_LOG("%d name = %s %x\r\n", blocks, name, fileType);
snprintf(bufferOut, 128, "%d", blocks); snprintf(bufferOut, 128, "%d", blocks);
screen.PrintText(true, x, y, bufferOut, textColour, bgColour); screenMain->PrintText(true, x, y, bufferOut, textColour, bgColour);
x += 5 * 8; x += 5 * 8;
snprintf(bufferOut, 128, "\"%s\"", name); snprintf(bufferOut, 128, "\"%s\"", name);
screen.PrintText(true, x, y, bufferOut, textColour, bgColour); screenMain->PrintText(true, x, y, bufferOut, textColour, bgColour);
x += 19 * 8; x += 19 * 8;
char modifier = 0x20; char modifier = 0x20;
if ((fileType & 0x80) == 0) if ((fileType & 0x80) == 0)
@ -887,7 +1044,7 @@ void FileBrowser::DisplayDiskInfo(DiskImage* diskImage, const char* filenameForI
else if (fileType & 0x40) else if (fileType & 0x40)
modifier = screen2petscii(60); modifier = screen2petscii(60);
snprintf(bufferOut, 128, "%s%c", fileTypes[fileType & 7], modifier); snprintf(bufferOut, 128, "%s%c", fileTypes[fileType & 7], modifier);
screen.PrintText(true, x, y, bufferOut, textColour, bgColour); screenMain->PrintText(true, x, y, bufferOut, textColour, bgColour);
y += fontHeight; y += fontHeight;
} }
entryOffset += 32; entryOffset += 32;
@ -903,7 +1060,7 @@ void FileBrowser::DisplayDiskInfo(DiskImage* diskImage, const char* filenameForI
x = 0; x = 0;
//DEBUG_LOG("%d blocks free\r\n", blocksFree); //DEBUG_LOG("%d blocks free\r\n", blocksFree);
snprintf(bufferOut, 128, "%d BLOCKS FREE.\r\n", blocksFree); snprintf(bufferOut, 128, "%d BLOCKS FREE.\r\n", blocksFree);
screen.PrintText(true, x, y, bufferOut, textColour, bgColour); screenMain->PrintText(true, x, y, bufferOut, textColour, bgColour);
y += fontHeight; y += fontHeight;
} }
@ -914,8 +1071,8 @@ void FileBrowser::DisplayDiskInfo(DiskImage* diskImage, const char* filenameForI
FILINFO filIcon; FILINFO filIcon;
if (CheckForPNG(filenameForIcon, filIcon)) if (CheckForPNG(filenameForIcon, filIcon))
{ {
x = screen.ScaleX(1024) - 320; x = screenMain->ScaleX(1024) - 320;
y = screen.ScaleY(0); y = screenMain->ScaleY(0);
DisplayPNG(filIcon, x, y); DisplayPNG(filIcon, x, y);
} }
} }
@ -938,7 +1095,7 @@ void FileBrowser::AutoSelectTestImage()
if (index != maxEntries) if (index != maxEntries)
{ {
caddySelections.Clear(); ClearSelections();
caddySelections.entries.push_back(*current); caddySelections.entries.push_back(*current);
selectionsMade = FillCaddyWithSelections(); selectionsMade = FillCaddyWithSelections();
} }

View file

@ -25,6 +25,7 @@
#include "DiskImage.h" #include "DiskImage.h"
#include "DiskCaddy.h" #include "DiskCaddy.h"
#include "ROMs.h" #include "ROMs.h"
#include "ScreenBase.h"
#define VIC2_COLOUR_INDEX_BLACK 0 #define VIC2_COLOUR_INDEX_BLACK 0
#define VIC2_COLOUR_INDEX_WHITE 1 #define VIC2_COLOUR_INDEX_WHITE 1
@ -51,51 +52,88 @@ class FileBrowser
{ {
public: public:
class BrowsableList;
class BrowsableListView
{
public:
BrowsableListView(BrowsableList* list, ScreenBase* screen, u32 columns, u32 rows, u32 positionX, u32 positionY, bool lcdPgUpDown)
: list(list)
, screen(screen)
, columns(columns)
, rows(rows)
, positionX(positionX)
, positionY(positionY)
, lcdPgUpDown(lcdPgUpDown)
{
}
void Refresh();
bool CheckBrowseNavigation(bool pageOnly);
BrowsableList* list;
u32 offset;
ScreenBase* screen;
u32 columns;
u32 rows;
u32 positionX;
u32 positionY;
bool lcdPgUpDown;
};
class BrowsableList class BrowsableList
{ {
public: public:
BrowsableList() BrowsableList()
: current(0) : current(0)
, currentIndex(0) , currentIndex(0)
, offset(0)
{ {
} }
void Clear() void Clear()
{ {
u32 index;
entries.clear(); entries.clear();
current = 0; current = 0;
currentIndex = 0; currentIndex = 0;
offset = 0; for (index = 0; index < views.size(); ++index)
{
views[index].offset = 0;
} }
}
void AddView(ScreenBase* screen, u32 columns, u32 rows, u32 positionX, u32 positionY, bool lcdPgUpDown)
{
BrowsableListView view(this, screen, columns, rows, positionX, positionY, lcdPgUpDown);
views.push_back(view);
}
void ClearSelections();
struct Entry struct Entry
{ {
Entry() : caddyIndex(-1)
{
}
FILINFO filImage; FILINFO filImage;
FILINFO filIcon; FILINFO filIcon;
int caddyIndex;
}; };
Entry* FindEntry(const char* name); Entry* FindEntry(const char* name);
void RefreshViews();
bool CheckBrowseNavigation();
std::vector<Entry> entries; std::vector<Entry> entries;
Entry* current; Entry* current;
u32 currentIndex; u32 currentIndex;
u32 offset;
std::vector<BrowsableListView> views;
}; };
class Folder : public BrowsableList FileBrowser(DiskCaddy* diskCaddy, ROMs* roms, unsigned deviceID, bool displayPNGIcons, ScreenBase* screenMain, ScreenBase* screenLCD);
{
public:
Folder()
: BrowsableList()
, name(0)
{
}
FILINFO* name;
};
FileBrowser(DiskCaddy* diskCaddy, ROMs* roms, unsigned deviceID, bool displayPNGIcons);
void AutoSelectTestImage(); void AutoSelectTestImage();
void DisplayRoot(); void DisplayRoot();
@ -111,7 +149,7 @@ public:
bool SelectionsMade() { return selectionsMade; } bool SelectionsMade() { return selectionsMade; }
const char* LastSelectionName() { return lastSelectionName; } const char* LastSelectionName() { return lastSelectionName; }
void ClearSelections() { selectionsMade = false; caddySelections.Clear(); } void ClearSelections();
void ShowDeviceAndROM(); void ShowDeviceAndROM();
@ -119,8 +157,6 @@ public:
void SetDeviceID(u8 id) { deviceID = id; } void SetDeviceID(u8 id) { deviceID = id; }
Folder* GetCurrentFolder();
static const long int LSTBuffer_size = 1024 * 8; static const long int LSTBuffer_size = 1024 * 8;
static unsigned char LSTBuffer[]; static unsigned char LSTBuffer[];
@ -138,7 +174,7 @@ private:
void UpdateInputFolders(); void UpdateInputFolders();
void UpdateInputDiskCaddy(); void UpdateInputDiskCaddy();
void RefeshDisplayForBrowsableList(FileBrowser::BrowsableList* browsableList, int xOffset, bool showSelected = true); //void RefeshDisplayForBrowsableList(FileBrowser::BrowsableList* browsableList, int xOffset, bool showSelected = true);
bool FillCaddyWithSelections(); bool FillCaddyWithSelections();
@ -153,8 +189,7 @@ private:
State_DiskCaddy State_DiskCaddy
} state; } state;
Folder folder; BrowsableList folder;
u32 maxOnScreen;
DiskCaddy* diskCaddy; DiskCaddy* diskCaddy;
bool selectionsMade; bool selectionsMade;
const char* lastSelectionName; const char* lastSelectionName;
@ -164,6 +199,9 @@ private:
BrowsableList caddySelections; BrowsableList caddySelections;
ScreenBase* screenMain;
ScreenBase* screenLCD;
char PNG[FILEBROWSER_MAX_PNG_SIZE]; char PNG[FILEBROWSER_MAX_PNG_SIZE];
}; };
#endif #endif

View file

@ -32,6 +32,7 @@ unsigned InputMappings::directDiskSwapRequest = 0;
//unsigned InputMappings::escapeSequenceIndex = 0; //unsigned InputMappings::escapeSequenceIndex = 0;
InputMappings::InputMappings() InputMappings::InputMappings()
: keyboardBrowseLCDScreen(false)
{ {
} }
@ -136,6 +137,7 @@ bool InputMappings::CheckKeyboardBrowseMode()
keyboardFlags = 0; keyboardFlags = 0;
// TODO: add KEY_HOME and KEY_END
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))
@ -149,11 +151,25 @@ bool InputMappings::CheckKeyboardBrowseMode()
else if (keyboard->KeyHeld(KEY_UP)) else if (keyboard->KeyHeld(KEY_UP))
SetKeyboardFlag(UP_FLAG); SetKeyboardFlag(UP_FLAG);
else if (keyboard->KeyHeld(KEY_PAGEUP) || keyboard->KeyHeld(KEY_LEFT)) else if (keyboard->KeyHeld(KEY_PAGEUP) || keyboard->KeyHeld(KEY_LEFT))
{
if (keyboardBrowseLCDScreen)
SetKeyboardFlag(PAGEUP_LCD_FLAG);
else
SetKeyboardFlag(PAGEUP_FLAG); SetKeyboardFlag(PAGEUP_FLAG);
}
else if (keyboard->KeyHeld(KEY_DOWN)) else if (keyboard->KeyHeld(KEY_DOWN))
SetKeyboardFlag(DOWN_FLAG); SetKeyboardFlag(DOWN_FLAG);
else if (keyboard->KeyHeld(KEY_PAGEDOWN) || keyboard->KeyHeld(KEY_RIGHT)) else if (keyboard->KeyHeld(KEY_PAGEDOWN) || keyboard->KeyHeld(KEY_RIGHT))
{
if (keyboardBrowseLCDScreen)
SetKeyboardFlag(PAGEDOWN_LCD_FLAG);
else
SetKeyboardFlag(PAGEDOWN_FLAG); SetKeyboardFlag(PAGEDOWN_FLAG);
}
//else if (keyboard->KeyHeld(KEY_HOME))
// SetKeyboardFlag(PAGEUP_LCD_FLAG);
//else if (keyboard->KeyHeld(KEY_END))
// SetKeyboardFlag(PAGEDOWN_LCD_FLAG);
else else
{ {
unsigned index; unsigned index;

View file

@ -34,6 +34,9 @@
#define INSERT_FLAG (1 << 10) #define INSERT_FLAG (1 << 10)
#define NUMBER_FLAG (1 << 11) #define NUMBER_FLAG (1 << 11)
#define PAGEDOWN_LCD_FLAG (1 << 12)
#define PAGEUP_LCD_FLAG (1 << 13)
class InputMappings : public Singleton<InputMappings> class InputMappings : public Singleton<InputMappings>
{ {
protected: protected:
@ -42,6 +45,8 @@ protected:
unsigned keyboardFlags; unsigned keyboardFlags;
unsigned buttonFlags; unsigned buttonFlags;
bool keyboardBrowseLCDScreen;
//inline void SetUartFlag(unsigned flag) { uartFlags |= flag; } //inline void SetUartFlag(unsigned flag) { uartFlags |= flag; }
//inline bool UartFlag(unsigned flag) { return (uartFlags & flag) != 0; } //inline bool UartFlag(unsigned flag) { return (uartFlags & flag) != 0; }
inline void SetKeyboardFlag(unsigned flag) { keyboardFlags |= flag; } inline void SetKeyboardFlag(unsigned flag) { keyboardFlags |= flag; }
@ -64,6 +69,11 @@ public:
buttonFlags = 0; buttonFlags = 0;
} }
void SetKeyboardBrowseLCDScreen(bool value)
{
keyboardBrowseLCDScreen = value;
}
inline bool Exit() inline bool Exit()
{ {
return KeyboardFlag(ESC_FLAG)/* | UartFlag(ESC_FLAG)*/ | ButtonFlag(ESC_FLAG); return KeyboardFlag(ESC_FLAG)/* | UartFlag(ESC_FLAG)*/ | ButtonFlag(ESC_FLAG);
@ -103,6 +113,10 @@ public:
{ {
return KeyboardFlag(PAGEUP_FLAG)/* | UartFlag(PAGEUP_FLAG)*/; return KeyboardFlag(PAGEUP_FLAG)/* | UartFlag(PAGEUP_FLAG)*/;
} }
inline bool BrowsePageUpLCD()
{
return KeyboardFlag(PAGEUP_LCD_FLAG);
}
inline bool BrowseDown() inline bool BrowseDown()
{ {
@ -113,6 +127,10 @@ public:
{ {
return KeyboardFlag(PAGEDOWN_FLAG)/* | UartFlag(PAGEDOWN_FLAG)*/; return KeyboardFlag(PAGEDOWN_FLAG)/* | UartFlag(PAGEDOWN_FLAG)*/;
} }
inline bool BrowsePageDownLCD()
{
return KeyboardFlag(PAGEDOWN_LCD_FLAG);
}
inline bool BrowseInsert() inline bool BrowseInsert()
{ {

251
src/SSD1306.cpp Normal file
View file

@ -0,0 +1,251 @@
// Pi1541 - A Commodore 1541 disk drive emulator
// Copyright(C) 2018 Stephen White
//
// This file is part of Pi1541.
//
// Pi1541 is free software : you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Pi1541 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Pi1541. If not, see <http://www.gnu.org/licenses/>.
#include "SSD1306.h"
#include "debug.h"
#include <string.h>
extern "C"
{
#include "xga_font_data.h"
}
#define SSD1306_CMD_SET_MEMORY_ADDRESSING_MODE 0x20
#define SSD1306_CMD_SET_PAGE_ADDRESS 0x22
#define SSD1306_CMD_DEACTIVATE_SCROLL 0x2E
#define SSD1306_CMD_ACTIVATE_SCROLL 0x2F
#define SSD1306_CMD_SET_CONTRAST_CONTROL 0x81 // Set Contrast Control for BANK0
#define SSD1306_ENABLE_CHARGE_PUMP 0x8D
#define SSD1306_CMD_ENTIRE_DISPLAY_ON 0xA4
#define SSD1306_CMD_ENTIRE_DISPLAY_OFF 0xA5
#define SSD1306_CMD_NORMAL_DISPLAY 0xA6 // 1 = on pixel
#define SSD1306_CMD_INVERT_DISPLAY 0xA7 // 0 = on pixel
#define SSD1306_CMD_DISPLAY_OFF 0xAE
#define SSD1306_CMD_DISPLAY_ON 0xAF
#define SSD1306_CMD_MULTIPLEX_RATIO 0xA8
#define SSD1306_CMD_SET_START_LINE 0x40
#define SSD1306_CMD_SET_DISPLAY_OFFSET 0xD3
#define SSD1306_CMD_SET_DISPLAY_CLOCK_DIVIDE_RATIO 0xD5
#define SSD1306_CMD_SET_PRE_CHARGE_PERIOD 0xD9
#define SSD1306_CMD_SET_COM_PINS 0xDA
#define SSD1306_CMD_SET_VCOMH_DESELECT_LEVEL 0xDB
#define SSD1306_CONTROL_REG 0x00
#define SSD1306_DATA_REG 0x40
unsigned char frame[SSD1306_128x64_BYTES];
SSD1306::SSD1306(int BSCMaster, u8 address)
: BSCMaster(BSCMaster)
, address(address)
{
RPI_I2CInit(BSCMaster, 1);
// SSD1306 data sheet configuration flow
SendCommand(SSD1306_CMD_DISPLAY_OFF);
SendCommand(SSD1306_CMD_MULTIPLEX_RATIO);
SendCommand(0x3F); // SSD1306_LCDHEIGHT - 1
SendCommand(SSD1306_CMD_SET_DISPLAY_OFFSET);
SendCommand(0x00); // no Offset
SendCommand(SSD1306_CMD_SET_START_LINE | 0x0);
SendCommand(0xA1); // Set Segment Re-Map
SendCommand(0xC8); // Set COM Output Scan Direction
SendCommand(SSD1306_CMD_SET_COM_PINS); // Layout and direction
SendCommand(0x12);
SendCommand(SSD1306_CMD_SET_CONTRAST_CONTROL);
SendCommand(0x7F);
SendCommand(SSD1306_CMD_ENTIRE_DISPLAY_ON);
SendCommand(SSD1306_CMD_NORMAL_DISPLAY);
SendCommand(0xD5);
SendCommand(0x80);
SendCommand(SSD1306_CMD_SET_PRE_CHARGE_PERIOD);
SendCommand(0xF1);
SendCommand(SSD1306_CMD_SET_VCOMH_DESELECT_LEVEL);
SendCommand(0x40);
SendCommand(SSD1306_CMD_SET_DISPLAY_CLOCK_DIVIDE_RATIO);
SendCommand(0x80); // upper nibble is rate, lower nibble is divisor
SendCommand(SSD1306_ENABLE_CHARGE_PUMP); // Enable charge pump regulator
SendCommand(0x14); // external = 0x10 internal = 0x14
SendCommand(0x00); // Set Lower Column Start Address
SendCommand(0x10); // Set Higher Column Start Address
SendCommand(0xB0); // Set Page Start Address for Page Addressing Mode
SendCommand(SSD1306_CMD_SET_MEMORY_ADDRESSING_MODE); // Set Memory Addressing Mode
SendCommand(0x00); // 00 - Horizontal Addressing Mode
SendCommand(0x21); // Set Column Address (only for horizontal or vertical mode)
SendCommand(0x00);
SendCommand(0x7F);
SendCommand(SSD1306_CMD_SET_PAGE_ADDRESS);
SendCommand(0x00);
SendCommand(0x07);
SendCommand(SSD1306_CMD_DEACTIVATE_SCROLL);
}
void SSD1306::SendCommand(u8 command)
{
char buffer[2];
buffer[0] = SSD1306_CONTROL_REG;
buffer[1] = command;
RPI_I2CWrite(BSCMaster, address, buffer, sizeof(buffer));
}
void SSD1306::SendData(u8 data)
{
char buffer[2];
buffer[0] = SSD1306_DATA_REG;
buffer[1] = data;
RPI_I2CWrite(BSCMaster, address, buffer, sizeof(buffer));
}
void SSD1306::Home()
{
SendCommand(0x21); // column range
SendCommand(0x00); // set start to 0
SendCommand(0x7F); // set end to 0x7F
SendCommand(0x22); // row range
SendCommand(0x00); // set start to 0
SendCommand(0x07); // set end to 0x07
}
void SSD1306::MoveCursorByte(u8 row, u8 col)
{
if (col > 127) { col = 127; }
if (row > 7) { row = 7; }
SendCommand(0x21); // set column
SendCommand(col); // start = col
SendCommand(0x7F); // end = col max
SendCommand(0x22); // set row
SendCommand(row); // start = row
SendCommand(0x07); // end = row max
}
void SSD1306::MoveCursorCharacter(u8 row, u8 col)
{
if (col > 15) { col = 15; }
if (row > 7) { row = 7; }
MoveCursorByte(row, col << 3);
}
void SSD1306::RefreshScreen()
{
int i;
Home();
for (i = 0; i < SSD1306_128x64_BYTES; i++)
{
SendData(frame[i]);
}
}
void SSD1306::ClearScreen()
{
memset(frame, 0, sizeof(frame));
RefreshScreen();
}
void SSD1306::DisplayOn()
{
SendCommand(SSD1306_CMD_DISPLAY_ON);
ClearScreen();
}
void SSD1306::DisplayOff()
{
ClearScreen();
SendCommand(SSD1306_CMD_DISPLAY_OFF);
}
void SSD1306::Plottext(int x, int y, char* str, bool inverse)
{
int i;
i = 0;
while (str[i] && x < 16)
{
PlotCharacter(x++, y, str[i++], inverse);
}
}
// Pg 143 - 145. Transposing an 8x8 bit matrix. Hacker's Delight
void transpose8(unsigned char* B, const unsigned char* A, bool inverse)
{
unsigned x, y, t;
x = (A[7] << 24) | (A[6] << 16) | (A[5] << 8) | A[4];
y = (A[3] << 24) | (A[2] << 16) | (A[1] << 8) | A[0];
if (inverse)
{
x = ~x;
y = ~y;
}
t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);
t = (x ^ (x >> 14)) & 0x0000CCCC; x = x ^ t ^ (t << 14);
t = (y ^ (y >> 14)) & 0x0000CCCC; y = y ^ t ^ (t << 14);
t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
x = t;
B[0] = x >> 24; B[1] = x >> 16; B[2] = x >> 8; B[3] = x;
B[4] = y >> 24; B[5] = y >> 16; B[6] = y >> 8; B[7] = y;
}
void SSD1306::PlotCharacter(int x, int y, char c, bool inverse)
{
unsigned char a[8], b[8];
transpose8(a, avpriv_vga16_font + (c * 16), inverse);
transpose8(b, avpriv_vga16_font + (c * 16) + 8, inverse);
memcpy(frame + (y * 256) + (x * 8), a, 8);
memcpy(frame + (y * 256) + (x * 8) + 128, b, 8);
}

99
src/SSD1306.h Normal file
View file

@ -0,0 +1,99 @@
// Pi1541 - A Commodore 1541 disk drive emulator
// Copyright(C) 2018 Stephen White
//
// This file is part of Pi1541.
//
// Pi1541 is free software : you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Pi1541 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Pi1541. If not, see <http://www.gnu.org/licenses/>.
#ifndef SSD1306_H
#define SSD1306_H
#include "types.h"
extern "C"
{
#include "rpi-i2c.h"
}
// 8 pages * (128 columns * 8 bits)
//0 127
//0 127
//0 127
//________________________________________________________
//7777777 | 7
//6666666 | 6
//5555555 | 5
//4444444 PG(ROW)0 | PG(ROW)1 4
//3333333 | 3
//2222222 | 2
//1111111 | 1
//0000000 | 0
//________________________________________________________
//7777777 | 7
//6666666 | 6
//5555555 | 5
//4444444 PG(ROW)2 | PG(ROW)3 4
//3333333 | 3
//2222222 | 2
//1111111 | 1
//0000000 | 0
//________________________________________________________
//7777777 | 7
//6666666 | 6
//5555555 | 5
//4444444 PG(ROW)4 | PG(ROW)5 4
//3333333 | 3
//2222222 | 2
//1111111 | 1
//0000000 | 0
//________________________________________________________
//7777777 | 7
//6666666 | 6
//5555555 | 5
//4444444 PG(ROW)6 | PG(ROW)7 4
//3333333 | 3
//2222222 | 2
//1111111 | 1
//0000000 | 0
//________________________________________________________
#define SSD1306_128x64_BYTES ((128 * 64) / 8)
class SSD1306
{
public:
// 128x32 0x3C
// 128x64 0x3D or 0x3C (if SA0 is grounded)
SSD1306(int BSCMaster = 1, u8 address = 0x3C);
void PlotCharacter(int x, int y, char ascii, bool inverse);
void Plottext(int x, int y, char* str, bool inverse);
void DisplayOn();
void DisplayOff();
void ClearScreen();
void RefreshScreen();
protected:
void SendCommand(u8 command);
void SendData(u8 data);
void Home();
void MoveCursorByte(u8 row, u8 col);
void MoveCursorCharacter(u8 row, u8 col);
unsigned char frame[SSD1306_128x64_BYTES];
int BSCMaster;
u8 address;
};
#endif

View file

@ -148,14 +148,6 @@ void Screen::PlotPixel8(u32 pixel_offset, RGBA Colour)
framebuffer[pixel_offset++] = RED(Colour); framebuffer[pixel_offset++] = RED(Colour);
} }
void Screen::ClipRect(u32& x1, u32& y1, u32& x2, u32& y2)
{
if (x1 > width) x1 = width;
if (y1 > height) y1 = height;
if (x2 > width) x2 = width;
if (y2 > height) y2 = height;
}
void Screen::ClearArea(u32 x1, u32 y1, u32 x2, u32 y2, RGBA colour) void Screen::ClearArea(u32 x1, u32 y1, u32 x2, u32 y2, RGBA colour)
{ {
ClipRect(x1, y1, x2, y2); ClipRect(x1, y1, x2, y2);
@ -195,7 +187,7 @@ void Screen::Clear(RGBA colour)
ClearArea(0, 0, width, height, colour); ClearArea(0, 0, width, height, colour);
} }
u32 Screen::GetCBMFontHeight() u32 Screen::GetFontHeight()
{ {
if (CBMFont) if (CBMFont)
return 8; return 8;

View file

@ -19,28 +19,14 @@
#ifndef SCREEN_H #ifndef SCREEN_H
#define SCREEN_H #define SCREEN_H
#include "types.h" #include "ScreenBase.h"
typedef u32 RGBA; class Screen : public ScreenBase
#define RED(colour) ( (u8)(((u32)colour) & 0xFF) )
#define GREEN(colour) ( (u8)(((u32)colour >> 8) & 0xFF) )
#define BLUE(colour) ( (u8)(((u32)colour >> 16) & 0xFF) )
#define ALPHA(colour) ( (u8)(((u32)colour >> 24) & 0xFF) )
#define RGBA(r, g, b, a) ( ((u32)((u8)(r))) | ((u32)((u8)(g)) << 8) | ((u32)((u8)(b)) << 16) | ((u32)((u8)(a)) << 24) )
class Screen
{ {
public: public:
Screen() Screen()
: opened(false) : ScreenBase()
, width(0)
, height(0)
, bpp(0)
, pitch(0)
, framebuffer(0)
{ {
} }
@ -61,37 +47,26 @@ public:
void PlotImage(u32* image, int x, int y, int w, int h); void PlotImage(u32* image, int x, int y, int w, int h);
u32 Width() const { return width; }
u32 Height() const { return height; }
u32 GetCBMFontHeight();
float GetScaleX() const { return scaleX; } float GetScaleX() const { return scaleX; }
float GetScaleY() const { return scaleY; } float GetScaleY() const { return scaleY; }
u32 ScaleX(u32 x) { return (u32)((float)x * scaleX); } u32 ScaleX(u32 x) { return (u32)((float)x * scaleX); }
u32 ScaleY(u32 y) { return (u32)((float)y * scaleY); } u32 ScaleY(u32 y) { return (u32)((float)y * scaleY); }
u32 GetFontHeight();
void SwapBuffers() {}
private: private:
typedef void (Screen::*PlotPixelFunction)(u32 pixel_offset, RGBA Colour); typedef void (Screen::*PlotPixelFunction)(u32 pixel_offset, RGBA Colour);
PlotPixelFunction plotPixelFn;
void PlotPixel32(u32 pixel_offset, RGBA Colour); void PlotPixel32(u32 pixel_offset, RGBA Colour);
void PlotPixel24(u32 pixel_offset, RGBA Colour); void PlotPixel24(u32 pixel_offset, RGBA Colour);
void PlotPixel16(u32 pixel_offset, RGBA Colour); void PlotPixel16(u32 pixel_offset, RGBA Colour);
void PlotPixel8(u32 pixel_offset, RGBA Colour); void PlotPixel8(u32 pixel_offset, RGBA Colour);
void ClipRect(u32& x1, u32& y1, u32& x2, u32& y2);
PlotPixelFunction plotPixelFn;
bool opened;
u32 width;
u32 height;
u32 bpp;
u32 pitch;
volatile u8* framebuffer;
float scaleX; float scaleX;
float scaleY; float scaleY;
}; };

97
src/ScreenBase.h Normal file
View file

@ -0,0 +1,97 @@
// Pi1541 - A Commodore 1541 disk drive emulator
// Copyright(C) 2018 Stephen White
//
// This file is part of Pi1541.
//
// Pi1541 is free software : you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Pi1541 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Pi1541. If not, see <http://www.gnu.org/licenses/>.
#ifndef SCREENBASE_H
#define SCREENBASE_H
#include "types.h"
typedef u32 RGBA;
#define RED(colour) ( (u8)(((u32)colour) & 0xFF) )
#define GREEN(colour) ( (u8)(((u32)colour >> 8) & 0xFF) )
#define BLUE(colour) ( (u8)(((u32)colour >> 16) & 0xFF) )
#define ALPHA(colour) ( (u8)(((u32)colour >> 24) & 0xFF) )
#define RGBA(r, g, b, a) ( ((u32)((u8)(r))) | ((u32)((u8)(g)) << 8) | ((u32)((u8)(b)) << 16) | ((u32)((u8)(a)) << 24) )
class ScreenBase
{
public:
ScreenBase()
: opened(false)
, width(0)
, height(0)
, bpp(0)
, pitch(0)
, framebuffer(0)
{
}
virtual void ClearArea(u32 x1, u32 y1, u32 x2, u32 y2, RGBA colour) = 0;
virtual void Clear(RGBA colour) = 0;
virtual void ScrollArea(u32 x1, u32 y1, u32 x2, u32 y2) = 0;
virtual void WriteChar(bool petscii, u32 x, u32 y, unsigned char c, RGBA colour) = 0;
virtual u32 PrintText(bool petscii, u32 xPos, u32 yPos, char *ptr, RGBA TxtColour = RGBA(0xff, 0xff, 0xff, 0xff), RGBA BkColour = RGBA(0, 0, 0, 0xFF), bool measureOnly = false, u32* width = 0, u32* height = 0) = 0;
virtual u32 MeasureText(bool petscii, char *ptr, u32* width = 0, u32* height = 0) = 0;
virtual void PlotPixel(u32 x, u32 y, RGBA colour) = 0;
virtual void PlotImage(u32* image, int x, int y, int w, int h) = 0;
u32 Width() const { return width; }
u32 Height() const { return height; }
virtual float GetScaleX() const { return 1; }
virtual float GetScaleY() const { return 1; }
virtual u32 ScaleX(u32 x) { return x; }
virtual u32 ScaleY(u32 y) { return y; }
virtual u32 GetFontHeight() = 0;
virtual void SwapBuffers() = 0;
bool IsMonocrome() const { return bpp == 1; }
protected:
//typedef void (ScreenBase::*PlotPixelFunction)(u32 pixel_offset, RGBA Colour);
//PlotPixelFunction plotPixelFn;
void ClipRect(u32& x1, u32& y1, u32& x2, u32& y2)
{
if (x1 > width) x1 = width;
if (y1 > height) y1 = height;
if (x2 > width) x2 = width;
if (y2 > height) y2 = height;
}
bool opened;
u32 width;
u32 height;
u32 bpp;
u32 pitch;
u8* framebuffer;
};
#endif

100
src/ScreenLCD.cpp Normal file
View file

@ -0,0 +1,100 @@
// Pi1541 - A Commodore 1541 disk drive emulator
// Copyright(C) 2018 Stephen White
//
// This file is part of Pi1541.
//
// Pi1541 is free software : you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Pi1541 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Pi1541. If not, see <http://www.gnu.org/licenses/>.
#include "ScreenLCD.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "debug.h"
void ScreenLCD::Open(u32 widthDesired, u32 heightDesired, u32 colourDepth, int BSCMaster)
{
bpp = 1;
if (widthDesired < 128)
widthDesired = 128;
if (heightDesired < 64)
heightDesired = 64;
if (widthDesired > 128)
widthDesired = 128;
if (heightDesired > 64)
heightDesired = 64;
width = widthDesired;
height = heightDesired;
DEBUG_LOG("BSCMaster = %d\r\n");
ssd1306 = new SSD1306(BSCMaster);
ssd1306->DisplayOn();
ssd1306->Plottext(5, 1, "Pi1541", false);
ssd1306->RefreshScreen();
opened = true;
}
void ScreenLCD::ClearArea(u32 x1, u32 y1, u32 x2, u32 y2, RGBA colour)
{
ClipRect(x1, y1, x2, y2);
}
void ScreenLCD::ScrollArea(u32 x1, u32 y1, u32 x2, u32 y2)
{
}
void ScreenLCD::Clear(RGBA colour)
{
ssd1306->ClearScreen();
}
void ScreenLCD::WriteChar(bool petscii, u32 x, u32 y, unsigned char c, RGBA colour)
{
if (opened)
{
}
}
void ScreenLCD::PlotPixel(u32 x, u32 y, RGBA colour)
{
}
void ScreenLCD::PlotImage(u32* image, int x, int y, int w, int h)
{
}
u32 ScreenLCD::PrintText(bool petscii, u32 x, u32 y, char *ptr, RGBA TxtColour, RGBA BkColour, bool measureOnly, u32* width, u32* height)
{
int len = 0;
ssd1306->Plottext(x >> 3, y >> 4, ptr, (BkColour & 0xffffff) != 0);
return len;
}
u32 ScreenLCD::MeasureText(bool petscii, char *ptr, u32* width, u32* height)
{
return PrintText(petscii, 0, 0, ptr, 0, 0, true, width, height);
}
u32 ScreenLCD::GetFontHeight()
{
return 16;
}
void ScreenLCD::SwapBuffers()
{
ssd1306->RefreshScreen();
}

58
src/ScreenLCD.h Normal file
View file

@ -0,0 +1,58 @@
// Pi1541 - A Commodore 1541 disk drive emulator
// Copyright(C) 2018 Stephen White
//
// This file is part of Pi1541.
//
// Pi1541 is free software : you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Pi1541 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Pi1541. If not, see <http://www.gnu.org/licenses/>.
#ifndef SCREENLCD_H
#define SCREENLCD_H
#include "ScreenBase.h"
#include "SSD1306.h"
class ScreenLCD : public ScreenBase
{
public:
ScreenLCD()
: ScreenBase()
, ssd1306(0)
{
}
void Open(u32 width, u32 height, u32 colourDepth, int BSCMaster);
void ClearArea(u32 x1, u32 y1, u32 x2, u32 y2, RGBA colour);
void Clear(RGBA colour);
void ScrollArea(u32 x1, u32 y1, u32 x2, u32 y2);
void WriteChar(bool petscii, u32 x, u32 y, unsigned char c, RGBA colour);
u32 PrintText(bool petscii, u32 xPos, u32 yPos, char *ptr, RGBA TxtColour = RGBA(0xff, 0xff, 0xff, 0xff), RGBA BkColour = RGBA(0, 0, 0, 0xFF), bool measureOnly = false, u32* width = 0, u32* height = 0);
u32 MeasureText(bool petscii, char *ptr, u32* width = 0, u32* height = 0);
void PlotPixel(u32 x, u32 y, RGBA colour);
void PlotImage(u32* image, int x, int y, int w, int h);
u32 GetFontHeight();
void SwapBuffers();
private:
SSD1306* ssd1306 = 0;
};
#endif

View file

@ -18,12 +18,14 @@
#include "defs.h" #include "defs.h"
#include <string.h> #include <string.h>
#include <strings.h>
#include "Timer.h" #include "Timer.h"
#include "ROMs.h" #include "ROMs.h"
#include "stb_image.h" #include "stb_image.h"
extern "C" extern "C"
{ {
#include "rpi-aux.h" #include "rpi-aux.h"
#include "rpi-i2c.h"
#include "rpi-gpio.h" #include "rpi-gpio.h"
#include "startup.h" #include "startup.h"
#include "cache.h" #include "cache.h"
@ -37,12 +39,13 @@ extern "C"
#include "diskio.h" #include "diskio.h"
#include "Pi1541.h" #include "Pi1541.h"
#include "FileBrowser.h" #include "FileBrowser.h"
#include "ScreenLCD.h"
#include "logo.h" #include "logo.h"
#include "sample.h" #include "sample.h"
unsigned versionMajor = 1; unsigned versionMajor = 1;
unsigned versionMinor = 2; unsigned versionMinor = 3;
// When the emulated CPU starts we execute the first million odd cycles in non-real-time (ie as fast as possible so the emulated 1541 becomes responsive to CBM-Browser asap) // When the emulated CPU starts we execute the first million odd cycles in non-real-time (ie as fast as possible so the emulated 1541 becomes responsive to CBM-Browser asap)
// During these cycles the CPU is executing the ROM self test routines (these do not need to be cycle accurate) // During these cycles the CPU is executing the ROM self test routines (these do not need to be cycle accurate)
@ -84,6 +87,7 @@ DiskCaddy diskCaddy;
Pi1541 pi1541; Pi1541 pi1541;
CEMMCDevice m_EMMC; CEMMCDevice m_EMMC;
Screen screen; Screen screen;
ScreenLCD* screenLCD = 0;
Options options; Options options;
const char* fileBrowserSelectedName; const char* fileBrowserSelectedName;
u8 deviceID = 8; u8 deviceID = 8;
@ -570,8 +574,8 @@ void emulator()
roms.lastManualSelectedROMIndex = 0; roms.lastManualSelectedROMIndex = 0;
diskCaddy.SetScreen(&screen); diskCaddy.SetScreen(&screen, screenLCD);
fileBrowser = new FileBrowser(&diskCaddy, &roms, deviceID, options.DisplayPNGIcons()); fileBrowser = new FileBrowser(&diskCaddy, &roms, deviceID, options.DisplayPNGIcons(), &screen, screenLCD);
fileBrowser->DisplayRoot(); fileBrowser->DisplayRoot();
pi1541.Initialise(); pi1541.Initialise();
@ -598,6 +602,7 @@ void emulator()
selectedViaIECCommands = false; selectedViaIECCommands = false;
inputMappings->Reset(); inputMappings->Reset();
inputMappings->SetKeyboardBrowseLCDScreen(screenLCD && options.KeyboardBrowseLCDScreen());
fileBrowser->ShowDeviceAndROM(); fileBrowser->ShowDeviceAndROM();
@ -1145,6 +1150,15 @@ extern "C"
CheckOptions(); CheckOptions();
if (strcasecmp(options.GetLCDName(), "ssd1306_128x64") == 0)
{
screenLCD = new ScreenLCD();
screenLCD->Open(128, 64, 1, options.SplitIECLines() ? 1 : 0);
}
else
{
}
IEC_Bus::SetSplitIECLines(options.SplitIECLines()); IEC_Bus::SetSplitIECLines(options.SplitIECLines());
IEC_Bus::SetInvertIECInputs(options.InvertIECInputs()); IEC_Bus::SetInvertIECInputs(options.InvertIECInputs());
IEC_Bus::SetInvertIECOutputs(options.InvertIECOutputs()); IEC_Bus::SetInvertIECOutputs(options.InvertIECOutputs());

View file

@ -135,6 +135,7 @@ Options::Options(void)
, ignoreReset(0) , ignoreReset(0)
, screenWidth(1024) , screenWidth(1024)
, screenHeight(768) , screenHeight(768)
, keyboardBrowseLCDScreen(0)
{ {
strcpy(ROMFontName, "chargen"); strcpy(ROMFontName, "chargen");
starFileName[0] = 0; starFileName[0] = 0;
@ -186,10 +187,15 @@ void Options::Process(char* buffer)
ELSE_CHECK_DECIMAL_OPTION(ignoreReset) ELSE_CHECK_DECIMAL_OPTION(ignoreReset)
ELSE_CHECK_DECIMAL_OPTION(screenWidth) ELSE_CHECK_DECIMAL_OPTION(screenWidth)
ELSE_CHECK_DECIMAL_OPTION(screenHeight) ELSE_CHECK_DECIMAL_OPTION(screenHeight)
ELSE_CHECK_DECIMAL_OPTION(keyboardBrowseLCDScreen)
else if ((strcasecmp(pOption, "StarFileName") == 0)) else if ((strcasecmp(pOption, "StarFileName") == 0))
{ {
strncpy(starFileName, pValue, 255); strncpy(starFileName, pValue, 255);
} }
else if ((strcasecmp(pOption, "LCDName") == 0))
{
strncpy(LCDName, pValue, 255);
}
else if ((strcasecmp(pOption, "ROM") == 0) || (strcasecmp(pOption, "ROM1") == 0)) else if ((strcasecmp(pOption, "ROM") == 0) || (strcasecmp(pOption, "ROM1") == 0))
{ {
strncpy(ROMName, pValue, 255); strncpy(ROMName, pValue, 255);

View file

@ -66,6 +66,12 @@ public:
inline unsigned int ScreenWidth() const { return screenWidth; } inline unsigned int ScreenWidth() const { return screenWidth; }
inline unsigned int ScreenHeight() const { return screenHeight; } inline unsigned int ScreenHeight() const { return screenHeight; }
// Page up and down will jump a different amount based on the maximum number rows displayed.
// Perhaps we should use some keyboard modifier to the the other screen?
inline unsigned int KeyboardBrowseLCDScreen() const { return keyboardBrowseLCDScreen; }
const char* GetLCDName() const { return LCDName; }
static unsigned GetDecimal(char* pString); static unsigned GetDecimal(char* pString);
private: private:
@ -87,7 +93,10 @@ private:
unsigned int screenWidth; unsigned int screenWidth;
unsigned int screenHeight; unsigned int screenHeight;
unsigned int keyboardBrowseLCDScreen;
char starFileName[256]; char starFileName[256];
char LCDName[256];
char ROMFontName[256]; char ROMFontName[256];
char ROMName[256]; char ROMName[256];

186
src/rpi-i2c.c Normal file
View file

@ -0,0 +1,186 @@
#include <stdio.h>
#include "rpi-aux.h"
#include "rpi-base.h"
#include "rpi-gpio.h"
#include "startup.h"
#include "stdlib.h"
#include "rpiHardware.h"
/* Define the system clock frequency in MHz for the baud rate calculation.
This is clearly defined on the BCM2835 datasheet errata page:
http://elinux.org/BCM2835_datasheet_errata */
#define FALLBACK_SYS_FREQ 250000000
#define I2C_BSC0_BASE (PERIPHERAL_BASE + 0x205000)
#define I2C_BSC1_BASE (PERIPHERAL_BASE + 0x804000)
#define GetBaseAddress(BSCMaster) (BSCMaster == 0 ? I2C_BSC0_BASE : I2C_BSC1_BASE)
#define I2C_BSC_C 0x00 // Control register
#define I2C_BSC_S 0x04 // Statis register
#define I2C_BSC_DLEN 0x08
#define I2C_BSC_A 0x0C // Slave address
#define I2C_BSC_FIFO 0x10
#define I2C_BSC_DIV 0x14
#define I2C_BSC_DEL 0x18
#define I2C_BSC_CLKT 0x1C
#define CONTROL_BIT_READ (1 << 0) // READ Read Transfer
#define CONTROL_BIT_CLEAR0 (1 << 4) // CLEAR FIFO 00 = No action. x1 = Clear FIFO. One shot operation. 1x = Clear FIFO.
#define CONTROL_BIT_CLEAR1 (1 << 5)
#define CONTROL_BIT_ST (1 << 7) // ST Start Transfer
#define CONTROL_BIT_INTD (1 << 8) // INTD Interrupt on DONE
#define CONTROL_BIT_INTT (1 << 9) // INTT Interrupt on TX
#define CONTROL_BIT_INTR (1 << 10) // INTR Interrupt on RX
#define CONTROL_BIT_I2CEN (1 << 15) // I2C Enable
#define STATUS_BIT_TA (1 << 0) // Transfer Active
#define STATUS_BIT_DONE (1 << 1) // Done
#define STATUS_BIT_TXW (1 << 2) // FIFO needs Writing (full)
#define STATUS_BIT_RXR (1 << 3) // FIFO needs Reading (full)
#define STATUS_BIT_TXD (1 << 4) // FIFO can accept Data
#define STATUS_BIT_RXD (1 << 5) // FIFO contains Data
#define STATUS_BIT_TXE (1 << 6) // FIFO Empty
#define STATUS_BIT_RXF (1 << 7) // FIFO Full
#define STATUS_BIT_ERR (1 << 8) // ERR ACK Error
#define STATUS_BIT_CLKT (1 << 9) // CLKT Clock Stretch Timeout
#define FIFO_SIZE 16
void RPI_I2CSetClock(int BSCMaster, int clock_freq)
{
_data_memory_barrier();
int sys_freq = get_clock_rate(CORE_CLK_ID);
if (!sys_freq) {
sys_freq = FALLBACK_SYS_FREQ;
}
unsigned short divider = (unsigned short)(sys_freq / clock_freq);
write32(GetBaseAddress(BSCMaster) + I2C_BSC_DIV, divider);
_data_memory_barrier();
}
void RPI_I2CInit(int BSCMaster, int fast)
{
if (BSCMaster == 0)
{
RPI_SetGpioPinFunction(RPI_GPIO0, FS_ALT0);
RPI_SetGpioPinFunction(RPI_GPIO1, FS_ALT0);
}
else
{
RPI_SetGpioPinFunction(RPI_GPIO2, FS_ALT0);
RPI_SetGpioPinFunction(RPI_GPIO3, FS_ALT0);
}
RPI_I2CSetClock(BSCMaster, fast != 0 ? 400000 : 100000);
}
int RPI_I2CRead(int BSCMaster, unsigned char slaveAddress, void* buffer, unsigned count)
{
int success = 0;
if (slaveAddress < 0x80)
{
if (count > 0)
{
unsigned baseAddress = GetBaseAddress(BSCMaster);
unsigned char* data = (unsigned char*)buffer;
write32(baseAddress + I2C_BSC_A, slaveAddress);
write32(baseAddress + I2C_BSC_C, CONTROL_BIT_CLEAR1);
write32(baseAddress + I2C_BSC_S, STATUS_BIT_CLKT | STATUS_BIT_ERR | STATUS_BIT_DONE);
write32(baseAddress + I2C_BSC_DLEN, count);
write32(baseAddress + I2C_BSC_C, CONTROL_BIT_I2CEN | CONTROL_BIT_ST | CONTROL_BIT_READ);
while (!(read32(baseAddress + I2C_BSC_S) & STATUS_BIT_DONE))
{
while (read32(baseAddress + I2C_BSC_S) & STATUS_BIT_RXD)
{
*data++ = (unsigned char)read32(baseAddress + I2C_BSC_FIFO);
count--;
}
}
while (count > 0 && (read32(baseAddress + I2C_BSC_S) & STATUS_BIT_RXD))
{
*data++ = (unsigned char)read32(baseAddress + I2C_BSC_FIFO);
count--;
}
unsigned status = read32(baseAddress + I2C_BSC_S);
if (status & STATUS_BIT_ERR)
{
write32(baseAddress + I2C_BSC_S, STATUS_BIT_ERR);
}
else if ((status & STATUS_BIT_CLKT) == 0 && count == 0)
{
success = 1;
}
write32(baseAddress + I2C_BSC_S, STATUS_BIT_DONE);
}
else
{
success = 1;
}
}
return success;
}
int RPI_I2CWrite(int BSCMaster, unsigned char slaveAddress, void* buffer, unsigned count)
{
int success = 0;
if (slaveAddress < 0x80)
{
if (count > 0)
{
unsigned baseAddress = GetBaseAddress(BSCMaster);
unsigned char* data = (unsigned char*)buffer;
write32(baseAddress + I2C_BSC_A, slaveAddress);
write32(baseAddress + I2C_BSC_C, CONTROL_BIT_CLEAR1);
write32(baseAddress + I2C_BSC_S, STATUS_BIT_CLKT | STATUS_BIT_ERR | STATUS_BIT_DONE);
write32(baseAddress + I2C_BSC_DLEN, count);
for (unsigned i = 0; count > 0 && i < FIFO_SIZE; i++)
{
write32(baseAddress + I2C_BSC_FIFO, *data++);
count--;
}
write32(baseAddress + I2C_BSC_C, CONTROL_BIT_I2CEN | CONTROL_BIT_ST);
while (!(read32(baseAddress + I2C_BSC_S) & STATUS_BIT_DONE))
{
while (count > 0 && (read32(baseAddress + I2C_BSC_S) & STATUS_BIT_TXD))
{
write32(baseAddress + I2C_BSC_FIFO, *data++);
count--;
}
}
unsigned status = read32(baseAddress + I2C_BSC_S);
if (status & STATUS_BIT_ERR)
{
write32(baseAddress + I2C_BSC_S, STATUS_BIT_ERR);
}
else if ((status & STATUS_BIT_CLKT) == 0 && count == 0)
{
success = 1;
}
write32(baseAddress + I2C_BSC_S, STATUS_BIT_DONE);
}
else
{
success = 1;
}
}
//DEBUG_LOG("I2C Write %d %d\r\n", count, success);
return success;
}

11
src/rpi-i2c.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef RPI_AUX_H
#define RPI_AUX_H
#include "rpi-base.h"
extern void RPI_I2CInit(int BSCMaster, int fast);
extern void RPI_I2CSetClock(int BSCMaster, int clock_freq);
extern int RPI_I2CRead(int BSCMaster, unsigned char slaveAddress, void* buffer, unsigned count);
extern int RPI_I2CWrite(int BSCMaster, unsigned char slaveAddress, void* buffer, unsigned count);
#endif