From 944203654209101307b97f4069cb15706c0841e2 Mon Sep 17 00:00:00 2001 From: Tomer Rubinstein Date: Mon, 28 Oct 2019 16:19:31 +0200 Subject: [PATCH] Zoom_H6: Library for controling Zoom H6 Recorder This library enables sending control commands and receiving device status from the Zoom H6 audio recorder --- library.json | 19 ++++++++ library.properties | 10 ++++ src/ZoomH6.cpp | 114 +++++++++++++++++++++++++++++++++++++++++++++ src/ZoomH6.h | 55 ++++++++++++++++++++++ 4 files changed, 198 insertions(+) create mode 100644 library.json create mode 100644 library.properties create mode 100644 src/ZoomH6.cpp create mode 100644 src/ZoomH6.h diff --git a/library.json b/library.json new file mode 100644 index 0000000..fb9c3a1 --- /dev/null +++ b/library.json @@ -0,0 +1,19 @@ +{ + "name": "Zoom_H6_Remote", + "version": "1.0.0-rc", + "frameworks": "arduino", + "platforms": "*", + "keywords": "ZOOM,H6,Remote", + "description": "Library for controling Zoom H6 audio recorder with Arduino framework", + "repository": { + "type": "git", + "url": "https://github.com/tomer99r/ZoomH6_Arduino.git" + }, + "authors": [ + { + "name": "Tomer Rubinstein", + "email": "tomer99r@gmail.com", + "maintainer": true + } + ] +} diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..7fb326e --- /dev/null +++ b/library.properties @@ -0,0 +1,10 @@ +name=Zoom_H6_Remote +version=1.0.0-rc +author=Tomer Rubinstein +maintainer=Tomer Rubinstein +sentence=Library for contorling Zoom H6 audio recorder with Arduino framework +paragraph=This library enables sending commands and getting status from Zoom H6 audio recorder using Arduino framework. +category=Device Control +url=https://github.com/tomer99r/ZoomH6_Arduino.git +includes=ZoomH6.h +architectures=* diff --git a/src/ZoomH6.cpp b/src/ZoomH6.cpp new file mode 100644 index 0000000..6a5c5be --- /dev/null +++ b/src/ZoomH6.cpp @@ -0,0 +1,114 @@ +#include "ZoomH6.h" +static const byte handshakeSeq[] = {0xC2, 0xE1, 0x31, 0x2E, 0x30, 0x30,0xA1,0x80,0x00 }; +static const byte handshakeReply[] = {0x82, 0x83, 0x80, 0x81}; + +ZoomH6Remote::ZoomH6Remote(HardwareSerial* serial, Stream* debug, uint32_t timeout) : + _serial(serial), _debug(debug), _timeout(timeout) {} + +/*This will write the data to the serial, and return the expected number of replys + in case of failure the result is negative */ +int8_t ZoomH6Remote::writeWithReply(byte* data, size_t dataLength, byte* reply, size_t replyLength) { + int8_t respCount = 0; + + for (int i = 0; i < dataLength; ++i) { + _serial->write(data[i]); + } + + uint32_t timeout = millis() + _timeout; + do { + if (_serial->available()) { + byte resp = _serial->read(); + if (reply != nullptr) { + reply[respCount % replyLength] = resp; + } + timeout = millis() + _timeout; + respCount++; + } + + } while (millis() <= timeout);//respCount < replyLength); + + return respCount; +} + +bool ZoomH6Remote::initialize() { + byte reply[3] = {0}; + + if(*_serial) _serial->end(); + _serial->begin(2400, SERIAL_8N1); // connection to Zoom. + + uint32_t timeout = millis() + 10000; + while (!*_serial) { + if(millis() > timeout) goto FAIL_TIME; + } + + timeout = millis() + 10000; + do { + if(_serial->available()) { + reply[0] = _serial->read(); + } else { + _serial->write(0x00); + delay(200); + } + if(millis() > timeout) return false; + } while(reply[0] != 0x82); + + if (!writeWithReply(handshakeSeq, 1, reply, 1)) goto FAIL_TIME; + if (reply[0] != handshakeReply[1]) goto FAIL_RES; + + if (!writeWithReply(&handshakeSeq[1], 5, reply, 1)) goto FAIL_TIME; + if (reply[0] != handshakeReply[2]) goto FAIL_RES; + + if (!writeWithReply(&handshakeSeq[6], 1, reply, 1)) goto FAIL_TIME; + if (reply[0] != handshakeReply[3]) goto FAIL_RES; + + writeWithReply(&handshakeSeq[7], 2, reply, 3); //clear status + printStatus(reply[1], reply[2]); + + return true; +FAIL_TIME: + if (_debug) _debug->println("Failed handshake - timeout"); + return false; +FAIL_RES: + if (_debug) { + for (int i = 0; i < 3; i++) { + _debug->println(reply[i]); + } + _debug->println("Failed handshake - invalid return value"); + } + return false; +} + +void ZoomH6Remote::printStatus(byte& high, byte& low) { + if (_debug) { + if (high == 0x00 && low == 0x00) _debug->println("No Channel Record Ready!"); + + if (high & StatusHigh::Record_on) _debug->println("Start Recording"); + if (high & StatusHigh::Channel_L_on) _debug->println("Left Channel Enabled"); + if (high & StatusHigh::Channel_R_on) _debug->println("Right Channel Enabled"); + if (high & StatusHigh::Channel_1_on) _debug->println("Channel 1 Enabled"); + + if (low & StatusLow::Channel_2_on) _debug->println("Channel 2 Enabled"); + if (low & StatusLow::Channel_3_on) _debug->println("Channel 3 Enabled"); + if (low & StatusLow::Channel_4_on) _debug->println("Channel 4 Enabled"); + } +} + +/* This method is used to transmit commands for the Zoom, + * primary - the primary command + * secondary - the sub command + * gap - the time to set between sending a command to releasing it (getting the status) in millis + * debug - verbose of result status to the debug serial + */ +bool ZoomH6Remote::sendCommand(byte primary, byte secondary, uint32_t gap, byte* reply) { + byte command[2] = {primary, secondary}; + byte releaseCom[2] = {Commands::SecFunc, SubCommands::Release }; + + if (!writeWithReply(command, 2, reply, 3)) return false; + if (reply != nullptr) printStatus(reply[1], reply[2]); + + if (gap) delay(gap); + + if (!writeWithReply(releaseCom, 2, nullptr, 3)) return false; + + return true; +} diff --git a/src/ZoomH6.h b/src/ZoomH6.h new file mode 100644 index 0000000..3853ef0 --- /dev/null +++ b/src/ZoomH6.h @@ -0,0 +1,55 @@ +#ifndef ZOOM_H6_H +#define ZOOM_H6_H +#include "Arduino.h" + +enum Commands { + Record = 0x81, + Play = 0x82, + SkipBackward = 0x84, + SkipForward = 0x88, + Stop = 0x90, + SecFunc = 0x80, +}; + +enum SubCommands { + Release = 0x00, + Channel_L = 0x01, + Channel_R = 0x02, + Channel_1 = 0x04, + Channel_2 = 0x08, + Channel_3 = 0x10, + Channel_4 = 0x20, + VolumeDown = 0x40, + VolumeUp = 0x80, +}; + +enum StatusHigh { + Record_on = 0x01, + Channel_L_on = 0x20, + Channel_R_on = 0x08, + Channel_1_on = 0x02, +}; + +enum StatusLow { + Channel_2_on = 0x20, + Channel_3_on = 0x08, + Channel_4_on = 0x02, +}; +class ZoomH6Remote { + public: + ZoomH6Remote(HardwareSerial* serial, Stream* debug = nullptr, uint32_t timeout = 40); + ~ZoomH6Remote() = default; + + bool initialize(); + bool sendCommand(byte primary, byte secondary, uint32_t gap, byte* reply = nullptr); + + private: + int8_t writeWithReply(byte* data, size_t dataLength, byte* reply, size_t replyLength); + void printStatus(byte& high, byte& low); + + Stream* _debug; + uint32_t _timeout; + HardwareSerial* _serial; +}; + +#endif