0 | module Bindings.RtlSdr.Buffer
  1 |
  2 | import public Bindings.RtlSdr.Raw.Buffer
  3 | import Bindings.RtlSdr.Device
  4 | import Bindings.RtlSdr.Error
  5 | import Bindings.RtlSdr.Raw.Support
  6 |
  7 | import Data.Buffer
  8 | import System.FFI
  9 |
 10 | %default total
 11 |
 12 | ||| A IQ record contains the cartesian plane coordinates upon
 13 | ||| the circle at a given time `t`. Both `(i, q)` are encoded
 14 | ||| as `(Int16, Int16)` for a given sample.
 15 | public export
 16 | record IQ where
 17 |   constructor MkIQ
 18 |   iVal : Int16
 19 |   qVal : Int16
 20 |
 21 | export
 22 | Eq IQ where
 23 |   a == b = (iVal a, qVal a) == (iVal b, qVal b)
 24 |   a /= b = not (a == b)
 25 |
 26 | export
 27 | Num IQ where
 28 |   MkIQ a b + MkIQ a' b' = MkIQ (a+a') (b+b')
 29 |   MkIQ a b * MkIQ a' b' = MkIQ (a*a' + b*b') (a*b' + b*a')
 30 |   fromInteger x = MkIQ (cast x) 0
 31 |
 32 | -- Turn [U8] into [S16] re-centred around zero.
 33 | scaleIQ : Bits8 -> Int16
 34 | scaleIQ v = (cast {to = Int16} v) - 128
 35 |
 36 | toIQ : Bits8 -> Bits8 -> IQ
 37 | toIQ i q = MkIQ (scaleIQ i) (scaleIQ q)
 38 |
 39 | toIQList : List Bits8 -> List IQ
 40 | toIQList [] = []
 41 | toIQList [_] = []
 42 | toIQList (xs::ys::rest) = (toIQ xs ys) :: toIQList rest
 43 |
 44 | ||| Read samples from the device synchronously.
 45 | |||
 46 | ||| @h is the device handle
 47 | ||| @b is a buffer to write samples to
 48 | export
 49 | readSync : Ptr RtlSdrHandle -> Buffer -> IO (Either RTLSDR_ERROR Int)
 50 | readSync h b = do
 51 |   l <- rawSize b
 52 |   v <- prim__castPtr <$> malloc 4 -- n_read
 53 |   r <- fromPrim $ read_sync h b l v
 54 |   let nr = peekInt v
 55 |   free $ prim__forgetPtr v
 56 |   io_pure $ if r == 0 then Right nr else Left RtlSdrError
 57 |
 58 | ||| Call callback closure type signature
 59 | public export
 60 | ReadAsyncFn : Type
 61 | ReadAsyncFn = AnyPtr -> List IQ -> IO ()
 62 |
 63 | ||| Read samples from the device asynchronously. This will block until
 64 | ||| it is being canceled using `cancelAsync`.
 65 | |||
 66 | ||| @h is the device handle
 67 | ||| @cbIO is the callback closure to received samples
 68 | ||| @ctx  is a user defined context to pass to the callback closure
 69 | ||| @bn   optional buffer count, buf_num * buf_len = overall buffer size
 70 | |||     set to 0 for default buffer count (15)
 71 | ||| @bl   optional buffer length, must be multiple of 512,
 72 | |||     should be a multiple of 16384 (URB size), set to 0
 73 | |||     for default buffer length (16 * 32 * 512)
 74 | export
 75 | readAsync : Ptr RtlSdrHandle -> ReadAsyncFn -> AnyPtr -> Int -> Int -> IO (Either RTLSDR_ERROR ())
 76 | readAsync h cbIO ctx bn bl = do
 77 |   let cbPrim = \bufPtr, bufLen, ctxPtr => toPrim $
 78 |         cbIO ctxPtr =<< ((io_pure . toIQList) =<< readBufPtr' bufPtr bufLen)
 79 |   r <- fromPrim $ read_async h cbPrim ctx bn bl
 80 |   io_pure $ if r == 0 then Right () else Left RtlSdrError
 81 |
 82 | ||| Cancel all pending asynchronous operations on the device.
 83 | |||
 84 | ||| @h is the device handle
 85 | export
 86 | cancelAsync : Ptr RtlSdrHandle -> IO (Either RTLSDR_ERROR ())
 87 | cancelAsync h = do
 88 |   r <- fromPrim $ cancel_async h
 89 |   io_pure $ if r == 0 then Right () else Left RtlSdrError
 90 |
 91 | ||| Reset internal Hardware FIFO.
 92 | |||
 93 | ||| See section 11.4.2; USB_EPA_CTL in datasheet.
 94 | |||
 95 | ||| @h is the device handle
 96 | export
 97 | resetBuffer : Ptr RtlSdrHandle -> IO (Either RTLSDR_ERROR ())
 98 | resetBuffer h = do
 99 |   r <- fromPrim $ reset_buffer h
100 |   io_pure $ if r == 0 then Right () else Left RtlSdrError
101 |