├── LICENSE ├── README.md ├── case ├── grumpy_case_build123d.py ├── grumpy_case_cadquery.py ├── grumpy_case_choc.py ├── grumpy_case_lp.py ├── grumpy_lp.FCStd └── grumpy_lp_choc.FCStd ├── firmware └── QMK │ ├── grumpy │ ├── config.h │ ├── halconf.h │ ├── info.json │ ├── keymaps │ │ ├── default │ │ │ └── keymap.c │ │ └── vial │ │ │ ├── config.h │ │ │ ├── keymap.c │ │ │ ├── rules.mk │ │ │ └── vial.json │ ├── mcuconf.h │ └── rules.mk │ ├── grumpy_MX_vial.uf2 │ ├── grumpy_chocV1 │ ├── config.h │ ├── halconf.h │ ├── info.json │ ├── keymaps │ │ ├── default │ │ │ └── keymap.c │ │ └── vial │ │ │ ├── config.h │ │ │ ├── keymap.c │ │ │ ├── rules.mk │ │ │ └── vial.json │ ├── mcuconf.h │ └── rules.mk │ └── grumpy_chocV1_vial.uf2 ├── grumpy_ch552t ├── fp-info-cache ├── fp-lib-table ├── grumpy_ch522t.kicad_pcb ├── grumpy_ch522t.kicad_prl ├── grumpy_ch522t.kicad_pro └── grumpy_ch522t.kicad_sch ├── grumpy_choc ├── fp-info-cache ├── fp-lib-table ├── grumpy_choc.kicad_pcb ├── grumpy_choc.kicad_prl ├── grumpy_choc.kicad_pro ├── grumpy_choc.kicad_sch └── sym-lib-table ├── grumpy_xiao ├── grumpy.kicad_pcb ├── grumpy.kicad_prl ├── grumpy.kicad_pro └── grumpy.kicad_sch ├── img ├── choc_v1_alu.jpg ├── grumpies.jpg ├── grumpy.png └── grumpy_mjf.png └── prod ├── ChocV1 low profile ├── case_choc │ ├── grumpy case threads drawing.pdf │ ├── grumpy_lp_choc_bottom.step │ └── grumpy_lp_choc_top.step └── grumpy_chocV1_GERBER_20250107.zip ├── MX ChocV2 low profile ├── case_chocV2 │ ├── grumpy_lp.step │ ├── grumpy_lp.stl │ ├── grumpy_lp_bottom.step │ └── grumpy_lp_bottom.stl └── grumpy_chocV2_GERBER_20240611.zip └── MX Xiao ├── case_mx └── grumpy.stl └── grumpy_mx_GERBER_20230724.zip /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 weteor 2 | 3 | CERN Open Hardware Licence Version 2 - Permissive 4 | 5 | Preamble 6 | 7 | CERN has developed this licence to promote collaboration among 8 | hardware designers and to provide a legal tool which supports the 9 | freedom to use, study, modify, share and distribute hardware designs 10 | and products based on those designs. Version 2 of the CERN Open 11 | Hardware Licence comes in three variants: this licence, CERN-OHL-P 12 | (permissive); and two reciprocal licences: CERN-OHL-W (weakly 13 | reciprocal) and CERN-OHL-S (strongly reciprocal). 14 | 15 | The CERN-OHL-P is copyright CERN 2020. Anyone is welcome to use it, in 16 | unmodified form only. 17 | 18 | Use of this Licence does not imply any endorsement by CERN of any 19 | Licensor or their designs nor does it imply any involvement by CERN in 20 | their development. 21 | 22 | 23 | 1 Definitions 24 | 25 | 1.1 'Licence' means this CERN-OHL-P. 26 | 27 | 1.2 'Source' means information such as design materials or digital 28 | code which can be applied to Make or test a Product or to 29 | prepare a Product for use, Conveyance or sale, regardless of its 30 | medium or how it is expressed. It may include Notices. 31 | 32 | 1.3 'Covered Source' means Source that is explicitly made available 33 | under this Licence. 34 | 35 | 1.4 'Product' means any device, component, work or physical object, 36 | whether in finished or intermediate form, arising from the use, 37 | application or processing of Covered Source. 38 | 39 | 1.5 'Make' means to create or configure something, whether by 40 | manufacture, assembly, compiling, loading or applying Covered 41 | Source or another Product or otherwise. 42 | 43 | 1.6 'Notice' means copyright, acknowledgement and trademark notices, 44 | references to the location of any Notices, modification notices 45 | (subsection 3.3(b)) and all notices that refer to this Licence 46 | and to the disclaimer of warranties that are included in the 47 | Covered Source. 48 | 49 | 1.7 'Licensee' or 'You' means any person exercising rights under 50 | this Licence. 51 | 52 | 1.8 'Licensor' means a person who creates Source or modifies Covered 53 | Source and subsequently Conveys the resulting Covered Source 54 | under the terms and conditions of this Licence. A person may be 55 | a Licensee and a Licensor at the same time. 56 | 57 | 1.9 'Convey' means to communicate to the public or distribute. 58 | 59 | 60 | 2 Applicability 61 | 62 | 2.1 This Licence governs the use, copying, modification, Conveying 63 | of Covered Source and Products, and the Making of Products. By 64 | exercising any right granted under this Licence, You irrevocably 65 | accept these terms and conditions. 66 | 67 | 2.2 This Licence is granted by the Licensor directly to You, and 68 | shall apply worldwide and without limitation in time. 69 | 70 | 2.3 You shall not attempt to restrict by contract or otherwise the 71 | rights granted under this Licence to other Licensees. 72 | 73 | 2.4 This Licence is not intended to restrict fair use, fair dealing, 74 | or any other similar right. 75 | 76 | 77 | 3 Copying, Modifying and Conveying Covered Source 78 | 79 | 3.1 You may copy and Convey verbatim copies of Covered Source, in 80 | any medium, provided You retain all Notices. 81 | 82 | 3.2 You may modify Covered Source, other than Notices. 83 | 84 | You may only delete Notices if they are no longer applicable to 85 | the corresponding Covered Source as modified by You and You may 86 | add additional Notices applicable to Your modifications. 87 | 88 | 3.3 You may Convey modified Covered Source (with the effect that You 89 | shall also become a Licensor) provided that You: 90 | 91 | a) retain Notices as required in subsection 3.2; and 92 | 93 | b) add a Notice to the modified Covered Source stating that You 94 | have modified it, with the date and brief description of how 95 | You have modified it. 96 | 97 | 3.4 You may Convey Covered Source or modified Covered Source under 98 | licence terms which differ from the terms of this Licence 99 | provided that You: 100 | 101 | a) comply at all times with subsection 3.3; and 102 | 103 | b) provide a copy of this Licence to anyone to whom You 104 | Convey Covered Source or modified Covered Source. 105 | 106 | 107 | 4 Making and Conveying Products 108 | 109 | You may Make Products, and/or Convey them, provided that You ensure 110 | that the recipient of the Product has access to any Notices applicable 111 | to the Product. 112 | 113 | 114 | 5 DISCLAIMER AND LIABILITY 115 | 116 | 5.1 DISCLAIMER OF WARRANTY -- The Covered Source and any Products 117 | are provided 'as is' and any express or implied warranties, 118 | including, but not limited to, implied warranties of 119 | merchantability, of satisfactory quality, non-infringement of 120 | third party rights, and fitness for a particular purpose or use 121 | are disclaimed in respect of any Source or Product to the 122 | maximum extent permitted by law. The Licensor makes no 123 | representation that any Source or Product does not or will not 124 | infringe any patent, copyright, trade secret or other 125 | proprietary right. The entire risk as to the use, quality, and 126 | performance of any Source or Product shall be with You and not 127 | the Licensor. This disclaimer of warranty is an essential part 128 | of this Licence and a condition for the grant of any rights 129 | granted under this Licence. 130 | 131 | 5.2 EXCLUSION AND LIMITATION OF LIABILITY -- The Licensor shall, to 132 | the maximum extent permitted by law, have no liability for 133 | direct, indirect, special, incidental, consequential, exemplary, 134 | punitive or other damages of any character including, without 135 | limitation, procurement of substitute goods or services, loss of 136 | use, data or profits, or business interruption, however caused 137 | and on any theory of contract, warranty, tort (including 138 | negligence), product liability or otherwise, arising in any way 139 | in relation to the Covered Source, modified Covered Source 140 | and/or the Making or Conveyance of a Product, even if advised of 141 | the possibility of such damages, and You shall hold the 142 | Licensor(s) free and harmless from any liability, costs, 143 | damages, fees and expenses, including claims by third parties, 144 | in relation to such use. 145 | 146 | 147 | 6 Patents 148 | 149 | 6.1 Subject to the terms and conditions of this Licence, each 150 | Licensor hereby grants to You a perpetual, worldwide, 151 | non-exclusive, no-charge, royalty-free, irrevocable (except as 152 | stated in this section 6, or where terminated by the Licensor 153 | for cause) patent licence to Make, have Made, use, offer to 154 | sell, sell, import, and otherwise transfer the Covered Source 155 | and Products, where such licence applies only to those patent 156 | claims licensable by such Licensor that are necessarily 157 | infringed by exercising rights under the Covered Source as 158 | Conveyed by that Licensor. 159 | 160 | 6.2 If You institute patent litigation against any entity (including 161 | a cross-claim or counterclaim in a lawsuit) alleging that the 162 | Covered Source or a Product constitutes direct or contributory 163 | patent infringement, or You seek any declaration that a patent 164 | licensed to You under this Licence is invalid or unenforceable 165 | then any rights granted to You under this Licence shall 166 | terminate as of the date such process is initiated. 167 | 168 | 169 | 7 General 170 | 171 | 7.1 If any provisions of this Licence are or subsequently become 172 | invalid or unenforceable for any reason, the remaining 173 | provisions shall remain effective. 174 | 175 | 7.2 You shall not use any of the name (including acronyms and 176 | abbreviations), image, or logo by which the Licensor or CERN is 177 | known, except where needed to comply with section 3, or where 178 | the use is otherwise allowed by law. Any such permitted use 179 | shall be factual and shall not be made so as to suggest any kind 180 | of endorsement or implication of involvement by the Licensor or 181 | its personnel. 182 | 183 | 7.3 CERN may publish updated versions and variants of this Licence 184 | which it considers to be in the spirit of this version, but may 185 | differ in detail to address new problems or concerns. New 186 | versions will be published with a unique version number and a 187 | variant identifier specifying the variant. If the Licensor has 188 | specified that a given variant applies to the Covered Source 189 | without specifying a version, You may treat that Covered Source 190 | as being released under any version of the CERN-OHL with that 191 | variant. If no variant is specified, the Covered Source shall be 192 | treated as being released under CERN-OHL-S. The Licensor may 193 | also specify that the Covered Source is subject to a specific 194 | version of the CERN-OHL or any later version in which case You 195 | may apply this or any later version of CERN-OHL with the same 196 | variant identifier published by CERN. 197 | 198 | 7.4 This Licence shall not be enforceable except by a Licensor 199 | acting as such, and third party beneficiary rights are 200 | specifically excluded. 201 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### grumpy 2 | 3 | 28 key (3-row) angled unibody keyboard with col stagger 4 | 5 | top 6 | 7 | ## Features 8 | 9 | ###### MX Xiao-Version: 10 | 11 | - spacing: MX 12 | - case: open bottom (3dp) 13 | - Hotswap sockets (MX) 14 | - Seeed Xiao Controller 15 | - RP2040 (w/ QMK, Vial) 16 | - BLE (w/ZMK) 17 | - SAMD21 (should work, don't have one to test) 18 | - gerber and case files are supplied (kicad files, stl as well as cadquery files) 19 | - completely open source, permissive license ([CERN-OHL-P](https://cern-ohl.web.cern.ch/home)) 20 | 21 | ###### MX/ChocV2 CH552T-Version: 22 | 23 | - spacing: MX 24 | - case: top w/ bottom plate (top and bottom 3dp) 25 | - Hotswap sockets (MX and Choc V1/V2) 26 | - CH552T Controller (w/ FAK firmware) 27 | - gerber and case files are supplied (kicad files, stl as well as cadquery files) 28 | - completely open source, permissive license ([CERN-OHL-P](https://cern-ohl.web.cern.ch/home)) 29 | 30 | ###### ChocV1 Xiao-Version: 31 | 32 | - spacing: choc 33 | - case: top w/ bottom plate (top 3dp/cnc, bottom 3dp) 34 | - Hotswap sockets (Choc V1) 35 | - Seeed Xiao Controller 36 | - RP2040 (w/ QMK, Vial) 37 | - BLE (w/ZMK) 38 | - SAMD21 (should work, don't have one to test) 39 | - gerber and case files are supplied (kicad files, stl as well as cadquery files) 40 | - completely open source, permissive license ([CERN-OHL-P](https://cern-ohl.web.cern.ch/home)) 41 | 42 | ## Want one? 43 | 44 | All production files you need to build your own board can be found [here](./prod/). 45 | 46 | The case has no bottom and ends right below the HS Sockets. You may either use it as is, but preferably use some 2-3mm self-adhesive neopren on the whole pcb. The case will be hard to print on a FDM Printer, so maybe use a service to print it in resin or nylon. 47 | 48 | Apart from the pcb and optionally a case you need: 49 | 50 | ###### Xiao-Version 51 | 52 | - 28 hotswap sockets 53 | - 28 diodes (1N4148 int SOT-123) 54 | - 28 of your favourite switches 55 | - 1 Controller 56 | 57 | ###### CH552T-Version: 58 | 59 | - 28 hotswap sockets 60 | - 28 diodes (1N4148 int SOT-123) 61 | - 28 of your favourite switches 62 | - 1x CH552T (TSSOP-20) 63 | - 1x USBLC6-2SC6 (SOT-23-6) 64 | - 1x 10kOhm resistor (SMD 0603) 65 | - 2x 5.1kOhm resistors (SMD 0603) 66 | - 2x 100nF capacitors (SMD 0603) 67 | - 1x USB Connector C-Type, 12 pin/16pin, mid-mount (1.6mm) 68 | 69 | ### firmware 70 | 71 | ###### Xiao-Version: 72 | 73 | firmware configs for qmk and vial can be found in the [firmware folder](./firmware). 74 | 75 | The first time the pcb is plugged in, the bootloader will provide a drive to upload the firmware file. 76 | 77 | ###### CH552T-Version: 78 | 79 | firmware config for FAK can be found [here](https://github.com/weteor/fak-config/tree/main/keyboards/grumpy). Please also see [FAK-Firmware site](https://github.com/semickolon/fak) for more information 80 | 81 | Bootloader should be available on first plugins until firmware is written. After that either use the firmware BOOT to go into bootloader, or hold the boot button on the pcb pressed while pluggin in the usb cable. 82 | 83 | ## the rest 84 | 85 | Everything in this repository is free to use however you might see fit. If you want to support me and my projects, please consider linking back to this repository if you build/change/use anything. 86 | 87 | If you would like to send me a tip, you could do it [here](https://ko-fi.com/weteor) (Please don't feel like you have to). 88 | 89 | ## more pictures 90 | 91 | ![top](img/choc_v1_alu.jpg) 92 | ![top](img/grumpies.jpg) 93 | -------------------------------------------------------------------------------- /case/grumpy_case_build123d.py: -------------------------------------------------------------------------------- 1 | from build123d import * 2 | 3 | import cadquery as cq 4 | import cadquery.selectors as cqs 5 | from cadquery import NearestToPointSelector, exporters as exp 6 | 7 | # CONSTANTS 8 | spacing = 19.05 # MX-Spacing 9 | holeSize = 14 # Platehole size 10 | pcbThickness = 1.6 # PCB Thickness 11 | hsThickness = 1.85 # HS Socket Thickness below PCB 12 | hsSafety = 1 # extra space to hide HS Sockets 13 | 14 | # CASE PARAMETERS 15 | keySafety = 0.5 # extra space between keycap and case 16 | spaceAbovePCB = 0.25 # space between PCB and Plate. 17 | plateHeight = 5 - spaceAbovePCB # heigth of plate 18 | colStagger = 0.25 * spacing # stagger between cols 19 | 20 | 21 | heightAbovePlate = 8.5 # height of case rim measured from plate 22 | heightBelowPlate = pcbThickness+hsThickness+hsSafety # height of rim hiding pcb and Sockets 23 | 24 | overallHeight = heightAbovePlate+heightBelowPlate+plateHeight 25 | 26 | outerRad = 5 # radius of outer edge fillets 27 | outerRadSmall = 1.5 # radius of other outline fillets 28 | 29 | wallWidth = 7.5 # Wall Width (in effect only left and right) 30 | lWallWidth = 3 # min Wallthickness for keys outside of case body 31 | 32 | rectOffset = 0.125*19.05-colStagger/2 # rectangular case body y offset 33 | rectHeight = 3*spacing+2*lWallWidth+colStagger # rectangular case y height 34 | 35 | 36 | caseWidth = 10 *spacing + 2*wallWidth # absolute case width 37 | caseHeight = 3*spacing + 2*wallWidth + 3*colStagger # absolute case height 38 | 39 | handAngle = 14 # degrees of rotation for each hand 40 | 41 | centerInset = 2 #how much lower the inner cutout should be 42 | 43 | def getRowPos(rowOffset=0): 44 | """ returns x y coordinate tuple for each right hand switch of the selected row 45 | 46 | :param rowOffset: row number counted from the top 47 | :return list of coordinate tuples 48 | """ 49 | 50 | topSwitchY = caseHeight/2-wallWidth-spacing/2-rowOffset*spacing 51 | 52 | 53 | points = [ 54 | ( 1.5 * spacing, topSwitchY - 2 * colStagger ), 55 | ( 2.5 * spacing, topSwitchY - 1 * colStagger ), 56 | ( 3.5 * spacing, topSwitchY - 2 * colStagger ), 57 | ] 58 | if (rowOffset > 0): 59 | # points.append(( 4.5 * spacing, topSwitchY - 3.5 * colStagger ) ) 60 | points.append(( 4.5 * spacing, topSwitchY - 4 * colStagger ) ) 61 | 62 | if (rowOffset < 2): 63 | points.append(( 0.5 * spacing, topSwitchY - 4 * colStagger )) 64 | 65 | 66 | 67 | return points 68 | 69 | def getSwitchPositions(keys=True): 70 | """ collects all positions for the first three rows 71 | 72 | :param keys: if true returns alphakey positions, if false returns thumbkeyposition 73 | :return list of coordinate tuples 74 | """ 75 | if keys: 76 | return getRowPos(0) + getRowPos(1) + getRowPos(2) 77 | else: 78 | return [( 0.25 * spacing, caseHeight/2-wallWidth-spacing/2-2*spacing - 4 * colStagger )] 79 | 80 | def getAlphaKeyPos(): 81 | return getSwitchPositions(True) 82 | 83 | def getThumbKeyPos(): 84 | return getSwitchPositions(False) 85 | 86 | def getAllKeyPos(): 87 | return getAlphaKeyPos() + getThumbKeyPos() 88 | 89 | def getInnerEdges(object): 90 | obj = ( object.edges() 91 | .filter_by(Axis.Z) 92 | .filter_by( 93 | lambda v: v.center().X > 2 and v.center().X < (caseWidth/2-20)) 94 | ) 95 | return obj; 96 | 97 | 98 | ## ------------------------------------------------------------------------------ 99 | 100 | with BuildSketch() as SketchOutline: 101 | # outline shapes for alpha and thumbs 102 | with Locations(getAlphaKeyPos()): 103 | Rectangle(spacing+2*lWallWidth, spacing+2*lWallWidth) 104 | with Locations(getThumbKeyPos()): 105 | Rectangle(spacing*1.5+2*lWallWidth, spacing+2*lWallWidth) 106 | with Locations((caseWidth/4-7+5,-8)): 107 | Rectangle(caseWidth/2+10, 2*spacing+2*wallWidth+2.5+10, rotation=-handAngle) 108 | with Locations((-21.2,5)): 109 | Rectangle(40-lWallWidth, 46.9, mode=Mode.SUBTRACT) 110 | 111 | with BuildSketch() as CaseOutline: 112 | with Locations((4.33,0,0)): 113 | add(SketchOutline.sketch, rotation=handAngle) 114 | with Locations((-20,0)): 115 | Rectangle(40,caseHeight*2, mode=Mode.SUBTRACT) 116 | 117 | with BuildSketch() as CaseOutlineFilletOuter: 118 | add(CaseOutline.sketch) 119 | fillet(CaseOutlineFilletOuter.edges().sort_by(Axis.X)[-1].vertices(), outerRad) 120 | 121 | with BuildSketch() as KeyCutout: 122 | with Locations(getAlphaKeyPos()): 123 | Rectangle(spacing+keySafety, spacing+keySafety) 124 | with Locations(getThumbKeyPos()): 125 | Rectangle(1.5*spacing+keySafety, spacing+keySafety) 126 | fillet(KeyCutout.vertices().sort_by(Axis.X)[4:], 1) 127 | fillet(KeyCutout.vertices().group_by(Axis.X)[0].sort_by(Axis.Y)[0], 1) 128 | fillet(KeyCutout.vertices().group_by(Axis.X)[2].sort_by(Axis.Y)[0], 1) 129 | 130 | with BuildSketch() as USBCutoutOuter: 131 | Rectangle(13,7) 132 | fillet(USBCutoutOuter.vertices(), 2.5) 133 | 134 | with BuildSketch() as USBCutoutInner: 135 | Rectangle(10,5) 136 | fillet(USBCutoutInner.vertices(), 1.5) 137 | 138 | with BuildSketch() as USBCutoutOuterStraight: 139 | with Locations((0,-1.5)): 140 | Rectangle(12.5,10.5) 141 | fillet(USBCutoutOuterStraight.vertices().group_by(Axis.Y)[-1], 2.5) 142 | ## ------------------------------------------------------------------------------ 143 | 144 | with BuildPart() as FullCase: 145 | 146 | # Build Case Bottom below Plate 147 | with BuildPart() as Bottom: 148 | add(CaseOutlineFilletOuter.sketch) 149 | extrude(amount=heightBelowPlate) 150 | # select faces that should not be offset = open faces 151 | remFaces = Bottom.faces().sort_by(Axis.Z)[0] 152 | remFaces += Bottom.faces().sort_by(Axis.Z)[-1] 153 | remFaces += Bottom.faces().sort_by(Axis.X)[:5].sort_by(Axis.Y)[-4:] 154 | # create shell 155 | offset(amount=-lWallWidth, openings=remFaces, kind=Kind.INTERSECTION) 156 | fillet(getInnerEdges(Bottom), outerRadSmall) 157 | 158 | # Build Plate part 159 | with BuildPart(Plane(origin=(0,0,heightBelowPlate))) as Plate: 160 | add(CaseOutlineFilletOuter.sketch) 161 | extrude(amount=plateHeight) 162 | fillet(getInnerEdges(Plate), outerRadSmall) 163 | # work plane for further operations 164 | wPlane = Plane(origin=(4.33,0,heightBelowPlate)).rotated((0,0,handAngle)) 165 | # add cutouts for switch clips 166 | with BuildSketch(wPlane) : 167 | with Locations(getAllKeyPos()): 168 | Rectangle(5,holeSize+2) 169 | extrude(amount=plateHeight-1.5, mode=Mode.SUBTRACT) 170 | # add switch cutout 171 | with BuildSketch(wPlane) : 172 | with Locations(getAllKeyPos()): 173 | Rectangle(holeSize,holeSize) 174 | extrude(amount=plateHeight, mode=Mode.SUBTRACT) 175 | 176 | # Build Top part 177 | with BuildPart(Plane(origin=(0,0,heightBelowPlate+plateHeight))) as Top: 178 | add(CaseOutlineFilletOuter.sketch) 179 | extrude(amount=heightAbovePlate) 180 | fillet(getInnerEdges(Top), outerRadSmall) 181 | # work plane for further operations 182 | wPlane = Plane(origin=(4.33,0,heightBelowPlate+plateHeight)).rotated((0,0,handAngle)) 183 | # add keycap cutout 184 | with BuildSketch(wPlane) : 185 | add(KeyCutout.sketch) 186 | extrude(amount=heightAbovePlate, mode=Mode.SUBTRACT) 187 | # lower center cutout 188 | extrude(Top.faces().filter_by(Axis.Z).group_by(Axis.Z)[-1].sort_by(Axis.X)[0], 189 | amount=-centerInset, mode=Mode.SUBTRACT) 190 | show_object(Bottom) 191 | show_object(Plate) 192 | show_object(Top) 193 | 194 | mirror(FullCase.part, about=Plane.YZ) 195 | 196 | # add fillets on mirrored edges 197 | fillet(FullCase.edges() 198 | .filter_by(Axis.Z) 199 | .filter_by( 200 | lambda v: (v.center().X < 0.05 and v.center().X > -0.05) and 201 | ((v.center().Y < 0 and v.center().Y > -25) or v.center().Y > 7)), 1) 202 | # add top groove 203 | groove_wire = FullCase.faces().filter_by(Axis.Z).group_by(Axis.Z)[-2][0].outer_wire() #wires().sort_by(SortBy.LENGTH)[-1] 204 | groove_wire = groove_wire.rotate(Axis.Z, 180).translate((0,33,centerInset)) 205 | extrude(Face(groove_wire), amount=-2, mode=Mode.SUBTRACT) 206 | 207 | # fillet top groove edges 208 | groove_fil_edges = FullCase.edges(Select.LAST).group_by(Axis.Y)[-1].sort_by(Axis.X)[1:-1] 209 | fillet(groove_fil_edges, outerRadSmall) 210 | 211 | # outline Chamfer 212 | main_top_face = FullCase.faces().filter_by(Axis.Z).group_by(Axis.Z)[-1].sort_by(Axis.X)[0] 213 | chamfer(main_top_face.outer_wire().edges(), 1) 214 | chamfer(main_top_face.inner_wires().edges(), 0.5) 215 | 216 | inset_face = FullCase.faces().filter_by(Axis.Z).group_by(Axis.Z)[-2].sort_by(Axis.Y)[0] 217 | chamfer(inset_face.edges(), 0.5) 218 | 219 | bottom_face = FullCase.faces().filter_by(Axis.Z).group_by(Axis.Z)[0][0] 220 | chamfer(bottom_face.outer_wire().edges(), 0.7) 221 | 222 | # usb cutout 223 | usb_face = FullCase.faces().filter_by(Axis.Y).group_by(Axis.Y)[-1].sort_by(SortBy.LENGTH)[-1] 224 | usb_plane = Plane(usb_face).shift_origin((usb_face.center().X,usb_face.center().Y,heightBelowPlate)) 225 | with BuildSketch(usb_plane): 226 | add(USBCutoutInner.sketch) 227 | extrude(amount=-5, mode=Mode.SUBTRACT) 228 | 229 | with BuildSketch(usb_plane): 230 | add(USBCutoutOuterStraight.sketch, rotation=180) 231 | extrude(amount=-1, mode=Mode.SUBTRACT) 232 | 233 | inner_usb_edges = FullCase.faces(Select.LAST).filter_by(Axis.Y).sort_by(Axis.Y)[0].inner_wires().edges() 234 | outer_usb_edges = FullCase.edges(Select.LAST).group_by(Axis.Y)[-1].sort_by(Axis.X)[1:-1] 235 | 236 | chamfer(inner_usb_edges, 0.75) 237 | chamfer(outer_usb_edges, 0.75) 238 | 239 | show_object(FullCase, name="full" ) -------------------------------------------------------------------------------- /case/grumpy_case_cadquery.py: -------------------------------------------------------------------------------- 1 | import cadquery as cq 2 | import cadquery.selectors as cqs 3 | from cadquery import NearestToPointSelector, exporters as exp 4 | 5 | # CONSTANTS 6 | spacing = 19.05 # MX-Spacing 7 | holeSize = 14 # Platehole size 8 | pcbThickness = 1.6 # PCB Thickness 9 | hsThickness = 1.85 # HS Socket Thickness below PCB 10 | hsSafety = 1 # extra space to hide HS Sockets 11 | 12 | # CASE PARAMETERS 13 | keySafety = 0.5 # extra space between keycap and case 14 | spaceAbovePCB = 0.25 # space between PCB and Plate. 15 | plateHeight = 5 - spaceAbovePCB # heigth of plate 16 | colStagger = 0.25 * spacing # stagger between cols 17 | 18 | 19 | heightAbovePlate = 8.5 # height of case rim measured from plate 20 | heightBelowPlate = pcbThickness+hsThickness+hsSafety # height of rim hiding pcb and Sockets 21 | 22 | overallHeight = heightAbovePlate+heightBelowPlate+plateHeight 23 | 24 | outerRad = 5 # radius of outer edge fillets 25 | outerRadSmall = 1.5 # radius of other outline fillets 26 | 27 | wallWidth = 7.5 # Wall Width (in effect only left and right) 28 | lWallWidth = 3 # min Wallthickness for keys outside of case body 29 | 30 | rectOffset = 0.125*19.05-colStagger/2 # rectangular case body y offset 31 | rectHeight = 3*spacing+2*lWallWidth+colStagger # rectangular case y height 32 | 33 | 34 | caseWidth = 10 *spacing + 2*wallWidth # absolute case width 35 | caseHeight = 3*spacing + 2*wallWidth + 3*colStagger # absolute case height 36 | 37 | handAngle = 14 # degrees of rotation for each hand 38 | 39 | centerInset = 2 #how much lower the inner cutout should be 40 | 41 | ## ------------------------------------------------------------------------------ 42 | 43 | def getRowPos(rowOffset=0): 44 | """ returns x y coordinate tuple for each right hand switch of the selected row 45 | 46 | :param rowOffset: row number counted from the top 47 | :return list of coordinate tuples 48 | """ 49 | 50 | topSwitchY = caseHeight/2-wallWidth-spacing/2-rowOffset*spacing 51 | 52 | 53 | points = [ 54 | ( 1.5 * spacing, topSwitchY - 2 * colStagger ), 55 | ( 2.5 * spacing, topSwitchY - 1 * colStagger ), 56 | ( 3.5 * spacing, topSwitchY - 2 * colStagger ), 57 | ] 58 | if (rowOffset > 0): 59 | # points.append(( 4.5 * spacing, topSwitchY - 3.5 * colStagger ) ) 60 | points.append(( 4.5 * spacing, topSwitchY - 4 * colStagger ) ) 61 | 62 | if (rowOffset < 2): 63 | points.append(( 0.5 * spacing, topSwitchY - 4 * colStagger )) 64 | 65 | 66 | 67 | return points 68 | 69 | def getSwitchPositions(keys=True): 70 | """ collects all positions for the first three rows 71 | 72 | :param keys: if true returns alphakey positions, if false returns thumbkeyposition 73 | :return list of coordinate tuples 74 | """ 75 | if keys: 76 | return getRowPos(0) + getRowPos(1) + getRowPos(2) 77 | else: 78 | return [( 0.25 * spacing, caseHeight/2-wallWidth-spacing/2-2*spacing - 4 * colStagger )] 79 | 80 | def getAlphaKeyPos(): 81 | return getSwitchPositions(True) 82 | 83 | def getThumbKeyPos(): 84 | return getSwitchPositions(False) 85 | 86 | def getAllKeyPos(): 87 | return getAlphaKeyPos() + getThumbKeyPos() 88 | 89 | ## ------------------------------------------------------------------------------ 90 | 91 | # CADQUERY EXTENSIONS 92 | 93 | def _rotateAndClean(self, inverseCut = False): 94 | if inverseCut: 95 | cutDir = -1 96 | else: 97 | cutDir = 1 98 | 99 | obj = ( 100 | self.rotate((0,0,0),(0,0,1),handAngle) 101 | .translate((4.33,0,0)) 102 | .moveTo(-20,0) 103 | .rect(40,caseHeight*2) 104 | .cutBlind(cutDir * overallHeight) 105 | ) 106 | return obj 107 | 108 | 109 | def _filletOuterEdges(self): 110 | # fillet outmost edges 111 | obj = ( 112 | self.edges("|Z") 113 | .edges(cqs.BoxSelector( (caseWidth/2, caseHeight, 0), (caseWidth, -caseHeight, overallHeight) )) 114 | .fillet(outerRad) 115 | ) 116 | return obj 117 | 118 | 119 | def _filletInnerEdges(self): 120 | # fillet inner edges 121 | obj = ( 122 | self.edges("|Z") 123 | .edges(cqs.BoxSelector( (2, caseHeight, 0), (caseWidth/2-20, -caseHeight, overallHeight) )) 124 | .fillet(outerRadSmall) 125 | ) 126 | return obj 127 | 128 | 129 | def _caseShape(self, height, filletOuter=True, filletInner=True): 130 | obj = ( 131 | self.placeSketch(so) 132 | .extrude(height) 133 | .rotateAndClean() 134 | ) 135 | if filletOuter: 136 | obj = obj.filletOuterEdges() 137 | 138 | if filletInner: 139 | # fillet inner edges 140 | obj = obj.filletInnerEdges() 141 | return obj 142 | 143 | cq.Workplane.filletOuterEdges = _filletOuterEdges # selects the ">X" edges and fillets them 144 | cq.Workplane.filletInnerEdges = _filletInnerEdges # selects all edges except ">X" and X<0 and fillets them 145 | cq.Workplane.rotateAndClean = _rotateAndClean # rotates and translates the object by hand spacing and angle 146 | cq.Workplane.caseShape = _caseShape # creates the base Case outline with given height and optional inner and outer fillet 147 | 148 | ## ------------------------------------------------------------------------------ 149 | 150 | # SKETCH FOR OUTLINE WITHOUT FILLETS 151 | so = ( 152 | cq.Sketch() 153 | # create outline shape for all keys w/ min. wall widht 154 | .push(getAlphaKeyPos()) 155 | .rect(spacing+2*lWallWidth, spacing+2*lWallWidth) 156 | .reset() 157 | .push(getThumbKeyPos()) 158 | .rect(spacing*1.5+2*lWallWidth,spacing+2*lWallWidth) 159 | .reset() 160 | # add rectangular outline to key shape 161 | .push([(caseWidth/4-7+5,-8)]) 162 | .rect(caseWidth/2+10, 2*spacing+2*wallWidth+2.5+10, angle=-handAngle) 163 | # readd middle cutout 164 | .push([(-21.2,5)]) 165 | .rect(40-lWallWidth, 46.9, mode='s') 166 | .clean() 167 | ) 168 | 169 | 170 | # SKETCH FOR SWITCH CUTOUTS IN TOP PART 171 | si = ( 172 | cq.Sketch() 173 | # create shape for all keys w/ keysafety added 174 | .push(getAlphaKeyPos()) 175 | .rect(spacing+keySafety, spacing+keySafety) 176 | .reset() 177 | .push(getThumbKeyPos()) 178 | .rect(spacing*1.5+keySafety, spacing+keySafety) 179 | .clean() 180 | # fillet all edges except the leftmost, which will later be on the mirror plane 181 | .reset() 182 | .vertices(cqs.BoxSelector( (2, caseHeight/2, 10), (caseWidth/2+2, -caseHeight/2, -10) )) 183 | .fillet(1) 184 | .reset() 185 | .vertices(cqs.BoxSelector( (-2, 0, -1), (2, -caseHeight, 1) )) 186 | .fillet(1) 187 | ) 188 | 189 | # SKETCH FOR INNER USB CUTOUT 190 | su = (cq.Sketch() 191 | .rect(10,5) 192 | .reset() 193 | .vertices() 194 | .fillet(1.5) 195 | ) 196 | # SKETCH FOR OUTER USB CUTOUT 197 | suo = (cq.Sketch() 198 | .rect(13,7) 199 | .reset() 200 | .vertices() 201 | .fillet(2.5) 202 | ) 203 | 204 | # SKETCH FOR OUTER USB CUTOUT w/ STRAIGHT BOTTOM 205 | suo_down = (cq.Sketch() 206 | .push([(0,-1.5)]) 207 | .rect(12.5,10.5) 208 | .reset() 209 | .vertices(">Y") 210 | .fillet(2.5) 211 | ) 212 | 213 | ## ------------------------------------------------------------------------------ 214 | 215 | # BOTTOM 216 | bottom = ( 217 | cq.Workplane("XY") 218 | .caseShape(heightBelowPlate, filletInner=False) 219 | # hollow out bottom, so only the rim remains 220 | .faces(cqs.SumSelector(cqs.StringSyntaxSelector("Z or Z").workplane().transformed(offset=(4.33,0,-1.5),rotate=(0,0,handAngle)) 232 | .pushPoints(getAllKeyPos()) 233 | .rect(5,holeSize+2) 234 | .cutBlind(-plateHeight) 235 | # add switch cutouts 236 | .faces(">Z").workplane().transformed(rotate=(0,0,handAngle)) 237 | .pushPoints(getAllKeyPos()) 238 | .rect(holeSize,holeSize) 239 | .cutBlind(-overallHeight) 240 | ) 241 | 242 | # TOP 243 | top = ( 244 | cq.Workplane("XY", origin=(0,0,heightBelowPlate+plateHeight)) 245 | .caseShape(heightAbovePlate) 246 | .faces(">Z").workplane().transformed(offset=(4.33,0,0),rotate=(0,0,handAngle)) 247 | # remove keycutout 248 | .placeSketch(si) 249 | .cutBlind(-heightAbovePlate) 250 | # lower middle cutout 251 | .faces(">Z") 252 | .faces(cqs.NearestToPointSelector((0,-20, overallHeight))).wires().toPending() 253 | .cutBlind(-centerInset) 254 | ) 255 | 256 | # MERGE ALL PARTS 257 | half = ( 258 | bottom.union(plate.union(top)) 259 | ) 260 | 261 | # CREATE FULL CASE 262 | full = ( 263 | half.mirror("YZ",union=True) 264 | # fillet on X=0 265 | .edges("|Z") 266 | .edges(cqs.BoxSelector( (-1, caseHeight, heightBelowPlate+plateHeight+1), (1, -caseHeight*2, overallHeight) )) 267 | .fillet(1) 268 | # add top groove 269 | .faces(cqs.NearestToPointSelector((0,-10, overallHeight))).wires().translate((0,42+0.1*lWallWidth, centerInset)).item(1).rotateAboutCenter((0,0,1), 180).toPending() 270 | .cutBlind(-2) 271 | # round bottom near thumbs 272 | .edges("|Z") 273 | .edges(cqs.NearestToPointSelector((0,-20,0))) 274 | .fillet(2) 275 | # round groove 276 | .edges("|Z") 277 | .edges(cqs.NearestToPointSelector((0,15,overallHeight))) 278 | .fillet(0.5) 279 | .faces("|Y") 280 | .edges(cqs.BoxSelector( (-20, 10, overallHeight-centerInset), (20, 120, overallHeight) )) 281 | .fillet(outerRadSmall) 282 | # add chamfer to outline 283 | .faces(">Z") 284 | .faces(cqs.NearestToPointSelector((0,caseHeight/2, overallHeight))) 285 | .wires().item(0) 286 | .chamfer(1) 287 | # add chamfer to keycutout 288 | .faces(">Z") 289 | .faces(cqs.NearestToPointSelector((0,caseHeight/2, overallHeight))) 290 | .wires().item(1) 291 | .chamfer(0.5) 292 | # add chamfer to middle cutout 293 | .faces("|Z") 294 | .faces(cqs.NearestToPointSelector((0,-10, overallHeight-centerInset))) 295 | .wires().item(0) 296 | .chamfer(0.5) 297 | .faces(cqs.NearestToPointSelector((0,-10, overallHeight-centerInset))) 298 | .wires().item(1) 299 | .chamfer(0.5 ) 300 | # add chamfer to bottom rim 301 | .faces(" 0): 67 | points.append(( 4.5 * spacing_x, topSwitchY - 3.5 * colStagger ) ) 68 | # points.append(( 4.5 * spacing, topSwitchY - 4 * colStagger ) ) 69 | 70 | if (rowOffset < 2): 71 | points.append(( 0.5 * spacing_x, topSwitchY - 4 * colStagger )) 72 | return points 73 | 74 | def getSwitchPositions(keys=True): 75 | """ collects all positions for the first three rows 76 | 77 | :param keys: if true returns alphakey positions, if false returns thumbkeyposition 78 | :return list of coordinate tuples 79 | """ 80 | if keys: 81 | return getRowPos(0) + getRowPos(1) + getRowPos(2) 82 | else: 83 | return [( 0.25 * spacing_x, caseHeight/2-wallWidth-spacing_y/2-2*spacing_y - 4 * colStagger )] 84 | 85 | def getAlphaKeyPos(): 86 | return getSwitchPositions(True) 87 | 88 | def getThumbKeyPos(): 89 | return getSwitchPositions(False) 90 | 91 | def getAllKeyPos(): 92 | return getAlphaKeyPos() + getThumbKeyPos() 93 | 94 | def getAllKeyPosMir(): 95 | switchPos = list(map(lambda pnt: (-1*pnt[0], pnt[1]), getAlphaKeyPos() + getThumbKeyPos())) 96 | return switchPos 97 | 98 | def getInnerEdges(object): 99 | obj = ( object.edges() 100 | .filter_by(Axis.Z) 101 | .filter_by( 102 | lambda v: v.center().X > 2 and v.center().X < (caseWidth/2-20)) 103 | ) 104 | return obj; 105 | 106 | # %% 107 | ## ------------------------------------------------------------------------------ 108 | 109 | with BuildSketch() as SketchOutline: 110 | # outline shapes for alpha and thumbs 111 | with Locations(getAlphaKeyPos()): 112 | Rectangle(spacing_x+2*lWallWidth, spacing_y+2*lWallWidth) 113 | with Locations(getThumbKeyPos()): 114 | Rectangle(spacing_x*1.5+2*lWallWidth, spacing_y+2*lWallWidth) 115 | with Locations((caseWidth/4-7+5,-8)): 116 | Rectangle(caseWidth/2+10, 2*spacing_y+2*wallWidth+2.5+10, rotation=-handAngle) 117 | with Locations((-21.5,7.3)): 118 | Rectangle(40-lWallWidth, 46.9, mode=Mode.SUBTRACT) 119 | 120 | with BuildSketch() as CaseOutline: 121 | with Locations((part_x_offset,0,0)): 122 | add(SketchOutline.sketch, rotation=handAngle) 123 | with Locations((-20,0)): 124 | Rectangle(40,caseHeight*2, mode=Mode.SUBTRACT) 125 | 126 | with BuildSketch() as CaseOutlineFilletOuter: 127 | add(CaseOutline.sketch) 128 | fillet(CaseOutlineFilletOuter.edges().sort_by(Axis.X)[-1].vertices(), outerRad) 129 | 130 | with BuildSketch() as KeyCutout: 131 | with Locations(getAlphaKeyPos()): 132 | Rectangle(spacing_x+keySafety, spacing_y+keySafety) 133 | with Locations(getThumbKeyPos()): 134 | Rectangle(1.5*spacing_x+keySafety, spacing_y+keySafety) 135 | fillet(KeyCutout.vertices().sort_by(Axis.X)[4:], 1) 136 | fillet(KeyCutout.vertices().group_by(Axis.X)[0].sort_by(Axis.Y)[0], 1) 137 | fillet(KeyCutout.vertices().group_by(Axis.X)[2].sort_by(Axis.Y)[0], 1) 138 | 139 | with BuildSketch() as USBCutoutInner: 140 | Rectangle(11.5,6.5+usbStraightExtra) 141 | fillet(USBCutoutInner.vertices(), 1.5) 142 | 143 | with BuildSketch() as USBCutoutOuter: 144 | with Locations((0,-1.5)): 145 | Rectangle(12.5,10.5) 146 | fillet(USBCutoutOuter.vertices().group_by(Axis.Y)[-1], 2) 147 | 148 | with BuildSketch() as BottomKeyCutout: 149 | with Locations([(-5.5,0), (5.5,0)]): 150 | Circle(1.25) 151 | with Locations((0,0)): 152 | Circle(2) 153 | with Locations([(1.3-0.5, -5-0.5,9+1)]): 154 | Rectangle(8.6,6.5) 155 | with Locations([(-5-1.3+0.5,-3.7)]): 156 | Rectangle(8.6,5.5) 157 | with Locations((-5-1.3+1.25+2/2,-2)): 158 | Rectangle(7.6+2.5+2,4) 159 | 160 | with BuildSketch(Plane.XY.rotated((0,0,180))) as BottomKeyCutoutRot: 161 | add(BottomKeyCutout) 162 | # %% 163 | ## ------------------------------------------------------------------------------ 164 | 165 | bottomPlateWire = 0 166 | 167 | with BuildPart() as CaseHalf: 168 | 169 | # Build Case Bottom below Plate 170 | with BuildPart() as Bottom: 171 | add(CaseOutlineFilletOuter.sketch) 172 | extrude(amount=heightBelowPlate) 173 | # select faces that should not be offset = open faces 174 | remFaces = Bottom.faces().sort_by(Axis.Z)[0] 175 | remFaces += Bottom.faces().sort_by(Axis.Z)[-1] 176 | remFaces += Bottom.faces().sort_by(Axis.X)[:5].sort_by(Axis.Y)[-4:] 177 | # create shell 178 | offset(amount=-lWallWidth, openings=remFaces, kind=Kind.INTERSECTION) 179 | fillet(getInnerEdges(Bottom), outerRadSmall) 180 | 181 | # Build Plate part 182 | with BuildPart(Plane(origin=(0,0,heightBelowPlate))) as Plate: 183 | add(CaseOutlineFilletOuter.sketch) 184 | extrude(amount=plateHeight) 185 | fillet(getInnerEdges(Plate), outerRadSmall) 186 | # work plane for further operations 187 | wPlane = Plane(origin=(part_x_offset,0,heightBelowPlate)).rotated((0,0,handAngle)) 188 | # add cutouts for switch clips 189 | with BuildSketch(wPlane) : 190 | with Locations(getAllKeyPos()): 191 | RectangleRounded(holeSize+2,holeSize, holeFillet) 192 | extrude(amount=plateHeight-plateClipHeight, mode=Mode.SUBTRACT) 193 | # add switch cutout 194 | with BuildSketch(wPlane) : 195 | with Locations(getAllKeyPos()): 196 | RectangleRounded(holeSize,holeSize,holeFillet) 197 | extrude(amount=plateHeight, mode=Mode.SUBTRACT) 198 | 199 | # Build Top part 200 | with BuildPart(Plane(origin=(0,0,heightBelowPlate+plateHeight))) as Top: 201 | add(CaseOutlineFilletOuter.sketch) 202 | extrude(amount=heightAbovePlate) 203 | fillet(getInnerEdges(Top), outerRadSmall) 204 | # work plane for further operations 205 | wPlane = Plane(origin=(part_x_offset,0,heightBelowPlate+plateHeight)).rotated((0,0,handAngle)) 206 | # add keycap cutout 207 | with BuildSketch(wPlane) : 208 | add(KeyCutout.sketch) 209 | extrude(amount=heightAbovePlate, mode=Mode.SUBTRACT) 210 | # lower center cutout 211 | extrude(Top.faces().filter_by(Axis.Z).group_by(Axis.Z)[-1].sort_by(Axis.X)[0], 212 | amount=-centerInset, mode=Mode.SUBTRACT) 213 | #show_object(Bottom) 214 | #show_object(Plate) 215 | #show_object(Top) 216 | # %% 217 | 218 | with BuildPart() as CaseFull: 219 | add(CaseHalf.part) 220 | mirror(CaseHalf.part, about=Plane.YZ) 221 | 222 | # add fillets on mirrored edges 223 | fillet(CaseFull.edges() 224 | .filter_by(Axis.Z) 225 | .filter_by( 226 | lambda v: (v.center().X < 0.05 and v.center().X > -0.05) and 227 | ((v.center().Y < 0 and v.center().Y > -19) or v.center().Y > 7)), 1) 228 | 229 | # add fillets on mirrored edges 230 | fillet(CaseFull.edges() 231 | .filter_by(Axis.Z) 232 | .group_by(Axis.Z)[-1] 233 | .filter_by( 234 | lambda v: (v.center().X < 0.05 and v.center().X > -0.05) and 235 | ((v.center().Y < -19 and v.center().Y > -25) or v.center().Y > 7)), 1) 236 | 237 | # add fillets on mirrored edges 238 | fillet(CaseFull.edges() 239 | .filter_by(Axis.Z) 240 | .group_by(Axis.Z)[0] 241 | .filter_by( 242 | lambda v: (v.center().X < 0.05 and v.center().X > -0.05) and 243 | ((v.center().Y < -19 and v.center().Y > -25) or v.center().Y > 7)), 2) 244 | 245 | # add top groove 246 | groove_wire = CaseFull.faces().filter_by(Axis.Z).group_by(Axis.Z)[-2][0].outer_wire() #wires().sort_by(SortBy.LENGTH)[-1] 247 | groove_wire = groove_wire.rotate(Axis.Z, 180).translate((0,33,centerInset)) 248 | extrude(Face(groove_wire), amount=-2, mode=Mode.SUBTRACT) 249 | 250 | # fillet top groove edges 251 | #groove_fil_edges = mainCase.edges(Select.LAST).group_by(Axis.Y)[-1].sort_by(Axis.X)[1:-1] 252 | groove_fil_edges = CaseFull.edges(Select.LAST).group_by(Axis.Y)[-1].filter_by(Axis.Z) 253 | fillet(groove_fil_edges, outerRadSmall) 254 | 255 | 256 | # outline Chamfer 257 | main_top_face = CaseFull.faces().filter_by(Axis.Z).group_by(Axis.Z)[-1].sort_by(Axis.X)[0] 258 | #chamfer(main_top_face.outer_wire().edges(), 1) 259 | #chamfer(main_top_face.inner_wires().edges(), 0.5) 260 | 261 | inset_face = CaseFull.faces().filter_by(Axis.Z).group_by(Axis.Z)[-2].sort_by(Axis.Y)[0] 262 | chamfer(inset_face.edges(), 0.5) 263 | 264 | # lower bottom ridge, added back with bottom part 265 | extrude(CaseFull.faces().sort_by(Axis.Z)[0], amount=-bottom_part_thickness, mode=Mode.SUBTRACT) 266 | 267 | #chamfer(bottom_face.outer_wire().edges(), 0.7) 268 | 269 | bottomPlateWire = CaseFull.faces().sort_by(Axis.Z)[0].inner_wires(); 270 | 271 | 272 | # usb cutout 273 | usb_face = CaseFull.faces().filter_by(Axis.Y).group_by(Axis.Y)[-1].sort_by(SortBy.LENGTH)[-1] 274 | usb_plane = Plane(usb_face).shift_origin((usb_face.center().X,usb_face.center().Y,heightBelowPlate)) 275 | with BuildSketch(usb_plane.shift_origin((usb_face.center().X,usb_face.center().Y,heightBelowPlate-usbStraightExtra/2-0.4))): 276 | add(USBCutoutInner.sketch) 277 | extrude(amount=-11, mode=Mode.SUBTRACT) 278 | 279 | with BuildSketch(usb_plane.shift_origin((usb_face.center().X,usb_face.center().Y,heightBelowPlate-usbStraightExtra/2+1.1))): 280 | add(USBCutoutOuter.sketch, rotation=180) 281 | extrude(amount=-1, mode=Mode.SUBTRACT) 282 | 283 | inner_usb_edges = CaseFull.faces(Select.LAST).filter_by(Axis.Y).sort_by(Axis.Y)[0].inner_wires().edges() 284 | outer_usb_edges = CaseFull.edges(Select.LAST).group_by(Axis.Y)[-1].sort_by(Axis.X)[1:-1] 285 | 286 | #chamfer(inner_usb_edges, 0.75) 287 | chamfer(outer_usb_edges, 0.75) 288 | show(CaseFull) 289 | 290 | # %% 291 | 292 | with BuildPart() as BottomPlate: 293 | extrude(CaseFull.faces().sort_by(Axis.Z)[0], amount=bottom_part_thickness) 294 | with BuildSketch(): 295 | make_face(bottomPlateWire[0]) 296 | extrude(amount=bottom_part_thickness) 297 | with BuildSketch(): 298 | make_face(bottomPlateWire[0].offset_2d(-0.5)) 299 | extrude(amount=hsThickness) 300 | 301 | middle_hole = inset_face.outer_wire().offset_2d(-1.5) 302 | 303 | with BuildSketch(): 304 | make_face(middle_hole) 305 | extrude(amount=5, mode=Mode.SUBTRACT) 306 | 307 | wPlane = Plane(origin=(part_x_offset,0,0)).rotated((0,0,handAngle)) 308 | 309 | #BottomPlate.part.export_step('grumpy_lp_choc_bottom_woHoles.step') 310 | 311 | with BuildSketch(wPlane) : 312 | with Locations(getAlphaKeyPos()): 313 | add(BottomKeyCutout.sketch) 314 | extrude(amount=max(bottom_part_thickness, hsThickness), mode=Mode.SUBTRACT) 315 | 316 | with BuildSketch(wPlane) : 317 | with Locations(getThumbKeyPos()): 318 | add(BottomKeyCutoutRot.sketch) 319 | extrude(amount=max(bottom_part_thickness, hsThickness), mode=Mode.SUBTRACT) 320 | 321 | wPlane = Plane(origin=(-part_x_offset,0,0)).rotated((0,0,-handAngle)) 322 | 323 | with BuildSketch(wPlane) : 324 | with Locations(getAllKeyPosMir()[:-1]): 325 | add(BottomKeyCutout.sketch) 326 | extrude(amount=max(bottom_part_thickness, hsThickness), mode=Mode.SUBTRACT) 327 | 328 | with BuildSketch(wPlane) : 329 | with Locations(getAllKeyPosMir()[-1]): 330 | add(BottomKeyCutoutRot.sketch) 331 | extrude(amount=max(bottom_part_thickness, hsThickness), mode=Mode.SUBTRACT) 332 | 333 | show (BottomPlate) 334 | BottomPlate.part.export_step('grumpy_lp_choc_bottom.step') 335 | 336 | # %% 337 | 338 | show(CaseFull) 339 | #show(BottomPlate ) 340 | #FullCase.part.export_stl('grumpy_lp_choc.stl') 341 | #FullCase.part.export_step('grumpy_lp_choc.step') 342 | BottomPlate.part.export_step('grumpy_lp_choc_bottom.step') 343 | #BottomPlate.part.export_stl('grumpy_lp_choc_bottom.stl') 344 | -------------------------------------------------------------------------------- /case/grumpy_case_lp.py: -------------------------------------------------------------------------------- 1 | from build123d import * 2 | from ocp_vscode import * 3 | set_port(3939) 4 | set_defaults(reset_camera=Camera.CENTER) 5 | 6 | # CONSTANTS 7 | spacing = 19.05 # MX-Spacing 8 | holeSize = 13.9 # Platehole size 9 | pcbThickness = 1.6 # PCB Thickness 10 | hsThickness = 3.3-pcbThickness # HS Socket Thickness below PCB 11 | hsSafety = 0.3 # extra space to hide HS Sockets 12 | 13 | # CASE PARAMETERS 14 | keySafety = 0.5 # extra space between keycap and case 15 | spaceAbovePCB = 0.1 # space between PCB and Plate. 16 | plateHeight = 2.2 - spaceAbovePCB # heigth of plate 17 | plateClipHeight = 1.2 # switch clipping (1.2 for choc, 1.5 for MX) 18 | colStagger = 0.25 * spacing # stagger between cols 19 | 20 | 21 | heightAbovePlate = 8.5-6.6+3.5 # height of case rim measured from plate 22 | heightBelowPlate = pcbThickness+hsThickness+hsSafety # height of rim hiding pcb and Sockets 23 | 24 | overallHeight = heightAbovePlate+heightBelowPlate+plateHeight 25 | 26 | outerRad = 5 # radius of outer edge fillets 27 | outerRadSmall = 1.5 # radius of other outline fillets 28 | 29 | wallWidth = 7.5 # Wall Width (in effect only left and right) 30 | lWallWidth = 3 # min Wallthickness for keys outside of case body 31 | 32 | rectOffset = 0.125*19.05-colStagger/2 # rectangular case body y offset 33 | rectHeight = 3*spacing+2*lWallWidth+colStagger # rectangular case y height 34 | 35 | 36 | caseWidth = 10 *spacing + 2*wallWidth # absolute case width 37 | caseHeight = 3*spacing + 2*wallWidth + 3*colStagger # absolute case height 38 | 39 | handAngle = 14 # degrees of rotation for each hand 40 | 41 | centerInset = 1 #how much lower the inner cutout should be 42 | 43 | usbStraightExtra = 3 # extra Y length of cutout, if the inner cutout should be straight 44 | 45 | def getRowPos(rowOffset=0): 46 | """ returns x y coordinate tuple for each right hand switch of the selected row 47 | 48 | :param rowOffset: row number counted from the top 49 | :return list of coordinate tuples 50 | """ 51 | 52 | topSwitchY = caseHeight/2-wallWidth-spacing/2-rowOffset*spacing 53 | 54 | 55 | points = [ 56 | ( 1.5 * spacing, topSwitchY - 2 * colStagger ), 57 | ( 2.5 * spacing, topSwitchY - 1 * colStagger ), 58 | ( 3.5 * spacing, topSwitchY - 2 * colStagger ), 59 | ] 60 | if (rowOffset > 0): 61 | points.append(( 4.5 * spacing, topSwitchY - 3.5 * colStagger ) ) 62 | # points.append(( 4.5 * spacing, topSwitchY - 4 * colStagger ) ) 63 | 64 | if (rowOffset < 2): 65 | points.append(( 0.5 * spacing, topSwitchY - 4 * colStagger )) 66 | 67 | 68 | 69 | return points 70 | 71 | def getSwitchPositions(keys=True): 72 | """ collects all positions for the first three rows 73 | 74 | :param keys: if true returns alphakey positions, if false returns thumbkeyposition 75 | :return list of coordinate tuples 76 | """ 77 | if keys: 78 | return getRowPos(0) + getRowPos(1) + getRowPos(2) 79 | else: 80 | return [( 0.25 * spacing, caseHeight/2-wallWidth-spacing/2-2*spacing - 4 * colStagger )] 81 | 82 | def getAlphaKeyPos(): 83 | return getSwitchPositions(True) 84 | 85 | def getThumbKeyPos(): 86 | return getSwitchPositions(False) 87 | 88 | def getAllKeyPos(): 89 | return getAlphaKeyPos() + getThumbKeyPos() 90 | 91 | def getInnerEdges(object): 92 | obj = ( object.edges() 93 | .filter_by(Axis.Z) 94 | .filter_by( 95 | lambda v: v.center().X > 2 and v.center().X < (caseWidth/2-20)) 96 | ) 97 | return obj; 98 | 99 | 100 | ## ------------------------------------------------------------------------------ 101 | 102 | with BuildSketch() as SketchOutline: 103 | # outline shapes for alpha and thumbs 104 | with Locations(getAlphaKeyPos()): 105 | Rectangle(spacing+2*lWallWidth, spacing+2*lWallWidth) 106 | with Locations(getThumbKeyPos()): 107 | Rectangle(spacing*1.5+2*lWallWidth, spacing+2*lWallWidth) 108 | with Locations((caseWidth/4-7+5,-8)): 109 | Rectangle(caseWidth/2+10, 2*spacing+2*wallWidth+2.5+10, rotation=-handAngle) 110 | with Locations((-21.2,5)): 111 | Rectangle(40-lWallWidth, 46.9, mode=Mode.SUBTRACT) 112 | 113 | with BuildSketch() as CaseOutline: 114 | with Locations((4.33,0,0)): 115 | add(SketchOutline.sketch, rotation=handAngle) 116 | with Locations((-20,0)): 117 | Rectangle(40,caseHeight*2, mode=Mode.SUBTRACT) 118 | 119 | with BuildSketch() as CaseOutlineFilletOuter: 120 | add(CaseOutline.sketch) 121 | fillet(CaseOutlineFilletOuter.edges().sort_by(Axis.X)[-1].vertices(), outerRad) 122 | 123 | with BuildSketch() as KeyCutout: 124 | with Locations(getAlphaKeyPos()): 125 | Rectangle(spacing+keySafety, spacing+keySafety) 126 | with Locations(getThumbKeyPos()): 127 | Rectangle(1.5*spacing+keySafety, spacing+keySafety) 128 | fillet(KeyCutout.vertices().sort_by(Axis.X)[4:], 1) 129 | fillet(KeyCutout.vertices().group_by(Axis.X)[0].sort_by(Axis.Y)[0], 1) 130 | fillet(KeyCutout.vertices().group_by(Axis.X)[2].sort_by(Axis.Y)[0], 1) 131 | 132 | with BuildSketch() as USBCutoutInner: 133 | Rectangle(11.5,6.5+usbStraightExtra) 134 | fillet(USBCutoutInner.vertices(), 1.5) 135 | 136 | with BuildSketch() as USBCutoutOuter: 137 | with Locations((0,-1.5)): 138 | Rectangle(12.5,10.5) 139 | fillet(USBCutoutOuter.vertices().group_by(Axis.Y)[-1], 1.5) 140 | ## ------------------------------------------------------------------------------ 141 | 142 | bottomPlateWire = 0 143 | 144 | with BuildPart() as FullCase: 145 | 146 | # Build Case Bottom below Plate 147 | with BuildPart() as Bottom: 148 | add(CaseOutlineFilletOuter.sketch) 149 | extrude(amount=heightBelowPlate) 150 | # select faces that should not be offset = open faces 151 | remFaces = Bottom.faces().sort_by(Axis.Z)[0] 152 | remFaces += Bottom.faces().sort_by(Axis.Z)[-1] 153 | remFaces += Bottom.faces().sort_by(Axis.X)[:5].sort_by(Axis.Y)[-4:] 154 | # create shell 155 | offset(amount=-lWallWidth, openings=remFaces, kind=Kind.INTERSECTION) 156 | fillet(getInnerEdges(Bottom), outerRadSmall) 157 | 158 | # Build Plate part 159 | with BuildPart(Plane(origin=(0,0,heightBelowPlate))) as Plate: 160 | add(CaseOutlineFilletOuter.sketch) 161 | extrude(amount=plateHeight) 162 | fillet(getInnerEdges(Plate), outerRadSmall) 163 | # work plane for further operations 164 | wPlane = Plane(origin=(4.33,0,heightBelowPlate)).rotated((0,0,handAngle)) 165 | # add cutouts for switch clips 166 | with BuildSketch(wPlane) : 167 | with Locations(getAllKeyPos()): 168 | Rectangle(holeSize+2,holeSize) 169 | extrude(amount=plateHeight-plateClipHeight, mode=Mode.SUBTRACT) 170 | # add switch cutout 171 | with BuildSketch(wPlane) : 172 | with Locations(getAllKeyPos()): 173 | Rectangle(holeSize,holeSize) 174 | extrude(amount=plateHeight, mode=Mode.SUBTRACT) 175 | 176 | # Build Top part 177 | with BuildPart(Plane(origin=(0,0,heightBelowPlate+plateHeight))) as Top: 178 | add(CaseOutlineFilletOuter.sketch) 179 | extrude(amount=heightAbovePlate) 180 | fillet(getInnerEdges(Top), outerRadSmall) 181 | # work plane for further operations 182 | wPlane = Plane(origin=(4.33,0,heightBelowPlate+plateHeight)).rotated((0,0,handAngle)) 183 | # add keycap cutout 184 | with BuildSketch(wPlane) : 185 | add(KeyCutout.sketch) 186 | extrude(amount=heightAbovePlate, mode=Mode.SUBTRACT) 187 | # lower center cutout 188 | extrude(Top.faces().filter_by(Axis.Z).group_by(Axis.Z)[-1].sort_by(Axis.X)[0], 189 | amount=-centerInset, mode=Mode.SUBTRACT) 190 | #show_object(Bottom) 191 | #show_object(Plate) 192 | #show_object(Top) 193 | 194 | mirror(FullCase.part, about=Plane.YZ) 195 | 196 | # add fillets on mirrored edges 197 | fillet(FullCase.edges() 198 | .filter_by(Axis.Z) 199 | .filter_by( 200 | lambda v: (v.center().X < 0.05 and v.center().X > -0.05) and 201 | ((v.center().Y < 0 and v.center().Y > -21) or v.center().Y > 7)), 1) 202 | 203 | # add fillets on mirrored edges 204 | fillet(FullCase.edges() 205 | .filter_by(Axis.Z) 206 | .group_by(Axis.Z)[-1] 207 | .filter_by( 208 | lambda v: (v.center().X < 0.05 and v.center().X > -0.05) and 209 | ((v.center().Y < -21 and v.center().Y > -25) or v.center().Y > 7)), 1) 210 | 211 | # add fillets on mirrored edges 212 | fillet(FullCase.edges() 213 | .filter_by(Axis.Z) 214 | .group_by(Axis.Z)[0] 215 | .filter_by( 216 | lambda v: (v.center().X < 0.05 and v.center().X > -0.05) and 217 | ((v.center().Y < -21 and v.center().Y > -25) or v.center().Y > 7)), 2) 218 | # add top groove 219 | groove_wire = FullCase.faces().filter_by(Axis.Z).group_by(Axis.Z)[-2][0].outer_wire() #wires().sort_by(SortBy.LENGTH)[-1] 220 | groove_wire = groove_wire.rotate(Axis.Z, 180).translate((0,33,centerInset)) 221 | extrude(Face(groove_wire), amount=-2, mode=Mode.SUBTRACT) 222 | 223 | # fillet top groove edges 224 | groove_fil_edges = FullCase.edges(Select.LAST).group_by(Axis.Y)[-1].sort_by(Axis.X)[1:-1] 225 | fillet(groove_fil_edges, outerRadSmall) 226 | 227 | # outline Chamfer 228 | main_top_face = FullCase.faces().filter_by(Axis.Z).group_by(Axis.Z)[-1].sort_by(Axis.X)[0] 229 | #chamfer(main_top_face.outer_wire().edges(), 1) 230 | #chamfer(main_top_face.inner_wires().edges(), 0.5) 231 | 232 | inset_face = FullCase.faces().filter_by(Axis.Z).group_by(Axis.Z)[-2].sort_by(Axis.Y)[0] 233 | chamfer(inset_face.edges(), 0.5) 234 | 235 | bottom_face = FullCase.faces().filter_by(Axis.Z).group_by(Axis.Z)[0][0] 236 | chamfer(bottom_face.outer_wire().edges(), 0.7) 237 | 238 | bottomPlateWire = FullCase.faces().sort_by(Axis.Z)[0].inner_wires(); 239 | 240 | # usb cutout 241 | usb_face = FullCase.faces().filter_by(Axis.Y).group_by(Axis.Y)[-1].sort_by(SortBy.LENGTH)[-1] 242 | usb_plane = Plane(usb_face).shift_origin((usb_face.center().X,usb_face.center().Y,heightBelowPlate)) 243 | with BuildSketch(usb_plane.shift_origin((usb_face.center().X,usb_face.center().Y,heightBelowPlate-usbStraightExtra/2))): 244 | add(USBCutoutInner.sketch) 245 | extrude(amount=-11, mode=Mode.SUBTRACT) 246 | 247 | with BuildSketch(usb_plane): 248 | add(USBCutoutOuter.sketch, rotation=180) 249 | extrude(amount=-1, mode=Mode.SUBTRACT) 250 | 251 | inner_usb_edges = FullCase.faces(Select.LAST).filter_by(Axis.Y).sort_by(Axis.Y)[0].inner_wires().edges() 252 | outer_usb_edges = FullCase.edges(Select.LAST).group_by(Axis.Y)[-1].sort_by(Axis.X)[1:-1] 253 | 254 | #chamfer(inner_usb_edges, 0.75) 255 | chamfer(outer_usb_edges, 0.75) 256 | 257 | with BuildPart() as BottomPlate: 258 | with BuildSketch() as bpsk: 259 | with BuildLine(): 260 | add(bottomPlateWire) 261 | make_face() 262 | offset(amount=-0.2) 263 | 264 | extrude(amount=hsThickness) 265 | 266 | show(FullCase ) 267 | #show(BottomPlate ) 268 | #FullCase.part.export_stl('grumpy_lp.stl') 269 | FullCase.part.export_step('grumpy_lp.step') 270 | BottomPlate.part.export_step('grumpy_lp_bottom.step') 271 | -------------------------------------------------------------------------------- /case/grumpy_lp.FCStd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/case/grumpy_lp.FCStd -------------------------------------------------------------------------------- /case/grumpy_lp_choc.FCStd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/case/grumpy_lp_choc.FCStd -------------------------------------------------------------------------------- /firmware/QMK/grumpy/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 weteor 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | //#include "config_common.h" 21 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy/halconf.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 weteor 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #define HAL_USE_I2C TRUE 21 | 22 | #include_next 23 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "keyboard_name": "grumpy", 3 | "manufacturer": "weteor", 4 | "url": "https://github.com/weteor/grumpy/", 5 | "maintainer": "weteor", 6 | "processor": "RP2040", 7 | "bootloader": "rp2040", 8 | "diode_direction": "COL2ROW", 9 | "rp2040_bootloader_double_tap_reset": true, 10 | "rp2040_bootloader_double_tap_reset_timeout": true, 11 | "matrix_pins" : { 12 | "cols": [ "GP26", "GP27", "GP28", "GP29", "GP6"], 13 | "rows": [ "GP7", "GP0", "GP1", "GP2", "GP4", "GP3" ] 14 | }, 15 | "matrix_size": { 16 | "cols": 5, 17 | "rows": 6 18 | }, 19 | "usb": { 20 | "vid": "0xFEED", 21 | "pid": "0x4657", 22 | "device_version": "0.2.0" 23 | }, 24 | "build": { 25 | "lto": false, 26 | }, 27 | "features": { 28 | "bootmagic": true, 29 | "extrakey": true, 30 | "command": false, 31 | "console": false, 32 | "mousekey": false, 33 | "nkro": true, 34 | }, 35 | "layouts": { 36 | "LAYOUT_28": { 37 | "layout": [ 38 | { "label": "01", "matrix": [0,0], "x": 1, "y": 0.25 }, 39 | { "label": "02", "matrix": [0,1], "x": 2, "y": 0 }, 40 | { "label": "03", "matrix": [0,2], "x": 3, "y": 0.25 }, 41 | { "label": "04", "matrix": [0,3], "x": 4, "y": 0.75 }, 42 | { "label": "34", "matrix": [0,4], "x": 6, "y": 0.75 }, 43 | { "label": "33", "matrix": [1,0], "x": 7, "y": 0.25 }, 44 | { "label": "32", "matrix": [1,1], "x": 8, "y": 0 }, 45 | { "label": "31", "matrix": [1,2], "x": 9, "y": 0.25 }, 46 | { "label": "10", "matrix": [1,3], "x": 0, "y": 1.625 }, 47 | { "label": "11", "matrix": [1,4], "x": 1, "y": 1.25 }, 48 | { "label": "12", "matrix": [2,0], "x": 2, "y": 1 }, 49 | { "label": "13", "matrix": [2,1], "x": 3, "y": 1.25 }, 50 | { "label": "14", "matrix": [2,2], "x": 4, "y": 1.75 }, 51 | { "label": "44", "matrix": [2,3], "x": 6, "y": 1.75 }, 52 | { "label": "43", "matrix": [2,4], "x": 7, "y": 1.25 }, 53 | { "label": "42", "matrix": [3,0], "x": 8, "y": 1 }, 54 | { "label": "41", "matrix": [3,1], "x": 9, "y": 1.25 }, 55 | { "label": "40", "matrix": [3,2], "x": 10, "y": 1.625 }, 56 | { "label": "20", "matrix": [3,3], "x": 0, "y": 2.625 }, 57 | { "label": "21", "matrix": [3,4], "x": 1, "y": 2.25 }, 58 | { "label": "22", "matrix": [4,0], "x": 2, "y": 2 }, 59 | { "label": "23", "matrix": [4,1], "x": 3, "y": 2.25 }, 60 | { "label": "24", "matrix": [4,2], "x": 4, "y": 2.75, "w": 1.5 }, 61 | { "label": "54", "matrix": [4,3], "x": 5.5, "y": 2.75, "w": 1.5 }, 62 | { "label": "53", "matrix": [4,4], "x": 7, "y": 2.25 }, 63 | { "label": "52", "matrix": [5,0], "x": 8, "y": 2 }, 64 | { "label": "51", "matrix": [5,1], "x": 9, "y": 2.25 }, 65 | { "label": "50", "matrix": [5,2], "x": 10, "y": 2.625 } 66 | ] 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy/keymaps/default/keymap.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2021 weteor 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #include QMK_KEYBOARD_H 18 | 19 | enum layers 20 | { 21 | _ALPHA_QWERTY = 0, 22 | }; 23 | 24 | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { 25 | 26 | 27 | [_ALPHA_QWERTY] = LAYOUT_grumpy( 28 | KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, 29 | KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, 30 | KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH 31 | ) 32 | }; 33 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy/keymaps/vial/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 weteor 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #define VIAL_KEYBOARD_UID {0xD8, 0xE1, 0xE5, 0x27, 0x39, 0x36, 0x89, 0x45} 21 | 22 | #define VIAL_KEY_OVERRIDE_ENTRIES 20 23 | #define VIAL_COMBO_ENTRIES 20 24 | #define VIAL_TAP_DANCE_ENTRIES 20 25 | #define DYNAMIC_KEYMAP_LAYER_COUNT 6 26 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy/keymaps/vial/keymap.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2021 weteor 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #include QMK_KEYBOARD_H 18 | 19 | enum layers 20 | { 21 | _ALPHA_QWERTY = 0, 22 | }; 23 | 24 | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { 25 | 26 | 27 | [_ALPHA_QWERTY] = LAYOUT_28( 28 | KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, 29 | KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, 30 | KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH 31 | ) 32 | }; 33 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy/keymaps/vial/rules.mk: -------------------------------------------------------------------------------- 1 | VIA_ENABLE = yes 2 | VIAL_ENABLE = yes 3 | VIAL_INSECURE = yes 4 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy/keymaps/vial/vial.json: -------------------------------------------------------------------------------- 1 | { 2 | "lighting": "none", 3 | "matrix": { 4 | "rows": 6, 5 | "cols": 5 6 | }, 7 | "layouts": { 8 | "keymap":[ 9 | [ 10 | { 11 | "r": 14, 12 | "x": 3 13 | }, 14 | "0,2" 15 | ], 16 | [ 17 | { 18 | "y": -0.75, 19 | "x": 2 20 | }, 21 | "0,1", 22 | { 23 | "x": 1 24 | }, 25 | "0,3" 26 | ], 27 | [ 28 | { 29 | "y": -0.5, 30 | "x": 5 31 | }, 32 | "0,4" 33 | ], 34 | [ 35 | { 36 | "y": -0.75, 37 | "x": 3 38 | }, 39 | "1,2" 40 | ], 41 | [ 42 | { 43 | "y": -0.75, 44 | "x": 2 45 | }, 46 | "1,1", 47 | { 48 | "x": 1 49 | }, 50 | "1,3" 51 | ], 52 | [ 53 | { 54 | "y": -0.625, 55 | "x": 1 56 | }, 57 | "1,0" 58 | ], 59 | [ 60 | { 61 | "y": -0.875, 62 | "x": 5 63 | }, 64 | "1,4" 65 | ], 66 | [ 67 | { 68 | "y": -0.75, 69 | "x": 3 70 | }, 71 | "2,2" 72 | ], 73 | [ 74 | { 75 | "y": -0.75, 76 | "x": 2 77 | }, 78 | "2,1", 79 | { 80 | "x": 1 81 | }, 82 | "2,3" 83 | ], 84 | [ 85 | { 86 | "y": -0.625, 87 | "x": 1 88 | }, 89 | "2,0" 90 | ], 91 | [ 92 | { 93 | "y": -0.875, 94 | "x": 5, 95 | "w": 1.5 96 | }, 97 | "2,4" 98 | ], 99 | [ 100 | { 101 | "r": -14, 102 | "y": -1, 103 | "x": 7 104 | }, 105 | "3,2" 106 | ], 107 | [ 108 | { 109 | "y": -0.75, 110 | "x": 6 111 | }, 112 | "3,3", 113 | { 114 | "x": 1 115 | }, 116 | "3,1" 117 | ], 118 | [ 119 | { 120 | "y": -0.5, 121 | "x": 5 122 | }, 123 | "3,4" 124 | ], 125 | [ 126 | { 127 | "y": -0.75, 128 | "x": 7 129 | }, 130 | "4,2" 131 | ], 132 | [ 133 | { 134 | "y": -0.75, 135 | "x": 6 136 | }, 137 | "4,3", 138 | { 139 | "x": 1 140 | }, 141 | "4,1" 142 | ], 143 | [ 144 | { 145 | "y": -0.625, 146 | "x": 9 147 | }, 148 | "4,0" 149 | ], 150 | [ 151 | { 152 | "y": -0.875, 153 | "x": 5 154 | }, 155 | "4,4" 156 | ], 157 | [ 158 | { 159 | "y": -0.75, 160 | "x": 7 161 | }, 162 | "5,2" 163 | ], 164 | [ 165 | { 166 | "y": -0.75, 167 | "x": 6 168 | }, 169 | "5,3", 170 | { 171 | "x": 1 172 | }, 173 | "5,1" 174 | ], 175 | [ 176 | { 177 | "y": -0.625, 178 | "x": 9 179 | }, 180 | "5,0" 181 | ], 182 | [ 183 | { 184 | "y": -0.875, 185 | "x": 4.5, 186 | "w": 1.5 187 | }, 188 | "5,4" 189 | ] 190 | ] 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy/mcuconf.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 weteor 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include_next 21 | 22 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy/rules.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/firmware/QMK/grumpy/rules.mk -------------------------------------------------------------------------------- /firmware/QMK/grumpy_MX_vial.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/firmware/QMK/grumpy_MX_vial.uf2 -------------------------------------------------------------------------------- /firmware/QMK/grumpy_chocV1/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 weteor 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | //#include "config_common.h" 21 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy_chocV1/halconf.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 weteor 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #define HAL_USE_I2C TRUE 21 | 22 | #include_next 23 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy_chocV1/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "keyboard_name": "grumpy_choc", 3 | "manufacturer": "weteor", 4 | "url": "https://github.com/weteor/grumpy/", 5 | "maintainer": "weteor", 6 | "processor": "RP2040", 7 | "bootloader": "rp2040", 8 | "diode_direction": "COL2ROW", 9 | "rp2040_bootloader_double_tap_reset": true, 10 | "rp2040_bootloader_double_tap_reset_timeout": true, 11 | "matrix_pins" : { 12 | "cols": [ "GP29", "GP6", "GP0", "GP7", "GP1"], 13 | "rows": [ "GP26", "GP27", "GP28", "GP3", "GP4", "GP2" ] 14 | }, 15 | "matrix_size": { 16 | "cols": 5, 17 | "rows": 6 18 | }, 19 | "usb": { 20 | "vid": "0xFEED", 21 | "pid": "0x4657", 22 | "device_version": "0.2.0" 23 | }, 24 | "build": { 25 | "lto": false, 26 | }, 27 | "features": { 28 | "bootmagic": true, 29 | "extrakey": true, 30 | "command": false, 31 | "console": false, 32 | "mousekey": false, 33 | "nkro": true, 34 | }, 35 | "layouts": { 36 | "LAYOUT_28": { 37 | "layout": [ 38 | { "label": "01", "matrix": [0,0], "x": 1, "y": 0.25 }, 39 | { "label": "02", "matrix": [0,1], "x": 2, "y": 0 }, 40 | { "label": "03", "matrix": [0,2], "x": 3, "y": 0.25 }, 41 | { "label": "04", "matrix": [0,3], "x": 4, "y": 0.75 }, 42 | { "label": "34", "matrix": [0,4], "x": 6, "y": 0.75 }, 43 | { "label": "33", "matrix": [1,0], "x": 7, "y": 0.25 }, 44 | { "label": "32", "matrix": [1,1], "x": 8, "y": 0 }, 45 | { "label": "31", "matrix": [1,2], "x": 9, "y": 0.25 }, 46 | { "label": "10", "matrix": [1,3], "x": 0, "y": 1.625 }, 47 | { "label": "11", "matrix": [1,4], "x": 1, "y": 1.25 }, 48 | { "label": "12", "matrix": [2,0], "x": 2, "y": 1 }, 49 | { "label": "13", "matrix": [2,1], "x": 3, "y": 1.25 }, 50 | { "label": "14", "matrix": [2,2], "x": 4, "y": 1.75 }, 51 | { "label": "44", "matrix": [2,3], "x": 6, "y": 1.75 }, 52 | { "label": "43", "matrix": [2,4], "x": 7, "y": 1.25 }, 53 | { "label": "42", "matrix": [3,0], "x": 8, "y": 1 }, 54 | { "label": "41", "matrix": [3,1], "x": 9, "y": 1.25 }, 55 | { "label": "40", "matrix": [3,2], "x": 10, "y": 1.625 }, 56 | { "label": "20", "matrix": [3,3], "x": 0, "y": 2.625 }, 57 | { "label": "21", "matrix": [3,4], "x": 1, "y": 2.25 }, 58 | { "label": "22", "matrix": [4,0], "x": 2, "y": 2 }, 59 | { "label": "23", "matrix": [4,1], "x": 3, "y": 2.25 }, 60 | { "label": "24", "matrix": [4,2], "x": 4, "y": 2.75, "w": 1.5 }, 61 | { "label": "54", "matrix": [4,3], "x": 5.5, "y": 2.75, "w": 1.5 }, 62 | { "label": "53", "matrix": [4,4], "x": 7, "y": 2.25 }, 63 | { "label": "52", "matrix": [5,0], "x": 8, "y": 2 }, 64 | { "label": "51", "matrix": [5,1], "x": 9, "y": 2.25 }, 65 | { "label": "50", "matrix": [5,2], "x": 10, "y": 2.625 } 66 | ] 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy_chocV1/keymaps/default/keymap.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2021 weteor 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #include QMK_KEYBOARD_H 18 | 19 | enum layers 20 | { 21 | _ALPHA_QWERTY = 0, 22 | }; 23 | 24 | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { 25 | 26 | 27 | [_ALPHA_QWERTY] = LAYOUT_grumpy( 28 | KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, 29 | KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, 30 | KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH 31 | ) 32 | }; 33 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy_chocV1/keymaps/vial/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 weteor 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #define VIAL_KEYBOARD_UID {0xD8, 0xE1, 0xE5, 0x27, 0x39, 0x36, 0x89, 0x45} 21 | 22 | #define VIAL_KEY_OVERRIDE_ENTRIES 20 23 | #define VIAL_COMBO_ENTRIES 20 24 | #define VIAL_TAP_DANCE_ENTRIES 20 25 | #define DYNAMIC_KEYMAP_LAYER_COUNT 6 26 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy_chocV1/keymaps/vial/keymap.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2021 weteor 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #include QMK_KEYBOARD_H 18 | 19 | enum layers 20 | { 21 | _ALPHA_QWERTY = 0, 22 | }; 23 | 24 | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { 25 | 26 | 27 | [_ALPHA_QWERTY] = LAYOUT_28( 28 | KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, 29 | KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, 30 | KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH 31 | ) 32 | }; 33 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy_chocV1/keymaps/vial/rules.mk: -------------------------------------------------------------------------------- 1 | VIA_ENABLE = yes 2 | VIAL_ENABLE = yes 3 | VIAL_INSECURE = yes 4 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy_chocV1/keymaps/vial/vial.json: -------------------------------------------------------------------------------- 1 | { 2 | "lighting": "none", 3 | "matrix": { 4 | "rows": 6, 5 | "cols": 5 6 | }, 7 | "layouts": { 8 | "keymap":[ 9 | [ 10 | { 11 | "r": 14, 12 | "x": 3 13 | }, 14 | "0,2" 15 | ], 16 | [ 17 | { 18 | "y": -0.75, 19 | "x": 2 20 | }, 21 | "0,1", 22 | { 23 | "x": 1 24 | }, 25 | "0,3" 26 | ], 27 | [ 28 | { 29 | "y": -0.5, 30 | "x": 5 31 | }, 32 | "0,4" 33 | ], 34 | [ 35 | { 36 | "y": -0.75, 37 | "x": 3 38 | }, 39 | "1,2" 40 | ], 41 | [ 42 | { 43 | "y": -0.75, 44 | "x": 2 45 | }, 46 | "1,1", 47 | { 48 | "x": 1 49 | }, 50 | "1,3" 51 | ], 52 | [ 53 | { 54 | "y": -0.625, 55 | "x": 1 56 | }, 57 | "1,0" 58 | ], 59 | [ 60 | { 61 | "y": -0.875, 62 | "x": 5 63 | }, 64 | "1,4" 65 | ], 66 | [ 67 | { 68 | "y": -0.75, 69 | "x": 3 70 | }, 71 | "2,2" 72 | ], 73 | [ 74 | { 75 | "y": -0.75, 76 | "x": 2 77 | }, 78 | "2,1", 79 | { 80 | "x": 1 81 | }, 82 | "2,3" 83 | ], 84 | [ 85 | { 86 | "y": -0.625, 87 | "x": 1 88 | }, 89 | "2,0" 90 | ], 91 | [ 92 | { 93 | "y": -0.875, 94 | "x": 5, 95 | "w": 1.5 96 | }, 97 | "2,4" 98 | ], 99 | [ 100 | { 101 | "r": -14, 102 | "y": -1, 103 | "x": 7 104 | }, 105 | "3,2" 106 | ], 107 | [ 108 | { 109 | "y": -0.75, 110 | "x": 6 111 | }, 112 | "3,3", 113 | { 114 | "x": 1 115 | }, 116 | "3,1" 117 | ], 118 | [ 119 | { 120 | "y": -0.5, 121 | "x": 5 122 | }, 123 | "3,4" 124 | ], 125 | [ 126 | { 127 | "y": -0.75, 128 | "x": 7 129 | }, 130 | "4,2" 131 | ], 132 | [ 133 | { 134 | "y": -0.75, 135 | "x": 6 136 | }, 137 | "4,3", 138 | { 139 | "x": 1 140 | }, 141 | "4,1" 142 | ], 143 | [ 144 | { 145 | "y": -0.625, 146 | "x": 9 147 | }, 148 | "4,0" 149 | ], 150 | [ 151 | { 152 | "y": -0.875, 153 | "x": 5 154 | }, 155 | "4,4" 156 | ], 157 | [ 158 | { 159 | "y": -0.75, 160 | "x": 7 161 | }, 162 | "5,2" 163 | ], 164 | [ 165 | { 166 | "y": -0.75, 167 | "x": 6 168 | }, 169 | "5,3", 170 | { 171 | "x": 1 172 | }, 173 | "5,1" 174 | ], 175 | [ 176 | { 177 | "y": -0.625, 178 | "x": 9 179 | }, 180 | "5,0" 181 | ], 182 | [ 183 | { 184 | "y": -0.875, 185 | "x": 4.5, 186 | "w": 1.5 187 | }, 188 | "5,4" 189 | ] 190 | ] 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy_chocV1/mcuconf.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 weteor 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include_next 21 | 22 | -------------------------------------------------------------------------------- /firmware/QMK/grumpy_chocV1/rules.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/firmware/QMK/grumpy_chocV1/rules.mk -------------------------------------------------------------------------------- /firmware/QMK/grumpy_chocV1_vial.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/firmware/QMK/grumpy_chocV1_vial.uf2 -------------------------------------------------------------------------------- /grumpy_ch552t/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (version 7) 3 | (lib (name "mcu")(type "KiCad")(uri "D:/.build/kleeb/mcu.pretty")(options "")(descr "")) 4 | (lib (name "weteor")(type "KiCad")(uri "D:/.build/weteor_kicad_lib/footprints")(options "")(descr "")) 5 | ) 6 | -------------------------------------------------------------------------------- /grumpy_ch552t/grumpy_ch522t.kicad_prl: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "active_layer": 0, 4 | "active_layer_preset": "", 5 | "auto_track_width": true, 6 | "hidden_netclasses": [], 7 | "hidden_nets": [], 8 | "high_contrast_mode": 0, 9 | "net_color_mode": 1, 10 | "opacity": { 11 | "images": 0.6, 12 | "pads": 1.0, 13 | "tracks": 1.0, 14 | "vias": 1.0, 15 | "zones": 0.6 16 | }, 17 | "selection_filter": { 18 | "dimensions": true, 19 | "footprints": true, 20 | "graphics": true, 21 | "keepouts": true, 22 | "lockedItems": true, 23 | "otherItems": true, 24 | "pads": true, 25 | "text": true, 26 | "tracks": true, 27 | "vias": true, 28 | "zones": true 29 | }, 30 | "visible_items": [ 31 | 0, 32 | 1, 33 | 2, 34 | 3, 35 | 4, 36 | 5, 37 | 8, 38 | 9, 39 | 10, 40 | 11, 41 | 12, 42 | 13, 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 | 40 65 | ], 66 | "visible_layers": "ffcffff_ffffffff", 67 | "zone_display_mode": 0 68 | }, 69 | "meta": { 70 | "filename": "grumpy_lp.kicad_prl", 71 | "version": 3 72 | }, 73 | "project": { 74 | "files": [] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /grumpy_ch552t/grumpy_ch522t.kicad_pro: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "3dviewports": [], 4 | "design_settings": { 5 | "defaults": { 6 | "board_outline_line_width": 0.09999999999999999, 7 | "copper_line_width": 0.19999999999999998, 8 | "copper_text_italic": false, 9 | "copper_text_size_h": 1.5, 10 | "copper_text_size_v": 1.5, 11 | "copper_text_thickness": 0.3, 12 | "copper_text_upright": false, 13 | "courtyard_line_width": 0.049999999999999996, 14 | "dimension_precision": 4, 15 | "dimension_units": 3, 16 | "dimensions": { 17 | "arrow_length": 1270000, 18 | "extension_offset": 500000, 19 | "keep_text_aligned": true, 20 | "suppress_zeroes": false, 21 | "text_position": 0, 22 | "units_format": 1 23 | }, 24 | "fab_line_width": 0.09999999999999999, 25 | "fab_text_italic": false, 26 | "fab_text_size_h": 1.0, 27 | "fab_text_size_v": 1.0, 28 | "fab_text_thickness": 0.15, 29 | "fab_text_upright": false, 30 | "other_line_width": 0.15, 31 | "other_text_italic": false, 32 | "other_text_size_h": 1.0, 33 | "other_text_size_v": 1.0, 34 | "other_text_thickness": 0.15, 35 | "other_text_upright": false, 36 | "pads": { 37 | "drill": 2.2, 38 | "height": 2.2, 39 | "width": 2.2 40 | }, 41 | "silk_line_width": 0.15, 42 | "silk_text_italic": false, 43 | "silk_text_size_h": 1.0, 44 | "silk_text_size_v": 1.0, 45 | "silk_text_thickness": 0.15, 46 | "silk_text_upright": false, 47 | "zones": { 48 | "min_clearance": 0.5 49 | } 50 | }, 51 | "diff_pair_dimensions": [], 52 | "drc_exclusions": [], 53 | "meta": { 54 | "version": 2 55 | }, 56 | "rule_severities": { 57 | "annular_width": "error", 58 | "clearance": "error", 59 | "connection_width": "warning", 60 | "copper_edge_clearance": "error", 61 | "copper_sliver": "warning", 62 | "courtyards_overlap": "error", 63 | "diff_pair_gap_out_of_range": "error", 64 | "diff_pair_uncoupled_length_too_long": "error", 65 | "drill_out_of_range": "error", 66 | "duplicate_footprints": "warning", 67 | "extra_footprint": "warning", 68 | "footprint": "error", 69 | "footprint_type_mismatch": "ignore", 70 | "hole_clearance": "ignore", 71 | "hole_near_hole": "ignore", 72 | "invalid_outline": "error", 73 | "isolated_copper": "warning", 74 | "item_on_disabled_layer": "error", 75 | "items_not_allowed": "error", 76 | "length_out_of_range": "error", 77 | "lib_footprint_issues": "warning", 78 | "lib_footprint_mismatch": "warning", 79 | "malformed_courtyard": "error", 80 | "microvia_drill_out_of_range": "error", 81 | "missing_courtyard": "ignore", 82 | "missing_footprint": "warning", 83 | "net_conflict": "warning", 84 | "npth_inside_courtyard": "ignore", 85 | "padstack": "warning", 86 | "pth_inside_courtyard": "ignore", 87 | "shorting_items": "error", 88 | "silk_edge_clearance": "ignore", 89 | "silk_over_copper": "ignore", 90 | "silk_overlap": "ignore", 91 | "skew_out_of_range": "error", 92 | "solder_mask_bridge": "ignore", 93 | "starved_thermal": "error", 94 | "text_height": "warning", 95 | "text_thickness": "warning", 96 | "through_hole_pad_without_hole": "error", 97 | "too_many_vias": "error", 98 | "track_dangling": "warning", 99 | "track_width": "error", 100 | "tracks_crossing": "error", 101 | "unconnected_items": "error", 102 | "unresolved_variable": "error", 103 | "via_dangling": "warning", 104 | "zones_intersect": "error" 105 | }, 106 | "rules": { 107 | "max_error": 0.005, 108 | "min_clearance": 0.0, 109 | "min_connection": 0.0, 110 | "min_copper_edge_clearance": 0.0, 111 | "min_hole_clearance": 0.25, 112 | "min_hole_to_hole": 0.25, 113 | "min_microvia_diameter": 0.19999999999999998, 114 | "min_microvia_drill": 0.09999999999999999, 115 | "min_resolved_spokes": 2, 116 | "min_silk_clearance": 0.0, 117 | "min_text_height": 0.7999999999999999, 118 | "min_text_thickness": 0.08, 119 | "min_through_hole_diameter": 0.3, 120 | "min_track_width": 0.0, 121 | "min_via_annular_width": 0.09999999999999999, 122 | "min_via_diameter": 0.5, 123 | "solder_mask_clearance": 0.0, 124 | "solder_mask_min_width": 0.0, 125 | "solder_mask_to_copper_clearance": 0.0, 126 | "use_height_for_length_calcs": true 127 | }, 128 | "teardrop_options": [ 129 | { 130 | "td_allow_use_two_tracks": true, 131 | "td_curve_segcount": 5, 132 | "td_on_pad_in_zone": false, 133 | "td_onpadsmd": true, 134 | "td_onroundshapesonly": false, 135 | "td_ontrackend": false, 136 | "td_onviapad": true 137 | } 138 | ], 139 | "teardrop_parameters": [ 140 | { 141 | "td_curve_segcount": 0, 142 | "td_height_ratio": 1.0, 143 | "td_length_ratio": 0.5, 144 | "td_maxheight": 2.0, 145 | "td_maxlen": 1.0, 146 | "td_target_name": "td_round_shape", 147 | "td_width_to_size_filter_ratio": 0.9 148 | }, 149 | { 150 | "td_curve_segcount": 0, 151 | "td_height_ratio": 1.0, 152 | "td_length_ratio": 0.5, 153 | "td_maxheight": 2.0, 154 | "td_maxlen": 1.0, 155 | "td_target_name": "td_rect_shape", 156 | "td_width_to_size_filter_ratio": 0.9 157 | }, 158 | { 159 | "td_curve_segcount": 0, 160 | "td_height_ratio": 1.0, 161 | "td_length_ratio": 0.5, 162 | "td_maxheight": 2.0, 163 | "td_maxlen": 1.0, 164 | "td_target_name": "td_track_end", 165 | "td_width_to_size_filter_ratio": 0.9 166 | } 167 | ], 168 | "track_widths": [], 169 | "via_dimensions": [], 170 | "zones_allow_external_fillets": false 171 | }, 172 | "layer_presets": [], 173 | "viewports": [] 174 | }, 175 | "boards": [], 176 | "cvpcb": { 177 | "equivalence_files": [] 178 | }, 179 | "erc": { 180 | "erc_exclusions": [], 181 | "meta": { 182 | "version": 0 183 | }, 184 | "pin_map": [ 185 | [ 186 | 0, 187 | 0, 188 | 0, 189 | 0, 190 | 0, 191 | 0, 192 | 1, 193 | 0, 194 | 0, 195 | 0, 196 | 0, 197 | 2 198 | ], 199 | [ 200 | 0, 201 | 2, 202 | 0, 203 | 1, 204 | 0, 205 | 0, 206 | 1, 207 | 0, 208 | 2, 209 | 2, 210 | 2, 211 | 2 212 | ], 213 | [ 214 | 0, 215 | 0, 216 | 0, 217 | 0, 218 | 0, 219 | 0, 220 | 1, 221 | 0, 222 | 1, 223 | 0, 224 | 1, 225 | 2 226 | ], 227 | [ 228 | 0, 229 | 1, 230 | 0, 231 | 0, 232 | 0, 233 | 0, 234 | 1, 235 | 1, 236 | 2, 237 | 1, 238 | 1, 239 | 2 240 | ], 241 | [ 242 | 0, 243 | 0, 244 | 0, 245 | 0, 246 | 0, 247 | 0, 248 | 1, 249 | 0, 250 | 0, 251 | 0, 252 | 0, 253 | 2 254 | ], 255 | [ 256 | 0, 257 | 0, 258 | 0, 259 | 0, 260 | 0, 261 | 0, 262 | 0, 263 | 0, 264 | 0, 265 | 0, 266 | 0, 267 | 2 268 | ], 269 | [ 270 | 1, 271 | 1, 272 | 1, 273 | 1, 274 | 1, 275 | 0, 276 | 1, 277 | 1, 278 | 1, 279 | 1, 280 | 1, 281 | 2 282 | ], 283 | [ 284 | 0, 285 | 0, 286 | 0, 287 | 1, 288 | 0, 289 | 0, 290 | 1, 291 | 0, 292 | 0, 293 | 0, 294 | 0, 295 | 2 296 | ], 297 | [ 298 | 0, 299 | 2, 300 | 1, 301 | 2, 302 | 0, 303 | 0, 304 | 1, 305 | 0, 306 | 2, 307 | 2, 308 | 2, 309 | 2 310 | ], 311 | [ 312 | 0, 313 | 2, 314 | 0, 315 | 1, 316 | 0, 317 | 0, 318 | 1, 319 | 0, 320 | 2, 321 | 0, 322 | 0, 323 | 2 324 | ], 325 | [ 326 | 0, 327 | 2, 328 | 1, 329 | 1, 330 | 0, 331 | 0, 332 | 1, 333 | 0, 334 | 2, 335 | 0, 336 | 0, 337 | 2 338 | ], 339 | [ 340 | 2, 341 | 2, 342 | 2, 343 | 2, 344 | 2, 345 | 2, 346 | 2, 347 | 2, 348 | 2, 349 | 2, 350 | 2, 351 | 2 352 | ] 353 | ], 354 | "rule_severities": { 355 | "bus_definition_conflict": "error", 356 | "bus_entry_needed": "error", 357 | "bus_to_bus_conflict": "error", 358 | "bus_to_net_conflict": "error", 359 | "conflicting_netclasses": "error", 360 | "different_unit_footprint": "error", 361 | "different_unit_net": "error", 362 | "duplicate_reference": "error", 363 | "duplicate_sheet_names": "error", 364 | "endpoint_off_grid": "warning", 365 | "extra_units": "error", 366 | "global_label_dangling": "warning", 367 | "hier_label_mismatch": "error", 368 | "label_dangling": "error", 369 | "lib_symbol_issues": "warning", 370 | "missing_bidi_pin": "warning", 371 | "missing_input_pin": "warning", 372 | "missing_power_pin": "error", 373 | "missing_unit": "warning", 374 | "multiple_net_names": "warning", 375 | "net_not_bus_member": "warning", 376 | "no_connect_connected": "warning", 377 | "no_connect_dangling": "warning", 378 | "pin_not_connected": "error", 379 | "pin_not_driven": "error", 380 | "pin_to_pin": "warning", 381 | "power_pin_not_driven": "error", 382 | "similar_labels": "warning", 383 | "simulation_model_issue": "ignore", 384 | "unannotated": "error", 385 | "unit_value_mismatch": "error", 386 | "unresolved_variable": "error", 387 | "wire_dangling": "error" 388 | } 389 | }, 390 | "libraries": { 391 | "pinned_footprint_libs": [], 392 | "pinned_symbol_libs": [] 393 | }, 394 | "meta": { 395 | "filename": "grumpy_lp.kicad_pro", 396 | "version": 1 397 | }, 398 | "net_settings": { 399 | "classes": [ 400 | { 401 | "bus_width": 12, 402 | "clearance": 0.2, 403 | "diff_pair_gap": 0.25, 404 | "diff_pair_via_gap": 0.25, 405 | "diff_pair_width": 0.2, 406 | "line_style": 0, 407 | "microvia_diameter": 0.3, 408 | "microvia_drill": 0.1, 409 | "name": "Default", 410 | "pcb_color": "rgba(0, 0, 0, 0.000)", 411 | "schematic_color": "rgba(0, 0, 0, 0.000)", 412 | "track_width": 0.25, 413 | "via_diameter": 0.5, 414 | "via_drill": 0.3, 415 | "wire_width": 6 416 | } 417 | ], 418 | "meta": { 419 | "version": 3 420 | }, 421 | "net_colors": null, 422 | "netclass_assignments": null, 423 | "netclass_patterns": [] 424 | }, 425 | "pcbnew": { 426 | "last_paths": { 427 | "gencad": "", 428 | "idf": "", 429 | "netlist": "", 430 | "plot": "", 431 | "pos_files": "", 432 | "specctra_dsn": "", 433 | "step": "grumpy_lp_mx.step", 434 | "svg": "", 435 | "vrml": "" 436 | }, 437 | "page_layout_descr_file": "" 438 | }, 439 | "schematic": { 440 | "annotate_start_num": 0, 441 | "drawing": { 442 | "dashed_lines_dash_length_ratio": 12.0, 443 | "dashed_lines_gap_length_ratio": 3.0, 444 | "default_line_thickness": 6.0, 445 | "default_text_size": 50.0, 446 | "field_names": [], 447 | "intersheets_ref_own_page": false, 448 | "intersheets_ref_prefix": "", 449 | "intersheets_ref_short": false, 450 | "intersheets_ref_show": false, 451 | "intersheets_ref_suffix": "", 452 | "junction_size_choice": 3, 453 | "label_size_ratio": 0.375, 454 | "pin_symbol_size": 25.0, 455 | "text_offset_ratio": 0.15 456 | }, 457 | "legacy_lib_dir": "", 458 | "legacy_lib_list": [], 459 | "meta": { 460 | "version": 1 461 | }, 462 | "net_format_name": "", 463 | "page_layout_descr_file": "", 464 | "plot_directory": "", 465 | "spice_current_sheet_as_root": false, 466 | "spice_external_command": "spice \"%I\"", 467 | "spice_model_current_sheet_as_root": true, 468 | "spice_save_all_currents": false, 469 | "spice_save_all_voltages": false, 470 | "subpart_first_id": 65, 471 | "subpart_id_separator": 0 472 | }, 473 | "sheets": [ 474 | [ 475 | "614a618d-e872-4108-be17-bc533570c595", 476 | "" 477 | ] 478 | ], 479 | "text_variables": {} 480 | } 481 | -------------------------------------------------------------------------------- /grumpy_choc/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (version 7) 3 | (lib (name "mcu")(type "KiCad")(uri "/home/weteor/.build/kleeb/mcu.pretty")(options "")(descr "")) 4 | (lib (name "weteor")(type "KiCad")(uri "/home/weteor/.build/weteor_kicad_lib/footprints")(options "")(descr "")) 5 | (lib (name "pg1350")(type "KiCad")(uri "/home/weteor/.build/kleeb/pg1350.pretty")(options "")(descr "")) 6 | ) 7 | -------------------------------------------------------------------------------- /grumpy_choc/grumpy_choc.kicad_prl: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "active_layer": 0, 4 | "active_layer_preset": "", 5 | "auto_track_width": true, 6 | "hidden_netclasses": [], 7 | "hidden_nets": [], 8 | "high_contrast_mode": 0, 9 | "net_color_mode": 1, 10 | "opacity": { 11 | "images": 0.6, 12 | "pads": 1.0, 13 | "tracks": 1.0, 14 | "vias": 1.0, 15 | "zones": 0.6 16 | }, 17 | "selection_filter": { 18 | "dimensions": true, 19 | "footprints": true, 20 | "graphics": true, 21 | "keepouts": true, 22 | "lockedItems": true, 23 | "otherItems": true, 24 | "pads": true, 25 | "text": true, 26 | "tracks": true, 27 | "vias": true, 28 | "zones": true 29 | }, 30 | "visible_items": [ 31 | 0, 32 | 1, 33 | 2, 34 | 3, 35 | 4, 36 | 5, 37 | 8, 38 | 9, 39 | 10, 40 | 11, 41 | 12, 42 | 13, 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 | 40 65 | ], 66 | "visible_layers": "ffcffff_ffffffff", 67 | "zone_display_mode": 0 68 | }, 69 | "git": { 70 | "repo_password": "", 71 | "repo_type": "", 72 | "repo_username": "", 73 | "ssh_key": "" 74 | }, 75 | "meta": { 76 | "filename": "grumpy_choc.kicad_prl", 77 | "version": 3 78 | }, 79 | "project": { 80 | "files": [] 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /grumpy_choc/grumpy_choc.kicad_pro: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "3dviewports": [], 4 | "design_settings": { 5 | "defaults": { 6 | "apply_defaults_to_fp_fields": false, 7 | "apply_defaults_to_fp_shapes": false, 8 | "apply_defaults_to_fp_text": false, 9 | "board_outline_line_width": 0.1, 10 | "copper_line_width": 0.2, 11 | "copper_text_italic": false, 12 | "copper_text_size_h": 1.5, 13 | "copper_text_size_v": 1.5, 14 | "copper_text_thickness": 0.3, 15 | "copper_text_upright": false, 16 | "courtyard_line_width": 0.05, 17 | "dimension_precision": 4, 18 | "dimension_units": 3, 19 | "dimensions": { 20 | "arrow_length": 1270000, 21 | "extension_offset": 500000, 22 | "keep_text_aligned": true, 23 | "suppress_zeroes": false, 24 | "text_position": 0, 25 | "units_format": 1 26 | }, 27 | "fab_line_width": 0.1, 28 | "fab_text_italic": false, 29 | "fab_text_size_h": 1.0, 30 | "fab_text_size_v": 1.0, 31 | "fab_text_thickness": 0.15, 32 | "fab_text_upright": false, 33 | "other_line_width": 0.15, 34 | "other_text_italic": false, 35 | "other_text_size_h": 1.0, 36 | "other_text_size_v": 1.0, 37 | "other_text_thickness": 0.15, 38 | "other_text_upright": false, 39 | "pads": { 40 | "drill": 4.0, 41 | "height": 4.0, 42 | "width": 4.0 43 | }, 44 | "silk_line_width": 0.15, 45 | "silk_text_italic": false, 46 | "silk_text_size_h": 1.0, 47 | "silk_text_size_v": 1.0, 48 | "silk_text_thickness": 0.15, 49 | "silk_text_upright": false, 50 | "zones": { 51 | "min_clearance": 0.5 52 | } 53 | }, 54 | "diff_pair_dimensions": [], 55 | "drc_exclusions": [], 56 | "meta": { 57 | "version": 2 58 | }, 59 | "rule_severities": { 60 | "annular_width": "error", 61 | "clearance": "error", 62 | "connection_width": "warning", 63 | "copper_edge_clearance": "error", 64 | "copper_sliver": "warning", 65 | "courtyards_overlap": "error", 66 | "diff_pair_gap_out_of_range": "error", 67 | "diff_pair_uncoupled_length_too_long": "error", 68 | "drill_out_of_range": "error", 69 | "duplicate_footprints": "warning", 70 | "extra_footprint": "warning", 71 | "footprint": "error", 72 | "footprint_symbol_mismatch": "warning", 73 | "footprint_type_mismatch": "ignore", 74 | "hole_clearance": "ignore", 75 | "hole_near_hole": "ignore", 76 | "holes_co_located": "warning", 77 | "invalid_outline": "error", 78 | "isolated_copper": "warning", 79 | "item_on_disabled_layer": "error", 80 | "items_not_allowed": "error", 81 | "length_out_of_range": "error", 82 | "lib_footprint_issues": "warning", 83 | "lib_footprint_mismatch": "warning", 84 | "malformed_courtyard": "error", 85 | "microvia_drill_out_of_range": "error", 86 | "missing_courtyard": "ignore", 87 | "missing_footprint": "warning", 88 | "net_conflict": "warning", 89 | "npth_inside_courtyard": "ignore", 90 | "padstack": "warning", 91 | "pth_inside_courtyard": "ignore", 92 | "shorting_items": "error", 93 | "silk_edge_clearance": "ignore", 94 | "silk_over_copper": "ignore", 95 | "silk_overlap": "ignore", 96 | "skew_out_of_range": "error", 97 | "solder_mask_bridge": "ignore", 98 | "starved_thermal": "error", 99 | "text_height": "warning", 100 | "text_thickness": "warning", 101 | "through_hole_pad_without_hole": "error", 102 | "too_many_vias": "error", 103 | "track_dangling": "warning", 104 | "track_width": "error", 105 | "tracks_crossing": "error", 106 | "unconnected_items": "error", 107 | "unresolved_variable": "error", 108 | "via_dangling": "warning", 109 | "zones_intersect": "error" 110 | }, 111 | "rules": { 112 | "max_error": 0.005, 113 | "min_clearance": 0.0, 114 | "min_connection": 0.0, 115 | "min_copper_edge_clearance": 0.3, 116 | "min_hole_clearance": 0.25, 117 | "min_hole_to_hole": 0.25, 118 | "min_microvia_diameter": 0.2, 119 | "min_microvia_drill": 0.1, 120 | "min_resolved_spokes": 2, 121 | "min_silk_clearance": 0.0, 122 | "min_text_height": 0.8, 123 | "min_text_thickness": 0.08, 124 | "min_through_hole_diameter": 0.3, 125 | "min_track_width": 0.0, 126 | "min_via_annular_width": 0.1, 127 | "min_via_diameter": 0.5, 128 | "solder_mask_clearance": 0.0, 129 | "solder_mask_min_width": 0.0, 130 | "solder_mask_to_copper_clearance": 0.0, 131 | "use_height_for_length_calcs": true 132 | }, 133 | "teardrop_options": [ 134 | { 135 | "td_onpadsmd": true, 136 | "td_onroundshapesonly": false, 137 | "td_ontrackend": false, 138 | "td_onviapad": true 139 | } 140 | ], 141 | "teardrop_parameters": [ 142 | { 143 | "td_allow_use_two_tracks": true, 144 | "td_curve_segcount": 0, 145 | "td_height_ratio": 1.0, 146 | "td_length_ratio": 0.5, 147 | "td_maxheight": 2.0, 148 | "td_maxlen": 1.0, 149 | "td_on_pad_in_zone": false, 150 | "td_target_name": "td_round_shape", 151 | "td_width_to_size_filter_ratio": 0.9 152 | }, 153 | { 154 | "td_allow_use_two_tracks": true, 155 | "td_curve_segcount": 0, 156 | "td_height_ratio": 1.0, 157 | "td_length_ratio": 0.5, 158 | "td_maxheight": 2.0, 159 | "td_maxlen": 1.0, 160 | "td_on_pad_in_zone": false, 161 | "td_target_name": "td_rect_shape", 162 | "td_width_to_size_filter_ratio": 0.9 163 | }, 164 | { 165 | "td_allow_use_two_tracks": true, 166 | "td_curve_segcount": 0, 167 | "td_height_ratio": 1.0, 168 | "td_length_ratio": 0.5, 169 | "td_maxheight": 2.0, 170 | "td_maxlen": 1.0, 171 | "td_on_pad_in_zone": false, 172 | "td_target_name": "td_track_end", 173 | "td_width_to_size_filter_ratio": 0.9 174 | } 175 | ], 176 | "track_widths": [], 177 | "tuning_pattern_settings": { 178 | "diff_pair_defaults": { 179 | "corner_radius_percentage": 80, 180 | "corner_style": 1, 181 | "max_amplitude": 1.0, 182 | "min_amplitude": 0.2, 183 | "single_sided": false, 184 | "spacing": 1.0 185 | }, 186 | "diff_pair_skew_defaults": { 187 | "corner_radius_percentage": 80, 188 | "corner_style": 1, 189 | "max_amplitude": 1.0, 190 | "min_amplitude": 0.2, 191 | "single_sided": false, 192 | "spacing": 0.6 193 | }, 194 | "single_track_defaults": { 195 | "corner_radius_percentage": 80, 196 | "corner_style": 1, 197 | "max_amplitude": 1.0, 198 | "min_amplitude": 0.2, 199 | "single_sided": false, 200 | "spacing": 0.6 201 | } 202 | }, 203 | "via_dimensions": [], 204 | "zones_allow_external_fillets": false 205 | }, 206 | "ipc2581": { 207 | "dist": "", 208 | "distpn": "", 209 | "internal_id": "", 210 | "mfg": "", 211 | "mpn": "" 212 | }, 213 | "layer_presets": [], 214 | "viewports": [] 215 | }, 216 | "boards": [], 217 | "cvpcb": { 218 | "equivalence_files": [] 219 | }, 220 | "erc": { 221 | "erc_exclusions": [], 222 | "meta": { 223 | "version": 0 224 | }, 225 | "pin_map": [ 226 | [ 227 | 0, 228 | 0, 229 | 0, 230 | 0, 231 | 0, 232 | 0, 233 | 1, 234 | 0, 235 | 0, 236 | 0, 237 | 0, 238 | 2 239 | ], 240 | [ 241 | 0, 242 | 2, 243 | 0, 244 | 1, 245 | 0, 246 | 0, 247 | 1, 248 | 0, 249 | 2, 250 | 2, 251 | 2, 252 | 2 253 | ], 254 | [ 255 | 0, 256 | 0, 257 | 0, 258 | 0, 259 | 0, 260 | 0, 261 | 1, 262 | 0, 263 | 1, 264 | 0, 265 | 1, 266 | 2 267 | ], 268 | [ 269 | 0, 270 | 1, 271 | 0, 272 | 0, 273 | 0, 274 | 0, 275 | 1, 276 | 1, 277 | 2, 278 | 1, 279 | 1, 280 | 2 281 | ], 282 | [ 283 | 0, 284 | 0, 285 | 0, 286 | 0, 287 | 0, 288 | 0, 289 | 1, 290 | 0, 291 | 0, 292 | 0, 293 | 0, 294 | 2 295 | ], 296 | [ 297 | 0, 298 | 0, 299 | 0, 300 | 0, 301 | 0, 302 | 0, 303 | 0, 304 | 0, 305 | 0, 306 | 0, 307 | 0, 308 | 2 309 | ], 310 | [ 311 | 1, 312 | 1, 313 | 1, 314 | 1, 315 | 1, 316 | 0, 317 | 1, 318 | 1, 319 | 1, 320 | 1, 321 | 1, 322 | 2 323 | ], 324 | [ 325 | 0, 326 | 0, 327 | 0, 328 | 1, 329 | 0, 330 | 0, 331 | 1, 332 | 0, 333 | 0, 334 | 0, 335 | 0, 336 | 2 337 | ], 338 | [ 339 | 0, 340 | 2, 341 | 1, 342 | 2, 343 | 0, 344 | 0, 345 | 1, 346 | 0, 347 | 2, 348 | 2, 349 | 2, 350 | 2 351 | ], 352 | [ 353 | 0, 354 | 2, 355 | 0, 356 | 1, 357 | 0, 358 | 0, 359 | 1, 360 | 0, 361 | 2, 362 | 0, 363 | 0, 364 | 2 365 | ], 366 | [ 367 | 0, 368 | 2, 369 | 1, 370 | 1, 371 | 0, 372 | 0, 373 | 1, 374 | 0, 375 | 2, 376 | 0, 377 | 0, 378 | 2 379 | ], 380 | [ 381 | 2, 382 | 2, 383 | 2, 384 | 2, 385 | 2, 386 | 2, 387 | 2, 388 | 2, 389 | 2, 390 | 2, 391 | 2, 392 | 2 393 | ] 394 | ], 395 | "rule_severities": { 396 | "bus_definition_conflict": "error", 397 | "bus_entry_needed": "error", 398 | "bus_to_bus_conflict": "error", 399 | "bus_to_net_conflict": "error", 400 | "conflicting_netclasses": "error", 401 | "different_unit_footprint": "error", 402 | "different_unit_net": "error", 403 | "duplicate_reference": "error", 404 | "duplicate_sheet_names": "error", 405 | "endpoint_off_grid": "warning", 406 | "extra_units": "error", 407 | "global_label_dangling": "warning", 408 | "hier_label_mismatch": "error", 409 | "label_dangling": "error", 410 | "lib_symbol_issues": "warning", 411 | "missing_bidi_pin": "warning", 412 | "missing_input_pin": "warning", 413 | "missing_power_pin": "error", 414 | "missing_unit": "warning", 415 | "multiple_net_names": "warning", 416 | "net_not_bus_member": "warning", 417 | "no_connect_connected": "warning", 418 | "no_connect_dangling": "warning", 419 | "pin_not_connected": "error", 420 | "pin_not_driven": "error", 421 | "pin_to_pin": "warning", 422 | "power_pin_not_driven": "error", 423 | "similar_labels": "warning", 424 | "simulation_model_issue": "ignore", 425 | "unannotated": "error", 426 | "unit_value_mismatch": "error", 427 | "unresolved_variable": "error", 428 | "wire_dangling": "error" 429 | } 430 | }, 431 | "libraries": { 432 | "pinned_footprint_libs": [], 433 | "pinned_symbol_libs": [] 434 | }, 435 | "meta": { 436 | "filename": "grumpy_choc.kicad_pro", 437 | "version": 1 438 | }, 439 | "net_settings": { 440 | "classes": [ 441 | { 442 | "bus_width": 12, 443 | "clearance": 0.2, 444 | "diff_pair_gap": 0.25, 445 | "diff_pair_via_gap": 0.25, 446 | "diff_pair_width": 0.2, 447 | "line_style": 0, 448 | "microvia_diameter": 0.3, 449 | "microvia_drill": 0.1, 450 | "name": "Default", 451 | "pcb_color": "rgba(0, 0, 0, 0.000)", 452 | "schematic_color": "rgba(0, 0, 0, 0.000)", 453 | "track_width": 0.25, 454 | "via_diameter": 0.5, 455 | "via_drill": 0.3, 456 | "wire_width": 6 457 | } 458 | ], 459 | "meta": { 460 | "version": 3 461 | }, 462 | "net_colors": null, 463 | "netclass_assignments": null, 464 | "netclass_patterns": [] 465 | }, 466 | "pcbnew": { 467 | "last_paths": { 468 | "gencad": "", 469 | "idf": "", 470 | "netlist": "", 471 | "plot": "gerber/", 472 | "pos_files": "", 473 | "specctra_dsn": "", 474 | "step": "grumpy_lp_choc.step", 475 | "svg": "", 476 | "vrml": "" 477 | }, 478 | "page_layout_descr_file": "" 479 | }, 480 | "schematic": { 481 | "annotate_start_num": 0, 482 | "bom_export_filename": "", 483 | "bom_fmt_presets": [], 484 | "bom_fmt_settings": { 485 | "field_delimiter": ",", 486 | "keep_line_breaks": false, 487 | "keep_tabs": false, 488 | "name": "CSV", 489 | "ref_delimiter": ",", 490 | "ref_range_delimiter": "", 491 | "string_delimiter": "\"" 492 | }, 493 | "bom_presets": [], 494 | "bom_settings": { 495 | "exclude_dnp": false, 496 | "fields_ordered": [ 497 | { 498 | "group_by": false, 499 | "label": "Reference", 500 | "name": "Reference", 501 | "show": true 502 | }, 503 | { 504 | "group_by": true, 505 | "label": "Value", 506 | "name": "Value", 507 | "show": true 508 | }, 509 | { 510 | "group_by": false, 511 | "label": "Datasheet", 512 | "name": "Datasheet", 513 | "show": true 514 | }, 515 | { 516 | "group_by": false, 517 | "label": "Footprint", 518 | "name": "Footprint", 519 | "show": true 520 | }, 521 | { 522 | "group_by": false, 523 | "label": "Qty", 524 | "name": "${QUANTITY}", 525 | "show": true 526 | }, 527 | { 528 | "group_by": true, 529 | "label": "DNP", 530 | "name": "${DNP}", 531 | "show": true 532 | } 533 | ], 534 | "filter_string": "", 535 | "group_symbols": true, 536 | "name": "Grouped By Value", 537 | "sort_asc": true, 538 | "sort_field": "Reference" 539 | }, 540 | "connection_grid_size": 50.0, 541 | "drawing": { 542 | "dashed_lines_dash_length_ratio": 12.0, 543 | "dashed_lines_gap_length_ratio": 3.0, 544 | "default_line_thickness": 6.0, 545 | "default_text_size": 50.0, 546 | "field_names": [], 547 | "intersheets_ref_own_page": false, 548 | "intersheets_ref_prefix": "", 549 | "intersheets_ref_short": false, 550 | "intersheets_ref_show": false, 551 | "intersheets_ref_suffix": "", 552 | "junction_size_choice": 3, 553 | "label_size_ratio": 0.375, 554 | "operating_point_overlay_i_precision": 3, 555 | "operating_point_overlay_i_range": "~A", 556 | "operating_point_overlay_v_precision": 3, 557 | "operating_point_overlay_v_range": "~V", 558 | "overbar_offset_ratio": 1.23, 559 | "pin_symbol_size": 25.0, 560 | "text_offset_ratio": 0.15 561 | }, 562 | "legacy_lib_dir": "", 563 | "legacy_lib_list": [], 564 | "meta": { 565 | "version": 1 566 | }, 567 | "net_format_name": "", 568 | "page_layout_descr_file": "", 569 | "plot_directory": "", 570 | "spice_current_sheet_as_root": false, 571 | "spice_external_command": "spice \"%I\"", 572 | "spice_model_current_sheet_as_root": true, 573 | "spice_save_all_currents": false, 574 | "spice_save_all_dissipations": false, 575 | "spice_save_all_voltages": false, 576 | "subpart_first_id": 65, 577 | "subpart_id_separator": 0 578 | }, 579 | "sheets": [ 580 | [ 581 | "614a618d-e872-4108-be17-bc533570c595", 582 | "Root" 583 | ] 584 | ], 585 | "text_variables": {} 586 | } 587 | -------------------------------------------------------------------------------- /grumpy_choc/sym-lib-table: -------------------------------------------------------------------------------- 1 | (sym_lib_table 2 | (version 7) 3 | (lib (name "mcu")(type "KiCad")(uri "/home/weteor/.build/kleeb/mcu.kicad_sym")(options "")(descr "")) 4 | ) 5 | -------------------------------------------------------------------------------- /grumpy_xiao/grumpy.kicad_prl: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "active_layer": 31, 4 | "active_layer_preset": "", 5 | "auto_track_width": true, 6 | "hidden_netclasses": [], 7 | "hidden_nets": [], 8 | "high_contrast_mode": 0, 9 | "net_color_mode": 1, 10 | "opacity": { 11 | "images": 0.6, 12 | "pads": 1.0, 13 | "tracks": 1.0, 14 | "vias": 1.0, 15 | "zones": 0.6 16 | }, 17 | "selection_filter": { 18 | "dimensions": true, 19 | "footprints": true, 20 | "graphics": true, 21 | "keepouts": true, 22 | "lockedItems": true, 23 | "otherItems": true, 24 | "pads": true, 25 | "text": true, 26 | "tracks": true, 27 | "vias": true, 28 | "zones": true 29 | }, 30 | "visible_items": [ 31 | 0, 32 | 1, 33 | 2, 34 | 3, 35 | 4, 36 | 5, 37 | 8, 38 | 9, 39 | 10, 40 | 11, 41 | 12, 42 | 13, 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 | 40 65 | ], 66 | "visible_layers": "fffffff_ffffffff", 67 | "zone_display_mode": 0 68 | }, 69 | "meta": { 70 | "filename": "grumpy.kicad_prl", 71 | "version": 3 72 | }, 73 | "project": { 74 | "files": [] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /grumpy_xiao/grumpy.kicad_pro: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "3dviewports": [], 4 | "design_settings": { 5 | "defaults": { 6 | "board_outline_line_width": 0.09999999999999999, 7 | "copper_line_width": 0.19999999999999998, 8 | "copper_text_italic": false, 9 | "copper_text_size_h": 1.5, 10 | "copper_text_size_v": 1.5, 11 | "copper_text_thickness": 0.3, 12 | "copper_text_upright": false, 13 | "courtyard_line_width": 0.049999999999999996, 14 | "dimension_precision": 4, 15 | "dimension_units": 3, 16 | "dimensions": { 17 | "arrow_length": 1270000, 18 | "extension_offset": 500000, 19 | "keep_text_aligned": true, 20 | "suppress_zeroes": false, 21 | "text_position": 0, 22 | "units_format": 1 23 | }, 24 | "fab_line_width": 0.09999999999999999, 25 | "fab_text_italic": false, 26 | "fab_text_size_h": 1.0, 27 | "fab_text_size_v": 1.0, 28 | "fab_text_thickness": 0.15, 29 | "fab_text_upright": false, 30 | "other_line_width": 0.15, 31 | "other_text_italic": false, 32 | "other_text_size_h": 1.0, 33 | "other_text_size_v": 1.0, 34 | "other_text_thickness": 0.15, 35 | "other_text_upright": false, 36 | "pads": { 37 | "drill": 0.762, 38 | "height": 1.524, 39 | "width": 1.524 40 | }, 41 | "silk_line_width": 0.15, 42 | "silk_text_italic": false, 43 | "silk_text_size_h": 1.0, 44 | "silk_text_size_v": 1.0, 45 | "silk_text_thickness": 0.15, 46 | "silk_text_upright": false, 47 | "zones": { 48 | "min_clearance": 0.5 49 | } 50 | }, 51 | "diff_pair_dimensions": [], 52 | "drc_exclusions": [], 53 | "meta": { 54 | "version": 2 55 | }, 56 | "rule_severities": { 57 | "annular_width": "error", 58 | "clearance": "error", 59 | "connection_width": "warning", 60 | "copper_edge_clearance": "error", 61 | "copper_sliver": "warning", 62 | "courtyards_overlap": "error", 63 | "diff_pair_gap_out_of_range": "error", 64 | "diff_pair_uncoupled_length_too_long": "error", 65 | "drill_out_of_range": "error", 66 | "duplicate_footprints": "warning", 67 | "extra_footprint": "warning", 68 | "footprint": "error", 69 | "footprint_type_mismatch": "ignore", 70 | "hole_clearance": "error", 71 | "hole_near_hole": "error", 72 | "invalid_outline": "error", 73 | "isolated_copper": "warning", 74 | "item_on_disabled_layer": "error", 75 | "items_not_allowed": "error", 76 | "length_out_of_range": "error", 77 | "lib_footprint_issues": "warning", 78 | "lib_footprint_mismatch": "warning", 79 | "malformed_courtyard": "error", 80 | "microvia_drill_out_of_range": "error", 81 | "missing_courtyard": "ignore", 82 | "missing_footprint": "warning", 83 | "net_conflict": "warning", 84 | "npth_inside_courtyard": "ignore", 85 | "padstack": "warning", 86 | "pth_inside_courtyard": "ignore", 87 | "shorting_items": "error", 88 | "silk_edge_clearance": "warning", 89 | "silk_over_copper": "ignore", 90 | "silk_overlap": "ignore", 91 | "skew_out_of_range": "error", 92 | "solder_mask_bridge": "error", 93 | "starved_thermal": "error", 94 | "text_height": "warning", 95 | "text_thickness": "warning", 96 | "through_hole_pad_without_hole": "error", 97 | "too_many_vias": "error", 98 | "track_dangling": "warning", 99 | "track_width": "error", 100 | "tracks_crossing": "error", 101 | "unconnected_items": "error", 102 | "unresolved_variable": "error", 103 | "via_dangling": "warning", 104 | "zones_intersect": "error" 105 | }, 106 | "rules": { 107 | "max_error": 0.005, 108 | "min_clearance": 0.0, 109 | "min_connection": 0.0, 110 | "min_copper_edge_clearance": 0.0, 111 | "min_hole_clearance": 0.25, 112 | "min_hole_to_hole": 0.25, 113 | "min_microvia_diameter": 0.19999999999999998, 114 | "min_microvia_drill": 0.09999999999999999, 115 | "min_resolved_spokes": 2, 116 | "min_silk_clearance": 0.0, 117 | "min_text_height": 0.7999999999999999, 118 | "min_text_thickness": 0.08, 119 | "min_through_hole_diameter": 0.3, 120 | "min_track_width": 0.0, 121 | "min_via_annular_width": 0.09999999999999999, 122 | "min_via_diameter": 0.5, 123 | "solder_mask_clearance": 0.0, 124 | "solder_mask_min_width": 0.0, 125 | "solder_mask_to_copper_clearance": 0.0, 126 | "use_height_for_length_calcs": true 127 | }, 128 | "teardrop_options": [ 129 | { 130 | "td_onpadsmd": true, 131 | "td_onroundshapesonly": false, 132 | "td_ontrackend": false, 133 | "td_onviapad": true 134 | } 135 | ], 136 | "teardrop_parameters": [ 137 | { 138 | "td_allow_use_two_tracks": true, 139 | "td_curve_segcount": 0, 140 | "td_height_ratio": 1.0, 141 | "td_length_ratio": 0.5, 142 | "td_maxheight": 2.0, 143 | "td_maxlen": 1.0, 144 | "td_on_pad_in_zone": false, 145 | "td_target_name": "td_round_shape", 146 | "td_width_to_size_filter_ratio": 0.9 147 | }, 148 | { 149 | "td_allow_use_two_tracks": true, 150 | "td_curve_segcount": 0, 151 | "td_height_ratio": 1.0, 152 | "td_length_ratio": 0.5, 153 | "td_maxheight": 2.0, 154 | "td_maxlen": 1.0, 155 | "td_on_pad_in_zone": false, 156 | "td_target_name": "td_rect_shape", 157 | "td_width_to_size_filter_ratio": 0.9 158 | }, 159 | { 160 | "td_allow_use_two_tracks": true, 161 | "td_curve_segcount": 0, 162 | "td_height_ratio": 1.0, 163 | "td_length_ratio": 0.5, 164 | "td_maxheight": 2.0, 165 | "td_maxlen": 1.0, 166 | "td_on_pad_in_zone": false, 167 | "td_target_name": "td_track_end", 168 | "td_width_to_size_filter_ratio": 0.9 169 | } 170 | ], 171 | "track_widths": [], 172 | "via_dimensions": [], 173 | "zones_allow_external_fillets": false 174 | }, 175 | "layer_presets": [], 176 | "viewports": [] 177 | }, 178 | "boards": [], 179 | "cvpcb": { 180 | "equivalence_files": [] 181 | }, 182 | "erc": { 183 | "erc_exclusions": [], 184 | "meta": { 185 | "version": 0 186 | }, 187 | "pin_map": [ 188 | [ 189 | 0, 190 | 0, 191 | 0, 192 | 0, 193 | 0, 194 | 0, 195 | 1, 196 | 0, 197 | 0, 198 | 0, 199 | 0, 200 | 2 201 | ], 202 | [ 203 | 0, 204 | 2, 205 | 0, 206 | 1, 207 | 0, 208 | 0, 209 | 1, 210 | 0, 211 | 2, 212 | 2, 213 | 2, 214 | 2 215 | ], 216 | [ 217 | 0, 218 | 0, 219 | 0, 220 | 0, 221 | 0, 222 | 0, 223 | 1, 224 | 0, 225 | 1, 226 | 0, 227 | 1, 228 | 2 229 | ], 230 | [ 231 | 0, 232 | 1, 233 | 0, 234 | 0, 235 | 0, 236 | 0, 237 | 1, 238 | 1, 239 | 2, 240 | 1, 241 | 1, 242 | 2 243 | ], 244 | [ 245 | 0, 246 | 0, 247 | 0, 248 | 0, 249 | 0, 250 | 0, 251 | 1, 252 | 0, 253 | 0, 254 | 0, 255 | 0, 256 | 2 257 | ], 258 | [ 259 | 0, 260 | 0, 261 | 0, 262 | 0, 263 | 0, 264 | 0, 265 | 0, 266 | 0, 267 | 0, 268 | 0, 269 | 0, 270 | 2 271 | ], 272 | [ 273 | 1, 274 | 1, 275 | 1, 276 | 1, 277 | 1, 278 | 0, 279 | 1, 280 | 1, 281 | 1, 282 | 1, 283 | 1, 284 | 2 285 | ], 286 | [ 287 | 0, 288 | 0, 289 | 0, 290 | 1, 291 | 0, 292 | 0, 293 | 1, 294 | 0, 295 | 0, 296 | 0, 297 | 0, 298 | 2 299 | ], 300 | [ 301 | 0, 302 | 2, 303 | 1, 304 | 2, 305 | 0, 306 | 0, 307 | 1, 308 | 0, 309 | 2, 310 | 2, 311 | 2, 312 | 2 313 | ], 314 | [ 315 | 0, 316 | 2, 317 | 0, 318 | 1, 319 | 0, 320 | 0, 321 | 1, 322 | 0, 323 | 2, 324 | 0, 325 | 0, 326 | 2 327 | ], 328 | [ 329 | 0, 330 | 2, 331 | 1, 332 | 1, 333 | 0, 334 | 0, 335 | 1, 336 | 0, 337 | 2, 338 | 0, 339 | 0, 340 | 2 341 | ], 342 | [ 343 | 2, 344 | 2, 345 | 2, 346 | 2, 347 | 2, 348 | 2, 349 | 2, 350 | 2, 351 | 2, 352 | 2, 353 | 2, 354 | 2 355 | ] 356 | ], 357 | "rule_severities": { 358 | "bus_definition_conflict": "error", 359 | "bus_entry_needed": "error", 360 | "bus_to_bus_conflict": "error", 361 | "bus_to_net_conflict": "error", 362 | "conflicting_netclasses": "error", 363 | "different_unit_footprint": "error", 364 | "different_unit_net": "error", 365 | "duplicate_reference": "error", 366 | "duplicate_sheet_names": "error", 367 | "endpoint_off_grid": "warning", 368 | "extra_units": "error", 369 | "global_label_dangling": "warning", 370 | "hier_label_mismatch": "error", 371 | "label_dangling": "error", 372 | "lib_symbol_issues": "warning", 373 | "missing_bidi_pin": "warning", 374 | "missing_input_pin": "warning", 375 | "missing_power_pin": "error", 376 | "missing_unit": "warning", 377 | "multiple_net_names": "warning", 378 | "net_not_bus_member": "warning", 379 | "no_connect_connected": "warning", 380 | "no_connect_dangling": "warning", 381 | "pin_not_connected": "error", 382 | "pin_not_driven": "error", 383 | "pin_to_pin": "warning", 384 | "power_pin_not_driven": "error", 385 | "similar_labels": "warning", 386 | "simulation_model_issue": "ignore", 387 | "unannotated": "error", 388 | "unit_value_mismatch": "error", 389 | "unresolved_variable": "error", 390 | "wire_dangling": "error" 391 | } 392 | }, 393 | "libraries": { 394 | "pinned_footprint_libs": [], 395 | "pinned_symbol_libs": [] 396 | }, 397 | "meta": { 398 | "filename": "grumpy.kicad_pro", 399 | "version": 1 400 | }, 401 | "net_settings": { 402 | "classes": [ 403 | { 404 | "bus_width": 12, 405 | "clearance": 0.2, 406 | "diff_pair_gap": 0.25, 407 | "diff_pair_via_gap": 0.25, 408 | "diff_pair_width": 0.2, 409 | "line_style": 0, 410 | "microvia_diameter": 0.3, 411 | "microvia_drill": 0.1, 412 | "name": "Default", 413 | "pcb_color": "rgba(0, 0, 0, 0.000)", 414 | "schematic_color": "rgba(0, 0, 0, 0.000)", 415 | "track_width": 0.25, 416 | "via_diameter": 0.8, 417 | "via_drill": 0.4, 418 | "wire_width": 6 419 | } 420 | ], 421 | "meta": { 422 | "version": 3 423 | }, 424 | "net_colors": null, 425 | "netclass_assignments": null, 426 | "netclass_patterns": [] 427 | }, 428 | "pcbnew": { 429 | "last_paths": { 430 | "gencad": "", 431 | "idf": "", 432 | "netlist": "", 433 | "plot": "", 434 | "pos_files": "", 435 | "specctra_dsn": "", 436 | "step": "grumpypcb.step", 437 | "svg": "", 438 | "vrml": "" 439 | }, 440 | "page_layout_descr_file": "" 441 | }, 442 | "schematic": { 443 | "annotate_start_num": 0, 444 | "drawing": { 445 | "dashed_lines_dash_length_ratio": 12.0, 446 | "dashed_lines_gap_length_ratio": 3.0, 447 | "default_line_thickness": 6.0, 448 | "default_text_size": 50.0, 449 | "field_names": [], 450 | "intersheets_ref_own_page": false, 451 | "intersheets_ref_prefix": "", 452 | "intersheets_ref_short": false, 453 | "intersheets_ref_show": false, 454 | "intersheets_ref_suffix": "", 455 | "junction_size_choice": 3, 456 | "label_size_ratio": 0.375, 457 | "pin_symbol_size": 25.0, 458 | "text_offset_ratio": 0.15 459 | }, 460 | "legacy_lib_dir": "", 461 | "legacy_lib_list": [], 462 | "meta": { 463 | "version": 1 464 | }, 465 | "net_format_name": "", 466 | "page_layout_descr_file": "", 467 | "plot_directory": "", 468 | "spice_current_sheet_as_root": false, 469 | "spice_external_command": "spice \"%I\"", 470 | "spice_model_current_sheet_as_root": true, 471 | "spice_save_all_currents": false, 472 | "spice_save_all_voltages": false, 473 | "subpart_first_id": 65, 474 | "subpart_id_separator": 0 475 | }, 476 | "sheets": [ 477 | [ 478 | "614a618d-e872-4108-be17-bc533570c595", 479 | "" 480 | ] 481 | ], 482 | "text_variables": {} 483 | } 484 | -------------------------------------------------------------------------------- /img/choc_v1_alu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/img/choc_v1_alu.jpg -------------------------------------------------------------------------------- /img/grumpies.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/img/grumpies.jpg -------------------------------------------------------------------------------- /img/grumpy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/img/grumpy.png -------------------------------------------------------------------------------- /img/grumpy_mjf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/img/grumpy_mjf.png -------------------------------------------------------------------------------- /prod/ChocV1 low profile/case_choc/grumpy case threads drawing.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/prod/ChocV1 low profile/case_choc/grumpy case threads drawing.pdf -------------------------------------------------------------------------------- /prod/ChocV1 low profile/grumpy_chocV1_GERBER_20250107.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/prod/ChocV1 low profile/grumpy_chocV1_GERBER_20250107.zip -------------------------------------------------------------------------------- /prod/MX ChocV2 low profile/case_chocV2/grumpy_lp.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/prod/MX ChocV2 low profile/case_chocV2/grumpy_lp.stl -------------------------------------------------------------------------------- /prod/MX ChocV2 low profile/case_chocV2/grumpy_lp_bottom.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/prod/MX ChocV2 low profile/case_chocV2/grumpy_lp_bottom.stl -------------------------------------------------------------------------------- /prod/MX ChocV2 low profile/grumpy_chocV2_GERBER_20240611.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/prod/MX ChocV2 low profile/grumpy_chocV2_GERBER_20240611.zip -------------------------------------------------------------------------------- /prod/MX Xiao/case_mx/grumpy.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/prod/MX Xiao/case_mx/grumpy.stl -------------------------------------------------------------------------------- /prod/MX Xiao/grumpy_mx_GERBER_20230724.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weteor/Grumpy/0a1ea6c46a17778650b71261e2852e8dad9eb8cc/prod/MX Xiao/grumpy_mx_GERBER_20230724.zip --------------------------------------------------------------------------------