def make_chlist(chans): # list containing the chans, gains and referencing nchans = len(chans) #number of channels #wrappers include a "chanlist" object (just an Unsigned Int array) for holding the chanlist information mylist = c.chanlist(nchans) #create a chanlist of length nchans #now pack the channel, gain and reference information into the chanlist object #N.B. the CR_PACK and other comedi macros are now python functions for index in range(nchans): mylist[index]=c.cr_pack(chans[index].no, chans[index].devrange, chans[index].aref) return mylist
def make_chlist(chans): # list containing the chans, gains and referencing nchans = len(chans) #number of channels #wrappers include a "chanlist" object (just an Unsigned Int array) for holding the chanlist information mylist = c.chanlist(nchans) #create a chanlist of length nchans #now pack the channel, gain and reference information into the chanlist object #N.B. the CR_PACK and other comedi macros are now python functions for index in range(nchans): mylist[index] = c.cr_pack(chans[index].no, chans[index].devrange, chans[index].aref) return mylist
def prepare_cmd(self,channels,gains,aref,freq): #First create the channel setup nchans = size(channels) channel_config = c.chanlist(nchans) #create a chanlist of length nchans print channel_config print channels for index in range(nchans): channel_config[index]=c.cr_pack(channels[index], gains[index], aref[index]) #Then create the command cmd = c.comedi_cmd_struct() cmd.subdev = self.subdevice cmd.flags = 0 cmd.start_src = c.TRIG_NOW cmd.start_arg = 0 cmd.scan_begin_src = c.TRIG_TIMER cmd.scan_begin_arg = int(1e9/freq) cmd.convert_src = c.TRIG_TIMER cmd.convert_arg = 0 cmd.scan_end_src = c.TRIG_COUNT cmd.scan_end_arg = nchans cmd.stop_src = c.TRIG_NONE cmd.stop_arg = 0 cmd.chanlist = channel_config cmd.chanlist_len = nchans ret = self.test_cmd(cmd) if ret !=0: self.logger.error("Error preparing command") return -1 return cmd
def streamer(device,subdevice,chans,comedi_range,shared_array): ''' read the channels defined in chans, on the device/subdevice, and streams the values in the shared_array. The shared_array has a lock, to avoid reading and writing at the same time and it's process-proof. device: '/dev/comedi0' subdevice : 0=in, 1=out chans : [0,1,2,3,4....] : BE AWARE the reading is done crescendo, no matter the order given here. It means that [0,1,2] and [2,0,1] will both have [0,1,2] as result, but you can ask for [0,1,5]. comedi_range: same size as chans, with the proper range for each chan. If unknown, try [0,0,0,....]. shared_array: same size as chans, must be defined before with multiprocess.Array: shared_array= Array('f', np.arange(len(chans))) ''' dev=c.comedi_open(device) if not dev: raise "Error openning Comedi device" fd = c.comedi_fileno(dev) #get a file-descriptor for use later BUFSZ = 10000 #buffer size freq=8000# acquisition frequency: if too high, set frequency to maximum. nchans = len(chans) #number of channels aref =[c.AREF_GROUND]*nchans mylist = c.chanlist(nchans) #create a chanlist of length nchans maxdata=[0]*(nchans) range_ds=[0]*(nchans) for index in range(nchans): #pack the channel, gain and reference information into the chanlist object mylist[index]=c.cr_pack(chans[index], comedi_range[index], aref[index]) maxdata[index]=c.comedi_get_maxdata(dev,subdevice,chans[index]) range_ds[index]=c.comedi_get_range(dev,subdevice,chans[index],comedi_range[index]) cmd = c.comedi_cmd_struct() period = int(1.0e9/freq) # in nanoseconds ret = c.comedi_get_cmd_generic_timed(dev,subdevice,cmd,nchans,period) if ret: raise "Error comedi_get_cmd_generic failed" cmd.chanlist = mylist # adjust for our particular context cmd.chanlist_len = nchans cmd.scan_end_arg = nchans cmd.stop_arg=0 cmd.stop_src=c.TRIG_NONE t0 = time.time() j=0 ret = c.comedi_command(dev,cmd) if ret !=0: raise "comedi_command failed..." #Lines below are for initializing the format, depending on the comedi-card. data = os.read(fd,BUFSZ) # read buffer and returns binary data data_length=len(data) #print maxdata #print data_length if maxdata[0]<=65536: # case for usb-dux-D n = data_length/2 # 2 bytes per 'H' format = `n`+'H' elif maxdata[0]>65536: #case for usb-dux-sigma n = data_length/4 # 2 bytes per 'H' format = `n`+'I' #print struct.unpack(format,data) # init is over, start acquisition and stream last_t=time.time() try: while True: #t_now=time.time() #while (t_now-last_t)<(1./frequency): #t_now=time.time() ##print t_now-last_t #last_t=t_now data = os.read(fd,BUFSZ) # read buffer and returns binary data #print len(data), data_length if len(data)==data_length: datastr = struct.unpack(format,data) # convert binary data to digital value if len(datastr)==nchans: #if data not corrupted for some reason #shared_array.acquire() for i in range(nchans): shared_array[i]=c.comedi_to_phys((datastr[i]),range_ds[i],maxdata[i]) #print datastr #shared_array.release() #j+=1 #print j #print "Frequency= ",(j/(time.time()-t0)) #print np.transpose(shared_array[:]) except (KeyboardInterrupt): c.comedi_cancel(dev,subdevice) ret = c.comedi_close(dev) if ret !=0: raise "comedi_close failed..."
chans= range(nchans) gains= [ 0 for i in chans ] aref =[c.AREF_GROUND for i in chans ] cmdtest_messages = [ "success", "invalid source", "source conflict", "invalid argument", "argument conflict", "invalid chanlist"] #wrappers include a "chanlist" object (just an Unsigned Int array) for holding the chanlist information mylist = c.chanlist(nchans) #create a chanlist of length nchans #now pack the channel, gain and reference information into the chanlist object #N.B. the CR_PACK and other comedi macros are now python functions for index in range(nchans): mylist[index]=c.cr_pack(chans[index], gains[index], aref[index]) size = c.comedi_get_buffer_size(dev, subdevice) print "buffer size is ", size map = mmap.mmap(fd, size, mmap.MAP_SHARED, mmap.PROT_READ) print "map = ", map def dump_cmd(cmd): print "---------------------------" print "command structure contains:"
def streamer(device, subdevice, chans, comedi_range, shared_array): ''' read the channels defined in chans, on the device/subdevice, and streams the values in the shared_array. The shared_array has a lock, to avoid reading and writing at the same time and it's process-proof. device: '/dev/comedi0' subdevice : 0=in, 1=out chans : [0,1,2,3,4....] : BE AWARE the reading is done crescendo, no matter the order given here. It means that [0,1,2] and [2,0,1] will both have [0,1,2] as result, but you can ask for [0,1,5]. comedi_range: same size as chans, with the proper range for each chan. If unknown, try [0,0,0,....]. shared_array: same size as chans, must be defined before with multiprocess.Array: shared_array= Array('f', np.arange(len(chans))) ''' dev = c.comedi_open(device) if not dev: raise "Error openning Comedi device" fd = c.comedi_fileno(dev) #get a file-descriptor for use later BUFSZ = 10000 #buffer size freq = 8000 # acquisition frequency: if too high, set frequency to maximum. nchans = len(chans) #number of channels aref = [c.AREF_GROUND] * nchans mylist = c.chanlist(nchans) #create a chanlist of length nchans maxdata = [0] * (nchans) range_ds = [0] * (nchans) for index in range( nchans ): #pack the channel, gain and reference information into the chanlist object mylist[index] = c.cr_pack(chans[index], comedi_range[index], aref[index]) maxdata[index] = c.comedi_get_maxdata(dev, subdevice, chans[index]) range_ds[index] = c.comedi_get_range(dev, subdevice, chans[index], comedi_range[index]) cmd = c.comedi_cmd_struct() period = int(1.0e9 / freq) # in nanoseconds ret = c.comedi_get_cmd_generic_timed(dev, subdevice, cmd, nchans, period) if ret: raise "Error comedi_get_cmd_generic failed" cmd.chanlist = mylist # adjust for our particular context cmd.chanlist_len = nchans cmd.scan_end_arg = nchans cmd.stop_arg = 0 cmd.stop_src = c.TRIG_NONE t0 = time.time() j = 0 ret = c.comedi_command(dev, cmd) if ret != 0: raise "comedi_command failed..." #Lines below are for initializing the format, depending on the comedi-card. data = os.read(fd, BUFSZ) # read buffer and returns binary data data_length = len(data) #print maxdata #print data_length if maxdata[0] <= 65536: # case for usb-dux-D n = data_length / 2 # 2 bytes per 'H' format = ` n ` + 'H' elif maxdata[0] > 65536: #case for usb-dux-sigma n = data_length / 4 # 2 bytes per 'H' format = ` n ` + 'I' #print struct.unpack(format,data) # init is over, start acquisition and stream last_t = time.time() try: while True: #t_now=time.time() #while (t_now-last_t)<(1./frequency): #t_now=time.time() ##print t_now-last_t #last_t=t_now data = os.read(fd, BUFSZ) # read buffer and returns binary data #print len(data), data_length if len(data) == data_length: datastr = struct.unpack( format, data) # convert binary data to digital value if len(datastr ) == nchans: #if data not corrupted for some reason #shared_array.acquire() for i in range(nchans): shared_array[i] = c.comedi_to_phys( (datastr[i]), range_ds[i], maxdata[i]) #print datastr #shared_array.release() #j+=1 #print j #print "Frequency= ",(j/(time.time()-t0)) #print np.transpose(shared_array[:]) except (KeyboardInterrupt): c.comedi_cancel(dev, subdevice) ret = c.comedi_close(dev) if ret != 0: raise "comedi_close failed..."
#three lists containing the chans, gains and referencing #the lists must all have the same length chans = [0, 1, 2, 3] gains = [0, 0, 0, 0] aref = [c.AREF_GROUND, c.AREF_GROUND, c.AREF_GROUND, c.AREF_GROUND] cmdtest_messages = [ "success", "invalid source", "source conflict", "invalid argument", "argument conflict", "invalid chanlist" ] nchans = len(chans) #number of channels #wrappers include a "chanlist" object (just an Unsigned Int array) for holding the chanlist information mylist = c.chanlist(nchans) #create a chanlist of length nchans #now pack the channel, gain and reference information into the chanlist object #N.B. the CR_PACK and other comedi macros are now python functions for index in range(nchans): mylist[index] = c.cr_pack(chans[index], gains[index], aref[index]) size = c.comedi_get_buffer_size(dev, subdevice) print("buffer size is ", size) map = mmap.mmap(fd, size, mmap.MAP_SHARED, mmap.PROT_READ) print("map = ", map) def dump_cmd(cmd): print("---------------------------") print("command structure contains:")
maxdata = c.comedi_get_maxdata(dev, 0, 0) print "Max Data: %d" % maxdata subdev = c.comedi_find_subdevice_by_type(dev, c.COMEDI_SUBD_COUNTER, 0) print "Subdevice: %d" % subdev print "Locked? %d" % c.comedi_lock(dev, subdev) nChannels = c.comedi_get_n_channels(dev, subdev) print "Num Channels: %d" % nChannels crange = c.comedi_get_range(dev, 0, 0, 0) print "Range: %s" % str(crange) params = c.chanlist(1) params[0] = 0 # configure the encoder instr = c.comedi_insn_struct() instr.insn = c.INSN_CONFIG instr.n = 1 instr.data = params instr.subdev = 5 # instr.chanspec = c.cr_pack(0,0,c.AREF_OTHER) instr.chanspec = c.cr_pack(0,0,0) ret=c.comedi_do_insn(dev,instr); print ret # Encoder read instruction */
def pci_6033e_init(self, dev_name): self.dev = c.comedi_open(dev_name) if not(self.dev): self.warn_dialog("Unable to open device: " + dev_name) return(-1) ret = c.comedi_lock(self.dev, SUBDEVICE) if (ret < 0): self.warn_dialog("Could not lock comedi device") return(-1) # get a file-descriptor for use later self.fd = c.comedi_fileno(self.dev) if (self.fd <= 0): self.warn_dialog("Error obtaining Comedi device file descriptor") c.comedi_close(self.dev) return(-1) # Channel range (0-5V) if (c.comedi_range_is_chan_specific(self.dev, SUBDEVICE) != 0): self.warn_dialog("Comedi range is channel specific!") c.comedi_close(self.dev) return(-1) self.comedi_range = c.comedi_get_range(self.dev, SUBDEVICE, 0, CHAN_RANGE) self.comedi_maxdata = c.comedi_get_maxdata(self.dev, SUBDEVICE, 0) board_name = c.comedi_get_board_name(self.dev) if (board_name != "pci-6033e"): print("Opened wrong device!") # Prepare channels, gains, refs self.comedi_num_chans = NUM_CHANNELS chans = range(self.comedi_num_chans) gains = [0]*self.comedi_num_chans aref = [c.AREF_GROUND]*self.comedi_num_chans chan_list = c.chanlist(self.comedi_num_chans) # Configure all the channels! for i in range(self.comedi_num_chans): chan_list[i] = c.cr_pack(chans[i], gains[i], aref[i]) # The comedi command self.cmd = c.comedi_cmd_struct() # 1.0e9 because this number is in nanoseconds for some reason period = int(1.0e9/float(SCAN_FREQ)) # Init cmd ret = c.comedi_get_cmd_generic_timed(self.dev, SUBDEVICE, self.cmd, self.comedi_num_chans, period) if (ret): self.warn_dialog("Could not initiate command") c.comedi_close(self.dev) return(-1) # Populate command self.cmd.chanlist = chan_list self.cmd.chanlist_len = self.comedi_num_chans self.cmd.scan_end_arg = self.comedi_num_chans self.cmd.stop_src = c.TRIG_NONE self.cmd.stop_arg = 0 print("real timing: %d ns" % self.cmd.convert_arg) print("Real scan freq: %d Hz" % (1.0/(float(self.cmd.convert_arg)*32.0*1.0e-9))) #print("period: %d ns" % period) print_cmd(self.cmd) # Test command out. ret = c.comedi_command_test(self.dev, self.cmd) if (ret < 0): self.warn_dialog("Comedi command test failed!") c.comedi_close(self.dev) return(-1) print("Command test passed") return(0)
def acquire_data(config): """ Acquire data from data acquisition device. """ #Open a comedi device dev = c.comedi_open(config['device']) if not dev: err_msg = "%s: error: unable to open openning Comedi device" % ( PROG_NAME, ) sys.stderr.write(err_msg) sys.exit(1) # Get a file-descriptor to access data fd = c.comedi_fileno(dev) # Setup channels nchans = len(config['channels']) aref_str = config['aref'].lower() if aref_str == 'diff': aref = [c.AREF_DIFF] * nchans elif aref_str == 'common': aref = [c.AREF_COMMON] * nchans elif aref_str == 'ground': aref = [c.AREF_GROUND] * nchans else: raise ValueError, 'unknown aref' #nchans = len(config['channels']) #aref =[c.AREF_GROUND]*nchans # Pack the channel, gain and reference information into the chanlist object channel_list = c.chanlist(nchans) for i in range(nchans): channel_list[i] = c.cr_pack(config['channels'][i], config['gains'][i], aref[i]) # Construct a comedi command cmd = c.comedi_cmd_struct() cmd.subdev = config['subdev'] cmd.flags = DEFAULT_CMD_FLAGS cmd.start_src = c.TRIG_NOW cmd.sart_arg = DEFAULT_CMD_SART_ARG cmd.scan_begin_src = c.TRIG_TIMER cmd.scan_begin_arg = int(NANO_SEC / config['sample_freq']) cmd.convert_src = c.TRIG_TIMER cmd.convert_arg = DEFAULT_CMD_CONVERT_ARG cmd.scan_end_src = c.TRIG_COUNT cmd.scan_end_arg = nchans cmd.stop_src = c.TRIG_COUNT cmd.stop_arg = config['sample_num'] cmd.chanlist = channel_list cmd.chanlist_len = nchans # Test comedi command if config['verbose']: print 'Testing comedi command' print for i in range(0, DEFAULT_CMD_TEST_NUM): if config['verbose']: print_cmd(cmd) ret = c.comedi_command_test(dev, cmd) if config['verbose']: print print '\t*** test %d returns %s' % (i, CMD_TEST_MSG[ret]) print if not ret == 0: msg_data = (PROG_NAME, CMD_TEST_MSG[ret]) err_msg = '%s: error: unable to configure daq device - %s' % msg_data sys.stderr.write(err_msg) # Acquire data if config['verbose']: print 'acquiring data' print sys.stdout.flush() ret = c.comedi_command(dev, cmd) # non blocking if not ret == 0: err_msg = '%s: error: unable to execute comedi command' % (PROG_NAME, ) sys.stderr.write(err_msg) sys.exit(1) # Read data from buffer - may want to add a timeout here read_done = False bytes_total = 2 * config['sample_num'] * nchans bytes_read = 0 datastr = '' while not read_done: try: buffstr = os.read(fd, bytes_total) except OSError, err: if err.args[0] == 4: continue raise datastr += buffstr bytes_read += len(buffstr) if config['verbose']: print '\tread:', bytes_read, 'of', 2 * config[ 'sample_num'] * nchans, 'bytes' if bytes_read == bytes_total: read_done = True
def scancommand(self, nscans=1000, chans=None, gains=None, aref=None): """Setup a scan nscans: total number of scans (int) chans: which channels (list) gains: which gain adjustments (list) aref: analog references (list) The lists must all have the same length! [sic] I think this will work but it's completely untested! --bryan I was not able to get this to work with my Vellemen P8061-2 board -- foley """ if not chans: raise RuntimeError("No Channels given in 'chans'") if not gains: raise RuntimeError("No gains given in 'gains'") if not aref: raise RuntimeError("No analog references given in 'aref'") if not len(chans) == len(gains) == len(aref): raise RuntimeError( "chans(%d), gains(%d), and aref(%d) not the same size" % (len(chans), len(gains), len(aref))) nchans = len(chans) # number of channels # wrappers include a "chanlist" object (just an Unsigned Int # array) for holding the chanlist information mylist = c.chanlist(nchans) # create a chanlist of length nchans # now pack the channel, gain and reference information into # the chanlist object # N.B. the CR_PACK and other comedi macros are now python functions for index in range(nchans): mylist[index] = c.cr_pack( chans[index], gains[index], aref[index]) # construct a comedi command manually cmd = c.cmd_struct() cmd.subdev = 0 cmd.flags = 0 cmd.start_src = c.TRIG_NOW cmd.sart_arg = 0 cmd.scan_begin_src = c.TRIG_TIMER cmd.scan_begin_arg = int(1.0E9 / 100000) cmd.convert_src = c.TRIG_TIMER cmd.convert_arg = 1 cmd.scan_end_src = c.TRIG_COUNT cmd.scan_end_arg = nchans cmd.stop_src = c.TRIG_COUNT cmd.stop_arg = nscans cmd.chanlist = mylist cmd.chanlist_len = nchans dev = self.dev # test our comedi command a few times. ret = c.command_test(dev, cmd) print("first cmd test returns ", ret) ret = c.command_test(dev, cmd) print("second test returns ", ret) ret = c.command_test(dev, cmd) if not ret: raise RuntimeError("Error testing comedi command") ret = c.command(self.dev, cmd) chunk = 8 # chunk: how many bytes to read at a time datalist = [] data = os.read(self.cfd, chunk) while len(data) > 0: datalist.append(data) data = os.read(self.cfd, chunk) datastr = string.join(datalist, '') print("Data from command:") print(datastr) # Here's your data, as a single string! # if you've got Numeric installed you can convert data # into a flat Numpy array with: # dataarray = Numeric.fromstring(data, Int16) return ret