module System.USB.IO.StandardDeviceRequests
( setHalt
, clearRemoteWakeup
, setRemoteWakeup
, setStandardTestMode, TestMode(..)
, getInterfaceAltSetting
, getDeviceStatus
, getEndpointStatus
, setDeviceAddress
, synchFrame, FrameNumber
) where
import Data.Bits ( testBit, shiftL )
import Data.Bool ( Bool )
import Data.Data ( Data )
import Data.Eq ( Eq )
import Data.Functor ( (<$>) )
import Data.Typeable ( Typeable )
import Data.Word ( Word8, Word16 )
import Prelude ( (+), fromInteger, fromIntegral, Enum )
import System.IO ( IO )
import Text.Read ( Read )
import Text.Show ( Show )
import Data.Eq.Unicode ( (≡) )
import Data.Function.Unicode ( (∘) )
import Prelude.Unicode ( (⋅) )
import qualified Data.ByteString as B ( head, unpack )
import Bindings.Libusb ( c'LIBUSB_REQUEST_SET_FEATURE
, c'LIBUSB_REQUEST_CLEAR_FEATURE
, c'LIBUSB_REQUEST_GET_INTERFACE
, c'LIBUSB_REQUEST_GET_STATUS
, c'LIBUSB_REQUEST_SET_ADDRESS
, c'LIBUSB_REQUEST_SYNCH_FRAME
)
import System.USB.DeviceHandling ( DeviceHandle
, InterfaceNumber
, InterfaceAltSetting
)
import System.USB.Descriptors ( EndpointAddress
, DeviceStatus(..)
)
import System.USB.IO.Synchronous ( Timeout
, RequestType(Standard)
, Recipient( ToDevice
, ToInterface
, ToEndpoint
)
, Value
, control, readControlExact
)
import System.USB.Unsafe ( marshalEndpointAddress )
import Utils ( genFromEnum )
haltFeature, remoteWakeupFeature, testModeFeature ∷ Value
haltFeature = 0
remoteWakeupFeature = 1
testModeFeature = 2
setHalt ∷ DeviceHandle → EndpointAddress → (Timeout → IO ())
setHalt devHndl endpointAddr =
control devHndl
Standard
ToEndpoint
c'LIBUSB_REQUEST_SET_FEATURE
haltFeature
(marshalEndpointAddress endpointAddr)
clearRemoteWakeup ∷ DeviceHandle → (Timeout → IO ())
clearRemoteWakeup devHndl =
control devHndl
Standard
ToDevice
c'LIBUSB_REQUEST_CLEAR_FEATURE
remoteWakeupFeature
0
setRemoteWakeup ∷ DeviceHandle → (Timeout → IO ())
setRemoteWakeup devHndl =
control devHndl
Standard
ToDevice
c'LIBUSB_REQUEST_SET_FEATURE
remoteWakeupFeature
0
setStandardTestMode ∷ DeviceHandle → TestMode → (Timeout → IO ())
setStandardTestMode devHndl testMode =
control devHndl
Standard
ToDevice
c'LIBUSB_REQUEST_SET_FEATURE
testModeFeature
((genFromEnum testMode + 1) `shiftL` 8)
data TestMode = Test_J
| Test_K
| Test_SE0_NAK
| Test_Packet
| Test_Force_Enable
deriving (Eq, Show, Read, Enum, Data, Typeable)
getInterfaceAltSetting ∷ DeviceHandle → InterfaceNumber → (Timeout → IO InterfaceAltSetting)
getInterfaceAltSetting devHndl ifNum = \timeout → do
B.head <$> readControlExact devHndl
Standard
ToInterface
c'LIBUSB_REQUEST_GET_INTERFACE
0
(fromIntegral ifNum)
1
timeout
getDeviceStatus ∷ DeviceHandle → (Timeout → IO DeviceStatus)
getDeviceStatus devHndl = \timeout → do
(unmarshalDeviceStatus ∘ B.head) <$> readControlExact devHndl
Standard
ToDevice
c'LIBUSB_REQUEST_GET_STATUS
0
0
2
timeout
where
unmarshalDeviceStatus ∷ Word8 → DeviceStatus
unmarshalDeviceStatus a =
DeviceStatus { remoteWakeup = testBit a 1
, selfPowered = testBit a 0
}
getEndpointStatus ∷ DeviceHandle → EndpointAddress → (Timeout → IO Bool)
getEndpointStatus devHndl endpointAddr = \timeout → do
((1 ≡) ∘ B.head) <$> readControlExact devHndl
Standard
ToEndpoint
c'LIBUSB_REQUEST_GET_STATUS
0
(marshalEndpointAddress endpointAddr)
2
timeout
setDeviceAddress ∷ DeviceHandle → Word16 → (Timeout → IO ())
setDeviceAddress devHndl deviceAddr = control devHndl
Standard
ToDevice
c'LIBUSB_REQUEST_SET_ADDRESS
deviceAddr
0
synchFrame ∷ DeviceHandle → EndpointAddress → (Timeout → IO FrameNumber)
synchFrame devHndl endpointAddr = \timeout → do
unmarshallFrameNumber <$> readControlExact
devHndl
Standard
ToEndpoint
c'LIBUSB_REQUEST_SYNCH_FRAME
0
(marshalEndpointAddress endpointAddr)
2
timeout
where
unmarshallFrameNumber bs = let [h, l] = B.unpack bs
in fromIntegral h ⋅ 256 + fromIntegral l
type FrameNumber = Word16