Compare commits

..

6 Commits

Author SHA1 Message Date
1e78421829 Logic fix, set_state returns true/false for debugging purposes 2024-05-18 00:22:38 -05:00
0fb69b0fbc Add max_brightness parameter so I don't blind myself without a case 2024-05-18 00:18:59 -05:00
0b8893d433 Add class for HUSB238 board control and LED matrix control 2024-05-18 00:13:19 -05:00
700e87f807 App sync code, handles button presses from mixer and syncs changes from VM. Included python code from the mixer. Some other PCB changes, but still needs improvements 2024-05-16 23:42:27 -05:00
efdbb11f92 Code changes 2024-04-27 00:50:07 -05:00
cdac51a0f5 PCB v1.1: Errata fixes
* Vss and Vdd were mixed up on U1 and U2
* Wrong pinout was used for WS2812B LEDs, causing Dout and Din to be reversed
* ItsyBitsy M4 Express does not have pull-up resistors on SDA and SCL. Add 10k resistors to fix
2024-04-27 00:49:51 -05:00
57 changed files with 75453 additions and 67218 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"board": {
"active_layer": 37,
"active_layer": 0,
"active_layer_preset": "",
"auto_track_width": true,
"hidden_netclasses": [],

View File

@@ -2927,6 +2927,12 @@
(color 0 0 0 0)
(uuid "5538a9c5-164e-4428-8e13-08b32894887e")
)
(junction
(at 196.85 115.57)
(diameter 0)
(color 0 0 0 0)
(uuid "725edc77-e13b-4c72-ba42-11cefbbd15a1")
)
(junction
(at 83.82 144.78)
(diameter 0)
@@ -2957,6 +2963,12 @@
(color 0 0 0 0)
(uuid "d92da9b6-69ac-4759-8307-62d5cae2077d")
)
(junction
(at 196.85 118.11)
(diameter 0)
(color 0 0 0 0)
(uuid "e1f00d49-f293-4ed0-8944-c6d4bf180443")
)
(junction
(at 45.72 54.61)
(diameter 0)
@@ -3323,6 +3335,16 @@
)
(uuid "517b1850-6ec4-429f-94b5-b08c8699c6ef")
)
(wire
(pts
(xy 193.04 115.57) (xy 196.85 115.57)
)
(stroke
(width 0)
(type default)
)
(uuid "5484a4ab-a36e-4117-9481-8daa4e05a538")
)
(wire
(pts
(xy 269.24 22.86) (xy 274.32 22.86)
@@ -3533,6 +3555,16 @@
)
(uuid "8574fa64-be79-48b3-94d2-0f07450a148b")
)
(wire
(pts
(xy 193.04 118.11) (xy 196.85 118.11)
)
(stroke
(width 0)
(type default)
)
(uuid "8589fd10-2ed4-4736-8ccc-0fee4baafb04")
)
(polyline
(pts
(xy 125.73 74.93) (xy 242.57 74.93)
@@ -3563,6 +3595,26 @@
)
(uuid "9156c182-aa02-4326-ba31-859ed692a216")
)
(wire
(pts
(xy 196.85 115.57) (xy 214.63 115.57)
)
(stroke
(width 0)
(type default)
)
(uuid "918951b4-91a6-49f8-98d1-a6992d46aa92")
)
(wire
(pts
(xy 196.85 125.73) (xy 181.61 125.73)
)
(stroke
(width 0)
(type default)
)
(uuid "9380a0c9-ab4a-4d61-9b53-220301f389c5")
)
(wire
(pts
(xy 33.02 43.18) (xy 35.56 43.18)
@@ -3623,6 +3675,16 @@
)
(uuid "b02a45a2-0319-4711-8a85-a431b1192f15")
)
(wire
(pts
(xy 196.85 118.11) (xy 214.63 118.11)
)
(stroke
(width 0)
(type default)
)
(uuid "b047e30f-6874-4a1e-8962-5d056845d358")
)
(wire
(pts
(xy 92.71 50.8) (xy 92.71 53.34)
@@ -3663,6 +3725,16 @@
)
(uuid "b9277049-0d14-45aa-92e0-b5075a7b3e90")
)
(wire
(pts
(xy 181.61 107.95) (xy 196.85 107.95)
)
(stroke
(width 0)
(type default)
)
(uuid "bb637b46-9527-4811-9f10-24cb865962e4")
)
(wire
(pts
(xy 78.74 162.56) (xy 83.82 162.56)
@@ -3703,6 +3775,16 @@
)
(uuid "cb5d2a4d-ad94-4e4b-a976-6f4280ac8bdf")
)
(wire
(pts
(xy 181.61 107.95) (xy 181.61 125.73)
)
(stroke
(width 0)
(type default)
)
(uuid "cc4e188c-6afb-41db-9634-11a3ce7b6b4b")
)
(polyline
(pts
(xy 125.73 11.9737) (xy 125.73 44.45)
@@ -4065,6 +4147,28 @@
)
)
)
(global_label "MCP_CS"
(shape input)
(at 245.11 138.43 0)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify left)
)
(uuid "110d57d2-9a85-4aeb-9b6a-69c907ecb067")
(property "Intersheetrefs" "${INTERSHEET_REFS}"
(at 255.5337 138.43 0)
(effects
(font
(size 1.27 1.27)
)
(justify left)
(hide yes)
)
)
)
(global_label "Pot3"
(shape input)
(at 245.11 120.65 0)
@@ -4131,6 +4235,28 @@
)
)
)
(global_label "MCP_CS"
(shape input)
(at 127 124.46 180)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify right)
)
(uuid "18abe3ae-619d-4ea9-a26d-baf9ec2f3ec9")
(property "Intersheetrefs" "${INTERSHEET_REFS}"
(at 116.5763 124.46 0)
(effects
(font
(size 1.27 1.27)
)
(justify right)
(hide yes)
)
)
)
(global_label "Pot4"
(shape input)
(at 245.11 123.19 0)
@@ -4309,7 +4435,7 @@
)
(global_label "SCL"
(shape input)
(at 214.63 118.11 180)
(at 193.04 118.11 180)
(fields_autoplaced yes)
(effects
(font
@@ -4319,7 +4445,7 @@
)
(uuid "25a9e4b3-d3c4-4398-9b40-e314daec08f0")
(property "Intersheetrefs" "${INTERSHEET_REFS}"
(at 208.1372 118.11 0)
(at 186.5472 118.11 0)
(effects
(font
(size 1.27 1.27)
@@ -4507,22 +4633,22 @@
)
(global_label "Gnd"
(shape input)
(at 139.7 105.41 90)
(at 139.7 135.89 270)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify left)
(justify right)
)
(uuid "416099f5-edd9-49c5-9c1c-b310b0c356d2")
(property "Intersheetrefs" "${INTERSHEET_REFS}"
(at 139.7 98.8568 90)
(at 139.7 142.4432 90)
(effects
(font
(size 1.27 1.27)
)
(justify left)
(justify right)
(hide yes)
)
)
@@ -4593,28 +4719,6 @@
)
)
)
(global_label "Gnd"
(shape input)
(at 127 124.46 180)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify right)
)
(uuid "47bd9f65-0e2a-4fc6-bd4e-d5f3d0725d71")
(property "Intersheetrefs" "${INTERSHEET_REFS}"
(at 120.4468 124.46 0)
(effects
(font
(size 1.27 1.27)
)
(justify right)
(hide yes)
)
)
)
(global_label "USB_5v"
(shape input)
(at 214.63 138.43 180)
@@ -4813,6 +4917,28 @@
)
)
)
(global_label "MCP_CS"
(shape input)
(at 127 167.64 180)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify right)
)
(uuid "60a88f2d-666a-4237-80f4-f94f107c2781")
(property "Intersheetrefs" "${INTERSHEET_REFS}"
(at 116.5763 167.64 0)
(effects
(font
(size 1.27 1.27)
)
(justify right)
(hide yes)
)
)
)
(global_label "Ch1Zero"
(shape input)
(at 214.63 133.35 180)
@@ -4969,22 +5095,22 @@
)
(global_label "3v3"
(shape input)
(at 139.7 135.89 270)
(at 139.7 105.41 90)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify right)
(justify left)
)
(uuid "780c5de9-c6f4-48fa-9f30-e27df039c166")
(property "Intersheetrefs" "${INTERSHEET_REFS}"
(at 139.7 142.2618 90)
(at 139.7 99.0382 90)
(effects
(font
(size 1.27 1.27)
)
(justify right)
(justify left)
(hide yes)
)
)
@@ -5145,7 +5271,29 @@
)
(global_label "3v3"
(shape input)
(at 139.7 179.07 270)
(at 139.7 148.59 90)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify left)
)
(uuid "874a06cc-f88c-4ce2-b716-495aece4e91b")
(property "Intersheetrefs" "${INTERSHEET_REFS}"
(at 139.7 142.2182 90)
(effects
(font
(size 1.27 1.27)
)
(justify left)
(hide yes)
)
)
)
(global_label "3v3"
(shape input)
(at 181.61 116.84 180)
(fields_autoplaced yes)
(effects
(font
@@ -5153,9 +5301,9 @@
)
(justify right)
)
(uuid "874a06cc-f88c-4ce2-b716-495aece4e91b")
(uuid "8905a1e9-00a6-49a6-8c08-28db9dd718c6")
(property "Intersheetrefs" "${INTERSHEET_REFS}"
(at 139.7 185.4418 90)
(at 175.2382 116.84 0)
(effects
(font
(size 1.27 1.27)
@@ -5255,22 +5403,22 @@
)
(global_label "Gnd"
(shape input)
(at 139.7 148.59 90)
(at 139.7 179.07 270)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify left)
(justify right)
)
(uuid "a44823a6-d03a-4caa-9b7d-6a4a45328ed8")
(property "Intersheetrefs" "${INTERSHEET_REFS}"
(at 139.7 142.0368 90)
(at 139.7 185.6232 90)
(effects
(font
(size 1.27 1.27)
)
(justify left)
(justify right)
(hide yes)
)
)
@@ -5561,28 +5709,6 @@
)
)
)
(global_label "Gnd"
(shape input)
(at 127 167.64 180)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify right)
)
(uuid "c18809a2-710c-49cd-8166-9b76e2516110")
(property "Intersheetrefs" "${INTERSHEET_REFS}"
(at 120.4468 167.64 0)
(effects
(font
(size 1.27 1.27)
)
(justify right)
(hide yes)
)
)
)
(global_label "3v3"
(shape input)
(at 135.89 22.86 180)
@@ -5805,7 +5931,7 @@
)
(global_label "SDA"
(shape input)
(at 214.63 115.57 180)
(at 193.04 115.57 180)
(fields_autoplaced yes)
(effects
(font
@@ -5815,7 +5941,7 @@
)
(uuid "e0d49592-71dc-4662-8945-bae7a5e15ebd")
(property "Intersheetrefs" "${INTERSHEET_REFS}"
(at 208.0767 115.57 0)
(at 186.4867 115.57 0)
(effects
(font
(size 1.27 1.27)
@@ -7099,7 +7225,7 @@
(justify left)
)
)
(property "Footprint" "Resistor_SMD:R_0805_2012Metric"
(property "Footprint" "Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder"
(at 90.932 46.99 90)
(effects
(font
@@ -7487,7 +7613,7 @@
(justify left)
)
)
(property "Footprint" "Resistor_SMD:R_0805_2012Metric"
(property "Footprint" "Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder"
(at 90.932 58.42 90)
(effects
(font
@@ -7805,6 +7931,76 @@
)
)
)
(symbol
(lib_id "Device:R")
(at 196.85 111.76 0)
(unit 1)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(dnp no)
(fields_autoplaced yes)
(uuid "8a9ad484-cf4c-444d-bbcc-13e67f9a1d26")
(property "Reference" "R3"
(at 199.39 110.4899 0)
(effects
(font
(size 1.27 1.27)
)
(justify left)
)
)
(property "Value" "R"
(at 199.39 113.0299 0)
(effects
(font
(size 1.27 1.27)
)
(justify left)
)
)
(property "Footprint" "Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder"
(at 195.072 111.76 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 196.85 111.76 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 196.85 111.76 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(pin "2"
(uuid "266096b0-0722-468b-b667-02afdd8ba748")
)
(pin "1"
(uuid "a9d6408d-fc4c-4df3-b784-212408267add")
)
(instances
(project "ControlMixer"
(path "/825e47bb-7d66-4b90-ba40-80bd9e0f877b"
(reference "R3")
(unit 1)
)
)
)
)
(symbol
(lib_id "ControlMixer:AP63300WU")
(at 45.72 45.72 0)
@@ -8032,6 +8228,75 @@
)
)
)
(symbol
(lib_id "Device:R")
(at 196.85 121.92 0)
(unit 1)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(dnp no)
(uuid "9c81b569-a375-4470-9c43-6c6df22a9875")
(property "Reference" "R4"
(at 199.39 120.6499 0)
(effects
(font
(size 1.27 1.27)
)
(justify left)
)
)
(property "Value" "R"
(at 199.39 123.1899 0)
(effects
(font
(size 1.27 1.27)
)
(justify left)
)
)
(property "Footprint" "Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder"
(at 195.072 121.92 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 196.85 121.92 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 196.85 121.92 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(pin "2"
(uuid "266096b0-0722-468b-b667-02afdd8ba749")
)
(pin "1"
(uuid "a9d6408d-fc4c-4df3-b784-212408267ade")
)
(instances
(project "ControlMixer"
(path "/825e47bb-7d66-4b90-ba40-80bd9e0f877b"
(reference "R4")
(unit 1)
)
)
)
)
(symbol
(lib_id "Device:LED")
(at 74.93 162.56 0)
@@ -8228,7 +8493,7 @@
)
)
(pin "1"
(uuid "93ecfcd0-262d-4208-b330-12ddfa292a0c")
(uuid "93ecfcd0-262d-4208-b330-12ddfa292a0d")
)
(instances
(project "ControlMixer"
@@ -8500,7 +8765,7 @@
)
)
(pin "1"
(uuid "93ecfcd0-262d-4208-b330-12ddfa292a0c")
(uuid "93ecfcd0-262d-4208-b330-12ddfa292a0e")
)
(instances
(project "ControlMixer"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,12 @@
%TF.GenerationSoftware,KiCad,Pcbnew,8.0.1*%
%TF.CreationDate,2024-04-10T00:32:00-05:00*%
%TF.CreationDate,2024-04-27T00:37:19-05:00*%
%TF.ProjectId,ControlMixer,436f6e74-726f-46c4-9d69-7865722e6b69,rev?*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Paste,Bot*%
%TF.FilePolarity,Positive*%
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 8.0.1) date 2024-04-10 00:32:00*
G04 Created by KiCad (PCBNEW 8.0.1) date 2024-04-27 00:37:19*
%MOMM*%
%LPD*%
G01*
@@ -29,59 +29,59 @@ G04 Aperture macros list*
20,1,$1+$1,$6,$7,$8,$9,0*
20,1,$1+$1,$8,$9,$2,$3,0*%
G04 Aperture macros list end*
%ADD10RoundRect,0.250000X0.262500X0.450000X-0.262500X0.450000X-0.262500X-0.450000X0.262500X-0.450000X0*%
%ADD11RoundRect,0.250000X0.475000X-0.250000X0.475000X0.250000X-0.475000X0.250000X-0.475000X-0.250000X0*%
%ADD12R,5.100000X2.350000*%
%ADD13RoundRect,0.250000X0.450000X-0.262500X0.450000X0.262500X-0.450000X0.262500X-0.450000X-0.262500X0*%
%ADD10RoundRect,0.250000X0.350000X0.450000X-0.350000X0.450000X-0.350000X-0.450000X0.350000X-0.450000X0*%
%ADD11RoundRect,0.250000X0.450000X-0.350000X0.450000X0.350000X-0.450000X0.350000X-0.450000X-0.350000X0*%
%ADD12RoundRect,0.250000X0.475000X-0.250000X0.475000X0.250000X-0.475000X0.250000X-0.475000X-0.250000X0*%
%ADD13R,5.100000X2.350000*%
%ADD14RoundRect,0.150000X0.512500X0.150000X-0.512500X0.150000X-0.512500X-0.150000X0.512500X-0.150000X0*%
%ADD15RoundRect,0.250000X0.250000X0.475000X-0.250000X0.475000X-0.250000X-0.475000X0.250000X-0.475000X0*%
G04 APERTURE END LIST*
D10*
%TO.C,R2*%
X213037464Y-32305000D03*
X211212464Y-32305000D03*
X213124964Y-32305000D03*
X211124964Y-32305000D03*
%TD*%
D11*
%TO.C,C2.2*%
X205712464Y-41005000D03*
X205712464Y-39105000D03*
%TO.C,R1*%
X215962464Y-36305000D03*
X215962464Y-34305000D03*
%TD*%
D12*
%TO.C,L1*%
X200212464Y-37905000D03*
X200212464Y-42055000D03*
%TD*%
D11*
%TO.C,C4*%
X218462464Y-36255000D03*
X218462464Y-34355000D03*
%TO.C,C2.2*%
X205712464Y-39105000D03*
X205712464Y-41005000D03*
%TD*%
D13*
%TO.C,R1*%
X215962464Y-36217500D03*
X215962464Y-34392500D03*
%TO.C,L1*%
X200212464Y-42055000D03*
X200212464Y-37905000D03*
%TD*%
D12*
%TO.C,C4*%
X218462464Y-34355000D03*
X218462464Y-36255000D03*
%TD*%
D14*
%TO.C,U4*%
X212562464Y-34805000D03*
X212562464Y-35755000D03*
X212562464Y-36705000D03*
X210287464Y-36705000D03*
X210287464Y-35755000D03*
X210287464Y-34805000D03*
X210287464Y-35755000D03*
X210287464Y-36705000D03*
X212562464Y-36705000D03*
X212562464Y-35755000D03*
X212562464Y-34805000D03*
%TD*%
D11*
D12*
%TO.C,C2.1*%
X208212464Y-41005000D03*
X208212464Y-39105000D03*
X208212464Y-41005000D03*
%TD*%
%TO.C,C3*%
X206462464Y-35555000D03*
X206462464Y-33655000D03*
X206462464Y-35555000D03*
%TD*%
D15*
%TO.C,C1*%
X212662464Y-39055000D03*
X210762464Y-39055000D03*
X212662464Y-39055000D03*
%TD*%
M02*

View File

@@ -1,12 +1,12 @@
%TF.GenerationSoftware,KiCad,Pcbnew,8.0.1*%
%TF.CreationDate,2024-04-10T00:32:00-05:00*%
%TF.CreationDate,2024-04-27T00:37:19-05:00*%
%TF.ProjectId,ControlMixer,436f6e74-726f-46c4-9d69-7865722e6b69,rev?*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Legend,Bot*%
%TF.FilePolarity,Positive*%
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 8.0.1) date 2024-04-10 00:32:00*
G04 Created by KiCad (PCBNEW 8.0.1) date 2024-04-27 00:37:19*
%MOMM*%
%LPD*%
G01*
@@ -57,6 +57,38 @@ X211386868Y-30538390D02*
X211958296Y-31109819D01*
X211958296Y-31109819D02*
X211339249Y-31109819D01*
X218067283Y-35138333D02*
X217591092Y-34805000D01*
X218067283Y-34566905D02*
X217067283Y-34566905D01*
X217067283Y-34566905D02*
X217067283Y-34947857D01*
X217067283Y-34947857D02*
X217114902Y-35043095D01*
X217114902Y-35043095D02*
X217162521Y-35090714D01*
X217162521Y-35090714D02*
X217257759Y-35138333D01*
X217257759Y-35138333D02*
X217400616Y-35138333D01*
X217400616Y-35138333D02*
X217495854Y-35090714D01*
X217495854Y-35090714D02*
X217543473Y-35043095D01*
X217543473Y-35043095D02*
X217591092Y-34947857D01*
X217591092Y-34947857D02*
X217591092Y-34566905D01*
X218067283Y-36090714D02*
X218067283Y-35519286D01*
X218067283Y-35805000D02*
X217067283Y-35805000D01*
X217067283Y-35805000D02*
X217210140Y-35709762D01*
X217210140Y-35709762D02*
X217305378Y-35614524D01*
X217305378Y-35614524D02*
X217352997Y-35519286D01*
X206072044Y-42674047D02*
X206119664Y-42626428D01*
X206119664Y-42626428D02*
@@ -187,38 +219,6 @@ X217922582Y-37574700D02*
X218160677Y-38288985D01*
X218160677Y-38288985D02*
X217541630Y-38288985D01*
X216129130Y-38672319D02*
X216462463Y-38196128D01*
X216700558Y-38672319D02*
X216700558Y-37672319D01*
X216700558Y-37672319D02*
X216319606Y-37672319D01*
X216319606Y-37672319D02*
X216224368Y-37719938D01*
X216224368Y-37719938D02*
X216176749Y-37767557D01*
X216176749Y-37767557D02*
X216129130Y-37862795D01*
X216129130Y-37862795D02*
X216129130Y-38005652D01*
X216129130Y-38005652D02*
X216176749Y-38100890D01*
X216176749Y-38100890D02*
X216224368Y-38148509D01*
X216224368Y-38148509D02*
X216319606Y-38196128D01*
X216319606Y-38196128D02*
X216700558Y-38196128D01*
X215176749Y-38672319D02*
X215748177Y-38672319D01*
X215462463Y-38672319D02*
X215462463Y-37672319D01*
X215462463Y-37672319D02*
X215557701Y-37815176D01*
X215557701Y-37815176D02*
X215652939Y-37910414D01*
X215652939Y-37910414D02*
X215748177Y-37958033D01*
X209224368Y-36509819D02*
X209224368Y-37319342D01*
X209224368Y-37319342D02*
@@ -415,43 +415,35 @@ X211897900Y-31570000D02*
X212352028Y-31570000D01*
X211897900Y-33040000D02*
X212352028Y-33040000D01*
%TO.C,C2.2*%
X204977464Y-39793748D02*
X204977464Y-40316252D01*
X206447464Y-39793748D02*
X206447464Y-40316252D01*
%TO.C,L1*%
X197112464Y-43080000D02*
X197112464Y-36880000D01*
X197562464Y-36880000D02*
X197112464Y-36880000D01*
X197562464Y-43080000D02*
X197112464Y-43080000D01*
X202862464Y-36880000D02*
X203312464Y-36880000D01*
X202862464Y-43080000D02*
X203312464Y-43080000D01*
X203312464Y-36880000D02*
X203312464Y-43080000D01*
%TO.C,C4*%
X217727464Y-35043748D02*
X217727464Y-35566252D01*
X219197464Y-35043748D02*
X219197464Y-35566252D01*
%TO.C,R1*%
X215227464Y-35077936D02*
X215227464Y-35532064D01*
X216697464Y-35077936D02*
X216697464Y-35532064D01*
X215227464Y-35077936D02*
X215227464Y-35532064D01*
%TO.C,C2.2*%
X206447464Y-39793748D02*
X206447464Y-40316252D01*
X204977464Y-39793748D02*
X204977464Y-40316252D01*
%TO.C,L1*%
X203312464Y-36880000D02*
X203312464Y-43080000D01*
X202862464Y-43080000D02*
X203312464Y-43080000D01*
X202862464Y-36880000D02*
X203312464Y-36880000D01*
X197562464Y-43080000D02*
X197112464Y-43080000D01*
X197562464Y-36880000D02*
X197112464Y-36880000D01*
X197112464Y-43080000D02*
X197112464Y-36880000D01*
%TO.C,C4*%
X219197464Y-35043748D02*
X219197464Y-35566252D01*
X217727464Y-35043748D02*
X217727464Y-35566252D01*
%TO.C,U4*%
X210624964Y-34195000D02*
X211424964Y-34195000D01*
X210624964Y-37315000D02*
X211424964Y-37315000D01*
X212224964Y-34195000D02*
X211424964Y-34195000D01*
X212224964Y-37315000D02*
X211424964Y-37315000D01*
X212724964Y-34245000D02*
X212484964Y-33915000D01*
X212964964Y-33915000D01*
@@ -463,20 +455,28 @@ X212484964Y-33915000D01*
X212964964Y-33915000D01*
X212724964Y-34245000D01*
G37*
X212224964Y-37315000D02*
X211424964Y-37315000D01*
X212224964Y-34195000D02*
X211424964Y-34195000D01*
X210624964Y-37315000D02*
X211424964Y-37315000D01*
X210624964Y-34195000D02*
X211424964Y-34195000D01*
%TO.C,C2.1*%
X207477464Y-39793748D02*
X207477464Y-40316252D01*
X208947464Y-39793748D02*
X208947464Y-40316252D01*
X207477464Y-39793748D02*
X207477464Y-40316252D01*
%TO.C,C3*%
X205727464Y-34343748D02*
X205727464Y-34866252D01*
X207197464Y-34343748D02*
X207197464Y-34866252D01*
X205727464Y-34343748D02*
X205727464Y-34866252D01*
%TO.C,C1*%
X211451212Y-38320000D02*
X211973716Y-38320000D01*
X211451212Y-39790000D02*
X211973716Y-39790000D01*
X211451212Y-38320000D02*
X211973716Y-38320000D01*
%TD*%
M02*

View File

@@ -1,11 +1,11 @@
%TF.GenerationSoftware,KiCad,Pcbnew,8.0.1*%
%TF.CreationDate,2024-04-10T00:32:00-05:00*%
%TF.CreationDate,2024-04-27T00:37:20-05:00*%
%TF.ProjectId,ControlMixer,436f6e74-726f-46c4-9d69-7865722e6b69,rev?*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Profile,NP*%
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 8.0.1) date 2024-04-10 00:32:00*
G04 Created by KiCad (PCBNEW 8.0.1) date 2024-04-27 00:37:20*
%MOMM*%
%LPD*%
G01*

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,12 @@
%TF.GenerationSoftware,KiCad,Pcbnew,8.0.1*%
%TF.CreationDate,2024-04-10T00:32:05-05:00*%
%TF.CreationDate,2024-04-27T00:37:23-05:00*%
%TF.ProjectId,ControlMixer,436f6e74-726f-46c4-9d69-7865722e6b69,rev?*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Drillmap*%
%TF.FilePolarity,Positive*%
%FSLAX45Y45*%
G04 Gerber Fmt 4.5, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 8.0.1) date 2024-04-10 00:32:05*
G04 Created by KiCad (PCBNEW 8.0.1) date 2024-04-27 00:37:23*
%MOMM*%
%LPD*%
G01*

View File

@@ -1,7 +1,7 @@
M48
; DRILL file {KiCad 8.0.1} date 2024-04-10T00:32:04-0500
; DRILL file {KiCad 8.0.1} date 2024-04-27T00:37:22-0500
; FORMAT={-:-/ absolute / inch / decimal}
; #@! TF.CreationDate,2024-04-10T00:32:04-05:00
; #@! TF.CreationDate,2024-04-27T00:37:22-05:00
; #@! TF.GenerationSoftware,Kicad,Pcbnew,8.0.1
; #@! TF.FileFunction,NonPlated,1,2,NPTH
FMAT,2

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
M48
; DRILL file {KiCad 8.0.1} date 2024-04-10T00:32:04-0500
; DRILL file {KiCad 8.0.1} date 2024-04-27T00:37:22-0500
; FORMAT={-:-/ absolute / inch / decimal}
; #@! TF.CreationDate,2024-04-10T00:32:04-05:00
; #@! TF.CreationDate,2024-04-27T00:37:22-05:00
; #@! TF.GenerationSoftware,Kicad,Pcbnew,8.0.1
; #@! TF.FileFunction,Plated,1,2,PTH
FMAT,2
@@ -41,27 +41,27 @@ X3.5531Y-2.9451
X3.6319Y-2.886
X3.6909Y-5.012
X3.7106Y-3.2207
X3.7205Y-2.5514
X3.7303Y-3.5553
X3.7303Y-3.8703
X3.7303Y-4.3624
X3.7303Y-4.697
X4.0846Y-2.5514
X4.1142Y-5.3663
X4.1732Y-2.1281
X4.2618Y-5.3663
X4.4094Y-2.1281
X4.498Y-5.327
X5.0492Y-3.1419
X5.1673Y-5.012
X5.187Y-3.2207
X5.187Y-4.697
X5.1969Y-2.5514
X5.2067Y-2.886
X5.2067Y-3.5553
X5.2067Y-3.8703
X5.2067Y-4.3624
X5.2264Y-3.1419
X5.561Y-2.5514
X5.6102Y-5.3618
X5.6988Y-2.0789
X5.7776Y-5.3663
X5.9154Y-2.0789
X6.0531Y-5.386
X6.7028Y-4.697
@@ -71,7 +71,7 @@ X6.7421Y-2.886
X6.7421Y-3.2207
X6.7421Y-3.5553
X6.7421Y-3.8703
X7.0768Y-2.5514
X6.752Y-2.5514
X7.2343Y-2.1183
X7.2736Y-5.327
X7.4114Y-2.1183
@@ -92,6 +92,7 @@ X8.1988Y-2.886
X8.1988Y-3.2207
X8.1988Y-3.5553
X8.1988Y-3.8703
X8.2087Y-2.5474
X8.217Y-1.4884
X8.2269Y-1.2423
X8.2269Y-1.2719
@@ -122,12 +123,18 @@ X8.5335Y-1.6262
X8.5335Y-1.6656
X8.5335Y-1.7049
X8.5335Y-1.7443
X8.5335Y-2.5514
X8.5531Y-2.01
X8.563Y-4.2126
X8.563Y-4.7638
X8.5925Y-1.5278
X8.7697Y-5.3762
X8.622Y-5.3762
X8.7598Y-3.0709
X8.7598Y-3.3661
X8.7598Y-3.7205
X8.7598Y-4.1339
X8.7795Y-4.5276
X8.7992Y-2.7165
X8.937Y-5.7874
X8.9469Y-2.886
X8.9469Y-4.9333
X8.9764Y-2.3425
@@ -137,17 +144,24 @@ X9.0256Y-2.9254
X9.0256Y-4.9333
X9.065Y-2.9451
X9.065Y-4.9333
X9.1142Y-4.8819
X9.1142Y-5.0591
X9.2618Y-1.9805
X9.2815Y-4.2246
X9.311Y-2.2638
X9.3209Y-2.9451
X9.3307Y-3.5236
X9.3701Y-2.7285
X9.4488Y-3.6417
X9.4587Y-2.9451
X9.4587Y-4.2246
X9.4685Y-1.9094
X9.4882Y-2.6772
X9.5374Y-2.5907
X9.6063Y-2.2638
X9.6324Y-3.0863
X9.6457Y-3.89
X9.7047Y-2.6378
T2
X1.7626Y-5.2585
X1.8126Y-5.2585
@@ -165,96 +179,96 @@ X7.7536Y-5.2585
X7.8036Y-5.2585
X7.8536Y-5.2585
T3
X1.6273Y-5.5864
X1.6273Y-5.8864
X1.7801Y-5.5864
X1.7801Y-5.8864
X1.9329Y-5.5864
X1.9329Y-5.8864
X2.0857Y-5.5864
X2.0857Y-5.8864
X2.2385Y-5.5864
X2.2385Y-5.8864
X2.3913Y-5.5864
X2.3913Y-5.8864
X2.5441Y-5.5864
X2.5441Y-5.8864
X2.6969Y-5.5864
X2.6969Y-5.8864
X2.8497Y-5.5864
X2.8497Y-5.8864
X3.1432Y-5.5864
X3.1432Y-5.8864
X3.296Y-5.5864
X3.296Y-5.8864
X3.4488Y-5.5864
X3.4488Y-5.8864
X3.6016Y-5.5864
X3.6016Y-5.8864
X3.7544Y-5.5864
X3.7544Y-5.8864
X3.9072Y-5.5864
X3.9072Y-5.8864
X4.06Y-5.5864
X4.06Y-5.8864
X4.2128Y-5.5864
X4.2128Y-5.8864
X4.3656Y-5.5864
X4.3656Y-5.8864
X4.659Y-5.5864
X4.659Y-5.8864
X4.8118Y-5.5864
X4.8118Y-5.8864
X4.9646Y-5.5864
X4.9646Y-5.8864
X5.1174Y-5.5864
X5.1174Y-5.8864
X5.2702Y-5.5864
X5.2702Y-5.8864
X5.423Y-5.5864
X5.423Y-5.8864
X5.5758Y-5.5864
X5.5758Y-5.8864
X5.7286Y-5.5864
X5.7286Y-5.8864
X5.8814Y-5.5864
X5.8814Y-5.8864
X6.1688Y-5.5864
X6.1688Y-5.8864
X6.3216Y-5.5864
X6.3216Y-5.8864
X6.4744Y-5.5864
X6.4744Y-5.8864
X6.6272Y-5.5864
X6.6272Y-5.8864
X6.78Y-5.5864
X6.78Y-5.8864
X6.9328Y-5.5864
X6.9328Y-5.8864
X7.0856Y-5.5864
X7.0856Y-5.8864
X7.2384Y-5.5864
X7.2384Y-5.8864
X7.3912Y-5.5864
X7.3912Y-5.8864
X7.6452Y-5.5864
X7.6452Y-5.8864
X7.798Y-5.5864
X7.798Y-5.8864
X7.9508Y-5.5864
X7.9508Y-5.8864
X8.1036Y-5.5864
X8.1036Y-5.8864
X8.2564Y-5.5864
X8.2564Y-5.8864
X8.4092Y-5.5864
X8.4092Y-5.8864
X8.562Y-5.5864
X8.562Y-5.8864
X8.7148Y-5.5864
X8.7148Y-5.8864
X8.8676Y-5.5864
X8.8676Y-5.8864
X1.6319Y-5.5587
X1.6319Y-5.8587
X1.7847Y-5.5587
X1.7847Y-5.8587
X1.9375Y-5.5587
X1.9375Y-5.8587
X2.0903Y-5.5587
X2.0903Y-5.8587
X2.2431Y-5.5587
X2.2431Y-5.8587
X2.3959Y-5.5587
X2.3959Y-5.8587
X2.5487Y-5.5587
X2.5487Y-5.8587
X2.7015Y-5.5587
X2.7015Y-5.8587
X2.8543Y-5.5587
X2.8543Y-5.8587
X3.1432Y-5.5587
X3.1432Y-5.8587
X3.296Y-5.5587
X3.296Y-5.8587
X3.4488Y-5.5587
X3.4488Y-5.8587
X3.6016Y-5.5587
X3.6016Y-5.8587
X3.7544Y-5.5587
X3.7544Y-5.8587
X3.9072Y-5.5587
X3.9072Y-5.8587
X4.06Y-5.5587
X4.06Y-5.8587
X4.2128Y-5.5587
X4.2128Y-5.8587
X4.3656Y-5.5587
X4.3656Y-5.8587
X4.659Y-5.5587
X4.659Y-5.8587
X4.8118Y-5.5587
X4.8118Y-5.8587
X4.9646Y-5.5587
X4.9646Y-5.8587
X5.1174Y-5.5587
X5.1174Y-5.8587
X5.2702Y-5.5587
X5.2702Y-5.8587
X5.423Y-5.5587
X5.423Y-5.8587
X5.5758Y-5.5587
X5.5758Y-5.8587
X5.7286Y-5.5587
X5.7286Y-5.8587
X5.8814Y-5.5587
X5.8814Y-5.8587
X6.1688Y-5.5587
X6.1688Y-5.8587
X6.3216Y-5.5587
X6.3216Y-5.8587
X6.4744Y-5.5587
X6.4744Y-5.8587
X6.6272Y-5.5587
X6.6272Y-5.8587
X6.78Y-5.5587
X6.78Y-5.8587
X6.9328Y-5.5587
X6.9328Y-5.8587
X7.0856Y-5.5587
X7.0856Y-5.8587
X7.2384Y-5.5587
X7.2384Y-5.8587
X7.3912Y-5.5587
X7.3912Y-5.8587
X7.6452Y-5.5587
X7.6452Y-5.8587
X7.798Y-5.5587
X7.798Y-5.8587
X7.9508Y-5.5587
X7.9508Y-5.8587
X8.1036Y-5.5587
X8.1036Y-5.8587
X8.2564Y-5.5587
X8.2564Y-5.8587
X8.4092Y-5.5587
X8.4092Y-5.8587
X8.562Y-5.5587
X8.562Y-5.8587
X8.7148Y-5.5587
X8.7148Y-5.8587
X8.8676Y-5.5587
X8.8676Y-5.8587
X9.2394Y-3.2435
X9.2394Y-3.3435
X9.2394Y-3.4435

View File

@@ -5,7 +5,7 @@
"Application": "Pcbnew",
"Version": "8.0.1"
},
"CreationDate": "2024-04-10T00:32:00-05:00"
"CreationDate": "2024-04-27T00:37:20-05:00"
},
"GeneralSpecs": {
"ProjectId": {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
import board
import digitalio
import usb_mixer
recovery_pin = digitalio.DigitalInOut(board.D3)
recovery_pin.direction = digitalio.Direction.INPUT
recovery_pin.pull = digitalio.Pull.UP
if recovery_pin.value == True:
print("Booting normal mode")
usb_mixer.initUsb()
else:
print("Booting recovery mode")

View File

@@ -0,0 +1,63 @@
import usb_mixer
import board
import adafruit_dotstar
import analogio
import time
import math
import ulab.numpy
import supervisor
import key_interface
import storage
ANALOG_SAMPLE_SIZE=150
pixel = adafruit_dotstar.DotStar(board.DOTSTAR_CLOCK, board.DOTSTAR_DATA, 1)
slider_in = [
analogio.AnalogIn(board.A0),
analogio.AnalogIn(board.A1),
analogio.AnalogIn(board.A2),
analogio.AnalogIn(board.A3),
analogio.AnalogIn(board.A4)
]
i2c = board.I2C()
keys = key_interface.KeyInterface(i2c)
slider_vals = [0,0,0,0,0]
buttons = [0,0,0,0,0]
def readSlider(num):
vals = []
for i in range(0, ANALOG_SAMPLE_SIZE):
vals.append((slider_in[num].value / 0xFFFF) * 0xFFF) # Scale analogio back to ADC resolution
val_median = ulab.numpy.mean(ulab.numpy.ndarray(vals))
return math.floor((val_median / 0xFFF) * usb_mixer.RESOLUTION)
try:
pixel.fill((0,0,32))
while not supervisor.runtime.usb_connected:
time.sleep(0.5)
mixer = usb_mixer.UsbMixer()
pixel.fill((0,32,0))
while True:
new_values = [
readSlider(0),
readSlider(1),
readSlider(2),
readSlider(3),
readSlider(4)
]
new_buttons = keys.scan()
if new_values != slider_vals or new_buttons != buttons:
mixer.send_values(new_values[0], new_values[1], new_values[2], new_values[3], new_values[4], new_buttons)
pixel.fill((32,32,32))
slider_vals = new_values
buttons = new_buttons
pixel.fill((0,32,0))
time.sleep(0.001)
except Exception as ex:
pixel.fill((255,0,0))
with open("/runtime_ex.txt", "w") as fp:
fp.write(ex)
print(ex)

View File

@@ -0,0 +1,40 @@
import board
import busio
import digitalio
from adafruit_mcp230xx.mcp23017 import MCP23017
class KeyInterface:
_MCP23017_OLATA = 0x14
_MCP23017_OLATB = 0x15
def set_olata(self, val: int):
self.mcp._write_u8(self._MCP23017_OLATA, val)
def set_olatb(self, val: int):
self.mcp._write_u8(self._MCP23017_OLATB, val)
def __init__(self, i2c):
self._i2c = i2c
# Turn on MCP
self._mcp_reset_pin = digitalio.DigitalInOut(board.D4)
self._mcp_reset_pin.direction = digitalio.Direction.OUTPUT
self._mcp_reset_pin.value = True
# Initialize MCP
self.mcp = MCP23017(self._i2c)
# Set up MCP pins
self.mcp.iodirb = 255 # GPIO B (rows) all input
self.mcp.ipolb = 255 # GPIO B inverted polarity
self.mcp.gppub = 255 # GPIO B all pulled up
self.set_olata(0) # GPIO A all output low
def scan(self):
result = []
for i in range(0, 6):
self.mcp.iodira = 0xFF ^ (0x01 << i)
result.append(self.mcp.gpiob)
self.mcp.iodira = 0xFF
return result

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,111 @@
from power import HUSB238
import board
import neopixel
VM_GREEN = (32,255,32)
VM_RED = (255,16,16)
LED1 = 1 << 0 # 1
LED2 = 1 << 1 # 2
LED3 = 1 << 2 # 4
LED4 = 1 << 3 # 8
LED5 = 1 << 4 # 16
LED6 = 1 << 5 # 32
LED7 = 1 << 6 # 64
LED8 = 1 << 7 # 128
LED9 = 1 << 8 # 256
LED10 = 1 << 9 # 512
LED11 = 1 << 10 # 1024
LED12 = 1 << 11 # 2048
LED13 = 1 << 12 # 4096
LED14 = 1 << 13 # 8192
LED15 = 1 << 14 # 16384
LED16 = 1 << 15 # 32768
LED17 = 1 << 16 # 65536
LED18 = 1 << 17 # 131072
LED19 = 1 << 18 # 262144
LED20 = 1 << 19 # 524288
LED21 = 1 << 20 # 1048576
LED22 = 1 << 21 # 2097152
LED23 = 1 << 22 # 4194304
LED24 = 1 << 23 # 8388608
LED25 = 1 << 24 # 16777216
LED26 = 1 << 25 # 33554432
LED27 = 1 << 26 # 67108864
LED28 = 1 << 27 # 134217728
LED29 = 1 << 28 # 268435456
LED30 = 1 << 29 # 536870912
LED31 = 1 << 30 # 1073741824
LED32 = 1 << 31 # 2147483648
LED33 = 1 << 32 # 4294967296
LED34 = 1 << 33 # 8589934592
LED35 = 1 << 34 # 17179869184
LED36 = 1 << 35 # 34359738368
LED37 = 1 << 36 # 68719476736
LED38 = 1 << 37 # 137438953472
LED39 = 1 << 38 # 274877906944
LED40 = 1 << 39 # 549755813888
LED41 = 1 << 40 # 1099511627776
LED42 = 1 << 41 # 2199023255552
LED43 = 1 << 42 # 4398046511104
LED44 = 1 << 43 # 8796093022208
LED45 = 1 << 44 # 17592186044416
leds = [
LED1, LED2, LED3, LED4, LED5,
LED6, LED7, LED8, LED9, LED10,
LED11, LED12, LED13, LED14, LED15,
LED16, LED17, LED18, LED19, LED20,
LED21, LED22, LED23, LED24, LED25,
LED26, LED27, LED28, LED29, LED30,
LED31, LED32, LED33, LED34, LED35,
LED36, LED37, LED38, LED39, LED40,
LED41, LED42, LED43, LED44, LED45
]
def get_led_states(value):
return [(value & led) != 0 for led in leds]
_COLORS = [
VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN,
VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN,
VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN,
VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN,
VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN
]
class MixerLeds:
def __init__(self, i2c, max_brightness = 1):
self._i2c = i2c
self._pd = HUSB238(i2c)
self._pixels = neopixel.NeoPixel(board.D5, 45, auto_write=False, brightness=max_brightness)
self._known_wattage = 0
self._max_brightness = max_brightness
def _init_pd(self):
if not self._pd.connect():
print('Init PD failed to start connection')
return False
if self._known_wattage == self._pd.wattage:
return True
available_wattage = self._pd.attempt_wattage(30)
self._known_wattage = available_wattage[1]
if not available_wattage[0]:
self._pixels.deinit()
available_brightness = max(available_wattage[1]/30.0, self._max_brightness)
self._pixels = neopixel.NeoPixel(board.D5, 45, brightness=available_brightness, auto_write=False)
return True
def set_state(self, state):
if not self._init_pd():
return False
for idx, led_state in enumerate(get_led_states(state)):
if (led_state):
self._pixels[idx] = _COLORS[idx]
else:
self._pixels[idx] = (0,0,0)
self._pixels.show()
return True

View File

@@ -0,0 +1,88 @@
import adafruit_husb238
import time
class HUSB238:
_pd = None
def __init__(self, i2c):
self._i2c = i2c
def connect(self):
if (self.is_connected()):
try:
return self._pd.attached
except Exception as e:
return False
try:
self._pd = adafruit_husb238.Adafruit_HUSB238(self._i2c)
return True
except Exception as e:
self._pd = None
return False
def is_connected(self):
if self._pd is not None:
try:
return self._pd.attached
except Exception as e:
self._pd = None
return False
else:
return False
def attempt_wattage(self, watts):
if not self.is_connected():
return False, 0
if self.wattage >= watts:
return True, self.wattage
voltages = self.available_voltages
next_voltage_index = voltages.index(self.voltage) + 1
while self.wattage < watts and next_voltage_index < len(voltages):
if not self.is_connected():
print('Connection lost')
return False, 0
target = voltages[next_voltage_index]
self.voltage = target
time.sleep(1)
if (self._pd.voltage != target):
print(f'Voltage did not switch to {target}v')
return False, self.wattage
next_voltage_index += 1
resulting_wattage = self.wattage
return resulting_wattage >= watts, resulting_wattage
@property
def wattage(self):
return self.voltage * self.current
@property
def available_voltages(self):
return self._safe_pd_call(lambda: self._pd.available_voltages, [])
@property
def voltage(self):
return self._safe_pd_call(lambda: self._pd.voltage, 0);
@voltage.setter
def voltage(self, value):
self._pd.voltage = value
@property
def current(self):
return self._safe_pd_call(lambda: self._pd.current, 0)
def _unsafe_pd_call(self, func, default_val, attempts=20):
attempt_count = 0
while attempt_count < attempts:
try:
return func()
except Exception as e:
print('unsafe waiting')
time.sleep(0.5)
return default_val
def _safe_pd_call(self, func, default_val):
if self.is_connected():
return func()
else:
return default_val

View File

@@ -0,0 +1 @@
SD cards mounted at /sd will hide this file from Python. SD cards are not visible via USB CIRCUITPY.

View File

View File

@@ -0,0 +1,86 @@
import usb_hid
import supervisor
import storage
import usb_midi
DEFAULT_REPORT_ID = 1
HANDSHAKE_REPORT_ID = 2
VENDOR_ID = 0x0359
PRODUCT_ID = 0x6497 # T9 MIXR
RESOLUTION = 100 # Voicemeeter sliders go from 12.0 to -60.0 in 0.1 increments
REPORT_DESCRIPTOR = bytes([
0x05, 0x01, # Usage Page (Generic Desktop Controls)
0x09, 0x08, # Usage (Multi-Axis Controller)
#0x09, 0x04, # Joystick usage (for windows to pick up as usb controller)
0xA1, 0x01, # Collection (Application)
# BUTTONS
0x05, 0x09, # Usage Page (Button)
0x19, 0x01, # Usage Minimum (Button 1)
0x29, 0x30, # Usage Maximum (Button 48)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x01, # Logical Maximum (1)
0x75, 0x01, # Report Size (1 bit)
0x95, 0x30, # Report Count (48)
0x81, 0x02, # Input (Data, Variable, Absolute)
# SLIDERS
0x15, 0x00, # Logical Minimum (0)
0x26, 0xFF, 0xFF, # Logical Maximum (RESOLUTION (720))
0x75, 0x10, # Report Size (16-bit)
#0x85, DEFAULT_REPORT_ID, # Report ID (DEFAULT_REPORT_ID)
0x95, 0x05, # Report Count (5)
0x09, 0x30, # Usage (X)
0x09, 0x31, # Usage (Y)
0x09, 0x32, # Usage (Z)
0x09, 0x33, # Usage (Rx)
0x09, 0x34, # Usage (Ry)
0x81, 0x00, # Input (Data, Array, Absolute)
0xC0, # End Collection
#0x05, 0x06, # Usage Page (Generic Device Controls)
#0x09, 0x01, # Usage (Background/Nonuser controls)
#0xA1, 0x01, # Collection (Application)
#0x75, 0x20, # Report Size (32-bit)
#0x95, 0x01, # Report Count (1)
#0x85, HANDSHAKE_REPORT_ID,# Report ID (HANDSHAKE_REPORT_ID)
#0x81, 0x01, # Input (Constant, Array, Absolute)
#0xC0, # End Collection
])
def initUsb():
if supervisor.runtime.usb_connected:
raise RuntimeError("USB cannot be initialized post-boot")
supervisor.set_usb_identification(manufacturer="TechAbsol", product="USB Mixer", vid=VENDOR_ID, pid=PRODUCT_ID)
usb_midi.disable()
usb_hid.set_interface_name("CircuitPython Mixer")
sliders = usb_hid.Device(
report_descriptor = REPORT_DESCRIPTOR,
usage_page=0x01,
usage=0x08,
report_ids=(0,),
in_report_lengths=(16,),
out_report_lengths=(0,),
)
#storage.disable_usb_drive()
#storage.remount("/", False)
usb_hid.enable((sliders,))
class UsbMixer():
def __init__(self):
if not supervisor.runtime.usb_connected:
raise RuntimeError("USB is not connected")
self._device = next((dev for dev in usb_hid.devices if dev.usage_page == 0x01 and dev.usage == 0x08))
if self._device is None:
raise RuntimeError("USB mixer doesn't appear to be initialized")
def _valToBytes(self, value):
return bytes([value & 0xFF, (value >> 8) & 0xFF])
def _keysToBytes(self, keys):
return bytes([keys[0], keys[1], keys[2], keys[3], keys[4], keys[5]])
def send_values(self, slider1, slider2, slider3, slider4, slider5, keys):
report = self._keysToBytes(keys) + self._valToBytes(slider1) + self._valToBytes(slider2) + self._valToBytes(slider3) + self._valToBytes(slider4) + self._valToBytes(slider5)
self._device.send_report(report)

View File

@@ -108,6 +108,7 @@
mixerAutoConnectCheckbox = new CheckBox();
mixerLabel = new Label();
notifyIcon1 = new NotifyIcon(components);
listBox1 = new ListBox();
groupBox1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)trackBar1).BeginInit();
((System.ComponentModel.ISupportInitialize)trackBar2).BeginInit();
@@ -202,6 +203,7 @@
autoConnectCheckBox.TabIndex = 71;
autoConnectCheckBox.Text = "Auto-connect on start";
autoConnectCheckBox.UseVisualStyleBackColor = true;
autoConnectCheckBox.CheckedChanged += autoConnectCheckBox_CheckedChanged;
//
// button1
//
@@ -479,6 +481,7 @@
checkBox5.TabIndex = 38;
checkBox5.Text = "B3";
checkBox5.UseVisualStyleBackColor = true;
checkBox5.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox6
//
@@ -490,6 +493,7 @@
checkBox6.TabIndex = 37;
checkBox6.Text = "B2";
checkBox6.UseVisualStyleBackColor = true;
checkBox6.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox7
//
@@ -501,6 +505,7 @@
checkBox7.TabIndex = 36;
checkBox7.Text = "B1";
checkBox7.UseVisualStyleBackColor = true;
checkBox7.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox8
//
@@ -512,6 +517,7 @@
checkBox8.TabIndex = 35;
checkBox8.Text = "A5";
checkBox8.UseVisualStyleBackColor = true;
checkBox8.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox9
//
@@ -523,6 +529,7 @@
checkBox9.TabIndex = 34;
checkBox9.Text = "A4";
checkBox9.UseVisualStyleBackColor = true;
checkBox9.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox10
//
@@ -534,6 +541,7 @@
checkBox10.TabIndex = 33;
checkBox10.Text = "A3";
checkBox10.UseVisualStyleBackColor = true;
checkBox10.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox11
//
@@ -546,6 +554,7 @@
checkBox11.Tag = "A2";
checkBox11.Text = "A2";
checkBox11.UseVisualStyleBackColor = true;
checkBox11.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox12
//
@@ -558,6 +567,7 @@
checkBox12.Tag = "";
checkBox12.Text = "A1";
checkBox12.UseVisualStyleBackColor = true;
checkBox12.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox13
//
@@ -593,6 +603,7 @@
checkBox15.TabIndex = 48;
checkBox15.Text = "B3";
checkBox15.UseVisualStyleBackColor = true;
checkBox15.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox16
//
@@ -604,6 +615,7 @@
checkBox16.TabIndex = 47;
checkBox16.Text = "B2";
checkBox16.UseVisualStyleBackColor = true;
checkBox16.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox17
//
@@ -615,6 +627,7 @@
checkBox17.TabIndex = 46;
checkBox17.Text = "B1";
checkBox17.UseVisualStyleBackColor = true;
checkBox17.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox18
//
@@ -626,6 +639,7 @@
checkBox18.TabIndex = 45;
checkBox18.Text = "A5";
checkBox18.UseVisualStyleBackColor = true;
checkBox18.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox19
//
@@ -637,6 +651,7 @@
checkBox19.TabIndex = 44;
checkBox19.Text = "A4";
checkBox19.UseVisualStyleBackColor = true;
checkBox19.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox20
//
@@ -648,6 +663,7 @@
checkBox20.TabIndex = 43;
checkBox20.Text = "A3";
checkBox20.UseVisualStyleBackColor = true;
checkBox20.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox21
//
@@ -660,6 +676,7 @@
checkBox21.Tag = "A2";
checkBox21.Text = "A2";
checkBox21.UseVisualStyleBackColor = true;
checkBox21.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox22
//
@@ -672,6 +689,7 @@
checkBox22.Tag = "";
checkBox22.Text = "A1";
checkBox22.UseVisualStyleBackColor = true;
checkBox22.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox23
//
@@ -707,6 +725,7 @@
checkBox25.TabIndex = 58;
checkBox25.Text = "B3";
checkBox25.UseVisualStyleBackColor = true;
checkBox25.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox26
//
@@ -718,6 +737,7 @@
checkBox26.TabIndex = 57;
checkBox26.Text = "B2";
checkBox26.UseVisualStyleBackColor = true;
checkBox26.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox27
//
@@ -729,6 +749,7 @@
checkBox27.TabIndex = 56;
checkBox27.Text = "B1";
checkBox27.UseVisualStyleBackColor = true;
checkBox27.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox28
//
@@ -740,6 +761,7 @@
checkBox28.TabIndex = 55;
checkBox28.Text = "A5";
checkBox28.UseVisualStyleBackColor = true;
checkBox28.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox29
//
@@ -751,6 +773,7 @@
checkBox29.TabIndex = 54;
checkBox29.Text = "A4";
checkBox29.UseVisualStyleBackColor = true;
checkBox29.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox30
//
@@ -762,6 +785,7 @@
checkBox30.TabIndex = 53;
checkBox30.Text = "A3";
checkBox30.UseVisualStyleBackColor = true;
checkBox30.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox31
//
@@ -774,6 +798,7 @@
checkBox31.Tag = "A2";
checkBox31.Text = "A2";
checkBox31.UseVisualStyleBackColor = true;
checkBox31.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox32
//
@@ -786,6 +811,7 @@
checkBox32.Tag = "";
checkBox32.Text = "A1";
checkBox32.UseVisualStyleBackColor = true;
checkBox32.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox33
//
@@ -821,6 +847,7 @@
checkBox35.TabIndex = 68;
checkBox35.Text = "B3";
checkBox35.UseVisualStyleBackColor = true;
checkBox35.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox36
//
@@ -832,6 +859,7 @@
checkBox36.TabIndex = 67;
checkBox36.Text = "B2";
checkBox36.UseVisualStyleBackColor = true;
checkBox36.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox37
//
@@ -843,6 +871,7 @@
checkBox37.TabIndex = 66;
checkBox37.Text = "B1";
checkBox37.UseVisualStyleBackColor = true;
checkBox37.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox38
//
@@ -854,6 +883,7 @@
checkBox38.TabIndex = 65;
checkBox38.Text = "A5";
checkBox38.UseVisualStyleBackColor = true;
checkBox38.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox39
//
@@ -865,6 +895,7 @@
checkBox39.TabIndex = 64;
checkBox39.Text = "A4";
checkBox39.UseVisualStyleBackColor = true;
checkBox39.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox40
//
@@ -876,6 +907,7 @@
checkBox40.TabIndex = 63;
checkBox40.Text = "A3";
checkBox40.UseVisualStyleBackColor = true;
checkBox40.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox41
//
@@ -888,6 +920,7 @@
checkBox41.Tag = "A2";
checkBox41.Text = "A2";
checkBox41.UseVisualStyleBackColor = true;
checkBox41.CheckedChanged += busCheckbox_CheckedChanged;
//
// checkBox42
//
@@ -900,6 +933,7 @@
checkBox42.Tag = "";
checkBox42.Text = "A1";
checkBox42.UseVisualStyleBackColor = true;
checkBox42.CheckedChanged += busCheckbox_CheckedChanged;
//
// slider1Label
//
@@ -967,6 +1001,7 @@
mixerAutoConnectCheckbox.TabIndex = 8;
mixerAutoConnectCheckbox.Text = "Auto-connect on start";
mixerAutoConnectCheckbox.UseVisualStyleBackColor = true;
mixerAutoConnectCheckbox.CheckedChanged += checkBox43_CheckedChanged;
//
// mixerLabel
//
@@ -982,12 +1017,23 @@
notifyIcon1.Icon = (Icon)resources.GetObject("notifyIcon1.Icon");
notifyIcon1.Text = "notifyIcon1";
notifyIcon1.Visible = true;
notifyIcon1.Click += notifyIcon1_Click;
//
// listBox1
//
listBox1.FormattingEnabled = true;
listBox1.ItemHeight = 15;
listBox1.Location = new Point(12, 278);
listBox1.Name = "listBox1";
listBox1.Size = new Size(200, 64);
listBox1.TabIndex = 77;
//
// Form1
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(780, 363);
Controls.Add(listBox1);
Controls.Add(groupBox2);
Controls.Add(slider5Label);
Controls.Add(slider4Label);
@@ -1058,6 +1104,7 @@
Name = "Form1";
Text = "Form1";
FormClosing += Form1_FormClosing;
Resize += Form1_Resize;
groupBox1.ResumeLayout(false);
groupBox1.PerformLayout();
((System.ComponentModel.ISupportInitialize)trackBar1).EndInit();
@@ -1156,5 +1203,6 @@
private CheckBox mixerAutoConnectCheckbox;
private Label mixerLabel;
private NotifyIcon notifyIcon1;
private ListBox listBox1;
}
}

View File

@@ -1,17 +1,21 @@
using System.Diagnostics;
using System.Reflection;
using HidLibrary;
using HidSliders.Hid;
using Voicemeeter;
using VoiceMeeter;
using Timer = System.Windows.Forms.Timer;
namespace HidSliders.Gui
{
public partial class Form1 : Form
{
private IDisposable? _vmClient;
private IHidDevice? _hidDevice;
private const float Resolution = 72.0f;
private bool _mixerConnected;
private List<MixerButton> _previousButtons = [];
private readonly HidInterface _hidInterface;
private const int ZeroPercent = 90;
private readonly List<ChannelControlCollection> _channels;
private bool _suppressCheckboxUpdate = false;
private Timer _syncTimer = new();
public Form1()
{
InitializeComponent();
@@ -44,24 +48,134 @@ namespace HidSliders.Gui
_channels[3].ChannelSelector.Value = Properties.Settings.Default.Channel4Strip;
_channels[4].ChannelSelector.Value = Properties.Settings.Default.Channel5Strip;
_syncTimer.Tick += SyncVM;
_syncTimer.Interval = 100;
_syncTimer.Enabled = true;
if (Properties.Settings.Default.AutoConnect)
{
autoConnectCheckBox.Checked = true;
Task.Run(ConnectVoicemeeter).Wait();
}
var enumerator = new HidEnumerator();
var hidDevices = enumerator.Enumerate(0x0359, [0x6497]);
_hidDevice = hidDevices.FirstOrDefault();
voicemeeterStatusLabel.Text = $"Mixer {(_hidDevice?.IsConnected == true ? "" : "not ")}connected";
_hidInterface = new HidInterface();
mixerLabel.Text = "Mixer not connected";
if (_hidDevice?.IsConnected == true && Properties.Settings.Default.MixerAutoConnect)
if (Properties.Settings.Default.MixerAutoConnect)
{
UsbListenerLoop();
ConnectHidMixer();
mixerAutoConnectCheckbox.Checked = true;
}
}
private void OnSliderValues(int[] values)
{
this.BeginInvoke(() =>
{
for (int i = 0; i < 5; i++)
{
var gain = HidToGain(values[i]);
SetStripGain(_channels[i].CurrentStrip, gain);
_channels[i].TrackBar.Value = (int)gain;
_channels[i].IndicatorLabel.Text = $"{gain} dB";
}
});
}
private void HandleButtonPress(MixerButton button)
{
var buttonGroup = MixerButtonHelper.GetButtonGroup(button);
var channelButton = MixerButtonHelper.GetChannelButton(button, buttonGroup);
ChannelControlCollection channel;
switch (buttonGroup)
{
case ButtonGroups.Channel1:
channel = _channels[0];
break;
case ButtonGroups.Channel2:
channel = _channels[1];
break;
case ButtonGroups.Channel3:
channel = _channels[2];
break;
case ButtonGroups.Channel4:
channel = _channels[3];
break;
case ButtonGroups.Channel5:
channel = _channels[4];
break;
default:
throw new Exception();
}
switch (channelButton)
{
case ChannelButton.ChannelA1:
channel.BusA1Checkbox.Checked = !channel.BusA1Checkbox.Checked;
break;
case ChannelButton.ChannelA2:
channel.BusA2Checkbox.Checked = !channel.BusA2Checkbox.Checked;
break;
case ChannelButton.ChannelA3:
channel.BusA3Checkbox.Checked = !channel.BusA3Checkbox.Checked;
break;
case ChannelButton.ChannelA4:
channel.BusA4Checkbox.Checked = !channel.BusA4Checkbox.Checked;
break;
case ChannelButton.ChannelA5:
channel.BusA5Checkbox.Checked = !channel.BusA5Checkbox.Checked;
break;
case ChannelButton.ChannelB1:
channel.BusB1Checkbox.Checked = !channel.BusB1Checkbox.Checked;
break;
case ChannelButton.ChannelB2:
channel.BusB2Checkbox.Checked = !channel.BusB2Checkbox.Checked;
break;
case ChannelButton.ChannelB3:
channel.BusB3Checkbox.Checked = !channel.BusB3Checkbox.Checked;
break;
case ChannelButton.ChannelMute:
channel.MuteCheckBox.Checked = !channel.MuteCheckBox.Checked;
break;
default:
throw new Exception();
}
listBox1.Items.Add($"{buttonGroup} {channelButton} pressed");
}
private void OnButtons(List<MixerButton> buttons)
{
BeginInvoke(() =>
{
var newButtons = buttons.Except(_previousButtons).ToList();
_previousButtons = buttons;
newButtons.ForEach(HandleButtonPress);
});
}
private void OnSliderComplete()
{
BeginInvoke(() =>
{
_mixerConnected = false;
button1.Enabled = true;
mixerLabel.Text = "Mixer disconnected";
});
}
private void ConnectHidMixer()
{
_mixerConnected = _hidInterface.ConnectDevice(0x0359, 0x6497);
if (_mixerConnected)
{
mixerLabel.Text = "Mixer connected";
button1.Enabled = false;
_hidInterface.SliderObservable.Subscribe(OnSliderValues, OnSliderComplete);
_hidInterface.ButtonsObservable.Subscribe(OnButtons);
}
}
private async Task ConnectVoicemeeter()
{
RunVoicemeeterParam version = RunVoicemeeterParam.None;
@@ -84,6 +198,7 @@ namespace HidSliders.Gui
{
EnableVMControls(version);
voicemeeterStatusLabel.Text = "Connected";
_syncTimer.Start();
}
}
@@ -92,6 +207,16 @@ namespace HidSliders.Gui
await ConnectVoicemeeter();
}
private void SyncVM(object? sender, EventArgs eventArgs)
{
if (_vmClient == null || Remote.IsParametersDirty() != 1) return;
foreach (var channelControlCollection in _channels)
{
SyncChannelControls(channelControlCollection);
}
}
private void EnableVMControls(RunVoicemeeterParam version)
{
foreach (var channel in _channels)
@@ -106,6 +231,7 @@ namespace HidSliders.Gui
private void SyncChannelControls(ChannelControlCollection channel)
{
_suppressCheckboxUpdate = true;
channel.BusA1Checkbox.Checked = GetBusEnabled(channel.CurrentStrip, VMBus.A1);
channel.BusB1Checkbox.Checked = GetBusEnabled(channel.CurrentStrip, VMBus.B1);
if (vmBananaRadio.Checked || vmPotatoRadio.Checked)
@@ -125,6 +251,7 @@ namespace HidSliders.Gui
channel.TrackBar.Value = (int)GetStripGain(channel.CurrentStrip);
channel.SoloCheckBox.Checked = GetChannelSolo(channel.CurrentStrip);
channel.MuteCheckBox.Checked = GetChannelMute(channel.CurrentStrip);
_suppressCheckboxUpdate = false;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
@@ -133,56 +260,54 @@ namespace HidSliders.Gui
Properties.Settings.Default.Save();
}
private async void UsbListenerLoop()
{
if (_hidDevice == null) return;
mixerLabel.Text = "Mixer online";
while (true)
{
if (_hidDevice.IsConnected)
{
button1.Enabled = false;
//label1.Text = "waiting for report";
var progress = new Progress<string>();
progress.ProgressChanged += (o, s) => voicemeeterStatusLabel.Text = s;
var report = await Task.Run(() => _hidDevice.ReadReport());
if (report.ReadStatus == HidDeviceData.ReadStatus.Success)
{
var reportChunk = new byte[2];
for (int i = 0; i < 5; i++)
{
Array.Copy(report.Data, i * 2, reportChunk, 0, 2);
var sliderVal = BitConverter.ToInt16(reportChunk);
var gain = HidToGain(sliderVal);
SetStripGain(_channels[i].CurrentStrip, gain);
_channels[i].TrackBar.Value = (int)gain;
_channels[i].IndicatorLabel.Text = $"{gain} dB";
}
}
//button1.Enabled = true;
}
else
{
button1.Enabled = true;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
UsbListenerLoop();
ConnectHidMixer();
}
private float HidToGain(int hidValue)
{
// adjusted regression of yamaha board is approx y = 5.8456 + 17.0486 * ln(x)
// Truncate to first decimal (move decimal, int truncate, move decimal)
var realResult = 5.8456f + 17.0486f * (float)Math.Log(Math.Max(hidValue / Resolution, 0.02));
return ((int)(realResult * 10)) / 10.0f;
//var realResult = 5.8456f + 17.0486f * (float)Math.Log(Math.Max(hidValue / Resolution, 0.02));
//return ((int)(realResult * 10)) / 10.0f;
return (int)(CalculateGain(hidValue, ZeroPercent) * 10) / 10.0f;
}
public static float CalculateGain(float slider, int zeroPct)
{
float minSlider;
float maxSlider;
float minGain;
float maxGain;
if (slider >= zeroPct)
{
minSlider = zeroPct;
maxSlider = 100;
minGain = 0;
maxGain = 12;
}
else
{
minSlider = 0;
maxSlider = zeroPct;
minGain = -60;
maxGain = 0;
}
// Calculate the percentage of slider position within the range
var percentage = (slider - minSlider) / (maxSlider - minSlider);
// Interpolate gain within the range based on the percentage
var calculatedGain = minGain + (percentage * (maxGain - minGain));
return calculatedGain;
}
private void trackBar_Scroll(object sender, EventArgs e)
{
if (_suppressCheckboxUpdate) return;
if (sender is TrackBar trackBar && _vmClient != null)
{
var channel = _channels.First(c => c.OwnsControl(trackBar));
@@ -192,6 +317,7 @@ namespace HidSliders.Gui
private void busCheckbox_CheckedChanged(object sender, EventArgs e)
{
if (_suppressCheckboxUpdate) return;
if (sender is CheckBox { Tag: VMBus bus } checkBox && _vmClient != null)
{
var channel = _channels.First(c => c.OwnsControl(checkBox));
@@ -242,8 +368,6 @@ namespace HidSliders.Gui
}
}
private void SetBusEnabled(int strip, VMBus bus, bool enabled)
{
Remote.SetParameter($"Strip[{strip}].{bus}", enabled ? 1 : 0);
@@ -291,6 +415,7 @@ namespace HidSliders.Gui
private void soloCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (_suppressCheckboxUpdate) return;
if (sender is CheckBox checkBox && _vmClient != null)
{
var channel = _channels.First(c => c.OwnsControl(checkBox));
@@ -300,6 +425,7 @@ namespace HidSliders.Gui
private void muteCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (_suppressCheckboxUpdate) return;
if (sender is CheckBox checkBox && _vmClient != null)
{
var channel = _channels.First(c => c.OwnsControl(checkBox));

View File

@@ -9,10 +9,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="hidlibrary" Version="3.3.40" />
<PackageReference Include="hidlibrary" Version="3.2.49" />
<PackageReference Include="VoicemeeterRemote" Version="1.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\HidSliders.Hid\HidSliders.Hid.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Settings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>

View File

@@ -1,7 +0,0 @@
namespace HidSliders.Hid
{
public class Class1
{
}
}

View File

@@ -0,0 +1,87 @@
using System.Reactive.Subjects;
using HidLibrary;
namespace HidSliders.Hid
{
public class HidInterface
{
private IHidDevice? _device;
private Subject<int[]> _sliderUpdate = new();
private Subject<List<MixerButton>> _buttonsUpdate = new();
public IObservable<int[]> SliderObservable => _sliderUpdate;
public IObservable<List<MixerButton>> ButtonsObservable => _buttonsUpdate;
public bool ConnectDevice(int vendorId, int devId)
{
var enumerator = new HidEnumerator();
IEnumerable<IHidDevice> hidDevices = enumerator.Enumerate(vendorId, [devId]);
_device = hidDevices.FirstOrDefault();
if (_device is { IsConnected: true })
{
_device.OpenDevice();
_device.MonitorDeviceEvents = true;
_device.ReadReport(OnReport);
_device.Removed += DeviceOnRemoved;
_device.Inserted += DeviceOnInserted;
}
return _device?.IsConnected ?? false;
}
private void DeviceOnInserted()
{
_sliderUpdate = new Subject<int[]>();
_buttonsUpdate = new Subject<List<MixerButton>>();
}
private void DeviceOnRemoved()
{
_sliderUpdate.OnCompleted();
_buttonsUpdate.OnCompleted();
}
private void ReadSliders(byte[] reportSliderBytes)
{
var reportChunk = new byte[4];
var sliderValues = new int[5];
for (int i = 0; i < 5; i++)
{
Array.Copy(reportSliderBytes, i * 2, reportChunk, 0, 2);
sliderValues[i] = BitConverter.ToInt32(reportChunk);
}
_sliderUpdate.OnNext(sliderValues);
}
private void ReadButtons(byte[] reportButtonBytes)
{
if (reportButtonBytes.Length != 8)
{
throw new ArgumentException("incoming report data was not padded to 8 bytes");
}
var buttonLong = BitConverter.ToInt64(reportButtonBytes);
_buttonsUpdate.OnNext(MixerButtonHelper.GetSetFlags(buttonLong));
}
private void ReadReport(byte[] reportBytes)
{
var buttons = new byte[8];
var sliders = new byte[10];
Array.Copy(reportBytes, 0, buttons, 0, 6);
Array.Copy(reportBytes, 6, sliders, 0, 10);
ReadSliders(sliders);
ReadButtons(buttons);
}
private void OnReport(HidReport report)
{
if (!_device!.IsConnected) return;
ReadReport(report.Data);
_device!.ReadReport(OnReport);
}
}
}

View File

@@ -7,7 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="hidlibrary" Version="3.3.40" />
<PackageReference Include="hidlibrary" Version="3.2.49" />
<PackageReference Include="System.Reactive" Version="6.0.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,75 @@
namespace HidSliders.Hid;
[Flags]
public enum MixerButton : long
{
Button1 = 1L << 0, // 1
Button2 = 1L << 1, // 2
Button3 = 1L << 2, // 4
Button4 = 1L << 3, // 8
Button5 = 1L << 4, // 16
Button6 = 1L << 5, // 32
Button7 = 1L << 6, // 64
Button8 = 1L << 7, // 128
Button9 = 1L << 8, // 256
Button10 = 1L << 9, // 512
Button11 = 1L << 10, // 1024
Button12 = 1L << 11, // 2048
Button13 = 1L << 12, // 4096
Button14 = 1L << 13, // 8192
Button15 = 1L << 14, // 16384
Button16 = 1L << 15, // 32768
Button17 = 1L << 16, // 65536
Button18 = 1L << 17, // 131072
Button19 = 1L << 18, // 262144
Button20 = 1L << 19, // 524288
Button21 = 1L << 20, // 1048576
Button22 = 1L << 21, // 2097152
Button23 = 1L << 22, // 4194304
Button24 = 1L << 23, // 8388608
Button25 = 1L << 24, // 16777216
Button26 = 1L << 25, // 33554432
Button27 = 1L << 26, // 67108864
Button28 = 1L << 27, // 134217728
Button29 = 1L << 28, // 268435456
Button30 = 1L << 29, // 536870912
Button31 = 1L << 30, // 1073741824
Button32 = 1L << 31, // 2147483648
Button33 = 1L << 32, // 4294967296
Button34 = 1L << 33, // 8589934592
Button35 = 1L << 34, // 17179869184
Button36 = 1L << 35, // 34359738368
Button37 = 1L << 36, // 68719476736
Button38 = 1L << 37, // 137438953472
Button39 = 1L << 38, // 274877906944
Button40 = 1L << 39, // 549755813888
Button41 = 1L << 40, // 1099511627776
Button42 = 1L << 41, // 2199023255552
Button43 = 1L << 42, // 4398046511104
Button44 = 1L << 43, // 8796093022208
Button45 = 1L << 44 // 17592186044416
}
[Flags]
public enum ButtonGroups : long
{
Channel1 = 0b00001_00000000_00000000_00000000_00000000_11111111,
Channel2 = 0b00010_00000000_00000000_00000000_11111111_00000000,
Channel3 = 0b00100_00000000_00000000_11111111_00000000_00000000,
Channel4 = 0b01000_00000000_11111111_00000000_00000000_00000000,
Channel5 = 0b10000_11111111_00000000_00000000_00000000_00000000,
}
[Flags]
public enum ChannelButton
{
ChannelA1 = 1 << 0,
ChannelA2 = 1 << 1,
ChannelA3 = 1 << 2,
ChannelA4 = 1 << 3,
ChannelA5 = 1 << 4,
ChannelB1 = 1 << 5,
ChannelB2 = 1 << 6,
ChannelB3 = 1 << 7,
ChannelMute = 1 << 8,
}

View File

@@ -0,0 +1,75 @@
namespace HidSliders.Hid;
public class MixerButtonHelper
{
public static List<MixerButton> GetSetFlags(long value)
{
var setFlags = new List<MixerButton>();
foreach (MixerButton flag in Enum.GetValues(typeof(MixerButton)))
{
if ((value & (long)flag) == (long)flag)
{
setFlags.Add(flag);
}
}
return setFlags;
}
public static ButtonGroups GetButtonGroup(MixerButton button)
{
var buttonValue = (long)button;
if (((long)ButtonGroups.Channel1 & buttonValue) != 0) return ButtonGroups.Channel1;
if (((long)ButtonGroups.Channel2 & buttonValue) != 0) return ButtonGroups.Channel2;
if (((long)ButtonGroups.Channel3 & buttonValue) != 0) return ButtonGroups.Channel3;
if (((long)ButtonGroups.Channel4 & buttonValue) != 0) return ButtonGroups.Channel4;
if (((long)ButtonGroups.Channel5 & buttonValue) != 0) return ButtonGroups.Channel5;
throw new ArgumentException("The provided button does not match any button group.", nameof(button));
}
public static ChannelButton GetChannelButton(MixerButton button)
{
return GetChannelButton(button, GetButtonGroup(button));
}
public static ChannelButton GetChannelButton(MixerButton button, ButtonGroups buttonGroup)
{
var longButton = (long)button;
if (longButton >= 0x10000000000)
{
return ChannelButton.ChannelMute;
}
int intButton = 0;
switch (buttonGroup)
{
case ButtonGroups.Channel1:
intButton = (int)(longButton >> 0);
break;
case ButtonGroups.Channel2:
intButton = (int)(longButton >> 8);
break;
case ButtonGroups.Channel3:
intButton = (int)(longButton >> 16);
break;
case ButtonGroups.Channel4:
intButton = (int)(longButton >> 24);
break;
case ButtonGroups.Channel5:
intButton = (int)(longButton >> 32);
break;
}
if (((int)ChannelButton.ChannelA1 & intButton) != 0) return ChannelButton.ChannelA1;
if (((int)ChannelButton.ChannelA2 & intButton) != 0) return ChannelButton.ChannelA2;
if (((int)ChannelButton.ChannelA3 & intButton) != 0) return ChannelButton.ChannelA3;
if (((int)ChannelButton.ChannelA4 & intButton) != 0) return ChannelButton.ChannelA4;
if (((int)ChannelButton.ChannelA5 & intButton) != 0) return ChannelButton.ChannelA5;
if (((int)ChannelButton.ChannelB1 & intButton) != 0) return ChannelButton.ChannelB1;
if (((int)ChannelButton.ChannelB2 & intButton) != 0) return ChannelButton.ChannelB2;
if (((int)ChannelButton.ChannelB3 & intButton) != 0) return ChannelButton.ChannelB3;
throw new ArgumentException("The provided button does not match any channel button in the specified button group.", nameof(button));
}
}