kicad-ipc-rs/src/model/board.rs

557 lines
13 KiB
Rust

use std::str::FromStr;
#[derive(Clone, Debug, Eq, PartialEq)]
/// KiCad net descriptor.
pub struct BoardNet {
/// Numeric net code.
pub code: i32,
/// Net name.
pub name: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
/// Board layer descriptor.
pub struct BoardLayerInfo {
/// KiCad layer id.
pub id: i32,
/// Human-readable layer name.
pub name: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
/// Enabled layer set for a board.
pub struct BoardEnabledLayers {
/// Number of copper layers configured in the board stack.
pub copper_layer_count: u32,
/// Enabled board layers.
pub layers: Vec<BoardLayerInfo>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
/// Board origin kind.
pub enum BoardOriginKind {
/// Grid origin.
Grid,
/// Drill/place origin.
Drill,
}
impl FromStr for BoardOriginKind {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"grid" => Ok(Self::Grid),
"drill" => Ok(Self::Drill),
_ => Err(format!(
"unknown board origin kind `{value}`; expected `grid` or `drill`"
)),
}
}
}
impl std::fmt::Display for BoardOriginKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Grid => write!(f, "grid"),
Self::Drill => write!(f, "drill"),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
/// 2D coordinate in nanometer units.
pub struct Vector2Nm {
/// X coordinate in nm.
pub x_nm: i64,
/// Y coordinate in nm.
pub y_nm: i64,
}
#[derive(Clone, Debug, Eq, PartialEq)]
/// Pad-to-net lookup row derived from footprint items.
pub struct PadNetEntry {
/// Footprint reference (e.g. `U1`) when available.
pub footprint_reference: Option<String>,
/// Footprint id when available.
pub footprint_id: Option<String>,
/// Pad item id when available.
pub pad_id: Option<String>,
/// Pad number/text as shown in KiCad.
pub pad_number: String,
/// Net code when connected.
pub net_code: Option<i32>,
/// Net name when connected.
pub net_name: Option<String>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
/// Arc geometry in nanometer units.
pub struct ArcStartMidEndNm {
/// Arc start point.
pub start: Vector2Nm,
/// Arc midpoint.
pub mid: Vector2Nm,
/// Arc end point.
pub end: Vector2Nm,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
/// Polyline node geometry.
pub enum PolyLineNodeGeometryNm {
/// Straight segment point.
Point(Vector2Nm),
/// Arc segment node.
Arc(ArcStartMidEndNm),
}
#[derive(Clone, Debug, Eq, PartialEq)]
/// Polyline geometry.
pub struct PolyLineNm {
/// Ordered geometry nodes.
pub nodes: Vec<PolyLineNodeGeometryNm>,
/// Whether last node closes back to first.
pub closed: bool,
}
#[derive(Clone, Debug, Eq, PartialEq)]
/// Polygon with optional interior holes.
pub struct PolygonWithHolesNm {
/// Outer outline polygon.
pub outline: Option<PolyLineNm>,
/// Interior holes.
pub holes: Vec<PolyLineNm>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PadShapeAsPolygonEntry {
pub pad_id: String,
pub layer_id: i32,
pub layer_name: String,
pub polygon: PolygonWithHolesNm,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PadstackPresenceEntry {
pub item_id: String,
pub layer_id: i32,
pub layer_name: String,
pub presence: PadstackPresenceState,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PadstackPresenceState {
Present,
NotPresent,
Unknown(i32),
}
impl std::fmt::Display for PadstackPresenceState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Present => write!(f, "PSP_PRESENT"),
Self::NotPresent => write!(f, "PSP_NOT_PRESENT"),
Self::Unknown(value) => write!(f, "UNKNOWN({value})"),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ColorRgba {
pub r: f64,
pub g: f64,
pub b: f64,
pub a: f64,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BoardStackupLayerType {
Copper,
Dielectric,
Silkscreen,
SolderMask,
SolderPaste,
Undefined,
Unknown(i32),
}
#[derive(Clone, Debug, PartialEq)]
pub struct BoardStackupDielectricProperties {
pub epsilon_r: f64,
pub loss_tangent: f64,
pub material_name: String,
pub thickness_nm: Option<i64>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct BoardStackupLayer {
pub layer: BoardLayerInfo,
pub user_name: String,
pub material_name: String,
pub enabled: bool,
pub thickness_nm: Option<i64>,
pub layer_type: BoardStackupLayerType,
pub color: Option<ColorRgba>,
pub dielectric_layers: Vec<BoardStackupDielectricProperties>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct BoardStackup {
pub finish_type_name: String,
pub impedance_controlled: bool,
pub edge_has_connector: bool,
pub edge_has_castellated_pads: bool,
pub edge_has_edge_plating: bool,
pub layers: Vec<BoardStackupLayer>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BoardLayerClass {
Silkscreen,
Copper,
Edges,
Courtyard,
Fabrication,
Other,
Unknown(i32),
}
#[derive(Clone, Debug, PartialEq)]
pub struct BoardLayerGraphicsDefault {
pub layer_class: BoardLayerClass,
pub line_thickness_nm: Option<i64>,
pub text_font_name: Option<String>,
pub text_size_nm: Option<Vector2Nm>,
pub text_stroke_width_nm: Option<i64>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct GraphicsDefaults {
pub layers: Vec<BoardLayerGraphicsDefault>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum InactiveLayerDisplayMode {
Normal,
Dimmed,
Hidden,
Unknown(i32),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum NetColorDisplayMode {
All,
Ratsnest,
Off,
Unknown(i32),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BoardFlipMode {
Normal,
FlippedX,
Unknown(i32),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RatsnestDisplayMode {
AllLayers,
VisibleLayers,
Unknown(i32),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DrcSeverity {
Warning,
Error,
Exclusion,
Ignore,
Info,
Action,
Debug,
Undefined,
}
impl std::fmt::Display for DrcSeverity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let value = match self {
Self::Warning => "warning",
Self::Error => "error",
Self::Exclusion => "exclusion",
Self::Ignore => "ignore",
Self::Info => "info",
Self::Action => "action",
Self::Debug => "debug",
Self::Undefined => "undefined",
};
write!(f, "{value}")
}
}
impl FromStr for DrcSeverity {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"warning" => Ok(Self::Warning),
"error" => Ok(Self::Error),
"exclusion" => Ok(Self::Exclusion),
"ignore" => Ok(Self::Ignore),
"info" => Ok(Self::Info),
"action" => Ok(Self::Action),
"debug" => Ok(Self::Debug),
"undefined" => Ok(Self::Undefined),
_ => Err(format!(
"unknown drc severity `{value}`; expected warning, error, exclusion, ignore, info, action, debug, or undefined"
)),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BoardEditorAppearanceSettings {
pub inactive_layer_display: InactiveLayerDisplayMode,
pub net_color_display: NetColorDisplayMode,
pub board_flip: BoardFlipMode,
pub ratsnest_display: RatsnestDisplayMode,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum NetClassType {
Explicit,
Implicit,
Unknown(i32),
}
#[derive(Clone, Debug, PartialEq)]
pub struct NetClassBoardSettings {
pub clearance_nm: Option<i64>,
pub track_width_nm: Option<i64>,
pub diff_pair_track_width_nm: Option<i64>,
pub diff_pair_gap_nm: Option<i64>,
pub diff_pair_via_gap_nm: Option<i64>,
pub color: Option<ColorRgba>,
pub tuning_profile: Option<String>,
pub has_via_stack: bool,
pub has_microvia_stack: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub struct NetClassInfo {
pub name: String,
pub priority: Option<i32>,
pub class_type: NetClassType,
pub constituents: Vec<String>,
pub board: Option<NetClassBoardSettings>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct NetClassForNetEntry {
pub net_name: String,
pub net_class: NetClassInfo,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PcbViaType {
Through,
BlindBuried,
Micro,
Blind,
Buried,
Unknown(i32),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbViaLayers {
pub padstack_layers: Vec<BoardLayerInfo>,
pub drill_start_layer: Option<BoardLayerInfo>,
pub drill_end_layer: Option<BoardLayerInfo>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PcbPadType {
Pth,
Smd,
EdgeConnector,
Npth,
Unknown(i32),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PcbZoneType {
Copper,
Graphical,
RuleArea,
Teardrop,
Unknown(i32),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbTrack {
pub id: Option<String>,
pub start_nm: Option<Vector2Nm>,
pub end_nm: Option<Vector2Nm>,
pub width_nm: Option<i64>,
pub layer: BoardLayerInfo,
pub net: Option<BoardNet>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbArc {
pub id: Option<String>,
pub start_nm: Option<Vector2Nm>,
pub mid_nm: Option<Vector2Nm>,
pub end_nm: Option<Vector2Nm>,
pub width_nm: Option<i64>,
pub layer: BoardLayerInfo,
pub net: Option<BoardNet>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbVia {
pub id: Option<String>,
pub position_nm: Option<Vector2Nm>,
pub via_type: PcbViaType,
pub layers: Option<PcbViaLayers>,
pub net: Option<BoardNet>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PcbFootprint {
pub id: Option<String>,
pub reference: Option<String>,
pub position_nm: Option<Vector2Nm>,
pub orientation_deg: Option<f64>,
pub layer: BoardLayerInfo,
pub pad_count: usize,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbPad {
pub id: Option<String>,
pub number: String,
pub pad_type: PcbPadType,
pub position_nm: Option<Vector2Nm>,
pub net: Option<BoardNet>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbBoardGraphicShape {
pub id: Option<String>,
pub layer: BoardLayerInfo,
pub net: Option<BoardNet>,
pub geometry_kind: Option<String>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbBoardText {
pub id: Option<String>,
pub layer: BoardLayerInfo,
pub text: Option<String>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbBoardTextBox {
pub id: Option<String>,
pub layer: BoardLayerInfo,
pub text: Option<String>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbField {
pub name: String,
pub visible: bool,
pub text: Option<String>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbZone {
pub id: Option<String>,
pub name: String,
pub zone_type: PcbZoneType,
pub layer_count: usize,
pub filled: bool,
pub polygon_count: usize,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbDimension {
pub id: Option<String>,
pub layer: BoardLayerInfo,
pub text: Option<String>,
pub style_kind: Option<String>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbGroup {
pub id: Option<String>,
pub name: String,
pub item_count: usize,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PcbUnknownItem {
pub type_url: String,
pub raw_len: usize,
}
#[derive(Clone, Debug, PartialEq)]
pub enum PcbItem {
Track(PcbTrack),
Arc(PcbArc),
Via(PcbVia),
Footprint(PcbFootprint),
Pad(PcbPad),
BoardGraphicShape(PcbBoardGraphicShape),
BoardText(PcbBoardText),
BoardTextBox(PcbBoardTextBox),
Field(PcbField),
Zone(PcbZone),
Dimension(PcbDimension),
Group(PcbGroup),
Unknown(PcbUnknownItem),
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use super::{BoardOriginKind, DrcSeverity};
#[test]
fn board_origin_kind_parses_known_values() {
assert_eq!(
BoardOriginKind::from_str("grid").expect("grid should parse"),
BoardOriginKind::Grid
);
assert_eq!(
BoardOriginKind::from_str("drill").expect("drill should parse"),
BoardOriginKind::Drill
);
}
#[test]
fn board_origin_kind_rejects_unknown_values() {
let result = BoardOriginKind::from_str("other");
assert!(result.is_err());
}
#[test]
fn drc_severity_parses_known_values() {
assert_eq!(
DrcSeverity::from_str("warning").expect("warning should parse"),
DrcSeverity::Warning
);
assert_eq!(
DrcSeverity::from_str("error").expect("error should parse"),
DrcSeverity::Error
);
}
#[test]
fn drc_severity_rejects_unknown_values() {
let result = DrcSeverity::from_str("fatal");
assert!(result.is_err());
}
}