Skip to content

Commit

Permalink
Update tests and README, mainly.
Browse files Browse the repository at this point in the history
  • Loading branch information
ajkeller34 committed Sep 4, 2017
1 parent 8b1d513 commit c09b08a
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 34 deletions.
94 changes: 66 additions & 28 deletions README.md
@@ -1,4 +1,9 @@
[![Build Status](https://travis-ci.org/PainterQubits/Alazar.jl.svg?branch=master)](https://travis-ci.org/PainterQubits/Alazar.jl)
[![Coverage Status](https://coveralls.io/repos/PainterQubits/Alazar.jl/badge.svg?branch=master&service=github)](https://coveralls.io/github/PainterQubits/Alazar.jl?branch=master)
[![codecov.io](http://codecov.io/github/PainterQubits/Alazar.jl/coverage.svg?branch=master)](http://codecov.io/github/PainterQubits/Alazar.jl?branch=master)

# Alazar.jl

[AlazarTech](http://www.alazartech.com) API wrapper for Julia, bare bones.

Adapted from the C and Python APIs by Andrew Keller (andrew.keller.09@gmail.com)
Expand All @@ -11,37 +16,70 @@ using Alazar
```

## Description
This module provides a thin wrapper on top of the AlazarTech C
API. Nearly all the exported methods directly map to underlying C
functions. Please see the ATS-SDK Guide for detailed specification of
these functions. It is up to the user to provide error handling.

`alazaropen()`, which loads the shared libraries, must be called once
and only once after loading this package. When using multiple Julia
worker processes, do not call it from workers or undefined behavior
may occur. No manual cleanup is necessary upon exiting Julia.
This module provides a thin wrapper on top of the AlazarTech C API. Nearly all the exported
methods directly map to underlying C functions. Please see the ATS-SDK Guide for detailed
specification of these functions. It is up to the user to provide error handling.

`alazaropen()`, which loads the shared libraries, must be called once and only once after
loading this package. When using multiple Julia worker processes, do not call it from
workers or undefined behavior may occur. No manual cleanup is necessary upon exiting Julia.

## Types introduced

## Types
### Type aliases
`U32`, `U16`, `U8`, `S32`, `S16`, `dsp_module_handle` aliased to their
respective C types.
### DMABufferArray
An indexable, iterable type where each index is a pointer to a page-aligned
chunk of memory suitable for DMA transfer. The memory is all contiguous and
backed by a `SharedArray`. The end user is responsible for ensuring that the
nth buffer in the array falls on a page boundary, but we warn about it.

```
struct DMABufferVector{S,T} <: AbstractVector{S}
```

AlazarTech digitizers use direct memory access (DMA) to transfer data from digitizers to
the computer's main memory. This struct abstracts memory buffers on the host. The elements
of a `DMABufferVector` are pointers to the individual buffers, which are each page-aligned,
provided a page-aligned backing array is used (e.g. `Base.SharedVector` or
`Alazar.PageAlignedVector`).

`DMABufferVector` may be constructed as, for example,
`DMABufferVector(SharedVector{UInt8}, bytes_buf, n_buf)` or
`DMABufferVector(Alazar.PageAlignedArray{UInt8}, bytes_buf, n_buf)`.

The fields of a `DMABufferVector{S,T}` are:
- `bytes_buf::Int`: The number of bytes per buffer. If there is more than one buffer it
should be a multiple of Base.Mmap.PAGESIZE. This is enforced in the inner constructor.
- `n_buf::Int`: The number of buffers to allocate.
- `backing::T`: The page-aligned backing array. `S` is `Ptr{eltype(T)}`.

This code may not support 32-bit systems.

### PageAlignedArray

```
mutable struct PageAlignedArray{T,N} <: AbstractArray{T,N}
```

An `N`-dimensional array of eltype `T` which is guaranteed to have its memory be
page-aligned. This has to be a mutable struct because finalizers are used to clean up the
memory allocated by C calls when there remain no references to the PageAlignedArray object
in Julia.

### Type aliases

- `PageAlignedVector{T} = PageAlignedArray{T,1}`.

- `U32`, `U16`, `U8`, `S32`, `S16` are aliased to their respective unsigned and signed
N-bit C types.

- `dsp_module_handle = Ptr{Void}`.

### AlazarBits
`Alazar8Bit`, `Alazar12Bit`, `Alazar16Bit`.
These encapsulate 8-bit, 12-bit, and 16-bit UInts. They have very little
overhead being declared immutable, but have the advantage that 12-bit and 16-bit
formats are distinguishable by type.
### AlazarFFTOutputFormat
`U16Log`, `U16Amp2`, `U8Log`, `U8Amp2`,
`S32Real`, `S32Imag`, `FloatLog`, `FloatAmp2`.
Similar strategy as for `AlazarBits` types. Permits efficient encoding of
FFT output data while distinguishing between e.g. `S32Real` and `S32Imag`.

## To do
- `Alazar8Bit`, `Alazar12Bit`, `Alazar16Bit`. These encapsulate 8-bit, 12-bit, and 16-bit
unsigned integers in the Alazar format. They have very little overhead being declared
immutable, but have the advantage that 12-bit and 16-bit formats are distinguishable by
type.

### AlazarFFTOutputFormat

- Replace ugly dependency code with BinDeps
- Put all the constants into a `baremodule`?
- `U16Log`, `U16Amp2`, `U8Log`, `U8Amp2`, `S32Real`, `S32Imag`, `FloatLog`, `FloatAmp2`.
Similar strategy as for `AlazarBits` types. Permits efficient encoding of FFT output data
while distinguishing between e.g. `S32Real` and `S32Imag`.
8 changes: 3 additions & 5 deletions src/buffer.jl
Expand Up @@ -14,8 +14,8 @@ provided a page-aligned backing array is used (e.g. `Base.SharedVector` or
`DMABufferVector(Alazar.PageAlignedArray{UInt8}, bytes_buf, n_buf)`.
The fields of a `DMABufferVector{S,T}` are:
- `bytes_buf::Int`: The number of bytes per buffer. If there is more than one buffer it should
be a multiple of Base.Mmap.PAGESIZE. This is enforced in the inner constructor.
- `bytes_buf::Int`: The number of bytes per buffer. If there is more than one buffer it
should be a multiple of Base.Mmap.PAGESIZE. This is enforced in the inner constructor.
- `n_buf::Int`: The number of buffers to allocate.
- `backing::T`: The page-aligned backing array. `S` is `Ptr{eltype(T)}`.
Expand Down Expand Up @@ -103,8 +103,6 @@ Allocate page-aligned memory and return a `Ptr{T}` to the allocation. The caller
responsible for de-allocating the memory using `virtualfree`, otherwise it will leak.
"""
function virtualalloc(size_bytes::Integer, ::Type{T}) where {T}
local addr

@static is_windows() ? begin
MEM_COMMIT = 0x1000
PAGE_READWRITE = 0x4
Expand Down Expand Up @@ -136,5 +134,5 @@ function virtualfree(addr::Ptr{T}) where {T}
return ccall((:free, linux_libc), Void, (Ptr{Void},), addr)
end : @static is_apple() ? begin
return ccall((:free, "libSystem.dylib"), Void, (Ptr{Void},), addr)
end : throw(SystemError())
end : error("OS not supported")
end
5 changes: 4 additions & 1 deletion test/runtests.jl
Expand Up @@ -23,9 +23,12 @@ p = PageAlignedVector{Int}(512)
@test_throws ErrorException DMABufferVector(PageAlignedVector{Int}, 64, 10)

# Should throw an error if a non-page-aligned AbstractVector type is used.
@test_throws ErrorException DMABufferVector(Vector{Int}, 512, 1)
# However, sometimes a Vector may be page-aligned, by chance. Not sure how to ensure
# this test will pass in general.
# @test_throws ErrorException DMABufferVector(Vector{Int}, 512, 1)

# Should throw an error if anything but an AbstractVector type is used.
@test_throws MethodError DMABufferVector(Array{Int,2}, 512, 1)
@test_throws MethodError DMABufferVector(Array{Int}, 512, 1)

dma = DMABufferVector(PageAlignedVector{Int}, Base.Mmap.PAGESIZE, 10)
Expand Down

0 comments on commit c09b08a

Please sign in to comment.