packages feed

RMP-0.0.2: src/System/RMP.hs

-- TODO: Check for null pointers and fail appropriately. perhaps use the ForeignPtrWrap module.

module System.RMP where

import System.RMP.USB
import Foreign
import Foreign.C.Types
import Control.Processor(IOProcessor, wrapProcessor, processor)
import Control.Arrow((>>>),arr)

type Packet = Ptr RMPPacket

data RMPState = RMPState { rmpCtx :: Ptr RMPUSB, rmpReadPkt :: Packet }

-- | A processor wrapper: Takes the robot controller (something that reads telemetries and sends commands)
-- and returns an IOProcessor that runs the robot.
rmp :: IOProcessor Packet Packet -> IOProcessor () ()
rmp = wrapProcessor readPacket writePacket allocRMP readConv writeConv releaseRMP 
    where 
      readPacket :: () -> RMPState -> IO RMPState
      readPacket _ state = do
        res <- rmpUsbReadPacket (rmpCtx state) (rmpReadPkt state)
        -- todo: deal with res != 0
        return state
      
      readConv :: RMPState -> IO Packet
      readConv = return . rmpReadPkt
      
      writePacket :: Packet -> RMPState -> IO RMPState
      writePacket pkt state = do
        res <- rmpUsbWritePacket (rmpCtx state) pkt
        -- todo: deal with res != 0
        return state
      
      writeConv :: RMPState -> IO ()
      writeConv = const (return ())
      
      allocRMP :: () -> IO RMPState
      allocRMP _ = do
        ctx <- rmpUsbNew
        rPkt <- rmpPacketNew
        return (RMPState ctx rPkt)
      
      releaseRMP :: RMPState -> IO ()
      releaseRMP state = do
        rmpPacketDelete (rmpReadPkt state)
        rmpUsbDelete (rmpCtx state)

-----------------------------------------------------------------------------

velocityPacket :: Integral a => IOProcessor (a, a) Packet
velocityPacket = processor proc alloc conv release 
    where
      proc :: Integral a => (a,a) -> Packet -> IO Packet
      proc (trans, rot) pkt = do
        rmpPacketSetCommandVelocity pkt (fromIntegral trans) (fromIntegral rot)
        return pkt
        
      alloc :: Integral a => (a,a) -> IO Packet
      alloc _ = do
        pkt <- rmpPacketNew
        return pkt

      conv :: Packet -> IO Packet
      conv = return
      
      release :: Packet -> IO ()
      release pkt = do
        rmpPacketDelete pkt
      


-- data Packet = Empty 
--             | PitchRoll { pitchAngle :: Double; pitchRate :: Double, rollAngle :: Double, rollRate :: Double }
--             | VelocityYaw { wheelsVelocity :: (Double, Double), yawRate :: Double }
--             | WheelDisplacement { wheelsDisplacement :: (Double, Double) }

      
-----------------------------------------------------------------------------

-- | A dummy version of rmp that:
--        
-- 1. Does not read from the robot (Ignores all robot telemetries)
--
-- 2. Can only send commands
--
-- it's really an IOSink.
--
simpleRMP :: IOProcessor Packet ()
simpleRMP = processor writePacket allocRMP writeConv releaseRMP 
    where 
      writePacket :: Packet -> (Ptr RMPUSB) -> IO (Ptr RMPUSB)
      writePacket pkt rmpUsb = do
        res <- rmpUsbWritePacket rmpUsb pkt
        -- todo: deal with res != 0
        return rmpUsb
      
      writeConv :: (Ptr RMPUSB) -> IO ()
      writeConv = const . return $ ()
      
      allocRMP :: Packet -> IO (Ptr RMPUSB)
      allocRMP _ = rmpUsbNew
      
      releaseRMP :: (Ptr RMPUSB) -> IO ()
      releaseRMP = rmpUsbDelete


-- | An even simple RMP interface, that supports only sending velocity commands, and nothing more.
velocityRMP :: Integral a => IOProcessor (a,a) ()
velocityRMP = velocityPacket >>> simpleRMP