Updated the ScreenManager class and added the previousDisplay methods allong with screen refresh rate

This commit is contained in:
anschrammh 2020-01-20 08:10:18 +01:00
parent 6dfee719a9
commit 424a135151
2 changed files with 187 additions and 126 deletions

View File

@ -1,6 +1,8 @@
#include "ScreenManager.h" #include "ScreenManager.h"
ScreenManager::ScreenManager(Adafruit_SSD1306 &display, SDCardManager *sdCardManager) : _displayRef(display), _displayColorInverted(false), _displayDimmed(false), _enabled(true), _currentView(NO_CURRENT_VIEW), _error(OK) ScreenManager::ScreenManager(Adafruit_SSD1306 &display, SDCardManager *sdCardManager) : _displayRef(display), _error(OK)
, _displayColorInverted(false), _displayDimmed(false), _enabled(true), _refreshRateHz(1), _refreshInterval(1000), _timeRef(0),_forceRefresh(false)
, _currentView(NO_CURRENT_VIEW), _tail(NULL)
, _viewNotFound{&(displayError), (ErrorInfo *)malloc(sizeof(ErrorInfo)), RESERVED_VIEW_UID, NULL} , _viewNotFound{&(displayError), (ErrorInfo *)malloc(sizeof(ErrorInfo)), RESERVED_VIEW_UID, NULL}
, _viewFuncUndefined{&(displayError), (ErrorInfo *)malloc(sizeof(ErrorInfo)), RESERVED_VIEW_UID, NULL} , _viewFuncUndefined{&(displayError), (ErrorInfo *)malloc(sizeof(ErrorInfo)), RESERVED_VIEW_UID, NULL}
, _currentViewUndefined{&(displayError), (ErrorInfo *)malloc(sizeof(ErrorInfo)), RESERVED_VIEW_UID, NULL} , _currentViewUndefined{&(displayError), (ErrorInfo *)malloc(sizeof(ErrorInfo)), RESERVED_VIEW_UID, NULL}
@ -8,6 +10,10 @@ ScreenManager::ScreenManager(Adafruit_SSD1306 &display, SDCardManager *sdCardMan
,_sdCardManager(sdCardManager) ,_sdCardManager(sdCardManager)
{ {
_viewLinkedList = (ViewLinkedList) createEmptyList(); _viewLinkedList = (ViewLinkedList) createEmptyList();
//We set the error messages :
((ErrorInfo *)_viewNotFound.pData)->errorMessage = FPSTR("View does not exist");
((ErrorInfo *)_viewFunctionFailedToExecute.pData)->errorMessage = FPSTR("View function failed\nto execute");
((ErrorInfo *)_viewFuncUndefined.pData)->errorMessage = FPSTR("View function is NULL");
} }
boolean ScreenManager::init() boolean ScreenManager::init()
@ -66,8 +72,8 @@ void ScreenManager::setDefault()
boolean ScreenManager::addView(boolean (*viewLogicFunction)(Adafruit_SSD1306&, void*), void *pData, const unsigned char UID) boolean ScreenManager::addView(boolean (*viewLogicFunction)(Adafruit_SSD1306&, void*), void *pData, const unsigned char UID)
{ {
ViewLink viewLink ={viewLogicFunction, pData, UID, NULL}; ViewLink viewLink ={viewLogicFunction, pData, UID, NULL, NULL};
addNewLinkAtTheEnd(&_viewLinkedList, viewLink); return addNewLinkAtTheEnd(&_viewLinkedList, viewLink);
} }
void *ScreenManager::createEmptyList() void *ScreenManager::createEmptyList()
@ -87,33 +93,48 @@ boolean ScreenManager::addNewLinkAtTheEnd(ViewLinkedList *viewLinkedList, ViewLi
//Because of the const member //Because of the const member
memcpy(newViewLink, &viewLink, sizeof(*newViewLink)); memcpy(newViewLink, &viewLink, sizeof(*newViewLink));
if(isListEmpty(*viewLinkedList))*viewLinkedList = newViewLink; //If this is the first link
else if(isListEmpty(*viewLinkedList))
{ {
if((*viewLinkedList)->UID == newViewLink->UID) //The link list points to the first link (aka the head)
{
ViewLink *link = *viewLinkedList;
*viewLinkedList = newViewLink; *viewLinkedList = newViewLink;
newViewLink->next = link->next; //The previous pointer is still NULL;
free(link); //The _tail pointer is the same as the head one.
_tail = *viewLinkedList;
}
else //If there are some links already
{
ViewLinkedList *cursor = viewLinkedList;
ViewLink *previousLink = NULL;
while(*cursor != NULL)
{
previousLink = *cursor;
//We check if the UID already exists, if yes we replace the link
if((*cursor)->UID == newViewLink->UID)
{
ViewLink *toDelete = *cursor;
*cursor = newViewLink;
newViewLink->next = toDelete->next;
newViewLink->previous = toDelete->previous;
//We check if the link as a next link registered
if(toDelete->next != NULL)
{
//We update it's previous link since it's going to be deleted
toDelete->next->previous = newViewLink;
}
//We do not forget to check if the link replaced is also the tail, in this case, we must update the tail
if(_tail == toDelete)_tail = newViewLink;
free(toDelete);
return true; return true;
} }
cursor = &(*cursor)->next;
ViewLinkedList cursor = *viewLinkedList;
while(cursor->next != NULL)
{
if(cursor->next->UID == newViewLink->UID)
{
ViewLink *link = cursor->next;
cursor->next = newViewLink;
newViewLink->next = link->next;
free(link);
return true;
} }
cursor = cursor->next; newViewLink->previous = previousLink;
} *cursor = newViewLink;
cursor->next = newViewLink; //We need to update the tail
_tail = newViewLink;
} }
return true; return true;
@ -128,25 +149,28 @@ boolean ScreenManager::removeLinkByUID(ViewLinkedList *viewLinkedList, const uns
{ {
if(isListEmpty(*viewLinkedList))return false; if(isListEmpty(*viewLinkedList))return false;
if((*viewLinkedList)->UID == UID) ViewLinkedList *cursor = viewLinkedList;
{
ViewLink *tmp = *viewLinkedList;
*viewLinkedList = (*viewLinkedList)->next;
free(tmp);
return true;
}
ViewLinkedList cursor = *viewLinkedList; while(*cursor != NULL)
while(!isListEmpty(cursor->next))
{ {
if(cursor->next->UID == UID) //We check if this is the link we want to delete
if((*cursor)->UID == UID)
{ {
ViewLink *tmp = cursor->next; ViewLink *toDelete = *cursor;
cursor->next = cursor->next->next; *cursor = (*cursor)->next;
free(tmp);
if(toDelete->next != NULL)
{
//We update the previous link of the next member since it's going to be deleted
toDelete->next->previous = toDelete->previous;
}
//We also update the tail if the link we delete was the tail
if(_tail == toDelete)_tail = toDelete->previous;
free(toDelete);
return true; return true;
} }
cursor = cursor->next; cursor = &(*cursor)->next;
} }
return false; return false;
} }
@ -186,119 +210,135 @@ ViewLink* ScreenManager::getLinkByUID(ViewLinkedList viewLinkedList, const unsig
return NULL; return NULL;
} }
boolean ScreenManager::displayView(const int UID) void ScreenManager::run()
{
if((millis() - _timeRef < _refreshInterval && !_forceRefresh) || !_enabled) return;
_timeRef = millis();
if(((_error == OK || _error == VIEW_FAILED_TO_EXECUTE) || _forceRefresh) && _currentView != NO_CURRENT_VIEW)
{ {
if(!_enabled) return true;
//Reset draw settings:
_displayRef.clearDisplay(); _displayRef.clearDisplay();
_displayRef.setCursor(0,0); _displayRef.setCursor(0,0);
_displayRef.setTextSize(1); _displayRef.setTextSize(1);
switch(_error)
if(UID == -1 && _currentView == NO_CURRENT_VIEW)
{ {
//We display an error message on the screen case OK:
((ErrorInfo *)_currentViewUndefined.pData)->errorMessage = FPSTR("Could not display current view"); case VIEW_FAILED_TO_EXECUTE:
((ErrorInfo *)_currentViewUndefined.pData)->viewUID = UID; if(!(*_currentView->viewLogicFunction)(_displayRef, _currentView->pData))
(*_currentViewUndefined.viewLogicFunction)(_displayRef, _currentViewUndefined.pData);
_displayRef.display();
_error = CURRENT_VIEW_UNDEFINED;
return false;
}
else if(UID == -1)
{ {
if(_currentView->viewLogicFunction == NULL)
{
//We display an error message on the screen
((ErrorInfo *)_viewFuncUndefined.pData)->errorMessage = FPSTR("View function is NULL");
((ErrorInfo *)_viewFuncUndefined.pData)->viewUID = _currentView->UID;
(*_viewFuncUndefined.viewLogicFunction)(_displayRef, _viewFuncUndefined.pData);
_displayRef.display();
_error = VIEW_FUNC_UNDEFINED;
return false;
}
else if(!(*_currentView->viewLogicFunction)(_displayRef, _currentView->pData))
{
//We display an error message on the screen
_displayRef.clearDisplay(); _displayRef.clearDisplay();
((ErrorInfo *)_viewFunctionFailedToExecute.pData)->errorMessage = FPSTR("View function failed\nto execute"); //Error while executing the view function
((ErrorInfo *)_viewFunctionFailedToExecute.pData)->viewUID = _currentView->UID; ((ErrorInfo *)_viewFunctionFailedToExecute.pData)->viewUID = _currentView->UID;
(*_viewFunctionFailedToExecute.viewLogicFunction)(_displayRef, _viewFunctionFailedToExecute.pData); (*_viewFunctionFailedToExecute.viewLogicFunction)(_displayRef, _viewFunctionFailedToExecute.pData);
_displayRef.display();
_error = VIEW_FAILED_TO_EXECUTE; _error = VIEW_FAILED_TO_EXECUTE;
return false;
} }
else
_error = OK; _error = OK;
_displayRef.display(); break;
return true; case VIEW_NOT_FOUND:
(*_viewNotFound.viewLogicFunction)(_displayRef, _viewNotFound.pData);
break;
case VIEW_FUNC_UNDEFINED:
(*_viewFuncUndefined.viewLogicFunction)(_displayRef, _viewFuncUndefined.pData);
break;
} }
_displayRef.display();
_forceRefresh = false;
}
}
boolean ScreenManager::displayView(const uint8_t UID)
{
if(!_enabled) return true;
_forceRefresh = true;
ViewLink *viewLink = getLinkByUID(_viewLinkedList, UID); ViewLink *viewLink = getLinkByUID(_viewLinkedList, UID);
if(viewLink == NULL) if(viewLink == NULL)
{ {
//We display an error message on the screen //We display an error message on the screen
((ErrorInfo *)_viewNotFound.pData)->errorMessage = FPSTR("View does not exist");
((ErrorInfo *)_viewNotFound.pData)->viewUID = UID; ((ErrorInfo *)_viewNotFound.pData)->viewUID = UID;
(*_viewNotFound.viewLogicFunction)(_displayRef, _viewNotFound.pData);
_displayRef.display();
_error = VIEW_NOT_FOUND; _error = VIEW_NOT_FOUND;
_currentView = &_viewNotFound;
return false; return false;
}else if(viewLink->viewLogicFunction == NULL) }
else if(viewLink->viewLogicFunction == NULL)
{ {
//We display an error message on the screen //We display an error message on the screen
((ErrorInfo *)_viewFuncUndefined.pData)->errorMessage = FPSTR("View function is NULL");
((ErrorInfo *)_viewFuncUndefined.pData)->viewUID = UID; ((ErrorInfo *)_viewFuncUndefined.pData)->viewUID = UID;
(*_viewFuncUndefined.viewLogicFunction)(_displayRef, _viewFuncUndefined.pData);
_displayRef.display();
_error = VIEW_FUNC_UNDEFINED; _error = VIEW_FUNC_UNDEFINED;
_currentView = viewLink; _currentView = viewLink;
return false; return false;
} }
if(!(*viewLink->viewLogicFunction)(_displayRef, viewLink->pData))
{
//We display an error message on the screen
_displayRef.clearDisplay();
((ErrorInfo *)_viewFunctionFailedToExecute.pData)->errorMessage = FPSTR("View function failed\nto execute");
((ErrorInfo *)_viewFunctionFailedToExecute.pData)->viewUID = UID;
(*_viewFunctionFailedToExecute.viewLogicFunction)(_displayRef, _viewFunctionFailedToExecute.pData);
_displayRef.display();
_error = VIEW_FAILED_TO_EXECUTE;
_currentView = viewLink;
return false;
}
_displayRef.display();
_currentView = viewLink; _currentView = viewLink;
_error = OK; _error = OK;
return true; run();
return _error == OK;
} }
boolean ScreenManager::displayNextView() void ScreenManager::displayNextView()
{ {
_forceRefresh = true;
_error = OK;
if(_currentView == NO_CURRENT_VIEW && !isListEmpty(_viewLinkedList)) if(_currentView == NO_CURRENT_VIEW && !isListEmpty(_viewLinkedList))
{ {
_currentView = _viewLinkedList; _currentView = _viewLinkedList;
return displayView();
} }
else if(!isListEmpty(_currentView->next))
if(!isListEmpty(_currentView->next))
{ {
_currentView = _currentView->next; _currentView = _currentView->next;
return displayView(); }
//End of the views, we cycle again :)
else if(isListEmpty(_currentView->next) && !isListEmpty(_viewLinkedList))
{
_currentView = _viewLinkedList;
} }
_currentView = _viewLinkedList; //We check if the view function is defined :
return displayView(); if(_currentView != NO_CURRENT_VIEW)
{
if(_currentView->viewLogicFunction == NULL)
{
((ErrorInfo *)_viewFuncUndefined.pData)->viewUID = _currentView->UID;
_error = VIEW_FUNC_UNDEFINED;
}
}
run();
}
void ScreenManager::displayPreviousView()
{
_forceRefresh = true;
_error = OK;
if(_currentView == NO_CURRENT_VIEW && !isListEmpty(_tail))
{
_currentView = _tail;
}
else if(!isListEmpty(_currentView->previous))
{
_currentView = _currentView->previous;
}
//End of the views, we cycle again :)
else if(isListEmpty(_currentView->previous) && !isListEmpty(_tail))
{
_currentView = _tail;
}
//We check if the view function is defined :
if(_currentView != NO_CURRENT_VIEW)
{
if(_currentView->viewLogicFunction == NULL)
{
((ErrorInfo *)_viewFuncUndefined.pData)->viewUID = _currentView->UID;
_error = VIEW_FUNC_UNDEFINED;
}
}
run();
} }
void ScreenManager::invertDisplayColor(const boolean inverted) void ScreenManager::invertDisplayColor(const boolean inverted)
@ -354,6 +394,20 @@ void ScreenManager::clearDisplay(const boolean bufferOnly)
} }
} }
void ScreenManager::clearViews()
{
ViewLinkedList cursor = _viewLinkedList;
while(!isListEmpty(cursor))
{
ViewLink *toDelete = cursor;
cursor = cursor->next;
free(cursor);
}
//Do not forget to mark the list as empty
_viewLinkedList = NULL;
_tail = NULL;
}
void ScreenManager::setEnabled(boolean value) void ScreenManager::setEnabled(boolean value)
{ {
_enabled = value; _enabled = value;

View File

@ -16,18 +16,21 @@ class ScreenManager
boolean addView(boolean (*viewLogicFunction)(Adafruit_SSD1306&, void*), void *pData, const unsigned char UID); boolean addView(boolean (*viewLogicFunction)(Adafruit_SSD1306&, void*), void *pData, const unsigned char UID);
boolean removeView(const unsigned char UID); boolean removeView(const unsigned char UID);
boolean displayView(const int UID = -1); boolean displayView(const uint8_t UID);
boolean displayNextView(); void displayNextView();
void displayPreviousView();
boolean applyCfgFromSD(); boolean applyCfgFromSD();
void invertDisplayColor(const boolean inverted); void invertDisplayColor(const boolean inverted);
void orientDisplay(const Orientation orientation); void orientDisplay(const Orientation orientation);
void dimDisplay(const boolean dimmed); void dimDisplay(const boolean dimmed);
void clearDisplay(const boolean bufferOnly = false); void clearDisplay(const boolean bufferOnly = false);
void clearViews();
void sleep(); void sleep();
void wakeUp(); void wakeUp();
void setEnabled(boolean value); void setEnabled(boolean value);
boolean getEnabled(); boolean getEnabled();
boolean init(); boolean init();
void run();
Error getError() const; Error getError() const;
const char* getErrorMessage() const; const char* getErrorMessage() const;
@ -58,7 +61,11 @@ class ScreenManager
boolean _displayColorInverted; boolean _displayColorInverted;
boolean _displayDimmed; boolean _displayDimmed;
boolean _enabled; boolean _enabled;
ViewLink* _currentView; uint8_t _refreshRateHz;
uint16_t _refreshInterval;
uint64_t _timeRef;
boolean _forceRefresh;
ViewLink *_currentView, *_tail;
ViewLink _viewNotFound, _viewFuncUndefined, _currentViewUndefined, _viewFunctionFailedToExecute; ViewLink _viewNotFound, _viewFuncUndefined, _currentViewUndefined, _viewFunctionFailedToExecute;
SDCardManager *_sdCardManager; SDCardManager *_sdCardManager;