# main.py
from jitx import Board, Circle, LayerSet, Net, Port, Pour, Side, current, rectangle
from jitx.circuit import Circuit
from jitx.common import Power
from jitx.feature import KeepOut, Soldermask
from jitx.net import provide
from jitx.sample import SampleDesign
from jitxlib.parts import Capacitor, CapacitorQuery, Resistor, ResistorQuery
from jitxlib.symbols.net_symbols import GroundSymbol, PowerSymbol
from . import rectangles
from .cap_touch import CapTouch
from .components.Q_J.ComponentCR2032_BS_6_1 import ComponentCR2032_BS_6_1 as Bat
from .components.TOGIALED.ComponentTJ_S3210SW5TGLC2R_A5 import (
ComponentTJ_S3210SW5TGLC2R_A5 as led,
)
from .components.Texas_Instruments.ComponentSN74HC14PWR import (
CircuitSN74HC14PWR as schmitt,
)
from .components.Texas_Instruments.ComponentTLV9001IDBVR import (
ComponentTLV9001IDBVR as opamp,
)
[docs]
class SchmittInverter(Port):
"""Custom port type for a Schmitt trigger inverter with input and output ports."""
input = Port()
output = Port()
[docs]
class SchmittInverterWithPassives(Circuit):
"""Parametric circuit for a Schmitt inverter with configurable passive components."""
# Create ports
gnd = Port()
out = Port()
inp = Port() # External input port (connects through input resistor)
schmittinverter = SchmittInverter()
def __init__(
self,
feedback_resistance=10e6, # Feedback resistor (input to output)
input_capacitance=None, # Input capacitor (input to ground)
series_output_resistance=None, # Optional series resistor on output
input_resistance=None, # Input resistor (external input to schmitt input)
):
# Store parameters
self.feedback_resistance = feedback_resistance
self.input_capacitance = input_capacitance
self.series_output_resistance = series_output_resistance
self.input_resistance = input_resistance
# Create passive components
self.parts = []
self.nets = []
# Always add feedback resistor (input to output)
self.parts.append(
Resistor(resistance=self.feedback_resistance).insert(
self.schmittinverter.input, self.schmittinverter.output
)
)
# Add input capacitor if specified (input to ground)
if self.input_capacitance is not None:
self.parts.append(
Capacitor(capacitance=self.input_capacitance).insert(
self.schmittinverter.input, self.gnd
)
)
# Handle input connection with optional input resistor
if self.input_resistance is not None:
# Add input resistor between external input and schmitt input
self.parts.append(
Resistor(resistance=self.input_resistance).insert(
self.inp, self.schmittinverter.input
)
)
else:
# Direct connection from external input to schmitt input
self.nets.append(self.inp + self.schmittinverter.input)
# Handle output connection with optional series resistor
if self.series_output_resistance is not None:
# Add series resistor between schmitt output and final output
self.parts.append(
Resistor(resistance=self.series_output_resistance).insert(
self.schmittinverter.output, self.out
)
)
else:
# Direct connection from schmitt output to final output
self.nets.append(self.schmittinverter.output + self.out)
BOARD_W = 50.0
BOARD_H = 100.0
COPPER_ISO = 0.1
# LED footprint parameters for checks (match your physical choices)
LED_DIAM = 6.0 # mm
LED_TAIL = 2.0 # extra reach along the orientation
LED_CLEAR = 0.25 # safety margin in tests
[docs]
class Gourd(Board):
shape = rectangle(BOARD_W, BOARD_H, radius=2)
[docs]
class Driver(Circuit):
power = Power()
ctrl = Port()
cap = [Port(), Port(), Port()]
def __init__(self):
self.sc = [schmitt(), schmitt()]
# Connect schmitt inverter grounds to driver ground and create VCC ports
nets_list = []
for s in self.sc:
nets_list.append(s.power + self.power)
self.nets = nets_list
self.parts = []
# Create parametric Schmitt inverters with passives in a list
self.inverters = [
# f1 and f2: Basic feedback configuration for capacitive touch inputs with series output resistance
SchmittInverterWithPassives(
feedback_resistance=10e6, series_output_resistance=10e6
),
SchmittInverterWithPassives(
feedback_resistance=10e6, series_output_resistance=10e6
),
# s1 and s2: Oscillator configuration with timing capacitors
SchmittInverterWithPassives(
feedback_resistance=3.3e6,
input_capacitance=100e-9,
series_output_resistance=15e6,
),
SchmittInverterWithPassives(
feedback_resistance=4.7e6,
input_capacitance=100e-9,
series_output_resistance=15e6,
),
]
# Connect specific inputs and outputs
# f1 and f2 inputs to capacitive touch ports
self.nets.append(self.inverters[0].schmittinverter.input + self.cap[0]) # f1
self.nets.append(self.inverters[1].schmittinverter.input + self.cap[1]) # f2
# Create required SchmittInverter ports and connect them
inverter_ports = [self.require(SchmittInverter) for _ in self.inverters]
# Connect each parametric circuit to its required SchmittInverter port
for inv_circuit, inv_port in zip(self.inverters, inverter_ports):
self.nets.append(inv_circuit.schmittinverter + inv_port)
# Connect grounds for all inverters
for inv_circuit in self.inverters:
self.nets.append(inv_circuit.gnd + self.power.Vn)
# All outputs to cap[2] (f1, f2, s1, s2)
for inv_circuit in self.inverters:
self.nets.append(inv_circuit.out + self.cap[2])
self.buffer = opamp()
self.parts.append(
Capacitor(capacitance=4.7e-6).insert(
self.buffer.Vp, self.buffer.Vn, short_trace=True
)
)
self.nets.append(self.buffer.OUT + self.ctrl)
self.nets.append(self.cap[2] + self.buffer.INp)
self.nets.append(
self.buffer.OUT + self.buffer.INn
) # Feedback for non-inverting buffer
self.nets.append(self.buffer.Vp + self.power.Vp) # Positive supply
self.nets.append(self.buffer.Vn + self.power.Vn) # Ground
@provide(SchmittInverter)
def provide_inverter(self, bundle: SchmittInverter):
for s in self.sc:
yield from [
{
bundle.input: s.inv.P_1A,
bundle.output: s.inv.P_1Y,
},
{
bundle.input: s.inv.P_2A,
bundle.output: s.inv.P_2Y,
},
{
bundle.input: s.inv.P_3A,
bundle.output: s.inv.P_3Y,
},
{
bundle.input: s.inv.P_4A,
bundle.output: s.inv.P_4Y,
},
{
bundle.input: s.inv.P_5A,
bundle.output: s.inv.P_5Y,
},
{
bundle.input: s.inv.P_6A,
bundle.output: s.inv.P_6Y,
},
]
[docs]
class Lit(Circuit):
power = Power()
def __init__(self):
# LED facing "down" by default; caller will rotate instance by Rect.angle
self.l = led().at(0, -3.25)
# Add 680 ohm resistor
self.resistor = Resistor(resistance=680).insert(self.l.p[1], self.power.Vn)
self.nets = [self.power.Vp + self.l.p[2]]
self.sm = Soldermask(shape=Circle(radius=3.0))
self.v = KeepOut(pour=True, shape=Circle(radius=3.2), layers=LayerSet(0))
[docs]
class Mondrian(Circuit):
def __init__(self):
# Generate rectangles (roles + angles included)
rects = rectangles.mondrian_bsp(
width=BOARD_W - 2.0, # slight inset from the board outline
height=BOARD_H - 2.0,
line_thickness=0.75,
min_size=6.0,
seed=6,
role_weights={"mask": 0.45, "void": 0.1, "led": 0.08},
colors={"mask": "#e5e5e5", "void": "#928647", "led": "#900d1a"},
led_diam=LED_DIAM,
led_extra=LED_TAIL,
led_clearance=LED_CLEAR,
led_count=8,
)
# Soldermask for all rectangles
self.sms = [Soldermask(rectangle(r.w, r.h).at(r.cx, r.cy)) for r in rects]
# KeepOut (void) for 'void' and 'led' roles
self.voids = [
KeepOut(
pour=True, shape=rectangle(r.w, r.h).at(r.cx, r.cy), layers=LayerSet(0)
)
for r in rects
if r.role in ("void", "led")
]
# Driver circuit with schmitt inverters
self.gnd = Net(name="GND")
self.vcc = Net(name="VCC")
self.driver = Driver()
self.battery = Bat()
self.nets = []
self.gnd += self.battery.p[1]
self.vcc += self.battery.p[2]
self.gnd += self.driver.power.Vn
self.vcc += self.driver.power.Vp
self.ls = []
self.rs = []
cval = [6.8e-9, 8.2e-9, 10e-9, 12e-9, 15e-9, 18e-9, 22e-9, 27e-9]
# Create parametric Schmitt inverter circuits for LEDs
self.led_drivers = []
for r in rects:
if r.role == "led":
rot = (r.angle - 270.0) % 360
inst = Lit().at(r.cx, r.cy, rotate=rot, on=Side.Bottom)
self.ls.append(inst)
# Connect each LED's VCC to the main power supply
self.vcc += inst.power.Vp
# Create parametric Schmitt inverter with passives for this LED
led_driver = SchmittInverterWithPassives(
feedback_resistance=330e3,
input_capacitance=cval.pop(0),
input_resistance=330e3,
)
self.led_drivers.append(led_driver)
dr = self.driver.require(SchmittInverter)
# Connect LED driver ground and output
self.nets.append(led_driver.schmittinverter + dr)
self.nets.append(led_driver.gnd + self.gnd)
self.nets.append(led_driver.out + inst.power.Vn)
# Connect driver control to LED driver input (330k resistor now internal)
self.nets.append(led_driver.inp + self.driver.ctrl)
# Create capacitive touch sensors
self.pokes = [
CapTouch(10.0, 40.0, 0.1),
CapTouch(12.0, 40.0, 0.1),
CapTouch(10.0, 40.0, 0.1),
]
# Connect each touch sensor: B to ground, A to driver capacitor ports
for poke, cap_port in zip(self.pokes, self.driver.cap):
self.gnd += poke.B
self.nets.append(poke.A + cap_port) # Connect touch sensor to driver input
# Build the nets list
self.gnd += Pour(layer=1, shape=current.design.board.shape, isolate=COPPER_ISO)
self.vcc += Pour(layer=0, shape=current.design.board.shape, isolate=COPPER_ISO)
self.gnd.symbol = GroundSymbol()
self.vcc.symbol = PowerSymbol()
[docs]
class Resistors(SampleDesign):
resistor_defaults = ResistorQuery(case="0402", tolerance=0.01)
capacitor_defaults = CapacitorQuery(case="0402")
board = Gourd()
circuit = Mondrian()