Files
AVR/AVR Working w-o Decoder/AVR.cpp
2026-01-17 10:19:53 -06:00

1085 lines
27 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 "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;
// 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();
void ProcessSerialReceive(void);
void EnumerateComPorts();
unsigned long Hex2Dec(uint8_t *p, int dig);
bool UserWantsToExitCanSniff = false;
// For special cursor positioning
bool consoleInit = false;
HANDLE hStdout, hStdin;
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
WORD wOldColorAttrs; // Save the current console colors
void Console_Init();
void Console_Cls();
void Console_SetCursor(short x, short y);
void Console_Write(char *text);
void Console_WriteAt(short x, short y, char *text);
void Console_ScrollBottomRegion(short topLine, short bottomLine);
bool Console_AdvanceToNextLineIfNotRoomFor(short x, int scroll = -1);
uint8_t LastSentMessage[MAXTEXTLEN];
uint16_t LastSentMessageLen;
uint64_t LastSentMessageTime; // when the last message was sent
typedef struct {
const char Char;
const char *pDescription;
const char *pCommand;
int cmdLen;
} 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 Off", "\x02" "07E7F" "\x03", 7 },
{ '2', "Zone 2 On", "\x02" "07EBA" "\x03", 7 },
{ '@', "Zone 2 Off", "\x02" "07EBB" "\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", "", 0 },
{ '?', "Help on runtime commands", "", 0 },
{ 'S', "Set RTS", "", 0 },
{ 's', "Clear RTS", "", 0 },
{ '\x1B', "quit the program", "", 0 },
};
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 angle brackets.
//
// Consider line-wrapping to align the next line
//
void EmitBuffer(const char *prefix, const uint8_t *buf, bool appendReturn = false) {
int i = 0;
const char *p = (const char *)buf;
printf("[%3d]%s", (int)strlen(p), prefix);
while (*p) {
if (isprint(*p)) {
putchar(*p);
i++;
} else if (*p == '\r') {
putchar('\n');
Console_ScrollBottomRegion(-14, -1);
} else if (*p == '\n') {
// skip it
} else {
printf("[%02X]", (unsigned char)*p);
}
if ((i & 3) == 0) {
if (Console_AdvanceToNextLineIfNotRoomFor(12, 1)) {
printf(" ");
i = 0;
} else {
printf(" ");
}
}
p++;
}
if (appendReturn) {
putch('\r');
} else {
putch('\n');
Console_ScrollBottomRegion(-14, -1);
}
}
void EchoSerialRecv(const uint8_t *pMsg) {
Console_SetCursor(0, -3);
EmitBuffer("< ", pMsg);
Console_ScrollBottomRegion(-14, -1);
}
void SerialSend(const uint8_t *p, int len) {
Console_SetCursor(0, -3);
EmitBuffer("> ", p);
Console_ScrollBottomRegion(-14, -1);
if (avr.Write((const LPVOID)p, len) != len) {
Console_SetCursor(0, -3);
Console_Write("***** Failed to send. Port not open?");
Console_ScrollBottomRegion(-14, -1);
} else {
// If we send something, we expect a response within ?200ms? and if not we should try again, up to 5 times.
memcpy(LastSentMessage, p, len);
LastSentMessageTime = GetTickCount64();
LastSentMessageLen = len;
}
}
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, -3);
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(-14, -1);
}
}
// 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)(uint32_t val) = NULL) {
char buf[MAXTEXTLEN];
const char *p = buf;
if (fncHelper) {
// Get the binary value if we need it
uint32_t val = 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_Write(outBuf);
Console_AdvanceToNextLineIfNotRoomFor(28);
}
const char * BusyToText(uint32_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 * OnOffText(uint32_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%02X ?", (unsigned char)val);
}
return buf;
}
const char * InputText(uint32_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?";
}
}
// 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 ShowAll(void) {
if (avrStatus.headerValid) {
Console_SetCursor(0, 3);
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");
}
}
void ProcessKeyboard(void) {
static uint32_t spin = 0;
bool cmdFound = false;
Console_SetCursor(0, -3);
if (spin++ % 16 == 0)
EmitSpinner();
if (CS_KeyHit()) {
int c = CS_GetChar();
switch (c) {
case '?':
EmitRuntimeHelp();
break;
case '/':
ShowAll();
break;
case '\x1B':
UserWantsToExitCanSniff = true;
break;
case 'S':
avr.Set_RTS_State(TRUE);
Console_SetCursor(0, -3);
printf("RTS set ON\n");
Console_ScrollBottomRegion(-14, -1);
break;
case 's':
avr.Set_RTS_State(FALSE);
Console_SetCursor(0, -3);
printf("RTS set OFF\n");
Console_ScrollBottomRegion(-14, -1);
break;
default:
for (int i = 0; i < sizeof(UserCommands) / sizeof(UserCmd_T); i++) {
if (UserCommands[i].Char == c) {
SerialSend((const uint8_t *)UserCommands[i].pCommand, UserCommands[i].cmdLen);
cmdFound = true;
break;
}
}
if (!cmdFound) {
Console_SetCursor(0, -3);
printf("Unrecognized command '%c' (0x%02X)\n", isprint(c) ? c : '.', (unsigned char)c);
Console_ScrollBottomRegion(-14, -1);
}
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 EmitHelp() {
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[]) {
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", &param1)) {
avrOnPort = param1;
} else if (2 == sscanf_s(argv[i], "-C=%d,%d", &param1, &param2)) {
avrOnPort = param1;
avrBaud = param2;
} else {
printf("***** Unrecognized command '%s' *****\n", argv[i]);
EmitHelp();
exit(EXIT_IllegalOption);
}
}
if (argc == 0 || avrOnPort == COM_NO_PORT) {
EmitHelp();
}
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);
do {
ProcessKeyboard();
ProcessSerialReceive();
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) {
uint8_t *p = (uint8_t *)string;
while (*p) {
*targ++ = *p++;
}
}
// 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);
}
void ProcessResponse(uint8_t type, uint8_t guard, uint16_t cmd, uint16_t data) {
(void)type;
(void)guard;
char buf[MAXTEXTLEN];
switch (cmd) {
case 0x26:
sprintf_s(buf, MAXTEXTLEN, "Vol: %s", VolumeDB(data));
SetData(&avrStatus.config.DT15, Dec2Hex(data, 2));
Console_Write(buf);
ShowAll();
break;
default:
sprintf_s(buf, MAXTEXTLEN, "type: %X, guard: %X, cmd: %02X, data: %02X", type, guard, cmd, data);
Console_Write(buf);
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
{
// 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, guard;
uint16_t rcmd, rdat;
type = (uint8_t)Hex2Dec(&szBuffer[1], 1);
guard = (uint8_t)Hex2Dec(&szBuffer[2], 1);
rcmd = (uint16_t)Hex2Dec(&szBuffer[3], 2);
rdat = (uint16_t)Hex2Dec(&szBuffer[5], 2);
ProcessResponse(type, guard, rcmd, rdat);
//ShowType(typ);
//ShowGuard(grd);
//DecodeStatus(rcmd, rdat);
}
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);
}
ShowAll();
} 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>)
//
//
void ProcessSerialReceive() {
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';
}
}
if (messageBuf[0]) {
//EmitBuffer("~", messageBuf, true); // Show them the partial receipt if anything is there
}
} else {
// If we're waiting for a response to something we sent, and it's been more than 200ms, resend it
if (LastSentMessageTries > 0) {
if ((GetTickCount64() - LastSentMessageTime) > 200) {
LastSentMessageLen && (GetTickCount64() - LastSentMessageTime) > 200);
SerialSend(LastSentMessage, LastSentMessageLen);
}
}
}
}
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);
GetConsoleScreenBufferInfo(hStdout, &csbiInfo);
wOldColorAttrs = csbiInfo.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;
CONSOLE_SCREEN_BUFFER_INFO csbi;
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(char *text) {
DWORD written;
WriteConsole(hStdout, text, (DWORD)strlen(text), &written, nullptr);
}
void Console_WriteAt(short x, short y, 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, &csbiInfo);
csbiInfo.dwCursorPosition.X = (short)((x < 0) ? csbiInfo.srWindow.Right + x : x);
csbiInfo.dwCursorPosition.Y = (short)((y < 0) ? csbiInfo.srWindow.Bottom + y : y);
SetConsoleCursorPosition(hStdout, csbiInfo.dwCursorPosition);
}
void Console_ScrollBottomRegion(short topLine, short bottomLine) {
GetConsoleScreenBufferInfo(hStdout, &csbiInfo);
if (topLine < 0) topLine = csbiInfo.srWindow.Bottom + topLine;
if (bottomLine < 0) bottomLine = csbiInfo.srWindow.Bottom + bottomLine;
SMALL_RECT scrollRect = { 0, topLine, csbiInfo.dwMaximumWindowSize.X, bottomLine };
COORD dest = { 0, topLine - 1 };
CHAR_INFO fill = { ' ', { FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE } };
ScrollConsoleScreenBuffer(hStdout, &scrollRect, nullptr, dest, &fill);
}
bool Console_AdvanceToNextLineIfNotRoomFor(short x, int scroll) {
bool advanced = false;
GetConsoleScreenBufferInfo(hStdout, &csbiInfo);
if (csbiInfo.dwCursorPosition.X + x > csbiInfo.dwMaximumWindowSize.X) {
advanced = true;
if (scroll == 1) {
Console_ScrollBottomRegion(-14, -1);
} else {
csbiInfo.dwCursorPosition.Y++;
}
Console_SetCursor(0, csbiInfo.dwCursorPosition.Y);
}
return advanced;
}