1645 lines
44 KiB
C++
1645 lines
44 KiB
C++
#pragma warning(disable : 4706) // assignment within conditional expression
|
|
#pragma warning(disable : 4996) // _CRT_SECURE_NO_DEPRECATE
|
|
|
|
#include "stdafx.h"
|
|
#include <Windows.h>
|
|
#include <conio.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <time.h>
|
|
#include <timeapi.h>
|
|
#include "SerialPort\SerialPort.h"
|
|
|
|
enum
|
|
{
|
|
COM_NO_PORT = -1,
|
|
COM_MIN_PORT = 1,
|
|
COM_MAX_PORT = 99
|
|
};
|
|
CSerialPort avr;
|
|
int avrOnPort = COM_NO_PORT; // Serial Port 1, 2, ... taking note that some USB adapters can be up toward channel 11, 12, ...
|
|
unsigned avrBaud = 9600;
|
|
|
|
DWORD const retryInterval = 1000; // ms
|
|
|
|
// Each DT is the hex-character from the stream
|
|
//
|
|
//
|
|
typedef struct {
|
|
uint8_t DT0; // * Baud Rate
|
|
uint8_t DT1; // * Receive Buffer 'E'
|
|
uint8_t DT2; // * Receive Buffer '0'
|
|
uint8_t DT3; // * '1'
|
|
uint8_t DT4; // * Command Timeout '9'
|
|
uint8_t DT5; // * '0'
|
|
uint8_t DT6; // * '0'
|
|
uint8_t DT7; // * System '0':Ok, '1':Busy
|
|
uint8_t DT8; // * Power 0:Off, 1:On
|
|
uint8_t DT9; // Input 0: Phono, 1:CD, 2:Tuner, 3:CD-R, 4:MD-Tape, 5:DVD, 6:D-TV, 7:Cbl, 9:VCR1, A:VCR2
|
|
uint8_t DT10; // 6ch input 0:Off, 1:On
|
|
uint8_t DT11; // Input Mode 0:AUTO, 2:DTS, 4:Analog, 5:Analog Only
|
|
uint8_t DT12; // Audio Mute 0:Off, 1:On
|
|
uint8_t DT13;
|
|
uint8_t DT14;
|
|
uint8_t DT15;
|
|
uint8_t DT16;
|
|
uint8_t DT17;
|
|
uint8_t DT18;
|
|
uint8_t DT19;
|
|
|
|
uint8_t DT20;
|
|
uint8_t DT21;
|
|
uint8_t DT22;
|
|
uint8_t DT23;
|
|
uint8_t DT24;
|
|
uint8_t DT25;
|
|
uint8_t DT26;
|
|
uint8_t DT27;
|
|
uint8_t DT28;
|
|
uint8_t DT29;
|
|
|
|
uint8_t DT30;
|
|
uint8_t DT31;
|
|
uint8_t DT32;
|
|
uint8_t DT33;
|
|
uint8_t DT34;
|
|
uint8_t DT35;
|
|
uint8_t DT36;
|
|
uint8_t DT37;
|
|
uint8_t DT38;
|
|
uint8_t DT39;
|
|
|
|
uint8_t DT40;
|
|
uint8_t DT41;
|
|
uint8_t DT42;
|
|
uint8_t DT43;
|
|
uint8_t DT44;
|
|
uint8_t DT45;
|
|
uint8_t DT46;
|
|
uint8_t DT47;
|
|
uint8_t DT48;
|
|
uint8_t DT49;
|
|
|
|
uint8_t DT50;
|
|
uint8_t DT51;
|
|
uint8_t DT52;
|
|
uint8_t DT53;
|
|
uint8_t DT54;
|
|
uint8_t DT55;
|
|
uint8_t DT56;
|
|
uint8_t DT57;
|
|
uint8_t DT58;
|
|
uint8_t DT59;
|
|
|
|
uint8_t DT60;
|
|
uint8_t DT61;
|
|
uint8_t DT62;
|
|
uint8_t DT63;
|
|
uint8_t DT64;
|
|
uint8_t DT65;
|
|
uint8_t DT66;
|
|
uint8_t DT67;
|
|
uint8_t DT68;
|
|
uint8_t DT69;
|
|
|
|
uint8_t DT70;
|
|
uint8_t DT71;
|
|
uint8_t DT72;
|
|
uint8_t DT73;
|
|
uint8_t DT74;
|
|
uint8_t DT75;
|
|
uint8_t DT76;
|
|
uint8_t DT77;
|
|
uint8_t DT78;
|
|
uint8_t DT79;
|
|
|
|
uint8_t DT80;
|
|
uint8_t DT81;
|
|
uint8_t DT82;
|
|
uint8_t DT83;
|
|
uint8_t DT84;
|
|
uint8_t DT85;
|
|
uint8_t DT86;
|
|
uint8_t DT87;
|
|
uint8_t DT88;
|
|
uint8_t DT89;
|
|
|
|
uint8_t DT90;
|
|
uint8_t DT91;
|
|
uint8_t DT92;
|
|
uint8_t DT93;
|
|
uint8_t DT94;
|
|
uint8_t DT95;
|
|
uint8_t DT96;
|
|
uint8_t DT97;
|
|
uint8_t DT98;
|
|
uint8_t DT99;
|
|
|
|
uint8_t DT100;
|
|
uint8_t DT101;
|
|
uint8_t DT102;
|
|
uint8_t DT103;
|
|
uint8_t DT104;
|
|
uint8_t DT105;
|
|
uint8_t DT106;
|
|
uint8_t DT107;
|
|
uint8_t DT108;
|
|
uint8_t DT109;
|
|
|
|
uint8_t DT110;
|
|
uint8_t DT111;
|
|
uint8_t DT112;
|
|
uint8_t DT113;
|
|
uint8_t DT114;
|
|
uint8_t DT115;
|
|
uint8_t DT116;
|
|
uint8_t DT117;
|
|
uint8_t DT118;
|
|
uint8_t DT119;
|
|
|
|
uint8_t DT120;
|
|
uint8_t DT121;
|
|
uint8_t DT122;
|
|
uint8_t DT123;
|
|
uint8_t DT124;
|
|
uint8_t DT125;
|
|
uint8_t DT126;
|
|
uint8_t DT127;
|
|
uint8_t DT128;
|
|
uint8_t DT129;
|
|
|
|
uint8_t DT130;
|
|
uint8_t DT131;
|
|
uint8_t DT132;
|
|
uint8_t DT133;
|
|
uint8_t DT134;
|
|
uint8_t DT135;
|
|
uint8_t DT136;
|
|
uint8_t DT137; // PB/SB Select 00: PR, 01: SB // Last documented register
|
|
uint8_t DT138;
|
|
uint8_t DT139;
|
|
|
|
uint8_t DT140;
|
|
uint8_t DT141;
|
|
uint8_t DT142;
|
|
uint8_t DT143;
|
|
uint8_t DT144;
|
|
uint8_t DT145;
|
|
uint8_t DT146;
|
|
uint8_t DT147;
|
|
uint8_t DT148;
|
|
uint8_t DT149;
|
|
|
|
uint8_t DT150;
|
|
uint8_t DT151;
|
|
uint8_t DT152;
|
|
uint8_t DT153;
|
|
uint8_t DT154;
|
|
uint8_t DT155;
|
|
|
|
uint8_t DT156_255[100];
|
|
} AVR_Configuration_T;
|
|
|
|
|
|
// 264 total
|
|
typedef struct {
|
|
uint8_t type[5]; // Model ID
|
|
uint8_t version; // A-Z
|
|
uint8_t length[2]; // 1 - 255
|
|
} AVR_StatusHeader_T;
|
|
|
|
typedef struct {
|
|
bool headerValid;
|
|
bool configValid;
|
|
AVR_StatusHeader_T header;
|
|
AVR_Configuration_T config;
|
|
|
|
} AVR_Status_T;
|
|
|
|
//AVR_StatusHeader_T avrStatusHeader;
|
|
//AVR_Configuration_T avrConfigData;
|
|
AVR_Status_T avrStatus;
|
|
|
|
|
|
typedef enum {
|
|
EXIT_OK = 0,
|
|
EXIT_IllegalOption = 1,
|
|
EXIT_ConfigError = 2,
|
|
EXIT_UserESC = 3,
|
|
EXIT_UserQ = 4,
|
|
EXIT_ExternalQ = 5
|
|
} ExitCode;
|
|
|
|
constexpr auto MAXTEXTLEN = 512;
|
|
char progname[MAXTEXTLEN];
|
|
|
|
int AttachToSerialPort();
|
|
int DetachSerialPort();
|
|
|
|
// SerialSend
|
|
//
|
|
// Try to send the message.
|
|
//
|
|
// @param[in] p is a pointer to the message to send
|
|
// @param[in] len is the count of bytes in the message
|
|
// @returns true if the serial interface accepted it.
|
|
//
|
|
bool SerialSend(const uint8_t *p, DWORD len);
|
|
|
|
#define SERIALQUEUESIZE 3
|
|
typedef struct {
|
|
uint8_t *messageToSend;
|
|
DWORD len;
|
|
} SerialQueue_T;
|
|
|
|
static SerialQueue_T serialQueue[SERIALQUEUESIZE];
|
|
static int serialQueueCount = 0;
|
|
|
|
|
|
// ProcessSerialQueue
|
|
//
|
|
// If there are parameters passed, insert a message into the queue.
|
|
// Process the queue (with zero or more messages) to send
|
|
//
|
|
// @param[in] p is a pointer to the message to send
|
|
// @param[in] len is the count of bytes in the message
|
|
// @returns false if the queue (which is a fixed size) is full.
|
|
//
|
|
bool ProcessSerialQueue(const uint8_t *p = NULL, DWORD len = 0);
|
|
|
|
|
|
// ProcessSerialReceive
|
|
//
|
|
// See if anything came in, and if so, process it.
|
|
//
|
|
// @returns true if a message was processed.
|
|
//
|
|
bool ProcessSerialReceive(void);
|
|
void EnumerateComPorts();
|
|
unsigned long Hex2Dec(uint8_t *p, int dig);
|
|
|
|
// Helpers to convert status codes to text
|
|
const char *BusyToText(uint8_t val);
|
|
const char *WarnToText(uint8_t val);
|
|
const char *PlaybackToText(uint8_t val);
|
|
const char *FsToText(uint8_t val);
|
|
const char *ZonePower(uint8_t val);
|
|
const char *VolumeDB(uint8_t val);
|
|
const char *ProgramName(uint8_t val);
|
|
|
|
void ShowAllStatusInfo();
|
|
|
|
bool UserWantsToExitCanSniff = false;
|
|
|
|
DWORD progStartTime;
|
|
|
|
// For special cursor positioning
|
|
bool consoleInit = false;
|
|
HANDLE hStdout, hStdin;
|
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
WORD wOldColorAttrs; // Save the current console colors
|
|
|
|
short consoleWidth = 105;
|
|
short consoleHeight = 80;
|
|
// 0 99
|
|
// +---------------------------------------------------------------+
|
|
// | Program banner information | 0
|
|
// | on two lines |
|
|
// | Current status information starts on line 3 |
|
|
// | and down a ways... |
|
|
// | |
|
|
// | |
|
|
// | |
|
|
// + Down near the bottom is the scroll region + 59
|
|
// | |
|
|
// | |
|
|
// | | 79
|
|
// +---------------------------------------------------------------+ 80
|
|
short scrollTop = 59;
|
|
short scrollBot = 79;
|
|
short consoleScrollHeight = 20;
|
|
|
|
|
|
void Console_Init();
|
|
void Console_Cls();
|
|
bool Console_SetCursorVisibility(bool visible);
|
|
void Console_SetCursor(short x, short y);
|
|
void Console_Write(const char *text);
|
|
void Console_WriteAt(short x, short y, const char *text);
|
|
void Console_ScrollBottomRegion(short topLine, short bottomLine);
|
|
bool Console_AdvanceToNextLineIfNotRoomFor(short x, int scroll = -1);
|
|
|
|
typedef struct {
|
|
const char *pMsg;
|
|
DWORD MsgLen;
|
|
} Message_T;
|
|
|
|
typedef struct {
|
|
const char Char;
|
|
const char *pDescription;
|
|
Message_T TxMsg;
|
|
} UserCmd_T;
|
|
|
|
const UserCmd_T UserCommands[] = {
|
|
{ 'R', "Ready", {"\x11" "000" "\x03", 5 } },
|
|
{ 'P', "Power On", {"\x02" "07A1D" "\x03", 7} },
|
|
{ 'p', "Power Off", {"\x02" "07A1E" "\x03", 7} },
|
|
{ '1', "Zone 1 On", {"\x02" "07E7E" "\x03", 7} },
|
|
{ '!', "Zone 1 Standby", {"\x02" "07E7F" "\x03", 7} },
|
|
{ '2', "Zone 2 On", {"\x02" "07EBA" "\x03", 7} },
|
|
{ '@', "Zone 2 Standby", {"\x02" "07EBB" "\x03", 7} },
|
|
{ '3', "Zone 3 On", {"\x02" "07AED" "\x03", 7} },
|
|
{ '#', "Zone 3 Standby", {"\x02" "07AEE" "\x03", 7} },
|
|
{ 'V', "Vol 1 Up", {"\x02" "07A1A" "\x03", 7} },
|
|
{ 'v', "Vol 1 Down", {"\x02" "07A1B" "\x03", 7} },
|
|
{ 'M', "Vol 1 Mute", {"\x02" "07EA2" "\x03", 7} },
|
|
{ 'm', "Vol 1 UnMute", {"\x02" "07EA3" "\x03", 7} },
|
|
{ '/', "Show All" },
|
|
{ '?', "Help on runtime commands" },
|
|
{ 'S', "Set RTS" },
|
|
{ 's', "Clear RTS" },
|
|
{ '\x1B', "Quit App" },
|
|
};
|
|
|
|
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
|
|
void (*fncHelper)(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen);
|
|
const char *TextFormatter; // used primarily for development printf(TextFormatter, value)
|
|
const char *(*fncValueToText)(uint8_t rDat);
|
|
} MessageHandler_T;
|
|
|
|
void RxSystemReport( uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen);
|
|
void RxWarningReport(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen);
|
|
void RxPlaybackReport(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen);
|
|
void RxFsReport(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen);
|
|
|
|
void RxPowerStatus( uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen);
|
|
|
|
void RxMasterVolStatus(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen);
|
|
void RxProgramStatus(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen);
|
|
|
|
|
|
// 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)
|
|
// fncHelper: optional function to call upon receipt
|
|
//
|
|
const MessageHandler_T MessageHandlers[] = {
|
|
//rCmd cfgOfs num ShowAll function
|
|
{0x00, 7, 1, 1, RxSystemReport },
|
|
{0x01, 0, 0, 0, RxWarningReport },
|
|
{0x10, 31, 1, 1, RxPlaybackReport },
|
|
{0x11, 32, 1, 1, RxFsReport },
|
|
{0x12, 33, 1, 1, NULL }, // EX/EX
|
|
{0x13, 34, 1, 1, NULL }, // Thr / Bypass
|
|
{0x14, 35, 1, 1, NULL }, // RED dts
|
|
{0x15, 38, 1, 1, NULL }, // Tuner tuned
|
|
{0x16, 43, 1, 1, NULL }, // Dts 96/24
|
|
{0x20, 8, 0, 1, RxPowerStatus, "Zone Power: %s", ZonePower},
|
|
{0x21, 9, 1, 1, NULL }, // Input Source
|
|
{0x22, 11, 1, 1, NULL }, // Input Mode
|
|
{0x23, 12, 1, 1, NULL }, // Mute Status
|
|
{0x24, 13, 1, 1, NULL }, // Zone 2 Input Source
|
|
{0x25, 14, 1, 1, NULL }, // Zone 2 Mute
|
|
{0x26, 15, 2, 1, RxMasterVolStatus },
|
|
{0x27, 17, 2, 1, NULL }, // Zone 2 Vol
|
|
{0x28, 19, 2, 1, RxProgramStatus }, // Program
|
|
{0x29, 25, 1, 1, NULL }, // Tuner Page
|
|
{0x2A, 26, 1, 1, NULL }, // Tuner Preset Number
|
|
{0x2B, 23, 1, 1, NULL }, // OSD
|
|
{0x2C, 24, 1, 1, NULL }, // Sleep Timer
|
|
{0x2D, 22, 1, 1, NULL }, // EX/ES(Key)
|
|
{0x2E, 29, 1, 1, NULL }, // Speaker Relay A
|
|
{0x2F, 30, 1, 1, NULL }, // Speaker Relay B
|
|
|
|
{0x36, 39, 1, 1, NULL }, // DC1 Trigger
|
|
|
|
{0x3C, 45, 1, 1, NULL }, // DC2 Trigger
|
|
|
|
{0x82, 27, 1, 1, NULL }, // Night Mode
|
|
|
|
{0xA1, 0, 0, 0, NULL }, // Zone 3 Mute
|
|
|
|
};
|
|
|
|
// RCMD 00
|
|
//
|
|
void RxSystemReport(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen) {
|
|
(void)rCmd, pMessage, msgLen;
|
|
//SetData(&avrStatus.config.DT8, pMessage + 5, 2);
|
|
char buf[MAXTEXTLEN];
|
|
sprintf_s(buf, MAXTEXTLEN, "System Report: %s\n", BusyToText(rDat));
|
|
Console_Write(buf);
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
//ShowAllStatusInfo();
|
|
}
|
|
|
|
// RCMD 01
|
|
//
|
|
void RxWarningReport(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen) {
|
|
(void)rCmd, pMessage, msgLen;
|
|
//SetData(&avrStatus.config.DT8, pMessage + 5, 2);
|
|
char buf[MAXTEXTLEN];
|
|
sprintf_s(buf, MAXTEXTLEN, "Warning Report: %s\n", WarnToText(rDat));
|
|
Console_Write(buf);
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
//ShowAllStatusInfo();
|
|
}
|
|
|
|
// RCMD 10
|
|
void RxPlaybackReport(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen) {
|
|
(void)rCmd, pMessage, msgLen;
|
|
char buf[MAXTEXTLEN];
|
|
sprintf_s(buf, MAXTEXTLEN, "Playback Report: %s\n", PlaybackToText(rDat));
|
|
Console_Write(buf);
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
//ShowAllStatusInfo();
|
|
}
|
|
|
|
// RCMD 11
|
|
void RxFsReport(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen) {
|
|
(void)rCmd, pMessage, msgLen;
|
|
char buf[MAXTEXTLEN];
|
|
sprintf_s(buf, MAXTEXTLEN, "Playback Report: %s\n", FsToText(rDat));
|
|
Console_Write(buf);
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
//ShowAllStatusInfo();
|
|
}
|
|
|
|
// RCMD 20
|
|
void RxPowerStatus(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen) {
|
|
(void)rCmd, pMessage, msgLen;
|
|
//SetData(&avrStatus.config.DT8, pMessage + 5, 2);
|
|
char buf[MAXTEXTLEN];
|
|
sprintf_s(buf, MAXTEXTLEN, "Zone Power: %s\n", ZonePower(rDat));
|
|
Console_Write(buf);
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
//ShowAllStatusInfo();
|
|
}
|
|
|
|
// RCMD 26
|
|
void RxMasterVolStatus(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen) {
|
|
(void)rCmd, pMessage, msgLen;
|
|
char buf[MAXTEXTLEN];
|
|
sprintf_s(buf, MAXTEXTLEN, "Vol: %s\n", VolumeDB(rDat));
|
|
Console_Write(buf);
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
//ShowAllStatusInfo();
|
|
}
|
|
|
|
// RCMD 28
|
|
void RxProgramStatus(uint8_t rCmd, uint8_t rDat, uint8_t *pMessage, uint32_t msgLen) {
|
|
(void)rCmd, pMessage, msgLen;
|
|
char buf[MAXTEXTLEN];
|
|
sprintf_s(buf, MAXTEXTLEN, "Vol: %s\n", ProgramName(rDat));
|
|
Console_Write(buf);
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
//ShowAllStatusInfo();
|
|
}
|
|
|
|
int CS_KeyHit() {
|
|
int h = _kbhit();
|
|
return h;
|
|
}
|
|
|
|
int CS_GetChar() {
|
|
int k = _getch(); // More leadin chars
|
|
return k;
|
|
}
|
|
|
|
BOOL WINAPI ControlIntercept(DWORD CtrlType) {
|
|
switch (CtrlType) {
|
|
case CTRL_C_EVENT:
|
|
case CTRL_CLOSE_EVENT:
|
|
case CTRL_BREAK_EVENT:
|
|
case CTRL_LOGOFF_EVENT:
|
|
case CTRL_SHUTDOWN_EVENT:
|
|
UserWantsToExitCanSniff = true;
|
|
return FALSE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
void ProcessWindowsMessage(void) {
|
|
MSG msgx;
|
|
bool msgReturn;
|
|
msgReturn = PeekMessage(&msgx, NULL, WM_QUIT, WM_QUIT, PM_NOREMOVE);
|
|
if (msgReturn == true && msgx.message == WM_QUIT) {
|
|
UserWantsToExitCanSniff = true;
|
|
}
|
|
}
|
|
|
|
|
|
// EmitBuffer
|
|
//
|
|
// Emits the provided buffer to the console, translating non-printable
|
|
// characters into hex codes enclosed in square brackets.
|
|
//
|
|
// Consider line-wrapping to align the next line
|
|
//
|
|
void EmitBuffer(const char *prefix, const uint8_t *buf, size_t len = 0, bool appendReturn = false) {
|
|
int i = 0;
|
|
const char *p = (const char *)buf;
|
|
DWORD now = timeGetTime();
|
|
char txtBuf[MAXTEXTLEN] = "";
|
|
|
|
if (len == 0) len = strlen((const char *)buf);
|
|
sprintf_s(txtBuf, MAXTEXTLEN, "%7.3f: [%3d]%s", (float)(now - progStartTime)/1000.0f, (int)strlen(p), prefix);
|
|
Console_Write(txtBuf);
|
|
while (*p && ((unsigned)(p - (const char *)buf) < len)) {
|
|
if (isprint(*p)) {
|
|
putchar(*p);
|
|
i++;
|
|
} else if (*p == '\r') {
|
|
putchar('\n');
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
} else if (*p == '\n') {
|
|
// skip it
|
|
} else {
|
|
printf("[%02X]", (unsigned char)*p);
|
|
}
|
|
if ((i & 3) == 0) {
|
|
if (Console_AdvanceToNextLineIfNotRoomFor(12, 1)) {
|
|
//Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
printf(" "); // sized to get past the timestamp, length, and prefix
|
|
i = 0;
|
|
} else {
|
|
printf(" ");
|
|
}
|
|
}
|
|
p++;
|
|
}
|
|
if (appendReturn) {
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot); // putch('\r');
|
|
} else {
|
|
//putch('\n');
|
|
//Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
}
|
|
}
|
|
|
|
|
|
void EchoSerialRecv(const uint8_t *pMsg) {
|
|
Console_SetCursor(0, -1);
|
|
EmitBuffer("< ", pMsg);
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
}
|
|
|
|
bool SerialSend(const uint8_t *p, DWORD len) {
|
|
bool retVal = false;
|
|
Console_SetCursor(0, -1);
|
|
EmitBuffer("> ", p, len);
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
if (avr.Write((const LPVOID)p, len) == len) {
|
|
retVal = true;
|
|
} else {
|
|
Console_SetCursor(0, -1);
|
|
Console_Write("***** Failed to send. Port not open?");
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
bool ProcessSerialQueue(const uint8_t *p, DWORD len) {
|
|
bool retVal = false; // assume fail
|
|
static bool freshData = false;
|
|
|
|
if (p && len) {
|
|
if (serialQueueCount < SERIALQUEUESIZE) {
|
|
serialQueue[serialQueueCount].messageToSend = (uint8_t *)malloc(len);
|
|
if (serialQueue[serialQueueCount].messageToSend) {
|
|
memcpy(serialQueue[serialQueueCount].messageToSend, p, len);
|
|
serialQueue[serialQueueCount].len = len;
|
|
serialQueueCount++;
|
|
retVal = true;
|
|
freshData = true;
|
|
}
|
|
}
|
|
}
|
|
if (serialQueueCount) {
|
|
if (SerialSend((const uint8_t *)serialQueue[0].messageToSend, serialQueue[0].len)) {
|
|
--serialQueueCount;
|
|
free(serialQueue[0].messageToSend);
|
|
for (int i = 0; i < serialQueueCount; i++) {
|
|
serialQueue[i] = serialQueue[i + 1];
|
|
}
|
|
retVal = true;
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
|
|
void EmitSpinner() {
|
|
static int x = 0;
|
|
const char arrow[] = "|/-\\|/-\\";
|
|
printf("%c\b", arrow[x++]);
|
|
if (x == 8) x = 0;
|
|
}
|
|
|
|
|
|
void EmitRuntimeHelp() {
|
|
for (int i = 0; i < sizeof(UserCommands) / sizeof(UserCmd_T); i++) {
|
|
char tinyBuf[6];
|
|
if (isprint(UserCommands[i].Char)) {
|
|
sprintf_s(tinyBuf, sizeof(tinyBuf), "%c", UserCommands[i].Char);
|
|
} else if (UserCommands[i].Char == '\x1B') {
|
|
sprintf_s(tinyBuf, sizeof(tinyBuf), "%s", "<esc>");
|
|
} else if (UserCommands[i].Char < ' ') {
|
|
sprintf_s(tinyBuf, sizeof(tinyBuf), "^%c", UserCommands[i].Char + 64);
|
|
} else {
|
|
sprintf_s(tinyBuf, sizeof(tinyBuf), "0x%02X", (unsigned char)UserCommands[i].Char);
|
|
}
|
|
char buf[MAXTEXTLEN];
|
|
sprintf_s(buf, MAXTEXTLEN, " %5s %-25s", tinyBuf, UserCommands[i].pDescription);
|
|
Console_AdvanceToNextLineIfNotRoomFor((short)strlen(buf), 1);
|
|
Console_Write(buf);
|
|
}
|
|
if (avr.IsOpen()) {
|
|
Console_SetCursor(0, -1);
|
|
printf(" Com Status: RTS: %-3s ", avr.Get_RTS_State() ? "ON" : "OFF");
|
|
printf("DTR: %-3s ", avr.Get_DTR_State() ? "ON" : "OFF");
|
|
printf("CTS: %-3s ", avr.Get_CTS_State() ? "ON" : "OFF");
|
|
printf("DSR: %-3s ", avr.Get_DSR_State() ? "ON" : "OFF");
|
|
printf("RI: %-3s\n", avr.Get_RI_State() ? "ON" : "OFF");
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
}
|
|
}
|
|
|
|
|
|
// PCMessage
|
|
//
|
|
// Various responses need to be formatted and shown on screen
|
|
// The last param will allow resetting the column counter
|
|
// and pre and post-pending \n
|
|
//
|
|
static void PCMessage(const char *msg, int len, uint8_t **src, const char * (fncHelper)(uint8_t val) = NULL) {
|
|
char buf[MAXTEXTLEN];
|
|
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(buf, (char *)*src, len); // s/w
|
|
*src += len;
|
|
buf[len] = '\0';
|
|
}
|
|
|
|
char outBuf[MAXTEXTLEN];
|
|
sprintf_s(outBuf, MAXTEXTLEN, "%17s %-8s",
|
|
msg,
|
|
p
|
|
);
|
|
Console_AdvanceToNextLineIfNotRoomFor(26);
|
|
Console_Write(outBuf);
|
|
}
|
|
|
|
|
|
const char * BusyToText(uint8_t val) {
|
|
static char buf[16];
|
|
if (val == 0) {
|
|
strcpy_s(buf, sizeof(buf), "OK");
|
|
} else if (val == 1) {
|
|
strcpy_s(buf, sizeof(buf), "BUSY");
|
|
} else {
|
|
sprintf_s(buf, sizeof(buf), "0x%02X ?", (unsigned char)val);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
const char * WarnToText(uint8_t val) {
|
|
static char buf[16];
|
|
if (val == 0) {
|
|
strcpy_s(buf, sizeof(buf), "OK");
|
|
} else if (val == 1) {
|
|
strcpy_s(buf, sizeof(buf), "BUSY");
|
|
} else {
|
|
sprintf_s(buf, sizeof(buf), "0x%02X ?", (unsigned char)val);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
const char *PlaybackToText(uint8_t val) {
|
|
static char buf[60];
|
|
const char *playbackList[] = {
|
|
/* 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 Discrete",
|
|
/* C */ "Other than AAC 2/0",
|
|
/* D */ "AAC 2/0",
|
|
};
|
|
if (val < sizeof(playbackList)/sizeof(playbackList[0]))
|
|
strcpy_s(buf, sizeof(buf), playbackList[val]);
|
|
else
|
|
sprintf_s(buf, sizeof(buf), "0x%04X ?", val);
|
|
return buf;
|
|
}
|
|
|
|
const char *FsToText(uint8_t val) {
|
|
static char buf[60];
|
|
const char *fsList[] = {
|
|
/* 0 */ "Analog",
|
|
/* 1 */ "32 kHz",
|
|
/* 2 */ "44.1 kHz",
|
|
/* 3 */ "48 kHz",
|
|
/* 4 */ "64 kHz",
|
|
/* 5 */ "88.2 kHz",
|
|
/* 6 */ "96 kHz",
|
|
/* 7 */ "unknown",
|
|
/* 8 */ "128.0 kHz unk",
|
|
/* 9 */ "176.4 kHz unk",
|
|
/* A */ "192.0 kHz unk",
|
|
};
|
|
if (val < sizeof(fsList) / sizeof(fsList[0]))
|
|
strcpy_s(buf, sizeof(buf), fsList[val]);
|
|
else
|
|
sprintf_s(buf, sizeof(buf), "0x%04X ?", val);
|
|
return buf;
|
|
}
|
|
|
|
|
|
|
|
const char * OnOffText(uint8_t val) {
|
|
static char buf[16];
|
|
if (val == 0) {
|
|
strcpy_s(buf, sizeof(buf), "Off");
|
|
} else if (val == 1) {
|
|
strcpy_s(buf, sizeof(buf), "On");
|
|
} else {
|
|
sprintf_s(buf, sizeof(buf), "0x%04X ?", val);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
const char *ZonePower(uint8_t val) {
|
|
static char buf[60];
|
|
const char *powerList[8] = {
|
|
/* 0 */ "All Off (Main, Zone 2, Zone 3)",
|
|
/* 1 */ "All On (Main, Zone 2, Zone 3)",
|
|
/* 2 */ "Main On | Zone 2 Off | Zone 3 Off",
|
|
/* 3 */ "Main Off | Zone 2 On | Zone 3 On ",
|
|
/* 4 */ "Main On | Zone 2 On | Zone 3 Off",
|
|
/* 5 */ "Main On | Zone 2 Off | Zone 3 Off",
|
|
/* 6 */ "Main Off | Zone 2 On | Zone 3 On ",
|
|
/* 7 */ "Main Off | Zone 2 Off | Zone 3 On ",
|
|
};
|
|
if (val < 8)
|
|
strcpy_s(buf, sizeof(buf), powerList[val]);
|
|
else
|
|
sprintf_s(buf, sizeof(buf), "0x%04X ?", val);
|
|
return buf;
|
|
}
|
|
|
|
const char * InputText(uint8_t val) {
|
|
const char *inputList[13] = {
|
|
"0:Phono", "1:CD", "2:Tuner", "3:CD-R", "4:MD-Tape", "5:DVD", "6:D-TV",
|
|
"7:Cable", "8:unk", "9:VCR1", "A:VCR2", "B:unk", "C:V-Aux"
|
|
};
|
|
if (val <= 12) {
|
|
return inputList[val];
|
|
} else {
|
|
return "huh?";
|
|
}
|
|
}
|
|
|
|
const char *ProgramName(uint8_t val) {
|
|
static char returnBuf[MAXTEXTLEN] = "";
|
|
|
|
returnBuf[0] = '\0';
|
|
if (val & 0x80) {
|
|
strcpy_s(returnBuf, MAXTEXTLEN, "STRAIGHT ");
|
|
}
|
|
val &= 0x7F; // Not accommodating the other variants yet
|
|
const char *nameList[] = {
|
|
"Hall A (HALL1)",
|
|
"Hall B",
|
|
"Hall C",
|
|
"unk",
|
|
"Hall C",
|
|
"Hall E",
|
|
"Live Concert (HALL2)",
|
|
"unk",
|
|
"Tokyo",
|
|
"Freiburg (CHURCH)",
|
|
"Royaumont",
|
|
"unk",
|
|
"Village Gate",
|
|
"Village Vanguard",
|
|
"The Bottom Line (JAZZ)",
|
|
"unk",
|
|
"The Roxy Theater (ROCK)",
|
|
"Warehouse Loft",
|
|
"Arena",
|
|
"unk",
|
|
"Disco",
|
|
"Party",
|
|
"Game",
|
|
"7 Ch Stereo",
|
|
"Pop/Rock (Music Video)",
|
|
"DJ",
|
|
"unk",
|
|
"unk",
|
|
"Opera",
|
|
"Pavillion",
|
|
"unk",
|
|
"unk",
|
|
"Mono Movie",
|
|
"Variety Sports",
|
|
"unk",
|
|
"unk",
|
|
"Spectacre",
|
|
"Sci - Fi",
|
|
"unk",
|
|
"unk",
|
|
"Adventure",
|
|
"General",
|
|
"unk",
|
|
"unk",
|
|
"Normal",
|
|
"Enhanced",
|
|
"unk",
|
|
"unk",
|
|
"PLII Movie",
|
|
"PLII Music",
|
|
"Neo: 6 Movie",
|
|
"Neo: 6 Music",
|
|
"STEREO A 2CH Stereo",
|
|
"STEREO B 2CH Direct Stereo"
|
|
"THX A Cinema",
|
|
"THX B Music",
|
|
};
|
|
if (val < sizeof(nameList)) {
|
|
strcat_s(returnBuf, MAXTEXTLEN, nameList[val]);
|
|
} else {
|
|
strcpy_s(returnBuf, MAXTEXTLEN, "huh?");
|
|
}
|
|
return returnBuf;
|
|
}
|
|
|
|
|
|
|
|
// VolumeDB
|
|
//
|
|
// Convert the communication units of volume into db
|
|
//
|
|
// Piecewise
|
|
// for values 0 to 199
|
|
// db = 0.5634 x - 112.11
|
|
// for values 200 to 255
|
|
// db = 0.5 x - 99.5
|
|
// Single Linear
|
|
// db = 0.5574 x - 111.45
|
|
//
|
|
const char *VolumeDB(uint32_t val) {
|
|
static char buf[16];
|
|
float m, b;
|
|
|
|
if (val < 200) {
|
|
m = 0.5634f;
|
|
b = -112.11f;
|
|
} else {
|
|
m = 0.5f;
|
|
b = -99.5f;
|
|
}
|
|
float db = m * val + b;
|
|
sprintf_s(buf, sizeof(buf), "%+5.1f db", db);
|
|
return buf;
|
|
}
|
|
|
|
void ShowAllStatusInfo(void) {
|
|
if (avrStatus.headerValid) {
|
|
bool priorState = Console_SetCursorVisibility(false);
|
|
Console_SetCursor(0, 2);
|
|
char buf[MAXTEXTLEN];
|
|
sprintf_s(buf, MAXTEXTLEN, "Model ID: %c%c%c%c%c, ver: %c\n", avrStatus.header.type[0], avrStatus.header.type[1],
|
|
avrStatus.header.type[2], avrStatus.header.type[3], avrStatus.header.type[4],
|
|
avrStatus.header.version);
|
|
Console_Write(buf);
|
|
uint8_t *p = (uint8_t *)&avrStatus.config;
|
|
PCMessage("Baud Rate", 1, &p);
|
|
PCMessage("Rx Buffer", 2, &p);
|
|
PCMessage("Cmd Timeout", 3, &p);
|
|
PCMessage("Handshake", 1, &p);
|
|
PCMessage("Busy", 1, &p, BusyToText);
|
|
PCMessage("Power", 1, &p, OnOffText);
|
|
if (avrStatus.configValid) {
|
|
PCMessage("Input", 1, &p, InputText);
|
|
PCMessage("6 ch", 1, &p);
|
|
PCMessage("Inp mode", 1, &p);
|
|
PCMessage("Mute", 1, &p, OnOffText);
|
|
PCMessage("Zone 2", 1, &p, InputText);
|
|
PCMessage("Mute 2", 1, &p, OnOffText);
|
|
PCMessage("Volume", 2, &p, VolumeDB);
|
|
PCMessage("Volume 2", 2, &p, VolumeDB);
|
|
PCMessage("pgm", 2, &p);
|
|
PCMessage("effect", 1, &p, OnOffText);
|
|
PCMessage("6.1/es status", 1, &p);
|
|
PCMessage("OSD", 1, &p);
|
|
PCMessage("sleep", 1, &p);
|
|
PCMessage("Tuner Pg", 1, &p);
|
|
PCMessage("Tuner #", 1, &p);
|
|
PCMessage("Night", 1, &p, OnOffText);
|
|
PCMessage("?????", 1, &p);
|
|
PCMessage("Spkr A", 1, &p, OnOffText);
|
|
PCMessage("Spkr B", 1, &p, OnOffText);
|
|
PCMessage("Playback", 1, &p);
|
|
PCMessage("Fs", 1, &p);
|
|
PCMessage("Ex/Es", 1, &p);
|
|
PCMessage("Thr Bypass", 1, &p);
|
|
PCMessage("Red DTS", 1, &p);
|
|
PCMessage("Headph", 1, &p, OnOffText);
|
|
PCMessage("Tuner Band", 1, &p);
|
|
PCMessage("Tuner Tuned", 1, &p);
|
|
PCMessage("DC1 Control Out", 1, &p);
|
|
PCMessage("?????", 2, &p);
|
|
PCMessage("DC1 Trig Ctrl", 1, &p);
|
|
PCMessage("DTS 96/24", 1, &p, OnOffText);
|
|
PCMessage("DC2 Trig Ctrl", 1, &p);
|
|
PCMessage("DC2 Trig", 1, &p);
|
|
PCMessage("Spkr B Set", 1, &p);
|
|
PCMessage("Zone 2 SP out", 1, &p, OnOffText);
|
|
PCMessage("Main R", 2, &p);
|
|
PCMessage("Main L", 2, &p);
|
|
PCMessage("Center", 2, &p);
|
|
PCMessage("Rear R", 2, &p);
|
|
PCMessage("Rear L", 2, &p);
|
|
PCMessage("Sur Bk R", 2, &p);
|
|
PCMessage("Sur Bk L", 2, &p);
|
|
PCMessage("Front R", 2, &p);
|
|
PCMessage("Front L", 2, &p);
|
|
PCMessage("Sub", 2, &p);
|
|
PCMessage("?????", 6, &p);
|
|
PCMessage("LFE SP", 2, &p);
|
|
PCMessage("LFE HP", 2, &p);
|
|
PCMessage("Audio Delay", 2, &p);
|
|
PCMessage("?????", 4, &p);
|
|
PCMessage("Inp Mode Set", 1, &p);
|
|
PCMessage("Dimmer", 1, &p);
|
|
PCMessage("OSD Msg", 1, &p);
|
|
PCMessage("OSD Shift", 2, &p);
|
|
PCMessage("Gray Back", 1, &p);
|
|
PCMessage("Video Conv", 1, &p, OnOffText);
|
|
PCMessage("D Range SP", 1, &p);
|
|
PCMessage("D Range HP", 1, &p);
|
|
PCMessage("Zone 2 Vol out", 1, &p);
|
|
PCMessage("?????", 1, &p);
|
|
PCMessage("Memory Guard", 1, &p, OnOffText);
|
|
PCMessage("SP set center", 1, &p);
|
|
PCMessage("SP set main", 1, &p);
|
|
PCMessage("SP set rear L/R", 1, &p);
|
|
PCMessage("SP set rear ct", 1, &p);
|
|
PCMessage("SP set front", 1, &p);
|
|
PCMessage("SP set LFE/Bass", 1, &p);
|
|
PCMessage("6 ch center", 1, &p);
|
|
PCMessage("6 ch sub", 1, &p);
|
|
PCMessage("Main level", 1, &p);
|
|
PCMessage("Test Mode", 1, &p);
|
|
PCMessage("?????", 1, &p);
|
|
PCMessage("Lvl 6 ch main L", 2, &p);
|
|
PCMessage("Lvl 6 ch main R", 2, &p);
|
|
PCMessage("Lvl 6 ch center", 2, &p);
|
|
PCMessage("Lvl 6 ch sl", 2, &p);
|
|
PCMessage("Lvl 6 ch sr", 2, &p);
|
|
PCMessage("Lvl 6 ch sbl", 2, &p);
|
|
PCMessage("Lvl 6 ch sbr", 2, &p);
|
|
PCMessage("Lvl 6 ch front l", 2, &p);
|
|
PCMessage("Lvl 6 ch front r", 2, &p);
|
|
PCMessage("Lvl 6 ch swfr", 2, &p);
|
|
PCMessage("Zone 3 Inp", 1, &p);
|
|
PCMessage("Zone 3 Mute", 1, &p);
|
|
PCMessage("Zone 3 Vol", 2, &p);
|
|
PCMessage("?????", 1, &p);
|
|
PCMessage("MultiCh Select", 1, &p);
|
|
PCMessage("MultiCh Surround", 1, &p);
|
|
PCMessage("SP Set SW1", 1, &p);
|
|
PCMessage("SP Set Crossover", 1, &p);
|
|
PCMessage("Component OSD", 1, &p, OnOffText);
|
|
PCMessage("PB/SB Select", 1, &p);
|
|
}
|
|
printf("\n");
|
|
Console_SetCursorVisibility(priorState);
|
|
}
|
|
}
|
|
|
|
|
|
void ProcessKeyboard(void) {
|
|
static uint32_t spin = 0;
|
|
bool cmdFound = false;
|
|
|
|
Console_SetCursor(0, -1);
|
|
if (spin++ % 16 == 0)
|
|
EmitSpinner();
|
|
if (CS_KeyHit()) {
|
|
int c = CS_GetChar();
|
|
switch (c) {
|
|
case '?':
|
|
EmitRuntimeHelp();
|
|
break;
|
|
case '/':
|
|
ShowAllStatusInfo();
|
|
break;
|
|
case '\x1B':
|
|
UserWantsToExitCanSniff = true;
|
|
break;
|
|
case 'S':
|
|
avr.Set_RTS_State(TRUE);
|
|
Console_SetCursor(0, -1);
|
|
printf("RTS set ON\n");
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
break;
|
|
case 's':
|
|
avr.Set_RTS_State(FALSE);
|
|
Console_SetCursor(0, -1);
|
|
printf("RTS set OFF\n");
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
break;
|
|
default:
|
|
for (int i = 0; i < sizeof(UserCommands) / sizeof(UserCmd_T); i++) {
|
|
if (UserCommands[i].Char == c) {
|
|
ProcessSerialQueue((const uint8_t *)UserCommands[i].TxMsg.pMsg, UserCommands[i].TxMsg.MsgLen);
|
|
cmdFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!cmdFound) {
|
|
Console_SetCursor(0, -1);
|
|
printf("Unrecognized command '%c' (0x%02X)\n", isprint(c) ? c : '.', (unsigned char)c);
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
void GetProgName(char *name) {
|
|
char *p = strrchr(name, '\\');
|
|
if (p) {
|
|
p++;
|
|
} else {
|
|
p = name;
|
|
}
|
|
strcpy_s(progname, MAXTEXTLEN, p);
|
|
p = strrchr(progname, '.');
|
|
if (0 == stricmp(p, ".exe")) {
|
|
*p = '\0';
|
|
}
|
|
}
|
|
|
|
|
|
void EmitCommandLineHelp() {
|
|
printf("%s [options] by Smartware Computing\n", progname);
|
|
printf(" options:\n");
|
|
printf(" -C=X[,yyyy] Set to Com port X to baud rate yyyy\n");
|
|
printf(" Defaults baud is %d\n", avrBaud);
|
|
printf("\n");
|
|
if (avrOnPort == COM_NO_PORT) {
|
|
EnumerateComPorts();
|
|
}
|
|
exit(EXIT_OK);
|
|
}
|
|
|
|
|
|
|
|
/******************************************************/
|
|
/* m a i n ( ) */
|
|
/******************************************************/
|
|
|
|
int __cdecl main(int argc, char *argv[]) {
|
|
progStartTime = timeGetTime();
|
|
Console_Init();
|
|
|
|
GetProgName(argv[0]);
|
|
// Change the colors...
|
|
// SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_INTENSITY);
|
|
for (int i = 1; i < argc; i++) {
|
|
int param1, param2;
|
|
if (1 == sscanf_s(argv[i], "-C=%d", ¶m1)) {
|
|
avrOnPort = param1;
|
|
} else if (2 == sscanf_s(argv[i], "-C=%d,%d", ¶m1, ¶m2)) {
|
|
avrOnPort = param1;
|
|
avrBaud = param2;
|
|
} else {
|
|
printf("***** Unrecognized command '%s' *****\n", argv[i]);
|
|
EmitCommandLineHelp();
|
|
exit(EXIT_IllegalOption);
|
|
}
|
|
}
|
|
if (argc == 0 || avrOnPort == COM_NO_PORT) {
|
|
EmitCommandLineHelp();
|
|
}
|
|
|
|
Console_Cls();
|
|
if (!SetConsoleCtrlHandler(ControlIntercept, TRUE)) {
|
|
printf("WARN: Cannot install Console Control Handler\n");
|
|
}
|
|
|
|
if (AttachToSerialPort()) {
|
|
printf("AVR - a command shell utility for a Yamaha RX-2400 AVR by D.Smart\n");
|
|
printf("Attached to Serial Port on COM%i at %i baud\n", avrOnPort, avrBaud);
|
|
Console_WriteAt(0, scrollTop - 1, "----------------------------------------");
|
|
|
|
do {
|
|
ProcessKeyboard();
|
|
/* bool anyRcvdMsg = */ ProcessSerialReceive();
|
|
ProcessSerialQueue();
|
|
ProcessWindowsMessage();
|
|
} while (!UserWantsToExitCanSniff);
|
|
DetachSerialPort();
|
|
} else {
|
|
printf("Failed to attach to Serial Port on COM%i\n", avrOnPort);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
void SetData(uint8_t *targ, const uint8_t *string, size_t len = 0) {
|
|
uint8_t *p = (uint8_t *)string;
|
|
if (len == 0) len = strlen((const char *)string);
|
|
memcpy(targ, p, len);
|
|
}
|
|
|
|
// Dec2Hex
|
|
//
|
|
// Convert a number to a hex-ascii string
|
|
//
|
|
const uint8_t *Dec2Hex(uint32_t val, uint16_t numDigits) {
|
|
static uint8_t buf[16];
|
|
sprintf_s((char *)buf, 16, "%0*X", numDigits, val);
|
|
return buf;
|
|
}
|
|
|
|
// Hex2Dec
|
|
//
|
|
// All responses are pretty much Hex-ASCII, so
|
|
// we sometimes want to convert it to decimal
|
|
// This takes a buffer and converts the specified
|
|
// number of characters.
|
|
//
|
|
unsigned long Hex2Dec(uint8_t *p, int dig) {
|
|
unsigned long x = 0;
|
|
while (dig--) {
|
|
if (*p >= '0' && *p <= '9')
|
|
x = x * 16 + *p - '0';
|
|
else if (*p >= 'a' && *p <= 'f')
|
|
x = x * 16 + 0x0a + *p - 'a';
|
|
else if (*p >= 'A' && *p <= 'F')
|
|
x = x * 16 + 0x0a + *p - 'A';
|
|
p++;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
|
|
bool CheckTheChecksum(uint8_t *szBuffer, uint32_t num) {
|
|
uint8_t sum = 0;
|
|
for (uint16_t i = 1; i < num - 3; i++) {
|
|
sum += szBuffer[i];
|
|
}
|
|
uint8_t cksum = (uint8_t)Hex2Dec(&szBuffer[num - 3], 2);
|
|
//printf("CheckSum: %02X v. %c%c\n", sum, szBuffer[num - 3], szBuffer[num - 2]);
|
|
return (sum == cksum);
|
|
}
|
|
|
|
// ProcessResponse
|
|
//
|
|
// @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]
|
|
//
|
|
void ProcessResponse(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[MAXTEXTLEN];
|
|
(void)len; // not used
|
|
|
|
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].fncHelper) {
|
|
(*MessageHandlers[i].fncHelper)(rcmd, rdat, szBuffer, len);
|
|
}
|
|
if (MessageHandlers[i].showAll) {
|
|
ShowAllStatusInfo();
|
|
}
|
|
}
|
|
}
|
|
Console_SetCursor(0, -1);
|
|
if (!found) {
|
|
sprintf_s(buf, MAXTEXTLEN, "type: %X, guard: %X, cmd: %02X, data: %02X", type, guard, rcmd, rdat);
|
|
Console_Write(buf);
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
}
|
|
switch (rcmd) {
|
|
case 0x20: // Power status
|
|
// SetData(&avrStatus.config.DT8, Dec2Hex(rdat, 1));
|
|
// sprintf_s(buf, MAXTEXTLEN, "Zone Power: %s\n", ZonePower(rdat));
|
|
// Console_Write(buf);
|
|
// Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
// ShowAllStatusInfo();
|
|
// break;
|
|
case 0x23: // Mute
|
|
// SetData(&avrStatus.config.DT12, Dec2Hex(rdat, 1));
|
|
// sprintf_s(buf, MAXTEXTLEN, "Mute: %s\n", OnOffText(rdat));
|
|
// Console_Write(buf);
|
|
// Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
// ShowAllStatusInfo();
|
|
// break;
|
|
case 0x25: // Zone 2 Mute
|
|
// SetData(&avrStatus.config.DT14, Dec2Hex(rdat, 1));
|
|
// sprintf_s(buf, MAXTEXTLEN, "Zone 2 Mute: %s\n", OnOffText(rdat));
|
|
// Console_Write(buf);
|
|
// Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
// ShowAllStatusInfo();
|
|
// break;
|
|
case 0x26: // Master Volume
|
|
// RxMasterVolStatus(rcmd, rdat, szBuffer, len);
|
|
// SetData(&avrStatus.config.DT15, Dec2Hex(rdat, 2));
|
|
// sprintf_s(buf, MAXTEXTLEN, "Vol: %s\n", VolumeDB(rdat));
|
|
// Console_Write(buf);
|
|
// Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
// ShowAllStatusInfo();
|
|
// break;
|
|
case 0x28: // Program
|
|
// SetData(&avrStatus.config.DT19, Dec2Hex(rdat, 2));
|
|
// sprintf_s(buf, MAXTEXTLEN, "Prog: %s\n", ProgramName(rdat));
|
|
// Console_Write(buf);
|
|
// Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
// ShowAllStatusInfo();
|
|
break;
|
|
case 0x82: // Night Mode
|
|
// SetData(&avrStatus.config.DT27, Dec2Hex(rdat, 1));
|
|
// sprintf_s(buf, MAXTEXTLEN, "Night Mode: %s\n", OnOffText(rdat));
|
|
// Console_Write(buf);
|
|
// Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
// ShowAllStatusInfo();
|
|
break;
|
|
case 0x36: // DC1 Trigger
|
|
// SetData(&avrStatus.config.DT39, Dec2Hex(rdat, 1));
|
|
// sprintf_s(buf, MAXTEXTLEN, "Trigger Out 1: %s\n", OnOffText(rdat));
|
|
// Console_Write(buf);
|
|
// Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
// ShowAllStatusInfo();
|
|
break;
|
|
case 0x3C: // DC2 Trigger
|
|
// SetData(&avrStatus.config.DT45, Dec2Hex(rdat, 1));
|
|
// sprintf_s(buf, MAXTEXTLEN, "Trigger Out 2: %s\n", OnOffText(rdat));
|
|
// Console_Write(buf);
|
|
// Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
// ShowAllStatusInfo();
|
|
break;
|
|
case 0xA1: // Zone 3 Mute
|
|
// //SetData(&avrStatus.config.DT14, Dec2Hex(rdat, 1));
|
|
// sprintf_s(buf, MAXTEXTLEN, "Zone 3 Mute: %s\n", OnOffText(rdat));
|
|
// Console_Write(buf);
|
|
// Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
// ShowAllStatusInfo();
|
|
break;
|
|
|
|
default: // Everything not yet handled
|
|
// sprintf_s(buf, MAXTEXTLEN, "type: %X, guard: %X, cmd: %02X, data: %02X", type, guard, rcmd, rdat);
|
|
// Console_Write(buf);
|
|
// Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// AnalyzeResponse
|
|
//
|
|
// Given a response string, typically of the form:
|
|
// [11] .... [03]
|
|
// [12] .... [03]
|
|
// ... etc
|
|
//
|
|
//
|
|
void AnalyzeResponse(uint8_t *szBuffer, uint32_t num) {
|
|
switch (szBuffer[0]) {
|
|
case 0x02: // STX
|
|
ProcessResponse(szBuffer, num);
|
|
break;
|
|
case 0x11: // DC1
|
|
break;
|
|
case 0x12: // DC2
|
|
if (CheckTheChecksum(szBuffer, num)) {
|
|
if (num == 21) {
|
|
memcpy(&avrStatus.header, &szBuffer[1], sizeof(AVR_StatusHeader_T));
|
|
num = Hex2Dec(&avrStatus.header.length[0], 2);
|
|
memcpy(&avrStatus.config.DT0, &szBuffer[9], num); // Copy bits of the config
|
|
avrStatus.headerValid = true;
|
|
} else if (num == 150) {
|
|
memcpy(&avrStatus.header, &szBuffer[1], sizeof(AVR_StatusHeader_T));
|
|
num = Hex2Dec(&avrStatus.header.length[0], 2);
|
|
memcpy(&avrStatus.config.DT0, &szBuffer[9], num); // Copy the config
|
|
|
|
//memcpy(&avrStatus.header, &szBuffer[1], sizeof(AVR_StatusHeader_T) + sizeof(AVR_Configuration_T));
|
|
avrStatus.headerValid = true;
|
|
avrStatus.configValid = true;
|
|
} else {
|
|
printf("***** Received message of unexpected length [%u]\n", num);
|
|
}
|
|
ShowAllStatusInfo();
|
|
} else {
|
|
printf("Checksum failure on Status Header\n");
|
|
}
|
|
//PrintConfiguration(szBuffer);
|
|
break;
|
|
case 0x14: // DC4 Extended Response
|
|
//DecodeExtended(szBuffer);
|
|
// Decode Extended response
|
|
break;
|
|
case '0':
|
|
//rcmd = Hex2Dec(&szBuffer[0], 2);
|
|
//DecodeString(rcmd, &szBuffer[2]);
|
|
break;
|
|
default:
|
|
//printf("[%d] %s\n", i, szBuffer);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ProcessSerialReceive
|
|
//
|
|
// All character sequences end with \x03 (this is the equiv of a <cr>)
|
|
//
|
|
//
|
|
bool ProcessSerialReceive() {
|
|
bool anythingReceived = false;
|
|
uint8_t rcv_buff[MAXTEXTLEN] = { 0 };
|
|
static uint8_t messageBuf[MAXTEXTLEN] = { 0 };
|
|
static uint8_t *p = messageBuf; // used to fill the rcv_buff as data comes in
|
|
|
|
uint32_t num = avr.Read(rcv_buff, MAXTEXTLEN);
|
|
if (num) {
|
|
for (uint32_t i = 0; i < num; i++) {
|
|
*p = rcv_buff[i];
|
|
if (*p++ == '\x03') { // End of message
|
|
*p = '\0'; // null terminate it
|
|
EchoSerialRecv(messageBuf);
|
|
//
|
|
// @TODO Now do something with the received message
|
|
//
|
|
AnalyzeResponse(messageBuf, (uint32_t)strlen((char *)messageBuf));
|
|
|
|
p = messageBuf; // Reset the buffer for the next message, which might be in rcv_buff
|
|
*p = '\0';
|
|
anythingReceived = true;
|
|
}
|
|
}
|
|
if (messageBuf[0]) {
|
|
//EmitBuffer("~", messageBuf, 0, true); // Show them the partial receipt if anything is there
|
|
}
|
|
}
|
|
return anythingReceived;
|
|
}
|
|
|
|
|
|
|
|
void EnumerateComPorts() {
|
|
printf("Com Port Scan:\n");
|
|
int foundPorts = 0;
|
|
for (int pNum = COM_MIN_PORT; pNum < COM_MAX_PORT; pNum++) {
|
|
char cBuf[20]; // generously sized
|
|
|
|
sprintf_s(cBuf, sizeof(cBuf), "\\\\.\\COM%d", pNum);
|
|
bool portFound = false;
|
|
HANDLE port = CreateFile(cBuf, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
|
if (port == INVALID_HANDLE_VALUE) {
|
|
DWORD dwError = GetLastError();
|
|
if ((dwError == ERROR_ACCESS_DENIED) || (dwError == ERROR_GEN_FAILURE)
|
|
|| (dwError == ERROR_SHARING_VIOLATION) || (dwError == ERROR_SEM_TIMEOUT)) {
|
|
foundPorts++;
|
|
portFound = true;
|
|
}
|
|
} else {
|
|
foundPorts++;
|
|
portFound = true;
|
|
CloseHandle(port);
|
|
}
|
|
if (portFound) {
|
|
printf(" Com Port %d found.\n", pNum);
|
|
}
|
|
}
|
|
if (foundPorts == 0) {
|
|
printf(" No Com Ports found, perhaps you need to plug in an adapter?\n");
|
|
}
|
|
}
|
|
|
|
|
|
int DetachSerialPort() {
|
|
if (avr.IsOpen()) {
|
|
avr.Close();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int AttachToSerialPort() {
|
|
bool success = false;
|
|
if (avrOnPort >= COM_MIN_PORT && avrOnPort <= COM_MAX_PORT) {
|
|
char buf[20]; // generously sized.
|
|
|
|
sprintf_s(buf, sizeof(buf), "\\\\.\\COM%d", avrOnPort);
|
|
DWORD Access = GENERIC_WRITE | GENERIC_READ;
|
|
if (avr.Open(buf, avrBaud, 8, NOPARITY, ONESTOPBIT, Access)) {
|
|
success = true;
|
|
avr.Set_RTS_State(false);
|
|
Sleep(250);
|
|
avr.Set_RTS_State(true);
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
|
|
void Console_Init() {
|
|
hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
|
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) {
|
|
fprintf(stderr, "Error: Unable to get console buffer info. Code: %lu\n", GetLastError());
|
|
exit(1);
|
|
}
|
|
|
|
// Desired size (width x height)
|
|
COORD newSize;
|
|
newSize.X = consoleWidth; // columns
|
|
newSize.Y = consoleHeight; // rows
|
|
|
|
// Step 1: Shrink window if needed before shrinking buffer
|
|
SMALL_RECT tempWindow = csbi.srWindow;
|
|
tempWindow.Right = tempWindow.Left + (newSize.X - 1);
|
|
tempWindow.Bottom = tempWindow.Top + (newSize.Y - 1);
|
|
|
|
if (!SetConsoleWindowInfo(hStdout, TRUE, &tempWindow)) {
|
|
fprintf(stderr, "Error: Unable to temporarily resize window. Code: %lu\n", GetLastError());
|
|
exit(1);
|
|
}
|
|
|
|
// Step 2: Set new buffer size
|
|
if (!SetConsoleScreenBufferSize(hStdout, newSize)) {
|
|
fprintf(stderr, "Error: Unable to set console buffer size. Code: %lu\n", GetLastError());
|
|
exit(1);
|
|
}
|
|
|
|
// Step 3: Set final window size to match buffer
|
|
SMALL_RECT newWindow;
|
|
newWindow.Left = 0;
|
|
newWindow.Top = 0;
|
|
newWindow.Right = newSize.X - 1;
|
|
newWindow.Bottom = newSize.Y - 1;
|
|
|
|
if (!SetConsoleWindowInfo(hStdout, TRUE, &newWindow)) {
|
|
fprintf(stderr, "Error: Unable to set console window size. Code: %lu\n", GetLastError());
|
|
exit(1);
|
|
}
|
|
// end
|
|
|
|
wOldColorAttrs = csbi.wAttributes;
|
|
//SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_INTENSITY);
|
|
}
|
|
|
|
void Console_Close() {
|
|
SetConsoleTextAttribute(hStdout, wOldColorAttrs);
|
|
}
|
|
|
|
void Console_Cls() {
|
|
COORD coordScreen = { 0, 0 }; // home for the cursor
|
|
DWORD cCharsWritten;
|
|
DWORD dwConSize;
|
|
|
|
// Get the number of character cells in the current buffer.
|
|
if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) {
|
|
return;
|
|
}
|
|
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
|
|
// Fill the entire screen with blanks.
|
|
if (!FillConsoleOutputCharacter(hStdout, // Handle to console screen buffer
|
|
(TCHAR)' ', // Character to write to the buffer
|
|
dwConSize, // Number of cells to write
|
|
coordScreen, // Coordinates of first cell
|
|
&cCharsWritten)) { // Receive number of characters written
|
|
return;
|
|
}
|
|
// Get the current text attribute.
|
|
if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) {
|
|
return;
|
|
}
|
|
// Set the buffer's attributes accordingly.
|
|
if (!FillConsoleOutputAttribute(hStdout, // Handle to console screen buffer
|
|
csbi.wAttributes, // Character attributes to use
|
|
dwConSize, // Number of cells to set attribute
|
|
coordScreen, // Coordinates of first cell
|
|
&cCharsWritten)) { // Receive number of characters written
|
|
return;
|
|
}
|
|
// Put the cursor at its home coordinates.
|
|
SetConsoleCursorPosition(hStdout, coordScreen);
|
|
}
|
|
|
|
void Console_Write(const char *text) {
|
|
DWORD written;
|
|
GetConsoleScreenBufferInfo(hStdout, &csbi);
|
|
if (csbi.dwCursorPosition.Y >= (csbi.srWindow.Bottom - consoleScrollHeight)) {
|
|
//Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
}
|
|
WriteConsole(hStdout, text, (DWORD)strlen(text), &written, nullptr);
|
|
}
|
|
|
|
void Console_WriteAt(short x, short y, const char *text) {
|
|
Console_SetCursor(x, y);
|
|
DWORD written;
|
|
WriteConsole(hStdout, text, (DWORD)strlen(text), &written, nullptr);
|
|
}
|
|
|
|
void Console_SetCursor(short x, short y) {
|
|
GetConsoleScreenBufferInfo(hStdout, &csbi);
|
|
csbi.dwCursorPosition.X = (short)((x < 0) ? csbi.srWindow.Right + x : x);
|
|
csbi.dwCursorPosition.Y = (short)((y < 0) ? csbi.srWindow.Bottom + y : y);
|
|
SetConsoleCursorPosition(hStdout, csbi.dwCursorPosition);
|
|
}
|
|
|
|
void Console_ScrollBottomRegion(short topLine, short bottomLine) {
|
|
GetConsoleScreenBufferInfo(hStdout, &csbi);
|
|
if (topLine < 0) topLine = csbi.srWindow.Bottom + topLine;
|
|
if (bottomLine < 0) bottomLine = csbi.srWindow.Bottom + bottomLine;
|
|
SMALL_RECT scrollRect = { 0, topLine, csbi.dwMaximumWindowSize.X-1, bottomLine };
|
|
COORD dest = { 0, topLine - 1 };
|
|
CHAR_INFO fill = { ' ', { FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE } };
|
|
ScrollConsoleScreenBuffer(hStdout, &scrollRect, &scrollRect, dest, &fill);
|
|
putch('\r'); // Cursor to left margin
|
|
}
|
|
|
|
bool Console_AdvanceToNextLineIfNotRoomFor(short x, int scroll) {
|
|
bool advanced = false;
|
|
GetConsoleScreenBufferInfo(hStdout, &csbi);
|
|
if (csbi.dwCursorPosition.X + x > csbi.dwMaximumWindowSize.X) {
|
|
advanced = true;
|
|
if (scroll == 1) {
|
|
Console_ScrollBottomRegion(scrollTop, scrollBot);
|
|
} else {
|
|
csbi.dwCursorPosition.Y++;
|
|
}
|
|
Console_SetCursor(0, csbi.dwCursorPosition.Y);
|
|
}
|
|
return advanced;
|
|
}
|
|
|
|
// Console_SetCursorVisibility
|
|
//
|
|
// Set the state of the cursor and provide the prior state so it
|
|
// can be restored
|
|
//
|
|
// @param[in] bool the desired state, true is visible
|
|
// @returns the prior state, true is visible
|
|
//
|
|
bool Console_SetCursorVisibility(bool visible) {
|
|
CONSOLE_CURSOR_INFO cursorInfo;
|
|
bool priorState = true;
|
|
|
|
if (!GetConsoleCursorInfo(hStdout, &cursorInfo)) {
|
|
// printf("***** Error: Unable to get cursor info.\n");
|
|
return priorState;
|
|
}
|
|
priorState = cursorInfo.bVisible;
|
|
cursorInfo.bVisible = visible; // true = show, false = hide
|
|
if (!SetConsoleCursorInfo(hStdout, &cursorInfo)) {
|
|
// std::cerr << "Error: Unable to set cursor info.\n";
|
|
}
|
|
return priorState;
|
|
} |