Last active
May 3, 2021 01:17
-
-
Save guyfawcus/6c9c3fe966322494fbaa1589de68624d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Zoom H6 remote control" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "import serial\n", | |
| "import time\n", | |
| "from collections import namedtuple\n", | |
| "\n", | |
| "s = serial.Serial('/dev/ttyUSB1')\n", | |
| "s.baudrate = 2400\n", | |
| "s.timeout = 0.032" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Remote to Recorder\n", | |
| "####################\n", | |
| "stop = bytearray([0b10010000, 0b00000000])\n", | |
| "forward = bytearray([0b10001000, 0b00000000])\n", | |
| "reverse = bytearray([0b10000100, 0b00000000])\n", | |
| "play_pause = bytearray([0b10000010, 0b00000000])\n", | |
| "record = bytearray([0b10000001, 0b00000000])\n", | |
| "\n", | |
| "vol_up = bytearray([0b10000000, 0b10000000])\n", | |
| "vol_down = bytearray([0b10000000, 0b01000000])\n", | |
| "\n", | |
| "ch4 = bytearray([0b10000000, 0b00100000])\n", | |
| "ch3 = bytearray([0b10000000, 0b00010000])\n", | |
| "ch2 = bytearray([0b10000000, 0b00001000])\n", | |
| "ch1 = bytearray([0b10000000, 0b00000100])\n", | |
| "right = bytearray([0b10000000, 0b00000010])\n", | |
| "left = bytearray([0b10000000, 0b00000001])\n", | |
| "\n", | |
| "release_button = bytearray([0b10000000, 0b00000000])\n", | |
| "\n", | |
| "\n", | |
| "# Recorder to remote\n", | |
| "####################\n", | |
| "Button = namedtuple('Button', 'name value')\n", | |
| "\n", | |
| "play = Button(value=bytearray([0b00000000, 0b00000001]), name='play')\n", | |
| "rec = Button(value=bytearray([0b00000001, 0b00000000]), name='record')\n", | |
| "\n", | |
| "# r = record = red\n", | |
| "rl = Button(value=bytearray([0b00100000, 0b00000000]), name='rl')\n", | |
| "rr = Button(value=bytearray([0b00001000, 0b00000000]), name='rr')\n", | |
| "r1 = Button(value=bytearray([0b00000010, 0b00000000]), name='r1')\n", | |
| "r2 = Button(value=bytearray([0b00000000, 0b00100000]), name='r2')\n", | |
| "r3 = Button(value=bytearray([0b00000000, 0b00001000]), name='r3')\n", | |
| "r4 = Button(value=bytearray([0b00000000, 0b00000010]), name='r4')\n", | |
| "\n", | |
| "# s = solo = yellow\n", | |
| "sl = Button(value=bytearray([0b01100000, 0b00000000]), name='sl')\n", | |
| "sr = Button(value=bytearray([0b00011000, 0b00000000]), name='sr')\n", | |
| "s1 = Button(value=bytearray([0b00000110, 0b00000000]), name='s1')\n", | |
| "s2 = Button(value=bytearray([0b00000000, 0b01100000]), name='s2')\n", | |
| "s3 = Button(value=bytearray([0b00000000, 0b00011000]), name='s3')\n", | |
| "s4 = Button(value=bytearray([0b00000000, 0b00000110]), name='s4')\n", | |
| "\n", | |
| "# p = play = green\n", | |
| "pl = Button(value=bytearray([0b01000000, 0b00000000]), name='pl')\n", | |
| "pr = Button(value=bytearray([0b00010000, 0b00000000]), name='pr')\n", | |
| "p1 = Button(value=bytearray([0b00000100, 0b00000000]), name='p1')\n", | |
| "p2 = Button(value=bytearray([0b00000000, 0b01000000]), name='p2')\n", | |
| "p3 = Button(value=bytearray([0b00000000, 0b00010000]), name='p3')\n", | |
| "p4 = Button(value=bytearray([0b00000000, 0b00000100]), name='p4')\n", | |
| "\n", | |
| "solo_bytes_list = [sl, sr, s1, s2, s3, s4]\n", | |
| "\n", | |
| "data_bytes_list = [play, rec,\n", | |
| " rl, rr, r1, r2, r3, r4,\n", | |
| " pl, pr, p1, p2, p3, p4]" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "def to_bin(byte):\n", | |
| " '''Handy function for formatting a byte as binary'''\n", | |
| " return bin(byte)[2:].zfill(8)\n", | |
| "\n", | |
| "\n", | |
| "def combine(commands = []):\n", | |
| " '''This does a bitwise 'or' on each byte to comine commands.\n", | |
| " For example: ch1 = 10000000 00000100\n", | |
| " ch2 = 10000000 00001000\n", | |
| " result = 10000000 00001100 \n", | |
| " '''\n", | |
| " final_command = bytearray([0b00000000, 0b00000000])\n", | |
| " \n", | |
| " for command in commands:\n", | |
| " byte_one = final_command[0] | command[0]\n", | |
| " byte_two = final_command[1] | command[1]\n", | |
| " final_command = bytearray([byte_one, byte_two])\n", | |
| " \n", | |
| " return final_command\n", | |
| "\n", | |
| "\n", | |
| "def send(command):\n", | |
| " '''Send a command to the recorder and return the status'''\n", | |
| " s.reset_input_buffer()\n", | |
| " s.write(command)\n", | |
| " s.write(release_button)\n", | |
| " time.sleep(0.5)\n", | |
| " while s.in_waiting:\n", | |
| " print(get_data())\n", | |
| "\n", | |
| "\n", | |
| "def get_data():\n", | |
| " '''Intended to be run in a loop'''\n", | |
| " init_byte = s.read(1)\n", | |
| " \n", | |
| " # If the there was no data, start over\n", | |
| " if init_byte == b'':\n", | |
| " return\n", | |
| "\n", | |
| " # We can ingore these messages as they don't contain data\n", | |
| " elif init_byte == b'\\x86':\n", | |
| " rx_bytes = s.read(2)\n", | |
| "\n", | |
| " # These are the bytes we're looking for\n", | |
| " elif init_byte == b'\\x84': \n", | |
| " rx_bytes = s.read(2)\n", | |
| " \n", | |
| " # Check the 'clear all' case\n", | |
| " if rx_bytes == b'\\x00\\x00':\n", | |
| " return ['clear']\n", | |
| "\n", | |
| " else:\n", | |
| " state = []\n", | |
| "\n", | |
| " # First, check if any channels are in 'solo' mode\n", | |
| " for data_bytes in solo_bytes_list:\n", | |
| " if rx_bytes[0] & data_bytes.value[0] == data_bytes.value[0] and rx_bytes[1] & data_bytes.value[1] == data_bytes.value[1]:\n", | |
| " state.append(data_bytes.name)\n", | |
| " \n", | |
| " \n", | |
| " # Then check all of the other possible values\n", | |
| " for data_bytes in data_bytes_list:\n", | |
| " if rx_bytes[0] & data_bytes.value[0] == data_bytes.value[0] and rx_bytes[1] & data_bytes.value[1] == data_bytes.value[1]:\n", | |
| " # Ignore data if the channel is soloed\n", | |
| " if 's' + data_bytes.name[-1] not in state:\n", | |
| " state.append(data_bytes.name)\n", | |
| "\n", | |
| " return state\n", | |
| "\n", | |
| " else:\n", | |
| " # Cover any unforseen data (haven't come across any yet)\n", | |
| " print('Unknown sequence:', init_byte)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Initialise the connection using the handshake\n", | |
| "while True:\n", | |
| " s.write(b'\\00')\n", | |
| " \n", | |
| " if s.read(1) == b'\\x82':\n", | |
| " s.write(b'\\xC2')\n", | |
| " \n", | |
| " if s.read(1) == b'\\x83':\n", | |
| " s.write(b'\\xE1\\x31\\x2E\\x30\\x30')\n", | |
| " \n", | |
| " if s.read(1) == b'\\x80':\n", | |
| " s.write(b'\\xA1')\n", | |
| " \n", | |
| " if s.read(1) == b'\\x81':\n", | |
| " s.write(b'\\x80\\x80')\n", | |
| " break" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "scrolled": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "# Emulate pressing all of the channel buttons\n", | |
| "send(left)\n", | |
| "#send(right)\n", | |
| "print()\n", | |
| "send(ch1)\n", | |
| "print()\n", | |
| "send(ch2)\n", | |
| "print()\n", | |
| "send(ch3)\n", | |
| "print()\n", | |
| "send(ch4)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# This command will pair or unpair channels 1 and 2\n", | |
| "send(combine([ch1, ch2]))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Wait for data and decode it\n", | |
| "# press a button on the recorder to see output\n", | |
| "# Press stop to interrupt the kernel when finished\n", | |
| "while True:\n", | |
| " data = get_data()\n", | |
| " if data is not None: print(data)" | |
| ] | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Python 3", | |
| "language": "python", | |
| "name": "python3" | |
| }, | |
| "language_info": { | |
| "codemirror_mode": { | |
| "name": "ipython", | |
| "version": 3 | |
| }, | |
| "file_extension": ".py", | |
| "mimetype": "text/x-python", | |
| "name": "python", | |
| "nbconvert_exporter": "python", | |
| "pygments_lexer": "ipython3", | |
| "version": "3.6.9" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 2 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment