Add support for .ini file,
Add support for extended messages (advanced protocol), Add handy command lines for Power, Volume in db, and Mute.
This commit is contained in:
@@ -210,6 +210,8 @@ typedef enum {
|
||||
|
||||
constexpr auto MAXTEXTLEN = 512;
|
||||
char progname[MAXTEXTLEN];
|
||||
char ininame[MAXTEXTLEN] = "";
|
||||
|
||||
|
||||
int AttachToSerialPort();
|
||||
int DetachSerialPort();
|
||||
@@ -261,7 +263,9 @@ unsigned long Hex2Dec(uint8_t *p, int dig);
|
||||
|
||||
//void ShowAllStatusInfo();
|
||||
void GetAndSendCustomMessage();
|
||||
void GetAndSendExtendedMessage();
|
||||
void GetAndSendOSDMessage();
|
||||
bool SendExtendedMessage(char *buf);
|
||||
|
||||
void EmitRuntimeHelp();
|
||||
|
||||
@@ -383,7 +387,8 @@ const UserCmd_T UserCommands[] = {
|
||||
//{ 'J', "Dual Mono - Main", {"\x02" "07E93" "\x03", 7} },
|
||||
//{ 'K', "Dual Mono - Sub", {"\x02" "07E94" "\x03", 7} },
|
||||
//{ 'L', "Dual Mono - All", {"\x02" "07E95" "\x03", 7} },
|
||||
{ ':', "Custom Message" },
|
||||
{ ':', "Send Command Message" },
|
||||
{ '=', "Send Extended Message" },
|
||||
{ '/', "Show All" },
|
||||
{ '?', "Help on runtime commands" },
|
||||
{ 'S', "Set RTS" },
|
||||
@@ -413,6 +418,9 @@ void ProcessKeyboard(void) {
|
||||
case ':':
|
||||
GetAndSendCustomMessage();
|
||||
break;
|
||||
case '=':
|
||||
GetAndSendExtendedMessage();
|
||||
break;
|
||||
case '?':
|
||||
EmitRuntimeHelp();
|
||||
break;
|
||||
@@ -557,6 +565,35 @@ void GetAndSendCustomMessage() {
|
||||
}
|
||||
}
|
||||
|
||||
bool SendExtendedMessage(char * buf) {
|
||||
HexUppercase(buf); // Gets nulled if there are non-Hex
|
||||
if (strlen(buf)) {
|
||||
char msg[75]; // Hope it is large enough
|
||||
const char * prefix = "\x14" "20";
|
||||
unsigned len = (unsigned)strlen(buf);
|
||||
sprintf_s(msg, 70, "%s%02X%s", prefix, len, buf);
|
||||
char *p = &msg[1];
|
||||
uint8_t checksum = 0;
|
||||
do {
|
||||
checksum += *p++;
|
||||
} while (*p && (p < msg + 70)); // 70 < 75 to generously reserve space for SUM0,SUM1,ETX,\0
|
||||
sprintf_s(p, 75 - strlen(msg), "%02X\x03", checksum);
|
||||
Console_ScrollBottomRegion();
|
||||
avr->ProcessSerialQueue(msg, (uint16_t)strlen(msg));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GetAndSendExtendedMessage() {
|
||||
char buf[60];
|
||||
Console_ScrollBottomRegion();
|
||||
Console_ScrollBottomRegion();
|
||||
Console_WriteAt(0, -2, "Enter DT0...DTX Hex string to send: ");
|
||||
gets_s(buf, sizeof(buf) - 1);
|
||||
SendExtendedMessage(buf);
|
||||
}
|
||||
|
||||
|
||||
void GetProgName(char *name) {
|
||||
char *p = strrchr(name, '\\');
|
||||
@@ -570,6 +607,8 @@ void GetProgName(char *name) {
|
||||
if (p && 0 == stricmp(p, ".exe")) {
|
||||
*p = '\0';
|
||||
}
|
||||
strcpy_s(ininame, MAXTEXTLEN, progname);
|
||||
strcat_s(ininame, MAXTEXTLEN, ".ini");
|
||||
}
|
||||
|
||||
|
||||
@@ -602,35 +641,88 @@ void InformationUpdate(AVRInterface::AVRMessageType_T type, const char *msg) {
|
||||
}
|
||||
|
||||
void EmitCommandLineHelp() {
|
||||
printf("%s [Options] by Smartware Computing\n", progname);
|
||||
const char * by = "by Smartware Computing";
|
||||
printf("%s [Options] %80s\n", progname, by);
|
||||
printf("\n");
|
||||
printf(" This program can control a Yamaha AVR RX-2400 receiver via the RS-232 port.\n");
|
||||
printf(" It may work for other similar models, and the API docs used to build this\n");
|
||||
printf(" showed commands not in the RX-2400, but they were implemented herein.\n");
|
||||
printf(" This program can control a Yamaha AVR RX-V2400 receiver via the RS-232 port.\n");
|
||||
printf(" It may work for other similar models.\n");
|
||||
printf("\n");
|
||||
printf(" Options:\n");
|
||||
printf(" -SerialPort=X[,yyyy] Set to Com port X to baud rate yyyy.\n");
|
||||
printf(" Defaults baud is %d\n", avrBaud);
|
||||
printf(" -Command=S,F,O[,V] Execute a command and exit (based on the numeric values):\n");
|
||||
printf(" S - Subsystem,\n");
|
||||
printf(" F - Function,\n");
|
||||
printf(" O - Operation,\n");
|
||||
printf(" V - Value used by only certain command.\n");
|
||||
printf(" Use the -ExportInfo command to see the Command List.\n");
|
||||
printf(" NOTE: Program will auto-exit after performing the command,\n");
|
||||
printf(" or after 5 seconds without obvious success.\n");
|
||||
printf(" -Verbose Shows progress during -Command operation.\n");
|
||||
printf(" NOTE: It is always verbose in interactive mode.\n");
|
||||
printf(" -ExportInfo Export AVR Control Parameters and exit.\n");
|
||||
printf(" This software, and/or material is the property of Smartware Computing. All use,\n");
|
||||
printf(" disclosure, and/or reproduction not specifically authorized by Smartware\n");
|
||||
printf(" Computing is prohibited. This program has no warranty or declaration of fitness\n");
|
||||
printf(" for your use, and no claim that it will function as intended. While the author is\n");
|
||||
printf(" using this regularly with an RX-V2400 receiver, it was developed using the full\n");
|
||||
printf(" capability expressed in the Yamaha RS232C Standard document, even though not all\n");
|
||||
printf(" features have been tested and NOT ALL AVRs support all commands.\n");
|
||||
printf("\n");
|
||||
printf(" Example: avr -SerialPort=2 -Command=0,0,0 (Turn Main Power On)\n");
|
||||
printf(" There is no claim that it cannot damage your AVR, and you are accepting the risk!\n");
|
||||
printf("\n");
|
||||
printf(" Reference Documents:\n");
|
||||
printf(" + Yamaha RX-V2400 RS232C Standard - with decoding of most parameters.\n");
|
||||
printf(" + Yamaha RX-V2400 RS232C Extended - raw hex streams are supported.\n");
|
||||
printf("\n");
|
||||
printf(" This program is copyright (c) 2025 by Smartware Computing, all rights reserved.\n");
|
||||
printf("\n");
|
||||
printf(" Author David Smart, Smartware Computing\n");
|
||||
|
||||
printf("\n");
|
||||
printf("Options:\n");
|
||||
printf("\n");
|
||||
printf(" -SerialPort=X[,yyyy] Set to Com port X to baud rate yyyy.\n");
|
||||
printf(" Defaults baud is %d\n", avrBaud);
|
||||
printf(" NOTE: At least for the RX-V2400, 9600,8,N,1 is required.\n");
|
||||
printf(" NOTE: At least for the RX-V2400, the host must assert RTS.\n");
|
||||
printf("\n");
|
||||
printf(" -Command=S,F,O[,V] Execute command and exit (based on the numeric values):\n");
|
||||
printf(" S - Subsystem,\n");
|
||||
printf(" F - Function,\n");
|
||||
printf(" O - Operation,\n");
|
||||
printf(" V - Value used by only certain commands. This value is\n");
|
||||
printf(" entered as a decimal value (like the S,F, and O).\n");
|
||||
printf(" Use the -ExportInfo command to see the Command List.\n");
|
||||
printf(" NOTE: Program will auto-exit after performing the command,\n");
|
||||
printf(" or after about 5 seconds without obvious success.\n");
|
||||
printf("\n");
|
||||
printf(" -Extended=xxxxxxxx... Send Extended Command defined by ASCII hex sequence of DT0...DTx.\n");
|
||||
printf(" The length and checksum will be computed in the overall message.\n");
|
||||
printf(" [DC4][SW][KIND][L0][L1][DT0][DT1]...[DTx][SUM0][SUM1][ETX]\n");
|
||||
printf("\n");
|
||||
printf(" -Verbose Shows progress during -Command operation.\n");
|
||||
printf(" NOTE: %s is always verbose in interactive mode.\n", progname);
|
||||
printf("\n");
|
||||
printf(" -ExportInfo[=S[,F[,O]]] Export AVR Control Parameters and exit, optionally \n");
|
||||
printf(" filtered to a subsystem, function, and operation.\n");
|
||||
printf(" NOTE: The unfiltered list is quite long.\n");
|
||||
printf("\n");
|
||||
printf("Handy Commands: Here's a few commands, made 'simpler' to access.\n");
|
||||
printf("\n");
|
||||
printf(" -Power=On|Off Control Main Power - On or Off\n");
|
||||
printf(" -Zone1Volume=+xx.y Set the zone 1 volume db level in the range -80.0 to +16.5.\n");
|
||||
printf(" -Zone2Volume=+xx.y Set the zone 2 volume db level in the range -80.0 to +16.5.\n");
|
||||
printf(" -Zone3Volume=+xx.y Set the zone 2 volume db level in the range -80.0 to +16.5.\n");
|
||||
printf(" CAUTION: Take care that you don't blow your speakers/ears!\n");
|
||||
printf(" -Mute=On|Off Mute on or Mute off\n");
|
||||
printf("\n");
|
||||
printf("ini File:\n");
|
||||
printf("\n");
|
||||
printf(" %s.ini, if it exists in the same folder as the program, will be read before any command\n", progname);
|
||||
printf(" line parameters are processed. Supported items: \n");
|
||||
printf(" + Either form of the SerialPort command.\n");
|
||||
printf(" + Anything else is silently ignored.\n");
|
||||
printf("\n");
|
||||
printf("Examples:\n");
|
||||
printf("\n");
|
||||
printf(" > avr -ExportInfo=1,0 (See the options for Main Power)\n");
|
||||
printf(" > avr -SerialPort=2 -Command=1,0,0 (Turn Main Power On)\n");
|
||||
printf("\n");
|
||||
printf("Exit Codes:\n");
|
||||
printf("\n");
|
||||
printf(" 0 = Normal exit\n");
|
||||
printf(" 1 = Illegal Option or unrecognized command\n");
|
||||
printf(" 2 = Program Internal Error - Data table failed santity check.\n");
|
||||
printf(" 3 = External Quit (e.g. Windows command to close).\n");
|
||||
printf(" 4 = Something very abnormal happened to cause exit.\n");
|
||||
printf("\n");
|
||||
printf(" Exit Codes:\n");
|
||||
printf(" 0 = Normal exit\n");
|
||||
printf(" 1 = Illegal Option or unrecognized command\n");
|
||||
printf(" 2 = Program Internal Error - Table data failed santity check.\n");
|
||||
printf(" 3 = External Quit (e.g. Windows command to close).\n");
|
||||
printf(" 4 = Something very abnormal happened to cause exit.\n");
|
||||
if (avrOnPort == COM_NO_PORT) {
|
||||
EnumerateComPorts();
|
||||
}
|
||||
@@ -647,6 +739,24 @@ DWORD AppTime() {
|
||||
return timeGetTime() - startTime;
|
||||
}
|
||||
|
||||
void ReadIniFile() {
|
||||
char buf[MAXTEXTLEN] = "";
|
||||
FILE *fp = fopen(ininame, "r");
|
||||
int param1, param2;
|
||||
|
||||
if (fp) {
|
||||
while (!feof(fp)) {
|
||||
fgets(buf, sizeof(buf) - 1, fp);
|
||||
if (1 == sscanf_s(buf, "-SerialPort=%d", ¶m1)) {
|
||||
avrOnPort = param1;
|
||||
} else if (2 == sscanf_s(buf, "-SerialPort=%d,%d", ¶m1, ¶m2)) {
|
||||
avrOnPort = param1;
|
||||
avrBaud = param2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************/
|
||||
/* m a i n ( ) */
|
||||
/******************************************************/
|
||||
@@ -672,6 +782,9 @@ int __cdecl main(int argc, char *argv[]) {
|
||||
short consoleLeft = 15;
|
||||
short consoleTop = 15;
|
||||
int CommandToExecute[4] = { -1, -1, -1, -1 };
|
||||
float db;
|
||||
int parseCount = 0;
|
||||
char *pExtendedMessage = NULL;
|
||||
|
||||
// MessageHandlerSanityCheck(); // If the table is bad, we exit here
|
||||
GetProgName(argv[0]);
|
||||
@@ -680,6 +793,8 @@ int __cdecl main(int argc, char *argv[]) {
|
||||
avr = new AVRInterface(SerialSend);
|
||||
avr->RegisterInformationCallback(InformationUpdate);
|
||||
|
||||
ReadIniFile();
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
int param1, param2;
|
||||
if (1 == sscanf_s(argv[i], "-SerialPort=%d", ¶m1)) {
|
||||
@@ -691,6 +806,8 @@ int __cdecl main(int argc, char *argv[]) {
|
||||
// After the port is open, execute this and exit
|
||||
} else if (4 == sscanf_s(argv[i], "-Command=%d,%d,%d,%d", &CommandToExecute[0], &CommandToExecute[1], &CommandToExecute[2], &CommandToExecute[3])) {
|
||||
// After the port is open, execute this and exit
|
||||
} else if (0 == strncmp(argv[i], "-Extended=", 10)) {
|
||||
pExtendedMessage = argv[i] + 10;
|
||||
} else if (0 == strcmp(argv[i], "-Verbose")) {
|
||||
verboseMode = true;
|
||||
} else if (0 == strcmp(argv[i], "-ExportInfo")) {
|
||||
@@ -699,6 +816,74 @@ int __cdecl main(int argc, char *argv[]) {
|
||||
avr->ExportInformation();
|
||||
verboseMode = saveVerbose;
|
||||
exit(EXIT_OK);
|
||||
} else if (1 <= (parseCount = sscanf_s(argv[i], "-ExportInfo=%d,%d,%d", &CommandToExecute[0], &CommandToExecute[1], &CommandToExecute[2]))) {
|
||||
//
|
||||
// // If they didn't provide all three, set the others to default (wildcard)
|
||||
//
|
||||
switch (parseCount) {
|
||||
case 1:
|
||||
CommandToExecute[1] = AVRInterface::AVRFunction_E::fncFunctionCount;
|
||||
// break; // fall thru on purpose
|
||||
case 2:
|
||||
CommandToExecute[2] = AVRInterface::AVRArg_T::eARGCount;
|
||||
// break; // fall thru on purpose
|
||||
default:
|
||||
// nothing to do
|
||||
break;
|
||||
}
|
||||
bool saveVerbose = verboseMode;
|
||||
verboseMode = true;
|
||||
avr->ExportInformation((AVRInterface::AVRSubsystem_T)CommandToExecute[0],
|
||||
(AVRInterface::AVRFunction_E)CommandToExecute[1],
|
||||
(AVRInterface::AVRArg_T)CommandToExecute[2]);
|
||||
verboseMode = saveVerbose;
|
||||
exit(EXIT_OK);
|
||||
} else if (0 == strcmp(argv[i], "-Power=On")) {
|
||||
CommandToExecute[0] = AVRInterface::subMain;
|
||||
CommandToExecute[1] = AVRInterface::fncPower;
|
||||
CommandToExecute[2] = AVRInterface::eOn;
|
||||
} else if (0 == strcmp(argv[i], "-Power=Off")) {
|
||||
CommandToExecute[0] = AVRInterface::subMain;
|
||||
CommandToExecute[1] = AVRInterface::fncPower;
|
||||
CommandToExecute[2] = AVRInterface::eOff;
|
||||
} else if (0 == strcmp(argv[i], "-Mute=On")) {
|
||||
CommandToExecute[0] = AVRInterface::subMain;
|
||||
CommandToExecute[1] = AVRInterface::fncMute;
|
||||
CommandToExecute[2] = AVRInterface::eOn;
|
||||
} else if (0 == strcmp(argv[i], "-Mute=Off")) {
|
||||
CommandToExecute[0] = AVRInterface::subMain;
|
||||
CommandToExecute[1] = AVRInterface::fncMute;
|
||||
CommandToExecute[2] = AVRInterface::eOff;
|
||||
} else if (1 == sscanf_s(argv[i], "-Zone1Volume=%4f", &db)) {
|
||||
if (db >= -80.0f && db <= +16.5f) {
|
||||
CommandToExecute[0] = AVRInterface::sysCommand;
|
||||
CommandToExecute[1] = AVRInterface::fncSetValue;
|
||||
CommandToExecute[2] = AVRInterface::eMasterVol;
|
||||
CommandToExecute[3] = avr->VolumeDBtoAPIValue(db);
|
||||
} else {
|
||||
printf("***** Volume %+4.1f not in the range '-80.0 <= value <= 16.5' *****\n", db);
|
||||
exit(EXIT_IllegalOption);
|
||||
}
|
||||
} else if (1 == sscanf_s(argv[i], "-Zone2Volume=%4f", &db)) {
|
||||
if (db >= -80.0f && db <= +16.5f) {
|
||||
CommandToExecute[0] = AVRInterface::sysCommand;
|
||||
CommandToExecute[1] = AVRInterface::fncSetValue;
|
||||
CommandToExecute[2] = AVRInterface::eZone2Vol;
|
||||
CommandToExecute[3] = avr->VolumeDBtoAPIValue(db);
|
||||
} else {
|
||||
printf("***** Volume %+4.1f not in the range '-80.0 <= value <= 16.5' *****\n", db);
|
||||
exit(EXIT_IllegalOption);
|
||||
}
|
||||
} else if (1 == sscanf_s(argv[i], "-Zone3Volume=%4f", &db)) {
|
||||
if (db >= -80.0f && db <= +16.5f) {
|
||||
CommandToExecute[0] = AVRInterface::sysCommand;
|
||||
CommandToExecute[1] = AVRInterface::fncSetValue;
|
||||
CommandToExecute[2] = AVRInterface::eZone3Vol;
|
||||
CommandToExecute[3] = avr->VolumeDBtoAPIValue(db);
|
||||
} else {
|
||||
printf("***** Volume %+4.1f not in the range '-80.0 <= value <= 16.5' *****\n", db);
|
||||
exit(EXIT_IllegalOption);
|
||||
}
|
||||
} else {
|
||||
printf("***** Unrecognized command '%s' *****\n", argv[i]);
|
||||
EmitCommandLineHelp();
|
||||
@@ -711,7 +896,7 @@ int __cdecl main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
if (AttachToSerialPort()) {
|
||||
if (CommandToExecute[0] != -1 && CommandToExecute[1] != -1 && CommandToExecute[2] != -1) {
|
||||
if (pExtendedMessage || (CommandToExecute[0] != -1 && CommandToExecute[1] != -1 && CommandToExecute[2] != -1)) {
|
||||
DWORD refTime = AppTime();
|
||||
DWORD nowTime = AppTime();
|
||||
DWORD elapsedTime = nowTime - refTime;
|
||||
@@ -726,11 +911,16 @@ int __cdecl main(int argc, char *argv[]) {
|
||||
nowTime = AppTime();
|
||||
elapsedTime = nowTime - refTime;
|
||||
} while ((elapsedTime < 5000) && (state != AVRInterface::stReady));
|
||||
|
||||
|
||||
if (elapsedTime < 5000) {
|
||||
avr->AVRCommand((AVRInterface::AVRSubsystem_T)CommandToExecute[0],
|
||||
(AVRInterface::AVRFunction_E)CommandToExecute[1],
|
||||
(AVRInterface::AVRArg_T)CommandToExecute[2]);
|
||||
if (pExtendedMessage) {
|
||||
SendExtendedMessage(pExtendedMessage);
|
||||
} else {
|
||||
avr->AVRCommand((AVRInterface::AVRSubsystem_T)CommandToExecute[0],
|
||||
(AVRInterface::AVRFunction_E)CommandToExecute[1],
|
||||
(AVRInterface::AVRArg_T)CommandToExecute[2],
|
||||
(uint8_t)CommandToExecute[3]);
|
||||
}
|
||||
refTime = nowTime = AppTime();
|
||||
do {
|
||||
Sleep(10); // @TODO how long to wait should not be based on lucky timing
|
||||
@@ -741,8 +931,6 @@ int __cdecl main(int argc, char *argv[]) {
|
||||
}
|
||||
state = avr->Tick(nowTime);
|
||||
} while (((nowTime - refTime) < 5000) && (state != AVRInterface::stReady));
|
||||
} else {
|
||||
// printf("%u\n", elapsedTime);
|
||||
}
|
||||
DetachSerialPort();
|
||||
exit(EXIT_OK);
|
||||
@@ -755,7 +943,7 @@ int __cdecl main(int argc, char *argv[]) {
|
||||
printf("WARN: Cannot install Console Control Handler\n");
|
||||
}
|
||||
|
||||
printf("AVR - a command shell utility for a Yamaha RX-2400 AVR by D.Smart ");
|
||||
printf("AVR - a command shell utility for a Yamaha RX-V2400 AVR by D.Smart ");
|
||||
printf("[COM%i at %i baud]", avrOnPort, avrBaud);
|
||||
Console_WriteAt(0, consoleHeight - consoleScrollHeight -1, "----------------------------------------");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user