├── .gitignore ├── .gitmodules ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── README_dotstar_8x8.md ├── case ├── dotstar_8x8 │ ├── 3mf │ │ ├── base.3mf │ │ ├── button_peg_backing.3mf │ │ ├── button_peg_shaft.3mf │ │ ├── prusa_slicer_project.3mf │ │ └── top_cover.3mf │ ├── dep │ │ ├── NopSCADlib │ │ │ ├── CHANGELOG.md │ │ │ ├── COPYING │ │ │ ├── core.scad │ │ │ ├── global_defs.scad │ │ │ ├── readme.md │ │ │ ├── utils │ │ │ │ ├── core │ │ │ │ │ ├── bom.scad │ │ │ │ │ ├── clip.scad │ │ │ │ │ ├── core.scad │ │ │ │ │ ├── global.scad │ │ │ │ │ ├── polyholes.scad │ │ │ │ │ ├── rounded_rectangle.scad │ │ │ │ │ ├── sphere.scad │ │ │ │ │ └── teardrops.scad │ │ │ │ ├── dogbones.scad │ │ │ │ ├── fillet.scad │ │ │ │ ├── maths.scad │ │ │ │ ├── quadrant.scad │ │ │ │ ├── rounded_cylinder.scad │ │ │ │ ├── sweep.scad │ │ │ │ ├── thread.scad │ │ │ │ └── tube.scad │ │ │ └── vitamins │ │ │ │ ├── insert.scad │ │ │ │ ├── inserts.scad │ │ │ │ ├── nut.scad │ │ │ │ ├── nuts.scad │ │ │ │ ├── pin_header.scad │ │ │ │ ├── pin_headers.scad │ │ │ │ ├── screw.scad │ │ │ │ ├── screws.scad │ │ │ │ ├── washer.scad │ │ │ │ └── washers.scad │ │ └── mattwach │ │ │ ├── util.scad │ │ │ └── vitamins │ │ │ └── electronics │ │ │ ├── adafruit_dotstar_8x8_matrix.scad │ │ │ ├── buttons.scad │ │ │ ├── cr2032_battery.scad │ │ │ ├── ds3231_rtc.scad │ │ │ └── pi_pico.scad │ ├── lib │ │ ├── matrix_clock_assembled_board.scad │ │ ├── matrix_clock_kicad_pcb.step │ │ └── matrix_clock_kicad_pcb.stl │ └── matrix_clock_case.scad └── led_matrix_64x32 │ ├── dep │ ├── button_pcb.scad │ ├── button_pcb_kicad.stl │ ├── main_pcb.scad │ └── main_pcb.stl │ ├── export │ ├── bottom_support.3mf │ └── top_support.3mf │ ├── led_matrix_64x32.scad │ └── lib │ ├── NopSCADlib │ ├── CHANGELOG.md │ ├── COPYING │ ├── core.scad │ ├── global_defs.scad │ ├── readme.md │ ├── utils │ │ ├── core │ │ │ ├── bom.scad │ │ │ ├── clip.scad │ │ │ ├── core.scad │ │ │ ├── global.scad │ │ │ ├── polyholes.scad │ │ │ ├── rounded_rectangle.scad │ │ │ ├── sphere.scad │ │ │ └── teardrops.scad │ │ ├── dogbones.scad │ │ ├── fillet.scad │ │ ├── maths.scad │ │ ├── quadrant.scad │ │ ├── rounded_cylinder.scad │ │ ├── sweep.scad │ │ ├── thread.scad │ │ └── tube.scad │ └── vitamins │ │ ├── button.scad │ │ ├── buttons.scad │ │ ├── insert.scad │ │ ├── inserts.scad │ │ ├── nut.scad │ │ ├── nuts.scad │ │ ├── pin_header.scad │ │ ├── pin_headers.scad │ │ ├── screw.scad │ │ ├── screws.scad │ │ ├── washer.scad │ │ └── washers.scad │ └── mattwach │ ├── honeycomb.scad │ ├── util.scad │ └── vitamins │ └── electronics │ ├── cr2032_battery.scad │ ├── ds3231_rtc.scad │ ├── led_panel_64x32.scad │ └── pi_pico.scad ├── firmware ├── matrix_clock_dotstar_8x8.uf2 └── matrix_clock_led_64x32.uf2 ├── images ├── button_hardware.jpg ├── clock_set.jpg ├── completed_pcb.jpg ├── console.png ├── ds8x8 │ ├── 3d_case_underside.png │ ├── 3d_printed_case.png │ ├── ds_matrix_clock.jpg │ ├── matrix_clock2.jpg │ ├── minicom.jpg │ ├── numbers.jpg │ ├── opened_clock.jpg │ └── schematic.png ├── kicad_button_layout.png ├── kicad_layout.png ├── matrix_back.jpg ├── matrix_clock.jpg ├── matrix_only.jpg ├── matrix_with_numbers.jpg ├── openscad_bottom.png ├── openscad_model.png ├── openscad_top.png ├── other_matrix_modes.jpg └── schematic.png ├── schematic ├── button_pcb_kicad │ ├── button_pcb_kicad.kicad_pcb │ ├── button_pcb_kicad.kicad_prl │ ├── button_pcb_kicad.kicad_pro │ ├── button_pcb_kicad.kicad_sch │ ├── flatcam │ │ ├── Project_20230128_192544.FlatPrj │ │ ├── button_pcb_kicad-Edge_Cuts.gbr_cutout_cnc.nc │ │ ├── button_pcb_kicad-F_Cu.gbr_iso_combined_cnc.nc │ │ ├── button_pcb_kicad-NPTH.drl_cnc.nc │ │ ├── button_pcb_kicad-PTH.drl_cnc.nc │ │ └── test.nc │ ├── fp-info-cache │ └── gerber │ │ ├── button_pcb_kicad-Edge_Cuts.gbr │ │ ├── button_pcb_kicad-F_Cu.gbr │ │ ├── button_pcb_kicad-NPTH.drl │ │ ├── button_pcb_kicad-PTH.drl │ │ └── button_pcb_kicad-job.gbrjob ├── dotstar_8x8_kicad │ ├── export │ │ ├── matrix_clock_kicad-B_Cu.gbr │ │ ├── matrix_clock_kicad-Edge_Cuts.gbr │ │ ├── matrix_clock_kicad-NPTH.drl │ │ ├── matrix_clock_kicad-PTH.drl │ │ └── matrix_clock_kicad-job.gbrjob │ ├── flatcam │ │ ├── matrix_clock.FlatPrj │ │ ├── matrix_clock_kicad-B_Cu.gbr_iso_combined_cnc.nc │ │ ├── matrix_clock_kicad-Edge_Cuts.gbr_edit_cutout_cnc.nc │ │ ├── matrix_clock_kicad-PTH.mounting_drill.nc │ │ ├── matrix_clock_kicad-PTH.small_drill.nc │ │ └── test.nc │ ├── fp-info-cache │ ├── matrix_clock_kicad.kicad_pcb │ ├── matrix_clock_kicad.kicad_prl │ ├── matrix_clock_kicad.kicad_pro │ ├── matrix_clock_kicad.kicad_sch │ └── matrix_clock_kicad.net └── led_matrix_64x32_kicad │ ├── flatcam │ ├── Project_20230127_103059.FlatPrj │ └── led_matrix_64x32_kicad-F_Paste.nc │ ├── fp-info-cache │ ├── gerber │ ├── led_matrix_64x32_kicad-F_Mask.gbr │ ├── led_matrix_64x32_kicad-F_Mask.svg │ ├── led_matrix_64x32_kicad-F_Paste.gbr │ ├── led_matrix_64x32_kicad-F_Paste.svg │ └── led_matrix_64x32_kicad-job.gbrjob │ ├── led_matrix_64x32_kicad.kicad_pcb │ ├── led_matrix_64x32_kicad.kicad_prl │ ├── led_matrix_64x32_kicad.kicad_pro │ ├── led_matrix_64x32_kicad.kicad_sch │ └── led_matrix_64x32_kicad.net └── src ├── CMakeLists.txt ├── bootstrap.sh ├── buttons.c ├── buttons.h ├── clock.h ├── clock_ds3231.c ├── clock_pico_internal.c ├── clock_render.c ├── clock_render.h ├── clock_settings.c ├── clock_settings.h ├── colors.c ├── colors.h ├── debounce.c ├── debounce.h ├── debug.c ├── debug.h ├── led_matrix.h ├── led_matrix_64x32.c ├── led_matrix_dotstar.c ├── main.c ├── monitor.c ├── monitor.h ├── number_draw.c ├── number_draw.h ├── pico_sdk_import.cmake ├── render ├── blank.c ├── blank.h ├── bounce.c ├── bounce.h ├── distances.inc ├── drops.c ├── drops.h ├── fade.c ├── fade.h ├── matrix.c ├── matrix.h ├── matrix_with_numbers.c ├── matrix_with_numbers.h ├── number_cascade.c ├── number_cascade.h ├── number_cascade_hires.c ├── number_cascade_hires.h ├── waveform.c └── waveform.h ├── set_time_high_res.c ├── set_time_high_res.h ├── set_time_low_res.c ├── set_time_low_res.h └── tools └── distance_generator.py /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *-backups 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/pico_uart_console"] 2 | path = src/pico_uart_console 3 | url = https://github.com/mattwach/pico_uart_console.git 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.sourceDirectory": "${workspaceFolder}/src", 3 | "cSpell.words": [ 4 | "Dotstar", 5 | "Microcontroller", 6 | "Pico", 7 | "pullup", 8 | "TLDR" 9 | ] 10 | } -------------------------------------------------------------------------------- /case/dotstar_8x8/3mf/base.3mf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/case/dotstar_8x8/3mf/base.3mf -------------------------------------------------------------------------------- /case/dotstar_8x8/3mf/button_peg_backing.3mf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/case/dotstar_8x8/3mf/button_peg_backing.3mf -------------------------------------------------------------------------------- /case/dotstar_8x8/3mf/button_peg_shaft.3mf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/case/dotstar_8x8/3mf/button_peg_shaft.3mf -------------------------------------------------------------------------------- /case/dotstar_8x8/3mf/prusa_slicer_project.3mf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/case/dotstar_8x8/3mf/prusa_slicer_project.3mf -------------------------------------------------------------------------------- /case/dotstar_8x8/3mf/top_cover.3mf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/case/dotstar_8x8/3mf/top_cover.3mf -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/core.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | // Include this file to use the minimum library plus screws, nuts and washers 22 | // 23 | include 24 | // 25 | // Fasteners used by a lot of other vitamins 26 | // 27 | include 28 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/global_defs.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | // This file included directly or indirectly in every scad file. 22 | // 23 | // This scheme allows the following: 24 | // bom defaults to 0 25 | // Setting $bom on the command line or in the main file before including lib.scad overrides it everywhere. 26 | // Setting $bom after including lib overrides bom in the libs but not in the local file. 27 | // Setting $_bom in the local file overrides it in the local file but not in the libs. 28 | // 29 | rr_green = [0, 146/255, 0]; // RepRap logo colour 30 | crimson = [220/255, 20/255, 60/255]; 31 | 32 | $_bom = is_undef($bom) ? 0 : $bom; // 0 no bom, 1 assemblies and stls, 2 vitamins as well 33 | $exploded = is_undef($explode) ? 0 : $explode; // 1 for exploded view 34 | layer_height = is_undef($layer_height) ? 0.25 : $layer_height; // layer height when printing 35 | extrusion_width = is_undef($extrusion_width) ? 0.5 : $extrusion_width; // filament width when printing 36 | nozzle = is_undef($nozzle) ? 0.45 : $nozzle; // 3D printer nozzle 37 | cnc_bit_r = is_undef($cnc_bit_r) ? 1.2 : $cnc_bit_r; // minimum tool radius when milling 2D objects 38 | pp1_colour = is_undef($pp1_colour) ? rr_green : $pp1_colour; // printed part colour 1, RepRap logo colour 39 | pp2_colour = is_undef($pp2_colour) ? crimson : $pp2_colour; // printed part colour 2 40 | pp3_colour = is_undef($pp3_colour) ? "SteelBlue" : $pp3_colour; // printed part colour 3 41 | pp4_colour = is_undef($pp4_colour) ? "darkorange" : $pp4_colour;// printed part colour 4 42 | show_rays = is_undef($show_rays) ? false : $show_rays; // show camera sight lines and light direction 43 | show_threads = is_undef($show_threads) ? false : $show_threads; // show screw threads 44 | 45 | // Minimum wall is about two filaments wide but we extrude it closer to get better bonding 46 | squeezed_wall = $preview ? 2 * extrusion_width - layer_height * (1 - PI / 4) 47 | : extrusion_width - layer_height / 2 + nozzle / 2 + extrusion_width / 2; 48 | 49 | inf = 1e10; // very big 50 | eps = 1/128; // small fudge factor to stop CSG barfing on coincident faces. 51 | $fa = 6; 52 | $fs = extrusion_width / 2; 53 | 54 | function round_to_layer(z) = ceil(z / layer_height) * layer_height; 55 | // Some additional named colours 56 | function grey(n) = [0.01, 0.01, 0.01] * n; //! Generate a shade of grey to pass to color(). 57 | silver = [0.75, 0.75, 0.75]; 58 | gold = [255, 215, 0] / 255; 59 | brass = [255, 220, 100] / 255; 60 | copper = [230, 140, 51] / 255; 61 | 62 | /* 63 | * Enums 64 | */ 65 | // 66 | // Screws 67 | // 68 | hs_cap = 0; 69 | hs_pan = 1; 70 | hs_cs = 2; // counter sunk 71 | hs_hex = 3; 72 | hs_grub = 4; // pulley set screw 73 | hs_cs_cap = 5; 74 | hs_dome = 6; 75 | // 76 | // Hot end descriptions 77 | // 78 | jhead = 1; 79 | e3d = 2; 80 | // 81 | // Face enumeration 82 | // 83 | f_bottom = 0; 84 | f_top = 1; 85 | f_left = 2; 86 | f_right = 3; 87 | f_front = 4; 88 | f_back = 5; 89 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/utils/core/clip.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Construct arbitrarily large box to partition 3D space and clip objects, useful for creating cross sections to see the inside when debugging. 22 | //! 23 | //! Original version by Doug Moen on the OpenSCAD forum 24 | // 25 | // 26 | module box(xmin, ymin, zmin, xmax, ymax, zmax) //! Construct a box given its bounds 27 | polyhedron( 28 | [[xmin, ymin, zmin], // 0 29 | [xmin, ymin, zmax], // 1 30 | [xmin, ymax, zmin], // 2 31 | [xmin, ymax, zmax], // 3 32 | [xmax, ymin, zmin], // 4 33 | [xmax, ymin, zmax], // 5 34 | [xmax, ymax, zmin], // 6 35 | [xmax, ymax, zmax]], // 7 36 | [[7,5,1,3], // top 37 | [2,0,4,6], // bottom 38 | [5,4,0,1], // front 39 | [3,2,6,7], // back 40 | [5,7,6,4], // right 41 | [0,2,3,1]] // left 42 | ); 43 | 44 | module clip(xmin = -inf, ymin = -inf, zmin = -inf, xmax = inf, ymax = inf, zmax = inf) //! Clip child to specified boundaries 45 | render() intersection() { 46 | children(); 47 | 48 | box(xmin, ymin, zmin, xmax, ymax, zmax); 49 | } 50 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/utils/core/core.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | // Include this file to use the minimum library 22 | // 23 | include <../../global_defs.scad> 24 | // 25 | // Global functions and modules 26 | // 27 | use 28 | 29 | module use_stl(name) { //! Import an STL to make a build platter 30 | stl(name); 31 | path = is_undef($target) ? "../stls/" : str($cwd, "/", $target, "/stls/"); 32 | import(str(path, name, ".stl")); 33 | } 34 | 35 | module use_dxf(name) { //! Import a DXF to make a build panel 36 | dxf(name); 37 | path = is_undef($target) ? "../dxfs/" : str($cwd, "/", $target, "/dxfs/"); 38 | import(str(path, name, ".dxf")); 39 | } 40 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/utils/core/global.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Global constants, functions and modules. This file is used directly or indirectly in every scad file. 22 | // 23 | include <../../global_defs.scad> 24 | 25 | function inch(x) = x * 25.4; //! Inch to mm conversion (For fractional inches, 'inch(1 + 7/8)' will work as expected.) 26 | function foot(x) = x * 25.4 * 12; //! Foot to mm conversion 27 | function yard(x) = x * 25.4 * 12 * 3; //! Yard to mm conversion 28 | function mm(x) = x; //! Explicit mm specified 29 | function cm(x) = x * 10.0; //! cm to mm conversion 30 | function m(x) = x * 1000.0; //! m to mm conversion 31 | 32 | function sqr(x) = x * x; //! Returns the square of `x` 33 | function echoit(x) = echo(x) x; //! Echo expression and return it, useful for debugging 34 | function no_point(str) = chr([for(c = str(str)) if(c == ".") ord("p") else ord(c)]);//! Replace decimal point in string with 'p' 35 | function in(list, x) = !!len([for(v = list) if(v == x) true]); //! Returns true if `x` is an element in the `list` 36 | function Len(x) = is_list(x) ? len(x) : 0; //! Returns the length of a list or 0 if `x` is not a list 37 | function r2sides(r) = $fn ? $fn : ceil(max(min(360/ $fa, r * 2 * PI / $fs), 5)); //! Replicates the OpenSCAD logic to calculate the number of sides from the radius 38 | function r2sides4n(r) = floor((r2sides(r) + 3) / 4) * 4; //! Round up the number of sides to a multiple of 4 to ensure points land on all axes 39 | function limit(x, min, max) = max(min(x, max), min); //! Force x in range min <= x <= max 40 | 41 | module translate_z(z) translate([0, 0, z]) children(); //! Shortcut for Z only translations 42 | module vflip(flip=true) rotate([flip ? 180 : 0, 0, 0]) children(); //! Invert children by doing a 180° flip around the X axis 43 | module hflip(flip=true) rotate([0, flip ? 180: 0, 0]) children(); //! Invert children by doing a 180° flip around the Y axis 44 | module ellipse(xr, yr) scale([1, yr / xr]) circle4n(xr); //! Draw an ellipse 45 | 46 | function slice_str(str, start, end, s ="") = start >= end ? s : slice_str(str, start + 1, end, str(s, str[start])); // Helper for slice() 47 | 48 | function slice(list, start = 0, end = undef) = let( //! Slice a list or string with Python type semantics 49 | len = len(list), 50 | start = limit(start < 0 ? len + start : start, 0, len), 51 | end = is_undef(end) ? len : limit(end < 0 ? len + end : end, 0, len) 52 | ) is_string(list) ? slice_str(list, start, end) : [for(i = [start : 1 : end - 1]) list[i]]; 53 | 54 | 55 | module render_if(render = true, convexity = 2) //! Renders an object if `render` is true, otherwise leaves it unrendered 56 | if (render) 57 | render(convexity = convexity) 58 | children(); 59 | else 60 | children(); 61 | 62 | module extrude_if(h, center = true) //! Extrudes 2D object to 3D when `h` is nonzero, otherwise leaves it 2D 63 | if(h) 64 | linear_extrude(h, center = center, convexity = 2) // 3D 65 | children(); 66 | else 67 | children(); // 2D 68 | 69 | module circle4n(r, d = undef) { //! Circle with multiple of 4 vertices 70 | R = is_undef(d) ? r : d / 2; 71 | circle(R, $fn = r2sides4n(R)); 72 | } 73 | 74 | module semi_circle(r, d = undef) //! A semi circle in the positive Y domain 75 | intersection() { 76 | R = is_undef(d) ? r : d / 2; 77 | circle4n(R); 78 | 79 | sq = R + 1; 80 | translate([-sq, 0]) 81 | square([2 * sq, sq]); 82 | } 83 | 84 | module right_triangle(width, height, h, center = true) //! A right angled triangle with the 90° corner at the origin. 3D when `h` is nonzero, otherwise 2D 85 | extrude_if(h, center = center) 86 | polygon(points = [[0,0], [width, 0], [0, height]]); 87 | 88 | include 89 | include 90 | include 91 | include 92 | include 93 | include 94 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/utils/core/rounded_rectangle.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Rectangle with rounded corners. 22 | // 23 | module rounded_square(size, r, center = true) //! Like `square()` but with with rounded corners 24 | { 25 | assert(r < min(size.x, size.y) / 2); 26 | $fn = r2sides4n(r); 27 | offset(r) offset(-r) square(size, center = center); 28 | } 29 | 30 | module rounded_rectangle(size, r, center = false, xy_center = true) //! Like `cube()` but corners rounded in XY plane and separate centre options for xy and z. 31 | { 32 | extrude_if(size.z, center = center) 33 | rounded_square([size.x, size.y], r, xy_center); 34 | } 35 | 36 | module rounded_cube_xy(size, r = 0, xy_center = false, z_center = false) //! Like `cube()` but corners rounded in XY plane and separate centre options for xy and z. 37 | { 38 | extrude_if(size.z, center = z_center) 39 | rounded_square([size.x, size.y], r, xy_center); 40 | } 41 | 42 | module rounded_cube_xz(size, r = 0, xy_center = false, z_center = false) //! Like `cube()` but corners rounded in XZ plane and separate centre options for xy and z. 43 | { 44 | translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, z_center ? 0 : size.z / 2]) 45 | rotate([90, 0, 0]) 46 | rounded_cube_xy([size.x, size.z, size.y], r, xy_center = true, z_center = true); 47 | } 48 | 49 | module rounded_cube_yz(size, r = 0, xy_center = false, z_center = false) //! Like `cube()` but corners rounded in YX plane and separate centre options for xy and z. 50 | { 51 | translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, z_center ? 0 : size.z / 2]) 52 | rotate([90, 0, 90]) 53 | rounded_cube_xy([size.y, size.z, size.x], r, xy_center = true, z_center = true); 54 | } 55 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/utils/core/sphere.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | //! Redefines `sphere()` to always have a vertex on all six half axes I.e. vertices at the poles and the equator and `$fn` a multiple of four. 21 | //! This ensures `hull` and `minkowski` results have the correct dimensions when spheres are placed at the corners. 22 | 23 | module sphere(r = 1, d = undef) { //! Override `sphere` so that has vertices on all three axes. Has the advantage of giving correct dimensions when hulled 24 | R = is_undef(d) ? r : d / 2; 25 | rotate_extrude($fn = r2sides4n(R)) 26 | rotate(-90) 27 | semi_circle(R); 28 | } 29 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/utils/dogbones.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! When square holes are cut with a CNC bit they get rounded corners. If it is important that 22 | //! a square cornered part fits in the hole then circles are placed in the corners making a bone shape. 23 | // 24 | include <../utils/core/core.scad> 25 | 26 | module dogbone_square(size, r = cnc_bit_r, center = true, x_offset, y_offset) //! Square with circles at the corners, with optional offsets 27 | { 28 | x_offset = is_undef(x_offset) ? r / sqrt(2) : x_offset; 29 | y_offset = is_undef(y_offset) ? r / sqrt(2) : y_offset; 30 | 31 | union() { 32 | square(size, center = center); 33 | 34 | if(r > 0) { 35 | origin = center ? [0, 0] : size / 2; 36 | 37 | for(x = [-1, 1], y = [-1, 1]) 38 | translate(origin + [x * (size.x / 2 - x_offset), y * (size.y / 2 - y_offset)]) 39 | drill(r, 0); 40 | } 41 | } 42 | } 43 | 44 | module dogbone_rectangle(size, r = cnc_bit_r, center = true, xy_center = true, x_offset, y_offset) //! Rectangle with cylinders at the corners 45 | { 46 | extrude_if(h = size.z, center = center) 47 | dogbone_square([size.x, size.y], r, xy_center, x_offset, y_offset); 48 | } 49 | 50 | module dogbone_rectangle_x(size, r = cnc_bit_r, center = true, xy_center = true) //! Rectangle with cylinders at the corners, offset in the x direction 51 | { 52 | dogbone_rectangle(size = size, r = r, center = center, x_offset = 0, y_offset = r); 53 | } 54 | 55 | module dogbone_rectangle_y(size, r = cnc_bit_r, center = true, xy_center = true) //! Rectangle with cylinders at the corners, offset in the y direction 56 | { 57 | dogbone_rectangle(size = size, r = r, center = center, x_offset = r, y_offset = 0); 58 | } 59 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/utils/fillet.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Rounded fillet for adding to corners. 22 | // 23 | include <../utils/core/core.scad> 24 | 25 | module fillet(r, h, center = false) //! Fillet with specified radius and height 26 | extrude_if(h, center = center) 27 | difference() { 28 | translate([-eps, -eps, 0]) 29 | square(r + eps); 30 | 31 | translate([r, r]) 32 | circle(r + eps); 33 | } 34 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/utils/quadrant.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Square with one rounded corner. 22 | // 23 | include <../utils/core/core.scad> 24 | 25 | module quadrant(w, r, center = false) { //! Draw a square with one rounded corner, can be centered on the arc centre, when `center` is `true`. 26 | h = is_list(w) ? w.y : w; 27 | w = is_list(w) ? w.x : w; 28 | offset_w = center ? r - w : 0; 29 | offset_h = center ? r - h : 0; 30 | translate([offset_w, offset_h]) 31 | hull() { 32 | intersection() { 33 | translate([w - r, h - r]) 34 | circle4n(r); 35 | 36 | square([w, h]); 37 | } 38 | 39 | square([w, eps]); 40 | 41 | square([eps, h]); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/utils/rounded_cylinder.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Cylinder with a rounded end. 22 | // 23 | include <../utils/core/core.scad> 24 | 25 | module rounded_corner(r, h, r2, ir = 0) { //! 2D version 26 | assert(ir <= r - r2); 27 | 28 | translate([ir , 0]) 29 | hull() { 30 | square([eps, h]); 31 | 32 | square([r - ir, eps]); 33 | 34 | translate([r - r2 - ir, h - r2]) 35 | intersection() { 36 | circle4n(r2, $fs = 0.2); 37 | 38 | square(r2); 39 | } 40 | } 41 | } 42 | 43 | module rounded_cylinder(r, h, r2, ir = 0, angle = 360) //! Rounded cylinder given radius `r`, height `h`, optional internal radius `ir` and optional `angle` 44 | { 45 | rotate_extrude(angle = angle) 46 | rounded_corner(r, h, r2, ir); 47 | } 48 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/utils/tube.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Simple tube or ring 22 | // 23 | include <../utils/core/core.scad> 24 | 25 | module ring(or, ir) //! Create a ring with specified external and internal radii 26 | difference() { 27 | circle4n(or); 28 | circle4n(ir); 29 | } 30 | 31 | module tube(or, ir, h, center = true) //! Create a tube with specified external and internal radii and height `h` 32 | linear_extrude(h, center = center, convexity = 5) 33 | ring(or, ir); 34 | 35 | module woven_tube(or, ir, h, center= true, colour = grey(30), colour2, warp = 2, weft) {//! Create a woven tube with specified external and internal radii, height `h`, colours, warp and weft 36 | colour2 = colour2 ? colour2 : colour * 0.8; 37 | weft = weft ? weft : warp; 38 | warp_count = max(floor(PI * or / warp), 0.5); 39 | angle = 360 / (2 * warp_count); 40 | 41 | module layer(weft) { 42 | points = [[ir, weft / 2], [or, weft / 2], [or, -weft / 2], [ir, -weft / 2]]; 43 | color(colour) 44 | for (i = [0 : warp_count]) 45 | rotate(2 * i * angle) 46 | rotate_extrude(angle = angle) 47 | polygon(points); 48 | color(colour2) 49 | for (i = [0 : warp_count]) 50 | rotate((2 * i + 1) * angle) 51 | rotate_extrude(angle = angle) 52 | polygon(points); 53 | } 54 | 55 | translate_z(center ? -h / 2 : 0) { 56 | weft_count = floor(h / weft); 57 | if (weft_count > 0) 58 | for (i = [0 : weft_count - 1]) { 59 | translate_z(i * weft + weft / 2) 60 | rotate(i * angle) 61 | layer(weft); 62 | } 63 | remainder = h - weft * weft_count; 64 | if (remainder) { 65 | translate_z(weft_count * weft + remainder / 2) 66 | rotate(weft_count * angle) 67 | layer(remainder); 68 | } 69 | } 70 | } 71 | 72 | module rectangular_tube(size, center = true, thickness = 1, fillet = 0.5) { //! Create a rectangular tube with filleted corners 73 | extrude_if(size.z, center = center) 74 | difference() { 75 | rounded_square([size.x, size.y], fillet); 76 | rounded_square([size.x - 2 * thickness, size.y - 2 * thickness], fillet); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/vitamins/inserts.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | // Threaded inserts 22 | // 23 | // l o h s b r r r 24 | // e u o c a i i i 25 | // n t l r r n n n 26 | // g e e e r g g g 27 | // t r w e 1 2 3 28 | // h d l 29 | // d d h d d 30 | // d 31 | // 32 | F1BM2 = [ "F1BM2", 4.0, 3.6, 3.2, 2, 3.0, 1.0, 3.4, 3.1 ]; 33 | F1BM2p5 = [ "F1BM2p5", 5.8, 4.6, 4.0, 2.5, 3.65, 1.6, 4.4, 3.9 ]; 34 | F1BM3 = [ "F1BM3", 5.8, 4.6, 4.0, 3, 3.65, 1.6, 4.4, 3.9 ]; 35 | F1BM4 = [ "F1BM4", 8.2, 6.3, 5.6, 4, 5.15, 2.3, 6.0, 5.55 ]; 36 | 37 | inserts = [ F1BM2, F1BM2p5, F1BM3, F1BM4 ]; 38 | 39 | use 40 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/vitamins/nuts.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | include 20 | // 21 | // Nuts 22 | // 23 | M2_nut_trap_depth = 2.5; 24 | M2p5_nut_trap_depth = 2.5; 25 | M3_nut_trap_depth = 3; 26 | M4_nut_trap_depth = 4; 27 | M5_nut_depth = 4; 28 | M6_nut_depth = 5; 29 | M8_nut_depth = 6.5; 30 | 31 | // s r t n w t t 32 | // c a h y a r h 33 | // r d i l s a r 34 | // e i c o h p e 35 | // w u k c e d 36 | // s n r d 37 | // e t e p 38 | // s h p i 39 | // s k t t 40 | // h c 41 | // h 42 | M2_nut = ["M2_nut", 2, 4.9, 1.6, 2.4, M2_washer, M2_nut_trap_depth, 0]; 43 | M2p5_nut = ["M2p5_nut", 2.5, 5.8, 2.2, 3.8, M2p5_washer, M2p5_nut_trap_depth, 0]; 44 | M3_nut = ["M3_nut", 3, 6.4, 2.4, 4, M3_washer, M3_nut_trap_depth, 0]; 45 | M4_nut = ["M4_nut", 4, 8.1, 3.2, 5, M4_washer, M4_nut_trap_depth, 0]; 46 | M5_nut = ["M5_nut", 5, 9.2, 4, 6.25, M5_washer, M5_nut_depth, 0]; 47 | M6_nut = ["M6_nut", 6, 11.5, 5, 8, M6_washer, M6_nut_depth, 0]; 48 | M6_half_nut = ["M6_half_nut", 6, 11.5, 3, 8, M6_washer, 3, 0]; 49 | M8_nut = ["M8_nut", 8, 15, 6.5, 8, M8_washer, M8_nut_depth, 0]; 50 | toggle_nut = ["toggle_nut", 6.1, 9.2, 1.5, 1.5, M6_washer, 1.5, inch(1/40)]; 51 | 52 | M4_wingnut = ["M4_wingnut", 4, 10, 3.75,8, M4_washer, 0, 22, 10, 6, 3]; 53 | // sx ty1 ty2 hammer 54 | M3_sliding_t_nut = ["M3_sliding_t_nut", 3, 6, 3.0, 4.0, false, 0, 10, 10, 6, false]; 55 | M4_sliding_t_nut = ["M4_sliding_t_nut", 4, 6, 3.25,4.5, false, 0, 11, 10, 6, false]; 56 | M5_sliding_t_nut = ["M5_sliding_t_nut", 5, 6, 3.25,4.5, false, 0, 11, 10, 7, false]; 57 | M3_hammer_nut = ["M3_hammer_nut", 3, 6, 2.75,4.0, false, 0, 5.5, 10, 6, true]; 58 | M4_hammer_nut = ["M4_hammer_nut", 4, 6, 3.25,4.5, false, 0, 5.5, 10, 6, true]; 59 | 60 | // DIN 562 (thin) square nuts 61 | // s w h 62 | // c i e 63 | // r d i 64 | // e t g 65 | // w h h 66 | // t 67 | // 68 | M3nS_thin_nut = ["M3nS_thin_nut", 3, 5.5, 1.8]; 69 | M4nS_thin_nut = ["M4nS_thin_nut", 4, 7, 2.2]; 70 | M5nS_thin_nut = ["M5nS_thin_nut", 5, 8, 2.7]; 71 | M6nS_thin_nut = ["M6nS_thin_nut", 6, 10, 3.2]; 72 | M8nS_thin_nut = ["M8nS_thin_nut", 8, 13, 4]; 73 | 74 | nuts = [M2_nut, M2p5_nut, M3_nut, M4_nut, M5_nut, M6_nut, M8_nut]; 75 | 76 | use 77 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/vitamins/pin_headers.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // p p b p p b s b b p r r 21 | // i i e i i a o o o i a a 22 | // t n l n n s c x x n 23 | // c o e k b h 24 | // h l w w c s t y 25 | // c h z o 26 | // f 27 | 2p54header = ["2p54header", 2.54, 11.6, 3.2, 0.66, gold, grey(20), 8.5, [0, 0, 8.7], 2.4, 0, 0, 0 ]; 28 | 2p54joiner = ["2p54joiner", 2.54, 6.86, 2.5, 0.66, gold, grey(20), 8.5, [0, 0, 8.7], 2.4, 0, 0, 0 ]; // Cropped pins for joining PCBs 29 | 30 | jst_xh_header = ["jst_xh_header",2.5, 10, 3.4, 0.64, gold, grey(90), 0, [4.9, 5.75, 7], 0.8, 0.525, 0.6, 6.1]; 31 | jst_ph_header = ["jst_ph_header",2.0, 9, 3.4, 0.64, silver, grey(90), 0, [3.9, 4.5, 6], 0.6, 0.55, 0.25, 4.8]; 32 | 33 | pin_headers = [ 2p54header ]; 34 | 35 | use 36 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/NopSCADlib/vitamins/washers.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | // Washers 22 | // 23 | // s d t s s s s p 24 | // c i h o t p p e 25 | // r a i f a r r n 26 | // e m c t r i i n 27 | // w e k n n y 28 | // t n d g g 29 | // e e i v 30 | // r s a d t e 31 | // s i h r 32 | // a k 33 | M3_penny_washer = ["M3_penny", 3, 12, 0.8, false, 5.8, 5.6, 1.0, true]; 34 | M4_penny_washer = ["M4_penny", 4, 14, 0.8, false, 7.9, 7.0, 1.2, true]; 35 | M5_penny_washer = ["M5_penny", 5, 20, 1.4, false, 9.0, 8.8, 1.6, true]; 36 | M6_penny_washer = ["M6_penny", 6, 26, 1.5, false, 10.6, 9.9, 1.6, true]; 37 | M8_penny_washer = ["M8_penny", 8, 30, 1.5, false, 13.8, 12.7, 2.0, true]; 38 | 39 | M2_washer = ["M2", 2, 5, 0.3, false, 4.5, 4.4, 0.5, undef]; 40 | M2p5_washer = ["M2p5", 2.5, 5.9, 0.5, false, 5.4, 5.1, 0.6, undef]; 41 | M3_washer = ["M3", 3, 7, 0.5, false, 5.8, 5.6, 1.0, M3_penny_washer]; 42 | M3p5_washer = ["M3p5", 3.5, 8, 0.5, false, 6.9, 6.2, 1.0, undef]; 43 | M4_washer = ["M4", 4, 9, 0.8, false, 7.9, 7.0, 1.2, M4_penny_washer]; 44 | M5_washer = ["M5", 5, 10, 1.0, false, 9.0, 8.8, 1.6, M5_penny_washer]; 45 | M6_washer = ["M6", 6, 12.5, 1.5, false, 10.6, 9.9, 1.6, M6_penny_washer]; 46 | M8_washer = ["M8", 8, 17, 1.6, false, 13.8, 12.7, 2.0, M8_penny_washer]; 47 | toggle_washer = ["toggle", 6.1,12, 0.6, false, 10, 0, 0, undef]; 48 | 49 | M3_rubber_washer= ["M3_rubber",3, 10, 1.5, true, 5.8, M3_penny_washer]; 50 | 51 | washers = [M2_washer, M2p5_washer, M3_washer, M3p5_washer, M4_washer, M5_washer, M6_washer, M8_washer, M3_rubber_washer]; 52 | 53 | use 54 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/mattwach/util.scad: -------------------------------------------------------------------------------- 1 | module tx(x) translate([x,0,0]) children(); 2 | module ty(y) translate([0,y,0]) children(); 3 | module tz(z) translate([0,0,z]) children(); 4 | 5 | // Planes 6 | module txy(x, y) translate([x,y,0]) children(); 7 | module txz(x, z) translate([x,0,z]) children(); 8 | module tyz(y, z) translate([0,y,z]) children(); 9 | 10 | module boardxy(x, y, pin_spacing=2.54) { 11 | translate([x * pin_spacing, y * pin_spacing,0]) children(); 12 | } 13 | 14 | 15 | module rx(x) rotate([x,0,0]) children(); 16 | module ry(y) rotate([0,y,0]) children(); 17 | module rz(z) rotate([0,0,z]) children(); 18 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/mattwach/vitamins/electronics/adafruit_dotstar_8x8_matrix.scad: -------------------------------------------------------------------------------- 1 | use <../../util.scad> 2 | 3 | DOTSTAR_8X8_BASE_WIDTH = 25.4; 4 | DOTSTAR_8X8_WIDTH_WITH_TABS = 35.8; 5 | DOTSTAR_8X8_TAB_WIDTH = (DOTSTAR_8X8_WIDTH_WITH_TABS - DOTSTAR_8X8_BASE_WIDTH) / 2; 6 | DOTSTAR_8X8_TAB_HOLE_DIAMETER = 3.3; 7 | DOTSTAR_8X8_PCB_THICKNESS = 1.5; 8 | DOTSTAR_8X8_THICKNESS = 2.4; 9 | DOTSTAR_8X8_BOLT_SPAN = DOTSTAR_8X8_BASE_WIDTH - DOTSTAR_8X8_TAB_WIDTH; 10 | 11 | module adafruit_dotstar_8x8_matrix(include_tabs=true) { 12 | overlap = 0.01; 13 | 14 | module base_pcb() { 15 | color("#222") cube([ 16 | DOTSTAR_8X8_BASE_WIDTH, 17 | DOTSTAR_8X8_BASE_WIDTH, 18 | DOTSTAR_8X8_PCB_THICKNESS]); 19 | } 20 | 21 | module tab() { 22 | module main() { 23 | color("#222") cube([ 24 | DOTSTAR_8X8_TAB_WIDTH, 25 | DOTSTAR_8X8_TAB_WIDTH, 26 | DOTSTAR_8X8_PCB_THICKNESS]); 27 | } 28 | module hole() { 29 | translate([ 30 | DOTSTAR_8X8_TAB_WIDTH / 2, 31 | DOTSTAR_8X8_TAB_WIDTH / 2, 32 | -overlap]) cylinder( 33 | d=DOTSTAR_8X8_TAB_HOLE_DIAMETER, 34 | DOTSTAR_8X8_PCB_THICKNESS + overlap * 2); 35 | } 36 | difference() { 37 | main(); 38 | hole(); 39 | } 40 | } 41 | 42 | module pads() { 43 | pad_side_offset = 1.27; 44 | pad_diameter = 2; 45 | pad_spacing = 2.54; 46 | pad_depth = 0.1; 47 | pad_text_size = 1.2; 48 | module pad() { 49 | tz(-overlap) color("gold") cylinder(d=pad_diameter, h=pad_depth); 50 | } 51 | 52 | module bottom_pads() { 53 | module pad_with_label(label) { 54 | txy(pad_side_offset, pad_side_offset) pad(); 55 | translate([ 56 | pad_side_offset - (pad_text_size / 2), 57 | pad_spacing, 58 | pad_depth - overlap]) 59 | color("white") 60 | ry(180) rz(90) 61 | linear_extrude(pad_depth) text(label, size=pad_text_size); 62 | } 63 | 64 | pad_with_label("COUT"); 65 | tx(pad_spacing) pad_with_label("DOUT"); 66 | tx(pad_spacing * 2) pad_with_label("GND"); 67 | tx(pad_spacing * 3) pad_with_label("+5V"); 68 | } 69 | 70 | module top_pads() { 71 | module pad_with_label(label) { 72 | txy(DOTSTAR_8X8_BASE_WIDTH - pad_side_offset, 73 | DOTSTAR_8X8_BASE_WIDTH - pad_side_offset) pad(); 74 | translate([ 75 | DOTSTAR_8X8_BASE_WIDTH - pad_side_offset - (pad_text_size / 2), 76 | DOTSTAR_8X8_BASE_WIDTH - pad_spacing, 77 | pad_depth - overlap]) 78 | color("white") 79 | ry(180) rz(90) 80 | linear_extrude(pad_depth) text(label, size=pad_text_size, halign="right"); 81 | } 82 | 83 | pad_with_label("CIN"); 84 | tx(-pad_spacing) pad_with_label("DIN"); 85 | tx(-pad_spacing * 2) pad_with_label("GND"); 86 | tx(-pad_spacing * 3) pad_with_label("+5V"); 87 | } 88 | 89 | module center_pads() { 90 | center_pad_yoffset = 14.5; 91 | center_pad_span = 6.2; 92 | center_pad_xoffset = (DOTSTAR_8X8_BASE_WIDTH - center_pad_span) / 2; 93 | module pad_with_label(label) { 94 | txy(center_pad_xoffset, center_pad_yoffset) { 95 | pad(); 96 | translate([ 97 | 0, 98 | pad_diameter / 2, 99 | pad_depth - overlap]) ry(180) color("white") 100 | linear_extrude(pad_depth) 101 | text(label, size=pad_text_size, halign="center"); 102 | } 103 | } 104 | pad_with_label("+5V"); 105 | tx(center_pad_span) pad_with_label("GND"); 106 | } 107 | 108 | bottom_pads(); 109 | top_pads(); 110 | center_pads(); 111 | } 112 | 113 | module led_matrix() { 114 | led_matrix_span = 23.7; 115 | led_side_count = 8; 116 | led_offset = (DOTSTAR_8X8_BASE_WIDTH - led_matrix_span) / 2; 117 | led_width = 2; 118 | led_spacing = (led_matrix_span - led_width) / (led_side_count - 1); 119 | module led() { 120 | led_thickness = DOTSTAR_8X8_THICKNESS - DOTSTAR_8X8_PCB_THICKNESS; 121 | translate([ 122 | led_offset, 123 | led_offset, 124 | DOTSTAR_8X8_PCB_THICKNESS]) color("#ddd", 0.5) cube([ 125 | led_width, 126 | led_width, 127 | led_thickness]); 128 | } 129 | for (y = [0:led_side_count-1]) { 130 | for (x = [0:led_side_count-1]) { 131 | txy(x * led_spacing, y * led_spacing) led(); 132 | } 133 | } 134 | } 135 | 136 | base_pcb(); 137 | 138 | if (include_tabs) { 139 | tx(-DOTSTAR_8X8_TAB_WIDTH) tab(); 140 | tx(DOTSTAR_8X8_BASE_WIDTH) tab(); 141 | txy(-DOTSTAR_8X8_TAB_WIDTH, 142 | DOTSTAR_8X8_BASE_WIDTH - DOTSTAR_8X8_TAB_WIDTH) tab(); 143 | txy(DOTSTAR_8X8_BASE_WIDTH, 144 | DOTSTAR_8X8_BASE_WIDTH - DOTSTAR_8X8_TAB_WIDTH) tab(); 145 | } 146 | 147 | pads(); 148 | led_matrix(); 149 | } 150 | 151 | /* 152 | $fa=2; 153 | $fs=0.2; 154 | adafruit_dotstar_8x8_matrix(); 155 | */ 156 | 157 | -------------------------------------------------------------------------------- /case/dotstar_8x8/dep/mattwach/vitamins/electronics/cr2032_battery.scad: -------------------------------------------------------------------------------- 1 | use <../../util.scad> 2 | 3 | CR2032_DIAMETER = 20; 4 | CR2032_THICKNESS = 3.2; 5 | 6 | module cr2032() { 7 | negative_diameter = 17.7; 8 | negative_height = 0.3; 9 | overlap = 0.01; 10 | marker_thickness = 0.5; 11 | marker_length = 5; 12 | marker_depth = 0.1; 13 | module cell() { 14 | color("silver") union() { 15 | cylinder(d=negative_diameter, h=negative_height + overlap); 16 | tz(negative_height) cylinder(d=CR2032_DIAMETER, h=CR2032_THICKNESS-negative_height); 17 | } 18 | } 19 | 20 | module positive_marker() { 21 | color("#aaa") union() { 22 | translate([ 23 | -marker_length / 2, 24 | -marker_thickness / 2, 25 | CR2032_THICKNESS - marker_depth + overlap 26 | ]) cube([marker_length, marker_thickness, marker_depth]); 27 | translate([ 28 | -marker_thickness / 2, 29 | -marker_length / 2, 30 | CR2032_THICKNESS - marker_depth + overlap 31 | ]) cube([marker_thickness, marker_length, marker_depth]); 32 | } 33 | } 34 | 35 | module negative_marker() { 36 | color("#aaa") translate([ 37 | -marker_length / 2, 38 | -marker_thickness / 2, 39 | -overlap 40 | ]) cube([marker_length, marker_thickness, marker_depth]); 41 | } 42 | 43 | difference() { 44 | cell(); 45 | negative_marker(); 46 | positive_marker(); 47 | } 48 | } 49 | 50 | /* 51 | $fa=2; 52 | $fs=0.5; 53 | cr2032(); 54 | */ 55 | -------------------------------------------------------------------------------- /case/dotstar_8x8/lib/matrix_clock_assembled_board.scad: -------------------------------------------------------------------------------- 1 | use <../dep/mattwach/util.scad> 2 | use <../dep/mattwach/vitamins/electronics/buttons.scad> 3 | include <../dep/mattwach/vitamins/electronics/pi_pico.scad> 4 | include <../dep/mattwach/vitamins/electronics/ds3231_rtc.scad> 5 | include <../dep/NopSCADlib/core.scad> 6 | include <../dep/NopSCADlib/vitamins/pin_headers.scad> 7 | 8 | MATRIX_CLOCK_PCB_LENGTH = 63.5; 9 | MATRIX_CLOCK_PCB_WIDTH = 54.6; 10 | MATRIX_CLOCK_PCB_THICKNESS = 1.6; 11 | 12 | module matrix_clock_assembled_board() { 13 | overlap = 0.01; 14 | 15 | module pcb() { 16 | color("#760") translate([ 17 | MATRIX_CLOCK_PCB_LENGTH, 18 | MATRIX_CLOCK_PCB_WIDTH, 19 | 0]) rz(-90) import("lib/matrix_clock_kicad_pcb.stl"); 20 | } 21 | 22 | module pico() { 23 | translate([ 24 | 59.8, 25 | 25.7, 26 | -overlap * 2]) ry(180) pi_pico(); 27 | } 28 | 29 | module rtc() { 30 | pin_x_offset = 47.6; 31 | pin_y_offset = 4.5; 32 | pin_z_offset = 2.4 + MATRIX_CLOCK_PCB_THICKNESS + 3; 33 | module clock_pins() { 34 | translate([ 35 | pin_x_offset, 36 | pin_y_offset, 37 | pin_z_offset]) ry(180) pin_header(2p54header, 4, 1); 38 | } 39 | 40 | module clock_module() { 41 | translate([ 42 | 58.8, 43 | 40.3, 44 | pin_z_offset + 1.6]) rz(-90) rx(180) ds3231_rtc(); 45 | } 46 | 47 | clock_pins(); 48 | clock_module(); 49 | } 50 | 51 | module led_matrix_interface() { 52 | translate([ 53 | 3.8, 54 | 41.9, 55 | MATRIX_CLOCK_PCB_THICKNESS]) rz(-90) jst_xh_header(jst_xh_header, 4); 56 | } 57 | 58 | module interface_buttons() { 59 | button_y_offset = 4.6; 60 | button_z_offset = 2; 61 | translate([ 62 | 10.2, 63 | button_y_offset, 64 | button_z_offset]) push_switch_12x12(include_button=false); 65 | translate([ 66 | 24.8, 67 | button_y_offset, 68 | button_z_offset]) push_switch_12x12(include_button=false); 69 | } 70 | 71 | module reset_button() { 72 | reset_button_length = 6.3; 73 | reset_button_width = 2.4; 74 | reset_button_height = 3; 75 | translate([ 76 | 26, 77 | 50, 78 | -reset_button_height]) cube([ 79 | reset_button_length, 80 | reset_button_width, 81 | reset_button_height]); 82 | } 83 | 84 | pcb(); 85 | pico(); 86 | rtc(); 87 | led_matrix_interface(); 88 | interface_buttons(); 89 | reset_button(); 90 | } 91 | 92 | /* 93 | $fa=2; 94 | $fs=0.2; 95 | matrix_clock_assembled_board(); 96 | */ 97 | -------------------------------------------------------------------------------- /case/dotstar_8x8/lib/matrix_clock_kicad_pcb.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/case/dotstar_8x8/lib/matrix_clock_kicad_pcb.stl -------------------------------------------------------------------------------- /case/led_matrix_64x32/dep/button_pcb.scad: -------------------------------------------------------------------------------- 1 | use <../lib/mattwach/util.scad> 2 | include <../lib/NopSCADlib/core.scad> 3 | include <../lib/NopSCADlib/vitamins/buttons.scad> 4 | include <../lib/NopSCADlib/vitamins/pin_headers.scad> 5 | 6 | module button_pcb() { 7 | pcb_zsize = 1.6; 8 | 9 | module pcb() { 10 | rz(90) color("#262") import("dep/button_pcb_kicad.stl"); 11 | } 12 | 13 | module buttons() { 14 | module button() { 15 | translate([ 16 | 4.65, 17 | 18.6, 18 | pcb_zsize 19 | ]) square_button(button_6mm); 20 | } 21 | 22 | button(); 23 | ty(10.7) button(); 24 | } 25 | 26 | module pins() { 27 | translate([ 28 | 4.5, 29 | 9, 30 | 0]) rz(180) ry(180) pin_header(2p54header, 3, 1, right_angle=true); 31 | } 32 | 33 | pcb(); 34 | buttons(); 35 | pins(); 36 | } 37 | 38 | /* 39 | $fa=2; 40 | $fs=0.2; 41 | button_pcb(); 42 | */ 43 | 44 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/dep/button_pcb_kicad.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/case/led_matrix_64x32/dep/button_pcb_kicad.stl -------------------------------------------------------------------------------- /case/led_matrix_64x32/dep/main_pcb.scad: -------------------------------------------------------------------------------- 1 | use <../lib/mattwach/util.scad> 2 | use <../lib/mattwach/vitamins/electronics/pi_pico.scad> 3 | include <../lib/mattwach/vitamins/electronics/ds3231_rtc.scad> 4 | include <../lib/NopSCADlib/core.scad> 5 | include <../lib/NopSCADlib/vitamins/pin_headers.scad> 6 | 7 | module main_pcb() { 8 | pcb_zsize = 1.6; 9 | 10 | module pcb() { 11 | rz(90) color("#262") import("dep/main_pcb.stl"); 12 | } 13 | 14 | module pico() { 15 | translate([ 16 | 58.65, 17 | 54.2, 18 | pcb_zsize]) rz(180) pi_pico(); 19 | } 20 | 21 | module rtc() { 22 | pin_x_offset = 41.05; 23 | pin_y_offset = 4.05; 24 | pin_z_offset = -2.54; 25 | module clock_pins() { 26 | translate([ 27 | pin_x_offset, 28 | pin_y_offset, 29 | pin_z_offset]) pin_header(2p54header, 4, 1); 30 | } 31 | 32 | module clock_module() { 33 | translate([ 34 | 29.9, 35 | -31.7, 36 | -2.54]) ry(180) rz(90) ds3231_rtc(); 37 | } 38 | 39 | clock_pins(); 40 | clock_module(); 41 | } 42 | 43 | module led_interface_pins() { 44 | translate([ 45 | 23.25, 46 | 13.35, 47 | pcb_zsize]) rz(-90) pin_header(2p54header, 8, 2, right_angle=true); 48 | } 49 | 50 | module button_pins() { 51 | translate([ 52 | 55, 53 | 21.6, 54 | pcb_zsize]) pin_header(2p54header, 3, 1, right_angle=true); 55 | } 56 | 57 | module power_pins() { 58 | translate([ 59 | 18.65, 60 | 64.65, 61 | pcb_zsize]) rz(-90) pin_header(2p54header, 2, 1, right_angle=true); 62 | } 63 | 64 | pcb(); 65 | pico(); 66 | rtc(); 67 | led_interface_pins(); 68 | button_pins(); 69 | power_pins(); 70 | } 71 | 72 | /* 73 | $fa=2; 74 | $fs=0.2; 75 | main_pcb(); 76 | */ 77 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/dep/main_pcb.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/case/led_matrix_64x32/dep/main_pcb.stl -------------------------------------------------------------------------------- /case/led_matrix_64x32/export/bottom_support.3mf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/case/led_matrix_64x32/export/bottom_support.3mf -------------------------------------------------------------------------------- /case/led_matrix_64x32/export/top_support.3mf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/case/led_matrix_64x32/export/top_support.3mf -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/core.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | // Include this file to use the minimum library plus screws, nuts and washers 22 | // 23 | include 24 | // 25 | // Fasteners used by a lot of other vitamins 26 | // 27 | include 28 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/global_defs.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | // This file included directly or indirectly in every scad file. 22 | // 23 | // This scheme allows the following: 24 | // bom defaults to 0 25 | // Setting $bom on the command line or in the main file before including lib.scad overrides it everywhere. 26 | // Setting $bom after including lib overrides bom in the libs but not in the local file. 27 | // Setting $_bom in the local file overrides it in the local file but not in the libs. 28 | // 29 | rr_green = [0, 146/255, 0]; // RepRap logo colour 30 | crimson = [220/255, 20/255, 60/255]; 31 | 32 | $_bom = is_undef($bom) ? 0 : $bom; // 0 no bom, 1 assemblies and stls, 2 vitamins as well 33 | $exploded = is_undef($explode) ? 0 : $explode; // 1 for exploded view 34 | layer_height = is_undef($layer_height) ? 0.25 : $layer_height; // layer height when printing 35 | extrusion_width = is_undef($extrusion_width) ? 0.5 : $extrusion_width; // filament width when printing 36 | nozzle = is_undef($nozzle) ? 0.45 : $nozzle; // 3D printer nozzle 37 | cnc_bit_r = is_undef($cnc_bit_r) ? 1.2 : $cnc_bit_r; // minimum tool radius when milling 2D objects 38 | pp1_colour = is_undef($pp1_colour) ? rr_green : $pp1_colour; // printed part colour 1, RepRap logo colour 39 | pp2_colour = is_undef($pp2_colour) ? crimson : $pp2_colour; // printed part colour 2 40 | pp3_colour = is_undef($pp3_colour) ? "SteelBlue" : $pp3_colour; // printed part colour 3 41 | pp4_colour = is_undef($pp4_colour) ? "darkorange" : $pp4_colour;// printed part colour 4 42 | show_rays = is_undef($show_rays) ? false : $show_rays; // show camera sight lines and light direction 43 | show_threads = is_undef($show_threads) ? false : $show_threads; // show screw threads 44 | 45 | // Minimum wall is about two filaments wide but we extrude it closer to get better bonding 46 | squeezed_wall = $preview ? 2 * extrusion_width - layer_height * (1 - PI / 4) 47 | : extrusion_width - layer_height / 2 + nozzle / 2 + extrusion_width / 2; 48 | 49 | inf = 1e10; // very big 50 | eps = 1/128; // small fudge factor to stop CSG barfing on coincident faces. 51 | $fa = 6; 52 | $fs = extrusion_width / 2; 53 | 54 | function round_to_layer(z) = ceil(z / layer_height) * layer_height; 55 | // Some additional named colours 56 | function grey(n) = [0.01, 0.01, 0.01] * n; //! Generate a shade of grey to pass to color(). 57 | silver = [0.75, 0.75, 0.75]; 58 | gold = [255, 215, 0] / 255; 59 | brass = [255, 220, 100] / 255; 60 | copper = [230, 140, 51] / 255; 61 | 62 | /* 63 | * Enums 64 | */ 65 | // 66 | // Screws 67 | // 68 | hs_cap = 0; 69 | hs_pan = 1; 70 | hs_cs = 2; // counter sunk 71 | hs_hex = 3; 72 | hs_grub = 4; // pulley set screw 73 | hs_cs_cap = 5; 74 | hs_dome = 6; 75 | // 76 | // Hot end descriptions 77 | // 78 | jhead = 1; 79 | e3d = 2; 80 | // 81 | // Face enumeration 82 | // 83 | f_bottom = 0; 84 | f_top = 1; 85 | f_left = 2; 86 | f_right = 3; 87 | f_front = 4; 88 | f_back = 5; 89 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/utils/core/clip.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Construct arbitrarily large box to partition 3D space and clip objects, useful for creating cross sections to see the inside when debugging. 22 | //! 23 | //! Original version by Doug Moen on the OpenSCAD forum 24 | // 25 | // 26 | module box(xmin, ymin, zmin, xmax, ymax, zmax) //! Construct a box given its bounds 27 | polyhedron( 28 | [[xmin, ymin, zmin], // 0 29 | [xmin, ymin, zmax], // 1 30 | [xmin, ymax, zmin], // 2 31 | [xmin, ymax, zmax], // 3 32 | [xmax, ymin, zmin], // 4 33 | [xmax, ymin, zmax], // 5 34 | [xmax, ymax, zmin], // 6 35 | [xmax, ymax, zmax]], // 7 36 | [[7,5,1,3], // top 37 | [2,0,4,6], // bottom 38 | [5,4,0,1], // front 39 | [3,2,6,7], // back 40 | [5,7,6,4], // right 41 | [0,2,3,1]] // left 42 | ); 43 | 44 | module clip(xmin = -inf, ymin = -inf, zmin = -inf, xmax = inf, ymax = inf, zmax = inf) //! Clip child to specified boundaries 45 | render() intersection() { 46 | children(); 47 | 48 | box(xmin, ymin, zmin, xmax, ymax, zmax); 49 | } 50 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/utils/core/core.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | // Include this file to use the minimum library 22 | // 23 | include <../../global_defs.scad> 24 | // 25 | // Global functions and modules 26 | // 27 | use 28 | 29 | module use_stl(name) { //! Import an STL to make a build platter 30 | stl(name); 31 | path = is_undef($target) ? "../stls/" : str($cwd, "/", $target, "/stls/"); 32 | import(str(path, name, ".stl")); 33 | } 34 | 35 | module use_dxf(name) { //! Import a DXF to make a build panel 36 | dxf(name); 37 | path = is_undef($target) ? "../dxfs/" : str($cwd, "/", $target, "/dxfs/"); 38 | import(str(path, name, ".dxf")); 39 | } 40 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/utils/core/global.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Global constants, functions and modules. This file is used directly or indirectly in every scad file. 22 | // 23 | include <../../global_defs.scad> 24 | 25 | function inch(x) = x * 25.4; //! Inch to mm conversion (For fractional inches, 'inch(1 + 7/8)' will work as expected.) 26 | function foot(x) = x * 25.4 * 12; //! Foot to mm conversion 27 | function yard(x) = x * 25.4 * 12 * 3; //! Yard to mm conversion 28 | function mm(x) = x; //! Explicit mm specified 29 | function cm(x) = x * 10.0; //! cm to mm conversion 30 | function m(x) = x * 1000.0; //! m to mm conversion 31 | 32 | function sqr(x) = x * x; //! Returns the square of `x` 33 | function echoit(x) = echo(x) x; //! Echo expression and return it, useful for debugging 34 | function no_point(str) = chr([for(c = str(str)) if(c == ".") ord("p") else ord(c)]);//! Replace decimal point in string with 'p' 35 | function in(list, x) = !!len([for(v = list) if(v == x) true]); //! Returns true if `x` is an element in the `list` 36 | function Len(x) = is_list(x) ? len(x) : 0; //! Returns the length of a list or 0 if `x` is not a list 37 | function r2sides(r) = $fn ? $fn : ceil(max(min(360/ $fa, r * 2 * PI / $fs), 5)); //! Replicates the OpenSCAD logic to calculate the number of sides from the radius 38 | function r2sides4n(r) = floor((r2sides(r) + 3) / 4) * 4; //! Round up the number of sides to a multiple of 4 to ensure points land on all axes 39 | function limit(x, min, max) = max(min(x, max), min); //! Force x in range min <= x <= max 40 | 41 | module translate_z(z) translate([0, 0, z]) children(); //! Shortcut for Z only translations 42 | module vflip(flip=true) rotate([flip ? 180 : 0, 0, 0]) children(); //! Invert children by doing a 180° flip around the X axis 43 | module hflip(flip=true) rotate([0, flip ? 180: 0, 0]) children(); //! Invert children by doing a 180° flip around the Y axis 44 | module ellipse(xr, yr) scale([1, yr / xr]) circle4n(xr); //! Draw an ellipse 45 | 46 | function slice_str(str, start, end, s ="") = start >= end ? s : slice_str(str, start + 1, end, str(s, str[start])); // Helper for slice() 47 | 48 | function slice(list, start = 0, end = undef) = let( //! Slice a list or string with Python type semantics 49 | len = len(list), 50 | start = limit(start < 0 ? len + start : start, 0, len), 51 | end = is_undef(end) ? len : limit(end < 0 ? len + end : end, 0, len) 52 | ) is_string(list) ? slice_str(list, start, end) : [for(i = [start : 1 : end - 1]) list[i]]; 53 | 54 | 55 | module render_if(render = true, convexity = 2) //! Renders an object if `render` is true, otherwise leaves it unrendered 56 | if (render) 57 | render(convexity = convexity) 58 | children(); 59 | else 60 | children(); 61 | 62 | module extrude_if(h, center = true) //! Extrudes 2D object to 3D when `h` is nonzero, otherwise leaves it 2D 63 | if(h) 64 | linear_extrude(h, center = center, convexity = 2) // 3D 65 | children(); 66 | else 67 | children(); // 2D 68 | 69 | module circle4n(r, d = undef) { //! Circle with multiple of 4 vertices 70 | R = is_undef(d) ? r : d / 2; 71 | circle(R, $fn = r2sides4n(R)); 72 | } 73 | 74 | module semi_circle(r, d = undef) //! A semi circle in the positive Y domain 75 | intersection() { 76 | R = is_undef(d) ? r : d / 2; 77 | circle4n(R); 78 | 79 | sq = R + 1; 80 | translate([-sq, 0]) 81 | square([2 * sq, sq]); 82 | } 83 | 84 | module right_triangle(width, height, h, center = true) //! A right angled triangle with the 90° corner at the origin. 3D when `h` is nonzero, otherwise 2D 85 | extrude_if(h, center = center) 86 | polygon(points = [[0,0], [width, 0], [0, height]]); 87 | 88 | include 89 | include 90 | include 91 | include 92 | include 93 | include 94 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/utils/core/rounded_rectangle.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Rectangle with rounded corners. 22 | // 23 | module rounded_square(size, r, center = true) //! Like `square()` but with with rounded corners 24 | { 25 | assert(r < min(size.x, size.y) / 2); 26 | $fn = r2sides4n(r); 27 | offset(r) offset(-r) square(size, center = center); 28 | } 29 | 30 | module rounded_rectangle(size, r, center = false, xy_center = true) //! Like `cube()` but corners rounded in XY plane and separate centre options for xy and z. 31 | { 32 | extrude_if(size.z, center = center) 33 | rounded_square([size.x, size.y], r, xy_center); 34 | } 35 | 36 | module rounded_cube_xy(size, r = 0, xy_center = false, z_center = false) //! Like `cube()` but corners rounded in XY plane and separate centre options for xy and z. 37 | { 38 | extrude_if(size.z, center = z_center) 39 | rounded_square([size.x, size.y], r, xy_center); 40 | } 41 | 42 | module rounded_cube_xz(size, r = 0, xy_center = false, z_center = false) //! Like `cube()` but corners rounded in XZ plane and separate centre options for xy and z. 43 | { 44 | translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, z_center ? 0 : size.z / 2]) 45 | rotate([90, 0, 0]) 46 | rounded_cube_xy([size.x, size.z, size.y], r, xy_center = true, z_center = true); 47 | } 48 | 49 | module rounded_cube_yz(size, r = 0, xy_center = false, z_center = false) //! Like `cube()` but corners rounded in YX plane and separate centre options for xy and z. 50 | { 51 | translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, z_center ? 0 : size.z / 2]) 52 | rotate([90, 0, 90]) 53 | rounded_cube_xy([size.y, size.z, size.x], r, xy_center = true, z_center = true); 54 | } 55 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/utils/core/sphere.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | //! Redefines `sphere()` to always have a vertex on all six half axes I.e. vertices at the poles and the equator and `$fn` a multiple of four. 21 | //! This ensures `hull` and `minkowski` results have the correct dimensions when spheres are placed at the corners. 22 | 23 | module sphere(r = 1, d = undef) { //! Override `sphere` so that has vertices on all three axes. Has the advantage of giving correct dimensions when hulled 24 | R = is_undef(d) ? r : d / 2; 25 | rotate_extrude($fn = r2sides4n(R)) 26 | rotate(-90) 27 | semi_circle(R); 28 | } 29 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/utils/dogbones.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! When square holes are cut with a CNC bit they get rounded corners. If it is important that 22 | //! a square cornered part fits in the hole then circles are placed in the corners making a bone shape. 23 | // 24 | include <../utils/core/core.scad> 25 | 26 | module dogbone_square(size, r = cnc_bit_r, center = true, x_offset, y_offset) //! Square with circles at the corners, with optional offsets 27 | { 28 | x_offset = is_undef(x_offset) ? r / sqrt(2) : x_offset; 29 | y_offset = is_undef(y_offset) ? r / sqrt(2) : y_offset; 30 | 31 | union() { 32 | square(size, center = center); 33 | 34 | if(r > 0) { 35 | origin = center ? [0, 0] : size / 2; 36 | 37 | for(x = [-1, 1], y = [-1, 1]) 38 | translate(origin + [x * (size.x / 2 - x_offset), y * (size.y / 2 - y_offset)]) 39 | drill(r, 0); 40 | } 41 | } 42 | } 43 | 44 | module dogbone_rectangle(size, r = cnc_bit_r, center = true, xy_center = true, x_offset, y_offset) //! Rectangle with cylinders at the corners 45 | { 46 | extrude_if(h = size.z, center = center) 47 | dogbone_square([size.x, size.y], r, xy_center, x_offset, y_offset); 48 | } 49 | 50 | module dogbone_rectangle_x(size, r = cnc_bit_r, center = true, xy_center = true) //! Rectangle with cylinders at the corners, offset in the x direction 51 | { 52 | dogbone_rectangle(size = size, r = r, center = center, x_offset = 0, y_offset = r); 53 | } 54 | 55 | module dogbone_rectangle_y(size, r = cnc_bit_r, center = true, xy_center = true) //! Rectangle with cylinders at the corners, offset in the y direction 56 | { 57 | dogbone_rectangle(size = size, r = r, center = center, x_offset = r, y_offset = 0); 58 | } 59 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/utils/fillet.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Rounded fillet for adding to corners. 22 | // 23 | include <../utils/core/core.scad> 24 | 25 | module fillet(r, h, center = false) //! Fillet with specified radius and height 26 | extrude_if(h, center = center) 27 | difference() { 28 | translate([-eps, -eps, 0]) 29 | square(r + eps); 30 | 31 | translate([r, r]) 32 | circle(r + eps); 33 | } 34 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/utils/quadrant.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Square with one rounded corner. 22 | // 23 | include <../utils/core/core.scad> 24 | 25 | module quadrant(w, r, center = false) { //! Draw a square with one rounded corner, can be centered on the arc centre, when `center` is `true`. 26 | h = is_list(w) ? w.y : w; 27 | w = is_list(w) ? w.x : w; 28 | offset_w = center ? r - w : 0; 29 | offset_h = center ? r - h : 0; 30 | translate([offset_w, offset_h]) 31 | hull() { 32 | intersection() { 33 | translate([w - r, h - r]) 34 | circle4n(r); 35 | 36 | square([w, h]); 37 | } 38 | 39 | square([w, eps]); 40 | 41 | square([eps, h]); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/utils/rounded_cylinder.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Cylinder with a rounded end. 22 | // 23 | include <../utils/core/core.scad> 24 | 25 | module rounded_corner(r, h, r2, ir = 0) { //! 2D version 26 | assert(ir <= r - r2); 27 | 28 | translate([ir , 0]) 29 | hull() { 30 | square([eps, h]); 31 | 32 | square([r - ir, eps]); 33 | 34 | translate([r - r2 - ir, h - r2]) 35 | intersection() { 36 | circle4n(r2, $fs = 0.2); 37 | 38 | square(r2); 39 | } 40 | } 41 | } 42 | 43 | module rounded_cylinder(r, h, r2, ir = 0, angle = 360) //! Rounded cylinder given radius `r`, height `h`, optional internal radius `ir` and optional `angle` 44 | { 45 | rotate_extrude(angle = angle) 46 | rounded_corner(r, h, r2, ir); 47 | } 48 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/utils/tube.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! Simple tube or ring 22 | // 23 | include <../utils/core/core.scad> 24 | 25 | module ring(or, ir) //! Create a ring with specified external and internal radii 26 | difference() { 27 | circle4n(or); 28 | circle4n(ir); 29 | } 30 | 31 | module tube(or, ir, h, center = true) //! Create a tube with specified external and internal radii and height `h` 32 | linear_extrude(h, center = center, convexity = 5) 33 | ring(or, ir); 34 | 35 | module woven_tube(or, ir, h, center= true, colour = grey(30), colour2, warp = 2, weft) {//! Create a woven tube with specified external and internal radii, height `h`, colours, warp and weft 36 | colour2 = colour2 ? colour2 : colour * 0.8; 37 | weft = weft ? weft : warp; 38 | warp_count = max(floor(PI * or / warp), 0.5); 39 | angle = 360 / (2 * warp_count); 40 | 41 | module layer(weft) { 42 | points = [[ir, weft / 2], [or, weft / 2], [or, -weft / 2], [ir, -weft / 2]]; 43 | color(colour) 44 | for (i = [0 : warp_count]) 45 | rotate(2 * i * angle) 46 | rotate_extrude(angle = angle) 47 | polygon(points); 48 | color(colour2) 49 | for (i = [0 : warp_count]) 50 | rotate((2 * i + 1) * angle) 51 | rotate_extrude(angle = angle) 52 | polygon(points); 53 | } 54 | 55 | translate_z(center ? -h / 2 : 0) { 56 | weft_count = floor(h / weft); 57 | if (weft_count > 0) 58 | for (i = [0 : weft_count - 1]) { 59 | translate_z(i * weft + weft / 2) 60 | rotate(i * angle) 61 | layer(weft); 62 | } 63 | remainder = h - weft * weft_count; 64 | if (remainder) { 65 | translate_z(weft_count * weft + remainder / 2) 66 | rotate(weft_count * angle) 67 | layer(remainder); 68 | } 69 | } 70 | } 71 | 72 | module rectangular_tube(size, center = true, thickness = 1, fillet = 0.5) { //! Create a rectangular tube with filleted corners 73 | extrude_if(size.z, center = center) 74 | difference() { 75 | rounded_square([size.x, size.y], fillet); 76 | rounded_square([size.x - 2 * thickness, size.y - 2 * thickness], fillet); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/vitamins/button.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | //! PCB mounted buttons. Can optionally have a coloured cap 22 | // 23 | include <../utils/core/core.scad> 24 | use <../utils/rounded_cylinder.scad> 25 | 26 | function square_button_width(type) = type[1]; //! Width and depth of the base 27 | function square_button_height(type) = type[2]; //! Height of the base 28 | function square_button_wall(type) = type[3]; //! Offset of the metal part 29 | function square_button_rivit(type) = type[4]; //! Size of the corner rivets 30 | function square_button_d(type) = type[5]; //! Button diameter 31 | function square_button_h(type) = type[6]; //! Height of the button above the PCB 32 | function square_button_cap_flange_d(type) = type[7]; //! Diameter of the flange of the cap 33 | function square_button_cap_d(type) = type[8]; //! Diameter of the body of the cap 34 | function square_button_cap_h(type) = type[9]; //! Height of the cap including the stem 35 | function square_button_cap_stem(type) = type[10]; //! Length of the cap stem 36 | function square_button_cap_flange_h(type) = type[11]; //! Height of the cap flange 37 | 38 | module square_button(type, colour = "yellow") { //! Draw square button with specified cap colour if it has a cap 39 | w = square_button_width(type); 40 | flange_d = square_button_cap_flange_d(type); 41 | vitamin(str("square_button(", type[0], flange_d ? str(", \"", colour, "\"") : "", "): Square button ", w, "mm", 42 | flange_d ? str(" with ", colour, " cap") : "")); 43 | h = square_button_height(type); 44 | wall = square_button_wall(type); 45 | rivit = square_button_rivit(type); 46 | pitch = (w/ 2 - wall - rivit * 0.75); 47 | stem = square_button_cap_stem(type); 48 | 49 | color(grey(20)) { 50 | rounded_rectangle([w, w, h - 0.5], r = wall); 51 | 52 | for(x = [-1, 1], y = [-1, 1]) 53 | translate([x * pitch, y * pitch]) 54 | cylinder(d = rivit, h = h); 55 | 56 | cylinder(d = square_button_d(type), h = square_button_h(type)); 57 | } 58 | 59 | color("silver") 60 | translate_z(h - 0.5) 61 | rounded_rectangle([w - 2 * wall, w - 2 * wall, 0.2], r = wall, center = true); 62 | 63 | if(flange_d) 64 | translate_z(square_button_h(type)) 65 | color(colour) rotate_extrude() { 66 | square([square_button_d(type) / 2, stem]); 67 | 68 | translate([0, stem]) { 69 | square([flange_d / 2, square_button_cap_flange_h(type)]); 70 | 71 | rounded_corner(r = square_button_cap_d(type) / 2, h = square_button_cap_h(type) - stem, r2 = 0.5); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/vitamins/buttons.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | // w h w r b b c c c c c 22 | // i e a i u u a a a a a 23 | // d i l v t t p p p p p 24 | // t g l i 25 | // h h t d h f d h s f 26 | // d t h 27 | button_12mm = ["button_12mm", 12, 4.0, 0.8, 1.5, 6.8, 4.3, 12.86, 11.44, 8.15, 2.7, 1.4]; 28 | button_6mm = ["button_6mm", 6, 4.0, 0.2, 1.0, 3.5, 5.0, 0]; 29 | button_4p5mm= ["button_4p5mm", 4.5, 3.1, 0.1, 0.9, 2.4, 4.5, 0]; 30 | 31 | buttons = [button_4p5mm, button_6mm, button_12mm]; 32 | 33 | use 34 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/vitamins/inserts.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | // Threaded inserts 22 | // 23 | // l o h s b r r r 24 | // e u o c a i i i 25 | // n t l r r n n n 26 | // g e e e r g g g 27 | // t r w e 1 2 3 28 | // h d l 29 | // d d h d d 30 | // d 31 | // 32 | F1BM2 = [ "F1BM2", 4.0, 3.6, 3.2, 2, 3.0, 1.0, 3.4, 3.1 ]; 33 | F1BM2p5 = [ "F1BM2p5", 5.8, 4.6, 4.0, 2.5, 3.65, 1.6, 4.4, 3.9 ]; 34 | F1BM3 = [ "F1BM3", 5.8, 4.6, 4.0, 3, 3.65, 1.6, 4.4, 3.9 ]; 35 | F1BM4 = [ "F1BM4", 8.2, 6.3, 5.6, 4, 5.15, 2.3, 6.0, 5.55 ]; 36 | 37 | inserts = [ F1BM2, F1BM2p5, F1BM3, F1BM4 ]; 38 | 39 | use 40 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/vitamins/nuts.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | include 20 | // 21 | // Nuts 22 | // 23 | M2_nut_trap_depth = 2.5; 24 | M2p5_nut_trap_depth = 2.5; 25 | M3_nut_trap_depth = 3; 26 | M4_nut_trap_depth = 4; 27 | M5_nut_depth = 4; 28 | M6_nut_depth = 5; 29 | M8_nut_depth = 6.5; 30 | 31 | // s r t n w t t 32 | // c a h y a r h 33 | // r d i l s a r 34 | // e i c o h p e 35 | // w u k c e d 36 | // s n r d 37 | // e t e p 38 | // s h p i 39 | // s k t t 40 | // h c 41 | // h 42 | M2_nut = ["M2_nut", 2, 4.9, 1.6, 2.4, M2_washer, M2_nut_trap_depth, 0]; 43 | M2p5_nut = ["M2p5_nut", 2.5, 5.8, 2.2, 3.8, M2p5_washer, M2p5_nut_trap_depth, 0]; 44 | M3_nut = ["M3_nut", 3, 6.4, 2.4, 4, M3_washer, M3_nut_trap_depth, 0]; 45 | M4_nut = ["M4_nut", 4, 8.1, 3.2, 5, M4_washer, M4_nut_trap_depth, 0]; 46 | M5_nut = ["M5_nut", 5, 9.2, 4, 6.25, M5_washer, M5_nut_depth, 0]; 47 | M6_nut = ["M6_nut", 6, 11.5, 5, 8, M6_washer, M6_nut_depth, 0]; 48 | M6_half_nut = ["M6_half_nut", 6, 11.5, 3, 8, M6_washer, 3, 0]; 49 | M8_nut = ["M8_nut", 8, 15, 6.5, 8, M8_washer, M8_nut_depth, 0]; 50 | toggle_nut = ["toggle_nut", 6.1, 9.2, 1.5, 1.5, M6_washer, 1.5, inch(1/40)]; 51 | 52 | M4_wingnut = ["M4_wingnut", 4, 10, 3.75,8, M4_washer, 0, 22, 10, 6, 3]; 53 | // sx ty1 ty2 hammer 54 | M3_sliding_t_nut = ["M3_sliding_t_nut", 3, 6, 3.0, 4.0, false, 0, 10, 10, 6, false]; 55 | M4_sliding_t_nut = ["M4_sliding_t_nut", 4, 6, 3.25,4.5, false, 0, 11, 10, 6, false]; 56 | M5_sliding_t_nut = ["M5_sliding_t_nut", 5, 6, 3.25,4.5, false, 0, 11, 10, 7, false]; 57 | M3_hammer_nut = ["M3_hammer_nut", 3, 6, 2.75,4.0, false, 0, 5.5, 10, 6, true]; 58 | M4_hammer_nut = ["M4_hammer_nut", 4, 6, 3.25,4.5, false, 0, 5.5, 10, 6, true]; 59 | 60 | // DIN 562 (thin) square nuts 61 | // s w h 62 | // c i e 63 | // r d i 64 | // e t g 65 | // w h h 66 | // t 67 | // 68 | M3nS_thin_nut = ["M3nS_thin_nut", 3, 5.5, 1.8]; 69 | M4nS_thin_nut = ["M4nS_thin_nut", 4, 7, 2.2]; 70 | M5nS_thin_nut = ["M5nS_thin_nut", 5, 8, 2.7]; 71 | M6nS_thin_nut = ["M6nS_thin_nut", 6, 10, 3.2]; 72 | M8nS_thin_nut = ["M8nS_thin_nut", 8, 13, 4]; 73 | 74 | nuts = [M2_nut, M2p5_nut, M3_nut, M4_nut, M5_nut, M6_nut, M8_nut]; 75 | 76 | use 77 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/vitamins/pin_headers.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // p p b p p b s b b p r r 21 | // i i e i i a o o o i a a 22 | // t n l n n s c x x n 23 | // c o e k b h 24 | // h l w w c s t y 25 | // c h z o 26 | // f 27 | 2p54header = ["2p54header", 2.54, 11.6, 3.2, 0.66, gold, grey(20), 8.5, [0, 0, 8.7], 2.4, 0, 0, 0 ]; 28 | 2p54joiner = ["2p54joiner", 2.54, 6.86, 2.5, 0.66, gold, grey(20), 8.5, [0, 0, 8.7], 2.4, 0, 0, 0 ]; // Cropped pins for joining PCBs 29 | 30 | jst_xh_header = ["jst_xh_header",2.5, 10, 3.4, 0.64, gold, grey(90), 0, [4.9, 5.75, 7], 0.8, 0.525, 0.6, 6.1]; 31 | jst_ph_header = ["jst_ph_header",2.0, 9, 3.4, 0.64, silver, grey(90), 0, [3.9, 4.5, 6], 0.6, 0.55, 0.25, 4.8]; 32 | 33 | pin_headers = [ 2p54header ]; 34 | 35 | use 36 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/NopSCADlib/vitamins/washers.scad: -------------------------------------------------------------------------------- 1 | // 2 | // NopSCADlib Copyright Chris Palmer 2018 3 | // nop.head@gmail.com 4 | // hydraraptor.blogspot.com 5 | // 6 | // This file is part of NopSCADlib. 7 | // 8 | // NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the 9 | // GNU General Public License as published by the Free Software Foundation, either version 3 of 10 | // the License, or (at your option) any later version. 11 | // 12 | // NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 | // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | // See the GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along with NopSCADlib. 17 | // If not, see . 18 | // 19 | 20 | // 21 | // Washers 22 | // 23 | // s d t s s s s p 24 | // c i h o t p p e 25 | // r a i f a r r n 26 | // e m c t r i i n 27 | // w e k n n y 28 | // t n d g g 29 | // e e i v 30 | // r s a d t e 31 | // s i h r 32 | // a k 33 | M3_penny_washer = ["M3_penny", 3, 12, 0.8, false, 5.8, 5.6, 1.0, true]; 34 | M4_penny_washer = ["M4_penny", 4, 14, 0.8, false, 7.9, 7.0, 1.2, true]; 35 | M5_penny_washer = ["M5_penny", 5, 20, 1.4, false, 9.0, 8.8, 1.6, true]; 36 | M6_penny_washer = ["M6_penny", 6, 26, 1.5, false, 10.6, 9.9, 1.6, true]; 37 | M8_penny_washer = ["M8_penny", 8, 30, 1.5, false, 13.8, 12.7, 2.0, true]; 38 | 39 | M2_washer = ["M2", 2, 5, 0.3, false, 4.5, 4.4, 0.5, undef]; 40 | M2p5_washer = ["M2p5", 2.5, 5.9, 0.5, false, 5.4, 5.1, 0.6, undef]; 41 | M3_washer = ["M3", 3, 7, 0.5, false, 5.8, 5.6, 1.0, M3_penny_washer]; 42 | M3p5_washer = ["M3p5", 3.5, 8, 0.5, false, 6.9, 6.2, 1.0, undef]; 43 | M4_washer = ["M4", 4, 9, 0.8, false, 7.9, 7.0, 1.2, M4_penny_washer]; 44 | M5_washer = ["M5", 5, 10, 1.0, false, 9.0, 8.8, 1.6, M5_penny_washer]; 45 | M6_washer = ["M6", 6, 12.5, 1.5, false, 10.6, 9.9, 1.6, M6_penny_washer]; 46 | M8_washer = ["M8", 8, 17, 1.6, false, 13.8, 12.7, 2.0, M8_penny_washer]; 47 | toggle_washer = ["toggle", 6.1,12, 0.6, false, 10, 0, 0, undef]; 48 | 49 | M3_rubber_washer= ["M3_rubber",3, 10, 1.5, true, 5.8, M3_penny_washer]; 50 | 51 | washers = [M2_washer, M2p5_washer, M3_washer, M3p5_washer, M4_washer, M5_washer, M6_washer, M8_washer, M3_rubber_washer]; 52 | 53 | use 54 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/mattwach/honeycomb.scad: -------------------------------------------------------------------------------- 1 | // Implements a honeycomb grid 2 | 3 | module honeycomb(size, side_width, gap) { 4 | xsize = size[0]; 5 | ysize = size[1]; 6 | zsize = size[2]; 7 | span = side_width + gap; 8 | 9 | xsteps = floor(xsize / span); 10 | ysteps = floor(ysize / span); 11 | 12 | module hexagon() { 13 | r = side_width * 0.5 / cos(30); 14 | linear_extrude(zsize) 15 | polygon([ for (a = [0:60:360]) [cos(a) * r, sin(a) * r]]); 16 | } 17 | 18 | translate([ 19 | -cos(30) * span * xsteps / 2, 20 | span * (-sin(30) * xsteps - ysteps) / 2, 21 | 0 22 | ]) 23 | for (x = [0:xsteps]) { 24 | translate([cos(30) * span * x, sin(30) * span * x, 0]) 25 | for (y = [0:ysteps]) { 26 | translate([0, y * span, 0]) hexagon(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/mattwach/util.scad: -------------------------------------------------------------------------------- 1 | module tx(x) translate([x,0,0]) children(); 2 | module ty(y) translate([0,y,0]) children(); 3 | module tz(z) translate([0,0,z]) children(); 4 | 5 | // Planes 6 | module txy(x, y) translate([x,y,0]) children(); 7 | module txz(x, z) translate([x,0,z]) children(); 8 | module tyz(y, z) translate([0,y,z]) children(); 9 | 10 | module boardxy(x, y, pin_spacing=2.54) { 11 | translate([x * pin_spacing, y * pin_spacing,0]) children(); 12 | } 13 | 14 | 15 | module rx(x) rotate([x,0,0]) children(); 16 | module ry(y) rotate([0,y,0]) children(); 17 | module rz(z) rotate([0,0,z]) children(); 18 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/mattwach/vitamins/electronics/cr2032_battery.scad: -------------------------------------------------------------------------------- 1 | use <../../util.scad> 2 | 3 | CR2032_DIAMETER = 20; 4 | CR2032_THICKNESS = 3.2; 5 | 6 | module cr2032() { 7 | negative_diameter = 17.7; 8 | negative_height = 0.3; 9 | overlap = 0.01; 10 | marker_thickness = 0.5; 11 | marker_length = 5; 12 | marker_depth = 0.1; 13 | module cell() { 14 | color("silver") union() { 15 | cylinder(d=negative_diameter, h=negative_height + overlap); 16 | tz(negative_height) cylinder(d=CR2032_DIAMETER, h=CR2032_THICKNESS-negative_height); 17 | } 18 | } 19 | 20 | module positive_marker() { 21 | color("#aaa") union() { 22 | translate([ 23 | -marker_length / 2, 24 | -marker_thickness / 2, 25 | CR2032_THICKNESS - marker_depth + overlap 26 | ]) cube([marker_length, marker_thickness, marker_depth]); 27 | translate([ 28 | -marker_thickness / 2, 29 | -marker_length / 2, 30 | CR2032_THICKNESS - marker_depth + overlap 31 | ]) cube([marker_thickness, marker_length, marker_depth]); 32 | } 33 | } 34 | 35 | module negative_marker() { 36 | color("#aaa") translate([ 37 | -marker_length / 2, 38 | -marker_thickness / 2, 39 | -overlap 40 | ]) cube([marker_length, marker_thickness, marker_depth]); 41 | } 42 | 43 | difference() { 44 | cell(); 45 | negative_marker(); 46 | positive_marker(); 47 | } 48 | } 49 | 50 | /* 51 | $fa=2; 52 | $fs=0.5; 53 | cr2032(); 54 | */ 55 | -------------------------------------------------------------------------------- /case/led_matrix_64x32/lib/mattwach/vitamins/electronics/led_panel_64x32.scad: -------------------------------------------------------------------------------- 1 | use <../../util.scad> 2 | 3 | LED_PANEL_64_32_BACK_LENGTH = 253; 4 | LED_PANEL_64_32_BACK_WIDTH = 125.8; 5 | LED_PANEL_64_32_FRONT_LENGTH = 256; 6 | LED_PANEL_64_32_FRONT_WIDTH = 128; 7 | LED_PANEL_64_32_THICKNESS = 14; 8 | 9 | LED_PANEL_64_32_BOLT_HOLE_WSPAN = 112; 10 | LED_PANEL_64_32_BOLT_HOLE_WOFFSET = ( 11 | LED_PANEL_64_32_BACK_WIDTH - LED_PANEL_64_32_BOLT_HOLE_WSPAN) / 2; 12 | LED_PANEL_64_32_BOLT_HOLE_LSPAN = 120; 13 | LED_PANEL_64_32_BOLT_HOLE_LOFFSET = 14 | LED_PANEL_64_32_BACK_LENGTH / 2 - LED_PANEL_64_32_BOLT_HOLE_LSPAN; 15 | 16 | 17 | module led_panel_64x32() { 18 | overlap = 0.01; 19 | pcb_thickness = 2; 20 | side_support_thickness = 10.9; 21 | end_support_thickness = 10.7; 22 | inner_support_thinkness = 12; 23 | center_support_thickness = 13.8; 24 | 25 | end_cutout_xsize = 45.9; 26 | inner_cutout_width = LED_PANEL_64_32_BACK_WIDTH - (side_support_thickness * 2); 27 | cutout_depth = LED_PANEL_64_32_THICKNESS - pcb_thickness + overlap; 28 | 29 | inner_cutout_xsize = 30 | (LED_PANEL_64_32_BACK_LENGTH - 31 | end_support_thickness * 2 - 32 | inner_support_thinkness * 2 - 33 | end_cutout_xsize * 2 - 34 | center_support_thickness) / 2; 35 | 36 | module shell() { 37 | xoffset = (LED_PANEL_64_32_BACK_LENGTH - LED_PANEL_64_32_FRONT_LENGTH) / 2; 38 | yoffset = (LED_PANEL_64_32_BACK_WIDTH - LED_PANEL_64_32_FRONT_WIDTH) / 2; 39 | 40 | hull() { 41 | cube([ 42 | LED_PANEL_64_32_BACK_LENGTH, 43 | LED_PANEL_64_32_BACK_WIDTH, 44 | overlap]); 45 | translate([ 46 | xoffset, 47 | yoffset, 48 | LED_PANEL_64_32_THICKNESS - pcb_thickness]) cube([ 49 | LED_PANEL_64_32_FRONT_LENGTH, 50 | LED_PANEL_64_32_FRONT_WIDTH, 51 | pcb_thickness]); 52 | } 53 | } 54 | 55 | module end_cutout() { 56 | cutout_bump_span = 90; 57 | 58 | module main_cutout() { 59 | translate([ 60 | end_support_thickness, 61 | side_support_thickness, 62 | -overlap]) cube([ 63 | end_cutout_xsize, 64 | inner_cutout_width, 65 | cutout_depth]); 66 | } 67 | 68 | module slanted_cutout() { 69 | slanted_cutout_width1 = 33.8; 70 | slanted_cutout_support_thickness = 6; 71 | slanted_cutout_width2 = slanted_cutout_width1 + (end_support_thickness - slanted_cutout_support_thickness) * 2; 72 | hull() { 73 | translate([ 74 | slanted_cutout_support_thickness, 75 | (LED_PANEL_64_32_BACK_WIDTH - slanted_cutout_width1) / 2, 76 | -overlap]) cube([ 77 | overlap, 78 | slanted_cutout_width1, 79 | cutout_depth]); 80 | translate([ 81 | end_support_thickness - overlap, 82 | (LED_PANEL_64_32_BACK_WIDTH - slanted_cutout_width2) / 2, 83 | -overlap]) cube([ 84 | overlap * 2, 85 | slanted_cutout_width2, 86 | cutout_depth]); 87 | } 88 | } 89 | 90 | module bump() { 91 | cutout_bump_diameter = 13.5; 92 | cutout_bump_offset = (LED_PANEL_64_32_BACK_WIDTH - cutout_bump_span) / 2; 93 | translate([ 94 | cutout_bump_diameter / 2, 95 | cutout_bump_offset, 96 | -overlap]) cylinder( 97 | d = cutout_bump_diameter, 98 | h = cutout_depth); 99 | } 100 | 101 | difference() { 102 | union() { 103 | main_cutout(); 104 | slanted_cutout(); 105 | } 106 | bump(); 107 | ty(cutout_bump_span) bump(); 108 | } 109 | } 110 | 111 | module middle_cutout() { 112 | translate([ 113 | end_support_thickness + end_cutout_xsize + inner_support_thinkness, 114 | side_support_thickness, 115 | -overlap]) cube([ 116 | inner_cutout_xsize, 117 | inner_cutout_width, 118 | cutout_depth]); 119 | } 120 | 121 | module bolt_holes() { 122 | module hole() { 123 | hole_diameter = 3; 124 | hole_depth = cutout_depth; 125 | tz(-overlap) cylinder(d=hole_diameter, h=hole_depth); 126 | } 127 | 128 | module hole_row() { 129 | hole(); 130 | ty(LED_PANEL_64_32_BOLT_HOLE_WSPAN) hole(); 131 | } 132 | 133 | txy(LED_PANEL_64_32_BOLT_HOLE_LOFFSET, LED_PANEL_64_32_BOLT_HOLE_WOFFSET) { 134 | hole_row(); 135 | tx(LED_PANEL_64_32_BOLT_HOLE_LSPAN) hole_row(); 136 | tx(LED_PANEL_64_32_BOLT_HOLE_LSPAN * 2) hole_row(); 137 | } 138 | } 139 | 140 | difference() { 141 | color("#444") shell(); 142 | color("#222") end_cutout(); 143 | color("#222") txy( 144 | LED_PANEL_64_32_BACK_LENGTH, 145 | LED_PANEL_64_32_BACK_WIDTH 146 | ) rz(180) end_cutout(); 147 | color("#222") middle_cutout(); 148 | color("#222") tx(inner_cutout_xsize + center_support_thickness) middle_cutout(); 149 | color("gold") bolt_holes(); 150 | } 151 | } 152 | 153 | /* 154 | $fa=2; 155 | $fs=0.5; 156 | led_panel_64x32(); 157 | */ 158 | -------------------------------------------------------------------------------- /firmware/matrix_clock_dotstar_8x8.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/firmware/matrix_clock_dotstar_8x8.uf2 -------------------------------------------------------------------------------- /firmware/matrix_clock_led_64x32.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/firmware/matrix_clock_led_64x32.uf2 -------------------------------------------------------------------------------- /images/button_hardware.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/button_hardware.jpg -------------------------------------------------------------------------------- /images/clock_set.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/clock_set.jpg -------------------------------------------------------------------------------- /images/completed_pcb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/completed_pcb.jpg -------------------------------------------------------------------------------- /images/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/console.png -------------------------------------------------------------------------------- /images/ds8x8/3d_case_underside.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/ds8x8/3d_case_underside.png -------------------------------------------------------------------------------- /images/ds8x8/3d_printed_case.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/ds8x8/3d_printed_case.png -------------------------------------------------------------------------------- /images/ds8x8/ds_matrix_clock.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/ds8x8/ds_matrix_clock.jpg -------------------------------------------------------------------------------- /images/ds8x8/matrix_clock2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/ds8x8/matrix_clock2.jpg -------------------------------------------------------------------------------- /images/ds8x8/minicom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/ds8x8/minicom.jpg -------------------------------------------------------------------------------- /images/ds8x8/numbers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/ds8x8/numbers.jpg -------------------------------------------------------------------------------- /images/ds8x8/opened_clock.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/ds8x8/opened_clock.jpg -------------------------------------------------------------------------------- /images/ds8x8/schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/ds8x8/schematic.png -------------------------------------------------------------------------------- /images/kicad_button_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/kicad_button_layout.png -------------------------------------------------------------------------------- /images/kicad_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/kicad_layout.png -------------------------------------------------------------------------------- /images/matrix_back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/matrix_back.jpg -------------------------------------------------------------------------------- /images/matrix_clock.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/matrix_clock.jpg -------------------------------------------------------------------------------- /images/matrix_only.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/matrix_only.jpg -------------------------------------------------------------------------------- /images/matrix_with_numbers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/matrix_with_numbers.jpg -------------------------------------------------------------------------------- /images/openscad_bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/openscad_bottom.png -------------------------------------------------------------------------------- /images/openscad_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/openscad_model.png -------------------------------------------------------------------------------- /images/openscad_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/openscad_top.png -------------------------------------------------------------------------------- /images/other_matrix_modes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/other_matrix_modes.jpg -------------------------------------------------------------------------------- /images/schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/images/schematic.png -------------------------------------------------------------------------------- /schematic/button_pcb_kicad/button_pcb_kicad.kicad_prl: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "active_layer": 31, 4 | "active_layer_preset": "", 5 | "auto_track_width": true, 6 | "hidden_nets": [], 7 | "high_contrast_mode": 0, 8 | "net_color_mode": 1, 9 | "opacity": { 10 | "pads": 1.0, 11 | "tracks": 1.0, 12 | "vias": 1.0, 13 | "zones": 0.6 14 | }, 15 | "ratsnest_display_mode": 0, 16 | "selection_filter": { 17 | "dimensions": true, 18 | "footprints": true, 19 | "graphics": true, 20 | "keepouts": true, 21 | "lockedItems": true, 22 | "otherItems": true, 23 | "pads": true, 24 | "text": true, 25 | "tracks": true, 26 | "vias": true, 27 | "zones": true 28 | }, 29 | "visible_items": [ 30 | 0, 31 | 1, 32 | 2, 33 | 3, 34 | 4, 35 | 5, 36 | 8, 37 | 9, 38 | 10, 39 | 11, 40 | 12, 41 | 13, 42 | 14, 43 | 15, 44 | 16, 45 | 17, 46 | 18, 47 | 19, 48 | 20, 49 | 21, 50 | 22, 51 | 23, 52 | 24, 53 | 25, 54 | 26, 55 | 27, 56 | 28, 57 | 29, 58 | 30, 59 | 32, 60 | 33, 61 | 34, 62 | 35, 63 | 36 64 | ], 65 | "visible_layers": "ffcf2ff_ffffffff", 66 | "zone_display_mode": 1 67 | }, 68 | "meta": { 69 | "filename": "button_pcb_kicad.kicad_prl", 70 | "version": 3 71 | }, 72 | "project": { 73 | "files": [] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /schematic/button_pcb_kicad/flatcam/Project_20230128_192544.FlatPrj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/schematic/button_pcb_kicad/flatcam/Project_20230128_192544.FlatPrj -------------------------------------------------------------------------------- /schematic/button_pcb_kicad/flatcam/button_pcb_kicad-NPTH.drl_cnc.nc: -------------------------------------------------------------------------------- 1 | (G-CODE GENERATED BY FLATCAM v8.994 - www.flatcam.org - Version Date: 2020/11/7) 2 | 3 | (Name: button_pcb_kicad-NPTH.drl_cnc) 4 | (Type: G-code from Geometry) 5 | (Units: MM) 6 | 7 | (Created on Saturday, 28 January 2023 at 19:33) 8 | 9 | (Specially modified by mattwach to work with the Sainsmart 3080 that I have.) 10 | 11 | 12 | (TOOLS DIAMETER: ) 13 | (Tool: 1 -> Dia: 2.2) 14 | 15 | (FEEDRATE Z: ) 16 | (Tool: 1 -> Feedrate: 180.0) 17 | 18 | (FEEDRATE RAPIDS: ) 19 | (Tool: 1 -> Feedrate Rapids: 1500) 20 | 21 | (Z_CUT: ) 22 | (Tool: 1 -> Z_Cut: -1.7) 23 | 24 | (Tools Offset: ) 25 | (Tool: 1 -> Offset Z: 0.0) 26 | 27 | (Z_MOVE: ) 28 | (Tool: 1 -> Z_Move: 2) 29 | 30 | (Z Toolchange: 15.0 mm) 31 | (X,Y Toolchange: 0.0000, 0.0000 mm) 32 | (Z Start: None mm) 33 | (Z End: 10.0 mm) 34 | (X,Y End: 0.0000, 0.0000 mm) 35 | (Steps per circle: 64) 36 | (Preprocessor Excellon: default) 37 | 38 | (X range: 1.9000 ... 40.1000 mm) 39 | (Y range: -6.1000 ... -3.9000 mm) 40 | 41 | (Spindle Speed: 10000 RPM) 42 | G21 43 | G90 44 | G17 45 | G94 46 | 47 | 48 | G01 F180.00 49 | 50 | M5 51 | G00 Z15.0000 52 | G00 X0.0000 Y0.0000 53 | G00 Z15.0000 54 | 55 | G01 F180.00 56 | M03 S10000 57 | G00 X3.0000 Y-5.0000 58 | G01 Z-1.7000 59 | G01 Z0 60 | G00 Z2.0000 61 | G00 X39.0000 Y-5.0000 62 | G01 Z-1.7000 63 | G01 Z0 64 | G00 Z2.0000 65 | M05 66 | G00 Z10.00 67 | G00 X0.0 Y0.0 68 | 69 | 70 | -------------------------------------------------------------------------------- /schematic/button_pcb_kicad/flatcam/button_pcb_kicad-PTH.drl_cnc.nc: -------------------------------------------------------------------------------- 1 | (G-CODE GENERATED BY FLATCAM v8.994 - www.flatcam.org - Version Date: 2020/11/7) 2 | 3 | (Name: button_pcb_kicad-PTH.drl_cnc) 4 | (Type: G-code from Geometry) 5 | (Units: MM) 6 | 7 | (Created on Saturday, 28 January 2023 at 19:33) 8 | 9 | (Specially modified by mattwach to work with the Sainsmart 3080 that I have.) 10 | 11 | 12 | (TOOLS DIAMETER: ) 13 | (Tool: 1 -> Dia: 1.1) 14 | 15 | (FEEDRATE Z: ) 16 | (Tool: 1 -> Feedrate: 300) 17 | 18 | (FEEDRATE RAPIDS: ) 19 | (Tool: 1 -> Feedrate Rapids: 1500) 20 | 21 | (Z_CUT: ) 22 | (Tool: 1 -> Z_Cut: -1.7) 23 | 24 | (Tools Offset: ) 25 | (Tool: 1 -> Offset Z: 0.0) 26 | 27 | (Z_MOVE: ) 28 | (Tool: 1 -> Z_Move: 2) 29 | 30 | (Z Toolchange: 10.0 mm) 31 | (X,Y Toolchange: 0.0000, 0.0000 mm) 32 | (Z Start: None mm) 33 | (Z End: 10.0 mm) 34 | (X,Y End: 0.0000, 0.0000 mm) 35 | (Steps per circle: 64) 36 | (Preprocessor Excellon: default) 37 | 38 | (X range: 14.7940 ... 33.0620 mm) 39 | (Y range: -7.4430 ... -1.8430 mm) 40 | 41 | (Spindle Speed: 10000 RPM) 42 | G21 43 | G90 44 | G17 45 | G94 46 | 47 | 48 | G01 F300.00 49 | 50 | M5 51 | G00 Z10.0000 52 | G00 X0.0000 Y0.0000 53 | G00 Z10.0000 54 | 55 | G01 F300.00 56 | M03 S10000 57 | G00 X15.3440 Y-2.3930 58 | G01 Z-1.7000 59 | G01 Z0 60 | G00 Z2.0000 61 | G00 X32.5120 Y-6.8930 62 | G01 Z-1.7000 63 | G01 Z0 64 | G00 Z2.0000 65 | G00 X32.5120 Y-2.3930 66 | G01 Z-1.7000 67 | G01 Z0 68 | G00 Z2.0000 69 | G00 X26.0120 Y-6.8930 70 | G01 Z-1.7000 71 | G01 Z0 72 | G00 Z2.0000 73 | G00 X26.0120 Y-2.3930 74 | G01 Z-1.7000 75 | G01 Z0 76 | G00 Z2.0000 77 | G00 X21.8440 Y-6.8930 78 | G01 Z-1.7000 79 | G01 Z0 80 | G00 Z2.0000 81 | G00 X21.8440 Y-2.3930 82 | G01 Z-1.7000 83 | G01 Z0 84 | G00 Z2.0000 85 | G00 X15.3440 Y-6.8930 86 | G01 Z-1.7000 87 | G01 Z0 88 | G00 Z2.0000 89 | M05 90 | G00 Z10.00 91 | G00 X0.0 Y0.0 92 | 93 | 94 | -------------------------------------------------------------------------------- /schematic/button_pcb_kicad/flatcam/test.nc: -------------------------------------------------------------------------------- 1 | (CNC Regtangle Test File) 2 | 3 | G21 (Units in MM) 4 | G90 (Absolute positioning) 5 | G94 (Units per minute feed rate mode) 6 | 7 | G01 F200 (Move to starting position) 8 | G01 Z10 9 | G00 X-1 Y1 10 | M03 S10000.0 (Start motor) 11 | G01 Z1.0 (Move to dwell height) 12 | 13 | G01 F60 (Approach material) 14 | G01 Z0.0 15 | G01 F120.0 (Draw rectangle) 16 | G01 X43 17 | G01 Y-10 18 | G01 X-1 19 | G01 Y1 20 | 21 | G01 F200 22 | G01 Z10 (Exit material) 23 | M05 (Stop motor) 24 | (Test complete, EOF) 25 | 26 | -------------------------------------------------------------------------------- /schematic/button_pcb_kicad/gerber/button_pcb_kicad-Edge_Cuts.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,6.0.9+dfsg-1*% 2 | %TF.CreationDate,2023-01-28T14:04:22-08:00*% 3 | %TF.ProjectId,button_pcb_kicad,62757474-6f6e-45f7-9063-625f6b696361,rev?*% 4 | %TF.SameCoordinates,PX791ddc0PY5e69ec0*% 5 | %TF.FileFunction,Profile,NP*% 6 | %FSLAX46Y46*% 7 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 8 | G04 Created by KiCad (PCBNEW 6.0.9+dfsg-1) date 2023-01-28 14:04:22* 9 | %MOMM*% 10 | %LPD*% 11 | G01* 12 | G04 APERTURE LIST* 13 | %TA.AperFunction,Profile*% 14 | %ADD10C,0.150000*% 15 | %TD*% 16 | G04 APERTURE END LIST* 17 | D10* 18 | X0Y0D02* 19 | X0Y-9000000D01* 20 | X42000000Y0D02* 21 | X0Y0D01* 22 | X42000000Y-9000000D02* 23 | X42000000Y0D01* 24 | X0Y-9000000D02* 25 | X42000000Y-9000000D01* 26 | M02* 27 | -------------------------------------------------------------------------------- /schematic/button_pcb_kicad/gerber/button_pcb_kicad-NPTH.drl: -------------------------------------------------------------------------------- 1 | M48 2 | ; DRILL file {KiCad 6.0.9+dfsg-1} date Sat 28 Jan 2023 02:04:25 PM PST 3 | ; FORMAT={-:-/ absolute / metric / decimal} 4 | ; #@! TF.CreationDate,2023-01-28T14:04:25-08:00 5 | ; #@! TF.GenerationSoftware,Kicad,Pcbnew,6.0.9+dfsg-1 6 | ; #@! TF.FileFunction,NonPlated,1,2,NPTH 7 | FMAT,2 8 | METRIC 9 | ; #@! TA.AperFunction,NonPlated,NPTH,ComponentDrill 10 | T1C2.200 11 | % 12 | G90 13 | G05 14 | T1 15 | X3.0Y-5.0 16 | X39.0Y-5.0 17 | T0 18 | M30 19 | -------------------------------------------------------------------------------- /schematic/button_pcb_kicad/gerber/button_pcb_kicad-PTH.drl: -------------------------------------------------------------------------------- 1 | M48 2 | ; DRILL file {KiCad 6.0.9+dfsg-1} date Sat 28 Jan 2023 02:04:25 PM PST 3 | ; FORMAT={-:-/ absolute / metric / decimal} 4 | ; #@! TF.CreationDate,2023-01-28T14:04:25-08:00 5 | ; #@! TF.GenerationSoftware,Kicad,Pcbnew,6.0.9+dfsg-1 6 | ; #@! TF.FileFunction,Plated,1,2,PTH 7 | FMAT,2 8 | METRIC 9 | ; #@! TA.AperFunction,Plated,PTH,ComponentDrill 10 | T1C1.100 11 | % 12 | G90 13 | G05 14 | T1 15 | X15.344Y-2.393 16 | X15.344Y-6.893 17 | X21.844Y-2.393 18 | X21.844Y-6.893 19 | X26.012Y-2.393 20 | X26.012Y-6.893 21 | X32.512Y-2.393 22 | X32.512Y-6.893 23 | T0 24 | M30 25 | -------------------------------------------------------------------------------- /schematic/button_pcb_kicad/gerber/button_pcb_kicad-job.gbrjob: -------------------------------------------------------------------------------- 1 | { 2 | "Header": { 3 | "GenerationSoftware": { 4 | "Vendor": "KiCad", 5 | "Application": "Pcbnew", 6 | "Version": "6.0.9+dfsg-1" 7 | }, 8 | "CreationDate": "2023-01-28T14:04:22-08:00" 9 | }, 10 | "GeneralSpecs": { 11 | "ProjectId": { 12 | "Name": "button_pcb_kicad", 13 | "GUID": "62757474-6f6e-45f7-9063-625f6b696361", 14 | "Revision": "rev?" 15 | }, 16 | "Size": { 17 | "X": 42.15, 18 | "Y": 9.15 19 | }, 20 | "LayerNumber": 2, 21 | "BoardThickness": 1.6, 22 | "Finish": "None" 23 | }, 24 | "DesignRules": [ 25 | { 26 | "Layers": "Outer", 27 | "PadToPad": 0.2, 28 | "PadToTrack": 0.2, 29 | "TrackToTrack": 0.2, 30 | "MinLineWidth": 0.4, 31 | "TrackToRegion": 0.508, 32 | "RegionToRegion": 0.508 33 | } 34 | ], 35 | "FilesAttributes": [ 36 | { 37 | "Path": "button_pcb_kicad-F_Cu.gbr", 38 | "FileFunction": "Copper,L1,Top", 39 | "FilePolarity": "Positive" 40 | }, 41 | { 42 | "Path": "button_pcb_kicad-Edge_Cuts.gbr", 43 | "FileFunction": "Profile", 44 | "FilePolarity": "Positive" 45 | } 46 | ], 47 | "MaterialStackup": [ 48 | { 49 | "Type": "Legend", 50 | "Name": "Top Silk Screen" 51 | }, 52 | { 53 | "Type": "SolderPaste", 54 | "Name": "Top Solder Paste" 55 | }, 56 | { 57 | "Type": "SolderMask", 58 | "Thickness": 0.01, 59 | "Name": "Top Solder Mask" 60 | }, 61 | { 62 | "Type": "Copper", 63 | "Thickness": 0.035, 64 | "Name": "F.Cu" 65 | }, 66 | { 67 | "Type": "Dielectric", 68 | "Thickness": 1.51, 69 | "Material": "FR4", 70 | "Name": "F.Cu/B.Cu", 71 | "Notes": "Type: dielectric layer 1 (from F.Cu to B.Cu)" 72 | }, 73 | { 74 | "Type": "Copper", 75 | "Thickness": 0.035, 76 | "Name": "B.Cu" 77 | }, 78 | { 79 | "Type": "SolderMask", 80 | "Thickness": 0.01, 81 | "Name": "Bottom Solder Mask" 82 | }, 83 | { 84 | "Type": "SolderPaste", 85 | "Name": "Bottom Solder Paste" 86 | }, 87 | { 88 | "Type": "Legend", 89 | "Name": "Bottom Silk Screen" 90 | } 91 | ] 92 | } 93 | -------------------------------------------------------------------------------- /schematic/dotstar_8x8_kicad/export/matrix_clock_kicad-Edge_Cuts.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,6.0.7+dfsg-3*% 2 | %TF.CreationDate,2022-12-10T17:15:55-08:00*% 3 | %TF.ProjectId,matrix_clock_kicad,6d617472-6978-45f6-936c-6f636b5f6b69,rev?*% 4 | %TF.SameCoordinates,PX69fa208PY4509570*% 5 | %TF.FileFunction,Profile,NP*% 6 | %FSLAX46Y46*% 7 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 8 | G04 Created by KiCad (PCBNEW 6.0.7+dfsg-3) date 2022-12-10 17:15:55* 9 | %MOMM*% 10 | %LPD*% 11 | G01* 12 | G04 APERTURE LIST* 13 | %TA.AperFunction,Profile*% 14 | %ADD10C,0.100000*% 15 | %TD*% 16 | G04 APERTURE END LIST* 17 | D10* 18 | X4875000Y-56610000D02* 19 | G75* 20 | G03* 21 | X4875000Y-56610000I-1000000J0D01* 22 | G01* 23 | X51875000Y-3610000D02* 24 | G75* 25 | G03* 26 | X51875000Y-3610000I-1000000J0D01* 27 | G01* 28 | X0Y0D02* 29 | X0Y-63500000D01* 30 | X54610000Y0D02* 31 | X0Y0D01* 32 | X54610000Y-63500000D02* 33 | X54610000Y0D01* 34 | X0Y-63500000D02* 35 | X54610000Y-63500000D01* 36 | M02* 37 | -------------------------------------------------------------------------------- /schematic/dotstar_8x8_kicad/export/matrix_clock_kicad-NPTH.drl: -------------------------------------------------------------------------------- 1 | M48 2 | ; DRILL file {KiCad 6.0.7+dfsg-3} date Sat 10 Dec 2022 05:16:35 PM PST 3 | ; FORMAT={-:-/ absolute / metric / decimal} 4 | ; #@! TF.CreationDate,2022-12-10T17:16:35-08:00 5 | ; #@! TF.GenerationSoftware,Kicad,Pcbnew,6.0.7+dfsg-3 6 | ; #@! TF.FileFunction,NonPlated,1,2,NPTH 7 | FMAT,2 8 | METRIC 9 | ; #@! TA.AperFunction,NonPlated,NPTH,ComponentDrill 10 | T1C1.500 11 | ; #@! TA.AperFunction,NonPlated,NPTH,ComponentDrill 12 | T2C1.800 13 | % 14 | G90 15 | G05 16 | T1 17 | X15.99Y-8.24 18 | X20.84Y-8.24 19 | T2 20 | X15.69Y-5.21 21 | X21.14Y-5.21 22 | T0 23 | M30 24 | -------------------------------------------------------------------------------- /schematic/dotstar_8x8_kicad/export/matrix_clock_kicad-PTH.drl: -------------------------------------------------------------------------------- 1 | M48 2 | ; DRILL file {KiCad 6.0.7+dfsg-3} date Sat 10 Dec 2022 05:16:35 PM PST 3 | ; FORMAT={-:-/ absolute / metric / decimal} 4 | ; #@! TF.CreationDate,2022-12-10T17:16:35-08:00 5 | ; #@! TF.GenerationSoftware,Kicad,Pcbnew,6.0.7+dfsg-3 6 | ; #@! TF.FileFunction,Plated,1,2,PTH 7 | FMAT,2 8 | METRIC 9 | ; #@! TA.AperFunction,Plated,PTH,ComponentDrill 10 | T1C0.800 11 | ; #@! TA.AperFunction,Plated,PTH,ComponentDrill 12 | T2C1.000 13 | ; #@! TA.AperFunction,Plated,PTH,ComponentDrill 14 | T3C1.020 15 | ; #@! TA.AperFunction,Plated,PTH,ComponentDrill 16 | T4C1.300 17 | % 18 | G90 19 | G05 20 | T1 21 | X24.13Y-58.42 22 | X24.13Y-60.92 23 | T2 24 | X8.89Y-59.69 25 | X11.43Y-59.69 26 | X13.97Y-59.69 27 | X16.51Y-59.69 28 | X50.165Y-12.075 29 | X50.165Y-14.615 30 | X50.165Y-17.155 31 | X50.165Y-19.695 32 | T3 33 | X9.525Y-5.08 34 | X9.525Y-7.62 35 | X9.525Y-10.16 36 | X9.525Y-12.7 37 | X9.525Y-15.24 38 | X9.525Y-17.78 39 | X9.525Y-20.32 40 | X9.525Y-22.86 41 | X9.525Y-25.4 42 | X9.525Y-27.94 43 | X9.525Y-30.48 44 | X9.525Y-33.02 45 | X9.525Y-35.56 46 | X9.525Y-38.1 47 | X9.525Y-40.64 48 | X9.525Y-43.18 49 | X9.525Y-45.72 50 | X9.525Y-48.26 51 | X9.525Y-50.8 52 | X9.525Y-53.34 53 | X15.875Y-53.11 54 | X18.415Y-53.11 55 | X20.955Y-53.11 56 | X27.305Y-5.08 57 | X27.305Y-7.62 58 | X27.305Y-10.16 59 | X27.305Y-12.7 60 | X27.305Y-15.24 61 | X27.305Y-17.78 62 | X27.305Y-20.32 63 | X27.305Y-22.86 64 | X27.305Y-25.4 65 | X27.305Y-27.94 66 | X27.305Y-30.48 67 | X27.305Y-33.02 68 | X27.305Y-35.56 69 | X27.305Y-38.1 70 | X27.305Y-40.64 71 | X27.305Y-43.18 72 | X27.305Y-45.72 73 | X27.305Y-48.26 74 | X27.305Y-50.8 75 | X27.305Y-53.34 76 | T4 77 | X37.32Y-33.655 78 | X37.32Y-38.655 79 | X37.465Y-48.26 80 | X37.465Y-53.26 81 | X49.82Y-33.655 82 | X49.82Y-38.655 83 | X49.965Y-48.26 84 | X49.965Y-53.26 85 | T0 86 | M30 87 | -------------------------------------------------------------------------------- /schematic/dotstar_8x8_kicad/export/matrix_clock_kicad-job.gbrjob: -------------------------------------------------------------------------------- 1 | { 2 | "Header": { 3 | "GenerationSoftware": { 4 | "Vendor": "KiCad", 5 | "Application": "Pcbnew", 6 | "Version": "6.0.7+dfsg-3" 7 | }, 8 | "CreationDate": "2022-12-10T17:15:55-08:00" 9 | }, 10 | "GeneralSpecs": { 11 | "ProjectId": { 12 | "Name": "matrix_clock_kicad", 13 | "GUID": "6d617472-6978-45f6-936c-6f636b5f6b69", 14 | "Revision": "rev?" 15 | }, 16 | "Size": { 17 | "X": 54.71, 18 | "Y": 63.6 19 | }, 20 | "LayerNumber": 2, 21 | "BoardThickness": 1.6, 22 | "Finish": "None" 23 | }, 24 | "DesignRules": [ 25 | { 26 | "Layers": "Outer", 27 | "PadToPad": 0.2, 28 | "PadToTrack": 0.2, 29 | "TrackToTrack": 0.2, 30 | "MinLineWidth": 0.5, 31 | "TrackToRegion": 0.508, 32 | "RegionToRegion": 0.508 33 | } 34 | ], 35 | "FilesAttributes": [ 36 | { 37 | "Path": "matrix_clock_kicad-B_Cu.gbr", 38 | "FileFunction": "Copper,L2,Bot", 39 | "FilePolarity": "Positive" 40 | }, 41 | { 42 | "Path": "matrix_clock_kicad-Edge_Cuts.gbr", 43 | "FileFunction": "Profile", 44 | "FilePolarity": "Positive" 45 | } 46 | ], 47 | "MaterialStackup": [ 48 | { 49 | "Type": "Legend", 50 | "Name": "Top Silk Screen" 51 | }, 52 | { 53 | "Type": "SolderPaste", 54 | "Name": "Top Solder Paste" 55 | }, 56 | { 57 | "Type": "SolderMask", 58 | "Thickness": 0.01, 59 | "Name": "Top Solder Mask" 60 | }, 61 | { 62 | "Type": "Copper", 63 | "Thickness": 0.035, 64 | "Name": "F.Cu" 65 | }, 66 | { 67 | "Type": "Dielectric", 68 | "Thickness": 1.51, 69 | "Material": "FR4", 70 | "Name": "F.Cu/B.Cu", 71 | "Notes": "Type: dielectric layer 1 (from F.Cu to B.Cu)" 72 | }, 73 | { 74 | "Type": "Copper", 75 | "Thickness": 0.035, 76 | "Name": "B.Cu" 77 | }, 78 | { 79 | "Type": "SolderMask", 80 | "Thickness": 0.01, 81 | "Name": "Bottom Solder Mask" 82 | }, 83 | { 84 | "Type": "SolderPaste", 85 | "Name": "Bottom Solder Paste" 86 | }, 87 | { 88 | "Type": "Legend", 89 | "Name": "Bottom Silk Screen" 90 | } 91 | ] 92 | } 93 | -------------------------------------------------------------------------------- /schematic/dotstar_8x8_kicad/flatcam/matrix_clock.FlatPrj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/schematic/dotstar_8x8_kicad/flatcam/matrix_clock.FlatPrj -------------------------------------------------------------------------------- /schematic/dotstar_8x8_kicad/flatcam/matrix_clock_kicad-PTH.mounting_drill.nc: -------------------------------------------------------------------------------- 1 | (G-CODE GENERATED BY FLATCAM v8.994 - www.flatcam.org - Version Date: 2020/11/7) 2 | 3 | (Name: matrix_clock_kicad-PTH.drl_edit_3_cnc) 4 | (Type: G-code from Geometry) 5 | (Units: MM) 6 | 7 | (Created on Sunday, 11 December 2022 at 07:05) 8 | 9 | (Specially modified by mattwach to work with the Sainsmart 3080 that I have.) 10 | 11 | 12 | (TOOLS DIAMETER: ) 13 | (Tool: 1 -> Dia: 2.0) 14 | 15 | (FEEDRATE Z: ) 16 | (Tool: 1 -> Feedrate: 120.0) 17 | 18 | (FEEDRATE RAPIDS: ) 19 | (Tool: 1 -> Feedrate Rapids: 1500) 20 | 21 | (Z_CUT: ) 22 | (Tool: 1 -> Z_Cut: -1.7) 23 | 24 | (Tools Offset: ) 25 | (Tool: 1 -> Offset Z: 0.0) 26 | 27 | (Z_MOVE: ) 28 | (Tool: 1 -> Z_Move: 2) 29 | 30 | (Z Toolchange: 15 mm) 31 | (X,Y Toolchange: 0.0000, 0.0000 mm) 32 | (Z Start: None mm) 33 | (Z End: 0.5 mm) 34 | (X,Y End: 0.0000, 0.0000 mm) 35 | (Steps per circle: 64) 36 | (Preprocessor Excellon: default) 37 | 38 | (X range: 2.7000 ... 51.8000 mm) 39 | (Y range: -57.7000 ... -2.6000 mm) 40 | 41 | (Spindle Speed: 10000 RPM) 42 | G21 43 | G90 44 | G17 45 | G94 46 | 47 | 48 | G01 F120.00 49 | 50 | M5 51 | G00 Z15.0000 52 | G00 X0.0000 Y0.0000 53 | (MSG, Change to Tool Dia = 2.0000 ||| Total drills for tool T1 = 2) 54 | G00 Z15.0000 55 | 56 | G01 F120.00 57 | M03 S10000 58 | G00 X3.7000 Y-3.6000 59 | G01 Z-1.7000 60 | G01 Z0 61 | G00 Z2.0000 62 | G00 X50.8000 Y-56.7000 63 | G01 Z-1.7000 64 | G01 Z0 65 | G00 Z2.0000 66 | M05 67 | G00 Z0.50 68 | G00 X0.0 Y0.0 69 | 70 | 71 | -------------------------------------------------------------------------------- /schematic/dotstar_8x8_kicad/flatcam/matrix_clock_kicad-PTH.small_drill.nc: -------------------------------------------------------------------------------- 1 | (G-CODE GENERATED BY FLATCAM v8.994 - www.flatcam.org - Version Date: 2020/11/7) 2 | 3 | (Name: matrix_clock_kicad-PTH.drl_edit_5_cnc) 4 | (Type: G-code from Geometry) 5 | (Units: MM) 6 | 7 | (Created on Monday, 12 December 2022 at 09:11) 8 | 9 | (Specially modified by mattwach to work with the Sainsmart 3080 that I have.) 10 | 11 | 12 | (TOOLS DIAMETER: ) 13 | (Tool: 1 -> Dia: 0.9) 14 | 15 | (FEEDRATE Z: ) 16 | (Tool: 1 -> Feedrate: 300) 17 | 18 | (FEEDRATE RAPIDS: ) 19 | (Tool: 1 -> Feedrate Rapids: 1500) 20 | 21 | (Z_CUT: ) 22 | (Tool: 1 -> Z_Cut: -1.7) 23 | 24 | (Tools Offset: ) 25 | (Tool: 1 -> Offset Z: 0.0) 26 | 27 | (Z_MOVE: ) 28 | (Tool: 1 -> Z_Move: 2) 29 | 30 | (Z Toolchange: 15 mm) 31 | (X,Y Toolchange: 0.0000, 0.0000 mm) 32 | (Z Start: None mm) 33 | (Z End: 0.5 mm) 34 | (X,Y End: 0.0000, 0.0000 mm) 35 | (Steps per circle: 64) 36 | (Preprocessor Excellon: default) 37 | 38 | (X range: 3.9900 ... 46.1650 mm) 39 | (Y range: -61.3700 ... -11.6250 mm) 40 | 41 | (Spindle Speed: 10000 RPM) 42 | G21 43 | G90 44 | G17 45 | G94 46 | 47 | 48 | G01 F300.00 49 | 50 | M5 51 | G00 Z15.0000 52 | G00 X0.0000 Y0.0000 53 | G00 Z15.0000 54 | 55 | G01 F300.00 56 | M03 S10000 57 | G00 X30.4750 Y-58.4200 58 | G01 Z-1.7000 59 | G01 Z0 60 | G00 Z2.0000 61 | G00 X4.6400 Y-53.2600 62 | G01 Z-1.7000 63 | G01 Z0 64 | G00 Z2.0000 65 | G00 X4.6400 Y-48.2600 66 | G01 Z-1.7000 67 | G01 Z0 68 | G00 Z2.0000 69 | G00 X4.7850 Y-38.6550 70 | G01 Z-1.7000 71 | G01 Z0 72 | G00 Z2.0000 73 | G00 X4.7850 Y-33.6550 74 | G01 Z-1.7000 75 | G01 Z0 76 | G00 Z2.0000 77 | G00 X17.1400 Y-53.2600 78 | G01 Z-1.7000 79 | G01 Z0 80 | G00 Z2.0000 81 | G00 X17.1400 Y-48.2600 82 | G01 Z-1.7000 83 | G01 Z0 84 | G00 Z2.0000 85 | G00 X17.2850 Y-38.6550 86 | G01 Z-1.7000 87 | G01 Z0 88 | G00 Z2.0000 89 | G00 X17.2850 Y-33.6550 90 | G01 Z-1.7000 91 | G01 Z0 92 | G00 Z2.0000 93 | G00 X4.4400 Y-19.6950 94 | G01 Z-1.7000 95 | G01 Z0 96 | G00 Z2.0000 97 | G00 X4.4400 Y-17.1550 98 | G01 Z-1.7000 99 | G01 Z0 100 | G00 Z2.0000 101 | G00 X4.4400 Y-14.6150 102 | G01 Z-1.7000 103 | G01 Z0 104 | G00 Z2.0000 105 | G00 X4.4400 Y-12.0750 106 | G01 Z-1.7000 107 | G01 Z0 108 | G00 Z2.0000 109 | G00 X38.0950 Y-59.6900 110 | G01 Z-1.7000 111 | G01 Z0 112 | G00 Z2.0000 113 | G00 X40.6350 Y-59.6900 114 | G01 Z-1.7000 115 | G01 Z0 116 | G00 Z2.0000 117 | G00 X43.1750 Y-59.6900 118 | G01 Z-1.7000 119 | G01 Z0 120 | G00 Z2.0000 121 | G00 X45.7150 Y-59.6900 122 | G01 Z-1.7000 123 | G01 Z0 124 | G00 Z2.0000 125 | G00 X30.4750 Y-60.9200 126 | G01 Z-1.7000 127 | G01 Z0 128 | G00 Z2.0000 129 | M05 130 | G00 Z0.50 131 | G00 X0.0 Y0.0 132 | 133 | 134 | -------------------------------------------------------------------------------- /schematic/dotstar_8x8_kicad/flatcam/test.nc: -------------------------------------------------------------------------------- 1 | (CNC Regtangle Test File) 2 | 3 | G21 (Units in MM) 4 | G90 (Absolute positioning) 5 | G94 (Units per minute feed rate mode) 6 | 7 | G01 F200 (Move to starting position) 8 | G01 Z10 9 | G00 X-1 Y1 10 | M03 S10000.0 (Start motor) 11 | G01 Z1.0 (Move to dwell height) 12 | 13 | G01 F60 (Approach material) 14 | G01 Z0.0 15 | G01 F120.0 (Draw rectangle) 16 | G01 X55 17 | G01 Y-64 18 | G01 X-1 19 | G01 Y1 20 | 21 | G01 F200 22 | G01 Z10 (Exit material) 23 | M05 (Stop motor) 24 | (Test complete, EOF) 25 | 26 | -------------------------------------------------------------------------------- /schematic/dotstar_8x8_kicad/fp-info-cache: -------------------------------------------------------------------------------- 1 | 4957761239997 2 | Raspberry_Pi_Pico 3 | Crystal_SMD_HC49-US 4 | SMD Crystal HC-49-SD http://cdn-reichelt.de/documents/datenblatt/B400/xxx-HC49-SMD.pdf, 11.4x4.7mm^2 package 5 | SMD SMT crystal 6 | 0 7 | 2 8 | 2 9 | Raspberry_Pi_Pico 10 | RP2040-QFN-56 11 | QFN, 56 Pin (http://www.cypress.com/file/416486/download#page=40), generated with kicad-footprint-generator ipc_dfn_qfn_generator.py 12 | QFN DFN_QFN 13 | 0 14 | 70 15 | 57 16 | Raspberry_Pi_Pico 17 | RPi_Pico_SMD_TH 18 | Through hole straight pin header, 2x20, 2.54mm pitch, double rows 19 | Through hole pin header THT 2x20 2.54mm double row 20 | 0 21 | 86 22 | 43 23 | -------------------------------------------------------------------------------- /schematic/dotstar_8x8_kicad/matrix_clock_kicad.kicad_prl: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "active_layer": 37, 4 | "active_layer_preset": "All Layers", 5 | "auto_track_width": true, 6 | "hidden_nets": [], 7 | "high_contrast_mode": 0, 8 | "net_color_mode": 1, 9 | "opacity": { 10 | "pads": 1.0, 11 | "tracks": 1.0, 12 | "vias": 1.0, 13 | "zones": 0.6 14 | }, 15 | "ratsnest_display_mode": 0, 16 | "selection_filter": { 17 | "dimensions": true, 18 | "footprints": true, 19 | "graphics": true, 20 | "keepouts": true, 21 | "lockedItems": true, 22 | "otherItems": true, 23 | "pads": true, 24 | "text": true, 25 | "tracks": true, 26 | "vias": true, 27 | "zones": true 28 | }, 29 | "visible_items": [ 30 | 0, 31 | 1, 32 | 2, 33 | 3, 34 | 4, 35 | 5, 36 | 8, 37 | 9, 38 | 10, 39 | 11, 40 | 12, 41 | 13, 42 | 14, 43 | 15, 44 | 16, 45 | 17, 46 | 18, 47 | 19, 48 | 20, 49 | 21, 50 | 22, 51 | 23, 52 | 24, 53 | 25, 54 | 26, 55 | 27, 56 | 28, 57 | 29, 58 | 30, 59 | 32, 60 | 33, 61 | 34, 62 | 35, 63 | 36 64 | ], 65 | "visible_layers": "fffffff_ffffffff", 66 | "zone_display_mode": 0 67 | }, 68 | "meta": { 69 | "filename": "matrix_clock_kicad.kicad_prl", 70 | "version": 3 71 | }, 72 | "project": { 73 | "files": [] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /schematic/led_matrix_64x32_kicad/flatcam/Project_20230127_103059.FlatPrj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattwach/matrix_clock/750646eb556ee4517caf140ce9ef55ca965173a1/schematic/led_matrix_64x32_kicad/flatcam/Project_20230127_103059.FlatPrj -------------------------------------------------------------------------------- /schematic/led_matrix_64x32_kicad/fp-info-cache: -------------------------------------------------------------------------------- 1 | 5011857610853 2 | PI Pico 3 | Crystal_SMD_HC49-US 4 | SMD Crystal HC-49-SD http://cdn-reichelt.de/documents/datenblatt/B400/xxx-HC49-SMD.pdf, 11.4x4.7mm^2 package 5 | SMD SMT crystal 6 | 0 7 | 2 8 | 2 9 | PI Pico 10 | RP2040-QFN-56 11 | QFN, 56 Pin (http://www.cypress.com/file/416486/download#page=40), generated with kicad-footprint-generator ipc_dfn_qfn_generator.py 12 | QFN DFN_QFN 13 | 0 14 | 70 15 | 57 16 | PI Pico 17 | RPi_Pico_SMD_TH 18 | Through hole straight pin header, 2x20, 2.54mm pitch, double rows 19 | Through hole pin header THT 2x20 2.54mm double row 20 | 0 21 | 86 22 | 43 23 | -------------------------------------------------------------------------------- /schematic/led_matrix_64x32_kicad/gerber/led_matrix_64x32_kicad-F_Paste.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,6.0.9+dfsg-1*% 2 | %TF.CreationDate,2023-01-27T09:36:51-08:00*% 3 | %TF.ProjectId,led_matrix_64x32_kicad,6c65645f-6d61-4747-9269-785f33327836,rev?*% 4 | %TF.SameCoordinates,PX2efe460PY2edf448*% 5 | %TF.FileFunction,Paste,Top*% 6 | %TF.FilePolarity,Positive*% 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW 6.0.9+dfsg-1) date 2023-01-27 09:36:51* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | G04 Aperture macros list* 15 | %AMRoundRect* 16 | 0 Rectangle with rounded corners* 17 | 0 $1 Rounding radius* 18 | 0 $2 $3 $4 $5 $6 $7 $8 $9 X,Y pos of 4 corners* 19 | 0 Add a 4 corners polygon primitive as box body* 20 | 4,1,4,$2,$3,$4,$5,$6,$7,$8,$9,$2,$3,0* 21 | 0 Add four circle primitives for the rounded corners* 22 | 1,1,$1+$1,$2,$3* 23 | 1,1,$1+$1,$4,$5* 24 | 1,1,$1+$1,$6,$7* 25 | 1,1,$1+$1,$8,$9* 26 | 0 Add four rect primitives between the rounded corners* 27 | 20,1,$1+$1,$2,$3,$4,$5,0* 28 | 20,1,$1+$1,$4,$5,$6,$7,0* 29 | 20,1,$1+$1,$6,$7,$8,$9,0* 30 | 20,1,$1+$1,$8,$9,$2,$3,0*% 31 | G04 Aperture macros list end* 32 | %TA.AperFunction,Profile*% 33 | %ADD10C,0.100000*% 34 | %TD*% 35 | %ADD11RoundRect,0.250000X0.337500X0.475000X-0.337500X0.475000X-0.337500X-0.475000X0.337500X-0.475000X0*% 36 | %ADD12R,0.510000X0.700000*% 37 | %ADD13RoundRect,0.250000X-0.350000X-0.450000X0.350000X-0.450000X0.350000X0.450000X-0.350000X0.450000X0*% 38 | %ADD14RoundRect,0.500000X0.500000X0.500000X-0.500000X0.500000X-0.500000X-0.500000X0.500000X-0.500000X0*% 39 | G04 APERTURE END LIST* 40 | D10* 41 | X0Y0D02* 42 | X70104000Y0D01* 43 | X70104000Y0D02* 44 | X70104000Y-61976000D01* 45 | X0Y-61976000D02* 46 | X70104000Y-61976000D01* 47 | X0Y0D02* 48 | X0Y-61976000D01* 49 | D11* 50 | %TO.C,C3*% 51 | X66294000Y-55880000D03* 52 | X64219000Y-55880000D03* 53 | %TD*% 54 | D12* 55 | %TO.C,U2*% 56 | X66101000Y-45978500D03* 57 | X65151000Y-45978500D03* 58 | X64201000Y-45978500D03* 59 | X64201000Y-48298500D03* 60 | X66101000Y-48298500D03* 61 | %TD*% 62 | D13* 63 | %TO.C,R1*% 64 | X64167000Y-51583500D03* 65 | X66167000Y-51583500D03* 66 | %TD*% 67 | D14* 68 | %TO.C,SW3*% 69 | X27432000Y-31877000D03* 70 | X27432000Y-39877000D03* 71 | %TD*% 72 | D11* 73 | %TO.C,C2*% 74 | X66167000Y-42545000D03* 75 | X64092000Y-42545000D03* 76 | %TD*% 77 | M02* 78 | -------------------------------------------------------------------------------- /schematic/led_matrix_64x32_kicad/gerber/led_matrix_64x32_kicad-job.gbrjob: -------------------------------------------------------------------------------- 1 | { 2 | "Header": { 3 | "GenerationSoftware": { 4 | "Vendor": "KiCad", 5 | "Application": "Pcbnew", 6 | "Version": "6.0.9+dfsg-1" 7 | }, 8 | "CreationDate": "2023-01-27T09:36:51-08:00" 9 | }, 10 | "GeneralSpecs": { 11 | "ProjectId": { 12 | "Name": "led_matrix_64x32_kicad", 13 | "GUID": "6c65645f-6d61-4747-9269-785f33327836", 14 | "Revision": "rev?" 15 | }, 16 | "Size": { 17 | "X": 70.204, 18 | "Y": 62.076 19 | }, 20 | "LayerNumber": 2, 21 | "BoardThickness": 1.6, 22 | "Finish": "None" 23 | }, 24 | "DesignRules": [ 25 | { 26 | "Layers": "Outer", 27 | "PadToPad": 0.2, 28 | "PadToTrack": 0.2, 29 | "TrackToTrack": 0.2, 30 | "MinLineWidth": 0.4, 31 | "TrackToRegion": 0.508, 32 | "RegionToRegion": 0.508 33 | } 34 | ], 35 | "FilesAttributes": [ 36 | { 37 | "Path": "led_matrix_64x32_kicad-F_Paste.gbr", 38 | "FileFunction": "SolderPaste,Top", 39 | "FilePolarity": "Positive" 40 | } 41 | ], 42 | "MaterialStackup": [ 43 | { 44 | "Type": "Legend", 45 | "Name": "Top Silk Screen" 46 | }, 47 | { 48 | "Type": "SolderPaste", 49 | "Name": "Top Solder Paste" 50 | }, 51 | { 52 | "Type": "SolderMask", 53 | "Thickness": 0.01, 54 | "Name": "Top Solder Mask" 55 | }, 56 | { 57 | "Type": "Copper", 58 | "Thickness": 0.035, 59 | "Name": "F.Cu" 60 | }, 61 | { 62 | "Type": "Dielectric", 63 | "Thickness": 1.51, 64 | "Material": "FR4", 65 | "Name": "F.Cu/B.Cu", 66 | "Notes": "Type: dielectric layer 1 (from F.Cu to B.Cu)" 67 | }, 68 | { 69 | "Type": "Copper", 70 | "Thickness": 0.035, 71 | "Name": "B.Cu" 72 | }, 73 | { 74 | "Type": "SolderMask", 75 | "Thickness": 0.01, 76 | "Name": "Bottom Solder Mask" 77 | }, 78 | { 79 | "Type": "SolderPaste", 80 | "Name": "Bottom Solder Paste" 81 | }, 82 | { 83 | "Type": "Legend", 84 | "Name": "Bottom Silk Screen" 85 | } 86 | ] 87 | } 88 | -------------------------------------------------------------------------------- /schematic/led_matrix_64x32_kicad/led_matrix_64x32_kicad.kicad_prl: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "active_layer": 36, 4 | "active_layer_preset": "", 5 | "auto_track_width": true, 6 | "hidden_nets": [], 7 | "high_contrast_mode": 0, 8 | "net_color_mode": 1, 9 | "opacity": { 10 | "pads": 1.0, 11 | "tracks": 1.0, 12 | "vias": 1.0, 13 | "zones": 0.6 14 | }, 15 | "ratsnest_display_mode": 0, 16 | "selection_filter": { 17 | "dimensions": true, 18 | "footprints": true, 19 | "graphics": true, 20 | "keepouts": true, 21 | "lockedItems": true, 22 | "otherItems": true, 23 | "pads": true, 24 | "text": true, 25 | "tracks": true, 26 | "vias": true, 27 | "zones": true 28 | }, 29 | "visible_items": [ 30 | 0, 31 | 1, 32 | 2, 33 | 3, 34 | 4, 35 | 5, 36 | 8, 37 | 9, 38 | 10, 39 | 11, 40 | 12, 41 | 13, 42 | 14, 43 | 15, 44 | 16, 45 | 17, 46 | 18, 47 | 19, 48 | 20, 49 | 21, 50 | 22, 51 | 23, 52 | 24, 53 | 25, 54 | 26, 55 | 27, 56 | 28, 57 | 29, 58 | 30, 59 | 32, 60 | 33, 61 | 34, 62 | 35, 63 | 36 64 | ], 65 | "visible_layers": "fffffef_ffffffff", 66 | "zone_display_mode": 1 67 | }, 68 | "meta": { 69 | "filename": "led_matrix_64x32_kicad.kicad_prl", 70 | "version": 3 71 | }, 72 | "project": { 73 | "files": [] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | # Pull in SDK (must be before project) 4 | include(pico_sdk_import.cmake) 5 | 6 | project(pico_examples C CXX ASM) 7 | set(CMAKE_C_STANDARD 11) 8 | set(CMAKE_CXX_STANDARD 17) 9 | 10 | if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0") 11 | message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}") 12 | endif() 13 | 14 | set(PICO_EXAMPLES_PATH ${PROJECT_SOURCE_DIR}) 15 | 16 | # Choose a clock source 17 | set(CLOCK_SOURCE clock_ds3231) 18 | #set(CLOCK_SOURCE clock_pico_internal) 19 | 20 | # Choose an led matrix 21 | #set(LED_MATRIX_SOURCE led_matrix_dotstar) 22 | set(LED_MATRIX_SOURCE led_matrix_64x32) 23 | 24 | # Initialize the SDK 25 | pico_sdk_init() 26 | 27 | add_compile_options(-Wall 28 | -Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int 29 | -Wno-unused-function # we have some for the docs that aren't called 30 | -Wno-maybe-uninitialized 31 | -D${LED_MATRIX_SOURCE} 32 | ) 33 | 34 | add_executable(matrix_clock 35 | ${CLOCK_SOURCE}.c 36 | ${LED_MATRIX_SOURCE}.c 37 | buttons.c 38 | clock_render.c 39 | clock_settings.c 40 | colors.c 41 | debounce.c 42 | debug.c 43 | main.c 44 | monitor.c 45 | number_draw.c 46 | set_time_low_res.c 47 | set_time_high_res.c 48 | render/blank.c 49 | render/bounce.c 50 | render/fade.c 51 | render/drops.c 52 | render/matrix.c 53 | render/matrix_with_numbers.c 54 | render/number_cascade.c 55 | render/number_cascade_hires.c 56 | render/waveform.c 57 | ) 58 | 59 | # pull in common dependencies 60 | target_link_libraries(matrix_clock 61 | pico_stdlib 62 | UART_CONSOLE 63 | ) 64 | 65 | if(CLOCK_SOURCE STREQUAL clock_pico_internal) 66 | target_link_libraries(matrix_clock 67 | hardware_rtc 68 | ) 69 | endif() 70 | 71 | if(CLOCK_SOURCE STREQUAL clock_ds3231) 72 | target_link_libraries(matrix_clock 73 | hardware_i2c 74 | ) 75 | endif() 76 | 77 | if(LED_MATRIX_SOURCE STREQUAL led_matrix_dotstar) 78 | target_link_libraries(matrix_clock 79 | hardware_spi 80 | ) 81 | endif() 82 | 83 | if(LED_MATRIX_SOURCE STREQUAL led_matrix_64x32) 84 | target_link_libraries(matrix_clock 85 | pico_multicore 86 | ) 87 | endif() 88 | 89 | # enable usb output, disable uart output 90 | pico_enable_stdio_usb(matrix_clock 1) 91 | pico_enable_stdio_uart(matrix_clock 0) 92 | 93 | # create map/bin/hex file etc. 94 | pico_add_extra_outputs(matrix_clock) 95 | 96 | add_subdirectory(pico_uart_console) 97 | -------------------------------------------------------------------------------- /src/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f pico_uart_console/CMakeLists.txt ]; then 4 | git submodule init 5 | git submodule update 6 | fi 7 | 8 | rm -rf build 9 | mkdir build 10 | cd build 11 | cmake .. 12 | 13 | -------------------------------------------------------------------------------- /src/buttons.c: -------------------------------------------------------------------------------- 1 | #include "buttons.h" 2 | #include "debounce.h" 3 | #include "led_matrix.h" 4 | #include "hardware/gpio.h" 5 | #include "pico/stdlib.h" 6 | 7 | #if defined(led_matrix_dotstar) 8 | #define INCREMENT_BUTTON_GPIO 15 9 | #define SELECT_BUTTON_GPIO 14 10 | #elif defined(led_matrix_64x32) 11 | #define INCREMENT_BUTTON_GPIO 26 12 | #define SELECT_BUTTON_GPIO 27 13 | #else 14 | #error Unknown LED_MATRIX_SOURCE 15 | #endif 16 | 17 | #define CURRENT_OVER_GPIO 7 18 | #define CURRENT_OVER_FRAMES (5000 / FRAME_DELAY_MS) 19 | #define DEBOUNCE_MS 10 20 | 21 | struct Debounce select_db; 22 | struct Debounce increment_db; 23 | uint8_t button_bit_array; 24 | uint32_t current_over_frames; 25 | 26 | static inline uint32_t uptime_ms() { 27 | return to_ms_since_boot(get_absolute_time()); 28 | } 29 | 30 | // Callback for gpio_set_irq_callback. Since it's an ISR, 31 | // try to avoid expensive operations. 32 | static void button_pressed_callback(uint gpio, uint32_t events) { 33 | switch (gpio) { 34 | case SELECT_BUTTON_GPIO: 35 | // The callback helper helps filter away debounce glitches 36 | // The debounce_gpio_irq_callback_helper has a side effect (updates state in 37 | // the debounce structure so it should always be called. 38 | if (debounce_gpio_irq_callback_helper(&select_db, uptime_ms(), events) && 39 | select_db.val) { 40 | button_bit_array |= SELECT_BUTTON; 41 | } 42 | break; 43 | case INCREMENT_BUTTON_GPIO: 44 | // The comment for SELECT_BUTTON_GPIO above also apply here. 45 | if (debounce_gpio_irq_callback_helper(&increment_db, uptime_ms(), events) && 46 | increment_db.val) { 47 | button_bit_array |= INCREMENT_BUTTON; 48 | } 49 | break; 50 | case CURRENT_OVER_GPIO: 51 | current_over_frames = CURRENT_OVER_FRAMES; 52 | break; 53 | } 54 | } 55 | 56 | // Sets up a pin to sense a button press. Hardware-wise the button is 57 | // connected to the pin and to ground. The code below sets the internal 58 | // pullup for the button so the pin will sit at 3.3V when the button 59 | // is not pressed. When the button is pressed, the 3.3V will be pulled 60 | // to ground which is an event that the pico is configured to recognize 61 | // and raise an interrupt for. 62 | static void setup_gpio(uint gpio) { 63 | gpio_init(gpio); 64 | gpio_set_dir(gpio, GPIO_IN); 65 | gpio_pull_up(gpio); 66 | sleep_ms(1); // give the pullup some time to do it's thing. Maybe not needed. 67 | gpio_set_irq_enabled(gpio, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true); 68 | } 69 | 70 | void buttons_init(void) { 71 | // Setup two GPIOs for select and increment buttons. 72 | // These are connected to ground though a button. The chip 73 | // is then configured to use internal pullup resistors. 74 | setup_gpio(SELECT_BUTTON_GPIO); 75 | setup_gpio(INCREMENT_BUTTON_GPIO); 76 | 77 | // current over is for detecting if the current was limited 78 | setup_gpio(CURRENT_OVER_GPIO); 79 | 80 | gpio_set_irq_callback(button_pressed_callback); 81 | irq_set_enabled(IO_IRQ_BANK0, true); 82 | 83 | debounce_init(&select_db, DEBOUNCE_MS); 84 | debounce_init(&increment_db, DEBOUNCE_MS); 85 | button_bit_array = 0x00; 86 | } 87 | 88 | uint8_t is_current_over(void) { 89 | if (current_over_frames > 0) { 90 | --current_over_frames; 91 | return 1; 92 | } 93 | return 0; 94 | } 95 | 96 | uint8_t buttons_get(void) { 97 | const uint8_t value = button_bit_array; 98 | button_bit_array = 0x00; // reset 99 | return value; 100 | } 101 | -------------------------------------------------------------------------------- /src/buttons.h: -------------------------------------------------------------------------------- 1 | #ifndef BUTTONS_H 2 | #define BUTTONS_H 3 | // Manages button state 4 | 5 | #include 6 | 7 | // These define bits in the return array. Sequence should be 1, 2, 4, 8, ... 8 | #define SELECT_BUTTON 1 9 | #define INCREMENT_BUTTON 2 10 | 11 | void buttons_init(void); 12 | 13 | // returns current button state as a bit array 14 | // Note that reading the value also resets the state back to unpressed 15 | // e.g. 16 | // * somewone presses and releases the SELECT_BUTTON 17 | // * some amount of time goes by 18 | // * buttons_get() is called 19 | // * SELECT_BUTTON is returned 20 | // * any future calls to buttons_get() return zero until a button 21 | // is pressed again. 22 | uint8_t buttons_get(void); 23 | 24 | // returns a 1 if there is a recent current overload event. 25 | uint8_t is_current_over(void); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/clock.h: -------------------------------------------------------------------------------- 1 | #ifndef CLOCK_H 2 | #define CLOCK_H 3 | 4 | // Generic clock header. 5 | // 6 | // The currently-implemented .c file talks to a DS3231 RTC module but 7 | // you can use other modules, an atomic clock receiver, a gps module, 8 | // internet itme or whatever you want on the backend - it just has to 9 | // provide the following functions as-declared below. Thhen just 10 | // link in the new implementation in CMakeLists.txt 11 | 12 | #include "pico/stdlib.h" 13 | 14 | // gets the current time in HHMM format (0000 - 2359) 15 | // For example, if 1354 is returned, the time is 13:54 (or 16 | // 1:34 PM if you prefer) 17 | uint16_t clock_get_time(); 18 | 19 | // Sets the time. For example: time_hhmm = 1234 would set the 20 | // time to 12:34. Note that 24h time is always used so 1234 21 | // is 12:34 PM and 0034 is 12:34 AM. 22 | void clock_set_time(uint16_t time_hhmm); 23 | 24 | // initialize the clock 25 | void clock_init(); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/clock_ds3231.c: -------------------------------------------------------------------------------- 1 | #include "clock.h" 2 | #include "hardware/i2c.h" 3 | #include 4 | 5 | // GP4 - Pin6 is the default 6 | #define SDA_PIN PICO_DEFAULT_I2C_SDA_PIN 7 | // GP5 - Pin 7 is the default 8 | #define SCL_PIN PICO_DEFAULT_I2C_SCL_PIN 9 | 10 | #define DS3231_I2C_ADDRESS 0x68 11 | 12 | uint16_t clock_get_time() { 13 | // Need two bytes of data to capture hours and minutes from tje 14 | // DS3231. 15 | uint8_t buf[2]; 16 | const uint8_t addr = 0x01; // register address that starts with minute 17 | 18 | // Read address 0x01 and 0x02 from the DS3231 19 | i2c_write_blocking(i2c0, DS3231_I2C_ADDRESS, &addr, 1, true); 20 | const int err = i2c_read_blocking(i2c0, DS3231_I2C_ADDRESS, buf, 2, false); 21 | if (err < 0) { 22 | return 100 - err; 23 | } 24 | // The minute byte is not a direct binary number but is instead 25 | // has a bit format of 0HHHLLLL, where H is the "tens" place and 26 | // L is the "ones" 27 | const uint8_t minute = (buf[0] & 0x0F) + ((buf[0] >> 4) * 10); 28 | 29 | // Hours is a bit more involved to process due to the possibility 30 | // of 12h and 24h modes. If you know what mode the clock is going 31 | // to be in, then the code below can be simplified. 32 | uint8_t hours = buf[1] & 0x0F; 33 | if (buf[1] & 0x10) { 34 | hours += 10; 35 | } 36 | if (buf[1] & 0x40) { 37 | // 12 hour mode 38 | if (buf[1] & 0x20) { 39 | hours += 12; 40 | } 41 | } else { 42 | if (buf[1] & 0x20) { 43 | hours += 20; 44 | } 45 | } 46 | return (hours * 100) + minute; 47 | } 48 | 49 | void clock_set_time(uint16_t time_hhmm) { 50 | const uint8_t minutes_ones = time_hhmm % 10; 51 | const uint8_t minutes_tens = (time_hhmm / 10) % 10; 52 | const uint8_t hours_ones = (time_hhmm / 100) % 10; 53 | const uint8_t hours_tens = (time_hhmm / 1000) % 10; 54 | // set to 15:04:05 55 | uint8_t buf[4]; 56 | buf[0] = 0x00; // Register address 57 | buf[1] = 0x00; // seconds 58 | buf[2] = (minutes_tens << 4) | minutes_ones; // minutes 59 | buf[3] = (hours_tens << 4) | hours_ones; // hours, in 24h format 60 | int err = i2c_write_blocking(i2c0, DS3231_I2C_ADDRESS, buf, 4, false); 61 | if (err >= 0) { 62 | printf("Clock set to %02d:%02d.\n", time_hhmm / 100, time_hhmm % 100); 63 | } else { 64 | printf("Clock set error %d\n", err); 65 | } 66 | } 67 | 68 | void clock_init() { 69 | i2c_init(i2c0, 100 * 1000); 70 | gpio_set_function(SDA_PIN, GPIO_FUNC_I2C); 71 | gpio_set_function(SCL_PIN, GPIO_FUNC_I2C); 72 | } 73 | -------------------------------------------------------------------------------- /src/clock_pico_internal.c: -------------------------------------------------------------------------------- 1 | #include "clock.h" 2 | #include "hardware/rtc.h" 3 | #include "pico/stdlib.h" 4 | #include "pico/util/datetime.h" 5 | #include 6 | 7 | uint16_t clock_get_time() { 8 | datetime_t t; 9 | rtc_get_datetime(&t); 10 | return (t.hour * 100) + t.min; 11 | } 12 | 13 | void clock_set_time(uint16_t time_hhmm) { 14 | const uint8_t hours = time_hhmm / 100; 15 | const uint8_t minutes = time_hhmm % 100; 16 | 17 | // Date does not matter for this application. 18 | datetime_t t = { 19 | .year = 2023, 20 | .month = 1, 21 | .day = 7, 22 | .dotw = 6, // Saturday 23 | .hour = hours, 24 | .min = minutes, 25 | .sec = 00 26 | }; 27 | 28 | // Start the RTC and wait for it to take effect 29 | rtc_set_datetime(&t); 30 | sleep_us(64); 31 | printf("Clock set to %02d:%02d.\n", hours, minutes); 32 | } 33 | 34 | void clock_init() { 35 | rtc_init(); 36 | clock_set_time(1345); 37 | } 38 | -------------------------------------------------------------------------------- /src/clock_render.h: -------------------------------------------------------------------------------- 1 | #ifndef CLOCK_RENDER_H 2 | #define CLOCK_RENDER_H 3 | 4 | #include 5 | #include "clock_settings.h" 6 | 7 | #if defined(led_matrix_64x32) 8 | #define MATRIX_ONLY_MODE_INDEX 1 9 | #endif 10 | 11 | // provides a common interface for rendering a clock 12 | uint8_t clock_render( 13 | uint32_t* led, 14 | uint8_t button_pressed, 15 | uint32_t frame_index, 16 | uint16_t time_hhmm, 17 | const struct ClockSettings* settings); 18 | 19 | // returns the number of available display modes 20 | uint8_t clock_render_num_display_modes(void); 21 | // maps a display mode index to a name. 22 | const char* clock_render_display_mode_name(uint8_t mode); 23 | // change current display mode 24 | void clock_render_set_display_mode(uint8_t mode); 25 | uint8_t clock_render_get_display_mode(void); 26 | void clock_render_reset_mode_change(void); 27 | // returns the next mode change time in hhmm 28 | uint16_t clock_render_next_mode_change(void); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/clock_settings.h: -------------------------------------------------------------------------------- 1 | // Contains program settings, stored in flash 2 | #ifndef CLOCK_SETTINGS_H 3 | #define CLOCK_SETTINGS_H 4 | 5 | // This module handles user settings. It handles both the user interface 6 | // (shell prompt over USB) and storing/loading from flash. 7 | 8 | #include 9 | 10 | //Change this when adding fields. It will cause all settings to reset 11 | #define CLOCK_SETTINGS_VERSION 4 12 | 13 | // Here are the settings. The checksum, eyecatcher and version fields 14 | // are there to detect the cases where setting have not ever been written 15 | // or were updated in an incompatible way. Bad/unreliable flash could also 16 | // cause mismatches here. Having the eyscatcher is probably caution overkill 17 | // but it can help in troubleshooting efforts. 18 | struct ClockSettings { 19 | uint32_t checksum; // the sum of all byte in this structure except for this one 20 | uint8_t eyecatcher[4]; // 'MCLK' 21 | uint32_t version; // bump this when structure changes 22 | 23 | uint8_t brightness_step; // brightness value 24 | uint8_t startup_display_mode; // This is "normal" by default but the user can 25 | // change it if preferred. 26 | 27 | // sleep settings in hhmm format. If they are equal, then sleep is OFF 28 | uint16_t sleep_time; 29 | uint16_t wake_time; 30 | 31 | // mode change settings 32 | uint16_t enabled_modes; 33 | uint16_t mode_change_minutes; 34 | }; 35 | 36 | void clock_settings_init(void); 37 | 38 | // Call this regularly to give the user a responsive USB shell. 39 | // returns a 1 if the frame_index needs to be reset 40 | uint8_t clock_settings_poll(uint16_t time_hhmm, uint32_t last_fps); 41 | 42 | // Get a read-only copy of the settings. 43 | const struct ClockSettings* clock_settings(void); 44 | 45 | // Converts a ClockSettings->brightness to 0-255 brightness 46 | uint8_t brightness_step_to_brightness(const struct ClockSettings* settings); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/colors.c: -------------------------------------------------------------------------------- 1 | #include "colors.h" 2 | 3 | struct Color { 4 | uint32_t value; 5 | const char* name; 6 | }; 7 | 8 | // defines colors 9 | static struct Color colors[10] = { 10 | { 0x352311, "brown" }, // 0 11 | { 0xFF0000, "red" }, // 1 12 | { 0xD05000, "orange" }, // 2 13 | { 0xFFFF10, "yellow" }, // 3 14 | { 0x00FF00, "green" }, // 4 15 | { 0x0000FF, "blue" }, // 5 16 | { 0x00FFFF, "cyan" }, // 6 17 | { 0xFF00FF, "magenta" }, // 7 18 | { 0xA03030, "pink" }, // 8 19 | { 0xFFFFFF, "white" }, // 9 20 | }; 21 | 22 | uint32_t get_color(uint8_t number) { 23 | return colors[number].value; 24 | } 25 | 26 | const char* get_color_name(uint8_t number) { 27 | return colors[number].name; 28 | } 29 | -------------------------------------------------------------------------------- /src/colors.h: -------------------------------------------------------------------------------- 1 | #ifndef COLORS_H 2 | #define COLORS_H 3 | 4 | #include 5 | 6 | // pass a number 0-9 to get a color in 0xVVRRGGBB format where 7 | // VV is birghtness 8 | // RR is red 9 | // GG is green 10 | // BB is blue 11 | // All range 0-255 12 | uint32_t get_color(uint8_t number); 13 | // pass a number to gt a color name 14 | const char* get_color_name(uint8_t number); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/debounce.c: -------------------------------------------------------------------------------- 1 | #include "debounce.h" 2 | #ifdef LIB_PICO_PLATFORM 3 | #include "hardware/gpio.h" 4 | #else 5 | #define GPIO_IRQ_EDGE_FALL 4 6 | #define GPIO_IRQ_EDGE_RISE 8 7 | #endif 8 | 9 | 10 | void debounce_init(struct Debounce* db, uint8_t hold_time_ms) { 11 | db->hold_time_ms = hold_time_ms; 12 | db->last_sample_time_ms = 0; 13 | db->val = 0; 14 | } 15 | 16 | uint8_t debounce_sample(struct Debounce* db, uint32_t time_ms, uint8_t val) { 17 | if (val == db->val) { 18 | return 0; // didn't change 19 | } 20 | if ((db->last_sample_time_ms == 0) || 21 | (time_ms < db->last_sample_time_ms) || 22 | time_ms >= (db->last_sample_time_ms + db->hold_time_ms)) { 23 | db->val = val; 24 | db->last_sample_time_ms = time_ms; 25 | return 1; 26 | } 27 | return 0; 28 | } 29 | 30 | // IRQ callback that handles the not-so-intuitive logic of converting a set 31 | // of rising and falling edges into a clean signal that filters away debounce 32 | // noise without losing presses. 33 | uint8_t debounce_gpio_irq_callback_helper(struct Debounce* db, uint32_t time_ms, uint32_t events) { 34 | uint8_t val = 0; 35 | switch (events) { 36 | case 0x00: 37 | val = db->val; // keep it the same 38 | break; 39 | case GPIO_IRQ_EDGE_FALL: 40 | val = 1; // it's pressed 41 | break; 42 | case GPIO_IRQ_EDGE_RISE: 43 | break; // not pressed 44 | case GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL: 45 | val = 1 - db->val; // invert the current state 46 | break; 47 | } 48 | return debounce_sample(db, time_ms, val); 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/debounce.h: -------------------------------------------------------------------------------- 1 | #ifndef LIB_UTIL_DEBOUNCE_H 2 | #define LIB_UTIL_DEBOUNCE_H 3 | // Simple debounce logic that throttles the update of a value. 4 | // 5 | // Poll example: 6 | // 7 | // void main(void) { 8 | // struct Debounce db; 9 | // debounce_init(&db, 8); 10 | // uint32_t time_ms = 0; 11 | // for (;; ++time_ms) { 12 | // // PB0 will only update every 8ms 13 | // if (debounce_sample(&db, time_ms, PINB & 0x01)) { 14 | // if (db.val) { 15 | // // button was pushed 16 | // } else { 17 | // // button was released 18 | // } 19 | // } 20 | // _delay_ms(1); 21 | // } 22 | // } 23 | // 24 | // Interrupt example 25 | // 26 | // volatile uint32_t counter; 27 | // struct Debounce db; 28 | // void main(void) { 29 | // time_measure_init(); 30 | // debounce_init(&db, 8); 31 | // // Setup pin change interrupt on PB0 32 | // GIMSK |= 1 << INT0; 33 | // 34 | // while (1) { 35 | // lowpower_powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); 36 | // cli(); 37 | // const uint32_t local_counter = counter; 38 | // sei(); 39 | // // do something with counter (print it, etc) 40 | // _delay_ms(1000); 41 | // } 42 | // } 43 | // 44 | // ISR(PCINT0_vect) 45 | // { 46 | // // called on real (and bouncy) rising and falling edges. 47 | // // rising is intersting to register the press 48 | // // falling is interesting to filter away decontact bounces. 49 | // if (debounce_sample(&db, time_measure_ms(), PINB & 0x01)) { 50 | // if (db.val) { 51 | // ++counter; 52 | // } else { 53 | // // do something on on up position if you want to 54 | // } 55 | // } 56 | // } 57 | 58 | #include 59 | 60 | struct Debounce { 61 | volatile uint32_t last_sample_time_ms; // the last time a sample was recorded 62 | uint8_t hold_time_ms; // How long to filter away debounce signals 63 | volatile uint8_t val; 64 | }; 65 | 66 | // Initialize 67 | // 68 | // db: Debounce structure 69 | // hold_time_ms: The length of time to filter away debounce signals 70 | void debounce_init(struct Debounce* db, uint8_t hold_time_ms); 71 | 72 | 73 | // Provides a new value. If the time difference is < hold_time_ms, then 74 | // the old value will be returned (debounce). 75 | // 76 | // db: Debounce structure 77 | // time_ms: A timetamp, in milliseconds 78 | // val: Latest value 79 | // 80 | // Returns: 1 if the value changed AND time_ms is high enough, zero otherwise 81 | uint8_t debounce_sample(struct Debounce* db, uint32_t time_ms, uint8_t val); 82 | 83 | // Callback helper for pi pico. 84 | // 85 | // Bascially the gpio_set_irq_callback is tricky to deal with because of the 86 | // surprising behavoir of GPIO_IRQ_EDGE_FALL and GPIO_IRQ_EDGE_RISE sometimes 87 | // both being active on the same callback. This quickly lead to the realization 88 | // of "which one happened first?" "does it matter?" 89 | // 90 | // I went through this entire exersize in an isolated project named button_interrupt_analyze 91 | // where all callback events were held in a ring buffer. This allowed me to 92 | // work out and verify the handling logic that is in this helper function. 93 | // 94 | // Usage: 95 | // 96 | // struct Debounce db; 97 | // 98 | // void main() { 99 | // ... 100 | // // can also to all of this with gpio_set_irq_enabled_with callback if you only 101 | // // have one button. 102 | // gpio_set_irq_enabled(BUTTON_GPIO, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true); 103 | // gpio_set_irq_callback(button_pressed_callback); 104 | // irq_set_enabled(IO_IRQ_BANK0, true); 105 | // ... 106 | // } 107 | // 108 | // static void button_pressed_callback(uint gpio, uint32_t events) { 109 | // const uint8_t triggered = gpio_irq_callback_helper(&db, events); 110 | // const uint8_t is_pressed = db.val; 111 | // ... 112 | // } 113 | uint8_t debounce_gpio_irq_callback_helper(struct Debounce* db, uint32_t time_ms, uint32_t events); 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /src/debug.c: -------------------------------------------------------------------------------- 1 | #include "debug.h" 2 | #include 3 | #include 4 | 5 | #include "led_matrix.h" 6 | 7 | #define RED_BIT 0x04 8 | #define GREEN_BIT 0x02 9 | #define BLUE_BIT 0x01 10 | static void dump_point(uint32_t pixel) { 11 | if ((pixel & 0xFF000000) == 0) { 12 | putchar(pixel ? '?' : '.'); 13 | return; 14 | } 15 | // only look at bit 3-7 16 | uint8_t color = 0x00; 17 | if ((pixel >> 16) & 0xF0) { 18 | color |= RED_BIT; 19 | } 20 | if ((pixel >> 8) & 0xF0) { 21 | color |= GREEN_BIT; 22 | } 23 | if (pixel & 0xF0) { 24 | color |= BLUE_BIT; 25 | } 26 | char c = ':'; 27 | switch (color) { 28 | case BLUE_BIT: 29 | c = 'B'; 30 | break; 31 | case GREEN_BIT: 32 | c = 'G'; 33 | break; 34 | case BLUE_BIT | GREEN_BIT: 35 | c = 'A'; 36 | break; 37 | case RED_BIT: 38 | c = 'R'; 39 | break; 40 | case RED_BIT | BLUE_BIT: 41 | c = 'M'; 42 | break; 43 | case RED_BIT | GREEN_BIT: 44 | c = 'Y'; 45 | break; 46 | case RED_BIT | GREEN_BIT | BLUE_BIT: 47 | c = 'W'; 48 | break; 49 | } 50 | putchar(c); 51 | } 52 | 53 | void debug_dump_led(const uint32_t* led) { 54 | for (int8_t y=LED_MATRIX_HEIGHT - 1; y >= 0; --y) { 55 | for (uint8_t x=0; x 6 | 7 | void debug_printf(const char* fmt, ...); 8 | 9 | // dump led state to stdout 10 | void debug_dump_led(const uint32_t* led); 11 | 12 | // wait for a keypress 13 | void debug_wait_for_key(void); 14 | 15 | // convienence 16 | void debug_dump_led_with_wait(const char* msg, const uint32_t* led); 17 | 18 | #endif 19 | 20 | -------------------------------------------------------------------------------- /src/led_matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef LED_MATRIX_H 2 | #define LED_MATRIX_H 3 | // This file is the front-end abstraction for any number of 4 | // "LED HARDWARE" modules. The idea is that you change the .c 5 | // file in CMakeLists.txt to correspond to the hardware you 6 | // actually have and the link process will then bundle the 7 | // appropriate code into the driver. 8 | 9 | #include 10 | 11 | #if defined(led_matrix_dotstar) 12 | #define LED_MATRIX_WIDTH 8 13 | #define LED_MATRIX_HEIGHT 8 14 | #define FRAME_DELAY_MS 25 // 40FPS 15 | #elif defined(led_matrix_64x32) 16 | #define LED_MATRIX_WIDTH 32 17 | #define LED_MATRIX_HEIGHT 64 18 | #define FRAME_DELAY_MS 5 // 200FPS 19 | #else 20 | #error Unknown LED_MATRIX_SOURCE 21 | #endif 22 | 23 | // Matrix dimensions. You may need to change these if your's 24 | // is different as well as attend to code that might not 25 | // like your chosen numbers. 26 | #define LED_MATRIX_COUNT (LED_MATRIX_WIDTH * LED_MATRIX_HEIGHT) 27 | 28 | // Initialize the matrix 29 | void led_matrix_init(); 30 | 31 | // render the matrix. 32 | // data is of the form 0xIIRRGGBB where 33 | // II -> Intensity (brightness) 34 | // RR -> Red 35 | // GG -> Green 36 | // BB -> Blue 37 | // 38 | // Values are 0-255 39 | // format is horizontal rows. The first pixel 40 | // sent is the southwest corner of the matrix. 41 | void led_matrix_render(uint32_t* data); 42 | 43 | // stop any background operations. This is needed to 44 | // safely write settings to flash. Some drivers will 45 | // not need to do anything here. Another call to 46 | // led_matrix_render would be expected to start things 47 | // back up. 48 | void led_matrix_stop(void); 49 | 50 | // converts a x,y coordinate to a pixel index 51 | static inline uint32_t get_pixel_idx(uint16_t x, uint16_t y) { 52 | return (y * LED_MATRIX_WIDTH) + x; 53 | } 54 | 55 | // sets a pixel 56 | static inline void set_pixel( 57 | uint32_t* led, // matrix 58 | uint16_t x, 59 | uint16_t y, 60 | uint8_t br, // brightness 61 | uint8_t r, // red 62 | uint8_t g, // green 63 | uint8_t b // blue 64 | ) { 65 | const uint32_t pixel = (br << 24) | (r << 16) | (g << 8) | b; 66 | const uint16_t idx = get_pixel_idx(x, y); 67 | led[idx] = pixel; 68 | } 69 | 70 | // sets a pixel from a color 71 | static inline void set_pixel2( 72 | uint32_t* led, // matrix 73 | uint16_t x, 74 | uint16_t y, 75 | uint32_t pixel 76 | ) { 77 | const uint16_t idx = get_pixel_idx(x, y); 78 | led[idx] = pixel; 79 | } 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /src/led_matrix_dotstar.c: -------------------------------------------------------------------------------- 1 | // LED matrix implementation for dotstar hardware 2 | #include "led_matrix.h" 3 | #include "pico/stdlib.h" 4 | #include "hardware/spi.h" 5 | 6 | #define SCK_PIN 18 7 | #define MOSI_PIN 19 8 | #define SPI_SPEED 1000000 9 | 10 | void led_matrix_init() { 11 | spi_init(spi0, SPI_SPEED); 12 | gpio_set_function(SCK_PIN, GPIO_FUNC_SPI); 13 | gpio_set_function(MOSI_PIN, GPIO_FUNC_SPI); 14 | } 15 | 16 | // writes 4 bytes via SPI 17 | static inline void write_bytes(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) { 18 | uint8_t msg[4] = {b1, b2, b3, b4}; 19 | spi_write_blocking(spi0, msg, 4); 20 | } 21 | 22 | // starts a new frame 23 | static inline void start_frame() { 24 | write_bytes(0, 0, 0, 0); 25 | } 26 | 27 | // displays a given color 28 | static inline void color(uint32_t pixel) { 29 | const uint8_t br = pixel >> 27; // The harware handles 0-31 only 30 | const uint8_t red = (pixel >> 16) & 0xFF; 31 | const uint8_t green = (pixel >> 8) & 0xFF; 32 | const uint8_t blue = pixel & 0xFF; 33 | write_bytes(0xE0 | br, blue, green, red); 34 | } 35 | 36 | void led_matrix_render(uint32_t* data) { 37 | start_frame(); 38 | for (uint8_t i=0; i < LED_MATRIX_COUNT; ++i) { 39 | color(data[i]); 40 | } 41 | } 42 | 43 | void led_matrix_stop(void) { } 44 | 45 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | // Matrix clock 2 | // 3 | // By: Matt Wachowski 4 | 5 | #include "pico/stdlib.h" 6 | #include 7 | #include "clock.h" 8 | #include "clock_render.h" 9 | #include "clock_settings.h" 10 | #include "led_matrix.h" 11 | #include "monitor.h" 12 | #include "buttons.h" 13 | #include "set_time_low_res.h" 14 | #include "set_time_high_res.h" 15 | 16 | #if defined(led_matrix_dotstar) 17 | #define SET_TIME_RENDER set_time_lowres_render 18 | #elif defined(led_matrix_64x32) 19 | #define SET_TIME_RENDER set_time_highres_render 20 | #else 21 | #error Unknown LED_MATRIX_SOURCE 22 | #endif 23 | 24 | #define TIME_UPDATE_FRAMES (1000/FRAME_DELAY_MS) 25 | #define LED_PIN PICO_DEFAULT_LED_PIN 26 | 27 | // set to 1 if the user is setting the time 28 | uint8_t setting_time; 29 | 30 | // format is 0xIIRRGGBB See led_matrix.h for mor details. 31 | uint32_t led[LED_MATRIX_COUNT]; 32 | uint16_t time_hhmm; // a cache of the time to avoid calling for it as much 33 | 34 | struct Monitor monitor; 35 | 36 | static inline uint32_t uptime_ms() { 37 | return to_ms_since_boot(get_absolute_time()); 38 | } 39 | 40 | // Initialization function 41 | static void init(void) { 42 | setting_time = 0; 43 | gpio_init(LED_PIN); 44 | gpio_set_dir(LED_PIN, GPIO_OUT); 45 | clock_settings_init(); 46 | led_matrix_init(); 47 | clock_init(); 48 | buttons_init(); 49 | sleep_ms(50); 50 | time_hhmm = clock_get_time(); 51 | monitor_init(&monitor); 52 | } 53 | 54 | // Updates time_hhmm periocially (based on TIME_UPDATE_FRAMES) 55 | static void maybe_update_time(uint32_t frame_idx) { 56 | if ((frame_idx % TIME_UPDATE_FRAMES) == 0) { 57 | time_hhmm = clock_get_time(); 58 | } 59 | } 60 | 61 | // called repeatedly by main to render a frame 62 | static uint32_t render(uint32_t frame_idx) { 63 | uint32_t t1 = uptime_ms(); 64 | maybe_update_time(frame_idx); 65 | memset(led, 0, sizeof(led)); 66 | uint8_t toggle_setting_time = 0; 67 | uint8_t buttons = buttons_get(); 68 | buttons |= clock_settings_poll(time_hhmm, monitor.last_fps); 69 | if (setting_time) { 70 | toggle_setting_time = SET_TIME_RENDER( 71 | led, buttons, frame_idx, time_hhmm, clock_settings()); 72 | } else { 73 | toggle_setting_time = clock_render( 74 | led, buttons, frame_idx, time_hhmm, clock_settings()); 75 | } 76 | ++frame_idx; 77 | if (toggle_setting_time) { 78 | setting_time = !setting_time; 79 | frame_idx = 0; 80 | } 81 | led_matrix_render(led); 82 | // calculate tdelta to get a smooth frame rate, even if the loop time 83 | // varies. 84 | uint32_t tdelta = uptime_ms() - t1; 85 | if (tdelta < FRAME_DELAY_MS) { 86 | sleep_ms(FRAME_DELAY_MS - tdelta); 87 | } 88 | return frame_idx; 89 | } 90 | 91 | // Program starting point 92 | int main() { 93 | init(); 94 | uint32_t frame_idx = 0; 95 | while (1) { 96 | frame_idx = render(frame_idx); 97 | gpio_put(LED_PIN, is_current_over()); 98 | monitor_frame(&monitor); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/monitor.c: -------------------------------------------------------------------------------- 1 | #include "monitor.h" 2 | 3 | #include "pico/stdlib.h" 4 | 5 | #define FPS_SAMPLES 500 6 | 7 | static inline uint32_t uptime_ms() { 8 | return to_ms_since_boot(get_absolute_time()); 9 | } 10 | 11 | void monitor_init(struct Monitor* m) { 12 | m->fps_idx = 0; 13 | m->last_fps_sample = uptime_ms(); 14 | m->last_fps = 0; 15 | } 16 | 17 | void monitor_frame(struct Monitor* m) { 18 | ++m->fps_idx; 19 | if (m->fps_idx == FPS_SAMPLES) { 20 | const uint32_t new_fps_sample = uptime_ms(); 21 | m->last_fps = m->fps_idx * 1000 / (new_fps_sample - m->last_fps_sample); 22 | m->last_fps_sample = new_fps_sample; 23 | m->fps_idx = 0; 24 | } 25 | } -------------------------------------------------------------------------------- /src/monitor.h: -------------------------------------------------------------------------------- 1 | #ifndef MONITOR_H 2 | #define MONITOR_H 3 | 4 | #include 5 | 6 | // usage: 7 | // struct Monitor m; 8 | // 9 | // int main() { 10 | // monitor_init(&m); 11 | // while (1) { 12 | // render_frame(); 13 | // monitor_frame(&m) 14 | // // m.last_fps is periodically updated with an fps value 15 | // } 16 | // ... 17 | //} 18 | 19 | struct Monitor { 20 | uint32_t last_fps; 21 | uint32_t fps_idx; 22 | uint32_t last_fps_sample; 23 | }; 24 | 25 | void monitor_init(struct Monitor* m); 26 | 27 | void monitor_frame(struct Monitor* m); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/number_draw.c: -------------------------------------------------------------------------------- 1 | #include "number_draw.h" 2 | #include "colors.h" 3 | #include "led_matrix.h" 4 | #include 5 | 6 | // numbers are made of lines 7 | // Each line is on a coordinate system from 0x00 to 0x10 8 | // end with all -1 9 | // 10 | // Note: 0,0 is lower, left 11 | struct Line { 12 | int8_t x0; 13 | int8_t y0; 14 | int8_t x1; 15 | int8_t y1; 16 | }; 17 | 18 | struct Line zero[] = { 19 | {0, 0, 16, 0}, 20 | {0, 0, 0, 16}, 21 | {0, 16, 16, 16}, 22 | {16, 0, 16, 16}, 23 | {-1, -1, -1, -1}, 24 | }; 25 | 26 | struct Line one[] = { 27 | {8, 0, 8, 16}, 28 | {0, 0, 16, 0}, 29 | {0, 16, 8, 16}, 30 | {-1, -1, -1, -1}, 31 | }; 32 | 33 | struct Line two[] = { 34 | {0, 0, 16, 0}, 35 | {0, 0, 0, 8}, 36 | {0, 8, 16, 8}, 37 | {16, 8, 16, 16}, 38 | {0, 16, 16, 16}, 39 | {-1, -1, -1, -1}, 40 | }; 41 | 42 | 43 | struct Line three[] = { 44 | {0, 0, 16, 0}, 45 | {0, 8, 16, 8}, 46 | {0, 16, 16, 16}, 47 | {16, 0, 16, 16}, 48 | {-1, -1, -1, -1}, 49 | }; 50 | 51 | struct Line four[] = { 52 | {16, 0, 16, 16}, 53 | {0, 8, 0, 16}, 54 | {0, 8, 16, 8}, 55 | {-1, -1, -1, -1}, 56 | }; 57 | 58 | struct Line five[] = { 59 | {0, 0, 16, 0}, 60 | {16, 0, 16, 8}, 61 | {0, 8, 16, 8}, 62 | {0, 8, 0, 16}, 63 | {0, 16, 16, 16}, 64 | {-1, -1, -1, -1}, 65 | }; 66 | 67 | struct Line six[] = { 68 | {0, 0, 16, 0}, 69 | {0, 0, 0, 16}, 70 | {0, 8, 16, 8}, 71 | {0, 16, 16, 16}, 72 | {16, 0, 16, 8}, 73 | {-1, -1, -1, -1}, 74 | }; 75 | 76 | struct Line seven[] = { 77 | {0, 16, 16, 16}, 78 | {16, 0, 16, 16}, 79 | {-1, -1, -1, -1}, 80 | }; 81 | 82 | struct Line eight[] = { 83 | {0, 0, 16, 0}, 84 | {0, 8, 16, 8}, 85 | {0, 16, 16, 16}, 86 | {0, 0, 0, 16}, 87 | {16, 0, 16, 16}, 88 | {-1, -1, -1, -1}, 89 | }; 90 | 91 | struct Line nine[] = { 92 | {0, 16, 16, 16}, 93 | {0, 8, 0, 16}, 94 | {0, 8, 16, 8}, 95 | {16, 0, 16, 16}, 96 | {0, 0, 16, 0}, 97 | {-1, -1, -1, -1}, 98 | }; 99 | 100 | struct Line* font_lines[] = { 101 | zero, 102 | one, 103 | two, 104 | three, 105 | four, 106 | five, 107 | six, 108 | seven, 109 | eight, 110 | nine, 111 | }; 112 | 113 | // draws a single pixel to the set matrix 114 | static void pixel( 115 | uint32_t* led, 116 | int16_t x, 117 | int16_t y, 118 | uint32_t color_with_brightness) { 119 | if ((x < 0) || (x >= LED_MATRIX_WIDTH)) { 120 | return; 121 | } 122 | if ((y < 0) || (y >= LED_MATRIX_HEIGHT)) { 123 | return; 124 | } 125 | uint16_t pixel_idx = get_pixel_idx(x, y); 126 | led[pixel_idx] = color_with_brightness; 127 | } 128 | 129 | void number_font_init( 130 | struct NumberFont* font, 131 | uint8_t brightness, 132 | uint8_t char_width, 133 | uint8_t char_height, 134 | uint8_t char_spacing) { 135 | if (char_width & 1) { 136 | --char_width; 137 | } 138 | if (char_height & 1) { 139 | --char_height; 140 | } 141 | font->x = 0; 142 | font->y = 0; 143 | font->brightness = brightness; 144 | font->char_width = char_width; 145 | font->char_height = char_height; 146 | font->char_spacing = char_spacing; 147 | } 148 | 149 | static inline void draw_line( 150 | struct NumberFont* font, 151 | uint32_t* led, 152 | const struct Line* line) { 153 | // scale from the 0-16 scale to the provided width/height values 154 | const int16_t x0 = font->x + ((line->x0 * font->char_width) >> 4); 155 | const int16_t y0 = font->y + ((line->y0 * font->char_height) >> 4); 156 | const int16_t x1 = font->x + ((line->x1 * font->char_width) >> 4); 157 | const int16_t y1 = font->y + ((line->y1 * font->char_height) >> 4); 158 | 159 | const int8_t xdir = x1 > x0 ? 1 : -1; 160 | const int8_t ydir = y1 > y0 ? 1 : -1; 161 | 162 | const int16_t dx = (x1 - x0) * xdir; 163 | const int16_t dy = (y1 - y0) * ydir; 164 | 165 | int16_t D = 2 * dy - dx; 166 | int16_t x = x0; 167 | int16_t y = y0; 168 | 169 | pixel(led, x, y, font->color); 170 | 171 | while (x != x1 || y != y1) { 172 | if (D > 0) { 173 | y += ydir; 174 | D -= 2 * dx; 175 | } 176 | 177 | if (D <= 0) { 178 | x += xdir; 179 | D += 2 * dy; 180 | } 181 | 182 | pixel(led, x, y, font->color); 183 | } 184 | } 185 | 186 | // Draws a number 0-9 at the specified cordinates 187 | void number_draw_mode( 188 | struct NumberFont* font, 189 | uint32_t* led, 190 | uint8_t digit, 191 | uint8_t mode) { 192 | if (digit > 9) { 193 | return; 194 | } 195 | const struct Line* lines = font_lines[digit]; 196 | if (mode == DRAW_MODE_NUMBER) { 197 | font->color = ((uint32_t)font->brightness << 24) | get_color(digit); 198 | } 199 | 200 | for (; lines[0].x0 >= 0; ++lines) { 201 | draw_line(font, led, lines); 202 | } 203 | font->x += font->char_spacing; 204 | } 205 | 206 | void number_draw_dash(struct NumberFont* font, uint32_t* led) { 207 | font->color = ((uint32_t)font->brightness << 24) | 0xFFFFFF; // white 208 | const struct Line dash1 = {0, 4, 0, 5}; 209 | draw_line(font, led, &dash1); 210 | const struct Line dash2 = {0, 12, 0, 13}; 211 | draw_line(font, led, &dash2); 212 | font->x += 2; 213 | } 214 | 215 | // Draws val to led memory. val must be 0-99. 216 | void draw_numbers( 217 | struct NumberFont* font, 218 | uint32_t* led, 219 | uint8_t val) { 220 | const uint8_t tens = val / 10; 221 | number_draw(font, led, tens); 222 | const uint8_t ones = val % 10; 223 | number_draw(font, led, ones); 224 | } 225 | 226 | -------------------------------------------------------------------------------- /src/number_draw.h: -------------------------------------------------------------------------------- 1 | #ifndef NUMBER_DRAW_H 2 | #define NUMBER_DRAW_H 3 | // Draws a number to the LED matrix 4 | 5 | #include 6 | 7 | #define DRAW_MODE_NUMBER 0 8 | #define DRAW_MODE_COLOR 1 9 | 10 | struct NumberFont { 11 | uint32_t color; 12 | int16_t x; 13 | int16_t y; 14 | uint8_t brightness; 15 | uint8_t char_width; 16 | uint8_t char_height; 17 | uint8_t char_spacing; 18 | }; 19 | 20 | // initialize a font 21 | // char spacing does not include char_width 22 | // char width and height will be made odd for better rendering 23 | void number_font_init( 24 | struct NumberFont* font, 25 | uint8_t brightness, 26 | uint8_t char_width, 27 | uint8_t char_height, 28 | uint8_t char_spacing); 29 | 30 | // draws dashes between numbers 31 | void number_draw_dash(struct NumberFont* font, uint32_t* led); 32 | 33 | void number_draw_mode( 34 | struct NumberFont* font, 35 | uint32_t* led, 36 | uint8_t digit, 37 | uint8_t mode); 38 | 39 | // draws a digit with an indexed color. Off screen for x,y is OK 40 | static inline void number_draw( 41 | struct NumberFont* font, 42 | uint32_t* led, 43 | uint8_t digit) { 44 | number_draw_mode(font, led, digit, DRAW_MODE_NUMBER); 45 | } 46 | 47 | // draws two digits with an indexed color 48 | void draw_numbers( 49 | struct NumberFont* font, 50 | uint32_t* led, 51 | uint8_t val); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/pico_sdk_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 9 | endif () 10 | 11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 14 | endif () 15 | 16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 19 | endif () 20 | 21 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 22 | set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") 23 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 24 | 25 | if (NOT PICO_SDK_PATH) 26 | if (PICO_SDK_FETCH_FROM_GIT) 27 | include(FetchContent) 28 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 29 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 30 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 31 | endif () 32 | FetchContent_Declare( 33 | pico_sdk 34 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 35 | GIT_TAG master 36 | ) 37 | if (NOT pico_sdk) 38 | message("Downloading Raspberry Pi Pico SDK") 39 | FetchContent_Populate(pico_sdk) 40 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 41 | endif () 42 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 43 | else () 44 | message(FATAL_ERROR 45 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 46 | ) 47 | endif () 48 | endif () 49 | 50 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 51 | if (NOT EXISTS ${PICO_SDK_PATH}) 52 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 53 | endif () 54 | 55 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 56 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 57 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 58 | endif () 59 | 60 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 61 | 62 | include(${PICO_SDK_INIT_CMAKE_FILE}) 63 | -------------------------------------------------------------------------------- /src/render/blank.c: -------------------------------------------------------------------------------- 1 | #include "blank.h" 2 | 3 | #include "../led_matrix.h" 4 | #include 5 | 6 | void blank_render( 7 | uint32_t* led, 8 | uint32_t unused_frame_index, 9 | uint16_t unused_time_hhmm, 10 | const struct ClockSettings* unused_settings) { 11 | memset(led, 0, LED_MATRIX_WIDTH * LED_MATRIX_HEIGHT * sizeof(uint32_t)); 12 | } 13 | -------------------------------------------------------------------------------- /src/render/blank.h: -------------------------------------------------------------------------------- 1 | #ifndef RENDER_BLANK_H 2 | #define RENDER_BLANK_H 3 | 4 | #include 5 | #include "../clock_settings.h" 6 | 7 | // Turns off all LEDs 8 | void blank_render( 9 | uint32_t* led, 10 | uint32_t frame_index, 11 | uint16_t time_hhmm, 12 | const struct ClockSettings* settings); 13 | #endif 14 | 15 | -------------------------------------------------------------------------------- /src/render/bounce.h: -------------------------------------------------------------------------------- 1 | #ifndef RENDER_BOUNCE_H 2 | #define RENDER_BOUNCE_H 3 | 4 | #include 5 | #include "../clock_settings.h" 6 | 7 | // Turns off all LEDs 8 | void bounce_render( 9 | uint32_t* led, 10 | uint32_t frame_index, 11 | uint16_t time_hhmm, 12 | const struct ClockSettings* settings); 13 | #endif 14 | 15 | -------------------------------------------------------------------------------- /src/render/distances.inc: -------------------------------------------------------------------------------- 1 | // This file was generated by running matrix_clock/tools/distance_generator.py 2 | // with no arguments and redirecting the output to a file. 3 | 4 | #define NUM_DISTANCES 11 // MAX is -1 this val 5 | 6 | // Each number below is the weight to apply to a color at a given 7 | // distance. The range is 0x00-0xFF. 8 | 9 | uint8_t distance_weights[NUM_DISTANCES] __in_flash() = { 10 | 0xFF, // 0 11 | 0x99, // 1 12 | 0x6D, // 2 13 | 0x55, // 3 14 | 0x46, // 4 15 | 0x3B, // 5 16 | 0x33, // 6 17 | 0x2D, // 7 18 | 0x28, // 8 19 | 0x24, // 9 20 | 0x21, // 10 21 | }; 22 | 23 | 24 | // Each number below is the offset into the array for the given 25 | // distance. The next element is used to calculate the length. 26 | // The final element is used only for the length calculation 27 | 28 | uint16_t distance_offsets[NUM_DISTANCES + 1] __in_flash() = { 29 | 0x0000, // 0 30 | 0x0001, // 1 31 | 0x0004, // 2 32 | 0x0009, // 3 33 | 0x0010, // 4 34 | 0x0019, // 5 35 | 0x0024, // 6 36 | 0x0031, // 7 37 | 0x0040, // 8 38 | 0x0051, // 9 39 | 0x0064, // 10 40 | 0x0079, 41 | }; 42 | 43 | // each element is of the format 0xXXYY 44 | uint16_t distance_points[121] __in_flash() = { 45 | // 0 46 | 0x0000, 47 | // 1 48 | 0x0100, 0x0101, 0x0001, 49 | // 2 50 | 0x0200, 0x0201, 0x0101, 0x0102, 0x0002, 51 | // 3 52 | 0x0300, 0x0301, 0x0302, 0x0202, 0x0203, 0x0103, 0x0003, 53 | // 4 54 | 0x0400, 0x0401, 0x0402, 0x0302, 0x0303, 0x0203, 0x0204, 0x0104, 55 | 0x0004, 56 | // 5 57 | 0x0500, 0x0501, 0x0502, 0x0402, 0x0403, 0x0404, 0x0304, 0x0204, 58 | 0x0205, 0x0105, 0x0005, 59 | // 6 60 | 0x0600, 0x0601, 0x0602, 0x0502, 0x0503, 0x0504, 0x0404, 0x0405, 61 | 0x0305, 0x0205, 0x0206, 0x0106, 0x0006, 62 | // 7 63 | 0x0700, 0x0701, 0x0702, 0x0703, 0x0603, 0x0604, 0x0504, 0x0505, 64 | 0x0405, 0x0406, 0x0306, 0x0307, 0x0207, 0x0107, 0x0007, 65 | // 8 66 | 0x0800, 0x0801, 0x0802, 0x0803, 0x0703, 0x0704, 0x0705, 0x0605, 67 | 0x0606, 0x0506, 0x0507, 0x0407, 0x0307, 0x0308, 0x0208, 0x0108, 68 | 0x0008, 69 | // 9 70 | 0x0900, 0x0901, 0x0902, 0x0903, 0x0803, 0x0804, 0x0805, 0x0705, 71 | 0x0706, 0x0606, 0x0607, 0x0507, 0x0508, 0x0408, 0x0308, 0x0309, 72 | 0x0209, 0x0109, 0x0009, 73 | // 10 74 | 0x0A00, 0x0A01, 0x0A02, 0x0A03, 0x0903, 0x0904, 0x0905, 0x0805, 75 | 0x0806, 0x0807, 0x0707, 0x0708, 0x0608, 0x0508, 0x0509, 0x0409, 76 | 0x0309, 0x030A, 0x020A, 0x010A, 0x000A, 77 | }; 78 | 79 | -------------------------------------------------------------------------------- /src/render/drops.h: -------------------------------------------------------------------------------- 1 | #ifndef RENDER_DROPS_H 2 | #define RENDER_DROPS_H 3 | 4 | #include 5 | #include "../clock_settings.h" 6 | 7 | void drops_render( 8 | uint32_t* led, 9 | uint32_t frame_index, 10 | uint16_t time_hhmm, 11 | const struct ClockSettings* settings); 12 | #endif 13 | 14 | -------------------------------------------------------------------------------- /src/render/fade.c: -------------------------------------------------------------------------------- 1 | #include "fade.h" 2 | 3 | #include "../clock_settings.h" 4 | #include "../led_matrix.h" 5 | #include "../number_draw.h" 6 | #include 7 | #include 8 | 9 | // Note, this code assumes 256 LED max. If oyu have more, 10 | // you'll need to change data types or simply disable this module. 11 | 12 | // Contains the order in which the fade should happen 13 | // each value is an offset into the matrix. The array order determines 14 | // the order. 15 | static uint16_t fade_order[LED_MATRIX_COUNT]; 16 | 17 | // we need to hold our data becuase it is added to each frame 18 | static uint32_t data[LED_MATRIX_COUNT]; 19 | static uint32_t target[LED_MATRIX_COUNT]; 20 | 21 | // update these at the start to avoid odd changing mid animation 22 | static uint8_t minutes; 23 | 24 | static struct NumberFont font; 25 | 26 | // how fast the fade occurs 27 | #define FRAMES_PER_FADE_PIXEL 1 28 | 29 | // we take a frame_index modulus and compare to the following 30 | // thresholds to determine what the render should be doing 31 | #define BUILD_HOUR_DIGITS (FRAMES_PER_FADE_PIXEL * LED_MATRIX_COUNT) 32 | #define SHOW_HOUR (BUILD_HOUR_DIGITS + 50) 33 | #define BUILD_MINUTE_DIGITS (SHOW_HOUR + FRAMES_PER_FADE_PIXEL * LED_MATRIX_COUNT) 34 | #define SHOW_MINUTE (BUILD_MINUTE_DIGITS + 50) 35 | #define BLANK_OUT (SHOW_MINUTE + FRAMES_PER_FADE_PIXEL * LED_MATRIX_COUNT) 36 | #define SHOW_BLANK (BLANK_OUT + 50) 37 | #define STATE_MODULUS SHOW_BLANK 38 | 39 | static void swap_with_random_fade_slot(uint16_t i) { 40 | const uint16_t j = (uint8_t)(random() % LED_MATRIX_COUNT); 41 | const uint16_t tmp = fade_order[i]; 42 | fade_order[i] = fade_order[j]; 43 | fade_order[j] = tmp; 44 | } 45 | 46 | static void shuffle_fade_order(void) { 47 | for (uint16_t i=0; i < LED_MATRIX_COUNT; ++i) { 48 | swap_with_random_fade_slot(i); 49 | } 50 | } 51 | 52 | static void init(uint8_t brightness) { 53 | memset(data, 0, sizeof(data)); 54 | for (uint16_t i=0; i 5 | #include "../clock_settings.h" 6 | 7 | // Turns off all LEDs 8 | void fade_render( 9 | uint32_t* led, 10 | uint32_t frame_index, 11 | uint16_t time_hhmm, 12 | const struct ClockSettings* settings); 13 | #endif 14 | 15 | -------------------------------------------------------------------------------- /src/render/matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef RENDER_MATRIX_H 2 | #define RENDER_MATRIX_H 3 | 4 | #include 5 | #include "../clock_settings.h" 6 | 7 | // Renders the "falling point" matrix-style effect 8 | // where particle speed is the time digit e.g. 9 | // 13:45 -> 10 | // 11 | // The 1 is dropped. 12 | // The 3 is represented by slow points 13 | // The 4 is rpresented by medium-speed points 14 | // The 5 is represented by fast points 15 | // 16 | // The digits themselves (0-9) are represented 17 | // by colors as-defined in colors.c. Under current 18 | // definitions this would represent 13:45 as 19 | // 1 -> dropped 20 | // 3 -> yellow (slow) 21 | // 4 -> green (medium speed) 22 | // 5 -> blue (fast) 23 | void matrix_render( 24 | uint32_t* led, 25 | uint32_t frame_index, 26 | uint16_t time_hhmm, 27 | const struct ClockSettings* settings); 28 | #endif 29 | 30 | -------------------------------------------------------------------------------- /src/render/matrix_with_numbers.c: -------------------------------------------------------------------------------- 1 | #include "matrix_with_numbers.h" 2 | #include "matrix.h" 3 | #include "../led_matrix.h" 4 | #include "../number_draw.h" 5 | 6 | #define FONT_XPAD 1 7 | #define FONT_YPAD 1 8 | 9 | static struct NumberFont font; 10 | 11 | static void overlay_numbers(uint32_t* led, uint16_t time_hhmm) { 12 | font.x = LED_MATRIX_WIDTH - font.char_spacing * 4 - 2 - FONT_XPAD + 1; 13 | font.y = FONT_YPAD; 14 | 15 | draw_numbers(&font, led, time_hhmm / 100); 16 | number_draw_dash(&font, led); 17 | draw_numbers(&font, led, time_hhmm % 100); 18 | } 19 | 20 | void matrix_with_numbers_render( 21 | uint32_t* led, 22 | uint32_t frame_index, 23 | uint16_t time_hhmm, 24 | const struct ClockSettings* settings) { 25 | if (frame_index == 0) { 26 | number_font_init(&font, brightness_step_to_brightness(settings), 3, 5, 4); 27 | } 28 | matrix_render(led, frame_index, time_hhmm, settings); 29 | overlay_numbers(led, time_hhmm); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/render/matrix_with_numbers.h: -------------------------------------------------------------------------------- 1 | #ifndef RENDER_MATRIX_WITH_NUMBERS_H 2 | #define RENDER_MATRIX_WITH_NUMBERS_H 3 | 4 | #include 5 | #include "../clock_settings.h" 6 | 7 | // calls matrix and overlays numbers 8 | void matrix_with_numbers_render( 9 | uint32_t* led, 10 | uint32_t frame_index, 11 | uint16_t time_hhmm, 12 | const struct ClockSettings* settings); 13 | #endif 14 | 15 | -------------------------------------------------------------------------------- /src/render/number_cascade.c: -------------------------------------------------------------------------------- 1 | #include "number_cascade.h" 2 | 3 | #include "../led_matrix.h" 4 | #include "../number_draw.h" 5 | 6 | #define FRAMES_PER_SCROLL 7 7 | #define FONT FONT3X5 8 | 9 | static int8_t hours_ypos; // upper right of hour text 10 | static struct NumberFont font; 11 | 12 | void number_cascade_render( 13 | uint32_t* led, 14 | uint32_t frame_index, 15 | uint16_t time_hhmm, 16 | const struct ClockSettings* settings) { 17 | if (frame_index == 0) { 18 | hours_ypos = 0; 19 | frame_index = 1; // don't scroll right away 20 | number_font_init( 21 | &font, 22 | brightness_step_to_brightness(settings), 23 | (LED_MATRIX_WIDTH / 2) - 1, 24 | LED_MATRIX_HEIGHT / 2 + 2, 25 | LED_MATRIX_WIDTH / 2); 26 | } 27 | font.y = hours_ypos; 28 | uint8_t show_hours = 1; 29 | for (; 30 | font.y < LED_MATRIX_HEIGHT; 31 | font.y += font.char_height, show_hours = !show_hours) { 32 | font.x = show_hours ? 0 : LED_MATRIX_WIDTH - (font.char_spacing * 2); 33 | const int8_t val = show_hours ? time_hhmm / 100 : time_hhmm % 100; 34 | draw_numbers(&font, led, val); 35 | } 36 | if ((frame_index % FRAMES_PER_SCROLL) == 0) { 37 | ++hours_ypos; 38 | if (hours_ypos > 0) { 39 | // need to set the ypos so that bottom 40 | // row of the minutes is showing 41 | hours_ypos = -(font.char_height * 2) + 1; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/render/number_cascade.h: -------------------------------------------------------------------------------- 1 | #ifndef RENDER_NUMBER_CASCADE_H 2 | #define RENDER_NUMBER_CASCADE_H 3 | 4 | #include 5 | #include "../clock_settings.h" 6 | 7 | // Cascades time numbers 8 | void number_cascade_render( 9 | uint32_t* led, 10 | uint32_t frame_index, 11 | uint16_t time_hhmm, 12 | const struct ClockSettings* settings); 13 | #endif 14 | 15 | -------------------------------------------------------------------------------- /src/render/number_cascade_hires.h: -------------------------------------------------------------------------------- 1 | #ifndef RENDER_NUMBER_CASCADE_HIRES_H 2 | #define RENDER_NUMBER_CASCADE_HIRES_H 3 | 4 | #include 5 | #include "../clock_settings.h" 6 | 7 | // Cascades time numbers 8 | void number_cascade_hires_render( 9 | uint32_t* led, 10 | uint32_t frame_index, 11 | uint16_t time_hhmm, 12 | const struct ClockSettings* settings); 13 | #endif 14 | 15 | -------------------------------------------------------------------------------- /src/render/waveform.c: -------------------------------------------------------------------------------- 1 | #include "waveform.h" 2 | 3 | #include "../led_matrix.h" 4 | #include "../number_draw.h" 5 | #include "../colors.h" 6 | #include 7 | #include 8 | 9 | #define MIN_DIRECTION_WEIGHT 0x85 10 | #define MAX_DIRECTION_WEIGHT 0xFF 11 | #define MAX_DELTA 4 12 | #define WAVEFORM_COUNT 3 13 | 14 | #define FONT_WIDTH 15 15 | #define FONT_HEIGHT 13 16 | #define FONT_XOFFSET ((LED_MATRIX_WIDTH - FONT_WIDTH) >> 1) 17 | #define FONT_YSPACING 16 18 | 19 | struct Waveform { 20 | // 0xIIRRGGBB 21 | uint32_t color; 22 | int8_t dir; 23 | uint8_t dir_weight; 24 | // an xpos for each given ypos. -1 means "nothing" 25 | // ypos is the (index + frame_index) % LED_MATRIX_HEIGHT 26 | int8_t xpos[LED_MATRIX_HEIGHT]; 27 | }; 28 | 29 | static struct Waveform waves[WAVEFORM_COUNT]; 30 | static struct NumberFont font; 31 | 32 | static inline int16_t rand_range(int16_t min, int16_t max) { 33 | return min + (random() % (max - min)); 34 | } 35 | 36 | static inline void reverse_wave(struct Waveform* w) { 37 | w->dir = 0 - w->dir; 38 | w->dir_weight = rand_range(MIN_DIRECTION_WEIGHT, MAX_DIRECTION_WEIGHT); 39 | } 40 | 41 | static void add_wave_point(struct Waveform* w, uint8_t head_idx) { 42 | const int8_t prev_head_idx = head_idx == 0 ? LED_MATRIX_HEIGHT - 1 : head_idx - 1; 43 | const int8_t prev_x = w->xpos[prev_head_idx]; 44 | if (prev_x < 0) { 45 | // just initialized (or bug) 46 | w->xpos[head_idx] = random() % LED_MATRIX_WIDTH; 47 | return; 48 | } 49 | // The logic below chooses an xdelta and direction from the 50 | // previous x position. It leans toward using w->dir (-1 or 1) 51 | // as a direction, weighted by 0-MAX_DELTA. The chances 52 | // of this happening are w->dir_weight / 255. Otherwise 53 | // the wave will proceed in the oppossite direction to 54 | // create a chaotic feel to the rendering. 55 | uint16_t r = random(); 56 | // -1 means reverse 57 | const int8_t reverse = (r & 0xFF) < w->dir_weight ? 1 : -1; 58 | r >>= 8; 59 | const int8_t delta = reverse * w->dir * ((int8_t)(r % MAX_DELTA)); 60 | int8_t new_x = prev_x + delta; 61 | if ((new_x < 0) || (new_x >= LED_MATRIX_WIDTH)) { 62 | new_x = prev_x - delta; // go the other way instead 63 | reverse_wave(w); 64 | } 65 | w->xpos[head_idx] = new_x; 66 | } 67 | 68 | static void add_wave_points(uint32_t frame_index) { 69 | for (uint8_t i=0; ixpos[head_idx]; 77 | for (uint16_t y=0; yxpos[head_idx]; 79 | if (targetx < 0) { 80 | // all done 81 | return; 82 | } 83 | if (targetx == xcursor) { 84 | set_pixel2(led, xcursor, y, w->color); 85 | } else { 86 | const int8_t dir = targetx > xcursor ? 1 : -1; 87 | for (; xcursor != targetx; xcursor += dir) { 88 | set_pixel2(led, xcursor, y, w->color); 89 | } 90 | } 91 | head_idx = head_idx == 0 ? LED_MATRIX_HEIGHT - 1 : head_idx - 1; 92 | } 93 | } 94 | 95 | static void render_waves(uint32_t* led, uint32_t frame_index, uint16_t time_hhmm, uint32_t br_mask) { 96 | for (uint8_t i=0; icolor = br_mask | get_color(time_hhmm % 10); 100 | render_wave(led, w, head_idx); 101 | time_hhmm /= 10; 102 | } 103 | } 104 | 105 | static void overlay_time( 106 | uint32_t* led, uint16_t time_hhmm, uint32_t br_mask) { 107 | for (uint8_t i=0; i<4; ++i) { 108 | font.x = FONT_XOFFSET; 109 | font.y = 1 + i * FONT_YSPACING; 110 | font.color = br_mask | 0x00FFFFFF; 111 | number_draw_mode(&font, led, time_hhmm % 10, DRAW_MODE_COLOR); 112 | time_hhmm = time_hhmm / 10; 113 | } 114 | } 115 | 116 | static void init_wave(struct Waveform* w, uint8_t idx, uint8_t brightness) { 117 | w->dir_weight = rand_range(MIN_DIRECTION_WEIGHT, MAX_DIRECTION_WEIGHT); 118 | w->dir = random() & 1 ? -1 : 1; 119 | for (uint8_t i = 0; i < LED_MATRIX_HEIGHT; ++i) { 120 | w->xpos[i] = -1; 121 | } 122 | w->color = 0; 123 | } 124 | 125 | static void init(const uint8_t brightness) { 126 | number_font_init(&font, brightness, FONT_WIDTH, FONT_HEIGHT, FONT_WIDTH + 1); 127 | for (uint8_t i=0; i 5 | #include "../clock_settings.h" 6 | 7 | // Turns off all LEDs 8 | void waveform_render( 9 | uint32_t* led, 10 | uint32_t frame_index, 11 | uint16_t time_hhmm, 12 | const struct ClockSettings* settings); 13 | #endif 14 | 15 | -------------------------------------------------------------------------------- /src/set_time_high_res.c: -------------------------------------------------------------------------------- 1 | #include "set_time_high_res.h" 2 | 3 | #include "buttons.h" 4 | #include "clock.h" 5 | #include "colors.h" 6 | #include "led_matrix.h" 7 | #include "number_draw.h" 8 | #include 9 | 10 | #define DIGIT_CURRENT_BRIGHTNESS 0xFF 11 | #define DIGIT_SELECTED_BRIGHTNESS 0xFF 12 | #define DIGIT_OTHER_BRIGHTNESS 0x80 13 | // hold the time when the state was first entered. This 14 | // is used to avoid setting the clock (which changes seconds 15 | // to zero) if the user just scrolls through the time without 16 | // changing anything. 17 | static uint16_t orig_time; 18 | 19 | #define PLACE_HOUR_TENS 0 20 | #define PLACE_HOUR_ONES 1 21 | #define PLACE_MINUTE_TENS 2 22 | #define PLACE_MINUTE_ONES 3 23 | static uint8_t place; 24 | static uint8_t digits[4]; 25 | 26 | static struct NumberFont font; 27 | 28 | static void init(uint16_t time_hhmm) { 29 | orig_time = time_hhmm; 30 | digits[0] = time_hhmm / 1000; 31 | digits[1] = (time_hhmm / 100) % 10; 32 | digits[2] = (time_hhmm / 10) % 10; 33 | digits[3] = time_hhmm % 10; 34 | place = PLACE_HOUR_TENS; 35 | // assuming a 64x32 display for the font sizes 36 | number_font_init( 37 | &font, 38 | 0xFF, 39 | 6, 40 | 5, 41 | 7 42 | ); 43 | } 44 | 45 | static void render_digits( 46 | uint32_t* led, 47 | uint8_t val, 48 | uint8_t max_val, 49 | int16_t x, 50 | uint8_t is_current) { 51 | font.y = LED_MATRIX_HEIGHT - font.char_height - 3; 52 | for (uint8_t v=0; v <= max_val; ++v, font.y -= (font.char_height + 2)) { 53 | font.x = x; 54 | if (v != val) { 55 | font.char_width -= 2; 56 | font.x += 1; 57 | font.brightness = DIGIT_OTHER_BRIGHTNESS; 58 | number_draw(&font, led, v); 59 | font.char_width += 2; 60 | font.x -= 1; 61 | } else if (is_current) { 62 | font.brightness = DIGIT_CURRENT_BRIGHTNESS; 63 | number_draw(&font, led, v); 64 | } else { 65 | font.brightness = DIGIT_SELECTED_BRIGHTNESS; 66 | number_draw(&font, led, v); 67 | } 68 | } 69 | 70 | if (is_current) { 71 | // draw a line on the top and bottom to indicate the 72 | // current slot 73 | const uint32_t color = 0xFF000000 | get_color(val); 74 | for (uint16_t cx=0; cx max_val) { 112 | digits[p] = 0; 113 | } 114 | } 115 | } 116 | 117 | // public interface. Called to show and allow changing of the time 118 | uint8_t set_time_highres_render( 119 | uint32_t* led, 120 | uint8_t button_pressed, 121 | uint32_t frame_index, 122 | uint16_t time_hhmm, 123 | const struct ClockSettings* settings) { 124 | if (frame_index == 0) { 125 | init(time_hhmm); 126 | } 127 | 128 | if (button_pressed & SELECT_BUTTON) { 129 | ++place; 130 | if (place == 4) { 131 | maybe_set_time(); 132 | return 1; 133 | } 134 | } 135 | 136 | if (button_pressed & INCREMENT_BUTTON) { 137 | ++digits[place]; 138 | check_for_digit_wrap(); 139 | } 140 | 141 | render_digits( 142 | led, 143 | digits[0], 144 | 2, 145 | 0, 146 | place == 0); 147 | render_digits( 148 | led, 149 | digits[1], 150 | digits[0] == 2 ? 3 : 9, 151 | font.char_spacing + 1, 152 | place == 1); 153 | render_digits( 154 | led, 155 | digits[2], 156 | 5, 157 | LED_MATRIX_WIDTH - 2 - font.char_spacing * 2, 158 | place == 2); 159 | render_digits( 160 | led, 161 | digits[3], 162 | 9, 163 | LED_MATRIX_WIDTH - 1 - font.char_spacing, 164 | place == 3); 165 | return 0; 166 | } 167 | -------------------------------------------------------------------------------- /src/set_time_high_res.h: -------------------------------------------------------------------------------- 1 | #ifndef SET_TIME_HIRES_H 2 | #define SET_TIME_HIRES_H 3 | 4 | #include 5 | #include "clock_settings.h" 6 | 7 | // provides a common interface for rendering a clock 8 | 9 | uint8_t set_time_highres_render( 10 | uint32_t* led, 11 | uint8_t button_pressed, 12 | uint32_t frame_index, 13 | uint16_t time_hhmm, 14 | const struct ClockSettings* settings); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/set_time_low_res.c: -------------------------------------------------------------------------------- 1 | #include "set_time_low_res.h" 2 | 3 | #include "buttons.h" 4 | #include "clock.h" 5 | #include "led_matrix.h" 6 | #include "number_draw.h" 7 | #include 8 | 9 | // hold the time when the state was first entered. This 10 | // is used to avoid setting the clock (which changes seconds 11 | // to zero) if the user just scrolls through the time without 12 | // changing anything. 13 | static uint16_t orig_time; 14 | 15 | // UI state. 16 | static uint8_t hours; 17 | static uint8_t minutes; 18 | static uint8_t showing_minutes; 19 | 20 | static struct NumberFont font; 21 | 22 | // Increments minutes 23 | static void increment_minutes(void) { 24 | ++minutes; 25 | if (minutes >= 60) { 26 | minutes = 0; 27 | } 28 | } 29 | 30 | // Increments hours 31 | static void increment_hours(void) { 32 | ++hours; 33 | if (hours >= 24) { 34 | hours = 0; 35 | } 36 | } 37 | 38 | // Increments either the hours or minutes 39 | static void increment_current(void) { 40 | if (showing_minutes) { 41 | increment_minutes(); 42 | } else { 43 | increment_hours(); 44 | } 45 | } 46 | 47 | // public interface. Called to show and allow changing of the time 48 | uint8_t set_time_lowres_render( 49 | uint32_t* led, 50 | uint8_t button_pressed, 51 | uint32_t frame_index, 52 | uint16_t time_hhmm, 53 | const struct ClockSettings* settings) { 54 | if (frame_index == 0) { 55 | orig_time = time_hhmm; 56 | hours = time_hhmm / 100; 57 | minutes = time_hhmm % 100; 58 | showing_minutes = 0; 59 | number_font_init( 60 | &font, 61 | brightness_step_to_brightness(settings), 62 | LED_MATRIX_WIDTH / 2 - 1, 63 | LED_MATRIX_HEIGHT, 64 | LED_MATRIX_WIDTH / 4); 65 | } 66 | font.x = 0; 67 | font.y = 0; 68 | draw_numbers( 69 | &font, 70 | led, 71 | showing_minutes ? minutes : hours); 72 | if (button_pressed & INCREMENT_BUTTON) { 73 | increment_current(); 74 | } 75 | if (button_pressed & SELECT_BUTTON) { 76 | if (showing_minutes) { 77 | const uint16_t new_time = hours * 100 + minutes; 78 | if (new_time != orig_time) { 79 | clock_set_time(new_time); 80 | } 81 | return 1; 82 | } 83 | showing_minutes = 1; 84 | } 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /src/set_time_low_res.h: -------------------------------------------------------------------------------- 1 | #ifndef SET_TIME_LOWRES_H 2 | #define SET_TIME_LOWRES_H 3 | 4 | #include 5 | #include "clock_settings.h" 6 | 7 | // provides a common interface for rendering a clock 8 | 9 | uint8_t set_time_lowres_render( 10 | uint32_t* led, 11 | uint8_t button_pressed, 12 | uint32_t frame_index, 13 | uint16_t time_hhmm, 14 | const struct ClockSettings* settings); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/tools/distance_generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """This program calculates x,y coordinates for 90 angle arcs at various 4 | distances from a point. 5 | 6 | The format is included in the generated include file for clarity. 7 | """ 8 | 9 | import math 10 | from typing import TextIO 11 | 12 | DISTANCE_SCALE = 1.5 13 | MIN_WEIGHT = 0x20 14 | ANGLE_INCREMENT = math.pi / 1800 15 | 16 | def get_weight(distance: int) -> int: 17 | if distance == 0: 18 | return 255 19 | scale = float(distance) / DISTANCE_SCALE 20 | return round(255.0 / (1 + scale)) 21 | 22 | 23 | def calc_weights() -> list[int]: 24 | weights = [] 25 | distance = 0 26 | while True: 27 | w = get_weight(distance) 28 | if w < MIN_WEIGHT: 29 | return weights 30 | weights.append(w) 31 | distance = distance + 1.0 32 | 33 | def gen_points(distance: int) -> list[tuple[int, int]]: 34 | """Format is (x, y)""" 35 | data = [] 36 | angle = 0.0 37 | while True: 38 | x = round(distance * math.cos(angle)) 39 | y = round(distance * math.sin(angle)) 40 | if not data or data[-1] != (x, y): 41 | data.append((x, y)) 42 | angle = angle + ANGLE_INCREMENT 43 | if angle > math.pi / 2.0: 44 | break 45 | return data 46 | 47 | def generate_header() -> None: 48 | output = ( 49 | '// This file was generated by running matrix_clock/tools/distance_generator.py', 50 | '// with no arguments and redirecting the output to a file.', 51 | '', 52 | ) 53 | print('\n'.join(output)) 54 | 55 | def generate_weights(weights: list[int]) -> None: 56 | data = ( 57 | f'#define NUM_DISTANCES {len(weights)} // MAX is -1 this val', 58 | '', 59 | '// Each number below is the weight to apply to a color at a given ', 60 | '// distance. The range is 0x00-0xFF.', 61 | '', 62 | 'uint8_t distance_weights[NUM_DISTANCES] __in_flash() = {', 63 | ) 64 | print('\n'.join(data)) 65 | for idx, w in enumerate(weights): 66 | print(' 0x%02X, // %d' % (w, idx)) 67 | print('};\n') 68 | 69 | def generate_offsets(distances: list[list[tuple[int, int]]]) -> None: 70 | data = ( 71 | '', 72 | '// Each number below is the offset into the array for the given ', 73 | '// distance. The next element is used to calculate the length.', 74 | '// The final element is used only for the length calculation', 75 | '', 76 | 'uint16_t distance_offsets[NUM_DISTANCES + 1] __in_flash() = {', 77 | ) 78 | print('\n'.join(data)) 79 | offset = 0; 80 | for idx, point_list in enumerate(distances): 81 | print(f' 0x%04X, // %d' % (offset, idx)) 82 | offset += len(point_list) 83 | print(f' 0x%04X,' % offset) 84 | print('};\n') 85 | 86 | def chunks(lst, n): 87 | """Yield successive n-sized chunks from lst.""" 88 | for i in range(0, len(lst), n): 89 | yield lst[i:i + n] 90 | 91 | def generate_point_list(idx: int, points: list[tuple[int, int]]) -> None: 92 | print(f' // {idx}') 93 | for pl in chunks(points, 8): 94 | line = [' '] 95 | for p in pl: 96 | x, y = p 97 | line.append('0x%02X%02X,' % (x, y)) 98 | print(' '.join(line)) 99 | 100 | def generate_data(distances: list[list[tuple[int, int]]]) -> None: 101 | num_points = sum(len(pl) for pl in distances) 102 | data = ( 103 | '// each element is of the format 0xXXYY', 104 | 'uint16_t distance_points[%u] __in_flash() = {' % num_points, 105 | ) 106 | print('\n'.join(data)) 107 | for idx, point_list in enumerate(distances): 108 | generate_point_list(idx, point_list) 109 | print('};\n') 110 | 111 | 112 | def generate_output( 113 | weights: list[int], distances: list[list[tuple[int, int]]]) -> None: 114 | generate_header() 115 | generate_weights(weights) 116 | generate_offsets(distances) 117 | generate_data(distances) 118 | 119 | def main() -> None: 120 | weights = calc_weights() 121 | distances = [gen_points(d) for d in range(len(weights))] 122 | generate_output(weights, distances) 123 | 124 | if __name__ == '__main__': 125 | main() 126 | 127 | --------------------------------------------------------------------------------