refactor(woagpad): replace git submodule with raw src take 2

This commit is contained in:
A Badly Drawn Wobbler 2025-10-13 08:17:10 +00:00
parent b3f094c737
commit 9a3822458e
49 changed files with 779844 additions and 1 deletions

@ -1 +0,0 @@
Subproject commit 45ad0acfb75f09cad6c23c3f9da03b5283886215

1
hackpads/woagpad/.envrc Normal file
View file

@ -0,0 +1 @@
use flake

1
hackpads/woagpad/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.direnv/

6
hackpads/woagpad/.gitmodules vendored Normal file
View file

@ -0,0 +1,6 @@
[submodule "scottokeebs"]
path = PCB/scottokeebs
url = https://github.com/joe-scotto/scottokeebs.git
[submodule "PCB/scottokeebs"]
path = PCB/scottokeebs
url = https://github.com/joe-scotto/scottokeebs.git

File diff suppressed because it is too large Load diff

14055
hackpads/woagpad/CAD/Top.step Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,370 @@
(footprint "MODULE_DM-OLED096-636"
(version 20240108)
(generator "pcbnew")
(generator_version "8.0")
(layer "F.Cu")
(property "Reference" "REF**"
(at -9.525 -13.97 0)
(layer "F.SilkS")
(uuid "7e7212f9-e047-40a7-957d-9d75dff2839c")
(effects
(font
(size 1 1)
(thickness 0.15)
)
)
)
(property "Value" "MODULE_DM-OLED096-636"
(at 0.635 13.97 0)
(layer "F.Fab")
(uuid "b4d4ccf0-8fa9-449e-8875-0f43c4ccb85c")
(effects
(font
(size 1 1)
(thickness 0.15)
)
)
)
(property "Footprint" ""
(at 0 0 0)
(layer "F.Fab")
(hide yes)
(uuid "327d7d67-4cc6-496f-aae4-d8a52e3ad33f")
(effects
(font
(size 1.27 1.27)
(thickness 0.15)
)
)
)
(property "Datasheet" ""
(at 0 0 0)
(layer "F.Fab")
(hide yes)
(uuid "44d966ca-b591-43fa-abd7-084ca15b9340")
(effects
(font
(size 1.27 1.27)
(thickness 0.15)
)
)
)
(property "Description" ""
(at 0 0 0)
(layer "F.Fab")
(hide yes)
(uuid "55c5ce1c-04ca-4599-a868-8ec72d21b7b0")
(effects
(font
(size 1.27 1.27)
(thickness 0.15)
)
)
)
(attr through_hole)
(fp_line
(start -13 -13)
(end 13 -13)
(stroke
(width 0.127)
(type solid)
)
(layer "F.SilkS")
(uuid "9c62812f-bfbd-4b3c-a3a1-46e18d680177")
)
(fp_line
(start -13 13)
(end -13 -13)
(stroke
(width 0.127)
(type solid)
)
(layer "F.SilkS")
(uuid "b723a164-4c49-4b0d-9496-67031f78638b")
)
(fp_line
(start -7 11)
(end -7 13)
(stroke
(width 0.127)
(type solid)
)
(layer "F.SilkS")
(uuid "7ddb0cd8-3715-419a-8c4b-c28165d9b8fa")
)
(fp_line
(start -7 13)
(end -13 13)
(stroke
(width 0.127)
(type solid)
)
(layer "F.SilkS")
(uuid "92969aee-7932-4a43-8e5a-f0c790a30fe1")
)
(fp_line
(start 7 11)
(end -7 11)
(stroke
(width 0.127)
(type solid)
)
(layer "F.SilkS")
(uuid "f53e6c35-61c0-4fc8-b9c1-10b0272ae1cc")
)
(fp_line
(start 7 13)
(end 7 11)
(stroke
(width 0.127)
(type solid)
)
(layer "F.SilkS")
(uuid "2ec3b725-8068-4545-9d37-d6cc81f827cd")
)
(fp_line
(start 13 -13)
(end 13 13)
(stroke
(width 0.127)
(type solid)
)
(layer "F.SilkS")
(uuid "d7c454bd-b567-455f-9101-26e8ab46a350")
)
(fp_line
(start 13 13)
(end 7 13)
(stroke
(width 0.127)
(type solid)
)
(layer "F.SilkS")
(uuid "0d7aedf2-90ce-42f6-bd4f-f56cc2228e90")
)
(fp_circle
(center -4 -13.5)
(end -3.9 -13.5)
(stroke
(width 0.2)
(type solid)
)
(fill none)
(layer "F.SilkS")
(uuid "604bc2c2-0646-44e5-a562-16bf01eff296")
)
(fp_line
(start -13.25 -13.25)
(end 13.25 -13.25)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "c27c2d7c-fde7-42b1-a691-6e1340bf957b")
)
(fp_line
(start -13.25 13.25)
(end -13.25 -13.25)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "747ffc5e-a76e-4c01-b869-c69053f62497")
)
(fp_line
(start 13.25 -13.25)
(end 13.25 13.25)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "74dc61d1-6cb0-42bf-9e15-5d92e7782e64")
)
(fp_line
(start 13.25 13.25)
(end -13.25 13.25)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "e92eb786-c889-4c2d-8c6d-09a9c5df5d48")
)
(fp_line
(start -13 -13)
(end 13 -13)
(stroke
(width 0.127)
(type solid)
)
(layer "F.Fab")
(uuid "eac64748-33df-4bb1-b917-51611c93b902")
)
(fp_line
(start -13 13)
(end -13 -13)
(stroke
(width 0.127)
(type solid)
)
(layer "F.Fab")
(uuid "7c5f815c-7233-45fe-abb5-3a0f30199754")
)
(fp_line
(start -7 11)
(end 7 11)
(stroke
(width 0.127)
(type solid)
)
(layer "F.Fab")
(uuid "7c2d9fa3-0ce8-4f74-a37a-efa8eab80054")
)
(fp_line
(start -7 13)
(end -13 13)
(stroke
(width 0.127)
(type solid)
)
(layer "F.Fab")
(uuid "4713d769-0495-42fc-9bb0-6ca438fc0fff")
)
(fp_line
(start -7 13)
(end -7 11)
(stroke
(width 0.127)
(type solid)
)
(layer "F.Fab")
(uuid "10182d28-39e8-4cf0-99de-7de692dfe285")
)
(fp_line
(start 7 11)
(end 7 13)
(stroke
(width 0.127)
(type solid)
)
(layer "F.Fab")
(uuid "c42c9119-f089-4ec8-b6ed-f4d51b48eb44")
)
(fp_line
(start 13 -13)
(end 13 13)
(stroke
(width 0.127)
(type solid)
)
(layer "F.Fab")
(uuid "c5ef328d-a690-4bb3-adda-1d00b28bff06")
)
(fp_line
(start 13 13)
(end 7 13)
(stroke
(width 0.127)
(type solid)
)
(layer "F.Fab")
(uuid "6d6707f6-9b6b-4d50-8275-f72a8e17755f")
)
(fp_circle
(center -4 -13.5)
(end -3.9 -13.5)
(stroke
(width 0.2)
(type solid)
)
(fill none)
(layer "F.Fab")
(uuid "d0c4d446-2b4d-434c-9fe3-16f23045638a")
)
(pad "1" thru_hole rect
(at -3.81 -11.5)
(size 1.508 1.508)
(drill 1)
(layers "*.Cu" "*.Mask")
(remove_unused_layers no)
(solder_mask_margin 0.102)
(uuid "74b4afec-2c0f-441c-b0e3-c5eccc477669")
)
(pad "2" thru_hole circle
(at -1.27 -11.5)
(size 1.508 1.508)
(drill 1)
(layers "*.Cu" "*.Mask")
(remove_unused_layers no)
(solder_mask_margin 0.102)
(uuid "79003ed0-b938-4ac5-854b-9537b33e66a2")
)
(pad "3" thru_hole circle
(at 1.27 -11.5)
(size 1.508 1.508)
(drill 1)
(layers "*.Cu" "*.Mask")
(remove_unused_layers no)
(solder_mask_margin 0.102)
(uuid "456c3e03-51e1-4a58-9b8e-68d30b2a2070")
)
(pad "4" thru_hole circle
(at 3.81 -11.5)
(size 1.508 1.508)
(drill 1)
(layers "*.Cu" "*.Mask")
(remove_unused_layers no)
(solder_mask_margin 0.102)
(uuid "90bb6b7c-156c-44bb-8fd0-bc8a1d30431f")
)
(pad "MP" thru_hole circle
(at -11 -11)
(size 3 3)
(drill 2)
(layers "*.Cu" "*.Mask")
(remove_unused_layers no)
(solder_mask_margin 0.102)
(uuid "8d34444f-8f15-4d3e-af4a-adffde6c55a9")
)
(pad "MP" thru_hole circle
(at -11 11)
(size 3 3)
(drill 2)
(layers "*.Cu" "*.Mask")
(remove_unused_layers no)
(solder_mask_margin 0.102)
(uuid "b73989a4-ad2b-4544-b5db-180d47bca05d")
)
(pad "MP" thru_hole circle
(at 11 -11)
(size 3 3)
(drill 2)
(layers "*.Cu" "*.Mask")
(remove_unused_layers no)
(solder_mask_margin 0.102)
(uuid "abb9a1f6-2b7d-40a0-a47d-92cdb9b14a3c")
)
(pad "MP" thru_hole circle
(at 11 11)
(size 3 3)
(drill 2)
(layers "*.Cu" "*.Mask")
(remove_unused_layers no)
(solder_mask_margin 0.102)
(uuid "0c54fc9d-1728-4e08-82f8-71a253490e82")
)
(model "/Users/taranmittal/Documents/MITTAL1/PCB/CUSTOM LIBRARY.pretty/DM-OLED096-636/DM-OLED096-636.step"
(offset
(xyz 0 0 0)
)
(scale
(xyz 1 1 1)
)
(rotate
(xyz 90 180 180)
)
)
)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,18 @@
(fp_lib_table
(version 7)
(lib (name "ScottoKeebs_Alps")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_Alps.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_CAD")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_CAD.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_Choc")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_Choc.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_Components")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_Components.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_Cutout")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_Cutout.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_Hotswap")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_Hotswap.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_Hybrid")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_Hybrid.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_KH")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_KH.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_MCU")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_MCU.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_Miscellaneous")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_Miscellaneous.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_MX")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_MX.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_NB")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_NB.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_Scotto")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_Scotto.pretty")(options "")(descr ""))
(lib (name "ScottoKeebs_Stabilizer")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/footprints/ScottoKeebs_Stabilizer.pretty")(options "")(descr ""))
(lib (name "Library")(type "KiCad")(uri "${KIPRJMOD}/Library.pretty")(options "")(descr ""))
)

View file

@ -0,0 +1,5 @@
(sym_lib_table
(version 7)
(lib (name "Seeed_Studio_XIAO_Series")(type "KiCad")(uri "${KIPRJMOD}/OPL_Kicad_Library/Seeed Studio XIAO Series Library/Seeed_Studio_XIAO_Series.kicad_sym")(options "")(descr ""))
(lib (name "ScottoKeebs")(type "KiCad")(uri "${KIPRJMOD}/scottokeebs/Extras/ScottoKicad/symbols/ScottoKeebs.kicad_sym")(options "")(descr ""))
)

View file

@ -0,0 +1,179 @@
(version 1)
#Kicad 7
# ----------------------------------- Minimum trace width and spacing (PICK ONE) --------------------
# 2-layer, 1oz copper
(rule "Minimum Trace Width and Spacing (outer layer)"
(constraint track_width (min 0.127mm))
(constraint clearance (min 0.127mm))
(condition "A.Type == 'track'"))
# ------------------------------------------------------------------------------------------------------
# Drill/hole size - listed here to maintain order of rule application. Must not override rule set in Via hole/diameter size below.
(rule "drill hole size (mechanical)"
(constraint hole_size (min 0.15mm) (max 6.3mm)))
# ----------------------------------- Via hole/diameter size (PICK ONE) ------------------------------------
# 2-layer standard
(rule "Minimum Via Diameter and Hole Size"
(constraint hole_size (min 0.3mm))
(constraint via_diameter (min 0.5mm))
(constraint disallow buried_via)
(condition "A.Type == 'via'"))
# ----------------------------------- Drill/hole size ------------------------------------
(rule "PTH Hole Size"
(constraint hole_size (min 0.2mm) (max 6.35mm))
(condition "A.Type != 'Via' && A.isPlated()"))
(rule "Minimum Non-plated Hole Size"
(constraint hole_size (min 0.5mm))
(condition "A.Type == 'pad' && !A.isPlated()"))
(rule "Pad Size"
(constraint hole_size (min 0.5mm))
(constraint annular_width (min 0.22mm))
(condition "A.Type == 'Pad' && A.isPlated()"))
(rule "Minimum Castellated Hole Size"
(constraint hole_size (min 0.6mm))
(condition "A.Type == 'pad' && A.Fabrication_Property == 'Castellated pad'"))
(rule "Min. Plated Slot Width"
(constraint hole_size (min 0.5mm))
(condition "(A.Hole_Size_X != A.Hole_Size_Y) && A.isPlated()"))
(rule "Min. Non-Plated Slot Width"
(constraint hole_size (min 1.0mm))
(condition "(A.Hole_Size_X != A.Hole_Size_Y) && !A.isPlated()"))
# ----------------------------------- Minimum clearance ----------------------------------
(rule "hole to hole clearance (different nets)"
(constraint hole_to_hole (min 0.5mm))
(condition "A.Net != B.Net"))
(rule "via to track clearance"
(constraint hole_clearance (min 0.254mm))
(condition "A.Type == 'via' && B.Type == 'track'"))
(rule "via to via clearance (same nets)"
(constraint hole_to_hole (min 0.254mm))
(condition "A.Type == 'via' && B.Type == A.Type && A.Net == B.Net"))
(rule "pad to pad clearance (with hole, different nets)"
(constraint hole_to_hole (min 0.5mm))
(condition "A.Type == 'pad' && B.Type == A.Type && A.Net != B.Net"))
(rule "pad to pad clearance (without hole, different nets)"
(constraint clearance (min 0.127mm))
(condition "A.Type == 'Pad' && B.Type == 'Pad'"))
(rule "NPTH to Track clearance"
(constraint hole_clearance (min 0.254mm))
(condition "A.Pad_Type == 'NPTH, mechanical' && B.Type == 'track'"))
(rule "NPTH with copper around"
(constraint hole_clearance (min 0.20mm))
(condition "A.Pad_Type == 'NPTH, mechanical' && B.Type != 'track'"))
(rule "PTH to Track clearance"
(constraint hole_clearance (min 0.33mm))
(condition "A.isPlated() && A.Type != 'Via' && B.Type == 'track'"))
(rule "Pad to Track clearance"
(constraint clearance (min 0.2mm))
(condition "A.isPlated() && A.Type != 'Via' && B.Type == 'track'"))
# ----------------------------------- Board Outlines (PICK ONE) -------------------------------------
#Default Routed Edge Clearance
(rule "Trace to Outline"
(constraint edge_clearance (min 0.3mm))
(condition "A.Type == 'track'"))
# ----------------------------------- silkscreen (Kicad 7 only) --------------------------
(rule "Minimum Text"
(constraint text_thickness (min 0.15mm))
(constraint text_height (min 1mm))
(layer "?.Silkscreen"))
#JLCPCB pad to silkscreen clearance rule is actually 0.15mm, but KiCad libraries violate that slightly, so JLC will have to deal with it.
(rule "Pad to Silkscreen"
(constraint silk_clearance (min 0.14mm))
(layer outer)
(condition "A.Type == 'pad' && (B.Type == 'text' || B.Type == 'graphic')"))
# 2-layer, 1oz copper
(rule "Minimum Trace Width (outer layer)"
(constraint track_width (min 5mil))
(layer outer)
(condition "A.Type == 'track'"))
(rule "Minimum Trace Spacing (outer layer)"
(constraint clearance (min 5mil))
(layer outer)
(condition "A.Type == 'track' && B.Type == A.Type"))
(rule "Trace to Outline"
(constraint edge_clearance (min 0.3mm))
(condition "A.Type == 'track'"))
# drill/hole size
(rule "drill hole size (mechanical)"
(constraint hole_size (min 0.2mm) (max 6.3mm)))
(rule "Minimum Via Hole Size"
(constraint hole_size (min 0.2mm))
(condition "A.Type == 'via'"))
(rule "Minimum Via Diameter"
(constraint via_diameter (min 0.45mm))
(condition "A.Type == 'via'"))
(rule "PTH Hole Size"
(constraint hole_size (min 0.2mm) (max 6.35mm))
(condition "A.isPlated()"))
(rule "Minimum Non-plated Hole Size"
(constraint hole_size (min 0.5mm))
(condition "A.Type == 'pad' && !A.isPlated()"))
(rule "Minimum Castellated Hole Size"
(constraint hole_size (min 0.6mm))
(condition "A.Type == 'pad' && A.Fabrication_Property == 'Castellated pad'"))
# clearance
(rule "hole to hole clearance (different nets)"
(constraint hole_to_hole (min 0.5mm))
(condition "A.Net != B.Net"))
(rule "via to track clearance"
(constraint hole_clearance (min 0.254mm))
(condition "A.Type == 'via' && B.Type == 'track'"))
(rule "via to via clearance (same nets)"
(constraint hole_to_hole (min 0.254mm))
(condition "A.Type == 'via' && B.Type == A.Type && A.Net == B.Net"))
(rule "pad to pad clearance (with hole, different nets)"
(constraint hole_to_hole (min 0.5mm))
(condition "A.Type == 'pad' && B.Type == A.Type && A.Net != B.Net"))
(rule "pad to pad clearance (without hole, different nets)"
(constraint clearance (min 0.127mm))
(condition "A.Type == 'pad' && B.Type == A.Type && A.Net != B.Net"))
(rule "NPTH to Track clearance)"
(constraint hole_clearance (min 0.254mm))
(condition "A.Pad_Type == 'NPTH, mechanical' && B.Type == 'track'"))
(rule "PTH to Track clearance)"
(constraint hole_clearance (min 0.33mm))
(condition "A.isPlated() && B.Type == 'track'"))
(rule "Pad to Track clearance)"
(constraint clearance (min 0.2mm))
(condition "A.isPlated() && B.Type == 'track'"))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
{
"board": {
"active_layer": 0,
"active_layer_preset": "All Layers",
"auto_track_width": true,
"hidden_netclasses": [],
"hidden_nets": [],
"high_contrast_mode": 0,
"net_color_mode": 1,
"opacity": {
"images": 0.6,
"pads": 1.0,
"tracks": 1.0,
"vias": 1.0,
"zones": 0.6
},
"selection_filter": {
"dimensions": true,
"footprints": true,
"graphics": true,
"keepouts": true,
"lockedItems": false,
"otherItems": true,
"pads": true,
"text": true,
"tracks": true,
"vias": true,
"zones": true
},
"visible_items": [
0,
1,
2,
3,
4,
5,
8,
9,
10,
11,
12,
13,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
32,
33,
34,
35,
36,
39,
40
],
"visible_layers": "fffffff_ffffffff",
"zone_display_mode": 0
},
"git": {
"repo_password": "",
"repo_type": "",
"repo_username": "",
"ssh_key": ""
},
"meta": {
"filename": "woagpad.kicad_prl",
"version": 3
},
"project": {
"files": []
}
}

View file

@ -0,0 +1,592 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false,
"board_outline_line_width": 0.05,
"copper_line_width": 0.2,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.05,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": false,
"text_position": 0,
"units_format": 1
},
"fab_line_width": 0.1,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.1,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 9.4,
"height": 9.4,
"width": 9.4
},
"silk_line_width": 0.1,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.1,
"silk_text_upright": false,
"zones": {
"min_clearance": 0.5
}
},
"diff_pair_dimensions": [],
"drc_exclusions": [],
"meta": {
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint": "error",
"footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "ignore",
"hole_clearance": "error",
"hole_near_hole": "error",
"holes_co_located": "warning",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "warning",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"net_conflict": "warning",
"npth_inside_courtyard": "ignore",
"padstack": "warning",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "ignore",
"text_height": "warning",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
"track_width": "error",
"tracks_crossing": "error",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zones_intersect": "error"
},
"rules": {
"max_error": 0.005,
"min_clearance": 0.0,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.5,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.2,
"min_microvia_drill": 0.1,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.8,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.0,
"min_via_annular_width": 0.1,
"min_via_diameter": 0.5,
"solder_mask_to_copper_clearance": 0.0,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_onpadsmd": true,
"td_onroundshapesonly": false,
"td_ontrackend": false,
"td_onviapad": true
}
],
"teardrop_parameters": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [],
"tuning_pattern_settings": {
"diff_pair_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 1.0
},
"diff_pair_skew_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
},
"single_track_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
}
},
"via_dimensions": [],
"zones_allow_external_fillets": false
},
"ipc2581": {
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": ""
},
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"conflicting_netclasses": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"endpoint_off_grid": "warning",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"missing_bidi_pin": "warning",
"missing_input_pin": "warning",
"missing_power_pin": "error",
"missing_unit": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"simulation_model_issue": "ignore",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "woagpad.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2,
"via_diameter": 0.6,
"via_drill": 0.3,
"wire_width": 6
}
],
"meta": {
"version": 3
},
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"plot": "plots/",
"pos_files": "",
"specctra_dsn": "",
"step": "woagpad.step",
"svg": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"bom_export_filename": "",
"bom_fmt_presets": [],
"bom_fmt_settings": {
"field_delimiter": ",",
"keep_line_breaks": false,
"keep_tabs": false,
"name": "CSV",
"ref_delimiter": ",",
"ref_range_delimiter": "",
"string_delimiter": "\""
},
"bom_presets": [],
"bom_settings": {
"exclude_dnp": false,
"fields_ordered": [
{
"group_by": false,
"label": "Reference",
"name": "Reference",
"show": true
},
{
"group_by": true,
"label": "Value",
"name": "Value",
"show": true
},
{
"group_by": false,
"label": "Datasheet",
"name": "Datasheet",
"show": true
},
{
"group_by": false,
"label": "Footprint",
"name": "Footprint",
"show": true
},
{
"group_by": false,
"label": "Qty",
"name": "${QUANTITY}",
"show": true
},
{
"group_by": true,
"label": "DNP",
"name": "${DNP}",
"show": true
}
],
"filter_string": "",
"group_symbols": true,
"name": "Grouped By Value",
"sort_asc": true,
"sort_field": "Reference"
},
"connection_grid_size": 50.0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"operating_point_overlay_i_precision": 3,
"operating_point_overlay_i_range": "~A",
"operating_point_overlay_v_precision": 3,
"operating_point_overlay_v_range": "~V",
"overbar_offset_ratio": 1.23,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"ngspice": {
"fix_include_paths": true,
"meta": {
"version": 0
},
"model_mode": 4,
"workbook_filename": ""
},
"page_layout_descr_file": "",
"plot_directory": "",
"spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"",
"spice_model_current_sheet_as_root": true,
"spice_save_all_currents": false,
"spice_save_all_dissipations": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"648b3d94-76ed-481b-b946-3ec0ab4b1f4d",
"Root"
]
],
"text_variables": {}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,70 @@
# The Woagpad
## A macropad of all time
![Woagpad](./assets/Woagpad-Render.png)
The woagpad is a board I decided to create because a macropad
kinda just sounds fun. I really also wanted the rotary encoders
to be able to change volume and control media playback (although RMK doesn't support it yet. Eventually:tm:).
## Features
- **Rust based firmware**: Through the power of [RMK](https://haobogu.github.io/rmk), the firmware is written in 100% Rust. Crab gaming :crab:
- [VIAL](https://get.vial.today/) support OOTB
- **128x64 OLED Display**: Display whatever the hell you want*
- **2 EC11 Rotary Encoders**: Control your volume or scroll through pages with these*
- **3x3 key matrix**: Keypad, macro, media controls, whatever the hell you want. You have 9 keys to mess around with (this includes the push buttons on the rotary encoders)
*The default rmk firmware does not support OLED display or rotary encoders yet.
Once those are implemented, the firmware will be updated to support them.
Write your own firmware to take advantage of these features!
## Design
### PCB
![Schematic](./assets/Schematic.png)
Bog standard PCB Schematic for a macropad.
This is actually my first design that uses a matrix
and an OLED display so that's fun.
Also yes, 2 encoders can share a pin! Neat.
|Front|Back|
|---|---|
|![PCB Front Design](./assets/PCB-Front.png)|![PCB Back Design](./assets/PCB-Back.png)|
First PCB with actual mounting holes.
although in this case, the mounting holes are used
for mounting the top and bottom of the case.
See the case design for more details.
### Case
![Case Design](./assets/Woagpad-Construct.png)
Top integrated plate + frame. Bottom half with standoffs
for heat inserts to screw the two halves together.
Also yes, the encoder holes are slightly larger than the encoders.
I have no idea how well they'll actually fit so I decided for
more tolerance than normal. It'll be fine... right?
### BOM
- 1x PCB
- see production/gerber.zip
- 1x Case
- see production/Top.step
- see production/Bottom.step
- 7X Cherry MX Switches
- 7X DSA Keycaps
- 2X Rotary Encoders
- 9X 1N4148 Diodes
- 3X M3x5mx4mm Heatset inserts
- 3X M3x16mm Bolts
- 1x XIAO RP2040
- 1x 0.91" 128x64 OLED Display
## Extras
First time using [RMK](https://haobogu.github.io/rmk) for firmware. It was WAY easier compared to other firmware options.
Highly reccomend if you don't need additional features.

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 KiB

View file

@ -0,0 +1,9 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "probe-rs run --chip RP2040"
# runner = "elf2uf2-rs -d"
[build]
target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
[env]
DEFMT_LOG = "debug"

10
hackpads/woagpad/firmware/.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
target
*.bin
*.elf
*.hex
*.uf2
.embuild
.DS_Store

2133
hackpads/woagpad/firmware/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
[package]
name = "firmware"
version = "0.1.0"
authors = ["Haobo Gu <haobogu@outlook.com>"]
description = "Keyboard firmware written in Rust"
homepage = "https://github.com/haobogu/rmk"
repository = "https://github.com/haobogu/rmk"
readme = "../../README.md"
edition = "2021"
license = "MIT OR Apache-2.0"
[dependencies]
rmk = { version = "0.5" }
embassy-time = { version = "0.4", features = ["defmt"] }
embassy-rp = { version = "0.3", features = [
"rp2040",
"defmt",
"time-driver",
"critical-section-impl",
] }
embassy-executor = { version = "0.7", features = [
"defmt",
"arch-cortex-m",
"executor-thread",
"task-arena-size-32768",
] }
cortex-m-rt = "0.7.3"
portable-atomic = { version = "1.5", features = ["critical-section"] }
defmt = "0.3"
defmt-rtt = "0.4"
panic-probe = { version = "0.3", features = ["print-defmt"] }
embassy-futures = { version = "0.1.1", features = ["defmt"] }
# [features]
# avoid having to use --allow-multiple-definition linker flag
# on macOS with Apple Silicon at least
# default = ["rp-pico/disable-intrinsics"]
[build-dependencies]
xz2 = "0.1.7"
json = "0.12"
const-gen = "1.6"
[[bin]]
name = "firmware"
test = false
bench = false
[profile.dev]
codegen-units = 1 # better optimizations
debug = true
opt-level = 1
overflow-checks = true
lto = false
panic = 'unwind'
[profile.release]
codegen-units = 1 # better optimizations
debug = true # no overhead for bare-metal
opt-level = "z" # optimize for binary size
overflow-checks = false
lto = "fat"

View file

@ -0,0 +1,33 @@
[tasks.install-llvm-tools]
install_crate = { rustup_component_name = "llvm-tools" }
[tasks.flip-link]
install_crate = { crate_name = "flip-link", binary = "flip-link", test_arg = [
"-h",
] }
[tasks.objcopy]
install_crate = { crate_name = "cargo-binutils", binary = "cargo", test_arg = [
"objcopy",
"--help",
] }
command = "cargo"
args = ["objcopy", "--release", "--", "-O", "ihex", "firmware.hex"]
dependencies = ["install-llvm-tools", "flip-link"]
[tasks.uf2]
install_crate = { crate_name = "cargo-hex-to-uf2", binary = "cargo", test_arg = [
"hex-to-uf2",
"--help",
] }
command = "cargo"
args = [
"hex-to-uf2",
"--input-path",
"firmware.hex",
"--output-path",
"firmware.uf2",
"--family",
"rp2040",
]
dependencies = ["objcopy"]

View file

@ -0,0 +1,53 @@
# RMK
RMK is a feature-rich and easy-to-use keyboard firmware.
## Use the template
1. Install [probe-rs](https://github.com/probe-rs/probe-rs)
```shell
# Linux/macOS
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.sh | sh
# Windows
irm https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.ps1 | iex
```
2. Build the firmware
```shell
cargo build --release
```
3. Flash using debug probe
If you have a debug probe connected to your rp2040 board, flashing is quite simple: run the following command to automatically compile and flash RMK firmware to the board:
```shell
cargo run --release
```
4. (Optional) Flash using USB
If you don't have a debug probe, you can use `elf2uf2-rs` to flash your rp2040 firmware via USB. There are several additional steps you have to do:
1. Install `elf2uf2-rs`: `cargo install elf2uf2-rs`
2. Update `.cargo/config.toml`, use `elf2uf2` as the flashing tool
```diff
- runner = "probe-rs run --chip RP2040"
+ runner = "elf2uf2-rs -d"
```
3. Connect your rp2040 board holding the BOOTSEL key, ensure that rp's USB drive appears
4. Flash
```shell
cargo run --release
```
Then, you will see logs like if everything goes right:
```shell
Finished release [optimized + debuginfo] target(s) in 0.21s
Running `elf2uf2-rs -d 'target\thumbv6m-none-eabi\release\rmk-rp2040'`
Found pico uf2 disk G:\
Transfering program to pico
173.00 KB / 173.00 KB [=======================] 100.00 % 193.64 KB/s
```

View file

@ -0,0 +1,85 @@
//! This build script copies the `memory.x` file from the crate root into
//! a directory where the linker can always find it at build time.
//! For many projects this is optional, as the linker always searches the
//! project root directory -- wherever `Cargo.toml` is. However, if you
//! are using a workspace or have a more complicated build setup, this
//! build script becomes required. Additionally, by requesting that
//! Cargo re-run the build script whenever `memory.x` is changed,
//! updating `memory.x` ensures a rebuild of the application with the
//! new memory settings.
//!
//! The build script also sets the linker flags to tell it which link script to use.
use const_gen::*;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::{env, fs};
use xz2::read::XzEncoder;
fn main() {
// Generate vial config at the root of project
println!("cargo:rerun-if-changed=vial.json");
generate_vial_config();
// Put `memory.x` in our output directory and ensure it's
// on the linker search path.
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("memory.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
// By default, Cargo will re-run a build script whenever
// any file in the project changes. By specifying `memory.x`
// here, we ensure the build script is only re-run when
// `memory.x` is changed.
println!("cargo:rerun-if-changed=memory.x");
println!("cargo:rerun-if-changed=keyboard.toml");
// Specify linker arguments.
// `--nmagic` is required if memory section addresses are not aligned to 0x10000,
// for example the FLASH and RAM sections in your `memory.x`.
// See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
println!("cargo:rustc-link-arg=--nmagic");
// Set the linker script to the one provided by cortex-m-rt.
println!("cargo:rustc-link-arg=-Tlink.x");
// Set the linker script of the defmt
println!("cargo:rustc-link-arg=-Tdefmt.x");
println!("cargo:rustc-linker=flip-link");
}
fn generate_vial_config() {
// Generated vial config file
let out_file = Path::new(&env::var_os("OUT_DIR").unwrap()).join("config_generated.rs");
let p = Path::new("vial.json");
let mut content = String::new();
match File::open(p) {
Ok(mut file) => {
file.read_to_string(&mut content)
.expect("Cannot read vial.json");
}
Err(e) => println!("Cannot find vial.json {:?}: {}", p, e),
};
let vial_cfg = json::stringify(json::parse(&content).unwrap());
let mut keyboard_def_compressed: Vec<u8> = Vec::new();
XzEncoder::new(vial_cfg.as_bytes(), 6)
.read_to_end(&mut keyboard_def_compressed)
.unwrap();
let keyboard_id: Vec<u8> = vec![0xB9, 0xBC, 0x09, 0xB2, 0x9D, 0x37, 0x4C, 0xEA];
let const_declarations = [
const_declaration!(pub VIAL_KEYBOARD_DEF = keyboard_def_compressed),
const_declaration!(pub VIAL_KEYBOARD_ID = keyboard_id),
]
.join("\n");
fs::write(out_file, const_declarations).unwrap();
}

View file

@ -0,0 +1,34 @@
[
[
"0,0\n\n\n\n\n\n\n\n\ne",
{
"x": 1
},
"1,0\n\n\n\n\n\n\n\n\ne"
],
[
"0,1\n\n\n\n\n\n\n\n\ne",
{
"x": 1
},
"1,1\n\n\n\n\n\n\n\n\ne"
],
[
{
"y": 0.25
},
"0,0",
"0,1",
"0,2"
],
[
"1,0",
"1,1",
"1,2"
],
[
"2,0",
"2,1",
"2,2"
]
]

View file

@ -0,0 +1,48 @@
[keyboard]
name = "firmware"
product_name = "firmware"
vendor_id = 0x4c4b
product_id = 0x4643
manufacturer = "rmk"
chip = "rp2040"
[matrix]
# Input and output pins are mandatory
input_pins = ["PIN_6", "PIN_7", "PIN_8", "PIN_9"]
output_pins = ["PIN_19", "PIN_20", "PIN_21"]
# WARNING: Currently row2col/col2row is set in RMK's feature gate, configs here do nothing actually
# row2col = true
[layout]
rows = 4
cols = 3
layers = 2
keymap = [
[
["A", "B", "C"],
["Kc1", "Kc2", "Kc3"],
["LCtrl", "MO(1)", "LShift"],
["OSL(1)", "LT(2, Kc9)", "LM(1, LShift | LGui)"]
],
[
["_", "TT(1)", "TG(2)"],
["_", "_", "_"],
["_", "_", "_"],
["_", "_", "_"]
],
]
[light]
# All light pins are high-active by default, uncomment if you want it to be low-active
# capslock.pin = "PB2"
# capslock.low_active = true
# scrolllock.pin = "PA3"
# scrolllock.low_active = true
# Just ignore if no light pin is used for it
# numslock.pin = "PA5"
# numslock.low_active = true
[storage]
# Storage feature is enabled by default
# enabled = false

View file

@ -0,0 +1,15 @@
MEMORY {
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}
EXTERN(BOOT2_FIRMWARE)
SECTIONS {
/* ### Boot loader */
.boot2 ORIGIN(BOOT2) :
{
KEEP(*(.boot2));
} > BOOT2
} INSERT BEFORE .text;

View file

@ -0,0 +1,6 @@
source [find interface/cmsis-dap.cfg]
transport select swd
source [find target/rp2040.cfg]
adapter speed 10000

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,6 @@
[toolchain]
channel = "stable"
components = ["rust-src", "rustfmt", "llvm-tools"]
targets = [
"thumbv6m-none-eabi",
]

View file

@ -0,0 +1,704 @@
#!/usr/bin/env python3
import sys
import struct
import subprocess
import re
import os
import os.path
import argparse
import json
from time import sleep
chip_families = [
{
"id": "0x16573617",
"short_name": "ATMEGA32",
"description": "Microchip (Atmel) ATmega32"
},
{
"id": "0x1851780a",
"short_name": "SAML21",
"description": "Microchip (Atmel) SAML21"
},
{
"id": "0x1b57745f",
"short_name": "NRF52",
"description": "Nordic NRF52"
},
{
"id": "0x1c5f21b0",
"short_name": "ESP32",
"description": "ESP32"
},
{
"id": "0x1e1f432d",
"short_name": "STM32L1",
"description": "ST STM32L1xx"
},
{
"id": "0x202e3a91",
"short_name": "STM32L0",
"description": "ST STM32L0xx"
},
{
"id": "0x21460ff0",
"short_name": "STM32WL",
"description": "ST STM32WLxx"
},
{
"id": "0x22e0d6fc",
"short_name": "RTL8710B",
"description": "Realtek AmebaZ RTL8710B"
},
{
"id": "0x2abc77ec",
"short_name": "LPC55",
"description": "NXP LPC55xx"
},
{
"id": "0x300f5633",
"short_name": "STM32G0",
"description": "ST STM32G0xx"
},
{
"id": "0x31d228c6",
"short_name": "GD32F350",
"description": "GD32F350"
},
{
"id": "0x3379CFE2",
"short_name": "RTL8720D",
"description": "Realtek AmebaD RTL8720D"
},
{
"id": "0x04240bdf",
"short_name": "STM32L5",
"description": "ST STM32L5xx"
},
{
"id": "0x4c71240a",
"short_name": "STM32G4",
"description": "ST STM32G4xx"
},
{
"id": "0x4fb2d5bd",
"short_name": "MIMXRT10XX",
"description": "NXP i.MX RT10XX"
},
{
"id": "0x51e903a8",
"short_name": "XR809",
"description": "Xradiotech 809"
},
{
"id": "0x53b80f00",
"short_name": "STM32F7",
"description": "ST STM32F7xx"
},
{
"id": "0x55114460",
"short_name": "SAMD51",
"description": "Microchip (Atmel) SAMD51"
},
{
"id": "0x57755a57",
"short_name": "STM32F4",
"description": "ST STM32F4xx"
},
{
"id": "0x5a18069b",
"short_name": "FX2",
"description": "Cypress FX2"
},
{
"id": "0x5d1a0a2e",
"short_name": "STM32F2",
"description": "ST STM32F2xx"
},
{
"id": "0x5ee21072",
"short_name": "STM32F1",
"description": "ST STM32F103"
},
{
"id": "0x621e937a",
"short_name": "NRF52833",
"description": "Nordic NRF52833"
},
{
"id": "0x647824b6",
"short_name": "STM32F0",
"description": "ST STM32F0xx"
},
{
"id": "0x675a40b0",
"short_name": "BK7231U",
"description": "Beken 7231U/7231T"
},
{
"id": "0x68ed2b88",
"short_name": "SAMD21",
"description": "Microchip (Atmel) SAMD21"
},
{
"id": "0x6a82cc42",
"short_name": "BK7251",
"description": "Beken 7251/7252"
},
{
"id": "0x6b846188",
"short_name": "STM32F3",
"description": "ST STM32F3xx"
},
{
"id": "0x6d0922fa",
"short_name": "STM32F407",
"description": "ST STM32F407"
},
{
"id": "0x6db66082",
"short_name": "STM32H7",
"description": "ST STM32H7xx"
},
{
"id": "0x70d16653",
"short_name": "STM32WB",
"description": "ST STM32WBxx"
},
{
"id": "0x7b3ef230",
"short_name": "BK7231N",
"description": "Beken 7231N"
},
{
"id": "0x7eab61ed",
"short_name": "ESP8266",
"description": "ESP8266"
},
{
"id": "0x7f83e793",
"short_name": "KL32L2",
"description": "NXP KL32L2x"
},
{
"id": "0x8fb060fe",
"short_name": "STM32F407VG",
"description": "ST STM32F407VG"
},
{
"id": "0x9fffd543",
"short_name": "RTL8710A",
"description": "Realtek Ameba1 RTL8710A"
},
{
"id": "0xada52840",
"short_name": "NRF52840",
"description": "Nordic NRF52840"
},
{
"id": "0xbfdd4eee",
"short_name": "ESP32S2",
"description": "ESP32-S2"
},
{
"id": "0xc47e5767",
"short_name": "ESP32S3",
"description": "ESP32-S3"
},
{
"id": "0xd42ba06c",
"short_name": "ESP32C3",
"description": "ESP32-C3"
},
{
"id": "0x2b88d29c",
"short_name": "ESP32C2",
"description": "ESP32-C2"
},
{
"id": "0x332726f6",
"short_name": "ESP32H2",
"description": "ESP32-H2"
},
{
"id": "0x540ddf62",
"short_name": "ESP32C6",
"description": "ESP32-C6"
},
{
"id": "0x3d308e94",
"short_name": "ESP32P4",
"description": "ESP32-P4"
},
{
"id": "0xf71c0343",
"short_name": "ESP32C5",
"description": "ESP32-C5"
},
{
"id": "0x77d850c4",
"short_name": "ESP32C61",
"description": "ESP32-C61"
},
{
"id": "0xde1270b7",
"short_name": "BL602",
"description": "Boufallo 602"
},
{
"id": "0xe08f7564",
"short_name": "RTL8720C",
"description": "Realtek AmebaZ2 RTL8720C"
},
{
"id": "0xe48bff56",
"short_name": "RP2040",
"description": "Raspberry Pi RP2040"
},
{
"id": "0xe48bff57",
"short_name": "RP2XXX_ABSOLUTE",
"description": "Raspberry Pi Microcontrollers: Absolute (unpartitioned) download"
},
{
"id": "0xe48bff58",
"short_name": "RP2XXX_DATA",
"description": "Raspberry Pi Microcontrollers: Data partition download"
},
{
"id": "0xe48bff59",
"short_name": "RP2350_ARM_S",
"description": "Raspberry Pi RP2350, Secure Arm image"
},
{
"id": "0xe48bff5a",
"short_name": "RP2350_RISCV",
"description": "Raspberry Pi RP2350, RISC-V image"
},
{
"id": "0xe48bff5b",
"short_name": "RP2350_ARM_NS",
"description": "Raspberry Pi RP2350, Non-secure Arm image"
},
{
"id": "0x00ff6919",
"short_name": "STM32L4",
"description": "ST STM32L4xx"
},
{
"id": "0x9af03e33",
"short_name": "GD32VF103",
"description": "GigaDevice GD32VF103"
},
{
"id": "0x4f6ace52",
"short_name": "CSK4",
"description": "LISTENAI CSK300x/400x"
},
{
"id": "0x6e7348a8",
"short_name": "CSK6",
"description": "LISTENAI CSK60xx"
},
{
"id": "0x11de784a",
"short_name": "M0SENSE",
"description": "M0SENSE BL702"
},
{
"id": "0x4b684d71",
"short_name": "MaixPlay-U4",
"description": "Sipeed MaixPlay-U4(BL618)"
},
{
"id": "0x9517422f",
"short_name": "RZA1LU",
"description": "Renesas RZ/A1LU (R7S7210xx)"
},
{
"id": "0x2dc309c5",
"short_name": "STM32F411xE",
"description": "ST STM32F411xE"
},
{
"id": "0x06d1097b",
"short_name": "STM32F411xC",
"description": "ST STM32F411xC"
},
{
"id": "0x72721d4e",
"short_name": "NRF52832xxAA",
"description": "Nordic NRF52832xxAA"
},
{
"id": "0x6f752678",
"short_name": "NRF52832xxAB",
"description": "Nordic NRF52832xxAB"
},
{
"id": "0xa0c97b8e",
"short_name": "AT32F415",
"description": "ArteryTek AT32F415"
},
{
"id": "0x699b62ec",
"short_name": "CH32V",
"description": "WCH CH32V2xx and CH32V3xx"
},
{
"id": "0x7be8976d",
"short_name": "RA4M1",
"description": "Renesas RA4M1"
}
]
UF2_MAGIC_START0 = 0x0A324655 # "UF2\n"
UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected
UF2_MAGIC_END = 0x0AB16F30 # Ditto
INFO_FILE = "/INFO_UF2.TXT"
appstartaddr = 0x2000
familyid = 0x0
def is_uf2(buf):
w = struct.unpack("<II", buf[0:8])
return w[0] == UF2_MAGIC_START0 and w[1] == UF2_MAGIC_START1
def is_hex(buf):
try:
w = buf[0:30].decode("utf-8")
except UnicodeDecodeError:
return False
if w[0] == ':' and re.match(rb"^[:0-9a-fA-F\r\n]+$", buf):
return True
return False
def convert_from_uf2(buf):
global appstartaddr
global familyid
numblocks = len(buf) // 512
curraddr = None
currfamilyid = None
families_found = {}
prev_flag = None
all_flags_same = True
outp = []
for blockno in range(numblocks):
ptr = blockno * 512
block = buf[ptr:ptr + 512]
hd = struct.unpack(b"<IIIIIIII", block[0:32])
if hd[0] != UF2_MAGIC_START0 or hd[1] != UF2_MAGIC_START1:
print("Skipping block at " + ptr + "; bad magic")
continue
if hd[2] & 1:
# NO-flash flag set; skip block
continue
datalen = hd[4]
if datalen > 476:
assert False, "Invalid UF2 data size at " + ptr
newaddr = hd[3]
if (hd[2] & 0x2000) and (currfamilyid == None):
currfamilyid = hd[7]
if curraddr == None or ((hd[2] & 0x2000) and hd[7] != currfamilyid):
currfamilyid = hd[7]
curraddr = newaddr
if familyid == 0x0 or familyid == hd[7]:
appstartaddr = newaddr
padding = newaddr - curraddr
if padding < 0:
assert False, "Block out of order at " + ptr
if padding > 10*1024*1024:
assert False, "More than 10M of padding needed at " + ptr
if padding % 4 != 0:
assert False, "Non-word padding size at " + ptr
while padding > 0:
padding -= 4
outp.append(b"\x00\x00\x00\x00")
if familyid == 0x0 or ((hd[2] & 0x2000) and familyid == hd[7]):
outp.append(block[32 : 32 + datalen])
curraddr = newaddr + datalen
if hd[2] & 0x2000:
if hd[7] in families_found.keys():
if families_found[hd[7]] > newaddr:
families_found[hd[7]] = newaddr
else:
families_found[hd[7]] = newaddr
if prev_flag == None:
prev_flag = hd[2]
if prev_flag != hd[2]:
all_flags_same = False
if blockno == (numblocks - 1):
print("--- UF2 File Header Info ---")
families = load_families()
for family_hex in families_found.keys():
family_short_name = ""
for name, value in families.items():
if value == family_hex:
family_short_name = name
print("Family ID is {:s}, hex value is 0x{:08x}".format(family_short_name,family_hex))
print("Target Address is 0x{:08x}".format(families_found[family_hex]))
if all_flags_same:
print("All block flag values consistent, 0x{:04x}".format(hd[2]))
else:
print("Flags were not all the same")
print("----------------------------")
if len(families_found) > 1 and familyid == 0x0:
outp = []
appstartaddr = 0x0
return b"".join(outp)
def convert_to_carray(file_content):
outp = "const unsigned long bindata_len = %d;\n" % len(file_content)
outp += "const unsigned char bindata[] __attribute__((aligned(16))) = {"
for i in range(len(file_content)):
if i % 16 == 0:
outp += "\n"
outp += "0x%02x, " % file_content[i]
outp += "\n};\n"
return bytes(outp, "utf-8")
def convert_to_uf2(file_content):
global familyid
datapadding = b""
while len(datapadding) < 512 - 256 - 32 - 4:
datapadding += b"\x00\x00\x00\x00"
numblocks = (len(file_content) + 255) // 256
outp = []
for blockno in range(numblocks):
ptr = 256 * blockno
chunk = file_content[ptr:ptr + 256]
flags = 0x0
if familyid:
flags |= 0x2000
hd = struct.pack(b"<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
flags, ptr + appstartaddr, 256, blockno, numblocks, familyid)
while len(chunk) < 256:
chunk += b"\x00"
block = hd + chunk + datapadding + struct.pack(b"<I", UF2_MAGIC_END)
assert len(block) == 512
outp.append(block)
return b"".join(outp)
class Block:
def __init__(self, addr):
self.addr = addr
self.bytes = bytearray(256)
def encode(self, blockno, numblocks):
global familyid
flags = 0x0
if familyid:
flags |= 0x2000
hd = struct.pack("<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
flags, self.addr, 256, blockno, numblocks, familyid)
hd += self.bytes[0:256]
while len(hd) < 512 - 4:
hd += b"\x00"
hd += struct.pack("<I", UF2_MAGIC_END)
return hd
def convert_from_hex_to_uf2(buf):
global appstartaddr
appstartaddr = None
upper = 0
currblock = None
blocks = []
for line in buf.split('\n'):
if line[0] != ":":
continue
i = 1
rec = []
while i < len(line) - 1:
rec.append(int(line[i:i+2], 16))
i += 2
tp = rec[3]
if tp == 4:
upper = ((rec[4] << 8) | rec[5]) << 16
elif tp == 2:
upper = ((rec[4] << 8) | rec[5]) << 4
elif tp == 1:
break
elif tp == 0:
addr = upper + ((rec[1] << 8) | rec[2])
if appstartaddr == None:
appstartaddr = addr
i = 4
while i < len(rec) - 1:
if not currblock or currblock.addr & ~0xff != addr & ~0xff:
currblock = Block(addr & ~0xff)
blocks.append(currblock)
currblock.bytes[addr & 0xff] = rec[i]
addr += 1
i += 1
numblocks = len(blocks)
resfile = b""
for i in range(0, numblocks):
resfile += blocks[i].encode(i, numblocks)
return resfile
def to_str(b):
return b.decode("utf-8")
def get_drives():
drives = []
if sys.platform == "win32":
r = subprocess.check_output(["wmic", "PATH", "Win32_LogicalDisk",
"get", "DeviceID,", "VolumeName,",
"FileSystem,", "DriveType"])
for line in to_str(r).split('\n'):
words = re.split(r'\s+', line)
if len(words) >= 3 and words[1] == "2" and words[2] == "FAT":
drives.append(words[0])
else:
searchpaths = ["/media"]
if sys.platform == "darwin":
searchpaths = ["/Volumes"]
elif sys.platform == "linux":
searchpaths += ["/media/" + os.environ["USER"], '/run/media/' + os.environ["USER"]]
for rootpath in searchpaths:
if os.path.isdir(rootpath):
for d in os.listdir(rootpath):
if os.path.isdir(rootpath):
drives.append(os.path.join(rootpath, d))
def has_info(d):
try:
return os.path.isfile(d + INFO_FILE)
except:
return False
return list(filter(has_info, drives))
def board_id(path):
with open(path + INFO_FILE, mode='r') as file:
file_content = file.read()
return re.search(r"Board-ID: ([^\r\n]*)", file_content).group(1)
def list_drives():
for d in get_drives():
print(d, board_id(d))
def write_file(name, buf):
with open(name, "wb") as f:
f.write(buf)
print("Wrote %d bytes to %s" % (len(buf), name))
def load_families():
# The expectation is that the `uf2families.json` file is in the same
# directory as this script. Make a path that works using `__file__`
# which contains the full path to this script.
# filename = "uf2families.json"
# pathname = os.path.join(os.path.dirname(os.path.abspath(__file__)), filename)
# with open(pathname) as f:
# chip_families = json.load(f)
families = {}
for family in chip_families:
families[family["short_name"]] = int(family["id"], 0)
return families
def main():
global appstartaddr, familyid
def error(msg):
print(msg, file=sys.stderr)
sys.exit(1)
parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.')
parser.add_argument('input', metavar='INPUT', type=str, nargs='?',
help='input file (HEX, BIN or UF2)')
parser.add_argument('-b', '--base', dest='base', type=str,
default="0x2000",
help='set base address of application for BIN format (default: 0x2000)')
parser.add_argument('-f', '--family', dest='family', type=str,
default="0x0",
help='specify familyID - number or name (default: 0x0)')
parser.add_argument('-o', '--output', metavar="FILE", dest='output', type=str,
help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible')
parser.add_argument('-d', '--device', dest="device_path",
help='select a device path to flash')
parser.add_argument('-l', '--list', action='store_true',
help='list connected devices')
parser.add_argument('-c', '--convert', action='store_true',
help='do not flash, just convert')
parser.add_argument('-D', '--deploy', action='store_true',
help='just flash, do not convert')
parser.add_argument('-w', '--wait', action='store_true',
help='wait for device to flash')
parser.add_argument('-C', '--carray', action='store_true',
help='convert binary file to a C array, not UF2')
parser.add_argument('-i', '--info', action='store_true',
help='display header information from UF2, do not convert')
args = parser.parse_args()
appstartaddr = int(args.base, 0)
families = load_families()
if args.family.upper() in families:
familyid = families[args.family.upper()]
else:
try:
familyid = int(args.family, 0)
except ValueError:
error("Family ID needs to be a number or one of: " + ", ".join(families.keys()))
if args.list:
list_drives()
else:
if not args.input:
error("Need input file")
with open(args.input, mode='rb') as f:
inpbuf = f.read()
from_uf2 = is_uf2(inpbuf)
ext = "uf2"
if args.deploy:
outbuf = inpbuf
elif from_uf2 and not args.info:
outbuf = convert_from_uf2(inpbuf)
ext = "bin"
elif from_uf2 and args.info:
outbuf = ""
convert_from_uf2(inpbuf)
elif is_hex(inpbuf):
outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8"))
elif args.carray:
outbuf = convert_to_carray(inpbuf)
ext = "h"
else:
outbuf = convert_to_uf2(inpbuf)
if not args.deploy and not args.info:
print("Converted to %s, output size: %d, start address: 0x%x" %
(ext, len(outbuf), appstartaddr))
if args.convert or ext != "uf2":
if args.output == None:
args.output = "flash." + ext
if args.output:
write_file(args.output, outbuf)
if ext == "uf2" and not args.convert and not args.info:
drives = get_drives()
if len(drives) == 0:
if args.wait:
print("Waiting for drive to deploy...")
while len(drives) == 0:
sleep(0.1)
drives = get_drives()
elif not args.output:
error("No drive to deploy.")
for d in drives:
print("Flashing %s (%s)" % (d, board_id(d)))
write_file(d + "/NEW.UF2", outbuf)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,35 @@
use rmk::action::KeyAction;
use rmk::{a, k, layer, mo};
pub(crate) const COL: usize = 3;
pub(crate) const ROW: usize = 3;
pub(crate) const NUM_LAYER: usize = 2;
pub(crate) const NUM_ENCODER: usize = 2;
#[rustfmt::skip]
pub fn get_default_keymap() -> [[[KeyAction; COL]; ROW]; NUM_LAYER] {
[
layer!([
[k!(MediaPrevTrack), k!(MediaPlayPause), k!(MediaNextTrack)],
[k!(Kp4), k!(LShift), k!(Kp6)],
[mo!(1), k!(Kp2), k!(Kp3)]
]),
layer!([
[k!(Kp7), k!(Kp8), k!(Kp9)],
[k!(Kp4), k!(Kp5), k!(Kp6)],
[mo!(0), k!(SecureUnlock), k!(Bootloader)]
]),
]
}
pub fn get_default_encoder_map() -> [[(KeyAction, KeyAction); NUM_ENCODER]; NUM_LAYER] {
[
[
(k!(KbVolumeUp), k!(KbVolumeDown)),
(k!(KbVolumeUp), k!(KbVolumeDown)),
],
[
(k!(KbVolumeUp), k!(KbVolumeDown)),
(k!(KbVolumeUp), k!(KbVolumeDown)),
],
]
}

View file

@ -0,0 +1,12 @@
macro_rules! config_matrix_pins_rp {
(peripherals: $p:ident, input: [$($in_pin:ident), *], output: [$($out_pin:ident), +]) => {
{
let mut output_pins = [$(Output::new(AnyPin::from($p.$out_pin), embassy_rp::gpio::Level::Low)), +];
let input_pins = [$(Input::new(AnyPin::from($p.$in_pin), embassy_rp::gpio::Pull::Down)), +];
output_pins.iter_mut().for_each(|p| {
p.set_low();
});
(input_pins, output_pins)
}
};
}

View file

@ -0,0 +1,94 @@
#![no_main]
#![no_std]
#[macro_use]
mod keymap;
#[macro_use]
mod macros;
mod vial;
use defmt::*;
use defmt_rtt as _;
use embassy_executor::Spawner;
use embassy_rp::{
bind_interrupts,
flash::{Async, Flash},
gpio::{AnyPin, Input, Output},
peripherals::USB,
usb::{Driver, InterruptHandler},
Peripheral,
};
// use embassy_rp::flash::Blocking;
use panic_probe as _;
use rmk::{
config::{KeyboardUsbConfig, RmkConfig, VialConfig},
input_device::{rotary_encoder::RotaryEncoder, InputDevice},
run_devices, run_rmk, run_rmk_with_async_flash,
};
use vial::{VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID};
bind_interrupts!(struct Irqs {
USBCTRL_IRQ => InterruptHandler<USB>;
});
const FLASH_SIZE: usize = 2 * 1024 * 1024;
#[embassy_executor::main]
async fn main(spawner: Spawner) {
info!("RMK start!");
// Initialize peripherals
let p = embassy_rp::init(Default::default());
// Create the usb driver, from the HAL
let driver = Driver::new(p.USB, Irqs);
// Pin config
let (input_pins, output_pins) = config_matrix_pins_rp!(peripherals: p, input: [PIN_2, PIN_29, PIN_27], output: [PIN_28, PIN_0, PIN_1]);
// Use internal flash to emulate eeprom
// Both blocking and async flash are support, use different API
// let flash = Flash::<_, Blocking, FLASH_SIZE>::new_blocking(p.FLASH);
let flash = Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0);
let keyboard_usb_config = KeyboardUsbConfig {
vid: 0x4c4b,
pid: 0x4643,
manufacturer: "woagpad",
product_name: "woagpad",
serial_number: "vial:f64c2b3c:000001",
};
let vial_config = VialConfig::new(VIAL_KEYBOARD_ID, VIAL_KEYBOARD_DEF);
let keyboard_config = RmkConfig {
usb_config: keyboard_usb_config,
vial_config,
..Default::default()
};
let mut pin_4 = AnyPin::from(p.PIN_4).into_ref();
let pin_shared = Input::new(&mut pin_4, embassy_rp::gpio::Pull::Up);
let pin_left_b = Input::new(AnyPin::from(p.PIN_3), embassy_rp::gpio::Pull::Up);
let pin_right_b = Input::new(AnyPin::from(p.PIN_26), embassy_rp::gpio::Pull::Up);
let mut left_encoder = RotaryEncoder::new(pin_shared, pin_left_b, 0);
// TODO: Implement right encoder (currently, the pin cannot be shared like this)
// let mut right_encoder = RotaryEncoder::new(pin_shared, pin_right_b, 1);
// Start serving
// Use `run_rmk` for blocking flash
embassy_futures::join::join(
run_rmk_with_async_flash(
input_pins,
output_pins,
driver,
flash,
&mut keymap::get_default_keymap(),
keyboard_config,
spawner,
),
// note: encoders aren't implemented yet, so this does basically nothing for now /shrug
run_devices!(left_encoder),
// run_devices!(left_encoder, right_encoder),
)
.await;
}

View file

@ -0,0 +1,28 @@
// Vial config is automatically generated by `build.rs`, according to `vial.json`
// Please put `vial.json` at your project's root
include!(concat!(env!("OUT_DIR"), "/config_generated.rs"));
// Or you can manually generate vial config then put here
// pub const VIAL_KEYBOARD_ID: &[u8; 8] = &[0xB9, 0xBC, 0x09, 0xB2, 0x9D, 0x37, 0x4C, 0xEA];
// pub const VIAL_KEYBOARD_DEF: &[u8; 308] = &[
// 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x04, 0xE6, 0xD6, 0xB4, 0x46, 0x02, 0x00, 0x21, 0x01,
// 0x16, 0x00, 0x00, 0x00, 0x74, 0x2F, 0xE5, 0xA3, 0xE0, 0x01, 0x58, 0x00, 0xF1, 0x5D, 0x00, 0x3D,
// 0x88, 0x89, 0xC6, 0x54, 0x36, 0xC3, 0x17, 0x4F, 0xE4, 0xE2, 0x11, 0x2F, 0x22, 0xB0, 0xBC, 0xC8,
// 0x21, 0x18, 0x12, 0x8B, 0x06, 0x39, 0x42, 0xED, 0x2D, 0x7A, 0x5C, 0xC0, 0x20, 0x95, 0xFA, 0x59,
// 0xBD, 0x04, 0x61, 0xF7, 0xDE, 0x2F, 0xD2, 0xFB, 0x8E, 0xAD, 0x8E, 0xE5, 0x16, 0x4E, 0xEA, 0x09,
// 0xC7, 0x59, 0xDC, 0x04, 0x50, 0xB5, 0x7A, 0x56, 0x03, 0xA4, 0x7C, 0xE2, 0xFE, 0x87, 0x69, 0xA2,
// 0xA1, 0xF1, 0xFC, 0xBB, 0xF8, 0x7D, 0xD8, 0x5F, 0x6A, 0x39, 0xB4, 0xC9, 0x00, 0xE8, 0x52, 0xD3,
// 0xEE, 0x5C, 0x59, 0x88, 0x1E, 0x19, 0x66, 0x17, 0x5D, 0xF6, 0xD2, 0x28, 0x0B, 0xC9, 0xB8, 0x38,
// 0x43, 0x9A, 0x38, 0x26, 0x8C, 0x45, 0xB1, 0x9C, 0xE5, 0x1B, 0x50, 0xF5, 0x71, 0x7F, 0x3A, 0xB4,
// 0xE9, 0xB5, 0x2F, 0xA9, 0xEA, 0xE3, 0xC8, 0xAC, 0x3F, 0x77, 0x37, 0x28, 0xA3, 0x4E, 0xC7, 0x14,
// 0xE4, 0xCF, 0x31, 0xCB, 0x33, 0x11, 0x3F, 0x27, 0x9D, 0xFB, 0x5C, 0x61, 0x96, 0xFE, 0x27, 0x7B,
// 0x04, 0x13, 0x1F, 0xEC, 0xD6, 0x57, 0xD2, 0x32, 0xB8, 0x00, 0x4E, 0x21, 0x32, 0x79, 0xA9, 0x09,
// 0x45, 0xCD, 0x11, 0x6F, 0xF9, 0x37, 0xFB, 0x57, 0xF7, 0x28, 0xC3, 0xAF, 0x00, 0x0F, 0xF3, 0xB2,
// 0x1F, 0xC3, 0x7C, 0x84, 0xA0, 0xF0, 0x09, 0xEE, 0x49, 0x99, 0x39, 0xC2, 0x69, 0x4A, 0xFE, 0x38,
// 0xFE, 0xE7, 0x80, 0xCA, 0x37, 0x46, 0x7B, 0xC9, 0xF4, 0x39, 0x7B, 0x30, 0x0E, 0x22, 0xA6, 0xD3,
// 0x18, 0x1B, 0xA7, 0x70, 0xB9, 0x14, 0x91, 0x13, 0xC2, 0x5F, 0x02, 0xD1, 0x1A, 0x62, 0x6B, 0xC6,
// 0xFC, 0xD3, 0x18, 0xC0, 0x62, 0xA5, 0xEA, 0xD0, 0xDF, 0x18, 0xDD, 0xD3, 0x53, 0x63, 0x11, 0x08,
// 0x00, 0x00, 0x00, 0x00, 0xF5, 0x5B, 0x73, 0xB4, 0xF2, 0x19, 0x3D, 0xF2, 0x00, 0x01, 0x8D, 0x02,
// 0xD9, 0x02, 0x00, 0x00, 0xC6, 0xA2, 0x63, 0x43, 0xB1, 0xC4, 0x67, 0xFB, 0x02, 0x00, 0x00, 0x00,
// 0x00, 0x04, 0x59, 0x5A,
// ];

View file

@ -0,0 +1,38 @@
{
"name": "firmware",
"vendorId": "0x4C4B",
"productId": "0x4643",
"lighting": "none",
"matrix": {
"rows": 3,
"cols": 3
},
"layouts": {
"keymap": [
[
"0,0\n\n\n\n\n\n\n\n\ne",
{
"x": 1
},
"1,0\n\n\n\n\n\n\n\n\ne"
],
[
"0,1\n\n\n\n\n\n\n\n\ne",
{
"x": 1
},
"1,1\n\n\n\n\n\n\n\n\ne"
],
[
{
"y": 0.25
},
"0,0",
"0,1",
"0,2"
],
["1,0", "1,1", "1,2"],
["2,0", "2,1", "2,2"]
]
}
}

82
hackpads/woagpad/flake.lock generated Normal file
View file

@ -0,0 +1,82 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1739834344,
"narHash": "sha256-PUAcU3YlKNFYrBBHkqshO4wRfMunzhMTEIH1dyhjTtk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f0295845e58ada369322524631821b01c0db13a7",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1739845646,
"narHash": "sha256-UGQVBU/yDn6u0kAE4z1PYrOaaf3wl+gAAv5rui2TkFQ=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "ab2cd2b8b25ab3f65b8ce4aa701a6d69fbb0210f",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View file

@ -0,0 +1,34 @@
{
description = "Cross compiling a rust program using rust-overlay";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { nixpkgs, flake-utils, rust-overlay, ... }:
flake-utils.lib.eachDefaultSystem (localSystem:
let
pkgs = import nixpkgs {
inherit localSystem;
overlays = [ (import rust-overlay) ];
};
toolchain = pkgs.rust-bin.stable.latest.default.override {
extensions = ["rust-analyzer" "rust-src" "rustfmt" "llvm-tools"];
targets = ["thumbv6m-none-eabi"];
};
in
{
devShells.default = pkgs.mkShell {
buildInputs = [ toolchain pkgs.cargo-binstall pkgs.alejandra pkgs.flip-link pkgs.cargo-make pkgs.probe-rs pkgs.nixd pkgs.pkg-config pkgs.openssl ];
};
});
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
Production files for [hackpad](https://hackpad.hackclub.com)!

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.