Major changes - refactoring the AVRInterface class to take on more responsibility.

This commit is contained in:
2026-01-25 21:39:10 -06:00
parent 30f4047b7c
commit 152e0c2d80
3 changed files with 858 additions and 82 deletions

View File

@@ -11,7 +11,8 @@
#include <time.h> #include <time.h>
#include <timeapi.h> #include <timeapi.h>
#include "SerialPort\SerialPort.h" #include "SerialPort\SerialPort.h"
#include "AVRCommandDecoder.h" #include "AVRInterface.h"
//#include "AVRCommandDecoder.h"
#include "ConsoleHandler.h" #include "ConsoleHandler.h"
enum enum
@@ -20,12 +21,14 @@ enum
COM_MIN_PORT = 1, COM_MIN_PORT = 1,
COM_MAX_PORT = 99 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, ... 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; unsigned avrBaud = 9600;
const uint32_t retryInterval = 1000; // ms const uint32_t retryInterval = 1000; // ms
AVRInterface *avr;
// Each DT is the hex-character from the stream // Each DT is the hex-character from the stream
// //
// //
@@ -176,7 +179,7 @@ typedef struct {
} AVR_Configuration_T; } AVR_Configuration_T;
// 264 total
typedef struct { typedef struct {
uint8_t type[5]; // Model ID uint8_t type[5]; // Model ID
uint8_t version; // A-Z 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 // Just big enough to hold an OSD message which is a 1 message command, 4 messages with text
#define SERIALQUEUESIZE 5 #define SERIALQUEUESIZE 5
typedef struct { typedef struct {
uint8_t *messageToSend; uint8_t *message;
uint16_t len; uint16_t len;
} SerialQueue_T; } SerialQueue_T;
@@ -250,11 +253,13 @@ bool ProcessSerialQueue(const uint8_t *p = NULL, uint16_t len = 0);
// //
// @returns true if a message was processed. // @returns true if a message was processed.
// //
bool ProcessSerialReceive(void); SerialQueue_T ProcessSerialReceive(void);
void HandleMessage(uint8_t *szBuffer, uint32_t num);
void EnumerateComPorts(); void EnumerateComPorts();
unsigned long Hex2Dec(uint8_t *p, int dig); unsigned long Hex2Dec(uint8_t *p, int dig);
void ShowAllStatusInfo(); //void ShowAllStatusInfo();
bool UserWantsToExitCanSniff = false; bool UserWantsToExitCanSniff = false;
DWORD progStartTime_ms; DWORD progStartTime_ms;
@@ -330,6 +335,7 @@ void UserCommandsSanityCheck() {
} }
} }
#if 0
// rCmd: 2-ASCII Hex Bytes converted to uint8_t // rCmd: 2-ASCII Hex Bytes converted to uint8_t
// configOffset: offset into avrStatus.config.DTxx // configOffset: offset into avrStatus.config.DTxx
// numToTransfer: number of bytes to transfer from message to config (0 = none) // numToTransfer: number of bytes to transfer from message to config (0 = none)
@@ -484,7 +490,7 @@ void MessageHandlerSanityCheck() {
exit(EXIT_ConfigError); exit(EXIT_ConfigError);
} }
} }
#endif
int CS_KeyHit() { int CS_KeyHit() {
int h = _kbhit(); int h = _kbhit();
@@ -580,7 +586,7 @@ bool SerialSend(const uint8_t *p, uint16_t len) {
Console_SetCursor(0, -1); Console_SetCursor(0, -1);
EmitBuffer("> ", p, len); EmitBuffer("> ", p, len);
Console_ScrollBottomRegion(); Console_ScrollBottomRegion();
if (avr.Write((const LPVOID)p, len) == len) { if (avrPort.Write((const LPVOID)p, len) == len) {
retVal = true; retVal = true;
} else { } else {
Console_SetCursor(0, -1); Console_SetCursor(0, -1);
@@ -596,9 +602,9 @@ bool ProcessSerialQueue(const uint8_t *p, uint16_t len) {
if (p && len) { if (p && len) {
if (serialQueueCount < SERIALQUEUESIZE) { if (serialQueueCount < SERIALQUEUESIZE) {
serialQueue[serialQueueCount].messageToSend = (uint8_t *)malloc(len); serialQueue[serialQueueCount].message = (uint8_t *)malloc(len);
if (serialQueue[serialQueueCount].messageToSend) { if (serialQueue[serialQueueCount].message) {
memcpy(serialQueue[serialQueueCount].messageToSend, p, len); memcpy(serialQueue[serialQueueCount].message, p, len);
serialQueue[serialQueueCount].len = len; serialQueue[serialQueueCount].len = len;
serialQueueCount++; serialQueueCount++;
retVal = true; retVal = true;
@@ -607,9 +613,9 @@ bool ProcessSerialQueue(const uint8_t *p, uint16_t len) {
} }
} }
if (serialQueueCount) { 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; --serialQueueCount;
free(serialQueue[0].messageToSend); free(serialQueue[0].message);
for (int i = 0; i < serialQueueCount; i++) { for (int i = 0; i < serialQueueCount; i++) {
serialQueue[i] = serialQueue[i + 1]; serialQueue[i] = serialQueue[i + 1];
} }
@@ -645,14 +651,14 @@ void EmitRuntimeHelp() {
Console_AdvanceToNextLineIfNotRoomFor((short)strlen(buf), 1); Console_AdvanceToNextLineIfNotRoomFor((short)strlen(buf), 1);
Console_Write(buf); Console_Write(buf);
} }
if (avr.IsOpen()) { if (avrPort.IsOpen()) {
Console_ScrollBottomRegion(); Console_ScrollBottomRegion();
Console_SetCursor(0, -1); Console_SetCursor(0, -1);
printf(" Com Status: RTS: %-3s ", avr.Get_RTS_State() ? "ON" : "OFF"); printf(" Com Status: RTS: %-3s ", avrPort.Get_RTS_State() ? "ON" : "OFF");
printf("DTR: %-3s ", avr.Get_DTR_State() ? "ON" : "OFF"); printf("DTR: %-3s ", avrPort.Get_DTR_State() ? "ON" : "OFF");
printf("CTS: %-3s ", avr.Get_CTS_State() ? "ON" : "OFF"); printf("CTS: %-3s ", avrPort.Get_CTS_State() ? "ON" : "OFF");
printf("DSR: %-3s ", avr.Get_DSR_State() ? "ON" : "OFF"); printf("DSR: %-3s ", avrPort.Get_DSR_State() ? "ON" : "OFF");
printf("RI: %-3s", avr.Get_RI_State() ? "ON" : "OFF"); printf("RI: %-3s", avrPort.Get_RI_State() ? "ON" : "OFF");
Console_ScrollBottomRegion(); Console_ScrollBottomRegion();
Console_SetCursor(0, -1); 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) { void ShowAllStatusInfo(void) {
if (avrStatus.headerValid) { if (avrStatus.headerValid) {
bool priorState = Console_SetCursorVisibility(false); bool priorState = Console_SetCursorVisibility(false);
@@ -807,7 +813,7 @@ void ShowAllStatusInfo(void) {
Console_SetCursorVisibility(priorState); Console_SetCursorVisibility(priorState);
} }
} }
#endif
void ProcessKeyboard(void) { void ProcessKeyboard(void) {
static uint32_t spin = 0; static uint32_t spin = 0;
@@ -819,6 +825,12 @@ void ProcessKeyboard(void) {
if (CS_KeyHit()) { if (CS_KeyHit()) {
int c = CS_GetChar(); int c = CS_GetChar();
switch (c) { switch (c) {
case 'P':
avr->Power(AVRInterface::avrPowerOn);
break;
case 'p':
avr->Power(AVRInterface::avrPowerOff);
break;
case 'O': case 'O':
ProcessSerialQueue((const uint8_t *)"\x02" "21000" "\x03", 7); ProcessSerialQueue((const uint8_t *)"\x02" "21000" "\x03", 7);
ProcessSerialQueue((const uint8_t *)"\x02" "3Test" "\x03", 7); ProcessSerialQueue((const uint8_t *)"\x02" "3Test" "\x03", 7);
@@ -830,19 +842,20 @@ void ProcessKeyboard(void) {
EmitRuntimeHelp(); EmitRuntimeHelp();
break; break;
case '/': case '/':
ShowAllStatusInfo(); avr->ReportAllStatus();
//ShowAllStatusInfo();
break; break;
case '\x1B': case '\x1B':
UserWantsToExitCanSniff = true; UserWantsToExitCanSniff = true;
break; break;
case 'S': case 'S':
avr.Set_RTS_State(TRUE); avrPort.Set_RTS_State(TRUE);
Console_SetCursor(0, -1); Console_SetCursor(0, -1);
printf("RTS set ON"); printf("RTS set ON");
Console_ScrollBottomRegion(); Console_ScrollBottomRegion();
break; break;
case 's': case 's':
avr.Set_RTS_State(FALSE); avrPort.Set_RTS_State(FALSE);
Console_SetCursor(0, -1); Console_SetCursor(0, -1);
printf("RTS set OFF"); printf("RTS set OFF");
Console_ScrollBottomRegion(); Console_ScrollBottomRegion();
@@ -894,7 +907,31 @@ void EmitCommandLineHelp() {
exit(EXIT_OK); 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 ( ) */ /* m a i n ( ) */
@@ -903,9 +940,8 @@ void EmitCommandLineHelp() {
// 0 99 // 0 99
// +---------------------------------------------------------------+ // +---------------------------------------------------------------+
// | Program banner information | 0 // | Program banner information | 0
// | on two lines | // | State machine status information starts on line 2 |
// | Current status information starts on line 3 | // | Overall information is on line 3 and onward |
// | and down a ways... |
// | | // | |
// | | // | |
// | | // | |
@@ -921,7 +957,7 @@ int __cdecl main(int argc, char *argv[]) {
short consoleScrollHeight = 30; short consoleScrollHeight = 30;
progStartTime_ms = timeGetTime(); 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 UserCommandsSanityCheck(); // If the table is bad, we exit here
Console_Init(consoleWidth, consoleHeight, consoleScrollHeight); Console_Init(consoleWidth, consoleHeight, consoleScrollHeight);
@@ -956,9 +992,29 @@ int __cdecl main(int argc, char *argv[]) {
printf("[COM%i at %i baud]", avrOnPort, avrBaud); printf("[COM%i at %i baud]", avrOnPort, avrBaud);
Console_WriteAt(0, consoleHeight - consoleScrollHeight -1, "----------------------------------------"); Console_WriteAt(0, consoleHeight - consoleScrollHeight -1, "----------------------------------------");
avr = new AVRInterface(SerialSend);
avr->RegisterInformationCallback(InformationUpdate);
do { do {
avr->Tick(timeGetTime());
ProcessKeyboard(); 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(); ProcessSerialQueue();
ProcessWindowsMessage(); ProcessWindowsMessage();
} while (!UserWantsToExitCanSniff); } while (!UserWantsToExitCanSniff);
@@ -1018,8 +1074,8 @@ bool CheckTheChecksum(uint8_t *szBuffer, uint32_t num) {
} }
#if 0
// ProcessResponse // ProcessReportResponse
// //
// @param[in] szBuffer is the received message // @param[in] szBuffer is the received message
// @param[in] len is the null terminated string length of the 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' // '\x02' 'type' 'guard' 'rcmd0' 'rcmd1' 'rdat0' 'rdat1' '\x03'
// [0] [1] [2] [3] [4] [5] [6] [7] // [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 ... // These don't have a checksum ...
// Example: [02] 4026 66[03] // Example: [02] 4026 66[03]
// 4 - controlled by encoder // 4 - controlled by encoder
@@ -1052,9 +1108,6 @@ void ProcessResponse(uint8_t *szBuffer, uint32_t len) {
if (MessageHandlers[i].numToTransfer == 2) { if (MessageHandlers[i].numToTransfer == 2) {
memcpy(&avrStatus.config.DT0 + MessageHandlers[i].configOffset, &szBuffer[5], 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) { if (MessageHandlers[i].TextFormatter && MessageHandlers[i].fncValueToText) {
sprintf_s(buf, MAXTEXTLEN, MessageHandlers[i].TextFormatter, MessageHandlers[i].fncValueToText(rdat)); sprintf_s(buf, MAXTEXTLEN, MessageHandlers[i].TextFormatter, MessageHandlers[i].fncValueToText(rdat));
Console_Write(buf); Console_Write(buf);
@@ -1071,10 +1124,11 @@ void ProcessResponse(uint8_t *szBuffer, uint32_t len) {
Console_Write(buf); Console_Write(buf);
Console_ScrollBottomRegion(); Console_ScrollBottomRegion();
} }
} }
#endif
// AnalyzeResponse
// HandleMessage
// //
// Given a response string, typically of the form: // Given a response string, typically of the form:
// [11] .... [03] // [11] .... [03]
@@ -1082,10 +1136,10 @@ void ProcessResponse(uint8_t *szBuffer, uint32_t len) {
// ... etc // ... etc
// //
// //
void AnalyzeResponse(uint8_t *szBuffer, uint32_t num) { void HandleMessage(uint8_t *szBuffer, uint32_t num) {
switch (szBuffer[0]) { switch (szBuffer[0]) {
case 0x02: // STX case 0x02: // STX
ProcessResponse(szBuffer, num); //ProcessReportResponse(szBuffer, num);
break; break;
case 0x11: // DC1 case 0x11: // DC1
break; break;
@@ -1107,9 +1161,8 @@ void AnalyzeResponse(uint8_t *szBuffer, uint32_t num) {
} else { } else {
printf("***** Received message of unexpected length [%u]\n", num); printf("***** Received message of unexpected length [%u]\n", num);
} }
ShowAllStatusInfo();
} else { } else {
printf("Checksum failure on Status Header\n"); Console_WriteAt(0, -1, "Checksum failure on Status Header");
} }
//PrintConfiguration(szBuffer); //PrintConfiguration(szBuffer);
break; 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 <cr>) // All character sequences end with \x03 (this is the equiv of a <cr>)
// //
// //
bool ProcessSerialReceive() { SerialQueue_T ProcessSerialReceive() {
bool anythingReceived = false; uint8_t partialRx[MAXTEXTLEN] = { 0 };
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); 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) { if (num) {
for (uint32_t i = 0; i < num; i++) { for (uint32_t i = 0; i < num; i++) {
*p = rcv_buff[i]; *p = partialRx[i];
if (*p++ == '\x03') { // End of message if (*p++ == '\x03') { // End of message
*p = '\0'; // null terminate it *p = '\0'; // null terminate it
EchoSerialRecv(messageBuf); // It is ready to return now
// retInfo.message = messageBuf[bufInUse];
// @TODO Now do something with the received message retInfo.len = (uint16_t)(p - messageBuf[bufInUse]);
// // Prepare the alternate buffer for the next message
AnalyzeResponse(messageBuf, (uint32_t)strlen((char *)messageBuf)); bufInUse = (++bufInUse & 1);
p = messageBuf[bufInUse]; // Reset the buffer for the next message, which might be in partialRx
p = messageBuf; // Reset the buffer for the next message, which might be in rcv_buff
*p = '\0'; *p = '\0';
anythingReceived = true;
} }
} }
if (messageBuf[0]) { if (messageBuf[0]) {
//EmitBuffer("~", messageBuf, 0, true); // Show them the partial receipt if anything is there //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() { int DetachSerialPort() {
if (avr.IsOpen()) { if (avrPort.IsOpen()) {
avr.Close(); avrPort.Close();
} }
return true; return true;
} }
@@ -1209,11 +1262,11 @@ int AttachToSerialPort() {
sprintf_s(buf, sizeof(buf), "\\\\.\\COM%d", avrOnPort); sprintf_s(buf, sizeof(buf), "\\\\.\\COM%d", avrOnPort);
uint32_t Access = GENERIC_WRITE | GENERIC_READ; 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; success = true;
avr.Set_RTS_State(false); avrPort.Set_RTS_State(false);
Sleep(250); Sleep(250);
avr.Set_RTS_State(true); avrPort.Set_RTS_State(true);
} }
} }
return success; return success;

View File

@@ -1,22 +1,227 @@
//
//
//
#ifdef _DEBUG
#include <stdio.h>
#endif
#include <memory.h> #include <memory.h>
#include <string.h>
#include <malloc.h> #include <malloc.h>
#include "AVRInterface.h" #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() { AVRInterface::~AVRInterface() {
FreeMemory(); 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) { void AVRInterface::Tick(uint32_t now_ms) {
uint32_t elapsed_ms = now_ms - sentAtTime_ms; uint32_t elapsed_ms = now_ms - sentAtTime_ms;
if (oldState != state && ReportInformation) {
oldState = state;
(*ReportInformation)(mtStatus, StateText[state]);
}
switch (state) { switch (state) {
default: default:
case AVRState_T::stPoweringUp: case AVRState_T::stPoweringUp:
readyResponsReceived = false; readyResponsReceived = false;
ProcessSerialQueue((uint8_t *)"\x11" "000" "\x03", 5); // Send the Ready Command ProcessSerialQueue(AVRCommands[eReady].pMsg, AVRCommands[eReady].MsgLen);
sentAtTime_ms = now_ms; sentAtTime_ms = now_ms;
readyTries++; readyTries++;
state = stAwaitingReadyResponse; state = stAwaitingReadyResponse;
@@ -38,6 +243,12 @@ void AVRInterface::Tick(uint32_t now_ms) {
case AVRState_T::stRetryInitializing: case AVRState_T::stRetryInitializing:
break; break;
case AVRState_T::stAwaitingResponse: case AVRState_T::stAwaitingResponse:
if (commandResponseReceived) {
state = stReady;
} else if (elapsed_ms > RETRY_INTERVAL_ms) {
ProcessSerialQueue();
state = stAwaitingResponse;
}
break; break;
case AVRState_T::stReady: case AVRState_T::stReady:
ProcessSerialQueue(); 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 AVRInterface::HandleMessage(const uint8_t *buffer, uint16_t len) {
bool showAllFlag = false;
switch (state) { switch (state) {
case stAwaitingReadyResponse: case stAwaitingReadyResponse:
switch (buffer[0]) { switch (buffer[0]) {
case 0x02: // STX <msg> ETX case 0x02: // STX <msg> ETX
commandResponseReceived = true;
showAllFlag = ProcessReportResponse(buffer, len);
break; break;
case 0x11: // DC1 <msg> ETX case 0x11: // DC1 <msg> ETX
break; break;
case 0x12: // DC2 <msg> ETX case 0x12: // DC2 <msg> ETX
if (CheckTheChecksum(buffer, len)) { 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; readyResponsReceived = true;
} }
break; break;
case 0x14: // DC4 <extended response> ETX case 0x14: // DC4 <extended response> ETX
// DecodeExtendedResponse(buffer, len); // once I figure out what is in here...
break; break;
default: default:
break; break;
} }
readyResponsReceived = true; break;
case stAwaitingResponse:
// @TODO Process the message here...
commandResponseReceived = true;
break; break;
case stReady: case stReady:
switch (buffer[0]) {
case 0x02: // STX <msg> ETX
commandResponseReceived = true;
showAllFlag = ProcessReportResponse(buffer, len);
break;
case 0x11: // DC1 <msg> ETX
break;
case 0x12: // DC2 <msg> 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 <extended response> ETX
// DecodeExtendedResponse(buffer, len); // once I figure out what is in here...
break;
default:
break;
}
break; break;
} }
return true; return showAllFlag;
} }
bool AVRInterface::Initialize() { bool AVRInterface::Initialize() {
state = AVRState_T::stPoweringUp;
return true; return true;
} }
@@ -79,6 +360,12 @@ bool AVRInterface::IsOnline() {
return true; return true;
} }
bool AVRInterface::Power(AVRPower_T cmd) { 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; return true;
} }
@@ -89,15 +376,22 @@ bool AVRInterface::Mute(AVRMute_T cmd) {
return true; 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 bool retVal = false; // assume fail
static bool freshData = false; static bool freshData = false;
if (p && len) { if (p && len) {
if (serialQueueCount < SERIALQUEUESIZE) { if (serialQueueCount < SERIALQUEUESIZE) {
serialQueue[serialQueueCount].messageToSend = (uint8_t *)malloc(len); serialQueue[serialQueueCount].messageToSend = (uint8_t *)malloc(len + 1);
if (serialQueue[serialQueueCount].messageToSend) { if (serialQueue[serialQueueCount].messageToSend) {
memcpy(serialQueue[serialQueueCount].messageToSend, p, len); memcpy(serialQueue[serialQueueCount].messageToSend, p, len);
*(serialQueue[serialQueueCount].messageToSend + len) = '\0';
serialQueue[serialQueueCount].len = len; serialQueue[serialQueueCount].len = len;
serialQueueCount++; serialQueueCount++;
retVal = true; retVal = true;
@@ -144,8 +438,8 @@ bool AVRInterface::CheckTheChecksum(const uint8_t *szBuffer, uint32_t num) {
// This takes a buffer and converts the specified // This takes a buffer and converts the specified
// number of characters. // number of characters.
// //
unsigned long AVRInterface::Hex2Dec(const uint8_t *p, int dig) { uint16_t AVRInterface::Hex2Dec(const uint8_t *p, int dig) {
unsigned long x = 0; uint16_t x = 0;
while (dig--) { while (dig--) {
if (*p >= '0' && *p <= '9') if (*p >= '0' && *p <= '9')
x = x * 16 + *p - '0'; x = x * 16 + *p - '0';
@@ -157,3 +451,230 @@ unsigned long AVRInterface::Hex2Dec(const uint8_t *p, int dig) {
} }
return x; 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);
}
}
}

View File

@@ -6,8 +6,7 @@ public:
/// @brief /// @brief
/// @param SendMessage is the function this AVRInterface calls to send a message to the device /// @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)) AVRInterface(bool (*SendMessage)(const uint8_t *buffer, uint16_t len));
: SendMethod(SendMessage) {};
~AVRInterface(); ~AVRInterface();
@@ -49,7 +48,7 @@ public:
/// @brief Send the power command /// @brief Send the power command
/// @param cmd /// @param cmd
/// @return true if sent /// @return true
/// ///
bool Power(AVRPower_T cmd); bool Power(AVRPower_T cmd);
@@ -67,7 +66,31 @@ public:
avrMute, avrMute,
avrUnMute, avrUnMute,
} AVRMute_T; } 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: private:
uint32_t sentAtTime_ms; uint32_t sentAtTime_ms;
@@ -79,14 +102,183 @@ private:
stRetryInitializing, stRetryInitializing,
stReady, stReady,
stAwaitingResponse, stAwaitingResponse,
stMaxStates
} AVRState_T; } AVRState_T;
AVRState_T state = stPoweringUp; AVRState_T state = stPoweringUp;
AVRState_T oldState = stMaxStates;
AVRState_T GetState() { AVRState_T GetState() {
return state; 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; // Dont 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; int readyTries;
#define RETRY_INTERVAL_ms 500 #define RETRY_INTERVAL_ms 500
#define MAXTRIES 5 #define MAXTRIES 5
@@ -100,12 +292,22 @@ private:
SerialQueue_T serialQueue[SERIALQUEUESIZE]; SerialQueue_T serialQueue[SERIALQUEUESIZE];
int serialQueueCount = 0; 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); 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(); void FreeMemory();
}; };