{- Canonnical representation Our IR (work in progress) -} module Data.GCode.Canon where import Data.ByteString (ByteString) import Data.GCode.Types (Axes, zeroAxes) import qualified Data.Map data Plane = XY | YZ | ZX | UV | WU | VW deriving (Show, Eq, Ord) data CutterCompenstationSide = CutterCompensationRight | CutterCompensationLeft | CutterCompensationOff deriving (Show, Eq, Ord) type Speed = Double type Seconds = Double data RotationDirection = ClockWise | CounterClockWise deriving (Show, Eq, Ord) data LengthUnit = Inches | MilliMeters | CentiMeters | Meters deriving (Show, Eq, Ord) data HeaterType = HeatedExtruder | HeatedBed | HeatedChamber deriving (Show, Eq, Ord) -- | Some heater with id or Nothing for current / default data Heater = Heater HeaterType (Maybe Int) deriving (Show, Eq, Ord) -- | Tool length compensation data CompensationMode = NoCompensation -- ^ Tool length compensation is disabled | LengthTable -- ^ Following moves will take into account tool offset from tool table | Dynamic Axes -- ^ Apply dynamic offset | Add Int -- ^ Add tool offset of the tool specified by the parameter to currently selected tool offset deriving (Show, Eq, Ord) -- Like linxucnc arcs, not used, subject to change data ArcParams = ArcParams { arcFirstEnd :: Double -- ^ first second coordinates according to selected plane , arcSecondEnd :: Double , arcFirstAxis :: Double , arcSecondAxis :: Double , arcRotation :: Int , arcAxisEndPoint :: Double , arcA :: Double , arcB :: Double , arcC :: Double , arcU :: Double , arcV :: Double , arcW :: Double } deriving (Eq, Show, Ord) data Canon = StraightTraverse Axes -- ^ Rapid motion to end position specified by Axes | StraightFeed Axes -- ^ Machining motion | StraightProbe Axes -- ^ Straight probe towards workpeice | SetCoords Axes -- ^ Set coordinates to provided values without motion | ArcFeed ArcParams -- ^ Movement along arc | ProgramEnd -- ^ End of the program | SetFeedRate Speed -- ^ Set feed rate for machining moves | SetTraverseRate Speed -- ^ Set feed rate for travel moves | PlaneSelect Plane -- ^ Set plane | PauseSeconds Double -- ^ Do nothing for specified number of seconds | SpindleStart { spindleDirection :: RotationDirection -- ^ Rotate spindle according to `RotationDirection` , spindleWaitForSpeed :: Bool -- ^ Wait for spindle to reach desired RPM } | SpindleStop -- ^ Stop spindle | SpindleSpeed Speed -- ^ Set spindle RPM | CoolantMist -- ^ Enable mist coolant | CoolantFlood -- ^ Enable flood coolant | CoolantStop -- ^ Stop all coolant flows -- Tools | ToolSelect Int -- ^ Select tool by its index | ToolChange -- ^ Perform tool change | ToolLengthCompensation CompensationMode -- ^ Enable tool length compensation -- Printer | FanOn -- ^ Enable fan | FanOff -- ^ Disable fan | SetTemperature Heater Double -- ^ Set temperature of the specific heater | SetTemperatureWait Heater Double -- ^ Set temperature and wait for it to be reached | CancelWaitTemperature -- ^ Cancel all temperature waits | LevelBed -- ^ Perform automated bed leveling -- Misc | DisableMotors Axes -- ^ Disable power to motors | DisplayMessage ByteString -- ^ Display a message, typically on LCD | Comment ByteString -- ^ Just a comment deriving (Show, Eq, Ord) -- | State of the Canon interpreter data CanonState = CanonState { canonPosition :: Axes -- ^ Position , canonTraverseRate :: Speed -- ^ Speed for travel moves , canonFeedRate :: Speed -- ^ Speed for machining moves , canonPlane :: Plane -- ^ Selected plane } deriving (Show, Eq, Ord) -- | Initial state of the Canon interpreter initCanonState :: CanonState initCanonState = CanonState { canonPosition = zeroAxes , canonTraverseRate = 0 , canonFeedRate = 0 , canonPlane = XY } -- | Step Canon interpreter, returning new state stepCanon :: CanonState -> Canon -> CanonState stepCanon s (StraightTraverse a) = s { canonPosition = Data.Map.union a (canonPosition s) } stepCanon s (StraightFeed a) = s { canonPosition = Data.Map.union a (canonPosition s) } stepCanon s (SetFeedRate r) = s { canonFeedRate = r } stepCanon s (SetTraverseRate r) = s { canonTraverseRate = r } stepCanon s (SetCoords a) = s { canonPosition = Data.Map.union a (canonPosition s) } stepCanon s (PlaneSelect p) = s { canonPlane = p } -- | Fully eval list of `Canon` commands. -- -- Slow, only useful for testing, use `Data.GCode.Pipes` variant instead evalCanon :: (CanonState -> CanonState -> Canon -> [a]) -> [Canon] -> [a] evalCanon f cs = go initCanonState cs where go _ [] = [] go st (c:rest) = let newSt = stepCanon st c in (f st newSt c) ++ (go newSt rest)