From 2ba02318db7c5b439b2a1edee1120c93b85d6e6f Mon Sep 17 00:00:00 2001 From: David Date: Sat, 24 Jan 2026 15:19:25 -0600 Subject: [PATCH] Significant refactoring with separate Console Handler. --- AVR Working Controller/AVR.cpp | 329 +++++++------------ AVR Working Controller/AVR.vcxproj | 2 + AVR Working Controller/AVR.vcxproj.filters | 6 + AVR Working Controller/AVRCommandDecoder.cpp | 2 +- AVR Working Controller/ConsoleHandler.cpp | 177 ++++++++++ AVR Working Controller/ConsoleHandler.h | 11 + 6 files changed, 307 insertions(+), 220 deletions(-) create mode 100644 AVR Working Controller/ConsoleHandler.cpp create mode 100644 AVR Working Controller/ConsoleHandler.h diff --git a/AVR Working Controller/AVR.cpp b/AVR Working Controller/AVR.cpp index 269ddfc..5944992 100644 --- a/AVR Working Controller/AVR.cpp +++ b/AVR Working Controller/AVR.cpp @@ -12,6 +12,7 @@ #include #include "SerialPort\SerialPort.h" #include "AVRCommandDecoder.h" +#include "ConsoleHandler.h" enum { @@ -220,7 +221,8 @@ int DetachSerialPort(); // bool SerialSend(const uint8_t *p, DWORD len); -#define SERIALQUEUESIZE 3 +// Just big enough to hold an OSD message which is a 1 message command, 4 messages with text +#define SERIALQUEUESIZE 5 typedef struct { uint8_t *messageToSend; DWORD len; @@ -252,51 +254,11 @@ bool ProcessSerialReceive(void); void EnumerateComPorts(); unsigned long Hex2Dec(uint8_t *p, int dig); - - - void ShowAllStatusInfo(); bool UserWantsToExitCanSniff = false; - DWORD progStartTime; -// For special cursor positioning -bool consoleInit = false; -HANDLE hStdout, hStdin; -CONSOLE_SCREEN_BUFFER_INFO csbi; -WORD wOldColorAttrs; // Save the current console colors - -short consoleWidth = 105; -short consoleHeight = 80; -short consoleScrollHeight = 30; -// 0 99 -// +---------------------------------------------------------------+ -// | Program banner information | 0 -// | on two lines | -// | Current status information starts on line 3 | -// | and down a ways... | -// | | -// | | -// | | -// + Down near the bottom is the scroll region + 59 -// | | -// | | -// | | 79 -// +---------------------------------------------------------------+ 80 -short scrollBot = 0; // set at init: consoleHeight - 1 -short scrollTop = 0; // set at init: consoleHeight - consoleScrollHeight - 1 - - -void Console_Init(); -void Console_Cls(); -bool Console_SetCursorVisibility(bool visible); -void Console_SetCursor(short x, short y); -void Console_Write(const char *text); -void Console_WriteAt(short x, short y, const char *text); -void Console_ScrollBottomRegion(short topLine, short bottomLine); -bool Console_AdvanceToNextLineIfNotRoomFor(short x, int scroll = -1); - typedef struct { const char *pMsg; DWORD MsgLen; @@ -324,6 +286,14 @@ const UserCmd_T UserCommands[] = { { 'v', "Vol 1 Down", {"\x02" "07A1B" "\x03", 7} }, { 'M', "Vol 1 Mute", {"\x02" "07EA2" "\x03", 7} }, { 'm', "Vol 1 UnMute", {"\x02" "07EA3" "\x03", 7} }, + { 'O', "OSD Test Message", }, + { 'T', "Tuning freq rqst", {"\x02" "22000" "\x03", 7} }, + { 'Y', "Main Vol rqst", {"\x02" "22001" "\x03", 7} }, + { 'y', "Zone 2 Vol rqst", {"\x02" "22002" "\x03", 7} }, + { 'U', "Input Name rqst", {"\x02" "22003" "\x03", 7} }, + { 'u', "Zone 2 Name rqst", {"\x02" "22004" "\x03", 7} }, + { 'I', "Zone 2 Vol rqst", {"\x02" "22005" "\x03", 7} }, + { 'i', "Zone 2 Name rqst", {"\x02" "22006" "\x03", 7} }, { '/', "Show All" }, { '?', "Help on runtime commands" }, { 'S', "Set RTS" }, @@ -342,6 +312,23 @@ typedef struct { const char *(*fncValueToText)(uint8_t rDat); } MessageHandler_T; +void UserCommandsSanityCheck() { + uint8_t usedKey[256] = { 0 }; + bool fail = false; + + size_t numCommands = sizeof(UserCommands) / sizeof(UserCmd_T); + for (size_t i = 0; i < numCommands; i++) { + usedKey[UserCommands[i].Char]++; + if (usedKey[UserCommands[i].Char] > 1) { + printf("UserCommandsSanityCheck: Command key %c used more than once\n", UserCommands[i].Char); + fail = true; + } + } + if (fail) { + printf("***** UserCommandsSanityCheck: Errors found in UserCommands table\n"); + exit(EXIT_ConfigError); + } +} // rCmd: 2-ASCII Hex Bytes converted to uint8_t // configOffset: offset into avrStatus.config.DTxx @@ -358,9 +345,9 @@ const MessageHandler_T MessageHandlers[] = { // | | +-------------------- Number of Bytes to transfer into the DT Block // | | | +----------------- Force a 'show all' status screen update // | | | | - // | | | | +-------- sprintf format string for the following - // | | | | | +--- Help to convert numeric value to text - // | | | | | | + // | | | | +-------- sprintf format string for the following Helper + // | | | | | +--- Helper to convert numeric value to text + // | | | | | | { 0x00, 7, 1, 1, "System Report: %s", BusyToText }, { 0x01, 0, 0, 0, "Warning Report: %s", WarnToText }, { 0x10, 31, 1, 1, "Playback Report: %s", PlaybackToText }, @@ -401,7 +388,7 @@ const MessageHandler_T MessageHandlers[] = { { 0x3C, 45, 1, 1, "DC2 Trigger Out: %s", OffOnText }, { 0x3D, 104, 0, 0, "Main Level: %s", Norm10dbDownText }, { 0x3E, 46, 1, 1, "SP B Set: %s", MainZoneBText }, - { 0x3F, 46, 1, 1, "Zone 2 Speaker: %s", OffOnText }, + { 0x3F, 47, 1, 1, "Zone 2 Speaker: %s", OffOnText }, { 0x40, 48, 2, 1, "Level Main R: %s", PM10dbText }, { 0x41, 50, 2, 1, "Level Main L: %s", PM10dbText }, @@ -465,9 +452,39 @@ const MessageHandler_T MessageHandlers[] = { { 0x9A, 0, 0, 0, "Multi Ch Level Swfr 2: %s", M20P0dbText }, { 0xA1, 0, 0, 0, "Zone 3 Mute: %s\n", OffOnText }, - }; +void MessageHandlerSanityCheck() { + uint8_t usedCommands[256] = { 0 }; + uint8_t blockOffset[256] = { 0 }; + + bool fail = false; + // Ensure that the MessageHandlers table is correct + for (int i = 0; i < sizeof(MessageHandlers) / sizeof(MessageHandlers[0]); i++) { + usedCommands[MessageHandlers[i].rCmd]++; + if (usedCommands[MessageHandlers[i].rCmd] > 1) { + printf("***** MessageHandler entry %d has duplicate rCmd of 0x%02X\n", i, MessageHandlers[i].rCmd); + fail = true; + } + blockOffset[MessageHandlers[i].configOffset]++; + if (MessageHandlers[i].configOffset != 0 && blockOffset[MessageHandlers[i].configOffset] > 1) { + printf("***** MessageHandler entry %d has duplicate configOffset of %d\n", i, MessageHandlers[i].configOffset); + fail = true; + } + + if (MessageHandlers[i].numToTransfer > 2) { + printf("***** MessageHandler entry %d has invalid numToTransfer of %d\n", i, MessageHandlers[i].numToTransfer); + } + if (MessageHandlers[i].configOffset + MessageHandlers[i].numToTransfer > sizeof(AVR_Configuration_T)) { + printf("***** MessageHandler entry %d has invalid configOffset of %d\n", i, MessageHandlers[i].configOffset); + } + } + if (fail) { + printf("***** MessageHandler table sanity check failed. Exiting.\n"); + exit(EXIT_ConfigError); + } +} + int CS_KeyHit() { int h = _kbhit(); @@ -526,7 +543,7 @@ void EmitBuffer(const char *prefix, const uint8_t *buf, size_t len = 0, bool app i++; } else if (*p == '\r') { putchar('\n'); - Console_ScrollBottomRegion(scrollTop, scrollBot); + Console_ScrollBottomRegion(); } else if (*p == '\n') { // skip it } else { @@ -534,7 +551,7 @@ void EmitBuffer(const char *prefix, const uint8_t *buf, size_t len = 0, bool app } if ((i & 3) == 0) { if (Console_AdvanceToNextLineIfNotRoomFor(12, 1)) { - //Console_ScrollBottomRegion(scrollTop, scrollBot); + //Console_ScrollBottomRegion(); printf(" "); // sized to get past the timestamp, length, and prefix i = 0; } else { @@ -544,10 +561,10 @@ void EmitBuffer(const char *prefix, const uint8_t *buf, size_t len = 0, bool app p++; } if (appendReturn) { - Console_ScrollBottomRegion(scrollTop, scrollBot); // putch('\r'); + Console_ScrollBottomRegion(); // putch('\r'); } else { //putch('\n'); - //Console_ScrollBottomRegion(scrollTop, scrollBot); + //Console_ScrollBottomRegion(); } } @@ -555,20 +572,20 @@ void EmitBuffer(const char *prefix, const uint8_t *buf, size_t len = 0, bool app void EchoSerialRecv(const uint8_t *pMsg) { Console_SetCursor(0, -1); EmitBuffer("< ", pMsg); - Console_ScrollBottomRegion(scrollTop, scrollBot); + Console_ScrollBottomRegion(); } bool SerialSend(const uint8_t *p, DWORD len) { bool retVal = false; Console_SetCursor(0, -1); EmitBuffer("> ", p, len); - Console_ScrollBottomRegion(scrollTop, scrollBot); + Console_ScrollBottomRegion(); if (avr.Write((const LPVOID)p, len) == len) { retVal = true; } else { Console_SetCursor(0, -1); Console_Write("***** Failed to send. Port not open?"); - Console_ScrollBottomRegion(scrollTop, scrollBot); + Console_ScrollBottomRegion(); } return retVal; } @@ -629,14 +646,14 @@ void EmitRuntimeHelp() { Console_Write(buf); } if (avr.IsOpen()) { - Console_ScrollBottomRegion(scrollTop, scrollBot); + Console_ScrollBottomRegion(); Console_SetCursor(0, -1); printf(" Com Status: RTS: %-3s ", avr.Get_RTS_State() ? "ON" : "OFF"); printf("DTR: %-3s ", avr.Get_DTR_State() ? "ON" : "OFF"); printf("CTS: %-3s ", avr.Get_CTS_State() ? "ON" : "OFF"); printf("DSR: %-3s ", avr.Get_DSR_State() ? "ON" : "OFF"); printf("RI: %-3s", avr.Get_RI_State() ? "ON" : "OFF"); - Console_ScrollBottomRegion(scrollTop, scrollBot); + Console_ScrollBottomRegion(); Console_SetCursor(0, -1); } } @@ -802,6 +819,13 @@ void ProcessKeyboard(void) { if (CS_KeyHit()) { int c = CS_GetChar(); switch (c) { + case 'O': + ProcessSerialQueue((const uint8_t *)"\x02" "21000" "\x03", 7); + ProcessSerialQueue((const uint8_t *)"\x02" "3Test" "\x03", 7); + ProcessSerialQueue((const uint8_t *)"\x02" "3 Mes" "\x03", 7); + ProcessSerialQueue((const uint8_t *)"\x02" "3sage" "\x03", 7); + ProcessSerialQueue((const uint8_t *)"\x02" "3 WOW" "\x03", 7); + break; case '?': EmitRuntimeHelp(); break; @@ -815,13 +839,13 @@ void ProcessKeyboard(void) { avr.Set_RTS_State(TRUE); Console_SetCursor(0, -1); printf("RTS set ON"); - Console_ScrollBottomRegion(scrollTop, scrollBot); + Console_ScrollBottomRegion(); break; case 's': avr.Set_RTS_State(FALSE); Console_SetCursor(0, -1); printf("RTS set OFF"); - Console_ScrollBottomRegion(scrollTop, scrollBot); + Console_ScrollBottomRegion(); break; default: for (int i = 0; i < sizeof(UserCommands) / sizeof(UserCmd_T); i++) { @@ -834,7 +858,7 @@ void ProcessKeyboard(void) { if (!cmdFound) { Console_SetCursor(0, -1); printf("Unrecognized command '%c' (0x%02X)", isprint(c) ? c : '.', (unsigned char)c); - Console_ScrollBottomRegion(scrollTop, scrollBot); + Console_ScrollBottomRegion(); } break; } @@ -876,9 +900,31 @@ void EmitCommandLineHelp() { /* m a i n ( ) */ /******************************************************/ +// 0 99 +// +---------------------------------------------------------------+ +// | Program banner information | 0 +// | on two lines | +// | Current status information starts on line 3 | +// | and down a ways... | +// | | +// | | +// | | +// + Down near the bottom is the scroll region + 59 +// | | +// | | +// | | 79 +// +---------------------------------------------------------------+ 80 + int __cdecl main(int argc, char *argv[]) { + short consoleWidth = 105; + short consoleHeight = 80; + short consoleScrollHeight = 30; + progStartTime = timeGetTime(); - Console_Init(); + MessageHandlerSanityCheck(); // If the table is bad, we exit here + UserCommandsSanityCheck(); // If the table is bad, we exit here + + Console_Init(consoleWidth, consoleHeight, consoleScrollHeight); GetProgName(argv[0]); // Change the colors... @@ -908,7 +954,7 @@ int __cdecl main(int argc, char *argv[]) { if (AttachToSerialPort()) { printf("AVR - a command shell utility for a Yamaha RX-2400 AVR by D.Smart "); printf("[COM%i at %i baud]", avrOnPort, avrBaud); - Console_WriteAt(0, scrollTop - 1, "----------------------------------------"); + Console_WriteAt(0, consoleHeight - consoleScrollHeight -1, "----------------------------------------"); do { ProcessKeyboard(); @@ -971,6 +1017,8 @@ bool CheckTheChecksum(uint8_t *szBuffer, uint32_t num) { return (sum == cksum); } + + // ProcessResponse // // @param[in] szBuffer is the received message @@ -1010,7 +1058,7 @@ void ProcessResponse(uint8_t *szBuffer, uint32_t len) { if (MessageHandlers[i].TextFormatter && MessageHandlers[i].fncValueToText) { sprintf_s(buf, MAXTEXTLEN, MessageHandlers[i].TextFormatter, MessageHandlers[i].fncValueToText(rdat)); Console_Write(buf); - Console_ScrollBottomRegion(scrollTop, scrollBot); + Console_ScrollBottomRegion(); } if (MessageHandlers[i].showAll) { ShowAllStatusInfo(); @@ -1021,7 +1069,7 @@ void ProcessResponse(uint8_t *szBuffer, uint32_t len) { Console_SetCursor(0, -1); sprintf_s(buf, MAXTEXTLEN, "***** type: %X, guard: %X, cmd: %02X, data: %02X", type, guard, rcmd, rdat); Console_Write(buf); - Console_ScrollBottomRegion(scrollTop, scrollBot); + Console_ScrollBottomRegion(); } } @@ -1171,160 +1219,3 @@ int AttachToSerialPort() { return success; } -void Console_Init() { - hStdin = GetStdHandle(STD_INPUT_HANDLE); - hStdout = GetStdHandle(STD_OUTPUT_HANDLE); - if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) { - fprintf(stderr, "Error: Unable to get console buffer info. Code: %lu\n", GetLastError()); - exit(1); - } - scrollBot = consoleHeight - 1; - scrollTop = consoleHeight - consoleScrollHeight - 1; - - // Desired size (width x height) - COORD newSize; - newSize.X = consoleWidth; // columns - newSize.Y = consoleHeight; // rows - - // Step 1: Shrink window if needed before shrinking buffer - SMALL_RECT tempWindow = csbi.srWindow; - tempWindow.Right = tempWindow.Left + (newSize.X - 1); - tempWindow.Bottom = tempWindow.Top + (newSize.Y - 1); - - if (!SetConsoleWindowInfo(hStdout, TRUE, &tempWindow)) { - fprintf(stderr, "Error: Unable to temporarily resize window. Code: %lu\n", GetLastError()); - exit(1); - } - - // Step 2: Set new buffer size - if (!SetConsoleScreenBufferSize(hStdout, newSize)) { - fprintf(stderr, "Error: Unable to set console buffer size. Code: %lu\n", GetLastError()); - exit(1); - } - - // Step 3: Set final window size to match buffer - SMALL_RECT newWindow; - newWindow.Left = 0; - newWindow.Top = 0; - newWindow.Right = newSize.X - 1; - newWindow.Bottom = newSize.Y - 1; - - if (!SetConsoleWindowInfo(hStdout, TRUE, &newWindow)) { - fprintf(stderr, "Error: Unable to set console window size. Code: %lu\n", GetLastError()); - exit(1); - } - // end - - wOldColorAttrs = csbi.wAttributes; - //SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_INTENSITY); -} - -void Console_Close() { - SetConsoleTextAttribute(hStdout, wOldColorAttrs); -} - -void Console_Cls() { - COORD coordScreen = { 0, 0 }; // home for the cursor - DWORD cCharsWritten; - DWORD dwConSize; - - // Get the number of character cells in the current buffer. - if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) { - return; - } - dwConSize = csbi.dwSize.X * csbi.dwSize.Y; - // Fill the entire screen with blanks. - if (!FillConsoleOutputCharacter(hStdout, // Handle to console screen buffer - (TCHAR)' ', // Character to write to the buffer - dwConSize, // Number of cells to write - coordScreen, // Coordinates of first cell - &cCharsWritten)) { // Receive number of characters written - return; - } - // Get the current text attribute. - if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) { - return; - } - // Set the buffer's attributes accordingly. - if (!FillConsoleOutputAttribute(hStdout, // Handle to console screen buffer - csbi.wAttributes, // Character attributes to use - dwConSize, // Number of cells to set attribute - coordScreen, // Coordinates of first cell - &cCharsWritten)) { // Receive number of characters written - return; - } - // Put the cursor at its home coordinates. - SetConsoleCursorPosition(hStdout, coordScreen); -} - -void Console_Write(const char *text) { - DWORD written; - GetConsoleScreenBufferInfo(hStdout, &csbi); - if (csbi.dwCursorPosition.Y >= (csbi.srWindow.Bottom - consoleScrollHeight)) { - //Console_ScrollBottomRegion(scrollTop, scrollBot); - } - WriteConsole(hStdout, text, (DWORD)strlen(text), &written, nullptr); -} - -void Console_WriteAt(short x, short y, const char *text) { - Console_SetCursor(x, y); - DWORD written; - WriteConsole(hStdout, text, (DWORD)strlen(text), &written, nullptr); -} - -void Console_SetCursor(short x, short y) { - GetConsoleScreenBufferInfo(hStdout, &csbi); - csbi.dwCursorPosition.X = (short)((x < 0) ? csbi.srWindow.Right + x : x); - csbi.dwCursorPosition.Y = (short)((y < 0) ? csbi.srWindow.Bottom + 1 + y : y); - SetConsoleCursorPosition(hStdout, csbi.dwCursorPosition); -} - -void Console_ScrollBottomRegion(short topLine, short bottomLine) { - GetConsoleScreenBufferInfo(hStdout, &csbi); - if (topLine < 0) topLine = csbi.srWindow.Bottom + topLine; - if (bottomLine < 0) bottomLine = csbi.srWindow.Bottom + bottomLine; - SMALL_RECT scrollRect = { 0, topLine, csbi.dwMaximumWindowSize.X-1, bottomLine }; - COORD dest = { 0, topLine - 1 }; - CHAR_INFO fill = { ' ', { FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE } }; - ScrollConsoleScreenBuffer(hStdout, &scrollRect, &scrollRect, dest, &fill); - putch('\r'); // Cursor to left margin -} - -bool Console_AdvanceToNextLineIfNotRoomFor(short x, int scroll) { - bool advanced = false; - GetConsoleScreenBufferInfo(hStdout, &csbi); - if (csbi.dwCursorPosition.X + x > csbi.dwMaximumWindowSize.X) { - advanced = true; - if (scroll == 1) { - Console_ScrollBottomRegion(scrollTop, scrollBot); - } else { - csbi.dwCursorPosition.Y++; - } - Console_SetCursor(0, csbi.dwCursorPosition.Y); - } - return advanced; -} - -// Console_SetCursorVisibility -// -// Set the state of the cursor and provide the prior state so it -// can be restored -// -// @param[in] bool the desired state, true is visible -// @returns the prior state, true is visible -// -bool Console_SetCursorVisibility(bool visible) { - CONSOLE_CURSOR_INFO cursorInfo; - bool priorState = true; - - if (!GetConsoleCursorInfo(hStdout, &cursorInfo)) { - // printf("***** Error: Unable to get cursor info.\n"); - return priorState; - } - priorState = cursorInfo.bVisible; - cursorInfo.bVisible = visible; // true = show, false = hide - if (!SetConsoleCursorInfo(hStdout, &cursorInfo)) { - // std::cerr << "Error: Unable to set cursor info.\n"; - } - return priorState; -} \ No newline at end of file diff --git a/AVR Working Controller/AVR.vcxproj b/AVR Working Controller/AVR.vcxproj index f693c09..d08249e 100644 --- a/AVR Working Controller/AVR.vcxproj +++ b/AVR Working Controller/AVR.vcxproj @@ -127,10 +127,12 @@ + + diff --git a/AVR Working Controller/AVR.vcxproj.filters b/AVR Working Controller/AVR.vcxproj.filters index 5cedb8e..b43dc3a 100644 --- a/AVR Working Controller/AVR.vcxproj.filters +++ b/AVR Working Controller/AVR.vcxproj.filters @@ -24,6 +24,9 @@ Source Files + + Source Files + @@ -32,5 +35,8 @@ Source Files + + Header Files + \ No newline at end of file diff --git a/AVR Working Controller/AVRCommandDecoder.cpp b/AVR Working Controller/AVRCommandDecoder.cpp index b71a14c..0ea6f54 100644 --- a/AVR Working Controller/AVRCommandDecoder.cpp +++ b/AVR Working Controller/AVRCommandDecoder.cpp @@ -144,7 +144,7 @@ const char *NotTunedTunedText(uint8_t val) { const char *InputModeText(uint8_t val) { static const char *buf[] = { - "Auto", "DTS", "Analog", "Analog Only", "AAC", "Unk" + "Auto", "unk", "DTS", "unk", "Analog", "Analog Only", "AAC", "Unk" }; if (val >= sizeof(buf) / sizeof(buf[0])) val = sizeof(buf) / sizeof(buf[0]) - 1; diff --git a/AVR Working Controller/ConsoleHandler.cpp b/AVR Working Controller/ConsoleHandler.cpp new file mode 100644 index 0000000..a198d7b --- /dev/null +++ b/AVR Working Controller/ConsoleHandler.cpp @@ -0,0 +1,177 @@ + + +#include "stdafx.h" +#include +#include +#include +#include "ConsoleHandler.h" + +// For special cursor positioning +static bool consoleInit = false; +static HANDLE hStdout, hStdin; +static CONSOLE_SCREEN_BUFFER_INFO csbi; +static WORD wOldColorAttrs; // Save the current console colors + +static short consoleWidth = 0; +static short consoleHeight = 0; +static short scrollBot = 0; // set at init: consoleHeight - 1 +static short scrollTop = 0; // set at init: consoleHeight - consoleScrollHeight - 1 + +void Console_Init(short Width, short Height, short bottomScrollHeight) { + hStdin = GetStdHandle(STD_INPUT_HANDLE); + hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) { + fprintf(stderr, "Error: Unable to get console buffer info. Code: %lu\n", GetLastError()); + exit(1); + } + consoleWidth = Width; + consoleHeight = Height; + + scrollBot = consoleHeight - 1; + scrollTop = consoleHeight - bottomScrollHeight - 1; + + // Desired size (width x height) + COORD newSize; + newSize.X = consoleWidth; // columns + newSize.Y = consoleHeight; // rows + + // Step 1: Shrink window if needed before shrinking buffer + SMALL_RECT tempWindow = csbi.srWindow; + tempWindow.Right = tempWindow.Left + (newSize.X - 1); + tempWindow.Bottom = tempWindow.Top + (newSize.Y - 1); + + if (!SetConsoleWindowInfo(hStdout, TRUE, &tempWindow)) { + fprintf(stderr, "Error: Unable to temporarily resize window. Code: %lu\n", GetLastError()); + exit(1); + } + + // Step 2: Set new buffer size + if (!SetConsoleScreenBufferSize(hStdout, newSize)) { + fprintf(stderr, "Error: Unable to set console buffer size. Code: %lu\n", GetLastError()); + exit(1); + } + + // Step 3: Set final window size to match buffer + SMALL_RECT newWindow; + newWindow.Left = 0; + newWindow.Top = 0; + newWindow.Right = newSize.X - 1; + newWindow.Bottom = newSize.Y - 1; + + if (!SetConsoleWindowInfo(hStdout, TRUE, &newWindow)) { + fprintf(stderr, "Error: Unable to set console window size. Code: %lu\n", GetLastError()); + exit(1); + } + // end + + wOldColorAttrs = csbi.wAttributes; + //SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_INTENSITY); +} + +void Console_Close() { + SetConsoleTextAttribute(hStdout, wOldColorAttrs); +} + +void Console_Cls() { + COORD coordScreen = { 0, 0 }; // home for the cursor + DWORD cCharsWritten; + DWORD dwConSize; + + // Get the number of character cells in the current buffer. + if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) { + return; + } + dwConSize = csbi.dwSize.X * csbi.dwSize.Y; + // Fill the entire screen with blanks. + if (!FillConsoleOutputCharacter(hStdout, // Handle to console screen buffer + (TCHAR)' ', // Character to write to the buffer + dwConSize, // Number of cells to write + coordScreen, // Coordinates of first cell + &cCharsWritten)) { // Receive number of characters written + return; + } + // Get the current text attribute. + if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) { + return; + } + // Set the buffer's attributes accordingly. + if (!FillConsoleOutputAttribute(hStdout, // Handle to console screen buffer + csbi.wAttributes, // Character attributes to use + dwConSize, // Number of cells to set attribute + coordScreen, // Coordinates of first cell + &cCharsWritten)) { // Receive number of characters written + return; + } + // Put the cursor at its home coordinates. + SetConsoleCursorPosition(hStdout, coordScreen); +} + +void Console_Write(const char *text) { + DWORD written; + WriteConsole(hStdout, text, (DWORD)strlen(text), &written, nullptr); +} + +void Console_WriteAt(short x, short y, const char *text) { + Console_SetCursor(x, y); + DWORD written; + WriteConsole(hStdout, text, (DWORD)strlen(text), &written, nullptr); +} + +void Console_SetCursor(short x, short y) { + GetConsoleScreenBufferInfo(hStdout, &csbi); + csbi.dwCursorPosition.X = (short)((x < 0) ? csbi.srWindow.Right + x : x); + csbi.dwCursorPosition.Y = (short)((y < 0) ? csbi.srWindow.Bottom + 1 + y : y); + SetConsoleCursorPosition(hStdout, csbi.dwCursorPosition); +} + +void Console_ScrollBottomRegion() { + short topLine = scrollTop + 1; + short bottomLine = scrollBot; + GetConsoleScreenBufferInfo(hStdout, &csbi); + if (topLine < 0) topLine = csbi.srWindow.Bottom + topLine; + if (bottomLine < 0) bottomLine = csbi.srWindow.Bottom + bottomLine; + SMALL_RECT scrollRect = { 0, topLine, csbi.dwMaximumWindowSize.X - 1, bottomLine }; + COORD dest = { 0, topLine - 1 }; + CHAR_INFO fill = { ' ', { FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE } }; + ScrollConsoleScreenBuffer(hStdout, &scrollRect, &scrollRect, dest, &fill); + _putch('\r'); // Cursor to left margin +} + +bool Console_AdvanceToNextLineIfNotRoomFor(short x, int scroll) { + bool advanced = false; + GetConsoleScreenBufferInfo(hStdout, &csbi); + if (csbi.dwCursorPosition.X + x > csbi.dwMaximumWindowSize.X) { + advanced = true; + if (scroll == 1) { + Console_ScrollBottomRegion(); + } else { + csbi.dwCursorPosition.Y++; + } + Console_SetCursor(0, csbi.dwCursorPosition.Y); + } + return advanced; +} + +// Console_SetCursorVisibility +// +// Set the state of the cursor and provide the prior state so it +// can be restored +// +// @param[in] bool the desired state, true is visible +// @returns the prior state, true is visible +// +bool Console_SetCursorVisibility(bool visible) { + CONSOLE_CURSOR_INFO cursorInfo; + bool priorState = true; + + if (!GetConsoleCursorInfo(hStdout, &cursorInfo)) { + // printf("***** Error: Unable to get cursor info.\n"); + return priorState; + } + priorState = cursorInfo.bVisible; + cursorInfo.bVisible = visible; // true = show, false = hide + if (!SetConsoleCursorInfo(hStdout, &cursorInfo)) { + // std::cerr << "Error: Unable to set cursor info.\n"; + } + return priorState; +} \ No newline at end of file diff --git a/AVR Working Controller/ConsoleHandler.h b/AVR Working Controller/ConsoleHandler.h new file mode 100644 index 0000000..c37ff68 --- /dev/null +++ b/AVR Working Controller/ConsoleHandler.h @@ -0,0 +1,11 @@ +#pragma once + + +void Console_Init(short Width, short Height, short bottomScrollHeight); +void Console_Cls(); +bool Console_SetCursorVisibility(bool visible); +void Console_SetCursor(short x, short y); +void Console_Write(const char *text); +void Console_WriteAt(short x, short y, const char *text); +void Console_ScrollBottomRegion(); +bool Console_AdvanceToNextLineIfNotRoomFor(short x, int scroll = -1);