Teensy Updates + CAD Updates #7

Merged
veroxzik merged 25 commits from teensy into master 2019-12-23 21:57:12 +03:00
60 changed files with 12048 additions and 7691 deletions
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.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+275
View File
@@ -0,0 +1,275 @@
EESchema-LIBRARY Version 2.4
#encoding utf-8
#
# Connector_Generic:Conn_01x05
#
DEF Connector_Generic:Conn_01x05 J 0 40 Y N 1 F N
F0 "J" 0 300 50 H V C CNN
F1 "Connector_Generic:Conn_01x05" 0 -300 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
S -50 -195 0 -205 1 1 6 N
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 105 0 95 1 1 6 N
S -50 205 0 195 1 1 6 N
S -50 250 50 -250 1 1 10 f
X Pin_1 1 -200 200 150 R 50 50 1 1 P
X Pin_2 2 -200 100 150 R 50 50 1 1 P
X Pin_3 3 -200 0 150 R 50 50 1 1 P
X Pin_4 4 -200 -100 150 R 50 50 1 1 P
X Pin_5 5 -200 -200 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_Generic:Conn_01x08
#
DEF Connector_Generic:Conn_01x08 J 0 40 Y N 1 F N
F0 "J" 0 400 50 H V C CNN
F1 "Connector_Generic:Conn_01x08" 0 -500 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
S -50 -395 0 -405 1 1 6 N
S -50 -295 0 -305 1 1 6 N
S -50 -195 0 -205 1 1 6 N
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 105 0 95 1 1 6 N
S -50 205 0 195 1 1 6 N
S -50 305 0 295 1 1 6 N
S -50 350 50 -450 1 1 10 f
X Pin_1 1 -200 300 150 R 50 50 1 1 P
X Pin_2 2 -200 200 150 R 50 50 1 1 P
X Pin_3 3 -200 100 150 R 50 50 1 1 P
X Pin_4 4 -200 0 150 R 50 50 1 1 P
X Pin_5 5 -200 -100 150 R 50 50 1 1 P
X Pin_6 6 -200 -200 150 R 50 50 1 1 P
X Pin_7 7 -200 -300 150 R 50 50 1 1 P
X Pin_8 8 -200 -400 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_Generic:Conn_01x11
#
DEF Connector_Generic:Conn_01x11 J 0 40 Y N 1 F N
F0 "J" 0 600 50 H V C CNN
F1 "Connector_Generic:Conn_01x11" 0 -600 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
S -50 -495 0 -505 1 1 6 N
S -50 -395 0 -405 1 1 6 N
S -50 -295 0 -305 1 1 6 N
S -50 -195 0 -205 1 1 6 N
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 105 0 95 1 1 6 N
S -50 205 0 195 1 1 6 N
S -50 305 0 295 1 1 6 N
S -50 405 0 395 1 1 6 N
S -50 505 0 495 1 1 6 N
S -50 550 50 -550 1 1 10 f
X Pin_1 1 -200 500 150 R 50 50 1 1 P
X Pin_10 10 -200 -400 150 R 50 50 1 1 P
X Pin_11 11 -200 -500 150 R 50 50 1 1 P
X Pin_2 2 -200 400 150 R 50 50 1 1 P
X Pin_3 3 -200 300 150 R 50 50 1 1 P
X Pin_4 4 -200 200 150 R 50 50 1 1 P
X Pin_5 5 -200 100 150 R 50 50 1 1 P
X Pin_6 6 -200 0 150 R 50 50 1 1 P
X Pin_7 7 -200 -100 150 R 50 50 1 1 P
X Pin_8 8 -200 -200 150 R 50 50 1 1 P
X Pin_9 9 -200 -300 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_Generic:Conn_01x14
#
DEF Connector_Generic:Conn_01x14 J 0 40 Y N 1 F N
F0 "J" 0 700 50 H V C CNN
F1 "Connector_Generic:Conn_01x14" 0 -800 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
S -50 -695 0 -705 1 1 6 N
S -50 -595 0 -605 1 1 6 N
S -50 -495 0 -505 1 1 6 N
S -50 -395 0 -405 1 1 6 N
S -50 -295 0 -305 1 1 6 N
S -50 -195 0 -205 1 1 6 N
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 105 0 95 1 1 6 N
S -50 205 0 195 1 1 6 N
S -50 305 0 295 1 1 6 N
S -50 405 0 395 1 1 6 N
S -50 505 0 495 1 1 6 N
S -50 605 0 595 1 1 6 N
S -50 650 50 -750 1 1 10 f
X Pin_1 1 -200 600 150 R 50 50 1 1 P
X Pin_10 10 -200 -300 150 R 50 50 1 1 P
X Pin_11 11 -200 -400 150 R 50 50 1 1 P
X Pin_12 12 -200 -500 150 R 50 50 1 1 P
X Pin_13 13 -200 -600 150 R 50 50 1 1 P
X Pin_14 14 -200 -700 150 R 50 50 1 1 P
X Pin_2 2 -200 500 150 R 50 50 1 1 P
X Pin_3 3 -200 400 150 R 50 50 1 1 P
X Pin_4 4 -200 300 150 R 50 50 1 1 P
X Pin_5 5 -200 200 150 R 50 50 1 1 P
X Pin_6 6 -200 100 150 R 50 50 1 1 P
X Pin_7 7 -200 0 150 R 50 50 1 1 P
X Pin_8 8 -200 -100 150 R 50 50 1 1 P
X Pin_9 9 -200 -200 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_Generic:Conn_02x08_Odd_Even
#
DEF Connector_Generic:Conn_02x08_Odd_Even J 0 40 Y N 1 F N
F0 "J" 50 400 50 H V C CNN
F1 "Connector_Generic:Conn_02x08_Odd_Even" 50 -500 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_2x??_*
$ENDFPLIST
DRAW
S -50 -395 0 -405 1 1 6 N
S -50 -295 0 -305 1 1 6 N
S -50 -195 0 -205 1 1 6 N
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 105 0 95 1 1 6 N
S -50 205 0 195 1 1 6 N
S -50 305 0 295 1 1 6 N
S -50 350 150 -450 1 1 10 f
S 150 -395 100 -405 1 1 6 N
S 150 -295 100 -305 1 1 6 N
S 150 -195 100 -205 1 1 6 N
S 150 -95 100 -105 1 1 6 N
S 150 5 100 -5 1 1 6 N
S 150 105 100 95 1 1 6 N
S 150 205 100 195 1 1 6 N
S 150 305 100 295 1 1 6 N
X Pin_1 1 -200 300 150 R 50 50 1 1 P
X Pin_10 10 300 -100 150 L 50 50 1 1 P
X Pin_11 11 -200 -200 150 R 50 50 1 1 P
X Pin_12 12 300 -200 150 L 50 50 1 1 P
X Pin_13 13 -200 -300 150 R 50 50 1 1 P
X Pin_14 14 300 -300 150 L 50 50 1 1 P
X Pin_15 15 -200 -400 150 R 50 50 1 1 P
X Pin_16 16 300 -400 150 L 50 50 1 1 P
X Pin_2 2 300 300 150 L 50 50 1 1 P
X Pin_3 3 -200 200 150 R 50 50 1 1 P
X Pin_4 4 300 200 150 L 50 50 1 1 P
X Pin_5 5 -200 100 150 R 50 50 1 1 P
X Pin_6 6 300 100 150 L 50 50 1 1 P
X Pin_7 7 -200 0 150 R 50 50 1 1 P
X Pin_8 8 300 0 150 L 50 50 1 1 P
X Pin_9 9 -200 -100 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Device:R
#
DEF Device:R R 0 0 N Y 1 F N
F0 "R" 80 0 50 V V C CNN
F1 "Device:R" 0 0 50 V V C CNN
F2 "" -70 0 50 V I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
R_*
$ENDFPLIST
DRAW
S -40 -100 40 100 0 1 10 N
X ~ 1 0 150 50 D 50 50 1 1 P
X ~ 2 0 -150 50 U 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Jumper:SolderJumper_3_Open
#
DEF Jumper:SolderJumper_3_Open JP 0 0 Y N 1 F N
F0 "JP" -100 -100 50 H V C CNN
F1 "Jumper:SolderJumper_3_Open" 0 110 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
SolderJumper*Open*
$ENDFPLIST
DRAW
A -40 0 40 901 -901 0 1 0 N -40 40 -40 -40
A -40 0 40 901 -901 0 1 0 F -40 40 -40 -40
A 40 0 40 -899 899 0 1 0 N 40 -40 40 40
A 40 0 40 -899 899 0 1 0 F 40 -40 40 40
S -20 40 20 -40 0 1 0 F
P 2 0 1 0 -100 0 -80 0 N
P 2 0 1 0 -40 40 -40 -40 N
P 2 0 1 0 0 -50 0 -40 N
P 2 0 1 0 40 40 40 -40 N
P 2 0 1 0 100 0 80 0 N
X A 1 -200 0 100 R 50 50 1 1 P
X C 2 0 -150 100 U 50 50 1 1 I
X B 3 200 0 100 L 50 50 1 1 P
ENDDRAW
ENDDEF
#
# power:+3.3V
#
DEF power:+3.3V #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -150 50 H I C CNN
F1 "power:+3.3V" 0 140 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
ALIAS +3.3V
DRAW
P 2 0 1 0 -30 50 0 100 N
P 2 0 1 0 0 0 0 100 N
P 2 0 1 0 0 100 30 50 N
X +3V3 1 0 0 0 U 50 50 1 1 W N
ENDDRAW
ENDDEF
#
# power:+5V
#
DEF power:+5V #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -150 50 H I C CNN
F1 "power:+5V" 0 140 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
P 2 0 1 0 -30 50 0 100 N
P 2 0 1 0 0 0 0 100 N
P 2 0 1 0 0 100 30 50 N
X +5V 1 0 0 0 U 50 50 1 1 W N
ENDDRAW
ENDDEF
#
# power:GND
#
DEF power:GND #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -250 50 H I C CNN
F1 "power:GND" 0 -150 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N
X GND 1 0 0 0 D 50 50 1 1 W N
ENDDRAW
ENDDEF
#
#End Library
File diff suppressed because it is too large Load Diff
@@ -1,43 +1,43 @@
update=2/15/2019 9:12:44 AM
version=1
last_client=eeschema
[general]
version=1
RootSch=
BoardNm=
[pcbnew]
version=1
LastNetListRead=
UseCmpFile=1
PadDrill=0.600000000000
PadDrillOvalY=0.600000000000
PadSizeH=1.500000000000
PadSizeV=1.500000000000
PcbTextSizeV=1.500000000000
PcbTextSizeH=1.500000000000
PcbTextThickness=0.300000000000
ModuleTextSizeV=1.000000000000
ModuleTextSizeH=1.000000000000
ModuleTextSizeThickness=0.150000000000
SolderMaskClearance=0.000000000000
SolderMaskMinWidth=0.000000000000
DrawSegmentWidth=0.200000000000
BoardOutlineThickness=0.100000000000
ModuleOutlineThickness=0.150000000000
[cvpcb]
version=1
NetIExt=net
[eeschema]
version=1
LibDir=
[eeschema/libraries]
[schematic_editor]
version=1
PageLayoutDescrFile=
PlotDirectoryName=
SubpartIdSeparator=0
SubpartFirstId=65
NetFmtName=
SpiceAjustPassiveValues=0
LabSize=50
ERC_TestSimilarLabels=1
update=11/24/2019 9:19:44 PM
version=1
last_client=kicad
[general]
version=1
RootSch=
BoardNm=
[pcbnew]
version=1
LastNetListRead=
UseCmpFile=1
PadDrill=0.600000000000
PadDrillOvalY=0.600000000000
PadSizeH=1.500000000000
PadSizeV=1.500000000000
PcbTextSizeV=1.500000000000
PcbTextSizeH=1.500000000000
PcbTextThickness=0.300000000000
ModuleTextSizeV=1.000000000000
ModuleTextSizeH=1.000000000000
ModuleTextSizeThickness=0.150000000000
SolderMaskClearance=0.000000000000
SolderMaskMinWidth=0.000000000000
DrawSegmentWidth=0.200000000000
BoardOutlineThickness=0.100000000000
ModuleOutlineThickness=0.150000000000
[cvpcb]
version=1
NetIExt=net
[eeschema]
version=1
LibDir=
[eeschema/libraries]
[schematic_editor]
version=1
PageLayoutDescrFile=
PlotDirectoryName=
SubpartIdSeparator=0
SubpartFirstId=65
NetFmtName=
SpiceAjustPassiveValues=0
LabSize=50
ERC_TestSimilarLabels=1
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
-196
View File
@@ -1,196 +0,0 @@
EESchema-LIBRARY Version 2.4
#encoding utf-8
#
# Connector_Generic_Conn_01x04
#
DEF Connector_Generic_Conn_01x04 J 0 40 Y N 1 F N
F0 "J" 0 200 50 H V C CNN
F1 "Connector_Generic_Conn_01x04" 0 -300 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
S -50 -195 0 -205 1 1 6 N
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 105 0 95 1 1 6 N
S -50 150 50 -250 1 1 10 f
X Pin_1 1 -200 100 150 R 50 50 1 1 P
X Pin_2 2 -200 0 150 R 50 50 1 1 P
X Pin_3 3 -200 -100 150 R 50 50 1 1 P
X Pin_4 4 -200 -200 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_Generic_Conn_01x08
#
DEF Connector_Generic_Conn_01x08 J 0 40 Y N 1 F N
F0 "J" 0 400 50 H V C CNN
F1 "Connector_Generic_Conn_01x08" 0 -500 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
S -50 -395 0 -405 1 1 6 N
S -50 -295 0 -305 1 1 6 N
S -50 -195 0 -205 1 1 6 N
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 105 0 95 1 1 6 N
S -50 205 0 195 1 1 6 N
S -50 305 0 295 1 1 6 N
S -50 350 50 -450 1 1 10 f
X Pin_1 1 -200 300 150 R 50 50 1 1 P
X Pin_2 2 -200 200 150 R 50 50 1 1 P
X Pin_3 3 -200 100 150 R 50 50 1 1 P
X Pin_4 4 -200 0 150 R 50 50 1 1 P
X Pin_5 5 -200 -100 150 R 50 50 1 1 P
X Pin_6 6 -200 -200 150 R 50 50 1 1 P
X Pin_7 7 -200 -300 150 R 50 50 1 1 P
X Pin_8 8 -200 -400 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_Generic_Conn_01x11
#
DEF Connector_Generic_Conn_01x11 J 0 40 Y N 1 F N
F0 "J" 0 600 50 H V C CNN
F1 "Connector_Generic_Conn_01x11" 0 -600 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
S -50 -495 0 -505 1 1 6 N
S -50 -395 0 -405 1 1 6 N
S -50 -295 0 -305 1 1 6 N
S -50 -195 0 -205 1 1 6 N
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 105 0 95 1 1 6 N
S -50 205 0 195 1 1 6 N
S -50 305 0 295 1 1 6 N
S -50 405 0 395 1 1 6 N
S -50 505 0 495 1 1 6 N
S -50 550 50 -550 1 1 10 f
X Pin_1 1 -200 500 150 R 50 50 1 1 P
X Pin_10 10 -200 -400 150 R 50 50 1 1 P
X Pin_11 11 -200 -500 150 R 50 50 1 1 P
X Pin_2 2 -200 400 150 R 50 50 1 1 P
X Pin_3 3 -200 300 150 R 50 50 1 1 P
X Pin_4 4 -200 200 150 R 50 50 1 1 P
X Pin_5 5 -200 100 150 R 50 50 1 1 P
X Pin_6 6 -200 0 150 R 50 50 1 1 P
X Pin_7 7 -200 -100 150 R 50 50 1 1 P
X Pin_8 8 -200 -200 150 R 50 50 1 1 P
X Pin_9 9 -200 -300 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_Generic_Conn_01x12
#
DEF Connector_Generic_Conn_01x12 J 0 40 Y N 1 F N
F0 "J" 0 600 50 H V C CNN
F1 "Connector_Generic_Conn_01x12" 0 -700 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
S -50 -595 0 -605 1 1 6 N
S -50 -495 0 -505 1 1 6 N
S -50 -395 0 -405 1 1 6 N
S -50 -295 0 -305 1 1 6 N
S -50 -195 0 -205 1 1 6 N
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 105 0 95 1 1 6 N
S -50 205 0 195 1 1 6 N
S -50 305 0 295 1 1 6 N
S -50 405 0 395 1 1 6 N
S -50 505 0 495 1 1 6 N
S -50 550 50 -650 1 1 10 f
X Pin_1 1 -200 500 150 R 50 50 1 1 P
X Pin_10 10 -200 -400 150 R 50 50 1 1 P
X Pin_11 11 -200 -500 150 R 50 50 1 1 P
X Pin_12 12 -200 -600 150 R 50 50 1 1 P
X Pin_2 2 -200 400 150 R 50 50 1 1 P
X Pin_3 3 -200 300 150 R 50 50 1 1 P
X Pin_4 4 -200 200 150 R 50 50 1 1 P
X Pin_5 5 -200 100 150 R 50 50 1 1 P
X Pin_6 6 -200 0 150 R 50 50 1 1 P
X Pin_7 7 -200 -100 150 R 50 50 1 1 P
X Pin_8 8 -200 -200 150 R 50 50 1 1 P
X Pin_9 9 -200 -300 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_TestPoint
#
DEF Connector_TestPoint TP 0 30 N N 1 F N
F0 "TP" 0 270 50 H V C CNN
F1 "Connector_TestPoint" 0 200 50 H V C CNN
F2 "" 200 0 50 H I C CNN
F3 "" 200 0 50 H I C CNN
$FPLIST
Pin*
Test*
$ENDFPLIST
DRAW
C 0 130 30 0 1 0 N
X 1 1 0 0 100 U 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Device_R
#
DEF Device_R R 0 0 N Y 1 F N
F0 "R" 80 0 50 V V C CNN
F1 "Device_R" 0 0 50 V V C CNN
F2 "" -70 0 50 V I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
R_*
$ENDFPLIST
DRAW
S -40 -100 40 100 0 1 10 N
X ~ 1 0 150 50 D 50 50 1 1 P
X ~ 2 0 -150 50 U 50 50 1 1 P
ENDDRAW
ENDDEF
#
# power_+5V
#
DEF power_+5V #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -150 50 H I C CNN
F1 "power_+5V" 0 140 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
P 2 0 1 0 -30 50 0 100 N
P 2 0 1 0 0 0 0 100 N
P 2 0 1 0 0 100 30 50 N
X +5V 1 0 0 0 U 50 50 1 1 W N
ENDDRAW
ENDDEF
#
# power_GND
#
DEF power_GND #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -250 50 H I C CNN
F1 "power_GND" 0 -150 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N
X GND 1 0 0 0 D 50 50 1 1 W N
ENDDRAW
ENDDEF
#
#End Library
File diff suppressed because it is too large Load Diff
-1918
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

-4
View File
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
@@ -1,238 +1,274 @@
//
//
//
#include "AirSensor.h"
#ifndef IR_SENSOR_MULTIPLEXED
int ir_sensor_pins[6] = {AIR_SENSOR_0_PIN, AIR_SENSOR_1_PIN, AIR_SENSOR_2_PIN, AIR_SENSOR_3_PIN, AIR_SENSOR_4_PIN, AIR_SENSOR_5_PIN};
#endif
// Sets the output pins to switch the charlieplexed array of LEDs.
// 0 is the bottom-most LED and 5 is the top-most
void AirSensor::changeLight(int light)
{
switch (light)
{
case 0:
pinMode(LED_0, OUTPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, INPUT);
digitalWrite(LED_0, HIGH);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, LOW);
break;
case 1:
pinMode(LED_0, OUTPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, INPUT);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, HIGH);
digitalWrite(LED_2, LOW);
break;
case 2:
pinMode(LED_0, INPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, HIGH);
digitalWrite(LED_2, LOW);
break;
case 3:
pinMode(LED_0, INPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, HIGH);
break;
case 4:
pinMode(LED_0, OUTPUT);
pinMode(LED_1, INPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(LED_0, HIGH);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, LOW);
break;
case 5:
pinMode(LED_0, OUTPUT);
pinMode(LED_1, INPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, HIGH);
break;
default:
turnOffLight();
break;
}
}
// Sets all output pins to high-impedance to turn off all LEDs
void AirSensor::turnOffLight()
{
pinMode(LED_0, INPUT);
pinMode(LED_1, INPUT);
pinMode(LED_2, INPUT);
}
int AirSensor::getValue(int sensor, bool light)
{
// Turn on light corresponding to read sensor
if (light)
{
changeLight(sensor);
}
else
{
turnOffLight();
}
#ifdef IR_SENSOR_MULTIPLEXED
// Set multiplexer to corresponding sensor
digitalWrite(MUX_A, bitRead(sensor, 0));
digitalWrite(MUX_B, bitRead(sensor, 1));
digitalWrite(MUX_C, bitRead(sensor, 2));
// Return sensor value
#ifdef IR_SENSOR_ANALOG
return analogRead(SENSOR_IN);
#else
delay(1);
return digitalRead(SENSOR_IN);
#endif
#else
#ifdef IR_SENSOR_ANALOG
return analogRead(ir_sensor_pins[sensor]);
#else
delay(1);
return digitalRead(ir_sensor_pins[sensor]);
#endif
#endif
}
AirSensor::AirSensor(int requiredSamples, int skippedSamples) : thresholds{ 10000, 10000, 10000, 10000, 10000, 10000 }, calibrationSamples{ 0, 0, 0, 0, 0, 0 }, skippedSamples{ 0, 0, 0, 0, 0, 0 }, samplesToAcquire(requiredSamples), samplesToSkip(skippedSamples), calibrated{ 0, 0, 0, 0, 0, 0 }, allCalibrated(false)
{
// Load config values
EEPROM.get(12, deadzone);
EEPROM.get(16, alpha);
#ifndef IR_SENSOR_ANALOG
// No calibration required in digital mode
for (int i = 0; i < 6; i++)
calibrated[i] = true;
allCalibrated = true;
#endif
}
// Check if all IR sensors are calibrated. If they are, set a flag to not need to re-check it
bool AirSensor::isCalibrated()
{
if (!allCalibrated)
{
for (int i = 0; i < 6; i++)
{
if (!calibrated[i])
return false;
}
allCalibrated = true;
}
return allCalibrated;
}
bool AirSensor::getSensorState(int sensor)
{
// Flash the LED and read the IR sensor
int value = getValue(sensor, true);
turnOffLight();
#ifdef IR_SENSOR_ANALOG
// If the sensor is calibrated, Store its current filtered value.
// We are using an exponential moving average to filter out environmental noise. Setting alpha to 1 disables it.
if (allCalibrated || calibrated[sensor]) {
sensorValues[sensor] = (float)value * alpha + sensorValues[sensor] * (1 - alpha);
return sensorValues[sensor] < thresholds[sensor];
}
else
{
// If it is not calibrated, perform calibration:
// Skip the first few samples. This might not be required, but improved performance in my case.
// This might be due to wiring mistakes I made - I'm leaving the code in either way as it can't hurt.
if (skippedSamples[sensor] > samplesToSkip)
{
// Keep the minimum value seen by the sensor
if (value < thresholds[sensor]) thresholds[sensor] = value;
// If we have enough samples:
if (++calibrationSamples[sensor] > samplesToAcquire)
{
// Consider the sensor calibrated. Finalize calibration for this sensor.
sensorValues[sensor] = value;
calibrated[sensor] = true;
thresholds[sensor] -= deadzone;
};
}
else
{
skippedSamples[sensor]++;
}
return false;
}
#else
return value == LOW ? true : false;
#endif
}
// Using data from air sensors, compute the height of the player's hand, from 0 (not present) to 1 (highest possible position).
float AirSensor::getHandPosition()
{
int highestTriggered = -1;
for (int i = 0; i < 6; i++)
{
if (getSensorState(i))
{
if ((i + 1) > highestTriggered)
highestTriggered = i + 1;
}
}
return highestTriggered == -1 ? 0 : ((float)highestTriggered / 6.0f);
}
void AirSensor::setDeadzone(int deadzone)
{
this->deadzone = deadzone;
EEPROM.put(12, deadzone);
}
void AirSensor::setAlpha(float alpha)
{
this->alpha = alpha;
EEPROM.put(16, alpha);
}
int AirSensor::getDeadzone()
{
return deadzone;
}
float AirSensor::getAlpha()
{
return alpha;
}
void AirSensor::recalibrate()
{
for (int i = 0; i < 6; i++)
{
thresholds[i] = 0;
calibrationSamples[i] = 0;
skippedSamples[i] = 0;
sensorValues[i] = 0;
calibrated[i] = false;
}
allCalibrated = false;
}
//
//
//
#include "AirSensor.h"
#ifndef IR_SENSOR_MULTIPLEXED
int ir_sensor_pins[6] = {AIR_SENSOR_0_PIN, AIR_SENSOR_1_PIN, AIR_SENSOR_2_PIN, AIR_SENSOR_3_PIN, AIR_SENSOR_4_PIN, AIR_SENSOR_5_PIN};
#endif
// Sets the output pins to switch the charlieplexed array of LEDs.
// 0 is the bottom-most LED and 5 is the top-most
void AirSensor::changeLight(int light)
{
switch (light)
{
case 0:
pinMode(LED_0, OUTPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, INPUT);
digitalWrite(LED_0, HIGH);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, LOW);
break;
case 1:
pinMode(LED_0, OUTPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, INPUT);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, HIGH);
digitalWrite(LED_2, LOW);
break;
case 2:
pinMode(LED_0, INPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, HIGH);
digitalWrite(LED_2, LOW);
break;
case 3:
pinMode(LED_0, INPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, HIGH);
break;
case 4:
pinMode(LED_0, OUTPUT);
pinMode(LED_1, INPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(LED_0, HIGH);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, LOW);
break;
case 5:
pinMode(LED_0, OUTPUT);
pinMode(LED_1, INPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, HIGH);
break;
default:
turnOffLight();
break;
}
}
// Sets all output pins to high-impedance to turn off all LEDs
void AirSensor::turnOffLight()
{
pinMode(LED_0, INPUT);
pinMode(LED_1, INPUT);
pinMode(LED_2, INPUT);
}
int AirSensor::getValue(int sensor, bool light)
{
// Turn on light corresponding to read sensor
if (light)
{
changeLight(sensor);
}
else
{
turnOffLight();
}
// Delay required because the read may occur faster than the physical light turning on
delayMicroseconds(150);
#ifdef IR_SENSOR_MULTIPLEXED
// Set multiplexer to corresponding sensor
digitalWrite(MUX_A, bitRead(sensor, 0));
digitalWrite(MUX_B, bitRead(sensor, 1));
digitalWrite(MUX_C, bitRead(sensor, 2));
// Return sensor value
if (digitalMode)
return digitalRead(SENSOR_IN);
else
return analogRead(SENSOR_IN);
#else
if (digitalMode)
return digitalRead(ir_sensor_pins[sensor]);
else
return analogRead(ir_sensor_pins[sensor]);
#endif
}
AirSensor::AirSensor(int requiredSamples, int skippedSamples) : thresholds{ 10000, 10000, 10000, 10000, 10000, 10000 }, calibrationSamples{ 0, 0, 0, 0, 0, 0 }, skippedSamples{ 0, 0, 0, 0, 0, 0 }, samplesToAcquire(requiredSamples), samplesToSkip(skippedSamples), calibrated{ 0, 0, 0, 0, 0, 0 }, allCalibrated(false)
{
// Load config values
EEPROM.get(12, deadzone);
EEPROM.get(16, alpha);
#ifdef IR_SENSOR_ANALOG
digitalMode = false;
#else
digitalMode = true;
#endif
if (digitalMode)
{
// Digital mode runs calibration in the constructor
for (int i = 0; i < 6; i++)
{
#ifndef IR_SENSOR_MULTIPLEXED
pinMode(ir_sensor_pins[i], INPUT);
#endif
calibrated[i] = getValue(i, true);
}
}
}
// Check if all IR sensors are calibrated. If they are, set a flag to not need to re-check it
bool AirSensor::isCalibrated()
{
#ifdef IGNORE_AIR_CALIBRATION
return true;
#else
if (!allCalibrated)
{
for (int i = 0; i < 6; i++)
{
if (!calibrated[i])
return false;
}
allCalibrated = true;
}
return allCalibrated;
#endif
}
bool AirSensor::getSensorState(int sensor)
{
// Flash the LED and read the IR sensor
int value = getValue(sensor, true);
turnOffLight();
if (digitalMode)
return value == LOW ? true : false;
else
{
// If the sensor is calibrated, Store its current filtered value.
// We are using an exponential moving average to filter out environmental noise. Setting alpha to 1 disables it.
if (allCalibrated || calibrated[sensor]) {
sensorValues[sensor] = (float)value * alpha + sensorValues[sensor] * (1 - alpha);
return sensorValues[sensor] < thresholds[sensor];
}
else
{
// If it is not calibrated, perform calibration:
// Skip the first few samples. This might not be required, but improved performance in my case.
// This might be due to wiring mistakes I made - I'm leaving the code in either way as it can't hurt.
if (skippedSamples[sensor] > samplesToSkip)
{
// Keep the minimum value seen by the sensor
if (value < thresholds[sensor]) thresholds[sensor] = value;
// If we have enough samples:
if (++calibrationSamples[sensor] > samplesToAcquire)
{
// Consider the sensor calibrated. Finalize calibration for this sensor.
sensorValues[sensor] = value;
calibrated[sensor] = true;
thresholds[sensor] -= deadzone;
};
}
else
{
skippedSamples[sensor]++;
}
return false;
}
}
}
bool AirSensor::isDigital()
{
return digitalMode;
}
// Using data from air sensors, compute the height of the player's hand, from 0 (not present) to 1 (highest possible position).
float AirSensor::getHandPosition()
{
int highestTriggered = -1;
for (int i = 0; i < 6; i++)
{
if (getSensorState(i))
{
if ((i + 1) > highestTriggered)
highestTriggered = i + 1;
}
}
return highestTriggered == -1 ? 0 : ((float)highestTriggered / 6.0f);
}
uint8_t AirSensor::getSensorReadings()
{
uint8_t reading = 0;
for (int i = 0; i < 6; i++)
{
reading |= ((int)getSensorState(i) << i);
}
return reading;
}
bool AirSensor::getSensorCalibrated(int i)
{
return calibrated[i];
}
void AirSensor::setDeadzone(int deadzone)
{
this->deadzone = deadzone;
EEPROM.put(12, deadzone);
}
void AirSensor::setAlpha(float alpha)
{
this->alpha = alpha;
EEPROM.put(16, alpha);
}
int AirSensor::getDeadzone()
{
return deadzone;
}
float AirSensor::getAlpha()
{
return alpha;
}
void AirSensor::recalibrate()
{
for (int i = 0; i < 6; i++)
{
thresholds[i] = 0;
calibrationSamples[i] = 0;
skippedSamples[i] = 0;
sensorValues[i] = 0;
calibrated[i] = false;
}
allCalibrated = false;
}
@@ -1,50 +1,52 @@
// AirSensor.h
#ifndef _AIRSENSOR_h
#define _AIRSENSOR_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#include "PinConfig.h"
#include <EEPROM.h>
class AirSensor
{
private:
void changeLight(int light);
void turnOffLight();
int thresholds[6];
int calibrationSamples[6];
int skippedSamples[6];
float sensorValues[6];
int samplesToAcquire;
int samplesToSkip;
bool calibrated[6];
bool allCalibrated;
uint16_t deadzone;
float alpha;
public:
AirSensor(int requiredSamples, int skippedSamples);
bool isCalibrated();
bool getSensorState(int sensor);
int getValue(int sensor, bool light);
float getHandPosition();
void setDeadzone(int deadzone);
void setAlpha(float alpha);
int getDeadzone();
float getAlpha();
void recalibrate();
};
#endif
// AirSensor.h
#ifndef _AIRSENSOR_h
#define _AIRSENSOR_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#include "PinConfig.h"
#include <EEPROM.h>
class AirSensor
{
private:
void changeLight(int light);
void turnOffLight();
int thresholds[6];
int calibrationSamples[6];
int skippedSamples[6];
float sensorValues[6];
int samplesToAcquire;
int samplesToSkip;
bool calibrated[6];
bool allCalibrated;
bool digitalMode;
uint16_t deadzone;
float alpha;
public:
AirSensor(int requiredSamples, int skippedSamples);
bool isCalibrated();
bool isDigital();
bool getSensorState(int sensor);
int getValue(int sensor, bool light);
float getHandPosition();
uint8_t getSensorReadings();
bool getSensorCalibrated(int i);
void setDeadzone(int deadzone);
void setAlpha(float alpha);
int getDeadzone();
float getAlpha();
void recalibrate();
};
#endif
+60
View File
@@ -0,0 +1,60 @@
// This file is for setting how the board will operate
// The top section is user-editable, the bottom section is not
#ifndef _CONFIG_h
#define _CONFIG_h
// *** USER EDITABLE CONFIG OPTIONS ***
// Uncomment this line to force the processor to use Serial Output
//#define FORCE_SERIAL
// Uncomment this line if your IR sensors are multiplexed (Confirm pinout on PinConfig.h)
//#define IR_SENSOR_MULTIPLEXED
// Uncomment this line if your IR sensors will be used in analog mode (Confirm pinout on PinConfig.h)
//#define IR_SENSOR_ANALOG
// Comment this line for default Seaurchin air sensor bindings
// Uncomment this line if your IR sensors will each be mapped to separate keyboard key
//#define IR_SENSOR_KEY
// Comment this line to use reactive LEDs (i.e. they will react to touch input)
// Uncomment this line to receive LED instructions via serial
//#define LED_SERIAL
// Uncomment this line if your LED lights are mirrored
//#define LED_REVERSE
// *** FOR CALIBRATING AND DEBUGGING
// Uncomment this line to output the touch values to the Serial port (for use with Arduino's Serial Plotter)
//#define SERIAL_PLOT
// Uncomment this line if you want RAW touch values (vs. normalized)
//#define SERIAL_RAW_VALUE
// Define PLOT_PIN as -1 to print all key's values, otherwise define as 0-15 for an individual key
#define PLOT_PIN -1
// Uncomment this if you wish to ignore a falsly calibrated air sensor
//#define IGNORE_AIR_CALIBRATION
// *** DO NOT CHANGE BELOW THIS LINE ***
// Determine if we're compiling on Teensy
#if defined(__MKL26Z64__) // Teensy LC
#define TEENSY
#define bitRead(value, bit) (((value) >> (bit)) & 0x01) // For some reason, bitRead isn't defined in the Teensy core (might be in Wiring.h?)
#ifndef FORCE_SERIAL
#define USB
#endif
#endif
// Comment out these lines to force Serial output
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32u4__)
#ifndef FORCE_SERIAL
#define USB
#endif
#endif
#endif // _CONFIG_h
@@ -6,6 +6,13 @@
#include "SerialOutput.h"
#endif
#ifdef LED_SERIAL
#include "SerialLeds.h"
bool updateLeds = false;
byte serialBuffer[200];
SerialLeds serialLeds;
#endif
#include "AirSensor.h"
#include "Touchboard.h"
#include <FastLED.h>
@@ -30,7 +37,9 @@ char command[32];
void onKeyPress(int key, bool wasHeld)
{
lightIntensity[key] = 1.0f;
#if !defined(SERIAL_PLOT) && defined(USB)
output->sendKeyEvent(key, true, wasHeld);
#endif
keyStates[key] = true;
}
@@ -40,6 +49,7 @@ void parseCommand()
{
char input1 = Serial.read();
char input2;
int i;
switch (input1)
{
case 't': // touchboard
@@ -58,6 +68,37 @@ void parseCommand()
break;
case 'c': // calibrate
touchboard->calibrateKeys();
break;
case 'n': // print neutral values
Serial.println("Neutral Values");
for (i = 0; i < 16; i++)
{
Serial.print("Key: ");
Serial.print(i);
Serial.print("\t");
Serial.println(touchboard->getNeutralValue(i));
}
break;
case 'e': // print moving average values
Serial.println("Moving Average Values");
for (i = 0; i < 16; i++)
{
Serial.print("Key: ");
Serial.print(i);
Serial.print("\t");
Serial.println(touchboard->getEmAverages(i));
}
break;
case 'r': // print raw values
Serial.println("Raw Values");
for (i = 0; i < 16; i++)
{
Serial.print("Key: ");
Serial.print(i);
Serial.print("\t");
Serial.println(touchboard->getRawValue(i));
}
break;
}
break;
case 'i': // ir sensors
@@ -158,26 +199,52 @@ void setup() {
Serial.begin(115200);
FastLED.addLeds<LED_TYPE, RGBPIN, LED_ORDER>(leds, 16);
// Set LEDs blue
// Flash LEDs orange 3 times
for (int i = 0; i < 3; i++)
{
for (CRGB& led : leds)
led = 0xFF5F00;
FastLED.show();
delay(1000);
for (CRGB& led : leds)
led = 0x000000;
FastLED.show();
delay(1000);
}
// Set LEDS to red prior to intialize
for (CRGB& led : leds)
{
led = 0x0000FF;
led = CRGB::Red;
FastLED.show();
}
// Initialize and calibrate touch sensors
touchboard = new Touchboard(onKeyPress);
// Set LEDs red
for (CRGB& led : leds)
{
led = 0xFF0000;
FastLED.show();
}
// Initialize air sensor - will automatically calibrate as it starts being read
// Initialize air sensor
// Digital mode calibrations in the constructor
// Analog mode will automatically calibrate as it starts being read
sensor = new AirSensor(500, 50);
// Display the number of air sensors that were calibrated
for (CRGB& led : leds)
led = 0x000000;
for (int i = 0; i < 6; i++)
{
if (sensor->getSensorCalibrated(i))
leds[i] = CRGB::Green;
else
leds[i] = CRGB::Red;
}
FastLED.show();
delay(3000);
// Set LEDs blue for "ready, waiting for air sensor calibration"
for (CRGB& led : leds)
led = 0x0000FF;
FastLED.show();
// Initialize relevant output method / USB or serial
#ifdef USB
output = new USBOutput();
@@ -188,47 +255,126 @@ void setup() {
void loop() {
// Process config commands
#ifndef LED_SERIAL
// Config commands can only be sent when the LEDs aren't being updated via serial
if (Serial.available())
{
parseCommand();
}
#else
// Wait until have at least one message
// For the sake of processing time we'll be discarding every other message
if (Serial.available() > 200)
{
Serial.readBytes(serialBuffer, 200);
updateLeds = serialLeds.processBulk(serialBuffer, 200);
}
else
updateLeds = false;
#endif
// If currently paused through a config command, do not execute main loop
if (!activated) return;
// Scan touch keyboard and update lights
touchboard->scan();
int index = 0;
for (int i = 0; i < 16; i++)
{
if (lightIntensity[i] > 0.05f)
lightIntensity[i] -= 0.05f;
#ifndef LED_REVERSE
index = i;
#else
index = 15 - i;
#endif
if (lightIntensity[index] > 0.05f)
lightIntensity[index] -= 0.05f;
// If the key is currently being held, set its color to purple
if (touchboard->update(i))
{
leds[i].setRGB(min(led_on.r / 2 + led_on.r / 2 * lightIntensity[i], 255), min(led_on.g / 2 + led_on.g / 2 * lightIntensity[i], 255), min(led_on.b / 2 + led_on.b / 2 * lightIntensity[i], 255));
#ifndef LED_SERIAL
leds[index].setRGB(min(led_on.r / 2 + led_on.r / 2 * lightIntensity[index], 255), min(led_on.g / 2 + led_on.g / 2 * lightIntensity[index], 255), min(led_on.b / 2 + led_on.b / 2 * lightIntensity[index], 255));
#endif
}
else
{
#ifndef LED_SERIAL
// If not, make it yellow and send the "key released" event if it was previously pressed
leds[i].setRGB(led_off.r / 2, led_off.g / 2, led_off.b / 2);
leds[index].setRGB(led_off.r / 2, led_off.g / 2, led_off.b / 2);
#endif
if (keyStates[i])
{
#if !defined(SERIAL_PLOT) && defined(USB)
output->sendKeyEvent(i, false, false);
#endif
keyStates[i] = false;
}
}
#ifdef LED_SERIAL
if (updateLeds)
{
RGBLed temp = serialLeds.getKey(i);
leds[index].setRGB(temp.r, temp.g, temp.b);
}
#endif
}
#ifdef SERIAL_PLOT
if (PLOT_PIN == -1)
{
for (int i = 0; i < 16; i++)
{
#ifdef SERIAL_RAW_VALUES
// Print values
Serial.print(touchboard->getRawValue(i));
#else
// Print normalized values
Serial.print(touchboard->getRawValue(i) - touchboard->getNeutralValue(i));
#endif
Serial.print("\t");
}
Serial.print(touchboard->getDeadzone());
Serial.println();
}
else
{
Serial.print(touchboard->getRawValue(PLOT_PIN));
Serial.print("\t");
Serial.print(touchboard->getEmAverages(PLOT_PIN));
Serial.print("\t");
Serial.print(touchboard->getEmAverages(PLOT_PIN) + touchboard->getThreshold());
Serial.print("\t");
Serial.print(touchboard->getNeutralValue(PLOT_PIN));
Serial.print("\t");
Serial.print(touchboard->getNeutralValue(PLOT_PIN) + touchboard->getDeadzone());
}
#endif
// Process air sensor hand position
const float newPosition = sensor->getHandPosition();
if (newPosition != sensorPosition)
{
#if !defined(SERIAL_PLOT) && defined(USB)
#ifdef IR_SENSOR_KEY
output->sendSensor(sensor->getSensorReadings());
#else
output->sendSensorEvent(newPosition);
#endif
#endif
sensorPosition = newPosition;
}
// Send update
#if !defined(SERIAL_PLOT) && defined(USB)
output->sendUpdate();
#endif
//#if defined(SERIAL_PLOT)
// Serial.print("\t");
// Serial.println(sensor->getSensorReadings());
//#endif
// If the air sensor is calibrated, update lights. The lights will stay red as long as the air sensor is not calibrated.
if (sensor->isCalibrated())
FastLED.show();
@@ -1,25 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2003
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpeNITHM", "OpeNITHM.vcxproj", "{C5F80730-F44F-4478-BDAE-6634EFC2CA88}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.ActiveCfg = Debug|Win32
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.Build.0 = Debug|Win32
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.ActiveCfg = Release|Win32
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {29CA5AFB-7A66-4485-A35E-907383CF8979}
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2003
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpeNITHM", "OpeNITHM.vcxproj", "{C5F80730-F44F-4478-BDAE-6634EFC2CA88}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.ActiveCfg = Debug|Win32
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.Build.0 = Debug|Win32
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.ActiveCfg = Release|Win32
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {29CA5AFB-7A66-4485-A35E-907383CF8979}
EndGlobalSection
EndGlobal
@@ -1,146 +1,149 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C5F80730-F44F-4478-BDAE-6634EFC2CA88}</ProjectGuid>
<RootNamespace>
</RootNamespace>
<ProjectName>OpeNITHM</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>
</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>
</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>
</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>
</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\OpeNITHM;$(ProjectDir)..\..\..\Arduino\libraries\HID-2.5.0\src;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\HID\src;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src;$(ProjectDir)..\..\..\Arduino\libraries\FastLED-master;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\libraries;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries;$(ProjectDir)..\..\..\..\AppData\Local\arduino15\packages\SparkFun\hardware\avr\1.1.6\libraries;$(ProjectDir)..\..\..\Arduino\libraries;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino;$(ProjectDir)..\..\..\..\AppData\Local\arduino15\packages\SparkFun\hardware\avr\1.1.6\variants\promicro;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\avr\include;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\avr\include\avr;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\lib\gcc\avr\4.8.1\include;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\lib\gcc\avr\4.9.2\include;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\lib\gcc\avr\4.9.3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<ForcedIncludeFiles>$(ProjectDir)__vm\.OpeNITHM.vsarduino.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>__AVR_ATmega32u4__;__AVR_ATmega32U4__;F_CPU=16000000L;ARDUINO=10802;ARDUINO_AVR_PROMICRO;ARDUINO_ARCH_AVR;USB_VID=0x1b4f;USB_PID=0x9206;__cplusplus=201103L;_VMICRO_INTELLISENSE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<ForcedIncludeFiles>%(ForcedIncludeFiles)</ForcedIncludeFiles>
<IgnoreStandardIncludePath>true</IgnoreStandardIncludePath>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectCapability Include="VisualMicro" />
</ItemGroup>
<ItemGroup>
<None Include="OpeNITHM.ino">
<FileType>CppCode</FileType>
</None>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AirSensor.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="CapacitiveSensor.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="Output.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="PinConfig.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="SerialOutput.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="Touchboard.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="USBOutput.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="__vm\.OpeNITHM.vsarduino.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="AirSensor.cpp" />
<ClCompile Include="CapacitiveSensor.cpp" />
<ClCompile Include="SerialOutput.cpp" />
<ClCompile Include="Touchboard.cpp" />
<ClCompile Include="USBOutput.cpp" />
</ItemGroup>
<PropertyGroup>
<DebuggerFlavor>VisualMicroDebugger</DebuggerFlavor>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C5F80730-F44F-4478-BDAE-6634EFC2CA88}</ProjectGuid>
<RootNamespace>
</RootNamespace>
<ProjectName>OpeNITHM</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>
</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>
</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>
</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>
</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\OpeNITHM;$(ProjectDir)..\..\..\Arduino\libraries\HID-2.5.0\src;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\HID\src;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src;$(ProjectDir)..\..\..\Arduino\libraries\FastLED-master;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\libraries;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries;$(ProjectDir)..\..\..\..\AppData\Local\arduino15\packages\SparkFun\hardware\avr\1.1.6\libraries;$(ProjectDir)..\..\..\Arduino\libraries;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino;$(ProjectDir)..\..\..\..\AppData\Local\arduino15\packages\SparkFun\hardware\avr\1.1.6\variants\promicro;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\avr\include;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\avr\include\avr;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\lib\gcc\avr\4.8.1\include;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\lib\gcc\avr\4.9.2\include;$(ProjectDir)..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\lib\gcc\avr\4.9.3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<ForcedIncludeFiles>$(ProjectDir)__vm\.OpeNITHM.vsarduino.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>__AVR_ATmega32u4__;__AVR_ATmega32U4__;F_CPU=16000000L;ARDUINO=10802;ARDUINO_AVR_PROMICRO;ARDUINO_ARCH_AVR;USB_VID=0x1b4f;USB_PID=0x9206;__cplusplus=201103L;_VMICRO_INTELLISENSE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<ForcedIncludeFiles>%(ForcedIncludeFiles)</ForcedIncludeFiles>
<IgnoreStandardIncludePath>true</IgnoreStandardIncludePath>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectCapability Include="VisualMicro" />
</ItemGroup>
<ItemGroup>
<None Include="OpeNITHM.ino">
<FileType>CppCode</FileType>
</None>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AirSensor.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="CapacitiveSensor.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="Config.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="Output.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="PinConfig.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="SerialOutput.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="Touchboard.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="USBOutput.h">
<FileType>CppCode</FileType>
</ClInclude>
<ClInclude Include="__vm\.OpeNITHM.vsarduino.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="AirSensor.cpp" />
<ClCompile Include="CapacitiveSensor.cpp" />
<ClCompile Include="SerialOutput.cpp" />
<ClCompile Include="Touchboard.cpp" />
<ClCompile Include="USBOutput.cpp" />
</ItemGroup>
<PropertyGroup>
<DebuggerFlavor>VisualMicroDebugger</DebuggerFlavor>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -1,63 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="OpeNITHM.ino" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="__vm\.OpeNITHM.vsarduino.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AirSensor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CapacitiveSensor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Output.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PinConfig.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="SerialOutput.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Touchboard.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="USBOutput.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="AirSensor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CapacitiveSensor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SerialOutput.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Touchboard.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="USBOutput.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="OpeNITHM.ino" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="__vm\.OpeNITHM.vsarduino.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AirSensor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CapacitiveSensor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Output.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PinConfig.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="SerialOutput.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Touchboard.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="USBOutput.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="AirSensor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CapacitiveSensor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SerialOutput.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Touchboard.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="USBOutput.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
@@ -1,13 +1,15 @@
// Output.h
#ifndef _OUTPUT_h
#define _OUTPUT_h
class Output
{
public:
virtual void sendKeyEvent(int key, bool pressed, bool doublePressed);
virtual void sendSensorEvent(float position);
};
#endif
// Output.h
#ifndef _OUTPUT_h
#define _OUTPUT_h
class Output
{
public:
virtual void sendKeyEvent(int key, bool pressed, bool doublePressed);
virtual void sendSensorEvent(float position);
virtual void sendSensor(int sensor);
virtual void sendUpdate();
};
#endif
+69
View File
@@ -0,0 +1,69 @@
#include "Config.h"
#ifndef _PINCONFIG_h
#define _PINCONFIG_h
#define CALIBRATION_SAMPLES 500
// Multiplexer pin settings
#ifdef TEENSY // Teensy LC
#define MUX_0 20
#define MUX_1 19
#define MUX_2 18
#else // Pro Micro
#define MUX_0 20
#define MUX_1 19
#define MUX_2 18
#endif
// Sensor pin settings
#ifdef TEENSY
#define LED_0 16
#define LED_1 21
#define LED_2 5
#else
#define LED_0 0
#define LED_1 2
#define LED_2 3
#endif
#ifdef IR_SENSOR_MULTIPLEXED
#define SENSOR_IN A0
#else
#ifdef TEENSY
#define AIR_SENSOR_0_PIN 10
#define AIR_SENSOR_1_PIN 11
#define AIR_SENSOR_2_PIN 12
#define AIR_SENSOR_3_PIN 6
#define AIR_SENSOR_4_PIN 8
#define AIR_SENSOR_5_PIN 9
#else
#define AIR_SENSOR_0_PIN 4
#define AIR_SENSOR_1_PIN 5
#define AIR_SENSOR_2_PIN 6
#define AIR_SENSOR_3_PIN 7
#define AIR_SENSOR_4_PIN 8
#define AIR_SENSOR_5_PIN 9
#endif
#endif
// Capsense pin settings
#define RECEIVE_1 21
#define RECEIVE_2 1
#define SEND 10
#ifdef TEENSY // Teensy LC
#define TOUCH_0 22
#define TOUCH_1 23
#endif
// Lighting pin settings
#define LED_TYPE WS2812B
#define LED_ORDER GRB
#ifdef TEENSY // Teensy LC
#define RGBPIN 4
#else
#define RGBPIN 16 // Pro Micro
#endif
#endif // _PINCONFIG_h
+96
View File
@@ -0,0 +1,96 @@
#include "SerialLeds.h"
SerialLeds::SerialLeds()
{ }
bool SerialLeds::process(byte in)
{
bool readyToProcess = false;
switch (currentState)
{
case headerSearch:
// Search for header
if (in == 0xAA)
{
dataBuffer[0] = in;
currentState = headerConfirm;
}
break;
case headerConfirm:
// Confirm header
if (in == 0xAA)
{
dataBuffer[1] = in;
currentState = dataRead;
currentReadNum = 2;
}
else
{
currentState = headerSearch;
}
break;
case dataRead:
{
dataBuffer[currentReadNum] = in;
currentReadNum++;
if (currentReadNum == 100)
{
if (memcmp(dataBuffer, lastBuffer, 100) != 0)
readyToProcess = true;
memcpy(lastBuffer, dataBuffer, 100);
currentState = headerSearch;
}
}
break;
}
return readyToProcess;
}
bool SerialLeds::processBulk(uint8_t *buf, size_t length)
{
bool readyToProcess = false;
currentState = headerSearch;
for (int i = 0; i < length - 100; i++)
{
switch (currentState)
{
case headerSearch:
if (buf[i] == 0xAA)
{
currentState = headerConfirm;
dataBuffer[0] = buf[i];
}
break;
case headerConfirm:
if (buf[i] == 0xAA)
{
currentState = dataRead;
dataBuffer[1] = buf[i];
}
else
{
currentState = headerSearch;
}
break;
case dataRead:
memcpy(dataBuffer + 2, buf + i, 98);
if (memcmp(dataBuffer, lastBuffer, 100) != 0)
{
memcpy(ledData.raw, dataBuffer + 2, 96);
readyToProcess = true;
}
memcpy(lastBuffer, dataBuffer, 100);
currentState = headerSearch;
return readyToProcess;
}
}
return readyToProcess;
}
// Left to Right
RGBLed SerialLeds::getKey(uint8_t key)
{
return ledData.rgb[30 - (key * 2)];
}
+43
View File
@@ -0,0 +1,43 @@
#ifndef __SERIALLEDS_h
#define __SERIALLEDS_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
typedef struct {
uint8_t b;
uint8_t r;
uint8_t g;
} RGBLed;
class SerialLeds
{
private:
enum state
{
headerSearch,
headerConfirm,
dataRead
};
uint8_t dataBuffer[100];
uint8_t lastBuffer[100];
state currentState = headerSearch;
uint8_t currentReadNum = 0;
public:
SerialLeds();
bool process(uint8_t in);
bool processBulk(uint8_t *buf, size_t length);
RGBLed getKey(uint8_t key); // Left to Right
union {
RGBLed rgb[32];
uint8_t raw[96];
} ledData;
};
#endif
@@ -1,29 +1,39 @@
//
//
//
#include "SerialOutput.h"
// Workaround for microcontrollers without USB functionality
// use a serial line to talk to a UC with USB, which will then act as a USB peripheral
// Only needed because I didn't receive my Atmega328p until late in the project
void SerialOutput::sendKeyEvent(int key, bool pressed, bool doublePressed)
{
builtPacket.data = 0;
builtPacket.keyEvent.isKeyboard = true;
builtPacket.keyEvent.isPressed = pressed;
builtPacket.keyEvent.isDoublePressed = doublePressed;
builtPacket.keyEvent.key = key;
Serial.write(builtPacket.data);
}
void SerialOutput::sendSensorEvent(float position)
{
builtPacket.data = 0;
builtPacket.sensorEvent.isKeyboard = false;
builtPacket.sensorEvent.position = position * 127;
Serial.write(builtPacket.data);
}
//
//
//
#include "SerialOutput.h"
// Workaround for microcontrollers without USB functionality
// use a serial line to talk to a UC with USB, which will then act as a USB peripheral
// Only needed because I didn't receive my Atmega328p until late in the project
void SerialOutput::sendKeyEvent(int key, bool pressed, bool doublePressed)
{
builtPacket.data = 0;
builtPacket.keyEvent.isKeyboard = true;
builtPacket.keyEvent.isPressed = pressed;
builtPacket.keyEvent.isDoublePressed = doublePressed;
builtPacket.keyEvent.key = key;
Serial.write(builtPacket.data);
}
void SerialOutput::sendSensorEvent(float position)
{
builtPacket.data = 0;
builtPacket.sensorEvent.isKeyboard = false;
builtPacket.sensorEvent.position = position * 127;
Serial.write(builtPacket.data);
}
// Implement at a later date
void SerialOutput::sendSensor(int sensor)
{
}
// Implement at a later date
void SerialOutput::sendUpdate()
{
}
@@ -1,41 +1,43 @@
// SerialOutput.h
#ifndef _SERIALOUTPUT_h
#define _SERIALOUTPUT_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#include "Output.h"
//All events can fit within one byte to save time sending over serial
union Packet
{
uint8_t data;
struct
{
bool isKeyboard : 1;
bool isPressed : 1;
bool isDoublePressed : 1;
unsigned int key : 5;
} keyEvent;
struct
{
bool isKeyboard : 1;
int position : 7;
} sensorEvent;
};
class SerialOutput : public Output
{
private:
Packet builtPacket = Packet();
public:
void sendKeyEvent(int key, bool pressed, bool doublePressed) override;
void sendSensorEvent(float position) override;
};
#endif
// SerialOutput.h
#ifndef _SERIALOUTPUT_h
#define _SERIALOUTPUT_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#include "Output.h"
//All events can fit within one byte to save time sending over serial
union Packet
{
uint8_t data;
struct
{
bool isKeyboard : 1;
bool isPressed : 1;
bool isDoublePressed : 1;
unsigned int key : 5;
} keyEvent;
struct
{
bool isKeyboard : 1;
int position : 7;
} sensorEvent;
};
class SerialOutput : public Output
{
private:
Packet builtPacket = Packet();
public:
void sendKeyEvent(int key, bool pressed, bool doublePressed) override;
void sendSensorEvent(float position) override;
void sendSensor(int sensor) override;
void sendUpdate() override;
};
#endif
@@ -1,128 +1,145 @@
#include "Touchboard.h"
void Touchboard::scan()
{
// For each key, set multiplexers and poll both capacitive sensors simultaneously
for (int i = 0; i < 8; i++)
{
digitalWrite(MUX_0, bitRead(i, 0));
digitalWrite(MUX_1, bitRead(i, 1));
digitalWrite(MUX_2, bitRead(i, 2));
unsigned int* values = sensor.sense(3);
// Store the values received from the sensor poll into their respective positions
keys[i] = values[0];
keys[i + 8] = values[1];
}
}
void Touchboard::calibrateKeys()
{
// Reset calibration data for all keys
for (int i = 0; i < 16; i++)
{
em_averages[i] = 0;
neutral_values[i] = 0;
key_states[i] = false;
keys[i] = false;
}
for (int i = 0; i < CALIBRATION_SAMPLES; i++) {
// Repeatedly scan all keys
scan();
// Store the lowest read value as our baseline
for (int j = 0; j < 16; j++) {
if (keys[j] > neutral_values[j]) neutral_values[j] = keys[j];
}
}
// After calibration is complete, initialize the averages to the baseline values established previously
for (int i = 0; i < 16; i++) {
em_averages[i] = neutral_values[i];
}
}
bool Touchboard::update(int key)
{
int read_value = keys[key];
float new_average = alpha * read_value + (1 - alpha) * em_averages[key];
if (read_value - neutral_values[key] < deadzone)
{
// If we are in the deadzone, ignore any touch events, set the key to be untouched and update the moving average.
if (key_states[key])
em_averages[key] = neutral_values[key];
else
em_averages[key] = new_average;
key_states[key] = false;
}
else
{
//If we are outside of the deadzone:
if (read_value > em_averages[key] + threshold)
{
// If we just detected a touch, make the key touched, discard the previous moving average and trigger the callback.
em_averages[key] = read_value;
onKeyPress(key, key_states[key]);
key_states[key] = true;
}
else
{
// Otherwise, just update the average.
em_averages[key] = new_average;
}
}
return key_states[key];
}
void Touchboard::setThreshold(uint16_t threshold)
{
this->threshold = threshold;
EEPROM.put(0, threshold);
}
void Touchboard::setDeadzone(uint16_t deadzone)
{
this->deadzone = deadzone;
EEPROM.put(4, deadzone);
}
void Touchboard::setAlpha(float alpha)
{
this->alpha = alpha;
EEPROM.put(8, alpha);
}
int Touchboard::getThreshold()
{
return threshold;
}
int Touchboard::getDeadzone()
{
return deadzone;
}
float Touchboard::getAlpha()
{
return alpha;
}
float Touchboard::getEmAverages(int key)
{
return em_averages[key];
}
Touchboard::Touchboard(void(*keyPressCallback)(int, bool)) :
sensor(CapacitiveSensor(SEND, RECEIVE_1, RECEIVE_2)),
onKeyPress(keyPressCallback)
{
EEPROM.get(0, threshold);
EEPROM.get(4, deadzone);
EEPROM.get(8, alpha);
pinMode(MUX_0, OUTPUT);
pinMode(MUX_1, OUTPUT);
pinMode(MUX_2, OUTPUT);
calibrateKeys();
}
#include "Touchboard.h"
void Touchboard::scan()
{
// For each key, set multiplexers and poll both capacitive sensors simultaneously
for (int i = 0; i < 8; i++)
{
digitalWrite(MUX_0, bitRead(i, 0));
digitalWrite(MUX_1, bitRead(i, 1));
digitalWrite(MUX_2, bitRead(i, 2));
#ifndef TEENSY
unsigned int* values = sensor.sense(3);
// Store the values received from the sensor poll into their respective positions
keys[i] = values[0];
keys[i + 8] = values[1];
#else
keys[i] = (unsigned int)touchRead(TOUCH_0);
keys[i+8] = (unsigned int)touchRead(TOUCH_1);
#endif
}
}
void Touchboard::calibrateKeys()
{
// Reset calibration data for all keys
for (int i = 0; i < 16; i++)
{
em_averages[i] = 0;
neutral_values[i] = 0;
key_states[i] = false;
keys[i] = false;
}
for (int i = 0; i < CALIBRATION_SAMPLES; i++) {
// Repeatedly scan all keys
scan();
// Store the lowest read value as our baseline
for (int j = 0; j < 16; j++) {
if (keys[j] > neutral_values[j]) neutral_values[j] = keys[j];
}
}
// After calibration is complete, initialize the averages to the baseline values established previously
for (int i = 0; i < 16; i++) {
em_averages[i] = neutral_values[i];
}
}
bool Touchboard::update(int key)
{
int read_value = keys[key];
float new_average = alpha * read_value + (1 - alpha) * em_averages[key];
if (read_value - neutral_values[key] < deadzone)
{
// If we are in the deadzone, ignore any touch events, set the key to be untouched and update the moving average.
if (key_states[key])
em_averages[key] = neutral_values[key];
else
em_averages[key] = new_average;
key_states[key] = false;
}
else
{
//If we are outside of the deadzone:
if (read_value > em_averages[key] + threshold)
{
// If we just detected a touch, make the key touched, discard the previous moving average and trigger the callback.
em_averages[key] = read_value;
onKeyPress(key, key_states[key]);
key_states[key] = true;
}
else
{
// Otherwise, just update the average.
em_averages[key] = new_average;
}
}
return key_states[key];
}
void Touchboard::setThreshold(uint16_t threshold)
{
this->threshold = threshold;
EEPROM.put(0, threshold);
}
void Touchboard::setDeadzone(uint16_t deadzone)
{
this->deadzone = deadzone;
EEPROM.put(4, deadzone);
}
void Touchboard::setAlpha(float alpha)
{
this->alpha = alpha;
EEPROM.put(8, alpha);
}
int Touchboard::getThreshold()
{
return threshold;
}
int Touchboard::getDeadzone()
{
return deadzone;
}
float Touchboard::getAlpha()
{
return alpha;
}
float Touchboard::getNeutralValue(int key)
{
return neutral_values[key];
}
float Touchboard::getEmAverages(int key)
{
return em_averages[key];
}
float Touchboard::getRawValue(int key)
{
return keys[key];
}
Touchboard::Touchboard(void(*keyPressCallback)(int, bool)) :
#ifndef TEENSY
sensor(CapacitiveSensor(SEND, RECEIVE_1, RECEIVE_2)),
#endif
onKeyPress(keyPressCallback)
{
EEPROM.get(0, threshold);
EEPROM.get(4, deadzone);
EEPROM.get(8, alpha);
pinMode(MUX_0, OUTPUT);
pinMode(MUX_1, OUTPUT);
pinMode(MUX_2, OUTPUT);
calibrateKeys();
}
@@ -1,41 +1,47 @@
// Touchboard.h
#ifndef _TOUCHBOARD_h
#define _TOUCHBOARD_h
#include "PinConfig.h"
#include "CapacitiveSensor.h"
#include <EEPROM.h>
#define EMA_TOUCHDETECT_ALPHA 0.1f
class Touchboard
{
private:
CapacitiveSensor sensor;
uint16_t threshold;
uint16_t deadzone;
float alpha;
float em_averages[16];
unsigned int keys[16];
int neutral_values[16];
void (*onKeyPress)(int, bool);
public:
boolean key_states[16];
Touchboard(void(*keyPressCallback)(int, bool));
void scan();
bool update(int key);
void setThreshold(uint16_t threshold);
void setDeadzone(uint16_t deadzone);
void setAlpha(float alpha);
int getThreshold();
int getDeadzone();
float getAlpha();
float getEmAverages(int key);
void calibrateKeys();
};
#endif
// Touchboard.h
#ifndef _TOUCHBOARD_h
#define _TOUCHBOARD_h
#include "PinConfig.h"
#ifndef TEENSY
#include "CapacitiveSensor.h"
#endif
#include <EEPROM.h>
#define EMA_TOUCHDETECT_ALPHA 0.1f
class Touchboard
{
private:
#ifndef TEENSY
CapacitiveSensor sensor;
#endif
uint16_t threshold;
uint16_t deadzone;
float alpha;
float em_averages[16];
unsigned int keys[16];
int neutral_values[16];
void (*onKeyPress)(int, bool);
public:
bool key_states[16];
Touchboard(void(*keyPressCallback)(int, bool));
void scan();
bool update(int key);
void setThreshold(uint16_t threshold);
void setDeadzone(uint16_t deadzone);
void setAlpha(float alpha);
int getThreshold();
int getDeadzone();
float getAlpha();
float getNeutralValue(int key);
float getEmAverages(int key);
float getRawValue(int key);
void calibrateKeys();
};
#endif
+119
View File
@@ -0,0 +1,119 @@
#include "PinConfig.h"
#ifdef USB
#include "USBOutput.h"
char bottomRow[] = {KEY_A, KEY_Z, KEY_S, KEY_X, KEY_D, KEY_C, KEY_F, KEY_V, KEY_G, KEY_B, KEY_H, KEY_N, KEY_J, KEY_M, KEY_K, KEY_COMMA};
char topRow[] = {KEY_1, KEY_Q, KEY_2, KEY_W, KEY_3, KEY_E, KEY_4, KEY_R, KEY_5, KEY_T, KEY_6, KEY_Y, KEY_7, KEY_U, KEY_8, KEY_I};
uint16_t airKeys[] = { KEY_SLASH, KEY_PERIOD, KEY_QUOTE , KEY_SEMICOLON, KEY_RIGHT_BRACE , KEY_LEFT_BRACE };
void USBOutput::sendKeyEvent(int key, bool pressed, bool doublePressed)
{
if (pressed) {
if (doublePressed) {
pressKey(topRow[key]);
}
else {
pressKey(bottomRow[key]);
releaseKey(topRow[key]);
}
}
else {
releaseKey(bottomRow[key]);
releaseKey(topRow[key]);
}
}
void USBOutput::sendSensorEvent(float position)
{
// Send hand up / hand down key
if (position > lastPosition)
{
writeKey(KEY_PAGE_UP);
if (wasAirHeld)
{
// Send Air Action
writeKey(KEY_END);
}
}
if (position < lastPosition)
{
writeKey(KEY_PAGE_DOWN);
if (wasAirHeld)
{
// Send Air Action
writeKey(KEY_END);
}
}
// Send hand seen / unseen key
if (position > 0.05f)
{
pressKey(KEY_HOME);
wasAirHeld = true;
}
else {
releaseKey(KEY_HOME);
wasAirHeld = false;
}
// Save last position for next loop
lastPosition = position;
}
void USBOutput::sendSensor(int sensor)
{
for (int i = 0; i < 6; i++)
{
if (bitRead(sensor, i))
pressKey(airKeys[i]);
else
releaseKey(airKeys[i]);
}
}
USBOutput::USBOutput()
{
#ifndef TEENSY
NKROKeyboard.begin();
#endif
lastPosition = 0;
}
void USBOutput::writeKey(uint16_t key)
{
#ifndef TEENSY
NKROKeyboard.write(key);
#else
Nkro.set_key(key);
Nkro.send_nkro_now();
Nkro.reset_key(key);
Nkro.send_nkro_now();
#endif
}
void USBOutput::pressKey(uint16_t key)
{
#ifndef TEENSY
pressKey(key);
#else
Nkro.set_key(key);
#endif
}
void USBOutput::releaseKey(uint16_t key)
{
#ifndef TEENSY
NKROKeyboard.release(key);
#else
Nkro.reset_key(key);
#endif
}
void USBOutput::sendUpdate()
{
Nkro.send_nkro_now();
}
#endif
@@ -1,26 +1,35 @@
// USBOutput.h
#ifndef _USBOUTPUT_h
#define _USBOUTPUT_h
#include "Output.h"
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#include <HID-Project.h>
class USBOutput : public Output
{
private:
float lastPosition;
public:
void sendKeyEvent(int key, bool pressed, bool doublePressed) override;
void sendSensorEvent(float position) override;
USBOutput();
};
#endif
// USBOutput.h
#ifndef _USBOUTPUT_h
#define _USBOUTPUT_h
#include "Config.h"
#include "Output.h"
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#ifndef TEENSY
#include <HID-Project.h>
#endif
class USBOutput : public Output
{
private:
float lastPosition;
bool wasAirHeld;
void writeKey(uint16_t key);
void pressKey(uint16_t key);
void releaseKey(uint16_t key);
public:
void sendKeyEvent(int key, bool pressed, bool doublePressed) override;
void sendSensorEvent(float position) override;
void sendSensor(int sensor) override;
void sendUpdate() override;
USBOutput();
};
#endif
-43
View File
@@ -1,43 +0,0 @@
#ifndef _PINCONFIG_h
#define _PINCONFIG_h
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32u4__)
#define USB
#endif
//#define IR_SENSOR_MULTIPLEXED
//#define IR_SENSOR_ANALOG // Uncomment if IR sensors are hooked up to analog pins
#define CALIBRATION_SAMPLES 500
// Multiplexer pin settings
#define MUX_0 20
#define MUX_1 19
#define MUX_2 18
// Sensor pin settings
#define LED_0 0
#define LED_1 2
#define LED_2 3
#ifdef IR_SENSOR_MULTIPLEXED
#define SENSOR_IN A0
#else
#define AIR_SENSOR_0_PIN 4
#define AIR_SENSOR_1_PIN 5
#define AIR_SENSOR_2_PIN 6
#define AIR_SENSOR_3_PIN 7
#define AIR_SENSOR_4_PIN 8
#define AIR_SENSOR_5_PIN 9
#endif
// Capsense pin settings
#define RECEIVE_1 21
#define RECEIVE_2 1
#define SEND 10
// Lighting pin settings
#define LED_TYPE WS2812B
#define LED_ORDER GRB
#define RGBPIN 16
#endif
File diff suppressed because it is too large Load Diff
+107
View File
@@ -0,0 +1,107 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2017 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WProgram_h
#define WProgram_h
#include <stdlib.h>
#include <string.h>
#include <math.h>
// some libraries and sketches depend on this
// AVR stuff, assuming Arduino.h or WProgram.h
// automatically includes it...
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include "avr_functions.h"
#include "wiring.h"
#include "HardwareSerial.h"
#define DMAMEM __attribute__ ((section(".dmabuffers"), used))
#define FASTRUN __attribute__ ((section(".fastrun"), noinline, noclone ))
#ifdef __cplusplus
#include "avr_emulation.h"
#include "usb_serial.h"
#include "usb_seremu.h"
#include "usb_keyboard.h"
#include "usb_mouse.h"
#include "usb_joystick.h"
#include "usb_nkro.h" // Via https://dawnmist.dreamwidth.org/1250.html
#include "usb_midi.h"
#include "usb_rawhid.h"
#include "usb_flightsim.h"
#include "usb_mtp.h"
#include "usb_audio.h"
#include "usb_touch.h"
#include "usb_undef.h" // do not allow usb_desc.h stuff to leak to user programs
#include "WCharacter.h"
#include "WString.h"
#include "elapsedMillis.h"
#include "IntervalTimer.h"
uint16_t makeWord(uint16_t w);
uint16_t makeWord(byte h, byte l);
#define word(...) makeWord(__VA_ARGS__)
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
void tone(uint8_t pin, uint16_t frequency, uint32_t duration = 0);
void noTone(uint8_t pin);
// WMath prototypes
int32_t random(void);
uint32_t random(uint32_t howbig);
int32_t random(int32_t howsmall, int32_t howbig);
void randomSeed(uint32_t newseed);
void srandom(unsigned int newseed);
#include "pins_arduino.h"
#endif // __cplusplus
// Fast memcpy
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
#ifdef __cplusplus
extern "C" {
extern void *memcpy (void *dst, const void *src, size_t count);
}
#else
extern void *memcpy (void *dst, const void *src, size_t count);
#endif
#endif
#endif // WProgram_h
File diff suppressed because it is too large Load Diff
+966
View File
@@ -0,0 +1,966 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2017 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _usb_desc_h_
#define _usb_desc_h_
// This header is NOT meant to be included when compiling
// user sketches in Arduino. The low-level functions
// provided by usb_dev.c are meant to be called only by
// code which provides higher-level interfaces to the user.
#include <stdint.h>
#include <stddef.h>
#define ENDPOINT_UNUSED 0x00
#define ENDPOINT_TRANSMIT_ONLY 0x15
#define ENDPOINT_RECEIVE_ONLY 0x19
#define ENDPOINT_TRANSMIT_AND_RECEIVE 0x1D
#define ENDPOINT_RECEIVE_ISOCHRONOUS 0x18
#define ENDPOINT_TRANSMIT_ISOCHRONOUS 0x14
/*
Each group of #define lines below corresponds to one of the
settings in the Tools > USB Type menu. This file defines what
type of USB device is actually created for each of those menu
options.
Each "interface" is a set of functionality your PC or Mac will
use and treat as if it is a unique device. Within each interface,
the "endpoints" are the actual communication channels. Most
interfaces use 1, 2 or 3 endpoints. By editing only this file,
you can customize the USB Types to be any collection of interfaces.
To modify a USB Type, delete the XYZ_INTERFACE lines for any
interfaces you wish to remove, and copy them from another USB Type
for any you want to add.
Give each interface a unique number, and edit NUM_INTERFACE to
reflect the total number of interfaces.
Next, assign unique endpoint numbers to all the endpoints across
all the interfaces your device has. You can reuse an endpoint
number for transmit and receive, but the same endpoint number must
not be used twice to transmit, or twice to receive.
Most endpoints also require their maximum size, and some also
need an interval specification (the number of milliseconds the
PC will check for data from that endpoint). For existing
interfaces, usually these other settings should not be changed.
Edit NUM_ENDPOINTS to be at least the largest endpoint number used.
Edit NUM_USB_BUFFERS to control how much memory the USB stack will
allocate. At least 2 should be used for each endpoint. More
memory will allow higher throughput for user programs that have
high latency (eg, spending time doing things other than interacting
with the USB).
Edit the ENDPOINT*_CONFIG lines so each endpoint is configured
the proper way (transmit, receive, or both).
If you are using existing interfaces (making your own device with
a different set of interfaces) the code in all other files should
automatically adapt to the new endpoints you specify here.
If you need to create a new type of interface, you'll need to write
the code which sends and receives packets, and presents an API to
the user. Usually, a pair of files are added for the actual code,
and code is also added in usb_dev.c for any control transfers,
interrupt-level code, or other very low-level stuff not possible
from the packet send/receive functons. Code also is added in
usb_inst.c to create an instance of your C++ object. This message
gives a quick summary of things you will need to know:
https://forum.pjrc.com/threads/49045?p=164512&viewfull=1#post164512
You may edit the Vendor and Product ID numbers, and strings. If
the numbers are changed, Teensyduino may not be able to automatically
find and reboot your board when you click the Upload button in
the Arduino IDE. You will need to press the Program button on
Teensy to initiate programming.
Some operating systems, especially Windows, may cache USB device
info. Changes to the device name may not update on the same
computer unless the vendor or product ID numbers change, or the
"bcdDevice" revision code is increased.
If these instructions are missing steps or could be improved, please
let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
*/
#if defined(USB_SERIAL)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0483
#define DEVICE_CLASS 2 // 2 = Communication Class
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'U','S','B',' ','S','e','r','i','a','l'}
#define PRODUCT_NAME_LEN 10
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 12
#define NUM_INTERFACE 2
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1
#define CDC_ACM_ENDPOINT 2
#define CDC_RX_ENDPOINT 3
#define CDC_TX_ENDPOINT 4
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#elif defined(USB_KEYBOARDONLY)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x04D0
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'K','e','y','b','o','a','r','d'}
#define PRODUCT_NAME_LEN 8
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 14
#define NUM_INTERFACE 3
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define KEYBOARD_INTERFACE 0 // Keyboard
#define KEYBOARD_ENDPOINT 3
#define KEYBOARD_SIZE 8
#define KEYBOARD_INTERVAL 1
#define KEYMEDIA_INTERFACE 2 // Keyboard Media Keys
#define KEYMEDIA_ENDPOINT 4
#define KEYMEDIA_SIZE 8
#define KEYMEDIA_INTERVAL 4
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY
#elif defined(USB_HID)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0482
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','J','o','y','s','t','i','c','k'}
#define PRODUCT_NAME_LEN 23
#define EP0_SIZE 64
#define NUM_ENDPOINTS 6
#define NUM_USB_BUFFERS 24
#define NUM_INTERFACE 5
#define SEREMU_INTERFACE 2 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define KEYBOARD_INTERFACE 0 // Keyboard
#define KEYBOARD_ENDPOINT 3
#define KEYBOARD_SIZE 8
#define KEYBOARD_INTERVAL 1
#define KEYMEDIA_INTERFACE 4 // Keyboard Media Keys
#define KEYMEDIA_ENDPOINT 6
#define KEYMEDIA_SIZE 8
#define KEYMEDIA_INTERVAL 4
#define MOUSE_INTERFACE 1 // Mouse
#define MOUSE_ENDPOINT 5
#define MOUSE_SIZE 8
#define MOUSE_INTERVAL 1
#define JOYSTICK_INTERFACE 3 // Joystick
#define JOYSTICK_ENDPOINT 4
#define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick
#define JOYSTICK_INTERVAL 2
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY
#elif defined(USB_SERIAL_HID)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0487
#define DEVICE_CLASS 0xEF
#define DEVICE_SUBCLASS 0x02
#define DEVICE_PROTOCOL 0x01
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'S','e','r','i','a','l','/','K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','J','o','y','s','t','i','c','k'}
#define PRODUCT_NAME_LEN 30
#define EP0_SIZE 64
#define NUM_ENDPOINTS 7
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 6
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1 // Serial
#define CDC_ACM_ENDPOINT 2
#define CDC_RX_ENDPOINT 3
#define CDC_TX_ENDPOINT 4
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define KEYBOARD_INTERFACE 2 // Keyboard
#define KEYBOARD_ENDPOINT 1
#define KEYBOARD_SIZE 8
#define KEYBOARD_INTERVAL 1
#define KEYMEDIA_INTERFACE 5 // Keyboard Media Keys
#define KEYMEDIA_ENDPOINT 7
#define KEYMEDIA_SIZE 8
#define KEYMEDIA_INTERVAL 4
#define MOUSE_INTERFACE 3 // Mouse
#define MOUSE_ENDPOINT 5
#define MOUSE_SIZE 8
#define MOUSE_INTERVAL 2
#define JOYSTICK_INTERFACE 4 // Joystick
#define JOYSTICK_ENDPOINT 6
#define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick
#define JOYSTICK_INTERVAL 1
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT7_CONFIG ENDPOINT_TRANSMIT_ONLY
#elif defined(USB_TOUCHSCREEN)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x04D3
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'K','e','y','b','o','a','r','d','/','T','o','u','c','h','s','c','r','e','e','n'}
#define PRODUCT_NAME_LEN 20
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 15
#define NUM_INTERFACE 4
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define KEYBOARD_INTERFACE 0 // Keyboard
#define KEYBOARD_ENDPOINT 3
#define KEYBOARD_SIZE 8
#define KEYBOARD_INTERVAL 1
#define KEYMEDIA_INTERFACE 2 // Keyboard Media Keys
#define KEYMEDIA_ENDPOINT 4
#define KEYMEDIA_SIZE 8
#define KEYMEDIA_INTERVAL 4
#define MULTITOUCH_INTERFACE 3 // Touchscreen
#define MULTITOUCH_ENDPOINT 5
#define MULTITOUCH_SIZE 8
#define MULTITOUCH_FINGERS 10
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
#elif defined(USB_HID_TOUCHSCREEN)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x04D4
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','T','o','u','c','h','s','c','r','e','e','n'}
#define PRODUCT_NAME_LEN 26
#define EP0_SIZE 64
#define NUM_ENDPOINTS 6
#define NUM_USB_BUFFERS 20
#define NUM_INTERFACE 5
#define SEREMU_INTERFACE 2 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define KEYBOARD_INTERFACE 0 // Keyboard
#define KEYBOARD_ENDPOINT 3
#define KEYBOARD_SIZE 8
#define KEYBOARD_INTERVAL 1
#define KEYMEDIA_INTERFACE 3 // Keyboard Media Keys
#define KEYMEDIA_ENDPOINT 4
#define KEYMEDIA_SIZE 8
#define KEYMEDIA_INTERVAL 4
#define MOUSE_INTERFACE 1 // Mouse
#define MOUSE_ENDPOINT 6
#define MOUSE_SIZE 8
#define MOUSE_INTERVAL 2
#define MULTITOUCH_INTERFACE 4 // Touchscreen
#define MULTITOUCH_ENDPOINT 5
#define MULTITOUCH_SIZE 8
#define MULTITOUCH_FINGERS 10
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY
#elif defined(USB_MIDI)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0485
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','M','I','D','I'}
#define PRODUCT_NAME_LEN 11
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 16
#define NUM_INTERFACE 2
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define MIDI_INTERFACE 0 // MIDI
#define MIDI_NUM_CABLES 1
#define MIDI_TX_ENDPOINT 3
#define MIDI_TX_SIZE 64
#define MIDI_RX_ENDPOINT 4
#define MIDI_RX_SIZE 64
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY
#elif defined(USB_MIDI4)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0485
#define BCD_DEVICE 0x0211
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','M','I','D','I','x','4'}
#define PRODUCT_NAME_LEN 13
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 16
#define NUM_INTERFACE 2
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define MIDI_INTERFACE 0 // MIDI
#define MIDI_NUM_CABLES 4
#define MIDI_TX_ENDPOINT 3
#define MIDI_TX_SIZE 64
#define MIDI_RX_ENDPOINT 4
#define MIDI_RX_SIZE 64
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY
#elif defined(USB_MIDI16)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0485
#define BCD_DEVICE 0x0212
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','M','I','D','I','x','1','6'}
#define PRODUCT_NAME_LEN 14
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 16
#define NUM_INTERFACE 2
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define MIDI_INTERFACE 0 // MIDI
#define MIDI_NUM_CABLES 16
#define MIDI_TX_ENDPOINT 3
#define MIDI_TX_SIZE 64
#define MIDI_RX_ENDPOINT 4
#define MIDI_RX_SIZE 64
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY
#elif defined(USB_MIDI_SERIAL)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0489
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','M','I','D','I'}
#define PRODUCT_NAME_LEN 11
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 3
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1 // Serial
#define CDC_ACM_ENDPOINT 1
#define CDC_RX_ENDPOINT 2
#define CDC_TX_ENDPOINT 3
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define MIDI_INTERFACE 2 // MIDI
#define MIDI_NUM_CABLES 1
#define MIDI_TX_ENDPOINT 4
#define MIDI_TX_SIZE 64
#define MIDI_RX_ENDPOINT 5
#define MIDI_RX_SIZE 64
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY
#elif defined(USB_MIDI4_SERIAL)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0489
#define BCD_DEVICE 0x0211
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','M','I','D','I','x','4'}
#define PRODUCT_NAME_LEN 13
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 3
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1 // Serial
#define CDC_ACM_ENDPOINT 1
#define CDC_RX_ENDPOINT 2
#define CDC_TX_ENDPOINT 3
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define MIDI_INTERFACE 2 // MIDI
#define MIDI_NUM_CABLES 4
#define MIDI_TX_ENDPOINT 4
#define MIDI_TX_SIZE 64
#define MIDI_RX_ENDPOINT 5
#define MIDI_RX_SIZE 64
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY
#elif defined(USB_MIDI16_SERIAL)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0489
#define BCD_DEVICE 0x0212
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','M','I','D','I','x','1','6'}
#define PRODUCT_NAME_LEN 14
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 3
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1 // Serial
#define CDC_ACM_ENDPOINT 1
#define CDC_RX_ENDPOINT 2
#define CDC_TX_ENDPOINT 3
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define MIDI_INTERFACE 2 // MIDI
#define MIDI_NUM_CABLES 16
#define MIDI_TX_ENDPOINT 4
#define MIDI_TX_SIZE 64
#define MIDI_RX_ENDPOINT 5
#define MIDI_RX_SIZE 64
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY
#elif defined(USB_RAWHID)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0486
#define RAWHID_USAGE_PAGE 0xFFAB // recommended: 0xFF00 to 0xFFFF
#define RAWHID_USAGE 0x0200 // recommended: 0x0100 to 0xFFFF
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y','d','u','i','n','o',' ','R','a','w','H','I','D'}
#define PRODUCT_NAME_LEN 18
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 12
#define NUM_INTERFACE 2
#define RAWHID_INTERFACE 0 // RawHID
#define RAWHID_TX_ENDPOINT 3
#define RAWHID_TX_SIZE 64
#define RAWHID_TX_INTERVAL 1
#define RAWHID_RX_ENDPOINT 4
#define RAWHID_RX_SIZE 64
#define RAWHID_RX_INTERVAL 1
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY
#elif defined(USB_FLIGHTSIM)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0488
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','F','l','i','g','h','t',' ','S','i','m',' ','C','o','n','t','r','o','l','s'}
#define PRODUCT_NAME_LEN 26
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 20
#define NUM_INTERFACE 2
#define FLIGHTSIM_INTERFACE 0 // Flight Sim Control
#define FLIGHTSIM_TX_ENDPOINT 3
#define FLIGHTSIM_TX_SIZE 64
#define FLIGHTSIM_TX_INTERVAL 1
#define FLIGHTSIM_RX_ENDPOINT 4
#define FLIGHTSIM_RX_SIZE 64
#define FLIGHTSIM_RX_INTERVAL 1
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY
#elif defined(USB_FLIGHTSIM_JOYSTICK)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0488
#define BCD_DEVICE 0x0211
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','F','l','i','g','h','t',' ','S','i','m',' ','C','o','n','t','r','o','l','s'}
#define PRODUCT_NAME_LEN 26
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 20
#define NUM_INTERFACE 3
#define FLIGHTSIM_INTERFACE 0 // Flight Sim Control
#define FLIGHTSIM_TX_ENDPOINT 3
#define FLIGHTSIM_TX_SIZE 64
#define FLIGHTSIM_TX_INTERVAL 1
#define FLIGHTSIM_RX_ENDPOINT 4
#define FLIGHTSIM_RX_SIZE 64
#define FLIGHTSIM_RX_INTERVAL 1
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define JOYSTICK_INTERFACE 2 // Joystick
#define JOYSTICK_ENDPOINT 5
#define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick
#define JOYSTICK_INTERVAL 1
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
#elif defined(USB_MTPDISK)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x04D1
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','M','T','P',' ','D','i','s','k'}
#define PRODUCT_NAME_LEN 15
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 20
#define NUM_INTERFACE 2
#define MTP_INTERFACE 0 // MTP Disk
#define MTP_TX_ENDPOINT 3
#define MTP_TX_SIZE 64
#define MTP_RX_ENDPOINT 3
#define MTP_RX_SIZE 64
#define MTP_EVENT_ENDPOINT 4
#define MTP_EVENT_SIZE 16
#define MTP_EVENT_INTERVAL 10
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY
#elif defined(USB_AUDIO)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x04D2
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','A','u','d','i','o'}
#define PRODUCT_NAME_LEN 12
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 16
#define NUM_INTERFACE 4
#define SEREMU_INTERFACE 0 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define AUDIO_INTERFACE 1 // Audio (uses 3 consecutive interfaces)
#define AUDIO_TX_ENDPOINT 3
#define AUDIO_TX_SIZE 180
#define AUDIO_RX_ENDPOINT 4
#define AUDIO_RX_SIZE 180
#define AUDIO_SYNC_ENDPOINT 5
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS
#elif defined(USB_MIDI_AUDIO_SERIAL)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x048A
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','M','I','D','I','/','A','u','d','i','o'}
#define PRODUCT_NAME_LEN 17
#define EP0_SIZE 64
#define NUM_ENDPOINTS 8
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 6
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1 // Serial
#define CDC_ACM_ENDPOINT 1
#define CDC_RX_ENDPOINT 2
#define CDC_TX_ENDPOINT 3
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define MIDI_INTERFACE 2 // MIDI
#define MIDI_NUM_CABLES 1
#define MIDI_TX_ENDPOINT 4
#define MIDI_TX_SIZE 64
#define MIDI_RX_ENDPOINT 5
#define MIDI_RX_SIZE 64
#define AUDIO_INTERFACE 3 // Audio (uses 3 consecutive interfaces)
#define AUDIO_TX_ENDPOINT 6
#define AUDIO_TX_SIZE 180
#define AUDIO_RX_ENDPOINT 7
#define AUDIO_RX_SIZE 180
#define AUDIO_SYNC_ENDPOINT 8
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS
#define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS
#define ENDPOINT8_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS
#elif defined(USB_MIDI16_AUDIO_SERIAL)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x048A
#define BCD_DEVICE 0x0212
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','M','I','D','I','x','1','6','/','A','u','d','i','o'}
#define PRODUCT_NAME_LEN 20
#define EP0_SIZE 64
#define NUM_ENDPOINTS 8
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 6
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1 // Serial
#define CDC_ACM_ENDPOINT 1
#define CDC_RX_ENDPOINT 2
#define CDC_TX_ENDPOINT 3
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define MIDI_INTERFACE 2 // MIDI
#define MIDI_NUM_CABLES 16
#define MIDI_TX_ENDPOINT 4
#define MIDI_TX_SIZE 64
#define MIDI_RX_ENDPOINT 5
#define MIDI_RX_SIZE 64
#define AUDIO_INTERFACE 3 // Audio (uses 3 consecutive interfaces)
#define AUDIO_TX_ENDPOINT 6
#define AUDIO_TX_SIZE 180
#define AUDIO_RX_ENDPOINT 7
#define AUDIO_RX_SIZE 180
#define AUDIO_SYNC_ENDPOINT 8
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS
#define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS
#define ENDPOINT8_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS
#elif defined(USB_EVERYTHING)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0476
#define RAWHID_USAGE_PAGE 0xFFAB // recommended: 0xFF00 to 0xFFFF
#define RAWHID_USAGE 0x0200 // recommended: 0x0100 to 0xFFFF
#define DEVICE_CLASS 0xEF
#define DEVICE_SUBCLASS 0x02
#define DEVICE_PROTOCOL 0x01
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'A','l','l',' ','T','h','e',' ','T','h','i','n','g','s'}
#define PRODUCT_NAME_LEN 14
#define EP0_SIZE 64
#define NUM_ENDPOINTS 15
#define NUM_USB_BUFFERS 31
#define NUM_INTERFACE 13
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1 // Serial
#define CDC_ACM_ENDPOINT 1
#define CDC_RX_ENDPOINT 2
#define CDC_TX_ENDPOINT 2
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define MIDI_INTERFACE 2 // MIDI
#define MIDI_NUM_CABLES 16
#define MIDI_TX_ENDPOINT 3
#define MIDI_TX_SIZE 64
#define MIDI_RX_ENDPOINT 3
#define MIDI_RX_SIZE 64
#define KEYBOARD_INTERFACE 3 // Keyboard
#define KEYBOARD_ENDPOINT 4
#define KEYBOARD_SIZE 8
#define KEYBOARD_INTERVAL 1
#define MOUSE_INTERFACE 4 // Mouse
#define MOUSE_ENDPOINT 5
#define MOUSE_SIZE 8
#define MOUSE_INTERVAL 2
#define RAWHID_INTERFACE 5 // RawHID
#define RAWHID_TX_ENDPOINT 6
#define RAWHID_TX_SIZE 64
#define RAWHID_TX_INTERVAL 1
#define RAWHID_RX_ENDPOINT 6
#define RAWHID_RX_SIZE 64
#define RAWHID_RX_INTERVAL 1
#define FLIGHTSIM_INTERFACE 6 // Flight Sim Control
#define FLIGHTSIM_TX_ENDPOINT 9
#define FLIGHTSIM_TX_SIZE 64
#define FLIGHTSIM_TX_INTERVAL 1
#define FLIGHTSIM_RX_ENDPOINT 9
#define FLIGHTSIM_RX_SIZE 64
#define FLIGHTSIM_RX_INTERVAL 1
#define JOYSTICK_INTERFACE 7 // Joystick
#define JOYSTICK_ENDPOINT 10
#define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick
#define JOYSTICK_INTERVAL 1
/*
#define MTP_INTERFACE 8 // MTP Disk
#define MTP_TX_ENDPOINT 11
#define MTP_TX_SIZE 64
#define MTP_RX_ENDPOINT 3
#define MTP_RX_SIZE 64
#define MTP_EVENT_ENDPOINT 11
#define MTP_EVENT_SIZE 16
#define MTP_EVENT_INTERVAL 10
*/
#define KEYMEDIA_INTERFACE 8 // Keyboard Media Keys
#define KEYMEDIA_ENDPOINT 12
#define KEYMEDIA_SIZE 8
#define KEYMEDIA_INTERVAL 4
#define AUDIO_INTERFACE 9 // Audio (uses 3 consecutive interfaces)
#define AUDIO_TX_ENDPOINT 13
#define AUDIO_TX_SIZE 180
#define AUDIO_RX_ENDPOINT 13
#define AUDIO_RX_SIZE 180
#define AUDIO_SYNC_ENDPOINT 14
#define MULTITOUCH_INTERFACE 12 // Touchscreen
#define MULTITOUCH_ENDPOINT 15
#define MULTITOUCH_SIZE 8
#define MULTITOUCH_FINGERS 10
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE
#define ENDPOINT7_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE
#define ENDPOINT8_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT9_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE
#define ENDPOINT10_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT11_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE
#define ENDPOINT12_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT13_CONFIG (ENDPOINT_RECEIVE_ISOCHRONOUS|ENDPOINT_TRANSMIT_ISOCHRONOUS)
#define ENDPOINT14_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS
#define ENDPOINT15_CONFIG ENDPOINT_TRANSMIT_ONLY
#elif defined(USB_NKRO)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x04D0
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'N','K','R','O',' ','K','e','y','b','o','a','r','d'}
#define PRODUCT_NAME_LEN 13
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 14
#define NUM_INTERFACE 4
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define KEYBOARD_INTERFACE 0 // Keyboard
#define KEYBOARD_ENDPOINT 3
#define KEYBOARD_SIZE 8
#define KEYBOARD_INTERVAL 1
#define KEYMEDIA_INTERFACE 2 // Keyboard Media Keys
#define KEYMEDIA_ENDPOINT 4
#define KEYMEDIA_SIZE 8
#define KEYMEDIA_INTERVAL 4
#define NKRO_INTERFACE 3 // NKRO Keyboard
#define NKRO_ENDPOINT 5
#define NKRO_SIZE 32
#define NKRO_REPORT_KEYS ( NKRO_SIZE - 1 )
#define NKRO_INTERVAL 1
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY
#elif defined(USB_SERIAL_NKRO)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0487
#define DEVICE_CLASS 0xEF
#define DEVICE_SUBCLASS 0x02
#define DEVICE_PROTOCOL 0x01
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'S','e','r','i','a','l','/','N','K','R','O',' ','K','e','y','b','o','a','r','d'}
#define PRODUCT_NAME_LEN 20
#define EP0_SIZE 64
#define NUM_ENDPOINTS 6
#define NUM_USB_BUFFERS 14
#define NUM_INTERFACE 5
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1 // Serial
#define CDC_ACM_ENDPOINT 2
#define CDC_RX_ENDPOINT 3
#define CDC_TX_ENDPOINT 4
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define KEYBOARD_INTERFACE 2 // Keyboard
#define KEYBOARD_ENDPOINT 1
#define KEYBOARD_SIZE 8
#define KEYBOARD_INTERVAL 1
#define KEYMEDIA_INTERFACE 3 // Keyboard Media Keys
#define KEYMEDIA_ENDPOINT 5
#define KEYMEDIA_SIZE 8
#define KEYMEDIA_INTERVAL 4
#define NKRO_INTERFACE 4 // NKRO Keyboard
#define NKRO_ENDPOINT 6
#define NKRO_SIZE 32
#define NKRO_REPORT_KEYS ( NKRO_SIZE - 1 )
#define NKRO_INTERVAL 1
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY
#endif
#ifdef USB_DESC_LIST_DEFINE
#if defined(NUM_ENDPOINTS) && NUM_ENDPOINTS > 0
// NUM_ENDPOINTS = number of non-zero endpoints (0 to 15)
extern const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS];
typedef struct {
uint16_t wValue;
uint16_t wIndex;
const uint8_t *addr;
uint16_t length;
} usb_descriptor_list_t;
extern const usb_descriptor_list_t usb_descriptor_list[];
#endif // NUM_ENDPOINTS
#endif // USB_DESC_LIST_DEFINE
#endif
+144
View File
@@ -0,0 +1,144 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2017 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _usb_dev_h_
#define _usb_dev_h_
#define USB_DESC_LIST_DEFINE
#include "usb_desc.h"
#if F_CPU >= 20000000 && !defined(USB_DISABLED)
// This header is NOT meant to be included when compiling
// user sketches in Arduino. The low-level functions
// provided by usb_dev.c are meant to be called only by
// code which provides higher-level interfaces to the user.
#include "usb_mem.h"
#ifdef __cplusplus
extern "C" {
#endif
void usb_init(void);
void usb_init_serialnumber(void);
void usb_isr(void);
usb_packet_t *usb_rx(uint32_t endpoint);
uint32_t usb_tx_byte_count(uint32_t endpoint);
uint32_t usb_tx_packet_count(uint32_t endpoint);
void usb_tx(uint32_t endpoint, usb_packet_t *packet);
void usb_tx_isochronous(uint32_t endpoint, void *data, uint32_t len);
extern volatile uint8_t usb_configuration;
extern uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS];
static inline uint32_t usb_rx_byte_count(uint32_t endpoint) __attribute__((always_inline));
static inline uint32_t usb_rx_byte_count(uint32_t endpoint)
{
endpoint--;
if (endpoint >= NUM_ENDPOINTS) return 0;
return usb_rx_byte_count_data[endpoint];
}
#ifdef CDC_DATA_INTERFACE
extern uint32_t usb_cdc_line_coding[2];
extern volatile uint32_t usb_cdc_line_rtsdtr_millis;
extern volatile uint32_t systick_millis_count;
extern volatile uint8_t usb_cdc_line_rtsdtr;
extern volatile uint8_t usb_cdc_transmit_flush_timer;
extern void usb_serial_flush_callback(void);
#endif
#ifdef SEREMU_INTERFACE
extern volatile uint8_t usb_seremu_transmit_flush_timer;
extern void usb_seremu_flush_callback(void);
#endif
#ifdef KEYBOARD_INTERFACE
extern uint8_t keyboard_modifier_keys;
extern uint8_t keyboard_keys[6];
extern uint8_t keyboard_protocol;
extern uint8_t keyboard_idle_config;
extern uint8_t keyboard_idle_count;
extern volatile uint8_t keyboard_leds;
#endif
#ifdef NKRO_INTERFACE
extern uint8_t nkro_report_data[NKRO_SIZE];
extern uint8_t nkro_protocol;
extern uint8_t nkro_idle_config;
extern uint8_t nkro_idle_count;
#endif
#ifdef MIDI_INTERFACE
extern void usb_midi_flush_output(void);
#endif
#ifdef FLIGHTSIM_INTERFACE
extern void usb_flightsim_flush_callback(void);
#endif
#ifdef AUDIO_INTERFACE
extern uint16_t usb_audio_receive_buffer[];
extern uint16_t usb_audio_transmit_buffer[];
extern uint32_t usb_audio_sync_feedback;
extern uint8_t usb_audio_receive_setting;
extern uint8_t usb_audio_transmit_setting;
extern void usb_audio_receive_callback(unsigned int len);
extern unsigned int usb_audio_transmit_callback(void);
extern int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen);
extern int usb_audio_set_feature(void *stp, uint8_t *buf);
#endif
#ifdef MULTITOUCH_INTERFACE
extern void usb_touchscreen_update_callback(void);
#endif
#ifdef __cplusplus
}
#endif
#else // F_CPU < 20000000
#ifdef __cplusplus
extern "C" {
#endif
void usb_init(void);
#ifdef __cplusplus
}
#endif
#endif // F_CPU
#endif
+92
View File
@@ -0,0 +1,92 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2017 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Arduino.h>
#include "usb_desc.h"
#if F_CPU >= 20000000
#ifdef CDC_DATA_INTERFACE
#ifdef CDC_STATUS_INTERFACE
usb_serial_class Serial;
#endif
#endif
#ifdef MIDI_INTERFACE
usb_midi_class usbMIDI;
#endif
#ifdef KEYBOARD_INTERFACE
usb_keyboard_class Keyboard;
#endif
#ifdef MOUSE_INTERFACE
usb_mouse_class Mouse;
#endif
#ifdef RAWHID_INTERFACE
usb_rawhid_class RawHID;
#endif
#ifdef FLIGHTSIM_INTERFACE
FlightSimClass FlightSim;
#endif
#ifdef SEREMU_INTERFACE
usb_seremu_class Serial;
#endif
#ifdef JOYSTICK_INTERFACE
usb_joystick_class Joystick;
uint8_t usb_joystick_class::manual_mode = 0;
#endif
#ifdef USB_DISABLED
usb_serial_class Serial;
#endif
#ifdef NKRO_INTERFACE
usb_nkro_class Nkro;
#endif
#else // F_CPU < 20 MHz
#if defined(USB_SERIAL) || defined(USB_SERIAL_HID)
usb_serial_class Serial;
#elif (USB_DISABLED)
usb_serial_class Serial;
#else
usb_seremu_class Serial;
#endif
#endif // F_CPU
void serialEvent() __attribute__((weak));
void serialEvent() {}
+117
View File
@@ -0,0 +1,117 @@
// Via https://dawnmist.dreamwidth.org/1250.html
#include "usb_dev.h"
#include "usb_nkro.h"
#include "core_pins.h" // for yield()
#include "keylayouts.h"
//#include "HardwareSerial.h"
#include <string.h> // for memcpy()
#ifdef NKRO_INTERFACE // defined by usb_dev.h -> usb_desc.h
// byte0: which modifier keys are currently pressed
// 1=left ctrl, 2=left shift, 4=left alt, 8=left gui
// 16=right ctrl, 32=right shift, 64=right alt, 128=right gui
// bytes1-NKRO_SIZE: which keys are currently pressed, one bit
// per key for codes 0 to ((8*NKRO_REPORT_SIZE) - 1)
uint8_t nkro_report_data[NKRO_SIZE];
// protocol setting from the host. We use exactly the same report
// either way, so this variable only stores the setting since we
// are required to be able to report which setting is in use.
uint8_t nkro_protocol=1;
// the idle configuration, how often we send the report to the
// host (ms * 4) even when it hasn't changed
uint8_t nkro_idle_config=125;
// count until idle timeout
uint8_t nkro_idle_count=0;
// NKRO Keyboard
void usb_nkro_reset_keys()
{
uint8_t index;
for (index=0; index < NKRO_SIZE; index++)
{
nkro_report_data[index] = 0;
}
}
void usb_nkro_reset_key(uint8_t usb_keycode)
{
uint8_t bit = usb_keycode % 8;
uint8_t byte = (usb_keycode / 8) + 1;
if (usb_keycode >= 240 && usb_keycode <= 247)
{
// Reset a modifier key
nkro_report_data[0] &= ~(1<< bit);
}
else if (byte > 0 && byte <= NKRO_REPORT_KEYS)
{
nkro_report_data[byte] &= ~(1 << bit);
}
}
void usb_nkro_set_key(uint8_t usb_keycode)
{
uint8_t bit = usb_keycode % 8;
uint8_t byte = (usb_keycode / 8) + 1;
if (usb_keycode >= 240 && usb_keycode <= 247)
{
// Reset a modifier key
nkro_report_data[0] |= (1 << bit);
}
else if (byte > 0 && byte <= NKRO_REPORT_KEYS)
{
nkro_report_data[byte] |= (1 << bit);
}
}
// Maximum number of transmit packets to queue so we don't starve other endpoints for memory
#define TX_PACKET_LIMIT 4
static uint8_t transmit_previous_timeout=0;
// When the PC isn't listening, how long do we wait before discarding data?
#define TX_TIMEOUT_MSEC 50
#if F_CPU == 96000000
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596)
#elif F_CPU == 48000000
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428)
#elif F_CPU == 24000000
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262)
#endif
int usb_nkro_send_nkro_now(void)
{
uint32_t wait_count=0;
usb_packet_t *tx_packet;
while (1) {
if (!usb_configuration) {
return -1;
}
if (usb_tx_packet_count(NKRO_ENDPOINT) < TX_PACKET_LIMIT) {
tx_packet = usb_malloc();
if (tx_packet) break;
}
if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) {
transmit_previous_timeout = 1;
return -1;
}
yield();
}
memcpy(tx_packet->buf, nkro_report_data, NKRO_SIZE);
tx_packet->len = NKRO_SIZE;
usb_tx(NKRO_ENDPOINT, tx_packet);
return 0;
}
#endif // NKRO_INTERFACE
+45
View File
@@ -0,0 +1,45 @@
// Via https://dawnmist.dreamwidth.org/1250.html
#ifndef USBnkro_h_
#define USBnkro_h_
#include "keylayouts.h"
#if defined(USB_NKRO) || defined(USB_SERIAL_NKRO)
#include <inttypes.h>
// C language implementation
#ifdef __cplusplus
extern "C" {
#endif
void usb_nkro_reset_keys();
void usb_nkro_reset_key(uint8_t key);
void usb_nkro_set_key(uint8_t key);
int usb_nkro_send_nkro_now();
#ifdef __cplusplus
}
#endif
// C interface
#ifdef __cplusplus
#include "Stream.h"
class usb_nkro_class
{
public:
void reset_keys() { usb_nkro_reset_keys(); }
void reset_key(uint8_t key) { usb_nkro_reset_key(key); }
void reset_key_ascii(char key) {usb_nkro_reset_key(keycodes_ascii[key-0x20]); }
void set_key(uint8_t key) { usb_nkro_set_key(key); }
void set_key_ascii(char key) {usb_nkro_set_key(keycodes_ascii[key-0x20]); }
int send_nkro_now(void) { return usb_nkro_send_nkro_now(); }
};
extern usb_nkro_class Nkro;
#endif // __cplusplus
#endif // USB_NKRO
#endif // USBnkro_h_
-52
View File
@@ -1,52 +0,0 @@
#include "PinConfig.h"
#ifdef USB
#include "USBOutput.h"
char bottomRow[] = {'a', 'z', 's', 'x', 'd', 'c', 'f', 'v', 'g', 'b', 'h', 'n', 'j', 'm', 'k', ','};
char topRow[] = {'1', 'q', '2', 'w', '3', 'e', '4', 'r', '5', 't', '6', 'y', '7', 'u', '8', 'i'};
void USBOutput::sendKeyEvent(int key, bool pressed, bool doublePressed)
{
if (pressed) {
if (doublePressed) {
NKROKeyboard.write(topRow[key]);
}
else {
NKROKeyboard.press(bottomRow[key]);
}
}
else {
NKROKeyboard.release(bottomRow[key]);
}
}
void USBOutput::sendSensorEvent(float position)
{
// Send hand up / hand down key
if (position > lastPosition) {
NKROKeyboard.write(KEY_PAGE_UP);
}
if (position < lastPosition) {
NKROKeyboard.write(KEY_PAGE_DOWN);
}
// Send hand seen / unseen key
if (position > 0.05f) {
NKROKeyboard.press(KEY_HOME);
}
else {
NKROKeyboard.release(KEY_HOME);
}
// Send hand moved key
NKROKeyboard.write(KEY_END);
}
USBOutput::USBOutput() {
NKROKeyboard.begin();
lastPosition = 0;
}
#endif
+425 -1
View File
@@ -2,4 +2,428 @@
This repository contails files related to OpeNITHM.
Firmware and schematic files can be found in this repository. Early CAD files and partial build instructions are located [here](https://drive.google.com/open?id=13EOi3ONAabND2K3P6B_jKoXaEpfQZMc9) and will slowly be migrated to this repository as they are finalized.
Firmware, schematics, board layout, and CAD files are included in this repo.
## List of Hardware
In the `CAD\STL` folder, you will find numerous parts that must be 3D printed.
| Part | Qty |
| --- |:---:|
| Center Frame | 1 |
| Right Frame | 1 |
| Left Frame | 1 |
| Key **OR** Key-US_Cust<sup>1</sup> | 16 |
| LED Clamp | 16 |
| Sensor Rail | 2 |
| Sensor Spacer Left<sup>2</sup> | 1 |
| Sensor Base Left<sup>2</sup> **OR** Integrated Sensor Base Left<sup>2</sup> | 1 |
| Sensor Cover Left<sup>2</sup> | 1 |
| Integrated Frame Mount Left<sup>2,3</sup> | 1 |
**NOTES:**
1. "Key" is designed for 3mm acrylic, "Key-US_Cust" is designed for 1/8" acrylic
2. Print out mirrored version of these parts as well.
3. Only print the frame mount if you are using the integrated sensor.
You will also need the following hardware:
| Part | Qty |
| --- |:---:|
| 4-40 Flat Head Screw, length 3/16" to 5/16" will work **OR** M3 equivalent | 2 |
| Acrylic Rectangles, 90mm x 26mm, Thickness 3mm **OR** 1/8" | 16 |
| Copper Tape, cut into rectangles 95mm x 26mm | 16 |
## List of Electronics
OpeNITHM is designed two different processors in mind: the Pro Micro and the Teensy LC.
Based on testing, it seems the Teensy LC is easier to set up and calibrate, but either should work with enough tuning.
### Teensy LC Build
Links are mostly suggestions (except the Teensy, which is only officially available through the PJRC site and authorized resellers).
The links below also assume you want to socket your Teensy and multiplexers for later use. You can solder them directly, if you'd like.
If you are going to solder your sensors directly to the PCB, it is not necessary buy the 0.1" Pin Header, Right Angle. Otherwise, include female 0.1" sockets for your sensors (commonly referred to as Dupont connectors).
| Part | Link | Qty |
| --- | --- |:---:|
| Teensy LC | https://www.pjrc.com/store/teensylc.html | 1 |
| Teensy LC Breakout Board | this Github, Circuit-Teensy folder contains gerbers | 1 |
| 74HC4051 Multiplexer Breaking Board | [Aliexpress][1] | 2 |
| 0.1" Pin Header, 1 row, 40 pos | [Aliexpress (qty 10)][2] | 2 |
| 0.1" Pin Header, Right Angle, 2 row, 16 pos | [LCSC][3] | 2 |
| 0.1" Socket, Straight, 1 row, 14 pos | [LCSC][4] | 2 |
| 0.1" Socket, Straight, 1 row, 5 pos | [LCSC][5] | 2 |
| 0.1" Socket, Straight, 1 row, 11 pos | [LCSC][6] | 2 |
| 0.1" Socket, Straight, 1 row, 8 pos | [LCSC][7] | 2 |
| 51k ohm Resistor, 1/6W or 1/8W | LCSC or Aliexpress | 6 |
| 33 ohm Resistor, 1/4W, 1/6W, or 1/8W | LCSC or Aliexpress | 3 |
| 1m WS2812B RGB 5V LED Strip, 30LED Per Meter | [Aliexpress][8] | 1 |
| IR LED and Photodiode Pair | [Aliexpress (20 pairs)][9] | 6 |
[1]: https://www.aliexpress.com/item/32807771098.html
[2]: https://www.aliexpress.com/item/665534073.html
[3]: https://lcsc.com/product-detail/Pin-Header-Female-Header_Changjiang-Connectors-A2541WR-2x8P_C239339.html
[4]: https://lcsc.com/product-detail/Pin-Header-Female-Header_Boom-Precision-Elec-Female-header-2-54-1-14P_C52711.html
[5]: https://lcsc.com/product-detail/Pin-Header-Female-Header_Boom-Precision-Elec-2-54mm-1-5p-Female-header_C50950.html
[6]: https://lcsc.com/product-detail/Pin-Header-Female-Header_Changjiang-Connectors-A2541HWV-11P_C225508.html
[7]: https://lcsc.com/product-detail/Pin-Header-Female-Header_Boom-Precision-Elec-2-54mm-1-8P-Straight-Female-header_C27438.html
[8]: https://www.aliexpress.com/item/2036819167.html
[9]: https://www.aliexpress.com/item/32395357185.html
## Installing on Teensy LC
**NOTE:** This firmware is *only* written to work for the Teensy LC. Do *not* use Teensy 2.0 or Teensy 3.x
Skip this section if you are using a Pro Micro.
Locate your `arduino` folder (usually `C:\Program Files (x86)\arduino`).
#### I have a fresh install of Teensyduino, or have never modified my USB profiles
Copy `Firmware/Teensy/boards.txt` to `arduino\hardware\teensy\avr\` and overwrite the existing.
Copy `Firmware/Teensy/teensy3` to `arduino\hardware\teensy\avr\cores\teensy3` and overwrite any conflicts.
#### I am applying the changes manually
(It is easier to copy and paste from the files in `Firmware/Teensy` instead of through here, the below is just for reference.)
Add `usb_nkro.c` and `usb_nkro.h` to `arduino\hardware\teensy\avr\cores\teensy3`
In `arduino\hardware\teesny\avr\boards.txt` add lines 1175-1179
```c
1175 teensyLC.menu.usb.nkrokeyboard=NKRO Keyboard
1176 teensyLC.menu.usb.nkrokeyboard.build.usbtype=USB_NKRO
1177 teensyLC.menu.usb.nkrokeyboard.fake_serial=teensy_gateway
1178 teensyLC.menu.usb.serialnkrokeyboard=Serial + NKRO Keyboard
1179 teensyLC.menu.usb.serialnkrokeyboard.build.usbtype=USB_SERIAL_NKRO
In `arduino\hardware\teensy\avr\cores\teensy3\WProgram.h` add line 59
```c
58 #include "usb_joystick.h"
59 #include "usb_nkro.h"
60 #include "usb_midi.h"
```
In `arduino\hardware\teensy\avr\cores\teensy3\usb_inst.cpp` add lines 75-77
```c
72 usb_serial_class Serial;
73 #endif
74
75 #ifdef NKRO_INTERFACE
76 usb_nkro_class Nkro;
77 #endif
78
79 #else // F_CPU < 20 MHz
```
In `arduino\hardware\teensy\avr\cores\teensy3\usb_dev.h` add lines 93-98
```c
90 extern volatile uint8_t keyboard_leds;
91 #endif
92
93 #ifdef NKRO_INTERFACE
94 extern uint8_t nkro_report_data[NKRO_SIZE];
95 extern uint8_t nkro_protocol;
96 extern uint8_t nkro_idle_config;
97 extern uint8_t nkro_idle_count;
98 #endif
99
100 #ifdef MIDI_INTERFACE
```
In `arduino\hardware\teensy\avr\cores\teensy3\usb_desc.h` add lines 868-948
```c
866 #define ENDPOINT15_CONFIG ENDPOINT_TRANSMIT_ONLY
867
868 #elif defined(USB_NKRO)
869 #define VENDOR_ID 0x16C0
870 #define PRODUCT_ID 0x04D0
871 #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
872 #define MANUFACTURER_NAME_LEN 11
873 #define PRODUCT_NAME {'N','K','R','O',' ','K','e','y','b','o','a','r','d'}
874 #define PRODUCT_NAME_LEN 13
875 #define EP0_SIZE 64
876 #define NUM_ENDPOINTS 5
877 #define NUM_USB_BUFFERS 14
878 #define NUM_INTERFACE 4
879 #define SEREMU_INTERFACE 1 // Serial emulation
880 #define SEREMU_TX_ENDPOINT 1
881 #define SEREMU_TX_SIZE 64
882 #define SEREMU_TX_INTERVAL 1
883 #define SEREMU_RX_ENDPOINT 2
884 #define SEREMU_RX_SIZE 32
885 #define SEREMU_RX_INTERVAL 2
886 #define KEYBOARD_INTERFACE 0 // Keyboard
887 #define KEYBOARD_ENDPOINT 3
888 #define KEYBOARD_SIZE 8
889 #define KEYBOARD_INTERVAL 1
890 #define KEYMEDIA_INTERFACE 2 // Keyboard Media Keys
891 #define KEYMEDIA_ENDPOINT 4
892 #define KEYMEDIA_SIZE 8
893 #define KEYMEDIA_INTERVAL 4
894 #define NKRO_INTERFACE 3 // NKRO Keyboard
895 #define NKRO_ENDPOINT 5
896 #define NKRO_SIZE 32
897 #define NKRO_REPORT_KEYS ( NKRO_SIZE - 1 )
898 #define NKRO_INTERVAL 1
899 #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
900 #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
901 #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
902 #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
903 #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
904 #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY
905
906 #elif defined(USB_SERIAL_NKRO)
907 #define VENDOR_ID 0x16C0
908 #define PRODUCT_ID 0x0487
909 #define DEVICE_CLASS 0xEF
910 #define DEVICE_SUBCLASS 0x02
911 #define DEVICE_PROTOCOL 0x01
912 #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
913 #define MANUFACTURER_NAME_LEN 11
914 #define PRODUCT_NAME {'S','e','r','i','a','l','/','N','K','R','O',' ','K','e','y','b','o','a','r','d'}
915 #define PRODUCT_NAME_LEN 20
916 #define EP0_SIZE 64
917 #define NUM_ENDPOINTS 6
918 #define NUM_USB_BUFFERS 14
919 #define NUM_INTERFACE 5
920 #define CDC_IAD_DESCRIPTOR 1
921 #define CDC_STATUS_INTERFACE 0
922 #define CDC_DATA_INTERFACE 1 // Serial
923 #define CDC_ACM_ENDPOINT 2
924 #define CDC_RX_ENDPOINT 3
925 #define CDC_TX_ENDPOINT 4
926 #define CDC_ACM_SIZE 16
927 #define CDC_RX_SIZE 64
928 #define CDC_TX_SIZE 64
929 #define KEYBOARD_INTERFACE 2 // Keyboard
930 #define KEYBOARD_ENDPOINT 1
931 #define KEYBOARD_SIZE 8
932 #define KEYBOARD_INTERVAL 1
933 #define KEYMEDIA_INTERFACE 3 // Keyboard Media Keys
934 #define KEYMEDIA_ENDPOINT 5
935 #define KEYMEDIA_SIZE 8
936 #define KEYMEDIA_INTERVAL 4
937 #define NKRO_INTERFACE 4 // NKRO Keyboard
938 #define NKRO_ENDPOINT 6
939 #define NKRO_SIZE 32
940 #define NKRO_REPORT_KEYS ( NKRO_SIZE - 1 )
941 #define NKRO_INTERVAL 1
942 #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
943 #define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY
944 #define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY
945 #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
946 #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
947 #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY
948 #endif
949
950 #ifdef USB_DESC_LIST_DEFINE
```
In `arduino\hardware\teensy\avr\cores\teensy3\usb_desc.c` add lines 239-265
```c
236 };
237 #endif
238
239 #ifdef NKRO_INTERFACE
240 // Via https://dawnmist.dreamwidth.org/1250.html
241 static uint8_t nkro_hid_report_desc[] = {
242 0x05, 0x01, // Usage Page (Generic Desktop),
243 0x09, 0x06, // Usage (Keyboard),
244 0xA1, 0x01, // Collection (Application),
245 // bitmap of modifiers
246 0x75, 0x01, // Report Size (1),
247 0x95, 0x08, // Report Count (8),
248 0x05, 0x07, // Usage Page (Key Codes),
249 0x19, 0xE0, // Usage Minimum (224),
250 0x29, 0xE7, // Usage Maximum (231),
251 0x15, 0x00, // Logical Minimum (0),
252 0x25, 0x01, // Logical Maximum (1),
253 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
254 // bitmap of keys
255 0x95, NKRO_REPORT_KEYS*8, // Report Count (),
256 0x75, 0x01, // Report Size (1),
257 0x15, 0x00, // Logical Minimum (0),
258 0x25, 0x01, // Logical Maximum(1),
259 0x05, 0x07, // Usage Page (Key Codes),
260 0x19, 0x00, // Usage Minimum (0),
261 0x29, NKRO_REPORT_KEYS*8-1, // Usage Maximum (),
262 0x81, 0x02, // Input (Data, Variable, Absolute),
263 0xc0 // End Collection
264 };
265 #endif
266
267 #ifdef JOYSTICK_INTERFACE
268 #if JOYSTICK_SIZE == 12
```
In `arduino\hardware\teensy\avr\cores\teensy3\usb_desc.c` add lines 603-610 and modify line 612
```c
600 #define MULTITOUCH_INTERFACE_DESC_SIZE 0
601 #endif
602
603 // Via https://dawnmist.dreamwidth.org/1250.html
604 #define NKRO_INTERFACE_DESC_POS MULTITOUCH_INTERFACE_DESC_POS+MULTITOUCH_INTERFACE_DESC_SIZE
605 #ifdef NKRO_INTERFACE
606 #define NKRO_INTERFACE_DESC_SIZE 9+9+7
607 #define NKRO_HID_DESC_OFFSET NKRO_INTERFACE_DESC_POS+9
608 #else
609 #define NKRO_INTERFACE_DESC_SIZE 0
610 #endif
611
612 #define CONFIG_DESC_SIZE NKRO_INTERFACE_DESC_POS+NKRO_INTERFACE_DESC_SIZE
613
614
615
616 // **************************************************************
```
In `arduino\hardware\teensy\avr\cores\teensy3\usb_desc.c` add lines 1131-1158
```c
1129 #endif // JOYSTICK_INTERFACE
1130
1131 #ifdef NKRO_INTERFACE
1132 // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
1133 9, // bLength
1134 4, // bDescriptorType
1135 NKRO_INTERFACE, // bInterfaceNumber
1136 0, // bAlternateSetting
1137 1, // bNumEndpoints
1138 0x03, // bInterfaceClass (0x03 = HID)
1139 0x00, // bInterfaceSubClass (0x01 = Boot)
1140 0x00, // bInterfaceProtocol (0x01 = Keyboard)
1141 0, // iInterface
1142 // HID interface descriptor, HID 1.11 spec, section 6.2.1
1143 9, // bLength
1144 0x21, // bDescriptorType
1145 0x11, 0x01, // bcdHID
1146 0, // bCountryCode
1147 1, // bNumDescriptors
1148 0x22, // bDescriptorType
1149 LSB(sizeof(nkro_hid_report_desc)), // wDescriptorLength
1150 MSB(sizeof(nkro_hid_report_desc)),
1151 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
1152 7, // bLength
1153 5, // bDescriptorType
1154 NKRO_ENDPOINT | 0x80, // bEndpointAddress
1155 0x03, // bmAttributes (0x03=intr)
1156 NKRO_SIZE, 0, // wMaxPacketSize
1157 NKRO_INTERVAL, // bInterval
1158 #endif // NKRO_INTERFACE
1159
1160 #ifdef MTP_INTERFACE
```
In `arduino\hardware\teensy\avr\cores\teensy3\usb_desc.c` add lines 1602-1605
```c
1600 {0x2100, MULTITOUCH_INTERFACE, config_descriptor+MULTITOUCH_HID_DESC_OFFSET, 9},
1601 #endif
1602 #ifdef NKRO_INTERFACE
1603 {0x2200, NKRO_INTERFACE, nkro_hid_report_desc, sizeof(nkro_hid_report_desc)},
1604 {0x2100, NKRO_INTERFACE, config_descriptor+NKRO_HID_DESC_OFFSET, 9},
1605 #endif
1606 #ifdef MTP_INTERFACE
```
In `arduino\hardware\teensy\avr\boards.txt` add lines 1175-1177
```
1174 teensyLC.menu.usb.flightsim.fake_serial=teensy_gateway
1175 teensyLC.menu.usb.nkrokeyboard=NKRO Keyboard
1176 teensyLC.menu.usb.nkrokeyboard.build.usbtype=USB_NKRO
1177 teensyLC.menu.usb.nkrokeyboard.fake_serial=teensy_gateway
1178 teensyLC.menu.usb.disable=No USB
```
## Configuring the Firmware and IDE
There are a number of options built into the firmware to give you flexibility in your implementation. These are presented as preprocessor defines that can be commented and uncommented to fit.
All user-editable defines are in `Config.h`, see the comments for additional information.
If you are not using either the Pro Micro or Teensy LC boards provided in this repo, it may be necessary to change the definitions of the pins, located in `PinConfig.h`.
If you do not have the FastLED and HID-Project libraries installed, do so though the `Tools->Manage Libraries` menu.
#### Compiling
When using a Pro Micro, select `Arduino/Genuino Micro` from `Tools->Board`.
When using a Teensy LC, select `Teensy LC` from `Tools->Board`, then select `NKRO Keyboard` from `Tools->USB Type` for reactive lights. If you are using serial light updates, select `Serial + NKRO Keyboard`.
Prior to compilation, review the (numerous) options available to the end user in `Config.h`. Comment and uncomment the corresponding options that match your setup.
## Running the Software
#### Configuring
Before use, the controller will need a few parameters set. This can easily be done using the Arduino Serial Monitor.
The exact settings will vary depending on your setup, but I would try these as a starting point:
```
tt50
td50
ta0.05
```
Use the command `g` to confirm your changes registered.
**NOTE:** Serial configuration will not work with serial lights. Disable this feature to allow for configuration.
Per WinEpic:
The touch detection system uses an exponential moving average (EMA) to detect changes in the read value. You need to tune 3 values: deadzone, threshold and alpha.
- **Deadzone** is the maximum value for which a key will be considered "untouched". If the read value ever falls below the deadzone value, the key will return to being untouched. The higher this value, the "harder" you need to push the key before it is considered an input, and the faster it will return to neutral once you start lifting your finger.
- **Threshold** is how large the different between the detected input and the EMA must be for a touch event to occur. It is used for single touches as a way to prevent accidental double inputs, and for double touches to detect them. Increasing it makes the controller less responsive and increases the risk of touches not registering. Decreasing it makes fake inputs more likely, and also makes it harder for the controller to detect multitouch.
- **Alpha** is how much weight the last readout has in the EMA. It is usually very close to 0. If it is too high, inputs won't register as they will be considered too similar to the moving average. If it is too low, the moving average won't update properly causing touches / double touches to not be detected properly.
Threshold and Deadzone values are expressed relative to the calibration baseline. For example, If a key reads 80 untouched and 100 touched, you're gonna want to set your deadzone to something around 15-20. Start with Alpha at 0.001 and slowly go up from there.
You can configure it using commands sent over the serial port. All changes, aside from recalibrating, apply immediately and persist after restarting.
- `tt <value>` changes the threshold.
- `td <value>` changes the deadzone.
- `ta <value>` changes the alpha.
- `tc` forces the controller to recalibrate, if you moved it to a different environment or accidentally touched it during initial calibration.
- `g` prints out the current configuration values.
When tuning, you want to increase alpha until it feels like you're missing inputs, then go back down.
#### Power On
At startup, the LEDs will flash orange 3 times. Do not hold your hands near the touchboard at this time. When the touchboard turns red, calibration begins. After the touchboard turns blue, calibration has finished.
#### Output
By default, the program will run in NKRO Keyboard mode. The specific keyboard keys are set in `USBOutput.cpp`, but are listed here in order of left to right:
```
a z s x d c f v g b h n j m k ,
```
When a second finger touches the pad, the following keys are pressed in order of left to right
```
1 q 2 w 3 e 4 r 5 t 6 y 7 u 8 i
```
By default, the air sensor functions as follows:
- `Home` is held as long as any sensor is triggered and released when there are no sensors triggered.
- `End` is pressed when any motion is detected, as long as the hand was previously in front of the sensors.
- `Page Up` is pressed and released when the sensor detections movement upwards.
- `Page Down` is pressed and released when the sensor detections movement downwards.
If `#define IR_SENSOR_KEY` is uncommented, each air sensor will report back individually. The default binding from bottom to top is:
```
/ . ' ; ] [
```
Per US QWERTY layout.