# Ergogen config for the eepyBoard
#
# Reference information:
# - Keycap size (FK MBK keycaps): 17.5mm x 16.5mm

# Metadata
meta:
  # Required version of Ergogen
  engine: "4.1.0"
  # Version of the board
  version: "1.0"
  author: binaryDiv

# Define units and default values used throughout this file
units:
  # Redefine choc units (keycap size + 1.5mm clearance)
  cx: 19
  cy: 18

  # Size of keycaps
  kcx: 17.5
  kcy: 16.5

  # Size of key rectangle in demo view (keycap size)
  $default_width: 17.5
  $default_height: 16.5

  # Actual spacing of keys
  $default_spread: cx
  $default_padding: cy

  # Vertical offset between function keys and primary keys
  function_zone_offset: 3

# Define the points (i.e. keys)
points:
  key:
    # Tag all points as "is_key" unless overwritten
    tags: [ is_key ]

  zones:
    # Primary keyboard zone
    primary:
      # Set anchor to fix placement on KiCad sheet
      anchor:
        shift: [ 100, -150 ]

      # Key rows (from bottom to top)
      rows:
        # Modifier row (Ctrl, ..., but excluding the thumb keys)
        mods:
          row_net: GP17
          led_previous_key: "{{zone.name}}_{{neighbor_col_left}}_{{row}}"
          tags: [ is_key, flip_led ]

        # Bottom letter row (Shift, ZXCV...)
        bottom:
          row_net: GP16
          led_previous_key: "{{zone.name}}_{{neighbor_col_right}}_{{row}}"

        # Middle/home letter row (Caps Lock, ASDFG...)
        home:
          row_net: GP15
          led_previous_key: "{{zone.name}}_{{neighbor_col_left}}_{{row}}"
          tags: [ is_key, flip_led ]

        # Top letter row (Tab, QWERT...)
        top:
          row_net: GP14
          led_previous_key: "{{zone.name}}_{{neighbor_col_right}}_{{row}}"

        # Number row (`, 12345...)
        numbers:
          row_net: GP13
          led_previous_key: "{{zone.name}}_{{neighbor_col_left}}_{{row}}"
          tags: [ is_key, flip_led ]

      # Key columns (from left to right)
      columns:
        # Left-most column (`, Tab, Caps Lock, Shift, Ctrl)
        zero:
          key.column_net: GP8
          key.neighbor_col_right: one
          rows.numbers.led_previous_key: function_esc_default
          rows.home.led_previous_key: primary_zero_top
          rows.mods.led_previous_key: primary_zero_bottom
        # First letter column (1, Q)
        one:
          key.column_net: GP7
          key.neighbor_col_left: zero
          key.neighbor_col_right: two
        # Second letter column (2, W)
        two:
          key.column_net: GP6
          key.neighbor_col_left: one
          key.neighbor_col_right: three
          rows.mods.skip: true
        # Third letter column (3, E)
        three:
          key.column_net: GP5
          key.neighbor_col_left: two
          key.neighbor_col_right: four
          rows.mods.skip: true
        # Fourth letter column (4, R)
        four:
          key.column_net: GP4
          key.neighbor_col_left: three
          key.neighbor_col_right: five
          rows.mods.skip: true
        # Fifth letter column (5, T)
        five:
          key.column_net: GP3
          key.neighbor_col_left: four
          key.neighbor_col_right: six
          rows.mods.skip: true
        # Sixth letter column (6, Y)
        six:
          key.column_net: GP2
          key.neighbor_col_left: five
          key.neighbor_col_right: seven
          rows.mods.skip: true
        # Seventh letter column (7, U)
        seven:
          key.column_net: GP1
          key.neighbor_col_left: six
          key.neighbor_col_right: eight
          rows.mods.skip: true
        # Eighth letter column (8, I)
        eight:
          key.column_net: GP0
          key.neighbor_col_left: seven
          key.neighbor_col_right: nine
          rows.mods.skip: true
        # Nineth letter column (9, O)
        nine:
          key.column_net: GP25
          key.neighbor_col_left: eight
          key.neighbor_col_right: ten
          rows.mods.skip: true
        # Tenth letter column (0, P)
        ten:
          key.column_net: GP24
          key.neighbor_col_left: nine
          key.neighbor_col_right: eleven
          rows.mods.skip: true
        # Eleventh letter column (-, [)
        eleven:
          key.column_net: GP23
          key.neighbor_col_left: ten
          key.neighbor_col_right: twelve
          rows.mods.led_previous_key: thumb_mirror_one_default
        # Twelfth letter column (=, ])
        twelve:
          key.column_net: GP22
          key.neighbor_col_left: eleven
          rows.top.led_previous_key: primary_twelve_numbers
          rows.bottom.led_previous_key: primary_twelve_home

    # Thumb fan
    thumb:
      # Position thumb keys based on the (non-existant) third key in the modifier row
      anchor:
        ref: primary_two_mods
        shift: [ 2, 0 ]

      # Rotate the thumb keys around the bottom-left corner of the key
      key:
        row_net: GP17
        tags: [ is_key, flip_led ]
        origin: [ -0.5cx, -0.5cy ]
        splay: -4

      # Define thumb keys
      columns:
        one:
          key.column_net: GP6
          key.mirror.column_net: GP24
          key.led_previous_key: primary_one_mods
          key.mirror.led_previous_key: thumb_mirror_two_default
        two:
          key.column_net: GP5
          key.mirror.column_net: GP25
          key.led_previous_key: thumb_one_default
          key.mirror.led_previous_key: thumb_mirror_three_default
        three:
          key.column_net: GP4
          key.mirror.column_net: GP0
          key.led_previous_key: thumb_two_default
          key.mirror.led_previous_key: thumb_mirror_four_default
        four:
          key.column_net: GP3
          key.mirror.column_net: GP1
          key.led_previous_key: thumb_three_default
          key.mirror.led_previous_key: thumb_four_default

      # Mirror the thumb fan
      mirror:
        ref: primary_five_numbers
        shift: [ 0.5cx, 0.5cx ]
        distance: 1cx

    # Function key row above the primary zone (Esc + 8 more keys)
    # (Note that the keys are only named "f[1-8]" for convenience and are not a full set of F1-F12 keys. They can be
    # used as F-keys when needed, but will more likely be used for macros and other special functions.)
    function:
      # Position function key row above primary zone with 3mm of vertical offset
      anchor:
        ref: primary_zero_numbers
        shift: [ 0, cy + function_zone_offset ]

      key:
        row_net: GP12

      # Define function keys
      columns:
        # Escape key
        esc:
          key.column_net: GP8
          key.led_previous_key: function_f1_default

        # Block of 4 keys with 6mm offset
        f1:
          key.spread: cx + 6
          key.column_net: GP7
          key.led_previous_key: function_f2_default
        f2:
          key.column_net: GP6
          key.led_previous_key: function_f3_default
        f3:
          key.column_net: GP5
          key.led_previous_key: function_f4_default
        f4:
          key.column_net: GP4
          key.led_previous_key: function_f5_default

        # Block of 4 keys with 6mm offset
        f5:
          key.spread: cx + 6
          key.column_net: GP3
          key.led_previous_key: function_f6_default
        f6:
          key.column_net: GP2
          key.led_previous_key: function_f7_default
        f7:
          key.column_net: GP1
          key.led_previous_key: function_f8_default
        f8:
          key.column_net: GP0
          key.led_previous_key: status_led

    # Additional points for special components in the upper right corner: Status LED, reset button, rotary encoder
    special:
      # Align points with the function key zone
      anchor:
        ref: primary_ten_numbers
        shift: [ 0, cy + function_zone_offset ]

      # These are not actually keys
      key:
        tags: [ no_key ]

      # Define points
      columns:
        # Neopixel status LED (first in the chain, see comment in PCB footprints for details)
        status_led:
          key:
            width: 3.4
            height: 3.0

        # Reset button
        reset_button:
          key:
            shift: [ -0.25cx - 1, 0 ]
            width: 6.5
            height: 6.5

        # Rotary encoder in the upper right corner
        rotary:
          key:
            row_net: GP12
            column_net: GP22
            shift: [ -0.25cx, 0 ]
            width: 20.5
            height: 20.5
            tags: [ is_rotary_encoder ]

# Generate outlines that can be used in the PCB and for 3D models
outlines:
  # Outline of the key caps
  keys:
    - what: rectangle
      where: is_key
      size: [ kcx, kcy ]

  # Rotary encoder with knob (2cm)
  rotary_encoder:
    - what: rectangle
      operation: stack
      size: [ 14, 14 ]
    - what: circle
      operation: stack
      radius: 10

  # Outline for the PCB
  board:
    - what: polygon
      points:
        - ref: primary_zero_numbers
          shift: [ -0.5cx + 1, 1.5cy + function_zone_offset + 2 ]
        - ref: primary_twelve_numbers
          shift: [ 0.5cx - 1, 1.5cy + function_zone_offset + 2]
        - ref: primary_twelve_mods
          shift: [ 0.5cx - 1, -0.5cy + 2 ]
        - ref: mirror_thumb_four
          shift: [ 0.5cx, -0.5cy + 2 ]
        - ref: thumb_four
          shift: [ 0.5cx, -0.5cy + 2 ]
        - ref: primary_zero_mods
          shift: [ -0.5cx + 1, -0.5cy + 2 ]
      expand: 4

  # Preview version of board with key caps and components for visualization
  board_preview:
    - board
    - ^keys
    # RP2040 controller board
    - what: rectangle
      operation: stack
      where: primary_eleven_numbers
      size: [ 54, 20 ]
      adjust.shift: [ 0, cy + function_zone_offset ]
    # Status LED
    - what: rectangle
      operation: stack
      where: special_status_led
      size: [ 3.4, 3.0 ]
    # Reset button
    - what: rectangle
      operation: stack
      where: special_reset_button
      size: [ 6.5, 6.5 ]
    # Rotary encoder
    - what: outline
      name: rotary_encoder
      operation: stack
      where: is_rotary_encoder

  # Cutouts for the switches
  switch_cutouts:
    - what: rectangle
      where: true
      size: 14

  # Board outline with switch cutouts
  switch_plate:
    - board
    - -switch_cutouts

# Generate the PCB
pcbs:
  eepyboard:
    # Define outline (edges) of the board based on the outlines defined above
    outlines:
      main:
        outline: board

    # Define PCB components
    footprints:
      controller:
        what: rp2040_purple
        where:
          ref: primary_eleven_numbers
          shift: [ 0, cy + function_zone_offset ]
          rotate: 90
        params:
          orientation: down
          # Use VBUS (5V from USB) as VCC net
          VBUS: VCC

      choc_hotswap:
        what: choc_pretty
        where: is_key
        # Rotate footprint so that the hotswap socket is at the bottom and the LED can be at the top
        adjust.rotate: 180
        params:
          keycaps: true
          hotswap: true
          from: "{{colrow}}"
          to: "{{column_net}}"

      diode:
        what: diode_smd
        where: is_key
        adjust:
          shift: [ 7, -7.5 ]
          rotate: 90
          resist: true
        params:
          side: B
          from: "{{colrow}}"
          to: "{{row_net}}"

      rotary_encoder:
        what: rotary_modified
        where: is_rotary_encoder
        params:
          from: "{{colrow}}"
          to: "{{column_net}}"
          A: GP10
          B: GP11
          C: GND

      diode_rotary_encoder:
        $extends: pcbs.eepyboard.footprints.diode
        where: is_rotary_encoder
        adjust:
          shift: [ 0, 0 ]
          rotate: 0

      led_chip:
        what: sk6812_mini_e
        # Place unrotated LEDs in all rows without the flip_led tag
        where: [ [ is_key, -flip_led ] ]
        # Position LEDs on the LED hole in the Choc switches
        adjust:
          shift: [ 0, 4.7 ]
        params:
          side: B
          din: "led_dout_{{led_previous_key}}"
          dout: "led_dout_{{zone.name}}_{{colrow}}"

      led_capacitor:
        what: cap_0805
        where: [ [ is_key, -flip_led ] ]
        adjust:
          shift: [ -6, 4.5 ]
          rotate: 90
          resist: true
        params:
          side: B
          from: VCC
          to: GND

      led_chip_flipped:
        $extends: pcbs.eepyboard.footprints.led_chip
        # Place flipped (rotated by 180°) LEDs in all rows *with* the flip_led tag
        where: [ [ is_key, flip_led ] ]
        adjust.rotate: 180

      led_capacitor_flipped:
        $extends: pcbs.eepyboard.footprints.led_capacitor
        where: [ [ is_key, flip_led ] ]
        adjust:
          shift: [ 6, 4.9 ]
          rotate: 270
          resist: true

      # Additional first LED (not bound to a key) that serves as a status LED.
      # Additionally, it runs on a reduced voltage to serve as a level converter for the next LED: The RP2040 runs on
      # 3.3V, but the SK6812 runs on 5V and requires at least 3.5V (5V * 0.7) for the control signal. By reducing the
      # power voltage with a diode, the threshold is reduced as well, so that the signal of the RP2040 is strong enough.
      status_led_chip:
        what: sk6812_mini_e
        where: special_status_led
        params:
          side: B
          VCC: VCC_status_led
          din: GP9
          dout: led_dout_status_led

      status_led_capacitor:
        what: cap_0805
        where: special_status_led
        adjust:
          shift: [ -6, -0.2 ]
          rotate: 90
        params:
          side: B
          from: VCC_status_led
          to: GND

      # Diode to reduce the voltage of the first LED chip by ~0.7V
      status_led_diode:
        what: diode_smd
        where: special_status_led
        adjust:
          shift: [ 0, 3.5 ]
          rotate: 0
        params:
          side: B
          from: VCC
          to: VCC_status_led

      reset_button:
        what: button_6x6
        where: special_reset_button
        params:
          from: GND
          to: RUN

      # Mounting holes
      mounting_hole_top_left:
        what: mountinghole_m2
        where:
          ref: function_esc
          shift: [ -9, 11.5 ]

      mounting_hole_top_center:
        what: mountinghole_m2
        where:
          ref: function_f4
          shift: [ 12.5, 0 ]

      mounting_hole_top_right:
        what: mountinghole_m2
        where:
          ref: primary_twelve_numbers
          shift: [ 9, cy + function_zone_offset + 11.5 ]

      mounting_hole_bottom_left:
        what: mountinghole_m2
        where:
          ref: primary_one_mods
          shift: [ 10.5, -12 ]

      mounting_hole_bottom_center:
        what: mountinghole_m2
        where:
          ref: primary_six_bottom
          shift: [ 0, -23 ]

      mounting_hole_bottom_right:
        what: mountinghole_m2
        where:
          ref: primary_eleven_mods
          shift: [ -10.5, -12 ]

      # Render text with project name and copyright onto the PCB
      copyright_text:
        what: text
        where:
          ref: primary_six_bottom
          shift: [ 0, -15 ]
        params:
          text: |-
            eepyBoard v1.0 by binaryDiv
            (c) 2024 (MIT License)
