module Data.GCode.Canon.Convert where
import Control.Applicative
import Data.GCode.Types (Code(..), Class(..), Axes, ParamDesignator(..))
import Data.GCode.Canon (Canon(..))
import qualified Data.Map
import qualified Data.GCode.Canon as C
import qualified Data.GCode.Types as T
import Data.GCode.RS274
import Data.GCode.Utils
toCanon :: Code -> [Canon]
toCanon c | isRapid c =
ifHasParam F c C.SetTraverseRate
<> ifNonEmptyAxes c C.StraightTraverse
toCanon c | isMove c =
ifHasParam F c C.SetFeedRate
<> ifNonEmptyAxes c C.StraightFeed
toCanon c | isCoordinateSystemOffset c = pure $ C.SetCoords (codeAxes c)
toCanon c | isDwell c
= pure . C.PauseSeconds $ getParamOrFail P c "No P for Dwell"
toCanon c | isMillimeters c = empty
toCanon c | isInches c = empty
toCanon c | isAbsolute c = empty
toCanon c | isRelative c = empty
toCanon c | isXYPlane c = pure $ C.PlaneSelect C.XY
toCanon c | isZXPlane c = pure $ C.PlaneSelect C.ZX
toCanon c | isYZPlane c = pure $ C.PlaneSelect C.YZ
toCanon c | isUVPlane c = pure $ C.PlaneSelect C.UV
toCanon c | isWUPlane c = pure $ C.PlaneSelect C.WU
toCanon c | isVWPlane c = pure $ C.PlaneSelect C.VW
toCanon Code { codeCls = Just FStandalone, codeNum = Just newFeed }
= pure $ C.SetFeedRate $ fromIntegral newFeed
toCanon Code { codeCls = Just SStandalone, codeNum = Just spindleRPM }
= pure $ C.SpindleSpeed $ fromIntegral spindleRPM
toCanon c | isUnitsPerMinute c = empty
toCanon c | isUnitsPerRevolution c = error "Don't know how to handle units per revolution"
toCanon c | isSpindleCW c = pure C.SpindleStart
{ spindleDirection = C.ClockWise
, spindleWaitForSpeed = True }
toCanon c | isSpindleCCW c = pure C.SpindleStart
{ spindleDirection = C.CounterClockWise
, spindleWaitForSpeed = True }
toCanon c | isSpindleStop c = pure C.SpindleStop
toCanon c | isCoolantMist c = pure C.CoolantMist
toCanon c | isCoolantFlood c = pure C.CoolantFlood
toCanon c | isCoolantStop c = pure C.CoolantStop
toCanon c | isToolChange c = pure C.ToolChange
toCanon (Code{codeCls=(Just T), codeNum=(Just toolId)}) = pure $ C.ToolSelect toolId
toCanon c | isToolLength c = pure $ C.ToolLengthCompensation C.LengthTable
toCanon c | isToolLengthDynamic c = pure $ C.ToolLengthCompensation $ C.Dynamic
(codeAxes c)
toCanon c | isToolLengthAdd c = pure $ C.ToolLengthCompensation $ C.Add
(round $ getParamOrFail H c "Add tool change offset requires H parameter of the tool to grab offset from")
toCanon c | isToolLengthCancel c = pure $ C.ToolLengthCompensation C.NoCompensation
toCanon c | isExtruderAbsolute c = empty
toCanon c | isExtruderRelative c = empty
toCanon c | isSetExtruderTemperature c = pure $ C.SetTemperature
(C.Heater C.HeatedExtruder $ round <$> getParam P c)
(getParamOrFail S c "Set extruder temperature command missing S parameter for temperature value")
toCanon c | isSetBedTemperature c = pure $ C.SetTemperature
(C.Heater C.HeatedBed $ round <$> getParam P c)
(getParamOrFail S c "Set bed temperature command missing S parameter for temperature value")
toCanon c | isSetChamberTemperature c = pure $ C.SetTemperature
(C.Heater C.HeatedChamber $ round <$> getParam P c)
(getParamOrFail S c "Set heated chamber temperature command missing S parameter for temperature value")
toCanon c | isCancelWaitTemperature c = pure $ C.CancelWaitTemperature
toCanon c | isSetExtruderTemperatureAndWait c = pure $ C.SetTemperatureWait
(C.Heater C.HeatedExtruder $ round <$> getParam P c)
(getParamOrFail S c "Set extruder temperature and wait command missing S parameter for temperature value")
toCanon c | isSetBedTemperatureAndWait c = pure $ C.SetTemperatureWait
(C.Heater C.HeatedBed $ round <$> getParam P c)
(getParamOrFail S c "Set bed temperature and wait command missing S parameter for temperature value")
toCanon c | isSetChamberTemperatureAndWait c = pure $ C.SetTemperatureWait
(C.Heater C.HeatedChamber $ round <$> getParam P c)
(getParamOrFail S c "Set chamber temperature and wait command missing S parameter for temperature value")
toCanon c | isCancelWaitTemperature c = pure $ C.CancelWaitTemperature
toCanon c | isFanOn c = pure C.FanOn
toCanon c | isFanOff c = pure C.FanOff
toCanon c | isGN 28 c = empty
toCanon c | isAutoBedLevel c = pure C.LevelBed
toCanon c | isDisplayMessage c = empty
toCanon c | isDisableActuators c = pure $ C.DisableMotors (codeAxes c)
toCanon c | isProgramEnd c = pure C.ProgramEnd
toCanon c | isCommentOnly c = pure $ C.Comment (codeComment c)
toCanon (T.Comment c) = pure $ C.Comment c
toCanon Empty = empty
toCanon (Other _) = empty
toCanon c = error $ "No canon for " ++ show c
ifHasParam :: (Monoid (f a), Applicative f)
=> ParamDesignator
-> Code
-> (Double -> a)
-> f a
ifHasParam p c f = case getParam p c of
Nothing -> mempty
Just val -> pure $ f val
ifNonEmptyAxes :: (Applicative f, Monoid (f a))
=> Code
-> (Axes -> a)
-> f a
ifNonEmptyAxes c f | codeAxes c /= mempty = pure $ f (codeAxes c)
ifNonEmptyAxes _ _ | otherwise = mempty
getParamOrFail :: ParamDesignator
-> Code
-> [Char]
-> Double
getParamOrFail param code msg = maybe (error msg) id (getParam param code)
isCommentOnly :: Code -> Bool
isCommentOnly (Code { codeCls = Nothing
, codeNum = Nothing
, codeSub = Nothing
, codeAxes = a
, codeParams = p
, codeComment = x }) |
Data.Map.null a && Data.Map.null p &&
x /= mempty = True
isCommentOnly _ = False