diff --git a/doc/quick-tech-report/circuits.ipynb b/doc/quick-tech-report/circuits.ipynb
new file mode 100644
index 0000000..2e78b30
--- /dev/null
+++ b/doc/quick-tech-report/circuits.ipynb
@@ -0,0 +1,1115 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import schemdraw\n",
+ "from schemdraw import elements as elm"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 123,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ "<__main__.DiodeOptocoupler at 0x7ff215993c70>"
+ ]
+ },
+ "execution_count": 123,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "class DiodeOptocoupler(schemdraw.elements.compound.ElementCompound):\n",
+ " def __init__(self, *args, **kwargs):\n",
+ " unit = 1.5\n",
+ " super().__init__(*args, unit=unit, **kwargs)\n",
+ "\n",
+ " box = kwargs.get('box', True)\n",
+ " boxfill = kwargs.get('boxfill', False)\n",
+ " bpad = kwargs.get('boxpad', .2)\n",
+ " label1, label2 = kwargs.get('label1'), kwargs.get('label2')\n",
+ " rev1, rev2 = kwargs.get('reverse1', False), kwargs.get('reverse2', False)\n",
+ "\n",
+ " D1 = self.add(elm.Diode(d='down', reverse=rev1))\n",
+ " D2 = self.add(elm.Diode(d='down', reverse=rev2, at=[2, 0]))\n",
+ " if label1:\n",
+ " self.segments.append(schemdraw.segments.SegmentText(D1.start + (0, 0.5), label1))\n",
+ " if label2:\n",
+ " self.segments.append(schemdraw.segments.SegmentText(D2.start + (0, 0.5), label2))\n",
+ " \n",
+ " self.add(elm.Arrow('r', at=[.6, -unit/2 + .2], l=.4, headwidth=.15, headlength=.4))\n",
+ " self.add(elm.Arrow('r', at=[.6, -unit/2 - .2], l=.4, headwidth=.15, headlength=.4))\n",
+ "\n",
+ " bbox = self.get_bbox()\n",
+ " if box:\n",
+ " self.add(elm.Rect(\n",
+ " 'r', at=[0, 0],\n",
+ " corner1=[bbox.xmin-bpad, bbox.ymin-bpad],\n",
+ " corner2=[bbox.xmax+bpad, bbox.ymax+bpad],\n",
+ " fill=boxfill, zorder=0))\n",
+ "\n",
+ " A = self.add(elm.Line('r', at=D2.start, l=bpad*2))\n",
+ " B = self.add(elm.Line('r', at=D2.end, l=bpad*2))\n",
+ " C = self.add(elm.Line('l', at=D1.start, tox=bbox.xmin-bpad))\n",
+ " D = self.add(elm.Line('l', at=D1.end, tox=bbox.xmin-bpad))\n",
+ " self.anchors['anode1'] = C.end\n",
+ " self.anchors['cathode1'] = D.end\n",
+ " self.anchors['anode2'] = B.end\n",
+ " self.anchors['cathode2'] = A.end\n",
+ "DiodeOptocoupler(box=False, reverse2=True, label2='D2')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 177,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 177,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "d = schemdraw.Drawing()\n",
+ "V1 = d.add(elm.SourceV(label='5V'))\n",
+ "d.add(elm.Line(d='right', l=d.unit*2))\n",
+ "d.add(elm.Resistor(d='down', label='R1'))\n",
+ "coupler = d.add(DiodeOptocoupler(d='right', box=False, label1='D1', label2='D2', anchor='anode1', reverse2=True))\n",
+ "d.here = coupler.cathode1\n",
+ "Q1 = d.add(elm.BjtNpn(d='right', anchor='collector', label='Q1'))\n",
+ "d.add(elm.Line(xy=Q1.emitter, d='down', l=d.unit*0.25))\n",
+ "d.add(elm.Line(d='left', tox=V1.start))\n",
+ "d.add(elm.Line(d='up', toy=V1.start))\n",
+ "d.add(elm.Resistor(xy=Q1.base, d='left', label='R2'))\n",
+ "d.add(elm.Dot(open=True, lftlabel='TX in'))\n",
+ "\n",
+ "d.add(elm.Line(xy=coupler.cathode2, d='up', toy=V1.end + d.unit*0.5))\n",
+ "vbus = d.add(elm.Line(d='right', l=d.unit*5))\n",
+ "\n",
+ "d.add(elm.Line(xy=coupler.anode2, d='right', l=d.unit*0.5))\n",
+ "j1 = d.add(elm.Dot())\n",
+ "d.add(elm.Line(l=d.unit*0.5))\n",
+ "amp1 = d.add(elm.Opamp(d='right', anchor='in1'))\n",
+ "\n",
+ "d.add(elm.Line(xy=j1.xy, d='up', l=d.unit))\n",
+ "j2 = d.add(elm.Dot())\n",
+ "\n",
+ "d.add(elm.Resistor(label='R3', d='right'))\n",
+ "d.add(elm.Line(l=d.unit*0.5))\n",
+ "j3 = d.add(elm.Dot())\n",
+ "d.add(elm.Line(d='down', toy=amp1.out))\n",
+ "j4 = d.add(elm.Dot())\n",
+ "d.add(elm.Line('left', tox=amp1.out))\n",
+ "\n",
+ "d.add(elm.Line('up', xy=j2.xy, l=d.unit*0.5))\n",
+ "d.add(elm.Capacitor(label='C1', d='right'))\n",
+ "d.add(elm.Line(tox=j3.xy))\n",
+ "d.add(elm.Line(d='down', toy=j3.xy))\n",
+ "\n",
+ "d.add(elm.Line(d='left', xy=amp1.in2, l=d.unit*0.2))\n",
+ "d.add(elm.Line(d='down', l=d.unit*0.5))\n",
+ "vgnd_bus = d.add(elm.Line(d='right', l=d.unit*5))\n",
+ "\n",
+ "d.draw()"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/doc/quick-tech-report/ir_tx_schema.pdf b/doc/quick-tech-report/ir_tx_schema.pdf
new file mode 100644
index 0000000..0e44ca5
Binary files /dev/null and b/doc/quick-tech-report/ir_tx_schema.pdf differ
diff --git a/doc/quick-tech-report/ir_tx_schema.svg b/doc/quick-tech-report/ir_tx_schema.svg
new file mode 100644
index 0000000..5d54c2b
--- /dev/null
+++ b/doc/quick-tech-report/ir_tx_schema.svg
@@ -0,0 +1,340 @@
+
+
diff --git a/doc/quick-tech-report/mesh_gen_viz.pdf b/doc/quick-tech-report/mesh_gen_viz.pdf
new file mode 100644
index 0000000..7ded2fc
Binary files /dev/null and b/doc/quick-tech-report/mesh_gen_viz.pdf differ
diff --git a/doc/quick-tech-report/mesh_gen_viz.svg b/doc/quick-tech-report/mesh_gen_viz.svg
new file mode 100644
index 0000000..59a31b9
--- /dev/null
+++ b/doc/quick-tech-report/mesh_gen_viz.svg
@@ -0,0 +1,1547 @@
+
+
diff --git a/doc/quick-tech-report/mesh_scan_crop.jpg b/doc/quick-tech-report/mesh_scan_crop.jpg
new file mode 100644
index 0000000..baa8e6c
Binary files /dev/null and b/doc/quick-tech-report/mesh_scan_crop.jpg differ
diff --git a/doc/quick-tech-report/photolink_schematic.pdf b/doc/quick-tech-report/photolink_schematic.pdf
new file mode 100644
index 0000000..3284427
Binary files /dev/null and b/doc/quick-tech-report/photolink_schematic.pdf differ
diff --git a/doc/quick-tech-report/photolink_schematic.pro b/doc/quick-tech-report/photolink_schematic.pro
new file mode 100644
index 0000000..02a2ddf
--- /dev/null
+++ b/doc/quick-tech-report/photolink_schematic.pro
@@ -0,0 +1,43 @@
+update=Tue Dec 1 17:26:36 2020
+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
diff --git a/doc/quick-tech-report/photolink_schematic.sch b/doc/quick-tech-report/photolink_schematic.sch
new file mode 100644
index 0000000..b5c6a64
--- /dev/null
+++ b/doc/quick-tech-report/photolink_schematic.sch
@@ -0,0 +1,486 @@
+EESchema Schematic File Version 4
+EELAYER 30 0
+EELAYER END
+$Descr A4 11693 8268
+encoding utf-8
+Sheet 1 1
+Title ""
+Date ""
+Rev ""
+Comp ""
+Comment1 ""
+Comment2 ""
+Comment3 ""
+Comment4 ""
+$EndDescr
+$Comp
+L Transistor_BJT:BC847 Q1
+U 1 1 5FC67B72
+P 3450 3300
+F 0 "Q1" H 3641 3300 50 0000 L CNN
+F 1 "BC847" H 3641 3255 50 0001 L CNN
+F 2 "Package_TO_SOT_SMD:SOT-23" H 3650 3225 50 0001 L CIN
+F 3 "http://www.infineon.com/dgdl/Infineon-BC847SERIES_BC848SERIES_BC849SERIES_BC850SERIES-DS-v01_01-en.pdf?fileId=db3a304314dca389011541d4630a1657" H 3450 3300 50 0001 L CNN
+ 1 3450 3300
+ 1 0 0 -1
+$EndComp
+$Comp
+L Device:R_Small R1
+U 1 1 5FC6861A
+P 3050 3300
+F 0 "R1" V 3246 3300 50 0000 C CNN
+F 1 "R_Small" V 3155 3300 50 0000 C CNN
+F 2 "" H 3050 3300 50 0001 C CNN
+F 3 "~" H 3050 3300 50 0001 C CNN
+ 1 3050 3300
+ 0 -1 -1 0
+$EndComp
+Wire Wire Line
+ 4750 3050 4600 3050
+Wire Wire Line
+ 3550 2950 3550 3100
+Wire Wire Line
+ 3150 3300 3250 3300
+$Comp
+L power:GND1 #PWR02
+U 1 1 5FC74679
+P 3550 3500
+F 0 "#PWR02" H 3550 3250 50 0001 C CNN
+F 1 "GND1" H 3555 3327 50 0000 C CNN
+F 2 "" H 3550 3500 50 0001 C CNN
+F 3 "" H 3550 3500 50 0001 C CNN
+ 1 3550 3500
+ 1 0 0 -1
+$EndComp
+Wire Wire Line
+ 4750 3250 4650 3250
+Wire Wire Line
+ 4600 3050 4600 2650
+Wire Wire Line
+ 4600 2650 4900 2650
+Connection ~ 4600 3050
+Wire Wire Line
+ 4900 2300 4600 2300
+Wire Wire Line
+ 4600 2300 4600 2650
+Connection ~ 4600 2650
+Text GLabel 9150 3350 2 50 Input ~ 0
+RX_OUT
+Text GLabel 2850 3300 0 50 Input ~ 0
+TX_IN
+Wire Wire Line
+ 2850 3300 2950 3300
+$Comp
+L power:+3V3 #PWR01
+U 1 1 5FC80852
+P 3550 2150
+F 0 "#PWR01" H 3550 2000 50 0001 C CNN
+F 1 "+3V3" H 3565 2323 50 0000 C CNN
+F 2 "" H 3550 2150 50 0001 C CNN
+F 3 "" H 3550 2150 50 0001 C CNN
+ 1 3550 2150
+ 1 0 0 -1
+$EndComp
+$Comp
+L Device:Opamp_Quad_Generic U1
+U 4 1 5FC81BCB
+P 5250 4650
+F 0 "U1" H 5250 4375 50 0000 C CNN
+F 1 "MCP6494" H 5250 4374 50 0001 C CNN
+F 2 "" H 5250 4650 50 0001 C CNN
+F 3 "~" H 5250 4650 50 0001 C CNN
+ 4 5250 4650
+ 1 0 0 1
+$EndComp
+$Comp
+L Device:R R2
+U 1 1 5FC87551
+P 3550 2400
+F 0 "R2" H 3620 2400 50 0000 L CNN
+F 1 "R" H 3620 2355 50 0001 L CNN
+F 2 "" V 3480 2400 50 0001 C CNN
+F 3 "~" H 3550 2400 50 0001 C CNN
+ 1 3550 2400
+ 1 0 0 -1
+$EndComp
+$Comp
+L Device:Opamp_Quad_Generic U1
+U 2 1 5FC77130
+P 7200 3250
+F 0 "U1" H 7200 2975 50 0000 C CNN
+F 1 "MCP6494" H 7200 2974 50 0001 C CNN
+F 2 "" H 7200 3250 50 0001 C CNN
+F 3 "~" H 7200 3250 50 0001 C CNN
+ 2 7200 3250
+ 1 0 0 1
+$EndComp
+$Comp
+L Device:Opamp_Quad_Generic U1
+U 1 1 5FC6A2B7
+P 5050 3150
+F 0 "U1" H 5050 2783 50 0000 C CNN
+F 1 "MCP6494" H 5050 2874 50 0000 C CNN
+F 2 "" H 5050 3150 50 0001 C CNN
+F 3 "~" H 5050 3150 50 0001 C CNN
+ 1 5050 3150
+ 1 0 0 1
+$EndComp
+Wire Wire Line
+ 7500 3250 7600 3250
+Wire Wire Line
+ 3550 2250 3550 2150
+$Comp
+L Device:D_ALT LED1
+U 1 1 5FC90B25
+P 3550 2800
+F 0 "LED1" V 3550 3100 50 0000 R CNN
+F 1 "D_ALT" V 3505 2720 50 0001 R CNN
+F 2 "" H 3550 2800 50 0001 C CNN
+F 3 "~" H 3550 2800 50 0001 C CNN
+ 1 3550 2800
+ 0 -1 -1 0
+$EndComp
+Wire Wire Line
+ 3550 2550 3550 2650
+$Comp
+L Device:D_ALT PD1
+U 1 1 5FC93B60
+P 4150 2800
+F 0 "PD1" V 4150 2880 50 0000 L CNN
+F 1 "D_ALT" V 4105 2720 50 0001 R CNN
+F 2 "" H 4150 2800 50 0001 C CNN
+F 3 "~" H 4150 2800 50 0001 C CNN
+ 1 4150 2800
+ 0 1 1 0
+$EndComp
+Wire Wire Line
+ 4150 3050 4150 2950
+Wire Wire Line
+ 4150 3050 4600 3050
+$Comp
+L Device:R R3
+U 1 1 5FC9B279
+P 4350 4500
+F 0 "R3" H 4420 4500 50 0000 L CNN
+F 1 "R" H 4420 4455 50 0001 L CNN
+F 2 "" V 4280 4500 50 0001 C CNN
+F 3 "~" H 4350 4500 50 0001 C CNN
+ 1 4350 4500
+ 1 0 0 -1
+$EndComp
+$Comp
+L Device:R R4
+U 1 1 5FC9B8DC
+P 4350 5000
+F 0 "R4" H 4420 5000 50 0000 L CNN
+F 1 "R" H 4420 4955 50 0001 L CNN
+F 2 "" V 4280 5000 50 0001 C CNN
+F 3 "~" H 4350 5000 50 0001 C CNN
+ 1 4350 5000
+ 1 0 0 -1
+$EndComp
+$Comp
+L Device:C C1
+U 1 1 5FC9BF27
+P 4650 5000
+F 0 "C1" H 4765 5000 50 0000 L CNN
+F 1 "C" H 4765 4955 50 0001 L CNN
+F 2 "" H 4688 4850 50 0001 C CNN
+F 3 "~" H 4650 5000 50 0001 C CNN
+ 1 4650 5000
+ 1 0 0 -1
+$EndComp
+Wire Wire Line
+ 4350 4650 4350 4750
+Wire Wire Line
+ 4350 4750 4650 4750
+Wire Wire Line
+ 4650 4750 4650 4850
+Connection ~ 4350 4750
+Wire Wire Line
+ 4350 4750 4350 4850
+$Comp
+L power:GND2 #PWR05
+U 1 1 5FC9F5E3
+P 4350 5300
+F 0 "#PWR05" H 4350 5050 50 0001 C CNN
+F 1 "GND2" H 4355 5127 50 0000 C CNN
+F 2 "" H 4350 5300 50 0001 C CNN
+F 3 "" H 4350 5300 50 0001 C CNN
+ 1 4350 5300
+ 1 0 0 -1
+$EndComp
+Wire Wire Line
+ 4350 5300 4350 5250
+Wire Wire Line
+ 4650 5150 4650 5250
+Wire Wire Line
+ 4650 5250 4350 5250
+Connection ~ 4350 5250
+Wire Wire Line
+ 4350 5250 4350 5150
+$Comp
+L power:+3V0 #PWR04
+U 1 1 5FCA206B
+P 4350 4250
+F 0 "#PWR04" H 4350 4100 50 0001 C CNN
+F 1 "+3V0" H 4365 4423 50 0000 C CNN
+F 2 "" H 4350 4250 50 0001 C CNN
+F 3 "" H 4350 4250 50 0001 C CNN
+ 1 4350 4250
+ 1 0 0 -1
+$EndComp
+Wire Wire Line
+ 4350 4250 4350 4350
+Wire Wire Line
+ 4950 4750 4650 4750
+Connection ~ 4650 4750
+Wire Wire Line
+ 4950 4550 4800 4550
+Wire Wire Line
+ 4800 4550 4800 4150
+Wire Wire Line
+ 4800 4150 5700 4150
+Wire Wire Line
+ 5700 4150 5700 4650
+Wire Wire Line
+ 5700 4650 5550 4650
+Connection ~ 5700 4650
+$Comp
+L Device:R R5
+U 1 1 5FCB3FD4
+P 5050 2650
+F 0 "R5" V 4843 2650 50 0000 C CNN
+F 1 "100k" V 4934 2650 50 0000 C CNN
+F 2 "" V 4980 2650 50 0001 C CNN
+F 3 "~" H 5050 2650 50 0001 C CNN
+ 1 5050 2650
+ 0 1 1 0
+$EndComp
+$Comp
+L Device:C C2
+U 1 1 5FCB45E4
+P 5050 2300
+F 0 "C2" V 5302 2300 50 0000 C CNN
+F 1 "7p" V 5211 2300 50 0000 C CNN
+F 2 "" H 5088 2150 50 0001 C CNN
+F 3 "~" H 5050 2300 50 0001 C CNN
+ 1 5050 2300
+ 0 -1 -1 0
+$EndComp
+Wire Wire Line
+ 5200 2300 5500 2300
+Wire Wire Line
+ 5500 2300 5500 2650
+Wire Wire Line
+ 5500 3150 5350 3150
+$Comp
+L Device:R R6
+U 1 1 5FCB92E2
+P 6150 3150
+F 0 "R6" V 5943 3150 50 0000 C CNN
+F 1 "1k" V 6034 3150 50 0000 C CNN
+F 2 "" V 6080 3150 50 0001 C CNN
+F 3 "~" H 6150 3150 50 0001 C CNN
+ 1 6150 3150
+ 0 1 1 0
+$EndComp
+$Comp
+L Device:R R7
+U 1 1 5FCB995A
+P 7200 2700
+F 0 "R7" V 6993 2700 50 0000 C CNN
+F 1 "100k" V 7084 2700 50 0000 C CNN
+F 2 "" V 7130 2700 50 0001 C CNN
+F 3 "~" H 7200 2700 50 0001 C CNN
+ 1 7200 2700
+ 0 1 1 0
+$EndComp
+Wire Wire Line
+ 5600 3150 5500 3150
+Connection ~ 5500 3150
+Wire Wire Line
+ 7350 2700 7600 2700
+Wire Wire Line
+ 7600 2700 7600 3250
+Wire Wire Line
+ 9150 3350 9050 3350
+Wire Wire Line
+ 5200 2650 5500 2650
+Connection ~ 5500 2650
+Wire Wire Line
+ 5500 2650 5500 3150
+$Comp
+L power:+3V0 #PWR03
+U 1 1 5FCC0528
+P 4150 2150
+F 0 "#PWR03" H 4150 2000 50 0001 C CNN
+F 1 "+3V0" H 4165 2323 50 0000 C CNN
+F 2 "" H 4150 2150 50 0001 C CNN
+F 3 "" H 4150 2150 50 0001 C CNN
+ 1 4150 2150
+ 1 0 0 -1
+$EndComp
+Wire Wire Line
+ 4150 2150 4150 2650
+$Comp
+L Graphic:SYM_Arrow_Normal #SYM1
+U 1 1 5FCC452D
+P 3850 2775
+F 0 "#SYM1" H 3850 2835 50 0001 C CNN
+F 1 "SYM_Arrow_Normal" H 3860 2725 50 0001 C CNN
+F 2 "" H 3850 2775 50 0001 C CNN
+F 3 "~" H 3850 2775 50 0001 C CNN
+ 1 3850 2775
+ 1 0 0 -1
+$EndComp
+$Comp
+L Graphic:SYM_Arrow_Normal #SYM2
+U 1 1 5FCC5099
+P 3850 2850
+F 0 "#SYM2" H 3850 2910 50 0001 C CNN
+F 1 "SYM_Arrow_Normal" H 3860 2800 50 0001 C CNN
+F 2 "" H 3850 2850 50 0001 C CNN
+F 3 "~" H 3850 2850 50 0001 C CNN
+ 1 3850 2850
+ 1 0 0 -1
+$EndComp
+Wire Notes Line
+ 3200 3000 4450 3000
+Wire Notes Line
+ 4450 3000 4450 2600
+Wire Notes Line
+ 4450 2600 3200 2600
+Wire Notes Line
+ 3200 2600 3200 3000
+Text Notes 2900 2700 0 50 ~ 0
+IR link
+Wire Wire Line
+ 4650 3750 5950 3750
+Wire Wire Line
+ 5950 4650 5950 3750
+Wire Wire Line
+ 5700 4650 5950 4650
+Wire Notes Line
+ 3850 1550 3850 5700
+Text Notes 3750 1750 2 100 ~ 0
+Stator
+Text Notes 3950 1750 0 100 ~ 0
+Rotor
+Text Label 5650 3750 2 50 ~ 0
+VGND
+Text Notes 5300 1950 2 50 ~ 0
+TIA G=100kΩ
+Text Notes 7500 2350 2 50 ~ 0
+Amplifier G=100
+Text Notes 8950 2900 2 50 ~ 0
+Comparator
+Text Notes 5650 4000 2 50 ~ 0
+Virtual Ground Buffer
+$Comp
+L Device:C C3
+U 1 1 5FC76733
+P 5750 3150
+F 0 "C3" V 5900 3150 50 0000 C CNN
+F 1 "7p" V 5911 3150 50 0001 C CNN
+F 2 "" H 5788 3000 50 0001 C CNN
+F 3 "~" H 5750 3150 50 0001 C CNN
+ 1 5750 3150
+ 0 1 1 0
+$EndComp
+Wire Wire Line
+ 6650 3350 6650 3750
+Wire Wire Line
+ 6650 3350 6900 3350
+Connection ~ 6650 3750
+$Comp
+L Device:Opamp_Quad_Generic U1
+U 3 1 5FC7A609
+P 8750 3350
+F 0 "U1" H 8750 3075 50 0000 C CNN
+F 1 "MCP6494" H 8750 3074 50 0001 C CNN
+F 2 "" H 8750 3350 50 0001 C CNN
+F 3 "~" H 8750 3350 50 0001 C CNN
+ 3 8750 3350
+ 1 0 0 1
+$EndComp
+$Comp
+L Device:C C4
+U 1 1 5FC8AF8D
+P 7850 3250
+F 0 "C4" V 8102 3250 50 0000 C CNN
+F 1 "7p" V 8011 3250 50 0001 C CNN
+F 2 "" H 7888 3100 50 0001 C CNN
+F 3 "~" H 7850 3250 50 0001 C CNN
+ 1 7850 3250
+ 0 1 1 0
+$EndComp
+$Comp
+L Device:R R8
+U 1 1 5FC9BACD
+P 6400 3400
+F 0 "R8" V 6300 3400 50 0000 C CNN
+F 1 "1k" V 6284 3400 50 0001 C CNN
+F 2 "" V 6330 3400 50 0001 C CNN
+F 3 "~" H 6400 3400 50 0001 C CNN
+ 1 6400 3400
+ -1 0 0 1
+$EndComp
+Wire Wire Line
+ 5950 3750 6400 3750
+Connection ~ 5950 3750
+Wire Wire Line
+ 6400 3550 6400 3750
+Connection ~ 6400 3750
+Wire Wire Line
+ 6400 3750 6650 3750
+Wire Wire Line
+ 6300 3150 6400 3150
+Wire Wire Line
+ 6400 3250 6400 3150
+Wire Wire Line
+ 6400 2700 7050 2700
+Connection ~ 6400 3150
+Wire Wire Line
+ 6400 3150 6900 3150
+Wire Wire Line
+ 6400 3150 6400 2700
+Wire Wire Line
+ 6000 3150 5900 3150
+$Comp
+L Device:R R9
+U 1 1 5FCAEC24
+P 8100 3500
+F 0 "R9" V 8000 3500 50 0000 C CNN
+F 1 "100k" V 7984 3500 50 0001 C CNN
+F 2 "" V 8030 3500 50 0001 C CNN
+F 3 "~" H 8100 3500 50 0001 C CNN
+ 1 8100 3500
+ -1 0 0 1
+$EndComp
+Wire Wire Line
+ 7600 3250 7700 3250
+Connection ~ 7600 3250
+Wire Wire Line
+ 8450 3450 8350 3450
+Wire Wire Line
+ 8000 3250 8100 3250
+Wire Wire Line
+ 6650 3750 8100 3750
+Wire Wire Line
+ 8350 3450 8350 3750
+Wire Wire Line
+ 8100 3350 8100 3250
+Connection ~ 8100 3250
+Wire Wire Line
+ 8100 3250 8450 3250
+Connection ~ 8100 3750
+Wire Wire Line
+ 8100 3750 8350 3750
+Wire Wire Line
+ 8100 3650 8100 3750
+Wire Wire Line
+ 4650 3250 4650 3750
+Text Notes 5700 3750 0 50 ~ 0
+1/2 VCC = 1.5V
+$EndSCHEMATC
diff --git a/doc/quick-tech-report/photolink_schematic.svg b/doc/quick-tech-report/photolink_schematic.svg
new file mode 100644
index 0000000..a24a7ec
--- /dev/null
+++ b/doc/quick-tech-report/photolink_schematic.svg
@@ -0,0 +1,3246 @@
+
+
diff --git a/doc/quick-tech-report/proto_3d_design.jpg b/doc/quick-tech-report/proto_3d_design.jpg
new file mode 100644
index 0000000..f527828
Binary files /dev/null and b/doc/quick-tech-report/proto_3d_design.jpg differ
diff --git a/doc/quick-tech-report/prototype_early_comms_small.jpg b/doc/quick-tech-report/prototype_early_comms_small.jpg
new file mode 100644
index 0000000..506da48
Binary files /dev/null and b/doc/quick-tech-report/prototype_early_comms_small.jpg differ
diff --git a/doc/quick-tech-report/rotohsm_tech_report.pdf b/doc/quick-tech-report/rotohsm_tech_report.pdf
new file mode 100644
index 0000000..a7d2162
Binary files /dev/null and b/doc/quick-tech-report/rotohsm_tech_report.pdf differ
diff --git a/doc/quick-tech-report/rotohsm_tech_report.tex b/doc/quick-tech-report/rotohsm_tech_report.tex
index 76b5d8f..bf51a87 100644
--- a/doc/quick-tech-report/rotohsm_tech_report.tex
+++ b/doc/quick-tech-report/rotohsm_tech_report.tex
@@ -315,18 +315,6 @@ In our design with a stationary payload where only the security mesh and sensors
reports and a high-frequency alarm trigger heartbeat signal have to pass from rotor to stator. For this, a simple
optocoupler close to the axis of rotation is a good solution.
-% FIXME note prototype implementation here
-
-\subsection{Hardware prototype}
-
-% FIXME expand & update below w/ hw proto findings
-
-We are currently working on a hardware prototype that demonstrates the fundamental components of our concept. The
-prototype will be based on a security mesh made with a commercial printed circuit board manufacturing process. In our
-prototype we intend to use two commercially available hollow-shaft brushless DC (BLDC) motors originally intended for
-quadcopter-mounted camera gimbals, one for driving and one for power transfer. The prototype will have a usable internal
-volume sufficient to house a small form factor PC ($\approx\SI{2}{\liter}$).
-
\section{Attacks}
\subsection{Attacks on the mesh}
@@ -382,7 +370,134 @@ If the rate of rotation is set to change on a schedule, it is trivially detectab
\section{Prototype implementation}
%FIXME
-FIXME
+To validate our theoretical design, we have implemented a prototype rotary HSM. The main engineering challenges we
+solved in our prototype are:
+\begin{enumerate}
+ \item Fundamental mechanical design suitable for rapid prototyping that can withstand a rotation of $\SI{500}{rpm}$.
+ \item Automatic generation of security mesh PCB layouts for quick adaption to new form factors.
+ \item Non-contact power transmission to rotor.
+ \item Non-contact bidirectional data communication between stator and rotor.
+\end{enumerate}
+
+\subsection{Mechanical design}
+
+We sized our prototype to have space for one or two full-size Raspberry Pi boards. Each one of these boards is already
+more powerful than an ordinary HSM, but they are small enough to simplify our prototype's design. For low-cost
+prototyping we designed our prototype to use printed circuit boards as its main structural material. The interlocking
+parts were designed in FreeCAD mechanical CAD as shown in Figure \ref{proto_3d_design}. The mechanical designs were
+exported to KiCAD for electrical design before being sent to a commercial PCB manufacturer. Rotor and stator are built
+from interlocking, soldered PCBs. The components are mounted to a $\SI{6}{\milli\meter}$ brass tube using FDM 3D printed
+flanges. The rotor is driven by a small hobby quadcopter motor.
+
+Security is provided by a PCB security mesh enveloping the entire system and extending to within a few millimeters of
+the shaft. For security it is not necessary to cover the entire circumference of the module with mesh, so we opted to
+use only three narrow longitudinal struts to save weight.
+
+To mount the entire HSM, we chose to use ``2020'' modular aluminium profile.
+
+\begin{figure}
+ \center
+ \includegraphics[height=7cm]{proto_3d_design.jpg}
+ \caption{The 3D CAD design of the prototype.}
+ \label{proto_3d_design}
+\end{figure}
+
+\subsection{PCB security mesh generation}
+
+To allow a quick iteration of our design while producing results with a realistic level of security, we wrote a plugin
+for the KiCAD EDA suite that automatically generates parametrized security meshes. When KiCAD is used in conjunction
+with FreeCAD through FreeCAD's KiCAD StepUp plugin, this ends up in an efficient toolchain from mechanical CAD design to
+security mesh PCB gerber files. The mesh generation plugin can be found at its
+website\footnote{\url{https://blog.jaseg.de/posts/kicad-mesh-plugin/}}.
+
+Our mesh generation plugin overlays a grid on the target area and then produces a randomized tree covering this grid.
+The individual mesh traces are then traced along a depth-first search through this tree. A visualization of the steps is
+shown in Figure \ref{mesh_gen_viz}. A sample of the production results from our prototype is shown in Figure
+\ref{mesh_gen_sample}.
+
+\begin{figure}
+ \center
+ \includegraphics[width=9cm]{mesh_gen_viz.pdf}
+ \caption{Overview of the automatic security mesh generation process. 1 - the blob is the example target area. 2 - A
+ grid is overlayed. 3 - Grid cells outside of the target area are removed. 4 - A random tree covering the remaining
+ cells is generated. 5 - The mesh traces are traced along a depth-first walk of the tree. 6 - Result.}
+ \label{mesh_gen_viz}
+\end{figure}
+
+\begin{figure}
+ \center
+ \includegraphics[width=6cm]{mesh_scan_crop.jpg}
+ \caption{A section of the security mesh PCB we produced with our toolchain for the prototype HSM.}
+ \label{mesh_gen_sample}
+\end{figure}
+
+\subsection{Data transmission through rotating joint}
+
+As a baseline solution for data transmission, we settled on a $\SI{115}{\kilo\baud}$ UART signal sent through a simple
+bidirectional infrared link. In the transmitter, the UART TX line on-off modulates a $\SI{920}{\nano\meter}$ IR LED
+through a common-emitter driver transistor. In the receiver, an IR PIN photodiode reverse-biased to
+$\frac{1}{2}V_\text{CC}$ is connected to a reasonably wideband transimpedance amplifier (TIA) with a
+$\SI{100}{\kilo\ohm}$ transimpedance. As shown in Figure \ref{photolink_schematic}, the output of this TIA is fed
+through another $G=100$ amplifier whose output is then squared up by a comparator. We used an \textsf{MCP6494} quad
+CMOS op-amp. At a specified $\SI{2}{\milli\ampere}$ current consumption it is within our rotor's power budget, and its
+Gain Bandwidth Product of $\SI{7.5}{\mega\hertz}$ yields a useful transimpedance in the photodiode-facing TIA stage.
+
+To reduce the requirements on power transmission to the rotor, we have tried to reduce power consumption of the
+rotor-side receiver/transmitter pair trading off stator-side power consumption. One part of this is that we use
+a wide-angle photodiode and IR LED on the stator, but use narrow-angle components on the rotor. The two rx/tx pairs are
+arranged next to the motor on opposite sides. By placing the narrow-angle rotor rx/tx components on the outside as
+shown in Figure \ref{ir_tx_schema}, the motor shields both IR links from crosstalk. The rotor transmitter LED is
+driven at $\SI{1}{\milli\ampere}$ while the stator transmitter LED is driven at $\SI{20}{\milli\ampere}$.
+
+\begin{figure}
+ \center
+ \includegraphics{ir_tx_schema.pdf}
+ \caption{Schema of our bidirectional IR communication link between rotor and stator, view along axis of rotation. 1
+ - Rotor base PCB. 2 - Stator IR link PCB. 3 - Motor. 4 - receiver PIN photodiode. 5 - transmitter IR LED.}
+ \label{ir_tx_schema}
+\end{figure}
+
+\begin{figure}
+ \center
+ \includegraphics[width=9cm]{photolink_schematic.pdf}
+ \caption{Schematic of the IR communication link. Component values are only examples. In particular C2 depends highly
+ on the photodiode used and stray capacitances due to the component layout.}
+ \label{photolink_schematic}
+\end{figure}
+
+\subsection{Power transmission through rotating joint}
+
+Since this prototype serves only demonstration purposes, we chose to use the simplest possible method of power
+transmission: Solar cells. We mounted six series-connected solar cells made up from three commercially available modules
+on the circular PCB at the end of our cylindrical rotor. The solar cells direclty feed the rotor's logic supply with
+buffering by a large $\SI{33}{\micro\farad}$ ceramic capacitor. With six cells in series, they provide around
+$\SI{3.0}{\volt}$ at several tens of $\si{\milli\ampere}$ given sufficient illumination.
+
+For simplicity and weight reduction, at this point we chose to forego large buffer capacitors on the rotor. This means
+variations in solar cell illumination directly couple into the microcontroller's supply rail. Initially, we experimented
+with regular residential LED light bulbs, but those turned out to have too much flicker and lead to our microcontroller
+frequently rebooting. Trials using an incandecent light produced a stable supply, but the large amount of infrared light
+emitted by the incandecent light bulb severely disturbed our near-infrared communication link. As a consequence of
+this, we settled on a small LED light made for photography applications that provdided us with mostly flicker-free
+light, leading to a sufficiently stable microcontroller VCC rail without any disturbance to the IR link.
+
+\subsection{Evaluation}
+
+During experiments, our prototype performed as intended. After some experimentation, we got both power and data
+transmission through the rotating joint working reliably. Figure \ref{prototype_early_comms} shows our prototype
+performing reliably at maximum speed for the first time. Our improvised IR link is open in both directions for about
+$\SI{60}{\degree}$ of the rotation, which allows us to reliably transfer several tens of bytes in each direction during
+each receiver's fly-by even at high speed of rotation. As a result of our prototype experiments, we consider a
+larger-scale implementation of the inertial HSM concept practical.
+
+\begin{figure}
+ \center
+ \includegraphics[width=8cm]{prototype_early_comms_small.jpg}
+ \caption{The protoype when we first achieved reliable power transfer and bidirectional communication between stator
+ and rotor. In the picture, the prototype was communicating reliably up to the maximum $\approx\SI{1500}{rpm}$ that
+ we could get out of its hobby quadcopter parts.}
+ \label{prototype_early_comms}
+\end{figure}
\section{Future Work}
@@ -416,9 +531,10 @@ or courier services after spin-up.
\section{Conclusion}
In this paper, we have presented inertial hardware security modules, a novel concept for the construction of highly
secure hardware security modules from inexpensive, commonly available parts. We have elaborated the engineering
-considerations underlying a practical implementation of this concept. We have analyzed the concept for its security
-properties and highlighted its ability to significantly strengthen otherwise weak tamper detection barriers. We have
-laid out some ideas for future research on the concept.
+considerations underlying a practical implementation of this concept. We have implemented a prototype demonstrating
+practical solutions to the significant engineering challenges of this concept. We have analyzed the concept for its
+security properties and highlighted its ability to significantly strengthen otherwise weak tamper detection barriers. We
+have laid out some ideas for future research on the concept.
\printbibliography[heading=bibintoc]
\appendix
diff --git a/prototype/fw/src/main.c b/prototype/fw/src/main.c
index 0998fce..42c1ea7 100644
--- a/prototype/fw/src/main.c
+++ b/prototype/fw/src/main.c
@@ -73,7 +73,7 @@ int main(void) {
int i = 0;
while (23) {
if (tx_st.remaining_bytes == 0) {
- if (i > 1000) {
+ if (i > 100) {
res_buf.req_seq = req_seq;
res_buf.res_seq = res_seq;
res_seq += 1;
@@ -118,7 +118,7 @@ int main(void) {
} else {
if (rc == sizeof(req_buf)) {
crc32_t check_crc = pkt_crc(&req_buf, &req_buf.trailer);
- if (check_crc != req_buf.trailer.crc32) {
+ if (check_crc != req_buf.trailer.crc32 || check_crc == 0 || check_crc == -1) {
rx_crc_error += 1;
} else {
req_seq = req_buf.req_seq;
diff --git a/prototype/fw/tools/ser_test.py b/prototype/fw/tools/ser_test.py
index 8680f46..ebd95ed 100644
--- a/prototype/fw/tools/ser_test.py
+++ b/prototype/fw/tools/ser_test.py
@@ -32,15 +32,15 @@ if __name__ == '__main__':
while True:
data = ser.read()
for c in data:
- if byte_count == 0:
- print(f'\033[38;5;244m{time.time() - start_time: 8.3f} \033[0m', end='')
+ #if byte_count == 0:
+ #print(f'\033[38;5;244m{time.time() - start_time: 8.3f} \033[0m', end='')
col = '\033[91m' if c == 0 else '\033[0m' # if c == (lastc - 1) % 256 else '\033[92m')
- print(f'{col}{c:02x}', end=' ')
+ #print(f'{col}{c:02x}', end=' ')
line += bytes([c])
byte_count += 1
if c == 0:
- print(' ' * (16 - byte_count), end='\033[0m\n')
+ #print(' ' * (16 - byte_count), end='\033[0m\n')
byte_count = 16
try:
payload = cobs.decode(packet)
@@ -51,7 +51,8 @@ if __name__ == '__main__':
else:
crc_ok = False
ref_crc = ''
- print(' '.join(f'{col if col else ""}{c if c else 0:02x}' for col, c in itertools.zip_longest(field_colors,
+ if len(payload) == 12:
+ print(' '.join(f'{col if col else ""}{c if c else 0:02x}' for col, c in itertools.zip_longest(field_colors,
payload)), 'OK' if crc_ok else f'WRONG')
except cobs.DecodeError:
print('COBS framing error')
@@ -61,7 +62,7 @@ if __name__ == '__main__':
isprint = lambda c: c in b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ '
if byte_count == 16:
printable = ''.join( chr(c) if isprint(c) else '.' for c in line )
- print(f'\033[93m | {printable}\033[0m')
+ #print(f'\033[93m | {printable}\033[0m')
byte_count = 0
line = b''
lastc = c