#use-added-syntax(jitx)
defpackage first-design :
  import core
  import math
  import jitx
  import jitx/commands

  import ocdb/utils/defaults
  import ocdb/utils/landpatterns
  import ocdb/utils/symbols
  import ocdb/utils/symbol-utils
  import ocdb/utils/generic-components
  import ocdb/utils/bundles
  import ocdb/utils/box-symbol
  import ocdb/utils/property-structs
  import ocdb/utils/connects


pcb-component lora-modem :
  port spi : spi-peripheral()

  pin-properties :
    [pin:Ref | pads:Int ... | side:Dir]
    [spi.sdo   | 1 | Left]
    [spi.sdi   | 2 | Left]
    [spi.sck   | 3 | Left]
    [spi.cs    | 4 | Left]
    [ant       | 5 | Right]
    [vdd       | 6 | Up]
    [gnd       | 7 | Down]

  make-box-symbol()
  assign-landpattern(soic127p-landpattern(8))

pcb-component microcontroller :
  pin-properties :
    [pin:Ref | pads:Int ... | side:Dir]
    for i in 0 to 14 do :
      [PA[i]   | i + 1 | Right]
    [vdd       | 15 | Up]
    [gnd       | 16 | Down]
  make-box-symbol()
  assign-landpattern(soic127p-landpattern(16))

  supports adc: 
    adc.adc => self.PA[0]
  supports adc: 
    adc.adc => self.PA[1]
  supports adc: 
    adc.adc => self.PA[2]

  supports i2c :
    i2c.sda => self.PA[10]
    i2c.scl => self.PA[11]

  pcb-bundle io-pin : 
    pin p

  for i in 0 to 14 do :
    supports io-pin :
      io-pin.p => self.PA[i]
  
  for i in 0 to 2 do :
    supports spi-controller():
      require io:io-pin[4]
      spi-controller().copi => io[0].p  
      spi-controller().cipo => io[1].p  
      spi-controller().cs   => io[2].p
      spi-controller().sck  => io[3].p  
  
  for i in 0 to 14 do:
    supports gpio:
      require io:io-pin
      gpio.gpio => io.p

pcb-component thermocouple-amplifier :
  manufacturer = "Microchip"
  mpn = "MCP9600"
  description = "Thermocouple EMF to Temperature Converter, ±1.5°C Maximum Accuracy"
  port i2c : i2c
  pin-properties :
    [pin:Ref      | pads:Int ...         | side:Dir     ]
    [GND      | 1, 3, 5, 6, 7, 9, 10, 13, 17, 18, 21 | Down  ]
    [Vin+     | 2               | Right   ]
    [Vin-     | 4               | Right   ]
    [Vdd      | 8               | Up      ]
    [Alert[1] | 11              | Left    ]
    [Alert[2] | 12              | Left    ]
    [Alert[3] | 14              | Left    ]
    [Alert[4] | 15              | Left    ]
    [ADDR     | 16              | Left    ]
    [i2c.scl  | 19              | Left    ]
    [i2c.sda  | 20              | Left    ]

  make-box-symbol()
  assign-landpattern(qfn-landpattern(0.65, 5.0, 20, 0.3, 0.4, [3.25 3.25]))

pcb-component op-amp :
  pin-properties :
    [pin:Ref | pads:Int ...]
    [in+     | 3 ]
    [in-     | 4 ]
    [out     | 1 ]
    [v+      | 5 ]
    [v-      | 2 ]
  assign-landpattern(SOT95P280X145-5N)
  symbol = op-amp-sym(self.in+ => op-amp-sym.in+
                      self.in- => op-amp-sym.in-
                      self.out => op-amp-sym.out
                      self.v-  => op-amp-sym.v-
                      self.v+  => op-amp-sym.v+)


pcb-pad round-pth-pad :
  type = TH
  shape = Circle(0.8)
  layer(SolderMask(Top)) = Circle(0.8)
  layer(SolderMask(Bottom)) = Circle(0.8)
  layer(Cutout()) = Circle(0.5)

pcb-symbol pin-header-symbol :
  layer("foreground") = Rectangle(2.54, 7.62, loc(-1.27, 0.0))
  for i in 0 to 3 do :
    pin p[(i + 1)] at Point(-2.54, (2.54 - (to-double(i) * 2.54))) with :
      direction = Left
      length = 2.54
      number-size = 0.762
      name-size = 0.762
  preferred-orientation = PreferRotation([0])
  layer("reference")  = Text(">REF", 0.7056, W, loc(-2.54, 4.2))

pcb-landpattern pin-header-landpattern :
  pad p[1] : round-pth-pad at loc(-2.54, 0.0)
  pad p[2] : round-pth-pad at loc(0.0, 0.0)
  pad p[3] : round-pth-pad at loc(2.54, 0.0)
  layer(Courtyard(Top)) = Rectangle(6.6, 1.6)
  layer(Silkscreen("values", Top)) = Text(">REF", 0.7, C, loc(0.0, -1.2))

pcb-component three-pin-header :
  port p : pin[[1 2 3]]
  landpattern = pin-header-landpattern(p[1] => pin-header-landpattern.p[1]
                                       p[2] => pin-header-landpattern.p[2]
                                       p[3] => pin-header-landpattern.p[3])
  symbol =           pin-header-symbol(p[1] => pin-header-symbol.p[1]
                                       p[2] => pin-header-symbol.p[2]
                                       p[3] => pin-header-symbol.p[3])
  reference-prefix = "J"

pcb-pad rect-smd-pad :
  type = SMD
  val pad-shape = Rectangle(0.75, 1.0)
  shape = pad-shape
  layer(SolderMask(Top)) = pad-shape
  layer(Paste(Top)) = pad-shape

pcb-landpattern polarized-chip-landpattern :
  pad a : rect-smd-pad at loc(1.0, 0.0)
  pad c : rect-smd-pad at loc(-1.0, 0.0)
  layer(Courtyard(Top)) = Rectangle(3.0, 2.0)
  layer(Silkscreen("pol", Top)) = Line(0.30, [Point((- 1.5), (- 1.0)) Point((- 1.5), 1.0)])
  layer(Silkscreen("values", Top)) = Text(">REF", 0.7, C, loc(0.0, -1.2))

pcb-component photodiode :
  pin a 
  pin c
  landpattern = polarized-chip-landpattern(a => polarized-chip-landpattern.a, 
                                           c => polarized-chip-landpattern.c)
  val sym = diode-sym(DiodePhoto)
  symbol =                             sym(a => sym.a, 
                                           c => sym.c)
  reference-prefix = "D"
  property(self.responsivity) = 125.0e-6 / 1000.0 ; Current out / light in @850nm (A / lux) 
  property(self.capacitance) = 11.0e-12 ; Self capacitance (F)

pcb-module transimpedance-amplifier (rf:Double, cf:Double):
  pin input
  pin output
  pin vdd
  pin gnd

  inst op-amp:op-amp
  inst decoupling-cap : ceramic-cap(10.0e-6)

  ; Connect module pins and decoupling to op-amp power pins. 
  net (vdd op-amp.v+ decoupling-cap.p[1])
  net (gnd op-amp.v- decoupling-cap.p[2])

  ; Add and connect feedback network
  inst r : chip-resistor(closest-std-val(rf, 1.0))
  inst c : ceramic-cap(cf)

  net (gnd    op-amp.in+)
  net (input, op-amp.in-, r.p[1] c.p[1])
  net (output op-amp.out, r.p[2] c.p[2])

  schematic-group(self) = trans-amp

pcb-module amplified-photodiode ( photodiode:Instantiable, 
                                  supply-voltage:Double, 
                                  lux-at-full-range:Double, 
                                  target-bandwidth:Double) :
  pin output
  pin vdd
  pin gnd

  inst pd : photodiode
  
  ; Calculate 1% gain resistor TIDU535
  val max-light-current = property(pd.responsivity) * lux-at-full-range
  val target-gain-resistance = closest-std-val(supply-voltage / max-light-current, 1.0)

  ; Calculate feedback capacitor for stability at bandwidth
  val cf = closest-std-val(1.0 / (2.0 * PI * target-gain-resistance * target-bandwidth) * 0.9, 10.0)

  inst amp : transimpedance-amplifier(target-gain-resistance, cf)
  net (pd.c amp.input)
  net (output amp.output)
  net (gnd pd.a amp.gnd)
  net (vdd amp.vdd)

  schematic-group(pd) = schematic-group(amp)

pcb-module main-design :

  inst connector : three-pin-header
  inst mcu : microcontroller

  net GND (connector.p[1] mcu.gnd)
  net VDD (connector.p[2] mcu.vdd)

  inst high-sensitivity-photodiode : amplified-photodiode(photodiode, 3.3, 500.0,  1.0e6)
  inst low-sensitivity-photodiode :  amplified-photodiode(photodiode, 3.3, 2000.0,  1.0e6)
  require light:adc[2] from mcu
  net (high-sensitivity-photodiode.output light[0].adc)
  net (low-sensitivity-photodiode.output light[1].adc)

  inst K : thermocouple-amplifier
  require K-i2c : i2c from mcu
  require alert:gpio[4] from mcu
  net (K-i2c, K.i2c)
  for i in 0 to 4 do : 
    net (alert[i].gpio, K.Alert[i + 1])

  inst lora : lora-modem
  require lora-spi:spi-controller() from mcu
  connect-spi(mcu, lora-spi, [lora.spi])

  net (GND high-sensitivity-photodiode.gnd low-sensitivity-photodiode.gnd K.GND lora.gnd)
  net (VDD high-sensitivity-photodiode.vdd low-sensitivity-photodiode.vdd K.Vdd lora.vdd)

  symbol(GND) = ocdb/utils/symbols/ground-sym
  symbol(VDD) = ocdb/utils/symbols/supply-sym

set-current-design("first-design")
make-default-board(main-design, 4, Rectangle(25.0, 25.0))

; Export CAD with default options
export-cad()

; Show the Schematic and PCB for the design
view-board()
view-schematic()