' ************************************************* ' * * ' * source code module for dll with support * ' * functions for hardware access with and * ' * without NiDAQ devices. * ' * Also supports USB UART devices under NT * ' * by * ' * Prof.Dr.Godfried-Willem Raes * ' ************************************************* ' * This module contains all low level code for * ' * the music automats at Logos Foundation * ' * as well as for the invisible instruments * ' * GMT version 10.05 * ' ************************************************* ' metacompilation constant for debugging of pp code: '%pp_debug = %True ' if compiled with this constant, messages are generated on 'out of timers' from ' ' winApi in robot control procedures. '%g_nidaq = %True ' this includes extra nidaq functions for NiDAQ7.4 - legacy ' Hardware and NiDAQ/NiDAQmx support library for GMT ' 23.11.2000: Kernel32 crash in g_nih.dll ' bug found: NiDAQ cannot configure callback procedures without window handles correctly... ' so we disabled the double buffer copy mechanism. ' 06.11.2001: 16 bit ports implemented for Vibi on NiDAQ 6533 DaqCard devices. ' 15.05.2002: support for Activewire usb devices added. ' 19.05.2002: proc. added for serial IO devices. ' 28.05.2002: Klung support for AW-USB added. ' 03.06.2002: AW-USB buffer out procedures tested in Belly and Autosax code sections. ' 04.06.2002: AW-USB buffer out added for Klung, Troms, Harma, ThunderWood ' Springers code modified for multiport use. ' Rotomoton cannot work with AW-USB since it has only 4 input bits available... ' 06.06.2002: IO port selector implemented for . ' 01.07.2002: AW-USB tested on Troms and Belly: O.K. ' 04.08.2002: Debug Thunderwood: new lightning relais and storm component. ' 09.08.2002: Autosax feedback procedure added. ' 12.08.2002: Playseq code added by Kristof Lauwers (Klung) ' 14.08.2002: start implementation of play seq for autosax ' 29.08.2002: start support for ' 09.09.2002: first tests flex motors code. ' 17.09.2002: Flex motors usb port support added. ' 16.10.2002: runs o.k. with AW-USB support. ' 20.10.2002: up and running... ' 26.10.2002: dripper listentask added. ' 20.11.2002: Thunderwood all off code improved. ' 24.11.2002: Harma support for network UDP/IP listening added. - crashes! ' 06.12.2002: Belly support for network UDP/IP listening added. ' double belly tasks removed. Now we use a controller for the mapping switch. ' 08.12.2002: Harma coding changed. Motor task eliminated. Now uses a periodic timer for PWM. ' 12.12.2002: Dripper UDP listen added. ' 15.12.2002: Belly-listen debugged. ' 17.12.2002: listen task messaging for belly implemented. ' 20.12.2002: selective channel listening implemented for all automats. ' 04.01.2003: Flex_beat inline usb coding added. ' 19.01.2003: Flex coding midi-input ' 30.01.2003: Support for ADXL202 using serial port added. ' 31.01.2003: Code for ADXL202 finalized. ' 08.02.2003: Code support for quad radar interface added.(Requires NiDAQ) ' 10.02.2003: DFT's for quadradar added. ' 24.02.2003: unused callback window code for NiDAQ removed. ' 02.03.2003: Absolute coordinates and velocity derivation added in Quadrada section. ' 03.03.2003: acceleration derivation added in quadrada. ' 11.03.2003: integration vars. added in quadrada ' 31.03.2003: Quadradar code finalized. ' 14.04.2003: New sonar code added. ' 19.04.2003: Tubi support added. ' 25.04.2003: Tubi USB support added. ' 06.05.2003: Tubi up and working. Midi listen o.k. ' 29.05.2003: Code for softshift solenoids in Flex added. ' 01.06.2003: Coding for Flex changed and improved. ' 07.03.2003: Development of code works on ' 08.03.2003: testing. ' 10.03.2003: Flex now also listens to meta commands. ' 20.09.2003: display procs. for Quadrada added to library. - note: the radar-control task is in g_main.inc (g_lib.dll) ' 21.09.2003: id. for sonar (sonar control task in g_main.inc) ' 23.09.2003: research in equivalence parametering for sonar/radar ' 30.10.2003: sonar coding changed. Now with data dependent integration. ' 04.11.2003: sonar statistics coding added. ' 11.04.2004: Troms support removed. ' 14.04.2004: SonarRanger support added.(Polaroid 50kHz system) - needs printerport. ' 19.07.2004: integration changed to float in quadradar callback procedure qt().amp ' 24.07.2004: autosax listen improved. - start/stop procs added to all robot code. ' debug on harma implementation. ' 25.07.2004: Harma listentask rewritten. We still have problems with it! ' 26.07.2004: further work un usb buffered output for Harma. ' this dll now runs in realtime priority. ' Seems to work again in tests on Harma. Other robots to be checked again. (Klung and ThunderWood) ' 27.07.2004: all robotlistentasks upgraded. ' 21.11.2004: new code module g_mm added. ' 09.12.2004: red light support added to Harma. ' 10.12.2004: dito debugging. ' 23.01.2005: tubi procs. become unneeded now. ' 25.01.2005: old tubi code moved to g_h_tubi.inc (in tubi directory) ' 30.01.2005: vibi and dripper support is now conditional: these robots become midi controlled. ' 07.02.2005: vibi code moved to \robots\vibi\vibi_dllprocs.inc ' 05.03.2005: adapted to PBWIN 8.00 compiler ' 14.03.2005: dripper support removed. ' 28.03.2005: belly code adapted to bell-swap. ' 12.07.2005: harma coding now conditional: will become midi robot ' 16.05.2005: original coding for harma moved to :C:\b\pb\gmt\robots\harma\g_harma.inc ' 28.11.2005: start added code for new sonar devices on USB/COM ports. ' 18.12.2005: all harma code removed here. ' 06.01.2006: kl - working on UsbSonar implementation ' basics are working but still some todo's - see comment in the usbsonar section.. ' 10.01.2006: support for Krum added. ' 02.05.2006: autosax V2 removed. - resource adapted. ' 26.06.2006: crashes after installing on Xi, being forced to upgrade the NiDAQ drivers to version 7.4.1 ' could only be solved by avoiding to link g_nih.dll statically. ' 26.07.2006: problem seems to be solved... ' 19.08.2006: Klung I/O select removed. ' 31.08.2006: Springers I/O select removed. ' 18.10.2006: Klung removed, rotomoton removed, thunderwood removed. ' 29.11.2006: recompiled under PBWIN8.03 ' 08.01.2007: recompile ' 24.02.2007: new resource file ' 23.05.2007: NiDaq upgrade 7.44 ' 31.08.2008: adapted to PB compiler 9.0 - gwr changed varnames 'point', com$ , display (proc.name) ' 12.05.2009: Problems with Nidaq 7.44 running under Windows 7. ' 31.05.2009: temporary attempt to start making 3 different compilations... ' using $dll string constant in the bi file ' Works on \\No with g_noh.dll and g_nxh.dll. g_nih.dll fails to load. ' 02.06.2009: all flex code removed from module. ' support for giant_display removed from code. ' 03.06.2009: Checktimerresolution procedure moved to g_indep.dll ' Call to this proc removed from initdll here, since it was doubled with the exe. ' 06.06.2009: coding to get menu's right in GMT with NIDAmx. Sonar_Daq code adapted. ' 07.06.2009: should now work with NiDAQmx and the g_nxh.dll compilation. ' 08.06.2009: cleanup of no longer used code. ' debug session ' 10.06.2009: Start implementing a 3 channel 1024S/s task for Nidaqmx ' 13.06.2009: Implementation of timescaled buffers in 2 octave intervals for NiDAQmx ' 14.06.2009: Data acquisition under NiDAQmx works pretty well now. Debug o.k. ' code can still be improved for speed and intelligence. ' 19.06.2009: batch file compilation implemented ' 04.07.2009: debug and test session under Nidaqmx ' 05.07.2009: debug and research on fast doppler ' 12.07.2009: works perfectly under Win7, XP gives problems at times. ' 13.07.2009: persistent problems on \\Xi... ' 22.07.2009: First concert using NiDAQmx: GWR's butoh production ' 03.09.2009: Start implementation of 24GHz devices. ' 08.09.2009: further work on 24GHz radar implementation, but by far nor ready yet!!! ' 19.09.2009: further work on 24GHz implementation ' 09.03.2010: problems after NidaqMx upgrade to 9.1. it apppears that our EveryN callback functions need to be CDECL. ' sonar and doppler work again.. with the 24Ghz radar we don't get crashes, but we get errors.. ' Channel assignment adapted to new wiring of the hardware. ' 11.04.2010: Doppler DAQ code appears to be stable now on all platforms. ' 30.03.2011: Compiler upgrade to version 10 - problem with the Thread Create function! ' *********************** METACOMMANDS *************************************************************************** #COMPILER PBWIN 10 #DEBUG ERROR OFF ' if ON should trap array boundary errors... #DEBUG DISPLAY OFF 'ON ' this slows down the code and should be only set during development!!! #TOOLS OFF 'ON ' OFF ' temporary: 3 different compilations '%NiDAQ = 1 ' always compile 2 times: once with this constant, once without it!!! '%g_NiDAQmx = 1 ' third compilation '#INCLUDE ONCE "_meta.inc" ' use only this one for batch file compilation of the 3 versions '#include ONCE "_g_noh.inc" ' no NiDaq support defined '#include ONCE "_g_nih.inc" ' NiDaq 7.4 support - defines %NiDAQ #INCLUDE ONCE "_g_nxh.inc" ' Nidaqmx 8.8 support - defines %g_NiDAQmx #OPTION VERSION5 ' compile for Windows2000 and/or NT5 #IF %DEF(%NIDAQ) #COMPILE DLL "g_nih.dll" ' public declarations in g_h.bi - $dll in .bi file defined. #ELSEIF %DEF(%g_NiDAQmx) #COMPILE DLL "g_nxh.dll" ' public declarations in g_h.bi #ELSE #COMPILE DLL "g_noh.dll" ' public declarations in g_h.bi #ENDIF #REGISTER ALL ' This metastatement should appear only once. #DIM ALL #INCLUDE ONCE "..\winapi\g_win.inc" ' Win32API - version for pb 9.00 '#INCLUDE "..\winapi\Win32api.inc" ' include too large, does not compile %Winapi = 1 ' g_win.inc should contain the timer functions... #INCLUDE ONCE "g_kons.bi" ' only integer constants and strings can be declared in PB #INCLUDE ONCE "g_type.bi" ' This declares all our own structures, user defined types #IF %DEF(%NiDAQ) #INCLUDE ONCE "..\winapi\Nidaq32-pb.inc" 'proc.declarations V7.44 #INCLUDE ONCE "..\winapi\Nidaqcns-pb.inc" 'constants declaration V7.44 #INCLUDE ONCE "..\winapi\Nidaqerr-pb.inc" 'error handling procs. and msg's. '#INCLUDE "..\winapi\Nidex32-pb.inc" 'examples & error library - enable this if you want to debug ' any nidaq function with retval = NiDaqError .... (remmed in the source here) #INCLUDE ONCE "g_glib.bi" 'required for radar displays etc... #ELSEIF %DEF(%g_NiDAQmx) #INCLUDE ONCE "..\winapi\NIDAQmx_const.inc" ' constants for NiDAQmx V8.8 , V9.9 #INCLUDE ONCE "..\winapi\NIDAQmx_err.inc" ' error codes for NiDAQmx V8.8 , V9.9 #INCLUDE ONCE "..\winapi\NIDAQmx_pb.inc" ' function declarations V9.9 #INCLUDE ONCE "g_glib.bi" #ENDIF #INCLUDE ONCE "g_lib.bi" ' essential #INCLUDE ONCE "g_mus.bi" #INCLUDE ONCE "g_indep.bi" ' essential #INCLUDE ONCE "g_file.bi" '#INCLUDE "g_net.bi" ' seems not required. '#INCLUDE "g_robo.bi" ' removed 02.06.2009 #IF %DEF(%ACTIVEWIRE) #INCLUDE ONCE "..\USB_ActiveWire\AwUSBapi.inc" #ENDIF %g_h_inc = %True #INCLUDE ONCE "g_h.bi" ' declares for exported functions and procedures only #RESOURCE "resource\g_h.pbr" '#resource "resource\g_h.res" does not work... ' **************************************************************************** ' globals: pointers to structures used in GMT:******************************** GLOBAL pDAQparams AS DataAcquisitionParameters PTR GLOBAL pDIOparams AS DigitalIOparameters PTR ' pointers to the world created in the GMT application: GLOBAL pT() AS Taak PTR ' pointers to the global Task() structures in GMT. GLOBAL pTeX() AS ExtraInfo PTR ' added 20.09.2003 GLOBAL pApp AS ApplicationType PTR ' pointer to App structure in GMT GLOBAL pgh AS GMT_HANDLES PTR ' handles to gmt windows created in GMT GLOBAL pUDCtrl() AS UpDownController PTR ' 20.09.2003 'GLOBAL pButnSW() AS SwitchController PTR ' 24.04.2000 'GLOBAL pButnOS() AS OneShotController PTR ' 24.04.2000 GLOBAL pSlider() AS SliderController PTR ' 20.09.2003 ' data acquisition buffers: GLOBAL ADCbuffer() AS INTEGER GLOBAL DAQbuffer() AS INTEGER GLOBAL ADXL202 AS AccelSensDevice ' 30.01.2003 - serial version (Axe2) GLOBAL UsbSonar AS USBSonarDevice ' 23.12.2005 - we use the same type as for adxl for now, but probably will need a separate one later on.. GLOBAL qr() AS RadarType ' 08.02.2003 QuadRadar GLOBAL sr AS SonarType ' 14.04.2003 ii- sonar GLOBAL tetrad AS RadarTetrahedronType ' placed here 13.07.2009 GLOBAL R24GT AS Radar24GHzTetrahedronType ' 07.09.2009 GLOBAL db0() AS INTEGER GLOBAL db1() AS INTEGER GLOBAL db2() AS INTEGER GLOBAL db3() AS INTEGER GLOBAL db4() AS INTEGER GLOBAL db5() AS INTEGER GLOBAL db6() AS INTEGER GLOBAL db7() AS INTEGER GLOBAL db8() AS INTEGER ' for compatibility with legacy hardware for GLOBAL db9() AS INTEGER GLOBAL dbA() AS INTEGER GLOBAL dbB() AS INTEGER GLOBAL dbC() AS INTEGER GLOBAL dbD() AS INTEGER GLOBAL dbE() AS INTEGER GLOBAL dbF() AS INTEGER GLOBAL xfbuf() AS SINGLE ' for ii_doppler and 24GHz radar GLOBAL yfBuf() AS SINGLE ' frequency buffers. 64 measurements deep. GLOBAL zfBuf() AS SINGLE GLOBAL cfBuf() AS SINGLE GLOBAL dbx() AS DOUBLE ' 0.25 second buffers, fast data - Sampling rate 1024 S/s GLOBAL dby() AS DOUBLE GLOBAL dbz() AS DOUBLE 'GLOBAL dbce() AS DOUBLE ' double def. rename required!!! GLOBAL dbxm() AS DOUBLE ' 1 second buffers, medium data - Sampling rate 256 S/s GLOBAL dbym() AS DOUBLE GLOBAL dbzm() AS DOUBLE 'GLOBAL dbcm() AS DOUBLE GLOBAL dbxs() AS DOUBLE ' 4 second buffers, slow data - Sampling rate 64 S/s GLOBAL dbys() AS DOUBLE GLOBAL dbzs() AS DOUBLE 'GLOBAL dbcs() AS DOUBLE GLOBAL dbx24Gf() AS DOUBLE GLOBAL dby24Gf() AS DOUBLE GLOBAL dbz24Gf() AS DOUBLE GLOBAL dbc24Gf() AS DOUBLE GLOBAL dbx24Gm() AS DOUBLE GLOBAL dby24Gm() AS DOUBLE GLOBAL dbz24Gm() AS DOUBLE GLOBAL dbc24Gm() AS DOUBLE GLOBAL dbx24Gs() AS DOUBLE GLOBAL dby24Gs() AS DOUBLE GLOBAL dbz24Gs() AS DOUBLE GLOBAL dbc24Gs() AS DOUBLE GLOBAL hInst AS LONG ' instance handle of this dll - saved in gh.gnh GLOBAL CritSecWait AS Critical_Section ' used in the Wait procedure GLOBAL board AS DWORD ' holds the connected board. (constant %II_2000, %ANACOMP etc...) ' read from ini file GLOBAL SonarRanger AS SonarRangerType ' only for Sonar Ranging device (Polaroid 50kHz) GLOBAL Doppler AS DopplerType ' for ii_2000 under NiDAQmx ' for USB_UART support: GLOBAL USB_DIO() AS USB_DIO_TYPE ' 10.01.2002 - USB UART's Elektor GLOBAL DisplayPanel AS DisplayType ' 07.02.2002 GLOBAL IOports AS IOportsType ' 08.02.2002 GLOBAL NiMxDevs() AS ASCIIZ * 20 ' 06.06.2009 ' non-exported functions and procedures: DECLARE FUNCTION DLLMAIN (BYVAL h AS LONG, BYVAL fwdReason AS LONG, BYVAL lpvReserved AS LONG) AS LONG DECLARE FUNCTION Ni_16bitHandshake(BYVAL prt AS BYTE) AS LONG ' 05.11.2001 'DECLARE FUNCTION Aw_Usb_CentroPort (BYVAL devnr AS DWORD) AS DWORD ' 15.05.2002 DECLARE FUNCTION IOportselector (BYVAL device AS DWORD) AS DWORD DECLARE CALLBACK FUNCTION IoDlgCallback() AS LONG ' for acceleration sensor device: [30.01.2003] - 24.10.2007 replaced with Axe3 sensor. DECLARE SUB ADXL202_CB (BYVAL wTimerID AS LONG, BYVAL msg AS LONG, BYVAL EventNr AS LONG, BYVAL dw1 AS LONG, BYVAL dw2 AS LONG) ' for QuadRadar: [08.02.2003] - 2.8GHz devices DECLARE SUB RadarDAQTask_CB (BYVAL wTimerID AS LONG, BYVAL msg AS LONG, BYVAL eventnr AS LONG, BYVAL dw1 AS LONG, BYVAL dw2 AS LONG) DECLARE FUNCTION Quadradar_PosAmp (BYVAL i AS DWORD) AS DWORD ' 30.03.2003 - uses integrated amplitude input. DECLARE FUNCTION Quadradar_TetraMath (BYVAL i AS DWORD) AS DWORD ' 11.03.2003 ' for Sonar - ii [14.04.2003] - 40kHz devices - NiDAQ version DECLARE SUB SonarDAQTask_CB (BYVAL wTimerID AS LONG, BYVAL msg AS LONG, BYVAL eventnr AS LONG, BYVAL dw1 AS LONG, BYVAL dw2 AS LONG) ' for NIDAQmx: [06.06.2009] 'ímportant note: since NidaqMx version 9.1., it is crucial to use CDECL DECLARE FUNCTION ii2000_EveryNCallback CDECL (BYVAL taskHandle AS LONG, BYVAL everyNsamplesEventType AS LONG, BYVAL nSamples AS LONG, BYVAL pCallBackData AS DWORD PTR) AS LONG DECLARE FUNCTION Quadrada_EveryNCallback CDECL (BYVAL taskHandle AS LONG, BYVAL everyNsamplesEventType AS LONG, BYVAL nSamples AS LONG, BYVAL pCallBackData AS DWORD PTR) AS LONG DECLARE FUNCTION NiDAQmx_DoneCallback CDECL (BYVAL taskHandle AS LONG,BYVAL stat AS LONG, BYVAL pCallBackData AS DWORD PTR) AS LONG DECLARE FUNCTION Doppler_EveryNCallback CDECL (BYVAL taskHandle AS LONG, BYVAL everyNsamplesEventType AS LONG, BYVAL nSamples AS LONG, BYVAL pCallBackData AS DWORD PTR) AS LONG ' for 24GHz radar devices in tetrahedron setup: DECLARE FUNCTION R24GT_EveryNCallback CDECL (BYVAL taskHandle AS LONG, BYVAL everyNsamplesEventType AS LONG, BYVAL nSamples AS LONG, BYVAL pCallBackData AS DWORD PTR) AS LONG ' common for sonar and radar, NiDAQ and NiDAQmx: DECLARE SUB Sonar_ii_Math () ' 07.06.2009 DECLARE SUB Quadrada_ii_Math () ' 07.06.2009 ' only for NiDAQmx: DECLARE SUB Doppler_ii_Math () ' to be written ' ************************************************************************************** FUNCTION DLLMAIN(BYVAL H AS LONG, _ BYVAL fwdReason AS LONG, _ BYVAL lpvReserved AS LONG) EXPORT AS LONG 'here we reserve buffers for all devices we might possibly use.. is this a good idea? LOCAL retval AS LONG LOCAL i AS DWORD FUNCTION = %True SELECT CASE fwdReason CASE %DLL_PROCESS_ATTACH IF ISFALSE hInst THEN hInst = H ' done only in StartDataAcquisitionTask !!! DIM ADCbuffer(7) AS GLOBAL INTEGER ' primary buffer twice the size of DAQbuffer in DB mode. DIM DAQbuffer(7) AS GLOBAL INTEGER ' for memory allocation only. DIM pT(%NumberOfTasks -1) AS GLOBAL TAAK PTR 'DIM pTeX(%NumberOfTasks -1) as global ExtraInfo PTR ' 29.05.2002 - removed again DIM USB_DIO(7) AS GLOBAL USB_DIO_TYPE ' 10.01.2002 DIM qr(4) AS GLOBAL RadarType ' 08.02.2003 -0,1,2,3= raw data, 4= integrated results DIM db0(255) AS GLOBAL INTEGER ' for ii-devices. DIM db1(255) AS GLOBAL INTEGER DIM db2(255) AS GLOBAL INTEGER DIM db3(255) AS GLOBAL INTEGER DIM db4(255) AS GLOBAL INTEGER DIM db5(255) AS GLOBAL INTEGER DIM db6(255) AS GLOBAL INTEGER DIM db7(255) AS GLOBAL INTEGER DIM db8(255) AS GLOBAL INTEGER ' for sonar ii-devices. DIM db9(255) AS GLOBAL INTEGER DIM dbA(255) AS GLOBAL INTEGER DIM dbB(255) AS GLOBAL INTEGER DIM dbC(255) AS GLOBAL INTEGER DIM dbD(255) AS GLOBAL INTEGER DIM dbE(255) AS GLOBAL INTEGER DIM dbF(255) AS GLOBAL INTEGER ' following are for the radar invisible instrument. qr(0).pXbuf = VARPTR(db0(0)) ' same buffers also used for sonar! qr(0).pYbuf = VARPTR(db1(0)) qr(1).pXbuf = VARPTR(db2(0)) qr(1).pYbuf = VARPTR(db3(0)) qr(2).pXbuf = VARPTR(db4(0)) qr(2).pYbuf = VARPTR(db5(0)) qr(3).pXbuf = VARPTR(db6(0)) qr(3).pYbuf = VARPTR(db7(0)) ' following for doppler sonar under NiDAQmx: ' 13.06.2009, changed to: DIM dbx(0 TO 255) AS GLOBAL DOUBLE ' 0.25 second buffers, fast data - Sampling rate 1024 S/s DIM dby(0 TO 255) AS GLOBAL DOUBLE DIM dbz(0 TO 255) AS GLOBAL DOUBLE ' DIM dbce(0 TO 255) AS GLOBAL DOUBLE ' R24GT DIM dbxm(0 TO 255) AS GLOBAL DOUBLE ' 1 second buffers, medium data - Sampling rate 256 S/s DIM dbym(0 TO 255) AS GLOBAL DOUBLE DIM dbzm(0 TO 255) AS GLOBAL DOUBLE ' DIM dbcm(0 TO 255) AS GLOBAL DOUBLE DIM dbxs(0 TO 255) AS GLOBAL DOUBLE ' 4 second buffers, slow data - Sampling rate 64 S/s DIM dbys(0 TO 255) AS GLOBAL DOUBLE DIM dbzs(0 TO 255) AS GLOBAL DOUBLE ' DIM dbcs(0 TO 255) AS GLOBAL DOUBLE DIM xfbuf(0 TO 63) AS GLOBAL SINGLE ' frequency buffers. 64 measurements deep. DIM yfbuf(0 TO 63) AS GLOBAL SINGLE DIM zfbuf(0 TO 63) AS GLOBAL SINGLE DIM cfbuf(0 TO 63) AS GLOBAL SINGLE ' only used for 24GHz system R24GT ' dim doppler as global dopplerType ' 14.06.2009 - done outside proc. doppler.pxfast = VARPTR(dbx(0)) doppler.pyfast = VARPTR(dby(0)) doppler.pzfast = VARPTR(dbz(0)) doppler.pxm = VARPTR(dbxm(0)) doppler.pym = VARPTR(dbym(0)) doppler.pzm = VARPTR(dbzm(0)) doppler.pxslow = VARPTR(dbxs(0)) doppler.pyslow = VARPTR(dbys(0)) doppler.pzslow = VARPTR(dbzs(0)) doppler.pxfbuf = VARPTR(xfbuf(0)) doppler.pyfbuf = VARPTR(yfbuf(0)) doppler.pzfbuf = VARPTR(zfbuf(0)) '-------------------------------------------------- 24GHz radar--------------------------------------- ' to be done also for R24GT system! (4 channels!!!) ' DIM dbx24Gf(0 TO 511) AS GLOBAL DOUBLE ' 0.25 second buffers, fast data - sampling rate 2048 S/s ' DIM dby24Gf(0 TO 511) AS GLOBAL DOUBLE ' DIM dbz24Gf(0 TO 511) AS GLOBAL DOUBLE ' DIM dbc24Gf(0 TO 511) AS GLOBAL DOUBLE ' DIM dbx24Gm(0 TO 255) AS GLOBAL DOUBLE ' 1 second buffers, medium data - sampling rate 256 S/s ' DIM dby24Gm(0 TO 255) AS GLOBAL DOUBLE ' DIM dbz24Gm(0 TO 255) AS GLOBAL DOUBLE ' DIM dbc24Gm(0 TO 255) AS GLOBAL DOUBLE ' DIM dbx24Gs(0 TO 255) AS GLOBAL DOUBLE ' 4 second buffers, slow data - sampling rate 64 S/s ' DIM dby24Gs(0 TO 255) AS GLOBAL DOUBLE ' DIM dbz24Gs(0 TO 255) AS GLOBAL DOUBLE ' DIM dbc24Gs(0 TO 255) AS GLOBAL DOUBLE ' R24GT.pxfast = VARPTR(dbx24Gf(0)) ' R24GT.pyfast = VARPTR(dby24Gf(0)) ' R24GT.pzfast = VARPTR(dbz24Gf(0)) ' R24GT.pcfast = VARPTR(dbc24Gf(0)) ' R24GT.pxm = VARPTR(dbx24Gm(0)) ' R24GT.pym = VARPTR(dby24Gm(0)) ' R24GT.pzm = VARPTR(dbz24Gm(0)) ' R24GT.pcm = VARPTR(dbc24Gm(0)) ' R24GT.pxslow = VARPTR(dbx24Gs(0)) ' R24GT.pyslow = VARPTR(dby24Gs(0)) ' R24GT.pzslow = VARPTR(dbz24Gs(0)) ' R24GT.pcslow = VARPTR(dbc24Gs(0)) ' R24GT.pxfbuf = VARPTR(xfbuf(0)) ' common with other structures... ' R24GT.pyfbuf = VARPTR(yfbuf(0)) ' R24GT.pxfbuf = VARPTR(zfbuf(0)) ' R24GT.pcfbuf = VARPTR(cfbuf(0)) 'buffer inits for R24GT are only doen @ initialisation of the radar DIM NiMxDevs(0 TO 3) AS GLOBAL ASCIIZ * 20 ' this enumerates all devices we own and could have ' connected NiMxDevs(0) = "Dev1" 'index corresponds with devicenr later on, which starts from 1, 'so having an element(0) make no sense... NiMxDevs(1) = "USB6210-1" NiMxDevs(2) = "USB6212-1" 'renamed via the NiDAQ MAX utility 8.06.2009 NiMxDevs(3) = "USB6210-2" ' MSGBOX "g_n*h.dll" & STR$(H) & " " & STR$(hInst),,FUNCNAME$ - dit werkt. H = hInst ELSE MSGBOX "g_n*h.dll loaded twice! " & STR$(H) & " " & STR$(hInst),,FUNCNAME$ END IF ' timeBeginPeriod CheckTimerResolution ' must be matched with a call to timeEndPeriod. InitializeCriticalSection CritSecWait ' 11.09.2000 CASE %DLL_PROCESS_DETACH #IF %DEF(%NiDAQ) IF pDIOparams THEN IF @pDIOparams.id THEN DAQ_Clear @pDIOparams.id END IF IF pDAQparams THEN IF @pDAQparams.id THEN DAQ_Clear @pDAQparams.id END IF END IF IF qr(0).TimerId THEN TimeKillEvent qr(0).TimerId #ENDIF DeleteCriticalSection CritSecWait ' 11.09.2000 ' timeEndPeriod CheckTimerResolution ' must be paired with timeBeginPeriod ' ChecktimerResolution is a proc in g_indep now (06.2009) #IF(%DEF(%ACTIVEWIRE)) ' close USB Activewire ports before leaving: ' 15.05.2002 i = %False DO IF (IOports.AwUSB(i) AND %PortUsed) THEN AwusbClose END IF INCR i LOOP UNTIL i = 32 #ENDIF CASE %DLL_THREAD_ATTACH 'SetPriorityClass hInst, %REALTIME_PRIORITY_CLASS ' 26.07.2004 - foutief! ' juiste versie: (26.10.2005] i = SetPriorityClass (GetCurrentProcess(), %REALTIME_PRIORITY_CLASS) ' MSGBOX "g_nih.dll thread attach" ' o.k. CASE %DLL_THREAD_DETACH CASE ELSE FUNCTION = %False END SELECT END FUNCTION FUNCTION InitDAQdll (BYREF T() AS TAAK,_ BYREF TEx() AS ExtraInfo,_ BYREF gh AS GMT_HANDLES,_ BYREF App AS ApplicationType,_ BYREF DAQparams AS DataAcquisitionParameters,_ BYREF DIOparams AS DigitalIOParameters) EXPORT AS LONG ' this function is called from GMT_Initialize in GMT.BAS ' DIM pTEX(%NumberOfTasks-1) AS GLOBAL ExtraInfo PTR ' added 20.09.2003 DIM pT(%NumberOfTasks-1) AS GLOBAL TAAK PTR LOCAL i AS DWORD LOCAL m AS ASCIIZ * 100 LOCAL szTitelBox AS ASCIIZ * 45 szTitelBox = "{g_n*h.dll}-[InitDAQdll]" & CHR$(13) FOR i = 0 TO %Numberoftasks -1 pTEX(i)= VARPTR(Tex(i)) ' - we will need this for calling stoptask en starttask procs. ' as well as for parameter windows in dll-tasks pT(i) = VARPTR(T(i)) NEXT i pgh = VARPTR(gh) IF ISFALSE pgh THEN m ="Null pointer for GMT handles on initialisation of g_n*h.dll" MessageBox hInst,m, szTitelbox,%MB_OK OR %MB_ICONSTOP OR %MB_TASKMODAL OR %MB_TOPMOST ELSE @pgh.gnh = hInst END IF pApp = VARPTR(App) IF ISFALSE pApp THEN m = "Null pointer for application on initialisation of g_n*h.dll" MessageBox hInst,m, szTitelbox,%MB_OK OR %MB_ICONSTOP OR %MB_TASKMODAL OR %MB_TOPMOST END IF pDAQparams = VARPTR(DAQparams) IF ISFALSE pDAQparams THEN m = "Null pointer for DAQparams on initialisation of g_n*h.dll" MessageBox hInst,m, szTitelbox,%MB_OK OR %MB_ICONSTOP OR %MB_TASKMODAL OR %MB_TOPMOST END IF pDIOparams = VARPTR(DIOparams) IF ISFALSE pDIOparams THEN m = "Null pointer for DIOparams on initialisation of g_n*h.dll" MessageBox hInst,m, szTitelbox,%MB_OK OR %MB_ICONSTOP OR %MB_TASKMODAL OR %MB_TOPMOST END IF END FUNCTION FUNCTION PrepareDaqMenu () EXPORT AS LONG ' 25.06.2002, used for preparing the menu in GMT ' 01.06.2009, modified. ' 06.06.2009, further debug ' 08.06.2009, should work fine now, both with NiDAQ and NiDAQmx LOCAL md AS ASCIIZ * 40 LOCAL m AS ASCIIZ * 20 LOCAL NiDaqVer AS CUR LOCAL hPop AS LONG LOCAL i AS LONG LOCAL hMenu AS LONG hMenu = GetMenu(@pgh.setup) NiDaqVer = NiDAQ_Version ' warning "nidaq ver" + STR$(Nidaqver) IF NiDaqVer THEN m = "NiDAQ " + STR$(NiDaqVer) ' Warning TRIM$(m) 'ok EnableMenuItem hMenu, %ID_POP_DAQDEVS, %MF_ENABLED EnableMenuitem hMenu, %IDM_NIDAQ, %MF_ENABLED md = "National Instruments" MENU NEW POPUP TO hPop MENU ADD POPUP, hMenu, md, hPop, %MF_ENABLED, AT BYCMD %IDM_NIDAQ ' now let the user select the devices found... MENU DELETE hMenu, BYCMD %IDM_NIDAQ i = 1 DO md = FindNiDAQdevice (i,%False) 'in this dll ' Warning "dev= " & md & STR$(i) 'md = "NI_USB-6212" IF LEFT$(UCASE$(md),2) <> "NO" THEN MENU ADD STRING, hPop, TRIM$(m) & " " & TRIM$(md), %IDM_DAQ_PORTS+ i-1, %MF_ENABLED, AT BYCMD %IDM_NIDAQ MENU DRAW BAR @pgh.setup EXIT LOOP ELSE EXIT DO ' exits on the first connected device found now., END IF INCR i LOOP ' we can retrieve the device id's as %IDM_DAQ_PORTS + id in the callback... ' If we found no NiDAQ devices,we offer the choice to use the testpanel: ' IF ExistFile($NiDAQmxTestPanel) THEN ' MENU ADD STRING, hPop, "NiMAX" , %IDM_DAQ_PORTS_LAST + 1, %MF_ENABLED, AT BYCMD %IDM_NIDAQ ' END IF ' MENU DRAW BAR @pgh.setup ELSE ' no NiDaq version installed MENU DELETE hMenu, BYCMD %ID_POP_DAQDEVS END IF MENU DRAW BAR @pgh.setup FUNCTION = %True END FUNCTION FUNCTION NiDAQ_Version () EXPORT AS CUR 'returns the NiDAQ version installed on this computer 'function modified 02.06.2009 gwr #IF %DEF(%NiDAQ) LOCAL a& Get_Ni_DAQ_Version (a&) ' this initializes and resets the board! FUNCTION = VAL(LEFT$(HEX$(a& AND &HFFFF),1) + "." + RIGHT$(HEX$(a& AND &HFFFF),2)) #ELSEIF %DEF(%g_NiDAQmx) LOCAL vermaj AS DWORD DAQmxGetSysNIDAQMajorVersion (vermaj) LOCAL vermin AS DWORD DAQmxGetSysNIDAQMajorVersion (vermin) FUNCTION = VAL(STR$(vermaj)& "." & TRIM$(STR$(vermin))) ' returns 8.8, checked gwr. #ELSE FUNCTION = %False #ENDIF END FUNCTION FUNCTION FindNiDAQdevice (BYVAL DeviceNumber AS INTEGER, BYVAL param AS DWORD) EXPORT AS STRING ' devicenumber passed from preparemenu function. Count starts at 1 ` ' note: this clashes with NimxDEvs(0), which is "dev1", which can never be chosen ' if devicenumber here has to be at least one.. ' param = %Search - used for preparation menu = %False ' param = %Verify - used for setting params ' param is not used anymore! FUNCTION = "NONE" 'default return. ' warning FUNCNAME$ + STR$(devicenumber) + STR$(param) IF DeviceNumber <= %False THEN EXIT FUNCTION #IF %DEF(%g_NiDAQmx) ' new coding 06.06.2009/08.06.2009 - gwr LOCAL gegevens AS DWORD LOCAL ret AS LONG LOCAL device AS ASCIIZ * 20 LOCAL i AS LONG LOCAL errBuff AS ASCIIZ * 1024 FOR i = 1 TO UBOUND(NiMxDevs) ret = DAQmxGetDevSerialNum (NiMxDevs(i), gegevens) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) ' Warning "sern err: " + STR$(i) & TRIM$(errbuff) ITERATE FOR END IF 'IF gegevens THEN 'PRINT "Serial number= "; STR$(gegevens); " &H"; HEX$(gegevens) ' serial number ' dit geeft 0 wanneer het device niet aan de usb poort hangt. ' Volgende funktie werkt voor alle spullen die ooit aan de komputer hebben gehangen...: ret = DAQmxGetDevProductNum (NiMxDevs(i), gegevens) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) ' Warning STR$(i) & TRIM$(errbuff) END IF device = NiMxDevs(i) ' warning TRIM$(device) & HEX$(gegevens) + STR$(i) + STR$(Devicenumber) 'ok SELECT CASE gegevens ' ' uit te breiden naarmate we meer devices hebben. CASE &H7339 ' PRINT "Device found = NI_USB-6212" & " " & HEX$(gegevens) @pDAQparams.device = NiMxDevs(i) '"Ni_USB-6212" '? we better return NiMxDevs(i) @pDAQparams.id = i 'Devicenumber ' mag niet 0 zijn! - sonar_daq verwacht dat dit i is, en niet Devicenmber.. kan dit elders verdere implicaties hebben? @pDAQparams.nrchannels = 16 @pDAQparams.mode = %DAQ_NI @pDAQparams.bBitsPerSample = 16 FUNCTION = @pDAQparams.device EXIT FUNCTION CASE &H726F ' PRINT "Device found = NI_USB-6210" & " " & HEX$(gegevens) @pDAQparams.device = NiMxDevs(i) '"Ni_USB-6210" @pDAQparams.id = i 'Devicenumber ' mag niet nul zijn. @pDAQparams.nrchannels = 16 @pDAQparams.mode = %DAQ_NI @pDAQparams.bBitsPerSample = 16 FUNCTION = @pDAQparams.device EXIT FUNCTION CASE ELSE ' ' kan eigenlijk niet ' PRINT "Device number= " ; STR$(gegevens);" &H"; HEX$(gegevens) ' device number @pDAQparams.device = NiMxDevs(i) @pDAQparams.id = i 'Devicenumber FUNCTION = "NONE" EXIT FUNCTION END SELECT 'EXIT FOR 'END IF NEXT i #ENDIF #IF %DEF(%NiDAQ) '27.06.1999: This procedure returns the name of the NiDAQ device found on this computer. 'called for setting up the menu in GMT, and again for confirmation after selection. (second call, no longer used) LOCAL devicekode AS INTEGER Init_DA_Brds BYVAL DeviceNumber, devicekode ' resets the board! SELECT CASE devicekode CASE 1: FUNCTION ="NONE" ' Not a National Instruments DAQ device" CASE 7: FUNCTION ="PC-DIO-24" @pDioParams.id = DeviceNumber @pDIOParams.device = "PC-DIO-24" @pDIOParams.nrports = 3 @pDIOParams.mode = %DAQ_NI CASE 33: FUNCTION ="DAQPad-1200" CASE 35: FUNCTION ="DAQCard DIO-24" ' pcmcia card for static digital I/O ' implemented 26.09.2000 -8255 compatible ' Serves as replacement for printer port on NT machines. ' IF param THEN @pDioParams.id = DeviceNumber @pDIOParams.device = "DAQCard DIO-24" @pDIOParams.nrports = 3 @pDIOParams.mode = %DAQ_NI ' END IF CASE 52 ' pcmcia 16 bit device FUNCTION ="DAQCard-AI-16XE-50" @pDAQparams.device = "DAQCard-AI-16XE-50" @pDAQparams.id = Devicenumber @pDAQparams.nrchannels = 16 @pDAQparams.mode = %DAQ_NI @pDAQparams.bBitsPerSample = 16 CASE 53 FUNCTION ="DAQCard-AI-16E-4" ' pcmcia device used on , Karin, Arne , ' IF param THEN @pDAQparams.device = "DAQCard-AI-16E-4" @pDAQparams.id = Devicenumber @pDAQparams.nrchannels = 16 @pDAQparams.mode = %DAQ_NI @pDAQparams.bBitsPerSample = 12 ' END IF CASE 67: FUNCTION ="AT-DIO-32HS" ' ISA bus card - compatible with 6533 @pDIOparams.device = "AT-DIO-32HS" @pDIOparams.id = Devicenumber @pDIOparams.nrports = 4 @pDIOparams.mode = %DAQ_NI CASE 68 FUNCTION = "DAQCard-6533" ' this we have and implemented 26.09.2000 ' IF param THEN @pDIOparams.device = "DAQCard-6533" @pDIOparams.id = Devicenumber @pDIOparams.nrports = 4 @pDIOparams.mode = %DAQ_NI ' END IF 'CASE 69: FUNCTION ="DAQArb AT-5411" 'CASE 75: FUNCTION ="DAQPad-6507/6508" CASE 76 FUNCTION = "DAQPad-6020E FOR USB" ' USB device used on Yes etc... (ii code)- sold to MIM ' IF param THEN @pDAQparams.device = "DAQPad-6020E FOR USB" @pDAQparams.id = Devicenumber @pDAQparams.nrchannels = 16 @pDAQparams.mode = %DAQ_NI @pDAQparams.bBitsPerSample = 1 ' END IF 'CASE 88: FUNCTION = "DAQCard-6062E" 'CASE 89: FUNCTION = "DAQCard-6715" 'CASE 90: FUNCTION = "DAQCard-6023E" 'CASE 91: FUNCTION = "DAQCard-6024E" CASE 211 FUNCTION ="PCI-DIO-32HS" ' ordered 21.09.2000 - for music automats. ' implementation started 26.09.2000 'CASE 275: FUNCTION ="DAQPad-6070E FOR 1394" 'CASE 276: FUNCTION ="DAQPad-6052E" CASE ELSE FUNCTION ="Not Implemented" END SELECT #ELSE FUNCTION = "NONE" #ENDIF END FUNCTION ' 27.12.1999: DAQ-ports: SUB NiDAQDigOut (BYVAL n AS BYTE) EXPORT ' Note: this procedure only works with analog data acquisition devices, not with DIO devices. ' we use the 8-bit port as data port and one of the timers to generate the strobe. ' Data is output on pins D0-D7 ' strobe on either counter0 or counter1 output. ' for coding documentation: see STCgenerateSinglePulse.c in the NiDAQ examples. #IF %DEF(%NiDAQ) STATIC init AS BYTE LOCAL retval AS INTEGER LOCAL dummy AS INTEGER ' DIG_Line_Config ' configures a specific line for either input or output ' DIG_Prt_Config ' configures the port for either input or output STEP 1 ' DIG_Out_Prt ' writes data to the port ' DIG_Out_Line ' sets a single line STEP 2 ' DIG_In_Prt ' reads a byte from the port ' DIG_In_Line ' reads a single bit from a line IF ISFALSE init THEN IF ISFALSE @pDAQparams.id THEN EXIT SUB retval = DIG_Prt_Config% (@pDAQparams.id,0,0,1) 'dev.1, port 0, mode 0 = no handshaking, dir = 1, for output port) 'dummy = NIDAQErrorHandler(retval,"DIG_Prt_Config",1) ' this is O.K. init = %True END IF retval = DIG_Out_Port% (@pDAQparams.id,0,(n)) 'dummy = NIDAQErrorHandler(retval,"NiDAQ Dig_out error",1) NiDAQ_Pulse_Out 0, 1 ' 1 microsecond, 1 ms for test with USB daqpad #ELSE EXIT SUB #ENDIF END SUB SUB NiDAQ_Pulse_Out (BYVAL counter AS DWORD, BYVAL duration AS DWORD) EXPORT ' duration is in microseconds! #IF %DEF(%NiDAQ) ' the procedure quits as soon as the pulse is started. ' It's up to your application not to call the proc. again before the pulse is done, or, ' to timeout for the pulse in your own code. LOCAL cnt AS DWORD LOCAL retval AS INTEGER LOCAL dummy AS INTEGER LOCAL countval AS DWORD ' E-series devices used the GPCTR functions IF counter = 0 THEN cnt = %ND_COUNTER_0 ELSEIF counter = 1 THEN cnt = %ND_COUNTER_1 ELSE EXIT SUB ' invalid counter number END IF SELECT CASE UCASE$(LEFT$(@pDAQparams.device,4)) CASE "NONE" EXIT SUB CASE "DAQP", "DAQC" ' both the DAQpad and the DAQcard are E-series devices. retval = GPCTR_Control (@pDAQparams.id,cnt, %ND_RESET) 'dummy = NIDAQErrorHandler(retval,"GPCTR_Control/RESET",1) retval = GPCTR_Set_Application (@pDAQparams.id, cnt, %ND_Single_Pulse_GNR) ' used as strobe pulse generator 'dummy = NIDAQErrorHandler(retval,"gptcr_set_application",1) countval = duration * 20 ' for 20MHz clock IF countval < 2 THEN countval = 2 IF UCASE$(LEFT$(@pDAQparams.device,4))= "DAQP" THEN ' daqpad (USB) needs 1 ms minimum!!! retval = GPCTR_Change_Parameter (@pDAQparams.id, cnt, %ND_SOURCE, %ND_INTERNAL_100_KHZ) ' set clock 'dummy = NIDAQErrorHandler(retval,"change param/ clocksource",1) ELSE retval = GPCTR_Change_Parameter (@pDAQparams.id, cnt, %ND_SOURCE, %ND_INTERNAL_20_MHZ) ' set clock 'dummy = NIDAQErrorHandler(retval,"change param/ clocksource",1) END IF retval = GPCTR_Change_Parameter (@pDAQparams.id, cnt, %ND_OUTPUT_POLARITY, %ND_NEGATIVE) ' dummy = NIDAQErrorHandler(retval,"NiDAQ CPCTR: cannot change parameter strobe negative ",1) retval = GPCTR_Change_Parameter (@pDAQparams.id, cnt, %ND_COUNT_1, 3) ' 150ns delay time ' dummy = NIDAQErrorHandler(retval,"NiDAQ CPCTR: cannot change parameter 150ns delay",1) retval = GPCTR_Change_Parameter (@pDAQparams.id, cnt, %ND_COUNT_2, countval) ' 1000ns pulsduur ' dummy = NIDAQErrorHandler(retval,"NiDAQ CPCTR: cannot change parameter pulse duration",1) retval = Select_Signal (@pDAQparams.id,%ND_GPCTR0_OUTPUT,%ND_GPCTR0_OUTPUT,%ND_LOW_TO_HIGH) '%ND_HIGH_TO_LOW is not accepted! ' dummy = NIDAQErrorHandler(retval,"Select_Signal error",1) retval = GPCTR_Control (@pDAQparams.id,cnt, %ND_PROGRAM) 'PREPARE) ' dummy = NIDAQErrorHandler(retval,"Strobing error", 1) 'retval = Select_Signal (@pDAQparams.id, %ND_GPCTR0_OUTPUT,%ND_NONE,%ND_DONT_CARE) ' make output hi-z ' retval = GPCTR_Control (@pDAQparams.id,counter,BYVAL %ND_ARM) ' should arm the counter and do the action... 'dummy = NIDAQErrorHandler(retval,"NiDAQ Strobing error",1) CASE ELSE countval = duration \ 10 ' for 100kHz clock IF countval < 1 THEN countval = 1 retval = ICTR_Setup (@pDAQparams.id, counter, 4, countval, 1) ' negative going strobe pulse on TC, soft strobe, binary count ' dummy = NIDAQErrorHandler(retval,"ICTR_Setup error",1) ' retval = ICTR_Reset(@pDAQparams.id, counter, 0) ' switch the bit... ' dummy = NIDAQErrorHandler(retval,"ICTR_Reset to 0",1) ' retval = ICTR_Reset(@pDAQparams.id, counter, 1) ' dummy = NIDAQErrorHandler(retval,"ICTR_Reset to 1",1) END SELECT #ENDIF END SUB FUNCTION Ni_CentroPort (BYVAL devnr AS INTEGER) EXPORT AS LONG ' initialize NiDaq board as printerport for use with our pp-hardware. ' works with DAQCard DIO24 & our NiDAQ-2-LPT adaptor board ' as well as with 6533 devices and corresponding adapter board. #IF %DEF(%NiDAQ) LOCAL stat AS LONG stat = DIG_Prt_Config (devnr,0,0,1) ' make port 0 (A-port) output only - no handshaking. stat = DIG_PRT_Config (devnr,1,0,0) ' make port 1 (B-port) input only - bits 3,4,5,6,7 stat = DIG_PRT_Config (devnr,2,0,1) ' make port 2 (C-port) output only - bits 0,1,2,3 stat = DIG_Out_Line (devnr,2,0,1) ' strobe must be high at rest. FUNCTION = %NoError #ELSE FUNCTION = %False #ENDIF END FUNCTION FUNCTION Aw_Usb_CentroPort (BYVAL devnr AS DWORD) EXPORT AS DWORD ' no need to export this function #IF %DEF(%ACTIVEWIRE) LOCAL retval AS DWORD DIM b(1) AS STATIC BYTE b(0) = &H0FF '&B11111111 ' set lsb bits to output ' b(1) = &B00001111 ' set msb bits low nibble to output, high nibble to input b(1) = &H0FF '&B11111111 retval = AwusbEnablePort(b(0),2) IF ISFALSE retval THEN FUNCTION = %True ELSE MSGBOX AwUsbErrorMessage (retval),,"" 'er = GetLastError 'msgbox STR$(er) FUNCTION = %False END IF ' init levels b(0)= %False b(1)=&B00000001 retval = AwusbOutPort (b(0),2) ' was 1 - changed 03.06.2002 IF retval THEN IOports.msblsb(devnr) = &H100 MSGBOX AwUsbErrorMessage (retval),,"" ELSE FUNCTION = %True END IF #ELSE FUNCTION = %False #ENDIF END FUNCTION SUB LedDisplay (BYVAL number?, BYVAL dot1?, BYVAL dot2?, BYVAL dot3?) EXPORT 'IF ISFALSE HIBYT(HIWRD(Displaypanel.padr)) THEN EXIT SUB LOCAL lownibble? LOCAL highnibble? LOCAL strobebyte AS BYTE LOCAL t& LOCAL adres AS WORD LOCAL f AS LONG LOCAL teller AS WORD LOCAL b AS STRING * 4 SELECT CASE Displaypanel.dev ' must equal a device type constant CASE %Bom1_Display ' = &H0000 SELECT CASE Displaypanel.padr CASE %False ' NiDAQ DIO device in LPT mode. #IF %DEF(%NiDAQ) IF @pDIOparams.id THEN lownibble? = number? MOD 10 highnibble? = number? \ 10 IF ISFALSE highnibble? THEN highnibble? = 15 ' blank it IF (highnibble? = 15) AND (lownibble? = 0) THEN lownibble? = 15 SHIFT LEFT highnibble?, 4 highnibble? = highnibble? OR lownibble? PortOut 0,highnibble? BIT SET strobebyte,0 IF dot1? THEN BIT RESET strobebyte, 1 ELSE BIT SET strobebyte, 1 ' inverted IF dot2? THEN BIT RESET strobebyte, 2 ELSE BIT SET strobebyte, 2 ' inverted IF dot3? THEN BIT SET strobebyte, 3 ELSE BIT RESET strobebyte, 3 PortOut 2,strobebyte g_Strobe 2,strobebyte,0 ELSE EXIT SUB ' no device selected... END IF #ENDIF CASE &H100 ' NiDAQ port on DAQ card - code added 16.11.2000 ' no support for the dots! (that would need 3 extra bits) #IF %DEF(%NiDAQ) lownibble? = number? MOD 10 highnibble? = number? \ 10 IF ISFALSE highnibble? THEN highnibble? = 15 ' blank it IF (highnibble? = 15) AND (lownibble? = 0) THEN lownibble? = 15 SHIFT LEFT highnibble?, 4 highnibble? = highnibble? OR lownibble? NiDAQDigOut highnibble? #ENDIF EXIT SUB CASE &H278, &H320, &H378, %Padr ' code for 1994 horizontal BOM display dot1? = dot1? AND 1 dot2? = dot2? AND 1 dot3? = dot3? AND 1 ' dot1? en dot2? = decimal dots ' dot3? is bit3 van Padr%+2 en kan worden gebruikt om de knipperled op de print in te schakelen. ' willen we 'rare' tekens vermijden op het ' MSB display, dan moeten we begrenzen alsvolgt: ' number? = number? MOD 100 ' c = &HA ' ] = &HB (omgekeerde kleine c) ' u = &HC ' _C= &HD (onherkenbaar teken) ' t = &HE ' blank = &HF lownibble? = number? MOD 10 highnibble? = number? \ 10 IF ISFALSE highnibble? THEN highnibble? = 15 ' blank it IF (highnibble? = 15) AND (lownibble? = 0) THEN lownibble? = 15 SHIFT LEFT highnibble?, 4 highnibble? = highnibble? OR lownibble? PortOut Displaypanel.padr, highnibble? PortOut Displaypanel.padr, highnibble? strobebyte = %CtrlHiNib '80 ' 0101 0000 = %CtrlHiNib ' all led's OFF IF dot1? THEN BIT SET strobebyte, 1 ELSE BIT RESET strobebyte, 1 IF dot2? THEN BIT RESET strobebyte, 2 ELSE BIT SET strobebyte, 2 'bit2 is geinverteerd op de printerkaart IF dot3? THEN BIT SET strobebyte, 3 ELSE BIT RESET strobebyte, 3 Strobe Displaypanel.preg ,strobebyte ,0,%StrobeLength CASE &H0FF0 TO &H7FF1 ' usb devices 0-7 'local dev 'dev = lowrd(displaypanel.padr) 'shift right dev, 12 lownibble? = number? MOD 10 highnibble? = number? \ 10 IF ISFALSE highnibble? THEN highnibble? = 15 ' blank it IF (highnibble? = 15) AND (lownibble? = 0) THEN lownibble? = 15 SHIFT LEFT highnibble?, 4 highnibble? = highnibble? OR lownibble? PortOut displaypanel.padr,highnibble? BIT SET strobebyte,0 IF dot1? THEN BIT SET strobebyte, 1 ELSE BIT RESET strobebyte, 1 IF dot2? THEN BIT SET strobebyte, 2 ELSE BIT RESET strobebyte, 2 IF dot3? THEN BIT SET strobebyte, 3 ELSE BIT RESET strobebyte, 3 ' PortOut displaypanel.preg,strobebyte g_Strobe displaypanel.preg,strobebyte,0 CASE &H08A00 TO &H08A40 ' Activewire USB port - tested 03.06.2002 o.k. lownibble? = number? MOD 10 highnibble? = number? \ 10 IF ISFALSE highnibble? THEN highnibble? = 15 ' blank it IF (highnibble? = 15) AND (lownibble? = 0) THEN lownibble? = 15 SHIFT LEFT highnibble?, 4 highnibble? = highnibble? OR lownibble? BIT SET strobebyte,0 IF dot1? THEN BIT SET strobebyte, 1 ELSE BIT RESET strobebyte, 1 IF dot2? THEN BIT SET strobebyte, 2 ELSE BIT RESET strobebyte, 2 IF dot3? THEN BIT SET strobebyte, 3 ELSE BIT RESET strobebyte, 3 b = CHR$(highnibble?) & CHR$(strobebyte AND &H0FE) & CHR$(highnibble?) & CHR$(strobebyte) f = BufOut(Displaypanel.padr, VARPTR(b),4) ' takes ca. 3 ms., strobes are 17microseconds (measured on YES) CASE ELSE EXIT SUB END SELECT CASE %Bom2_Display ' = &H1000 SELECT CASE number? CASE 0 TO 9 ' no change CASE 10 TO 99 lownibble? = number? MOD 10 highnibble? = number? \ 10 number? = highnibble? SHIFT LEFT number?,4 number? = number? OR lownibble? CASE 100 TO 149 '255 ' display as number preceded with special sign lownibble? = number? MOD 10 highnibble? = number? \ 10 number? = highnibble? SHIFT LEFT number?, 4 number? = number? OR lownibble? CASE 150 TO 199 highnibble? = number? MOD 10 lownibble? = number? \ 10 number? = lownibble? SHIFT LEFT number? ,4 number? = number? OR highnibble? CASE 200 TO 255 lownibble? = number? MOD 16 highnibble? = number? \ 16 SHIFT LEFT number?, 4 number? = number? OR lownibble? CASE ELSE END SELECT SELECT CASE Displaypanel.padr CASE %False ' NiDAQ - code for DIO device in LPT mode #IF %DEF(%NiDAQ) IF @pDIOparams.id THEN PortOut 0,number? BIT SET strobebyte,0 IF dot1? THEN BIT SET strobebyte, 1 ELSE BIT RESET strobebyte, 1 IF dot2? THEN BIT SET strobebyte, 2 ELSE BIT RESET strobebyte, 2 IF dot3? THEN BIT SET strobebyte, 3 ELSE BIT RESET strobebyte, 3 PortOut 2,strobebyte g_Strobe 2,strobebyte,0 END IF #ENDIF CASE &H100 ' NiDAQ - code for port in DAQ device - added 16.11.2000 #IF %DEF(%NiDAQ) NiDAQDigOut number? #ENDIF EXIT SUB ' CASE &H101 ' ' Arcom ' EXIT SUB ' CASE &H102 ' ' Contec ' EXIT SUB CASE &H278,&H378,&H320 PortOut LOWRD(Displaypanel.padr), number? dot1? = dot1? AND 1 ' decimal dot dot2? = dot2? AND 1 ' decimal dot dot3? = dot3? AND 1 ' blinking green LED strobebyte = %CtrlHiNib OR 6 '80 + 6 ' 0101 0110 ' all led's OFF IF dot1? THEN BIT RESET strobebyte, 1 ELSE BIT SET strobebyte, 1 IF dot2? THEN BIT SET strobebyte, 2 ELSE BIT RESET strobebyte, 2 'bit2 is geinverteerd op de printerkaart IF dot3? THEN BIT SET strobebyte, 3 ELSE BIT RESET strobebyte, 3 ' IF dot3? THEN BIT RESET strobebyte, 3 ELSE BIT SET strobebyte, 3 Strobe Displaypanel.preg, strobebyte, 0, %StrobeLength CASE &H0FF0 TO &H7FF0 ' usb device - Elektuur PortOut Displaypanel.padr,number? BIT SET strobebyte,0 IF dot1? THEN BIT SET strobebyte, 1 ELSE BIT RESET strobebyte, 1 IF dot2? THEN BIT SET strobebyte, 2 ELSE BIT RESET strobebyte, 2 IF dot3? THEN BIT SET strobebyte, 3 ELSE BIT RESET strobebyte, 3 g_Strobe Displaypanel.preg,strobebyte,0 CASE &H08A00 TO &H08A40 ' Activewire USB port - tested 03.06.2002 o.k. BIT SET strobebyte,0 IF dot1? THEN BIT SET strobebyte, 1 ELSE BIT RESET strobebyte, 1 IF dot2? THEN BIT SET strobebyte, 2 ELSE BIT RESET strobebyte, 2 IF dot3? THEN BIT SET strobebyte, 3 ELSE BIT RESET strobebyte, 3 b = CHR$(number?) & CHR$(strobebyte AND &H0FE) & CHR$(number?) & CHR$(strobebyte) f = BufOut(Displaypanel.padr, VARPTR(b),4) ' takes ca. 3 ms., strobes are 17microseconds (measured on YES) END SELECT END SELECT END SUB FUNCTION Sonar_DAQ (BYVAL param AS LONG) EXPORT AS LONG ' rewrite of data acquisition code for invisible instrument devices using sonar boards. ' coding for Nidaqmx 06.06.2009 added ' test session 04.07.2009 gwr LOCAL i AS INTEGER LOCAL retval AS INTEGER LOCAL dummy AS INTEGER LOCAL timebase AS INTEGER LOCAL sampleinterval AS INTEGER LOCAL scaninterval AS INTEGER LOCAL scantimebase AS INTEGER LOCAL sampletimebase AS INTEGER LOCAL physicalchannels$ LOCAL nametoassigntochannels$ warning FUNCNAME$ board = %ii_2000 FOR i = 0 TO 15 sr.stat(i) = NUL$(128) ' clear the statistics buffers. NEXT i #IF %DEF(%g_NIDAQmx) '06.06.2009 '04.07.2009 - now we try this at 128S/s, twice as fast as previous version. LOCAL ret AS LONG 'static taskname AS ASCIIZ * 20 'static taskhandle AS DWORD LOCAL errBuff AS ASCIIZ * 2048 LOCAL cpcb AS DWORD LOCAL device AS ASCIIZ * 10 '' DIM physicalChannel(0 TO 15) AS STATIC ASCIIZ * 40 '' DIM nameToAssignToChannel (0 TO 15) AS ASCIIZ * 40 'static physicalChannel$ ' 13.10.2009 'static nametoassigntochannels$ DIM nametoassigntolines (0 TO 15) AS STATIC ASCIIZ * 40 '?? LOCAL customscalename AS ASCIIZ * 40 SELECT CASE param CASE -1 FUNCTION = @pDAQparams.mode CASE 0 GOSUB StopsonarDaq @pDAQparams.mode = %DAQ_NI CASE %DAQ_DOUBLEBUFFER warning "start double buffer""\ GOSUB StopSonarDAQ ' doet niks on the first call @pDAQparams.channel = %DAQ_S07_M8F @pDAQparams.mode = %DAQ_NI OR %DAQ_DOUBLEBUFFER @pDAQparams.inputconfig = 1 ' single ended ground referenced. @pDAQparams.rate = %False FOR i = 0 TO 7 @pDAQparams.voltagerange(i) = 5 @pDAQparams.samplingrate(i) = 128 '64 @pDAQparams.channelvector(i) = i @pDAQparams.polarity(i) = 1 ' unipolar @pDAQparams.rate = @pDAQparams.rate + @pDAQparams.samplingrate(i) NEXT i @pDAQparams.taskname = "Sonar ii-2000" ' can be anything you like ret = DAQmxCreateTask(@pDAQparams.taskname, @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) warning "Create Sonar DAQ task error " & TRIM$(errbuff) Logfile "Create Sonar DAQ task error " & TRIM$(errbuff) END IF ' msgbox str$(@pDaqParams.id),,funcname$ device = NiMxDevs(@pDAQparams.id) '' physicalChannel(0) = TRIM$(device) & "/ai0" 'these strings must be as they appear in NiMax '' physicalChannel(1) = TRIM$(device) &"/ai1" '' physicalChannel(2) = TRIM$(device) &"/ai2" '' physicalChannel(3) = TRIM$(device) &"/ai3" '' physicalChannel(4) = TRIM$(device) &"/ai4" '' physicalChannel(5) = TRIM$(device) &"/ai5" '' physicalChannel(6) = TRIM$(device) &"/ai6" '' physicalChannel(7) = TRIM$(device) &"/ai7" '' ' following could be the actual use of the channels (xa, ya, za, Sa, xv, yv, zc, Mv in the case of the sonar board) '' nameToAssignToChannel(0) ="Ai0" '' nameToAssignToChannel(1) ="Ai1" '' nameToAssignToChannel(2) ="Ai2" '' nameToAssignToChannel(3) ="Ai3" '' nameToAssignToChannel(4) ="Ai4" '' nameToAssignToChannel(5) ="Ai5" '' nameToAssignToChannel(6) ="Ai6" '' nameToAssignToChannel(7) ="Ai7" '' 'note: the following works, but you can also create all channels at once with one '' 'DAQmxCreateAIVoltageChan call.. '' FOR i = 0 TO 7 '' 'logfile TRIM$(physicalChannel(i)) ' we get here. result ok. '' ret = DAQmxCreateAIVoltageChan(BYVAL @pDAQparams.taskhandle, physicalChannel(i),nameToAssignToChannel(i),%DAQmx_Val_RSE,0.0,5.0,%DAQmx_Val_Volts ,customscalename) '' '@pDAQparams.taskhandle moet byval '' 'using a variable for terminalconfig (byval as wel as byref) crashes. '' 'the constants don't cause a crash, but give a nidaq error (request value is not supported '' 'for the property DaqMX_Ai_termCfg). '' ' note gwr: we want to get data in 12 bit format (for compatibility with existing hardware) '' ' Sonar voltage range is 0 to 5V unipolar '' IF ret THEN '' DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) '' 'MSGBOX "2.error:" + TRIM$(errBuff) '' 'Logfile TRIM$(errBuff) 'ok '' 'EXIT FUNCTION '' END IF '' NEXT i physicalchannels$ = TRIM$(device) + "/ai0:7" nametoassigntochannels$ = "Ai0, Ai1, Ai2, Ai3, Ai4, Ai5, Ai6, Ai7" DAQmxCreateAIVoltageChan(BYVAL @pDAQparams.taskhandle, TRIM$(physicalChannels$),TRIM$(nameToAssignToChannels$),%DAQmx_Val_RSE,0.0,5.0,%DAQmx_Val_Volts ,customscalename) ret = DaqmxCfgSampClkTiming(BYVAL @pDAQparams.taskhandle,"OnboardClock",128,%DAQmx_val_Rising,%DAQmx_Val_ContSamps,1) 'for our first test we went for strict compatibility and requested 64 S/s on each channel '04.07.2009: now trying to run at 128 S/s ' we sample 8 channels. 'note: last param means nothing when using %DAQmx_Val_ContSamps IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) 'MSGBOX "Clock error:" + TRIM$(errBuff) 'PRINT TRIM$(errbuff) logfile "Clock error:" & TRIM$(errBuff) ELSE 'logfile "DaqmxCfgSampClkTiming passed with 128S/s" END IF 'sleep 5000 cpcb = CODEPTR(ii2000_EveryNCallback) ret = DAQmxRegisterEveryNSamplesEvent(BYVAL @pDAQparams.taskhandle,%DAQmx_Val_Acquired_Into_Buffer,1,0,BYVAL cpcb, BYVAL %NULL) '8 = nrEvents - from all channels together?? then we better take a mult of 16 ' check with x-tof's findings ' 04.07.2009: now set to 1, for 1 sample from each channel IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "error:" + TRIM$(errBuff) ELSE 'logfile "DAQmxRegisterEveryNSamplesEvent passed with N = 1" END IF cpcb = CODEPTR(NiDAQmx_DoneCallback) ret = DAQmxRegisterDoneEvent(@pDAQparams.taskhandle,0,cpcb,BYVAL %NULL) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "error:" + TRIM$(errBuff) ELSE ' logfile "DAQmxRegisterDoneEvent passed with cptr =" & STR$(cpcb) END IF ret = DAQmxStartTask(BYVAL @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile TRIM$(errBuff) ' EXIT FUNCTION END IF 'Logfile "acquisition started.." @pDAQparams.daqstopped = %False warning "ök.." FUNCTION = %DAQ_DOUBLEBUFFER CASE ELSE MSGBOX "Illegal mode",, FUNCNAME$ END SELECT EXIT FUNCTION ' essential!!! #ENDIF #IF %DEF(%NiDAQ) '14.04.2003 - for PCMCIA card 'board = %ii_2000 ' 64S/s SELECT CASE param CASE -1 ' returns operational mode FUNCTION = @pDAQparams.mode CASE 0 ' stops data acquisition GOSUB StopSonarDAQ @pDAQparams.mode = %DAQ_NI CASE %DAQ_DOUBLEBUFFER GOSUB StopSonarDAQ @pDAQparams.channel = %DAQ_S07_M8F @pDAQparams.mode = %DAQ_NI OR %DAQ_DOUBLEBUFFER @pDAQparams.inputconfig = 1 ' single ended ground referenced. ' first set the AI characteristics FOR i = 0 TO 7 @pDAQparams.samplingrate(i) = 64 @pDAQparams.ChannelVector(i) = i @pDAQparams.polarity(i) = 1 '0= bipolar , 1= unipolar @pDAQparams.voltagerange(i) = 5 '10 '5 '1 '10 ' set to 0 to 5V @pDAQparams.GainVector(i) = 2 '2 '10 retval = AI_Configure%(@pDAQparams.id,i,@pDAQparams.inputconfig,1,@pDAQparams.polarity(i),0) ' dummy = NIDAQErrorHandler(retval,"AI_Config error {G_Nih.dll} [Sonar]",0) ' in NiDAQEX_PB.BAS NEXT i @pDaqparams.rate = @pDAQparams.samplingrate(0) * 8 ' 8 channels only = 512 S/s scantimebase = 2 ' use 100kHz / 10 microsecond clock scaninterval = 100000& / @pDAQparams.samplingrate(0) ' 100 * 10 = 1ms sampletimebase = -3 ' use 20MHz / 50ns clock sampleinterval = INT(20000000& / 100000&) '50000&) ' = 400 voor samplingrate = 50000 S/s @pDaqparams.scanfreq = @pDAQparams.samplingrate(0) ' = 100000& / scaninterval retval = DAQ_DB_Config(@pDAQparams.id,%True) ' for debug only: 'retval = DAQ_Rate(@pDAQparams.rate,0,sampletimebase,sampleinterval) ' msgbox "Scanrate = " & STR$(@pDAQparams.rate) ' 512 for 64 S/s ' now we can recalculate the circular buffer size, for the data refreshrate we want: @pDAQparams.Buffersize = @pDAQparams.rate ' in aantal samples voor 1 sekonde buffer REDIM ADCbuffer(@pDAQparams.Buffersize -1) AS GLOBAL INTEGER @pDAQparams.pADCbuffer = VARPTR(ADCbuffer(0)) ' Prepare for acquisition of multiple channels: retval = SCAN_SetUp(@pDAQparams.id,8,BYREF @pDAQparams.ChannelVector(0),BYREF @pDAQparams.Gainvector(0)) 'dummy = NIDAQErrorHandler(retval,"Scan_Setup error in {g_nih}[Sonar]",0) retval = SCAN_Start(@pDAQparams.id,@pDAQparams.pADCbuffer,@pDAQparams.buffersize,sampletimebase,sampleinterval,scantimebase,scaninterval) 'dummy = NIDAQErrorHandler(retval,"Scan_Start error in {g_nih.dll}[Sonar]",0) ' now start periodic event to retrieve the data: every 15 ms for Sr= 64 S/s (66.66 times a second) ' for 64 S/s: sr.TimerId = TimeSetEvent (15,0,CODEPTR(SonarDAQTask_CB),8,%TIME_PERIODIC OR %TIME_CALLBACK_FUNCTION) IF ISFALSE sr.TimerId THEN MSGBOX "Failure starting Sonar data acquisition timer",, FUNCNAME$ END IF @pDAQparams.daqstopped = %False FUNCTION = %DAQ_DOUBLEBUFFER CASE ELSE MSGBOX "Illegal mode",, FUNCNAME$ END SELECT EXIT FUNCTION #ENDIF StopSonarDAQ: #IF %DEF(%NIDAQ) IF sr.timerId THEN TimeKillevent sr.timerid retval = DAQ_Clear (@pDAQparams.id) @pDAQparams.daqstopped = %True #ENDIF #IF %DEF(%g_NIDAQmx) IF @pDAQparams.taskhandle THEN ret = DAQmxStopTask(BYVAL @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) Logfile TRIM$(errbuff) END IF ret = DAQmxClearTask(BYVAL @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) Logfile TRIM$(errbuff) END IF END IF 'Warning "aquisition stopped" @pDAQparams.daqstopped = %True @pDAQparams.taskhandle = %False @pDAQparams.taskname = NUL$(20) #ENDIF RETURN END FUNCTION SUB SonarDAQTask_CB (BYVAL wTimerID AS LONG, BYVAL msg AS LONG, BYVAL eventnr AS LONG, BYVAL dw1 AS LONG, BYVAL dw2 AS LONG) ' This is the callback we use with NiDAQ 7.4 in the g_nih.dll only ' modified (data processing split of, 07.06.2009 gwr LOCAL i AS DWORD LOCAL dummy AS INTEGER STATIC tog AS DWORD LOCAL dev AS DWORD LOCAL Q AS SINGLE LOCAL lx AS SINGLE LOCAL ly AS SINGLE LOCAL dTf AS DWORD ' dynamic, data dependent integration time - 30.10.2003 STATIC xfo AS LONG ' for accelleration calculation STATIC yfo AS LONG STATIC zfo AS LONG STATIC xyzfo AS LONG #IF %DEF(%NiDAQ) STATIC tlast AS DWORD LOCAL newestpointindex AS LONG STATIC DAQstopped AS INTEGER DIM AD(eventnr-1) AS LOCAL INTEGER ' the number of data to be returned is passed in eventnr. ' first we acquire the data: dummy = DAQ_Monitor (@pDAQparams.id,-1,0,eventnr, VARPTR(AD(0)),newestpointindex,DAQstopped) IF tlast THEN IF newestpointindex = tlast THEN EXIT SUB END IF END IF tlast = newestpointindex ARRAY DELETE db0(), AD(0) ' db(0) is deleted, the array shifted left and AD(0) added at the end ARRAY DELETE db1(), AD(1) ARRAY DELETE db2(), AD(2) ARRAY DELETE db3(), AD(3) ARRAY DELETE db4(), AD(4) ARRAY DELETE db5(), AD(5) ARRAY DELETE db6(), AD(6) ARRAY DELETE db7(), AD(7) Sonar_ii_Math ' common for NiDAQ and NiDAQmx #ENDIF END SUB SUB Sonar_ii_Math () ' this proc. is called from the callback for sonar in %NiDaq as well as for Nidaqmx ' modifications to make this possible: gwr 06.06.2009 ' NOTE: the application code has to set a value for sr.dta if integration is required. ' This value can be changed on the fly using the Sonar_Control parameter window created in g_main.inc. ' 29.10.2003: Now we have dynamic data dependent integration on the velocity channels. ' 07.06.2009: Now works with NiDAQmx. Trying to raise the sampling rate to 256S/s still to be tested. ' 04.07.2009: sampling at 128 S/s LOCAL i AS DWORD LOCAL dummy AS INTEGER STATIC tog AS DWORD LOCAL dev AS DWORD LOCAL Q AS SINGLE LOCAL lx AS SINGLE LOCAL ly AS SINGLE LOCAL dTf AS DWORD ' dynamic, data dependent integration time - 30.10.2003 STATIC xfo AS LONG ' for accelleration calculation STATIC yfo AS LONG STATIC zfo AS LONG STATIC xyzfo AS LONG ' the following is common for all Sonar ii_2000 daq hardware: ' the AD(0) to AD(7) references could be replaced with db0(UBOUND(db0))= db0(255) ' Note that db0(255) is always the most recently acquired data sr.xa = ((sr.xa * sr.dta) + db0(255)) / (sr.dta+1) ' amplitude integration added 29.10.2003 sr.ya = ((sr.ya * sr.dta) + db1(255)) / (sr.dta+1) sr.za = ((sr.za * sr.dta) + db2(255)) / (sr.dta+1) sr.xyza = ((sr.xyza * sr.dta) + db3(255)) / (sr.dta+1) ' dynamic adaptive coding: added 30.10.2003] ' this integrates over none up to 24 samples and automates the former sr.dtf xfo = sr.xf ' required for acceleration derivation. yfo = sr.yf zfo = sr.zf xyzfo = sr.xyzf IF sr.xf THEN dtf = INT(2 *(12 - LOG2(sr.xf))) ELSE dtf = 24 END IF sr.xf = ((sr.xf * dtf) + db4(255))/ (dtf+1) IF sr.yf THEN dtf = INT(2 * (12 - LOG2(sr.yf))) ELSE dtf = 24 END IF sr.yf = ((sr.yf * dtf) + db5(255))/ (dtf+1) IF sr.zf THEN dtf = INT(2 * (12 - LOG2(sr.zf))) ELSE dtf = 24 END IF sr.zf = ((sr.zf * dtf) + db6(255))/ (dtf+1) IF sr.xyzf THEN dtf = INT(2 * (12 - LOG2(sr.xyzf))) ELSE dtf = 24 END IF sr.xyzf = ((sr.xyzf * dtf) + db7(255))/ (dtf+1) ' calculated data channels: ' new scaling 04.11.2003: sr.xe = SQR(sr.xa * sr.xf) ' better then (sr.xa * sr.xf) \ %d12 ' so range is again 12 bits sr.ye = SQR(sr.ya * sr.yf) '\ %d12 sr.ze = SQR(sr.za * sr.zf) ' \ %d12 sr.xyze = SQR(sr.xyza * sr.xyzf) '\ %d12 ARRAY DELETE db8(), sr.xe ' compatible with BOM and Songbook ARRAY DELETE db9(), sr.ye ARRAY DELETE dbA(), sr.ze ARRAY DELETE dbB(), sr.xyze ' new accelleration code 30.10.2003 - now we do not need sr.dT anymore. ' however we may need rescaling now, using sr.ascale [ added 01.11.2003] sr.xac = (sr.xf - xfo) * sr.ascale sr.yac = (sr.yf - yfo) * sr.ascale sr.zac = (sr.zf - zfo) * sr.ascale sr.xyzac = (sr.xyzf - xyzfo) * sr.ascale ' we perform the ceiling here: ( range is always -2048 to 2047, or 12 bits bipolar) 'sr.xac = max(sr.xac, -2048) 'sr.xac = min(sr.xac, 2047) ' or in a single statement: sr.xac = MIN(MAX(sr.xac, -2048),2047) sr.yac = MIN(MAX(sr.yac, -2048),2047) sr.zac = MIN(MAX(sr.zac, -2048),2047) sr.xyzac = MIN(MAX(sr.xyzac, -2048),2047) ARRAY DELETE dbC(), sr.xac ' for compatibility with BOM and Songbook ARRAY DELETE dbD(), sr.yac ARRAY DELETE dbE(), sr.zac ARRAY DELETE dbF(), sr.xyzac amplitude: ' leaky integrator for surface amplitudes: ' AD(0) - AD(1) - AD(2) = sr.xa, sr.ya, sr.za amplitudes used for position information ' this is the value we will use for position determination ' new 02.11.2003 ' ceiling added 03.11.2003 sr.amp = MIN(((sr.dta * sr.amp) + (SQR( (sr.xa^2) + (sr.ya^2) + (sr.za^2) ))) / (sr.dta+1), %d12) lineposition: ' linevector x->y and y->x IF (sr.xa > sr.noise) AND (sr.ya > sr.noise) THEN Q = SQR(sr.xa / sr.ya) ' for math: cfr. quadrada.html sr.lxy = (2! - Q) / (Q+1) sr.lyx = ((2*Q) -1) / (Q+1) ' ELSE ' sr.lxy = -1 : sr.lyx = -1 ' better use previous value... END IF ' linevector x->z and z->x IF (sr.xa > sr.noise) AND (sr.za > sr.noise) THEN Q = SQR(sr.xa / sr.za) sr.lxz = (2! - Q) / (Q+1) sr.lzx = ((2*Q)-1) / (Q+1) ' ELSE ' sr.lxz = -1 : sr.lzx = -1 END IF ' linevector y->z and z->y: IF (sr.ya > sr.noise) AND (sr.za > sr.noise) THEN Q = SQR(sr.ya/sr.za) sr.lyz = (2! - Q) / (Q+1) sr.lzy = ((2*Q)-1) / (Q+1) ' ELSE ' sr.lyz = -1 : sr.lzy = -1 END IF ' berekening van de grootte van het oppervlak van het reflekterend lichaam gezien door elke transducer: LOCAL s1 AS LONG LOCAL s2 AS LONG ' vanuit x -transducer IF (sr.lxy >= %False) AND (sr.lxy <= 1) THEN s1 = sr.xa * (sr.lyx^2) ELSE s1 = %False END IF IF (sr.lxz >= %False) AND (sr.lxz <= 1) THEN s2 = sr.xa * ((sr.lzx)^2) ELSE s2 = %False END IF IF ISFALSE s1*s2 THEN sr.sx = MAX(s1,s2) ELSE sr.sx = (s1+s2) / 2 ' vanuit de y -transducer: IF (sr.lyx >= %False) AND (sr.lyx <= 1) THEN s1 = sr.ya * ((sr.lxy)^2) ELSE s1 = %False END IF IF (sr.lyz >= %False) AND (sr.lyz <= 1) THEN s2 = sr.ya * ((sr.lzy)^2) ELSE s2 = %False END IF IF ISFALSE s1*s2 THEN sr.sy = MAX(s1,s2) ELSE sr.sy = (s1+s2) / 2 ' vanuit de z -transducer: IF (sr.lzx >= %False) AND (sr.lzx <= 1) THEN s1 = sr.za * ((sr.lxz)^2) ELSE s1 = %False END IF IF (sr.lzy >= %False) AND (sr.lzy <= 1) THEN s2 = sr.za * ((sr.lyz)^2) ELSE s2 = %False END IF IF ISFALSE s1*s2 THEN sr.sz = MAX(s1,s2) ELSE sr.sz = (s1+s2) / 2 'integration: sr.s = (sr.sx + sr.sy + sr.sz) / 3! ' normal average ' statistic analysis: IF ISFALSE sr.statistic THEN EXIT SUB ELSE ' statistical data analysis: (cfr. former Bomstat procedures) ' store 7 bit reduced data in 16 strings ' sr.stat() = string * 128 in the type! IF BIT (sr.statistic,0) THEN i = ASC(MID$(sr.stat(0),1+(db0(128)/32),1)) IF i THEN MID$(sr.stat(0),1+(db0(128)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(0),1+(db0(255)/32),1) = CHR$(ASC(MID$(sr.stat(0),1+(db0(255)/32),1)) + 1) END IF IF BIT (sr.statistic,1) THEN i = ASC(MID$(sr.stat(1),1+(db1(128)/32),1)) IF i THEN MID$(sr.stat(1),1+(db1(128)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(1),1+(db1(255)/32),1) = CHR$(ASC(MID$(sr.stat(1),1+(db1(255)/32),1)) + 1) END IF IF BIT (sr.statistic,2) THEN i = ASC(MID$(sr.stat(2),1+(db2(128)/32),1)) IF i THEN MID$(sr.stat(2),1+(db2(128)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(2),1+(db2(255)/32),1) = CHR$(ASC(MID$(sr.stat(2),1+(db2(255)/32),1)) + 1) END IF IF BIT (sr.statistic,3) THEN i = ASC(MID$(sr.stat(3),1+(db3(128)/32),1)) IF i THEN MID$(sr.stat(3),1+(db3(128)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(3),1+(db3(255)/32),1) = CHR$(ASC(MID$(sr.stat(3),1+(db3(255)/32),1)) + 1) END IF IF BIT (sr.statistic,4) THEN i = ASC(MID$(sr.stat(4),1+(db4(128)/32),1)) IF i THEN MID$(sr.stat(4),1+(db4(128)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(4),1+(db4(255)/32),1) = CHR$(ASC(MID$(sr.stat(4),1+(db4(255)/32),1)) + 1) END IF IF BIT (sr.statistic,5) THEN i = ASC(MID$(sr.stat(5),1+(db5(128)/32),1)) IF i THEN MID$(sr.stat(5),1+(db5(128)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(5),1+(db5(255)/32),1) = CHR$(ASC(MID$(sr.stat(5),1+(db5(255)/32),1)) + 1) END IF IF BIT (sr.statistic,6) THEN i = ASC(MID$(sr.stat(6),1+(db6(128)/32),1)) IF i THEN MID$(sr.stat(6),1+(db6(128)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(6),1+(db6(255)/32),1) = CHR$(ASC(MID$(sr.stat(6),1+(db6(255)/32),1)) + 1) END IF IF BIT (sr.statistic,7) THEN i = ASC(MID$(sr.stat(7),1+(db7(128)/32),1)) IF i THEN MID$(sr.stat(7),1+(db7(128)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(7),1+(db7(255)/32),1) = CHR$(ASC(MID$(sr.stat(7),1+(db7(255)/32),1)) + 1) END IF ' energie-kanalen: IF BIT (sr.statistic,8) THEN i = ASC(MID$(sr.stat(8),1+(db8(128)/32),1)) IF i THEN MID$(sr.stat(8),1+(db8(128)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(8),1+(db8(255)/32),1) = CHR$(ASC(MID$(sr.stat(8),1+(db8(255)/32),1)) + 1) END IF IF BIT (sr.statistic,9) THEN i = ASC(MID$(sr.stat(9),1+(db9(128)/32),1)) IF i THEN MID$(sr.stat(9),1+(db9(128)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(9),1+(db9(255)/32),1) = CHR$(ASC(MID$(sr.stat(9),1+(db9(255)/32),1)) + 1) END IF IF BIT (sr.statistic,10) THEN i = ASC(MID$(sr.stat(10),1+(dbA(128)/32),1)) IF i THEN MID$(sr.stat(10),1+(dbA(128)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(10),1+(dbA(255)/32),1) = CHR$(ASC(MID$(sr.stat(10),1+(dbA(255)/32),1)) + 1) END IF IF BIT (sr.statistic,11) THEN i = ASC(MID$(sr.stat(11),1+(dbB(128)/32),1)) IF i THEN MID$(sr.stat(11),1+(dbB(128)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(11),1+(dbB(255)/32),1) = CHR$(ASC(MID$(sr.stat(11),1+(dbB(255)/32),1)) + 1) END IF ' accelleration channels: note: these have bipolar data! Range -2048 to 2047 ' so we shift the data with 2048 and get the zero value in the middle of the graph IF BIT (sr.statistic,12) THEN i = ASC(MID$(sr.stat(12),1+((dbC(128)+2048)/32),1)) IF i THEN MID$(sr.stat(12),1+((dbC(128)+2048)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(12),1+((dbC(255)+2048)/32),1) = CHR$(ASC(MID$(sr.stat(12),1+((dbC(255)+2048)/32),1)) + 1) END IF IF BIT (sr.statistic,13) THEN i = ASC(MID$(sr.stat(13),1+((dbD(128)+2048)/32),1)) IF i THEN MID$(sr.stat(13),1+((dbD(128)+2048)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(13),1+((dbD(255)+2048)/32),1) = CHR$(ASC(MID$(sr.stat(13),1+((dbD(255)+2048)/32),1)) + 1) END IF IF BIT (sr.statistic,14) THEN i = ASC(MID$(sr.stat(14),1+((dbE(128)+2048)/32),1)) IF i THEN MID$(sr.stat(14),1+((dbE(128)+2048)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(14),1+((dbE(255)+2048)/32),1) = CHR$(ASC(MID$(sr.stat(14),1+((dbE(255)+2048)/32),1)) + 1) END IF IF BIT (sr.statistic,15) THEN i = ASC(MID$(sr.stat(15),1+((dbF(128)+2048)/32),1)) IF i THEN MID$(sr.stat(15),1+((dbF(128)+2048)/32),1) = CHR$(i - 1) END IF MID$(sr.stat(15),1+((dbF(255)+2048)/32),1) = CHR$(ASC(MID$(sr.stat(15),1+((dbF(255)+2048)/32),1)) + 1) END IF END IF END SUB #IF %DEF(%NiDAQ) OR %DEF(%g_NIDAQmx) SUB Sonar_Statistics_Display () EXPORT ' 03.11.2003 ' task code for ii-sonar statistics display. ' the code for the parameter window resides in g_lib.dll (UD-Callback, setting the channel) ' the Task().channel field should pass the parameter for the channel to be displayed IF ISFALSE @pT(%Sonar_Stat_Task).tog THEN @pt(%Sonar_Stat_Task).freq = 16 IF ISFALSE @pgh.harvel THEN @pgh.harvel = MakeHarvelWindow ' in g_lib.dll END IF @pT(%Sonar_Stat_Task).tog = %True END IF IF ISFALSE BIT(sr.statistic, @pT(%Sonar_Stat_Task).channel) THEN BIT SET sr.statistic, @pT(%Sonar_Stat_Task).channel @pT(%Sonar_Stat_Task).Har.vel = sr.stat(MIN(@pT(%Sonar_Stat_Task).channel,15)) ShowHar @pT(%Sonar_Stat_Task).Har, 1,140,2! END SUB #ENDIF SUB Sonar_Display () EXPORT #IF %DEF(%NiDAQ) OR %DEF(%g_NiDAQmx) ' task code for ii-sonar display. (no references to any NiDaq function here) LOCAL k AS DWORD STATIC a() AS SINGLE IF ISFALSE @pT(%Sonar_Display_Task).tog THEN DIM a(5) AS STATIC SINGLE @pT(%Sonar_Display_Task).tog = %True @pT(%Sonar_Display_Task).freq = 21 '16 IF ISFALSE @pT(%Sonar_Display_Task).hParam THEN IF ISFALSE @pgh.spec THEN @pT(%Sonar_Display_Task).hParam = MakeSpectrumWindow ' should be same as @pgh.spec ELSE @pT(%Sonar_Display_Task).hparam = @pgh.spec END IF EXIT SUB END IF END IF k = @pT(%Sonar_Display_Task).patch SELECT CASE k CASE %False a(0) = sr.xa / %d12 ' normalize a(1) = sr.ya / %d12 a(2) = sr.za / %d12 a(3) = sr.xf / %d12 a(4) = sr.yf / %d12 a(5) = sr.zf / %d12 DrawRadarTriangle @pT(%Sonar_Display_Task).hParam, a() ' in: g_glib.dll CASE 1 TO 12 ' unipolar data channels - wave display DECR k DIM by(255) AS LOCAL INTEGER AT sr.pb(k) DIM sp(255) AS STATIC SINGLE FOR k = 0 TO 255 sp(k) = (by(k) / %d11) - 1 ' so we can use the full screen for the unipolar data NEXT k ShowNormArray @pgh.spec, sp() CASE 13 TO 16 ' bipolar, accelleration channels DECR k DIM by(255) AS LOCAL INTEGER AT sr.pb(k) DIM sp(255) AS STATIC SINGLE FOR k = 0 TO 255 sp(k) = by(k) / %d11 NEXT k ShowNormArray @pgh.spec, sp() ' displays 4 seconds of data (2 seconds under Nidaqmx) CASE 17 ' new display Draw_SonarTetrahedron @pT(%Sonar_Display_Task).hParam, sr ' in g_glib.dll END SELECT #ENDIF END SUB SUB Doppler_Tetrahedron_Display () EXPORT #IF %DEF(%NiDAQ) OR %DEF(%g_NiDAQmx) ' task code for ii-sonar display in fast doppler mode (no references to any NiDaq function here) ' tetrahedron setup. ' added 07.07.2009 - gwr ' normalisation for frequencies to be improved. LOCAL k AS DWORD STATIC a() AS SINGLE IF ISFALSE @pT(%DopplerTetraDisplay).tog THEN DIM a(5) AS STATIC SINGLE @pT(%DopplerTetraDisplay).freq = 30 ' filmspeed. 21 '16 IF ISFALSE @pT(%DopplerTetraDisplay).hParam THEN IF ISFALSE @pgh.spec THEN @pT(%DopplerTetraDisplay).hParam = MakeSpectrumWindow ' should be same as @pgh.spec ELSE @pT(%DopplerTetraDisplay).hparam = @pgh.spec END IF EXIT SUB END IF @pT(%DopplerTetraDisplay).tog = %True END IF ' k = @pT(%DopplerTetraDisplay).patch ' not in use now (copied from sonar) ' SELECT CASE k ' CASE %False a(0) = Doppler.xa ' normalized - may need further integration! a(1) = Doppler.ya ' drawn in blue a(2) = Doppler.za a(3) = MIN(Doppler.xf / 128,1) ' to be checked for realistic range a(4) = MIN(Doppler.yf / 128,1) ' this should be a normalisation a(5) = MIN(Doppler.zf / 128,1) DrawRadarTriangle @pT(%DopplerTetraDisplay).hParam, a() ' in: g_glib.dll ' CASE 1 TO 12 ' ' unipolar data channels - wave display ' DECR k ' DIM by(255) AS LOCAL INTEGER AT sr.pb(k) ' DIM sp(255) AS STATIC SINGLE ' FOR k = 0 TO 255 ' sp(k) = (by(k) / %d11) - 1 ' so we can use the full screen for the unipolar data ' NEXT k ' ShowNormArray @pgh.spec, sp() ' CASE 13 TO 16 ' ' bipolar, accelleration channels ' DECR k ' DIM by(255) AS LOCAL INTEGER AT sr.pb(k) ' DIM sp(255) AS STATIC SINGLE ' FOR k = 0 TO 255 ' sp(k) = by(k) / %d11 ' NEXT k ' ShowNormArray @pgh.spec, sp() ' displays 4 seconds of data ' CASE 17 ' ' new display ' Draw_SonarTetrahedron @pT(%Sonar_Display_Task).hParam, sr ' in g_glib.dll ' END SELECT #ENDIF END SUB SUB Radar_Display () EXPORT #IF %DEF(%NiDAQ) OR %DEF(%g_NiDAQmx) LOCAL i AS DWORD ' task code for ii-Radar display in Quadrada mode. ' The contents are normally changed by the UD controll (nr. 3) in the Radar Ctrl parameter window. IF ISFALSE @pgh.spec THEN ' we need a window handle before we can proceed. @pgh.spec = MakeSpectrumWindow 'StopTask %Radar_Display_Task EXIT SUB END IF SELECT CASE @pT(%Radar_Display_Task).patch ' note: we can now display the wave for any channel from the DAQ we want by using values 1,2,3,4,5,6,7,8 CASE %False @pT(%Radar_Display_Task).freq = 16 Draw_QuadRadar_square @pgh.spec , VARPTR (qr(0)) 'BYVAL pr(0) ' in g_glib.dll - pr() is a pointer array CASE 1 ' wave display DAQ channel 0 - X-vektor @pT(%Radar_Display_Task).freq = 1 ' buffer is 2 seconds, we display 1 second intervals DIM by(255) AS LOCAL INTEGER AT qr(0).pxbuf DIM sp(255) AS STATIC SINGLE FOR i = 0 TO 255 sp(i) = by(i) / 2048 NEXT i ShowNormarray @pgh.spec, sp() 'bx() CASE 2 ' wave display DAQ channel 1 - Y vektor @pT(%Radar_Display_Task).freq = 1 ' buffer is 2 seconds, we display 1 second intervals DIM by(255) AS LOCAL INTEGER AT qr(0).pybuf DIM sp(255) AS STATIC SINGLE FOR i = 0 TO 255 sp(i) = by(i) / 2048 NEXT i ShowNormarray @pgh.spec, sp() 'bx() CASE 3 ' wave display DAQ channel 2 - X-vektor @pT(%Radar_Display_Task).freq = 1 ' buffer is 2 seconds, we display 1 second intervals DIM by(255) AS LOCAL INTEGER AT qr(1).pxbuf DIM sp(255) AS STATIC SINGLE FOR i = 0 TO 255 sp(i) = by(i) / 2048 NEXT i ShowNormarray @pgh.spec, sp() 'bx() CASE 4 ' wave display DAQ channel 3 - Y vektor @pT(%Radar_Display_Task).freq = 1 ' buffer is 2 seconds, we display 1 second intervals DIM by(255) AS LOCAL INTEGER AT qr(1).pybuf DIM sp(255) AS STATIC SINGLE FOR i = 0 TO 255 sp(i) = by(i) / 2048 NEXT i ShowNormarray @pgh.spec, sp() 'bx() CASE 5 ' wave display DAQ channel 4 - X-vektor @pT(%Radar_Display_Task).freq = 1 ' buffer is 2 seconds, we display 1 second intervals DIM by(255) AS LOCAL INTEGER AT qr(2).pxbuf DIM sp(255) AS STATIC SINGLE FOR i = 0 TO 255 sp(i) = by(i) / 2048 NEXT i ShowNormarray @pgh.spec, sp() 'bx() CASE 6 ' wave display DAQ channel 5 - Y-vektor @pT(%Radar_Display_Task).freq = 1 ' buffer is 2 seconds, we display 1 second intervals DIM by(255) AS LOCAL INTEGER AT qr(2).pybuf DIM sp(255) AS STATIC SINGLE FOR i = 0 TO 255 sp(i) = by(i) / 2048 NEXT i ShowNormarray @pgh.spec, sp() 'bx() CASE 7 ' wave display DAQ channel 6 - X-vektor @pT(%Radar_Display_Task).freq = 1 ' buffer is 2 seconds, we display 1 second intervals DIM by(255) AS LOCAL INTEGER AT qr(3).pxbuf DIM sp(255) AS STATIC SINGLE FOR i = 0 TO 255 sp(i) = by(i) / 2048 NEXT i ShowNormarray @pgh.spec, sp() 'bx() CASE 8 ' wave display DAQ channel 7 - Y vektor @pT(%Radar_Display_Task).freq = 1 ' buffer is 2 seconds, we display 1 second intervals DIM by(255) AS LOCAL INTEGER AT qr(3).pybuf DIM sp(255) AS STATIC SINGLE FOR i = 0 TO 255 sp(i) = by(i) / 2048 NEXT i ShowNormarray @pgh.spec, sp() 'bx() END SELECT #ENDIF ' instead of using separate exclusive tasks, we use one and the same dll task with ' a parameter for what to display... (use the Task().patch field to this purpose... END SUB SUB Sonar_ii_VU () EXPORT ' VU-monitor procedure as used in BOM for the tetrahedral sonar setup STATIC resolution AS BYTE STATIC v% STATIC h%, bw%, Sp% LOCAL il?, H1% LOCAL hBrush AS LONG LOCAL hDC AS LONG LOCAL versize% LOCAL hOldBrush AS LONG DIM spoint(0 TO 15) AS LOCAL INTEGER IF ISFALSE @pT(%Sonar_VU_Task).tog THEN resolution = 8 ' this value should be made adjustable, read from $BOMINI v% = 2^resolution 'v% = 512 ' for 9 bit resolution v% = 256 for 8 bit, v% = 128 for 7 bit etc... IF ISFALSE @pT(%Sonar_VU_Task).hParam THEN @pT(%Sonar_VU_Task).hParam = Make_ii_VU_Window (8) h% = 1 ' horizontal start position for VU-graph bw% = 7 ' breedte van de balkjes Sp% = 5 ' spatie tussen de balkjes ' @pT(%Sonar_VU_Task).freq = 8 ' changed to 8 30.10.2003 ' was 3 '16 - should be set in application code. ' however, since we are using periodic timers now, this is not required at all... @pT(%Sonar_VU_Task).tog = %True END IF hDC = GetDC (@pT(%Sonar_VU_Task).hParam) ' blank existing graph: PatBlt hDC, h%,0,h% + ((bw%+ Sp%)*16) ,v%,%WHITENESS ' all 16 channels filled. spoint(0)= sr.xa spoint(1)= sr.ya spoint(2)= sr.za spoint(3)= sr.xyza spoint(4)= sr.xf spoint(5)= sr.yf spoint(6)= sr.zf spoint(7)= sr.xyzf spoint(8)= sr.xe spoint(9)= sr.ye spoint(10)= sr.ze spoint(11)= sr.xyze spoint(12)= sr.xac spoint(13)= sr.yac spoint(14)= sr.zac spoint(15)= sr.xyzac FOR il? = 0 TO 11 SHIFT RIGHT spoint(il?), 12 - resolution SELECT CASE il? CASE 0, 1, 2 hBrush = CreateSolidBrush (%GREEN) CASE 4,5,6 hBrush = CreateSolidBrush (%BLUE) CASE 8,9,10 hBrush = CreateSolidBrush (%CYAN) CASE ELSE hBrush = CreateSolidBrush (%RED) END SELECT hOldBrush = SelectObject(hDC, hBrush) H1% = h% + (il? * bw%) versize% = v% - spoint(il?) Rectangle hDC, H1%, v%, H1%+Sp%, versize% SelectObject hDC, hOldBrush DeleteObject hBrush NEXT il? FOR il? = 12 TO 15 spoint(il?) = spoint(il?) + 4096 SHIFT RIGHT spoint(il?), 13 - resolution SELECT CASE il? CASE 12,13,14 hBrush = CreateSolidBrush (%YELLOW) CASE ELSE hBrush = CreateSolidBrush (%RED) END SELECT hOldBrush = SelectObject(hDC, hBrush) H1% = h% + (il? * bw%) versize% = v% - spoint(il?) Rectangle hDC, H1%, v%, H1%+Sp%, versize% SelectObject hDC, hOldBrush DeleteObject hBrush NEXT il? ReleaseDC @pT(%Sonar_VU_Task).hParam, hDC END SUB SUB Radar_ii_VU () EXPORT ' VU-monitor procedure as used in Quadrada . - displays low level incoming amplitudes for both phases ' 19.09.2003: moved to DLL ' to be done: parameter such that we can change the display mode between raw and processed data... ' we can use the @pT().patch field to set the parameters for what to display. ' 0 = low level incoming amplitudes (for checking oscillation conditions and noise) ' 4 = Quadrada setup 4 bars for surface, 4 bars for speed STATIC resolution AS DWORD STATIC v% STATIC h%, bw%, Sp% LOCAL il?, H1% LOCAL hBrush AS LONG LOCAL hDC AS LONG LOCAL versize% LOCAL hOldBrush AS LONG LOCAL t AS DWORD DIM rpoint(0 TO 7) AS LOCAL INTEGER IF ISFALSE @pT(%Radar_VU_Task).tog THEN resolution = 7 '9 v% = 2^resolution 'v% = 512 ' for 9 bit resolution IF ISFALSE @pT(%Radar_VU_Task).hParam THEN @pT(%Radar_VU_Task).hParam = Make_ii_VU_Window (resolution) ' in g_hgen.inc h% = 1 ' horizontal start position for VU-graph bw% = 14 ' 7 ' breedte van de balkjes Sp% = 5 ' spatie tussen de balkjes @pT(%Radar_VU_Task).freq = 8 @pT(%Radar_VU_Task).tog = %True EXIT SUB END IF hDC = GetDC (@pT(%Radar_VU_Task).hParam) ' blank existing graph: PatBlt hDC, h%,0,h% + ((bw%+ Sp%)*16) ,v%,%WHITENESS SELECT CASE @pT(%Radar_VU_Task).patch CASE %False ' raw data. rpoint(0)= qr(0).xal rpoint(1)= qr(0).yal rpoint(2)= qr(1).xal rpoint(3)= qr(1).yal rpoint(4)= qr(2).xal rpoint(5)= qr(2).yal rpoint(6)= qr(3).xal rpoint(7)= qr(3).yal FOR il? = 0 TO 7 SELECT CASE il? CASE 0, 1 hBrush = CreateSolidBrush (%GREEN) CASE 2, 3 hBrush = CreateSolidBrush (%BLUE) CASE 4,5 hBrush = CreateSolidBrush (%YELLOW) CASE 6,7 hBrush = CreateSolidBrush (%RED) END SELECT hOldBrush = SelectObject (hDC, hBrush) H1% = h% + (il? * bw%) versize% = v% - rpoint(il?) Rectangle hDC, H1%, v%, H1%+Sp%, versize% SelectObject hDC, hOldBrush DeleteObject hBrush NEXT il? CASE 4 ' monitor procedure for Quadrada - displays bar-graph of analysis results rpoint(0)= MIN(qr(0).s,128) rpoint(1)= MIN(qr(1).s,128) rpoint(2)= MIN(qr(2).s,128) rpoint(3)= MIN(qr(3).s,128) rpoint(4)= MIN(qr(0).vf ,128) rpoint(5)= MIN(qr(1).vf ,128) rpoint(6)= MIN(qr(2).vf ,128) rpoint(7)= MIN(qr(3).vf ,128) FOR il? = 0 TO 7 SELECT CASE il? CASE 0, 4 hBrush = CreateSolidBrush (%GREEN) CASE 1,5 hBrush = CreateSolidBrush (%BLUE) CASE 2,6 hBrush = CreateSolidBrush (%YELLOW) CASE 3,7 hBrush = CreateSolidBrush (%RED) END SELECT hOldBrush = SelectObject (hDC, hBrush) H1% = h% + (il? * bw%) versize% = v% - rpoint(il?) Rectangle hDC, H1%, v%, H1%+Sp%, versize% SelectObject hDC, hOldBrush DeleteObject hBrush NEXT il? END SELECT ReleaseDC @pT(%Radar_VU_Task).hParam, hDC END SUB FUNCTION Radar_DAQ (BYVAL param AS LONG) EXPORT AS LONG ' this procedure starts/stops the data-acquisition for quad radar devices. ' 08.06.2009: support for NiDAQmx added ' 04.07.2009: gwr tests. board = %ii_2003 LOCAL i AS INTEGER FOR i = 0 TO 4 IF qr(i).sfakt < 1 THEN qr(i).sfakt = 2 ^ 11.25 ' 23.03.2003 - default. NEXT i 'MSGBOX FUNCNAME$ + STR$(param) #IF %DEF(%g_NiDAQmx) LOCAL ret AS LONG 'static taskname AS ASCIIZ * 20 - now @pDAQparams.taskname 'static taskhandle AS DWORD - now @pDAQparams.taskhandle LOCAL errBuff AS ASCIIZ * 2048 LOCAL cpcb AS DWORD LOCAL device AS ASCIIZ * 10 STATIC init AS DWORD '' DIM physicalChannel(0 TO 15) AS STATIC ASCIIZ * 40 '' DIM nameToAssignToChannel (0 TO 15) AS ASCIIZ * 40 DIM nametoassigntolines (0 TO 15) AS STATIC ASCIIZ * 40 LOCAL physicalchannels$ LOCAL nametoassigntochannels$ LOCAL customscalename AS ASCIIZ * 40 SELECT CASE param CASE -1 FUNCTION = @pDAQparams.mode CASE 0 GOSUB StopRadarDaq @pDAQparams.mode = %DAQ_NI CASE %DAQ_DOUBLEBUFFER IF ISFALSE @pDAQparams.daqstopped THEN GOSUB StopRadarDAQ END IF @pDAQparams.channel = %DAQ_RADAR @pDAQparams.mode = %DAQ_NI OR %DAQ_DOUBLEBUFFER @pDAQparams.inputconfig = 1 ' single ended ground referenced. @pDAQparams.rate = %False FOR i = 0 TO 7 @pDAQparams.samplingrate(i) = 128 @pDAQparams.ChannelVector(i) = i @pDAQparams.polarity(i) = 0 '0= bipolar , 1= unipolar @pDAQparams.voltagerange(i) = 10 ' set to -5 to +5V @pDAQparams.GainVector(i) = 1 @pDAQparams.rate = @pDAQparams.rate + @pDAQparams.samplingrate(i) ' sum of samplingrates. ' this to allow checks with the capabilities of the device. NEXT i @pDAQparams.taskname = "Quadradar-ii2003" ' can be anything you like ret = DAQmxCreateTask(@pDAQparams.taskname, @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) Logfile "Create Quadradar DAQ task error " & TRIM$(errbuff) END IF device = NiMxDevs(@pDAQparams.id) '.id is hier 1 of 2 nu. 'MSGBOX device + STR$(@pDaqPArams.id),,FUNCNAME$ '' physicalChannel(0) = TRIM$(device) & "/ai0" 'these strings must be as they appear in NiMax '' physicalChannel(1) = TRIM$(device) &"/ai1" '' physicalChannel(2) = TRIM$(device) &"/ai2" '' physicalChannel(3) = TRIM$(device) &"/ai3" '' physicalChannel(4) = TRIM$(device) &"/ai4" '' physicalChannel(5) = TRIM$(device) &"/ai5" '' physicalChannel(6) = TRIM$(device) &"/ai6" '' physicalChannel(7) = TRIM$(device) &"/ai7" '' ' following could be the actual use of the channels '' nameToAssignToChannel(0) ="Ai0" '' nameToAssignToChannel(1) ="Ai1" '' nameToAssignToChannel(2) ="Ai2" '' nameToAssignToChannel(3) ="Ai3" '' nameToAssignToChannel(4) ="Ai4" '' nameToAssignToChannel(5) ="Ai5" '' nameToAssignToChannel(6) ="Ai6" '' nameToAssignToChannel(7) ="Ai7" '' 'note: the following works, but you can also create all channels at once with one '' 'DAQmxCreateAIVoltageChan call.. '' FOR i = 0 TO 7 '' 'logfile TRIM$(physicalChannel(i)) ' we get here. result ok. '' ret = DAQmxCreateAIVoltageChan(BYVAL @pDAQparams.taskhandle, physicalChannel(i),nameToAssignToChannel(i),%DAQmx_Val_RSE,-5.0,5.0,%DAQmx_Val_Volts ,customscalename) '' '@pDAQparams.taskhandle moet byval '' 'using a variable for terminalconfig (byval as wel as byref) crashes. '' 'the constants don't cause a crash, but give a nidaq error (request value is not supported '' 'for the property DaqMX_Ai_termCfg). '' ' note gwr: we want to get data in 12 bit format (for compatibility with existing hardware) '' ' Quadradar voltage range is 0-5V to 5V bipolar '' IF ret THEN '' DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) '' Logfile TRIM$(errBuff) 'ok '' END IF '' NEXT i physicalchannels$ = TRIM$(device) + "/ai0:7" nametoassigntochannels$ = "Ai0, Ai1, Ai2, Ai3, Ai4, Ai5, Ai6, Ai7" DAQmxCreateAIVoltageChan(BYVAL @pDAQparams.taskhandle, TRIM$(physicalChannelS$),TRIM$(nameToAssignToChannels$),%DAQmx_Val_RSE,-5.0,5.0,%DAQmx_Val_Volts ,customscalename) ret = DaqmxCfgSampClkTiming(BYVAL @pDAQparams.taskhandle,"OnboardClock",128,%DAQmx_val_Rising,%DAQmx_Val_ContSamps,1) 'for our first test we go for strict compatibility and request 128 S/s on each channel ' we sample 8 channels. 'note: last param means nothing when using %DAQmx_Val_ContSamps IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "Clock error:" & TRIM$(errBuff) ELSE 'logfile "DaqmxCfgSampClkTiming passed with 128S/s" END IF cpcb = CODEPTR(Quadrada_EveryNCallback) ret = DAQmxRegisterEveryNSamplesEvent(BYVAL @pDAQparams.taskhandle,%DAQmx_Val_Acquired_Into_Buffer,1,0,BYVAL cpcb, BYVAL %NULL) '8 = nrEvents - from all channels together?? then we better take a mult of 16 ' check with x-tof's findings ' changed to 1 on 04.07.2009 gwr seems to be correct now. IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "error:" + TRIM$(errBuff) ELSE 'logfile "DAQmxRegisterEveryNSamplesEvent passed with N = 1" END IF cpcb = CODEPTR(NiDAQmx_DoneCallback) ret = DAQmxRegisterDoneEvent(@pDAQparams.taskhandle,0,cpcb,BYVAL %NULL) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "error:" + TRIM$(errBuff) ELSE ' logfile "DAQmxRegisterDoneEvent passed with cptr =" & STR$(cpcb) END IF ret = DAQmxStartTask(BYVAL @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile TRIM$(errBuff) END IF 'Logfile "radar aquisition started.." @pDAQparams.daqstopped = %False FUNCTION = %DAQ_DOUBLEBUFFER '%True CASE ELSE MSGBOX "Illegal mode",, FUNCNAME$ END SELECT EXIT FUNCTION ' essential!!! - ommitting this caused us half a day of debugging work... #ENDIF #IF %DEF(%NiDAQ) LOCAL retval AS INTEGER LOCAL dummy AS INTEGER LOCAL timebase AS INTEGER LOCAL sampleinterval AS INTEGER LOCAL scaninterval AS INTEGER LOCAL scantimebase AS INTEGER LOCAL sampletimebase AS INTEGER 'coded: 10.02.2003 - 23.03.2003 SELECT CASE param CASE -1 ' returns operational mode FUNCTION = @pDAQparams.mode CASE 0 ' stops data acquisition GOSUB StopRadarDAQ @pDAQparams.mode = %DAQ_NI CASE %DAQ_DOUBLEBUFFER GOSUB StopRadarDAQ @pDAQparams.channel = %DAQ_RADAR @pDAQparams.mode = %DAQ_NI OR %DAQ_DOUBLEBUFFER @pDAQparams.inputconfig = 1 ' single ended ground referenced. ' first set the AI characteristics FOR i = 0 TO 7 @pDAQparams.samplingrate(i) = 128 @pDAQparams.ChannelVector(i) = i @pDAQparams.polarity(i) = 0 '0= bipolar , 1= unipolar @pDAQparams.voltagerange(i) = 10 '5 '1 '10 ' set to -5 to +5V @pDAQparams.GainVector(i) = 1 '2 '10 ' note: unfortunately, increasing the gain also increases the DC offset of the card... ' 0.5 gives -10V to + 10V ' 1 gives -5V to + 5V ' 2 gives -2.5 to + 2,5V ' 5 gives -1V to +1V ' 10 -500mV to +500mV ' 20 -250mV to + 250mV ' 50 -100mV to + 100mV ' 100 -50mV to +50mV retval = AI_Configure%(@pDAQparams.id,i,@pDAQparams.inputconfig,1,@pDAQparams.polarity(i),0) ' msgbox str$(retval),,"ai-conf" 'ok 'dummy = NIDAQErrorHandler(retval,"AI_Config error {G_Nih.dll} [Radar]",0) ' in NiDAQEX_PB.BAS NEXT i @pDaqparams.rate = @pDAQparams.samplingrate(0) * 8 ' 8 channels only scantimebase = 2 ' use 100kHz / 10 microsecond clock scaninterval = 1000 ' this was set to :100000& / @pDAQparams.samplingrate(0) for , but ' when using 128 S/s, we get an NiDAQ error message protesting about ' the scan interval being too short. ' Thus we tried setting it to 1000 = 100 * 10 microseconds = 1 ms sampletimebase = -3 ' use 20MHz / 50ns clock sampleinterval = INT(20000000& / 100000&) '50000&) ' = 400 voor samplingrate = 50000 S/s @pDaqparams.scanfreq = @pDAQparams.samplingrate(0) ' = 100000& / scaninterval retval = DAQ_DB_Config(@pDAQparams.id,%True) ' msgbox str$(retval),,"db-conf" 'ok ' for debug only: retval = DAQ_Rate(@pDAQparams.rate,0,sampletimebase,sampleinterval) ' msgbox "Scanrate = " & STR$(@pDAQparams.rate) ' 1024 for 128 S/s ' now we can recalculate the circular buffer size, for the data refreshrate we want: @pDAQparams.Buffersize = @pDAQparams.rate ' in aantal samples voor 1 sekonde buffer REDIM ADCbuffer(@pDAQparams.Buffersize -1) AS GLOBAL INTEGER @pDAQparams.pADCbuffer = VARPTR(ADCbuffer(0)) ' Prepare for acquisition of multiple channels: retval = SCAN_SetUp(@pDAQparams.id,8,BYREF @pDAQparams.ChannelVector(0),BYREF @pDAQparams.Gainvector(0)) ' msgbox str$(retval),,"scan-stup" 'ok 'dummy = NIDAQErrorHandler(retval,"Scan_Setup error in {g_nih}[Radar]",0) retval = SCAN_Start(@pDAQparams.id,@pDAQparams.pADCbuffer,@pDAQparams.buffersize,sampletimebase,sampleinterval,scantimebase,scaninterval) ' msgbox str$(retval),,"scan-strt" ' ok 'dummy = NIDAQErrorHandler(retval,"Scan_Start error in {g_nih.dll}[Radar]",0) FUNCTION = %DAQ_DOUBLEBUFFER ' now start periodic event to retrieve the data: every 15 ms for Sr= 64 S/s (66.66 times a second) ' for 64 S/s: ' qr(0).TimerId = TimeSetEvent (15,0,CODEPTR(RadarDAQTask_CB),8,%TIME_PERIODIC OR %TIME_CALLBACK_FUNCTION) ' for 128 S/s: ' SELECT CASE qr(0).params ' CASE %ZEROCROSS qr(0).TimerId = TimeSetEvent (7,0,CODEPTR(RadarDAQTask_CB),8,%TIME_PERIODIC OR %TIME_CALLBACK_FUNCTION) ' CASE ELSE ' qr(0).TimerId = TimeSetEvent (7,0,CODEPTR(RadarDAQTask_CB_orig),8,%TIME_PERIODIC OR %TIME_CALLBACK_FUNCTION) ' END SELECT ' (using a periodic timer, every 8 ms, for 128S/s would be too slow, so we use 7ms) ' alternative: get data 8 times a second: ' qr(0).TimerId = TimeSetEvent (125,0,CODEPTR(RadarDAQTask_CB),64,%TIME_PERIODIC OR %TIME_CALLBACK_FUNCTION) IF ISFALSE qr(0).TimerId THEN MSGBOX "Failure starting QuadRadar data acquisition timer",, FUNCNAME$ END IF @pDAQparams.daqstopped = %False ' CASE %DAQ_SINGLEBUFFER ' = 4 ' GOSUB StopRadarDAQ ' ' NOT SUPPORTED !!! ' MSGBOX "Mode not supported",,FUNCNAME$ CASE ELSE MSGBOX "Illegal mode",, FUNCNAME$ END SELECT EXIT FUNCTION #ENDIF StopRadarDAQ: #IF %DEF(%NiDAQ) IF qr(0).timerId THEN TimeKillevent qr(0).timerid retval = DAQ_Clear (@pDAQparams.id) 'fails.. @pDAQparams.daqstopped = %True RETURN #ELSEIF %DEF(%g_NiDAQmx) IF @pDAQparams.taskhandle THEN ret = DAQmxStopTask(BYVAL @pDAQparams.taskHandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) Logfile TRIM$(errbuff) END IF ret = DAQmxClearTask(BYVAL @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) Logfile TRIM$(errbuff) END IF 'Warning "aquisition stopped" END IF @pDAQparams.daqstopped = %True @pDAQparams.taskhandle = %False @pDAQparams.taskname = NUL$(20) RETURN #ENDIF ' in case memory gets shuffled around... ' qr(0).pXbuf = VARPTR(Db0(0)) ' qr(0).pYbuf = VARPTR(Db1(0)) ' qr(1).pXbuf = VARPTR(Db2(0)) ' qr(1).pYbuf = VARPTR(Db3(0)) ' qr(2).pXbuf = VARPTR(Db4(0)) ' qr(2).pYbuf = VARPTR(Db5(0)) ' qr(3).pXbuf = VARPTR(Db6(0)) ' qr(3).pYbuf = VARPTR(Db7(0)) END FUNCTION FUNCTION GetSonarPointer () EXPORT AS DWORD sr.pb(0) = VARPTR(db0(0)) sr.pb(1) = VARPTR(db1(0)) sr.pb(2) = VARPTR(db2(0)) sr.pb(3) = VARPTR(db3(0)) sr.pb(4) = VARPTR(db4(0)) sr.pb(5) = VARPTR(db5(0)) sr.pb(6) = VARPTR(db6(0)) sr.pb(7) = VARPTR(db7(0)) sr.pb(8) = VARPTR(db8(0)) sr.pb(9) = VARPTR(db9(0)) sr.pb(10) = VARPTR(dbA(0)) sr.pb(11) = VARPTR(dbB(0)) sr.pb(12) = VARPTR(dbC(0)) sr.pb(13) = VARPTR(dbD(0)) sr.pb(14) = VARPTR(dbE(0)) sr.pb(15) = VARPTR(dbF(0)) FUNCTION = VARPTR(sr) END FUNCTION FUNCTION GetRadarpointer (BYVAL n AS DWORD) EXPORT AS DWORD ' must be called after intialisation IF n > UBOUND(qr) THEN MSGBOX "Pointer index out of range" ,,FUNCNAME$ EXIT FUNCTION END IF qr(0).pXbuf = VARPTR(db0(0)) ' A transducer, phase x qr(0).pYbuf = VARPTR(db1(0)) ' phase y qr(1).pXbuf = VARPTR(db2(0)) ' B transducer, phase x qr(1).pYbuf = VARPTR(db3(0)) ' phase y qr(2).pXbuf = VARPTR(db4(0)) qr(2).pYbuf = VARPTR(db5(0)) qr(3).pXbuf = VARPTR(db6(0)) qr(3).pYbuf = VARPTR(db7(0)) ' note that for n = 4, there is no data array!!!, so qr(4).pXbuf = qr(4).pYbuf = %False !!! ' we may use these fields for preservation of the traject. IF qr(n).setup = %TETRAHEDRON THEN ' DIM tetrad AS GLOBAL RadarTetrahedronType - now done on init declare. [13.07.2009] END IF FUNCTION = VARPTR(qr(n)) END FUNCTION SUB RadarDAQTask_CB (BYVAL wTimerID AS LONG, BYVAL msg AS LONG, BYVAL eventnr AS LONG, BYVAL dw1 AS LONG, BYVAL dw2 AS LONG) ' version using fixed length buffers:db0 - db7 - SQUARE SETUP with ZEROCROSS f-determination ' this version runs 128 times a second. ' this is the callback for the NiDAQ 7.4 version STATIC tlast AS DWORD LOCAL dummy AS INTEGER LOCAL newestpointindex AS LONG STATIC DAQstopped AS INTEGER DIM AD(eventnr-1) AS LOCAL INTEGER ' the number of data to be returned is passed in eventnr. ' first we acquire the data: #IF %DEF(%NiDAQ) dummy = DAQ_Monitor (@pDAQparams.id,-1,0,eventnr, VARPTR(AD(0)),newestpointindex,DAQstopped) ' logfile funcname$ + str$(dummy) + str$(newestpointindex) + str$(daqstopped) 'seems to work.. IF tlast THEN IF newestpointindex = tlast THEN EXIT SUB END IF tlast = newestpointindex ARRAY DELETE db0(), AD(0) ' db0() size = 255 ARRAY DELETE db1(), AD(1) ARRAY DELETE db2(), AD(2) ARRAY DELETE db3(), AD(3) ARRAY DELETE db4(), AD(4) ARRAY DELETE db5(), AD(5) ARRAY DELETE db6(), AD(6) ARRAY DELETE db7(), AD(7) ' logfile str$(AD(0)) + STR$(AD(1)) + STR$(AD(2)) + STR$(AD(3))+ STR$(AD(4)) + STR$(AD(5)) + STR$(AD(6)) + STR$(AD(7)) ' ok na het switchen in faust!! Quadrada_ii_Math 'dit ontbrak! #ENDIF END SUB SUB Quadrada_ii_Math () ' common for NiDAQ and NiDAQmx versions ' called from the data acquisition callback functions. ' 07.06.2009 gwr. should be compatible with all preexisting code and compositions LOCAL i AS DWORD STATIC tog AS DWORD LOCAL dev AS DWORD LOCAL Q AS SINGLE LOCAL lx AS SINGLE LOCAL ly AS SINGLE DIM AD(7) AS LOCAL INTEGER IF ISFALSE tog THEN DIM trigval(7) AS STATIC LONG ' for Schmitt-trigger DIM poscnt(7) AS STATIC DWORD ' running counter positive pulselength DIM negcnt(7) AS STATIC DWORD ' running counter negative pulselength DIM posamp(7) AS STATIC DWORD DIM negamp(7) AS STATIC DWORD DIM prev(7) AS STATIC DWORD ' flip flop DIM posend(7) AS STATIC DWORD ' endcount DIM negend(7) AS STATIC DWORD ' endcount DIM ampsum(7) AS STATIC DWORD DIM nosig(7) AS STATIC DWORD FOR i = 0 TO 7 trigval(i) = qr(i \2).noise posend(i) = 1 negend(i) = 1 poscnt(i) = 1 negcnt(i) = 1 NEXT i tog = %True END IF ' dit is een beetje stom, maar gevolg van de split van de funktie nodig voor dubbel gebruik... AD(0) = db0(255) ' bij 128 S/s zijn deze buffers 2 sekonden diep. AD(1) = db1(255) AD(2) = db2(255) AD(3) = db3(255) AD(4) = db4(255) AD(5) = db5(255) AD(6) = db6(255) AD(7) = db7(255) '-------------- FOR i = 0 TO 7 dev = i \ 2 ' 0,1,2,3 - radar sensor teller ' first we check for a no movement condition: ' for fast reset on no movements we add following rule: IF ABS(AD(i)) =< qr(dev).noise THEN INCR nosig(i) IF nosig(i) > qr(dev).dt THEN IF ISFALSE i MOD 2 THEN qr(dev).xf = %False qr(dev).xal = %False qr(dev).xt = %False ELSE qr(dev).yf = %False qr(dev).yal = %False qr(dev).yt = %False END IF ' IF ISFALSE prev(i) THEN ' we are counting lows negcnt(i) = %False ' reset frequency counter negamp(i) = %False ' ELSE ' we are counting highs poscnt(i) = %False posamp(i) = %False ' END IF ELSE ' ? END IF END IF amplitude: ' leaky integrator for amplitudes: IF ISFALSE i MOD 2 THEN ' this is the value we will use for position determination ' note that this a a square rooted unipolar value! (11 bit) ' qr().amp can never become larger than 1448 ' integration bug corrected 19.07.2004: we now use floats here. qr(dev).amp = ((qr(dev).dta * qr(dev).amp) + (SQR((AD(i)^2) + (AD(i+1)^2)) / 2)) / (qr(dev).dta + 1) END IF doppler_R: ' in line very fast frequency counter with schmitt-trigger square wave former: ' this can work even faster if we only count the duration of a single pulse. IF AD(i) > trigval(i) THEN IF ISFALSE prev(i) THEN poscnt(i) = 1 ' restart positive pulse counter prev(i) = %True ' flipflop negend(i) = negcnt(i) ' store duration of negative pulse trigval(i) = - qr(dev).noise ' set trigger value to negative for hysteresis IF (negamp(i) > %False) AND (posamp(i) > %False) THEN ampsum(i) = posamp(i) + negamp(i) ' sum of squares over full period IF ISFALSE i MOD 2 THEN qr(dev).xt = posend(i) + negend(i) qr(dev).xal = SQR(ampsum(i)/qr(dev).xt) qr(dev).xt = qr(dev).xt / @pDAQparams.Samplingrate(0) qr(dev).xf = 1!/ qr(dev).xt ELSE qr(dev).yt = posend(i) + negend(i) qr(dev).yal = SQR(ampsum(i)/qr(dev).yt) qr(dev).yt = qr(dev).yt / @pDAQparams.Samplingrate(0) qr(dev).yf = 1! / qr(dev).yt END IF ELSE IF ISFALSE i MOD 2 THEN qr(dev).xf = %False qr(dev).xal = %False ELSE qr(dev).yf = %False qr(dev).yal = %False END IF END IF nosig(i) = %False ' reset no movement counter posamp(i) = AD(i)^2 ' restart amplitude calculation ELSE INCR poscnt(i) posamp(i) = posamp(i) + (AD(i)^2) ' increment amplitude sum of squares END IF ELSE IF prev(i) THEN negcnt(i) = 1 ' restart negative pulse counter prev(i) = %False ' flipflop posend(i) = poscnt(i) ' store duration of positive pulse trigval(i) = qr(dev).noise ' give positive hysteresis IF (posamp(i) > %False) AND (negamp(i) > %False) THEN ' new 02.04.2003 ampsum(i) = posamp(i) + negamp(i) ' store sum of squares over complete previous period IF ISFALSE i MOD 2 THEN qr(dev).xt = posend(i) + negend(i) qr(dev).xal = SQR(ampsum(i)/qr(dev).xt) qr(dev).xt = qr(dev).xt / @pDAQparams.Samplingrate(0) qr(dev).xf = 1!/ qr(dev).xt ELSE qr(dev).yt = posend(i) + negend(i) qr(dev).yal = SQR(ampsum(i)/qr(dev).yt) qr(dev).yt = qr(dev).yt / @pDAQparams.Samplingrate(0) qr(dev).yf = 1! / qr(dev).yt END IF ELSE IF ISFALSE i MOD 2 THEN qr(dev).xf = %False qr(dev).xal = %False ELSE qr(dev).yf = %False qr(dev).yal = %False END IF END IF nosig(i) = %False negamp(i) = AD(i)^2 ELSE INCR negcnt(i) negamp(i) = negamp(i) + (AD(i)^2) END IF END IF NEXT i lineposition: ' faster code: IF (qr(0).amp > qr(0).noise) AND (qr(2).amp > qr(2).noise) THEN Q = SQR(qr(0).amp / qr(2).amp) qr(0).l = (2! - Q) / (Q+1) Q = SQR(qr(2).amp / qr(0).amp) qr(2).l = (2! - Q) / (Q+1) ELSE qr(0).l = -1 : qr(2).l = -1 END IF IF (qr(1).amp > qr(1).noise) AND (qr(3).amp > qr(3).noise) THEN Q = SQR(qr(1).amp / qr(3).amp) qr(1).l = (2! - Q) / (Q+1) Q = SQR(qr(3).amp / qr(1).amp) qr(3).l = (2! - Q) / (Q+1) ELSE qr(1).l = -1 : qr(3).l = -1 END IF ' berekening van de grootte van het oppervlak van het reflekterend lichaam: FOR dev = 0 TO 3 IF (qr(dev).l >= %False) AND (qr(dev).l <= 1) THEN qr(dev).s = qr(dev).amp * ((qr(dev).l+1)^2) ' now the range is again 11 bits (0 - 2048) ' for flexibility, we added a scaling factor: qr(dev).s = qr(dev).s / qr(dev).sfakt QuadRadar_PosAmp dev ELSE qr(dev).s = %False qr(dev).v = %False qr(dev).acc = %False qr(dev).xf = %False ' added 23.03.2003 qr(dev).yf = %False qr(dev).vf = %False ' added 24.03.2003 qr(dev).acf = %False ' added 26.03.2003 END IF NEXT dev integration: ' integration section: qr(4).s = (qr(0).s + qr(1).s + qr(2).s + qr(3).s) / 4! ' normal average ' from here we could derive moving mass as: ' qr(4).m = (qr(0).s * qr(1).s * qr(2).s * qr(3).s)^(3/10) ' volume at 1kg/dm^3 ==> mass ' and impuls as: ' qr(4).i = qr(4).m * qr(4).v ' kgm/s ' and force as: ' qr(4).f = qr(4).f * qr(4).acc ' kgm/s^2 lx = (qr(0).pc.real + qr(1).pc.real + qr(2).pc.real + qr(3).pc.real) / 4! ' average ly = (qr(0).pc.imag + qr(1).pc.imag + qr(2).pc.imag + qr(3).pc.imag) / 4! ' average qr(4).pc.real = ((qr(4).pc.real * 3) + lx) / 4! ' integrated 31ms qr(4).pc.imag = ((qr(4).pc.imag * 3) + ly) / 4! ' integrated C2P qr(4).pc, qr(4).pl ' integrated ' qr(4).vf = (qr(0).vf + qr(1).vf + qr(2).vf + qr(3).vf) / 4! ' average - changed 23.09.2003 to ' integrated value: (now over 125ms) qr(4).vf = ((qr(4).vf * 16) + (qr(0).vf + qr(1).vf + qr(2).vf + qr(3).vf)) / 20! ' in Hz IF MIN(qr(0).v,qr(1).v,qr(2).v,qr(3).v,qr(4).s) <= %False THEN qr(4).v = %False qr(4).acc = %False ELSE qr(4).v = (qr(4).v + qr(3).v + qr(2).v + qr(1).v + qr(0).v) / 5! ' integrated qr(4).acc = (qr(0).acc + qr(1).acc + qr(2).acc + qr(3).acc + qr(4).acc) / 5! ' -1 to + 0.5 range END IF END SUB FUNCTION Quadradar_PosAmp (BYVAL i AS DWORD) AS DWORD ' only for radar square setup. STATIC tog AS DWORD STATIC cosine AS SINGLE STATIC oldspeed AS SINGLE STATIC ppc() AS complex STATIC ppl() AS polar LOCAL pc AS complex LOCAL pl AS polar IF ISFALSE tog THEN DIM ppc(4) AS STATIC complex ' may become arrays to save trajects DIM ppl(4) AS STATIC polar tog = %True END IF ppc(i) = qr(i).pc ' save previous position information, before we calculate the new data ppl(i) = qr(i).pl ' coordinates and speed calculation for the square setup. qr(i).pc.real = qr(0).l - qr(2).l ' -1 to + 1 qr(i).pc.imag = qr(1).l - qr(3).l ' -1 to + 1 C2P qr(i).pc, qr(i).pl ' convert cartesian to polar - this preserves signs. ' knowing this, we can perform the cosine correction on the doppler frequencies in order to ' calculate movement speed. f = v .cos(angle) ' note that if the angle is larger than 45 degrees, we better use the adjacent transducer as ' data source. ' we need knowledge of position and the direction of the movement. Therefore we need data with regard ' to the previous position as well as with regard to the position now: ' We limit the calculation to movements within the covered square. IF (qr(i).pc.real >= -1!) AND (qr(i).pc.imag >= -1!) AND (qr(i).pc.real <= 1!) AND (qr(i).pc.imag <=1!) AND _ (ppc(i).real >= -1!) AND (ppc(i).imag >= -1!) AND (ppc(i).real =< 1!) AND (ppc(i).imag =< 1!) THEN ' step 1: schuif lijnstuk vorig punt tot huidig punt naar centrum van koordinatenstelsel: pc.real = ppc(i).real - qr(i).pc.real pc.imag = ppc(i).imag - qr(i).pc.imag ' step 2: nu moeten we de hoek met de x-as van dit lijnstuk vinden na konversie in polaire koordinaten: C2P pc, pl IF ISFALSE i MOD 2 THEN ' transducers A and C use the angle with the X-axis cosine = ABS(COS(pl.ang)) ELSE ' transducers B and D use the angle with the Y-axis, so we add 90 degrees. 'cosine = ABS(COS((ATN(1)*2) - pl.ang)) ' which is equivalent to taking the sine: cosine = ABS(SIN(pl.ang)) END IF IF ISFALSE qr(i).xf THEN qr(i).xf = qr(i).yf ' hier zouden we ook kunnen blokkeren wegens te IF ISFALSE qr(i).yf THEN qr(i).yf = qr(i).xf ' onbetrouwbare input. We zouden kunnen eisen dat ' zowel xf als yf > 0 en zelfs f = min(xf.yf) qr(i).acf = qr(i).vf ' used as temporary storage IF i < 2 THEN IF cosine > 0.5 THEN '0.707 THEN ' we could also take 0.5 (= cos 60 degrees) for more overlap ' we preserve the values for xf, yf qr(i).vf = (qr(i).xf + qr(i).yf) / (cosine + cosine) ELSE ' use adjacent source qr(i).vf = qr(i+1).vf END IF ELSE IF cosine > 0.5 THEN '0.707 THEN qr(i).vf = (qr(i).xf + qr(i).yf) / (cosine + cosine) ELSE qr(i).vf = qr(i-1).vf ' take info from adjacent channel END IF END IF IF qr(i).acf > %False THEN qr(i).acf = qr(i).vf - qr(i).acf ELSE qr(i).acf = %False' new fast accelleration value. ' note: with this hardware the absolute velocity in m/s equals qr(n).vf / 16.3 ' acceleration in m/s^2 is then qr(n).acf * 32 ' as now (02.04.2003) the returned values -if valid- range for vf from 0 to 72 and for acf -38 to + 36 ' In theory vf cannot become larger than 64Hz * 1.4142 = 90Hz. ' now we can derive the slow speed of the movement, if detected. oldspeed = qr(i).v ' for slow acceleration qr(i).v = 100 * SQR( ((ppc(i).real - qr(i).pc.real)^2) + ((ppc(i).imag - qr(i).pc.imag)^2) ) ' as now this value ranges from 0 to 0.11 , hence the multiply by 100, so we get 0-11 ' note: the absolute slow speed will depend on the physical size of the setup! IF oldspeed THEN qr(i).acc = qr(i).v - oldspeed ELSE qr(i).acc = %False ' acceleration FUNCTION = %true EXIT FUNCTION END IF NoValid: ' no valid data... - below noise level or outside coordinates of our setup qr(i).v = %False qr(i).acc = %False ' qr(i).pc.real = %False '? ' qr(i).pc.imag = %False '? qr(i).xf = %False ' added 23.03.2003 qr(i).yf = %False qr(i).vf = %False ' added 24.03.2003 qr(i).acf = %False ' added 26.03.2003 FUNCTION = %False END FUNCTION FUNCTION Quadradar_TetraMath (BYVAL i AS DWORD) AS DWORD ' for a setup using 4 doppler radar modules set up on the vertexes of a tetrahedron LOCAL q AS SINGLE ' uses Tetrad, as global type. ' we suppose x= 0 = left ' y= 1 = right ' z= 2 = front ' p= 3 = top ' the other vertexes are allways (i +1) MOD 4, (i+2) MOD 4, (i+3) MOD 4 SELECT CASE i CASE 0 Tetrad.ax = qr(i).amp 'MAX(qr(i).xal,qr(i).yal) IF Tetrad.ax THEN ' te berekenen: xy, xz, xh IF Tetrad.ay THEN Q = SQR(Tetrad.ax / Tetrad.ay) Tetrad.xy = (2! - Q)/ (Q + 1) ' 0-1 ELSE IF Tetrad.yx > %false AND Tetrad.yx < 1 THEN Tetrad.xy = 1- Tetrad.yx ELSE Tetrad.xy = -1 END IF END IF IF Tetrad.az THEN Q = SQR(Tetrad.ax / Tetrad.az) Tetrad.xz = (2! - Q)/ (Q + 1) ELSE IF Tetrad.zx > %False AND Tetrad.zx < 1 THEN Tetrad.xz = 1 - Tetrad.zx ELSE Tetrad.xz = -1 END IF END IF IF Tetrad.ah THEN Q = SQR(Tetrad.ax / Tetrad.ah) Tetrad.xh = (2! - Q)/ (Q + 1) ELSE IF Tetrad.hx > %False AND Tetrad.hx < 1 THEN Tetrad.xh = 1- Tetrad.hx ELSE Tetrad.xh = -1 END IF END IF IF Tetrad.xy >= %False AND Tetrad.xz >=%False AND Tetrad.xh >= %False THEN Tetrad.sx = Tetrad.ax * (((Tetrad.xy + Tetrad.xz + Tetrad.xh)/3)^2) Tetrad.sx = Tetrad.sx ^ 2 ELSE Tetrad.sx = %False END IF ELSE Tetrad.xy = 2 '-1 Tetrad.xz = 2 '-1 Tetrad.xh = 2 '-1 Tetrad.sx = %False END IF CASE 1 Tetrad.ay = qr(i).amp 'MAX(qr(i).xal,qr(i).yal) ' te berekenen: yx, yz, yh IF Tetrad.ay THEN IF Tetrad.ax THEN Q = SQR(Tetrad.ay / Tetrad.ax) Tetrad.yx = (2! - Q)/ (Q + 1) ' 0-1 ELSE IF Tetrad.xy > %false AND Tetrad.xy < 1 THEN Tetrad.yx = 1- Tetrad.xy ELSE Tetrad.yx = -1 END IF END IF IF Tetrad.az THEN Q = SQR(Tetrad.ay / Tetrad.az) Tetrad.yz = (2! - Q)/ (Q + 1) ELSE IF Tetrad.zy > %False AND Tetrad.zy < 1 THEN Tetrad.yz = 1 - Tetrad.zy ELSE Tetrad.yz = -1 END IF END IF IF Tetrad.ah THEN Q = SQR(Tetrad.ay / Tetrad.ah) Tetrad.yh = (2! - Q)/ (Q + 1) ELSE IF Tetrad.hy > %False AND Tetrad.hy < 1 THEN Tetrad.yh = 1- Tetrad.hy ELSE Tetrad.yh = -1 END IF END IF IF Tetrad.yx >= %False AND Tetrad.yz >=%False AND Tetrad.yh >= %False THEN Tetrad.sy = Tetrad.ay * (((Tetrad.yx + Tetrad.yz + Tetrad.yh)/3)^2) Tetrad.sy = Tetrad.sy ^ 2 ELSE Tetrad.sy = %False END IF ELSE Tetrad.yx = 2 '-1 Tetrad.yz = 2 '-1 Tetrad.yh = 2 '-1 Tetrad.sy = %False END IF CASE 2 Tetrad.az = qr(i).amp 'MAX(qr(i).xal,qr(i).yal) ' te berekenen: zx, zy, zh IF Tetrad.az THEN IF Tetrad.ax THEN Q = SQR(Tetrad.az / Tetrad.ax) Tetrad.zx = (2! - Q)/ (Q + 1) ' 0-1 ELSE IF Tetrad.xz > %false AND Tetrad.xz < 1 THEN Tetrad.zx = 1- Tetrad.xz ELSE Tetrad.zx = -1 END IF END IF IF Tetrad.ay THEN Q = SQR(Tetrad.az / Tetrad.ay) Tetrad.zy = (2! - Q)/ (Q + 1) ELSE IF Tetrad.yz > %False AND Tetrad.yz < 1 THEN Tetrad.zy = 1 - Tetrad.yz ELSE Tetrad.zy = -1 END IF END IF IF Tetrad.ah THEN Q = SQR(Tetrad.az / Tetrad.ah) Tetrad.zh = (2! - Q)/ (Q + 1) ELSE IF Tetrad.hz > %False AND Tetrad.hz < 1 THEN Tetrad.zh = 1- Tetrad.hz ELSE Tetrad.zh = -1 END IF END IF IF Tetrad.zx >= %False AND Tetrad.zy >=%False AND Tetrad.zh >= %False THEN Tetrad.sz = Tetrad.az * (((Tetrad.zx + Tetrad.zy + Tetrad.zh)/3)^2) Tetrad.sz = Tetrad.sz ^ 2 ELSE Tetrad.sz = %False END IF ELSE Tetrad.zx = 2 '-1 Tetrad.zy = 2 '-1 Tetrad.zh = 2 '-1 Tetrad.sz = %False END IF CASE 3 Tetrad.ah = qr(i).amp 'MAX(qr(i).xal,qr(i).yal) ' te berekenen: hx, hy, hz IF Tetrad.ah THEN IF Tetrad.ax THEN Q = SQR(Tetrad.ah / Tetrad.ax) Tetrad.hx = (2! - Q)/ (Q + 1) ' 0-1 ELSE IF Tetrad.xh > %false AND Tetrad.xh < 1 THEN Tetrad.hx = 1- Tetrad.xh ELSE Tetrad.hx = -1 END IF END IF IF Tetrad.ay THEN Q = SQR(Tetrad.ah / Tetrad.ay) Tetrad.hy = (2! - Q)/ (Q + 1) ELSE IF Tetrad.yh > %False AND Tetrad.yh < 1 THEN Tetrad.hy = 1 - Tetrad.yh ELSE Tetrad.hy = -1 END IF END IF IF Tetrad.az THEN Q = SQR(Tetrad.ah / Tetrad.az) Tetrad.hz = (2! - Q)/ (Q + 1) ELSE IF Tetrad.zh > %False AND Tetrad.zh < 1 THEN Tetrad.hz = 1- Tetrad.zh ELSE Tetrad.hz = -1 END IF END IF IF Tetrad.hx >= %False AND Tetrad.hz >=%False AND Tetrad.hy >= %False THEN Tetrad.sh = Tetrad.ah * (((Tetrad.hx + Tetrad.hy + Tetrad.hz)/3)^2) Tetrad.sh = Tetrad.sh ^ 2 ELSE Tetrad.sh = %False END IF ELSE Tetrad.hx = 2 '-1 Tetrad.hy = 2 '-1 Tetrad.hz = 2 '-1 Tetrad.sh = %False END IF END SELECT ' in principe hebben we nu alle koordinaten met voldoende redundantie ' we hebben ook de aspektoppervlakten vanuit 4 gezichtspunten. END FUNCTION FUNCTION GetTetraRadarPointer () EXPORT AS DWORD FUNCTION = VARPTR(Tetrad) END FUNCTION FUNCTION Test_USB_IO (BYVAL devnr AS DWORD) EXPORT AS DWORD ' returns %True if the device is found, else %False. LOCAL f AS ASCIIZ * 15 LOCAL retval AS DWORD LOCAL pt AS SECURITY_ATTRIBUTES PTR pt = VARPTR(USB_DIO(devnr).Security) f = "\\.\usbuart_" & TRIM$(STR$(devnr)) retval = CreateFile(f,%False,%FILE_SHARE_READ OR %FILE_SHARE_WRITE,BYVAL pt,%OPEN_EXISTING,0,0) IF retval = %INVALID_HANDLE_VALUE THEN FUNCTION = %False ELSE FUNCTION = %True CloseHandle retval END IF END FUNCTION FUNCTION Open_USB_IO (BYVAL devnr AS DWORD) EXPORT AS DWORD LOCAL f AS ASCIIZ * 15 LOCAL lIn AS LONG LOCAL Siz AS LONG LOCAL lOut AS LONG LOCAL pin AS BYTE LOCAL adr AS WORD LOCAL pt AS SECURITY_ATTRIBUTES PTR pt = VARPTR(USB_DIO(devnr).Security) IF USB_DIO(devnr).h THEN Close_USB_IO USB_DIO(devnr).h f = "\\.\usbuart_" & TRIM$(STR$(devnr)) USB_DIO(devnr).h = CreateFile(f,%GENERIC_WRITE OR %GENERIC_READ,%FILE_SHARE_WRITE OR %FILE_SHARE_READ,_ BYVAL pt,%OPEN_EXISTING,0,0) ' following also works, but gives no apparent performance advantage ' USB_DIO(devnr).h = CreateFile(f,%GENERIC_WRITE OR %GENERIC_READ,%FILE_SHARE_WRITE OR %FILE_SHARE_READ,_ ' BYVAL pt,%OPEN_EXISTING,%FILE_FLAG_OVERLAPPED,0) IF USB_DIO(devnr).h <> %INVALID_HANDLE_VALUE THEN ' ' programm the pull up's: ' ' poort 0: lIn = 4119 ' cfr. documentation Elektuur 01.2002 = &H001017 ' = dec. 00 16 23 DeviceIoControl USB_DIO(devnr).h, 4&, lIn,3,lOut,1,Siz, USB_DIO(devnr).gOverlapped ' ' poort 1: lIn = 4375 ' = &H1117 ' = dec. 00 17 23 DeviceIoControl USB_DIO(devnr).h, 4&, lIn,3,lOut,1,Siz, USB_DIO(devnr).gOverlapped ' ' programm the ports current, we set to maximum: FOR pin = 0 TO 7 ' set to 15: lIn = (65536 * 15) + (Pin * 256) + 23 ' = dec. 15 Pin 23 ' set to 0: (this is too low to get a logic 0 on the data lines) 'lIn = (Pin * 256) + 23 ' cfr. documentation Elektuur 02.2002 ' 0 Pin 23 DeviceIoControl USB_DIO(devnr).h, 4&, lIn,3,lOut,1,Siz, USB_DIO(devnr).gOverlapped NEXT pin ' write initial port condition: (bits reset, except bit0 of port p1 adr = devnr SHIFT LEFT adr, 12 adr = adr OR &H0FF0 Portout adr,%False PortOut adr + 1, 1 FUNCTION = %True 'USB_DIO(devnr).h ELSE MSGBOX "Cannot open USB port" USB_DIO(devnr).h = %False FUNCTION = %False END IF END FUNCTION SUB Close_USB_IO (BYVAL devnr AS DWORD) EXPORT IF USB_DIO(devnr).h THEN CloseHandle USB_DIO(devnr).h USB_DIO(devnr).h = %False END IF END SUB FUNCTION Open_Serial_IO (BYVAL devnr AS DWORD, hardware AS STRING) EXPORT AS DWORD ' to be used for ADXL202, BS2 stamps and suchlike devices ' should also be used for Sonar USB devices since they use a port manager to make them behave like a com port. MSGBOX FUNCNAME$ + STR$(devnr) + hardware STATIC sioh AS DWORD STATIC ccom$ sioh = FREEFILE IF devnr < 10 THEN ccom$ = "COM" & TRIM$(STR$(devnr)) ELSE MSGBOX "Com's > 9 not yet implemented in GMT",, FUNCNAME$ EXIT FUNCTION END IF COMM OPEN ccom$ AS #sioh IF ERRCLEAR THEN MSGBOX "Error opening " & ccom$ & " for " & hardware,, FUNCNAME$ EXIT FUNCTION ELSE ' MSGBOX "device handle" + STR$(sioh) + " opened succesfull" END IF SELECT CASE TRIM$(UCASE$(hardware)) CASE "USB_SONAR_V0" ' version 1.0 'MSGBOX "To be done!!!" ,, FUNCNAME$ ' msgbox "Opening USB Sonar",,funcname$ ' settings to be checked with Johannes '!! looks like opening and initialsising device works here, but the filehandle is invalid when we use it later on in our app ' cfr code in g_interfaces.inc, SUB Demo_UsbSonar() COMM SET #sioh, BAUD = 115200 'max is 256000 baud COMM SET #sioh, BYTE = 8 ' 8 bits COMM SET #sioh, PARITY = %FALSE ' No parity COMM SET #sioh, STOP = 0 ' 1 stop bit COMM SET #sioh, TXBUFFER = 64 ' transmit buffer COMM SET #sioh, RXBUFFER = 64 ' receive buffer ' Optional settings for flow control COMM SET #sioh, CTSFLOW = 0 ' Disable CTS COMM SET #sioh, RTSFLOW = 0 ' Disable RTS COMM SET #sioh, XINPFLOW = 0 ' Disable XON/OFF Input flow control COMM SET #sioh, XOUTFLOW = 0 ' Disable XON/XOFF Output flow control COMM SEND #sioh, CHR$(128) ' COMM SEND sioh, CHR$(&HFF, &H7F) 'reset usb sonar device MSGBOX "ËRR:"+ STR$(ERR) UsbSonar.hsio = sioh UsbSonar.com = devnr IF ERR THEN MSGBOX "ERROR" + STR$(ERRCLEAR) + " happened!",,FUNCNAME$ CASE "ADXL202" ' LOCAL dummy AS STRING ADXL202.hsio = sioh ADXL202.com = devnr ' memo: global ADXL202 as AccelSensDevice ' The ADXL202 board is powered by the DTS line of the COMport. ' Minimum settings COMM SET #sioh, BAUD = 38400 'max is 256000 baud ! (25kByte/s, of 40 microsekonde per byte) IF ERRCLEAR THEN MSGBOX "Error setbaudrate to 38400",, FUNCNAME$ COMM CLOSE #sioh EXIT FUNCTION END IF COMM SET #sioh, BYTE = 8 ' 8 bits IF ERRCLEAR THEN MSGBOX "Error setting COM port to 8 bit",, FUNCNAME$ COMM CLOSE #sioh EXIT FUNCTION END IF COMM SET #sioh, PARITY = %False ' No parity IF ERRCLEAR THEN MSGBOX "Error setting no parity on COM port",, FUNCNAME$ COMM CLOSE #sioh EXIT FUNCTION END IF ' comm set #sioh, START = 0 ' 1 start bit how can be set 1 start bit ??? COMM SET #sioh, STOP = 0 '0 = 1 stop bit, 1= 1.5 stop bit , 2= 2 stop bits IF ERRCLEAR THEN MSGBOX "Error setting stopbit",, FUNCNAME$ COMM CLOSE #sioh EXIT FUNCTION END IF COMM SET #sioh, TXBUFFER = 2048 ' transmit buffer IF ERRCLEAR THEN MSGBOX "Transmit Buffer allocation error",, FUNCNAME$ COMM CLOSE #sioh EXIT FUNCTION END IF COMM SET #sioh, RXBUFFER = 4096 '256 '64 '4 '4096 ' receive buffer IF ERRCLEAR THEN MSGBOX "Receive Buffer error",, FUNCNAME$ COMM CLOSE #sioh EXIT FUNCTION END IF ADXL202.samplingrate = 50 '64 ADXL202.Xbuf = REPEAT$(512,CHR$(13)& CHR$(88)) ' set 5000 as default center value = &H1388 ADXL202.Ybuf = REPEAT$(512,CHR$(13)& CHR$(88)) ' start the data acquisition task (using a periodic timer) ADXL202.TimerId = TimeSetEvent (1000/ADXL202.samplingrate,0,CODEPTR(ADXL202_CB),0,%TIME_PERIODIC OR %TIME_CALLBACK_FUNCTION) IF ISFALSE ADXL202.TimerId THEN MSGBOX "Failure starting ADXL202 data acquisition timer",, FUNCNAME$ COMM CLOSE #sioh ADXL202.hsio = %False ADXL202.com = %False EXIT FUNCTION ELSE ADXL202.naam = "ADXL202" ADXL202.Xref = 4900 ' reference center value ADXL202.Yref = 4660 ' reference center value ADXL202.tiltX = %False ADXL202.tiltY = %False ADXL202.accX = %False ADXL202.accY = %False ADXL202.daX = %False ADXL202.daY = %False ADXL202.xavg = ADXL202.Xref ADXL202.yavg = ADXL202.Yref ' request 4 bytes of data on init: COMM SEND #sioh, "G" ' = &H47 request data IF ERRCLEAR THEN MSGBOX "Sending error",, FUNCNAME$ END IF END IF CASE "BS2" ' Minimum settings COMM SET #sioh, BAUD = 9600 ' 128000 'max is 256000 baud ! (25kByte/s, of 40 microsekonde per byte) COMM SET #sioh, BYTE = 8 ' 8 bits COMM SET #sioh, PARITY = %FALSE ' No parity COMM SET #sioh, STOP = 0 ' 1 stop bit COMM SET #sioh, TXBUFFER = 2048 ' transmit buffer COMM SET #sioh, RXBUFFER = 4096 ' receive buffer ' Optional settings for flow control COMM SET #sioh, CTSFLOW = 1 ' Enable CTS COMM SET #sioh, RTSFLOW = 1 ' Enable RTS COMM SET #sioh, XINPFLOW = 0 ' Disable XON/OFF Input flow control COMM SET #sioh, XOUTFLOW = 0 ' Disable XON/XOFF Output flow control END SELECT FUNCTION = sioh END FUNCTION FUNCTION Close_Serial_IO (BYREF sioh AS DWORD, hardware AS STRING) EXPORT AS DWORD LOCAL dummy AS STRING ' logfile FUNCNAME$ IF ISFALSE sioh THEN EXIT FUNCTION SELECT CASE TRIM$(UCASE$(hardware)) CASE "ADXL202" ' stop timertask... IF ADXL202.TimerId THEN timeKillEvent ADXL202.TimerId : ADXL202.TimerId = %False IF COMM(#sioh, RXQUE) THEN COMM RECV #sioh, COMM(#sioh,RXQUE),dummy SLEEP 100 COMM CLOSE #sioh ADXL202.hsio = %False ADXL202.com = %False CASE ELSE IF COMM(#sioh, RXQUE) THEN COMM RECV #sioh, COMM(#sioh,RXQUE),dummy logfile "closing COM" + STR$(sioh) COMM CLOSE #sioh END SELECT sioh = %False ' logfile FUNCNAME$ + " done - lasterr" + STR$(ERRCLEAR) FUNCTION = %False END FUNCTION SUB ADXL202_CB (BYVAL wTimerID AS LONG, BYVAL msg AS LONG, BYVAL eventnr AS LONG, BYVAL dw1 AS LONG, BYVAL dw2 AS LONG) ' No export! ' this function is called at the required sampling rate as a callback for TimeSetEvent started on ' selecting the serial ADXL202 sensor device. STATIC dta AS STRING * 4 STATIC q AS DWORD LOCAL dummy AS STRING LOCAL tx AS LONG LOCAL ty AS LONG q = COMM(#ADXL202.hsio, RXQUE) IF ERRCLEAR THEN MSGBOX "RXQUE error",, FUNCNAME$ EXIT SUB END IF IF q >= 4 THEN COMM RECV #ADXL202.hsio, 4, dta ' dta = X-msb, X-lsb, Y-msb, Y-lsb IF ERRCLEAR THEN MSGBOX "Read error Com port" ,, FUNCNAME$ EXIT SUB END IF ADXL202.Xval = (ASC(LEFT$(dta,1)) * 256) + ASC(MID$(dta,2,1)) ADXL202.Yval = (ASC(MID$(dta,3,1)) * 256) + ASC(MID$(dta,4,1)) ADXL202.Xbuf = MID$(dta,2,1) & LEFT$(dta,1) & ADXL202.Xbuf ' fixed length string 1024 bytes ADXL202.Ybuf = RIGHT$(dta,1) & MID$(dta,3,1) & ADXL202.Ybuf ' now convert this data to real information: ' running average ADXL202.xavg = ((ADXL202.xavg * 99) + ADXL202.Xval) / 100 ' 2 second integration time ADXL202.yavg = ((ADXL202.yavg * 99) + ADXL202.Yval) / 100 ' 2 second integration time ' absolute acceleration: (this is positional!) ADXL202.accX = (ADXL202.Xval - ADXL202.Xref) /1250 '-2g to + 2g ' / 2500 ' range -4g to + 4g ADXL202.accY = (ADXL202.Yval - ADXL202.Yref) /1250 '-2g to + 2g ' / 2500 ' range -4g to + 4g ' relative acceleration would be: (would be much more usefull:) ADXL202.daX = (ADXL202.Xval - ADXL202.xavg) / 1250 ' range -2g to + 2g ADXL202.daY = (ADXL202.Yval - ADXL202.yavg) / 1250 ' range -2g to + 2g ' value is in degrees now! ' to calculate tilt, we need to integrate the buffer and compare it with the reference value tx = ADXL202.xavg - ADXL202.Xref ' range= 3550 to 6270 for -1g to + 1g, so tx = -1350 to + 1370 ty = ADXL202.yavg - ADXL202.Yref ' range= 3330 to 5960 for -1g to + 1g, so ty = -1330 to + 1300 tx = MIN(1250,tx) ty = MIN(1250,ty) tx = MAX(-1250,tx) tx = MAX(-1250,tx) ' nu is 1g = 1350 units = 90 graden ADXL202.tiltX = 57.3 * ARCSIN(tx / 1250) ' convert rad to degrees * 57.2958 ADXL202.tiltY = 57.3 * ARCSIN(ty / 1250) IF q-4 > %False THEN COMM RECV #ADXL202.hsio, q-4, dummy IF ERRCLEAR THEN MSGBOX "Flushing error Com port" ,, FUNCNAME$ EXIT SUB END IF END IF COMM SEND #ADXL202.hsio, "G" ' request new data. IF ERRCLEAR THEN MSGBOX "Sending error",, FUNCNAME$ EXIT SUB END IF ELSE ' no data, this is mostly the case... COMM SEND #ADXL202.hsio, "G" ' request new data. IF ERRCLEAR THEN MSGBOX "Sending error",, FUNCNAME$ EXIT SUB END IF END IF END SUB FUNCTION GetADXL202pointer () EXPORT AS DWORD FUNCTION = VARPTR(ADXL202) END FUNCTION FUNCTION BufOut (BYVAL adrreg AS DWORD,BYVAL pd AS DWORD, BYVAL siz AS DWORD) EXPORT AS DWORD ' adrreg is composed as the .preg, pinp, preg byte in our IO device types. ' pd is a pointer to the first element of the databuffer ' siz is the length in bytes - it must be even!!! LOCAL dev AS WORD LOCAL retval AS DWORD DIM b(siz-1) AS LOCAL BYTE AT pd ' must be local or we get a gpf... SELECT CASE adrreg #IF %DEF(%ACTIVEWIRE) CASE &H08A00 TO &H08A40 ' activewire usb devices retval = AwusbOutPort (b(0), siz) IF ISFALSE retval THEN dev = LOBYT(adrreg) SHIFT RIGHT dev, 1 ' now dev. is 0,1,2,3,4,5... IOports.msblsb(dev) = b(siz-1) SHIFT LEFT IOports.msblsb(dev), 8 IOports.msblsb(dev) = IOports.msblsb(dev) OR b(siz-2) FUNCTION = %True ELSE MSGBOX AwUsbErrorMessage (retval),,FUNCNAME$ FUNCTION = %False END IF #ENDIF END SELECT END FUNCTION SUB PortOut (BYVAL adr AS WORD, BYVAL b AS BYTE) EXPORT LOCAL retval AS LONG ' mimic Visual Basic statement SELECT CASE adr #IF %DEF(%NiDAQ) CASE 0,1,2 ' uses a NiDAQ DIO device retval = DIG_Out_Port(@pDIOparams.id, adr,b) CASE &H100 ' uses a NiDAQ DAQ device retval = DIG_Out_Port(@pDAQparams.id, adr,b) #ENDIF 'CASE < &H278 ' EXIT SUB CASE %Padr, %Padr+1, %Padr + 2 '- this crashes on NT machines if you do not run UserPort.exe ! push ax ! push dx ! mov dx, adr?? ! mov al, b? ! out dx, al ! pop dx ! pop ax CASE &H0FF0 TO &H7FF1 '> &H037F ' should be &H0FF0 to &H7FF1 ' uses a USB UART device - new 10.01.2002 ' the device number is in the high nibble of the high byte of adr 'Note that adr?? must be &H?FF? (lowest possible value is 4080) LOCAL dev AS DWORD LOCAL lIn AS LONG ' 3 bytes used as databuffer LOCAL lOut AS LONG ' 1 byte LOCAL siz AS LONG dev = adr SHIFT RIGHT dev,12 ' the port (each device has 2 ports) is in the low nibble of adr??, so adr?? AND &H000F ' new: lIn = b SHIFT LEFT lIn,8 lIn = lIn OR (adr AND &H000F) SHIFT LEFT lIn,8 lIn = lIn OR 21 DeviceIOControl USB_DIO(dev).h, 4&,lIn,3,lOut,1,siz,USB_DIO(dev).gOverlapped #IF %DEF(%ACTIVEWIRE) CASE &H08A00 TO &H08A40 ' for activewire devices ' the device number is in the lowest byte, numbered in even steps: 0,2,4,6,8... ' but, we do not need the device number since we can have only one instance of an ' aw-usb device in this thread. DIM b(1) AS LOCAL BYTE dev = LOBYT(adr) SHIFT RIGHT dev, 1 ' now dev. is 0,1,2,3,4,5... IF ISFALSE BIT(adr,0) THEN ' data byte for lsb, so 8 bit transfer b(0) = b retval = AwusbOutPort (b(0),1) IF ISFALSE retval THEN IOports.msblsb(dev) = IOports.msblsb(dev) AND &H0FF00 IOports.msblsb(dev) = IOports.msblsb(dev) OR b ELSE MSGBOX AwUsbErrorMessage (retval),,"" END IF ELSE ' register byte for msb, so 16 bit transfer ' we use the previous lsb as data byte b(1) = b b(0) = LOBYT(IOports.msblsb(dev)) retval = AwusbOutPort (b(0), 2) IF ISFALSE retval THEN lOut = b SHIFT LEFT lOut,8 IOports.msblsb(dev) = IOports.msblsb(dev) AND &H00FF IOports.msblsb(dev) = IOports.msblsb(dev) OR lOut ELSE MSGBOX AwUsbErrorMessage (retval),,"" END IF END IF #ENDIF END SELECT END SUB FUNCTION PortIn? (BYVAL adr??) EXPORT LOCAL answer AS BYTE #IF %DEF(%NiDAQ) ' ' this gives a general protection error when we do mov Portin, al... LOCAL retval AS INTEGER LOCAL pattern AS INTEGER SELECT CASE adr?? CASE &H379, %Padr+1 ' mimic Visual Basic statement ! push ax ! push dx ! mov dx, adr?? ! in al, dx ! mov answer, al ! pop dx ! pop ax FUNCTION = answer CASE 0,1,2 ' now adr?? must correspond the the port to be read (0,1,2...) ' used and tested in Roto_Mot retval = DIG_In_Port(@pDIOparams.id, adr??,pattern) FUNCTION = LOBYT(pattern) CASE &H0FF0 TO &H7FF1 ' uses a USB UART device - new 10.01.2002 ' the device number is in the high nibble of the high byte of adr 'Note that adr?? must be &H?FF? (lowest possible value is 4080) LOCAL dev AS DWORD LOCAL lIn AS LONG LOCAL lOut AS LONG LOCAL siz AS LONG dev = adr?? SHIFT RIGHT dev,12 ' the port (each device has 2 ports) is in the low nibble of adr??, so adr?? AND &H000F 'lIn = (256 * (adr?? AND &H000F)) + 20 lIn = adr?? AND &H000F SHIFT LEFT lIn, 8 lIn = lIn OR 20 DeviceIOControl USB_DIO(dev).h, 4&,lIn,2,lOut,2,siz,USB_DIO(dev).gOverlapped SHIFT RIGHT lOut, 8 FUNCTION = lOut ' was: (lOut / 256) AND 255 #IF %DEF(%ACTIVEWIRE) CASE &H08A00 TO &H08A40 ' for activewire devices - the leading zero is mandatory! ' the device number is in the lowest byte, numbered in even steps: 0,2,4,6,8... ' but, we do not need the device number since we can have only one instance of an ' aw-usb device in this thread. AwusbInPort BYVAL(VARPTR(lIn)),2 ' we always must read a word (16 bits) IF BIT(adr??,0) THEN ' data byte for lsb, so 8 bit transfer FUNCTION = LOBYT(lIn) ELSE ' register byte for msb, so HIBYT FUNCTION = HIBYT(lIn) END IF #ENDIF CASE ELSE ' nothing FUNCTION = %False END SELECT #ELSE SELECT CASE adr?? CASE <&H200 ' refuse FUNCTION = %False CASE %Padr TO %Padr + 2 ' mimic Visual Basic statement ! push ax ! push dx ! mov dx, adr?? ! in al, dx ! mov answer, al ! pop dx ! pop ax FUNCTION = answer CASE &H0FF0 TO &H7FF1 LOCAL dev AS DWORD LOCAL lIn AS LONG LOCAL lOut AS LONG LOCAL siz AS LONG dev = adr?? SHIFT RIGHT dev,12 lIn = adr?? AND &H000F SHIFT LEFT lIn, 8 lIn = lIn OR 20 DeviceIOControl USB_DIO(dev).h, 4&,lIn,2,lOut,2,siz,USB_DIO(dev).gOverlapped SHIFT RIGHT lOut, 8 FUNCTION = lOut #IF %DEF(%ACTIVEWIRE) CASE &H08A00 TO &H08A40 ' for activewire devices AwusbInPort BYVAL(VARPTR(lIn)),2 IF BIT(adr??,0) THEN FUNCTION = LOBYT(lIn) ELSE FUNCTION = HIBYT(lIn) END IF #ENDIF CASE ELSE FUNCTION = %False END SELECT #ENDIF END FUNCTION SUB Strobe (BYVAL Adr AS WORD, BYVAL strobebyte AS BYTE, BYVAL bitnumber AS BYTE, BYVAL t AS WORD) EXPORT ' when used with NiDAQ DIO devices, strobebyte will be disregarded. STATIC timres AS SINGLE STATIC tog AS LONG LOCAL tc0 AS QUAD 'LARGE_INTEGER ' was winApi type in 6.00 LOCAL tc1 AS QUAD 'LARGE_INTEGER LOCAL pqt0 AS QUAD PTR LOCAL pqt1 AS QUAD PTR pqt0 = VARPTR(tc0) pqt1 = VARPTR(tc1) IF ISFALSE tog THEN QueryPerformanceFrequency tc0 ' returns the performancecounterfrequency in Hz IF @pqt0 THEN timres = 1000000 / @pqt0 ' expressed in microseconds ELSE MSGBOX "[g_n*h.dll Strobe]: This PC cannot perform micro timing!",,": [Strobe]" END IF tog = %True END IF SELECT CASE Adr CASE &H0FF0 TO &H7FF1 '> &H037F ' uses a USB UART device - new 06.02.2002 ' the device number is in the high nibble of the high byte of adr ' Note that adr?? must be &H?FF? (lowest possible value is 4080) LOCAL dev AS DWORD LOCAL lIn AS LONG LOCAL lOut AS LONG LOCAL siz AS LONG dev = Adr SHIFT RIGHT dev,12 ' the port (each device has 2 ports) is in the low nibble of adr??, so adr?? AND &H000F BIT RESET strobebyte, bitnumber lIn = strobebyte SHIFT LEFT lIn,16 lIn = lIn + 21 + (256 * (Adr AND &H000F)) DeviceIOControl USB_DIO(dev).h, 4&,lIn,3,lOut,1,siz,USB_DIO(dev).gOverlapped BIT SET strobebyte, bitnumber lIn = strobebyte SHIFT LEFT lIn,16 lIn = lIn + 21 + (256 * (Adr AND &H000F)) DeviceIOControl USB_DIO(dev).h, 4&,lIn,3,lOut,1,siz,USB_DIO(dev).gOverlapped CASE >= %Padr ' Adr = I/O adres ' strobebyte = bit pattern to write ' bitnumber = bit to toggle ' t = time to keep bit in toggled position, expressed in microseconds. ' this strobes a single bit on a given I/O port ' Note that the printer port uses the port on base adres + 2 ' strobebyte = Portin (Adr) = %CtrlHiNib 'strobebyte = 80 ' BIT SET strobebyte, 0 ' makes strobe-low BIT TOGGLE strobebyte, bitnumber ' makes strobe-low, if printer port ! push eax ! push edx ! mov dx, Adr ! mov al, strobebyte ! out dx, al ! pop edx ! pop eax IF timres THEN QueryPerformanceCounter tc0 @pqt0 = @pqt0 + (t / timres) DO QueryPerformanceCounter tc1 LOOP UNTIL @pqt1 >= @pqt0 ELSE @pqt0 = 0 DO INCR @pqt0 LOOP UNTIL @pqt0 = t END IF BIT TOGGLE strobebyte, bitnumber ' makes strobe high, if printer port ! push eax ! push edx ! mov dx, Adr ! mov al, strobebyte ! out dx, al ! pop edx ! pop eax CASE 0,1,2 'ni_Strobe @pDIOparams.id, Adr, bitnumber, t #IF %DEF(%NiDAQ) 'stat = DIG_Out_Line @pDIOparams.id,adr,bitnumber,0 ' make strobe low. IF timres THEN QueryPerformanceCounter tc0 @pqt0 = @pqt0 + (t / timres) DO QueryPerformanceCounter tc1 LOOP UNTIL @pqt1 >= @pqt0 ELSE @pqt0 = 0 DO INCR @pqt0 LOOP UNTIL @pqt0 = t END IF 'stat = DIG_Out_Line @pDIOparams.id,adr,bitnumber,1 #ENDIF END SELECT END SUB FUNCTION g_Strobe (BYVAL Adr AS WORD, BYVAL strobebyte AS BYTE, BYVAL bitnumber AS BYTE) EXPORT AS LONG LOCAL pqt0 AS QUAD PTR LOCAL pqt1 AS QUAD PTR LOCAL tc0 AS QUAD LOCAL tc1 AS QUAD LOCAL dev AS DWORD LOCAL siz AS LONG LOCAL retval AS DWORD SELECT CASE Adr #IF %DEF(%ACTIVEWIRE) CASE &H08A00 TO &H08A40 ' for activewire devices ' the device number is in the lowest byte, numbered in even steps: 0,2,4,6,8... ' but, we do not need the device number since we can have only one instance of an ' aw-usb device in this thread. ' The strobe pulses generated are 17 microseconds long. (measured 18.05.2002) ' The time to transfer a byte (time between strobes) is 50 microseconds. (02.06.2002 YES) DIM b(3) AS LOCAL BYTE dev = LOBYT(adr) SHIFT RIGHT dev, 1 ' now dev. is 0,1,2,3,4,5... b(0) = LOBYT (IOports.msblsb(dev)) b(2) = b(0) b(1) = strobebyte b(3) = strobebyte BIT RESET b(1),bitnumber BIT SET b(3),bitnumber retval = AwusbOutPort (b(0),4) IF ISFALSE retval THEN IOports.msblsb(dev) = b(3) SHIFT LEFT IOports.msblsb(dev),8 IOports.msblsb(dev) = IOports.msblsb(dev) OR b(0) ELSE MSGBOX AwUsbErrorMessage (retval),,FUNCNAME$ FUNCTION = %False EXIT FUNCTION END IF #ENDIF CASE &H0FF0 TO &H7FF1 '> &H037F ' uses a USB UART device - new 06.02.2002 ' the device number is in the high nibble of the high byte of adr ' Note that adr?? must be &H?FF? (lowest possible value is 4080) LOCAL lIn AS LONG LOCAL lOut AS LONG dev = Adr SHIFT RIGHT dev,12 ' goto probeer: ' the port (each device has 2 ports) is in the low nibble of adr??, so adr?? AND &H000F BIT RESET strobebyte, bitnumber ' new: lIn = strobebyte SHIFT LEFT lIn,8 lIn = lIn OR (Adr AND &H000F) SHIFT LEFT lIn,8 lIn = lIn OR 21 DeviceIOControl USB_DIO(dev).h, 4&,lIn,3,lOut,1,siz,USB_DIO(dev).gOverlapped BIT SET lIn, bitnumber +16 DeviceIOControl USB_DIO(dev).h, 4&,lIn,3,lOut,1,siz,USB_DIO(dev).gOverlapped FUNCTION = %True EXIT FUNCTION probeer: ' try to do it in one move: BIT RESET strobebyte, bitnumber tc0 = strobebyte SHIFT LEFT tc0,8 tc0 = tc0 OR (Adr AND &H000F) SHIFT LEFT tc0, 8 tc0 = tc0 OR 21 SHIFT LEFT tc0, 8 BIT SET strobebyte, bitnumber tc0 = tc0 OR strobebyte SHIFT LEFT tc0, 8 tc0 = tc0 OR (Adr AND &H000F) SHIFT LEFT tc0,8 tc0 = tc0 OR 21 DeviceIOControl USB_DIO(dev).h, 4&,tc0,6,lOut,1,siz,USB_DIO(dev).gOverlapped CASE >= %Padr pqt0 = VARPTR(tc0) pqt1 = VARPTR(tc1) ' takes 25 microseconds on and [strobe stays negative for 12.5 microseconds] ' Adr = I/O adres ' strobebyte = bit pattern to write ' bitnumber = bit to toggle ' this strobes a single bit on a given I/O port ' Note that the printer port uses the port on base adres + 2 ' strobebyte = Portin (Adr) = %CtrlHiNib BIT TOGGLE strobebyte, bitnumber ' makes strobe-low, if printer port ! push eax ! push edx ! mov dx, Adr ! mov al, strobebyte ! out dx, al ! pop edx ! pop eax QueryPerformanceCounter tc0 INCR @pqt0 '@pqt0 = @pqt0 + 1 '(t / timres) DO QueryPerformanceCounter tc1 LOOP UNTIL @pqt1 >= @pqt0 BIT TOGGLE strobebyte, bitnumber ' makes strobe high, if printer port ! push eax ! push edx ! mov dx, Adr ! mov al, strobebyte ! out dx, al ! pop edx ! pop eax QueryPerformanceCounter tc0 INCR @pqt0 '@pqt0 = @pqt0 + 1 '(t / timres) DO QueryPerformanceCounter tc1 LOOP UNTIL @pqt1 >= @pqt0 CASE 0,1,2 #IF %DEF(%NiDAQ) ' devnr = assigned by NiDAQ ' portnumber = 0,1,2 for DIO devices ' strobebyte = bit pattern to write - no longer required since we can switch individual bits. ' bitnumber = bit to toggle in strobebyte ' t = time to keep bit in toggled position, expressed in microseconds. ' this strobes a single bit on a given I/O port ' Note that the hardware uses the port 2 'stat = DIG_Out_Line (@pDIOparams.id,Adr,bitnumber,0) ' make strobe low DIG_Out_Line @pDIOparams.id,Adr,bitnumber,0 ' without these query's the negative strobe becomes 9 microseconds on Putty using NiDAQ DIO24 ' measured with Vibi, using Fluke, 22.10.2001 ' with NiDAQ 6355 on Vaio, we get strobes between 24 and 30 microseconds. ' on Lily, we get 100 microseconds. ' QueryPerformanceCounter tc0 ' INCR @pqt0 ' DO ' QueryPerformanceCounter tc1 ' LOOP UNTIL @pqt1 >= @pqt0 ' stat = DIG_Out_Line (@pDIOparams.id,Adr,bitnumber,1) DIG_Out_Line @pDIOparams.id,Adr,bitnumber,1 ' QueryPerformanceCounter tc0 ' INCR @pqt0 ' DO ' QueryPerformanceCounter tc1 ' LOOP UNTIL @pqt1 >= @pqt0 ' we can also do (maybe even faster...): [yields same speed on Vaio with 6355 card] ' BIT RESET strobebyte, bitnumber ' stat = DIG_Out_Prt(@pDIOparams.id,Adr,strobebyte) ' BIT SET strobebyte, bitnumber ' stat = DIG_Out_Prt(@pDIOparams.id,Adr,strobebyte) #ENDIF END SELECT FUNCTION = %True END FUNCTION '' *********************************************************** '' * machine control code for musical robots * '' *********************************************************** FUNCTION Ni_16bitHandshake (BYVAL prt AS BYTE) EXPORT AS LONG ' initialize the DIO device for 16 bit I/O with handshaking ' prt = 0 resets the group settings ' prt = 1 configures output to the lowest 16 bit port ' prt = 2 configures output to the highest 16 bit port (only for 6355 cards) ' prt = 12 configure %DualHandshake mode ' STATIC tog AS BYTE ' implemented for and - under test. LOCAL stat AS INTEGER LOCAL retval AS INTEGER #IF %DEF(%NiDAQ) SELECT CASE UCASE$(@pDIOparams.device) CASE UCASE$("DAQCard DIO-24") SELECT CASE prt CASE 0 ' reset to non-handshaking mode, delete all port-grouping ' retval = DIG_SCAN_Setup(@pDIOparams.id,1,0,0,1) - proc. not found in dll... CASE 1 ' this card cannot be used for 16bit transfers, but we implemented a pretty fast ' pseudo 16bit out in our Ni_16bitOut function ' question: can we use following code? ' DIM lst(0 TO 1) AS LOCAL INTEGER ' lst(0) = 1 ' lst(1) = 0 ' retval = DIG_SCAN_Setup(@pDIOparams.id,1,2,VARPTR(lst()),1) ' with this, we have to use DIG_Block_Out for I/O ' stat= NiDAQErrorhandler(stat,"DIG_SCAN_Setup",0) ' alternative: stat = DIG_Prt_Config (@pDioparams.id,0,1,1) ' mode=1 for handhake enabled, dir=1 for output 'retval = NiDAQErrorhandler(stat,"DIG_Prt_Config",0) stat = DIG_Prt_Config (@pDioparams.id,1,0,1) ' port B, mode=0 no handshake ' retval = NiDAQErrorhandler(stat,"DIG_Prt_Config",0) @pDIOparams.flags = %WordHandshake END SELECT CASE UCASE$("DAQCard-6533"),"AT-DIO-32HS","PCI-DIO-32HS" SELECT CASE prt CASE 0 ' reset to non-handshaking mode, delete all port-groupings stat = DIG_Grp_Config(@pDIOparams.id,1,0,0,1) 'group=1, groupsize=0 (16bit),port=0,dir =1 for output ' retval = NiDAQErrorhandler(stat,"DIG_Grp_Config",0) @pDIOparams.flags = %False CASE 1 stat = DIG_Grp_Config(@pDIOparams.id,prt,2,0,1) 'group=1, groupsize=2 (16bit),port=0,dir =1 for output ' retval = NiDAQErrorhandler(stat,"DIG_Grp_Config",0) 'stat = DIG_Grp_Mode(@pDIOparams.id,prt,4,0,1,1,7) 'config handshake 8255 mode ' this leads to strobe pulses of 100ns ' or: use long pulse mode - protocol = 2 'stat = DIG_Grp_Mode(@pDIOparams.id,prt,2,0,1,1,7) ' 700ns strobe pulse '' above hangs..., apparently we must use: 'stat = DIG_Grp_Mode(@pDIOparams.id,prt,2,0,1,0,7) ' 700ns strobe pulse - positive going stat = DIG_Grp_Mode(@pDIOparams.id,prt,2,0,0,1,7) ' 700ns strobe pulse - negative going ' retval = NiDAQErrorHandler(stat,"DIG_Grp_Mode",0) @pDIOparams.flags = %WordHandshake ' 16 bit FUNCTION = %True CASE 2 stat = DIG_Grp_Config(@pDIOparams.id,prt,2,2,1) 'group=1, groupsize=2 (16bit),port=2,dir =1 for output ' retval = NiDAQErrorhandler(stat,"DIG_Grp_Config",0) stat = DIG_Grp_Mode(@pDIOparams.id,1,2,0,0,1,7) ' retval = NiDAQErrorHandler(stat,"DIG_Grp_Mode",0) @pDIOparams.flags = %WordHandshake FUNCTION = %True CASE 12 ' test dualhandshake mode ' in mode 2, 300ns, we measured 1ms for each reg/data byte transfer..., strobes are 100 microsec. ' configure port 0 as a group - (dataport) stat = DIG_Grp_Config(@pDIOparams.id,1,1,0,1) 'group=1, groupsize=1 (8bit),port=0,dir =1 for output ' retval = NiDAQErrorhandler(stat,"DIG_Grp_Config",0) 'stat = DIG_Grp_Mode(@pDIOparams.id,1,2,0,0,1,3) ' 300ns strobe pulse - negative going stat = DIG_Grp_Mode(@pDIOparams.id,1,4,0,1,1,0) ' 8255 mode... 'stat = DIG_Grp_Mode(@pDIOparams.id,1,1,0,1,1,0) ' retval = NiDAQErrorHandler(stat,"DIG_Grp_Mode",0) ' configure port 2 as a group - (dataport) stat = DIG_Grp_Config(@pDIOparams.id,2,1,2,1) 'group=2, groupsize=1 (8bit),port=0,dir =1 for output ' retval = NiDAQErrorhandler(stat,"DIG_Grp_Config",0) 'stat = DIG_Grp_Mode(@pDIOparams.id,2,2,0,0,1,3) ' 300ns strobe pulse - negative going stat = DIG_Grp_Mode(@pDIOparams.id,2,4,0,1,1,0) ' 8255 mode 'stat = DIG_Grp_Mode(@pDIOparams.id,2,1,0,1,1,0) ' retval = NiDAQErrorHandler(stat,"DIG_Grp_Mode",0) @pDIOparams.flags = %DualHandshake FUNCTION = %True CASE 13 ' test for harma stat = DIG_PRT_Config (@pDIOparams.id,2,0,1) ' make port 2 (C-port) output only - bits 0,1,2,3 stat = DIG_Out_Line (@pDIOparams.id,2,0,1) ' strobe must be high at rest. ' configure port 0 as a group - (dataport) ' configure port 2 as non-strobed I/O port stat = DIG_Grp_Config(@pDIOparams.id,1,1,0,1) 'group=1, groupsize=1 (8bit),port=0,dir =1 for output ' retval = NiDAQErrorhandler(stat,"DIG_Grp_Config",0) stat = DIG_Grp_Mode(@pDIOparams.id,1,2,0,0,1,7) ' retval = NiDAQErrorHandler(stat,"DIG_Grp_Mode",0) stat = DIG_PRT_Config (@pDIOparams.id,2,0,1) ' make port 2 (C-port) output only - bits 0,1,2,3 stat = DIG_Out_Line (@pDIOparams.id,2,0,1) ' strobe must be high at rest. @pDIOparams.flags = 13 CASE 14 ' this should attempt pattern generation mode, so timing would be only ' dependent on the internal clock of our NiDAQ device. stat = DIG_Grp_Config(@pDIOparams.id,prt,2,0,1) 'group=1, groupsize=2 (16bit),port=0,dir =1 for output ' retval = NiDAQErrorhandler(stat,"DIG_Grp_Config",0) stat = DIG_Block_PG_Config(@pDIOparams.id,1,1,0,2,2,0) ' timebase set to 10 microseconds ' now we can only use DIG_Block_Out operations to output data... ' %WordBlockTransfer END SELECT CASE ELSE MSGBOX "Invalid device for 16bit handshake operation",,"g_nih.dll" @pDIOparams.flags = %False FUNCTION = %False EXIT FUNCTION END SELECT #ELSE @pDIOparams.flags = %False FUNCTION = %False #ENDIF END FUNCTION FUNCTION Ni_16bitOut (BYVAL grp AS INTEGER, BYVAL bh AS BYTE, BYVAL bl AS BYTE) EXPORT AS LONG '05.11.2001 - implemented for Vibi with 8355 DAQ card 'on this leads to 100ns strobe signals in mode 4, 800ns strobes for mode=2. 'This would lead to suggest a peak data rate in the order of 5MWord/sec 'the practical data rate is in the order of 10000 words/second LOCAL w AS WORD LOCAL stat AS INTEGER LOCAL retval AS INTEGER LOCAL latched AS INTEGER STATIC card AS LONG #IF %DEF(%NiDAQ) IF ISFALSE card THEN SELECT CASE UCASE$(@pDIOparams.device) CASE UCASE$("DAQCard DIO-24") card = 1 CASE UCASE$("DAQCard-6533"),"AT-DIO-32HS","PCI-DIO-32HS" card = 2 CASE ELSE MSGBOX "Invalid device for 16bit PortOut",,"g_nih.dll" FUNCTION = %False EXIT FUNCTION card = -1 END SELECT END IF SELECT CASE card CASE 1 ' not tested yet... ' block code: ' DIM Buf(0 TO 2) AS LOCAL INTEGER ' LOCAL remain AS LONG ' Buf(0)=bh : Buf(1)=bl ' retval = DIG_Block_Out(@pDIOparams.id,1,Buf(),1) ' DO ' stat = Dig_Block_Check(@pDioParams.id,1,remain) ' 'retval = NiDAQYield(1) ' ??? ' LOOP UNTIL ISFALSE(remain) ' retval = NiDAQErrorhandler(stat,"DIG_Block_Check",0) ' FUNCTION = %True ' alternative: retval = DIG_Out_Port(@pDIOparams.id,1,bh) ' use special handshake connector board!!! retval = DIG_Out_Port(@pDIOparams.id,0,bl) DO stat = Dig_Prt_Status(@pDioParams.id,0,latched) 'retval = NiDAQYield(1) ' ??? LOOP UNTIL latched ' retval = NiDAQErrorhandler(stat,"DIG_Prt_Status",0) FUNCTION = %True CASE 2 SELECT CASE @pDioparams.flags CASE %False FUNCTION = %False ' illegal call EXIT FUNCTION CASE %DualHandShake ' = 2 ' in this mode we do not use the card's controll signals ACK/REQ as strobe ' for our automats, but only bit 0 of the second port. ' set register ' BIT SET bh,0 ' retval = DIG_Out_Grp @pDIOparams.id,2,bh OR 1 ' DO ' stat = DIG_Grp_Status(@pDIOparams.id,2,latched) ' LOOP UNTIL latched ' set data 'retval = DIG_Out_Grp @pDIOparams.id,1,bl ' DO ' stat = DIG_Grp_Status(@pDIOparams.id,1,latched) ' LOOP UNTIL latched ' strobe low 'BIT RESET bh,0 ' retval = DIG_Out_Grp @pDIOparams.id,2,bh AND &HFE ' DO ' stat = DIG_Grp_Status(@pDIOparams.id,2,latched) ' LOOP UNTIL latched ' strobe high again 'BIT SET bh,0 ' retval = DIG_Out_Grp @pDIOparams.id,2,bh OR 1 ' DO ' stat = DIG_Grp_Status(@pDIOparams.id,2,latched) ' LOOP UNTIL latched CASE 13, %ByteHandshake ' =1 ' testmode for harma - to be tested, with first pcb prototype 6533 board ' gives 25microsecond strobes on Vaio BIT SET bh,0 retval = DIG_Out_Port(@pDIOparams.id,2,bh) stat = Dig_Out_Grp (@pDIOparams.id,1,bl) DO stat = DIG_Grp_Status(@pDIOparams.id,1,latched) LOOP UNTIL latched BIT RESET bh,0 retval = DIG_Out_Port(@pDIOparams.id,2,bh) BIT SET bh,0 retval = DIG_Out_Port(@pDIOparams.id,2,bh) CASE %WordHandshake '=4 w = bh SHIFT LEFT w,8 w = w OR bl Dig_Out_Grp @pDIOparams.id,grp,w ' voor DAQCard 6533 FUNCTION = %True END SELECT CASE ELSE FUNCTION = %False END SELECT #ELSE FUNCTION = %False #ENDIF END FUNCTION FUNCTION IOportselector (BYVAL device AS DWORD) EXPORT AS DWORD ' device is the ID constant for the hardware that needs a port to connect to. 'note: the code dealing with the robot types directly is moved to separate helper functions 'in g_robo.dll (legacy since 02.06.2009 LOCAL hIOdlg AS LONG LOCAL ID_IODlg AS DWORD LOCAL hmo AS DWORD LOCAL usbcnt AS DWORD LOCAL usbawcnt AS DWORD LOCAL arrsize AS DWORD LOCAL i AS DWORD LOCAL d AS LONG LOCAL answer AS DWORD LOCAL ret AS DWORD LOCAL cnt AS LONG LOCAL items() AS STRING FUNCTION = %False arrsize = 0 cnt = 0 REDIM items(arrsize) 'share global Ioports with g_robo.dll 'Share_IoPorts VARPTR(Ioports), VARPTR(USB_DIO(0)) - removed 02.062009 ' check for NT: IF IsNT THEN ' check for a driver: Userport.sys under C:\Winnt\system32\drivers ' run UserPort.Exe, click start and then exit. ' To remove the driver: ' run UserPort.exe, click stop. ' Documentation is under C:b\pb\LPT_Drivers 'msgbox "NT detected" ' "C:\winnt\system32\drivers\UserPort.sys" ' for NT and Win2000 ' "C:\WINDOWS\system32\drivers\UserPort.sys" ' for XP items(0) = TRIM$(GetWindir) & "\system32\drivers\UserPort.sys" IF ExistFile (items(0)) THEN IOports.padr = %Padr items(0) = "1- Forced LPT port on &H" & LTrimZero(HEX$(IOports.padr)) INCR cnt REDIM PRESERVE items(cnt) ELSE IOports.padr = %False items(0)="" MSGBOX "Install or run UserPort.exe to get access to your ports" ,,FUNCNAME$ END IF ELSE ' if not NT, we can use the printerport as a first device: IF ISFALSE HIBYT(HIWRD(IOports.padr)) THEN IOports.padr = %Padr items(0) = "1- LPT port on &H" & LTrimZero(HEX$(%Padr)) INCR cnt REDIM PRESERVE items(cnt) ELSE items(0)= "" END IF END IF ' now create and calculate the size of the items array in function of available ports: ' #IF %DEF(%NiDAQ) IF @pDIOParams.id THEN IF ISFALSE HIBYT(HIWRD(IOports.NiDAQ_DIO)) THEN items(cnt)="2- NiDAQ DIO port" IOports.NiDAQ_DIO = %True INCR cnt REDIM PRESERVE items(cnt) END IF END IF IF @pDAQParams.id THEN IF ISFALSE HIBYT(HIWRD(IOports.NiDAQ_Daq)) THEN items(cnt)="3- NiDAQ DAQ port" IOports.NiDAQ_DAQ = %True INCR cnt REDIM PRESERVE items(cnt) END IF END IF ' #ENDIF ' add and count number of free usb uart devices: ' [Elektor type slow ports] usbcnt = 0 DO IF ISFALSE HIBYT(HIWRD(IOports.USB(usbcnt))) THEN hmo = Test_USB_IO (usbcnt) IF hmo THEN items(cnt)= TRIM$(STR$(4+usbcnt) & "- USB UART port nr." & STR$(usbcnt)) IOports.USB(usbcnt)= %True INCR usbcnt INCR cnt REDIM PRESERVE items(cnt) ELSE EXIT DO END IF ELSE INCR usbcnt END IF LOOP #IF(%DEF(%ACTIVEWIRE)) ' add and count number of free activewire usb devices: ' we have to change this code, since a single thread can only use a single Activewire usb device. usbawcnt = 0 DO IF ISFALSE HIBYT(HIWRD(IOports.AWUSB(usbawcnt))) THEN ' if in use the hibyt should read &B10000000 = &H8 ret = AwUsbOpen(usbawcnt) IF ISFALSE ret THEN items(cnt) = TRIM$(STR$(14+usbawcnt) & "- ActiveWire USB nr." & STR$(usbawcnt)) IOports.AwUSB(usbawcnt) = %True INCR usbawcnt INCR cnt REDIM PRESERVE items(cnt) AwUSBClose EXIT DO ELSE EXIT DO END IF ELSE INCR usbawcnt END IF LOOP #ENDIF ' if no ports are found , or none are free anymore, we should quit here... IF ISFALSE cnt THEN MSGBOX "No more free I/O ports found...",,FUNCNAME$ FUNCTION = %False EXIT FUNCTION END IF ID_IODlg= 100 DIALOG NEW @pgh.setup, "I/O-port selector",,,100,50,,TO hIOdlg CONTROL ADD LISTBOX, hIODlg, id_IODlg,items(), 0, 0, 100, 40,,, CALL IoDlgCallback ' modal: cnt = %False DIALOG SHOW MODAL hIOdlg TO cnt ' note cnt cannot be a register variable DIALOG END hIodlg ' msgbox items(IOports.msg-1) & " selected" SELECT CASE device CASE %IDM_BOM1 DisplayPanel.dev = %Bom1_Display SELECT CASE IOports.msg CASE 1 DisplayPanel.padr = %Padr DisplayPanel.pinp = %Padr + 1 DisplayPanel.preg = %Padr + 2 IOports.padr = %PortUsed OR %Padr ' set to port bin use FUNCTION = %True #IF %DEF(%NiDAQ) CASE 2 Ni_CentroPort @pDIOparams.id DisplayPanel.padr = %False ' NiDAQ dio DisplayPanel.pinp = 1 Displaypanel.preg = 2 IOports.NiDAQ_DIO = IOports.NiDAQ_DIO OR %PortUsed FUNCTION = %True CASE 3 DisplayPanel.padr = &H100 IOports.NiDAQ_DAQ = IOports.NiDAQ_DAQ OR %PortUsed FUNCTION = %True #ENDIF CASE 4 TO 13 IOports.msg = IOports.msg - 4 i = Open_USB_IO (IOports.msg) IF i > %False THEN ' now USB_DIO(devnr).h must contain a valid handle IOports.USB(IOports.msg)= %PortUsed OR %True SHIFT LEFT IOports.msg, 12 DisplayPanel.padr = IOports.msg DisplayPanel.padr = DisplayPanel.padr OR &H0FF0 DisplayPanel.preg = IOports.msg OR &H0FF1 FUNCTION = %True ' MSGBOX HEX$(DisplayPanel.padr) & " USB port selected" ELSE MSGBOX "Failure on opening requested USB port" END IF CASE 14 TO 46 #IF %DEF(%ACTIVEWIRE) ' activewire USB ports IOports.msg = IOports.msg - 14 i = AwUsbOpen (IOports.msg) IF ISFALSE i THEN IOports.AwUSB(IOports.msg)= %PortUsed OR %True SHIFT LEFT IOports.msg, 1 ' = x 2 DisplayPanel.padr = IOports.msg OR &H08A00 ' even DisplayPanel.preg = IOports.msg OR &H08A01 ' odd Aw_USB_CentroPort IOports.msg FUNCTION = %True ELSE MSGBOX "Failure on opening ActiveWire USB port",,"" END IF #ENDIF END SELECT CASE %IDM_BOM2 DisplayPanel.dev = %Bom2_Display SELECT CASE IOports.msg CASE 1 DisplayPanel.padr = %Padr IOports.padr = %PortUsed OR %Padr ' set to port bin use FUNCTION = %True #IF %DEF(%NiDAQ) CASE 2 Ni_CentroPort @pDIOparams.id DisplayPanel.padr = %False DisplayPanel.pinp = 1 Displaypanel.preg = 2 IOports.NiDAQ_DIO = %Portused OR %TRue FUNCTION = %True CASE 3 DisplayPanel.padr = &H100 IOports.NiDAQ_DAQ = %Portused OR %True FUNCTION = %True #ENDIF CASE 4 TO 13 IOports.msg = IOports.msg - 4 i = Open_USB_IO (IOports.msg) IF i > %False THEN IOports.USB(IOports.msg) = %PortUsed OR %True SHIFT LEFT IOports.msg, 12 DisplayPanel.padr = IOports.msg DisplayPanel.padr = DisplayPanel.padr OR &H0FF0 DisplayPanel.preg = IOports.msg OR &H0FF1 FUNCTION = %True ELSE MSGBOX "Failure on opening requested USB port",,"" END IF CASE 14 TO 46 #IF %DEF(%ACTIVEWIRE) ' activewire USB ports IOports.msg = IOports.msg - 14 i = AwUsbOpen (IOports.msg) IF ISFALSE i THEN IOports.AwUSB(IOports.msg)= %PortUsed OR %True SHIFT LEFT IOports.msg, 1 ' = x 2 DisplayPanel.padr = IOports.msg OR &H08A00 ' even DisplayPanel.preg = IOports.msg OR &H08A01 ' odd Aw_USB_CentroPort IOports.msg FUNCTION = %True ELSE MSGBOX "Failure on opening ActiveWire USB port",,"" END IF #ENDIF END SELECT CASE %IDM_SONARRANGER ' new 14.04.2004 SELECT CASE IOports.msg CASE 1 IOports.padr = %Padr OR %PortUsed SonarRanger.padr = %Padr SonarRanger.pinp = %Padr +1 SonarRanger.preg = %Padr + 2 FUNCTION = %True #IF %DEF(%NiDAQ) CASE 2 ' ' NiDAQDIO IF @pDIOParams.id THEN SonarRanger.pAdr= %False ' use port 0 for data. SonarRanger.pInp= 1 ' input port SonarRanger.pReg= 2 ' controll port - low nibble Ni_CentroPort @pDIOParams.id IOports.NiDAQ_DIO = %PortUsed OR %True 'm = "SonarRanger using " & @pDIOParams.device FUNCTION = %True ELSE MSGBOX "NiDAQ DIO device not initialized",,FUNCNAME$ END IF #ENDIF CASE 3 TO 46 MSGBOX "This port cannot be used for SonarRanger",,FUNCNAME$ END SELECT END SELECT IOports.msg = %False ' reset the message from the callback. END FUNCTION CALLBACK FUNCTION IoDlgCallback () AS LONG ' LOCAL lParam AS LONG ' LOCAL wParam AS LONG LOCAL TXT$ ' lParam = CBLPARAM ' wParam = CBWPARAM IF CBCTLMSG = %LBN_SELCHANGE THEN LISTBOX GET TEXT CBHNDL, 100 TO TXT$ 'msgbox txt$ 'function = VAL(LEFT$(txt$,1)) DIALOG END CBHNDL IOports.msg = VAL(TXT$) ' was: VAL(LEFT$(txt$,1)) FUNCTION = %True END IF END FUNCTION FUNCTION Topo (k%) EXPORT AS LONG ' #IF %DEF(%NiDAQ) - the conditional is not required here, since there are no NiDAQ calls here. ' this function was only used in Songbook - translated from Bom96. ' 22.08.99: used in Topoi as well. ' now the timeframe is a common parameter. ' We use bom.dT, updated from slider(1) in the Cockpit window. ' The original value for bom.dT was a constant = 125 ms. ' 25.03.2002: modified with new stat function in g_indep.dll ' 15.04.2003: moved to g_nih.dll STATIC Co AS LONG STATIC xh%, yh%, zh% LOCAL x%,y%,z% LOCAL sig! ' de overgedragen variabele k% kan volgende waarden aannemen: ' 0 = dan wordt de analyze uitgevoerd op grond van gemeten amplitudes ' 4 = dan wordt de analyze uitgevoerd op grond van gemeten snelheden ' als beveiliging zou de kode : IF k% THEN k%=4 ingepast kunnen worden. ' [22.08.99: implemented as follows:] ' changed to 250ms buffers 05.04.2003 - becomes worse ' so we now take 1 second! FUNCTION = Co ' default value = previous value SELECT CASE k% CASE <= 3 k% = %False ' body surface channels x% = AvgStatArr(Db0(), sig!,64) y% = AvgStatArr(Db1(), sig!,64) z% = AvgStatArr(Db2(), sig!,64) CASE <= 7 k% = 4 ' velocity channels x% = AvgStatArr(Db4(), sig!,64) y% = AvgStatArr(Db5(), sig!,64) z% = AvgStatArr(Db6(), sig!,64) CASE <= 11 k% = 8 ' power-channels x% = AvgStatArr(Db8(), sig!,64) y% = AvgStatArr(Db9(), sig!,64) z% = AvgStatArr(DbA(), sig!,64) CASE ELSE ' k% = 12 ' accelleration channels : not yet implemented. ' x% = AvgStatArr(DbC(), sig!,64) ' y% = AvgStatArr(DbD(), sig!,64) ' z% = AvgStatArr(DbE(), sig!,64) MSGBOX "Do not call Topo on acceleration channels!",, FUNCNAME$ EXIT FUNCTION END SELECT ' get 4-bit statistic positional amplitudes SHIFT RIGHT x%,8 ' 0-15 SHIFT RIGHT y%,8 SHIFT RIGHT z%,8 ' 'Hold-function causing positions to be held on standstill. IF MAX(x%,y%,z%) < = (sr.noise OR 1) THEN 'FUNCTION = Co EXIT FUNCTION END IF ' if nothing has changed as compared to the previous call of this ' function, exit and return the previous value of this function. ' This is a Hold-function as well IF (x% = xh%) AND (y% = yh%) AND (z% = zh%) THEN 'FUNCTION = Co EXIT FUNCTION END IF xh% = x% yh% = y% zh% = z% ' Topografische analyze: ' de ordening der plaatsbepalingen verloopt in wijzerzin uitgaand ' van geval x=y en z>x (12u positie) ' het bijzonder geval (centrale im- of explosie krijgt het nummer 1) IF x% = y% THEN IF y% = z% THEN FUNCTION = 1: Co = 1: EXIT FUNCTION ' eerste halfuur: IF x% < z% THEN FUNCTION = 2: Co = 2: EXIT FUNCTION ' tweede halfuur: IF x% > z% THEN FUNCTION = 8: Co = 8: EXIT FUNCTION END IF IF y% <= sr.noise THEN IF x% < z% THEN FUNCTION = 3: Co = 3: EXIT FUNCTION ' tweede halfuur IF x% > z% THEN FUNCTION = 9: Co = 9: EXIT FUNCTION END IF IF y% = z% THEN IF x% < y% THEN FUNCTION = 4: Co = 4: EXIT FUNCTION ' tweede halfuur: IF x% > z% THEN FUNCTION = 10: Co = 10: EXIT FUNCTION END IF IF z% <= sr.noise THEN IF x% < y% THEN FUNCTION = 5: Co = 5: EXIT FUNCTION 'tweede halfuur IF x% > y% THEN FUNCTION = 11: Co = 11: EXIT FUNCTION END IF IF x% = z% THEN IF x% < y% THEN FUNCTION = 6: Co = 6: EXIT FUNCTION ' tweede halfuur: IF x% > y% THEN FUNCTION = 12: Co = 12: EXIT FUNCTION END IF IF x% <= sr.noise THEN IF y% > z% THEN FUNCTION = 7: Co = 7: EXIT FUNCTION ' tweede halfuur IF y% < z% THEN FUNCTION = 13: Co = 13: EXIT FUNCTION END IF ' bijzondere -teoretisch wiskundig onmogelijke gevallen zijn er wanneer ' twee waarden nul zouden zijn: een beweging in een ruimtelijke figuur ' (intersektie van 2 bolsegmenten) loodrecht op zowel de ene 0-vektor als ' de andere nul vektor. In volgorde zouden dit zijn: ' x=0 , y=0 , z >0 : beide handen omhoog op cirkels rond x en y ? ' x=0 , z=0 , y > 0 ' y =0, z=0, x > 0 ' #ENDIF END FUNCTION FUNCTION Place () EXPORT AS LONG STATIC Co AS LONG STATIC xh%, yh%, zh% LOCAL xf%, yf%,zf% LOCAL x%, y%, z% LOCAL sig! LOCAL t AS DWORD LOCAL av AS LONG ' old: ' get 4-bit statistic positional amplitudes ' new: ' changed to 500ms 18.02.2002 ' to 1 sec. 05.04.2003 xf% = AvgStatArr (Db0(), sig!, @pDaqparams.scanfreq) yf% = AvgStatArr (Db1(), sig!, @pDaqparams.scanfreq) zf% = AvgStatArr (Db2(), sig!, @pDaqparams.scanfreq) SHIFT RIGHT xf%,8 SHIFT RIGHT yf%,8 SHIFT RIGHT zf%,8 ' if nothing has changed as compared to the previous call, exit. IF (xf% = xh%) AND (yf% = yh%) AND (zf% = zh%) THEN FUNCTION = Co ' default value = previous value EXIT FUNCTION END IF xh% = xf% yh% = yf% zh% = zf% x% = 2 * SQR(sr.xe) y% = 2 * SQR(sr.ye) z% = 2 * SQR(sr.ze) ' Following statement functions as a 'Hold on' causing chords to ' be held on standstill. IF MAX(x%,y%,z%) <= sr.noise THEN FUNCTION = Co EXIT FUNCTION END IF ' Following statement implements the possibility to switch-off an ' effect or chord on a small and slow movement of the hand: av = AvgStatArr (Db7(), sig!, @pDaqparams.scanfreq) ' now 1 sec. SHIFT RIGHT av, 8 IF av <= sr.noise THEN Co = 1 : FUNCTION = 1 : EXIT FUNCTION '---- ' Following logic figures out the radial position in space of a movement IF ISFALSE yf% AND ISFALSE zf% THEN Co = 2: FUNCTION = 2: EXIT FUNCTION IF ISFALSE xf% AND ISFALSE yf% THEN Co = 3: FUNCTION = 3: EXIT FUNCTION IF ISFALSE xf% AND ISFALSE zf% THEN Co = 4: FUNCTION = 4: EXIT FUNCTION IF (xf% EQV yf%) AND (yf% EQV zf%) THEN Co = 5: FUNCTION = 5: EXIT FUNCTION IF yf% EQV zf% THEN Co = 6: FUNCTION = 6: EXIT FUNCTION IF xf% EQV yf% THEN Co = 7: FUNCTION = 7: EXIT FUNCTION IF xf% EQV zf% THEN Co = 8: FUNCTION = 8: EXIT FUNCTION IF (xf% < yf%) AND (xf% < zf%) THEN IF (yf% < zf%) THEN Co = 9 FUNCTION = 9 EXIT FUNCTION ELSE Co = 10 FUNCTION = 10 EXIT FUNCTION END IF END IF IF (yf% < xf%) AND (yf% < zf%) THEN IF (xf% < zf%) THEN Co = 11 FUNCTION = 11 EXIT FUNCTION ELSE Co = 12 FUNCTION = 12 EXIT FUNCTION END IF END IF IF (zf% < xf%) AND (zf% < yf%) THEN IF (xf% < yf%) THEN Co = 13 FUNCTION = 13 EXIT FUNCTION ELSE Co = 14 FUNCTION = 14 EXIT FUNCTION END IF END IF END FUNCTION ' *********************************************** ' * SONAR RANGER SUPPORT SECTION * ' *********************************************** FUNCTION SonarRanger_Init_DLL (BYREF gh AS GMT_HANDLES, BYVAL tasknr AS WORD) EXPORT AS DWORD ' returns a pointer to SonarRanger.structure to the executable. ' the user has to pass a value for tasknr. This task will we used for the data acquisition. LOCAL m AS ASCIIZ * 40 LOCAL i AS LONG LOCAL chk AS BYTE IF ISFALSE pgh THEN ' pgh is a global pointer pgh = VARPTR(gh) END IF IF ISFALSE @pgh.gnh THEN @pgh.gnh = hInst ' instance handle of this dll. END IF IF ISFALSE SonarRanger.preg THEN i = IOportselector (%IDM_SONARRANGER) END IF IF ISFALSE i THEN FUNCTION = %False : EXIT FUNCTION SonarRanger.tasknr = tasknr SonarRanger.naam = "Ranger" ' default settings: (real time updatable with ctrl-window) SonarRanger.nearlimit = 34 ' in cm SonarRanger.farlimit = 680 ' in cm SonarRanger.mintime = sonarRanger.nearlimit * 2 / %VelSound ' 2 ms SonarRanger.maxtime = SonarRanger.farlimit * 2 / %VelSound ' 40ms SonarRanger.range = SonarRanger.farlimit - SonarRanger.nearlimit ' required for normalisation SonarRanger.dT = 4 SonarRanger.dv = 8 SonarRanger.rate = 8 ' movable dll tasks: @pT(SonarRanger.tasknr).cPtr = CODEPTR(SonarRanger_DAQ) @pT(SonarRanger.tasknr).naam = SonarRanger.naam @pT(SonarRanger.tasknr).freq = 1000 @pT(SonarRanger.tasknr).flags = %DLL_TASK ' initialize hardware: PortOut Sonarranger.Padr, %False ' make data lines low. - we use only bit 0 here. chk = PortIn(SonarRanger.pinp) IF BIT (chk,4) THEN ' check for power-on condition - bit 4. ' StartTask SonarRanger.tasknr ' sonar-daq task ELSE MSGBOX "Sonar device unavailable or not powered on",, FUNCNAME$ IF @pT(SonarRanger.tasknr).swit THEN stoptask SonarRanger.tasknr FUNCTION = %False EXIT FUNCTION END IF FUNCTION = VARPTR(SonarRanger) m = "SonarRanger using port &H" & LTrimzero(HEX$(SonarRanger.padr)) Sendmessage gh.Cockpit, %WM_SETTEXT,0, VARPTR(m) END FUNCTION SUB SonarRanger_DAQ () EXPORT STATIC Olddistance AS DWORD ' in cm STATIC tog AS DWORD STATIC tt AS DWORD ' in ms. LOCAL chk AS BYTE ' data acquisition task for sonarranger. ' ' polling code - it would be better to use timer or real hardware interrupt. ' hardware timing leads to the best precision. ' now the measurement precision is a direct function of the timing resolution in GMT. ' %Inithigh = 1 ' bit 0 ' %Echo = 128 ' bit 7 ' %Power = 16 ' bit 4 IF ISFALSE tog THEN PortOut Sonarranger.Padr, 1 ' set bit 0 %InitHigh ' make INIT High. This enables the 420kHz ' oscillator and causes a transmit of 16 cycles @ 300V - 49.4kHz ' The transducer holds a 150V dc bias, for receive. ' The osc. output steps to 93kHz and remains there as long as INIT stays high. tt = TimeGetTime tog = %True @pT(SonarRanger.tasknr).freq = 1000 ' poll as fast as possible... (we need ms precision...) EXIT SUB ELSE ' wait for echo... chk = PortIn(SonarRanger.pinp) ' input port IF BIT (chk,7) THEN ' check bit 7 (centronics busy signal) tog = %True ' here we could also check for time-out conditions. IF TimeGetTime - tt > SonarRanger.maxtime THEN ' reset! PortOut SonarRanger.Padr, %False @pT(Sonarranger.tasknr).freq = SonarRanger.rate '8 tog = %False END IF EXIT SUB ELSE ' Echo bit is inverted on printeradapter. ' Wait for echo. (When echo pulses high, and read-out is false) tt = TimeGetTime - tt ' read time-count value PortOut SonarRanger.padr, %False ' reset port to 0, bit 0 is enough... ' make init low again. IF ISFALSE SonarRanger.dT THEN ' without integration: SonarRanger.Distance = tt * %Velsound SHIFT RIGHT SonarRanger.Distance, 1 ' divide by 2 ELSE ' with integration: SonarRanger.Distance = (SonarRanger.Distance * (SonarRanger.dT -1)/ SonarRanger.dT) + ((tt * %Velsound / 2)/ SonarRanger.dT) END IF ' mits een konstante samplingfrekwentie ' kan ook de bewegingssnelheid in 1 dimensie worden afgeleid: ' Merk op dat de meetfout hier 2% * 2% = 4% beloopt, en dat de snelheid ook ' een funktie is van de cosinus van de bewegingshoek tegenover de rechte ' gevormd door de ultrasone golf! @pT(SonarRanger.tasknr).freq = SonarRanger.rate '8 SonarRanger.Delta = Olddistance - SonarRanger.Distance ' positive means coming closer to device Olddistance = SonarRanger.Distance ' we use SonarRanger.dv for integration... ' may contain bug: depends on SonarRanger.rate !!! SonarRanger.Speed = (SonarRanger.Speed * (SonarRanger.dv-1) / SonarRanger.dv) + (SonarRanger.Delta * @pT(SonarRanger.tasknr).freq /SonarRanger.dv) ' in cm/s - signed 'OldSpeed = SonarRanger.Speed IF SonarRanger.Distance < SonarRanger.Nearlimit THEN SonarRanger.Distance = SonarRanger.NearLimit ' we should reset the device, it may crash... IF SonarRanger.Distance > SonarRanger.Farlimit THEN SonarRanger.Distance = SonarRanger.Farlimit ' 14.04.2004 SonarRanger.normdist = (SonarRanger.Distance - SonarRanger.Nearlimit)/ SonarRanger.range ' 0-1, mormalization tog = %False ' Omzettingskonstante: ' = geluidssnelheid/2 ( afstand= v.t/2 in sonar) ' geluidssnelheid in cm/ms = 34 cm/ms = %VelSound END IF END IF END SUB ' ****************************************** ' * USBSONAR UPPORT SECTION * ' ****************************************** '20060106 - status: ' both pulse - and dopplermodus are basically working ' initialise with function USBSonar_Init_DLL(mode, tasknr, monitortasknr) (g_h.bas), which returns a pointer to the USBSonarDevice structure ' mode = %USB_SONAR_PULSEMODE or %USB_SONAR_DOPPLERMODE ' in dopplermode tasknris dummy and monitortaksnr is used as a flag: 0 = no monitor window, 1 = monitorwindow, as we're using a thread for that now (2006.03.02) ' " " you can switch on/off the monitoring simply by setting/clearing UsbSonar.montasknr ' then call Create_UsbSonar_Control (g_main) ' once the task is started you can read tout he following from the USBSonarDevice struct: ' for pulsemode: UsbSonar.dist - distance in some arbitrary unit ' USbSonar.amp - amplitude of signal - at first sight not very usefull, but worth testing further.. ' for dopplermode: USbSonar.speed - we rescaled the values we got from the usbsonar device logarithmically to rangd [-64, 64] - single precision ' UsbSonar.energy byte [0-127] in rest already > 100 ' UsbSonar.sps - samples taken per second - we put this here because it's dynamic, dependent on chosen OutputDownSampling.. ' note also that samples are NOT comming in in a steady tempo. ' this is the integrated value of what we actually get ' UsbSonar.acceleration - an experiment to track beginning and end of movement - at least in visuals it looks nice with a treshold of 2 ' influenced by sps! ' USbSonar.pbEnergy - pointer to buffer of last USbSonar.buufersize energy values (byte) ' USbSonar.pbSpeed - " " " " " " speed " (integer) ' UsbSonar.pbAccell - " " " " " " acceleration " (single) ' USbSonar.buffersize - bufferlength in samples. right now it's not allowed to change it after initialistation!! ' in dopplermode we have a monitor window that shows energy and speed buffers and points with clear acceleration ' TO DO: support for multiple devices, mixed doppler and pulsemode ' convert distance values in dist to m ' clean up thread code for doppler - dummywindow should disappear, monitorwindow should be toggeleable ' re-insert control window - creatusbsonarcontrol still needs a tasknr!!! FUNCTION USBSonar_Init_DLL(BYVAL MODE AS DWORD, BYVAL tasknr AS DWORD, OPT BYVAL monitortasknr AS DWORD) EXPORT AS DWORD 'initialises the USBSonar and returns pointer to the USBSonar structure 'mode = %USB_SONAR_PULSEMODE or %USB_SONAR_DOPPLERMODE 'IMPORTANT: make sure to call Create_UsbSonar_Control (g_main) from your app after calling this function but before starting the UsbSonar task! 'returns pointer to USbSonarDevice structuur 'we should add a param for nr devices to be used / COM portnrs in ini file?? - of uitproberen welke luisteren?.. '!!! for dopplermode we don;t use a task anymore, as this was allways resulting in unexlainable crashes. ' now data-aquisition is done in a separate thread, so the tasknr en monitortasknr here is dummy 'we gaan er nu van uit dat je bij het opstarten een mode kiest, en daar dan bij blijft - mssch dynamisch maken? ' STATIC be() AS BYTE ' STATIC bs() AS SINGLE ' STATIC ba() AS SINGLE LOCAL retval AS LONG LOCAL dummy AS LONG MSGBOX FUNCNAME$ UsbSonar.tasknr = tasknr USbSonar.MonTasknr = monitortasknr ' UsbSOnar.hsio = Open_Serial_IO (BYVAL 2, "USB_SONAR_V0") ' SLEEP 100 UsbSonar.mode = MODE ' warning FUNCNAME$ + " mode =" + STR$(mode) + STR$(%USB_SONAR_DOPPLERMODE) 'we prepare the buffers here, so it's safe to access them as soon as init function has been called 'we only buffer the data in dopplermode for now ' UsbSonar.buffersize = 256 ' REDIM be(USbSonar.buffersize - 1) ' REDIM bs(USbSonar.buffersize - 1) ' REDIM ba(UsbSonar.buffersize - 1) ' UsbSonar.pbEnergy = VARPTR(be(0)) ' USbSonar.pbSpeed = VARPTR(bs(0)) ' UsbSonar.pbAccell = VARPTR(ba(0)) SELECT CASE MODE CASE %USB_SONAR_PULSEMODE UsbSOnar.hsio = Open_Serial_IO (BYVAL 2, "USB_SONAR_V0") SLEEP 100 UsbSonar_SetPulseDefaultsettings @pT(UsbSonar.tasknr).naam = "US_Pulse" @pT(UsbSonar.tasknr).freq = 20 ' voor freq/2 pulsen/metingen per seconde.. @pT(UsbSonar.tasknr).cptr = CODEPTR(UsbSonar_PulseTask) @pT(UsbSonar.tasknr).flags = %DLL_TASK OR %PERTIM_TASK @pTEx(UsbSonar.tasknr).stopcptr = CODEPTR(UsbSonar_Cleanup) IF Monitortasknr THEN Warning "Monitoring in pulsemode not supported yet" CASE %USB_SONAR_DOPPLERMODE ' UsbSonar_SetDopplerDefaultSettings ' @pT(UsbSonar.tasknr).naam = "US_doppler" ' @pT(UsbSonar.tasknr).freq = 100 ' @pT(UsbSonar.tasknr).cptr = CODEPTR(UsbSonar_DopplerTask) ' @pT(UsbSonar.tasknr).flags = %DLL_TASK OR %PERTIM_TASK ' @pTEx(UsbSonar.tasknr).stopcptr = CODEPTR(UsbSonar_Cleanup) ' IF MonitorTasknr THEN ' @pT(Monitortasknr).naam = "US_P_Mon" ' @pT(MonitorTasknr).freq = 12 ' @pT(USbSonar.tasknr).flags = %DLL_TASK OR %PERTIM_TASK ' @pT(MonitorTasknr).cptr = CODEPTR(UsbSonar_MonitorTask) ' END IF THREAD CREATE USbSonar_DopplerThread(dummy) TO retval IF ISFALSE retval THEN warning "couldn't create USB-Sonar thread" END SELECT FUNCTION = VARPTR(UsbSonar) END FUNCTION SUB UsbSonar_PulseTask() STATIC PulseSent AS DWORD STATIC hwViz AS DWORD STATIC slnr AS DWORD LOCAL dwread AS DWORD LOCAL buf$, a$ LOCAL normarr() AS SINGLE LOCAL i AS INTEGER LOCAL mx AS BYTE, piek AS BYTE IF ISFALSE @pT(UsbSonar.tasknr).tog THEN @pT(UsbSonar.tasknr).tog = %true hwViz = MakeSpectrumWindow 'hoort hier niet thuis - laten het voorlopig staan om te debuggen END IF IF USbSonar.UpdTxdur AND (UsbSonar.TxDur <> UsbSonar.UpdTxDur) THEN UsbSonar.TxDur = UsbSonar.updTxdur USbSonar.UpdTXDur = 0 COMM SEND UsbSonar.hsio, CHR$(%TXCH_SetPulseTXDuration, UsbSonar.TxDur) END IF IF UsbSonar.updRxDur AND (UsbSonar.RxDur <> UsbSonar.updRXDur) THEN UsbSonar.RxDur = UsbSonar.updRXDur UsbSonar.updRXDur = 0 COMM SEND UsbSonar.hsio, CHR$(%TXCH_SetPulseRXDuration, UsbSonar.RxDur) END IF IF ISFALSE PulseSent THEN 'send new pulse COMM SEND UsbSonar.hsio, CHR$(&H80) 'send pulse PulseSent = 1 EXIT SUB ELSE 'receive pulse Pulsesent = 0 i = COMM(UsbSonar.hsio, RXQUE) COMM RECV UsbSonar.hsio, i, buf$ REDIM Normarr(i) 'normarr alleen voor visualisatie.. FOR i = 1 TO LEN(buf$) IF ASC(buf$, i) < UsbSonar.noise THEN ITERATE FOR IF (i>8) AND (ASC(buf$, i)> mx) THEN ' > 8: onbetrouwbaar en dichter dan toegelaten, dus dat negeren we hier mx = ASC(buf$, i) piek = i END IF Normarr(i) = ASC(buf$, i) / 256 - .5 NEXT IF mx > UsbSonar.noise THEN UsbSonar.dist = piek 'berekening naar meter nog te doen! UsbSonar.amp = 127 * (mx - UsbSonar.noise) / (256 - UsbSonar.noise) 'scalen naar[0-127]; noisefloor = 0 ELSE UsbSonar.dist = 0 UsbSonar.amp = 0 END IF ShowNormArray hwViz, Normarr() 'niet te verwarren met sonar display: toont een buffer waarin de piek(en) staan voor reflecternde voorwerpen 'hoe verder in de buffer, hoe groter de afstand.. END IF END SUB SUB UsbSonar_SetPulseDefaultSettings EXPORT USBSonar.RXDur = 52 'should be enough to measure some 3m far USBSonar.TXDur = 23 'a bit higher then recommended by Johannes, but works better for longer distances - penalty is a loss in precision USBSonar.noise = 120 COMM SEND UsbSonar.hsio, CHR$(%TXCH_SetPulseTXDuration, USBSonar.TXDur) COMM SEND UsbSonar.hsio, CHR$(%TXCH_SetPulseRXDuration, USBSonar.RXDur) END SUB SUB UsbSonar_Cleanup() 'close COM port ' logfile FUNCNAME$ ' UsbSonar_MonitorTask 1 'tell monitor task to kill its window IF UsbSonar.mode = %USB_SONAR_DOPPLERMODE THEN COMM SEND USbSonar.hsio, CHR$(%TXCH_DopplerStopCmd) END IF '!!!!! if we do call the Close_Serial_IO function here, we get a crash when we exit the program (also if that happens much later than the calling of this function ' according to the PB docs closing of the port will be handled by the compler afterwards.. ' 20060221 - this solved half of our exit crashes.. Close_Serial_IO (BYREF UsbSonar.hsio, "USB_SONAR_V0") IF ERR THEN MSGBOX "Error" + STR$(ERRCLEAR) + " happened while closing the USB sonar!",,FUNCNAME$ + "@g_h.bas" END IF @pT(UsbSonar.tasknr).tog = 0 UsbSonar.hsio = 0 'so it gets re-initialised.. ' logfile FUNCNAME$ + " done" 'we presume the device is on COM port 2 - we should make this confiurable later on END SUB FUNCTION GetUsbSonarPointer() EXPORT AS DWORD FUNCTION = VARPTR(UsbSonar) END FUNCTION THREAD FUNCTION USbSonar_DopplerThread(BYVAL dummy AS LONG) AS LONG 'alles (Behalve monitorwindow) gebeurt in de deze functie - van initialisatie tot einde - om mysterie crashes te vermijden 'lijkt nu goed te werken (@006.03.02) #REGISTER NONE LOCAL ccom$ LOCAL i AS INTEGER, j AS INTEGER LOCAL activewindows AS LONG LOCAL buf$, membuf$, b$ LOCAL nextAqTime AS DWORD LOCAL nextVisTime AS DWORD LOCAL hw AS LONG STATIC be() AS BYTE STATIC bs() AS SINGLE STATIC ba() AS SINGLE UsbSonar.buffersize = 256 REDIM be(USbSonar.buffersize - 1) REDIM bs(USbSonar.buffersize - 1) REDIM ba(UsbSonar.buffersize - 1) UsbSonar.pbEnergy = VARPTR(be(0)) USbSonar.pbSpeed = VARPTR(bs(0)) UsbSonar.pbAccell = VARPTR(ba(0)) '---------- initialise Sonar Device ERRCLEAR UsbSonar.hsio = FREEFILE ccom$ = "COM2" COMM OPEN ccom$ AS UsbSonar.hsio 'with #DEBUG ON we get an errormessage here.. IF ERR THEN Warning FUNCNAME$ +": err1" + STR$(ERRCLEAR): EXIT FUNCTION COMM SET UsbSonar.hsio, BAUD = 115200 'max is 256000 baud COMM SET UsbSonar.hsio, BYTE = 8 ' 8 bits COMM SET UsbSonar.hsio, PARITY = %FALSE ' No parity COMM SET UsbSonar.hsio, STOP = 0 ' 1 stop bit COMM SET UsbSonar.hsio, TXBUFFER = 64 ' transmit buffer COMM SET UsbSonar.hsio, RXBUFFER = 64 ' receive buffer ' Optional settings for flow control COMM SET UsbSonar.hsio, CTSFLOW = 0 ' Disable CTS COMM SET UsbSonar.hsio, RTSFLOW = 0 ' Disable RTS COMM SET UsbSonar.hsio, XINPFLOW = 0 ' Disable XON/OFF Input flow control COMM SET UsbSonar.hsio, XOUTFLOW = 0 ' Disable XON/XOFF Output flow control COMM SEND UsbSonar.hsio, CHR$(128) UsbSonar.Bias= 0 'might make sense to adapt this live UsbSonar.FilterCoef = 28 'was 8 UsbSonar.OutputDownSampling = 2 UsbSonar.PowerTresh = 56 UsbSonar.OutputFilterCoef = 28 COMM SEND UsbSonar.hsio, CHR$(%TXCH_SetBias, UsbSonar.Bias) COMM SEND UsbSonar.hsio, CHR$(%TXCH_SetFiltercoef, UsbSonar.FilterCoef) COMM SEND UsbSonar.hsio, CHR$(%TXCH_SetOutputDownSampling, UsbSonar.OutputDownSampling) COMM SEND USbSonar.hsio, CHR$(%TXCH_SetPowerThresh, UsbSonar.PowerTresh) COMM SEND UsbSonar.hsio, CHR$(%TXCH_SetOutputFilterCoef, UsbSonar.OutputFilterCoef) SLEEP 200 'this one's crucial!! COMM SEND UsbSonar.hsio, CHR$(%TXCH_DopplerStartCmd) SLEEP 200 'this one's crucial!! 'purge first buffer i = COMM(UsbSonar.hsio, RXQUE) IF i THEN COMM RECV UsbSonar.hsio, i, buf$ END IF ' msgbox "enter loop" '---------- main loop DO IF NextAqTime < TimeGetTime THEN NextAqTime = TimeGetTime + 10 '= equivalent to task freq 100 in GMT... i = COMM(UsbSonar.hsio, RXQUE) CONTROL SET TEXT hw, 3, STR$(i) + STR$(timegettime) IF i THEN COMM RECV UsbSonar.hsio, i, buf$ IF LEN(membuf$) THEN 'partial buffer last time - add the two now buf$ = membuf$ + buf$ membuf$ = "" END IF ReadNextChunk: 'first find %RXH_DopplerData FOR i = 1 TO LEN(buf$) IF ASC(buf$, i) <> %RXCH_DopplerData THEN ITERATE FOR ELSE EXIT FOR END IF NEXT IF i = LEN(buf$) THEN EndOfLoop IF (LEN(buf$) - i) < 4 THEN 'partial buffer membuf$ = MID$(buf$, i) GOTO EndOfLoop END IF UsbSonar.energy = ASC(buf$, i + 1) TRACE PRINT "E" + STR$(USbSonar.Energy) '!!MSB = SIGNED char, LSB = unsigned char b$ = MID$(buf$, i+3, 1) + MID$(buf$, i + 2, 1) POKE$ VARPTR(j), PEEK$(STRPTR(b$), 2) UsbSonar.speed = SGN(j) * SQR(ABS(j)) UsbSonar.accelleration = bs(i) - bs(i-1) 'would it make sense to buffer this one? TRACE PRINT "S" + STR$(USbSonar.Speed) ARRAY DELETE bs(), UsbSonar.Speed 'dus achteraan in buffer = recentste! ARRAY DELETE be(), UsbSonar.energy ARRAY DELETE ba(), UsbSonar.accelleration buf$ = MID$(buf$, i + 4) IF LEN(buf$) > 3 THEN GOTO readNextChunk ELSE membuf$ = buf$ END IF END IF END IF IF NextVisTime < TimeGetTime THEN NextVisTime = TimeGetTime + 42 IF USbSonar.MonTasknr THEN 'deze is / zou moeten toggelbaar UsbSonar_Threaded_Monitor ELSEIF UsbSonar.hwMon THEN USbSonar_Threaded_Monitor 1 'cleanup falg END IF END IF EndOfLoop: SLEEP 10 LOOP '---------- clean up COMM SEND USbSonar.hsio, CHR$(%TXCH_DopplerStopCmd) IF COMM(UsbSonar.hsio, RXQUE) THEN COMM RECV UsbSonar.hsio, COMM(UsbSonar.hsio, RXQUE), buf$ END FUNCTION SUB UsbSonar_Threaded_Monitor (OPT BYVAL endit AS DWORD) 'heel vreemde bug:" 'als we in de loop waar we be / bs tekenen logfile str$(bs(i)) gebruiken, krijgen we als waarde 922.337203685478 of 92.2337203685478 ' bij logfile "i:" + STR$(i) + " - value:" + STR$(be(i)) krijgen we deze waarden voor i; en voorbe(i) krijgen we wat er plausibele waarden uitzien STATIC init AS DWORD ' STATIC hw AS DWORD LOCAL i AS LONG LOCAL s AS SINGLE IF ISFALSE UsbSonar.hwMon THEN IF ISFALSE USbSOnar.pbAccell THEN MSGBOX "not ready!" EXIT SUB END IF init = 1 DIM be(UsbSonar.Buffersize -1) AS STATIC BYTE AT UsbSonar.pbEnergy DIM bs(UsbSonar.Buffersize -1) AS STATIC SINGLE AT UsbSonar.pbSpeed DIM ba(UsbSonar.Buffersize -1) AS STATIC SINGLE AT UsbSonar.pbAccell GRAPHIC WINDOW "UsbSonar Doppler -" + STR$(UsbSonar.buffersize) + " samples", 1, 1, 300, 250 TO USbSonar.hwMon GRAPHIC ATTACH USbSonar.hwMon, 0, REDRAW GRAPHIC SCALE (0, 255) - (UsbSonar.buffersize, -255) GRAPHIC WIDTH 0 GRAPHIC STYLE 0 GRAPHIC REDRAW EXIT SUB END IF IF endit THEN IF (USbSonar.hwMon > 0) THEN GRAPHIC ATTACH USbSonar.hwMon, 0, REDRAW GRAPHIC WINDOW END UsbSonar.hwMon = 0 END IF EXIT SUB END IF '!!!!!! apparently graphic attach has to be called every time !!! ' otherwise, not only it fails to redraw the window, but it seems to corrupt certain variables ' if we do the following without graphic attach: ' FOR i = 0 TO USbSonar.Buffersize - 1 ' logfile "i:" + STR$(i) + " - value:" + STR$(be(i)) ' GRAPHIC SET PIXEL (i, be(i)), 0 ' NEXT ' then i (wich is declared as long) becomes 922.337! GRAPHIC ATTACH USbSonar.hwMon, 0, REDRAW GRAPHIC CLEAR &H0111111 'grijs raster GRAPHIC COLOR &H0666666, &H0 FOR i = -250 TO 255 STEP 50 GRAPHIC LINE (0, i) - (UsbSonar.buffersize - 1, i) NEXT FOR i = 0 TO UsbSonar.buffersize - 1 STEP 50 GRAPHIC LINE(i, -255) - (i, 255) NEXT '------- energy in pink GRAPHIC COLOR &H0FF99FF, 0 GRAPHIC FONT "Lucida Console", 7, 0 GRAPHIC SET POS (0, -230) GRAPHIC PRINT "Energy [0, 127]" FOR i = 0 TO UBOUND(be) GRAPHIC SET PIXEL (i, be(i)) ', 0 NEXT '------- acceleration in yelloz GRAPHIC COLOR &H066FFFF GRAPHIC SET POS (170, -230) GRAPHIC PRINT "accell [-127, 127]" FOR i = 0 TO UBOUND(ba) GRAPHIC LINE (i, ba(i)) - (i, 0) NEXT '----- speed in green GRAPHIC COLOR &H066ffcc GRAPHIC SET POS (85, -230) GRAPHIC PRINT "Speed [-64 - 64]" FOR i = 0 TO UBOUND(bs) GRAPHIC SET PIXEL (i, bs(i)) ', 0 NEXT GRAPHIC REDRAW END SUB SUB g_h_dummy () EXPORT MSGBOX "dummy@g_h",,FUNCNAME$ END SUB FUNCTION ii2000_EveryNCallback CDECL (BYVAL taskHandle AS LONG, BYVAL everyNsamplesEventType AS LONG, BYVAL nSamples AS LONG, BYVAL pCallBackData AS DWORD PTR) AS LONG 'this function gets called every 8 samples and should read the data '07.06.2009: this is working! '04.07.2009: now trying to run at 128S/s , thus our time buffer is only 2 seconds now. #IF %DEF(%g_NIDAQmx) LOCAL ret AS LONG LOCAL errBuff AS ASCIIZ * 2048 LOCAL i AS LONG DIM value(31) AS STATIC DOUBLE 'data buffer - float's ret = DAQmxReadAnalogF64(taskHandle,1,0.01,%DAQmx_Val_GroupByScanNumber,VARPTR(value(0)),UBOUND(value),nSamples,BYVAL %NULL) 'nr of samples 'array size = at least nrsamples * nrchans ' so if we understand X-tofs remarks well, nr. of samples should be 1 here, meaning 1 for each channel, ' and not 8 as we first had it. (gwr 04.07.2009) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) 'MSGBOX "6.err: " + TRIM$(errbuff) warning TRIM$(errbuff) ELSE ' transfer and process the data into the sonar data arrays. ' value() ranges here from 0 to 5.000 ' note that dbx(255) always has the most recent data sample!!! ARRAY DELETE db0(), MAX(0,value(0) *819) ' back conversion to 12 bit resolution 0-4096 ARRAY DELETE db1(), MAX(0,value(1) *819) ' for 0-4096, it should be *819.2, but we risk overflow ARRAY DELETE db2(), MAX(0,value(2) *819) ' 5 x 819 = 4095 ARRAY DELETE db3(), MAX(0,value(3) *819) ARRAY DELETE db4(), MIN(MAX(0,value(4) *819),4095) ' this channels overflows and blocks... ARRAY DELETE db5(), MIN(MAX(0,value(5) *819),4095) ' this one also ARRAY DELETE db6(), MIN(MAX(0,value(6) *819),4095) ARRAY DELETE db7(), MIN(MAX(0,value(7) *819),4095) Sonar_ii_Math ' this is common and compatible with the %Nidaq code. for ii_2000 END IF #ENDIF END FUNCTION FUNCTION Quadrada_EveryNCallback CDECL (BYVAL taskHandle AS LONG, BYVAL everyNsamplesEventType AS LONG, BYVAL nSamples AS LONG, BYVAL pCallBackData AS DWORD PTR) AS LONG 'this function gets called every 8 samples and should read the data '07.06.2009: tested ' note that we here have bipolar values!!! #IF %DEF(%g_NIDAQmx) LOCAL ret AS LONG LOCAL errBuff AS ASCIIZ * 2048 LOCAL i AS LONG DIM value(31) AS STATIC DOUBLE 'data buffer ret = DAQmxReadAnalogF64(taskHandle,1,0.01,%DAQmx_Val_GroupByScanNumber,VARPTR(value(0)),UBOUND(value),nSamples,BYVAL %NULL) 'nr of samples 'array size = at least nrsamples * nrchans ' 1 sample for eacht channel. IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) warning TRIM$(errbuff) ' if the acquisition stops here, we have to set @pDAQparams.daqstopped = %True ' this is to be checked. ELSE ' transfer and process the data into the radar data arrays. ' the values here are -5V to +5V ARRAY DELETE db0(), MAX(-2048,value(0) *409.6) ' back conversion to 12 bit resolution -2048 to + 2047 ipv 0-4096 ARRAY DELETE db1(), MAX(-2048,value(1) *409.6) ARRAY DELETE db2(), MAX(-2048,value(2) *409.6) ARRAY DELETE db3(), MAX(-2048,value(3) *409.6) ARRAY DELETE db4(), MAX(-2048,value(4) *409.6) ARRAY DELETE db5(), MAX(-2048,value(5) *409.6) ARRAY DELETE db6(), MAX(-2048,value(6) *409.6) ARRAY DELETE db7(), MAX(-2048,value(7) *409.6) Quadrada_ii_Math ' this is common and compatible with the %Nidaq code. for Quadrada hardware END IF #ENDIF END FUNCTION FUNCTION NiDAQmx_DoneCallback CDECL (BYVAL taskhandle AS LONG,BYVAL stat AS LONG, BYVAL pCallBackData AS DWORD PTR) AS LONG ' this procedure can be common to all our NiDAQmx applications, sonar as well as radar. ' the procedure needs not to be exported. It's only used as an internal callback. ' 07.06.2009: checked gwr. ' note we can also use @pDAQparameters.taskhandle instead of passing the variable.??? ' probably we cannot, because in would contradict the prototype of the function call. ' 29.09.2009 separate versionmade fror 24ghz radar #IF %DEF(%g_NIDAQmx) 'this function is called when an error occurs which forces the DAQ to stop 'works (checked door de usb kabel uit te trekken tijdens het werken - wordt proper afgehandeld..) LOCAL errBuff AS ASCIIZ * 2048 LOCAL ret AS LONG 'this function gets called when something's wrong and the DAQ stops.. 'Warning "DAQ stopped" '03.08.2009 examinating crashes and errors.. the crash is an acces violation. also when we don't crash, pb reports an '"illegal function call" error when we switch the doppler off or on again after switching off (thus not the very first time..) DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) Warning TRIM$(errbuff) ret = DAQmxClearTask(BYVAL @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) Warning TRIM$(errbuff) END IF Warning "data acquisition stopped from NiDAQmx callback" @pDAQparams.daqstopped = %True ' added 08.06.2009 @pDAQparams.taskhandle = %False @pDAQparams.taskname = NUL$(10) #ENDIF END FUNCTION FUNCTION Doppler_DAQ (BYVAL param AS LONG) EXPORT AS LONG ' this procedure starts/stops the data-acquisition for the doppler ' channels 8,9,10 on the ii-2000 board. ' only supported for NiDAQmx. ' 10.06.2009: first redaction. ' 05.07.2009: debug session. ' 07.07.2009: changed to -10V --- + 10V range ' TRACE NEW "doppler_Daq_trace" 'for debug.. ' TRACE ON ' TRACE PRINT FUNCNAME$ + STR$(param) board = %ii_2000 ' exit function ' warning FUNCNAME$ LOCAL i AS INTEGER ' MSGBOX FUNCNAME$ + STR$(param) #IF %DEF(%g_NiDAQmx) LOCAL ret AS LONG LOCAL errBuff AS ASCIIZ * 2048 LOCAL cpcb AS DWORD LOCAL device AS ASCIIZ * 10 LOCAL physicalchannels AS ASCIIZ * 40 LOCAL nametoassigntochannels AS ASCIIZ * 40 STATIC EveryN AS LONG ' MSGBOX "predim" REDIM PRESERVE physicalChannel(0 TO 15) AS STATIC ASCIIZ * 40 'was dim, but gets repeated on every call.. REDIM PRESERVE nameToAssignToChannel (0 TO 15) AS ASCIIZ * 40 ' REDIM PRESERVE nametoassigntolines (0 TO 15) AS STATIC ASCIIZ * 40 ' MSGBOX "postdim" LOCAL customscalename AS ASCIIZ * 40 ' warning "check:" + STR$(param) SELECT CASE param CASE -1 FUNCTION = @pDAQparams.mode CASE 0 ' MSGBOX "pre gosub.." ' exit function 'experiment -and even then we get a crash GOSUB StopDopplerDaq 'is this one the culprit? ' @pDAQparams.mode = %DAQ_NI CASE %DAQ_DOUBLEBUFFER warning "prepare double buffer.." IF ISFALSE @pDAQparams.daqstopped THEN ' MSGBOX "pre gosub 2" GOSUB StopDopplerDAQ END IF @pDAQparams.channel = %DAQ_RADAR @pDAQparams.mode = %DAQ_NI OR %DAQ_DOUBLEBUFFER @pDAQparams.inputconfig = 1 ' single ended ground referenced. @pDAQparams.rate = %False FOR i = 8 TO 10 @pDAQparams.samplingrate(i) = 1024 @pDAQparams.ChannelVector(i) = i @pDAQparams.polarity(i) = 0 '0= bipolar , 1= unipolar @pDAQparams.voltagerange(i) = 20 '10= set to -5 to +5V @pDAQparams.GainVector(i) = 1 @pDAQparams.rate = @pDAQparams.rate + @pDAQparams.samplingrate(i) ' sum of samplingrates. ' this to allow checks with the capabilities of the device. NEXT i @pDAQparams.taskname = "Doppler-ii2000" ' can be anything you like ret = DAQmxCreateTask(@pDAQparams.taskname, @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) warning "Create Doppler DAQ task error " & TRIM$(errbuff) END IF device = NiMxDevs(@pDAQparams.id) '.id is hier 1 of 2 nu. physicalchannels = TRIM$(device) + "/ai8:10" warning TRIM$(physicalchannels) nametoassigntochannels = "Ai8, Ai9, Ai10" ret = DAQmxCreateAIVoltageChan(BYVAL @pDAQparams.taskhandle, physicalChannels$,nameToAssignToChannels$,%DAQmx_Val_RSE,-10.0,10.0,%DAQmx_Val_Volts ,customscalename) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) warning "error creating channels: " + TRIM$(errBuff) 'ok END IF ' warning "channels ok" 'ok.. ret = DaqmxCfgSampClkTiming(BYVAL @pDAQparams.taskhandle,"OnboardClock",1024,%DAQmx_val_Rising,%DAQmx_Val_ContSamps,1) ' we sample 3 channels. ' note: last param means nothing when using %DAQmx_Val_ContSamps IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "Clock error:" & TRIM$(errBuff) ELSE 'logfile "DaqmxCfgSampClkTiming passed with 1024S/s" END IF ' íf we don't call the following, the default is used 'reming this function made the Attempted to read samples that are no longer available. ' ' ' -buffer ' ret = DAQmxCfgInputBuffer(BYVAL @pDAQparams.taskhandle,240) 'use a sample DMA buffer ' IF ret THEN ' DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) ' logfile "Inputbuffer error:" & TRIM$(errBuff) ' END IF '-------- cpcb = CODEPTR(Doppler_EveryNCallback) ' 12 samples each time gives us 1 cs resolution ' 4 samples for each channel ' should create a transfer of 3 x 4 samples each time. ' !!!! this is too fast for xi - change to 32 sample pc or more and adapt callback ret = DAQmxRegisterEveryNSamplesEvent(BYVAL @pDAQparams.taskhandle,%DAQmx_Val_Acquired_Into_Buffer,4,0,BYVAL cpcb, BYVAL %NULL) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "DAQmxRegisterEveryNSamplesEvent error:" + TRIM$(errBuff) 'ELSE 'logfile "DAQmxRegisterEveryNSamplesEvent passed with N = 4" END IF cpcb = CODEPTR(NiDAQmx_DoneCallback) ret = DAQmxRegisterDoneEvent(@pDAQparams.taskhandle,0,cpcb,BYVAL %NULL) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "DAQmxRegisterDoneEvent error:" & TRIM$(errBuff) 'ELSE ' logfile "DAQmxRegisterDoneEvent passed with cptr =" & STR$(cpcb) END IF ' warning "start doppler task" ' logfile "Start doppler task" TRACE PRINT "start doppler dask.. - last error was" + STR$(ERRCLEAR) ret = DAQmxStartTask(BYVAL @pDAQparams.taskhandle) '->the crash really seems to be caused by this, although we still get the retval 0 just before it really happens 'note: the callback gets called a couple of times (allways 4 timmes?) in between this function call and the actual crash.. 'when compiling with debug error on, sometimes we get error logfile "ret:" + STR$(ret) ' MSGBOX "ret:" + STR$(ret) 'when crashing sometimes this is the last msgbox we get, sometimes we get to "start done" IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "DAQmxStartTask error: " & TRIM$(errBuff) END IF ' logfile "Start done" ' warning "start done" 'Logfile "doppler aquisition started.." @pDAQparams.daqstopped = %False FUNCTION = %DAQ_DOUBLEBUFFER '%True CASE ELSE MSGBOX "Illegal mode",, FUNCNAME$ END SELECT EXIT FUNCTION ' essential!!! StopDopplerDAQ: IF @pDAQparams.taskhandle THEN TRACE PRINT "handle did exist.." ' MSGBOX "1" ret = DAQmxStopTask(BYVAL @pDAQparams.taskHandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) Logfile TRIM$(errbuff) END IF ' MSGBOX "2" ret = DAQmxClearTask(BYVAL @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) Logfile TRIM$(errbuff) END IF END IF @pDAQparams.daqstopped = %True @pDAQparams.taskhandle = %False @pDAQparams.taskname = NUL$(20) TRACE PRINT "now return..." ' MSGBOX "return from gosub" 'sometimes we return here without any gosub!!! RETURN #ENDIF END FUNCTION FUNCTION Doppler_EveryNCallback CDECL (BYVAL taskHandle AS LONG, BYVAL everyNsamplesEventType AS LONG, BYVAL nSamples AS LONG, BYVAL pCallBackData AS DWORD PTR) AS LONG ' callback handler for data acquisition with the ii_2000 board on the Doppler channels. ' this function gets called every 12 samples and reads the acquired data. 256 times a second ' the latency is 3.9ms. ' note that we here have bipolar values!!! ' 11.06.2009: after adjusting the buffer-size this works very well on \\No ' 13.06.2009: We cannot do the DFT from within the callback, it's too many fps for the processor ' however we could easily create different time-scale buffers ' 0.25 sec = fast buffer = 256 samples (= sampling rate 1024 S/s) ' 1 sec = medium buffer = 256 samples (converted sampling rate 256 S/s) ' 4 sec = slow buffer = 256 samples (converted sampling rate 64 S/s) ' 14.06.2009: this function runs at 256 times a second. ' problem with dc offset and extremely low frequency components... ' 07.07.2009: Voltage range changed to -10V to +10V (20V range) ' Note that we use the full 16 bit resolution of the NiUSB device here. ' 08.07.2009: High pass filter for DC removal added. ' 09.07.2009: acceleration data added. ' 12.07.2009: accelleration calculus improved. ' 08.04.2010: amplitude scaling changed a factor 5 LOCAL i AS LONG STATIC cnt AS DWORD #IF %DEF(%g_NIDAQmx) LOCAL ret AS LONG LOCAL errBuff AS ASCIIZ * 2048 LOCAL newval AS DOUBLE REDIM value(95) AS STATIC DOUBLE 'data buffer 'was 47 - does it take longer before we crash now? to be tested after medieaval rehearsal.. STATIC xslow, yslow, zslow AS DOUBLE STATIC xdc, ydc, zdc AS DOUBLE ' for dc offset removal. ' STATIC oxf, oyf, ozf AS SINGLE 'ret = DAQmxReadAnalogF64(taskHandle,12,0.1,%DAQmx_Val_GroupByScanNumber,VARPTR(value(0)),UBOUND(value),nSamples,BYVAL %NULL) 'nr of samples 'array size = at least nrsamples * nrchans '0.012 note: 'time out = 12 x (1/1024) seconds ' nr of samples per channel=4 ret = DAQmxReadAnalogF64(taskHandle,4,0.012,%DAQmx_Val_GroupByScanNumber,VARPTR(value(0)),UBOUND(value),nSamples,BYVAL %NULL) '-1: as much as available - used to be 4 IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "DaqmxReadAnalogF64 error: " & TRIM$(errbuff) warning "DaqmxReadAnalogF64 error: " & TRIM$(errbuff) ' warning TRIM$(errbuff) ' if the acquisition stops here, we have to set @pDAQparams.daqstopped = %True ' this is to be checked. ELSE ' transfer and process the data into the sonar data arrays. ' with DC offset removal: (high pass filter) ' changed to -10 = +10 Volt range 07.07.2009 'Xdc = ((Xdc * 1275) + Value(0))/ 1280 ' 1275 = 255 * 5, 1280 = 256 * 5 ' for 20V range this becomes: 'Xdc = ((Xdc * 2550) + Value(0)) / 2560 ' 2550 = 255 * 10, 2560 = 256 * 10 ' this makes a high pass filter (differenciator) ' if we are right, the cut off is around 4Hz now. (to be checked) ' a version using a variable LPF parameter would be: ' Xdc = (Xdc * Doppler.hpf) / (Doppler.hpf + 1) ' ARRAY DELETE dbx(), (value(0) - Xdc)/ 10 ' 5V version: ARRAY DELETE dbx(), (value(0) /5) - Xdc 'dbx(255) = always newest data, dbx(0)= oldest data sample ' ARRAY DELETE dbx(), (value(0) /10) - Xdc 'dbx(255) = always newest data, dbx(0)= oldest data sample ' Ydc = ((Ydc * 2550) + Value(1))/ 2560 ' ARRAY DELETE dby(), (value(1) /10) - Ydc ' Zdc = ((Zdc * 2550) + Value(2))/ 2560 ' ARRAY DELETE dbz(), (value(2) /10) - Zdc ' Xdc = ((Xdc * 2550) + Value(3))/ 2560 ' ARRAY DELETE dbx(), (value(3) /10) - Xdc ' Ydc = ((Ydc * 2550) + Value(4))/ 2560 ' ARRAY DELETE dby(), (value(4) /10) - Ydc ' Zdc = ((Zdc * 2550) + Value(5))/ 2560 ' ARRAY DELETE dbz(), (value(5) /10) - Zdc ' ' Xdc = ((Xdc * 2550) + Value(6))/ 2560 ' ARRAY DELETE dbx(), (value(6) /10) - Xdc ' Ydc = ((Ydc * 2550) + Value(7))/ 2560 ' ARRAY DELETE dby(), (value(7) /10) - Ydc ' Zdc = ((Zdc * 2550) + Value(8))/ 2560 ' ARRAY DELETE dbz(), (value(8) /10) - Zdc ' ' Xdc = ((Xdc * 2550) + Value(9))/ 2560 ' ARRAY DELETE dbx(), (value(9) /10) - Xdc ' so here we should write the most recent data sampled. ' Ydc = ((Ydc * 2550) + Value(10))/ 2560 ' ARRAY DELETE dby(), (value(10)/10) - Ydc ' Zdc = ((Zdc * 2550) + Value(11))/ 2560 ' ARRAY DELETE dbz(), (value(11)/10) - Zdc ' version with parametric control over the differenciator for DC removal: [08.07.2009] gwr ' note: doppler.hpf should never be zero, since that erases any signal... ' the hpf range is now quadratic from 1 to 128^2 ' up to 07.04.2010 we divided by 10 here, to rescale the voltages to 0-1V since the ADC returns -10V to +10V 'thus we could never have an overflow. However the signal with the ii2010 omni transducers seems not to exceed -2 to +2V 'hence we changed the division here to /2 instead of the former /10 'now there is a risk for overflow! 'hence we added the limiter with the MIN function. (gwr) IF Doppler.hpf THEN i = Doppler.hpf + 1 Xdc = ((Xdc * Doppler.hpf) + Value(0)) / i '(Doppler.hpf + 1) ARRAY DELETE dbx(), MIN((value(0) - Xdc)/2,1) 'dbx(255) = always newest data, dbx(0)= oldest data sample Ydc = ((Ydc * Doppler.hpf) + Value(1)) / i '(Doppler.hpf + 1) ARRAY DELETE dby(), MIN((value(1) - Ydc)/2,1) Zdc = ((Zdc * Doppler.hpf) + Value(2)) / i '(Doppler.hpf + 1) ARRAY DELETE dbz(),MIN((value(2) - Zdc)/2,1) Xdc = ((Xdc * Doppler.hpf) + Value(3)) / i '(Doppler.hpf + 1) ARRAY DELETE dbx(), MIN((value(3) - Xdc)/2,1) Ydc = ((Ydc * Doppler.hpf) + Value(4)) / i '(Doppler.hpf + 1) ARRAY DELETE dby(), MIN((value(4) - Ydc)/2,1) Zdc = ((Zdc * Doppler.hpf) + Value(5)) / i '(Doppler.hpf + 1) ARRAY DELETE dbz(), MIN((value(5) - Zdc)/2,1) Xdc = ((Xdc * Doppler.hpf) + Value(6)) / i '(Doppler.hpf + 1) ARRAY DELETE dbx(), MIN((value(6) - Xdc)/2,1) Ydc = ((Ydc * Doppler.hpf) + Value(7)) / i '(Doppler.hpf + 1) ARRAY DELETE dby(), MIN((value(7) - Ydc)/2,1) Zdc = ((Zdc * Doppler.hpf) + Value(8)) / i '(Doppler.hpf + 1) ARRAY DELETE dbz(), MIN((value(8) - Zdc)/2,1) Xdc = ((Xdc * Doppler.hpf) + Value(9)) / i '(Doppler.hpf + 1) ARRAY DELETE dbx(), MIN((value(9) - Xdc)/2,1) Ydc = ((Ydc * Doppler.hpf) + Value(10)) / i '(Doppler.hpf + 1) ARRAY DELETE dby(), MIN((value(10) - Ydc)/2,1) Zdc = ((Zdc * Doppler.hpf) + Value(11)) / i '(Doppler.hpf + 1) ARRAY DELETE dbz(), MIN((value(11) - Zdc)/2,1) ELSE ' no data processing with filter, limiter added 08.04.2010 gwr ARRAY DELETE dbx(),MIN(value(0)/2,1) ARRAY DELETE dby(),MIN(value(1)/2,1) ARRAY DELETE dbz(),MIN(value(2)/2,1) ARRAY DELETE dbx(),MIN(value(3)/2,1) ARRAY DELETE dby(),MIN(value(4)/2,1) ARRAY DELETE dbz(),MIN(value(5)/2,1) ARRAY DELETE dbx(),MIN(value(6)/2,1) ARRAY DELETE dby(),MIN(value(7)/2,1) ARRAY DELETE dbz(),MIN(value(8)/2,1) ARRAY DELETE dbx(),MIN(value(9)/2,1) ARRAY DELETE dby(),MIN(value(10)/2,1) ARRAY DELETE dbz(),MIN(value(11)/2,1) END IF ' since the samples flow in at a rate of 4 per channel at a time ' nr samples in the function above is samples *per channel*, ' so we get 4 new samples on each of the 3 channels ' the timing latency is 4.096ms. ' downsampling to medium 1 second buffer: [ sampling rate becomes 256 S/s) ' newval = dbxm(255) ' FOR i = 252 TO 255 ' newval = (newval + dbx(i)) /2 ' NEXT i ' ARRAY DELETE dbxm(), newval ' ' better (faster code),doing exactly the same thing: newval = (dbxm(255)/16) + (dbx(252)/16) + (dbx(253)/8) + (dbx(254)/4) + (dbx(255)/2) ' sum always = 1 ARRAY DELETE dbxm(), newval newval = dbym(255)/16 + dby(252)/16 + dby(253)/8 + dby(254)/4 + dby(255)/2 ARRAY DELETE dbym(), newval newval = dbzm(255)/16 + dbz(252)/16 + dbz(253)/8 + dbz(254)/4 + dbz(255)/2 ARRAY DELETE dbzm(), newval ' downsampling to slow 4 second buffer: { sampling rate becomes 64 S/s) xslow = (xslow + dbxm(255))/2 ' running integrator or simple FIR filter yslow = (yslow + dbym(255))/2 zslow = (zslow + dbzm(255))/2 IF ISFALSE (cnt MOD 4) THEN ARRAY DELETE dbxs(), xslow ARRAY DELETE dbys(), yslow ARRAY DELETE dbzs(), zslow END IF INCR cnt ' if isfalse (cnt mod 100) then '50 = 20 x per sekonde ' Doppler_ii_Math ' takes still way too long to perform from within the callback... ' end if ' surface calculations: [this works from within the callback] ' rectified sigma function: [ FIR-filter ] ' surfx = ((surfx * dta) + abs(dbx(0))) / (dta+1) ' dta = integratiediepte (0 tot 255) ' normalized in the range 0-1 Doppler.xa = ((Doppler.xa * Doppler.dta) + ABS(dbx(255))) / (Doppler.dta +1) 'sampling rate remains 1024S/s but is lowpassed and rectified Doppler.ya = ((Doppler.ya * Doppler.dta) + ABS(dby(255))) / (Doppler.dta +1) Doppler.za = ((Doppler.za * Doppler.dta) + ABS(dbz(255))) / (Doppler.dta +1) ' speed calculations, using zero-cross calculation: (proc. in g_indep) ' noise level should become a function of .xa, ya. za ' the noise parameter is now expressed in fraction of normalized full scale, hence 1E-3 is 60dB or 1/1000 ' Since we count on every call (256 times a second) the entire buffer, the maximum ' difference between succesive values can never be larger than 4. (on each refresh, we are getting 4 new ' samples in dbx(). IF Doppler.xa > doppler.noise THEN Doppler.xf = WaveFreq_Dbl (dbx(), 1024, Doppler.noise)' 1E-3) '4 * 2.44E-4) ' new function in g_indep ' the values are expressed in Hz ' the theoretical absolute maximum value would be 512Hz(corresponding to movement speed of 5m/s) ' the gate-time is 0.256 Sec. ' as for now, no integration is performed. ELSE 'Doppler.xf = %False ' we could also write Doppler.xf = Doppler.xf / 2 for a fast decay to zero. Doppler.xf = Doppler.xf / 2 END IF IF Doppler.ya > doppler.noise THEN Doppler.yf = WaveFreq_Dbl (dby(), 1024, Doppler.noise) '1E-3) '4 * 2.44E-4) ' noise = 1/4096 = 12 bit ELSE Doppler.yf = Doppler.yf / 2 END IF IF Doppler.za > doppler.noise THEN Doppler.zf = WaveFreq_Dbl (dbz(), 1024, Doppler.noise) '1E-3) '4 * 2.44E-4) ' * 4 = 10 bits resolution ELSE Doppler.zf = Doppler.zf/2 END IF ' accelleration calculation: ' theory: if we take the maximum accelleration for body movement as 100m/s2, we need to ' measure accelleration with a time interval of 50ms. Since one sample in our buffer ' corresponds to 0.976ms, this corresponds to 51 samples. ' However, if we want to optimize for speed of response -at the detriment of resolution- ' we should take the timeinterval as 1cs = 10ms and thus 10 samples. ' hence: ' following are part of the structure, and thus global ' DIM xfbuf(0 to 63) as global single ' we take 63, to give us some margin ' DIM yfbuf(0 to 63) as global single ' done on init. ' DIM zfbuf(0 to 63) as global single ' Doppler.pxfbuf = varptr(xfbuf(0)) ' done on dll-init ' Doppler.pyfbuf = varptr(yfbuf(0)) ' Doppler.pzfbuf = varptr(zfbuf(0)) i = 63 - Doppler.dtacc ' range for dtacc: 1 to 63. Crash if exceeded. ARRAY DELETE xfbuf(), Doppler.xf ARRAY DELETE yfbuf(), Doppler.yf ARRAY DELETE zfbuf(), Doppler.zf ' waarbij de maat van de buffer de dt bepaalt. Doppler.xac = (Doppler.xf - xfbuf(i)) / Doppler.dtacc ' 12 = 63 - 51, voor 10 samp: 53 = 63 - 10 Doppler.yac = (Doppler.yf - yfbuf(i)) / Doppler.dtacc Doppler.zac = (Doppler.zf - zfbuf(i)) / Doppler.dtacc ' de resolutie neemt toe met .dtacc, maar de scaling blijft konstant. ' zonder de deling door dtacc hadden we: ' dtacc = 1 : X= -22/+8 Y= -8/+8 z= -8/+8 ' dtacc = 2 : X= -16/+20 Y= -16/+24 z= -20/+24 ' dtacc = 4 : X= -72/+72 y= -52/+64 z= -64/+52 ' dtacc = 6 : x= -72/+104 Y= -84/+88 Z= -76/+72 ' dtacc =10 : X= -48/+175 Y=-112/+124 Z= -168/+144 ' met de deling en na debug..., krijgen we nu: ' X= -9/+8 Y=-8/+24 Z=-8/+8 ' onafhankelijk van de setting voor dtacc. ' de resolutie neemt evenredig toe met dtacc natuurlijk END IF #ENDIF END FUNCTION SUB Doppler_ii_Math () STATIC tog AS LONG ' to be tested. This requires a very fast processor!!! ' DFT math on the buffer such as to return spectral data and power. ' if the processor load is too heavy, we can make this a task instead of running from the callback ' for reasonable tempo resolution we need 4 second buffers ' test-bed now in Faust- Tango code (4.07.09) IF ISFALSE tog THEN DIM hanx(0 TO 4095) AS STATIC DOUBLE DIM hany(0 TO 4095) AS STATIC DOUBLE DIM hanz(0 TO 4095) AS STATIC DOUBLE ' following moved to init dll: ' DIM Spx(0 TO 4095) AS GLOBAL DOUBLE ' calculated spectrum, bands in 0.25Hz increments, 0-2047 ' DIM Spy(0 TO 4095) AS GLOBAL DOUBLE ' DIM Spz(0 TO 4095) AS GLOBAL DOUBLE ' DIM Han(0 TO 4095) AS STATIC DOUBLE ' MAT Han() = CON ' HanningWindow_dbl Han() tog = %True END IF ' first we could apply a hanning window to the array, however, this changes its data! ' HanningWindow Spx() 'in g_indep ' it would be better to create a new hanning function, ' converting doubles on the input to singles and applying hanning window. ' Then we could calculate the FFT in single precision. ' however, it may very well be that there is no longer a speed penalty to using double throughout ' tmp remmed out: ' MAT hanx() = dbx() * Han() ' copy the input data and apply hanning window ' MAT hany() = dby() * Han() ' MAT hanz() = dbz() * Han() '-------------- ' HanningWindow_dbl Hanx() ' in g_indep ' HanningWindow_dbl Hany() ' HanningWindow_dbl Hanz() ' without windowing: ' DFT_Dbl dbx(),Spx() ' this would perform a spectral transform on the 4 second buffer ' DFT_Dbl dby(),Spy() ' DFT_Dbl dbz(),Spz() ' with hanning window: ' DFT_Dbl hanx(), Spx() ' DFT_Dbl hany(), Spy() ' DFT_Dbl hanz(), Spz() END SUB FUNCTION GetDopplerPointer () EXPORT AS DWORD ' must be called after initialisation ' in your own application FUNCTION = VARPTR(doppler) END FUNCTION ' ---------------------------- 24GHz radar system support ------------------------------------------------ ' wordt dit al ergens gebruikt: ja, in de Butoh kompilatie. FUNCTION Get24GHzRadarPointer () EXPORT AS DWORD ' function = varptr(...) FUNCTION = VARPTR(R24GT) END FUNCTION FUNCTION R24GT_DAQ (BYVAL param AS LONG) EXPORT AS LONG ' this procedure starts/stops the data-acquisition for the 24GHz radar tetrahedron ' channels 1,2,3,4 on the 24GHz board. ' only supported for NiDAQmx. ' 08.09.2009: first redaction. ' 25.11.2009 note R24GT.dtq should be set by the calling application first ' in first experiments, 20 looks like a good value.. ' both TL-lights and motors in the orchestra cause a lot of noise in the radar signal ' 09.03.2010: adapted to new channel assignment on the NiDAQ interface. 'restored to callback every 8 samples instead 0f 32 (which used to crash on xi) 'on yo does'nt crash, but gives lots of errors.. STATIC init AS DWORD board = %R24GT ' new constant 08.09.2009 LOCAL i AS INTEGER warning "FUNCNAME$ + STR$(param)" #IF %DEF(%g_NiDAQmx) LOCAL ret AS LONG LOCAL errBuff AS ASCIIZ * 2048 LOCAL cpcb AS DWORD LOCAL device AS ASCIIZ * 10 LOCAL physicalchannels AS ASCIIZ * 40 LOCAL nametoassigntochannels AS ASCIIZ * 40 LOCAL customscalename AS ASCIIZ * 40 IF ISFALSE init THEN warning "ïnit" + FUNCNAME$ 'following buffers stay fixed in size.. REDIM dbx24Gf(2048 * 3600) AS DOUBLE 'one hour buffer - four buffers are about 60 mb, but that shouldn't be a problem.. REDIM dby24Gf(2048 * 3600) AS DOUBLE REDIM dbz24Gf(2048 * 3600) AS DOUBLE REDIM dbc24Gf(2048 * 3600) AS DOUBLE REDIM dbx24Gm(UBOUND(dbx24Gf)\8) AS DOUBLE REDIM dby24Gm(UBOUND(dby24Gf)\8) AS DOUBLE REDIM dbz24Gm(UBOUND(dbz24Gf)\8) AS DOUBLE REDIM dbc24Gm(UBOUND(dbc24Gf)\8) AS DOUBLE REDIM dbx24Gs(UBOUND(dbx24Gm)\8) AS DOUBLE REDIM dby24Gs(UBOUND(dby24Gm)\8) AS DOUBLE REDIM dbz24Gs(UBOUND(dbz24Gm)\8) AS DOUBLE REDIM dbc24Gs(UBOUND(dbc24Gm)\8) AS DOUBLE REDIM xfbuf(UBOUND(dbx24Gm)) AS SINGLE 'klopt dit? zelfde rate als mid buffer? REDIM zfbuf(UBOUND(dbx24Gm)) AS SINGLE '*re*dim seems to be crucial here.. REDIM yfbuf(UBOUND(dbx24Gm)) AS SINGLE REDIM cfbuf(UBOUND(dbx24Gm)) AS SINGLE R24GT.bufpos = 0 R24GT.pxfast = VARPTR(dbx24Gf(0)) R24GT.pyfast = VARPTR(dby24Gf(0)) R24GT.pzfast = VARPTR(dbz24Gf(0)) R24GT.pcfast = VARPTR(dbc24Gf(0)) R24GT.pxm = VARPTR(dbx24Gm(0)) R24GT.pym = VARPTR(dby24Gm(0)) R24GT.pzm = VARPTR(dbz24Gm(0)) R24GT.pcm = VARPTR(dbc24Gm(0)) R24GT.pxslow = VARPTR(dbx24Gs(0)) R24GT.pyslow = VARPTR(dby24Gs(0)) R24GT.pzslow = VARPTR(dbz24Gs(0)) R24GT.pcslow = VARPTR(dbc24Gs(0)) R24GT.pxfbuf = VARPTR(xfbuf(0)) ' common with other structures... R24GT.pyfbuf = VARPTR(yfbuf(0)) R24GT.pzfbuf = VARPTR(zfbuf(0)) R24GT.pcfbuf = VARPTR(cfbuf(0)) warning "dim & ptrs done" init = 1 END IF warning "check param" + STR$(param) SELECT CASE param CASE -1 FUNCTION = @pDAQparams.mode CASE 0 GOSUB StopR24GT_Daq 'is this one the culprit? apparently not.. ' @pDAQparams.mode = %DAQ_NI CASE %DAQ_DOUBLEBUFFER warning "init double buffer" IF ISFALSE @pDAQparams.daqstopped THEN ' MSGBOX "pre gosub 2" GOSUB StopR24GT_DAQ END IF @pDAQparams.channel = %DAQ_RADAR @pDAQparams.mode = %DAQ_NI OR %DAQ_DOUBLEBUFFER @pDAQparams.inputconfig = 1 ' single ended ground referenced. @pDAQparams.rate = %False FOR i = 12 TO 15 'changed 09.03.2010 - gwr, conform to new hardware wiring. Was: 1 TO 4 @pDAQparams.samplingrate(i) = 2048 @pDAQparams.ChannelVector(i) = i @pDAQparams.polarity(i) = 0 '0= bipolar , 1= unipolar @pDAQparams.voltagerange(i) = 20 '-10 to + 10V @pDAQparams.GainVector(i) = 1 @pDAQparams.rate = @pDAQparams.rate + @pDAQparams.samplingrate(i) ' sum of samplingrates. ' this to allow checks with the capabilities of the device. NEXT i @pDAQparams.taskname = "R24GT" ' can be anything you like ret = DAQmxCreateTask(@pDAQparams.taskname, @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) Logfile "Create R24GT DAQ task error " & TRIM$(errbuff) END IF device = NiMxDevs(@pDAQparams.id) '.id is hier 1 of 2 nu. 'note: create all channels at once with one call - otherwise we get crashes.. 'DAQmxCreateAIVoltageChan call.. 'physicalchannels$ = TRIM$(Device) + "/ai1:4" - in de eerste bedrading, nu gewijzigd in: physicalchannels$ = TRIM$(Device) + "/ai12:15" 'dit was fout.. /ai12:4 kon omogelijk werken!! nametoassigntochannels$ = "A1, A2, A3, A4" 'heeft dit enige betekenis of moet het nu Ä12, A13, A14, A15" zijn ret = DAQmxCreateAIVoltageChan(BYVAL @pDAQparams.taskhandle, physicalChannels$,nameToAssignToChannels$,%DAQmx_Val_RSE,-10.0,10.0,%DAQmx_Val_Volts ,customscalename) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) warning "createvoltagechannels: " + TRIM$(errBuff) logfile TRIM$(errBuff) 'ok END IF ret = DaqmxCfgSampClkTiming(BYVAL @pDAQparams.taskhandle,"OnboardClock",2048,%DAQmx_val_Rising,%DAQmx_Val_ContSamps,1) ' we sample 4 channels. ' note: last param means nothing when using %DAQmx_Val_ContSamps IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "Clock error:" & TRIM$(errBuff) END IF ' -buffer ret = DAQmxCfgInputBuffer(BYVAL @pDAQparams.taskhandle,640) 'use a sample DMA buffer IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "Inputbuffer error:" & TRIM$(errBuff) END IF '-------- cpcb = CODEPTR(R24GT_EveryNCallback) ' 32 samples each time gives us 64ms resolution. ' with the current sampplingrate (2048), working with less then 32 samples seiously increases the chance of crashes on xi and shop. ' less then 8 crashses guaranteed ' should create a transfer of 4 x 32 samples each time. ret = DAQmxRegisterEveryNSamplesEvent(BYVAL @pDAQparams.taskhandle,%DAQmx_Val_Acquired_Into_Buffer,8,0,BYVAL cpcb, BYVAL %NULL) 'rstored 32 to 8 IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "DAQmxRegisterEveryNSamplesEvent error:" + TRIM$(errBuff) END IF cpcb = CODEPTR(R24GT_DoneCallback) ret = DAQmxRegisterDoneEvent(@pDAQparams.taskhandle,0,cpcb,BYVAL %NULL) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "DAQmxRegisterDoneEvent error:" & TRIM$(errBuff) END IF ret = DAQmxStartTask(BYVAL @pDAQparams.taskhandle) '->the crash really seems to be caused by this, although we still get the retval 0 just ' before it happens 'note: the callback gets called a couple of times in between this function call and the actual crash.. 'when compiling with debug error on, sometimes we get error IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "DAQmxStartTask error: " & TRIM$(errBuff) END IF @pDAQparams.daqstopped = %False warning "init done:" FUNCTION = %DAQ_DOUBLEBUFFER '%True CASE ELSE MSGBOX "Illegal mode",, FUNCNAME$ END SELECT ' msgbox "started.." EXIT FUNCTION ' essential!!! StopR24GT_DAQ: 'TO DO: allow to save log, then reset buffer.. IF @pDAQparams.taskhandle THEN ret = DAQmxStopTask(BYVAL @pDAQparams.taskHandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) END IF ret = DAQmxClearTask(BYVAL @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) END IF END IF @pDAQparams.daqstopped = %True @pDAQparams.taskhandle = %False @pDAQparams.taskname = NUL$(20) RETURN #ENDIF END FUNCTION FUNCTION offsetpos(BYVAL currentpos AS LONG,BYVAL offset AS LONG, BYVAL maxpos AS LONG) AS LONG 'this function helps counting in a circular buffer.. 'presuming that offset is no bigger than the size of the buffer, and that we start counting from 0, not 1!! 'should go in g_math maybe? 'note: offset can be negative!! ' logfile FUNCNAME$ + STR$(currentpos) + STR$(offset) + STR$(maxpos) currentpos = currentpos + offset IF currentpos < 0 THEN currentpos = (maxpos - currentpos) - 1 ELSEIF currentpos > maxpos THEN 'sic, no >= currentpos = (currentpos MOD maxpos) - 1 'thus here we should substract 1, so one step further then max position = 0 and not 1 END IF ' logfile " --->" + STR$(Currentpos) FUNCTION = currentpos END FUNCTION FUNCTION R24GT_EveryNCallback CDECL (BYVAL taskHandle AS LONG, BYVAL everyNsamplesEventType AS LONG, BYVAL nSamples AS LONG, BYVAL pCallBackData AS DWORD PTR) AS LONG ' callback handler for data acquisition with the 24GHz board, 4 channels - tetrahedron setup ' this function gets called every 8 samples and reads the acquired data. 256 s/s, 4 samples (daq internal sr: 2048 samples per channel / second) ' the latency is 3.9ms. ' note that we here have bipolar values!!! ' 07.09.2009: Modelled after the similar doppler function ' if we would do this using allocated memory we need 29,4912MByte/h * 4 = 120MByte/h - Xi has 512mb of memory, 3 gig is standard if you buy a laptop now... ' 2009.09.30: we try to remove the superfluous buffer shuffling and just use one big buffer.. ' copy of code before changes below 'oktober 2009: adapting of this code to 32 samples per call by xof.. not sure if understood everything right.. to be checked!! '2009.10.19 we get crashes again - probably something wrong in our calculations on the mid and slow buffers... 'pointer out of range" '2009.10.22 crashes solved. visualised log created in butoh.exe in pd , which looks fine after fixing a minor bug.. ' now check amps (why aren't they buffered*?) en do acceleration.. ' 2009.10.30 made R24GT_II_VU. amplitude (range 0-1) and speed work fine, result of acceleration look less ok - hardly ever becomes negative ' looks like channels are swapped (???) '2010.10.06 restored to old version on request by gwr.. LOCAL i AS LONG STATIC cnt AS DWORD #IF %DEF(%g_NIDAQmx) LOCAL ret AS LONG LOCAL errBuff AS ASCIIZ * 2048 LOCAL newval AS DOUBLE LOCAL div AS DWORD LOCAL ub AS DWORD LOCAL lbuf() AS DOUBLE REDIM value(256) AS STATIC DOUBLE 'inputdata buffer - twice as big as what we suspect to need.. STATIC xslow, yslow, zslow, cslow AS DOUBLE STATIC xdc, ydc, zdc, cdc AS DOUBLE ' for dc offset removal. 'nr of samples -> use -1 = all new samples, which normally is as much as you expect, but on some occasions it appears to be twice as much 'array size = at least nrsamples * nrchans ' time out = 12 x (1/2048) seconds 'vanwaar 12? - anyway, after solving all bugs, timing appears to be really tight. after 10 minutes of sampling we get exactly as much calls here as expected.. ' nr of samples per channel=32 IF ISFALSE R24GT.dtacc THEN R24GT.dtacc = 10 ret = DAQmxReadAnalogF64(taskHandle,-1,0.006,%DAQmx_Val_GroupByScanNumber,VARPTR(value(0)),UBOUND(value),nSamples,BYVAL %NULL) '!!!! since we changed the nr of samples we an expect here from 8 to 32, the code below probably needs to be revised.. ' logfile "nsamples:" + STR$(nsamples) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) logfile "DaqmxReadAnalogF64 error: " & TRIM$(errbuff) warning "DaqmxReadAnalogF64 error: " & TRIM$(errbuff) EXIT FUNCTION ' warning TRIM$(errbuff) ' if the acquisition stops here, we have to set @pDAQparams.daqstopped = %True ' this is to be checked. END IF ' transfer and process the data into the radar data arrays. ' with DC offset removal: (high pass filter) ' version with parametric control over the differenciator for DC removal: [08.07.2009] gwr ' note: R24GT.hpf should never be zero, since that erases any signal... ' the hpf range is now quadratic from 1 to 128^2 'everything we used to do 8 times we have to do 32 times now.. maybe first considering different buffering strattegies.. 'in first instance, do basic filtering save everything to big buffer(s) - all the rest we probably better do somewhere else then in this callback anyway.. div = R24GT.hpf + 1 FOR i = 0 TO (nsamples - 1) xdc = IIF(R24GT.hpf, (xdc * R24GT.hpf + value(4*i))/div, value(4*i)) 'if hpf >0, integrate, otherwise take sampled value directly.. ydc = IIF(R24GT.hpf, (ydc * R24GT.hpf + value(4*i + 1))/div, value(4*i + 1)) zdc = IIF(R24GT.hpf, (zdc * R24GT.hpf + value(4*i + 2))/div, value(4*i + 2)) cdc = IIF(R24GT.hpf, (cdc * R24GT.hpf + value(4*i + 3))/div, value(4*i + 3)) dbx24Gf(R24GT.bufpos) = xdc 'value (4 * i) dby24Gf(R24GT.bufpos) = ydc 'value (4 * i + 1) dbz24Gf(R24GT.bufpos) = zdc 'value (4 * i + 2) dbc24Gf(R24GT.bufpos) = cdc 'value (4 * i + 3) ' logfile "write fast buffer @" + str$(R24GT.bufpos) + str$(dbx24Gf(R24GT.bufpos)) + STR$(dby24Gf(R24GT.bufpos)) + STR$(dbz24Gf(R24GT.bufpos)) + STR$(dbc24Gf(R24GT.bufpos)) INCR R24GT.bufpos IF R24GT.bufpos > UBOUND(dbx24Gf) THEN Warning "one hour of radar data recorded - resetting circular buffer pointer" logfile "one hour of radar data recorded - resetting circular buffer pointer" R24GT.bufpos = 0 END IF NEXT ' if isfalse R24GT.bufpos mod 200 then logfile "cb" + str$(R24GT.bufpos) 'ok ' !!! the stuff below should be thoroughly checked... ' now we have to downsample from 2048 s/s -> 256 s/s = factor 8 ' we have 32 new input samples, so 4 output samples.. ' so bufpos in medium array = R24GT.bufpos\8, but we should calc from current bufpos - 31 to current bufpos ' >>>>> we gaan er voorlopig van uit dat we over mnder dan een uur bezig zijn, en de ringteller van de hoofdbuffer niet rondgegaan is - later aan te passen!!! ' newval = dbx24Gm(255)/256 + dbx24Gf(248)/256 + dbx24Gf(249)/128 + dbx24Gf(250)/64 + dbx24Gf(251)/32 + dbx24Gf(252)/16 + dbx24Gf(253)/ 8 + dbx24Gf(254)/4 + dbx24Gf(255)/2 ' sum always = 1 ' tpos = R24GT.bufpos - 31 #IF %DEF(%r24_32spb) LOCAL tpos AS LONG 'DWORD tpos = offsetpos(R24GT.bufpos, -32, UBOUND(dbx24Gf)) dbx24GM(tpos\8) = dbx24GM(offsetpos((tpos\8), - 1, UBOUND(dbx24GM))) 'take last value ub = UBOUND(dbx24Gf) 'note: for optimalisation we could check before if there's a risk of crossing the ubound, and if that doens't happen, drop all the offsetpos's... 'note the difference.. dbx24g*M*(tpos\8) vs dbx24g*F*(tpos) dbx24GM(tpos\8) = dbx24GM(tpos\8)/256 + dbx24Gf(offsetpos(tpos, 1, ub))/256 + dbx24Gf(offsetpos(tpos, 2, ub))/64 + dbx24Gf(offsetpos(tpos, 3, ub))/32 + _ dbx24Gf(offsetpos(tpos, 4, ub))/16 + dbx24Gf(offsetpos(tpos, 5, ub))/8 + dbx24Gf(offsetpos(tpos, 6, ub))/4 + dbx24Gf(offsetpos(tpos, 7, ub))/2 dby24GM(tpos\8) = dby24GM(tpos\8 + 1)/256 + dby24Gf(offsetpos(tpos, 1, ub))/256 + dby24Gf(offsetpos(tpos, 2, ub))/64 + dby24Gf(offsetpos(tpos, 3, ub))/32 + _ dby24Gf(offsetpos(tpos, 4, ub))/16 + dby24Gf(offsetpos(tpos, 5, ub))/8 + dby24Gf(offsetpos(tpos, 6, ub))/4 + dby24Gf(offsetpos(tpos, 7, ub))/2 dbz24GM(tpos\8 ) = dbz24GM(tpos\8)/256 + dbz24Gf(offsetpos(tpos, 1, ub))/256 + dbz24Gf(offsetpos(tpos, 2, ub))/64 + dbz24Gf(offsetpos(tpos, 3, ub))/32 + _ dbz24Gf(offsetpos(tpos, 4, ub))/16 + dbz24Gf(offsetpos(tpos, 5, ub))/8 + dbz24Gf(offsetpos(tpos, 6, ub))/4 + dbz24Gf(offsetpos(tpos, 7, ub))/2 dbc24GM(tpos\8) = dbc24GM(tpos\8)/256 + dbc24Gf(offsetpos(tpos, 1, ub))/256 + dbc24Gf(offsetpos(tpos, 2, ub))/64 + dbc24Gf(offsetpos(tpos, 3, ub))/32 + _ dbc24Gf(offsetpos(tpos, 4, ub))/16 + dbc24Gf(offsetpos(tpos, 5, ub))/8 + dbc24Gf(offsetpos(tpos, 6, ub))/4 + dbc24Gf(offsetpos(tpos, 7, ub))/2 tpos = offsetpos(tpos, 8, UBOUND(dbx24Gf)) ' logfile "write gm buffer @" + STR$(tpos\8) dbx24GM(tpos\8) = dbx24GM(tpos\8)/256 + dbx24Gf(offsetpos(tpos, 1, ub))/256 + dbx24Gf(offsetpos(tpos, 2, ub))/64 + dbx24Gf(offsetpos(tpos, 3, ub))/32 + _ dbx24Gf(offsetpos(tpos, 4, ub))/16 + dbx24Gf(offsetpos(tpos, 5, ub))/8 + dbx24Gf(offsetpos(tpos, 6, ub))/4 + dbx24Gf(offsetpos(tpos, 7, ub))/2 dby24GM(tpos\8) = dby24GM(tpos\8 + 1)/256 + dby24Gf(offsetpos(tpos, 1, ub))/256 + dby24Gf(offsetpos(tpos, 2, ub))/64 + dby24Gf(offsetpos(tpos, 3, ub))/32 + _ dby24Gf(offsetpos(tpos, 4, ub))/16 + dby24Gf(offsetpos(tpos, 5, ub))/8 + dby24Gf(offsetpos(tpos, 6, ub))/4 + dby24Gf(offsetpos(tpos, 7, ub))/2 dbz24GM(tpos\8 ) = dbz24GM(tpos\8)/256 + dbz24Gf(offsetpos(tpos, 1, ub))/256 + dbz24Gf(offsetpos(tpos, 2, ub))/64 + dbz24Gf(offsetpos(tpos, 3, ub))/32 + _ dbz24Gf(offsetpos(tpos, 4, ub))/16 + dbz24Gf(offsetpos(tpos, 5, ub))/8 + dbz24Gf(offsetpos(tpos, 6, ub))/4 + dbz24Gf(offsetpos(tpos, 7, ub))/2 dbc24GM(tpos\8) = dbc24GM(tpos\8)/256 + dbc24Gf(offsetpos(tpos, 1, ub))/256 + dbc24Gf(offsetpos(tpos, 2, ub))/64 + dbc24Gf(offsetpos(tpos, 3, ub))/32 + _ dbc24Gf(offsetpos(tpos, 4, ub))/16 + dbc24Gf(offsetpos(tpos, 5, ub))/8 + dbc24Gf(offsetpos(tpos, 6, ub))/4 + dbc24Gf(offsetpos(tpos, 7, ub))/2 tpos = offsetpos(tpos, 8, UBOUND(dbx24Gf)) ' logfile "write gm buffer @" + STR$(tpos\8) dbx24GM(tpos\8) = dbx24GM(tpos\8)/256 + dbx24Gf(offsetpos(tpos, 1, ub))/256 + dbx24Gf(offsetpos(tpos, 2, ub))/64 + dbx24Gf(offsetpos(tpos, 3, ub))/32 + _ dbx24Gf(offsetpos(tpos, 4, ub))/16 + dbx24Gf(offsetpos(tpos, 5, ub))/8 + dbx24Gf(offsetpos(tpos, 6, ub))/4 + dbx24Gf(offsetpos(tpos, 7, ub))/2 dby24GM(tpos\8) = dby24GM(tpos\8 + 1)/256 + dby24Gf(offsetpos(tpos, 1, ub))/256 + dby24Gf(offsetpos(tpos, 2, ub))/64 + dby24Gf(offsetpos(tpos, 3, ub))/32 + _ dby24Gf(offsetpos(tpos, 4, ub))/16 + dby24Gf(offsetpos(tpos, 5, ub))/8 + dby24Gf(offsetpos(tpos, 6, ub))/4 + dby24Gf(offsetpos(tpos, 7, ub))/2 dbz24GM(tpos\8 ) = dbz24GM(tpos\8)/256 + dbz24Gf(offsetpos(tpos, 1, ub))/256 + dbz24Gf(offsetpos(tpos, 2, ub))/64 + dbz24Gf(offsetpos(tpos, 3, ub))/32 + _ dbz24Gf(offsetpos(tpos, 4, ub))/16 + dbz24Gf(offsetpos(tpos, 5, ub))/8 + dbz24Gf(offsetpos(tpos, 6, ub))/4 + dbz24Gf(offsetpos(tpos, 7, ub))/2 dbc24GM(tpos\8) = dbc24GM(tpos\8)/256 + dbc24Gf(offsetpos(tpos, 1, ub))/256 + dbc24Gf(offsetpos(tpos, 2, ub))/64 + dbc24Gf(offsetpos(tpos, 3, ub))/32 + _ dbc24Gf(offsetpos(tpos, 4, ub))/16 + dbc24Gf(offsetpos(tpos, 5, ub))/8 + dbc24Gf(offsetpos(tpos, 6, ub))/4 + dbc24Gf(offsetpos(tpos, 7, ub))/2 tpos = offsetpos(tpos, 8, UBOUND(dbx24Gf)) ' logfile "write gm buffer @" + STR$(tpos\8) dbx24GM(tpos\8) = dbx24GM(tpos\8)/256 + dbx24Gf(offsetpos(tpos, 1, ub))/256 + dbx24Gf(offsetpos(tpos, 2, ub))/64 + dbx24Gf(offsetpos(tpos, 3, ub))/32 + _ dbx24Gf(offsetpos(tpos, 4, ub))/16 + dbx24Gf(offsetpos(tpos, 5, ub))/8 + dbx24Gf(offsetpos(tpos, 6, ub))/4 + dbx24Gf(offsetpos(tpos, 7, ub))/2 dby24GM(tpos\8) = dby24GM(tpos\8 + 1)/256 + dby24Gf(offsetpos(tpos, 1, ub))/256 + dby24Gf(offsetpos(tpos, 2, ub))/64 + dby24Gf(offsetpos(tpos, 3, ub))/32 + _ dby24Gf(offsetpos(tpos, 4, ub))/16 + dby24Gf(offsetpos(tpos, 5, ub))/8 + dby24Gf(offsetpos(tpos, 6, ub))/4 + dby24Gf(offsetpos(tpos, 7, ub))/2 dbz24GM(tpos\8 ) = dbz24GM(tpos\8)/256 + dbz24Gf(offsetpos(tpos, 1, ub))/256 + dbz24Gf(offsetpos(tpos, 2, ub))/64 + dbz24Gf(offsetpos(tpos, 3, ub))/32 + _ dbz24Gf(offsetpos(tpos, 4, ub))/16 + dbz24Gf(offsetpos(tpos, 5, ub))/8 + dbz24Gf(offsetpos(tpos, 6, ub))/4 + dbz24Gf(offsetpos(tpos, 7, ub))/2 dbc24GM(tpos\8) = dbc24GM(tpos\8)/256 + dbc24Gf(offsetpos(tpos, 1, ub))/256 + dbc24Gf(offsetpos(tpos, 2, ub))/64 + dbc24Gf(offsetpos(tpos, 3, ub))/32 + _ dbc24Gf(offsetpos(tpos, 4, ub))/16 + dbc24Gf(offsetpos(tpos, 5, ub))/8 + dbc24Gf(offsetpos(tpos, 6, ub))/4 + dbc24Gf(offsetpos(tpos, 7, ub))/2 logfile STR$(dbx24GM(tpos\8)) #ELSE ' old code (presuming 8 samples at a time, shifting buffers instead of circular big ones..) ' since the samples flow in at a rate of 8 per channel at a time -> is 32 sample now.. ' nr samples in the function above is samples *per channel*, ' so we get 8 new samples on each of the 4 channels ' the timing latency is 3.9ms ' downsampling to medium 1 second buffer: [ sampling rate becomes 256 S/s) newval = dbx24Gm(255)/256 + dbx24Gf(248)/256 + dbx24Gf(249)/128 + dbx24Gf(250)/64 + dbx24Gf(251)/32 + dbx24Gf(252)/16 + dbx24Gf(253)/ 8 + dbx24Gf(254)/4 + dbx24Gf(255)/2 ' sum always = 1 ARRAY DELETE dbx24Gm(), newval newval = dby24Gm(255)/256 + dby24Gf(248)/256 + dby24Gf(249)/128 + dby24Gf(250)/64 + dby24Gf(251)/32 + dby24Gf(252)/16 + dby24Gf(253)/ 8 + dby24Gf(254)/4 + dby24Gf(255)/2 ARRAY DELETE dby24Gm(), newval newval = dbz24Gm(255)/256 + dbz24Gf(248)/256 + dbz24Gf(249)/128 + dbz24Gf(250)/64 + dbz24Gf(251)/32 + dbz24Gf(252)/16 + dbz24Gf(253)/ 8 + dbz24Gf(254)/4 + dbz24Gf(255)/2 ARRAY DELETE dbz24Gm(), newval newval = dbc24Gm(255)/256 + dbc24Gf(248)/256 + dbc24Gf(249)/128 + dbc24Gf(250)/64 + dbc24Gf(251)/32 + dbc24Gf(252)/16 + dbc24Gf(253)/ 8 + dbc24Gf(254)/4 + dbc24Gf(255)/2 ARRAY DELETE dbc24Gm(), newval ' downsampling to slow 4 second buffer: { sampling rate becomes 64 S/s) xslow = (xslow + dbx24Gm(255))/2 ' running integrator yslow = (yslow + dby24Gm(255))/2 zslow = (zslow + dbz24Gm(255))/2 cslow = (cslow + dbc24Gm(255))/2 IF ISFALSE (cnt MOD 8) THEN ARRAY DELETE dbx24Gs(), xslow ARRAY DELETE dby24Gs(), yslow ARRAY DELETE dbz24Gs(), zslow ARRAY DELETE dbc24Gs(), cslow END IF #ENDIF #IF %DEF(%r24_32spb) ub = UBOUND(dbx24Gm) tpos = tpos\8 'last filled in pos in GM buffer now ' logfile "process gm buffer @" + STR$(tpos) ' logfile STR$(dbx24GM(tpos)) ' logfile "xslow wrap:" + STR$(offsetpos(tpos, -3, ub)) + " reading in Gmx buffer - ub" + STR$(UBOUND(Dbx24Gm)) xslow = (xslow + dbx24Gm(offsetpos(tpos, -3, ub)))/2 yslow = (yslow + dby24Gm(offsetpos(tpos, -3, ub)))/2 zslow = (zslow + dbz24Gm(offsetpos(tpos, -3, ub)))/2 cslow = (cslow + dbc24Gm(offsetpos(tpos, -3, ub)))/2 ' logfile "xslow wrap2:" + STR$(offsetpos(tpos, -2, ub)) + " reading in Gmx buffer - ub" + STR$(UBOUND(Dbx24Gm)) xslow = (xslow + dbx24Gm(offsetpos(tpos, -2, ub)))/2 yslow = (yslow + dby24Gm(offsetpos(tpos, -2, ub)))/2 zslow = (zslow + dbz24Gm(offsetpos(tpos, -2, ub)))/2 cslow = (cslow + dbc24Gm(offsetpos(tpos, -2, ub)))/2 ' logfile "xslow wrap3:" + STR$(offsetpos(tpos, -1, ub)) + " reading in Gmx buffer - ub" + STR$(UBOUND(Dbx24Gm)) xslow = (xslow + dbx24Gm(offsetpos(tpos, -1, ub)))/2 yslow = (yslow + dby24Gm(offsetpos(tpos, -1, ub)))/2 zslow = (zslow + dbz24Gm(offsetpos(tpos, -1, ub)))/2 cslow = (cslow + dbc24Gm(offsetpos(tpos, -1, ub)))/2 xslow = (xslow + dbx24Gm(tpos))/2 yslow = (yslow + dby24Gm(tpos))/2 zslow = (zslow + dbz24Gm(tpos))/2 cslow = (cslow + dbc24Gm(tpos))/2 ' logfile "x, y, z, c slow:" + STR$(xslow) + STR$(yslow) + STR$(zslow) + STR$(cslow) ' logfile "cnt" + STR$(cnt) IF ISFALSE (cnt MOD 2) THEN dbx24Gs(tpos\8) = xslow dby24Gs(tpos\8) = yslow dbz24Gs(tpos\8) = zslow dbc24Gs(tpos\8) = cslow END IF INCR cnt #ELSE ' 'to check: R24GT_ii_math.. waar is deze functie ??? ' INCR cnt ' ' if isfalse (cnt mod 100) then '50 = 20 x per sekonde ' ' R24GT_ii_Math ' takes still way too long to perform from within the callback... ' ' end if ' ' surface calculations: [this works from within the callback] ' rectified sigma function: ' surfx = ((surfx * dta) + abs(dbx24Gf(0))) / (dta+1) ' dta = integratiediepte (0 tot 255) '???? dbx24Gf(0) - dat snapt xof niet.. ' normalized in the range 0-1 R24GT.xa = ((R24GT.xa * R24GT.dta) + ABS(dbx24Gf(255))) / (R24GT.dta +1) '???? alleen met de laatste sample? - dus dan vallen er altijd 31 tussenuit.. R24GT.ya = ((R24GT.ya * R24GT.dta) + ABS(dby24Gf(255))) / (R24GT.dta +1) '???? waarom moet dit nog geintegreerd worden? R24GT.za = ((R24GT.za * R24GT.dta) + ABS(dbz24Gf(255))) / (R24GT.dta +1) R24GT.ca = ((R24GT.ca * R24GT.dta) + ABS(dbc24Gf(255))) / (R24GT.dta +1) #ENDIF #IF %DEF(%r24_32spb) 'absolute waarde van alle samples, geintegreerd.. -> gwr, klopt dit? '2009.10.29 blijkbaar is .dta 0?!? onderstaande kan dan niet goed werken.. logfile "CURRENT BPOS:" + STR$(R24GT.bufpos) FOR i = -31 TO -1 tpos = offsetpos(R24GT.bufpos, i, UBOUND(dbx24Gf)) 'mult by 127 to get in in the same scale as the sonar.. R24GT.xa = ((R24GT.xa * R24GT.dta) + 127 * ABS(dbx24Gf(tpos))) / (R24GT.dta + 1) R24GT.ya = ((R24GT.ya * R24GT.dta) + 127 * ABS(dby24Gf(tpos))) / (R24GT.dta + 1) R24GT.za = ((R24GT.za * R24GT.dta) + 127 * ABS(dbz24Gf(tpos))) / (R24GT.dta + 1) R24GT.ca = ((R24GT.ca * R24GT.dta) + 127 * ABS(dbc24Gf(tpos))) / (R24GT.dta + 1) ' logfile "24Gf offset@" + STR$(i) + STR$(tpos) + str$(R24GT.xa) + str$(dbx24Gf(tpos)) NEXT #ELSE ' speed calculations, using zero-cross calculation: (proc. in g_indep) ' noise level should become a function of .xa, ya. za ' the noise parameter is now expressed in fraction of normalized full scale, hence 1E-3 is 60dB or 1/1000 ' Since we count on every call (256 times a second) the entire buffer, the maximum ' difference between succesive values can never be larger than 4. (on each refresh, we are getting 4 new ' samples in dbx24Gf(). IF R24GT.xa > R24GT.noise THEN ' to be checked!!! R24GT.xf = WaveFreq_Dbl (dbx24Gf(), 512, R24GT.noise)' 1E-3) '4 * 2.44E-4) ' new function in g_indep ' the values are expressed in Hz ' the theoretical absolute maximum value would be 512Hz(corresponding to movement speed of 5m/s) ' the gate-time is 0.256 Sec. ' as for now, no integration is performed. ELSE 'R24GT.xf = %False ' we could also write R24GT.xf = R24GT.xf / 2 for a fast decay to zero. R24GT.xf /= 2 'xof wonders: isn't just putting 0 more correct? END IF IF R24GT.ya > R24GT.noise THEN R24GT.yf = WaveFreq_Dbl (dby24Gf(), 1024, R24GT.noise) '1E-3) '4 * 2.44E-4) ' noise = 1/4096 = 12 bit ELSE R24GT.yf /= 2 END IF IF R24GT.za > R24GT.noise THEN R24GT.zf = WaveFreq_Dbl (dbz24Gf(), 1024, R24GT.noise) '1E-3) '4 * 2.44E-4) ' * 4 = 10 bits resolution ELSE R24GT.zf /= 2 END IF IF R24GT.ca > R24GT.noise THEN R24GT.cf = WaveFreq_Dbl (dbc24Gf(), 1024, R24GT.noise) '1E-3) '4 * 2.44E-4) ' * 4 = 10 bits resolution ELSE R24GT.cf /= 2 END IF #ENDIF 'snelheidsberekening 'hiervoor moeten we nu een aparte buffer maken.. ' logfile "***compute speeds.. current bufpos: "+ STR$(R24GT.bufpos) ' logfile "noise:" + STR$(R24GT.noise) + " - sig:" + STR$(R24Gt.xa) IF R24GT.xa > R24GT.noise THEN REDIM lbuf(1024) AS LOCAL DOUBLE IF R24GT.bufpos => 1024 THEN POKE$ VARPTR(lbuf(0)), PEEK$(VARPTR(dbx24Gf(R24GT.bufpos -1024)), 1024 * 8) ELSE i = 1024 - R24GT.bufpos POKE$ VARPTR(lbuf(0)), PEEK$(VARPTR(dbx24Gf(UBOUND(Dbx24Gf)-i)), i*8) POKE$ VARPTR(lbuf(i-1)), PEEK$(VARPTR(dbx24Gf(0)), (R24Gt.bufpos-1) * 8) END IF R24GT.xf = WaveFreq_Dbl(lbuf(),1024, R24GT.noise)'/2 'by dividing by 2 we get same scale as the sonar (?) ' logfile "wavfreq direct:" + STR$(R24GT.xf) ELSE ' logfile "wavfreq div" + STR$(R24GT.xf) R24GT.xf /= 2 '? 'frequency response seems to have a different curve then with sonar system, with a lower average but high peeks.. END IF IF R24GT.ya > R24GT.noise THEN REDIM lbuf(1024) AS LOCAL DOUBLE IF R24GT.bufpos >= 1024 THEN POKE$ VARPTR(lbuf(0)), PEEK$(VARPTR(dby24Gf(R24GT.bufpos -1024)), 1024 * 8) ELSE i = 1024 - R24GT.bufpos POKE$ VARPTR(lbuf(0)), PEEK$(VARPTR(dby24Gf(UBOUND(Dby24Gf)-i)), i*8) POKE$ VARPTR(lbuf(i)), PEEK$(VARPTR(dby24Gf(0)), ((R24Gt.bufpos-1)) * 8) FOR i = LBOUND(lbuf) TO UBOUND(lbuf) NEXT END IF R24GT.yf = WaveFreq_Dbl(lbuf(),1024, R24GT.noise)'/2 ' logfile "wavfreq direct:" + STR$(R24GT.yf) ELSE R24GT.yf /= 2 '? END IF IF R24GT.za > R24GT.noise THEN REDIM lbuf(1024) AS LOCAL DOUBLE IF R24GT.bufpos >= 1024 THEN POKE$ VARPTR(lbuf(0)), PEEK$(VARPTR(dbz24Gf(R24GT.bufpos -1024)), 1024 * 8) ELSE i = 1024 - R24GT.bufpos POKE$ VARPTR(lbuf(0)), PEEK$(VARPTR(dbz24Gf(UBOUND(Dby24Gf)-i)), i*8) POKE$ VARPTR(lbuf(i)), PEEK$(VARPTR(dbz24Gf(0)), ((R24Gt.bufpos-1)) * 8) END IF R24GT.zf = WaveFreq_Dbl(lbuf(),1024, R24GT.noise) '/2 ' logfile "wavfreq direct:" + STR$(R24GT.zf) ELSE R24GT.zf /= 2 '? END IF IF R24GT.ca > R24GT.noise THEN REDIM lbuf(1024) AS LOCAL DOUBLE IF R24GT.bufpos > 1024 THEN POKE$ VARPTR(lbuf(0)), PEEK$(VARPTR(dbc24Gf(R24GT.bufpos -1024)), 1024 * 8) ELSE i = 1024 - R24GT.bufpos POKE$ VARPTR(lbuf(0)), PEEK$(VARPTR(dbc24Gf(UBOUND(Dbc24Gf)-i)), i*8) POKE$ VARPTR(lbuf(i)), PEEK$(VARPTR(dbc24Gf(0)), ((R24Gt.bufpos-1)) * 8) END IF R24GT.cf = WaveFreq_Dbl(lbuf(),1024, R24GT.noise)'/2 ' logfile "wavfreq direct:" + STR$(R24GT.cf) ELSE R24GT.cf /= 2 '? END IF ' logfile "***speeds done" ' the following used to happen every 8 samples.. every 32 now.. 'TO DO TO DO TO DO ' ' accelleration calculation: ' ' theory: if we take the maximum accelleration for body movement as 100m/s2, we need to ' ' measure accelleration with a time interval of 50ms. Since one sample in our buffer ' ' corresponds to 0.976ms, this corresponds to 51 samples. ' ' However, if we want to optimize for speed of response -at the detriment of resolution- ' ' we should take the timeinterval as 1cs = 10ms and thus 10 samples. ' ' hence: ' ' following are part of the structure, and thus global ' ' DIM xfbuf(0 to 63) as global single ' we take 63, to give us some margin ' ' DIM yfbuf(0 to 63) as global single ' done on init. ' ' DIM zfbuf(0 to 63) as global single ' ' DIM cfBuf(0 to 63) as global single ' ' R24GT.pxfbuf = varptr(xfbuf(0)) ' done on dll-init ' ' R24GT.pyfbuf = varptr(yfbuf(0)) ' ' R24GT.pzfbuf = varptr(zfbuf(0)) ' ' R24GT.pcfbuf = varptr(cfbuf(0)) ' i = 63 - R24GT.dtacc ' range for dtacc: 1 to 63. Crash if exceeded. '??? '>>>>>>>>>>>>>>>>> in original idea, same rate as mid buffer. problem: we only have the frequencies computerd once every 32 samples now in stead of every 8/.. '>>>>>>>>>>>>>>>> bet idea seems to store it only once for every 32 samples? #IF %DEF(%r24_32spb) '??? zijn y en z hier omgewisseld?? tpos = R24Gt.bufpos \ 32 ' logfile "buffer f" + STR$(tpos) + STR$(UBOUND(xfbuf)) + STR$( R24Gt.xf ) + STR$( R24Gt.yf ) + STR$( R24Gt.zf ) + STR$( R24Gt.cf ) xfbuf(tpos) = R24Gt.xf yfbuf(tpos) = R24Gt.yf zfbuf(tpos) = R24Gt.zf cfbuf(tpos) = R24Gt.cf #ELSE ' logfile "speeds buffered" ARRAY DELETE xfbuf(), R24GT.xf ARRAY DELETE yfbuf(), R24GT.yf ARRAY DELETE zfbuf(), R24GT.zf ' waarbij de maat van de buffer de dt bepaalt. ARRAY DELETE cfbuf(), R24GT.cf #ENDIF ' '???? volgende kan gewoon blijven staan zoals het was? ' heel assuymetrisch - komt nauwelijks onder 0.. 'note .dtacc mag niet 0 zijn i = 63 - R24GT.dtacc ' range for dtacc: 1 to 63. Crash if exceeded. '??? R24GT.xac = (R24GT.xf - xfbuf(i)) / R24GT.dtacc ' 12 = 63 - 51, voor 10 samp: 53 = 63 - 10 R24GT.yac = (R24GT.yf - yfbuf(i)) / R24GT.dtacc 'dus de acceleratie wordt berekend door de huidige sample te vergelijken met die van R24GT.dtacc stappen terug?? ' zou ok moeten zijn mits integratie, maar waar gebeurt deze? R24GT.zac = (R24GT.zf - zfbuf(i)) / R24GT.dtacc R24GT.cac = (R24GT.cf - cfbuf(i)) / R24GT.dtacc ' ' de resolutie neemt toe met .dtacc, maar de scaling blijft konstant. ' ' zonder de deling door dtacc hadden we: ' ' dtacc = 1 : X= -22/+8 Y= -8/+8 z= -8/+8 ' ' dtacc = 2 : X= -16/+20 Y= -16/+24 z= -20/+24 ' ' dtacc = 4 : X= -72/+72 y= -52/+64 z= -64/+52 ' ' dtacc = 6 : x= -72/+104 Y= -84/+88 Z= -76/+72 ' ' dtacc =10 : X= -48/+175 Y=-112/+124 Z= -168/+144 ' ' met de deling en na debug..., krijgen we nu: ' ' X= -9/+8 Y=-8/+24 Z=-8/+8 ' ' onafhankelijk van de setting voor dtacc. ' ' de resolutie neemt evenredig toe met dtacc natuurlijk ' END IF logfile "exit callback" #ENDIF END FUNCTION FUNCTION R24GT_DoneCallback CDECL (BYVAL taskhandle AS LONG,BYVAL stat AS LONG, BYVAL pCallBackData AS DWORD PTR) AS LONG ' this procedure can be common to all our NiDAQmx applications, sonar as well as radar. ' the procedure needs not to be exported. It's only used as an internal callback. ' 07.06.2009: checked gwr. ' note we can also use @pDAQparameters.taskhandle instead of passing the variable.??? 'no.. this parmeters are required by NidaqMx ' probably we cannot, because in would contradict the prototype of the function call. ' 29.09.2009 separate versionmade fror 24ghz radar for debugging - probably we can merge it again with the general one later on.. #IF %DEF(%g_NIDAQmx) 'this function is called when an error occurs which forces the DAQ to stop, not when it was terminated in a proper way.. 'works (checked door de usb kabel uit te trekken tijdens het werken - wordt proper afgehandeld..) LOCAL errBuff AS ASCIIZ * 2048 LOCAL ret AS LONG 'this function gets called when something's wrong and the DAQ stops.. 'Warning "DAQ stopped" '03.08.2009 examinating crashes and errors.. the crash is an acces violation. also when we don't crash, pb reports an '"illegal function call" error when we switch the doppler off or on again after switching off (thus not the very first time..) DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) Warning TRIM$(errbuff) ret = DAQmxClearTask(BYVAL @pDAQparams.taskhandle) IF ret THEN DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) Warning TRIM$(errbuff) END IF Warning "data acquisition stopped from NiDAQmx callback" @pDAQparams.daqstopped = %True ' added 08.06.2009 @pDAQparams.taskhandle = %False @pDAQparams.taskname = NUL$(10) MSGBOX "R24GT acquisition stopped!",,FUNCNAME$ #ENDIF END FUNCTION SUB R24GT_ii_VU () EXPORT ' VU-monitor procedure as used in BOM for the tetrahedral sonar setup STATIC resolution AS BYTE STATIC v% STATIC h%, bw%, Sp% LOCAL il?, H1% LOCAL hBrush AS LONG LOCAL hDC AS LONG LOCAL versize% LOCAL hOldBrush AS LONG DIM spoint(0 TO 15) AS LOCAL SINGLE IF ISFALSE @pT(%R24GT_VU_Task).tog THEN resolution = 8 ' this value should be made adjustable, read from $BOMINI v% = 2^resolution 'v% = 512 ' for 9 bit resolution v% = 256 for 8 bit, v% = 128 for 7 bit etc... IF ISFALSE @pT(%R24GT_VU_Task).hParam THEN @pT(%R24GT_VU_Task).hParam = Make_ii_VU_Window (8) h% = 1 ' horizontal start position for VU-graph bw% = 7 ' breedte van de balkjes Sp% = 5 ' spatie tussen de balkjes ' @pT(%Sonar_VU_Task).freq = 8 ' changed to 8 30.10.2003 ' was 3 '16 - should be set in application code. ' however, since we are using periodic timers now, this is not required at all... @pT(%R24GT_VU_Task).tog = %True END IF logfile FUNCNAME$ + STR$(R24GT.xa)+ STR$(R24GT.ya)+ STR$(R24GT.za) + STR$(R24GT.ca)+ STR$(R24GT.xf)+ STR$(R24GT.yf)+ STR$(R24GT.zf) + STR$(R24GT.cf)+ STR$(R24GT.xac)+ STR$(R24GT.yac)+ STR$(R24GT.zac) + STR$(R24GT.cac) hDC = GetDC (@pT(%R24GT_VU_Task).hParam) ' blank existing graph: PatBlt hDC, h%,0,h% + ((bw%+ Sp%)*16) ,v%,%WHITENESS ' all 16 channels filled. spoint(0)= R24GT.xa '* 127 spoint(1)= R24GT.ya '* 127 spoint(2)= R24GT.za '* 127 spoint(3)= R24GT.ca '* 127 spoint(4)= R24GT.xf spoint(5)= R24GT.yf spoint(6)= R24GT.zf spoint(7)= R24GT.cf ' spoint(8)= R24GT.xe ' spoint(9)= R24GT.ye ' spoint(10)= R24GT.ze ' spoint(11)= R24GT.xyze spoint(12)= R24GT.xac spoint(13)= R24GT.yac spoint(14)= R24GT.zac spoint(15)= R24GT.cac FOR il? = 0 TO 7 ' SHIFT RIGHT spoint(il?), 12 - resolution ??? SELECT CASE il? CASE 0 TO 3 hBrush = CreateSolidBrush (%GREEN) CASE 4 TO 7 hBrush = CreateSolidBrush (%BLUE) CASE 12 TO 15 hBrush = CreateSolidBrush (%CYAN) CASE ELSE hBrush = CreateSolidBrush (%RED) END SELECT hOldBrush = SelectObject(hDC, hBrush) H1% = h% + (il? * bw%) versize% = v% - spoint(il?) Rectangle hDC, H1%, v%, H1%+Sp%, versize% ' logfile "draw rect for" + STR$(il) + STR$(H1%) + STR$(v%) ok ' logfile "spoint:" + STR$(spoint(il?)) SelectObject hDC, hOldBrush DeleteObject hBrush NEXT il? FOR il? = 12 TO 15 spoint(il?) = spoint(il?) * 64 + 64 ' SHIFT RIGHT spoint(il?), 13 - resolution SELECT CASE il? CASE 12 TO 15 hBrush = CreateSolidBrush (%YELLOW) CASE ELSE hBrush = CreateSolidBrush (%RED) END SELECT hOldBrush = SelectObject(hDC, hBrush) H1% = h% + (il? * bw%) versize% = v% - spoint(il?) Rectangle hDC, H1%, v%, H1%+Sp%, versize% SelectObject hDC, hOldBrush DeleteObject hBrush NEXT il? ReleaseDC @pT(%Sonar_VU_Task).hParam, hDC END SUB ' 'FUNCTION R24GT_EveryNCallback(BYVAL taskHandle AS LONG, BYVAL everyNsamplesEventType AS LONG, BYVAL nSamples AS LONG, BYVAL pCallBackData AS DWORD PTR) AS LONG '' callback handler for data acquisition with the 24GHz board, 4 channels - tetrahedron setup ' ' this function gets called every 8 samples and reads the acquired data. 256 s/s, 4 samples (daq internal sr: 2048 samples per channel / second) ' ' the latency is 3.9ms. ' ' note that we here have bipolar values!!! ' ' 07.09.2009: Modelled after the similar doppler function ' ' if we would do this using allocated memory we need 29,4912MByte/h * 4 = 120MByte/h - Xi has 512mb of memory, 3 gig is standard if you buy a laptop now... ' old code with continuous buffer shuffling ' ' LOCAL i AS LONG ' STATIC cnt AS DWORD '#IF %DEF(%g_NIDAQmx) ' LOCAL ret AS LONG ' LOCAL errBuff AS ASCIIZ * 2048 ' LOCAL newval AS DOUBLE ' REDIM value(256) AS STATIC DOUBLE 'data buffer - twice as big as what we suspect to need.. ' STATIC xslow, yslow, zslow, cslow AS DOUBLE ' STATIC xdc, ydc, zdc, cdc AS DOUBLE ' for dc offset removal. ' ' 'nr of samples -> use -1 = all new samples, which normally is as much as you expect, but on some occasions it appears to be twice as much ' 'array size = at least nrsamples * nrchans ' ' time out = 12 x (1/2048) seconds 'vanwaar 12? - anyway, after solving all bugs, timing appears to be really tight. after 10 minutes of sampling we get exactly as much calls here as expected.. ' ' nr of samples per channel=32 ' ' ' ret = DAQmxReadAnalogF64(taskHandle,-1,0.006,%DAQmx_Val_GroupByScanNumber,VARPTR(value(0)),UBOUND(value),nSamples,BYVAL %NULL) ' ' '!!!! since we changed the nr of samples we an expect here from 8 to 32, the code below probably needs to be revised.. ' ' ' ' ' IF ret THEN ' DAQmxGetExtendedErrorInfo(errBuff, SIZEOF(errbuff)) ' logfile "DaqmxReadAnalogF64 error: " & TRIM$(errbuff) ' ' warning TRIM$(errbuff) ' ' if the acquisition stops here, we have to set @pDAQparams.daqstopped = %True ' ' this is to be checked. ' ELSE ' ' transfer and process the data into the radar data arrays. ' ' with DC offset removal: (high pass filter) ' ' version with parametric control over the differenciator for DC removal: [08.07.2009] gwr ' ' note: R24GT.hpf should never be zero, since that erases any signal... ' ' the hpf range is now quadratic from 1 to 128^2 ' ' ' 'everything we used to do 8 times we have to do 32 times now.. maybe first considering different buffering strattegies.. ' ' ' IF R24GT.hpf THEN ' i = R24GT.hpf + 1 ' Xdc = ((Xdc * R24GT.hpf) + Value(0)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbx24Gf(), (value(0) - Xdc)/10 'dbx(255) = always newest data, dbx(0)= oldest data sample ' Ydc = ((Ydc * R24GT.hpf) + Value(1)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dby24Gf(), (value(1) - Ydc)/10 ' Zdc = ((Zdc * R24GT.hpf) + Value(2)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbz24Gf(), (value(2) - Zdc)/10 ' Cdc = ((Cdc * R24GT.hpf) + Value(3)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbc24Gf(), (value(3) - Cdc)/10 ' ' Xdc = ((Xdc * R24GT.hpf) + Value(4)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbx24Gf(), (value(4) - Xdc)/10 ' Ydc = ((Ydc * R24GT.hpf) + Value(5)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dby24Gf(), (value(5) - Ydc)/10 ' Zdc = ((Zdc * R24GT.hpf) + Value(6)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbz24Gf(), (value(6) - Zdc)/10 ' Cdc = ((Cdc * R24GT.hpf) + Value(7)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbc24Gf(), (value(7) - Cdc)/10 ' ' Xdc = ((Xdc * R24GT.hpf) + Value(8)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbx24Gf(), (value(8) - Xdc)/10 ' Ydc = ((Ydc * R24GT.hpf) + Value(9)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dby24Gf(), (value(9) - Ydc)/10 ' Zdc = ((Zdc * R24GT.hpf) + Value(10)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbz24Gf(), (value(10) - Zdc)/10 ' Cdc = ((Cdc * R24GT.hpf) + Value(11)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbc24Gf(), (value(11) - Cdc)/10 ' ' Xdc = ((Xdc * R24GT.hpf) + Value(12)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbx24Gf(), (value(12) - Xdc)/10 ' Ydc = ((Ydc * R24GT.hpf) + Value(13)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dby24Gf(), (value(13) - Ydc)/10 ' Zdc = ((Zdc * R24GT.hpf) + Value(14)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbz24Gf(), (value(14) - Zdc)/10 ' Cdc = ((Cdc * R24GT.hpf) + Value(15)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbc24Gf(), (value(15) - Cdc)/10 ' ' uit te breiden tot 31 ' Xdc = ((Xdc * R24GT.hpf) + Value(16)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbx24Gf(), (value(16) - Xdc)/10 ' Ydc = ((Ydc * R24GT.hpf) + Value(17)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dby24Gf(), (value(17) - Ydc)/10 ' Zdc = ((Zdc * R24GT.hpf) + Value(18)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbz24Gf(), (value(18) - Zdc)/10 ' Cdc = ((Cdc * R24GT.hpf) + Value(19)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbc24Gf(), (value(19) - Cdc)/10 ' ' Xdc = ((Xdc * R24GT.hpf) + Value(20)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbx24Gf(), (value(20) - Xdc)/10 ' Ydc = ((Ydc * R24GT.hpf) + Value(21)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dby24Gf(), (value(21) - Ydc)/10 ' Zdc = ((Zdc * R24GT.hpf) + Value(22)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbz24Gf(), (value(22) - Zdc)/10 ' Cdc = ((Cdc * R24GT.hpf) + Value(23)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbc24Gf(), (value(23) - Cdc)/10 ' ' Xdc = ((Xdc * R24GT.hpf) + Value(24)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbx24Gf(), (value(24) - Xdc)/10 ' Ydc = ((Ydc * R24GT.hpf) + Value(25)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dby24Gf(), (value(25) - Ydc)/10 ' Zdc = ((Zdc * R24GT.hpf) + Value(26)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbz24Gf(), (value(26) - Zdc)/10 ' Cdc = ((Cdc * R24GT.hpf) + Value(27)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbc24Gf(), (value(27) - Cdc)/10 ' ' Xdc = ((Xdc * R24GT.hpf) + Value(28)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbx24Gf(), (value(28) - Xdc)/10 ' Ydc = ((Ydc * R24GT.hpf) + Value(29)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dby24Gf(), (value(29) - Ydc)/10 ' Zdc = ((Zdc * R24GT.hpf) + Value(30)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbz24Gf(), (value(30) - Zdc)/10 ' Cdc = ((Cdc * R24GT.hpf) + Value(31)) / i '(R24GT.hpf + 1) ' ARRAY DELETE dbc24Gf(), (value(31) - Cdc)/10 ' ' ELSE ' ' no data processing with filter ' ARRAY DELETE dbx24Gf(),value(0)/10 ' ARRAY DELETE dby24Gf(),value(1)/10 ' ARRAY DELETE dbz24Gf(),value(2)/10 ' ARRAY DELETE dbc24Gf(),value(3)/10 ' ARRAY DELETE dbx24Gf(),value(4)/10 ' ARRAY DELETE dby24Gf(),value(5)/10 ' ARRAY DELETE dbz24Gf(),value(6)/10 ' ARRAY DELETE dbc24Gf(), value(7)/10 ' ARRAY DELETE dbx24Gf(),value(8)/10 ' ARRAY DELETE dby24Gf(),value(9)/10 ' ARRAY DELETE dbz24Gf(),value(10)/10 ' ARRAY DELETE dbc24Gf(), value(11)/10 ' ARRAY DELETE dbx24Gf(),value(12)/10 ' ARRAY DELETE dby24Gf(),value(13)/10 ' ARRAY DELETE dbz24Gf(),value(14)/10 ' ARRAY DELETE dbc24Gf(), value(15)/10 ' ' uit te breiden tot 31 ' ARRAY DELETE dbx24Gf(),value(16)/10 ' ARRAY DELETE dby24Gf(),value(17)/10 ' ARRAY DELETE dbz24Gf(),value(18)/10 ' ARRAY DELETE dbc24Gf(),value(19)/10 ' ARRAY DELETE dbx24Gf(),value(20)/10 ' ARRAY DELETE dby24Gf(),value(21)/10 ' ARRAY DELETE dbz24Gf(),value(22)/10 ' ARRAY DELETE dbc24Gf(),value(23)/10 ' ARRAY DELETE dbx24Gf(),value(24)/10 ' ARRAY DELETE dby24Gf(),value(25)/10 ' ARRAY DELETE dbz24Gf(),value(26)/10 ' ARRAY DELETE dbc24Gf(), value(27)/10 ' ARRAY DELETE dbx24Gf(),value(28)/10 ' ARRAY DELETE dby24Gf(),value(29)/10 ' ARRAY DELETE dbz24Gf(),value(30)/10 ' ARRAY DELETE dbc24Gf(), value(31)/10 ' END IF ' ' since the samples flow in at a rate of 8 per channel at a time ' ' nr samples in the function above is samples *per channel*, ' ' so we get 8 new samples on each of the 4 channels ' ' the timing latency is 3.9ms ' ' ' downsampling to medium 1 second buffer: [ sampling rate becomes 256 S/s) ' newval = dbx24Gm(255)/256 + dbx24Gf(248)/256 + dbx24Gf(249)/128 + dbx24Gf(250)/64 + dbx24Gf(251)/32 + dbx24Gf(252)/16 + dbx24Gf(253)/ 8 + dbx24Gf(254)/4 + dbx24Gf(255)/2 ' sum always = 1 ' ARRAY DELETE dbx24Gm(), newval ' newval = dby24Gm(255)/256 + dby24Gf(248)/256 + dby24Gf(249)/128 + dby24Gf(250)/64 + dby24Gf(251)/32 + dby24Gf(252)/16 + dby24Gf(253)/ 8 + dby24Gf(254)/4 + dby24Gf(255)/2 ' ARRAY DELETE dby24Gm(), newval ' newval = dbz24Gm(255)/256 + dbz24Gf(248)/256 + dbz24Gf(249)/128 + dbz24Gf(250)/64 + dbz24Gf(251)/32 + dbz24Gf(252)/16 + dbz24Gf(253)/ 8 + dbz24Gf(254)/4 + dbz24Gf(255)/2 ' ARRAY DELETE dbz24Gm(), newval ' newval = dbc24Gm(255)/256 + dbc24Gf(248)/256 + dbc24Gf(249)/128 + dbc24Gf(250)/64 + dbc24Gf(251)/32 + dbc24Gf(252)/16 + dbc24Gf(253)/ 8 + dbc24Gf(254)/4 + dbc24Gf(255)/2 ' ARRAY DELETE dbc24Gm(), newval ' ' downsampling to slow 4 second buffer: { sampling rate becomes 64 S/s) ' xslow = (xslow + dbx24Gm(255))/2 ' running integrator ' yslow = (yslow + dby24Gm(255))/2 ' zslow = (zslow + dbz24Gm(255))/2 ' cslow = (cslow + dbc24Gm(255))/2 ' IF ISFALSE (cnt MOD 8) THEN ' ARRAY DELETE dbx24Gs(), xslow ' ARRAY DELETE dby24Gs(), yslow ' ARRAY DELETE dbz24Gs(), zslow ' ARRAY DELETE dbc24Gs(), cslow ' END IF ' ' ' INCR cnt ' ' if isfalse (cnt mod 100) then '50 = 20 x per sekonde ' ' R24GT_ii_Math ' takes still way too long to perform from within the callback... ' ' end if ' ' ' surface calculations: [this works from within the callback] ' ' rectified sigma function: ' ' surfx = ((surfx * dta) + abs(dbx24Gf(0))) / (dta+1) ' dta = integratiediepte (0 tot 255) ' ' normalized in the range 0-1 ' R24GT.xa = ((R24GT.xa * R24GT.dta) + ABS(dbx24Gf(255))) / (R24GT.dta +1) ' R24GT.ya = ((R24GT.ya * R24GT.dta) + ABS(dby24Gf(255))) / (R24GT.dta +1) ' R24GT.za = ((R24GT.za * R24GT.dta) + ABS(dbz24Gf(255))) / (R24GT.dta +1) ' R24GT.ca = ((R24GT.ca * R24GT.dta) + ABS(dbc24Gf(255))) / (R24GT.dta +1) ' ' speed calculations, using zero-cross calculation: (proc. in g_indep) ' ' noise level should become a function of .xa, ya. za ' ' the noise parameter is now expressed in fraction of normalized full scale, hence 1E-3 is 60dB or 1/1000 ' ' Since we count on every call (256 times a second) the entire buffer, the maximum ' ' difference between succesive values can never be larger than 4. (on each refresh, we are getting 4 new ' ' samples in dbx24Gf(). ' IF R24GT.xa > R24GT.noise THEN ' to be checked!!! ' R24GT.xf = WaveFreq_Dbl (dbx24Gf(), 512, R24GT.noise)' 1E-3) '4 * 2.44E-4) ' new function in g_indep ' ' the values are expressed in Hz ' ' the theoretical absolute maximum value would be 512Hz(corresponding to movement speed of 5m/s) ' ' the gate-time is 0.256 Sec. ' ' as for now, no integration is performed. ' ELSE ' 'R24GT.xf = %False ' we could also write R24GT.xf = R24GT.xf / 2 for a fast decay to zero. ' R24GT.xf = R24GT.xf / 2 'xof wonders: isn't just putting 0 more correct? ' END IF ' IF R24GT.ya > R24GT.noise THEN ' R24GT.yf = WaveFreq_Dbl (dby24Gf(), 1024, R24GT.noise) '1E-3) '4 * 2.44E-4) ' noise = 1/4096 = 12 bit ' ELSE ' R24GT.yf = R24GT.yf / 2 ' END IF ' IF R24GT.za > R24GT.noise THEN ' R24GT.zf = WaveFreq_Dbl (dbz24Gf(), 1024, R24GT.noise) '1E-3) '4 * 2.44E-4) ' * 4 = 10 bits resolution ' ELSE ' R24GT.zf = R24GT.zf/2 ' END IF ' IF R24GT.ca > R24GT.noise THEN ' R24GT.cf = WaveFreq_Dbl (dbc24Gf(), 1024, R24GT.noise) '1E-3) '4 * 2.44E-4) ' * 4 = 10 bits resolution ' ELSE ' R24GT.cf = R24GT.cf/2 ' END IF ' ' accelleration calculation: ' ' theory: if we take the maximum accelleration for body movement as 100m/s2, we need to ' ' measure accelleration with a time interval of 50ms. Since one sample in our buffer ' ' corresponds to 0.976ms, this corresponds to 51 samples. ' ' However, if we want to optimize for speed of response -at the detriment of resolution- ' ' we should take the timeinterval as 1cs = 10ms and thus 10 samples. ' ' hence: ' ' following are part of the structure, and thus global ' ' DIM xfbuf(0 to 63) as global single ' we take 63, to give us some margin ' ' DIM yfbuf(0 to 63) as global single ' done on init. ' ' DIM zfbuf(0 to 63) as global single ' ' DIM cfBuf(0 to 63) as global single ' ' R24GT.pxfbuf = varptr(xfbuf(0)) ' done on dll-init ' ' R24GT.pyfbuf = varptr(yfbuf(0)) ' ' R24GT.pzfbuf = varptr(zfbuf(0)) ' ' R24GT.pcfbuf = varptr(cfbuf(0)) ' i = 63 - R24GT.dtacc ' range for dtacc: 1 to 63. Crash if exceeded. ' ARRAY DELETE xfbuf(), R24GT.xf ' ARRAY DELETE yfbuf(), R24GT.yf ' ARRAY DELETE zfbuf(), R24GT.zf ' waarbij de maat van de buffer de dt bepaalt. ' ARRAY DELETE cfbuf(), R24GT.cf ' R24GT.xac = (R24GT.xf - xfbuf(i)) / R24GT.dtacc ' 12 = 63 - 51, voor 10 samp: 53 = 63 - 10 ' R24GT.yac = (R24GT.yf - yfbuf(i)) / R24GT.dtacc ' R24GT.zac = (R24GT.zf - zfbuf(i)) / R24GT.dtacc ' R24GT.cac = (R24GT.cf - cfbuf(i)) / R24GT.dtacc ' ' de resolutie neemt toe met .dtacc, maar de scaling blijft konstant. ' ' zonder de deling door dtacc hadden we: ' ' dtacc = 1 : X= -22/+8 Y= -8/+8 z= -8/+8 ' ' dtacc = 2 : X= -16/+20 Y= -16/+24 z= -20/+24 ' ' dtacc = 4 : X= -72/+72 y= -52/+64 z= -64/+52 ' ' dtacc = 6 : x= -72/+104 Y= -84/+88 Z= -76/+72 ' ' dtacc =10 : X= -48/+175 Y=-112/+124 Z= -168/+144 ' ' met de deling en na debug..., krijgen we nu: ' ' X= -9/+8 Y=-8/+24 Z=-8/+8 ' ' onafhankelijk van de setting voor dtacc. ' ' de resolutie neemt evenredig toe met dtacc natuurlijk ' END IF ' 'logfile "exit callback" '#ENDIF 'END FUNCTION '[eof]