'---------------------------------------------------- ' S a c t r a c k S p i k e 2 S c r i p t '11/22/02 '---------------------------------------------------- ' 'C H A N N E L S : '------------------ ' ' D/A ' 0 = primary H target to rack ' 1 = primary V target to rack ' 2 = secondary H target to rack ' 3 = secondary V target to rack ' ' A/D ' 0 = unit (1v=?) ' 1 = H eye position (1v=10deg) ' 2 = V eye position (1v=10deg) ' 3 = primary H target position feedback (1v=10deg) ' 4 = primary V target position feedback (1v=10deg) ' 5 = H eye velocity (1v=100d/s) Note: Cannot differentiate position fast enough to be useful for controlling experiement. ' 6 = V eye velocity (1v=100d/s) CED says digitizing hardware differentiated velocity is the proper way to do this. (Bergel 11/2002) ' 7 = secondary H target position feedback (1v=10deg) ' 8 = secondary V target position feedback (1v=10deg) ' 9 = H head position (1v=10deg) ' 10 = V head position (1v=10deg) ' 11 = H second eye position (1v=10deg) ' 12 = V second eye position (1v=10deg) ' 13 ' 14 ' 15 ' ' Dig/INput LOW byte ' 0 = Mayhem detector ' 1 = Spike detection pulse for Collision testing ' ' Dig/OUTput LOW byte ' 0 through 7 = parallel interface control of LED array ' Dig/OUTput HIGH byte ' 0 = primary shutter ' 1 = secondary shutter ' 2 = feeder pulse ' 3 = on-target tone ' 4 = stimulation pulse ' ' ' ' 'E V E N T T R A C E M A R K E R S : '--------------------------------------- ' ' EVENT MARKERS ' "01" = intial target step ' "02" = response target step ' "N" = open primary shutter ' "F" = close primary shutter ' "n" = close secondary shutter ' "f" = open secondary shutter ' ' MemGuided ' 1 = response period starts (he's supposed to move) ' 2 = response target step (he did move) ' 5 = intertrial interval starts ' 3 = fixataion period starts ' 4 = memorize period starts ' 5 = wait period starts ' 6 = time out const kBOBmode := 0, '0=booth mode, 1=development mode 'kBOBmode := 1, '0=booth mode, 1=development mode kParameterMilestone$ := "Sactrack 9/7/2006 format", 'for preference files kOnlineAnalysisInterval := 0.100, 'How often to process online data kSpotInterval := 0.100, 'How often to process spot shutter information kMaxLED := 47, kRedColorBit := 1, kGrnColorBit := 0, 'kSerialPort := 1, kSpotSm% := 1, kSpotLg% := 4, 'utility kError := -1, 'standard error code kEmpty := -1, kTrue := 1, kFalse := 0, kNAN := 999999999, 'simulated NAN (not-a-number), kPi := 3.141592654, kRadians := 360 / (2 * kPi), kStaticXY := 0, kStaticRadial := 1, kMS := 1000, kMaxVectors% := 8, 'booths kRobinsonBooth := 0, kOKNbooth := 1, kLEDbooth := 2, kVisualBooth := 3, kBobBooth := 4, 'modes kInvalid := -1, kCalibrate := 0, kXY := 1, kRadial := 2, kRamp := 4, kList := 5, kSine := 9, kStatic := 10, kThreeSpot := 96, kAdapt := 98, kMemory := 97, kGalvos34 := 0, kGalvos45 := 1, kLED := 2, kBob := 99, 'traces kWaveForm := 1, kEventPlus := 3, kMarker := 5, kRealWave := 9, kSecondTargColor := 14, 'green 'arrays kGenHistoArraySize% := 201, kReactionSize% := 121, kErrorSize% := 201, kHistoSize% := 251, kTableSize% := 1000, kTableOffset1000% := 1000, kTableOffset2000% := 2000, kTableOffsetCommon% := 0, kMaxPlots% := 4, kMaxBinPlots% := 2, kEvokedPlots% := 1, 'kMaxPlots%+kMaxBinPlots% := kMaxPlots% + kMaxBinPlots% + kEvokedPlots%, kTableRampCounters% := 600, kAttrNum% := 30, 'this includes the selectable, hist selectable and evoked kAvgCount := 25, 'dialog box components kPopupLabel := 18, kTypeInLabel := 9, kUnitLabel := 13, kX := 60, 'files kDoNotSave$ := "Do Not Save"; var 'the data table transfered to the sequencer '0000 - 0999 Common parameters '[00] := gWindowHvgDAC%; 'HWIND 'visually guided on-target window '[01] := gWindowVvgDAC%; 'VWIND '[10] := pRealMinTime*1000; 'ASSOONAS '[11] := pRealMaxTime*1000; 'NOLATER '[12] := pRealContiguousTime*1000; 'CONTTON '[13] := pRealTimeOn*1000; 'TOTALTON '[14] := pOnFirst*1000; 'DURFIRST '[15] := pOnSubsequent*1000; 'DURSUB '[16] := pForgiveness*1000; 'FORGTIME '[17] := pForceOT; '[30] := gWhichBooth '[31] := update report window info '[32] := V62 events, for on-line analysis '1000 - 1999 Calibrate parmeters '5000 - 5999 Ramp parameters '6000 - 6999 '7000 - 7999 Adapt parameters '8000 - 8999 Memory parameters '9000 - 9999 Overlap parameters 'odds & ends gstr$, gI%, gTemp1%, gTemp2%, gTemp3%, 'filenames/directories gFileName$ := kDoNotSave$,'holds the name of the current data file as it is being sampled gScriptDir$, 'path to script file gPrefDir$, gDataDir$, 'folder holding the data files 'windows gDataWindow%, 'Handle of new data file gSpotWindow%, gDebugWindow%, 'debugging information gGreetingWindow%, gSpikeWindow%, gRewardBoxParameterWindow%, gCollisionWindow%, gComplexHandle%, gTragectoryHandle%, gFloat%[20], 'global for floating window states 'window related gLastMode% := kInvalid, gNumMonitors%, gSpotScopeActive% := 1, gSpikeScopeActive% := 0, gSpikeWidthWM := 60, gSpikePreWM := 15, gSerialPort, gTable%[kTableSize%], gAppX1 := 0, 'app window gAppY1 := 0, gAppX2 := 100, gAppY2 := 100, gLogX1 := 80, 'Log window gLogY1 := 80, gLogX2 := 100, gLogY2 := 100, gDataX1 := 0, 'Data window gDataY1 := 0, gDataX2 := 100, gDataY2 := 100, gSpotX1 := 0, 'Spot scope window gSpotY1 := 0, gSpotX2 := 33, gSpotY2 := 44, gDebugX1 := 0, 'Debug window gDebugY1 := 0, gDebugX2 := 20, gDebugY2 := 20, gSpikeX1 := 0, 'Spike scope window gSpikeY1 := 66, gSpikeX2 := 33, gSpikeY2 := 100, gTragectoryX1 := 10, 'Tragectory window gTragectoryY1 := 40, gTragectoryX2 := 30, gTragectoryY2 := 65, 'channels gChUnit, ':= 1; gChHeye1, ':= 2; gChVeye1, ':= 3; gChHtarg1, ':= 4; gChVtarg1, ':= 5; gChHvel, ':= 6; gChVvel, ':= 7; gChHtarg2, ':= 8; gChVtarg2, ':= 9; back connector gChHhead, ':= 10; back connector gChVhead, ':= 11; back connector gChHeye2, ':= 10; back connector gChVeye2, ':= 11; back connector gChAux1, ':= 10; back connector gChAux2, ':= 11; back connector gChAux3, gChAux4, gChAux5, ':= 12; back connector ':= 13; back connector ':= 14; back connector gChUnit2, ':= 15; back connector ':= 16; back connector gChMemRectVel, gChMemHeyeinhead, gChMemVeyeinhead, gChMemHeyeVergence, gChMemVeyeVergence, gChSpikeWM%, gChSpikeWMperm%, gChEvents, gChFreq, gChKeyboard, gChShutter1Status, gChShutter2Status, gChShutter2on, gChShutter2off, gChShutter1on, gChShutter1off, gUnitData := 1, pGazeData := 0, pVergenceData := 0, pGeneralData910% := 0, pSampleCh1112% := 0, pSampleCh13% := 0, 'cursors gCursorAccept, 'buttons gQuitButton := 1, gReLaunchButton := 2, gNewDigFile := 3, gSineButton := 5, gStaticButton := 6, gRampButton := 7, gListButton := 8, gMemoryButton := 9, gThreeSpotButton := 10, gAdaptButton := 11, gRadialButton := 12, gXYbutton := 13, gCalibrateButton := 14, gLimitButton := 16, gRewardButton := 17, gDisplayButton := 18, gPrefSaveButton := 19, gPrefOpenButton := 20, gGetAllButton := 21, gNextComplexButton := 38, gResetHistoButton := 39, gAnalysisButton, 'counters gNumBlocked, 'positions blocked, like multiple zeros gLastRedShutterMarker := 0, gRedShutterMultiplier := 1, gLastGrnShutterMarker := 0, gGrnShutterMultiplier := 1, 'gEvents gRightLimit := 1, gLeftLimit := 1, 'timing gLastOnLineTime, gLastProcessUnit, gLastProcessRectVel, gLastProcessSpot, gLastRedState, gLastGrnState, 'location pExcursionLimit := 20, gLastRadius, gLastTheta, 'I/O calibration gBitsPerDegreeOut, gBitsPerDegreeIn, gSineScale, gIn2outConversion%, pTraceStyleTarget :=1, '0=lines 1=dots pTraceStyleAnimal :=1, '0=lines 1=dots '-------------------------- 'G E N E R A L '-------------------------- 'preferences pUnitHi := 7, pUnitLo := -7, pUnitCursor := -6.0, '+ these are obsolete and can be deleted as soon as they are removed from the preference file pWtEye := 0.25, pWtUnit := 0.25, pWtIFR := 0.25, pWtKeyboard := 0.25, pWtEvents := 0.25, '- these are obsolete and can be deleted as soon as they are removed from the preference file pWtChan000[32+1], pWtChan400[10+1], pWtChan800[10+1], pScaleMargin := 1.0, pScaleMinimum := 21.0, 'pChRegHi[20][40], '20 modes and 40 traces 'pChRegLo[20][40], '20 modes and 40 traces 'pChMemHi[20][40], '20 modes and 40 traces 'pChMemLo[20][40], '20 modes and 40 traces '-------------------------- 'C A L I B R A T E '-------------------------- 'preferences pCalibrateRadius := 10, pCalibrateHorzOffset% := 0, pCalibrateVertOffset% := 0, pCalibrateTheta := 1, 'hit the corners pCalibrateDelay% := 50, pLEDintensity% := 12, 'variables gCalibrateShutter1% := kTrue, 'don't remember this parameter gCalibrateShutter2% := kTrue, 'don't remember this parameter gCalibrateFeed% := 0, 'don't remember this parameter '-------------------------- 'X Y '-------------------------- 'preferences pXYlocations := 5, pXYseparation := 5, pXYHorzOffset% := 0, pXYVertOffset% := 0, '-------------------------- 'R A D I A L '-------------------------- 'preferences pRadialAngle[8], pRadialRadius[8], pRadialTargetSteps := 1, pStepSize := 5, pRadialReturnToZero := kFalse, pRadialHorzOffset% := 0, pRadialVertOffset% := 0, pRadialBlankDur := 0, pRadialOnsetVel := 75, pRadialOffsetVel := 30, pRadialRTZstim := 0, pRadialRTZstimOT := 250, '-------------------------- 'T H R E E S P O T '-------------------------- 'preferences pThreeSpotSeparation := 10, pThreeSpotVectors[8], pThreeSpotAdapt[8], pThreeSpotOnsetVel := 75, pThreeSpotOffsetVel := 30, pThreeTimeOn% := 1000, pThreeSpotHorzOffset% := 0, pThreeSpotVertOffset% := 0, pThreeSpotWindowBeg% := 0, pThreeSpotWindowEnd% := 1000, pThreeSpotStartRadius% := 0, pThreeSpotSacLower := 3.0, pThreeSpotSacUpper := 25.0, 'variables '-------------------------- 'A D A P T '-------------------------- 'preferences pAdaptVectors[8], pAdaptAdapt[8], pAdaptInitialSteps[8], pAdaptGapDur := 0, pAdaptBlankDur := 0, pAdaptChosenVector := 0, pAdaptOnsetVel := 75, pAdaptOffsetVel := 30, pAdaptFollowDur := 0, pAdaptRTZ := 0, pAdaptType := 0, pAdaptStepEverytime% := 0, pAdaptHorzOffset% := 0, pAdaptVertOffset% := 0, pAdaptStimDir[4], pAdaptStim1, pAdaptStim2, pAdaptStimRatio := 100, pAdaptWindowBeg% := 0, pAdaptWindowEnd% := 1000, pAdaptStartRadius% := 0, 'variables gAdaptInitialRadius, gAdaptInitialTheta, gAdaptSecondRadius, gAdaptSecondTheta, gAdaptTimeForZero, '-------------------------- 'M E M O R Y '-------------------------- 'preferences pMemoryVectors[8], pMemoryAdapt[8], pMemoryFixDur[8], pMemoryFixPeriphDurs[8], pMemoryWaitDurs[8], pMemoryPeriphDurs[8], pMemoryInitialSteps[8], pMemoryChosenVector := 0, pMemoryOnsetVel := 75, pMemoryOffsetVel := 30, pMemoryFollowDur := 0, pMemoryRTZ := 0, pMemoryType := 0, pMemoryResponseDur := 0.5, pMemoryPostFailure := 1, pMemoryPostColor := 2, pMemoryTimeouts := 0, pMemoryStimDir[4], pMemoryStim1, pMemoryStim2, pMemoryStimRatio := 100, pMemoryMemCtlRatio := 100, 'variables gMemoryInitialRadius, gMemoryInitialTheta, gMemorySecondRadius, gMemorySecondTheta, gMemoryTimeForZero, '-------------------------- 'S T A T I C '-------------------------- 'preferences pStaticMode := 1, 'radial pStaticXorRadius := 0, pStaticYorTheta := 0, pStimType% := 0, 's-key stimulation pStimShutterDur := 0, pStimDelay := 0, pStimNoResponse := 0, pStimDur := 10, pStimAmp := 7, 'OBSOLETE, safe TTL voltage pStimInterval := 1000, pStimBefore := 1, pStimAfter := 5, pCollisionX1 := 25, pCollisionY1 := 50, pCollisionX2 := 100, pCollisionY2 := 100, pCollisionLatency := 1000, '1000/100 = 10 ms 'variables gCollisionN, gCollisionPlotLast := 0, gSamplesPerMS := 50, 'unit gEditN, gEditPlot%, gBackwardAnchor, gCurrentAnchor, gForwardAnchor, gEditIndex, '-------------------------- 'S I N E '-------------------------- 'preferences pSineFrequency := 1.0, pSineAmplitude := 10.0, pSineAngle := 0.0, pSineXoffset := 0, pSineYoffset := 0, '-------------------------- 'R A M P '-------------------------- 'preferences pRampAngle[8], pRampPriVelocity[8], pRampSecVelocity[8], pRampRatio := 100, pRampSecVelStartTime := 0, pRampExcursion := 20, pRampStepLatency := 100, pRampPlateau1 := 1000, pRampPlateau2 := 1000, 'variables gStepRamps := 0, '-------------------------- 'R A M P '-------------------------- 'preferences pListFeed%, pListTrials%, 'variables '-------------------------- 'R E W A R D '-------------------------- 'preferences pDisplay := kLED, 'Galvos34=0 Galvos45=1 LED=2 Bob=99 pHorzOffset := 0, pVertOffset := 0, pRealTimeOn := 1.0, pRealMinTime := 1.5, pRealMaxTime := 5.0, pRealContiguousTime := 0.5, pForgiveness := 0.4, pONfirst := 1.4, pONsubsequent := 1.0, pMayhemDuration := 0, 'off pForceOT% := 0, 'off pLimits%[8], pWindowHvg := 2, 'window variables pWindowVvg := 2, pWindowHmg := 5, pWindowVmg := 5, 'variables gLastCurrentTime, gTimeOnAccumulator, gContiguousAccumulator, gTimeAccumulator, gMinTimeOK, gMaxTimeOK, gTimeOnOK, gContiguousTimeOK, gWindowHvgDAC%, 'for visually guided OT comparison gWindowVvgDAC%, gWindowHmgDAC%, 'for memory guided OT comparison gWindowVmgDAC%, gForgivenessAccumulator, 'time to feed variables gFeedAccumulator, gSubsequent := kFalse, 'been on-target long enough to be eligible for faster feed rate gWhichBooth := kLEDbooth, 'kOKNbooth gMultiTargets := kFalse, '-------------------------- 'R E W A R D B O X P A R A M E T E R S '-------------------------- 'preferences pDirectFeed := 2, '1/27/06 used to be value = 1 which is now direct-feed-MAC pHWinSize := 82, pVWinSize := 82, pHTargInv := 1, pTimeOn := 2000000, pBlankDur := 300000, pFeedDelay := 1500000, pFeederOnTime := 100000, pEvenGodMustWait := 250000, pNumSacc% := 0, pEncAccel := 20, pEncAccelThresh := 2, pEncAccDly := 5000, pHgain1 := 1024, pHOffset1 := 0, pVGain1 := 1024, pVOffset1 := 0, pHgain2 := 1024, pHOffset2 := 0, pVGain2 := 1024, pVOffset2 := 0, pClearErr := 0, pFeedRate% := 0, 'variables gRewardVersion$, '-------------------------- 'O N L I N E A N A L Y S I S '-------------------------- 'preferences pMinSaccadicVelocity := 75, pOnsetVelocity := 20, pOffsetVelocity := 20, pMinTargAmp := 2, pMaxTargAmp := 22, pMinGain := 0.8, pMaxGain := 1.2, pMaxThetaError := 22, pSaccadeSearchStart := 0.100, pSaccadeSearchEnd := 0.600, 'variables gSubject$ := "MonkeysName", gAnalHandle%[kAttrNum%], gAnalPlotSelect%[kAttrNum%], gAnalXattr[kAttrNum%], gAnalYattr[kAttrNum%], gAnalParamOne[kAttrNum%], gAnalWinSize[kAttrNum%][4], 'xLo, yLo, xHi, yHi gAnalN[kAttrNum%], gAnalNpos[kAttrNum%], gAnalNneg[kAttrNum%], gAnalAvePos[kAttrNum%], gAnalAveNeg[kAttrNum%], gAnalPosAccum[kAttrNum%], gAnalNegAccum[kAttrNum%], gAnalXlo%[kAttrNum%], 'manage window size gAnalXhi%[kAttrNum%], gAnalYlo%[kAttrNum%], 'manage window size gAnalYhi%[kAttrNum%], gAnalLabelAxis$[kAttrNum%], '9/7/06 =[30] gAnalLabelTitle$[kAttrNum%], gAnalLabelButton$[kAttrNum%], 'single histogram plots gGenHistoArrayPos[kGenHistoArraySize%], gGenHistoArrayNeg[kGenHistoArraySize%], 'histogram plots gErrorSampleLO := 50, 'region to sample after saccade gErrorSampleHI := 57, gHistoSelect% := kFalse, gHistoYmax% := 100, 'spikes/s of Histo Max Y gHistoNum%[8], 'kMaxVectors% gHistoHandle%[8], 'kMaxVectors% gHistoWinSize[8][4], 'xLo, yLo, xHi, yHi gHistoEarliestOnset, gHistoLatestOffset, gHistoData%[kHistoSize%][8], 'kMaxVectors% gHistoAlignment% := 0, '0 means saccade onset, 1 means saccade offset gHistoBin := 10, 'Histogram bin width in ms gHistoStart := -300, 'for alignment gHistoEnd := 300, 'for alignment 'complex spike plots gComplexSelect% := kFalse, gComplexYmax := 500, 'spikes/s of Histo Max Y gComplexNum%[8], 'kMaxVectors% gComplexWinSize[8][4], 'xLo, yLo, xHi, yHi gComplexData%[kHistoSize%][8], 'kMaxVectors% gComplexAlignment% := 0, '0 means saccade onset, 1 means saccade offset gComplexStart := -300, 'for alignment gComplexEnd := 300, 'for alignment gNumCS%[8], gComplexSpikes[10001][400], gNextComplexPlot% := -1, gTragectorySelect% := kFalse, gTragectoryWinSize[4], gTragectoryN, '-------------------------- 'S E Q U E N C E - V A R I A B L E S '-------------------------- 'THESE SEQVAR CAN ONLY BE FILLED AFTER THE NEW%() COMMAND IN THE NEW ROUTINE ' := 1 ' := 2 ' := 3 ' := 4 ' := 5 ' := 6 ' := 7 ' := 8 ' := 9 ' := 10 ' := 11 ' := 12 ' := 13 ' := 14 ' := 15 ' := 16 ' := 17 ' := 18 ' := 19 ' := 20 ' := 21 ' := 22 ' := 23 ' := 24 ' := 25 ' := 26 ' := 27 ' := 28 ' := 29 ' := 30 ' := 31 ' := 32 ' := 33 ' := 34 ' := 35 ' := 36 ' := 37 sHITTYPE1 := 38, sHITTYPE2 := 39, ' := 40, ' := 41 sSHUT1 := 42, sSHUT2 := 43, ' := 44 ' := 45 ' := 46 ' := 47 ' := 48 ' := 49 ' := 50 ' := 51 ' := 52 ' := 53 sPARAMCHANGED := 54; ' := 55 ' := 56 'we are using DAC 0,1,2,3; so the following VAR are reserved ' := 57 reserved by CED for DAC0 feedback ' := 58 reserved by CED for DAC1 feedback ' := 59 reserved by CED for DAC2 feedback ' := 60 reserved by CED for DAC3 feedback 'we are not using DAC 4,5,6,7; so ok to use following var ' := 61 ' := 62 ' := 63 ' := 64 'THESE SEQVAR CAN ONLY BE FILLED AFTER THE FILENEW() COMMAND IN THE NEW ROUTINE '-------------------------- 'P R E F E R E N C E A R R A Y 'I N I T I A L I Z A T I O N ' 'Can't declare and initialize 'arrays at the same time '-------------------------- 'GENERAL VARIABLES ArrConst(pLimits%[], 20); 'end of axis arrconst(pWtChan000[], 1); 'channel weights arrconst(pWtChan400[], 1); 'channel weights arrconst(pWtChan800[], 1); 'channel weights pWtChan000[0] := 0; 'unused pWtChan400[0] := 0; 'unused pWtChan800[0] := 0; 'unused 'RADIAL ArrConst(pRadialAngle[], kNAN); pRadialAngle[0] := 0; pRadialAngle[1] := 180; ArrConst(pRadialRadius[], kNAN); pRadialRadius[0] := 0; pRadialRadius[1] := 5; pRadialRadius[2] := 10; 'MEMORY ArrConst(pMemoryVectors[], kNAN); pMemoryVectors[0] := 0; 'positive side pMemoryVectors[4] := 180; 'negative side ArrConst(pMemoryAdapt[], kNAN); pMemoryAdapt[0] := 0; 'positive side pMemoryAdapt[4] := 0; 'negative side ArrConst(pMemoryFixDur[], kNAN); pMemoryFixDur[0] := 1.0; ArrConst(pMemoryFixPeriphDurs[], kNAN); pMemoryFixPeriphDurs[0] := 1.0; ArrConst(pMemoryWaitDurs[], kNAN); pMemoryWaitDurs[0] := 0.0; ArrConst(pMemoryPeriphDurs[], kNAN); pMemoryPeriphDurs[0] := 1.0; ArrConst(pMemoryInitialSteps[], kNAN); pMemoryInitialSteps[0] := 10; 'ADAPT ArrConst(pAdaptVectors[], kNAN); pAdaptVectors[0] := 0; 'positive side pAdaptVectors[4] := 180; 'negative side ArrConst(pAdaptAdapt[], kNAN); pAdaptAdapt[0] := -5; 'positive side pAdaptAdapt[4] := -5; 'negative side ArrConst(pAdaptInitialSteps[], kNAN); pAdaptInitialSteps[0] := 10; 'RAMP ArrConst(pRampAngle[], kNAN); pRampAngle[0] := 0; pRampAngle[1] := 180; ArrConst(pRampPriVelocity[], kNAN); pRampPriVelocity[0] := 20; ArrConst(pRampSecVelocity[], kNAN); pRampSecVelocity[0] := 0; 'ANALYSIS gAnalXattr[0] := 2; 'the default attribute assignments gAnalYattr[0] := 4; gAnalXattr[1] := 2; gAnalYattr[1] := 9; gAnalXattr[2] := 2; gAnalYattr[2] := 3; gAnalXattr[3] := 6; gAnalYattr[3] := 3; gAnalXattr[kMaxPlots%+0] := 5; gAnalParamOne[kMaxPlots%+0] := 10.0; gAnalXattr[kMaxPlots%+1] := 8; gAnalParamOne[kMaxPlots%+1] := 6.0; gAnalXattr[kMaxPlots%+kMaxBinPlots%+kEvokedPlots% - 1] := 21; 'ALWAYS Stimulation Number gAnalYattr[kMaxPlots%+kMaxBinPlots%+kEvokedPlots% - 1] := 22; 'ALWAYS Evoked Saccade Amplitude ArrConst(gAnalHandle%[], -1); 'set to invalid value ArrConst(gAnalWinSize[][], -1); 'Set the window parameters to unused ArrConst(gAnalPlotSelect%[], kFalse); ArrConst(gAnalNpos[], 0); ArrConst(gAnalNneg[], 0); ArrConst(gAnalAvePos[], 0); ArrConst(gAnalAveNeg[], 0); ArrConst(gAnalPosAccum[], 0); ArrConst(gAnalNegAccum[], 0); ArrConst(gAnalXlo%[], 0); ArrConst(gAnalXhi%[], 1); ArrConst(gHistoWinSize[][],-1); ArrConst(gTragectoryWinSize[],-1); InitializeAttributeNames(); ResetComplexVar(); 'initialize arrays and counters related to complex spike presentation var junk; gTemp2% := 80; gTemp1% := 100; gTemp3% := 0; for gI% := 0 to kMaxPlots%+kMaxBinPlots%+kEvokedPlots% - 1 do gAnalWinSize[gI%][0] := gTemp2%; 'x1 gAnalWinSize[gI%][1] := gTemp3% * 20; 'y1 gAnalWinSize[gI%][2] := gTemp1%; 'x2 gAnalWinSize[gI%][3] := (gTemp3% + 1) * 20; 'y2 gTemp3% := gTemp3% + 1; junk := ((gI%+1) mod 5); if ((gI%+1) mod 5) = 0 then gTemp1% := gTemp1% - 20; gTemp2% := gTemp2% - 20; gTemp3% := 0; endif next '-------------------------- 'G L O B A L 'I N I T I A L I Z A T I O N ' 'Can't declare and initialize 'variables with program contants '-------------------------- 'main() HideSelectedItems(); view(App()); Window(gAppX1,gAppY1,gAppX2,gAppY2); 'set maximum single monitor application size ToolbarVisible(1); 'Make toolbar visible always gNumMonitors% := System(1,0); 'determine how many montitors there are '6/7/06 SAVE - not sure what to do since 2 monitor users can select "Dual View" or "Horizontal Span" modes which produce different results. 'if gNumMonitors% = 2 then ' gSpotX2 := gSpotX2/2; 'adjusts the DEFAULT spot scope shape for two monitors 'endif SetDefaultHistogramLocations(); SetDefaultComplexLocations(); InitializeForNewSubject(); DoToolbar(); 'Setup the toolbar 'Setup the toolbar '---------------------------------------------------- ' HideSelectedItems ' 'To maximize data window space, hide all the toolbars. ' ' 1 - iconic menu bar (file-open, file-save, etc.) ' 2 - status bar (bottom of script window) ' 3 - script file window (leave this undisturbed) ' 4 - edit bar (never used this) ' 5 - play wave bar (never used this) ' 6 - script bar () ' 7 - sample bar () ' 8 - sample control bar (START ABORT buttons) ' 9 - sequence control bar (sequence line number) ' '1/30/07 '---------------------------------------------------- proc HideSelectedItems() var i%; gFloat%[0] := 9; 'just deal with the first 9 toolbars for i% := 1 to gFloat%[0] do 'hide all windows and save state docase case i% = 3 then gFloat%[i%] := View(App(i%)).WindowVisible(); 'get script window status else gFloat%[i%] := View(App(i%)).WindowVisible(0); endcase next; end '---------------------------------------------------- ' RestoreSelectedItems ' 'Restore the toolbars that were open when Sactrack 'opened ' '1/30/07 '---------------------------------------------------- proc RestoreSelectedItems() var i%; for i% := 1 to gFloat%[0] do 'restore hidden windows View(App(i%)).WindowVisible(gFloat%[i%]); next; end '---------------------------------------------------- ' InitializeForNewSubject ' 'Called when Sactrack is run for the first time or 're-started by clicking that button. ' '1/26/06 '---------------------------------------------------- proc InitializeForNewSubject() 'must preceed DialogIntialSettings so it can report finding the Reward Box 'prepare the log window '---------------------- View(LogHandle()); 'Make log view the current view EditSelectAll(); 'Select all text in log view EditClear(); 'Delete it Window(gLogX1,gLogY1,gLogX2,gLogY2); 'Display it at the bottom of the screen WindowVisible(1); 'Make it visible gPrefDir$ := "C:/Documents and Settings/All Users/Desktop/"; 'get the current file path gScriptDir$ := View(App(3)).FileName$(2); FilePathSet(gPrefDir$); 'aim at the desktop where preference files are saved PreferencesOpen%(kTrue); DialogIntialSettings(); 'Set up reward box gDataDir$ := gPrefDir$ + gSubject$ + " " + date$(2,2,3,3,".") + "/"; FilePathSet(gDataDir$,1,1); 'CREATES data directory folder MyMessage(gGreetingWindow%, "Ready", "\n Select a mode button above to get started.",gNumMonitors%); 'give the user a hint about what to do next SetToolbar(kInvalid); 'Setup the toolbar end 'InitializeForNewSubject '---------------------------------------------------- ' InitializeAttributeNames '8/15/06 '---------------------------------------------------- proc InitializeAttributeNames() 'List$ := "-none-|Horz Eye/Targ Amp|Saccade Number|Polar Amp|Polar Gain|Polar Saccade Error|Polar Target Step Size|Polar Target Theta|Reaction Time|Saccade Duration|Vert eye/tar Amp", gAnalLabelAxis$[0] := "Num";'this is a trick for single histograms gAnalLabelTitle$[0] := "Num";'this is a trick for single histograms gAnalLabelButton$[0] := "N"; 'this is a trick for single histograms gAnalLabelAxis$[1] := "Horz Eye & Targ Amp"; gAnalLabelTitle$[1] := "H Eye & Targ Amp"; gAnalLabelButton$[1] := "H-amp"; gAnalLabelAxis$[2] := "Saccade Number"; gAnalLabelTitle$[2] := "Sac Num"; gAnalLabelButton$[2] := "Sac Num"; gAnalLabelAxis$[3] := "Polar Amp"; gAnalLabelTitle$[3] := "Polar Amp"; gAnalLabelButton$[3] := "P-amp"; gAnalLabelAxis$[4] := "Polar Gain"; gAnalLabelTitle$[4] := "Polar Gain"; gAnalLabelButton$[4] := "P-gain"; gAnalLabelAxis$[5] := "Polar Saccade Error"; gAnalLabelTitle$[5] := "Sac Error"; gAnalLabelButton$[5] := "P-Error"; gAnalLabelAxis$[6] := "Polar Target Amp"; gAnalLabelTitle$[6] := "Target Amp"; gAnalLabelButton$[6] := "PT-amp"; gAnalLabelAxis$[7] := "Polar Target Theta"; gAnalLabelTitle$[7] := "Target Theta"; gAnalLabelButton$[7] := "Theta"; gAnalLabelAxis$[8] := "Reaction Time"; gAnalLabelTitle$[8] := "Rxn Time"; gAnalLabelButton$[8] := "Rxn"; gAnalLabelAxis$[9] := "Saccade Duration"; gAnalLabelTitle$[9] := "Sac Dur"; gAnalLabelButton$[9] := "Dur"; gAnalLabelAxis$[10] := "Vert Eye & Targ Amp"; gAnalLabelTitle$[10] := "V Eye & Targ Amp"; gAnalLabelButton$[10] := "V-amp"; gAnalLabelAxis$[11] := "Horz Eye Amp"; gAnalLabelTitle$[11] := "Horz Eye Amp"; gAnalLabelButton$[11] := "HE-amp"; gAnalLabelAxis$[12] := "Vert Eye Amp"; gAnalLabelTitle$[12] := "Vert Eye Amp"; gAnalLabelButton$[12] := "VE-amp"; gAnalLabelAxis$[13] := "Horz Targ Amp"; gAnalLabelTitle$[13] := "Horz Targ Amp"; gAnalLabelButton$[13] := "HT-amp"; gAnalLabelAxis$[14] := "Vert Targ Amp"; gAnalLabelTitle$[14] := "Vert Targ Amp"; gAnalLabelButton$[14] := "VT-amp"; gAnalLabelAxis$[20] := ""; gAnalLabelTitle$[20] := ""; gAnalLabelButton$[20] := ""; gAnalLabelAxis$[21] := "Stimulation Number"; gAnalLabelTitle$[21] := "Stim Num"; gAnalLabelButton$[21] := "Stim Num"; gAnalLabelAxis$[22] := "Evoked Saccade Amp"; gAnalLabelTitle$[22] := "Evoked Sac Amp"; gAnalLabelButton$[22] := "Evoked"; end 'InitializeAttributeNames '---------------------------------------------------- ' MyMessage 'This is supposed to simplify presenting messages to 'the user, especially with multiple monitors which 'should not be presented in the middle of the two 'monitors. '4/7/05 '---------------------------------------------------- proc MyMessage(&aWindow%, aStr$, bStr$, aNumMonitors%) var aResult; aResult := ViewKind(aWindow%); if aStr$ = "" then 'no labels to show signals its time to close window if aResult >= 0 then 'window exists if aResult = 1 then '1=text view View(aWindow%); 'bring it to the top FileClose(0, -1); 'Close the window, 1=don't query endif endif else aWindow% := FileNew(1); 'give the user a hint about what to do next 'Window(30/aNumMonitors%, 45, 70/aNumMonitors%, 55); Window(60, 45, 90, 55); WindowTitle$(aStr$); FrontView(aWindow%); Print(bStr$); endif end 'MyMessage '---------------------------------------------------- ' DoToolbar '11/22/02 '---------------------------------------------------- proc DoToolbar() Toolbar("", 1023); 'Wait here until quit is pressed end 'DoToolbar '---------------------------------------------------- ' SetToolbar '1/21/04 '---------------------------------------------------- proc SetToolbar(aMode%) var a%,aPlot%,aStr$; ToolbarClear(); 'eliminate all the buttons 'these buttons are always dispalyed, set'em up ToolbarSet(0,"",Idle%); 'Call Idle%() whenever there is free time ToolbarSet(gQuitButton,"Quit Sactrack",Quit%); ToolbarSet(gReLaunchButton,"Re-Launch Sactrack", Stop%); ToolbarSet(gNewDigFile,"New Dig File", NewDig%); ToolbarSet(gStaticButton,"Static",DialogStatic%); ToolbarSet(gSineButton,"Sine",DialogSine%); ToolbarSet(gRampButton,"Ramp",DialogRamp%); ToolbarSet(gListButton,"List",DialogList%); ToolbarSet(gMemoryButton,"Memory",DialogMemory%); ToolbarSet(gThreeSpotButton,"3Spot",DialogThreeSpot%); ToolbarSet(gAdaptButton,"Adapt",DialogAdapt%); ToolbarSet(gRadialButton,"Radial",DialogRadial%); ToolbarSet(gXYbutton,"XY",DialogXY%); ToolbarSet(gCalibrateButton,"Calibrate",DialogCalibrate%); ToolbarSet(gLimitButton,"Limits",DialogLimits%); ToolbarSet(gRewardButton,"Behavior",DialogBehavior%); ToolbarSet(gDisplayButton,"Display",DialogDisplay%); ToolbarSet(gPrefSaveButton,"PrefSave",PrefSave%); ToolbarSet(gPrefOpenButton,"PrefOpen",PrefOpen%); ToolbarSet(gGetAllButton,"Status",RewardStatus%); 'the following buttons only appear if the associated plot is displayed a% := gGetAllButton + 1; 'plus a little separation for aPlot% := 0 to kMaxPlots%+kMaxBinPlots%+kEvokedPlots%-1 do if gAnalPlotSelect%[aPlot%] then aStr$ := (gAnalLabelButton$[gAnalXattr[aPlot%]] + " v " + gAnalLabelButton$[gAnalYattr[aPlot%]]); 'gPlot% := aPlot%; 'can't pass an argument with a button callback routine 'ToolbarSet(a%,aStr$,ResetPlotProcess%); docase case aPlot% = 0 then ToolbarSet(a%,aStr$,ResetPlotZero%); case aPlot% = 1 then ToolbarSet(a%,aStr$,ResetPlotOne%); case aPlot% = 2 then ToolbarSet(a%,aStr$,ResetPlotTwo%); case aPlot% = 3 then ToolbarSet(a%,aStr$,ResetPlotThree%); case aPlot% = 4 then ToolbarSet(a%,aStr$,ResetPlotFour%); case aPlot% = 5 then ToolbarSet(a%,aStr$,ResetPlotFive%); case aPlot% = 6 then ToolbarSet(a%,aStr$,ResetPlotSix%); case aPlot% = 7 then ToolbarSet(a%,aStr$,ResetPlotSeven%); endcase a% := a% + 1; endif next if gComplexSelect% then ToolbarSet(a%,"Next Complex",NextComplexDisplay%); a% := a% + 1; endif if gComplexSelect% then ToolbarSet(a%,"Reset Complex",ResetComplex%); a% := a% + 1; endif if gHistoSelect% then ToolbarSet(a%,"Reset Histo",ResetHistogramProcess%); a% := a% + 1; endif if gTragectorySelect% then ToolbarSet(a%,"Reset Tragectory",ResetTragectoryProcess%); a% := a% + 1; endif ToolbarSet(a%,"Analysis",DialogAnalysis%); gAnalysisButton := a%; 'show these if Static mode is active a% := a% + 1; 'for a little separation if aMode% = kStatic then ToolbarSet(a%,"Rt5°|0x27",StaticRt5%); 'start at +2 so there is a little separating space a% := a% + 1; ToolbarSet(a%,"Lf5°|0x25",StaticLf5%); a% := a% + 1; ToolbarSet(a%,"Ctr|0x20",StaticCenter%); a% := a% + 1; ToolbarSet(a%,"Up5°|0x26",StaticUp5%); a% := a% + 1; ToolbarSet(a%,"Dn5°|0x28",StaticDn5%); a% := a% + 1; a% := a% + 1; ToolbarSet(a%,"&Stimulate",StaticStimulate%); if pStimType% > 0 then 'search or collision mode ToolbarSet(a%,"Reset Stim Plot",ResetPlotCollision%); a% := a% + 1; endif if pStimType% = 2 then 'collision mode only ToolbarSet(a%,"&Dec Latency", LatencyDecrease%); a% := a% + 1; ToolbarSet(a%,"&Inc Latency", LatencyIncrease%); a% := a% + 1; endif endif if pDisplay = 2 then ToolbarEnable(gXYbutton,0); 'disallow XY mode in the LED booth ToolbarEnable(gSinebutton,0); 'disallow Sine mode in the LED booth else ToolbarEnable(gThreeSpotButton,0); 'only LED booth can use 3spot endif if aMode% = kInvalid then ToolbarEnable(gAnalysisButton,0); 'can't start an analysis window until there is scrolling data ToolbarEnable(gReLaunchButton,0); ToolbarEnable(gNewDigFile,0); endif ToolbarEnable(gResetHistoButton,gHistoSelect%); end 'SetToolbar '---------------------------------------------------- ' DialogIntialSettings ' 'DO NOT SET ANY SEQUENCE VARIABLES HERE SINCE THEY 'WILL BE INITIALIZED IN THE NEW%() SUBROUTINE. ' '4/18/03 '---------------------------------------------------- proc DialogIntialSettings() var aMessageBack$,bMessageBack$, bResult%, index%, bValue%, aWindow%, ok%, aTab1, aTab2, i%, aSampleCh910%, 'aSampleCh1112% , aSampleCh13%, aRow := 1; aTab1 := 50; aTab2 := aTab1 + 12; aSampleCh910% := 0; docase case pGeneralData910% = kTrue then 'general aSampleCh910% := 0; case pGazeData = kTrue then 'gaze aSampleCh910% := 1; case pVergenceData = kTrue then 'vergence aSampleCh910% := 2; endcase DlgCreate("Sactrack Initial Settings",kX); DlgString(1, "What is the NAME of your subject?", 32,"",aTab1,aRow); aRow := aRow + 2; DlgList(2, "Which BOOTH are you running in?","Robinson|OKN|LED|Visual|Bob",99,aTab1,aRow); aRow := aRow + 2; DlgList(3, "Sample channel 0 as UNITS this way:","No Unit Sampling|50kHz Unit Sampling|Multi-Unit Sampling",99,aTab1,aRow); '|100k Unit Sample",99,aTab1,aRow); aRow := aRow + 1; Dlgtext("Sample channels 1,2 as: HV-eye",0,aRow); aRow := aRow + 1; Dlgtext("Sample channels 3,4 as: HV-target",0,aRow); aRow := aRow + 1; Dlgtext("Sample channels 5,6 as: HV-eye velocity (deleted when file closed)",0,aRow); aRow := aRow + 1; Dlgtext("Sample channels 7,8 as: HV-target2",0,aRow); aRow := aRow + 1; DlgList(4, "Sample channels 9,10 as:","General purpose|HV-head|HV-eye2 (vergence)",99,aTab1,aRow); aRow := aRow + 1; DlgList(5, "Sample channels 11,12 as:","Not sampled|General purpose",99,aTab1,aRow); aRow := aRow + 1; DlgList(6, "Sample channel 13 as:","Not sampled|General purpose",99,aTab1,aRow); aRow := aRow + 1; Dlgtext("Sample channels 14,15: Can't do without deviating from 50kHz unit and 1kHz trace sampling.",0,aRow); aRow := aRow + 2; DlgList(7, "Display Spot Scope?","No|Yes",99,aTab1,aRow); aRow := aRow + 1; DlgList(8, "Display Spike Scope?","No|Yes",99,aTab1,aRow); aRow := aRow + 1; dlgInteger(9, " - Total duration of data displayed by Spike Monitor",0,500,aTab1,aRow); dlgText(" sampled unit points", aTab2, aRow); aRow := aRow + 1; dlgInteger(10, " - Pre-trigger duration of data displayed by Spike Monitor",0,500,aTab1,aRow); dlgText(" sampled unit points", aTab2, aRow); aRow := aRow + 2; DlgList(11, "Draw target traces with","Lines|Dots",99,aTab1,aRow); aRow := aRow + 1; DlgList(12, "Draw animal traces with","Lines|Dots",99,aTab1,aRow); aRow := aRow + 1; Dlgtext(" ",aTab1,aRow); ok% := dlgshow(gSubject$, gWhichBooth, gUnitData, aSampleCh910%, pSampleCh1112% , pSampleCh13%, gSpotScopeActive%, gSpikeScopeActive%, gSpikeWidthWM, gSpikePreWM, pTraceStyleTarget, pTraceStyleAnimal); if ok% <= 0 then halt; else docase case gWhichBooth = kRobinsonBooth then 'Robinson Booth pDisplay := 1; 'galvo 45 case gWhichBooth = kOKNbooth then 'OKN Booth pDisplay := 0; 'galvo 34 case gWhichBooth = kLEDbooth then 'LED Booth pDisplay := 2; 'LEDs case gWhichBooth = kVisualBooth then 'Visual Booth pDisplay := 0; 'galvo 34 case gWhichBooth = kBobBooth then 'Bob Booth pDisplay := kBob; '1v=10deg output endcase pGazeData := kFalse; pVergenceData := kFalse; pGeneralData910% := kFalse; docase case aSampleCh910% = 0 then 'always digitize ch 9 & 10 pGeneralData910% := kTrue; case aSampleCh910% = 1 then 'gaze pGazeData := kTrue; case aSampleCh910% = 2 then 'vergence pVergenceData := kTrue; endcase SetCalibration(); 'Set input and output gains View(LogHandle()); 'Make log view the current view EditSelectAll(); 'Select all text in log view EditSelectAll(); EditClear(); 'Delete text MyMessage(aWindow%, "Processing", "\n Initializing the Reward Box.", gNumMonitors%); 'SETUP SERIAL PORT 'This is a work-around to deal with the fact that the COM1 serial 'port in Bob's computer has some kind of comflict and reports that 'another program is using it. So, with this routine, if COM1 cannot 'be opened, the program tries to open COM2. 8/29/05 gSerialPort := 0; repeat gSerialPort := gSerialPort + 1; bResult% := SerialOpen(gSerialPort,9600); 'open the serial port until (bResult% >= 0) or gSerialPort = 2; if bResult% >= 0 then PrintLog("Reward Box using serial port #" + str$(gSerialPort) + "\n"); bResult% := SerialWrite(gSerialPort,"get version\r"); 'ask if reward box is connected bResult% := SerialRead(gSerialPort, aMessageBack$); 'listen for a response aMessageBack$ := DelStr$(aMessageBack$, 1, 7); 'strip off the "STATUS " on the left side gRewardVersion$ := left$(aMessageBack$,Len(aMessageBack$)-1); 'strip off the CR on the right side else PrintLog("No serial port could be opened.\n"); endif 'INITIALIZE REWARD BOX IF IT WAS FOUND if gRewardVersion$ <> "" then 'only do this if the Reward Box was found if gWhichBooth = kRobinsonBooth then bResult% := SerialWrite(gSerialPort, "set "+"htarginv=0"+"\r"); 'robinson calibration box else bResult% := SerialWrite(gSerialPort, "set htarginv=1\r"); 'fuchs calibration box endif if pHgain1 <= 0 then pHgain1 := 1024; 'invalid value override, can happen if reward box unpowered endif if pHgain2 <= 0 then pHgain2 := 1024; 'invalid value override, can happen if reward box unpowered endif if pVgain1 <= 0 then pVgain1 := 1024; 'invalid value override, can happen if reward box unpowered endif if pVgain2 <= 0 then pVgain2 := 1024; 'invalid value override, can happen if reward box unpowered endif bResult% := SetRewardValue%("directfeed", pDirectFeed); 'allows CED to feed animal bResult% := SetRewardValue%("hwinsize", pHWinSize); 'needed to stop flashing System Error LED bResult% := SetRewardValue%("vwinsize", pVWinSize); 'needed to stop flashing System Error LED bResult% := SetRewardValue%("timeon", pTimeOn); bResult% := SetRewardValue%("blankdur", pBlankDur); bResult% := SetRewardValue%("feeddelay", pFeedDelay); bResult% := SetRewardValue%("feederontime", pFeederOnTime); bResult% := SetRewardValue%("evengodmustwait", pEvenGodMustWait); bResult% := SetRewardValue%("numsacc", pNumSacc%); bResult% := SetRewardValue%("encaccel", pEncAccel); bResult% := SetRewardValue%("encaccelthresh", pEncAccelThresh); bResult% := SetRewardValue%("encaccdly", pEncAccDly); bResult% := SetRewardValue%("hgain1", pHgain1); bResult% := SetRewardValue%("hoffset1", pHOffset1); bResult% := SetRewardValue%("vgain1", pVGain1); bResult% := SetRewardValue%("voffset1", pVOffset1); bResult% := SetRewardValue%("hgain2", pHgain2); bResult% := SetRewardValue%("hoffset2", pHOffset2); bResult% := SetRewardValue%("vgain2", pVGain2); bResult% := SetRewardValue%("voffset2", pVOffset2); PrintLog("Reward Box Running Firmware " + gRewardVersion$); else PrintLog("Reward Box not found\n"); endif MyMessage(aWindow%, "", "", gNumMonitors%) endif end 'DialogIntialSettings '---------------------------------------------------- ' SetRewardValue '5/13/05 '---------------------------------------------------- func SetRewardValue%(aParamName$, aValue%) var bResult%, aMessageTo$; aMessageTo$ := "set " + aParamName$ + "=" + Print$("%12d", aValue%) + "\r"; bResult% := SerialWrite(gSerialPort, aMessageTo$); 'disable reward box feeder so direct feed works return bResult% end; 'SetRewardValue '---------------------------------------------------- ' GetRewardValue '5/13/05 '---------------------------------------------------- func GetRewardValue%(aParamName$) var bResult, aValue%, index%, aMessageBack$; aParamName$ := "get " + aParamName$ + "\r"; bResult := SerialWrite(gSerialPort,aParamName$); bResult := SerialRead(gSerialPort, aMessageBack$,"\r"); 'listen for a response index% := instr(aMessageBack$, "="); aMessageBack$ := DelStr$(aMessageBack$, 1, index%); aValue% := val(aMessageBack$); return aValue%; end; 'GetRewardValue '---------------------------------------------------- ' RewardStatus '5/20/05 '---------------------------------------------------- func RewardStatus%() if ViewKind(gRewardBoxParameterWindow%) < 0 then gRewardBoxParameterWindow% := FileNew(1); endif; FrontView(gRewardBoxParameterWindow%); Window(30/gNumMonitors%, 25, 70/gNumMonitors%, 75); WindowTitle$("Reward Box Parameters Report"); GetAllRewardValues(); Print("ClearErr = ", + pClearErr); Print("TimeOn = ", + pTimeOn); Print("DirectFeed = ", + pDirectFeed); Print("HTargInv = ", + pHTargInv); Print("FeedDelay = ", + pFeedDelay); Print("FeederOnTime = ", + pFeederOnTime); Print("BlankDur = ", + pBlankDur); Print("EvenGodMustWait = ", + pEvenGodMustWait); Print("NumSacc = ", + pNumSacc%); Print("HWinSize = ", + pHWinSize); Print("VWinSize = ", + pVWinSize); 'Print(Default); 'nothing to read, nothing to print Print(gRewardVersion$); Print("Hgain1 = ", + pHgain1); Print("VGain1 = ", + pVGain1); Print("Hgain2 = ", + pHgain2); Print("VGain2 = ", + pVGain2); Print("HOffset1 = ", + pHOffset1); Print("VOffset1 = ", + pVOffset1); Print("HOffset2 = ", + pHOffset2); Print("VOffset2 = ", + pVOffset2); Print("EncAccDly = ", + pEncAccDly); Print("EncAccelThresh = ", + pEncAccelThresh); Print("EncAccel = ", + pEncAccel); return kTrue; 'leave toolbar end 'RewardStatus '---------------------------------------------------- ' GetAllRewardValues '5/13/05 '---------------------------------------------------- proc GetAllRewardValues() var aWindow%, aDummy; if gRewardVersion$ <> "" then 'only do this if the Reward Box was found MyMessage(aWindow%, "Processing", "Getting the parameters from the Reward Box.", gNumMonitors%); pHgain1 := GetRewardValue%("Hgain1"); pHOffset1 := GetRewardValue%("HOffset1"); pVGain1 := GetRewardValue%("VGain1"); pVOffset1 := GetRewardValue%("VOffset1"); pHgain2 := GetRewardValue%("Hgain2"); pHOffset2 := GetRewardValue%("HOffset2"); pVGain2 := GetRewardValue%("VGain2"); pVOffset2 := GetRewardValue%("VOffset2"); '10/18/05 The following attributes are not changed by Sactrack and can cause the Reward box to act wierd if Sactrack sends it an inappropriate value. aDummy := GetRewardValue%("HWinSize"); 'pHWinSize := GetRewardValue%("HWinSize"); aDummy := GetRewardValue%("VWinSize"); 'pVWinSize := GetRewardValue%("VWinSize"); aDummy := GetRewardValue%("HTargInv"); 'pHTargInv := GetRewardValue%("HTargInv"); aDummy := GetRewardValue%("TimeOn"); 'pTimeOn := GetRewardValue%("TimeOn"); aDummy := GetRewardValue%("BlankDur"); 'pBlankDur := GetRewardValue%("BlankDur"); aDummy := GetRewardValue%("FeedDelay"); 'pFeedDelay := GetRewardValue%("FeedDelay"); aDummy := GetRewardValue%("FeederOnTime"); 'pFeederOnTime := GetRewardValue%("FeederOnTime"); aDummy := GetRewardValue%("NumSacc"); 'pNumSacc% := GetRewardValue%("NumSacc"); aDummy := GetRewardValue%("EncAccel"); 'pEncAccel := GetRewardValue%("EncAccel"); aDummy := GetRewardValue%("EncAccelThresh"); 'pEncAccelThresh := GetRewardValue%("EncAccelThresh"); aDummy := GetRewardValue%("EncAccDly"); 'pEncAccDly := GetRewardValue%("EncAccDly"); aDummy := GetRewardValue%("ClearErr"); 'pClearErr := GetRewardValue%("ClearErr"); aDummy := GetRewardValue%("DirectFeed"); 'pDirectFeed := GetRewardValue%("DirectFeed"); aDummy := GetRewardValue%("EvenGodMustWait"); 'pEvenGodMustWait := GetRewardValue%("EvenGodMustWait"); MyMessage(aWindow%, "", "", gNumMonitors%); 'close the window endif end; 'GetAllRewardValues '---------------------------------------------------- ' SetCalibration '1/30/03 '---------------------------------------------------- proc SetCalibration() var aBitsOut, aBitsIn, aOutInBitRatio; aBitsOut := pow(2,32); '4,294,967,296 aBitsIn := pow(2,16); '65,536 docase case pDisplay = kGalvos34 then gBitsPerDegreeOut := aBitsOut / 68.26666666; '2.93v=10deg, full range=68.26deg, galvo standard is 62,920,704.6 bits/degree gSineScale := 32768 / 68.26666666; '2.93v=10deg, 0-32768 represents the scale of 0-1 case pDisplay = kGalvos45 then gBitsPerDegreeOut := aBitsOut / 90; '2.2v=10deg, full range=90.0deg, galvo standard is 47,721,858.84 bits/degree gSineScale := 32768 / 90; '2.2v=10deg, 0-32768 represents the scale of 0-1 case (pDisplay = kLED) or (pDisplay = kBob)then gBitsPerDegreeOut := aBitsOut / 200; '1v=10deg, full range=200deg, output standard is 21,474,836.48 bits/degree gSineScale := 32768 / 200; '1v=10degrees, 0-32768 represents the scale of 0-1 endcase gBitsPerDegreeIn := aBitsIn / 200; '327.68 bits / degree gWindowHvgDAC% := round(pWindowHvg * gBitsPerDegreeIn); 'for visually guided OT comparison gWindowVvgDAC% := round(pWindowVvg * gBitsPerDegreeIn); '7/31/06 currently unused gWindowHmgDAC% := round(pWindowHmg * gBitsPerDegreeIn); 'for memory guided OT comparison gWindowVmgDAC% := round(pWindowVmg * gBitsPerDegreeIn); aOutInBitRatio := gBitsPerDegreeOut / gBitsPerDegreeIn; gIn2outConversion% := aOutInBitRatio; end 'SetCalibration '---------------------------------------------------- ' SaveLastDataFile 'Close and delete or close and name current data files. 'Also, close the current Spot Scope window. '12/6/04 '---------------------------------------------------- proc SaveLastDataFile() GetWindowPositions(); GetUnitTracePrefs(); GetTraceWeights(); if gFileName$ = kDoNotSave$ then MyFileClose(gDataWindow%, -1); 'Close & don't query else if viewkind(gDataWindow%)>=0 then samplestop(); 'stop the sampling so we can delete the velocity traces, they are more accurately computed in saccade view(gDataWindow%); chandelete(gChHvel); 'to save disk space chandelete(gChVvel); 'to save disk space MyFileClose(gDataWindow%, -35); 'Close & autoname endif endif MyFileClose(gSpotWindow%, -1); 'Close & don't query end 'SaveLastDataFile '---------------------------------------------------- ' GetUnitTracePrefs '5/24/06 '---------------------------------------------------- proc GetUnitTracePrefs() if viewkind(gDataWindow%)>=0 then view(gDataWindow%); if chankind(gChUnit) > 0 then pUnitCursor := HCursor(gCursorAccept); 'horiz cursor: acceptance pulse threshold pUnitHi := yhigh(gChUnit); pUnitLo := ylow(gChUnit); endif endif end 'GetUnitTracePrefs '---------------------------------------------------- ' CreateFileName 'Create a file name to save digitized data with. '12/7/04 '---------------------------------------------------- proc CreateFileName(aMode) var aDate$, aTime$, aMode$, aColonLocation%; aDate$ := "_" + date$(2,2,3,3,"."); aTime$ := "_" + time$(1,3); ',3,""); '1=24 hr, 3=hr&min, 3=hideAMPM, ""=OS default aColonLocation% := InStr(aTime$, ":"); aTime$ := DelStr$(aTime$, aColonLocation%, 1); 'remove on char where the ":" is docase case aMode = kCalibrate then gFilename$ := kDoNotSave$; return 'all done, leave now case aMode = kXY then aMode$ := "_XY"; case aMode = kRadial then aMode$ := "_Radial"; case aMode = kAdapt then aMode$ := "_Adapt"; case aMode = kStatic then aMode$ := "_Static"; case aMode = kRamp then aMode$ := "_Ramp"; case aMode = kSine then aMode$ := "_Sine"; case aMode = kMemory then aMode$ := "_Memory"; case aMode = kList then aMode$ := "_List"; endcase gFilename$ := gSubject$ + aDate$ + aTime$ + aMode$ + ".smr"; end 'CreateFileName '---------------------------------------------------- ' NewDig 'Stop and save the current data file. Open a new 'data file. ' '3/14/06 '---------------------------------------------------- func NewDig%() 'If "New Dig File" is pressed var aResult; aResult := query("Do you want to save the current data file and open a new one?","Continue","Cancel"); if aResult > 0 then SampleStop(); 'Stop sampling SaveLastDataFile(); ResetModeVariables(); CreateFileName(gLastMode%); New%(); Start%(); '(gMultiTargets); 'request the target2 be shown ReloadMode(); 'force them to be used SampleSeqTable(gTable%, kTableOffset1000%); 'RE-load all this data into the tabl SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed SetToolbar(gLastMode%); endif return kTrue; 'Stay in toolbar end 'NewDig '---------------------------------------------------- ' New 'Open a data view create some memory channels and 'arrange all the channels. '11/22/02 '---------------------------------------------------- func New%() 'New sampling window var ok%, aFirstCh, aStr$, bStr$, aResult%, aChanBinSize, aChanFreq; 'intialize variables ResetModeVariables(); gLastOnLineTime := 0; gLastProcessUnit := 0; gLastProcessRectVel := 0; gLastProcessSpot := 0; gLastRedState := -1; 'invalid gLastGrnState := -1; 'invalid 'declare channels gChUnit := 1; gChHeye1 := 2; gChVeye1 := 3; gChHtarg1 := 4; gChVtarg1 := 5; gChHvel := 6; gChVvel := 7; gChHtarg2 := 8; gChVtarg2 := 9; gChHhead := 10; gChVhead := 11; gChHeye2 := 10; gChVeye2 := 11; gChAux1 := 10; gChAux2 := 11; gChAux3 := 12; gChAux4 := 13; gChAux5 := 14; gChUnit2 := 15; ':= 16; ':= 17; ':= 18; ':= 19; ':= 20; ':= 21; ':= 22; ':= 23; ':= 24; ':= 25; ':= 26; ':= 27; ':= 28; gChSpikeWMperm% := 29; ':= 30 gChKeyboard := 31; gChEvents := 32; 'change the following default colors PaletteSet(22, 100, 40, 65); 'medium red 'create and label the sampling channels '-------------------------------------- SampleClear(); 'must preceed sequencer selection 'clear ALL the sampling settings View(LogHandle()); 'Make log view the current view WindowVisible(0); 'make mode specific digigitizg choices '------------------------------------------ gMultiTargets := kFalse; 'default, most paradigms have TWO target channels docase case gLastMode% = kCalibrate then aStr$ := gScriptDir$ + "sactrack_calibrate.pls"; gMultiTargets := kTrue; 'need all target channels to calibration case gLastMode% = kSine then aStr$ := gScriptDir$ + "sactrack_sine.pls"; case gLastMode% = kStatic then aStr$ := gScriptDir$ + "sactrack_static.pls"; case gLastMode% = kXY then aStr$ := gScriptDir$ + "sactrack_xy.pls"; case gLastMode% = kRamp then aStr$ := gScriptDir$ + "sactrack_ramp.pls"; case gLastMode% = kThreeSpot then aStr$ := gScriptDir$ + "sactrack_threespot.pls"; case gLastMode% = kAdapt then aStr$ := gScriptDir$ + "sactrack_adapt.pls"; case gLastMode% = kRadial then aStr$ := gScriptDir$ + "sactrack_radial.pls"; case gLastMode% = kList then aStr$ := gScriptDir$ + "sactrack_list.pls"; case gLastMode% = kMemory then aStr$ := gScriptDir$ + "sactrack_memory.pls"; gMultiTargets := kTrue; 'Memory paradigm has FOUR target channels endcase 'Information to help the user when the CED box cannot be found '-------------------------------------------------------------- aResult% := SampleSequencer(aStr$); 'set the sequencer to use if aResult% < 0 then dlgcreate("Sequencer Error",kX); dlgtext("The sequencer script was not found.", 0, 1); bStr$ := "Looking for " + aStr$; dlgtext(bStr$, 0, 2); dlgtext(" ", 0, 3); DlgButton(0,""); 'remove the CANCEL button ok% := dlgShow(); endif 'Set up sampling configuration, ch assingment, names, sample rates '----------------------------------------------------------------- docase case gUnitData = 1 then '0=no unit, 1=50k, 2=multi '4/13/07 Wish next line produced an error code so I could test if expansion box is present 'aResult%:= SampleWaveform(gChUnit, 17, 50000); 'channel and sample at 50 kHz SampleWaveform(gChUnit, 0, 50000); 'channel and sample at 50 kHz SampleTitle$(gChUnit, "Unit"); ' case gUnitData = 2 then '0=no unit, 1=50k, 2=100k ' SampleWaveform(gChUnit, 0, 100000); 'channel and sample at 100 kHz ' SampleTitle$(gChUnit, "Unit"); case gUnitData = 2 then '0=no unit, 1=50k, 2=multi SampleWaveform(gChUnit, 0, 25000); 'channel and sample at 25 kHz SampleTitle$(gChUnit, "Unit1"); SampleWaveform(gChUnit2, 15, 25000); 'channel and sample at 25 kHz SampleTitle$(gChUnit2, "Unit2"); endcase SampleWaveform(gChHeye1, 1,1000); 'H Eye channel SampleTitle$(gChHeye1, "H Eye"); SampleWaveform(gChVeye1, 2,1000); 'V Eye channel SampleTitle$(gChVeye1, "V Eye"); SampleWaveform(gChHtarg1,3,1000); 'H Target channel SampleTitle$(gChHtarg1, "H Targ"); SampleWaveform(gChVtarg1,4,1000); 'V Target channel SampleTitle$(gChVtarg1, "V Targ"); 'NOTE: don't use a rectified and/or summed velocity since 'it is useful to have the directions available to determine 'if the animal moved in the right direction whe presented 'with a stimulus. SampleWaveform(gChHvel, 5,1000); 'H Vel channel SampleTitle$(gChHvel, "H Vel"); SampleWaveform(gChVvel, 6,1000); 'V Vel channel SampleTitle$(gChVvel, "V Vel"); SampleDigMark(100); 'channel to record events '5/19/05 - there is an upper limit how big a file can be and it depends 'on how many channels are being digitized. Here is what Tim Bergel says: ' 'Spike2 tries to optimise the pattern of sampling to firstly minimise the 'errors in the sampling rate and secondly to maximise the sampling run time. 'As it happens, with your sampling configuration, patterns with zero errors 'are available for both 6 and 8 slower ADC channels, but in order to get it 'to work with 6 channels the ADC has to be run very fast and a shorter 'overall file time results. This does happen sometimes and you have not made 'any error. ' 'Given that the sampling rates can be got correct with 8 slower channels and 'with a longer runtime, in theory Spike2 could do better for you by sampling 'the two extra channels and discarding the data. However it does not try to 'do this - firstly because in general that results in inefficient use of the 'ADC hardware and also because the automatic optimisation would become 'excessively complex. ' 'Given that it will not make much difference to your file size, I can see no 'reason not to sample the full 8 slow channels always. ' ' 'Sactrack produces files of the duration shown below. To get the maximum 'file size all the time, Sactrack always digitizes 8 analog channels, but 'deletes the background target signal unless data was collected in Memory 'behavioral control mode. ' ' 1:29:28 with 1-50k Unit and 6-1k analog channels ' 2:23:09 with 1-50k Unit and 8-1k analog channels, ADC 250k ' 'if gMultiTargets = kTrue then SampleWaveform(gChHtarg2,7,1000); 'H2 Target channel SampleTitle$(gChHtarg2, "H2 Targ"); SampleWaveform(gChVtarg2,8,1000); 'V2 Target channel SampleTitle$(gChVtarg2, "V2 Targ"); 'endif '1/19/06 ALWAYS sample channels 0-10 because it gives us the longest sample time. ' ' 5:57:54 with 1-50k Unit and 8-1k analog channels, ADC 250k ' 'if pGeneralData910% = kTrue then SampleWaveform(gChAux1,9,1000); 'aux1 channel SampleTitle$(gChAux1, "Aux 1"); SampleWaveform(gChAux2,10,1000); 'aux2 channel SampleTitle$(gChAux2, "Aux 2"); 'endif if pGazeData = kTrue then SampleTitle$(gChHhead, "H Head"); SampleTitle$(gChVhead, "V Head"); endif if pVergenceData = kTrue then SampleTitle$(gChHeye2, "H Eye2"); SampleTitle$(gChVeye2, "V Eye2"); endif if pSampleCh1112% = kTrue then SampleWaveform(gChAux3,11,1000); 'aux3 channel SampleTitle$(gChAux3, "Aux 3"); SampleWaveform(gChAux4,12,1000); 'aux4 channel SampleTitle$(gChAux4, "Aux 4"); endif if pSampleCh13% = kTrue then SampleWaveform(gChAux5,13,1000); 'aux5 channel SampleTitle$(gChAux5, "Aux 5"); endif SampleTitle$(gChEvents, "Events"); SampleOptimise(2,1,2); 'Full optimize, group channels, Power 1401 'prepare a new data file and its window '-------------------------------------- gDataWindow% := FileNew(0,1); 'Open a new data file for sampling if gDataWindow% < 0 then message("COULD NOT CREATE a data window because the PC and CED are not communicating. Close Spike2 and shut-down the 1401. Then turn-on the 1401 and re-run Spike2. (Run TRY1401?)\n"); halt; endif 'confirm that the waveform channel frequency got set to 1kHz '----------------------------------------------------------- aChanBinSize := Binsize(gChHeye1); aChanFreq := 1/aChanBinSize; if aChanFreq <> 1000.0 then message("Wrong HORZ EYE sampling rate: " + str$(aChanFreq) + " Hz\n"); halt; endif aChanBinSize := Binsize(gChVeye1); aChanFreq := 1/aChanBinSize; if aChanFreq <> 1000.0 then message("Wrong HORZ EYE sampling rate: " + str$(aChanFreq) + " Hz\n"); halt; endif aChanBinSize := Binsize(gChHtarg1); aChanFreq := 1/aChanBinSize; if aChanFreq <> 1000.0 then message("Wrong HORZ TARGET sampling rate: " + str$(aChanFreq) + " Hz\n"); halt; endif aChanBinSize := Binsize(gChVtarg1); aChanFreq := 1/aChanBinSize; if aChanFreq <> 1000.0 then message("Wrong VERT TARGET sampling rate: " + str$(aChanFreq) + " Hz\n"); halt; endif '----------------------------------------- 'CANNOT SET SEQUENCE OR TABLE VARIABLES 'BEFORE THIS POINT AS THE VALUES WILL BE 'INITIALIZED '----------------------------------------- SetParametersCommon(); 'load the TABLE variables FrontView(gDataWindow%); 'Bring the data view to the front 'windowTitle$(gFilename$); DrawMode(-1,2); 'Set event draw mode to lines Window(gDataX1,gDataY1,gDataX2,gDataY2); 'Make data window in top bit of screen XRange(0,10); 'show ten seconds of data on the screen aResult% := SMOpen();'1,1); 'create the memory channels '--------------------------- gChMemRectVel := MemChan(kRealWave,0,BinSize(gChHeye1)); 'computed rectified velocity trace if pGazeData = kTrue then gChMemHeyeinhead := MemChan(kRealWave,0,BinSize(gChHeye1)); 'computed horz eye in head trace (gaze-head) gChMemVeyeinhead := MemChan(kRealWave,0,BinSize(gChVeye1)); 'computed vert eye in head trace (gaze-head) ChanShow(gChMemHeyeinhead); ChanShow(gChMemVeyeinhead); endif if pVergenceData = kTrue then gChMemHeyeVergence := MemChan(kRealWave,0,BinSize(gChHeye1)); 'computed horz right-left eye gChMemVeyeVergence := MemChan(kRealWave,0,BinSize(gChHeye1)); 'computed vert right-left eye 'ChanShow(gChMemHeyeVergence); 4/12/06 'ChanShow(gChMemVeyeVergence); 4/12/06 endif 'configure the CED channels '-------------------------- DrawMode(gChKeyboard,1); 'show as text not vertical lines ChanHide(gChKeyboard); '9/7/04 Noto DrawMode(gChEvents,1); 'shows sequencer MARK stamps ChanShow(gChEvents); docase case gLastMode% = kMemory then MarkMask(gChEvents,-1,1,-1); 'all layers, include, all codes MarkMask(gChEvents,0,-1,-1); 'layer 0, invert, all codes, MarkMask(gChEvents,0,1, 00,01,35,47,64,65,66,67,68,69,71,72,92,97); '00 01 # / @ A B C D E G H \ a" marker filter leaves these in case gLastMode% = kAdapt then MarkMask(gChEvents,-1,1,-1); 'all layers, include, all codes MarkMask(gChEvents,0,-1,-1); 'layer 0, invert, all codes, MarkMask(gChEvents,0,1, 01,47,63,64,92); '01 / ? @ \" marker filter leaves these in case gLastMode% = kStatic then MarkMask(gChEvents,-1,1,-1); 'all layers, include, all codes MarkMask(gChEvents,0,-1,-1); 'layer 0, invert, all codes, MarkMask(gChEvents,0,1, 01,47,63,64,92); '"/ ? @ \ 01" marker filter leaves these in case gLastMode% = kThreeSpot then MarkMask(gChEvents,-1,1,-1); 'all layers, include, all codes MarkMask(gChEvents,0,-1,-1); 'layer 0, invert, all codes, MarkMask(gChEvents,0,1, 00,01,02,47,62,60,33,65,66,67,97,98,99); '"00 01 02 @ > < ! A B C a b c" marker filter leaves these in else ChanHide(gChEvents); 'don't show the event channel endcase ' if kBobMode then ' MarkMask(gChEvents,-1,1,-1); 'all layers, include, all codes ' MarkMask(gChEvents,0,-1,-1); 'layer 0, invert, all codes, ' MarkMask(gChEvents,0,1, 43,63,94); '+?#^ marker filter leaves these in ' endif 'duplicate event channels are used to show shuttering of the two targets if gLastMode% = kMemory then' gChShutter1on := ChanDuplicate(gChEvents); 'create a duplicate MarkMask(gChShutter1on, 0, 0, -1); 'exclude everything in layer 0 MarkMask(gChShutter1on, 0, 1, 0, 1, "N"); 'include the codes we want MarkMask(gChShutter1on, 0, 0, 0, chr$(1)); 'exclude everything in layer 0 ChanColour(gChShutter1on, 1, 16); 'red ChanTitle$(gChShutter1on,"Shut1"); ChanHide(gChShutter1on); 'make visible gChShutter1off := ChanDuplicate(gChEvents); 'create a duplicate MarkMask(gChShutter1off, 0, 0, -1); 'exclude everything in layer 0 MarkMask(gChShutter1off, 0, 1, 0, 1, "F"); 'include the codes we want MarkMask(gChShutter1off, 0, 0, 0, chr$(1)); 'exclude everything in layer 0 ChanColour(gChShutter1off, 1, 16); 'red ChanTitle$(gChShutter1off,"Shut1"); ChanHide(gChShutter1off); 'make visible gChShutter2on := ChanDuplicate(gChEvents); 'create a duplicate MarkMask(gChShutter2on, 0, 0, -1); 'exclude everything in layer 0 MarkMask(gChShutter2on, 0, 1, 0, 1, "n"); 'include the codes we want MarkMask(gChShutter2on, 0, 0, 0, chr$(1)); 'exclude everything in layer 0 ChanColour(gChShutter2on, 1, kSecondTargColor); 'grn ChanTitle$(gChShutter2on,"Shut2"); ChanHide(gChShutter2on); 'make visible gChShutter2off := ChanDuplicate(gChEvents); 'create a duplicate MarkMask(gChShutter2off, 0, 0, -1); 'exclude everything in layer 0 MarkMask(gChShutter2off, 0, 1, 0, 1, "f"); 'include the codes we want MarkMask(gChShutter2off, 0, 0, 0, chr$(1)); 'exclude everything in layer 0 ChanColour(gChShutter2off, 1, kSecondTargColor); 'grn ChanTitle$(gChShutter2off,"Shut2"); ChanHide(gChShutter2off); 'make visible gChShutter1status := MemChan(kWaveForm, 0, 0.001); 'create a waveform ch ChanWeight(gChShutter1status, 0.05); ChanColour(gChShutter1status, 1, 16); 'red ChanTitle$(gChShutter1status,"Shut1status"); YRange(gChShutter1status,-1,1); ChanShow(gChShutter1status); 'make visible gChShutter2status := MemChan(kWaveForm, 0, 0.001); 'create a waveform ch ChanWeight(gChShutter2status, 0.05); ChanColour(gChShutter2status, 1, kSecondTargColor);'grn ChanTitle$(gChShutter2status,"Shut2status"); YRange(gChShutter2status,-1,1); ChanShow(gChShutter2status); 'make visible endif 'set up the unit channels '------------------------ if gUnitData > 0 then '0=no unit, 1=50k, 2=multi 'prepare a spike monitor window gChSpikeWM% := MemChan(6,gSpikeWidthWM,binsize(gChUnit),gSpikePreWM); 'create a wavemark ch for spike monitor DrawMode(gChSpikeWM%,2); 'noto 1.10.06 draw as lines ChanScale(gChSpikeWM%, ChanScale(1)); ChanOffset(gChSpikeWM%, ChanOffset(1)); ChanUnits$(gChSpikeWM%, ChanUnits$(1)); ChanTitle$(gChSpikeWM%, "Accept Spk"); ChanShow(gChSpikeWM%); if (gSpikeScopeActive% = 1) and (gLastMode% <> kCalibrate) then gSpikeWindow% := SMopen(1,1); 'spike monitor SMcontrol(0, 2); 'two dimensional SMcontrol(8, 10); 'max 10 spikes SMcontrol(9, 0.15); 'time range = 0.15 SMcontrol(10, 0); 'no display rectangles 'var i%,a%; 'for i% := 0 to 14 do ' a% := smcontrol(i%); ' a% := a%; 'next Window(gSpikeX1,gSpikeY1,gSpikeX2,gSpikeY2); 'Make data monitor window in lower-left part of screen FrontView(gDataWindow%); '5/4/06 Noto wants this window on top so it responds to the 's' key stimulation endif View(gDataWindow%); ' gChFreq := MemChan(kEventPlus,0,BinSize(gChUnit)); gChFreq := ChanDuplicate(gChSpikeWM%); 'duplicate the spike wavemark to draw the frequency ChanTitle$(gChFreq,"Instant Freq"); ChanUnits$(gChFreq,"Hz"); DrawMode(gChFreq,7,3); 'Dot size 3 ChanShow(gChFreq); YRange(gChFreq, 0, 1000); 'show spikes as frequency ' MemImport(gChFreq,gChSpikeWM%,gLastProcessUnit,aCurrentTime); ' MemImport(gChFreq,gChSpikeWM%,0,maxtime()); ' ProcessAuto(0.001,0); 'make the frequency update automatically ChanTitle$(gChUnit,"Unit"); gCursorAccept := HCursorNew(gChUnit, pUnitCursor); 'horiz cursor: acceptance pulse threshold SetUnitTraceScales(); 'YRange(gChUnit, pUnitLo, pUnitHi); endif 'set up the analog channels '---------------------------- ChanScale(gChHeye1, 20); 'set the ±32k bit range represents 20 volts 'YRange(gChHeye1, -21, 21); ChanColour(gChHeye1, 1, 0); 'black ChanUnits$(gChHeye1,"deg"); DrawMode(gChHeye1,pTraceStyleAnimal); ChanColour(gChHvel, 1, 0); 'black ChanUnits$(gChHvel,"deg/s"); ChanHide(gChHvel); DrawMode(gChHvel,pTraceStyleAnimal); ChanScale(gChVeye1, 20); 'set the ±32k bit range represents 20 volts 'YRange(gChVeye1, -21, 21); ChanColour(gChVeye1, 1, 0); 'black ChanUnits$(gChVeye1,"deg"); DrawMode(gChVeye1,pTraceStyleAnimal); ChanColour(gChVvel, 1, 0); 'black ChanUnits$(gChVvel,"deg/s"); ChanHide(gChVvel); DrawMode(gChVvel,pTraceStyleAnimal); ChanScale(gChHtarg1, 20); 'set the ±32k bit range represents 20 volts 'YRange(gChHtarg1, -21, 21); ChanColour(gChHtarg1, 1, 16); 'red ChanUnits$(gChHtarg1,"deg"); DrawMode(gChHtarg1,pTraceStyleTarget); ChanScale(gChVtarg1, 20); 'set the ±32k bit range represents 20 volts 'YRange(gChVtarg1, -21, 21); ChanColour(gChVtarg1, 1, 16); 'red ChanUnits$(gChVtarg1,"deg"); DrawMode(gChVtarg1,pTraceStyleTarget); YRange(gChMemRectVel, 0, 1000); ChanColour(gChMemRectVel, 1, 25); 'purple ChanTitle$(gChMemRectVel,"Rect Vel"); ChanUnits$(gChMemRectVel,"deg/s"); DrawMode(gChMemRectVel,pTraceStyleAnimal); SetVelocityChannels(); '7/8/05 for Noto 'if gMultiTargets = kTrue then ChanScale(gChHtarg2, 20); 'set the ±32k bit range represents 20 volts 'YRange(gChHtarg2, -21, 21); ChanColour(gChHtarg2, 1, kSecondTargColor); 'grn ChanUnits$(gChHtarg2,"deg"); DrawMode(gChHtarg2,pTraceStyleTarget); ChanScale(gChVtarg2, 20); 'set the ±32k bit range represents 20 volts 'YRange(gChVtarg2, -21, 21); ChanColour(gChVtarg2, 1, kSecondTargColor); 'grn ChanUnits$(gChVtarg2,"deg"); DrawMode(gChVtarg2,pTraceStyleTarget); 'endif if pGazeData = kTrue then ChanScale(gChHhead, 20); 'set the ±32k bit range represents 20 volts YRange(gChHhead, -21, 21); ChanColour(gChHhead, 1, kSecondTargColor); 'grn ChanUnits$(gChHhead,"deg"); DrawMode(gChHhead,pTraceStyleAnimal); ChanScale(gChVhead, 20); 'set the ±32k bit range represents 20 volts YRange(gChVhead, -21, 21); ChanColour(gChVhead, 1, kSecondTargColor); 'grn ChanUnits$(gChVhead,"deg"); DrawMode(gChVhead,pTraceStyleAnimal); ChanScale(gChMemHeyeinhead, 20); 'set the ±32k bit range represents 20 volts YRange(gChMemHeyeinhead, -21, 21); ChanColour(gChMemHeyeinhead, 1, 25); 'purple ChanUnits$(gChMemHeyeinhead,"deg"); DrawMode(gChMemHeyeinhead,pTraceStyleAnimal); ChanScale(gChMemVeyeinhead, 20); 'set the ±32k bit range represents 20 volts YRange(gChMemVeyeinhead, -21, 21); ChanColour(gChMemVeyeinhead, 1, 25); 'purple ChanUnits$(gChMemVeyeinhead,"deg"); DrawMode(gChMemVeyeinhead,pTraceStyleAnimal); endif if pVergenceData = kTrue then ChanScale(gChHeye2, 20); 'set the ±32k bit range represents 20 volts 'YRange(gChHeye2, -21, 21); ChanColour(gChHeye2, 1, 13); 'blue ChanUnits$(gChHeye2,"deg"); DrawMode(gChHeye2,pTraceStyleAnimal); ChanScale(gChVeye2, 20); 'set the ±32k bit range represents 20 volts 'YRange(gChVeye2, -21, 21); ChanColour(gChVeye2, 1, 13); 'blue ChanUnits$(gChVeye2,"deg"); DrawMode(gChVeye2,pTraceStyleAnimal); ChanColour(gChMemHeyeVergence, 1, 0); 'black YRange(gChMemHeyeVergence, -21, 21); ChanUnits$(gChMemHeyeVergence,"deg"); ChanTitle$(gChMemHeyeVergence,"H Verg"); DrawMode(gChMemHeyeVergence,pTraceStyleAnimal); HCursorNew(gChMemHeyeVergence, 0.0); 'for comparison ChanColour(gChMemVeyeVergence, 1, 0); 'black YRange(gChMemVeyeVergence, -21, 21); ChanUnits$(gChMemVeyeVergence,"deg"); ChanTitle$(gChMemVeyeVergence,"V Verg"); DrawMode(gChMemVeyeVergence,pTraceStyleAnimal); HCursorNew(gChMemVeyeVergence, 0.0); 'for comparison endif if pGeneralData910% = kTrue then ChanScale(gChAux1, 20); 'set the ±32k bit range represents 20 volts YRange(gChAux1, -21, 21); ChanColour(gChAux1, 1, 13); 'blue ChanUnits$(gChAux1,"deg"); DrawMode(gChAux1,pTraceStyleAnimal); ChanHide(gChAux1); ChanScale(gChAux2, 20); 'set the ±32k bit range represents 20 volts YRange(gChAux2, -21, 21); ChanColour(gChAux2, 1, 13); 'blue ChanUnits$(gChAux2,"deg"); DrawMode(gChAux2,pTraceStyleAnimal); ChanHide(gChAux2); endif if pSampleCh1112% = kTrue then ChanScale(gChAux3, 20); 'set the ±32k bit range represents 20 volts YRange(gChAux3, -21, 21); ChanColour(gChAux3, 1, 13); 'blue ChanUnits$(gChAux3,"deg"); DrawMode(gChAux3,pTraceStyleAnimal); ChanHide(gChAux3); ChanScale(gChAux4, 20); 'set the ±32k bit range represents 20 volts YRange(gChAux4, -21, 21); ChanColour(gChAux4, 1, 13); 'blue ChanUnits$(gChAux4,"deg"); DrawMode(gChAux4,pTraceStyleAnimal); ChanHide(gChAux4); endif if pSampleCh13% = kTrue then ChanScale(gChAux5, 20); 'set the ±32k bit range represents 20 volts YRange(gChAux5, -21, 21); ChanColour(gChAux5, 1, 13); 'blue ChanUnits$(gChAux5,"deg"); DrawMode(gChAux5,pTraceStyleAnimal); ChanHide(gChAux5); endif 'position the channels on the screen in a convenient order '--------------------------------------------------------- '-1=drop before 0=drop on 1=drop after ChanOrder(-1); 'arrange in order: lowest at top, highest at bottom if gUnitData = 1 then aFirstCh := gChUnit; else aFirstCh := gChHeye1; endif if gLastMode% = kMemory then ChanOrder(aFirstCh,-1,gChShutter1status); ChanOrder(aFirstCh,-1,gChShutter2status); endif ChanOrder(aFirstCh,-1,gChKeyboard); 'ch to move around - how far to move - which ch to move ChanOrder(aFirstCh,-1,gChEvents); 'ch to move around - how far to move - which ch to move ChanOrder(gChHeye1,0,gChHtarg1); 'ch to move around - how far to move - which ch to move ChanOrder(gChVeye1,0,gChVtarg1); 'ch to move around - how far to move - which ch to move if pVergenceData = kTrue then ChanOrder(gChHeye1, 0, gChHeye2); 'ch to move around - how far to move - which ch to move ChanOrder(gChVeye1, 0, gChVeye2); 'ch to move around - how far to move - which ch to move endif if gMultiTargets = kTrue then ChanOrder(gChHeye1, 0, gChHtarg2); 'ch to move around - how far to move - which ch to move ChanOrder(gChVeye1, 0, gChVtarg2); 'ch to move around - how far to move - which ch to move else ChanHide(gChHtarg2); 'hide unneeded ch so the targets are as big as possible ChanHide(gChVtarg2); endif if pGazeData = kTrue then ChanOrder(gChHeye1, 0, gChMemHeyeinhead); 'ch to move around - how far to move - which ch to move ChanOrder(gChVeye1, 0, gChMemVeyeinhead); 'ch to move around - how far to move - which ch to move ChanOrder(gChHeye1, 0, gChHhead); 'ch to move around - how far to move - which ch to move ChanOrder(gChVeye1, 0, gChVhead); 'ch to move around - how far to move - which ch to move endif if gUnitData > 0 then '0=no unit, 1=50k, 2=100k ChanOrder(gChFreq,+1,gChUnit); 'ch to move around - how far to move - which ch to move ChanOrder(gChFreq,+1,gChSpikeWM%); 'ch to move around - how far to move - which ch to move endif 'chanorder(); 'lock Y scale for the traces '------------------------ Yaxislock(gChHeye1,1); 'lock the grouped traces Yaxislock(gChVeye1,1); var howmany; howmany := chanorder(gChHtarg1,0); howmany := chanorder(gChVtarg1,0); if gLastMode% = kCalibrate then grid(1); 'display the grid to make it easier to calibrate YAxisMode(4+4096); 'hide small ticks & put scale marks on right side YAxisStyle(-1, 0, 10); 'grid every 10 degrees XAxisMode(4); 'hide small ticks XAxisStyle(1, 0, 1); 'seconds, automatic, grid every 1 second ChanHide(gChHeye1); 'the eye positions are unnecessary in calibrate ChanHide(gChVeye1); Yaxislock(gChHtarg1,1); 'have to re-lock the grouped traces now that the eye traces have been hidden Yaxislock(gChVtarg1,1); if gUnitData > 0 then '0=no unit, 1=50k, 2=100k ChanHide(gChUnit); 'remove unneeded ch so the targets are as big as possible ChanHide(gChFreq); ChanHide(gChSpikeWM%); endif if pGazeData = kTrue then ChanHide(gChHhead); 'remove unneeded ch so the targets are as big as possible ChanHide(gChVhead); 'remove unneeded ch so the targets are as big as possible ChanHide(gChMemHeyeinhead); 'remove unneeded ch so the targets are as big as possible ChanHide(gChMemVeyeinhead); 'remove unneeded ch so the targets are as big as possible endif endif if gLastMode% = kThreeSpot then ChanShow(gChHtarg2); 'the center positions are necessary in threespot ChanShow(gChVtarg2); ChanOrder(gChHeye1, 0, gChHtarg2); 'ch to move around - how far to move - which ch to move ChanOrder(gChVeye1, 0, gChVtarg2); 'ch to move around - how far to move - which ch to move Yaxislock(gChHtarg1,1); 'have to re-lock the grouped traces now that the eye traces have been hidden Yaxislock(gChVtarg1,1); endif howmany := chanorder(gChHtarg1,0); howmany := chanorder(gChVtarg1,0); SetTraceWeights(); 'for programming purposes '------------------------ if kBOBmode = kTrue then ChanShow(gChHvel); ChanShow(gChVvel); ChanShow(gChEvents); ChanHide(gChKeyboard); PresentDebugWindow(); ' gDebugWindow% := FileNew(1); ' Window(gDebugX1,gDebugY1,gDebugX2,gDebugY2); 'Make data window in top bit of screen ' WindowTitle$("Debug Window"); ' FrontView(gDataWindow%); ' FrontView(gDebugWindow%); endif 'prepare the toolbar '------------------- ToolbarEnable(gReLaunchButton,0); 'Disable "Sample stop" button return 1; end 'New '---------------------------------------------------- ' PresentDebugWindow ' '7/24/06 '---------------------------------------------------- func PresentDebugWindow() if ViewKind(gDebugWindow%) < 0 then 'allows program to run without a 1401 connected to it gDebugWindow% := FileNew(1); Window(gDebugX1,gDebugY1,gDebugX2,gDebugY2); 'Make data window in top bit of screen WindowTitle$("Debug Window"); endif FrontView(gDataWindow%); FrontView(gDebugWindow%); ' else ' view(gDebugWindow%); 'window has been made, just ' endif end 'PresentDebugWindow '---------------------------------------------------- ' SearchMode ' '4/27/06 '---------------------------------------------------- func ModeSearch%() ' SampleSeqVar(sMODE, 0); MyFileClose(gEditPlot%, 0); 'close & query the last edit file View(gCollisionWindow%); XYDelete(2); ' ToolbarEnable(gIncButton,1); ' ToolbarEnable(gDecButton,1); ' ToolbarEnable(gAcceptButton,0); ' ToolbarEnable(gPrevButton,0); ' ToolbarEnable(gNextButton,0); ' ToolbarEnable(gSearchButton,0); ' ToolbarEnable(gCollisionButton,1); ' ToolbarEnable(gEditButton,0); ' gChangeParam := 1; return 1; end 'ModeSearch '---------------------------------------------------- ' ModeCollision ' '4/27/06 '---------------------------------------------------- func ModeCollision%() ' SampleSeqVar(sMODE, 1); MyFileClose(gEditPlot%, 0); 'close & query the last edit file View(gCollisionWindow%); XYDelete(2); ' ToolbarEnable(gIncButton,1); ' ToolbarEnable(gDecButton,1); ' ToolbarEnable(gAcceptButton,0); ' ToolbarEnable(gPrevButton,0); ' ToolbarEnable(gNextButton,0); ' ToolbarEnable(gSearchButton,1); ' ToolbarEnable(gCollisionButton,0); ' ToolbarEnable(gEditButton,1); ' gChangeParam := 1; return 1; end 'ModeCollision '---------------------------------------------------- ' ModeEdit ' '4/27/06 '---------------------------------------------------- func ModeEdit%() var aDataXdel[(pStimBefore+pStimAfter)*gSamplesPerMS+1], aDataYdel[(pStimBefore+pStimAfter)*gSamplesPerMS+1], plotX1 := 25, plotY1 := 0, plotX2 := 100, plotY2 := 50, aStr$; ' SampleSeqVar(sMODE, 2); ' ToolbarEnable(gIncButton,0); ' ToolbarEnable(gDecButton,0); ' ToolbarEnable(gAcceptButton,1); ' ToolbarEnable(gPrevButton,1); ' ToolbarEnable(gNextButton,1); ' ToolbarEnable(gSearchButton,1); ' ToolbarEnable(gCollisionButton,1); ' ToolbarEnable(gEditButton,0); 'create the edit window '----------------------- gEditN := 0; gEditPlot% := FileNew(12,1); 'prepare to plot the spike traces aStr$ := gSubject$ + " --- Select --- "; WindowTitle$(aStr$); Window(plotX1,plotY1,plotX2,plotY2); 'Make data window in top bit of screen WindowRange(gEditPlot%); '2.16.05 turn off auto-scaling 'XYDrawMode(1,5,1); 'auto axis range mode XYDrawMode(-1,5,0); 'auto axis range mode explicitly off XYDrawMode(1,2,0); 'no dots XYjoin(1,1); 'join with lines XYcolour(1,16); 'red 'prepare a channel for highlighting/deleting a trace view(gCollisionWindow%); XYsetChan(0); '2.16.05 turn off auto-scaling 'XYDrawMode(2,5,1); 'auto axis range mode XYDrawMode(-1,5,0); 'auto axis range mode explicitly off XYDrawMode(2,2,3); 'medium dots XYcolour(2,0); 'black gCurrentAnchor := 0; gBackwardAnchor := gCurrentAnchor - ((pStimBefore+pStimAfter)*gSamplesPerMS+1); gForwardAnchor := gCurrentAnchor + (pStimBefore+pStimAfter)*gSamplesPerMS+1; XYGetData(1, aDataXdel[], aDataYdel[], 0, (pStimBefore+pStimAfter)*gSamplesPerMS); XYAddData(2, aDataXdel[], aDataYdel[]); LogUpdate(); 'gChangeParam := 1; return 1; end 'ModeCollision '---------------------------------------------------- ' LogUpdate '4/27/06 '---------------------------------------------------- proc LogUpdate() var aLatency, aMode, aHiDur, aLoDur, aDeadTime; ' aLatency := SampleSeqVar(sLATENCY)/100.0; ' aMode := SampleSeqVar(sMODE); ' aHiDur := SampleSeqVar(sHIDUR)/100.0; ' aLoDur := SampleSeqVar(sLODUR)/100.0; View(LogHandle()); 'Make log view the current view EditSelectAll(); 'Select all text in log view EditClear(); 'Delete it if aMode = 0 then PrintLog("S E A R C H M O D E\n"); PrintLog("Time zero = Stim Pulse\n"); PrintLog("Collision latency = ", aLatency, " ms (inactive)"); PrintLog("Stim pulse HIGH dur = ", aHiDur, " ms"); PrintLog("Stim pulse LOW dur = ", aLoDur, " ms"); PrintLog("\n"); PrintLog("Event Marks\n"); 'PrintLog(" .T = Incoming trigger detected\n"); PrintLog(" .S = Stimulation pulse sent\n"); endif if aMode = 1 then PrintLog("C O L L I S I O N M O D E\n"); PrintLog("Time zero = Spontaneous Pulse\n"); PrintLog("Collision latency = ", aLatency, " ms"); PrintLog("Stim pulse HIGH dur = ", aHiDur, " ms"); PrintLog("Stim pulse LOW dur = ", aLoDur, " ms (min)"); PrintLog("\n"); PrintLog("Event Marks\n"); PrintLog(" .T = Incoming trigger detected\n"); PrintLog(" .S = Stimulation pulse sent\n"); endif if aMode = 2 then PrintLog("E D I T M O D E\n"); endif end 'LogUpdate '---------------------------------------------------- ' WindowRange '4/27/06 '---------------------------------------------------- proc WindowRange(theWindow%) 'called for ' gCollisionWindow% and ' gEditWindow% View(theWindow%); XRange(-pStimBefore/1000-0.0005, pStimAfter/1000+0.0005); 'loX,hiX end 'WindowRange '---------------------------------------------------- ' ResetPlotCollision '4/28/06 '---------------------------------------------------- func ResetPlotCollision%() var aStr$; View(gCollisionWindow%); XYdelete(1); 'delete all points gCollisionN := 0; TitleCollision(); return kTrue; 'Stay in toolbar end 'ResetPlotCollision '---------------------------------------------------- ' TitleCollision ' 'Updates information displayed in the collision plot 'title bar. '4/27/06 '---------------------------------------------------- proc TitleCollision() var aStr$; View(gCollisionWindow%); docase case pStimType% = 1 then aStr$ := gSubject$ + Str$(gCollisionN) + " --- Time = " + Str$(gCollisionPlotLast) + " --- Stimulation interval = " + str$( pStimInterval) + " ms"; case pStimType% = 2 then aStr$ := gSubject$ + Str$(gCollisionN) + " --- Time = " + Str$(gCollisionPlotLast) + " --- Collision latency = " + str$( pCollisionLatency / 100) + " ms"; endcase WindowTitle$(aStr$); end 'TitleCollision '---------------------------------------------------- ' SetVelocityChannels ' 'The velocity input calibration is: ' 1 volt = 10 deg/sec for Ramp ' 1 volt = 100 deg/sec for all other modes '4/15/03 '---------------------------------------------------- proc SetVelocityChannels() if ViewKind(gDataWindow%) >= 0 then 'allows program to run without a 1401 connected to it View(gDataWindow%); docase case gLastMode% = kRamp then ChanScale(gChHvel, 20); ChanScale(gChVvel, 20); YRange(gChHvel,-100,100); YRange(gChVvel,-100,100); else ChanScale(gChHvel, 200); ChanScale(gChVvel, 200); YRange(gChHvel,-1000,1000); YRange(gChVvel,-1000,1000); endcase endif end; 'SetVelocityChannels '---------------------------------------------------- ' Start '11/22/02 '---------------------------------------------------- func Start%() var numPtsShownPerCh%, aTraceNum%, report%; report% := SampleStart(0); 'Start sampling 'Enable ToolbarEnable(gStaticbutton,1); ToolbarEnable(gSinebutton,1); ToolbarEnable(gRampButton,1); ToolbarEnable(gThreeSpotButton,1); ToolbarEnable(gAdaptButton,1); ToolbarEnable(gRadialButton,1); ToolbarEnable(gXYbutton,1); ToolbarEnable(gCalibrateButton,1); ToolbarEnable(gAnalysisButton,1); ToolbarEnable(gRewardButton,1); ToolbarEnable(gReLaunchButton,1); ToolbarEnable(gMemoryButton,1); ToolbarEnable(gPrefOpenButton,1); ToolbarEnable(gPrefSaveButton,1); if gSpotScopeActive% = 1 then 'set up the scope view View(gDataWindow%); gSpotWindow% := MeasureToXY(14,gChHeye1,0); '0=full speed, create the XY view and measurement process Window(gSpotX1,gSpotY1,gSpotX2,gSpotY2); 'make the reticle square 'arrange it like this so the EYE can be seen on top of the TARGET numPtsShownPerCh% := 2; MeasureX(100,gChHtarg1,"Cursor(0)"); MeasureY(100,gChVtarg1,"Cursor(0)"); MeasureChan(1,"Tar1Pos",numPtsShownPerCh%); 'the first XY channel = TARGET MeasureX(100,gChHeye1,"Cursor(0)"); MeasureY(100,gChVeye1,"Cursor(0)"); MeasureChan(0,"EyePos",numPtsShownPerCh%); 'add a new XY hannel = EYE if gMultiTargets = kTrue then MeasureX(100,gChHtarg2,"Cursor(0)"); MeasureY(100,gChVtarg2,"Cursor(0)"); MeasureChan(0,"Tar2Pos",numPtsShownPerCh%); 'add a new XY channel = TARGET 2 endif if pVergenceData = kTrue then MeasureX(100,gChHeye2,"Cursor(0)"); MeasureY(100,gChVeye2,"Cursor(0)"); MeasureChan(0,"Eye2Pos",numPtsShownPerCh%); 'add a new XY channel = EYE 2 endif WindowVisible(1); WindowTitle$("SpotScope"); if kBOBmode = kTrue then WindowVisible(0); endif ProcessAuto(0.001,0,0,0,0); YAxisStyle(-1, 2, 5); XAxisStyle(1, 2, 5); Grid(1); aTraceNum% := 1; XYColour(aTraceNum%,16); 'target1 color = red XYDrawMode(aTraceNum%,1,0); 'target1 dots XYDrawMode(aTraceNum%,2,kSpotLg%); 'target1 point size XYDrawMode(aTraceNum%,4,0); 'target1 line size XYkey(aTraceNum%,0); 'key off aTraceNum% := aTraceNum% + 1; XYColour(aTraceNum%,0); 'eye color = black XYDrawMode(aTraceNum%,1,0); 'eye dots XYDrawMode(aTraceNum%,2,kSpotLg%); 'eye point size XYDrawMode(aTraceNum%,4,0); 'eye line size XYkey(aTraceNum%,0); 'key off if gMultiTargets = kTrue then 'if aBackground% = kTrue then aTraceNum% := aTraceNum% + 1; XYColour(aTraceNum%,kSecondTargColor); 'target2 color = green XYDrawMode(aTraceNum%,1,0); 'target2 dots XYDrawMode(aTraceNum%,2,kSpotLg%); 'target2 point size XYDrawMode(aTraceNum%,4,0); 'target2 line size XYkey(aTraceNum%,0); endif if pVergenceData = kTrue then aTraceNum% := aTraceNum% + 1; XYColour(aTraceNum%,13); 'eye color = blue XYDrawMode(aTraceNum%,1,0); 'eye dots XYDrawMode(aTraceNum%,2,kSpotLg%); 'eye point size XYDrawMode(aTraceNum%,4,0); 'eye line size XYkey(aTraceNum%,0); 'key off endif endif 'if gSpotScopeActive% = 1 return kTrue; 'Stay with toolbar end 'Start '---------------------------------------------------- ' Stop '11/22/02 '---------------------------------------------------- func Stop%() 'If "Stop" is pressed SampleStop(); 'Stop sampling SaveLastDataFile(); PreferencesSave%(kTrue); gLastMode% := kInvalid; InitializeForNewSubject(); return kTrue; 'Stay in toolbar end 'Stop '---------------------------------------------------- ' GetWindowPositions 'Function calls from buttons cannot have arguments. '3/29/05 '---------------------------------------------------- proc GetWindowPositions() const kTooSmall% := 10; var aaa%, bbb%, aPlot%, aX1,aX2,aY1,aY2; 'get log window position and size view(app(0)); WindowGetPos(aX1,aY1,aX2,aY2); gAppX1 := aX1; gAppY1 := aY1; gAppX2 := aX2; gAppY2 := aY2; 'get log window position and size if ViewKind(LogHandle()) >= 0 then View(LogHandle()); 'Make log view the current view WindowGetPos(aX1,aY1,aX2,aY2); if aX2 - aX1 > kTooSmall% and aY2-aY1 > kTooSmall% then 'never save a very small log view, can't get'em view them gLogX1 := aX1; gLogY1 := aY1; gLogX2 := aX2; gLogY2 := aY2; endif endif 'get scrolling data window position and size if ViewKind(gDataWindow%) >= 0 then View(gDataWindow%); 'Make the data view the current view WindowGetPos(aX1,aY1,aX2,aY2); if aX2 - aX1 > kTooSmall% and aY2-aY1 > kTooSmall% then 'never save a very small Data view, can't get'em view them gDataX1 := aX1; gDataY1 := aY1; gDataX2 := aX2; gDataY2 := aY2; endif endif 'get spot scope position and size if ViewKind(gSpotWindow%) >= 0 then View(gSpotWindow%); 'Make the data view the current view WindowGetPos(aX1,aY1,aX2,aY2); if aX2 - aX1 > kTooSmall% and aY2-aY1 > kTooSmall% then 'never save a very small Spot view, can't get'em view them gSpotX1 := aX1; gSpotY1 := aY1; gSpotX2 := aX2; gSpotY2 := aY2; endif endif 'get debug window position and size if ViewKind(gDebugWindow%) >= 0 then View(gDebugWindow%); 'Make the data view the current view WindowGetPos(gDebugX1,gDebugY1,gDebugX2,gDebugY2); WindowGetPos(aX1,aY1,aX2,aY2); if aX2 - aX1 > kTooSmall% and aY2-aY1 > kTooSmall% then 'never save a very small Debug view, can't get'em view them gDebugX1 := aX1; gDebugY1 := aY1; gDebugX2 := aX2; gDebugY2 := aY2; endif endif 'get Spike scope position and size if ViewKind(gSpikeWindow%) >= 0 then View(gSpikeWindow%); 'Make the data view the current view WindowGetPos(aX1,aY1,aX2,aY2); if aX2 - aX1 > kTooSmall% and aY2-aY1 > kTooSmall% then 'never save a very small Spike view, can't get'em view them gSpikeX1 := aX1; gSpikeY1 := aY1; gSpikeX2 := aX2; gSpikeY2 := aY2; endif endif 'update the parameters by determining which plots are still shown and where they are, some may have been user-deleted 'XY plots and single window histograms for aPlot% := 0 to kMaxPlots%+kMaxBinPlots%+kEvokedPlots%-1 do bbb% := gAnalHandle%[aPlot%]; aaa% := ViewKind(gAnalHandle%[aPlot%]); if ViewKind(gAnalHandle%[aPlot%]) <> 12 then gAnalHandle%[aPlot%] := -1; gAnalPlotSelect%[aPlot%] := kFalse; else View(gAnalHandle%[aPlot%]); WindowGetPos(aX1,aY1,aX2,aY2); if aX2 - aX1 > kTooSmall% and aY2-aY1 > kTooSmall% then 'never save a very small log view, can't get'em view them gAnalWinSize[aPlot%][0] := aX1; gAnalWinSize[aPlot%][1] := aY1; gAnalWinSize[aPlot%][2] := aX2; gAnalWinSize[aPlot%][3] := aY2; endif endif next 'eight window histogram windows for aPlot% := 0 to kMaxVectors% - 1 do if ViewKind(gHistoHandle%[aPlot%]) <> 12 then gHistoHandle%[aPlot%] := -1; else View(gHistoHandle%[aPlot%]); WindowGetPos(aX1,aY1,aX2,aY2); if aX2 - aX1 > kTooSmall% and aY2-aY1 > kTooSmall% then 'never save a very small log view, can't get'em view them gHistoWinSize[aPlot%][0] := aX1; gHistoWinSize[aPlot%][1] := aY1; gHistoWinSize[aPlot%][2] := aX2; gHistoWinSize[aPlot%][3] := aY2; endif endif next 'get Tragectory position and size if ViewKind(gTragectoryHandle%) >= 0 then View(gTragectoryHandle%); 'Make the data view the current view WindowGetPos(aX1,aY1,aX2,aY2); if aX2 - aX1 > kTooSmall% and aY2-aY1 > kTooSmall% then 'never save a very small view, can't get'em view them gTragectoryX1 := aX1; gTragectoryY1 := aY1; gTragectoryX2 := aX2; gTragectoryY2 := aY2; endif endif 'if ViewKind(gComplexHandle%) < 0 then 'NOTE: the complex plot is always H=50% V=100% end 'GetAnalysisWindowPositions '---------------------------------------------------- ' SetWindowPositions 'Position all the windows except the on-line analysis 'windows. '5/23/05 '---------------------------------------------------- proc SetWindowPositions() var aPlot%, aX1,aY1,aX2,aY2; 'Set log window position and size view(app(0)); window(gAppX1,gAppY1,gAppX2,gAppY2); 'Set log window position and size if ViewKind(LogHandle()) >= 0 then View(LogHandle()); 'Make log view the current view window(gLogX1,gLogY1,gLogX2,gLogY2); endif 'Set scrolling data window position and size if ViewKind(gDataWindow%) >= 0 then View(gDataWindow%); 'Make the data view the current view window(gDataX1,gDataY1,gDataX2,gDataY2); endif 'Set spot scope position and size if ViewKind(gSpotWindow%) >= 0 then View(gSpotWindow%); 'Make the data view the current view window(gSpotX1,gSpotY1,gSpotX2,gSpotY2); endif 'Set debug window position and size if ViewKind(gDebugWindow%) >= 0 then View(gDebugWindow%); 'Make the data view the current view window(gDebugX1,gDebugY1,gDebugX2,gDebugY2); endif 'Set Spike scope position and size if ViewKind(gSpikeWindow%) >= 0 then View(gSpikeWindow%); 'Make the data view the current view window(gSpikeX1,gSpikeY1,gSpikeX2,gSpikeY2); endif 'XY plots and single window histograms for aPlot% := 0 to kMaxPlots%+kMaxBinPlots%+kEvokedPlots%-1 do 'if ViewKind(gAnalHandle%[aPlot%]) > 0 then if ViewKind(gAnalHandle%[aPlot%]) = 12 then View(gAnalHandle%[aPlot%]); aX1 := gAnalWinSize[aPlot%][0]; aY1 := gAnalWinSize[aPlot%][1]; aX2 := gAnalWinSize[aPlot%][2]; aY2 := gAnalWinSize[aPlot%][3]; window(aX1,aY1,aX2,aY2); endif next 'eight window histogram windows for aPlot% := 0 to kMaxVectors% - 1 do 'if ViewKind(gHistoHandle%[aPlot%]) < 0 then if ViewKind(gHistoHandle%[aPlot%]) = 12 then View(gHistoHandle%[aPlot%]); aX1 := gHistoWinSize[aPlot%][0]; aY1 := gHistoWinSize[aPlot%][1]; aX2 := gHistoWinSize[aPlot%][2]; aY2 := gHistoWinSize[aPlot%][3]; window(aX1,aY1,aX2,aY2); endif next 'Set tragectory position and size if ViewKind(gTragectoryHandle%) >= 0 then View(gTragectoryHandle%); 'Make the view the current view window(gTragectoryX1,gTragectoryY1,gTragectoryX2,gTragectoryY2); endif end 'SetWindowPositions '---------------------------------------------------- ' PrefSave 'Function calls from buttons cannot have arguments. '3/29/05 '---------------------------------------------------- func PrefSave%() PreferencesSave%(kTrue); return kTrue; 'Stay in toolbar end; 'PrefSave '---------------------------------------------------- ' PreferencesSave 'This saves the user preferences to a file called 'sactrack_parameters.txt found in the same directory 'that the application scripts are found. '10/18/04 '---------------------------------------------------- func PreferencesSave%(aDialog%) var aResult, bStr$,aStr$, aVector%, i%, aX1,aY1,aX2,aY2, aSm% := 10; GetWindowPositions(); GetAllRewardValues(); GetUnitTracePrefs(); GetTraceWeights(); 'write out the preference values now 'for backward compatibility, DO NOT REARRANGE the order which the parameters are written 'this time stamp assures that parameter files compatible aStr$ := kParameterMilestone$ + Chr$(13) ; 'Sactrack Configuration parameters aStr$ := aStr$ + str$(gWhichBooth) + " " + str$(gUnitData) + " " + str$(pGazeData) + " " + str$(pVergenceData) + " " + str$(pTraceStyleTarget) + " " + str$(pTraceStyleAnimal) + Chr$(13) ; 'booth prefs 'Data & Information Window preferences aStr$ := aStr$ + str$(gLogX1) + " " + str$(gLogY1) + " " + str$(gLogX2) + " " + str$(gLogY2) + Chr$(13); 'log window location aStr$ := aStr$ + str$(gDataX1) + " " + str$(gDataY1) + " " + str$(gDataX2) + " " + str$(gDataY2) + Chr$(13); 'data window location aStr$ := aStr$ + str$(gSpotX1) + " " + str$(gSpotY1) + " " + str$(gSpotX2) + " " + str$(gSpotY2) + Chr$(13); 'Spot window location aStr$ := aStr$ + str$(gDebugX1) + " " + str$(gDebugY1) + " " + str$(gDebugX2) + " " + str$(gDebugY2) + Chr$(13); 'Debug window location aStr$ := aStr$ + str$(gSpikeX1) + " " + str$(gSpikeY1) + " " + str$(gSpikeX2) + " " + str$(gSpikeY2) + Chr$(13); 'Spike window location 'Online Analysis XY plots for i% := 0 to kAttrNum%-1 do aStr$ := aStr$ + str$(gAnalWinSize[i%][0]) + " " + str$(gAnalWinSize[i%][1]) + " " + str$(gAnalWinSize[i%][2]) + " " + str$(gAnalWinSize[i%][3]) + Chr$(13); ' next 'the histogram window locations for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + str$(gHistoWinSize[aVector%][0]) + " " + str$(gHistoWinSize[aVector%][1]) + " " + str$(gHistoWinSize[aVector%][2]) + " " + str$(gHistoWinSize[aVector%][3]) + Chr$(13); next 'monkey's name aStr$ := aStr$ + gSubject$ + Chr$(13); 'Calibration parameters aStr$ := aStr$ + str$(pCalibrateRadius) + " " + str$(pCalibrateHorzOffset%) + " " + str$(pCalibrateVertOffset%) + " " + str$(pCalibrateDelay%) + " " + str$(pCalibrateTheta) + Chr$(13); 'XY parameters aStr$ := aStr$ + str$(pXYlocations) + " " + str$(pXYseparation) + " " + str$(pXYHorzOffset%) + " " + str$(pXYVertOffset%) + Chr$(13); 'Static parameters aStr$ := aStr$ + str$(pStaticMode) + " " + str$(pStaticXorRadius) + " " + str$(pStaticYorTheta) + " " + str$(pStimShutterDur) + " " + str$(pStimDelay) + " " + str$(pStimDur) + " " + str$(pStimAmp) + Chr$(13); 'Sine parameters aStr$ := aStr$ + str$(pSineFrequency) + " " + str$(pSineAmplitude) + " " + str$(pSineAngle) + Chr$(13); 'Radial parameters aStr$ := aStr$ + str$(pRadialReturnToZero) + " " + str$(pRadialHorzOffset%) + " " + str$(pRadialVertOffset%) + Chr$(13); for i% := 0 to 7 do aStr$ := aStr$ + Print$("%12f", pRadialAngle[i%]) + " "; 'use print$ to accomodate kNAN next aStr$ := aStr$ + Chr$(13); for i% := 0 to 7 do aStr$ := aStr$ + Print$("%12f", pRadialRadius[i%]) + " "; 'use print$ to accomodate kNAN next aStr$ := aStr$ + Chr$(13); 'Reward parameters aStr$ := aStr$ + str$(pDisplay) + " " + str$(pHorzOffset) + " " + str$(pVertOffset) + " " + str$(pWindowHvg) + " " + str$(pWindowVvg) + " " + str$(pWindowHmg) + " " + str$(pWindowVmg) + " " + str$(pRealTimeOn) + " " + str$(pRealContiguousTime) + " " + str$(pRealMinTime) + " " + str$(pRealMaxTime) + " " + str$(pForgiveness) + " " + str$(pOnFirst) + " " + str$(pOnSubsequent) + " " + Chr$(13); 'Limits preferences for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + str$(pLimits%[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); 'Ramp preferences for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pRampAngle[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pRampPriVelocity[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pRampSecVelocity[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); aStr$ := aStr$ + str$(pRampRatio) + " " + str$(pRampSecVelStartTime) + " " + str$(pRampExcursion) + " " + str$(pRampStepLatency) + " " + str$(pRampPlateau1) + " " + str$(pRampPlateau2) + Chr$(13); 'Adapt preferences for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pAdaptVectors[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pAdaptAdapt[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pAdaptInitialSteps[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); aStr$ := aStr$ + str$(pAdaptOnSetVel) + " " + str$(pAdaptOffsetVel) + " " + str$(pAdaptFollowDur) + " " + str$(pAdaptRTZ) + " " + str$(pAdaptType) + " " + str$(pAdaptBlankDur) + " " + str$(pAdaptGapDur) + str$(pAdaptHorzOffset%) + " " + str$(pAdaptVertOffset%) + Chr$(13); 'Memory preferences for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pMemoryVectors[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pMemoryAdapt[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pMemoryInitialSteps[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pMemoryFixDur[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pMemoryFixPeriphDurs[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pMemoryWaitDurs[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); for aVector% := 0 to kMaxVectors% - 1 do aStr$ := aStr$ + print$("%12f", pMemoryPeriphDurs[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); aStr$ := aStr$ + str$(pMemoryOnSetVel) + " " + str$(pMemoryOffsetVel) + " " + str$(pMemoryFollowDur) + " " + str$(pMemoryResponseDur) + " " + str$(pMemoryRTZ) + " " + str$(pMemoryType) + " " + str$(pMemoryPostFailure) + " " + str$(pMemoryPostColor) + " " + str$(pMemoryTimeouts) + Chr$(13); 'Analysis preferences aStr$ := aStr$ + str$(pMinTargAmp) + " " + str$(pMaxTargAmp) + " " + str$(pMinSaccadicVelocity) + " " + str$(pOnsetVelocity) + " " + str$(pOffsetVelocity) + " " + str$(pMinGain) + " " + str$(pMaxGain) + " " + str$(pSaccadeSearchStart) + " " + str$(pSaccadeSearchEnd) + Chr$(13); 'Reward Box gains and offsets aStr$ := aStr$ + str$(pHgain1) + " " + str$(pHOffset1) + " " + str$(pVGain1) + " " + str$(pVOffset1) + " " + str$(pHgain2) + " " + str$(pHOffset2) + " " + str$(pVGain2) + " " + str$(pVOffset2) + Chr$(13); 'Spike scope and spot scope preferences aStr$ := aStr$ + str$(gSpotScopeActive%) + " " + str$(gSpikeScopeActive%) + " " + str$(gSpikeWidthWM) + " " + str$(gSpikePreWM) + Chr$(13); 'Adapt and Memory stimulation parameters aStr$ := aStr$ + str$(pAdaptStim1) + " " + str$(pAdaptStim2) + " " + str$(pMemoryStim1) + " " + str$(pMemoryStim2) + " " + str$(pAdaptStimRatio) + " " + str$(pMemoryStimRatio) + Chr$(13); for aVector% := 0 to (kMaxVectors%/2) - 1 do 'only 4 (choices encoded as 0,1,2) aStr$ := aStr$ + print$("%12f", pAdaptStimDir[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); for aVector% := 0 to (kMaxVectors%/2) - 1 do 'only 4 (choices encoded as 0,1,22) aStr$ := aStr$ + print$("%12f", pMemoryStimDir[aVector%]) + " "; next aStr$ := aStr$ + Chr$(13); aStr$ := aStr$ + str$(pMayhemDuration) + " " + str$(pGeneralData910%) + " " + str$(pSampleCh1112%) + " " + str$(pSampleCh13%) + Chr$(13); aStr$ := aStr$ + str$(0) + Chr$(13); 'don't save when stimulation must always be set to 's' key 'aStr$ := aStr$ + str$(pStimType%) + Chr$(13); aStr$ := aStr$ + str$(pLEDintensity%) + Chr$(13); aStr$ := aStr$ + str$(pStimNoResponse) + Chr$(13); aStr$ := aStr$ + str$(gAppX1) + " " + str$(gAppY1) + " " + str$(gAppX2) + " " + str$(gAppY2) + Chr$(13); 'app window location aStr$ := aStr$ + str$(pUnitCursor) + " " + str$(pUnitHi) + " " + str$(pUnitLo) + Chr$(13); 'unit trace cursor and y-scale aStr$ := aStr$ + str$(pMaxThetaError) + Chr$(13); aStr$ := aStr$ + str$(pWtUnit) + " " + str$(pWtEye) + " " + str$(pWtIFR) + Chr$(13); aStr$ := aStr$ + str$(pAdaptWindowBeg%) + " " + str$(pAdaptWindowEnd%) + Chr$(13); aStr$ := aStr$ + str$(pAdaptStartRadius%) + Chr$(13); aStr$ := aStr$ + str$(pAdaptStepEverytime%) + Chr$(13); 'Online Analysis XY plots for i% := 0 to kAttrNum%-1 do aStr$ := aStr$ + str$(gAnalXattr[i%]) + " " + str$(gAnalYattr[i%]) + " " + str$(gAnalParamOne[i%]) + Chr$(13); next aStr$ := aStr$ + str$(pScaleMargin) + " " + str$(pScaleMinimum) + Chr$(13); aStr$ := aStr$ + str$(gTragectoryX1) + " " + str$(gTragectoryY1) + " " + str$(gTragectoryX2) + " " + str$(gTragectoryY2) + Chr$(13); 'tragectory window location 'aStr$ := aStr$ + str$(pWtShutStat) + Chr$(13); 'Memory shutter status weights 'trace weights 'for i% := 1 to 32 do 'skip [0] for i% := 0 to 32 do 'write the whole array because PreferencesOpen reads the whole array aStr$ := aStr$ + str$(pWtChan000[i%]) + " "; next aStr$ := aStr$ + Chr$(13); 'for i% := 1 to 10 do 'skip [0] for i% := 0 to 10 do 'write the whole array because PreferencesOpen reads the whole array aStr$ := aStr$ + str$(pWtChan400[i%]) + " "; next aStr$ := aStr$ + Chr$(13); 'for i% := 1 to 10 do 'skip [0] for i% := 0 to 10 do 'write the whole array because PreferencesOpen reads the whole array aStr$ := aStr$ + str$(pWtChan800[i%]) + " "; next aStr$ := aStr$ + Chr$(13); aStr$ := aStr$ + str$(gHistoYmax%) + Chr$(13); '+ these are obsolete and can be deleted as soon as they are removed from the preference file 'pWtEye 'pWtUnit 'pWtIFR 'pWtKeyboard 'pWtEvents '- these are obsolete and can be deleted as soon as they are removed from the preference file '------------------------------------------- '^^^ add NEW PARAMETERS above this line ^^^ ' 'for debugging trace weight preferences ' for i% := 1 to 32 do ' Printlog("PrefSave %5d,%14.2f\n", i%, pWtChan000[i%]); ' next; ' for i% := 1 to 10 do ' Printlog("PrefSave %5d,%14.2f\n", 400+i%, pWtChan400[i%]); ' next; ' for i% := 1 to 10 do ' Printlog("PrefSave %5d,%14.2f\n", 800+i%, pWtChan800[i%]); ' next; '-------------------------------------------------- 'open a file and write the first set of prefs to it '-------------------------------------------------- aResult := filenew(1); aResult := len(aStr$); 'just to see how long the string is, shockingly the manual says it can be aResult := print("%s", aStr$); 'write the string to the file '-------------------------------------------------- FilePathSet(gPrefDir$); 'NOTE: doesn't open dialog box if gPrefDir$ is part of the filename. BUG? 'aim at the desktop where preference files are saved if aDialog% = kTrue then bStr$ := gSubject$ + "_parameters.txt"; aResult := filesaveas(bStr$,1,1,"Save the preference file, CANCEL button saves nothing"); 'save the file with the filename the user chooses else aResult := filesaveas( "sactrack_parameters.txt",1,1); 'save it with the default name endif aResult := fileclose(0,-1); 'close it, don't ask end 'PreferencesSave '---------------------------------------------------- ' PrefOpen 'Buttons can only call functions, not procedures. 'PrefOpen also calls ReloadMode which forces the use 'of the newly loaded preferences. '3/29/05 '---------------------------------------------------- func PrefOpen%() PreferencesOpen%(kTrue); 'load the preferences SetWindowPositions(); SetTraceWeights(); ReloadMode(); 'force them to be used return kTrue; 'Stay in toolbar end; 'PrefOpen '---------------------------------------------------- ' PreferencesOpen 'This loads the user preferences from a file called 'sactrack_parameters.txt found in the same directory 'that the application scripts are found. This file 'should readable by all future versions of Sactrack. ' 'Delete sactrack_parameters.txt if you want the default 'values. '10/18/04 '---------------------------------------------------- func PreferencesOpen%(aDialog%) var a$, bStr$, aVector%, i%, aResult; bStr$ := gPrefDir$ + "sactrack_parameters.txt"; if aDialog% = kTrue then aResult := fileopen("*.txt",1,0,"Open a preference file, CANCEL button uses default preferences"); 'open the preference file, a file the user chooses if aResult <= 0 then aResult := fileopen(bStr$,1); 'something went wrong, try to open the default pref file endif else aResult := fileopen(bStr$,1); 'open the preference file endif if aResult > 0 then aResult := read(a$); 'read milestone date if (aResult > 0) and (a$ = kParameterMilestone$) then aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gWhichBooth, gUnitData, pGazeData, pVergenceData, pTraceStyleTarget, pTraceStyleAnimal); 'basic choices endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gLogX1, gLogY1, gLogX2, gLogY2); 'log window endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gDataX1, gDataY1, gDataX2, gDataY2); 'data window endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gSpotX1, gSpotY1, gSpotX2, gSpotY2); 'spot window endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gDebugX1, gDebugY1, gDebugX2, gDebugY2); 'Debug window endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gSpikeX1, gSpikeY1, gSpikeX2, gSpikeY2); 'spike monitor window endif 'Online Analysis XY plots for i% := 0 to kAttrNum%-1 do aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gAnalWinSize[i%][0],gAnalWinSize[i%][1],gAnalWinSize[i%][2],gAnalWinSize[i%][3]); 'window endif next 'just read the parameters for the histogram plot windows for aVector% := 0 to kMaxVectors% - 1 do aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gHistoWinSize[aVector%][0],gHistoWinSize[aVector%][1],gHistoWinSize[aVector%][2],gHistoWinSize[aVector%][3]); 'window endif next aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gSubject$); 'the monkey's name endif 'Calibration parameters aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pCalibrateRadius,pCalibrateHorzOffset%,pCalibrateVertOffset%,pCalibrateDelay%,pCalibrateTheta); 'calibration parameters endif 'XY parameters aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pXYlocations,pXYseparation, pXYHorzOffset%, pXYVertOffset%); 'xy parameters endif 'Static parameters aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pStaticMode,pStaticXorRadius,pStaticYorTheta,pStimShutterDur,pStimDelay,pStimDur,pStimAmp); 'static parameters endif 'Sine parameters aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pSineFrequency,pSineAmplitude,pSineAngle); 'sine parameters endif 'Radial parameters aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pRadialReturnToZero, pRadialHorzOffset%, pRadialVertOffset%); 'radial parameters endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pRadialAngle[0],pRadialAngle[1],pRadialAngle[2],pRadialAngle[3],pRadialAngle[4],pRadialAngle[5],pRadialAngle[6],pRadialAngle[7]); 'radial parameters endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pRadialRadius[0],pRadialRadius[1],pRadialRadius[2],pRadialRadius[3],pRadialRadius[4],pRadialRadius[5],pRadialRadius[6],pRadialRadius[7]); 'radial parameters endif 'Reward parameters aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pDisplay,pHorzOffset,pVertOffset,pWindowHvg,pWindowVvg,pWindowHmg,pWindowVmg,pRealTimeOn,pRealContiguousTime,pRealMinTime,pRealMaxTime,pForgiveness,pOnFirst,pOnSubsequent); endif 'Limits preferences aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pLimits%[0],pLimits%[1],pLimits%[2],pLimits%[3],pLimits%[4],pLimits%[5],pLimits%[6],pLimits%[7]); endif 'Ramp preferences aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pRampAngle[0],pRampAngle[1],pRampAngle[2],pRampAngle[3],pRampAngle[4],pRampAngle[5],pRampAngle[6],pRampAngle[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pRampPriVelocity[0],pRampPriVelocity[1],pRampPriVelocity[2],pRampPriVelocity[3],pRampPriVelocity[4],pRampPriVelocity[5],pRampPriVelocity[6],pRampPriVelocity[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pRampSecVelocity[0],pRampSecVelocity[1],pRampSecVelocity[2],pRampSecVelocity[3],pRampSecVelocity[4],pRampSecVelocity[5],pRampSecVelocity[6],pRampSecVelocity[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pRampRatio,pRampSecVelStartTime,pRampExcursion,pRampStepLatency,pRampPlateau1,pRampPlateau2); endif 'Adapt preferences aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pAdaptVectors[0],pAdaptVectors[1],pAdaptVectors[2],pAdaptVectors[3],pAdaptVectors[4],pAdaptVectors[5],pAdaptVectors[6],pAdaptVectors[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pAdaptAdapt[0],pAdaptAdapt[1],pAdaptAdapt[2],pAdaptAdapt[3],pAdaptAdapt[4],pAdaptAdapt[5],pAdaptAdapt[6],pAdaptAdapt[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pAdaptInitialSteps[0],pAdaptInitialSteps[1],pAdaptInitialSteps[2],pAdaptInitialSteps[3],pAdaptInitialSteps[4],pAdaptInitialSteps[5],pAdaptInitialSteps[6],pAdaptInitialSteps[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pAdaptOnSetVel,pAdaptOffsetVel,pAdaptFollowDur,pAdaptRTZ,pAdaptType,pAdaptBlankDur,pAdaptGapDur, pAdaptHorzOffset%, pAdaptVertOffset%); endif 'Memory preferences aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pMemoryVectors[0],pMemoryVectors[1],pMemoryVectors[2],pMemoryVectors[3],pMemoryVectors[4],pMemoryVectors[5],pMemoryVectors[6],pMemoryVectors[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pMemoryAdapt[0],pMemoryAdapt[1],pMemoryAdapt[2],pMemoryAdapt[3],pMemoryAdapt[4],pMemoryAdapt[5],pMemoryAdapt[6],pMemoryAdapt[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pMemoryInitialSteps[0],pMemoryInitialSteps[1],pMemoryInitialSteps[2],pMemoryInitialSteps[3],pMemoryInitialSteps[4],pMemoryInitialSteps[5],pMemoryInitialSteps[6],pMemoryInitialSteps[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pMemoryFixDur[0],pMemoryFixDur[1],pMemoryFixDur[2],pMemoryFixDur[3],pMemoryFixDur[4],pMemoryFixDur[5],pMemoryFixDur[6],pMemoryFixDur[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pMemoryFixPeriphDurs[0],pMemoryFixPeriphDurs[1],pMemoryFixPeriphDurs[2],pMemoryFixPeriphDurs[3],pMemoryFixPeriphDurs[4],pMemoryFixPeriphDurs[5],pMemoryFixPeriphDurs[6],pMemoryFixPeriphDurs[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pMemoryWaitDurs[0],pMemoryWaitDurs[1],pMemoryWaitDurs[2],pMemoryWaitDurs[3],pMemoryWaitDurs[4],pMemoryWaitDurs[5],pMemoryWaitDurs[6],pMemoryWaitDurs[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pMemoryPeriphDurs[0],pMemoryPeriphDurs[1],pMemoryPeriphDurs[2],pMemoryPeriphDurs[3],pMemoryPeriphDurs[4],pMemoryPeriphDurs[5],pMemoryPeriphDurs[6],pMemoryPeriphDurs[7]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pMemoryOnSetVel,pMemoryOffsetVel,pMemoryFollowDur,pMemoryResponseDur,pMemoryRTZ,pMemoryType,pMemoryPostFailure,pMemoryPostColor,pMemoryTimeouts); endif 'Analysis preferences aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pMinTargAmp,pMaxTargAmp,pMinSaccadicVelocity,pOnsetVelocity,pOffsetVelocity,pMinGain,pMaxGain,pSaccadeSearchStart,pSaccadeSearchEnd); endif 'Reward Box gains and offsets aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pHgain1,pHOffset1,pVGain1,pVOffset1,pHgain2,pHOffset2,pVGain2,pVOffset2); endif 'Spike scope and spot scope preferences aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gSpotScopeActive%,gSpikeScopeActive%,gSpikeWidthWM,gSpikePreWM); endif 'Adapt and Memory stimulation parameters aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pAdaptStim1,pAdaptStim2,pMemoryStim1,pMemoryStim2,pAdaptStimRatio,pMemoryStimRatio); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pAdaptStimDir[0],pAdaptStimDir[1],pAdaptStimDir[2],pAdaptStimDir[3]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pMemoryStimDir[0],pMemoryStimDir[1],pMemoryStimDir[2],pMemoryStimDir[3]); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pMayhemDuration, pGeneralData910%, pSampleCh1112%, pSampleCh13%); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pStimType%); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pLEDintensity%); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pStimNoResponse); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gAppX1, gAppY1, gAppX2, gAppY2); 'log window endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pUnitCursor, pUnitHi, pUnitLo); 'log window endif 'unit trace cursor and y-scale aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pMaxThetaError); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pWtUnit, pWtEye, pWtIFR); 'read in trace weights endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pAdaptWindowBeg%, pAdaptWindowEnd%); 'read in trace weights endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pAdaptStartRadius%); endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pAdaptStepEverytime%); endif 'Online Analysis XY plots for i% := 0 to kAttrNum%-1 do aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gAnalXattr[i%],gAnalYattr[i%],gAnalParamOne[i%]); 'window endif next aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, pScaleMargin, pScaleMinimum); 'read in plot scale parameters endif aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gTragectoryX1, gTragectoryY1, gTragectoryX2, gTragectoryY2); 'tragectory window endif 'trace weights 'for i% := 1 to 32 do 'skip [0] aResult := read(a$); 'read in the data string if it exists if aResult > 0 then 'readstr(a$, pWtChan000[i%]); 'trace readstr(a$, pWtChan000[]); 'trace endif 'next 'for i% := 1 to 10 do 'skip [0] aResult := read(a$); 'read in the data string if it exists if aResult > 0 then 'readstr(a$, pWtChan400[400+i%]); 'trace readstr(a$, pWtChan400[]); 'trace endif 'next 'for i% := 1 to 10 do 'skip [0] aResult := read(a$); 'read in the data string if it exists if aResult > 0 then 'readstr(a$, pWtChan800[800+i%]); 'trace readstr(a$, pWtChan800[]); 'trace endif 'next aResult := read(a$); 'read in the data string if it exists if aResult > 0 then readstr(a$, gHistoYmax%); endif '------------------------------------------- '^^^ add NEW PARAMETERS above this line ^^^ ' 'for debugging trace weight preferences ' for i% := 1 to 32 do ' Printlog("PrefOpen %5d,%14.2f\n", i%, pWtChan000[i%]); ' next; ' for i% := 1 to 10 do ' Printlog("PrefOpen %5d,%14.2f\n", 400+i%, pWtChan400[i%]); ' next; ' for i% := 1 to 10 do ' Printlog("PrefOpen %5d,%14.2f\n", 800+i%, pWtChan800[i%]); ' next; else message("The parameter file was not loaded because it is incompatible with the current format."); endif 'if (aResult > 0) and (a$ = kParameterMilestone$) then aResult := fileclose(0); 'close the input file, prepare to overwrite endif end 'PreferencesOpen '---------------------------------------------------- ' ReloadMode 'This is called whenever new preferences are loaded. 'Since the sequencer is running autonomously the 'current mode dialog box must be called up so 'computations can be performed using the new 'preference and the new values sent out to the 'sequencer. This scheme leaves the current digitized 'file going. ' '4/21/05 '---------------------------------------------------- proc ReloadMode() docase case gLastMode% = kCalibrate then DialogCalibrate%(); case gLastMode% = kXY then DialogXY%(); case gLastMode% = kRadial then DialogRadial%(); case gLastMode% = kAdapt then DialogAdapt%(); case gLastMode% = kStatic then DialogStatic%(); case gLastMode% = kRamp then DialogRamp%(); case gLastMode% = kSine then DialogSine%(); case gLastMode% = kMemory then DialogMemory%(); endcase end 'ReloadMode '---------------------------------------------------- ' GetTraceWeights '6/5/06 '---------------------------------------------------- proc GetTraceWeights() var i%; if viewkind(gDataWindow%)>=0 then view(gDataWindow%); for i% := 0 to 32 do '[0] not used if ChanKind(i%) then pWtChan000[i%] := ChanWeight(i%); 'Printlog("GetTraceWeights %5d,%14.2f\n", i%, pWtChan000[i%]); endif; next; for i% := 0 to 10 do '[0] not used if ChanKind(400+i%) then pWtChan400[i%] := ChanWeight(400+i%); 'Printlog("GetTraceWeights %5d,%14.2f\n", 400+i%, pWtChan400[i%]); endif; next; for i% := 0 to 10 do '[0] not used if ChanKind(800+i%) then pWtChan800[i%] := ChanWeight(800+i%); 'Printlog("GetTraceWeights %5d,%14.2f\n", 800+i%, pWtChan800[i%]); endif; next; endif end 'GetTraceWeights '---------------------------------------------------- ' SetTraceWeights '6/5/06 '---------------------------------------------------- proc SetTraceWeights() var 'aWtUnit, 'aWtEye, 'aWtIFR, i%; ' if gUnitData > 0 then ' aWtUnit := pWtUnit; 'users will change the ' aWtEye := pWtEye; ' aWtIFR := pWtIFR; ' else ' aWtUnit := 0.0; ' aWtEye := 0.5; 'H and V share the screen in behavioral mode ' aWtIFR := 0.0; ' endif if viewkind(gDataWindow%) >= 0 then view(gDataWindow%); for i% := 0 to 32 do '[0] not used if ChanKind(i%) then ChanWeight(i%, pWtChan000[i%]); 'Printlog("SetTraceWeights %5d,%14.2f\n", i%, pWtChan000[i%]); endif; next; for i% := 0 to 10 do '[0] not used if ChanKind(400+i%) then ChanWeight(400+i%, pWtChan400[i%]); 'Printlog("SetTraceWeights %5d,%14.2f\n", 400+i%, pWtChan400[i%]); endif; next; for i% := 0 to 10 do '[0] not used if ChanKind(800+i%) then ChanWeight(800+i%, pWtChan800[i%]); 'Printlog("SetTraceWeights %5d,%14.2f\n", 800+i%, pWtChan800[i%]); endif; next; endif 'viewkind(gDataWindow%) >= 0 end 'SetTraceWeights '---------------------------------------------------- ' SetUnitTraceScales 'The scales for the other traces are set automatically 'in the dialog box handling routine for each mode. 'The unit trace is different because its scale doesn't 'change. '5/24/06 '---------------------------------------------------- proc SetUnitTraceScales() if viewkind(gDataWindow%) >= 0 then view(gDataWindow%); if chankind(gChUnit) > 0 then HCursor(gCursorAccept, pUnitCursor); 'horiz cursor: acceptance pulse threshold yrange(gChUnit, pUnitLo, pUnitHi); 'unit trace Y-scale endif endif end 'SetUnitTraceScales '---------------------------------------------------- ' CloseHistoPlots 'Close the on-line analysis histo plots if they are 'open. '4/17/03 '---------------------------------------------------- Proc CloseHistoPlots() var aVector%; for aVector% := 0 to kMaxVectors% - 1 do if ViewKind(gHistoHandle%[aVector%]) = 12 then View(gHistoHandle%[aVector%]); FileClose(0,-1); gHistoHandle%[aVector%] := -1; endif next end 'CloseHistoPlots '---------------------------------------------------- ' MyAnalysisClose '11/21/03 '---------------------------------------------------- proc MyAnalysisClose(aWindow%, aQuery) 'aQuery: 0=query -1=no query if ViewKind(aWindow%) >= 0 then '-2=invalid, -1=unknown View(aWindow%); FileClose(0, aQuery); 'Close the window endif end 'MyAnalysisClose '---------------------------------------------------- ' MyFileClose '11/21/03 '---------------------------------------------------- proc MyFileClose(aWindow%, aQuery) 'aQuery: 0=query -1=no query var aResult; MyMessage(gGreetingWindow%, "", "", gNumMonitors%); 'this will toggle the window closed if ViewKind(aWindow%) >= 0 then '-2=invalid, -1=unknown View(aWindow%); aResult := SampleStop(); if aQuery = -35 then 'special case where previous must be saved with provided filename if gChSpikeWM% > 0 then aResult := MemSave(gChSpikeWM%, gChSpikeWMperm%); 'save the unit wavemark unit channel, if found, to ch (#30, Noto 8/16/05), (#29, Robi 1/3/05) DrawMode(gChSpikeWMperm%,2); 'draw as lines endif FileSaveAs(gDataDir$ + gFileName$,-1); 'save the file to its own folder FileClose(0, -1); 'Close the window, 1=don't query else FileClose(0, aQuery); 'Close the window endif endif end 'MyFileClose '---------------------------------------------------- ' Quit '11/22/02 '---------------------------------------------------- func Quit%() 'If "Quit" is pressed var list%[100], i%; SaveLastDataFile(); PreferencesSave%(kTrue); MyFileClose(gDebugWindow%, -1); 'Close & don't query MyFileClose(gRewardBoxParameterWindow%, -1); 'Close & don't query i% := 4096; 'specify XY views ViewList(list%[], i%); 'get a list of the views that match for i% := 0 to list%[0] do if ViewKind(list%[i%]) >= 0 then View(list%[i%]); 'pull up those views FileClose(0, -1); 'close current, don't query endif next '+ extinquish the LEDs on the LED array var aStr$, aResult%; aStr$ := gScriptDir$ + "sactrack_ledoff.pls"; aResult% := SampleSequencer(aStr$); 'set the sequencer to use gDataWindow% := FileNew(0,1); 'Open a new data file for sampling windowTitle$("Extinguishing LED array"); aResult% := SampleStart(0); 'Start sampling '5/12/06 leaving this in causes user to have to respond to a dialog box, etc. 'Yield(1); 'give the sequencer a chance to run before stopping it view(gDataWindow%); ' repeat ' 'PrintLog(" V62 = ", SampleSeqVar(1)); ' aResult% := SampleSeqVar(1); ' until aResult% = 1; fileClose(0, -1); '- extinquish the LEDs on the LED array View(LogHandle()); 'Make log view the current view EditSelectAll(); 'Select all text in log view EditSelectAll(); EditClear(); 'Delete text FileClose(0, -1); 'close it, don't query SerialClose(gSerialPort); RestoreSelectedItems(); return kFalse; 'leave toolbar end 'Quit '---------------------------------------------------- ' DialogList '2/17/06 '---------------------------------------------------- func DialogList%() var a%, aa, ok%, i%, aIndexTrial%, j%, m%, aDoneTrial%, aDoneList%, aListHandle%, aSize%, aIndex%, aIndexBegin%, aLastIndex%, aReal, aLine$, aC$,aP[10], aTab0, aTab1, aTab2, aTab4, aTab5, aTab6, aTab7, aTab8, aTab9, aRow := 1, aBeginArray[1000], aBeginElements% := 0, aNum[10000], aStr$[10], boardAddress, LEDaddress, aBadList% := kFalse, aTable%[10000], aBitsIn; const kAbsRad1 := 1, kAbsRad2 := 2, kShutter1 := 3, kShutter2 := 4, kOnTargetDetect := 5, kOnTargetDuration := 6, kVelocityDetect := 7, kDelay := 8, kStimulate := 9, kBegin := 999999999, kEnd := -999999999, kEOC := 999999997, kEOT := 999999998, kEOL := 999999999; aTab0 := 0; aTab1 := 5; aTab2 := aTab1 + 25; aTab4 := aTab2 + kUnitLabel; aTab5 := aTab1 + 16; aTab6 := aTab5 + 16; aTab7 := aTab5 + 30; aTab8 := aTab2 + 17; aTab9 := aTab2 + 30; aBitsIn := pow(2,16); '65536 dlgcreate("List Parameters",kX); dlgtext("LIST moves the target based on instructions in your list. There is an example list in the Sactrack folder.", aTab0, aRow); aRow := aRow + 1; dlgtext("Feeding and inter-trial interval parameters are specified in the Behavior Dialogbox.", aTab0, aRow); aRow := aRow + 2; dlglist(1,"Trials chosen","sequentially|randomly", 99, aTab2, aRow); aRow := aRow + 2; dlginteger(2,"Velocity Onset",0,2000, aTab2, aRow); dlgText("d/s", aTab4, aRow); aRow := aRow + 1; dlginteger(3,"Velocity Offset",0,2000, aTab2, aRow); dlgText("d/s", aTab4, aRow); aRow := aRow + 2; dlgText("", aTab4, aRow); 'dlgButton(0,"Cancel"); 'dlgButton(1,"Open New List File"); 'dlgButton(2,"Use Current List File"); 'ok% := dlgshow(pListFeed%, pListTrials%); ok% := dlgshow(pListTrials%, pAdaptOnSetVel, pAdaptOffsetVel); if ok% > 0 then i% := -1; aListHandle% := fileopen("*.txt",1,0,"Choose a List File to Open"); if aListHandle% < 0 then if aListHandle% = -1549 then message("The List could not be opened probably because it has opened with another application."); else message("The List could not be opened."); endif else '+ write mode parameters '+---------------------------------------------------- m% := 0; ArrConst(aTable%[], kNAN); 'pre-set all locations to NAN aTable%[m%+3] := (aBitsIn/20) * (pAdaptOnSetVel/100); aTable%[m%+4] := (aBitsIn/20) * (pAdaptOffSetVel/100); ArrConst(gTable%, 0); 'clear global table data ArrAdd(gTable%, aTable%); 'copy the table to be used with NEWDIG SampleSeqTable(gTable%, kTableOffset1000%); 'load all these values into the table Table(aTable%[]); 'kBOBmode ' 'display the table of data being send to the sequence ' if kBOBmode = kTrue then ' PresentDebugWindow(); ' j% := 0; ' while j% < 550 do ' Print("%5d,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f\n", j%, aTable%[j%+0], aTable%[j%+1], aTable%[j%+2], aTable%[j%+3], aTable%[j%+4], aTable%[j%+5], aTable%[j%+6], aTable%[j%+7], aTable%[j%+8], aTable%[j%+9]); ' j% := j% + 10; ' wend ' endif ' '+---------------------------------------------------- '- write mode parameters 'DATA FLOW SCHEME (save) '+---------------------------------------------------- '*.txt --> ( aNum[] & aBeginArray[] ) --> aTable%[] '*.txt contains the Excel list 'aNum[] holds each command in a 10 value space 'aBeginArray[] points to the beginning of trials in aNum[] 'aTable%[] holds a very large collection of trials randomly or sequentially constructed from the list. 'The trials in aTable%[] are presented in order. Move to beginning of the file when the end is found. '+---------------------------------------------------- '+ read-in user's List '+---------------------------------------------------- readsetup("\t", "t ", "", "", "\t"); aIndexBegin% := -1; arrconst(aBeginArray[],kBegin); repeat aSize% := read(aStr$[]); docase case lcase$(aStr$[0]) = "begin" then i% := i% + 1; aNum[i%] := kBegin; aIndexBegin% := aIndexBegin% + 1; aBeginArray[aIndexBegin%] := i%; aBeginElements% := aBeginElements% + 1; i% := i% + 9; 'end the row of 10 parameters case lcase$(aStr$[0]) = "absrad1" then i% := i% + 1; aNum[i%] := kAbsRad1; i% := i% + 1; aNum[i%] := val(aStr$[1]); 'radius i% := i% + 1; aNum[i%] := val(aStr$[2]); 'theta i% := i% + 7; 'end the row of 10 parameters case lcase$(aStr$[0]) = "shutter1" then i% := i% + 1; aNum[i%] := kShutter1; i% := i% + 1; aNum[i%] := val(aStr$[1]); 'state i% := i% + 8; 'end the row of 10 parameters case lcase$(aStr$[0]) = "stimulate" then i% := i% + 1; aNum[i%] := kStimulate; i% := i% + 9; 'end the row of 10 parameters case lcase$(aStr$[0]) = "delay" then i% := i% + 1; aNum[i%] := kDelay; i% := i% + 1; aNum[i%] := val(aStr$[1]); 'duration i% := i% + 8; 'end the row of 10 parameters case lcase$(aStr$[0]) = "ontargetdetect" then i% := i% + 1; aNum[i%] := kOnTargetDetect; i% := i% + 1; aNum[i%] := val(aStr$[1]); 'duration i% := i% + 8; 'end the row of 10 parameters case lcase$(aStr$[0]) = "velocitydetect" then i% := i% + 1; aNum[i%] := kVelocityDetect; i% := i% + 1; aNum[i%] := val(aStr$[1]); 'duration i% := i% + 8; 'end the row of 10 parameters case lcase$(aStr$[0]) = "end" then i% := i%; 'do nothing, except at the very end, see below else if aStr$[0] = "" then ; 'do nothing else aBadList% := kTrue; message("An unrecognized command was found in column 1."); endif endcase until (aSize% < 0) or (aBadList% = kTrue); i% := i% + 1; aNum[i%] := kEnd; 'required to end the list View(aListHandle%); fileclose(); Table(aTable%[]); 'kBOBmode ' 'display the table of data being send to the Sequencer ' if kBOBmode = kTrue then ' PresentDebugWindow(); ' j% := 0; ' while j% < 100 do ' Print("%5d,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f\n", j%, aNum[j%+0], aNum[j%+1], aNum[j%+2], aNum[j%+3], aNum[j%+4], aNum[j%+5], aNum[j%+6], aNum[j%+7], aNum[j%+8], aNum[j%+9]); ' j% := j% + 10; ' wend ' endif '+---------------------------------------------------- '- read-in user's List if aBadList% = kFalse then 'problem in the list, do not send it to the sequencer '+ generate a large random sequence of trials '+---------------------------------------------------- a% := 0; 'pre-set all locations to NAN ArrConst(aTable%[], kNAN); aLastIndex% := -1; 'initial value 'create entries to put in the table that will be read by the sequencer aDoneList% := kFalse; aIndexBegin% := 0; 'input list aIndexTrial% := 0; 'output list repeat 'for aIndexTrial% := 0 to 9 do 'make TABLE list of 10 trials aDoneTrial% := kFalse; if pListTrials% = 1 then 'random repeat aReal := aBeginElements%; 'aIndexBegin% := aBeginElements% * rand(); 'truncate aIndexBegin% := aReal * rand(); 'truncate until aIndexBegin% <> aLastIndex%; 'neighboring locations can't be the same endif aLastIndex% := aIndexBegin%; aIndex% := aBeginArray[aIndexBegin%]; aIndex% := aIndex% + 10; 'gotta skip the leading kBegin in each trial repeat aa := aNum[aIndex%] ; docase '---------------------------------------------------- case (aNum[aIndex%] = kBegin) or (aNum[aIndex%] = kEnd) then aDoneTrial% := kTrue; '---------------------------------------------------- case aNum[aIndex%] = kAbsRad1 then aIndex% := aIndex% + 1; aP[1] := aNum[aIndex%]; aIndex% := aIndex% + 1; aP[2] := aNum[aIndex%]; aTable%[a%] := kAbsRad1; a% := a% + 1; 'absRad1 aTable%[a%] := Radial2dacH%(aP[1], aP[2], 0); a% := a% + 1; ' DAC-X value aTable%[a%] := Radial2dacV%(aP[1], aP[2], 0); a% := a% + 1; ' DAC-Y value EncodeLED80 (aP[1], aP[2], kRedColorBit, boardAddress, LEDaddress); aTable%[a%] := (boardAddress + 192) * 256; a% := a% + 1; ' LED board, shift left 8 bits aTable%[a%] := LEDaddress * 256; a% := a% + 1; ' LED address, shift left 8 bits aTable%[a%] := kEOC; a% := a% + 1; 'end of command, for visual separation, sequencer knows how many parameters each command ha aIndex% := aIndex% + 8; '---------------------------------------------------- case aNum[aIndex%] = kShutter1 then aIndex% := aIndex% + 1; aTable%[a%] := kShutter1; a% := a% + 1; 'kShutter1 aTable%[a%] := aNum[aIndex%]; a% := a% + 1; ' shutter state aTable%[a%] := kEOC; a% := a% + 1; 'end of command, for visual separation, sequencer knows how many parameters each command ha aIndex% := aIndex% + 9; '---------------------------------------------------- case aNum[aIndex%] = kDelay then aIndex% := aIndex% + 1; aTable%[a%] := kDelay; a% := a% + 1; 'kDelay aTable%[a%] := aNum[aIndex%]; a% := a% + 1; ' delay dur in ms aTable%[a%] := kEOC; a% := a% + 1; 'end of command, for visual separation, sequencer knows how many parameters each command ha aIndex% := aIndex% + 9; '---------------------------------------------------- case aNum[aIndex%] = kVelocityDetect then aIndex% := aIndex% + 1; aTable%[a%] := kVelocityDetect; a% := a% + 1; 'kVelocityDetect aTable%[a%] := aNum[aIndex%]; a% := a% + 1; ' test dur in ms aTable%[a%] := kEOC; a% := a% + 1; 'end of command, for visual separation, sequencer knows how many parameters each command ha aIndex% := aIndex% + 9; '---------------------------------------------------- case aNum[aIndex%] = kOnTargetDetect then aIndex% := aIndex% + 1; aTable%[a%] := kOnTargetDetect; a% := a% + 1; 'kOnTargetDetect aTable%[a%] := aNum[aIndex%]; a% := a% + 1; ' test dur in ms aTable%[a%] := kEOC; a% := a% + 1; 'end of command, for visual separation, sequencer knows how many parameters each command ha aIndex% := aIndex% + 9; '---------------------------------------------------- case aNum[aIndex%] = kStimulate then aTable%[a%] := kStimulate; a% := a% + 1; 'kStimulate aTable%[a%] := kEOC; a% := a% + 1; 'end of command, for visual separation, sequencer knows how many parameters each command ha aIndex% := aIndex% + 10; '---------------------------------------------------- else aIndex% := aIndex% + 10; endcase until aDoneTrial% = kTrue; '999999999 or -999999999, no more commands in trial aTable%[a%] := kEOT; a% := a% + 1; 'end of command, for visual separation, sequencer knows how many parameters each command ha 'next 'for aIndexTrial% aIndexTrial% := aIndexTrial% + 1; if pListTrials% = 0 then 'sequential aIndexBegin% := aIndexBegin% + 1; endif aDoneList% := (aBeginElements% = aIndexBegin%); until (aIndexTrial% = 100) or (aDoneList% = kTrue); aTable%[a%] := kEOL; a% := a% + 1; 'end of list, for visual separation, sequencer knows how many parameters each command ha if gLastMode% <> kList then gLastMode% := kList; SaveLastDataFile(); ResetModeVariables(); CreateFileName(kList); New%(); Start%(); '(kTrue); 'request the target2 be shown else ResetModeVariables(); endif Table(aTable%[]); 'kBOBmode ' 'display the table of data being send to the sequence ' if kBOBmode = kTrue then ' PresentDebugWindow(); ' j% := 0; ' while j% < 550 do ' Print("%5d,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f\n", j%, aTable%[j%+0], aTable%[j%+1], aTable%[j%+2], aTable%[j%+3], aTable%[j%+4], aTable%[j%+5], aTable%[j%+6], aTable%[j%+7], aTable%[j%+8], aTable%[j%+9]); ' j% := j% + 10; ' wend ' endif ' ArrConst(gTable%, 0); 'clear global table data ArrAdd(gTable%, aTable%); 'copy the table to be used with NEWDIG SampleSeqTable(gTable%, kTableOffset2000%); 'load all this data into the tabl '----------------------------------------------------- '- generate a large random sequence of trials StartNewSession(kList); SetSpotScales(0, 0, pAdaptHorzOffset%, pAdaptVertOffset%); 'use limits SetScrollingScales(0, 0, pAdaptHorzOffset%, pAdaptVertOffset%); SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed SetToolbar(kList); SetVelocityChannels(); EditSelectAll(); EditClear(); ReportFlagSet(); endif 'if aBadlist = kFalse endif 'if aListHandle% < 0 endif 'if ok% return kTrue; 'Stay in toolbar end; 'DialogList '---------------------------------------------------- ' DialogCalibrate '11/22/02 '---------------------------------------------------- func DialogCalibrate%() var ok%, aStr$, aRow := 1, aTab1 := 30, aTab2, aTab3 := 6, aTab4 := 50, aEmpty := 0, boardAddress, LEDaddress, a, i%, m, aTable%[kTableSize%], aRadius, aTheta; aTab2 := aTab1 + kUnitLabel; dlgcreate("Calibration Parameters",kX); dlgreal(1,"Target Step", 0, 50, aTab1, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 1; dlginteger(2,"Horizontal Offset",-20,20, aTab1, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 1; dlginteger(3,"Vertical Offset",-20,20, aTab1, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 2; dlgList(4,"Pattern", "Steady in the Center|Oblique (Corners)|Horz-Vert (Cross)", 99, aTab1, aRow); aRow := aRow + 1; dlginteger(5,"Time between jumps",1, 2000, aTab1, aRow); dlgText("ms", aTab2, aRow); aRow := aRow + 2; dlglist(6,"Primary target shutter","closed|open", 99, aTab1, aRow); aRow := aRow + 1; dlglist(7,"Secondary target shutter","closed|open", 99, aTab1, aRow); aRow := aRow + 1; dlgText("", aTab1, aRow); dlglist(8,"Feeder","off|continuous", 99, aTab1, aRow); aRow := aRow + 2; dlgText("", aTab1, aRow); ok% := dlgshow(pCalibrateRadius, pCalibrateHorzOffset%, pCalibrateVertOffset%, pCalibrateTheta, pCalibrateDelay%, gCalibrateShutter1%, gCalibrateShutter2%, gCalibrateFeed%); if ok% > 0 then if pDisplay = 2 then 'remove any offsets when in the LED booth if (pCalibrateHorzOffset% <> 0) or (pCalibrateVertOffset% <> 0) then pCalibrateHorzOffset% := 0; pCalibrateVertOffset% := 0; message("The offsets have been reset to zero because they are not allowed in LED mode."); endif endif 'gMaxH := pCalibrateRadius; 'gMaxV := pCalibrateRadius; docase case pCalibrateTheta = 0 then aTheta := 0; aRadius := 0; 'remain in the center position case pCalibrateTheta = 1 then aTheta := 45; aRadius := pCalibrateRadius / 0.707106781; 'convert from Radial to XY coordinates case pCalibrateTheta = 2 then aTheta := 0; aRadius := pCalibrateRadius; endcase a := SampleSeqTable(); aTable%[0] := 4; 'number of points to show aTable%[1] := pCalibrateDelay% * 100; 'duration aTable%[2] := gCalibrateShutter1%; 'primary shutter aTable%[3] := gCalibrateShutter2%; 'secondary shutter aTable%[4] := gCalibrateFeed%; 'feeder test for i% := 1 to aTable%[0] do aTheta := aTheta - 90; NormalizeRadiusTheta (aEmpty, aTheta); m := i% * 10; 'primary X&Y positions: 100,200,300,400 aTable%[m+0] := Radial2dacH%(aRadius, aTheta, pCalibrateHorzOffset%); aTable%[m+1] := Radial2dacV%(aRadius, aTheta, pCalibrateVertOffset%); 'primary BRD&ADD positions: 100,200,300,400 EncodeLED80 (aRadius, aTheta, kRedColorBit, boardAddress, LEDaddress); aTable%[m+2] := (boardAddress + 192) * 256; aTable%[m+3] := LEDaddress * 256; 'secondary BRD&ADD positions: 100,200,300,400 EncodeLED80 (aRadius, aTheta, kGrnColorBit, boardAddress, LEDaddress); aTable%[m+4] := (boardAddress + 192) * 256; aTable%[m+5] := LEDaddress * 256; next StartNewSession(kCalibrate); SetSpotScales(pCalibrateRadius, pCalibrateRadius, pCalibrateHorzOffset%, pCalibrateVertOffset%); SetScrollingScales(pCalibrateRadius, pCalibrateRadius, pCalibrateHorzOffset%, pCalibrateVertOffset%); ArrConst(gTable%, 0); 'clear global table data ArrAdd(gTable%, aTable%); 'copy the table to be used with NEWDIG SampleSeqTable(gTable%, kTableOffset1000%); 'load all this data into the tabl SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed SetToolbar(kCalibrate); SetVelocityChannels(); EditSelectAll(); EditClear(); ReportFlagSet(); endif return kTrue; 'Stay in toolbar end; 'DialogCalibrate '---------------------------------------------------- ' DialogSine '4/4/03 '---------------------------------------------------- func DialogSine%() var ok%, aStr$, aReal, aTab1 := 20, aTab2, aTab3 := 6, aRow := 1, aTable%[kTableSize%]; aTab2 := aTab1 + 12; dlgcreate("Sine Parameters",kX); dlgreal(1,"Frequency",0,100,aTab1, aRow); dlgText("Hz", aTab2, aRow); aRow := aRow + 1; dlgreal(2,"Pk-Pk Amplitude",0,45,aTab1, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 1; dlgreal(3,"Angle",0,359,aTab1, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 2; dlginteger(4,"Horizontal Offset",-50,50, aTab1, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 1; dlginteger(5,"Vertical Offset",-50,50, aTab1, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 1; ok% := dlgshow(pSineFrequency, pSineAmplitude, pSineAngle, pSineXoffset, pSineYoffset); if ok% > 0 then if gLastMode% <> kSine then gLastMode% := kSine; SaveLastDataFile(); ResetModeVariables(); CreateFileName(kSine); New%(); Start%(); '(kFalse); else ResetModeVariables(); endif aReal := pSineAmplitude * gSineScale; aTable%[0] := 0; 'unused field aTable%[1] := pSineFrequency * 360 * 11930465 / 100000; 'frequency aTable%[2] := aReal * cos(pSineAngle/kRadians); 'x-amplitude coefficient, 0-32768, 32768 is ±10deg aTable%[3] := aReal * sin(pSineAngle/kRadians); 'y-amplitude coefficient, 0-32768, 32768 is ±10deg aTable%[4] := Degrees2dac%(pSineXoffset); 'x-offset, 0-32768, 32768 is ±10deg aTable%[5] := Degrees2dac%(pSineYoffset); 'y-offset, 0-32768, 32768 is ±10deg SetSpotScales(pSineAmplitude/2, pSineAmplitude/2, pSineXoffset, pSineYoffset); SetScrollingScales(pSineAmplitude/2, pSineAmplitude/2, pSineXoffset, pSineYoffset); ArrConst(gTable%, 0); 'clear global table data ArrAdd(gTable%, aTable%); 'copy the table to be used with NEWDIG SampleSeqTable(gTable%, kTableOffset1000%); 'load all this data into the tabl SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed SetToolbar(kSine); SetVelocityChannels(); EditSelectAll(); EditClear(); ReportFlagSet(); endif return kTrue; 'Stay in toolbar end 'DialogSine '---------------------------------------------------- ' DialogStatic '1/8/03 '---------------------------------------------------- func DialogStatic%() var ok%, aStr$, item1%, item2, item3, item4, item4%, item5, item6, item7, item8, item9, item10, item11, aTemp, bTemp, aValid, aResult, aRow := 1, aTab1, aTab2, aTab3, aTab4, aTab5, aTab6, boardAddress, LEDaddress; aTab1 := 3; aTab2 := 30 + aTab1; aTab3 := 17 + aTab2; aTab4 := 8; aTab5 := aTab2 + 12; aTab6 := aTab3 + 12; item1% := pStaticMode; 'need temp variables to verify a valid choice has been made before committing them to preferences item2 := pStaticXorRadius; item3 := pStaticYorTheta; item4% := pStimType%; item4 := pStimShutterDur; item5 := pStimDelay; item6 := pStimDur; item7 := pStimInterval; item8 := pCollisionLatency/100; item11 := pStimNoResponse; item9 := pStimBefore; item10 := pStimAfter; dlgcreate("Static Coordinates",kX); dlgText("Coordinate system", aTab1, aRow); dlgText("X or Radius", aTab2, aRow); dlgText("Y or Theta", aTab3, aRow); aRow := aRow + 1; dlglist(1,"","XY|Radial",99, aTab1, aRow); dlgreal(2,"",-160,160,aTab2, aRow); 'radius OR x dlgText("deg", aTab5, aRow); dlgreal(3,"",-360,360,aTab3, aRow); 'theta OR y dlgText("deg", aTab6, aRow); aRow := aRow + 1; dlgText("(The ARROW KEYS will step the target 5°)", 0, aRow); aRow := aRow + 2; dlglist(4,"Stimulation mode","Press 's' key|Antidromic Search|Antidromic Collision",99, aTab2, aRow); aRow := aRow + 1; dlgreal(5,"Shutter closed duration",0,10000, aTab2, aRow); dlgText("ms (any stim mode)", aTab5, aRow); aRow := aRow + 1; dlgreal(6,"Shutter-pulse delay",0,10000, aTab2, aRow); dlgText("ms (any stim mode)", aTab5, aRow); aRow := aRow + 1; dlgreal(7,"Pulse duration",0,10000, aTab2, aRow); dlgText("ms (any stim mode)", aTab5, aRow); aRow := aRow + 2; dlgreal(8,"Inter-pulse interval",0,10000, aTab2, aRow); dlgText("ms (Antidromic Search mode)", aTab5, aRow); aRow := aRow + 1; dlgreal(9,"Spike to Stimulation Delay",0,10000, aTab2, aRow); dlgText("ms (Antidromic Collision mode)", aTab5, aRow); aRow := aRow + 1; dlgreal(10,"Post Stim No-Response Period",0,10000, aTab2, aRow); dlgText("ms (Antidromic Collision mode)", aTab5, aRow); aRow := aRow + 2; dlgreal(11,"Display time before trigger",0,10000, aTab2, aRow); dlgText("ms (Antidromic mode)", aTab5, aRow); aRow := aRow + 1; dlgreal(12,"Display time after trigger",0,10000, aTab2, aRow); dlgText("ms (Antidromic mode)", aTab5, aRow); aRow := aRow + 1; dlgText("", aTab2, aRow); ok% := dlgshow(item1%, item2, item3, item4%, item4, item5, item6, item7, item8, item11, item9, item10); if ok% > 0 then aTemp := item2; bTemp := item3; aValid := kTrue; docase case item1% = kStaticXY then if (abs(aTemp) > 45) or (abs(bTemp) > 45) then aValid := kFalse; endif case item1% = kStaticRadial then NormalizeRadiusTheta (aTemp, bTemp); endcase if aValid then pStaticMode := item1%; pStaticXorRadius := aTemp; 'item2 pStaticYorTheta := bTemp; 'item3 pStimType% := item4%; pStimShutterDur := item4; pStimDelay := item5; pStimDur := item6; pStimInterval := item7; pCollisionLatency := item8*100; pStimNoResponse := item11; pStimBefore := item9; pStimAfter := item10; if gLastMode% <> kStatic then gLastMode% := kStatic; SaveLastDataFile(); ResetModeVariables(); CreateFileName(kStatic); New%(); Start%(); '(kFalse); gCollisionPlotLast := 0; else gLastMode% := kStatic; ResetModeVariables(); view(gDataWindow%); gCollisionPlotLast := MaxTime(); endif 'close the old collision window, if it is there. '----------------------- aResult := ViewKind(gCollisionWindow%); if aResult >= 0 then View(gCollisionWindow%); 'bring it to the top FileClose(0, -1); 'Close the window, 1=don't query endif 'create a new collision window '----------------------- if pStimType% > 0 then gCollisionN := 0; gCollisionWindow% := FileNew(12,1); 'prepare to plot the spike traces Window(pCollisionX1,pCollisionY1,pCollisionX2,pCollisionY2); 'Make data window in top bit of screen WindowRange(gCollisionWindow%); XYDrawMode(-1,5,0); 'auto axis range mode explicitly off XYDrawMode(1,2,2); 'small dots XYcolour(1,16); 'red TitleCollision(); endif StaticLoad(); SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed SetToolbar(kStatic); SetVelocityChannels(); EditSelectAll(); EditClear(); ReportFlagSet(); endif 'if aValid endif 'if ok% > 0 return kTrue; 'Stay in toolbar end 'DialogStatic '---------------------------------------------------- ' IncreaseLatency ' '5/1/06 '---------------------------------------------------- func LatencyIncrease%() 'just change one table entry gTable%[10] := gTable%[10] + 10; '0.1 ms at 100kHz pCollisionLatency := gTable%[10]; 'to report in log window 're-send whole table SampleSeqTable(gTable%, kTableOffset1000%); 'load all this data into the tabl SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed Report(); TitleCollision(); return kTrue; 'Stay with toolbar end 'LatencyIncrease '---------------------------------------------------- ' DecreaseLatency ' '5/1/06 '---------------------------------------------------- func LatencyDecrease%() 'just change one table entry gTable%[10] := gTable%[10] - 10; '0.1 ms at 100kHz pCollisionLatency := gTable%[10]; 'to report in log window 're-send whole table SampleSeqTable(gTable%, kTableOffset1000%); 'load all this data into the tabl SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed Report(); TitleCollision(); return kTrue; 'Stay with toolbar end 'LatencyDecrease '---------------------------------------------------- ' StaticLoad ' 'This routine computes and passes the next static 'target position to the sequencer. '4/22/03 '---------------------------------------------------- proc StaticLoad() var boardAddress, LEDaddress, aRadius, aTheta, aTable%[kTableSize%], aX, aY, aMax, aCurrent; docase 'coordinate pairs have to be both used case pStaticMode = kStaticXY then SampleSeqVar(1, Degrees2dac%(pStaticXorRadius + pHorzOffset)); SampleSeqVar(2, Degrees2dac%(pStaticYorTheta + pVertOffset)); aTable%[1] := Degrees2dac%(pStaticXorRadius + pHorzOffset); aTable%[2] := Degrees2dac%(pStaticYorTheta + pVertOffset); XY2Radial(pStaticXorRadius, pStaticYorTheta, 0, 0,aRadius, aTheta); aRadius := round(aRadius); aTheta := round(aTheta); case pStaticMode = kStaticRadial then SampleSeqVar(1, Radial2dacH%(pStaticXorRadius, pStaticYorTheta, pHorzOffset)); SampleSeqVar(2, Radial2dacV%(pStaticXorRadius, pStaticYorTheta, pVertOffset)); aTable%[01] := Radial2dacH%(pStaticXorRadius, pStaticYorTheta, pHorzOffset); aTable%[02] := Radial2dacV%(pStaticXorRadius, pStaticYorTheta, pVertOffset); aRadius := pStaticXorRadius; aTheta := pStaticYorTheta; endcase EncodeLED80 (aRadius, aTheta, kRedColorBit, boardAddress, LEDaddress); SampleSeqVar(3, (boardAddress + 192) * 256); 'shift left 8 bits SampleSeqVar(4, LEDaddress * 256); 'shift left 8 bits aTable%[03] := (boardAddress + 192) * 256; 'shift left 8 bits aTable%[04] := LEDaddress * 256; 'shift left 8 bits 'send stimulate parameters aTable%[05] := pStimShutterDur; 'shutter closed in ms aTable%[06] := pStimDelay; 'stim delay in ms aTable%[07] := pStimDur; 'stim duration in ms aTable%[08] := pStimType%; 'stim type gTable%[09] := 0; 'Indicate that we want to position the target aTable%[10] := pCollisionLatency; aTable%[15] := pStimInterval; 'search mode, time between pulses aTable%[16] := pStimNoResponse; aCurrent := 0; if ViewKind(gSpotWindow%) >= 0 then View(gSpotWindow%); 'Make the data view the current view aCurrent := xHigh() - 1; 'subtract the extra 1 degree endif aMax := max(aRadius, aCurrent, 20); '20 degrees minimum SetSpotScales(aMax, aMax, pHorzOffset, pVertOffset); SetScrollingScales(aMax, aMax, pHorzOffset, pVertOffset); ArrConst(gTable%, 0); 'clear global table data ArrAdd(gTable%, aTable%); 'copy the table to be used with NEWDIG SampleSeqTable(gTable%, kTableOffset1000%); 'load all this data into the tabl end 'StaticLoad '---------------------------------------------------- ' StaticStimulate 'Enables the "S" key to shutter the target and send 'a stimulation trigger pulse. '1/20/04 '---------------------------------------------------- func StaticStimulate%() 'just change one table entry gTable%[09] := 1; 'Indicate that we want to stimulate 're-send whole table SampleSeqTable(gTable%, kTableOffset1000%); 'load all this data into the tabl SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed return kTrue; 'Stay with toolbar end 'StaticStimulate '---------------------------------------------------- ' StaticLf5 'Enables arrow key control of the static mode. '1/20/04 '---------------------------------------------------- func StaticLf5%() ResetModeVariables(); if pStaticMode = kStaticRadial then Message("Converting from Radial to XY coordinates and starting from the center."); pStaticXorRadius := 0; pStaticYorTheta := 0; pStaticMode := kStaticXY; endif pStaticXorRadius := pStaticXorRadius - 5; StaticLoad(); SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed return kTrue; 'Stay with toolbar end 'StaticLf5 '---------------------------------------------------- ' StaticRt5 'Enables arrow key control of the static mode. '1/20/04 '---------------------------------------------------- func StaticRt5%() ResetModeVariables(); if pStaticMode = kStaticRadial then Message("Converting from Radial to XY coordinates and starting from the center."); pStaticXorRadius := 0; pStaticYorTheta := 0; pStaticMode := kStaticXY; endif pStaticXorRadius := pStaticXorRadius + 5; StaticLoad(); SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed return kTrue; 'Stay with toolbar end 'StaticRt5 '---------------------------------------------------- ' StaticCenter 'Enables spacebar control of the static mode. '1/20/04 '---------------------------------------------------- func StaticCenter%() ResetModeVariables(); if pStaticMode = kStaticRadial then Message("Converting from Radial to XY coordinates and starting from the center."); pStaticXorRadius := 0; pStaticYorTheta := 0; pStaticMode := kStaticXY; endif pStaticXorRadius := 0; pStaticYorTheta := 0; StaticLoad(); SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed return kTrue; 'Stay with toolbar end 'StaticCenter '---------------------------------------------------- ' StaticUp5 'Enables arrow key control of the static mode. '1/20/04 '---------------------------------------------------- func StaticUp5%() ResetModeVariables(); if pStaticMode = kStaticRadial then Message("Converting from Radial to XY coordinates and starting from the center."); pStaticXorRadius := 0; pStaticYorTheta := 0; pStaticMode := kStaticXY; endif pStaticYorTheta := pStaticYorTheta + 5; StaticLoad(); SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed return kTrue; 'Stay with toolbar end 'StaticUp5 '---------------------------------------------------- ' StaticDn5 'Enables arrow key control of the static mode. '1/20/04 '---------------------------------------------------- func StaticDn5%() ResetModeVariables(); if pStaticMode = kStaticRadial then Message("Converting from Radial to XY coordinates and starting from the center."); pStaticXorRadius := 0; pStaticYorTheta := 0; pStaticMode := kStaticXY; endif pStaticYorTheta := pStaticYorTheta - 5; StaticLoad(); SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed return kTrue; 'Stay with toolbar end 'StaticDn5 '---------------------------------------------------- ' DialogRamp '2/12/03 '---------------------------------------------------- func DialogRamp%() var ok%, aTable%[kTableSize%], a, i, item1$, item3$, item4$, aTab1 := 27, aTab2, aTab3 := 34, aTab4, aRow := 1, a%, b%, i%, j%, m%, n%, t%, u%, aTest%, aTheta, aBitsIn; aBitsIn := pow(2,16); '65536 aTab2 := aTab1 + 37; aTab4 := aTab3 + kUnitLabel; 'prepare the multi input parameters for i := 0 to 7 do if pRampAngle[i] = kNAN then 'do not display it else item1$ := item1$ + Str$(pRampAngle[i]) + " "; endif if pRampPriVelocity[i] = kNAN then 'do not display it else item3$ := item3$ + Str$(pRampPriVelocity[i]) + " "; endif if pRampSecVelocity[i] = kNAN then 'do not display it else item4$ := item4$ + Str$(pRampSecVelocity[i]) + " "; endif next dlgcreate("Ramp Parameters",kX); dlgstring(1,"Angles (<9)",aTab1,". 0123456789", aTab3, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 1; dlgreal(2,"StepRamp / Ramp ratio",0,100, aTab3, aRow); dlgText("%", aTab4, aRow); aRow := aRow + 2; dlgstring(3,"Primary Velocities (<9)",aTab1,". 0123456789", aTab3, aRow); dlgText("d/s", aTab2, aRow); aRow := aRow + 1; dlgstring(4,"Secondary Velocities (<9)",aTab1,". 0123456789", aTab3, aRow); dlgText("d/s", aTab2, aRow); aRow := aRow + 1; dlgreal(5,"Secondary Velocity start time",0,10000, aTab3, aRow); dlgText("ms", aTab4, aRow); aRow := aRow + 2; dlgreal(6,"Excursion",0,50, aTab3, aRow); dlgText("deg", aTab4, aRow); aRow := aRow + 1; dlgreal(7,"Pre-Ramp step latency",0,10000, aTab3, aRow); dlgText("ms", aTab4, aRow); aRow := aRow + 2; dlgreal(8,"Plateau 1",0,10000, aTab3, aRow); dlgText("ms", aTab4, aRow); aRow := aRow + 1; dlgreal(9,"Plateau 2",0,10000, aTab3, aRow); dlgText("ms", aTab4, aRow); aRow := aRow + 1; dlgText("", aTab4, aRow); aRow := aRow + 1; ok% := dlgshow(item1$,pRampRatio,item3$,item4$,pRampSecVelStartTime,pRampExcursion,pRampStepLatency,pRampPlateau1,pRampPlateau2); if ok% > 0 then if gLastMode% <> kRamp then gLastMode% := kRamp; SaveLastDataFile(); ResetModeVariables(); CreateFileName(kRamp); New%(); Start%(); '(kFalse); else ResetModeVariables(); endif a := ReadStr(item1$, pRampAngle); for i := a to 7 do pRampAngle[i] := kNAN; 'unused angles must be filled with NAN next a := ReadStr(item3$, pRampPriVelocity); for i := a to 7 do pRampPriVelocity[i] := kNAN; 'unused angles must be filled with NAN next a := ReadStr(item4$, pRampSecVelocity); for i := a to 7 do pRampSecVelocity[i] := kNAN; 'unused angles must be filled with NAN next '0-9 GENERAL TABLE VARIABLES m% := 0; aTable%[m%+0] := pRampRatio / 100 * 128; 'convert ratio to power of two to make it easier in sequencer aTable%[m%+1] := pRampPlateau1; 'first plateau aTable%[m%+2] := pRampPlateau2; 'second plateau aTable%[m%+3] := pRampStepLatency; 'step duration aTest% := 0; for a% := 0 to 7 do if pRampSecVelocity[a%] <> kNAN then aTest% := 1; endif next if aTest% = 0 then pRampSecVelStartTime := 0; 'make sure that no secondary velocity time is saved when no secondary velocities have been specified endif aTable%[m%+4] := pRampSecVelStartTime; 'when second velocity starts '20-90, load up the PRIMARY VELOCITY INCREMENT X-VALUES chart '180-260, load up the SECONDARY VELOCITY INCREMENT X-VALUES chart m% := 20; n% := 180; for a% := 0 to 7 do for b% := 0 to 7 do if (pRampAngle[a%] = kNAN) or (pRampPriVelocity[b%] = kNAN) then aTable%[m%+b%] := kNAN; aTable%[n%+b%] := kNAN; else aTable%[m%+b%] := Radial2dacH%(pRampPriVelocity[b%]/1000, pRampAngle[a%], 0); '1 ms X increment in DAC terms aTable%[n%+b%] := Radial2dacH%(pRampSecVelocity[b%]/1000, pRampAngle[a%], 0); '1 ms X increment in DAC terms endif next m% := m% + 10; n% := n% + 10; next '100-170, load up the PRIMARY VELOCITY INCREMENT Y-VALUES chart '260-340, load up the SECONDARY VELOCITY INCREMENT Y-VALUES chart m% := 100; n% := 260; for a% := 0 to 7 do for b% := 0 to 7 do if (pRampAngle[a%] = kNAN) or (pRampPriVelocity[b%] = kNAN) then aTable%[m%+b%] := kNAN; aTable%[n%+b%] := kNAN; else aTable%[m%+b%] := Radial2dacV%(pRampPriVelocity[b%]/1000, pRampAngle[a%], 0); '1 ms Y increment in DAC terms aTable%[n%+b%] := Radial2dacV%(pRampSecVelocity[b%]/1000, pRampAngle[a%], 0); '1 ms y increment in DAC terms endif next m% := m% + 10; n% := n% + 10; next m% := 10; t% := 340; u% := 350; 'active directions for i% := 0 to 7 do aTable%[m%+i%] := 0; 'usage counter if pRampAngle[i%] <> kNAN then aTheta := pRampAngle[i%]; aTable%[t%+i%] := Radial2dacH%(pRampExcursion, aTheta, 0); 'limit X in DAC terms aTable%[u%+i%] := Radial2dacV%(pRampExcursion, aTheta, 0); 'limit Y in DAC terms endif next Table(aTable%[]); 'kBOBmode ' 'display the table of data being send to the sequence ' if kBOBmode = kTrue then ' view(gDebugWindow%); ' j% := 0; ' while j% < 510 do ' Print("%5d,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f\n", j%, aTable%[j%+0], aTable%[j%+1], aTable%[j%+2], aTable%[j%+3], aTable%[j%+4], aTable%[j%+5], aTable%[j%+6], aTable%[j%+7], aTable%[j%+8], aTable%[j%+9]); ' j% := j% + 10; ' wend ' endif SetSpotScales(pRampExcursion, pRampExcursion, 0, 0); SetScrollingScales(pRampExcursion, pRampExcursion, 0, 0); ArrConst(gTable%, 0); 'clear global table data ArrAdd(gTable%, aTable%); 'copy the table to be used with NEWDIG SampleSeqTable(gTable%, kTableOffset1000%); 'load all this data into the tabl ResetVectorCounterCommon(); SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed SetToolbar(kRamp); SetVelocityChannels(); EditSelectAll(); EditClear(); ReportFlagSet(); endif return kTrue; 'Stay in toolbar end 'DialogRamp '---------------------------------------------------- ' ResetVectorCounterCommon ' 'Reset the vector counter area in the TABLE '4/5/07 '---------------------------------------------------- func ResetVectorCounterCommon() var j%, aTable%[1000]; SampleSeqTable(aTable%, kTableOffsetCommon%, 1); 'get 0-999 for j% := 0 to 7 do aTable%[j% + kTableRampCounters%] := 0; 'initialize next SampleSeqTable(aTable%, kTableOffsetCommon%); 'set 0-999 end 'ResetVectorCounterCommon '---------------------------------------------------- ' DialogMemory 'Presents the Overlap and Remembered paradigms. '2/16/05 '---------------------------------------------------- func DialogMemory%() var a%, b%, i%, j%, k%, m%, n%, p%, q%, r%, s%, t%, u%, v%, w%, aOpposite, aProblem, bProblem, aBitsIn, aRow1$[3], aRow2$[3], aRow3$[3], aRow4$[3], item2$, item3$, item4$, item5$, item6$, ok%, aRow := 2, aTab1, aTab2, aTab4, aTab5, aTab6, aTab7, aGroup, aTest, theMode%, aNumVectors%, aHowMany, aRadius%, aNumRadii%, aTheta%, aTable%[kTableSize%], aRadiusArray[kMaxVectors%], aThetaArray[kMaxVectors%], boardAddress, LEDaddress, aTheta, b, c, aSlope, aPerpSlope, aReal, bReal, cReal, aIntA%[6]; aBitsIn := pow(2,16); '65536 aTab1 := 5; aTab2 := aTab1 + 25; aTab4 := aTab2 + kUnitLabel; aTab5 := aTab1 + 16; aTab6 := aTab5 + 16; aTab7 := aTab5 + 30; 'Transfer the numeric values to strings to be shown in the 'dialog box. Strings are needed so fields can be empty if not used. 'If a value is kNAN then show an empty field. if pMemoryVectors[0] <> kNAN then aRow1$[0] := str$(pMemoryVectors[0]); endif if pMemoryAdapt[0] <> kNAN then aRow1$[1] := str$(pMemoryAdapt[0]); endif if pMemoryAdapt[4] <> kNAN then aRow1$[2] := str$(pMemoryAdapt[4]); endif if pMemoryVectors[1] <> kNAN then aRow2$[0] := str$(pMemoryVectors[1]); endif if pMemoryAdapt[1] <> kNAN then aRow2$[1] := str$(pMemoryAdapt[1]); endif if pMemoryAdapt[5] <> kNAN then aRow2$[2] := str$(pMemoryAdapt[5]); endif if pMemoryVectors[2] <> kNAN then aRow3$[0] := str$(pMemoryVectors[2]); endif if pMemoryAdapt[2] <> kNAN then aRow3$[1] := str$(pMemoryAdapt[2]); endif if pMemoryAdapt[6] <> kNAN then aRow3$[2] := str$(pMemoryAdapt[6]); endif if pMemoryVectors[3] <> kNAN then aRow4$[0] := str$(pMemoryVectors[3]); endif if pMemoryAdapt[3] <> kNAN then aRow4$[1] := str$(pMemoryAdapt[3]); endif if pMemoryAdapt[7] <> kNAN then aRow4$[2] := str$(pMemoryAdapt[7]); endif Array2Str$(pMemoryInitialSteps[], 7, item2$); Array2Str$(pMemoryFixDur[], 7, item3$); Array2Str$(pMemoryFixPeriphDurs[], 7, item4$); Array2Str$(pMemoryWaitDurs[], 7, item5$); Array2Str$(pMemoryPeriphDurs[], 7, item6$); 'Setup the dialog box and its controls dlgcreate("Memory",kX); dlgtext(" Pos Vector Pos Vector Neg Vector", 0, aRow); aRow := aRow + 1; 'These must be strings so it is possible to have empty 'fields. Real and integer fields must contain a value. dlgstring(1,"",6,".0123456789", aTab1, aRow); dlgstring(2,"",6,".0123456789-", aTab5, aRow); dlgstring(3,"",6,".0123456789-", aTab6, aRow); dlglist(4,"","None|Pos Direction|Neg Direction|Pos & Neg Dirs", 99, aTab7, aRow); aRow := aRow + 1; dlgstring(5,"",6,".0123456789", aTab1, aRow); dlgstring(6,"",6,".0123456789-", aTab5, aRow); dlgstring(7,"",6,".0123456789-", aTab6, aRow); dlglist(8,"","None|Pos Direction|Neg Direction|Pos & Neg Dirs", 99, aTab7, aRow); aRow := aRow + 1; dlgstring(9,"",6,".0123456789", aTab1, aRow); dlgstring(10,"",6,".0123456789-", aTab5, aRow); dlgstring(11,"",6,".0123456789-", aTab6, aRow); dlglist(12,"","None|Pos Direction|Neg Direction|Pos & Neg Dirs", 99, aTab7, aRow); aRow := aRow + 1; dlgstring(13,"",6,".0123456789", aTab1, aRow); dlgstring(14,"",6,".0123456789-", aTab5, aRow); dlgstring(15,"",6,".0123456789-", aTab6, aRow); dlglist(16,"","None|Pos Direction|Neg Direction|Pos & Neg Dirs", 99, aTab7, aRow); aRow := aRow + 1; 'spaces used to position text dlgtext(" 0 - 90° ±0.00 thru 0.99 = percent step", 0, aRow); aRow := aRow + 1; dlgtext(" 271 - 360° ±1.00 and above = fixed step Random % to Stimulate", 0, aRow); aRow := aRow + 1; dlgtext("opp computed Neg = towards the center", 0, aRow); dlginteger(17,"",0,100,aTab7,aRow); aRow := aRow + 1; aGroup := dlgGroup("", 48, 1, -1, 9); 'upper left (xy), width, height [vertical=lines, horz=char] aGroup := dlgGroup("", 15, 1, -1, 9); 'upper left (xy), width, height [vertical=lines, horz=char] aGroup := dlgGroup(" - Vectors - - - - - - - - - - - Adapt Steps - - - - - - - - - - - Stimulation - ", 1, 1, 14, 9); 'upper left (xy), width, height [vertical=lines, horz=char] aRow := aRow + 1; dlgtext("Multiple vectors used only when Return to Zero selected", 0, aRow); aRow := aRow + 2; dlgText("(Flash primary until on-target)", aTab2 - 3, aRow); aRow := aRow + 1; dlgstring(18,"Fixation dur (<9)",23,". 0123456789", aTab2, aRow); dlgText("sec", aTab2 + 26, aRow); aRow := aRow + 1; dlglist(19,"Every step is","Random|Return to Zero", 99, aTab2, aRow); aRow := aRow + 1; dlgstring(20,"Initial step sizes (<9)",23,". 0123456789", aTab2, aRow); dlgText("deg", aTab2 + 26, aRow); aRow := aRow + 1; dlginteger(21,"Memory / Control Trial Ratio", 0, 100, aTab2, aRow); dlgText("%", aTab4, aRow); aRow := aRow + 1; dlgstring(22,"Fixation and Peripheral dur (<9)",23,". 0123456789", aTab2, aRow); dlgText("sec", aTab2 + 26, aRow); aRow := aRow + 1; dlgstring(23,"Peripheral off then wait dur (<9)",23,". 0123456789", aTab2, aRow); dlgText("sec (Remembered only)", aTab2 + 26, aRow); aRow := aRow + 1; dlginteger(24,"Stimulation #1 dur",0,2000, aTab2, aRow); dlgText("ms", aTab4, aRow); aRow := aRow + 1; dlgText("(Must not move for 50 ms)", aTab2 - 3, aRow); aRow := aRow + 1; dlgReal(25,"Response dur up to",0,2000, aTab2, aRow); dlgText("sec", aTab4, aRow); aRow := aRow + 1; dlginteger(26,"Velocity onset",0,2000, aTab2, aRow); dlgText("d/s (Used by all modes)", aTab4, aRow); aRow := aRow + 1; dlginteger(27,"Velocity offset",0,2000, aTab2, aRow); dlgText("d/s (Used by Rel Eye)", aTab4, aRow); aRow := aRow + 1; dlginteger(28,"Stimulation #2 dur",0,2000, aTab2, aRow); dlgText("ms", aTab4, aRow); aRow := aRow + 1; 'SAVE: waiting for need to code proportional to eye stepping 'dlglist(23,"Type of Adapt Step","Fixed Rel Target|Fixed Rel Eye|Prop Rel Eye", 99, aTab2, aRow); dlglist(29,"Type of adapt step","Fixed Rel Target|Fixed Rel Eye", 99, aTab2, aRow); aRow := aRow + 1; dlginteger(30,"Target follows eye position for",0,2000, aTab2, aRow); dlgText("ms", aTab4, aRow); aRow := aRow + 1; dlgText("(Must stay on-target for 300 ms or enter Follow mode)", aTab2 - 3, aRow); aRow := aRow + 1; dlgText("(Feed)", aTab2 - 3, aRow); aRow := aRow + 1; ' dlglist(30,"Flash new target until on-target","No|Yes", 99, aTab2, aRow); ' aRow := aRow + 1; dlglist(31,"Post response target(s)","Both Colors|Primary Color|Secondary Color", 99, aTab2, aRow); aRow := aRow + 1; dlgstring(32,"Post response dur (<9)",23,". 0123456789", aTab2, aRow); dlgText("sec", aTab2 + 26, aRow); aRow := aRow + 1; dlgText("(Feed again if remained on-target)", aTab2 - 3, aRow); aRow := aRow + 1; dlglist(33,"If not participating, then","Abort, Repeat this Trial|Abort, Start a New Trial", 99, aTab2, aRow); aRow := aRow + 1; ' dlglist(33,"Flash new target until on-target","No|Yes", 99, aTab2, aRow); ' aRow := aRow + 1; dlgText("", aTab2, aRow); 'stuff some like-type variables into an array to stay under the limit of 20 dlgShow variables aIntA%[0] := pMemoryOnSetVel; aIntA%[1] := pMemoryOffsetVel; aIntA%[2] := pMemoryStim2; aIntA%[3] := pMemoryType; aIntA%[4] := pMemoryFollowDur; ' aIntA%[5] := pMemoryPostFailure; ' aIntA%[6] := pMemoryPostColor; aIntA%[5] := pMemoryPostColor; SampleSeqVar(sPARAMCHANGED, 0); 'signal that parameters may change, sequencer get ready to receive ' ok% := dlgShow(aRow1$[], pMemoryStimDir[0], ' aRow2$[], pMemoryStimDir[1], ' aRow3$[], pMemoryStimDir[2], ' aRow4$[], pMemoryStimDir[3], ' pMemoryStimRatio, ' item3$, pMemoryRTZ, item2$, item4$, item5$, pMemoryStim1, pMemoryResponseDur, ' aIntA%[], ' item6$, pMemoryTimeouts,pMemoryPostFailure); ok% := dlgShow(aRow1$[], pMemoryStimDir[0], aRow2$[], pMemoryStimDir[1], aRow3$[], pMemoryStimDir[2], aRow4$[], pMemoryStimDir[3], pMemoryStimRatio, item3$, pMemoryRTZ, item2$, pMemoryMemCtlRatio, item4$, item5$, pMemoryStim1, pMemoryResponseDur, aIntA%[], item6$, pMemoryTimeouts); docase case ok% = 0 then SampleSeqVar(sPARAMCHANGED, 2); 'resume without reseting counters, etc. case ok% > 0 then 'TEST that all vectors are positive directions. If not, bail out. aProblem := kFalse; aTest := val(aRow1$[0]); if aTest > 90 and aTest < 271 then aProblem := kTrue; endif aTest := val(aRow2$[0]); if aTest > 90 and aTest < 271 then aProblem := kTrue; endif aTest := val(aRow3$[0]); if aTest > 90 and aTest < 271 then aProblem := kTrue; endif aTest := val(aRow4$[0]); if aTest > 90 and aTest < 271 then aProblem := kTrue; endif if aProblem = kTrue then dlgcreate("Bad Parameter",kX); dlgtext("All vectors must be 90° or less.", 0, 1); dlgtext("Or they must be greater than 270°.", 0, 2); dlgtext(" ", 0, 3); DlgButton(0,""); 'remove the CANCEL button ok% := dlgShow(); endif 'TEST that only percent adapt steps have been selected when proportional to eye adapt stepping has been selected if pMemoryType = 2 then 'adapt type if abs(val(aRow1$[1])) >= 1 then bProblem := kTrue; endif if abs(val(aRow1$[2])) >= 1 then bProblem := kTrue; endif if abs(val(aRow2$[1])) >= 1 then bProblem := kTrue; endif if abs(val(aRow2$[2])) >= 1 then bProblem := kTrue; endif if abs(val(aRow3$[1])) >= 1 then bProblem := kTrue; endif if abs(val(aRow3$[2])) >= 1 then bProblem := kTrue; endif if abs(val(aRow4$[1])) >= 1 then bProblem := kTrue; endif if abs(val(aRow4$[2])) >= 1 then bProblem := kTrue; endif endif if bProblem = kTrue then dlgcreate("Bad Parameter",kX); dlgtext("All adapt steps must be expressed in percent", 0, 1); dlgtext("when using proportional adapt stepping.", 0, 2); dlgtext(" ", 0, 3); DlgButton(0,""); 'remove the CANCEL button ok% := dlgShow(); endif 'implemented this way to accomodate multiple error messages if (aProblem = kFalse) and (bProblem = kFalse) then if gLastMode% <> kMemory then gLastMode% := kMemory; SaveLastDataFile(); ResetModeVariables(); CreateFileName(kMemory); New%(); Start%(); '(kTrue); else ResetModeVariables(); endif 'un-stuff some like variables into an array to keep under the limit of 20 dlgShow variables pMemoryOnSetVel := aIntA%[0]; pMemoryOffsetVel := aIntA%[1]; pMemoryStim2 := aIntA%[2]; pMemoryType := aIntA%[3]; pMemoryFollowDur := aIntA%[4]; ' pMemoryPostFailure := aIntA%[5]; ' pMemoryPostColor := aIntA%[6]; pMemoryPostColor := aIntA%[5]; gMemoryTimeForZero := kFalse; 'Set all the parameters to invalid ArrConst(pMemoryVectors[], kNAN); ArrConst(pMemoryAdapt[], kNAN); 'Fill the parameters with a numeric value if 'one was provided, otherwise, leave it set to kNAN. if aRow1$[0] <> "" then pMemoryVectors[0] := val(aRow1$[0]); endif; if aRow1$[1] <> "" then pMemoryAdapt[0] := val(aRow1$[1]); endif; if aRow1$[2] <> "" then pMemoryAdapt[4] := val(aRow1$[2]); endif; if aRow2$[0] <> "" then pMemoryVectors[1] := val(aRow2$[0]); endif; if aRow2$[1] <> "" then pMemoryAdapt[1] := val(aRow2$[1]); endif; if aRow2$[2] <> "" then pMemoryAdapt[5] := val(aRow2$[2]); endif; if aRow3$[0] <> "" then pMemoryVectors[2] := val(aRow3$[0]); endif; if aRow3$[1] <> "" then pMemoryAdapt[2] := val(aRow3$[1]); endif; if aRow3$[2] <> "" then pMemoryAdapt[6] := val(aRow3$[2]); endif; if aRow4$[0] <> "" then pMemoryVectors[3] := val(aRow4$[0]); endif; if aRow4$[1] <> "" then pMemoryAdapt[3] := val(aRow4$[1]); endif; if aRow4$[2] <> "" then pMemoryAdapt[7] := val(aRow4$[2]); endif; 'force all active vectors to have a valid adapt size, if none specified, 'substitute zero instead of NAN for i% := 0 to 3 do if pMemoryVectors[i%] <> kNAN then if pMemoryAdapt[i%] = kNAN then pMemoryAdapt[i%] := 0; endif if pMemoryAdapt[i% + 4] = kNAN then pMemoryAdapt[i% + 4] := 0; endif endif next 'setup opposite vectors aNumVectors% := 0; for i% := 0 to 3 do if pMemoryVectors[i%] <> kNAN then aNumVectors% := aNumVectors% + 2; 'specified vector and opposite vector aOpposite := i% + 4; pMemoryVectors[aOpposite] := pMemoryVectors[i%] + 180; if pMemoryVectors[aOpposite] >= 360 then pMemoryVectors[aOpposite] := pMemoryVectors[aOpposite] - 360 endif endif next 'must set unused to kNAN here since some items come through as zero even though the array is preset to kNAN aHowMany := ReadStr(item3$, pMemoryFixDur); 'read in the fixation duration for i% := aHowMany to 7 do pMemoryFixDur[i%] := kNAN; 'unused steps must be filled with NAN next aHowMany := ReadStr(item4$, pMemoryFixPeriphDurs); 'read in the fixation duration for i% := aHowMany to 7 do pMemoryFixPeriphDurs[i%] := kNAN; 'unused steps must be filled with NAN next aHowMany := ReadStr(item5$, pMemoryWaitDurs); 'read in the fixation duration for i% := aHowMany to 7 do pMemoryWaitDurs[i%] := kNAN; 'unused steps must be filled with NAN next aHowMany := ReadStr(item6$, pMemoryPeriphDurs); 'read in the fixation duration for i% := aHowMany to 7 do pMemoryPeriphDurs[i%] := kNAN; 'unused steps must be filled with NAN next aHowMany := ReadStr(item2$, pMemoryInitialSteps); 'read in target steps for i% := aHowMany to 7 do pMemoryInitialSteps[i%] := kNAN; 'unused steps must be filled with NAN next b := (aBitsIn/20) * (pMemoryOnSetVel/100); c := (aBitsIn/20) * ((pMemoryOnSetVel/2)/100); 'pre-set all locations to NAN ArrConst(aTable%[], kNAN); 'Adapt paradigm info stored in TABLE, A=8000 ' A+0 = Type of adapt: 0=RelTarg, 1=RelEye, 2=ProEye ' A+1 = Type of stepping: 0=RTZ, 1=Random ' A+2 = Timeouts: 0=repeat trial, 1=new trial ' A+3 = Onset Velocity Threshold ' A+4 = Offset Velocity Threshold ' A+5 ' A+6 = Follow Duration ' A+7 = Response Duration ' A+8 = Response Failure: 0=Do Not Flash, 1=Flash ' A+9 = Post Color: 0=both, 1=primary, 2=secondary ' A+10 ' A+11 ' A+12 = Stimulation/NoStimulation ratio ' A+13 ' A+14 ' A+15 ' A+16 ' A+17 ' A+18 ' A+19 'A+20-29 INITIAL STEPS on vector 0 in X DAC units 'A+30-39 INITIAL STEPS on vector 1 in X DAC units 'A+40-49 INITIAL STEPS on vector 2 in X DAC units 'A+50-59 INITIAL STEPS on vector 3 in X DAC units 'A+60-69 INITIAL STEPS on vector 4 in X DAC units 'A+70-79 INITIAL STEPS on vector 5 in X DAC units 'A+80-89 INITIAL STEPS on vector 6 in X DAC units 'A+90-99 INITIAL STEPS on vector 7 in X DAC units 'A+100-109 INITIAL STEPS on vector 0 in Y DAC units 'A+110-119 INITIAL STEPS on vector 1 in Y DAC units 'A+120-129 INITIAL STEPS on vector 2 in Y DAC units 'A+130-139 INITIAL STEPS on vector 3 in Y DAC units 'A+140-149 INITIAL STEPS on vector 4 in Y DAC units 'A+150-159 INITIAL STEPS on vector 5 in Y DAC units 'A+160-169 INITIAL STEPS on vector 6 in Y DAC units 'A+170-179 INITIAL STEPS on vector 7 in Y DAC units 'A+180-189 ADAPT STEPS on vector 0 in X DAC units 'A+190-199 ADAPT STEPS on vector 1 in X DAC units 'A+200-209 ADAPT STEPS on vector 2 in X DAC units 'A+210-219 ADAPT STEPS on vector 3 in X DAC units 'A+220-229 ADAPT STEPS on vector 4 in X DAC units 'A+230-239 ADAPT STEPS on vector 5 in X DAC units 'A+240-249 ADAPT STEPS on vector 6 in X DAC units 'A+250-259 ADAPT STEPS on vector 7 in X DAC units 'A+260-269 ADAPT STEPS on vector 0 in Y DAC units 'A+270-279 ADAPT STEPS on vector 1 in Y DAC units 'A+280-289 ADAPT STEPS on vector 2 in Y DAC units 'A+290-299 ADAPT STEPS on vector 3 in Y DAC units 'A+300-309 ADAPT STEPS on vector 4 in Y DAC units 'A+310-319 ADAPT STEPS on vector 5 in Y DAC units 'A+320-329 ADAPT STEPS on vector 6 in Y DAC units 'A+330-339 ADAPT STEPS on vector 7 in Y DAC units 'A+340-349 LED board addresses 'A+350-359 Axis Slopes, compute the slope from a line going through 0,0 and 1 deg on the desired axis '(y2-y1)/(x2-x1) = (y2-0)/(x2-0) = y2/x2 'A+360-369 PERPENDICULAR Axis Slopes 'perpSlope = -(1/slope) 'Two special cases: 'axis = 0 or 180 degrees; slope = 0; perpSlope= NAN; use eye X and target Y 'axis = 90 or 270 degrees; slope = NAN; perpSlope = 0; use eye Y and target X 'A+370-379 EXCURSION LIMIT in X DAC units 'A+380-389 EXCURSION LIMIT in Y DAC units 'A+390-399 X value for 1 deg step (for LED computation) 'A+400-409 Y value for 1 deg step (for LED computation) 'A+410-419 fixation durations 'A+420-429 fixation/peripheral durations 'A+430-439 wait durations 'A+440-449 peripheral durations 'A+450-459 step stimulation durations 'A+460-469 velocity stimulation durations '0-9 GENERAL TABLE VARIABLES m% := 0; aTable%[m%+0] := pMemoryType; '0=FixTarg, 1=FixEye, 2=ProEye if pMemoryRTZ = kTrue then aTable%[m%+1] := 1; 'yes RTZ, move to zero first else aTable%[m%+1] := -1; 'no RTZ, invalid value endif aTable%[m%+2] := pMemoryTimeOuts; aTable%[m%+3] := (aBitsIn/20) * (pMemoryOnSetVel/100); aTable%[m%+4] := (aBitsIn/20) * (pMemoryOffSetVel/100); aTable%[m%+6] := pMemoryFollowDur; aTable%[m%+7] := pMemoryResponseDur * 1000; 'in ms aTable%[m%+8] := pMemoryPostFailure; aTable%[m%+9] := pMemoryPostColor; aTable%[m%+12] := pMemoryStimRatio / 100 * 128; 'convert ratio to power of two to make it easier in sequencer aTable%[m%+13] := abs(128-(pMemoryMemCtlRatio / 100 * 128)); 'hi=mem, lo=ctl, abs() in case of negative number, convert ratio to power of two to make it easier in sequencer '20-90, load up the INITIAL STEP X-VALUES chart '180-260, load up the ADAPT STEP X-VALUES chart m% := 20; n% := 180; for a% := 0 to 7 do for b% := 0 to 7 do if (pMemoryVectors[a%] = kNAN) or (pMemoryInitialSteps[b%] = kNAN) then aTable%[m%+b%] := kNAN; aTable%[n%+b%] := kNAN; else aTable%[m%+b%] := Radial2dacH%(pMemoryInitialSteps[b%], pMemoryVectors[a%], 0); 'initial X in DAC terms if abs(pMemoryAdapt[a%]) >= 1 then 'degrees aTable%[n%+b%] := Radial2dacH%(pMemoryAdapt[a%], pMemoryVectors[a%], 0); 'adapt X in DAC terms else if pMemoryType = 0 or pMemoryType = 1 then '0=FixTarg, 1=FixEye, 2=ProEye aReal := pMemoryAdapt[a%] * pMemoryInitialSteps[b%]; 'compute adapt step size from % backstep aTable%[n%+b%] := Radial2dacH%(aReal, pMemoryVectors[a%], 0); 'adapt X in DAC terms else 'must adjust these for the angle 'aTable%[n%+b%] := cos(Radians(pMemoryVectors[a%])) * pMemoryAdapt[a%] * 100; 'adapt X in percent * 100 endif endif endif next m% := m% + 10; n% := n% + 10; next '100-170, load up the INITIAL STEP Y-VALUES chart '260-340, load up the ADAPT STEP Y-VALUES chart m% := 100; n% := 260; for a% := 0 to 7 do for b% := 0 to 7 do if (pMemoryVectors[a%] = kNAN) or (pMemoryInitialSteps[b%] = kNAN) then aTable%[m%+b%] := kNAN; aTable%[n%+b%] := kNAN; else aTable%[m%+b%] := Radial2dacV%(pMemoryInitialSteps[b%], pMemoryVectors[a%], 0); 'initial X in DAC terms if abs(pMemoryAdapt[a%]) >= 1 then 'degrees aTable%[n%+b%] := Radial2dacV%(pMemoryAdapt[a%], pMemoryVectors[a%], 0); 'adapt X in DAC terms else if pMemoryType = 0 or pMemoryType = 1 then '0=FixTarg, 1=FixEye, 2=ProEye aReal := pMemoryAdapt[a%] * pMemoryInitialSteps[b%]; 'compute adapt step size from % backstep aTable%[n%+b%] := Radial2dacV%(aReal, pMemoryVectors[a%], 0); 'adapt Y in DAC terms else 'must adjust these for the angle 'aTable%[n%+b%] := sin(Radians(pMemoryVectors[a%])) * pMemoryAdapt[a%] * 100; 'adapt Y in percent * 100 endif endif endif next m% := m% + 10; n% := n% + 10; next m% := 10; q% := 340; r% := 350; s% := 360; t% := 370; u% := 380; v% := 390; w% := 400; 'active directions for i% := 0 to 7 do 'usage claimed to be used for more parameters 'aTable%[m%+i%] := 0; 'usage counter if pMemoryVectors[i%] <> kNAN then EncodeLED80(1, pMemoryVectors[i%], kRedColorBit, boardAddress, LEDaddress); 'determine which LED board is used aTable%[q%+i%] := boardAddress; ' This has very little use since it has the address ' for the axes and not the axis the target is on. Because ' the sequencer moves the target in an XY fashion it ' doesn't know which axis the target is on. docase case (pMemoryVectors[i%] = 0) or (pMemoryVectors[i%] = 180) then 'point is on the horizontal axis aTable%[r%+i%] := 0; 'slope is flat aTable%[s%+i%] := kNAN; 'perpendicular slope is infinity case (pMemoryVectors[i%] = 90) or (pMemoryVectors[i%] = 270) then 'point is on the vertical axis aTable%[r%+i%] := kNAN; 'slope is infinity aTable%[s%+i%] := 0; 'perpendicular slope is flat else aSlope := Radial2dacV%(1, pMemoryVectors[i%], 0) / Radial2dacH%(1, pMemoryVectors[i%], 0); 'compute slope for axis, use radius of 1 degree docase case trunc(aSlope) = 0 then aTable%[r%+i%] := 0; 'slope is flat aTable%[s%+i%] := kNAN; 'perpendicular slope is infinity case abs(aSlope) > 100 then aTable%[r%+i%] := kNAN; 'slope is infinity aTable%[s%+i%] := 0; 'perpendicular slope is flat else 'multiply slopes by 10 to preserve 0.1 accuracy while using INTEGER math in the sequencer aTable%[r%+i%] := 10 * aSlope; aTable%[s%+i%] := 10 * (-(1 / aSlope)); 'perpendicular slope is -(1/slope) endcase endcase aTheta := pMemoryVectors[i%]; aTable%[t%+i%] := Radial2dacH%(GetLimit%(aTheta), aTheta, 0); 'limit (20deg) X in DAC terms aTable%[u%+i%] := Radial2dacV%(GetLimit%(aTheta), aTheta, 0); 'limit (20deg) Y in DAC terms aTable%[v%+i%] := Radial2dacH%(1, pMemoryVectors[i%], 0); 'compute the DAC value for a 1 deg step aTable%[w%+i%] := Radial2dacV%(1, pMemoryVectors[i%], 0); 'compute the DAC value for a 1 deg step endif next endif 'if (aProblem = kFalse) and (bProblem = kFalse) m% := 410; for b% := 0 to 7 do if (pMemoryFixDur[b%] = kNAN) then aTable%[m%+b%] := kNAN; else aTable%[m%+b%] := pMemoryFixDur[b%] * 1000; 'in ms endif next m% := 420; for b% := 0 to 7 do if (pMemoryFixPeriphDurs[b%] = kNAN) then aTable%[m%+b%] := kNAN; else aTable%[m%+b%] := pMemoryFixPeriphDurs[b%] * 1000; 'in ms endif next m% := 430; for b% := 0 to 7 do if (pMemoryWaitDurs[b%] = kNAN) then aTable%[m%+b%] := kNAN; else aTable%[m%+b%] := pMemoryWaitDurs[b%] * 1000; 'in ms endif next m% := 440; for b% := 0 to 7 do if (pMemoryPeriphDurs[b%] = kNAN) then aTable%[m%+b%] := kNAN; else aTable%[m%+b%] := pMemoryPeriphDurs[b%] * 1000; 'in ms endif next m% := 450; for b% := 0 to 3 do aTable%[m%+b%] := 0; aTable%[m%+b%+4] := 0; if pMemoryStimDir[b%] = 1 then 'pos aTable%[m%+b%] := pMemoryStim1*100; endif if pMemoryStimDir[b%] = 2 then 'neg aTable%[m%+b%+4] := pMemoryStim1*100; endif if pMemoryStimDir[b%] = 3 then 'pos + neg aTable%[m%+b%] := pMemoryStim1*100; aTable%[m%+b%+4] := pMemoryStim1*100; endif next m% := 460; for b% := 0 to 3 do aTable%[m%+b%] := 0; aTable%[m%+b%+4] := 0; if pMemoryStimDir[b%] = 1 then 'pos aTable%[m%+b%] := pMemoryStim2*100; endif if pMemoryStimDir[b%] = 2 then 'neg aTable%[m%+b%+4] := pMemoryStim2*100; endif if pMemoryStimDir[b%] = 3 then 'pos + neg aTable%[m%+b%] := pMemoryStim2*100; aTable%[m%+b%+4] := pMemoryStim2*100; endif next Table(aTable%[]); 'kBOBmode ' 'display the table of data being send to the sequence ' if kBOBmode = kTrue then ' view(gDebugWindow%); ' j% := 0; ' while j% < 550 do ' Print("%5d,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f\n", j%, aTable%[j%+0], aTable%[j%+1], aTable%[j%+2], aTable%[j%+3], aTable%[j%+4], aTable%[j%+5], aTable%[j%+6], aTable%[j%+7], aTable%[j%+8], aTable%[j%+9]); ' j% := j% + 10; ' wend ' endif StartNewSession(kMemory); SetSpotScales(0,0,0,0); 'use limits, no offsets SetScrollingScales(0,0,0,0); 'SetTraceWeights(); ArrConst(gTable%, 0); 'clear global table data ArrAdd(gTable%, aTable%); 'copy the table to be used with NEWDIG SampleSeqTable(gTable%, kTableOffset1000%); 'load all this data into the tabl SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed SetToolbar(kMemory); SetVelocityChannels(); EditSelectAll(); EditClear(); ReportFlagSet(); endcase 'if ok% return kTrue; 'Stay in toolbar end; 'DialogMemory 'aNumPtsShown% '---------------------------------------------------- ' ReportFlagSet 'aT%[31] in var aT%[1000] signals that it is time to 'update the report in the LOG window. Change just one 'TABLE variable to minimize time reading and writing 'whole table. '3/23/05 '---------------------------------------------------- proc ReportFlagSet() var aVar%[1]; 'create an array with ONE element aVar%[0] := 1; 'signal that it is time to show the user some numbers SampleSeqTable(aVar%,31); 'SET REPORT flag end; 'ReportFlagSet '---------------------------------------------------- ' DialogAdapt '1/16/03 '---------------------------------------------------- func DialogAdapt%() const kSlopeMultiplier100 := 100.0; var a%, b%, i%, j%, k%, m%, n%, p%, q%, r%, s%, t%, u%, v%, w%, x%, y%, aOpposite, aProblem, bProblem, aOffset[2], aBitsIn, aRow1$[3], aRow2$[3], aRow3$[3], aRow4$[3], item1, item2, item3, item2$, item3%, item7%, item6%, ok%, aRow := 2, aTab1, aTab2, aTab4, aTab5, aTab6, aTab7, aTab8, aTab9, aGroup, aTest, theMode%, aNumVectors%, aHowMany, aRadius%, aNumRadii%, aTheta%, aTable%[kTableSize%], aRadiusArray[kMaxVectors%], aThetaArray[kMaxVectors%], boardAddress, LEDaddress, aTheta, b, c, aSlope, aPerpSlope, aReal, bReal, cReal, aIntA%[4], aWindow%[2], aSmallerStepFound%,aEqualStepFound%;', 'cSlope,dSlope; aBitsIn := pow(2,16); '65536 aTab1 := 5; aTab2 := aTab1 + 25; aTab4 := aTab2 + kUnitLabel; aTab5 := aTab1 + 16; aTab6 := aTab5 + 16; aTab7 := aTab5 + 30; aTab8 := aTab2 + 17; aTab9 := aTab2 + 30; 'Transfer the numeric values to strings to be shown in the 'dialog box. Strings are needed so fields can be empty if not used. 'If a value is kNAN then show an empty field. if pAdaptVectors[0] <> kNAN then aRow1$[0] := str$(pAdaptVectors[0]); endif if pAdaptAdapt[0] <> kNAN then aRow1$[1] := str$(pAdaptAdapt[0]); endif if pAdaptAdapt[4] <> kNAN then aRow1$[2] := str$(pAdaptAdapt[4]); endif if pAdaptVectors[1] <> kNAN then aRow2$[0] := str$(pAdaptVectors[1]); endif if pAdaptAdapt[1] <> kNAN then aRow2$[1] := str$(pAdaptAdapt[1]); endif if pAdaptAdapt[5] <> kNAN then aRow2$[2] := str$(pAdaptAdapt[5]); endif if pAdaptVectors[2] <> kNAN then aRow3$[0] := str$(pAdaptVectors[2]); endif if pAdaptAdapt[2] <> kNAN then aRow3$[1] := str$(pAdaptAdapt[2]); endif if pAdaptAdapt[6] <> kNAN then aRow3$[2] := str$(pAdaptAdapt[6]); endif if pAdaptVectors[3] <> kNAN then aRow4$[0] := str$(pAdaptVectors[3]); endif if pAdaptAdapt[3] <> kNAN then aRow4$[1] := str$(pAdaptAdapt[3]); endif if pAdaptAdapt[7] <> kNAN then aRow4$[2] := str$(pAdaptAdapt[7]); endif Array2Str$(pAdaptInitialSteps[], 7, item2$); item1 := pAdaptOnSetVel; item2 := pAdaptOffsetVel; item3 := pAdaptFollowDur; item7% := pAdaptStartRadius%; item3% := pAdaptRTZ; item6% := pAdaptGapDur; aWindow%[0] := pAdaptWindowBeg%; aWindow%[1] := pAdaptWindowEnd%; aOffset[0] := pAdaptHorzOffset%; aOffset[1] := pAdaptVertOffset%; 'Setup the dialog box and its controls dlgcreate("Adapt",kX); dlgtext(" Pos Vector Pos Vector Neg Vector", 0, aRow); aRow := aRow + 1; 'These must be strings so it is possible to have empty 'fields. Real and integer fields must contain a value. dlgstring(1,"",6,".0123456789", aTab1, aRow); dlgstring(2,"",6,".0123456789-", aTab5, aRow); dlgstring(3,"",6,".0123456789-", aTab6, aRow); dlglist(4,"","None|Pos Direction|Neg Direction|Pos & Neg Dirs", 99, aTab7, aRow); aRow := aRow + 1; dlgstring(5,"",6,".0123456789", aTab1, aRow); dlgstring(6,"",6,".0123456789-", aTab5, aRow); dlgstring(7,"",6,".0123456789-", aTab6, aRow); dlglist(8,"","None|Pos Direction|Neg Direction|Pos & Neg Dirs", 99, aTab7, aRow); aRow := aRow + 1; dlgstring(9,"",6,".0123456789", aTab1, aRow); dlgstring(10,"",6,".0123456789-", aTab5, aRow); dlgstring(11,"",6,".0123456789-", aTab6, aRow); dlglist(12,"","None|Pos Direction|Neg Direction|Pos & Neg Dirs", 99, aTab7, aRow); aRow := aRow + 1; dlgstring(13,"",6,".0123456789", aTab1, aRow); dlgstring(14,"",6,".0123456789-", aTab5, aRow); dlgstring(15,"",6,".0123456789-", aTab6, aRow); dlglist(16,"","None|Pos Direction|Neg Direction|Pos & Neg Dirs", 99, aTab7, aRow); aRow := aRow + 1; 'spaces used to position text dlgtext(" 0 - 90° ±0.00 thru 0.99 = percent step", 0, aRow); aRow := aRow + 1; dlgtext(" 271 - 360° ±1.00 and above = fixed step Random % to Stimulate", 0, aRow); aRow := aRow + 1; dlgtext("opp computed Neg = towards the center", 0, aRow); dlginteger(17,"",0,100,aTab7,aRow); aRow := aRow + 1; aGroup := dlgGroup("", 48, 1, -1, 9); 'upper left (xy), width, height [vertical=lines, horz=char] aGroup := dlgGroup("", 15, 1, -1, 9); 'upper left (xy), width, height [vertical=lines, horz=char] aGroup := dlgGroup(" - Vectors - - - - - - - - - - - Adapt Steps - - - - - - - - - - - Stimulation - ", 1, 1, 14, 9); 'upper left (xy), width, height [vertical=lines, horz=char] aRow := aRow + 1; dlgtext("Multiple vectors used only when Return to Zero selected", 0, aRow); aRow := aRow + 2; dlginteger(18,"Start at This Radius (non-RTZ)",-80, 80, aTab2, aRow); dlgText("creates a ± auto step-out deadzone", aTab4, aRow); aRow := aRow + 1; dlglist(19,"Every step is","Random|Return to Zero", 99, aTab2, aRow); aRow := aRow + 1; dlgstring(20,"Initial Step Sizes (<9)",23,". 0123456789", aTab2, aRow); dlgText("deg", aTab2 + 26, aRow); aRow := aRow + 1; dlginteger(21,"Stimulation #1 dur",0,2000, aTab2, aRow); dlgText("ms", aTab4, aRow); aRow := aRow + 1; dlgInteger(22,"Gap Dur",0,2000, aTab2, aRow); dlgText("ms", aTab4, aRow); aRow := aRow + 1; dlginteger(23,"Velocity Onset",0,2000, aTab2, aRow); dlgText("d/s (Rel Target or Rel Eye)", aTab4, aRow); aRow := aRow + 1; dlginteger(24,"Velocity Offset",0,2000, aTab2, aRow); dlgText("d/s (Rel Eye only)", aTab4, aRow); aRow := aRow + 1; dlginteger(25,"Reaction Time Window",0,1000, aTab2, aRow); dlgText("to", aTab4, aRow); dlginteger(26,"",0,1000, aTab8, aRow); dlgText("ms", aTab9, aRow); aRow := aRow + 1; dlgInteger(27,"Blanking Dur",0,2000, aTab2, aRow); dlgText("ms (disables adaptation)", aTab4, aRow); aRow := aRow + 1; 'SAVE: waiting for need to code proportional to eye stepping dlglist(28,"Type of Adapt Step","Relative to Target|Relative to Eye", 99, aTab2, aRow); aRow := aRow + 1; dlgtext("Adapt Step Everytime", 0, aRow); dlgcheck(29,"", aTab2-1, aRow); aRow := aRow + 1; dlginteger(30,"Stimulation #2 dur",0,2000, aTab2, aRow); dlgText("ms", aTab4, aRow); aRow := aRow + 1; dlginteger(31,"Follow Eye Position",0,2000, aTab2, aRow); dlgText("ms", aTab4, aRow); aRow := aRow + 2; dlginteger(32,"Horizontal Offset",-40,40, aTab2, aRow); dlgText("deg", aTab4, aRow); aRow := aRow + 1; dlginteger(33,"Vertical Offset",-40,40, aTab2, aRow); dlgText("deg", aTab4, aRow); aRow := aRow + 1; dlgText("", aTab2, aRow); aIntA%[0] := pAdaptBlankDur; aIntA%[1] := pAdaptType; 'careful, aIntA%[1] is tested below aIntA%[2] := pAdaptStepEverytime%; aIntA%[3] := pAdaptStim2; ok% := dlgShow(aRow1$[], pAdaptStimDir[0], aRow2$[], pAdaptStimDir[1], aRow3$[], pAdaptStimDir[2], aRow4$[], pAdaptStimDir[3], pAdaptStimRatio, item7%, item3%, item2$, pAdaptStim1, item6%, item1, item2, aWindow%[], aIntA%[], item3, aOffset[]); if ok% > 0 then if pDisplay = 2 then 'remove any offsets when in the LED booth 'if (pAdaptHorzOffset% <> 0) or (pAdaptVertOffset% <> 0) then if (aOffset[0] <> 0) or (aOffset[1] <> 0) then aOffset[0] := 0; aOffset[1] := 0; message("The offsets have been reset to zero because they are not allowed in LED mode."); endif endif 'TEST that all vectors are positive directions. If not bail out. aProblem := kFalse; aTest := val(aRow1$[0]); if aTest > 90 and aTest < 271 then aProblem := kTrue; endif aTest := val(aRow2$[0]); if aTest > 90 and aTest < 271 then aProblem := kTrue; endif aTest := val(aRow3$[0]); if aTest > 90 and aTest < 271 then aProblem := kTrue; endif aTest := val(aRow4$[0]); if aTest > 90 and aTest < 271 then aProblem := kTrue; endif if aProblem = kTrue then dlgcreate("Bad Parameter",kX); dlgtext("All vectors must be 90° or less.", 0, 1); dlgtext("Or they must be greater than 270°.", 0, 2); dlgtext(" ", 0, 3); DlgButton(0,""); 'remove the CANCEL button ok% := dlgShow(); endif ' 'TEST that only percent adapt steps have been selected when proportional to eye adapt stepping has been selected ' if aIntA%[1] = 2 then 'pAdaptType ' if abs(val(aRow1$[1])) >= 1 then bProblem := kTrue; endif ' if abs(val(aRow1$[2])) >= 1 then bProblem := kTrue; endif ' if abs(val(aRow2$[1])) >= 1 then bProblem := kTrue; endif ' if abs(val(aRow2$[2])) >= 1 then bProblem := kTrue; endif ' if abs(val(aRow3$[1])) >= 1 then bProblem := kTrue; endif ' if abs(val(aRow3$[2])) >= 1 then bProblem := kTrue; endif ' if abs(val(aRow4$[1])) >= 1 then bProblem := kTrue; endif ' if abs(val(aRow4$[2])) >= 1 then bProblem := kTrue; endif ' endif ' if bProblem = kTrue then ' dlgcreate("Bad Parameter",kX); ' dlgtext("All adapt steps must be expressed in percent", 0, 1); ' dlgtext("when using proportional adapt stepping.", 0, 2); ' dlgtext(" ", 0, 3); ' DlgButton(0,""); 'remove the CANCEL button ' ok% := dlgShow(); ' endif atest := abs(val(aRow1$[1])); atest := abs(val(aRow1$[2])); atest := abs(val(aRow2$[1])); atest := abs(val(aRow2$[2])); atest := abs(val(aRow3$[1])); atest := abs(val(aRow3$[2])); atest := abs(val(aRow4$[1])); atest := abs(val(aRow4$[2])); var anyGreaterThanZero, anyLessThanOne; anyGreaterThanZero := ((abs(val(aRow1$[1]))>=1) or (abs(val(aRow1$[2]))>=1) or (abs(val(aRow2$[1]))>=1) or (abs(val(aRow2$[2]))>=1) or (abs(val(aRow3$[1]))>=1) or (abs(val(aRow3$[2]))>=1) or (abs(val(aRow4$[1]))>=1) or (abs(val(aRow4$[2]))>=1)); anyLessThanOne := (((abs(val(aRow1$[1]))<>0) and (abs(val(aRow1$[1]))<1)) or ((abs(val(aRow1$[2]))<>0) and (abs(val(aRow1$[2]))<1)) or ((abs(val(aRow2$[1]))<>0) and (abs(val(aRow2$[1]))<1)) or ((abs(val(aRow2$[2]))<>0) and (abs(val(aRow2$[2]))<1)) or ((abs(val(aRow3$[1]))<>0) and (abs(val(aRow3$[1]))<1)) or ((abs(val(aRow3$[2]))<>0) and (abs(val(aRow3$[2]))<1)) or ((abs(val(aRow4$[1]))<>0) and (abs(val(aRow4$[1]))<1)) or ((abs(val(aRow4$[2]))<>0) and (abs(val(aRow4$[2]))<1))); bProblem := (anyGreaterThanZero=1) and (anyLessThanOne=1); if bProblem = kTrue then dlgcreate("Bad Parameter",kX); dlgtext("Cannot mix fixed and proportional adapt step sizes", 0, 1); dlgtext(" ", 0, 2); DlgButton(0,""); 'remove the CANCEL button ok% := dlgShow(); endif 'implemented this way to accomodate multiple error messages if (aProblem = kFalse) and (bProblem = kFalse) then SampleSeqVar(sPARAMCHANGED, 0); 'signal parameters will be changing 'un-stuff some like variables into an array to keep under the limit of 20 dlgShow variables pAdaptBlankDur := aIntA%[0]; pAdaptType := aIntA%[1]; pAdaptStepEverytime% := aIntA%[2]; pAdaptStim2 := aIntA%[3]; pAdaptWindowBeg% := aWindow%[0]; pAdaptWindowEnd% := aWindow%[1]; pAdaptHorzOffset% := aOffset[0]; pAdaptVertOffset% := aOffset[1]; gAdaptTimeForZero := kFalse; 'Set all the parameters to invalid ArrConst(pAdaptVectors[], kNAN); ArrConst(pAdaptAdapt[], kNAN); 'Fill the parameters with a numeric value if 'one was provided, otherwise, leave it set to kNAN. if aRow1$[0] <> "" then pAdaptVectors[0] := val(aRow1$[0]); endif; if aRow1$[1] <> "" then pAdaptAdapt[0] := val(aRow1$[1]); endif; if aRow1$[2] <> "" then pAdaptAdapt[4] := val(aRow1$[2]); endif; if aRow2$[0] <> "" then pAdaptVectors[1] := val(aRow2$[0]); endif; if aRow2$[1] <> "" then pAdaptAdapt[1] := val(aRow2$[1]); endif; if aRow2$[2] <> "" then pAdaptAdapt[5] := val(aRow2$[2]); endif; if aRow3$[0] <> "" then pAdaptVectors[2] := val(aRow3$[0]); endif; if aRow3$[1] <> "" then pAdaptAdapt[2] := val(aRow3$[1]); endif; if aRow3$[2] <> "" then pAdaptAdapt[6] := val(aRow3$[2]); endif; if aRow4$[0] <> "" then pAdaptVectors[3] := val(aRow4$[0]); endif; if aRow4$[1] <> "" then pAdaptAdapt[3] := val(aRow4$[1]); endif; if aRow4$[2] <> "" then pAdaptAdapt[7] := val(aRow4$[2]); endif; 'force all active vectors to have a valid adapt size, if none specified, 'substitute zero instead of NAN for i% := 0 to 3 do if pAdaptVectors[i%] <> kNAN then if pAdaptAdapt[i%] = kNAN then pAdaptAdapt[i%] := 0; endif if pAdaptAdapt[i% + 4] = kNAN then pAdaptAdapt[i% + 4] := 0; endif endif next 'setup opposite vectors aNumVectors% := 0; for i% := 0 to 3 do if pAdaptVectors[i%] <> kNAN then aNumVectors% := aNumVectors% + 2; 'specified vector and opposite vector aOpposite := i% + 4; pAdaptVectors[aOpposite] := pAdaptVectors[i%] + 180; if pAdaptVectors[aOpposite] >= 360 then pAdaptVectors[aOpposite] := pAdaptVectors[aOpposite] - 360 endif endif next aHowMany := ReadStr(item2$, pAdaptInitialSteps); 'read in target steps 'must set unused to kNAN here since some items come through as zero even though the array is preset to kNAN for i% := aHowMany to 7 do pAdaptInitialSteps[i%] := kNAN; 'unused steps must be filled with NAN next pAdaptStartRadius% := item7%; pAdaptRTZ := item3%; 'type of adapt pAdaptOnSetVel := item1; 'velocity threshold pAdaptOffSetVel := item2; 'velocity threshold pAdaptFollowDur := item3; 'follow eye duration pAdaptGapDur := item6%; 'gap duration b := (aBitsIn/20) * (pAdaptOnSetVel/100); c := (aBitsIn/20) * ((pAdaptOnSetVel/2)/100); 'pre-set all locations to NAN ArrConst(aTable%[], kNAN); 'The timese each dir used has been usurped to pass parameters to the sequencer 'A+10-19 TIMES EACH DIRECTION USED 'A+20-29 INITIAL STEPS on vector 0 in X DAC units 'A+30-39 INITIAL STEPS on vector 1 in X DAC units 'A+40-49 INITIAL STEPS on vector 2 in X DAC units 'A+50-59 INITIAL STEPS on vector 3 in X DAC units 'A+60-69 INITIAL STEPS on vector 4 in X DAC units 'A+70-79 INITIAL STEPS on vector 5 in X DAC units 'A+80-89 INITIAL STEPS on vector 6 in X DAC units 'A+90-99 INITIAL STEPS on vector 7 in X DAC units 'A+100-109 INITIAL STEPS on vector 0 in Y DAC units 'A+110-119 INITIAL STEPS on vector 1 in Y DAC units 'A+120-129 INITIAL STEPS on vector 2 in Y DAC units 'A+130-139 INITIAL STEPS on vector 3 in Y DAC units 'A+140-149 INITIAL STEPS on vector 4 in Y DAC units 'A+150-159 INITIAL STEPS on vector 5 in Y DAC units 'A+160-169 INITIAL STEPS on vector 6 in Y DAC units 'A+170-179 INITIAL STEPS on vector 7 in Y DAC units 'A+180-189 ADAPT STEPS on vector 0 in X DAC units 'A+190-199 ADAPT STEPS on vector 1 in X DAC units 'A+200-209 ADAPT STEPS on vector 2 in X DAC units 'A+210-219 ADAPT STEPS on vector 3 in X DAC units 'A+220-229 ADAPT STEPS on vector 4 in X DAC units 'A+230-239 ADAPT STEPS on vector 5 in X DAC units 'A+240-249 ADAPT STEPS on vector 6 in X DAC units 'A+250-259 ADAPT STEPS on vector 7 in X DAC units 'A+260-269 ADAPT STEPS on vector 0 in Y DAC units 'A+270-279 ADAPT STEPS on vector 1 in Y DAC units 'A+280-289 ADAPT STEPS on vector 2 in Y DAC units 'A+290-299 ADAPT STEPS on vector 3 in Y DAC units 'A+300-309 ADAPT STEPS on vector 4 in Y DAC units 'A+310-319 ADAPT STEPS on vector 5 in Y DAC units 'A+320-329 ADAPT STEPS on vector 6 in Y DAC units 'A+330-339 ADAPT STEPS on vector 7 in Y DAC units 'A+340-349 LED board addresses 'A+350-359 Axis Slopes, compute the slope from a line going through 0,0 and 1 deg on the desired axis '(y2-y1)/(x2-x1) = (y2-0)/(x2-0) = y2/x2 'A+360-369 PERPENDICULAR Axis Slopes 'perpSlope = -(1/slope) 'Two special cases: 'axis = 0 or 180 degrees; slope = 0; perpSlope= NAN; use eye X and target Y 'axis = 90 or 270 degrees; slope = NAN; perpSlope = 0; use eye Y and target X 'A+370-379 EXCURSION LIMIT in X DAC units 'A+380-389 EXCURSION LIMIT in Y DAC units 'A+390-399 X value for 1 deg step (for LED computation) 'A+400-409 Y value for 1 deg step (for LED computation) 'A+410-419 DEADZONE LIMIT in X DAC units 'A+420-429 DEADZONE LIMIT in Y DAC units ' 'A+450-459 step stimulation durations 'A+460-469 velocity stimulation durations '0-9 GENERAL TABLE VARIABLES m% := 0; docase case (pAdaptType = 0) and (anyGreaterThanZero = 1) then aTable%[m%+0] := 0; '0=FixTarg, 1=ProTarg, 2=FixEye, 3=ProEye case (pAdaptType = 0) and (anyLessThanOne = 1) then aTable%[m%+0] := 1; '0=FixTarg, 1=ProTarg, 2=FixEye, 3=ProEye case (pAdaptType = 1) and (anyGreaterThanZero = 1) then aTable%[m%+0] := 2; '0=FixTarg, 1=ProTarg, 2=FixEye, 3=ProEye case (pAdaptType = 1) and (anyLessThanOne = 1) then aTable%[m%+0] := 3; '0=FixTarg, 1=ProTarg, 2=FixEye, 3=ProEye endcase if pAdaptRTZ = kTrue then aTable%[m%+1] := 1; 'yes RTZ, move to zero first else aTable%[m%+1] := -1; 'no RTZ, invalid value endif aTable%[m%+2] := pAdaptGapDur; aTable%[m%+3] := (aBitsIn/20) * (pAdaptOnSetVel/100); aTable%[m%+4] := (aBitsIn/20) * (pAdaptOffSetVel/100); aTable%[m%+5] := pAdaptBlankDur; aTable%[m%+6] := pAdaptFollowDur; aTable%[m%+7] := pAdaptWindowBeg%; aTable%[m%+8] := pAdaptWindowEnd%; aTable%[m%+10] := Degrees2dac%(pAdaptHorzOffset%); aTable%[m%+11] := Degrees2dac%(pAdaptVertOffset%); aTable%[m%+12] := pAdaptStimRatio / 100 * 128; 'convert ratio to power of two to make it easier in sequencer if pAdaptRTZ = kTrue then aTable%[m%+13] := 0; 'starting point in X DAC terms aTable%[m%+14] := 0; 'starting point in Y DAC terms else 'user-specified radius on the first theta aTable%[m%+13] := Radial2dacH%(pAdaptStartRadius%, pAdaptVectors[0], 0); 'starting point in X DAC terms aTable%[m%+14] := Radial2dacV%(pAdaptStartRadius%, pAdaptVectors[0], 0); 'starting point in Y DAC terms endif aTable%[m%+15] := pAdaptStepEverytime%; '20-90, load up the INITIAL STEP X-VALUES chart '180-260, load up the ADAPT STEP X-VALUES chart m% := 20; n% := 180; 'aSmallerStepFound% := kFalse; 'aEqualStepFound% := kFalse; for a% := 0 to 7 do for b% := 0 to 7 do if (pAdaptVectors[a%] = kNAN) or (pAdaptInitialSteps[b%] = kNAN) then 'no values entered aTable%[m%+b%] := kNAN; aTable%[n%+b%] := kNAN; else aTable%[m%+b%] := Radial2dacH%(pAdaptInitialSteps[b%], pAdaptVectors[a%], 0); 'initial X in DAC terms if pAdaptInitialSteps[b%] < getLimit%(pAdaptVectors[a%]) then aSmallerStepFound% := kTrue; endif if pAdaptInitialSteps[b%] = getLimit%(pAdaptVectors[a%]) then aEqualStepFound% := kTrue; endif if abs(pAdaptAdapt[a%]) >= 1 then 'fixed step in degrees aTable%[n%+b%] := Radial2dacH%(pAdaptAdapt[a%], pAdaptVectors[a%], 0); 'adapt X in DAC terms else if pAdaptType = 0 then '0=Relative to Targ, 1=Relative to Eye aReal := pAdaptAdapt[a%] * pAdaptInitialSteps[b%]; 'compute adapt step size from % backstep aTable%[n%+b%] := Radial2dacH%(aReal, pAdaptVectors[a%], 0); 'adapt X in DAC terms else 'if pAdaptType = 1 then '0=Relative to Targ, 1=Relative to Eye aTable%[n%+b%] := Proportional2ThetaH(pAdaptAdapt[a%], pAdaptVectors[a%]) * 100; 'adapt X in percent * 100 endif endif endif next m% := m% + 10; n% := n% + 10; next docase case (aSmallerStepFound% = kFalse) and (aEqualStepFound% = kTrue) then message("Initial steps = limit settings. Computational roundoffs may require increasing limits by 1 deg.") case aSmallerStepFound% = kFalse then message("All the initial steps exceed the limit settings.") endcase '100-170, load up the INITIAL STEP Y-VALUES chart '260-340, load up the ADAPT STEP Y-VALUES chart m% := 100; n% := 260; for a% := 0 to 7 do for b% := 0 to 7 do if (pAdaptVectors[a%] = kNAN) or (pAdaptInitialSteps[b%] = kNAN) then 'no values entered aTable%[m%+b%] := kNAN; aTable%[n%+b%] := kNAN; else aTable%[m%+b%] := Radial2dacV%(pAdaptInitialSteps[b%], pAdaptVectors[a%], 0); 'initial Y in DAC terms if abs(pAdaptAdapt[a%]) >= 1 then 'fixed step in degrees aTable%[n%+b%] := Radial2dacV%(pAdaptAdapt[a%], pAdaptVectors[a%], 0); 'adapt Y in DAC terms else if pAdaptType = 0 then '0=Relative to Targ, 1=Relative to Eye aReal := pAdaptAdapt[a%] * pAdaptInitialSteps[b%]; 'compute adapt step size from % backstep aTable%[n%+b%] := Radial2dacV%(aReal, pAdaptVectors[a%], 0); 'adapt Y in DAC terms else 'if pAdaptType = 1 then '0=Relative to Targ, 1=Relative to Eye aTable%[n%+b%] := Proportional2ThetaV(pAdaptAdapt[a%], pAdaptVectors[a%]) * 100; 'adapt Y in percent * 100 endif endif endif next m% := m% + 10; n% := n% + 10; next m% := 10; q% := 340; r% := 350; 'axis slope s% := 360; 'perpendicular slope t% := 370; u% := 380; v% := 390; w% := 400; x% := 410; 'x-deadzone limit y% := 420; 'y-deadzone limit 'active directions for i% := 0 to 7 do if pAdaptVectors[i%] <> kNAN then EncodeLED80(1, pAdaptVectors[i%], kRedColorBit, boardAddress, LEDaddress); 'determine which LED board is used aTable%[q%+i%] := boardAddress; ' This has very little use since it has the address ' for the axes and not the axis the target is on. Because ' the sequencer moves the target in an XY fashion it ' doesn't know which axis the target is on. docase case (pAdaptVectors[i%] = 0) or (pAdaptVectors[i%] = 180) then 'point is on the horizontal axis aTable%[r%+i%] := 0; 'flat = slope aTable%[s%+i%] := kNAN; 'infinity = perpendicular slope case (pAdaptVectors[i%] = 90) or (pAdaptVectors[i%] = 270) then 'point is on the vertical axis aTable%[r%+i%] := kNAN; 'infinity = slope aTable%[s%+i%] := 0; 'flat = perpendicular slope else aReal := Radial2dacV%(1, pAdaptVectors[i%], 0); 'compute slope for axis, use radius of 1 degree bReal := Radial2dacH%(1, pAdaptVectors[i%], 0); 'compute slope for axis, use radius of 1 degree cReal := aReal/bReal; aSlope := aReal/bReal; 'multiply slopes by 100 to preserve 0.01 accuracy while using INTEGER math in the sequencer 'because of equation, the 100 factor cancels itself out. Very large D/A could roll over. aReal := kSlopeMultiplier100 * aSlope; bReal := kSlopeMultiplier100 * (-(1.0 / aSlope)); 'perpendicular slope is -(1/slope) docase case round(aReal) = 0 then aTable%[r%+i%] := 0; 'flat = slope aTable%[s%+i%] := kNAN; 'infinity = perpendicular slope case round(bReal) = 0 then aTable%[r%+i%] := kNAN; 'infinity = slope aTable%[s%+i%] := 0; 'flat = perpendicular slope else aTable%[r%+i%] := round(aReal); aTable%[s%+i%] := round(bReal); 'perpendicular slope is -(1/slope) endcase endcase '5/11/05 Will it be a problem that: ' the Y limit for 0 & 180 is 0 degrees ' the X limit for 90 & 270 is 0 degrees '7/3/06 Looks like it actually is a problem! aTheta := pAdaptVectors[i%]; docase case (aTheta = 0) or (aTheta = 180) then aTable%[t%+i%] := Radial2dacH%(GetLimit%(aTheta), aTheta+1, 0); 'problems when limit is zero aTable%[u%+i%] := Radial2dacV%(GetLimit%(aTheta), aTheta+1, 0); case (aTheta = 90) or (aTheta = 270) then aTable%[t%+i%] := Radial2dacH%(GetLimit%(aTheta), aTheta+1, 0); 'problems when limit is zero aTable%[u%+i%] := Radial2dacV%(GetLimit%(aTheta), aTheta+1, 0); else aTable%[t%+i%] := Radial2dacH%(GetLimit%(aTheta), aTheta, 0); 'use natural radius and theta aTable%[u%+i%] := Radial2dacV%(GetLimit%(aTheta), aTheta, 0); endcase aTable%[v%+i%] := Radial2dacH%(1, pAdaptVectors[i%], 0); 'compute the DAC value for a 1 deg step aTable%[w%+i%] := Radial2dacV%(1, pAdaptVectors[i%], 0); 'compute the DAC value for a 1 deg step aTable%[x%+i%] := abs(Radial2dacH%(pAdaptStartRadius%, pAdaptVectors[i%], 0));'absolute val DEADZONE in X DAC terms aTable%[y%+i%] := abs(Radial2dacV%(pAdaptStartRadius%, pAdaptVectors[i%], 0));'absolute val DEADZONE in Y DAC terms endif next m% := 450; for b% := 0 to 3 do aTable%[m%+b%] := 0; aTable%[m%+b%+4] := 0; if pAdaptStimDir[b%] = 1 then 'pos aTable%[m%+b%] := pAdaptStim1*100; endif if pAdaptStimDir[b%] = 2 then 'neg aTable%[m%+b%+4] := pAdaptStim1*100; endif if pAdaptStimDir[b%] = 3 then 'pos + neg aTable%[m%+b%] := pAdaptStim1*100; aTable%[m%+b%+4] := pAdaptStim1*100; endif next m% := 460; for b% := 0 to 3 do aTable%[m%+b%] := 0; aTable%[m%+b%+4] := 0; if pAdaptStimDir[b%] = 1 then 'pos aTable%[m%+b%] := pAdaptStim2*100; endif if pAdaptStimDir[b%] = 2 then 'neg aTable%[m%+b%+4] := pAdaptStim2*100; endif if pAdaptStimDir[b%] = 3 then 'pos + neg aTable%[m%+b%] := pAdaptStim2*100; aTable%[m%+b%+4] := pAdaptStim2*100; endif next Table(aTable%[]); 'kBOBmode ' 'display the table of data being send to the sequence ' if kBOBmode = kTrue then ' view(gDebugWindow%); ' j% := 0; ' while j% < 550 do ' Print("%5d,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f\n", j%, aTable%[j%+0], aTable%[j%+1], aTable%[j%+2], aTable%[j%+3], aTable%[j%+4], aTable%[j%+5], aTable%[j%+6], aTable%[j%+7], aTable%[j%+8], aTable%[j%+9]); ' j% := j% + 10; ' wend ' endif StartNewSession(kAdapt); SetSpotScales(0, 0, pAdaptHorzOffset%, pAdaptVertOffset%); 'use limits SetScrollingScales(0, 0, pAdaptHorzOffset%, pAdaptVertOffset%); ArrConst(gTable%, 0); 'clear global table data ArrAdd(gTable%, aTable%); 'copy the table to be used with NEWDIG SampleSeqTable(gTable%, kTableOffset1000%); 'load all this data into the tabl SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed SetToolbar(kAdapt); SetVelocityChannels(); EditSelectAll(); EditClear(); ReportFlagSet(); endif 'if (aProblem = kFalse) and (bProblem = kFalse) endif 'if ok% return kTrue; 'Stay in toolbar end; 'DialogAdapt 'aNumPtsShown% '---------------------------------------------------- ' DialogThreeSpot '5/3/07 '---------------------------------------------------- func DialogThreeSpot%() const kSlopeMultiplier100 := 100.0; var a%, b%, i%, j%, k%, m%, n%, p%, q%, r%, s%, t%, u%, v%, w%, x%, y%, aOpposite, aProblem, aBitsIn, ok%, aRow, aItem%, aTab1, aTab2, aTab4, aTab5, aTab6, aTab7, aTab8, aTab9, aTest, aTemp, theMode%, aNumVectors%, aHowMany, aRadius%, aNumRadii%, aTheta%, aTable%[kTableSize%], aRadiusArray[kMaxVectors%], aThetaArray[kMaxVectors%], boardAddress, LEDaddress, aTheta, b, c, aSlope, aPerpSlope, aReal, bReal; aBitsIn := pow(2,16); '65536 aTab1 := 5; aTab2 := aTab1 + 25; aTab4 := aTab2 + kUnitLabel; aTab5 := aTab1 + 16; aTab6 := aTab5 + 16; aTab7 := aTab5 + 30; aTab8 := aTab2 + 19; aTab9 := aTab2 + 32; 'Setup the dialog box and its controls dlgcreate("ThreeSpot",kX); aRow := 1; dlgtext(" Pos Vector Adapt Pos Dir Adapt Neg Dir", 0, aRow); aItem% := 1; aRow := aRow + 1; dlgreal(aItem%,"",0,360, aTab1, aRow); aItem% := aItem% + 1; dlgreal(aItem%,"",-0.99,0.99, aTab5, aRow); aItem% := aItem% + 1; dlgreal(aItem%,"",-0.99,0.99, aTab6, aRow); aItem% := aItem% + 1; aRow := aRow + 1; 'spaces used to position text dlgtext(" 0 - 90° or ±0.00 thru 0.99 = percent step", 0, aRow); aRow := aRow + 1; dlgtext(" 271 - 360° Neg moves towards center", 0, aRow); aRow := aRow + 2; dlgreal(aItem%,"Spot Separation",0,80, aTab2, aRow); dlgText("deg", aTab4, aRow); aItem% := aItem% + 1; aRow := aRow + 1; dlginteger(aItem%,"Horizontal Offset",-40,40, aTab2, aRow); dlgText("deg", aTab4, aRow); aItem% := aItem% + 1; aRow := aRow + 1; dlginteger(aItem%,"Vertical Offset",-40,40, aTab2, aRow); dlgText("deg", aTab4, aRow); aItem% := aItem% + 1; aRow := aRow + 1; dlginteger(aItem%,"Velocity Onset",0,2000, aTab2, aRow); dlgText("d/s", aTab4, aRow); aItem% := aItem% + 1; aRow := aRow + 1; dlginteger(aItem%,"Velocity Offset",0,2000, aTab2, aRow); dlgText("d/s", aTab4, aRow); aItem% := aItem% + 1; aRow := aRow + 1; dlginteger(aItem%,"Adapt Saccades Between",0,100, aTab2, aRow); dlgText("and", aTab4, aRow); aItem% := aItem% + 1; dlginteger(aItem%,"",0,100, aTab8, aRow); dlgText("deg", aTab9, aRow); aItem% := aItem% + 1; aRow := aRow + 1; dlgText("", aTab2, aRow); 'ok% := dlgShow(aRow1$[], pThreeSpotSeparation, aOffset[], pThreeSpotOnSetVel, pThreeSpotOffSetVel, pThreeTimeOn%); 'ok% := dlgShow(pThreeSpotVectors[0], pThreeSpotAdapt[0], pThreeSpotAdapt[4], pThreeSpotSeparation, aOffset[], pThreeSpotOnSetVel, pThreeSpotOffSetVel, pThreeTimeOn%); 'ok% := dlgShow(pThreeSpotVectors[0], pThreeSpotAdapt[0], pThreeSpotAdapt[4], pThreeSpotSeparation, aOffset[], pThreeSpotOnSetVel, pThreeSpotOffSetVel); ok% := dlgShow(pThreeSpotVectors[0], pThreeSpotAdapt[0], pThreeSpotAdapt[4], pThreeSpotSeparation, pThreeSpotHorzOffset%, pThreeSpotVertOffset%, pThreeSpotOnSetVel, pThreeSpotOffSetVel, pThreeSpotSacLower, pThreeSpotSacUpper); if ok% > 0 then 'TEST that all vectors are positive directions. If not bail out. if pThreeSpotVectors[0] > 90 and pThreeSpotVectors[0] <= 270 then aProblem := kTrue; endif if aProblem = kTrue then dlgcreate("Bad Parameter",kX); dlgtext("All vectors must be 90° or less.", 0, 1); dlgtext("Or they must be greater than 270°.", 0, 2); dlgtext(" ", 0, 3); DlgButton(0,""); 'remove the CANCEL button ok% := dlgShow(); endif 'exchange values so largest value is in the "UPPER" variable if pThreeSpotSacLower > pThreeSpotSacUpper then aTemp := pThreeSpotSacLower; pThreeSpotSacLower := pThreeSpotSacUpper; pThreeSpotSacUpper := aTemp; endif 'implemented this way to accomodate multiple error messages if (aProblem = kFalse) then 'and (bProblem = kFalse) then SampleSeqVar(sPARAMCHANGED, 0); 'signal parameters will be changing 'pre-set all locations to NAN ArrConst(aTable%[], kNAN); 'The timese each dir used has been usurped to pass parameters to the sequencer 'A+10-19 TIMES EACH DIRECTION USED 'A+20-29 INITIAL STEPS on vector 0 in X DAC units 'A+30-39 INITIAL STEPS on vector 1 in X DAC units 'A+40-49 INITIAL STEPS on vector 2 in X DAC units 'A+50-59 INITIAL STEPS on vector 3 in X DAC units 'A+60-69 INITIAL STEPS on vector 4 in X DAC units 'A+70-79 INITIAL STEPS on vector 5 in X DAC units 'A+80-89 INITIAL STEPS on vector 6 in X DAC units 'A+90-99 INITIAL STEPS on vector 7 in X DAC units 'A+100-109 INITIAL STEPS on vector 0 in Y DAC units 'A+110-119 INITIAL STEPS on vector 1 in Y DAC units 'A+120-129 INITIAL STEPS on vector 2 in Y DAC units 'A+130-139 INITIAL STEPS on vector 3 in Y DAC units 'A+140-149 INITIAL STEPS on vector 4 in Y DAC units 'A+150-159 INITIAL STEPS on vector 5 in Y DAC units 'A+160-169 INITIAL STEPS on vector 6 in Y DAC units 'A+170-179 INITIAL STEPS on vector 7 in Y DAC units 'A+180-189 ADAPT STEPS on vector 0 in X DAC units 'A+190-199 ADAPT STEPS on vector 1 in X DAC units 'A+200-209 ADAPT STEPS on vector 2 in X DAC units 'A+210-219 ADAPT STEPS on vector 3 in X DAC units 'A+220-229 ADAPT STEPS on vector 4 in X DAC units 'A+230-239 ADAPT STEPS on vector 5 in X DAC units 'A+240-249 ADAPT STEPS on vector 6 in X DAC units 'A+250-259 ADAPT STEPS on vector 7 in X DAC units 'A+260-269 ADAPT STEPS on vector 0 in Y DAC units 'A+270-279 ADAPT STEPS on vector 1 in Y DAC units 'A+280-289 ADAPT STEPS on vector 2 in Y DAC units 'A+290-299 ADAPT STEPS on vector 3 in Y DAC units 'A+300-309 ADAPT STEPS on vector 4 in Y DAC units 'A+310-319 ADAPT STEPS on vector 5 in Y DAC units 'A+320-329 ADAPT STEPS on vector 6 in Y DAC units 'A+330-339 ADAPT STEPS on vector 7 in Y DAC units 'A+340-349 LED board addresses 'A+350-359 Axis Slopes, compute the slope from a line going through 0,0 and 1 deg on the desired axis '(y2-y1)/(x2-x1) = (y2-0)/(x2-0) = y2/x2 'A+360-369 PERPENDICULAR Axis Slopes 'perpSlope = -(1/slope) 'Two special cases: 'axis = 0 or 180 degrees; slope = 0; perpSlope= NAN; use eye X and target Y 'axis = 90 or 270 degrees; slope = NAN; perpSlope = 0; use eye Y and target X 'A+370-379 EXCURSION LIMIT in X DAC units 'A+380-389 EXCURSION LIMIT in Y DAC units 'A+390-399 X value for 1 deg step (for LED computation) 'A+400-409 Y value for 1 deg step (for LED computation) 'A+410-419 DEADZONE LIMIT in X DAC units 'A+420-429 DEADZONE LIMIT in Y DAC units ' 'A+450-459 step stimulation durations 'A+460-469 velocity stimulation durations '0-9 GENERAL TABLE VARIABLES m% := 0; aTable%[m%+3] := (aBitsIn/20) * (pThreeSpotOnSetVel/100); aTable%[m%+4] := (aBitsIn/20) * (pThreeSpotOffSetVel/100); aTable%[m%+7] := pThreeSpotWindowBeg%; aTable%[m%+8] := pThreeSpotWindowEnd%; aTable%[m%+10] := Degrees2dac%(pThreeSpotHorzOffset%); aTable%[m%+11] := Degrees2dac%(pThreeSpotVertOffset%); aTable%[m%+15] := pThreeTimeOn%; aTable%[m%+16] := max( Radial2dacH%(pThreeSpotSacLower, pThreeSpotVectors[0], 0), Radial2dacV%(pThreeSpotSacLower, pThreeSpotVectors[0], 0) ); aTable%[m%+17] := max( Radial2dacH%(pThreeSpotSacUpper, pThreeSpotVectors[0], 0), Radial2dacV%(pThreeSpotSacUpper, pThreeSpotVectors[0], 0) ); if pThreeSpotVectors[0] < 45+22 or pThreeSpotVectors[0] > 315-22 then aTable%[m%+18] := 1; 'use delta X to determine saccade direction else aTable%[m%+18] := 0; 'use delta Y to determine saccade direction endif '20-90, load up the INITIAL STEP X-VALUES chart '100-170, load up the INITIAL STEP Y-VALUES chart '180-260, load up the ADAPT STEP X-VALUES chart '260-340, load up the ADAPT STEP Y-VALUES chart 'positive direction separation aTable%[20] := Radial2dacH%(pThreeSpotSeparation, pThreeSpotVectors[0], 0); 'initial X in DAC terms aTable%[100] := Radial2dacV%(pThreeSpotSeparation, pThreeSpotVectors[0], 0); 'initial Y in DAC terms 'positive direction adapt step aTable%[180] := Proportional2ThetaH(pThreeSpotAdapt[0], pThreeSpotVectors[0]) * 100; 'adapt X in percent * 100 aTable%[260] := Proportional2ThetaV(pThreeSpotAdapt[4], pThreeSpotVectors[0]) * 100; 'adapt Y in percent * 100 aReal := pThreeSpotVectors[0] + 180; if aReal >= 360 then aReal := aReal - 360 endif 'negative direction separation aTable%[60] := Radial2dacH%(pThreeSpotSeparation, aReal, 0); 'initial X in DAC terms aTable%[140] := Radial2dacV%(pThreeSpotSeparation, aReal, 0); 'initial Y in DAC terms 'negative direction adapt step aTable%[220] := Proportional2ThetaH(pThreeSpotAdapt[a%], aReal) * 100; 'adapt X in percent * 100 aTable%[300] := Proportional2ThetaV(pThreeSpotAdapt[a%], aReal) * 100; 'adapt Y in percent * 100 m% := 10; q% := 340; r% := 350; 'axis slope s% := 360; 'perpendicular slope t% := 370; u% := 380; v% := 390; w% := 400; x% := 410; 'x-deadzone limit y% := 420; 'y-deadzone limit 'active directions for i% := 0 to 7 do if pThreeSpotVectors[i%] <> kNAN then EncodeLED80(1, pThreeSpotVectors[i%], kRedColorBit, boardAddress, LEDaddress); 'determine which LED board is used aTable%[q%+i%] := boardAddress; ' This has very little use since it has the address ' for the axes and not the axis the target is on. Because ' the sequencer moves the target in an XY fashion it ' doesn't know which axis the target is on. docase case (pThreeSpotVectors[i%] = 0) or (pThreeSpotVectors[i%] = 180) then 'point is on the horizontal axis aTable%[r%+i%] := 0; 'flat = slope aTable%[s%+i%] := kNAN; 'infinity = perpendicular slope case (pThreeSpotVectors[i%] = 90) or (pThreeSpotVectors[i%] = 270) then 'point is on the vertical axis aTable%[r%+i%] := kNAN; 'infinity = slope aTable%[s%+i%] := 0; 'flat = perpendicular slope else aReal := Radial2dacV%(1, pThreeSpotVectors[i%], 0); 'compute slope for axis, use radius of 1 degree bReal := Radial2dacH%(1, pThreeSpotVectors[i%], 0); 'compute slope for axis, use radius of 1 degree aSlope := aReal/bReal; 'multiply slopes by 100 to preserve 0.01 accuracy while using INTEGER math in the sequencer 'because of equation, the 100 factor cancels itself out. Very large D/A could roll over. aReal := kSlopeMultiplier100 * aSlope; bReal := kSlopeMultiplier100 * (-(1.0 / aSlope)); 'perpendicular slope is -(1/slope) docase case round(aReal) = 0 then aTable%[r%+i%] := 0; 'flat = slope aTable%[s%+i%] := kNAN; 'infinity = perpendicular slope case round(bReal) = 0 then aTable%[r%+i%] := kNAN; 'infinity = slope aTable%[s%+i%] := 0; 'flat = perpendicular slope else aTable%[r%+i%] := round(aReal); aTable%[s%+i%] := round(bReal); 'perpendicular slope is -(1/slope) endcase endcase '5/11/05 Will it be a problem that: ' the Y limit for 0 & 180 is 0 degrees ' the X limit for 90 & 270 is 0 degrees '7/3/06 Looks like it actually is a problem! aTheta := pThreeSpotVectors[i%]; docase case (aTheta = 0) or (aTheta = 180) then aTable%[t%+i%] := Radial2dacH%(GetLimit%(aTheta), aTheta+1, 0); 'problems when limit is zero aTable%[u%+i%] := Radial2dacV%(GetLimit%(aTheta), aTheta+1, 0); case (aTheta = 90) or (aTheta = 270) then aTable%[t%+i%] := Radial2dacH%(GetLimit%(aTheta), aTheta+1, 0); 'problems when limit is zero aTable%[u%+i%] := Radial2dacV%(GetLimit%(aTheta), aTheta+1, 0); else aTable%[t%+i%] := Radial2dacH%(GetLimit%(aTheta), aTheta, 0); 'use natural radius and theta aTable%[u%+i%] := Radial2dacV%(GetLimit%(aTheta), aTheta, 0); endcase aTable%[v%+i%] := Radial2dacH%(1, pThreeSpotVectors[i%], 0); 'compute the DAC value for a 1 deg step aTable%[w%+i%] := Radial2dacV%(1, pThreeSpotVectors[i%], 0); 'compute the DAC value for a 1 deg step aTable%[x%+i%] := abs(Radial2dacH%(pThreeSpotStartRadius%, pThreeSpotVectors[i%], 0));'absolute val DEADZONE in X DAC terms aTable%[y%+i%] := abs(Radial2dacV%(pThreeSpotStartRadius%, pThreeSpotVectors[i%], 0));'absolute val DEADZONE in Y DAC terms endif next Table(aTable%[]); 'kBOBmode StartNewSession(kThreeSpot); SetSpotScales(0, 0, pThreeSpotHorzOffset%, pThreeSpotVertOffset%); 'use limits SetScrollingScales(0, 0, pThreeSpotHorzOffset%, pThreeSpotVertOffset%); ArrConst(gTable%, 0); 'clear global table data ArrAdd(gTable%, aTable%); 'copy the table to be used with NEWDIG SampleSeqTable(gTable%, kTableOffset1000%); 'load all this data into the tabl SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed SetToolbar(kThreeSpot); SetVelocityChannels(); EditSelectAll(); EditClear(); ReportFlagSet(); endif 'if (aProblem = kFalse) and (bProblem = kFalse) endif 'if ok% return kTrue; 'Stay in toolbar end; 'DialogThreeSpot '---------------------------------------------------- ' StartNewSession '5/25/06 '---------------------------------------------------- proc StartNewSession(aMode%) 'SampleSeqVar(sPARAMCHANGED, 0); 'signal that parameters may change, sequencer get ready to receive if gLastMode% <> aMode% then gLastMode% := aMode%; SaveLastDataFile(); ResetModeVariables(); CreateFileName(aMode%); New%(); Start%(); '(kFalse); else ResetModeVariables(); endif end 'StartNewSession '---------------------------------------------------- ' DialogRadial '1/10/03 '---------------------------------------------------- func DialogRadial%() var i%, j%, k, m%, n%, aBitsIn, ok%, int%, aTest, bTest, aRadius%, aTheta%, aNumVectors%, aNumRadii%, boardAddress, LEDaddress, aTable%[kTableSize%], aRadiusArray[kMaxVectors%], aThetaArray[kMaxVectors%], aZeroFound, item1$, item2$, aRotate := 0, aPosition, aTab1 := 32, aTab2, aTab3, aRow := 1, aWidth := 30, aH,aV, aMaxH := 0, aMaxV := 0; aBitsIn := pow(2,16); '65536 aTab2 := aTab1 + aWidth + 3; aTab3 := aTab1 + 13; dlgcreate("Radial Parameters",kX); dlgstring(1,"Target Directions (<9)",aWidth,". 0123456789", aTab1, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 1; dlgreal(2,"Selected Directions Rotated By",-359,+359,aTab1, aRow); dlgText("deg", aTab3, aRow); aRow := aRow + 1; dlgstring(3,"Target Locations (<9)",aWidth,". 0123456789", aTab1, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 2; dlginteger(4,"Horizontal Offset",-40,40, aTab1, aRow); dlgText("deg", aTab3, aRow); aRow := aRow + 1; dlginteger(5,"Vertical Offset",-40,40, aTab1, aRow); dlgText("deg", aTab3, aRow); aRow := aRow + 2; dlgInteger(6,"Blanking Dur (velocity triggered)",0,2000, aTab1, aRow); dlgText("ms", aTab3, aRow); aRow := aRow + 1; dlglist(7,"Type of stepping","Random|Return to zero (RTZ)", 99, aTab1, aRow); aRow := aRow + 1; dlgInteger(8,"Stim after RTZ, on-target trigger",0,100, aTab1, aRow); dlgText("%", aTab3, aRow); aRow := aRow + 1; dlgInteger(9,"Stim after RTZ, must remain OT for",0,500, aTab1, aRow); dlgText("ms", aTab3, aRow); aRow := aRow + 2; dlgText("Radial mode monitors dig input ch0 for the Mayhem monitor signal.", 0, aRow); aRow := aRow + 1; dlgText("", aTab1, aRow); Array2Str$(pRadialAngle[], 7, item1$); Array2Str$(pRadialRadius[], 7, item2$); ok% := dlgshow(item1$, aRotate, item2$, pRadialHorzOffset%, pRadialVertOffset%, pRadialBlankDur, pRadialReturnToZero, pRadialRTZstim, pRadialRTZstimOT); if ok% > 0 then if pDisplay = 2 then 'remove any offsets when in the LED booth if (pRadialHorzOffset% <> 0) or (pCalibrateVertOffset% <> 0) then pRadialHorzOffset% := 0; pRadialVertOffset% := 0; message("The offsets have been reset to zero because they are not allowed in LED mode."); endif endif aNumVectors%:= ReadStr(item1$, pRadialAngle); for i% := aNumVectors% to 7 do pRadialAngle[i%] := kNAN; 'unused angles must be filled with NAN next for i% := 0 to aNumVectors%-1 do pRadialAngle[i%] := pRadialAngle[i%] + aRotate; if pRadialAngle[i%] > 359 then pRadialAngle[i%] := pRadialAngle[i%] - 360; endif if pRadialAngle[i%] < 0 then pRadialAngle[i%] := pRadialAngle[i%] + 360; endif next aNumRadii% := ReadStr(item2$, pRadialRadius); for i% := aNumRadii% to 7 do pRadialRadius[i%] := kNAN; 'unused angles must be filled with NAN next 'for i% := 0 to kMaxVectors%-1 do ' aRadiusArray[i%] := kNAN; ' aThetaArray[i%] := kNAN; 'next arrconst(aRadiusArray[], kNAN); arrconst(aThetaArray[], kNAN); j% := 0; k := 0; for i% := 0 to kMaxVectors%-1 do if pRadialAngle[i%] <> kNAN then aThetaArray[j%] := pRadialAngle[i%]; j% := j% + 1; endif if pRadialRadius[i%] <> kNAN then aRadiusArray[k] := pRadialRadius[i%]; k := k + 1; endif next 'determine the maximum scale size needed for H and V 'gMaxH := 0; 'gMaxV := 0; m% := 0; 'whether using RTZ or not, compute the offsetted zero aTable%[m%+6] := Radial2dacH%(0, 0, pRadialHorzOffset%); 'x A/D location for 0 aTable%[m%+7] := Radial2dacV%(0, 0, pRadialVertOffset%); 'y A/D location for 0 aTable%[m%+4] := pRadialRTZstim / 100 * 128; 'convert ratio to power of two to make it easier in sequencer aTable%[m%+5] := pRadialBlankDur; aTable%[m%+2] := (aBitsIn/20) * (pRadialOnSetVel/100); aTable%[m%+3] := (aBitsIn/20) * (pRadialOffSetVel/100); aTable%[m%+8] := pRadialRTZstimOT * 100; if pRadialReturnToZero = kTrue then aZeroFound := kTrue; 'RTZ - allow NO zero locations aTable%[m%+1] := 1; '1001 = yes RTZ, move to zero first else aZeroFound := kFalse; 'RANDOM - allow ONE zero location aTable%[m%+1] := -1; '1001 = no RTZ, invalid value endif 'fill the position arrays n% := 0; for aRadius% := 0 to aNumRadii%-1 do for aTheta% := 0 to aNumVectors%-1 do aTest := (aRadiusArray[aRadius%] <> 0); 'radius = zero? bTest := (aZeroFound = kFalse); 'seen a zero before? if (aRadiusArray[aRadius%] <= GetLimit%(aThetaArray[aTheta%])) then 'stays within user-specified limits? if (aTest = kTrue) or (bTest = kTrue) then n% := n%+1; m% := n% * 10; if aRadiusArray[aRadius%] = 0 then aZeroFound := kTrue; endif aTable%[m%+0] := 0; 'location used? aTable%[m%+1] := Radial2dacH%(aRadiusArray[aRadius%], aThetaArray[aTheta%], pRadialHorzOffset%); 'x A/D location aTable%[m%+2] := Radial2dacV%(aRadiusArray[aRadius%], aThetaArray[aTheta%], pRadialVertOffset%); 'y A/D location EncodeLED80 (aRadiusArray[aRadius%], aThetaArray[aTheta%], kRedColorBit, boardAddress, LEDaddress); aTable%[m%+3] := (boardAddress + 192) * 256; 'shift left 8 bits aTable%[m%+4] := LEDaddress * 256; 'shift left 8 bits aTable%[0] := aTable%[0] + 1; 'total number of target locations aH := cos(aThetaArray[aTheta%]/kRadians)*aRadiusArray[aRadius%]; aV := sin(aThetaArray[aTheta%]/kRadians)*aRadiusArray[aRadius%]; aMaxH := max(abs(aH)+abs(pRadialHorzOffset%),aMaxH); aMaxV := max(abs(aV)+abs(pRadialVertOffset%),aMaxV); endif endif next next Table(aTable%[]); 'kBOBmode ' 'display the table of data being send to the sequence ' if kBOBmode = kTrue then ' view(gDebugWindow%); ' Print("\n"); ' j% := 0; ' while j% < 510 do ' Print("%5d,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f\n", j%, aTable%[j%+0], aTable%[j%+1], aTable%[j%+2], aTable%[j%+3], aTable%[j%+4], aTable%[j%+5], aTable%[j%+6], aTable%[j%+7], aTable%[j%+8], aTable%[j%+9]); ' j% := j% + 10; ' wend ' endif var aMax; aMax := max(aMaxH, aMaxV); StartNewSession(kRadial); SetSpotScales(aMax, aMax, pRadialHorzOffset%, pRadialVertOffset%); SetScrollingScales(aMax, aMax, pRadialHorzOffset%, pRadialVertOffset%); if aTable%[0] > 0 then ArrConst(gTable%, 0); 'clear global table data ArrAdd(gTable%, aTable%); 'copy the table to be used with NEWDIG SampleSeqTable(gTable%, kTableOffset1000%); 'load all this data into the tabl SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed SetToolbar(kRadial); SetVelocityChannels(); EditSelectAll(); EditClear(); ReportFlagSet(); else message("Try again. Your Radial and Limit settings produced NO TARGET LOCATIONS."); endif endif return kTrue; 'Stay in toolbar end; 'DialogRadial '---------------------------------------------------- ' NormalizeRadiusTheta 'Makes corrections so the radius so it is positive. 'It also corrects theta so it is positive and between '0 and 359°. '10/27/03 '---------------------------------------------------- proc NormalizeRadiusTheta (&aRadius, &aTheta) if aRadius < 0 then aTheta := aTheta + 180; 'correct theta when the radius is negative endif if aTheta > 359 then aTheta := aTheta - 360; 'correct any theta larger than 359° endif if aTheta < 0 then 'correct any thetas smaller than 0° aTheta := aTheta + 360; endif aRadius := abs(aRadius); 'radius is always positive end 'NormalizeRadiusTheta '---------------------------------------------------- ' Odd '1/13/03 '---------------------------------------------------- func Odd%(aNumber) var aReal, aInteger%; aReal := aNumber / 2; aInteger% := aNumber / 2; if aReal = aInteger% then return kFalse else return kTrue endif end '---------------------------------------------------- ' DialogXY ' 'Gets user's choices then computes all the variables 'required for it to run. '12/18/02 '---------------------------------------------------- func DialogXY%() var i%, j%, m%, n%, ok%, aH,aV, item1%, item2%, aPosition, bPosition, aTable%[kTableSize%], aRow := 1, aTemp%, aTab1 := 25, aTab2, aMaxH := 0, aMaxV := 0; aTab2 := aTab1 + kPopupLabel; item1% := pXYlocations - 2; 'convert for use as a popup menu index item2% := pXYseparation - 1; 'convert for use as a popup menu index dlgcreate("XY Parameters",kX); dlglist(1,"Target Locations","2|3|4|5|6|7|8|9|10", 99, aTab1, aRow); dlgText("per axis", aTab2, aRow); aRow := aRow + 1; dlglist(2,"Locations separated by","1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30", 99, aTab1, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 2; dlginteger(3,"Horizontal Offset",-40,40, aTab1, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 1; dlginteger(4,"Vertical Offset",-40,40, aTab1, aRow); dlgText("deg", aTab2, aRow); aRow := aRow + 2; dlgText("XY mode monitors dig input ch0 for the Mayhem monitor signal.", 0, aRow); aRow := aRow + 1; dlgText("", 0, aRow); ok% := dlgshow(item1%, item2%, pXYHorzOffset%, pXYVertOffset%); if ok% > 0 then if pDisplay = 2 then message("The XY stimulus does not work in LED mode."); 'save just to be sure endif pXYlocations := item1% + 2; 'convert back to actual number of locations pXYseparation := item2% + 1; 'convert back to actual degrees of separation 'determine the maximum scale size needed for H and V 'gMaxH := 0; 'gMaxV := 0; aTable%[0] := pXYlocations * pXYlocations; 'total number of target locations n% := 0; aPosition := -(pXYlocations / 2 - 0.5) * pXYseparation; 'fill the position arrays for i% := 0 to pXYlocations-1 do bPosition := -(pXYlocations / 2 - 0.5) * pXYseparation; for j% := 0 to pXYlocations-1 do n% := n%+1; m% := n%*10; aTable%[m%+0] := 0; 'location used? aTable%[m%+1] := Degrees2dac%(aPosition + pXYHorzOffset%); 'x A/D location aTable%[m%+2] := Degrees2dac%(bPosition + pXYVertOffset%); 'y A/D location aH := aPosition + pXYHorzOffset%; aV := bPosition + pXYVertOffset%; aMaxH := max(aH,aMaxH); aMaxV := max(aV,aMaxV); bPosition := bPosition + pXYseparation; next aPosition := aPosition + pXYseparation; next StartNewSession(kXY); SetSpotScales(aMaxH, aMaxV, pXYHorzOffset%, pXYVertOffset%); SetScrollingScales(aMaxH, aMaxV, pXYHorzOffset%, pXYVertOffset%); ArrConst(gTable%, 0); 'clear global table data ArrAdd(gTable%, aTable%); 'copy the table to be used with NEWDIG SampleSeqTable(gTable%, kTableOffset1000%); 'load all this data into the tabl SampleSeqVar(sPARAMCHANGED, kTrue); 'signal parameters changed SetToolbar(kXY); SetVelocityChannels(); EditSelectAll(); EditClear(); ReportFlagSet(); endif return kTrue; 'Stay in toolbar end; 'DialogXY '---------------------------------------------------- ' ResetModeVariables '1/3/02 '---------------------------------------------------- proc ResetModeVariables() SampleSeqVar(sHITTYPE1,0); SampleSeqVar(sHITTYPE2,0); gForgivenessAccumulator := 0; 'reset blanking gTimeOnAccumulator := 0; 'reset interval gContiguousAccumulator := 0; 'reset gFeedAccumulator := 0; 'reset gTimeAccumulator := 0; gMinTimeOK := kFalse; 'target presented for the minimum period of time gMaxTimeOK := kFalse; gContiguousTimeOK := kFalse; gTimeOnOK := kFalse; end 'ResetModeVariables '---------------------------------------------------- ' GetLimit 'Report the limit for a given theta. ' '11/16/04 '---------------------------------------------------- func GetLimit%(theta) while theta > 360 do theta := theta - 360; 'adjust theta to a useable value wend docase case theta >= 337.5 then return pLimits%[0]; case theta >= 292.5 then return pLimits%[7]; case theta >= 247.5 then return pLimits%[6]; case theta >= 202.5 then return pLimits%[5]; case theta >= 157.5 then return pLimits%[4]; case theta >= 112.5 then return pLimits%[3]; case theta >= 67.5 then return pLimits%[2]; case theta >= 22.5 then return pLimits%[1]; case theta >= 0 then return pLimits%[0]; endcase return kTrue; 'Stay in toolbar end 'GetLimit '---------------------------------------------------- ' DialogLimits 'Get the excursion limits for each axis and ±22 'degrees around it. These apply to most Sactrack modes. ' '11/7/03 '---------------------------------------------------- func DialogLimits%() var junk1%,junk2%,junk3%,junk4%,junk5%,ok%,i%; dlgcreate("Excursion Limits",kX); dlglabel(1,"",10); dlglabel(2,"These are the center angles and apply to",0); dlglabel(3,"± 22.5° around the angles",0); dlglabel(4,"",10); dlginteger(5," 0°", 0, 160); 'these limits are huge to accomodate stepping from one side of the screen to the other in one step dlginteger(6," 45°", 0, 90); dlginteger(7," 90°", 0, 90); 'these are not failsafe dlginteger(8,"135°", 0, 90); dlginteger(9,"180°", 0, 160); 'and can only protect against the extremest of poor choices dlginteger(10,"225°", 0, 90); dlginteger(11,"270°", 0, 90); dlginteger(12,"315°", 0, 90); dlglabel(13,"",10); ok% := dlgShow(junk1%,junk2%,junk3%,junk4%,pLimits%[],junk5%); ReloadMode(); 'force them to be used return kTrue; 'Stay in toolbar end 'DialogLimits '---------------------------------------------------- ' SetScrollingScales 'Set the Y-range for all the traces, even for ones 'that are unrelated to a mode. If the trace doesn't 'exist the request will be ignored. ' '6/2/06 '---------------------------------------------------- proc SetScrollingScales(aMaxX, aMaxY, aOffX, aOffY); SetScrollingScale(gChHeye1, aMaxX, -1, aOffX); SetScrollingScale(gChHtarg1, aMaxX, -1, aOffX); SetScrollingScale(gChHeye2, aMaxX, -1, aOffX); SetScrollingScale(gChHtarg2, aMaxX, -1, aOffX); SetScrollingScale(gChHhead, aMaxX, -1, aOffX); SetScrollingScale(gChAux1, aMaxX, -1, aOffX); SetScrollingScale(gChAux3, aMaxX, -1, aOffX); SetScrollingScale(gChAux5, aMaxX, -1, aOffX); SetScrollingScale(gChVeye1, -1, aMaxY, aOffY); SetScrollingScale(gChVtarg1, -1, aMaxY, aOffY); SetScrollingScale(gChVeye2, -1, aMaxY, aOffY); SetScrollingScale(gChVtarg2, -1, aMaxY, aOffY); SetScrollingScale(gChVhead, -1, aMaxY, aOffY); SetScrollingScale(gChAux2, -1, aMaxY, aOffY); SetScrollingScale(gChAux4, -1, aMaxY, aOffY); if pVergenceData = kTrue then SetScrollingScale(gChMemHeyeVergence, aMaxX, -1, aOffX); SetScrollingScale(gChMemVeyeVergence, -1, aMaxY, aOffY); endif if pGazeData = kTrue then SetScrollingScale(gChMemHeyeinhead, aMaxX, -1, aOffX); SetScrollingScale(gChMemVeyeinhead, -1, aMaxY, aOffY); endif end '---------------------------------------------------- ' SetScrollingScale 'Set the Y scale. Will use the largest x or y. 'Use aMaxX, aMaxY this way: ' ' + num = use this number as max range ' 0 = use limit setting ' - num = inactive direction ' '5/23/06 '---------------------------------------------------- proc SetScrollingScale(aTrace%, aMaxX, aMaxY, aOff); const kHorz := 0, kVert := 1; var aMaxZ := 0; 'set the trace scale docase case (aMaxX = 0) and (aMaxY < 0) then 'use the limits 'aMaxZ := GetMaxLimit(kHorz); 'X-Horizontal aMaxZ := max(GetMaxLimit(kHorz),GetMaxLimit(kVert)); case (aMaxX < 0) and (aMaxY = 0) then 'use the limits 'aMaxZ := GetMaxLimit(kVert); 'Y-Vertical aMaxZ := max(GetMaxLimit(kHorz),GetMaxLimit(kVert)); else aMaxZ := max(aMaxX, aMaxY); endcase aMaxZ := aMaxZ + aOff; 'add the offset, if any 'aMaxZ := aMaxZ + 1; 'make it a little larger to see the whole spot aMaxZ := aMaxZ + pScaleMargin; 'make it a little larger to see the whole spot aMaxZ := max(aMaxZ, pScaleMinimum); 'use nothing smaller than 25 degrees if ViewKind(gDataWindow%) >= 0 then view(gDataWindow%); 'Make the data view the current view if aTrace% > 0 then yrange(aTrace%, -aMaxZ, aMaxZ); 'set the range if the trace exists endif endif end 'SetScrollingScale '---------------------------------------------------- ' SetSpotScales 'Set the XY scale. Will use the largest x or y. 'When both aMaxX and aMaxY set to 0 forces routine to 'use the limit settings instead of the passed arguments. '5/23/06 '---------------------------------------------------- proc SetSpotScales(aMaxX, aMaxY, aOffX, aOffY); var aMaxZ := 0; 'set the spot scope scale if (aMaxX = 0) and (aMaxY = 0) then 'use the limits aMaxX := GetMaxLimit(0); 'X-Horizontal aMaxY := GetMaxLimit(1); 'Y-Vertical endif aMaxX := aMaxX + aOffX; 'add the offsets aMaxY := aMaxY + aOffY; 'aMaxX := max(10, aMaxX); 'no smaller than 10 deg, probably a mistake if it is less than 10 'aMaxY := max(10, aMaxY); ' aMaxX := aMaxX + 1; 'make it a little larger to see the whole spot ' aMaxY := aMaxY + 1; aMaxX := aMaxX + pScaleMargin; 'make it a little larger to see the whole spot aMaxY := aMaxY + pScaleMargin; aMaxZ := max(aMaxX, aMaxY); 'use the largest, X or Y aMaxZ := max(aMaxZ, pScaleMinimum); 'use nothing smaller than 25 degrees if ViewKind(gSpotWindow%) >= 0 then View(gSpotWindow%); 'Make the data view the current view yrange(-1,-aMaxZ,aMaxZ); xrange(-aMaxZ,aMaxZ); endif end 'SetSpotScales '---------------------------------------------------- ' GetMaxLimit 'Get the maximum scale required for H or V. '6/1/06 '---------------------------------------------------- func GetMaxLimit(aAxis); 'x=0 y -1 docase case(aAxis = 0) then 'max horizontal return max(pLimits%[0], pLimits%[1]*0.707, pLimits%[3]*0.707, pLimits%[4], pLimits%[5]*0.707, pLimits%[7]*0.707); case(aAxis = 1) then 'max vertical return max(pLimits%[2], pLimits%[1]*0.707, pLimits%[3]*0.707, pLimits%[6], pLimits%[5]*0.707, pLimits%[7]*0.707); endcase end 'GetMaxLimit '---------------------------------------------------- ' SetDefaultHistogramLocations 'Set the values used to position the directional 'histograms ' '9/3/04 '---------------------------------------------------- proc SetDefaultHistogramLocations() gHistoWinSize[0][0] := 76; gHistoWinSize[0][1] := 31; gHistoWinSize[0][2] := 100; gHistoWinSize[0][3] := 61; gHistoWinSize[1][0] := 76; gHistoWinSize[1][1] := 0; gHistoWinSize[1][2] := 100; gHistoWinSize[1][3] := 30; gHistoWinSize[2][0] := 51; gHistoWinSize[2][1] := 0; gHistoWinSize[2][2] := 75; gHistoWinSize[2][3] := 30; gHistoWinSize[3][0] := 26; gHistoWinSize[3][1] := 0; gHistoWinSize[3][2] := 50; gHistoWinSize[3][3] := 30; gHistoWinSize[4][0] := 26; gHistoWinSize[4][1] := 31; gHistoWinSize[4][2] := 50; gHistoWinSize[4][3] := 61; gHistoWinSize[5][0] := 26; gHistoWinSize[5][1] := 62; gHistoWinSize[5][2] := 50; gHistoWinSize[5][3] := 92; gHistoWinSize[6][0] := 51; gHistoWinSize[6][1] := 62; gHistoWinSize[6][2] := 75; gHistoWinSize[6][3] := 92; gHistoWinSize[7][0] := 76; gHistoWinSize[7][1] := 62; gHistoWinSize[7][2] := 100; gHistoWinSize[7][3] := 92; end 'SetDefaultHistogramLocations '---------------------------------------------------- ' SetDefaultComplexLocations 'Set the values used to position the complex window ' '6/7/06 '---------------------------------------------------- proc SetDefaultComplexLocations() gComplexWinSize[0][0] := 76; gComplexWinSize[0][1] := 31; gComplexWinSize[0][2] := 100; gComplexWinSize[0][3] := 61; gComplexWinSize[1][0] := 76; gComplexWinSize[1][1] := 0; gComplexWinSize[1][2] := 100; gComplexWinSize[1][3] := 30; gComplexWinSize[2][0] := 51; gComplexWinSize[2][1] := 0; gComplexWinSize[2][2] := 75; gComplexWinSize[2][3] := 30; gComplexWinSize[3][0] := 26; gComplexWinSize[3][1] := 0; gComplexWinSize[3][2] := 50; gComplexWinSize[3][3] := 30; gComplexWinSize[4][0] := 26; gComplexWinSize[4][1] := 31; gComplexWinSize[4][2] := 50; gComplexWinSize[4][3] := 61; gComplexWinSize[5][0] := 26; gComplexWinSize[5][1] := 62; gComplexWinSize[5][2] := 50; gComplexWinSize[5][3] := 92; gComplexWinSize[6][0] := 51; gComplexWinSize[6][1] := 62; gComplexWinSize[6][2] := 75; gComplexWinSize[6][3] := 92; gComplexWinSize[7][0] := 76; gComplexWinSize[7][1] := 62; gComplexWinSize[7][2] := 100; gComplexWinSize[7][3] := 92; end 'SetDefaultComplexLocations '---------------------------------------------------- ' DialogAnalysis '4/17/03 '---------------------------------------------------- func DialogAnalysis%() var '*** if you change aList$ you must change >proc InitializeAttributeNames< and other places ! ! ! ! ' "-none-" is a trick for single histograms aList$ := "-none-|Horz Eye and Targ Amp|Saccade Number|Polar Amp|Polar Gain|Polar Saccade Error|Polar Target Amp|Polar Target Theta|Reaction Time|Saccade Duration|Vert eye and Targ Amp|Horz Eye Amp|Vert Eye Amp|Horz Targ Amp|Vert Targ Amp", ' aList$ := "", ' aList$ += "-none-|", ' aList$ += "Horz Eye and Targ Amp|", ' aList$ += "Saccade Number|Polar Amp|", ' aList$ += "Polar Gain|Polar Saccade Error|", ' aList$ += "Polar Target Amp|", ' aList$ += "Polar Target Theta|", ' aList$ += "Reaction Time|", ' aList$ += "Saccade Duration|", ' aList$ += "Vert eye and Targ Amp|", ' aList$ += "Horz Eye Amp|", ' aList$ += "Vert Eye Amp|", ' aList$ += "Horz Targ Amp|", ' aList$ += "Vert Targ Amp", ' '*** if you change aList$ you must change >proc InitializeAttributeNames< and other places ! ! ! ! ok%, aPlot := 3, aRow := 1, aUp := 0, aDn := 20, aTemp, aHalfSize, aLeft, aRight, aLimit%, aChanged%, i%, aResult%, aGroup[3][4], '[var_fields] [instances] bGroup[3][2], cGroup, dGroup[3], eGroup[2], item%, aT1,aT2,aT3,aT4,aT5,aT6, aTab0,aTab1,aTab2,aTab3,aTab4,aTab5,aTab6,aTab7,aTab8; aTab0 := 42; aTab1 := aTab0 + 15; aTab2 := 53; aTab3 := aTab1 + 15; aTab4 := aTab3 + -2; aTab5 := 35; aTab6 := 72; aTab7 := 80; aTab8 := 92; aT1 := 0; aT2 := aT1 + 8; aT3 := aT2 + 20; aT4 := aT3 + 5; aT5 := aT4 + 26; aT6 := aT5 + 10; 'update the parameters by determining which plots are still shown and where they are, some may have been user-deleted GetWindowPositions(); dlgcreate("Online Analysis",kX); aRow := aRow + 1; dlgText("T R I A L F I L T E R P A R A M E T E R S", 0, aRow); aRow := aRow + 1; dlgReal(1,"Polar Target Step Size (Lo / Hi)", 0, 100, aTab0, aRow); dlgReal(2, "", 0, 100, aTab1, aRow); dlgText("deg", aTab4, aRow); aRow := aRow + 1; dlgReal(3,"Saccadic Onset Velocity", 0, 1000, aTab0, aRow); dlgText("d/s", aTab4, aRow); aRow := aRow + 1; dlgReal(4,"Saccadic Offset Velocity", 0, 1000, aTab0, aRow); dlgText("d/s", aTab4, aRow); aRow := aRow + 1; dlgReal(5,"Min Peak Saccadic Velocity", 0, 1000, aTab0, aRow); dlgText("d/s", aTab4, aRow); aRow := aRow + 1; dlgReal(6,"Saccadic Gain (Lo / Hi)", 0, 10, aTab0, aRow); dlgReal(7, "", 0, 10, aTab1, aRow); aRow := aRow + 1; dlgReal(8,"Max Deviation from Cardinal Directions", 0, 180, aTab0, aRow); dlgText("deg", aTab4, aRow); aRow := aRow + 1; dlgReal(9,"Saccade search post target (start/stop)", -2, 2, aTab0, aRow); dlgReal(10, "", -2, 2, aTab1, aRow); dlgText("sec", aTab4, aRow); aRow := aRow + 2; dlgText("S P E C I F Y P L O T S T O B E S H O W N",0, aRow); 'standard selectable plots '------------------------- aRow := aRow + 1; dlgText("Use",aT1, aRow); dlgText("X attribute",aT2+3, aRow); dlgText("Y attribute",aT4+3, aRow); aRow := aRow + 1; item% := 11; for i% := 0 to kMaxPlots%-1 do dlgCheck(item%, "",aT1, aRow); item% := item% + 1; dlgList(item%, "", aList$, 99, aT2, aRow); item% := item% + 1; dlgText("vs", aT3, aRow); dlgList(item%, "", aList$, 99, aT4, aRow); item% := item% + 1; aRow := aRow + 1; next for i% := 0 to kMaxPlots%-1 do aGroup[0][i%] := gAnalPlotSelect%[i%]; aGroup[1][i%] := gAnalXattr[i%]; aGroup[2][i%] := gAnalYattr[i%]; next 'histogram selectable plots '-------------------------- dlgText("Bin Size",aTab1+2, aRow); aRow := aRow + 1; for i% := kMaxPlots% to kMaxPlots%+kMaxBinPlots%-1 do dlgCheck(item%, "",aT1, aRow); item% := item% + 1; dlgList(item%, "", aList$, 99, aT2, aRow); item% := item% + 1; dlgText("vs Trials", aT3, aRow); dlgReal(item%, "", -1000, 1000, aTab1, aRow); item% := item% + 1; aRow := aRow + 1; next for i% := kMaxPlots% to kMaxPlots%+kMaxBinPlots%-1 do bGroup[0][i%-kMaxPlots%] := gAnalPlotSelect%[i%]; bGroup[1][i%-kMaxPlots%] := gAnalXattr[i%]; bGroup[2][i%-kMaxPlots%] := gAnalParamOne[i%]; next 'fixed plots '----------- aRow := aRow + 1; dlgCheck(item%, "Evoked Saccades vs. Stimulation Number",aT1,aRow); item% := item% + 1; aRow := aRow + 2; cGroup := gAnalPlotSelect%[kMaxPlots%+kMaxBinPlots%+kEvokedPlots%-1]; dlgCheck(item%, "Cardinal Dir Histograms Lined Up On the Saccade -->",aT1,aRow); item% := item% + 1; dlgList(item%, "","Onset|Offset", 99, aTab2, aRow); item% := item% + 1; dlgText("y-scale", aTab6, aRow); dlginteger(item%,"", 0, 10000, aTab7, aRow); item% := item% + 1; dlgText("spikes/s", aTab8, aRow); aRow := aRow + 1; dlgCheck(item%, "Cardinal Dir Complex Spikes Lined Up On the Saccade -->",aT1,aRow); item% := item% + 1; dlgList(item%, "","Onset|Offset", 99, aTab2, aRow); item% := item% + 1; aRow := aRow + 2; 'dGroup[0][0] := gHistoSelect%; 'dGroup[1][0] := gHistoAlignment%; 'dGroup[0][1] := gComplexSelect%; 'dGroup[1][1] := gComplexAlignment%; dGroup[0] := gHistoSelect%; dGroup[1] := gHistoAlignment%; dGroup[2] := gHistoYmax%; eGroup[0] := gComplexSelect%; eGroup[1] := gComplexAlignment%; dlgCheck(item%, "XY Saccade Tragectories",aT1,aRow); item% := item% + 1; aRow := aRow + 2; dlgText("",0, aRow); ok% := dlgshow(pMinTargAmp, pMaxTargAmp, pOnsetVelocity, pOffsetVelocity, pMinSaccadicVelocity, pMinGain, pMaxGain, pMaxThetaError, pSaccadeSearchStart, pSaccadeSearchEnd, aGroup[][], bGroup[][], cGroup, dGroup[], eGroup[], gTragectorySelect%); if ok% > 0 then 'standard selectable plots '------------------------- for i% := 0 to kMaxPlots%-1 do aChanged% := kFalse; 'detect if any changes have occurred, protects us from changing the attributes and not reseting the plot if gAnalPlotSelect%[i%] <> aGroup[0][i%] then aChanged% := kTrue; endif if gAnalXattr[i%] <> aGroup[1][i%] then aChanged% := kTrue; endif if gAnalYattr[i%] <> aGroup[2][i%] then aChanged% := kTrue; endif if aChanged% = kTrue then gAnalPlotSelect%[i%] := aGroup[0][i%]; gAnalXattr[i%] := aGroup[1][i%]; gAnalYattr[i%] := aGroup[2][i%]; if ViewKind(gAnalHandle%[i%]) = 12 then 'if view present view(gAnalHandle%[i%]); fileClose(0,-1); gAnalHandle%[i%] := -2; 'invalid handle 'ResetPlot(i%); endif endif if ViewKind(gAnalHandle%[i%]) = 12 then 'if view present AnalysisPresent(i%); else 'view not present if gAnalPlotSelect%[i%] = 1 then 'want to make it present? AnalysisCreate(i%); ResetPlot(i%); endif endif next 'histogram selectable plots '-------------------------- for i% := kMaxPlots% to kMaxPlots%+kMaxBinPlots%-1 do aChanged% := kFalse; 'detect if any changes have occurred, protects us from changing the attributes and not reseting the plot if gAnalPlotSelect%[i%] <> bGroup[0][i%-kMaxPlots%] then aChanged% := kTrue; endif if gAnalXattr[i%] <> bGroup[1][i%-kMaxPlots%] then aChanged% := kTrue; endif if gAnalParamOne[i%] <> bGroup[2][i%-kMaxPlots%] then aChanged% := kTrue; endif if aChanged% = kTrue then gAnalPlotSelect%[i%] := bGroup[0][i%-kMaxPlots%]; gAnalXattr[i%] := bGroup[1][i%-kMaxPlots%]; gAnalYattr[i%] := 0; 'ALWAYS Saccade Number gAnalParamOne[i%] := bGroup[2][i%-kMaxPlots%]; if ViewKind(gAnalHandle%[i%]) = 12 then 'if view present view(gAnalHandle%[i%]); fileClose(0,-1); gAnalHandle%[i%] := -2; 'invalid handle 'ResetPlot(i%); endif endif if ViewKind(gAnalHandle%[i%]) = 12 then 'if view present AnalysisPresent(i%); else 'view not present if gAnalPlotSelect%[i%] = 1 then 'want to make it present? AnalysisCreate(i%); ResetPlot(i%); endif endif next 'Evoked Saccade vs Stimulation Number '-------------------------- i% := kMaxPlots%+kMaxBinPlots%+kEvokedPlots%-1; 'detect if any changes have occurred, protects us from changing the attributes and not reseting the plot if gAnalPlotSelect%[i%] <> cGroup then gAnalPlotSelect%[i%] := cGroup; gAnalXattr[i%] := 21; 'ALWAYS Stimulation Number gAnalYattr[i%] := 22; 'ALWAYS Evoked Saccade Amplitude if ViewKind(gAnalHandle%[i%]) = 12 then 'if view present view(gAnalHandle%[i%]); fileClose(0,-1); gAnalHandle%[i%] := -2; 'invalid handle 'ResetPlot(i%); endif endif if ViewKind(gAnalHandle%[i%]) = 12 then 'if view present AnalysisPresent(i%); else 'view not present if gAnalPlotSelect%[i%] = 1 then 'want to make it present? AnalysisCreate(i%); ResetPlot(i%); endif endif '-H----------Prepare 8 histogram windows---------- gHistoSelect% := dGroup[0]; gHistoAlignment% := dGroup[1]; gHistoYmax% := dGroup[2]; 'used in ResetHistogramProcess gComplexSelect% := eGroup[0]; gComplexAlignment% := eGroup[1]; aTemp := 0; for i% := 0 to kMaxVectors% - 1 do if ViewKind(gHistoHandle%[i%]) = 12 then aTemp := aTemp + 1; 'record how many histo plots are present else gHistoHandle%[i%] := -1; 'record which histo plots have been closed endif next if aTemp > 0 then 'if plots are present for i% := 0 to kMaxVectors% - 1 do if ViewKind(gHistoHandle%[i%]) = 12 then 'if view present FrontView(gHistoHandle%[i%]); 'bring them to the top YRange(1,0,gHistoYmax%); 're-scale plot in case user has changed iti endif next if gHistoSelect% = 0 then CloseHistoPlots(); 'user finished with plots endif else if gHistoSelect% = 1 then ResetHistogramProcess%(); endif endif '-C----------Prepare complex window---------- if gComplexSelect% = 0 then 'whenever plot is de-selected ResetComplexVar(); 'initialize start time, arrays and counters related to complex spike presentation endif if ViewKind(gComplexHandle%) >= 0 then 'if view present frontview(gComplexHandle%); 'bring it up front endif '-T----------Prepare tragectory window if gTragectorySelect% = kFalse then if ViewKind(gTragectoryHandle%) = 12 then 'if view present view(gTragectoryHandle%); fileClose(0,-1); gTragectoryHandle% := -2; 'invalid handle ResetTragectory(); endif endif if ViewKind(gTragectoryHandle%) = 12 then 'if view present FrontView(gTragectoryHandle%); 'bring it to the top if gTragectorySelect% = kFalse then MyAnalysisClose(gTragectoryHandle%, -1); 'user finished with plot endif else 'view not present if gTragectorySelect% = kTrue then 'want to make it present? AnalysisTragectoryCreate(); ResetTragectory(); 'ResetTragectoryProcess%(); endif endif endif 'if ok% > 0 then view(gDataWindow%); gLastOnLineTime := MaxTime(); 'start analyzing from this point in time SetToolbar(gLastMode%); 'present new buttons as required ToolbarEnable(gResetHistoButton,gHistoSelect%); return kTrue; 'Stay in toolbar end 'DialogAnalysis '---------------------------------------------------- ' AnalysisPresent '7/26/06 '---------------------------------------------------- proc AnalysisPresent(aPlot%) FrontView(gAnalHandle%[aPlot%]); 'bring it to the top if gAnalPlotSelect%[aPlot%] = 0 then MyAnalysisClose(gAnalHandle%[aPlot%], -1); 'user finished with plot endif end 'AnalysisPresent '---------------------------------------------------- ' AnalysisCreate '7/26/06 '---------------------------------------------------- proc AnalysisCreate(aPlot%) gAnalHandle%[aPlot%] := FileNew(12,1); 'create a new plot Window( gAnalWinSize[aPlot%][0], gAnalWinSize[aPlot%][1], gAnalWinSize[aPlot%][2], gAnalWinSize[aPlot%][3]); 'put it where it was last time end 'AnalysisCreate '---------------------------------------------------- ' AnalysisTragectoryCreate '1/10/07 '---------------------------------------------------- proc AnalysisTragectoryCreate() gTragectoryHandle% := FileNew(12,1); 'create a new plot Window( gTragectoryX1, 'put it where it was last time gTragectoryY1, gTragectoryX2, gTragectoryY2); 'put it where it was last time end 'AnalysisTragectoryCreate '---------------------------------------------------- ' AnalysisCreateHistogram 'Create a histogram and configure the traits common 'to each histogram. '10/10/03 '---------------------------------------------------- proc AnalysisCreateHistogram(aVector%) var Xav[2], Yav[2], left,top,right,bottom; left := gHistoWinSize[aVector%][0]; top := gHistoWinSize[aVector%][1]; right := gHistoWinSize[aVector%][2]; bottom := gHistoWinSize[aVector%][3]; Xav[0] := 0; Xav[1] := 0; Yav[0] := 0; Yav[1] := 1200; 'create and configure the histogram window gHistoHandle%[aVector%] := FileNew(12,1); View(gHistoHandle%[aVector%]); Window(left, top, right, bottom); TitleHistogram(aVector%); XTitle$("Time re. Alignment (ms)"); XYDrawMode(1,2,2); 'big dots XYcolour(1,16); 'red XYJoin(1,1); 'join the dot XYDrawMode(1,4,2); 'width of line == dot size Xrange(gHistoStart, gHistoEnd); YRange(1,0,gHistoYmax%); XYDrawMode(1,5,0); 'Manual scaling ChanTitle$(0,"Spks/s"); 'make vertical line-up marker XYsetChan(0); XYDrawMode(2,2,1); XYcolour(2,24); XYJoin(2,1); XYDrawMode(2,4,1); XYAddData(2,Xav[],Yav[]); end 'AnalysisCreateHistogram '---------------------------------------------------- ' ResetPlotXXXX 'An ugly little work around to allows the buttons to 'call routines based on the user's plotting choices. '8/17/06 '---------------------------------------------------- func ResetPlotZero%() ResetPlotProcess%(0); return kTrue; end func ResetPlotOne%() ResetPlotProcess%(1); return kTrue; end func ResetPlotTwo%() ResetPlotProcess%(2); return kTrue; end func ResetPlotThree%() ResetPlotProcess%(3); return kTrue; end func ResetPlotFour%() ResetPlotProcess%(4); return kTrue; end func ResetPlotFive%() ResetPlotProcess%(5); return kTrue; end func ResetPlotSix%() ResetPlotProcess%(6); return kTrue; end func ResetPlotSeven%() ResetPlotProcess%(7); return kTrue; end '---------------------------------------------------- ' ResetPlotProcess '8/15/06 '---------------------------------------------------- func ResetPlotProcess%(aPlot%) GetWindowPositions(); if ViewKind(gAnalHandle%[aPlot%]) = 12 then 'if view present View(gAnalHandle%[aPlot%]); FileClose(0,-1); endif AnalysisCreate(aPlot%); ResetPlot(aPlot%); return kTrue; end 'ResetPlotProcess '---------------------------------------------------- ' ResetPlot 'To have user-selectable attributes, all plots have 'all the channels. They are not filled if the user 'did not request them. '8/15/06 '---------------------------------------------------- proc ResetPlot(aPlot%) if ViewKind(gAnalHandle%[aPlot%]) = 12 then 'if view present view(gAnalHandle%[aPlot%]); Window( gAnalWinSize[aPlot%][0], 'this may not be needed gAnalWinSize[aPlot%][1], gAnalWinSize[aPlot%][2], gAnalWinSize[aPlot%][3]); 'put it where it was last time gAnalN[aPlot%] := 0; 'n = 0 gAnalNpos[aPlot%] := 0; 'POSn = 0 gAnalNneg[aPlot%] := 0; 'NEGn = 0 gAnalAvePos[aPlot%] := 0; gAnalAveNeg[aPlot%] := 0; TitleSet(aPlot%); 'select the appropriate plot title Xtitle$(gAnalLabelAxis$[gAnalXattr[aPlot%]]); 'label plot's X axis ChanTitle$(0, gAnalLabelAxis$[gAnalYattr[aPlot%]]); 'equivalent to Ytitle$ which doesn't exist ArrConst(gGenHistoArrayPos[],0); ArrConst(gGenHistoArrayNeg[],0); '+ direction XYDrawMode(1,2,2); 'small dots XYcolour(1,16); 'red '- direction XYsetChan(0); 'add a second channel XYDrawMode(2,2,2); 'small dots XYColour(2,24); 'blue if gAnalYattr[aPlot%] = 0 then 'histogram plot XYJoin(1,1); 'join the points with lines XYJoin(2,1); endif docase case gAnalXattr[aPlot%] = 1 then 'Horz Eye/Targ Amp gAnalXlo%[aPlot%] := -1; gAnalXhi%[aPlot%] := 1; KeySetup(aPlot%,"Eye","Target","",""); case gAnalXattr[aPlot%] = 2 then 'Saccade Number gAnalXlo%[aPlot%] := 0; gAnalXhi%[aPlot%] := 10; ShowMeanTraces(aPlot%); 'activate mean traces KeySetup(aPlot%,"+ Dir","- Dir","+ Mean","- Mean"); case gAnalXattr[aPlot%] = 3 then 'Polar Amp gAnalXlo%[aPlot%] := 0; gAnalXhi%[aPlot%] := 10; case gAnalXattr[aPlot%] = 4 then 'Polar Gain gAnalXlo%[aPlot%] := 0; gAnalXhi%[aPlot%] := 1.5; case gAnalXattr[aPlot%] = 5 then 'Polar Saccade Error gAnalXlo%[aPlot%] := -10; gAnalXhi%[aPlot%] := 10; case gAnalXattr[aPlot%] = 6 then 'Polar Target Step Size gAnalXlo%[aPlot%] := 0; gAnalXhi%[aPlot%] := 20; case gAnalXattr[aPlot%] = 7 then 'Polar Target Theta gAnalXlo%[aPlot%] := 0; gAnalXhi%[aPlot%] := 359; case gAnalXattr[aPlot%] = 8 then 'Reaction Time gAnalXlo%[aPlot%] := -600; gAnalXhi%[aPlot%] := 600; case gAnalXattr[aPlot%] = 9 then 'Saccade Duration gAnalXlo%[aPlot%] := 0; gAnalXhi%[aPlot%] := 500; case gAnalXattr[aPlot%] = 10 then 'Vert eye/tar Amp gAnalXlo%[aPlot%] := -1; gAnalXhi%[aPlot%] := 1; KeySetup(aPlot%,"Eye","Target","",""); case gAnalXattr[aPlot%] = 11 then 'HE Amp gAnalXlo%[aPlot%] := -10; gAnalXhi%[aPlot%] := 10; case gAnalXattr[aPlot%] = 12 then 'VE Amp gAnalXlo%[aPlot%] := -10; gAnalXhi%[aPlot%] := 10; case gAnalXattr[aPlot%] = 13 then 'HT Amp gAnalXlo%[aPlot%] := -10; gAnalXhi%[aPlot%] := 10; case gAnalXattr[aPlot%] = 14 then 'VT Amp gAnalXlo%[aPlot%] := -10; gAnalXhi%[aPlot%] := 10; case gAnalXattr[aPlot%] = 21 then 'Stimulation Number gAnalXlo%[aPlot%] := 0; gAnalXhi%[aPlot%] := 10; ShowMeanTraces(aPlot%); 'activate mean traces KeySetup(aPlot%,"+ Dir","- Dir","+ Mean","- Mean"); endcase docase case gAnalYattr[aPlot%] = 0 then 'Number of Saccade gAnalYlo%[aPlot%] := 0; gAnalYhi%[aPlot%] := 10; XYDrawMode(1,2,5); 'Big dot XYDrawMode(2,2,5); 'Big dot KeySetup(aPlot%,"+ Dir","- Dir","+ Mean","- Mean"); case gAnalYattr[aPlot%] = 1 then 'Horz Eye/Targ Amp gAnalYlo%[aPlot%] := -1; gAnalYhi%[aPlot%] := 1; case gAnalYattr[aPlot%] = 2 then 'Saccade Number gAnalYlo%[aPlot%] := 0; gAnalYhi%[aPlot%] := 10; case gAnalYattr[aPlot%] = 3 then 'Polar Amp gAnalYlo%[aPlot%] := 0; gAnalYhi%[aPlot%] := 10; case gAnalYattr[aPlot%] = 4 then 'Polar Gain gAnalYlo%[aPlot%] := 0; gAnalYhi%[aPlot%] := 1.5; case gAnalYattr[aPlot%] = 5 then 'Polar Saccade Error gAnalYlo%[aPlot%] := -10; gAnalYhi%[aPlot%] := 10; case gAnalYattr[aPlot%] = 6 then 'Polar Target Step Size gAnalYlo%[aPlot%] := 0; gAnalYhi%[aPlot%] := 20; case gAnalYattr[aPlot%] = 7 then 'Polar Target Theta gAnalYlo%[aPlot%] := 0; gAnalYhi%[aPlot%] := 359; case gAnalYattr[aPlot%] = 8 then 'Reaction Time gAnalYlo%[aPlot%] := 0; gAnalYhi%[aPlot%] := 100; case gAnalYattr[aPlot%] = 9 then 'Saccade Duration gAnalYlo%[aPlot%] := 0; gAnalYhi%[aPlot%] := 500; case gAnalYattr[aPlot%] = 10 then 'Vert eye/tar Amp gAnalYlo%[aPlot%] := -1; gAnalYhi%[aPlot%] := 1; case gAnalYattr[aPlot%] = 22 then 'Evoked Saccade Amp gAnalYlo%[aPlot%] := 0; gAnalYhi%[aPlot%] := 10; endcase XRange(gAnalXlo%[aPlot%],gAnalXhi%[aPlot%]); 'scale X axis YRange(-1,gAnalYlo%[aPlot%],gAnalYhi%[aPlot%]); 'scale Y axis endif end 'ResetPlot '---------------------------------------------------- ' ResetTragectoryProcess '4/7/06 '---------------------------------------------------- func ResetTragectoryProcess%() GetWindowPositions(); if ViewKind(gTragectoryHandle%) = 12 then 'if view present View(gTragectoryHandle%); FileClose(0,-1); endif AnalysisTragectoryCreate(); ResetTragectory(); return kTrue; end 'ResetTragectoryProcess '---------------------------------------------------- ' ResetTragectory ' '1/9/07 '---------------------------------------------------- proc ResetTragectory() if ViewKind(gTragectoryHandle%) = 12 then 'if view present view(gTragectoryHandle%); Window( gTragectoryX1, 'put it where it was last time gTragectoryY1, gTragectoryX2, gTragectoryY2); 'put it where it was last time gTragectoryN := 0; XRange(-20,20); 'scale X axis YRange(-1,-20,20); 'scale Y axis TitleSetTragectory(); XYDrawMode(1,2,2); 'small dots XYcolour(1,16); 'red endif end '---------------------------------------------------- ' ShowMeanTraces ' '9/5/06 '---------------------------------------------------- proc ShowMeanTraces(aPlot%) if ViewKind(gAnalHandle%[aPlot%]) = 12 then 'if view present view(gAnalHandle%[aPlot%]); '+ average XYsetChan(0); 'new channel for R avg XYDrawMode(3,2,5); 'Big dot XYColour(3,16); 'Big red dot XYJoin(3,1); XYDrawMode(3,4,2); 'Draw line between points '- average XYsetChan(0); 'new channel for L avg XYDrawMode(4,2,5); 'Big dot XYColour(4,24); 'Big blue dot XYJoin(4,1); XYDrawMode(4,4,2); 'Draw line between points endif end 'ShowMeanTraces '---------------------------------------------------- ' KeySetup ' '9/5/06 '---------------------------------------------------- proc KeySetup(aPlot%,a$,b$,c$,d$) if ViewKind(gAnalHandle%[aPlot%]) = 12 then 'if view present view(gAnalHandle%[aPlot%]); 'plot legend XYkey(1,1); 'show key XYkey(2,1); 'transparent key XYkey(3,0); 'no border ChanTitle$(1, a$); 'ch 1 name ChanTitle$(2, b$); 'ch 2 name ChanTitle$(3, c$); 'ch 3 name ChanTitle$(4, d$); 'ch 4 name endif end 'KeySetup '---------------------------------------------------- ' NextComplexDisplay 'User wants to see the unit traces from the next 'cardinal angle. Stuff the data in the window upon ''request. '6/7/06 '---------------------------------------------------- func NextComplexDisplay%() var a%, b, c, d%, e%, i%, index%, aTrial%, aTemp[10001], aLeftX[10001], aRightX[10001], aDirOffset%, aResult%, aSpacing := 0.1, aRow% := 0; gNextComplexPlot% := gNextComplexPlot% + 1; 'increment pointer, show 0, 45, 90 degrees, etc. if gNextComplexPlot% > kMaxVectors% - 1 then gNextComplexPlot% := 0; 'only 0-7 vectors endif 'fill arrays with X values for plotting for c := 0 to 10000 do aLeftX[c] := c * 0.02; 'in ms x20us aRightX[c] := (c * 0.02) + 210; 'shift my 10ms next; if ViewKind(gComplexHandle%) >= 0 then view(gComplexHandle%); fileclose(0,-1); endif gComplexHandle% := FileNew(12,1); 'type 12=XY, 1=make visible now FrontView(gComplexHandle%); Window(0,0,100,99.7824); aRow% := 0; for aTrial%:= 1 to 49 step 2 do aDirOffset% := gNextComplexPlot% * 50; 'direction offset a% := aDirOffset% + aTrial%-1; b := 0.5 + aRow%; 'gComplexSpikes[10001][400], aResult% := ArrConst(aTemp[], gComplexSpikes[][a%]); 'load a trial of spike data aResult% := ArrAdd(aTemp[], b); 'vertically offset the data d% := XYSetChan(0); aResult% := XYAddData(d%, aLeftX[], aTemp[]); 'draw it aResult% := ArrConst(aTemp[], gComplexSpikes[][a%+1]);'load a trial of spike data aResult% := ArrAdd(aTemp[], b); 'vertically offset the data e% := XYSetChan(0); aResult% := XYAddData(e%, aRightX[], aTemp[]); 'draw it if odd%(aRow%) then XYcolour(d%, 24); 'blue XYcolour(e%, 24); 'blue else XYcolour(d%, 16); 'red XYcolour(e%, 16); 'red endif; XYjoin(d%, 1); XYDrawMode(d%, 2, 1); 'point size small XYDrawMode(d%, 3, 0); 'solid line XYDrawMode(d%, 4, 1); 'line thickness thin XYjoin(e%, 1); XYDrawMode(e%, 2, 1); 'point size small XYDrawMode(e%, 3, 0); 'solid line XYDrawMode(e%, 4, 1); 'line thickness thin aRow% := aRow% + 1; next; WindowTitle$("Complex Spikes @ " + str$(gNextComplexPlot% * 45) + " degrees"); return kTrue; end 'NextComplexDisplay '---------------------------------------------------- ' ResetHistogramProcess '4/7/06 '---------------------------------------------------- func ResetHistogramProcess%() var i%; GetWindowPositions(); ResetHistogram(); CloseHistoPlots(); 'user finished with plots for i% := 0 to kMaxVectors% - 1 do AnalysisCreateHistogram(i%); View(gHistoHandle%[i%]); Xrange(gHistoStart, gHistoEnd); next return kTrue; end 'ResetHistogramProcess '---------------------------------------------------- ' ResetHistogram '1/26/04 '---------------------------------------------------- proc ResetHistogram(); var i%; for i% := 0 to kMaxVectors% - 1 do ArrConst(gHistoData%[][i%],0); 'Initialize Histogram data arrays with zeros gHistoNum%[i%] := 0; next end 'ResetHistogram '---------------------------------------------------- ' ResetComplex '8/10/06 '---------------------------------------------------- func ResetComplex%() if query("Do you want to RESET the COMPLEX SPIKE windows?") = kTrue then if ViewKind(gComplexHandle%) >= 0 then 'if view present view(gComplexHandle%); fileclose(0,-1); 'close complex display without asking endif ResetComplexVar(); endif return kTrue; end 'ResetComplex '---------------------------------------------------- ' ResetComplexVar '9/7/06 '---------------------------------------------------- proc ResetComplexVar() ArrConst(gNumCS%[],0); 'reset how many trials captured in each direction ArrConst(gComplexSpikes[][], 0.5); 'initialize each trace to the centerline of the plot gNextComplexPlot% := -1; end 'ResetComplexVar '---------------------------------------------------- ' DialogDisplay '1/2/07 '---------------------------------------------------- func DialogDisplay%() var ok%, aRow := 1, aLeft := 37, bResult%, aRight, aScaleMargin, aScaleMinimum; aRight := aLeft + kUnitLabel; dlgcreate("Display Parameters",kX); dlglist(1,"Type of display","Galvo34|Galvo45|LED", 99, aLeft, aRow); aRow := aRow + 1; dlginteger(2,"LED intensity (12=brightest)",1,12, aLeft, aRow); aRow := aRow + 2; dlgreal(3,"Spot and Scroll scale added margin (±)",0,100, aLeft, aRow); dlgText("deg", aRight, aRow); aRow := aRow + 1; dlgreal(4,"Spot and Scroll scale minimal value (±)",0,100, aLeft, aRow); dlgText("deg", aRight, aRow); aRow := aRow + 1; dlgText("", aLeft, aRow); aScaleMargin := pScaleMargin; aScaleMinimum := pScaleMinimum; ok% := dlgshow(pDisplay, pLEDintensity%, pScaleMargin, pScaleMinimum); if ok% > 0 then SetCalibration(); 'Set input and output gains SetParametersCommon(); 'load the TABLE if (aScaleMargin <> pScaleMargin) or (aScaleMinimum <> pScaleMinimum) then 'did they change? ReloadMode(); 'force param to be used endif endif return kTrue; 'Stay in toolbar end 'DialogDisplay '---------------------------------------------------- ' DialogBehavior '12/16/02 '---------------------------------------------------- func DialogBehavior%() var ok%, aRow := 1, aLeft := 37, bResult%, aRight; aRight := aLeft + kUnitLabel; dlgcreate("Behavior Parameters",kX); dlgreal(1,"Horz window size (visually guided) (±)",0,10, aLeft, aRow); dlgText("deg", aRight, aRow); aRow := aRow + 1; dlgreal(2,"Vert window size (visually guided) (±)",0,10, aLeft, aRow); dlgText("deg", aRight, aRow); aRow := aRow + 2; '7/31/06 not currently used, save in case it is ever required dlgreal(3,"Horz window size (memory guided) (±)",0,10, aLeft, aRow); dlgText("deg", aRight, aRow); aRow := aRow + 1; dlgreal(4,"Vert window size (memory guided) (±)",0,10, aLeft, aRow); dlgText("deg", aRight, aRow); aRow := aRow + 2; dlgreal(5,"On-target for a total of",0.0,10, aLeft, aRow); dlgText("sec", aRight, aRow); aRow := aRow + 1; dlgreal(6,"On-target continuously for",0.0,10, aLeft, aRow); dlgText("sec", aRight, aRow); aRow := aRow + 1; dlgreal(7,"Move target as soon as",0.0,50, aLeft, aRow); dlgText("sec", aRight, aRow); aRow := aRow + 1; dlgreal(8,"Move target no later than",0.0,50, aLeft, aRow); dlgText("sec", aRight, aRow); aRow := aRow + 2; dlgreal(9,"Feeder blanking",0.1,3, aLeft, aRow); dlgText("sec", aRight, aRow); aRow := aRow + 1; dlgreal(10,"First time on",0.1,10, aLeft, aRow); dlgText("sec", aRight, aRow); aRow := aRow + 1; dlgreal(11,"Subsequent time on",0.1,10, aLeft, aRow); dlgText("sec", aRight, aRow); aRow := aRow + 1; 'dlginteger(10,"Earn it this many times before feeding",0.1,10, aLeft, aRow); dlginteger(12,"(Non-functional)",0,10, aLeft, aRow); dlgText("sec", aRight, aRow); aRow := aRow + 2; dlgreal(13,"Mayhem time-out duration ( XY + Radial )",0,30, aLeft, aRow); dlgText("sec", aRight, aRow); aRow := aRow + 2; dlgText("Force on-target at all times", 0, aRow); dlgcheck(14,"", aLeft-1, aRow); aRow := aRow + 1; dlgText("", aLeft, aRow); var aScaleMargin, aScaleMinimum; aScaleMargin := pScaleMargin; aScaleMinimum := pScaleMinimum; ' ok% := dlgshow(pDisplay, pLEDintensity%, pWindowHvg, pWindowVvg, pWindowHmg, pWindowVmg, pRealTimeOn, pRealContiguousTime, pRealMinTime, pRealMaxTime, pForgiveness, pOnFirst, pOnSubsequent, pFeedRate%, pMayhemDuration, pForceOT%); ' ok% := dlgshow(pDisplay, pLEDintensity%, pWindowHvg, pWindowVvg, pScaleMargin, pScaleMinimum, pRealTimeOn, pRealContiguousTime, pRealMinTime, pRealMaxTime, pForgiveness, pOnFirst, pOnSubsequent, pFeedRate%, pMayhemDuration, pForceOT%); ok% := dlgshow(pWindowHvg, pWindowVvg, pWindowHmg, pWindowVmg, pRealTimeOn, pRealContiguousTime, pRealMinTime, pRealMaxTime, pForgiveness, pOnFirst, pOnSubsequent, pFeedRate%, pMayhemDuration, pForceOT%); if ok% > 0 then SetCalibration(); 'Set input and output gains gWindowHvgDAC% := round(pWindowHvg * gBitsPerDegreeIn); gWindowVvgDAC% := round(pWindowVvg * gBitsPerDegreeIn); gWindowHmgDAC% := round(pWindowHmg * gBitsPerDegreeIn); gWindowVmgDAC% := round(pWindowVmg * gBitsPerDegreeIn); SetParametersCommon(); 'load the TABLE endif return kTrue; 'Stay in toolbar end 'DialogBehavior '---------------------------------------------------- ' SetParametersCommon ' 'Load the Reward parameters in the TABLE '10/6/04 '---------------------------------------------------- func SetParametersCommon() var aTable%[1000]; aTable%[00] := gWindowHvgDAC%; 'HWIND 'visually guided on-target window aTable%[01] := gWindowVvgDAC%; 'VWIND aTable%[09] := pFeedRate%; 'FEEDRATE aTable%[10] := pRealMinTime*1000; 'ASSOONAS aTable%[11] := pRealMaxTime*1000; 'NOLATER aTable%[12] := pRealContiguousTime*1000; 'CONTTON aTable%[13] := pRealTimeOn*1000; 'TOTALTON aTable%[14] := pOnFirst*1000; 'DURFIRST aTable%[15] := pOnSubsequent*1000; 'DURSUB aTable%[16] := pForgiveness*1000; 'FORGTIME aTable%[17] := pForceOT%; 'override, make him OT all the time aTable%[18] := pMayhemDuration*1000; 'time-outs when shouting or shaking in XY mode aTable%[29] := pLEDintensity%*256; aTable%[30] := gWhichBooth; 'shutter polarity is different in Robinson booth vs. other booths aTable%[31] := 0; 'time to update report to user aTable%[32] := gIn2outConversion%; 'needed to convert a A/D signal to a D/A signal SampleSeqTable(aTable%, kTableOffsetCommon%); 'load 0-999 end 'SetParametersCommon '---------------------------------------------------- ' Idle ' 'Control comes here when Spike2 has nothing to do. '11/22/02 '---------------------------------------------------- func Idle%() var aCurrentTime, aMoveNow, aTable%[1000], aT%[1000]; ' a%; 'VERY useful code for monitoring values in the sequencer. Without it there would be 'no way to debug sequencer code. This is made more complicated by using the 'TABLE data structure. Sactrack must use TABLE because there are so few sequencer VAR. if kBOBmode = 1 then ' var ' a%; ' ' SampleSeqTable(aTable%,000,1); 'GET table data ' 'display the table of data being send to the sequence ' if kBOBmode = kTrue then ' var ' j%; ' view(gDebugWindow%); ' j% := 600; ' Print("%5d,%14.1f,%14.1f,%14.1f,%14.1f\n", j%, aTable%[j%+0], aTable%[j%+1], aTable%[j%+2], aTable%[j%+3]); ' while j% < 550 do ' Print("%5d,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f\n", j%, aTable%[j%+0], aTable%[j%+1], aTable%[j%+2], aTable%[j%+3], aTable%[j%+4], aTable%[j%+5], aTable%[j%+6], aTable%[j%+7], aTable%[j%+8], aTable%[j%+9]); ' j% := j% + 10; ' wend ' endif ' a%:=000; PrintLog(" V21 = ", SampleSeqVar(21)); 'PrintLog(" V11 , V13 = ", SampleSeqVar(11), " ", SampleSeqVar(13)); ' PrintLog(" Step size ",SampleSeqVar(14)); 'PrintLog("\numPtsShownPerCh%10d,%10d,%10d,%10d,%10d,%10d,%10d,%10d,%10d,%10d,%10d",aT%[a%+0],aT%[a%+1],aT%[a%+2],aT%[a%+3],aT%[a%+4],aT%[a%+5],aT%[a%+6],aT%[a%+7],aT%[a%+8],aT%[a%+9],aT%[a%+10]); 'PrintLog("\numPtsShownPerCh%10d,%10d,%10d,%10d,%10d,%10d,%10d,%10d,%10d,%10d,%10d",aT%[a%+10],aT%[a%+11],aT%[a%+12],aT%[a%+13],aT%[a%+14],aT%[a%+15],aT%[a%+16],aT%[a%+17],aT%[a%+18],aT%[a%+19],aT%[a%+20]); ' PrintLog("\numPtsShownPerCh%10d,%10d,%10d,%10d",aT%[010],aT%[011],aT%[506],aT%[507]); 'PrintLog("%5d,%10d,%10d,%10d,%10d,%10d,%10d,%10d,%10d,%10d,%10d,","200",aT%[a%+0], " ", aT%[a%+1], " ", aT%[a%+2], " ", aT%[a%+3], " ", aT%[a%+4], " ", aT%[a%+5], " ", aT%[a%+6], " ", aT%[a%+7], " ", aT%[a%+8], " ", aT%[a%+9], " ", aT%[a%+10]); 'PrintLog("0 ",aT%[a%+0], " ", aT%[a%+1], " ", aT%[a%+2], " ", aT%[a%+3], " ", aT%[a%+4], " ", aT%[a%+5], " ", aT%[a%+6], " ", aT%[a%+7], " ", aT%[a%+8], " ", aT%[a%+9]); 'PrintLog("260 ",aT%[a%+0], " ", aT%[a%+1], " ", aT%[a%+2], " ", aT%[a%+3], " ", aT%[a%+4], " ", aT%[a%+5], " ", aT%[a%+6], " ", aT%[a%+7], " ", aT%[a%+8], " ", aT%[a%+9]); 'PrintLog("V1 ",SampleSeqVar(1), " V2 ", SampleSeqVar(2), " V3 ", SampleSeqVar(3), " V4 ", SampleSeqVar(4), " V5 ", SampleSeqVar(5), " V6 ", SampleSeqVar(6), " V7 ", SampleSeqVar(7), " V8 ", SampleSeqVar(8)); 'PrintLog("0 ",aT%[0], " 1 ", aT%[1], " 2 ", aT%[2], " 3 ", aT%[3], " 4 ", aT%[4], " 5 ", aT%[5]," 6 ",aT%[6], " 7 ", aT%[7], " 8 ", aT%[8], " 9 ", aT%[9]); 'PrintLog("500 ",aT%[500], " 501 ", aT%[501], " 502 ", aT%[502], " 503 ", aT%[503], " 504 ", aT%[504], " 505 ", aT%[505], " 506 ", aT%[506], " 507 ", aT%[507], " 508 ", aT%[508]); ' PrintLog("200 ",aT%[200], " 201 ", aT%[201], " 202 ", aT%[202], " 203 ", aT%[203], " 204 ", aT%[204], " 205 ", aT%[205], " 206 ", aT%[206], " 207 ", aT%[207], " 208 ", aT%[208]); 'PrintLog("TIMECURR ",SampleSeqVar(28), " TIMECHEK ", SampleSeqVar(29), " V5 ", SampleSeqVar(5), " V6 ", SampleSeqVar(6), " V7 ", SampleSeqVar(7), " V8 ", SampleSeqVar(8)); 'PrintLog("TIMECURR-TIMEBEG ",SampleSeqVar(7), " TIMEBEG ", SampleSeqVar(sELAPSED), " ASSOONAS ", SampleSeqVar(sASSOONAS)); 'PrintLog(" DURCONT ", SampleSeqVar(sDURCONT), " DURON ", SampleSeqVar(sDURON), " ELAPSED ", SampleSeqVar(sELAPSED), " ASSOONAS ", aT%[10], " CONTTON ", aT%[12], " TOTALON ",aT%[13], " TIMEFEED ", aT%[15]); 'PrintLog(" How many ",SampleSeqVar(7), " Selected ",SampleSeqVar(5), " Used? ",SampleSeqVar(2)); 'PrintLog(" How many ",SampleSeqVar(7), " Selected ",SampleSeqVar(5), " Used? ",SampleSeqVar(2)); 'view(gDebugWindow%); 'Print(" ASSOONAS ", aT%[10], " CONTTON ", aT%[12], " TOTALON ",aT%[13], " TIMEFEED ", aT%[15]); 'Printlog(" [29] ", aT%[29]); 'PrintLog("current ", SampleSeqVar(4)," ",SampleSeqVar(5)," ","step ", SampleSeqVar(6)," ",SampleSeqVar(7)," ","adapt ", SampleSeqVar(8)," ",SampleSeqVar(9)); 'PrintLog("stim type ", SampleSeqVar(8)); endif 'kBOBmode if ViewKind(gDataWindow%) >= 0 then 'allows program to run without a 1401 connected to it View(gDataWindow%); aCurrentTime := Maxtime(); endif aCurrentTime := trunc(aCurrentTime * 1000) / 1000; 'fix values at 3 decimal positions 'PrintLog(aCurrentTime); TimeToProcessSpotScope(aCurrentTime); TimeToProcessUnit(aCurrentTime); TimeToUpdateMemChan(aCurrentTime); TimeToPlot(); 'executed only when there is an event to process SampleSeqTable(aT%,0,1); 'GET table data if aT%[31] > 0 then 'if > 0 then the trial numbers have changed Report(); 'write the trial numbers for the user to view aT%[31] := 0; SampleSeqTable(aT%,0,0); 'SET REPORT flag endif return kTrue; 'Stay in toolbar end 'Idle '---------------------------------------------------- ' BinSpikes ' 'Get the spikes from a trial and bin them. '10/10/03 '---------------------------------------------------- 'proc BinSpikes(aBinData%[]) 'don't forget: aBinData% is passed by reference and is kHistoSize% large (251) ' const ' 'kMaxSpikes := 2000; ' kMaxSpikes := 10; ' var ' aTimeZero, ' aHistoAbsTimeStart, ' aHistoAbsTimeEnd, ' aEventTimeData[kMaxSpikes], 'this makes room for 2000 spikes in 0.600 sec ' aNumEventData%, ' aEnd, ' aStart, ' aBinIndex%, ' aSpikeIndex%; ' ' ArrConst(aEventTimeData[],0); 'initialize aEventTimeData[] with zeros ' if gHistoAlignment% = 0 then ' aTimeZero := gHistoEarliestOnset; ' else ' aTimeZero := gHistoLatestOffset; ' endif; ' ' aHistoAbsTimeStart := aTimeZero + (gHistoStart / kMS); 'remember, gHistoStart is always a negative number ' aHistoAbsTimeEnd := aTimeZero + (gHistoEnd / kMS); 'remember, gHistoEnd is always positive ' View(gDataWindow%); ' ' 'fill aEventTimeData with data from ch29 ' aNumEventData% := ChanData(gChSpikeWM%, aEventTimeData[], aHistoAbsTimeStart, aHistoAbsTimeEnd); ' ' if aNumEventData% > 0 then '4/7/06 no sense binning the spikes if none were found ' ArrSub(aEventTimeData[], aHistoAbsTimeStart); 'this converts aEventTimeData[] so th 'convert it to ms ' ArrMul(aEventTimeData[], kMS); ' ' aStart := 0; ' aSpikeIndex% := 0; 'initialize these counter dudes to zero ' aBinIndex% := 0; 'at it starts from gHistoStart ' ' 'tally spikes in the bins ' for aEnd := gHistoBin to (gHistoEnd - gHistoStart) step gHistoBin do ' while (aEventTimeData[aSpikeIndex%] < aEnd) and (aEventTimeData[aSpikeIndex%] >= aStart) and (aSpikeIndex% < kMaxSpikes) do ' 'printlog("aBinIndex% = ", str$(aBinIndex%)); ' 'printlog("aEventTimeData[aSpikeIndex%] = ", str$(aEventTimeData[aSpikeIndex%])); ' aBinData%[aBinIndex%] := aBinData%[aBinIndex%] + 1; ' aSpikeIndex% := aSpikeIndex% + 1; ' if aSpikeIndex% >= kMaxSpikes then ' Message("Too many spikes were found in BinSpikes(), tell Bob. The trial was not plotted in the histogram"); ' ArrConst(aBinData%[],0); 'initialize aEventTimeData[] with zeros ' endif ' wend; ' 'view(gDebugWindow%); ' 'Print("aStart= " + str$(aStart) + " aEnd= " + str$(aEnd) + " aSpikeIndex= " + str$(aSpikeIndex%) + " aBinIndex= " + str$(aBinIndex%) + "\n"); ' aStart := aEnd; 'move histobin boundaries ' aBinIndex% := aBinIndex% + 1; 'go to the next bin ' next; ' endif 'aNumEventData% > 0 'end; 'BinSpikes(Data) '---------------------------------------------------- ' BinSpikes ' 'Get the spikes from a trial and bin them to be used 'in the 8-direction histograms. '10/10/03 '---------------------------------------------------- proc BinSpikes(aBinData%[]) 'don't forget: aBinData% is passed by reference and is kHistoSize% large (251) const kMaxSpikes := 4000; '3/16/07 This is 4000 spikes per 600ms which is 6.666kHz 'kMaxSpikes := 10; var aTimeZero, aHistoAbsTimeStart, aHistoAbsTimeEnd, aEventTimeData[kMaxSpikes], 'this makes room for 2000 spikes in 0.600 sec aNumEventData%, aEnd, aStart, aBinIndex%, aSpikeIndex%; ArrConst(aEventTimeData[],0); 'initialize aEventTimeData[] with zeros if gHistoAlignment% = 0 then aTimeZero := gHistoEarliestOnset; else aTimeZero := gHistoLatestOffset; endif; aHistoAbsTimeStart := aTimeZero + (gHistoStart / kMS); 'remember, gHistoStart is always a negative number aHistoAbsTimeEnd := aTimeZero + (gHistoEnd / kMS); 'remember, gHistoEnd is always positive View(gDataWindow%); 'fill aEventTimeData with data from ch29 memory channel m2 '3/16/07 ChanData will not load an array beyond its dimension. aNumEventData% := ChanData(gChSpikeWM%, aEventTimeData[], aHistoAbsTimeStart, aHistoAbsTimeEnd); if aNumEventData% > 0 then '4/7/06 no sense binning the spikes if none were found if aNumEventData% < kMaxSpikes then '3/16/07 skip if it is saturated ArrSub(aEventTimeData[], aHistoAbsTimeStart); 'this converts aEventTimeData[] so th ArrMul(aEventTimeData[], kMS); 'convert it to ms aStart := 0; aSpikeIndex% := 0; 'initialize these counter dudes to zero aBinIndex% := 0; 'at it starts from gHistoStart 'tally spikes in the bins for aEnd := gHistoBin to (gHistoEnd - gHistoStart) step gHistoBin do while (aEventTimeData[aSpikeIndex%] < aEnd) and (aEventTimeData[aSpikeIndex%] >= aStart) and (aSpikeIndex% < kMaxSpikes) do 'printlog("aBinIndex% = ", str$(aBinIndex%)); 'printlog("aEventTimeData[aSpikeIndex%] = ", str$(aEventTimeData[aSpikeIndex%])); aBinData%[aBinIndex%] := aBinData%[aBinIndex%] + 1; aSpikeIndex% := aSpikeIndex% + 1; wend; 'view(gDebugWindow%); 'Print("aStart= " + str$(aStart) + " aEnd= " + str$(aEnd) + " aSpikeIndex= " + str$(aSpikeIndex%) + " aBinIndex= " + str$(aBinIndex%) + "\n"); aStart := aEnd; 'move histobin boundaries aBinIndex% := aBinIndex% + 1; 'go to the next bin next; else Message("Too many spikes were found in BinSpikes(), tell Bob. The trial was not plotted in the histogram"); ArrConst(aBinData%[],0); 'initialize aEventTimeData[] with zeros endif 'aNumEventData% < kMaxSpikes endif 'aNumEventData% > 0 end; 'BinSpikes(Data) '---------------------------------------------------- ' TimeToProcessUnit 'Draws unit acceptance pulses based on the analog unit 'channel using a horizontal cursor as a threshold. '10/9/03 '---------------------------------------------------- proc TimeToProcessUnit(aCurrentTime) if viewkind(gDataWindow%) >= 0 then if gUnitData > 0 then '0=no unit, 1=50k, 2=100k if viewkind(gCursorAccept) >= 0 then if aCurrentTime - gLastProcessUnit > 0 then 'make sure some time has passed since the last time data was imported View(gDataWindow%); var aLevel; aLevel := HCursor(gCursorAccept); 'collect spikes that exceed threshold if aLevel >= 0 then MemImport(gChSpikeWM%, gChUnit, gLastProcessUnit, aCurrentTime, 2, 0, aLevel); 'fall-thru cursor 1'positive threshold else MemImport(gChSpikeWM%, gChUnit, gLastProcessUnit, aCurrentTime, 3, 0, aLevel); 'fall-thru cursor 1 negative threshold endif gLastProcessUnit := aCurrentTime endif endif endif endif end 'TimeToProcessUnit '---------------------------------------------------- ' TimeToRectifyVelocity 'Adds the H & V velocity traces and computes the 'absolute value and puts it into a new channel. '10/30/03 '---------------------------------------------------- proc TimeToUpdateMemChan(aCurrentTime) 'Enter only once every 100ms if gLastProcessRectVel + kOnlineAnalysisInterval < aCurrentTime then var aDataLength%, aBeg, aEnd, i, junk, aMax; '1/31/07 - this protection so that this routine processes a maximum 'of aMax seconds of data, otherwise, the program get bogged down 'and can crash. aMax := 3.00; if aCurrentTime-gLastProcessRectVel > aMax then aCurrentTime := gLastProcessRectVel + aMax; endif aBeg := gLastProcessRectVel; aEnd := aCurrentTime; aDataLength% := (aEnd - aBeg + 0.001) * 1000; var aData1[aDataLength%], aData2[aDataLength%]; View(gDataWindow%); 'rectified velocity '------------------ ChanData(gChHvel, aData1[], aBeg, aEnd); ChanData(gChVvel, aData2[], aBeg, aEnd); Abs(aData1[]); Abs(aData2[]); ArrAdd(aData1[], aData2[]); ChanWriteWave(gChMemRectVel, aData1[], gLastProcessRectVel); 'eye in head '----------- if pGazeData = kTrue then ChanData(gChHeye1, aData1[], aBeg, aEnd); 'head data ChanData(gChHhead, aData2[], aBeg, aEnd); 'gaze data ArrSub(aData1[], aData2[]); ChanWriteWave(gChMemHeyeinhead, aData1[], gLastProcessRectVel); ChanData(gChVeye1, aData1[], aBeg, aEnd); 'head data ChanData(gChVhead, aData2[], aBeg, aEnd); 'gaze data ArrSub(aData1[], aData2[]); ChanWriteWave(gChMemVeyeinhead, aData1[], gLastProcessRectVel); endif 'two eye vergence '----------- if pVergenceData = kTrue then ChanData(gChHeye1, aData1[], aBeg, aEnd); 'data ChanData(gChHeye2, aData2[], aBeg, aEnd); 'data ArrSub(aData1[], aData2[]); ChanWriteWave(gChMemHeyeVergence, aData1[], gLastProcessRectVel); ChanData(gChVeye1, aData1[], aBeg, aEnd); 'data ChanData(gChVeye2, aData2[], aBeg, aEnd); 'data ArrSub(aData1[], aData2[]); ChanWriteWave(gChMemVeyeVergence, aData1[], gLastProcessRectVel); endif 'MEMORY: shutters on/off display '----------------------- if gLastMode% = kMemory then ShutterDisplay(aBeg, aEnd, aDataLength%); endif 'if gLastMode% = kMemory gLastProcessRectVel := aCurrentTime; endif end 'TimeToUpdateMemChan '---------------------------------------------------- ' ShutterDisplay ' 'Shows a smudged trace when a shutter is open and a 'thin trace when the shutter is closed. Does this 'for target1 and target2. '6/9/05 '---------------------------------------------------- proc ShutterDisplay(aBeg, aEnd, aDataLength%) var i,aN, aF, aMin, aData7[aDataLength%], aDataStart%, aData8[aDataLength%]; for i := 0 to aDataLength%-1 do if gLastRedShutterMarker = 0 then aData7[i] := gLastRedShutterMarker; else aData7[i] := gLastRedShutterMarker * gRedShutterMultiplier; gRedShutterMultiplier := gRedShutterMultiplier * -1; endif next aN := 0; aF := 0; aMin := aBeg; 'search for multiple .F and .N events up to an endpoint while ((aN > -1) or (aF > -1)) and (aMin <= aEnd) do aN := NextTime(gChShutter1on, aMin); aF := NextTime(gChShutter1off, aMin); if aN > aEnd then aN := -1; endif if aF > aEnd then aF := -1; endif if aN > 0 and aF > 0 then if aN <= aF then aF := -1; else aN := -1; endif endif docase case aN > 0 then aMin := aN; aDataStart% := (aN - aBeg) * 1000; gLastRedShutterMarker := 1; for i := aDataStart% to aDataLength%-1 do 'change trace to aEnd to ON level aData7[i] := gLastRedShutterMarker * gRedShutterMultiplier; gRedShutterMultiplier := gRedShutterMultiplier * -1; next case aF > 0 then aMin := aF; aDataStart% := (aF - aBeg) * 1000; gLastRedShutterMarker := 0; for i := aDataStart% to aDataLength%-1 do 'change trace to aEnd to OFF level aData7[i] := gLastRedShutterMarker; next endcase wend ChanWriteWave(gChShutter1status, aData7[], gLastProcessRectVel); for i := 0 to aDataLength%-1 do if gLastGrnShutterMarker = 0 then aData8[i] := gLastGrnShutterMarker; else aData8[i] := gLastGrnShutterMarker * gGrnShutterMultiplier; gGrnShutterMultiplier := gGrnShutterMultiplier * -1; endif next aN := 0; aF := 0; aMin := aBeg; 'search for multiple .f and .n events up to an endpoint while ((aN > -1) or (aF > -1)) and (aMin <= aEnd) do aN := NextTime(gChShutter2on, aMin); aF := NextTime(gChShutter2off, aMin); if aN > aEnd then aN := -1; endif if aF > aEnd then aF := -1; endif if aN > 0 and aF > 0 then if aN <= aF then aF := -1; else aN := -1; endif endif docase case aN > 0 then aMin := aN; aDataStart% := (aN - aBeg) * 1000; gLastGrnShutterMarker := 1; for i := aDataStart% to aDataLength%-1 do 'change trace to aEnd to ON level aData8[i] := gLastGrnShutterMarker * gGrnShutterMultiplier; gGrnShutterMultiplier := gGrnShutterMultiplier * -1; next case aF > 0 then aMin := aF; aDataStart% := (aF - aBeg) * 1000; gLastGrnShutterMarker := 0; for i := aDataStart% to aDataLength%-1 do 'change trace to aEnd to OFF level aData8[i] := gLastGrnShutterMarker; next endcase wend ChanWriteWave(gChShutter2status, aData8[], gLastProcessRectVel); end 'ShutterDisplay '---------------------------------------------------- ' Report ' 'Give the user some feedback about the points shown. '1/24/02 '---------------------------------------------------- proc Report() var f$,j%, m$,t$; var aTable%[kTableSize%]; ' View(LogHandle()); 'Make log view the current view ' EditSelectAll(); 'Select all text in log view ' EditClear(); 'Delete it ' f$ := "FILE: " + gFilename$; docase case gLastMode% = kCalibrate then m$ := "MODE: Calibrate "; case gLastMode% = kXY then m$ := "MODE: XY "; t$ := "Times all points shown: " + str$(SampleSeqVar(sHITTYPE1)); case gLastMode% = kRadial then m$ := "MODE: Radial "; t$ := "Times all points shown: " + str$(SampleSeqVar(sHITTYPE1)); case gLastMode% = kSine then m$ := "MODE: Sine "; case gLastMode% = kStatic then m$ := "MODE: Static "; 't$ := "Collision latency: " + str$( pCollisionLatency / 100) + " ms"; case gLastMode% = kAdapt then m$ := "MODE: Adapt "; t$ := "Adapt: " + str$(SampleSeqVar(sHITTYPE1)) + " NonAdapt: " + str$(SampleSeqVar(sHITTYPE2)); case gLastMode% = kMemory then m$ := "MODE: Memory "; t$ := "Adapt: " + str$(SampleSeqVar(sHITTYPE1)) + " NonAdapt: " + str$(SampleSeqVar(sHITTYPE2)); case gLastMode% = kRamp then m$ := "MODE: StepRamp "; t$ := "Ramps: " + str$(SampleSeqVar(sHITTYPE1)) + " StepRamps: " + str$(SampleSeqVar(sHITTYPE2)); SampleSeqTable(aTable%,0,1); 'GET table data for j% := 0 to 7 do if aTable%[kTableRampCounters%+j%] > 0 then t$ := t$ + " " + str$(pRampAngle[j%]) + "-Deg: " + str$(aTable%[kTableRampCounters%+j%]); endif next endcase ' View(LogHandle()); 'Make log view the current view ' Print(m$ + "\n"); ' Print(f$ + "\n"); ' Print(t$ + "\n"); View(gDataWindow%); windowTitle$(m$ + " " + f$ + " " + t$); end 'Report '---------------------------------------------------- ' TimeToProcessSpotScope ' 'This manages the spot scope in the way it reflects 'if the shutters are open or closed. The spots are 'large when the shutter is open and small when the 'shutter is closed ' '4/19/05 '---------------------------------------------------- proc TimeToProcessSpotScope(aCurrentTime) var aRedState, aGrnState; if gLastProcessSpot + kSpotInterval < aCurrentTime then 'time to check spot shutter status? gLastProcessSpot := aCurrentTime; if ViewKind(gSpotWindow%) >= 0 then 'only if the spot scope is visible View(gSpotWindow%); aRedState := SampleSeqVar(sSHUT1); if aRedState <> gLastRedState then gLastRedState := aRedState; if aRedState = 1 then XYDrawMode(1,2,kSpotLg%); 'red spot large, shutter open else XYDrawMode(1,2,kSpotSm%); 'red spot small, shutter closed endif endif if gMultiTargets = kTrue then aGrnState := SampleSeqVar(sSHUT2); if aGrnState <> gLastGrnState then gLastGrnState := aGrnState; if aGrnState = 1 then XYDrawMode(3,2,kSpotLg%); 'green spot large, shutter open else XYDrawMode(3,2,kSpotSm%); 'green spot small, shutter closed endif endif endif endif endif end 'TimeToProcessSpotScope '---------------------------------------------------- ' TimeToPlot '4/15/03 '---------------------------------------------------- proc TimeToPlot() var aCode%[4], aTime; if viewkind(gDataWindow%) >= 0 then '4/5/06 an attempt to avoid problems in the transition when switching between modes CollisionPlotting(); View(gDataWindow%); 'printlog("searchin' at ", gLastOnLineTime); aTime := NextTime(gChEvents, gLastOnLineTime, aCode%[]); 'find next target step on ch32, the event channel if (aTime > 0) then if MaxTime() - aTime > 3.00 then 'three seconds from edge of data if (aCode%[0] = 1) then 'MARK 1 (.01) only NextSaccadeAnalysis(aTime); endif if (aCode%[0] = 47) then 'MARK 47 (./) only NextStimAnalysis(aTime); endif gLastOnLineTime := aTime + 0.00001; 'remember this time plus a little bit to avoid finding same location multiple times endif endif endif end 'TimeToPlot '---------------------------------------------------- ' NextStimAnalysis ' 'On-line analysis plots '10/7/03 '---------------------------------------------------- proc NextStimAnalysis(aTime) var i%, bTime, aHEsize, aVEsize, aPolarEyeRadius, aPolarEyeTheta, aEyeValid, Xavg[kAvgCount+10], Yavg[kAvgCount+10], aNumPoints, aPosDirEyeMove, aTime$; aTime$ := print$("%8.1f",aTime); aEyeValid := MeasureSaccade(aTime, aHEsize, aVEsize, bTime); 'find saccade step if (aEyeValid = kTrue) then XY2Radial(aHEsize, aVEsize, 0, 0, aPolarEyeRadius, aPolarEyeTheta); 'pos step or neg step? if (aPolarEyeTheta > 90) and (aPolarEyeTheta <= 270) then aPosDirEyeMove := kFalse; else aPosDirEyeMove := kTrue; endif i% := kMaxPlots%+kMaxBinPlots%+kEvokedPlots%-1; 'Evoked Saccade Size vs. Stimulate Number '-9--------------------------------------------------- 'if ViewKind(gAnalHandle%[i%]) >= 0 then if ViewKind(gAnalHandle%[i%]) = 12 then View(gAnalHandle%[i%]); if aPosDirEyeMove = kTrue then gAnalNpos[i%] := gAnalNpos[i%] + 1; XYAddData(1, gAnalNpos[i%], aPolarEyeRadius); 'plot gain vs. POSITIVE saccade num 'plot next average data point if (gAnalNpos[i%] mod kAvgCount) = 0 then aNumPoints := XYGetData(1,Xavg[],Yavg[],gAnalNpos[i%] - kAvgCount, gAnalNpos[i%]); gAnalAvePos[i%] := ArrSum(Yavg[:aNumPoints]) / aNumPoints; XYAddData(3, gAnalNpos[i%], gAnalAvePos[i%]); endif; else gAnalNneg[i%] := gAnalNneg[i%] + 1; XYAddData(2, gAnalNneg[i%], aPolarEyeRadius); 'plot gain vs. NEGATIVE saccade num 'plot next average data point if (gAnalNneg[i%] mod kAvgCount) = 0 then aNumPoints := XYGetData(2,Xavg[],Yavg[], gAnalNneg[i%] - kAvgCount, gAnalNneg[i%]); gAnalAveNeg[i%] := ArrSum(Yavg[:aNumPoints]) / aNumPoints; XYAddData(4, gAnalNneg[i%], gAnalAveNeg[i%]); endif; endif 'TitleEvokedSaccadeStimNumber(); TitleSet(i%); View(LogHandle()).Print("Analysis: " + aTime$ + " Evoked Saccade Size v Stimulate Number for " + str$(aPolarEyeTheta) + "\n"); endif 'if ViewKind(gAnalHandle%[i%]) >= 0 else View(LogHandle()).Print("Analysis: " + aTime$ + " Rejected (stim) - Invalid eye movement for " + "\n"); '+ str$(aPolarEyeTheta) + "\n"); endif 'aEyeValid = kTrue end 'NextStimAnalysis '---------------------------------------------------- ' NextSaccadeAnalysis ' 'On-line analysis plots '8/17/06 '---------------------------------------------------- proc NextSaccadeAnalysis(aTime) var aTime$, bTime, aStatus$, aReason$, aHTsize, aVTsize, aHEsize, aVEsize, aPolarGain := kNAN, aPolarTargetRadius, aPolarTargetTheta, aPolarEyeRadius, aPolarEyeTheta, aHistoBinData%[kHistoSize%], aVector%, aFreqArray[kHistoSize%], aXData[2],aYData[2], aTargValid,aEyeValid, Xavg[kAvgCount+10], Yavg[kAvgCount+10], aNumPoints, aNum%, aBeg, aEnd, aTraceData[8], avgHEpos,avgVEpos, avgHTpos,avgVTpos, aHerror,aVerror,aPolarError, aReaction, aPosDirTarMove%, aDuration, i%,j%,k%, aSingleHistogramPlot%, aX1,aX2,aX3,aX4, aY1,aY2,aY3,aY4, aSacNumTrue%, aYctr%, aXh; aTime$ := print$("%8.1f",aTime); 'proceed if there was a valid target movement and a valid saccade aTargValid := MeasureTarget(aTime, aHTsize, aVTsize); 'find target step aEyeValid := MeasureSaccade(aTime, aHEsize, aVEsize, bTime); 'find saccade step if (aTargValid = kTrue) then if (aEyeValid = kTrue) then 'divide by zero protection XY2Radial(aHTsize, aVTsize, 0, 0, aPolarTargetRadius, aPolarTargetTheta); 'pos step or neg step? XY2Radial(aHEsize, aVEsize, 0, 0, aPolarEyeRadius, aPolarEyeTheta); 'pos step or neg step? if aPolarTargetRadius <> 0 then 'divide by zero protection 'compare filter gain setting? aPolarGain := aPolarEyeRadius/aPolarTargetRadius; if (aPolarGain >= pMinGain) then if (aPolarGain <= pMaxGain) then 'user-entered choice 'compare filter direction if (aPolarTargetRadius >= pMinTargAmp) then if (aPolarTargetRadius <= pMaxTargAmp) then 'user-entered choice 'compare filter theta error if (ThetaDifference(aPolarTargetTheta, aPolarEyeTheta) <= pMaxThetaError) then 'user-entered choice '+ valid trial now, compute remaing attributes + '------------------------------------------- aDuration := gHistoLatestOffset - gHistoEarliestOnset; aReaction := (bTime - aTime) * 1000.0; 'convert to ms 'used by HISTOGRAM and COMPLEX aVector% := round(aPolarEyeTheta/45); 'determine which way the animal moved so we know which plot to add the data to if aVector% = 8 then aVector% := 0; '360° is the same as 0° endif if (aPolarTargetTheta > 90) and (aPolarTargetTheta <= 270) then aPosDirTarMove% := kFalse; else aPosDirTarMove% := kTrue; endif '+++++ Error aBeg := bTime + gErrorSampleLO / 1000; '0.050; aEnd := bTime + gErrorSampleHI / 1000; '0.050 + 0.008; 'average 8 ms of time View(gDataWindow%); aNum% := ChanData(gChHeye1, aTraceData[], aBeg, aEnd); avgHEpos := ArrSum(aTraceData[:aNum%]) / aNum%; 'get average H eye pos aNum% := ChanData(gChHtarg1, aTraceData[], aBeg, aEnd); avgHTpos := ArrSum(aTraceData[:aNum%]) / aNum%; 'get average H tar pos aNum% := ChanData(gChVeye1, aTraceData[], aBeg, aEnd); avgVEpos := ArrSum(aTraceData[:aNum%]) / aNum%; 'get average V eye pos aNum% := ChanData(gChVtarg1, aTraceData[], aBeg, aEnd); avgVTpos := ArrSum(aTraceData[:aNum%]) / aNum%; 'get average V tar pos aHerror := avgHTpos - avgHEpos; aVerror := avgVTpos - avgVEpos; aPolarError := sqrt((aHerror * aHerror) + (aVerror * aVerror)); if aPosDirTarMove% = kFalse then aPolarError := -(aPolarError); endif '----- Error '------------------------------------------- '- valid trial now, compute remaing attributes - '0 skip '1 Horz Eye and Targ Amp '2 Saccade Number '3 Polar Amp '4 Polar Gain '5 Polar Saccade Error '6 Polar Target Step Size '7 Polar Target Theta '8 Reaction Time '9 Saccade Duration '10 Vert eye and tar Amp '11 Horz Eye Amp '12 Vert Eye Amp '13 Horz Targ Amp '14 Vert Targ Amp '+ Add attribute data to EACH plot, if present + '------------------------- ' for j% := 0 to kMaxPlots%-1 do for j% := 0 to kMaxPlots%+kMaxBinPlots%-1 do 'if ViewKind(gAnalHandle%[j%]) >= 0 then if ViewKind(gAnalHandle%[j%]) = 12 then View(gAnalHandle%[j%]); '+ initial var that each plot use + '---------------------------------- aX1 := kNaN; aX2 := kNaN; aY1 := kNaN; aY2 := kNaN; aSingleHistogramPlot% := kFalse; gAnalN[j%] := gAnalN[j%] + 1; 'inc the number of saccades for this plot if aPosDirTarMove% = kTrue then gAnalNpos[j%] := gAnalNpos[j%] + 1; else gAnalNneg[j%] := gAnalNneg[j%] + 1; endif '- initial var that each plot use - '---------------------------------- aSacNumTrue% := gAnalXattr[j%] or gAnalYattr[j%]; '+ prepare the X-value(s) + '--------------------- docase case gAnalXattr[j%] = 0 then ; 'no choice made so skip it case gAnalXattr[j%] = 1 then 'Horz Eye and Targ Amp aX1 := aHEsize; aX2 := aHTsize; case gAnalXattr[j%] = 2 then 'Saccade Number if aPosDirTarMove% = kTrue then 'pos dir LoadTheChannels(gAnalNpos[j%],aSacNumTrue%,aPosDirTarMove%,aX1,aX2); if (gAnalNpos[j%] mod kAvgCount) = 0 then aX3 := gAnalNpos[j%]; endif else 'neg dir LoadTheChannels(gAnalNneg[j%],aSacNumTrue%,aPosDirTarMove%,aX1,aX2); if (gAnalNneg[j%] mod kAvgCount) = 0 then aX4 := gAnalNneg[j%]; endif endif case gAnalXattr[j%] = 3 then 'Polar Amp aX1 := aPolarEyeRadius; case gAnalXattr[j%] = 4 then 'Polar Gain LoadTheChannels(aPolarGain,aSacNumTrue%,aPosDirTarMove%,aX1,aX2); LoadTheAvgChannels(j%,aSacNumTrue%,aPosDirTarMove%,kTrue,aX3,aX4); case gAnalXattr[j%] = 5 then 'Polar Saccade Error if gAnalYattr[j%] = 0 then LoadSingleHistogram(j%,gAnalParamOne[j%],aPolarError,aPosDirTarMove%); aSingleHistogramPlot% := kTrue; else LoadTheChannels(aPolarError,aSacNumTrue%,aPosDirTarMove%,aX1,aX2); LoadTheAvgChannels(j%,aSacNumTrue%,aPosDirTarMove%,kFalse,aX3,aX4); endif case gAnalXattr[j%] = 6 then 'Polar Target Step Size if aHTsize >= 0 then aX1 := aPolarTargetRadius; else aX1 := -aPolarTargetRadius; endif case gAnalXattr[j%] = 7 then 'Polar Target Theta aX1 := aPolarTargetTheta; case gAnalXattr[j%] = 8 then 'Reaction Time if gAnalYattr[j%] = 0 then LoadSingleHistogram(j%,gAnalParamOne[j%],aReaction,aPosDirTarMove%); aSingleHistogramPlot% := kTrue; else LoadTheChannels(aReaction,aSacNumTrue%,aPosDirTarMove%,aX1,aX2); LoadTheAvgChannels(j%,aSacNumTrue%,aPosDirTarMove%,kFalse,aX3,aX4); endif case gAnalXattr[j%] = 9 then 'Saccade Duration aX1 := aDuration; case gAnalXattr[j%] = 10 then 'Vert eye and tar Amp aX1 := aVEsize; aX2 := aVTsize; case gAnalXattr[j%] = 11 then 'Horz Eye Amp aX1 := aHEsize; case gAnalXattr[j%] = 12 then 'Vert Eye Amp aX1 := aVEsize; case gAnalXattr[j%] = 13 then 'Horz Targ Amp aX1 := aHTsize; case gAnalXattr[j%] = 14 then 'Vert Targ Amp aX1 := aVTsize; endcase '--------------------- '- prepare the X-value(s) - '+ prepare the Y-value(s) + '--------------------- docase case gAnalYattr[j%] = 0 then ; 'no choice made so skip it case gAnalYattr[j%] = 1 then 'Horz Eye/Targ Amp aY1 := aHEsize; aY2 := aHTsize; case gAnalYattr[j%] = 2 then 'Saccade Number if aPosDirTarMove% = kTrue then 'pos dir LoadTheChannels(gAnalNpos[j%],aSacNumTrue%,aPosDirTarMove%,aY1,aY2); if (gAnalNpos[j%] mod kAvgCount) = 0 then aY3 := gAnalNpos[j%]; endif else 'neg dir LoadTheChannels(gAnalNneg[j%],aSacNumTrue%,aPosDirTarMove%,aY1,aY2); if (gAnalNneg[j%] mod kAvgCount) = 0 then aY4 := gAnalNneg[j%]; endif endif case gAnalYattr[j%] = 3 then 'Polar Amp 'aY1 := aPolarEyeRadius; LoadTheChannels(aPolarEyeRadius,aSacNumTrue%,aPosDirTarMove%,aY1,aY2); LoadTheAvgChannels(j%,aSacNumTrue%,aPosDirTarMove%,kFalse,aY3,aY4); case gAnalYattr[j%] = 4 then 'Polar Gain LoadTheChannels(aPolarGain,aSacNumTrue%,aPosDirTarMove%,aY1,aY2); LoadTheAvgChannels(j%,aSacNumTrue%,aPosDirTarMove%,kFalse,aY3,aY4); 'SAVE - not a valid Y-axis attribute case gAnalYattr[j%] = 5 then 'Polar Saccade Error if aSingleHistogramPlot% = kTrue then 'do nothing else LoadTheChannels(aPolarError,aSacNumTrue%,aPosDirTarMove%,aY1,aY2); LoadTheAvgChannels(j%,aSacNumTrue%,aPosDirTarMove%,kFalse,aY3,aY4); endif case gAnalYattr[j%] = 6 then 'Polar Target Step Size if aHTsize >= 0 then aY1 := aPolarTargetRadius; else aY1 := -aPolarTargetRadius; endif case gAnalYattr[j%] = 7 then 'Polar Target Theta aY1 := aPolarTargetTheta; 'SAVE - not a valid Y-axis attribute case gAnalYattr[j%] = 8 then 'Reaction Time if aSingleHistogramPlot% = kTrue then 'do nothing else LoadTheChannels(aReaction,aSacNumTrue%,aPosDirTarMove%,aY1,aY2); LoadTheAvgChannels(j%,aSacNumTrue%,aPosDirTarMove%,kFalse,aY3,aY4); endif case gAnalYattr[j%] = 9 then 'Saccade Duration 'aY1 := aDuration; LoadTheChannels(aDuration,aSacNumTrue%,aPosDirTarMove%,aY1,aY2); LoadTheAvgChannels(j%,aSacNumTrue%,aPosDirTarMove%,kFalse,aY3,aY4); case gAnalYattr[j%] = 10 then 'Vert eye/tar Amp aY1 := aVEsize; aY2 := aVTsize; case gAnalYattr[j%] = 11 then 'Horz Eye Amp aY1 := aHEsize; case gAnalYattr[j%] = 12 then 'Vert Eye Amp aY1 := aVEsize; case gAnalYattr[j%] = 13 then 'Horz Targ Amp aY1 := aHTsize; case gAnalYattr[j%] = 14 then 'Vert Targ Amp aY1 := aVTsize; endcase '--------------------- '+ prepare the Y-value(s) + if aSingleHistogramPlot% = kTrue then ; 'taken care of with a subroutine else 'STANDARD PLOT '------------- if (aX1 <> kNaN) and (aY1 <> kNaN) then XYAddData(1, aX1, aY1); endif if (aX2 <> kNaN) and (aY2 <> kNaN) then XYAddData(2, aX2, aY2); endif if (aX3 <> kNaN) and (aY3 <> kNaN) then XYAddData(3, aX3, aY3); endif if (aX4 <> kNaN) and (aY4 <> kNaN) then XYAddData(4, aX4, aY4); endif endif TitleSet(j%); View(LogHandle()).Print("Analysis: " + aTime$ + " " + PlotNameGet$(j%) + " " + str$(aPolarEyeTheta) + "\n"); endif next 'for j% '+ Eight Direction Histograms '------------------------- ' Add attribute data to EACH plot, if present '---------------------------------------------------- if gHistoSelect% and (gUnitData > 0) then ArrConst(aHistoBinData%[],0); 'init it with zeros BinSpikes(aHistoBinData%[]); 'load the current trial's spikes gHistoNum%[aVector%] := gHistoNum%[aVector%] + 1; 'increment the number of trials ArrAdd(gHistoData%[][aVector%], aHistoBinData%[]); 'add the new data to the previously collected data ArrConst(aFreqArray[], gHistoData%[][aVector%]); 'ArrConst(aFreqArray[],Hist45Data%[]); ArrDiv(aFreqArray[], gHistoNum%[aVector%]); 'ArrDiv(aFreqArray[],nHist45%); ArrMul(aFreqArray[], kMS/gHistoBin); 'This should be in Hertz ' Update display if ViewKind(gHistoHandle%[aVector%]) >= 0 then View(gHistoHandle%[aVector%]); 'LastView%:=View(gHisto45%); ' delete old data XYDelete(1); 'delete the old histogram ' put new array data like a real histogram aYctr% := 0; for aXh := gHistoStart to gHistoEnd step gHistoBin do aXData[0] := aXh; aXData[1] := aXh + gHistoBin; aYData[0] := aFreqArray[aYctr%]; aYData[1] := aFreqArray[aYctr%]; XYAddData(1, aXData[], aYData[]); 'add new set of data points aYctr% := aYctr% + 1; next; TitleHistogram(aVector%); View(LogHandle()).Print("Analysis: " + aTime$ + " Plotted histogram for " + str$(aPolarEyeTheta) + "\n"); endif endif '- Eight Direction Histograms 'Eight Direction Complex Spikes '---------------------------------------------------- 'This will collect data until each direction has amassed '50 trials if gComplexSelect% and (gUnitData > 0) then if gNumCS%[aVector%] < 50 then 'enter until 50 trials have been collected for EACH vector gNumCS%[aVector%] := gNumCS%[aVector%] + 1; var aTimeZero, aMaxLoc%, aMinLoc%, aMaxVal, aMinVal, aDirOffset%, a%, aTemp[10001]; if gComplexAlignment% = 0 then aTimeZero := gHistoEarliestOnset; else aTimeZero := gHistoLatestOffset; endif; View(gDataWindow%); ChanData(gChUnit, aTemp[], aTimeZero, aTimeZero + 0.2); 'grab 200ms of data aMinLoc% := Min(aTemp[]); 'find location of minimum data aMinVal := aTemp[aMinLoc%]; 'store minimum value ArrSub(aTemp[], aMinVal); 'offset all data by that amount (make >= 0) aMaxLoc% := Max(aTemp[]); 'find location of maximum data aMaxVal := aTemp[aMaxLoc%]; 'store maximum value ArrDiv(aTemp[], aMaxVal * 0.9); 'normalized (make <= 1) aDirOffset% := aVector% * 50; 'direction offset a% := aDirOffset% + gNumCS%[aVector%]-1; 'direction offset + trace num for direction ArrConst(gComplexSpikes[][a%], aTemp[]); 'fill the place in array endif endif '+ XY Saccade Tragectories '------------------------- if gTragectorySelect% then var aLength, aEarly, aLate; aEarly := gHistoEarliestOnset; aLate := gHistoLatestOffset; aLength := ((gHistoLatestOffset+0.020)-(gHistoEarliestOnset-0.020))*1000; var aTragectoryXData[aLength+1], aTragectoryYData[aLength+1]; gTragectoryN := gTragectoryN + 1; View(gDataWindow%); ChanData(gChHeye1, aTragectoryXData[], gHistoEarliestOnset-0.020, gHistoLatestOffset+0.020); 'grab 200ms of data ChanData(gChVeye1, aTragectoryYData[], gHistoEarliestOnset-0.020, gHistoLatestOffset+0.020); 'grab 200ms of data ArrSub(aTragectoryXData[],aTragectoryXData[0]); ArrSub(aTragectoryYData[],aTragectoryYData[0]); if viewkind(gTragectoryHandle%) >= 0 then View(gTragectoryHandle%); XYAddData(1, aTragectoryXData[], aTragectoryYData[]); 'add new set of data points TitleSetTragectory(); endif endif '+ XY Saccade Tragectories else View(LogHandle()).Print("Analysis: " + aTime$ + " Rejected - Saccaded in wrong direction [" + str$(aPolarTargetTheta) + " <= " + str$(pMaxThetaError) + "] for " + str$(aPolarEyeTheta) + "\n"); endif 'ThetaDifference(aPolarTargetTheta, aPolarEyeTheta) =< pMaxThetaError else View(LogHandle()).Print("Analysis: " + aTime$ + " Rejected - Target radius too large [" + str$(aPolarTargetRadius) + " => " + str$(pMinTargAmp) + "] for " + str$(aPolarEyeTheta) + "\n"); endif 'aPolarTargetRadius <= pMaxTargAmp else View(LogHandle()).Print("Analysis: " + aTime$ + " Rejected - Target radius too small [" + str$(aPolarTargetRadius) + " <= " + str$(pMinTargAmp) + "] for " + str$(aPolarEyeTheta) + "\n"); endif 'aPolarTargetRadius >= pMinTargAmp else View(LogHandle()).Print("Analysis: " + aTime$ + " Rejected - Gain too large [" + str$(aPolarGain) + " => " + str$(pMinGain) + "] for " + str$(aPolarEyeTheta) + "\n"); endif 'aPolarGain <= pMaxGain else View(LogHandle()).Print("Analysis: " + aTime$ + " Rejected - Gain too small [" + str$(aPolarGain) + " <= " + str$(pMinGain) + "] for " + str$(aPolarEyeTheta) + "\n"); endif 'aPolarGain >= pMinGain endif 'aPolarTargetRadius <> 0 else View(LogHandle()).Print("Analysis: " + aTime$ + " Rejected - Invalid eye movement for " + "\n"); '+ str$(aPolarEyeTheta) + "\n"); endif 'aEyeValid = kTrue else View(LogHandle()).Print("Analysis: " + aTime$ + " Rejected - Invalid (0 deg step?) target movement for " + "\n"); '+ str$(aPolarEyeTheta) + "\n"); endif 'aTargValid = kTrue end 'NextSaccadeAnalysis '---------------------------------------------------- ' LoadSingleHistogram ' '9/1/06 '---------------------------------------------------- proc LoadSingleHistogram(j%,aBinSz,aValue,aPosDirTarMove%); var i%, aIndex%, aHalfSize; View(gAnalHandle%[j%]); gAnalXlo%[j%] := XLow(); 'get the range set by the user gAnalXhi%[j%] := XHigh(); aHalfSize := (kGenHistoArraySize%-1)/2; if gAnalXlo%[j%] < -aHalfSize * aBinSz then 'keep plot no bigger than available data gAnalXlo%[j%] := -aHalfSize * aBinSz; endif if gAnalXhi%[j%] > aHalfSize * aBinSz then gAnalXhi%[j%] := aHalfSize * aBinSz; endif if aBinSz <> 0 then 'does the data fit in the averaging array aIndex% := round(aValue / aBinSz) + aHalfSize; 'clump into 10ms bins if (aIndex% >= 0) and (aIndex% <= kGenHistoArraySize%-1) then if aPosDirTarMove% then gGenHistoArrayPos[aIndex%] := gGenHistoArrayPos[aIndex%] + 1; gAnalPosAccum[j%] := gAnalPosAccum[j%] + aValue; '10/11/06 gAnalNpos[j%] := gAnalNpos[j%] + 1; XYDelete(1); for i% := 0 to kGenHistoArraySize%-1 do XYAddData(1, (i% - aHalfSize) * aBinSz, gGenHistoArrayPos[i%]); next else gGenHistoArrayNeg[aIndex%] := gGenHistoArrayNeg[aIndex%] + 1; gAnalNegAccum[j%] := gAnalNegAccum[j%] + aValue; '10/11/06 gAnalNneg[j%] := gAnalNneg[j%] + 1; XYDelete(2); for i% := 0 to kGenHistoArraySize%-1 do XYAddData(2, (i% - aHalfSize) * aBinSz, gGenHistoArrayNeg[i%]); next endif 'report the average of the last 25 POSITIVE points if ((gAnalNpos[j%] mod kAvgCount) = 0) and (gAnalPosAccum[j%] <> 0) then gAnalAvePos[j%] := gAnalPosAccum[j%] / kAvgCount; gAnalPosAccum[j%] := 0; endif 'report the average of the last 25 NEGATIVE points if ((gAnalNneg[j%] mod kAvgCount) = 0) and (gAnalNegAccum[j%] <> 0) then gAnalAveNeg[j%] := gAnalNegAccum[j%] / kAvgCount; gAnalNegAccum[j%] := 0; endif XRange(gAnalXlo%[j%], gAnalXhi%[j%]); endif endif end 'LoadSingleHistogram '---------------------------------------------------- ' LoadTheChannels ' 'Loads data into the channel(s) depending on whether 'we are plotting +/- direction or not '8/30/06 '---------------------------------------------------- proc LoadTheChannels(aValue,aSacNumTrue%,aPosDirTarMove%,&aCh,&bCh) aCh := kNaN; bCh := kNaN; if aSacNumTrue% = kTrue then if aPosDirTarMove% = kTrue then aCh := aValue; else bCh := aValue; endif else aCh := aValue; endif end 'LoadTheChannels '---------------------------------------------------- ' LoadTheAvgChannels ' 'Load data after computing the average when plotting '+/- directions '8/31/06 '---------------------------------------------------- proc LoadTheAvgChannels(j%,aSacNumTrue%,aPosDirTarMove%,aAvgX%,&aCh,&bCh) var Xavg[kAvgCount+10], Yavg[kAvgCount+10], aNumPoints; aCh := kNaN; bCh := kNaN; if aSacNumTrue% = kTrue then if aPosDirTarMove% = kTrue then if (gAnalNpos[j%] mod kAvgCount) = 0 then aNumPoints := XYGetData(1,Xavg[],Yavg[],gAnalNpos[j%] - kAvgCount, gAnalNpos[j%]); if aNumPoints > 0 then '9/8/06 if aAvgX% = kTrue then gAnalAvePos[j%] := ArrSum(Xavg[:aNumPoints]) / aNumPoints; 'average X axis, pos dir else gAnalAvePos[j%] := ArrSum(Yavg[:aNumPoints]) / aNumPoints; 'average Y axis, pos dir endif aCh := gAnalAvePos[j%]; endif endif; else if (gAnalNneg[j%] mod kAvgCount) = 0 then aNumPoints := XYGetData(2,Xavg[],Yavg[], gAnalNneg[j%] - kAvgCount, gAnalNneg[j%]); PrintLog("aNumPoints = ",aNumPoints, " j% = ", j%); if aNumPoints > 0 then '9/8/06 if aAvgX% = kTrue then gAnalAveNeg[j%] := ArrSum(Xavg[:aNumPoints]) / aNumPoints; 'average X axis, neg dir else gAnalAveNeg[j%] := ArrSum(Yavg[:aNumPoints]) / aNumPoints; 'average Y axis, neg dir endif bCh := gAnalAveNeg[j%]; endif endif; endif endif end 'LoadTheAvgChannels '---------------------------------------------------- ' ThetaDifference '5/30/06 '---------------------------------------------------- func ThetaDifference(aTheta, bTheta) var cTheta, dTheta, aDiff, bDiff, cDiff, dDiff; cTheta := aTheta + 360; 'add 360 to deal with theta at the 0/360 degree boundry dTheta := bTheta + 360; aDiff := abs(aTheta - bTheta); 'compute all of them bDiff := abs(aTheta - dTheta); cDiff := abs(cTheta - bTheta); dDiff := abs(cTheta - dTheta); return min(aDiff, bDiff, cDiff, dDiff); 'the smallest is the one we are interested in end 'ThetaDifference '---------------------------------------------------- ' CollisionPlotting '4/28/06 '---------------------------------------------------- proc CollisionPlotting() var aCurrentTime, aMoveNow, aLatency, aMode, aHiDur, aLoDur, aDeadTime, aFreq, a,i, aDataX[(pStimBefore + pStimAfter) * gSamplesPerMS + 1], aDataY[(pStimBefore + pStimAfter) * gSamplesPerMS + 1], aDataXdel[(pStimBefore + pStimAfter) * gSamplesPerMS + 1], aDataYdel[(pStimBefore + pStimAfter) * gSamplesPerMS + 1], aTime, aCode%[4], aStr$, aResult; ' 'enter if the user has made a change ' if gChangeParam = 1 then ' gChangeParam := 0; ' gCollisionN := 0; ' ' 'divide by zero protection ' if aHiDur + aLoDur = 0 then ' aFreq := 0; ' else ' aFreq := (1/(aHiDur+aLoDur)) * 1000; ' endif ' ' LogUpdate(); ' ' View(gDataPlot%); ' gCollisionPlotLast := Maxtime(); ' if gCollisionPlotLast < 1.000 then ' gCollisionPlotLast := 1.000; ' endif ' ' WindowRange(gCollisionWindow%); ' ResetPlotCollision%(); 'erase the plot ' endif 'skip when there is no collision plot is available if (ViewKind(gCollisionWindow%) >= 0) and (SampleSeqVar(8) > 0) then View(gDataWindow%); 'exclude events too close to the right side of the screen if gCollisionPlotLast < MaxTime() - 2.00 then 'must protect gCollisionPlotLast from creeping past MaxTime aTime := NextTime(gChEvents, gCollisionPlotLast, aCode%[]); 'find the next event marker 'skip if no event marker was found if (aTime > 0) and (aTime < MaxTime()) then '(aTime > gCollisionPlotLast) and 'skip unless a marker representing stimulation was found 'line up on .S in Search Mode 'line up on .T in Collision Mode if aCode%[0] = 47 then ' if ((SampleSeqVar(8)=0) and (aCode%[0] = 83)) or ((SampleSeqVar(8)=1) and (aCode%[0] = 84)) then gCollisionN := gCollisionN + 1; 'count the events found 'Prepare to get 10ms of data on either side of zero plus zero. 'At 100kHz, that is 1000+1000+1 data points View(gCollisionWindow%); a := -pStimBefore/1000; for i := 0 to (pStimBefore+pStimAfter)*gSamplesPerMS do '50kHz, was 100kHz aDataX[i] := a; ' a := a + 0.00001; 'the interval in seconds at 100kHz a := a + 0.00002; 'the interval in seconds at 100kHz next 'in search mode, only store/plot 5 traces if (SampleSeqVar(8) = 1) and (gCollisionN > 5) then XYdelete(1,0,(pStimBefore+pStimAfter)*gSamplesPerMS); gCollisionN := gCollisionN - 1; endif View(gDataWindow%); aResult := ChanData(1, aDataY[], aTime-pStimBefore/1000, aTime+pStimAfter/1000); view(gCollisionWindow%); aResult := XYAddData(1, aDataX[], aDataY[]); TitleCollision(); endif gCollisionPlotLast := aTime + 0.0001; 'remember this time endif endif endif ' return kTrue; 'Stay in toolbar end 'CollisionPlotting '---------------------------------------------------- ' PlotNameGet '8/17/06 '---------------------------------------------------- func PlotNameGet$(aPlot%) return gAnalLabelTitle$[gAnalXattr[aPlot%]] + " v " + gAnalLabelTitle$[gAnalYattr[aPlot%]]; end 'PlotNameGet '---------------------------------------------------- ' TitleSet 'Update the information in the title bar in this 'analysis window. It can title regular plots or 'two direction plots. '8/15/06 '---------------------------------------------------- proc TitleSet(aPlot%) var aStr$; if ViewKind(gAnalHandle%[aPlot%]) = 12 then 'if view present view(gAnalHandle%[aPlot%]); docase case (gAnalXattr[aPlot%] = 2) or (gAnalXattr[aPlot%] = 21) then aStr$ := (PlotNameGet$(aPlot%) + " N=" + Str$(-gAnalNneg[aPlot%]) + "/+" + Str$(gAnalNpos[aPlot%]) + " last 25 pt ave=" + Print$("%6.3f",-gAnalAveNeg[aPlot%]) + "/+" + Print$("%6.3f",gAnalAvePos[aPlot%])); case gAnalYattr[aPlot%] = 0 then aStr$ := (PlotNameGet$(aPlot%) + " N=" + Str$(-gAnalNneg[aPlot%]) + "/+" + Str$(gAnalNpos[aPlot%])); else aStr$ := (PlotNameGet$(aPlot%) + " N=" + Str$(gAnalN[aPlot%])); endcase WindowTitle$(aStr$); endif end 'TitleSet '---------------------------------------------------- ' TitleSetTragectory 'Update the information in the title bar in this 'analysis window. It can title regular plots or 'two direction plots. '1/10/07 '---------------------------------------------------- proc TitleSetTragectory() var aStr$; if ViewKind(gTragectoryHandle%) = 12 then 'if view present view(gTragectoryHandle%); aStr$ := ("XY Saccade Tragectory" + " N=" + Str$(gTragectoryN)); WindowTitle$(aStr$); endif end 'TitleSetTragectory '---------------------------------------------------- ' TitlePolarGainStepsize 'Update the information in the title bar in this 'analysis window. '1/30/04 '---------------------------------------------------- proc TitlePolarGainStepsize() var aStr$; View(gAnalHandle%[0]); aStr$ := ("Polar Gain vs Target Step Size N=" + Str$(gAnalN[0])); WindowTitle$(aStr$); end 'TitlePolarGainStepsize '---------------------------------------------------- ' TitlePolarGainSaccadeNumber 'Update the information in the title bar in this 'analysis window. '1/30/04 '---------------------------------------------------- proc TitlePolarGainSaccadeNumber() var aStr$; View(gAnalHandle%[1]); aStr$ := ( "Polar Gain vs Sac Num N=" + Str$(-gAnalNneg[1]) + "/+" + Str$(gAnalNpos[1]) + " last 25 pt ave=" + Print$("%6.3f",-gAnalAveNeg[1]) + "/+" + Print$("%6.3f",gAnalAvePos[1])); WindowTitle$(aStr$); end '---------------------------------------------------- ' TitleSaccadesPolarSaccadeError 'Update the information in the title bar in this 'analysis window. '1/30/04 '---------------------------------------------------- proc TitleSaccadesPolarSaccadeError() var aStr$; View(gAnalHandle%[2]); aStr$ := ( "Sac vs Polar Sac Error N=" + Str$(-gAnalNneg[2]) + "/+" + Str$(gAnalNpos[2]) + " last 25 pt ave=" + Print$("%6.3f",-gAnalAveNeg[2]) + "/+" + Print$("%6.3f",gAnalAvePos[2])); WindowTitle$(aStr$); end '---------------------------------------------------- ' TitleSaccadeReactionTime 'Update the information in the title bar in this 'analysis window. '1/30/04 '---------------------------------------------------- proc TitleSaccadeReactionTime() var aStr$; View(gAnalHandle%[3]); aStr$ := ( "Sac vs Reaction Time N=" + Str$(-gAnalNneg[3]) + "/+" + Str$(gAnalNpos[3]) + " last 25 pt ave=" + Print$("%6.3f",gAnalAveNeg[3]) + "/+" + Print$("%6.3f",gAnalAvePos[3])); WindowTitle$(aStr$); end '---------------------------------------------------- ' TitlePolarAmpSaccadeNumber 'Update the information in the title bar in this 'analysis window. '2/9/05 '---------------------------------------------------- proc TitlePolarAmpSaccadeNumber() var aStr$; View(gAnalHandle%[4]); aStr$ := ( "Polar Amp vs Sac Num N=" + Str$(-gAnalNneg[4]) + "/+" + Str$(gAnalNpos[4]) + " last 25 pt ave=" + Print$("%6.3f",-gAnalAveNeg[4]) + "/+" + Print$("%6.3f",gAnalAvePos[4])); WindowTitle$(aStr$); end 'TitlePolarAmpSaccadeNumber '---------------------------------------------------- ' TitlePolarAmpStepsize 'Update the information in the title bar in this 'analysis window. '2/10/05 '---------------------------------------------------- proc TitlePolarAmpStepsize() var aStr$; View(gAnalHandle%[5]); aStr$ := ("Polar Amp vs Target Step Size N=" + Str$(gAnalN[5])); WindowTitle$(aStr$); end 'TitlePolarAmpStepsize '---------------------------------------------------- ' TitlePolarAmpStepsize 'Update the information in the title bar in this 'analysis window. '2/11/05 '---------------------------------------------------- proc TitlePolarAmpTargetTheta() var aStr$; View(gAnalHandle%[6]); aStr$ := ("Polar Amp vs Target Theta N=" + Str$(gAnalN[6])); WindowTitle$(aStr$); end 'TitlePolarAmpTargetTheta '---------------------------------------------------- ' TitleEyeTargetAmp 'Update the information in the title bar in this 'analysis window. '2/10/05 '---------------------------------------------------- proc TitleEyeTargetAmp() var aStr$; View(gAnalHandle%[7]); aStr$ := ("H Eye & Target Amp vs V Eye & Target Amp N=" + Str$(gAnalN[7])); WindowTitle$(aStr$); end 'TitleEyeTargetAmp '---------------------------------------------------- ' TitleSaccadeDurationSaccadeNumber 'Update the information in the title bar in this 'analysis window. '1/30/04 '---------------------------------------------------- proc TitleSaccadeDurationSaccadeNumber() var aStr$; View(gAnalHandle%[8]); aStr$ := ( "Saccade Dur vs Sac Number N=" + Str$(-gAnalNneg[8]) + "/+" + Str$(gAnalNpos[8]) + " last 25 pt ave=" + Print$("%6.3f",-gAnalAveNeg[1]) + "/+" + Print$("%6.3f",gAnalAvePos[1])); WindowTitle$(aStr$); end 'TitleSaccadeDurationSaccadeNumber '---------------------------------------------------- ' TitleLatencyHistogram 'Update the information in the title bar in this 'analysis window. '1/30/04 '---------------------------------------------------- proc TitleHistogram(aVector%) var aStr$; View(gHistoHandle%[aVector%]); aStr$ := ("Histogram @ " + Str$(aVector% * 45) + " deg N=" + Str$(gHistoNum%[aVector%])); WindowTitle$(aStr$); end 'TitleHistogram '---------------------------------------------------- ' TitleComplex 'Update the information in the title bar in this 'analysis window. '6/7/06 '---------------------------------------------------- 'proc TitleComplex(aVector%) ' var ' aStr$; ' ' View(gComplexHandle%[aVector%]); ' aStr$ := ("Complex @ " + Str$(aVector% * 45) + " deg N=" + Str$(gComplexNum%[aVector%])); ' WindowTitle$(aStr$); 'end 'TitleComplex ' '---------------------------------------------------- ' MeasureSaccade 'Search for a saccade on the velocity channel. Report 'when it began, ended, the time of the peak velocity, 'and the amplitude. '4/16/03 '---------------------------------------------------- func MeasureSaccade(aTime, &aHsize, &aVsize, &aPeakTime) var aBeg, aEnd, aVelBeg, aVelEnd, aValid := kFalse; if (aTime >= 0) then 'only work with valid times View(gDataWindow%); aBeg := aTime + pSaccadeSearchStart; 'earliest time to look before the target for the peak velocity aEnd := aTime + pSaccadeSearchEnd; 'latest time to look after the target for the peak velocity if (aBeg >= 0) and (aEnd <= MaxTime()) then 'the saccade must be valid and completely take place in the file aPeakTime := ChanSearch(gChMemRectVel, 4, aBeg, aEnd, pMinSaccadicVelocity); 'search forward for the first peak exceeding a threshold if (aPeakTime >= 0) then 'only work with valid times aVelBeg := ChanSearch(gChMemRectVel, 8, aPeakTime, 0, pOnsetVelocity); 'search backward for falling threshold aVelEnd := ChanSearch(gChMemRectVel, 8, aPeakTime, MaxTime(), pOffsetVelocity); 'search forward for falling threshold if (aVelBeg >= 0) and (aVelEnd >= 0) then 'must find a valid beginning and a valid end aValid := kTrue; 'something resembling a saccade was found gHistoEarliestOnset := aVelBeg; gHistoLatestOffset := aVelEnd; aHsize := ChanValue(gChHeye1, aVelEnd) - ChanValue(gChHeye1, aVelBeg); aVsize := ChanValue(gChVeye1, aVelEnd) - ChanValue(gChVeye1, aVelBeg); endif endif endif endif return aValid; 'report if a saccade was found end; 'MeasureSaccade '---------------------------------------------------- ' MeasureTarget 'Uses the points twenty-five ms before and after the 'event time passed here. '4/16/03 '---------------------------------------------------- func MeasureTarget(aTime, &aHsize, &aVsize) var aBefore, aAfter, aDelta, aValid := kFalse, aSurround := 0.025; if (aTime - aSurround > 0) then '11/4/03, protect from a negative value, not sure where it comes from, but it happens View(gDataWindow%); aBefore:= ChanValue(gChHtarg1, aTime - aSurround); aAfter := ChanValue(gChHtarg1, aTime + aSurround); aHsize := aAfter - aBefore; aBefore:= ChanValue(gChVtarg1, aTime - aSurround); aAfter := ChanValue(gChVtarg1, aTime + aSurround); aVsize := aAfter - aBefore; if (abs(aHsize) > 1) or (abs(aVsize) > 1) then aValid := kTrue; endif endif return aValid; end; 'MeasureTarget '6/22/06 not used '---------------------------------------------------- ' S m a r t R a n d ' 'Based on the user-selected event ratio and actual 'event ratio, a compensated ratio is returned that 'helps the random function generator maintain the 'intended ratio of events. '2/21/03 '---------------------------------------------------- func SmartRand(aIdeal, aActual) var aDifference,aRandom,aCombined; aDifference := aIdeal - aActual; aRandom := rand(); aCombined := aRandom + aDifference; return aCombined; 'the farther away it gets from ideal, the more likely it will be chosen end 'SmartRand '6/22/06 not used '---------------------------------------------------- ' Radial2XY ' 'Convert radial coordinates to XY. '6/2/06 '---------------------------------------------------- proc Radial2XY(aRadius, aTheta, &aX, &aY) aX := cos(Radians(aTheta)) * aRadius; aY := sin(Radians(aTheta)) * aRadius; end 'Radial2XY '---------------------------------------------------- ' Radial2dacH ' 'Convert r-theta coordinates to return the horizontal 'value sent to the D/A. '1/8/03 '---------------------------------------------------- func Radial2dacH%(aRadius, aTheta, aOffset) 'var x; 'x := Degrees2dac%(cos(Radians(aTheta)) * aRadius + aOffset); 'PrintLog("X = ",x," ",aRadius," ",aTheta," ",aOffset); return Degrees2dac%(cos(Radians(aTheta)) * aRadius + aOffset); end 'Radial2dacH '---------------------------------------------------- ' R a d i a l 2 d a c V ' 'Convert r-theta coordinates to return the vertical 'value sent to the D/A. '1/8/03 '---------------------------------------------------- func Radial2dacV%(aRadius, aTheta, aOffset) 'var y; 'y := Degrees2dac%(sin(Radians(aTheta)) * aRadius + aOffset); 'PrintLog("Y = ",y," ",aRadius," ",aTheta," ",aOffset); return Degrees2dac%(sin(Radians(aTheta)) * aRadius + aOffset); end 'Radial2dacV '---------------------------------------------------- ' Proportional2ThetaH ' 'Returns a number proportional to the cos of theta. 'Useful when determining how much horizontal '"proportional to eye" adapting to call for. '7/14/06 '---------------------------------------------------- func Proportional2ThetaH(aPercent, aTheta) if (aTheta > 90) and (aTheta <= 270) then aPercent := -(aPercent); endif 'var x; 'x := cos(Radians(aTheta)) * aPercent; return cos(Radians(aTheta)) * aPercent; end 'Proportional2ThetaH '---------------------------------------------------- ' Proportional2ThetaV ' 'Returns a number proportional to the sin of theta. 'Useful when determining how much vertical '"proportional to eye" adapting to call for. '7/14/06 '---------------------------------------------------- func Proportional2ThetaV(aPercent, aTheta) 'if (aTheta > 90) and (aTheta <= 270) then if (aTheta > 180) and (aTheta <= 360) then aPercent := -(aPercent); endif 'var y; 'y := sin(Radians(aTheta)) * aPercent; return sin(Radians(aTheta)) * aPercent; end 'Proportional2ThetaV '---------------------------------------------------- ' D A C 2 R a d i a l ' 'Convert DAC XY coordinates to radius and theta. '11/25/03 '---------------------------------------------------- proc DAC2Radial(aX, aY, aXoffset, aYoffset, &aRadius, &aTheta) aX := aX / gBitsPerDegreeIn; aY := aY / gBitsPerDegreeIn; XY2Radial(aX, aY, aXoffset, aYoffset, aRadius, aTheta) end 'DAC2Radial '---------------------------------------------------- ' X Y 2 R a d i a l ' 'Convert XY coordinates to radius and theta. '2/5/04 '---------------------------------------------------- proc XY2Radial(aX, aY, aXoffset, aYoffset, &aRadius, &aTheta) var aSOT; 'sine of theta aX := aX + aXoffset; aY := aY + aYoffset; aRadius := sqrt(pow(aX,2) + pow(aY,2)); 'compute hypotenus if aX = 0 then if aY = 0 then aTheta := 0; 'dead center else if aY > 0 then aTheta := 90; 'straight up else aTheta := 270; 'straight dn endif endif else aTheta := aTan(aY/aX); aTheta := Degrees(aTheta); if aX < 0 then aTheta := 180 + aTheta; endif NormalizeRadiusTheta (aRadius, aTheta); endif end 'XY2Radial '---------------------------------------------------- ' A r r a y 2 S t r ' 'Unloads the numbers from an array and converts them 'to type string and concatenates them in to one string 'with separating spaces. This is useful when displaying 'multiple parameters in dlgString boxes. '12/18/03 '---------------------------------------------------- func Array2Str$(&aArray[], aMaxElement, &aStr$) var i; for i := 0 to aMaxElement do 'initial steps if aArray[i] <> kNAN then if i = 0 then aStr$ := str$(aArray[i]); 'avoid getting an unwanted leading blank else aStr$ := aStr$ + " " + str$(aArray[i]); endif endif next end '---------------------------------------------------- ' R a d i a n s ' 'Converts an angle expressed in degrees to radians '11/22/02 '---------------------------------------------------- func Radians(degrees) return degrees / (360/(2 * kPi)); end 'Radians '---------------------------------------------------- ' Degrees ' 'Converts an angle expressed in radians to degrees '11/17/03 '---------------------------------------------------- func Degrees(radians) return radians * (360/(2 * kPi)); end 'Degrees '---------------------------------------------------- ' Degrees2dac ' 'From Tim Bergel. The problem you are getting is 'caused by the integer arithmetic failing to be able 'to cope with a value greater than c. 2e9, as integer 'values run from (approx.) -2e9 to 2e9. Just using 'the value in a function argument is OK as it evades 'the arithmetic system. So you have to avoid using '4294967296 in an integer context. I suggest 'something like the routine below. 'There are two reasons why we use 32-bit variable 'values for DACs. Firstly, it means that if we 'switch to 18-bit DACs in future hardware, there 'will be no changes in the sequencer, just more of 'the 32-bit 'value will be used. This is actually 'unlikely to happen, the major reason why we do this 'is that if you write a loop which increments a DAC by 'a small value each time round to generate a ramp, if 'you do this with just 16 bits the slopes get very 'inaccurate when you are adding a small amount - there 'is no amount to add which is between 9 and 10 for 'example, so at that level you average a 5% error in 'the DAC slope. If you use a 32-bit value, the problem 'is reduced by a factor of 65000 and you get nice 'accurate ramps. '11/22/02 '---------------------------------------------------- func Degrees2dac%(degrees) var dac; dac := degrees * gBitsPerDegreeOut; 'gBitsPerDegreeOut changes when using galvos and LED if dac > 2147483647 then dac := 2147483647; 'Limit to safe integer value endif if dac < -2147483647 then dac := -2147483647; endif return dac; end 'Degrees2dac '---------------------------------------------------- ' Volts2dac ' 'From Tim Bergel: The problem you are getting is 'caused by the integer arithmetic failing to be able 'to cope with a value greater than c. 2e9, as integer 'values run from (approx.) -2e9 to 2e9. Just using 'the value in a function argument is OK as it evades 'the arithmetic system. So you have to avoid using '4294967296 in an integer context. I suggest 'something like the routine below. 'There are two reasons why we use 32-bit variable 'values for DACs. Firstly, it means that if we 'switch to 18-bit DACs in future hardware, there 'will be no changes in the sequencer, just more of 'the 32-bit 'value will be used. This is actually 'unlikely to happen, the major reason why we do this 'is that if you write a loop which increments a DAC by 'a small value each time round to generate a ramp, if 'you do this with just 16 bits the slopes get very 'inaccurate when you are adding a small amount - there 'is no amount to add which is between 9 and 10 for 'example, so at that level you average a 5% error in 'the DAC slope. If you use a 32-bit value, the problem 'is reduced by a factor of 65000 and you get nice 'accurate ramps. '11/22/02 '---------------------------------------------------- func Volts2dac%(volts) var aBitsOut, dac; aBitsOut := pow(2,32); '4,294,967,296 dac := volts * aBitsOut / 20; '1v=10deg, full range=200deg; if dac > 2147483647 then dac := 2147483647; 'Limit to safe integer value endif if dac < -2147483647 then dac := -2147483647; endif return dac; end 'Degrees2dac '---------------------------------------------------- ' EncodeLED80 ' 'This routine takes position data for the LED spots 'and converts it to the information that controls the 'LED hemisphere. '---------------------------------------------------- proc EncodeLED80(radius, theta, colorBit, &boardAddress, &LEDaddress) boardAddress := -1; 'invalid values LEDaddress := -1; theta := round(theta); 'just a precaution so it will work with Spike2 v5.14 if (radius = 0) then 'although each axis has a radius of 0, only the 0 leg of the LED hemisphere is wired to show it. theta := 0; endif docase case theta = 0 then if (radius <= kMaxLED) then boardAddress := 0; else boardAddress := 1; endif case theta = 45 then boardAddress := 2; case theta = 90 then boardAddress := 3; case theta = 135 then boardAddress := 4; case theta = 180 then if (radius <= kMaxLED) then boardAddress := 5; else boardAddress := 6; endif case theta = 225 then boardAddress := 7; case theta = 270 then boardAddress := 8; case theta = 315 then boardAddress := 9; endcase if ((boardAddress <> 1) and (boardAddress <> 6)) then LEDaddress := round(radius * 2 + colorBit); 'must round to work with Spike2 v5.14 else LEDaddress := round((radius - 48) * 2 + colorBit); 'must round to work with Spike2 v5.14 -- deals with concatenated boards on the 0 and 180 degree axes endif end '---------------------------------------------------- ' Table ' 'This routine displays the data being sent to the 'sequencer in the table. '---------------------------------------------------- proc Table(aTable%[]) var j%; if kBOBmode = kTrue then PresentDebugWindow(); j% := 0; while j% < 550 do Print("%5d,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f,%14.1f\n", j%, aTable%[j%+0], aTable%[j%+1], aTable%[j%+2], aTable%[j%+3], aTable%[j%+4], aTable%[j%+5], aTable%[j%+6], aTable%[j%+7], aTable%[j%+8], aTable%[j%+9]); j% := j% + 10; wend endif end