#include "ScreenManager.h" ScreenManager::ScreenManager(Adafruit_SSD1306 &display) : _displayRef(display), _displayColorInverted(false), _displayDimmed(false), _currentView(NO_CURRENT_VIEW), _error(OK) , _viewNotFound{&(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} , _viewFunctionFailedToExecute{&(displayError), (ErrorInfo *)malloc(sizeof(ErrorInfo)), RESERVED_VIEW_UID, NULL} { _viewLinkedList = (ViewLinkedList) createEmptyList(); _displayRef.setRotation(OR_0); _displayRef.setTextColor(WHITE); } boolean ScreenManager::addView(boolean (*viewLogicFunction)(Adafruit_SSD1306&, void*), void *pData, const unsigned char UID) { ViewLink viewLink ={viewLogicFunction, pData, UID, NULL}; addNewLinkAtTheEnd(&_viewLinkedList, viewLink); } void *ScreenManager::createEmptyList() { return NULL; } boolean ScreenManager::addNewLinkAtTheEnd(ViewLinkedList *viewLinkedList, ViewLink viewLink) { ViewLink *newViewLink = (ViewLink*) malloc(sizeof(ViewLink)); if(newViewLink == NULL) { _error = MALLOC_FAILED; return false; } //Because of the const member memcpy(newViewLink, &viewLink, sizeof(*newViewLink)); if(isListEmpty(*viewLinkedList))*viewLinkedList = newViewLink; else { if((*viewLinkedList)->UID == newViewLink->UID) { ViewLink *link = *viewLinkedList; *viewLinkedList = newViewLink; newViewLink->next = link->next; free(link); return true; } 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; } cursor->next = newViewLink; } return true; } boolean ScreenManager::removeView(const unsigned char UID) { return removeLinkByUID(&_viewLinkedList ,UID); } boolean ScreenManager::removeLinkByUID(ViewLinkedList *viewLinkedList, const unsigned char UID) { if(isListEmpty(*viewLinkedList))return false; if((*viewLinkedList)->UID == UID) { ViewLink *tmp = *viewLinkedList; *viewLinkedList = (*viewLinkedList)->next; free(tmp); return true; } ViewLinkedList cursor = *viewLinkedList; while(!isListEmpty(cursor->next)) { if(cursor->next->UID == UID) { ViewLink *tmp = cursor->next; cursor->next = cursor->next->next; free(tmp); return true; } cursor = cursor->next; } return false; } boolean ScreenManager::isListEmpty(ViewLinkedList viewLinkedList) { return viewLinkedList == NULL; } ScreenManager::Error ScreenManager::getError() const { return _error; } void ScreenManager::iterateThroughList() { Serial.println("Lets go through"); ViewLinkedList temp = _viewLinkedList; while(!isListEmpty(temp)) { Serial.print("UID : ");Serial.println(temp->UID); temp = temp->next; } } ViewLink* ScreenManager::getLinkByUID(ViewLinkedList viewLinkedList, const unsigned char UID) { if(isListEmpty(viewLinkedList)) return NULL; while(!isListEmpty(viewLinkedList)) { if(viewLinkedList->UID == UID)return viewLinkedList; viewLinkedList = viewLinkedList->next; } return NULL; } boolean ScreenManager::displayView(const int UID) { //Reset draw settings: _displayRef.clearDisplay(); _displayRef.setCursor(0,0); _displayRef.setTextSize(1); if(UID == -1 && _currentView == NO_CURRENT_VIEW) { //We display an error message on the screen ((ErrorInfo *)_currentViewUndefined.pData)->errorMessage = F("Could not display current view"); ((ErrorInfo *)_currentViewUndefined.pData)->viewUID = UID; (*_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 = F("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(); ((ErrorInfo *)_viewFunctionFailedToExecute.pData)->errorMessage = F("View function failed\nto execute"); ((ErrorInfo *)_viewFunctionFailedToExecute.pData)->viewUID = _currentView->UID; (*_viewFunctionFailedToExecute.viewLogicFunction)(_displayRef, _viewFunctionFailedToExecute.pData); _displayRef.display(); _error = VIEW_FAILED_TO_EXECUTE; return false; } _error = OK; _displayRef.display(); return true; } ViewLink *viewLink = getLinkByUID(_viewLinkedList, UID); if(viewLink == NULL) { //We display an error message on the screen ((ErrorInfo *)_viewNotFound.pData)->errorMessage = F("View does not exist"); ((ErrorInfo *)_viewNotFound.pData)->viewUID = UID; (*_viewNotFound.viewLogicFunction)(_displayRef, _viewNotFound.pData); _displayRef.display(); _error = VIEW_NOT_FOUND; _currentView = &_viewNotFound; return false; }else if(viewLink->viewLogicFunction == NULL) { //We display an error message on the screen ((ErrorInfo *)_viewFuncUndefined.pData)->errorMessage = F("View function is NULL"); ((ErrorInfo *)_viewFuncUndefined.pData)->viewUID = UID; (*_viewFuncUndefined.viewLogicFunction)(_displayRef, _viewFuncUndefined.pData); _displayRef.display(); _error = VIEW_FUNC_UNDEFINED; _currentView = viewLink; return false; } if(!(*viewLink->viewLogicFunction)(_displayRef, viewLink->pData)) { //We display an error message on the screen _displayRef.clearDisplay(); ((ErrorInfo *)_viewFunctionFailedToExecute.pData)->errorMessage = F("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; _error = OK; return true; } boolean ScreenManager::displayNextView() { if(_currentView == NO_CURRENT_VIEW && !isListEmpty(_viewLinkedList)) { _currentView = _viewLinkedList; return displayView(); } if(!isListEmpty(_currentView->next)) { _currentView = _currentView->next; return displayView(); } _currentView = _viewLinkedList; return displayView(); } void ScreenManager::invertDisplayColor(const boolean inverted) { _displayRef.invertDisplay(inverted); _displayColorInverted = inverted; } void ScreenManager::dimDisplay(const boolean dimmed) { _displayRef.dim(dimmed); _displayDimmed = dimmed; } void ScreenManager::orientDisplay(const Orientation orientation) { _displayRef.setRotation(orientation); } boolean ScreenManager::isDisplayColorInverted() const { return _displayColorInverted; } Orientation ScreenManager::getDisplayOrientation() const { return (Orientation) _displayRef.getRotation(); } boolean ScreenManager::isDisplayDimmed() const { return _displayDimmed; } void ScreenManager::clearDisplay(const boolean bufferOnly) { if(bufferOnly) _displayRef.clearDisplay(); else { _displayRef.clearDisplay(); _displayRef.display(); } } unsigned char ScreenManager::getViewCount() { unsigned char counter = 0; ViewLinkedList temp = _viewLinkedList; while(!isListEmpty(temp)) { counter++; temp = temp->next; } return counter; } int ScreenManager::getCurrentViewUID() const { if(_currentView == NO_CURRENT_VIEW) return -1; return _currentView->UID < 0 ? -1 : _currentView->UID; } boolean ScreenManager::displayError(Adafruit_SSD1306 &display, void *pData) { const ErrorInfo *errorInfo = (ErrorInfo *) pData; display.setTextSize(3); display.setCursor(19,3); display.drawRect(0,0,display.width(), 27, WHITE); display.print(F("ERROR")); display.setTextSize(1); display.setCursor(0,29); display.print(errorInfo->errorMessage); //We then display the view UID that caused the probleme if(errorInfo->viewUID >= 0) { display.setCursor(0,56); char buff[30] = ""; sprintf(buff,"VIEW UID : %d" ,errorInfo->viewUID); display.println(buff); } return true; } const char* ScreenManager::getErrorMessage()const { //NO_VIEW_ERROR, MALLOC_FAILED, VIEW_NOT_FOUND, VIEW_FUNC_UNDEFINED, VIEW_FAILED_TO_EXECUTE, CURRENT_VIEW_UNDEFINED switch(_error) { case OK: return "NO ERROR"; case MALLOC_FAILED: return "MALLOC FAILED"; case VIEW_NOT_FOUND: return "VIEW NOT FOUND"; case VIEW_FUNC_UNDEFINED: return "VIEW FUNCTION UNDEFINED (NULL)"; case VIEW_FAILED_TO_EXECUTE: return "VIEW FAILED TO EXECUTE (RETURNED FALSE)"; case CURRENT_VIEW_UNDEFINED: return "CURRENT VIEW UNDEFINED"; default : return "UNKNOWN ERROR"; } }