Apart Concept 1 Serial Controller Program with modern UI
This commit is contained in:
commit
c4bde4c18c
103 changed files with 38385 additions and 0 deletions
133
src/protocol/Concept1Protocol.h
Normal file
133
src/protocol/Concept1Protocol.h
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
#pragma once
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <optional>
|
||||
|
||||
// Low-level, stateless helpers for the Apart Concept 1 RS-232 ASCII protocol.
|
||||
//
|
||||
// Port settings (fixed by the device): 19200 baud, 8 data bits, no parity,
|
||||
// 1 stop bit, no flow control. Every instruction ends with <CR> (0x0D).
|
||||
namespace Concept1 {
|
||||
|
||||
constexpr int kBaudRate = 19200;
|
||||
constexpr char kCr = '\r';
|
||||
constexpr char kLf = '\n';
|
||||
|
||||
// Volume levels: -79..0 dB, with -80 meaning "OFF".
|
||||
constexpr int kLevelOff = -80;
|
||||
constexpr int kLevelMin = -79;
|
||||
constexpr int kLevelMax = 0;
|
||||
|
||||
// Equalizer (bass/treble): -14..14 in steps of 2.
|
||||
constexpr int kEqMin = -14;
|
||||
constexpr int kEqMax = 14;
|
||||
constexpr int kEqStep = 2;
|
||||
|
||||
// Input gain: -20..14 in steps of 2.
|
||||
constexpr int kGainMin = -20;
|
||||
constexpr int kGainMax = 14;
|
||||
constexpr int kGainStep = 2;
|
||||
|
||||
enum class Command { Set, Get, Inc, Dec };
|
||||
|
||||
enum class Zone { None, Zone1, Zone2 };
|
||||
|
||||
enum class Source { A, B, C, D };
|
||||
|
||||
// All attributes understood by the Concept 1.
|
||||
enum class Attribute {
|
||||
MultiZone,
|
||||
ZoneLink,
|
||||
MusicLevel, // MSCLVL
|
||||
MicLevel, // MICLVL
|
||||
MaxMusicLevel, // MAXMSCLVL
|
||||
MaxMicLevel, // MAXMICLVL
|
||||
Select, // SELECT A/B/C/D
|
||||
EqBass, // EQBASS
|
||||
EqTreble, // EQTREB
|
||||
Standby, // STANDBY
|
||||
AutoLoudness, // AUTOLD
|
||||
PagingActive, // PAGACT
|
||||
InputGain, // IPGAIN (per source)
|
||||
Echo, // ECHO
|
||||
LineFeed, // LF
|
||||
BackSpace, // BS
|
||||
Header, // HEADER
|
||||
ValueFeedback, // VALFB
|
||||
Info, // INFO (GET only)
|
||||
SourceName, // SOURCENAME (per source)
|
||||
Serial, // SERIAL (GET only)
|
||||
HwVersion, // HWVRSN (GET only)
|
||||
SwVersion, // SWVRSN (GET only)
|
||||
Restore, // RESTORE (SET only)
|
||||
Unknown
|
||||
};
|
||||
|
||||
// Classification of a line received from the device.
|
||||
enum class ReplyKind {
|
||||
Value, // an attribute value, e.g. "MSCLVL ZONE1 -16"
|
||||
Info, // a single line of a GET INFO dump (also Value-shaped)
|
||||
Paging, // "PAGING ZONEx ON/OFF" or "PAGING ON/OFF"
|
||||
Acknowledge, // "Command Executed!" (also accepts the doc typo "Exicuted")
|
||||
PleaseCycle, // "Please Cycle Power!"
|
||||
PowerDown, // "POWER DOWN!"
|
||||
Standby, // bare "STANDBY ON" sent while not ready
|
||||
Error, // "ERROR: ...!"
|
||||
NotImplemented, // "Not Yet Implemented!"
|
||||
Echo, // an echoed instruction (when ECHO is on)
|
||||
Unknown
|
||||
};
|
||||
|
||||
struct ParsedReply {
|
||||
ReplyKind kind = ReplyKind::Unknown;
|
||||
Attribute attribute = Attribute::Unknown;
|
||||
Zone zone = Zone::None;
|
||||
std::optional<Source> source;
|
||||
QString rawText; // full original line (trimmed)
|
||||
QString textValue; // string value (source names, serial, versions, error text)
|
||||
std::optional<int> intValue; // numeric value where applicable (dB / eq / gain)
|
||||
bool boolValue = false; // for ON/OFF attributes
|
||||
bool hasBool = false; // whether boolValue is meaningful
|
||||
};
|
||||
|
||||
// --- String mapping helpers ---------------------------------------------
|
||||
QString attributeToken(Attribute attr); // e.g. "MSCLVL"
|
||||
Attribute attributeFromToken(const QString &token); // case-insensitive
|
||||
QString commandToken(Command cmd);
|
||||
QString zoneToken(Zone zone); // "ZONE1"/"ZONE2"/""
|
||||
QString sourceToken(Source src); // "A".."D"
|
||||
std::optional<Source> sourceFromToken(const QString &token);
|
||||
std::optional<Zone> zoneFromToken(const QString &token);
|
||||
|
||||
// --- Value validation / normalisation -----------------------------------
|
||||
int clampLevel(int value); // -80..0
|
||||
int normalizeEq(int value); // snap to nearest valid -14..14/2
|
||||
int normalizeGain(int value); // snap to nearest valid -20..14/2
|
||||
int clampStep(int step); // 1..10
|
||||
QString levelToDisplay(int level); // "OFF" or "-16 dB"
|
||||
QString levelToken(int level); // "OFF" or "-16" (protocol wire form)
|
||||
|
||||
// --- Command building ----------------------------------------------------
|
||||
// Builds a full instruction terminated with <CR>.
|
||||
QByteArray buildCommand(Command cmd, Attribute attr,
|
||||
Zone zone = Zone::None,
|
||||
std::optional<Source> source = std::nullopt,
|
||||
std::optional<QString> value = std::nullopt);
|
||||
|
||||
// Convenience builders.
|
||||
QByteArray buildGet(Attribute attr, Zone zone = Zone::None,
|
||||
std::optional<Source> source = std::nullopt);
|
||||
QByteArray buildSetBool(Attribute attr, bool on, Zone zone = Zone::None);
|
||||
QByteArray buildSetInt(Attribute attr, int value, Zone zone = Zone::None,
|
||||
std::optional<Source> source = std::nullopt);
|
||||
QByteArray buildSetString(Attribute attr, const QString &value,
|
||||
std::optional<Source> source = std::nullopt);
|
||||
QByteArray buildStep(Command incOrDec, Attribute attr, int step,
|
||||
Zone zone = Zone::None);
|
||||
|
||||
// --- Reply parsing -------------------------------------------------------
|
||||
// Parses a single line (without <CR>/<LF>) received from the device.
|
||||
ParsedReply parseReply(const QString &line);
|
||||
|
||||
} // namespace Concept1
|
||||
Loading…
Add table
Add a link
Reference in a new issue