Skip to content

Instantly share code, notes, and snippets.

@ddribin
Last active November 21, 2024 16:15
Show Gist options
  • Save ddribin/6be9227772295000cf45217302a0554d to your computer and use it in GitHub Desktop.
Save ddribin/6be9227772295000cf45217302a0554d to your computer and use it in GitHub Desktop.
Lark grammar and Python script for Potentiometers
pot : "PDB18" GANGS "-" PIN_TYPE DETENT SHAFT_LENGTH SHAFT_STYLE "-" RESISTANCE TAPER
GANGS : "1" | "2"
PIN_TYPE \
: "K" // PC pins, vertical 12.5mm
| "A" // PC pins, vertical 18.0mm
DETENT \
: "2" // Center detents
| "4" // No Detents
// Length is in millimeters
SHAFT_LENGTH : "15" | "18" | "20" | "25" | "30"
SHAFT_STYLE \
: "F" // Metal flatted
| "K" // Metal knurled
| "P" // Metal plain
// Standard code, e.g. "103" = "1,000"
RESISTANCE : DIGIT DIGIT DIGIT
TAPER \
: "B" // Linear
| "A2" // Logarithmic (Audio)
DIGIT : "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
#!/usr/bin/env python3
import sys
from typing import Any
from dataclasses import dataclass
from enum import IntEnum, StrEnum
from lark import Lark, Transformer, Token
from pathlib import Path
class Gang(IntEnum):
SINGLE = 1
DUAL = 2
def __str__(self) -> str:
match self:
case self.SINGLE:
return "Single gang"
case self.DUAL:
return "Dual gang"
class PinType(StrEnum):
PC_PINS_12_5 = "K"
PC_PINS_18 = "A"
def __str__(self) -> str:
match self:
case self.PC_PINS_12_5:
return "PC Pins vertical/Down Facing (12.5 mm)"
case self.PC_PINS_18:
return "PC Pins vertical/Down Facing (18.0 mm)"
class Detent(IntEnum):
CENTER_DETENT = 2
NO_DETENT = 4
def __str__(self) -> str:
match self:
case self.CENTER_DETENT:
return "Center Detent"
case self.NO_DETENT:
return "No Detent"
class ShaftLength(IntEnum):
L15 = 15
L18 = 18
L20 = 20
L25 = 25
L30 = 30
def __str__(self) -> str:
match self:
case self.L15:
return "15 mm"
case self.L18:
return "18 mm"
case self.L20:
return "20 mm"
case self.L25:
return "25 mm"
case self.L30:
return "30 mm"
class ShaftStyle(StrEnum):
FLATTED = "F"
KNURLED = "K"
PLAIN = "P"
def __str__(self) -> str:
match self:
case self.FLATTED:
return "Metal Flatted"
case self.KNURLED:
return "Metal Knurled"
case self.PLAIN:
return "Metal Plain"
@dataclass(frozen=True)
class Resistance:
code: str
def __str__(self) -> str:
int_code = int(self.code)
(base, exponent) = divmod(int_code, 10)
value = base * (10**exponent)
return f"{value:,} ohm"
class Taper(StrEnum):
LINEAR = "B"
AUDIO = "A2"
def __str__(self) -> str:
match self:
case self.LINEAR:
return "Linear Taper"
case self.AUDIO:
return "Logarithmic (Audio) Taper"
@dataclass(frozen=True)
class Potentiometer:
gang: Gang
pin_type: PinType
detent: Detent
shaft_length: ShaftLength
shaft_style: ShaftStyle
resistance: Resistance
taper: Taper
def __str__(self) -> str:
l: list[Any] = [
self.gang,
self.pin_type,
self.detent,
self.shaft_length,
self.shaft_style,
self.resistance,
self.taper,
]
s = ", ".join(str(x) for x in l)
return s
@property
def long_description(self) -> str:
lines = [
f"Gang = {self.gang}",
f"Pin type = {self.pin_type}",
f"Detent = {self.detent}",
f"Shaft length = {self.shaft_length}",
f"Shaft style = {self.shaft_style}",
f"Resistance = {self.resistance}",
f"Taper = {self.taper}",
]
return "\n".join(lines)
class PotentiometerParser:
def __init__(self) -> None:
self._parser = Lark(Path("pot.lark").read_text(), start="pot")
def parse(self, string: str) -> None:
tree = self._parser.parse(string)
# print(tree.pretty())
# print(tree)
transformer = PotentiometerTransformer()
poteniometer = transformer.transform(tree)
print(poteniometer.long_description)
class PotentiometerTransformer(Transformer):
def pot(self, arg: list[Any]) -> Potentiometer:
pot = Potentiometer(
gang=arg[0],
pin_type=arg[1],
detent=arg[2],
shaft_length=arg[3],
shaft_style=arg[4],
resistance=arg[5],
taper=arg[6],
)
return pot
def GANGS(self, token: Token) -> Gang:
return Gang(int(token))
def PIN_TYPE(self, token: Token) -> PinType:
return PinType(str(token))
def DETENT(self, token: Token) -> Detent:
return Detent(int(token))
def SHAFT_LENGTH(self, token: Token) -> ShaftLength:
return ShaftLength(int(token))
def SHAFT_STYLE(self, token: Token) -> ShaftStyle:
return ShaftStyle(str(token))
def RESISTANCE(self, token: Token) -> Resistance:
return Resistance(str(token))
def TAPER(self, token: Token) -> Taper:
return Taper(str(token))
if __name__ == "__main__":
parser = PotentiometerParser()
parser.parse(sys.argv[1])
@ddribin
Copy link
Author

ddribin commented Nov 21, 2024

Lark: https://lark-parser.readthedocs.io/en/stable/

Source: Page 5 of https://www.bourns.com/docs/Product-Datasheets/PDB18.pdf

Example output:

> ./pot.py PDB181-K415K-103B
Gang = Single gang
Pin type = PC Pins vertical/Down Facing (12.5 mm)
Detent = No Detent
Shaft length = 15 mm
Shaft style = Metal Knurled
Resistance = 10,000 ohm
Taper = Linear Taper
> ./pot.py PDB182-K420K-504A2
Gang = Dual gang
Pin type = PC Pins vertical/Down Facing (12.5 mm)
Detent = No Detent
Shaft length = 20 mm
Shaft style = Metal Knurled
Resistance = 500,000 ohm
Taper = Logarithmic (Audio) Taper

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment