From 8cd05e5e7e6ad16884bce70d2aa14bc5e3fda59c Mon Sep 17 00:00:00 2001 From: David Date: Sun, 18 Jan 2026 15:45:49 -0600 Subject: [PATCH] Improved decoding and screen presentation (especially the scroll region at the bottom). --- AVR Working w-o Decoder/AVR.cpp | 367 ++++++++++++++---- ...aha RX-V2400_RS232C_CommandsForSW.pdf.xlsx | Bin 37030 -> 37073 bytes 2 files changed, 290 insertions(+), 77 deletions(-) diff --git a/AVR Working w-o Decoder/AVR.cpp b/AVR Working w-o Decoder/AVR.cpp index 8c0f487..f34be04 100644 --- a/AVR Working w-o Decoder/AVR.cpp +++ b/AVR Working w-o Decoder/AVR.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "SerialPort\SerialPort.h" enum @@ -21,6 +22,8 @@ CSerialPort avr; int avrOnPort = COM_NO_PORT; // Serial Port 1, 2, ... taking note that some USB adapters can be up toward channel 11, 12, ... unsigned avrBaud = 9600; +DWORD const retryInterval = 1000; // ms + // Each DT is the hex-character from the stream // // @@ -234,36 +237,92 @@ char progname[MAXTEXTLEN]; int AttachToSerialPort(); int DetachSerialPort(); -void ProcessSerialReceive(void); + +// SerialSend +// +// Try to send the message. +// +// @param[in] p is a pointer to the message to send +// @param[in] len is the count of bytes in the message +// @returns true if the serial interface accepted it. +// +bool SerialSend(const uint8_t *p, DWORD len); + +#define SERIALQUEUESIZE 3 +typedef struct { + uint8_t *messageToSend; + DWORD len; +} SerialQueue_T; + +static SerialQueue_T serialQueue[SERIALQUEUESIZE]; +static int serialQueueCount = 0; + + +// ProcessSerialQueue +// +// If there are parameters passed, insert a message into the queue. +// Process the queue (with zero or more messages) to send +// +// @param[in] p is a pointer to the message to send +// @param[in] len is the count of bytes in the message +// @returns false if the queue (which is a fixed size) is full. +// +bool ProcessSerialQueue(const uint8_t *p = NULL, DWORD len = 0); + + +// ProcessSerialReceive +// +// See if anything came in, and if so, process it. +// +// @returns true if a message was processed. +// +bool ProcessSerialReceive(void); void EnumerateComPorts(); unsigned long Hex2Dec(uint8_t *p, int dig); bool UserWantsToExitCanSniff = false; +DWORD progStartTime; // For special cursor positioning bool consoleInit = false; HANDLE hStdout, hStdin; -CONSOLE_SCREEN_BUFFER_INFO csbiInfo; +CONSOLE_SCREEN_BUFFER_INFO csbi; WORD wOldColorAttrs; // Save the current console colors +short consoleWidth = 105; +short consoleHeight = 70; +short consoleScrollHeight = 14; +// 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 + 69 +// | | +// | | 79 +// +---------------------------------------------------------------+ +const int scrollTop = 59; +const int scrollBot = 69; + + void Console_Init(); void Console_Cls(); void Console_SetCursor(short x, short y); -void Console_Write(char *text); -void Console_WriteAt(short x, short y, char *text); +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); -uint8_t LastSentMessage[MAXTEXTLEN]; -uint16_t LastSentMessageLen; -uint64_t LastSentMessageTime; // when the last message was sent - typedef struct { const char Char; const char *pDescription; const char *pCommand; - int cmdLen; + DWORD cmdLen; } UserCmd_T; const UserCmd_T UserCommands[] = { @@ -324,21 +383,26 @@ void ProcessWindowsMessage(void) { // EmitBuffer // // Emits the provided buffer to the console, translating non-printable -// characters into hex codes enclosed in angle brackets. +// characters into hex codes enclosed in square brackets. // // Consider line-wrapping to align the next line // -void EmitBuffer(const char *prefix, const uint8_t *buf, bool appendReturn = false) { +void EmitBuffer(const char *prefix, const uint8_t *buf, size_t len = 0, bool appendReturn = false) { int i = 0; const char *p = (const char *)buf; - printf("[%3d]%s", (int)strlen(p), prefix); - while (*p) { + DWORD now = timeGetTime(); + char txtBuf[MAXTEXTLEN] = ""; + + if (len == 0) len = strlen((const char *)buf); + sprintf_s(txtBuf, MAXTEXTLEN, "%7.3f: [%3d]%s", (float)(now - progStartTime)/1000.0f, (int)strlen(p), prefix); + Console_Write(txtBuf); + while (*p && ((unsigned)(p - (const char *)buf) < len)) { if (isprint(*p)) { putchar(*p); i++; } else if (*p == '\r') { putchar('\n'); - Console_ScrollBottomRegion(-14, -1); + Console_ScrollBottomRegion(scrollTop, scrollBot); } else if (*p == '\n') { // skip it } else { @@ -346,7 +410,8 @@ void EmitBuffer(const char *prefix, const uint8_t *buf, bool appendReturn = fals } if ((i & 3) == 0) { if (Console_AdvanceToNextLineIfNotRoomFor(12, 1)) { - printf(" "); + //Console_ScrollBottomRegion(scrollTop, scrollBot); + printf(" "); // sized to get past the timestamp, length, and prefix i = 0; } else { printf(" "); @@ -355,34 +420,64 @@ void EmitBuffer(const char *prefix, const uint8_t *buf, bool appendReturn = fals p++; } if (appendReturn) { - putch('\r'); + Console_ScrollBottomRegion(scrollTop, scrollBot); // putch('\r'); } else { - putch('\n'); - Console_ScrollBottomRegion(-14, -1); + //putch('\n'); + //Console_ScrollBottomRegion(scrollTop, scrollBot); } } void EchoSerialRecv(const uint8_t *pMsg) { - Console_SetCursor(0, -3); + Console_SetCursor(0, -1); EmitBuffer("< ", pMsg); - Console_ScrollBottomRegion(-14, -1); + Console_ScrollBottomRegion(scrollTop, scrollBot); } -void SerialSend(const uint8_t *p, int len) { - Console_SetCursor(0, -3); - EmitBuffer("> ", p); - Console_ScrollBottomRegion(-14, -1); - if (avr.Write((const LPVOID)p, len) != len) { - Console_SetCursor(0, -3); - Console_Write("***** Failed to send. Port not open?"); - Console_ScrollBottomRegion(-14, -1); +bool SerialSend(const uint8_t *p, DWORD len) { + bool retVal = false; + Console_SetCursor(0, -1); + EmitBuffer("> ", p, len); + Console_ScrollBottomRegion(scrollTop, scrollBot); + if (avr.Write((const LPVOID)p, len) == len) { + retVal = true; } else { - // If we send something, we expect a response within ?200ms? and if not we should try again, up to 5 times. - memcpy(LastSentMessage, p, len); - LastSentMessageTime = GetTickCount64(); - LastSentMessageLen = len; + Console_SetCursor(0, -1); + Console_Write("***** Failed to send. Port not open?"); + Console_ScrollBottomRegion(scrollTop, scrollBot); } + return retVal; +} + +bool ProcessSerialQueue(const uint8_t *p, DWORD len) { + bool retVal = false; // assume fail + static bool freshData = false; + //DWORD now = timeGetTime(); + //static DWORD lastSendTime = timeGetTime(); + + if (p && len) { + if (serialQueueCount < SERIALQUEUESIZE) { + serialQueue[serialQueueCount].messageToSend = (uint8_t *)malloc(len); + if (serialQueue[serialQueueCount].messageToSend) { + memcpy(serialQueue[serialQueueCount].messageToSend, p, len); + serialQueue[serialQueueCount].len = len; + serialQueueCount++; + retVal = true; + freshData = true; + } + } + } + if (serialQueueCount) { + if (SerialSend((const uint8_t *)serialQueue[0].messageToSend, serialQueue[0].len)) { + --serialQueueCount; + free(serialQueue[0].messageToSend); + for (int i = 0; i < serialQueueCount; i++) { + serialQueue[i] = serialQueue[i + 1]; + } + retVal = true; + } + } + return retVal; } @@ -412,13 +507,13 @@ void EmitRuntimeHelp() { Console_Write(buf); } if (avr.IsOpen()) { - Console_SetCursor(0, -3); + 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\n", avr.Get_RI_State() ? "ON" : "OFF"); - Console_ScrollBottomRegion(-14, -1); + Console_ScrollBottomRegion(scrollTop, scrollBot); } } @@ -450,8 +545,8 @@ static void PCMessage(const char *msg, int len, uint8_t **src, const char * (fnc msg, p ); + Console_AdvanceToNextLineIfNotRoomFor(26); Console_Write(outBuf); - Console_AdvanceToNextLineIfNotRoomFor(28); } @@ -491,6 +586,75 @@ const char * InputText(uint32_t val) { } } +const char *ProgramName(uint8_t val) { + val &= 0x7F; // Not accommodating the other variants yet + const char *nameList[] = { + "Hall A(HALL1)", + "Hall B", + "Hall C", + "unk", + "Hall C", + "Hall E", + "Live Concert", + "unk", + "Tokyo", + "Freiburg", + "Royaumont", + "unk", + "Village Gate", + "Village Vanguard", + "The Bottom Line", + "unk", + "The Roxy Theater", + "Warehouse Loft", + "Arena", + "unk", + "Disco", + "Party", + "Game", + "6 / 8CH Stereo", + "Pop / Rock", + "DJ", + "unk", + "unk", + "Opera", + "Pavillion", + "unk", + "unk", + "Mono Movie", + "Variety Sports", + "unk", + "unk", + "Spectacre", + "Sci - Fi", + "unk", + "unk", + "Adventure", + "General", + "unk", + "unk", + "Normal", + "Enhanced", + "unk", + "unk", + "PLII Movie", + "PLII Music", + "Neo: 6 Movie", + "Neo: 6 Music", + "STEREO A 2CH Stereo", + "STEREO B 2CH Direct Stereo" + "THX A Cinema", + "THX B Music", + }; + if (val < sizeof(nameList)) { + return nameList[val]; + } else { + return "huh?"; + } +} + + + // VolumeDB // // Convert the communication units of volume into db @@ -521,7 +685,7 @@ const char *VolumeDB(uint32_t val) { void ShowAll(void) { if (avrStatus.headerValid) { - Console_SetCursor(0, 3); + Console_SetCursor(0, 2); char buf[MAXTEXTLEN]; sprintf_s(buf, MAXTEXTLEN, "Model ID: %c%c%c%c%c, ver: %c\n", avrStatus.header.type[0], avrStatus.header.type[1], avrStatus.header.type[2], avrStatus.header.type[3], avrStatus.header.type[4], @@ -637,7 +801,7 @@ void ProcessKeyboard(void) { static uint32_t spin = 0; bool cmdFound = false; - Console_SetCursor(0, -3); + Console_SetCursor(0, -1); if (spin++ % 16 == 0) EmitSpinner(); if (CS_KeyHit()) { @@ -654,28 +818,28 @@ void ProcessKeyboard(void) { break; case 'S': avr.Set_RTS_State(TRUE); - Console_SetCursor(0, -3); + Console_SetCursor(0, -1); printf("RTS set ON\n"); - Console_ScrollBottomRegion(-14, -1); + Console_ScrollBottomRegion(scrollTop, scrollBot); break; case 's': avr.Set_RTS_State(FALSE); - Console_SetCursor(0, -3); + Console_SetCursor(0, -1); printf("RTS set OFF\n"); - Console_ScrollBottomRegion(-14, -1); + Console_ScrollBottomRegion(scrollTop, scrollBot); break; default: for (int i = 0; i < sizeof(UserCommands) / sizeof(UserCmd_T); i++) { if (UserCommands[i].Char == c) { - SerialSend((const uint8_t *)UserCommands[i].pCommand, UserCommands[i].cmdLen); + ProcessSerialQueue((const uint8_t *)UserCommands[i].pCommand, UserCommands[i].cmdLen); cmdFound = true; break; } } if (!cmdFound) { - Console_SetCursor(0, -3); + Console_SetCursor(0, -1); printf("Unrecognized command '%c' (0x%02X)\n", isprint(c) ? c : '.', (unsigned char)c); - Console_ScrollBottomRegion(-14, -1); + Console_ScrollBottomRegion(scrollTop, scrollBot); } break; } @@ -699,7 +863,7 @@ void GetProgName(char *name) { } -void EmitHelp() { +void EmitCommandLineHelp() { printf("%s [options] by Smartware Computing\n", progname); printf(" options:\n"); printf(" -C=X[,yyyy] Set to Com port X to baud rate yyyy\n"); @@ -718,6 +882,7 @@ void EmitHelp() { /******************************************************/ int __cdecl main(int argc, char *argv[]) { + progStartTime = timeGetTime(); Console_Init(); GetProgName(argv[0]); @@ -732,12 +897,12 @@ int __cdecl main(int argc, char *argv[]) { avrBaud = param2; } else { printf("***** Unrecognized command '%s' *****\n", argv[i]); - EmitHelp(); + EmitCommandLineHelp(); exit(EXIT_IllegalOption); } } if (argc == 0 || avrOnPort == COM_NO_PORT) { - EmitHelp(); + EmitCommandLineHelp(); } Console_Cls(); @@ -750,7 +915,8 @@ int __cdecl main(int argc, char *argv[]) { printf("Attached to Serial Port on COM%i at %i baud\n", avrOnPort, avrBaud); do { ProcessKeyboard(); - ProcessSerialReceive(); + /* bool anyRcvdMsg = */ ProcessSerialReceive(); + ProcessSerialQueue(); ProcessWindowsMessage(); } while (!UserWantsToExitCanSniff); DetachSerialPort(); @@ -815,14 +981,23 @@ void ProcessResponse(uint8_t type, uint8_t guard, uint16_t cmd, uint16_t data) { char buf[MAXTEXTLEN]; switch (cmd) { case 0x26: - sprintf_s(buf, MAXTEXTLEN, "Vol: %s", VolumeDB(data)); + sprintf_s(buf, MAXTEXTLEN, "Vol: %s\n", VolumeDB(data)); SetData(&avrStatus.config.DT15, Dec2Hex(data, 2)); Console_Write(buf); + Console_ScrollBottomRegion(scrollTop, scrollBot); + ShowAll(); + break; + case 0x28: + sprintf_s(buf, MAXTEXTLEN, "Prog: %s\n", ProgramName(data)); + SetData(&avrStatus.config.DT19, Dec2Hex(data, 2)); + Console_Write(buf); + Console_ScrollBottomRegion(scrollTop, scrollBot); ShowAll(); break; default: sprintf_s(buf, MAXTEXTLEN, "type: %X, guard: %X, cmd: %02X, data: %02X", type, guard, cmd, data); Console_Write(buf); + Console_ScrollBottomRegion(scrollTop, scrollBot); break; } } @@ -902,7 +1077,8 @@ void AnalyzeResponse(uint8_t *szBuffer, uint32_t num) { // All character sequences end with \x03 (this is the equiv of a ) // // -void ProcessSerialReceive() { +bool ProcessSerialReceive() { + bool anythingReceived = false; uint8_t rcv_buff[MAXTEXTLEN] = { 0 }; static uint8_t messageBuf[MAXTEXTLEN] = { 0 }; static uint8_t *p = messageBuf; // used to fill the rcv_buff as data comes in @@ -921,20 +1097,14 @@ void ProcessSerialReceive() { p = messageBuf; // Reset the buffer for the next message, which might be in rcv_buff *p = '\0'; + anythingReceived = true; } } if (messageBuf[0]) { - //EmitBuffer("~", messageBuf, true); // Show them the partial receipt if anything is there - } - } else { - // If we're waiting for a response to something we sent, and it's been more than 200ms, resend it - if (LastSentMessageTries > 0) { - if ((GetTickCount64() - LastSentMessageTime) > 200) { - LastSentMessageLen && (GetTickCount64() - LastSentMessageTime) > 200); - SerialSend(LastSentMessage, LastSentMessageLen); - } + //EmitBuffer("~", messageBuf, 0, true); // Show them the partial receipt if anything is there } } + return anythingReceived; } @@ -997,8 +1167,47 @@ int AttachToSerialPort() { void Console_Init() { hStdin = GetStdHandle(STD_INPUT_HANDLE); hStdout = GetStdHandle(STD_OUTPUT_HANDLE); - GetConsoleScreenBufferInfo(hStdout, &csbiInfo); - wOldColorAttrs = csbiInfo.wAttributes; + if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) { + fprintf(stderr, "Error: Unable to get console buffer info. Code: %lu\n", GetLastError()); + exit(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); } @@ -1009,7 +1218,6 @@ void Console_Close() { void Console_Cls() { COORD coordScreen = { 0, 0 }; // home for the cursor DWORD cCharsWritten; - CONSOLE_SCREEN_BUFFER_INFO csbi; DWORD dwConSize; // Get the number of character cells in the current buffer. @@ -1041,8 +1249,12 @@ void Console_Cls() { SetConsoleCursorPosition(hStdout, coordScreen); } -void Console_Write(char *text) { +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); } @@ -1053,33 +1265,34 @@ void Console_WriteAt(short x, short y, char *text) { } void Console_SetCursor(short x, short y) { - GetConsoleScreenBufferInfo(hStdout, &csbiInfo); - csbiInfo.dwCursorPosition.X = (short)((x < 0) ? csbiInfo.srWindow.Right + x : x); - csbiInfo.dwCursorPosition.Y = (short)((y < 0) ? csbiInfo.srWindow.Bottom + y : y); - SetConsoleCursorPosition(hStdout, csbiInfo.dwCursorPosition); + GetConsoleScreenBufferInfo(hStdout, &csbi); + csbi.dwCursorPosition.X = (short)((x < 0) ? csbi.srWindow.Right + x : x); + csbi.dwCursorPosition.Y = (short)((y < 0) ? csbi.srWindow.Bottom + y : y); + SetConsoleCursorPosition(hStdout, csbi.dwCursorPosition); } void Console_ScrollBottomRegion(short topLine, short bottomLine) { - GetConsoleScreenBufferInfo(hStdout, &csbiInfo); - if (topLine < 0) topLine = csbiInfo.srWindow.Bottom + topLine; - if (bottomLine < 0) bottomLine = csbiInfo.srWindow.Bottom + bottomLine; - SMALL_RECT scrollRect = { 0, topLine, csbiInfo.dwMaximumWindowSize.X, 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, nullptr, dest, &fill); + ScrollConsoleScreenBuffer(hStdout, &scrollRect, &scrollRect, dest, &fill); + putch('\r'); // Cursor to left margin } bool Console_AdvanceToNextLineIfNotRoomFor(short x, int scroll) { bool advanced = false; - GetConsoleScreenBufferInfo(hStdout, &csbiInfo); - if (csbiInfo.dwCursorPosition.X + x > csbiInfo.dwMaximumWindowSize.X) { + GetConsoleScreenBufferInfo(hStdout, &csbi); + if (csbi.dwCursorPosition.X + x > csbi.dwMaximumWindowSize.X) { advanced = true; if (scroll == 1) { - Console_ScrollBottomRegion(-14, -1); + Console_ScrollBottomRegion(scrollTop, scrollBot); } else { - csbiInfo.dwCursorPosition.Y++; + csbi.dwCursorPosition.Y++; } - Console_SetCursor(0, csbiInfo.dwCursorPosition.Y); + Console_SetCursor(0, csbi.dwCursorPosition.Y); } return advanced; } \ No newline at end of file diff --git a/DataSheets/Yamaha RX-V2400_RS232C_CommandsForSW.pdf.xlsx b/DataSheets/Yamaha RX-V2400_RS232C_CommandsForSW.pdf.xlsx index adc66ec5f5254cbea4cf59e982d79e184e52d5e0..18a7e2908cff37e1d4dc268b1ab8daeddcb3b4cc 100644 GIT binary patch delta 13172 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

La==F8cy`3guz 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