256 lines
7.6 KiB
Haskell
256 lines
7.6 KiB
Haskell
{-# LANGUAGE ForeignFunctionInterface, DeriveDataTypeable, GeneralizedNewtypeDeriving #-}
|
|
|
|
module HWiid ( BDAddr(..)
|
|
, Wiimote
|
|
, WiimoteState(..)
|
|
, WiimoteMesg(..)
|
|
, nullWiimote
|
|
, bdAddrAny
|
|
, hwiidFlagMesgInterface
|
|
, hwiidFlagNonblock
|
|
, hwiidReportStatus
|
|
, hwiidReportButtons
|
|
, hwiidLed1
|
|
, hwiidLed2
|
|
, hwiidLed3
|
|
, hwiidLed4
|
|
, hwiidButton2
|
|
, hwiidButton1
|
|
, hwiidButtonB
|
|
, hwiidButtonA
|
|
, hwiidButtonMinus
|
|
, hwiidButtonHome
|
|
, hwiidButtonLeft
|
|
, hwiidButtonRight
|
|
, hwiidButtonDown
|
|
, hwiidButtonUp
|
|
, hwiidButtonPlus
|
|
, hwiidNunchukButtonZ
|
|
, hwiidNunchukButtonC
|
|
, hwiidMesgTypeStatus
|
|
, hwiidMesgTypeButton
|
|
, hwiidOpen
|
|
, hwiidOpenTimeout
|
|
, hwiidClose
|
|
, hwiidGetState
|
|
, hwiidSetReportMode
|
|
, hwiidSetLed
|
|
, hwiidGetMesg
|
|
) where
|
|
|
|
|
|
import Data.Bits
|
|
import Data.Typeable
|
|
import Data.Word
|
|
import Foreign.C.Types
|
|
import Foreign.Marshal.Alloc (alloca, free)
|
|
import Foreign.Marshal.Array (peekArray)
|
|
import Foreign.Marshal.Utils (with)
|
|
import Foreign.Ptr
|
|
import Foreign.Storable
|
|
import System.Posix.Clock (TimeSpec)
|
|
|
|
#include <cwiid.h>
|
|
|
|
hwiidFlagMesgInterface :: CInt
|
|
hwiidFlagMesgInterface = (#const CWIID_FLAG_MESG_IFC)
|
|
|
|
hwiidFlagNonblock :: CInt
|
|
hwiidFlagNonblock = (#const CWIID_FLAG_NONBLOCK)
|
|
|
|
|
|
hwiidReportStatus :: Word8
|
|
hwiidReportStatus = (#const CWIID_RPT_STATUS)
|
|
|
|
hwiidReportButtons :: Word8
|
|
hwiidReportButtons = (#const CWIID_RPT_BTN)
|
|
|
|
|
|
hwiidLed1 :: Word8
|
|
hwiidLed1 = (#const CWIID_LED1_ON)
|
|
|
|
hwiidLed2 :: Word8
|
|
hwiidLed2 = (#const CWIID_LED2_ON)
|
|
|
|
hwiidLed3 :: Word8
|
|
hwiidLed3 = (#const CWIID_LED3_ON)
|
|
|
|
hwiidLed4 :: Word8
|
|
hwiidLed4 = (#const CWIID_LED4_ON)
|
|
|
|
|
|
hwiidButton2 :: Word16
|
|
hwiidButton2 = (#const CWIID_BTN_2)
|
|
|
|
hwiidButton1 :: Word16
|
|
hwiidButton1 = (#const CWIID_BTN_1)
|
|
|
|
hwiidButtonB :: Word16
|
|
hwiidButtonB = (#const CWIID_BTN_B)
|
|
|
|
hwiidButtonA :: Word16
|
|
hwiidButtonA = (#const CWIID_BTN_A)
|
|
|
|
hwiidButtonMinus :: Word16
|
|
hwiidButtonMinus = (#const CWIID_BTN_MINUS)
|
|
|
|
hwiidButtonHome :: Word16
|
|
hwiidButtonHome = (#const CWIID_BTN_HOME)
|
|
|
|
hwiidButtonLeft :: Word16
|
|
hwiidButtonLeft = (#const CWIID_BTN_LEFT)
|
|
|
|
hwiidButtonRight :: Word16
|
|
hwiidButtonRight = (#const CWIID_BTN_RIGHT)
|
|
|
|
hwiidButtonDown :: Word16
|
|
hwiidButtonDown = (#const CWIID_BTN_DOWN)
|
|
|
|
hwiidButtonUp :: Word16
|
|
hwiidButtonUp = (#const CWIID_BTN_UP)
|
|
|
|
hwiidButtonPlus :: Word16
|
|
hwiidButtonPlus = (#const CWIID_BTN_PLUS)
|
|
|
|
|
|
hwiidNunchukButtonZ :: Word16
|
|
hwiidNunchukButtonZ = (#const CWIID_NUNCHUK_BTN_Z)
|
|
|
|
hwiidNunchukButtonC :: Word16
|
|
hwiidNunchukButtonC = (#const CWIID_NUNCHUK_BTN_C)
|
|
|
|
|
|
hwiidMesgTypeStatus :: (#type enum cwiid_mesg_type)
|
|
hwiidMesgTypeStatus = (#const CWIID_MESG_STATUS)
|
|
|
|
hwiidMesgTypeButton :: (#type enum cwiid_mesg_type)
|
|
hwiidMesgTypeButton = (#const CWIID_MESG_BTN)
|
|
|
|
|
|
|
|
data BDAddr = BDAddr (Word8, Word8, Word8, Word8, Word8, Word8)
|
|
deriving (Eq, Ord, Show)
|
|
|
|
instance Storable BDAddr where
|
|
sizeOf _ = (#size bdaddr_t)
|
|
alignment _ = alignment (undefined :: CInt)
|
|
|
|
peek addr = do
|
|
b0 <- peekByteOff addr 0
|
|
b1 <- peekByteOff addr 1
|
|
b2 <- peekByteOff addr 2
|
|
b3 <- peekByteOff addr 3
|
|
b4 <- peekByteOff addr 4
|
|
b5 <- peekByteOff addr 5
|
|
return $ BDAddr (b0, b1, b2, b3, b4, b5)
|
|
|
|
poke addr (BDAddr (b0, b1, b2, b3, b4, b5)) = do
|
|
pokeByteOff addr 0 b0
|
|
pokeByteOff addr 1 b1
|
|
pokeByteOff addr 2 b2
|
|
pokeByteOff addr 3 b3
|
|
pokeByteOff addr 4 b4
|
|
pokeByteOff addr 5 b5
|
|
|
|
bdAddrAny :: BDAddr
|
|
bdAddrAny = BDAddr (0, 0, 0, 0, 0, 0)
|
|
|
|
|
|
data WiimoteState = WiimoteState
|
|
{ stateButtons :: Word16
|
|
} deriving (Eq, Show)
|
|
|
|
instance Storable WiimoteState where
|
|
sizeOf _ = (#size struct cwiid_state)
|
|
alignment _ = alignment (undefined :: CInt)
|
|
|
|
peek state = do
|
|
buttons <- (#peek struct cwiid_state, buttons) state
|
|
return $ WiimoteState (buttons)
|
|
|
|
poke state (WiimoteState (buttons)) = do
|
|
(#poke struct cwiid_state, buttons) state buttons
|
|
|
|
|
|
data WiimoteMesg = WiimoteStatusMesg
|
|
{ mesgType :: (#type enum cwiid_mesg_type)
|
|
, mesgBattery :: Word8
|
|
, mesgExtensionType :: (#type enum cwiid_ext_type)
|
|
}
|
|
| WiimoteButtonMesg
|
|
{ mesgType :: (#type enum cwiid_mesg_type)
|
|
, mesgButtons :: Word16
|
|
}
|
|
| WiimoteMesgUnknown
|
|
deriving (Eq, Show)
|
|
|
|
instance Storable WiimoteMesg where
|
|
sizeOf _ = (#size union cwiid_mesg)
|
|
alignment _ = alignment (undefined :: CInt)
|
|
|
|
peek mesg = do
|
|
mesgtype <- (#peek union cwiid_mesg, type) mesg
|
|
|
|
case () of
|
|
_ | mesgtype == hwiidMesgTypeStatus -> do
|
|
battery <- (#peek struct cwiid_status_mesg, battery) mesg
|
|
exttype <- (#peek struct cwiid_status_mesg, ext_type) mesg
|
|
return $ WiimoteStatusMesg mesgtype battery exttype
|
|
| mesgtype == hwiidMesgTypeButton -> do
|
|
buttons <- (#peek struct cwiid_btn_mesg, buttons) mesg
|
|
return $ WiimoteButtonMesg mesgtype buttons
|
|
| otherwise -> return WiimoteMesgUnknown
|
|
|
|
|
|
poke _ _ = error "Can't write WiimoteMesg"
|
|
|
|
|
|
newtype Wiimote = Wiimote (Ptr Wiimote) deriving (Eq, Ord, Show, Storable)
|
|
|
|
|
|
nullWiimote :: Wiimote
|
|
nullWiimote = Wiimote nullPtr
|
|
|
|
foreign import ccall unsafe "cwiid.h cwiid_open_timeout"
|
|
cwiid_open_timeout :: Ptr BDAddr -> CInt -> CInt -> IO Wiimote
|
|
|
|
hwiidOpenTimeout :: BDAddr -> CInt -> CInt -> IO Wiimote
|
|
hwiidOpenTimeout addr flags timeout = with addr $ \addrptr -> cwiid_open_timeout addrptr flags timeout
|
|
|
|
defaultTimeout :: CInt
|
|
defaultTimeout = 5
|
|
|
|
hwiidOpen :: BDAddr -> CInt -> IO Wiimote
|
|
hwiidOpen addr flags = hwiidOpenTimeout addr flags defaultTimeout
|
|
|
|
foreign import ccall unsafe "cwiid.h cwiid_close"
|
|
hwiidClose :: Wiimote -> IO CInt
|
|
|
|
foreign import ccall unsafe "cwiid.h cwiid_get_state"
|
|
cwiid_get_state :: Wiimote -> Ptr WiimoteState -> IO CInt
|
|
|
|
hwiidGetState :: Wiimote -> IO WiimoteState
|
|
hwiidGetState wiimote = alloca $ \state -> do
|
|
cwiid_get_state wiimote state
|
|
peek state
|
|
|
|
foreign import ccall unsafe "cwiid.h cwiid_set_rpt_mode"
|
|
hwiidSetReportMode :: Wiimote -> Word8 -> IO CInt
|
|
|
|
foreign import ccall unsafe "cwiid.h cwiid_set_led"
|
|
hwiidSetLed :: Wiimote -> Word8 -> IO CInt
|
|
|
|
foreign import ccall unsafe "cwiid.h cwiid_get_mesg"
|
|
cwiid_get_mesg :: Wiimote -> Ptr CInt -> Ptr (Ptr WiimoteMesg) -> Ptr TimeSpec -> IO CInt
|
|
|
|
hwiidGetMesg :: Wiimote -> IO [WiimoteMesg]
|
|
hwiidGetMesg wiimote = alloca $ \countptr -> alloca $ \arrayptr -> alloca $ \timestamp -> do
|
|
ret <- cwiid_get_mesg wiimote countptr arrayptr timestamp
|
|
count <- peek countptr
|
|
array <- peek arrayptr
|
|
|
|
if (ret == 0) then do
|
|
list <- peekArray (fromIntegral count) array
|
|
free array
|
|
return list
|
|
else return []
|