diff --git a/MiniDSP.cpp b/MiniDSP.cpp index 1aadefe2..90b7c716 100644 --- a/MiniDSP.cpp +++ b/MiniDSP.cpp @@ -14,104 +14,88 @@ #include "MiniDSP.h" -namespace { -uint8_t RequestStatusOutputCommand[] = {0x05, 0xFF, 0xDA, 0x02}; -uint8_t StatusInputCommand[]{0x05, 0xFF, 0xDA}; +void MiniDSP::ParseHIDData(USBHID *hid __attribute__((unused)), bool is_rpt_id __attribute__((unused)), uint8_t len, uint8_t *buf) { -// Returns first byte of the sum of given bytes. -uint8_t Checksum(const uint8_t *data, uint16_t nbytes) { - uint64_t sum = 0; - for (uint16_t i = 0; i < nbytes; i++) { - sum += data[i]; - } + constexpr uint8_t StatusInputCommand[]{0x05, 0xFF, 0xDA}; - return sum & 0xFF; -} -} // namespace + // Only care about valid data for the MiniDSP 2x4HD. + if (HIDUniversal::VID != MINIDSP_VID || HIDUniversal::PID != MINIDSP_PID || len <= 4 || buf == nullptr) + return; -void MiniDSP::ParseHIDData(USBHID *hid __attribute__((unused)), - bool is_rpt_id __attribute__((unused)), uint8_t len, - uint8_t *buf) { + // 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) { - // Only care about valid data for the MiniDSP 2x4HD. - if (HIDUniversal::VID != MINIDSP_VID || HIDUniversal::PID != MINIDSP_PID || - len <= 2 || buf == nullptr) { - return; - } + // 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]; - // 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) { + // Update status. + volume = newVolume; + muted = newIsMuted; - // 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]; + // Call callbacks. + if (pFuncOnVolumeChange != nullptr && newVolume != volume) + pFuncOnVolumeChange(volume); - const auto volumeUpdated = newVolume != volume; - const auto isMutedUpdated = newIsMuted != isMuted; - - // Update status. - volume = newVolume; - isMuted = newIsMuted; - - // Call callbacks. - if (volumeChangeCallback != nullptr && volumeUpdated) { - volumeChangeCallback(volume); - } - - if (mutedChangeCallback != nullptr && isMutedUpdated) { - mutedChangeCallback(isMuted); - } - } + if (pFuncOnMutedChange != nullptr && newIsMuted != muted) + pFuncOnMutedChange(muted); + } }; uint8_t MiniDSP::OnInitSuccessful() { - // Verify we're actually connected to the MiniDSP 2x4HD. - if (HIDUniversal::VID != MINIDSP_VID || HIDUniversal::PID != MINIDSP_PID) { - return 0; - } + // 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. - RequestStatus(); + // Request current status so we can initialize the values. + RequestStatus(); - if (onInitCallback != nullptr) { - onInitCallback(); - } + if (pFuncOnInit != nullptr) + pFuncOnInit(); - return 0; + return 0; }; -void MiniDSP::SendCommand(uint8_t *command, uint16_t command_length) const { - // Only send command if we're actually connected to the MiniDSP 2x4HD. - if (HIDUniversal::VID != MINIDSP_VID || HIDUniversal::PID != MINIDSP_PID) { - return; - } +uint8_t MiniDSP::Checksum(const uint8_t *data, uint8_t data_length) const { + uint16_t sum = 0; + for (uint8_t i = 0; i < data_length; i++) + sum += data[i]; - // Message is padded to 64 bytes with 0xFF and is of format: - // [ length (command + checksum byte) ] [ command ] [ checksum ] [ OxFF... ] + return sum & 0xFF; +} - // MiniDSP expects 64 byte messages. - uint8_t buf[64]; +void MiniDSP::SendCommand(uint8_t *command, uint8_t command_length) const { + // Sanity check on command length. + if (command_length > 63) + return; - // Set length, including checksum byte. - buf[0] = command_length + 1; + // Message is padded to 64 bytes with 0xFF and is of format: + // [ length (command + checksum byte) ] [ command ] [ checksum ] [ OxFF... ] - // Copy actual command. - memcpy(&buf[1], command, command_length); + // MiniDSP expects 64 byte messages. + uint8_t buf[64]; - const auto checksumOffset = command_length + 1; + // Set length, including checksum byte. + buf[0] = command_length + 1; - // Set checksum byte. - buf[checksumOffset] = Checksum(buf, command_length + 1); + // Copy actual command. + memcpy(&buf[1], command, command_length); - // Pad the rest. - memset(&buf[checksumOffset + 1], 0xFF, sizeof(buf) - checksumOffset - 1); + const auto checksumOffset = command_length + 1; - pUsb->outTransfer(bAddress, epInfo[epInterruptOutIndex].epAddr, sizeof(buf), - buf); + // Set checksum byte. + buf[checksumOffset] = Checksum(buf, command_length + 1); + + // Pad the rest. + memset(&buf[checksumOffset + 1], 0xFF, sizeof(buf) - checksumOffset - 1); + + pUsb->outTransfer(bAddress, epInfo[epInterruptOutIndex].epAddr, sizeof(buf), buf); } void MiniDSP::RequestStatus() const { - SendCommand(RequestStatusOutputCommand, sizeof(RequestStatusOutputCommand)); + uint8_t RequestStatusOutputCommand[] = {0x05, 0xFF, 0xDA, 0x02}; + + SendCommand(RequestStatusOutputCommand, sizeof(RequestStatusOutputCommand)); } diff --git a/MiniDSP.h b/MiniDSP.h index cea2aa34..4f5dc000 100644 --- a/MiniDSP.h +++ b/MiniDSP.h @@ -14,7 +14,6 @@ #pragma once -#include "controllerEnums.h" #include "hiduniversal.h" #define MINIDSP_VID 0x2752 // MiniDSP @@ -31,127 +30,150 @@ * It uses the HIDUniversal class for all the USB communication. */ class MiniDSP : public HIDUniversal { -public: - /** - * Constructor for the MiniDSP class. - * @param p Pointer to the USB class instance. - */ - MiniDSP(USB *p) : HIDUniversal(p){}; + public: + /** + * Constructor for the MiniDSP class. + * @param p Pointer to the USB class instance. + */ + MiniDSP(USB *p) : HIDUniversal(p){}; - /** - * Used to check if a MiniDSP 2x4HD is connected. - * @return Returns true if it is connected. - */ - bool connected() { - return HIDUniversal::isReady() && HIDUniversal::VID == MINIDSP_VID && - HIDUniversal::PID == MINIDSP_PID; - }; + /** + * Used to check if a MiniDSP 2x4HD is connected. + * @return Returns true if it is connected. + */ + bool connected() { + return HIDUniversal::isReady() && HIDUniversal::VID == MINIDSP_VID && HIDUniversal::PID == MINIDSP_PID; + }; - /** - * Used to call your own function when the device is successfully initialized. - * @param func Function to call. - */ - void SetOnInitCallback(void (*func)(void)) { onInitCallback = func; }; + /** + * Used to call your own function when the device is successfully + * initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { pFuncOnInit = funcOnInit; }; - /** - * Used to call your own function when the volume has changed. - * The volume is passed as an unsigned integer that represents twice the -dB - * value. Example: 19 represents -9.5dB. - * @param func Function to call. - */ - void SetVolumeChangeCallback(void (*func)(uint8_t)) { - volumeChangeCallback = func; - } + /** + * Used to call your own function when the volume has changed. + * The volume is passed as an unsigned integer that represents twice the + * -dB value. Example: 19 represents -9.5dB. + * @param funcOnVolumeChange Function to call. + */ + void attachOnVolumeChange(void (*funcOnVolumeChange)(uint8_t)) { + pFuncOnVolumeChange = funcOnVolumeChange; + } - /** - * Used to call your own function when the muted status has changed. - * The muted status is passed as a boolean. True means muted, false means - * unmuted. - * @param func Function to call. - */ - void SetMutedChangeCallback(void (*func)(bool)) { - mutedChangeCallback = func; - } + /** + * Used to call your own function when the muted status has changed. + * The muted status is passed as a boolean. True means muted, false + * means unmuted. + * @param funcOnMutedChange Function to call. + */ + void attachOnMutedChange(void (*funcOnMutedChange)(bool)) { + pFuncOnMutedChange = funcOnMutedChange; + } - /** - * Retrieve the current volume of the MiniDSP. - * The volume is passed as an unsigned integer that represents twice the -dB - * value. Example: 19 represents -9.5dB. - * @return Current volume. - */ - int GetVolume() const { return volume; } + /** + * Retrieve the current volume of the MiniDSP. + * The volume is passed as an unsigned integer that represents twice the + * -dB value. Example: 19 represents -9.5dB. + * @return Current volume. + */ + int getVolume() const { + return volume; + } - /** - * Retrieve the current muted status of the MiniDSP - * @return `true` if the device is muted, `false` otherwise. - */ - bool IsMuted() const { return isMuted; } + /** + * Retrieve the current volume of the MiniDSP in -dB. + * @return Current volume. + */ + float getVolumeDB() const { + return volume / -2.0; + } -protected: - /** @name HIDUniversal implementation */ - /** - * Used to parse USB HID data. - * @param hid Pointer to the HID class. - * @param is_rpt_id Only used for Hubs. - * @param len The length of the incoming data. - * @param buf Pointer to the data buffer. - */ - void ParseHIDData(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); + /** + * Retrieve the current muted status of the MiniDSP + * @return `true` if the device is muted, `false` otherwise. + */ + bool isMuted() const { + return muted; + } - /** - * Called when a device is successfully initialized. - * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. - * This is useful for instance if you want to set the LEDs in a specific way. - */ - uint8_t OnInitSuccessful(); - /**@}*/ + protected: + /** @name HIDUniversal implementation */ + /** + * Used to parse USB HID data. + * @param hid Pointer to the HID class. + * @param is_rpt_id Only used for Hubs. + * @param len The length of the incoming data. + * @param buf Pointer to the data buffer. + */ + void ParseHIDData(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); - /** @name USBDeviceConfig implementation */ - /** - * Used by the USB core to check what this driver support. - * @param vid The device's VID. - * @param pid The device's PID. - * @return Returns true if the device's VID and PID matches this driver. - */ - virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) { - return vid == MINIDSP_VID && pid == MINIDSP_PID; - }; - /**@}*/ + /** + * Called when a device is successfully initialized. + * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. + * This is useful for instance if you want to set the LEDs in a specific + * way. + */ + uint8_t OnInitSuccessful(); + /**@}*/ -private: - /** - * Send the "Request status" command to the MiniDSP. The response includes the - * current volume and the muted status. - */ - void RequestStatus() const; + /** @name USBDeviceConfig implementation */ + /** + * Used by the USB core to check what this driver support. + * @param vid The device's VID. + * @param pid The device's PID. + * @return Returns true if the device's VID and PID matches this + * driver. + */ + virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) { + return vid == MINIDSP_VID && pid == MINIDSP_PID; + }; + /**@}*/ - /** - * Send the given MiniDSP command. This function will create a buffer with the - * expected header and checksum and send it to the MiniDSP. Responses will - * come in throug `ParseHIDData`. - * @param command Buffer of the command to send. - * @param command_length Length of the buffer. - */ - void SendCommand(uint8_t *command, uint16_t command_length) const; + private: + /** + * Calculate checksum for given buffer. + * Checksum is given by summing up all bytes in `data` and returning the first byte. + * @param data Buffer to calculate checksum for. + * @param data_length Length of the buffer. + */ + uint8_t Checksum(const uint8_t *data, uint8_t data_length) const; - // Callbacks + /** + * Send the "Request status" command to the MiniDSP. The response + * includes the current volume and the muted status. + */ + void + RequestStatus() const; - // Pointer to function called in onInit(). - void (*onInitCallback)(void) = nullptr; + /** + * Send the given MiniDSP command. This function will create a buffer + * with the expected header and checksum and send it to the MiniDSP. + * Responses will come in throug `ParseHIDData`. + * @param command Buffer of the command to send. + * @param command_length Length of the buffer. + */ + void SendCommand(uint8_t *command, uint8_t command_length) const; - // Pointer to function called when volume changes. - void (*volumeChangeCallback)(uint8_t) = nullptr; + // Callbacks - // Pointer to function called when muted status changes. - void (*mutedChangeCallback)(bool) = nullptr; + // Pointer to function called in onInit(). + void (*pFuncOnInit)(void) = nullptr; - // ----------------------------------------------------------------------------- + // Pointer to function called when volume changes. + void (*pFuncOnVolumeChange)(uint8_t) = nullptr; - // MiniDSP state. Currently only volume and muted status are implemented, but - // others can be added easily if needed. + // Pointer to function called when muted status changes. + void (*pFuncOnMutedChange)(bool) = nullptr; - // The volume is stored as an unsigned integer that represents twice the - // -dB value. Example: 19 represents -9.5dB. - uint8_t volume = 0; - bool isMuted = false; + // ----------------------------------------------------------------------------- + + // MiniDSP state. Currently only volume and muted status are + // implemented, but others can be added easily if needed. + + // The volume is stored as an unsigned integer that represents twice the + // -dB value. Example: 19 represents -9.5dB. + uint8_t volume = 0; + bool muted = false; }; diff --git a/examples/MiniDSP/MiniDSP.ino b/examples/MiniDSP/MiniDSP.ino index 031a3ac1..8b7a20be 100644 --- a/examples/MiniDSP/MiniDSP.ino +++ b/examples/MiniDSP/MiniDSP.ino @@ -1,7 +1,5 @@ /* - Example sketch for the Playstation Buzz library - developed by Kristian Lauszus - For more information visit my blog: http://blog.tkjelectronics.dk/ or - send me an e-mail: kristianl@tkjelectronics.com + Example sketch for the MiniDSP 2x4HD library - developed by Dennis Frett */ #include @@ -15,34 +13,38 @@ USB Usb; MiniDSP MiniDSP(&Usb); -void OnMiniDSPConnected() { Serial.println("MiniDSP connected"); } +void OnMiniDSPConnected() { + Serial.println("MiniDSP connected"); +} void OnVolumeChange(uint8_t volume) { - Serial.println("Volume is: " + String(volume)); + Serial.println("Volume is: " + String(volume)); } void OnMutedChange(bool isMuted) { - Serial.println("Muted status: " + String(isMuted ? "muted" : "unmuted")); + Serial.println("Muted status: " + String(isMuted ? "muted" : "unmuted")); } void setup() { - Serial.begin(115200); + Serial.begin(115200); #if !defined(__MIPSEL__) - while (!Serial) - ; // Wait for serial port to connect - used on Leonardo, Teensy and other - // boards with built-in USB CDC serial connection + while (!Serial) + ; // Wait for serial port to connect - used on Leonardo, Teensy and other + // boards with built-in USB CDC serial connection #endif - if (Usb.Init() == -1) { - Serial.print(F("\r\nOSC did not start")); - while (1) - ; // Halt - } - Serial.println(F("\r\nMiniDSP 2x4HD Library Started")); + if (Usb.Init() == -1) { + Serial.print(F("\r\nOSC did not start")); + while (1) + ; // Halt + } + Serial.println(F("\r\nMiniDSP 2x4HD Library Started")); - // Register callbacks. - MiniDSP.SetOnInitCallback(&OnMiniDSPConnected); - MiniDSP.SetVolumeChangeCallback(&OnVolumeChange); - MiniDSP.SetMutedChangeCallback(&OnMutedChange); + // Register callbacks. + MiniDSP.attachOnInit(&OnMiniDSPConnected); + MiniDSP.attachOnVolumeChange(&OnVolumeChange); + MiniDSP.attachOnMutedChange(&OnMutedChange); } -void loop() { Usb.Task(); } +void loop() { + Usb.Task(); +}