1316 lines
43 KiB
C++
1316 lines
43 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"
|
||
#include "AVRInterface.h"
|
||
//#include "AVRCommandDecoder.h"
|
||
#include "ConsoleHandler.h"
|
||
|
||
enum
|
||
{
|
||
COM_NO_PORT = -1,
|
||
COM_MIN_PORT = 1,
|
||
COM_MAX_PORT = 99
|
||
};
|
||
CSerialPort avrPort;
|
||
int avrOnPort = COM_NO_PORT; // Serial Port 1, 2, ... taking note that some USB adapters can be up toward channel 11, 12, ...
|
||
unsigned avrBaud = 9600;
|
||
|
||
const uint32_t retryInterval = 1000; // ms
|
||
|
||
AVRInterface *avr;
|
||
|
||
// Each DT is the hex-character from the stream
|
||
//
|
||
//
|
||
typedef struct {
|
||
uint8_t DT0; // * Baud Rate '@'
|
||
uint8_t DT1; // * Receive Buffer 'E'
|
||
uint8_t DT2; // * Receive Buffer '0'
|
||
uint8_t DT3; // * '1'
|
||
uint8_t DT4; // * Command Timeout '9'
|
||
uint8_t DT5; // * '0'
|
||
uint8_t DT6; // * '0'
|
||
uint8_t DT7; // * System '0':Ok, '1':Busy
|
||
uint8_t DT8; // * Power 0:Off, 1:On
|
||
uint8_t DT9; // Input 0: Phono, 1:CD, 2:Tuner, 3:CD-R, 4:MD-Tape, 5:DVD, 6:D-TV, 7:Cbl, 9:VCR1, A:VCR2
|
||
uint8_t DT10; // 6ch input 0:Off, 1:On
|
||
uint8_t DT11; // Input Mode 0:AUTO, 2:DTS, 4:Analog, 5:Analog Only
|
||
uint8_t DT12; // Audio Mute 0:Off, 1:On
|
||
uint8_t DT13; // Zone2 Input 0: PHONO / 1: CD / 2: TUNER / 3: CD-R / 4: MD-TAPE / 5: DVD / 6: D-TV-LD / 7: CBL-SAT / 9: VCR1 / A: VCR2-DVR / C: V-AUX
|
||
uint8_t DT14; // Zone2 Mute 0: OFF / 1: ON
|
||
uint8_t DT15; // Master Volume Upper 4 bit
|
||
uint8_t DT16; // Master Volume Lower 4 bit
|
||
uint8_t DT17; // Zone2 Volume Upper 4 bit
|
||
uint8_t DT18; // Zone2 Volume Lower 4 bit
|
||
uint8_t DT19; // Program Upper 4 bit
|
||
uint8_t DT20; // Program Lower 4 bit
|
||
uint8_t DT21; // Effect 0: OFF / 1: ON
|
||
uint8_t DT22; // 6.1/ES key status 0: OFF / 1: MATRIX ON / 2: DISCRETE ON / 3: AUTO
|
||
uint8_t DT23; // OSD* 0: FULL / 1: SHORT / 2: OFF
|
||
uint8_t DT24; // Sleep 0: 120 / 2: 90 / 3: 60 / 4: 30 / 5: OFF
|
||
uint8_t DT25; // Tuner Page 0: Page A / 1: Page B / 2: Page C / 3: Page D / 4: PageE
|
||
uint8_t DT26; // Tuner No. 0: No.1 / 1: No.2 / 2: No.3 / 3: No.4 / 4: No.5 / 5: No.6 / 6: No.7 / 7: No.8
|
||
uint8_t DT27; // Night mode 0: OFF / 1: ON
|
||
uint8_t DT28; // Care
|
||
uint8_t DT29; // Speaker relay A 0: OFF / 1: ON
|
||
uint8_t DT30; // Speaker relay B 0: OFF / 1: ON
|
||
uint8_t DT31; // Playback 0: 6ch input / 1: Analog / 2: PCM / 3: DD*(except 2.0) / 4: DD(2.0) / 5: DD.Karaoke / 6: DD.EX / 7: DTS / 8: DTS-ES / 9: Other DIGITAL / A: DTS Analog Mute / B: DTS ES Discrete
|
||
uint8_t DT32; // Fs 0: Analog / 1: 32kHz / 2: 44.1kHz / 3: 48kiHz / 4: 64kHz / 5: 88.2kHz / 6: 96kHz / 7: Unknown B: DTS 96/24
|
||
uint8_t DT33; // EX/ES playback 0: OFF / 1: MATRIX ON / 2: DISCRETE ON
|
||
uint8_t DT34; // Thr / Bypass 0: Normal / 1: Bypass
|
||
uint8_t DT35; // RED dts 0: Release / 1: Wait
|
||
uint8_t DT36; // Head Phone 0: OFF / 1: ON
|
||
uint8_t DT37; // TUNER BAND 0: FM / 1: AM
|
||
uint8_t DT38; // TUNER TUNED 0: NOT TUNED / 1: TUNED
|
||
uint8_t DT39; // DC1 Control Out 0: LOW / 1: HIGH
|
||
|
||
uint8_t DT40; // Don’t care
|
||
uint8_t DT41; // Don't Care
|
||
uint8_t DT42; // 0-2 DC1 TRG Ctrl. 0: Zone1 / 1: Zone2 / 2: Zone1&2
|
||
uint8_t DT43; // 0/1 dts 96/24 0: OFF / 1: ON
|
||
uint8_t DT44; // 0-2 DC2 TRG Ctrl. 0: Zone1 / 1: Zone2 / 2: Zone1&2
|
||
uint8_t DT45; // 0/1 DC2 Trigger 0: LOW / 1: HIGH
|
||
uint8_t DT46; // SP B set 0: Zone1 / 1: Zone2
|
||
uint8_t DT47; // Zone 2 SP out 0: OFF / 1: ON
|
||
uint8_t DT48; // MAIN R Upper 4bit
|
||
uint8_t DT49; // Lower 4bit
|
||
uint8_t DT50; // MAIN L Upper 4bit
|
||
uint8_t DT51; // Lower 4bit
|
||
uint8_t DT52; // CENTER Upper 4bit
|
||
uint8_t DT53; // Lower 4bit
|
||
uint8_t DT54; // REAR R Upper 4bit
|
||
uint8_t DT55; // Lower 4bit
|
||
uint8_t DT56; // REAR L Upper 4bit
|
||
uint8_t DT57; // Lower 4bit
|
||
uint8_t DT58; // SUR BACK Upper 4bit
|
||
uint8_t DT59; // R Lower 4bit
|
||
uint8_t DT60; // SUR BACK Upper 4bit
|
||
uint8_t DT61; // L Lower 4bit
|
||
uint8_t DT62; // FRONT R Upper 4bit
|
||
uint8_t DT63; // Lower 4bit
|
||
uint8_t DT64; // FRONT L Upper 4bit
|
||
uint8_t DT65; // Lower 4bit
|
||
uint8_t DT66; // SWFR 1 Upper 4bit
|
||
uint8_t DT67; // Lower 4bit
|
||
uint8_t DT68; // Don't Care
|
||
uint8_t DT69; // Don't Care
|
||
uint8_t DT70; // Don't Care
|
||
uint8_t DT71; // Don't Care
|
||
uint8_t DT72; // Don't Care
|
||
uint8_t DT73; // Don't Care
|
||
uint8_t DT74; // LFE Lvl. SP Upper 4bit
|
||
uint8_t DT75; // Lower 4bit
|
||
uint8_t DT76; // LFE Lvl. HP Upper 4bit
|
||
uint8_t DT77; // Lower 4bit
|
||
uint8_t DT78; // Audio Delay Upper 4bit
|
||
uint8_t DT79; // Lower 4bit
|
||
|
||
uint8_t DT80; // Don't Care
|
||
uint8_t DT81; // Don't Care
|
||
uint8_t DT82; // Don't Care
|
||
uint8_t DT83; // Don't Care
|
||
uint8_t DT84; // Input mode set 0: AUTO / 1: LAST
|
||
uint8_t DT85; // Dimmer 0: -4 / 1: -3 / 2: -2 / 3: -1 / 4: 0
|
||
uint8_t DT86; // OSD Message
|
||
uint8_t DT87; // OSD shift Upper 4bit
|
||
uint8_t DT88; // Lower 4bit
|
||
uint8_t DT89; // Glay back 0: OFF / 1: AUTO
|
||
uint8_t DT90; // Video conversion 0: OFF / 1: ON
|
||
uint8_t DT91; // D. Range SP 0: MAX / 1: STD / 2: MIN
|
||
uint8_t DT92; // HP 0: MAX / 1: STD / 2: MIN
|
||
uint8_t DT93; // Zone 2 vol. Out
|
||
uint8_t DT94; // Don't Care
|
||
uint8_t DT95; // Memory guard 0: OFF / 1: ON
|
||
uint8_t DT96; // SP set Center 0: Large / 1: Small / 2: None
|
||
uint8_t DT97; // Main 0: Large / 1: Small
|
||
uint8_t DT98; // Rear L/R 0: Large / 1: Small / 2: None
|
||
uint8_t DT99; // Rear CT 0: Large / 1: Small / 2: None
|
||
uint8_t DT100; // Front 0: Yes / 1: None
|
||
uint8_t DT101; // LFE/BASS 0: SWFR / 1: Main / 2: Both
|
||
uint8_t DT102; // 6CH Center 0: Center / 1: Main
|
||
uint8_t DT103; // SWFR 0: SWFR / 1: Main
|
||
uint8_t DT104; // Main level 0: Normal / 1: -10dB
|
||
uint8_t DT105; // Test mode 0: OFF / 1: Dolby / 2: DTS
|
||
uint8_t DT106; // Don't Care
|
||
uint8_t DT107; // LVL 6CH MAIN L Upper 4bit
|
||
uint8_t DT108; // Lower 4bit
|
||
uint8_t DT109; // MAIN R Upper 4bit
|
||
uint8_t DT110; // Lower 4bit
|
||
uint8_t DT111; // CENTER Upper 4bit
|
||
uint8_t DT112; // Lower 4bit
|
||
uint8_t DT113; // SL Upper 4bit
|
||
uint8_t DT114; // Lower 4bit
|
||
uint8_t DT115; // SR Upper 4bit
|
||
uint8_t DT116; // Lower 4bit
|
||
uint8_t DT117; // SBL Upper 4bit
|
||
uint8_t DT118; // Lower 4bit
|
||
uint8_t DT119; // SBR Upper 4bit
|
||
uint8_t DT120; // Lower 4bit
|
||
uint8_t DT121; // FRONT L Upper 4bit
|
||
uint8_t DT122; // Lower 4bit
|
||
uint8_t DT123; // FRONT R Upper 4bit
|
||
uint8_t DT124; // Lower 4bit
|
||
uint8_t DT125; // SWFR Upper 4bit
|
||
uint8_t DT126; // Lower 4bit
|
||
uint8_t DT127; // 0 - C Z3 Input
|
||
uint8_t DT128; // 0/1 Z3 Mute
|
||
uint8_t DT129; // 0 - F Z3 Volume Upper 4bit
|
||
|
||
uint8_t DT130; // 0 - F Lower 4bit
|
||
uint8_t DT131; // Don't Care
|
||
uint8_t DT132; // MULTI_CH SELECT 00:6CH / 01:8CH TUNER / 02: 8CH CD / 04: 8CH CD-R / 05: 8CH DVD / 06: DTV / 07: 8CH CBL/SAT / 09: 8CH VCR1 / 0A: VCR2/DVR / 0C: VAUX
|
||
uint8_t DT133; // MULTI_CH SURROUND to 00: Surround / 01: Main
|
||
uint8_t DT134; // SP SET SW1 00: L-R / 01: F-R / 02: NONE
|
||
uint8_t DT135; // SP SET CROSSOVER 00: 40Hz / 01: 60Hz / 02: 80Hz / 03: 90Hz / 04: 100Hz / 05: 110Hz / 06: 120Hz / 07: 160Hz / 08: 200Hz
|
||
uint8_t DT136; // COMPONENT OSD 00: OFF / 01: ON
|
||
uint8_t DT137; // PB/SB SELECT 00: PR / 01: SB
|
||
|
||
uint8_t DT138[100]; // From here on is just buffer in case it sends more data
|
||
} AVR_Configuration_T;
|
||
|
||
|
||
|
||
typedef struct {
|
||
uint8_t type[5]; // Model ID
|
||
uint8_t version; // A-Z
|
||
uint8_t length[2]; // 1 - 255
|
||
} AVR_StatusHeader_T;
|
||
|
||
typedef struct {
|
||
bool headerValid;
|
||
bool configValid;
|
||
AVR_StatusHeader_T header;
|
||
AVR_Configuration_T config;
|
||
|
||
} AVR_Status_T;
|
||
|
||
//AVR_StatusHeader_T avrStatusHeader;
|
||
//AVR_Configuration_T avrConfigData;
|
||
AVR_Status_T avrStatus;
|
||
|
||
|
||
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, uint16_t len);
|
||
|
||
// Just big enough to hold an OSD message which is a 1 message command, 4 messages with text
|
||
#define SERIALQUEUESIZE 5
|
||
typedef struct {
|
||
uint8_t *message;
|
||
uint16_t 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, uint16_t len = 0);
|
||
|
||
|
||
// ProcessSerialReceive
|
||
//
|
||
// See if anything came in, and if so, process it.
|
||
//
|
||
// @returns true if a message was processed.
|
||
//
|
||
SerialQueue_T ProcessSerialReceive(void);
|
||
void HandleMessage(uint8_t *szBuffer, uint32_t num);
|
||
|
||
void EnumerateComPorts();
|
||
unsigned long Hex2Dec(uint8_t *p, int dig);
|
||
|
||
//void ShowAllStatusInfo();
|
||
void GetAndSendCustomMessage();
|
||
|
||
|
||
bool UserWantsToExitCanSniff = false;
|
||
DWORD progStartTime_ms;
|
||
|
||
typedef struct {
|
||
const char *pMsg;
|
||
uint16_t MsgLen;
|
||
} Message_T;
|
||
|
||
typedef struct {
|
||
const char Char;
|
||
const char *pDescription;
|
||
Message_T TxMsg;
|
||
} UserCmd_T;
|
||
|
||
// Runtime commands from the keyboard to send to the AVR
|
||
//
|
||
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} },
|
||
{ 'O', "OSD Test Message", },
|
||
{ 'T', "Tuning freq rqst", {"\x02" "22000" "\x03", 7} },
|
||
{ 'Y', "Zone 1 Vol rqst", {"\x02" "22001" "\x03", 7} },
|
||
{ 'y', "Zone 2 Vol rqst", {"\x02" "22002" "\x03", 7} },
|
||
{ 'U', "Zone 1 Input rqst", {"\x02" "22003" "\x03", 7} },
|
||
{ 'u', "Zone 2 Input rqst", {"\x02" "22004" "\x03", 7} },
|
||
{ 'I', "Zone 3 Vol rqst", {"\x02" "22005" "\x03", 7} },
|
||
{ 'i', "Zone 3 Input rqst", {"\x02" "22006" "\x03", 7} },
|
||
//{ '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" },
|
||
{ '/', "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
|
||
const char *TextFormatter; // used primarily for development printf(TextFormatter, value)
|
||
const char *(*fncValueToText)(uint8_t rDat);
|
||
} MessageHandler_T;
|
||
|
||
void UserCommandsSanityCheck() {
|
||
uint8_t usedKey[256] = { 0 };
|
||
bool fail = false;
|
||
|
||
size_t numCommands = sizeof(UserCommands) / sizeof(UserCmd_T);
|
||
for (size_t i = 0; i < numCommands; i++) {
|
||
usedKey[UserCommands[i].Char]++;
|
||
if (usedKey[UserCommands[i].Char] > 1) {
|
||
printf("UserCommandsSanityCheck: Command key %c used more than once\n", UserCommands[i].Char);
|
||
fail = true;
|
||
}
|
||
}
|
||
if (fail) {
|
||
printf("***** UserCommandsSanityCheck: Errors found in UserCommands table\n");
|
||
exit(EXIT_ConfigError);
|
||
}
|
||
}
|
||
|
||
#if 0
|
||
// rCmd: 2-ASCII Hex Bytes converted to uint8_t
|
||
// configOffset: offset into avrStatus.config.DTxx
|
||
// numToTransfer: number of bytes to transfer from message to config (0 = none)
|
||
// show all status
|
||
// fncHelper: optional function to call upon receipt
|
||
//
|
||
const MessageHandler_T MessageHandlers[] = {
|
||
//
|
||
// Configuration Map for Response Messages
|
||
//
|
||
// +--------------------------- rCmd
|
||
// | +----------------------- DT Block Offset
|
||
// | | +-------------------- Number of Bytes to transfer into the DT Block
|
||
// | | | +----------------- Force a 'show all' status screen update
|
||
// | | | |
|
||
// | | | | +-------- sprintf format string for the following Helper
|
||
// | | | | | +--- Helper to convert numeric value to text
|
||
// | | | | | |
|
||
{ 0x00, 7, 1, 1, "System Report: %s", BusyToText },
|
||
{ 0x01, 0, 0, 0, "Warning Report: %s", WarnToText },
|
||
{ 0x10, 31, 1, 1, "Playback Report: %s", PlaybackToText },
|
||
{ 0x11, 32, 1, 1, "Fs Report: %s", FsToText }, --
|
||
{ 0x12, 33, 1, 1, "Ex/Ex: %s", OffMatrixDiscreteText }, // EX/EX --
|
||
{ 0x13, 34, 1, 1, "Thr Bypass: %s", OffOnText }, // Thr / Bypass --
|
||
{ 0x14, 35, 1, 1, "RED dts: %s", ReleaseWaitText}, // RED dts --
|
||
{ 0x15, 38, 1, 1, "Tuner tuned: %s", NotTunedTunedText}, // Tuner tuned --
|
||
{ 0x16, 43, 1, 1, "DTS 96/24: %s", OffOnText}, // Dts 96/24
|
||
{ 0x20, 8, 0, 1, "Zone Power: %s", ZonePower },
|
||
{ 0x21, 9, 1, 1, "Input: %s", InputText}, // Input Source
|
||
{ 0x22, 11, 1, 1, "Input Mode: %s", InputModeText}, // Input Mode
|
||
{ 0x23, 12, 1, 1, "Mute: %s", OffOnText },
|
||
{ 0x24, 13, 1, 1, "Zone 2 Input: %s", InputText}, // Zone 2 Input Source
|
||
{ 0x25, 14, 1, 1, "Zone 2 Mute: %s", OffOnText },
|
||
{ 0x26, 15, 2, 1, "Volume: %s", VolumeDB },
|
||
{ 0x27, 17, 2, 1, "Zone 2 Vol: %s", VolumeDB}, // Zone 2 Vol
|
||
{ 0x28, 19, 2, 1, "Program: %s", ProgramName }, // Program --
|
||
{ 0x29, 25, 1, 1, "Tuner Page: %s", PresetLabelText}, // Tuner Page --
|
||
{ 0x2A, 26, 1, 1, "Tuner Preset: %s", PresetNumberText}, // Tuner Preset Number --
|
||
{ 0x2B, 23, 1, 1, "OSD: %s", OSDFullShortOffText}, // OSD --
|
||
{ 0x2C, 24, 1, 1, "Sleep: %s", SleepTimerText}, // Sleep Timer --
|
||
{ 0x2D, 22, 1, 1, "EX/ES(Key): %s", OffMatrixDiscreteAutoText}, // EX/ES(Key)
|
||
{ 0x2E, 29, 1, 1, "SP Relay A: ", OffOnText}, // Speaker Relay A
|
||
{ 0x2F, 30, 1, 1, "SP Relay B: ", OffOnText}, // Speaker Relay B
|
||
{ 0x30, 0, 0, 0, "Home Preset:%s", PresetLabelText }, // Preset A, B, ... F
|
||
{ 0x31, 0, 0, 0, "Home Memory:%s", PresetLabelText }, // Preset A, B, ... F
|
||
{ 0x32, 0, 0, 0, "Home Vol Preset: %s", PresetLabelText }, // Preset A, B, ... F
|
||
{ 0x33, 0, 0, 0, "Home Vol Memory: %s", PresetLabelText }, // Preset A, B, ... F
|
||
{ 0x34, 36, 1, 1, "Headphone: %s", OffOnText }, --
|
||
{ 0x35, 37, 1, 1, "FM/AM: %s", FMAMText }, --
|
||
{ 0x36, 39, 1, 1, "DC1 Trigger Out: %s", OffOnText }, --
|
||
{ 0x37, 0, 0, 0, "Home Zone 2 Vol Preset: %s", PresetLabelText },
|
||
{ 0x38, 0, 0, 0, "Home Zone 2 Vol: %s", PresetLabelText },
|
||
{ 0x39, 0, 0, 0, "Dual Mono: %s", MainSubAllText },
|
||
{ 0x3A, 42, 1, 1, "DC1 Trigger Control: %s", WhichZoneText }, --
|
||
{ 0x3B, 44, 1, 1, "DC2 Trigger Control: %s", WhichZoneText }, --
|
||
{ 0x3C, 45, 1, 1, "DC2 Trigger Out: %s", OffOnText }, --
|
||
{ 0x3D, 104, 0, 0, "Main Level: %s", Norm10dbDownText },
|
||
{ 0x3E, 46, 1, 1, "SP B Set: %s", Zone1Zone2Text },
|
||
{ 0x3F, 47, 1, 1, "Zone 2 Speaker: %s", OffOnText },
|
||
|
||
{ 0x40, 48, 2, 1, "Level Main R: %s", PM10dbText }, --
|
||
{ 0x41, 50, 2, 1, "Level Main L: %s", PM10dbText }, --
|
||
{ 0x42, 52, 2, 1, "Level Center: %s", PM10dbText }, --
|
||
{ 0x43, 54, 2, 1, "Level Rear R: %s", PM10dbText }, --
|
||
{ 0x44, 56, 2, 1, "Level Rear L: %s", PM10dbText }, --
|
||
{ 0x45, 58, 2, 1, "Level Sur Back R: %s", PM10dbText }, --
|
||
{ 0x46, 60, 2, 1, "Level Sur Back L: %s", PM10dbText }, --
|
||
{ 0x47, 62, 2, 1, "Level Front R: %s", PM10dbText }, --
|
||
{ 0x48, 64, 2, 1, "Level Front L: %s", PM10dbText }, --
|
||
{ 0x49, 66, 2, 1, "Level Swfr 1: %s", PM10dbText }, --
|
||
{ 0x4A, 0, 0, 0, "Level Swfr 2: %s", PM10dbText },
|
||
|
||
{ 0x50, 0, 0, 0, "Main L/R Bal: %s", BalanceText },
|
||
{ 0x51, 74, 2, 1, "LFE Level SP: %s", M20P0dbText }, --
|
||
{ 0x52, 76, 2, 1, "LFE Level HP: %s", M20P0dbText }, --
|
||
{ 0x53, 78, 2, 1, "Audio Delay: %s", ZeroTo160msText }, --
|
||
{ 0x54, 0, 0, 0, "SP Delay Center: %s", ZeroTo5msText },
|
||
{ 0x55, 0, 0, 0, "SP Delay Rear CT: %s", ZeroTo30msText },
|
||
|
||
{ 0x60, 84, 1, 1, "Input Mode: %s", AutoLastText }, --
|
||
{ 0x61, 85, 1, 1, "Dimmer: %s", M4To0Text }, --
|
||
{ 0x62, 87, 2, 1, "OSD Shift: %s", M5toP5Text }, --
|
||
{ 0x63, 89, 1, 1, "Gray Back: %s", OffAutoText }, --
|
||
{ 0x64, 91, 1, 1, "Dynamic Range SP: %s", MaxStdMinText }, --
|
||
{ 0x65, 92, 1, 1, "Dynamic Range HP: %s", MaxStdMinText }, --
|
||
{ 0x66, 93, 0, 0, "Zone 2 Vol out: %s", VarFixText }, --
|
||
{ 0x67, 0, 0, 0, "Zone 2 Mode: %s", Mode1Mode2Text },
|
||
{ 0x68, 95, 1, 1, "Mem Guard: %s", OffOnText },
|
||
{ 0x69, 90, 1, 1, "Video Conv: %s", OffOnText },
|
||
{ 0x6A, 136, 1, 1, "Comp OSD: %s", OffOnText },
|
||
{ 0x6B, 0, 0, 0, "Zone 3 Vol out: %s", VarFixText },
|
||
{ 0x70, 96, 1, 1, "Center Sp Size: %s", LSNText },
|
||
{ 0x71, 97, 1, 1, "Main Sp Size: %s", LSNText },
|
||
{ 0x72, 98, 1, 1, "Rear LR Sp Size: %s", LSNText },
|
||
{ 0x73, 99, 1, 1, "Sur Back Size: %s", LLSSNText },
|
||
{ 0x74, 100, 1, 1, "Front Sp: %s", YesNoneText },
|
||
{ 0x75, 101, 1, 1, "LFE Bass Out: %s", SwfrMainBothText }, --
|
||
{ 0x76, 134, 1, 1, "SW1: %s", LrFrNoneText },
|
||
|
||
{ 0x78, 102, 1, 1, "6 Ch Center: %s", CenterMainText },
|
||
{ 0x79, 103, 1, 1, "6 Ch Swfr: %s", SwfrMainText },
|
||
{ 0x7A, 133, 1, 1, "6 Ch Surround: %s", SurrMainText },
|
||
{ 0x7B, 0, 0, 0, "Multi Ch Select: %s", SixEightText },
|
||
{ 0x7E, 135, 1, 1, "SW Crossover", CrossOverText },
|
||
|
||
{ 0x80, 105, 1, 1, "Test Mode: %s", OffDolbyDspText }, --
|
||
{ 0x81, 0, 0, 0, "Analog Special: %s", OffOn2OnMultiText },
|
||
{ 0x82, 27, 1, 1, "Night Mode: %s", OffOnText }, --
|
||
|
||
{ 0x90, 0, 0, 0, "Multi Ch Level Main R: %s" , M10P10dbText }, --
|
||
{ 0x91, 0, 0, 0, "Multi Ch Level Main L: %s" , M10P10dbText }, --
|
||
{ 0x92, 0, 0, 0, "Multi Ch Level Center: %s" , M10P10dbText }, --
|
||
{ 0x93, 0, 0, 0, "Multi Ch Level Rear R: %s" , M10P10dbText }, --
|
||
{ 0x94, 0, 0, 0, "Multi Ch Level Rear L: %s" , M10P10dbText }, --
|
||
{ 0x95, 0, 0, 0, "Multi Ch Level Sur B R: %s", M10P10dbText }, --
|
||
{ 0x96, 0, 0, 0, "Multi Ch Level Sur B L: %s", M10P10dbText }, --
|
||
{ 0x97, 0, 0, 0, "Multi Ch Level Front R: %s", M10P10dbText }, --
|
||
{ 0x98, 0, 0, 0, "Multi Ch Level Front L: %s", M10P10dbText }, --
|
||
{ 0x99, 0, 0, 0, "Multi Ch Level Swfr 1: %s" , M20P0dbText }, --
|
||
{ 0x9A, 0, 0, 0, "Multi Ch Level Swfr 2: %s" , M20P0dbText },
|
||
|
||
{ 0xA1, 0, 0, 0, "Zone 3 Mute: %s\n", OffOnText }, --
|
||
};
|
||
|
||
void MessageHandlerSanityCheck() {
|
||
uint8_t usedCommands[256] = { 0 };
|
||
uint8_t blockOffset[256] = { 0 };
|
||
|
||
bool fail = false;
|
||
// Ensure that the MessageHandlers table is correct
|
||
for (int i = 0; i < sizeof(MessageHandlers) / sizeof(MessageHandlers[0]); i++) {
|
||
usedCommands[MessageHandlers[i].rCmd]++;
|
||
if (usedCommands[MessageHandlers[i].rCmd] > 1) {
|
||
printf("***** MessageHandler entry %d has duplicate rCmd of 0x%02X\n", i, MessageHandlers[i].rCmd);
|
||
fail = true;
|
||
}
|
||
blockOffset[MessageHandlers[i].configOffset]++;
|
||
if (MessageHandlers[i].configOffset != 0 && blockOffset[MessageHandlers[i].configOffset] > 1) {
|
||
printf("***** MessageHandler entry %d has duplicate configOffset of %d\n", i, MessageHandlers[i].configOffset);
|
||
fail = true;
|
||
}
|
||
|
||
if (MessageHandlers[i].numToTransfer > 2) {
|
||
printf("***** MessageHandler entry %d has invalid numToTransfer of %d\n", i, MessageHandlers[i].numToTransfer);
|
||
}
|
||
if (MessageHandlers[i].configOffset + MessageHandlers[i].numToTransfer > sizeof(AVR_Configuration_T)) {
|
||
printf("***** MessageHandler entry %d has invalid configOffset of %d\n", i, MessageHandlers[i].configOffset);
|
||
}
|
||
}
|
||
if (fail) {
|
||
printf("***** MessageHandler table sanity check failed. Exiting.\n");
|
||
exit(EXIT_ConfigError);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
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;
|
||
uint32_t now_ms = timeGetTime();
|
||
char txtBuf[MAXTEXTLEN] = "";
|
||
|
||
if (len == 0) len = strlen((const char *)buf);
|
||
sprintf_s(txtBuf, MAXTEXTLEN, "%7.3f: [%3d]%s", (float)(now_ms - progStartTime_ms)/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();
|
||
} else if (*p == '\n') {
|
||
// skip it
|
||
} else {
|
||
printf("[%02X]", (unsigned char)*p);
|
||
}
|
||
if ((i & 3) == 0) {
|
||
if (Console_AdvanceToNextLineIfNotRoomFor(12, 1)) {
|
||
//Console_ScrollBottomRegion();
|
||
printf(" "); // sized to get past the timestamp, length, and prefix
|
||
i = 0;
|
||
} else {
|
||
printf(" ");
|
||
}
|
||
}
|
||
p++;
|
||
}
|
||
if (appendReturn) {
|
||
Console_ScrollBottomRegion(); // putch('\r');
|
||
} else {
|
||
//putch('\n');
|
||
//Console_ScrollBottomRegion();
|
||
}
|
||
}
|
||
|
||
#if 0
|
||
void EchoSerialRecv(const uint8_t *pMsg) {
|
||
Console_SetCursor(0, -1);
|
||
EmitBuffer("< ", pMsg);
|
||
Console_ScrollBottomRegion();
|
||
}
|
||
#endif
|
||
|
||
bool SerialSend(const uint8_t *p, uint16_t len) {
|
||
bool retVal = false;
|
||
//Console_SetCursor(0, -1);
|
||
//EmitBuffer("> ", p, len);
|
||
//Console_ScrollBottomRegion();
|
||
if (avrPort.Write((const LPVOID)p, len) == len) {
|
||
retVal = true;
|
||
} else {
|
||
Console_WriteAt(0, -1, "***** Failed to send. Port not open?");
|
||
}
|
||
return retVal;
|
||
}
|
||
|
||
#if 0
|
||
bool ProcessSerialQueue(const uint8_t *p, uint16_t len) {
|
||
bool retVal = false; // assume fail
|
||
static bool freshData = false;
|
||
|
||
if (p && len) {
|
||
if (serialQueueCount < SERIALQUEUESIZE) {
|
||
serialQueue[serialQueueCount].message = (uint8_t *)malloc(len);
|
||
if (serialQueue[serialQueueCount].message) {
|
||
memcpy(serialQueue[serialQueueCount].message, p, len);
|
||
serialQueue[serialQueueCount].len = len;
|
||
serialQueueCount++;
|
||
retVal = true;
|
||
freshData = true;
|
||
}
|
||
}
|
||
}
|
||
if (serialQueueCount) {
|
||
if (SerialSend((const uint8_t *)serialQueue[0].message, serialQueue[0].len)) {
|
||
--serialQueueCount;
|
||
free(serialQueue[0].message);
|
||
for (int i = 0; i < serialQueueCount; i++) {
|
||
serialQueue[i] = serialQueue[i + 1];
|
||
}
|
||
retVal = true;
|
||
}
|
||
}
|
||
return retVal;
|
||
}
|
||
#endif
|
||
|
||
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 (avrPort.IsOpen()) {
|
||
Console_ScrollBottomRegion();
|
||
Console_SetCursor(0, -1);
|
||
printf(" Com Status: RTS: %-3s ", avrPort.Get_RTS_State() ? "ON" : "OFF");
|
||
printf("DTR: %-3s ", avrPort.Get_DTR_State() ? "ON" : "OFF");
|
||
printf("CTS: %-3s ", avrPort.Get_CTS_State() ? "ON" : "OFF");
|
||
printf("DSR: %-3s ", avrPort.Get_DSR_State() ? "ON" : "OFF");
|
||
printf("RI: %-3s", avrPort.Get_RI_State() ? "ON" : "OFF");
|
||
Console_ScrollBottomRegion();
|
||
Console_SetCursor(0, -1);
|
||
}
|
||
}
|
||
|
||
#if 0
|
||
// 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);
|
||
}
|
||
#endif
|
||
|
||
|
||
#if 0
|
||
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, OffOnText);
|
||
if (avrStatus.configValid) {
|
||
PCMessage("Input", 1, &p, InputText);
|
||
PCMessage("6 ch", 1, &p);
|
||
PCMessage("Inp mode", 1, &p);
|
||
PCMessage("Mute", 1, &p, OffOnText);
|
||
PCMessage("Zone 2", 1, &p, InputText);
|
||
PCMessage("Mute 2", 1, &p, OffOnText);
|
||
PCMessage("Volume", 2, &p, VolumeDB);
|
||
PCMessage("Volume 2", 2, &p, VolumeDB);
|
||
PCMessage("pgm", 2, &p);
|
||
PCMessage("effect", 1, &p, OffOnText);
|
||
PCMessage("6.1/es status", 1, &p);
|
||
PCMessage("OSD", 1, &p);
|
||
PCMessage("sleep", 1, &p);
|
||
PCMessage("Tuner Pg", 1, &p);
|
||
PCMessage("Tuner #", 1, &p);
|
||
PCMessage("Night", 1, &p, OffOnText);
|
||
PCMessage("?????", 1, &p);
|
||
PCMessage("Spkr A", 1, &p, OffOnText);
|
||
PCMessage("Spkr B", 1, &p, OffOnText);
|
||
PCMessage("Playback", 1, &p);
|
||
PCMessage("Fs", 1, &p);
|
||
PCMessage("Ex/Es", 1, &p);
|
||
PCMessage("Thr Bypass", 1, &p);
|
||
PCMessage("Red DTS", 1, &p);
|
||
PCMessage("Headph", 1, &p, OffOnText);
|
||
PCMessage("Tuner Band", 1, &p);
|
||
PCMessage("Tuner Tuned", 1, &p);
|
||
PCMessage("DC1 Control Out", 1, &p);
|
||
PCMessage("?????", 2, &p);
|
||
PCMessage("DC1 Trig Ctrl", 1, &p);
|
||
PCMessage("DTS 96/24", 1, &p, OffOnText);
|
||
PCMessage("DC2 Trig Ctrl", 1, &p);
|
||
PCMessage("DC2 Trig", 1, &p);
|
||
PCMessage("Spkr B Set", 1, &p);
|
||
PCMessage("Zone 2 SP out", 1, &p, OffOnText);
|
||
PCMessage("Main R", 2, &p);
|
||
PCMessage("Main L", 2, &p);
|
||
PCMessage("Center", 2, &p);
|
||
PCMessage("Rear R", 2, &p);
|
||
PCMessage("Rear L", 2, &p);
|
||
PCMessage("Sur Bk R", 2, &p);
|
||
PCMessage("Sur Bk L", 2, &p);
|
||
PCMessage("Front R", 2, &p);
|
||
PCMessage("Front L", 2, &p);
|
||
PCMessage("Sub", 2, &p);
|
||
PCMessage("?????", 6, &p);
|
||
PCMessage("LFE SP", 2, &p);
|
||
PCMessage("LFE HP", 2, &p);
|
||
PCMessage("Audio Delay", 2, &p);
|
||
PCMessage("?????", 4, &p);
|
||
PCMessage("Inp Mode Set", 1, &p);
|
||
PCMessage("Dimmer", 1, &p);
|
||
PCMessage("OSD Msg", 1, &p);
|
||
PCMessage("OSD Shift", 2, &p);
|
||
PCMessage("Gray Back", 1, &p);
|
||
PCMessage("Video Conv", 1, &p, OffOnText);
|
||
PCMessage("D Range SP", 1, &p);
|
||
PCMessage("D Range HP", 1, &p);
|
||
PCMessage("Zone 2 Vol out", 1, &p);
|
||
PCMessage("?????", 1, &p);
|
||
PCMessage("Memory Guard", 1, &p, OffOnText);
|
||
PCMessage("SP set center", 1, &p);
|
||
PCMessage("SP set main", 1, &p);
|
||
PCMessage("SP set rear L/R", 1, &p);
|
||
PCMessage("SP set rear ct", 1, &p);
|
||
PCMessage("SP set front", 1, &p);
|
||
PCMessage("SP set LFE/Bass", 1, &p);
|
||
PCMessage("6 ch center", 1, &p);
|
||
PCMessage("6 ch sub", 1, &p);
|
||
PCMessage("Main level", 1, &p);
|
||
PCMessage("Test Mode", 1, &p);
|
||
PCMessage("?????", 1, &p);
|
||
PCMessage("Lvl 6 ch main L", 2, &p);
|
||
PCMessage("Lvl 6 ch main R", 2, &p);
|
||
PCMessage("Lvl 6 ch center", 2, &p);
|
||
PCMessage("Lvl 6 ch sl", 2, &p);
|
||
PCMessage("Lvl 6 ch sr", 2, &p);
|
||
PCMessage("Lvl 6 ch sbl", 2, &p);
|
||
PCMessage("Lvl 6 ch sbr", 2, &p);
|
||
PCMessage("Lvl 6 ch front l", 2, &p);
|
||
PCMessage("Lvl 6 ch front r", 2, &p);
|
||
PCMessage("Lvl 6 ch swfr", 2, &p);
|
||
PCMessage("Zone 3 Inp", 1, &p);
|
||
PCMessage("Zone 3 Mute", 1, &p);
|
||
PCMessage("Zone 3 Vol", 2, &p);
|
||
PCMessage("?????", 1, &p);
|
||
PCMessage("MultiCh Select", 1, &p);
|
||
PCMessage("MultiCh Surround", 1, &p);
|
||
PCMessage("SP Set SW1", 1, &p);
|
||
PCMessage("SP Set Crossover", 1, &p);
|
||
PCMessage("Component OSD", 1, &p, OffOnText);
|
||
PCMessage("PB/SB Select", 1, &p);
|
||
}
|
||
printf("\n");
|
||
Console_SetCursorVisibility(priorState);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
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 'P':
|
||
avr->Power(AVRInterface::AVROnOff_E::eOn);
|
||
break;
|
||
case 'p':
|
||
avr->Power(AVRInterface::AVROnOff_E::eOff);
|
||
break;
|
||
case 'O':
|
||
avr->ProcessSerialQueue("\x02" "21000" "\x03", 7);
|
||
avr->ProcessSerialQueue("\x02" "3Test" "\x03", 7);
|
||
avr->ProcessSerialQueue("\x02" "3 Mes" "\x03", 7);
|
||
avr->ProcessSerialQueue("\x02" "3sage" "\x03", 7);
|
||
avr->ProcessSerialQueue("\x02" "3 WOW" "\x03", 7);
|
||
break;
|
||
case ':':
|
||
GetAndSendCustomMessage();
|
||
break;
|
||
case '?':
|
||
EmitRuntimeHelp();
|
||
break;
|
||
case '/':
|
||
avr->ReportAllStatus();
|
||
//ShowAllStatusInfo();
|
||
break;
|
||
case '\x1B':
|
||
UserWantsToExitCanSniff = true;
|
||
break;
|
||
case 'S':
|
||
avrPort.Set_RTS_State(TRUE);
|
||
Console_SetCursor(0, -1);
|
||
printf("RTS set ON");
|
||
Console_ScrollBottomRegion();
|
||
break;
|
||
case 's':
|
||
avrPort.Set_RTS_State(FALSE);
|
||
Console_SetCursor(0, -1);
|
||
printf("RTS set OFF");
|
||
Console_ScrollBottomRegion();
|
||
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);
|
||
avr->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)", isprint(c) ? c : '.', (unsigned char)c);
|
||
Console_ScrollBottomRegion();
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
void HexUppercase(char *p) {
|
||
const char *hex = "0123456789ABCDEF";
|
||
while (*p) {
|
||
if (*p >= 'a' && *p <= 'f')
|
||
*p = *p - 'a' + 'A';
|
||
if (NULL == strchr(hex, *p)) {
|
||
*p = '\0';
|
||
return;
|
||
}
|
||
p++;
|
||
}
|
||
}
|
||
|
||
void GetAndSendCustomMessage() {
|
||
char buf[20];
|
||
char msg[30];
|
||
Console_ScrollBottomRegion();
|
||
Console_ScrollBottomRegion();
|
||
Console_WriteAt(0, -2, "Enter Hex string to send: ");
|
||
gets_s(buf, sizeof(buf));
|
||
HexUppercase(buf);
|
||
if (strlen(buf) != 5) {
|
||
Console_WriteAt(0, -1, " Invalid. String must be exactly 5 HEX chars");
|
||
Console_ScrollBottomRegion();
|
||
} else {
|
||
Console_ScrollBottomRegion();
|
||
sprintf_s(msg, sizeof(msg), "\x02%s\x03", buf);
|
||
avr->ProcessSerialQueue(msg, strlen(msg));
|
||
}
|
||
}
|
||
|
||
|
||
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);
|
||
}
|
||
|
||
void InformationUpdate(AVRInterface::AVRMessageType_T type, const char *msg) {
|
||
char buf[MAXTEXTLEN] = "";
|
||
switch (type) {
|
||
case AVRInterface::AVRMessageType_T::mtStatus:
|
||
sprintf_s(buf, MAXTEXTLEN, "AVR Status: %-60s", msg);
|
||
Console_WriteAt(0, 1, buf);
|
||
break;
|
||
case AVRInterface::AVRMessageType_T::mtInfo:
|
||
Console_WriteAt(0, -1, msg);
|
||
Console_ScrollBottomRegion();
|
||
break;
|
||
case AVRInterface::AVRMessageType_T::mtModelInfo:
|
||
Console_WriteAt(0, 2, msg);
|
||
break;
|
||
case AVRInterface::AVRMessageType_T::mtStreamStart:
|
||
Console_SetCursor(0, 3);
|
||
// break; // fall through
|
||
case AVRInterface::AVRMessageType_T::mtStream:
|
||
Console_AdvanceToNextLineIfNotRoomFor(40); // @TODO hard-coded - ick
|
||
Console_Write(msg);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
/******************************************************/
|
||
/* m a i n ( ) */
|
||
/******************************************************/
|
||
|
||
// 0 Width
|
||
// +---------------------------------------------------------------+
|
||
// | Program banner information | 0
|
||
// | State machine status information starts on line 2 |
|
||
// | Overall information is on line 3 and onward |
|
||
// | |
|
||
// | |
|
||
// | |
|
||
// + Down near the bottom is the scroll region + 59
|
||
// | |
|
||
// | |
|
||
// | | 79
|
||
// +---------------------------------------------------------------+ 80
|
||
|
||
int __cdecl main(int argc, char *argv[]) {
|
||
short consoleWidth = 122;
|
||
short consoleHeight = 80;
|
||
short consoleScrollHeight = 30;
|
||
|
||
progStartTime_ms = timeGetTime();
|
||
// MessageHandlerSanityCheck(); // If the table is bad, we exit here
|
||
UserCommandsSanityCheck(); // If the table is bad, we exit here
|
||
|
||
Console_Init(consoleWidth, consoleHeight, consoleScrollHeight);
|
||
|
||
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 ");
|
||
printf("[COM%i at %i baud]", avrOnPort, avrBaud);
|
||
Console_WriteAt(0, consoleHeight - consoleScrollHeight -1, "----------------------------------------");
|
||
|
||
avr = new AVRInterface(SerialSend);
|
||
avr->RegisterInformationCallback(InformationUpdate);
|
||
|
||
do {
|
||
avr->Tick(timeGetTime());
|
||
ProcessKeyboard();
|
||
SerialQueue_T anyRcvdMsg = ProcessSerialReceive();
|
||
if (anyRcvdMsg.len) {
|
||
// Show to the user
|
||
//EchoSerialRecv(anyRcvdMsg.message);
|
||
|
||
// Let the AVR interface handle it first
|
||
bool showAllFlag = avr->HandleMessage(anyRcvdMsg.message, anyRcvdMsg.len);
|
||
|
||
if (showAllFlag) {
|
||
bool priorState = Console_SetCursorVisibility(false);
|
||
avr->ReportAllStatus();
|
||
Console_SetCursorVisibility(priorState);
|
||
}
|
||
// old way to parse the message
|
||
//HandleMessage(anyRcvdMsg.message, anyRcvdMsg.len);
|
||
}
|
||
|
||
//ProcessSerialQueue();
|
||
ProcessWindowsMessage();
|
||
} while (!UserWantsToExitCanSniff);
|
||
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);
|
||
}
|
||
|
||
|
||
#if 0
|
||
// ProcessReportResponse
|
||
//
|
||
// @param[in] szBuffer is the received message
|
||
// @param[in] len is the null terminated string length of the message
|
||
//
|
||
// Typical Message:
|
||
// '\x02' 'type' 'guard' 'rcmd0' 'rcmd1' 'rdat0' 'rdat1' '\x03'
|
||
// [0] [1] [2] [3] [4] [5] [6] [7]
|
||
//
|
||
void ProcessReportResponse(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].TextFormatter && MessageHandlers[i].fncValueToText) {
|
||
sprintf_s(buf, MAXTEXTLEN, MessageHandlers[i].TextFormatter, MessageHandlers[i].fncValueToText(rdat));
|
||
Console_Write(buf);
|
||
Console_ScrollBottomRegion();
|
||
}
|
||
if (MessageHandlers[i].showAll) {
|
||
ShowAllStatusInfo();
|
||
}
|
||
}
|
||
}
|
||
if (!found) {
|
||
Console_SetCursor(0, -1);
|
||
sprintf_s(buf, MAXTEXTLEN, "***** type: %X, guard: %X, cmd: %02X, data: %02X", type, guard, rcmd, rdat);
|
||
Console_Write(buf);
|
||
Console_ScrollBottomRegion();
|
||
}
|
||
}
|
||
#endif
|
||
|
||
|
||
// HandleMessage
|
||
//
|
||
// Given a response string, typically of the form:
|
||
// [11] .... [03]
|
||
// [12] .... [03]
|
||
// ... etc
|
||
//
|
||
//
|
||
void HandleMessage(uint8_t *szBuffer, uint32_t num) {
|
||
switch (szBuffer[0]) {
|
||
case 0x02: // STX
|
||
//ProcessReportResponse(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);
|
||
}
|
||
} else {
|
||
Console_WriteAt(0, -1, "Checksum failure on Status Header");
|
||
}
|
||
//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>)
|
||
//
|
||
//
|
||
SerialQueue_T ProcessSerialReceive() {
|
||
uint8_t partialRx[MAXTEXTLEN] = { 0 };
|
||
|
||
static uint8_t bufInUse = 0;
|
||
static uint8_t messageBuf[2][MAXTEXTLEN] = { 0 };
|
||
static uint8_t *p = messageBuf[bufInUse]; // used to fill the partialRx as data comes in
|
||
SerialQueue_T retInfo = { NULL, 0 };
|
||
|
||
uint32_t num = avrPort.Read(partialRx, MAXTEXTLEN);
|
||
if (num) {
|
||
for (uint32_t i = 0; i < num; i++) {
|
||
*p = partialRx[i];
|
||
if (*p++ == '\x03') { // End of message
|
||
*p = '\0'; // null terminate it
|
||
// It is ready to return now
|
||
retInfo.message = messageBuf[bufInUse];
|
||
retInfo.len = (uint16_t)(p - messageBuf[bufInUse]);
|
||
// Prepare the alternate buffer for the next message
|
||
bufInUse = (++bufInUse & 1);
|
||
p = messageBuf[bufInUse]; // Reset the buffer for the next message, which might be in partialRx
|
||
*p = '\0';
|
||
}
|
||
}
|
||
if (messageBuf[0]) {
|
||
//EmitBuffer("~", messageBuf, 0, true); // Show them the partial receipt if anything is there
|
||
}
|
||
}
|
||
return retInfo;
|
||
}
|
||
|
||
|
||
|
||
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) {
|
||
uint32_t 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 (avrPort.IsOpen()) {
|
||
avrPort.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);
|
||
uint32_t Access = GENERIC_WRITE | GENERIC_READ;
|
||
if (avrPort.Open(buf, avrBaud, 8, NOPARITY, ONESTOPBIT, Access)) {
|
||
success = true;
|
||
avrPort.Set_RTS_State(false);
|
||
Sleep(250);
|
||
avrPort.Set_RTS_State(true);
|
||
}
|
||
}
|
||
return success;
|
||
}
|
||
|