From ab4591cb0e074ce98c24645cdb80cb5012aed566 Mon Sep 17 00:00:00 2001 From: Paul Oliver Date: Fri, 7 Feb 2025 17:10:05 +0000 Subject: Initial --- hsm-drive/Hsm/Drive.hs | 105 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 hsm-drive/Hsm/Drive.hs (limited to 'hsm-drive/Hsm/Drive.hs') diff --git a/hsm-drive/Hsm/Drive.hs b/hsm-drive/Hsm/Drive.hs new file mode 100644 index 0000000..dffb8dc --- /dev/null +++ b/hsm-drive/Hsm/Drive.hs @@ -0,0 +1,105 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE OverloadedRecordDot #-} +{-# LANGUAGE OverloadedStrings #-} + +module Hsm.Drive + ( Speed(Slow, Medium, Fast) + , Direction(Forward, Backward) + , Duration + , DriveEnv(..) + , Command(Move) + , pwmMapperDefault + , driveEnvDefault + , drive + ) where + +import Control.Concurrent (threadDelay) +import Data.Text (pack) +import Data.Typeable (Typeable) +import Foreign.Ptr (Ptr) +import GHC.Records (HasField) +import Hsm.GPIO (GPIO(..), LineRequest, active, inactive, setPins) +import Hsm.Log qualified as L +import Hsm.PWM (PWMChannel(PWM3), PWMHandle, setDutyCycle) + +data Speed + = Slow + | Medium + | Fast + deriving (Read, Show, Typeable) + +data Direction + = Forward + | Backward + deriving (Read, Show, Typeable) + +type Duration = Float + +data Command + = Move Speed Direction Duration + | Stop Duration + deriving (Read, Show, Typeable) + +data DriveEnv = DriveEnv + { gpioM1F :: GPIO + , gpioM1B :: GPIO + , gpioM2F :: GPIO + , gpioM2B :: GPIO + , gpioM3F :: GPIO + , gpioM3B :: GPIO + , gpioM4F :: GPIO + , gpioM4B :: GPIO + , pwmChannel :: PWMChannel + , pwmPeriod :: Int + , pwmMapper :: Speed -> Int + } + +pwmMapperDefault :: Speed -> Int +pwmMapperDefault Slow = 500000 +pwmMapperDefault Medium = 750000 +pwmMapperDefault Fast = 1000000 + +driveEnvDefault :: DriveEnv +driveEnvDefault = + DriveEnv + { gpioM1F = GPIO24 + , gpioM1B = GPIO25 + , gpioM2F = GPIO8 + , gpioM2B = GPIO7 + , gpioM3F = GPIO12 + , gpioM3B = GPIO16 + , gpioM4F = GPIO20 + , gpioM4B = GPIO21 + , pwmChannel = PWM3 + , pwmPeriod = 1000000 -- 1ms + , pwmMapper = pwmMapperDefault + } + +drive :: + HasField "driveEnv" env DriveEnv + => PWMHandle + -> Ptr LineRequest + -> env + -> [Command] + -> IO Bool +drive pwmHandle lineRequest env commands = do + mapM_ runCommand commands + return True + where + logMsg = L.logMsg ["drive"] + pinsForward = [gpioM1F, gpioM2F, gpioM3F, gpioM4F] <*> [env.driveEnv] + pinsBackward = [gpioM1B, gpioM2B, gpioM3B, gpioM4B] <*> [env.driveEnv] + toMicroSeconds = round . (* 1000000) + runCommand command = do + logMsg $ "Running command: " <> pack (show command) + case command of + (Move speed direction duration) -> do + case direction of + Forward -> setPins lineRequest pinsForward active + Backward -> setPins lineRequest pinsBackward active + setDutyCycle pwmHandle env.driveEnv.pwmChannel + $ env.driveEnv.pwmMapper speed + threadDelay $ toMicroSeconds duration + setDutyCycle pwmHandle env.driveEnv.pwmChannel 0 + setPins lineRequest (pinsForward <> pinsBackward) inactive + (Stop duration) -> threadDelay $ toMicroSeconds duration -- cgit v1.2.1