Send Beginners mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
        [email protected]

You can reach the person managing the list at
        [email protected]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."


Today's Topics:

   1.  System.USB.writeInterrupt -- confused by error   message from
      type system (emacstheviking)
   2. Re:  System.USB.writeInterrupt -- confused by error message
      from type system (Karol Samborski)
   3. Re:  System.USB.writeInterrupt -- confused by error message
      from type system (Alexander Polakov)
   4. Re:  System.USB.writeInterrupt -- confused by error message
      from type system (Alexander Polakov)
   5. Re:  System.USB.writeInterrupt -- confused by error message
      from type system (emacstheviking)


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

Message: 1
Date: Wed, 27 Feb 2013 11:46:47 +0000
From: emacstheviking <[email protected]>
Subject: [Haskell-beginners] System.USB.writeInterrupt -- confused by
        error   message from type system
To: [email protected]
Message-ID:
        <caeieuukefsdkoyr8ywihkrspggsxsgbfxs_uj6m53axmamt...@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"

Hello,

I am building a USB gadget with a HexWax ExpandIO-USB chip, here:
http://hexwax.com/Products/expandIO-USB/

The device is working fine (lsusb shows it) and so I thought that in the
name of continued training and doing things the hard way, that I would use
Haskell to talk to it!
I have only ever done USB with 'C' in the past and I am now stuck fighting
the type checker.

Here is my full code so far, it works in so far as it finds the device,
opens and closes a connection and prints out some stuff. I then wanted to
send four NUL bytes which elicits the same as a response according to the
documentation but I cannot get it to compile. Apologies for it in advance,
it's the journey you know, not the arrival, anyway, here it is...

module Main where

import Data.ByteString.Char8 as BS hiding (putStrLn)
import Data.Word (Word16)
import Data.Vector as V (filterM, null, (!)) --as V hiding
((++))
import System.USB
import System.Environment


-- hexwax expandIO-USB default code:
"0b40:0132"
main :: IO ()
main = do
  findHexWax (0xb40,0x132) >>= \hw ->
    case hw of
      Just dev -> hexwaxGo dev
      Nothing  -> putStrLn "HexWax device not found"


findHexWax :: (Word16,Word16) -> IO (Maybe Device)
findHexWax (cVendor, cProd) = do
  usbCtx  <- newCtx
  usbDevs <- getDevices usbCtx
  setDebug usbCtx PrintWarnings
  boards <- V.filterM (isTarget (cVendor, cProd)) usbDevs
  case V.null boards of
    True  -> return Nothing
    False -> return $ Just $ boards!0
  where
    isTarget :: (Word16, Word16) -> Device -> IO Bool
    isTarget (cVendor, cProd) dev = do
      info <- getDeviceDesc dev
      let vid = deviceVendorId info
      let vpr = deviceProductId info
      return $ ((vid, vpr) == (cVendor, cProd))


hexwaxGo :: Device -> IO ()
hexwaxGo dev = withDeviceHandle dev (testBoard dev)



testBoard :: Device -> DeviceHandle -> IO ()
testBoard dev handle = do
  putStrLn $ "Inspecting device: \"" ++ (show dev) ++ "\"\n"
  -- write 0x00 0x00 0x00 0x00, get back
same...
  let payload  = pack "\x00\x00\x00\x00"
  let endPoint = EndpointAddress 0 Out
  action <- writeInterrupt handle endPoint
  (size, status) <- action payload 1000
  return ()

And the error message:

Prelude> :r
[1 of 1] Compiling Main             ( usb1.hs, interpreted )

usb1.hs:60:13:
    Couldn't match expected type `IO t0' with actual type `WriteAction'
    In the return type of a call of `writeInterrupt'
    Probable cause: `writeInterrupt' is applied to too few arguments
    In a stmt of a 'do' block: action <- writeInterrupt handle endPoint
    In the expression:
      do { putStrLn $ "Inspecting device: \"" ++ (show dev) ++ "\"";
           let payload = pack "\NUL\NUL\NUL\NUL";
           let endPoint = EndpointAddress 0 Out;
           action <- writeInterrupt handle endPoint;
           .... }
Failed, modules loaded: none.



I have spent a few hours trying this and that, my Haskell is improving but
not much good if I can't compile my program now is it!

So, can anybody point out the error of my ways here please as I just can't
see it!

Thanks,
Sean Charles.

PS: Code style comments, alternative ways of making it more concise (but
still readable and understandable mind you) are also welcome.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: 
<http://www.haskell.org/pipermail/beginners/attachments/20130227/aa1faeb1/attachment-0001.htm>

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

Message: 2
Date: Wed, 27 Feb 2013 13:07:29 +0100
From: Karol Samborski <[email protected]>
Subject: Re: [Haskell-beginners] System.USB.writeInterrupt -- confused
        by error message from type system
To: The Haskell-Beginners Mailing List - Discussion of primarily
        beginner-level topics related to Haskell <[email protected]>
Message-ID:
        <cace2dtt4s8fsr+pa_9o+f8tcmdwkaht3nqef_a5yaww9awb...@mail.gmail.com>
Content-Type: text/plain; charset=UTF-8

Hi Sean,

I think that your function for testing board should look like this:

testBoard :: Device -> DeviceHandle -> IO ()
testBoard dev handle = do
  putStrLn $ "Inspecting device: \"" ++ (show dev) ++ "\"\n"
  -- write 0x00 0x00 0x00 0x00, get back same...
  let payload  = pack "\x00\x00\x00\x00"
  let endPoint = EndpointAddress 0 Out
  let action = writeInterrupt handle endPoint
  (size, status) <- action payload 1000
  return ()

You need to use let because writeInterrupt returns (Timeout ->
ByteString -> IO (Size, Bool)) instead of IO (Timeout -> ByteString ->
IO (Size, Bool))

Karol



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

Message: 3
Date: Wed, 27 Feb 2013 16:14:40 +0400
From: Alexander Polakov <[email protected]>
Subject: Re: [Haskell-beginners] System.USB.writeInterrupt -- confused
        by error message from type system
To: The Haskell-Beginners Mailing List - Discussion of primarily
        beginner-level topics related to Haskell <[email protected]>
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii

* emacstheviking <[email protected]> [130227 16:00]:

>   let payload  = pack "\x00\x00\x00\x00"
>   let endPoint = EndpointAddress 0 Out
>   action <- writeInterrupt    handle          endPoint           
              ^^^^^^^^^^^^^^    ^^^^^^          ^^^^^^^^           ^^^^^^^
              writeInterrupt :: DeviceHandle -> EndpointAddress -> WriteAction

WriteAction parameter is missing. GHC tells you about that right here:

> usb1.hs:60:13:
>     Couldn't match expected type `IO t0' with actual type `WriteAction'
>     In the return type of a call of `writeInterrupt'
>     Probable cause: `writeInterrupt' is applied to too few arguments
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

>     In a stmt of a 'do' block: action <- writeInterrupt handle endPoint
>     In the expression:
>       do { putStrLn $ "Inspecting device: \"" ++ (show dev) ++ "\"";
>            let payload = pack "\NUL\NUL\NUL\NUL";
>            let endPoint = EndpointAddress 0 Out;
>            action <- writeInterrupt handle endPoint;
>            .... }
> Failed, modules loaded: none.
> 

-- 
Alexander Polakov | plhk.ru



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

Message: 4
Date: Wed, 27 Feb 2013 16:43:36 +0400
From: Alexander Polakov <[email protected]>
Subject: Re: [Haskell-beginners] System.USB.writeInterrupt -- confused
        by error message from type system
To: The Haskell-Beginners Mailing List - Discussion of primarily
        beginner-level topics related to Haskell <[email protected]>
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii

* Alexander Polakov <[email protected]> [130227 16:29]:
> * emacstheviking <[email protected]> [130227 16:00]:
> 
> >   let payload  = pack "\x00\x00\x00\x00"
> >   let endPoint = EndpointAddress 0 Out
> >   action <- writeInterrupt    handle          endPoint           
>               ^^^^^^^^^^^^^^    ^^^^^^          ^^^^^^^^           ^^^^^^^
>               writeInterrupt :: DeviceHandle -> EndpointAddress -> WriteAction

Uhhmm, sorry, I'm being stupid and confusing here (sleep deprived a bit).
I was looking at WriteAction definition while writing this, which is:

 type WriteAction = ByteString -> Timeout -> IO (Size, Status)

So, you have to supply ByteString and Timeout to use it as IO action
(with <-):

> (size, status) <- writeInterrupt handle endPoint payload 1000

or use let like Karol Samborski suggested.

-- 
Alexander Polakov | plhk.ru



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

Message: 5
Date: Wed, 27 Feb 2013 16:41:18 +0000
From: emacstheviking <[email protected]>
Subject: Re: [Haskell-beginners] System.USB.writeInterrupt -- confused
        by error message from type system
To: The Haskell-Beginners Mailing List - Discussion of primarily
        beginner-level topics related to Haskell <[email protected]>
Message-ID:
        <CAEiEuUJBMyXLEmWpX0pGJmCAgrbD7dD=u1zakbxjzqjrwwi...@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"

Karol, Alexander,

Thanks for your feedback... I am still a little confused as I shall
explain... first of all let's look at the prototype for 'writeInterrupt',

    writeInterrupt :: DeviceHandle -> EndpointAddress -> WriteAction

To me, that reads a "takes a device handle and an endpoint address and
returns a WriteAction", and to quote the WriteAction help text verbatim so
there is no confusion:

    type WriteAction = ByteString -> Timeout -> IO (Size, Status)Source

    Handy type synonym for write transfers.

        "A WriteAction is a function which takes a ByteString to write and
a Timeout.
         The function returns an IO action which, when exectued(sic),
returns the number
         of bytes that were actually written paired with a Status flag
which indicates whether
         the transfer Completed or TimedOut."


Now let's move to my original code and the 'right' code...

    action <- writeInterrupt handle endPoint
    let action = writeInterrupt handle endPoint


If I understand things correctly up to this point, my mistake was being too
eager in using "<-", my mind at that point was obviously confusing the
return value from WriteAction with the return type of writeInterrupt and I
can see now that what I should have done was use "let" which captures the
WriteAction that is returned which can be executed with the payload and the
timeout on the next line:

    (size, status) <- action payload 1000

On this line, the use of "<-" is what is required in order to cause the
promised IO action to  perform its duties and return me the tuple of data
sent and status returned from the USB inner workings.

However, we now come to the new type checker error, and this one has me
floored right now. Time and time again I find myself beating my head
against a wall and tearing my hair out trying to understand the
thousand-and-one variations on strings in Haskell! I even tried the
"string-conversions" (convertString) package but decided to battle it out
instead...

First the new code as edited in response to Karol:

    testBoard :: Device -> DeviceHandle -> IO ()
    testBoard dev handle = do
      putStrLn $ "Inspecting device: \"" ++ (show dev) ++ "\""
      -- write 0x00 0x00 0x00 0x00, get back same...we need to pad
the
      -- packet out to 64 bytes for a full-speed device... should
probably
      -- get this (64) from the device configuration / description
record
      -- for maximum
portability!

      let payload  = BS.replicate 64 '\0'
      let endPoint = EndpointAddress 0 Out
      let action   = writeInterrupt handle endPoint
      (size, status) <- action payload 1000
      return ()

And the new error:

usb1.hs:64:28:
    Couldn't match expected type
`bytestring-0.9.2.1:Data.ByteString.Internal.ByteString'
                with actual type `ByteString'
    In the first argument of `action', namely `payload'
    In a stmt of a 'do' block: (size, status) <- action payload 1000
    In the expression:
      do { putStrLn $ "Inspecting device: \"" ++ (show dev) ++ "\"";
           let payload = BS.replicate 64 '\NUL';
           let endPoint = EndpointAddress 0 Out;
           let action = writeInterrupt handle endPoint;
           .... }


Where and why does it think that "Data.ByteString.Internal.ByteString" is
the type of the first parameter to "action" which is quite clearly stated
as being "ByteString" ???
I know that "String", the native type is 4-bytes and that ByteString
(Strict) and ByteString (Lazy) are both 8-bit, which is great, and I
understand that the strict version (at least to me) feels like the
rightmatch to be using for data buffers for a USB transfer but why oh why
oh why can't I understand why the type checker picked up "internal"
somewhere along the way?

In the source code for WriteAction we have this:

    type WriteAction = B.ByteString ? Timeout ? IO (Size, Status)

and at the top of the that source file:

    -- from bytestring:
    import qualified Data.ByteString          as B  ( ByteString,
packCStringLen, drop, length )
    import qualified Data.ByteString.Internal as BI ( createAndTrim,
createAndTrim' )
    import qualified Data.ByteString.Unsafe   as BU ( unsafeUseAsCStringLen
)


So why is it trying to be "internal"! I have tried not to be lazy, I have
read everything and looked everywhere before posting again. If it had said:

    type WriteAction = BI.ByteString ? Timeout ? IO (Size, Status)

I would have understood but it doesn't does it ?!
Can somebody explain for me so I can just get on and write my killer USB
application please! LOL

:)
Thanks,
Sean.





On 27 February 2013 12:07, Karol Samborski <[email protected]> wrote:

> Hi Sean,
>
> I think that your function for testing board should look like this:
>
> testBoard :: Device -> DeviceHandle -> IO ()
> testBoard dev handle = do
>   putStrLn $ "Inspecting device: \"" ++ (show dev) ++ "\"\n"
>   -- write 0x00 0x00 0x00 0x00, get back same...
>   let payload  = pack "\x00\x00\x00\x00"
>   let endPoint = EndpointAddress 0 Out
>   let action = writeInterrupt handle endPoint
>   (size, status) <- action payload 1000
>   return ()
>
> You need to use let because writeInterrupt returns (Timeout ->
> ByteString -> IO (Size, Bool)) instead of IO (Timeout -> ByteString ->
> IO (Size, Bool))
>
> Karol
>
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://www.haskell.org/mailman/listinfo/beginners
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: 
<http://www.haskell.org/pipermail/beginners/attachments/20130227/4cf5dc1a/attachment.htm>

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

_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners


End of Beginners Digest, Vol 56, Issue 43
*****************************************

Reply via email to