Hi,
I'm trying to write my own software in Python for controlling the DLPC900. For this purpose, I am using the hidapi library in python. So far I was able to make it work only the stop sequence and start sequence commands (the latter only in pre-stored pattern mode), while if I want to load other images it doesn't work. I'm using a code based on the work of another user (https://e2e.ti.com/support/dlp/f/94/t/540992?I-released-a-small-python-interface-for-the-lightcrafter-6500), the main difference is that I am using hidap library, and not libusb (I used libusb and it worked fine, but sometimes the connection with the board was lost, so I preferred to switch library).
I would like to know if anyone have already controlled the board with the hidapi library in python, so that I can find out what's wrong with the code.
Here my code:
import hid import time import numpy import os class DmdDeviceHID: def __init__(self): hid.enumerate() self.device = hid.device() self.device.open(0x0451, 0xc900) print(self.device.get_manufacturer_string()) print(self.device.get_product_string()) print(self.device.get_serial_number_string()) # self.ans = [] def command(self,mode,sequencebyte,com1,com2,data=None): buffer = [] flagstring='' if mode=='r': flagstring+='1' else: flagstring+='0' flagstring+='0000000' buffer.append(0x00) buffer.append(bitstobytes(flagstring)[0]) buffer.append(sequencebyte) temp=bitstobytes(convlen(len(data)+2,16)) buffer.append(temp[0]) buffer.append(temp[1]) buffer.append(com2) buffer.append(com1) if len(buffer)+len(data)<=65: #65 = max number of sent bytes for i in data: buffer.append(i) for i in range(65-len(buffer)): buffer.append(0x00) self.device.write(buffer) else: for i in range(65-len(buffer)): buffer.append(data[i]) self.device.write(buffer) buffer = [0x00] j=0 while j<len(data)-58: buffer.append(data[j+58]) j=j+1 if j%65==0: self.device.write(buffer) buffer = [0x00] if j%65!=0: while j%65!=0: buffer.append(0x00) j=j+1 self.device.write(buffer) def checkforerrors(self): self.command('r',0x22,0x01,0x00,[]) # if self.ans[6]!=0: # print (self.ans[6]) ## function printing all of the dlp answer # def readreply(self): # for i in self.ans: # print (hex(i)) ## functions for idle mode activation def idle_on(self): self.command('w',0x00,0x02,0x01,[int('00000001',2)]) # self.checkforerrors() def idle_off(self): self.command('w',0x00,0x02,0x01,[int('00000000',2)]) # self.checkforerrors() ## functions for power management def standby(self): self.command('w',0x00,0x02,0x00,[int('00000001',2)]) # self.checkforerrors() def wakeup(self): self.command('w',0x00,0x02,0x00,[int('00000000',2)]) # self.checkforerrors() def reset(self): self.command('w',0x00,0x02,0x00,[int('00000010',2)]) # self.checkforerrors() ## test write and read operations, as reported in the dlpc900 programmer's guide def testread(self): self.command('r',0xff,0x11,0x00,[]) # self.readreply() def testwrite(self): self.command('w',0x22,0x11,0x00,[0xff,0x01,0xff,0x01,0xff,0x01]) # self.checkforerrors() ## some self explaining functions def changemode(self,mode): self.command('w',0x00,0x1a,0x1b,[mode]) # self.checkforerrors() def startsequence(self): self.command('w',0x00,0x1a,0x24,[2]) # self.checkforerrors() def pausesequence(self): self.command('w',0x00,0x1a,0x24,[1]) # self.checkforerrors() def stopsequence(self): self.command('w',0x00,0x1a,0x24,[0]) # self.checkforerrors() def configurelut(self,imgnum,repeatnum): img=convlen(imgnum,11) repeat=convlen(repeatnum,32) string=repeat+'00000'+img im_bytes=bitstobytes(string) self.command('w',0x00,0x1a,0x31,im_bytes) # self.checkforerrors() def definepattern(self,index,exposure,bitdepth,color,triggerin,darktime, triggerout,patind,bitpos): payload=[] index=convlen(index,16) index=bitstobytes(index) for i in index: payload.append(i) exposure=convlen(exposure,24) #24 or 32? exposure=bitstobytes(exposure) for i in exposure: payload.append(i) optionsbyte='' #optionsbyte+='0'*8 #I put this line. I dont know if it's right. see the manual optionsbyte+='1' bitdepth=convlen(bitdepth-1,3) optionsbyte=bitdepth+optionsbyte optionsbyte=color+optionsbyte if triggerin: optionsbyte='1'+optionsbyte else: optionsbyte='0'+optionsbyte payload.append(bitstobytes(optionsbyte)[0]) darktime=convlen(darktime,24) darktime=bitstobytes(darktime) for i in darktime: payload.append(i) triggerout=convlen(not triggerout,8) triggerout=bitstobytes(triggerout) for i in triggerout: payload.append(i) patind=convlen(patind,11) bitpos=convlen(bitpos,5) lastbits=bitpos+patind lastbits=bitstobytes(lastbits) for i in lastbits: payload.append(i) self.command('w',0x00,0x1a,0x34,payload) # self.checkforerrors() def setbmp(self,index,size): payload=[] index=convlen(index,5) index='0'*11+index index=bitstobytes(index) for i in index: payload.append(i) total=convlen(size,32) total=bitstobytes(total) for i in total: payload.append(i) self.command('w',0x00,0x1a,0x2a,payload) # self.checkforerrors() def bmpload(self,image,size): t=time.clock() packnum=int(size//504)+1 counter=0 for i in range(packnum): if i %100==0: print (i,packnum) payload=[] if i<packnum-1: leng=convlen(504,16) bits=504 else: leng=convlen(size%504,16) bits=size%504 leng=bitstobytes(leng) for j in range(2): payload.append(leng[j]) for j in range(bits): payload.append(image[counter]) counter+=1 self.command('w',0x11,0x1a,0x2b,payload) #0x11 is for a response, IDK if we need it # self.checkforerrors() print("Time for loading: ", time.clock()-t) def defsequence(self,images,exp,ti,dt,to,rep): self.stopsequence() arr=[] for i in images: arr.append(i) num=len(arr) encodedimages=[] sizes=[] t=time.clock() self.configurelut(num,rep) for i in range(int((num-1)//24)+1): print ('merging...') if i<(int((num-1)//24)): imagedata=mergeimages(arr[i*24:(i+1)*24]) else: imagedata=mergeimages(arr[i*24:]) print('encoding...') imagedata,size=new_encode(imagedata) encodedimages.append(imagedata) sizes.append(size) if i<(int((num-1)//24)): for j in range(i*24,(i+1)*24): self.definepattern(j,exp[j],1,'111',ti[j],dt[j],to[j],i,j-i*24) else: for j in range(i*24,num): self.definepattern(j,exp[j],1,'111',ti[j],dt[j],to[j],i,j-i*24) print ("Time for merging and encoding: ", time.clock()-t) for i in range(int((num-1)//24)+1): #for i in range(len(encodedimages)) should work? self.setbmp(int((num-1)//24)-i,sizes[int((num-1)//24)-i]) print ('uploading...') self.bmpload(encodedimages[int((num-1)//24)-i],sizes[int((num-1)//24)-i]) print ("Total time: ", time.clock()-t) def convlen(a,l): """ This function converts a number "a" into a bit string of length "l". """ b=bin(a)[2:] padding=l-len(b) b='0'*padding+b return b def bitstobytes(a): """ This function converts a bit string into a given nuymber of bytes """ bytelist=[] if len(a)%8!=0: #if length is not a multiple of 8, make it a multiple. padding=8-len(a)%8 a='0'*padding+a for i in range(int(len(a)//8)): #put the bit in an array of byte bytelist.append(int(a[8*i:8*(i+1)],2)) bytelist.reverse() #reverse the list return bytelist def mergeimages(images): """ function that encodes a 8 bit numpy array matrix as a enhanced run length encoded string of bits """ mergedimage=numpy.zeros((1080,1920,3),dtype='uint8') #put this as numpy.uint8? for i in range(len(images)): if i<8: mergedimage[:,:,2]=mergedimage[:,:,2]+images[i]*(2**i) #with the multiplication, the 8 bit pixel contains the info abopu all the 8 images (if we are in binary...) if i>7 and i<16: mergedimage[:,:,1]=mergedimage[:,:,1]+images[i]*(2**(i-8)) if i>15 and i<24: #maybe 24 because in RGB you have 8*3 mergedimage[:,:,0]=mergedimage[:,:,0]+images[i]*(2**(i-16)) return mergedimage def new_encode(image): ## header creation bytecount=48 bitstring=[] bitstring.append(0x53) bitstring.append(0x70) bitstring.append(0x6c) bitstring.append(0x64) width=convlen(1920,16) width=bitstobytes(width) for i in width: bitstring.append(i) height=convlen(1080,16) height=bitstobytes(height) for i in height: bitstring.append(i) total=convlen(0,32) total=bitstobytes(total) for i in total: bitstring.append(i) for i in range(8): bitstring.append(0xff) for i in range(4): ## black curtain bitstring.append(0x00) bitstring.append(0x00) bitstring.append(0x02) ## enhanced rle bitstring.append(0x01) for i in range(21): bitstring.append(0x00) n=0 i=0 j=0 while i <1080: while j <1920: if i>0: if numpy.all(image[i,j,:]==image[i-1,j,:]): while j<1920 and numpy.all(image[i,j,:]==image[i-1,j,:]): n=n+1 j=j+1 bitstring.append(0x00) bitstring.append(0x01) bytecount+=2 if n>=128: byte1=(n & 0x7f)|0x80 byte2=(n >> 7) bitstring.append(byte1) bitstring.append(byte2) bytecount+=2 else: bitstring.append(n) bytecount+=1 n=0 else: if j < 1919: #1919 since I compare j and j+1 pixel if numpy.all(image[i,j,:]==image[i,j+1,:]): n=n+1 while j<1919 and numpy.all(image[i,j,:]==image[i,j+1,:]): n=n+1 j=j+1 if n>=128: byte1=(n & 0x7f)|0x80 byte2=(n >> 7) bitstring.append(byte1) bitstring.append(byte2) bytecount+=2 else: bitstring.append(n) bytecount+=1 bitstring.append(image[i,j-1,0]) bitstring.append(image[i,j-1,1]) bitstring.append(image[i,j-1,2]) bytecount+=3 j=j+1 n=0 elif j > 1917 or numpy.all(image[i,j+1,:]==image[i,j+2,:]) or numpy.all(image[i,j+1,:]==image[i-1,j+1,:]): bitstring.append(0x01) bytecount+=1 bitstring.append(image[i,j,0]) bitstring.append(image[i,j,1]) bitstring.append(image[i,j,2]) bytecount+=3 j=j+1 n=0 else: bitstring.append(0x00) bytecount+=1 toappend=[] while j<1919 and numpy.any(image[i,j,:]!=image[i,j+1,:]): """ I've moved the j<1919 condition as first condition since sometimes it tries to read image array at wrong index. """ n=n+1 toappend.append(image[i,j,0]) toappend.append(image[i,j,1]) toappend.append(image[i,j,2]) j=j+1 if n>=128: byte1=(n & 0x7f)|0x80 byte2=(n >> 7) bitstring.append(byte1) bitstring.append(byte2) bytecount+=2 else: bitstring.append(n) bytecount+=1 for k in toappend: bitstring.append(k) bytecount+=1 #j=j+1 n=0 elif j == 1919: bitstring.append(0x01) bytecount+=1 bitstring.append(image[i,j,0]) bitstring.append(image[i,j,1]) bitstring.append(image[i,j,2]) bytecount+=3 j=j+1 n=0 else: if j < 1919: #1919 since I compare j and j+1 pixel if numpy.all(image[i,j,:]==image[i,j+1,:]): n=n+1 while j<1919 and numpy.all(image[i,j,:]==image[i,j+1,:]): n=n+1 j=j+1 if n>=128: byte1=(n & 0x7f)|0x80 byte2=(n >> 7) bitstring.append(byte1) bitstring.append(byte2) bytecount+=2 else: bitstring.append(n) bytecount+=1 bitstring.append(image[i,j-1,0]) bitstring.append(image[i,j-1,1]) bitstring.append(image[i,j-1,2]) bytecount+=3 j=j+1 n=0 elif j > 1917 or numpy.all(image[i,j+1,:]==image[i,j+2,:]) or numpy.all(image[i,j+1,:]==image[i-1,j+1,:]): bitstring.append(0x01) bytecount+=1 bitstring.append(image[i,j,0]) bitstring.append(image[i,j,1]) bitstring.append(image[i,j,2]) bytecount+=3 j=j+1 n=0 else: bitstring.append(0x00) bytecount+=1 toappend=[] while j<1919 and numpy.any(image[i,j,:]!=image[i,j+1,:]): """ I've moved the j<1919 condition as first condition since sometimes it tries to read image array at wrong index. """ n=n+1 toappend.append(image[i,j,0]) toappend.append(image[i,j,1]) toappend.append(image[i,j,2]) j=j+1 if n>=128: byte1=(n & 0x7f)|0x80 byte2=(n >> 7) bitstring.append(byte1) bitstring.append(byte2) bytecount+=2 else: bitstring.append(n) bytecount+=1 for k in toappend: bitstring.append(k) bytecount+=1 #j=j+1 n=0 elif j == 1919: bitstring.append(0x01) bytecount+=1 bitstring.append(image[i,j,0]) bitstring.append(image[i,j,1]) bitstring.append(image[i,j,2]) bytecount+=3 j=j+1 n=0 j=0 i=i+1 bitstring.append(0x00) bitstring.append(0x00) bytecount+=2 bitstring.append(0x00) bitstring.append(0x01) bitstring.append(0x00) bytecount+=3 while (bytecount)%4!=0: bitstring.append(0x00) bytecount+=1 size=bytecount print (size) total=convlen(size,32) total=bitstobytes(total) for i in range(len(total)): bitstring[i+8]=total[i] for i in bitstring: print(i) return bitstring, bytecount if __name__ == "__main__": hiddev = DmdDeviceHID() import PIL.Image try: images=[] directory_in_str = "X:\\DMD\\Patterns\\DMD_patterns\\bin_sinusoidal_pattern\\" directory = os.fsencode(directory_in_str) i = 0 for file in sorted(os.listdir(directory)): filename = os.fsdecode(file) if filename.endswith("320.png"): arr = numpy.asarray(PIL.Image.open(directory_in_str+filename), dtype = numpy.bool) images.append(arr) i += 1 if i > 1: break hiddev.changemode(3) exposure=[1000000]*len(images) dark_time=[0]*len(images) trigger_in=[False]*len(images) trigger_out=[True]*len(images) hiddev.defsequence(images,exposure,trigger_in,dark_time,trigger_out, 60) hiddev.startsequence() work = "y" while work != "n": work = input() finally: hiddev.stopsequence() print("stopped")
Thank you,
Michele