{-# LINE 1 "System/CWiid.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LINE 2 "System/CWiid.hsc" #-}

module System.CWiid
       (cwiidOpen, cwiidSetLed, cwiidSetRptMode, cwiidGetBtnState,
        cwiidLed1, cwiidLed2, cwiidLed3, cwiidLed4, combineCwiidLedFlag,
        cwiidBtn2, cwiidBtn1, cwiidBtnB, cwiidBtnA, cwiidBtnMinus,
        cwiidBtnHome, cwiidBtnLeft, cwiidBtnRight, cwiidBtnDown, cwiidBtnUp,
        cwiidBtnPlus, combineCwiidBtnFlag, diffCwiidBtnFlag,
        CWiidBtnFlag(..), CWiidState(..), CWiidWiimote) where

-- import Foreign.C.Error
import Data.Bits
import Foreign.C.Types
import Foreign.Marshal
import Foreign.Ptr
import Foreign.Storable


{-# LINE 19 "System/CWiid.hsc" #-}

-----------------------------------------------------------------------------
-- Data type
---

-- typedef struct {
--         uint8_t b[6];
-- } __attribute__((packed)) bdaddr_t;
-- #define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
data CWiidBdaddr = CWiidBdaddr Int Int Int Int Int Int
instance Storable CWiidBdaddr where
  sizeOf = const (6)
{-# LINE 31 "System/CWiid.hsc" #-}
  alignment = sizeOf
  poke bdat (CWiidBdaddr b0 b1 b2 b3 b4 b5) = do
    ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) bdat b0
{-# LINE 34 "System/CWiid.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 1)) bdat b1
{-# LINE 35 "System/CWiid.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 2)) bdat b2
{-# LINE 36 "System/CWiid.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 3)) bdat b3
{-# LINE 37 "System/CWiid.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 4)) bdat b4
{-# LINE 38 "System/CWiid.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 5)) bdat b5
{-# LINE 39 "System/CWiid.hsc" #-}
  peek bdat = do
    b0 <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) bdat
{-# LINE 41 "System/CWiid.hsc" #-}
    b1 <- ((\hsc_ptr -> peekByteOff hsc_ptr 1)) bdat
{-# LINE 42 "System/CWiid.hsc" #-}
    b2 <- ((\hsc_ptr -> peekByteOff hsc_ptr 2)) bdat
{-# LINE 43 "System/CWiid.hsc" #-}
    b3 <- ((\hsc_ptr -> peekByteOff hsc_ptr 3)) bdat
{-# LINE 44 "System/CWiid.hsc" #-}
    b4 <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) bdat
{-# LINE 45 "System/CWiid.hsc" #-}
    b5 <- ((\hsc_ptr -> peekByteOff hsc_ptr 5)) bdat
{-# LINE 46 "System/CWiid.hsc" #-}
    return $ CWiidBdaddr b0 b1 b2 b3 b4 b5

-- typedef struct wiimote cwiid_wiimote_t;
newtype CWiidWiimote = CWiidWiimote { unCWiidWiimote :: Ptr () }

{--
struct cwiid_state {
        uint8_t rpt_mode;
        uint8_t led;
        uint8_t rumble;
        uint8_t battery;
        uint16_t buttons;
        uint8_t acc[3];
        struct cwiid_ir_src ir_src[CWIID_IR_SRC_COUNT];
        enum cwiid_ext_type ext_type;
        union ext_state ext;
        enum cwiid_error error;
};
--}
newtype CWiidLedFlag = CWiidLedFlag { unCWiidLedFlag :: Int }
                     deriving (Eq, Show)
cwiidLed1  :: CWiidLedFlag
cwiidLed1  = CWiidLedFlag 1
cwiidLed2  :: CWiidLedFlag
cwiidLed2  = CWiidLedFlag 2
cwiidLed3  :: CWiidLedFlag
cwiidLed3  = CWiidLedFlag 4
cwiidLed4  :: CWiidLedFlag
cwiidLed4  = CWiidLedFlag 8

{-# LINE 73 "System/CWiid.hsc" #-}
combineCwiidLedFlag :: [CWiidLedFlag] -> CWiidLedFlag
combineCwiidLedFlag = CWiidLedFlag . foldr ((.|.) . unCWiidLedFlag) 0

newtype CWiidBtnFlag = CWiidBtnFlag { unCWiidBtnFlag :: Int }
                     deriving (Eq, Show)
cwiidBtn2      :: CWiidBtnFlag
cwiidBtn2      = CWiidBtnFlag 1
cwiidBtn1      :: CWiidBtnFlag
cwiidBtn1      = CWiidBtnFlag 2
cwiidBtnB      :: CWiidBtnFlag
cwiidBtnB      = CWiidBtnFlag 4
cwiidBtnA      :: CWiidBtnFlag
cwiidBtnA      = CWiidBtnFlag 8
cwiidBtnMinus  :: CWiidBtnFlag
cwiidBtnMinus  = CWiidBtnFlag 16
cwiidBtnHome   :: CWiidBtnFlag
cwiidBtnHome   = CWiidBtnFlag 128
cwiidBtnLeft   :: CWiidBtnFlag
cwiidBtnLeft   = CWiidBtnFlag 256
cwiidBtnRight  :: CWiidBtnFlag
cwiidBtnRight  = CWiidBtnFlag 512
cwiidBtnDown   :: CWiidBtnFlag
cwiidBtnDown   = CWiidBtnFlag 1024
cwiidBtnUp     :: CWiidBtnFlag
cwiidBtnUp     = CWiidBtnFlag 2048
cwiidBtnPlus   :: CWiidBtnFlag
cwiidBtnPlus   = CWiidBtnFlag 4096

{-# LINE 91 "System/CWiid.hsc" #-}
combineCwiidBtnFlag :: [CWiidBtnFlag] -> CWiidBtnFlag
combineCwiidBtnFlag = CWiidBtnFlag . foldr ((.|.) . unCWiidBtnFlag) 0
diffCwiidBtnFlag :: CWiidBtnFlag -> CWiidBtnFlag -> CWiidBtnFlag
diffCwiidBtnFlag a b = CWiidBtnFlag $ ai - (ai .&. bi)
  where ai = unCWiidBtnFlag a
        bi = unCWiidBtnFlag b

data CWiidState = CWiidState { rptMode :: Int, led :: Int, rumble :: Int, 
                               battery :: Int, buttons :: Int } -- xxx 定義不足
                deriving Show
instance Storable CWiidState where
  sizeOf = const (60)
{-# LINE 103 "System/CWiid.hsc" #-}
  alignment = sizeOf
  poke cwst (CWiidState rp l ru ba bu) = do
    ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) cwst rp
{-# LINE 106 "System/CWiid.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 1)) cwst l
{-# LINE 107 "System/CWiid.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 2)) cwst ru
{-# LINE 108 "System/CWiid.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 3)) cwst ba
{-# LINE 109 "System/CWiid.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 4)) cwst bu
{-# LINE 110 "System/CWiid.hsc" #-}
  peek cwst = do
    rp <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) cwst
{-# LINE 112 "System/CWiid.hsc" #-}
    l <- ((\hsc_ptr -> peekByteOff hsc_ptr 1)) cwst
{-# LINE 113 "System/CWiid.hsc" #-}
    ru <- ((\hsc_ptr -> peekByteOff hsc_ptr 2)) cwst
{-# LINE 114 "System/CWiid.hsc" #-}
    ba <- ((\hsc_ptr -> peekByteOff hsc_ptr 3)) cwst
{-# LINE 115 "System/CWiid.hsc" #-}
    bu <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) cwst
{-# LINE 116 "System/CWiid.hsc" #-}
    return $ CWiidState rp l ru ba bu

-----------------------------------------------------------------------------
-- Haskell land
---
-- wiimote = cwiid_open(&bdaddr, 0)))
cwiidOpen :: IO (Maybe CWiidWiimote)
cwiidOpen =
  alloca $ \bdAddr -> do
    poke bdAddr $ CWiidBdaddr 0 0 0 0 0 0
    handle <- c_cwiid_open bdAddr 0 -- エラー処理必要
    if handle == nullPtr
      then return Nothing
      else return $ Just $ CWiidWiimote handle

cwiidSetLed :: CWiidWiimote -> IO CInt
cwiidSetLed wm = c_cwiid_set_led  handle 9 -- set on LED 1 and 4
  where handle = unCWiidWiimote wm

cwiidSetRptMode :: CWiidWiimote -> IO CInt
cwiidSetRptMode wm = c_cwiid_set_rpt_mode handle 2 -- set BTN
  where handle = unCWiidWiimote wm

cwiidGetBtnState :: CWiidWiimote -> IO CWiidBtnFlag
cwiidGetBtnState wm =
  alloca $ \wiState -> do
    _ <- c_cwiid_get_state handle wiState
    ws <- peek wiState
    return $ CWiidBtnFlag $ buttons ws
      where handle = unCWiidWiimote wm

-----------------------------------------------------------------------------
-- C land
---
-- Haskell => C
---

-- cwiid_wiimote_t *cwiid_open(bdaddr_t *bdaddr, int flags)
foreign import ccall safe "cwiid_open" c_cwiid_open
  :: Ptr CWiidBdaddr -> CInt -> IO (Ptr ())

-- typedef unsigned char             uint8_t
-- int cwiid_set_led(cwiid_wiimote_t *wiimote, uint8_t led)
foreign import ccall safe "cwiid_set_led" c_cwiid_set_led
  :: Ptr () -> CUChar -> IO CInt

-- int cwiid_set_rpt_mode(cwiid_wiimote_t *wiimote, uint8_t rpt_mode);
foreign import ccall safe "cwiid_set_rpt_mode" c_cwiid_set_rpt_mode
  :: Ptr () -> CUChar -> IO CInt

-- int cwiid_get_state(cwiid_wiimote_t *wiimote, struct cwiid_state *state);
foreign import ccall safe "cwiid_get_state" c_cwiid_get_state
  :: Ptr () -> Ptr CWiidState -> IO CInt


-- C => Haskell
---

-- int cwiid_set_mesg_callback(cwiid_wiimote_t *wiimote,
--                             cwiid_mesg_callback_t *callback)
-- xxxxx
-- typedef void cwiid_mesg_callback_t(cwiid_wiimote_t *, int,
--                                    union cwiid_mesg [], struct timespec *)
-- xxxxx