#include <memory.h>
#include <malloc.h>
#include <string.h>
#include "AVRDriver.h"

#define LONGESTTEXT 160

//   SendToRS232  (SendCallBack)
// <------------------------------------------------------+<---------+
//                                                        A          A
//   Notifications    (NotifyCallBack)                    |          |
// <------------------------------------------------+	  |		     |
//                                                  A	  |		     |
//                +----------------------+          |	  |		     |
// -------------->|   ::AVRDriver        |          |	  |		     |
//                |    (*NotifyCallBack) |          |	  |		     |
//                |    (*SendCallBack)   |          |	  |		     |
//                +----------------------+          |	  |		     |
//                                                  |	  |		     |
//                +----------------------+   +-----------------+     |
//  ------------->|   Tick               |-->|                 |     |
//                |                      |   |                 |     |
//                +----------------------+   |  internal       |     |
//                                           |  logic          |     |
//  Rx RS-232 msg +----------------------+   |                 |     |
//  ------------->|   HandleMessage()    |-->|                 |     |
//                |                      |   |                 |     |
//                +----------------------+   |                 |     |
//                                           |                 |     |
//  Cmd to AVR    +----------------------+   |                 |     |
//  ------------->|   AVRCommand(subsys, |-->|                 |     |
//                |      func,cmd,arg)   |   |                 |     |
//                +----------------------+   +-----------------+     |
//																     |
//                +----------------------+   |                 |     |
//  ------------->|   SendOSDMessage()   |-->|                 |     |
//                |                      |   |                 |     |
//                +----------------------+   +-----------------+     |
//																     |
//                +----------------------+   					     |
//  ------------->| SendMessageToSerial()|-------------------------->+
//                |   Raw Message Send   |   
//                +----------------------+   
//

AVRDriver::AVRDriver(
	NotifyCallBack notifyCB,	///<! used to notify of internal events
	SendCallBack sendCB			///<! used to send to the RS-232 interface
	) {
	NotifyHost = notifyCB;
	RS232Send = sendCB;
	state = stPoweringUp;
}

AVRDriver::~AVRDriver() {
	FreeSendQueue();
}

uint32_t AVRDriver::GetTick() {
	return lastTick_ms;
}

AVRDriver::AVRState_T AVRDriver::Tick(uint32_t now_ms) {
	if (!bFirstTickInitialized) {
		bFirstTickInitialized = true;
		firstTick_ms = now_ms;
	}
	lastTick_ms = now_ms;
	uint32_t elapsed_ms = now_ms - sentAtTime_ms;
	char buf[LONGESTTEXT] = "";

	if (oldState != state) {
		(*NotifyHost)(mtState, NULL, state);
	}
	oldState = state;
	switch (state) {
	default:
	case AVRState_T::stPoweringUp:
		readyResponsReceived = false;
		AVRCommand(sysCommand, fncReady, eOn);
		sentAtTime_ms = now_ms;
		readyTries++;
		state = stAwaitingReadyResponse;
		break;
	case stAwaitingReadyResponse:
		if (readyResponsReceived) {
			state = stReady;
		} else if (elapsed_ms > RETRY_INTERVAL_ms) {
			if (readyTries > MAXTRIES) {
				// fail
				state = stFailed;
			} else {
				state = stPoweringUp;
			}
		}
		break;
	case AVRState_T::stInitializing:
		break;
	case AVRState_T::stRetryInitializing:
		break;
	case AVRState_T::stAwaitingResponse:
		if (commandResponseReceived) {
			state = stReady;
		} else if (elapsed_ms > RETRY_INTERVAL_ms) {
			SendMessageToSerial();
			state = stAwaitingResponse;
		}
		break;
	case AVRState_T::stReady:
		SendMessageToSerial();
		break;
	case AVRState_T::stFailed:
		(*NotifyHost)(mtFailed, "State = Failed", 0);
		break;
	}
	return state;
}


typedef struct {
	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
} MessageHandler_T;

// 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 MessageHandler[] = {
	//
	// Configuration Map for Response Messages
	// 
	//   +--------------------------- rCmd
	//   |    +----------------------- DT Block Offset
	//   |    |  +-------------------- Number of Bytes to transfer into the DT Block
	//   |    |  | 
	//   |    |  |  
	//   |    |  | 
	//   |    |  | 
	//   |    |  | 
	{ 0x00,   7, 1 },
	{ 0x01,   0, 0 },
	{ 0x10,  31, 1 },
	{ 0x11,  32, 1 },
	{ 0x12,  33, 1 },
	{ 0x13,  34, 1 },
	{ 0x14,  35, 1 },
	{ 0x15,  38, 1 },
	{ 0x16,  43, 1 },
	{ 0x20,   8, 0 },
	{ 0x21,   9, 1 },
	{ 0x22,  11, 1 },
	{ 0x23,  12, 1 },
	{ 0x24,  13, 1 },
	{ 0x25,  14, 1 },
	{ 0x26,  15, 2 },
	{ 0x27,  17, 2 },
	{ 0x28,  19, 2 },
	{ 0x29,  25, 1 },
	{ 0x2A,  26, 1 },
	{ 0x2B,  23, 1 },
	{ 0x2C,  24, 1 },
	{ 0x2D,  22, 1 },
	{ 0x2E,  29, 1 },
	{ 0x2F,  30, 1 },
	{ 0x30,   0, 0 },
	{ 0x31,   0, 0 },
	{ 0x32,   0, 0 },
	{ 0x33,   0, 0 },
	{ 0x34,  36, 1 },
	{ 0x35,  37, 1 },
	{ 0x36,  39, 1 },
	{ 0x37,   0, 0 },
	{ 0x38,   0, 0 },
	{ 0x39,   0, 0 },
	{ 0x3A,  42, 1 },
	{ 0x3B,  44, 1 },
	{ 0x3C,  45, 1 },
	{ 0x3D, 104, 0 },
	{ 0x3E,  46, 1 },
	{ 0x3F,  47, 1 },
				   
	{ 0x40,  48, 2 },
	{ 0x41,  50, 2 },
	{ 0x42,  52, 2 },
	{ 0x43,  54, 2 },
	{ 0x44,  56, 2 },
	{ 0x45,  58, 2 },
	{ 0x46,  60, 2 },
	{ 0x47,  62, 2 },
	{ 0x48,  64, 2 },
	{ 0x49,  66, 2 },
	{ 0x4A,   0, 0 },
				   
	{ 0x50,   0, 0 },
	{ 0x51,  74, 2 },
	{ 0x52,  76, 2 },
	{ 0x53,  78, 2 },
	{ 0x54,   0, 0 },
	{ 0x55,   0, 0 },
				   
	{ 0x60,  84, 1 },
	{ 0x61,  85, 1 },
	{ 0x62,  87, 2 },
	{ 0x63,  89, 1 },
	{ 0x64,  91, 1 },
	{ 0x65,  92, 1 },
	{ 0x66,  93, 0 },
	{ 0x67,   0, 0 },
	{ 0x68,  95, 1 },
	{ 0x69,  90, 1 },
	{ 0x6A, 136, 1 },
	{ 0x6B,   0, 0 },
	{ 0x70,  96, 1 },
	{ 0x71,  97, 1 },
	{ 0x72,  98, 1 },
	{ 0x73,  99, 1 },
	{ 0x74, 100, 1 },
	{ 0x75, 101, 1 },
	{ 0x76, 134, 1 },
				   
	{ 0x78, 102, 1 },
	{ 0x79, 103, 1 },
	{ 0x7A, 133, 1 },
	{ 0x7B,   0, 0 },
	{ 0x7E, 135, 1 },
				   
	{ 0x80, 105, 1 },
	{ 0x81,   0, 0 },
	{ 0x82,  27, 1 },
				   
	{ 0x90,   0, 0 },
	{ 0x91,   0, 0 },
	{ 0x92,   0, 0 },
	{ 0x93,   0, 0 },
	{ 0x94,   0, 0 },
	{ 0x95,   0, 0 },
	{ 0x96,   0, 0 },
	{ 0x97,   0, 0 },
	{ 0x98,   0, 0 },
	{ 0x99,   0, 0 },
	{ 0x9A,   0, 0 },
				   
	{ 0xA1,   0, 0 },
};


uint8_t AVRDriver::ProcessResponse(const uint8_t *buffer, uint16_t len) {
	const uint8_t *p = buffer;
	uint8_t offsetChanged = 0;
	(void)len;
	//char buf[LONGESTTEXT];


	//uint8_t type = (uint8_t)Hex2Dec(p + 1, 1);
	//uint8_t guard = (uint8_t)Hex2Dec(p + 2, 1);
	uint8_t rcmd = (uint8_t)Hex2Dec(p + 3, 2);
	//uint8_t rdat = (uint8_t)Hex2Dec(p + 5, 2);

	bool found = false;
	for (int i = 0; i < sizeof(MessageHandler) / sizeof(MessageHandler[0]); i++) {
		if (MessageHandler[i].rCmd == rcmd) {
			found = true;
			if (MessageHandler[i].numToTransfer == 1) {
				memcpy(&avrStatus.config.DT0 + MessageHandler[i].configOffset, p + 6, 1);
			}
			if (MessageHandler[i].numToTransfer == 2) {
				memcpy(&avrStatus.config.DT0 + MessageHandler[i].configOffset, p + 5, 2);
			}
			offsetChanged = MessageHandler[i].configOffset;
			break;	// no need to scan more
		}
	}
	//if (!found && NotifyHost) {
	//	sprintf_s(buf, LONGESTTEXT, "***** type: %X, guard: %X, cmd: %02X, data: %02X", type, guard, rcmd, rdat);
	//	(*NotifyHost)(mtInfo, buf, (uint32_t)strlen(buf));
	//}
	return offsetChanged;
}

/// 
/// Given a response string, typically of the form:
///		[02] .... [03]				// Command Responses from the AVR
///		[11] .... [03]				// Commands to 
///		[12] .... [03]
/// 	[14] ............ [03]
///
/// @param buffer contains the message
/// @param len of the message
/// @return 0 if none, or the index into the main status array that was updated
/// 
uint8_t AVRDriver::HandleMessage(const uint8_t *buffer, uint16_t len) {
	uint8_t offsetChanged = 0;

	(*NotifyHost)(mtRcvdMsg, buffer, len);
	switch (state) {
	case stAwaitingReadyResponse:
		switch (buffer[0]) {
		case 0x02:	// STX <msg> ETX
			commandResponseReceived = true;
			(*NotifyHost)(mtStatusMsg, buffer, len);
			break;
		case 0x11:	// DC1 <msg> ETX
			// AVR does not send any DC1 messages, these are for commands to the AVR
			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;
					offsetChanged = 0xFF;	// @TODO Bad hack for 'everything' changed
				} 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;
					offsetChanged = 0xFF;	// @TODO Bad hack for 'everything' changed
				} else {
					(*NotifyHost)(mtErrRxLength, NULL, len);
				}
				readyResponsReceived = true;
			}
			break;
		case 0x14:	// DC4 <extended response> ETX
			// DecodeExtendedResponse(buffer, len);		// once I figure out what is in here...
			(*NotifyHost)(mtExtendedResp, buffer, len);
			break;
		default:
			break;
		}
		break;
	case stAwaitingResponse:
		offsetChanged = ProcessResponse(buffer, len);
		commandResponseReceived = true;
		(*NotifyHost)(mtParamUpdated, NULL, offsetChanged);
		break;
	case stReady:
		switch (buffer[0]) {
		case 0x02:	// STX <msg> ETX
			offsetChanged = ProcessResponse(buffer, len);
			commandResponseReceived = true;
			(*NotifyHost)(mtParamUpdated, NULL, offsetChanged);
			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;
					offsetChanged = 0xFF;	// @TODO Bad hack for 'everything' changed
				} 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;
					offsetChanged = 0xFF;	// @TODO Bad hack for 'everything' changed
				} else {
					(*NotifyHost)(mtErrRxLength, NULL, 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;
	}
	return offsetChanged;
}


bool AVRDriver::AVRSendOSDMessage(const char *pMsg) {
	const char valid[] = " !#%&()*+,-.0123456789:<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz";
	char buf[17] = { 0 };
	if (strlen(pMsg) <= 16) {
		for (size_t i = 0; i < 16; i++) {
			if (*pMsg == '\0') {
				buf[i] = ' ';
			} else if (strchr(valid, *pMsg)) {
				buf[i] = *pMsg++;
			} else {
				return false;	// Invalid character
			}
		}
		SendMessageToSerial("\x02" "21000" "\x03", 7);	// Start the OSD message
		char msg[8];
		for (int i = 0; i < 16; i += 4) {
			strcpy_s(msg, sizeof(msg), "\x02");			// Each chunk
			strcat_s(msg, sizeof(msg), "3");
			strncat_s(msg, sizeof(msg), &buf[i], 4);
			strcat_s(msg, sizeof(msg), "\x03");
			SendMessageToSerial(msg, 7);
		}
		return true;
	} else {
		return false;
	}
}



bool AVRDriver::SendMessageToSerial(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) {
			(*NotifyHost)(mtXmtdMsg, msg, 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;
				freshData = true;
			}
		}
	}
	if (serialQueueCount) {
		if ((*RS232Send)((const uint8_t *)serialQueue[0].messageToSend, serialQueue[0].len)) {
			--serialQueueCount;
			free(serialQueue[0].messageToSend);
			serialQueue[0].messageToSend = NULL;
			for (int i = 0; i < serialQueueCount; i++) {
				serialQueue[i] = serialQueue[i + 1];
			}
			retVal = true;
		}
		state = stAwaitingResponse;
	}
	return retVal;
}


MessageTable_T MessageTable[] = {
	// System Commands
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncReady, AVRArg_T::eOn, "\x11" "000" "\x03", 5 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncReportEnable, AVRArg_T::eOn, "\x02" "20000" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncReportEnable, AVRArg_T::eOff, "\x02" "20001" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncReportDelay, AVRArg_T::e0ms, "\x02" "20100" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncReportDelay, AVRArg_T::e50ms, "\x02" "20101" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncReportDelay, AVRArg_T::e100ms, "\x02" "20102" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncReportDelay, AVRArg_T::e150ms, "\x02" "20103" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncReportDelay, AVRArg_T::e200ms, "\x02" "20104" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncReportDelay, AVRArg_T::e250ms, "\x02" "20105" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncReportDelay, AVRArg_T::e300ms, "\x02" "20106" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncReportDelay, AVRArg_T::e350ms, "\x02" "20107" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncReportDelay, AVRArg_T::e400ms, "\x02" "20108" "\x03", 7 },

	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncRequest, AVRArg_T::eTuningFreq,     "\x02" "22000" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncRequest, AVRArg_T::eMainVolDB,      "\x02" "22001" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncRequest, AVRArg_T::eZone2VolDB,     "\x02" "22002" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncRequest, AVRArg_T::eInputName,      "\x02" "22003" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncRequest, AVRArg_T::eZone2InputName, "\x02" "22004" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncRequest, AVRArg_T::eZoneXVolDB,     "\x02" "22005" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncRequest, AVRArg_T::eZoneXInputName, "\x02" "22006" "\x03", 7 },

	// System Commands with variable data
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eMasterVol, "\x02" "230xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eZone2Vol,  "\x02" "231xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eMainLRBal,  "\x02" "232xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eMainLevel,  "\x02" "233xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eZone3Vol,  "\x02" "234xx" "\x03", 7 },

	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eMainLevelR,   "\x02" "240xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eMainLevelL,   "\x02" "241xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eCenterLevel,  "\x02" "242xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eRearR,        "\x02" "243xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eRearL,        "\x02" "244xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eFrontR,       "\x02" "245xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eFrontL,       "\x02" "246xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eSurBackR,     "\x02" "247xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eSurBackL,     "\x02" "248xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eSwfr1,        "\x02" "249xx" "\x03", 7 },
	{ AVRSubsystem_T::sysCommand, AVRFunction_T::fncSetValue, AVRArg_T::eSwfr2,        "\x02" "24Axx" "\x03", 7 },

	// Operation Commands
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncPower, AVRArg_T::eOn, "\x02" "07A1D" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncPower, AVRArg_T::eOff, "\x02" "07A1E" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncVolume, AVRArg_T::eUp, "\x02" "07A1A" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncVolume, AVRArg_T::eDown, "\x02" "07A1B" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncMute, AVRArg_T::eOn, "\x02" "07EA2" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncMute, AVRArg_T::eOff, "\x02" "07EA3" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncOSD, AVRArg_T::eOSDOff, "\x02" "07EB0" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncOSD, AVRArg_T::eOSDShort, "\x02" "07EB1" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncOSD, AVRArg_T::eOSDFull, "\x02" "07EB2" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncNightModeOnOff, AVRArg_T::eOn, "\x02" "07E9B" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncNightModeOnOff, AVRArg_T::eOff, "\x02" "07E9C" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncSleep, AVRArg_T::eSleepOff, "\x02" "07EB3" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncSleep, AVRArg_T::eSleep120, "\x02" "07EB4" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncSleep, AVRArg_T::eSleep90, "\x02" "07EB5" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncSleep, AVRArg_T::eSleep60, "\x02" "07EB6" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncSleep, AVRArg_T::eSleep30, "\x02" "07EB7" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncSpeakerAOnOff, AVRArg_T::eOn, "\x02" "07EAB" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncSpeakerAOnOff, AVRArg_T::eOff, "\x02" "07EAC" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncSpeakerBOnOff, AVRArg_T::eOn, "\x02" "07EAD" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncSpeakerBOnOff, AVRArg_T::eOff, "\x02" "07EAE" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncDC1TrigControl, AVRArg_T::eZone1, "\x02" "07E32" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncDC1TrigControl, AVRArg_T::eZone2, "\x02" "07E33" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncDC1TrigControl, AVRArg_T::eZone3, "\x02" "07E31" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncDualMono, AVRArg_T::eDualMain, "\x02" "07E93" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncDualMono, AVRArg_T::eDualSub, "\x02" "07E94" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncDualMono, AVRArg_T::eDualAll, "\x02" "07E95" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncDC1TrigControl, AVRArg_T::eZone1, "\x02" "07E96" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncDC1TrigControl, AVRArg_T::eZone2, "\x02" "07E97" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncDC1TrigControl, AVRArg_T::eZone3, "\x02" "07E9F" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncDC1TrigControl, AVRArg_T::eZoneOR, "\x02" "07E98" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncSpeakerBZone, AVRArg_T::eZone1, "\x02" "07E28" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncSpeakerBZone, AVRArg_T::eZone2, "\x02" "07E29" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncZone2SpeakerOnOff, AVRArg_T::eOn, "\x02" "07E99" "\x03", 7 },
	{ AVRSubsystem_T::subMain, AVRFunction_T::fncZone2SpeakerOnOff, AVRArg_T::eOff, "\x02" "07E9A" "\x03", 7 },

	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioBand, AVRArg_T::eFM, "\x02" "07EBC" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioBand, AVRArg_T::eAM, "\x02" "07EBD" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioTune, AVRArg_T::eUp, "\x02" "07EBE" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioTune, AVRArg_T::eDown, "\x02" "07EBF" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetPage, AVRArg_T::eA, "\x02" "07AE0" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetPage, AVRArg_T::eB, "\x02" "07AE1" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetPage, AVRArg_T::eC, "\x02" "07AE2" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetPage, AVRArg_T::eD, "\x02" "07AE3" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetPage, AVRArg_T::eE, "\x02" "07AE4" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetNumber, AVRArg_T::e1, "\x02" "07AE5" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetNumber, AVRArg_T::e2, "\x02" "07AE6" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetNumber, AVRArg_T::e3, "\x02" "07AE7" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetNumber, AVRArg_T::e4, "\x02" "07AE8" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetNumber, AVRArg_T::e5, "\x02" "07AE9" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetNumber, AVRArg_T::e6, "\x02" "07AEA" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetNumber, AVRArg_T::e7, "\x02" "07AEB" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetNumber, AVRArg_T::e8, "\x02" "07AEC" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetMemory, AVRArg_T::eA, "\x02" "07E2B" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetMemory, AVRArg_T::eB, "\x02" "07E2C" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetMemory, AVRArg_T::eC, "\x02" "07E2D" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetMemory, AVRArg_T::eD, "\x02" "07E2E" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetMemory, AVRArg_T::eE, "\x02" "07E2F" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetMemory, AVRArg_T::eF, "\x02" "07E20" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetRecall, AVRArg_T::eA, "\x02" "07E35" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetRecall, AVRArg_T::eB, "\x02" "07E36" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetRecall, AVRArg_T::eC, "\x02" "07E37" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetRecall, AVRArg_T::eD, "\x02" "07E38" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetRecall, AVRArg_T::eE, "\x02" "07E39" "\x03", 7 },
	{ AVRSubsystem_T::subRadio, AVRFunction_T::fncRadioPresetRecall, AVRArg_T::eF, "\x02" "07E3A" "\x03", 7 },

	{ AVRSubsystem_T::subAudio, AVRFunction_T::fnc6ChInput, AVRArg_T::eOn, "\x02" "07EA4" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fnc6ChInput, AVRArg_T::eOff, "\x02" "07EA5" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncInputMode, AVRArg_T::eInpAuto, "\x02" "07EA6" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncInputMode, AVRArg_T::eDD_RF, "\x02" "07EA7" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncInputMode, AVRArg_T::eDTS, "\x02" "07EA8" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncInputMode, AVRArg_T::eDigital, "\x02" "07EA9" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncInputMode, AVRArg_T::eAnalog, "\x02" "07EAA" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncInputMode, AVRArg_T::eAAC, "\x02" "07E3B" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncEx_EsOnOff, AVRArg_T::eOnMatrix, "\x02" "07EB8" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncEx_EsOnOff, AVRArg_T::eESESOff, "\x02" "07EB9" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncEx_EsOnOff, AVRArg_T::eAuto, "\x02" "07E7C" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncEx_EsOnOff, AVRArg_T::eDiscrete, "\x02" "07E7D" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncEffect, AVRArg_T::eEffectOn, "\x02" "07E27" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncEffect, AVRArg_T::eStereo, "\x02" "07EE0" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Hall_A, "\x02" "07EE1" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Hall_B, "\x02" "07EE2" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Hall_C, "\x02" "07EE3" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Hall_USA, "\x02" "07EE4" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Hall_E, "\x02" "07EE5" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Live_Concert, "\x02" "07EE6" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Tokyo, "\x02" "07EE7" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Freiburg, "\x02" "07EE8" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Royaumont, "\x02" "07EE9" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Village_Gate, "\x02" "07EEA" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Village_Vanguard, "\x02" "07EEB" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::The_Bottom_Line, "\x02" "07EEC" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::The_Roxy_Theater, "\x02" "07EED" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Warehouse_Loft, "\x02" "07EEE" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Arena, "\x02" "07EEF" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Disco, "\x02" "07EF0" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Party, "\x02" "07EF1" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Game, "\x02" "07EF2" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Stereo_6_8Ch, "\x02" "07EFF" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Pop_Rock, "\x02" "07EF3" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::DJ, "\x02" "07EF4" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Opera, "\x02" "07EF5" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Pavillion, "\x02" "07EF6" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Mono_Movie, "\x02" "07EF7" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Variety_Sports, "\x02" "07EF8" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Spectacre, "\x02" "07EF9" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Sci_Fi, "\x02" "07EFA" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Adventure, "\x02" "07EFB" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::General, "\x02" "07EFC" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Normal, "\x02" "07EFD" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Enhanced, "\x02" "07EFE" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::PLII_Movie, "\x02" "07E67" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::PLII_Music, "\x02" "07E68" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Neo_6_Movie, "\x02" "07E69" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Neo_6_Music, "\x02" "07E6A" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Direct_2Ch, "\x02" "07EC1" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::Stereo_2Ch, "\x02" "07EC0" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::THX_Ultra_PL, "\x02" "07EC2" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::THX_Music, "\x02" "07EC3" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::THX_Ultra_PL2, "\x02" "07EC7" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncDSPSoundScape, AVRArg_T::THX_Ultra_NEO6, "\x02" "07EC8" "\x03", 7 },

	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncVolumeMemory, AVRArg_T::eA, "\x02" "07E6B" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncVolumeMemory, AVRArg_T::eB, "\x02" "07E6C" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncVolumeMemory, AVRArg_T::eC, "\x02" "07E6D" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncVolumeMemory, AVRArg_T::eD, "\x02" "07E6E" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncVolumeMemory, AVRArg_T::eE, "\x02" "07E6F" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncVolumeMemory, AVRArg_T::eF, "\x02" "07E60" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncVolumeRecall, AVRArg_T::eA, "\x02" "07E75" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncVolumeRecall, AVRArg_T::eB, "\x02" "07E76" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncVolumeRecall, AVRArg_T::eC, "\x02" "07E77" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncVolumeRecall, AVRArg_T::eD, "\x02" "07E78" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncVolumeRecall, AVRArg_T::eE, "\x02" "07E79" "\x03", 7 },
	{ AVRSubsystem_T::subAudio, AVRFunction_T::fncVolumeRecall, AVRArg_T::eF, "\x02" "07E7A" "\x03", 7 },

	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncPower, AVRArg_T::eOn, "\x02" "07E7E" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncPower, AVRArg_T::eOff, "\x02" "07E7F" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::ePhono, "\x02" "07A14" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::eCD, "\x02" "07A15" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::eTuner, "\x02" "07A16" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::eCDR, "\x02" "07A19" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::eMD_Tape, "\x02" "07AC9" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::eDVD, "\x02" "07AC1" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::eDTV, "\x02" "07A54" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::eCable, "\x02" "07AC0" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::eSat, "\x02" "07ACA" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::eVCR1, "\x02" "07A0F" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::eVCR2_DVR, "\x02" "07A13" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::eVCR3, "\x02" "07AC8" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncInput, AVRArg_T::eV_Aux, "\x02" "07A55" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncDC1OnOff, AVRArg_T::eOn, "\x02" "07E73" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncDC1OnOff, AVRArg_T::eOff, "\x02" "07E74" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncDC2OnOff, AVRArg_T::eOn, "\x02" "07E3E" "\x03", 7 },
	{ AVRSubsystem_T::subZone1, AVRFunction_T::fncDC2OnOff, AVRArg_T::eOff, "\x02" "07E3F" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolume, AVRArg_T::eUp, "\x02" "07ADA" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolume, AVRArg_T::eDown, "\x02" "07ADB" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncMute, AVRArg_T::eOn, "\x02" "07EA0" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncMute, AVRArg_T::eOff, "\x02" "07EA1" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::ePhono, "\x02" "07AD0" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::eCD, "\x02" "07AD1" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::eTuner, "\x02" "07AD2" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::eCDR, "\x02" "07AD4" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::eMD_Tape, "\x02" "07ACF" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::eDVD, "\x02" "07ACD" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::eDTV, "\x02" "07AD9" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::eCable, "\x02" "07ACC" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::eSat, "\x02" "07ACB" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::eVCR1, "\x02" "07AD6" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::eVCR2_DVR, "\x02" "07AD7" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::eVCR3, "\x02" "07ACE" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncInput, AVRArg_T::eV_Aux, "\x02" "07AD8" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncPower, AVRArg_T::eOn, "\x02" "07EBA" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncPower, AVRArg_T::eOff, "\x02" "07EBB" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolumeMemory, AVRArg_T::eA, "\x02" "07E87" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolumeMemory, AVRArg_T::eB, "\x02" "07E88" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolumeMemory, AVRArg_T::eC, "\x02" "07E89" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolumeMemory, AVRArg_T::eD, "\x02" "07E8A" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolumeMemory, AVRArg_T::eE, "\x02" "07E8B" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolumeMemory, AVRArg_T::eF, "\x02" "07E8C" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolumeRecall, AVRArg_T::eA, "\x02" "07E8D" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolumeRecall, AVRArg_T::eB, "\x02" "07E8E" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolumeRecall, AVRArg_T::eC, "\x02" "07E8F" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolumeRecall, AVRArg_T::eD, "\x02" "07E90" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolumeRecall, AVRArg_T::eE, "\x02" "07E91" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncVolumeRecall, AVRArg_T::eF, "\x02" "07E92" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncDC1OnOff, AVRArg_T::eOn, "\x02" "07E71" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncDC1OnOff, AVRArg_T::eOff, "\x02" "07E72" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncDC2OnOff, AVRArg_T::eOn, "\x02" "07E3C" "\x03", 7 },
	{ AVRSubsystem_T::subZone2, AVRFunction_T::fncDC2OnOff, AVRArg_T::eOff, "\x02" "07E3D" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncPower, AVRArg_T::eOn, "\x02" "07AED" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncPower, AVRArg_T::eStandby, "\x02" "07AEE" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncMute, AVRArg_T::eOn, "\x02" "07E26" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncMute, AVRArg_T::eOff, "\x02" "07E66" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolume, AVRArg_T::eUp, "\x02" "07AFD" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolume, AVRArg_T::eDown, "\x02" "07AFE" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::ePhono, "\x02" "07AF1" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::eCD, "\x02" "07AF2" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::eTuner, "\x02" "07AF3" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::eCDR, "\x02" "07AF5" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::eMD_Tape, "\x02" "07AF4" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::eDVD, "\x02" "07AFC" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::eDTV, "\x02" "07AF6" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::eCable, "\x02" "07AF7" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::eSat, "\x02" "07AF8" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::eVCR1, "\x02" "07AF9" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::eVCR2_DVR, "\x02" "07AFA" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::eVCR3, "\x02" "07AFB" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncInput, AVRArg_T::eV_Aux, "\x02" "07AF0" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolumeMemory, AVRArg_T::eA, "\x02" "07E20" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolumeMemory, AVRArg_T::eB, "\x02" "07E21" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolumeMemory, AVRArg_T::eC, "\x02" "07E22" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolumeMemory, AVRArg_T::eD, "\x02" "07E23" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolumeMemory, AVRArg_T::eE, "\x02" "07E24" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolumeMemory, AVRArg_T::eF, "\x02" "07E25" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolumeRecall, AVRArg_T::eA, "\x02" "07E60" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolumeRecall, AVRArg_T::eB, "\x02" "07E61" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolumeRecall, AVRArg_T::eC, "\x02" "07E62" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolumeRecall, AVRArg_T::eD, "\x02" "07E63" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolumeRecall, AVRArg_T::eE, "\x02" "07E64" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncVolumeRecall, AVRArg_T::eF, "\x02" "07E65" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncDC1OnOff, AVRArg_T::eOn, "\x02" "07E83" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncDC1OnOff, AVRArg_T::eOff, "\x02" "07E84" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncDC2OnOff, AVRArg_T::eOn, "\x02" "07E85" "\x03", 7 },
	{ AVRSubsystem_T::subZone3, AVRFunction_T::fncDC2OnOff, AVRArg_T::eOff, "\x02" "07E86" "\x03", 7 },
};

uint16_t AVRDriver::GetMessageTableSize() {
	return sizeof(MessageTable) / sizeof(MessageTable_T);
}

MessageTable_T *AVRDriver::GetMessageTableRecord(uint16_t i) {
	if (i < sizeof(MessageTable) / sizeof(MessageTable_T)) {
		return &MessageTable[i];
	} else {
		return NULL;
	}
}

bool AVRDriver::AVRCommand(AVRSubsystem_T subsystem,
	AVRFunction_T function,
	AVRArg_T arg,
	uint8_t variableData) {
	bool found = false;
	for (int i = 0; i < sizeof(MessageTable) / sizeof(MessageTable_T); i++) {
		if (MessageTable[i].subsystem == subsystem && MessageTable[i].function == function and MessageTable[i].arg == arg) {
			found = true;
			const char *p = strchr(MessageTable[i].Message, 'x');
			if (p) {
				char hexBuf[3] = "";
				char *bigBuf = (char *)malloc(MessageTable[i].MessageLen + 1);
				if (bigBuf) {
					memcpy(bigBuf, MessageTable[i].Message, MessageTable[i].MessageLen);
					char *pWr = (char *)strchr(bigBuf, 'x');
					Inject2ASCIIHexCharsAt(pWr, variableData);
					SendMessageToSerial(bigBuf, MessageTable[i].MessageLen);
					free(bigBuf);
				} else {
					(*NotifyHost)(mtErrMalloc, NULL, MessageTable[i].MessageLen + 1);
				}
			} else {
				SendMessageToSerial(MessageTable[i].Message, MessageTable[i].MessageLen);
			}
			break;
		}
	}
	if (!found) {
		(*NotifyHost)(mtErrNotFound, NULL, (subsystem << 16) | (function << 8) | (arg));
	}
	return true;
}

void AVRDriver::Inject2ASCIIHexCharsAt(char *p, uint8_t val) {
	const char *hex = "0123456789ABCDEF";
	*p++ = hex[(val >> 4)];
	*p = hex[(val & 0x0F)];
}

void AVRDriver::FreeSendQueue() {
	for (int i = 0; i < serialQueueCount; i++) {
		if (serialQueue[0].messageToSend) {
			free(serialQueue[0].messageToSend);
		}
	}
}


bool AVRDriver::CheckTheChecksum(const uint8_t *szBuffer, uint32_t num) {
	uint8_t sum = 0;
	for (uint16_t i = 1; i < num - 3; i++) {
		sum += szBuffer[i];
	}
	uint8_t cksum = (uint8_t)Hex2Dec(&szBuffer[num - 3], 2);
	return (sum == cksum);
}

// Hex2Dec
//
//	All responses are pretty much Hex-ASCII, so
//	we sometimes want to convert it to decimal
//	This takes a buffer and converts the specified
//	number of characters.
//
uint16_t AVRDriver::Hex2Dec(const uint8_t *p, int dig) {
	uint16_t x = 0;
	while (dig--) {
		if (*p >= '0' && *p <= '9')
			x = x * 16 + *p - '0';
		else if (*p >= 'a' && *p <= 'f')
			x = x * 16 + 0x0a + *p - 'a';
		else if (*p >= 'A' && *p <= 'F')
			x = x * 16 + 0x0a + *p - 'A';
		p++;
	}
	return x;
}

