{-# LANGUAGE TypeApplications #-}
module Network.SocketCAN.LowLevel
  ( socket
  , bind
  , send
  , recv
  , module Network.Socket
  ) where

import Control.Monad (void)
import Foreign.Ptr (Ptr)
import Network.Socket (Family(AF_CAN), Socket, close)
import Network.SocketCAN.Bindings (SockAddrCAN(..), SocketCANFrame)

import qualified Foreign.Ptr
import qualified Foreign.Marshal.Alloc
import qualified Foreign.Storable
import qualified Network.Socket
import qualified Network.Socket.Address
import qualified Network.SocketCAN.Bindings

-- | Create raw CAN socket
socket
  :: IO Socket
socket :: IO Socket
socket =
  Family -> SocketType -> ProtocolNumber -> IO Socket
Network.Socket.socket
    Family
AF_CAN
    SocketType
Network.Socket.Raw
    ProtocolNumber
Network.SocketCAN.Bindings.CAN_RAW

-- | Bind CAN socket
bind
  :: Socket
  -> SockAddrCAN
  -> IO ()
bind :: Socket -> SockAddrCAN -> IO ()
bind = Socket -> SockAddrCAN -> IO ()
forall sa. SocketAddress sa => Socket -> sa -> IO ()
Network.Socket.Address.bind

send
  :: Socket
  -> SocketCANFrame
  -> IO ()
send :: Socket -> SocketCANFrame -> IO ()
send Socket
canSock SocketCANFrame
cf =
  (Ptr SocketCANFrame -> IO ()) -> IO ()
forall a b. Storable a => (Ptr a -> IO b) -> IO b
Foreign.Marshal.Alloc.alloca ((Ptr SocketCANFrame -> IO ()) -> IO ())
-> (Ptr SocketCANFrame -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr SocketCANFrame
ptr -> do
    Ptr SocketCANFrame -> SocketCANFrame -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
Foreign.Storable.poke Ptr SocketCANFrame
ptr SocketCANFrame
cf
    IO Int -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void
      (IO Int -> IO ()) -> IO Int -> IO ()
forall a b. (a -> b) -> a -> b
$ Socket -> Ptr Word8 -> Int -> IO Int
Network.Socket.sendBuf
          Socket
canSock
          (Ptr SocketCANFrame -> Ptr Word8
forall a b. Ptr a -> Ptr b
Foreign.Ptr.castPtr Ptr SocketCANFrame
ptr)
          (SocketCANFrame -> Int
forall a. Storable a => a -> Int
Foreign.Storable.sizeOf SocketCANFrame
cf)

recv
  :: Socket
  -> IO SocketCANFrame
recv :: Socket -> IO SocketCANFrame
recv Socket
canSock =
  (Ptr SocketCANFrame -> IO SocketCANFrame) -> IO SocketCANFrame
forall a b. Storable a => (Ptr a -> IO b) -> IO b
Foreign.Marshal.Alloc.alloca ((Ptr SocketCANFrame -> IO SocketCANFrame) -> IO SocketCANFrame)
-> (Ptr SocketCANFrame -> IO SocketCANFrame) -> IO SocketCANFrame
forall a b. (a -> b) -> a -> b
$ \Ptr SocketCANFrame
ptr -> do
    (Int
_nBytes, SockAddrCAN
_sockAddr) <-
      forall sa a.
SocketAddress sa =>
Socket -> Ptr a -> Int -> IO (Int, sa)
Network.Socket.Address.recvBufFrom
        @SockAddrCAN
        Socket
canSock
        (Ptr SocketCANFrame
ptr :: Ptr SocketCANFrame)
        (SocketCANFrame -> Int
forall a. Storable a => a -> Int
Foreign.Storable.sizeOf (SocketCANFrame
forall a. HasCallStack => a
undefined :: SocketCANFrame))
    Ptr SocketCANFrame -> IO SocketCANFrame
forall a. Storable a => Ptr a -> IO a
Foreign.Storable.peek Ptr SocketCANFrame
ptr IO SocketCANFrame
-> (SocketCANFrame -> IO SocketCANFrame) -> IO SocketCANFrame
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= SocketCANFrame -> IO SocketCANFrame
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure