// ----------------------------------------------------------------------------- /// @file Display.c /// @brief Description // ----------------------------------------------------------------------------- // Micro-Key bv // Industrieweg 28, 9804 TG Noordhorn // Postbus 92, 9800 AB Zuidhorn // The Netherlands // Tel: +31 594 503020 // Fax: +31 594 505825 // Email: support@microkey.nl // Web: www.microkey.nl // ----------------------------------------------------------------------------- /// $Revision$ /// $Author$ /// $Date$ // (c) 2017 Micro-Key bv // ----------------------------------------------------------------------------- /// @file Display.c /// @ingroup {group_name} // ----------------------------------------------------------------------------- // Include files // ----------------------------------------------------------------------------- #include #include "Display.h" #include "Logger.h" #include "nhd0420.h" #include "platform.h" // ----------------------------------------------------------------------------- // Constant and macro definitions // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // Type definitions // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // File-scope variables // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // Function declarations // ----------------------------------------------------------------------------- static void DisplayTask(void* parameters); // ----------------------------------------------------------------------------- // Function definitions // ----------------------------------------------------------------------------- ErrorStatus Display_construct(struct Display* self, struct DisplayDevice* displayDevice, int TaskPriority, uint16_t stackSize, int maxCharactersPerTransmit, int refreshFeedFrequency_ms, int refreshPeriod) { ErrorStatus returnValue = SUCCESS; if (!self->initialized) { self->displayDevice = displayDevice; self->TaskPriority = TaskPriority; self->stackSize = stackSize; self->maxCharactersPerTransmit = maxCharactersPerTransmit; self->refreshFeedCounter = 0; self->refreshFeedFrequency_ms = refreshFeedFrequency_ms; self->refreshPeriod_ms = refreshPeriod; if(returnValue == SUCCESS) { // Create a semaphore to sync writing requests to the display vSemaphoreCreateBinary(self->displayWriteRequest); } if (returnValue == SUCCESS) { returnValue = DisplayContent_construct(&self->displayContent, self->displayDevice->parameters.numberOfRows, self->displayDevice->parameters.numberOfColumns); } self->runTask = true; if(returnValue == SUCCESS) { if (xTaskCreate(DisplayTask, (const char*)"DisplayTask", self->stackSize, self, self->TaskPriority, &self->taskHandle) != pdTRUE) { returnValue = ERROR; LOGGER_ERROR(mainLog, "Starting display task failed"); } else { LOGGER_INFO(mainLog, "Display task started"); self->initialized = true; } } } else { returnValue = ERROR; } return returnValue; } void Display_destruct(struct Display* self) { self->runTask = false; } ErrorStatus Display_clearScreen(struct Display* self) { ErrorStatus returnValue = SUCCESS; DisplayContent_clear(&self->displayContent); xSemaphoreGive(self->displayWriteRequest); return returnValue; } ErrorStatus Display_clearLine(struct Display* self, size_t line) { char buffer[self->displayDevice->parameters.numberOfColumns + 1]; int loopcounter; for (loopcounter = 0; loopcounter < self->displayDevice->parameters.numberOfColumns; loopcounter++) { buffer[loopcounter] = 0x20; } buffer[self->displayDevice->parameters.numberOfColumns] = '\0'; return Display_write(self, buffer, line, 1); } ErrorStatus Display_setState(struct Display* self, DisplayDevice_functionalState state) { return DisplayDevice_setState(self->displayDevice, state); } ErrorStatus Display_setBrightness(struct Display* self, size_t brightness) { return DisplayDevice_setBrightness(self->displayDevice, brightness); } ErrorStatus Display_setContrast(struct Display* self, size_t contrast) { return DisplayDevice_setContrast(self->displayDevice, contrast); } ErrorStatus Display_write(struct Display* self, const char* buffer, size_t row, size_t column) { ErrorStatus returnValue = SUCCESS; if (self->initialized) { int length = 0; // Prior to any action on the display memory, perform necessary checkings if (returnValue == SUCCESS) { // Check that the row coordinate does not exceed the display boundary if (row - 1 >= self->displayDevice->parameters.numberOfRows) { returnValue = ERROR; } } if (returnValue == SUCCESS) { // Check that the column coordinate does not exceed the display boundary if (column - 1 >= self->displayDevice->parameters.numberOfColumns) { returnValue = ERROR; } } if (returnValue == SUCCESS) { length = strlen(buffer); // Check that the length request does not exceed the display boundary // This is checked in combination with the column coordinate // numberOfColumns - column >= length // must be valid in order to put the requested message on display if (self->displayDevice->parameters.numberOfColumns - (column - 1) < length) { returnValue = ERROR; } } if (returnValue == SUCCESS) { int loopCounter; for (loopCounter = 0; loopCounter < length; loopCounter++) { DisplayContent_updateCharacter(&self->displayContent, (row - 1), (column - 1) + loopCounter, buffer[loopCounter]); } xSemaphoreGive(self->displayWriteRequest); } } else { returnValue = ERROR; } return returnValue; } void Display_feedRefreshCounter(struct Display* self) { if (self->initialized) { self->refreshFeedCounter++; if (self->refreshFeedCounter * self->refreshFeedFrequency_ms > self->refreshPeriod_ms) { xSemaphoreGive(self->displayWriteRequest); } } } void Display_feedRefreshCounterFromISR(struct Display* self) { portBASE_TYPE higherPriorityTaskWoken = pdFALSE; if (self->initialized) { self->refreshFeedCounter++; if (self->refreshFeedCounter * self->refreshFeedFrequency_ms > self->refreshPeriod_ms) { xSemaphoreGiveFromISR(self->displayWriteRequest, &higherPriorityTaskWoken); } } portEND_SWITCHING_ISR(higherPriorityTaskWoken); } static void DisplayTask(void* parameters) { struct Display* self = (struct Display*)parameters; char buffer; int rowCounter = 0; int colCounter = 0; while (self->runTask) { xSemaphoreTake(self->displayWriteRequest, portMAX_DELAY); // Check for display refresh timings if (self->refreshFeedCounter * self->refreshFeedFrequency_ms > self->refreshPeriod_ms) { self->refreshFeedCounter = 0; DisplayContent_refresh(&self->displayContent); } for (rowCounter = 0; rowCounter < self->displayDevice->parameters.numberOfRows; rowCounter++) { for (colCounter = 0; colCounter < self->displayDevice->parameters.numberOfColumns; colCounter++) { if (DisplayContent_isCharacterUpdated(&self->displayContent, rowCounter, colCounter)) { buffer = DisplayContent_getCharacter(&self->displayContent, rowCounter, colCounter); DisplayDevice_write(self->displayDevice, &buffer, 1, rowCounter + 1, colCounter + 1); } } } vTaskDelay(10); } // Task has been marked to end - after leaving the endless loop, end/delete this task vTaskDelete(NULL); }