#pragma warning(disable : 4706) // assignment within conditional expression #pragma warning(disable : 4996) // _CRT_SECURE_NO_DEPRECATE #include "stdafx.h" #include #include #include #include #include #include #include #include "SerialPort\SerialPort.h" enum { COM_NO_PORT = -1, COM_MIN_PORT = 1, COM_MAX_PORT = 99 }; 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; // Each DT is the hex-character from the stream // // typedef struct { uint8_t DT0; // * Baud Rate uint8_t DT1; // * Receive Buffer 'E' uint8_t DT2; // * Receive Buffer '0' uint8_t DT3; // * '1' uint8_t DT4; // * Command Timeout '9' uint8_t DT5; // * '0' uint8_t DT6; // * '0' uint8_t DT7; // * System '0':Ok, '1':Busy uint8_t DT8; // * Power 0:Off, 1:On uint8_t DT9; // Input 0: Phono, 1:CD, 2:Tuner, 3:CD-R, 4:MD-Tape, 5:DVD, 6:D-TV, 7:Cbl, 9:VCR1, A:VCR2 uint8_t DT10; // 6ch input 0:Off, 1:On uint8_t DT11; // Input Mode 0:AUTO, 2:DTS, 4:Analog, 5:Analog Only uint8_t DT12; // Audio Mute 0:Off, 1:On uint8_t DT13; uint8_t DT14; uint8_t DT15; uint8_t DT16; uint8_t DT17; uint8_t DT18; uint8_t DT19; uint8_t DT20; uint8_t DT21; uint8_t DT22; uint8_t DT23; uint8_t DT24; uint8_t DT25; uint8_t DT26; uint8_t DT27; uint8_t DT28; uint8_t DT29; uint8_t DT30; uint8_t DT31; uint8_t DT32; uint8_t DT33; uint8_t DT34; uint8_t DT35; uint8_t DT36; uint8_t DT37; uint8_t DT38; uint8_t DT39; uint8_t DT40; uint8_t DT41; uint8_t DT42; uint8_t DT43; uint8_t DT44; uint8_t DT45; uint8_t DT46; uint8_t DT47; uint8_t DT48; uint8_t DT49; uint8_t DT50; uint8_t DT51; uint8_t DT52; uint8_t DT53; uint8_t DT54; uint8_t DT55; uint8_t DT56; uint8_t DT57; uint8_t DT58; uint8_t DT59; uint8_t DT60; uint8_t DT61; uint8_t DT62; uint8_t DT63; uint8_t DT64; uint8_t DT65; uint8_t DT66; uint8_t DT67; uint8_t DT68; uint8_t DT69; uint8_t DT70; uint8_t DT71; uint8_t DT72; uint8_t DT73; uint8_t DT74; uint8_t DT75; uint8_t DT76; uint8_t DT77; uint8_t DT78; uint8_t DT79; uint8_t DT80; uint8_t DT81; uint8_t DT82; uint8_t DT83; uint8_t DT84; uint8_t DT85; uint8_t DT86; uint8_t DT87; uint8_t DT88; uint8_t DT89; uint8_t DT90; uint8_t DT91; uint8_t DT92; uint8_t DT93; uint8_t DT94; uint8_t DT95; uint8_t DT96; uint8_t DT97; uint8_t DT98; uint8_t DT99; uint8_t DT100; uint8_t DT101; uint8_t DT102; uint8_t DT103; uint8_t DT104; uint8_t DT105; uint8_t DT106; uint8_t DT107; uint8_t DT108; uint8_t DT109; uint8_t DT110; uint8_t DT111; uint8_t DT112; uint8_t DT113; uint8_t DT114; uint8_t DT115; uint8_t DT116; uint8_t DT117; uint8_t DT118; uint8_t DT119; uint8_t DT120; uint8_t DT121; uint8_t DT122; uint8_t DT123; uint8_t DT124; uint8_t DT125; uint8_t DT126; uint8_t DT127; uint8_t DT128; uint8_t DT129; uint8_t DT130; uint8_t DT131; uint8_t DT132; uint8_t DT133; uint8_t DT134; uint8_t DT135; uint8_t DT136; uint8_t DT137; // PB/SB Select 00: PR, 01: SB // Last documented register uint8_t DT138; uint8_t DT139; uint8_t DT140; uint8_t DT141; uint8_t DT142; uint8_t DT143; uint8_t DT144; uint8_t DT145; uint8_t DT146; uint8_t DT147; uint8_t DT148; uint8_t DT149; uint8_t DT150; uint8_t DT151; uint8_t DT152; uint8_t DT153; uint8_t DT154; uint8_t DT155; uint8_t DT156_255[100]; } AVR_Configuration_T; // 264 total typedef struct { uint8_t type[5]; // Model ID uint8_t version; // A-Z uint8_t length[2]; // 1 - 255 } AVR_StatusHeader_T; typedef struct { bool headerValid; bool configValid; AVR_StatusHeader_T header; AVR_Configuration_T config; } AVR_Status_T; //AVR_StatusHeader_T avrStatusHeader; //AVR_Configuration_T avrConfigData; AVR_Status_T avrStatus; typedef enum { EXIT_OK = 0, EXIT_IllegalOption = 1, EXIT_ConfigError = 2, EXIT_UserESC = 3, EXIT_UserQ = 4, EXIT_ExternalQ = 5 } ExitCode; constexpr auto MAXTEXTLEN = 512; char progname[MAXTEXTLEN]; int AttachToSerialPort(); int DetachSerialPort(); void ProcessSerialReceive(void); void EnumerateComPorts(); unsigned long Hex2Dec(uint8_t *p, int dig); bool UserWantsToExitCanSniff = false; // For special cursor positioning bool consoleInit = false; HANDLE hStdout, hStdin; CONSOLE_SCREEN_BUFFER_INFO csbiInfo; WORD wOldColorAttrs; // Save the current console colors 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_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; } UserCmd_T; const UserCmd_T UserCommands[] = { { 'R', "Ready", "\x11" "000" "\x03", 5 }, { 'P', "Power On", "\x02" "07A1D" "\x03", 7 }, { 'p', "Power Off", "\x02" "07A1E" "\x03", 7 }, { '1', "Zone 1 On", "\x02" "07E7E" "\x03", 7 }, { '!', "Zone 1 Off", "\x02" "07E7F" "\x03", 7 }, { '2', "Zone 2 On", "\x02" "07EBA" "\x03", 7 }, { '@', "Zone 2 Off", "\x02" "07EBB" "\x03", 7 }, { 'V', "Vol 1 Up", "\x02" "07A1A" "\x03", 7 }, { 'v', "Vol 1 Down", "\x02" "07A1B" "\x03", 7 }, { 'M', "Vol 1 Mute", "\x02" "07EA2" "\x03", 7 }, { 'm', "Vol 1 UnMute", "\x02" "07EA3" "\x03", 7 }, { '/', "Show All", "", 0 }, { '?', "Help on runtime commands", "", 0 }, { 'S', "Set RTS", "", 0 }, { 's', "Clear RTS", "", 0 }, { '\x1B', "quit the program", "", 0 }, }; int CS_KeyHit() { int h = _kbhit(); return h; } int CS_GetChar() { int k = _getch(); // More leadin chars return k; } BOOL WINAPI ControlIntercept(DWORD CtrlType) { switch (CtrlType) { case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: UserWantsToExitCanSniff = true; return FALSE; default: return FALSE; } } void ProcessWindowsMessage(void) { MSG msgx; bool msgReturn; msgReturn = PeekMessage(&msgx, NULL, WM_QUIT, WM_QUIT, PM_NOREMOVE); if (msgReturn == true && msgx.message == WM_QUIT) { UserWantsToExitCanSniff = true; } } // EmitBuffer // // Emits the provided buffer to the console, translating non-printable // characters into hex codes enclosed in angle brackets. // // Consider line-wrapping to align the next line // void EmitBuffer(const char *prefix, const uint8_t *buf, bool appendReturn = false) { int i = 0; const char *p = (const char *)buf; printf("[%3d]%s", (int)strlen(p), prefix); while (*p) { if (isprint(*p)) { putchar(*p); i++; } else if (*p == '\r') { putchar('\n'); Console_ScrollBottomRegion(-14, -1); } else if (*p == '\n') { // skip it } else { printf("[%02X]", (unsigned char)*p); } if ((i & 3) == 0) { if (Console_AdvanceToNextLineIfNotRoomFor(12, 1)) { printf(" "); i = 0; } else { printf(" "); } } p++; } if (appendReturn) { putch('\r'); } else { putch('\n'); Console_ScrollBottomRegion(-14, -1); } } void EchoSerialRecv(const uint8_t *pMsg) { Console_SetCursor(0, -3); EmitBuffer("< ", pMsg); Console_ScrollBottomRegion(-14, -1); } 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); } 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; } } void EmitSpinner() { static int x = 0; const char arrow[] = "|/-\\|/-\\"; printf("%c\b", arrow[x++]); if (x == 8) x = 0; } void EmitRuntimeHelp() { for (int i = 0; i < sizeof(UserCommands) / sizeof(UserCmd_T); i++) { char tinyBuf[6]; if (isprint(UserCommands[i].Char)) { sprintf_s(tinyBuf, sizeof(tinyBuf), "%c", UserCommands[i].Char); } else if (UserCommands[i].Char == '\x1B') { sprintf_s(tinyBuf, sizeof(tinyBuf), "%s", ""); } else if (UserCommands[i].Char < ' ') { sprintf_s(tinyBuf, sizeof(tinyBuf), "^%c", UserCommands[i].Char + 64); } else { sprintf_s(tinyBuf, sizeof(tinyBuf), "0x%02X", (unsigned char)UserCommands[i].Char); } char buf[MAXTEXTLEN]; sprintf_s(buf, MAXTEXTLEN, " %5s %-25s", tinyBuf, UserCommands[i].pDescription); Console_AdvanceToNextLineIfNotRoomFor((short)strlen(buf), 1); Console_Write(buf); } if (avr.IsOpen()) { Console_SetCursor(0, -3); 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); } } // PCMessage // // Various responses need to be formatted and shown on screen // The last param will allow resetting the column counter // and pre and post-pending \n // static void PCMessage(const char *msg, int len, uint8_t **src, const char * (fncHelper)(uint32_t val) = NULL) { char buf[MAXTEXTLEN]; const char *p = buf; if (fncHelper) { // Get the binary value if we need it uint32_t val = Hex2Dec(*src, len); p = (*fncHelper)(val); *src += len; } else { // Create a string value when we need that strncpy(buf, (char *)*src, len); // s/w *src += len; buf[len] = '\0'; } char outBuf[MAXTEXTLEN]; sprintf_s(outBuf, MAXTEXTLEN, "%17s %-8s", msg, p ); Console_Write(outBuf); Console_AdvanceToNextLineIfNotRoomFor(28); } const char * BusyToText(uint32_t val) { static char buf[16]; if (val == 0) { strcpy_s(buf, sizeof(buf), "OK"); } else if (val == 1) { strcpy_s(buf, sizeof(buf), "BUSY"); } else { sprintf_s(buf, sizeof(buf), "0x%02X ?", (unsigned char)val); } return buf; } const char * OnOffText(uint32_t val) { static char buf[16]; if (val == 0) { strcpy_s(buf, sizeof(buf), "OFF"); } else if (val == 1) { strcpy_s(buf, sizeof(buf), "ON"); } else { sprintf_s(buf, sizeof(buf), "0x%02X ?", (unsigned char)val); } return buf; } const char * InputText(uint32_t val) { const char *inputList[13] = { "0:Phono", "1:CD", "2:Tuner", "3:CD-R", "4:MD-Tape", "5:DVD", "6:D-TV", "7:Cable", "8:unk", "9:VCR1", "A:VCR2", "B:unk", "C:V-Aux" }; if (val <= 12) { return inputList[val]; } else { return "huh?"; } } // VolumeDB // // Convert the communication units of volume into db // // Piecewise // for values 0 to 199 // db = 0.5634 x - 112.11 // for values 200 to 255 // db = 0.5 x - 99.5 // Single Linear // db = 0.5574 x - 111.45 // const char *VolumeDB(uint32_t val) { static char buf[16]; float m, b; if (val < 200) { m = 0.5634f; b = -112.11f; } else { m = 0.5f; b = -99.5f; } float db = m * val + b; sprintf_s(buf, sizeof(buf), "%+5.1f db", db); return buf; } void ShowAll(void) { if (avrStatus.headerValid) { Console_SetCursor(0, 3); 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], avrStatus.header.version); Console_Write(buf); uint8_t *p = (uint8_t *)&avrStatus.config; PCMessage("Baud Rate", 1, &p); PCMessage("Rx Buffer", 2, &p); PCMessage("Cmd Timeout", 3, &p); PCMessage("Handshake", 1, &p); PCMessage("Busy", 1, &p, BusyToText); PCMessage("Power", 1, &p, OnOffText); if (avrStatus.configValid) { PCMessage("Input", 1, &p, InputText); PCMessage("6 ch", 1, &p); PCMessage("Inp mode", 1, &p); PCMessage("Mute", 1, &p, OnOffText); PCMessage("Zone 2", 1, &p, InputText); PCMessage("Mute 2", 1, &p, OnOffText); PCMessage("Volume", 2, &p, VolumeDB); PCMessage("Volume 2", 2, &p, VolumeDB); PCMessage("pgm", 2, &p); PCMessage("effect", 1, &p, OnOffText); PCMessage("6.1/es status", 1, &p); PCMessage("OSD", 1, &p); PCMessage("sleep", 1, &p); PCMessage("Tuner Pg", 1, &p); PCMessage("Tuner #", 1, &p); PCMessage("Night", 1, &p, OnOffText); PCMessage("?????", 1, &p); PCMessage("Spkr A", 1, &p, OnOffText); PCMessage("Spkr B", 1, &p, OnOffText); PCMessage("Playback", 1, &p); PCMessage("Fs", 1, &p); PCMessage("Ex/Es", 1, &p); PCMessage("Thr Bypass", 1, &p); PCMessage("Red DTS", 1, &p); PCMessage("Headph", 1, &p, OnOffText); PCMessage("Tuner Band", 1, &p); PCMessage("Tuner Tuned", 1, &p); PCMessage("DC1 Control Out", 1, &p); PCMessage("?????", 2, &p); PCMessage("DC1 Trig Ctrl", 1, &p); PCMessage("DTS 96/24", 1, &p, OnOffText); PCMessage("DC2 Trig Ctrl", 1, &p); PCMessage("DC2 Trig", 1, &p); PCMessage("Spkr B Set", 1, &p); PCMessage("Zone 2 SP out", 1, &p, OnOffText); PCMessage("Main R", 2, &p); PCMessage("Main L", 2, &p); PCMessage("Center", 2, &p); PCMessage("Rear R", 2, &p); PCMessage("Rear L", 2, &p); PCMessage("Sur Bk R", 2, &p); PCMessage("Sur Bk L", 2, &p); PCMessage("Front R", 2, &p); PCMessage("Front L", 2, &p); PCMessage("Sub", 2, &p); PCMessage("?????", 6, &p); PCMessage("LFE SP", 2, &p); PCMessage("LFE HP", 2, &p); PCMessage("Audio Delay", 2, &p); PCMessage("?????", 4, &p); PCMessage("Inp Mode Set", 1, &p); PCMessage("Dimmer", 1, &p); PCMessage("OSD Msg", 1, &p); PCMessage("OSD Shift", 2, &p); PCMessage("Gray Back", 1, &p); PCMessage("Video Conv", 1, &p, OnOffText); PCMessage("D Range SP", 1, &p); PCMessage("D Range HP", 1, &p); PCMessage("Zone 2 Vol out", 1, &p); PCMessage("?????", 1, &p); PCMessage("Memory Guard", 1, &p, OnOffText); PCMessage("SP set center", 1, &p); PCMessage("SP set main", 1, &p); PCMessage("SP set rear L/R", 1, &p); PCMessage("SP set rear ct", 1, &p); PCMessage("SP set front", 1, &p); PCMessage("SP set LFE/Bass", 1, &p); PCMessage("6 ch center", 1, &p); PCMessage("6 ch sub", 1, &p); PCMessage("Main level", 1, &p); PCMessage("Test Mode", 1, &p); PCMessage("?????", 1, &p); PCMessage("Lvl 6 ch main L", 2, &p); PCMessage("Lvl 6 ch main R", 2, &p); PCMessage("Lvl 6 ch center", 2, &p); PCMessage("Lvl 6 ch sl", 2, &p); PCMessage("Lvl 6 ch sr", 2, &p); PCMessage("Lvl 6 ch sbl", 2, &p); PCMessage("Lvl 6 ch sbr", 2, &p); PCMessage("Lvl 6 ch front l", 2, &p); PCMessage("Lvl 6 ch front r", 2, &p); PCMessage("Lvl 6 ch swfr", 2, &p); PCMessage("Zone 3 Inp", 1, &p); PCMessage("Zone 3 Mute", 1, &p); PCMessage("Zone 3 Vol", 2, &p); PCMessage("?????", 1, &p); PCMessage("MultiCh Select", 1, &p); PCMessage("MultiCh Surround", 1, &p); PCMessage("SP Set SW1", 1, &p); PCMessage("SP Set Crossover", 1, &p); PCMessage("Component OSD", 1, &p, OnOffText); PCMessage("PB/SB Select", 1, &p); } printf("\n"); } } void ProcessKeyboard(void) { static uint32_t spin = 0; bool cmdFound = false; Console_SetCursor(0, -3); if (spin++ % 16 == 0) EmitSpinner(); if (CS_KeyHit()) { int c = CS_GetChar(); switch (c) { case '?': EmitRuntimeHelp(); break; case '/': ShowAll(); break; case '\x1B': UserWantsToExitCanSniff = true; break; case 'S': avr.Set_RTS_State(TRUE); Console_SetCursor(0, -3); printf("RTS set ON\n"); Console_ScrollBottomRegion(-14, -1); break; case 's': avr.Set_RTS_State(FALSE); Console_SetCursor(0, -3); printf("RTS set OFF\n"); Console_ScrollBottomRegion(-14, -1); 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); cmdFound = true; break; } } if (!cmdFound) { Console_SetCursor(0, -3); printf("Unrecognized command '%c' (0x%02X)\n", isprint(c) ? c : '.', (unsigned char)c); Console_ScrollBottomRegion(-14, -1); } break; } } return; } void GetProgName(char *name) { char *p = strrchr(name, '\\'); if (p) { p++; } else { p = name; } strcpy_s(progname, MAXTEXTLEN, p); p = strrchr(progname, '.'); if (0 == stricmp(p, ".exe")) { *p = '\0'; } } void EmitHelp() { 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"); printf(" Defaults baud is %d\n", avrBaud); printf("\n"); if (avrOnPort == COM_NO_PORT) { EnumerateComPorts(); } exit(EXIT_OK); } /******************************************************/ /* m a i n ( ) */ /******************************************************/ int __cdecl main(int argc, char *argv[]) { Console_Init(); GetProgName(argv[0]); // Change the colors... // SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_INTENSITY); for (int i = 1; i < argc; i++) { int param1, param2; if (1 == sscanf_s(argv[i], "-C=%d", ¶m1)) { avrOnPort = param1; } else if (2 == sscanf_s(argv[i], "-C=%d,%d", ¶m1, ¶m2)) { avrOnPort = param1; avrBaud = param2; } else { printf("***** Unrecognized command '%s' *****\n", argv[i]); EmitHelp(); exit(EXIT_IllegalOption); } } if (argc == 0 || avrOnPort == COM_NO_PORT) { EmitHelp(); } Console_Cls(); if (!SetConsoleCtrlHandler(ControlIntercept, TRUE)) { printf("WARN: Cannot install Console Control Handler\n"); } if (AttachToSerialPort()) { printf("AVR - a command shell utility for a Yamaha RX-2400 AVR by D.Smart\n"); printf("Attached to Serial Port on COM%i at %i baud\n", avrOnPort, avrBaud); do { ProcessKeyboard(); ProcessSerialReceive(); ProcessWindowsMessage(); } while (!UserWantsToExitCanSniff); DetachSerialPort(); } else { printf("Failed to attach to Serial Port on COM%i\n", avrOnPort); } return(0); } void SetData(uint8_t *targ, const uint8_t *string) { uint8_t *p = (uint8_t *)string; while (*p) { *targ++ = *p++; } } // Dec2Hex // // Convert a number to a hex-ascii string // const uint8_t *Dec2Hex(uint32_t val, uint16_t numDigits) { static uint8_t buf[16]; sprintf_s((char *)buf, 16, "%0*X", numDigits, val); return buf; } // Hex2Dec // // All responses are pretty much Hex-ASCII, so // we sometimes want to convert it to decimal // This takes a buffer and converts the specified // number of characters. // unsigned long Hex2Dec(uint8_t *p, int dig) { unsigned long x = 0; while (dig--) { if (*p >= '0' && *p <= '9') x = x * 16 + *p - '0'; else if (*p >= 'a' && *p <= 'f') x = x * 16 + 0x0a + *p - 'a'; else if (*p >= 'A' && *p <= 'F') x = x * 16 + 0x0a + *p - 'A'; p++; } return x; } bool CheckTheChecksum(uint8_t *szBuffer, uint32_t num) { uint8_t sum = 0; for (uint16_t i = 1; i < num - 3; i++) { sum += szBuffer[i]; } uint8_t cksum = (uint8_t)Hex2Dec(&szBuffer[num - 3], 2); //printf("CheckSum: %02X v. %c%c\n", sum, szBuffer[num - 3], szBuffer[num - 2]); return (sum == cksum); } void ProcessResponse(uint8_t type, uint8_t guard, uint16_t cmd, uint16_t data) { (void)type; (void)guard; char buf[MAXTEXTLEN]; switch (cmd) { case 0x26: sprintf_s(buf, MAXTEXTLEN, "Vol: %s", VolumeDB(data)); SetData(&avrStatus.config.DT15, Dec2Hex(data, 2)); Console_Write(buf); ShowAll(); break; default: sprintf_s(buf, MAXTEXTLEN, "type: %X, guard: %X, cmd: %02X, data: %02X", type, guard, cmd, data); Console_Write(buf); break; } } // AnalyzeResponse // // Given a response string, typically of the form: // [11] .... [03] // [12] .... [03] // ... etc // // void AnalyzeResponse(uint8_t *szBuffer, uint32_t num) { switch (szBuffer[0]) { case 0x02: // STX { // Example: [02] 4026 66[03] // 4 - controlled by encoder // 0 - guard status 0 = no guard // 26 - master vol // 66 - volume setting (-54.6db) uint8_t type, guard; uint16_t rcmd, rdat; type = (uint8_t)Hex2Dec(&szBuffer[1], 1); guard = (uint8_t)Hex2Dec(&szBuffer[2], 1); rcmd = (uint16_t)Hex2Dec(&szBuffer[3], 2); rdat = (uint16_t)Hex2Dec(&szBuffer[5], 2); ProcessResponse(type, guard, rcmd, rdat); //ShowType(typ); //ShowGuard(grd); //DecodeStatus(rcmd, rdat); } break; case 0x11: // DC1 break; case 0x12: // DC2 if (CheckTheChecksum(szBuffer, num)) { if (num == 21) { memcpy(&avrStatus.header, &szBuffer[1], sizeof(AVR_StatusHeader_T)); num = Hex2Dec(&avrStatus.header.length[0], 2); memcpy(&avrStatus.config.DT0, &szBuffer[9], num); // Copy bits of the config avrStatus.headerValid = true; } else if (num == 150) { memcpy(&avrStatus.header, &szBuffer[1], sizeof(AVR_StatusHeader_T)); num = Hex2Dec(&avrStatus.header.length[0], 2); memcpy(&avrStatus.config.DT0, &szBuffer[9], num); // Copy the config //memcpy(&avrStatus.header, &szBuffer[1], sizeof(AVR_StatusHeader_T) + sizeof(AVR_Configuration_T)); avrStatus.headerValid = true; avrStatus.configValid = true; } else { printf("***** Received message of unexpected length [%u]\n", num); } ShowAll(); } else { printf("Checksum failure on Status Header\n"); } //PrintConfiguration(szBuffer); break; case 0x14: // DC4 Extended Response //DecodeExtended(szBuffer); // Decode Extended response break; case '0': //rcmd = Hex2Dec(&szBuffer[0], 2); //DecodeString(rcmd, &szBuffer[2]); break; default: //printf("[%d] %s\n", i, szBuffer); break; } } // ProcessSerialReceive // // All character sequences end with \x03 (this is the equiv of a ) // // void ProcessSerialReceive() { 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 uint32_t num = avr.Read(rcv_buff, MAXTEXTLEN); if (num) { for (uint32_t i = 0; i < num; i++) { *p = rcv_buff[i]; if (*p++ == '\x03') { // End of message *p = '\0'; // null terminate it EchoSerialRecv(messageBuf); // // @TODO Now do something with the received message // AnalyzeResponse(messageBuf, (uint32_t)strlen((char *)messageBuf)); p = messageBuf; // Reset the buffer for the next message, which might be in rcv_buff *p = '\0'; } } 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); } } } } void EnumerateComPorts() { printf("Com Port Scan:\n"); int foundPorts = 0; for (int pNum = COM_MIN_PORT; pNum < COM_MAX_PORT; pNum++) { char cBuf[20]; // generously sized sprintf_s(cBuf, sizeof(cBuf), "\\\\.\\COM%d", pNum); bool portFound = false; HANDLE port = CreateFile(cBuf, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); if (port == INVALID_HANDLE_VALUE) { DWORD dwError = GetLastError(); if ((dwError == ERROR_ACCESS_DENIED) || (dwError == ERROR_GEN_FAILURE) || (dwError == ERROR_SHARING_VIOLATION) || (dwError == ERROR_SEM_TIMEOUT)) { foundPorts++; portFound = true; } } else { foundPorts++; portFound = true; CloseHandle(port); } if (portFound) { printf(" Com Port %d found.\n", pNum); } } if (foundPorts == 0) { printf(" No Com Ports found, perhaps you need to plug in an adapter?\n"); } } int DetachSerialPort() { if (avr.IsOpen()) { avr.Close(); } return true; } int AttachToSerialPort() { bool success = false; if (avrOnPort >= COM_MIN_PORT && avrOnPort <= COM_MAX_PORT) { char buf[20]; // generously sized. sprintf_s(buf, sizeof(buf), "\\\\.\\COM%d", avrOnPort); DWORD Access = GENERIC_WRITE | GENERIC_READ; if (avr.Open(buf, avrBaud, 8, NOPARITY, ONESTOPBIT, Access)) { success = true; avr.Set_RTS_State(false); Sleep(250); avr.Set_RTS_State(true); } } return success; } void Console_Init() { hStdin = GetStdHandle(STD_INPUT_HANDLE); hStdout = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleScreenBufferInfo(hStdout, &csbiInfo); wOldColorAttrs = csbiInfo.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; CONSOLE_SCREEN_BUFFER_INFO csbi; 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(char *text) { DWORD written; WriteConsole(hStdout, text, (DWORD)strlen(text), &written, nullptr); } void Console_WriteAt(short x, short y, 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, &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); } 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 }; COORD dest = { 0, topLine - 1 }; CHAR_INFO fill = { ' ', { FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE } }; ScrollConsoleScreenBuffer(hStdout, &scrollRect, nullptr, dest, &fill); } bool Console_AdvanceToNextLineIfNotRoomFor(short x, int scroll) { bool advanced = false; GetConsoleScreenBufferInfo(hStdout, &csbiInfo); if (csbiInfo.dwCursorPosition.X + x > csbiInfo.dwMaximumWindowSize.X) { advanced = true; if (scroll == 1) { Console_ScrollBottomRegion(-14, -1); } else { csbiInfo.dwCursorPosition.Y++; } Console_SetCursor(0, csbiInfo.dwCursorPosition.Y); } return advanced; }