From 92e3b5f49f6f5336530988e7839ab3ed283b86e4 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sun, 19 Mar 2023 00:53:31 +0100 Subject: Big site update --- content/_index.rst | 9 + content/blog/_index.rst | 3 + content/blog/hsm-basics/index.rst | 214 + content/blog/hsm-basics/mori_semi_hsm_talk_web.pdf | Bin 0 -> 1075912 bytes content/blog/ihsm-worlds-first-diy-hsm/index.rst | 41 + content/blog/kicad-mesh-plugin/images/anim.webp | Bin 0 -> 35626 bytes content/blog/kicad-mesh-plugin/images/cells-0.svg | 2444 ++++ .../blog/kicad-mesh-plugin/images/cells-100.svg | 2444 ++++ content/blog/kicad-mesh-plugin/images/cells-25.svg | 2444 ++++ content/blog/kicad-mesh-plugin/images/cells-50.svg | 2444 ++++ content/blog/kicad-mesh-plugin/images/cells-75.svg | 2444 ++++ .../kicad-mesh-plugin/images/grid-vis-plain.svg | 138 + content/blog/kicad-mesh-plugin/images/grid-vis.svg | 138 + .../images/kicad-mesh-outline.png | Bin 0 -> 120770 bytes .../images/kicad-mesh-result-large.png | Bin 0 -> 197766 bytes .../images/kicad-mesh-settings.png | Bin 0 -> 46346 bytes .../images/kicad-mesh-settings2.png | Bin 0 -> 131267 bytes .../blog/kicad-mesh-plugin/images/maze_tiles.svg | 2070 +++ .../kicad-mesh-plugin/images/maze_tiles_plain.svg | 1731 +++ .../blog/kicad-mesh-plugin/images/modern_art.svg | 1609 ++ .../kicad-mesh-plugin/images/tiles-25-small.svg | 14636 +++++++++++++++++++ .../kicad-mesh-plugin/images/traces-25-small.svg | 7 + content/blog/kicad-mesh-plugin/index.rst | 221 + .../images/daylight_spectrum_dvd.jpg | Bin 0 -> 79150 bytes .../images/driver_ringing_strong.jpg | Bin 0 -> 285952 bytes .../images/driver_ringing_weak.jpg | Bin 0 -> 292100 bytes .../images/electronics_whole.jpg | Bin 0 -> 438776 bytes .../led-characterization/images/hsv_cylinder.png | Bin 0 -> 293981 bytes .../images/photodiode_sensitivity.svg | 874 ++ .../led-characterization/images/preamp_back.jpg | Bin 0 -> 340446 bytes .../led-characterization/images/preamp_front.jpg | Bin 0 -> 308167 bytes .../images/preamp_schematic.jpg | Bin 0 -> 277414 bytes .../images/processed_plot_cheap_rgb.svg | 2366 +++ .../images/raw_plot_cheap_rgb.svg | 2739 ++++ .../blog/led-characterization/images/rgb_cube.svg | 222 + .../images/spectrograph_step1_parts.jpg | Bin 0 -> 284254 bytes .../images/spectrograph_step2.jpg | Bin 0 -> 277234 bytes .../images/spectrograph_step3.jpg | Bin 0 -> 256192 bytes .../images/spectrograph_step4_complete.jpg | Bin 0 -> 303777 bytes .../images/zeus_hammer_breadboard.jpg | Bin 0 -> 445768 bytes .../images/zeus_hammer_breadboard_original.jpg | Bin 0 -> 2474273 bytes .../images/zeus_hammer_schematic.jpg | Bin 0 -> 148056 bytes .../images/zeus_hammer_schematic_original.jpg | Bin 0 -> 1893757 bytes content/blog/led-characterization/index.rst | 504 + ...led_within_srgb_fancy_camera_path_scale=2.5.mkv | Bin 0 -> 2676955 bytes ...ed_within_srgb_fancy_camera_path_scale=2.5.webm | Bin 0 -> 1822963 bytes .../video/led_within_srgb_scale=1.0.mkv | Bin 0 -> 1223799 bytes .../video/led_within_srgb_scale=1.0.webm | Bin 0 -> 789099 bytes .../video/led_within_srgb_scale=2.5.mkv | Bin 0 -> 1559120 bytes .../video/led_within_srgb_scale=2.5.webm | Bin 0 -> 920089 bytes .../video/led_within_srgb_scale=3.mkv | Bin 0 -> 1709475 bytes .../video/led_within_srgb_scale=3.webm | Bin 0 -> 925593 bytes content/blog/led-characterization/video/sRGB.mkv | Bin 0 -> 1269287 bytes content/blog/led-characterization/video/sRGB.webm | Bin 0 -> 791821 bytes .../blog/led-characterization/video/scale=1.mkv | Bin 0 -> 1011548 bytes .../blog/led-characterization/video/scale=1.webm | Bin 0 -> 758345 bytes .../blog/led-characterization/video/scale=2.5.mkv | Bin 0 -> 1296564 bytes .../blog/led-characterization/video/scale=2.5.webm | Bin 0 -> 882674 bytes .../blog/led-characterization/video/scale=5.mkv | Bin 0 -> 1571645 bytes .../blog/led-characterization/video/scale=5.webm | Bin 0 -> 879476 bytes .../images/asymmetric_iled.svg | 2222 +++ .../images/asymmetric_vgate.svg | 1933 +++ .../multichannel-led-driver/images/bcm_schema.jpg | Bin 0 -> 1626022 bytes .../images/corrected_brightness_sim.svg | 765 + .../images/driver_linearity_raw.svg | 937 ++ .../images/driver_output_ltspice_schematic.jpg | Bin 0 -> 876019 bytes .../images/driver_pcb_built.jpg | Bin 0 -> 1229840 bytes .../images/driver_ringing_strong.jpg | Bin 0 -> 285952 bytes .../images/driver_ringing_weak.jpg | Bin 0 -> 292100 bytes .../images/led_strip_alight.jpg | Bin 0 -> 1752106 bytes .../images/linearization_setup.jpg | Bin 0 -> 2038436 bytes .../images/olsndot_output_schematic.jpg | Bin 0 -> 1410898 bytes .../multichannel-led-driver/images/olsndot_pcb.png | Bin 0 -> 137479 bytes .../images/olsndot_schematic.png | Bin 0 -> 362216 bytes .../images/overshoot_sim_r0.svg | 1885 +++ .../images/overshoot_sim_r100.svg | 1788 +++ .../multichannel-led-driver/images/pwm_schema.jpg | Bin 0 -> 840134 bytes .../images/uncorrected_brightness_sim.svg | 727 + content/blog/multichannel-led-driver/index.rst | 456 + .../olsndot_v02_schematics_and_pcb.pdf | Bin 0 -> 1036117 bytes content/blog/private-contact-discovery/index.rst | 38 + .../mori_semi_psi_talk.odp | Bin 0 -> 35999576 bytes .../mori_semi_psi_talk.pdf | Bin 0 -> 11600295 bytes content/blog/serial-protocols/index.rst | 249 + .../images/succulents.jpg | Bin 0 -> 587685 bytes .../blog/sybil-resistance-identity/index-old.rst | 244 + content/blog/sybil-resistance-identity/index.rst | 89 + .../images/edgerouter_interface_config.png | Bin 0 -> 148433 bytes .../images/edgerouter_route_config.png | Bin 0 -> 75601 bytes .../images/edgerouter_sfp_config.png | Bin 0 -> 56138 bytes .../images/edgerouter_snat_config.png | Bin 0 -> 118370 bytes .../images/edgerouter_snat_config2.png | Bin 0 -> 82458 bytes .../images/sfp_onu_ploam_pw_config.png | Bin 0 -> 152023 bytes .../blog/telekom-gpon-sfp/images/sfp_onu_reset.png | Bin 0 -> 132106 bytes .../telekom-gpon-sfp/images/sfp_onu_web_if.png | Bin 0 -> 133838 bytes content/blog/telekom-gpon-sfp/index.rst | 216 + .../images/thors_hammer_breadboard.jpg | Bin 0 -> 3229178 bytes .../thors-hammer/images/thors_hammer_schematic.jpg | Bin 0 -> 1822573 bytes content/blog/thors-hammer/index.rst | 60 + content/blog/thors-hammer/video/thors_hammer.mkv | Bin 0 -> 3799797 bytes content/blog/thors-hammer/video/thors_hammer.mov | Bin 0 -> 33979697 bytes content/blog/thors-hammer/video/thors_hammer.webm | Bin 0 -> 4868825 bytes .../blog/wifi-led-driver/images/board_in_case.jpg | Bin 0 -> 2898747 bytes .../wifi-led-driver/images/board_in_case.small.jpg | Bin 0 -> 817789 bytes content/blog/wifi-led-driver/images/boards.jpg | Bin 0 -> 3642485 bytes .../blog/wifi-led-driver/images/boards.small.jpg | Bin 0 -> 865465 bytes content/blog/wifi-led-driver/images/layout.png | Bin 0 -> 114048 bytes content/blog/wifi-led-driver/images/schematic.png | Bin 0 -> 301982 bytes content/blog/wifi-led-driver/index.rst | 145 + .../resource/lyza_schematic_and_pcb.pdf | Bin 0 -> 781457 bytes content/posts/hsm-basics/index.rst | 214 - .../posts/hsm-basics/mori_semi_hsm_talk_web.pdf | Bin 1075912 -> 0 bytes content/posts/ihsm-worlds-first-diy-hsm/index.rst | 41 - content/posts/kicad-mesh-plugin/images/anim.webp | Bin 35626 -> 0 bytes content/posts/kicad-mesh-plugin/images/cells-0.svg | 2444 ---- .../posts/kicad-mesh-plugin/images/cells-100.svg | 2444 ---- .../posts/kicad-mesh-plugin/images/cells-25.svg | 2444 ---- .../posts/kicad-mesh-plugin/images/cells-50.svg | 2444 ---- .../posts/kicad-mesh-plugin/images/cells-75.svg | 2444 ---- .../kicad-mesh-plugin/images/grid-vis-plain.svg | 138 - .../posts/kicad-mesh-plugin/images/grid-vis.svg | 138 - .../images/kicad-mesh-outline.png | Bin 120770 -> 0 bytes .../images/kicad-mesh-result-large.png | Bin 197766 -> 0 bytes .../images/kicad-mesh-settings.png | Bin 46346 -> 0 bytes .../images/kicad-mesh-settings2.png | Bin 131267 -> 0 bytes .../posts/kicad-mesh-plugin/images/maze_tiles.svg | 2070 --- .../kicad-mesh-plugin/images/maze_tiles_plain.svg | 1731 --- .../posts/kicad-mesh-plugin/images/modern_art.svg | 1609 -- .../kicad-mesh-plugin/images/tiles-25-small.svg | 14636 ------------------- .../kicad-mesh-plugin/images/traces-25-small.svg | 7 - content/posts/kicad-mesh-plugin/index.rst | 221 - .../images/daylight_spectrum_dvd.jpg | Bin 79150 -> 0 bytes .../images/driver_ringing_strong.jpg | Bin 285952 -> 0 bytes .../images/driver_ringing_weak.jpg | Bin 292100 -> 0 bytes .../images/electronics_whole.jpg | Bin 438776 -> 0 bytes .../led-characterization/images/hsv_cylinder.png | Bin 293981 -> 0 bytes .../images/photodiode_sensitivity.svg | 874 -- .../led-characterization/images/preamp_back.jpg | Bin 340446 -> 0 bytes .../led-characterization/images/preamp_front.jpg | Bin 308167 -> 0 bytes .../images/preamp_schematic.jpg | Bin 277414 -> 0 bytes .../images/processed_plot_cheap_rgb.svg | 2366 --- .../images/raw_plot_cheap_rgb.svg | 2739 ---- .../posts/led-characterization/images/rgb_cube.svg | 222 - .../images/spectrograph_step1_parts.jpg | Bin 284254 -> 0 bytes .../images/spectrograph_step2.jpg | Bin 277234 -> 0 bytes .../images/spectrograph_step3.jpg | Bin 256192 -> 0 bytes .../images/spectrograph_step4_complete.jpg | Bin 303777 -> 0 bytes .../images/zeus_hammer_breadboard.jpg | Bin 445768 -> 0 bytes .../images/zeus_hammer_breadboard_original.jpg | Bin 2474273 -> 0 bytes .../images/zeus_hammer_schematic.jpg | Bin 148056 -> 0 bytes .../images/zeus_hammer_schematic_original.jpg | Bin 1893757 -> 0 bytes content/posts/led-characterization/index.rst | 500 - ...led_within_srgb_fancy_camera_path_scale=2.5.mkv | Bin 2676955 -> 0 bytes ...ed_within_srgb_fancy_camera_path_scale=2.5.webm | Bin 1822963 -> 0 bytes .../video/led_within_srgb_scale=1.0.mkv | Bin 1223799 -> 0 bytes .../video/led_within_srgb_scale=1.0.webm | Bin 789099 -> 0 bytes .../video/led_within_srgb_scale=2.5.mkv | Bin 1559120 -> 0 bytes .../video/led_within_srgb_scale=2.5.webm | Bin 920089 -> 0 bytes .../video/led_within_srgb_scale=3.mkv | Bin 1709475 -> 0 bytes .../video/led_within_srgb_scale=3.webm | Bin 925593 -> 0 bytes content/posts/led-characterization/video/sRGB.mkv | Bin 1269287 -> 0 bytes content/posts/led-characterization/video/sRGB.webm | Bin 791821 -> 0 bytes .../posts/led-characterization/video/scale=1.mkv | Bin 1011548 -> 0 bytes .../posts/led-characterization/video/scale=1.webm | Bin 758345 -> 0 bytes .../posts/led-characterization/video/scale=2.5.mkv | Bin 1296564 -> 0 bytes .../led-characterization/video/scale=2.5.webm | Bin 882674 -> 0 bytes .../posts/led-characterization/video/scale=5.mkv | Bin 1571645 -> 0 bytes .../posts/led-characterization/video/scale=5.webm | Bin 879476 -> 0 bytes .../images/asymmetric_iled.svg | 2222 --- .../images/asymmetric_vgate.svg | 1933 --- .../multichannel-led-driver/images/bcm_schema.jpg | Bin 1626022 -> 0 bytes .../images/corrected_brightness_sim.svg | 765 - .../images/driver_linearity_raw.svg | 937 -- .../images/driver_output_ltspice_schematic.jpg | Bin 876019 -> 0 bytes .../images/driver_pcb_built.jpg | Bin 1229840 -> 0 bytes .../images/driver_ringing_strong.jpg | Bin 285952 -> 0 bytes .../images/driver_ringing_weak.jpg | Bin 292100 -> 0 bytes .../images/led_strip_alight.jpg | Bin 1752106 -> 0 bytes .../images/linearization_setup.jpg | Bin 2038436 -> 0 bytes .../images/olsndot_output_schematic.jpg | Bin 1410898 -> 0 bytes .../multichannel-led-driver/images/olsndot_pcb.png | Bin 137479 -> 0 bytes .../images/olsndot_schematic.png | Bin 362216 -> 0 bytes .../images/overshoot_sim_r0.svg | 1885 --- .../images/overshoot_sim_r100.svg | 1788 --- .../multichannel-led-driver/images/pwm_schema.jpg | Bin 840134 -> 0 bytes .../images/uncorrected_brightness_sim.svg | 727 - content/posts/multichannel-led-driver/index.rst | 456 - .../olsndot_v02_schematics_and_pcb.pdf | Bin 1036117 -> 0 bytes content/posts/private-contact-discovery/index.rst | 38 - .../mori_semi_psi_talk.odp | Bin 35999576 -> 0 bytes .../mori_semi_psi_talk.pdf | Bin 11600295 -> 0 bytes content/posts/serial-protocols/index.rst | 249 - .../images/succulents.jpg | Bin 587685 -> 0 bytes .../posts/sybil-resistance-identity/index-old.rst | 244 - content/posts/sybil-resistance-identity/index.rst | 89 - .../images/edgerouter_interface_config.png | Bin 148433 -> 0 bytes .../images/edgerouter_route_config.png | Bin 75601 -> 0 bytes .../images/edgerouter_sfp_config.png | Bin 56138 -> 0 bytes .../images/edgerouter_snat_config.png | Bin 118370 -> 0 bytes .../images/edgerouter_snat_config2.png | Bin 82458 -> 0 bytes .../images/sfp_onu_ploam_pw_config.png | Bin 152023 -> 0 bytes .../telekom-gpon-sfp/images/sfp_onu_reset.png | Bin 132106 -> 0 bytes .../telekom-gpon-sfp/images/sfp_onu_web_if.png | Bin 133838 -> 0 bytes content/posts/telekom-gpon-sfp/index.rst | 216 - .../images/thors_hammer_breadboard.jpg | Bin 3229178 -> 0 bytes .../thors-hammer/images/thors_hammer_schematic.jpg | Bin 1822573 -> 0 bytes content/posts/thors-hammer/index.rst | 60 - content/posts/thors-hammer/video/thors_hammer.mkv | Bin 3799797 -> 0 bytes content/posts/thors-hammer/video/thors_hammer.mov | Bin 33979697 -> 0 bytes content/posts/thors-hammer/video/thors_hammer.webm | Bin 4868825 -> 0 bytes .../posts/wifi-led-driver/images/board_in_case.jpg | Bin 2898747 -> 0 bytes .../wifi-led-driver/images/board_in_case.small.jpg | Bin 817789 -> 0 bytes content/posts/wifi-led-driver/images/boards.jpg | Bin 3642485 -> 0 bytes .../posts/wifi-led-driver/images/boards.small.jpg | Bin 865465 -> 0 bytes content/posts/wifi-led-driver/images/layout.png | Bin 114048 -> 0 bytes content/posts/wifi-led-driver/images/schematic.png | Bin 301982 -> 0 bytes content/posts/wifi-led-driver/index.rst | 145 - .../resource/lyza_schematic_and_pcb.pdf | Bin 781457 -> 0 bytes content/projects/_index.rst | 6 + content/projects/gerbolyze/README.rst | 700 + content/projects/gerbolyze/index.rst | 17 + content/projects/gerbolyze/pics/ex-flattening.png | Bin 0 -> 47137 bytes .../projects/gerbolyze/pics/ex-intersections.png | Bin 0 -> 48558 bytes content/projects/gerbolyze/pics/ex-strokes.png | Bin 0 -> 67441 bytes content/projects/gerbolyze/pics/ex-svg-joins.png | Bin 0 -> 18659 bytes content/projects/gerbolyze/pics/ex-svg-strokes.png | Bin 0 -> 67441 bytes content/projects/gerbolyze/pics/ex-svg-winding.png | Bin 0 -> 34356 bytes .../projects/gerbolyze/pics/fr4_comparison2.jpg | Bin 0 -> 271943 bytes .../gerbolyze/pics/pcbway_sample_01_small.jpg | Bin 0 -> 453117 bytes .../gerbolyze/pics/pcbway_sample_02_small.jpg | Bin 0 -> 521032 bytes .../gerbolyze/pics/pcbway_sample_03_small.jpg | Bin 0 -> 746718 bytes .../projects/gerbolyze/pics/process-overview.png | Bin 0 -> 516640 bytes .../projects/gerbolyze/pics/process-overview.svg | 7230 +++++++++ content/projects/gerbolyze/pics/sample1.jpg | Bin 0 -> 299841 bytes content/projects/gerbolyze/pics/sample2.jpg | Bin 0 -> 251440 bytes content/projects/gerbolyze/pics/sample3.jpg | Bin 0 -> 171160 bytes .../projects/gerbolyze/pics/subtract_example.png | Bin 0 -> 237770 bytes .../projects/gerbolyze/pics/test_svg_readme.svg | 515 + .../gerbolyze/pics/test_svg_readme_composited.png | Bin 0 -> 1211058 bytes .../gerbolyze/pics/vec_contours_composited.png | Bin 0 -> 40471 bytes .../gerbolyze/pics/vec_hexgrid_composited.png | Bin 0 -> 249235 bytes .../gerbolyze/pics/vec_poisson_composited.png | Bin 0 -> 278253 bytes .../gerbolyze/pics/vec_square_composited.png | Bin 0 -> 201613 bytes content/projects/gerbonara/index.rst | 141 + content/projects/lolcat-c/LOLCat-Rainbow.jpg | Bin 0 -> 42785 bytes content/projects/lolcat-c/index.rst | 105 + content/projects/lolcat-c/screenshot.png | Bin 0 -> 198032 bytes content/projects/lolcat-c/sl.gif | Bin 0 -> 1466027 bytes content/projects/python-mpv/README.rst | 401 + content/projects/python-mpv/index.rst | 18 + content/projects/svg-flatten/index.rst | 15 + content/projects/wsdiff/index.rst | 63 + content/projects/wsdiff/latest.png | Bin 0 -> 136920 bytes 253 files changed, 60707 insertions(+), 51480 deletions(-) create mode 100644 content/_index.rst create mode 100644 content/blog/_index.rst create mode 100644 content/blog/hsm-basics/index.rst create mode 100644 content/blog/hsm-basics/mori_semi_hsm_talk_web.pdf create mode 100644 content/blog/ihsm-worlds-first-diy-hsm/index.rst create mode 100755 content/blog/kicad-mesh-plugin/images/anim.webp create mode 100755 content/blog/kicad-mesh-plugin/images/cells-0.svg create mode 100755 content/blog/kicad-mesh-plugin/images/cells-100.svg create mode 100755 content/blog/kicad-mesh-plugin/images/cells-25.svg create mode 100755 content/blog/kicad-mesh-plugin/images/cells-50.svg create mode 100755 content/blog/kicad-mesh-plugin/images/cells-75.svg create mode 100755 content/blog/kicad-mesh-plugin/images/grid-vis-plain.svg create mode 100755 content/blog/kicad-mesh-plugin/images/grid-vis.svg create mode 100755 content/blog/kicad-mesh-plugin/images/kicad-mesh-outline.png create mode 100755 content/blog/kicad-mesh-plugin/images/kicad-mesh-result-large.png create mode 100755 content/blog/kicad-mesh-plugin/images/kicad-mesh-settings.png create mode 100755 content/blog/kicad-mesh-plugin/images/kicad-mesh-settings2.png create mode 100755 content/blog/kicad-mesh-plugin/images/maze_tiles.svg create mode 100755 content/blog/kicad-mesh-plugin/images/maze_tiles_plain.svg create mode 100755 content/blog/kicad-mesh-plugin/images/modern_art.svg create mode 100755 content/blog/kicad-mesh-plugin/images/tiles-25-small.svg create mode 100755 content/blog/kicad-mesh-plugin/images/traces-25-small.svg create mode 100644 content/blog/kicad-mesh-plugin/index.rst create mode 100644 content/blog/led-characterization/images/daylight_spectrum_dvd.jpg create mode 100644 content/blog/led-characterization/images/driver_ringing_strong.jpg create mode 100644 content/blog/led-characterization/images/driver_ringing_weak.jpg create mode 100644 content/blog/led-characterization/images/electronics_whole.jpg create mode 100644 content/blog/led-characterization/images/hsv_cylinder.png create mode 100644 content/blog/led-characterization/images/photodiode_sensitivity.svg create mode 100644 content/blog/led-characterization/images/preamp_back.jpg create mode 100644 content/blog/led-characterization/images/preamp_front.jpg create mode 100644 content/blog/led-characterization/images/preamp_schematic.jpg create mode 100644 content/blog/led-characterization/images/processed_plot_cheap_rgb.svg create mode 100644 content/blog/led-characterization/images/raw_plot_cheap_rgb.svg create mode 100644 content/blog/led-characterization/images/rgb_cube.svg create mode 100644 content/blog/led-characterization/images/spectrograph_step1_parts.jpg create mode 100644 content/blog/led-characterization/images/spectrograph_step2.jpg create mode 100644 content/blog/led-characterization/images/spectrograph_step3.jpg create mode 100644 content/blog/led-characterization/images/spectrograph_step4_complete.jpg create mode 100644 content/blog/led-characterization/images/zeus_hammer_breadboard.jpg create mode 100644 content/blog/led-characterization/images/zeus_hammer_breadboard_original.jpg create mode 100644 content/blog/led-characterization/images/zeus_hammer_schematic.jpg create mode 100644 content/blog/led-characterization/images/zeus_hammer_schematic_original.jpg create mode 100644 content/blog/led-characterization/index.rst create mode 100644 content/blog/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv create mode 100644 content/blog/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.webm create mode 100644 content/blog/led-characterization/video/led_within_srgb_scale=1.0.mkv create mode 100644 content/blog/led-characterization/video/led_within_srgb_scale=1.0.webm create mode 100644 content/blog/led-characterization/video/led_within_srgb_scale=2.5.mkv create mode 100644 content/blog/led-characterization/video/led_within_srgb_scale=2.5.webm create mode 100644 content/blog/led-characterization/video/led_within_srgb_scale=3.mkv create mode 100644 content/blog/led-characterization/video/led_within_srgb_scale=3.webm create mode 100644 content/blog/led-characterization/video/sRGB.mkv create mode 100644 content/blog/led-characterization/video/sRGB.webm create mode 100644 content/blog/led-characterization/video/scale=1.mkv create mode 100644 content/blog/led-characterization/video/scale=1.webm create mode 100644 content/blog/led-characterization/video/scale=2.5.mkv create mode 100644 content/blog/led-characterization/video/scale=2.5.webm create mode 100644 content/blog/led-characterization/video/scale=5.mkv create mode 100644 content/blog/led-characterization/video/scale=5.webm create mode 100644 content/blog/multichannel-led-driver/images/asymmetric_iled.svg create mode 100644 content/blog/multichannel-led-driver/images/asymmetric_vgate.svg create mode 100644 content/blog/multichannel-led-driver/images/bcm_schema.jpg create mode 100644 content/blog/multichannel-led-driver/images/corrected_brightness_sim.svg create mode 100644 content/blog/multichannel-led-driver/images/driver_linearity_raw.svg create mode 100644 content/blog/multichannel-led-driver/images/driver_output_ltspice_schematic.jpg create mode 100644 content/blog/multichannel-led-driver/images/driver_pcb_built.jpg create mode 100644 content/blog/multichannel-led-driver/images/driver_ringing_strong.jpg create mode 100644 content/blog/multichannel-led-driver/images/driver_ringing_weak.jpg create mode 100644 content/blog/multichannel-led-driver/images/led_strip_alight.jpg create mode 100644 content/blog/multichannel-led-driver/images/linearization_setup.jpg create mode 100644 content/blog/multichannel-led-driver/images/olsndot_output_schematic.jpg create mode 100644 content/blog/multichannel-led-driver/images/olsndot_pcb.png create mode 100644 content/blog/multichannel-led-driver/images/olsndot_schematic.png create mode 100644 content/blog/multichannel-led-driver/images/overshoot_sim_r0.svg create mode 100644 content/blog/multichannel-led-driver/images/overshoot_sim_r100.svg create mode 100644 content/blog/multichannel-led-driver/images/pwm_schema.jpg create mode 100644 content/blog/multichannel-led-driver/images/uncorrected_brightness_sim.svg create mode 100644 content/blog/multichannel-led-driver/index.rst create mode 100644 content/blog/multichannel-led-driver/olsndot_v02_schematics_and_pcb.pdf create mode 100644 content/blog/private-contact-discovery/index.rst create mode 100644 content/blog/private-contact-discovery/mori_semi_psi_talk.odp create mode 100644 content/blog/private-contact-discovery/mori_semi_psi_talk.pdf create mode 100644 content/blog/serial-protocols/index.rst create mode 100755 content/blog/sybil-resistance-identity/images/succulents.jpg create mode 100644 content/blog/sybil-resistance-identity/index-old.rst create mode 100644 content/blog/sybil-resistance-identity/index.rst create mode 100644 content/blog/telekom-gpon-sfp/images/edgerouter_interface_config.png create mode 100644 content/blog/telekom-gpon-sfp/images/edgerouter_route_config.png create mode 100644 content/blog/telekom-gpon-sfp/images/edgerouter_sfp_config.png create mode 100644 content/blog/telekom-gpon-sfp/images/edgerouter_snat_config.png create mode 100644 content/blog/telekom-gpon-sfp/images/edgerouter_snat_config2.png create mode 100644 content/blog/telekom-gpon-sfp/images/sfp_onu_ploam_pw_config.png create mode 100644 content/blog/telekom-gpon-sfp/images/sfp_onu_reset.png create mode 100644 content/blog/telekom-gpon-sfp/images/sfp_onu_web_if.png create mode 100644 content/blog/telekom-gpon-sfp/index.rst create mode 100644 content/blog/thors-hammer/images/thors_hammer_breadboard.jpg create mode 100644 content/blog/thors-hammer/images/thors_hammer_schematic.jpg create mode 100644 content/blog/thors-hammer/index.rst create mode 100644 content/blog/thors-hammer/video/thors_hammer.mkv create mode 100644 content/blog/thors-hammer/video/thors_hammer.mov create mode 100644 content/blog/thors-hammer/video/thors_hammer.webm create mode 100644 content/blog/wifi-led-driver/images/board_in_case.jpg create mode 100644 content/blog/wifi-led-driver/images/board_in_case.small.jpg create mode 100644 content/blog/wifi-led-driver/images/boards.jpg create mode 100644 content/blog/wifi-led-driver/images/boards.small.jpg create mode 100644 content/blog/wifi-led-driver/images/layout.png create mode 100644 content/blog/wifi-led-driver/images/schematic.png create mode 100644 content/blog/wifi-led-driver/index.rst create mode 100644 content/blog/wifi-led-driver/resource/lyza_schematic_and_pcb.pdf delete mode 100644 content/posts/hsm-basics/index.rst delete mode 100644 content/posts/hsm-basics/mori_semi_hsm_talk_web.pdf delete mode 100644 content/posts/ihsm-worlds-first-diy-hsm/index.rst delete mode 100755 content/posts/kicad-mesh-plugin/images/anim.webp delete mode 100755 content/posts/kicad-mesh-plugin/images/cells-0.svg delete mode 100755 content/posts/kicad-mesh-plugin/images/cells-100.svg delete mode 100755 content/posts/kicad-mesh-plugin/images/cells-25.svg delete mode 100755 content/posts/kicad-mesh-plugin/images/cells-50.svg delete mode 100755 content/posts/kicad-mesh-plugin/images/cells-75.svg delete mode 100755 content/posts/kicad-mesh-plugin/images/grid-vis-plain.svg delete mode 100755 content/posts/kicad-mesh-plugin/images/grid-vis.svg delete mode 100755 content/posts/kicad-mesh-plugin/images/kicad-mesh-outline.png delete mode 100755 content/posts/kicad-mesh-plugin/images/kicad-mesh-result-large.png delete mode 100755 content/posts/kicad-mesh-plugin/images/kicad-mesh-settings.png delete mode 100755 content/posts/kicad-mesh-plugin/images/kicad-mesh-settings2.png delete mode 100755 content/posts/kicad-mesh-plugin/images/maze_tiles.svg delete mode 100755 content/posts/kicad-mesh-plugin/images/maze_tiles_plain.svg delete mode 100755 content/posts/kicad-mesh-plugin/images/modern_art.svg delete mode 100755 content/posts/kicad-mesh-plugin/images/tiles-25-small.svg delete mode 100755 content/posts/kicad-mesh-plugin/images/traces-25-small.svg delete mode 100644 content/posts/kicad-mesh-plugin/index.rst delete mode 100644 content/posts/led-characterization/images/daylight_spectrum_dvd.jpg delete mode 100644 content/posts/led-characterization/images/driver_ringing_strong.jpg delete mode 100644 content/posts/led-characterization/images/driver_ringing_weak.jpg delete mode 100644 content/posts/led-characterization/images/electronics_whole.jpg delete mode 100644 content/posts/led-characterization/images/hsv_cylinder.png delete mode 100644 content/posts/led-characterization/images/photodiode_sensitivity.svg delete mode 100644 content/posts/led-characterization/images/preamp_back.jpg delete mode 100644 content/posts/led-characterization/images/preamp_front.jpg delete mode 100644 content/posts/led-characterization/images/preamp_schematic.jpg delete mode 100644 content/posts/led-characterization/images/processed_plot_cheap_rgb.svg delete mode 100644 content/posts/led-characterization/images/raw_plot_cheap_rgb.svg delete mode 100644 content/posts/led-characterization/images/rgb_cube.svg delete mode 100644 content/posts/led-characterization/images/spectrograph_step1_parts.jpg delete mode 100644 content/posts/led-characterization/images/spectrograph_step2.jpg delete mode 100644 content/posts/led-characterization/images/spectrograph_step3.jpg delete mode 100644 content/posts/led-characterization/images/spectrograph_step4_complete.jpg delete mode 100644 content/posts/led-characterization/images/zeus_hammer_breadboard.jpg delete mode 100644 content/posts/led-characterization/images/zeus_hammer_breadboard_original.jpg delete mode 100644 content/posts/led-characterization/images/zeus_hammer_schematic.jpg delete mode 100644 content/posts/led-characterization/images/zeus_hammer_schematic_original.jpg delete mode 100644 content/posts/led-characterization/index.rst delete mode 100644 content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv delete mode 100644 content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.webm delete mode 100644 content/posts/led-characterization/video/led_within_srgb_scale=1.0.mkv delete mode 100644 content/posts/led-characterization/video/led_within_srgb_scale=1.0.webm delete mode 100644 content/posts/led-characterization/video/led_within_srgb_scale=2.5.mkv delete mode 100644 content/posts/led-characterization/video/led_within_srgb_scale=2.5.webm delete mode 100644 content/posts/led-characterization/video/led_within_srgb_scale=3.mkv delete mode 100644 content/posts/led-characterization/video/led_within_srgb_scale=3.webm delete mode 100644 content/posts/led-characterization/video/sRGB.mkv delete mode 100644 content/posts/led-characterization/video/sRGB.webm delete mode 100644 content/posts/led-characterization/video/scale=1.mkv delete mode 100644 content/posts/led-characterization/video/scale=1.webm delete mode 100644 content/posts/led-characterization/video/scale=2.5.mkv delete mode 100644 content/posts/led-characterization/video/scale=2.5.webm delete mode 100644 content/posts/led-characterization/video/scale=5.mkv delete mode 100644 content/posts/led-characterization/video/scale=5.webm delete mode 100644 content/posts/multichannel-led-driver/images/asymmetric_iled.svg delete mode 100644 content/posts/multichannel-led-driver/images/asymmetric_vgate.svg delete mode 100644 content/posts/multichannel-led-driver/images/bcm_schema.jpg delete mode 100644 content/posts/multichannel-led-driver/images/corrected_brightness_sim.svg delete mode 100644 content/posts/multichannel-led-driver/images/driver_linearity_raw.svg delete mode 100644 content/posts/multichannel-led-driver/images/driver_output_ltspice_schematic.jpg delete mode 100644 content/posts/multichannel-led-driver/images/driver_pcb_built.jpg delete mode 100644 content/posts/multichannel-led-driver/images/driver_ringing_strong.jpg delete mode 100644 content/posts/multichannel-led-driver/images/driver_ringing_weak.jpg delete mode 100644 content/posts/multichannel-led-driver/images/led_strip_alight.jpg delete mode 100644 content/posts/multichannel-led-driver/images/linearization_setup.jpg delete mode 100644 content/posts/multichannel-led-driver/images/olsndot_output_schematic.jpg delete mode 100644 content/posts/multichannel-led-driver/images/olsndot_pcb.png delete mode 100644 content/posts/multichannel-led-driver/images/olsndot_schematic.png delete mode 100644 content/posts/multichannel-led-driver/images/overshoot_sim_r0.svg delete mode 100644 content/posts/multichannel-led-driver/images/overshoot_sim_r100.svg delete mode 100644 content/posts/multichannel-led-driver/images/pwm_schema.jpg delete mode 100644 content/posts/multichannel-led-driver/images/uncorrected_brightness_sim.svg delete mode 100644 content/posts/multichannel-led-driver/index.rst delete mode 100644 content/posts/multichannel-led-driver/olsndot_v02_schematics_and_pcb.pdf delete mode 100644 content/posts/private-contact-discovery/index.rst delete mode 100644 content/posts/private-contact-discovery/mori_semi_psi_talk.odp delete mode 100644 content/posts/private-contact-discovery/mori_semi_psi_talk.pdf delete mode 100644 content/posts/serial-protocols/index.rst delete mode 100755 content/posts/sybil-resistance-identity/images/succulents.jpg delete mode 100644 content/posts/sybil-resistance-identity/index-old.rst delete mode 100644 content/posts/sybil-resistance-identity/index.rst delete mode 100644 content/posts/telekom-gpon-sfp/images/edgerouter_interface_config.png delete mode 100644 content/posts/telekom-gpon-sfp/images/edgerouter_route_config.png delete mode 100644 content/posts/telekom-gpon-sfp/images/edgerouter_sfp_config.png delete mode 100644 content/posts/telekom-gpon-sfp/images/edgerouter_snat_config.png delete mode 100644 content/posts/telekom-gpon-sfp/images/edgerouter_snat_config2.png delete mode 100644 content/posts/telekom-gpon-sfp/images/sfp_onu_ploam_pw_config.png delete mode 100644 content/posts/telekom-gpon-sfp/images/sfp_onu_reset.png delete mode 100644 content/posts/telekom-gpon-sfp/images/sfp_onu_web_if.png delete mode 100644 content/posts/telekom-gpon-sfp/index.rst delete mode 100644 content/posts/thors-hammer/images/thors_hammer_breadboard.jpg delete mode 100644 content/posts/thors-hammer/images/thors_hammer_schematic.jpg delete mode 100644 content/posts/thors-hammer/index.rst delete mode 100644 content/posts/thors-hammer/video/thors_hammer.mkv delete mode 100644 content/posts/thors-hammer/video/thors_hammer.mov delete mode 100644 content/posts/thors-hammer/video/thors_hammer.webm delete mode 100644 content/posts/wifi-led-driver/images/board_in_case.jpg delete mode 100644 content/posts/wifi-led-driver/images/board_in_case.small.jpg delete mode 100644 content/posts/wifi-led-driver/images/boards.jpg delete mode 100644 content/posts/wifi-led-driver/images/boards.small.jpg delete mode 100644 content/posts/wifi-led-driver/images/layout.png delete mode 100644 content/posts/wifi-led-driver/images/schematic.png delete mode 100644 content/posts/wifi-led-driver/index.rst delete mode 100644 content/posts/wifi-led-driver/resource/lyza_schematic_and_pcb.pdf create mode 100644 content/projects/_index.rst create mode 100644 content/projects/gerbolyze/README.rst create mode 100644 content/projects/gerbolyze/index.rst create mode 100644 content/projects/gerbolyze/pics/ex-flattening.png create mode 100644 content/projects/gerbolyze/pics/ex-intersections.png create mode 100644 content/projects/gerbolyze/pics/ex-strokes.png create mode 100644 content/projects/gerbolyze/pics/ex-svg-joins.png create mode 100644 content/projects/gerbolyze/pics/ex-svg-strokes.png create mode 100644 content/projects/gerbolyze/pics/ex-svg-winding.png create mode 100644 content/projects/gerbolyze/pics/fr4_comparison2.jpg create mode 100644 content/projects/gerbolyze/pics/pcbway_sample_01_small.jpg create mode 100644 content/projects/gerbolyze/pics/pcbway_sample_02_small.jpg create mode 100644 content/projects/gerbolyze/pics/pcbway_sample_03_small.jpg create mode 100644 content/projects/gerbolyze/pics/process-overview.png create mode 100644 content/projects/gerbolyze/pics/process-overview.svg create mode 100644 content/projects/gerbolyze/pics/sample1.jpg create mode 100644 content/projects/gerbolyze/pics/sample2.jpg create mode 100644 content/projects/gerbolyze/pics/sample3.jpg create mode 100644 content/projects/gerbolyze/pics/subtract_example.png create mode 100644 content/projects/gerbolyze/pics/test_svg_readme.svg create mode 100644 content/projects/gerbolyze/pics/test_svg_readme_composited.png create mode 100644 content/projects/gerbolyze/pics/vec_contours_composited.png create mode 100644 content/projects/gerbolyze/pics/vec_hexgrid_composited.png create mode 100644 content/projects/gerbolyze/pics/vec_poisson_composited.png create mode 100644 content/projects/gerbolyze/pics/vec_square_composited.png create mode 100644 content/projects/gerbonara/index.rst create mode 100644 content/projects/lolcat-c/LOLCat-Rainbow.jpg create mode 100644 content/projects/lolcat-c/index.rst create mode 100644 content/projects/lolcat-c/screenshot.png create mode 100644 content/projects/lolcat-c/sl.gif create mode 100644 content/projects/python-mpv/README.rst create mode 100644 content/projects/python-mpv/index.rst create mode 100644 content/projects/svg-flatten/index.rst create mode 100644 content/projects/wsdiff/index.rst create mode 100644 content/projects/wsdiff/latest.png (limited to 'content') diff --git a/content/_index.rst b/content/_index.rst new file mode 100644 index 0000000..ad39a14 --- /dev/null +++ b/content/_index.rst @@ -0,0 +1,9 @@ +--- +title: jaseg.de +--- + +Hi there, and welcome to my personal website. + +I'm jaseg, and I write about my projects here. You can find long-form articles in the blog, and links to my open-source +projects on the projects page. On the top right of this page, there are links to my git repositories and social media +pages. If you want to learn more about me, head over to the about page. diff --git a/content/blog/_index.rst b/content/blog/_index.rst new file mode 100644 index 0000000..9bff67d --- /dev/null +++ b/content/blog/_index.rst @@ -0,0 +1,3 @@ +--- +title: Blog +--- diff --git a/content/blog/hsm-basics/index.rst b/content/blog/hsm-basics/index.rst new file mode 100644 index 0000000..306edcd --- /dev/null +++ b/content/blog/hsm-basics/index.rst @@ -0,0 +1,214 @@ +--- +title: "Hardware Security Module Basics" +date: 2019-05-17T15:29:20+08:00 +--- + +Hardware Security Modules and Security Research and Cryptography +================================================================ + +On May 17 2019 I gave a short presentation on the fundamentals of hardware security modules at the weekly seminar of +Prof. Mori's security research working group at Waseda University. The motivation for this was that outside of low-level +hardware security people and people working in the financial industry HSMs are not thought about that often. In +particular most network or systems security people would not consider them an option. Also it could turn out to be +really interesting to think about what could be done with an HSM in conjunction with modern cryptography (instead of +just plain old RSA-OAEP and AES-CBC). + +`Click here to download a PDF with the slides for this talk. `__ + +Ideas for research in HSMs +========================== + +Preparing for this talk brought me back to some research ideas I've been working on for a while now. Since I'm not sure +I'll find the time to properly research this topic, I thought it would be great to write down some rought outlines first +for future reference. + +The Problem with current HSM tech +--------------------------------- + +Currently, HSMs are only used in certain specific niche applications such as certificate authority key management and +financial transaction data handling. One key reason for this is that HSMs currently don't provide the affordances that +would be needed for them to be adopted more widely by the cryptographic and security engineering community. As far as I +can tell, the two core missing affordances are: + +1. To be more widely adopted, HSMs must become less expensive. Currently, they go for several tens of thousands of Euro, + which puts them outside most budgets. +2. To be more widely adopted, HSMs must provide the standardized programming interfaces familiar to cryptographic + developers. Currently, every HSM vendor has their own custom cryptographic API and a developer will have to train on + one specific vendor's tooling. Furthermore, any documentation of these internals is kept secret behind NDAs. This + constitutes a high barrier to entry, decreasing adoption in particular with young developers accustomed to + open-source ecosystems. + +Attacking cost of implementation +-------------------------------- + +The first issue can be addressed by simply creating a viable low-cost alternative. There is no fundamental technical +reason for the high cost of HSMs. This cost is instead due to manufacturers trying to recoup their expenses for R&D as +well as certification from the small volumes HSMs are sold in. + +Compared to system integration and certification the pure R&D cost of HSM defense mechanisms themselves is not too high +in an academic context it should be feasible to develop a sort of HSM blueprint that can then be cheaply produced by +anyone in need. Since the application areas outlined here are far from the core business areas of the clients of +established HSM vendors this would most likely not be a realistic threat to any established vendor's business and a +co-existence of both should not pose any problems in the short term. + +Benefits of an academic HSM standard +------------------------------------ + +Tackling the high cost of current HSM hardware with an open-source HSM blueprint would yield +several academic advantages beyond cost reduction. + +1. An open-source blueprint could serve as an academic reference design to evaluate and compare other HSM designs + against. For instance this would not only allow quantifying the effectiveness of academic security measures but also + allow an evaluation of commercial HSMs. +2. An open-source blueprint could stimulate academic research in this academically very quiet albeit commercially + important area. This research would ultimately benefit everyone employing HSMs by raising security standards in the + field. Since HSMs are never solely relied upon for overal system security both defensive and offensive security + research would yield these benefits. +3. An open-source blueprint would encourage new people to get into the field and both apply HSMs to practical problems + as well as improve HSMs themselves. Currently, this is highly discouraged due to the strictly proprietary nature of + all available systems. +4. Finally, developing an open-source HSM blueprint might yield new findings in adjacent academic areas due to the + hightly multi-disciplinary nature of security research in general and HSM design in particular. + +Scope of an academic HSM standard +--------------------------------- + +An academic HSM blueprint would need to be flexible so that researchers can adapt it to their particular problem. A +modular architecture would lend itself to this flexibility. Fundamentally, there would be three components to this +architecture. First, a **base** containing infrastructure such as the surveillance microcontroller, power supplies, +power supply filtering and hardware DPA countermeasures, and possibly a standardized mechanical and electrical +interface. + +Next to the base, a system integrator would put their *payload*. The nature of this payload is intentionally kept +unspecified, and it might be anything from a cryptographic microcontroller to a small embedded system such as a +raspberry pi single board computer. Keeping the *payload* open like this achieves two benefits: It gives the HSM +blueprint's user *their* familiar tooling and the hardware *they* need, allowing fast adoption. Someone well-versed in +e.g. Javascript could literally implement their cryptography in Javascript, run it on an off-the-shelf raspberry pi and +just apply the HSM blueprint around it. In addition, keeping the *payload* open reduces the scope of what needs to be +implemented. Building a general SDK on top of something like a bare ARM SoC such as a TI OMAP or a Freescale/NXP IMX +would be a considerable additional burden, on top of the actual HSM design. Keeping the *payload* open allows research +to concentrate on the actual point, the HSM design. + +The final and most important component would be a set of *security measures* that can be combined with the base to +form the final HSM. Each of these *security measures* would entail a detailed specification of its design, manufacture +and security properties. These *security measures* could be simple things like tamper switches or potting, but could +also be complex things like security meshes. + +Given these three components -- *base*, *payload* and *security measures* as detailed specifications any engineer should +be able to design and manufacture a HSM customized to their needs. Unifying these three components within the HSM +blueprint would be a set of reference designs. Each reference design would implement a particular parametrization of the +three architectural components with a physical hole cut out where the payload would go.. These reference designs would +for one serve to guide any implementer on the customization and integration of their own derivation from the blueprint. +In addition it would serve as an extremely simple, low-cost point of entry into the ecosystem. A curious researcher +could simply replicate the reference design and put their existing payload inside. Practically this might mean e.g. a +researcher having PCBs produced according to the design files for a reference design for a mesh-based HSM, producing +their own mesh, physically glueing a raspberry pi SBC into the middle of it, and potting the resulting system. Given the +ease of prototype PCB fabrication today this would realistically allow evaluation of HSM technologies on a budget that +is orders of magnitude less than the cost of current HSMs. + +Research ideas for tamper detection mechanisms +============================================== + +The core component of an HSM blueprint would be a suite of tamper detection mechanisms. Following are a few ideas on how +to improve on the current state of the art of membrane tamper switches plus temperature sensors plus PCB and printed +security meshes plus potting. + +DIY or small lab mesh production +-------------------------------- +**Analog sensing** meshes are a proven technology where instead of just monitoring for continuity and shorts, analog +parameters of the mesh traces such as inductance and mutual capacitance are monitored. In 2019, `Immler et al. published +a paper `__ where took this principle and turned it all the +way up. They directly derived a cryptographic secret from the analog properties of their HSM's security mesh in an +attempt to built a `Physically Unclonable Function, or PUF +`__. The idea with PUFs is that they reproduce some entropy +that comes from random tolerances of their production process. The same PUF will always yield (approximately) the same +key, but since you cannot control these random production variations, in practice the resulting PUF cannot be cloned. +Note however, that its secrets can of course be copied if you find a way to read them out. + +As Immler et al. demonstrated in their paper, you don't need any secret sauce to create an analog mesh sensing circuit. +All you need are a bunch of (admittedly, expensive) off-the-shelf analog ICs. The interesting bit here is that by +applying more advanced analog sensing, weaknesses of an otherwise coarse mesh desing could maybe be alleviated. That is, +instead of monitoring a very fine mesh for continuity, you could instead closely monitor inductance and capacitance of a +more coarse mesh. This trade-off between sensing circuit complexity (resp. cost) and mesh production capabilities may +allow someone with a poorly equipped lab to still make a decent HSM. The question is, how do you produce a "decent" mesh +given only basic tools? Here are some ideas. + +**3D metal patterning techniques** refers to any technique for producing thin, patterned metal structures on a +three-dimensional plastic substrate. The basic process would consist of 3D-printing the polymer substrate, depositing a +thin metal layer on top and then patterning this metal layer. A good starting point here would be the recent work of +`Ben Kraznow`_ on this exact thing. + +**Copper filament methods** would be any method embedding copper wire from a spool in some resin or other matrix. This +could mean either of a systematic approach of carefully winding or folding the copper wire into patterns or a +non-systematic approach of simply stuffing a large tangle of copper wire into a small space. The main challenge with the +former would be to find a non-tedious way of production. The main challenge with the latter would be to find process +parameters that guarantee complete coverage of the HSM without holes or other areas of lower sensitivity to intrusions. +Both approaches would require careful consideration of the overall design including the polymer resin supporting +structure to ensure sensitivity against attacks since copper wire is mechanically much stronger than the micrometre-thin +metal coatings used in patterning techniques. + +Envelope measurement +-------------------- + +Finally, I think there is another set of currently under-utilized tamper-detection methods that would be very +interesting to explore. I am not aware of an academic term for these, so I am just going to dub them *envelope +measurement* here. + +The fundamental apporach of a mesh is to build a physical security envelope (the mesh) that physically detects when it +is disturbed (open or short circuits). This approach works well but has the disadvantage that these meshes are rather +complex to manufacture since effectively every part of them is acting as a sensing element. A conceptually more complex +but in practice potentially simpler approach might be to split the functions of security envelope and sensing element. +This would mean that in place of the mesh, some form of passive element such as metal foil forms the security envelope +which is then checked for tampering using a very sensitive sensor inside. This remote-sensing approach might simplify +the manufacture of the envelope itself and thus yield a design that is more easily customized. Following are a few ideas +on how to approach this envelope measurement problem. + +**Ultrasonic** If the HSM is potted, a few ultrasonic transducers could be added inside the potting. With several +transducers, any one could be used to transmit ultrasound while the others measure complex phase and energy of the +signal they receive. The circuitry for this could be made fairly simple if using a static transmit frequency or a low +chirp rate by using a homodyne receiver built around a comparator fed into some timers. This approach would likely +detect any mechanical attack and would also rule out chemical attacks involving liquids (though starting from which +amount of liquid depends on receiver sensitivity). The main disadvantages might be high power consumption and cost and +size of the ultrasonic transducers. Traditional cheap transducers made for air as a transmission medium are fairly large +and might not adequately couple into potting compound. If somehow one could convince a standard small piezo element to +do the same job that would be great as far as cost and size are concerned. A concern in some fringe use cases might be +suceptibility to ambient noise, though this could easily be reduced at the expense of space and heat dissipation +capacity by adding sound dampening on the outside. A likely attack vector against this approach might be using a laser +cutter to drill a hole through the potting compound, then inserting probes carefully chosen to not couple too much +to the potting compound ultrasonically. + +**Light** In either an unpotted HSM or one potted with a transparent (at some wavelengths) potting compound one could +embed LEDs and photodiodes in a similar setup to the ultrasonic setup described above. In contrast to the ultrasound, +the LEDs would literally have to light up the HSM's interior and shadows might be an issue since the HSM is likely some +flat rectangular shape. A possible solution to this would be to coat both the embedded payload and the lid with some +highly reflective paint such as some glossy silver paint or simple white paint. The basic approach might be as simple as +simply turning on several LEDs distributed throughout the HSM in turn and measuring amplitude at several photodetectors, +or as complex as doing a LIDAR-like phase measurement sweeping through a range of frequencies to determine not only +absorption but also phase/distance characteristics between emitter LED and detector photodiode. Using some high-gain TIA +along with a homodyne detector (lock-in amplifier) and changing emitter intensity, very precise measurements of both +absorption and phase might be possible, as might be measurements through almost opaque, diffuse potting compounds such +as a grey epoxide resin. The main disadvantages of this method would likely be the need to thoroughly light-proof the +entire HSM (likely by wrapping it in metal foil) and the potentially high cost of transmitter and receiver circuitry +(nice TIAs aren't cheap). To be effective against attacks using e.g. very fine drills and probes the system would likely +have to be very sensitive. + +**Radar** Finally, one could turn to standard radar techniques to fingerprint the inside of the HSM. The goal here would +be fingerprinting instead of mapping since only changes need to be detected. In this approach one could use homodyne +detection to improve sensitivity and reduce receiver complexity, and sweep frequencies similar to an FMCW radar (but +probably without exploiting the self-demodulation effect). Besides high cost, this approach has two disadvantages. +First, such a system would likely not go beyond 24GHz or maybe 40GHz due to component availability issues. Even at 40GHz +the wavelength in the potting compound would be in the order of magnitude of several millimeters. Fine intrusions using +some tool chosen to not interact too much with the EM field inside the HSM such as a heated ceramic needle or simply a +laser cutter might not be detectable using this approach. In any case, this system would certainly not be able to detect +small holes piercing the HSM enclosure. The HSM enclosure would have to be made into an RF shield, likely by using some +metal foil in it. + +Overall in the author's opinion these three techniques are most promising in order *Light*, *Ultrasonic*, *Radar*. Light +would prbably provide the best sensitivity at expense of some cost. Ultrasonic might be used in conjunction with light +to cover some additional angles since it is potentially very low-cost. Radar seems hard to engineer into a solution that +works reliably and also would likely be at least an order of magnitude more expensive than the other two technologies +while not providing better sensitivity. + +.. _`Ben Kraznow`: https://www.youtube.com/watch?v=Z228xymQYho +.. _affordances: https://en.wikipedia.org/wiki/Affordance + diff --git a/content/blog/hsm-basics/mori_semi_hsm_talk_web.pdf b/content/blog/hsm-basics/mori_semi_hsm_talk_web.pdf new file mode 100644 index 0000000..b8b7177 Binary files /dev/null and b/content/blog/hsm-basics/mori_semi_hsm_talk_web.pdf differ diff --git a/content/blog/ihsm-worlds-first-diy-hsm/index.rst b/content/blog/ihsm-worlds-first-diy-hsm/index.rst new file mode 100644 index 0000000..0932fc9 --- /dev/null +++ b/content/blog/ihsm-worlds-first-diy-hsm/index.rst @@ -0,0 +1,41 @@ +--- +title: "New Paper on Inertial Hardware Security Modules" +date: 2021-11-23T23:42:20+01:00 +--- + +World's First DIY HSM +===================== + +Last week, Prof. Dr. Björn Scheuermann and I have `published our first joint paper on Hardware Security Modules +`__. In our paper, we introduce Inertial Hardware Security +Modules (IHSMs), a new way of building high-security HSMs from basic components. I think the technology we demonstrate +in our paper might allow some neat applications where some civil organization deploys a service that no one, not even +they themselves, can snoop on. Anyone can built an IHSM without needing any fancy equipment, which makes me optimistic +that maybe the ideas of the `Cypherpunk movement `__ aren't obsolete +after all, despite even the word "crypto" having been co-opted by radical capitalist environmental destructionists. + +An IHSM is basically an ultra-secure enclosure for something like a server or a raspberry pi that even someone with +unlimited resources would have a really hard time cracking without destroying all data stored in it. The principle of an +IHSM is the same as that of a `normal HSM`_. You have a payload that contains really secret data. There's really no way +to prevent an attacker with physical access to the thing from opening it given enough time and abrasive discs for their +angle grinder. So what you do instead is that you make it self-destruct its secrets within microseconds of anyone +tampering with it. Usually, such HSMs are used for storing credit card pins and other financial data. They're expensive +as fuck, all the while being about the same processing speed as a smartphone. Traditional HSMs use printed or +lithographically patterned conductive foils for their security mesh. These foils are not an off-the-shelf component and +are made in a completely custom manufacturing process. To create your own, you would have to re-engineer that entire +process and probably spend some serious money on production machines. + +Inertial HSMs take the concept of traditional HSMs, but replace the usual tamper detection mesh with a few security mesh +PCBs. These PCBs are coarser than traditional meshes by orders of magnitude, and would alone not even be close to enough +to keep out even a moderately motivated attacker. IHSMs fix this issue by spinning the entire tamper detection mesh at +very high speed. To tamper with the mesh, an attacker would have to stop it. This, in turn, can be easily detected by +the mesh's alarm circuitry using a simple accelerometer as a rotation sensor. + +In our paper, we have shown a working prototype of the core concepts one needs to build such an IHSM. To build an IHSM +you only need a basic electronics lab. I built the prototype in our paper at home during one of Germany's COVID +lockdowns. You can have a look at our code and CAD on `my git `__. What is missing right +now is an integration of all of these fragments into something cohesive that an interested person with the right tools +could go out and build. We are planning to release this sort of documentation at some point, but right now we are +focusing our effort on the next iteration of the design instead. Stay tuned for updates ;) + +.. _`normal HSM`: {{}} diff --git a/content/blog/kicad-mesh-plugin/images/anim.webp b/content/blog/kicad-mesh-plugin/images/anim.webp new file mode 100755 index 0000000..a2244d0 Binary files /dev/null and b/content/blog/kicad-mesh-plugin/images/anim.webp differ diff --git a/content/blog/kicad-mesh-plugin/images/cells-0.svg b/content/blog/kicad-mesh-plugin/images/cells-0.svg new file mode 100755 index 0000000..f1d881c --- /dev/null +++ b/content/blog/kicad-mesh-plugin/images/cells-0.svg @@ -0,0 +1,2444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/kicad-mesh-plugin/images/cells-100.svg b/content/blog/kicad-mesh-plugin/images/cells-100.svg new file mode 100755 index 0000000..efc4f03 --- /dev/null +++ b/content/blog/kicad-mesh-plugin/images/cells-100.svg @@ -0,0 +1,2444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/kicad-mesh-plugin/images/cells-25.svg b/content/blog/kicad-mesh-plugin/images/cells-25.svg new file mode 100755 index 0000000..670ad1a --- /dev/null +++ b/content/blog/kicad-mesh-plugin/images/cells-25.svg @@ -0,0 +1,2444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/kicad-mesh-plugin/images/cells-50.svg b/content/blog/kicad-mesh-plugin/images/cells-50.svg new file mode 100755 index 0000000..3b5a0a3 --- /dev/null +++ b/content/blog/kicad-mesh-plugin/images/cells-50.svg @@ -0,0 +1,2444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/kicad-mesh-plugin/images/cells-75.svg b/content/blog/kicad-mesh-plugin/images/cells-75.svg new file mode 100755 index 0000000..40e7fc4 --- /dev/null +++ b/content/blog/kicad-mesh-plugin/images/cells-75.svg @@ -0,0 +1,2444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/kicad-mesh-plugin/images/grid-vis-plain.svg b/content/blog/kicad-mesh-plugin/images/grid-vis-plain.svg new file mode 100755 index 0000000..80b8d84 --- /dev/null +++ b/content/blog/kicad-mesh-plugin/images/grid-vis-plain.svg @@ -0,0 +1,138 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/kicad-mesh-plugin/images/grid-vis.svg b/content/blog/kicad-mesh-plugin/images/grid-vis.svg new file mode 100755 index 0000000..fbcdafa --- /dev/null +++ b/content/blog/kicad-mesh-plugin/images/grid-vis.svg @@ -0,0 +1,138 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/kicad-mesh-plugin/images/kicad-mesh-outline.png b/content/blog/kicad-mesh-plugin/images/kicad-mesh-outline.png new file mode 100755 index 0000000..fc0d51e Binary files /dev/null and b/content/blog/kicad-mesh-plugin/images/kicad-mesh-outline.png differ diff --git a/content/blog/kicad-mesh-plugin/images/kicad-mesh-result-large.png b/content/blog/kicad-mesh-plugin/images/kicad-mesh-result-large.png new file mode 100755 index 0000000..798287b Binary files /dev/null and b/content/blog/kicad-mesh-plugin/images/kicad-mesh-result-large.png differ diff --git a/content/blog/kicad-mesh-plugin/images/kicad-mesh-settings.png b/content/blog/kicad-mesh-plugin/images/kicad-mesh-settings.png new file mode 100755 index 0000000..72e7e25 Binary files /dev/null and b/content/blog/kicad-mesh-plugin/images/kicad-mesh-settings.png differ diff --git a/content/blog/kicad-mesh-plugin/images/kicad-mesh-settings2.png b/content/blog/kicad-mesh-plugin/images/kicad-mesh-settings2.png new file mode 100755 index 0000000..8da33be Binary files /dev/null and b/content/blog/kicad-mesh-plugin/images/kicad-mesh-settings2.png differ diff --git a/content/blog/kicad-mesh-plugin/images/maze_tiles.svg b/content/blog/kicad-mesh-plugin/images/maze_tiles.svg new file mode 100755 index 0000000..4b71f19 --- /dev/null +++ b/content/blog/kicad-mesh-plugin/images/maze_tiles.svg @@ -0,0 +1,2070 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/kicad-mesh-plugin/images/maze_tiles_plain.svg b/content/blog/kicad-mesh-plugin/images/maze_tiles_plain.svg new file mode 100755 index 0000000..be1f8d5 --- /dev/null +++ b/content/blog/kicad-mesh-plugin/images/maze_tiles_plain.svg @@ -0,0 +1,1731 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/kicad-mesh-plugin/images/modern_art.svg b/content/blog/kicad-mesh-plugin/images/modern_art.svg new file mode 100755 index 0000000..2729b63 --- /dev/null +++ b/content/blog/kicad-mesh-plugin/images/modern_art.svg @@ -0,0 +1,1609 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/kicad-mesh-plugin/images/tiles-25-small.svg b/content/blog/kicad-mesh-plugin/images/tiles-25-small.svg new file mode 100755 index 0000000..21b17ed --- /dev/null +++ b/content/blog/kicad-mesh-plugin/images/tiles-25-small.svg @@ -0,0 +1,14636 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/kicad-mesh-plugin/images/traces-25-small.svg b/content/blog/kicad-mesh-plugin/images/traces-25-small.svg new file mode 100755 index 0000000..af9a8ef --- /dev/null +++ b/content/blog/kicad-mesh-plugin/images/traces-25-small.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/content/blog/kicad-mesh-plugin/index.rst b/content/blog/kicad-mesh-plugin/index.rst new file mode 100644 index 0000000..226f23f --- /dev/null +++ b/content/blog/kicad-mesh-plugin/index.rst @@ -0,0 +1,221 @@ +--- +title: "Kicad Mesh Plugin" +date: 2020-08-18T13:15:39+02:00 +--- + +.. raw:: html + +
+ +
+ +Tamper Detection Meshes +======================= + +Cryptography is at the foundation of our modern, networked world. From email to card payment infrastructure in brick and +mortar stores, cryptographic keys secure almost every part of our digital lives againts cybercriminals or curious +surveillance capitalists. Without cryptography, many of the things we routinely do in our lives such as paying for +groceries with a credit card, messaging a friend on `Signal `_ or unlocking a car with its keyfob +would not be possible. The security of all of these systems in its core lies on the secrecy of cryptographic keys. +Systems differ in what kind of keys they use, how often these keys are replaced and the intricacies of the cryptographic +operations these keys fit into but all have in common that their security relies on keeping the keys secret. + +In practice, this secrecy has been implemented in many different ways. Mass-market software such as browsers or +messenger apps usually relies on some operating system facility to tell the computer "*please keep this piece of memory +away from all other applications*". While on desktop operating systems usually this does not provide much of a barrier +to other programs on the same computer, on modern mobile operating systems this approach is actually quite secure. +However, given sufficient resources no security is perfect. All of these systems can be compromised if the host +operating system is compromised sufficiently, and for organizations with considerable resources a market has sprung up +that offers turn-key solutions for all wiretapping needs. + +In some applications, this level of security has not been considered sufficient. Particularly financial infrastructure +is such a high-profile target that a lot of effort has been put into the security of cryptographic implementations. The +best cryptographic algorithm is useless if it is run on a compromised system (from that system's point of view anyway). +One of the core cryptographic components in financial applications are smartcards like they are used as payment cards in +most countries nowadays. These smartcards contain a small, specialized cryptographic microcontroller that is designed to +be hard to tamper with. Though one of the design goals of the system is to reduce the amount of sensitive information +stored on the card, things such as copying of a card can only be hindered by making the chip hard to read out. + +.. raw:: html + +
+ +
+ +With smartcards being the means of choice on one side of the counter in electronic payments, on the other side of the +counter a different technology prevails. Attacks on payment terminals are bound to have much more dire consequences than +attacks on individual cards since one terminal might see hundreds of cards being read every day. For this reason, the +level of attack countermeasures employed in these terminals is a considerable step up from bare smartcards. While a +smartcard is made physically hard to tamper, it does not have a battery and it can only detect tampering once it is +powered by a reader. This allows for well-equipped attackers to use tools such as Focused Ion Beam (FIB) workstations to +circumvent the smartcard's defences while it is powered down, and then power up the card to carry out the actual attack. + +The answer to this problem in electronic payment infrastructure is called *Hardware Security Module*, or HSM. An HSM is +similar to a smartcard in its function (cryptographic processing using keys that are meant to never leave the protection +of the HSM). The one major between the two is that an HSM has its own battery and is continuously powered from its +manufacture to the day it is scrapped. If the HSM looses power at any point in time, it uses a small amount of energy +stored internally to securely wipe all cryptographic secrets from its memory within a few milliseconds. + +Being powered at all times allows the HSM to actively detect and respond to attacks. The most common way this is done is +by wrapping the juicy secret parts in a foil or a printed circuit board that is patterned with a long and convoluted +maze of wires, called a *mesh*. The HSM is continuously monitoring these wires for changes (such as shorts, breaks or +changes in resistance) and will sound the alarm when any are detected. Practically, this presents a considerable hurdle +to any attacker: They have to find a way to disable or circumvent the mesh while it is being monitored by the HSM. In +practice, often this is no insurmountable challenge but it again increases attack costs. + +DIY Meshes +========== + +Throughout my studies in security research I have always had an interest in HSMs. I have taken apart my fair share of +HSMs and at this point, to understand the technology more, I want to experiment with building my own HSM. In last year's +`HSM basics <{{}}>`_ post I have lined out some ideas for a next generation design that +deviates from the bread-and-butter apporoach of using a mesh as the primary security feature. Before embarking on +practical experiments with these ideas, I want to first take a stab at replicating the current state of the art as best +I can. State of the art meshes often use exotic substrates such as 3D plastic parts with traces chemically deposited on +their surface or special flexible substrates with conductive ink traces. These technologies will likely be too +cumbersome for me to implement myself only for a few prototypes, and industrial manufacturers will most likely be too +expensive. Thus, I will concentrate on regular PCB technology for now. + +The idea of a mesh on a PCB is pretty simple: You have one or several traces that you try to cover every corner of the +mesh PCB's area with. To be most effective, the traces should be as thin and as close together as possible. To increase +the chances of a manipulation being detected, multiple traces can also be used that can then be monitored for shorts +between them. + +While one can feasibly lay out these traces by hand, this really is an ideal application of a simple auto-router. While +general PCB autorouting is *hard*, auto-routing just a few traces to approximate a space-filling curve is not. Since I +am just starting out, I went with the simplest algorithmic solution I could think of. I first approximate the area +designated to the mesh with a square grid whose cells are a multiple of my trace/space size. The mesh will only be drawn +into grid cells that are fully inside the set boundaries. All cells outside or going across the border are discarded in +this step. + +I decided to implement this auto-router in a KiCAD plugin. Though KiCADs plugin API is not the best, it was just about +usable for this task. + +.. raw:: html + +
+ KiCAD showing an irregular board shape with rounded corners and
+        indents. In the middle of the board there is a footprint for a 4-pin surface-mount pin header. +
The process starts out with the mesh shape being defined inside KiCAD. The mesh's outline is drawn + onto one of the graphical "Eco" layers. A footprint is placed to serve as a placeholder for the mesh's + connections to the outside world. This footprint is later used as the starting point for the mesh generation + algorithm.
+
+ +.. raw:: html + +
+ A vizualization of the grid fitting process. Over the mesh's irregular
+        outline a grid is drawn. In this picture, all grid cells that are fully inside the grid are shown. Grid cells
+        that overlap the mesh border are highlighted. Grid cells outside of the mesh border are not drawn. +
A visualization of the grid fitting process. First, a grid large enough to contain the mesh border + is generated. Then, every cell is checked for overlap with the mesh border area. If the cell is fully inside, it + (yellow), it is considered in the mesh generation later. Cells outside (gray) or on the border (red) are + discarded.
+
+ +After generating the grid, starting from the place I want to connect to the mesh, I walk the grid's cells one by one to +generate a tree that covers the entire grid's area. To set the mesh's starting place I place a footprint on the board +(dark gray in the picture above) whose designator I then tell my script. The tree generation algorithm looks like a +depth-first search, except all checks are random. Depending on the level of randomness used at each step of the +algorithm it yields more or less organized-looking results. Below are five example runs of the algorithm at differing +levels of randomness with the cells colored according to their distance from the tree root. 0% randomness means that the +algorithm is going to try cells in forward direction first on every step, and only then try out left and right. 100% +means that on every step, the algorithm is choosing a new direction at random. + +.. raw:: html + +
+
+ a completely organized looking grid with spiral patterns all over. +
0%
+
+ +
25%
+
+ +
50%
+
+ +
75%
+
+ a completely random looking grid with cells aggregating into ireggular
+        areas that look like paint splotches. +
100%
+
+
+ +After I have built this tree like you would do in a depth-first search, I draw my one or several mesh mesh traces into +it. The core observation here is that there is only 16 possible ways a cell can be connected: It has four neighbors, +each of which it can either be connected to or not, which results in 2^4 options. If you consider rotations and +mirroring, this works out to rotations or mirrored versions of only six base tiles: The empty tile, a tile with all four +sides connected, a straight through, a 90 degree bend, and a "T"-junction—see the illustration below. + +.. raw:: html + +
+ +
+ There are six possible tile types in our connectivity graph inside its square tiling. This graphic illustrates + all sixteen rotations of these with how they would look in a two-conductor mesh. +
+
+ +After tiling the grid according to the key above, we get the result below. + +.. raw:: html + +
+ +
+ An auto-routed mesh with traces colored according to tile types. +
+
+ +.. raw:: html + +
+ +
+ The same mesh, but with traces all black. +
+
+ +Putting it all together got me the KiCAD plugin you can see in the screenshot below. + +.. raw:: html + +
+ +
+ The plugin settings window open. +
+
+ +.. raw:: html + +
+ +
+ After runing the plugin, the generated mesh looks like this in pcbnew. +
+
+ +I am fairly happy with the result, but getting there was a medium pain. Especially KiCAD's plugin API is still very +unfinieshed. It is hard to use, most parts are completely undocumented and if you use anything but its most basic parts +things tend to break. One particular pain point for me was that after generating the mesh, the traces have been added to +the board, but are still invisible for some reason. You have to save the board first, then re-load the file for them to +become visible. Also KiCAD crashes whenever the plugin tries to remove a trace, so currently my workflow involves always +making a copy of the board file first and treating mesh generation as a non-reversible finishing step. + +`Check out the code on my cgit `_. + +.. :: + + .. raw:: html + +
+ +
+
+ diff --git a/content/blog/led-characterization/images/daylight_spectrum_dvd.jpg b/content/blog/led-characterization/images/daylight_spectrum_dvd.jpg new file mode 100644 index 0000000..d01242e Binary files /dev/null and b/content/blog/led-characterization/images/daylight_spectrum_dvd.jpg differ diff --git a/content/blog/led-characterization/images/driver_ringing_strong.jpg b/content/blog/led-characterization/images/driver_ringing_strong.jpg new file mode 100644 index 0000000..0419a0e Binary files /dev/null and b/content/blog/led-characterization/images/driver_ringing_strong.jpg differ diff --git a/content/blog/led-characterization/images/driver_ringing_weak.jpg b/content/blog/led-characterization/images/driver_ringing_weak.jpg new file mode 100644 index 0000000..12f9c5d Binary files /dev/null and b/content/blog/led-characterization/images/driver_ringing_weak.jpg differ diff --git a/content/blog/led-characterization/images/electronics_whole.jpg b/content/blog/led-characterization/images/electronics_whole.jpg new file mode 100644 index 0000000..faaf751 Binary files /dev/null and b/content/blog/led-characterization/images/electronics_whole.jpg differ diff --git a/content/blog/led-characterization/images/hsv_cylinder.png b/content/blog/led-characterization/images/hsv_cylinder.png new file mode 100644 index 0000000..265f3e0 Binary files /dev/null and b/content/blog/led-characterization/images/hsv_cylinder.png differ diff --git a/content/blog/led-characterization/images/photodiode_sensitivity.svg b/content/blog/led-characterization/images/photodiode_sensitivity.svg new file mode 100644 index 0000000..e845444 --- /dev/null +++ b/content/blog/led-characterization/images/photodiode_sensitivity.svg @@ -0,0 +1,874 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/led-characterization/images/preamp_back.jpg b/content/blog/led-characterization/images/preamp_back.jpg new file mode 100644 index 0000000..0af495d Binary files /dev/null and b/content/blog/led-characterization/images/preamp_back.jpg differ diff --git a/content/blog/led-characterization/images/preamp_front.jpg b/content/blog/led-characterization/images/preamp_front.jpg new file mode 100644 index 0000000..62fad28 Binary files /dev/null and b/content/blog/led-characterization/images/preamp_front.jpg differ diff --git a/content/blog/led-characterization/images/preamp_schematic.jpg b/content/blog/led-characterization/images/preamp_schematic.jpg new file mode 100644 index 0000000..6be7bbd Binary files /dev/null and b/content/blog/led-characterization/images/preamp_schematic.jpg differ diff --git a/content/blog/led-characterization/images/processed_plot_cheap_rgb.svg b/content/blog/led-characterization/images/processed_plot_cheap_rgb.svg new file mode 100644 index 0000000..9745172 --- /dev/null +++ b/content/blog/led-characterization/images/processed_plot_cheap_rgb.svg @@ -0,0 +1,2366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/led-characterization/images/raw_plot_cheap_rgb.svg b/content/blog/led-characterization/images/raw_plot_cheap_rgb.svg new file mode 100644 index 0000000..895569f --- /dev/null +++ b/content/blog/led-characterization/images/raw_plot_cheap_rgb.svg @@ -0,0 +1,2739 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/led-characterization/images/rgb_cube.svg b/content/blog/led-characterization/images/rgb_cube.svg new file mode 100644 index 0000000..8af7a00 --- /dev/null +++ b/content/blog/led-characterization/images/rgb_cube.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + G+ + + + + + + + + R+ + + + + B+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + R- + + + + B- + + + + + + + + G- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + R : 83 + + + G : 150 + + + B : 60 + + G: 150 + B: 60 + R: 83 + + + + + + + + R + G + B + + + R + G + B + + + R 255 + G 255 + B 255 + + + + + \ No newline at end of file diff --git a/content/blog/led-characterization/images/spectrograph_step1_parts.jpg b/content/blog/led-characterization/images/spectrograph_step1_parts.jpg new file mode 100644 index 0000000..107220a Binary files /dev/null and b/content/blog/led-characterization/images/spectrograph_step1_parts.jpg differ diff --git a/content/blog/led-characterization/images/spectrograph_step2.jpg b/content/blog/led-characterization/images/spectrograph_step2.jpg new file mode 100644 index 0000000..b678372 Binary files /dev/null and b/content/blog/led-characterization/images/spectrograph_step2.jpg differ diff --git a/content/blog/led-characterization/images/spectrograph_step3.jpg b/content/blog/led-characterization/images/spectrograph_step3.jpg new file mode 100644 index 0000000..acd6d5e Binary files /dev/null and b/content/blog/led-characterization/images/spectrograph_step3.jpg differ diff --git a/content/blog/led-characterization/images/spectrograph_step4_complete.jpg b/content/blog/led-characterization/images/spectrograph_step4_complete.jpg new file mode 100644 index 0000000..d23560d Binary files /dev/null and b/content/blog/led-characterization/images/spectrograph_step4_complete.jpg differ diff --git a/content/blog/led-characterization/images/zeus_hammer_breadboard.jpg b/content/blog/led-characterization/images/zeus_hammer_breadboard.jpg new file mode 100644 index 0000000..08efebb Binary files /dev/null and b/content/blog/led-characterization/images/zeus_hammer_breadboard.jpg differ diff --git a/content/blog/led-characterization/images/zeus_hammer_breadboard_original.jpg b/content/blog/led-characterization/images/zeus_hammer_breadboard_original.jpg new file mode 100644 index 0000000..4f8f34e Binary files /dev/null and b/content/blog/led-characterization/images/zeus_hammer_breadboard_original.jpg differ diff --git a/content/blog/led-characterization/images/zeus_hammer_schematic.jpg b/content/blog/led-characterization/images/zeus_hammer_schematic.jpg new file mode 100644 index 0000000..0e6f483 Binary files /dev/null and b/content/blog/led-characterization/images/zeus_hammer_schematic.jpg differ diff --git a/content/blog/led-characterization/images/zeus_hammer_schematic_original.jpg b/content/blog/led-characterization/images/zeus_hammer_schematic_original.jpg new file mode 100644 index 0000000..b50b3a0 Binary files /dev/null and b/content/blog/led-characterization/images/zeus_hammer_schematic_original.jpg differ diff --git a/content/blog/led-characterization/index.rst b/content/blog/led-characterization/index.rst new file mode 100644 index 0000000..6ad4d64 --- /dev/null +++ b/content/blog/led-characterization/index.rst @@ -0,0 +1,504 @@ +--- +title: "LED Characterization" +date: 2018-05-02T11:18:38+02:00 +--- + +Preface +------- + +Recently, I have been working on a `small driver`_ for ambient lighting using 12V LED strips like you can get +inexpensively from China. I wanted to be able to just throw one of these somewhere, stick down some LED tape, hook it up +to a small transformer and be able to control it through Wifi. When I was writing the firmware, I noticed that when +fading between different colors, the colors look *all wrong*! This observation led me down a rabbit hole of color +perception and LED peculiarities. + +The idea of the LED driver was that it can be used either with up to eight single-color LED tapes or, much more +interesting, with up to two RGB or RGBW (red-green-blue-white) LED tapes. For ambient lighting high color resolution was +really important so you could dim it down a lot without flickering. I ended up using the same driver stage I used in the +`multichannel LED driver`_ project for its great color resolution and low hardware requirements. + +.. raw:: html + +
+ An illustration of the RGB color cube. +
An illustration of the RGB color cube. + Picture by + Maklaan from Wikimedia Commons, + CC-BY-SA 3.0 +
+
+ +To make setting colors over Wifi more intuitive I implemented support for HSV colors. RGB is fine for communication +between computers, but I think HSV is easier to work with when manually inputting colors from the command line. RGB is +close to how most monitors, cameras and the human visual apparatus work on a very low level but doesn't match +higher-level human color perception very well. When we describe a color we tend to think in terms of "hue" or +"brightness", and computing a measure of those from RGB values is not easy. + +Colors and Color Spaces +----------------------- + +`Color spaces`_ are a mathematical abstraction of the concept of color. When we say "RGB", most of the time we actually +mean `sRGB`_, a standardized notion of how to map three numbers labelled "red", "green" and "blue" onto a perceived +color. `HSV`_ is an early attempt to more closely align these numbers with our perception. After HSV, a number of other +*perceptual* color spaces such as `XYZ (CIE 1931)`_ and `CIE Lab/LCh`_ were born, further improving this alignment. In +this mathematical model, mapping a color from one color space into another color space is just a coordinate +transformation. + +.. raw:: html + +
+ An illustration of the HSV color space as a cylinder. +
An illustration of the HSV color space as a cylinder. + Picture by + SharkD from Wikimedia Commons, + CC-BY-SA 3.0 +
+
+ +CIE 1931 XYZ is much larger than any other color space, which is why it is a good basis to express other color spaces +in. In XYZ there are many coordinates that are outside of what the human eye can perceive. Below is an illustration of +the sRGB space within XYZ. The wireframe cube is (0,0,0) to (1,1,1) in XYZ. The colorful object in the middle is what +of sRGB fits inside XYZ, and the lines extending out from it indicate the space that can be expressed in sRGB but not in +XYZ. The fat white curve is a projection of the *monochromatic spectral locus*, that is the curve of points you get in +XYZ for pure visible wavelengths. + +As you can see, sRGB is *much* smaller than XYZ or even the part within the monochromatic locus that we can perceive. In +particular in the blues and greens we loose *a lot* of colors to sRGB. + +.. raw:: html + +
+ +
Illustration of the measured sRGB color space within XYZ. The thick, white line is the spectral + locus. + + mkv/h264 download / + webm download +
+
+ +The wrong colors I got when fading between colors were caused by this coordinate transformation being askew. Thinking +over the problem, there are several sources for imperfections: + +* The LED driver may not be entirely linear. For most modulations such as PWM the brightness will be linear starting + from a certain value, but there is probably an offset caused by imperfect edges of the LED current. This offset can be + compensated with software calibration. I built a calibration setup for driver linearity in the `multichannel LED + driver`_ project. Below are pictures of ringing on the edges of an LED driver's waveform. + +* The red, green and blue channels of the LEDs used on the LED tape are not matched. This skews the RGB color space. + In practice, the blue channel of my RGB tape to me *looks* much brighter than the red channel. + +* The precise colors of the red, green and blue channels of the LEDs are unknown. Though the red channel *looks* red, it + may be of a slightly different hue compared to the reference red used in `sRGB`_ which would also skew the RGB color + space. + +.. raw:: html + +
+
+ Strong ringing on the LED voltage waveform edge at about
+            100% overshoot during about 70% of the cycle time. +
The LED strip being at the end of a couple meters of wire caused extremely bad ringing at high + driving frequencies.
+
+
+ Weak ringing on the LED voltage waveform edge at about 30%
+            overshoot during about 20% of the cycle time. +
Adding a resistor in front of the MOSFET gate to slow the transition dampened the ringing + somewhat, but ultimately it cannot be eliminated entirely.
+
+
+ +These last two errors are tricky to compensate. What I needed for that was basically a model of the *perceived* colors +of the LED tape's color channels. A way of doing his is to record the spectra of all color channels and then evaluate +their respective XYZ coordinates. If all three channels are measured in one go with the same setup the relative +magnitudes of the channels in XYZ will be accurate. + +To map any color to the LEDs, the color's XYZ coordinates simply have to be mapped onto the linear coordinate system +produced by these three points within XYZ. LEDs are mostly linear in their luminous flux vs. current characteristic so +this model will be adequate. The spectral integrals mapping the channels' measured responses to XYZ need only be +calculated once and their results can be used as scaling factors thereafter. + +Measuring the spectrum +---------------------- + +In order to compensate for the cheap LED tape's non-ideal performance I had to measure the LED's red, green and blue +channels' spectra. The obvious thing would be to go out and buy a `spectrograph`_, or ask someone to borrow theirs. The +former is kind of expensive, and I did not want to wait two weeks for the thing to arrive. The latter I could probably +not do every time I got new LED tape. Thus the only choice was to build my own. + +Luckily, building your own spectrometer is really easy. The first thing you need is something that splits incident light +into its constituent wavelengths. In professional devices this is called the *`monochromator`_*, since it allows extraction +of small color bands from the spectrum. The second thing is some sort of optics that project the incident light onto a +screen behind the monochromator. In professional devices lenses or curved mirrors are used. In a simple homebrew job a +pinhole as you would use in a `camera obscura`_ does a remarkably nice job. + +For the monochromator component several things could be used. A prism would work, but I did not have any. The +alternative is a `diffraction grating`_. Professional gratings are quite specialized pieces of equipment and thus +rather expensive. Luckily, there is a common household item that works almost as well: A regular CD or DVD. The +microscopic grooves that are used to record data in a CD or DVD work the same as the grooves in a professional +diffraction grating. + +Household spectra +----------------- + +From this starting point, a few seconds on my favorite search engine yielded an `article by two researchers from the +National Science Museum in Tokyo`_ providing a nice blueprint for a simple cardboard-and-DVD construction for use in +classrooms. I replicated their device using a DVD and it worked beautifully. Daylight and several types of small LEDs I +had around did show the expected spectra. Small red, yellow, green, and blue LEDs showed narrow spectra, daylight one +continuous broad one, and white LEDs a continuous broad one with a distinct bright spot in the blue part. The +single-color LED spectra are quite narrow since they are determined by the LED's semiconductor's band gap, which is +specific to the semiconductor used and is quite precise. White LEDs are in fact a blue LED chip covered with a so-called +*phosphor*. This phosphor is not elementary phosphorus but an anorganic compound that absorbs the LED chip's blue light +and re-emits a broader spectrum of more yellow-ish wavelengths instead. The final LED spectrum is a superposition of +both spectra, with some of the original blue light leaking through the phosphor mixing with the broadband yellow +spectrum of the phosphor. + +.. raw:: html + +
+
+ +
The ingredients. The cup of coffee and Madoka Magica DVD set are essential to the eventual + function of the appartus.
+
+
+ +
Step 1: Cut to size and mark down all holes as described in the manual
+
+
+ +
Step 2: Cut out all holes
+
+
+ +
The finished result with the back side showing. The viewing window is on the bottom of the other + side.
+
+
+ + +Now that I had a spectrograph, I needed a somewhat predictable way of measuring the spectrum it gave me. + +Measuring a spectrum +-------------------- + +Pointing a camera at the spectrograph would be the obvious thing to do. This produces pretty images but has one critical +flaw: I wanted to acquire quantitative measurements of brightness across the spectrum. Since I don't have a precise +technical datasheet specifying the spectral response of any of my cameras I can't compare the absolute brightness of +different colors on their pictures. Some other sensor was needed. + +.. raw:: html + +
+ +
The daylight spectrum as seen using a DVD as a grating. + Picture by + Xofc from Wikimedia Commons, + CC-BY-SA 4.0 +
+
+ + +Measuring light intensity +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Looking around my lab, I found a bag of `SFH2701`_ visible-light photodiodes. Their +datasheet includes their spectral response so I can compensate for that, allowing precise-ish absolute intensity +measurements. Just like LEDs, photodiodes are extremely linear across several orders of magnitude. The datasheet of the +classic `BPW34`_ photodiode shows that this photodiode's light current is exactly proportional to illuminance over at +least three orders of magnitude. The `SFH2701`_ datasheet does not include a similar graph but its performance will be +similar. The `SFH2701`_ photodiodes I had at hand were perfect for the job compared to the vintage `BPW34`_ since their +active sensing area is really small (0.6mm by 0.6mm) compared to the BPW34 (a whopping 3mm by 3mm). If I were to use a +`BPW34`_ I would have to insert some small apterture in front of it so it does not catch too broad a part of the +spectrum at once. The `SFH2701`_ is small enough that if I just point it at the projected spectrum directly I will +already get only a small part of the spectrum inside its 0.6mm active area. + +To convert the photodiode's tiny photocurrent into a measurable voltage I built another copy of the `transimpedance +amplifier`_ circuit I already used in the `multichannel LED driver`_. A `transimpedance amplifier`_ is an +amplifiert that produces a large voltage from a small current. The weird name comes from the fact that it works kind of +like an amplified resistor (which can be generalized as an *impedance* electrically). Apply a current to a resistor and +you get a voltage. A transimpedance amplifiert does the same with the difference that its input always stays at 0V, +making it look like an ideal current sink to the connected current source. + +Transimpedance amplifiers are common in optoelectronics to convert small photocurrents to voltages. In this instance I +built a very simple circuit with a dampened transimpedance amplifier stage followed by a simple RC filter for noise +rejection and a regular non-inverting amplifier using another op-amp from the same chip to further boost the filtered +transimpedance amplifier output. I put all the passives setting amplifier response (the gain-setting resistors and the +filter resistor and capacitors) on a small removable adapter so I could easily change them if necessary. I put a small +trimpot on the virtual ground both amplifers use as a reference so I could trim that if necessary. + +.. raw:: html + +
+ A drawing of the photodiode preamplifier's schematic +
The photodiode preamplifier schematic. Schematic drawn with an unlicensed copy of + DaveCAD.
+
+ +Following are pictures of the preamplifier board. The connectors on the top-left side are two copies of the analog +signal for the ADC and a small panel meter. The SMA connector is used as the photodiode input since coax cables are +generally low-leakage and have built-in shielding. The circuit is powered via the micro-USB connector and the analog +ground bias voltage can be adjusted using the trimpot. + +For easy replacement, all passives setting gain and frequency response are on a small, pluggable carrier PCB made from a +SMD-to-DIP adapter. + +Flying-wire construction is just fine for this low-frequency circuit. In a high-speed photodiode preamp, the +transimpedance amplifier circuit would be highly sensitive to stray capacitance, but we're not aiming at high speed +here. + +.. raw:: html + +
+
+ +
The front side of the preamplifier board.
+
+
+ +
The wiring of the photodiode preamp.
+
+
+ +Given a way to measure intensity what remains missing is a way to scan a single photodiode across the spectrum. + +Scanning the projection +~~~~~~~~~~~~~~~~~~~~~~~ + +A cheap linear stage can be found in any old CD or DVD drive. These drives use a small linear stage based on a +stepper-driven screw to move the laser unit radially. Removing the laser unit and connecting a leftover stepper driver +module I was left with a small linear stage with about 45 steps per cm without microstepping enabled. The driver I used +was an `A4988`_ module that required at least 8V motor drive voltage. I used a small micro USB-input boost converter +module to generate a stable 10V supply for the motor driver, with the USB's 5V rail used as a logic supply for the motor +driver. + +The `SFH2701`_ can easily be mounted to the linear stage using a small SMD breakout board glued in place with thin wires +connecting it to the transimpedance amplifier. The DVD drive linear stage is not very strong so it is important that +this wire does not put too much strain on it. + +Above the photodiode, I mounted a small piece of paper on the linear stage to be used as a projection screen to align +the linear stage in front of the spectrometer viewing window. A line on the screen paper points to the photodiode die in +parallel to the linear stage allowing precise alignment. + +The whole unit with photodiode preamplifier, linear stage, photodiode and stepper motor driver finally looks like this: + +.. raw:: html + +
+ The complete electronics setup of the spectrograph. In the back
+        there is the DVD drive stepper stage. In front of it, mounted on a piece of wood are a small USB-to-12V
+        switching-regulator module to power the stepper motor in the top left, below on the bottom left is the
+        photodiode preamp and on the right is a breadboard with the stepper driver module and lots of jumper wires
+        interconnecting everything. On the right of the breadboard, a buspirate is attached to interface everything to a
+        computer. On the bottom edge of the piece of wood, two LED panel meters are mounted for readout of the preamp
+        output and the stepper supply voltages. +
The complete electronics setup. The buspirate on the right interfaces to a computer and controls the + stepper driver and ADC'es the preamp output. The two panel meters show the preamp output and stepper voltage for + setup.
+
+ +The projection of the spectrum can be adjusted by moving the light source relative to the entry slot and by moving +around the grating DVD. + +The capture process +~~~~~~~~~~~~~~~~~~~ + +To capture a spectrum, first the light source has to be mounted near the spectrograph's entry slot. The LED tape I +tested I just taped face-down directly into it. Next, the grating DVD has to be adjusted to make sure the spectrum +covers a sensible part of the photodiode's path. Mostly, this boils down to adjusting the photodiode distance and height +to match the vertical extent and wiggling the grating DVD to adjust the projection's horizontal position. + +After the optics are set-up, the photodiode preamplifier has to be adjusted. In my experiments, most LED tape at 5GΩ +required a high-ish amplification. The goal in this step is to maximize the peak response of the preamp to be just +shy of its VCC rail to make best use of its dynamic range. To adjust the pre-amp, I took several very coarsely-spaced +measurements to give me an estimate of the peak while I did not yet know its precise location. + +Since stray daylight totally swamped out the weak projection of the LED's spectrum I shielded the entire setup with a +small box made of black cardboard and two black t-shirts on top. This shielding proved adequate for all my measurements +but I had to be careful not to accidentially move the DVD that was stuck into the spectrograph with the shielding +t-shirts. + +For capturing a single spectrum I wrote a small python script that will automatically move the stepper in adjustable +intervals and take two measurements at each point, one with the LED tape off that can be used for offset calibration and +one with the LED tape on. All measurements are stored in a sqlite database that can then be accesssed from other +scripts. + +I built a small script that shows the progress of the current run and an jupyter notebook for data analysis. The jupyter +notebook is capable of live-updating a graph with the in-progress spectrum's data. This was quite useful as a sanity +check for when I made some mistake easy to spot in the resulting data. + +After one color channel is captured, the LED tape has to be manually set to the next color and the next measurement can +begin. + +.. raw:: html + +
+ A plot with three wide peaks, two large peaks on both sides and
+        one smaller one in the middle. The middle one overlaps the two on the sides. The large ones are about 2.5V in
+        amplitude. Overall, the plot is about 300 stepper steps wide with each peak being around 130 steps wide. +
A plot of the raw preamp output voltage versus stepper position. From left to right, the three peaks + are blue, green and red. Step 0 corresponds to the bottommost stepper position and the shortest wavelength. +
+
+ + +Data analysis +~~~~~~~~~~~~~ + +Data analysis consists of three major steps: Offset- and stray light removal, wavelength and amplitude calibration and +color space mapping. + +Offset removal +************** +The first task is to remove the offset caused by dark current as well as stray light of the LED's bright primary +reflection on the DVD. The LED is very bright and only a small part of its light gets reflected by the grating towards +the photodiode screen. The remaining part of the light is reflected onto the table in front of the DVD spectrograph. +Though I covered all of this with black cardboard, some of that light ultimately gets reflected onto the photodiode. +This causes a large offset, in particular in the blue part of the spectrum since in this part the photodiode is closest +to the spectrograph's opening. + +The composite offset can be approximated with a second-order polynomial that is fitted to all the data outside of the +main peak's area. Since at this point the wavelength of each data point is still unknown this is done with a rough first +estimate of the three colors' peaks' locations and widths. + +Wavelength- and amplitude calibration +************************************* +The photodiode's response is strongly wavelength-dependent. In particular in the blue band, the photodiode's sensitivity +gets very poor down to about 20% at the edge to ultraviolet. This effect is strong enough to move the apparent location +of the blue peak towards red. + +.. raw:: html + +
+ A plot of photodiode sensitivity against wavelength relative
+        to peak sensitivity at 820nm.  The sensitivity rises from 20% at 380nm approximately linearly to 80% at 620nm,
+        then the rise rolls off. +
A plot of the photodiode's relative sensitivity in the visible spectrum. The sensitivity is + normalized against its peak at 820nm. +
+
+ +The problem is that in order to remove this non-linearity, we would already have to know the wavelength of the measured +light. Since I don't, I settled for a two-step process. First, a coarse wavelength calibration is done relative to the +red peak and the short-wavelength edge of the blue peak. The photodiode measurements are then sensitivity-corrected +using this coarse measurement. Then all three channel peaks are measured in the resulting data and a fine wavelength +estimate is produced by a least-squares fit of a linear function. This fine estimate is then used for a second +sensitivity correction of all original measurements and the scale is changed from stepper motor step count to +wavelength in nanometers. + +.. raw:: html + +
+ A plot with three wide peaks, all three of different
+        heights. The leftmost peak is highest at 6nA, the middle peak lowest at 1.6nA and the rightmost peak in between
+        at 4nA.  The middle one overlaps the two on the sides.  Overall, the plot spans about 300nm on its x axis with
+        each peak being around 100nm wide. +
A plot of the processed measurements. From left to right, the three peaks are blue, green and red. +
+
+ +.. FIXME re-do these measurements, avoiding clipping +.. FIXME re-do calibration using CCFL +.. FIXME calibration for brightness imbalance due to wedge-shaped projection of spectrum + +Color space mapping +******************* +Finally, to achieve the objective of measuring the LED tape's channels' precise color coordinates the measured spetra +have to be matched against the color spaces' *color matching functions*. The color matching functions describe how +strong the color space's idealized *standard observer* would react to light at a particular wavelength. Going from a +measured spectrum to color coordinates XYZ works by integrating over the product of the measurement and each color +coordinate's color matching function. + +The result are three color coordinates X, Y and Z for each channel R, G and B yielding nine coordinates in total. When +written as a matrix conversion between XYZ color space and LED-RGB color space is as simple as multiplying that matrix +(or its inverse) and a vector from one of the color spaces. + +In XYZ space, the set of colors that can be produced with this LED tape is described by the `parallelepiped`_ spanned by +the three channel's XYZ vectors. In the following figures, you can see a three-dimensional model of the RGB LED's color +space (colorful) as well as sRGB (white) for comparison plotted within CIE 1931 XYZ. There is no natural map to scale +both so for this illustration the LED color space has been scaled to fit. These figures were made with blender and a few +lines of python. The blender project file including all settings and the python script to generate the color space +models can be found in the `project repo`_. + +.. raw:: html + +
+ +
Illustration of the measured LED color space scaled to fit within XYZ with sRGB (light gray) for + comparison. The thick, white line is the spectral locus. + + mkv/h264 download / + webm download +
+
+ +As you can see, the result is pretty disappointing. The LED's color space parallepiped is very narrow, which is because +the blue channel is much brighter than the other two channels. An easy fix for this is to scale-up the RGB space and +drop any values outside XYZ. The scaling factor is a trade-off between color space coverage and brightness. You can +produce the most colors when you clip all channels to brightness of the weakest channel (green in this case), but that +will make the result very dim. Scaling brightness like that stretches the RGB parallelepiped along its major axis. Up to +a point the number of possible colors (the gamut) increases at expense of maximum brightness. When the parallelepiped is +stretched far enought for all three channel vectors to be outside the 1,1,1 XYZ-cube, maximum brightness continues to +decrease but the gamut stays constant. I don't know a simple scientific way to solve this problem, so I just played +around with a couple of factors and settled on 2.5 as a reasonable compromise. Below is an illustration. + +.. raw:: html + +
+ +
Illustration of the measured LED color space at scale factor 2.5 within XYZ with sRGB (light gray) + for comparison. The thick, white line is the spectral locus. + + mkv/h264 download / + webm download +
+
+ +Firmware implementation +----------------------- +In the end, the above measurements yield two matrices: One for mapping XYZ to RGB, and one for mapping RGB to XYZ. Of +the several versions of CIE XYZ I chose the CIE 1931 XYZ color space as a basis for the firmware because it is most +popular. Mapping a color coordinate in one color space to the other is as simple as performing nine floating-point +multiplications and six additions. Mapping Lab or Lch to RGB is done by first mapping Lab/Lch to XYZ, then XYZ to RGB. +Lab to XYZ is somewhat complex since it requires a floating-point power for gamma correction, but any self-respecting +libc will have one of those so this is still no problem. Lch also requires floating-point sine and cosine functions, but +these should still be no problem on most hardware. + +My implementation of these conversions in the ESP8266 firmware of my `Wifi LED driver`_ can be found `on Github`_. You +can view the Jupyter notebook most of the analysis above `here `__. + +.. _`on Github`: https://github.com/jaseg/esp_led_drv/blob/master/user/led_controller.c +.. _`project repo`: https://github.com/jaseg/led_drv +.. _`Wifi LED driver`: {{}} +.. _`small driver`: {{}} +.. _`multichannel LED driver`: {{}} +.. _`sRGB`: https://en.wikipedia.org/wiki/SRGB +.. _`CC BY-SA 3.0`: https://creativecommons.org/licenses/by-sa/3.0 +.. _`Color spaces`: https://en.wikipedia.org/wiki/Color_space +.. _`HSV`: https://en.wikipedia.org/wiki/HSL_and_HSV +.. _`CIE Lab/LCh`: https://en.wikipedia.org/wiki/Lab_color_space +.. _`XYZ (CIE 1931)`: https://en.wikipedia.org/wiki/CIE_1931_color_space +.. _`camera obscura`: https://en.wikipedia.org/wiki/Pinhole_camera +.. _`article by two researchers from the National Science Museum in Tokyo`: http://www.candac.ca/candacweb/sites/default/files/BuildaSpectroscope.pdf +.. _`spectrograph`: https://en.wikipedia.org/wiki/Ultraviolet%E2%80%93visible_spectroscopy +.. _`monochromator`: https://en.wikipedia.org/wiki/Monochromator +.. _`diffraction grating`: https://en.wikipedia.org/wiki/Diffraction_grating +.. _`SFH2701`: https://dammedia.osram.info/media/resource/hires/osram-dam-2495903/SFH%202701.pdf +.. _`BPW34`: http://www.vishay.com/docs/81521/bpw34.pdf +.. _`transimpedance amplifier`: https://en.wikipedia.org/wiki/Transimpedance_amplifier +.. _`A4988`: https://www.pololu.com/file/0J450/A4988.pdf +.. _`parallelepiped`: https://en.wikipedia.org/wiki/Parallelepiped diff --git a/content/blog/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv b/content/blog/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv new file mode 100644 index 0000000..0a1eece Binary files /dev/null and b/content/blog/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv differ diff --git a/content/blog/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.webm b/content/blog/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.webm new file mode 100644 index 0000000..04d355c Binary files /dev/null and b/content/blog/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.webm differ diff --git a/content/blog/led-characterization/video/led_within_srgb_scale=1.0.mkv b/content/blog/led-characterization/video/led_within_srgb_scale=1.0.mkv new file mode 100644 index 0000000..69dfccf Binary files /dev/null and b/content/blog/led-characterization/video/led_within_srgb_scale=1.0.mkv differ diff --git a/content/blog/led-characterization/video/led_within_srgb_scale=1.0.webm b/content/blog/led-characterization/video/led_within_srgb_scale=1.0.webm new file mode 100644 index 0000000..8034882 Binary files /dev/null and b/content/blog/led-characterization/video/led_within_srgb_scale=1.0.webm differ diff --git a/content/blog/led-characterization/video/led_within_srgb_scale=2.5.mkv b/content/blog/led-characterization/video/led_within_srgb_scale=2.5.mkv new file mode 100644 index 0000000..a7fba0b Binary files /dev/null and b/content/blog/led-characterization/video/led_within_srgb_scale=2.5.mkv differ diff --git a/content/blog/led-characterization/video/led_within_srgb_scale=2.5.webm b/content/blog/led-characterization/video/led_within_srgb_scale=2.5.webm new file mode 100644 index 0000000..d0c9135 Binary files /dev/null and b/content/blog/led-characterization/video/led_within_srgb_scale=2.5.webm differ diff --git a/content/blog/led-characterization/video/led_within_srgb_scale=3.mkv b/content/blog/led-characterization/video/led_within_srgb_scale=3.mkv new file mode 100644 index 0000000..94c7750 Binary files /dev/null and b/content/blog/led-characterization/video/led_within_srgb_scale=3.mkv differ diff --git a/content/blog/led-characterization/video/led_within_srgb_scale=3.webm b/content/blog/led-characterization/video/led_within_srgb_scale=3.webm new file mode 100644 index 0000000..3dc88cc Binary files /dev/null and b/content/blog/led-characterization/video/led_within_srgb_scale=3.webm differ diff --git a/content/blog/led-characterization/video/sRGB.mkv b/content/blog/led-characterization/video/sRGB.mkv new file mode 100644 index 0000000..903c719 Binary files /dev/null and b/content/blog/led-characterization/video/sRGB.mkv differ diff --git a/content/blog/led-characterization/video/sRGB.webm b/content/blog/led-characterization/video/sRGB.webm new file mode 100644 index 0000000..737cc1b Binary files /dev/null and b/content/blog/led-characterization/video/sRGB.webm differ diff --git a/content/blog/led-characterization/video/scale=1.mkv b/content/blog/led-characterization/video/scale=1.mkv new file mode 100644 index 0000000..410896e Binary files /dev/null and b/content/blog/led-characterization/video/scale=1.mkv differ diff --git a/content/blog/led-characterization/video/scale=1.webm b/content/blog/led-characterization/video/scale=1.webm new file mode 100644 index 0000000..dc599be Binary files /dev/null and b/content/blog/led-characterization/video/scale=1.webm differ diff --git a/content/blog/led-characterization/video/scale=2.5.mkv b/content/blog/led-characterization/video/scale=2.5.mkv new file mode 100644 index 0000000..6ff3619 Binary files /dev/null and b/content/blog/led-characterization/video/scale=2.5.mkv differ diff --git a/content/blog/led-characterization/video/scale=2.5.webm b/content/blog/led-characterization/video/scale=2.5.webm new file mode 100644 index 0000000..6a6a860 Binary files /dev/null and b/content/blog/led-characterization/video/scale=2.5.webm differ diff --git a/content/blog/led-characterization/video/scale=5.mkv b/content/blog/led-characterization/video/scale=5.mkv new file mode 100644 index 0000000..b4e7e65 Binary files /dev/null and b/content/blog/led-characterization/video/scale=5.mkv differ diff --git a/content/blog/led-characterization/video/scale=5.webm b/content/blog/led-characterization/video/scale=5.webm new file mode 100644 index 0000000..0298a11 Binary files /dev/null and b/content/blog/led-characterization/video/scale=5.webm differ diff --git a/content/blog/multichannel-led-driver/images/asymmetric_iled.svg b/content/blog/multichannel-led-driver/images/asymmetric_iled.svg new file mode 100644 index 0000000..c18d5de --- /dev/null +++ b/content/blog/multichannel-led-driver/images/asymmetric_iled.svg @@ -0,0 +1,2222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/multichannel-led-driver/images/asymmetric_vgate.svg b/content/blog/multichannel-led-driver/images/asymmetric_vgate.svg new file mode 100644 index 0000000..473f494 --- /dev/null +++ b/content/blog/multichannel-led-driver/images/asymmetric_vgate.svg @@ -0,0 +1,1933 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/multichannel-led-driver/images/bcm_schema.jpg b/content/blog/multichannel-led-driver/images/bcm_schema.jpg new file mode 100644 index 0000000..5d3ef08 Binary files /dev/null and b/content/blog/multichannel-led-driver/images/bcm_schema.jpg differ diff --git a/content/blog/multichannel-led-driver/images/corrected_brightness_sim.svg b/content/blog/multichannel-led-driver/images/corrected_brightness_sim.svg new file mode 100644 index 0000000..2b9cf16 --- /dev/null +++ b/content/blog/multichannel-led-driver/images/corrected_brightness_sim.svg @@ -0,0 +1,765 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/multichannel-led-driver/images/driver_linearity_raw.svg b/content/blog/multichannel-led-driver/images/driver_linearity_raw.svg new file mode 100644 index 0000000..58aa43f --- /dev/null +++ b/content/blog/multichannel-led-driver/images/driver_linearity_raw.svg @@ -0,0 +1,937 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/multichannel-led-driver/images/driver_output_ltspice_schematic.jpg b/content/blog/multichannel-led-driver/images/driver_output_ltspice_schematic.jpg new file mode 100644 index 0000000..52000a8 Binary files /dev/null and b/content/blog/multichannel-led-driver/images/driver_output_ltspice_schematic.jpg differ diff --git a/content/blog/multichannel-led-driver/images/driver_pcb_built.jpg b/content/blog/multichannel-led-driver/images/driver_pcb_built.jpg new file mode 100644 index 0000000..f5da956 Binary files /dev/null and b/content/blog/multichannel-led-driver/images/driver_pcb_built.jpg differ diff --git a/content/blog/multichannel-led-driver/images/driver_ringing_strong.jpg b/content/blog/multichannel-led-driver/images/driver_ringing_strong.jpg new file mode 100644 index 0000000..0419a0e Binary files /dev/null and b/content/blog/multichannel-led-driver/images/driver_ringing_strong.jpg differ diff --git a/content/blog/multichannel-led-driver/images/driver_ringing_weak.jpg b/content/blog/multichannel-led-driver/images/driver_ringing_weak.jpg new file mode 100644 index 0000000..12f9c5d Binary files /dev/null and b/content/blog/multichannel-led-driver/images/driver_ringing_weak.jpg differ diff --git a/content/blog/multichannel-led-driver/images/led_strip_alight.jpg b/content/blog/multichannel-led-driver/images/led_strip_alight.jpg new file mode 100644 index 0000000..b001395 Binary files /dev/null and b/content/blog/multichannel-led-driver/images/led_strip_alight.jpg differ diff --git a/content/blog/multichannel-led-driver/images/linearization_setup.jpg b/content/blog/multichannel-led-driver/images/linearization_setup.jpg new file mode 100644 index 0000000..faafc92 Binary files /dev/null and b/content/blog/multichannel-led-driver/images/linearization_setup.jpg differ diff --git a/content/blog/multichannel-led-driver/images/olsndot_output_schematic.jpg b/content/blog/multichannel-led-driver/images/olsndot_output_schematic.jpg new file mode 100644 index 0000000..90941df Binary files /dev/null and b/content/blog/multichannel-led-driver/images/olsndot_output_schematic.jpg differ diff --git a/content/blog/multichannel-led-driver/images/olsndot_pcb.png b/content/blog/multichannel-led-driver/images/olsndot_pcb.png new file mode 100644 index 0000000..87b10f8 Binary files /dev/null and b/content/blog/multichannel-led-driver/images/olsndot_pcb.png differ diff --git a/content/blog/multichannel-led-driver/images/olsndot_schematic.png b/content/blog/multichannel-led-driver/images/olsndot_schematic.png new file mode 100644 index 0000000..69906e5 Binary files /dev/null and b/content/blog/multichannel-led-driver/images/olsndot_schematic.png differ diff --git a/content/blog/multichannel-led-driver/images/overshoot_sim_r0.svg b/content/blog/multichannel-led-driver/images/overshoot_sim_r0.svg new file mode 100644 index 0000000..004872b --- /dev/null +++ b/content/blog/multichannel-led-driver/images/overshoot_sim_r0.svg @@ -0,0 +1,1885 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/multichannel-led-driver/images/overshoot_sim_r100.svg b/content/blog/multichannel-led-driver/images/overshoot_sim_r100.svg new file mode 100644 index 0000000..c8efd61 --- /dev/null +++ b/content/blog/multichannel-led-driver/images/overshoot_sim_r100.svg @@ -0,0 +1,1788 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/multichannel-led-driver/images/pwm_schema.jpg b/content/blog/multichannel-led-driver/images/pwm_schema.jpg new file mode 100644 index 0000000..0265665 Binary files /dev/null and b/content/blog/multichannel-led-driver/images/pwm_schema.jpg differ diff --git a/content/blog/multichannel-led-driver/images/uncorrected_brightness_sim.svg b/content/blog/multichannel-led-driver/images/uncorrected_brightness_sim.svg new file mode 100644 index 0000000..28cb4be --- /dev/null +++ b/content/blog/multichannel-led-driver/images/uncorrected_brightness_sim.svg @@ -0,0 +1,727 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/blog/multichannel-led-driver/index.rst b/content/blog/multichannel-led-driver/index.rst new file mode 100644 index 0000000..7de03d5 --- /dev/null +++ b/content/blog/multichannel-led-driver/index.rst @@ -0,0 +1,456 @@ +--- +title: "32-Channel LED tape driver" +date: 2018-05-02T11:31:14+02:00 +--- + +Theoretical basics +================== + +Together, a friend and I outfitted the small staircase at Berlin's Chaos Computer Club with nice, shiny RGB-WW LED tape +for ambient lighting. This tape is like regular RGB tape but with an additional warm white channel, which makes for much +more natural pastels and whites. There are several variants of RGBW tape. Cheap ones have separate RGB and white LEDs, +which is fine for indirect lighting but does not work for direct lighting. Since we wanted to mount our tape in channels +at the front of the steps, we had to use the slightly more expensive variant with integrated RGBW LEDs. These are LEDs +in the 5050 (5.0mm by 5.0mm) form factor common with RGB LEDs that have a small section divided off for the white +channel. The red, green and blue LED chips sit together in the larger section covered with clear epoxy and the white +channel is made up from the usual blue LED inside a yellow phosphor in the smaller section. + +Since we wanted to light up all of 15 steps, and for greatest visual effect we would have liked to be able to control +each step individually we had to find a way to control 60 channels of LED tape with a reasonable amount of hardware. + +LED tape has integrated series resistors and runs off a fixed 12V or 24V constant-voltage supply. This means you don't +need a complex constant-current driver as you'd need with high-power LEDs. You can just hook up a section of LED tape +to a beefy MOSFET to control it. Traditionally, you would do *Pulse Width Modulation* (PWM) on the MOSFET's input to +control the LED tape's brightness. + +Pulse Width Modulation +---------------------- + +`Pulse Width Modulation`_ is a technique of controlling the brightness of a load such as an LED with a digital signal. +The basic idea is that if you turn the LED on and off much too fast for anyone to notice, you can control its power by +changing how long you turn it on versus how long you leave it off. + +PWM divides each second into a large number of periods. At the beginning of each period, you turn the LED on. After +that, you wait a certain time until you turn it off. Then, you wait for the next period to begin. The periods are always +the same length but you can set when you turn off the LED. If you turn it off right away, it's off almost all the time +and it looks like it's off to your eye. If you turn it off right at the end, it's on almost all the time and it looks +super bright to your eye. Now, if you turn it off halfway into the cycle, it's on half the time and it will look to your +eye as half as bright as before. This means that you can control the LED's brightness with only a digital signal and +good timing. + +.. raw:: html + +
+ A visualization of PWM at different duty cycles. +
Waveforms of two PWM cycles at different duty cycles.
+
+ +PWM works great if you have a dedicated PWM output on your microcontroller. It's extremely simple in both hardware and +software. Unfortunately for us, controlling 32 channels with PWM is not that easy. Cheap microcontrollers only have `a +handful of hardware PWM outputs`_, so we'd either have to do everything in software, bit-banging our LED modulation, or +we'd have to use a dedicated chip. + +Doing PWM in software is both error-prone and slow. Since the maximum dynamic range of a PWM signal is limited by the +shortest duty cycle it can do, software PWM being slow means it has poor PWM resolution at maybe 8 bits at most. Poor +color resolution is not a problem if all you're doing is to fade around the `HSV rainbow`_, but for ambient lighting +where you *really* want to control the brightness down to a faint shimmer you need all the color resolution you can get. + +If you rule out software PWM, what remains are dedicated `hardware PWM controllers`_. Most of these have either of three +issues: + +* They're expensive +* They don't have generous PWM resolution either (12 bits if you're lucky) +* They're meant to drive small LEDs such as a 7-segment display directly and you can't just hook up a MOSFET to their + output + +This means we're stuck in a dilemma between two poor solutions if we'd want to do PWM. Luckily for us, PWM is not the +only modulation in town. + +.. _`Pulse Width Modulation`: https://en.wikipedia.org/wiki/Pulse-width_modulation +.. _`a handful of hardware PWM outputs`: https://www.nxp.com/parametricSearch#/&c=c731_c380_c173_c161_c163&page=1 +.. _`HSV rainbow`: https://en.wikipedia.org/wiki/HSL_and_HSV +.. _`hardware PWM controllers`: http://www.ti.com/lit/ds/symlink/tlc5940.pdf + +Binary Code Modulation +---------------------- + +PWM is the bread-and-butter of the maker crowd. Everyone and their cat is doing it and it works really well most of the +time. Unbeknownst to most of the maker crowd, there is however another popular modulation method that's mostly used in +professional LED systems: Enter `*Binary Code Modulation* (BCM) `_. + +BCM is to PWM sort of what barcodes are to handwriting. While PWM is easy to understand and simple to implement if all +you have is a counter and an IO pin, BCM is more complicated. On the other hand, computers can do complicated and BCM +really shines in multi-channel applications. + +Similar to PWM, BCM works by turning on and off the LED in short periods fast enough to make your eye perceive it as +partially on all the time. In PWM the channel's brightness is linearly dependent on its duty cycle, i.e. the percentage +it is turned on. In PWM the duty cycle D is the total period T divided by the on period T_on. The issue with doing PWM +on many channels at once is that you have to turn off each channel at the exact time to match its duty cycle. +Controlling many IO pins at once with precise timing is really hard to do in software. + +BCM avoids this by further dividing each period into smaller periods which we'll call *bit periods* and splitting each +channel's duty cycle into chunks the size of these bit periods. The amazingly elegant thing in BCM now is that as you +can guess from the name these bit periods are weighted in powers of two. Say the shortest bit period lasts 1 +microsecond. Then the second-shortest bit period is 2 microseconds and the third is 4, the fifth 8, the sixth 16 and so +on. + +.. raw:: html + +
+ A visualization of BCM at different duty cycles. +
Waveforms of a single 4-bit BCM cycle at different duty cycles. This BCM can produce 16 different + levels.
+
+ +Staggered like this, you turn on the LED for integer value of microseconds by turning it on in the bit periods +corresponding to the binary bits of that value. If I want my LED to light for 19 microseconds every period, I turn it on +in the 16 microsecond bit period, the 2 microsecond bit period and the 1 microsecond bit period and leave it off for the +4 and 8 mircosecond bit periods. + +Now, how this is better instead of just more complicated than plain old PWM might not be clear yet. But consider this: +Turning on and off a large number of channels, each at its own arbitrary time is hard because doing the timing in +software is hard. We can't use hardware timers since we only have two or three of those, and we have 32 channels. +However, we can use one hardware timer to trigger a really cheap external latch to turn on or off the 32 channels all at +once. With this setup, we can only controll all channels at once, but we can do so with very precise timing. + +All we need to do is to set our timer to the durations of the BCM bit periods, and we can get the same result as we'd +get with PWM with only one hardware timer and a bit of code that is not timing-critical anymore. + +Applications of Binary Code Modulation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +BCM is a truly wondrous technique, and outside of hobbyist circles it is in fact very widely known. Though we're using +it to control just 32 channels here, you can do much more channels without any problems. The most common application +where BCM is invariably used is *any* kind of LED screen. Controlling the thousands and thousands of LEDs in an LED +screen with PWM with a dedicated timer for each LED would not be feasible. With BCM, all you need to dedicate to a +single LED is a flipflop (or part of one if you're multiplexing). In fact, there is a whole range of `ICs with no other +purpose than to enable BCM on large LED matrices `_. Basically, these are a +high-speed shift register with latched outputs much like the venerable 74HC595_, only their outputs are constant-current +sinks made so that you can directly connect an LED to them. + +.. _74HC595: http://www.ti.com/lit/ds/symlink/sn74hc595.pdf + +Running BCM on LED tape +~~~~~~~~~~~~~~~~~~~~~~~ + +In our case, we don't need any special driver chips to control our LED tape. We just connect the outputs of a 74HC595_ +shift register to one MOSFET_ each, and then we directly connect the LED tape to these MOSFETs. The MOSFETs allow us to +drive a couple of amps into the LED tape from the weak outputs of the shift register. + +The BCM timing is done by hooking up two timer channels of our microcontroller to the shift registers *strobe* and +*reset* inputs. We set the timer to PWM mode so we can generate pulses with precise timing. At the beginning of each +bit period, a pulse will strobe the data for this bit period that we shifted in previously. At the end of the bit +period, one pulse will reset the shift register and one will strobe the freshly-reset zeros into the outputs. + +.. raw:: html + +
+ From left to right, we see the STM32, one of the shift
+        registers, and the LEDs and MOSFETs. The LED tape is driven to ground by the MOSFETs, which are in turn directly
+        driven from the shift register outputs. The shift register is wired up to the STM32 with its clock and data
+        inputs on SCK and MOSI and its RESET and STROBE inputs on channel 2 and 3 of timer 1. +
+ The schematic of a single output of this LED driver. Multiple shift register stages can be cascaded. +
+
+ + +Our implementation of this system runs on an STM32F030F4P6_, the smallest, cheapest ARM microcontroller you can get from +ST. This microcontroller has only 16kB of flash and 1kB of RAM, but that's plenty for our use. We use its SPI controller +to feed the modulation data to the shift registers really fast, and we use two timer channels to control the shift +registers' reset and strobe. + +We can easily cascade shift registers without any ill side-effects, and even hundreds of channels should be no problem +for this setup. The only reason we chose to stick to a 32-channel board is the mechanics of it. We thought it would be +easier to have several small boards instead of having one huge board with loads of connectors and cables coming off it. + +The BOM cost per channel for our system is 3ct for a reasonable MOSFET, about 1ct for one eighth of a shift register +plus less than a cent for one resistor between shift register and MOSFET. In the end, the connectors are more expensive +than the driving circuitry. + +.. _MOSFET: https://en.wikipedia.org/wiki/MOSFET +.. _STM32F030F4P6: http://www.st.com/resource/en/datasheet/stm32f030f4.pdf + +Hardware design +=============== + +From this starting point, we made a very prototype-y hardware design for a 32-channel 12V LED tape driver. The design is +based on the STM32F030F4P6_ driving the shift registers as explained above. The system is controlled through an RS485_ +bus that is connected up to the microcontroller's UART using an MAX485_-compatible RS485 transceiver. The LED tape is +connected using 9-pin SUB-D_ connectors since they are cheap and good enough for the small current of our short segments +of LED tape. The MOSFETs we use are small SOT-23_ logic-level MOSFETs. In various prototypes we used both International +Rectifier's IRLML6244_ as well as Alpha & Omega Semiconductor's AO3400_. Both are good up to about 30V/5A. Since we're +only driving about 2m of LED tape per channel we're not going above about 0.5A and the MOSFETs don't even get warm. + +.. _RS485: https://en.wikipedia.org/wiki/RS-485 +.. _MAX485: https://datasheets.maximintegrated.com/en/ds/MAX1487-MAX491.pdf +.. _IRLML6244: https://www.infineon.com/dgdl/?fileId=5546d462533600a4015356686fed261f +.. _AO3400: http://aosmd.com/pdfs/datasheet/AO3400.pdf +.. _SUB-D: https://en.wikipedia.org/wiki/D-subminiature +.. _SOT-23: http://www.nxp.com/documents/outline_drawing/SOT23.pdf + +Switching nonlinearities +------------------------ +During testing of our initial prototype, we noticed that the brightness seemed to jump around when fading to very low +values. It turned out that our extremely simple LED driving circuit consisting of only the shift register directly +driving a MOSFET, which in turn directly drives the LED tape was maybe a little bit too simple. After some measurements +it turned out that we were looking at about 6Vpp of ringing on the driver's output voltage. The picture below is the +voltrage we saw on our oscilloscope on the LED tape. + +.. raw:: html + +
+ Strong ringing on the LED voltage waveform edge at about
+            100% overshoot during about 70% of the cycle time. +
Bad ringing on the LED output voltage caused by wiring inductance. Note that the effect on the + actual LED current is less bad than this looks since the LED's V/I curve is nonlinear.
+
+ + +Dynamic switching behavior: Cause and Effect +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A bit of LTSpice_ action later we found that the inductance of the few metres of cable leading to the LED tape is the +likely culprit. The figure below is the schematic used for the simulations. + +.. raw:: html + +
+ The LTSpice schematic of one output of the driver,
+        taking into account the shift register's output ESR and the wiring ESL. +
The schematic of the simulation in LTSpice
+
+ +As tested, the driver does not include any per-output smoothing so the ~.5A transient on each BCM cycle hits the cable +in full. Combined with the cable inductance, this works out to a considerable lag of the rising edge of the LED +current, and bad ringing on its falling edge. Below is the voltage on the LED output from an LTSpice simulation of our +driver. + +.. raw:: html + +
+ The result of the LTSpice simulation of our driver output. The LED
+        current shows similar ringing to what we measured using the oscilloscope. Interestingly, the gate voltage shows
+        strong ringing, too. +
The result of our LTSpice simulation. This simulation assumes 1µH of wiring inductance and 50Ω of + output impedance on the part of the shift register. The ringing at the gate visible in the gate voltage graph is + due to feed-through of the ringing at the output through the MOSFET's parasitic Cgd.
+
+ +We were able to reduce the rining and limit the effect somewhat by putting a 220Ω series resistor in between the shift +register output and the MOSFET gate. This resistor forms an RC circuit with the MOSFET's nanofarad or two of gate +capacitance. The result of this is that the LED current passing the wire's ESL rises slightly more slowly and thus the +series inductance gets excited slightly less, and the overshoot decreases. Below is a picture of the waveform with the +damping resistor in place and a picture of our measurement for comparison. The resistor values don't agree perfectly +since the estimated ESL and stray capacitance of the wiring is probably way off. + +.. raw:: html + +
+ Weak ringing on the LED voltage waveform edge at about 30%
+        overshoot during about 20% of the cycle time. +
Adding a resistor in front of the MOSFET gate to slow the transition damped the ringing somewhat, + but ultimately it cannot be eliminated entirely. Note how you can actually see the miller plateau on the + trailing edge of this signal. +
+
+ +.. raw:: html + +
+ The result of the LTSpice simulation of our driver output with an
+        extra 100 Ohms between shift register output and MOSFET gate. Similar to the oscilloscope measurement the
+        ringing is much reduced in its amplitude. +
The LTSpice simulation result with the same parameters as above but with an extra 100Ω between the + shfit register's output and the MOSFET's gate.
+
+ +A side effect of this fix is that now the effective on-time of the LED tape is much longer than the duty cycle at the +shift register's output at very small duty cycles (1µs or less). This is caused by the MOSFET's `miller +plateau`_. For illustration, below is a graph of both the excitation waveform (the boxy line) and the resulting LED +current (the other ones) both without damping (top) and with 220Ω damping (bottom). As you can see the effective duty +cycle of the LED current is not at all equal to the 50% duty cycle of the excitation square wave. + +.. raw:: html + +
+ The result of an LTSpice simulation of the LED duty cycle without and
+        with damping. Dampening widens the LED current waveform from 50% duty cycle with sharp edges to about 80% duty
+        cycle with soft edges. +
Simulated LED duty cycle with and without damping. The damping resistance used in this simulation + was 220Ω.
+
+ +.. raw:: html + +
+ The gate voltages in the spice simulation above. The undamped
+        response shows sharp edges with the miller plateau being a barely noticeable step, but with strong ringing on
+        the trailing edge. The damped response shows RC-like slow-edges, but has wide miller plateaus on both edges
+        adding up to about 50% of the pulse width. +
The MOSFET gate voltage from the simulation in the figure above. You can clearly see how the miller + plateau (the horizontal part of the trace at about 1V) is getting much wider with added damped, and how the + resulting gate charge/discharge curve is not at all that of a capacitor anymore.
+
+ + + +In conclusion, we have three major causes for our calculated LED brightness not matching reality: + +* Ringing of the equivalent series inductance of the wiring leading up to the LED tape +* Miller plateau lag +* The damping resistor and the MOSFET gate forming an RC filter that helps with wire ESL ringing but worsens the miller + plateau issue and deforms the LED current edges. + +Added up, these three effects yield a picture that agrees well with our simulations and measurements. The overall effect +is neglegible at long period durations (>10µs), but gets really bad at short period durations (<1µs). The effect is +non-linear, so correcting for it is not as simple as adding an offset. + +.. _LTSpice: http://www.analog.com/en/design-center/design-tools-and-calculators/ltspice-simulator.html +.. _`miller plateau`: https://www.vishay.com/docs/68214/turnonprocess.pdf + +Measuring LED tape brightness +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to correct for the nonlinearities mentioned above, we decided to implement a lookup table mapping BCM period to +actual timer setting. That is, each row of the table contains the actual period length we need to set the +microcontroller's timer to in order to get our intended brightness steps. + +To calibrate our driver, we needed a setup for reproducible measurement of the relative brightness of our LED tape at +different settings. Absolute brightness is not of interest to us as the eye can't perceive it. To perform the +calibration, the LED driver is set to enable each single BCM period in turn, i.e. brightness values 1, 2, 4, 8, 16 etc. + +The setup we used to measure the LED tape's brightness consists of a bunch of LED tape stuck into a tin can for +shielding against both stray light and electromagnetic interference and a photodiode looking at the LED tape. We used +the venerable BPW34_ photodiode in our setup as I had a bunch leftover from another project and because they are quite +sensitive owing to their physically large die area. + +.. raw:: html + +
+ The led measurement setup consists of several PCBs and a
+        breadboard linked with a bunch of wires and a big tin can to shield the LEDs and the photodiode. A large sub-D
+        connector is put into the top of the tin can as a feed-through for the LED tape's control signals and the
+        photodiode signal. In the background the control laptop is visible. +
The LED brighness measurement setup. The big tin can contains a bunch of LED tape and the + photodiode. The breadboard on the right is used for the photodiode preamplifier and for jumpering around the LED + tape's channels. The red board next to it is the buspirate used as ADC. The board on the bottom left is a + TTL-to-RS485 converter and the board in the middle is the unit under test.
+
+ +The photodiode's photocurrent is converted into a voltage using a very simple transimpedance amplifier based around a +MCP6002_ opamp that was damped into oblivion with a couple nanofarads of capacitance in its feedback loop. The MCP6002_ +is a fine choice here since I had a bunch and because it is a CMOS opamp, meaning it has low bias current that would +mess up our measurements. For many applications, opamp bias current is not a big issue but when using the opamp to +directly measure very small currents at its input it quickly swamps out the signal for most BJT-input types. + +The transimpedance amplifier's output is read from the computer using the ADC input of a buspirate USB thinggamajob. In +general I would not recommend the buspirate as a tool for this job since it's ADC is not particularly good and it's +programming interface is positively atrocious, but it was what I had and it beat first wiring up one of the dedicated +ADC chips I had in my parts bin. + +The computer runs a small python script cycling the LED tape through all its BCM period settings and taking a brightness +measurement at each step. Later on, these measurements can be plotted to visualize the resulting slope's linearity, and +we can even do a simulation of the resulting brightness for all possible control values by just adding the measured +photocurrents for a certain BCM setpoint just as our retinas would do. + +.. raw:: html + +
+ +
+ A plot of the measured brightness of our LED tape for each BCM period. The brightness values are normalized + to the value measured at the LSB setpoint (brightness=1/65535). Ideally, this plot would show a straight + line with slope 1. Obviously, it doesn't. The bend in the curve is caused by the above-mentioned duty cycle + offset adding an offset to all brightness values. Shown is both the raw data (light), which has essentially zero + measurement error and a linear fit (dark). + + The plot is in log-log to approximate how the human eye would perceive brightness, i.e. highly sensitive at + low values but not very sensitive at all at large values. +
+
+ +While it would be possible to fully automate the optimization of BCM driver lookup tables, we needed only one and in the +end I just sat down and manually tweaked the ideal values we initially calculated until I liked the result. You can see +the resulting brightness curve below. + +.. raw:: html + +
+
+ +
+ Calculated brightness curve for the uncorrected BCM setup. As you can see, at low setpoints the result + is about as smooth as sandpaper, which is well in line with our observations. At high setpoints the + offset gets swamped out and the nonlinearity in the low bits is not visible anymore. +
+
+ +
+ Brightness curve for the corrected BCM setup extrapolated using actual measurements. Looks as buttery + smooth in real life as it does in this plot. +
+ +
+
+ +.. _BPW34: http://www.vishay.com/docs/81521/bpw34.pdf +.. _MCP6002: http://ww1.microchip.com/downloads/en/DeviceDoc/21733j.pdf + +Controlling the driver +---------------------- + +Now that our driver was behaving linear enough that you couldn't see it actually wasn't we needed a nice way to control +it from a computer of our choice. In the ultimate application (our staircase) we'll use a raspberry pi for this. Since +we already settled on an RS485_ bus for its robustness and simplicity, we had to device a protocol to control the driver +over this bus. Here, we settled on a simple, COBS_-based protocol for the reasons I wrote about in `How to talk to your +microcontroller over serial `_. + +To address our driver nodes, we modified the Makefile to build a random 32-bit MAC into each firmware image. The +protocol has only five message types: + +1. A 0-byte *ping* packet, to which each node would reply with its own address in the + first 100ms after boot. This can be used to initially discover the addresses of all nodes connected to the bus. You'd + spam the bus with *ping* packets, and then hit reset on each node in turn. The control computer would then receive + each device's MAC address as you hit reset. +2. A 4-byte *address* packet that says which device that the following packet is for. This way of us using the packet + length instead of a packet type field is not particularly elegant, but our system is simple enough and it was easy to + implement. +3. A 64-byte *frame buffer* packet that contains 16 bits of left-aligned brightness data for every channel +4. A one-byte *get status* packet that tells the device to respond with... +5. ...a 27-byte status packet containing a brief description of the firmware (version number, channel count, bit depth + etc.) as well as the device's current life stats (VCC, temperature, uptime, UART frame errors etc.). + +Wrapped up in a nice python interface we can now easily enumerate any drivers we connect to a bus, query their status +and control their outputs. + +.. _COBS: https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing + +Conclusion +---------- + +.. raw:: html + +
+
+ + A picture of the LED driver schematic + +
The LED driver schematic
+
+ + A picture of the LED driver PCB layout + +
The LED driver PCB layout
+
+
+ +Putting some thought into the control circuitry and software, you can easily control large numbers of channels of LEDs +using extremely inexpensive driving hardware without any compromises on dynamic range. The design we settled on can +drive 32 channels of LED tape with a dynamic range of 14bit at a BOM cost of below 10€. All it really takes is a couple +of shift registers and a mildly bored STM32 microcontroller. + +Get a PDF file of the schematic and PCB layout `here `__ or download the CAD files +and the firmware sources `from github `_. You can view the Jupyter notebook used to +analyze the brightness measurement data `here `__. + diff --git a/content/blog/multichannel-led-driver/olsndot_v02_schematics_and_pcb.pdf b/content/blog/multichannel-led-driver/olsndot_v02_schematics_and_pcb.pdf new file mode 100644 index 0000000..2a4e037 Binary files /dev/null and b/content/blog/multichannel-led-driver/olsndot_v02_schematics_and_pcb.pdf differ diff --git a/content/blog/private-contact-discovery/index.rst b/content/blog/private-contact-discovery/index.rst new file mode 100644 index 0000000..797de50 --- /dev/null +++ b/content/blog/private-contact-discovery/index.rst @@ -0,0 +1,38 @@ +--- +title: "Private Contact Discovery" +date: 2019-06-22T10:30:00+08:00 +--- + +Private Contact Discovery +========================= + +Private Contact Discovery (PCD) is the formal name for the problem modern smartphone messenger applications have on +installation: Given a user's address book, find out which of their contacts also use the same messenger without the +messenger's servers learning anything about the user's address book. The widespread non-private way to do this is to +simply upload the user's address book to the app's operator's servers and do an SQL JOIN keyed on the phone number field +against the database of registered users. People have tried sprinkling some hashes over these phone numbers in an +attempt to improve privacy, but obviously running a brute-force preimage attack given a domain of maybe a few billion +valid inputs is not cryptographically hard. + +Private Contact Discovery can be phrased in terms of Private Set Intersection (PSI), the cryptographic problem of having +two parties holding one set each find the intersection of their sets without disclosing any other information. PSI has +been an active field of research for a while and already yielded useful results for some use cases. Alas, none of those +results were truly practical yet for usage in PCD in a typical messenger application. They would require too much CPU +time or too much data to be transferred. + +At USENIX Security 2019, Researchers from technical universities Graz and Darmstadt published a paper titled *Private +Contact Discovery at Scale* +(`eprint `__ | `PDF `__). +In this paper, they basically optimize the hell out of existing cryptographic solutions to private contact discovery, +jumping from a still-impractical state of the art right to practicality. Their scheme allows a client with 1k contacts +to run PCD against a server with 1B contacts in about 3s on a phone. The main disadvantage of their scheme is that it +requires the client to in advance download a compressed database of all users, that clocks in at about 1GB for 1B users. + +I found this paper very interesting for its immediate practical applicability. As an excuse to dig into the topic some +more, I gave a short presentation at my university lab's research seminar on this paper +(slides: `PDF `__ | `ODP `__). + +Even if you're not working on secure communication systems on a day-to-day basis this paper might interest you. If +you're working with social account information of any kind I can highly recommend giving it a look. Not only might your +users benefit from improved privacy, but your company might be able to avoid a bunch of data protection and +accountability issues by simply not producing as much sensitive data in the first place. diff --git a/content/blog/private-contact-discovery/mori_semi_psi_talk.odp b/content/blog/private-contact-discovery/mori_semi_psi_talk.odp new file mode 100644 index 0000000..e7df32e Binary files /dev/null and b/content/blog/private-contact-discovery/mori_semi_psi_talk.odp differ diff --git a/content/blog/private-contact-discovery/mori_semi_psi_talk.pdf b/content/blog/private-contact-discovery/mori_semi_psi_talk.pdf new file mode 100644 index 0000000..e06fd63 Binary files /dev/null and b/content/blog/private-contact-discovery/mori_semi_psi_talk.pdf differ diff --git a/content/blog/serial-protocols/index.rst b/content/blog/serial-protocols/index.rst new file mode 100644 index 0000000..2f9bb2d --- /dev/null +++ b/content/blog/serial-protocols/index.rst @@ -0,0 +1,249 @@ +--- +title: "How to talk to your microcontroller over serial" +date: 2018-05-19T08:09:46+02:00 +--- + +Scroll to the end for the `TL;DR `_. + +In this article I will give an overview on the protocols spoken on serial ports, highlighting common pitfalls. I will +summarize some points on how to design a serial protocol that is simple to implement and works reliably even under error +conditions. + +If you have done low-level microcontroller firmware you will regularly have had to stuff some data up a serial port to +another microcontroller or to a computer. In the age of USB, an old-school serial port is still the simplest and +quickest way to get communication to a control computer up and running. Integrating a ten thousand-line USB stack into +your firmware and writing the necessary low-level drivers on the host side might take days. Poking a few registers to +set up your UART to talk to an external hardware USB to serial converter is a matter of minutes. + +This simplicity is treacherous, though. Oftentimes, you start writing your serial protocol as needs arise. Things might +start harmless with something like ``SET_LED ON\n``, but as the code grows it is easy to end up in a hot mess of command +modes, protocol states that breaks under stress. The ways in which serial protocols break are manifold. The simplest one +is that at some point a character is mangled, leading to both ends of the conversation ending up in misaligned protocol +states. With a fragile protocol, you might end up in a state that is hard to recover from. In extreme cases, this leads +to code such as `this gem`_ performing some sort of arcane ritual to get back to some known state, and all just because +someone did not do their homework. Below we'll embark on a journey through the lands of protocol design, exploring the +facets of this deceptively simple problem. + +.. _`this gem`: https://github.com/juhasch/pyBusPirateLite/blob/dece35f6e421d4f6a007d1db98d148e2f2126ebb/pyBusPirateLite/base.py#L113 + +Text-based serial protocols +=========================== + +The first serial protocol you've likely written is a human-readable, text-based one. Text-based protocols have the big +advantage that you can just print them on a terminal and you can immediately see what's happening. In most cases you can +even type out the protocol with your bare hands, meaning that you don't really need a debugging tool beyond a serial +console. + +However, text-based protocols also have a number of disadvantages. Depending on your application, these might not matter +and in many cases a text-based protocol is the most sensible solution. But then, in some cases they might and it's good +to know when you hit one of them. + +Problems +-------- + +Low information density +~~~~~~~~~~~~~~~~~~~~~~~ + +Generally, you won't be able to stuff much more than four or five bit of information down a serial port using a +single byte of a human-readable protocol. In many cases you will get much less. If you have 10 commands that are only +issued a couple times a second nobody cares that you spend maybe ten bytes per command on nice, verbose strings such as +``SET LED``. But if you're trying to squeeze a half-kilobyte framebuffer down the line you might start to notice the +difference between hex and base-64 encoding, and a binary protocol might really be more up to the job. + +Complex parsing code +~~~~~~~~~~~~~~~~~~~~ + +On the computer side of thing, with the whole phalanx of an operating system, the standard library of your programming +language of choice and for all intents and purposes unlimted CPU and memory resources to spare you can easily parse +anything spoken on a serial port in real time, even at a blazing fast full Megabaud. The microcontroller side however is +an entirely different beast. On a small microcontroller, printf_ alone will eat about half your flash. On most small +microcontrollers, you just won't get a regex library even though it would make parsing textual commands *so much +simpler*. Lacking these resources, you might end up hand-knitting a lot of low-level C code to do something seemingly +simple such as parsing ``set_channel (13, 1.1333)\n``. These issues have to be taken into account in the protocol design +from the beginning. For example, you don't really need matching parentheses, don't use them. + +Fragile protocol state +~~~~~~~~~~~~~~~~~~~~~~ + +Say you have a ``SET_DISPLAY`` command. Now say your display can display four lines of text. The obvious approach to this +is probably the SMTP_ or HTTP_ way of sending ``SET_DISPLAY\nThis is line 1\nThis is line 2\n\n``. This would certainly +work, but it is very fragile. With this protocol, you're in trouble if at any point the terminating second newline +character gets mangled (say, someone unplugs the cable, or the control computer reboots, or a cosmic ray hits something +and ``0x10 '\n'`` turns into ``0x50 'P'``). + +.. _SMTP: https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol +.. _HTTP: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol + +Timeouts don't work +~~~~~~~~~~~~~~~~~~~ + +You might try to solve the problem of your protocol state machine tangling up with a timeout. "If I don't get a valid +command for more than 200ms I go back to default state." But consider the above example. Say, your control computer +sends a ``SET_DISPLAY`` command every 100ms. If in one of them the state machine tangles up, the parser hangs since the +timeout is never hit, because a new line of text is arriving every 100ms. + +Framing is hard +~~~~~~~~~~~~~~~ + +You might also try to drop the second newline and using a convention such as ``SET_DISPLAY`` is followed by two lines of +text, then commands resume.". This works as long as your display contents never look like commands. If you are only ever +displaying the same three messages on a character LCD that might work, but if you're displaying binary framebuffer +data you've lost. + +Solutions +--------- + +Keep the state machine simple +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In a text-based protocol, always use a single line of text to represent a single command. Don't do protocol states or +modes where you can toggle between different interpretations for a line. If you have to send human-readable text as part +of a command (such as ``SET_DISPLAY``), escape it so it doesn't contain any newlines. + +This way, you keep your protocol state machine simple. If at any time your serial trips and flips a bit or looses a byte +your protocol will recover on the next newline character, returning to its base state. + +Encode numbers in hex when possible +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Printing a number in hexadecimal is a very tidy operation, even on the smalest 8-bit microcontrollers. In contrast, +printing decimal requires both division and remainder in a loop which might get annoyingly code- and time-intensive on +large numbers (say a 32-bit int) and small microcontrollers. + +If you have to send fractional values, consider their precision. Instead of sending a 12 bit ADC result as a 32-bit +float formatted like ``0.176513671875`` sending ``0x2d3`` and dividing by 4096 on the host might be more sensible. If you +really have to communicate big floats and you can't take the overhead of including both printf_ and scanf_ you can +use hexadecimal floating point, which is basically ``hex((int)foo) + "." + hex((int)(65536*(foo - (int)foo)))`` for four +digits. You can also just hex-encode the binary IEEE-754_ representation of the float, sending ``hex(*(int *)&float)``. +Most programming languages will have a `simple, built-in means to parse this sort of thing +`__. + +.. _printf: http://git.musl-libc.org/cgit/musl/tree/src/stdio/vfprintf.c +.. _scanf: http://git.musl-libc.org/cgit/musl/tree/src/stdio/vfscanf.c +.. _IEEE-754: https://en.wikipedia.org/wiki/IEEE_754 + +Escape multiline strings +~~~~~~~~~~~~~~~~~~~~~~~~ + +If you have to send arbitrary strings, escape special characters. This not only has the advantage of yielding a robust +protocol: It also ensures you can actually see everything that's going on when debugging. The string ``"\r\n"`` is easy to +distinguish from ``"\n"`` while your terminal emulator might not care. + +The simplest encoding to use is the C-style backslash encoding. Host-side, most languages will have a `built-in means of +escaping a string like that `__. + +Encoding binary data +-------------------- + +For binary data, hex and base-64 are the most common encodings. Since hex is simpler to implement I'd go with it unless +I really need the 30% bandwidth improvement base-64 brings. + +Binary serial protocols +======================= + +In contrast to anything human-readable, binary protocols are generally more bandwidth-efficient and are easier to format +and parse. However, binary protocols come with their own version of the caveats we discussed for text-based protocols. + +The framing problem in binary protocols +--------------------------------------- + +The most basic problems with binary protocols as with text-based ones is framing, i.e. splitting up the continuous +serial data stream into discrete packets. The issue is that it is that you have to somehow mark boundaries between +frames. The simplest way would be to use some special character to delimit frames, but then any 8-bit character you +could choose could also occur within a frame. + +SLIP/PPP-like special character framing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some protocols solve this problem much like we have solved it above for strings in line-based protocols, by escaping any +occurence of the special delimiter character within frames. That is, if you want to use ``0x00`` as a delimiter, you would +encode a packet containing ``0xde 0xad 0x00 0xbe 0xef`` as something like ``0xde 0xad 0x01 0x02 0xbe 0xef``, replacing the +null byte with a magic sequence. This framing works, but is has one critical disadvantage: The length of the resulting +escaped data is dependent on the raw data, and in the worst case twice as long. In a raw packet consisting entirely of +null bytes, every byte must be escaped with two escape bytes. This means that in this case the packet length doubles, +and in this particular case we're even less efficient than base-64. + +Highly variable packet length is also bad since it makes it very hard to make any timing guarantees for our protocol. + +9-bit framing +~~~~~~~~~~~~~ + +A framing mode sometimes used is to configure the UARTs to transmit 9-bit characters and to use the 9th bit to designate +control characters. This works really well, and gives plenty of control characters to work with. The main problem with +this is that a 9-bit serial interface is highly nonstandard and you need UARTs on both ends that actually support this +mode. Another issue is that though more efficient than both delmitier-based and purely text-based protocols, it still +incurs an extra about 10% of bandwidth overhead. This is not a lot if all you're sending is a little command every now +and then, but if you're trying to push large amounts of data through your serial it's still bad. + +COBS +~~~~ + +Given the limitations of the two above-mentioned framing formats, we really want something better. The `Serial Line +Internet Protocol (SLIP)`_ as well as the `Point to Point Protocol (PPP)`_, standardized in 1988 and 1994 respectively, +both use escape sequences. This might come as a surprise, but humanity has actually still made significant technological +progress on protocols for 8-bit serial interfaces until the turn of the millennium. In 1999, `Consistent Overhead Byte +Stuffing (COBS)`_ (`wiki `__) was published by a few +researchers from Apple Computer and Stanford University. As a reaction on the bandwidth doubling problem present in +PPP_, COBS *always* has an overhead of a single byte, no matter what or how long a packet's content is. + +COBS uses the null byte as a delimiter interleaves all the raw packet data and a `run-length encoding`_ of the non-zero +portions of the raw packet. That is, it prepends the number of bytes until the first zero byte to the packet, plus one. +Then it takes all the leading non-zero bytes of the packet, unmodified. Then, it again encodes the distance from the +first zero to the second zero, plus one. And then it takes the second non-zero run of bytes unmodified. And so on. At +the end, the packet is terminated with a zero byte. + +The result of this scheme is that the encoded packet does not contain any zero bytes, as every zero byte has been +replaced with the number of bytes until the next zero byte, plus one, and that can't be zero. Both formatter and parser +each have to keep a counter running to keep track of the distances between zero bytes. The first byte of the packet +initializes that counter and is dropped by the parser. After that, every encoded byte received results in one raw byte +parsed. + +While this might sound more complicated than the escaping explained above, the gains in predictability and efficiency +are worth it. An implementation of encoder and decoder should each be about ten lines of C or two lines of Python. A +minor asymmetry of the protocol is that while decoding can be done in-place, encoding either needs two passes or you +need to scan forward for the next null byte. + +.. _`Point to Point Protocol (PPP)`: https://en.wikipedia.org/wiki/Point-to-Point_Protocol +.. _PPP: https://en.wikipedia.org/wiki/Point-to-Point_Protocol +.. _`Serial Line Internet Protocol (SLIP)`: https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol +.. _`Consistent Overhead Byte Stuffing (COBS)`: http://www.stuartcheshire.org/papers/COBSforToN.pdf +.. _`Point-to-Point Protocol (PPP)`: https://en.wikipedia.org/wiki/Point-to-Point_Protocol +.. _`run-length encoding`: https://en.wikipedia.org/wiki/Run-length_encoding + +State machines and error recovery +--------------------------------- + +In binary protocols even more than in textual ones it is tempting to build complex state machines triggering actions on +a sequence of protocol packets. Please resist that temptation. As with textual protocols keeping the protocol state to +the minimum possible allows for a self-synchronizing protocol. A serial protocol should be designed such that if due to +a dropped packet or two both ends will naturally re-synchronize within another packet or two. A simple way of doing that +is to always transmit one semantic command per packet and to design these commands in the most idempotent_ way possible. +For example, when filling a framebuffer piece by piece, include the offset in each piece instead of keeping track of it +on the receiving side. + +.. _idempotent: https://en.wikipedia.org/wiki/Idempotence#Computer_science_meaning + +Conclusion +========== + +Here's your five-step guide to serial bliss: + +1. Unless you have super-special requirements, always use the slowest you can get away with from 9600Bd, 115200Bd or + 1MBd. 8N1 framing if you're talking to anything but another microcontroller on the same board. Using common values + like these makes it easier when you'll inevitably have to guess these at some point in the future ;) +2. If you're doing something simple and speed is not a particular concern, use a human-readable text-based protocol. Use + one command/reply per line, begin each line with some sort of command word and format numbers in hexadecimal. Bonus + points for the device replying to unknown commands with a human-readable status message and printing a brief protocol + overview on boot. +3. If you're doing something even slightly nontrivial or need moderate throughput (>1k commands per second or >20 byte of + data per command) use a COBS-based protocol. A good starting point is a ``[target MAC][command ID][command + arguments]`` packet format for multidrop busses. For single-drop you may decide to drop the MAC address. +4. Always include some sort of "status" command that prints life stats such as VCC, temperature, serial framing errors + and uptime. You'll need some sort of ping command anyway and that command might as well do something useful. +5. If at all possible, keep your protocol context-free across packets/lines. That is, a certain command should always be + self-contained, and no command should change the meaning of the next packet/line/command that is sent. This is really + important to allow for self-synchronization. If you really need to break up something into multiple commands, say you + want to set a large framebuffer in pieces, do it in a idempotent_ way: Instead of sending something like ``FRAMEBUFFER + INCOMING:\n[byte 0-16]\n[byte 17-32]\n[...]\nEND OF FRAME`` rather send ``FRAMEBUFFER DATA FOR OFFSET 0: [byte + 0-16]\nFRAMEBUFFER DATA FOR OFFSET 17: [byte 17-32]\n[...]\nSWAP BUFFERS\n``. + diff --git a/content/blog/sybil-resistance-identity/images/succulents.jpg b/content/blog/sybil-resistance-identity/images/succulents.jpg new file mode 100755 index 0000000..938bffd Binary files /dev/null and b/content/blog/sybil-resistance-identity/images/succulents.jpg differ diff --git a/content/blog/sybil-resistance-identity/index-old.rst b/content/blog/sybil-resistance-identity/index-old.rst new file mode 100644 index 0000000..6f1bee3 --- /dev/null +++ b/content/blog/sybil-resistance-identity/index-old.rst @@ -0,0 +1,244 @@ +--- +title: "Theia Attack Resistance and Digital Identity" +date: 2020-09-09T15:00:00+02:00 +--- + +.. raw:: html + +
+ +
Photo by Tim Bennett on Unsplash
+
+ + +Theia in Cyberspace +=================== + +In informatics, the term *distributed system* is used to describe the aggregate behavior of a complex network made up of +individual computers. For decades, computer scientists to some success have been trying to figure out how exactly the +individual computers that make up such a distributed system need to be programmed for the resulting amalgamation to +behave in a predictable, maybe even a desirable way. Though seemingly simple on its surface, this problem has a +surprising depth to it that has yielded research questions for a whole field for several decades now. One particular +as-of-yet unsolved problem is resistance against *theia attacks* (or "sybil" attacks in older terminology). + + Named after the 1973 book by Flora Rheta Schreiber on dissociative identity disorder, a sybil attack is an + attack where one computer in a distributed system pretends to be multiple computers to gain an advantage. From your + author's standpoint, naming a type of computer security attack after a medical condition was an unfortunate choice. + For this reason this post uses the term *Theia attack* to refer to the same concept. Theia is a greek godess of light + and glitter and the name alludes to the attacker performing something alike an optical illusion, causing the attacked + to perceive multiple distinct images that in the end are all only reflections of the same attacker. + +The core insight of computer science research on theia attacks is that there cannot be any technological way of +preventing such an attack, and any practical countermeasure must be grounded in some authority or ground truth that is +external to the systems—bridging from technology to its social or political context. + +Looking around, we can see a parallel between this question ("which computer is a real computer?") and a social issue +that recently has been growing in importance: Just like computers can pretend to be other computers, they can also +pretend to be humans. As can humans. Be it within the context of election manipulation or down-to-earth astroturfing_ +the recurring issue is that in today's online communities, it is hard for an individual to tell who of their online +acquaintances are who they seem to be. Different platforms attempt different solutions to this problem, and all fail in +some way or another. Facebook employs good old snitching, turning people against each other and asking them "Do you know +this person?". Twitter is more laid-back and avoids this Stasi_ methodology in favor of requiring a working mobile phone +number from its subjects, essentially short-circuiting identity verification to the phone company's check of their +subscriber's national passport. + +.. the preceding is a simplified representation of these platform's practices. In particular facebook uses several + methods depending on the case. I think this abbreviated discussion should be ok for the sake of the argument. I am + not 100% certain on the accuracy on the accuracy of the statement though. Does fb still do the snitching thing? Is + twitter usually content with a phone number? + +Trusting Crypto-Anarchist Authorities +===================================== + +Beyond these centralistic solutions to the problem, crypto-anarchists and anarcho-capitalists have been brewing on some +interesting novel approaches to online identity based on *blockchain* distributed ledger technology. Distributed +ledgers are a distributed systems design pattern that yields a system that works like an append-only logbook. +Participants can create new entries in this logbook, but no one—neither the original author, nor other participants—can +retroactively change a logbook entry once it has been written. In the blockchain model, past entries are essentially +written into stone. This near-perfect immutability is what opens them for a number of use cases from cryptographic +pseudo-currencies [#cryptocurrency]_. + +An overview over a variety of these unconventional blockchain identity verification approaches can be found in `this +unpublished 2020 survey by Siddarth, Ivliev, Siri and Berman `_. +They walk their readers through a number of different projects that try to solve the question "Is this human who they +pretend to be?" using joint socio-technological approaches. In the following few sections, you may find a short outline +of a small selection of them. The conlusion of this post will be a commentary on these approaches, and on the underlying +problem of identity in a digital world. + +.. BrightID + +In one scheme, identity is determined by "notary" computers that aggregate large amounts of information on a user's +social contacts. These computers then run an algorithm derived from the SybilGuard_, SybilLimit_ and SybilInfer_ lineage +of random-walk based algorithms. These algorithms assume that authentic social graphs are small world graphs: Everyone +knows everyone else through a friend's friend's friend. They also assume that there is an upper bound on how many +connections with authentic users an attacker can forge: Anyone who is not embedded into the graph well enough is cut +out. Like this, they put an upper limit on the number of theia identites an attacker can assume given a certian number +of connections to real people. + +Disregarding the catastrophic privacy issues of storing large amounts of data on social relationships on someone else's +computer, this second assumption is where this model unfortunately breaks down. Applying common sense, it is completely +realistic for an attacker to forge a large number of social connections: This is precisely what most of social media +marketing is about! A more malicious angle on this would be to consider how in meatspace [#meatspacefn]_ multi-level +marketing schemes are successful in coaxing people to abuse their social graphs to disastrous consequences to the +well-being of themselves and others. Similar schemes would certainly be possible in cyberspace as well. An additional +point to consider is that the upper limit SybilGuard_ and others place on the number of fake identities one can have is +simply not that strict at all. An attacker could still get away with a reasonable number of false identities before +getting caught by any such algorithm. + +.. Duniter + +In another scheme, identity is awarded to anyone who can convince several people already in the network to vouch for +them, and who is at most a few degrees removed from one of several pre-determined celebrities. Apart from again being +vulnerable to conmen and other scammers, this system has the glaring flaw of roundly refusing to recognize any person +who is not willing or able to engage with multiple of its members. Along with the system's informal requirement for +members to only vouch for people they have physically met this leads to a nonstarter in a cyberspace that grown +specifically *because* it transcends national borders and physical distance—two most serious obstacles to in-person +communication. + +.. Idena Network + +The last scheme I will outline in this post is based around a set of `Turing tests`_; that is, quizzes that are designed +to tell apart man and machine. In this system, all participants have to simultaneously undergo a Turing test once in a +fortnight. The idea is that this limits the number of theia identities an attacker can assume since they can only solve +that many Turing tests at the same time. The system uses a particular type of picture classification-based Turing test +and does not seem to be designed with the blind or mentally disabled in mind with accessibility concerns nowhere to be +found in the so-called "manifesto" published by its creators. But even ignoring that, the system obviously fails at an +even more basic level: The idea that everyone takes a Turing test at the same time only works in a world without time +zones. Or jobs for that matter. Also, it assumes that an attacker cannot simply hire a small army of people someplace +else to fool the system. + +.. _SybilLimit: https://www.comp.nus.edu.sg/~yuhf/yuh-sybillimit.pdf +.. _SybilGuard: http://www.math.cmu.edu/~adf/research/SybilGuard.pdf +.. _SybilInfer: https://www.princeton.edu/~pmittal/publications/sybilinfer-ndss09.pdf +.. _`Turing Tests`: https://en.wikipedia.org/wiki/Turing_test + +Identity between Cyberspace and Meatspace +========================================= + +A common thread in these solutions, from the Facebook'esque Stasi_ methods to the crypto-anarchist challenge-response +utopias, is that they all approach digital identity as a question of Objective Truth™ that can unanimously be decided at +a system level—or that can be externalized to the next larger system such as the state. Alas, the important question +remains unasked: + + What *is* identity? + +The answer to this question certainly depends on the system being examined. For example, an important reason the +capitalist corporations mentioned above require knowledge about their users' identity is to generate plausible +statistics for the advertisers that form their customer base, similar to how a farmer will keep statics on yield and +quality for the buyers of his crop. With this background, a full decoupling of platform accounts from a notion of legal +identity seems at odds with the platform's business model—and we will have to adjust our expectations for reform +accordingly. + +A common thread among all systems mentioned above is that they all have a social component to them. For this common use +case of social systems, I want to make a suggestion on how we can approach digital identity in a more practical, less +discriminatory [#discriminatory]_ manner than any of the methods we discussed above. I think both using people's social +connections and proxying the decisions of external authorities such as the state are bad systems to decide who is a +person and who is not. I will now illustrate this point a bit. Let us think about how many digital identities a human +beign might have. First, consider the case of n=0, someone who simply wants no business with the system at all. For +simplicity, let us assume that we have solved this issue of consent, i.e. every person who is identified by the system +consents to this practice. For n=1, the approaches outlined above all provide some approximate solution. States may not +grant every human sufficient ID (e.g. children, the mentally disabled or prisoners might be left out), and the social +systems might fail to catch people who simply do not have any friends, but otherwise their approximations hold. Maybe. +But what about n=2, n=3, ...? None of these systems adequately consider cases where a human being might legitimately +wish to hold multiple digital identities, non-maliciously. + +Consider a hypothetical lesbian, conservative politician. An active social media presence is a core component of a +modern politician's carreer. At the same time, "conservative homophobe" is still well within the realm of tautology and +it would be legitimate for this politician to wish to not disclose a large fraction of their private life to the world +at large. They might have a separate online identity for matters related to it. For this politician, the social +relationship-based systems referenced above would either incorporate outing as a design feature, or they would force +the politician to choose either of their two identities: To choose between private life and carreer. When deferring to +the state as the decider over personhood, at least the platform's operator would know about the outrageously sensitive +link between the politician's online identities. Clearly, no such solution can be considered socially just. + +Let us try not to be caught up on saving the world at this point. The issue of conservative homophobia is out of the +scope of our consideration, and it is not one that anyone can solve in the near future. Magical realism aside, least of +all can some technological thing beckon this change. There is a case for legitimate uses of multiple, separate digital +identities, and we do not have a technical or political answer to it. All hope is not lost yet, though. We can easily +undo this gordian knot by acknowledging an unspoken assumption that underlies any social relationships between real +people, past the procrustean bed of computer systems or organizational structures these relationships are cast into. + + As a function of social interaction, digital identities conform to roles_ in sociological terminology, and are not + at all the same as personhood_. Roles are subjective and arise from a relationship between people, and a single + person might legitimately perform different roles depending on context. + +When computer scientists or programmers are creating new systems, there always is an (often implicit) modelling stage. +Formally, during this stage a domain expert and a modeller with a computer science background come together, each +contributing their knowledge to form a model that is both appropriate for real-world use and practical from an +engineering point of view. In practice, these two roles are often necessarily fulfilled by the same person, who is often +also the programmer of the thing. This leads to many computer systems using poor models. A typical example of this issue +are systems requiring a person's name that use three input fields labelled "First Name", "Middle Initial" and "Last +Name". These systems are often created by US-American programmers, who are used to this naming schema from their lived +experience. Unfortunately, this schema breaks down for those few billion people who use their last name first, who have +more than one middle name, or who have multiple given names and do not normally use the first one of those. + +Once a system creator's implicit assumptions have been encoded into the system like this, it is often very hard to get +out of that situation. A pattern to use during careful modelling is to keep the model flexible to account for unforeseen +corner cases. For example, when modelling a system requiring a person's name, one would have to ask what the name is +used for. It may be the most sensible decision to simply ask the user for their name twice: Once in first name/last name +format for e.g. tax purposes, and once with a free-form text field for e.g. displaying on their account page. + +While for names, many systems already use some form of flexible model by e.g. having a *handle* or *nickname* separate +from the *display name*, "social" systems still often are stuck with an identity model based around a concept of a +single, rigid identity. In practice, people perform different roles_ in different circumstances. When asking for a +person's identity, one would get wildly different answers from different people. A person's identity as perceived by +others is coupled to their relationship more than to some underlying, biological or administrative truth. Thinking back +to the straw man politician above, this is evident in subtle ways in almost all our everyday relationships: Some people +may know me by my legal name, some by my online nickname. To some I may be a computer scientist, to some a flatmate. +None of my friends and acquaintances have ever wanted to see my passport, or asked to take my DNA to ascertain that I am +a distinct human being from the other humans they know. Likewise, identifying me by my social connections is impractical +as it would require an exceedingly weird amount of what can only be described as snooping. Yet, this concept of a +single, consistent, global, true identity is exactly what up to now all technological solutions to the identity problem +are trying to achieve. + +Building Bridges +================ + +I think I can offer you one main take-aways from the discussion above. + + During modelling social systems, focus on relationships—not identity. + +Rephrased into more actionable points, as someone designing a social digital system, do the following: + +0. Early in the design stages, take the time to consider fundamental modelling issues like this one. If you don't, you + will likely get stuck with a sub-optimal model that will be hard to get rid of. +1. Where possible, be flexible. Allow people to chose their own identifier. Don't require them to use their real names, + they may not wish to disclose those or they may not be in a format that is useful to you (they may be too long, too + short, too ubiquituous, in foreign characters etc.). A free-form text field with a reasonable length limit is a good + approach here. +2. Do not use credit cards or phone numbers to identify people. There are many people who do not have either, and + scammers can simply buy this data in bulk on the darknet. +3. Allow people to create multiple identites [#accountswitchopsec]_, and acknowledge the role of social relationships in + your interaction features. People have very legitimate reasons to separate areas of their lifes, and it is not for + you or your computer to decide who is who to whom. If your thing requires a global search function, re-consider the + data protection aspects of your system. If you want to encourage social functions in the face of bots and trolls, + make it easy for people to share their identities out-of-band, such as through a QR code or a copy-and-pasteable + short link. If you require someone's legal name or address for billing purposes, unify these identities behind the + scenes if at all and allow them to act as if fully independent in public. + +While change of perspective comes with its share of user experience challenges, but also with a promise for a more +human, more dignified online experience. Perhaps we can find a way to adapt cyberspace to humans, instead of continuing +trying it the other way around. + +.. _astroturfing: https://en.wikipedia.org/wiki/Astroturfing +.. _Stasi: https://en.wikipedia.org/wiki/Stasi + +.. [#cryptocurrency] Pseudo-currencies in that, while they provide some aspects of a regular currency such as ownership + and transactions, they lack most others. Traditional currencies are backed by states, regulated by central banks + tasked with maintaining their stability and ultimately provide accountability through law enforcement, courts + and political elections. + +.. [#discriminatory] Discriminatory as in discriminating against minorities, but also as in deciding what is and what is + not. + +.. [#accountswitchopsec] This does mean that you should not actively prevent people from creating multiple accounts. It + does not necessarily entail building a proper user interface around this practice. If you do the latter, e.g. by + offering a "switch identity" button or an identiy drop-down menu on a post submission form, you can easily + encourage slip-ups that might disclose the connection between two identities, and you make it possible for + someone hacking a single login to learn about this connection as well. + +.. [#meatspacefn] Meatspace_ is where people physically are, as opposed to cyberspace + +.. _Meatspace: https://dictionary.cambridge.org/dictionary/english/meatspace +.. _roles: https://en.wikipedia.org/wiki/Role +.. _personhood: https://en.wikipedia.org/wiki/Personhood diff --git a/content/blog/sybil-resistance-identity/index.rst b/content/blog/sybil-resistance-identity/index.rst new file mode 100644 index 0000000..f90b5ac --- /dev/null +++ b/content/blog/sybil-resistance-identity/index.rst @@ -0,0 +1,89 @@ +--- +title: "Identity between Cyberspace and Meatspace" +date: 2020-09-09T15:00:00+02:00 +draft: true +--- + +.. raw:: html + +
+ +
Photo by Tim Bennett on Unsplash
+
+ +Identity in Cyberspace +====================== + +.. Identity is a frequent problem +.. Easy solutions abound +.. Precise modelling is uncommon +.. True identity is sensitive, hard to handle +.. +.. Often, conversational features emphasized -> true identity is unnecessary +.. Social role theory +.. Call to action + +Most computer systems that interface with humans have a concept of user identity. The data structures used for its +storage vary, but usually one *account* corresponds to one human *user*. In many applications, the system operator tries +to ensure that one user cannot create multiple accounts. In online social networks, astrotufing_ and trolling are easier +to fight when limits are imposed on account creation. In online stores, fraud prevention means the store operator needs +their customers legal identity and the operator must be able to ban offending customers. In mobile messaging systems, +users have to be able to find each other by some identifier such as name or phone number, and this identifier has to be +unique and hard to forge. + +Today, in systems that allow anyone to create an account have largely converged to require either an email address or a +mobile phone number. Email addresses are used by systems that are less vulnerable to abuse and that are used on laptop +or desktop computers. Mobile phone numbers are abundantly used in smartphone apps, as well as in systems more prone to +abuse such as online social networks or ecommerce. Both are easily verified using a confirmation email or SMS. + +When designing or programming an online system, it is uncommon that the precise real-world semantics of accounts are +modelled. Most computer systems use ad-hoc data models. During their creation, their programmers implicit assumptions +about the world are encoded into these data models. Most of the time this works fine, but it does lead to significant +blind spots that can make systems break down for a fraction of their users. + +Lives in Meatspace +================== + +A consequence of the proliferation of phone numbers being used to identify people is that most people will not be able +to create multiple accounts. *"That's the point!"* you might say, but while we want to prevent scammers, spammers and +boored schoolchildren from messing with our systems, everybody else may have legitimate reasons to have more than one +account. + +We can apply sociology's model of roles_ to understand this issue. In sociology, a role is the comprehensive pattern of +rules and expectations that govern an individual's behavior corresponding to their social position. A key fact is that +most people occupy mutliple roles. A parent may also be a company employee or a wife and perform accordingly given the +circumstances. Systems that tie digital identity to legal personhood through the contracts behind phone numbers impede +their users' attempts at role separation. Effects of this are e.g. that nowadays employers routinely screen applicants' +social media accounts for unacceptable content. + +While this role conflict merely amounts to a minor inconvenience to most there are many to who it poses an existential +problem. Consider an LGBT+ person living in a repressive country or a politically conservative person living in a +very liberal city. Both have legitimate reasons to strictly separate parts of their private lives from others. For both, +much is at stake. Yet, both will have to practically circumvent most online systems registration barriers to implement +this separation. + +Trusting the User +================= + +While there is no single solution to these issues, there are several possible mitigations. The first and most important +one is to systematically think about the system's data model when creating it. Which assumptions about the real world +are inherent in it? Are these assumptions likely to cause issues? Ad-hoc models are easily created, but hard to get rid +of when they start causing problems. + +A general guideline on identity should be that hindering trolls by requiring things like phone numbers or credit card +numbers is very likely to also be an obstacle to many entirely legitimate uses. Captchas_ or invitation links can help +to keep out the trolls. Another approach is to limit the damage a troll can cause with things like effective moderation +systems, reputation systems or by limiting the reach of newly created accounts. + +Outside of e-commerce, actually tying a digital account to a real-world identity is very rarely necessary. The value of +a messenger app is not in the names in its contacts list, but the conversations behind these names. When two people meet +each other on the street, their interaction is shaped by a myriad of social factors—but *not* by them showing each other +their photo ID. + +Humans with their messy identities do not fit today's cyberspace well. Let's adapt cyberspace to humans, instead of +trying it the other way around. + +.. _astroturfing: https://en.wikipedia.org/wiki/Astroturfing +.. _roles: https://en.wikipedia.org/wiki/Role +.. _Captchas: https://link.springer.com/content/pdf/10.1007/3-540-39200-9_18.pdf + diff --git a/content/blog/telekom-gpon-sfp/images/edgerouter_interface_config.png b/content/blog/telekom-gpon-sfp/images/edgerouter_interface_config.png new file mode 100644 index 0000000..72d2a9b Binary files /dev/null and b/content/blog/telekom-gpon-sfp/images/edgerouter_interface_config.png differ diff --git a/content/blog/telekom-gpon-sfp/images/edgerouter_route_config.png b/content/blog/telekom-gpon-sfp/images/edgerouter_route_config.png new file mode 100644 index 0000000..fe65051 Binary files /dev/null and b/content/blog/telekom-gpon-sfp/images/edgerouter_route_config.png differ diff --git a/content/blog/telekom-gpon-sfp/images/edgerouter_sfp_config.png b/content/blog/telekom-gpon-sfp/images/edgerouter_sfp_config.png new file mode 100644 index 0000000..01da1e7 Binary files /dev/null and b/content/blog/telekom-gpon-sfp/images/edgerouter_sfp_config.png differ diff --git a/content/blog/telekom-gpon-sfp/images/edgerouter_snat_config.png b/content/blog/telekom-gpon-sfp/images/edgerouter_snat_config.png new file mode 100644 index 0000000..6e033ac Binary files /dev/null and b/content/blog/telekom-gpon-sfp/images/edgerouter_snat_config.png differ diff --git a/content/blog/telekom-gpon-sfp/images/edgerouter_snat_config2.png b/content/blog/telekom-gpon-sfp/images/edgerouter_snat_config2.png new file mode 100644 index 0000000..fb7ce32 Binary files /dev/null and b/content/blog/telekom-gpon-sfp/images/edgerouter_snat_config2.png differ diff --git a/content/blog/telekom-gpon-sfp/images/sfp_onu_ploam_pw_config.png b/content/blog/telekom-gpon-sfp/images/sfp_onu_ploam_pw_config.png new file mode 100644 index 0000000..66f6f6a Binary files /dev/null and b/content/blog/telekom-gpon-sfp/images/sfp_onu_ploam_pw_config.png differ diff --git a/content/blog/telekom-gpon-sfp/images/sfp_onu_reset.png b/content/blog/telekom-gpon-sfp/images/sfp_onu_reset.png new file mode 100644 index 0000000..13c2ca6 Binary files /dev/null and b/content/blog/telekom-gpon-sfp/images/sfp_onu_reset.png differ diff --git a/content/blog/telekom-gpon-sfp/images/sfp_onu_web_if.png b/content/blog/telekom-gpon-sfp/images/sfp_onu_web_if.png new file mode 100644 index 0000000..dea0b8f Binary files /dev/null and b/content/blog/telekom-gpon-sfp/images/sfp_onu_web_if.png differ diff --git a/content/blog/telekom-gpon-sfp/index.rst b/content/blog/telekom-gpon-sfp/index.rst new file mode 100644 index 0000000..17f78d5 --- /dev/null +++ b/content/blog/telekom-gpon-sfp/index.rst @@ -0,0 +1,216 @@ +--- +title: "Ubiquiti EdgeRouter on Deutsche Telekom GPON Fiber" +date: 2022-02-21T20:00:00+01:00 +--- + +Disclaimer +========== + +I provide this guide as a reference for other knowledgeable users without any warranty. Please feel free to use this as +a resource but do not hold me responsible if this does not work for you. There is a significant chance that due to an +error on my side or due to Telekom changing their setup this guide will not work for you, and you may end up having to +pay for an unsuccessful Telekom technician visit. That is your own risk, and I do not assume any liability. + +Tl;dr +===== + +The "Telekom Digitalisierungsbox Glasfasermodem" is a GPON ONT in SFP form factor that works with an Ubiquiti EdgeRouter +6P's SFP port. You can order it from Telekom or other vendors using the Telekom P/N 40823569 or its EAN 4718937619382. +It costs about the same as the separate plastic box modem, but saves a lot of space and does not require a separate +power supply. + +To configure, first access the SFP ONT's web interface at ``10.10.1.1`` by configuring your SPF port's IP to static +``10.10.1.2``. User credentials are either admin/admin or admin/1234. In the web interface, set put PLOAM password into the +"SLID" setting in ASCII mode, then save & reboot the device. Now, configure PPPoE on the router's SFP port using the +PPPoE UID ``[anschlusskennung] [zugangsnummer] "#" [mitbenutzernummer] "@t-online.de"`` and your "Persönliches Kennwort" as +PPPoE password. Set the VLAN to ``7``, and you are good to go. + +Background +========== + +I moved into a new apartment that has a fiber internet connection operated by Deutsche Telekom. Having made some poor +experiences with AVM's FritzBox brand of routers that is commonly used by German carriers, I decided to use my own +Router instead of the one provided by Deutsche Telekom. Like other German providers, Telekom charges exorbitant amounts +in monthly fees for their routers, so even though my choice ended up being a high-end piece of commercial equipment I +will still be cheaper than going with Telekom's much shittier device when added up over a two-year contract period. + +The hardware I chose is the Ubiquiti EdgeRouter 6P. This device is from Ubiquiti's commercial lineup and is intended to +power something like a small branch office of a company. It comes in a small form factor (as opposed to larger rackmount +units), it does not consume a lot of power, it has five PoE-capable Ethernet ports which I can directly connect up to +the Ubiquiti Unifi UAP access point that I already have, and it has a powerful configuration interface. It can even +act as a VPN endpoint! + +Telekom's fiber internet offering for residential customers is GPON-based. GPON stands for "Gigabit Passive Optical +Network" and means that instead of patching through one fiber or pair of fibers to each customer, several customers in +one building are connected to a single fiber through optical splitters. These optical splitters are passive, i.e. they +are just fancy pieces of glass and fibers and do not require electrical power. The advantage of GPON is lower initial +cost for the operator, the disadvantage is that competing providers can only ever hope to get traffic handed through by +Telekom and will never be able to use their own equipment on the "network" end of the fiber. + +Telekom wants you to connect to its fiber network through a small plastic box that they call "modem", and that the rest +of the world calls "ONT", or Optical Network Terminator. Telekom's ONT has an upstream optical port with an LC +connector, and a regular RJ45 ethernet port downstream. The "modem" in fact contains an entire linux system that +terminates the ITU-standard suite of protocols that is used to manage what happens on the fiber, e.g. scheduling of +transmission slots and adjustment of transmitter laser power. + +Looking at Telekom's plastic box ONT and my nice and shiny EdgeRouter, I was not a fan of this solution. Doing some +research I found out that you can in fact get GPON ONTs in an SFP module form factor. My EdgeRouter has an SFP slot, so +if I could get one of these that is compatible with Telekom's GPON flavor I could theoretically just plug it into my +EdgeRouter's SFP slot with no separate power supply needed, saving a lot of space in the process. + +Finding a GPON SFP ONT that is compatible with Telekom's network turned out to be the hard part. While there are lots of +commercial devices that look like they *should be* compatible, I could not be sure and I did not feel like sinking lots +of money and weeks of trial and error into figuring out which are and which are not. After about half a dozen calls with +various Telekom customer service departments I found the solution that ultimately ended up working: For their business +customer fiber internet offering, Telekom uses the same GPON standard, but different ONT equipment. Their router for +business customers is called "Digitalisierungsbox" and it in fact comes with an SFP GPON ONT. And, as it turns out, you +can order that SFP GPON ONT separately for about 50 € (the same as the plastic box one) from either Telekom or a number +of independent online stores. The Telekom part number of the thing is 40823569, the EAN is 4718937619382. + +Below is a list of steps that I had to undertake in order to get my EdgeRouter/SFP ONT setup to work. + +Hardware Setup +============== + +The hardware setup is really simple. The SFP ONU is plugged into the EdgeRouter's SFP port. The ONU is connected to +the Telekom Fiber through the LC/APC to SC/APC adapter cable that is included in its package. Telekom's technician will +install an LC/APC coupler to join both cables. To configure the EdgeRouter, connect yourself through an ethernet cable +*on port 2*. Ubiquiti's setup wizards assume the WAN interface is either port 1 or the SFP port (port 5), and default to +use port 2 as their LAN interface even when port 5 is configured as the only WAN port. The default IP for the EdgeRouter +is ``192.168.1.1``, and the default UID/PW is ubnt/ubnt. + +Configuration +============= + +Getting access to the SFP ONU's config interface +------------------------------------------------ + +In this section I am assuming you want to configure the SFP ONU while it is plugged into the EdgeRouter from a laptop +connected to the EdgeRouter's ethernet port 2. To do this, we have to first configure the right IP/subnet on the +EdgeRouter's SFP interface, then patch connections between the SFP ONU and the laptop through the EdgeRouter. + +1. First, inside the EdgeRouter's config interface we need to configure a static IP with accompanying SNAT rule on the + SFP port to allow us to access the SFP module's web interface through the laptop connected to the EdgeRouter. For + this, configure the eth5 interface (which is the SFP port) to use the static IP ``10.10.1.2/24``. + +.. raw:: html + +
+ + The EdgeRouter's graphical configuration interface showing IP
+           address 10.10.1.2/24 being configured for interface eth5, which is the SFP interface. + +
SFP interface configuration to access the SFP ONU from a laptop connected to the EdgeRouter's LAN + port
+
+ +2. With the SFP port assigned an IP address, we need to add a NAT rule to forward connections from the configuration + laptop on eth2 to the SFP port. We do this by adding a source NAT rule with masquerading enabled, for the TCP + protocol, with destination address ``10.10.1.0/24`` (the SFP config interface's private network). + +.. raw:: html + +
+ + The EdgeRouter's graphical configuration interface showing a
+            source NAT being configured for interface eth5 for TCP protocol connections to destination address 10.10.1.1
+            using masquerading. + +
Source NAT configuration to access the SFP ONU from LAN. eth5, masquerading on, TCP, destination + 10.10.1.1 (the SFP ONU's IP).
+
+ +3. Finally, make sure that your laptop will actually use the EdgeRouter as its gateway for IPs within ``10.10.1.0/24``. + On the laptop, disable any VPNs, disconnect your Wifi and make sure that IP r shows a default route pointing at the + EdgeRouter's ``192.168.1.1``. If that isn't the case, on Linux you can manually add the necessary route by using + ``sudo ip r a 10.10.1.0/24 via 192.168.1.1 dev enp5s0`` + +After setting up this temporary route, you should be able to access the SFP ONU's configuration web interface by +pointing a browser at ``http://10.10.1.1/`` Just make sure you use plain-text HTTP here, not secure HTTP**S**. The +default login credentials for the device are admin/1234. + +.. raw:: html + +
+ + The SFP ONU configuration web interface is a basic-looking website with
+            a big Zyxel logo on it. It has menu options named status, setup and management. It shows a system overview
+            page that lists the device's uptime and software version. + +
The SFP ONU's web interface.
+
+ +Configuring the PLOAM password / SLID / ONT-Installationskennung +---------------------------------------------------------------- + +On the SFP ONU's web interface, we only have to change one single setting: Under "Setup", we have to set what the SFP +ONU calls "SLID" to the PLOAM password for the interface. Telekom calls this the "ONT-Installationskennung". You get +this from your Telekom technician. In the config interface, select ASCII mode and enter the number using the format +``ABCD000000`` with four capital letters followed by six zeros. If necessary, you can read the SFP ONU's serial number +on this page. + +.. raw:: html + +
+ + The SFP ONU configuration web interface shows its SLID
+            configuration page. A text field labelled SLID asks the user to enter a value of at most ten characters. As
+            an example, abcdefg123 is listed. + +
The SFP ONU's config interface to set SLID/PLOAM PW/ONT-Installationskennung.
+
+ +Press "Save Config" on the top right of the web page, then select "Reset ONU" and click "Apply" under the "Reset ONU" +link on the left. Make sure to not select the factory reset option instead. + +.. raw:: html + +
+ + The SFP ONU configuration web interface shows its reset ONU page. There
+            are two options labelled Reset ONU and Reset to factory default settings. The reset ONU option is
+            selected. + +
Rebooting the SFP ONU.
+
+ +With the ONU configured, after the reset the "GPON Information" page from the left menu under "Status" from the top menu +should show ``GPON Line Status: O5``. You can now remove the SNAT rule and IP address from the SFP interface in the +EdgeRouter's config. I recommend this since there is no way to change the ONU's default credentials, and leaving the +SNAT rule in place makes it vulnerable to attacks from your LAN. If you use the EdgeRouter's setup wizard in the next +step, that wizard will reset all of these settings. + +Configuring PPPoE and NAT +------------------------- + +Our ONU now has a low-level connection to Telekom's fiber network. The next step is to configure the EdgeRouter to +authenticate with the ONU through PPPoE. The easiest way to do this is to use the EdgeRouter's "Basic Setup" wizard as +described in the `EdgeOS User Guide`. In the wizard, select the SFP port (``eth5``) as the internet/WAN port. Select +``Internet Connection Type`` as ``PPPoE``, then enter the PPPoE credentials you got from your Telekom technician. The +password is your "Persönliches Kennwort" that you also use to log in to your customer account on Telekom's website. The +account name is ``[anschlusskennung] [zugangsnummer] "#" [mitbenutzernummer] "@t-online.de"``, so something like +``002712345678012345678901#0001@t-online.de``. Enable "Internet connection is on VLAN" and enter VLAN ID ``7``. This is +necessary because of the way Telekom set up their triple play (TV/phone/internet) service. After following through with +the wizard, your internet should be already working on port 2 of the router. Note that despite selecting the SFP port as +the router's WAN port, the wizard will still reserve port 1 (``eth0``) for another WAN interface, so you will only be +able to access the configuration interface through port 2 (``eth1``) after the wizard is done. You can of course change +this later. + +That's it, you're done and your internet should be working! + +Having Fun with the SPF GPON ONU +================================ + +If you want to dig deeper into the internals of Telekom's GPON implementation, the SFP ONU's firmware is a great +starting point. Default credentials are all admin/admin or admin/1234 and you can even get a regular busybox shell on +the device through SSH. The device's firmware is based on OpenWRT, and the source for large parts of the core control +components can be found under open source licenses as well. While I would strictly advice you to not mess around with +the actual modem settings because due to GPON you share a medium with your neighbors and might very well disrupt their +internet if you mess up, inspecting the ONU's firmware is a great way to learn about the inner workings of a modern GPON +network. + +If you are interested in messing around with the SFP ONU, there is a github repository where interesting thins are +collected `here `__. + +.. _`EdgeOS User Guide`: https://dl.ubnt.com/guides/edgemax/EdgeOS_UG.pdf + diff --git a/content/blog/thors-hammer/images/thors_hammer_breadboard.jpg b/content/blog/thors-hammer/images/thors_hammer_breadboard.jpg new file mode 100644 index 0000000..4504d83 Binary files /dev/null and b/content/blog/thors-hammer/images/thors_hammer_breadboard.jpg differ diff --git a/content/blog/thors-hammer/images/thors_hammer_schematic.jpg b/content/blog/thors-hammer/images/thors_hammer_schematic.jpg new file mode 100644 index 0000000..3061f61 Binary files /dev/null and b/content/blog/thors-hammer/images/thors_hammer_schematic.jpg differ diff --git a/content/blog/thors-hammer/index.rst b/content/blog/thors-hammer/index.rst new file mode 100644 index 0000000..ba851a5 --- /dev/null +++ b/content/blog/thors-hammer/index.rst @@ -0,0 +1,60 @@ +--- +title: "Thor's Hammer" +date: 2018-05-03T11:59:37+02:00 +--- + +In case you were having an inferiority complex because your friends' IBM Model M keyboards are so much louder than the +shitty rubber dome freebie you got with your pc... Here's the solution: Thor's Hammer, a simple typing cadence enhancer +for `PS/2`_ keyboards. + +.. raw:: html + +
+ +
A demonstration of the completed project. + + h264 download / + webm download +
+
+ +The connects to the keyboard's PS/2 clock line and briefly actuates a large solenoid on each key press. An interesting +fact about PS/2 is that the clock line is only active as long as either the host computer or the input device actually +want to send data. In case of a keyboard that's the case when a key is pressed or when the host changes the keyboard's +LED state, otherwise the clock line is silent. We ignore the LED activity for now as it's generally coupled to key +presses. By just triggering an NE555 configured as astable flipflop we can stretch each train of clock pulses to a +pulse a few tens of milliseconds long that is enough to actuate the solenoid. + +.. raw:: html + +
+ The schematic of the PS2 driver +
The schematic of the driver stretching the PS/2 clock pulses to drive the solenoid.
+
+ + +Since PS/2 sends each key press and key release separately this circuit will pulse twice per keystroke. It would be +possible to ignore one of them but I figure the added noise just adds to the experience. + +Built on a breadboard, the circuit looks like this. + +.. raw:: html + +
+ The circuit built on a breadboard +
The completed circuit built up on a breadboard and attached to a keyboard.
+
+ + +Since my solenoid did not have a tensioning spring I used a rubber band and some vinyl tape to make an adjustable +tensioner. The small orange USB hub serves as an end-stop because I had nothing else of the right shape. The sound and +resonance of the thing can be adjusted to taste by moving the end stop, adjusting the tensioning rubber and tuning the +excitation duration using the potentiometer. My particular solenoid was a bit slow so I added some pieces of circuit +board as shims between the plunger and the case to limit the plunger's travel inside the solenoid core. + +.. _`PS/2`: https://en.wikipedia.org/wiki/PS/2_port + diff --git a/content/blog/thors-hammer/video/thors_hammer.mkv b/content/blog/thors-hammer/video/thors_hammer.mkv new file mode 100644 index 0000000..c9581e9 Binary files /dev/null and b/content/blog/thors-hammer/video/thors_hammer.mkv differ diff --git a/content/blog/thors-hammer/video/thors_hammer.mov b/content/blog/thors-hammer/video/thors_hammer.mov new file mode 100644 index 0000000..fff65a8 Binary files /dev/null and b/content/blog/thors-hammer/video/thors_hammer.mov differ diff --git a/content/blog/thors-hammer/video/thors_hammer.webm b/content/blog/thors-hammer/video/thors_hammer.webm new file mode 100644 index 0000000..2bcf1ca Binary files /dev/null and b/content/blog/thors-hammer/video/thors_hammer.webm differ diff --git a/content/blog/wifi-led-driver/images/board_in_case.jpg b/content/blog/wifi-led-driver/images/board_in_case.jpg new file mode 100644 index 0000000..843900a Binary files /dev/null and b/content/blog/wifi-led-driver/images/board_in_case.jpg differ diff --git a/content/blog/wifi-led-driver/images/board_in_case.small.jpg b/content/blog/wifi-led-driver/images/board_in_case.small.jpg new file mode 100644 index 0000000..5c0aa81 Binary files /dev/null and b/content/blog/wifi-led-driver/images/board_in_case.small.jpg differ diff --git a/content/blog/wifi-led-driver/images/boards.jpg b/content/blog/wifi-led-driver/images/boards.jpg new file mode 100644 index 0000000..79f8154 Binary files /dev/null and b/content/blog/wifi-led-driver/images/boards.jpg differ diff --git a/content/blog/wifi-led-driver/images/boards.small.jpg b/content/blog/wifi-led-driver/images/boards.small.jpg new file mode 100644 index 0000000..6f5c28c Binary files /dev/null and b/content/blog/wifi-led-driver/images/boards.small.jpg differ diff --git a/content/blog/wifi-led-driver/images/layout.png b/content/blog/wifi-led-driver/images/layout.png new file mode 100644 index 0000000..11fc50e Binary files /dev/null and b/content/blog/wifi-led-driver/images/layout.png differ diff --git a/content/blog/wifi-led-driver/images/schematic.png b/content/blog/wifi-led-driver/images/schematic.png new file mode 100644 index 0000000..8294f12 Binary files /dev/null and b/content/blog/wifi-led-driver/images/schematic.png differ diff --git a/content/blog/wifi-led-driver/index.rst b/content/blog/wifi-led-driver/index.rst new file mode 100644 index 0000000..f1e53a9 --- /dev/null +++ b/content/blog/wifi-led-driver/index.rst @@ -0,0 +1,145 @@ +--- +title: "Wifi Led Driver" +date: 2018-05-02T11:31:03+02:00 +--- + +Project motivation +================== + +.. FIXME finished project picture with LED tape +.. raw:: html + +
+ +
The completed driver board installed in the 3D-printed case. This device can now be connected to + 12V and two segments of LED tape that can then be controlled trough Wifi. The ESP8266 module goes on the pin + header on the left and was removed for this picture. +
+
+ +After the `multichannel LED driver`_ was completed, I was just getting used to controlling LEDs at 14-bit resolution. +I liked the board we designed in this project, but at 32 channels it was a bit large for most use cases. Sometimes I +just want to pop a piece of LED tape or two somewhere, but I don't need a full 32 channels of control. I ended up +thinking that a smaller version of the 32-channel driver that didn't require a separate control computer would be +handy. So I sat down and designed a variant of the design with only 8 channels instead of 32 and an on-board ESP8266_ +module instead of the RS485_ transceiver for WiFi connectivity. + +The Electronics +=============== + +The schematic was mostly copy-pasted from the 32-channel design. The PCB was designed from scratch. This time, I went +for a 5x7cm form factor to allow for enough room for all connectors and to give the ESP8266_'s WiFi antenna enough +space. The board has two 5-pin Phoenix-style_ for two RGB-White (RGBW) tapes and one 2-pin Phoenix-style_ connector for +12V power input. The control circuitry and the serial protocol are unchanged, but the STM32_ now talks to an ESP-01_ +module running custom firmware. + +The LEDs are driven using a 74HC595_ shift register controlling a bunch of AO3400_ MOSFETs_, with resistors in front of +the MOSFETs_' gates to slow down the transitions a bit to reduce brighntess nonlinearities and EMI_ resulting from +ringing of the LED tape's wiring inductance. + +The board has two spots for either `self-resettable fuses (polyfuses) `__ or regular melting-wire fuses_ in +a small SMD_ package, one for each RGBW output. For low currents the self-resettable fuses should be okay but at higher +currents their `trip times get long enough that they become unlikely to trip in time to save anything +`__, so plain old non-resettable fuses would be the way to go there. + +.. FIXME finished board photos +.. FIXME board with test tape picture + +.. raw:: html + +
+
+ +
+ The schematic of the driver board, with the ESP8266 on the top left, the STM32 microcontroller for LED + modulation below, the shift register in the middle and the LED drivers and outputs on the right. + Download PDF +
+
+ +
+ The board layout with the top side being visible. The top side contains the footprint for the ESP8266, the + microcontroller, fuses, filter cap, connectors and the shift register. The LEDs are connected on the left, + with one connector per LED tape segment. The power input connector is on the bottom right. The LED driver + MOSFETs are in small SOT-23 packages on the back of the board. Since this board is not intended for + super-high currents, the MOSFETs are adequately cooled just through the board's copper planes. + Download PDF +
+
+
+ +.. raw:: html + +
+ +
The completed PCBs of this project (front) and the `multichannel LED driver`_ project the driver + circuitry was derived from (back). +
+
+ + +The Firmware +============ + +The STM32_ firmware only had to be slightly modified to accomodate the reduced channel count since the protocol remains +unchanged. The ESP firmware is based on esphttpd_ by Spritetm_. The modifications to the webserver firmware are pretty +basic. First, the UART console has been disabled since I use the UART to talk to the STM32. The few bootloader messages +popping out the UART on boot are not an issue, since they're unlikely to contain the fixed 32-bit address prefix the +serial protocol requires for the STM32_ to do anything. + +Second, I added LED control by adding drivers for the serial protocol and a bunch of colorspace conversion functions. +When I first tested the prototype software, I noticed that color reproduction was extremely poor. When I just sent a +HSV_ rainbow fade from a python command line, the result looked totally wrong. The fade did not seem to go at a constant +speed and some colors, in particular yellow, orange and greens, were not visible at all. The problem turned out to be a +stark mismatch of the red, green and blue channels of the LED tape and less-than-optimal color reproduction of the pure +colors. I decided to properly measure the LED tape's color reproduction so I could compensate for it in software. This +turned out to be an extremely interesting project, the details of which you can read in my `LED characterization`_ +article. + +Third, I updated the built-in websites with some ad-hoc documentation on how to use the thing and a basic interface for +LED control. + +.. FIXME screenshot of firmware website + +Making an enclosure +=================== + +To be actually useful, the driver needed a robust enclosure. Bare PCBs are nice for prototyping, but for actually +putting the thing anywhere it needs a case to protect it against random destruction. + +The board has four mounting holes with comfortable spacing in its corners to allow easy mounting inside a 3D-printed +case. The case itself is described in an OpenSCAD_ script. To make it look a little nicer, a little 3D relief is laid +into the lid. The 3D relief is generated with a bit of blender magic. The source STL_ model is loaded into blender, then +blender's amazingly flexible rendering system is used to export a depth map of a projection of the model as a PNG_ file. +This depth map is then imported as a triangle mesh into OpenSCAD_. + +For the relief to look good, I chose a rather high resolution for the depth map. This unfortunately leads to extreme +memory use and processing time on the part of OpenSCAD_, but since I have access to a sufficiently fast machine that is +not a problem. Just be careful if you try opening the OpenSCAD_ file on your machine, OpenSCAD_ will probably crash +unless you're on a beefy machine or interrupt it when it starts auto-rendering the file. + +The board is mounted into the enclosure using knurled insert nuts that are pressed into a 3D-printed hole using a bit of +violence. + +.. _`multichannel LED driver`: {{}} +.. _`LED characterization`: {{}} +.. _ESP8266: https://en.wikipedia.org/wiki/ESP8266 +.. _RS485: https://en.wikipedia.org/wiki/RS-485 +.. _Phoenix-style: https://www.phoenixcontact.com/online/portal/de?uri=pxc-oc-itemdetail:pid=1757019&library=dede&tab=1 +.. _STM32: http://www.st.com/resource/en/datasheet/stm32f030f4.pdf +.. _ESP-01: http://www.watterott.com/de/ESP8266-WiFi-Serial-Transceiver-Modul +.. _74HC595: http://www.ti.com/lit/ds/symlink/sn74hc595.pdf +.. _AO3400: http://aosmd.com/pdfs/datasheet/AO3400.pdf +.. _MOSFETs: https://en.wikipedia.org/wiki/MOSFET +.. _EMI: https://en.wikipedia.org/wiki/Electromagnetic_interference +.. _polyfuse: https://en.wikipedia.org/wiki/Resettable_fuse +.. _SMD: https://en.wikipedia.org/wiki/Surface-mount_technology +.. _fuses: https://en.wikipedia.org/wiki/Fuse_(electrical) +.. _littlefuse-16r-datasheet: http://m.littelfuse.com/~/media/electronics/datasheets/resettable_ptcs/littelfuse_ptc_16r_datasheet.pdf.pdf +.. _OpenSCAD: http://www.openscad.org/ +.. _STL: https://en.wikipedia.org/wiki/STL_(file_format) +.. _PNG: https://en.wikipedia.org/wiki/Portable_Network_Graphics +.. _esphttpd: https://github.com/Spritetm/esphttpd +.. _Spritetm: http://spritesmods.com/ +.. _`HSV`: https://en.wikipedia.org/wiki/HSL_and_HSV + diff --git a/content/blog/wifi-led-driver/resource/lyza_schematic_and_pcb.pdf b/content/blog/wifi-led-driver/resource/lyza_schematic_and_pcb.pdf new file mode 100644 index 0000000..6532888 Binary files /dev/null and b/content/blog/wifi-led-driver/resource/lyza_schematic_and_pcb.pdf differ diff --git a/content/posts/hsm-basics/index.rst b/content/posts/hsm-basics/index.rst deleted file mode 100644 index 306edcd..0000000 --- a/content/posts/hsm-basics/index.rst +++ /dev/null @@ -1,214 +0,0 @@ ---- -title: "Hardware Security Module Basics" -date: 2019-05-17T15:29:20+08:00 ---- - -Hardware Security Modules and Security Research and Cryptography -================================================================ - -On May 17 2019 I gave a short presentation on the fundamentals of hardware security modules at the weekly seminar of -Prof. Mori's security research working group at Waseda University. The motivation for this was that outside of low-level -hardware security people and people working in the financial industry HSMs are not thought about that often. In -particular most network or systems security people would not consider them an option. Also it could turn out to be -really interesting to think about what could be done with an HSM in conjunction with modern cryptography (instead of -just plain old RSA-OAEP and AES-CBC). - -`Click here to download a PDF with the slides for this talk. `__ - -Ideas for research in HSMs -========================== - -Preparing for this talk brought me back to some research ideas I've been working on for a while now. Since I'm not sure -I'll find the time to properly research this topic, I thought it would be great to write down some rought outlines first -for future reference. - -The Problem with current HSM tech ---------------------------------- - -Currently, HSMs are only used in certain specific niche applications such as certificate authority key management and -financial transaction data handling. One key reason for this is that HSMs currently don't provide the affordances that -would be needed for them to be adopted more widely by the cryptographic and security engineering community. As far as I -can tell, the two core missing affordances are: - -1. To be more widely adopted, HSMs must become less expensive. Currently, they go for several tens of thousands of Euro, - which puts them outside most budgets. -2. To be more widely adopted, HSMs must provide the standardized programming interfaces familiar to cryptographic - developers. Currently, every HSM vendor has their own custom cryptographic API and a developer will have to train on - one specific vendor's tooling. Furthermore, any documentation of these internals is kept secret behind NDAs. This - constitutes a high barrier to entry, decreasing adoption in particular with young developers accustomed to - open-source ecosystems. - -Attacking cost of implementation --------------------------------- - -The first issue can be addressed by simply creating a viable low-cost alternative. There is no fundamental technical -reason for the high cost of HSMs. This cost is instead due to manufacturers trying to recoup their expenses for R&D as -well as certification from the small volumes HSMs are sold in. - -Compared to system integration and certification the pure R&D cost of HSM defense mechanisms themselves is not too high -in an academic context it should be feasible to develop a sort of HSM blueprint that can then be cheaply produced by -anyone in need. Since the application areas outlined here are far from the core business areas of the clients of -established HSM vendors this would most likely not be a realistic threat to any established vendor's business and a -co-existence of both should not pose any problems in the short term. - -Benefits of an academic HSM standard ------------------------------------- - -Tackling the high cost of current HSM hardware with an open-source HSM blueprint would yield -several academic advantages beyond cost reduction. - -1. An open-source blueprint could serve as an academic reference design to evaluate and compare other HSM designs - against. For instance this would not only allow quantifying the effectiveness of academic security measures but also - allow an evaluation of commercial HSMs. -2. An open-source blueprint could stimulate academic research in this academically very quiet albeit commercially - important area. This research would ultimately benefit everyone employing HSMs by raising security standards in the - field. Since HSMs are never solely relied upon for overal system security both defensive and offensive security - research would yield these benefits. -3. An open-source blueprint would encourage new people to get into the field and both apply HSMs to practical problems - as well as improve HSMs themselves. Currently, this is highly discouraged due to the strictly proprietary nature of - all available systems. -4. Finally, developing an open-source HSM blueprint might yield new findings in adjacent academic areas due to the - hightly multi-disciplinary nature of security research in general and HSM design in particular. - -Scope of an academic HSM standard ---------------------------------- - -An academic HSM blueprint would need to be flexible so that researchers can adapt it to their particular problem. A -modular architecture would lend itself to this flexibility. Fundamentally, there would be three components to this -architecture. First, a **base** containing infrastructure such as the surveillance microcontroller, power supplies, -power supply filtering and hardware DPA countermeasures, and possibly a standardized mechanical and electrical -interface. - -Next to the base, a system integrator would put their *payload*. The nature of this payload is intentionally kept -unspecified, and it might be anything from a cryptographic microcontroller to a small embedded system such as a -raspberry pi single board computer. Keeping the *payload* open like this achieves two benefits: It gives the HSM -blueprint's user *their* familiar tooling and the hardware *they* need, allowing fast adoption. Someone well-versed in -e.g. Javascript could literally implement their cryptography in Javascript, run it on an off-the-shelf raspberry pi and -just apply the HSM blueprint around it. In addition, keeping the *payload* open reduces the scope of what needs to be -implemented. Building a general SDK on top of something like a bare ARM SoC such as a TI OMAP or a Freescale/NXP IMX -would be a considerable additional burden, on top of the actual HSM design. Keeping the *payload* open allows research -to concentrate on the actual point, the HSM design. - -The final and most important component would be a set of *security measures* that can be combined with the base to -form the final HSM. Each of these *security measures* would entail a detailed specification of its design, manufacture -and security properties. These *security measures* could be simple things like tamper switches or potting, but could -also be complex things like security meshes. - -Given these three components -- *base*, *payload* and *security measures* as detailed specifications any engineer should -be able to design and manufacture a HSM customized to their needs. Unifying these three components within the HSM -blueprint would be a set of reference designs. Each reference design would implement a particular parametrization of the -three architectural components with a physical hole cut out where the payload would go.. These reference designs would -for one serve to guide any implementer on the customization and integration of their own derivation from the blueprint. -In addition it would serve as an extremely simple, low-cost point of entry into the ecosystem. A curious researcher -could simply replicate the reference design and put their existing payload inside. Practically this might mean e.g. a -researcher having PCBs produced according to the design files for a reference design for a mesh-based HSM, producing -their own mesh, physically glueing a raspberry pi SBC into the middle of it, and potting the resulting system. Given the -ease of prototype PCB fabrication today this would realistically allow evaluation of HSM technologies on a budget that -is orders of magnitude less than the cost of current HSMs. - -Research ideas for tamper detection mechanisms -============================================== - -The core component of an HSM blueprint would be a suite of tamper detection mechanisms. Following are a few ideas on how -to improve on the current state of the art of membrane tamper switches plus temperature sensors plus PCB and printed -security meshes plus potting. - -DIY or small lab mesh production --------------------------------- -**Analog sensing** meshes are a proven technology where instead of just monitoring for continuity and shorts, analog -parameters of the mesh traces such as inductance and mutual capacitance are monitored. In 2019, `Immler et al. published -a paper `__ where took this principle and turned it all the -way up. They directly derived a cryptographic secret from the analog properties of their HSM's security mesh in an -attempt to built a `Physically Unclonable Function, or PUF -`__. The idea with PUFs is that they reproduce some entropy -that comes from random tolerances of their production process. The same PUF will always yield (approximately) the same -key, but since you cannot control these random production variations, in practice the resulting PUF cannot be cloned. -Note however, that its secrets can of course be copied if you find a way to read them out. - -As Immler et al. demonstrated in their paper, you don't need any secret sauce to create an analog mesh sensing circuit. -All you need are a bunch of (admittedly, expensive) off-the-shelf analog ICs. The interesting bit here is that by -applying more advanced analog sensing, weaknesses of an otherwise coarse mesh desing could maybe be alleviated. That is, -instead of monitoring a very fine mesh for continuity, you could instead closely monitor inductance and capacitance of a -more coarse mesh. This trade-off between sensing circuit complexity (resp. cost) and mesh production capabilities may -allow someone with a poorly equipped lab to still make a decent HSM. The question is, how do you produce a "decent" mesh -given only basic tools? Here are some ideas. - -**3D metal patterning techniques** refers to any technique for producing thin, patterned metal structures on a -three-dimensional plastic substrate. The basic process would consist of 3D-printing the polymer substrate, depositing a -thin metal layer on top and then patterning this metal layer. A good starting point here would be the recent work of -`Ben Kraznow`_ on this exact thing. - -**Copper filament methods** would be any method embedding copper wire from a spool in some resin or other matrix. This -could mean either of a systematic approach of carefully winding or folding the copper wire into patterns or a -non-systematic approach of simply stuffing a large tangle of copper wire into a small space. The main challenge with the -former would be to find a non-tedious way of production. The main challenge with the latter would be to find process -parameters that guarantee complete coverage of the HSM without holes or other areas of lower sensitivity to intrusions. -Both approaches would require careful consideration of the overall design including the polymer resin supporting -structure to ensure sensitivity against attacks since copper wire is mechanically much stronger than the micrometre-thin -metal coatings used in patterning techniques. - -Envelope measurement --------------------- - -Finally, I think there is another set of currently under-utilized tamper-detection methods that would be very -interesting to explore. I am not aware of an academic term for these, so I am just going to dub them *envelope -measurement* here. - -The fundamental apporach of a mesh is to build a physical security envelope (the mesh) that physically detects when it -is disturbed (open or short circuits). This approach works well but has the disadvantage that these meshes are rather -complex to manufacture since effectively every part of them is acting as a sensing element. A conceptually more complex -but in practice potentially simpler approach might be to split the functions of security envelope and sensing element. -This would mean that in place of the mesh, some form of passive element such as metal foil forms the security envelope -which is then checked for tampering using a very sensitive sensor inside. This remote-sensing approach might simplify -the manufacture of the envelope itself and thus yield a design that is more easily customized. Following are a few ideas -on how to approach this envelope measurement problem. - -**Ultrasonic** If the HSM is potted, a few ultrasonic transducers could be added inside the potting. With several -transducers, any one could be used to transmit ultrasound while the others measure complex phase and energy of the -signal they receive. The circuitry for this could be made fairly simple if using a static transmit frequency or a low -chirp rate by using a homodyne receiver built around a comparator fed into some timers. This approach would likely -detect any mechanical attack and would also rule out chemical attacks involving liquids (though starting from which -amount of liquid depends on receiver sensitivity). The main disadvantages might be high power consumption and cost and -size of the ultrasonic transducers. Traditional cheap transducers made for air as a transmission medium are fairly large -and might not adequately couple into potting compound. If somehow one could convince a standard small piezo element to -do the same job that would be great as far as cost and size are concerned. A concern in some fringe use cases might be -suceptibility to ambient noise, though this could easily be reduced at the expense of space and heat dissipation -capacity by adding sound dampening on the outside. A likely attack vector against this approach might be using a laser -cutter to drill a hole through the potting compound, then inserting probes carefully chosen to not couple too much -to the potting compound ultrasonically. - -**Light** In either an unpotted HSM or one potted with a transparent (at some wavelengths) potting compound one could -embed LEDs and photodiodes in a similar setup to the ultrasonic setup described above. In contrast to the ultrasound, -the LEDs would literally have to light up the HSM's interior and shadows might be an issue since the HSM is likely some -flat rectangular shape. A possible solution to this would be to coat both the embedded payload and the lid with some -highly reflective paint such as some glossy silver paint or simple white paint. The basic approach might be as simple as -simply turning on several LEDs distributed throughout the HSM in turn and measuring amplitude at several photodetectors, -or as complex as doing a LIDAR-like phase measurement sweeping through a range of frequencies to determine not only -absorption but also phase/distance characteristics between emitter LED and detector photodiode. Using some high-gain TIA -along with a homodyne detector (lock-in amplifier) and changing emitter intensity, very precise measurements of both -absorption and phase might be possible, as might be measurements through almost opaque, diffuse potting compounds such -as a grey epoxide resin. The main disadvantages of this method would likely be the need to thoroughly light-proof the -entire HSM (likely by wrapping it in metal foil) and the potentially high cost of transmitter and receiver circuitry -(nice TIAs aren't cheap). To be effective against attacks using e.g. very fine drills and probes the system would likely -have to be very sensitive. - -**Radar** Finally, one could turn to standard radar techniques to fingerprint the inside of the HSM. The goal here would -be fingerprinting instead of mapping since only changes need to be detected. In this approach one could use homodyne -detection to improve sensitivity and reduce receiver complexity, and sweep frequencies similar to an FMCW radar (but -probably without exploiting the self-demodulation effect). Besides high cost, this approach has two disadvantages. -First, such a system would likely not go beyond 24GHz or maybe 40GHz due to component availability issues. Even at 40GHz -the wavelength in the potting compound would be in the order of magnitude of several millimeters. Fine intrusions using -some tool chosen to not interact too much with the EM field inside the HSM such as a heated ceramic needle or simply a -laser cutter might not be detectable using this approach. In any case, this system would certainly not be able to detect -small holes piercing the HSM enclosure. The HSM enclosure would have to be made into an RF shield, likely by using some -metal foil in it. - -Overall in the author's opinion these three techniques are most promising in order *Light*, *Ultrasonic*, *Radar*. Light -would prbably provide the best sensitivity at expense of some cost. Ultrasonic might be used in conjunction with light -to cover some additional angles since it is potentially very low-cost. Radar seems hard to engineer into a solution that -works reliably and also would likely be at least an order of magnitude more expensive than the other two technologies -while not providing better sensitivity. - -.. _`Ben Kraznow`: https://www.youtube.com/watch?v=Z228xymQYho -.. _affordances: https://en.wikipedia.org/wiki/Affordance - diff --git a/content/posts/hsm-basics/mori_semi_hsm_talk_web.pdf b/content/posts/hsm-basics/mori_semi_hsm_talk_web.pdf deleted file mode 100644 index b8b7177..0000000 Binary files a/content/posts/hsm-basics/mori_semi_hsm_talk_web.pdf and /dev/null differ diff --git a/content/posts/ihsm-worlds-first-diy-hsm/index.rst b/content/posts/ihsm-worlds-first-diy-hsm/index.rst deleted file mode 100644 index 370a053..0000000 --- a/content/posts/ihsm-worlds-first-diy-hsm/index.rst +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: "New Paper on Inertial Hardware Security Modules" -date: 2021-11-23T23:42:20+01:00 ---- - -World's First DIY HSM -===================== - -Last week, Prof. Dr. Björn Scheuermann and I have `published our first joint paper on Hardware Security Modules -`__. In our paper, we introduce Inertial Hardware Security -Modules (IHSMs), a new way of building high-security HSMs from basic components. I think the technology we demonstrate -in our paper might allow some neat applications where some civil organization deploys a service that no one, not even -they themselves, can snoop on. Anyone can built an IHSM without needing any fancy equipment, which makes me optimistic -that maybe the ideas of the `Cypherpunk movement `__ aren't obsolete -after all, despite even the word "crypto" having been co-opted by radical capitalist environmental destructionists. - -An IHSM is basically an ultra-secure enclosure for something like a server or a raspberry pi that even someone with -unlimited resources would have a really hard time cracking without destroying all data stored in it. The principle of an -IHSM is the same as that of a `normal HSM`_. You have a payload that contains really secret data. There's really no way -to prevent an attacker with physical access to the thing from opening it given enough time and abrasive discs for their -angle grinder. So what you do instead is that you make it self-destruct its secrets within microseconds of anyone -tampering with it. Usually, such HSMs are used for storing credit card pins and other financial data. They're expensive -as fuck, all the while being about the same processing speed as a smartphone. Traditional HSMs use printed or -lithographically patterned conductive foils for their security mesh. These foils are not an off-the-shelf component and -are made in a completely custom manufacturing process. To create your own, you would have to re-engineer that entire -process and probably spend some serious money on production machines. - -Inertial HSMs take the concept of traditional HSMs, but replace the usual tamper detection mesh with a few security mesh -PCBs. These PCBs are coarser than traditional meshes by orders of magnitude, and would alone not even be close to enough -to keep out even a moderately motivated attacker. IHSMs fix this issue by spinning the entire tamper detection mesh at -very high speed. To tamper with the mesh, an attacker would have to stop it. This, in turn, can be easily detected by -the mesh's alarm circuitry using a simple accelerometer as a rotation sensor. - -In our paper, we have shown a working prototype of the core concepts one needs to build such an IHSM. To build an IHSM -you only need a basic electronics lab. I built the prototype in our paper at home during one of Germany's COVID -lockdowns. You can have a look at our code and CAD on `my git `__. What is missing right -now is an integration of all of these fragments into something cohesive that an interested person with the right tools -could go out and build. We are planning to release this sort of documentation at some point, but right now we are -focusing our effort on the next iteration of the design instead. Stay tuned for updates ;) - -.. _`normal HSM`: {{}} diff --git a/content/posts/kicad-mesh-plugin/images/anim.webp b/content/posts/kicad-mesh-plugin/images/anim.webp deleted file mode 100755 index a2244d0..0000000 Binary files a/content/posts/kicad-mesh-plugin/images/anim.webp and /dev/null differ diff --git a/content/posts/kicad-mesh-plugin/images/cells-0.svg b/content/posts/kicad-mesh-plugin/images/cells-0.svg deleted file mode 100755 index f1d881c..0000000 --- a/content/posts/kicad-mesh-plugin/images/cells-0.svg +++ /dev/null @@ -1,2444 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/posts/kicad-mesh-plugin/images/cells-100.svg b/content/posts/kicad-mesh-plugin/images/cells-100.svg deleted file mode 100755 index efc4f03..0000000 --- a/content/posts/kicad-mesh-plugin/images/cells-100.svg +++ /dev/null @@ -1,2444 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/posts/kicad-mesh-plugin/images/cells-25.svg b/content/posts/kicad-mesh-plugin/images/cells-25.svg deleted file mode 100755 index 670ad1a..0000000 --- a/content/posts/kicad-mesh-plugin/images/cells-25.svg +++ /dev/null @@ -1,2444 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/posts/kicad-mesh-plugin/images/cells-50.svg b/content/posts/kicad-mesh-plugin/images/cells-50.svg deleted file mode 100755 index 3b5a0a3..0000000 --- a/content/posts/kicad-mesh-plugin/images/cells-50.svg +++ /dev/null @@ -1,2444 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/posts/kicad-mesh-plugin/images/cells-75.svg b/content/posts/kicad-mesh-plugin/images/cells-75.svg deleted file mode 100755 index 40e7fc4..0000000 --- a/content/posts/kicad-mesh-plugin/images/cells-75.svg +++ /dev/null @@ -1,2444 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/posts/kicad-mesh-plugin/images/grid-vis-plain.svg b/content/posts/kicad-mesh-plugin/images/grid-vis-plain.svg deleted file mode 100755 index 80b8d84..0000000 --- a/content/posts/kicad-mesh-plugin/images/grid-vis-plain.svg +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/kicad-mesh-plugin/images/grid-vis.svg b/content/posts/kicad-mesh-plugin/images/grid-vis.svg deleted file mode 100755 index fbcdafa..0000000 --- a/content/posts/kicad-mesh-plugin/images/grid-vis.svg +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/kicad-mesh-plugin/images/kicad-mesh-outline.png b/content/posts/kicad-mesh-plugin/images/kicad-mesh-outline.png deleted file mode 100755 index fc0d51e..0000000 Binary files a/content/posts/kicad-mesh-plugin/images/kicad-mesh-outline.png and /dev/null differ diff --git a/content/posts/kicad-mesh-plugin/images/kicad-mesh-result-large.png b/content/posts/kicad-mesh-plugin/images/kicad-mesh-result-large.png deleted file mode 100755 index 798287b..0000000 Binary files a/content/posts/kicad-mesh-plugin/images/kicad-mesh-result-large.png and /dev/null differ diff --git a/content/posts/kicad-mesh-plugin/images/kicad-mesh-settings.png b/content/posts/kicad-mesh-plugin/images/kicad-mesh-settings.png deleted file mode 100755 index 72e7e25..0000000 Binary files a/content/posts/kicad-mesh-plugin/images/kicad-mesh-settings.png and /dev/null differ diff --git a/content/posts/kicad-mesh-plugin/images/kicad-mesh-settings2.png b/content/posts/kicad-mesh-plugin/images/kicad-mesh-settings2.png deleted file mode 100755 index 8da33be..0000000 Binary files a/content/posts/kicad-mesh-plugin/images/kicad-mesh-settings2.png and /dev/null differ diff --git a/content/posts/kicad-mesh-plugin/images/maze_tiles.svg b/content/posts/kicad-mesh-plugin/images/maze_tiles.svg deleted file mode 100755 index 4b71f19..0000000 --- a/content/posts/kicad-mesh-plugin/images/maze_tiles.svg +++ /dev/null @@ -1,2070 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/kicad-mesh-plugin/images/maze_tiles_plain.svg b/content/posts/kicad-mesh-plugin/images/maze_tiles_plain.svg deleted file mode 100755 index be1f8d5..0000000 --- a/content/posts/kicad-mesh-plugin/images/maze_tiles_plain.svg +++ /dev/null @@ -1,1731 +0,0 @@ - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/kicad-mesh-plugin/images/modern_art.svg b/content/posts/kicad-mesh-plugin/images/modern_art.svg deleted file mode 100755 index 2729b63..0000000 --- a/content/posts/kicad-mesh-plugin/images/modern_art.svg +++ /dev/null @@ -1,1609 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/kicad-mesh-plugin/images/tiles-25-small.svg b/content/posts/kicad-mesh-plugin/images/tiles-25-small.svg deleted file mode 100755 index 21b17ed..0000000 --- a/content/posts/kicad-mesh-plugin/images/tiles-25-small.svg +++ /dev/null @@ -1,14636 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/posts/kicad-mesh-plugin/images/traces-25-small.svg b/content/posts/kicad-mesh-plugin/images/traces-25-small.svg deleted file mode 100755 index af9a8ef..0000000 --- a/content/posts/kicad-mesh-plugin/images/traces-25-small.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/content/posts/kicad-mesh-plugin/index.rst b/content/posts/kicad-mesh-plugin/index.rst deleted file mode 100644 index 85b407c..0000000 --- a/content/posts/kicad-mesh-plugin/index.rst +++ /dev/null @@ -1,221 +0,0 @@ ---- -title: "Kicad Mesh Plugin" -date: 2020-08-18T13:15:39+02:00 ---- - -.. raw:: html - -
- -
- -Tamper Detection Meshes -======================= - -Cryptography is at the foundation of our modern, networked world. From email to card payment infrastructure in brick and -mortar stores, cryptographic keys secure almost every part of our digital lives againts cybercriminals or curious -surveillance capitalists. Without cryptography, many of the things we routinely do in our lives such as paying for -groceries with a credit card, messaging a friend on `Signal `_ or unlocking a car with its keyfob -would not be possible. The security of all of these systems in its core lies on the secrecy of cryptographic keys. -Systems differ in what kind of keys they use, how often these keys are replaced and the intricacies of the cryptographic -operations these keys fit into but all have in common that their security relies on keeping the keys secret. - -In practice, this secrecy has been implemented in many different ways. Mass-market software such as browsers or -messenger apps usually relies on some operating system facility to tell the computer "*please keep this piece of memory -away from all other applications*". While on desktop operating systems usually this does not provide much of a barrier -to other programs on the same computer, on modern mobile operating systems this approach is actually quite secure. -However, given sufficient resources no security is perfect. All of these systems can be compromised if the host -operating system is compromised sufficiently, and for organizations with considerable resources a market has sprung up -that offers turn-key solutions for all wiretapping needs. - -In some applications, this level of security has not been considered sufficient. Particularly financial infrastructure -is such a high-profile target that a lot of effort has been put into the security of cryptographic implementations. The -best cryptographic algorithm is useless if it is run on a compromised system (from that system's point of view anyway). -One of the core cryptographic components in financial applications are smartcards like they are used as payment cards in -most countries nowadays. These smartcards contain a small, specialized cryptographic microcontroller that is designed to -be hard to tamper with. Though one of the design goals of the system is to reduce the amount of sensitive information -stored on the card, things such as copying of a card can only be hindered by making the chip hard to read out. - -.. raw:: html - -
- -
- -With smartcards being the means of choice on one side of the counter in electronic payments, on the other side of the -counter a different technology prevails. Attacks on payment terminals are bound to have much more dire consequences than -attacks on individual cards since one terminal might see hundreds of cards being read every day. For this reason, the -level of attack countermeasures employed in these terminals is a considerable step up from bare smartcards. While a -smartcard is made physically hard to tamper, it does not have a battery and it can only detect tampering once it is -powered by a reader. This allows for well-equipped attackers to use tools such as Focused Ion Beam (FIB) workstations to -circumvent the smartcard's defences while it is powered down, and then power up the card to carry out the actual attack. - -The answer to this problem in electronic payment infrastructure is called *Hardware Security Module*, or HSM. An HSM is -similar to a smartcard in its function (cryptographic processing using keys that are meant to never leave the protection -of the HSM). The one major between the two is that an HSM has its own battery and is continuously powered from its -manufacture to the day it is scrapped. If the HSM looses power at any point in time, it uses a small amount of energy -stored internally to securely wipe all cryptographic secrets from its memory within a few milliseconds. - -Being powered at all times allows the HSM to actively detect and respond to attacks. The most common way this is done is -by wrapping the juicy secret parts in a foil or a printed circuit board that is patterned with a long and convoluted -maze of wires, called a *mesh*. The HSM is continuously monitoring these wires for changes (such as shorts, breaks or -changes in resistance) and will sound the alarm when any are detected. Practically, this presents a considerable hurdle -to any attacker: They have to find a way to disable or circumvent the mesh while it is being monitored by the HSM. In -practice, often this is no insurmountable challenge but it again increases attack costs. - -DIY Meshes -========== - -Throughout my studies in security research I have always had an interest in HSMs. I have taken apart my fair share of -HSMs and at this point, to understand the technology more, I want to experiment with building my own HSM. In last year's -`HSM basics <{{}}>`_ post I have lined out some ideas for a next generation design that -deviates from the bread-and-butter apporoach of using a mesh as the primary security feature. Before embarking on -practical experiments with these ideas, I want to first take a stab at replicating the current state of the art as best -I can. State of the art meshes often use exotic substrates such as 3D plastic parts with traces chemically deposited on -their surface or special flexible substrates with conductive ink traces. These technologies will likely be too -cumbersome for me to implement myself only for a few prototypes, and industrial manufacturers will most likely be too -expensive. Thus, I will concentrate on regular PCB technology for now. - -The idea of a mesh on a PCB is pretty simple: You have one or several traces that you try to cover every corner of the -mesh PCB's area with. To be most effective, the traces should be as thin and as close together as possible. To increase -the chances of a manipulation being detected, multiple traces can also be used that can then be monitored for shorts -between them. - -While one can feasibly lay out these traces by hand, this really is an ideal application of a simple auto-router. While -general PCB autorouting is *hard*, auto-routing just a few traces to approximate a space-filling curve is not. Since I -am just starting out, I went with the simplest algorithmic solution I could think of. I first approximate the area -designated to the mesh with a square grid whose cells are a multiple of my trace/space size. The mesh will only be drawn -into grid cells that are fully inside the set boundaries. All cells outside or going across the border are discarded in -this step. - -I decided to implement this auto-router in a KiCAD plugin. Though KiCADs plugin API is not the best, it was just about -usable for this task. - -.. raw:: html - -
- KiCAD showing an irregular board shape with rounded corners and
-        indents. In the middle of the board there is a footprint for a 4-pin surface-mount pin header. -
The process starts out with the mesh shape being defined inside KiCAD. The mesh's outline is drawn - onto one of the graphical "Eco" layers. A footprint is placed to serve as a placeholder for the mesh's - connections to the outside world. This footprint is later used as the starting point for the mesh generation - algorithm.
-
- -.. raw:: html - -
- A vizualization of the grid fitting process. Over the mesh's irregular
-        outline a grid is drawn. In this picture, all grid cells that are fully inside the grid are shown. Grid cells
-        that overlap the mesh border are highlighted. Grid cells outside of the mesh border are not drawn. -
A visualization of the grid fitting process. First, a grid large enough to contain the mesh border - is generated. Then, every cell is checked for overlap with the mesh border area. If the cell is fully inside, it - (yellow), it is considered in the mesh generation later. Cells outside (gray) or on the border (red) are - discarded.
-
- -After generating the grid, starting from the place I want to connect to the mesh, I walk the grid's cells one by one to -generate a tree that covers the entire grid's area. To set the mesh's starting place I place a footprint on the board -(dark gray in the picture above) whose designator I then tell my script. The tree generation algorithm looks like a -depth-first search, except all checks are random. Depending on the level of randomness used at each step of the -algorithm it yields more or less organized-looking results. Below are five example runs of the algorithm at differing -levels of randomness with the cells colored according to their distance from the tree root. 0% randomness means that the -algorithm is going to try cells in forward direction first on every step, and only then try out left and right. 100% -means that on every step, the algorithm is choosing a new direction at random. - -.. raw:: html - -
-
- a completely organized looking grid with spiral patterns all over. -
0%
-
- -
25%
-
- -
50%
-
- -
75%
-
- a completely random looking grid with cells aggregating into ireggular
-        areas that look like paint splotches. -
100%
-
-
- -After I have built this tree like you would do in a depth-first search, I draw my one or several mesh mesh traces into -it. The core observation here is that there is only 16 possible ways a cell can be connected: It has four neighbors, -each of which it can either be connected to or not, which results in 2^4 options. If you consider rotations and -mirroring, this works out to rotations or mirrored versions of only six base tiles: The empty tile, a tile with all four -sides connected, a straight through, a 90 degree bend, and a "T"-junction—see the illustration below. - -.. raw:: html - -
- -
- There are six possible tile types in our connectivity graph inside its square tiling. This graphic illustrates - all sixteen rotations of these with how they would look in a two-conductor mesh. -
-
- -After tiling the grid according to the key above, we get the result below. - -.. raw:: html - -
- -
- An auto-routed mesh with traces colored according to tile types. -
-
- -.. raw:: html - -
- -
- The same mesh, but with traces all black. -
-
- -Putting it all together got me the KiCAD plugin you can see in the screenshot below. - -.. raw:: html - -
- -
- The plugin settings window open. -
-
- -.. raw:: html - -
- -
- After runing the plugin, the generated mesh looks like this in pcbnew. -
-
- -I am fairly happy with the result, but getting there was a medium pain. Especially KiCAD's plugin API is still very -unfinieshed. It is hard to use, most parts are completely undocumented and if you use anything but its most basic parts -things tend to break. One particular pain point for me was that after generating the mesh, the traces have been added to -the board, but are still invisible for some reason. You have to save the board first, then re-load the file for them to -become visible. Also KiCAD crashes whenever the plugin tries to remove a trace, so currently my workflow involves always -making a copy of the board file first and treating mesh generation as a non-reversible finishing step. - -`Check out the code on my cgit `_. - -.. :: - - .. raw:: html - -
- -
-
- diff --git a/content/posts/led-characterization/images/daylight_spectrum_dvd.jpg b/content/posts/led-characterization/images/daylight_spectrum_dvd.jpg deleted file mode 100644 index d01242e..0000000 Binary files a/content/posts/led-characterization/images/daylight_spectrum_dvd.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/driver_ringing_strong.jpg b/content/posts/led-characterization/images/driver_ringing_strong.jpg deleted file mode 100644 index 0419a0e..0000000 Binary files a/content/posts/led-characterization/images/driver_ringing_strong.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/driver_ringing_weak.jpg b/content/posts/led-characterization/images/driver_ringing_weak.jpg deleted file mode 100644 index 12f9c5d..0000000 Binary files a/content/posts/led-characterization/images/driver_ringing_weak.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/electronics_whole.jpg b/content/posts/led-characterization/images/electronics_whole.jpg deleted file mode 100644 index faaf751..0000000 Binary files a/content/posts/led-characterization/images/electronics_whole.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/hsv_cylinder.png b/content/posts/led-characterization/images/hsv_cylinder.png deleted file mode 100644 index 265f3e0..0000000 Binary files a/content/posts/led-characterization/images/hsv_cylinder.png and /dev/null differ diff --git a/content/posts/led-characterization/images/photodiode_sensitivity.svg b/content/posts/led-characterization/images/photodiode_sensitivity.svg deleted file mode 100644 index e845444..0000000 --- a/content/posts/led-characterization/images/photodiode_sensitivity.svg +++ /dev/null @@ -1,874 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/led-characterization/images/preamp_back.jpg b/content/posts/led-characterization/images/preamp_back.jpg deleted file mode 100644 index 0af495d..0000000 Binary files a/content/posts/led-characterization/images/preamp_back.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/preamp_front.jpg b/content/posts/led-characterization/images/preamp_front.jpg deleted file mode 100644 index 62fad28..0000000 Binary files a/content/posts/led-characterization/images/preamp_front.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/preamp_schematic.jpg b/content/posts/led-characterization/images/preamp_schematic.jpg deleted file mode 100644 index 6be7bbd..0000000 Binary files a/content/posts/led-characterization/images/preamp_schematic.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/processed_plot_cheap_rgb.svg b/content/posts/led-characterization/images/processed_plot_cheap_rgb.svg deleted file mode 100644 index 9745172..0000000 --- a/content/posts/led-characterization/images/processed_plot_cheap_rgb.svg +++ /dev/null @@ -1,2366 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/led-characterization/images/raw_plot_cheap_rgb.svg b/content/posts/led-characterization/images/raw_plot_cheap_rgb.svg deleted file mode 100644 index 895569f..0000000 --- a/content/posts/led-characterization/images/raw_plot_cheap_rgb.svg +++ /dev/null @@ -1,2739 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/led-characterization/images/rgb_cube.svg b/content/posts/led-characterization/images/rgb_cube.svg deleted file mode 100644 index 8af7a00..0000000 --- a/content/posts/led-characterization/images/rgb_cube.svg +++ /dev/null @@ -1,222 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - G+ - - - - - - - - R+ - - - - B+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - R- - - - - B- - - - - - - - - G- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - R : 83 - - - G : 150 - - - B : 60 - - G: 150 - B: 60 - R: 83 - - - - - - - - R - G - B - - - R - G - B - - - R 255 - G 255 - B 255 - - - - - \ No newline at end of file diff --git a/content/posts/led-characterization/images/spectrograph_step1_parts.jpg b/content/posts/led-characterization/images/spectrograph_step1_parts.jpg deleted file mode 100644 index 107220a..0000000 Binary files a/content/posts/led-characterization/images/spectrograph_step1_parts.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/spectrograph_step2.jpg b/content/posts/led-characterization/images/spectrograph_step2.jpg deleted file mode 100644 index b678372..0000000 Binary files a/content/posts/led-characterization/images/spectrograph_step2.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/spectrograph_step3.jpg b/content/posts/led-characterization/images/spectrograph_step3.jpg deleted file mode 100644 index acd6d5e..0000000 Binary files a/content/posts/led-characterization/images/spectrograph_step3.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/spectrograph_step4_complete.jpg b/content/posts/led-characterization/images/spectrograph_step4_complete.jpg deleted file mode 100644 index d23560d..0000000 Binary files a/content/posts/led-characterization/images/spectrograph_step4_complete.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/zeus_hammer_breadboard.jpg b/content/posts/led-characterization/images/zeus_hammer_breadboard.jpg deleted file mode 100644 index 08efebb..0000000 Binary files a/content/posts/led-characterization/images/zeus_hammer_breadboard.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/zeus_hammer_breadboard_original.jpg b/content/posts/led-characterization/images/zeus_hammer_breadboard_original.jpg deleted file mode 100644 index 4f8f34e..0000000 Binary files a/content/posts/led-characterization/images/zeus_hammer_breadboard_original.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/zeus_hammer_schematic.jpg b/content/posts/led-characterization/images/zeus_hammer_schematic.jpg deleted file mode 100644 index 0e6f483..0000000 Binary files a/content/posts/led-characterization/images/zeus_hammer_schematic.jpg and /dev/null differ diff --git a/content/posts/led-characterization/images/zeus_hammer_schematic_original.jpg b/content/posts/led-characterization/images/zeus_hammer_schematic_original.jpg deleted file mode 100644 index b50b3a0..0000000 Binary files a/content/posts/led-characterization/images/zeus_hammer_schematic_original.jpg and /dev/null differ diff --git a/content/posts/led-characterization/index.rst b/content/posts/led-characterization/index.rst deleted file mode 100644 index 6a8c7ee..0000000 --- a/content/posts/led-characterization/index.rst +++ /dev/null @@ -1,500 +0,0 @@ ---- -title: "LED Characterization" -date: 2018-05-02T11:18:38+02:00 ---- - -Preface -------- - -Recently, I have been working on a `small driver`_ for ambient lighting using 12V LED strips like you can get -inexpensively from China. I wanted to be able to just throw one of these somewhere, stick down some LED tape, hook it up -to a small transformer and be able to control it through Wifi. When I was writing the firmware, I noticed that when -fading between different colors, the colors look *all wrong*! This observation led me down a rabbit hole of color -perception and LED peculiarities. - -The idea of the LED driver was that it can be used either with up to eight single-color LED tapes or, much more -interesting, with up to two RGB or RGBW (red-green-blue-white) LED tapes. For ambient lighting high color resolution was -really important so you could dim it down a lot without flickering. I ended up using the same driver stage I used in the -`multichannel LED driver`_ project for its great color resolution and low hardware requirements. - -.. raw:: html - -
- An illustration of the RGB color cube. -
An illustration of the RGB color cube. - Picture by - Maklaan from Wikimedia Commons, - CC-BY-SA 3.0 -
-
- -To make setting colors over Wifi more intuitive I implemented support for HSV colors. RGB is fine for communication -between computers, but I think HSV is easier to work with when manually inputting colors from the command line. RGB is -close to how most monitors, cameras and the human visual apparatus work on a very low level but doesn't match -higher-level human color perception very well. When we describe a color we tend to think in terms of "hue" or -"brightness", and computing a measure of those from RGB values is not easy. - -Colors and Color Spaces ------------------------ - -`Color spaces`_ are a mathematical abstraction of the concept of color. When we say "RGB", most of the time we actually -mean `sRGB`_, a standardized notion of how to map three numbers labelled "red", "green" and "blue" onto a perceived -color. `HSV`_ is an early attempt to more closely align these numbers with our perception. After HSV, a number of other -*perceptual* color spaces such as `XYZ (CIE 1931)`_ and `CIE Lab/LCh`_ were born, further improving this alignment. In -this mathematical model, mapping a color from one color space into another color space is just a coordinate -transformation. - -.. raw:: html - -
- An illustration of the HSV color space as a cylinder. -
An illustration of the HSV color space as a cylinder. - Picture by - SharkD from Wikimedia Commons, - CC-BY-SA 3.0 -
-
- -CIE 1931 XYZ is much larger than any other color space, which is why it is a good basis to express other color spaces -in. In XYZ there are many coordinates that are outside of what the human eye can perceive. Below is an illustration of -the sRGB space within XYZ. The wireframe cube is (0,0,0) to (1,1,1) in XYZ. The colorful object in the middle is what -of sRGB fits inside XYZ, and the lines extending out from it indicate the space that can be expressed in sRGB but not in -XYZ. The fat white curve is a projection of the *monochromatic spectral locus*, that is the curve of points you get in -XYZ for pure visible wavelengths. - -As you can see, sRGB is *much* smaller than XYZ or even the part within the monochromatic locus that we can perceive. In -particular in the blues and greens we loose *a lot* of colors to sRGB. - -.. raw:: html - -
- -
Illustration of the measured sRGB color space within XYZ. The thick, white line is the spectral - locus. - - mkv/h264 download / - webm download -
-
- -The wrong colors I got when fading between colors were caused by this coordinate transformation being askew. Thinking -over the problem, there are several sources for imperfections: - -* The LED driver may not be entirely linear. For most modulations such as PWM the brightness will be linear starting - from a certain value, but there is probably an offset caused by imperfect edges of the LED current. This offset can be - compensated with software calibration. I built a calibration setup for driver linearity in the `multichannel LED - driver`_ project. Below are pictures of ringing on the edges of an LED driver's waveform. - -* The red, green and blue channels of the LEDs used on the LED tape are not matched. This skews the RGB color space. - In practice, the blue channel of my RGB tape to me *looks* much brighter than the red channel. - -* The precise colors of the red, green and blue channels of the LEDs are unknown. Though the red channel *looks* red, it - may be of a slightly different hue compared to the reference red used in `sRGB`_ which would also skew the RGB color - space. - -.. raw:: html - -
-
- Strong ringing on the LED voltage waveform edge at about
-            100% overshoot during about 70% of the cycle time. -
The LED strip being at the end of a couple meters of wire caused extremely bad ringing at high - driving frequencies.
-
- Weak ringing on the LED voltage waveform edge at about 30%
-            overshoot during about 20% of the cycle time. -
Adding a resistor in front of the MOSFET gate to slow the transition dampened the ringing - somewhat, but ultimately it cannot be eliminated entirely.
-
-
- -These last two errors are tricky to compensate. What I needed for that was basically a model of the *perceived* colors -of the LED tape's color channels. A way of doing his is to record the spectra of all color channels and then evaluate -their respective XYZ coordinates. If all three channels are measured in one go with the same setup the relative -magnitudes of the channels in XYZ will be accurate. - -To map any color to the LEDs, the color's XYZ coordinates simply have to be mapped onto the linear coordinate system -produced by these three points within XYZ. LEDs are mostly linear in their luminous flux vs. current characteristic so -this model will be adequate. The spectral integrals mapping the channels' measured responses to XYZ need only be -calculated once and their results can be used as scaling factors thereafter. - -Measuring the spectrum ----------------------- - -In order to compensate for the cheap LED tape's non-ideal performance I had to measure the LED's red, green and blue -channels' spectra. The obvious thing would be to go out and buy a `spectrograph`_, or ask someone to borrow theirs. The -former is kind of expensive, and I did not want to wait two weeks for the thing to arrive. The latter I could probably -not do every time I got new LED tape. Thus the only choice was to build my own. - -Luckily, building your own spectrometer is really easy. The first thing you need is something that splits incident light -into its constituent wavelengths. In professional devices this is called the *`monochromator`_*, since it allows extraction -of small color bands from the spectrum. The second thing is some sort of optics that project the incident light onto a -screen behind the monochromator. In professional devices lenses or curved mirrors are used. In a simple homebrew job a -pinhole as you would use in a `camera obscura`_ does a remarkably nice job. - -For the monochromator component several things could be used. A prism would work, but I did not have any. The -alternative is a `diffraction grating`_. Professional gratings are quite specialized pieces of equipment and thus -rather expensive. Luckily, there is a common household item that works almost as well: A regular CD or DVD. The -microscopic grooves that are used to record data in a CD or DVD work the same as the grooves in a professional -diffraction grating. - -Household spectra ------------------ - -From this starting point, a few seconds on my favorite search engine yielded an `article by two researchers from the -National Science Museum in Tokyo`_ providing a nice blueprint for a simple cardboard-and-DVD construction for use in -classrooms. I replicated their device using a DVD and it worked beautifully. Daylight and several types of small LEDs I -had around did show the expected spectra. Small red, yellow, green, and blue LEDs showed narrow spectra, daylight one -continuous broad one, and white LEDs a continuous broad one with a distinct bright spot in the blue part. The -single-color LED spectra are quite narrow since they are determined by the LED's semiconductor's band gap, which is -specific to the semiconductor used and is quite precise. White LEDs are in fact a blue LED chip covered with a so-called -*phosphor*. This phosphor is not elementary phosphorus but an anorganic compound that absorbs the LED chip's blue light -and re-emits a broader spectrum of more yellow-ish wavelengths instead. The final LED spectrum is a superposition of -both spectra, with some of the original blue light leaking through the phosphor mixing with the broadband yellow -spectrum of the phosphor. - -.. raw:: html - -
-
- -
The ingredients. The cup of coffee and Madoka Magica DVD set are essential to the eventual - function of the appartus.
-
- -
Step 1: Cut to size and mark down all holes as described in the manual
-
-
- -
Step 2: Cut out all holes
-
- -
The finished result with the back side showing. The viewing window is on the bottom of the other - side.
-
-
- - -Now that I had a spectrograph, I needed a somewhat predictable way of measuring the spectrum it gave me. - -Measuring a spectrum --------------------- - -Pointing a camera at the spectrograph would be the obvious thing to do. This produces pretty images but has one critical -flaw: I wanted to acquire quantitative measurements of brightness across the spectrum. Since I don't have a precise -technical datasheet specifying the spectral response of any of my cameras I can't compare the absolute brightness of -different colors on their pictures. Some other sensor was needed. - -.. raw:: html - -
- -
The daylight spectrum as seen using a DVD as a grating. - Picture by - Xofc from Wikimedia Commons, - CC-BY-SA 4.0 -
-
- - -Measuring light intensity -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Looking around my lab, I found a bag of `SFH2701`_ visible-light photodiodes. Their -datasheet includes their spectral response so I can compensate for that, allowing precise-ish absolute intensity -measurements. Just like LEDs, photodiodes are extremely linear across several orders of magnitude. The datasheet of the -classic `BPW34`_ photodiode shows that this photodiode's light current is exactly proportional to illuminance over at -least three orders of magnitude. The `SFH2701`_ datasheet does not include a similar graph but its performance will be -similar. The `SFH2701`_ photodiodes I had at hand were perfect for the job compared to the vintage `BPW34`_ since their -active sensing area is really small (0.6mm by 0.6mm) compared to the BPW34 (a whopping 3mm by 3mm). If I were to use a -`BPW34`_ I would have to insert some small apterture in front of it so it does not catch too broad a part of the -spectrum at once. The `SFH2701`_ is small enough that if I just point it at the projected spectrum directly I will -already get only a small part of the spectrum inside its 0.6mm active area. - -To convert the photodiode's tiny photocurrent into a measurable voltage I built another copy of the `transimpedance -amplifier`_ circuit I already used in the `multichannel LED driver`_. A `transimpedance amplifier`_ is an -amplifiert that produces a large voltage from a small current. The weird name comes from the fact that it works kind of -like an amplified resistor (which can be generalized as an *impedance* electrically). Apply a current to a resistor and -you get a voltage. A transimpedance amplifiert does the same with the difference that its input always stays at 0V, -making it look like an ideal current sink to the connected current source. - -Transimpedance amplifiers are common in optoelectronics to convert small photocurrents to voltages. In this instance I -built a very simple circuit with a dampened transimpedance amplifier stage followed by a simple RC filter for noise -rejection and a regular non-inverting amplifier using another op-amp from the same chip to further boost the filtered -transimpedance amplifier output. I put all the passives setting amplifier response (the gain-setting resistors and the -filter resistor and capacitors) on a small removable adapter so I could easily change them if necessary. I put a small -trimpot on the virtual ground both amplifers use as a reference so I could trim that if necessary. - -.. raw:: html - -
- A drawing of the photodiode preamplifier's schematic -
The photodiode preamplifier schematic. Schematic drawn with an unlicensed copy of - DaveCAD.
-
- -Following are pictures of the preamplifier board. The connectors on the top-left side are two copies of the analog -signal for the ADC and a small panel meter. The SMA connector is used as the photodiode input since coax cables are -generally low-leakage and have built-in shielding. The circuit is powered via the micro-USB connector and the analog -ground bias voltage can be adjusted using the trimpot. - -For easy replacement, all passives setting gain and frequency response are on a small, pluggable carrier PCB made from a -SMD-to-DIP adapter. - -Flying-wire construction is just fine for this low-frequency circuit. In a high-speed photodiode preamp, the -transimpedance amplifier circuit would be highly sensitive to stray capacitance, but we're not aiming at high speed -here. - -.. raw:: html - -
-
- -
The front side of the preamplifier board.
-
- -
The wiring of the photodiode preamp.
-
-
- -Given a way to measure intensity what remains missing is a way to scan a single photodiode across the spectrum. - -Scanning the projection -~~~~~~~~~~~~~~~~~~~~~~~ - -A cheap linear stage can be found in any old CD or DVD drive. These drives use a small linear stage based on a -stepper-driven screw to move the laser unit radially. Removing the laser unit and connecting a leftover stepper driver -module I was left with a small linear stage with about 45 steps per cm without microstepping enabled. The driver I used -was an `A4988`_ module that required at least 8V motor drive voltage. I used a small micro USB-input boost converter -module to generate a stable 10V supply for the motor driver, with the USB's 5V rail used as a logic supply for the motor -driver. - -The `SFH2701`_ can easily be mounted to the linear stage using a small SMD breakout board glued in place with thin wires -connecting it to the transimpedance amplifier. The DVD drive linear stage is not very strong so it is important that -this wire does not put too much strain on it. - -Above the photodiode, I mounted a small piece of paper on the linear stage to be used as a projection screen to align -the linear stage in front of the spectrometer viewing window. A line on the screen paper points to the photodiode die in -parallel to the linear stage allowing precise alignment. - -The whole unit with photodiode preamplifier, linear stage, photodiode and stepper motor driver finally looks like this: - -.. raw:: html - -
- The complete electronics setup of the spectrograph. In the back
-        there is the DVD drive stepper stage. In front of it, mounted on a piece of wood are a small USB-to-12V
-        switching-regulator module to power the stepper motor in the top left, below on the bottom left is the
-        photodiode preamp and on the right is a breadboard with the stepper driver module and lots of jumper wires
-        interconnecting everything. On the right of the breadboard, a buspirate is attached to interface everything to a
-        computer. On the bottom edge of the piece of wood, two LED panel meters are mounted for readout of the preamp
-        output and the stepper supply voltages. -
The complete electronics setup. The buspirate on the right interfaces to a computer and controls the - stepper driver and ADC'es the preamp output. The two panel meters show the preamp output and stepper voltage for - setup.
-
- -The projection of the spectrum can be adjusted by moving the light source relative to the entry slot and by moving -around the grating DVD. - -The capture process -~~~~~~~~~~~~~~~~~~~ - -To capture a spectrum, first the light source has to be mounted near the spectrograph's entry slot. The LED tape I -tested I just taped face-down directly into it. Next, the grating DVD has to be adjusted to make sure the spectrum -covers a sensible part of the photodiode's path. Mostly, this boils down to adjusting the photodiode distance and height -to match the vertical extent and wiggling the grating DVD to adjust the projection's horizontal position. - -After the optics are set-up, the photodiode preamplifier has to be adjusted. In my experiments, most LED tape at 5GΩ -required a high-ish amplification. The goal in this step is to maximize the peak response of the preamp to be just -shy of its VCC rail to make best use of its dynamic range. To adjust the pre-amp, I took several very coarsely-spaced -measurements to give me an estimate of the peak while I did not yet know its precise location. - -Since stray daylight totally swamped out the weak projection of the LED's spectrum I shielded the entire setup with a -small box made of black cardboard and two black t-shirts on top. This shielding proved adequate for all my measurements -but I had to be careful not to accidentially move the DVD that was stuck into the spectrograph with the shielding -t-shirts. - -For capturing a single spectrum I wrote a small python script that will automatically move the stepper in adjustable -intervals and take two measurements at each point, one with the LED tape off that can be used for offset calibration and -one with the LED tape on. All measurements are stored in a sqlite database that can then be accesssed from other -scripts. - -I built a small script that shows the progress of the current run and an jupyter notebook for data analysis. The jupyter -notebook is capable of live-updating a graph with the in-progress spectrum's data. This was quite useful as a sanity -check for when I made some mistake easy to spot in the resulting data. - -After one color channel is captured, the LED tape has to be manually set to the next color and the next measurement can -begin. - -.. raw:: html - -
- A plot with three wide peaks, two large peaks on both sides and
-        one smaller one in the middle. The middle one overlaps the two on the sides. The large ones are about 2.5V in
-        amplitude. Overall, the plot is about 300 stepper steps wide with each peak being around 130 steps wide. -
A plot of the raw preamp output voltage versus stepper position. From left to right, the three peaks - are blue, green and red. Step 0 corresponds to the bottommost stepper position and the shortest wavelength. -
-
- - -Data analysis -~~~~~~~~~~~~~ - -Data analysis consists of three major steps: Offset- and stray light removal, wavelength and amplitude calibration and -color space mapping. - -Offset removal -************** -The first task is to remove the offset caused by dark current as well as stray light of the LED's bright primary -reflection on the DVD. The LED is very bright and only a small part of its light gets reflected by the grating towards -the photodiode screen. The remaining part of the light is reflected onto the table in front of the DVD spectrograph. -Though I covered all of this with black cardboard, some of that light ultimately gets reflected onto the photodiode. -This causes a large offset, in particular in the blue part of the spectrum since in this part the photodiode is closest -to the spectrograph's opening. - -The composite offset can be approximated with a second-order polynomial that is fitted to all the data outside of the -main peak's area. Since at this point the wavelength of each data point is still unknown this is done with a rough first -estimate of the three colors' peaks' locations and widths. - -Wavelength- and amplitude calibration -************************************* -The photodiode's response is strongly wavelength-dependent. In particular in the blue band, the photodiode's sensitivity -gets very poor down to about 20% at the edge to ultraviolet. This effect is strong enough to move the apparent location -of the blue peak towards red. - -.. raw:: html - -
- A plot of photodiode sensitivity against wavelength relative
-        to peak sensitivity at 820nm.  The sensitivity rises from 20% at 380nm approximately linearly to 80% at 620nm,
-        then the rise rolls off. -
A plot of the photodiode's relative sensitivity in the visible spectrum. The sensitivity is - normalized against its peak at 820nm. -
-
- -The problem is that in order to remove this non-linearity, we would already have to know the wavelength of the measured -light. Since I don't, I settled for a two-step process. First, a coarse wavelength calibration is done relative to the -red peak and the short-wavelength edge of the blue peak. The photodiode measurements are then sensitivity-corrected -using this coarse measurement. Then all three channel peaks are measured in the resulting data and a fine wavelength -estimate is produced by a least-squares fit of a linear function. This fine estimate is then used for a second -sensitivity correction of all original measurements and the scale is changed from stepper motor step count to -wavelength in nanometers. - -.. raw:: html - -
- A plot with three wide peaks, all three of different
-        heights. The leftmost peak is highest at 6nA, the middle peak lowest at 1.6nA and the rightmost peak in between
-        at 4nA.  The middle one overlaps the two on the sides.  Overall, the plot spans about 300nm on its x axis with
-        each peak being around 100nm wide. -
A plot of the processed measurements. From left to right, the three peaks are blue, green and red. -
-
- -.. FIXME re-do these measurements, avoiding clipping -.. FIXME re-do calibration using CCFL -.. FIXME calibration for brightness imbalance due to wedge-shaped projection of spectrum - -Color space mapping -******************* -Finally, to achieve the objective of measuring the LED tape's channels' precise color coordinates the measured spetra -have to be matched against the color spaces' *color matching functions*. The color matching functions describe how -strong the color space's idealized *standard observer* would react to light at a particular wavelength. Going from a -measured spectrum to color coordinates XYZ works by integrating over the product of the measurement and each color -coordinate's color matching function. - -The result are three color coordinates X, Y and Z for each channel R, G and B yielding nine coordinates in total. When -written as a matrix conversion between XYZ color space and LED-RGB color space is as simple as multiplying that matrix -(or its inverse) and a vector from one of the color spaces. - -In XYZ space, the set of colors that can be produced with this LED tape is described by the `parallelepiped`_ spanned by -the three channel's XYZ vectors. In the following figures, you can see a three-dimensional model of the RGB LED's color -space (colorful) as well as sRGB (white) for comparison plotted within CIE 1931 XYZ. There is no natural map to scale -both so for this illustration the LED color space has been scaled to fit. These figures were made with blender and a few -lines of python. The blender project file including all settings and the python script to generate the color space -models can be found in the `project repo`_. - -.. raw:: html - -
- -
Illustration of the measured LED color space scaled to fit within XYZ with sRGB (light gray) for - comparison. The thick, white line is the spectral locus. - - mkv/h264 download / - webm download -
-
- -As you can see, the result is pretty disappointing. The LED's color space parallepiped is very narrow, which is because -the blue channel is much brighter than the other two channels. An easy fix for this is to scale-up the RGB space and -drop any values outside XYZ. The scaling factor is a trade-off between color space coverage and brightness. You can -produce the most colors when you clip all channels to brightness of the weakest channel (green in this case), but that -will make the result very dim. Scaling brightness like that stretches the RGB parallelepiped along its major axis. Up to -a point the number of possible colors (the gamut) increases at expense of maximum brightness. When the parallelepiped is -stretched far enought for all three channel vectors to be outside the 1,1,1 XYZ-cube, maximum brightness continues to -decrease but the gamut stays constant. I don't know a simple scientific way to solve this problem, so I just played -around with a couple of factors and settled on 2.5 as a reasonable compromise. Below is an illustration. - -.. raw:: html - -
- -
Illustration of the measured LED color space at scale factor 2.5 within XYZ with sRGB (light gray) - for comparison. The thick, white line is the spectral locus. - - mkv/h264 download / - webm download -
-
- -Firmware implementation ------------------------ -In the end, the above measurements yield two matrices: One for mapping XYZ to RGB, and one for mapping RGB to XYZ. Of -the several versions of CIE XYZ I chose the CIE 1931 XYZ color space as a basis for the firmware because it is most -popular. Mapping a color coordinate in one color space to the other is as simple as performing nine floating-point -multiplications and six additions. Mapping Lab or Lch to RGB is done by first mapping Lab/Lch to XYZ, then XYZ to RGB. -Lab to XYZ is somewhat complex since it requires a floating-point power for gamma correction, but any self-respecting -libc will have one of those so this is still no problem. Lch also requires floating-point sine and cosine functions, but -these should still be no problem on most hardware. - -My implementation of these conversions in the ESP8266 firmware of my `Wifi LED driver`_ can be found `on Github`_. You -can view the Jupyter notebook most of the analysis above `here `__. - -.. _`on Github`: https://github.com/jaseg/esp_led_drv/blob/master/user/led_controller.c -.. _`project repo`: https://github.com/jaseg/led_drv -.. _`Wifi LED driver`: {{}} -.. _`small driver`: {{}} -.. _`multichannel LED driver`: {{}} -.. _`sRGB`: https://en.wikipedia.org/wiki/SRGB -.. _`CC BY-SA 3.0`: https://creativecommons.org/licenses/by-sa/3.0 -.. _`Color spaces`: https://en.wikipedia.org/wiki/Color_space -.. _`HSV`: https://en.wikipedia.org/wiki/HSL_and_HSV -.. _`CIE Lab/LCh`: https://en.wikipedia.org/wiki/Lab_color_space -.. _`XYZ (CIE 1931)`: https://en.wikipedia.org/wiki/CIE_1931_color_space -.. _`camera obscura`: https://en.wikipedia.org/wiki/Pinhole_camera -.. _`article by two researchers from the National Science Museum in Tokyo`: http://www.candac.ca/candacweb/sites/default/files/BuildaSpectroscope.pdf -.. _`spectrograph`: https://en.wikipedia.org/wiki/Ultraviolet%E2%80%93visible_spectroscopy -.. _`monochromator`: https://en.wikipedia.org/wiki/Monochromator -.. _`diffraction grating`: https://en.wikipedia.org/wiki/Diffraction_grating -.. _`SFH2701`: https://dammedia.osram.info/media/resource/hires/osram-dam-2495903/SFH%202701.pdf -.. _`BPW34`: http://www.vishay.com/docs/81521/bpw34.pdf -.. _`transimpedance amplifier`: https://en.wikipedia.org/wiki/Transimpedance_amplifier -.. _`A4988`: https://www.pololu.com/file/0J450/A4988.pdf -.. _`parallelepiped`: https://en.wikipedia.org/wiki/Parallelepiped diff --git a/content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv b/content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv deleted file mode 100644 index 0a1eece..0000000 Binary files a/content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv and /dev/null differ diff --git a/content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.webm b/content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.webm deleted file mode 100644 index 04d355c..0000000 Binary files a/content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.webm and /dev/null differ diff --git a/content/posts/led-characterization/video/led_within_srgb_scale=1.0.mkv b/content/posts/led-characterization/video/led_within_srgb_scale=1.0.mkv deleted file mode 100644 index 69dfccf..0000000 Binary files a/content/posts/led-characterization/video/led_within_srgb_scale=1.0.mkv and /dev/null differ diff --git a/content/posts/led-characterization/video/led_within_srgb_scale=1.0.webm b/content/posts/led-characterization/video/led_within_srgb_scale=1.0.webm deleted file mode 100644 index 8034882..0000000 Binary files a/content/posts/led-characterization/video/led_within_srgb_scale=1.0.webm and /dev/null differ diff --git a/content/posts/led-characterization/video/led_within_srgb_scale=2.5.mkv b/content/posts/led-characterization/video/led_within_srgb_scale=2.5.mkv deleted file mode 100644 index a7fba0b..0000000 Binary files a/content/posts/led-characterization/video/led_within_srgb_scale=2.5.mkv and /dev/null differ diff --git a/content/posts/led-characterization/video/led_within_srgb_scale=2.5.webm b/content/posts/led-characterization/video/led_within_srgb_scale=2.5.webm deleted file mode 100644 index d0c9135..0000000 Binary files a/content/posts/led-characterization/video/led_within_srgb_scale=2.5.webm and /dev/null differ diff --git a/content/posts/led-characterization/video/led_within_srgb_scale=3.mkv b/content/posts/led-characterization/video/led_within_srgb_scale=3.mkv deleted file mode 100644 index 94c7750..0000000 Binary files a/content/posts/led-characterization/video/led_within_srgb_scale=3.mkv and /dev/null differ diff --git a/content/posts/led-characterization/video/led_within_srgb_scale=3.webm b/content/posts/led-characterization/video/led_within_srgb_scale=3.webm deleted file mode 100644 index 3dc88cc..0000000 Binary files a/content/posts/led-characterization/video/led_within_srgb_scale=3.webm and /dev/null differ diff --git a/content/posts/led-characterization/video/sRGB.mkv b/content/posts/led-characterization/video/sRGB.mkv deleted file mode 100644 index 903c719..0000000 Binary files a/content/posts/led-characterization/video/sRGB.mkv and /dev/null differ diff --git a/content/posts/led-characterization/video/sRGB.webm b/content/posts/led-characterization/video/sRGB.webm deleted file mode 100644 index 737cc1b..0000000 Binary files a/content/posts/led-characterization/video/sRGB.webm and /dev/null differ diff --git a/content/posts/led-characterization/video/scale=1.mkv b/content/posts/led-characterization/video/scale=1.mkv deleted file mode 100644 index 410896e..0000000 Binary files a/content/posts/led-characterization/video/scale=1.mkv and /dev/null differ diff --git a/content/posts/led-characterization/video/scale=1.webm b/content/posts/led-characterization/video/scale=1.webm deleted file mode 100644 index dc599be..0000000 Binary files a/content/posts/led-characterization/video/scale=1.webm and /dev/null differ diff --git a/content/posts/led-characterization/video/scale=2.5.mkv b/content/posts/led-characterization/video/scale=2.5.mkv deleted file mode 100644 index 6ff3619..0000000 Binary files a/content/posts/led-characterization/video/scale=2.5.mkv and /dev/null differ diff --git a/content/posts/led-characterization/video/scale=2.5.webm b/content/posts/led-characterization/video/scale=2.5.webm deleted file mode 100644 index 6a6a860..0000000 Binary files a/content/posts/led-characterization/video/scale=2.5.webm and /dev/null differ diff --git a/content/posts/led-characterization/video/scale=5.mkv b/content/posts/led-characterization/video/scale=5.mkv deleted file mode 100644 index b4e7e65..0000000 Binary files a/content/posts/led-characterization/video/scale=5.mkv and /dev/null differ diff --git a/content/posts/led-characterization/video/scale=5.webm b/content/posts/led-characterization/video/scale=5.webm deleted file mode 100644 index 0298a11..0000000 Binary files a/content/posts/led-characterization/video/scale=5.webm and /dev/null differ diff --git a/content/posts/multichannel-led-driver/images/asymmetric_iled.svg b/content/posts/multichannel-led-driver/images/asymmetric_iled.svg deleted file mode 100644 index c18d5de..0000000 --- a/content/posts/multichannel-led-driver/images/asymmetric_iled.svg +++ /dev/null @@ -1,2222 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/multichannel-led-driver/images/asymmetric_vgate.svg b/content/posts/multichannel-led-driver/images/asymmetric_vgate.svg deleted file mode 100644 index 473f494..0000000 --- a/content/posts/multichannel-led-driver/images/asymmetric_vgate.svg +++ /dev/null @@ -1,1933 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/multichannel-led-driver/images/bcm_schema.jpg b/content/posts/multichannel-led-driver/images/bcm_schema.jpg deleted file mode 100644 index 5d3ef08..0000000 Binary files a/content/posts/multichannel-led-driver/images/bcm_schema.jpg and /dev/null differ diff --git a/content/posts/multichannel-led-driver/images/corrected_brightness_sim.svg b/content/posts/multichannel-led-driver/images/corrected_brightness_sim.svg deleted file mode 100644 index 2b9cf16..0000000 --- a/content/posts/multichannel-led-driver/images/corrected_brightness_sim.svg +++ /dev/null @@ -1,765 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/multichannel-led-driver/images/driver_linearity_raw.svg b/content/posts/multichannel-led-driver/images/driver_linearity_raw.svg deleted file mode 100644 index 58aa43f..0000000 --- a/content/posts/multichannel-led-driver/images/driver_linearity_raw.svg +++ /dev/null @@ -1,937 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/multichannel-led-driver/images/driver_output_ltspice_schematic.jpg b/content/posts/multichannel-led-driver/images/driver_output_ltspice_schematic.jpg deleted file mode 100644 index 52000a8..0000000 Binary files a/content/posts/multichannel-led-driver/images/driver_output_ltspice_schematic.jpg and /dev/null differ diff --git a/content/posts/multichannel-led-driver/images/driver_pcb_built.jpg b/content/posts/multichannel-led-driver/images/driver_pcb_built.jpg deleted file mode 100644 index f5da956..0000000 Binary files a/content/posts/multichannel-led-driver/images/driver_pcb_built.jpg and /dev/null differ diff --git a/content/posts/multichannel-led-driver/images/driver_ringing_strong.jpg b/content/posts/multichannel-led-driver/images/driver_ringing_strong.jpg deleted file mode 100644 index 0419a0e..0000000 Binary files a/content/posts/multichannel-led-driver/images/driver_ringing_strong.jpg and /dev/null differ diff --git a/content/posts/multichannel-led-driver/images/driver_ringing_weak.jpg b/content/posts/multichannel-led-driver/images/driver_ringing_weak.jpg deleted file mode 100644 index 12f9c5d..0000000 Binary files a/content/posts/multichannel-led-driver/images/driver_ringing_weak.jpg and /dev/null differ diff --git a/content/posts/multichannel-led-driver/images/led_strip_alight.jpg b/content/posts/multichannel-led-driver/images/led_strip_alight.jpg deleted file mode 100644 index b001395..0000000 Binary files a/content/posts/multichannel-led-driver/images/led_strip_alight.jpg and /dev/null differ diff --git a/content/posts/multichannel-led-driver/images/linearization_setup.jpg b/content/posts/multichannel-led-driver/images/linearization_setup.jpg deleted file mode 100644 index faafc92..0000000 Binary files a/content/posts/multichannel-led-driver/images/linearization_setup.jpg and /dev/null differ diff --git a/content/posts/multichannel-led-driver/images/olsndot_output_schematic.jpg b/content/posts/multichannel-led-driver/images/olsndot_output_schematic.jpg deleted file mode 100644 index 90941df..0000000 Binary files a/content/posts/multichannel-led-driver/images/olsndot_output_schematic.jpg and /dev/null differ diff --git a/content/posts/multichannel-led-driver/images/olsndot_pcb.png b/content/posts/multichannel-led-driver/images/olsndot_pcb.png deleted file mode 100644 index 87b10f8..0000000 Binary files a/content/posts/multichannel-led-driver/images/olsndot_pcb.png and /dev/null differ diff --git a/content/posts/multichannel-led-driver/images/olsndot_schematic.png b/content/posts/multichannel-led-driver/images/olsndot_schematic.png deleted file mode 100644 index 69906e5..0000000 Binary files a/content/posts/multichannel-led-driver/images/olsndot_schematic.png and /dev/null differ diff --git a/content/posts/multichannel-led-driver/images/overshoot_sim_r0.svg b/content/posts/multichannel-led-driver/images/overshoot_sim_r0.svg deleted file mode 100644 index 004872b..0000000 --- a/content/posts/multichannel-led-driver/images/overshoot_sim_r0.svg +++ /dev/null @@ -1,1885 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/multichannel-led-driver/images/overshoot_sim_r100.svg b/content/posts/multichannel-led-driver/images/overshoot_sim_r100.svg deleted file mode 100644 index c8efd61..0000000 --- a/content/posts/multichannel-led-driver/images/overshoot_sim_r100.svg +++ /dev/null @@ -1,1788 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/multichannel-led-driver/images/pwm_schema.jpg b/content/posts/multichannel-led-driver/images/pwm_schema.jpg deleted file mode 100644 index 0265665..0000000 Binary files a/content/posts/multichannel-led-driver/images/pwm_schema.jpg and /dev/null differ diff --git a/content/posts/multichannel-led-driver/images/uncorrected_brightness_sim.svg b/content/posts/multichannel-led-driver/images/uncorrected_brightness_sim.svg deleted file mode 100644 index 28cb4be..0000000 --- a/content/posts/multichannel-led-driver/images/uncorrected_brightness_sim.svg +++ /dev/null @@ -1,727 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/content/posts/multichannel-led-driver/index.rst b/content/posts/multichannel-led-driver/index.rst deleted file mode 100644 index 7de03d5..0000000 --- a/content/posts/multichannel-led-driver/index.rst +++ /dev/null @@ -1,456 +0,0 @@ ---- -title: "32-Channel LED tape driver" -date: 2018-05-02T11:31:14+02:00 ---- - -Theoretical basics -================== - -Together, a friend and I outfitted the small staircase at Berlin's Chaos Computer Club with nice, shiny RGB-WW LED tape -for ambient lighting. This tape is like regular RGB tape but with an additional warm white channel, which makes for much -more natural pastels and whites. There are several variants of RGBW tape. Cheap ones have separate RGB and white LEDs, -which is fine for indirect lighting but does not work for direct lighting. Since we wanted to mount our tape in channels -at the front of the steps, we had to use the slightly more expensive variant with integrated RGBW LEDs. These are LEDs -in the 5050 (5.0mm by 5.0mm) form factor common with RGB LEDs that have a small section divided off for the white -channel. The red, green and blue LED chips sit together in the larger section covered with clear epoxy and the white -channel is made up from the usual blue LED inside a yellow phosphor in the smaller section. - -Since we wanted to light up all of 15 steps, and for greatest visual effect we would have liked to be able to control -each step individually we had to find a way to control 60 channels of LED tape with a reasonable amount of hardware. - -LED tape has integrated series resistors and runs off a fixed 12V or 24V constant-voltage supply. This means you don't -need a complex constant-current driver as you'd need with high-power LEDs. You can just hook up a section of LED tape -to a beefy MOSFET to control it. Traditionally, you would do *Pulse Width Modulation* (PWM) on the MOSFET's input to -control the LED tape's brightness. - -Pulse Width Modulation ----------------------- - -`Pulse Width Modulation`_ is a technique of controlling the brightness of a load such as an LED with a digital signal. -The basic idea is that if you turn the LED on and off much too fast for anyone to notice, you can control its power by -changing how long you turn it on versus how long you leave it off. - -PWM divides each second into a large number of periods. At the beginning of each period, you turn the LED on. After -that, you wait a certain time until you turn it off. Then, you wait for the next period to begin. The periods are always -the same length but you can set when you turn off the LED. If you turn it off right away, it's off almost all the time -and it looks like it's off to your eye. If you turn it off right at the end, it's on almost all the time and it looks -super bright to your eye. Now, if you turn it off halfway into the cycle, it's on half the time and it will look to your -eye as half as bright as before. This means that you can control the LED's brightness with only a digital signal and -good timing. - -.. raw:: html - -
- A visualization of PWM at different duty cycles. -
Waveforms of two PWM cycles at different duty cycles.
-
- -PWM works great if you have a dedicated PWM output on your microcontroller. It's extremely simple in both hardware and -software. Unfortunately for us, controlling 32 channels with PWM is not that easy. Cheap microcontrollers only have `a -handful of hardware PWM outputs`_, so we'd either have to do everything in software, bit-banging our LED modulation, or -we'd have to use a dedicated chip. - -Doing PWM in software is both error-prone and slow. Since the maximum dynamic range of a PWM signal is limited by the -shortest duty cycle it can do, software PWM being slow means it has poor PWM resolution at maybe 8 bits at most. Poor -color resolution is not a problem if all you're doing is to fade around the `HSV rainbow`_, but for ambient lighting -where you *really* want to control the brightness down to a faint shimmer you need all the color resolution you can get. - -If you rule out software PWM, what remains are dedicated `hardware PWM controllers`_. Most of these have either of three -issues: - -* They're expensive -* They don't have generous PWM resolution either (12 bits if you're lucky) -* They're meant to drive small LEDs such as a 7-segment display directly and you can't just hook up a MOSFET to their - output - -This means we're stuck in a dilemma between two poor solutions if we'd want to do PWM. Luckily for us, PWM is not the -only modulation in town. - -.. _`Pulse Width Modulation`: https://en.wikipedia.org/wiki/Pulse-width_modulation -.. _`a handful of hardware PWM outputs`: https://www.nxp.com/parametricSearch#/&c=c731_c380_c173_c161_c163&page=1 -.. _`HSV rainbow`: https://en.wikipedia.org/wiki/HSL_and_HSV -.. _`hardware PWM controllers`: http://www.ti.com/lit/ds/symlink/tlc5940.pdf - -Binary Code Modulation ----------------------- - -PWM is the bread-and-butter of the maker crowd. Everyone and their cat is doing it and it works really well most of the -time. Unbeknownst to most of the maker crowd, there is however another popular modulation method that's mostly used in -professional LED systems: Enter `*Binary Code Modulation* (BCM) `_. - -BCM is to PWM sort of what barcodes are to handwriting. While PWM is easy to understand and simple to implement if all -you have is a counter and an IO pin, BCM is more complicated. On the other hand, computers can do complicated and BCM -really shines in multi-channel applications. - -Similar to PWM, BCM works by turning on and off the LED in short periods fast enough to make your eye perceive it as -partially on all the time. In PWM the channel's brightness is linearly dependent on its duty cycle, i.e. the percentage -it is turned on. In PWM the duty cycle D is the total period T divided by the on period T_on. The issue with doing PWM -on many channels at once is that you have to turn off each channel at the exact time to match its duty cycle. -Controlling many IO pins at once with precise timing is really hard to do in software. - -BCM avoids this by further dividing each period into smaller periods which we'll call *bit periods* and splitting each -channel's duty cycle into chunks the size of these bit periods. The amazingly elegant thing in BCM now is that as you -can guess from the name these bit periods are weighted in powers of two. Say the shortest bit period lasts 1 -microsecond. Then the second-shortest bit period is 2 microseconds and the third is 4, the fifth 8, the sixth 16 and so -on. - -.. raw:: html - -
- A visualization of BCM at different duty cycles. -
Waveforms of a single 4-bit BCM cycle at different duty cycles. This BCM can produce 16 different - levels.
-
- -Staggered like this, you turn on the LED for integer value of microseconds by turning it on in the bit periods -corresponding to the binary bits of that value. If I want my LED to light for 19 microseconds every period, I turn it on -in the 16 microsecond bit period, the 2 microsecond bit period and the 1 microsecond bit period and leave it off for the -4 and 8 mircosecond bit periods. - -Now, how this is better instead of just more complicated than plain old PWM might not be clear yet. But consider this: -Turning on and off a large number of channels, each at its own arbitrary time is hard because doing the timing in -software is hard. We can't use hardware timers since we only have two or three of those, and we have 32 channels. -However, we can use one hardware timer to trigger a really cheap external latch to turn on or off the 32 channels all at -once. With this setup, we can only controll all channels at once, but we can do so with very precise timing. - -All we need to do is to set our timer to the durations of the BCM bit periods, and we can get the same result as we'd -get with PWM with only one hardware timer and a bit of code that is not timing-critical anymore. - -Applications of Binary Code Modulation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -BCM is a truly wondrous technique, and outside of hobbyist circles it is in fact very widely known. Though we're using -it to control just 32 channels here, you can do much more channels without any problems. The most common application -where BCM is invariably used is *any* kind of LED screen. Controlling the thousands and thousands of LEDs in an LED -screen with PWM with a dedicated timer for each LED would not be feasible. With BCM, all you need to dedicate to a -single LED is a flipflop (or part of one if you're multiplexing). In fact, there is a whole range of `ICs with no other -purpose than to enable BCM on large LED matrices `_. Basically, these are a -high-speed shift register with latched outputs much like the venerable 74HC595_, only their outputs are constant-current -sinks made so that you can directly connect an LED to them. - -.. _74HC595: http://www.ti.com/lit/ds/symlink/sn74hc595.pdf - -Running BCM on LED tape -~~~~~~~~~~~~~~~~~~~~~~~ - -In our case, we don't need any special driver chips to control our LED tape. We just connect the outputs of a 74HC595_ -shift register to one MOSFET_ each, and then we directly connect the LED tape to these MOSFETs. The MOSFETs allow us to -drive a couple of amps into the LED tape from the weak outputs of the shift register. - -The BCM timing is done by hooking up two timer channels of our microcontroller to the shift registers *strobe* and -*reset* inputs. We set the timer to PWM mode so we can generate pulses with precise timing. At the beginning of each -bit period, a pulse will strobe the data for this bit period that we shifted in previously. At the end of the bit -period, one pulse will reset the shift register and one will strobe the freshly-reset zeros into the outputs. - -.. raw:: html - -
- From left to right, we see the STM32, one of the shift
-        registers, and the LEDs and MOSFETs. The LED tape is driven to ground by the MOSFETs, which are in turn directly
-        driven from the shift register outputs. The shift register is wired up to the STM32 with its clock and data
-        inputs on SCK and MOSI and its RESET and STROBE inputs on channel 2 and 3 of timer 1. -
- The schematic of a single output of this LED driver. Multiple shift register stages can be cascaded. -
-
- - -Our implementation of this system runs on an STM32F030F4P6_, the smallest, cheapest ARM microcontroller you can get from -ST. This microcontroller has only 16kB of flash and 1kB of RAM, but that's plenty for our use. We use its SPI controller -to feed the modulation data to the shift registers really fast, and we use two timer channels to control the shift -registers' reset and strobe. - -We can easily cascade shift registers without any ill side-effects, and even hundreds of channels should be no problem -for this setup. The only reason we chose to stick to a 32-channel board is the mechanics of it. We thought it would be -easier to have several small boards instead of having one huge board with loads of connectors and cables coming off it. - -The BOM cost per channel for our system is 3ct for a reasonable MOSFET, about 1ct for one eighth of a shift register -plus less than a cent for one resistor between shift register and MOSFET. In the end, the connectors are more expensive -than the driving circuitry. - -.. _MOSFET: https://en.wikipedia.org/wiki/MOSFET -.. _STM32F030F4P6: http://www.st.com/resource/en/datasheet/stm32f030f4.pdf - -Hardware design -=============== - -From this starting point, we made a very prototype-y hardware design for a 32-channel 12V LED tape driver. The design is -based on the STM32F030F4P6_ driving the shift registers as explained above. The system is controlled through an RS485_ -bus that is connected up to the microcontroller's UART using an MAX485_-compatible RS485 transceiver. The LED tape is -connected using 9-pin SUB-D_ connectors since they are cheap and good enough for the small current of our short segments -of LED tape. The MOSFETs we use are small SOT-23_ logic-level MOSFETs. In various prototypes we used both International -Rectifier's IRLML6244_ as well as Alpha & Omega Semiconductor's AO3400_. Both are good up to about 30V/5A. Since we're -only driving about 2m of LED tape per channel we're not going above about 0.5A and the MOSFETs don't even get warm. - -.. _RS485: https://en.wikipedia.org/wiki/RS-485 -.. _MAX485: https://datasheets.maximintegrated.com/en/ds/MAX1487-MAX491.pdf -.. _IRLML6244: https://www.infineon.com/dgdl/?fileId=5546d462533600a4015356686fed261f -.. _AO3400: http://aosmd.com/pdfs/datasheet/AO3400.pdf -.. _SUB-D: https://en.wikipedia.org/wiki/D-subminiature -.. _SOT-23: http://www.nxp.com/documents/outline_drawing/SOT23.pdf - -Switching nonlinearities ------------------------- -During testing of our initial prototype, we noticed that the brightness seemed to jump around when fading to very low -values. It turned out that our extremely simple LED driving circuit consisting of only the shift register directly -driving a MOSFET, which in turn directly drives the LED tape was maybe a little bit too simple. After some measurements -it turned out that we were looking at about 6Vpp of ringing on the driver's output voltage. The picture below is the -voltrage we saw on our oscilloscope on the LED tape. - -.. raw:: html - -
- Strong ringing on the LED voltage waveform edge at about
-            100% overshoot during about 70% of the cycle time. -
Bad ringing on the LED output voltage caused by wiring inductance. Note that the effect on the - actual LED current is less bad than this looks since the LED's V/I curve is nonlinear.
-
- - -Dynamic switching behavior: Cause and Effect -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A bit of LTSpice_ action later we found that the inductance of the few metres of cable leading to the LED tape is the -likely culprit. The figure below is the schematic used for the simulations. - -.. raw:: html - -
- The LTSpice schematic of one output of the driver,
-        taking into account the shift register's output ESR and the wiring ESL. -
The schematic of the simulation in LTSpice
-
- -As tested, the driver does not include any per-output smoothing so the ~.5A transient on each BCM cycle hits the cable -in full. Combined with the cable inductance, this works out to a considerable lag of the rising edge of the LED -current, and bad ringing on its falling edge. Below is the voltage on the LED output from an LTSpice simulation of our -driver. - -.. raw:: html - -
- The result of the LTSpice simulation of our driver output. The LED
-        current shows similar ringing to what we measured using the oscilloscope. Interestingly, the gate voltage shows
-        strong ringing, too. -
The result of our LTSpice simulation. This simulation assumes 1µH of wiring inductance and 50Ω of - output impedance on the part of the shift register. The ringing at the gate visible in the gate voltage graph is - due to feed-through of the ringing at the output through the MOSFET's parasitic Cgd.
-
- -We were able to reduce the rining and limit the effect somewhat by putting a 220Ω series resistor in between the shift -register output and the MOSFET gate. This resistor forms an RC circuit with the MOSFET's nanofarad or two of gate -capacitance. The result of this is that the LED current passing the wire's ESL rises slightly more slowly and thus the -series inductance gets excited slightly less, and the overshoot decreases. Below is a picture of the waveform with the -damping resistor in place and a picture of our measurement for comparison. The resistor values don't agree perfectly -since the estimated ESL and stray capacitance of the wiring is probably way off. - -.. raw:: html - -
- Weak ringing on the LED voltage waveform edge at about 30%
-        overshoot during about 20% of the cycle time. -
Adding a resistor in front of the MOSFET gate to slow the transition damped the ringing somewhat, - but ultimately it cannot be eliminated entirely. Note how you can actually see the miller plateau on the - trailing edge of this signal. -
-
- -.. raw:: html - -
- The result of the LTSpice simulation of our driver output with an
-        extra 100 Ohms between shift register output and MOSFET gate. Similar to the oscilloscope measurement the
-        ringing is much reduced in its amplitude. -
The LTSpice simulation result with the same parameters as above but with an extra 100Ω between the - shfit register's output and the MOSFET's gate.
-
- -A side effect of this fix is that now the effective on-time of the LED tape is much longer than the duty cycle at the -shift register's output at very small duty cycles (1µs or less). This is caused by the MOSFET's `miller -plateau`_. For illustration, below is a graph of both the excitation waveform (the boxy line) and the resulting LED -current (the other ones) both without damping (top) and with 220Ω damping (bottom). As you can see the effective duty -cycle of the LED current is not at all equal to the 50% duty cycle of the excitation square wave. - -.. raw:: html - -
- The result of an LTSpice simulation of the LED duty cycle without and
-        with damping. Dampening widens the LED current waveform from 50% duty cycle with sharp edges to about 80% duty
-        cycle with soft edges. -
Simulated LED duty cycle with and without damping. The damping resistance used in this simulation - was 220Ω.
-
- -.. raw:: html - -
- The gate voltages in the spice simulation above. The undamped
-        response shows sharp edges with the miller plateau being a barely noticeable step, but with strong ringing on
-        the trailing edge. The damped response shows RC-like slow-edges, but has wide miller plateaus on both edges
-        adding up to about 50% of the pulse width. -
The MOSFET gate voltage from the simulation in the figure above. You can clearly see how the miller - plateau (the horizontal part of the trace at about 1V) is getting much wider with added damped, and how the - resulting gate charge/discharge curve is not at all that of a capacitor anymore.
-
- - - -In conclusion, we have three major causes for our calculated LED brightness not matching reality: - -* Ringing of the equivalent series inductance of the wiring leading up to the LED tape -* Miller plateau lag -* The damping resistor and the MOSFET gate forming an RC filter that helps with wire ESL ringing but worsens the miller - plateau issue and deforms the LED current edges. - -Added up, these three effects yield a picture that agrees well with our simulations and measurements. The overall effect -is neglegible at long period durations (>10µs), but gets really bad at short period durations (<1µs). The effect is -non-linear, so correcting for it is not as simple as adding an offset. - -.. _LTSpice: http://www.analog.com/en/design-center/design-tools-and-calculators/ltspice-simulator.html -.. _`miller plateau`: https://www.vishay.com/docs/68214/turnonprocess.pdf - -Measuring LED tape brightness -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In order to correct for the nonlinearities mentioned above, we decided to implement a lookup table mapping BCM period to -actual timer setting. That is, each row of the table contains the actual period length we need to set the -microcontroller's timer to in order to get our intended brightness steps. - -To calibrate our driver, we needed a setup for reproducible measurement of the relative brightness of our LED tape at -different settings. Absolute brightness is not of interest to us as the eye can't perceive it. To perform the -calibration, the LED driver is set to enable each single BCM period in turn, i.e. brightness values 1, 2, 4, 8, 16 etc. - -The setup we used to measure the LED tape's brightness consists of a bunch of LED tape stuck into a tin can for -shielding against both stray light and electromagnetic interference and a photodiode looking at the LED tape. We used -the venerable BPW34_ photodiode in our setup as I had a bunch leftover from another project and because they are quite -sensitive owing to their physically large die area. - -.. raw:: html - -
- The led measurement setup consists of several PCBs and a
-        breadboard linked with a bunch of wires and a big tin can to shield the LEDs and the photodiode. A large sub-D
-        connector is put into the top of the tin can as a feed-through for the LED tape's control signals and the
-        photodiode signal. In the background the control laptop is visible. -
The LED brighness measurement setup. The big tin can contains a bunch of LED tape and the - photodiode. The breadboard on the right is used for the photodiode preamplifier and for jumpering around the LED - tape's channels. The red board next to it is the buspirate used as ADC. The board on the bottom left is a - TTL-to-RS485 converter and the board in the middle is the unit under test.
-
- -The photodiode's photocurrent is converted into a voltage using a very simple transimpedance amplifier based around a -MCP6002_ opamp that was damped into oblivion with a couple nanofarads of capacitance in its feedback loop. The MCP6002_ -is a fine choice here since I had a bunch and because it is a CMOS opamp, meaning it has low bias current that would -mess up our measurements. For many applications, opamp bias current is not a big issue but when using the opamp to -directly measure very small currents at its input it quickly swamps out the signal for most BJT-input types. - -The transimpedance amplifier's output is read from the computer using the ADC input of a buspirate USB thinggamajob. In -general I would not recommend the buspirate as a tool for this job since it's ADC is not particularly good and it's -programming interface is positively atrocious, but it was what I had and it beat first wiring up one of the dedicated -ADC chips I had in my parts bin. - -The computer runs a small python script cycling the LED tape through all its BCM period settings and taking a brightness -measurement at each step. Later on, these measurements can be plotted to visualize the resulting slope's linearity, and -we can even do a simulation of the resulting brightness for all possible control values by just adding the measured -photocurrents for a certain BCM setpoint just as our retinas would do. - -.. raw:: html - -
- -
- A plot of the measured brightness of our LED tape for each BCM period. The brightness values are normalized - to the value measured at the LSB setpoint (brightness=1/65535). Ideally, this plot would show a straight - line with slope 1. Obviously, it doesn't. The bend in the curve is caused by the above-mentioned duty cycle - offset adding an offset to all brightness values. Shown is both the raw data (light), which has essentially zero - measurement error and a linear fit (dark). - - The plot is in log-log to approximate how the human eye would perceive brightness, i.e. highly sensitive at - low values but not very sensitive at all at large values. -
-
- -While it would be possible to fully automate the optimization of BCM driver lookup tables, we needed only one and in the -end I just sat down and manually tweaked the ideal values we initially calculated until I liked the result. You can see -the resulting brightness curve below. - -.. raw:: html - -
-
- -
- Calculated brightness curve for the uncorrected BCM setup. As you can see, at low setpoints the result - is about as smooth as sandpaper, which is well in line with our observations. At high setpoints the - offset gets swamped out and the nonlinearity in the low bits is not visible anymore. -
-
- -
- Brightness curve for the corrected BCM setup extrapolated using actual measurements. Looks as buttery - smooth in real life as it does in this plot. -
- -
-
- -.. _BPW34: http://www.vishay.com/docs/81521/bpw34.pdf -.. _MCP6002: http://ww1.microchip.com/downloads/en/DeviceDoc/21733j.pdf - -Controlling the driver ----------------------- - -Now that our driver was behaving linear enough that you couldn't see it actually wasn't we needed a nice way to control -it from a computer of our choice. In the ultimate application (our staircase) we'll use a raspberry pi for this. Since -we already settled on an RS485_ bus for its robustness and simplicity, we had to device a protocol to control the driver -over this bus. Here, we settled on a simple, COBS_-based protocol for the reasons I wrote about in `How to talk to your -microcontroller over serial `_. - -To address our driver nodes, we modified the Makefile to build a random 32-bit MAC into each firmware image. The -protocol has only five message types: - -1. A 0-byte *ping* packet, to which each node would reply with its own address in the - first 100ms after boot. This can be used to initially discover the addresses of all nodes connected to the bus. You'd - spam the bus with *ping* packets, and then hit reset on each node in turn. The control computer would then receive - each device's MAC address as you hit reset. -2. A 4-byte *address* packet that says which device that the following packet is for. This way of us using the packet - length instead of a packet type field is not particularly elegant, but our system is simple enough and it was easy to - implement. -3. A 64-byte *frame buffer* packet that contains 16 bits of left-aligned brightness data for every channel -4. A one-byte *get status* packet that tells the device to respond with... -5. ...a 27-byte status packet containing a brief description of the firmware (version number, channel count, bit depth - etc.) as well as the device's current life stats (VCC, temperature, uptime, UART frame errors etc.). - -Wrapped up in a nice python interface we can now easily enumerate any drivers we connect to a bus, query their status -and control their outputs. - -.. _COBS: https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing - -Conclusion ----------- - -.. raw:: html - -
-
- - A picture of the LED driver schematic - -
The LED driver schematic
-
- - A picture of the LED driver PCB layout - -
The LED driver PCB layout
-
-
- -Putting some thought into the control circuitry and software, you can easily control large numbers of channels of LEDs -using extremely inexpensive driving hardware without any compromises on dynamic range. The design we settled on can -drive 32 channels of LED tape with a dynamic range of 14bit at a BOM cost of below 10€. All it really takes is a couple -of shift registers and a mildly bored STM32 microcontroller. - -Get a PDF file of the schematic and PCB layout `here `__ or download the CAD files -and the firmware sources `from github `_. You can view the Jupyter notebook used to -analyze the brightness measurement data `here `__. - diff --git a/content/posts/multichannel-led-driver/olsndot_v02_schematics_and_pcb.pdf b/content/posts/multichannel-led-driver/olsndot_v02_schematics_and_pcb.pdf deleted file mode 100644 index 2a4e037..0000000 Binary files a/content/posts/multichannel-led-driver/olsndot_v02_schematics_and_pcb.pdf and /dev/null differ diff --git a/content/posts/private-contact-discovery/index.rst b/content/posts/private-contact-discovery/index.rst deleted file mode 100644 index 797de50..0000000 --- a/content/posts/private-contact-discovery/index.rst +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: "Private Contact Discovery" -date: 2019-06-22T10:30:00+08:00 ---- - -Private Contact Discovery -========================= - -Private Contact Discovery (PCD) is the formal name for the problem modern smartphone messenger applications have on -installation: Given a user's address book, find out which of their contacts also use the same messenger without the -messenger's servers learning anything about the user's address book. The widespread non-private way to do this is to -simply upload the user's address book to the app's operator's servers and do an SQL JOIN keyed on the phone number field -against the database of registered users. People have tried sprinkling some hashes over these phone numbers in an -attempt to improve privacy, but obviously running a brute-force preimage attack given a domain of maybe a few billion -valid inputs is not cryptographically hard. - -Private Contact Discovery can be phrased in terms of Private Set Intersection (PSI), the cryptographic problem of having -two parties holding one set each find the intersection of their sets without disclosing any other information. PSI has -been an active field of research for a while and already yielded useful results for some use cases. Alas, none of those -results were truly practical yet for usage in PCD in a typical messenger application. They would require too much CPU -time or too much data to be transferred. - -At USENIX Security 2019, Researchers from technical universities Graz and Darmstadt published a paper titled *Private -Contact Discovery at Scale* -(`eprint `__ | `PDF `__). -In this paper, they basically optimize the hell out of existing cryptographic solutions to private contact discovery, -jumping from a still-impractical state of the art right to practicality. Their scheme allows a client with 1k contacts -to run PCD against a server with 1B contacts in about 3s on a phone. The main disadvantage of their scheme is that it -requires the client to in advance download a compressed database of all users, that clocks in at about 1GB for 1B users. - -I found this paper very interesting for its immediate practical applicability. As an excuse to dig into the topic some -more, I gave a short presentation at my university lab's research seminar on this paper -(slides: `PDF `__ | `ODP `__). - -Even if you're not working on secure communication systems on a day-to-day basis this paper might interest you. If -you're working with social account information of any kind I can highly recommend giving it a look. Not only might your -users benefit from improved privacy, but your company might be able to avoid a bunch of data protection and -accountability issues by simply not producing as much sensitive data in the first place. diff --git a/content/posts/private-contact-discovery/mori_semi_psi_talk.odp b/content/posts/private-contact-discovery/mori_semi_psi_talk.odp deleted file mode 100644 index e7df32e..0000000 Binary files a/content/posts/private-contact-discovery/mori_semi_psi_talk.odp and /dev/null differ diff --git a/content/posts/private-contact-discovery/mori_semi_psi_talk.pdf b/content/posts/private-contact-discovery/mori_semi_psi_talk.pdf deleted file mode 100644 index e06fd63..0000000 Binary files a/content/posts/private-contact-discovery/mori_semi_psi_talk.pdf and /dev/null differ diff --git a/content/posts/serial-protocols/index.rst b/content/posts/serial-protocols/index.rst deleted file mode 100644 index 2f9bb2d..0000000 --- a/content/posts/serial-protocols/index.rst +++ /dev/null @@ -1,249 +0,0 @@ ---- -title: "How to talk to your microcontroller over serial" -date: 2018-05-19T08:09:46+02:00 ---- - -Scroll to the end for the `TL;DR `_. - -In this article I will give an overview on the protocols spoken on serial ports, highlighting common pitfalls. I will -summarize some points on how to design a serial protocol that is simple to implement and works reliably even under error -conditions. - -If you have done low-level microcontroller firmware you will regularly have had to stuff some data up a serial port to -another microcontroller or to a computer. In the age of USB, an old-school serial port is still the simplest and -quickest way to get communication to a control computer up and running. Integrating a ten thousand-line USB stack into -your firmware and writing the necessary low-level drivers on the host side might take days. Poking a few registers to -set up your UART to talk to an external hardware USB to serial converter is a matter of minutes. - -This simplicity is treacherous, though. Oftentimes, you start writing your serial protocol as needs arise. Things might -start harmless with something like ``SET_LED ON\n``, but as the code grows it is easy to end up in a hot mess of command -modes, protocol states that breaks under stress. The ways in which serial protocols break are manifold. The simplest one -is that at some point a character is mangled, leading to both ends of the conversation ending up in misaligned protocol -states. With a fragile protocol, you might end up in a state that is hard to recover from. In extreme cases, this leads -to code such as `this gem`_ performing some sort of arcane ritual to get back to some known state, and all just because -someone did not do their homework. Below we'll embark on a journey through the lands of protocol design, exploring the -facets of this deceptively simple problem. - -.. _`this gem`: https://github.com/juhasch/pyBusPirateLite/blob/dece35f6e421d4f6a007d1db98d148e2f2126ebb/pyBusPirateLite/base.py#L113 - -Text-based serial protocols -=========================== - -The first serial protocol you've likely written is a human-readable, text-based one. Text-based protocols have the big -advantage that you can just print them on a terminal and you can immediately see what's happening. In most cases you can -even type out the protocol with your bare hands, meaning that you don't really need a debugging tool beyond a serial -console. - -However, text-based protocols also have a number of disadvantages. Depending on your application, these might not matter -and in many cases a text-based protocol is the most sensible solution. But then, in some cases they might and it's good -to know when you hit one of them. - -Problems --------- - -Low information density -~~~~~~~~~~~~~~~~~~~~~~~ - -Generally, you won't be able to stuff much more than four or five bit of information down a serial port using a -single byte of a human-readable protocol. In many cases you will get much less. If you have 10 commands that are only -issued a couple times a second nobody cares that you spend maybe ten bytes per command on nice, verbose strings such as -``SET LED``. But if you're trying to squeeze a half-kilobyte framebuffer down the line you might start to notice the -difference between hex and base-64 encoding, and a binary protocol might really be more up to the job. - -Complex parsing code -~~~~~~~~~~~~~~~~~~~~ - -On the computer side of thing, with the whole phalanx of an operating system, the standard library of your programming -language of choice and for all intents and purposes unlimted CPU and memory resources to spare you can easily parse -anything spoken on a serial port in real time, even at a blazing fast full Megabaud. The microcontroller side however is -an entirely different beast. On a small microcontroller, printf_ alone will eat about half your flash. On most small -microcontrollers, you just won't get a regex library even though it would make parsing textual commands *so much -simpler*. Lacking these resources, you might end up hand-knitting a lot of low-level C code to do something seemingly -simple such as parsing ``set_channel (13, 1.1333)\n``. These issues have to be taken into account in the protocol design -from the beginning. For example, you don't really need matching parentheses, don't use them. - -Fragile protocol state -~~~~~~~~~~~~~~~~~~~~~~ - -Say you have a ``SET_DISPLAY`` command. Now say your display can display four lines of text. The obvious approach to this -is probably the SMTP_ or HTTP_ way of sending ``SET_DISPLAY\nThis is line 1\nThis is line 2\n\n``. This would certainly -work, but it is very fragile. With this protocol, you're in trouble if at any point the terminating second newline -character gets mangled (say, someone unplugs the cable, or the control computer reboots, or a cosmic ray hits something -and ``0x10 '\n'`` turns into ``0x50 'P'``). - -.. _SMTP: https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol -.. _HTTP: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol - -Timeouts don't work -~~~~~~~~~~~~~~~~~~~ - -You might try to solve the problem of your protocol state machine tangling up with a timeout. "If I don't get a valid -command for more than 200ms I go back to default state." But consider the above example. Say, your control computer -sends a ``SET_DISPLAY`` command every 100ms. If in one of them the state machine tangles up, the parser hangs since the -timeout is never hit, because a new line of text is arriving every 100ms. - -Framing is hard -~~~~~~~~~~~~~~~ - -You might also try to drop the second newline and using a convention such as ``SET_DISPLAY`` is followed by two lines of -text, then commands resume.". This works as long as your display contents never look like commands. If you are only ever -displaying the same three messages on a character LCD that might work, but if you're displaying binary framebuffer -data you've lost. - -Solutions ---------- - -Keep the state machine simple -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In a text-based protocol, always use a single line of text to represent a single command. Don't do protocol states or -modes where you can toggle between different interpretations for a line. If you have to send human-readable text as part -of a command (such as ``SET_DISPLAY``), escape it so it doesn't contain any newlines. - -This way, you keep your protocol state machine simple. If at any time your serial trips and flips a bit or looses a byte -your protocol will recover on the next newline character, returning to its base state. - -Encode numbers in hex when possible -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Printing a number in hexadecimal is a very tidy operation, even on the smalest 8-bit microcontrollers. In contrast, -printing decimal requires both division and remainder in a loop which might get annoyingly code- and time-intensive on -large numbers (say a 32-bit int) and small microcontrollers. - -If you have to send fractional values, consider their precision. Instead of sending a 12 bit ADC result as a 32-bit -float formatted like ``0.176513671875`` sending ``0x2d3`` and dividing by 4096 on the host might be more sensible. If you -really have to communicate big floats and you can't take the overhead of including both printf_ and scanf_ you can -use hexadecimal floating point, which is basically ``hex((int)foo) + "." + hex((int)(65536*(foo - (int)foo)))`` for four -digits. You can also just hex-encode the binary IEEE-754_ representation of the float, sending ``hex(*(int *)&float)``. -Most programming languages will have a `simple, built-in means to parse this sort of thing -`__. - -.. _printf: http://git.musl-libc.org/cgit/musl/tree/src/stdio/vfprintf.c -.. _scanf: http://git.musl-libc.org/cgit/musl/tree/src/stdio/vfscanf.c -.. _IEEE-754: https://en.wikipedia.org/wiki/IEEE_754 - -Escape multiline strings -~~~~~~~~~~~~~~~~~~~~~~~~ - -If you have to send arbitrary strings, escape special characters. This not only has the advantage of yielding a robust -protocol: It also ensures you can actually see everything that's going on when debugging. The string ``"\r\n"`` is easy to -distinguish from ``"\n"`` while your terminal emulator might not care. - -The simplest encoding to use is the C-style backslash encoding. Host-side, most languages will have a `built-in means of -escaping a string like that `__. - -Encoding binary data --------------------- - -For binary data, hex and base-64 are the most common encodings. Since hex is simpler to implement I'd go with it unless -I really need the 30% bandwidth improvement base-64 brings. - -Binary serial protocols -======================= - -In contrast to anything human-readable, binary protocols are generally more bandwidth-efficient and are easier to format -and parse. However, binary protocols come with their own version of the caveats we discussed for text-based protocols. - -The framing problem in binary protocols ---------------------------------------- - -The most basic problems with binary protocols as with text-based ones is framing, i.e. splitting up the continuous -serial data stream into discrete packets. The issue is that it is that you have to somehow mark boundaries between -frames. The simplest way would be to use some special character to delimit frames, but then any 8-bit character you -could choose could also occur within a frame. - -SLIP/PPP-like special character framing -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Some protocols solve this problem much like we have solved it above for strings in line-based protocols, by escaping any -occurence of the special delimiter character within frames. That is, if you want to use ``0x00`` as a delimiter, you would -encode a packet containing ``0xde 0xad 0x00 0xbe 0xef`` as something like ``0xde 0xad 0x01 0x02 0xbe 0xef``, replacing the -null byte with a magic sequence. This framing works, but is has one critical disadvantage: The length of the resulting -escaped data is dependent on the raw data, and in the worst case twice as long. In a raw packet consisting entirely of -null bytes, every byte must be escaped with two escape bytes. This means that in this case the packet length doubles, -and in this particular case we're even less efficient than base-64. - -Highly variable packet length is also bad since it makes it very hard to make any timing guarantees for our protocol. - -9-bit framing -~~~~~~~~~~~~~ - -A framing mode sometimes used is to configure the UARTs to transmit 9-bit characters and to use the 9th bit to designate -control characters. This works really well, and gives plenty of control characters to work with. The main problem with -this is that a 9-bit serial interface is highly nonstandard and you need UARTs on both ends that actually support this -mode. Another issue is that though more efficient than both delmitier-based and purely text-based protocols, it still -incurs an extra about 10% of bandwidth overhead. This is not a lot if all you're sending is a little command every now -and then, but if you're trying to push large amounts of data through your serial it's still bad. - -COBS -~~~~ - -Given the limitations of the two above-mentioned framing formats, we really want something better. The `Serial Line -Internet Protocol (SLIP)`_ as well as the `Point to Point Protocol (PPP)`_, standardized in 1988 and 1994 respectively, -both use escape sequences. This might come as a surprise, but humanity has actually still made significant technological -progress on protocols for 8-bit serial interfaces until the turn of the millennium. In 1999, `Consistent Overhead Byte -Stuffing (COBS)`_ (`wiki `__) was published by a few -researchers from Apple Computer and Stanford University. As a reaction on the bandwidth doubling problem present in -PPP_, COBS *always* has an overhead of a single byte, no matter what or how long a packet's content is. - -COBS uses the null byte as a delimiter interleaves all the raw packet data and a `run-length encoding`_ of the non-zero -portions of the raw packet. That is, it prepends the number of bytes until the first zero byte to the packet, plus one. -Then it takes all the leading non-zero bytes of the packet, unmodified. Then, it again encodes the distance from the -first zero to the second zero, plus one. And then it takes the second non-zero run of bytes unmodified. And so on. At -the end, the packet is terminated with a zero byte. - -The result of this scheme is that the encoded packet does not contain any zero bytes, as every zero byte has been -replaced with the number of bytes until the next zero byte, plus one, and that can't be zero. Both formatter and parser -each have to keep a counter running to keep track of the distances between zero bytes. The first byte of the packet -initializes that counter and is dropped by the parser. After that, every encoded byte received results in one raw byte -parsed. - -While this might sound more complicated than the escaping explained above, the gains in predictability and efficiency -are worth it. An implementation of encoder and decoder should each be about ten lines of C or two lines of Python. A -minor asymmetry of the protocol is that while decoding can be done in-place, encoding either needs two passes or you -need to scan forward for the next null byte. - -.. _`Point to Point Protocol (PPP)`: https://en.wikipedia.org/wiki/Point-to-Point_Protocol -.. _PPP: https://en.wikipedia.org/wiki/Point-to-Point_Protocol -.. _`Serial Line Internet Protocol (SLIP)`: https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol -.. _`Consistent Overhead Byte Stuffing (COBS)`: http://www.stuartcheshire.org/papers/COBSforToN.pdf -.. _`Point-to-Point Protocol (PPP)`: https://en.wikipedia.org/wiki/Point-to-Point_Protocol -.. _`run-length encoding`: https://en.wikipedia.org/wiki/Run-length_encoding - -State machines and error recovery ---------------------------------- - -In binary protocols even more than in textual ones it is tempting to build complex state machines triggering actions on -a sequence of protocol packets. Please resist that temptation. As with textual protocols keeping the protocol state to -the minimum possible allows for a self-synchronizing protocol. A serial protocol should be designed such that if due to -a dropped packet or two both ends will naturally re-synchronize within another packet or two. A simple way of doing that -is to always transmit one semantic command per packet and to design these commands in the most idempotent_ way possible. -For example, when filling a framebuffer piece by piece, include the offset in each piece instead of keeping track of it -on the receiving side. - -.. _idempotent: https://en.wikipedia.org/wiki/Idempotence#Computer_science_meaning - -Conclusion -========== - -Here's your five-step guide to serial bliss: - -1. Unless you have super-special requirements, always use the slowest you can get away with from 9600Bd, 115200Bd or - 1MBd. 8N1 framing if you're talking to anything but another microcontroller on the same board. Using common values - like these makes it easier when you'll inevitably have to guess these at some point in the future ;) -2. If you're doing something simple and speed is not a particular concern, use a human-readable text-based protocol. Use - one command/reply per line, begin each line with some sort of command word and format numbers in hexadecimal. Bonus - points for the device replying to unknown commands with a human-readable status message and printing a brief protocol - overview on boot. -3. If you're doing something even slightly nontrivial or need moderate throughput (>1k commands per second or >20 byte of - data per command) use a COBS-based protocol. A good starting point is a ``[target MAC][command ID][command - arguments]`` packet format for multidrop busses. For single-drop you may decide to drop the MAC address. -4. Always include some sort of "status" command that prints life stats such as VCC, temperature, serial framing errors - and uptime. You'll need some sort of ping command anyway and that command might as well do something useful. -5. If at all possible, keep your protocol context-free across packets/lines. That is, a certain command should always be - self-contained, and no command should change the meaning of the next packet/line/command that is sent. This is really - important to allow for self-synchronization. If you really need to break up something into multiple commands, say you - want to set a large framebuffer in pieces, do it in a idempotent_ way: Instead of sending something like ``FRAMEBUFFER - INCOMING:\n[byte 0-16]\n[byte 17-32]\n[...]\nEND OF FRAME`` rather send ``FRAMEBUFFER DATA FOR OFFSET 0: [byte - 0-16]\nFRAMEBUFFER DATA FOR OFFSET 17: [byte 17-32]\n[...]\nSWAP BUFFERS\n``. - diff --git a/content/posts/sybil-resistance-identity/images/succulents.jpg b/content/posts/sybil-resistance-identity/images/succulents.jpg deleted file mode 100755 index 938bffd..0000000 Binary files a/content/posts/sybil-resistance-identity/images/succulents.jpg and /dev/null differ diff --git a/content/posts/sybil-resistance-identity/index-old.rst b/content/posts/sybil-resistance-identity/index-old.rst deleted file mode 100644 index 6f1bee3..0000000 --- a/content/posts/sybil-resistance-identity/index-old.rst +++ /dev/null @@ -1,244 +0,0 @@ ---- -title: "Theia Attack Resistance and Digital Identity" -date: 2020-09-09T15:00:00+02:00 ---- - -.. raw:: html - -
- -
Photo by Tim Bennett on Unsplash
-
- - -Theia in Cyberspace -=================== - -In informatics, the term *distributed system* is used to describe the aggregate behavior of a complex network made up of -individual computers. For decades, computer scientists to some success have been trying to figure out how exactly the -individual computers that make up such a distributed system need to be programmed for the resulting amalgamation to -behave in a predictable, maybe even a desirable way. Though seemingly simple on its surface, this problem has a -surprising depth to it that has yielded research questions for a whole field for several decades now. One particular -as-of-yet unsolved problem is resistance against *theia attacks* (or "sybil" attacks in older terminology). - - Named after the 1973 book by Flora Rheta Schreiber on dissociative identity disorder, a sybil attack is an - attack where one computer in a distributed system pretends to be multiple computers to gain an advantage. From your - author's standpoint, naming a type of computer security attack after a medical condition was an unfortunate choice. - For this reason this post uses the term *Theia attack* to refer to the same concept. Theia is a greek godess of light - and glitter and the name alludes to the attacker performing something alike an optical illusion, causing the attacked - to perceive multiple distinct images that in the end are all only reflections of the same attacker. - -The core insight of computer science research on theia attacks is that there cannot be any technological way of -preventing such an attack, and any practical countermeasure must be grounded in some authority or ground truth that is -external to the systems—bridging from technology to its social or political context. - -Looking around, we can see a parallel between this question ("which computer is a real computer?") and a social issue -that recently has been growing in importance: Just like computers can pretend to be other computers, they can also -pretend to be humans. As can humans. Be it within the context of election manipulation or down-to-earth astroturfing_ -the recurring issue is that in today's online communities, it is hard for an individual to tell who of their online -acquaintances are who they seem to be. Different platforms attempt different solutions to this problem, and all fail in -some way or another. Facebook employs good old snitching, turning people against each other and asking them "Do you know -this person?". Twitter is more laid-back and avoids this Stasi_ methodology in favor of requiring a working mobile phone -number from its subjects, essentially short-circuiting identity verification to the phone company's check of their -subscriber's national passport. - -.. the preceding is a simplified representation of these platform's practices. In particular facebook uses several - methods depending on the case. I think this abbreviated discussion should be ok for the sake of the argument. I am - not 100% certain on the accuracy on the accuracy of the statement though. Does fb still do the snitching thing? Is - twitter usually content with a phone number? - -Trusting Crypto-Anarchist Authorities -===================================== - -Beyond these centralistic solutions to the problem, crypto-anarchists and anarcho-capitalists have been brewing on some -interesting novel approaches to online identity based on *blockchain* distributed ledger technology. Distributed -ledgers are a distributed systems design pattern that yields a system that works like an append-only logbook. -Participants can create new entries in this logbook, but no one—neither the original author, nor other participants—can -retroactively change a logbook entry once it has been written. In the blockchain model, past entries are essentially -written into stone. This near-perfect immutability is what opens them for a number of use cases from cryptographic -pseudo-currencies [#cryptocurrency]_. - -An overview over a variety of these unconventional blockchain identity verification approaches can be found in `this -unpublished 2020 survey by Siddarth, Ivliev, Siri and Berman `_. -They walk their readers through a number of different projects that try to solve the question "Is this human who they -pretend to be?" using joint socio-technological approaches. In the following few sections, you may find a short outline -of a small selection of them. The conlusion of this post will be a commentary on these approaches, and on the underlying -problem of identity in a digital world. - -.. BrightID - -In one scheme, identity is determined by "notary" computers that aggregate large amounts of information on a user's -social contacts. These computers then run an algorithm derived from the SybilGuard_, SybilLimit_ and SybilInfer_ lineage -of random-walk based algorithms. These algorithms assume that authentic social graphs are small world graphs: Everyone -knows everyone else through a friend's friend's friend. They also assume that there is an upper bound on how many -connections with authentic users an attacker can forge: Anyone who is not embedded into the graph well enough is cut -out. Like this, they put an upper limit on the number of theia identites an attacker can assume given a certian number -of connections to real people. - -Disregarding the catastrophic privacy issues of storing large amounts of data on social relationships on someone else's -computer, this second assumption is where this model unfortunately breaks down. Applying common sense, it is completely -realistic for an attacker to forge a large number of social connections: This is precisely what most of social media -marketing is about! A more malicious angle on this would be to consider how in meatspace [#meatspacefn]_ multi-level -marketing schemes are successful in coaxing people to abuse their social graphs to disastrous consequences to the -well-being of themselves and others. Similar schemes would certainly be possible in cyberspace as well. An additional -point to consider is that the upper limit SybilGuard_ and others place on the number of fake identities one can have is -simply not that strict at all. An attacker could still get away with a reasonable number of false identities before -getting caught by any such algorithm. - -.. Duniter - -In another scheme, identity is awarded to anyone who can convince several people already in the network to vouch for -them, and who is at most a few degrees removed from one of several pre-determined celebrities. Apart from again being -vulnerable to conmen and other scammers, this system has the glaring flaw of roundly refusing to recognize any person -who is not willing or able to engage with multiple of its members. Along with the system's informal requirement for -members to only vouch for people they have physically met this leads to a nonstarter in a cyberspace that grown -specifically *because* it transcends national borders and physical distance—two most serious obstacles to in-person -communication. - -.. Idena Network - -The last scheme I will outline in this post is based around a set of `Turing tests`_; that is, quizzes that are designed -to tell apart man and machine. In this system, all participants have to simultaneously undergo a Turing test once in a -fortnight. The idea is that this limits the number of theia identities an attacker can assume since they can only solve -that many Turing tests at the same time. The system uses a particular type of picture classification-based Turing test -and does not seem to be designed with the blind or mentally disabled in mind with accessibility concerns nowhere to be -found in the so-called "manifesto" published by its creators. But even ignoring that, the system obviously fails at an -even more basic level: The idea that everyone takes a Turing test at the same time only works in a world without time -zones. Or jobs for that matter. Also, it assumes that an attacker cannot simply hire a small army of people someplace -else to fool the system. - -.. _SybilLimit: https://www.comp.nus.edu.sg/~yuhf/yuh-sybillimit.pdf -.. _SybilGuard: http://www.math.cmu.edu/~adf/research/SybilGuard.pdf -.. _SybilInfer: https://www.princeton.edu/~pmittal/publications/sybilinfer-ndss09.pdf -.. _`Turing Tests`: https://en.wikipedia.org/wiki/Turing_test - -Identity between Cyberspace and Meatspace -========================================= - -A common thread in these solutions, from the Facebook'esque Stasi_ methods to the crypto-anarchist challenge-response -utopias, is that they all approach digital identity as a question of Objective Truth™ that can unanimously be decided at -a system level—or that can be externalized to the next larger system such as the state. Alas, the important question -remains unasked: - - What *is* identity? - -The answer to this question certainly depends on the system being examined. For example, an important reason the -capitalist corporations mentioned above require knowledge about their users' identity is to generate plausible -statistics for the advertisers that form their customer base, similar to how a farmer will keep statics on yield and -quality for the buyers of his crop. With this background, a full decoupling of platform accounts from a notion of legal -identity seems at odds with the platform's business model—and we will have to adjust our expectations for reform -accordingly. - -A common thread among all systems mentioned above is that they all have a social component to them. For this common use -case of social systems, I want to make a suggestion on how we can approach digital identity in a more practical, less -discriminatory [#discriminatory]_ manner than any of the methods we discussed above. I think both using people's social -connections and proxying the decisions of external authorities such as the state are bad systems to decide who is a -person and who is not. I will now illustrate this point a bit. Let us think about how many digital identities a human -beign might have. First, consider the case of n=0, someone who simply wants no business with the system at all. For -simplicity, let us assume that we have solved this issue of consent, i.e. every person who is identified by the system -consents to this practice. For n=1, the approaches outlined above all provide some approximate solution. States may not -grant every human sufficient ID (e.g. children, the mentally disabled or prisoners might be left out), and the social -systems might fail to catch people who simply do not have any friends, but otherwise their approximations hold. Maybe. -But what about n=2, n=3, ...? None of these systems adequately consider cases where a human being might legitimately -wish to hold multiple digital identities, non-maliciously. - -Consider a hypothetical lesbian, conservative politician. An active social media presence is a core component of a -modern politician's carreer. At the same time, "conservative homophobe" is still well within the realm of tautology and -it would be legitimate for this politician to wish to not disclose a large fraction of their private life to the world -at large. They might have a separate online identity for matters related to it. For this politician, the social -relationship-based systems referenced above would either incorporate outing as a design feature, or they would force -the politician to choose either of their two identities: To choose between private life and carreer. When deferring to -the state as the decider over personhood, at least the platform's operator would know about the outrageously sensitive -link between the politician's online identities. Clearly, no such solution can be considered socially just. - -Let us try not to be caught up on saving the world at this point. The issue of conservative homophobia is out of the -scope of our consideration, and it is not one that anyone can solve in the near future. Magical realism aside, least of -all can some technological thing beckon this change. There is a case for legitimate uses of multiple, separate digital -identities, and we do not have a technical or political answer to it. All hope is not lost yet, though. We can easily -undo this gordian knot by acknowledging an unspoken assumption that underlies any social relationships between real -people, past the procrustean bed of computer systems or organizational structures these relationships are cast into. - - As a function of social interaction, digital identities conform to roles_ in sociological terminology, and are not - at all the same as personhood_. Roles are subjective and arise from a relationship between people, and a single - person might legitimately perform different roles depending on context. - -When computer scientists or programmers are creating new systems, there always is an (often implicit) modelling stage. -Formally, during this stage a domain expert and a modeller with a computer science background come together, each -contributing their knowledge to form a model that is both appropriate for real-world use and practical from an -engineering point of view. In practice, these two roles are often necessarily fulfilled by the same person, who is often -also the programmer of the thing. This leads to many computer systems using poor models. A typical example of this issue -are systems requiring a person's name that use three input fields labelled "First Name", "Middle Initial" and "Last -Name". These systems are often created by US-American programmers, who are used to this naming schema from their lived -experience. Unfortunately, this schema breaks down for those few billion people who use their last name first, who have -more than one middle name, or who have multiple given names and do not normally use the first one of those. - -Once a system creator's implicit assumptions have been encoded into the system like this, it is often very hard to get -out of that situation. A pattern to use during careful modelling is to keep the model flexible to account for unforeseen -corner cases. For example, when modelling a system requiring a person's name, one would have to ask what the name is -used for. It may be the most sensible decision to simply ask the user for their name twice: Once in first name/last name -format for e.g. tax purposes, and once with a free-form text field for e.g. displaying on their account page. - -While for names, many systems already use some form of flexible model by e.g. having a *handle* or *nickname* separate -from the *display name*, "social" systems still often are stuck with an identity model based around a concept of a -single, rigid identity. In practice, people perform different roles_ in different circumstances. When asking for a -person's identity, one would get wildly different answers from different people. A person's identity as perceived by -others is coupled to their relationship more than to some underlying, biological or administrative truth. Thinking back -to the straw man politician above, this is evident in subtle ways in almost all our everyday relationships: Some people -may know me by my legal name, some by my online nickname. To some I may be a computer scientist, to some a flatmate. -None of my friends and acquaintances have ever wanted to see my passport, or asked to take my DNA to ascertain that I am -a distinct human being from the other humans they know. Likewise, identifying me by my social connections is impractical -as it would require an exceedingly weird amount of what can only be described as snooping. Yet, this concept of a -single, consistent, global, true identity is exactly what up to now all technological solutions to the identity problem -are trying to achieve. - -Building Bridges -================ - -I think I can offer you one main take-aways from the discussion above. - - During modelling social systems, focus on relationships—not identity. - -Rephrased into more actionable points, as someone designing a social digital system, do the following: - -0. Early in the design stages, take the time to consider fundamental modelling issues like this one. If you don't, you - will likely get stuck with a sub-optimal model that will be hard to get rid of. -1. Where possible, be flexible. Allow people to chose their own identifier. Don't require them to use their real names, - they may not wish to disclose those or they may not be in a format that is useful to you (they may be too long, too - short, too ubiquituous, in foreign characters etc.). A free-form text field with a reasonable length limit is a good - approach here. -2. Do not use credit cards or phone numbers to identify people. There are many people who do not have either, and - scammers can simply buy this data in bulk on the darknet. -3. Allow people to create multiple identites [#accountswitchopsec]_, and acknowledge the role of social relationships in - your interaction features. People have very legitimate reasons to separate areas of their lifes, and it is not for - you or your computer to decide who is who to whom. If your thing requires a global search function, re-consider the - data protection aspects of your system. If you want to encourage social functions in the face of bots and trolls, - make it easy for people to share their identities out-of-band, such as through a QR code or a copy-and-pasteable - short link. If you require someone's legal name or address for billing purposes, unify these identities behind the - scenes if at all and allow them to act as if fully independent in public. - -While change of perspective comes with its share of user experience challenges, but also with a promise for a more -human, more dignified online experience. Perhaps we can find a way to adapt cyberspace to humans, instead of continuing -trying it the other way around. - -.. _astroturfing: https://en.wikipedia.org/wiki/Astroturfing -.. _Stasi: https://en.wikipedia.org/wiki/Stasi - -.. [#cryptocurrency] Pseudo-currencies in that, while they provide some aspects of a regular currency such as ownership - and transactions, they lack most others. Traditional currencies are backed by states, regulated by central banks - tasked with maintaining their stability and ultimately provide accountability through law enforcement, courts - and political elections. - -.. [#discriminatory] Discriminatory as in discriminating against minorities, but also as in deciding what is and what is - not. - -.. [#accountswitchopsec] This does mean that you should not actively prevent people from creating multiple accounts. It - does not necessarily entail building a proper user interface around this practice. If you do the latter, e.g. by - offering a "switch identity" button or an identiy drop-down menu on a post submission form, you can easily - encourage slip-ups that might disclose the connection between two identities, and you make it possible for - someone hacking a single login to learn about this connection as well. - -.. [#meatspacefn] Meatspace_ is where people physically are, as opposed to cyberspace - -.. _Meatspace: https://dictionary.cambridge.org/dictionary/english/meatspace -.. _roles: https://en.wikipedia.org/wiki/Role -.. _personhood: https://en.wikipedia.org/wiki/Personhood diff --git a/content/posts/sybil-resistance-identity/index.rst b/content/posts/sybil-resistance-identity/index.rst deleted file mode 100644 index f90b5ac..0000000 --- a/content/posts/sybil-resistance-identity/index.rst +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: "Identity between Cyberspace and Meatspace" -date: 2020-09-09T15:00:00+02:00 -draft: true ---- - -.. raw:: html - -
- -
Photo by Tim Bennett on Unsplash
-
- -Identity in Cyberspace -====================== - -.. Identity is a frequent problem -.. Easy solutions abound -.. Precise modelling is uncommon -.. True identity is sensitive, hard to handle -.. -.. Often, conversational features emphasized -> true identity is unnecessary -.. Social role theory -.. Call to action - -Most computer systems that interface with humans have a concept of user identity. The data structures used for its -storage vary, but usually one *account* corresponds to one human *user*. In many applications, the system operator tries -to ensure that one user cannot create multiple accounts. In online social networks, astrotufing_ and trolling are easier -to fight when limits are imposed on account creation. In online stores, fraud prevention means the store operator needs -their customers legal identity and the operator must be able to ban offending customers. In mobile messaging systems, -users have to be able to find each other by some identifier such as name or phone number, and this identifier has to be -unique and hard to forge. - -Today, in systems that allow anyone to create an account have largely converged to require either an email address or a -mobile phone number. Email addresses are used by systems that are less vulnerable to abuse and that are used on laptop -or desktop computers. Mobile phone numbers are abundantly used in smartphone apps, as well as in systems more prone to -abuse such as online social networks or ecommerce. Both are easily verified using a confirmation email or SMS. - -When designing or programming an online system, it is uncommon that the precise real-world semantics of accounts are -modelled. Most computer systems use ad-hoc data models. During their creation, their programmers implicit assumptions -about the world are encoded into these data models. Most of the time this works fine, but it does lead to significant -blind spots that can make systems break down for a fraction of their users. - -Lives in Meatspace -================== - -A consequence of the proliferation of phone numbers being used to identify people is that most people will not be able -to create multiple accounts. *"That's the point!"* you might say, but while we want to prevent scammers, spammers and -boored schoolchildren from messing with our systems, everybody else may have legitimate reasons to have more than one -account. - -We can apply sociology's model of roles_ to understand this issue. In sociology, a role is the comprehensive pattern of -rules and expectations that govern an individual's behavior corresponding to their social position. A key fact is that -most people occupy mutliple roles. A parent may also be a company employee or a wife and perform accordingly given the -circumstances. Systems that tie digital identity to legal personhood through the contracts behind phone numbers impede -their users' attempts at role separation. Effects of this are e.g. that nowadays employers routinely screen applicants' -social media accounts for unacceptable content. - -While this role conflict merely amounts to a minor inconvenience to most there are many to who it poses an existential -problem. Consider an LGBT+ person living in a repressive country or a politically conservative person living in a -very liberal city. Both have legitimate reasons to strictly separate parts of their private lives from others. For both, -much is at stake. Yet, both will have to practically circumvent most online systems registration barriers to implement -this separation. - -Trusting the User -================= - -While there is no single solution to these issues, there are several possible mitigations. The first and most important -one is to systematically think about the system's data model when creating it. Which assumptions about the real world -are inherent in it? Are these assumptions likely to cause issues? Ad-hoc models are easily created, but hard to get rid -of when they start causing problems. - -A general guideline on identity should be that hindering trolls by requiring things like phone numbers or credit card -numbers is very likely to also be an obstacle to many entirely legitimate uses. Captchas_ or invitation links can help -to keep out the trolls. Another approach is to limit the damage a troll can cause with things like effective moderation -systems, reputation systems or by limiting the reach of newly created accounts. - -Outside of e-commerce, actually tying a digital account to a real-world identity is very rarely necessary. The value of -a messenger app is not in the names in its contacts list, but the conversations behind these names. When two people meet -each other on the street, their interaction is shaped by a myriad of social factors—but *not* by them showing each other -their photo ID. - -Humans with their messy identities do not fit today's cyberspace well. Let's adapt cyberspace to humans, instead of -trying it the other way around. - -.. _astroturfing: https://en.wikipedia.org/wiki/Astroturfing -.. _roles: https://en.wikipedia.org/wiki/Role -.. _Captchas: https://link.springer.com/content/pdf/10.1007/3-540-39200-9_18.pdf - diff --git a/content/posts/telekom-gpon-sfp/images/edgerouter_interface_config.png b/content/posts/telekom-gpon-sfp/images/edgerouter_interface_config.png deleted file mode 100644 index 72d2a9b..0000000 Binary files a/content/posts/telekom-gpon-sfp/images/edgerouter_interface_config.png and /dev/null differ diff --git a/content/posts/telekom-gpon-sfp/images/edgerouter_route_config.png b/content/posts/telekom-gpon-sfp/images/edgerouter_route_config.png deleted file mode 100644 index fe65051..0000000 Binary files a/content/posts/telekom-gpon-sfp/images/edgerouter_route_config.png and /dev/null differ diff --git a/content/posts/telekom-gpon-sfp/images/edgerouter_sfp_config.png b/content/posts/telekom-gpon-sfp/images/edgerouter_sfp_config.png deleted file mode 100644 index 01da1e7..0000000 Binary files a/content/posts/telekom-gpon-sfp/images/edgerouter_sfp_config.png and /dev/null differ diff --git a/content/posts/telekom-gpon-sfp/images/edgerouter_snat_config.png b/content/posts/telekom-gpon-sfp/images/edgerouter_snat_config.png deleted file mode 100644 index 6e033ac..0000000 Binary files a/content/posts/telekom-gpon-sfp/images/edgerouter_snat_config.png and /dev/null differ diff --git a/content/posts/telekom-gpon-sfp/images/edgerouter_snat_config2.png b/content/posts/telekom-gpon-sfp/images/edgerouter_snat_config2.png deleted file mode 100644 index fb7ce32..0000000 Binary files a/content/posts/telekom-gpon-sfp/images/edgerouter_snat_config2.png and /dev/null differ diff --git a/content/posts/telekom-gpon-sfp/images/sfp_onu_ploam_pw_config.png b/content/posts/telekom-gpon-sfp/images/sfp_onu_ploam_pw_config.png deleted file mode 100644 index 66f6f6a..0000000 Binary files a/content/posts/telekom-gpon-sfp/images/sfp_onu_ploam_pw_config.png and /dev/null differ diff --git a/content/posts/telekom-gpon-sfp/images/sfp_onu_reset.png b/content/posts/telekom-gpon-sfp/images/sfp_onu_reset.png deleted file mode 100644 index 13c2ca6..0000000 Binary files a/content/posts/telekom-gpon-sfp/images/sfp_onu_reset.png and /dev/null differ diff --git a/content/posts/telekom-gpon-sfp/images/sfp_onu_web_if.png b/content/posts/telekom-gpon-sfp/images/sfp_onu_web_if.png deleted file mode 100644 index dea0b8f..0000000 Binary files a/content/posts/telekom-gpon-sfp/images/sfp_onu_web_if.png and /dev/null differ diff --git a/content/posts/telekom-gpon-sfp/index.rst b/content/posts/telekom-gpon-sfp/index.rst deleted file mode 100644 index 17f78d5..0000000 --- a/content/posts/telekom-gpon-sfp/index.rst +++ /dev/null @@ -1,216 +0,0 @@ ---- -title: "Ubiquiti EdgeRouter on Deutsche Telekom GPON Fiber" -date: 2022-02-21T20:00:00+01:00 ---- - -Disclaimer -========== - -I provide this guide as a reference for other knowledgeable users without any warranty. Please feel free to use this as -a resource but do not hold me responsible if this does not work for you. There is a significant chance that due to an -error on my side or due to Telekom changing their setup this guide will not work for you, and you may end up having to -pay for an unsuccessful Telekom technician visit. That is your own risk, and I do not assume any liability. - -Tl;dr -===== - -The "Telekom Digitalisierungsbox Glasfasermodem" is a GPON ONT in SFP form factor that works with an Ubiquiti EdgeRouter -6P's SFP port. You can order it from Telekom or other vendors using the Telekom P/N 40823569 or its EAN 4718937619382. -It costs about the same as the separate plastic box modem, but saves a lot of space and does not require a separate -power supply. - -To configure, first access the SFP ONT's web interface at ``10.10.1.1`` by configuring your SPF port's IP to static -``10.10.1.2``. User credentials are either admin/admin or admin/1234. In the web interface, set put PLOAM password into the -"SLID" setting in ASCII mode, then save & reboot the device. Now, configure PPPoE on the router's SFP port using the -PPPoE UID ``[anschlusskennung] [zugangsnummer] "#" [mitbenutzernummer] "@t-online.de"`` and your "Persönliches Kennwort" as -PPPoE password. Set the VLAN to ``7``, and you are good to go. - -Background -========== - -I moved into a new apartment that has a fiber internet connection operated by Deutsche Telekom. Having made some poor -experiences with AVM's FritzBox brand of routers that is commonly used by German carriers, I decided to use my own -Router instead of the one provided by Deutsche Telekom. Like other German providers, Telekom charges exorbitant amounts -in monthly fees for their routers, so even though my choice ended up being a high-end piece of commercial equipment I -will still be cheaper than going with Telekom's much shittier device when added up over a two-year contract period. - -The hardware I chose is the Ubiquiti EdgeRouter 6P. This device is from Ubiquiti's commercial lineup and is intended to -power something like a small branch office of a company. It comes in a small form factor (as opposed to larger rackmount -units), it does not consume a lot of power, it has five PoE-capable Ethernet ports which I can directly connect up to -the Ubiquiti Unifi UAP access point that I already have, and it has a powerful configuration interface. It can even -act as a VPN endpoint! - -Telekom's fiber internet offering for residential customers is GPON-based. GPON stands for "Gigabit Passive Optical -Network" and means that instead of patching through one fiber or pair of fibers to each customer, several customers in -one building are connected to a single fiber through optical splitters. These optical splitters are passive, i.e. they -are just fancy pieces of glass and fibers and do not require electrical power. The advantage of GPON is lower initial -cost for the operator, the disadvantage is that competing providers can only ever hope to get traffic handed through by -Telekom and will never be able to use their own equipment on the "network" end of the fiber. - -Telekom wants you to connect to its fiber network through a small plastic box that they call "modem", and that the rest -of the world calls "ONT", or Optical Network Terminator. Telekom's ONT has an upstream optical port with an LC -connector, and a regular RJ45 ethernet port downstream. The "modem" in fact contains an entire linux system that -terminates the ITU-standard suite of protocols that is used to manage what happens on the fiber, e.g. scheduling of -transmission slots and adjustment of transmitter laser power. - -Looking at Telekom's plastic box ONT and my nice and shiny EdgeRouter, I was not a fan of this solution. Doing some -research I found out that you can in fact get GPON ONTs in an SFP module form factor. My EdgeRouter has an SFP slot, so -if I could get one of these that is compatible with Telekom's GPON flavor I could theoretically just plug it into my -EdgeRouter's SFP slot with no separate power supply needed, saving a lot of space in the process. - -Finding a GPON SFP ONT that is compatible with Telekom's network turned out to be the hard part. While there are lots of -commercial devices that look like they *should be* compatible, I could not be sure and I did not feel like sinking lots -of money and weeks of trial and error into figuring out which are and which are not. After about half a dozen calls with -various Telekom customer service departments I found the solution that ultimately ended up working: For their business -customer fiber internet offering, Telekom uses the same GPON standard, but different ONT equipment. Their router for -business customers is called "Digitalisierungsbox" and it in fact comes with an SFP GPON ONT. And, as it turns out, you -can order that SFP GPON ONT separately for about 50 € (the same as the plastic box one) from either Telekom or a number -of independent online stores. The Telekom part number of the thing is 40823569, the EAN is 4718937619382. - -Below is a list of steps that I had to undertake in order to get my EdgeRouter/SFP ONT setup to work. - -Hardware Setup -============== - -The hardware setup is really simple. The SFP ONU is plugged into the EdgeRouter's SFP port. The ONU is connected to -the Telekom Fiber through the LC/APC to SC/APC adapter cable that is included in its package. Telekom's technician will -install an LC/APC coupler to join both cables. To configure the EdgeRouter, connect yourself through an ethernet cable -*on port 2*. Ubiquiti's setup wizards assume the WAN interface is either port 1 or the SFP port (port 5), and default to -use port 2 as their LAN interface even when port 5 is configured as the only WAN port. The default IP for the EdgeRouter -is ``192.168.1.1``, and the default UID/PW is ubnt/ubnt. - -Configuration -============= - -Getting access to the SFP ONU's config interface ------------------------------------------------- - -In this section I am assuming you want to configure the SFP ONU while it is plugged into the EdgeRouter from a laptop -connected to the EdgeRouter's ethernet port 2. To do this, we have to first configure the right IP/subnet on the -EdgeRouter's SFP interface, then patch connections between the SFP ONU and the laptop through the EdgeRouter. - -1. First, inside the EdgeRouter's config interface we need to configure a static IP with accompanying SNAT rule on the - SFP port to allow us to access the SFP module's web interface through the laptop connected to the EdgeRouter. For - this, configure the eth5 interface (which is the SFP port) to use the static IP ``10.10.1.2/24``. - -.. raw:: html - -
- - The EdgeRouter's graphical configuration interface showing IP
-           address 10.10.1.2/24 being configured for interface eth5, which is the SFP interface. - -
SFP interface configuration to access the SFP ONU from a laptop connected to the EdgeRouter's LAN - port
-
- -2. With the SFP port assigned an IP address, we need to add a NAT rule to forward connections from the configuration - laptop on eth2 to the SFP port. We do this by adding a source NAT rule with masquerading enabled, for the TCP - protocol, with destination address ``10.10.1.0/24`` (the SFP config interface's private network). - -.. raw:: html - -
- - The EdgeRouter's graphical configuration interface showing a
-            source NAT being configured for interface eth5 for TCP protocol connections to destination address 10.10.1.1
-            using masquerading. - -
Source NAT configuration to access the SFP ONU from LAN. eth5, masquerading on, TCP, destination - 10.10.1.1 (the SFP ONU's IP).
-
- -3. Finally, make sure that your laptop will actually use the EdgeRouter as its gateway for IPs within ``10.10.1.0/24``. - On the laptop, disable any VPNs, disconnect your Wifi and make sure that IP r shows a default route pointing at the - EdgeRouter's ``192.168.1.1``. If that isn't the case, on Linux you can manually add the necessary route by using - ``sudo ip r a 10.10.1.0/24 via 192.168.1.1 dev enp5s0`` - -After setting up this temporary route, you should be able to access the SFP ONU's configuration web interface by -pointing a browser at ``http://10.10.1.1/`` Just make sure you use plain-text HTTP here, not secure HTTP**S**. The -default login credentials for the device are admin/1234. - -.. raw:: html - -
- - The SFP ONU configuration web interface is a basic-looking website with
-            a big Zyxel logo on it. It has menu options named status, setup and management. It shows a system overview
-            page that lists the device's uptime and software version. - -
The SFP ONU's web interface.
-
- -Configuring the PLOAM password / SLID / ONT-Installationskennung ----------------------------------------------------------------- - -On the SFP ONU's web interface, we only have to change one single setting: Under "Setup", we have to set what the SFP -ONU calls "SLID" to the PLOAM password for the interface. Telekom calls this the "ONT-Installationskennung". You get -this from your Telekom technician. In the config interface, select ASCII mode and enter the number using the format -``ABCD000000`` with four capital letters followed by six zeros. If necessary, you can read the SFP ONU's serial number -on this page. - -.. raw:: html - -
- - The SFP ONU configuration web interface shows its SLID
-            configuration page. A text field labelled SLID asks the user to enter a value of at most ten characters. As
-            an example, abcdefg123 is listed. - -
The SFP ONU's config interface to set SLID/PLOAM PW/ONT-Installationskennung.
-
- -Press "Save Config" on the top right of the web page, then select "Reset ONU" and click "Apply" under the "Reset ONU" -link on the left. Make sure to not select the factory reset option instead. - -.. raw:: html - -
- - The SFP ONU configuration web interface shows its reset ONU page. There
-            are two options labelled Reset ONU and Reset to factory default settings. The reset ONU option is
-            selected. - -
Rebooting the SFP ONU.
-
- -With the ONU configured, after the reset the "GPON Information" page from the left menu under "Status" from the top menu -should show ``GPON Line Status: O5``. You can now remove the SNAT rule and IP address from the SFP interface in the -EdgeRouter's config. I recommend this since there is no way to change the ONU's default credentials, and leaving the -SNAT rule in place makes it vulnerable to attacks from your LAN. If you use the EdgeRouter's setup wizard in the next -step, that wizard will reset all of these settings. - -Configuring PPPoE and NAT -------------------------- - -Our ONU now has a low-level connection to Telekom's fiber network. The next step is to configure the EdgeRouter to -authenticate with the ONU through PPPoE. The easiest way to do this is to use the EdgeRouter's "Basic Setup" wizard as -described in the `EdgeOS User Guide`. In the wizard, select the SFP port (``eth5``) as the internet/WAN port. Select -``Internet Connection Type`` as ``PPPoE``, then enter the PPPoE credentials you got from your Telekom technician. The -password is your "Persönliches Kennwort" that you also use to log in to your customer account on Telekom's website. The -account name is ``[anschlusskennung] [zugangsnummer] "#" [mitbenutzernummer] "@t-online.de"``, so something like -``002712345678012345678901#0001@t-online.de``. Enable "Internet connection is on VLAN" and enter VLAN ID ``7``. This is -necessary because of the way Telekom set up their triple play (TV/phone/internet) service. After following through with -the wizard, your internet should be already working on port 2 of the router. Note that despite selecting the SFP port as -the router's WAN port, the wizard will still reserve port 1 (``eth0``) for another WAN interface, so you will only be -able to access the configuration interface through port 2 (``eth1``) after the wizard is done. You can of course change -this later. - -That's it, you're done and your internet should be working! - -Having Fun with the SPF GPON ONU -================================ - -If you want to dig deeper into the internals of Telekom's GPON implementation, the SFP ONU's firmware is a great -starting point. Default credentials are all admin/admin or admin/1234 and you can even get a regular busybox shell on -the device through SSH. The device's firmware is based on OpenWRT, and the source for large parts of the core control -components can be found under open source licenses as well. While I would strictly advice you to not mess around with -the actual modem settings because due to GPON you share a medium with your neighbors and might very well disrupt their -internet if you mess up, inspecting the ONU's firmware is a great way to learn about the inner workings of a modern GPON -network. - -If you are interested in messing around with the SFP ONU, there is a github repository where interesting thins are -collected `here `__. - -.. _`EdgeOS User Guide`: https://dl.ubnt.com/guides/edgemax/EdgeOS_UG.pdf - diff --git a/content/posts/thors-hammer/images/thors_hammer_breadboard.jpg b/content/posts/thors-hammer/images/thors_hammer_breadboard.jpg deleted file mode 100644 index 4504d83..0000000 Binary files a/content/posts/thors-hammer/images/thors_hammer_breadboard.jpg and /dev/null differ diff --git a/content/posts/thors-hammer/images/thors_hammer_schematic.jpg b/content/posts/thors-hammer/images/thors_hammer_schematic.jpg deleted file mode 100644 index 3061f61..0000000 Binary files a/content/posts/thors-hammer/images/thors_hammer_schematic.jpg and /dev/null differ diff --git a/content/posts/thors-hammer/index.rst b/content/posts/thors-hammer/index.rst deleted file mode 100644 index ba851a5..0000000 --- a/content/posts/thors-hammer/index.rst +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: "Thor's Hammer" -date: 2018-05-03T11:59:37+02:00 ---- - -In case you were having an inferiority complex because your friends' IBM Model M keyboards are so much louder than the -shitty rubber dome freebie you got with your pc... Here's the solution: Thor's Hammer, a simple typing cadence enhancer -for `PS/2`_ keyboards. - -.. raw:: html - -
- -
A demonstration of the completed project. - - h264 download / - webm download -
-
- -The connects to the keyboard's PS/2 clock line and briefly actuates a large solenoid on each key press. An interesting -fact about PS/2 is that the clock line is only active as long as either the host computer or the input device actually -want to send data. In case of a keyboard that's the case when a key is pressed or when the host changes the keyboard's -LED state, otherwise the clock line is silent. We ignore the LED activity for now as it's generally coupled to key -presses. By just triggering an NE555 configured as astable flipflop we can stretch each train of clock pulses to a -pulse a few tens of milliseconds long that is enough to actuate the solenoid. - -.. raw:: html - -
- The schematic of the PS2 driver -
The schematic of the driver stretching the PS/2 clock pulses to drive the solenoid.
-
- - -Since PS/2 sends each key press and key release separately this circuit will pulse twice per keystroke. It would be -possible to ignore one of them but I figure the added noise just adds to the experience. - -Built on a breadboard, the circuit looks like this. - -.. raw:: html - -
- The circuit built on a breadboard -
The completed circuit built up on a breadboard and attached to a keyboard.
-
- - -Since my solenoid did not have a tensioning spring I used a rubber band and some vinyl tape to make an adjustable -tensioner. The small orange USB hub serves as an end-stop because I had nothing else of the right shape. The sound and -resonance of the thing can be adjusted to taste by moving the end stop, adjusting the tensioning rubber and tuning the -excitation duration using the potentiometer. My particular solenoid was a bit slow so I added some pieces of circuit -board as shims between the plunger and the case to limit the plunger's travel inside the solenoid core. - -.. _`PS/2`: https://en.wikipedia.org/wiki/PS/2_port - diff --git a/content/posts/thors-hammer/video/thors_hammer.mkv b/content/posts/thors-hammer/video/thors_hammer.mkv deleted file mode 100644 index c9581e9..0000000 Binary files a/content/posts/thors-hammer/video/thors_hammer.mkv and /dev/null differ diff --git a/content/posts/thors-hammer/video/thors_hammer.mov b/content/posts/thors-hammer/video/thors_hammer.mov deleted file mode 100644 index fff65a8..0000000 Binary files a/content/posts/thors-hammer/video/thors_hammer.mov and /dev/null differ diff --git a/content/posts/thors-hammer/video/thors_hammer.webm b/content/posts/thors-hammer/video/thors_hammer.webm deleted file mode 100644 index 2bcf1ca..0000000 Binary files a/content/posts/thors-hammer/video/thors_hammer.webm and /dev/null differ diff --git a/content/posts/wifi-led-driver/images/board_in_case.jpg b/content/posts/wifi-led-driver/images/board_in_case.jpg deleted file mode 100644 index 843900a..0000000 Binary files a/content/posts/wifi-led-driver/images/board_in_case.jpg and /dev/null differ diff --git a/content/posts/wifi-led-driver/images/board_in_case.small.jpg b/content/posts/wifi-led-driver/images/board_in_case.small.jpg deleted file mode 100644 index 5c0aa81..0000000 Binary files a/content/posts/wifi-led-driver/images/board_in_case.small.jpg and /dev/null differ diff --git a/content/posts/wifi-led-driver/images/boards.jpg b/content/posts/wifi-led-driver/images/boards.jpg deleted file mode 100644 index 79f8154..0000000 Binary files a/content/posts/wifi-led-driver/images/boards.jpg and /dev/null differ diff --git a/content/posts/wifi-led-driver/images/boards.small.jpg b/content/posts/wifi-led-driver/images/boards.small.jpg deleted file mode 100644 index 6f5c28c..0000000 Binary files a/content/posts/wifi-led-driver/images/boards.small.jpg and /dev/null differ diff --git a/content/posts/wifi-led-driver/images/layout.png b/content/posts/wifi-led-driver/images/layout.png deleted file mode 100644 index 11fc50e..0000000 Binary files a/content/posts/wifi-led-driver/images/layout.png and /dev/null differ diff --git a/content/posts/wifi-led-driver/images/schematic.png b/content/posts/wifi-led-driver/images/schematic.png deleted file mode 100644 index 8294f12..0000000 Binary files a/content/posts/wifi-led-driver/images/schematic.png and /dev/null differ diff --git a/content/posts/wifi-led-driver/index.rst b/content/posts/wifi-led-driver/index.rst deleted file mode 100644 index 8e8b24d..0000000 --- a/content/posts/wifi-led-driver/index.rst +++ /dev/null @@ -1,145 +0,0 @@ ---- -title: "Wifi Led Driver" -date: 2018-05-02T11:31:03+02:00 ---- - -Project motivation -================== - -.. FIXME finished project picture with LED tape -.. raw:: html - -
- -
The completed driver board installed in the 3D-printed case. This device can now be connected to - 12V and two segments of LED tape that can then be controlled trough Wifi. The ESP8266 module goes on the pin - header on the left and was removed for this picture. -
-
- -After the `multichannel LED driver`_ was completed, I was just getting used to controlling LEDs at 14-bit resolution. -I liked the board we designed in this project, but at 32 channels it was a bit large for most use cases. Sometimes I -just want to pop a piece of LED tape or two somewhere, but I don't need a full 32 channels of control. I ended up -thinking that a smaller version of the 32-channel driver that didn't require a separate control computer would be -handy. So I sat down and designed a variant of the design with only 8 channels instead of 32 and an on-board ESP8266_ -module instead of the RS485_ transceiver for WiFi connectivity. - -The Electronics -=============== - -The schematic was mostly copy-pasted from the 32-channel design. The PCB was designed from scratch. This time, I went -for a 5x7cm form factor to allow for enough room for all connectors and to give the ESP8266_'s WiFi antenna enough -space. The board has two 5-pin Phoenix-style_ for two RGB-White (RGBW) tapes and one 2-pin Phoenix-style_ connector for -12V power input. The control circuitry and the serial protocol are unchanged, but the STM32_ now talks to an ESP-01_ -module running custom firmware. - -The LEDs are driven using a 74HC595_ shift register controlling a bunch of AO3400_ MOSFETs_, with resistors in front of -the MOSFETs_' gates to slow down the transitions a bit to reduce brighntess nonlinearities and EMI_ resulting from -ringing of the LED tape's wiring inductance. - -The board has two spots for either `self-resettable fuses (polyfuses) `__ or regular melting-wire fuses_ in -a small SMD_ package, one for each RGBW output. For low currents the self-resettable fuses should be okay but at higher -currents their `trip times get long enough that they become unlikely to trip in time to save anything -`__, so plain old non-resettable fuses would be the way to go there. - -.. FIXME finished board photos -.. FIXME board with test tape picture - -.. raw:: html - -
-
- -
- The schematic of the driver board, with the ESP8266 on the top left, the STM32 microcontroller for LED - modulation below, the shift register in the middle and the LED drivers and outputs on the right. - Download PDF -
-
- -
- The board layout with the top side being visible. The top side contains the footprint for the ESP8266, the - microcontroller, fuses, filter cap, connectors and the shift register. The LEDs are connected on the left, - with one connector per LED tape segment. The power input connector is on the bottom right. The LED driver - MOSFETs are in small SOT-23 packages on the back of the board. Since this board is not intended for - super-high currents, the MOSFETs are adequately cooled just through the board's copper planes. - Download PDF -
-
-
- -.. raw:: html - -
- -
The completed PCBs of this project (front) and the `multichannel LED driver`_ project the driver - circuitry was derived from (back). -
-
- - -The Firmware -============ - -The STM32_ firmware only had to be slightly modified to accomodate the reduced channel count since the protocol remains -unchanged. The ESP firmware is based on esphttpd_ by Spritetm_. The modifications to the webserver firmware are pretty -basic. First, the UART console has been disabled since I use the UART to talk to the STM32. The few bootloader messages -popping out the UART on boot are not an issue, since they're unlikely to contain the fixed 32-bit address prefix the -serial protocol requires for the STM32_ to do anything. - -Second, I added LED control by adding drivers for the serial protocol and a bunch of colorspace conversion functions. -When I first tested the prototype software, I noticed that color reproduction was extremely poor. When I just sent a -HSV_ rainbow fade from a python command line, the result looked totally wrong. The fade did not seem to go at a constant -speed and some colors, in particular yellow, orange and greens, were not visible at all. The problem turned out to be a -stark mismatch of the red, green and blue channels of the LED tape and less-than-optimal color reproduction of the pure -colors. I decided to properly measure the LED tape's color reproduction so I could compensate for it in software. This -turned out to be an extremely interesting project, the details of which you can read in my `LED characterization`_ -article. - -Third, I updated the built-in websites with some ad-hoc documentation on how to use the thing and a basic interface for -LED control. - -.. FIXME screenshot of firmware website - -Making an enclosure -=================== - -To be actually useful, the driver needed a robust enclosure. Bare PCBs are nice for prototyping, but for actually -putting the thing anywhere it needs a case to protect it against random destruction. - -The board has four mounting holes with comfortable spacing in its corners to allow easy mounting inside a 3D-printed -case. The case itself is described in an OpenSCAD_ script. To make it look a little nicer, a little 3D relief is laid -into the lid. The 3D relief is generated with a bit of blender magic. The source STL_ model is loaded into blender, then -blender's amazingly flexible rendering system is used to export a depth map of a projection of the model as a PNG_ file. -This depth map is then imported as a triangle mesh into OpenSCAD_. - -For the relief to look good, I chose a rather high resolution for the depth map. This unfortunately leads to extreme -memory use and processing time on the part of OpenSCAD_, but since I have access to a sufficiently fast machine that is -not a problem. Just be careful if you try opening the OpenSCAD_ file on your machine, OpenSCAD_ will probably crash -unless you're on a beefy machine or interrupt it when it starts auto-rendering the file. - -The board is mounted into the enclosure using knurled insert nuts that are pressed into a 3D-printed hole using a bit of -violence. - -.. _`multichannel LED driver`: {{}} -.. _`LED characterization`: {{}} -.. _ESP8266: https://en.wikipedia.org/wiki/ESP8266 -.. _RS485: https://en.wikipedia.org/wiki/RS-485 -.. _Phoenix-style: https://www.phoenixcontact.com/online/portal/de?uri=pxc-oc-itemdetail:pid=1757019&library=dede&tab=1 -.. _STM32: http://www.st.com/resource/en/datasheet/stm32f030f4.pdf -.. _ESP-01: http://www.watterott.com/de/ESP8266-WiFi-Serial-Transceiver-Modul -.. _74HC595: http://www.ti.com/lit/ds/symlink/sn74hc595.pdf -.. _AO3400: http://aosmd.com/pdfs/datasheet/AO3400.pdf -.. _MOSFETs: https://en.wikipedia.org/wiki/MOSFET -.. _EMI: https://en.wikipedia.org/wiki/Electromagnetic_interference -.. _polyfuse: https://en.wikipedia.org/wiki/Resettable_fuse -.. _SMD: https://en.wikipedia.org/wiki/Surface-mount_technology -.. _fuses: https://en.wikipedia.org/wiki/Fuse_(electrical) -.. _littlefuse-16r-datasheet: http://m.littelfuse.com/~/media/electronics/datasheets/resettable_ptcs/littelfuse_ptc_16r_datasheet.pdf.pdf -.. _OpenSCAD: http://www.openscad.org/ -.. _STL: https://en.wikipedia.org/wiki/STL_(file_format) -.. _PNG: https://en.wikipedia.org/wiki/Portable_Network_Graphics -.. _esphttpd: https://github.com/Spritetm/esphttpd -.. _Spritetm: http://spritesmods.com/ -.. _`HSV`: https://en.wikipedia.org/wiki/HSL_and_HSV - diff --git a/content/posts/wifi-led-driver/resource/lyza_schematic_and_pcb.pdf b/content/posts/wifi-led-driver/resource/lyza_schematic_and_pcb.pdf deleted file mode 100644 index 6532888..0000000 Binary files a/content/posts/wifi-led-driver/resource/lyza_schematic_and_pcb.pdf and /dev/null differ diff --git a/content/projects/_index.rst b/content/projects/_index.rst new file mode 100644 index 0000000..c975627 --- /dev/null +++ b/content/projects/_index.rst @@ -0,0 +1,6 @@ +--- +title: Projects +--- +I maintain a number of open-source projects. Most of these I started out of some personal need or interest. +I strive to keep all of them up to date and maintained, so if you notice an issue with one of them, please +open an issue on the project's issue tracker. diff --git a/content/projects/gerbolyze/README.rst b/content/projects/gerbolyze/README.rst new file mode 100644 index 0000000..cfa7673 --- /dev/null +++ b/content/projects/gerbolyze/README.rst @@ -0,0 +1,700 @@ +Gerbolyze renders SVG vector and PNG/JPG raster images into existing gerber PCB manufacturing files. +Vector data from SVG files is rendered losslessly *without* an intermediate rasterization/revectorization step. +Still, gerbolyze supports (almost) the full SVG 1.1 spec including complex, self-intersecting paths with holes, +patterns, dashes and transformations. + +Raster images can either be vectorized through contour tracing (like gerbolyze v1.0 did) or they can be embedded using +high-resolution grayscale emulation while (mostly) guaranteeing trace/space design rules. + +Try gerbolyze online at https://dyna.kokoroyukuma.de/gerboweb + +.. figure:: pics/pcbway_sample_02_small.jpg + :width: 800px + + Drawing by `トーコ Toko `__ converted using Gerbolyze and printed at PCBWay. + + +Tooling for PCB art is quite limited in both open source and closed source ecosystems. Something as simple as putting a +pretty picture on a PCB can be an extremely tedious task. Depending on the PCB tool used, various arcane incantations +may be necessary and even modestly complex images will slow down most PCB tools to a crawl. + +Gerbolyze solves this problem in a toolchain-agnostic way by directly vectorizing SVG vector and PNG or JPG bitmap files +onto existing gerber layers. Gerbolyze processes any spec-compliant SVG and "gerbolyzes" SVG vector data into a Gerber +spec-compliant form. Gerbolyze has been tested against both the leading open-source KiCAD toolchain and the +industry-standard Altium Designer. Gerbolyze is written with performance in mind and will happily vectorize tens of +thousands of primitives, generating tens of megabytes of gerber code without crapping itself. With gerbolyze you can +finally be confident that your PCB fab's toolchain will fall over before yours does if you overdo it with the high-poly +anime silkscreen. + +Gerbolyze is based on gerbonara_. + +.. image:: pics/process-overview.png + :width: 800px + +.. contents:: + +Tl;dr: Produce high-quality artistic PCBs in three easy steps! +-------------------------------------------------------------- + +Gerbolyze works in three steps. + +1. Generate a scale-accurate template of the finished PCB from your CAD tool's gerber output: + + .. code:: + + $ gerbolyze template --top template_top.svg [--bottom template_bottom.svg] my_gerber_dir + +2. Load the resulting template image Inkscape_ or another SVG editing program. Put your artwork on the appropriate SVG + layer. Dark colors become filled gerber primitives, bright colors become unfilled primitives. You can directly put + raster images (PNG/JPG) into this SVG as well, just position and scale them like everything else. SVG clips work for + images, too. Masks are not supported. + +3. Vectorize the edited SVG template image drectly into the PCB's gerber files: + + .. code:: + + $ gerbolyze paste --top template_top_edited.svg [--bottom ...] my_gerber_dir output_gerber_dir + +Quick Start Installation (Any Platform) +--------------------------------------- + +.. code-block:: shell + + python -m pip install --user gerbolyze + +To uninstall, run + +.. code-block:: shell + + python -m pip uninstall gerbolyze gerbonara resvg-wasi svg-flatten-wasi + +To update, run + +.. code-block:: shell + + python -m pip install --user --upgrade --upgrade-strategy eager gerbolyze + +Speeding up gerbolyze using natively-built binaries +--------------------------------------------------- + +This will install gerbolyze's binary dependency resvg and gerbolyze's svg-flatten utility as pre-built cross-platform +WASM binaries. When you first run gerbolyze, it will take some time (~30s) to link these binaries for your system. The +output is cached, so any future run is going to be fast. + +WASM is slower than natively-built binaries. To speed up gerbolyze, you can natively build its two binary dependencies: + +1. Install resvg natively using rust's cargo package manager: ``cargo install resvg`` +2. Install gerbolyze's svg-flatten utility natively. You can get pre-built binaries from gerbolyze's gitlab CI jobs `at + this link `__ by clicking the three dots on the + right next to the version you want. These pre-built binaries should work on any x86_64 linux since they are + statically linked. You can also build svg-flatten yourself by running ``make`` inside the ``svg-flatten`` folder from + a gerbolyze checkout. + +Gerbolyze will pick up these binaries when installed in your ``$PATH``. resvg is also picked up when it is installed by +cargo in your home's ``~/.cargo``, even if it's not in your ``$PATH``. You can override the resvg, usvg or svg-flatten +binary that gerbolyze uses by giving it the absoulute path to a binary in the ``$RESVG``, ``$USVG`` and ``$SVG_FLATTEN`` +environment variables. + + +Build from source (any distro) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: shell + + git clone --recurse-submodules https://git.jaseg.de/gerbolyze.git + cd gerbolyze + + python3 -m venv + source venv/bin/activate + python3 setup.py install + +Features +-------- + +Input on the left, output on the right. + +.. image:: pics/test_svg_readme_composited.png + :width: 800px + +* Almost full SVG 1.1 static spec coverage (!) + + * Paths with beziers, self-intersections and holes + * Strokes, even with dashes and markers + * Pattern fills and strokes + * Transformations and nested groups + * Proper text rendering with support for complex text layout (e.g. Arabic) + * elements via either built-in vectorizer or built-in halftone processor + * (some) CSS + +* Writes Gerber, SVG or KiCAD S-Expression (``.kicad_mod``) formats +* Can export from top/bottom SVGs to a whole gerber layer stack at once with filename autodetection +* Can export SVGs to ``.kicad_mod`` files like svg2mod (but with full SVG support) +* Beziers flattening with configurable tolerance using actual math! +* Polygon intersection removal +* Polygon hole removal (!) +* Optionally vector-compositing of output: convert black/white/transparent image to black/transparent image +* Renders SVG templates from input gerbers for accurate and easy scaling and positioning of artwork +* layer masking with offset (e.g. all silk within 1mm of soldermask) +* Can read gerbers from zip files +* Limited SVG support for board outline layers (no fill/region support) +* Dashed lines supported on board outline layers + +Gerbolyze is the end-to-end "paste this svg into these gerbers" command that handles all layers on both board sides at +once. The heavy-duty computer geometry logic of gerbolyze is handled by the svg-flatten utility (``svg-flatten`` +directory). svg-flatten reads an SVG file and renders it into a variety of output formats. svg-flatten can be used like +a variant of the popular svg2mod that supports all of SVG and handles arbitrary input ```` elements. + +Algorithm Overview +------------------ + +This is the algorithm gerbolyze uses to process a stack of gerbers. + +* Map input files to semantic layers by their filenames +* For each layer: + + * load input gerber + * Pass mask layers through ``gerbv`` for conversion to SVG + * Pass mask layers SVG through ``svg-flatten --dilate`` + * Pass input SVG through ``svg-flatten --only-groups [layer]`` + * Overlay input gerber, mask and input svg + * Write result to output gerber + +This is the algorithm svg-flatten uses to process an SVG. + +* pass input SVG through usvg_ +* iterate depth-first through resulting SVG. + + * for groups: apply transforms and clip and recurse + * for images: Vectorize using selected vectorizer + * for paths: + + * flatten path using Cairo + * remove self-intersections using Clipper + * if stroke is set: process dash, then offset using Clipper + * apply pattern fills + * clip to clip-path + * remove holes using Clipper + +* for KiCAD S-Expression export: vector-composite results using CavalierContours: subtract each clear output primitive + from all previous dark output primitives + +Web interface +------------- + +You can try gerbolyze online at https://dyna.kokoroyukuma.de/gerboweb + +The web interface does not expose all of gerbolyze's bells and whistles, but it allows you to simply paste a single SVG +file on a board to try out gerbolyze. Upload your design on the web interface, then download the template for either the +top or bottom side, and put your artwork on the appropriate layer of that template using Inkscape_. Finally, upload the +modified template and let gerbolyze process your design. + +Command-line usage +------------------ +.. _command_line_usage: + +Generate SVG template from Gerber files: + +.. code-block:: shell + + gerbolyze template [options] [--top|--bottom] input_dir_or.zip output.svg + +Render design from an SVG made with the template above into a set of gerber files: + +.. code-block:: shell + + gerbolyze paste [options] artwork.svg input_dir_or.zip output_dir_or.zip + +Use svg-flatten to convert an SVG file into Gerber or flattened SVG: + +.. code-block:: shell + + svg-flatten [options] --format [gerber|svg] [input_file.svg] [output_file] + +Use svg-flatten to convert an SVG file into the given layer of a KiCAD S-Expression (``.kicad_mod``) file: + +.. code-block:: shell + + svg-flatten [options] --format kicad --sexp-layer F.SilkS --sexp-mod-name My_Module [input_file.svg] [output_file] + +Use svg-flatten to convert an SVG file into a ``.kicad_mod`` with SVG layers fed into separate KiCAD layers based on +their IDs like the popular ``svg2mod`` is doing: + +Note: + Right now, the input SVG's layers must have *ids* that match up KiCAD's s-exp layer names. Note that when you name + a layer in Inkscape that only sets a ``name`` attribute, but does not change the ID. In order to change the ID in + Inkscape, you have to use Inkscape's "object properties" context menu function. + + Also note that svg-flatten expects the layer names KiCAD uses in their S-Expression format. These are *different* to + the layer names KiCAD exposes in the UI (even though most of them match up!). + + For your convenience, there is an SVG template with all the right layer names and IDs located next to this README. + +.. code-block:: shell + + svg-flatten [options] --format kicad --sexp-mod-name My_Module [input_file.svg] [output_file] + +``gerbolyze template`` +~~~~~~~~~~~~~~~~~~~~~~ + +Usage: ``gerbolyze template [OPTIONS] INPUT`` + +Generate SVG template for gerbolyze paste from gerber files. + +INPUT may be a gerber file, directory of gerber files or zip file with gerber files. The output file contains a preview +image of the input gerbers to allow you to position your artwork, as well as prepared Inkscape layers corresponding to +each gerber layer. Simply place your artwork in this SVG template using Inkscape. Starting in v3.0, gerbolyze +automatically keeps track of which board side (top or bottom) is contained in an SVG template. + +Options: +******** +``--top | --bottom`` + Output top or bottom side template. This affects both the preview image and the prepared Inkscape layers. + +``--vector | --raster`` + Embed preview renders into output file as SVG vector graphics instead of rendering them to PNG bitmaps. The + resulting preview may slow down your SVG editor. + +``--raster-dpi FLOAT`` + DPI for rastering preview + +``--bbox TEXT`` + Output file bounding box. Format: "w,h" to force [w] mm by [h] mm output canvas OR "x,y,w,h" to force [w] mm by [h] + mm output canvas with its bottom left corner at the given input gerber coördinates. + + +``gerbolyze paste`` +~~~~~~~~~~~~~~~~~~~ +(see `below `__) + +Usage: ``gerbolyze paste [OPTIONS] INPUT_GERBERS OVERLAY_SVG OUTPUT_GERBERS`` + +Render vector data and raster images from SVG file into gerbers. The SVG input file can be generated using ``gerbolyze +template`` and contains the name and board side of each layer. Note that for board outline layers, handling slightly +differs from other layers as PCB fabs do not support filled Gerber regions on these layers. + +Options: +******** + +``--bbox TEXT`` + Output file bounding box. Format: "w,h" to force [w] mm by [h] mm output canvas OR "x,y,w,h" to force [w] mm by [h] + mm output canvas with its bottom left corner at the given input gerber coördinates. This **must match the ``--bbox`` value given to + template**! + +``--subtract TEXT`` + Use user subtraction script from argument (see `below `_) + +``--no-subtract`` + Disable subtraction (see `below `_) + +``--dilate FLOAT`` + Default dilation for subtraction operations in mm (see `below `_) + +``--trace-space FLOAT`` + Passed through to svg-flatten, see `below `__. + +``--vectorizer TEXT`` + Passed through to svg-flatten, see `its description below `__. Also have a look at `the examples below `_. + +``--vectorizer-map TEXT`` + Passed through to svg-flatten, see `below `__. + +``--exclude-groups TEXT`` + Passed through to svg-flatten, see `below `__. + + +.. _outline_layers: + +Outline layers +************** + +Outline layers require special handling since PCB fabs do not support filled G36/G37 polygons on these layers. The main +difference between normal layers and outline layers is how strokes are handled. On outline layers, strokes are +translated to normal Gerber draw commands (D01, D02 etc.) with an aperture set to the stroke's width instead of tracing +them to G36/G37 filled regions. This means that on outline layers, SVG end caps and line join types do not work: All +lines are redered with round joins and end caps. + +One exception from this are patterns, which work as expected for both fills and strokes with full support for joins and +end caps. + +Dashed strokes are supported on outline layers and can be used to make easy mouse bites. + +.. _subtraction_script: + +Subtraction scripts +******************* + +.. image:: pics/subtract_example.png + :width: 800px + +Subtraction scripts tell ``gerbolyze paste`` to remove an area around certain input layers to from an overlay layer. +When a input layer is given in the subtraction script, gerbolyze will dilate (extend outwards) everything on this input +layer and remove it from the target overlay layer. By default, Gerbolyze subtracts the mask layer from the silk layer to +make sure there are no silk primitives that overlap bare copper, and subtracts each input layer from its corresponding +overlay to make sure the two do not overlap. In the picture above you can see both at work: The overlay contains +halftone primitives all over the place. The subtraction script has cut out an area around all pads (mask layer) and all +existing silkscreen. You can turn off this behavior by passing ``--no-subtract`` or pass your own "script". + +The syntax of these scripts is: + +.. code-block:: + + {target layer} -= {source layer} {dilation} [; ...] + +The target layer must be ``out.{layer name}`` and the source layer ``in.{layer name}``. The layer names are gerbolyze's +internal layer names, i.e.: ``paste, silk, mask, copper, outline, drill`` + +The dilation value is optional, but can be a float with a leading ``+`` or ``-``. If given, before subtraction the +source layer's features will be extended by that many mm. If not given, the dilation defaults to the value given by +``--dilate`` if given or 0.1 mm otherwise. To disable dilation, simply pass ``+0`` here. + +Multiple commands can be separated by semicolons ``;`` or line breaks. + +The default subtraction script is: + +.. code-block:: + + out.silk -= in.mask + out.silk -= in.silk+0.5 + out.mask -= in.mask+0.5 + out.copper -= in.copper+0.5 + +.. _svg_flatten: + +``svg-flatten`` +~~~~~~~~~~~~~~~ + +Usage: ``svg-flatten [OPTIONS]... [INPUT_FILE] [OUTPUT_FILE]`` + +Specify ``-`` for stdin/stdout. + +Options: +******** + +``-h, --help`` + Print help and exit + +``-v, --version`` + Print version and exit + +``-o, --format`` + Output format. Supported: gerber, gerber-outline (for board outline layers), svg, s-exp (KiCAD S-Expression) + +``-p, --precision`` + Number of decimal places use for exported coordinates (gerber: 1-9, SVG: >=0). Note that not all gerber viewers are + happy with too many digits. 5 or 6 is a reasonable choice. + +``--clear-color`` + SVG color to use in SVG output for "clear" areas (default: white) + +``--dark-color`` + SVG color to use in SVG output for "dark" areas (default: black) + +``-f, --flip-gerber-polarity`` + Flip polarity of all output gerber primitives for --format gerber. + +``-d, --trace-space`` + Minimum feature size of elements in vectorized graphics (trace/space) in mm. Default: 0.1mm. + +``--no-header`` + Do not export output format header/footer, only export the primitives themselves + +``--flatten`` + Flatten output so it only consists of non-overlapping white polygons. This perform composition at the vector level. + Potentially slow. This defaults to on when using KiCAD S-Exp export because KiCAD does not know polarity or colors. + +``--no-flatten`` + Disable automatic flattening for KiCAD S-Exp export + +``--dilate`` + Dilate output gerber primitives by this amount in mm. Used for masking out other layers. + +``-g, --only-groups`` + Comma-separated list of group IDs to export. + +``-b, --vectorizer`` + Vectorizer to use for bitmap images. One of poisson-disc (default), hex-grid, square-grid, binary-contours, + dev-null. Have a look at `the examples below `_. + +``--vectorizer-map`` + Map from image element id to vectorizer. Overrides --vectorizer. Format: id1=vectorizer,id2=vectorizer,... + + You can use this to set a certain vectorizer for specific images, e.g. if you want to use both halftone + vectorization and contour tracing in the same SVG. Note that you can set an ```` element's SVG ID from within + Inkscape though the context menu's Object Properties tool. + +``--force-svg`` + Force SVG input irrespective of file name + +``--force-png`` + Force bitmap graphics input irrespective of file name + +``-s, --size`` + Bitmap mode only: Physical size of output image in mm. Format: 12.34x56.78 + +``--sexp-mod-name`` + Module name for KiCAD S-Exp output. This is a mandatory argument if using S-Exp output. + +``--sexp-layer`` + Layer for KiCAD S-Exp output. Defaults to auto-detect layers from SVG layer/top-level group IDs. If given, SVG + groups and layers are completely ignored and everything is simply vectorized into this layer, though you cna still + use ``-g`` for group selection. + +``-a, --preserve-aspect-ratio`` + Bitmap mode only: Preserve aspect ratio of image. Allowed values are meet, slice. Can also parse full SVG + preserveAspectRatio syntax. + +``--no-usvg`` + Do not preprocess input using usvg (do not use unless you know *exactly* what you're doing) + +``--usvg-dpi`` + Passed through to usvg's --dpi, in case the input file has different ideas of DPI than usvg has. + +``--scale`` + Scale input svg lengths by this factor (-o gerber only). + +``-e, --exclude-groups`` + Comma-separated list of group IDs to exclude from export. Takes precedence over --only-groups. + +.. _vectorization: + +Gerbolyze image vectorization +----------------------------- + +Gerbolyze has two built-in strategies to translate pixel images into vector images. One is its built-in halftone +processor that tries to approximate grayscale. The other is its built-in binary vectorizer that traces contours in +black-and-white images. Below are examples for the four options. + +The vectorizers can be used in isolation through ``svg-flatten`` with either an SVG input that contains an image or a +PNG/JPG input. + +The vectorizer can be controlled globally using the ``--vectorizer`` flag in both ``gerbolyze`` and ``svg-flatten``. It +can also be set on a per-image basis in both using ``--vectorizer-map [image svg id]=[option]["," ...]``. + +.. for f in vec_*.png; convert -background white -gravity center $f -resize 500x500 -extent 500x500 (basename -s .png $f)-square.png; end +.. for vec in hexgrid square poisson contours; convert vec_"$vec"_whole-square.png vec_"$vec"_detail-square.png -background transparent -splice 25x0+0+0 +append -chop 25x0+0+0 vec_"$vec"_composited.png; end + +``--vectorizer poisson-disc`` (the default) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: pics/vec_poisson_composited.png + :width: 800px + +``--vectorizer hex-grid`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: pics/vec_hexgrid_composited.png + :width: 800px + +``--vectorizer square-grid`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: pics/vec_square_composited.png + :width: 800px + +``--vectorizer binary-contours`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: pics/vec_contours_composited.png + :width: 800px + +The binary contours vectorizer requires a black-and-white binary input image. As you can see, like every bitmap tracer +it will produce some artifacts. For artistic input this is usually not too bad as long as the input data is +high-resolution. Antialiased edges in the input image are not only OK, they may even help with an accurate +vectorization. + +GIMP halftone preprocessing guide +--------------------------------- + +Gerbolyze has its own built-in halftone processor, but you can also use the high-quality "newsprint" filter built into +GIMP_ instead if you like. This section will guide you through this. The PNG you get out of this can then be fed into +gerbolyze using ``--vectorizer binary-contours``. + +1 Import your desired artwork +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Though anime or manga pictures are highly recommended, you can use any image including photographs. Be careful to select +a picture with comparatively low detail that remains recognizable at very low resolution. While working on a screen this +is hard to vizualize, but the grain resulting from the low resolution of a PCB's silkscreen is quite coarse. + +.. image:: screenshots/02import02.png + :width: 800px + +2 Convert the image to grayscale +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: screenshots/06grayscale.png + :width: 800px + +3 Fine-tune the image's contrast +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To look well on the PCB, contrast is critical. If your source image is in color, you may have lost some contrast during +grayscale conversion. Now is the time to retouch that using the GIMP's color curve tool. + +When using the GIMP's newsprint filter, bright grays close to white and dark grays close to black will cause very small +dots that might be beyond your PCB manufacturer's maximum resolution. To control this case, add small steps at the ends +of the grayscale value curve as shown (exaggerated) in the picture below. These steps saturate very bright grays to +white and very dark grays to black while preserving the values in the middle. + +.. image:: screenshots/08curve_cut.png + :width: 800px + +4 Retouch details +~~~~~~~~~~~~~~~~~ + +Therer might be small details that don't look right yet, such as the image's background color or small highlights that +merge into the background now. You can manually change the color of any detail now using the GIMP's flood-fill tool. + +If you don't want the image's background to show up on the final PCB at all, just make it black. + +Particularly on low-resolution source images it may make sense to apply a blur with a radius similar to the following +newsprint filter's cell size (10px) to smooth out the dot pattern generated by the newsprint filter. + +.. image:: screenshots/09retouch.png + :width: 800px + +In the following example, I retouched the highlights in the hair of the character in the picture to make them completely +white instead of light-gray, so they still stand out nicely in the finished picture. + +.. image:: screenshots/10retouched.png + :width: 800px + +5 Run the newsprint filter +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now, run the GIMP's newsprint filter, under filters, distorts, newsprint. + +The first important settings is the spot size, which should be larger than your PCB's minimum detail size (about 10px +with ``gerbolyze render`` default settings for good-quality silkscreen). In general the cheap and fast standard option of chinese PCB houses will require a larger detail size, but when you order specialty options like large size, 4-layer or non-green color along with a longer turnaround time you'll get much better-quality silk screen. + +The second important setting is oversampling, which should be set to four or slightly higher. This improves the result +of the edge reconstruction of ``gerbolyze vectorize``. + +.. image:: screenshots/11newsprint.png + :width: 800px + +The following are examples on the detail resulting from the newsprint filter. + +.. image:: screenshots/12newsprint.png + :width: 800px + +6 Export the image for use with ``gerbolyze vectorize`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Simply export the image as a PNG file. Below are some pictures of the output ``gerbolyze vectorize`` produced for this +example. + +.. image:: screenshots/14result_cut.png + :width: 800px + +.. image:: screenshots/15result_cut.png + :width: 800px + +Manufacturing Considerations +---------------------------- + +The main consideration when designing artwork for PCB processes is the processes' trace/space design rule. The two +things you can do here is one, to be creative with graphical parts of the design and avoid extremely narrow lines, +wedges or other thin features that will not come out well. Number two is to keep detail in raster images several times +larger than the manufacturing processes native capability. For example, to target a trace/space design rule of 100 µm, +the smallest detail in embedded raster graphics should not be much below 1mm. + +Gerbolyze's halftone vectorizers have built-in support for trace/space design rules. While they can still produce small +artifacts that violate these rules, their output should be close enough to satifsy board houses and close enough for the +result to look good. The way gerbolyze does this is to clip the halftone cell's values to zero whenevery they get too +small, and to forcefully split or merge two neighboring cells when they get too close. While this process introduces +slight steps at the top and bottom of grayscale response, for most inputs these are not noticeable. + +On the other hand, for SVG vector elements as well as for traced raster images, Gerbolyze cannot help with these design +rules. There is no heuristic that would allow Gerbolyze to non-destructively "fix" a design here, so all that's on the +roadmap here is to eventually include a gerber-level design rule checker. + +As far as board houses go, I have made good experiences with the popular Chinese board houses. In my experience, JLC +will just produce whatever you send them with little fucks being given about design rule adherence or validity of the +input gerbers. This is great if you just want artistic circuit boards without much of a hassle, and you don't care if +they come out exactly as you imagined. The worst I've had happen was when an older version of gerbolyze generated +polygons with holes assuming standard fill-rule processing. The in the board house's online gerber viewer things looked +fine, and neither did they complain during file review. However, the resulting boards looked completely wrong because +all the dark halftones were missing. + +PCBWay on the other hand has a much more rigurous file review process. They will complain when you throw +illegal garbage gerbers at them, and they will helpfully guide you through your design rule violations. In this way you +get much more of a professional service from them and for designs that have to be functional their higher level of +scrutiny definitely is a good thing. For the design you saw in the first picture in this article, I ended up begging +them to just plot my files if it doesn't physically break their machines and to their credit, while they seemed unhappy +about it they did it and the result looks absolutely stunning. + +PCBWay is a bit more expensive on their lowest-end offering than JLC, but I found that for anything else (large boards, +multi-layer, gold plating etc.) their prices match. PCBWay offers a much broader range of manufacturing options such as +flexible circuit boards, multi-layer boards, thick or thin substrates and high-temperature substrates. + +When in doubt about how your design is going to come out on the board, do not hesitate to contact your board house. Most +of the end customer-facing online PCB services have a number of different factories that do a number of different +fabrication processes for them depending on order parameters. Places like PCBWay have exceptional quality control and +good customer service, but that is mostly focused on the technical aspects of the PCB. If you rely on visual aspects +like silkscreen uniformity or solder mask color that is a strong no concern to everyone else in the electronics +industry, you may find significant variations between manufacturers or even between orders with the same manufacturer +and you may encounter challenges communicating your requirements. + +Limitations +----------- + +SVG raster features +~~~~~~~~~~~~~~~~~~~ + +Currently, SVG masks and filters are not supported. Though SVG is marketed as a "vector graphics format", these two +features are really raster primitives that all SVG viewers perform at the pixel level after rasterization. Since +supporting these would likely not end up looking like what you want, it is not a planned feature. If you need masks or +filters, simply export the relevant parts of the SVG as a PNG then include that in your template. + +Gerber pass-through +~~~~~~~~~~~~~~~~~~~ + +Since gerbolyze has to composite your input gerbers with its own output, it has to fully parse and re-serialize them. +gerbolyze gerbonara_ for all its gerber parsing needs. Thus, gerbonara will interpret your gerbers and output will be in +gerbonara's gerber "dialect". If you find a corner case where this does not work and the output looks wrong, please file +a bug report with an example file on the gerbonara_ bug tracker. *Always* check the output files for errors before +submitting them to production. + +Gerbolyze is provided without any warranty, but still please open an issue or `send me an email +`__ if you find any errors or inconsistencies. + +Trace/Space design rule adherence +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +While the grayscale halftone vectorizers do a reasonable job adhering to a given trace/space design rule, they can still +produce small parts of output that violate it. For the contour vectorizer as well as for all SVG primitives, you are +responsible for adhering to design rules yourself as there is no algorithm that gerboyze could use to "fix" its input. + +A design rule checker is planned as a future addition to gerbolyze, but is not yet part of it. If in doubt, talk to your +fab and consider doing a test run of your design before ordering assembled boards ;) + +Gallery +------- + +.. image:: pics/sample3.jpg + :width: 400px + +For a demonstration of ``gerbolyze convert``, check out the `Gerbolyze Protoboard Index`_, where you can download gerber +files for over 7.000 SMD and THT protoboard layouts. + +Licensing +--------- + +This tool is licensed under the rather radical AGPLv3 license. Briefly, this means that you have to provide users of a +webapp using this tool in the backend with this tool's source. + +I get that some people have issues with the AGPL. In case this license prevents you from using this software, please +send me `an email `__ and I can grant you an exception. I want this software to be useful to as +many people as possible and I wouldn't want the license to be a hurdle to anyone. OTOH I see a danger of some cheap +board house just integrating a fork into their webpage without providing their changes back upstream, and I want to +avoid that so the default license is still AGPL. + +.. _usvg: https://github.com/RazrFalcon/resvg +.. _Inkscape: https://inkscape.org/ +.. _pcb-tools: https://github.com/curtacircuitos/pcb-tools +.. _pcb-tools-extension: https://github.com/opiopan/pcb-tools-extension +.. _GIMP: https://gimp.org/ +.. _gerbonara: https://gitlab.com/gerbolyze/gerbonara +.. _`Gerbolyze Protoboard Index`: https://dyna.kokoroyukuma.de/protos/ + diff --git a/content/projects/gerbolyze/index.rst b/content/projects/gerbolyze/index.rst new file mode 100644 index 0000000..47022ee --- /dev/null +++ b/content/projects/gerbolyze/index.rst @@ -0,0 +1,17 @@ +--- +title: "Gerbolyze" +external_links: + - name: Sources + url: "https://git.jaseg.de/gerbolyze.git" + - name: Issues + url: "https://github.com/jaseg/gerbolyze/issues" + - name: Docs + url: "https://gerbolyze.gitlab.io/gerbolyze" + - name: PyPI + url: "https://pypi.org/projects/gerbolyze" +summary: > + Gerbolyze is a tool that allows the modification of Gerber PCB artwork with a vector graphics editor like Inkscape. + Gerbolyze directly converts between SVG and Gerber, and accurately reproduces details that other tools can not. +--- + +.. include:: content/projects/gerbolyze/README.rst diff --git a/content/projects/gerbolyze/pics/ex-flattening.png b/content/projects/gerbolyze/pics/ex-flattening.png new file mode 100644 index 0000000..e702733 Binary files /dev/null and b/content/projects/gerbolyze/pics/ex-flattening.png differ diff --git a/content/projects/gerbolyze/pics/ex-intersections.png b/content/projects/gerbolyze/pics/ex-intersections.png new file mode 100644 index 0000000..05ccc59 Binary files /dev/null and b/content/projects/gerbolyze/pics/ex-intersections.png differ diff --git a/content/projects/gerbolyze/pics/ex-strokes.png b/content/projects/gerbolyze/pics/ex-strokes.png new file mode 100644 index 0000000..5ef3c49 Binary files /dev/null and b/content/projects/gerbolyze/pics/ex-strokes.png differ diff --git a/content/projects/gerbolyze/pics/ex-svg-joins.png b/content/projects/gerbolyze/pics/ex-svg-joins.png new file mode 100644 index 0000000..534e4c2 Binary files /dev/null and b/content/projects/gerbolyze/pics/ex-svg-joins.png differ diff --git a/content/projects/gerbolyze/pics/ex-svg-strokes.png b/content/projects/gerbolyze/pics/ex-svg-strokes.png new file mode 100644 index 0000000..bec71c0 Binary files /dev/null and b/content/projects/gerbolyze/pics/ex-svg-strokes.png differ diff --git a/content/projects/gerbolyze/pics/ex-svg-winding.png b/content/projects/gerbolyze/pics/ex-svg-winding.png new file mode 100644 index 0000000..3f85f6f Binary files /dev/null and b/content/projects/gerbolyze/pics/ex-svg-winding.png differ diff --git a/content/projects/gerbolyze/pics/fr4_comparison2.jpg b/content/projects/gerbolyze/pics/fr4_comparison2.jpg new file mode 100644 index 0000000..fa7c92e Binary files /dev/null and b/content/projects/gerbolyze/pics/fr4_comparison2.jpg differ diff --git a/content/projects/gerbolyze/pics/pcbway_sample_01_small.jpg b/content/projects/gerbolyze/pics/pcbway_sample_01_small.jpg new file mode 100644 index 0000000..f8d6397 Binary files /dev/null and b/content/projects/gerbolyze/pics/pcbway_sample_01_small.jpg differ diff --git a/content/projects/gerbolyze/pics/pcbway_sample_02_small.jpg b/content/projects/gerbolyze/pics/pcbway_sample_02_small.jpg new file mode 100644 index 0000000..ba8e984 Binary files /dev/null and b/content/projects/gerbolyze/pics/pcbway_sample_02_small.jpg differ diff --git a/content/projects/gerbolyze/pics/pcbway_sample_03_small.jpg b/content/projects/gerbolyze/pics/pcbway_sample_03_small.jpg new file mode 100644 index 0000000..1336739 Binary files /dev/null and b/content/projects/gerbolyze/pics/pcbway_sample_03_small.jpg differ diff --git a/content/projects/gerbolyze/pics/process-overview.png b/content/projects/gerbolyze/pics/process-overview.png new file mode 100644 index 0000000..01d3811 Binary files /dev/null and b/content/projects/gerbolyze/pics/process-overview.png differ diff --git a/content/projects/gerbolyze/pics/process-overview.svg b/content/projects/gerbolyze/pics/process-overview.svg new file mode 100644 index 0000000..b21aa70 --- /dev/null +++ b/content/projects/gerbolyze/pics/process-overview.svg @@ -0,0 +1,7230 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + KiCAD/Altium + SVG + Gerber! + + + + + + + + + + + + diff --git a/content/projects/gerbolyze/pics/sample1.jpg b/content/projects/gerbolyze/pics/sample1.jpg new file mode 100644 index 0000000..948da6f Binary files /dev/null and b/content/projects/gerbolyze/pics/sample1.jpg differ diff --git a/content/projects/gerbolyze/pics/sample2.jpg b/content/projects/gerbolyze/pics/sample2.jpg new file mode 100644 index 0000000..ef47bd4 Binary files /dev/null and b/content/projects/gerbolyze/pics/sample2.jpg differ diff --git a/content/projects/gerbolyze/pics/sample3.jpg b/content/projects/gerbolyze/pics/sample3.jpg new file mode 100644 index 0000000..780c080 Binary files /dev/null and b/content/projects/gerbolyze/pics/sample3.jpg differ diff --git a/content/projects/gerbolyze/pics/subtract_example.png b/content/projects/gerbolyze/pics/subtract_example.png new file mode 100644 index 0000000..f8e138a Binary files /dev/null and b/content/projects/gerbolyze/pics/subtract_example.png differ diff --git a/content/projects/gerbolyze/pics/test_svg_readme.svg b/content/projects/gerbolyze/pics/test_svg_readme.svg new file mode 100644 index 0000000..1a0178e --- /dev/null +++ b/content/projects/gerbolyze/pics/test_svg_readme.svg @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + सर्वे मानवाः स्वतन्त्राः समुत्पन्नाः वर्तन्ते अपि च, गौरवदृशा + + + + + لكن لا بد أن أوضح لك أن كل هذه الأفكار المغلوطة حول استنكار + + This is a gerber export test + + diff --git a/content/projects/gerbolyze/pics/test_svg_readme_composited.png b/content/projects/gerbolyze/pics/test_svg_readme_composited.png new file mode 100644 index 0000000..f686e19 Binary files /dev/null and b/content/projects/gerbolyze/pics/test_svg_readme_composited.png differ diff --git a/content/projects/gerbolyze/pics/vec_contours_composited.png b/content/projects/gerbolyze/pics/vec_contours_composited.png new file mode 100644 index 0000000..aa826f8 Binary files /dev/null and b/content/projects/gerbolyze/pics/vec_contours_composited.png differ diff --git a/content/projects/gerbolyze/pics/vec_hexgrid_composited.png b/content/projects/gerbolyze/pics/vec_hexgrid_composited.png new file mode 100644 index 0000000..9578260 Binary files /dev/null and b/content/projects/gerbolyze/pics/vec_hexgrid_composited.png differ diff --git a/content/projects/gerbolyze/pics/vec_poisson_composited.png b/content/projects/gerbolyze/pics/vec_poisson_composited.png new file mode 100644 index 0000000..e3ac758 Binary files /dev/null and b/content/projects/gerbolyze/pics/vec_poisson_composited.png differ diff --git a/content/projects/gerbolyze/pics/vec_square_composited.png b/content/projects/gerbolyze/pics/vec_square_composited.png new file mode 100644 index 0000000..02a89ea Binary files /dev/null and b/content/projects/gerbolyze/pics/vec_square_composited.png differ diff --git a/content/projects/gerbonara/index.rst b/content/projects/gerbonara/index.rst new file mode 100644 index 0000000..be28fb4 --- /dev/null +++ b/content/projects/gerbonara/index.rst @@ -0,0 +1,141 @@ +--- +title: "Gerbonara" +external_links: + - name: Sources + url: "https://git.jaseg.de/gerbonara.git" + - name: Issues + url: "https://gitlab.com/gerbolyze/gerbonara/issues" + - name: Docs + url: "https://gerbolyze.gitlab.io/gerbonara" + - name: PyPI + url: "https://pypi.org/projects/gerbonara" +summary: > + Gerbonara is a user-friendly, powerful tool for reading, writing, modification and rendering of Gerber PCB artwork + from the command line or from Python code. Gerbonara supports the Gerber dialects of all industry-standard EDA + tools. +--- + +Gerbonara is a library to read, modify and write PCB manufacturing files such as Gerber, Excellon and IPC-356 through a +pythonic API. Gerbonara can open a folder of manufacturing files, and parse file names and metadata to figure out which +file contains what. Gerbonara is tested using an extensive library of real-world example files from CAD tools including +KiCAD, Altium, Eagle, Allegro, gEDA, Fritzing, Siemens/Mentor Graphics PADS, and Target3001!. + +Gerbonara's API is built on two principles: + +**Meaningful, object-oriented API** + Gerbonara abstracts away the details of the underlying file format such as tool indices, coordinate notation and + graphical state, and presents meaningful "graphical objects" such as a `primitives.Line`, + `primitives.Arc`, or `Region` through its API. These objects can be easily created, + manipulated or deleted from code without breaking anything else. You can even copy graphical objects between files, + and Gerbonara will automatically convert coordinate format, units etc. for you. `GerberFile` and + `ExcellonFile` use the same types of `graphic objects `, so objects can be directly + copied between file types without conversion. + +**Unit-safety** + Gerbonara embeds physical `LengthUnit` information in all objects. The high-level API such as + `LayerStack.merge` or `GerberFile.offset` accepts arguments with an explicitly given unit and + automatically converts them as needed. Objects can be copied between `GerberFile` instances and unit + conversion will be handled transparently in the background. + +Gerbonara was started as an extensive refactoring of the pcb-tools_ and pcb-tools-extension_ packages. Both of these +have statement-based APIs, that is, they parse input files into one python object for every line in the file. This means +that when saving files they can recreate the input file almost byte by byte, but manipulating a file by changing +statements without breaking things is *hard*. + +Gerbonara powers gerbolyze_, a tool for converting SVG_ vector graphics files into Gerber, and embedding SVG_ into +existing Gerber files exported from a normal PCB tool for artistic purposes. + +Features +======== + + * File I/O + * Gerber, Excellon (drill file), IPC-356 (netlist) read and write + * supports file-level operations: offset, rotate, merge for all file types + * Modification API (`GraphicObject`) + * Rendering API (`GraphicPrimitive`) + * SVG export + * Full aperture macro support, including transformations (offset, rotation) + +Quick Start +=========== + +First, install gerbonara from PyPI using pip: + +.. code-block:: shell + + pip install --user gerbonara + +Then, you are ready to read and write gerber files: + +.. code-block:: python + + from gerbonara import LayerStack + + stack = LayerStack.from_directory('output/gerber') + w, h = stack.outline.size('mm') + print(f'Board size is {w:.1f} mm x {h:.1f} mm') + +Command-Line Interface +====================== + +Gerbonara comes with a `built-in command-line interface` that has functions for analyzing, rendering, +modifying, and merging Gerber files. To access it, use either the ``gerbonara`` command that is part of the python +package, or run ``python -m gerbonara`` For a list of functions or help on their usage, you can use: + +.. code:: console + + $ python -m gerbonara --help + [...] + $ python -m gerbonara render --help + +Development +=========== + +Gerbonara is developed on Gitlab under the gerbolyze org: + +https://gitlab.com/gerbolyze/gerbonara/ + +A mirror of the repository can be found at: + +https://git.jaseg.de/gerbonara + +Our issue tracker is also on Gitlab: + +https://gitlab.com/gerbolyze/gerbonara/-/issues + +The documentation can be found at gitlab: + +https://gerbolyze.gitlab.io/gerbonara/ + +With Gerbonara, we aim to support as many different format variants as possible. If you have a file that Gerbonara can't +open, please file an issue on our issue tracker. Even if Gerbonara can open all your files, for regression testing we +are very interested in example files generated by any CAD or CAM tool that is not already on the list of supported +tools. + +Supported CAD Tools +=================== + +Compatibility with the output of these CAD tools is tested as part of our test suite using example files generated by +these tools. Note that not all of these tools come with default Gerber file naming rules, so YMMV if your Gerbers use +some non-standard naming convention. + + * Allegro + * Altium + * Diptrace + * Eagle + * EasyEDA + * Fritzing + * gEDA + * KiCAD + * pcb-rnd + * Siemens / Mentor Graphics Xpedition + * Siemens PADS + * Target 3001! + * Upverter + * Zuken CR-8000 + +.. _pcb-tools: https://github.com/opiopan/pcb-tools-extension +.. _pcb-tools-extension: https://github.com/curtacircuitos/pcb-tools/issues +.. _gerbolyze: https://github.com/jaseg/gerbolyze +.. _SVG: https://en.wikipedia.org/wiki/Scalable_Vector_Graphics + diff --git a/content/projects/lolcat-c/LOLCat-Rainbow.jpg b/content/projects/lolcat-c/LOLCat-Rainbow.jpg new file mode 100644 index 0000000..9524d26 Binary files /dev/null and b/content/projects/lolcat-c/LOLCat-Rainbow.jpg differ diff --git a/content/projects/lolcat-c/index.rst b/content/projects/lolcat-c/index.rst new file mode 100644 index 0000000..6217b34 --- /dev/null +++ b/content/projects/lolcat-c/index.rst @@ -0,0 +1,105 @@ +--- +title: "lolcat-c" +external_links: + - name: Sources + url: "https://git.jaseg.de/lolcat.git" + - name: Issues + url: "https://github.com/jaseg/lolcat/issues" +summary: > + lolcat-c is a small, high-performance re-implementation of the + `lolcat `__ + rainbow cat utility. lolcat-c is meant as a lolcat that you can actually use in production. It is fast, not slowing + down whatever you pipe through it, and it robustly handles real-world terminal output including escape sequences. +--- + +What? +===== + +.. image:: LOLCat-Rainbow.jpg + +Screenshot +========== + +.. image:: screenshot.png + +.. image:: sl.gif + +Installation +============ + +Archlinux +--------- + +There's an `AUR package `__: + +.. code:: sh + + $ git clone https://aur.archlinux.org/packages/c-lolcat + $ cd c-lolcat + $ makepkg -csi + +Fedora +------ + +.. code:: sh + + $ dnf install lolcat + +Ubuntu (Snap) +------------- + +See `this awesome blog post by a kind person from the internet `__: + +.. code:: sh + + $ snap install lolcat-c + +Mac +--- + +Build loclcat with: + +.. code:: sh + + $ make lolcat + +...and put the resulting binary at a place of your choice. + +Others +------ + +.. code:: sh + + $ make && sudo make install + +Why? +==== + +This `lolcat` clone is an attempt to reduce the world's carbon dioxide emissions by optimizing inefficient code. It's +>10x as fast and <0.1% as large as the original one. + +.. code:: sh + + newton~/d/lolcat <3 dmesg>foo + newton~/d/lolcat <3 time upstream/bin/lolcat foo + 13.51user 1.34system 0:15.99elapsed 92%CPU (0avgtext+0avgdata 10864maxresident)k + 0inputs+0outputs (0major+1716minor)pagefaults 0swaps + newton~/d/lolcat <3 time ./lolcat foo + 0.02user 0.00system 0:00.09elapsed 34%CPU (0avgtext+0avgdata 1936maxresident)k + 0inputs+0outputs (0major+117minor)pagefaults 0swaps + +Bonus comparison with `python-lolcat `__: + +.. code:: sh + + newton~/d/lolcat <3 dmesg>foo + $ time python-lolcat foo + 12.27user 0.00system 0:12.29elapsed 99%CPU (0avgtext+0avgdata 11484maxresident)k + 0inputs+0outputs (0major+1627minor)pagefaults 0swaps + $ time c-lolcat foo + 0.29user 0.00system 0:00.30elapsed 98%CPU (0avgtext+0avgdata 468maxresident)k + 0inputs+0outputs (0major+21minor)pagefaults 0swaps + +(Read: `c-lolcat << python-lolcat << ruby-lolcat`) + + diff --git a/content/projects/lolcat-c/screenshot.png b/content/projects/lolcat-c/screenshot.png new file mode 100644 index 0000000..56282af Binary files /dev/null and b/content/projects/lolcat-c/screenshot.png differ diff --git a/content/projects/lolcat-c/sl.gif b/content/projects/lolcat-c/sl.gif new file mode 100644 index 0000000..9d994e8 Binary files /dev/null and b/content/projects/lolcat-c/sl.gif differ diff --git a/content/projects/python-mpv/README.rst b/content/projects/python-mpv/README.rst new file mode 100644 index 0000000..26815d1 --- /dev/null +++ b/content/projects/python-mpv/README.rst @@ -0,0 +1,401 @@ +.. vim: tw=120 sw=4 et + +python-mpv is a ctypes-based python interface to the mpv media player. It gives you more or less full control of all +features of the player, just as the lua interface does. + +Installation +------------ + +.. code:: bash + + pip install mpv + + +...though you can also realistically just copy `mpv.py`_ into your project as it's all nicely contained in one file. + +Requirements +~~~~~~~~~~~~ + +libmpv +...... +``libmpv.so`` either locally (in your current working directory) or somewhere in your system library search path. This +module is somewhat lenient as far as ``libmpv`` versions are concerned but since ``libmpv`` is changing quite frequently +you'll only get all the newest features when using an up-to-date version of this module. The unit tests for this module +do some basic automatic version compatibility checks. If you discover anything missing here, please open an `issue`_ or +submit a `pull request`_ on github. + +On Windows you can place libmpv anywhere in your ``%PATH%`` (e.g. next to ``python.exe``) or next to this module's +``mpv.py``. Before falling back to looking in the mpv module's directory, python-mpv uses the DLL search order built +into ctypes, which is different to the one Windows uses internally. Consult `this stackoverflow post +`__ for details. + +Python >= 3.7 (officially) +.......................... +The ``main`` branch officially only supports recent python releases (3.5 onwards), but there is the somewhat outdated +but functional `py2compat branch`_ providing Python 2 compatibility. + +.. _`py2compat branch`: https://github.com/jaseg/python-mpv/tree/py2compat +.. _`issue`: https://github.com/jaseg/python-mpv/issues +.. _`pull request`: https://github.com/jaseg/python-mpv/pulls + +Supported Platforms +................... + +**Linux**, **Windows** and **OSX** all seem to work mostly fine. For some notes on the installation on Windows see +`this comment`__. Shared library handling is quite bad on windows, so expect some pain there. On OSX there seems to be +some bug int the event logic. See `issue 36`_ and `issue 61`_ for details. Creating a pyQT window and having mpv draw +into it seems to be a workaround (about 10loc), but in case you want this fixed please weigh in on the issue tracker +since right now there is not many OSX users. + +.. __: https://github.com/jaseg/python-mpv/issues/60#issuecomment-352719773 +.. _`issue 61`: https://github.com/jaseg/python-mpv/issues/61 +.. _`issue 36`: https://github.com/jaseg/python-mpv/issues/36 + +Usage +----- + +.. code:: python + + import mpv + player = mpv.MPV(ytdl=True) + player.play('https://youtu.be/DOmdB7D-pUU') + player.wait_for_playback() + +python-mpv mostly exposes mpv's built-in API to python, adding only some porcelain on top. Most "`input commands `_" are mapped to methods of the MPV class. Check out these methods and their docstrings in `the source `__ for things you can do. Additional controls and status information are exposed through `MPV properties `_. These can be accessed like ``player.metadata``, ``player.fullscreen`` and ``player.loop_playlist``. + +Threading +~~~~~~~~~ + +The ``mpv`` module starts one thread for event handling, since MPV sends events that must be processed quickly. The +event queue has a fixed maxmimum size and some operations can cause a large number of events to be sent. + +If you want to handle threading yourself, you can pass ``start_event_thread=False`` to the ``MPV`` constructor and +manually call the ``MPV`` object's ``_loop`` function. If you have some strong need to not use threads and use some +external event loop (such as asyncio) instead you can do that, too with some work. The API of the backend C ``libmpv`` +has a function for producing a sort of event file descriptor for a handle. You can use that to produce a file descriptor +that can be passed to an event loop to tell it to wake up the python-mpv event handler on every incoming event. + +All API functions are thread-safe. If one is not, please file an issue on github. + +Advanced Usage +~~~~~~~~~~~~~~ + +Logging, Properties, Python Key Bindings, Screenshots and youtube-dl +.................................................................... + +.. code:: python + + #!/usr/bin/env python3 + import mpv + + def my_log(loglevel, component, message): + print('[{}] {}: {}'.format(loglevel, component, message)) + + player = mpv.MPV(log_handler=my_log, ytdl=True, input_default_bindings=True, input_vo_keyboard=True) + + # Property access, these can be changed at runtime + @player.property_observer('time-pos') + def time_observer(_name, value): + # Here, _value is either None if nothing is playing or a float containing + # fractional seconds since the beginning of the file. + print('Now playing at {:.2f}s'.format(value)) + + player.fullscreen = True + player.loop_playlist = 'inf' + # Option access, in general these require the core to reinitialize + player['vo'] = 'gpu' + + @player.on_key_press('q') + def my_q_binding(): + print('THERE IS NO ESCAPE') + + @player.on_key_press('s') + def my_s_binding(): + pillow_img = player.screenshot_raw() + pillow_img.save('screenshot.png') + + player.play('https://youtu.be/DLzxrzFCyOs') + player.wait_for_playback() + + del player + +Skipping silence using libav filters +.................................... + +The following code uses the libav silencedetect filter to skip silence at the beginning of a file. It works by loading +the filter, then parsing its output from mpv's log. Thanks to Sean DeNigris on github (#202) for the original code! + +.. code:: python + + #!/usr/bin/env python3 + import sys + import mpv + + p = mpv.MPV() + p.play(sys.argv[1]) + + def skip_silence(): + p.set_loglevel('debug') + p.af = 'lavfi=[silencedetect=n=-20dB:d=1]' + p.speed = 100 + def check(evt): + toks = evt['event']['text'].split() + if 'silence_end:' in toks: + return float(toks[2]) + p.time_pos = p.wait_for_event('log_message', cond=check) + p.speed = 1 + p.af = '' + + skip_silence() + p.wait_for_playback() + +Video overlays +.............. + +.. code:: python + + #!/usr/bin/env python3 + import time + from PIL import Image, ImageDraw, ImageFont + import mpv + + player = mpv.MPV() + + player.loop = True + player.play('test.webm') + player.wait_until_playing() + + font = ImageFont.truetype('DejaVuSans.ttf', 40) + + while not player.core_idle: + + time.sleep(0.5) + overlay = player.create_image_overlay() + + for pos in range(0, 500, 5): + ts = player.time_pos + if ts is None: + break + + img = Image.new('RGBA', (400, 150), (255, 255, 255, 0)) + d = ImageDraw.Draw(img) + d.text((10, 10), 'Hello World', font=font, fill=(0, 255, 255, 128)) + d.text((10, 60), f't={ts:.3f}', font=font, fill=(255, 0, 255, 255)) + + overlay.update(img, pos=(2*pos, pos)) + time.sleep(0.05) + + overlay.remove() + + +Playlist handling +................. + +.. code:: python + + #!/usr/bin/env python3 + import mpv + + player = mpv.MPV(ytdl=True, input_default_bindings=True, input_vo_keyboard=True) + + player.playlist_append('https://youtu.be/PHIGke6Yzh8') + player.playlist_append('https://youtu.be/Ji9qSuQapFY') + player.playlist_append('https://youtu.be/6f78_Tf4Tdk') + + player.playlist_pos = 0 + + while True: + # To modify the playlist, use player.playlist_{append,clear,move,remove}. player.playlist is read-only + print(player.playlist) + player.wait_for_playback() + +Directly feeding mpv data from python +..................................... + +.. code:: python + + #!/usr/bin/env python3 + import mpv + + player = mpv.MPV() + @player.python_stream('foo') + def reader(): + with open('test.webm', 'rb') as f: + while True: + yield f.read(1024*1024) + + player.play('python://foo') + player.wait_for_playback() + +Using external subtitles +........................ + +The easiest way to load custom subtitles from a file is to pass the ``--sub-file`` option to the ``loadfile`` call: + +.. code:: python + + #!/usr/bin/env python3 + import mpv + + player = mpv.MPV() + player.loadfile('test.webm', sub_file='test.srt') + player.wait_for_playback() + +Note that you can also pass many other options to ``loadfile``. See the mpv docs for details. + +If you want to add subtitle files or streams at runtime, you can use the ``sub-add`` command. ``sub-add`` can only be +called once the player is done loading the file and starts playing. An easy way to wait for this is to wait for the +``core-idle`` property. + +.. code:: python + + #!/usr/bin/env python3 + import mpv + + player = mpv.MPV() + player.play('test.webm') + player.wait_until_playing() + player.sub_add('test.srt') + player.wait_for_playback() + +Using MPV's built-in GUI +........................ + +python-mpv is using mpv via libmpv. libmpv is meant for embedding into other applications and by default disables most +GUI features such as the OSD or keyboard input. To enable the built-in GUI, use the following options when initializing +the MPV instance. See `Issue 102`_ for more details + +.. _`issue 102`: https://github.com/jaseg/python-mpv/issues/61 + +.. code:: python + + # Enable the on-screen controller and keyboard shortcuts + player = mpv.MPV(input_default_bindings=True, input_vo_keyboard=True, osc=True) + + # Alternative version using the old "floating box" style on-screen controller + player = mpv.MPV(player_operation_mode='pseudo-gui', + script_opts='osc-layout=box,osc-seekbarstyle=bar,osc-deadzonesize=0,osc-minmousemove=3', + input_default_bindings=True, + input_vo_keyboard=True, + osc=True) + +PyQT embedding +.............. + +.. code:: python + + #!/usr/bin/env python3 + import mpv + import sys + + from PyQt5.QtWidgets import * + from PyQt5.QtCore import * + + class Test(QMainWindow): + def __init__(self, parent=None): + super().__init__(parent) + self.container = QWidget(self) + self.setCentralWidget(self.container) + self.container.setAttribute(Qt.WA_DontCreateNativeAncestors) + self.container.setAttribute(Qt.WA_NativeWindow) + player = mpv.MPV(wid=str(int(self.container.winId())), + vo='x11', # You may not need this + log_handler=print, + loglevel='debug') + player.play('test.webm') + + app = QApplication(sys.argv) + + # This is necessary since PyQT stomps over the locale settings needed by libmpv. + # This needs to happen after importing PyQT before creating the first mpv.MPV instance. + import locale + locale.setlocale(locale.LC_NUMERIC, 'C') + win = Test() + win.show() + sys.exit(app.exec_()) + +PyGObject embedding +................... + +.. code:: python + + #!/usr/bin/env python3 + import gi + + import mpv + + gi.require_version('Gtk', '3.0') + from gi.repository import Gtk + + + class MainClass(Gtk.Window): + + def __init__(self): + super(MainClass, self).__init__() + self.set_default_size(600, 400) + self.connect("destroy", self.on_destroy) + + widget = Gtk.Frame() + self.add(widget) + self.show_all() + + # Must be created >after< the widget is shown, else property 'window' will be None + self.mpv = mpv.MPV(wid=str(widget.get_property("window").get_xid())) + self.mpv.play("test.webm") + + def on_destroy(self, widget, data=None): + self.mpv.terminate() + Gtk.main_quit() + + + if __name__ == '__main__': + # This is necessary since like Qt, Gtk stomps over the locale settings needed by libmpv. + # Like with Qt, this needs to happen after importing Gtk but before creating the first mpv.MPV instance. + import locale + locale.setlocale(locale.LC_NUMERIC, 'C') + + application = MainClass() + Gtk.main() + +Using OpenGL from PyGObject +........................... + +Just like it is possible to render into a GTK widget through X11 windows, it `also is possible to render into a GTK +widget using OpenGL `__ through this python API. + +Using OpenGL from PyQt5/QML +........................... + +Robozman_ has mangaed to `make mpv render into a PyQt5/QML widget using OpenGL +`__ through this python API. + +Using mpv inside imgui inside OpenGL via GLFW +............................................. + +dfaker_ has written a demo (`link `__) that uses mpv to render video into an `imgui `__ UI running on an OpenGL context inside `GLFW `__. Check out their demo to see how to integrate with imgui/OpenGL and how to access properties and manage the lifecycle of an MPV instance. + +Running tests +------------- + +Use pytest to run tests. + +Coding Conventions +------------------ + +The general aim is `PEP 8`_, with liberal application of the "consistency" section. 120 cells line width. Four spaces. +No tabs. Probably don't bother making pure-formatting PRs except if you think it *really* helps readability or it +*really* irks you if you don't. + +License +------- + +python-mpv inherits the underlying libmpv's license, which can be either GPLv2 or later (default) or LGPLv2.1 or later. +For details, see `the mpv copyright page`_. + +.. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/ +.. _`mpv.py`: https://raw.githubusercontent.com/jaseg/python-mpv/main/mpv.py +.. _cosven: https://github.com/cosven +.. _Robozman: https://gitlab.com/robozman +.. _dfaker: https://github.com/dfaker +.. _`the mpv copyright page`: https://github.com/mpv-player/mpv/blob/master/Copyright + diff --git a/content/projects/python-mpv/index.rst b/content/projects/python-mpv/index.rst new file mode 100644 index 0000000..a1bdcd5 --- /dev/null +++ b/content/projects/python-mpv/index.rst @@ -0,0 +1,18 @@ +--- +title: "python-mpv" +external_links: + - name: Sources + url: "https://git.jaseg.de/python-mpv.git" + - name: Issues + url: "https://github.com/jaseg/python-mpv/issues" + - name: Docs + url: "https://neinseg.gitlab.io/python-mpv" + - name: PyPI + url: "https://pypi.org/projects/mpv" +summary: > + python-mpv is a small, ctypes-based Python library wrapping the libmpv media player library. Despite its small size + and simple API, python-mpv allows advanced control over libmpv and beyond simple remote control of mpv can be used + to embed mpv in OpenGL, Qt, and GTK-based Python applications. +--- + +.. include:: content/projects/python-mpv/README.rst diff --git a/content/projects/svg-flatten/index.rst b/content/projects/svg-flatten/index.rst new file mode 100644 index 0000000..1554bcf --- /dev/null +++ b/content/projects/svg-flatten/index.rst @@ -0,0 +1,15 @@ +--- +title: "svg-flatten" +external_links: + - name: Sources + url: "https://git.jaseg.de/gerbolyze.git/tree/svg-flatten?h=main" + - name: Issues + url: "https://github.com/jaseg/gerbolyze/issues" + - name: Docs + url: "https://gerbolyze.gitlab.io/svg-flatten" +summary: > + svg-flatten is a command-line utility that performs vector occlusion and clipping on SVG files, producing a + flattened SVG file without overlapping elements, without changing what the file looks like. svg-flatten is used as a + part of gerbolyze. +--- + diff --git a/content/projects/wsdiff/index.rst b/content/projects/wsdiff/index.rst new file mode 100644 index 0000000..8c2a7bc --- /dev/null +++ b/content/projects/wsdiff/index.rst @@ -0,0 +1,63 @@ +--- +title: "wsdiff" +external_links: + - name: Sources + url: "https://git.jaseg.de/wsdiff.git" + - name: Issues + url: "https://github.com/jaseg/wsdiff/issues" + - name: Docs + url: "https://pypi.org/projects/wsdiff" +summary: > + wsdiff is a command-line utility that produces self-contained, syntax-highlighted, HTML-formatted diffs that support + both unified and side-by-side diffs from a single source file using nothing but CSS magic. +--- + +wsdiff is a python script that produces a diff of two files or directories as a single, self-contained HTML file. The +resulting diff works without Javascript and will automatically switch between inline and side-by-side formats depending +on available screen space. + +Installation +============ + +.. code:: sh + + $ pip install wsdiff + +Usage +===== + +:: + + usage: wsdiff [-h] [-b] [-s SYNTAX_CSS] [-l LEXER] [-L] [-t PAGETITLE] + [-o OUTPUT] [--header] [--content] + [old] [new] + + Given two source files or directories this application creates an html page + that highlights the differences between the two. + + positional arguments: + old source file or directory to compare ("before" file) + new source file or directory to compare ("after" file) + + options: + -h, --help show this help message and exit + -b, --open Open output file in a browser + -s SYNTAX_CSS, --syntax-css SYNTAX_CSS + Path to custom Pygments CSS file for code syntax + highlighting + -l LEXER, --lexer LEXER + Manually select pygments lexer (default: guess from + filename, use -L to list available lexers.) + -L, --list-lexers List available lexers for -l/--lexer + -t PAGETITLE, --pagetitle PAGETITLE + Override page title of output HTML file + -o OUTPUT, --output OUTPUT + Name of output file (default: stdout) + --header Only output HTML header with stylesheets and stuff, + and no diff + --content Only output HTML content, without header + +Example Output +============== + +.. image:: latest.png diff --git a/content/projects/wsdiff/latest.png b/content/projects/wsdiff/latest.png new file mode 100644 index 0000000..039fa46 Binary files /dev/null and b/content/projects/wsdiff/latest.png differ -- cgit