Reworking the AVR specific stuff into an AVRInterface class.

This commit is contained in:
2026-01-24 16:43:07 -06:00
parent 2ba02318db
commit 30f4047b7c
8 changed files with 298 additions and 20 deletions

View File

@@ -24,7 +24,7 @@ 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
const uint32_t retryInterval = 1000; // ms
// Each DT is the hex-character from the stream
//
@@ -219,13 +219,13 @@ int DetachSerialPort();
// @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);
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 *messageToSend;
DWORD len;
uint16_t len;
} SerialQueue_T;
static SerialQueue_T serialQueue[SERIALQUEUESIZE];
@@ -241,7 +241,7 @@ static int serialQueueCount = 0;
// @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);
bool ProcessSerialQueue(const uint8_t *p = NULL, uint16_t len = 0);
// ProcessSerialReceive
@@ -257,11 +257,11 @@ unsigned long Hex2Dec(uint8_t *p, int dig);
void ShowAllStatusInfo();
bool UserWantsToExitCanSniff = false;
DWORD progStartTime;
DWORD progStartTime_ms;
typedef struct {
const char *pMsg;
DWORD MsgLen;
uint16_t MsgLen;
} Message_T;
typedef struct {
@@ -531,11 +531,11 @@ void ProcessWindowsMessage(void) {
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();
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 - progStartTime)/1000.0f, (int)strlen(p), prefix);
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)) {
@@ -575,7 +575,7 @@ void EchoSerialRecv(const uint8_t *pMsg) {
Console_ScrollBottomRegion();
}
bool SerialSend(const uint8_t *p, DWORD len) {
bool SerialSend(const uint8_t *p, uint16_t len) {
bool retVal = false;
Console_SetCursor(0, -1);
EmitBuffer("> ", p, len);
@@ -590,7 +590,7 @@ bool SerialSend(const uint8_t *p, DWORD len) {
return retVal;
}
bool ProcessSerialQueue(const uint8_t *p, DWORD len) {
bool ProcessSerialQueue(const uint8_t *p, uint16_t len) {
bool retVal = false; // assume fail
static bool freshData = false;
@@ -920,7 +920,7 @@ int __cdecl main(int argc, char *argv[]) {
short consoleHeight = 80;
short consoleScrollHeight = 30;
progStartTime = timeGetTime();
progStartTime_ms = timeGetTime();
MessageHandlerSanityCheck(); // If the table is bad, we exit here
UserCommandsSanityCheck(); // If the table is bad, we exit here
@@ -1174,7 +1174,7 @@ void EnumerateComPorts() {
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();
uint32_t dwError = GetLastError();
if ((dwError == ERROR_ACCESS_DENIED) || (dwError == ERROR_GEN_FAILURE)
|| (dwError == ERROR_SHARING_VIOLATION) || (dwError == ERROR_SEM_TIMEOUT)) {
foundPorts++;
@@ -1208,7 +1208,7 @@ int AttachToSerialPort() {
char buf[20]; // generously sized.
sprintf_s(buf, sizeof(buf), "\\\\.\\COM%d", avrOnPort);
DWORD Access = GENERIC_WRITE | GENERIC_READ;
uint32_t Access = GENERIC_WRITE | GENERIC_READ;
if (avr.Open(buf, avrBaud, 8, NOPARITY, ONESTOPBIT, Access)) {
success = true;
avr.Set_RTS_State(false);

View File

@@ -127,11 +127,13 @@
<ItemGroup>
<ClCompile Include="AVR.cpp" />
<ClCompile Include="AVRCommandDecoder.cpp" />
<ClCompile Include="AVRInterface.cpp" />
<ClCompile Include="ConsoleHandler.cpp" />
<ClCompile Include="SerialPort\SerialPort.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AVRCommandDecoder.h" />
<ClInclude Include="AVRInterface.h" />
<ClInclude Include="ConsoleHandler.h" />
<ClInclude Include="SerialPort\SerialPort.h" />
</ItemGroup>

View File

@@ -27,6 +27,9 @@
<ClCompile Include="ConsoleHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AVRInterface.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="SerialPort\SerialPort.h">
@@ -38,5 +41,8 @@
<ClInclude Include="ConsoleHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AVRInterface.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,159 @@
#include <memory.h>
#include <malloc.h>
#include "AVRInterface.h"
//AVRInterface::AVRInterface(int (*SendMessage)(const void *buffer, unsigned int bufferSize)) {
//}
AVRInterface::~AVRInterface() {
FreeMemory();
}
void AVRInterface::Tick(uint32_t now_ms) {
uint32_t elapsed_ms = now_ms - sentAtTime_ms;
switch (state) {
default:
case AVRState_T::stPoweringUp:
readyResponsReceived = false;
ProcessSerialQueue((uint8_t *)"\x11" "000" "\x03", 5); // Send the Ready Command
sentAtTime_ms = now_ms;
readyTries++;
state = stAwaitingReadyResponse;
break;
case stAwaitingReadyResponse:
if (readyResponsReceived) {
state = stReady;
} else if (elapsed_ms > RETRY_INTERVAL_ms) {
if (readyTries > MAXTRIES) {
// fail
} else {
state = stPoweringUp;
}
}
break;
case AVRState_T::stInitializing:
break;
case AVRState_T::stRetryInitializing:
break;
case AVRState_T::stAwaitingResponse:
break;
case AVRState_T::stReady:
ProcessSerialQueue();
break;
}
}
bool AVRInterface::HandleMessage(const uint8_t *buffer, uint16_t len) {
switch (state) {
case stAwaitingReadyResponse:
switch (buffer[0]) {
case 0x02: // STX <msg> ETX
break;
case 0x11: // DC1 <msg> ETX
break;
case 0x12: // DC2 <msg> ETX
if (CheckTheChecksum(buffer, len)) {
readyResponsReceived = true;
}
break;
case 0x14: // DC4 <extended response> ETX
break;
default:
break;
}
readyResponsReceived = true;
break;
case stReady:
break;
}
return true;
}
bool AVRInterface::Initialize() {
return true;
}
bool AVRInterface::IsOnline() {
return true;
}
bool AVRInterface::Power(AVRPower_T cmd) {
return true;
}
bool AVRInterface::MasterVolumeButton(AVRVolumeButton_T cmd) {
return true;
}
bool AVRInterface::Mute(AVRMute_T cmd) {
return true;
}
bool AVRInterface::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].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 ((*SendMethod)((const uint8_t *)serialQueue[0].messageToSend, serialQueue[0].len)) {
--serialQueueCount;
free(serialQueue[0].messageToSend);
serialQueue[0].messageToSend = NULL;
for (int i = 0; i < serialQueueCount; i++) {
serialQueue[i] = serialQueue[i + 1];
}
retVal = true;
}
}
return retVal;
}
void AVRInterface::FreeMemory() {
for (int i = 0; i < serialQueueCount; i++) {
if (serialQueue[0].messageToSend)
free(serialQueue[0].messageToSend);
}
}
bool AVRInterface::CheckTheChecksum(const uint8_t *szBuffer, uint32_t num) {
uint8_t sum = 0;
for (uint16_t i = 1; i < num - 3; i++) {
sum += szBuffer[i];
}
uint8_t cksum = (uint8_t)Hex2Dec(&szBuffer[num - 3], 2);
//printf("CheckSum: %02X v. %c%c\n", sum, szBuffer[num - 3], szBuffer[num - 2]);
return (sum == cksum);
}
// Hex2Dec
//
// All responses are pretty much Hex-ASCII, so
// we sometimes want to convert it to decimal
// This takes a buffer and converts the specified
// number of characters.
//
unsigned long AVRInterface::Hex2Dec(const 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;
}

View File

@@ -0,0 +1,111 @@
#pragma once
#include <stdint.h>
class AVRInterface {
public:
/// @brief
/// @param SendMessage is the function this AVRInterface calls to send a message to the device
///
AVRInterface(int (*SendMessage)(const uint8_t *buffer, uint16_t len))
: SendMethod(SendMessage) {};
~AVRInterface();
/// @brief When the system receives something from the device, give it to this function to handle it
/// @param buffer
/// @param len
/// @return true if it was handled
///
bool HandleMessage(const uint8_t *buffer, uint16_t len);
/// @brief Call this periodically so timed activities can be handled.
///
/// Every 1 or even 50 to 100 msec is ok.
///
/// @param millisec
///
void Tick(uint32_t millisec);
/// @brief Initialize the AVR interface and issue the ready command.
///
/// This is temporarily blocking since nothing else should run until ready
///
/// @return true if initialized
///
bool Initialize();
/// @brief determine if the device is ready
///
/// @return true if ready
///
bool IsOnline();
/// @brief Power on and off commands
///
typedef enum {
avrPowerOff,
avrPowerOn,
} AVRPower_T;
/// @brief Send the power command
/// @param cmd
/// @return true if sent
///
bool Power(AVRPower_T cmd);
// MasterVolumeButton
// Issues volume up and down commands to the AVR.
//
typedef enum {
avrVolumeUp,
avrVolumeDown,
} AVRVolumeButton_T;
bool MasterVolumeButton(AVRVolumeButton_T cmd);
// Mute, UnMute
typedef enum {
avrMute,
avrUnMute,
} AVRMute_T;
bool Mute(AVRMute_T cmd);
private:
uint32_t sentAtTime_ms;
typedef enum {
stPoweringUp,
stAwaitingReadyResponse,
stInitializing,
stRetryInitializing,
stReady,
stAwaitingResponse,
} AVRState_T;
AVRState_T state = stPoweringUp;
AVRState_T GetState() {
return state;
}
bool readyResponsReceived;
int readyTries;
#define RETRY_INTERVAL_ms 500
#define MAXTRIES 5
#define SERIALQUEUESIZE 5
typedef struct {
uint8_t *messageToSend;
uint16_t len;
} SerialQueue_T;
SerialQueue_T serialQueue[SERIALQUEUESIZE];
int serialQueueCount = 0;
bool ProcessSerialQueue(const uint8_t *p = NULL, uint16_t len = NULL);
int (*SendMethod)(const uint8_t *buffer, uint16_t bufferSize);
bool CheckTheChecksum(const uint8_t *szBuffer, uint32_t num);
unsigned long Hex2Dec(const uint8_t *p, int dig);
void FreeMemory();
};

View File

@@ -36,7 +36,7 @@ CSerialPort::~CSerialPort()
Close();
}
BOOL CSerialPort::Open(LPCTSTR PortName, DWORD BaudRate, BYTE ByteSize, BYTE Parity, BYTE StopBits, DWORD DesiredAccess)
BOOL CSerialPort::Open(LPCTSTR PortName, uint32_t BaudRate, BYTE ByteSize, BYTE Parity, BYTE StopBits, uint32_t DesiredAccess)
{
Close();
m_PortHandle = CreateFile(PortName, DesiredAccess, 0, NULL, OPEN_EXISTING, 0, 0);
@@ -72,7 +72,7 @@ BOOL CSerialPort::Open(LPCTSTR PortName, DWORD BaudRate, BYTE ByteSize, BYTE Par
SetCommState(m_PortHandle, &dcb);
COMMTIMEOUTS touts;
touts.ReadIntervalTimeout = MAXDWORD; // This, plus the zero timeouts causes immediate return
touts.ReadIntervalTimeout = UINT32_MAX; // This, plus the zero timeouts causes immediate return
touts.ReadTotalTimeoutMultiplier = 0;
touts.ReadTotalTimeoutConstant = 0;
touts.WriteTotalTimeoutConstant = 1;
@@ -104,7 +104,7 @@ BOOL CSerialPort::IsOpen()
return (m_PortHandle != INVALID_HANDLE_VALUE);
}
DWORD CSerialPort::Read(LPVOID Buffer, DWORD BufferSize)
uint32_t CSerialPort::Read(LPVOID Buffer, uint32_t BufferSize)
{
DWORD Res(0);
if (m_PortHandle != INVALID_HANDLE_VALUE)
@@ -114,7 +114,7 @@ DWORD CSerialPort::Read(LPVOID Buffer, DWORD BufferSize)
return Res;
}
DWORD CSerialPort::Write(const LPVOID Buffer, DWORD BufferSize)
uint32_t CSerialPort::Write(const LPVOID Buffer, uint32_t BufferSize)
{
DWORD Res(0);
if (m_PortHandle != INVALID_HANDLE_VALUE)

View File

@@ -32,12 +32,12 @@ public:
BOOL Get_DSR_State();
BOOL Get_CTS_State();
BOOL Get_CD_State();
virtual DWORD Write(const LPVOID Buffer, DWORD BufferSize);
virtual DWORD Read(LPVOID Buffer, DWORD BufferSize);
virtual uint32_t Write(const LPVOID Buffer, uint32_t BufferSize);
virtual uint32_t Read(LPVOID Buffer, uint32_t BufferSize);
virtual BOOL IsOpen();
virtual void Close();
// Use PortName usually "COM1:" ... "COM4:" note that the name must end by ":"
virtual BOOL Open(LPCTSTR PortName, DWORD BaudRate, BYTE ByteSize, BYTE Parity, BYTE StopBits, DWORD DesiredAccess = GENERIC_READ|GENERIC_WRITE);
virtual BOOL Open(LPCTSTR PortName, uint32_t BaudRate, BYTE ByteSize, BYTE Parity, BYTE StopBits, uint32_t DesiredAccess = GENERIC_READ|GENERIC_WRITE);
CSerialPort();
virtual ~CSerialPort();