Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ or
easy_install ALP4lib
```

### Installation from source (Github)
### Installation from the source (Github)
To install the latest version from Github, clone the repository, and install the package with the the following command.
```shell script
python setup.py install
Expand Down
111 changes: 58 additions & 53 deletions src/ALP4.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,40 +366,45 @@ class ALP4(object):
This class controls a Vialux DMD board based on the Vialux ALP 4.X API.
"""

def __init__(self, version='4.3', libDir=None):
def __init__(self, version='4.3', libDir=None, invert=False, verbose=False):
self.verbose = verbose
self.invert = invert

os_type = platform.system()

if libDir is None:
try:
reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
key = _winreg.OpenKey(reg, r"SOFTWARE\ViALUX\ALP-" + version)
libDir = (_winreg.QueryValueEx(key, "Path"))[0] + "/ALP-{0} API/".format(version)
libPath = (_winreg.QueryValueEx(key, "Path"))[0] + "/ALP-{0} API/".format(version)
except EnvironmentError:
raise ValueError("Cannot auto detect libDir! Please specify it manually.")

if libDir.endswith('/'):
elif libDir.endswith('/'):
libPath = libDir
else:
libPath = libDir + '/'
## Load the ALP dll
if (os_type == 'Windows'):
if (ct.sizeof(ct.c_voidp) == 8): ## 64bit

if os_type == 'Windows':
if (ct.sizeof(ct.c_void_p) == 8): ## 64bit
libPath += 'x64/'
elif not (ct.sizeof(ct.c_voidp) == 4): ## 32bit
elif not (ct.sizeof(ct.c_void_p) == 4): ## 32bit
raise OSError('System not supported.')
else:
raise OSError('System not supported.')

if (version == '4.1'):
if version == '4.1':
libPath += 'alpD41.dll'
elif (version == '4.2'):
elif version == '4.2':
libPath += 'alpD41.dll'
elif (version == '4.3'):
elif version == '4.3':
libPath += 'alp4395.dll'
else:
raise ValueError("Unavailable ALPlib version. Currently supported version: 4.1, 4.2, 4.3")

print('Loading library: ' + libPath)
if self.verbose:
print('Loading library: ' + libPath)

## Load the ALP dll
self._ALPLib = ct.CDLL(libPath)

## Class parameters
Expand Down Expand Up @@ -449,7 +454,11 @@ def Initialize(self, DeviceNum=None):
'Inquery ALP_DEV_DISPLAY_HEIGHT fails.')
self.nSizeY = nSizeY.value

print('DMD found, resolution = ' + str(self.nSizeX) + ' x ' + str(self.nSizeY) + '.')
if self.verbose:
print('DMD found, resolution = ' + str(self.nSizeX) + ' x ' + str(self.nSizeY) + '.')

if self.invert:
self._checkError(self._ALPLib.AlpProjControl(self.ALP_ID, ALP_PROJ_INVERSION, ALP_DEFAULT+1), "Cannot set ALP_PROJ_INVERSION.")

def SeqAlloc(self, nbImg=1, bitDepth=1):
"""
Expand Down Expand Up @@ -494,7 +503,32 @@ def SeqAlloc(self, nbImg=1, bitDepth=1):
self._lastDDRseq = SequenceId
return SequenceId

def SeqPutEx(self, imgData, LineOffset, LineLoad, SequenceId=None, PicOffset=0, PicLoad=0, dataFormat='Python'):
def _cast_imgData(self, imgData, SequenceId):
if not isinstance(imgData, np.ndarray):
raise ValueError("imgData must be an numpy ndarray.")

bitplanes = self.SeqInquire(ALP_BITPLANES, SequenceId)
data_format = self.SeqInquire(ALP_DATA_FORMAT, SequenceId)

if data_format != ALP_DEFAULT and data_format != ALP_DATA_LSB_ALIGN:
raise NotImplementedError("Unsupported ALP_DATA_FORMAT.")

if 1 <= bitplanes <= 8:
imgData = imgData.astype(np.uint8)
if bitplanes < 8 and data_format == ALP_DATA_MSB_ALIGN:
imgData = np.left_shift(imgData, 8 - bitplanes)
elif 9 <= bitplanes <= 16:
imgData = imgData.astype(np.uint16)
if bitplanes < 16 and data_format == ALP_DATA_MSB_ALIGN:
imgData = np.left_shift(imgData, 16 - bitplanes)
else:
raise AssertionError


return imgData


def SeqPutEx(self, imgData, LineOffset, LineLoad, SequenceId=None, PicOffset=0, PicLoad=0):
"""
Image data transfer using AlpSeqPut is based on whole DMD frames. Applications that only
update small regions inside a frame suffer from overhead of this default behavior. An extended
Expand All @@ -516,7 +550,7 @@ def SeqPutEx(self, imgData, LineOffset, LineLoad, SequenceId=None, PicOffset=0,
PARAMETERS
----------

imgData : list, 1D array or 1D ndarray
imgData : numpy.ndarray
Data stream corresponding to a sequence of nSizeX by nSizeX images.
Values has to be between 0 and 255.
LineOffset : int
Expand All @@ -540,11 +574,6 @@ def SeqPutEx(self, imgData, LineOffset, LineLoad, SequenceId=None, PicOffset=0,
Depends on ALP_DATA_FORMAT.
PicLoad = 0 correspond to a complete sequence.
By default, PicLoad = 0.
dataFormat : string, optional
Specify the type of data sent as image.
Should be ' Python' or 'C'.
If the data is of Python format, it is converted into a C array before sending to the DMD via the dll.
By default dataFormat = 'Python'
"""

if not SequenceId:
Expand All @@ -556,13 +585,8 @@ def SeqPutEx(self, imgData, LineOffset, LineLoad, SequenceId=None, PicOffset=0,
ct.c_long(LineOffset),
ct.c_long(LineLoad))

if dataFormat not in ['Python', 'C']:
raise ValueError('dataFormat must be one of "Python" or "C"')

if dataFormat == 'Python':
pImageData = imgData.astype(np.uint8).ctypes.data_as(ct.c_void_p)
elif dataFormat == 'C':
pImageData = ct.cast(imgData, ct.c_void_p)
imgData = self._cast_imgData(imgData, SequenceId)
pImageData = imgData.ctypes.data_as(ct.c_void_p)

self._checkError(self._ALPLib.AlpSeqPutEx(self.ALP_ID, SequenceId, LinePutParam, pImageData),
'Cannot send image sequence to device.')
Expand All @@ -587,7 +611,7 @@ def SeqPut(self, imgData, SequenceId=None, PicOffset=0, PicLoad=0, dataFormat='P
PARAMETERS
----------

imgData : list, 1D array or 1D ndarray
imgData : numpy.ndarray
Data stream corresponding to a sequence of nSizeX by nSizeX images.
Values has to be between 0 and 255.
SequenceId : ctypes c_long
Expand All @@ -601,11 +625,6 @@ def SeqPut(self, imgData, SequenceId=None, PicOffset=0, PicLoad=0, dataFormat='P
Depends on ALP_DATA_FORMAT.
PicLoad = 0 correspond to a complete sequence.
By default, PicLoad = 0.
dataFormat : string, optional
Specify the type of data sent as image.
Should be ' Python' or 'C'.
If the data is of Python format, it is converted into a C array before sending to the DMD via the dll.
By default dataFormat = 'Python'

SEE ALSO
--------
Expand All @@ -616,12 +635,9 @@ def SeqPut(self, imgData, SequenceId=None, PicOffset=0, PicLoad=0, dataFormat='P
if not SequenceId:
SequenceId = self._lastDDRseq

if dataFormat == 'Python':
pImageData = imgData.astype(np.uint8).ctypes.data_as(ct.c_void_p)
elif dataFormat == 'C':
pImageData = ct.cast(imgData, ct.c_void_p)
else:
raise ValueError('dataFormat must be one of "Python" or "C"')
imgData = self._cast_imgData(imgData, SequenceId)

pImageData = imgData.ctypes.data_as(ct.c_void_p)

self._checkError(
self._ALPLib.AlpSeqPut(self.ALP_ID, SequenceId, ct.c_long(PicOffset), ct.c_long(PicLoad), pImageData),
Expand Down Expand Up @@ -661,8 +677,8 @@ def ImgToBitPlane(self, imgArray, bitShift=0):
return img_to_bitplane(imgArray, bitShift)


def SetTiming(self, SequenceId=None, illuminationTime=None, pictureTime=None, synchDelay=None,
synchPulseWidth=None, triggerInDelay=None):
def SetTiming(self, SequenceId=None, illuminationTime=ALP_DEFAULT, pictureTime=ALP_DEFAULT, synchDelay=ALP_DEFAULT,
synchPulseWidth=ALP_DEFAULT, triggerInDelay=ALP_DEFAULT):
"""
Set the timing properties of the sequence to display.

Expand Down Expand Up @@ -701,17 +717,6 @@ def SetTiming(self, SequenceId=None, illuminationTime=None, pictureTime=None, sy
if (SequenceId is None):
raise ValueError('No sequence to display.')

if (synchDelay is None):
synchDelay = ALP_DEFAULT
if (synchPulseWidth is None):
synchPulseWidth = ALP_DEFAULT
if (triggerInDelay is None):
triggerInDelay = ALP_DEFAULT
if (illuminationTime is None):
illuminationTime = ALP_DEFAULT
if (pictureTime is None):
pictureTime = ALP_DEFAULT

self._checkError(
self._ALPLib.AlpSeqTiming(self.ALP_ID, SequenceId, ct.c_long(illuminationTime), ct.c_long(pictureTime),
ct.c_long(synchDelay), ct.c_long(synchPulseWidth), ct.c_long(triggerInDelay)),
Expand Down Expand Up @@ -1023,7 +1028,7 @@ def Run(self, SequenceId=None, loop=True):
if (SequenceId is None) and (self._lastDDRseq):
SequenceId = self._lastDDRseq
if (SequenceId is None):
self._raiseError('No sequence to display.')
raise ValueError('No sequence to display.')

if loop:
self._checkError(self._ALPLib.AlpProjStartCont(self.ALP_ID, SequenceId), 'Cannot launch sequence.')
Expand Down