Skip to content

Commit

Permalink
Add a basic CLI for debugging
Browse files Browse the repository at this point in the history
  • Loading branch information
tgross35 committed May 2, 2024
1 parent db77f83 commit 518c298
Show file tree
Hide file tree
Showing 13 changed files with 365 additions and 58 deletions.
87 changes: 86 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ resolver = "2"
members = [
"altium",
"altium-macros",
"ecad-cli",
"ecadg",
# "drawsvg",
]
2 changes: 1 addition & 1 deletion altium/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ serde = "1.0.200"
serde-xml-rs = "0.6.0"
svg = "0.17.0"
uom = "0.36.0"
uuid = { version = "1.8.0", features = ["v1", "v4", "fast-rng"]}
uuid = { version = "1.8.0", features = ["v1", "v4", "fast-rng", "serde"]}
xml-rs = "0.8.20"

[dev-dependencies]
Expand Down
44 changes: 37 additions & 7 deletions altium/src/common.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{fmt, str};

use num_traits::CheckedMul;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::error::{AddContext, ErrorKind, Result, TruncBuf};
Expand All @@ -11,15 +12,15 @@ const SEP: u8 = b'|';
const KV_SEP: u8 = b'=';

/// Common coordinate type with x and y positions in nnaometers.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Location {
// These are nonpublic because we might want to combine `Location` and `LocationFract`
pub(crate) x: i32,
pub(crate) y: i32,
}

/// Location with fraction
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct LocationFract {
pub x: i32,
pub x_fract: i32,
Expand Down Expand Up @@ -60,6 +61,17 @@ impl Location {
}
}

impl LocationFract {
/// Sometimes we don't want to deal with fractions
#[inline]
pub fn as_location(self) -> Location {
Location {
x: self.x,
y: self.y,
}
}
}

impl From<(i32, i32)> for Location {
fn from(value: (i32, i32)) -> Self {
Self {
Expand All @@ -69,7 +81,7 @@ impl From<(i32, i32)> for Location {
}
}

#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
pub enum Visibility {
Hidden,
#[default]
Expand All @@ -86,9 +98,11 @@ impl FromUtf8<'_> for Visibility {
///
/// Every entity in Altium has a unique ID including files, library items, and records.
// TODO: figure out what file types use this exact format
#[derive(Clone, Copy, PartialEq)]
#[derive(Clone, Copy, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum UniqueId {
/// Altium's old style string unique ID
#[serde(with = "unique_id_serde")]
Simple([u8; 8]),
/// UUID style, used by some newer files
Uuid(Uuid),
Expand Down Expand Up @@ -139,6 +153,22 @@ impl FromUtf8<'_> for UniqueId {
}
}

mod unique_id_serde {
use serde::{de::Error, Deserialize, Deserializer, Serializer};

pub fn serialize<S: Serializer>(val: &[u8; 8], serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(std::str::from_utf8(val).unwrap())
}

pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<[u8; 8], D::Error> {
// let s = <String>::deserialize(deserializer);
let s: &str = Deserialize::deserialize(deserializer)?;
s.as_bytes()
.try_into()
.map_err(|_| D::Error::custom(format!("expected a 8-byte unique ID; got '{s}'")))
}
}

/// Altium uses the format `Key1=Val1|Key2=Val2...`, this handles that
pub fn split_altium_map(buf: &[u8]) -> impl Iterator<Item = (&[u8], &[u8])> {
buf.split(|b| *b == SEP).filter(|x| !x.is_empty()).map(|x| {
Expand Down Expand Up @@ -169,7 +199,7 @@ pub fn str_from_utf8(buf: &[u8]) -> Result<&str, ErrorKind> {
}

/// RGB color
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Rgb {
pub r: u8,
pub g: u8,
Expand Down Expand Up @@ -230,7 +260,7 @@ impl FromUtf8<'_> for Rgb {
}

/// Rotation when only 4 values are allowed
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum Rotation90 {
#[default]
R0 = 0,
Expand All @@ -256,7 +286,7 @@ impl FromUtf8<'_> for Rotation90 {
}
}

#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
pub enum ReadOnlyState {
#[default]
ReadWrite,
Expand Down
6 changes: 4 additions & 2 deletions altium/src/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

use std::ops::{Deref, DerefMut};

use serde::{Deserialize, Serialize};

lazy_static::lazy_static! {
pub(crate) static ref DEFAULT_FONT: Font = Font {
name: "Calibri".into(),
Expand All @@ -10,7 +12,7 @@ lazy_static::lazy_static! {
}

/// A font that is stored in a library
#[derive(Clone, Debug, Default, PartialEq)]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Font {
pub(crate) name: Box<str>,
pub(crate) size: u16,
Expand Down Expand Up @@ -41,7 +43,7 @@ impl Default for &Font {
//
// Or `Arc<RwLock<BTreeMap<u16, Arc<Font>>>>`. Yucky, but editable (edit the
// font if you're the only user duplicate it if you're not)
#[derive(Clone, Debug, Default, PartialEq)]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct FontCollection(Vec<Font>);

impl FontCollection {
Expand Down
4 changes: 3 additions & 1 deletion altium/src/sch/params.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Parameter types stored in a schematic

use serde::{Deserialize, Serialize};

use crate::{
common::{PosHoriz, PosVert},
parse::{FromUtf8, ParseUtf8},
Expand Down Expand Up @@ -87,7 +89,7 @@ impl FromUtf8<'_> for SheetStyle {
}

/// Allowed text alignments in a schematic
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
pub enum Justification {
#[default]
BottomLeft = 0,
Expand Down
7 changes: 4 additions & 3 deletions altium/src/sch/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::str::{self, Utf8Error};

use altium_macros::FromRecord;
use log::warn;
use serde::{Deserialize, Serialize};

use super::SchRecord;
use crate::common::{mils_to_nm, Location, Rotation90, Visibility};
Expand All @@ -18,7 +19,7 @@ use crate::{ErrorKind, Result, UniqueId};
/// Altium stores pins as binary in the schematic libraries but text in the
/// schematic documents, so we need to parse both.
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, FromRecord)]
#[derive(Clone, Debug, Default, PartialEq, FromRecord, Serialize, Deserialize)]
#[from_record(id = 2, record_variant = Pin)]
pub struct SchPin {
pub(super) formal_type: u8,
Expand Down Expand Up @@ -77,7 +78,7 @@ impl SchPin {
let (name, rest) = sized_buf_to_utf8(rest, "name")?;
let (designator, rest) = sized_buf_to_utf8(rest, "designator")?;

if !matches!(rest, [_, 0x03, b'|', b'&', b'|']) {
if !matches!(rest, [_, 0x03, b'|', b'&', b'|'] | [0x0, 0x0]) {
warn!("unexpected rest: {rest:02x?}");
}

Expand Down Expand Up @@ -175,7 +176,7 @@ fn get_rotation_and_hiding(val: u8) -> (Rotation90, Visibility, Visibility) {
}

#[repr(u8)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ElectricalType {
#[default]
Input = 0,
Expand Down
Loading

0 comments on commit 518c298

Please sign in to comment.