PushToGo on STM32F429-Disco Board
Dependencies: BSP_DISCO_F429ZI LCD_DISCO_F429ZI pushtogo usb
Diff: LCDConsole.cpp
- Revision:
- 0:084d1dae2ea1
- Child:
- 1:64c1fd738059
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LCDConsole.cpp Sun Aug 19 05:20:21 2018 +0000 @@ -0,0 +1,302 @@ +/* + * LCDStreamHandle.cpp + * + * Created on: 2018Äê2ÔÂ25ÈÕ + * Author: caoyuan9642 + */ + +#include "LCDConsole.h" +#include <math.h> +#include <ctype.h> +#include "MCULoadMeasurement.h" + +bool LCDConsole::inited = false; +Mutex LCDConsole::mutex; +LCD_DISCO_F429ZI LCDConsole::lcd; +int LCDConsole::x0 = 0, LCDConsole::y0 = 0, LCDConsole::width = lcd.GetXSize(), + LCDConsole::height = lcd.GetYSize(); +int LCDConsole::textheight = 0, LCDConsole::textwidth = 0, + LCDConsole::buffersize = 0; +int *LCDConsole::buffer, *LCDConsole::head, *LCDConsole::tail; +Semaphore LCDConsole::sem_update(0, 1); +Thread LCDConsole::thread(osPriorityLow, OS_STACK_SIZE, NULL, "LCD Console"); + +LCDConsole lcd_handle_out("lcd_stdout", LCD_COLOR_WHITE); +LCDConsole lcd_handle_err("lcd_stderr", LCD_COLOR_YELLOW); + + +#define BG_COLOR LCD_COLOR_BLACK + +void idle_hook() +{ + core_util_critical_section_enter(); + MCULoadMeasurement::getInstance().setMCUActive(false); +// sleep_manager_lock_deep_sleep(); +// sleep(); +// __WFI(); +// sleep_manager_unlock_deep_sleep(); + int i = 1000; + while (i--) + ; + MCULoadMeasurement::getInstance().setMCUActive(true); + core_util_critical_section_exit(); +} + +void LCDConsole::init(int x0, int y0, int width, int height) +{ + LCDConsole::x0 = x0; + LCDConsole::y0 = y0; + LCDConsole::width = width; + LCDConsole::height = height; + + // Clear area with background color + lcd.SetTextColor(BG_COLOR); + lcd.FillRect(x0, y0, width, height); + BSP_LCD_SetFont(&Font12); + + // Calculate width and height of the text area + textwidth = width / BSP_LCD_GetFont()->Width; + textheight = height / BSP_LCD_GetFont()->Height; + buffersize = textwidth * textheight; + + // Init buffer + buffer = new int[buffersize](); // Will be init to zero + head = tail = buffer; + + // Start task thread + thread.start(task_thread); + + // Register idle hook + Thread::attach_idle_hook(idle_hook); + MCULoadMeasurement::getInstance().reset(); +} + +void LCDConsole::task_thread() +{ + int *buffer0 = new int[buffersize](); // Local buffer + char sbuf[64]; + // Main loop + while (true) + { + // Wait for update signal. + int s = sem_update.wait(1000); + if (s == 0) + { + // Timeout, update CPU usage + lcd.SetBackColor(LCD_COLOR_BLUE); + lcd.SetTextColor(LCD_COLOR_WHITE); + int len = sprintf(sbuf, "Load: %4.1f%% ", + MCULoadMeasurement::getInstance().getCPUUsage() * 100); + lcd.DisplayStringAt(0, lcd.GetYSize() - BSP_LCD_GetFont()->Height, + (unsigned char*) sbuf, LEFT_MODE); + MCULoadMeasurement::getInstance().reset(); + + time_t t = time(NULL); + struct tm ts; + gmtime_r(&t, &ts); + strftime(sbuf, sizeof(sbuf), "%T, %x", &ts); + strcat(sbuf, " UTC"); // append + + lcd.SetBackColor(0xFF00AF7F); + lcd.DisplayStringAt(BSP_LCD_GetFont()->Width * len, + lcd.GetYSize() - BSP_LCD_GetFont()->Height, + (unsigned char*) sbuf, LEFT_MODE); + + continue; + } + + mutex.lock(); // Lock the buffer. If any thread is still printing stuff to the buffer, this will wait for it to finish + memcpy(buffer0, buffer, buffersize * sizeof(*buffer)); // Copy buffer to a private one to work in + mutex.unlock(); // Unlock the buffer. If any thread is waiting for the mutex, it can now run (and potentially generating another update signal). + + int *head0 = buffer0 + (head - buffer); + // clear area; +// lcd.SetTextColor(BG_COLOR); +// lcd.FillRect(x0, y0, width, height); + + int line = 0, col = 0; + int x = x0, y = y0; + lcd.SetBackColor(BG_COLOR); + for (int *p = head0, i = 0; i < buffersize; i++) + { + // Set color from the buffer + lcd.SetTextColor((uint32_t(0xFF000000 | (*p >> 8)))); + + // Content to draw + unsigned char c = (*p) & 0xFF; + + // Display the char if displayable, otherwise put white space + if (isprint(c)) + lcd.DisplayChar(x, y, c); + else + lcd.DisplayChar(x, y, ' '); + + x += BSP_LCD_GetFont()->Width; + col++; + if (col == textwidth) + { + // Next line + line++; + y += BSP_LCD_GetFont()->Height; + col = 0; + x = 0; + } + p++; + if (p - buffer0 == buffersize) + p = buffer0; // wrap around the buffer + } + } +} + +LCDConsole::LCDConsole(const char * name, uint32_t color) : + FileLike(name) +{ + this->color = color; +} + +ssize_t LCDConsole::read(void* buffer, size_t size) +{ +// Not supported + return -1; +} + +ssize_t LCDConsole::write(const void* str, size_t size) +{ + mutex.lock(); + char *pb = (char*) str; + for (char *p = pb; p < pb + size; p++) + { + char c = (int) (*p); + bool scroll = false; + if (isprint(c)) + { + *(tail++) = (color << 8) | c; // Put the current char and color into the buffer + if (tail >= buffer + buffersize) + tail -= buffersize; + if (tail == head) + scroll = true; + } + else if (c == '\b') + { + // Backspace, tail pointer go back by one + if (tail != head) // If the buffer is empty, do nothing + { + tail--; + if (tail < buffer) + tail += buffersize; + } + + } + else if (c == '\r') + { + // Roll back to start of line + int currpos = (tail - head + buffersize) % buffersize; // current position in buffer + int linestart = currpos - currpos % textwidth; // Position of the start of the line + tail = head + linestart; + if (tail >= buffer + buffersize) + tail -= buffersize; + } + else if (c == '\n') + { + // Newline + int currpos = (tail - head + buffersize) % buffersize; // current position in buffer + int nextlinestart = currpos - currpos % textwidth + textwidth; // Position of a new line start + tail = head + nextlinestart; + if (tail >= buffer + buffersize) + tail -= buffersize; + if (nextlinestart >= buffersize) // Scroll if the tail will overrun the head + scroll = true; + } + + // wrap + + if (scroll) + { + // Scroll a line + head += textwidth; // Increase head by one line + if (head >= buffer + buffersize) + { + head -= buffersize; // wrap + } + for (int *p = tail; p != head;) + { + *(p++) = 0; // Set everything between tail and head to null + if (p >= buffer + buffersize) + { + p -= buffersize; + } + } + } + } + sem_update.release(); // Signal the task to update the graphics + + mutex.unlock(); + return size; +} + +off_t LCDConsole::seek(off_t offset, int whence) +{ +// Not supported + return -1; +} + +int LCDConsole::close() +{ + return 0; +} + +void LCDConsole::redirect(bool tolcd) +{ + if (tolcd) + { + freopen("/lcd_stdout", "w", stdout); + freopen("/lcd_stderr", "w", stderr); + } + else + { + freopen("/stdout", "w", stdout); + freopen("/stderr", "w", stderr); + } +} + +// Override the default fatal error handler +extern "C" void error(const char* format, ...) +{ + static unsigned char buffer[257]; + core_util_critical_section_enter(); +#ifndef NDEBUG + + LCD_DISCO_F429ZI lcd; // Use local copy of the lcd, so that this function can be used at any stage of the initialization. + va_list arg; + va_start(arg, format); + int size = vsnprintf((char*) buffer, 256, format, arg); + if (size > 256) + { + // Properly terminate the string + size = 256; + buffer[256] = '\0'; + } + va_end(arg); + + BSP_LCD_SetFont(&Font20); + + lcd.Clear(LCD_COLOR_WHITE); + lcd.SetBackColor(LCD_COLOR_WHITE); + lcd.SetTextColor(LCD_COLOR_RED); + + int i = 0, line = 0; + while (i < size) + { + unsigned char c = buffer[i + 16]; + buffer[i + 16] = '\0'; + lcd.DisplayStringAtLine(line++, buffer + i); + buffer[i + 16] = c; + i += 16; + } +#endif + + core_util_critical_section_exit(); + exit(1); +} + +