Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add functionality for MiniDSP 2x4HD #737

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
102 changes: 93 additions & 9 deletions MiniDSP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,34 @@
#include "MiniDSP.h"

void MiniDSP::ParseHIDData(USBHID *hid __attribute__ ((unused)), bool is_rpt_id __attribute__ ((unused)), uint8_t len, uint8_t *buf) {

constexpr uint8_t StatusInputCommand[] = {0x05, 0xFF, 0xDA};

// Only care about valid data for the MiniDSP 2x4HD.
if(HIDUniversal::VID != MINIDSP_VID || HIDUniversal::PID != MINIDSP_PID || len <= 4 || buf == nullptr)
return;

// Check if this is a status update.
// First byte is the length, we ignore that for now.
if(memcmp(buf + 1, StatusInputCommand, sizeof (StatusInputCommand)) == 0) {
// Check if this is a requested mute change.
if(buf[1] == 0x17){
// Response is of format [ length ] [ 0x17 ] [ muted ]
muted = (bool)buf[2];
}

// Check if this is a requested volume change.
if(buf[1] == 0x42){
// Response is of format [ length ] [ 0x42 ] [ volume ]
volume = buf[2];

}

constexpr uint8_t InputCommand[] = {0x05, 0xFF};

// Only deal with status updates from now on.
if(memcmp(buf + 1, InputCommand, sizeof (InputCommand)) != 0)
return;

if(buf[3] == 0xDA){
// Parse data.
// Response is of format [ length ] [ 0x05 0xFF 0xDA ] [ volume ] [ muted ].
const auto newVolume = buf[sizeof (StatusInputCommand) + 1];
const auto newIsMuted = (bool)buf[sizeof (StatusInputCommand) + 2];
const auto newVolume = buf[4];
const auto newIsMuted = (bool)buf[5];

const auto volumeChanged = newVolume != volume;
const auto mutedChanged = newIsMuted != muted;
Expand All @@ -52,15 +65,56 @@ void MiniDSP::ParseHIDData(USBHID *hid __attribute__ ((unused)), bool is_rpt_id
if(pFuncOnMutedChange != nullptr && mutedChanged)
pFuncOnMutedChange(muted);
}


// Check if this is an input source update.
if(buf[3] == 0xA9 || buf[3] == 0xD9){
// Parse data.
// Response is of format [ length ] [ 0x05 0xFF 0xA9/0xD9 ] [ source ].
const auto newInputSource = buf[4];

// Ensure we only interpret valid inputs.
if(newInputSource >= 0x00 && newInputSource <= 0x02){
const auto inputSourceChanged = newInputSource != (char) inputSource;

// Update values.
inputSource = (InputSource) newInputSource;

// Call callbacks.
if(pFuncOnInputSourceChange != nullptr && inputSourceChanged)
pFuncOnInputSourceChange(inputSource);
}
}

// Check if this is an Config update.
if(buf[3] == 0xD8){
// Parse data.
// Response is of format [ length ] [ 0x05 0xFF 0xD8 ] [ config ].
const auto newConfig = buf[4];

// Ensure we only interpret valid inputs.
if(newConfig >= 0x00 && newConfig <= 0x03){
const auto configChanged = newConfig != (char) config;

// Update values.
config = (Config) newConfig;

// Call callbacks.
if(pFuncOnConfigChange != nullptr && configChanged)
pFuncOnConfigChange(config);
}
}
};

uint8_t MiniDSP::OnInitSuccessful() {
// Verify we're actually connected to the MiniDSP 2x4HD.
if(HIDUniversal::VID != MINIDSP_VID || HIDUniversal::PID != MINIDSP_PID)
return 0;

// Request current status so we can initialize the values.
// Request current information so we can initialize the values.
RequestStatus();
RequestInputSource();
RequestConfig();

if(pFuncOnInit != nullptr)
pFuncOnInit();
Expand Down Expand Up @@ -109,3 +163,33 @@ void MiniDSP::RequestStatus() const {

SendCommand(RequestStatusOutputCommand, sizeof (RequestStatusOutputCommand));
}

void MiniDSP::RequestInputSource() const {
uint8_t RequestInputSourceCommand[] = {0x05, 0xFF, 0xD9, 0x01};

SendCommand(RequestInputSourceCommand, sizeof(RequestInputSourceCommand));
}

void MiniDSP::RequestConfig() const {
uint8_t RequestConfigCommand[] = {0x05, 0xFF, 0xD8, 0x01};

SendCommand(RequestConfigCommand, sizeof(RequestConfigCommand));
}

void MiniDSP::setVolumeDB(float volumeDB) const {
// Only accept values between 0dB and -127.5dB.
// Don't do error handling.
if(volume > 0 || volume < -127.5){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if(volume > 0 || volume < -127.5){
if(volume < 0 || volume > -127.5) {

return;
}

uint8_t SetVolumeCommand[] = {0x42, (uint8_t)(-2*volumeDB)};
Copy link
Collaborator

@Lauszus Lauszus Sep 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint8_t SetVolumeCommand[] = {0x42, (uint8_t)(-2*volumeDB)};
uint8_t SetVolumeCommand[] = {0x42, (uint8_t)round(-2.0f * volumeDB)};


SendCommand(SetVolumeCommand, sizeof(SetVolumeCommand));
}

void MiniDSP::setMuted(bool muted) const {
uint8_t SetMutedommand[] = {0x17, muted ? (uint8_t)0x01 : (uint8_t)0x00};

SendCommand(SetMutedommand, sizeof(SetMutedommand));
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing new line.

82 changes: 81 additions & 1 deletion MiniDSP.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,21 @@
class MiniDSP : public HIDUniversal {
public:

enum class InputSource : uint8_t {
Analog = 0x00,
Toslink = 0x01,
USB = 0x02,
Unknown = 0x03
};

enum class Config : uint8_t {
Config_1 = 0x00,
Config_2 = 0x01,
Config_3 = 0x02,
Config_4 = 0x03,
Unknown = 0x04
};

/**
* Constructor for the MiniDSP class.
* @param p Pointer to the USB class instance.
Expand Down Expand Up @@ -83,6 +98,22 @@ class MiniDSP : public HIDUniversal {
pFuncOnMutedChange = funcOnMutedChange;
}

/**
* Used to call your own function when the input source has changed.
* @param funcOnInputSourceChange Function to call.
*/
void attachOnInputSourceChange(void (*funcOnInputSourceChange)(InputSource)) {
pFuncOnInputSourceChange = funcOnInputSourceChange;
}

/**
* Used to call your own function when the config has changed.
* @param funcOnConfigChange Function to call.
*/
void attachOnConfigChange(void (*funcOnConfigChange)(Config)) {
pFuncOnConfigChange = funcOnConfigChange;
}

/**
* Retrieve the current volume of the MiniDSP.
* The volume is passed as an unsigned integer that represents twice the
Expand All @@ -102,13 +133,42 @@ class MiniDSP : public HIDUniversal {
}

/**
* Retrieve the current muted status of the MiniDSP
* Retrieve the current muted status of the MiniDSP.
* @return `true` if the device is muted, `false` otherwise.
*/
bool isMuted() const {
return muted;
}

/**
* Retrieve the current input source of the MiniDSP.
* @return Current input source: `Analog`, `Toslink` or `USB`.
*/
InputSource getInputSource() const {
return inputSource;
}

/**
* Set volume of the MiniDSP in dB. Values between 0 and -127.5 are
* accepted. If any values outside if this range are passed, this
* function does nothing.
*
* Calling this function will not trigger the volume change callback.
*
* @param volumeDB New volume to set.
*/
void setVolumeDB(float volumeDB) const;


/**
* Mute or unmute the MiniDSP.
*
* Calling this function will not trigger the mute change callback.
*
* @param muted Muted status.
*/
void setMuted(bool muted) const;

protected:
/** @name HIDUniversal implementation */
/**
Expand Down Expand Up @@ -159,6 +219,18 @@ class MiniDSP : public HIDUniversal {
void
RequestStatus() const;

/**
* Send the "Request input source" command to the MiniDSP.
*/
void
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void
void RequestInputSource() const;

RequestInputSource() const;

/**
* Send the "Request config" command to the MiniDSP.
*/
void
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void
void RequestConfig() const;

RequestConfig() const;

/**
* Send the given MiniDSP command. This function will create a buffer
* with the expected header and checksum and send it to the MiniDSP.
Expand All @@ -179,6 +251,12 @@ class MiniDSP : public HIDUniversal {
// Pointer to function called when muted status changes.
void (*pFuncOnMutedChange)(bool) = nullptr;

// Pointer to function called when input source changes.
void (*pFuncOnInputSourceChange)(InputSource) = nullptr;

// Pointer to function called when config changes.
void (*pFuncOnConfigChange)(Config) = nullptr;

// -----------------------------------------------------------------------------

// MiniDSP state. Currently only volume and muted status are
Expand All @@ -188,4 +266,6 @@ class MiniDSP : public HIDUniversal {
// -dB value. Example: 19 represents -9.5dB.
uint8_t volume = 0;
bool muted = false;
InputSource inputSource = InputSource::Unknown;
Config config = Config::Unknown;
};
31 changes: 31 additions & 0 deletions examples/MiniDSP/MiniDSP.ino
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,35 @@ void OnMutedChange(bool isMuted) {
Serial.println("Muted status: " + String(isMuted ? "muted" : "unmuted"));
}

void OnInputSourceChange(MiniDSP::InputSource inputSource) {
String inputSourceStr = "Unknown";

if(inputSource == MiniDSP::InputSource::Analog) {
inputSourceStr = "Analog";
} else if(inputSource == MiniDSP::InputSource::Toslink) {
inputSourceStr = "Toslink";
} else if(inputSource == MiniDSP::InputSource::USB) {
inputSourceStr = "USB";
}

Serial.println("Input source: " + inputSourceStr);
}

void OnConfigChange(MiniDSP::Config config) {
String configStr = "Unknown";

if (config == MiniDSP::Config::Config_1) {
configStr = "Config 1";
} else if (config == MiniDSP::Config::Config_2) {
configStr = "Config 2";
} else if (config == MiniDSP::Config::Config_3) {
configStr = "Config 3";
} else if (config == MiniDSP::Config::Config_4) {
configStr = "Config 4";
}
Serial.println("Config: " + configStr);
}

void setup() {
Serial.begin(115200);
#if !defined(__MIPSEL__)
Expand All @@ -40,6 +69,8 @@ void setup() {
MiniDSP.attachOnInit(&OnMiniDSPConnected);
MiniDSP.attachOnVolumeChange(&OnVolumeChange);
MiniDSP.attachOnMutedChange(&OnMutedChange);
MiniDSP.attachOnInputSourceChange(&OnInputSourceChange);
MiniDSP.attachOnConfigChange(&OnConfigChange);
}

void loop() {
Expand Down
Loading