diff --git a/AVR Working Controller/AVR.cpp b/AVR Working Controller/AVR.cpp index c09ec08..c52969e 100644 --- a/AVR Working Controller/AVR.cpp +++ b/AVR Working Controller/AVR.cpp @@ -11,7 +11,8 @@ #include #include #include "SerialPort\SerialPort.h" -#include "AVRCommandDecoder.h" +#include "AVRInterface.h" +//#include "AVRCommandDecoder.h" #include "ConsoleHandler.h" enum @@ -20,12 +21,14 @@ enum COM_MIN_PORT = 1, COM_MAX_PORT = 99 }; -CSerialPort avr; +CSerialPort avrPort; 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; const uint32_t retryInterval = 1000; // ms +AVRInterface *avr; + // Each DT is the hex-character from the stream // // @@ -176,7 +179,7 @@ typedef struct { } AVR_Configuration_T; -// 264 total + typedef struct { uint8_t type[5]; // Model ID uint8_t version; // A-Z @@ -224,7 +227,7 @@ bool SerialSend(const uint8_t *p, uint16_t len); // 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; + uint8_t *message; uint16_t len; } SerialQueue_T; @@ -250,11 +253,13 @@ bool ProcessSerialQueue(const uint8_t *p = NULL, uint16_t len = 0); // // @returns true if a message was processed. // -bool ProcessSerialReceive(void); +SerialQueue_T ProcessSerialReceive(void); +void HandleMessage(uint8_t *szBuffer, uint32_t num); + void EnumerateComPorts(); unsigned long Hex2Dec(uint8_t *p, int dig); -void ShowAllStatusInfo(); +//void ShowAllStatusInfo(); bool UserWantsToExitCanSniff = false; DWORD progStartTime_ms; @@ -330,6 +335,7 @@ void UserCommandsSanityCheck() { } } +#if 0 // rCmd: 2-ASCII Hex Bytes converted to uint8_t // configOffset: offset into avrStatus.config.DTxx // numToTransfer: number of bytes to transfer from message to config (0 = none) @@ -484,7 +490,7 @@ void MessageHandlerSanityCheck() { exit(EXIT_ConfigError); } } - +#endif int CS_KeyHit() { int h = _kbhit(); @@ -580,7 +586,7 @@ bool SerialSend(const uint8_t *p, uint16_t len) { Console_SetCursor(0, -1); EmitBuffer("> ", p, len); Console_ScrollBottomRegion(); - if (avr.Write((const LPVOID)p, len) == len) { + if (avrPort.Write((const LPVOID)p, len) == len) { retVal = true; } else { Console_SetCursor(0, -1); @@ -596,9 +602,9 @@ bool ProcessSerialQueue(const uint8_t *p, uint16_t len) { 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].message = (uint8_t *)malloc(len); + if (serialQueue[serialQueueCount].message) { + memcpy(serialQueue[serialQueueCount].message, p, len); serialQueue[serialQueueCount].len = len; serialQueueCount++; retVal = true; @@ -607,9 +613,9 @@ bool ProcessSerialQueue(const uint8_t *p, uint16_t len) { } } if (serialQueueCount) { - if (SerialSend((const uint8_t *)serialQueue[0].messageToSend, serialQueue[0].len)) { + if (SerialSend((const uint8_t *)serialQueue[0].message, serialQueue[0].len)) { --serialQueueCount; - free(serialQueue[0].messageToSend); + free(serialQueue[0].message); for (int i = 0; i < serialQueueCount; i++) { serialQueue[i] = serialQueue[i + 1]; } @@ -645,14 +651,14 @@ void EmitRuntimeHelp() { Console_AdvanceToNextLineIfNotRoomFor((short)strlen(buf), 1); Console_Write(buf); } - if (avr.IsOpen()) { + if (avrPort.IsOpen()) { 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"); + printf(" Com Status: RTS: %-3s ", avrPort.Get_RTS_State() ? "ON" : "OFF"); + printf("DTR: %-3s ", avrPort.Get_DTR_State() ? "ON" : "OFF"); + printf("CTS: %-3s ", avrPort.Get_CTS_State() ? "ON" : "OFF"); + printf("DSR: %-3s ", avrPort.Get_DSR_State() ? "ON" : "OFF"); + printf("RI: %-3s", avrPort.Get_RI_State() ? "ON" : "OFF"); Console_ScrollBottomRegion(); Console_SetCursor(0, -1); } @@ -692,7 +698,7 @@ static void PCMessage(const char *msg, int len, uint8_t **src, const char * (fnc - +#if 0 void ShowAllStatusInfo(void) { if (avrStatus.headerValid) { bool priorState = Console_SetCursorVisibility(false); @@ -807,7 +813,7 @@ void ShowAllStatusInfo(void) { Console_SetCursorVisibility(priorState); } } - +#endif void ProcessKeyboard(void) { static uint32_t spin = 0; @@ -819,6 +825,12 @@ void ProcessKeyboard(void) { if (CS_KeyHit()) { int c = CS_GetChar(); switch (c) { + case 'P': + avr->Power(AVRInterface::avrPowerOn); + break; + case 'p': + avr->Power(AVRInterface::avrPowerOff); + break; case 'O': ProcessSerialQueue((const uint8_t *)"\x02" "21000" "\x03", 7); ProcessSerialQueue((const uint8_t *)"\x02" "3Test" "\x03", 7); @@ -830,19 +842,20 @@ void ProcessKeyboard(void) { EmitRuntimeHelp(); break; case '/': - ShowAllStatusInfo(); + avr->ReportAllStatus(); + //ShowAllStatusInfo(); break; case '\x1B': UserWantsToExitCanSniff = true; break; case 'S': - avr.Set_RTS_State(TRUE); + avrPort.Set_RTS_State(TRUE); Console_SetCursor(0, -1); printf("RTS set ON"); Console_ScrollBottomRegion(); break; case 's': - avr.Set_RTS_State(FALSE); + avrPort.Set_RTS_State(FALSE); Console_SetCursor(0, -1); printf("RTS set OFF"); Console_ScrollBottomRegion(); @@ -894,7 +907,31 @@ void EmitCommandLineHelp() { exit(EXIT_OK); } - +void InformationUpdate(AVRInterface::AVRMessageType_T type, const char *msg) { + char buf[MAXTEXTLEN] = ""; + switch (type) { + case AVRInterface::AVRMessageType_T::mtStatus: + sprintf_s(buf, MAXTEXTLEN, "AVR Status: %-60s", msg); + Console_WriteAt(0, 1, buf); + break; + case AVRInterface::AVRMessageType_T::mtInfo: + Console_WriteAt(0, -1, msg); + Console_ScrollBottomRegion(); + break; + case AVRInterface::AVRMessageType_T::mtModelInfo: + Console_WriteAt(0, 2, msg); + break; + case AVRInterface::AVRMessageType_T::mtStreamStart: + Console_SetCursor(0, 3); + // break; // fall through + case AVRInterface::AVRMessageType_T::mtStream: + Console_AdvanceToNextLineIfNotRoomFor(26); // @TODO hard-coded - ick + Console_Write(msg); + break; + default: + break; + } +} /******************************************************/ /* m a i n ( ) */ @@ -903,9 +940,8 @@ void EmitCommandLineHelp() { // 0 99 // +---------------------------------------------------------------+ // | Program banner information | 0 -// | on two lines | -// | Current status information starts on line 3 | -// | and down a ways... | +// | State machine status information starts on line 2 | +// | Overall information is on line 3 and onward | // | | // | | // | | @@ -921,7 +957,7 @@ int __cdecl main(int argc, char *argv[]) { short consoleScrollHeight = 30; progStartTime_ms = timeGetTime(); - MessageHandlerSanityCheck(); // If the table is bad, we exit here + // MessageHandlerSanityCheck(); // If the table is bad, we exit here UserCommandsSanityCheck(); // If the table is bad, we exit here Console_Init(consoleWidth, consoleHeight, consoleScrollHeight); @@ -956,9 +992,29 @@ int __cdecl main(int argc, char *argv[]) { printf("[COM%i at %i baud]", avrOnPort, avrBaud); Console_WriteAt(0, consoleHeight - consoleScrollHeight -1, "----------------------------------------"); + avr = new AVRInterface(SerialSend); + avr->RegisterInformationCallback(InformationUpdate); + do { + avr->Tick(timeGetTime()); ProcessKeyboard(); - /* bool anyRcvdMsg = */ ProcessSerialReceive(); + SerialQueue_T anyRcvdMsg = ProcessSerialReceive(); + if (anyRcvdMsg.len) { + // Show to the user + EchoSerialRecv(anyRcvdMsg.message); + + // Let the AVR interface handle it first + bool showAllFlag = avr->HandleMessage(anyRcvdMsg.message, anyRcvdMsg.len); + + if (showAllFlag) { + bool priorState = Console_SetCursorVisibility(false); + avr->ReportAllStatus(); + Console_SetCursorVisibility(priorState); + } + // old way to parse the message + //HandleMessage(anyRcvdMsg.message, anyRcvdMsg.len); + } + ProcessSerialQueue(); ProcessWindowsMessage(); } while (!UserWantsToExitCanSniff); @@ -1018,8 +1074,8 @@ bool CheckTheChecksum(uint8_t *szBuffer, uint32_t num) { } - -// ProcessResponse +#if 0 +// ProcessReportResponse // // @param[in] szBuffer is the received message // @param[in] len is the null terminated string length of the message @@ -1028,7 +1084,7 @@ bool CheckTheChecksum(uint8_t *szBuffer, uint32_t num) { // '\x02' 'type' 'guard' 'rcmd0' 'rcmd1' 'rdat0' 'rdat1' '\x03' // [0] [1] [2] [3] [4] [5] [6] [7] // -void ProcessResponse(uint8_t *szBuffer, uint32_t len) { +void ProcessReportResponse(uint8_t *szBuffer, uint32_t len) { // These don't have a checksum ... // Example: [02] 4026 66[03] // 4 - controlled by encoder @@ -1052,9 +1108,6 @@ void ProcessResponse(uint8_t *szBuffer, uint32_t len) { if (MessageHandlers[i].numToTransfer == 2) { memcpy(&avrStatus.config.DT0 + MessageHandlers[i].configOffset, &szBuffer[5], 2); } - //if (MessageHandlers[i].fncHelper) { - // (*MessageHandlers[i].fncHelper)(rcmd, rdat, szBuffer, len); - //} if (MessageHandlers[i].TextFormatter && MessageHandlers[i].fncValueToText) { sprintf_s(buf, MAXTEXTLEN, MessageHandlers[i].TextFormatter, MessageHandlers[i].fncValueToText(rdat)); Console_Write(buf); @@ -1071,10 +1124,11 @@ void ProcessResponse(uint8_t *szBuffer, uint32_t len) { Console_Write(buf); Console_ScrollBottomRegion(); } - } +#endif -// AnalyzeResponse + +// HandleMessage // // Given a response string, typically of the form: // [11] .... [03] @@ -1082,10 +1136,10 @@ void ProcessResponse(uint8_t *szBuffer, uint32_t len) { // ... etc // // -void AnalyzeResponse(uint8_t *szBuffer, uint32_t num) { +void HandleMessage(uint8_t *szBuffer, uint32_t num) { switch (szBuffer[0]) { case 0x02: // STX - ProcessResponse(szBuffer, num); + //ProcessReportResponse(szBuffer, num); break; case 0x11: // DC1 break; @@ -1107,9 +1161,8 @@ void AnalyzeResponse(uint8_t *szBuffer, uint32_t num) { } else { printf("***** Received message of unexpected length [%u]\n", num); } - ShowAllStatusInfo(); } else { - printf("Checksum failure on Status Header\n"); + Console_WriteAt(0, -1, "Checksum failure on Status Header"); } //PrintConfiguration(szBuffer); break; @@ -1132,34 +1185,34 @@ void AnalyzeResponse(uint8_t *szBuffer, uint32_t num) { // All character sequences end with \x03 (this is the equiv of a ) // // -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 +SerialQueue_T ProcessSerialReceive() { + uint8_t partialRx[MAXTEXTLEN] = { 0 }; - uint32_t num = avr.Read(rcv_buff, MAXTEXTLEN); + static uint8_t bufInUse = 0; + static uint8_t messageBuf[2][MAXTEXTLEN] = { 0 }; + static uint8_t *p = messageBuf[bufInUse]; // used to fill the partialRx as data comes in + SerialQueue_T retInfo = { NULL, 0 }; + + uint32_t num = avrPort.Read(partialRx, MAXTEXTLEN); if (num) { for (uint32_t i = 0; i < num; i++) { - *p = rcv_buff[i]; + *p = partialRx[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'; // null terminate it + // It is ready to return now + retInfo.message = messageBuf[bufInUse]; + retInfo.len = (uint16_t)(p - messageBuf[bufInUse]); + // Prepare the alternate buffer for the next message + bufInUse = (++bufInUse & 1); + p = messageBuf[bufInUse]; // Reset the buffer for the next message, which might be in partialRx *p = '\0'; - anythingReceived = true; } } if (messageBuf[0]) { //EmitBuffer("~", messageBuf, 0, true); // Show them the partial receipt if anything is there } } - return anythingReceived; + return retInfo; } @@ -1196,8 +1249,8 @@ void EnumerateComPorts() { int DetachSerialPort() { - if (avr.IsOpen()) { - avr.Close(); + if (avrPort.IsOpen()) { + avrPort.Close(); } return true; } @@ -1209,11 +1262,11 @@ int AttachToSerialPort() { sprintf_s(buf, sizeof(buf), "\\\\.\\COM%d", avrOnPort); uint32_t Access = GENERIC_WRITE | GENERIC_READ; - if (avr.Open(buf, avrBaud, 8, NOPARITY, ONESTOPBIT, Access)) { + if (avrPort.Open(buf, avrBaud, 8, NOPARITY, ONESTOPBIT, Access)) { success = true; - avr.Set_RTS_State(false); + avrPort.Set_RTS_State(false); Sleep(250); - avr.Set_RTS_State(true); + avrPort.Set_RTS_State(true); } } return success; diff --git a/AVR Working Controller/AVRInterface.cpp b/AVR Working Controller/AVRInterface.cpp index 13afe5e..1a56281 100644 --- a/AVR Working Controller/AVRInterface.cpp +++ b/AVR Working Controller/AVRInterface.cpp @@ -1,22 +1,227 @@ - +// +// +// +#ifdef _DEBUG +#include +#endif #include +#include #include #include "AVRInterface.h" +#include "AVRCommandDecoder.h" -//AVRInterface::AVRInterface(int (*SendMessage)(const void *buffer, unsigned int bufferSize)) { -//} +#define LONGESTTEXT 150 + +typedef enum { + eReady, + ePowerOn, + ePowerOff, + eVolumeUp, + eVolumeDown, + eMute, + eUnMute, +} AVRCommands_E; + +typedef struct { + AVRCommands_E MsgID; + const char *pMsg; + uint16_t MsgLen; +} Message_T; + +typedef struct { + //uint8_t type; // 0 to 4, and 0xFF for don't care + //uint8_t guard; // 0 to 2, and 0xFF for don't care + uint8_t rCmd; + uint8_t configOffset; // offset into the Config DT0 - DT155 array, or 0xFF for no action + uint8_t numToTransfer; // number of bytes to transfer into the Config array, or 0 for no action + bool showAll; // true to call ShowAllStatusInfo after processing + const char *TextFormatter; // used primarily for development printf(TextFormatter, value) + const char *(*fncValueToText)(uint8_t rDat); +} MessageHandler_T; + + +static const char * StateText[] = { + "Powering Up", + "Awaiting Ready Response", + "Initializing", + "Retry Initializing", + "Ready", + "Awaiting Response", + "Unknown State" +}; + +static const Message_T AVRCommands[] = { + { eReady, "\x11" "000" "\x03", 5 }, + { ePowerOn, "\x02" "07A1D" "\x03", 7 }, + { ePowerOff,"\x02" "07A1E" "\x03", 7 }, + { eVolumeUp,"\x02" "07A1A" "\x03", 7 }, + { eVolumeDown,"\x02" "07A1B" "\x03", 7 }, + { eMute, "\x02" "07EA2" "\x03", 7 }, + { eUnMute, "\x02" "07EA3" "\x03", 7 }, +}; + +// rCmd: 2-ASCII Hex Bytes converted to uint8_t +// configOffset: offset into avrStatus.config.DTxx +// numToTransfer: number of bytes to transfer from message to config (0 = none) +// show all status +// fncHelper: optional function to call upon receipt +// +static const MessageHandler_T MessageHandlers[] = { + // + // Configuration Map for Response Messages + // + // +--------------------------- rCmd + // | +----------------------- DT Block Offset + // | | +-------------------- Number of Bytes to transfer into the DT Block + // | | | +----------------- Force a 'show all' status screen update + // | | | | + // | | | | +-------- 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 }, + { 0x11, 32, 1, 1, "Fs Report: %s", FsToText }, + { 0x12, 33, 1, 1, "Ex/Ex: %s", OffMatrixDiscreteText }, // EX/EX + { 0x13, 34, 1, 1, "Thr Bypass: %s", OffOnText }, // Thr / Bypass + { 0x14, 35, 1, 1, "RED dts: %s", ReleaseWaitText}, // RED dts + { 0x15, 38, 1, 1, "Tuner tuned: %s", NotTunedTunedText}, // Tuner tuned + { 0x16, 43, 1, 1, "DTS 96/24: %s", OffOnText}, // Dts 96/24 + { 0x20, 8, 0, 1, "Zone Power: %s", ZonePower }, + { 0x21, 9, 1, 1, "Input: %s", InputText}, // Input Source + { 0x22, 11, 1, 1, "Input Mode: %s", InputModeText}, // Input Mode + { 0x23, 12, 1, 1, "Mute: %s", OffOnText }, + { 0x24, 13, 1, 1, "Zone 2 Input: %s", InputText}, // Zone 2 Input Source + { 0x25, 14, 1, 1, "Zone 2 Mute: %s", OffOnText }, + { 0x26, 15, 2, 1, "Volume: %s", VolumeDB }, + { 0x27, 17, 2, 1, "Zone 2 Vol: %s", VolumeDB}, // Zone 2 Vol + { 0x28, 19, 2, 1, "Program: %s", ProgramName }, // Program + { 0x29, 25, 1, 1, "Tuner Page: %s", PresetLabelText}, // Tuner Page + { 0x2A, 26, 1, 1, "Tuner Preset: %s", PresetNumberText}, // Tuner Preset Number + { 0x2B, 23, 1, 1, "OSD: %s", OSDFullShortOffText}, // OSD + { 0x2C, 24, 1, 1, "Sleep: %s", SleepTimerText}, // Sleep Timer + { 0x2D, 22, 1, 1, "EX/ES(Key): %s", OffMatrixDiscreteAutoText}, // EX/ES(Key) + { 0x2E, 29, 1, 1, "SP Relay A: ", OffOnText}, // Speaker Relay A + { 0x2F, 30, 1, 1, "SP Relay B: ", OffOnText}, // Speaker Relay B + { 0x30, 0, 0, 0, "Home Preset:%s", PresetLabelText }, // Preset A, B, ... F + { 0x31, 0, 0, 0, "Home Memory:%s", PresetLabelText }, // Preset A, B, ... F + { 0x32, 0, 0, 0, "Home Vol Preset: %s", PresetLabelText }, // Preset A, B, ... F + { 0x33, 0, 0, 0, "Home Vol Memory: %s", PresetLabelText }, // Preset A, B, ... F + { 0x34, 36, 1, 1, "Headphone: %s", OffOnText }, + { 0x35, 37, 1, 1, "FM/AM: %s", FMAMText }, + { 0x36, 39, 1, 1, "DC1 Trigger Out: %s", OffOnText }, + { 0x37, 0, 0, 0, "Home Zone 2 Vol Preset: %s", PresetLabelText }, + { 0x38, 0, 0, 0, "Home Zone 2 Vol: %s", PresetLabelText }, + { 0x39, 0, 0, 0, "Dual Mono: %s", MainSubAllText }, + { 0x3A, 42, 1, 1, "DC1 Trigger Control: %s", WhichZoneText }, + { 0x3B, 44, 1, 1, "DC2 Trigger Control: %s", WhichZoneText }, + { 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, 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 }, + { 0x42, 52, 2, 1, "Level Center: %s", PM10dbText }, + { 0x43, 54, 2, 1, "Level Rear R: %s", PM10dbText }, + { 0x44, 56, 2, 1, "Level Rear L: %s", PM10dbText }, + { 0x45, 58, 2, 1, "Level Sur Back R: %s", PM10dbText }, + { 0x46, 60, 2, 1, "Level Sur Back L: %s", PM10dbText }, + { 0x47, 62, 2, 1, "Level Front R: %s", PM10dbText }, + { 0x48, 64, 2, 1, "Level Front L: %s", PM10dbText }, + { 0x49, 66, 2, 1, "Level Swfr 1: %s", PM10dbText }, + { 0x4A, 0, 0, 0, "Level Swfr 2: %s", PM10dbText }, + + { 0x50, 0, 0, 0, "Main L/R Bal: %s", BalanceText }, + { 0x51, 74, 2, 1, "LFE Level SP: %s", M20P0dbText }, + { 0x52, 76, 2, 1, "LFE Level HP: %s", M20P0dbText }, + { 0x53, 78, 2, 1, "Audio Delay: %s", ZeroTo160msText }, + { 0x54, 0, 0, 0, "SP Delay Center: %s", ZeroTo5msText }, + { 0x55, 0, 0, 0, "SP Delay Rear CT: %s", ZeroTo30msText }, + + { 0x60, 84, 1, 1, "Input Mode: %s", AutoLastText }, + { 0x61, 85, 1, 1, "Dimmer: %s", M4To0Text }, + { 0x62, 87, 2, 1, "OSD Shift: %s", M5toP5Text }, + { 0x63, 89, 1, 1, "Gray Back: %s", OffAutoText }, + { 0x64, 91, 1, 1, "Dynamic Range SP: %s", MaxStdMinText }, + { 0x65, 92, 1, 1, "Dynamic Range HP: %s", MaxStdMinText }, + { 0x66, 93, 0, 0, "Zone 2 Vol out: %s", VarFixText }, + { 0x67, 0, 0, 0, "Zone 2 Mode: %s", Mode1Mode2Text }, + { 0x68, 95, 1, 1, "Mem Guard: %s", OffOnText }, + { 0x69, 90, 1, 1, "Video Conv: %s", OffOnText }, + { 0x6A, 136, 1, 1, "Comp OSD: %s", OffOnText }, + { 0x6B, 0, 0, 0, "Zone 3 Vol out: %s", VarFixText }, + { 0x70, 96, 1, 1, "Center Sp Size: %s", LSNText }, + { 0x71, 97, 1, 1, "Main Sp Size: %s", LSNText }, + { 0x72, 98, 1, 1, "Rear LR Sp Size: %s", LSNText }, + { 0x73, 99, 1, 1, "Sur Back Size: %s", LLSSNText }, + { 0x74, 100, 1, 1, "Front Sp: %s", YesNoneText }, + { 0x75, 101, 1, 1, "LFE Bass Out: %s", SwfrMainBothText }, + { 0x76, 134, 1, 1, "SW1: %s", LrFrNoneText }, + + { 0x78, 102, 1, 1, "6 Ch Center: %s", CenterMainText }, + { 0x79, 103, 1, 1, "6 Ch Swfr: %s", SwfrMainText }, + { 0x7A, 133, 1, 1, "6 Ch Surround: %s", SurrMainText }, + { 0x7B, 0, 0, 0, "Multi Ch Select: %s", SixEightText }, + { 0x7E, 135, 1, 1, "SW Crossover", CrossOverText }, + + { 0x80, 105, 1, 1, "Test Mode: %s", OffDolbyDspText }, + { 0x81, 0, 0, 0, "Analog Special: %s", OffOn2OnMultiText }, + { 0x82, 27, 1, 1, "Night Mode: %s", OffOnText }, + + { 0x90, 0, 0, 0, "Multi Ch Level Main R: %s", M10P10dbText }, + { 0x91, 0, 0, 0, "Multi Ch Level Main L: %s", M10P10dbText }, + { 0x92, 0, 0, 0, "Multi Ch Level Center: %s", M10P10dbText }, + { 0x93, 0, 0, 0, "Multi Ch Level Rear R: %s", M10P10dbText }, + { 0x94, 0, 0, 0, "Multi Ch Level Rear L: %s", M10P10dbText }, + { 0x95, 0, 0, 0, "Multi Ch Level Sur B R: %s", M10P10dbText }, + { 0x96, 0, 0, 0, "Multi Ch Level Sur B L: %s", M10P10dbText }, + { 0x97, 0, 0, 0, "Multi Ch Level Front R: %s", M10P10dbText }, + { 0x98, 0, 0, 0, "Multi Ch Level Front L: %s", M10P10dbText }, + { 0x99, 0, 0, 0, "Multi Ch Level Swfr 1: %s", M20P0dbText }, + { 0x9A, 0, 0, 0, "Multi Ch Level Swfr 2: %s", M20P0dbText }, + + { 0xA1, 0, 0, 0, "Zone 3 Mute: %s\n", OffOnText }, +}; + + + +AVRInterface::AVRInterface(bool (*SendMessage)(const uint8_t *buffer, uint16_t len)) { + SendMethod = SendMessage; + IsSanityCheckOK(); + MessageHandlerSanityCheck(); + Initialize(); +} AVRInterface::~AVRInterface() { FreeMemory(); } +bool AVRInterface::IsSanityCheckOK() { + static bool checked = false; + if (!checked) { + checked = true; + if (sizeof(AVRCommands) / sizeof(Message_T) != AVRState_T::stMaxStates + 1) { + #ifdef _DEBUG + printf("AVRCommands array size mismatch!\n"); + #endif + return false; + } + } + return true; +} + void AVRInterface::Tick(uint32_t now_ms) { uint32_t elapsed_ms = now_ms - sentAtTime_ms; + if (oldState != state && ReportInformation) { + oldState = state; + (*ReportInformation)(mtStatus, StateText[state]); + } switch (state) { default: case AVRState_T::stPoweringUp: readyResponsReceived = false; - ProcessSerialQueue((uint8_t *)"\x11" "000" "\x03", 5); // Send the Ready Command + ProcessSerialQueue(AVRCommands[eReady].pMsg, AVRCommands[eReady].MsgLen); sentAtTime_ms = now_ms; readyTries++; state = stAwaitingReadyResponse; @@ -38,6 +243,12 @@ void AVRInterface::Tick(uint32_t now_ms) { case AVRState_T::stRetryInitializing: break; case AVRState_T::stAwaitingResponse: + if (commandResponseReceived) { + state = stReady; + } else if (elapsed_ms > RETRY_INTERVAL_ms) { + ProcessSerialQueue(); + state = stAwaitingResponse; + } break; case AVRState_T::stReady: ProcessSerialQueue(); @@ -45,33 +256,103 @@ void AVRInterface::Tick(uint32_t now_ms) { } } +/// @brief Handle a just received message by parsing it +/// +/// Given a response string, typically of the form: +/// [11] .... [03] +/// [12] .... [03] +/// [14] ............ [03] +/// +/// @param buffer contains the message +/// @param len of the message +/// @return true, if data was accepted and the overall status changed, so might be shown +/// bool AVRInterface::HandleMessage(const uint8_t *buffer, uint16_t len) { + bool showAllFlag = false; + switch (state) { case stAwaitingReadyResponse: switch (buffer[0]) { case 0x02: // STX ETX + commandResponseReceived = true; + showAllFlag = ProcessReportResponse(buffer, len); break; case 0x11: // DC1 ETX break; case 0x12: // DC2 ETX if (CheckTheChecksum(buffer, len)) { + if (len == 21) { // Short message when power is off + memcpy(&avrStatus.header, &buffer[1], sizeof(AVR_StatusHeader_T)); + len = Hex2Dec(&avrStatus.header.length[0], 2); + memcpy(&avrStatus.config.DT0, &buffer[9], len); // Copy bits of the config + avrStatus.headerValid = true; + showAllFlag = true; + } else if (len == 150) { // Long message when power is on + memcpy(&avrStatus.header, &buffer[1], sizeof(AVR_StatusHeader_T)); + len = Hex2Dec(&avrStatus.header.length[0], 2); + memcpy(&avrStatus.config.DT0, &buffer[9], len); // Copy the config + avrStatus.headerValid = true; + avrStatus.configValid = true; + showAllFlag = true; + } else { + printf("***** Received message of unexpected length [%u]\n", len); + } readyResponsReceived = true; } break; case 0x14: // DC4 ETX + // DecodeExtendedResponse(buffer, len); // once I figure out what is in here... break; default: break; } - readyResponsReceived = true; + break; + case stAwaitingResponse: + // @TODO Process the message here... + commandResponseReceived = true; break; case stReady: + switch (buffer[0]) { + case 0x02: // STX ETX + commandResponseReceived = true; + showAllFlag = ProcessReportResponse(buffer, len); + break; + case 0x11: // DC1 ETX + break; + case 0x12: // DC2 ETX + if (CheckTheChecksum(buffer, len)) { + if (len == 21) { // Short message when power is off + memcpy(&avrStatus.header, &buffer[1], sizeof(AVR_StatusHeader_T)); + len = Hex2Dec(&avrStatus.header.length[0], 2); + memcpy(&avrStatus.config.DT0, &buffer[9], len); // Copy bits of the config + avrStatus.headerValid = true; + showAllFlag = true; + } else if (len == 150) { // Long message when power is on + memcpy(&avrStatus.header, &buffer[1], sizeof(AVR_StatusHeader_T)); + len = Hex2Dec(&avrStatus.header.length[0], 2); + memcpy(&avrStatus.config.DT0, &buffer[9], len); // Copy the config + avrStatus.headerValid = true; + avrStatus.configValid = true; + showAllFlag = true; + } else { + printf("***** Received message of unexpected length [%u]\n", len); + } + readyResponsReceived = true; + } + break; + case 0x14: // DC4 ETX + // DecodeExtendedResponse(buffer, len); // once I figure out what is in here... + break; + default: + break; + } break; } - return true; + return showAllFlag; } bool AVRInterface::Initialize() { + state = AVRState_T::stPoweringUp; return true; } @@ -79,6 +360,12 @@ bool AVRInterface::IsOnline() { return true; } bool AVRInterface::Power(AVRPower_T cmd) { + commandResponseReceived = false; + if (cmd == avrPowerOn) + ProcessSerialQueue(AVRCommands[ePowerOn].pMsg, AVRCommands[ePowerOn].MsgLen); + else + ProcessSerialQueue(AVRCommands[ePowerOff].pMsg, AVRCommands[ePowerOff].MsgLen); + state = stAwaitingResponse; return true; } @@ -89,15 +376,22 @@ bool AVRInterface::Mute(AVRMute_T cmd) { return true; } -bool AVRInterface::ProcessSerialQueue(const uint8_t *p, uint16_t len) { +bool AVRInterface::RegisterInformationCallback(void(*StatusChangeCallback)(AVRMessageType_T type, const char *msg)) { + ReportInformation = StatusChangeCallback; + return false; +} + +bool AVRInterface::ProcessSerialQueue(const void *msg, uint16_t len) { + const char *p = (const char *)msg; bool retVal = false; // assume fail static bool freshData = false; if (p && len) { if (serialQueueCount < SERIALQUEUESIZE) { - serialQueue[serialQueueCount].messageToSend = (uint8_t *)malloc(len); + serialQueue[serialQueueCount].messageToSend = (uint8_t *)malloc(len + 1); if (serialQueue[serialQueueCount].messageToSend) { memcpy(serialQueue[serialQueueCount].messageToSend, p, len); + *(serialQueue[serialQueueCount].messageToSend + len) = '\0'; serialQueue[serialQueueCount].len = len; serialQueueCount++; retVal = true; @@ -144,8 +438,8 @@ bool AVRInterface::CheckTheChecksum(const uint8_t *szBuffer, uint32_t num) { // This takes a buffer and converts the specified // number of characters. // -unsigned long AVRInterface::Hex2Dec(const uint8_t *p, int dig) { - unsigned long x = 0; +uint16_t AVRInterface::Hex2Dec(const uint8_t *p, int dig) { + uint16_t x = 0; while (dig--) { if (*p >= '0' && *p <= '9') x = x * 16 + *p - '0'; @@ -157,3 +451,230 @@ unsigned long AVRInterface::Hex2Dec(const uint8_t *p, int dig) { } return x; } + +// ProcessReportResponse +// +// @param[in] szBuffer is the received message +// @param[in] len is the null terminated string length of the message +// +// Typical Message: +// '\x02' 'type' 'guard' 'rcmd0' 'rcmd1' 'rdat0' 'rdat1' '\x03' +// [0] [1] [2] [3] [4] [5] [6] [7] +// +bool AVRInterface::ProcessReportResponse(const uint8_t *szBuffer, uint32_t len) { + // These don't have a checksum ... + // 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 = (uint8_t)Hex2Dec(&szBuffer[1], 1); + uint8_t guard = (uint8_t)Hex2Dec(&szBuffer[2], 1); + uint8_t rcmd = (uint8_t)Hex2Dec(&szBuffer[3], 2); + uint8_t rdat = (uint8_t)Hex2Dec(&szBuffer[5], 2); + char buf[LONGESTTEXT]; + (void)len; // not used + bool showAllFlag = false; + + bool found = false; + for (int i = 0; i < sizeof(MessageHandlers) / sizeof(MessageHandlers[0]); i++) { + if (MessageHandlers[i].rCmd == rcmd) { + found = true; + if (MessageHandlers[i].numToTransfer == 1) { + memcpy(&avrStatus.config.DT0 + MessageHandlers[i].configOffset, &szBuffer[6], 1); + } + if (MessageHandlers[i].numToTransfer == 2) { + memcpy(&avrStatus.config.DT0 + MessageHandlers[i].configOffset, &szBuffer[5], 2); + } + if (MessageHandlers[i].TextFormatter && MessageHandlers[i].fncValueToText) { + sprintf_s(buf, LONGESTTEXT, MessageHandlers[i].TextFormatter, MessageHandlers[i].fncValueToText(rdat)); + (*ReportInformation)(mtInfo, buf); + } + if (MessageHandlers[i].showAll) { + showAllFlag = true; // ShowAllStatusInfo(); + } + } + } + if (!found) { + sprintf_s(buf, LONGESTTEXT, "***** type: %X, guard: %X, cmd: %02X, data: %02X", type, guard, rcmd, rdat); + (*ReportInformation)(mtInfo, buf); + //Console_Write(buf); + //Console_ScrollBottomRegion(); + } + return showAllFlag; +} + +void AVRInterface::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"); + } + return; +} + +// 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 +// +void AVRInterface::PCMessage(const char *msg, int len, uint8_t **src, const char *(fncHelper)(uint8_t val)) { + char buf[LONGESTTEXT] = ""; + const char *p = buf; + + if (fncHelper) { + // Get the binary value if we need it + uint8_t val = (uint8_t)Hex2Dec(*src, len); + p = (*fncHelper)(val); + *src += len; + } else { + // Create a string value when we need that + strncpy_s(buf, LONGESTTEXT, (char *)*src, len); // s/w + *src += len; + buf[len] = '\0'; + } + + char outBuf[LONGESTTEXT] = ""; + sprintf_s(outBuf, LONGESTTEXT, "%17s %-8s", + msg, + p + ); + (*ReportInformation)(mtStream, outBuf); +} + + +void AVRInterface::ReportAllStatus() { + if (avrStatus.headerValid) { + char buf[LONGESTTEXT]; + sprintf_s(buf, LONGESTTEXT, "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); + (*ReportInformation)(mtModelInfo, buf); + + uint8_t *p = (uint8_t *)&avrStatus.config; + (*ReportInformation)(mtStreamStart, "---- AVR Status Report ----\n"); + 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, OffOnText); + if (avrStatus.configValid) { + PCMessage("Input", 1, &p, InputText); + PCMessage("6 ch", 1, &p); + PCMessage("Inp mode", 1, &p); + PCMessage("Mute", 1, &p, OffOnText); + PCMessage("Zone 2", 1, &p, InputText); + PCMessage("Mute 2", 1, &p, OffOnText); + PCMessage("Volume", 2, &p, VolumeDB); + PCMessage("Volume 2", 2, &p, VolumeDB); + PCMessage("pgm", 2, &p); + PCMessage("effect", 1, &p, OffOnText); + 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, OffOnText); + PCMessage("?????", 1, &p); + PCMessage("Spkr A", 1, &p, OffOnText); + PCMessage("Spkr B", 1, &p, OffOnText); + 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, OffOnText); + 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, OffOnText); + PCMessage("DC2 Trig Ctrl", 1, &p); + PCMessage("DC2 Trig", 1, &p); + PCMessage("Spkr B Set", 1, &p); + PCMessage("Zone 2 SP out", 1, &p, OffOnText); + 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, OffOnText); + 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, OffOnText); + 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, OffOnText); + PCMessage("PB/SB Select", 1, &p); + } + } +} diff --git a/AVR Working Controller/AVRInterface.h b/AVR Working Controller/AVRInterface.h index f2d2ee0..fb07b34 100644 --- a/AVR Working Controller/AVRInterface.h +++ b/AVR Working Controller/AVRInterface.h @@ -6,8 +6,7 @@ public: /// @brief /// @param SendMessage is the function this AVRInterface calls to send a message to the device /// - AVRInterface(int (*SendMessage)(const uint8_t *buffer, uint16_t len)) - : SendMethod(SendMessage) {}; + AVRInterface(bool (*SendMessage)(const uint8_t *buffer, uint16_t len)); ~AVRInterface(); @@ -49,7 +48,7 @@ public: /// @brief Send the power command /// @param cmd - /// @return true if sent + /// @return true /// bool Power(AVRPower_T cmd); @@ -67,7 +66,31 @@ public: avrMute, avrUnMute, } AVRMute_T; - bool Mute(AVRMute_T cmd); + + /// @brief Mute and Unmute + /// @param mute is avrMute or avrUnMute + /// @return true + bool Mute(AVRMute_T mute); + + typedef enum { + mtModelInfo, + mtStatus, // Special State machine status + mtInfo, // General purpose information + mtStreamStart, // Stream start + mtStream, // Status stream that word-wraps... + } AVRMessageType_T; + + /// @brief allows the host to register a callback for status changes + /// + /// the callback information is text + /// + /// @param StatusChangeCallback + /// @return + bool RegisterInformationCallback(void (*StatusChangeCallback)(AVRMessageType_T type, const char * msg)); + + /// @brief This will loop through the DT array and report the status of everything + /// + void ReportAllStatus(); private: uint32_t sentAtTime_ms; @@ -79,14 +102,183 @@ private: stRetryInitializing, stReady, stAwaitingResponse, + stMaxStates } AVRState_T; AVRState_T state = stPoweringUp; + AVRState_T oldState = stMaxStates; AVRState_T GetState() { return state; } - bool readyResponsReceived; + // 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; // Zone2 Input 0: PHONO / 1: CD / 2: TUNER / 3: CD-R / 4: MD-TAPE / 5: DVD / 6: D-TV-LD / 7: CBL-SAT / 9: VCR1 / A: VCR2-DVR / C: V-AUX + uint8_t DT14; // Zone2 Mute 0: OFF / 1: ON + uint8_t DT15; // Master Volume Upper 4 bit + uint8_t DT16; // Master Volume Lower 4 bit + uint8_t DT17; // Zone2 Volume Upper 4 bit + uint8_t DT18; // Zone2 Volume Lower 4 bit + uint8_t DT19; // Program Upper 4 bit + uint8_t DT20; // Program Lower 4 bit + uint8_t DT21; // Effect 0: OFF / 1: ON + uint8_t DT22; // 6.1/ES key status 0: OFF / 1: MATRIX ON / 2: DISCRETE ON / 3: AUTO + uint8_t DT23; // OSD* 0: FULL / 1: SHORT / 2: OFF + uint8_t DT24; // Sleep 0: 120 / 2: 90 / 3: 60 / 4: 30 / 5: OFF + uint8_t DT25; // Tuner Page 0: Page A / 1: Page B / 2: Page C / 3: Page D / 4: PageE + uint8_t DT26; // Tuner No. 0: No.1 / 1: No.2 / 2: No.3 / 3: No.4 / 4: No.5 / 5: No.6 / 6: No.7 / 7: No.8 + uint8_t DT27; // Night mode 0: OFF / 1: ON + uint8_t DT28; // Care + uint8_t DT29; // Speaker relay A 0: OFF / 1: ON + uint8_t DT30; // Speaker relay B 0: OFF / 1: ON + uint8_t DT31; // Playback 0: 6ch input / 1: Analog / 2: PCM / 3: DD*(except 2.0) / 4: DD(2.0) / 5: DD.Karaoke / 6: DD.EX / 7: DTS / 8: DTS-ES / 9: Other DIGITAL / A: DTS Analog Mute / B: DTS ES Discrete + uint8_t DT32; // Fs 0: Analog / 1: 32kHz / 2: 44.1kHz / 3: 48kiHz / 4: 64kHz / 5: 88.2kHz / 6: 96kHz / 7: Unknown B: DTS 96/24 + uint8_t DT33; // EX/ES playback 0: OFF / 1: MATRIX ON / 2: DISCRETE ON + uint8_t DT34; // Thr / Bypass 0: Normal / 1: Bypass + uint8_t DT35; // RED dts 0: Release / 1: Wait + uint8_t DT36; // Head Phone 0: OFF / 1: ON + uint8_t DT37; // TUNER BAND 0: FM / 1: AM + uint8_t DT38; // TUNER TUNED 0: NOT TUNED / 1: TUNED + uint8_t DT39; // DC1 Control Out 0: LOW / 1: HIGH + + uint8_t DT40; // Don’t care + uint8_t DT41; // Don't Care + uint8_t DT42; // 0-2 DC1 TRG Ctrl. 0: Zone1 / 1: Zone2 / 2: Zone1&2 + uint8_t DT43; // 0/1 dts 96/24 0: OFF / 1: ON + uint8_t DT44; // 0-2 DC2 TRG Ctrl. 0: Zone1 / 1: Zone2 / 2: Zone1&2 + uint8_t DT45; // 0/1 DC2 Trigger 0: LOW / 1: HIGH + uint8_t DT46; // SP B set 0: Zone1 / 1: Zone2 + uint8_t DT47; // Zone 2 SP out 0: OFF / 1: ON + uint8_t DT48; // MAIN R Upper 4bit + uint8_t DT49; // Lower 4bit + uint8_t DT50; // MAIN L Upper 4bit + uint8_t DT51; // Lower 4bit + uint8_t DT52; // CENTER Upper 4bit + uint8_t DT53; // Lower 4bit + uint8_t DT54; // REAR R Upper 4bit + uint8_t DT55; // Lower 4bit + uint8_t DT56; // REAR L Upper 4bit + uint8_t DT57; // Lower 4bit + uint8_t DT58; // SUR BACK Upper 4bit + uint8_t DT59; // R Lower 4bit + uint8_t DT60; // SUR BACK Upper 4bit + uint8_t DT61; // L Lower 4bit + uint8_t DT62; // FRONT R Upper 4bit + uint8_t DT63; // Lower 4bit + uint8_t DT64; // FRONT L Upper 4bit + uint8_t DT65; // Lower 4bit + uint8_t DT66; // SWFR 1 Upper 4bit + uint8_t DT67; // Lower 4bit + uint8_t DT68; // Don't Care + uint8_t DT69; // Don't Care + uint8_t DT70; // Don't Care + uint8_t DT71; // Don't Care + uint8_t DT72; // Don't Care + uint8_t DT73; // Don't Care + uint8_t DT74; // LFE Lvl. SP Upper 4bit + uint8_t DT75; // Lower 4bit + uint8_t DT76; // LFE Lvl. HP Upper 4bit + uint8_t DT77; // Lower 4bit + uint8_t DT78; // Audio Delay Upper 4bit + uint8_t DT79; // Lower 4bit + + uint8_t DT80; // Don't Care + uint8_t DT81; // Don't Care + uint8_t DT82; // Don't Care + uint8_t DT83; // Don't Care + uint8_t DT84; // Input mode set 0: AUTO / 1: LAST + uint8_t DT85; // Dimmer 0: -4 / 1: -3 / 2: -2 / 3: -1 / 4: 0 + uint8_t DT86; // OSD Message + uint8_t DT87; // OSD shift Upper 4bit + uint8_t DT88; // Lower 4bit + uint8_t DT89; // Glay back 0: OFF / 1: AUTO + uint8_t DT90; // Video conversion 0: OFF / 1: ON + uint8_t DT91; // D. Range SP 0: MAX / 1: STD / 2: MIN + uint8_t DT92; // HP 0: MAX / 1: STD / 2: MIN + uint8_t DT93; // Zone 2 vol. Out + uint8_t DT94; // Don't Care + uint8_t DT95; // Memory guard 0: OFF / 1: ON + uint8_t DT96; // SP set Center 0: Large / 1: Small / 2: None + uint8_t DT97; // Main 0: Large / 1: Small + uint8_t DT98; // Rear L/R 0: Large / 1: Small / 2: None + uint8_t DT99; // Rear CT 0: Large / 1: Small / 2: None + uint8_t DT100; // Front 0: Yes / 1: None + uint8_t DT101; // LFE/BASS 0: SWFR / 1: Main / 2: Both + uint8_t DT102; // 6CH Center 0: Center / 1: Main + uint8_t DT103; // SWFR 0: SWFR / 1: Main + uint8_t DT104; // Main level 0: Normal / 1: -10dB + uint8_t DT105; // Test mode 0: OFF / 1: Dolby / 2: DTS + uint8_t DT106; // Don't Care + uint8_t DT107; // LVL 6CH MAIN L Upper 4bit + uint8_t DT108; // Lower 4bit + uint8_t DT109; // MAIN R Upper 4bit + uint8_t DT110; // Lower 4bit + uint8_t DT111; // CENTER Upper 4bit + uint8_t DT112; // Lower 4bit + uint8_t DT113; // SL Upper 4bit + uint8_t DT114; // Lower 4bit + uint8_t DT115; // SR Upper 4bit + uint8_t DT116; // Lower 4bit + uint8_t DT117; // SBL Upper 4bit + uint8_t DT118; // Lower 4bit + uint8_t DT119; // SBR Upper 4bit + uint8_t DT120; // Lower 4bit + uint8_t DT121; // FRONT L Upper 4bit + uint8_t DT122; // Lower 4bit + uint8_t DT123; // FRONT R Upper 4bit + uint8_t DT124; // Lower 4bit + uint8_t DT125; // SWFR Upper 4bit + uint8_t DT126; // Lower 4bit + uint8_t DT127; // 0 - C Z3 Input + uint8_t DT128; // 0/1 Z3 Mute + uint8_t DT129; // 0 - F Z3 Volume Upper 4bit + + uint8_t DT130; // 0 - F Lower 4bit + uint8_t DT131; // Don't Care + uint8_t DT132; // MULTI_CH SELECT 00:6CH / 01:8CH TUNER / 02: 8CH CD / 04: 8CH CD-R / 05: 8CH DVD / 06: DTV / 07: 8CH CBL/SAT / 09: 8CH VCR1 / 0A: VCR2/DVR / 0C: VAUX + uint8_t DT133; // MULTI_CH SURROUND to 00: Surround / 01: Main + uint8_t DT134; // SP SET SW1 00: L-R / 01: F-R / 02: NONE + uint8_t DT135; // SP SET CROSSOVER 00: 40Hz / 01: 60Hz / 02: 80Hz / 03: 90Hz / 04: 100Hz / 05: 110Hz / 06: 120Hz / 07: 160Hz / 08: 200Hz + uint8_t DT136; // COMPONENT OSD 00: OFF / 01: ON + uint8_t DT137; // PB/SB SELECT 00: PR / 01: SB + + uint8_t DT138[100]; // From here on is just buffer in case it sends more data + } AVR_Configuration_T; + + 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; + bool commandResponseReceived; // a response to the last command was received + bool readyResponsReceived; // the special system ready response was received int readyTries; #define RETRY_INTERVAL_ms 500 #define MAXTRIES 5 @@ -100,12 +292,22 @@ private: SerialQueue_T serialQueue[SERIALQUEUESIZE]; int serialQueueCount = 0; - bool ProcessSerialQueue(const uint8_t *p = NULL, uint16_t len = NULL); + bool ProcessSerialQueue(const void *p = NULL, uint16_t len = NULL); - int (*SendMethod)(const uint8_t *buffer, uint16_t bufferSize); + bool IsSanityCheckOK(); + void MessageHandlerSanityCheck(); + + // host provided method to send to the AVR + bool (*SendMethod)(const uint8_t *buffer, uint16_t bufferSize); + + // host provided method to update the user with a text message + void(*ReportInformation)(AVRMessageType_T type, const char * message); + + void PCMessage(const char *msg, int len, uint8_t **src, const char *(fncHelper)(uint8_t val) = NULL); + bool ProcessReportResponse(const uint8_t *szBuffer, uint32_t len); bool CheckTheChecksum(const uint8_t *szBuffer, uint32_t num); - unsigned long Hex2Dec(const uint8_t *p, int dig); + uint16_t Hex2Dec(const uint8_t *p, int dig); void FreeMemory(); };