From 95410af8340c7be34ba464676aa545ef98bd3bff Mon Sep 17 00:00:00 2001 From: Gilbert Date: Wed, 2 Dec 2020 17:11:04 -0500 Subject: [PATCH 1/7] add verbose parameter at __init__ --- README.md | 2 +- src/ALP4.py | 29 ++++++++++++++++------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index e5714fa..9132af3 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/src/ALP4.py b/src/ALP4.py index afd6009..8e81fc8 100644 --- a/src/ALP4.py +++ b/src/ALP4.py @@ -339,7 +339,8 @@ 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, verbose=False): + self.verbose=verbose os_type = platform.system() @@ -347,32 +348,33 @@ def __init__(self, version='4.3', libDir=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' - print('Loading library: ' + libPath) + if self.verbose: + print('Loading library: ' + libPath) + ## Load the ALP dll self._ALPLib = ct.CDLL(libPath) ## Class parameters @@ -435,7 +437,8 @@ def Initialize(self, DeviceNum=None): print("Unknown DMDtype with value ", self.DMDType.value) raise EnvironmentError("DMD Type not supported or unknown.") - 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) + '.') def SeqAlloc(self, nbImg=1, bitDepth=1): """ From b379a574327297da98fba0df5d09a2b8e1af5f72 Mon Sep 17 00:00:00 2001 From: Gilbert Date: Wed, 2 Dec 2020 18:58:09 -0500 Subject: [PATCH 2/7] automatically leftshift remove c dataformat --- src/ALP4.py | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/ALP4.py b/src/ALP4.py index 8e81fc8..579a32b 100644 --- a/src/ALP4.py +++ b/src/ALP4.py @@ -483,6 +483,17 @@ def SeqAlloc(self, nbImg=1, bitDepth=1): self._lastDDRseq = SequenceId return SequenceId + def _cast_imgData(self, imgData): + if isinstance(imgData, np.ndarray): + if imgData.dtype == np.bool: + imgData = np.left_shift(imgData.astype(np.uint8), 7) + else: + imgData = imgData.astype(np.uint8) + else: + raise ValueError("imgData must be an numpy ndarray.") + return imgData + + def SeqPutEx(self, imgData, LineOffset, LineLoad, SequenceId=None, PicOffset=0, PicLoad=0, dataFormat='Python'): """ Image data transfer using AlpSeqPut is based on whole DMD frames. Applications that only @@ -505,7 +516,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 @@ -529,11 +540,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: @@ -548,10 +554,8 @@ def SeqPutEx(self, imgData, LineOffset, LineLoad, SequenceId=None, PicOffset=0, 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) + 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.') @@ -576,7 +580,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 @@ -590,11 +594,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 -------- @@ -605,12 +604,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) + + 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), From a2ce4b4f4b29e5b2fee295a97e254a055de62f96 Mon Sep 17 00:00:00 2001 From: Gilbert Date: Fri, 4 Dec 2020 15:57:07 -0500 Subject: [PATCH 3/7] Set PROJ_INVERSION during initialization. --- src/ALP4.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ALP4.py b/src/ALP4.py index 437c5a0..f90c941 100644 --- a/src/ALP4.py +++ b/src/ALP4.py @@ -339,8 +339,9 @@ 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, verbose=False): - self.verbose=verbose + def __init__(self, version='4.3', libDir=None, invert=False, verbose=False): + self.verbose = verbose + self.invert = invert os_type = platform.system() @@ -427,6 +428,9 @@ def Initialize(self, DeviceNum=None): 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): """ This function provides ALP memory for a sequence of pictures. All pictures of a sequence have the @@ -478,10 +482,11 @@ def _cast_imgData(self, imgData): imgData = imgData.astype(np.uint8) else: raise ValueError("imgData must be an numpy ndarray.") + return imgData - def SeqPutEx(self, imgData, LineOffset, LineLoad, SequenceId=None, PicOffset=0, PicLoad=0, dataFormat='Python'): + 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 @@ -538,9 +543,6 @@ 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"') - imgData = self._cast_imgData(imgData) pImageData = imgData.ctypes.data_as(ct.c_void_p) From 7a5fe30737b587e40163c25757f0cc1b43aac8c6 Mon Sep 17 00:00:00 2001 From: Gilbert Date: Fri, 4 Dec 2020 18:49:08 -0500 Subject: [PATCH 4/7] update the way casting the data --- src/ALP4.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/ALP4.py b/src/ALP4.py index f90c941..5f2b519 100644 --- a/src/ALP4.py +++ b/src/ALP4.py @@ -474,15 +474,28 @@ def SeqAlloc(self, nbImg=1, bitDepth=1): self._lastDDRseq = SequenceId return SequenceId - def _cast_imgData(self, imgData): - if isinstance(imgData, np.ndarray): - if imgData.dtype == np.bool: - imgData = np.left_shift(imgData.astype(np.uint8), 7) - else: - imgData = imgData.astype(np.uint8) - else: + 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 @@ -543,7 +556,7 @@ def SeqPutEx(self, imgData, LineOffset, LineLoad, SequenceId=None, PicOffset=0, ct.c_long(LineOffset), ct.c_long(LineLoad)) - imgData = self._cast_imgData(imgData) + 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), @@ -593,7 +606,7 @@ def SeqPut(self, imgData, SequenceId=None, PicOffset=0, PicLoad=0, dataFormat='P if not SequenceId: SequenceId = self._lastDDRseq - imgData = self._cast_imgData(imgData) + imgData = self._cast_imgData(imgData, SequenceId) pImageData = imgData.ctypes.data_as(ct.c_void_p) From 69500f3c031f71bcefe23b7a7d41b6bad3b8bf33 Mon Sep 17 00:00:00 2001 From: Gilbert Date: Fri, 4 Dec 2020 19:26:54 -0500 Subject: [PATCH 5/7] fix bugs --- src/ALP4.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ALP4.py b/src/ALP4.py index 5f2b519..42aa565 100644 --- a/src/ALP4.py +++ b/src/ALP4.py @@ -737,7 +737,7 @@ def DevInquire(self, inquireType): ret = ct.c_double(0) self._checkError(self._ALPLib.AlpDevInquire(self.ALP_ID, inquireType, ct.byref(ret)), 'Error sending request.') - return ret.value() + return ret.value def SeqInquire(self, inquireType, SequenceId=None): """ @@ -1014,7 +1014,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.') From 5407dba2d79efed54f9a94b341d7ce20f5b584e8 Mon Sep 17 00:00:00 2001 From: Gilbert Date: Fri, 11 Dec 2020 18:02:05 -0500 Subject: [PATCH 6/7] error handling and format the code --- src/ALP4.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ALP4.py b/src/ALP4.py index 42aa565..af1b489 100644 --- a/src/ALP4.py +++ b/src/ALP4.py @@ -371,6 +371,8 @@ def __init__(self, version='4.3', libDir=None, invert=False, verbose=False): libPath += 'alpD41.dll' elif version == '4.3': libPath += 'alp4395.dll' + else: + raise ValueError("Unavailable ALPlib version. Currently supported version: 4.1, 4.2, 4.3") if self.verbose: print('Loading library: ' + libPath) @@ -484,11 +486,11 @@ def _cast_imgData(self, imgData, SequenceId): if data_format != ALP_DEFAULT and data_format != ALP_DATA_LSB_ALIGN: raise NotImplementedError("Unsupported ALP_DATA_FORMAT.") - if 1<= bitplanes <= 8: + 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: + 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) From 5a2897378fb79436f065f472b8d75a5055210550 Mon Sep 17 00:00:00 2001 From: Gilbert Date: Mon, 19 Apr 2021 23:46:16 -0400 Subject: [PATCH 7/7] Move ALP_DEFAULT to function input --- src/ALP4.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/ALP4.py b/src/ALP4.py index af1b489..c9f5a65 100644 --- a/src/ALP4.py +++ b/src/ALP4.py @@ -654,8 +654,8 @@ def ImgToBitPlane(self, imgArray, bitShift=0): bitPlane[(ind - ind % 8) // 8] += (2 ** (7 - ind % 8)) * ((int(value) >> bitShift) % 2) return bitPlane - 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. @@ -694,17 +694,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)),